Commit d5474b0a authored by Russ Fish's avatar Russ Fish

More support for accounts and homedirs.

parent 00d031f4
......@@ -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
fatal("Cannot open $PASSDB: $!");
......@@ -206,8 +211,14 @@ sub doboot()
my ($exists,undef,$curgid) = getgrnam($group);
if ($exists) {
if ($gid != $curgid) {
warning("$group/$gid mismatch with existing group");
if (WINDOWS()) {
# 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;
}
......@@ -248,7 +259,7 @@ sub doboot()
%deletes = ();
# Write the DB back out!
if (! MFS()) {
if (! MFS() && ! WINDOWS()) {
dbmclose(%GRPDB);
}
......@@ -439,9 +450,11 @@ sub doboot()
}
}
# Write the DB back out!
if (! MFS()) {
if (! MFS() && ! WINDOWS()) {
dbmclose(%PWDDB);
}
os_accounts_end()
if (WINDOWS());
#
# Create sfs_users file and populate it with public SFS keys
......
......@@ -84,14 +84,14 @@ if (MFS()) {
"rc.rpms", "rc.startcmd");
}
elsif (WINDOWS()) {
@bootscripts = ("rc.misc", "rc.localize", "rc.keys",
# Do accounts first so we have passwords for Samba.
"rc.accounts","rc.mounts");
##"rc.topomap",
##"rc.route", "rc.tunnels", "rc.ifconfig", "rc.delays",
##"rc.hostnames", "rc.syncserver", "rc.trafgen",
##"rc.tarfiles", "rc.rpms", "rc.progagent", "rc.linkagent",
##"rc.startcmd", "rc.simulator");
@bootscripts = ("rc.misc", #"rc.localize",
"rc.keys", "rc.mounts",
"rc.accounts" ##, "rc.topomap",
##"rc.route", "rc.ifconfig",
##"rc.hostnames", ##"rc.syncserver", "rc.progagent",
##"rc.tarfiles", "rc.rpms",
##"rc.startcmd"
);
}
else {
@bootscripts = ("rc.misc", "rc.localize", "rc.keys", "rc.mounts",
......
......@@ -166,12 +166,12 @@ sub doboot()
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
# server. All that's left is to wrap the //fs names in symlinks.
if (WINDOWS()) {
while (($remote, $local) = each %mounts) {
my $host="fs";
my $host = "fs";
print "Link $local to //$host\n";
os_samba_mount($local, $host, 0);
}
......
......@@ -60,12 +60,22 @@ bin-install: dir-install
# These are found in the /share/windows directory.
$(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)/usrtogrp.exe
etc-install: dir-install sysetc-remove sysetc-install
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:
rm -f /etc/ssh_host*key.user /etc/shells
script-install: dir-install $(SCRIPTS)
$(INSTALL) -m 755 $(SRCDIR)/liblocsetup.pm $(BINDIR)/liblocsetup.pm
......
......@@ -15,8 +15,9 @@ use Exporter;
qw ( $CP $LN $RM $CHOWN $EGREP
$NFSMOUNT $UMOUNT $SFCMOUNT $SFCUMOUNT $NTS $NET
$TMPASSWD $SFSSD $SFSCD $RPMCMD
os_account_cleanup os_ifconfig_line os_etchosts_line
os_setup os_groupadd os_useradd os_userdel os_usermod os_mkdir
os_account_cleanup os_accounts_start os_accounts_end
os_ifconfig_line os_etchosts_line
os_setup os_groupadd os_groupgid os_useradd os_userdel os_usermod os_mkdir
os_ifconfig_veth
os_routing_enable_forward os_routing_enable_gated
os_routing_add_manual os_routing_del_manual os_homedirdel
......@@ -75,11 +76,7 @@ $BASH = "/bin/bash";
#
# These are not exported
#
my $USERADD = "/usr/sbin/useradd";
my $USERDEL = "/usr/sbin/userdel";
my $USERMOD = "/usr/sbin/usermod";
my $GROUPADD = "/usr/sbin/groupadd";
my $GROUPDEL = "/usr/sbin/groupdel";
my $ADDUSERS = "$BINDIR/addusers.exe";
my $IFCONFIGBIN = "/sbin/ifconfig";
my $IFCONFIG = "$IFCONFIGBIN %s inet %s netmask %s";
my $IFC_1000MBS = "1000baseTx";
......@@ -102,17 +99,24 @@ sub os_account_cleanup()
unlink @LOCKFILES;
# Generate the CygWin password and group files from the registry users.
# Make root's UID zero.
printf STDOUT "Resetting passwd and group files\n";
if (system("$MKPASSWD -l | \
$AWK -F: '/^root:/{\$3=\"0\"} {OFS=\":\"; print}' > /etc/passwd") != 0) {
print "Resetting the CygWin passwd and group files.\n";
my $cmd = "$MKPASSWD -l | $AWK -F: '" . 'BEGIN{ OFS=":" } ';
# 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";
return -1;
}
# Make wheel an alias for Administrators.
if (system("mkgroup -l | \
$AWK '/^Administrators:/{print \"wheel\" substr(\$0, index(\$0,\":\"))} \
{print}' > /etc/group") != 0) {
$cmd = "mkgroup -l | $AWK '";
# Make a duplicate group line that is a wheel alias for Administrators.
$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";
return -1;
}
......@@ -341,6 +345,54 @@ sub os_etchosts_line($$$)
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
#
......@@ -348,7 +400,10 @@ sub os_groupadd($$)
{
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($)
{
my($group) = @_;
return system("$GROUPDEL $group");
# Unimplemented.
return -1;
}
#
......@@ -368,7 +424,8 @@ sub os_userdel($)
{
my($login) = @_;
return system("$USERDEL $login");
# Unimplemented.
return -1;
}
#
......@@ -378,6 +435,9 @@ sub os_usermod($$$$$$)
{
my($login, $gid, $glist, $pswd, $root, $shell) = @_;
# Unimplemented.
return -1;
if ($root) {
$glist = join(',', split(/,/, $glist), "root");
}
......@@ -397,21 +457,76 @@ sub os_useradd($$$$$$$$$)
{
my($login, $uid, $gid, $pswd, $glist, $homedir, $gcos, $root, $shell) = @_;
if ($root) {
$glist = join(',', split(/,/, $glist), "root");
}
if ($glist ne "") {
$glist = "-G $glist";
# Groups have to be created before we can add members.
my $gname = $groupsByGid{$gid};
warn "*** Missing group name for gid $gid.\n"
if (!$gname);
$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.
$shell = MapShell($shell);
if (system("$USERADD -M -u $uid -g $gid $glist -p '$pswd' ".
"-d $homedir -s $shell -c \"$gcos\" $login") != 0) {
warn "*** WARNING: $USERADD $login error.\n";
# Use the leading 8 chars of the Unix MD5 passwd hash as a known random
# password, both here and in Samba. Skip over a "$1$" prefix.
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 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($)
return $fullpath;
}
sub os_samba_mount($$)
sub os_samba_mount($$$)
{
my ($local, $host, $verbose) = @_;
......
......@@ -12,15 +12,19 @@ chmod -f g+w $logfile
# Enable WINDOWS() in libsetup.pm .
iscygwin=/etc/emulab/iscygwin
chmod -f g+w /etc/emulab
chmod -f g+w $iscygwin
uname -r > $iscygwin
chmod g+w $iscygwin
chmod -f g-w /etc/emulab
# Set up for autologin as the swapin user.
tmcc=/usr/local/etc/emulab/tmcc.bin
swapper=`$tmcc creator | sed 's|.*SWAPPER=\([^ ]*\).*|\1|'`
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
cat <<EOF > $autologin
Windows Registry Editor Version 5.00
......@@ -30,7 +34,11 @@ Windows Registry Editor Version 5.00
"DefaultUserName"="$swapper"
EOF
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.
nodeid=`$tmcc nodeid`
......
......@@ -18,19 +18,22 @@ if [ $user = root ]; then
fi
# Shares are local to the Win32 login session context.
# We must process a user name and password for the first one to be opened.
###host=fs
host=pc88
# We must process a user name and password for the first one to be opened, and it
# has to go onto a drive letter. After that, we can use UNC //host paths freely.
host=fs
pswd=`tmcc accounts | awk '/LOGIN='$user' /{print substr($0,index($0," PSWD=")+9,8)}'`
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
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 ""
if [[ "$chr" != [yY] ]]; then break; fi
if [[ ! -z "$chr" && "$chr" != [yY] ]]; then break; fi
echo ""
echo "Re-trying Connection to //$host as $user."
echo "Re-trying connection to //$host as $user."
done
# Show network mount status.
net use
# Set the homedir for ssh in case we don't get through rc.mounts .
ln -f -s //$host/$user /users/$user
......
/bin/sh
/bin/csh
/bin/tcsh
/bin/bash
......@@ -17,19 +17,24 @@
# If you're logged in via rdesktop, see the Users tab in Task Manager.
pidfile=/var/run/sshd.pid
upidfile=$pidfile.user
running=
if [ -e $pidfile ]; then
if [ -e $upidfile ]; then
# Check that the process ID actually refers to a running process.
pid=`cat $pidfile`
pid=`cat $upidfile`
if ( kill -0 $pid >& /dev/null ); then
running=yes
fi
fi
if [ $running ]; then
# Kill a previous copy of sshd, so we can run one as this user.
echo "Killing previous sshd daemon."
ps -ef | awk '$2=='$pid'{print}'
kill $pid
if ( ps -u SYSTEM | grep -q "^ *$pid " ); then
echo "Ignoring SYSTEM sshd."
else
# 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
# 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
echo "Starting new sshd daemon as $user."
(CYGWIN="ntsec tty" /usr/sbin/sshd -p 2222 -o "UsePrivilegeSeparation no" \
-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 @@
# Stop the current the SSH daemon.
pidfile=/var/run/sshd.pid
upidfile=$pidfile.user
running=
if [ -e $pidfile ]; then
if [ -e $upidfile ]; then
# Check that the process ID actually refers to a running process.
pid=`cat $pidfile`
pid=`cat $upidfile`
if ( kill -0 $pid >& /dev/null ); then
running=yes
fi
fi
if [ $running ]; then
echo "Killing sshd daemon."
ps -ef | awk '$2=='$pid'{print}'
kill $pid
if ( ps -u SYSTEM | grep -q "^ *$pid " ); then
echo "Ignoring SYSTEM sshd."
else
echo "Killing sshd daemon."
ps -ef | awk '$2=='$pid'{print}'
kill $pid
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