...
 
Commits (5542)

Too many changes to show.

To preserve performance only 129 of 129+ files are displayed.

......@@ -10,6 +10,7 @@ clientside/os/imagezip/fat
clientside/os/imagezip/ntfs/liblocale
clientside/lib/event/event_wrap*
clientside/tmcc/cygwinxp/site-lisp
clientside/tmcc/freebsd/init
clientside/tmcc/plab
os/shd
www/cvsweb
......@@ -49,3 +50,8 @@ LGPL-COPYING
AGPL-COPYING
TODO.plab
MOVED-TO-WIKI
VERSION
protogeni/flack/js/forge
protogeni/flack/src/com/hurlant
protogeni/flack/src/com/mattism
protogeni/protogeniflash/src/com/mattism
#
# Copyright (c) 2000-2014 University of Utah and the Flux Group.
# Copyright (c) 2000-2017 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -32,6 +32,7 @@ PELABSUPPORT = @PELABSUPPORT@
PGENISUPPORT = @PROTOGENI_SUPPORT@
ISMAINSITE = @TBMAINSITE@
SPEWFROMOPS = @SPEWFROMOPS@
MOBILESUPPORT = @MOBILESUPPORT@
SYSTEM := $(shell uname -s)
include Makeconf
......@@ -52,10 +53,10 @@ SUBDIRS = \
clientside/lib \
db assign www @optional_subdirs@ clientside ipod security sensors \
pxe tbsetup account tmcd utils backend tip ipod vis \
sensors os xmlrpc install/newnode_sshkeys mote tools/whol \
tools/svn wiki bugdb collab node_usage install
sensors os xmlrpc autofs install/newnode_sshkeys \
tools/svn collab/exp-vis node_usage install
ifeq ($(ISMAINSITE),1)
SUBDIRS += tools/rmanage
SUBDIRS += tools/rmanage tools/whol
endif
ifeq ($(PGENISUPPORT),1)
SUBDIRS += protogeni apt
......@@ -107,7 +108,8 @@ boss-install-noupdatecheck: install-schemacheck \
install-setbuildinfo
# Only the checks:
install-checks: install-updatecheck \
install-checks: \
install-updatecheck \
install-schemacheck \
install-sitevarscheck \
install-dbfillcheck install-genischemacheck
......@@ -127,10 +129,10 @@ post-install:
ifeq ($(EVENTSYS),1)
@$(MAKE) -C event post-install
endif
@$(MAKE) -C mote post-install
ifeq ($(MOBILESUPPORT),1)
@$(MAKE) -C mobile
endif
@$(MAKE) -C tools post-install
@$(MAKE) -C wiki post-install
@$(MAKE) -C bugdb post-install
@$(MAKE) -C collab post-install
@$(MAKE) -C utils post-install
ifeq ($(NODE_USAGE_SUPPORT),1)
......@@ -174,6 +176,7 @@ opsfs-install: ops-install fs-install
@echo "Combined ops/fs install done."
install-mkdirs:
-mkdir -p $(INSTALL_TOPDIR)/db
-mkdir -p $(INSTALL_TOPDIR)/locks
-mkdir -p $(INSTALL_TOPDIR)/log
-mkdir -p $(INSTALL_TOPDIR)/log/mysql
......@@ -232,6 +235,8 @@ endif
subboss:
@$(MAKE) -C clientside subboss
@$(MAKE) -C tbsetup subboss
@$(MAKE) -C db subboss
@$(MAKE) -C os subboss
ifneq ($(SYSTEM),CYGWIN_NT-5.1)
@$(MAKE) -C tip client
......@@ -240,6 +245,7 @@ endif
subboss-install: subboss
@$(MAKE) -C clientside subboss-install
@$(MAKE) -C tbsetup subboss-install
@$(MAKE) -C os subboss-install
ifneq ($(SYSTEM),CYGWIN_NT-5.1)
@$(MAKE) -C tip client-install
......@@ -286,39 +292,27 @@ mfsoscheck:
fi
mfs: mfsoscheck
@$(MAKE) -C os mfs
@$(MAKE) -C clientside mfs
mfs-nostatic: mfsoscheck
@NOSTATIC=1 $(MAKE) -C os mfs
@NOSTATIC=1 $(MAKE) -C clientside mfs
mfs-install: destdircheck mfs client-mkdirs
@$(MAKE) -C os mfs-install
@$(MAKE) -C clientside mfs-install
mfs-nostatic-install: destdircheck mfs-nostatic client-mkdirs
@$(MAKE) -C os mfs-install
@$(MAKE) -C clientside mfs-install
frisbee-mfs: mfsoscheck
@$(MAKE) -C cdrom/groklilo client
@$(MAKE) -C os frisbee-mfs
@$(MAKE) -C clientside frisbee-mfs
frisbee-mfs-nostatic: mfsoscheck
@NOSTATIC=1 $(MAKE) -C cdrom/groklilo client
@NOSTATIC=1 $(MAKE) -C os frisbee-mfs
@NOSTATIC=1 $(MAKE) -C clientside frisbee-mfs
frisbee-mfs-install: destdircheck frisbee-mfs
@CLIENT_BINDIR=/etc/testbed $(MAKE) -e -C cdrom/groklilo client-install
@$(MAKE) -C os frisbee-mfs-install
@$(MAKE) -C clientside frisbee-mfs-install
frisbee-mfs-nostatic-install: destdircheck frisbee-mfs-nostatic
@CLIENT_BINDIR=/etc/testbed $(MAKE) -e -C cdrom/groklilo client-install
@$(MAKE) -C os frisbee-mfs-install
@$(MAKE) -C clientside frisbee-mfs-install
newnode-mfs: mfsoscheck
......@@ -431,6 +425,19 @@ ifeq ($(PGENISUPPORT),1)
endif
@echo "Done"
BRANCHCHECK=
BRANCHECHO= @echo "Skipping branch check since not the Mothership"
ifeq ($(ISMAINSITE),1)
ifeq ($(TBROOT),/usr/testbed)
BRANCHCHECK= cd $(SRCDIR) && \
git status --porcelain -s -b | head -1 | grep -q -s current
BRANCHECHO= @echo "Checking to make sure you are on the mothership branch"
endif
endif
install-branchcheck:
$(BRANCHECHO)
$(BRANCHCHECK)
# We use separate src and obj trees in Emulab, so the traditional distclean to
# clean "made" files from a mingled source-and-obj tree is unnecessary.
# However, this may be useful if you mistakenly configure and make a src tree.
......
#
# Copyright (c) 2000-2012 University of Utah and the Flux Group.
# Copyright (c) 2000-2012, 2016 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -108,6 +108,21 @@ distclean: default-clean
default-clean:
rm -f GNUmakefile
# This is to avoid warnings about duplicate targets.
default-install-notusing:
ifeq ($(ISMAINSITE),1)
ifeq ($(TBROOT),/usr/testbed)
(cd $(SRCDIR) ; \
git status --porcelain -s -b | head -1 | grep -q -s current)
else
/usr/bin/true
endif
else
/usr/bin/true
endif
#install: default-install
#
# Where to find source files.
# Using specific patterns instead of the catch-all VPATH variable
......
#
# Copyright (c) 2000-2012 University of Utah and the Flux Group.
# Copyright (c) 2000-2016 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -44,6 +44,7 @@ export JAR = @JAR@
prefix = @prefix@
exec_prefix = @exec_prefix@
ISMAINSITE = @TBMAINSITE@
TBROOT = @prefix@
TBDEFS = @TBDEFS@
TBDBNAME = @TBDBNAME@
......@@ -120,4 +121,4 @@ MERGE_BUILD_SANDBOX = @MERGE_BUILD_SANDBOX@
EXP_VIS_SUPPORT = @EXP_VIS_SUPPORT@
TESTBED_LIBSRCDIR = ${TESTBED_SRCDIR}/clientside/lib
TESTBED_LIBOBJDIR = ${OBJDIR}/clientside/lib
TESTBED_IMAGEZIPSRCDIR = ${OBJDIR}/clientside/os/imagezip
TESTBED_IMAGEZIPSRCDIR = ${TESTBED_SRCDIR}/clientside/os/imagezip
#!/usr/bin/perl -w
#
# Copyright (c) 2010-2014 University of Utah and the Flux Group.
# Copyright (c) 2010-2018 University of Utah and the Flux Group.
#
# {{{GENIPUBLIC-LICENSE
#
......@@ -31,20 +31,28 @@ use strict;
use English;
use Getopt::Std;
use Data::Dumper;
use Fcntl;
#
# Setup accounts/projects/group stuff on ops/fs. This is installed on
# op/fs and invoked from boss by tbaccy and the proj/group scripts/
# op/fs and invoked from boss by tbacct and the proj/group scripts.
#
sub usage()
{
print "Usage: accountsetup adduser ...\n";
print " accountsetup deluser ...\n";
print " accountsetup moduser ...\n";
print " accountsetup setgroups ...\n";
print " accountsetup chpass ...\n";
print " accountsetup addproject ...\n";
print " accountsetup addgroup ...\n";
print " accountsetup delproject ...\n";
print " accountsetup delgroup ...\n";
print " accountsetup checkdotfiles ...\n";
print " accountsetup createsshkey ...\n";
print " accountsetup dropfile ...\n";
print " accountsetup deactivateuser ...\n";
print " accountsetup reactivateuser ...\n";
exit(1);
}
my $optlist = "dnf";
......@@ -52,23 +60,41 @@ my $debug = 0;
my $force = 0;
my $impotent = 0;
# XXX make this a sitevar
my $RENAMEDIRS = 1;
#
# Configure variables
#
my $TB = "@prefix@";
my $USERPATH = "$TB/bin";
my $WITHZFS = @WITHZFS@;
my $ZFS_NOEXPORT = @ZFS_NOEXPORT@;
my $OURDOMAIN = "@OURDOMAIN@";
my $ZFS_ROOT = "@ZFS_ROOT@";
my $ZFS_QUOTA_USER = "@ZFS_QUOTA_USER@";
my $ZFS_QUOTA_PROJECT = "@ZFS_QUOTA_PROJECT@";
my $ZFS_QUOTA_GROUP = "@ZFS_QUOTA_GROUP@";
my $ZFS_QUOTA_USER_X = "@ZFS_QUOTA_USER_X@";
my $ZFS_QUOTA_PROJECT_X = "@ZFS_QUOTA_PROJECT_X@";
my $ZFS_QUOTA_GROUP_X = "@ZFS_QUOTA_GROUP_X@";
my $PW = "/usr/sbin/pw";
my $USERADD = "/usr/sbin/pw useradd";
my $USERDEL = "/usr/sbin/pw userdel";
my $USERMOD = "/usr/sbin/pw usermod";
my $GROUPADD = "/usr/sbin/pw groupadd";
my $GROUPDEL = "/usr/sbin/pw groupdel";
my $CHPASS = "/usr/bin/chpass";
my $CHOWN = "/usr/sbin/chown";
my $CHMOD = "/bin/chmod";
my $MKDIR = "/bin/mkdir";
my $NOLOGIN = "/sbin/nologin";
my $MV = "/bin/mv";
my $ZFS = "/sbin/zfs";
my $KEYGEN = "/usr/bin/ssh-keygen";
my $SKEL = "/usr/share/skel";
my $PIDFILE = "/var/run/mountd.pid";
my $TSFILE = "/var/run/mountd.ts";
# XXX
my $NOSUCHUSER = 67;
......@@ -80,22 +106,48 @@ my $USEREXISTS = 65;
use lib "@prefix@/lib";
use libtestbed;
# Defined in libtestbed;
# Generic (mounted) names for filesystems
my $USERROOT = USERROOT();
my $PROJROOT = PROJROOT();
my $GROUPROOT = GROUPROOT();
my $SCRATCHROOT = SCRATCHROOT();
# XXX we need the real fs mountpoints too
my $FSUSERROOT = "@FSDIR_USERS@";
my $FSPROJROOT = "@FSDIR_PROJ@";
my $FSGROUPROOT = "@FSDIR_GROUPS@";
my $FSSCRATCHROOT = "@FSDIR_SCRATCH@";
# Project subdir list
my @DIRLIST = ("exp", "images", "logs", "deltas", "tarfiles", "rpms",
"groups", "tiplogs", "images/sigs", "templates");
# Groups subdir list
my @GDIRLIST = ("exp", "images", "logs", "tarfiles", "rpms", "tiplogs");
#
# Function prototypes
#
sub AddUser();
sub DeleteUser();
sub SetGroups();
sub ModifyUser();
sub ChangePassword();
sub AddProject();
sub AddGroup();
sub DelProject();
sub DelGroup();
sub DropFile();
sub CheckDotFiles();
sub CreateSSHKey();
sub ReactivateUser();
sub DeactivateUser();
sub fatal($);
sub SetDotGroup($$);
sub ZFSexists($);
sub MakeDir($$);
sub WhackDir($$);
sub mysystem($);
sub runBusyLoop($);
#
# Check args.
......@@ -134,6 +186,14 @@ SWITCH: for ($cmd) {
ModifyUser();
last SWITCH;
};
/^setgroups$/ && do {
SetGroups();
last SWITCH;
};
/^chpass$/ && do {
ChangePassword();
last SWITCH;
};
/^addproject$/ && do {
AddProject();
last SWITCH;
......@@ -150,11 +210,34 @@ SWITCH: for ($cmd) {
DelGroup();
last SWITCH;
};
/^dropfile$/ && do {
DropFile();
last SWITCH;
};
/^checkdotfiles$/ && do {
CheckDotFiles();
last SWITCH;
};
/^createsshkey$/ && do {
CreateSSHKey();
last SWITCH;
};
/^deactivateuser$/ && do {
DeactivateUser();
last SWITCH;
};
/^reactivateuser$/ && do {
ReactivateUser();
last SWITCH;
};
# Default
usage();
}
exit(0);
#
# Usage: adduser username unix_uid full_name homedir unix_gid shell [ phash ]
#
sub AddUser()
{
if (@ARGV < 6) {
......@@ -167,53 +250,62 @@ sub AddUser()
my $hdir = shift(@ARGV);
my $gid = shift(@ARGV);
my $shell = shift(@ARGV);
my $hash = (@ARGV ? shift(@ARGV) : undef);
if ($WITHZFS) {
my $path = "${ZFS_ROOT}${hdir}";
if (!ZFSexists($path)) {
system("$ZFS create -o quota=${ZFS_QUOTA_USER} $path");
if ($?) {
fatal("Could not create ZFS $path");
}
if (! -d "$hdir") {
# XXX we only handle homedirs of the form /users/$user here...
if ($hdir ne "$USERROOT/$user" || MakeDir($USERROOT, $user)) {
fatal("Could not create $user homedir $hdir");
}
}
if (system("egrep -q -s '^${user}:' /etc/passwd") &&
system("$USERADD $user -u $uid -c \"$name\" ".
"-k $SKEL -h - -m -d $hdir -g $gid -s $shell")) {
if (mysystem("egrep -q -s '^${user}:' /etc/passwd") &&
runBusyLoop("$USERADD $user -u $uid -c \"$name\" ".
"-k $SKEL -h - -d $hdir -g $gid -s $shell")) {
if (($? >> 8) != $USEREXISTS) {
fatal("$USERADD: could not add account");
}
}
if ($WITHZFS) {
#
# Since the directory exists before the useradd call, the skeleton
# files are not copied in. Do that now.
#
if (! -e "$hdir/.cshrc") {
opendir(DIR, "$SKEL") or
fatal("Unable to open skeleton directory");
while (my $file = readdir(DIR)) {
if ($file =~ /^dot(.*)$/) {
system("/bin/cp -fp $SKEL/$file $hdir/$1") == 0
or fatal("Could not copy $SKEL/$file to $hdir/$1");
}
#
# Since we do not populate the new homedir with the useradd call,
# we need to copy the skeleton files over.
#
if (! -e "$hdir/.cshrc") {
opendir(DIR, "$SKEL") or
fatal("Unable to open skeleton directory");
while (my $file = readdir(DIR)) {
if ($file =~ /^dot(.*)$/) {
mysystem("/bin/cp -fp $SKEL/$file $hdir/$1") == 0
or fatal("Could not copy $SKEL/$file to $hdir/$1");
}
}
#
# And for the same reason, need to chown/chgrp everything.
# And set the owner and group right on everything
#
system("/usr/sbin/chown -R $user:$gid $hdir") == 0
mysystem("/usr/sbin/chown -R $user:$gid $hdir") == 0
or fatal("Could not chown $hdir");
}
if (defined($hash) &&
system("$CHPASS -p '$hash' $user")) {
fatal("Could not initialize password");
#
# Some directories we need, with proper owner/group/mode
#
foreach my $dir (".ssl", ".ssh") {
if (! -e "$hdir/$dir" &&
!mkdir("$hdir/$dir", 0700)) {
fatal("Could not make directory '$hdir/$dir': $!");
}
mysystem("$CHOWN -R $user:$gid $hdir/$dir") == 0
or fatal("Could not chown $hdir/$dir to $user:$gid");
chmod(0700, "$hdir/$dir")
or fatal("Could not chmod '$hdir/$dir' to 0700: $!");
}
return 0;
}
#
# Usage: deluser username homedir
#
sub DeleteUser()
{
if (@ARGV != 2) {
......@@ -222,84 +314,281 @@ sub DeleteUser()
my $user = shift(@ARGV);
my $hdir = shift(@ARGV);
if (system("$USERDEL $user")) {
#
# Note that this does NOT remove the user's homedir.
# We remove/rename it below...
#
if (runBusyLoop("$USERDEL $user")) {
if (($? >> 8) != $NOSUCHUSER) {
fatal("Could not remove user $user");
}
}
# XXX we only handle homedirs of the form /users/$user here...
if ($hdir ne "$USERROOT/$user" ||
(-e $hdir && WhackDir($USERROOT, $user))) {
fatal("Could not destroy $user homedir $hdir");
}
return 0;
}
#
# Usage: moduser username shell full_name
#
sub ModifyUser()
{
if (@ARGV != 3) {
fatal("moduser: Wrong number of arguments");
}
my $user = shift(@ARGV);
my $shell = shift(@ARGV);
my $name = shift(@ARGV);
if (runBusyLoop("$USERMOD $user -c \"$name\" -s $shell")) {
fatal("$USERMOD: could not modify account");
}
return 0;
}
#
# Usage: username group1 [ group2 ... groupN ]
# XXX this is specific to what is required by setgroups.
#
sub SetGroups()
{
if (@ARGV < 2) {
fatal("setgroups: Wrong number of arguments");
}
my $user = shift(@ARGV);
my $pgroup = shift(@ARGV);
my $grouplist = "''";
if (@ARGV > 0) {
$grouplist = "-G '" . join(',', @ARGV) . "'";
}
if (runBusyLoop("$USERMOD $user -g $pgroup $grouplist")) {
fatal("Could not modify user $user to add groups!\n");
}
SetDotGroup($user, $pgroup);
return 0;
}
sub ChangePassword()
{
if (@ARGV != 2) {
fatal("chpass: Wrong number of arguments");
}
my $user = shift(@ARGV);
my $hash = shift(@ARGV);
if (runBusyLoop("$CHPASS -p '$hash' $user")) {
fatal("Could not change password");
}
return 0;
}
#
# Usage: deactivate username
#
sub DeactivateUser()
{
if (@ARGV != 1) {
fatal("deactivateuser: Wrong number of arguments");
}
my $user = shift(@ARGV);
if ($WITHZFS) {
my $path = "${ZFS_ROOT}${hdir}";
if (ZFSexists($path)) {
system("$ZFS unmount -f $path");
system("$ZFS destroy $path");
if ($?) {
fatal("Could not destroy ZFS $path");
}
my $zfsdir = $ZFS_ROOT . USERROOT() . "/$user";
if (ZFSexists($zfsdir) &&
mysystem("$ZFS set mountpoint=none $zfsdir")) {
fatal("Could not set ZFS dir $zfsdir to mountpoint=none");
}
}
if (runBusyLoop("$USERMOD $user -d /var/empty -s $NOLOGIN")) {
fatal("Could not set shell to $NOLOGIN");
}
return 0;
}
sub ModifyUser()
#
# Usage: reactivate username
#
# The shell is changed via ModifyUser (we do not know the correct
# shell here), this is just for ZFS.
#
sub ReactivateUser()
{
fatal("moduser: Not implemented yet");
if (@ARGV != 1) {
fatal("reactivateuser: Wrong number of arguments");
}
my $user = shift(@ARGV);
my $hdir = USERROOT() . "/$user";
if ($WITHZFS) {
my $zfsdir = $ZFS_ROOT . USERROOT() . "/$user";
if (ZFSexists($zfsdir) &&
mysystem("$ZFS set mountpoint=$hdir $zfsdir")) {
fatal("Could not set ZFS dir $zfsdir to mountpoint=$hdir");
}
}
if (runBusyLoop("$USERMOD $user -d $hdir")) {
fatal("Could not set home directory back to $hdir");
}
#
# Make dot files are in the right group, since while the user was
# inactive, we skipped doing that cause the home dir was unmounted
# (ZFS). Need the current default group for that.
#
my (undef,undef,undef,$gid) = getpwnam($user);
if (!defined($gid)) {
fatal("Could not get gid for $user");
}
SetDotGroup($user,$gid);
return 0;
}
#
# Usage: addproject projname unix_gname unix_gid unix_uid
#
sub AddProject()
{
if (@ARGV != 3) {
if (@ARGV != 4) {
fatal("addproject: Wrong number of arguments");
}
my $name = shift(@ARGV);
my $unix_name = shift(@ARGV);
my $gid = shift(@ARGV);
my $unix_gid = shift(@ARGV);
my $unix_uid = shift(@ARGV);
if ($WITHZFS) {
my $path = "${ZFS_ROOT}${PROJROOT}/$name";
if (!ZFSexists($path)) {
system("$ZFS create -o quota=${ZFS_QUOTA_PROJECT} $path");
if ($?) {
fatal("Could not create ZFS $path");
}
# Create the project unix group
if (mysystem("egrep -q -s '^${unix_name}:' /etc/group")) {
print "Adding group $unix_name ...\n";
if (runBusyLoop("$GROUPADD $unix_name -g $unix_gid")) {
fatal("Could not add group $unix_name ($unix_gid)!\n");
}
$path = "${ZFS_ROOT}${GROUPROOT}/$name";
if (!ZFSexists($path)) {
system("$ZFS create -o quota=${ZFS_QUOTA_GROUP} $path");
if ($?) {
fatal("Could not create ZFS $path");
}
}
# Create the /proj directory
my $path = "$PROJROOT/$name";
if (! -d "$path" && MakeDir($PROJROOT, $name)) {
fatal("Could not make directory '$path'");
}
if (! chmod(0770, "$path")) {
fatal("Could not chmod '$path' to 0770: $!");
}
if (! chown($unix_uid, $unix_gid, "$path")) {
fatal("Could not chown '$path' to $unix_uid/$unix_gid: $!");
}
# Create required /proj subdirs
foreach my $dir (@DIRLIST) {
$path = "$PROJROOT/$name/$dir";
if (! -d "$path" && !mkdir("$path", 0770)) {
fatal("Could not make directory '$path': $!");
}
if (! chmod(0770, "$path")) {
fatal("Could not chmod '$path' to 0770: $!");
}
if (! chown($unix_uid, $unix_gid, "$path")) {
fatal("Could not chown '$path' to $unix_uid/$unix_gid: $!");
}
}
if (system("egrep -q -s '^${unix_name}:' /etc/group")) {
print "Adding group $unix_name ...\n";
# Create the /groups directory
$path = "$GROUPROOT/$name";
if (! -d "$path" && MakeDir($GROUPROOT, $name)) {
fatal("Could not make directory '$path'");
}
if (! chmod(0770, "$path")) {
fatal("Could not chmod '$path' to 0770: $!");
}
if (! chown($unix_uid, $unix_gid, "$path")) {
fatal("Could not chown '$path' to $unix_uid/$unix_gid: $!");
}
if (system("$GROUPADD $unix_name -g $gid")) {
fatal("Could not add group $unix_name ($gid)!\n");
# Create a symlink for the default group
$path = "$GROUPROOT/$name/$name";
if (! -e "$path") {
if (mysystem("ln -s $PROJROOT/$name $path")) {
fatal("Could not symlink $PROJROOT/$name to $path");
}
}
# Finally, create /scratch dir if supported
if ($SCRATCHROOT) {
$path = "$SCRATCHROOT/$name";
if (! -d "$path" && MakeDir($SCRATCHROOT, $name)) {
fatal("Could not make directory '$path'");
}
if (! chmod(0770, "$path")) {
fatal("Could not chmod '$path' to 0770: $!");
}
if (! chown($unix_uid, $unix_gid, "$path")) {
fatal("Could not chown '$path' to $unix_uid/$unix_gid: $!");
}
}
return 0;
}
#
# Usage: addgroup groupname unix_gname unix_gid unix_uid projname
#
sub AddGroup()
{
if (@ARGV != 3) {
if (@ARGV != 5) {
fatal("addgroup: Wrong number of arguments");
}
my $name = shift(@ARGV);
my $unix_name = shift(@ARGV);
my $gid = shift(@ARGV);
my $unix_gid = shift(@ARGV);
my $unix_uid = shift(@ARGV);
my $projname = shift(@ARGV);
if (system("egrep -q -s '^${unix_name}:' /etc/group")) {
# Create the group unix group
if (mysystem("egrep -q -s '^${unix_name}:' /etc/group")) {
print "Adding group $unix_name ...\n";
if (system("$GROUPADD $unix_name -g $gid")) {
fatal("Could not add group $unix_name ($gid)!\n");
if (runBusyLoop("$GROUPADD $unix_name -g $unix_gid")) {
fatal("Could not add group $unix_name ($unix_gid)!\n");
}
}
# Create the /groups/gid directory
my $path = "$GROUPROOT/$projname/$name";
# XXX note that this is always a regular directory, not a filesystem
if (! -d "$path" && !mkdir("$path", 0770)) {
fatal("Could not make directory '$path': $!");
}
if (! chmod(0770, "$path")) {
fatal("Could not chmod '$path' to 0770: $!");
}
if (! chown($unix_uid, $unix_gid, "$path")) {
fatal("Could not chown '$path' to $unix_uid/$unix_gid: $!");
}
# Create required /groups/gid subdirs
foreach my $dir (@GDIRLIST) {
$path = "$GROUPROOT/$projname/$name/$dir";
if (! -d "$path" && !mkdir("$path", 0770)) {
fatal("Could not make directory '$path': $!");
}
if (! chmod(0770, "$path")) {
fatal("Could not chmod '$path' to 0770: $!");
}
if (! chown($unix_uid, $unix_gid, "$path")) {
fatal("Could not chown '$path' to $unix_uid/$unix_gid: $!");
}
}
return 0;
}
#
# Usage: delproject projname unix_gname
#
sub DelProject()
{
if (@ARGV != 2) {
......@@ -308,57 +597,220 @@ sub DelProject()
my $name = shift(@ARGV);
my $unix_name = shift(@ARGV);
if ($WITHZFS) {
my $path = "${ZFS_ROOT}${PROJROOT}/$name";
if (ZFSexists($path)) {
system("$ZFS unmount -f $path");
system("$ZFS destroy $path");
if ($?) {
fatal("Could not destroy ZFS $path");
}
}
$path = "${ZFS_ROOT}${GROUPROOT}/$name";
if (ZFSexists($path)) {
system("$ZFS unmount -f $path");
system("$ZFS destroy $path");
if ($?) {
fatal("Could not destroy ZFS $path");
}
}
if ((-d "$PROJROOT/$name" && WhackDir($PROJROOT, $name)) ||
(-d "$GROUPROOT/$name" && WhackDir($GROUPROOT, $name)) ||
($SCRATCHROOT && -d "$SCRATCHROOT/$name" &&
WhackDir($SCRATCHROOT, $name))) {
fatal("Could not destroy project '$name' related directories");
}
if (system("egrep -q -s '^${unix_name}:' /etc/group") == 0) {
if (mysystem("egrep -q -s '^${unix_name}:' /etc/group") == 0) {
print "Deleting project $unix_name ...\n";
if (system("$GROUPDEL $unix_name")) {
if (runBusyLoop("$GROUPDEL $unix_name")) {
fatal("Could not delete group $unix_name!\n");
}
}
return 0;
}
#
# Usage: delgroup groupname unix_gname projname
#
sub DelGroup()
{
if (@ARGV != 2) {
if (@ARGV != 3) {
fatal("delgroup: Wrong number of arguments");
}
my $name = shift(@ARGV);
my $unix_name = shift(@ARGV);
my $projname = shift(@ARGV);
#
# XXX groups are different because they are a subdirectory under
# /groups/<pid>/.
#
if (-d "$GROUPROOT/$projname/$name" &&
WhackDir($GROUPROOT, "$projname/$name")) {
fatal("Could not destroy project group '$name' related directories");
}
if (system("egrep -q -s '^${unix_name}:' /etc/group") == 0) {
if (mysystem("egrep -q -s '^${unix_name}:' /etc/group") == 0) {
print "Deleting group $unix_name ...\n";
if (system("$GROUPDEL $unix_name")) {
if (runBusyLoop("$GROUPDEL $unix_name")) {
fatal("Could not delete group $unix_name!\n");
}
}
return 0;
}
sub fatal($) {
my ($msg) = @_;
#
# Drop a file into place. The file is piped into STDIN from boss.
#
sub DropFile()
{
if (@ARGV != 5) {
fatal("dropfile: Wrong number of arguments");
}
my $user = shift(@ARGV);
my $gid = shift(@ARGV);
my $mode = shift(@ARGV);
my $dir = shift(@ARGV);
my $fname = shift(@ARGV);
my $file = "$dir/$fname";
print STDERR "$msg\n";
exit(-1);
# Default the directory creation to 770. Might need to specify this too.
if (! -d "$dir" && mysystem("$MKDIR -m 770 -p $dir")) {
fatal("Could not make directory '$dir'");
}
#
# We want the file to have the proper mode before we try to write it,
# to avoid a race that allows someone to see the contents.
#
if (-e $file && mysystem("$MV -f $file ${file}.save")) {
fatal("Could not rename $file to ${file}.save");
}
sysopen(HANDLE, $file, O_WRONLY|O_CREAT|O_EXCL, 0600)
or fatal("sysopen $file: $!");
while (<STDIN>) {
print HANDLE $_;
}
close(HANDLE);
mysystem("$CHOWN $user:$gid $file") == 0
or fatal("Could not chown $file to $user:$gid");
mysystem("$CHMOD $mode $file") == 0
or fatal("Could not chmod '$file' to $mode");
return 0;
}
#
# Check the dot files.
#
sub CheckDotFiles()
{
if (@ARGV != 3) {
fatal("checkdotfiles: Wrong number of arguments");
}
my $user = shift(@ARGV);
my $gid = shift(@ARGV);
my $email = shift(@ARGV);
my $forward = "$USERROOT/$user/.forward";
my $cshrc = "$USERROOT/$user/.cshrc";
my $profile = "$USERROOT/$user/.profile";
# Just in case we got called before account created.
return 0
if (! -d "$USERROOT/$user");
#
# Set up a .forward file so that any email to them gets forwarded off.
#
print "Setting up .forward file for $user.\n";
sysopen(HANDLE, $forward, O_WRONLY|O_CREAT|O_TRUNC, 0600)
or fatal("sysopen $forward: $!");
print HANDLE "$email\n";
close(HANDLE);
mysystem("$CHOWN $user:$gid $forward") == 0
or fatal("Could not chown $forward to $user:$gid");
mysystem("$CHMOD 644 $forward") == 0
or fatal("Could not chmod '$forward' to 644");
#
# Add testbed path to .cshrc and .profile.
# Plus a conditional Cygwin section for the Windows system path.
#
my $cpathstr = "set path = ($USERPATH \$path)\n" .
'if ( `uname -s` =~ CYGWIN* ) then' . "\n" .
' setenv PATH "${PATH}:/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS"' . "\n" .
'endif';
if (-e $cshrc && system("egrep -q -s '$USERPATH' $cshrc")) {
system("echo '$cpathstr' >> $cshrc");
}
my $spathstr = "PATH=$USERPATH:\$PATH\n" .
'if [[ `uname -s` == CYGWIN* ]]; then' . "\n" .
' PATH="$PATH":/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS' . "\n" .
'fi';
if (-e $profile && system("egrep -q -s '$USERPATH' $profile")) {
system("echo '$spathstr' >> $profile");
}
return 0;
}
#
# Create ssh keys for user, sending back the pub part. This is a little
# incovenient since we generate two keys (V1 and V2) but can send back
# just one at a time via STDOUT (do not want to parse anything).
#
sub CreateSSHKey()
{
if (@ARGV != 3) {
fatal("createsshkey: Wrong number of arguments");
}
my $user = shift(@ARGV);
my $gid = shift(@ARGV);
my $type = shift(@ARGV);
my $sshdir = "$USERROOT/$user/.ssh";
my $sshkey = "$sshdir/";
if ($type eq "rsa1") {
$sshkey .= "identity";
}
elsif ($type eq "rsa") {
$sshkey .= "id_rsa";
}
else {
fatal("Bad key type: $type");
}
unlink($sshkey)
if (-e $sshkey);
#
# Since we send the key back via STDOUT, make sure all output
# goes to STDERR.
#
mysystem("$KEYGEN -t $type -P '' -f $sshkey ".
"-C '${type}" . "\@" . ${OURDOMAIN} . "' 1>&2") == 0
or fatal("Failure in ssh-keygen!");
mysystem("$CHOWN $user:$gid $sshkey ${sshkey}.pub") == 0
or fatal("Could not chown $sshkey to $user:$gid");
# Return the key via STDOUT to boss.
my $ident = `cat ${sshkey}.pub`;
print STDOUT $ident;
return 0;
}
#
# Make sure the users dot files and other critical files/dirs
# are in the correct group. I looked at the source code to
# chown, and it does not do anything to files that are already
# set correctly. Thank you chown.
#
sub SetDotGroup($$)
{
my ($user, $gid) = @_;
my @dots = (".login", ".profile", ".cshrc", ".ssl", ".ssh");
my $homedir = USERROOT() . "/$user";
if (! -e $homedir) {
print STDERR "$homedir does not exist, skipping dots chown\n";
return 0;
}
print "Changing dot files group for $user to $gid\n";
mysystem("$CHOWN $user:$gid $homedir") == 0
or fatal("Could not chown home dir to $user:$gid");
foreach my $dot (@dots) {
if (-e "$homedir/$dot") {
mysystem("$CHOWN -R $user:$gid $homedir/$dot") == 0
or fatal("Could not chown $homedir/$dot to $user:$gid");
}
}
}
#
......@@ -368,6 +820,281 @@ sub ZFSexists($)
{
my ($path) = @_;
system("$ZFS list $path >/dev/null 2>&1");
mysystem("$ZFS list $path >/dev/null 2>&1");
return ($? ? 0 : 1);
}
sub MakeDir($$)
{
my ($fs,$dir) = @_;
my ($cmd,$cmdarg,$path);
# XXX right now we assume that WITHZFS means per-user/proj FSes
if ($WITHZFS) {
$cmd = "$ZFS create";
$path = "${ZFS_ROOT}${fs}/$dir";
# XXX quotas
my ($refquota,$mult);
if ($fs eq $USERROOT) {
$refquota = $ZFS_QUOTA_USER;
$mult = $ZFS_QUOTA_USER_X;
} elsif ($fs eq $PROJROOT) {
$refquota = $ZFS_QUOTA_PROJECT;
$mult = $ZFS_QUOTA_PROJECT_X;
} elsif ($fs eq $GROUPROOT) {
$refquota = $ZFS_QUOTA_GROUP;
$mult = $ZFS_QUOTA_GROUP_X;
}
if (defined($refquota) && $refquota =~ /^(\d+(?:\.\d+)?)([MGT]?)$/) {
my ($num,$unit) = ($1,$2);
$unit = "" if (!defined($unit));
$num = sprintf "%.1f", $num * $mult;
$cmdarg = "-o refquota=$refquota -o quota=$num$unit";
} else {
$cmdarg = "";
}
} else {
$cmd = "mkdir";
$cmdarg = "";
$path = "$fs/$dir";
}
#
# If we are relying on ZFS to HUP mountd (!ZFS_NOEXPORT), then we have to
# give mountd a chance to finish its work before we return. This is because
# it is likely that our caller (on boss) will try to access the directory
# via NFS after we return and if mountd is not done, that will fail.
# If ZFS_NOEXPORT is set, then our caller will do the HUPing and waiting.
#
my $waitforit = 0;
if (!$ZFS_NOEXPORT) {
#
# Note that "waiting for mountd" involves a Utah hack to mountd to
# make it record a timestamp in a file when it is done. If there is
# no timestamp file, assume we are not running the hacked mountd and
# don't sleep. If the file exists, remove it and wait for it to
# reappear as a sign mountd is done.
#
# XXX since we cannot guarantee that mountd gets HUP'ed when we
# call zfs (i.e., the command fails or the nfsshare attribute is
# not set correctly) we save the old timestamp and put it back
# on failures. Otherwise, the next call to us or exports_setup will
# not properly wait for mountd.
#
if (-e "$TSFILE" && rename("$TSFILE", "$TSFILE.bak") != 0) {
$waitforit = 1;
}
}
if (mysystem("$cmd $cmdarg $path")) {
my $stat = $?;
if ($waitforit && !rename("$TSFILE.bak", "$TSFILE")) {
print STDERR "accountsetup: could not replace $TSFILE;".
" You must HUP mountd\n";
}
return $stat;
}
if ($waitforit) {
# With potentially thousands of mount points, this can take 15 seconds!
my $wtime = 15;
my $i;
for ($i = 0; $i < $wtime; $i++) {
if (-e "$TSFILE") {
print "accountsetup: mountd done.\n"
if ($i > 0);
last;
}
print "accountsetup: waiting for mountd to finish ($i)...\n";
sleep(1);
}
if ($i == $wtime) {
print STDERR "accountsetup: mountd not finished after $i seconds;".
"Perhaps ZFS sharenfs attribute not set on $path?\n";
if (!rename("$TSFILE.bak", "$TSFILE")) {
print STDERR "accountsetup: could not replace $TSFILE;".
" You must HUP mountd\n";
}
} else {
unlink("$TSFILE.bak");
}
}
# should we be setting permissions or ownership here?
return 0;
}
sub WhackDir($$)
{
my ($fs,$dir) = @_;
my $zfsfs = "";
if ($WITHZFS) {
my $path = "${ZFS_ROOT}${fs}/$dir";
$zfsfs = $path
if (ZFSexists($path));
}
if ($RENAMEDIRS) {
my ($cmd, $path, $npath);
my $suffix = "-D" . time();
if ($zfsfs) {
$cmd = "$ZFS rename";
$path = $zfsfs;
$npath = "${ZFS_ROOT}${fs}/$dir$suffix";
} else {
$cmd = "mv";
$path = "$fs/$dir";
$npath = "$fs/$dir$suffix";
}
if (mysystem("$cmd $path $npath")) {
return $?;
}
# Since we reuse uid/gids let's make the dir root/0700
$path = "$fs/$dir$suffix";
if (!chown(0, 0, $path) || !chmod(0700, $path)) {
print STDERR "WARNING: could not chown/chmod '$path': $!\n";
}
#
# And then unmount, we do not need it around. The empty subdir
# will still be there, so we have some clue ... maybe we should
# drop a file into the empty dir?
#
if ($zfsfs && mysystem("$ZFS set mountpoint=none $npath")) {
print STDERR "Could not set ZFS dir $npath to mountpoint=none\n";
}
}
#
# XXX maybe we should do this in the background since it could
# take a really long time!
#
else {
my ($cmd, $path);
if ($zfsfs) {
$cmd = "$ZFS destroy -f";
$path = $zfsfs;
} else {
$cmd = "rm -rf";
$path = "$fs/$dir";
}
if (mysystem("$cmd $path")) {
return $?;
}
}
return 0;
}
#
# HUP Mountd after changes to ZFS volumes. Not used, Mike says we
# can do "zfs share -a" instead, but I will leave this code here
# for now.
#
sub HUPMountd()
{
if (! -e $PIDFILE) {
fatal("$PIDFILE does not exist. Is mountd running?");
}
my $daemonpid = `cat $PIDFILE`;
chomp($daemonpid);
# untaint
if ($daemonpid =~ /^([-\@\w.]+)$/) {
$daemonpid = $1;
}
if (kill('HUP', $daemonpid) == 0) {
fatal("Could not kill(HUP) process $daemonpid (mountd): $!");
}
# Give mountd time to react.
sleep(1);
}
# XXX temporary while debugging
sub mysystem($)
{
my $cmd = shift;
print STDERR "accountsetup: '$cmd'\n";
if (open(FD, ">>/usr/testbed/log/accountsetup.log")) {
my $tstamp = POSIX::strftime("%b %e %H:%M:%S", localtime());
print FD "$tstamp: $cmd\n";
close(FD);
}
return system($cmd);
}
#
# Run pw/chpass, checking for a locked passwd/group file. The pw routines
# exit with non specific error code 1 for everything, so there is no way
# to tell that its a busy file except by looking at the error message. Then
# wait for a bit and try again. Silly.
#
sub runBusyLoop($)
{
my $command = shift;
my $maxtries = 20;
my $stime = time();
print STDERR "accountsetup: '$command'\n";
if (open(FD, ">>/usr/testbed/log/accountsetup.log")) {
my $tstamp = POSIX::strftime("%b %e %H:%M:%S", localtime($stime));
print FD "$tstamp: $command\n";
close(FD);
}
while ($maxtries--) {
my $output = "";
#
# This open implicitly forks a child, which goes on to execute the
# command. The parent is going to sit in this loop and capture the
# output of the child. We do this so that we have better control
# over the descriptors.
#
my $pid = open(PIPE, "-|");
if (!defined($pid)) {
print STDERR "runBusyLoop; popen failed!\n";
return -1;
}
if ($pid) {
while (<PIPE>) {
$output .= $_;
}
close(PIPE);
print $output;
if (!$?) {
if ($command =~ /^$PW .*/) {
if (open(FD, ">>/usr/testbed/log/accountsetup.log")) {
my $etime = time();
my $tstamp = POSIX::strftime("%b %e %H:%M:%S",
localtime($etime));
$etime -= $stime;
print FD "$tstamp: $PW done in $etime seconds\n";
close(FD);
}
}
return 0
}
if ($output =~ /(group|db) file is busy/m) {
print "runBusyLoop; waiting a few seconds before trying again\n";
sleep(3);
}
}
else {
open(STDERR, ">&STDOUT");
exec($command);
}
}
return -1;
}
sub fatal($) {
my ($msg) = @_;
print STDERR "$msg\n";
exit(-1);
}
#!/usr/bin/perl -wT
#
# Copyright (c) 2000-2012 University of Utah and the Flux Group.
# Copyright (c) 2000-2017 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -24,6 +24,7 @@
use English;
use Getopt::Std;
use XML::Simple;
use File::Temp qw(tempfile :POSIX );
#
# Parse ssh public keys and enter into the DB. The default format is
......@@ -48,7 +49,7 @@ sub usage()
print " -r Force a regenerate of initial key for user\n";
exit(-1);
}
my $optlist = "dkniwfu:rX:sRNC:S:";
my $optlist = "dkniwfu:rX:sRNC:S:Ia";
my $iskey = 0;
my $verify = 0;
my $initmode = 0;
......@@ -58,6 +59,8 @@ my $nobody = 0;
my $noemail = 0;
my $remove = 0;
my $nodelete = 0;
my $internal = 0;
my $isaptkey = 0;
my $Comment;
my $xmlfile;
......@@ -68,7 +71,11 @@ my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $TBAUDIT = "@TBAUDITEMAIL@";
my $OURDOMAIN = "@OURDOMAIN@";
my $CONTROL = "@USERNODE@";
my $KEYGEN = "/usr/bin/ssh-keygen";
my $ACCOUNTPROXY= "$TB/sbin/accountsetup";
my $SSH = "$TB/bin/sshtb";
my $SAVEUID = $UID;
my $USERUID;
# Locals
......@@ -83,6 +90,7 @@ my $user_name;
my $user_email;
my $user_dbid;
my $user_uid;
my $user_gid;
my $debug = 0;
#
......@@ -93,6 +101,9 @@ use libaudit;
use libdb;
use libtestbed;
use User;
if (@PROTOGENI_SUPPORT@) {
require APT_Utility;
}
#
# Function prototypes
......@@ -155,6 +166,9 @@ if (! getopts($optlist, \%options)) {
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"a"})) {
$isaptkey = 1;
}
if (defined($options{"k"})) {
$iskey = 1;
}
......@@ -170,6 +184,9 @@ if (defined($options{"i"})) {
if (defined($options{"N"})) {
$nodelete = 1;
}
if (defined($options{"I"})) {
$internal = 1;
}
if (defined($options{"r"})) {
$force = 1;
}
......@@ -248,6 +265,18 @@ if (defined($user)) {
$user_dbid = $target_user->dbid();
$user_uid = $target_user->uid();
$USERUID = $target_user->unix_uid();
my $firstproject;
if ($target_user->FirstApprovedProject(\$firstproject) < 0) {
fatal("Could not determine first approved project");
}
if (defined($firstproject)) {
$user_gid = $firstproject->unix_gid();
}
else {
$user_gid = "guest";
}
}
#
......@@ -273,18 +302,16 @@ else {
}
#
# Initmode or genmode, do it and exit. Eventually get rid of the switch
# to the target user.
# Initmode or genmode, do it and exit.
#
if ($initmode) {
# Drop root privs, switch to target user.
$EUID = $UID = $USERUID;
exit InitUser();
}