]> git.treefish.org Git - fex.git/blob - install
Original release 20150120
[fex.git] / install
1 #!/usr/bin/perl -w
2
3 use 5.006;
4 use Getopt::Std;
5 use File::Basename;
6 use Socket;
7 use IO::Socket::INET;
8 use Digest::MD5 'md5_hex';
9
10 $ENV{PATH} .= ':/sbin:/usr/sbin';
11
12 $usage = "usage: $0 [-p port] [IP-address]\n";
13 $xinetd = '/etc/xinetd.d/fex';
14
15 umask 022;
16
17 if ($<) {
18   die "you must be root to install F*EX\n";
19 }
20
21 goto INSTALL if $0 =~ /upgrade$/;
22
23 $fex = 'fex.rus.uni-stuttgart.de';
24 if (system("host $fex >/dev/null") != 0) {
25   die "host $fex is not resolvable - check /etc/resolv.conf\n";
26 }
27
28 if (`uname` =~ /^SunOS/) {
29   die "Solaris is currently not supported. "
30      ."Please contact framstag\@rus.uni-stuttgart.de for details.\n";
31 }
32
33 $opt_p = 80;
34
35 if (open $xinetd,$xinetd) {
36   while (<$xinetd>) {
37     if (/^\s*port\s*=\s*(\d+)/) {
38       $opt_p = $fexport = $1;
39     }
40     if (/^\s*bind\s*=\s*([\d.]+)/) {
41       $fexip = $ip = $1;
42     }
43   }
44   close $xinetd;
45 }
46
47 getopts('p:') or die $usage;
48
49 $arg = shift;
50 if ($arg and -f "locale/$arg/lib/fup.pl") {
51   exec 'locale/translate',$arg;
52 } else {
53   $ip = $arg || $fexip || 0;
54 }
55
56
57 # if (not $ip and open P,"ifconfig 2>/dev/null |") {
58 if (not $ip and open P,'host $(hostname)|') {
59   $guessed_ip = 0;
60   while (<P>) {
61     if (/(\d+\.\d+\.\d+\.\d+)/) { 
62       $guessed_ip = $1;
63       last;
64     }
65   }
66   close P;
67   print "Your IP [$guessed_ip] : ";
68   chomp($ip = <STDIN>);
69   $ip ||= $guessed_ip;
70 }
71
72 $ip =~ /^\d+\.\d+\.\d+\.\d+$/ or die $usage;
73
74 ($hostname) = gethostbyaddr(gethostbyname($ip),AF_INET);
75 die "cannot find hostname for IP $ip\n" unless $hostname;
76
77 print "checking prerequisites\n";
78
79 if (`which xinetd` =~ m{^/}) {
80   print "found xinetd\n";
81 } else {
82   print "xinetd executable NOT found\n";
83   $premiss++;
84 }
85
86 foreach (qw'/usr/lib/sendmail /usr/sbin/sendmail') {
87   if (-x) {
88     $sendmail = $_;
89     print "found $sendmail\n";
90     last;
91   }
92 }
93 unless ($sendmail) {
94   print "sendmail NOT found\n";
95   $premiss++;  
96 }
97
98 if ($premiss) {
99   print "installation aborted, nothing has been touched yet\n";
100   print "what now? ==> see doc/installation\n";
101   exit 1;
102 }
103
104 unless ($fexport) {
105   
106   $SH = IO::Socket::INET->new(
107     PeerAddr => $ip,
108     PeerPort => $opt_p,
109     Proto    => 'tcp',
110   );
111   
112   if ($SH) {
113     print "There is already a tcp-service running on $ip:$opt_p !\n";
114     print "Select another port for F*EX by running $0 -p OTHERPORT $ip\n";
115     print "or an alternative IP-address by running $0 OTHERADDRESS\n";
116     exit 5;
117   }
118 }
119
120 print "prerequisites checked, ok\n";
121
122 unless (getpwnam('fex')) {
123   print "creating user fex\n";
124   system 'useradd -s /bin/bash -c "File EXchange" -m fex';
125   exit $? if $?;
126 }
127
128 if (open F,'/etc/passwd') {
129   while (<F>) {
130     $fexbash = $_ if /^fex:.*\/bash/;
131   }
132   close F;
133 }
134 unless ($fexbash) {
135   die "no bash login shell for user fex\n";
136 }
137
138 INSTALL:
139
140 umask 077;
141
142 @FEX = getpwnam('fex') or die "no user fex\n";
143 $FEXHOME  = $FEX[7];
144
145 die "no HOME directory for user fex\n" unless -d $FEXHOME;
146
147 print "Installing:\n";
148
149 @save = (
150   "lib/fex.ph",
151   "lib/fup.pl",
152   "lib/reactivation.txt",
153   "etc/mime.types",
154   "htdocs/index.html",
155   "htdocs/robots.txt",
156   "htdocs/FAQ/local.faq",
157 );
158
159 foreach $s (@save) {
160   $f = "$FEXHOME/$s";
161   if (-e $f) {
162     $fs = $f.'_save';
163     rename $f,$fs and print "$f --> $fs\n";
164   }
165 }
166
167 cpav(qw'bin cgi-bin lib etc htdocs doc',$FEXHOME);
168 unlink "$FEXHOME/doc/License";
169 unlink "$FEXHOME/htdocs/License";
170
171 $hl = "$FEXHOME/htdocs/locale";
172 unless (-d $hl) { mkdir $hl or die "$0: cannot mkdir $hl - $!\n" }
173
174 if  (-d "$FEXHOME/spool") {
175   warn "checking spool ...\n";
176   &convert_spool;
177   system "chown -R fex $spooldir/";
178 } else {
179   $newinstall = $FEXHOME;
180   chmod 0700,$FEXHOME;
181   mkdir "$FEXHOME/spool",0700 or die "cannot mkdir $FEXHOME/spool - $!\n";
182   mkdir "$FEXHOME/spool/.error",0700;
183   system "chown -R fex $FEXHOME/spool";
184 }
185
186 foreach $s (@save) {
187   $f = "$FEXHOME/$s";
188   $fs = $f.'_save';
189   $fn = $f.'_new';
190   if (-e $fs) {
191     system "rm -rf $fn";
192     rename $f,$fn and print "$f --> $fn\n";
193     rename $fs,$f and print "$fs --> $f\n";
194   }
195 }
196
197 system(qw'perl -p -i -e',
198   's:href="/?FAQ.html":href="/FAQ/FAQ.html":',
199   "$FEXHOME/lib/fup.pl"
200 );
201   
202 $fph = "$FEXHOME/lib/fex.ph";
203 open $fph,$fph or die "cannot read $fph - $!\n";
204 while (<$fph>) {
205   s/'MYHOSTNAME.MYDOMAIN'/'$hostname'/;
206   $conf .= $_;
207 }
208 close $fph;
209
210 eval $conf;
211 $spooldir ||= "$FEXHOME/spool";
212
213 $fid = "$FEXHOME/.fex/id";
214 $aa = "$spooldir/$admin/@";
215
216 if ($newinstall) {
217   print "\n";
218   for (;;) {
219     print "Server hostname [$hostname] : ";
220     $_ = <STDIN>;
221     s/\s//g;
222     $hostname = $_ if $_;
223     last if gethostbyname($hostname);
224     print "No DNS for $hostname\n";
225   }
226   for (;;) {
227     print "F*EX admin [$admin] : ";
228     $_ = <STDIN>;
229     s/\s//g;
230     $admin = $_ if $_;
231     last if $admin =~ /.\@./;
232     print "admin must be a valid email address!\n";
233   }
234   while (not $admin_pw) {
235     print "F*EX admin password: ";
236     $admin_pw = <STDIN>;
237     $admin_pw =~ s/\s//g;
238   }
239   mkfid();
240   print "(admin password is in $aa)\n";
241   $conf =~ s/^\s*\$hostname\s*=.*/\$hostname = '$hostname';/m;
242   $conf =~ s/^\s*\$admin\s*=.*/\$admin = '$admin';/m;
243 } else {
244   if ($admin_pw) {
245     print "\nFound old \$admin_pw in $fph !\n";
246     print "This is no longer supported for security reason.\n";
247     if (open $aa,$aa) {
248       $_ = <$aa>||'';
249       chomp;
250       close $aa;
251       if ($_ ne $admin_pw) {
252         print "\nYou have to delete \$admin_pw in $fph and run\n";
253         print "$FEXHOME/bin/fac -u $admin $admin_pw\n";
254         print "\nThen rerun $0\n";
255         exit 2;
256       }
257     }
258     mkfid();
259     print "\$admin_pw is transfered to auth-ID in $aa\n\n";
260     $conf =~ s/^\s*(\$admin_pw)\s*=.*/# $1 is now auth_ID of user \$admin/m;
261   }
262 }
263
264 sub mkfid {
265   my $ad = dirname($aa);
266   mkdir $ad;
267   open $aa,'>',$aa or die "$0: cannot create $aa - $!\n";
268   print {$aa} "$admin_pw\n";
269   close $aa;
270   my $fd = dirname($fid);
271   mkdir $fd;
272   rename $fid,$fid.'_save';
273   open $fid,'>',$fid or die "$0: cannot create $fid - $!\n";
274   print {$fid} "$hostname:$opt_p\n";
275   print {$fid} "$admin\n";
276   print {$fid} "$admin_pw\n";
277   close $fid;
278   chmod 0700,$fd;
279   system "chown -R fex $fd $ad";
280 }
281
282 open $fph,">$fph.new" or die "$0: cannot write $fph.new - $!\n";
283 print {$fph} $conf;
284 close $fph;
285 system "chown fex $fph.new";
286 rename "$fph.new",$fph or die "$0: cannot rename $fph.new to $fph - $!\n"; 
287
288 do $fph or die "$0: error in new $fph - $!\n";
289
290 rename "locale/deutsch","locale/german"  if -d "locale/deutsch";
291 rename "locale/espanol","locale/spanish" if -d "locale/espanol";
292
293 if (@locales = glob "locale/*/lib/fup.pl") {
294   foreach (@locales) {
295     m{locale/(.+?)/} and $locale = $1;
296     if (-f "$FEXHOME/$_") { 
297       system 'locale/translate',$locale;
298       system "chown -R fex $FEXHOME/locale/$locale";
299       $hl = "$FEXHOME/htdocs/locale/$locale";
300       symlink "$FEXHOME/locale/$locale/htdocs",$hl unless -l $hl;
301     } else { 
302       push @nlocales,"./install $1\n";
303     }
304   }
305   if (@nlocales) {
306     if (glob "$FEXHOME/locale/*/lib/fup.pl") {
307       print "\nTo install another localized version, type:\n";
308     } else {
309       print "\nTo install a localized version, type:\n";
310     }
311     print @nlocales;
312   }
313 }
314
315 $fph = "$FEXHOME/lib/fex.ph";
316 do $fph;
317
318 unless (-f $xinetd) {
319   my $xc = '/etc/xinetd.conf';
320   if (open $xc,$xc) {
321     while (<$xc>) {
322       if (/^\s*only_from/) {
323         print "WARNING: found \"only_from\" in $xc : fexsrv is restricted!\n";
324       }
325     }
326     close $xc;
327   }
328   if (-d '/etc/xinetd.d') {
329     unless (-f $xinetd) {
330       open $xinetd,">$xinetd" or die "cannot write $xinetd - $!\n";
331       open F,'etc/xinetd_fex' or die "cannot read etc/xinetd_fex - $!\n";
332       while (<F>) {
333         s/FEXHOME/$FEXHOME/;
334         s/PORT/$opt_p/;
335         s/ADDRESS/$ip/;
336         print {$xinetd} $_;
337       }
338       close F;
339       close $xinetd;
340       system qw'/etc/init.d/xinetd restart';
341       print "WARNING: cannot restart xinetd\n" if $?;
342     }
343   } else {
344     print "WARNING: No /etc/xinetd.d found.\n";
345     print "WARNING: You have to install etc/xinetd_fex manually.\n";
346   }
347
348   $crontab = `crontab -u fex -l 2>/dev/null`;
349   if ($crontab !~ /fex_cleanup/) {
350     open $crontab,">fex.cron" or die "cannot create fex.cron - $!\n";
351     print {$crontab} $crontab,"\n";
352     print {$crontab} " 3 3 * * * exec $FEXHOME/bin/fex_cleanup\n";
353     close $crontab;
354     system qw(crontab -u fex fex.cron);
355   }
356
357   system "chown -R fex:root $FEXHOME $FEXHOME/spool/";
358   system "chmod -R go-r $FEXHOME/lib $FEXHOME/cgi-bin $FEXHOME/spool/";
359
360   print "\n";
361   print "Now check configuration file $FEXHOME/lib/fex.ph and run\n";
362   print "$FEXHOME/bin/fac for further configuration and user management.\n";
363   print "(You can do this as user \"fex\")\n";
364 } else {
365   
366   system "chmod -R go-r $FEXHOME/lib $FEXHOME/cgi-bin";
367   
368   print "\n";
369   print "F*EX update installed.\n";
370   print "You can inform your users about the new features with:\n";
371   print "$FEXHOME/bin/fexwall 'new F*EX features on $hostname' ".
372         "< $FEXHOME/doc/newfeatures\n";
373 }
374
375 if (@local_rdomains and not @local_rhosts) {
376   print "\nWARNING:\n";
377   print "In $fph you have @local_rdomains but not @local_rhosts!\n";
378   print "Selfregistrating of external users will not work!\n";
379   print "See ${fph}_new/\n";
380 }
381
382 if (`$sendmail -h 2>&1` =~ /exim/ and 
383     `grep trusted_users /etc/exim4/exim4.conf 2>/dev/null` !~ /\bfex\b/) {
384   print "\nWARNING:\n";
385   print "$sendmail is exim\n";
386   print "You MUST set in your exim4.conf:\n";
387   print "trusted_users = mail : uucp : fex\n";
388 }
389 exit;
390
391
392 sub convert_spool {
393   my ($f,$d,$to,$from,$link);
394   
395   local $) = $FEX[3];
396   local $> = $FEX[2];
397
398   our ($spooldir,$skeydir,$gkeydir);
399   $ENV{FEXLIB} = $FEXLIB = "$FEXHOME/lib";
400   require "$FEXLIB/fex.pp" or die "$0: cannot load $FEXLIB/fex.pp - $!\n";
401
402   # User --> user@maildomain
403   if ($mdomain) {
404     foreach $f (glob "$spooldir/.dkeys/*") {
405       if ($link = readlink $f) {
406         (undef,$to,$from,$file) = split('/',$link);
407         if ($file) {
408           $to   .= '@'.$mdomain if $to   !~ /@/;
409           $from .= '@'.$mdomain if $from !~ /@/;
410           if ($link ne "../$to/$from/$file") {
411             symlink "../$to/$from/$file",$f;
412           }
413         }
414       }
415     }
416   }
417
418   # fix spool layout: FROM and TO must have domains and must be lower case
419   foreach $d ((glob "$spooldir/*/*"),(glob "$spooldir/*")) {
420     if (not -l $d and -d $d and $d =~ m:(.+)/(.+):) {
421       $p = $1;
422       $b = $2;
423       if ($b !~ /^@/ and $b !~ /^[A-Z_-]+$/) {
424         if ($mdomain and $b !~ /@/) {
425           rename $d,sprintf("%s/%s@%s",$p,lc($b),$mdomain);
426         } elsif ($b ne lc($b)) {
427           rename $d,sprintf("%s/%s",$p,lc($b));
428         }
429       }
430     }
431   }
432
433   # split auth-ID and subuser file: @ --> @ @SUBUSER
434   foreach my $u (glob "$spooldir/*@*") {
435     next if -f "$u/\@SUBUSER";
436     open my $idf,"$u/\@" or next;
437     $id = <$idf>;
438     if (defined ($su = <$idf>) and $su =~ /\w/
439         and open my $suf,">$u/\@SUBUSER") {
440       print {$suf} $su;
441       while (defined ($su = <$idf>)) { print {$suf} $su }
442       close $suf;
443       close $idf;
444       if (open my $idf,">$u/\@") {
445         print {$idf} $id;
446         close $idf;
447       }
448     }
449   }
450
451   # create new SKEYs
452   foreach my $sf (glob "$spooldir/*/\@SUBUSER") {
453     $user = (split '/',$sf)[-2];
454     if (open $sf,$sf) {
455       while (<$sf>) {
456         s/#.*//;
457         if (/(.+\@.+):(.+)/) {
458           ($subuser,$id) = ($1,$2);
459           next if $subuser =~ /\*/;
460           $skey = md5_hex("$user:$subuser:$id");
461           if (open $skey,'>',"$skeydir/$skey") {
462             print {$skey} "from=$subuser\n",
463                           "to=$user\n",
464                           "id=$id\n";
465             close $skey;
466           }
467           mkdirp("$spooldir/$subuser/\@MAINUSER");
468           symlink $skey,"$spooldir/$subuser/\@MAINUSER/$user";
469         }
470       }
471     }
472     close $sf;
473   }
474
475   # create new GKEYs
476   foreach my $gf (glob "$spooldir/*/\@GROUP/*") {
477     next unless -f $gf;
478     $group = (split '/',$gf)[-1];
479     $user  = (split '/',$gf)[-3];
480     if (open $gf,$gf) {
481       while (<$gf>) {
482         s/#.*//;
483         if (/(.+\@.+):(.+)/) {
484           ($gm,$id) = ($1,$2);
485           $gkey = md5_hex("$user:$group:$gm:$id");
486           if (open $gkey,'>',"$gkeydir/$gkey") {
487             print {$gkey} "from=$gm\n",
488                           "to=\@$group\n",
489                           "user=$user\n",
490                           "id=$id\n";
491             close $gkey;
492           }
493           mkdirp("$spooldir/$gm/\@GROUP");
494           symlink "../../$user/\@GROUP/$group","$spooldir/$gm/\@GROUP/$group";
495         }
496       }
497     }
498     close $gf;
499   }
500 }
501
502 sub cpav {
503   my $dd = pop @_;
504   local *P;
505   
506   die "cpav: $dd is not a directory" unless -d $dd;
507   open P,"tar cf - @_ | su -c 'cd $dd; umask 022; tar xvf - 2>&1' fex |" 
508     or die "cpav: cannot tar - $!\n";
509   while (<P>) {
510     chomp;
511     print "$_ --> $dd/$_\n" unless /\/$/;
512   }
513   close P;
514 }