Conf.pm 87.4 KB
Newer Older
1
2
3
4
# -*- indent-tabs-mode: nil; -*-
# vim:ft=perl:et:sw=4
# $Id$

5
# Sympa - SYsteme de Multi-Postage Automatique
6
7
8
9
#
# Copyright (c) 1997, 1998, 1999 Institut Pasteur & Christophe Wolfhugel
# Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
# 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites
10
# Copyright (c) 2011, 2012, 2013, 2014, 2015 GIP RENATER
11
12
13
14
15
16
17
18
19
20
21
22
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
23
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
24

root's avatar
root committed
25
26
27
28
## This module handles the configuration file for Sympa.

package Conf;

29
30
use strict;
use warnings;
31
use English qw(-no_match_vars);
32
use Storable;
33

34
use Sympa;
35
use Sympa::ConfDef;
36
37
use Sympa::Constants;
use Sympa::Language;
38
use Sympa::LockedFile;
39
use Sympa::Log;
40
use SDM;
41
use tools;
42
43
use Sympa::Tools::Data;
use Sympa::Tools::File;
root's avatar
root committed
44

45
46
my $log = Sympa::Log->instance;

47
48
49
50
51
52
53
54
55
56
=head1 NAME

Conf - Sympa configuration

=head1 DESCRIPTION

=head2 CONSTANTS AND EXPORTED VARIABLES

=cut

57
## Database and SQL statement handlers
58
my $sth;
59
# parameters hash, keyed by parameter name
60
our %params =
61
    map { $_->{name} => $_ }
62
    grep { $_->{name} } @Sympa::ConfDef::params;
63
64
65

# valid virtual host parameters, keyed by parameter name
my %valid_robot_key_words;
66
my %db_storable_parameters;
67
my %optional_key_words;
68
foreach my $hash (@Sympa::ConfDef::params) {
69
70
71
72
    $valid_robot_key_words{$hash->{'name'}} = 1 if ($hash->{'vhost'});
    $db_storable_parameters{$hash->{'name'}} = 1
        if (defined($hash->{'db'}) and $hash->{'db'} ne 'none');
    $optional_key_words{$hash->{'name'}} = 1 if ($hash->{'optional'});
73
74
}

sikeda's avatar
sikeda committed
75
our $params_by_categories = _get_parameters_names_by_category();
76

77
my %old_params = (
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
    trusted_ca_options               => 'capath,cafile',
    'msgcat'                         => '',
    queueexpire                      => '',
    clean_delay_queueother           => '',
    web_recode_to                    => 'filesystem_encoding', # ??? - 5.2
    'localedir'                      => '',
    'ldap_export_connection_timeout' => '',                    # 3.3b3 - 4.1?
    'ldap_export_dnmanager'          => '',                    # ,,
    'ldap_export_host'               => '',                    # ,,
    'ldap_export_name'               => '',                    # ,,
    'ldap_export_password'           => '',                    # ,,
    'ldap_export_suffix'             => '',                    # ,,
    'tri'                            => 'sort',                # ??? - 1.3.4-1
    'sort'                           => '',                    # 1.4.0 - ???
    'pidfile'                        => '',                    # ??? - 6.1.17
    'pidfile_distribute'             => '',                    # ,,
    'pidfile_creation'               => '',                    # ,,
    'pidfile_bulk'                   => '',                    # ,,
    'archived_pidfile'               => '',                    # ,,
    'bounced_pidfile'                => '',                    # ,,
    'task_manager_pidfile'           => '',                    # ,,
99
100
101
102
103
104
    'email_gecos'       => 'gecos',              # 6.2a.?? - 6.2a.33
    'lock_method'       => '',                   # 5.3b.3 - 6.2a.33
    'html_editor_file'  => 'html_editor_url',    # 6.2a
    'openssl'           => '',                   # ?? - 6.2a.40
    'distribution_mode' => '',                   # 5.0a.1 - 6.2a.40
    'queuedistribute'   => '',                   # ,,
105
106
107
108

    # These are not yet implemented
    'crl_dir'          => '',
    'dkim_header_list' => '',
root's avatar
root committed
109
);
110

111
112
## These parameters now have a hard-coded value
## Customized value can be accessed though as %Ignored_Conf
olivier.salaun's avatar
olivier.salaun committed
113
my %Ignored_Conf;
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
my %hardcoded_params = (filesystem_encoding => 'utf8');

my %trusted_applications = (
    'trusted_application' => {
        'occurrence' => '0-n',
        'format'     => {
            'name' => {
                'format'     => '\S*',
                'occurrence' => '1',
                'case'       => 'insensitive',
            },
            'ip' => {
                'format'     => '\d+\.\d+\.\d+\.\d+',
                'occurrence' => '0-1'
            },
            'md5password' => {
                'format'     => '.*',
                'occurrence' => '0-1'
            },
            'proxy_for_variables' => {
                'format'     => '.*',
                'occurrence' => '0-n',
                'split_char' => ','
137
138
139
140
141
142
143
144
145
146
147
            },
            'set_variables' => {
                'format'     => '\S+=.*',
                'occurrence' => '0-n',
                'split_char' => ',',
            },
            'allow_commands' => {
                'format'     => '\S+',
                'occurrence' => '0-n',
                'split_char' => ',',
            },
148
149
        }
    }
150
);
151
my $binary_file_extension = ".bin";
152

153
our $wwsconf;
olivier.salaun's avatar
olivier.salaun committed
154
our %Conf = ();
root's avatar
root committed
155

156
157
158
159
160
161
162
163
164
165
166
=head2 FUNCTIONS

=over 4

=item load ( [ CONFIG_FILE ], [ NO_DB ], [ RETURN_RESULT ] )

Loads and parses the configuration file.  Reports errors if any.

do not try to load database values if NO_DB is set;
do not change gloval hash %Conf if RETURN_RESULT is set;

167
168
## we known that's dirty, this proc should be rewritten without this global
## var %Conf
169
170
171
172
173

=back

=cut

root's avatar
root committed
174
sub load {
175
176
    my $config_file   = shift || get_sympa_conf();
    my $no_db         = shift;
177
    my $return_result = shift;
178
    my $force_reload;
179

root's avatar
root committed
180
    my $config_err = 0;
181
182
    my %line_numbered_config;

183
    if (_source_has_not_changed($config_file) and !$return_result) {
184
185
186
187
        if (my $tmp_conf = _load_binary_cache(
                {'config_file' => $config_file . $binary_file_extension}
            )
            ) {
188
            %Conf = %{$tmp_conf};
189
190
191
            # Will force the robot.conf reloading, as sympa.conf is the
            # default.
            $force_reload = 1;
192
        }
193
    } else {
194
        $log->syslog('debug3',
195
196
            'File %s has changed since the last cache. Loading file',
            $config_file);
197
198
        # Will force the robot.conf reloading, as sympa.conf is the default.
        $force_reload = 1;
199
        ## Loading the Sympa main config file.
200
201
202
203
204
205
206
        if (my $config_loading_result = _load_config_file_to_hash(
                {'path_to_config_file' => $config_file}
            )
            ) {
            %line_numbered_config =
                %{$config_loading_result->{'numbered_config'}};
            %Conf       = %{$config_loading_result->{'config'}};
207
            $config_err = $config_loading_result->{'errors'};
208
        } else {
209
210
211
212
213
            return undef;
        }
        # Returning the config file content if this is what has been asked.
        return (\%line_numbered_config) if ($return_result);

214
215
        # Users may define parameters with a typo or other errors. Check that
        # the parameters
216
        # we found in the config file are all well defined Sympa parameters.
sikeda's avatar
sikeda committed
217
        $config_err += _detect_unknown_parameters_in_config(
218
219
220
221
222
223
            {   'config_hash' => \%Conf,
                'config_file_line_numbering_reference' =>
                    \%line_numbered_config,
            }
        );

224
225
        # Some parameter values are hardcoded. In that case, ignore what was
        #  set in the config file and simply use the hardcoded value.
226
227
        %Ignored_Conf =
            %{_set_hardcoded_parameter_values({'config_hash' => \%Conf,})};
root's avatar
root committed
228

sikeda's avatar
sikeda committed
229
        _set_listmasters_entry({'config_hash' => \%Conf, 'main_config' => 1});
230
231
232
233
234

        ## Some parameters must have a value specifically defined in the
        ## config. If not, it is an error.
        $config_err += _detect_missing_mandatory_parameters(
            {'config_hash' => \%Conf, 'file_to_check' => $config_file});
235

236
        # Some parameters need special treatments to get their final values.
sikeda's avatar
sikeda committed
237
        _infer_server_specific_parameter_values({'config_hash' => \%Conf,});
238

sikeda's avatar
sikeda committed
239
        _infer_robot_parameter_values({'config_hash' => \%Conf});
root's avatar
root committed
240

241
        if ($config_err) {
242
            $log->syslog('err', 'Errors while parsing main config file %s',
sikeda's avatar
sikeda committed
243
                $config_file);
244
245
            return undef;
        }
246

247
248
        _store_source_file_name(
            {'config_hash' => \%Conf, 'config_file' => $config_file});
sikeda's avatar
sikeda committed
249
        _save_config_hash_to_binary({'config_hash' => \%Conf,});
250
    }
root's avatar
root committed
251

252
253
    if (my $missing_modules_count =
        _check_cpan_modules_required_by_config({'config_hash' => \%Conf,})) {
254
        $log->syslog('err', 'Warning: %d required modules are missing',
sikeda's avatar
sikeda committed
255
            $missing_modules_count);
256
257
    }

258
259
    _replace_file_value_by_db_value({'config_hash' => \%Conf})
        unless ($no_db);
sikeda's avatar
sikeda committed
260
261
    _load_server_specific_secondary_config_files({'config_hash' => \%Conf,});
    _load_robot_secondary_config_files({'config_hash' => \%Conf});
262

263
    ## Load robot.conf files
264
265
266
267
268
269
270
271
    unless (
        load_robots(
            {   'config_hash'  => \%Conf,
                'no_db'        => $no_db,
                'force_reload' => $force_reload
            }
        )
        ) {
272
273
        return undef;
    }
sikeda's avatar
sikeda committed
274
    ##_create_robot_like_config_for_main_robot();
root's avatar
root committed
275
    return 1;
276
}
277

salaun's avatar
salaun committed
278
279
## load each virtual robots configuration files
sub load_robots {
280
    my $param = shift;
281
282
    my @robots;

sikeda's avatar
sikeda committed
283
    my $robots_list_ref = get_robots_list();
284
    unless (defined $robots_list_ref) {
285
        $log->syslog('err', 'Robots config loading failed');
286
        return undef;
287
    } else {
288
289
290
291
292
        @robots = @{$robots_list_ref};
    }
    unless ($#robots > -1) {
        return 1;
    }
293
    my $exiting = 0;
294
    foreach my $robot (@robots) {
295
        my $robot_config_file = "$Conf{'etc'}/$robot/robot.conf";
296
297
298
299
300
301
302
303
304
        my $robot_conf        = undef;
        unless (
            $robot_conf = _load_single_robot_config(
                {   'robot'        => $robot,
                    'no_db'        => $param->{'no_db'},
                    'force_reload' => $param->{'force_reload'}
                }
            )
            ) {
305
            $log->syslog(
sikeda's avatar
sikeda committed
306
307
308
309
                'err',
                'The config for robot %s contain errors: it could not be correctly loaded',
                $robot
            );
310
            $exiting = 1;
311
        } else {
312
313
            $param->{'config_hash'}{'robots'}{$robot} = $robot_conf;
        }
314
315
        _check_double_url_usage(
            {'config_hash' => $param->{'config_hash'}{'robots'}{$robot}});
316
    }
317
    return undef if ($exiting);
318
    return 1;
319
320
321
322
323
324
325
}

## returns a robot conf parameter
sub get_robot_conf {
    my ($robot, $param) = @_;

    if (defined $robot && $robot ne '*') {
326
327
        if (   defined $Conf{'robots'}{$robot}
            && defined $Conf{'robots'}{$robot}{$param}) {
328
329
            return $Conf{'robots'}{$robot}{$param};
        }
330
    }
331
    ## default
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
    return $Conf{$param};
}

=over 4

=item get_sympa_conf

Gets path name of main config file.
Path name is taken from:

=over 4

=item 1

C<--config> command line option

=item 2

C<SYMPA_CONFIG> environment variable

=item 3

built-in default

=back

=back

=cut

sub get_sympa_conf {
    return $main::options{'config'}
364
        if %main::options and defined $main::options{'config'};
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
    return $ENV{'SYMPA_CONFIG'} || Sympa::Constants::CONFIG;
}

=over 4

=item get_wwsympa_conf

Gets path name of wwsympa.conf file.
Path name is taken from:

=over 4

=item 1

C<SYMPA_WWSCONFIG> environment variable

=item 2

built-in default

=back

=back

=cut

sub get_wwsympa_conf {
    return $ENV{'SYMPA_WWSCONFIG'} || Sympa::Constants::WWSCONFIG;
salaun's avatar
salaun committed
393
394
}

395
396
# deletes all the *.conf.bin files.
sub delete_binaries {
397
    $log->syslog('debug2', '');
398
    my @files = (get_sympa_conf(), get_wwsympa_conf());
sikeda's avatar
sikeda committed
399
    foreach my $robot (@{get_robots_list()}) {
400
401
402
        push @files, "$Conf{'etc'}/$robot/robot.conf";
    }
    foreach my $c_file (@files) {
403
404
        my $binary_file = $c_file . ".bin";
        if (-f $binary_file) {
405
406
            if (-w $binary_file) {
                unlink $binary_file;
407
            } else {
408
                $log->syslog(
409
                    'err',
410
                    'Could not remove file %s. You should remove it manually to ensure the configuration used is valid',
411
412
                    $binary_file
                );
413
414
415
416
417
            }
        }
    }
}

418
419
# Return a reference to an array containing the names of the robots on the
# server.
420
sub get_robots_list {
421
    $log->syslog('debug2', "Retrieving the list of robots on the server");
422
    my @robots_list;
423
    unless (opendir DIR, $Conf{'etc'}) {
424
        $log->syslog('err',
sikeda's avatar
sikeda committed
425
426
            'Unable to open directory %s for virtual robots config',
            $Conf{'etc'});
427
428
429
430
431
432
433
434
435
436
437
438
        return undef;
    }
    foreach my $robot (readdir DIR) {
        my $robot_config_file = "$Conf{'etc'}/$robot/robot.conf";
        next unless (-d "$Conf{'etc'}/$robot");
        next unless (-f $robot_config_file);
        push @robots_list, $robot;
    }
    closedir(DIR);
    return \@robots_list;
}

439
## Returns a hash containing the values of all the parameters of the group
440
441
## (as defined in Sympa::ConfDef) whose name is given as argument, in the
## context of the robot given as argument.
442
443
sub get_parameters_group {
    my ($robot, $group) = @_;
444
    $log->syslog('debug3', 'Getting parameters for group "%s"', $group);
445
446
    my $param_hash;
    foreach my $param_name (keys %{$params_by_categories->{$group}}) {
447
        $param_hash->{$param_name} = get_robot_conf($robot, $param_name);
448
449
450
    }
    return $param_hash;
}
451
452

## fetch the value from parameter $label of robot $robot from conf_table
453
sub get_db_conf {
454
455
456
457

    my $robot = shift;
    my $label = shift;

458
459
460
461
462
463
464
465
466
467
468
469
    # if the value is related to a robot that is not explicitly defined, apply
    # it to the default robot.
    $robot = '*' unless (-f $Conf{'etc'} . '/' . $robot . '/robot.conf');
    unless ($robot) { $robot = '*' }

    unless (
        $sth = SDM::do_query(
            "SELECT value_conf AS value FROM conf_table WHERE (robot_conf =%s AND label_conf =%s)",
            SDM::quote($robot),
            SDM::quote($label)
        )
        ) {
470
        $log->syslog(
471
472
473
474
475
            'err',
            'Unable retrieve value of parameter %s for robot %s from the database',
            $label,
            $robot
        );
476
        return undef;
477
    }
478

479
    my $value = $sth->fetchrow;
480

481
    $sth->finish();
482
    return $value;
483
484
485
}

## store the value from parameter $label of robot $robot from conf_table
486
sub set_robot_conf {
487
488
489
490
    my $robot = shift;
    my $label = shift;
    my $value = shift;

491
    $log->syslog('info', 'Set config for robot %s, %s="%s"',
492
        $robot, $label, $value);
493

494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
    # set the current config before to update database.
    if (-f "$Conf{'etc'}/$robot/robot.conf") {
        $Conf{'robots'}{$robot}{$label} = $value;
    } else {
        $Conf{$label} = $value;
        $robot = '*';
    }

    unless (
        $sth = SDM::do_query(
            "SELECT count(*) FROM conf_table WHERE (robot_conf=%s AND label_conf =%s)",
            SDM::quote($robot),
            SDM::quote($label)
        )
        ) {
509
        $log->syslog(
510
511
512
513
514
            'err',
            'Unable to check presence of parameter %s for robot %s in database',
            $label,
            $robot
        );
515
        return undef;
516
    }
517

518
519
    my $count = $sth->fetchrow;
    $sth->finish();
520

521
    if ($count == 0) {
522
523
524
525
526
527
528
529
        unless (
            $sth = SDM::do_query(
                "INSERT INTO conf_table (robot_conf, label_conf, value_conf) VALUES (%s,%s,%s)",
                SDM::quote($robot),
                SDM::quote($label),
                SDM::quote($value)
            )
            ) {
530
            $log->syslog(
531
532
533
534
535
536
                'err',
                'Unable add value %s for parameter %s in the robot %s DB conf',
                $value,
                $label,
                $robot
            );
537
538
            return undef;
        }
539
540
541
542
543
544
545
546
547
548
549
    } else {
        unless (
            $sth = SDM::do_query(
                "UPDATE conf_table SET robot_conf=%s, label_conf=%s, value_conf=%s WHERE ( robot_conf  =%s AND label_conf =%s)",
                SDM::quote($robot),
                SDM::quote($label),
                SDM::quote($value),
                SDM::quote($robot),
                SDM::quote($label)
            )
            ) {
550
            $log->syslog(
551
552
553
554
555
556
                'err',
                'Unable set parameter %s value to %s in the robot %s DB conf',
                $label,
                $value,
                $robot
            );
557
            return undef;
558
        }
559
560
561
    }
}

562
563
# Store configs to database
sub conf_2_db {
564
    $log->syslog('debug2', '(%s)', @_);
565

566
    my @conf_parameters = @Sympa::ConfDef::params;
567
568

    # store in database robots parameters.
569
570
571
    # load only parameters that are in a robot.conf file (do not apply
    # defaults).
    my $robots_conf = load_robots();
572

573
    unless (opendir DIR, $Conf{'etc'}) {
574
        $log->syslog('err',
sikeda's avatar
sikeda committed
575
576
            'Unable to open directory %s for virtual robots config',
            $Conf{'etc'});
577
578
579
580
581
582
        return undef;
    }

    foreach my $robot (readdir(DIR)) {
        next unless (-d "$Conf{'etc'}/$robot");
        next unless (-f "$Conf{'etc'}/$robot/robot.conf");
583

584
        my $config;
585
586
587
588
589
590
591
        if (my $result_of_config_loading = _load_config_file_to_hash(
                {         'path_to_config_file' => $Conf{'etc'} . '/' 
                        . $robot
                        . '/robot.conf'
                }
            )
            ) {
592
593
            $config = $result_of_config_loading->{'config'};
        }
sikeda's avatar
sikeda committed
594
        _remove_unvalid_robot_entry($config);
595
596
597
598
599
600
601
602
603
604
605
606
607
608

        for my $i (0 .. $#conf_parameters) {
            if ($conf_parameters[$i]->{'name'}) {
                # skip separators in conf_parameters structure
                if (($conf_parameters[$i]->{'vhost'} eq '1')
                    && #skip parameters that can't be define by robot so not to be loaded in db at that stage
                    ($config->{$conf_parameters[$i]->{'name'}})
                    ) {
                    Conf::set_robot_conf(
                        $robot,
                        $conf_parameters[$i]->{'name'},
                        $config->{$conf_parameters[$i]->{'name'}}
                    );
                }
609
610
611
            }
        }
    }
612
    closedir(DIR);
613
614

    # store in database sympa;conf and wwsympa.conf
615

616
617
    ## Load configuration file. Ignoring database config and get result
    my $global_conf;
618
619
    unless ($global_conf =
        Conf::load(Conf::get_sympa_conf(), 1, 'return_result')) {
620
        $log->syslog('err', 'Configuration file %s has errors',
621
622
            Conf::get_sympa_conf());
        return undef;
623
    }
624
625
626
627
628
629
630
631
632
633

    for my $i (0 .. $#conf_parameters) {
        if (($conf_parameters[$i]->{'edit'} eq '1')
            && $global_conf->{$conf_parameters[$i]->{'name'}}) {
            Conf::set_robot_conf(
                "*",
                $conf_parameters[$i]->{'name'},
                $global_conf->{$conf_parameters[$i]->{'name'}}[0]
            );
        }
634
635
636
    }
}

637
638
639
## Check required files and create them if required
sub checkfiles_as_root {

640
    my $config_err = 0;
sympa-authors's avatar
   
sympa-authors committed
641

642
    ## Check aliases file
643
644
645
    unless (-f $Conf{'sendmail_aliases'}
        || ($Conf{'sendmail_aliases'} =~ /^none$/i)) {
        unless (open ALIASES, ">$Conf{'sendmail_aliases'}") {
646
            $log->syslog(
647
648
649
650
651
652
                'err',
                "Failed to create aliases file %s",
                $Conf{'sendmail_aliases'}
            );
            return undef;
        }
653

654
655
656
657
658
        print ALIASES
            "## This aliases file is dedicated to Sympa Mailing List Manager\n";
        print ALIASES
            "## You should edit your sendmail.mc or sendmail.cf file to declare it\n";
        close ALIASES;
659
        $log->syslog(
660
661
662
663
664
            'notice',
            "Created missing file %s",
            $Conf{'sendmail_aliases'}
        );
        unless (
665
            Sympa::Tools::File::set_file_rights(
666
667
668
669
670
671
                file  => $Conf{'sendmail_aliases'},
                user  => Sympa::Constants::USER,
                group => Sympa::Constants::GROUP,
                mode  => 0644,
            )
            ) {
672
            $log->syslog('err', 'Unable to set rights on %s',
673
674
675
                $Conf{'db_name'});
            return undef;
        }
sympa-authors's avatar
   
sympa-authors committed
676
677
    }

678
    foreach my $robot (keys %{$Conf{'robots'}}) {
sympa-authors's avatar
sympa-authors committed
679

680
681
682
683
        # create static content directory
        my $dir = get_robot_conf($robot, 'static_content_path');
        if ($dir ne '' && !-d $dir) {
            unless (mkdir($dir, 0775)) {
684
685
                $log->syslog('err', 'Unable to create directory %s: %m',
                    $dir);
686
687
                $config_err++;
            }
688

689
            unless (
690
                Sympa::Tools::File::set_file_rights(
691
692
693
694
695
                    file  => $dir,
                    user  => Sympa::Constants::USER,
                    group => Sympa::Constants::GROUP,
                )
                ) {
696
                $log->syslog('err', 'Unable to set rights on %s',
697
698
699
                    $Conf{'db_name'});
                return undef;
            }
700
        }
701
702
    }

703
    return 1;
704
705
}

sikeda's avatar
sikeda committed
706
707
708
709
710
711
712
713
714
715
## Check if data structures are uptodate
## If not, no operation should be performed before the upgrade process is run
sub data_structure_uptodate {
    my $version_file =
        Conf::get_robot_conf('*', 'etc') . '/data_structure.version';
    my $data_structure_version;

    if (-f $version_file) {
        my $fh;
        unless (open $fh, '<', $version_file) {
716
            $log->syslog('err', 'Unable to open %s: %m', $version_file);
sikeda's avatar
sikeda committed
717
718
719
720
721
722
723
724
725
726
727
728
729
730
            return undef;
        }
        while (<$fh>) {
            next if /^\s*$/;
            next if /^\s*\#/;
            chomp;
            $data_structure_version = $_;
            last;
        }
        close $fh;
    }

    if (defined $data_structure_version
        and $data_structure_version ne Sympa::Constants::VERSION) {
731
        $log->syslog('err',
sikeda's avatar
sikeda committed
732
733
734
735
736
737
738
739
            "Data structure (%s) is not uptodate for current release (%s)",
            $data_structure_version, Sympa::Constants::VERSION);
        return 0;
    }

    return 1;
}

740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
# Check if cookie parameter was changed.
# Old name: tools::cookie_changed().
sub cookie_changed {
    my $current = $Conf::Conf{'cookie'};
    $current = '' unless defined $current;

    my $changed = 1;
    if (-f "$Conf::Conf{'etc'}/cookies.history") {
        my $fh;
        unless (open $fh, "$Conf::Conf{'etc'}/cookies.history") {
            $log->syslog('err', 'Unable to read %s/cookies.history',
                $Conf::Conf{'etc'});
            return undef;
        }
        my $oldcook = <$fh>;
        close $fh;
        ($oldcook) = reverse split /\s+/, $oldcook;
        $oldcook = '' unless defined $oldcook;

        if ($oldcook eq $current) {
            $log->syslog('debug2', 'Cookie is stable');
            $changed = 0;
        }
        return $changed;
    } else {
        my $umask = umask 037;
        unless (open COOK, ">$Conf::Conf{'etc'}/cookies.history") {
            umask $umask;
            $log->syslog('err', 'Unable to create %s/cookies.history',
                $Conf::Conf{'etc'});
            return undef;
        }
        umask $umask;
        chown [getpwnam(Sympa::Constants::USER)]->[2],
            [getgrnam(Sympa::Constants::GROUP)]->[2],
            "$Conf::Conf{'etc'}/cookies.history";
        print COOK "$current ";
        close COOK;
        return (0);
    }
}

root's avatar
root committed
782
783
784
## Check a few files
sub checkfiles {
    my $config_err = 0;
785
786
787
788
789

    foreach my $p ('sendmail', 'openssl', 'antivirus_path') {
        next unless $Conf{$p};

        unless (-x $Conf{$p}) {
790
            $log->syslog('err', "File %s does not exist or is not executable",
791
792
                $Conf{$p});
            $config_err++;
793
        }
794
795
796
797
798
799
800
801
    }

    foreach my $qdir (
        'spool',          'queue',
        'queueautomatic', 'queuedigest',
        'queuemod',       'queuetopic',
        'queueauth',      'queueoutgoing',
        'queuebounce',    'queuesubscribe',
802
        'queuetask',      'tmpdir'
803
804
        ) {
        unless (-d $Conf{$qdir}) {
805
            $log->syslog('info', 'Creating spool %s', $Conf{$qdir});
806
            unless (mkdir($Conf{$qdir}, 0775)) {
807
808
                $log->syslog('err', 'Unable to create spool %s',
                    $Conf{$qdir});
809
810
811
                $config_err++;
            }
            unless (
812
                Sympa::Tools::File::set_file_rights(
813
814
815
                    file  => $Conf{$qdir},
                    user  => Sympa::Constants::USER,
                    group => Sympa::Constants::GROUP,
816
817
                )
                ) {
818
                $log->syslog('err', 'Unable to set rights on %s',
819
820
                    $Conf{$qdir});
                $config_err++;
821
            }
822
        }
root's avatar
root committed
823
    }
824

825
    ## Also create associated bad/ spools
826
    foreach my $qdir ('queue', 'queueautomatic') {
827
828
        my $subdir = $Conf{$qdir} . '/bad';
        unless (-d $subdir) {
829
            $log->syslog('info', 'Creating spool %s', $subdir);
830
            unless (mkdir($subdir, 0775)) {
831
                $log->syslog('err', 'Unable to create spool %s', $subdir);
832
833
834
                $config_err++;
            }
            unless (
835
                Sympa::Tools::File::set_file_rights(
836
837
838
                    file  => $subdir,
                    user  => Sympa::Constants::USER,
                    group => Sympa::Constants::GROUP,
839
840
                )
                ) {
841
                $log->syslog('err', 'Unable to set rights on %s', $subdir);
842
                $config_err++;
843
            }
844
        }
845
    }
salaun's avatar
salaun committed
846

847
848
    ## Check cafile and capath access
    if (defined $Conf{'cafile'} && $Conf{'cafile'}) {
849
        unless (-f $Conf{'cafile'} && -r $Conf{'cafile'}) {
850
            $log->syslog('err', 'Cannot access cafile %s', $Conf{'cafile'});
851
            Sympa::send_notify_to_listmaster('*', 'cannot_access_cafile',
852
                [$Conf{'cafile'}]);
853
            $config_err++;
854
        }
855
856
857
    }

    if (defined $Conf{'capath'} && $Conf{'capath'}) {
858
        unless (-d $Conf{'capath'} && -x $Conf{'capath'}) {
859
            $log->syslog('err', 'Cannot access capath %s', $Conf{'capath'});
860
            Sympa::send_notify_to_listmaster('*', 'cannot_access_capath',
861
                [$Conf{'capath'}]);
862
            $config_err++;
863
        }
864
865
    }

866
    ## queuebounce and bounce_path pointing to the same directory
867
    if ($Conf{'queuebounce'} eq $Conf{'bounce_path'}) {
868
        $log->syslog(
869
870
871
872
            'err',
            'Error in config: queuebounce and bounce_path parameters pointing to the same directory (%s)',
            $Conf{'queuebounce'}
        );
873
        Sympa::send_notify_to_listmaster(
874
            '*',
875
            'queuebounce_and_bounce_path_are_the_same',
876
877
            [$Conf{'queuebounce'}]
        );
878
        $config_err++;
879
    }
880

881
    ## automatic_list_creation enabled but queueautomatic pointing to queue
882
883
    if (($Conf{automatic_list_feature} eq 'on')
        && $Conf{'queue'} eq $Conf{'queueautomatic'}) {
884
        $log->syslog(
885
886
887
888
            'err',
            'Error in config: queue and queueautomatic parameters pointing to the same directory (%s)',
            $Conf{'queue'}
        );
889
        Sympa::send_notify_to_listmaster('*',
890
            'queue_and_queueautomatic_are_the_same',
891
            [$Conf{'queue'}]);
892
893
894
        $config_err++;
    }

sympa-authors's avatar
   
sympa-authors committed
895
896
    #  create pictures dir if usefull for each robot
    foreach my $robot (keys %{$Conf{'robots'}}) {
897
898
899
900
        my $dir = get_robot_conf($robot, 'static_content_path');
        if ($dir ne '' && -d $dir) {
            unless (-f $dir . '/index.html') {
                unless (open(FF, ">$dir" . '/index.html')) {
901
                    $log->syslog(
902
                        'err',
903
904
                        'Unable to create %s/index.html as an empty file to protect directory: %m',
                        $dir
905
906
907
                    );
                }
                close FF;
908
909
            }

910
911
            # create picture dir
            if (get_robot_conf($robot, 'pictures_feature') eq 'on') {
912
913
914
                my $pictures_dir =
                    get_robot_conf($robot, 'static_content_path')
                    . '/pictures';
915
916
                unless (-d $pictures_dir) {
                    unless (mkdir($pictures_dir, 0775)) {
917
                        $log->syslog('err', 'Unable to create directory %s',
918
919
920
921
922
923
924
925
                            $pictures_dir);
                        $config_err++;
                    }
                    chmod 0775, $pictures_dir;

                    my $index_path = $pictures_dir . '/index.html';
                    unless (-f $index_path) {
                        unless (open(FF, ">$index_path")) {
926
                            $log->syslog(
927
928
929
930
931
932
933
934
                                'err',
                                'Unable to create %s as an empty file to protect directory',
                                $index_path
                            );
                        }
                        close FF;
                    }
                }
935
936
937
            }
        }
    }
938

939
940
    #update_css();

root's avatar
root committed
941
942
943
944
    return undef if ($config_err);
    return 1;
}

945
## return 1 if the parameter is a known robot
946
## Valid options :
947
##    'just_try' : prevent error logs if robot is not valid
948
sub valid_robot {
949
    my $robot   = shift;
950
    my $options = shift;
951

952
953
    ## Main host
    return 1 if ($robot eq $Conf{'domain'});
954

955
    ## Missing etc directory
956
    unless (-d $Conf{'etc'} . '/' . $robot) {
957
        $log->syslog(
958
            'err',  'Robot %s undefined; no %s directory',
959
960
961
            $robot, $Conf{'etc'} . '/' . $robot
        ) unless ($options->{'just_try'});
        return undef;
962
    }
963

964
    ## Missing expl directory
965
    unless (-d $Conf{'home'} . '/' . $robot) {
966
        $log->syslog(
967
            'err',  'Robot %s undefined; no %s directory',
968
969
970
            $robot, $Conf{'home'} . '/' . $robot
        ) unless ($options->{'just_try'});
        return undef;
971
    }
972

973
974
    ## Robot not loaded
    unless (defined $Conf{'robots'}{$robot}) {
975
        $log->syslog('err', 'Robot %s was not loaded by this Sympa process',
976
977
978
            $robot)
            unless ($options->{'just_try'});
        return undef;
979
    }
980

981
982
983
984
985
986
987
988
989
    return 1;
}

## Returns the SSO record correponding to the provided sso_id
## return undef if none was found
sub get_sso_by_id {
    my %param = @_;

    unless (defined $param{'service_id'} && defined $param{'robot'}) {
990
        return undef;
991
992
993
    }

    foreach my $sso (@{$Conf{'auth_services'}{$param{'robot'}}}) {
994
        $log->syslog('notice', 'SSO: %s', $sso->{'service_id'});
995
        next unless ($sso->{'service_id'} eq $param{'service_id'});
996

997
        return $sso;
998
    }
999

1000
    return undef;
For faster browsing, not all history is shown. View entire blame