diff --git a/account/GNUmakefile.in b/account/GNUmakefile.in index 43c3315471c036f49c6efbb4d3a4d1e777b22a0e..e556e735e7fde9114d135aa404e61fed7cfe53ee 100644 --- a/account/GNUmakefile.in +++ b/account/GNUmakefile.in @@ -1,5 +1,5 @@ # -# Copyright (c) 2000-2011 University of Utah and the Flux Group. +# Copyright (c) 2000-2011, 2014 University of Utah and the Flux Group. # # {{{EMULAB-LICENSE # @@ -34,7 +34,7 @@ SBIN_STUFF = tbacct addsfskey addpubkey mkusercert quotamail genpubkeys \ manageremote LIBEXEC_STUFF = webtbacct webaddsfskey webaddpubkey webmkusercert \ webnewuser webnewproj webspewcert webmanageremote -CTRLSBIN_STUFF = adduserhook +CTRLSBIN_STUFF = adduserhook accountsetup # These scripts installed setuid, with sudo. SETUID_BIN_SCRIPTS = @@ -74,7 +74,8 @@ boss-install: all script-install @echo "Don't forget to do a post-install as root" script-install: $(addprefix $(INSTALL_SBINDIR)/, $(SBIN_STUFF)) \ - $(addprefix $(INSTALL_LIBEXECDIR)/, $(LIBEXEC_STUFF)) + $(addprefix $(INSTALL_LIBEXECDIR)/, $(LIBEXEC_STUFF)) \ + $(addprefix $(INSTALL_DIR)/opsdir/sbin/, $(CTRLSBIN_STUFF)) post-install: chmod 775 $(INSTALL_BINDIR) diff --git a/account/accountsetup.in b/account/accountsetup.in new file mode 100644 index 0000000000000000000000000000000000000000..cdeb1039377be3719a02862a53c3abd74ebaff9a --- /dev/null +++ b/account/accountsetup.in @@ -0,0 +1,373 @@ +#!/usr/bin/perl -w +# +# Copyright (c) 2010-2014 University of Utah and the Flux Group. +# +# {{{GENIPUBLIC-LICENSE +# +# GENI Public License +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and/or hardware specification (the "Work") to +# deal in the Work without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Work, and to permit persons to whom the Work +# is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Work. +# +# THE WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE WORK OR THE USE OR OTHER DEALINGS +# IN THE WORK. +# +# }}} +# +use strict; +use English; +use Getopt::Std; +use Data::Dumper; + +# +# 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/ +# +sub usage() +{ + print "Usage: accountsetup adduser ...\n"; + print " accountsetup deluser ...\n"; + print " accountsetup moduser ...\n"; + print " accountsetup addproject ...\n"; + print " accountsetup addgroup ...\n"; + print " accountsetup delproject ...\n"; + print " accountsetup delgroup ...\n"; + exit(1); +} +my $optlist = "dnf"; +my $debug = 0; +my $force = 0; +my $impotent = 0; + +# +# Configure variables +# +my $TB = "@prefix@"; +my $WITHZFS = @WITHZFS@; +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 $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 $ZFS = "/sbin/zfs"; +my $SKEL = "/usr/share/skel"; + +# XXX +my $NOSUCHUSER = 67; +my $USEREXISTS = 65; + +# +# Testbed Support libraries +# +use lib "@prefix@/lib"; +use libtestbed; + +# Defined in libtestbed; +my $PROJROOT = PROJROOT(); +my $GROUPROOT = GROUPROOT(); + +# +# Function prototypes +# +sub AddUser(); +sub DeleteUser(); +sub ModifyUser(); +sub AddProject(); +sub AddGroup(); +sub DelProject(); +sub DelGroup(); +sub fatal($); +sub ZFSexists($); + +# +# Check args. +# +my %options = (); +if (! getopts($optlist, \%options)) { + usage(); +} +if (defined($options{"d"})) { + $debug = 1; +} +if (defined($options{"f"})) { + $force = 1; +} +if (defined($options{"n"})) { + $impotent = 1; +} +usage() + if (@ARGV < 1); + +my $cmd = shift(@ARGV); + +# +# Now dispatch operation. +# +SWITCH: for ($cmd) { + /^adduser$/ && do { + AddUser(); + last SWITCH; + }; + /^deluser$/ && do { + DeleteUser(); + last SWITCH; + }; + /^moduser$/ && do { + ModifyUser(); + last SWITCH; + }; + /^addproject$/ && do { + AddProject(); + last SWITCH; + }; + /^addgroup$/ && do { + AddGroup(); + last SWITCH; + }; + /^delproject$/ && do { + DelProject(); + last SWITCH; + }; + /^delgroup$/ && do { + DelGroup(); + last SWITCH; + }; + # Default + usage(); +} +exit(0); + +sub AddUser() +{ + if (@ARGV < 6) { + fatal("adduser: Wrong number of arguments"); + } + + my $user = shift(@ARGV); + my $uid = shift(@ARGV); + my $name = shift(@ARGV); + 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 (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 (($? >> 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"); + } + } + } + # + # And for the same reason, need to chown/chgrp everything. + # + system("/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"); + } + return 0; +} + +sub DeleteUser() +{ + if (@ARGV != 2) { + fatal("deluser: Wrong number of arguments"); + } + my $user = shift(@ARGV); + my $hdir = shift(@ARGV); + + if (system("$USERDEL $user")) { + if (($? >> 8) != $NOSUCHUSER) { + fatal("Could not remove user $user"); + } + } + 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"); + } + } + } + return 0; +} + +sub ModifyUser() +{ + fatal("moduser: Not implemented yet"); +} + +sub AddProject() +{ + if (@ARGV != 3) { + fatal("addproject: Wrong number of arguments"); + } + my $name = shift(@ARGV); + my $unix_name = shift(@ARGV); + my $gid = 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"); + } + } + $path = "${ZFS_ROOT}${GROUPROOT}/$name"; + if (!ZFSexists($path)) { + system("$ZFS create -o quota=${ZFS_QUOTA_GROUP} $path"); + if ($?) { + fatal("Could not create ZFS $path"); + } + } + } + + if (system("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"); + } + } + return 0; +} + +sub AddGroup() +{ + if (@ARGV != 3) { + fatal("addgroup: Wrong number of arguments"); + } + my $name = shift(@ARGV); + my $unix_name = shift(@ARGV); + my $gid = shift(@ARGV); + + if (system("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"); + } + } + return 0; +} + +sub DelProject() +{ + if (@ARGV != 2) { + fatal("delproject: Wrong number of arguments"); + } + 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 (system("egrep -q -s '^${unix_name}:' /etc/group") == 0) { + print "Deleting project $unix_name ...\n"; + + if (system("$GROUPDEL $unix_name")) { + fatal("Could not delete group $unix_name!\n"); + } + } + return 0; +} + +sub DelGroup() +{ + if (@ARGV != 2) { + fatal("delgroup: Wrong number of arguments"); + } + my $name = shift(@ARGV); + my $unix_name = shift(@ARGV); + + if (system("egrep -q -s '^${unix_name}:' /etc/group") == 0) { + print "Deleting group $unix_name ...\n"; + + if (system("$GROUPDEL $unix_name")) { + fatal("Could not delete group $unix_name!\n"); + } + } + return 0; +} + +sub fatal($) { + my ($msg) = @_; + + print STDERR "$msg\n"; + exit(-1); +} + +# +# Check for ZFS existence. +# +sub ZFSexists($) +{ + my ($path) = @_; + + system("$ZFS list $path >/dev/null 2>&1"); + return ($? ? 0 : 1); +} diff --git a/account/tbacct.in b/account/tbacct.in index 215c449a1675280ac45fdd6a5e930245a9beb741..f0edfc03412e640b466fe1fdaf4a7b32dba87dab 100644 --- a/account/tbacct.in +++ b/account/tbacct.in @@ -61,6 +61,7 @@ my $TBLOGS = "@TBLOGSEMAIL@"; my $TBAUDIT = "@TBAUDITEMAIL@"; my $CONTROL = "@USERNODE@"; my $BOSSNODE = "@BOSSNODE@"; +my $WITHZFS = @WITHZFS@; my $WITHSFS = @SFSSUPPORT@; my $WIKISUPPORT = @WIKISUPPORT@; my $TRACSUPPORT = @TRACSUPPORT@; @@ -83,6 +84,7 @@ my $USERADD = "/usr/sbin/pw useradd"; my $USERDEL = "/usr/sbin/pw userdel"; my $USERMOD = "/usr/sbin/pw usermod"; my $CHPASS = "/usr/bin/chpass"; +my $ACCOUNTPROXY= "$TB/sbin/accountsetup"; my $SFSKEYGEN = "/usr/local/bin/sfskey gen"; my $GENELISTS = "$TB/sbin/genelists"; my $MKUSERCERT = "$TB/sbin/mkusercert"; @@ -423,7 +425,7 @@ sub AddUser() print "Adding user $user ($user_number) to local node.\n"; if (system("$USERADD $user -u $user_number -c \"$fullname\" ". - "-k /usr/share/skel -h - -m -d $HOMEDIR/$user ". + "-h - -d $HOMEDIR/$user ". "-g $default_groupname -s $PBAG")) { fatal("Could not add user $user to local node."); } @@ -439,10 +441,10 @@ sub AddUser() print "Adding user $user ($user_number) to $CONTROL.\n"; if (system("$SSH -host $CONTROL ". - "'$USERADD $user -u $user_number -c \"$fullname\" ". - "-k /usr/share/skel -h - -m -d $HOMEDIR/$user ". - "-g $default_groupname -s $shellpaths{$usr_shell}'")) { - if (($? >> 8) != $USEREXISTS) { + "'$ACCOUNTPROXY adduser $user $user_number \"$fullname\" ". + "$HOMEDIR/$user $default_groupname ". + "$shellpaths{$usr_shell}'")) { + if ($?) { fatal("Could not add user $user ($user_number) to $CONTROL."); } } @@ -471,6 +473,19 @@ sub AddUser() system("$SSH -host $CONTROL $ADDHOOK $user"); } } + if ($WITHZFS) { + # + # There is some lag before the automounter can mount the new + # volume. Lets delay until we can access the directory. + # + for (my $i = 0; $i < 10; $i++) { + sleep(1) + if (! -r "$HOMEDIR/$user/.cshrc"); + } + if (! -r "$HOMEDIR/$user/.cshrc") { + fatal("Could not access new user directory"); + } + } $UID = $SAVEUID; # @@ -590,8 +605,9 @@ sub DelUser() if (1) { print "Removing user $user from $CONTROL\n"; - if (system("$SSH -host $CONTROL '$USERDEL $user'")) { - if (($? >> 8) != $NOSUCHUSER) { + if (system("$SSH -host $CONTROL ". + " '$ACCOUNTPROXY deluser $user $HOMEDIR/$user'")) { + if ($?) { fatal("Could not remove user $user from $CONTROL."); } } diff --git a/configure b/configure index 7c3582bebfaec1bf2cb51eeb3f9424ae6f486f16..2d6535d3cf11082599e4c2c4ee90859429efe5b9 100755 --- a/configure +++ b/configure @@ -660,6 +660,11 @@ IPV6_SUBNET_PREFIX IPV6_ENABLED NFSMAPTOUSER IMAGEPROVENANCE +WITHZFS +ZFS_ROOT +ZFS_QUOTA_USER +ZFS_QUOTA_PROJECT +ZFS_QUOTA_GROUP NOVIRTNFSMOUNTS IMAGEDELTAS PROFILEVERSIONS @@ -5099,6 +5104,11 @@ IMAGEPROVENANCE=0 IMAGEDELTAS=0 PROFILEVERSIONS=0 NOVIRTNFSMOUNTS=0; +WITHZFS=0 +ZFS_ROOT=z +ZFS_QUOTA_USER="1G" +ZFS_QUOTA_PROJECT="100G" +ZFS_QUOTA_GROUP="10G" # # XXX You really don't want to change these! diff --git a/configure.in b/configure.in index c64f1dcaaec59fdd28630f129af37e18968a828b..2796adaefe23ff61670cf5f1c6cfbd1ba46853bf 100755 --- a/configure.in +++ b/configure.in @@ -295,6 +295,11 @@ AC_SUBST(IMAGEPROVENANCE) AC_SUBST(IMAGEDELTAS) AC_SUBST(PROFILEVERSIONS) AC_SUBST(NOVIRTNFSMOUNTS) +AC_SUBST(WITHZFS) +AC_SUBST(ZFS_ROOT) +AC_SUBST(ZFS_QUOTA_USER) +AC_SUBST(ZFS_QUOTA_PROJECT) +AC_SUBST(ZFS_QUOTA_GROUP) # # Offer both versions of the email addresses that have the @ escaped @@ -441,6 +446,11 @@ IMAGEPROVENANCE=0 IMAGEDELTAS=0 PROFILEVERSIONS=0 NOVIRTNFSMOUNTS=0 +WITHZFS=0 +ZFS_ROOT=z +ZFS_QUOTA_USER="1G" +ZFS_QUOTA_PROJECT="100G" +ZFS_QUOTA_GROUP="10G" # # XXX You really don't want to change these! diff --git a/tbsetup/mkgroup.in b/tbsetup/mkgroup.in index 4ef302210b8bc43ae6fcb15ad5c09824d93a2487..d0c80466a59375ff929c93e68055751782fece5e 100644 --- a/tbsetup/mkgroup.in +++ b/tbsetup/mkgroup.in @@ -1,6 +1,6 @@ #!/usr/bin/perl -wT # -# Copyright (c) 2000-2011 University of Utah and the Flux Group. +# Copyright (c) 2000-2014 University of Utah and the Flux Group. # # {{{EMULAB-LICENSE # @@ -57,10 +57,12 @@ my $BUGDBSUPPORT= @BUGDBSUPPORT@; my $OPSDBSUPPORT= @OPSDBSUPPORT@; my $TBBASE = "@TBBASE@"; my $TBWWW = "@TBWWW@"; +my $WITHZFS = @WITHZFS@; my $SSH = "$TB/bin/sshtb"; my $ADDMMLIST = "$TB/sbin/addmmlist"; my $OPSDBCONTROL= "$TB/sbin/opsdb_control"; my $GROUPADD = "/usr/sbin/pw groupadd"; +my $ACCOUNTPROXY= "$TB/sbin/accountsetup"; my @DIRLIST = ("exp", "images", "logs", "tarfiles", "rpms", "tiplogs"); my $SAVEUID = $UID; @@ -178,6 +180,7 @@ my $isnonlocal = $project->IsNonLocal(); # # The group directory lives here. # +my $projdir = "$PROJROOT/$pid"; my $groupdir = "$GRPROOT/$pid/$gid"; my $grouplink = "$PROJROOT/$pid/groups/$gid"; @@ -201,13 +204,23 @@ $UID = $EUID; # # Create group on the control node if it does not exist. # +my $proxy_command = ($pid eq $gid ? "addproject" : "addgroup"); +print "Adding group $unix_name to $control_node.\n"; if (system("$SSH -host $control_node ". - "egrep -q -s '^${unix_name}:' /etc/group")) { - print "Adding group $unix_name to $control_node.\n"; - - if (system("$SSH -host $control_node ". - "$GROUPADD $unix_name -g $unix_gid")) { - fatal("Could not add $unix_name ($unix_gid) to $control_node!\n"); + " $ACCOUNTPROXY $proxy_command $gid $unix_name $unix_gid")) { + fatal("Could not add $unix_name ($unix_gid) to $control_node!\n"); +} +if ($WITHZFS && $pid ne $gid) { + # + # There is some lag before the automounter can mount the new + # volume. Lets delay until we can access the project directory. + # + for (my $i = 0; $i < 10; $i++) { + sleep(1) + if (! -r $projdir); + } + if (! -r $projdir) { + fatal("Could not access new project directory: $projdir"); } } diff --git a/tbsetup/rmgroup.in b/tbsetup/rmgroup.in index f207b4d64ef1865d24ad2bef95defdbf5b8c458f..513bd213be8136f520a1d4fea7f81ecbbae5994d 100644 --- a/tbsetup/rmgroup.in +++ b/tbsetup/rmgroup.in @@ -1,6 +1,6 @@ #!/usr/bin/perl -wT # -# Copyright (c) 2000-2010 University of Utah and the Flux Group. +# Copyright (c) 2000-2014 University of Utah and the Flux Group. # # {{{EMULAB-LICENSE # @@ -73,6 +73,7 @@ my $GROUPDEL = "/usr/sbin/pw groupdel"; my $DELMMLIST = "$TB/sbin/delmmlist"; my $MODGROUPS = "$TB/sbin/modgroups"; my $OPSDBCONTROL = "$TB/sbin/opsdb_control"; +my $ACCOUNTPROXY = "$TB/sbin/accountsetup"; # # Untaint the path @@ -249,10 +250,13 @@ if (system("grep -q '^${unix_gid}:' /etc/group")) { $UID = 0; if ($CONTROL ne $BOSSNODE) { + my $proxy_command = ($pid eq $gid ? "delproject" : "delgroup"); + print "Removing group $unix_name ($unix_gid) on $CONTROL.\n"; - if (system("$SSH -host $CONTROL $GROUPDEL $unix_name")) { - if (($? >> 8) != 65) { + if (system("$SSH -host $CONTROL ". + " $ACCOUNTPROXY $proxy_command $gid $unix_name")) { + if ($?) { fatal("Could not remove group $unix_name from $CONTROL!"); } } diff --git a/tbsetup/rmproj.in b/tbsetup/rmproj.in index 14f900ad2eb051a63c0599b74eb481d8de024e7f..0e43232eb654e5a2dda408a4c0aae7cf54ffffbd 100755 --- a/tbsetup/rmproj.in +++ b/tbsetup/rmproj.in @@ -1,6 +1,6 @@ #!/usr/bin/perl -wT # -# Copyright (c) 2000-2013 University of Utah and the Flux Group. +# Copyright (c) 2000-2014 University of Utah and the Flux Group. # # {{{EMULAB-LICENSE # @@ -38,6 +38,7 @@ use strict; my $TB = "@prefix@"; my $TBOPS = "@TBOPSEMAIL@"; my $CONTROL = "@USERNODE@"; +my $WITHZFS = @WITHZFS@; my $MAILMANSUPPORT= @MAILMANSUPPORT@; my $RMGROUP = "$TB/sbin/rmgroup"; @@ -136,7 +137,7 @@ my $savename = "${pid}-${pid_idx}"; # # Rename the project directory. # -if (-e "$PROJROOT/$pid") { +if (!$WITHZFS && -e "$PROJROOT/$pid") { my $oldname = "$PROJROOT/$pid"; my $newname = "$PROJROOT/$savename"; diff --git a/tbsetup/rmuser.in b/tbsetup/rmuser.in index 9857a296c54d226d60a76131737d6dd35013001d..757755e0653657be5307d5436535c1548bd0ab39 100755 --- a/tbsetup/rmuser.in +++ b/tbsetup/rmuser.in @@ -1,6 +1,6 @@ #!/usr/bin/perl -wT # -# Copyright (c) 2000-2013 University of Utah and the Flux Group. +# Copyright (c) 2000-2014 University of Utah and the Flux Group. # # {{{EMULAB-LICENSE # @@ -51,6 +51,7 @@ my $TBOPS = "@TBOPSEMAIL@"; my $TBLOGS = "@TBLOGSEMAIL@"; my $CONTROL = "@USERNODE@"; my $BOSSNODE= "@BOSSNODE@"; +my $WITHZFS = @WITHZFS@; my $OURDOMAIN = "@OURDOMAIN@"; my $PGENISUPPORT = @PROTOGENI_SUPPORT@; my $PORTAL_ENABLE = @PORTAL_ENABLE@; @@ -376,7 +377,7 @@ EmulabFeatures->DeleteAll($target_user) == 0 or # # Rename the users home dir if its there. # -if (-d "$HOMEDIR/$target_uid") { +if (!$WITHZFS && -d "$HOMEDIR/$target_uid") { my $newname = "$HOMEDIR/$target_uid-" . TBDateTimeFSSafe(); if (rename("$HOMEDIR/$target_uid", $newname)) {