home *** CD-ROM | disk | FTP | other *** search
/ ftp.ncftp.com / ftp.ncftp.com.zip / ftp.ncftp.com / ncftpd / end_of_life / ncftpd-2.8.7-linux-x86-glibc2.1-export.tar.gz / ncftpd-2.8.7-linux-x86-glibc2.1-export.tar / ncftpd-2.8.7 / install_ncftpd.pl next >
Perl Script  |  2011-01-17  |  116KB  |  4,254 lines

  1. #!/usr/bin/perl -w
  2. #
  3. # This script is Copyright (C) 2002-2006 by Mike Gleason, NcFTP Software.
  4. # All Rights Reserved.
  5. #
  6. # This script tries to use the "lsof" utility if the package included it.
  7. # Thanks to Vic Abell <abe@purdue.edu> of the Purdue University
  8. # Computing Center for providing "lsof".
  9. #
  10. use strict;
  11. use Socket;
  12. use File::Copy;
  13. use POSIX qw(strftime);
  14.  
  15. # Porting checklist:
  16. #   df behavior
  17. #   du -s -k
  18. #   ps behavior
  19. #   echo -n / echo \c
  20. #   rc scripts
  21. #   lsof
  22. #   /var/log preference
  23. #   adduser program
  24. #   uninstall_ncftpd.pl
  25. #
  26.  
  27. my ($verbose)                 = 1;
  28. my ($force_install)            = 0;
  29. my ($prefix)                 = "";
  30. my ($eprefix)                 = "";
  31. my ($bindir)                 = "";
  32. my ($sbindir)                 = "";
  33. my ($datadir)                = "";
  34. my ($sysconfdir)            = "";
  35. my ($runtimedatadir)            = "/var/run";
  36. my ($logdir)                = "/var/log";
  37. my ($libdir)                = "";
  38. my ($includedir)            = "";
  39. my ($mandir)                = "";
  40. my ($ftpuser_preferred)            = "ftp";
  41. my ($ftpgroup_preferred)        = "ftp";
  42. my ($ftpuser)                = $ftpuser_preferred;
  43. my ($ftpgroup)                = $ftpgroup_preferred;
  44. my ($ftpuid)                = -1;
  45. my ($ftpgid)                = -1;
  46. my ($webuser)                = "";
  47. my ($webgroup)                = "";
  48. my ($webuid)                = -1;
  49. my ($webgid)                = -1;
  50. my ($host)                = "";
  51. my ($OS)                = "";
  52. my ($SYS)                = "";
  53. my ($linux_libc)            = "";
  54. my ($ftphome)                = "";
  55. my ($ncftpd_running_at_time_of_install)    = 0;
  56. my ($xinetd_running_at_time_of_install)    = 0;
  57. my ($inetd_running_at_time_of_install)    = 0;
  58. my ($lsof)                = "";
  59. my ($perl)                = "";
  60. my ($ftpport)                = 21;
  61. my ($ftpservicename)            = "ftp";
  62. my ($install_version)            = "";
  63. my ($existing_version)            = "";
  64. my ($existing_ncftpd)            = "";
  65. my ($existing_general_cf)        = "";
  66. my ($existing_domain_cf)        = "";
  67. my ($new_general_cf)            = "";
  68. my ($new_domain_cf)            = "";
  69. my ($new_ncftpd)            = "";
  70. my ($confdir)                = "";
  71. my ($rptbindir)                = "";
  72. my ($install_src_root)            = "";
  73. my ($extra_paths)            = "";
  74. my ($create_new_configs)        = 0;
  75. my ($inittab_preferred)            = 0;
  76. my ($run_ncftpd_verbose)         = 0;
  77. my ($startup_error_log)            = "";
  78. my ($rc_startup_script)            = "";
  79. my ($inittab_startup_script)        = "";
  80. my ($linux_distro)            = "";
  81. my ($linux_distro_class)        = "";
  82. my ($linux_distro_version)        = "";
  83. my ($linux_distro_version_num)        = 0;
  84. my ($linux_distro_release_file)        = "";
  85. my ($install_log)            = "";
  86. my ($pager)                 = "";
  87. my ($pager_pid)                = 0;
  88. my (@uninstall_items)            = ();
  89. my ($uninstaller)            = "";
  90. my ($binary_compat_err)            = "";
  91. my ($remove_ftp_from_ftpusers)        = 1;
  92.  
  93.  
  94.  
  95. sub Usage
  96. {
  97.     print <<EOF;
  98. Usage: $0 [options]
  99. Options: [defaults in brackets after descriptions]
  100. Invocation:
  101.   --help                  Print this message
  102.   --quiet, --silent       Do not print `checking...' messages
  103.   --debug                 Print debugging messages
  104. Directory and file names:
  105.   --prefix=PREFIX         Install architecture-independent files in PREFIX
  106.                           [/usr/local]
  107.   --exec-prefix=EPREFIX   Install architecture-dependent files in EPREFIX
  108.                           [same as prefix]
  109.   --bindir=DIR            User executables in DIR [EPREFIX/bin]
  110.   --sbindir=DIR           System admin executables in DIR [EPREFIX/sbin]
  111.   --sysconfdir=DIR        Read-only single-machine data in DIR [PREFIX/etc]
  112.   --runtimedatadir=DIR    Dynamic runtime state information DIR [$runtimedatadir]
  113.   --logdir=DIR            Create log files in DIR [$logdir]
  114.   --lsof=FILE             Use FILE as path to list-open-files program
  115. Features and packages:
  116.   --port=NUMBER           Install on port NUMBER [21]
  117.   --create-new-configs    Do not try to reuse existing configs, if present
  118.   --inittab               Run NcFTPd from /etc/inittab rather than an RC script
  119.   --enable-verbose-mode   Enable verbose logging mode by default
  120.   --leave-ftp-in-ftpusers Do not try to remove "ftp" from /etc/ftpusers
  121. EOF
  122.     Exit(2);
  123. }    # Usage
  124.  
  125.  
  126.  
  127. sub StripExtraSlashes
  128. {
  129.     my ($dir) = @_;
  130.     $dir =~ s/\/{2,}/\//g;
  131.     return ($dir) if ($dir eq "/");
  132.     $dir =~ s/\/+$//g;
  133.     return ($dir);
  134. }    # StripExtraSlashes    
  135.  
  136.  
  137.  
  138.  
  139. sub Getopts
  140. {
  141.     my($i, $arg, $val);
  142.  
  143.     for ($i = 0; $i < scalar(@ARGV); $i++) {
  144.         $arg = $ARGV[$i];
  145.         if ($arg eq "--help") {
  146.             Usage();
  147.         } elsif ($arg eq "--force") {
  148.             $force_install = 1;
  149.         } elsif ($arg eq "--create-new-configs") {
  150.             $create_new_configs = 1;
  151.         } elsif ($arg eq "--leave-ftp-in-ftpusers") {
  152.             $remove_ftp_from_ftpusers = 0;
  153.         } elsif ($arg eq "--inittab") {
  154.             if (! -f "/etc/inittab") {
  155.                 Exit(1, "This system does not use /etc/inittab.\n");
  156.             }
  157.             $inittab_preferred = 1;
  158.         } elsif ($arg eq "--silent") {
  159.             $verbose = 0;
  160.         } elsif ($arg eq "--quiet") {
  161.             $verbose = 0;
  162.         } elsif ($arg eq "--debug") {
  163.             $verbose = 2;
  164.         } elsif ($arg =~ /^-{1,2}(v+)(=(.*))?$/) {
  165.             if (defined($3)) {
  166.                 $run_ncftpd_verbose = int($3);
  167.             } else {
  168.                 $run_ncftpd_verbose = length($1);
  169.             }
  170.         } elsif ($arg =~ /^(--enable-verbose-mode|--with-verbose-mode)(=(.*))?$/) {
  171.             $run_ncftpd_verbose = 1;
  172.             if (defined($3)) {
  173.                 $run_ncftpd_verbose = int($3);
  174.             }
  175.         } elsif ($arg =~ /^--debug=(.*)/) {
  176.             $val = int($1);
  177.             Exit(1, "$val is not a valid debugging level.\n")
  178.                 if (($val < 0) || ($val > 10));
  179.             $verbose = $val;
  180.         } elsif ($arg =~ /^--port=(.*)/) {
  181.             $val = int($1);
  182.             Exit(1, "$val is not a valid port number.\n")
  183.                 if (($val < 1) || ($val >= 65535));
  184.             $ftpport = $val;
  185.         } elsif ($arg =~ /^--lsof=(.*)/) {
  186.             $val = StripExtraSlashes($1);
  187.             Exit(1, "$val is not an absolute pathname.\n")
  188.                 if ($val !~ /^\//);
  189.             $lsof = $val;
  190.         } elsif ($arg =~ /^--prefix=(.*)/) {
  191.             $val = StripExtraSlashes($1);
  192.             Exit(1, "$val is not an absolute pathname.\n")
  193.                 if ($val !~ /^\//);
  194.             $prefix = $val;
  195.         } elsif ($arg =~ /^--exec-prefix=(.*)/) {
  196.             $val = StripExtraSlashes($1);
  197.             Exit(1, "$val is not an absolute pathname.\n")
  198.                 if ($val !~ /^\//);
  199.             $eprefix = $val;
  200.         } elsif ($arg =~ /^--bindir=(.*)/) {
  201.             $val = StripExtraSlashes($1);
  202.             Exit(1, "$val is not an absolute pathname.\n")
  203.                 if ($val !~ /^\//);
  204.             $bindir = $val;
  205.         } elsif ($arg =~ /^--sbindir=(.*)/) {
  206.             $val = StripExtraSlashes($1);
  207.             Exit(1, "$val is not an absolute pathname.\n")
  208.                 if ($val !~ /^\//);
  209.             $sbindir = $val;
  210.         } elsif ($arg =~ /^--datadir=(.*)/) {
  211.             $val = StripExtraSlashes($1);
  212.             Exit(1, "$val is not an absolute pathname.\n")
  213.                 if ($val !~ /^\//);
  214.             $datadir = $val;
  215.         } elsif ($arg =~ /^--sysconfdir=(.*)/) {
  216.             $val = StripExtraSlashes($1);
  217.             Exit(1, "$val is not an absolute pathname.\n")
  218.                 if ($val !~ /^\//);
  219.             $sysconfdir = $val;
  220.         } elsif ($arg =~ /^--runtimedatadir=(.*)/) {
  221.             $val = StripExtraSlashes($1);
  222.             Exit(1, "$val is not an absolute pathname.\n")
  223.                 if ($val !~ /^\//);
  224.             $runtimedatadir = $val;
  225.         } elsif ($arg =~ /^--logdir=(.*)/) {
  226.             $val = StripExtraSlashes($1);
  227.             Exit(1, "$val is not an absolute pathname.\n")
  228.                 if ($val !~ /^\//);
  229.             $logdir = $val;
  230.         } elsif ($arg =~ /^--libdir=(.*)/) {
  231.             $val = StripExtraSlashes($1);
  232.             Exit(1, "$val is not an absolute pathname.\n")
  233.                 if ($val !~ /^\//);
  234.             $libdir = $val;
  235.         } elsif ($arg =~ /^--includedir=(.*)/) {
  236.             $val = StripExtraSlashes($1);
  237.             Exit(1, "$val is not an absolute pathname.\n")
  238.                 if ($val !~ /^\//);
  239.             $includedir = $val;
  240.         } elsif ($arg =~ /^--mandir=(.*)/) {
  241.             $val = StripExtraSlashes($1);
  242.             Exit(1, "$val is not an absolute pathname.\n")
  243.                 if ($val !~ /^\//);
  244.             $mandir = $val;
  245.         } else {
  246.             printf ("Argument not recognized: \"%s\".\nTry \"%s --help\" command line options.\n", $arg, $0);
  247.             Exit(3);
  248.         }
  249.     }
  250.  
  251.     $prefix = "/usr/local" if (! $prefix);
  252.     $eprefix = $prefix if (! $eprefix);
  253.     $bindir = $eprefix . "/bin" if (! $bindir);
  254.     $sbindir = $eprefix . "/sbin" if (! $sbindir);
  255.     $datadir = $prefix . "/share" if (! $datadir);
  256.     $sysconfdir = $prefix . "/etc" if (! $sysconfdir);
  257.     $runtimedatadir = "/var" if (! $runtimedatadir);
  258.     $libdir = $eprefix . "/lib" if (! $libdir);
  259.     $includedir = $prefix . "/include" if (! $includedir);
  260.     $mandir = $prefix . "/man" if (! $mandir);
  261.  
  262.     $confdir = "$sysconfdir/ncftpd";
  263.     $rptbindir = "$sysconfdir/ncftpd/rptbin";
  264.     $new_general_cf = "$confdir/general.cf";
  265.     $new_domain_cf = "$confdir/domain.cf";
  266.     $new_ncftpd = "$sbindir/ncftpd";
  267.  
  268.     if ($verbose > 1) {
  269.         Log(1, "prefix=$prefix\n");
  270.         Log(1, "eprefix=$eprefix\n");
  271.         Log(1, "bindir=$bindir\n");
  272.         Log(1, "sbindir=$sbindir\n");
  273.         Log(1, "datadir=$datadir\n");
  274.         Log(1, "sysconfdir=$sysconfdir\n");
  275.         Log(1, "runtimedatadir=$runtimedatadir\n");
  276.         Log(1, "logdir=$logdir\n");
  277.     #    Log(1, "libdir=$libdir\n");
  278.     #    Log(1, "includedir=$includedir\n");
  279.     #    Log(1, "mandir=$mandir\n");
  280.         Log(1, "port=$ftpport\n");
  281.         Log(1, "run_ncftpd_verbose=$run_ncftpd_verbose\n");
  282.         Log(1, "\n");
  283.     }
  284. }    # Getopts
  285.  
  286.  
  287.  
  288.  
  289. sub Mkdirs
  290. {
  291.     my ($path, $mode, $uid, $gid) = @_;
  292.     my ($subpath);
  293.     my ($i, $n, $e);
  294.     my (@nodes);
  295.     my($absolute) = 0;
  296.  
  297.     if (!defined($mode)) { $mode = 00755; }        # Umask will NOT affect.
  298.     @nodes = split(/\/+/, $path);
  299.  
  300.     $n = scalar(@nodes);
  301.     return 1 if ($n <= 0);        # It was just the root directory
  302.  
  303.     if ($nodes[0] eq "") {
  304.         #
  305.         # Absolute paths will leave us with an
  306.         # empty first node.
  307.         #
  308.         $absolute = 1;
  309.         shift(@nodes);
  310.         $n--;
  311.     }
  312.  
  313.     #
  314.     # Find the greatest part of the path that
  315.     # already exists.  We will then create the
  316.     # remaining nodes.
  317.     #
  318.     while (1) {
  319.         $subpath = "";
  320.         if ($absolute) { $subpath = "/"; }
  321.         for ($i = 0; $i < $n; $i++) {
  322.             $subpath .= $nodes[$i] . "/";
  323.         }
  324.         chop($subpath);
  325.         last if (-d "$subpath");
  326.         if (--$n <= 0) {
  327.             $subpath = "";
  328.             $n = 0;
  329.             last;
  330.         }
  331.     }
  332.  
  333.     #
  334.     # We now have in $subpath the portion of $path
  335.     # that already exists.  We now just need to
  336.     # create the remaining node(s).  We have in $n
  337.     # the number of successive nodes which exist.
  338.     #
  339.     $e = $n;
  340.     $n = scalar(@nodes);
  341.     return 1 if ($e == $n);            # Entire path already exists
  342.  
  343.     for ($i = $e ; $i < $n; $i++) {
  344.         if (($subpath eq "") && (! $absolute)) {
  345.             $subpath = $nodes[$i];
  346.         } else {
  347.             $subpath .= "/" . $nodes[$i];
  348.         }
  349.         return 0 if (! mkdir($subpath,$mode));
  350.         chown($uid, $gid, $subpath) if (($> == 0) && (defined($uid)) && (defined($gid)));
  351.         chmod($mode, $subpath);
  352.         UninstallLog("Rmdir(\"$subpath\");\n");
  353.     }
  354.  
  355.     return 1;                # Finished
  356. }    # Mkdirs
  357.  
  358.  
  359.  
  360. sub DiskFreeBytes
  361. {
  362.     my ($path) = @_;
  363.     my ($dfresult) = "";    
  364.     my (@dflines);
  365.     my (@column_headers);
  366.     my (@column_values);
  367.     my ($blocksize) = 0;
  368.  
  369.     $path = "\'$path\'";
  370.     if ($^O eq "sco3.2v5.0") {
  371.         $dfresult = `df -P -k $path 2>/dev/null`;
  372.     } elsif ($^O eq "sunos") {
  373.         $dfresult = `/usr/bin/df $path 2>/dev/null`;
  374.     } else {
  375.         $dfresult = `df -k $path 2>/dev/null`;
  376.     }
  377.  
  378.     #
  379.     # This is an ugly hack, but it's pick your poison:
  380.     # Parse "df" output which varies per platform,
  381.     # or try to use even more variants of statfs
  382.     # and friends from within Perl.
  383.     #
  384.     # The "df" option also implies that the user must
  385.     # be running in English for this to work, but this
  386.     # is still the most feasible option.
  387.     #
  388.     @dflines = split(/\r?\n/, $dfresult);
  389.     return (-1) if (scalar(@dflines) < 2);
  390.  
  391. # aix> df -k /usr/local/bin
  392. # Filesystem    1024-blocks      Free %Used    Iused %Iused Mounted on
  393. # /dev/hd2           749568     20136   98%    28087    15% /usr
  394.  
  395. # solaris> df -k /usr/local/bin
  396. # Filesystem            kbytes    used   avail capacity  Mounted on
  397. # /dev/dsk/c0t0d0s3    3527406 1175661 2316471    34%    /opt
  398.  
  399. # sunos> /usr/bin/df /usr/local
  400. # Filesystem            kbytes    used   avail capacity  Mounted on
  401. # /dev/sd0h             665662  380527  218569    64%    /home
  402.  
  403. # unixware7> df -k /usr/local/bin
  404. # filesystem          kbytes   used     avail    capacity  mounted on
  405. # /dev/root           2369587  729785   1639802  31%       /
  406.  
  407. # openunix8> df -k /usr/local/bin
  408. # filesystem          kbytes   used     avail    capacity  mounted on
  409. # /dev/root           8209215  1601741  6607474  20%       /
  410.  
  411. # linux> df -k /usr/local/bin
  412. # Filesystem           1k-blocks      Used Available Use% Mounted on
  413. # /dev/sdb5             31245640  15312240  14346180  52% /usr
  414.  
  415. # linux (Fedora 4 with logical volume groups) > df -k /usr/local/bin
  416. # Filesystem           1K-blocks      Used Available Use% Mounted on
  417. # /dev/mapper/VolGroup00-LogVol00
  418. #                        3301112   2709544    421176  87% /
  419.  
  420. # openbsd> df -k /usr/local/bin
  421. # Filesystem  1K-blocks     Used    Avail Capacity  Mounted on
  422. # /dev/sd0a     1770994   233886  1448559    14%    /
  423.  
  424. # bsd/os> df -k /usr/local/bin
  425. # Filesystem  1024-blocks     Used    Avail Capacity  Mounted on
  426. # /dev/sd0h       3998700   921434  2877331    24%    /usr
  427.  
  428. # irix> df -k /usr/local/bin
  429. # Filesystem             Type  kbytes     use     avail  %use Mounted on
  430. # /dev/root               xfs  1962860  1568024   394836  80  /
  431.  
  432. # tru64unix> df -k /usr/local/bin
  433. # Filesystem     1024-blocks        Used   Available Capacity  Mounted on
  434. # usr_domain#usr     2150400      782697     1307000    38%    /usr
  435. #
  436.  
  437. # scosv> df -P -k /usr/local/bin
  438. # Filesystem         1024-blocks     Used Available Capacity Mounted on
  439. # /dev/root              4893578   909216   3984362      19% /usr/local
  440.  
  441.     @column_headers = split(' ', $dflines[0]);
  442.     @column_values = split(' ', $dflines[1]);
  443.  
  444.     # Hack for Linux with logical volumes
  445.     if ((scalar(@column_values) == 1) && ($dflines[2] =~ /^\s/)) {
  446.         # Filesystem           1K-blocks      Used Available Use% M...
  447.         # /dev/mapper/VolGroup00-LogVol00
  448.         #                        3301112   2709544    421176  87% /
  449.         @column_values = split(' ', $dflines[2]);
  450.         unshift(@column_values, "/dev/null");
  451.     }
  452.  
  453.     if ((scalar(@column_headers) >= 5) && (scalar(@column_values) >= 5)) {
  454.         if ($column_headers[1] eq "1k-blocks") {
  455.             $blocksize = 1024;
  456.         } elsif ($column_headers[1] eq "1024-blocks") {
  457.             $blocksize = 1024;
  458.         } elsif ($column_headers[1] eq "1K-blocks") {
  459.             $blocksize = 1024;
  460.         } elsif (($column_headers[1] eq "kbytes") && ($column_headers[2] eq "used")) {
  461.             $blocksize = 1024;
  462.         } elsif (($column_headers[2] eq "kbytes") && ($column_headers[3] eq "use")) {
  463.             $blocksize = 1024;
  464.         }
  465.  
  466.         if ($blocksize == 1024) {
  467.             if ($column_headers[2] eq "Free") {
  468.                 return ($blocksize * $column_values[2]);
  469.             } elsif ($column_headers[3] eq "avail") {
  470.                 return ($blocksize * $column_values[3]);
  471.             } elsif ($column_headers[3] eq "Avail") {
  472.                 return ($blocksize * $column_values[3]);
  473.             } elsif ($column_headers[3] eq "Available") {
  474.                 return ($blocksize * $column_values[3]);
  475.             } elsif ($column_headers[4] eq "avail") {
  476.                 return ($blocksize * $column_values[4]);
  477.             }
  478.         }
  479.     }
  480.  
  481. # hp-ux> > df -k /usr/local/bin
  482. # /software/common       (/dev/vg00/lvol14      ) :  2235975 total allocated Kb
  483. #                                                     408093 free allocated Kb
  484. #                                                    1827882 used allocated Kb
  485. #                                                         81 % allocation used
  486.     if ($dfresult =~ /(\d+).free.allocated.Kb/s) {
  487.         return (int($1) * 1024);
  488.     }
  489.  
  490.     return (-1);
  491. }    # DiskFreeBytes
  492.  
  493.  
  494.  
  495.  
  496. sub PsGrep
  497. {
  498.     my ($pattern, $match_mode, $output, $pscmd) = @_;
  499.     my (@column_headers);
  500.     my (@column_values);
  501.     my ($column_number);
  502.     my ($line, $col);
  503.     my ($pid_column) = 0;
  504.     my ($command_pos) = 0;
  505.     my ($command) = 0;
  506.     my ($two_column_format) = 0;
  507.     my (@pids) = ();
  508.  
  509.     return () unless (defined($pattern));
  510.     $match_mode = "program" unless (defined($match_mode));
  511.     $output = "pids" unless (defined($output));
  512.  
  513.     if ((! defined($pscmd)) || (! $pscmd)) {
  514.         if ($^O =~ /^(solaris|aix|dec_osf|sco3.2v5.0|svr4)$/) {
  515.             $pscmd = "/bin/ps -e -o pid,args";
  516.         } elsif ($^O =~ /^(linux)$/) {
  517.             $pscmd = "/bin/ps -w -e -o pid,args";
  518.             if (open(PSCOMMAND, "/bin/ps --version |")) {
  519.                 $line = <PSCOMMAND>;
  520.                 close(PSCOMMAND);
  521.                 $pscmd = "/bin/ps auxw" if ($line =~ /version\s1/);
  522.             }
  523.         } elsif ($^O =~ /^(hpux)$/) {
  524.             $pscmd = "/bin/ps -ef";
  525.         } elsif ($^O =~ /^(unixware|openunix)$/) {
  526.             $pscmd = "/usr/bin/ps -ef";
  527.         } elsif ($^O =~ /^(freebsd|netbsd|openbsd|bsdos)$/) {
  528.             $pscmd = "/bin/ps -axw -o pid,command";
  529.         } elsif ($^O =~ /^(darwin|rhapsody)$/) {
  530.             $pscmd = "/bin/ps -auxw";
  531.         } elsif ($^O eq "irix") {
  532.             $pscmd = "/sbin/ps -e -o pid,args";
  533.         } elsif ($^O eq "sunos") {
  534.             $pscmd = "/bin/ps -axw";
  535.         } else {
  536.             $pscmd = "ps -ef";
  537.         }
  538.     }
  539.     $two_column_format = 1 if ($pscmd =~ /pid,/);
  540.  
  541.     if (open(PSCOMMAND, "$pscmd 2>/dev/null |")) {
  542.         unless (defined($line = <PSCOMMAND>)) {
  543.             close(PSCOMMAND);
  544.             return ();
  545.         }
  546.         if ($two_column_format) {
  547.             $pid_column = 0;
  548.             if ($match_mode eq "program") {
  549.                 $pattern = '^' . $pattern . '$'; 
  550.             }
  551.             while (defined($line = <PSCOMMAND>)) {
  552.                 chomp($line);
  553.                 @column_values = split(' ', $line, 2);
  554.                 $command = $column_values[1];
  555.                 $command =~ s/://;
  556.                 next unless defined($command);
  557.  
  558.                 if ($match_mode ne "full") {
  559.                     my (@a) = split(' ', $command);
  560.                     $command = $a[0];
  561.                     next unless defined($command);
  562.                 }
  563.                 if ($match_mode eq "program") {
  564.                     my (@a) = split(/\//, $command);
  565.                     $command = $a[-1];
  566.                     next unless defined($command);
  567.                     if ($command =~ /^[\(\[](.*)[\)\]]$/) {
  568.                         $command = $1;
  569.                         next unless defined($command);
  570.                     }
  571.                 }
  572.                 if ($command =~ /${pattern}/) {
  573.                     if ($output eq "long") {
  574.                         push(@pids, $line);
  575.                     } else {
  576.                         push(@pids, $column_values[$pid_column]);
  577.                     }
  578.                 }
  579.             }
  580.         } else {
  581.             $command_pos = index($line, "COMMAND");
  582.             $command_pos = index($line, "CMD") if ($command_pos <= 0);
  583.             unless ($command_pos > 0) {
  584.                 close(PSCOMMAND);
  585.                 return ();
  586.             }
  587.             @column_headers = split(' ', $line);
  588.             unless (scalar(@column_headers) > 0) {
  589.                 close(PSCOMMAND);
  590.                 return ();
  591.             }
  592.             $column_number = 0;
  593.             for $col (@column_headers) {
  594.                 $pid_column = $column_number if ($col eq "PID");
  595.                 $column_number++;
  596.             }
  597.             unless ($pid_column >= 0) {
  598.                 close(PSCOMMAND);
  599.                 return ();
  600.             }
  601.             if ($match_mode eq "program") {
  602.                 $pattern = '^' . $pattern . '$'; 
  603.             }
  604.             while (defined($line = <PSCOMMAND>)) {
  605.                 chomp($line);
  606.                 @column_values = split(' ', $line);
  607.                 $command = substr($line, $command_pos);
  608.                 $command =~ s/://;
  609.                 if ($match_mode ne "full") {
  610.                     my (@a) = split(' ', $command);
  611.                     $command = $a[0];
  612.                 }
  613.                 if ($match_mode eq "program") {
  614.                     my (@a) = split(/\//, $command);
  615.                     $command = $a[-1];
  616.                     if ($command =~ /^[\(\[](.*)[\)\]]$/) {
  617.                         $command = $1;
  618.                     }
  619.                 }
  620.                 if ($command =~ /${pattern}/) {
  621.                     if ($output eq "long") {
  622.                         push(@pids, $line);
  623.                     } else {
  624.                         push(@pids, $column_values[$pid_column]);
  625.                     }
  626.                 }
  627.             }
  628.         }
  629.         close(PSCOMMAND);
  630.     }
  631.  
  632.     return (@pids);
  633. }    # PsGrep
  634.  
  635.  
  636.  
  637.  
  638. sub SearchPath 
  639. {
  640.     my ($prog, $pathstotryfirst, $pathstoignore) = @_;
  641.     return ("") if ((! defined($prog)) || (! $prog));
  642.  
  643.     my (@ignore_paths) = ();
  644.     my ($PATH) = $ENV{"PATH"};
  645.     $PATH = "/bin:/usr/bin" if ((! defined($PATH)) || (! $PATH));
  646.     if ((defined($pathstotryfirst)) && ($pathstotryfirst ne "")) {
  647.         $PATH = "$pathstotryfirst:$PATH";
  648.     }
  649.     if ((defined($pathstoignore)) && ($pathstoignore ne "")) {
  650.         @ignore_paths = split(/:/, $pathstoignore);
  651.     }
  652.  
  653.     my (@path) = split(/:/, $PATH);
  654.     my ($dir, $pathprog, $idir, $ignore);
  655.     for $dir (@path) {
  656.         $ignore = 0;
  657.         for $idir (@ignore_paths) {
  658.             if ($idir eq $dir) {
  659.                 $ignore = 1;
  660.             }
  661.         }
  662.         next if ($ignore);
  663.         $pathprog = "$dir/$prog";
  664.         return ($pathprog) if (-x $pathprog);
  665.     }
  666.     return ("");
  667. }    # SearchPath
  668.  
  669.  
  670.  
  671.  
  672. sub UninstallLog
  673. {
  674.     my (@more_uninst_items) = @_;
  675.     push(@uninstall_items, @more_uninst_items);
  676. }    # UninstallLog
  677.  
  678.  
  679.  
  680.  
  681. sub Log
  682. {
  683.     my ($v, @args) = @_;
  684.     my ($arg);
  685.  
  686.     return if (! defined($v));
  687.     if ($v !~ /\d+/) {
  688.         $arg = $v;
  689.         print LOG $arg if ($install_log ne "");
  690.         print $arg;
  691.         $v = 0;
  692.         print $arg if ($verbose > $v);
  693.     }
  694.  
  695.     if (scalar(@args)) {
  696.         for $arg (@args) {
  697.             print LOG $arg if ($install_log ne "");
  698.             print $arg if ($verbose > $v);
  699.         }
  700.     }
  701. }    # Log
  702.  
  703.  
  704.  
  705.  
  706. sub CreateCustomUninstaller
  707. {
  708.     my ($line);
  709.     my (@uninstaller) = ();
  710.     my ($uninstall_item);
  711.     my (@reversed_uninstall_items);
  712.     my ($ltime) = strftime("%Y-%m-%d %H:%M:%S %z", localtime(time()));
  713.     my ($skip) = 0;
  714.  
  715.     if (($uninstaller ne "") && (open(UNINST, "<$uninstaller"))) {
  716.         @uninstaller = <UNINST>;
  717.         close(UNINST);
  718.  
  719.         foreach $line (@uninstaller) {
  720.             if ($line eq "#---prologue---#\n") {
  721.                 $line .= "#---begin prologue set by $0 on $ltime---#\n";
  722.                 $line .= "\t\$OS = \"$OS\";\n";
  723.                 $line .= "\t\$SYS = \"$SYS\";\n";
  724.                 $line .= "\t\$linux_distro = \"$linux_distro\";\n";
  725.                 $line .= "\t\$ftpport = $ftpport;\n";
  726.                 $line .= "#---end prologue set by $0 on $ltime---#\n";
  727.             } elsif ($line eq "#---host-specific---#\n") {
  728.                 $line .= "#---begin host-specifics set by $0 on $ltime---#\n";
  729.                 $line .= "\tIsThereAnFTPServerServing();\n";
  730.                 @reversed_uninstall_items = reverse(@uninstall_items);
  731.                 for $uninstall_item (@reversed_uninstall_items) {
  732.                     chomp($uninstall_item);
  733.                     $line .= "\t$uninstall_item\n";
  734.                 }
  735.                 $line .= "\tIsThereAnFTPServerServing();\n";
  736.                 $line .= "\tExit(0);\n";
  737.                 $line .= "#---end host-specifics set by $0 on $ltime---#\n";
  738.             } elsif ($line =~ /^#---begin/) {
  739.                 #
  740.                 # Omit existing #---begin / #---end blocks if they exist.
  741.                 #
  742.                 $line = "";
  743.                 $skip = 1;
  744.             } elsif ($line =~ /^#---end/) {
  745.                 $line = "";
  746.                 $skip = 0;
  747.             } elsif ($skip == 1) {
  748.                 $line = "";
  749.             }
  750.         }
  751.  
  752.         if (open(UNINST, ">$uninstaller")) {
  753.             print UNINST @uninstaller;
  754.             close(UNINST);
  755.             chmod(0700, $uninstaller);
  756.         }
  757.     }
  758. }    # CreateCustomUninstaller
  759.  
  760.  
  761.  
  762.  
  763. sub Exit
  764. {
  765.     my ($es, @reason) = @_;
  766.     if (scalar(@reason)) {
  767.         Log(0, @reason);
  768.     }
  769.     if ($install_log ne "") {
  770.         my ($ltime) = strftime("%Y-%m-%d %H:%M:%S %z", localtime(time()));
  771.         print LOG "--- Log closed at $ltime ---\n";
  772.         close(LOG);
  773.         if ($confdir ne "") {
  774.             unlink("$confdir/install_ncftpd.log");
  775.             if (move($install_log, "$confdir/install_ncftpd.log")) {
  776.                 $install_log = "$confdir/install_ncftpd.log";
  777.             }
  778.         }
  779.         print "\nInstallation log saved as $install_log.\n";
  780.         UninstallLog("Remove(\"$install_log\");\n");
  781.         $install_log = "";
  782.         CreateCustomUninstaller();
  783.     }
  784.     exit($es);
  785. }    # Exit
  786.  
  787.  
  788.  
  789.  
  790. sub OpenLog
  791. {
  792.     if (open(LOG, ">/etc/install_ncftpd.log")) {
  793.         my ($ltime) = strftime("%Y-%m-%d %H:%M:%S %z", localtime(time()));
  794.         $install_log = "/etc/install_ncftpd.log";
  795.         print LOG "--- Log created at $ltime ---\n";
  796.     }
  797. }    # OpenLog
  798.  
  799.  
  800.  
  801.  
  802. sub OpenPager
  803. {
  804.     if (-t STDOUT) {
  805.         if ((defined($ENV{"PAGER"})) && (-x $ENV{"PAGER"})) {
  806.             $pager = $ENV{"PAGER"};
  807.         } elsif (-x "/usr/bin/less") {
  808.             $pager = "/usr/bin/less";
  809.         } elsif (-x "/usr/bin/more") {
  810.             $pager = "/usr/bin/more";
  811.         } elsif (-x "/bin/more") {
  812.             $pager = "/bin/more";
  813.         } elsif (-x "/usr/bin/pg") {
  814.             $pager = "/usr/bin/pg";
  815.         }
  816.         if ($pager ne "") {
  817.             $pager_pid = open(STDOUT, "| $pager");
  818.             if ($pager_pid > 0) {
  819.                 $SIG{PIPE} = 'IGNORE';
  820.                 $| = 1;
  821.             }
  822.         }
  823.     } else {
  824.         $| = 1;
  825.     }
  826. }    # OpenPager
  827.  
  828.  
  829.  
  830.  
  831. sub SetOSVar
  832. {
  833.     my ($os)                = "";
  834.     my ($os_v)                = "";
  835.     my ($os_r)                = "";
  836.     my ($archp)                = "";
  837.     my (@os_r)                = (0,0,0);
  838.     my (@os_v)                = (0,0,0);
  839.     my ($arch)                = "";
  840.     my ($line);
  841.  
  842.     $host = lc( `uname -n 2>/dev/null` );
  843.     chomp($host);
  844.     Log(2, "host = $host\n");
  845.  
  846.     $os = lc( `uname -s 2>/dev/null` );
  847.     chomp($os);
  848.     Log(2, "os = $os\n");
  849.  
  850.     $os_v = lc( `uname -v 2>/dev/null` );
  851.     chomp($os_v);
  852.     if ($os_v =~ /(\d+(\.\d+)*)/) {
  853.         # Get just the version digit string
  854.         $os_v = $1;
  855.         @os_v = split(/\./, $os_v);
  856.     }
  857.     Log(2, "os_v = $os_v\n");
  858.  
  859.     $os_r = lc( `uname -r 2>/dev/null` );
  860.     chomp($os_r);
  861.     if ($os_r =~ /(\d+(\.\d+)*)/) {
  862.         # Get just the version digit string
  863.         $os_r = $1;
  864.         @os_r = split(/\./, $os_r);
  865.     }
  866.     Log(2, "os_r = $os_r\n");
  867.  
  868.     $arch = lc( `uname -m 2>/dev/null` );
  869.     chomp($arch);
  870.     Log(2, "arch = $arch\n");
  871.  
  872.     $archp = lc( `uname -p 2>/dev/null` );
  873.     chomp($archp);
  874.     Log(2, "archp = $archp\n");
  875.  
  876.     if ($os eq "osf1") {
  877.         if (($os_r[0] == 3) || ($os_r[0] == 4)) {
  878.             $OS = "digitalunix${os_r}-$arch";
  879.             $SYS = "digitalunix";
  880.         } else {
  881.             $OS = "tru64unix${os_r}-$arch";
  882.             $SYS = "tru64unix";
  883.         }
  884.     } elsif ($os eq "aix") {
  885.         $OS = "aix${os_v}.${os_r}";
  886.         $SYS = "aix";
  887.     } elsif ($os eq "irix") {
  888.         $OS = "irix${os_r}";
  889.         $SYS = "irix";
  890.     } elsif ($os eq "irix64") {
  891.         $OS = "irix64_${os_r}";
  892.         $SYS = "irix64";
  893.     } elsif ($os eq "hp-ux") {
  894.         $OS = "hpux${os_r}";
  895.         $SYS = "hpux";
  896.     } elsif ($os eq "freebsd") {
  897.         $OS = "freebsd${os_r}-$arch";
  898.         $SYS = "freebsd";
  899.     } elsif ($os eq "netbsd") {
  900.         $OS = "netbsd${os_r}-$arch";
  901.         $SYS = "netbsd";
  902.     } elsif ($os eq "openbsd") {
  903.         $OS = "openbsd${os_r}-$arch";
  904.         $SYS = "openbsd";
  905.     } elsif ($os =~ "^sco") {
  906.         $OS = "scosv";
  907.         $SYS = "sco";
  908.     } elsif ($os =~ "^dynix") {
  909.         $OS = "dynixptx${os_v}";
  910.         $SYS = "dynixptx";
  911.     } elsif ($os eq "linux") {
  912.         my ($libc) = "";
  913.  
  914.         $arch = "x86" if ($arch =~ /86$/);
  915.     
  916.         my ($tmpfile, $rnd);
  917.         $rnd = int(rand(10000));
  918.         $tmpfile = $0;
  919.         $tmpfile =~ s/^.*\///;
  920.         $tmpfile = "$tmpfile.$$.$rnd";
  921.         if ((-d "/root") && ($> == 0)) {
  922.             $tmpfile = "/root/$tmpfile";
  923.         } else {
  924.             # FIXME: /tmp race
  925.             #
  926.             $tmpfile = "/tmp/$tmpfile";
  927.         }
  928.         Log(2, "$tmpfile\n");
  929.         unlink("$tmpfile", "$tmpfile.c", "$tmpfile.o");
  930.         Exit(1, "Could not open $tmpfile.c: $!\n") unless open(TMPCFILE, "> $tmpfile.c");
  931.         print TMPCFILE <<EOF;
  932. #include <stdio.h>
  933. #include <stdlib.h>
  934. #ifdef HAVE_GNU_LIBC_VERSION_H
  935. #    include <gnu/libc-version.h>
  936. #else
  937. extern const char *gnu_get_libc_version(void);
  938. extern const char *gnu_get_libc_release(void);
  939. #endif
  940.  
  941. int main(void)
  942. {
  943.     const char *ver = gnu_get_libc_version();
  944.     const char *rel = gnu_get_libc_release();
  945.  
  946.     fprintf(stdout, "glibc%s\\n", ver);
  947.     exit(0);
  948. }
  949. EOF
  950.         Log(2, "created $tmpfile.c\n");
  951.         close(TMPCFILE);
  952.  
  953.         my ($CC);
  954.         if (-f "/usr/bin/gcc") {
  955.             $CC = "/usr/bin/gcc";
  956.         } elsif (-f "/usr/bin/cc") {
  957.             $CC = "/usr/bin/cc";
  958.         } else {
  959.             $CC = "cc";
  960.         }
  961.  
  962.         if (-f "/usr/include/gnu/libc-version.h") {
  963.             system("$CC", "-DHAVE_GNU_LIBC_VERSION_H", "$tmpfile.c", "-o", "$tmpfile") if ($CC ne "cc");
  964.         } else {
  965.             system("$CC", "$tmpfile.c", "-o", "$tmpfile") if ($CC ne "cc");
  966.         }
  967.         if (-f "$tmpfile") {
  968.             Log(2, "compiled $tmpfile.c to $tmpfile\n");
  969.             $libc=`$tmpfile`;
  970.             chomp($libc);
  971.             Log(2, "cc_libc = $libc\n");
  972.         }
  973.         unlink("$tmpfile", "$tmpfile.c", "$tmpfile.o");
  974.  
  975.         $OS = "linux-$arch";
  976.         $SYS = "linux";
  977.  
  978.         my ($f_libc) = "";
  979.         my @lib_libc = sort </lib/libc-*.*.so>;
  980.         for (my $li = scalar(@lib_libc) - 1; $li >= 0; $li--) {
  981.             if (-f $lib_libc[$li]) {
  982.                 $f_libc = $lib_libc[$li];
  983.                 Log(2, "f_libc = $f_libc\n");
  984.                 last;
  985.             }
  986.         }
  987.  
  988.         if ($libc =~ /^glibc/) {
  989.             if ($libc =~ /^(glibc\d+\.\d+)/) {
  990.                 $libc = $1;
  991.             }
  992.         } elsif ($f_libc =~ /libc-(\d+.\d+)/) {
  993.             $libc = "glibc" . $1;
  994.         } elsif (-f "/lib/libc-2.7.so") {
  995.             $libc = "glibc2.2";
  996.         } elsif (-f "/lib/libc-2.2.9.so") {
  997.             $libc = "glibc2.2";
  998.         } elsif (-f "/lib/libc-2.2.8.so") {
  999.             $libc = "glibc2.2";
  1000.         } elsif (-f "/lib/libc-2.2.7.so") {
  1001.             $libc = "glibc2.2";
  1002.         } elsif (-f "/lib/libc-2.2.6.so") {
  1003.             $libc = "glibc2.2";
  1004.         } elsif (-f "/lib/libc-2.2.5.so") {
  1005.             $libc = "glibc2.2";
  1006.         } elsif (-f "/lib/libc-2.2.4.so") {
  1007.             $libc = "glibc2.2";
  1008.         } elsif (-f "/lib/libc-2.2.3.so") {
  1009.             $libc = "glibc2.2";
  1010.         } elsif (-f "/lib/libc-2.2.2.so") {
  1011.             $libc = "glibc2.2";
  1012.         } elsif (-f "/lib/libc-2.2.1.so") {
  1013.             $libc = "glibc2.2";
  1014.         } elsif (-f "/lib/libc-2.2.0.so") {
  1015.             $libc = "glibc2.2";
  1016.         } elsif (-f "/lib/libc-2.1.3.so") {
  1017.             $libc = "glibc2.1";
  1018.         } elsif (-f "/lib/libc-2.1.2.so") {
  1019.             $libc = "glibc2.1";
  1020.         } elsif (-f "/lib/libc-2.1.1.so") {
  1021.             $libc = "glibc2.1";
  1022.         } elsif (-f "/lib/libc-2.1.0.so") {
  1023.             $libc = "glibc2.1";
  1024.         } elsif (-f "/lib/libc-2.1.so") {
  1025.             $libc = "glibc2.1";
  1026.         } elsif (-f "/lib/libc-2.0.0.so") {
  1027.             $libc = "glibc2.0";
  1028.         } elsif (-f "/lib/libc-2.0.1.so") {
  1029.             $libc = "glibc2.0";
  1030.         } elsif (-f "/lib/libc-2.0.2.so") {
  1031.             $libc = "glibc2.0";
  1032.         } elsif (-f "/lib/libc-2.0.3.so") {
  1033.             $libc = "glibc2.0";
  1034.         } elsif (-f "/lib/libc-2.0.4.so") {
  1035.             $libc = "glibc2.0";
  1036.         } elsif (-f "/lib/libc-2.0.5.so") {
  1037.             $libc = "glibc2.0";
  1038.         } elsif (-f "/lib/libc-2.0.6.so") {
  1039.             $libc = "glibc2.0";
  1040.         } elsif (-f "/lib/libc-2.0.7.so") {
  1041.             $libc = "glibc2.0";
  1042.         } elsif (-f "/lib/libc-2.0.8.so") {
  1043.             $libc = "glibc2.0";
  1044.         } elsif (-f "/lib/libc-2.0.9.so") {
  1045.             $libc = "glibc2.0";
  1046.         } elsif (-f "/lib/libc.so.6") {
  1047.             $libc = "glibc2.0";
  1048.         } elsif (-f "/lib/libc.so.6.1") {
  1049.             $libc = "glibc2.0";
  1050.         } else {
  1051.             $libc = "libc5";
  1052.         }
  1053.         $linux_libc = $libc;
  1054.  
  1055.         $linux_distro = "unknown";
  1056.         if (-f "/etc/SuSE-release") {
  1057.             $linux_distro = "SuSE";
  1058.             $linux_distro_release_file = "/etc/SuSE-release";
  1059.         } elsif (-f "/etc/turbolinux-release") {
  1060.             $linux_distro = "TurboLinux";
  1061.             $linux_distro_release_file = "/etc/turbolinux-release";
  1062.         } elsif (-f "/etc/slackware-version") {
  1063.             $linux_distro = "Slackware";
  1064.             $linux_distro_release_file = "/etc/slackware-version";
  1065.         } elsif (-f "/etc/slackware-release") {
  1066.             $linux_distro = "Slackware";
  1067.             $linux_distro_release_file = "/etc/slackware-release";
  1068.         } elsif (-f "/etc/mandriva-release") {
  1069.             $linux_distro = "Mandriva";
  1070.             $linux_distro_release_file = "/etc/mandriva-release";
  1071.         } elsif (-f "/etc/mandrake-release") {
  1072.             $linux_distro = "Mandrake";
  1073.             $linux_distro_release_file = "/etc/mandrake-release";
  1074.         } elsif (-f "/etc/cobalt-release") {
  1075.             $linux_distro = "Cobalt";
  1076.             $linux_distro_release_file = "/etc/cobalt-release";
  1077.         } elsif (-f "/etc/debian_version") {
  1078.             $linux_distro_class = "Debian";
  1079.             $linux_distro = "Debian";    # May be overridden down below
  1080.             $linux_distro_release_file = "/etc/debian_version";
  1081.         } elsif (-f "/etc/conectiva-release") {
  1082.             $linux_distro = "Conectiva";
  1083.             $linux_distro_release_file = "/etc/conectiva-release";
  1084.         } elsif (open(RH, "</etc/redhat-release")) {
  1085.             $line = <RH>;
  1086.             close(RH);
  1087.             $linux_distro = "Red Hat";
  1088.             if ($line =~ /^Red\ Hat\ Linux/) {
  1089.                 $linux_distro = "Red Hat";
  1090.                 $linux_distro_release_file = "/etc/redhat-release";
  1091.             } elsif ($line =~ /^Fedora/) {
  1092.                 $linux_distro = "Fedora Core";
  1093.                 $linux_distro_release_file = "/etc/redhat-release";
  1094.             } elsif ($line =~ /^LinuxPPC/) {
  1095.                 $linux_distro = "LinuxPPC";
  1096.             }
  1097.         } elsif (open(ETCISSUE, "</etc/issue")) {
  1098.             while (defined($line = <ETCISSUE>)) {
  1099.                 if ($line =~ /(Caldera|Cobalt|Debian|LinuxPPC|SuSE|TurboLinux|Slackware|Mandrake|Mandriva|Conectiva|Red\ Hat|Fedora(\ Core)?)/) {
  1100.                     $linux_distro = $1;
  1101.                     last;
  1102.                 } elsif ($line =~ /S\.u\.S\.E/i) {
  1103.                     $linux_distro = "SuSE";
  1104.                 }
  1105.             }
  1106.             close(ETCISSUE);
  1107.         }
  1108.         if (($linux_distro eq "unknown") || ($linux_distro eq "Debian")) {
  1109.             if (open(LSB, "</etc/lsb-release")) {
  1110.                 my ($maybe_linux_distro_version) = "";
  1111.                 my ($maybe_linux_distro) = "";
  1112.                 while (defined($line = <LSB>)) {
  1113.                     chomp($line);
  1114.                     if ($line =~ /^\s*DISTRIB_ID\s*=\s*(\S.*)/) {
  1115.                         $maybe_linux_distro = $1;
  1116.                     } elsif ($line =~ /^\s*DISTRIB_RELEASE\s*=\s*(\S.*)/) {
  1117.                         $maybe_linux_distro_version = $1;
  1118.                     }
  1119.                 }
  1120.                 close(LSB);
  1121.                 if ($maybe_linux_distro ne "") {
  1122.                     $linux_distro = $maybe_linux_distro;
  1123.                     if ($maybe_linux_distro_version ne "") {
  1124.                         $linux_distro_version = $maybe_linux_distro_version;
  1125.                     }
  1126.                 }
  1127.             }
  1128.         }
  1129.         if ($linux_distro eq "unknown") {
  1130.             my (@unknown_releases) = glob("/etc/*-release");
  1131.             if (scalar(@unknown_releases) > 0) {
  1132.                 $linux_distro_release_file = $unknown_releases[0];
  1133.                 $linux_distro = $unknown_releases[0];
  1134.                 $linux_distro =~ s/\-release$//;
  1135.                 $linux_distro =~ s-^.*/--;
  1136.                 Log(1, "Detected unknown linux_distro=$linux_distro.\n");
  1137.             }
  1138.         }
  1139.         if ($linux_distro_release_file ne "") {
  1140.             if (open(RH, "< $linux_distro_release_file")) {
  1141.                 while (defined($line = <RH>)) {
  1142.                     if ($line =~ /^\s*VERSION\s*=\s*(\S*)/i) {
  1143.                         $linux_distro_version = $1;
  1144.                     } elsif ($line =~ /(release|version)\s*(\S*)/i) {
  1145.                         $linux_distro_version = $2;
  1146.                     }
  1147.                 }
  1148.                 close(RH);
  1149.                 if ($linux_distro_version =~ /(\d+(\.\d+)?)/) {
  1150.                     $linux_distro_version_num = $1;
  1151.                 }
  1152.             }
  1153.         }
  1154.         if ($linux_distro_version ne "") {
  1155.             Log(1, "Linux Distribution: $linux_distro (Version $linux_distro_version)\n");
  1156.         } else {
  1157.             Log(1, "Linux Distribution: $linux_distro\n");
  1158.         }
  1159.         Log(1, "Linux LIBC Version: $linux_libc\n");
  1160.     } elsif ($os eq "bsd/os") {
  1161.         $OS= "bsdos${os_r}";
  1162.         $SYS = "bsdos";
  1163.     } elsif ($os eq "ultrix") {
  1164.         $OS= "ultrix-${arch}";
  1165.         $SYS = "ultrix";
  1166.     } elsif ($os eq "openunix") {
  1167.         $OS= "openunix${os_v}";
  1168.         $SYS = "openunix";
  1169.     } elsif ($os eq "unixware") {
  1170.         $OS= "unixware${os_v}";
  1171.         $SYS = "unixware";
  1172.     } elsif (($os eq "darwin") || ($os eq "rhapsody") || ($os =~ /^macos/))  {
  1173.         $OS= "macosx";
  1174.         $SYS = "macosx";
  1175.     } elsif ($os eq "sunos") {
  1176.         $arch = "sparc" if (! $arch);
  1177.         $archp = "$arch" if (! $archp);
  1178.         if (($os_r[0] == 5) && ($os_r[1] >= 7)) {
  1179.             $os_r =~ s/^\d+\.//;
  1180.             $OS = "solaris${os_r}-$archp";
  1181.             $SYS = "solaris";
  1182.         } elsif (($os_r[0] == 5) && ($os_r[1] < 7)) {
  1183.             $os_r =~ s/^5/2/;
  1184.             $OS = "solaris${os_r}-$archp";
  1185.             $SYS = "solaris";
  1186.         } elsif ($os_r[0] == 4) {
  1187.             $OS = "sunos${os_r}-$archp";
  1188.             $SYS = "sunos";
  1189.         } else {
  1190.             $OS = "solaris${os_r}-$archp";
  1191.             $SYS = "solaris";
  1192.         }
  1193.     } else {
  1194.         $OS = "$os";
  1195.         $SYS = "$os";
  1196.     }
  1197.  
  1198.     Log(1, "OS = $OS ; SYS = $SYS\n");
  1199. }    # SetOSVar
  1200.  
  1201.  
  1202.  
  1203.  
  1204. sub SetOSDefaults
  1205. {
  1206.     # Set log dir to OS defaults, unless we already have a /var/log.
  1207.     #
  1208.     if ((! -d $logdir) || (-l $logdir)) {
  1209.         if ($SYS eq "aix") {
  1210.             $logdir = "/var/adm";
  1211.         } elsif ($SYS =~ /^irix/) {
  1212.             $logdir = "/var/adm";
  1213.         } elsif ($SYS eq "hpux") {
  1214.             $logdir = "/var/spool/log";
  1215.         } elsif ($SYS eq "sco") {
  1216.             $logdir = "/var/adm/log";
  1217.         } elsif ($SYS eq "unixware") {
  1218.             $logdir = "/var/adm/log";
  1219.         } elsif ($SYS eq "openunix") {
  1220.             $logdir = "/var/adm/log";
  1221.         }
  1222.     }
  1223.     $startup_error_log = "$logdir/ncftpd/startup_errors";
  1224. }    # SetOSDefaults
  1225.  
  1226.  
  1227.  
  1228.  
  1229. sub VerifyOSPrerequisites
  1230. {
  1231.     if (($SYS eq "macosx") && (! -x "/usr/bin/ftp")) {
  1232.         Exit(1, "NcFTPd for Mac OS X requires the BSD Subsystem.  This is located on the Mac OS X installation disc.\n");
  1233.     }
  1234. }    # VerifyOSPrerequisites
  1235.  
  1236.  
  1237.  
  1238.  
  1239. sub SeeIfNcFTPdIsBinaryCompatible
  1240. {
  1241.     my ($f) = @_;
  1242.     my ($osdir, $ver, $n);
  1243.  
  1244.     $osdir = $f;
  1245.     $osdir =~ s/\/[^\/]+$//;
  1246.     $n = "$osdir/ncftpd";
  1247.     Log(1, "Try to run \"$n -b\".\n");
  1248.     $ver = "";
  1249.     $ver = `$n -b 2>&1` || "";
  1250.     chomp($ver);
  1251.     # i.e: "NcFTPd 2.7.1/849"
  1252.     if ($ver =~ /^NcFTPd\s([1-9]\.\d+\.\d+)\/\d+/) {
  1253.         Log(2, "  result = [$ver]\n");
  1254.         $ver = $1;
  1255.         $install_version = $ver;
  1256.         $install_src_root = $osdir;
  1257.         $binary_compat_err = "";
  1258.         return (1);
  1259.     } else {
  1260.         Log(1, "  result = [$ver]\n");
  1261.         $binary_compat_err = $ver;
  1262.         if ($SYS eq "openbsd") {
  1263.             unlink("$n.core");
  1264.         }
  1265.     }
  1266.     return (0);
  1267. }    # SeeIfNcFTPdIsBinaryCompatible
  1268.  
  1269.  
  1270.  
  1271.  
  1272. sub VerifyLocation
  1273. {
  1274.     my ($wd) = $0;
  1275.     my (@os_ncftpd);
  1276.     my ($f);
  1277.  
  1278.     $wd =~ s/\/*install_ncftpd.pl$//;    
  1279.     $wd = "." if (! $wd);
  1280.     if ($wd ne ".") {
  1281.         chdir($wd) or Exit(1, "Could not change directory to \"$wd\": $!\n");
  1282.     }
  1283.     $wd = `pwd 2>/dev/null`;
  1284.     chomp($wd);
  1285.     $wd = "." if (! $wd);
  1286.     Exit(1, "Could not find install_ncftpd.pl in directory \"$wd\"!\n") if (! -f "install_ncftpd.pl");
  1287.     $install_src_root = $wd;
  1288.  
  1289.     $install_version = "";
  1290.     @os_ncftpd = glob("$wd/*/ncftpd");
  1291.     if (scalar(@os_ncftpd) > 0) {
  1292.         foreach $f (@os_ncftpd) {
  1293.             $f =~ s-/ncftpd$--;
  1294.             $f =~ s-^.*/--;
  1295.         }
  1296.         my (@skipped_os_ncftpd) = ();
  1297.  
  1298.         sub version_int {
  1299.             my ($sver) = $_[0] || "0.0";
  1300.             if ($sver =~ /(\d+)\D+(\d+)\D+(\d+)/) {
  1301.                 return (10000 * int($1) + 100 * int($2) + int($3));
  1302.             } elsif ($sver =~ /(\d+)\D+(\d+)/) {
  1303.                 return (10000 * int($1) + 100 * int($2));
  1304.             } elsif ($sver =~ /(\d+)/) {
  1305.                 return (10000 * int($1));
  1306.             }
  1307.             return 0;
  1308.         }
  1309.  
  1310.         if ($SYS eq "linux") {
  1311.             my (@os_ncftpd2) = ();
  1312.             foreach $f (@os_ncftpd) {
  1313.                 my ($aver, $sver);
  1314.                 $sver = $linux_libc;
  1315.                 $sver =~ s/libc5/0/;
  1316.                 $sver = version_int($sver);
  1317.  
  1318.                 $aver = $f;
  1319.                 $aver =~ s/libc5/0/;
  1320.                 $aver = version_int($aver);
  1321.  
  1322.                 if ($aver <= $sver) {
  1323.                     push(@os_ncftpd2, $f);
  1324.                 } else {
  1325.                     push(@skipped_os_ncftpd, $f);
  1326.                 }
  1327.             }
  1328.             @os_ncftpd = @os_ncftpd2;
  1329.             @os_ncftpd = sort {
  1330.                 if ($a eq $linux_libc) {
  1331.                     return (-1);
  1332.                 } elsif ($b eq $linux_libc) {
  1333.                     return (1);
  1334.                 } else {
  1335.                     my ($aver, $bver);
  1336.  
  1337.                     $aver = $a;
  1338.                     $aver =~ s/libc5/0/;
  1339.                     $aver = version_int($aver);
  1340.  
  1341.                     $bver = $b;
  1342.                     $bver =~ s/libc5/0/;
  1343.                     $bver = version_int($bver);
  1344.  
  1345.                     $bver <=> $aver;
  1346.                 }
  1347.             } @os_ncftpd;
  1348.         } else {
  1349.             @os_ncftpd = sort {
  1350.                 if ($a eq $OS) {
  1351.                     return (-1);
  1352.                 } elsif ($b eq $OS) {
  1353.                     return (1);
  1354.                 } else {
  1355.                     my ($aver, $bver);
  1356.  
  1357.                     $aver = version_int($a);
  1358.                     $bver = version_int($b);
  1359.  
  1360.                     $bver <=> $aver;
  1361.                 }
  1362.             } @os_ncftpd;
  1363.         }
  1364.         if (scalar(@skipped_os_ncftpd) > 0) {
  1365.             Log(2, "List of platform subdirectories that will not be used as they appear to be aimed at newer systems than this one:\n");
  1366.             for $f (@skipped_os_ncftpd) {
  1367.                 Log(2, "  " . $f . "\n");
  1368.             }
  1369.         }
  1370.         Log(2, "List of platform subdirectories found that will be checked:\n");
  1371.         for $f (@os_ncftpd) {
  1372.             Log(2, "  " . $f . "\n");
  1373.         }
  1374.         for $f (@os_ncftpd) {
  1375.             last if (SeeIfNcFTPdIsBinaryCompatible("$wd/$f/ncftpd"));
  1376.         }
  1377.         if ($install_version eq "") {
  1378.             Log(0, "\nERROR: The package you downloaded will not run on this platform.\n");
  1379.             Log(0, "       Check http://www.ncftp.com/download/ for a package for $OS.\n");
  1380.             Exit(1);
  1381.         }
  1382.     } elsif (! -f "$wd/ncftpd") {
  1383.         Log(0, "\nERROR: There is no \"ncftpd\" program in the same directory as this script,\n$wd/install_ncftpd.pl.\n");
  1384.         Exit(1);
  1385.     } else {
  1386.         if (! SeeIfNcFTPdIsBinaryCompatible("$wd/ncftpd")) {
  1387.             if ($SYS eq "openbsd") {
  1388.                 # Look for a message similar to this:
  1389.                 # /tmp/ncftpd-2.8.2/ncftpd: can't load library 'libc.so.30.1'
  1390.                 my ($libc_so_link);
  1391.                 my (@libc_sos, $libc_so);
  1392.                 if (($binary_compat_err =~ /can.?t\ load\ library.*(libc\.so\.[0-9\.]+)/) || ($binary_compat_err =~ /(libc\.so\.[^:]+): No\ such\ file\ or\ directory/)) {
  1393.                     # Try to work around this by symlinking
  1394.                     # the version of libc.so we are using
  1395.                     # to the latest version on this host.
  1396.                     #
  1397.                     $libc_so_link = "/usr/lib/" . $1;
  1398.                     @libc_sos = glob("/usr/lib/libc.so.*");
  1399.                     $libc_so = $libc_sos[0];
  1400.                     if ((Symlink($libc_so, $libc_so_link, "do not overwrite")) && (! SeeIfNcFTPdIsBinaryCompatible("$wd/ncftpd"))) {
  1401.                         # Remove the link we made first,
  1402.                         # since it didn't work.
  1403.                         #
  1404.                         unlink($libc_so_link);
  1405.                         Log(0, "\nERROR: The package you downloaded will not run on this platform.\n");
  1406.                         Log(0, "       Check http://www.ncftp.com/download/ for a package for $OS.\n");
  1407.                         Exit(1);
  1408.                     }
  1409.                 } else {
  1410.                     Log(0, "\nERROR: The package you downloaded will not run on this platform.\n");
  1411.                     Log(0, "       Check http://www.ncftp.com/download/ for a package for $OS.\n");
  1412.                     Exit(1);
  1413.                 }
  1414.             } elsif ($SYS eq "macosx") {
  1415.                 my $archp = lc( `uname -p 2>/dev/null` );
  1416.                 chomp($archp);
  1417.                 Log(1, "The binaries do not run on this arch (\"$archp\").\n");
  1418.                 if ($archp eq "powerpc") {
  1419.                     Log(0, "\nERROR: This package is only for Mac OS X systems with Intel CPUs.\n");
  1420.                     Log(0, "       Check http://www.ncftp.com/download/ for the PowerPC version.\n");
  1421.                     Exit(1);
  1422.                 } else {
  1423.                     Log(0, "\nERROR: This package is only for Mac OS X systems with PowerPC CPUs.\n");
  1424.                     Log(0, "       Check http://www.ncftp.com/download/ for the Intel version.\n");
  1425.                     Exit(1);
  1426.                 }
  1427.             } else {
  1428.                 Log(0, "\nERROR: The package you downloaded will not run on this platform.\n");
  1429.                 Log(0, "       Check http://www.ncftp.com/download/ for a package for $OS.\n");
  1430.                 Exit(1);
  1431.             }
  1432.         }
  1433.     }
  1434.  
  1435.     Log(1, "Install source root is $install_src_root.\n");
  1436.     if ($install_src_root eq $wd) {
  1437.         return "$install_src_root/extra:$install_src_root";
  1438.     } else {
  1439.         return "$install_src_root/extra:$install_src_root:$wd";
  1440.     }
  1441. }    # VerifyLocation
  1442.  
  1443.  
  1444.  
  1445.  
  1446. sub VerifyPackageContents
  1447. {
  1448.     my ($f, $path);
  1449.     my (@required_files) = (
  1450.         "LICENSE",
  1451.         "conf/general.cf-dist",
  1452.         "conf/domain.cf-dist",
  1453.         "ncftpd",
  1454.         "ncftpd_edquota",
  1455.         "ncftpd_passwd",
  1456.         "ncftpd_repquota",
  1457.         "ncftpd_spy",
  1458.         "extra/ncftpd.init",
  1459.         "extra/ncftpd.sh",
  1460.     );
  1461.     my (@required_dirs) = (
  1462.         "extra",
  1463.     );
  1464.     for $f (@required_files) {
  1465.         $path = "$install_src_root/$f";
  1466.         if (! -f $path) {
  1467.             Log(0, "Missing required file for installation: $path.\n") if ($force_install);
  1468.             Exit(1, "Missing required file for installation: $path.\n") if (! $force_install);
  1469.         }
  1470.     }
  1471.     for $f (@required_dirs) {
  1472.         $path = "$install_src_root/$f";
  1473.         if (! -d $path) {
  1474.             Log(0, "Missing required directory for installation: $path.\n") if ($force_install);
  1475.             Exit(1, "Missing required directory for installation: $path.\n") if (! $force_install);
  1476.         }
  1477.     }
  1478. }    # VerifyPackageContents
  1479.  
  1480.  
  1481.  
  1482.  
  1483. sub VerifyFreeSpace
  1484. {
  1485.     my ($bytesfree, $kbytesfree, $duresult, $kbytesneeded);
  1486.  
  1487.     $bytesfree = DiskFreeBytes($eprefix);
  1488.     if ($bytesfree == (-1)) {
  1489.         Log(0, "Could not determine free space on $prefix.\n");
  1490.         return;
  1491.     }
  1492.     $kbytesfree = $bytesfree / 1024;
  1493.     Log(1, sprintf("$eprefix kbytes free: %.2f\n", $kbytesfree));
  1494.  
  1495.     if ($^O eq "sunos") {
  1496.         $duresult = `cd $install_src_root && du -s $install_src_root 2>&1`;
  1497.     } else {
  1498.         $duresult = `cd $install_src_root && du -s -k $install_src_root 2>&1`;
  1499.     }
  1500.     chomp($duresult);
  1501.     if ($duresult !~ /^(\d+)/) {
  1502.         Log(0, "Could not determine disk usage for $install_src_root.\n");
  1503.         Log(0, "Result was [$duresult]\n");
  1504.         return;
  1505.     }
  1506.     $kbytesneeded = int($1) + 100;
  1507.     Log(1, sprintf("$install_src_root kbytes usage: %.2f\n", $kbytesneeded));
  1508.     if ($kbytesneeded > $kbytesfree) {
  1509.         Log(0, sprintf("ERROR: %u kB of free space is required on $prefix,\n", $kbytesneeded));
  1510.         Log(0, sprintf("       but only %.2f kB available.\n", $kbytesfree));
  1511.         Exit(1) if (! $force_install);
  1512.     }
  1513. }    # VerifyFreeSpace
  1514.  
  1515.  
  1516.  
  1517.  
  1518. sub SetPATHEnvironmentVar
  1519. {
  1520.     my ($path_prefix) = @_;
  1521.     my (@path_prefix_list) = ();
  1522.     my ($HOME) = $ENV{"HOME"};
  1523.     my ($newPATH) = "";
  1524.     my (@origPATHs) = split(/:/, $ENV{"PATH"});
  1525.     my (@paths) = ();
  1526.     my (@pre_paths);
  1527.     my ($dir);
  1528.     my (%found_paths);
  1529.  
  1530.     $HOME = "/" unless (defined($HOME));
  1531.     $ENV{"PATH"} = "/bin:/usr/bin" if (! defined($ENV{"PATH"}));
  1532.     @origPATHs = split(/:/, $ENV{"PATH"});
  1533.     $extra_paths = $path_prefix if (defined($path_prefix));
  1534.     @path_prefix_list = split(/:/, $path_prefix) if defined($path_prefix);
  1535.     if ($> != 0) {
  1536.         #
  1537.         # PATH for unprivileged user.
  1538.         #
  1539.         @paths = (
  1540.             @path_prefix_list,
  1541.             ".",
  1542.             "$HOME/$OS/bin",
  1543.             "$HOME/bin/powerpc-apple-macos",
  1544.             "$HOME/bin",
  1545.             "$HOME/sh",
  1546.             "/opt/SUNWspro/bin",
  1547.             "/opt/ansic/bin",
  1548.             "/usr/vac/bin",
  1549.             "/usr/ccs/bin",
  1550.             "/udk/usr/ccs/bin",
  1551.             "/usr/local/bin",
  1552.             "/usr/local/sbin",
  1553.             "/bin",
  1554.             "/usr/bin",
  1555.             "/usr/contrib/bin",
  1556.             "/usr/X11R6/bin",
  1557.             "/usr/bin/X11R6",
  1558.             "/usr/X11/bin",
  1559.             "/usr/bin/X11",
  1560.             "/usr/sbin",
  1561.             "/sbin",
  1562.             "/etc",
  1563.             "/usr/ucb",
  1564.             "/usr/bsd",
  1565.             "/usr/freeware/bin",
  1566.             "/usr/openwin/bin",
  1567.             @origPATHs
  1568.         );
  1569.     } else {
  1570.         #
  1571.         # PATH for Superuser.
  1572.         #
  1573.  
  1574.         my (@pre_paths) = ();
  1575.         if ($HOME ne "/") {
  1576.             @pre_paths = (
  1577.                 "$HOME/bin/powerpc-apple-macos",
  1578.                 "$HOME/bin",
  1579.                 "$HOME/sh",
  1580.                 );
  1581.         }
  1582.  
  1583.         @paths = (
  1584.             @path_prefix_list,
  1585.             @pre_paths,
  1586.             "/bin",
  1587.             "/usr/bin",
  1588.             "/usr/sbin",
  1589.             "/sbin",
  1590.             "/usr/local/sbin",
  1591.             "/etc",
  1592.             "/usr/local/bin",
  1593.             "/usr/ucb",
  1594.             "/usr/bsd",
  1595.             "/opt/SUNWspro/bin",
  1596.             "/opt/ansic/bin",
  1597.             "/usr/vac/bin",
  1598.             "/usr/ccs/bin",
  1599.             "/udk/usr/ccs/bin",
  1600.             "/usr/contrib/bin",
  1601.             "/usr/X11R6/bin",
  1602.             "/usr/bin/X11R6",
  1603.             "/usr/X11/bin",
  1604.             "/usr/bin/X11",
  1605.             "/usr/freeware/bin",
  1606.             "/usr/openwin/bin",
  1607.             @origPATHs
  1608.         );
  1609.     }
  1610.  
  1611.     for $dir (@paths) {
  1612.         if (-d $dir) {
  1613.             if (! defined($found_paths{$dir})) {
  1614.                 $found_paths{$dir} = 1;
  1615.                 if ($newPATH eq "") {
  1616.                     $newPATH = $dir;
  1617.                 } else {
  1618.                     $newPATH .= ":" . $dir;
  1619.                 }
  1620.             }
  1621.         }
  1622.     }
  1623.  
  1624.     Log(1, "Setting PATH to \"$newPATH\".\n");
  1625.     $ENV{"PATH"} = $newPATH;
  1626. }    # SetPATHEnvironmentVar
  1627.  
  1628.  
  1629.  
  1630.  
  1631. sub LookupFTPServiceName
  1632. {
  1633.     return if ($ftpport == 21);
  1634.     return if ((defined($ftpservicename)) && ($ftpservicename ne "") && ($ftpservicename ne "ftp"));
  1635.  
  1636.     my ($ftpdataport) = $ftpport - 1;
  1637.     my ($name,$aliases,$port,$proto) = getservbyport($ftpport, "tcp");
  1638.     if (defined($name)) {
  1639.         $ftpservicename = $name;
  1640.     } else {
  1641.         ($name,$aliases,$port,$proto) = getservbyname("ftp-$port", "tcp");
  1642.         if (defined($port) && defined($name) && ($port == $ftpport)) {
  1643.             $ftpservicename = $name;
  1644.         } elsif ((-f "/etc/services") && (open(ETCSERVICES, ">>/etc/services"))) {
  1645.             print ETCSERVICES "\n#\n# Added by install_ncftpd.pl\n#\n";
  1646.             print ETCSERVICES "ftp-$ftpport-data\t$ftpdataport/tcp\n";
  1647.             print ETCSERVICES "ftp-$ftpport\t$ftpport/tcp\t\t\t# Alternate FTP Service port\n";
  1648.             Log(0, "Added \"ftp-$ftpport\" to /etc/services.\n");
  1649.             close(ETCSERVICES);
  1650.             UninstallLog("RemoveFromEtcServices(\"ftp-$ftpport-data\", \"ftp-$ftpport\");\n");
  1651.         }
  1652.     }
  1653. }    # LookupFTPServiceName
  1654.  
  1655.  
  1656.  
  1657. sub TestLsof
  1658. {
  1659.     if (open(LSOFTEST, "$lsof $lsof 2>&1 |")) {
  1660.         my (@lsof_result) = <LSOFTEST>;
  1661.         close(LSOFTEST);
  1662.         my (@lsof_lines) = grep(/COMMAND/, @lsof_result);
  1663.         if (scalar(@lsof_lines) > 0) {
  1664.             Log(1, "Test run of $lsof succeeded.\n");
  1665.             return (1);
  1666.         } else {
  1667.             Log(1, "Failed to run $lsof.\n");
  1668.             my ($i);
  1669.             for $i (@lsof_result) {
  1670.                 chomp($i);
  1671.                 Log(1, $i . "\n");
  1672.             }
  1673.         }
  1674.     }
  1675.     $lsof = "";
  1676.     return (0);
  1677. }    # TestLsof
  1678.  
  1679.  
  1680.  
  1681. sub FindLsof
  1682. {
  1683.     return (1) if (($lsof ne "") && (-x $lsof));
  1684.     $lsof = SearchPath("lsof", "/sbin:/usr/sbin:/usr/local/sbin:/usr/bin:/bin");
  1685.     return (1) if (TestLsof());
  1686.     $lsof = SearchPath("lsof", "", "/sbin:/usr/sbin:/usr/local/sbin:/usr/bin:/bin");
  1687.     return (1) if (TestLsof());
  1688.     return (0);
  1689. }    # FindLsof
  1690.  
  1691.  
  1692.  
  1693.  
  1694. sub FindPerl
  1695. {
  1696.     return (1) if (($perl ne "") && (-x $perl));
  1697.     $perl = SearchPath("perl");
  1698.     $perl = "/usr/bin/perl" if ($perl eq "");
  1699.     return (1);
  1700. }    # FindPerl
  1701.  
  1702.  
  1703.  
  1704.  
  1705. sub AbortIfSomethingWeDontKnowHowToDisableIsUsingPort21()
  1706. {
  1707.     my (@lsof_result);
  1708.  
  1709.     if (! FindLsof()) {
  1710.         Log(1, "Could not find lsof.\n");
  1711.     } elsif (open(LSOF, "$lsof -w -i tcp:$ftpport | fgrep LISTEN 2>/dev/null |")) {
  1712.         @lsof_result = <LSOF>;
  1713.         close(LSOF);
  1714.         if ((defined($lsof_result[0])) && ($lsof_result[0] =~ /^COMMAND/)) {
  1715.             my ($lines_printed) = 0;
  1716.             my ($line);
  1717.             for ($line = 1; $line < scalar(@lsof_result); $line++) {
  1718.                 my (@junk) = split(' ', $lsof_result[$line], 2);
  1719.                 my ($program) = $junk[0];
  1720.                 if ($program !~ /(ncftpd|xinetd|inetd|ftpd)/) {
  1721.                     if (! $lines_printed) {
  1722.                         Log(0, "\nERROR: You must first uninstall your current FTP server software.\n");
  1723.                         Log(0, "The following processes are using the FTP service port ($ftpport):\n\n");
  1724.                         Log(0, "  ", $lsof_result[0]);
  1725.                     }
  1726.                     Log(0, "  ", $lsof_result[$line]);
  1727.                     $lines_printed++;
  1728.                 } elsif ($program =~ /ncftpd/) {
  1729.                     $ncftpd_running_at_time_of_install++;
  1730.                 } elsif ($program =~ /xinetd/) {
  1731.                     $xinetd_running_at_time_of_install++;
  1732.                 } elsif ($program =~ /inetd/) {
  1733.                     $inetd_running_at_time_of_install++;
  1734.                 }
  1735.             }
  1736.             if ($lines_printed) {
  1737.                 Log(0, "\n");
  1738.                 Log(0, "You can try killing these processes and restarting the installation,\n");
  1739.                 Log(0, "but you must disable the other software's startup script. Otherwise,\n");
  1740.                 Log(0, "the next time you reboot the machine NcFTPd will not be able to start.\n");
  1741.                 Exit(1);
  1742.             }
  1743.         } else {
  1744.             Log(1, "No processes are currently handling FTP.\n");
  1745.         }
  1746.         Log(0, "NcFTPd is currently handling FTP.\n") if ($ncftpd_running_at_time_of_install > 0);
  1747.         Log(0, "Inetd is currently handling FTP.\n") if ($inetd_running_at_time_of_install > 0);
  1748.         Log(0,"Xinetd is currently handling FTP.\n") if ($xinetd_running_at_time_of_install > 0);
  1749.     } else {
  1750.         Log(1, "Could not run lsof.\n");
  1751.     }
  1752. }    # AbortIfSomethingWeDontKnowHowToDisableIsUsingPort21
  1753.  
  1754.  
  1755.  
  1756.  
  1757. sub CreateEtcShells
  1758. {
  1759.     return if (-f "/etc/shells");
  1760.  
  1761.     my (@shells_found) = ();
  1762.     my ($shell);
  1763.     my ($path);
  1764.     my ($aix_shells_found) = 0;
  1765.  
  1766.     if (open(AIXSHELLS, "/etc/security/login.cfg")) {
  1767.         #
  1768.         # AIX has information about its shells in this file.
  1769.         #
  1770.         # Example:
  1771.         #    shells = /bin/sh,/bin/bsh,/bin/csh,/bin/ksh,/bin/tsh,/usr/bin/sh,/usr/bin/bsh,/usr/bin/csh,/usr/bin/ksh,/usr/bin/tsh,/usr/sbin/sliplogin
  1772.         #
  1773.         my (@logincfgdata) = <AIXSHELLS>;
  1774.         close(AIXSHELLS);
  1775.         my (@shells_line) = grep(/^\s*shells\s*=/, @logincfgdata);
  1776.         if (scalar(@shells_line) > 0) {
  1777.             if ($shells_line[0] =~ /\=\s*(\/.*)/) {
  1778.                 $shells_line[0] = $1;
  1779.                 @shells_found = split(/,/, $shells_line[0]);
  1780.                 $aix_shells_found = scalar(@shells_found);
  1781.             }
  1782.         }
  1783.     }
  1784.  
  1785.     my (@paths) = ("/sbin", "/bin", "/bin/posix", "/usr/bin", "/usr/local/bin");
  1786.     my (@shells) = ("sh", "ksh", "csh", "bash", "tcsh", "zsh", "pdksh", "rksh", "passwd");
  1787.  
  1788.     for $path (@paths) {
  1789.         for $shell (@shells) {
  1790.             if (-x "$path/$shell") {
  1791.                 my ($a);
  1792.                 my ($b) = 0;
  1793.                 for $a (@shells_found) {
  1794.                     if ($a eq "$path/$shell") {
  1795.                         $b = 1;
  1796.                         last;
  1797.                     }
  1798.                 }
  1799.                 push(@shells_found, "$path/$shell") if ($b == 0);
  1800.             }
  1801.         }
  1802.     }
  1803.  
  1804.     return if (scalar(@shells_found) == 0);
  1805.     if (open(ETCSHELLS, ">/etc/shells")) {
  1806.         print ETCSHELLS "# NcFTPd will not allow users to connect who are not using one of\n# these shells.\n";
  1807.  
  1808.         if ($aix_shells_found) {
  1809.             print ETCSHELLS "#\n";
  1810.             print ETCSHELLS "# This file was generated from /etc/security/login.cfg.\n";
  1811.             print ETCSHELLS "# If you change this file, also change /etc/security/login.cfg.\n";
  1812.         }
  1813.  
  1814.         print ETCSHELLS "#\n";
  1815.         for $shell (@shells_found) {
  1816.             print ETCSHELLS $shell, "\n";
  1817.         }    
  1818.         close(ETCSHELLS);
  1819.         chmod(0644, "/etc/shells");
  1820.         Log(0, "Created /etc/shells.\n");
  1821.         UninstallLog("Remove(\"/etc/shells\");\n");
  1822.     }
  1823. }    # CreateEtcShells
  1824.  
  1825.  
  1826.  
  1827.  
  1828. sub CreateEtcFtpusers
  1829. {
  1830.     my ($user);
  1831.     my ($t0, $t1);
  1832.     my ($uid);
  1833.     my (@users) = (    "root", "kroot", "broot", "croot", "toor",
  1834.             "4Dgifts",
  1835.             "adabas",
  1836.             "adm",
  1837.             "Administrator",
  1838.             "administrator",
  1839.             "amanda",
  1840.             "anon",
  1841.             "at",
  1842.             "auditor",
  1843.             "auth",
  1844.             "bin",
  1845.             "bind",
  1846.             "cmwlogin",
  1847.             "cron",
  1848.             "cyrus",
  1849.             "daemon",
  1850.             "db2",
  1851.             "db2as",
  1852.             "db2fenc1",
  1853.             "db2inst1",
  1854.             "dbadmin",
  1855.             "dbmaker",
  1856.             "demo",
  1857.             "demos",
  1858.             "diag",
  1859.             "dpbox",
  1860.             "empress",
  1861.             "EZsetup",
  1862.             "fax",
  1863.             "fib",
  1864.             "firewall",
  1865.             "fixadm",
  1866.             "fixlohn",
  1867.             "flexlm",
  1868.             "fnet",
  1869.             "games",
  1870.             "gdm",
  1871.             "gnats",
  1872.             "guest",
  1873.             "halt",
  1874.             "hpdb",
  1875.             "imap",
  1876.             "informix",
  1877.             "ingres",
  1878.             "irc",
  1879.             "ixess",
  1880.             "kmem",
  1881.             "listen",
  1882.             "lnx",
  1883.             "lp",
  1884.             "lpd",
  1885.             "mail",
  1886.             "man",
  1887.             "mdom",
  1888.             "mosaic",
  1889.             "mysql",
  1890.             "named",
  1891.             "netscape",
  1892.             "news",
  1893.             "noaccess",
  1894.             "nobody",
  1895.             "nobody4",
  1896.             "nobodyV",
  1897.             "nonroot",
  1898.             "nonuser",
  1899.             "notes",
  1900.             "nouser",
  1901.             "nps",
  1902.             "ntp",
  1903.             "nuucp",
  1904.             "operator",
  1905.             "oracle",
  1906.             "OutOfBox",
  1907.             "pop",
  1908.             "postfix",
  1909.             "postgres",
  1910.             "quota",
  1911.             "radius",
  1912.             "reboot",
  1913.             "rfindd",
  1914.             "ris",
  1915.             "seti",
  1916.             "sgiweb",
  1917.             "shutdown",
  1918.             "skyrix",
  1919.             "spooladm",
  1920.             "sql",
  1921.             "squid",
  1922.             "sync",
  1923.             "sys",
  1924.             "sysadm",
  1925.             "tacacs",
  1926.             "tcb",
  1927.             "tty",
  1928.             "unknown",
  1929.             "uucp",
  1930.             "uucpa",
  1931.             "virtuoso",
  1932.             "vmware",
  1933.             "web",
  1934.             "wnn",
  1935.             "www",
  1936.             "wwwrun",
  1937.             "xfs",
  1938.             "xten",
  1939.             "yard",
  1940.             );
  1941.     my (@users_found) = ();
  1942.     my ($number_of_ftpusers_loaded) = 0;
  1943.  
  1944.     if (open(ETCFTPUSERS, "</etc/ftpusers")) {
  1945.         while (defined($user = <ETCFTPUSERS>)) {
  1946.             chomp($user);
  1947.             next unless ($user =~ /^[A-Za-z]/);
  1948.             push (@users_found, $user);
  1949.         }
  1950.         close(ETCFTPUSERS);
  1951.     }
  1952.     $number_of_ftpusers_loaded = scalar(@users_found);
  1953.  
  1954.     $t0 = time();
  1955.     Log(1,"Checking system user database for /etc/ftpusers suggestions.\n");
  1956.     for $user (@users) {
  1957.         my (@found) = grep(/$user/, @users_found);
  1958.         next if (scalar(@found) > 0);
  1959.         $uid = getpwnam($user);
  1960.         push (@users_found, $user) if (defined($uid));
  1961.         $t1 = time();
  1962.         if (($t1 - $t0) > 15) {
  1963.             Log(0, "Warning: It is taking too long to lookup usernames.  Perhaps you're using NIS or LDAP?\n");
  1964.             Log(0, "         The /etc/ftpusers checks will be skipped.\n");
  1965.             return;
  1966.         }
  1967.     }
  1968.  
  1969.     return if (scalar(@users_found) == 0);
  1970.  
  1971.     if ($number_of_ftpusers_loaded == 0) {
  1972.         if (open(ETCFTPUSERS, ">/etc/ftpusers")) {
  1973.             for $user (@users_found) {
  1974.                 print ETCFTPUSERS $user, "\n";
  1975.             }    
  1976.             close(ETCFTPUSERS);
  1977.             chmod(0644, "/etc/ftpusers");
  1978.             Log(0, "Created /etc/ftpusers.\n");
  1979.             UninstallLog("Remove(\"/etc/ftpusers\");\n");
  1980.         }
  1981.     } elsif ($number_of_ftpusers_loaded < scalar(@users_found)) {
  1982.         # Don't munge the system's existing file,
  1983.         # but warn about users we think should be
  1984.         # in there.
  1985.         #
  1986.         Log(0, "\n");
  1987.         Log(0, "Warning: your /etc/ftpusers file may be missing entries.\n");
  1988.         Log(0, "The /etc/ftpusers file is a list of users who should NOT\n");
  1989.         Log(0, "be allowed to login by FTP.  The following users were found\n");
  1990.         Log(0, "on your system, and are NOT in /etc/ftpusers.  Please review\n");
  1991.         Log(0, "the list below, and if one or more of the users below should\n");
  1992.         Log(0, "not be logging in by FTP, add them to /etc/ftpusers using\n");
  1993.         Log(0, "a text editor (such as ", defined($ENV{EDITOR}) ? $ENV{EDITOR} : "vi", ").\n\n");
  1994.         my ($i);
  1995.         my ($j) = 0;
  1996.         my ($n) = scalar(@users_found);
  1997.         for ($i = $number_of_ftpusers_loaded; $i < $n; $i++, $j++) {
  1998.             $user = $users_found[$i];
  1999.             Log(0, "    ") if (($j % 4) == 0);
  2000.             Log(0, sprintf("%-12s", $user));
  2001.             Log(0, "\n") if ((($j % 4) == 3) || ($i == ($n - 1)));
  2002.         }
  2003.         Log(0, "\n");
  2004.     }
  2005. }    # CreateEtcFtpusers
  2006.  
  2007.  
  2008.  
  2009.  
  2010. sub AddFTPGroup
  2011. {
  2012.     my ($i, $grp);
  2013.     my (@altgroups) = ("www", "web", "daemon", "nobody");
  2014.  
  2015.     $ftpgid = getgrnam($ftpgroup);
  2016.     if ((defined($ftpgid)) && ($ftpgid > 0)) {
  2017.         Log(1, "Using group $ftpgroup (GID $ftpgid)\n");
  2018.         return;
  2019.     }
  2020.  
  2021.     $ftpgid = getgrnam("_ftp");
  2022.     if ((defined($ftpgid)) && ($ftpgid > 0)) {
  2023.         $ftpgroup = "_ftp";
  2024.         Log(1, "Using group $ftpgroup (GID $ftpgid)\n");
  2025.         return;
  2026.     }
  2027.  
  2028.     #
  2029.     # The "ftp" group does not exist.
  2030.     # Try to add one.
  2031.     #
  2032.     Log(1, "$ftpgroup group does not exist\n");
  2033.  
  2034.     #
  2035.     # Pick a random GID.
  2036.     #
  2037.     for ($ftpgid = 50; $ftpgid < 400; $ftpgid += 10) {
  2038.         last if (! defined(getgrgid($ftpgid)));
  2039.     }
  2040.  
  2041.     if ($SYS eq "macosx") {
  2042.         if (SearchPath("niutil") ne "") {
  2043.             system("niutil", "-create",     "/", "/groups/$ftpgroup");
  2044.             system("niutil", "-createprop", "/", "/groups/$ftpgroup", "passwd", "*");
  2045.             system("niutil", "-createprop", "/", "/groups/$ftpgroup", "gid", "$ftpgid");
  2046.         }
  2047.     } elsif ($SYS eq "bsdos") {
  2048.         system("/usr/sbin/addgroup", "-g", $ftpgid, $ftpgroup);
  2049.     } elsif ($SYS eq "aix") {
  2050.         system("/usr/bin/mkgroup", "id=$ftpgid", $ftpgroup);
  2051.     } elsif ($SYS eq "sco") {
  2052.         system("/etc/groupadd", "-g", $ftpgid, $ftpgroup);
  2053.     } elsif (($SYS =~ /^(openbsd|netbsd|solaris|linux|tru64unix|digitalunix|unixware|openunix|hpux)$/) && (-x "/usr/sbin/groupadd")) {
  2054.         system("/usr/sbin/groupadd", "-g", $ftpgid, $ftpgroup);
  2055.     }
  2056.  
  2057.     $ftpgid = getgrnam($ftpgroup);
  2058.     if ((defined($ftpgid)) && ($ftpgid > 0)) {
  2059.         Log(0, "Created group $ftpgroup (UID $ftpgid)\n");
  2060.         UninstallLog("RemoveGroup(\"$ftpgroup\");\n");
  2061.         return;
  2062.     }
  2063.  
  2064.     # We'd prefer to be able to add the group, but we
  2065.     # can live without it since we can borrow commonly
  2066.     # available groupnames.
  2067.     #
  2068.     for $grp (@altgroups) {
  2069.         $ftpgid = getgrnam($grp);
  2070.         if ((defined($ftpgid)) && ($ftpgid > 0)) {
  2071.             $ftpgroup = $grp;
  2072.             Log(1, "Using alternate choice for group = $ftpgroup (UID $ftpgid)\n");
  2073.             return;
  2074.         }
  2075.     }
  2076. }    # AddFTPGroup
  2077.  
  2078.  
  2079.  
  2080.  
  2081. sub AddFTPUser
  2082. {
  2083.     my ($i, $usr);
  2084.     my (@altusers) = ("_www", "_sandbox", "www", "web", "daemon", "nobody");
  2085.     my ($noshell) = "";    # Most systems just leave the shell field blank.
  2086.     my (@shells) = ();
  2087.     my ($modified_etc_shells) = 0;
  2088.  
  2089.     $ftpuid = getpwnam($ftpuser);
  2090.     if ((defined($ftpuid)) && ($ftpuid > 0)) {
  2091.         Log(1, "Using user $ftpuser (UID $ftpuid)\n");
  2092.         return;
  2093.     }
  2094.  
  2095.     $ftpuid = getpwnam("_ftp");
  2096.     if ((defined($ftpuid)) && ($ftpuid > 0)) {
  2097.         $ftpuser = "_ftp";
  2098.         Log(1, "Using user $ftpuser (UID $ftpuid)\n");
  2099.         return;
  2100.     }
  2101.  
  2102.     #
  2103.     # The "ftp" user does not exist.
  2104.     # Try to add one.
  2105.     #
  2106.     Log(1, "$ftpuser user does not exist\n");
  2107.  
  2108.     $noshell = "/sbin/nologin" if (-x "/sbin/nologin");
  2109.     $noshell = "/dev/null" if ($SYS eq "macosx");
  2110.     $noshell = "/dev/null" if ($SYS =~ /^irix/);
  2111.     $noshell = "/usr/sbin/nologin" if ($SYS eq "freebsd");
  2112.     $noshell = "/sbin/nologin" if ($OS =~ /^freebsd4/);
  2113.     $noshell = "/nonexistent" if ($OS =~ /^freebsd[23]/);
  2114.     $noshell = "/bin/false" if ($SYS eq "tru64unix");    # Or else userdel fails
  2115.     $noshell = "/bin/false" if ($SYS eq "solaris");        # Or else useradd fails
  2116.     $noshell = "/bin/false" if ($SYS eq "unixware");    # Or else useradd fails
  2117.     $noshell = "/bin/false" if ($SYS eq "openunix");    # Or else useradd fails
  2118.     $noshell = "/bin/false" if ($SYS eq "hpux");        # Or else useradd fails
  2119.  
  2120.     if (($SYS =~ /^(forfutureuse)$/) && (-f "/etc/shells")) {
  2121.         #
  2122.         # Some systems won't let you add a user unless
  2123.         # you specify a valid shell program.  We don't
  2124.         # want to add the "ftp" user with a real shell,
  2125.         # so we add /bin/false to /etc/shells which
  2126.         # is harmless if actually logged in with.
  2127.         #
  2128.         if (open(ETCSHELLS, "</etc/shells")) {
  2129.             @shells = <ETCSHELLS>;
  2130.             Log(1, "Loading /etc/shells.\n");
  2131.             close(ETCSHELLS);
  2132.             if (scalar(grep(/$noshell/, @shells)) <= 0) {
  2133.                 #
  2134.                 # Our no-shell wasn't already in there,
  2135.                 # add it temporarily.
  2136.                 #
  2137.                 Log(1, "$noshell was not in /etc/shells.\n");
  2138.                 if (open(ETCSHELLS, ">>/etc/shells")) {
  2139.                     print ETCSHELLS $noshell, "\n";
  2140.                     close(ETCSHELLS);
  2141.                     $modified_etc_shells = 1;
  2142.                     Log(1, "Added $noshell to /etc/shells.\n");
  2143.                 }
  2144.             }
  2145.         }
  2146.     }
  2147.  
  2148.     #
  2149.     # Pick a random UID.
  2150.     #
  2151.     $ftpuid = 14;
  2152.     $ftpuid = 214 if ($SYS eq "sco");    # Otherwise SCO useradd fails
  2153.     for ($ftpuid = 14; $ftpuid < (65534 - 42); $ftpuid += 41) {
  2154.         last if (! defined(getpwuid($ftpuid)));
  2155.     }
  2156.  
  2157.     if ($SYS eq "macosx") {
  2158.         $ftphome = "/Library/FTPServer/Documents";
  2159.         if (SearchPath("niutil") ne "") {
  2160.             system("niutil", "-create",     "/", "/users/$ftpuser");
  2161.             system("niutil", "-createprop", "/", "/users/$ftpuser", "shell", "$noshell");
  2162.             system("niutil", "-createprop", "/", "/users/$ftpuser", "passwd", "*");
  2163.             system("niutil", "-createprop", "/", "/users/$ftpuser", "realname", "FTP Server");
  2164.             system("niutil", "-createprop", "/", "/users/$ftpuser", "uid", $ftpuid);
  2165.             system("niutil", "-createprop", "/", "/users/$ftpuser", "gid", $ftpgid);
  2166.             system("niutil", "-createprop", "/", "/users/$ftpuser", "home", $ftphome);
  2167.             # system("niutil", "-createprop", "/", "/users/$ftpuser", "_shadow_passwd", "");
  2168.             system("niutil", "-createprop", "/", "/users/$ftpuser", "expire", "0");
  2169.             system("niutil", "-createprop", "/", "/users/$ftpuser", "change", "0");
  2170.         }
  2171.     } elsif ($SYS =~ /^irix/) {
  2172.         # There doesn't seem to be a corresponding groupmgmt.
  2173.         system("/usr/sbin/passmgmt", "-a", "-u", $ftpuid, "-g", $ftpgid, "-c", "FTP User", "-s", $noshell, $ftpuser);
  2174.     } elsif ($SYS eq "bsdos") {
  2175.         system("/usr/sbin/adduser", "-u", $ftpuid, "-g", $ftpgid, "-G", "FTP User", "-s", $noshell, "-H", "/usr/home/$ftpuser", "-P", "*", $ftpuser);
  2176.     } elsif ($SYS eq "aix") {
  2177.         # User will get created with a regular shell, 
  2178.         # but they can't login in since we set su,rlogin,login=false.
  2179.         #
  2180.         system("/usr/bin/mkuser", "daemon=false", "expires=0", "gecos=FTP User", "id=$ftpuid", "pgrp=$ftpgroup", "login=false", "rlogin=false", "su=false", "umask=022", $ftpuser);
  2181.     } elsif ($SYS eq "sco") {
  2182.         system("/etc/useradd", "-u", $ftpuid, "-g", $ftpgid, "-c", "FTP User", "-s", $noshell, $ftpuser);
  2183.     } elsif (($SYS =~ /^(openbsd|netbsd|linux|tru64unix|digitalunix|solaris|unixware|openunix|hpux)$/) && (-x "/usr/sbin/useradd")) {
  2184.         system("/usr/sbin/useradd", "-u", $ftpuid, "-g", $ftpgid, "-c", "FTP User", "-s", $noshell, $ftpuser);
  2185.     } elsif ($OS =~ /^freebsd[56789]/) {
  2186.         if (open(ADDUSER, "| /usr/sbin/adduser -f - -w no -D -u $ftpuid")) {
  2187.             print ADDUSER "${ftpuser}::::::FTP User::nologin:\n";
  2188.             close(ADDUSER);
  2189.         }
  2190.     }
  2191.     
  2192.     if ($modified_etc_shells) {
  2193.         if (open(ETCSHELLS, ">/etc/shells")) {
  2194.             print ETCSHELLS @shells;
  2195.             close(ETCSHELLS);
  2196.             $modified_etc_shells = 0;
  2197.             Log(1, "Restored /etc/shells.\n");
  2198.             chmod(0644, "/etc/shells");
  2199.         }
  2200.     }
  2201.  
  2202.     $ftpuid = getpwnam($ftpuser);
  2203.     if ((defined($ftpuid)) && ($ftpuid > 0)) {
  2204.         Log(0, "Created user $ftpuser (UID $ftpuid)\n");
  2205.         UninstallLog("RemoveUser(\"$ftpuser\");\n");
  2206.         return;
  2207.     }
  2208.  
  2209.     # We'd prefer to be able to add the user, but we
  2210.     # can live without it since we can borrow commonly
  2211.     # available usernames.
  2212.     #
  2213.     for $usr (@altusers) {
  2214.         $ftpuid = getpwnam($usr);
  2215.         if ((defined($ftpuid)) && ($ftpuid > 0)) {
  2216.             $ftpuser = $usr;
  2217.             Log(1, "Using alternate choice for user = $ftpuser (UID $ftpuid)\n");
  2218.             return;
  2219.         }
  2220.     }
  2221. }    # AddFTPUser
  2222.  
  2223.  
  2224.  
  2225.  
  2226. sub CreateFTPHome
  2227. {
  2228.     my ($name,$passwd,$uid,$gid,$quota,$comment,$gcos,$dir,$shell,$expire);
  2229.  
  2230.     ($name,$passwd,$uid,$gid,$quota,$comment,$gcos,$dir,$shell,$expire) = 
  2231.         getpwnam($ftpuser);
  2232.     if (defined($dir)) {
  2233.         if (($ftpuser eq "www") && ($dir eq "/Library/WebServer")) {
  2234.             #
  2235.             # For Mac OS X, we'll try to use "www", and the
  2236.             # htdocs directory (/Library/WebServer/Documents)
  2237.             # for ftp-home.
  2238.             #
  2239.             $ftphome = "/Library/WebServer/Documents";
  2240.             Log(0, "Using $ftphome for ftp-home\n");
  2241.         } elsif ($ftpuser ne $ftpuser_preferred) {
  2242.             #
  2243.             # If we couldn't add "ftp", NcFTPd will use one of
  2244.             # the alternate users.  In this case, NcFTPd will
  2245.             # also not use that alternate user's home directory
  2246.             # as ftp-home.
  2247.             #
  2248.             if (-d "/export/home") {
  2249.                 $ftphome = "/export/home/ftp";
  2250.             } elsif (-d "/home") {
  2251.                 $ftphome = "/home/ftp";
  2252.             } elsif (-d "/usr/local") {
  2253.                 $ftphome = "/usr/local/ftp";
  2254.             } else {
  2255.                 $ftphome = "/usr/ftp";
  2256.             }
  2257.             Log(0, "Using $ftphome for ftp-home\n");
  2258.         } else {
  2259.             $ftphome = $dir;
  2260.             Log(0, "Using $ftphome for ftp-home\n");
  2261.         }
  2262.  
  2263.         #
  2264.         # Note that NcFTPd can run if ftp-home doesn't exist.
  2265.         #
  2266.         if (! -d $ftphome) {
  2267.             my ($did_mkd) = 0;
  2268.             if (Mkdirs($ftphome, 00755)) {
  2269.                 $did_mkd = 1;
  2270.             } else {
  2271.                 my ($alt_ftphome) = "/opt/ftp/anonymous_ftp_root";
  2272.                 if ((-d "/opt") && (Mkdirs($alt_ftphome, 00755))) {
  2273.                     Log(0, "Using $alt_ftphome for ftp-home since $ftphome could not be created.\n");
  2274.                     $ftphome = $alt_ftphome;
  2275.                     $did_mkd = 1;
  2276.                 }
  2277.             }
  2278.             if ($did_mkd) {
  2279.                 Log(0, "Created ftp-home directory, $ftphome\n");
  2280.                 if (open(README, ">$ftphome/README")) {
  2281.                     print README "This is the anonymous FTP area on $host.\n";
  2282.                     print README "Files for public access to the world can be placed here.\n";
  2283.                     close(README);
  2284.                     chmod(0644, "$ftphome/README");
  2285.                     UninstallLog("Remove(\"$ftphome/README\");\n");
  2286.                 }
  2287.             } else {
  2288.                 Log(0, "Warning: Could not create ftp-home directory, $ftphome\n");
  2289.             }
  2290.         }
  2291.  
  2292.         #
  2293.         # Make sure ~ftp is NOT owned by ftp!
  2294.         #
  2295.         chmod(0755, $ftphome);
  2296.         chown(0, 1, $ftphome);
  2297.     }
  2298. }    # CreateFTPHome
  2299.  
  2300.  
  2301.  
  2302.  
  2303. sub IsThereAnFTPServerServing
  2304. {
  2305.     my ($v) = @_;
  2306.     my ($hardway) = 0;
  2307.     my ($serveraddr);
  2308.  
  2309.     $v = 0 if (! defined($v));
  2310.     $serveraddr = inet_aton("localhost") || inet_aton("127.0.0.1");
  2311.     $hardway = 1 if (! defined($serveraddr));
  2312.  
  2313.     $hardway = 1 if (! socket(FTPSOCKET, PF_INET, SOCK_STREAM, getprotobyname('tcp')));
  2314.  
  2315.     if ($hardway) {
  2316.         #
  2317.         # This older way doesn't work as well.
  2318.         #
  2319.         Log(2, "Using alternate method to tell if FTP server is running.\n");
  2320.         my ($ftp) = SearchPath("ftp", "/usr/bin");
  2321.         my ($echo) = SearchPath("echo", "/bin:/usr/bin");
  2322.         if ($ftp eq "") {
  2323.             Log(0, "/usr/bin/ftp is not present.\n");
  2324.             Log(0, "Cannot tell if FTP server is running.\n");
  2325.             return (0);
  2326.         }
  2327.         if ($echo eq "") {
  2328.             Log(0, "/bin/echo is not present.\n");
  2329.             $echo = "echo";        # Try anyway
  2330.         }
  2331.         if (open(FTP, "$echo quit | $ftp -d -n 127.0.0.1 2>/dev/null |")) {
  2332.             my (@ftpresult) = <FTP>;
  2333.             close(FTP);
  2334.             # Connected to localhost.
  2335.             # 220 Hurricane NcFTPd Server (free personal license) ready.
  2336.             # ftp> quit
  2337.             # ---> QUIT
  2338.             # 221 Goodbye.
  2339.             my (@quitresult) = grep(@ftpresult, "QUIT");
  2340.             if (scalar(@quitresult) > 0) {
  2341.                 Log($v, "An FTP server is running.\n");
  2342.                 return (1);
  2343.             }
  2344.         }
  2345.         Log($v, "No FTP server is currently running.\n");
  2346.         return (0);
  2347.     }
  2348.  
  2349.     $serveraddr = sockaddr_in($ftpport, $serveraddr);
  2350.     if (connect(FTPSOCKET, $serveraddr)) {
  2351.         print FTPSOCKET "QUIT\r\n";
  2352.         close(FTPSOCKET);
  2353.         Log($v, "An FTP server is running.\n");
  2354.         return (1);
  2355.     }
  2356.  
  2357.     close(FTPSOCKET);
  2358.     Log($v, "No FTP server is running.\n");
  2359.     return (0);
  2360. }    # IsThereAnFTPServerServing
  2361.  
  2362.  
  2363.  
  2364.  
  2365. sub CommentOutFTPLineInInetdConf
  2366. {
  2367.     my ($inetd_conf) = "/etc/inetd.conf";
  2368.     $inetd_conf = "/etc/inet/inetd.conf" if ($SYS eq "solaris");
  2369.  
  2370.     my ($inetd_conf_new) = "$inetd_conf.new";
  2371.     my ($line);
  2372.     my ($disabled, $disableprefix);
  2373.  
  2374.     return unless (-f $inetd_conf);
  2375.  
  2376.     $disabled = 0;
  2377.     if (open(INETDCONF, "<$inetd_conf")) {
  2378.         if (! open(INETDCONFNEW, ">$inetd_conf_new")) {
  2379.             Log(0, "Could not create the file $inetd_conf_new: $!\n");
  2380.             Log(0, "The \"inetd\" process will not be able to be configured.\n");
  2381.             close(INETDCONF);
  2382.             return (0);
  2383.         }
  2384.  
  2385.         $disableprefix = "";
  2386.         while (defined($line = <INETDCONF>)) {
  2387.             if ($line =~ /^$ftpservicename\b/) {
  2388.                 $disableprefix = "#DISABLED by install_ncftpd.pl# ";
  2389.                 $disabled++;
  2390.             }
  2391.             print INETDCONFNEW $disableprefix, $line;
  2392.  
  2393.             # Also disable continuation lines.
  2394.             $disableprefix = "" unless ($line =~ /\\$/);
  2395.         }
  2396.         close(INETDCONF);
  2397.         close(INETDCONFNEW);
  2398.     }
  2399.  
  2400.     if ($disabled) {
  2401.         chmod(0644, $inetd_conf);
  2402.         unlink($inetd_conf);
  2403.         rename($inetd_conf_new, $inetd_conf) or Exit(1, "Could not rename $inetd_conf_new to $inetd_conf: $!\n");
  2404.         chmod(0644, $inetd_conf);
  2405.         Log(0, "Disabled the \"$ftpservicename\" service in the $inetd_conf file.\n");
  2406.         UninstallLog("UncommentOutFTPLineInInetdConf(\"$inetd_conf\");\n");
  2407.         return (1);
  2408.     } else {
  2409.         Log(0, "$inetd_conf does not appear to be handling the \"$ftpservicename\" service.\n");
  2410.         unlink($inetd_conf_new);
  2411.         return (0);
  2412.     }
  2413. }    # CommentOutFTPLineInInetdConf
  2414.  
  2415.  
  2416.  
  2417.  
  2418. sub CommentOutFTPLineInXinetdConf
  2419. {
  2420.     my ($inetd_conf) = "/etc/xinetd.conf";
  2421.     my ($inetd_conf_new) = "$inetd_conf.new";
  2422.     my ($line);
  2423.     my ($disabled, $disableprefix);
  2424.  
  2425.     return unless (-f $inetd_conf);
  2426.  
  2427.     $disabled = 0;
  2428.     if (open(INETDCONF, "<$inetd_conf")) {
  2429.         if (! open(INETDCONFNEW, ">$inetd_conf_new")) {
  2430.             Log(0, "Could not create the file $inetd_conf_new: $!\n");
  2431.             Log(0, "The \"xinetd\" process will not be able to be configured.\n");
  2432.             close(INETDCONF);
  2433.             return (0);
  2434.         }
  2435.  
  2436.         $disableprefix = "";
  2437.         while (defined($line = <INETDCONF>)) {
  2438.             if ($line =~ /^[^#]*service\s+$ftpservicename\b/) {
  2439.                 $disableprefix = "#DISABLED by install_ncftpd.pl# ";
  2440.                 $disabled++;
  2441.             }
  2442.             print INETDCONFNEW $disableprefix, $line;
  2443.  
  2444.             # Disable rest of block.
  2445.             $disableprefix = "" if ($line =~ /^[^#]*\}/);
  2446.         }
  2447.         close(INETDCONF);
  2448.         close(INETDCONFNEW);
  2449.     }
  2450.  
  2451.     if ($disabled) {
  2452.         chmod(0644, $inetd_conf);
  2453.         unlink($inetd_conf);
  2454.         rename($inetd_conf_new, $inetd_conf) or Exit(1, "Could not rename $inetd_conf_new to $inetd_conf: $!\n");
  2455.         chmod(0644, $inetd_conf);
  2456.         Log(0, "Disabled the \"$ftpservicename\" service in the $inetd_conf file.\n");
  2457.         UninstallLog("UncommentOutFTPLineInXinetdConf(\"$inetd_conf\");\n");
  2458.         return (1);
  2459.     } else {
  2460.         Log(0, "$inetd_conf does not appear to be handling the \"$ftpservicename\" service.\n");
  2461.         unlink($inetd_conf_new);
  2462.         return (0);
  2463.     }
  2464. }    # CommentOutFTPLineInXinetdConf
  2465.  
  2466.  
  2467.  
  2468.  
  2469. sub CommentOutFTPLineInXinetdD
  2470. {
  2471.     my ($inetd_d) = "/etc/xinetd.d";
  2472.     my ($inetd_conf);
  2473.     my ($line);
  2474.     my ($disabled, $disableprefix, $tdisabled);
  2475.  
  2476.     return unless (-d $inetd_d);
  2477.  
  2478.     my (@inetd_d_files) = glob("$inetd_d/*");
  2479.  
  2480.     $tdisabled = 0;
  2481.     for $inetd_conf (@inetd_d_files) {
  2482.         next if (-d $inetd_conf);
  2483.         if (open(INETDCONF, "<$inetd_conf")) {
  2484.             my ($inetd_conf_new) = "$inetd_conf.new";
  2485.             if (! open(INETDCONFNEW, ">$inetd_conf_new")) {
  2486.                 Log(0, "Could not create the file $inetd_conf_new: $!\n");
  2487.                 Log(0, "The \"xinetd\" process will not be able to be configured.\n");
  2488.                 close(INETDCONF);
  2489.                 return (0);
  2490.             }
  2491.  
  2492.             $disableprefix = "";
  2493.             $disabled = 0;
  2494.             while (defined($line = <INETDCONF>)) {
  2495.                 if ($line =~ /^[^#]*service\s+$ftpservicename\b/) {
  2496.                     $disableprefix = "#DISABLED by install_ncftpd.pl# ";
  2497.                     $disabled++;
  2498.                 }
  2499.                 print INETDCONFNEW $disableprefix, $line;
  2500.  
  2501.                 # Disable rest of block.
  2502.                 $disableprefix = "" if ($line =~ /^[^#]*\}/);
  2503.             }
  2504.             close(INETDCONF);
  2505.             close(INETDCONFNEW);
  2506.  
  2507.             if ($disabled) {
  2508.                 chmod(0644, $inetd_conf);
  2509.                 unlink($inetd_conf);
  2510.                 rename($inetd_conf_new, $inetd_conf) or Exit(1, "Could not rename $inetd_conf_new to $inetd_conf: $!\n");
  2511.                 chmod(0644, $inetd_conf);
  2512.                 Log(0, "Disabled the \"$ftpservicename\" service in the $inetd_conf file.\n");
  2513.                 $tdisabled++;
  2514.                 UninstallLog("UncommentOutFTPLineInXinetdD(\"$inetd_conf\");\n");
  2515.             } else {
  2516.                 unlink($inetd_conf_new);
  2517.             }
  2518.         }
  2519.     }
  2520.  
  2521.     if ($tdisabled > 0) {
  2522.         return (1);
  2523.     } else {
  2524.         Log(0, "$inetd_d does not appear to be handling the \"$ftpservicename\" service.\n");
  2525.         return (0);
  2526.     }
  2527. }    # CommentOutFTPLineInXinetdD
  2528.  
  2529.  
  2530.  
  2531.  
  2532. sub TellInetdToReloadConfiguration
  2533. {
  2534.     my (@pids) = PsGrep("inetd", "program", "pids");
  2535.     my ($pid) = 0;
  2536.     my ($npids) = scalar(@pids);
  2537.  
  2538.     if ($npids == 0) {
  2539.         Log(1, "Warning: No Inetd process is running?\n");
  2540.         return;
  2541.     }
  2542.  
  2543.     if ($npids > 1) {
  2544.         Log(1, "Warning: Multiple Inetd processes detected?\n");
  2545.         for $pid (@pids) {
  2546.             Log(1, "  PID $pid\n");
  2547.         }
  2548.     }
  2549.  
  2550.     for $pid (@pids) {
  2551.         Log(0, "Sending SIGHUP to Inetd running on PID $pid.\n");
  2552.         kill HUP => $pid;
  2553.     }
  2554.  
  2555.     Log(1, "Giving Inetd a few seconds to reload.\n");
  2556.     sleep(2);
  2557. }    # TellInetdToReloadConfiguration
  2558.  
  2559.  
  2560.  
  2561.  
  2562. sub TellXinetdToReloadConfiguration
  2563. {
  2564.     my (@pids) = PsGrep("xinetd", "program", "pids");
  2565.     my ($pid) = 0;
  2566.     my ($npids) = scalar(@pids);
  2567.  
  2568.     if ($npids == 0) {
  2569.         Log(1, "Warning: No Xinetd process is running?\n");
  2570.         return;
  2571.     }
  2572.  
  2573.     if ($npids > 1) {
  2574.         Log(1, "Warning: Multiple Xinetd processes detected?\n");
  2575.         for $pid (@pids) {
  2576.             Log(1, "  PID $pid\n");
  2577.         }
  2578.     }
  2579.  
  2580.     for $pid (@pids) {
  2581.         Log(0, "Sending SIGUSR2 to Xinetd running on PID $pid.\n");
  2582.         kill USR2 => $pid;
  2583.     }
  2584.  
  2585.     Log(1, "Giving Xinetd a few seconds to reload.\n");
  2586.     sleep(2);
  2587. }    # TellXinetdToReloadConfiguration
  2588.  
  2589.  
  2590.  
  2591.  
  2592. sub WaitForFTPServerToStart
  2593. {
  2594.     my ($i);
  2595.     my ($n) = @_;
  2596.     my ($isRunning) = 0;
  2597.     $n = 4 if ((! defined($n)) || ($n < 1));
  2598.  
  2599.     for ($i = 1; $i <= $n; $i++) {
  2600.         Log(0, "Checking if the FTP service has started.\n");
  2601.         $isRunning = IsThereAnFTPServerServing(1);
  2602.         last if ($isRunning == 1);
  2603.         Log(2, sprintf("Sleeping %d seconds.\n", (3 * $i)));
  2604.         sleep(3 * $i) if ($i < $n);
  2605.     }
  2606.     return ($isRunning);
  2607. }    # WaitForFTPServerToStart
  2608.  
  2609.  
  2610.  
  2611.  
  2612. sub WaitForFTPServerToExit
  2613. {
  2614.     my ($i);
  2615.     my ($n) = @_;
  2616.     my ($isRunning) = 0;
  2617.     $n = 4 if ((! defined($n)) || ($n < 1));
  2618.  
  2619.     for ($i = 1; $i <= $n; $i++) {
  2620.         $isRunning = IsThereAnFTPServerServing(1);
  2621.         last if ($isRunning == 0);
  2622.         Log(0, "Checking if the FTP service is still active.\n");
  2623.         Log(2, sprintf("Sleeping %d seconds.\n", (3 * $i)));
  2624.         sleep(3 * $i) if ($i < $n);
  2625.     }
  2626.     return (! $isRunning);
  2627. }    # WaitForFTPServerToExit
  2628.  
  2629.  
  2630.  
  2631.  
  2632. sub DisableInetdViaSMF                # solaris 10
  2633. {
  2634.     my ($inetadm) = "/usr/sbin/inetadm";
  2635.     my ($svc) = "network/ftp:default";
  2636.     my ($status);
  2637.  
  2638.     $status = `$inetadm 2>/dev/null | fgrep \"$svc\"`;
  2639.     return (0) if ($status eq "");
  2640.     Log(0, "Using inetadm to disable existing FTP service.\n");
  2641.     return (0) unless ($status =~ /online/);
  2642.  
  2643.     $status = `$inetadm -d \"$svc\" 2>&1 "`;
  2644.     $status = `$inetadm 2>/dev/null | fgrep \"$svc\"`;
  2645.     return (0) if ($status eq "");
  2646.     return (0) unless ($status =~ /disabled\s+disabled/);
  2647.     Log(1, "OK: $inetadm -d $svc\n");
  2648.     UninstallLog("\`$inetadm -e \\\"$svc\\\"\`;\n");
  2649.     return (1);
  2650. }    # DisableInetdViaSMF
  2651.  
  2652.  
  2653.  
  2654.  
  2655. sub DisableInetdHandlingOfFTP
  2656. {
  2657.     if (CommentOutFTPLineInInetdConf()) {
  2658.         TellInetdToReloadConfiguration();    
  2659.         if (! WaitForFTPServerToExit()) {
  2660.             Log(0, "\n");
  2661.             Log(0, "ERROR: FTP was disabled in the Inetd configuration file, but the\n"); 
  2662.             Log(0, "       FTP service is still accepting connections.  You need to\n");
  2663.             Log(0, "       manually shutdown and disable your existing FTP service then\n");
  2664.             Log(0, "       restart the installation process.\n");
  2665.             Log(0, "\n");
  2666.         }
  2667.     }
  2668.     if ((CommentOutFTPLineInXinetdConf()) || (CommentOutFTPLineInXinetdD())) {
  2669.         TellXinetdToReloadConfiguration();    
  2670.         if (! WaitForFTPServerToExit()) {
  2671.             Log(0, "\n");
  2672.             Log(0, "ERROR: FTP was disabled in the Xinetd configuration file, but the\n"); 
  2673.             Log(0, "       FTP service is still accepting connections.  You need to\n");
  2674.             Log(0, "       manually shutdown and disable your existing FTP service then\n");
  2675.             Log(0, "       restart the installation process.\n");
  2676.             Log(0, "\n");
  2677.         }
  2678.     }
  2679.     if (DisableInetdViaSMF()) {
  2680.         if (! WaitForFTPServerToExit()) {
  2681.             Log(0, "\n");
  2682.             Log(0, "ERROR: FTP was disabled using SMF (/usr/sbin/inetadm), but the\n"); 
  2683.             Log(0, "       FTP service is still accepting connections.  You need to\n");
  2684.             Log(0, "       manually shutdown and disable your existing FTP service then\n");
  2685.             Log(0, "       restart the installation process.\n");
  2686.             Log(0, "\n");
  2687.         }
  2688.     }
  2689. }    # DisableInetdHandlingOfFTP
  2690.  
  2691.  
  2692.  
  2693.  
  2694. sub KillFTPd
  2695. {
  2696.     my ($victim) = @_;
  2697.     my (@procs) = PsGrep($victim, "program", "pids");
  2698.     my (%origprocs);
  2699.     my ($proc);
  2700.     my ($nproc) = 0;
  2701.  
  2702.     return (0) if (scalar(@procs) == 0);
  2703.     Log(1, sprintf("Sending TERM signal to %d $victim processes.\n", scalar(@procs)));
  2704.  
  2705.     for $proc (@procs) {
  2706.         Log(2, "  ") if (($nproc % 10) == 0);
  2707.         Log(2, sprintf("%-7d", $proc));
  2708.         Log(2, "\n") if (($nproc % 10) == 9);
  2709.         $origprocs{$proc} = 1;
  2710.         $nproc++;
  2711.     }
  2712.     Log(2, "\n") if (($nproc % 10) != 9);
  2713.  
  2714.     kill TERM => @procs;
  2715.     sleep(3);
  2716.     my ($i);
  2717.     for ($i = 0; $i < 3; $i ++) {
  2718.         sleep(2);
  2719.         @procs = PsGrep($victim, "program", "pids");
  2720.         return (0) if (scalar(@procs) == 0);    # All are dead, done.
  2721.     }
  2722.  
  2723.     my ($newinstanceprocs) = 0;
  2724.     my (@stragglers) = ();
  2725.     for $proc (@procs) {
  2726.         if (defined($origprocs{$proc})) {
  2727.             push(@stragglers, $proc);
  2728.         } else {
  2729.             $newinstanceprocs++;
  2730.         }
  2731.     }
  2732.  
  2733.     if ($newinstanceprocs > 0) {
  2734.         Log(1, "New processes were born after the old ones were killed!\n");
  2735.     }
  2736.     return ($newinstanceprocs) if (scalar(@stragglers) == 0);
  2737.  
  2738.     Log(1, sprintf("Sending KILL signal to %d $victim processes.\n", scalar(@stragglers)));
  2739.     $nproc = 0;
  2740.     for $proc (@stragglers) {
  2741.         Log(2, "  ") if (($nproc % 10) == 0);
  2742.         Log(2, sprintf("%-7d", $proc));
  2743.         Log(2, "\n") if (($nproc % 10) == 9);
  2744.         $nproc++;
  2745.     }
  2746.     Log(2, "\n") if (($nproc % 10) != 9);
  2747.     kill KILL => @stragglers;            # KiLL 'Em ALL
  2748.     return ($newinstanceprocs);
  2749. }    # KillFTPd
  2750.  
  2751.  
  2752.  
  2753.  
  2754. sub NoteExistingNcFTPdConfigurationFromCommandLine
  2755. {
  2756.     my ($line) = @_;
  2757.  
  2758.     if ($line =~ /\s(\/\S*\/general.cf)\b/) {
  2759.         my ($cf) = $1;
  2760.         if ((-f $cf) && ($existing_general_cf eq "")) {
  2761.             $existing_general_cf = $cf;
  2762.             Log(1, "Found existing NcFTPd config file: $existing_general_cf.\n");
  2763.         }
  2764.     }
  2765.     if ($line =~ /\s(\/\S*\/domain.cf)\b/) {
  2766.         my ($cf) = $1;
  2767.         if ((-f $cf) && ($existing_domain_cf eq "")) {
  2768.             $existing_domain_cf = $cf;
  2769.             Log(1, "Found existing NcFTPd config file: $existing_domain_cf.\n");
  2770.         }
  2771.     }
  2772.     if ($line =~ /(\/\S*\/ncftpd)\s/) {
  2773.         my ($n) = $1;
  2774.         if ((! -d $n) && (-x _) && ($existing_ncftpd eq "")) {
  2775.             $existing_ncftpd = $n;
  2776.             Log(1, "Found existing NcFTPd at $existing_ncftpd.\n");
  2777.         }
  2778.     }
  2779. }    # NoteExistingNcFTPdConfigurationFromCommandLine
  2780.  
  2781.  
  2782.  
  2783.  
  2784. sub DisableExistingFTPServersRunningFromInittab
  2785. {
  2786.     if (open(ETCINITTAB, "</etc/inittab")) {
  2787.         my (@inittab_lines) = <ETCINITTAB>;
  2788.         close(ETCINITTAB);
  2789.  
  2790.         # nc:345:respawn:/usr/local/etc/ncftpd/ncftpd.sh
  2791.         my ($ncftpd_inittab_entries) = 0;
  2792.         my ($ftpd_inittab_entries) = 0;
  2793.         my ($ftpd) = "NcFTPd";
  2794.  
  2795.         my ($line);
  2796.         foreach $line (@inittab_lines) {
  2797.             next if ($line =~ /^\s*#/);    # skip comments
  2798.             next unless ($line =~ /^\w+:\w*:(\w+):.*/);
  2799.             next if ($1 eq "off");        # skip "off" services
  2800.             if ($line =~ /ncftpd/) {
  2801.                 Log(1, "Found NcFTPd entry in the /etc/inittab.\n");
  2802.                 $ncftpd_inittab_entries++;
  2803.                 $line = "#DISABLED by install_ncftpd.pl# $line";
  2804.                 if ($ncftpd_inittab_entries > 1) {
  2805.                     Log(0, "Multiple existing NcFTPd entries found in /etc/inittab -- all will be disabled.\n");
  2806.                     next;
  2807.                 }
  2808.                 NoteExistingNcFTPdConfigurationFromCommandLine($line);
  2809.                 $ftpd = "NcFTPd";
  2810.             } elsif ($line =~ /ftpd/i) {
  2811.                 Log(1, "Found other ftpd entry in the /etc/inittab.\n");
  2812.                 $ftpd_inittab_entries++;
  2813.                 $line = "#DISABLED by install_ncftpd.pl# $line";
  2814.                 if ($ftpd_inittab_entries > 1) {
  2815.                     Log(0, "Multiple existing ftpd entries found in /etc/inittab -- all will be disabled.\n");
  2816.                     next;
  2817.                 }
  2818.                 $ftpd = "ftpd" unless ($ncftpd_inittab_entries > 0);
  2819.             }
  2820.         }
  2821.         if (($ncftpd_inittab_entries > 0) || ($ftpd_inittab_entries > 0)) {
  2822.             chmod(0644, "/etc/inittab");
  2823.             UninstallLog("UncommentOutFTPLinesInInittab();\n");
  2824.             if (open(ETCINITTAB, ">/etc/inittab")) {
  2825.                 print ETCINITTAB @inittab_lines;
  2826.                 close(ETCINITTAB);
  2827.                 chmod(0644, "/etc/inittab");
  2828.                 Log(0, "Disabled $ftpd in /etc/inittab.\n");
  2829.  
  2830.                 my ($init) = SearchPath("init", "/sbin:/usr/sbin:/usr/bin:/bin");
  2831.                 $init = "init" unless ($init);
  2832.                 Log(1, "Running \"$init q\" to reload modified /etc/inittab.\n");
  2833.                 system($init, "q");
  2834.  
  2835.                 # At this point, "init" should send a TERM signal
  2836.                 # to ncftpd.  Some buggy "init" implementations do not,
  2837.                 # so wait a bit, then try to manually kill off the
  2838.                 # processes.
  2839.                 #
  2840.                 Log(1, "Waiting for $init to ask $ftpd to shutdown.\n");
  2841.                 sleep(5);
  2842.                 if (! WaitForFTPServerToExit(1)) {
  2843.                     Log(0, "Apparently \"$init\" did not shutdown $ftpd.  We'll try to now.\n");
  2844.                     # KillFTPd("ncftpd|ftpd|in.ftpd|wu\-?ftpd|pro[\-]?ftpd");
  2845.                     KillFTPd(".*ftpd");
  2846.                 }
  2847.  
  2848.                 if (! WaitForFTPServerToExit()) {
  2849.                     Log(0, "\n");
  2850.                     Log(0, "ERROR: $ftpd was disabled in the /etc/inittab, but it is still\n"); 
  2851.                     Log(0, "       accepting connections.  You need to shutdown NcFTPd, then\n");
  2852.                     Log(0, "       restart the installation process.\n");
  2853.                     Log(0, "\n");
  2854.                     Exit(1);
  2855.                 }
  2856.                 return (1);        # Done -- no more NcFTPd processes are running.
  2857.             } else {
  2858.                 Log(0, "Could not rewrite the /etc/inittab file: $!\n");
  2859.             }
  2860.         } else {
  2861.             Log(1, "Did not find NcFTPd or ftpd entries in the /etc/inittab.\n");
  2862.         }
  2863.     }
  2864.     return (0);    # Nothing disabled and killed
  2865. }    # DisableExistingFTPServersRunningFromInittab
  2866.  
  2867.  
  2868.  
  2869.  
  2870. sub DisableExistingNcFTPd
  2871. {
  2872.     my ($oCOLUMNS);
  2873.     my (@procs);
  2874.  
  2875.     #
  2876.     # This disables NcFTPd when it is not running from the
  2877.     # /etc/inittab.
  2878.     #
  2879.  
  2880.     $oCOLUMNS = $ENV{"COLUMNS"};
  2881.     $ENV{"COLUMNS"} = "132" if ((!defined($oCOLUMNS)) || ($oCOLUMNS < 132));
  2882.     @procs = PsGrep("respawn", "program", "long");
  2883.     $ENV{"COLUMNS"} = $oCOLUMNS if (defined($oCOLUMNS));
  2884.  
  2885.     if (scalar(@procs) > 0) {
  2886.         Log(1, "The \"respawn\" program is currently running.\n");
  2887.         my ($proc);
  2888.         for $proc (@procs) {
  2889.             if ($proc =~ /ncftpd/) {
  2890.                 Log(0, "\n");
  2891.                 Log(0, "ERROR: You appear to be using the \"respawn\" utility to launch NcFTPd:\n");
  2892.                 Log(0, "\n       ", $proc, "\n\n");
  2893.                 Log(0, "       You need to both kill this process *AND* make sure you disable\n");
  2894.                 Log(0, "       respawn from running when the system boots.  Once that is\n");
  2895.                 Log(0, "       completed, restart the installation process.\n");
  2896.                 Exit(1);
  2897.             }
  2898.         }
  2899.     }
  2900.     
  2901.     $oCOLUMNS = $ENV{"COLUMNS"};
  2902.     $ENV{"COLUMNS"} = "132" if ((!defined($oCOLUMNS)) || ($oCOLUMNS < 132));
  2903.     @procs = PsGrep("ncftpd", "program", "long");
  2904.     $ENV{"COLUMNS"} = $oCOLUMNS if (defined($oCOLUMNS));
  2905.  
  2906.     if (scalar(@procs) > 0) {
  2907.         Log(0, "NcFTPd is currently running.\n");
  2908.         my ($proc);
  2909.         for $proc (@procs) {
  2910.             NoteExistingNcFTPdConfigurationFromCommandLine($proc);
  2911.         }
  2912.         Log(0, "Terminating the running instance of NcFTPd.\n");
  2913.         if (KillFTPd("ncftpd") > 0) {
  2914.             Log(0, "\n");
  2915.             Log(0, "ERROR: NcFTPd respawned when it was killed.\n");
  2916.             Log(0, "       You need manually shutdown NcFTPd so it no longer respawns,\n");
  2917.             Log(0, "       and then restart the installation process.\n");
  2918.             Exit(1);
  2919.         }
  2920.  
  2921.         if (! WaitForFTPServerToExit()) {
  2922.             Log(0, "\n");
  2923.             Log(0, "ERROR: NcFTPd was terminated, but some other process is still\n");
  2924.             Log(0, "       accepting connections.  You need to terminate those processes\n");
  2925.             Log(0, "       and prevent them from restarting at boot time.  Once that is\n");
  2926.             Log(0, "       completed, restart the installation process.\n");
  2927.             Log(0, "\n");
  2928.             Exit(1);
  2929.         }
  2930.     } else {
  2931.         Log(0, "NcFTPd is not currently running.\n");
  2932.     }
  2933. }    # DisableExistingNcFTPd
  2934.  
  2935.  
  2936.  
  2937.  
  2938. sub CheckIfSomeOtherFTPServerIsStillRunning
  2939. {
  2940.     if (IsThereAnFTPServerServing(1)) {
  2941.         Log(0, "\n");
  2942.         Log(0, "ERROR: An unknown process is still accepting FTP connections.\n"); 
  2943.         Log(0, "       You need to terminate those processes *and* prevent them\n");
  2944.         Log(0, "       from restarting at boot time.  Once that is completed,\n");
  2945.         Log(0, "       restart the installation process.\n");
  2946.         Log(0, "\n");
  2947.         Exit(1);
  2948.     }
  2949. }    # CheckIfSomeOtherFTPServerIsStillRunning
  2950.  
  2951.  
  2952.  
  2953.  
  2954. sub DisableRcDir
  2955. {
  2956.     my ($rc_dir) = @_;
  2957.  
  2958.     my (@rc_scripts) = glob("$rc_dir/[SKIP]*");
  2959.     return if (scalar(@rc_scripts) < 1);
  2960.  
  2961.     my ($rc_script, $rc_file, $script_type, $disabled_rc_script_path, $i);
  2962.     for $rc_script (@rc_scripts) {
  2963.         next if (-d $rc_script);
  2964.         $rc_file = $rc_script;
  2965.         $rc_file =~ s/^.*\///;
  2966.         if ($rc_file =~ /(ftp|ftpd)\b/i) {
  2967.             #
  2968.             # This appears to be an rc script that
  2969.             # starts up NcFTPd or some other ftpd.
  2970.             # Disable it by renaming it with a prefix
  2971.             # that "rc" won't look for.
  2972.             #
  2973.             $script_type = "?";
  2974.             $script_type = "startup" if (substr($rc_file, 0, 1) eq "S");
  2975.             $script_type = "shutdown" if (substr($rc_file, 0, 1) eq "K");
  2976.             Log(0, "Disabling system $script_type script $rc_script.\n");
  2977.             $i = 0;
  2978.             for ($i = 1; $i < 1000; $i++) {
  2979.                 $disabled_rc_script_path = $rc_script;
  2980.                 $disabled_rc_script_path =~ s/\/[^\/]+$//;
  2981.                 $disabled_rc_script_path .= "/#DISABLED#_$rc_file";
  2982.                 $disabled_rc_script_path .= ".$i" if ($i > 1);
  2983.                 last if (! -f $disabled_rc_script_path);
  2984.             }
  2985.             if (rename($rc_script, $disabled_rc_script_path)) {
  2986.                 Log(1, "Renamed $rc_script to $disabled_rc_script_path.\n");
  2987.                 UninstallLog("Rename(\"$disabled_rc_script_path\", \"$rc_script\");\n");
  2988.             } else {
  2989.                 Log(0, "Could not rename $rc_script to $disabled_rc_script_path: $!\n");
  2990.             }
  2991.         }
  2992.     }
  2993. }    # DisableRcDir
  2994.  
  2995.  
  2996.  
  2997.  
  2998. sub DisableRcScripts
  2999. {
  3000.     my (@rc_dirs) = (
  3001.         "rc0.d",
  3002.         "rc1.d",
  3003.         "rc2.d",
  3004.         "rc3.d",
  3005.         "rc4.d",
  3006.         "rc5.d",
  3007.         "rcS.d",
  3008.         "rc6.d",
  3009.     );
  3010.  
  3011.     my (@rc_parent_dirs) = (
  3012.         "/etc",            # Solaris
  3013.         "/etc/rc.d",        # Red Hat
  3014.         "/etc/init.d",        # ??
  3015.         "/sbin",        # HP-UX
  3016.         "/sbin/rc.d",        # ??
  3017.         "/sbin/init.d",        # SuSE
  3018.     );
  3019.  
  3020.     my ($rc_parent_dir, $rc_dir, $rc_dirpath);
  3021.     for $rc_parent_dir (@rc_parent_dirs) {
  3022.         for $rc_dir (@rc_dirs) {
  3023.             $rc_dirpath = "$rc_parent_dir/$rc_dir";
  3024.             if (-d $rc_dirpath) {
  3025.                 DisableRcDir($rc_dirpath);
  3026.             }
  3027.         }
  3028.     }
  3029. }    # DisableRcScripts
  3030.  
  3031.  
  3032.  
  3033.  
  3034. sub NoteExistingNcFTPdVersion
  3035. {
  3036.     my ($cf, $cfdir, $n);
  3037.  
  3038.     if ($existing_ncftpd eq "") {
  3039.         $cf = "";
  3040.         $cf = $existing_general_cf if ($existing_general_cf ne "");
  3041.         $cf = $existing_domain_cf if ($existing_domain_cf ne "");
  3042.         if ($cf ne "") {
  3043.             $cfdir = $cf;
  3044.             $cfdir =~ s/\/[^\/]+$//;
  3045.             $n = "$cfdir/ncftpd";
  3046.             if (-x $n) {
  3047.                 $existing_ncftpd = $n;
  3048.             }
  3049.         }
  3050.         if ($existing_ncftpd eq "") {
  3051.             if (-x $new_ncftpd) {
  3052.                 $existing_ncftpd = $new_ncftpd;
  3053.             } else {
  3054.                 $n = SearchPath("ncftpd", "", ".::$extra_paths");
  3055.                 $existing_ncftpd = $n if ($n ne "");
  3056.             }
  3057.         }
  3058.     }
  3059.  
  3060.     if (($existing_general_cf eq "") && (-f $new_general_cf)) {
  3061.         $existing_general_cf = $new_general_cf;
  3062.         Log(1, "Found existing NcFTPd config file: $existing_general_cf.\n");
  3063.     }
  3064.  
  3065.     if (($existing_domain_cf eq "") && (-f $new_domain_cf)) {
  3066.         $existing_domain_cf = $new_domain_cf;
  3067.         Log(1, "Found existing NcFTPd config file: $existing_domain_cf.\n");
  3068.     }
  3069.  
  3070.     if (($existing_general_cf ne "") && ($existing_domain_cf eq "")) {
  3071.         $cf = $existing_general_cf;
  3072.         $cfdir = $cf;
  3073.         $cfdir =~ s/\/[^\/]+$//;
  3074.         $cf = "$cfdir/domain.cf";
  3075.         if (-f $cf) {
  3076.             $existing_domain_cf = $cf;
  3077.             Log(1, "Found existing NcFTPd config file: $existing_domain_cf.\n");
  3078.         }
  3079.     } elsif (($existing_general_cf eq "") && ($existing_domain_cf ne "")) {
  3080.         $cf = $existing_domain_cf;
  3081.         $cfdir = $cf;
  3082.         $cfdir =~ s/\/[^\/]+$//;
  3083.         $cf = "$cfdir/general.cf";
  3084.         if (-f $cf) {
  3085.             $existing_general_cf = $cf;
  3086.             Log(1, "Found existing NcFTPd config file: $existing_general_cf.\n");
  3087.         }
  3088.     } elsif (($existing_general_cf eq "") && ($existing_domain_cf eq "") && ($existing_ncftpd ne "")) {
  3089.         $cf = $existing_ncftpd;
  3090.         $cfdir = $cf;
  3091.         $cfdir =~ s/\/[^\/]+$//;
  3092.         $cf = "$cfdir/general.cf";
  3093.         if (-f $cf) {
  3094.             $existing_general_cf = $cf;
  3095.             Log(1, "Found existing NcFTPd config file: $existing_general_cf.\n");
  3096.         }
  3097.         $cf = $existing_ncftpd;
  3098.         $cfdir = $cf;
  3099.         $cfdir =~ s/\/[^\/]+$//;
  3100.         $cf = "$cfdir/domain.cf";
  3101.         if (-f $cf) {
  3102.             $existing_domain_cf = $cf;
  3103.             Log(1, "Found existing NcFTPd config file: $existing_domain_cf.\n");
  3104.         }
  3105.     }
  3106.  
  3107.     if ($existing_ncftpd eq "") {
  3108.         $cf = "";
  3109.         $cf = $existing_general_cf if ($existing_general_cf ne "");
  3110.         $cf = $existing_domain_cf if ($existing_domain_cf ne "");
  3111.         if ($cf ne "") {
  3112.             $cfdir = $cf;
  3113.             $cfdir =~ s/\/[^\/]+$//;
  3114.             $n = "$cfdir/ncftpd";
  3115.             if (-x $n) {
  3116.                 $existing_ncftpd = $n;
  3117.             }
  3118.         }
  3119.     }
  3120.  
  3121.     if ($existing_ncftpd ne "") {
  3122.         my ($ver) = `$existing_ncftpd -b 2>&1`;
  3123.         if ($ver =~ /([1234]\.\d+\.\d+)/) {
  3124.             $ver = $1;
  3125.             $existing_version = $ver;
  3126.         } else {
  3127.             $ver = `strings $existing_ncftpd 2>/dev/null | fgrep '@(#) NcFTPd '`;
  3128.             if ($ver =~ /([1234]\.\d+\.\d+)/) {
  3129.                 $ver = $1;
  3130.                 $existing_version = $ver;
  3131.             } else {
  3132.                 $ver = "unknown";
  3133.             }
  3134.         }
  3135.         Log(0, "Found existing NcFTPd (version $ver) at $existing_ncftpd.\n");
  3136.     }
  3137. }    # NoteExistingNcFTPdVersion
  3138.  
  3139.  
  3140.  
  3141.  
  3142. sub LoadExistingConfigs
  3143. {
  3144.     my ($line, $var, $val);
  3145.  
  3146.     if ($existing_general_cf ne "") {
  3147.         if (open(CF, "<$existing_general_cf")) {
  3148.             Log(1, "Loading existing settings from $existing_general_cf.\n");
  3149.             while (defined($line = <CF>)) {
  3150.                 chomp($line);
  3151.                 next unless ($line =~ /^([A-Za-z0-9_\-]+)\s*\=\s*([^\n\r]*)/);
  3152.                 $var = $1;
  3153.                 $val = $2;
  3154.                 Log(2, "  general.cf: [$var] = [$val]\n");
  3155.             }
  3156.             close(CF);
  3157.         }
  3158.     }
  3159.  
  3160.     if ($existing_domain_cf ne "") {
  3161.         if (open(CF, "<$existing_domain_cf")) {
  3162.             Log(1, "Loading existing settings from $existing_domain_cf.\n");
  3163.             while (defined($line = <CF>)) {
  3164.                 chomp($line);
  3165.                 next unless ($line =~ /^([A-Za-z0-9_\-]+)\s*\=\s*([^\n\r]*)/);
  3166.                 $var = $1;
  3167.                 $val = $2;
  3168.                 Log(2, "  domain.cf: [$var] = [$val]\n");
  3169.             }
  3170.             close(CF);
  3171.         }
  3172.     }
  3173. }    # LoadExistingConfigs
  3174.  
  3175.  
  3176.  
  3177.  
  3178. sub SafeRename
  3179. {
  3180.     my ($rnfm, $rnto) = @_;
  3181.     return ("") if (! -f $rnfm);
  3182.  
  3183.     $rnto = "$rnfm.orig" if (! defined($rnto));
  3184.     my ($ornto) = $rnto;
  3185.     my ($i);
  3186.     for ($i = 2; $i < 1000; $i++) {
  3187.         last if (! -f $rnto);
  3188.         $rnto = $ornto . "-$i";
  3189.     }
  3190.     if (rename($rnfm, $rnto)) {
  3191.         Log(1, "Renamed $rnfm to $rnto.\n");
  3192.         UninstallLog("Rename(\"$rnto\", \"$rnfm\");\n");
  3193.         return ($rnto);
  3194.     } else {
  3195.         Log(0, "Could not rename $rnfm to $rnto: $!\n");
  3196.         return ("");
  3197.     }
  3198. }    # SafeRename
  3199.  
  3200.  
  3201.  
  3202.  
  3203. sub SafeRenameWithNcVersion
  3204. {
  3205.     my ($rnfm, $rnto) = @_;
  3206.     $rnto = "$rnfm-$existing_version" if ((! defined($rnto)) && ($existing_version ne ""));
  3207.     return (SafeRename($rnfm, $rnto));
  3208. }    # SafeRenameWithNcVersion
  3209.  
  3210.  
  3211.  
  3212.  
  3213. sub LookupWebUser
  3214. {
  3215.     my (@webusers) = ("www", "httpd", "http", "apache", "web");
  3216.     my ($xwebuser, $xwebgroup);
  3217.     my ($name,$passwd,$uid,$gid,$quota,$comment,$gcos,$dir,$shell,$expire);
  3218.  
  3219.     Log(1, "Checking system user database for a web server username.\n");
  3220.     for $xwebuser (@webusers) {
  3221.         ($name,$passwd,$uid,$gid,$quota,$comment,$gcos,$dir,$shell,$expire) = 
  3222.             getpwnam($xwebuser);
  3223.         if (defined($name) && defined($uid) && defined($gid)) {
  3224.             $webuser = $xwebuser;
  3225.             $webuid = $uid;
  3226.             $webgid = $gid;
  3227.             $webgroup = "$gid";
  3228.             $xwebgroup = getgrgid($webgid);
  3229.             $webgroup = $xwebgroup if (defined($xwebgroup));
  3230.             Log(1, "Found web server user \"$webuser\" (UID $webuid), group \"$webgroup\" (GID $webgid) in system user database.\n");
  3231.             last;
  3232.         }
  3233.     }
  3234. }    # LookupWebUser
  3235.  
  3236.  
  3237.  
  3238.  
  3239. sub MkInstallDirs
  3240. {
  3241.     Mkdirs($bindir, 00755);
  3242.     Mkdirs($sbindir, 00755);
  3243.     Mkdirs($sysconfdir, 00755);
  3244.     Mkdirs($runtimedatadir, 00755);
  3245.     Mkdirs($logdir, 00755);
  3246.  
  3247.     # We don't use these yet...
  3248.     # Mkdirs($datadir, 00755);
  3249.     # Mkdirs($libdir, 00755);
  3250.     # Mkdirs($includedir, 00755);
  3251.     # Mkdirs($mandir, 00755);
  3252.  
  3253.     if ((defined($webgid)) && ($webgid != (-1))) {
  3254.         Mkdirs($confdir, 00750, 0, $webgid);
  3255.         Mkdirs($rptbindir, 00755, 0, $webgid);
  3256.         Mkdirs("$logdir/ncftpd", 00750, $webuid, $webgid);
  3257.     } else {
  3258.         Mkdirs($confdir, 00755);
  3259.         Mkdirs($rptbindir, 00755, 0, 0);
  3260.         Mkdirs("$logdir/ncftpd", 00750);
  3261.     }
  3262. }    # MkInstallDirs
  3263.  
  3264.  
  3265.  
  3266. sub FixScript
  3267. {
  3268.     my ($path, $headerline) = @_;
  3269.     my ($line);
  3270.  
  3271.     my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) =     
  3272.         stat($path);
  3273.     return 0 unless (defined($mtime));
  3274.  
  3275.     if (open(SRC, "<$path")) {
  3276.         $line = <SRC>;
  3277.         if (! open(DST, ">$path.new")) {
  3278.             close(SRC);
  3279.             return 0;
  3280.         } else {
  3281.             print DST $headerline, "\n";
  3282.             while (defined($line = <SRC>)) {
  3283.                 print DST $line;
  3284.             }
  3285.             close(DST);
  3286.             close(SRC);
  3287.             return 0 unless rename("$path.new", $path);
  3288.             chmod($mode, $path);
  3289.             utime($atime, $mtime, $path);
  3290.             return 1;
  3291.         }
  3292.     }
  3293.     return 0;
  3294. }    # FixScript
  3295.  
  3296.  
  3297.  
  3298.  
  3299. sub FixReportScripts
  3300. {
  3301.     return (0) unless (-d "${install_src_root}/rptbin");
  3302.  
  3303.     my (@scripts) = glob("${install_src_root}/rptbin/*.cgi");
  3304.     my ($script);
  3305.     my ($sh) = SearchPath("ksh");
  3306.  
  3307.     $sh = SearchPath("bash") unless ($sh ne "");
  3308.     if ($sh ne "") {
  3309.         foreach $script (@scripts) {
  3310.             FixScript($script, "#!${sh}");
  3311.         }
  3312.     }
  3313.  
  3314.     return (1);
  3315. }    # FixReportScripts
  3316.  
  3317.  
  3318.  
  3319.  
  3320. sub RemoveFtpFromEtcFtpusers
  3321. {
  3322.     return (0) if ($remove_ftp_from_ftpusers == 0);
  3323.     return (0) if ($existing_ncftpd ne "");    # Assume they wanted it that way
  3324.  
  3325.     my ($need_to_modify) = 0;
  3326.     my ($file_contents) = "";
  3327.     my ($user) = "";
  3328.     my ($disableprefix) = "#DISABLED by install_ncftpd.pl# ";
  3329.  
  3330.     if (open(ETCFTPUSERS, "</etc/ftpusers")) {
  3331.         while (defined($user = <ETCFTPUSERS>)) {
  3332.             chomp($user);
  3333.             if (($user =~ /^\s*#/) || ($user =~ /^\s*$/)) {
  3334.                 # Keep junk line as-is.
  3335.                 $file_contents .= $user . "\n";
  3336.                 next;
  3337.             }
  3338.             if ($user =~ /^\s*(\S+)\s*$/) {
  3339.                 if ($user ne $1) {
  3340.                     Log(0, "Found extraneous whitespace in /etc/ftpusers.  Need to remove it.\n");
  3341.                     $user = $1;
  3342.                     $need_to_modify++;
  3343.                 }
  3344.             }
  3345.             if ($user =~ /^(ftp|anonymous|_ftp)\s*$/) {
  3346.                 Log(0, "Found $user in /etc/ftpusers.  Need to remove it so anonymous FTP can work.\n");
  3347.                 $need_to_modify++;
  3348.                 $file_contents .= $disableprefix . $user . "\n";
  3349.             } else {
  3350.                 $file_contents .= $user . "\n";
  3351.             }
  3352.         }
  3353.         close(ETCFTPUSERS);
  3354.     }
  3355.  
  3356.     if ($need_to_modify > 0) {
  3357.         if (open(ETCFTPUSERS, ">/etc/ftpusers")) {
  3358.             print ETCFTPUSERS $file_contents;
  3359.             close(ETCFTPUSERS);
  3360.             # Modifying an existing file, so not necessary...
  3361.             # chown(0, 0, "/etc/ftpusers");
  3362.             # chmod(0644, "/etc/ftpusers");
  3363.             UninstallLog("UncommentFTPUsers();\n");
  3364.             Log(1, "Modified /etc/ftpusers successfully.\n");
  3365.         }
  3366.     }
  3367. }    # RemoveFtpFromEtcFtpusers
  3368.  
  3369.  
  3370.  
  3371.  
  3372. sub InstallDefaultConfigs
  3373. {
  3374.     my (@cfdata);
  3375.     my ($line, $var, $val, $oval, $ovar);
  3376.  
  3377.     Log(0, "Installing new NcFTPd config files.\n");
  3378.  
  3379.     if (! open(CF, "<$install_src_root/conf/general.cf-dist")) {
  3380.         Exit(1, "Could not open: $install_src_root/conf/general.cf-dist: $!\n");
  3381.     }
  3382.     @cfdata = <CF>;
  3383.     close(CF);
  3384.  
  3385.     foreach $line (@cfdata) {
  3386.         if ($line =~ /^REMOVE-THIS-LINE/) {
  3387.             $line = "# (removed by install_ncftpd.pl)\n";
  3388.             next;
  3389.         }
  3390.         next unless ($line =~ /^((#\s*)?[A-Za-z0-9_\-]+)\s*\=\s*([^\n\r]*)/);
  3391.         $var = $1;
  3392.         $val = $3;
  3393.         $oval = $val;
  3394.         $ovar = $var;
  3395.         $val =~ s-/var/log-$logdir-g;
  3396.         $val =~ s-/var/run-$runtimedatadir-g;
  3397.         $val =~ s-/home/ftp-$ftphome-g;
  3398.         $val =~ s-/usr/local/etc-$sysconfdir-g;
  3399.         $val =~ s-/usr/local/bin-$bindir-g;
  3400.         $val =~ s-/usr/local/sbin-$sbindir-g;
  3401.         $val =~ s-/usr/local-$prefix-g;
  3402.         $val = $ftpport if ($var =~ /#?port/);
  3403.         if (($var =~ /#?log-owner/) && ($webuser eq "")) {
  3404.             $var = "#log-owner";
  3405.         }
  3406.         if (($var =~ /#?log-group/) && ($webgroup eq "")) {
  3407.             $var = "#log-group";
  3408.         }
  3409.         if (($var =~ /#?log-owner/) && ($webuser ne "")) {
  3410.             $var = "log-owner";
  3411.             $val = $webuser;
  3412.         }
  3413.         if (($var =~ /#?log-group/) && ($webgroup ne "")) {
  3414.             $var = "log-group";
  3415.             $val = $webgroup;
  3416.         }
  3417.         if (($var =~ /#?log-umask/) && ($webuser ne "")) {
  3418.             $var = "log-umask";
  3419.             $val = "027";
  3420.         }
  3421.         if (($oval ne $val) || ($ovar ne $var)) {
  3422.             $line = "$var=$val\n";
  3423.             Log(2, "  set general.cf: $var=$val\n");
  3424.         }
  3425.     }
  3426.  
  3427.     if (! open(CF, ">$new_general_cf")) {
  3428.         Exit(1, "Could not create: $new_general_cf: $!\n");
  3429.     }
  3430.     print CF @cfdata;
  3431.     close(CF);
  3432.     Log(0, "Created $new_general_cf.\n");
  3433.     UninstallLog("Remove(\"$new_general_cf\");\n");
  3434.  
  3435.     #
  3436.     # Domain.cf
  3437.     #
  3438.  
  3439.     my ($addr, $myhostname, $myipaddr);
  3440.     my ($additionalsets) = 0;
  3441.     $myipaddr = "127.0.0.1";
  3442.     $myhostname = "localhost";
  3443.     Log(0, "Looking up IP address and hostname for this machine.\n");
  3444.     Log(2, "Running \"$install_src_root/ncftpd -e\".\n");
  3445.     $myhostname = `$install_src_root/ncftpd -e 2>/dev/null`;
  3446.     chomp($myhostname);
  3447.     Log(2, "  result = [$myhostname]\n");
  3448.     $myhostname = "localhost" if ((! defined($myhostname)) || ($myhostname eq ""));
  3449.     $addr = gethostbyname($myhostname);
  3450.     $myipaddr = inet_ntoa($addr) if (defined($addr));
  3451.     Log(2, "  ipaddr = [$myipaddr]\n");
  3452.  
  3453.     if (! open(CF, "<$install_src_root/conf/domain.cf-dist")) {
  3454.         Exit(1, "Could not open: $install_src_root/conf/domain.cf-dist: $!\n");
  3455.     }
  3456.     @cfdata = <CF>;
  3457.     close(CF);
  3458.  
  3459.     foreach $line (@cfdata) {
  3460.         if ($line =~ /^REMOVE-THIS-LINE/) {
  3461.             $line = "# (removed by install_ncftpd.pl)\n";
  3462.             next;
  3463.         }
  3464.         $additionalsets++ if ($line =~ /^#\ end\ of\ first/);
  3465.         next unless ($line =~ /^((#\s*)?[A-Za-z0-9_\-]+)\s*\=\s*([^\n\r]*)/);
  3466.         $var = $1;
  3467.         $val = $3;
  3468.         $oval = $val;
  3469.         $ovar = $var;
  3470.         $val =~ s-/var/log-$logdir-g;
  3471.         $val =~ s-/var/run-$runtimedatadir-g;
  3472.         $val =~ s-/home/ftp-$ftphome-g;
  3473.         $val =~ s-/usr/local/etc-$sysconfdir-g;
  3474.         $val =~ s-/usr/local/bin-$bindir-g;
  3475.         $val =~ s-/usr/local/sbin-$sbindir-g;
  3476.         $val =~ s-/usr/local-$prefix-g;
  3477.         $val = $ftphome if ($var =~ /#?ftp-home/);
  3478.         if ($additionalsets == 0) {
  3479.             $val = $myhostname if ($var =~ /#?set-name/);
  3480.             $val = $myhostname if ($var =~ /#?server-name/);
  3481.             $val = $myipaddr if ($var =~ /#?server-address/);
  3482.         }
  3483.         if (($oval ne $val) || ($ovar ne $var)) {
  3484.             $line = "$var=$val\n";
  3485.             Log(2, "  set domain.cf: $var=$val\n");
  3486.         }
  3487.     }
  3488.  
  3489.     if (! open(CF, ">$new_domain_cf")) {
  3490.         Exit(1, "Could not create: $new_domain_cf: $!\n");
  3491.     }
  3492.     print CF @cfdata;
  3493.     close(CF);
  3494.     Log(0, "Created $new_domain_cf.\n");
  3495.     UninstallLog("Remove(\"$new_domain_cf\");\n");
  3496. }    # InstallDefaultConfigs
  3497.  
  3498.  
  3499.  
  3500.  
  3501. sub InstallFile
  3502. {
  3503.     my ($srcfile, $dstdir, $dstmode, $dstuid, $dstgid) = @_;
  3504.     my ($srcpath, $dstpath, $dstfile);
  3505.  
  3506.     $dstfile = $srcfile;
  3507.     $dstfile =~ s-^.*/--;
  3508.     $srcpath = "$install_src_root/$srcfile";
  3509.     $dstpath = "$dstdir/$dstfile";
  3510.  
  3511.     my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) =     
  3512.         stat($srcpath);
  3513.     if (! defined($mode)) {
  3514.         Exit(1, "ERROR: Could not stat $srcpath: $!\n");
  3515.         return (0);
  3516.     }
  3517.  
  3518.     $dstmode = $mode unless defined($dstmode);
  3519.     $dstuid = $uid unless defined($dstuid);
  3520.     $dstgid = $gid unless defined($dstgid);
  3521.  
  3522.     SafeRenameWithNcVersion($dstpath);
  3523.     if (! copy($srcpath, $dstpath)) {
  3524.         Exit(1, "ERROR: Could not copy $srcpath to $dstpath: $!\n");
  3525.         return (0);
  3526.     }
  3527.     chmod($dstmode, $dstpath);
  3528.     chown($dstuid, $dstgid, $dstpath);
  3529.     utime($atime, $mtime, $dstpath);
  3530.  
  3531.     UninstallLog("Remove(\"$dstpath\");\n");
  3532.     Log(1, "Installed $dstpath.\n");
  3533.     return (1);
  3534. }    # InstallFile
  3535.  
  3536.  
  3537.  
  3538.  
  3539. sub Symlink
  3540. {
  3541.     my ($srcpath, $dstpath, $force) = @_;
  3542.  
  3543.     if ((-l $dstpath) || (-e $dstpath)) {
  3544.         if ($force eq "overwrite") {
  3545.             if (! unlink($dstpath)) {
  3546.                 Log(1, "Could not remove existing $dstpath: $!\n");
  3547.                 # But keep going
  3548.             }
  3549.         } elsif ($force eq "rename") {
  3550.             return 0 if (SafeRenameWithNcVersion($dstpath) eq "");
  3551.         } else {
  3552.             Log(1, "Warning: could not link $srcpath -> $dstpath: $dstpath already exists\n");
  3553.             return 0;
  3554.         }
  3555.     }
  3556.     if (! symlink($srcpath, $dstpath)) {
  3557.         Log(0, "Warning: could not link $srcpath -> $dstpath: $!\n");
  3558.         return 0;
  3559.     } else {
  3560.         Log(1, "  Linked $srcpath -> $dstpath.\n");
  3561.         UninstallLog("Remove(\"$dstpath\");\n");
  3562.     }
  3563.     return 1;
  3564. }    # Symlink
  3565.  
  3566.  
  3567.  
  3568. sub InstallConfigs
  3569. {
  3570.     my ($oldg, $oldd);
  3571.  
  3572.     Log(0, "Installing configuration files.\n");
  3573.     $oldg = SafeRenameWithNcVersion($new_general_cf);
  3574.     $oldd = SafeRenameWithNcVersion($new_domain_cf);
  3575.     if (($oldg ne "") && ($oldd ne "") && (! $create_new_configs)) {
  3576.         if (! copy($oldg, $new_general_cf)) {
  3577.             Log(0, "ERROR: Could not copy $oldg to $new_general_cf: $!\n");
  3578.         } else {
  3579.             UninstallLog("Rename(\"$oldg\", \"$new_general_cf\");\n");
  3580.         }
  3581.         if ($webgid != (-1)) {
  3582.             chmod(0640, $new_general_cf);
  3583.             chown(0, $webgid, $new_general_cf);
  3584.         } else {
  3585.             chmod(0600, $new_general_cf);
  3586.             chown(0, 0, $new_general_cf);
  3587.         }
  3588.  
  3589.         if (! copy($oldd, $new_domain_cf)) {
  3590.             Log(0, "ERROR: Could not copy $oldd to $new_domain_cf: $!\n");
  3591.         } else {
  3592.             UninstallLog("Rename(\"$oldd\", \"$new_domain_cf\");\n");
  3593.         }
  3594.         if ($webgid != (-1)) {
  3595.             chmod(0640, $new_domain_cf);
  3596.             chown(0, $webgid, $new_domain_cf);
  3597.         } else {
  3598.             chmod(0600, $new_domain_cf);
  3599.             chown(0, 0, $new_domain_cf);
  3600.         }
  3601.         if ((-f $new_general_cf) && (-f $new_domain_cf)) {
  3602.             Log(1, "Using copies of existing NcFTPd config files.\n");
  3603.             return;
  3604.         }
  3605.         Log(0, "Existing NcFTPd config files could not be copied.\n");
  3606.     }
  3607.  
  3608.     InstallDefaultConfigs();
  3609. }    # InstallConfigs
  3610.  
  3611.  
  3612.  
  3613.  
  3614. sub InstallPrograms
  3615. {
  3616.     my ($binuid, $bingid);
  3617.     my ($name,$passwd,$uid,$gid,$quota,$comment,$gcos,$dir,$shell,$expire);
  3618.  
  3619.     $binuid = 0;
  3620.     $bingid = 0;
  3621.  
  3622.     ($name,$passwd,$uid,$gid,$quota,$comment,$gcos,$dir,$shell,$expire) = 
  3623.         getpwnam("bin");
  3624.     if (defined($uid)) {
  3625.         $binuid = $uid;
  3626.         $bingid = $gid;
  3627.     }
  3628.  
  3629.     Log(0, "Installing programs.\n");
  3630.     InstallFile("ncftpd", $sbindir, 0751, $binuid, $bingid);
  3631.     InstallFile("ncftpd_spy", $sbindir, 0700, $binuid, $bingid);
  3632.     InstallFile("ncftpd_passwd", $sbindir, 0751, $binuid, $bingid);
  3633.     InstallFile("ncftpd_edquota", $sbindir, 0751, $binuid, $bingid);
  3634.     InstallFile("ncftpd_repquota", $sbindir, 0751, $binuid, $bingid);
  3635.     InstallFile("extra/pgrep.pl", $bindir, 0755, $binuid, $bingid);
  3636.     Symlink("$bindir/pgrep.pl", "$bindir/pkill.pl", "overwrite");
  3637.     InstallFile("extra/uninstall_ncftpd.pl", $confdir, 0700, 0, $bingid);
  3638.     $uninstaller = "$confdir/uninstall_ncftpd.pl";
  3639. }    # InstallPrograms
  3640.  
  3641.  
  3642.  
  3643.  
  3644. sub InstallStartupScript
  3645. {
  3646.     my (@initscript);
  3647.     my (@inittabscript);
  3648.     my (@startupitemscript);
  3649.     my ($initscriptpath);
  3650.     my ($inittabscriptpath);
  3651.     my ($inittabscript_redirect);
  3652.     my ($runlevels);
  3653.     my ($rc_local);
  3654.     my ($rc_local_already);
  3655.     my ($line, $nlines);
  3656.     my ($rc_link, @rc_links);
  3657.     my ($var, $val, %vars, $newval);
  3658.     my ($insserv);
  3659.  
  3660.     Log(0, "Configuring your system so NcFTPd starts automatically at system boot.\n");
  3661.     if (! open(SCRIPT, "<$install_src_root/extra/ncftpd.init")) {
  3662.         Exit(1, "Could not open $install_src_root/extra/ncftpd.init: $!\n");
  3663.     }
  3664.     @initscript = <SCRIPT>;
  3665.     close(SCRIPT);
  3666.  
  3667.     if (! open(SCRIPT, "<$install_src_root/extra/ncftpd.sh")) {
  3668.         Exit(1, "Could not open $install_src_root/extra/ncftpd.sh: $!\n");
  3669.     }
  3670.     @inittabscript = <SCRIPT>;
  3671.     close(SCRIPT);
  3672.  
  3673.     %vars = ();
  3674.     $vars{"NCFTPD_PREFIX"} = $prefix;
  3675.     $vars{"NCFTPD_GENERAL_CF"} = $new_general_cf;
  3676.     $vars{"NCFTPD_DOMAIN_CF"} = $new_domain_cf;
  3677.     $vars{"NCFTPD_STARTUP_ERROR_LOG"} = $startup_error_log;
  3678.     $vars{"NCFTPD_PROG_PATH"} = "$sbindir:$bindir:\$PATH";
  3679.     $vars{"NCFTPD_PROG"} = "$new_ncftpd";
  3680.     if ($run_ncftpd_verbose > 0) {
  3681.         $val = "-v";
  3682.         $val = "-vv" if ($run_ncftpd_verbose == 2);
  3683.         $val = "-vvv" if ($run_ncftpd_verbose == 3);
  3684.         $vars{"NCFTPD_VERBOSITY"} = "$val";
  3685.     }
  3686.  
  3687.     $nlines = 0;
  3688.     foreach $line (@initscript) {
  3689.         $nlines++;
  3690.         if (($nlines == 1) && ($linux_distro eq "SuSE") && ($linux_distro_version_num > 7)) {
  3691.             $line .= "#\n";
  3692.             $line .= "### BEGIN INIT INFO\n";
  3693.             $line .= "# Provides: ncftpd\n";
  3694.             $line .= "# Required-Start: \$network \$remote_fs \$syslog \$named\n";
  3695.             $line .= "# Required-Stop: \$network \$remote_fs \$syslog \$named\n";
  3696.             $line .= "# Default-Start: 3 5\n";
  3697.             $line .= "# Default-Stop: 0 1 2 6\n";
  3698.             $line .= "# Short-Description: NcFTPd FTP Server\n";
  3699.             $line .= "# Description: NcFTPd File Transfer Protocol (FTP) server daemon\n";
  3700.             $line .= "#\tSee the online documentation at http://www.ncftp.com/ncftpd/doc/\n";
  3701.             $line .= "### END INIT INFO\n";
  3702.             $line .= "#\n";
  3703.         } elsif (($nlines == 1) && (-f "/sbin/chkconfig")) {
  3704.             $line .= "#\n";
  3705.             $line .= "# chkconfig: 345 85 15\n";
  3706.             $line .= "# description: Starts and stops NcFTPd (FTP) service\n";
  3707.             $line .= "# processname: ncftpd\n";
  3708.             $line .= "# config: $new_general_cf\n";
  3709.             $line .= "# config: $new_domain_cf\n";
  3710.             $line .= "#\n";
  3711.         }
  3712.         for $var (keys %vars) {
  3713.             if ($line =~ /^\s*$var\=\"?([^\"]*)\"?/) {
  3714.                 $val = $1;
  3715.                 $newval = $vars{$var};
  3716.                 if ($newval ne $val) {
  3717.                     chomp($line);
  3718.                     $line = "#Configured by install_ncftpd.pl# $line\n";
  3719.                     $line .= "$var=\"$newval\"\n";
  3720.                 }
  3721.             }
  3722.         }
  3723.         if ($line =~ /#SOURCE\-RC/) {
  3724.             if ($SYS eq "hpux") {
  3725.                 $line = "PATH=/usr/sbin:/sbin:/bin:/usr/bin\nexport PATH\n";
  3726.             } elsif ($SYS eq "linux") {
  3727.                 if (($linux_distro eq "SuSE") && ($linux_distro_version_num > 7)) {
  3728.                     $line = ". /etc/rc.status\n\n";
  3729.                     $line .= "# Reset status of this service\n";
  3730.                     $line .= "rc_reset\n\n";
  3731.                 } elsif ($linux_distro eq "SuSE") {
  3732.                     $line = ". /etc/rc.config\n";
  3733.                 } else {
  3734.                     $line = "";
  3735.                     if (-f "/etc/sysconfig/network") {
  3736.                         if (-f "/etc/init.d/functions") {
  3737.                             $line .= "# Source function library.\n";
  3738.                             $line .= ". /etc/init.d/functions\n";
  3739.                             $line .= "\n";
  3740.                         } elsif (-f "/etc/rc.d/init.d/functions") {
  3741.                             $line .= "# Source function library.\n";
  3742.                             $line .= ". /etc/rc.d/init.d/functions\n";
  3743.                             $line .= "\n";
  3744.                         }
  3745.                         if (-f "/etc/sysconfig/network") {
  3746.                             $line .= "# Get config.\n";
  3747.                             $line .= ". /etc/sysconfig/network\n";
  3748.                             $line .= "\n";
  3749.                             $line .= "# Check that networking is up.\n";
  3750.                             $line .= "if [ \"X\${NETWORKING}\" = \"Xno\" ]\n";
  3751.                             $line .= "then\n";
  3752.                             $line .= "    exit 0\n";
  3753.                             $line .= "fi\n";
  3754.                             $line .= "\n";
  3755.                         }
  3756.                     }
  3757.                 }
  3758.             } else {
  3759.                 $line = "";
  3760.             }
  3761.         } elsif ($line =~ /^PKILL\=/) {
  3762.             if (-x "/usr/bin/pkill") {
  3763.                 $line = "PKILL=\"/usr/bin/pkill\"\n";
  3764.             } else {
  3765.                 $line = "PKILL=\"${bindir}/pkill.pl\"\n";
  3766.             }
  3767.         } elsif ($line =~ /^PGREP\=/) {
  3768.             if (-x "/usr/bin/pgrep") {
  3769.                 $line = "PGREP=\"/usr/bin/pgrep\"\n";
  3770.             } else {
  3771.                 $line = "PGREP=\"${bindir}/pgrep.pl\"\n";
  3772.             }
  3773.         } elsif ($line =~ /ECHO\-N/) {
  3774.             chomp($line);
  3775.             $line =~ s/\s*#\s*ECHO.*$//;
  3776.             if ($SYS =~ /(aix|hpux|solaris)/) {
  3777.                 $line =~ s/echo\s\-n/echo/;
  3778.                 $line .= "\'\\c\'";
  3779.             }
  3780.             $line .= "\n";
  3781.         } elsif ($line =~ /ECHO\-E/) {
  3782.             chomp($line);
  3783.             if (($linux_distro eq "SuSE") && ($linux_distro_version_num > 7)) {
  3784.                 if ($line =~ /rc_done/) {
  3785.                     $line =~ s/echo.*/rc_status -v/;
  3786.                 } elsif ($line =~ /rc_failed/) {
  3787.                     $line =~ s/echo.*/rc_failed \"\$es\"/;
  3788.                 }
  3789.             }
  3790.             $line =~ s/\s*#\s*ECHO.*$//;
  3791.             unless ($SYS eq "linux") {
  3792.                 $line =~ s/echo\s\-e/echo/;
  3793.             }
  3794.             $line .= "\n";
  3795.         } elsif ($line =~ /EXIT/) {
  3796.             if (($linux_distro eq "SuSE") && ($linux_distro_version_num > 7)) {
  3797.                 $line =~ s/exit.*/rc_exit/;
  3798.             }
  3799.         } elsif ($line =~ /#\s*Successfully\s*backgrounded/) {
  3800.             if ($SYS eq "hpux") {
  3801.                 $line .= "\t\t\tes=4    # HP-UX rc script exit status for backgrounding\n";
  3802.             }
  3803.         } elsif ($line =~ /^#EXTRA/) {
  3804.             $line = "";
  3805.             if ($SYS eq "hpux") {
  3806.                 $line .= "\n";
  3807.                 $line .= "\'start_msg\')\n";
  3808.                 $line .= "    echo \'Start NcFTPd\'\n";
  3809.                 $line .= "    es=0\n";
  3810.                 $line .= "    ;;\n";
  3811.                 $line .= "\n";
  3812.                 $line .= "\'stop_msg\')\n";
  3813.                 $line .= "    echo \'Stopping NcFTPd\'\n";
  3814.                 $line .= "    es=0\n";
  3815.                 $line .= "    ;;\n";
  3816.             }
  3817.         }
  3818.     }
  3819.  
  3820.     foreach $line (@inittabscript) {
  3821.         for $var (keys %vars) {
  3822.             if ($line =~ /^\s*$var\=\"?([^\"]*)\"?/) {
  3823.                 $val = $1;
  3824.                 $newval = $vars{$var};
  3825.                 if ($newval ne $val) {
  3826.                     chomp($line);
  3827.                     $line = "#Configured by install_ncftpd.pl# $line\n";
  3828.                     $line .= "$var=\"$newval\"\n";
  3829.                 }
  3830.             }
  3831.         }
  3832.     }
  3833.  
  3834.     @rc_links = ();
  3835.     $initscriptpath = "";
  3836.     $inittabscriptpath = "";
  3837.     $rc_local = "";
  3838.     $rc_local_already = 0;
  3839.     $runlevels = "2345";
  3840.     $inittabscript_redirect = "";
  3841.     $insserv = "";
  3842.  
  3843.     if ((-f "/etc/insserv.conf") && (-d "/etc/init.d"))  {
  3844.         # insserv is used by SuSE 10
  3845.         if (-x "/sbin/insserv") {
  3846.             $insserv = "/sbin/insserv";
  3847.         } elsif (-x "/usr/sbin/insserv") {
  3848.             $insserv = "/usr/sbin/insserv";
  3849.         }
  3850.     }
  3851.  
  3852.     if ($insserv ne "") {
  3853.         @rc_links = ();
  3854.         # Note: We use "NcFTPd" rather than "ncftpd" for the
  3855.         # initscript name, so that we can do a "pkill -x ncftpd"
  3856.         # and not terminate the initscript.
  3857.         #
  3858.         $initscriptpath = "/etc/init.d/NcFTPd";
  3859.     } elsif ($SYS eq "linux") {
  3860.         if ($linux_distro eq "SuSE") {
  3861.             if ($linux_distro_version_num > 7) {
  3862.                 # SuSE 8.x
  3863.                 @rc_links = (
  3864.                     "/etc/init.d/rc2.d/S21ncftpd",
  3865.                     "/etc/init.d/rc2.d/K21ncftpd",
  3866.                     "/etc/init.d/rc3.d/S21ncftpd",
  3867.                     "/etc/init.d/rc3.d/K21ncftpd",
  3868.                     "/etc/init.d/rc5.d/S21ncftpd",
  3869.                     "/etc/init.d/rc5.d/K21ncftpd",
  3870.                 );
  3871.                 $initscriptpath = "/etc/init.d/NcFTPd";
  3872.             } elsif (-d "/etc/init.d") {
  3873.                 if (-d "/etc/rc2.d") {
  3874.                     # ??
  3875.                     @rc_links = (
  3876.                         "/etc/rc2.d/S21ncftpd",
  3877.                         "/etc/rc2.d/K21ncftpd",
  3878.                         "/etc/rc3.d/S21ncftpd",
  3879.                         "/etc/rc3.d/K21ncftpd",
  3880.                     );
  3881.                 } else {
  3882.                     # SuSE 7.x
  3883.                     @rc_links = (
  3884.                         "/etc/init.d/rc2.d/S21ncftpd",
  3885.                         "/etc/init.d/rc2.d/K21ncftpd",
  3886.                         "/etc/init.d/rc3.d/S21ncftpd",
  3887.                         "/etc/init.d/rc3.d/K21ncftpd",
  3888.                     );
  3889.                 }
  3890.                 $initscriptpath = "/etc/init.d/NcFTPd";
  3891.             } else {
  3892.                 # SuSE 6.x
  3893.                 @rc_links = (
  3894.                     "/sbin/init.d/rc2.d/S21ncftpd",
  3895.                     "/sbin/init.d/rc2.d/K21ncftpd",
  3896.                     "/sbin/init.d/rc3.d/S21ncftpd",
  3897.                     "/sbin/init.d/rc3.d/K21ncftpd",
  3898.                 );
  3899.                 $initscriptpath = "/sbin/init.d/NcFTPd";
  3900.             }
  3901.         } elsif ($linux_distro =~ /(Red\ Hat|Mandrake|Mandriva|Conectiva|TurboLinux|Caldera|Cobalt|LinuxPPC|Fedora\ Core)/) {
  3902.  
  3903.             if (-d "/etc/rc2.d") {
  3904.                 @rc_links = (
  3905.                     "/etc/rc2.d/S85ncftpd",
  3906.                     "/etc/rc3.d/S85ncftpd",
  3907.                     "/etc/rc5.d/S85ncftpd",
  3908.                 );
  3909.             } else {
  3910.                 @rc_links = (
  3911.                     "/etc/rc.d/rc2.d/S85ncftpd",
  3912.                     "/etc/rc.d/rc3.d/S85ncftpd",
  3913.                     "/etc/rc.d/rc5.d/S85ncftpd",
  3914.                 );
  3915.             }
  3916.             if ((-d "/etc/init.d") && (! -d "/etc/rc.d/init.d")) {
  3917.                 $initscriptpath = "/etc/init.d/NcFTPd";
  3918.             } else {
  3919.                 $initscriptpath = "/etc/rc.d/init.d/NcFTPd";
  3920.             }
  3921.         } elsif ($linux_distro eq "Slackware") {
  3922.             $initscriptpath = "/etc/rc.d/rc.ncftpd";
  3923.             $rc_local = "/etc/rc.d/rc.local";
  3924.         } elsif ($linux_distro_class eq "Debian") {
  3925.             @rc_links = (
  3926.                 "/etc/rc0.d/K21ncftpd",
  3927.                 "/etc/rc1.d/K21ncftpd",
  3928.                 "/etc/rc2.d/S21ncftpd",
  3929.                 "/etc/rc3.d/S21ncftpd",
  3930.                 "/etc/rc4.d/S21ncftpd",
  3931.                 "/etc/rc5.d/S21ncftpd",
  3932.                 "/etc/rc6.d/K21ncftpd",
  3933.                 "/etc/rcS.d/K21ncftpd",
  3934.             );
  3935.             $initscriptpath = "/etc/init.d/NcFTPd";
  3936.         } else {
  3937.             Log(0, "This script has not been customized for your Linux distribution.\n");
  3938.             if (-f "/etc/inittab") {
  3939.                 $inittabscriptpath = "$confdir/ncftpd.inittab.sh";
  3940.                 Log(0, "  NcFTPd will be installed into the /etc/inittab, rather than use an rc script,\n");
  3941.                 Log(0, "  which should work OK.\n");
  3942.             } else {
  3943.                 $initscriptpath = "$confdir/ncftpd.init";
  3944.                 Log(0, "  You will need to manually install a startup script so NcFTPd will be\n");
  3945.                 Log(0, "  automatically started at boot time.  A sample startup script will be\n");
  3946.                 Log(0, "  installed as $initscriptpath.\n");
  3947.                 Log(0, "  If your system uses rc.d directories, you can simply create symbolic links\n");
  3948.                 Log(0, "  to $initscriptpath, otherwise you can\n");
  3949.                 Log(0, "  check to see if there is an \"rc.local\" script you can use to run\n");
  3950.                 Log(0, "  $initscriptpath.\n");
  3951.             }
  3952.         }
  3953.     } elsif ($SYS eq "freebsd") {
  3954.         if (-d "/usr/local/etc/rc.d") {
  3955.             $initscriptpath = "/usr/local/etc/rc.d/ncftpd.sh";
  3956.         } else {
  3957.             $initscriptpath = "/etc/rc.ncftpd";
  3958.             $rc_local = "/etc/rc.local";
  3959.         }
  3960.     } elsif ($SYS eq "macosx") {
  3961.         #
  3962.         # Special setup for Mac OS X.
  3963.         # OS X uses a non-traditional way to run startup scripts.
  3964.         #
  3965.         # We simply choose to extract a pre-built tar which creates
  3966.         # the startup scripts in /System/Library/StartupItems.
  3967.         #
  3968.         if ($verbose > 1) {
  3969.             Log(1, "/usr/bin/tar -x -C / -vpf \"$install_src_root/extra/osx_supplement.tar\"\n");
  3970.             system("/usr/bin/tar", "-x", "-C", "/", "-vpf", "$install_src_root/extra/osx_supplement.tar");
  3971.         } else {
  3972.             system("/usr/bin/tar", "-x", "-C", "/", "-pf", "$install_src_root/extra/osx_supplement.tar");
  3973.         }
  3974.  
  3975.         if (! open(SCRIPT, "</System/Library/StartupItems/NcFTPd/NcFTPd")) {
  3976.             Exit(1, "Could not open /System/Library/StartupItems/NcFTPd/NcFTPd: $!\n");
  3977.         }
  3978.         @startupitemscript = <SCRIPT>;
  3979.         close(SCRIPT);
  3980.         UninstallLog("Remove(\"/System/Library/StartupItems/NcFTPd/NcFTPd\");\n");
  3981.         UninstallLog("Remove(\"/System/Library/StartupItems/NcFTPd/StartupParameters.plist\");\n");
  3982.         UninstallLog("Rmdir(\"/System/Library/StartupItems/NcFTPd\");\n");
  3983.  
  3984.         foreach $line (@startupitemscript) {
  3985.             for $var (keys %vars) {
  3986.                 if ($line =~ /^\s*$var\=\"?([^\"]*)\"?/) {
  3987.                     $val = $1;
  3988.                     $newval = $vars{$var};
  3989.                     if ($newval ne $val) {
  3990.                         chomp($line);
  3991.                         $line = "    $var=\"$newval\"\t# from install_ncftpd.pl\n";
  3992.                     }
  3993.                 }
  3994.             }
  3995.         }
  3996.  
  3997.         if (! open(SCRIPT, ">/System/Library/StartupItems/NcFTPd/NcFTPd")) {
  3998.             Exit(1, "Could not rewrite /System/Library/StartupItems/NcFTPd/NcFTPd: $!\n");
  3999.         }
  4000.         print SCRIPT @startupitemscript;
  4001.         close(SCRIPT);
  4002.  
  4003.         #
  4004.         # But copy the standard init script to a suitable location,
  4005.         # so they can use it to restart NcFTPd.
  4006.         #
  4007.         $initscriptpath = "$sbindir/ncftpd.init";
  4008.     } elsif ($SYS eq "sco") {
  4009.         @rc_links = (
  4010.             "/etc/rc2.d/S92ncftpd",
  4011.         );
  4012.         $initscriptpath = "/etc/init.d/NcFTPd";
  4013.     } elsif (($SYS eq "unixware") || ($SYS eq "openunix")) {
  4014.         @rc_links = (
  4015.             "/etc/rc2.d/S75ncftpd",
  4016.         );
  4017.         $initscriptpath = "/etc/init.d/NcFTPd";
  4018.     } elsif ($SYS eq "aix") {
  4019.         $inittabscriptpath = "/etc/rc.ncftpd";
  4020.         $inittabscript_redirect = ' >/dev/console 2>&1';
  4021.         $runlevels = "2";
  4022.     } elsif ($SYS eq "solaris") {
  4023.         @rc_links = (
  4024.             "/etc/rc2.d/S75ncftpd",
  4025.         );
  4026.         $initscriptpath = "/etc/init.d/NcFTPd";
  4027.     } elsif ($SYS =~ /^irix/) {
  4028.         @rc_links = (
  4029.             "/etc/rc2.d/S65ncftpd",
  4030.         );
  4031.         $initscriptpath = "/etc/init.d/NcFTPd";
  4032.     } elsif ($SYS eq "tru64unix") {
  4033.         @rc_links = (
  4034.             "/sbin/rc0.d/K62ncftpd",
  4035.             "/sbin/rc2.d/K62ncftpd",
  4036.             "/sbin/rc3.d/S62ncftpd",
  4037.         );
  4038.         $initscriptpath = "/sbin/init.d/NcFTPd";
  4039.     } elsif ($SYS =~ /(openbsd|netbsd|bsdos|sunos)/) {
  4040.         $initscriptpath = "/etc/rc.ncftpd";
  4041.         $rc_local = "/etc/rc.local";
  4042.     } elsif ($SYS eq "hpux") {
  4043.         @rc_links = (
  4044.             "/sbin/rc1.d/K517ncftpd",
  4045.             "/sbin/rc2.d/S517ncftpd",
  4046.         );
  4047.         $initscriptpath = "/sbin/init.d/NcFTPd";
  4048.     } elsif (-f "/etc/inittab") {
  4049.         $inittab_preferred = 1;
  4050.         Log(0, "Warning: Unknown system type ($SYS)!  Startup script was not installed.\n");
  4051.         Log(0, "         NcFTPd will be run from the /etc/inittab instead.\n");
  4052.     } elsif (-f "/etc/rc.local") {
  4053.         $initscriptpath = "/etc/rc.ncftpd";
  4054.         $rc_local = "/etc/rc.local";
  4055.         Log(0, "Warning: Unknown system type ($SYS)!  Startup script was not installed.\n");
  4056.         Log(0, "         NcFTPd will be run from the /etc/rc.local instead.\n");
  4057.     } else {
  4058.         Log(0, "ERROR: Unknown system type ($SYS)!  Startup script was not installed.\n");
  4059.         Log(0, "       You will need to start NcFTPd manually and arrange for it to be\n");
  4060.         Log(0, "       started when the system boots.\n");
  4061.         return;
  4062.     }
  4063.  
  4064.     if ($inittab_preferred) {
  4065.         $inittabscriptpath = "$confdir/ncftpd.inittab.sh";
  4066.         if ($initscriptpath ne "") {
  4067.             Log(1, "Using $inittabscriptpath instead of $initscriptpath.\n");
  4068.         }
  4069.     }
  4070.  
  4071.     if ($inittabscriptpath ne "") {
  4072.         SafeRenameWithNcVersion($inittabscriptpath);
  4073.         if (! open(SCRIPT, ">$inittabscriptpath")) {
  4074.             Exit(1, "Could not create $inittabscriptpath: $!\n");
  4075.         } else {
  4076.             print SCRIPT @inittabscript;
  4077.             close(SCRIPT);
  4078.         }
  4079.         chmod(0755, $inittabscriptpath);
  4080.         Log(0, "Installed $inittabscriptpath.\n");
  4081.         UninstallLog("Remove(\"$inittabscriptpath\");\n");
  4082.  
  4083.         unlink("$sbindir/restart_ncftpd");
  4084.         if (open(RESTARTSCRIPT, ">$sbindir/restart_ncftpd")) {
  4085.             print RESTARTSCRIPT "#!/bin/sh\n";
  4086.             print RESTARTSCRIPT "NCFTPD_STOP_SCRIPT=\`grep \'^pid-file\' \"$new_general_cf\" \| cut -d= -f2\`\n";
  4087.             print RESTARTSCRIPT "if [ -x \"\$NCFTPD_STOP_SCRIPT\" ] ; then\n";
  4088.             print RESTARTSCRIPT "        echo \'Restarting NcFTPd.\'\n";
  4089.             print RESTARTSCRIPT "        /bin/sh \"\$NCFTPD_STOP_SCRIPT\"\n";
  4090.             print RESTARTSCRIPT "        exit 0\n";
  4091.             print RESTARTSCRIPT "fi\n";
  4092.             print RESTARTSCRIPT "exit 1\n";
  4093.             close(RESTARTSCRIPT);
  4094.             chmod(0700, "$sbindir/restart_ncftpd");
  4095.             Log(0, "Created $sbindir/restart_ncftpd.\n");
  4096.             UninstallLog("Remove(\"$sbindir/restart_ncftpd\");\n");
  4097.         }
  4098.  
  4099.         #
  4100.         # Now add our entry to the /etc/inittab.
  4101.         # When we "init q", NcFTPd will start up.
  4102.         #
  4103.         if (open(ETCINITTAB, ">>/etc/inittab")) {
  4104.             print ETCINITTAB "#\n# Added by install_ncftpd.pl\n#\n";
  4105.             print ETCINITTAB "nc:$runlevels:respawn:$inittabscriptpath$inittabscript_redirect\n";
  4106.             close(ETCINITTAB);
  4107.             Log(1, "Added entry to /etc/inittab.\n");
  4108.             UninstallLog("RemoveInittabEntry(\"nc:$runlevels:respawn:$inittabscriptpath$inittabscript_redirect\");\n");
  4109.         }
  4110.         $inittab_startup_script = $inittabscriptpath;
  4111.     } elsif ($initscriptpath ne "") {
  4112.         SafeRenameWithNcVersion($initscriptpath);
  4113.         if (! open(SCRIPT, ">$initscriptpath")) {
  4114.             Exit(1, "Could not create $initscriptpath: $!\n");
  4115.         } else {
  4116.             print SCRIPT @initscript;
  4117.             close(SCRIPT);
  4118.         }
  4119.         chmod(0755, $initscriptpath);
  4120.         Log(1, "Installed $initscriptpath.\n");
  4121.         UninstallLog("Remove(\"$initscriptpath\");\n");
  4122.  
  4123.         push(@rc_links, "$sbindir/restart_ncftpd");
  4124.         push(@rc_links, "$sbindir/stop_ncftpd");
  4125.         for $rc_link (@rc_links) {
  4126.             Symlink($initscriptpath, $rc_link, "overwrite");
  4127.         }
  4128.         $rc_startup_script = $initscriptpath;
  4129.  
  4130.         if ($insserv ne "") {
  4131.             Log(1, "Running $insserv to activate startup script in rc.d directories.\n");
  4132.             system($insserv, "NcFTPd"); # Assumes it works...
  4133.             UninstallLog("system(\"$insserv\", \"-r\", \"NcFTPd\");\n");
  4134.         }
  4135.     }
  4136.  
  4137.     if (($rc_local ne "") && ($rc_startup_script ne "")) {
  4138.         if (open(RCLOCAL, "<$rc_local")) {
  4139.             while (defined($line = <RCLOCAL>)) {
  4140.                 if ($line =~ /^[^#]*$rc_startup_script/) {
  4141.                     $rc_local_already++;
  4142.                     Log(1, "Already found $rc_startup_script in $rc_local.\n");
  4143.                     last;
  4144.                 }
  4145.             }
  4146.             close(RCLOCAL);
  4147.         }
  4148.         if (($rc_local_already == 0) && (open(RCLOCAL, ">>$rc_local"))) {
  4149.             if (($SYS eq "freebsd") && (! -s $rc_local)) {
  4150.                 print RCLOCAL "#!/bin/sh\n\n. /etc/rc.conf\n\n";
  4151.             }
  4152.             print RCLOCAL "#\n# Added by install_ncftpd.pl\n#\n";
  4153.             print RCLOCAL "$rc_startup_script start\n";
  4154.             close(RCLOCAL);
  4155.             chmod(0755, $rc_local);
  4156.             Log(1, "Added entry to $rc_local.\n");
  4157.             UninstallLog("RemoveRcLocalEntry(\"$rc_local\", \"$rc_startup_script start\");\n");
  4158.         }
  4159.     }
  4160. }    # InstallStartupScript
  4161.  
  4162.  
  4163.  
  4164.  
  4165. sub StartNcFTPd
  4166. {
  4167.     if ($rc_startup_script ne "") {
  4168.         Log(1, "  /bin/sh $rc_startup_script start\n");
  4169.         # This will echo "Starting NcFTPd:"
  4170.         system("/bin/sh", $rc_startup_script, "start");
  4171.         UninstallLog("KillFTPd(\"ncftpd\");\n");
  4172.     } elsif ($inittab_startup_script ne "") {
  4173.         my ($init) = SearchPath("init", "/sbin:/usr/sbin:/usr/bin:/bin");
  4174.         $init = "init" unless ($init);
  4175.         Log(0, "Running \"$init q\" to reload modified /etc/inittab.\n");
  4176.         system($init, "q");
  4177.         Log(0, "Starting NcFTPd.\n");
  4178.     }
  4179.     sleep(3);
  4180. }    # StartNcFTPd
  4181.  
  4182.  
  4183.  
  4184.  
  4185. sub NcFTPdShouldNowBeRunning
  4186. {
  4187.     if (! WaitForFTPServerToStart()) {
  4188.         Log(0, "\nERROR: NcFTPd did not startup.\n\n");
  4189.         if (open(ERRLOG, "<$startup_error_log")) {
  4190.             my ($line);
  4191.             while (defined($line = <ERRLOG>)) {
  4192.                 Log(0, $line);
  4193.             }
  4194.         }
  4195.         Exit(1);
  4196.     }
  4197.  
  4198.     Log(0, "\nCONGRATULATIONS!  NcFTPd has been successfully installed.\n");
  4199.     Log(0, "Your next step is to customize your installation by editing:\n\n");
  4200.     Log(0, "  $new_general_cf\n");
  4201.     Log(0, "  $new_domain_cf\n");
  4202.     Log(0, "\nBe sure to run $sbindir/restart_ncftpd after doing that.\n");
  4203. }    # NcFTPdShouldNowBeRunning
  4204.  
  4205.  
  4206.  
  4207.  
  4208. sub Main
  4209. {
  4210.     umask(077);
  4211.     OpenLog();
  4212. #    OpenPager();
  4213.     SetOSVar();
  4214.     Getopts();
  4215.     SetOSDefaults();
  4216.     if (($> != 0) && (! $force_install)) {
  4217.         Exit(1, "You need to be Superuser to install NcFTPd.  You are UID ", $>, ".\n");
  4218.     }
  4219.  
  4220.     VerifyOSPrerequisites();
  4221.     SetPATHEnvironmentVar( VerifyLocation() );
  4222.     FindPerl();
  4223.     VerifyPackageContents();
  4224.     VerifyFreeSpace();
  4225.     LookupFTPServiceName();
  4226.     AbortIfSomethingWeDontKnowHowToDisableIsUsingPort21();
  4227.     KillFTPd("ftpd|in.ftpd|wu\-?ftpd|proftpd");
  4228.     CreateEtcShells();
  4229.     CreateEtcFtpusers();
  4230.     AddFTPGroup();
  4231.     AddFTPUser();
  4232.     CreateFTPHome();
  4233.     IsThereAnFTPServerServing(0);
  4234.     DisableInetdHandlingOfFTP();
  4235.     DisableExistingFTPServersRunningFromInittab();    # Includes NcFTPd in /etc/inittab.
  4236.     DisableExistingNcFTPd();
  4237.     CheckIfSomeOtherFTPServerIsStillRunning();
  4238.     DisableRcScripts();
  4239.     NoteExistingNcFTPdVersion();
  4240.     LookupWebUser();
  4241.     MkInstallDirs();
  4242.     FixScript("extra/pgrep.pl", "#!${perl} -w");
  4243.     FixReportScripts();
  4244.     RemoveFtpFromEtcFtpusers();
  4245.     InstallConfigs();
  4246.     InstallPrograms();
  4247.     InstallStartupScript();
  4248.     StartNcFTPd();
  4249.     NcFTPdShouldNowBeRunning();
  4250.     Exit(0);
  4251. }    # Main
  4252.  
  4253. Main();
  4254.