File Coverage

lib/Mail/Toaster/Qmail.pm
Criterion Covered Total %
statement 201 1083 18.5
branch 38 582 6.5
condition 27 208 12.9
subroutine 31 70 44.2
pod 20 54 37.0
total 317 1997 15.8


line stmt bran cond sub pod time code
1             package Mail::Toaster::Qmail;
2 4     4   1739 use strict;
  4         6  
  4         122  
3 4     4   14 use warnings;
  4         6  
  4         204  
4              
5             our $VERSION = '5.50';
6              
7 4     4   17 use Carp;
  4         4  
  4         308  
8 4     4   19 use English qw( -no_match_vars );
  4         3  
  4         62  
9 4     4   2381 use File::Copy;
  4         3710  
  4         198  
10 4     4   18 use File::Path;
  4         6  
  4         177  
11 4     4   425 use Params::Validate qw( :all );
  4         5881  
  4         627  
12 4     4   1840 use POSIX;
  4         19698  
  4         18  
13 4     4   8699 use Sys::Hostname;
  4         709  
  4         200  
14              
15 4     4   17 use lib 'lib';
  4         7  
  4         34  
16 4     4   747 use parent 'Mail::Toaster::Base';
  4         211  
  4         27  
17              
18             sub build_pop3_run {
19 1     1 1 2 my $self = shift;
20 1         5 my %p = validate( @_, { $self->get_std_opts } );
21              
22 1 50       4 $self->get_supervise_dir or return;
23              
24 1         5 my @lines = $self->toaster->supervised_do_not_edit_notice(1);
25              
26 1 50       4 if ( $self->conf->{pop3_hostname} eq 'qmail' ) {
27 0         0 push @lines, $self->supervised_hostname_qmail( 'pop3' );
28             };
29              
30             #qmail-popup mail.cadillac.net /usr/local/vpopmail/bin/vchkpw qmail-pop3d Maildir 2>&1
31 1 0       3 my $exec = $self->toaster->supervised_tcpserver( 'pop3' ) or return;
32 0 0       0 my $chkpass = $self->_set_checkpasswd_bin( prot => 'pop3' ) or return;
33              
34 0         0 $exec .= "\\\n\tqmail-popup ";
35 0         0 $exec .= $self->toaster->supervised_hostname( "pop3" );
36 0         0 $exec .= "$chkpass qmail-pop3d Maildir ";
37 0         0 $exec .= $self->toaster->supervised_log_method( "pop3" );
38              
39 0         0 push @lines, $exec;
40              
41 0         0 my $file = '/tmp/toaster-watcher-pop3-runfile';
42 0 0       0 $self->util->file_write( $file, lines => \@lines ) or return;
43 0 0       0 $self->install_supervise_run( tmpfile => $file, prot => 'pop3' ) or return;
44 0         0 return 1;
45             }
46              
47             sub build_send_run {
48 0     0 1 0 my $self = shift;
49 0         0 my %p = validate( @_, { $self->get_std_opts } );
50 0         0 my %args = $self->get_std_args( %p );
51              
52 0         0 $self->audit( "generating send/run..." );
53              
54 0 0       0 $self->get_supervise_dir or return;
55              
56 0   0     0 my $mailbox = $self->conf->{send_mailbox_string} || './Maildir/';
57 0   0     0 my $send_log = $self->conf->{send_log_method} || 'syslog';
58              
59 0         0 my @lines = $self->toaster->supervised_do_not_edit_notice;
60              
61 0 0       0 if ( $send_log eq 'syslog' ) {
62 0         0 push @lines, "# use splogger to qmail-send logs to syslog\n
63             # make changes in /usr/local/etc/toaster-watcher.conf
64             exec qmail-start $mailbox splogger qmail\n";
65             }
66             else {
67 0         0 push @lines, "# sends logs to multilog as directed in log/run
68             # make changes in /usr/local/etc/toaster-watcher.conf
69             exec qmail-start $mailbox 2>&1\n";
70             }
71              
72 0         0 my $file = "/tmp/toaster-watcher-send-runfile";
73 0 0       0 $self->util->file_write( $file, lines => \@lines, fatal => 0) or return;
74 0 0       0 $self->install_supervise_run( tmpfile => $file, prot => 'send' ) or return;
75 0         0 return 1;
76             }
77              
78             sub build_smtp_run {
79 0     0 1 0 my $self = shift;
80 0         0 my %p = validate( @_, { $self->get_std_opts } );
81 0         0 my %args = $self->toaster->get_std_args( %p );
82              
83 0         0 $self->audit( "generating supervise/smtp/run...");
84              
85 0 0       0 $self->_test_smtpd_config_values() or return;
86              
87 0         0 my $mem;
88              
89 0         0 my @smtp_run_cmd = $self->toaster->supervised_do_not_edit_notice(1);
90 0         0 push @smtp_run_cmd, $self->smtp_set_qmailqueue();
91 0         0 push @smtp_run_cmd, $self->smtp_get_simenv();
92              
93 0 0       0 $self->get_control_dir or return; # verify control directory exists
94 0 0       0 $self->get_supervise_dir or return;
95              
96             push @smtp_run_cmd, $self->supervised_hostname_qmail( "smtpd" )
97 0 0       0 if $self->conf->{'smtpd_hostname'} eq "qmail";
98              
99 0         0 push @smtp_run_cmd, $self->_smtp_sanity_tests();
100              
101 0 0       0 my $exec = $self->toaster->supervised_tcpserver( "smtpd" ) or return;
102 0         0 $exec .= $self->smtp_set_rbls();
103 0 0       0 $exec .= "\\\n\trecordio " if $self->conf->{'smtpd_recordio'};
104 0 0       0 $exec .= "\\\n\tfixcrio " if $self->conf->{'smtpd_fixcrio'};
105 0         0 $exec .= "\\\n\tqmail-smtpd ";
106 0         0 $exec .= $self->smtp_auth_enable();
107 0 0       0 $exec .= $self->toaster->supervised_log_method( "smtpd" ) or return;
108              
109 0         0 push @smtp_run_cmd, $exec;
110              
111 0         0 my $file = '/tmp/toaster-watcher-smtpd-runfile';
112 0 0       0 $self->util->file_write( $file, lines => \@smtp_run_cmd ) or return;
113 0         0 $self->install_supervise_run( tmpfile => $file, prot => 'smtp' );
114 0         0 return 1;
115             }
116              
117             sub build_submit_run {
118 0     0 1 0 my $self = shift;
119 0         0 my %p = validate( @_, { $self->get_std_opts } );
120 0         0 my %args = $self->toaster->get_std_args( %p );
121              
122 0 0       0 return if ! $self->conf->{'submit_enable'};
123              
124 0         0 $self->audit( "generating submit/run...");
125              
126 0 0       0 return $self->error( "SMTPd config values failed tests!", %p )
127             if ! $self->_test_smtpd_config_values();
128              
129 0         0 my $vdir = $self->setup->vpopmail->get_vpop_dir;
130              
131 0 0       0 $self->get_control_dir or return; # verify control directory exists
132 0 0       0 $self->get_supervise_dir or return;
133              
134             # NOBADHELO note: don't subject authed clients to HELO tests since many
135             # (Outlook, OE) do not send a proper HELO. -twa, 2007-03-07
136 0         0 my @lines = (
137             $self->toaster->supervised_do_not_edit_notice(1),
138             $self->smtp_set_qmailqueue( prot => 'submit' ),
139             qq{export NOBADHELO=""\n\n},
140             );
141              
142             push @lines, $self->supervised_hostname_qmail( "submit" )
143 0 0       0 if $self->conf->{'submit_hostname'} eq "qmail";
144 0         0 push @lines, $self->_smtp_sanity_tests();
145              
146 0 0       0 my $exec = $self->toaster->supervised_tcpserver( "submit" ) or return;
147              
148 0         0 $exec .= "qmail-smtpd ";
149              
150 0 0       0 if ( $self->conf->{'submit_auth_enable'} ) {
151             $exec .= $self->toaster->supervised_hostname( "submit" )
152 0 0 0     0 if ( $self->conf->{'submit_hostname'} && $self->conf->{'qmail_smtpd_auth_0.31'} );
153              
154 0 0       0 my $chkpass = $self->_set_checkpasswd_bin( prot => 'submit' ) or return;
155 0         0 $exec .= "$chkpass /usr/bin/true ";
156             }
157              
158 0 0       0 $exec .= $self->toaster->supervised_log_method( "submit" ) or return;
159              
160 0         0 push @lines, $exec;
161              
162 0         0 my $file = '/tmp/toaster-watcher-submit-runfile';
163 0 0       0 $self->util->file_write( $file, lines => \@lines ) or return;
164 0 0       0 $self->install_supervise_run( tmpfile => $file, prot => 'submit' ) or return;
165 0         0 return 1;
166             }
167              
168             sub build_qmail_deliverable_run {
169 0     0 0 0 my $self = shift;
170 0         0 my $softlimit = $self->util->find_bin('softlimit');
171 0         0 my $qmdd = $self->util->find_bin('qmail-deliverabled');
172              
173 0         0 my @lines = "#!/bin/sh
174             MAXRAM=50000000
175             exec $softlimit -m \$MAXRAM $qmdd -f 2>&1
176             ";
177              
178 0         0 my $file = '/tmp/toaster-watcher-qmd-runfile';
179 0 0       0 $self->util->file_write( $file, lines => \@lines ) or return;
180 0 0       0 $self->install_supervise_run( tmpfile => $file, prot => 'qmail-deliverable' ) or return;
181 0         0 return 1;
182             };
183              
184             sub build_vpopmaild_run {
185 0     0 0 0 my $self = shift;
186              
187 0 0       0 if ( ! $self->conf->{vpopmail_daemon} ) {
188 0         0 $self->audit( "skipping vpopmaild/run" );
189 0         0 return;
190             };
191              
192 0         0 $self->audit( "generating vpopmaild/run..." );
193              
194 0         0 my $tcpserver = $self->util->find_bin('tcpserver');
195 0         0 my $vpopdir = $self->setup->vpopmail->get_vpop_dir;
196              
197 0         0 my @lines = $self->toaster->supervised_do_not_edit_notice;
198 0         0 push @lines, "#!/bin/sh
199             #exec 2>&1
200             exec 1>/dev/null 2>&1
201             exec $tcpserver -vHRD 127.0.0.1 89 $vpopdir/bin/vpopmaild
202             ";
203              
204 0         0 my $file = '/tmp/toaster-watcher-vpopmaild-runfile';
205 0 0       0 $self->util->file_write( $file, lines => \@lines, fatal => 0) or return;
206 0 0       0 $self->qmail->install_supervise_run( tmpfile => $file, prot => 'vpopmaild' ) or return;
207 0         0 return 1;
208             };
209              
210             sub build_qpsmtpd_run {
211 0     0 0 0 my $self = shift;
212             # unless/until there's not settings in toaster-watcher.conf, we'll assume the
213             # run file included with qpsmtpd is used
214 0         0 return 1;
215             };
216              
217             sub check_rcpthosts {
218 0     0 1 0 my ($self) = @_;
219 0         0 my $qmaildir = $self->get_qmail_dir;
220              
221 0 0       0 if ( !-d $qmaildir ) {
222 0         0 $self->audit( "check_rcpthost: oops! the qmail directory does not exist!");
223 0         0 return;
224             }
225              
226 0         0 my $assign = "$qmaildir/users/assign";
227 0         0 my $rcpt = "$qmaildir/control/rcpthosts";
228 0         0 my $mrcpt = "$qmaildir/control/morercpthosts";
229              
230             # make sure an assign and rcpthosts file exists.
231 0 0 0     0 unless ( -s $assign && -s $rcpt ) {
232 0         0 $self->audit("check_rcpthost: $assign or $rcpt is missing!");
233 0         0 return;
234             }
235              
236 0         0 my @domains = $self->get_domains_from_assign;
237              
238 0         0 print "check_rcpthosts: checking your rcpthost files.\n.";
239 0         0 my ( @f2, %rcpthosts, $domains, $count );
240              
241             # read in the contents of both rcpthosts files
242 0         0 my @f1 = $self->util->file_read( $rcpt );
243 0 0       0 @f2 = $self->util->file_read( $mrcpt )
244             if ( -e "$qmaildir/control/morercpthosts" );
245              
246             # put their contents into a hash
247 0         0 foreach ( @f1, @f2 ) { chomp $_; $rcpthosts{$_} = 1; }
  0         0  
  0         0  
248              
249             # and then for each domain in assign, make sure it is in rcpthosts
250 0         0 foreach (@domains) {
251 0         0 my $domain = $_->{'dom'};
252 0 0       0 unless ( $rcpthosts{$domain} ) {
253 0         0 print "\t$domain\n";
254 0         0 $count++;
255             }
256 0         0 $domains++;
257             }
258              
259 0 0 0     0 if ( ! $count || $count == 0 ) {
260 0         0 print "Congrats, your rcpthosts is correct!\n";
261 0         0 return 1;
262             }
263              
264 0 0       0 if ( $domains > 50 ) {
265 0         0 print
266             "\nDomains listed above should be added to $mrcpt. Don't forget to run 'qmail cdb' afterwards.\n";
267             }
268             else {
269 0         0 print "\nDomains listed above should be added to $rcpt. \n";
270             }
271             }
272              
273             sub config {
274 2     2 1 3 my $self = shift;
275 2         11 my %p = validate( @_, { $self->get_std_opts } );
276 2         10 my %args = $self->toaster->get_std_args( %p );
277 2 50       16 return $p{test_ok} if defined $p{test_ok};
278              
279 0         0 my $conf = $self->conf;
280 0         0 my $host = $conf->{toaster_hostname};
281 0 0       0 $host = hostname if $host =~ /(?:qmail|system)/;
282              
283 0         0 my $postmaster = $conf->{toaster_admin_email};
284 0   0     0 my $ciphers = $conf->{openssl_ciphers} || 'pci';
285              
286 0 0       0 if ( $ciphers =~ /^[a-z]+$/ ) {
287 0         0 $ciphers = $self->setup->openssl_get_ciphers( $ciphers );
288             };
289              
290             my @changes = (
291             { file => 'control/me', setting => $host, },
292             { file => 'control/concurrencyremote', setting => $conf->{'qmail_concurrencyremote'},},
293             { file => 'control/mfcheck', setting => $conf->{'qmail_mfcheck_enable'}, },
294             { file => 'control/tarpitcount', setting => $conf->{'qmail_tarpit_count'}, },
295             { file => 'control/tarpitdelay', setting => $conf->{'qmail_tarpit_delay'}, },
296 0         0 { file => 'control/spfbehavior', setting => $conf->{'qmail_spf_behavior'}, },
297             { file => 'alias/.qmail-postmaster', setting => $postmaster, },
298             { file => 'alias/.qmail-root', setting => $postmaster, },
299             { file => 'alias/.qmail-mailer-daemon', setting => $postmaster, },
300             { file => 'control/tlsserverciphers', setting => $ciphers },
301             { file => 'control/tlsclientciphers', setting => $ciphers },
302             );
303              
304 0 0       0 push @changes, $self->control_sql if $conf->{vpopmail_mysql};
305              
306 0         0 $self->config_write( \@changes );
307              
308 0         0 my $uid = getpwnam('vpopmail');
309 0         0 my $gid = getgrnam('vchkpw');
310              
311 0         0 my $control = $self->get_control_dir;
312 0         0 chown( $uid, $gid, "$control/servercert.pem" );
313 0         0 chown( $uid, $gid, "$control/sql" );
314 0         0 chmod oct('0640'), "$control/servercert.pem";
315 0         0 chmod oct('0640'), "$control/clientcert.pem";
316 0         0 chmod oct('0640'), "$control/sql";
317 0         0 chmod oct('0644'), "$control/concurrencyremote";
318              
319 0 0       0 $self->config_freebsd if $OSNAME eq 'freebsd';
320              
321             # qmail control script (qmail cdb, qmail restart, etc)
322 0         0 $self->control_create( %args );
323              
324             # create all the service and supervised dirs
325 0         0 $self->toaster->service_dir_create( %args );
326 0         0 $self->toaster->supervise_dirs_create( %args );
327              
328             # install the supervised control files
329 0         0 $self->install_qmail_control_files( %args );
330 0         0 $self->install_qmail_control_log_files( %args );
331             }
332              
333             sub config_freebsd {
334 0     0 0 0 my $self = shift;
335 0   0     0 my $tmp = $self->conf->{'toaster_tmp_dir'} || "/tmp";
336              
337             # disable sendmail
338 0         0 $self->freebsd->conf_check(
339             check => "sendmail_enable",
340             line => 'sendmail_enable="NONE"',
341             );
342              
343             # don't build sendmail when we rebuild the world
344 0 0       0 $self->util->file_write( "/etc/make.conf",
345             lines => ["NO_SENDMAIL=true"],
346             append => 1,
347             )
348             if ! `grep NO_SENDMAIL /etc/make.conf`;
349              
350             # make sure mailer.conf is set up for qmail
351 0         0 my $tmp_mailer_conf = "$tmp/mailer.conf";
352 0         0 my $qmdir = $self->get_qmail_dir;
353 0   0     0 my $maillogs = $self->util->find_bin('maillogs',fatal=>0 )
354             || '/usr/local/bin/maillogs';
355 0 0       0 open my $MAILER_CONF, '>', $tmp_mailer_conf
356             or $self->error( "unable to open $tmp_mailer_conf: $!",fatal=>0);
357              
358 0         0 print $MAILER_CONF "
359             # \$FreeBSD: release/9.1.0/etc/mail/mailer.conf 93858 2002-04-05 04:25:14Z gshapiro \$
360             #
361             sendmail $qmdir/bin/sendmail
362             send-mail $qmdir/bin/sendmail
363             mailq $maillogs yesterday
364             #mailq $qmdir/bin/qmail-qread
365             newaliases $qmdir/bin/newaliases
366             hoststat $qmdir/bin/qmail-tcpto
367             purgestat $qmdir/bin/qmail-tcpok
368             #
369             # Execute the \"real\" sendmail program, named /usr/libexec/sendmail/sendmail
370             #
371             #sendmail /usr/libexec/sendmail/sendmail
372             #send-mail /usr/libexec/sendmail/sendmail
373             #mailq /usr/libexec/sendmail/sendmail
374             #newaliases /usr/libexec/sendmail/sendmail
375             #hoststat /usr/libexec/sendmail/sendmail
376             #purgestat /usr/libexec/sendmail/sendmail
377              
378             ";
379              
380 0         0 $self->util->install_if_changed(
381             newfile => $tmp_mailer_conf,
382             existing => "/etc/mail/mailer.conf",
383             notify => 1,
384             clean => 1,
385             );
386 0         0 close $MAILER_CONF;
387             };
388              
389             sub config_write {
390 0     0 0 0 my $self = shift;
391 0         0 my $changes = shift;
392              
393 0         0 my $qdir = $self->get_qmail_dir;
394 0         0 my $control = "$qdir/control";
395 0 0       0 $self->util->file_write( "$control/locals", lines => ["\n"] )
396             if ! -e "$control/locals";
397              
398 0         0 foreach my $change (@$changes) {
399 0         0 my $file = $change->{'file'};
400 0         0 my $value = $change->{'setting'};
401              
402 0 0       0 if ( -e "$qdir/$file" ) {
403 0         0 my @now = $self->util->file_read( "$qdir/$file" );
404 0 0 0     0 if ( @now && $now[0] && $now[0] eq $value ) {
      0        
405 0 0       0 $self->audit( "config_write: $file to '$value', ok (same)" ) if $value !~ /pass/;
406 0         0 next;
407             };
408             }
409             else {
410 0         0 $self->util->file_write( "$qdir/$file", lines => [$value] );
411 0 0       0 $self->audit( "config: set $file to '$value'" ) if $value !~ /pass/;
412 0         0 next;
413             };
414              
415 0         0 $self->util->file_write( "$qdir/$file.tmp", lines => [$value] );
416              
417 0         0 my $r = $self->util->install_if_changed(
418             newfile => "$qdir/$file.tmp",
419             existing => "$qdir/$file",
420             clean => 1,
421             notify => 1,
422             verbose => 0
423             );
424 0 0       0 if ($r) { $r = $r == 1 ? "ok" : "ok (same)"; }
  0 0       0  
425 0         0 else { $r = "FAILED"; }
426              
427 0 0       0 $self->audit( "config: setting $file to '$value', $r" ) if $value !~ /pass/;
428             };
429              
430 0         0 my $manpath = "/etc/manpath.config";
431 0 0       0 if ( -e $manpath ) {
432 0 0       0 unless (`grep "$qdir/man" $manpath | grep -v grep`) {
433 0         0 $self->util->file_write( $manpath,
434             lines => ["OPTIONAL_MANPATH\t\t$qdir/man"],
435             append => 1,
436             );
437 0         0 $self->audit( "appended $qdir/man to MANPATH" );
438             }
439             }
440             };
441              
442             sub control_sql {
443 0     0 0 0 my $self = shift;
444 0         0 my $conf = $self->conf;
445              
446             my $dbhost = $conf->{vpopmail_mysql_repl_slave}
447 0 0       0 or die "missing db hostname\n";
448             my $dbport = $conf->{vpopmail_mysql_repl_slave_port}
449 0 0       0 or die "missing db server port\n";
450             my $dbname = $conf->{vpopmail_mysql_database}
451 0 0       0 or die "missing db name\n";
452             my $dbuser = $conf->{vpopmail_mysql_user}
453 0 0       0 or die "missing vpopmail SQL username\n";
454             my $password = $conf->{vpopmail_mysql_pass}
455 0 0       0 or die "missing vpopmail SQL pass\n";
456              
457             return {
458 0         0 file => 'control/sql',
459             setting => "server $dbhost
460             port $dbport
461             database $dbname
462             table relay
463             user $dbuser
464             pass $password
465             time 1800
466             ",
467             };
468             };
469              
470             sub control_create {
471 2     2 1 4 my $self = shift;
472 2         6 my %p = validate( @_, { $self->get_std_opts } );
473              
474 2         9 my $conf = $self->conf;
475 2         4 my $qmaildir = $self->get_qmail_dir;
476 2   50     6 my $confdir = $conf->{system_config_dir} || '/usr/local/etc';
477 2   50     6 my $tmp = $conf->{toaster_tmp_dir} || '/tmp';
478 2   50     6 my $prefix = $conf->{toaster_prefix} || '/usr/local';
479              
480 2         4 my $qmailctl = "$qmaildir/bin/qmailctl";
481              
482 2 50       11 return $p{test_ok} if defined $p{test_ok};
483              
484             # install a new qmailcontrol if newer than existing one.
485 0         0 $self->control_write( "$tmp/qmailctl", %p );
486 0         0 my $r = $self->util->install_if_changed(
487             newfile => "$tmp/qmailctl",
488             existing => $qmailctl,
489             mode => '0755',
490             notify => 1,
491             clean => 1,
492             );
493              
494 0 0       0 if ($r) { $r = $r == 1 ? 'ok' : "ok (same)"; } else { $r = "FAILED"; };
  0 0       0  
  0         0  
495              
496 0         0 $self->audit( "control_create: installed $qmaildir/bin/qmailctl, $r" );
497              
498 0         0 $self->util->syscmd( "$qmailctl cdb", verbose=>0 );
499              
500             # create aliases
501 0         0 foreach my $shortcut ( "$prefix/sbin/qmail", "$prefix/sbin/qmailctl" ) {
502 0 0       0 next if -l $shortcut;
503 0 0       0 if ( -e $shortcut ) {
504 0         0 $self->audit( "updating $shortcut.");
505 0         0 unlink $shortcut;
506 0 0       0 symlink( "$qmaildir/bin/qmailctl", $shortcut )
507             or $self->error( "couldn't link $shortcut: $!");
508             }
509             else {
510 0         0 $self->audit( "control_create: adding symlink $shortcut");
511 0 0       0 symlink( "$qmaildir/bin/qmailctl", $shortcut )
512             or $self->error( "couldn't link $shortcut: $!");
513             }
514             }
515              
516 0 0       0 if ( -e "$qmaildir/rc" ) {
517 0         0 $self->audit( "control_create: $qmaildir/rc already exists.");
518             }
519             else {
520 0         0 $self->build_send_run();
521 0         0 my $dir = $self->toaster->supervise_dir_get( 'send' );
522 0 0       0 copy( "$dir/run", "$qmaildir/rc" ) and
523             $self->audit( "control_create: created $qmaildir/rc.");
524 0         0 chmod oct('0755'), "$qmaildir/rc";
525             }
526              
527             # the FreeBSD port used to install this
528 0 0       0 if ( -e "$confdir/rc.d/qmail.sh" ) {
529 0 0       0 unlink("$confdir/rc.d/qmail.sh")
530             or $self->error( "couldn't delete $confdir/rc.d/qmail.sh: $!");
531             }
532             }
533              
534             sub control_write {
535 0     0 0 0 my $self = shift;
536 0 0       0 my $file = shift or die "missing file name";
537 0         0 my %p = validate( @_, { $self->get_std_opts } );
538              
539 0 0       0 open ( my $FILE_HANDLE, '>', $file ) or
540             return $self->error( "failed to open $file: $!" );
541              
542 0         0 my $qdir = $self->get_qmail_dir;
543 0   0     0 my $prefix = $self->conf->{'toaster_prefix'} || "/usr/local";
544 0         0 my $tcprules = $self->util->find_bin( 'tcprules', %p );
545 0         0 my $svc = $self->util->find_bin( 'svc', %p );
546 0         0 my $vpopetc = $self->setup->vpopmail->get_vpop_etc;
547              
548 0         0 print $FILE_HANDLE <<EOQMAILCTL;
549             #!/bin/sh
550              
551             PATH=$qdir/bin:$prefix/bin:/usr/bin:/bin
552             export PATH
553              
554             case "\$1" in
555             stat)
556             cd $qdir/supervise
557             svstat * */log
558             ;;
559             doqueue|alrm|flush)
560             echo "Sending ALRM signal to qmail-send."
561             $svc -a $qdir/supervise/send
562             ;;
563             queue)
564             qmail-qstat
565             qmail-qread
566             ;;
567             reload|hup)
568             echo "Sending HUP signal to qmail-send."
569             $svc -h $qdir/supervise/send
570             ;;
571             pause)
572             echo "Pausing qmail-send"
573             $svc -p $qdir/supervise/send
574             echo "Pausing qmail-smtpd"
575             $svc -p $qdir/supervise/smtp
576             ;;
577             cont)
578             echo "Continuing qmail-send"
579             $svc -c $qdir/supervise/send
580             echo "Continuing qmail-smtpd"
581             $svc -c $qdir/supervise/smtp
582             ;;
583             restart)
584             echo "Restarting qmail:"
585             echo "* Stopping qmail-smtpd."
586             $svc -d $qdir/supervise/smtp
587             echo "* Sending qmail-send SIGTERM and restarting."
588             $svc -t $qdir/supervise/send
589             echo "* Restarting qmail-smtpd."
590             $svc -u $qdir/supervise/smtp
591             ;;
592             cdb)
593             if [ -s $vpopetc/tcp.smtp ]
594             then
595             $tcprules $vpopetc/tcp.smtp.cdb $vpopetc/tcp.smtp.tmp < $vpopetc/tcp.smtp
596             chmod 644 $vpopetc/tcp.smtp*
597             echo "Reloaded $vpopetc/tcp.smtp."
598             fi
599              
600             if [ -s $vpopetc/tcp.submit ]
601             then
602             $tcprules $vpopetc/tcp.submit.cdb $vpopetc/tcp.submit.tmp < $vpopetc/tcp.submit
603             chmod 644 $vpopetc/tcp.submit*
604             echo "Reloaded $vpopetc/tcp.submit."
605             fi
606              
607             if [ -s /etc/tcp.smtp ]
608             then
609             $tcprules /etc/tcp.smtp.cdb /etc/tcp.smtp.tmp < /etc/tcp.smtp
610             chmod 644 /etc/tcp.smtp*
611             echo "Reloaded /etc/tcp.smtp."
612             fi
613              
614             if [ -s $qdir/control/simcontrol ]
615             then
616             if [ -x $qdir/bin/simscanmk ]
617             then
618             $qdir/bin/simscanmk
619             echo "Reloaded $qdir/control/simcontrol."
620             $qdir/bin/simscanmk -g
621             echo "Reloaded $qdir/control/simversions."
622             fi
623             fi
624              
625             if [ -s $qdir/users/assign ]
626             then
627             if [ -x $qdir/bin/qmail-newu ]
628             then
629             echo "Reloaded $qdir/users/assign."
630             fi
631             fi
632              
633             if [ -s $qdir/control/morercpthosts ]
634             then
635             if [ -x $qdir/bin/qmail-newmrh ]
636             then
637             $qdir/bin/qmail-newmrh
638             echo "Reloaded $qdir/control/morercpthosts"
639             fi
640             fi
641              
642             if [ -s $qdir/control/spamt ]
643             then
644             if [ -x $qdir/bin/qmail-newst ]
645             then
646             $qdir/bin/qmail-newst
647             echo "Reloaded $qdir/control/spamt"
648             fi
649             fi
650             ;;
651             help)
652             cat <<HELP
653             pause -- temporarily stops mail service (connections accepted, nothing leaves)
654             cont -- continues paused mail service
655             stat -- displays status of mail service
656             cdb -- rebuild the cdb files (tcp.smtp, users, simcontrol)
657             restart -- stops and restarts smtp, sends qmail-send a TERM & restarts it
658             doqueue -- sends qmail-send ALRM, scheduling queued messages for delivery
659             reload -- sends qmail-send HUP, rereading locals and virtualdomains
660             queue -- shows status of queue
661             alrm -- same as doqueue
662             hup -- same as reload
663             HELP
664             ;;
665             *)
666             echo "Usage: \$0 {restart|doqueue|flush|reload|stat|pause|cont|cdb|queue|help}"
667             exit 1
668             ;;
669             esac
670              
671             exit 0
672              
673             EOQMAILCTL
674              
675 0         0 close $FILE_HANDLE;
676             }
677              
678             sub get_domains_from_assign {
679 2     2 1 4 my $self = shift;
680 2         13 my %p = validate ( @_, {
681             'match' => { type=>SCALAR, optional=>1, },
682             'value' => { type=>SCALAR, optional=>1, },
683             $self->get_std_opts,
684             },
685             );
686              
687 2         33 my %args = $self->get_std_args( %p );
688             my ( $match, $value, $fatal, $verbose )
689 2         6 = ( $p{match}, $p{value}, $p{fatal}, $p{verbose} );
690              
691 2         5 my $qdir = $self->get_qmail_dir;
692 2         5 my $assign = "$qdir/users/assign";
693              
694 2 50       20 return $p{test_ok} if defined $p{test_ok};
695              
696 0 0       0 return $self->error( "the file $assign is missing or empty!", %args )
697             if ! -s $assign;
698              
699 0         0 my @domains;
700 0         0 my @lines = $self->util->file_read( $assign );
701              
702 0         0 foreach my $line (@lines) {
703 0         0 chomp $line;
704 0         0 my @fields = split( /:/, $line );
705 0 0 0     0 if ( $fields[0] ne "" && $fields[0] ne "." ) {
706 0         0 my %domain = (
707             stat => $fields[0],
708             dom => $fields[1],
709             uid => $fields[2],
710             gid => $fields[3],
711             dir => $fields[4],
712             );
713              
714 0 0       0 if (! $match) { push @domains, \%domain; next; };
  0         0  
  0         0  
715              
716 0 0 0     0 if ( $match eq "dom" && $value eq "$fields[1]" ) {
    0 0        
    0 0        
717 0         0 push @domains, \%domain;
718             }
719             elsif ( $match eq "uid" && $value eq "$fields[2]" ) {
720 0         0 push @domains, \%domain;
721             }
722             elsif ( $match eq "dir" && $value eq "$fields[4]" ) {
723 0         0 push @domains, \%domain;
724             }
725             }
726             }
727 0         0 return @domains;
728             }
729              
730             sub get_list_of_rbls {
731 4     4 1 23 my $self = shift;
732 4         19 my %p = validate( @_, { $self->get_std_opts } );
733              
734             # two arrays, one for sorted elements, one for unsorted
735 4         18 my ( @sorted, @unsorted );
736 0         0 my ( @list, %sort_keys, $sort );
737              
738 4         4 foreach my $key ( keys %{$self->conf} ) {
  4         8  
739              
740             # ignore everything that doesn't start wih rbl
741 4 50       26 next unless ( $key =~ /^rbl/ );
742              
743             # ignore other similar keys in $conf
744 4 50       10 next if ( $key =~ /^rbl_enable/ );
745 4 50       11 next if ( $key =~ /^rbl_reverse_dns/ );
746 4 50       10 next if ( $key =~ /^rbl_timeout/ );
747 4 100       15 next if ( $key =~ /_message$/ ); # RBL custom reject messages
748 3 100       6 next if ( $self->conf->{$key} == 0 ); # not enabled
749              
750 2         9 $key =~ /^rbl_([a-zA-Z0-9\.\-]*)\s*$/;
751              
752 2         16 $self->audit( "good key: $1 ");
753              
754             # test for custom sort key
755 2 100       6 if ( $self->conf->{$key} > 1 ) {
756 1         7 $self->audit( " sorted value ".$self->conf->{$key} );
757 1         5 @sorted[ $self->conf->{$key} - 2 ] = $1;
758             }
759             else {
760 1         3 $self->audit( " unsorted, ".$self->conf->{$key} );
761 1         3 push @unsorted, $1;
762             }
763             }
764              
765             # add the unsorted values to the sorted list
766 4         9 push @sorted, @unsorted;
767 4         7 @sorted = grep { defined $_ } @sorted; # weed out blanks
  2         7  
768 4         10 @sorted = grep { $_ =~ /\S/ } @sorted;
  2         10  
769              
770 4         18 $self->audit( "sorted order: " . join( "\n\t", @sorted ) );
771              
772             # test each RBL in the list
773 4 50       14 my $good_rbls = $self->test_each_rbl( rbls => \@sorted ) or return q{};
774              
775             # format them for use in a supervised (daemontools) run file
776 4         7 my $string_of_rbls;
777 4         7 foreach (@$good_rbls) {
778 2         15 my $mess = $self->conf->{"rbl_${_}_message"};
779 2         7 $string_of_rbls .= " \\\n\t\t-r $_";
780 2 50 33     13 if ( defined $mess && $mess ) {
781 0         0 $string_of_rbls .= ":'$mess'";
782             }
783             }
784              
785 4         12 $self->audit( $string_of_rbls );
786 4         25 return $string_of_rbls;
787             }
788              
789             sub get_list_of_rwls {
790 3     3 1 14 my $self = shift;
791 3         24 my %p = validate( @_, { $self->get_std_opts } );
792              
793 3         10 my @list;
794              
795 3         2 foreach my $key ( keys %{$self->conf} ) {
  3         6  
796              
797 3 100 66     19 next unless ( $key =~ /^rwl/ && $self->conf->{$key} == 1 );
798 2 50       7 next if ( $key =~ /^rwl_enable/ );
799              
800 2         5 $key =~ /^rwl_([a-zA-Z_\.\-]*)\s*$/;
801              
802 2         17 $self->audit( "good key: $1");
803 2         5 push @list, $1;
804             }
805 3         9 return \@list;
806             }
807              
808             sub get_qmailscanner_virus_sender_ips {
809              
810             # deprecated function
811              
812 0     0 0 0 my $self = shift;
813 0         0 my @ips;
814              
815 0         0 my $verbose = $self->conf->{verbose};
816 0         0 my $block = $self->conf->{qs_block_virus_senders};
817 0         0 my $clean = $self->conf->{qs_quarantine_clean};
818 0         0 my $quarantine = $self->conf->{qs_quarantine_dir};
819              
820 0 0       0 if (! -d $quarantine ) {
821 0 0       0 $quarantine = "/var/spool/qmailscan/quarantine"
822             if -d "/var/spool/qmailscan/quarantine";
823             }
824              
825 0 0       0 return $self->error( "no quarantine dir!") if ! -d "$quarantine/new";
826 0         0 my @files = $self->util->get_dir_files( "$quarantine/new" );
827              
828 0         0 foreach my $file (@files) {
829 0 0       0 if ($block) {
830 0         0 my $ipline = `head -n 10 $file | grep HELO`;
831 0         0 chomp $ipline;
832              
833 0 0       0 next unless ($ipline);
834 0 0       0 print " $ipline - " if $verbose;
835              
836 0         0 my @lines = split( /Received/, $ipline );
837 0         0 foreach my $line (@lines) {
838 0 0       0 print $line if $verbose;
839              
840             # Received: from unknown (HELO netbible.org) (202.54.63.141)
841 0         0 my ($ip) = $line =~ /([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/;
842              
843             # check the message and verify that it's
844             # a blocked virus, not an admin testing
845             # (Matt 4/3/2004)
846              
847 0 0 0     0 if ( $ip =~ /\s+/ or !$ip ) { print "$line\n" if $verbose; }
  0 0       0  
848 0         0 else { push @ips, $ip; }
849 0 0       0 print "\t$ip" if $verbose;
850             }
851 0 0       0 print "\n" if $verbose;
852             }
853 0 0       0 unlink $file if $clean;
854             }
855              
856 0         0 my ( %hash, @sorted );
857 0         0 foreach (@ips) { $hash{$_} = "1"; }
  0         0  
858 0         0 foreach ( keys %hash ) { push @sorted, $_; delete $hash{$_} }
  0         0  
  0         0  
859 0 0       0 $self->audit( "found " . scalar @sorted . " infected files" ) if scalar @sorted;
860 0         0 return @sorted;
861             }
862              
863             sub get_supervise_dir {
864 11     11 0 12 my $self = shift;
865 11   33     25 my $dir = $self->conf->{qmail_supervise} || $self->get_qmail_dir . '/supervise';
866 11 100       166 if ( ! -d $dir ) {
867 1         5 $self->util->mkdir_system( dir => $dir, fatal => 0 );
868             };
869 11 50       103 return $dir if -d $dir;
870 0         0 $self->error( "$dir does not exist!",fatal=>0);
871 0         0 return $dir;
872             };
873              
874             sub get_qmail_dir {
875 10     10 0 24 my $self = shift;
876 10   50     26 return $self->conf->{'qmail_dir'} || '/var/qmail';
877             };
878              
879             sub get_control_dir {
880 1     1 0 4 my $self = shift;
881 1         2 my $qmail_dir = $self->get_qmail_dir;
882 1         4 return "$qmail_dir/control";
883             };
884              
885             sub install_qmail {
886 2     2 1 4 my $self = shift;
887 2         11 my %p = validate( @_, {
888             'package' => { type=>SCALAR, optional=>1, },
889             $self->get_std_opts,
890             },
891             );
892              
893 2         11 my $package = $p{'package'};
894              
895 2         2 my ( $patch, $chkusr );
896              
897 2 50       19 return $p{'test_ok'} if defined $p{'test_ok'};
898              
899             # redirect if netqmail is selected
900 0 0       0 if ( $self->conf->{'install_netqmail'} ) {
901 0         0 return $self->netqmail();
902             }
903              
904 0 0       0 my $ver = $self->conf->{'install_qmail'} or do {
905 0         0 print "install_qmail: installation disabled in .conf, SKIPPING";
906 0         0 return;
907             };
908              
909 0         0 $self->install_qmail_groups_users();
910              
911 0   0     0 $package ||= "qmail-$ver";
912              
913 0   0     0 my $src = $self->conf->{'toaster_src_dir'} || "/usr/local/src";
914 0         0 my $qmaildir = $self->get_qmail_dir;
915 0         0 my $vpopdir = $self->setup->vpopmail->get_vpop_dir;
916 0   0     0 my $mysql = $self->conf->{'qmail_mysql_include'}
917             || "/usr/local/lib/mysql/libmysqlclient.a";
918 0   0     0 my $dl_site = $self->conf->{'toaster_dl_site'} || "http://www.tnpi.net";
919 0   0     0 my $dl_url = $self->conf->{'toaster_dl_url'} || "/internet/mail/toaster";
920 0         0 my $toaster_url = "$dl_site$dl_url";
921              
922 0         0 $self->util->cwd_source_dir( "$src/mail" );
923              
924 0 0       0 if ( -e $package ) {
925 0 0       0 unless ( $self->util->source_warning( package=>$package, src=>$src ) ) {
926 0         0 warn "install_qmail: FATAL: sorry, I can't continue.\n";
927 0         0 return;
928             }
929             }
930              
931 0 0       0 unless ( defined $self->conf->{'qmail_chk_usr_patch'} ) {
932 0         0 print "\nCheckUser support causes the qmail-smtpd daemon to verify that
933             a user exists locally before accepting the message, during the SMTP conversation.
934             This prevents your mail server from accepting messages to email addresses that
935             don't exist in vpopmail. It is not compatible with system user mailboxes. \n\n";
936              
937 0         0 $chkusr =
938             $self->util->yes_or_no( "Do you want qmail-smtpd-chkusr support enabled?" );
939             }
940             else {
941 0 0       0 if ( $self->conf->{'qmail_chk_usr_patch'} ) {
942 0         0 $chkusr = 1;
943 0         0 print "chk-usr patch: yes\n";
944             }
945             }
946              
947 0 0       0 if ($chkusr) { $patch = "$package-toaster-2.8.patch"; }
  0         0  
948 0         0 else { $patch = "$package-toaster-2.6.patch"; }
949              
950 0         0 my $site = "http://cr.yp.to/software";
951              
952 0 0       0 unless ( -e "$package.tar.gz" ) {
953 0 0       0 if ( -e "/usr/ports/distfiles/$package.tar.gz" ) {
954 4     4   17631 use File::Copy;
  4         6  
  4         23300  
955 0         0 copy( "/usr/ports/distfiles/$package.tar.gz",
956             "$src/mail/$package.tar.gz" );
957             }
958             else {
959 0         0 $self->util->get_url( "$site/$package.tar.gz" );
960 0 0       0 unless ( -e "$package.tar.gz" ) {
961 0         0 die "install_qmail FAILED: couldn't fetch $package.tar.gz!\n";
962             }
963             }
964             }
965              
966 0 0       0 unless ( -e $patch ) {
967 0         0 $self->util->get_url( "$toaster_url/patches/$patch" );
968 0 0       0 unless ( -e $patch ) { die "\n\nfailed to fetch patch $patch!\n\n"; }
  0         0  
969             }
970              
971 0         0 my $tar = $self->util->find_bin( "tar" );
972 0         0 my $patchbin = $self->util->find_bin( "patch" );
973 0 0 0     0 unless ( $tar && $patchbin ) { die "couldn't find tar or patch!\n"; }
  0         0  
974              
975 0         0 $self->util->syscmd( "$tar -xzf $package.tar.gz" );
976 0 0       0 chdir("$src/mail/$package")
977             or die "install_qmail: cd $src/mail/$package failed: $!\n";
978 0         0 $self->util->syscmd( "$patchbin < $src/mail/$patch" );
979              
980 0 0       0 $self->util->file_write( "conf-qmail", lines => [$qmaildir] )
981             or die "couldn't write to conf-qmail: $!";
982              
983 0 0       0 $self->util->file_write( "conf-vpopmail", lines => [$vpopdir] )
984             or die "couldn't write to conf-vpopmail: $!";
985              
986 0 0       0 $self->util->file_write( "conf-mysql", lines => [$mysql] )
987             or die "couldn't write to conf-mysql: $!";
988              
989 0         0 my $servicectl = "/usr/local/sbin/services";
990              
991 0 0       0 if ( -x $servicectl ) {
992              
993 0         0 print "Stopping Qmail!\n";
994 0         0 $self->util->syscmd( "$servicectl stop" );
995 0         0 $self->send_stop();
996             }
997              
998 0         0 my $make = $self->util->find_bin( "gmake", fatal => 0 );
999 0   0     0 $make ||= $self->util->find_bin( "make" );
1000              
1001 0         0 $self->util->syscmd( "$make setup" );
1002              
1003 0 0       0 unless ( -f "$qmaildir/control/servercert.pem" ) {
1004 0         0 $self->util->syscmd( "$make cert" );
1005             }
1006              
1007 0 0       0 if ($chkusr) {
1008 0         0 $self->util->chown( "$qmaildir/bin/qmail-smtpd",
1009             uid => 'vpopmail',
1010             gid => 'vchkpw',
1011             );
1012              
1013 0         0 $self->util->chmod( file => "$qmaildir/bin/qmail-smtpd",
1014             mode => '6555',
1015             );
1016             }
1017              
1018 0 0       0 unless ( -e "/usr/share/skel/Maildir" ) {
1019              
1020             # deprecated, not necessary unless using system accounts
1021             # $self->util->syscmd( "$qmaildir/bin/maildirmake /usr/share/skel/Maildir" );
1022             }
1023              
1024 0         0 $self->config();
1025              
1026 0 0       0 if ( -x $servicectl ) {
1027 0         0 print "Starting Qmail & supervised services!\n";
1028 0         0 $self->util->syscmd( "$servicectl start" );
1029             }
1030             }
1031              
1032             sub install_qmail_control_files {
1033 2     2 1 3 my $self = shift;
1034 2         7 my %p = validate( @_, { $self->get_std_opts } );
1035              
1036 2         10 my $supervise = $self->get_supervise_dir;
1037              
1038 2 50       23 return $p{'test_ok'} if defined $p{'test_ok'};
1039              
1040 0         0 foreach my $prot ( $self->toaster->get_daemons(1) ) {
1041 0         0 my $supdir = $self->toaster->supervise_dir_get( $prot);
1042 0         0 my $run_f = "$supdir/run";
1043              
1044 0 0       0 if ( -e $run_f ) {
1045 0         0 $self->audit( "install_qmail_control_files: $run_f already exists!");
1046 0         0 next;
1047             }
1048              
1049 0 0       0 if ( $prot eq "smtp" ) { $self->build_smtp_run }
  0 0       0  
    0          
    0          
    0          
    0          
    0          
1050 0         0 elsif ( $prot eq "send" ) { $self->build_send_run }
1051 0         0 elsif ( $prot eq "pop3" ) { $self->build_pop3_run }
1052 0         0 elsif ( $prot eq "submit" ) { $self->build_submit_run }
1053 0         0 elsif ( $prot eq "qmail-deliverable" ) { $self->build_qmail_deliverable_run }
1054 0         0 elsif ( $prot eq "vpopmaild" ) { $self->build_vpopmaild_run }
1055 0         0 elsif ( $prot eq "qpsmtpd" ) { $self->build_qpsmtpd_run }
1056 0         0 else { $self->error("I need help making run for $prot!"); };
1057             }
1058             }
1059              
1060             sub install_qmail_groups_users {
1061 2     2 0 4 my $self = shift;
1062 2         6 my %p = validate( @_, { $self->get_std_opts } );
1063              
1064 2         7 my $err = "ERROR: You need to update your toaster-watcher.conf file!\n";
1065              
1066 2   50     4 my $qmailg = $self->conf->{'qmail_group'} || 'qmail';
1067 2   50     4 my $alias = $self->conf->{'qmail_user_alias'} || 'alias';
1068 2   50     4 my $qmaild = $self->conf->{'qmail_user_daemon'} || 'qmaild';
1069 2   50     6 my $qmailp = $self->conf->{'qmail_user_passwd'} || 'qmailp';
1070 2   50     5 my $qmailq = $self->conf->{'qmail_user_queue'} || 'qmailq';
1071 2   50     5 my $qmailr = $self->conf->{'qmail_user_remote'} || 'qmailr';
1072 2   50     3 my $qmails = $self->conf->{'qmail_user_send'} || 'qmails';
1073 2   50     3 my $qmaill = $self->conf->{'qmail_user_log'} || 'qmaill';
1074 2   50     3 my $nofiles = $self->conf->{'qmail_log_group'} || 'nofiles';
1075              
1076 2 50       11 return $p{'test_ok'} if defined $p{'test_ok'};
1077              
1078 0         0 my $uid = 81;
1079 0         0 my $gid = 81;
1080              
1081 0 0       0 if ( $OSNAME eq 'darwin' ) { $uid = $gid = 200; }
  0         0  
1082              
1083 0         0 $self->setup->group_add( 'qnofiles', $gid );
1084 0         0 $self->setup->group_add( $qmailg, $gid + 1 );
1085              
1086 0         0 my $homedir = $self->get_qmail_dir;
1087              
1088 0         0 $self->setup->user_add($alias, $uid, $gid, homedir => "$homedir/alias" );
1089 0         0 $uid++;
1090 0         0 $self->setup->user_add($qmaild, $uid, $gid, homedir => $homedir );
1091 0         0 $uid++;
1092 0         0 $self->setup->user_add($qmaill, $uid, $gid, homedir => $homedir );
1093 0         0 $uid++;
1094 0         0 $self->setup->user_add($qmailp, $uid, $gid, homedir => $homedir );
1095 0         0 $uid++;
1096 0         0 $gid++;
1097 0         0 $self->setup->user_add($qmailq, $uid, $gid, homedir => $homedir );
1098 0         0 $uid++;
1099 0         0 $self->setup->user_add($qmailr, $uid, $gid, homedir => $homedir );
1100 0         0 $uid++;
1101 0         0 $self->setup->user_add($qmails, $uid, $gid, homedir => $homedir );
1102             }
1103              
1104             sub install_supervise_run {
1105 2     2 1 3 my $self = shift;
1106 2         32 my %p = validate( @_, {
1107             'tmpfile' => { type=>SCALAR, },
1108             'destination' => { type=>SCALAR, optional=>1, },
1109             'prot' => { type=>SCALAR, optional=>1, },
1110             $self->get_std_opts,
1111             },
1112             );
1113 2         10 my %args = $self->toaster->get_std_args( %p );
1114              
1115 2 50       13 return $p{test_ok} if defined $p{test_ok};
1116              
1117             my ( $tmpfile, $destination, $prot )
1118 0         0 = ( $p{tmpfile}, $p{destination}, $p{prot} );
1119              
1120 0 0       0 if ( !$destination ) {
1121 0 0       0 return $self->error( "you didn't set destination or prot!", %args ) if !$prot;
1122              
1123 0 0       0 my $dir = $self->toaster->supervise_dir_get( $prot )
1124             or return $self->error( "no sup dir for $prot found", %args );
1125 0         0 $destination = "$dir/run";
1126             }
1127              
1128 0 0       0 return $self->error( "the new file ($tmpfile) is missing!",%args)
1129             if !-e $tmpfile;
1130              
1131 0 0       0 my $s = -e $destination ? 'updating' : 'installing';
1132 0         0 $self->audit( "install_supervise_run: $s $destination");
1133              
1134             return $self->util->install_if_changed(
1135             existing => $destination, newfile => $tmpfile,
1136             mode => '0755', clean => 1,
1137             notify => $self->conf->{supervise_rebuild_notice} || 1,
1138 0   0     0 email => $self->conf->{toaster_admin_email} || 'postmaster',
      0        
1139             %args,
1140             );
1141             }
1142              
1143             sub install_qmail_control_log_files {
1144 2     2 1 2 my $self = shift;
1145 2         12 my %p = validate( @_, {
1146             prots => {
1147             type=>ARRAYREF, optional=>1,
1148             default=>['smtp', 'send', 'pop3', 'submit'],
1149             },
1150             $self->get_std_opts,
1151             },
1152             );
1153              
1154 2         10 my %args = $self->toaster->get_std_args( %p );
1155 2         4 my $prots = $p{prots};
1156 2 50       5 push @$prots, "vpopmaild" if $self->conf->{vpopmail_daemon};
1157              
1158 2         5 my $supervise = $self->get_supervise_dir;
1159              
1160 2         5 my %valid_prots = map { $_ => 1 } qw/ smtp send pop3 submit vpopmaild /;
  10         15  
1161              
1162 2 50       30 return $p{test_ok} if defined $p{test_ok};
1163              
1164             # Create log/run files
1165 0         0 foreach my $serv (@$prots) {
1166              
1167 0 0       0 die "invalid protocol: $serv!\n" unless $valid_prots{$serv};
1168              
1169 0         0 my $supervisedir = $self->toaster->supervise_dir_get( $serv );
1170 0         0 my $run_f = "$supervisedir/log/run";
1171              
1172 0         0 $self->audit( "install_qmail_control_log_files: preparing $run_f");
1173              
1174 0         0 my @lines = $self->toaster->supervised_do_not_edit_notice;
1175 0         0 push @lines, $self->toaster->supervised_multilog($serv);
1176              
1177 0         0 my $tmpfile = "/tmp/mt_supervise_" . $serv . "_log_run";
1178 0         0 $self->util->file_write( $tmpfile, lines => \@lines );
1179              
1180 0         0 $self->audit( "install_qmail_control_log_files: comparing $run_f");
1181              
1182 0 0       0 my $notify = $self->conf->{'supervise_rebuild_notice'} ? 1 : 0;
1183              
1184 0 0       0 if ( -s $tmpfile ) {
1185             $self->util->install_if_changed(
1186             newfile => $tmpfile, existing => $run_f,
1187             mode => '0755', clean => 1,
1188 0 0       0 notify => $notify, email => $self->conf->{'toaster_admin_email'},
1189             ) or return;
1190 0         0 $self->audit( " updating $run_f, ok" );
1191             }
1192              
1193 0         0 $self->toaster->supervised_dir_test( $serv );
1194             }
1195             }
1196              
1197             sub install_ssl_temp_key {
1198 0     0 0 0 my ( $self, $cert, $fatal ) = @_;
1199              
1200 0   0     0 my $user = $self->conf->{'smtpd_run_as_user'} || "vpopmail";
1201 0   0     0 my $group = $self->conf->{'qmail_group'} || "qmail";
1202              
1203 0         0 $self->util->chmod(
1204             file_or_dir => "$cert.new",
1205             mode => '0660',
1206             fatal => $fatal,
1207             );
1208              
1209 0         0 $self->util->chown( "$cert.new",
1210             uid => $user,
1211             gid => $group,
1212             fatal => $fatal,
1213             );
1214              
1215 0         0 move( "$cert.new", $cert );
1216             }
1217              
1218             sub maildir_in_skel {
1219              
1220 0     0 0 0 my $skel = "/usr/share/skel";
1221 0 0       0 if ( ! -d $skel ) {
1222 0 0       0 $skel = "/etc/skel" if -d "/etc/skel"; # linux
1223             }
1224              
1225 0 0       0 if ( ! -e "$skel/Maildir" ) {
1226             # only necessary for systems with local email accounts
1227             #$self->util->syscmd( "$qmaildir/bin/maildirmake $skel/Maildir" ) ;
1228             }
1229             }
1230              
1231             sub netqmail {
1232 2     2 0 4 my $self = shift;
1233 2         15 my %p = validate( @_, {
1234             'package' => { type=>SCALAR, optional=>1, },
1235             $self->get_std_opts,
1236             },
1237             );
1238              
1239 2         9 my $package = $p{package};
1240 2   50     7 my $ver = $self->conf->{'install_netqmail'} || "1.05";
1241 2   50     6 my $src = $self->conf->{'toaster_src_dir'} || "/usr/local/src";
1242 2         13 my $vhome = $self->setup->vpopmail->get_vpop_dir;
1243              
1244 2   33     17 $package ||= "netqmail-$ver";
1245              
1246 2 50       18 return $p{test_ok} if defined $p{test_ok};
1247              
1248 0         0 $self->install_qmail_groups_users();
1249              
1250             # check to see if qmail-smtpd already has vpopmail support
1251 0 0       0 return 0 if ! $self->netqmail_rebuild;
1252              
1253 0         0 $self->util->cwd_source_dir( "$src/mail" );
1254              
1255 0 0       0 $self->netqmail_get_sources( $package ) or return;
1256 0         0 my @patches = $self->netqmail_get_patches( $package );
1257              
1258 0         0 $self->util->extract_archive( "$package.tar.gz" );
1259              
1260             # netqmail requires a "collate" step before it can be built
1261 0 0       0 chdir("$src/mail/$package")
1262             or die "netqmail: cd $src/mail/$package failed: $!\n";
1263              
1264 0         0 $self->util->syscmd( "./collate.sh" );
1265              
1266 0 0       0 chdir("$src/mail/$package/$package")
1267             or die "netqmail: cd $src/mail/$package/$package failed: $!\n";
1268              
1269 0         0 my $patchbin = $self->util->find_bin( 'patch' );
1270              
1271 0         0 foreach my $patch (@patches) {
1272 0         0 print "\nnetqmail: applying patch $patch\n";
1273 0         0 sleep 1;
1274 0         0 $self->util->syscmd( "$patchbin < $src/mail/$patch" );
1275             };
1276              
1277 0         0 $self->netqmail_makefile_fixups();
1278 0 0       0 $self->netqmail_queue_extra() if $self->conf->{'qmail_queue_extra'};
1279 0 0       0 $self->netqmail_darwin_fixups() if $OSNAME eq "darwin";
1280 0         0 $self->netqmail_conf_cc();
1281 0         0 $self->netqmail_conf_fixups();
1282 0         0 $self->netqmail_chkuser_fixups();
1283              
1284 0         0 my $servicectl = '/usr/local/sbin/services';
1285 0 0       0 $servicectl = '/usr/local/bin/services' if ! -x $servicectl;
1286 0 0       0 if ( -x $servicectl ) {
1287 0         0 print "Stopping Qmail!\n";
1288 0         0 $self->send_stop();
1289 0         0 system "$servicectl stop";
1290             }
1291              
1292 0   0     0 my $make = $self->util->find_bin( "gmake", fatal => 0 ) || $self->util->find_bin( "make" );
1293 0         0 $self->util->syscmd( "$make setup" );
1294              
1295 0         0 $self->netqmail_ssl( $make );
1296 0         0 $self->netqmail_permissions();
1297              
1298 0         0 $self->maildir_in_skel();
1299 0         0 $self->config();
1300              
1301 0 0       0 if ( -x $servicectl ) {
1302 0         0 print "Starting Qmail & supervised services!\n";
1303 0         0 system "$servicectl start";
1304             }
1305             }
1306              
1307             sub netqmail_chkuser_fixups {
1308 0     0 0 0 my $self = shift;
1309              
1310 0 0       0 return if ! $self->conf->{vpopmail_qmail_ext};
1311              
1312 0         0 my $file = 'chkuser_settings.h';
1313 0         0 print "netqmail: fixing up $file\n";
1314              
1315 0         0 my @lines = $self->util->file_read( $file );
1316 0         0 foreach my $line (@lines) {
1317 0 0       0 if ( $line =~ /^\/\* \#define CHKUSER_ENABLE_USERS_EXTENSIONS/ ) {
1318 0         0 $line = "#define CHKUSER_ENABLE_USERS_EXTENSIONS";
1319             }
1320             }
1321 0         0 $self->util->file_write( $file, lines => \@lines );
1322              
1323             };
1324              
1325             sub netqmail_conf_cc {
1326 0     0 0 0 my $self = shift;
1327              
1328 0         0 my $vpopdir = $self->setup->vpopmail->get_vpop_dir;
1329 0         0 my $domainkeys = $self->conf->{'qmail_domainkeys'};
1330              
1331             # make changes to conf-cc
1332 0         0 print "netqmail: fixing up conf-cc\n";
1333 0         0 my $cmd = "cc -O2 -DTLS=20060104 -I$vpopdir/include";
1334              
1335             # add in the -I (include) dir for OpenSSL headers
1336 0 0 0     0 if ( -d "/opt/local/include/openssl" ) {
    0          
    0          
1337 0         0 print "netqmail: building against /opt/local/include/openssl.\n";
1338 0         0 $cmd .= " -I/opt/local/include/openssl";
1339             }
1340             elsif ( -d "/usr/local/include/openssl" && $self->conf->{'install_openssl'} )
1341             {
1342 0         0 print
1343             "netqmail: building against /usr/local/include/openssl from ports.\n";
1344 0         0 $cmd .= " -I/usr/local/include/openssl";
1345             }
1346             elsif ( -d "/usr/include/openssl" ) {
1347 0         0 print "netqmail: using system supplied OpenSSL libraries.\n";
1348 0         0 $cmd .= " -I/usr/include/openssl";
1349             }
1350             else {
1351 0 0       0 if ( -d "/usr/local/include/openssl" ) {
1352 0         0 print "netqmail: building against /usr/local/include/openssl.\n";
1353 0         0 $cmd .= " -I/usr/local/include/openssl";
1354             }
1355             else {
1356 0         0 print
1357             "netqmail: WARNING: I couldn't find your OpenSSL libraries. This might cause problems!\n";
1358             }
1359             }
1360              
1361             # add in the include directory for libdomainkeys
1362 0 0       0 if ( $domainkeys ) {
1363             # make sure libdomainkeys is installed
1364 0 0       0 if ( ! -e "/usr/local/include/domainkeys.h" ) {
1365 0         0 $self->setup->domainkeys();
1366             };
1367 0 0       0 if ( -e "/usr/local/include/domainkeys.h" ) {
1368 0         0 $cmd .= " -I/usr/local/include";
1369             };
1370             };
1371              
1372 0         0 $self->util->file_write( "conf-cc", lines => [$cmd] );
1373             };
1374              
1375             sub netqmail_conf_fixups {
1376 0     0 0 0 my $self = shift;
1377              
1378 0         0 print "netqmail: fixing up conf-qmail\n";
1379 0         0 my $qmaildir = $self->get_qmail_dir;
1380 0         0 $self->util->file_write( "conf-qmail", lines => [$qmaildir] );
1381              
1382 0         0 print "netqmail: fixing up conf-vpopmail\n";
1383 0         0 my $vpopdir = $self->setup->vpopmail->get_vpop_dir;
1384 0         0 $self->util->file_write( "conf-vpopmail", lines => [$vpopdir] );
1385              
1386 0         0 print "netqmail: fixing up conf-mysql\n";
1387 0   0     0 my $mysql = $self->conf->{'qmail_mysql_include'} || "/usr/local/lib/mysql/libmysqlclient.a";
1388 0         0 $self->util->file_write( "conf-mysql", lines => [$mysql] );
1389              
1390 0         0 print "netqmail: fixing up conf-groups\n";
1391 0   0     0 my $q_group = $self->conf->{'qmail_group'} || 'qmail';
1392 0   0     0 my $l_group = $self->conf->{'qmail_log_group'} || "qnofiles";
1393 0         0 $self->util->file_write( "conf-groups", lines => [ $q_group, $l_group ] );
1394             };
1395              
1396             sub netqmail_darwin_fixups {
1397 0     0 0 0 my $self = shift;
1398              
1399 0         0 print "netqmail: fixing up conf-ld\n";
1400 0 0       0 $self->util->file_write( "conf-ld", lines => ["cc -Xlinker -x"] )
1401             or die "couldn't write to conf-ld: $!";
1402              
1403 0         0 print "netqmail: fixing up dns.c for Darwin\n";
1404 0         0 my @lines = $self->util->file_read( "dns.c" );
1405 0         0 foreach my $line (@lines) {
1406 0 0       0 if ( $line =~ /#include <netinet\/in.h>/ ) {
1407 0         0 $line = "#include <netinet/in.h>\n#include <nameser8_compat.h>";
1408             }
1409             }
1410 0         0 $self->util->file_write( "dns.c", lines => \@lines );
1411              
1412 0         0 print "netqmail: fixing up strerr_sys.c for Darwin\n";
1413 0         0 @lines = $self->util->file_read( "strerr_sys.c" );
1414 0         0 foreach my $line (@lines) {
1415 0 0       0 if ( $line =~ /struct strerr strerr_sys/ ) {
1416 0         0 $line = "struct strerr strerr_sys = {0,0,0,0};";
1417             }
1418             }
1419 0         0 $self->util->file_write( "strerr_sys.c", lines => \@lines );
1420              
1421 0         0 print "netqmail: fixing up hier.c for Darwin\n";
1422 0         0 @lines = $self->util->file_read( "hier.c" );
1423 0         0 foreach my $line (@lines) {
1424 0 0       0 if ( $line =~
1425             /c\(auto_qmail,"doc","INSTALL",auto_uido,auto_gidq,0644\)/ )
1426             {
1427 0         0 $line =
1428             'c(auto_qmail,"doc","INSTALL.txt",auto_uido,auto_gidq,0644);';
1429             }
1430             }
1431 0         0 $self->util->file_write( "hier.c", lines => \@lines );
1432              
1433             # fixes due to case sensitive file system
1434 0         0 move( "INSTALL", "INSTALL.txt" );
1435 0         0 move( "SENDMAIL", "SENDMAIL.txt" );
1436             }
1437              
1438             sub netqmail_get_sources {
1439 0     0 0 0 my $self = shift;
1440 0 0       0 my $package = shift or croak "missing package name!";
1441 0         0 my $site = "http://www.qmail.org";
1442 0   0     0 my $src = $self->conf->{'toaster_src_dir'} || "/usr/local/src";
1443              
1444 0 0       0 $self->util->source_warning( package=>$package, src=>"$src/mail" ) or return;
1445              
1446 0 0       0 return 1 if -e "$package.tar.gz"; # already exists
1447              
1448             # check if the distfile is in the ports repo
1449 0         0 my $dist = "/usr/ports/distfiles/$package.tar.gz";
1450 0 0       0 if ( -e $dist ) {
1451 0         0 copy( $dist, "$src/mail/$package.tar.gz" );
1452             }
1453 0 0       0 return 1 if -e "$package.tar.gz";
1454              
1455 0         0 $self->util->get_url( "$site/$package.tar.gz" );
1456 0 0       0 return 1 if -e "$package.tar.gz";
1457              
1458 0         0 return $self->error( "couldn't fetch $package.tar.gz!" );
1459             };
1460              
1461             sub netqmail_get_patches {
1462 0     0 0 0 my $self = shift;
1463 0         0 my $package = shift;
1464              
1465 0         0 my $patch_ver = $self->conf->{'qmail_toaster_patch_version'};
1466              
1467 0         0 my @patches;
1468 0 0       0 push @patches, "$package-toaster-$patch_ver.patch" if $patch_ver;
1469              
1470 0 0 0     0 if ( defined $self->conf->{qmail_smtp_reject_patch} && $self->conf->{qmail_smtp_reject_patch} ) {
1471 0         0 push @patches, "$package-smtp_reject-3.0.patch";
1472             }
1473              
1474 0 0 0     0 if ( defined $self->conf->{qmail_domainkeys} && $self->conf->{qmail_domainkeys} ) {
1475 0         0 push @patches, "$package-toaster-3.1-dk.patch";
1476             };
1477              
1478 0         0 my ($sysname, undef, $version) = POSIX::uname;
1479 0 0 0     0 if ( $sysname eq 'FreeBSD' && $version =~ /^(9|10)/ ) {
1480 0         0 push @patches, "qmail-extra-patch-utmpx.patch";
1481             }
1482              
1483 0   0     0 my $dl_site = $self->conf->{'toaster_dl_site'} || "http://www.tnpi.net";
1484 0   0     0 my $dl_url = $self->conf->{'toaster_dl_url'} || "/internet/mail/toaster";
1485 0         0 my $toaster_url = "$dl_site$dl_url";
1486              
1487 0         0 foreach my $patch (@patches) {
1488 0 0       0 next if -e $patch;
1489 0         0 $self->util->get_url( "$toaster_url/patches/$patch" );
1490 0 0       0 next if -e $patch;
1491 0         0 return $self->error( "failed to fetch patch $patch!" );
1492             }
1493 0         0 return @patches;
1494             };
1495              
1496             sub netqmail_makefile_fixups {
1497 0     0 0 0 my $self = shift;
1498 0         0 my $vpopdir = $self->setup->vpopmail->get_vpop_dir;
1499              
1500             # find the openssl libraries
1501 0   0     0 my $prefix = $self->conf->{'toaster_prefix'} || "/usr/local/";
1502 0         0 my $ssl_lib = "$prefix/lib";
1503 0 0       0 if ( !-e "$ssl_lib/libcrypto.a" ) {
1504 0 0       0 if ( -e "/opt/local/lib/libcrypto.a" ) { $ssl_lib = "/opt/local/lib"; }
  0 0       0  
    0          
    0          
1505 0         0 elsif ( -e "/usr/local/lib/libcrypto.a" ) { $ssl_lib = "/usr/local/lib"; }
1506 0         0 elsif ( -e "/opt/lib/libcrypto.a" ) { $ssl_lib = "/opt/lib"; }
1507 0         0 elsif ( -e "/usr/lib/libcrypto.a" ) { $ssl_lib = "/usr/lib"; }
1508             }
1509              
1510              
1511 0         0 my @lines = $self->util->file_read( "Makefile" );
1512 0         0 foreach my $line (@lines) {
1513 0 0       0 if ( $vpopdir ne "/home/vpopmail" ) { # fix up vpopmail home dir
1514 0 0       0 if ( $line =~ /^VPOPMAIL_HOME/ ) {
1515 0         0 $line = 'VPOPMAIL_HOME=' . $vpopdir;
1516             }
1517             }
1518              
1519             # add in the discovered ssl library location
1520 0 0       0 if ( $line =~
1521             /tls.o ssl_timeoutio.o -L\/usr\/local\/ssl\/lib -lssl -lcrypto/ )
1522             {
1523 0         0 $line =
1524             ' tls.o ssl_timeoutio.o -L' . $ssl_lib . ' -lssl -lcrypto \\';
1525             }
1526              
1527             # again with the ssl libs
1528 0 0       0 if ( $line =~
1529             /constmap.o tls.o ssl_timeoutio.o ndelay.a -L\/usr\/local\/ssl\/lib -lssl -lcrypto \\/
1530             )
1531             {
1532 0         0 $line =
1533             ' constmap.o tls.o ssl_timeoutio.o ndelay.a -L' . $ssl_lib
1534             . ' -lssl -lcrypto \\';
1535             }
1536             }
1537 0         0 $self->util->file_write( "Makefile", lines => \@lines );
1538             };
1539              
1540             sub netqmail_permissions {
1541 0     0 0 0 my $self = shift;
1542              
1543 0         0 my $qmaildir = $self->get_qmail_dir;
1544 0         0 $self->util->chown( "$qmaildir/bin/qmail-smtpd",
1545             uid => 'vpopmail',
1546             gid => 'vchkpw',
1547             );
1548              
1549 0         0 $self->util->chmod(
1550             file_or_dir => "$qmaildir/bin/qmail-smtpd",
1551             mode => '6555',
1552             );
1553             };
1554              
1555             sub netqmail_queue_extra {
1556 0     0 0 0 my $self = shift;
1557              
1558 0         0 print "netqmail: enabling QUEUE_EXTRA...\n";
1559 0         0 my $success = 0;
1560 0         0 my @lines = $self->util->file_read( "extra.h" );
1561 0         0 foreach my $line (@lines) {
1562 0 0       0 if ( $line =~ /#define QUEUE_EXTRA ""/ ) {
1563 0         0 $line = '#define QUEUE_EXTRA "Tlog\0"';
1564 0         0 $success++;
1565             }
1566              
1567 0 0       0 if ( $line =~ /#define QUEUE_EXTRALEN 0/ ) {
1568 0         0 $line = '#define QUEUE_EXTRALEN 5';
1569 0         0 $success++;
1570             }
1571             }
1572              
1573 0 0       0 if ( $success == 2 ) {
1574 0         0 print "success.\n";
1575 0         0 $self->util->file_write( "extra.h", lines => \@lines );
1576             }
1577             else {
1578 0         0 print "FAILED.\n";
1579             }
1580             }
1581              
1582             sub netqmail_rebuild {
1583 0     0 0 0 my $self = shift;
1584              
1585 0         0 my $qdir = $self->get_qmail_dir;
1586              
1587 0 0       0 return 1 if ! -x "$qdir/bin/qmail-smtpd"; # not yet installed
1588              
1589             # does not have vpopmail support
1590 0 0       0 return 1 if ! `strings $qdir/bin/qmail-smtpd | grep vpopmail`;
1591              
1592 0         0 return $self->util->yes_or_no(
1593             "toasterized qmail is already installed, do you want to reinstall",
1594             timeout => 30,
1595             );
1596             }
1597              
1598             sub netqmail_ssl {
1599 0     0 0 0 my $self = shift;
1600 0         0 my $make = shift;
1601              
1602 0         0 my $qmaildir = $self->get_qmail_dir;
1603              
1604 0 0       0 if ( ! -d "$qmaildir/control" ) {
1605 0         0 mkpath "$qmaildir/control";
1606             };
1607              
1608 0         0 $ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin";
1609 0 0       0 if ( ! -f "$qmaildir/control/servercert.pem" ) {
1610 0         0 print "netqmail: installing SSL certificate\n";
1611 0 0       0 if ( -f "/usr/local/openssl/certs/server.pem" ) {
1612 0         0 copy( "/usr/local/openssl/certs/server.pem", "$qmaildir/control/servercert.pem");
1613 0         0 link( "$qmaildir/control/servercert.pem", "$qmaildir/control/clientcert.pem" );
1614             }
1615             else {
1616 0         0 system "$make cert";
1617             };
1618             }
1619              
1620 0 0       0 if ( ! -f "$qmaildir/control/rsa512.pem" ) {
1621 0         0 print "netqmail: install temp SSL \n";
1622 0         0 system "$make tmprsadh";
1623             }
1624             };
1625              
1626             sub netqmail_virgin {
1627 2     2 1 3 my $self = shift;
1628 2         10 my %p = validate( @_, {
1629             'package' => { type=>SCALAR, optional=>1, },
1630             $self->get_std_opts,
1631             },
1632             );
1633              
1634 2         8 my $package = $p{'package'};
1635 2         2 my $chkusr;
1636              
1637 2   50     5 my $ver = $self->conf->{'install_netqmail'} || "1.05";
1638 2   50     4 my $src = $self->conf->{'toaster_src_dir'} || "/usr/local/src";
1639 2         6 my $qmaildir = $self->get_qmail_dir;
1640              
1641 2   33     11 $package ||= "netqmail-$ver";
1642              
1643 2   50     5 my $mysql = $self->conf->{'qmail_mysql_include'}
1644             || "/usr/local/lib/mysql/libmysqlclient.a";
1645 2   50     3 my $qmailgroup = $self->conf->{'qmail_log_group'} || "qnofiles";
1646              
1647             # we do not want to try installing anything during "make test"
1648 2 50       5 if ( defined $p{'test_ok'} ) { return $p{'test_ok'}; }
  2         10  
1649              
1650 0         0 $self->install_qmail_groups_users();
1651              
1652 0         0 $self->util->cwd_source_dir( "$src/mail" );
1653 0         0 $self->netqmail_get_sources( $package );
1654              
1655 0 0       0 unless ( $self->util->extract_archive( "$package.tar.gz" ) ) {
1656 0         0 die "couldn't expand $package.tar.gz\n";
1657             }
1658              
1659             # netqmail requires a "collate" step before it can be built
1660 0 0       0 chdir("$src/mail/$package")
1661             or die "netqmail: cd $src/mail/$package failed: $!\n";
1662 0         0 $self->util->syscmd( "./collate.sh" );
1663 0 0       0 chdir("$src/mail/$package/$package")
1664             or die "netqmail: cd $src/mail/$package/$package failed: $!\n";
1665              
1666 0         0 $self->netqmail_conf_fixups();
1667 0 0       0 $self->netqmail_darwin_fixups() if $OSNAME eq 'darwin';
1668              
1669 0         0 print "netqmail: fixing up conf-cc\n";
1670 0 0       0 $self->util->file_write( "conf-cc", lines => ["cc -O2"] )
1671             or die "couldn't write to conf-cc: $!";
1672              
1673 0         0 my $servicectl = "/usr/local/sbin/services";
1674 0 0       0 if ( -x $servicectl ) {
1675 0         0 print "Stopping Qmail!\n";
1676 0         0 $self->send_stop();
1677 0         0 $self->util->syscmd( "$servicectl stop" );
1678             }
1679              
1680 0   0     0 my $make = $self->util->find_bin( "gmake", fatal => 0 ) || $self->util->find_bin( "make" );
1681 0         0 $self->util->syscmd( "$make setup" );
1682              
1683 0         0 $self->maildir_in_skel();
1684 0         0 $self->config();
1685              
1686 0 0       0 if ( -x $servicectl ) {
1687 0         0 print "Starting Qmail & supervised services!\n";
1688 0         0 $self->util->syscmd( "$servicectl start" );
1689             }
1690             }
1691              
1692             sub queue_check {
1693             # used in qqtool.pl
1694              
1695 1     1 0 2 my $self = shift;
1696 1         4 my %p = validate( @_, { $self->get_std_opts } );
1697              
1698 1         5 my $base = $self->conf->{qmail_dir};
1699 1 50       3 unless ( $base ) {
1700 0         0 print "queue_check: ERROR! qmail_dir is not set in conf! This is almost certainly an error!\n";
1701 0         0 $base = "/var/qmail"
1702             }
1703              
1704 1         3 my $queue = "$base/queue";
1705              
1706 1 50 33     28 unless ( $queue && -d $queue ) {
1707 1         8 my $err = "\tHEY! The queue directory for qmail is missing!\n";
1708 1 50       4 $err .= "\tI expected it to be at $queue\n" if $queue;
1709 1         3 $err .= "\tIt should have been set via the qmail_dir setting in toaster-watcher.conf!\n";
1710              
1711 1         8 return $self->error( $err, fatal => $p{fatal} );
1712             }
1713              
1714 0         0 $self->audit( "queue_check: checking $queue...ok" );
1715 0         0 return "$base/queue";
1716             }
1717              
1718             sub rebuild_simscan_control {
1719 0     0 0 0 my $self = shift;
1720 0 0       0 return if ! $self->conf->{install_simscan};
1721              
1722 0         0 my $qmdir = $self->get_qmail_dir;
1723              
1724 0         0 my $control = "$qmdir/control/simcontrol";
1725 0 0       0 return if ! -f $control;
1726 0 0 0     0 return 1 if ( -e "$control.cdb" && ! $self->util->file_is_newer( f1=>$control, f2=>"$control.cdb" ) );
1727              
1728 0         0 my $simscanmk = "$qmdir/bin/simscanmk";
1729 0 0       0 return if ! -x $simscanmk;
1730              
1731 0 0       0 `$simscanmk` or return 1;
1732 0         0 `$simscanmk -g`; # for old versions of simscan
1733             };
1734              
1735             sub rebuild_ssl_temp_keys {
1736 0     0 0 0 my $self = shift;
1737 0         0 my %p = validate( @_, { $self->get_std_opts } );
1738              
1739 0         0 my $openssl = $self->util->find_bin( "openssl" );
1740 0         0 my $fatal = $p{fatal};
1741              
1742 0         0 my $qmdir = $self->get_qmail_dir;
1743 0         0 my $cert = "$qmdir/control/rsa512.pem";
1744              
1745 0 0       0 return $p{'test_ok'} if defined $p{'test_ok'};
1746              
1747 0 0 0     0 if ( ! -f $cert || -M $cert >= 1 || !-e $cert ) {
      0        
1748 0         0 $self->audit( "rebuild_ssl_temp_keys: rebuilding RSA key");
1749 0         0 $self->util->syscmd( "$openssl genrsa -out $cert.new 512 2>/dev/null" );
1750              
1751 0         0 $self->install_ssl_temp_key( $cert, $fatal );
1752             }
1753              
1754 0         0 $cert = "$qmdir/control/dh512.pem";
1755 0 0 0     0 if ( ! -f $cert || -M $cert >= 1 || !-e $cert ) {
      0        
1756 0         0 $self->audit( "rebuild_ssl_temp_keys: rebuilding DSA 512 key");
1757 0         0 $self->util->syscmd( "$openssl dhparam -2 -out $cert.new 512 2>/dev/null" );
1758              
1759 0         0 $self->install_ssl_temp_key( $cert, $fatal );
1760             }
1761              
1762 0         0 $cert = "$qmdir/control/dh1024.pem";
1763 0 0 0     0 if ( ! -f $cert || -M $cert >= 1 || !-e $cert ) {
      0        
1764 0         0 $self->audit( "rebuild_ssl_temp_keys: rebuilding DSA 1024 key");
1765 0         0 system "$openssl dhparam -2 -out $cert.new 1024 2>/dev/null";
1766 0         0 $self->install_ssl_temp_key( $cert, $fatal );
1767             }
1768              
1769 0         0 return 1;
1770             }
1771              
1772             sub restart {
1773 0     0 1 0 my $self = shift;
1774 0         0 my %p = validate( @_, { 'prot' => { type => SCALAR }, $self->get_std_opts } );
1775              
1776 0 0       0 return $p{'test_ok'} if defined $p{'test_ok'};
1777              
1778 0         0 my $prot = $p{'prot'};
1779 0 0       0 my $dir = $self->toaster->service_dir_get( $prot ) or return;
1780              
1781 0 0 0     0 return $self->error( "no such dir: $dir!", fatal=>0 ) unless ( -d $dir || -l $dir );
1782              
1783 0         0 $self->toaster->supervise_restart($dir);
1784             }
1785              
1786             sub send_start {
1787 0     0 1 0 my $self = shift;
1788 0         0 my %p = validate( @_, { $self->get_std_opts } );
1789              
1790 0         0 my $qcontrol = $self->toaster->service_dir_get( "send" );
1791              
1792 0 0       0 return $p{'test_ok'} if defined $p{'test_ok'};
1793              
1794 0 0       0 return $self->error( "uh oh, the service directory $qcontrol is missing!") if ! -d $qcontrol;
1795              
1796 0 0       0 if ( ! $self->toaster->supervised_dir_test( "send" ) ) {
1797 0         0 return $self->error( "something is wrong with the service/send dir." );
1798             }
1799              
1800 0 0       0 return $self->error( "Only root can control supervised daemons, and you aren't root!") if $UID != 0;
1801              
1802 0         0 my $svc = $self->util->find_bin( "svc", verbose=>0 );
1803 0         0 my $svstat = $self->util->find_bin( "svstat", verbose=>0 );
1804              
1805             # Start the qmail-send (and related programs)
1806 0         0 system "$svc -u $qcontrol";
1807              
1808             # loop until it is up and running.
1809 0         0 foreach my $i ( 1 .. 200 ) {
1810 0         0 my $r = `$svstat $qcontrol`;
1811 0         0 chomp $r;
1812 0 0       0 if ( $r =~ /^.*:\sup\s\(pid [0-9]*\)\s[0-9]*\sseconds$/ ) {
1813 0         0 print "Yay, we're up!\n";
1814 0         0 return 1;
1815             }
1816 0         0 sleep 1;
1817             }
1818 0         0 return 1;
1819             }
1820              
1821             sub send_stop {
1822 0     0 1 0 my $self = shift;
1823 0         0 my %p = validate( @_, { $self->get_std_opts } );
1824              
1825 0         0 my %args = ( verbose => $p{verbose}, fatal => $p{fatal} );
1826              
1827 0 0       0 return $p{'test_ok'} if defined $p{'test_ok'};
1828              
1829 0         0 my $svc = $self->util->find_bin( "svc", verbose=>0 );
1830 0         0 my $svstat = $self->util->find_bin( "svstat", verbose=>0 );
1831              
1832 0         0 my $qcontrol = $self->toaster->service_dir_get( "send" );
1833              
1834 0 0       0 return $self->error( "uh oh, the service directory $qcontrol is missing! Giving up.",
1835             %args ) unless $qcontrol;
1836              
1837 0 0       0 return $self->error( "something was wrong with the service/send dir." )
1838             if ! $self->toaster->supervised_dir_test( "send" );
1839              
1840 0 0       0 return $self->error( "Only root can control supervised daemons, and you aren't root!",
1841             %args ) if $UID != 0;
1842              
1843             # send qmail-send a TERM signal
1844 0         0 system "$svc -d $qcontrol";
1845              
1846             # loop up to a thousand seconds waiting for qmail-send to exit
1847 0         0 foreach my $i ( 1 .. 1000 ) {
1848 0         0 my $r = `$svstat $qcontrol`;
1849 0         0 chomp $r;
1850 0 0       0 if ( $r =~ /^.*:\sdown\s[0-9]*\sseconds/ ) {
    0          
1851 0         0 print "Yay, we're down!\n";
1852 0         0 return;
1853             }
1854             elsif ( $r =~ /supervise not running/ ) {
1855 0         0 print "Yay, we're down!\n";
1856 0         0 return;
1857             }
1858             else {
1859              
1860             # if more than 100 seconds passes, lets kill off the qmail-remote
1861             # processes that are forcing us to wait.
1862              
1863 0 0       0 if ( $i > 100 ) {
1864 0         0 $self->util->syscmd( "killall qmail-remote", verbose=>0 );
1865             }
1866 0         0 print "$r\n";
1867             }
1868 0         0 sleep 1;
1869             }
1870 0         0 return 1;
1871             }
1872              
1873             sub smtp_get_simenv {
1874 0     0 0 0 my $self = shift;
1875              
1876 0 0       0 if ( $self->conf->{'simscan_debug'} ) {
1877 0         0 $self->audit( "setting SIMSCAN_DEBUG");
1878 0         0 return "SIMSCAN_DEBUG=1
1879             export SIMSCAN_DEBUG\n\n";
1880             };
1881              
1882 0         0 return '';
1883             };
1884              
1885             sub smtp_auth_enable {
1886 0     0 0 0 my $self = shift;
1887              
1888 0 0       0 return '' if ! $self->conf->{'smtpd_auth_enable'};
1889              
1890 0         0 my $smtp_auth = '';
1891              
1892 0         0 $self->audit( "build_smtp_run: enabling SMTP-AUTH");
1893              
1894             # deprecated, should not be used any longer
1895 0 0 0     0 if ( $self->conf->{'smtpd_hostname'} && $self->conf->{'qmail_smtpd_auth_0.31'} ) {
1896 0         0 $self->audit( " configuring smtpd hostname");
1897 0         0 $smtp_auth .= $self->toaster->supervised_hostname( 'smtpd' );
1898             }
1899              
1900 0 0       0 my $chkpass = $self->_set_checkpasswd_bin( prot => 'smtpd' )
1901             or return '';
1902              
1903 0         0 return "$smtp_auth $chkpass /usr/bin/true ";
1904             }
1905              
1906             sub smtp_set_qmailqueue {
1907 0     0 0 0 my $self = shift;
1908 0         0 my %p = validate( @_, { 'prot' => { type=>SCALAR, optional=>1 } } );
1909              
1910 0         0 my $prot = $p{'prot'};
1911 0         0 my $qdir = $self->get_qmail_dir;
1912              
1913 0 0       0 if ( $self->conf->{'filtering_method'} ne "smtp" ) {
1914 0         0 $self->audit( "filtering_method != smtp, not setting QMAILQUEUE.");
1915 0         0 return '';
1916             }
1917              
1918             # typically this will be simscan, qmail-scanner, or qmail-queue
1919 0   0     0 my $queue = $self->conf->{'smtpd_qmail_queue'} || "$qdir/bin/qmail-queue";
1920              
1921 0 0 0     0 if ( defined $prot && $prot eq "submit" ) {
1922 0         0 $queue = $self->conf->{'submit_qmail_queue'};
1923             }
1924              
1925             # if the selected one is not executable...
1926 0 0       0 if ( ! -x $queue ) {
1927              
1928 0 0       0 return $self->error( "$queue is not executable by uid $>.", fatal => 0)
1929             if !-x "$qdir/bin/qmail-queue";
1930              
1931 0         0 warn "WARNING: $queue is not executable! I'm falling back to
1932             $qdir/bin/qmail-queue. You need to either (re)install $queue or update your
1933             toaster-watcher.conf file to point to its correct location.\n
1934             You will continue to get this notice every 5 minutes until you fix this.\n";
1935 0         0 $queue = "$qdir/bin/qmail-queue";
1936             }
1937              
1938 0         0 $self->audit( " using $queue for QMAILQUEUE");
1939              
1940 0         0 return "QMAILQUEUE=\"$queue\"\nexport QMAILQUEUE\n\n";
1941             }
1942              
1943             sub smtp_set_rbls {
1944 0     0 0 0 my $self = shift;
1945              
1946 0 0 0     0 return q{} if ( ! $self->conf->{'rwl_enable'} && ! $self->conf->{'rbl_enable'} );
1947              
1948 0         0 my $rbl_cmd_string;
1949              
1950 0         0 my $rblsmtpd = $self->util->find_bin( "rblsmtpd" );
1951 0         0 $rbl_cmd_string .= "\\\n\t$rblsmtpd ";
1952              
1953 0         0 $self->audit( "smtp_set_rbls: using rblsmtpd");
1954              
1955 0   0     0 my $timeout = $self->conf->{'rbl_timeout'} || 60;
1956 0 0       0 $rbl_cmd_string .= $timeout != 60 ? "-t $timeout " : q{};
1957              
1958 0 0       0 $rbl_cmd_string .= "-c " if $self->conf->{'rbl_enable_fail_closed'};
1959 0 0       0 $rbl_cmd_string .= "-b " if !$self->conf->{'rbl_enable_soft_failure'};
1960              
1961 0 0 0     0 if ( $self->conf->{'rwl_enable'} && $self->conf->{'rwl_enable'} > 0 ) {
1962 0         0 my $list = $self->get_list_of_rwls();
1963 0         0 foreach my $rwl (@$list) { $rbl_cmd_string .= "\\\n\t\t-a $rwl " }
  0         0  
1964 0         0 $self->audit( "tested DNS white lists" );
1965             }
1966 0         0 else { $self->audit( "no RWLs selected"); };
1967              
1968 0 0 0     0 if ( $self->conf->{'rbl_enable'} && $self->conf->{'rbl_enable'} > 0 ) {
1969 0         0 my $list = $self->get_list_of_rbls();
1970 0 0       0 $rbl_cmd_string .= $list if $list;
1971 0         0 $self->audit( "tested DNS blacklists" );
1972             }
1973 0         0 else { $self->audit( "no RBLs selected") };
1974              
1975 0         0 return "$rbl_cmd_string ";
1976             };
1977              
1978             sub supervised_hostname_qmail {
1979 1     1 1 2 my $self = shift;
1980 1 50       4 my $prot = shift or croak "missing prot!";
1981              
1982 1         4 my $qsupervise = $self->get_supervise_dir;
1983              
1984 1         4 my $prot_val = "qmail_supervise_" . $prot;
1985 1   33     5 my $prot_dir = $self->conf->{$prot_val} || "$qsupervise/$prot";
1986              
1987 1         10 $self->audit( "supervise dir is $prot_dir");
1988              
1989 1 50       9 if ( $prot_dir =~ /^qmail_supervise\/(.*)$/ ) {
1990 0         0 $prot_dir = "$qsupervise/$1";
1991 0         0 $self->audit( "expanded supervise dir to $prot_dir");
1992             }
1993              
1994 1         4 my $qmaildir = $self->get_qmail_dir;
1995 1         5 my $me = "$qmaildir/control/me"; # the qmail file for the hostname
1996              
1997 1         6 my @lines = <<EORUN
1998             LOCAL=\`head -1 $me\`
1999             if [ -z \"\$LOCAL\" ]; then
2000             echo ERROR: $prot_dir/run tried reading your hostname from $me and failed!
2001             exit 1
2002             fi\n
2003             EORUN
2004             ;
2005 1         4 $self->audit( "hostname set to contents of $me");
2006              
2007 1         4 return @lines;
2008             }
2009              
2010             sub test_each_rbl {
2011 5     5 1 13 my $self = shift;
2012 5         23 my %p = validate( @_, {
2013             'rbls' => { type=>ARRAYREF },
2014             $self->get_std_opts,
2015             },
2016             );
2017              
2018 5         23 my $rbls = $p{'rbls'};
2019              
2020 5         5 my @valid_dnsbls;
2021 5         8 foreach my $rbl (@$rbls) {
2022 3 50       10 if ( ! $rbl ) {
2023 0         0 $self->error("how did a blank RBL make it in here?", fatal=>0);
2024 0         0 next;
2025             };
2026 3 50       15 next if ! $self->dns->rbl_test( zone => $rbl );
2027 3         26 push @valid_dnsbls, $rbl;
2028             }
2029 5         28 return \@valid_dnsbls;
2030             }
2031              
2032             sub UpdateVirusBlocks {
2033              
2034             # deprecated function - no longer maintained.
2035              
2036 0     0 0   my $self = shift;
2037 0           my %p = validate( @_, { 'ips' => ARRAYREF, $self->get_std_opts } );
2038              
2039 0           my $ips = $p{'ips'};
2040 0           my $time = $self->conf->{'qs_block_virus_senders_time'};
2041 0           my $relay = $self->conf->{'smtpd_relay_database'};
2042 0           my $vpdir = $self->setup->vpopmail->get_vpop_dir;
2043              
2044 0 0         if ( $relay =~ /^vpopmail_home_dir\/(.*)\.cdb$/ ) {
2045 0           $relay = "$vpdir/$1";
2046             }
2047             else {
2048 0 0         if ( $relay =~ /^(.*)\.cdb$/ ) { $relay = $1; }
  0            
2049             }
2050 0 0         unless ( -r $relay ) { die "$relay selected but not readable!\n" }
  0            
2051              
2052 0           my @lines;
2053              
2054 0           my $verbose = 0;
2055 0           my $in = 0;
2056 0           my $done = 0;
2057 0           my $now = time;
2058 0           my $expire = time + ( $time * 3600 );
2059              
2060 0 0         print "now: $now expire: $expire\n" if $verbose;
2061              
2062 0           my @userlines = $self->util->file_read( $relay );
2063 0           USERLINES: foreach my $line (@userlines) {
2064 0 0         unless ($in) { push @lines, $line }
  0            
2065 0 0         if ( $line =~ /^### BEGIN QMAIL SCANNER VIRUS ENTRIES ###/ ) {
2066 0           $in = 1;
2067              
2068 0           for (@$ips) {
2069 0           push @lines,
2070             "$_:allow,RBLSMTPD=\"-VIRUS SOURCE: Block will be automatically removed in $time hours: ($expire)\"\n";
2071             }
2072 0           $done++;
2073 0           next USERLINES;
2074             }
2075              
2076 0 0         if ( $line =~ /^### END QMAIL SCANNER VIRUS ENTRIES ###/ ) {
2077 0           $in = 0;
2078 0           push @lines, $line;
2079 0           next USERLINES;
2080             }
2081              
2082 0 0         if ($in) {
2083 0           my ($timestamp) = $line =~ /\(([0-9]+)\)"$/;
2084 0 0         unless ($timestamp) {
2085 0 0         print "ERROR: malformed line: $line\n" if $verbose;
2086             }
2087              
2088 0 0         if ( $now > $timestamp ) {
2089 0 0         print "removing $timestamp\t" if $verbose;
2090             }
2091             else {
2092 0 0         print "leaving $timestamp\t" if $verbose;
2093 0           push @lines, $line;
2094             }
2095             }
2096             }
2097              
2098 0 0         if ($done) {
2099 0 0         if ($verbose) {
2100 0           foreach (@lines) { print "$_\n"; };
  0            
2101             }
2102 0           $self->util->file_write( $relay, lines => \@lines );
2103             }
2104             else {
2105 0           print
2106             "FAILURE: Couldn't find QS section in $relay\n You need to add the following lines as documented in the toaster-watcher.conf and FAQ:
2107              
2108             ### BEGIN QMAIL SCANNER VIRUS ENTRIES ###
2109             ### END QMAIL SCANNER VIRUS ENTRIES ###
2110              
2111             ";
2112             }
2113              
2114 0           $self->setup->tcp_smtp( etc_dir => "$vpdir/etc" );
2115             }
2116              
2117             sub _memory_explanation {
2118              
2119 0     0     my ( $self, $prot, $maxcon ) = @_;
2120 0           my ( $sysmb, $maxsmtpd, $memorymsg,
2121             $perconnection, $connectmsg, $connections );
2122              
2123 0           warn "\nbuild_${prot}_run: your "
2124             . "${prot}_max_memory_per_connection and "
2125             . "${prot}_max_connections settings in toaster-watcher.conf have exceeded your "
2126             . "${prot}_max_memory setting. I have reduced the maximum concurrent connections "
2127             . "to $maxcon to compensate. You should fix your settings.\n\n";
2128              
2129 0 0         if ( $OSNAME eq "freebsd" ) {
2130 0           $sysmb = int( substr( `/sbin/sysctl hw.physmem`, 12 ) / 1024 / 1024 );
2131 0           $memorymsg = "Your system has $sysmb MB of physical RAM. ";
2132             }
2133             else {
2134 0           $sysmb = 1024;
2135 0           $memorymsg =
2136             "This example assumes a system with $sysmb MB of physical RAM.";
2137             }
2138              
2139 0           $maxsmtpd = int( $sysmb * 0.75 );
2140              
2141 0 0         if ( $self->conf->{'install_mail_filtering'} ) {
2142 0           $perconnection = 40;
2143 0           $connectmsg =
2144             "This is a reasonable value for systems which run filtering.";
2145             }
2146             else {
2147 0           $perconnection = 15;
2148 0           $connectmsg =
2149             "This is a reasonable value for systems which do not run filtering.";
2150             }
2151              
2152 0           $connections = int( $maxsmtpd / $perconnection );
2153 0           $maxsmtpd = $connections * $perconnection;
2154              
2155 0           warn <<EOMAXMEM;
2156              
2157             These settings control the concurrent connection limit set by tcpserver,
2158             and the per-connection RAM limit set by softlimit.
2159              
2160             Here are some suggestions for how to set these options:
2161              
2162             $memorymsg
2163              
2164             smtpd_max_memory = $maxsmtpd # approximately 75% of RAM
2165              
2166             smtpd_max_memory_per_connection = $perconnection
2167             # $connectmsg
2168              
2169             smtpd_max_connections = $connections
2170              
2171             If you want to allow more than $connections simultaneous SMTP connections,
2172             you'll either need to lower smtpd_max_memory_per_connection, or raise
2173             smtpd_max_memory.
2174              
2175             smtpd_max_memory_per_connection is a VERY important setting, because
2176             softlimit/qmail will start soft-bouncing mail if the smtpd processes
2177             exceed this value, and the number needs to be sufficient to allow for
2178             any virus scanning, filtering, or other processing you have configured
2179             on your toaster.
2180              
2181             If you raise smtpd_max_memory over $sysmb MB to allow for more than
2182             $connections incoming SMTP connections, be prepared that in some
2183             situations your smtp processes might use more than $sysmb MB of memory.
2184             In this case, your system will use swap space (virtual memory) to
2185             provide the necessary amount of RAM, and this slows your system down. In
2186             extreme cases, this can result in a denial of service-- your server can
2187             become unusable until the services are stopped.
2188              
2189             EOMAXMEM
2190              
2191             }
2192              
2193             sub _test_smtpd_config_values {
2194 0     0     my $self = shift;
2195 0           my %p = validate( @_, { $self->get_std_opts } );
2196              
2197 0           my ( $fatal, $verbose ) = ( $p{fatal}, $p{verbose} );
2198              
2199 0           my $file = $self->util->find_config( "toaster.conf" );
2200              
2201             return $self->error( "qmail_dir does not exist as configured in $file" )
2202 0 0         if !-d $self->conf->{'qmail_dir'};
2203              
2204             # if vpopmail is enabled, make sure the vpopmail home dir exists
2205             return $self->error( "vpopmail_home_dir does not exist as configured in $file" )
2206 0 0 0       if ( $self->conf->{'install_vpopmail'} && !-d $self->conf->{'vpopmail_home_dir'} );
2207              
2208             # make sure qmail_supervise is set and is not a directory
2209 0           my $qsuper = $self->conf->{'qmail_supervise'};
2210 0 0 0       return $self->error( "conf->qmail_supervise is not set!" )
2211             if ( !defined $qsuper || !$qsuper );
2212              
2213             # make sure qmail_supervise is not a directory
2214 0 0         return $self->error( "qmail_supervise ($qsuper) is not a directory!" )
2215             if !-d $qsuper;
2216              
2217 0           return 1;
2218             }
2219              
2220             sub _smtp_sanity_tests {
2221 0     0     my $self = shift;
2222 0           my $qdir = $self->get_qmail_dir;
2223              
2224 0           return "if [ ! -f $qdir/control/rcpthosts ]; then
2225             echo \"No $qdir/control/rcpthosts!\"
2226             echo \"Refusing to start SMTP listener because it'll create an open relay\"
2227             exit 1
2228             fi
2229             ";
2230              
2231             }
2232              
2233             sub _set_checkpasswd_bin {
2234 0     0     my $self = shift;
2235 0           my %p = validate( @_, { 'prot' => { type=>SCALAR } } );
2236              
2237 0           my $prot = $p{'prot'};
2238              
2239 0           $self->audit( " setting checkpasswd for protocol: $prot");
2240              
2241 0 0         my $vdir = $self->conf->{'vpopmail_home_dir'}
2242             or return $self->error( "vpopmail_home_dir not set in \$conf" );
2243              
2244 0           my $prot_dir = $prot . "_checkpasswd_bin";
2245 0           $self->audit(" getting protocol directory for $prot from conf->$prot_dir");
2246              
2247 0           my $chkpass;
2248 0 0         $chkpass = $self->conf->{$prot_dir} or do {
2249 0           print "WARN: $prot_dir is not set in toaster-watcher.conf!\n";
2250 0           $chkpass = "$vdir/bin/vchkpw";
2251             };
2252              
2253 0           $self->audit( " using $chkpass for checkpasswd");
2254              
2255             # vpopmail_home_dir is an alias, expand it
2256 0 0         if ( $chkpass =~ /^vpopmail_home_dir\/(.*)$/ ) {
2257 0           $chkpass = "$vdir/$1";
2258 0           $self->audit( " expanded to $chkpass" );
2259             }
2260              
2261 0 0         return $self->error( "chkpass program $chkpass selected but not executable!")
2262             unless -x $chkpass;
2263              
2264 0           return "$chkpass ";
2265             }
2266              
2267              
2268             1;
2269             __END__
2270              
2271              
2272             =head1 NAME
2273              
2274             Mail::Toaster:::Qmail - Qmail specific functions
2275              
2276              
2277             =head1 SYNOPSIS
2278              
2279             use Mail::Toaster::Qmail;
2280             my $qmail = Mail::Toaster::Qmail->new();
2281              
2282             $qmail->install();
2283              
2284             Mail::Toaster::Qmail is a module of Mail::Toaster. It contains methods for use with qmail, like starting and stopping the deamons, installing qmail, checking the contents of config files, etc. Nearly all functionality contained herein is accessed via toaster_setup.pl.
2285              
2286             See http://mail-toaster.org/ for details.
2287              
2288              
2289             =head1 DESCRIPTION
2290              
2291             This module has all sorts of goodies, the most useful of which are the build_????_run modules which build your qmail control files for you. See the METHODS section for more details.
2292              
2293              
2294             =head1 SUBROUTINES/METHODS
2295              
2296             An object of this class represents a means for interacting with qmail. There are functions for starting, stopping, installing, generating run-time config files, building ssl temp keys, testing functionality, monitoring processes, and training your spam filters.
2297              
2298             =over 8
2299              
2300             =item new
2301              
2302             To use any of the methods following, you need to create a qmail object:
2303              
2304             use Mail::Toaster::Qmail;
2305             my $qmail = Mail::Toaster::Qmail->new();
2306              
2307              
2308              
2309             =item build_pop3_run
2310              
2311             $qmail->build_pop3_run() ? print "success" : print "failed";
2312              
2313             Generate a supervise run file for qmail-pop3d. $file is the location of the file it's going to generate. I typically use it like this:
2314              
2315             $qmail->build_pop3_run()
2316              
2317             If it succeeds in building the file, it will install it. You should restart the service after installing a new run file.
2318              
2319             arguments required:
2320             file - the temp file to construct
2321              
2322             results:
2323             0 - failure
2324             1 - success
2325              
2326              
2327             =item install_qmail_control_log_files
2328              
2329             $qmail->install_qmail_control_log_files();
2330              
2331             Installs the files that control your supervised processes logging. Typically this consists of qmail-smtpd, qmail-send, and qmail-pop3d. The generated files are:
2332              
2333             arguments optional:
2334             prots - an arrayref list of protocols to build run files for.
2335             Defaults to [pop3,smtp,send,submit]
2336              
2337             Results:
2338             qmail_supervise/pop3/log/run
2339             qmail_supervise/smtp/log/run
2340             qmail_supervise/send/log/run
2341             qmail_supervise/submit/log/run
2342              
2343              
2344             =item install_supervise_run
2345              
2346             Installs a new supervise/run file for a supervised service. It first builds a new file, then compares it to the existing one and installs the new file if it has changed. It optionally notifies the admin.
2347              
2348             $qmail->build_smtp_run()
2349              
2350             arguments required:
2351             arguments optional:
2352             result:
2353             1 - success
2354             0 - error
2355              
2356             =item netqmail_virgin
2357              
2358             Builds and installs a pristine netqmail. This is necessary to resolve a chicken and egg problem. You can't apply the toaster patches (specifically chkuser) against netqmail until vpopmail is installed, and you can't install vpopmail without qmail being installed. After installing this, and then vpopmail, you can rebuild netqmail with the toaster patches.
2359              
2360             Usage:
2361             $qmail->netqmail_virgin( verbose=>1);
2362              
2363             arguments optional:
2364             package - the name of the programs tarball, defaults to "netqmail-1.05"
2365              
2366             result:
2367             qmail installed.
2368              
2369              
2370             =item send_start
2371              
2372             $qmail->send_start() - Start up the qmail-send process.
2373              
2374             After starting up qmail-send, we verify that it's running before returning.
2375              
2376              
2377             =item send_stop
2378              
2379             $qmail->send_stop()
2380              
2381             Use send_stop to quit the qmail-send process. It will send qmail-send the TERM signal and then wait until it's shut down before returning. If qmail-send fails to shut down within 100 seconds, then we force kill it, causing it to abort any outbound SMTP sessions that are active. This is safe, as qmail will attempt to deliver them again, and again until it succeeds.
2382              
2383              
2384             =item restart
2385              
2386             $qmail->restart( prot=>"smtp")
2387              
2388             Use restart to restart a supervised qmail process. It will send the TERM signal causing it to exit. It will restart immediately because it's supervised.
2389              
2390              
2391             =item supervised_hostname_qmail
2392              
2393             Gets/sets the qmail hostname for use in supervise/run scripts. It dynamically creates and returns those hostname portion of said run file such as this one based on the settings in $conf.
2394              
2395             arguments required:
2396             prot - the protocol name (pop3, smtp, submit, send)
2397              
2398             result:
2399             an array representing the hostname setting portion of the shell script */run.
2400              
2401             Example result:
2402              
2403             LOCAL=`head -1 /var/qmail/control/me`
2404             if [ -z "$LOCAL" ]; then
2405             echo ERROR: /var/service/pop3/run tried reading your hostname from /var/qmail/control/me and failed!
2406             exit 1
2407             fi
2408              
2409              
2410             =item test_each_rbl
2411              
2412             my $available = $qmail->test_each_rbl( rbls=>$selected, verbose=>1 );
2413              
2414             We get a list of RBL's in an arrayref, run some tests on them to determine if they are working correctly, and pass back the working ones in an arrayref.
2415              
2416             arguments required:
2417             rbls - an arrayref with a list of RBL zones
2418              
2419             result:
2420             an arrayref with the list of the correctly functioning RBLs.
2421              
2422              
2423             =item build_send_run
2424              
2425             $qmail->build_send_run() ? print "success";
2426              
2427             build_send_run generates a supervise run file for qmail-send. $file is the location of the file it's going to generate.
2428              
2429             $qmail->build_send_run() and
2430             $qmail->restart( prot=>'send');
2431              
2432             If it succeeds in building the file, it will install it. You can optionally restart qmail after installing a new run file.
2433              
2434             arguments required:
2435             file - the temp file to construct
2436              
2437             results:
2438             0 - failure
2439             1 - success
2440              
2441              
2442             =item build_smtp_run
2443              
2444             if ( $qmail->build_smtp_run( file=>$file) ) { print "success" };
2445              
2446             Generate a supervise run file for qmail-smtpd. $file is the location of the file it's going to generate.
2447              
2448             $qmail->build_smtp_run()
2449              
2450             If it succeeds in building the file, it will install it. You can optionally restart the service after installing a new run file.
2451              
2452             arguments required:
2453             file - the temp file to construct
2454              
2455             results:
2456             0 - failure
2457             1 - success
2458              
2459              
2460             =item build_submit_run
2461              
2462             if ( $qmail->build_submit_run( file=>$file ) ) { print "success"};
2463              
2464             Generate a supervise run file for qmail-smtpd running on submit. $file is the location of the file it's going to generate.
2465              
2466             $qmail->build_submit_run( file=>$file );
2467              
2468             If it succeeds in building the file, it will install it. You can optionally restart the service after installing a new run file.
2469              
2470             arguments required:
2471             file - the temp file to construct
2472              
2473             results:
2474             0 - failure
2475             1 - success
2476              
2477              
2478             =item check_service_dir
2479              
2480             Verify the existence of the qmail service directory (typically /service/[smtp|send|pop3]).
2481              
2482             arguments required:
2483             dir - the directory whose existence we test for
2484              
2485             results:
2486             0 - failure
2487             1 - success
2488              
2489              
2490             =item check_rcpthosts
2491              
2492             $qmail->check_rcpthosts;
2493              
2494             Checks the control/rcpthosts file and compares its contents to users/assign. Any zones that are in users/assign but not in control/rcpthosts or control/morercpthosts will be presented as a list and you will be expected to add them to morercpthosts.
2495              
2496             arguments required:
2497             none
2498              
2499             arguments optional:
2500             dir - defaults to /var/qmail
2501              
2502             result
2503             instructions to repair any problem discovered.
2504              
2505              
2506             =item config
2507              
2508             Qmail is nice because it is quite easy to configure. Just edit files and put the right values in them. However, many find that a problem because it is not so easy to always know the syntax for what goes in every file, and exactly where that file might be. This sub takes your values from toaster-watcher.conf and puts them where they need to be. It modifies the following files:
2509              
2510             /var/qmail/control/concurrencyremote
2511             /var/qmail/control/me
2512             /var/qmail/control/mfcheck
2513             /var/qmail/control/spfbehavior
2514             /var/qmail/control/tarpitcount
2515             /var/qmail/control/tarpitdelay
2516             /var/qmail/control/sql
2517             /var/qmail/control/locals
2518             /var/qmail/alias/.qmail-postmaster
2519             /var/qmail/alias/.qmail-root
2520             /var/qmail/alias/.qmail-mailer-daemon
2521              
2522             FreeBSD specific:
2523             /etc/rc.conf
2524             /etc/mail/mailer.conf
2525             /etc/make.conf
2526              
2527             You should not manually edit these files. Instead, make changes in toaster-watcher.conf and allow it to keep them updated.
2528              
2529             Usage:
2530             $qmail->config();
2531              
2532             results:
2533             0 - failure
2534             1 - success
2535              
2536              
2537             =item control_create
2538              
2539             To make managing qmail a bit easier, we install a control script that allows the administrator to interact with the running qmail processes.
2540              
2541             Usage:
2542             $qmail->control_create();
2543              
2544             Sample Output
2545             /usr/local/sbin/qmail {restart|doqueue|flush|reload|stat|pause|cont|cdb|queue|help}
2546              
2547             # qmail help
2548             pause -- temporarily stops mail service (connections accepted, nothing leaves)
2549             cont -- continues paused mail service
2550             stat -- displays status of mail service
2551             cdb -- rebuild the cdb files (tcp.smtp, users, simcontrol)
2552             restart -- stops and restarts smtp, sends qmail-send a TERM & restarts it
2553             doqueue -- sends qmail-send ALRM, scheduling queued messages for delivery
2554             reload -- sends qmail-send HUP, rereading locals and virtualdomains
2555             queue -- shows status of queue
2556             alrm -- same as doqueue
2557             hup -- same as reload
2558              
2559             results:
2560             0 - failure
2561             1 - success
2562              
2563              
2564             =item get_domains_from_assign
2565              
2566             Fetch a list of domains from the qmaildir/users/assign file.
2567              
2568             $qmail->get_domains_from_assign;
2569              
2570             arguments required:
2571             none
2572              
2573             arguments optional:
2574             match - field to match (dom, uid, dir)
2575             value - the pattern to match
2576              
2577             results:
2578             an array
2579              
2580              
2581             =item get_list_of_rbls
2582              
2583             Gets passed a hashref of values and extracts all the RBLs that are enabled in the file. See the toaster-watcher.conf file and the rbl_ settings therein for the format expected. See also the t/Qmail.t for examples of usage.
2584              
2585             my $r = $qmail->get_list_of_rbls( verbose => $verbose );
2586              
2587             result:
2588             an arrayref of values
2589              
2590              
2591             =item get_list_of_rwls
2592              
2593             my $selected = $qmail->get_list_of_rwls( verbose=>$verbose);
2594              
2595             Here we collect a list of the RWLs from the configuration file that gets passed to us and return them.
2596              
2597             result:
2598             an arrayref with the enabled rwls.
2599              
2600              
2601             =item install_qmail
2602              
2603             Builds qmail and installs qmail with patches (based on your settings in toaster-watcher.conf), installs the SSL certs, adjusts the permissions of several files that need it.
2604              
2605             Usage:
2606             $qmail->install_qmail( verbose=>1);
2607              
2608             arguments optional:
2609             package - the name of the programs tarball, defaults to "qmail-1.03"
2610              
2611             result:
2612             one kick a55 mail server.
2613              
2614             Patch info is here: http://mail-toaster.org/patches/
2615              
2616              
2617             =item install_qmail_control_files
2618              
2619             When qmail is first installed, it needs some supervised run files to run under tcpserver and daemontools. This sub generates the qmail/supervise/*/run files based on your settings. Perpetual updates are performed by toaster-watcher.pl.
2620              
2621             $qmail->install_qmail_control_files;
2622              
2623             arguments optional:
2624              
2625             result:
2626             qmail_supervise/pop3/run
2627             qmail_supervise/smtp/run
2628             qmail_supervise/send/run
2629             qmail_supervise/submit/run
2630              
2631              
2632              
2633             =back
2634              
2635             =head1 EXAMPLES
2636              
2637             Working examples of the usage of these methods can be found in t/Qmail.t, toaster-watcher.pl, and toaster_setup.pl.
2638              
2639              
2640             =head1 DIAGNOSTICS
2641              
2642             All functions include verbose output which is enabled by default. You can disable the status/verbose messages by calling the functions with verbose=>0. The default behavior is to die upon errors. That too can be overriddent by setting fatal=>0. See the tests in t/Qmail.t for code examples.
2643              
2644              
2645             #=head1 COMMON USAGE MISTAKES
2646              
2647              
2648              
2649             =head1 CONFIGURATION AND ENVIRONMENT
2650              
2651             Nearly all of the configuration options can be manipulated by setting the
2652             appropriate values in toaster-watcher.conf. After making changes in toaster-watcher.conf,
2653             you can run toaster-watcher.pl and your changes will propagate immediately,
2654             or simply wait a few minutes for them to take effect.
2655              
2656              
2657             =head1 DEPENDENCIES
2658              
2659             A list of all the other modules that this module relies upon, including any
2660             restrictions on versions, and an indication whether these required modules are
2661             part of the standard Perl distribution, part of the module's distribution,
2662             or must be installed separately.
2663              
2664             Params::Validate - from CPAN
2665             Mail::Toaster - with package
2666              
2667              
2668             =head1 BUGS AND LIMITATIONS
2669              
2670             None known. When found, report to author.
2671             Patches are welcome.
2672              
2673              
2674             =head1 TODO
2675              
2676              
2677             =head1 SEE ALSO
2678              
2679             Mail::Toaster
2680             Mail::Toaster::Conf
2681             toaster.conf
2682             toaster-watcher.conf
2683              
2684             http://mail-toaster.org/
2685              
2686              
2687             =head1 AUTHOR
2688              
2689             Matt Simerson (matt@tnpi.net)
2690              
2691              
2692             =head1 ACKNOWLEDGEMENTS
2693              
2694              
2695             =head1 LICENCE AND COPYRIGHT
2696              
2697             Copyright (c) 2004-2012 The Network People, Inc. (info@tnpi.net). All rights reserved.
2698              
2699             Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
2700              
2701             Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2702              
2703             Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
2704              
2705             Neither the name of the The Network People, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
2706              
2707             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2708              
2709             =cut