File Coverage

blib/lib/Kolab.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1             package Kolab;
2              
3             ##
4             ## Copyright (c) 2003 Code Fusion cc
5             ##
6             ## Writen by Stuart Bingė
7             ##
8             ## This program is free software; you can redistribute it and/or
9             ## modify it under the terms of the GNU General Public License as
10             ## published by the Free Software Foundation; either version 2, or
11             ## (at your option) any later version.
12             ##
13             ## This program is distributed in the hope that it will be useful,
14             ## but WITHOUT ANY WARRANTY; without even the implied warranty of
15             ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16             ## General Public License for more details.
17             ##
18             ## You can view the GNU General Public License, online, at the GNU
19             ## Project's homepage; see .
20             ##
21              
22 1     1   31073 use 5.008;
  1         3  
  1         74  
23 1     1   5 use strict;
  1         2  
  1         30  
24 1     1   4 use warnings;
  1         6  
  1         26  
25 1     1   1494 use Sys::Syslog;
  1         65609  
  1         79  
26 1     1   906 use URI;
  1         17198  
  1         29  
27 1     1   2470 use Net::LDAP;
  0            
  0            
28             use Kolab::Util;
29             #use Kolab::LDAP;
30             use vars qw(%config %haschanged);
31              
32             require Exporter;
33              
34             our @ISA = qw(Exporter);
35              
36             our %EXPORT_TAGS = (
37             'all' => [ qw(
38             %config
39             &reloadConfig
40             &reload
41             &log
42             &superLog
43             ) ]
44             );
45              
46             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
47              
48             our @EXPORT = qw(
49             &KOLAB_SILENT
50             &KOLAB_ERROR
51             &KOLAB_WARN
52             &KOLAB_INFO
53             &KOLAB_DEBUG
54             );
55              
56             our $VERSION = sprintf('%d.%02d', q$Revision: 1.2 $ =~ /(\d+)\.(\d+)/);
57              
58             sub KOLAB_SILENT() { 0 }
59             sub KOLAB_ERROR() { 1 }
60             sub KOLAB_WARN() { 2 }
61             sub KOLAB_INFO() { 3 }
62             sub KOLAB_DEBUG() { 4 }
63              
64             sub reloadConfig
65             {
66             my $tempval;
67             my $ldap;
68              
69             # `log_level' specifies what severity of messages we want to see in the logs.
70             # Possible values are:
71             # 0 - Silent
72             # 1 - Errors
73             # 2 - Warnings & Errors
74             # 3 - Info, Warnings & Errors (DEFAULT)
75             # 4 - Debug (i.e. everything)
76              
77             # Determine the root of the kolab installation, and read `kolab.globals'
78             if (!($tempval = (getpwnam('kolab'))[7])) {
79             $config{'log_level'} = KOLAB_WARN;
80             &log('C', 'Unable to determine the kolab root directory', KOLAB_ERROR);
81             # exit(1);
82             } else {
83             %config = readConfig(%config, "$tempval/etc/kolab/kolab.globals");
84             $config{'prefix'} = $tempval;
85             }
86              
87             # Now read `kolab.conf', overwriting values read from `kolab.globals'
88             %config = readConfig(\%config, "$tempval/etc/kolab/kolab.conf");
89              
90             # $config{'log_level'} = KOLAB_WARN if (!exists $config{'log_level'});
91             &log('C', 'Reloading configuration');
92              
93             # Get the UID/GID of the `kolab' user
94             if (!($config{'kolab_uid'} = (getpwnam('kolab'))[2])) {
95             &log('C', "Unable to determine the uid of user `kolab'", KOLAB_ERROR);
96             # exit(1);
97             }
98             if (!($config{'kolab_gid'} = (getgrnam('kolab'))[2])) {
99             &log('C', "Unable to determine the gid of user `kolab'", KOLAB_ERROR);
100             # exit(1);
101             }
102              
103             # Make sure the critical variables we need were defined in kolab.conf
104             if (!exists $config{'bind_dn'} || !exists $config{'bind_pw'} || !exists $config{'ldap_uri'} || !exists $config{'base_dn'}) {
105             &log('C', "One or more required configuration variables (`bind_dn', `bind_pw', `ldap_uri' and/or `base_dn') are missing in `kolab.conf'", KOLAB_ERROR);
106             exit(1);
107             }
108              
109             # Retrieve the LDAP values of the main kolab object to complete our config hash
110             if (!($tempval = URI->new($config{'ldap_uri'}))) {
111             &log('C', "Unable to parse ldap_uri `" . $config{'ldap_uri'} . "'", KOLAB_ERROR);
112             # exit(1);
113             } else {
114             $config{'ldap_ip'} = $tempval->host;
115             $config{'ldap_port'} = $tempval->port;
116             }
117              
118             # `kolab_dn' points to the main kolab object in LDAP
119             # Defaults to `k=kolab,$base_dn' if not specified (for backwards compatibility)
120             $config{'kolab_dn'} = "k=kolab," . $config{'base_dn'} if (!exists $config{'kolab_dn'});
121             if ($config{'kolab_dn'} eq '') {
122             &log('C', "`kolab_dn' is empty; skipping LDAP read");
123             } else {
124             my $mesg;
125             my $ldapobject;
126              
127             if (!($ldap = Net::LDAP->new($config{'ldap_ip'}, port => $config{'ldap_port'}))) {
128             &log('C', "Unable to connect to LDAP server `" . $config{'ldap_ip'} . ":" . $config{'ldap_port'} . "'", KOLAB_ERROR);
129             # exit(1);
130             }
131              
132             $mesg = $ldap->bind($config{'bind_dn'}, password => $config{'bind_pw'}) if $ldap;
133             if ($ldap && $mesg->code) {
134             &log('C', "Unable to bind to DN `" . $config{'bind_dn'} . "'", KOLAB_ERROR);
135             # exit(1);
136             }
137              
138             #$ldap = Kolab::LDAP::create(
139             # $config{'ldap_ip'},
140             # $config{'ldap_port'},
141             # $config{'bind_dn'},
142             # $config{'bind_pw'},
143             # 1
144             #);
145             if ($ldap) {
146             $mesg = $ldap->search(
147             base => $config{'kolab_dn'},
148             scope => 'base',
149             filter => '(objectclass=*)'
150             );
151             if (!$mesg->code) {
152             $ldapobject = $mesg->pop_entry;
153             foreach $tempval ($ldapobject->attributes) {
154             $config{$tempval} = $ldapobject->get_value($tempval);
155             }
156             } else {
157             &log('C', "Unable to find kolab object `" . $config{'kolab_dn'} . "'", KOLAB_ERROR);
158             # exit(1);
159             }
160             } else {
161             &log('C', "Unable to read configuration data from LDAP", KOLAB_WARN);
162             }
163             }
164              
165             # At this point we have read in all user-specified configuration variables.
166             # We now need to go through the list of all possible configuration variables
167             # and set the default values of those that were not overridden.
168              
169             # ProFTPd password
170             if (exists $config{'proftpd-userPassword'}) {
171             my $salt = substr($config{'proftpd-userPassword'}, 0, 2);
172             $config{'proftpd-userPassword'} = crypt($config{'proftpd-userPassword'}, $salt);
173             } else {
174             $config{'proftpd-userPassword'} = '';
175             }
176              
177             # Apache legacy mode
178             $config{'legacy-mode'} = "# no legacy configuration";
179             if (exists $config{'apache-http'} && $config{'apache-http'} =~ /true/i) {
180             $config{'legacy-mode'} = 'Include "' . $config{'prefix'} . '/etc/apache/legacy.conf"';
181             }
182             $config{'fqdn'} = trim(`hostname`);
183              
184             # Cyrus admin account
185             $tempval = $config{'cyrus-admins'} || 'manager';
186             (my $cmanager, my $dummy) = split(/ /, $tempval, 2);
187             $config{'cyrus_admin'} = $cmanager if (!exists $config{'cyrus_admin'});
188             $config{'cyrus_admin_pw'} = $config{'bind_pw'} if (!exists $config{'cyrus_admin_pw'});
189              
190             # `directory_mode' specifies what backend to use (for the main kolab
191             # object - for the other objects see their respective XXX_directory_mode).
192             # Defaults to `slurpd'
193             #
194             # NOTE: A plugin scheme is used for this; the backend module loaded
195             # is `Kolab::LDAP::$config{'directory_mode'}, so anyone is able to slot
196             # in a new Kolab::LDAP:: module, change `directory_mode' and have the new
197             # module used as a backend (as long as it conforms to the correct
198             # interface, that is).
199             #
200             # Currently supported backends:
201             # `ad' - Active Directory
202             # $config{'directory_mode'} = 'slurpd' if (!exists $config{'directory_mode'});
203              
204             # `conn_refresh_period' specifies how many minutes to wait before forceably
205             # tearing down the change listener connection, re-syncing, and re-connecting.
206             # Used by the AD backend.
207             # Defaults to one hour.
208             # $config{'conn_refresh_period'} = 60 if (!exists $config{'conn_refresh_period'});
209              
210             # `slurpd_port' specifies what port the kolab slurpd replication daemon listens on
211             # Defaults to 9999 for backwards compatibility
212             # $config{'slurpd_port'} = 9999 if (!exists $config{'slurpd_port'});
213              
214             # `user_ldap_uri', `user_bind_dn', `user_bind_pw' and `user_dn_list' are
215             # used to specify the DNs where user objects are located. They default to
216             # `ldap_uri', `bind_dn', `bind_pw' and `base_dn', respectively.
217             #
218             # NOTE: `user_dn_list' is a semi-colon separated list of DNs, as opposed
219             # to a single DN (such as `kolab_dn').
220             #
221             # TODO: Expand this to allow all separate entities (kolab object, users,
222             # shared folders, etc) to exist in user-specified locations
223             #
224             # TODO: Check Postfix LDAP aliasing when user_dn_list contains more than
225             # one DN.
226             $config{'user_ldap_uri'} = $config{'ldap_uri'} if (!exists $config{'user_ldap_uri'});
227              
228             if (!($tempval = URI->new($config{'user_ldap_uri'}))) {
229             &log('C', "Unable to parse user_ldap_uri `" . $config{'user_ldap_uri'} . "'", KOLAB_ERROR);
230             # exit(1);
231             } else {
232             $config{'user_ldap_ip'} = $tempval->host;
233             $config{'user_ldap_port'} = $tempval->port;
234             }
235              
236             $config{'user_bind_dn'} = $config{'bind_dn'} if (!exists $config{'user_bind_dn'});
237             $config{'user_bind_pw'} = $config{'bind_pw'} if (!exists $config{'user_bind_pw'});
238             $config{'user_dn_list'} = $config{'base_dn'} if (!exists $config{'user_dn_list'});
239             $config{'user_directory_mode'} = $config{'directory_mode'} if (!exists $config{'user_directory_mode'});
240              
241             # `user_object_class' denotes what object class to search for when locating users.
242             # Defaults to `inetOrgPerson'
243             # $config{'user_object_class'} = 'inetOrgPerson' if (!exists $config{'user_object_class'});
244              
245             # This part sets various backend-specific LDAP fields (if they have not been
246             # overridden) based on `directory_mode'.
247             #
248             # `user_delete_flag' is used to test whether a user object has been deleted
249             # `user_field_modified' is used to test whether a user object has been modified
250             # `user_field_guid' indicates a field that can be considered globally unique to the object
251             # `user_field_quota' indicates a field that stores the cyrus quota for the user
252             # if ($config{'user_directory_mode'} eq 'ad') {
253             # # AD
254             # $config{'user_field_deleted'} = 'isDeleted' if (!exists $config{'user_field_deleted'});
255             # $config{'user_field_modified'} = 'whenChanged' if (!exists $config{'user_field_modified'});
256             # $config{'user_field_guid'} = 'objectGUID' if (!exists $config{'user_field_guid'});
257             # $config{'user_field_quota'} = 'userquota' if (!exists $config{'user_field_quota'});
258             # } else {
259             # # slurd/default
260             # $config{'user_field_deleted'} = 'deleteflag' if (!exists $config{'user_field_deleted'});
261             # $config{'user_field_modified'} = 'modifytimestamp' if (!exists $config{'user_field_modified'});
262             # $config{'user_field_guid'} = 'entryUUID' if (!exists $config{'user_field_guid'});
263             # $config{'user_field_quota'} = 'userquota' if (!exists $config{'user_field_quota'});
264             # }
265              
266             # The `sf_XXX' variables are the shared folder equivalents of the `user_XXX' variables
267             $config{'sf_ldap_uri'} = $config{'ldap_uri'} if (!exists $config{'sf_ldap_uri'});
268              
269             if (!($tempval = URI->new($config{'sf_ldap_uri'}))) {
270             &log('C', "Unable to parse sf_ldap_uri `" . $config{'sf_ldap_uri'} . "'", KOLAB_ERROR);
271             # exit(1);
272             } else {
273             $config{'sf_ldap_ip'} = $tempval->host;
274             $config{'sf_ldap_port'} = $tempval->port;
275             }
276              
277             $config{'sf_bind_dn'} = $config{'bind_dn'} if (!exists $config{'sf_bind_dn'});
278             $config{'sf_bind_pw'} = $config{'bind_pw'} if (!exists $config{'sf_bind_pw'});
279             $config{'sf_dn_list'} = $config{'base_dn'} if (!exists $config{'sf_dn_list'});
280             $config{'sf_directory_mode'} = $config{'directory_mode'} if (!exists $config{'sf_directory_mode'});
281              
282             # $config{'sf_object_class'} = 'sharedfolder' if (!exists $config{'sf_object_class'});
283              
284             # if ($config{'sf_directory_mode'} eq 'ad') {
285             # # AD
286             # $config{'sf_field_deleted'} = 'isDeleted' if (!exists $config{'sf_field_deleted'});
287             # $config{'sf_field_modified'} = 'whenChanged' if (!exists $config{'sf_field_modified'});
288             # $config{'sf_field_guid'} = 'entryUUID' if (!exists $config{'sf_field_guid'});
289             # $config{'sf_field_quota'} = 'userquota' if (!exists $config{'sf_field_quota'});
290             # } else {
291             # # slurd/default
292             # $config{'sf_field_deleted'} = 'deleteflag' if (!exists $config{'sf_field_deleted'});
293             # $config{'sf_field_modified'} = 'modifytimestamp' if (!exists $config{'sf_field_modified'});
294             # $config{'sf_field_guid'} = 'entryUUID' if (!exists $config{'sf_field_guid'});
295             # $config{'sf_field_quota'} = 'userquota' if (!exists $config{'sf_field_quota'});
296             # }
297              
298             # `gyard_deletion_period' specifies how many minutes to leave lost users in
299             # the graveyard before deleting them.
300             # Defaults to seven days.
301             # $config{'gyard_deletion_period'} = 7 * 24 * 60 if (!exists $config{'gyard_deletion_period'});
302              
303             $config{'dirserv_home_server'} = $config{'fqdn'} if (!exists $config{'dirserv_home_server'});
304              
305             # That's it! We now have our config hash.
306             #Kolab::LDAP::destroy($ldap);
307             if (defined($ldap) && $ldap->isa('Net::LDAP')) {
308             $ldap->unbind;
309             $ldap->disconnect;
310             }
311              
312             &log('C', 'Finished reloading configuration');
313             }
314              
315             sub reload
316             {
317             my $prefix = $config{'prefix'};
318              
319             if ($haschanged{'slapd'}) {
320             &log('K', 'Restarting OpenLDAP...');
321             system("$prefix/etc/rc.d/rc.openldap restart");
322             }
323              
324             if ($haschanged{'saslauthd'}) {
325             &log('K', 'Restarting SASLAuthd...');
326             system("$prefix/etc/rc.d/rc.sasl stop; sleep 1; $prefix/sbin/saslauthd -a ldap -n 5");
327             }
328              
329             if ($haschanged{'apache'}) {
330             &log('K', 'Reloading Apache...');
331             system("$prefix/sbin/apachectl graceful");
332             }
333              
334             if ($haschanged{'postfix'}) {
335             &log('K', 'Reloading Postfix...');
336             system("$prefix/sbin/postfix reload");
337             }
338              
339             if ($haschanged{'imapd'}) {
340             &log('K', 'Restarting imapd...');
341             system("$prefix/etc/rc.d/rc.imapd restart");
342             }
343              
344             if ($config{'proftpd-ftp'} =~ /true/i) {
345             Kolab::log('K', 'Starting ProFTPd if not running');
346             system("$prefix/etc/rc.d/rc.proftpd start");
347             if ($haschanged{'proftpd'}) {
348             &log('K', 'Reloading ProFTPd...');
349             kill('SIGHUP', `cat $prefix/var/proftpd/proftpd.pid`);
350             }
351             } else {
352             &log('K', 'Stopping ProFTPd, if running...');
353             system("$prefix/etc/rc.d/rc.proftpd stop");
354             }
355              
356             %Kolab::Conf::haschanged = ();
357              
358             &log('K', 'Reload finished');
359             }
360              
361             sub log
362             {
363             my $prefix = shift;
364             my $text = shift;
365             my $priority = shift || KOLAB_INFO;
366              
367             my $level = $config{'log_level'};
368             if ($level >= $priority) {
369             if ($priority == KOLAB_ERROR) {
370             $text = $prefix . ' Error: ' . $text;
371             } elsif ($priority == KOLAB_WARN) {
372             $text = $prefix . ' Warning: ' . $text;
373             } elsif ($priority == KOLAB_DEBUG) {
374             $text = $prefix . ' Debug: ' . $text;
375             } else {
376             $text = $prefix . ': ' . $text;
377             }
378             syslog('info', "$text");
379             }
380             }
381              
382             sub superLog
383             {
384             my $text = shift;
385             syslog('info', "$text");
386             }
387              
388             reloadConfig();
389              
390             1;
391             __END__