Commit 77661f58 authored by Leigh B. Stoller's avatar Leigh B. Stoller

group,master.password: Add sshd, smmsp, mailnull, and sfs.

rc.conf: Remove fixed -p argument. Now set by mkjail.
rc.local,jailctl: Update for client side path reorg and cleanup.
jaildog.pl,mkjail.pl: Numerous fixes for jailed nodes.
parent dc3fc324
...@@ -12,9 +12,13 @@ bin:*:10: ...@@ -12,9 +12,13 @@ bin:*:10:
games:*:13: games:*:13:
staff:*:20:root staff:*:20:root
guest:*:31:root guest:*:31:root
sshd:*:22:
smmsp:*:25:
mailnull:*:26:
uucp:*:66: uucp:*:66:
xten:*:67:xten xten:*:67:xten
dialer:*:68: dialer:*:68:
network:*:69: network:*:69:
nogroup:*:65533: nogroup:*:65533:
nobody:*:65534: nobody:*:65534:
sfs:*:77:
...@@ -11,7 +11,7 @@ use Getopt::Std; ...@@ -11,7 +11,7 @@ use Getopt::Std;
# The point of this is to fire up the init code inside the jail, # The point of this is to fire up the init code inside the jail,
# and then wait for a signal from outside the jail. When that happens # and then wait for a signal from outside the jail. When that happens
# kill off everything inside the jail and exit. So, like a mini version # kill off everything inside the jail and exit. So, like a mini version
# of /sbin/init cause killing the jail cleanly from outside the jail # of /sbin/init, since killing the jail cleanly from outside the jail
# turns out to be rather difficult, and doing it from inside is very easy! # turns out to be rather difficult, and doing it from inside is very easy!
# #
my $DEFCONSIX = "/bin/sh /etc/rc"; my $DEFCONSIX = "/bin/sh /etc/rc";
......
...@@ -4,19 +4,15 @@ ...@@ -4,19 +4,15 @@
# Copyright (c) 2000-2002 University of Utah and the Flux Group. # Copyright (c) 2000-2002 University of Utah and the Flux Group.
# All rights reserved. # All rights reserved.
# #
. /etc/emulab/paths.sh
# #
# Jail startup. To be run inside of a jail! # Jail startup. To be run inside of a jail!
# #
case "$1" in case "$1" in
start) start)
if [ -f /usr/local/etc/emulab/jaildog.pl ]; then $BINDIR/jaildog.pl > /dev/null 2>&1
/usr/local/etc/emulab/jaildog.pl > /dev/null 2>&1 echo -n ' Emulab'
echo -n ' Emulab'
elif [ -f /etc/testbed/jaildog.pl ]; then
/etc/testbed/jaildog.pl > /dev/null 2>&1
echo -n ' Emulab'
fi
;; ;;
stop) stop)
# #
......
...@@ -25,11 +25,8 @@ my $optlist = "t:"; ...@@ -25,11 +25,8 @@ my $optlist = "t:";
# #
$| = 1; $| = 1;
# # Drag in path stuff so we can find emulab stuff.
# Untaint path BEGIN { require "/etc/emulab/paths.pm"; import emulabpaths; }
#
$ENV{'PATH'} = "/bin:/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
# #
# Must be root to run this. # Must be root to run this.
...@@ -43,19 +40,11 @@ if ($UID != 0) { ...@@ -43,19 +40,11 @@ if ($UID != 0) {
# Load the OS independent support library. It will load the OS dependent # Load the OS independent support library. It will load the OS dependent
# library and initialize itself. # library and initialize itself.
# #
if (-d "/usr/local/etc/emulab") {
use lib "/usr/local/etc/emulab";
$ENV{'PATH'} .= ":/usr/local/etc/emulab";
}
elsif (-d "/etc/testbed") {
use lib "/etc/testbed";
$ENV{'PATH'} .= ":/etc/testbed";
}
use libsetup; use libsetup;
# Locals # Locals
my $timeout = (60 * 60 * 12); # In seconds of course. my $timeout = (60 * 60 * 12); # In seconds of course.
my $logname = "/var/tmp/emulab-jaildog.debug"; my $logname = "$LOGDIR/emulab-jaildog.debug";
my $pidfile = "/var/run/emulab-jaildog.pid"; my $pidfile = "/var/run/emulab-jaildog.pid";
my $vnodeid; my $vnodeid;
...@@ -119,32 +108,79 @@ if (! ($vnodeid = jailedsetup())) { ...@@ -119,32 +108,79 @@ if (! ($vnodeid = jailedsetup())) {
if (-x TMTARBALLS()) { if (-x TMTARBALLS()) {
print "Installing Tarballs ...\n"; print "Installing Tarballs ...\n";
system(TMTARBALLS()); system(TMTARBALLS());
if ($? < 0) {
die("*** $0:\n".
" Failed to install tarballs!\n");
}
} }
if (-x TMSTARTUPCMD()) { if (-x TMSTARTUPCMD()) {
print "Running startup command ...\n"; print "Running startup command ...\n";
system("runstartup"); system("runstartup");
# Command does not actually run till a little later ...
if ($?) {
die("*** $0:\n".
" Failed to setup startup command!\n");
}
}
if (-x TMTRAFFICCONFIG()) {
print "Starting Traffic Generators ...\n";
# Exits immediately.
system(TMTRAFFICCONFIG());
if ($?) {
die("*** $0:\n".
" Failed to setup traffic generators!\n");
}
sleep(1);
} }
#
# Start isalive daemon.
#
startisalive();
# #
# Inform TMCD that we are up and running. # Inform TMCD that we are up and running.
# #
print "Informing Emulab Operations that we're up and running ...\n"; print "Informing Emulab Operations that we're up and running ...\n";
system("tmcc state ISUP"); system("tmcc state ISUP");
#
# Loop!
#
while (1) {
sleep($timeout);
my $date = POSIX::strftime("20%y/%m/%d %H:%M:%S", localtime());
print "Dogging it at $date\n";
#
# Run account update. Use immediate mode so that it exits right away
# if the lock is taken (another update already running).
#
print "Looking for new Emulab accounts ...\n";
system("update -i");
}
exit(0);
# #
# Fire off a child that does nothing but tell the boss we are alive. # Fire off a child that does nothing but tell the boss we are alive.
# #
my $mypid = fork(); sub startisalive()
if (! $mypid) { {
if (fork()) {
return;
}
my $failed = 0; my $failed = 0;
print "Keep alive starting up ... \n"; print "Keep alive starting up ... \n";
while (1) { while (1) {
# #
# Run tmcc in UDP mode. The command is ignored at the other end. # Run tmcc in UDP mode.
# Its just the connection that tells tmcd we are alive.
# Since its UDP, we try it a couple of times if it fails. # Since its UDP, we try it a couple of times if it fails.
# #
my $retries = 3; my $retries = 3;
...@@ -180,23 +216,3 @@ if (! $mypid) { ...@@ -180,23 +216,3 @@ if (! $mypid) {
} }
exit(0); exit(0);
} }
#
# Loop!
#
while (1) {
sleep($timeout);
my $date = POSIX::strftime("20%y/%m/%d %H:%M:%S", localtime());
print "Dogging it at $date\n";
#
# Run account update. Use immediate mode so that it exits right away
# if the lock is taken (another update already running).
#
print "Looking for new Emulab accounts ...\n";
system("update -i");
}
exit(0);
...@@ -11,7 +11,9 @@ xten:*:67:67::0:0:X-10 daemon:/usr/local/xten:/sbin/nologin ...@@ -11,7 +11,9 @@ xten:*:67:67::0:0:X-10 daemon:/usr/local/xten:/sbin/nologin
pop:*:68:6::0:0:Post Office Owner:/nonexistent:/sbin/nologin pop:*:68:6::0:0:Post Office Owner:/nonexistent:/sbin/nologin
nobody:*:65534:65534::0:0:Unprivileged user:/nonexistent:/sbin/nologin nobody:*:65534:65534::0:0:Unprivileged user:/nonexistent:/sbin/nologin
ftp:*:99:52::0:0:Anonymous Ftp:/var/spool/ftp:/bin/echo ftp:*:99:52::0:0:Anonymous Ftp:/var/spool/ftp:/bin/echo
sshd:*:22:22::0:0:Secure Shell Daemon:/var/empty:/sbin/nologin
smmsp:*:25:25::0:0:Sendmail Submission User:/var/spool/clientmqueue:/sbin/nologin smmsp:*:25:25::0:0:Sendmail Submission User:/var/spool/clientmqueue:/sbin/nologin
mailnull:*:26:26::0:0:Sendmail Default User:/var/spool/mqueue:/sbin/nologin
mysql:*:88:88::0:0:MySQL Daemon:/var/db/mysql:/sbin/nologin mysql:*:88:88::0:0:MySQL Daemon:/var/db/mysql:/sbin/nologin
sfs:*:77:77::0:0:SFS pseudo-user:/:/bin/nologin sfs:*:77:77::0:0:SFS pseudo-user:/:/bin/nologin
emulabman:*:65520:10::0:0:Emulab Man:/home/emulabman:/bin/tcsh emulabman:*:65520:10::0:0:Emulab Man:/home/emulabman:/bin/tcsh
...@@ -10,6 +10,9 @@ use Fcntl; ...@@ -10,6 +10,9 @@ use Fcntl;
use IO::Handle; use IO::Handle;
use Socket; use Socket;
# Drag in path stuff so we can find emulab stuff. Also untaints path.
BEGIN { require "/etc/emulab/paths.pm"; import emulabpaths; }
# #
# Questions: # Questions:
# #
...@@ -34,7 +37,7 @@ my $optlist = "i:p:e:s"; ...@@ -34,7 +37,7 @@ my $optlist = "i:p:e:s";
if ($UID) { if ($UID) {
die("Must be root to run this script!\n"); die("Must be root to run this script!\n");
} }
system("sysctl jail.set_hostname_allowed=0"); system("sysctl jail.set_hostname_allowed=0 >/dev/null 2>&1");
# #
# Catch ^C and exit with error. # Catch ^C and exit with error.
...@@ -64,38 +67,18 @@ $SIG{TERM} = 'IGNORE'; ...@@ -64,38 +67,18 @@ $SIG{TERM} = 'IGNORE';
STDOUT->autoflush(1); STDOUT->autoflush(1);
STDERR->autoflush(1); STDERR->autoflush(1);
#
# Untaint the environment.
#
$ENV{'PATH'} = "/tmp:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:".
"/usr/local/bin:/usr/site/bin:/usr/site/sbin";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Deal with the screwy path mess that I created!
#
my $EMULABPATH;
if (-e "/usr/local/etc/emulab/tmcc") {
$EMULABPATH = "/usr/local/etc/emulab";
}
elsif (-e "/etc/testbed/tmcc") {
$EMULABPATH = "/etc/testbed";
}
else {
die("*** $0:\n".
" Could not locate the testbed directory!\n");
}
# #
# Locals # Locals
# #
my $JAILPATH = "/var/emulab/jails"; my $JAILPATH = "/var/emulab/jails";
my $JAILCONFIG = "/etc/jail"; my $ETCJAIL = "/etc/jail";
my $LOCALROOTFS = "/local"; my $LOCALFS = "/users/local";
my $TMCC = "$EMULABPATH/tmcc"; my $LOCALMNTPNT = "/local";
my $TMCC = "$BINDIR/tmcc";
my $JAILCONFIG = "jailconfig";
my @ROOTCPDIRS = ("etc", "root"); my @ROOTCPDIRS = ("etc", "root");
my @ROOTMKDIRS = ("dev", "tmp", "var", "usr", "proc", "users", "opt", my @ROOTMKDIRS = ("dev", "tmp", "var", "usr", "proc", "users", "opt",
"bin", "sbin", "home", $LOCALROOTFS); "bin", "sbin", "home", $LOCALMNTPNT);
my @ROOTMNTDIRS = ("bin", "sbin", "usr"); my @ROOTMNTDIRS = ("bin", "sbin", "usr");
my $VNFILEMBS = 64; my $VNFILEMBS = 64;
my $MAXVNDEVS = 10; my $MAXVNDEVS = 10;
...@@ -108,6 +91,9 @@ my @mntpoints = (); ...@@ -108,6 +91,9 @@ my @mntpoints = ();
my $jailpid; my $jailpid;
my $tmccpid; my $tmccpid;
my $interactive = 0; my $interactive = 0;
my %jailconfig = ();
my $jailoptions;
my $sshdport = 50000;
# #
# Parse command arguments. Once we return from getopts, all that should be # Parse command arguments. Once we return from getopts, all that should be
...@@ -136,6 +122,20 @@ if (defined($options{'s'})) { ...@@ -136,6 +122,20 @@ if (defined($options{'s'})) {
$interactive = 1; $interactive = 1;
} }
#
# Get the parent IP.
#
my $hostname = `hostname`;
my $hostip;
# Untaint and strip newline.
if ($hostname =~ /^([-\w\.]+)$/) {
$hostname = $1;
my (undef,undef,undef,undef,@ipaddrs) = gethostbyname($hostname);
$hostip = inet_ntoa($ipaddrs[0]);
}
# #
# If no IP, then it defaults to our hostname's IP. # If no IP, then it defaults to our hostname's IP.
# #
...@@ -150,15 +150,7 @@ if (defined($options{'i'})) { ...@@ -150,15 +150,7 @@ if (defined($options{'i'})) {
} }
} }
else { else {
my $hostname = `hostname`; $IP = $hostip;
# Untaint and strip newline.
if ($hostname =~ /^([-\w\.]+)$/) {
$hostname = $1;
my (undef,undef,undef,undef,@ipaddrs) = gethostbyname($hostname);
$IP = inet_ntoa($ipaddrs[0]);
}
} }
if (!defined($IP)) { if (!defined($IP)) {
usage(); usage();
...@@ -179,7 +171,9 @@ print("Setting up jail for HOST:$HOST using IP:$IP\n") ...@@ -179,7 +171,9 @@ print("Setting up jail for HOST:$HOST using IP:$IP\n")
if ($debug); if ($debug);
# #
# First create the directory tree and such. # In most cases, the $HOST directory will have been created by the caller,
# and a config file possibly dropped in.
# When debugging, we have to create it here.
# #
chdir($JAILPATH) or chdir($JAILPATH) or
die("Could not chdir to $JAILPATH: $!\n"); die("Could not chdir to $JAILPATH: $!\n");
...@@ -188,7 +182,18 @@ if (! -e $HOST) { ...@@ -188,7 +182,18 @@ if (! -e $HOST) {
mkdir($HOST, 0770) or mkdir($HOST, 0770) or
fatal("Could not mkdir $HOST in $JAILPATH: $!"); fatal("Could not mkdir $HOST in $JAILPATH: $!");
} }
else {
getjailconfig("$JAILPATH/$HOST");
}
#
# See if special options supported, and if so setup args as directed.
#
setjailoptions();
#
# Create the "disk";
#
if (-e "$HOST/root") { if (-e "$HOST/root") {
# #
# Try to pick up where we left off. # Try to pick up where we left off.
...@@ -223,7 +228,8 @@ else { ...@@ -223,7 +228,8 @@ else {
$SIG{TERM} = 'DEFAULT'; $SIG{TERM} = 'DEFAULT';
$ENV{'TMCCVNODEID'} = $HOST; $ENV{'TMCCVNODEID'} = $HOST;
my $cmd = "jail $JAILPATH/$HOST/root $HOST $IP $JAILCONFIG/injail.pl"; my $cmd = "jail $jailoptions ".
"$JAILPATH/$HOST/root $HOST $IP /etc/jail/injail.pl";
if ($interactive) { if ($interactive) {
$cmd .= " /bin/csh"; $cmd .= " /bin/csh";
} }
...@@ -340,23 +346,37 @@ sub mkrootfs($) ...@@ -340,23 +346,37 @@ sub mkrootfs($)
# #
# Now a bunch of stuff to set up a nice environment in the jail. # Now a bunch of stuff to set up a nice environment in the jail.
# #
mysystem("cp -p $JAILCONFIG/rc.conf $path/root/etc"); mysystem("cp -p $ETCJAIL/rc.conf $path/root/etc");
mysystem("cp -p $JAILCONFIG/rc.local $path/root/etc"); mysystem("rm -f $path/root/etc/rc.conf.local");
mysystem("cp -p $JAILCONFIG/group $path/root/etc"); mysystem("cp -p $ETCJAIL/rc.local $path/root/etc");
mysystem("cp -p $JAILCONFIG/master.passwd $path/root/etc"); mysystem("cp -p $ETCJAIL/group $path/root/etc");
mysystem("cp -p $ETCJAIL/master.passwd $path/root/etc");
mysystem("cp /dev/null $path/root/etc/fstab"); mysystem("cp /dev/null $path/root/etc/fstab");
mysystem("pwd_mkdb -p -d $path/root/etc $path/root/etc/master.passwd"); mysystem("pwd_mkdb -p -d $path/root/etc $path/root/etc/master.passwd");
mysystem("echo '$IP $HOST' >> $path/root/etc/hosts"); mysystem("echo '$IP $HOST' >> $path/root/etc/hosts");
mysystem("echo 'sshd_flags=\"\$sshd_flags -p $sshdport\"' >> ".
" $path/root/etc/rc.conf");
# No X11 forwarding.
mysystem("cat $path/root/etc/ssh/sshd_config | ".
"sed -e 's/^X11Forwarding.*yes/X11Forwarding no/' > ".
"$path/root/tmp/sshd_foo");
mysystem("cp -f $path/root/tmp/sshd_foo $path/root/etc/ssh/sshd_config");
# In the jail, 127.0.0.1 refers to the jail, but we want to use the
# nameserver running *outside* the jail.
mysystem("cat /etc/resolv.conf | ".
"sed -e 's/127\.0\.0\.1/$hostip/' > ".
"$path/root/etc/resolv.conf");
# #
# Give the jail an NFS mount of the local project directory. This one # Give the jail an NFS mount of the local project directory. This one
# is read-write. # is read-write.
# #
if (defined($PID) && -e $LOCALROOTFS && -e "$LOCALROOTFS/$PID") { if (defined($PID) && -e $LOCALFS && -e "$LOCALFS/$PID") {
mysystem("mkdir -p $path/root/$LOCALROOTFS/$PID"); mysystem("mkdir -p $path/root/$LOCALMNTPNT/$PID");
mysystem("mount localhost:$LOCALROOTFS/$PID ". mysystem("mount localhost:$LOCALFS/$PID $path/root/$LOCALMNTPNT/$PID");
"$path/root/$LOCALROOTFS/$PID"); push(@mntpoints, "$path/root/$LOCALMNTPNT/$PID");
push(@mntpoints, "$path/root/$LOCALROOTFS/$PID");
} }
cleanmess($path); cleanmess($path);
...@@ -408,22 +428,17 @@ sub restorerootfs($) ...@@ -408,22 +428,17 @@ sub restorerootfs($)
# Give the jail an NFS mount of the local project directory. This one # Give the jail an NFS mount of the local project directory. This one
# is read-write. # is read-write.
# #
if (defined($PID) && -e $LOCALROOTFS && -e "$LOCALROOTFS/$PID") { if (defined($PID) && -e $LOCALFS && -e "$LOCALFS/$PID") {
mysystem("mount localhost:$LOCALROOTFS/$PID ". mysystem("mkdir -p $path/root/$LOCALMNTPNT/$PID");
"$path/root/$LOCALROOTFS/$PID"); mysystem("mount localhost:$LOCALFS/$PID $path/root/$LOCALMNTPNT/$PID");
push(@mntpoints, "$path/root/$LOCALROOTFS/$PID"); push(@mntpoints, "$path/root/$LOCALMNTPNT/$PID");
} }
cleanmess($path);
return 0; return 0;
} }
# #
# Deal with the path mess I created! I should have split the emulab # Okay, we clean up some of what is in /etc and /etc/emulab so that the
# directory into a /etc/emulab part with keys and such, and a # jail cannot see that stuff.
# /usr/local/bin part that had the scripts. I do not want to mess with that
# now, so mount a tiny MFS over /usr/local/etc/emulab, and then remove the
# bits that we do not want the jail to see.
# #
sub cleanmess($) { sub cleanmess($) {
my ($path) = @_; my ($path) = @_;
...@@ -435,28 +450,10 @@ sub cleanmess($) { ...@@ -435,28 +450,10 @@ sub cleanmess($) {
mysystem("rm -f $path/root/etc/emulab.cdkey"); mysystem("rm -f $path/root/etc/emulab.cdkey");
mysystem("rm -f $path/root/etc/emulab.pkey"); mysystem("rm -f $path/root/etc/emulab.pkey");
if (-e "/usr/local/etc/emulab/tmcc") { mysystem("rm -f $path/root/$ETCDIR/*.pem");
mysystem("mount_mfs -s 4096 -b 4096 -f 1024 -i 12000 -c 11 ". mysystem("rm -f $path/root/$ETCDIR/cvsup.auth");
"-T minimum dummy $path/root/usr/local/etc/emulab"); mysystem("rm -rf $path/root/$ETCDIR/.cvsup");
push(@mntpoints, "$path/root/usr/local/etc/emulab"); mysystem("rm -f $path/root/$ETCDIR/master.passwd");
mysystem("hier cp /usr/local/etc/emulab ".
" $path/root/usr/local/etc/emulab");
#
# And symlink /etc/testbed in. Ug, these paths are all a mess!
#
mysystem("rm -rf $path/root/etc/testbed");
mysystem("ln -s /usr/local/etc/emulab $path/root/etc/testbed");
mysystem("rm -f $path/root/usr/local/etc/emulab/*.pem");
mysystem("rm -f $path/root/usr/local/etc/emulab/cvsup.auth");
mysystem("rm -rf $path/root/usr/local/etc/emulab/.cvsup");
}
else {
mysystem("rm -f $path/root/etc/testbed/*.pem");
mysystem("rm -f $path/root/etc/testbed/cvsup.auth");
mysystem("rm -rf $path/root/etc/testbed/.cvsup");
}
# #
# Copy in emulabman if it exists. # Copy in emulabman if it exists.
...@@ -570,3 +567,94 @@ sub mysystem($) ...@@ -570,3 +567,94 @@ sub mysystem($)
fatal("Command failed: $? - $command"); fatal("Command failed: $? - $command");
} }
} }
#
# Read in the jail config file.
#
sub getjailconfig($)
{
my ($path) = @_;
$path .= "/$JAILCONFIG";
if (! -e $path) {
return 0;
}
if (! open(CONFIG, $path)) {
print("$path could not be opened for reading: $!\n");
return -1;
}
while (<CONFIG>) {
if ($_ =~ /^(.*)="(.+)"$/ ||
$_ =~ /^(.*)=(.+)$/) {
$jailconfig{$1} = $2;
}
}
close(CONFIG);
return 0;
}
#
# See if special jail opts supported.
#
sub setjailoptions() {
$jailoptions = "";
#
# Do this all the time, so that we can figure out the sshd port.
#
foreach my $key (keys(%jailconfig)) {
my $val = $jailconfig{$key};
SWITCH: for ($key) {
/^PORTRANGE$/ && do {
if ($val =~ /(\d+),(\d+)/) {
$jailoptions .= " -p $1:$2";
$sshdport = $1;
}
last SWITCH;
};
/^SYSVIPC$/ && do {
if ($val) {
$jailoptions .= " -o sysvipc";
}
else {
$jailoptions .= " -o nosysvipc";
}
last SWITCH;
};
/^INETRAW$/ && do {
if ($val) {
$jailoptions .= " -o inetraw";