trading in tar for rsync for improved vpopmail support
[freeside.git] / bin / svc_acct.export
1 #!/usr/bin/perl -w
2 #
3 # $Id: svc_acct.export,v 1.33 2002-02-18 00:13:57 jeff Exp $
4 #
5 # Create and export password, radius and vpopmail password files:
6 # passwd, passwd.adjunct, shadow, acp_passwd, acp_userinfo, acp_dialup
7 # users/assign, domains/vdomain/vpasswd
8 # Also export sendmail and qmail config files.
9
10 use strict;
11 use vars qw($conf);
12 use Archive::Tar;
13 use Fcntl qw(:flock);
14 use File::Path;
15 use IO::Handle;
16 use FS::Conf;
17 use Net::SSH qw(ssh);
18 use Net::SCP qw(scp);
19 use FS::UID qw(adminsuidsetup datasrc dbh);
20 use FS::Record qw(qsearch qsearchs fields);
21 use FS::svc_acct;
22 use FS::svc_domain;
23 use FS::svc_forward;
24
25 my $ssh='ssh';
26 my $rsync='rsync';
27
28 my $user = shift or die &usage;
29 adminsuidsetup $user;
30
31 $conf = new FS::Conf;
32
33 my $userpolicy = $conf->config('username_policy')
34   if $conf->exists('username_policy');
35
36 my @shellmachines = $conf->config('shellmachines')
37   if $conf->exists('shellmachines');
38
39 my @bsdshellmachines = $conf->config('bsdshellmachines')
40   if $conf->exists('bsdshellmachines');
41
42 my @nismachines = $conf->config('nismachines')
43   if $conf->exists('nismachines');
44
45 my @erpcdmachines = $conf->config('erpcdmachines')
46   if $conf->exists('erpcdmachines');
47
48 my @radiusmachines = $conf->config('radiusmachines')
49   if $conf->exists('radiusmachines');
50
51 my $icradiusmachines = $conf->exists('icradiusmachines');
52 my @icradiusmachines = $conf->config('icradiusmachines') if $icradiusmachines;
53 my $icradius_mysqldest =
54   $conf->config('icradius_mysqldest') || "/usr/local/var"
55     if $icradiusmachines;
56 my $icradius_mysqlsource =
57   $conf->config('icradius_mysqlsource') || "/usr/local/var/freeside"
58     if $icradiusmachines;
59 my $icradius_dbh;
60 if ( $icradiusmachines && $conf->exists('icradius_secrets') ) {
61   $icradius_dbh = DBI->connect($conf->config('icradius_secrets'))
62     or die $DBI::errstr;
63 } else {
64   $icradius_dbh = dbh;
65 }
66
67 my $textradiusprepend =
68   $conf->exists('textradiusprepend')
69     ? $conf->config('textradiusprepend')
70     : '';
71
72 warn "using depriciated textradiusprepend file" if $textradiusprepend;
73
74
75 my $radiusprepend =
76   $conf->exists('radiusprepend')
77     ? join("\n", $conf->config('radiusprepend'))
78     : '';
79
80 my @vpopmailmachines = $conf->config('vpopmailmachines')
81   if $conf->exists('vpopmailmachines');
82 my $vpopmailrestart = '';
83 $vpopmailrestart = $conf->config('vpopmailrestart')
84   if $conf->exists('vpopmailrestart');
85
86 my ($machine, $vpopdir, $vpopuid, $vpopgid) = split (/\s+/, $vpopmailmachines[0]) if $vpopmailmachines[0];
87
88 my($shellmachine, @qmailmachines);
89 if ( $conf->exists('qmailmachines') ) {
90   $shellmachine = $conf->config('shellmachine');
91   @qmailmachines = $conf->config('qmailmachines');
92 }
93
94 my(@sendmailmachines, $sendmailconfigpath, $sendmailrestart);
95 if ( $conf->exists('sendmailmachines') ) {
96   @sendmailmachines = $conf->config('sendmailmachines');
97   $sendmailconfigpath = $conf->config('sendmailconfigpath') || '/etc';
98   $sendmailrestart = $conf->config('sendmailrestart');
99 }
100
101 my $mydomain = $conf->config('domain') if $conf->exists('domain');
102
103
104
105
106 my(@saltset)= ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' );
107 require 5.004; #srand(time|$$);
108
109 my $spooldir = "/usr/local/etc/freeside/export.". datasrc;
110 my $spoollock = "/usr/local/etc/freeside/svc_acct.export.lock.". datasrc;
111
112 open(EXPORT,"+>>$spoollock") or die "Can't open $spoollock: $!";
113 select(EXPORT); $|=1; select(STDOUT);
114 unless ( flock(EXPORT,LOCK_EX|LOCK_NB) ) {
115   seek(EXPORT,0,0);
116   my($pid)=<EXPORT>;
117   chop($pid);
118   #no reason to start lots of blocking processes
119   die "Is another export process running under pid $pid?\n";
120 }
121 seek(EXPORT,0,0);
122 print EXPORT $$,"\n";
123
124 my(@svc_domain)=qsearch('svc_domain',{});
125
126 ( open(MASTER,">$spooldir/master.passwd")
127   and flock(MASTER,LOCK_EX|LOCK_NB)  
128 ) or die "Can't open $spooldir/.master.passwd: $!";
129 ( open(PASSWD,">$spooldir/passwd")
130   and flock(PASSWD,LOCK_EX|LOCK_NB)  
131 ) or die "Can't open $spooldir/passwd: $!";
132 ( open(SHADOW,">$spooldir/shadow")
133   and flock(SHADOW,LOCK_EX|LOCK_NB)  
134 ) or die "Can't open $spooldir/shadow: $!";
135 ( open(ACP_PASSWD,">$spooldir/acp_passwd")
136   and flock(ACP_PASSWD,LOCK_EX|LOCK_NB)  
137 ) or die "Can't open $spooldir/acp_passwd: $!";
138 ( open(ACP_DIALUP,">$spooldir/acp_dialup")
139   and flock(ACP_DIALUP,LOCK_EX|LOCK_NB)  
140 ) or die "Can't open $spooldir/acp_dialup: $!";
141 ( open(USERS,">$spooldir/users")
142   and flock(USERS,LOCK_EX|LOCK_NB)  
143 ) or die "Can't open $spooldir/users: $!";
144
145 ( open(ASSIGN,">$spooldir/assign")
146   and flock(ASSIGN,LOCK_EX|LOCK_NB)  
147 ) or die "Can't open $spooldir/assign: $!";
148 ( open(RCPTHOSTS,">$spooldir/rcpthosts")
149   and flock(RCPTHOSTS,LOCK_EX|LOCK_NB) 
150 ) or die "Can't open $spooldir/rcpthosts: $!";
151 ( open(VPOPRCPTHOSTS,">$spooldir/vpoprcpthosts")
152   and flock(VPOPRCPTHOSTS,LOCK_EX|LOCK_NB) 
153 ) or die "Can't open $spooldir/rcpthosts: $!";
154 ( open(RECIPIENTMAP,">$spooldir/recipientmap") 
155   and flock(RECIPIENTMAP,LOCK_EX|LOCK_NB) 
156 ) or die "Can't open $spooldir/recipientmap: $!";
157 ( open(VIRTUALDOMAINS,">$spooldir/virtualdomains") 
158   and flock(VIRTUALDOMAINS,LOCK_EX|LOCK_NB)
159 ) or die "Can't open $spooldir/virtualdomains: $!";
160 ( open(VPOPVIRTUALDOMAINS,">$spooldir/vpopvirtualdomains") 
161   and flock(VPOPVIRTUALDOMAINS,LOCK_EX|LOCK_NB)
162 ) or die "Can't open $spooldir/virtualdomains: $!";
163 ( open(VIRTUSERTABLE,">$spooldir/virtusertable")
164   and flock(VIRTUSERTABLE,LOCK_EX|LOCK_NB)
165 ) or die "Can't open $spooldir/virtusertable: $!";
166 ( open(SENDMAIL_CW,">$spooldir/sendmail.cw")
167   and flock(SENDMAIL_CW,LOCK_EX|LOCK_NB)
168 ) or die "Can't open $spooldir/sendmail.cw: $!";
169
170
171
172 chmod 0644, "$spooldir/passwd",
173             "$spooldir/acp_dialup",
174             "$spooldir/assign",
175             "$spooldir/sendmail.cw",
176             "$spooldir/virtusertable",
177             "$spooldir/rcpthosts",
178             "$spooldir/vpoprcpthosts",
179             "$spooldir/recipientmap",
180             "$spooldir/virtualdomains",
181             "$spooldir/vpopvirtualdomains",
182
183 ;
184 chmod 0600, "$spooldir/master.passwd",
185             "$spooldir/acp_passwd",
186             "$spooldir/shadow",
187             "$spooldir/users",
188 ;
189
190 rmtree"$spooldir/domains", 0, 1;
191 mkdir "$spooldir/domains", 0700;
192
193 if ( $icradiusmachines ) {
194   my $sth = $icradius_dbh->prepare("DELETE FROM radcheck");
195   $sth->execute or die "Can't reset radcheck table: ". $sth->errstr;
196   my $sth2 = $icradius_dbh->prepare("DELETE FROM radreply");
197   $sth2->execute or die "Can't reset radreply table: ". $sth2->errstr;
198 }
199
200 setpriority(0,0,10);
201
202 print USERS "$radiusprepend\n";
203
204 my %usernames;  ## this hack helps keep the passwd files sane
205 my @sendmail;
206
207 my $svc_domain;
208 foreach $svc_domain (sort {$a->domain cmp $b->domain} @svc_domain) {
209
210   my($domain)=$svc_domain->domain;
211   print RCPTHOSTS "$domain\n.$domain\n";
212   print VPOPRCPTHOSTS "$domain\n";
213   print SENDMAIL_CW "$domain\n";
214
215   ###
216   # FORMAT OF THE ASSIGN/USERS FILE HERE
217   print ASSIGN join(":",
218     "+" . $domain . "-",
219     $domain,
220     $vpopuid,
221     $vpopgid,
222     $vpopdir . "/domains/" . $domain,
223     "-",
224     "",
225     "",
226   ), "\n" if $vpopmailmachines[0];
227
228   (mkdir "$spooldir/domains/" . $domain, 0700)
229     or die "Can't create $spooldir/domains/" . $domain .": $!";
230
231   ( open(QMAILDEFAULT,">$spooldir/domains/" . $domain . "/.qmail-default")
232     and flock(QMAILDEFAULT,LOCK_EX|LOCK_NB)  
233   ) or die "Can't open $spooldir/domains/" . $domain . "/.qmail-default: $!";
234
235   ( open(VPASSWD,">$spooldir/domains/" . $domain . "/vpasswd")
236     and flock(VPASSWD,LOCK_EX|LOCK_NB)  
237   ) or die "Can't open $spooldir/domains/" . $domain . "/vpasswd: $!";
238
239   my ($svc_acct);
240
241   if ($svc_domain->getfield('catchall')) {
242     $svc_acct = qsearchs('svc_acct', {'svcnum' => $svc_domain->catchall});
243     die "Cannot find catchall account for domain $domain\n" unless $svc_acct;
244
245     my $username = $svc_acct->username;
246     push @sendmail, "\@$domain\t$username\n";
247     print VIRTUALDOMAINS "$domain:$username-$domain\n",
248                          ".$domain:$username-$domain\n",
249     ;
250
251     ###
252     # FORMAT OF THE .QMAIL-DEFAULT FILE HERE
253     print QMAILDEFAULT "| $vpopdir/bin/vdelivermail \"\" " . $svc_acct->email . "\n"
254       if $vpopmailmachines[0];
255
256   }else{
257     ###
258     # FORMAT OF THE .QMAIL-DEFAULT FILE HERE
259     print QMAILDEFAULT "| $vpopdir/bin/vdelivermail \"\" bounce-no-mailbox\n"
260       if $vpopmailmachines[0];
261   }
262
263   print VPOPVIRTUALDOMAINS "$domain:$domain\n";
264
265   foreach $svc_acct (qsearch('svc_acct', {'domsvc' => $svc_domain->svcnum})) {
266     my($password)=$svc_acct->getfield('_password');
267     my($cpassword,$rpassword);
268     #if ( ( length($password) <= 8 )
269     if ( ( length($password) <= 12 )
270          && ( $password ne '*' )
271          && ( $password ne '!!' )
272          && ( $password ne '' )
273        ) {
274       $cpassword=crypt($password,
275                        $saltset[int(rand(64))].$saltset[int(rand(64))]
276       );
277       $rpassword=$password;
278     } else {
279       $cpassword=$password;
280       $rpassword='UNIX';
281     }
282
283     my $username;
284
285     if ($mydomain && ($mydomain eq $svc_domain->domain)) {
286       $username=$svc_acct->username;
287     } elsif ($userpolicy =~ /^prepend domsvc$/) {
288       $username=$svc_acct->domsvc . $svc_acct->username;
289     } elsif ($userpolicy =~ /^append domsvc$/) {
290       $username=$svc_acct->username . $svc_acct->domsvc;
291     } elsif ($userpolicy =~ /^append domain$/) {
292       $username=$svc_acct->username . $svc_domain->domain;
293     } elsif ($userpolicy =~ /^append domain$/) {
294       $username=$svc_acct->username . $svc_domain->domain;
295     } elsif ($userpolicy =~ /^append \@domain$/) {
296       $username=$svc_acct->username . '@'. $svc_domain->domain;
297     } else {
298       die "Unknown policy in username_policy\n";
299     }
300
301     if ($svc_acct->dir ne '/dev/null' || $svc_acct->slipip ne '') {
302       if ($usernames{$username}++) {
303         die "Duplicate username detected: $username\n";
304       }
305     }
306             
307     if ( $svc_acct->uid  =~ /^(\d+)$/ ) {
308
309       die "Non-root user ". $svc_acct->username. " has 0 UID!"
310         if $svc_acct->uid == 0 && $svc_acct->username ne 'root';
311
312       if ( $svc_acct->dir ne "/dev/null") {
313
314         ###
315         # FORMAT OF FreeBSD MASTER PASSWD FILE HERE
316         print MASTER join(":",
317           $username,                        # User name
318           $cpassword,                       # Encrypted password
319           $svc_acct->uid,                   # User ID
320           $svc_acct->gid,                   # Group ID
321           "",                               # Login Class
322           "0",                              # Password Change Time
323           "0",                              # Password Expiration Time
324           $svc_acct->finger,                # Users name
325           $svc_acct->dir,                   # Users home directory
326           $svc_acct->shell,                 # shell
327         ), "\n" ;
328
329
330         ###
331         # FORMAT OF THE PASSWD FILE HERE
332         print PASSWD join(":",
333           $username,
334           'x', # "##". $username,
335           $svc_acct->uid,
336           $svc_acct->gid,
337           $svc_acct->finger,
338           $svc_acct->dir,
339           $svc_acct->shell,
340         ), "\n";
341
342         ###
343         # FORMAT OF THE SHADOW FILE HERE
344         print SHADOW join(":",
345           $username,
346           $cpassword,
347           '',
348           '',
349           '',
350           '',
351           '',
352           '',
353           '',
354         ), "\n";
355       }
356     }
357
358     ###
359     # FORMAT OF THE VPASSWD FILE HERE
360     print VPASSWD join(":",
361       $svc_acct->username,
362       $cpassword,
363       '1',
364       '0',
365       $svc_acct->username,
366       "$vpopdir/domains/" . $svc_domain->domain ."/" . $svc_acct->username,
367       'NOQUOTA',
368     ), "\n";
369
370
371     if ( $svc_acct->slipip ne '' ) {
372
373       ###
374       # FORMAT OF THE ACP_* FILES HERE
375       print ACP_PASSWD join(":",
376         $username,
377         $cpassword,
378         "0",
379         "0",
380         "",
381         "",
382         "",
383       ), "\n";
384
385       my($ip)=$svc_acct->slipip;
386
387       unless ( $ip eq '0.0.0.0' || $svc_acct->slipip eq '0e0' ) {
388         print ACP_DIALUP $username, "\t*\t", $svc_acct->slipip, "\n";
389       }
390
391       my %radreply = $svc_acct->radius_reply;
392       my %radcheck = $svc_acct->radius_check;
393
394       my $radcheck = join ", ", map { qq($_ = "$radcheck{$_}") } keys %radcheck;
395       $radcheck .= ", " if $radcheck;
396
397       ###
398       # FORMAT OF THE USERS FILE HERE
399       print USERS
400         $username,
401         qq(\t${textradiusprepend}),
402         $radcheck,
403         qq(Password = "$rpassword"\n\t),
404         join ",\n\t", map { qq($_ = "$radreply{$_}") } keys %radreply;
405
406       if ( $ip && $ip ne '0e0' ) {
407         #print USERS qq(,\n\tFramed-Address = "$ip"\n\n);
408         print USERS qq(,\n\tFramed-IP-Address = "$ip"\n\n);
409       } else {
410         print USERS qq(\n\n);
411       }
412
413       ###
414       # ICRADIUS export
415       if ( $icradiusmachines ) {
416   
417         my $sth = $icradius_dbh->prepare(
418           "INSERT INTO radcheck ( id, UserName, Attribute, Value ) VALUES ( ".
419           join(", ", map { $icradius_dbh->quote( $_ ) } (
420             '',
421             $username,
422             "Password",
423             $svc_acct->_password,
424           ) ). " )"
425         );
426         $sth->execute or die "Can't insert into radcheck table: ". $sth->errstr;
427   
428         foreach my $attribute ( keys %radcheck ) {
429           my $sth = $icradius_dbh->prepare(
430             "INSERT INTO radcheck ( id, UserName, Attribute, Value ) VALUES ( ".
431             join(", ", map { $icradius_dbh->quote( $_ ) } (
432               '',
433               $username,
434               $attribute,
435               $radcheck{$attribute},
436             ) ). " )"
437           );
438           $sth->execute or die "Can't insert into radcheck table: ". $sth->errstr;      }
439   
440         foreach my $attribute ( keys %radreply ) {
441           my $sth = $icradius_dbh->prepare(
442             "INSERT INTO radreply (id, UserName, Attribute, Value) VALUES ( ".
443             join(", ", map { $icradius_dbh->quote( $_ ) } (
444               '',
445               $username,
446               $attribute,
447               $radreply{$attribute},
448             ) ). " )"
449           );
450           $sth->execute or die "Can't insert into radreply table: ". $sth->errstr;      }
451   
452         if ( $ip && $ip ne '0e0' ) {
453           my $sth = $icradius_dbh->prepare(
454             "INSERT INTO radreply (id, UserName, Attribute, Value) VALUES ( ".
455             join(", ", map { $icradius_dbh->quote( $_ ) } (
456               '',
457               $username,
458               'Framed-IP-Address',
459               $ip,
460             ) ). " )"
461           );
462           $sth->execute or die "Can't insert into radreply table: ". $sth->errstr;      }
463       }
464     }
465   
466     ###
467     # vpopmail directory structure creation
468
469     (mkdir "$spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username, 0700)
470       or die "Can't create $spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . ": $!";
471     (mkdir "$spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . "/Maildir", 0700)
472       or die "Can't create $spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . " /Maildir: $!";
473     (mkdir "$spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . "/Maildir/cur", 0700)
474       or die "Can't create $spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . " /Maildir/cur: $!";
475     (mkdir "$spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . "/Maildir/new", 0700)
476       or die "Can't create $spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . " /Maildir/new: $!";
477     (mkdir "$spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . "/Maildir/tmp", 0700)
478       or die "Can't create $spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . " /Maildir/tmp: $!";
479
480     ( open(DOTQMAIL,">$spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . "/.qmail")
481       and flock(DOTQMAIL,LOCK_EX|LOCK_NB)  
482     ) or die "Can't open $spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . "/.qmail: $!";
483
484     my($svc_forward);
485     foreach $svc_forward (qsearch('svc_forward', {'srcsvc' => $svc_acct->svcnum})) {
486       my($destination);
487       if ($svc_forward->dstsvc) {
488         my $dst_acct = qsearchs('svc_acct', {'svcnum' => $svc_forward->dstsvc});
489         my $dst_domain = qsearchs('svc_domain', {'svcnum' => $dst_acct->domsvc});
490         $destination = $dst_acct->username . '@' . $dst_domain->domain;
491
492         if ($dst_domain->domain eq $mydomain) {
493           print VIRTUSERTABLE $svc_acct->username . "@" . $svc_domain->domain .
494             "\t" . $dst_acct->username . "\n";
495           print RECIPIENTMAP $svc_acct->username . "@" . $svc_domain->domain .
496             ":$destination\n";
497         }
498       } else {
499         $destination = $svc_forward->dst;
500       }
501     
502       ###
503       # FORMAT OF .QMAIL FILES HERE
504       print DOTQMAIL "$destination\n";
505     }
506
507     flock(DOTQMAIL,LOCK_UN);
508     close DOTQMAIL;
509
510   }
511
512   flock(VPASSWD,LOCK_UN);
513   flock(QMAILDEFAULT,LOCK_UN);
514   close VPASSWD;
515   close QMAILDEFAULT;
516
517 }
518
519 ###
520 # FORMAT OF THE ASSIGN/USERS FILE FINAL LINE HERE
521 print ASSIGN ".\n";
522
523 print VIRTUSERTABLE @sendmail;
524
525 flock(MASTER,LOCK_UN);
526 flock(PASSWD,LOCK_UN);
527 flock(SHADOW,LOCK_UN);
528 flock(ACP_DIALUP,LOCK_UN);
529 flock(ACP_PASSWD,LOCK_UN);
530 flock(USERS,LOCK_UN);
531 flock(ASSIGN,LOCK_UN);
532 flock(SENDMAIL_CW,LOCK_UN);
533 flock(VIRTUSERTABLE,LOCK_UN);
534 flock(RCPTHOSTS,LOCK_UN);
535 flock(VPOPRCPTHOSTS,LOCK_UN);
536 flock(RECIPIENTMAP,LOCK_UN);
537 flock(VPOPVIRTUALDOMAINS,LOCK_UN);
538
539 close MASTER;
540 close PASSWD;
541 close SHADOW;
542 close ACP_DIALUP;
543 close ACP_PASSWD;
544 close USERS;
545 close ASSIGN;
546 close SENDMAIL_CW;
547 close VIRTUSERTABLE;
548 close RCPTHOSTS;
549 close VPOPRCPTHOSTS;
550 close RECIPIENTMAP;
551 close VPOPVIRTUALDOMAINS;
552
553 ###
554 # export stuff
555 #
556
557 my($ashellmachine);
558 foreach $ashellmachine (@shellmachines) {
559   my $scp = new Net::SCP;
560   $scp->scp("$spooldir/passwd","root\@$ashellmachine:/etc/passwd.new")
561     or die "scp error: ". $scp->{errstr};
562   $scp->scp("$spooldir/shadow","root\@$ashellmachine:/etc/shadow.new")
563     or die "scp error: ". $scp->{errstr};
564   ssh("root\@$ashellmachine",
565     "( ".
566       "mv /etc/passwd.new /etc/passwd; ".
567       "mv /etc/shadow.new /etc/shadow; ".
568     " )"
569   )
570     == 0 or die "ssh error: $!";
571 }
572
573 my($bsdshellmachine);
574 foreach $bsdshellmachine (@bsdshellmachines) {
575   my $scp = new Net::SCP;
576   $scp->scp("$spooldir/passwd","root\@$bsdshellmachine:/etc/passwd.new")
577     or die "scp error: ". $scp->{errstr};
578   $scp->scp("$spooldir/master.passwd","root\@$bsdshellmachine:/etc/master.passwd.new")
579     or die "scp error: ". $scp->{errstr};
580   ssh("root\@$bsdshellmachine",
581     "( ".
582       "mv /etc/passwd.new /etc/passwd; ".
583       #"mv /etc/master.passwd.new /etc/master.passwd; ".
584       "pwd_mkdb /etc/master.passwd.new; ".
585     " )"
586   )
587     == 0 or die "ssh error: $!";
588 }
589
590 my($nismachine);
591 foreach $nismachine (@nismachines) {
592   my $scp = new Net::SCP;
593   $scp->scp("$spooldir/passwd","root\@$nismachine:/etc/global/passwd")
594     or die "scp error: ". $scp->{errstr};
595   $scp->scp("$spooldir/shadow","root\@$nismachine:/etc/global/shadow")
596     or die "scp error: ". $scp->{errstr};
597   ssh("root\@$nismachine",
598     "( ".
599       "cd /var/yp; make; ".
600     " )"
601   )
602     == 0 or die "ssh error: $!";
603 }
604
605 my($erpcdmachine);
606 foreach $erpcdmachine (@erpcdmachines) {
607   my $scp = new Net::SCP;
608   $scp->scp("$spooldir/acp_passwd","root\@$erpcdmachine:/usr/annex/acp_passwd")
609     or die "scp error: ". $scp->{errstr};
610   $scp->scp("$spooldir/acp_dialup","root\@$erpcdmachine:/usr/annex/acp_dialup")
611     or die "scp error: ". $scp->{errstr};
612   ssh("root\@$erpcdmachine",
613     "( ".
614       "kill -USR1 \`cat /usr/annex/erpcd.pid\'".
615     " )"
616   )
617     == 0 or die "ssh error: $!";
618 }
619
620 my($radiusmachine);
621 foreach $radiusmachine (@radiusmachines) {
622   my $scp = new Net::SCP;
623   $scp->scp("$spooldir/users","root\@$radiusmachine:/etc/raddb/users")
624     or die "scp error: ". $scp->{errstr};
625   ssh("root\@$radiusmachine",
626     "( ".
627       "builddbm".
628     " )"
629   )
630     == 0 or die "ssh error: $!";
631 }
632
633 foreach my $icradiusmachine ( @icradiusmachines ) {
634   my( $machine, $db, $user, $pass ) = split(/\s+/, $icradiusmachine);
635   chdir $icradius_mysqlsource or die "Can't cd $icradius_mysqlsource: $!";
636   open(WRITER,"|ssh root\@$machine mysql -v --user=$user -p $db");
637   my $oldfh = select WRITER; $|=1; select $oldfh;
638   print WRITER "$pass\n";
639   sleep 2;
640   print WRITER "LOCK TABLES radcheck WRITE, radreply WRITE;\n";
641   foreach my $file ( glob("radcheck.*") ) {
642     my $scp = new Net::SCP;
643     $scp->scp($file,"root\@$machine:$icradius_mysqldest/$db/$file")
644       or die "scp error: ". $scp->{errstr};
645   }
646   foreach my $file ( glob("radreply.*") ) {
647     my $scp = new Net::SCP;
648     $scp->scp($file,"root\@$machine:$icradius_mysqldest/$db/$file")
649       or die "scp error: ". $scp->{errstr};
650   }
651   close WRITER;
652 }
653
654 #my @args = ("/bin/tar", "c", "--force-local", "-C", "$spooldir", "-f", "$spooldir/vpoptarball", "domains");
655
656 #system {$args[0]} @args;
657
658 my($vpopmailmachine);
659 foreach $vpopmailmachine (@vpopmailmachines) {
660   my ($machine, $vpopdir, $vpopuid, $vpopgid) = split (/\s+/, $vpopmailmachine);
661   my $scp = new Net::SCP;
662 #  $scp->scp("$spooldir/vpoptarball","root\@$machine:vpoptarball")
663 #    or die "scp error: ". $scp->{errstr};
664 #  ssh("root\@$machine",
665 #    "( ".
666 #      "rm -rf domains; ".
667 #      "tar xf vpoptarball; ".
668 #      "chown -R $vpopuid:$vpopgid domains; ".
669 #      "tar cf vpoptarball domains; ".
670 #      "cd $vpopdir; ".
671 #      "tar xf ~/vpoptarball; ".
672 #    " )"
673 #  )
674 #    == 0 or die "ssh error: $!";
675
676   chdir $spooldir;
677   my @args = ("$rsync", "-rlpt", "-e", "$ssh", "domains/", "vpopmail\@$machine:$vpopdir/domains/");
678
679   system {$args[0]} @args;
680
681   $scp->scp("$spooldir/assign","root\@$machine:/var/qmail/users/assign")
682     or die "scp error: ". $scp->{errstr};
683   $scp->scp("$spooldir/vpopvirtualdomains","root\@$machine:/var/qmail/control/virtualdomains")
684     or die "scp error: ". $scp->{errstr};
685   $scp->scp("$spooldir/vpoprcpthosts","root\@$machine:/var/qmail/control/rcpthosts")
686     or die "scp error: ". $scp->{errstr};
687
688   ssh("root\@$machine",
689     "( ".
690       $vpopmailrestart .
691     " )"
692   )
693     == 0 or die "ssh error: $!";
694
695
696 }
697
698 my($sendmailmachine);
699 foreach $sendmailmachine (@sendmailmachines) {
700   my $scp = new Net::SCP;
701   $scp->scp("$spooldir/sendmail.cw","root\@$sendmailmachine:$sendmailconfigpath/sendmail.cw.new")
702     or die "scp error: ". $scp->{errstr};
703   $scp->scp("$spooldir/virtusertable","root\@$sendmailmachine:$sendmailconfigpath/virtusertable.new")
704     or die "scp error: ". $scp->{errstr};
705   ssh("root\@$sendmailmachine",
706     "( ".
707       "mv $sendmailconfigpath/sendmail.cw.new $sendmailconfigpath/sendmail.cw; ".
708       "mv $sendmailconfigpath/virtusertable.new $sendmailconfigpath/virtusertable; ".
709       $sendmailrestart.
710     " )"
711   )
712     == 0 or die "ssh error: $!";
713 }
714
715 my($qmailmachine);
716 foreach $qmailmachine (@qmailmachines) {
717   my $scp = new Net::SCP;
718   $scp->scp("$spooldir/recipientmap","root\@$qmailmachine:/var/qmail/control/recipientmap")
719     or die "scp error: ". $scp->{errstr};
720   $scp->scp("$spooldir/virtualdomains","root\@$qmailmachine:/var/qmail/control/virtualdomains")
721     or die "scp error: ". $scp->{errstr};
722   $scp->scp("$spooldir/rcpthosts","root\@$qmailmachine:/var/qmail/control/rcpthosts")
723     or die "scp error: ". $scp->{errstr};
724   #ssh("root\@$qmailmachine","/etc/init.d/qmail restart")
725   #  == 0 or die "ssh error: $!";
726 }
727
728 unlink $spoollock;
729 flock(EXPORT,LOCK_UN);
730 close EXPORT;
731
732 #
733
734 sub usage {
735   die "Usage:\n\n  svc_acct.export user\n";
736 }
737