Commit d5474b0a authored by Russ Fish's avatar Russ Fish

More support for accounts and homedirs.

parent 00d031f4
...@@ -187,9 +187,14 @@ sub doboot() ...@@ -187,9 +187,14 @@ sub doboot()
} }
} }
if (! MFS()) { # On CygWin, just make a batch of Windows accounts and generate
# /etc/passwd and /etc/group from the Windows accounts.
goto bad
if (WINDOWS() && os_accounts_start());
if (! MFS() && ! WINDOWS()) {
# #
# On the MFS, these will just start out as empty hashes. # These will just start out as empty hashes so everything is added.
# #
dbmopen(%PWDDB, $PASSDB, 0660) or dbmopen(%PWDDB, $PASSDB, 0660) or
fatal("Cannot open $PASSDB: $!"); fatal("Cannot open $PASSDB: $!");
...@@ -206,8 +211,14 @@ sub doboot() ...@@ -206,8 +211,14 @@ sub doboot()
my ($exists,undef,$curgid) = getgrnam($group); my ($exists,undef,$curgid) = getgrnam($group);
if ($exists) { if ($exists) {
if ($gid != $curgid) { if (WINDOWS()) {
warning("$group/$gid mismatch with existing group"); # Windows needs to know all of the groups by name.
os_groupgid($group, $gid);
}
else {
if ($gid != $curgid) {
warning("$group/$gid mismatch with existing group");
}
} }
next; next;
} }
...@@ -248,7 +259,7 @@ sub doboot() ...@@ -248,7 +259,7 @@ sub doboot()
%deletes = (); %deletes = ();
# Write the DB back out! # Write the DB back out!
if (! MFS()) { if (! MFS() && ! WINDOWS()) {
dbmclose(%GRPDB); dbmclose(%GRPDB);
} }
...@@ -439,9 +450,11 @@ sub doboot() ...@@ -439,9 +450,11 @@ sub doboot()
} }
} }
# Write the DB back out! # Write the DB back out!
if (! MFS()) { if (! MFS() && ! WINDOWS()) {
dbmclose(%PWDDB); dbmclose(%PWDDB);
} }
os_accounts_end()
if (WINDOWS());
# #
# Create sfs_users file and populate it with public SFS keys # Create sfs_users file and populate it with public SFS keys
......
...@@ -84,14 +84,14 @@ if (MFS()) { ...@@ -84,14 +84,14 @@ if (MFS()) {
"rc.rpms", "rc.startcmd"); "rc.rpms", "rc.startcmd");
} }
elsif (WINDOWS()) { elsif (WINDOWS()) {
@bootscripts = ("rc.misc", "rc.localize", "rc.keys", @bootscripts = ("rc.misc", #"rc.localize",
# Do accounts first so we have passwords for Samba. "rc.keys", "rc.mounts",
"rc.accounts","rc.mounts"); "rc.accounts" ##, "rc.topomap",
##"rc.topomap", ##"rc.route", "rc.ifconfig",
##"rc.route", "rc.tunnels", "rc.ifconfig", "rc.delays", ##"rc.hostnames", ##"rc.syncserver", "rc.progagent",
##"rc.hostnames", "rc.syncserver", "rc.trafgen", ##"rc.tarfiles", "rc.rpms",
##"rc.tarfiles", "rc.rpms", "rc.progagent", "rc.linkagent", ##"rc.startcmd"
##"rc.startcmd", "rc.simulator"); );
} }
else { else {
@bootscripts = ("rc.misc", "rc.localize", "rc.keys", "rc.mounts", @bootscripts = ("rc.misc", "rc.localize", "rc.keys", "rc.mounts",
......
...@@ -166,12 +166,12 @@ sub doboot() ...@@ -166,12 +166,12 @@ sub doboot()
return; return;
} }
# On Cygwin, the Samba mount is set up per-user by rc.cygwinxp-user, and what is # On CygWin, the Samba mount is set up per-user by rc.cygwinxp-user, and what is
# available through the mount is controlled by the smb.conf file on the file # available through the mount is controlled by the smb.conf file on the file
# server. All that's left is to wrap the //fs names in symlinks. # server. All that's left is to wrap the //fs names in symlinks.
if (WINDOWS()) { if (WINDOWS()) {
while (($remote, $local) = each %mounts) { while (($remote, $local) = each %mounts) {
my $host="fs"; my $host = "fs";
print "Link $local to //$host\n"; print "Link $local to //$host\n";
os_samba_mount($local, $host, 0); os_samba_mount($local, $host, 0);
} }
......
...@@ -60,12 +60,22 @@ bin-install: dir-install ...@@ -60,12 +60,22 @@ bin-install: dir-install
# These are found in the /share/windows directory. # These are found in the /share/windows directory.
$(INSTALL) -m 755 $(SRCDIR)/WSName.exe $(BINDIR)/WSName.exe $(INSTALL) -m 755 $(SRCDIR)/WSName.exe $(BINDIR)/WSName.exe
$(INSTALL) -m 755 $(SRCDIR)/addusers.exe $(BINDIR)/addusers.exe $(INSTALL) -m 755 $(SRCDIR)/addusers.exe $(BINDIR)/addusers.exe
$(INSTALL) -m 755 $(SRCDIR)/addusers.exe $(BINDIR)/usrtogrp.exe
etc-install: dir-install sysetc-remove sysetc-install etc-install: dir-install sysetc-remove sysetc-install
sysetc-install: dir-install ###ifcfgs sysetc-install: dir-install ###ifcfgs
# Copy host keys for the user sshd on port 2222
chmod g+r /etc/ssh_host*key
-cp /etc/ssh_host_key /etc/ssh_host_key.user
-cp /etc/ssh_host_dsa_key /etc/ssh_host_dsa_key.user
-cp /etc/ssh_host_rsa_key /etc/ssh_host_rsa_key.user
chmod g-r /etc/ssh_host*key /etc/ssh_host*key.user
# Install an /etc/shells file.
$(INSTALL) -m 755 $(SRCDIR)/shells /etc/shells
sysetc-remove: sysetc-remove:
rm -f /etc/ssh_host*key.user /etc/shells
script-install: dir-install $(SCRIPTS) script-install: dir-install $(SCRIPTS)
$(INSTALL) -m 755 $(SRCDIR)/liblocsetup.pm $(BINDIR)/liblocsetup.pm $(INSTALL) -m 755 $(SRCDIR)/liblocsetup.pm $(BINDIR)/liblocsetup.pm
......
...@@ -15,8 +15,9 @@ use Exporter; ...@@ -15,8 +15,9 @@ use Exporter;
qw ( $CP $LN $RM $CHOWN $EGREP qw ( $CP $LN $RM $CHOWN $EGREP
$NFSMOUNT $UMOUNT $SFCMOUNT $SFCUMOUNT $NTS $NET $NFSMOUNT $UMOUNT $SFCMOUNT $SFCUMOUNT $NTS $NET
$TMPASSWD $SFSSD $SFSCD $RPMCMD $TMPASSWD $SFSSD $SFSCD $RPMCMD
os_account_cleanup os_ifconfig_line os_etchosts_line os_account_cleanup os_accounts_start os_accounts_end
os_setup os_groupadd os_useradd os_userdel os_usermod os_mkdir os_ifconfig_line os_etchosts_line
os_setup os_groupadd os_groupgid os_useradd os_userdel os_usermod os_mkdir
os_ifconfig_veth os_ifconfig_veth
os_routing_enable_forward os_routing_enable_gated os_routing_enable_forward os_routing_enable_gated
os_routing_add_manual os_routing_del_manual os_homedirdel os_routing_add_manual os_routing_del_manual os_homedirdel
...@@ -75,11 +76,7 @@ $BASH = "/bin/bash"; ...@@ -75,11 +76,7 @@ $BASH = "/bin/bash";
# #
# These are not exported # These are not exported
# #
my $USERADD = "/usr/sbin/useradd"; my $ADDUSERS = "$BINDIR/addusers.exe";
my $USERDEL = "/usr/sbin/userdel";
my $USERMOD = "/usr/sbin/usermod";
my $GROUPADD = "/usr/sbin/groupadd";
my $GROUPDEL = "/usr/sbin/groupdel";
my $IFCONFIGBIN = "/sbin/ifconfig"; my $IFCONFIGBIN = "/sbin/ifconfig";
my $IFCONFIG = "$IFCONFIGBIN %s inet %s netmask %s"; my $IFCONFIG = "$IFCONFIGBIN %s inet %s netmask %s";
my $IFC_1000MBS = "1000baseTx"; my $IFC_1000MBS = "1000baseTx";
...@@ -102,17 +99,24 @@ sub os_account_cleanup() ...@@ -102,17 +99,24 @@ sub os_account_cleanup()
unlink @LOCKFILES; unlink @LOCKFILES;
# Generate the CygWin password and group files from the registry users. # Generate the CygWin password and group files from the registry users.
# Make root's UID zero. print "Resetting the CygWin passwd and group files.\n";
printf STDOUT "Resetting passwd and group files\n";
if (system("$MKPASSWD -l | \ my $cmd = "$MKPASSWD -l | $AWK -F: '" . 'BEGIN{ OFS=":" } ';
$AWK -F: '/^root:/{\$3=\"0\"} {OFS=\":\"; print}' > /etc/passwd") != 0) { # Make root's UID zero. Put non-root homedirs under /users, not /home.
$cmd .= '{ if ($1=="root") $3="0"; else sub("/home/", "/users/"); print }';
$cmd .= "' > /etc/passwd";
##print "$cmd\n";
if (system("$cmd") != 0) {
print STDERR "Could not generate /etc/password file: $!\n"; print STDERR "Could not generate /etc/password file: $!\n";
return -1; return -1;
} }
# Make wheel an alias for Administrators.
if (system("mkgroup -l | \ $cmd = "mkgroup -l | $AWK '";
$AWK '/^Administrators:/{print \"wheel\" substr(\$0, index(\$0,\":\"))} \ # Make a duplicate group line that is a wheel alias for Administrators.
{print}' > /etc/group") != 0) { $cmd .= '/^Administrators:/{print "wheel" substr($0, index($0,":"))} {print}';
$cmd .= "' > /etc/group";
##print "$cmd\n";
if (system("$cmd") != 0) {
print STDERR "Could not generate /etc/group file: $!\n"; print STDERR "Could not generate /etc/group file: $!\n";
return -1; return -1;
} }
...@@ -341,6 +345,54 @@ sub os_etchosts_line($$$) ...@@ -341,6 +345,54 @@ sub os_etchosts_line($$$)
return sprintf("%s\t%s %s", $ip, $name, $aliases); return sprintf("%s\t%s %s", $ip, $name, $aliases);
} }
#
# On Windows NT, accumulate an input file for the addusers command.
# See "AddUsers Automates Creation of a Large Number of Users",
# http://support.microsoft.com/default.aspx?scid=kb;en-us;199878
#
# The file format is comma-delimited, as follows:
#
# [Users]
# User Name,Full name,Password,Description,HomeDrive,Homepath,Profile,Script
#
# [Global] or [Local]
# Group Name,Comment,UserName,...
#
my $winusersfile = "$BOOTDIR/winusers";
my @groupNames;
my %groupsByGid;
my %groupMembers;
sub os_accounts_start()
{
# Remember group info to be put out at the end.
@groupNames = ();
%groupsByGid = ();
%groupMembers = ();
if (! open(WINUSERS, "> $winusersfile")) {
print STDERR "os_accounts_start: Cannot create $winusersfile .\n";
return -1;
}
# Users come before groups in the addusers.exe account stream.
# Notice the <CR>'s. It's a Windows file.
print WINUSERS "[Users]\r\n";
return 0;
}
#
# Remember the mapping from an existing group GID to its name.
#
sub os_groupgid($$)
{
my($group, $gid) = @_;
$groupsByGid{$gid} = $group; # Remember the name associated with the gid.
return 0;
}
# #
# Add a new group # Add a new group
# #
...@@ -348,7 +400,10 @@ sub os_groupadd($$) ...@@ -348,7 +400,10 @@ sub os_groupadd($$)
{ {
my($group, $gid) = @_; my($group, $gid) = @_;
return system("$GROUPADD -g $gid $group"); push(@groupNames, $group); # Remember all of the group names.
os_groupgid($group, $gid);
return 0;
} }
# #
...@@ -358,7 +413,8 @@ sub os_groupdel($) ...@@ -358,7 +413,8 @@ sub os_groupdel($)
{ {
my($group) = @_; my($group) = @_;
return system("$GROUPDEL $group"); # Unimplemented.
return -1;
} }
# #
...@@ -368,7 +424,8 @@ sub os_userdel($) ...@@ -368,7 +424,8 @@ sub os_userdel($)
{ {
my($login) = @_; my($login) = @_;
return system("$USERDEL $login"); # Unimplemented.
return -1;
} }
# #
...@@ -378,6 +435,9 @@ sub os_usermod($$$$$$) ...@@ -378,6 +435,9 @@ sub os_usermod($$$$$$)
{ {
my($login, $gid, $glist, $pswd, $root, $shell) = @_; my($login, $gid, $glist, $pswd, $root, $shell) = @_;
# Unimplemented.
return -1;
if ($root) { if ($root) {
$glist = join(',', split(/,/, $glist), "root"); $glist = join(',', split(/,/, $glist), "root");
} }
...@@ -397,21 +457,76 @@ sub os_useradd($$$$$$$$$) ...@@ -397,21 +457,76 @@ sub os_useradd($$$$$$$$$)
{ {
my($login, $uid, $gid, $pswd, $glist, $homedir, $gcos, $root, $shell) = @_; my($login, $uid, $gid, $pswd, $glist, $homedir, $gcos, $root, $shell) = @_;
if ($root) { # Groups have to be created before we can add members.
$glist = join(',', split(/,/, $glist), "root"); my $gname = $groupsByGid{$gid};
} warn "*** Missing group name for gid $gid.\n"
if ($glist ne "") { if (!$gname);
$glist = "-G $glist"; $groupMembers{$gname} .= "$login ";
$groupMembers{'Administrators'} .= "$login "
if ($root);
foreach my $gid (split(/,/, $glist)) {
$gname = $groupsByGid{$gid};
if ($gname) {
$groupMembers{$gname} .= "$login ";
}
else {
warn "*** Missing group name for gid $gid.\n";
}
} }
# Map the shell into a full path. # Map the shell into a full path.
$shell = MapShell($shell); $shell = MapShell($shell);
if (system("$USERADD -M -u $uid -g $gid $glist -p '$pswd' ". # Use the leading 8 chars of the Unix MD5 passwd hash as a known random
"-d $homedir -s $shell -c \"$gcos\" $login") != 0) { # password, both here and in Samba. Skip over a "$1$" prefix.
warn "*** WARNING: $USERADD $login error.\n"; my $pwd = $pswd;
$pwd =~ s/^(\$1\$)?(.{8}).*/$2/;
print WINUSERS "$login,$gcos,$pwd,,,,,\r\n";
return 0;
}
#
# Finish the input for the addusers command.
#
sub os_accounts_end()
{
# Dump out the group *creation* lines.
print WINUSERS "[Local]\r\n";
foreach my $grp (@groupNames) {
# Ignore group membership here. See "net localgroup" below.
print WINUSERS "$grp,Emulab $grp group,\r\n";
}
close WINUSERS;
# Create the whole batch of groups and accounts listed in the file.
# /p options: Users don't have to change passwords, and they never expire.
print "Creating the Windows users and groups.\n";
my $winfile = "C:/cygwin$winusersfile";
$winfile =~ s|/|\\|g;
my $cmd = "$ADDUSERS /c '$winfile' /p:le";
##print " $cmd\n";
if (system($cmd) != 0) {
warn "*** WARNING: AddUsers error ($cmd)\n";
return -1; return -1;
} }
return 0;
# Add members into groups using the "net localgroup /add" command.
# (Addusers only creates groups, it can't add a user to an existing group.)
while (my($grp, $members) = each %groupMembers) {
foreach my $mbr (split(/ /,$members)) {
print " Adding $mbr to $grp.\n";
my $cmd = "$NET localgroup $grp $mbr /add > /dev/null";
##print " $cmd\n";
if (system($cmd) != 0) {
warn "*** WARNING: net localgroup error ($cmd)\n";
}
}
}
# Make the CygWin /etc/passwd and /etc/group files match Windows.
return os_account_cleanup();
} }
# #
...@@ -543,7 +658,7 @@ sub MapShell($) ...@@ -543,7 +658,7 @@ sub MapShell($)
return $fullpath; return $fullpath;
} }
sub os_samba_mount($$) sub os_samba_mount($$$)
{ {
my ($local, $host, $verbose) = @_; my ($local, $host, $verbose) = @_;
......
...@@ -12,15 +12,19 @@ chmod -f g+w $logfile ...@@ -12,15 +12,19 @@ chmod -f g+w $logfile
# Enable WINDOWS() in libsetup.pm . # Enable WINDOWS() in libsetup.pm .
iscygwin=/etc/emulab/iscygwin iscygwin=/etc/emulab/iscygwin
chmod -f g+w /etc/emulab
chmod -f g+w $iscygwin chmod -f g+w $iscygwin
uname -r > $iscygwin uname -r > $iscygwin
chmod g+w $iscygwin chmod g+w $iscygwin
chmod -f g-w /etc/emulab
# Set up for autologin as the swapin user. # Set up for autologin as the swapin user.
tmcc=/usr/local/etc/emulab/tmcc.bin tmcc=/usr/local/etc/emulab/tmcc.bin
swapper=`$tmcc creator | sed 's|.*SWAPPER=\([^ ]*\).*|\1|'` swapper=`$tmcc creator | sed 's|.*SWAPPER=\([^ ]*\).*|\1|'`
echo "`date`: Set to autologin as $swapper." >> $logfile echo "`date`: Set to autologin as $swapper." >> $logfile
autologin=/tmp/autologin.reg alogdir=/var/emulab/boot
autologin=$alogdir/autologin.reg
chmod -f g+w $alogdir
rm -f $autologin rm -f $autologin
cat <<EOF > $autologin cat <<EOF > $autologin
Windows Registry Editor Version 5.00 Windows Registry Editor Version 5.00
...@@ -30,7 +34,11 @@ Windows Registry Editor Version 5.00 ...@@ -30,7 +34,11 @@ Windows Registry Editor Version 5.00
"DefaultUserName"="$swapper" "DefaultUserName"="$swapper"
EOF EOF
chmod g+rw $autologin chmod g+rw $autologin
regedit -s $autologin chmod -f g-w $alogdir
winautologin=`cygpath -w $autologin`
if ! regedit -s $winautologin ; then
echo "`date`: regedit -s $winautologin failed with code $?." >> $logfile
fi
# Make sure the computer name is right, reboots to change it if necessary. # Make sure the computer name is right, reboots to change it if necessary.
nodeid=`$tmcc nodeid` nodeid=`$tmcc nodeid`
......
...@@ -18,19 +18,22 @@ if [ $user = root ]; then ...@@ -18,19 +18,22 @@ if [ $user = root ]; then
fi fi
# Shares are local to the Win32 login session context. # Shares are local to the Win32 login session context.
# We must process a user name and password for the first one to be opened. # We must process a user name and password for the first one to be opened, and it
###host=fs # has to go onto a drive letter. After that, we can use UNC //host paths freely.
host=pc88 host=fs
pswd=`tmcc accounts | awk '/LOGIN='$user' /{print substr($0,index($0," PSWD=")+9,8)}'` pswd=`tmcc accounts | awk '/LOGIN='$user' /{print substr($0,index($0," PSWD=")+9,8)}'`
echo "Connecting to //$host as $user." echo "Connecting to //$host as $user."
while ! net use Z: '\\'$host'\'$user "$pswd" /user:$user /persistent:no > /dev/null while ! net use Z: '\\'$host'\'$user "$pswd" /user:$user /persistent:no
do do
read -p "Connection failed, try again? [y]: " -n 1 chr # Read one char (or none on <Enter>), add a time-out for autologins after boot.
read -p "Connection failed, try again? [y]: " -n 1 -t 5 chr
echo "" echo ""
if [[ "$chr" != [yY] ]]; then break; fi if [[ ! -z "$chr" && "$chr" != [yY] ]]; then break; fi
echo "" echo ""
echo "Re-trying Connection to //$host as $user." echo "Re-trying connection to //$host as $user."
done done
# Show network mount status.
net use
# Set the homedir for ssh in case we don't get through rc.mounts . # Set the homedir for ssh in case we don't get through rc.mounts .
ln -f -s //$host/$user /users/$user ln -f -s //$host/$user /users/$user
......
/bin/sh
/bin/csh
/bin/tcsh
/bin/bash
...@@ -17,19 +17,24 @@ ...@@ -17,19 +17,24 @@
# If you're logged in via rdesktop, see the Users tab in Task Manager. # If you're logged in via rdesktop, see the Users tab in Task Manager.
pidfile=/var/run/sshd.pid pidfile=/var/run/sshd.pid
upidfile=$pidfile.user
running= running=
if [ -e $pidfile ]; then if [ -e $upidfile ]; then
# Check that the process ID actually refers to a running process. # Check that the process ID actually refers to a running process.
pid=`cat $pidfile` pid=`cat $upidfile`
if ( kill -0 $pid >& /dev/null ); then if ( kill -0 $pid >& /dev/null ); then
running=yes running=yes
fi fi
fi fi
if [ $running ]; then if [ $running ]; then
# Kill a previous copy of sshd, so we can run one as this user. if ( ps -u SYSTEM | grep -q "^ *$pid " ); then
echo "Killing previous sshd daemon." echo "Ignoring SYSTEM sshd."
ps -ef | awk '$2=='$pid'{print}' else
kill $pid # Kill a previous copy of sshd, so we can run one as this user.
echo "Killing previous user sshd daemon."
ps -ef | awk '$2=='$pid'{print}'
kill $pid
fi
fi fi
# Set permissions on the key files needed for sshd to start up as this user. # Set permissions on the key files needed for sshd to start up as this user.
...@@ -46,3 +51,8 @@ chmod o-r /etc/ssh*key.user ...@@ -46,3 +51,8 @@ chmod o-r /etc/ssh*key.user
echo "Starting new sshd daemon as $user." echo "Starting new sshd daemon as $user."
(CYGWIN="ntsec tty" /usr/sbin/sshd -p 2222 -o "UsePrivilegeSeparation no" \ (CYGWIN="ntsec tty" /usr/sbin/sshd -p 2222 -o "UsePrivilegeSeparation no" \
-h /etc/ssh_host_key.user -h /etc/ssh_host_dsa_key.user &) -h /etc/ssh_host_key.user -h /etc/ssh_host_dsa_key.user &)
# Remember this one separately from the SYSTEM sshd.
chmod -f g+w $upidfile
cp $pidfile $upidfile
chmod -f g+w $upidfile
...@@ -7,16 +7,21 @@ ...@@ -7,16 +7,21 @@
# Stop the current the SSH daemon. # Stop the current the SSH daemon.
pidfile=/var/run/sshd.pid pidfile=/var/run/sshd.pid
upidfile=$pidfile.user
running= running=
if [ -e $pidfile ]; then if [ -e $upidfile ]; then
# Check that the process ID actually refers to a running process. # Check that the process ID actually refers to a running process.
pid=`cat $pidfile` pid=`cat $upidfile`
if ( kill -0 $pid >& /dev/null ); then if ( kill -0 $pid >& /dev/null ); then
running=yes running=yes
fi fi
fi fi
if [ $running ]; then if [ $running ]; then
echo "Killing sshd daemon." if ( ps -u SYSTEM | grep -q "^ *$pid " ); then
ps -ef | awk '$2=='$pid'{print}' echo "Ignoring SYSTEM sshd."
kill $pid else
echo "Killing sshd daemon."
ps -ef | awk '$2=='$pid'{print}'
kill $pid
fi
fi fi
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment