head	1.8;
access;
symbols;
locks
	root:1.8; strict;
comment	@# @;


1.8
date	95.08.21.22.36.13;	author tobias;	state Exp;
branches;
next	1.7;

1.7
date	95.08.20.21.55.01;	author tobias;	state Exp;
branches;
next	1.6;

1.6
date	95.08.05.21.21.05;	author tobias;	state Exp;
branches;
next	1.5;

1.5
date	95.08.05.21.10.36;	author tobias;	state Exp;
branches;
next	1.4;

1.4
date	95.08.05.21.08.56;	author tobias;	state Exp;
branches;
next	;


desc
@A utility to create an anonymous FTP account
@


1.8
log
@don't ask silly questions if you already have an ftp user
@
text
@#!/usr/bin/perl
#
# addftpuser: a utility to create an anonymous FTP account
#
# Copyright (C) 1995 Peter Tobias <tobias@@et-inf.fho-emden.de>
#
#    addftpuser is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published
#    by the Free Software Foundation; either version 2 of the License,
#    or (at your option) any later version.
#
#    addftpuser is distributed in the hope that it will be useful, but
#    WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#    General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with addftpuser; if not, write to the Free Software Foundation,
#    Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

$version = '$Revision: 1.7 $';
$version =~ s/\S+: (\S+) \$/$1/;

$plock = "/etc/ptmp";        # standard method of locking the passwd file
$uid = 10;                   # start searching for a free uid at uid 10
$default_home = "/home/ftp"; # the default ftp home directory
$default_dir_mode = 0755;    # the default directory permissions
$group = "staff";            # the default group for the ftp hierarchy


die "You must be root to run this script.\n" if ($> != 0);

# strip directory from the filename
$0 =~ s#.*/##;

# don't change the permissions
umask(000);

while ($ARGV[0] =~ m/^-/) {
  $_ = shift(@@ARGV);
  if (/--help$/) {
    &usage;
  } elsif (/--version$/) {
    &version;
  } elsif (/--group$/) {
    $group = shift(@@ARGV);
    die "$0: Option group requires an argument\n" unless ($group);
  } else {
    print "$0: Unknown option: $_\n";
    print "$0: Try `$0 --help' for more information.\n";
    exit(1);
  }
}

if (@@ARGV) {
  print "$0: Unknown argument: @@ARGV\n";
  print "$0: Try `$0 --help' for more information.\n";
  exit(1);
}

# check if the user "ftp" already exists
setpwent;
if ($home = (getpwnam("ftp"))[7]) {
   if (-d $home) {
     exit(0);
   } else {
     print "\nYou already have an anonymous FTP account, but the FTP home\n";
     print "directory [$home] does not exist!\n\nDo you want to create it? [y] ";

     if (<STDIN> =~ /^n/i) {
       exit(0);
     }
     $have_passwd_entry = 1;
   }
}
endpwent;

unless ($have_passwd_entry) {

  print "\nDo you want to set up an anonymous FTP account now? [n] ";
  if (<STDIN> =~ /^[^y]/i) {
    print "\nYou can add an anonymous FTP account later using /usr/sbin/addftpuser\n";
    exit(0);
  }

  # find the first free uid
  setpwent;
  while (getpwuid($uid)) {
    ++$uid;
  }
  endpwent;

  # we need the gid for the ftp account
  setgrent;
   $gid = (getgrnam($group))[2] ||
     die "$0: Oops, I can't find your \"$group\" group\n";
  endgrent;

  # we need the name of the home directory
  while(1) {
    $home = "";
    print "\nEnter the name of the FTP home directory: [$default_home] ";
    chop($home = <STDIN>);
    $home =~ s/\s+//g;         # remove spaces ...
    $home =~ s#//+#/#g;        # we don't want things like // in $home
    $home =~ s#/$##;           # remove trailing slash if it exists

    if (! $home) {
      $home = $default_home;
    }

    if (! ($home =~ m#^/#)) {
      print "\nYou have to use an absolute path for the home directory.\n";
      print "In other words, it must begin with a slash.\n";
      next;
    }
    if (-d $home) {
      print "\n$home does already exist, should I use it? [n] ";
      if (<STDIN> =~ /^[^y]/i) {
        next;
      }
    }
    last;
  }

  print "\nDo you want to create a directory for user uploads? [n] ";
  if (<STDIN> =~ /^[^y]/i) {
    $want_incoming = 0;
  } else {
    $want_incoming = 1;
    print "\nPlease look at /etc/ftpd/ftpaccess and its manual page for\n";
    print "further information on how to make /pub/incoming more secure.\n";
  }

  # don't let the user interrupt us
  &ignore_signals;

  # create a lockfile, add the "ftp" user and remove the lockfile
  if (-f $plock) {
    die "$0: /etc/passwd is locked. Try again later.\n";
  }
  link("/etc/passwd", "$plock") || die "$0: Can't create lockfile\n";

  print "\nCreating anonymous FTP account ...\n";

  open(PASSWD, ">>/etc/passwd") || die "$0: Couldn't append to /etc/passwd\n";
    print PASSWD "ftp:*:$uid:$gid:Anonymous FTP:$home:\n";
  close(PASSWD);

  unlink($plock);
}

# don't let the user interrupt us
if($have_passwd_entry) {
  &ignore_signals;
}

# create the ftp home directory and its subdirectories
@@dirs = split(/\//, $home);
shift(@@dirs);    # remove the first element (it's empty because of the
                 # leading slash in $home)
pop(@@dirs);      # remove the last element (we will create it later)
$done = "";

while(@@dirs) {
   $element = shift(@@dirs);
   unless(-d "$done/$element") {
     mkdir("$done/$element", $default_dir_mode);
   }
   $done = "$done/$element";
}

chmod(0555, "$home") || mkdir("$home", 0555) ||
	die "$0: can't mkdir $home: $!\n";
chmod(0111, "$home/bin") || mkdir("$home/bin", 0111) ||
	die "$0: can't mkdir $home/bin: $!\n";
chmod(0111, "$home/dev") || mkdir("$home/dev", 0111) ||
	die "$0: can't mkdir $home/dev: $!\n";
chmod(0111, "$home/lib") || mkdir("$home/lib", 0111) ||
	die "$0: can't mkdir $home/lib: $!\n";
chmod(0111, "$home/etc") || mkdir("$home/etc", 0111) ||
	die "$0: can't mkdir $home/etc: $!\n";
chmod(0555, "$home/pub") || mkdir("$home/pub", 0555) ||
	die "$0: can't mkdir $home/pub: $!\n";
chown(0, 0, "$home", "$home/bin", "$home/dev", "$home/lib", "$home/etc", "$home/pub");

if ($want_incoming) {
  chmod(0753, "$home/pub/incoming") || mkdir("$home/pub/incoming", 0753) ||
	die "$0: can't mkdir $home/pub/incoming: $!\n";
  chown(0, 0, "$home/pub/incoming");
}

foreach $prog ("/bin/ls", "/bin/gzip", "/bin/tar") {
  unlink("$home$prog");
  system("cp $prog $home$prog") &&
    die "$0: can't copy $prog to $home$prog. Giving up\n";
}

if (-f "/usr/bin/zip") {
  system("cp /usr/bin/zip $home/bin/zip") &&
    die "$0: can't copy /usr/bin/zip to $home/bin/zip. Giving up\n";
  chmod(0111, "/usr/bin/zip");
}

opendir(FTPBIN, "$home/bin");
  @@ftpfiles = readdir(FTPBIN);
closedir(FTPBIN);

($aout, $elf) = &filetype("$home/bin", @@ftpfiles);

if($elf) {
    $libc_link=&findlib(5);
    if ($libc_link) {
        $libc=readlink($libc_link) || die "$0: broken symbolic link: $!";
        ($dir = $libc_link) =~ s#[^/]+$## unless($libc =~ m#/#);
        system("cp /lib/ld-linux.so.1 $home/lib") && die "$0: can't copy ld-linux.so.1: $!\n";
        system("cp $dir$libc $home/lib") && die "$0: can't copy $dir$libc: $!\n";
        chmod(0555, "$home/lib/ld-linux.so.1", "$dir$libc");
        symlink("$libc", "$home/lib/libc.so.5");
        system("mknod -m 0666 $home/dev/zero c 1 5") && die "$0: mknod failed: $!\n";
    } else {
        print "$0: ELF binaries found but libc.so.5 not available\n";
    }
}
if($aout) {
    $libc_link=&findlib(4);
    if ($libc_link) {
        $libc = readlink($libc_link) || die "$0: broken symbolic link: $!";
        ($dir = $libc_link) =~ s#[^/]+$## unless($libc =~ m#/#);
        system("cp /lib/ld.so $home/lib") && die "$0: can't copy ld.so: $!\n";
        system("cp $dir$libc $home/lib") && die "$0: can't copy $dir$libc: $!\n";
        chmod(0555, "$home/lib/ld.so", "$dir$libc");
        symlink("$libc", "$home/lib/libc.so.4");
    } else {
        print "$0: a.out binaries found but libc.so.4 not available\n";
    }
}

system("cp /etc/ftpd/pathmsg $home/etc/pathmsg") &&
  die "$0: can't copy /etc/ftpd/pathmsg to $home/etc/pathmsg. Giving up\n";

# create the passwd file for the new anonymous ftp hierarchy
open(FPASSWD,">$home/etc/passwd");
  print FPASSWD "root:*:0:0:root::\n";
  print FPASSWD "ftp:*:$uid:$gid:Anonymous FTP::\n";
close(FPASSWD);

# create the group file for the new anonymous ftp hierarchy
open(FGROUP,">$home/etc/group");
  print FGROUP "root::0:\n";
  print FGROUP "ftp::$gid:\n";
close(FGROUP);

# fix a few permissions
chmod(0444, "$home/etc/passwd", "$home/etc/group", "$home/etc/pathmsg");
chmod(0111, "$home/bin/ls", "$home/bin/gzip", "$home/bin/tar");

# restore the default signal action. Not really necessary ...
&restore_signals;

############################################################################

sub usage {
  print "Usage: $0 [OPTION]\n\n";
  print "--group group         use this group for the anonymous FTP account\n";
  print "--help                display this help and exit\n";
  print "--version             output version information and exit\n";
  exit(0);
}

sub version {
  print "$0 $version\n";
  exit(0);
}

sub ignore_signals {
  $SIG{'HUP'} = 'IGNORE';
  $SIG{'INT'} = 'IGNORE';
  $SIG{'QUIT'} = 'IGNORE';
  $SIG{'TERM'} = 'IGNORE';
}

sub restore_signals {
  $SIG{'HUP'} = 'DEFAULT';
  $SIG{'INT'} = 'DEFAULT';
  $SIG{'QUIT'} = 'DEFAULT';
  $SIG{'TERM'} = 'DEFAULT';
}

sub findlib {
    my($v) = @@_;
    open(LD, "/etc/ld.so.conf");
        chomp(@@ld=<LD>);
    close(LD);
    unshift(@@ld, ("/lib", "/usr/lib"));

    while(@@ld) {
        $_ = shift(@@ld);
        return("$_/libc.so.$v") if (-f "$_/libc.so.$v");
    }
    return(0);
}

sub filetype {
    my($dir, @@files) = @@_;
    my($aout, $elf, $string);
    while(@@files) {
        $_ = shift(@@files);
        next if ($_ eq "." or $_ eq "..");
        open(CH, "$dir/$_");
        read(CH, $string, 4);
        if ($string =~ m/\177ELF/) {
           ++$elf;
        } elsif ($string =~ m/..\144./) {
           ++$aout;
        }
        close(CH);
        undef($string);
    }
    return($aout, $elf);
}
@


1.7
log
@removed --link option (hardlinks)
copy zip to ~ftp/bin if possible
check binaries in ~ftp/bin and copy a.out and/or ELF libraries
search for libraries using /etc/ld.so.conf
@
text
@d22 1
a22 1
$version = '$Revision$';
a61 7
print "\nDo you want to set up an anonymous FTP account now? [n] ";

if (<STDIN> =~ /^[^y]/i) {
  print "\nYou can add an anonymous FTP account later using /usr/sbin/addftpuser\n";
  exit(0);
}

a64 1
   print "\nYou already have an anonymous FTP account";
a65 1
     print ".\n";
d68 2
a69 2
     print ", but the FTP home\ndirectory [$home] does not exist!\n\nDo you want ";
     print "to create it? [y] ";
d80 6
@


1.6
log
@rewrote the newgetopt stuff (newgetopt is not necessary anymore)
@
text
@d18 1
a18 1
#    along with adduser; if not, write to the Free Software Foundation,
d22 2
a23 1
$version = "1.6";
a29 2
$use_hard_links = "no";      # should we create hardlinks instead of copies
                             # when possible? (using copies is more secure!)
a45 2
  } elsif (/--link$/) {
    $use_hard_links = "yes";
d181 2
d189 1
a189 1
chown(0, 0, "$home", "$home/bin", "$home/lib", "$home/etc", "$home/pub");
d197 5
a201 1
# check if we have /lib/libc.so.4 or newer
d203 38
a240 25
# @@libc_link = </lib/libc.so.?>;

opendir(LIB, "/lib/.") || die "$0: opendir failed\n";
(@@libc_link = grep(/^libc\.so\..{1}$/, readdir(LIB))) || die "$0: readdir failed\n";
closedir(LIB);

@@libc_link = sort(@@libc_link);
$libc_link = pop(@@libc_link) || die "$0: can't find /lib/libc.so.*\n";
$libc_link = "/lib/$libc_link";
$libc = readlink($libc_link) || die "$0: broken symbolic link ($libc_link)\n";

# try to create hard links for the following files. If it fails (e.g. they
# are not on the same partition) try to copy them.
@@files = ("/lib/$libc", "/lib/ld.so", "/bin/ls", "/bin/gzip", "/bin/tar");

foreach $prog (@@files) {
  unlink("$home$prog");
  if($use_hard_links eq "yes") {
    link("$prog", "$home$prog") ||
      system("cp $prog $home$prog") &&
        die "$0: can't link/copy $prog to $home$prog. Giving up\n";
  } else {
      system("cp $prog $home$prog") &&
        die "$0: can't copy $prog to $home$prog. Giving up\n";
  }
a241 2
unlink("$home$libc_link");
symlink("$libc", "$home$libc_link");
a258 1
chmod(0555, "$home/lib/libc.so.4", "$home/lib/ld.so");
a268 1
  print "--link                create hard links instead of copies\n";
d294 32
@


1.5
log
@replaced the glob() stuff with readdir ...
@
text
@d22 1
a22 1
$version = "1.5";
d41 17
a57 1
require 'newgetopt.pl';
d59 4
a62 2
unless (&NGetOpt('link', 'group=s', 'help', 'version')) {
  die "$0: Try `$0 --help' for more information.\n"
a63 5

&usage if $opt_help;
&version if $opt_version;
$use_hard_links = "yes" if $opt_link;
$group = $opt_group if $opt_group;
@


1.4
log
@fix permissions of existing directories
@
text
@d22 1
a22 1
$version = "1.4";
d38 3
d186 8
a193 1
@@libc_link = </lib/libc.so.?>;
d195 1
@
