1#! --PERL--
2# -*- indent-tabs-mode: nil; -*-
3# vim:ft=perl:et:sw=4
4# $Id$
5
6# Sympa - SYsteme de Multi-Postage Automatique
7#
8# Copyright (c) 1997, 1998, 1999 Institut Pasteur & Christophe Wolfhugel
9# Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
10# 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites
11# Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017 GIP RENATER
12# Copyright 2017 The Sympa Community. See the AUTHORS.md file at the top-level
13# directory of this distribution and at
14# <https://github.com/sympa-community/sympa.git>.
15#
16# This program is free software; you can redistribute it and/or modify
17# it under the terms of the GNU General Public License as published by
18# the Free Software Foundation; either version 2 of the License, or
19# (at your option) any later version.
20#
21# This program is distributed in the hope that it will be useful,
22# but WITHOUT ANY WARRANTY; without even the implied warranty of
23# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24# GNU General Public License for more details.
25#
26# You should have received a copy of the GNU General Public License
27# along with this program.  If not, see <http://www.gnu.org/licenses/>.
28
29use lib split(/:/, $ENV{SYMPALIB} || ''), '--modulesdir--';
30use strict;
31use warnings;
32use English qw(-no_match_vars);
33use Getopt::Long;
34use Pod::Usage;
35
36use Conf;
37use Sympa::Constants;
38use Sympa::Crash;    # Show traceback.
39use Sympa::Log;
40
41# If this program was invoked by the other, throw standard output away so
42# that parent's output (e.g. via CGI) won't be stained.
43unless (-t) {
44    open STDOUT, '>&STDERR';
45}
46
47my %options;
48unless (GetOptions(\%options, 'domain=s', 'help|h', 'version|v')) {
49    pod2usage(-exitval => 1, -output => \*STDERR);
50}
51if ($options{'help'}) {
52    pod2usage(0);
53} elsif ($options{'version'}) {
54    printf "Sympa %s\n", Sympa::Constants::VERSION;
55    exit 0;
56}
57
58my $log = Sympa::Log->instance;
59$log->{log_to_stderr} = 'all' if -t;
60
61my $robot_id = $options{'domain'};
62
63# Load configuration
64unless (Conf::load()) {
65    $log->syslog('err', 'The configuration file %s contains error',
66        Conf::get_sympa_conf());
67    exit 1;
68}
69
70$log->openlog(
71    $Conf::Conf{'syslog'},
72    $Conf::Conf{'log_socket_type'},
73    database_backend => undef
74);
75
76# setting log_level using conf unless it is set by calling option
77$log->{level} = $Conf::Conf{'log_level'};
78
79my ($aliases_file, $aliases_program, $aliases_db_type);
80if ($robot_id) {
81    unless (Conf::valid_robot($robot_id)) {
82        $log->syslog('err', 'Robot %s does not exist', $robot_id);
83        exit 1;
84    }
85    $aliases_file    = Conf::get_robot_conf($robot_id, 'sendmail_aliases');
86    $aliases_program = Conf::get_robot_conf($robot_id, 'aliases_program');
87    $aliases_db_type = Conf::get_robot_conf($robot_id, 'aliases_db_type');
88} else {
89    $aliases_file    = $Conf::Conf{'sendmail_aliases'};
90    $aliases_program = $Conf::Conf{'aliases_program'};
91    $aliases_db_type = $Conf::Conf{'aliases_db_type'};
92}
93if ($aliases_file eq 'none') {
94    exit 0;    # do nothing
95} elsif (!-e $aliases_file) {
96    $log->syslog('err', 'The aliases file %s does not exist', $aliases_file);
97    exit 1;
98}
99unless ($aliases_db_type =~ /\A\w+\z/) {
100    $log->syslog('err', 'Invalid aliases_db_type "%s"', $aliases_db_type);
101    exit 1;
102}
103
104if ($aliases_program =~ m{\A/}) {
105    $log->syslog('debug2', 'Executing "%s %s"',
106        $aliases_program, $aliases_file);
107
108    exec $aliases_program, $aliases_file;
109} elsif ($aliases_program eq 'makemap') {
110    $log->syslog('debug2', 'Executing "%s %s %s < %s"',
111        q{--MAKEMAP--}, $aliases_db_type, $aliases_file, $aliases_file);
112
113    unless (open STDIN, '<', $aliases_file) {
114        $log->syslog('err', 'Canot open %s', $aliases_file);
115        exit 1;
116    }
117    exec q{--MAKEMAP--}, $aliases_db_type, $aliases_file;
118} elsif ($aliases_program eq 'newaliases') {
119    $log->syslog(
120        'debug2',
121        'Executing "%s"',
122        q{--NEWALIASES-- --NEWALIASES_ARG--}
123    );
124
125    # Some newaliases utilities e.g. with Postfix cannot take arguments.
126    # OTOH if it may take arg, exec() must take separate one to avoid shell
127    # metacharacters.
128    if (q{--NEWALIASES_ARG--}) {
129        exec q{--NEWALIASES--}, q{--NEWALIASES_ARG--};
130    } else {
131        exec q{--NEWALIASES--};
132    }
133} elsif ($aliases_program eq 'postalias') {
134    $log->syslog('debug2', 'Executing "%s %s:%s"',
135        q{--POSTALIAS--}, $aliases_db_type, $aliases_file);
136
137    exec q{--POSTALIAS--}, "$aliases_db_type:$aliases_file";
138} elsif ($aliases_program eq 'postmap') {
139    $log->syslog('debug2', 'Executing "%s %s:%s"',
140        q{--POSTMAP--}, $aliases_db_type, $aliases_file);
141
142    exec q{--POSTMAP--}, "$aliases_db_type:$aliases_file";
143} elsif ($aliases_program eq 'none') {
144    $log->syslog('debug2', 'Skipping execution of aliases_program');
145    exit 0;
146} else {
147    $log->syslog('err', 'Invalid aliases_program "%s"', $aliases_program);
148    exit 1;
149}
150
151my $errno = $ERRNO;
152$log->syslog('err', 'Cannot execute aliases_program "%s": %m',
153    $aliases_program);
154exit($errno || 1);
155
156__END__
157
158=encoding utf-8
159
160=head1 NAME
161
162sympa_newaliases, sympa_newaliases.pl - Alias database maintenance
163
164=head1 SYNOPSIS
165
166  sympa_newaliases.pl --domain=dom.ain
167
168=head1 DESCRIPTION
169
170F<sympa_newaliases.pl> is a program to maintain alias database.
171
172It is typically invoked from
173L<Sympa::Aliases::Template> module via sympa_newaliases-wrapper,
174then updates alias database.
175
176=head1 OPTIONS
177
178F<sympa_newaliases.pl> may run with following options.
179
180=over
181
182=item C<--domain=>I<domain>
183
184Name of virtual robot on which aliases will be updated.
185
186=item C<-h>, C<--help>
187
188Print this help message.
189
190=back
191
192=head1 CONFIGURATION PARAMETERS
193
194Following site configuration parameters in F<--CONFIG--> will be referred.
195They may be overridden by robot.conf of each virtual robot.
196
197=over
198
199=item sendmail_aliases
200
201Source text of alias database.
202
203Default value is F<$SENDMAIL_ALIASES>.
204
205=item aliases_program
206
207System command to update alias database.
208Possible values are:
209
210=over
211
212=item C<makemap>
213
214Sendmail makemap utility.
215
216=item C<newaliases>
217
218L<newaliases(1)> or compatible utility.
219
220=item C<postalias>
221
222Postfix L<postalias(1)> utility.
223
224=item C<postmap>
225
226Postfix L<postmap(1)> utility.
227
228=item Full path
229
230Full path to executable file.
231File will be invoked with the value of C<sendmail_aliases> as an argument.
232
233=back
234
235Default value is C<newaliases>.
236
237=item aliases_db_type
238
239Type of alias database.
240This is meaningful when value of C<aliases_program> parameter is
241C<makemap>, C<postalias> or C<postmap>.
242
243Possible values will be vary by system commands.
244For example, C<postalias> and C<postmap> can support any of
245C<btree>, C<cdb>, C<dbm>, C<hash> and C<sdbm>.
246
247Default value is C<hash>.
248
249=back
250
251=head1 RETURN VALUE
252
253Returns with exit code 0.
254If invoked system command failed, returns with its exit code.
255On other failures, returns with 1.
256
257=head1 FILES
258
259=over
260
261=item F<--CONFIG-->
262
263Sympa site configuration.
264
265=item F<$LIBEXECDIR/sympa_newaliases-wrapper>
266
267Set UID wrapper for sympa_newaliases.pl.
268
269=back
270
271=head1 HISTORY
272
273sympa_newaliases.pl appeared on Sympa 6.1.18.
274It was initially written by
275IKEDA Soji <ikeda@conversion.co.jp>.
276
277=head1 SEE ALSO
278
279L<Sympa::Aliases::Template>.
280
281=cut
282