Filename | /usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf/LDAP.pm |
Statements | Executed 14 statements in 1.83ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 51µs | 230µs | BEGIN@44 | Mail::SpamAssassin::Conf::LDAP::
1 | 1 | 1 | 33µs | 123µs | BEGIN@51 | Mail::SpamAssassin::Conf::LDAP::
1 | 1 | 1 | 31µs | 42µs | BEGIN@46 | Mail::SpamAssassin::Conf::LDAP::
1 | 1 | 1 | 30µs | 35µs | BEGIN@48 | Mail::SpamAssassin::Conf::LDAP::
1 | 1 | 1 | 22µs | 107µs | BEGIN@49 | Mail::SpamAssassin::Conf::LDAP::
1 | 1 | 1 | 19µs | 48µs | BEGIN@47 | Mail::SpamAssassin::Conf::LDAP::
0 | 0 | 0 | 0s | 0s | __ANON__[:107] | Mail::SpamAssassin::Conf::LDAP::
0 | 0 | 0 | 0s | 0s | load | Mail::SpamAssassin::Conf::LDAP::
0 | 0 | 0 | 0s | 0s | load_modules | Mail::SpamAssassin::Conf::LDAP::
0 | 0 | 0 | 0s | 0s | load_with_ldap | Mail::SpamAssassin::Conf::LDAP::
0 | 0 | 0 | 0s | 0s | new | Mail::SpamAssassin::Conf::LDAP::
0 | 0 | 0 | 0s | 0s | sa_die | Mail::SpamAssassin::Conf::LDAP::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # <@LICENSE> | ||||
2 | # Licensed to the Apache Software Foundation (ASF) under one or more | ||||
3 | # contributor license agreements. See the NOTICE file distributed with | ||||
4 | # this work for additional information regarding copyright ownership. | ||||
5 | # The ASF licenses this file to you under the Apache License, Version 2.0 | ||||
6 | # (the "License"); you may not use this file except in compliance with | ||||
7 | # the License. You may obtain a copy of the License at: | ||||
8 | # | ||||
9 | # http://www.apache.org/licenses/LICENSE-2.0 | ||||
10 | # | ||||
11 | # Unless required by applicable law or agreed to in writing, software | ||||
12 | # distributed under the License is distributed on an "AS IS" BASIS, | ||||
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
14 | # See the License for the specific language governing permissions and | ||||
15 | # limitations under the License. | ||||
16 | # </@LICENSE> | ||||
17 | |||||
18 | =head1 NAME | ||||
19 | |||||
20 | Mail::SpamAssassin::Conf::LDAP - load SpamAssassin scores from LDAP database | ||||
21 | |||||
22 | =head1 SYNOPSIS | ||||
23 | |||||
24 | (see Mail::SpamAssassin) | ||||
25 | |||||
26 | |||||
27 | =head1 DESCRIPTION | ||||
28 | |||||
29 | Mail::SpamAssassin is a module to identify spam using text analysis and | ||||
30 | several internet-based realtime blacklists. | ||||
31 | |||||
32 | This class is used internally by SpamAssassin to load scores from an LDAP | ||||
33 | database. Please refer to the C<Mail::SpamAssassin> documentation for public | ||||
34 | interfaces. | ||||
35 | |||||
36 | =head1 METHODS | ||||
37 | |||||
38 | =over 4 | ||||
39 | |||||
40 | =cut | ||||
41 | |||||
42 | package Mail::SpamAssassin::Conf::LDAP; | ||||
43 | |||||
44 | 2 | 65µs | 2 | 410µs | # spent 230µs (51+179) within Mail::SpamAssassin::Conf::LDAP::BEGIN@44 which was called:
# once (51µs+179µs) by Mail::SpamAssassin::BEGIN@73 at line 44 # spent 230µs making 1 call to Mail::SpamAssassin::Conf::LDAP::BEGIN@44
# spent 179µs making 1 call to Exporter::import |
45 | |||||
46 | 2 | 73µs | 2 | 54µs | # spent 42µs (31+12) within Mail::SpamAssassin::Conf::LDAP::BEGIN@46 which was called:
# once (31µs+12µs) by Mail::SpamAssassin::BEGIN@73 at line 46 # spent 42µs making 1 call to Mail::SpamAssassin::Conf::LDAP::BEGIN@46
# spent 12µs making 1 call to strict::import |
47 | 2 | 61µs | 2 | 77µs | # spent 48µs (19+29) within Mail::SpamAssassin::Conf::LDAP::BEGIN@47 which was called:
# once (19µs+29µs) by Mail::SpamAssassin::BEGIN@73 at line 47 # spent 48µs making 1 call to Mail::SpamAssassin::Conf::LDAP::BEGIN@47
# spent 29µs making 1 call to warnings::import |
48 | 2 | 76µs | 2 | 40µs | # spent 35µs (30+5) within Mail::SpamAssassin::Conf::LDAP::BEGIN@48 which was called:
# once (30µs+5µs) by Mail::SpamAssassin::BEGIN@73 at line 48 # spent 35µs making 1 call to Mail::SpamAssassin::Conf::LDAP::BEGIN@48
# spent 5µs making 1 call to bytes::import |
49 | 2 | 80µs | 2 | 193µs | # spent 107µs (22+86) within Mail::SpamAssassin::Conf::LDAP::BEGIN@49 which was called:
# once (22µs+86µs) by Mail::SpamAssassin::BEGIN@73 at line 49 # spent 107µs making 1 call to Mail::SpamAssassin::Conf::LDAP::BEGIN@49
# spent 86µs making 1 call to re::import |
50 | |||||
51 | 1 | 2µs | # spent 123µs (33+90) within Mail::SpamAssassin::Conf::LDAP::BEGIN@51 which was called:
# once (33µs+90µs) by Mail::SpamAssassin::BEGIN@73 at line 53 | ||
52 | @ISA | ||||
53 | 1 | 1.45ms | 2 | 213µs | }; # spent 123µs making 1 call to Mail::SpamAssassin::Conf::LDAP::BEGIN@51
# spent 90µs making 1 call to vars::import |
54 | |||||
55 | 1 | 12µs | @ISA = qw(); | ||
56 | |||||
57 | ########################################################################### | ||||
58 | |||||
59 | sub new { | ||||
60 | my $class = shift; | ||||
61 | $class = ref($class) || $class; | ||||
62 | my ($main) = @_; | ||||
63 | |||||
64 | my $self = { | ||||
65 | 'main' => $main | ||||
66 | }; | ||||
67 | |||||
68 | bless ($self, $class); | ||||
69 | $self; | ||||
70 | } | ||||
71 | |||||
72 | ########################################################################### | ||||
73 | |||||
74 | sub load_modules { # static | ||||
75 | dbg("ldap: loading Net::LDAP and URI"); | ||||
76 | eval { | ||||
77 | require Net::LDAP; # actual server connection | ||||
78 | require URI; # parse server connection dsn | ||||
79 | }; | ||||
80 | |||||
81 | # do any other preloading that will speed up operation | ||||
82 | } | ||||
83 | |||||
84 | ########################################################################### | ||||
85 | |||||
86 | =item $f->load ($username) | ||||
87 | |||||
88 | Read configuration paramaters from LDAP server and parse scores from it. | ||||
89 | |||||
90 | =back | ||||
91 | |||||
92 | =cut | ||||
93 | |||||
94 | sub load { | ||||
95 | my ($self, $username) = @_; | ||||
96 | |||||
97 | my $conf = $self->{main}->{conf}; | ||||
98 | my $url = $conf->{user_scores_dsn}; # an ldap URI | ||||
99 | dbg("ldap: URL is $url"); | ||||
100 | if(!defined($url) || $url eq '') { | ||||
101 | dbg("ldap: No URL defined; skipping LDAP"); | ||||
102 | return; | ||||
103 | } | ||||
104 | |||||
105 | eval { | ||||
106 | # make sure we can see croak messages from DBI | ||||
107 | local $SIG{'__DIE__'} = sub { warn "$_[0]"; }; | ||||
108 | require Net::LDAP; | ||||
109 | require URI; | ||||
110 | load_with_ldap($self, $username, $url); | ||||
111 | 1; | ||||
112 | } or do { | ||||
113 | my $eval_stat = $@ ne '' ? $@ : "errno=$!"; chomp $eval_stat; | ||||
114 | if ($conf->{user_scores_fail_to_global}) { | ||||
115 | info("ldap: failed to load user (%s) scores from LDAP server, ". | ||||
116 | "using a global default: %s", $username, $eval_stat); | ||||
117 | return 1; | ||||
118 | } else { | ||||
119 | warn sprintf( | ||||
120 | "ldap: failed to load user (%s) scores from LDAP server: %s\n", | ||||
121 | $username, $eval_stat); | ||||
122 | return 0; | ||||
123 | } | ||||
124 | }; | ||||
125 | } | ||||
126 | |||||
127 | sub load_with_ldap { | ||||
128 | my ($self, $username, $url) = @_; | ||||
129 | |||||
130 | # ldapurl = scheme "://" [hostport] ["/" | ||||
131 | # [dn ["?" [attributes] ["?" [scope] | ||||
132 | # ["?" [filter] ["?" extensions]]]]]] | ||||
133 | |||||
134 | my $uri = URI->new("$url"); | ||||
135 | |||||
136 | my $host = $uri->host; | ||||
137 | if (!defined($host) || $host eq '') { | ||||
138 | dbg("ldap: No server specified, assuming localhost"); | ||||
139 | $host = "localhost"; | ||||
140 | } | ||||
141 | my $port = $uri->port; | ||||
142 | my $base = $uri->dn; | ||||
143 | my @attr = $uri->attributes; | ||||
144 | my $scope = $uri->scope; | ||||
145 | my $filter = $uri->filter; | ||||
146 | my $scheme = $uri->scheme; | ||||
147 | my %extn = $uri->extensions; # unused | ||||
148 | |||||
149 | $filter =~ s/__USERNAME__/$username/g; | ||||
150 | dbg("ldap: host=$host, port=$port, base='$base', attr=${attr[0]}, scope=$scope, filter='$filter'"); | ||||
151 | |||||
152 | my $main = $self->{main}; | ||||
153 | my $conf = $main->{conf}; | ||||
154 | my $ldapuser = $conf->{user_scores_ldap_username}; | ||||
155 | my $ldappass = $conf->{user_scores_ldap_password}; | ||||
156 | |||||
157 | if(!$ldapuser) { | ||||
158 | undef($ldapuser); | ||||
159 | } else { | ||||
160 | dbg("ldap: user='$ldapuser'"); | ||||
161 | } | ||||
162 | |||||
163 | if(!$ldappass) { | ||||
164 | undef($ldappass); | ||||
165 | } else { | ||||
166 | # don't log this to avoid leaking sensitive info | ||||
167 | # dbg("ldap: pass='$ldappass'"); | ||||
168 | } | ||||
169 | |||||
170 | my $f_attribute = $attr[0]; | ||||
171 | |||||
172 | my $ldap = Net::LDAP->new ("$host:$port", | ||||
173 | onerror => "warn", | ||||
174 | scheme => $scheme); | ||||
175 | |||||
176 | if (!defined($ldapuser) && !defined($ldappass)) { | ||||
177 | $ldap->bind; | ||||
178 | } else { | ||||
179 | $ldap->bind($ldapuser, password => $ldappass); | ||||
180 | } | ||||
181 | |||||
182 | my $result = $ldap->search( base => $base, | ||||
183 | filter => $filter, | ||||
184 | scope => $scope, | ||||
185 | attrs => \@attr | ||||
186 | ); | ||||
187 | |||||
188 | my $config_text = ''; | ||||
189 | foreach my $entry ($result->all_entries) { | ||||
190 | my @v = $entry->get_value($f_attribute); | ||||
191 | foreach my $v (@v) { | ||||
192 | dbg("ldap: retrieving prefs for $username: $v"); | ||||
193 | $config_text .= $v."\n"; | ||||
194 | } | ||||
195 | } | ||||
196 | if ($config_text ne '') { | ||||
197 | $conf->{main} = $main; | ||||
198 | $conf->parse_scores_only($config_text); | ||||
199 | delete $conf->{main}; | ||||
200 | } | ||||
201 | return; | ||||
202 | } | ||||
203 | |||||
204 | ########################################################################### | ||||
205 | |||||
206 | sub sa_die { Mail::SpamAssassin::sa_die(@_); } | ||||
207 | |||||
208 | ########################################################################### | ||||
209 | |||||
210 | 1 | 13µs | 1; |