Commit 87d450b3 authored by Mike Hibler's avatar Mike Hibler

First complete crack at performing all dir creation/deletion on fs.

Still untested.
parent 56dc0d3a
#!/usr/bin/perl -w
#
# Copyright (c) 2010-2014 University of Utah and the Flux Group.
# Copyright (c) 2010-2015 University of Utah and the Flux Group.
#
# {{{GENIPUBLIC-LICENSE
#
......@@ -47,11 +47,13 @@ sub usage()
print " accountsetup delgroup ...\n";
exit(1);
}
my $optlist = "dnfR";
my $optlist = "dnf";
my $debug = 0;
my $force = 0;
my $impotent = 0;
my $renamedirs = 0;
# XXX make this a sitevar
my $RENAMEDIRS = 1;
#
# Configure variables
......@@ -82,18 +84,24 @@ my $USEREXISTS = 65;
use lib "@prefix@/lib";
use libtestbed;
# Generic names for filesystems
# Generic (mounted) names for filesystems
my $USERROOT = USERROOT();
my $PROJROOT = PROJROOT();
my $GROUPROOT = GROUPROOT();
my $SCRATCHROOT = SCRATCHROOT();
# XXX we need the fs mountpoints too
# 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
#
......@@ -106,6 +114,7 @@ sub DelProject();
sub DelGroup();
sub fatal($);
sub ZFSexists($);
sub MakeDir($$);
sub WhackDir($$);
#
......@@ -124,9 +133,6 @@ if (defined($options{"f"})) {
if (defined($options{"n"})) {
$impotent = 1;
}
if (defined($options{"R"})) {
$renamedirs = 1;
}
usage()
if (@ARGV < 1);
......@@ -169,6 +175,9 @@ SWITCH: for ($cmd) {
}
exit(0);
#
# Usage: adduser username unix_uid full_name homedir unix_gid shell [ phash ]
#
sub AddUser()
{
if (@ARGV < 6) {
......@@ -183,45 +192,45 @@ sub AddUser()
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");
}
system("$ZFS share -a");
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")) {
"-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(.*)$/) {
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");
}
#
# And set the owner and group right on everything
#
system("/usr/sbin/chown -R $user:$gid $hdir") == 0
or fatal("Could not chown $hdir");
#
# Finally, set any initial password hash
#
if (defined($hash) &&
system("$CHPASS -p '$hash' $user")) {
fatal("Could not initialize password");
......@@ -229,6 +238,9 @@ sub AddUser()
return 0;
}
#
# Usage: deluser username homedir
#
sub DeleteUser()
{
if (@ARGV != 2) {
......@@ -255,68 +267,155 @@ sub DeleteUser()
return 0;
}
#
# Usage: moduser ...
#
sub ModifyUser()
{
fatal("moduser: Not implemented yet");
}
#
# 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");
}
system("$ZFS share -a");
# Create the project unix group
if (system("egrep -q -s '^${unix_name}:' /etc/group")) {
print "Adding group $unix_name ...\n";
if (system("$GROUPADD $unix_name -g $unix_gid")) {
fatal("Could not add group $unix_name ($unix_gid)!\n");
}
}
# 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': $!");
}
$path = "${ZFS_ROOT}${GROUPROOT}/$name";
if (!ZFSexists($path)) {
system("$ZFS create -o quota=${ZFS_QUOTA_GROUP} $path");
if ($?) {
fatal("Could not create ZFS $path");
}
system("$ZFS share -a");
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 (system("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);
# Create the group unix group
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");
if (system("$GROUPADD $unix_name -g $unix_gid")) {
fatal("Could not add group $unix_name ($unix_gid)!\n");
}
}
# Create the /groups/gid directory
$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) {
......@@ -325,9 +424,10 @@ sub DelProject()
my $name = shift(@ARGV);
my $unix_name = shift(@ARGV);
if (WhackDir($PROJROOT, $name) ||
WhackDir($GROUPROOT, $name) ||
($SCRATCHROOT && WhackDir($SCRATCHROOT, $name))) {
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");
}
......@@ -341,19 +441,24 @@ sub DelProject()
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 (WhackDir("$PROJROOT/$name", $name)) {
if (-d "$GROUPROOT/$projname/$name" &&
WhackDir($GROUPROOT, "$projname/$name")) {
fatal("Could not destroy project group '$name' related directories");
}
......@@ -385,54 +490,80 @@ sub ZFSexists($)
return ($? ? 0 : 1);
}
sub WhackDir($$)
sub MakeDir($$)
{
my ($fs,$name) = @_;
my ($fs,$dir) = @_;
my ($cmd,$cmdarg,$path);
if ($renamedirs) {
# XXX right now we assume that WITHZFS means per-user/proj FSes
if ($WITHZFS) {
$cmd = "$ZFS create";
$path = "${ZFS_ROOT}${fs}/$dir";
# XXX quotas
if ($fs eq $USERROOT) {
$cmdarg = "-o quota=$ZFS_QUOTA_USER";
} elsif ($fs eq $PROJROOT) {
$cmdarg = "-o quota=$ZFS_QUOTA_PROJECT";
} elsif ($fs eq $GROUPROOT) {
$cmdarg = "-o quota=$ZFS_QUOTA_GROUP";
} else {
$cmdarg = "";
}
} else {
$cmd = "mkdir";
$cmdarg = "";
$path = "$fs/$dir";
}
if (system("$cmd $cmdarg $path")) {
return $?;
}
# should we be setting permissions or ownership here?
# users
if ($WITHZFS) {
my $path = "${ZFS_ROOT}${dir}";
if (ZFSexists($path)) {
if ($renamedirs) {
my $npath = "$ZFS_ROOT/_ARCHIVED
if (system("$ZFS rename $path $npath")) {
return $?;
}
} else {
if (system("$ZFS unmount -f $path") ||
system("$ZFS destroy $path")) {
return $?;
}
}
}
return 0;
}
return 0;
}
sub WhackDir($$)
{
my ($fs,$dir) = @_;
my $zfsfs = "";
# proj
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");
}
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";
}
$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("$cmd $path $npath")) {
return $?;
}
} else {
my ($cmd, $path);
if ($zfsfs) {
$cmd = "$ZFS destroy -f";
$path = $zfsfs;
} else {
$cmd = "rm -rf";
$path = "$fs/$dir";
}
if (system("$cmd $path")) {
return $?;
}
}
return 0;
}
......
......@@ -63,7 +63,6 @@ my $CONTROL = "@USERNODE@";
my $BOSSNODE = "@BOSSNODE@";
my $WITHZFS = @WITHZFS@;
my $ZFS_NOEXPORT= @ZFS_NOEXPORT@;
my $WITHSFS = @SFSSUPPORT@;
my $WIKISUPPORT = @WIKISUPPORT@;
my $TRACSUPPORT = @TRACSUPPORT@;
my $BUGDBSUPPORT= @BUGDBSUPPORT@;
......@@ -86,10 +85,8 @@ 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";
my $SFSUPDATE = "$TB/sbin/sfskey_update";
my $PBAG = "$TB/sbin/paperbag";
my $EXPORTSSETUP= "$TB/sbin/exports_setup";
my $ADDWIKIUSER = "$TB/sbin/addwikiuser";
......@@ -119,7 +116,6 @@ my %shellpaths = ("csh" => "/bin/csh", "sh" => "/bin/sh",
"nologin" => "/usr/sbin/nologin");
my $errors = 0;
my $sfsupdate = 0;
my @row;
my $query_result;
......@@ -175,7 +171,6 @@ sub ThawUser();
sub VerifyUser();
sub UpdateEmail();
sub CheckDotFiles();
sub GenerateSFSKey();
sub RevokeUser();
sub fatal($);
......@@ -358,16 +353,6 @@ SWITCH: for ($cmd) {
};
}
#
# Invoke as real user for auditing (and cause of perl).
#
if ($WITHSFS && $sfsupdate) {
$EUID = $UID;
system($SFSUPDATE) == 0
or fatal("$SFSUPDATE failed!");
$EUID = 0;
}
#
# Now schedule account updates on all the nodes that this person has
# an account on.
......@@ -575,12 +560,6 @@ sub AddUser()
}
$EUID = 0;
CheckDotFiles();
# SFS key.
if ($CONTROL ne $BOSSNODE) {
GenerateSFSKey();
}
skipstuff:
return 0;
}
......@@ -657,7 +636,6 @@ sub DelUser()
$EUID = 0;
$sfsupdate = 1;
skipstuff:
return 0;
}
......@@ -1038,7 +1016,6 @@ sub FreezeUser()
$target_user->SetStatus(USERSTATUS_FROZEN());
$status = USERSTATUS_FROZEN();
}
$sfsupdate = 1;
return UpdateUser(1);
}
......@@ -1063,7 +1040,6 @@ sub ThawUser()
$target_user->SetStatus(USERSTATUS_ACTIVE());
$status = USERSTATUS_ACTIVE();
}
$sfsupdate = 1;
#
# This lets users start off as frozen in an ELABINELAB, and then
......@@ -1216,74 +1192,6 @@ sub CheckDotFiles()
return 0;
}
#
# Do SFS stuff. Might move this out to its own script at some point.
#
sub GenerateSFSKey()
{
my $sfsdir = "$HOMEDIR/$user/.sfs";
#
# Set up the sfs key, but only if not done so already.
# This has to be done from root because the sfs_users file needs
# to be updated (and "sfskey register" won't work because it
# prompts for the user's UNIX password if not run from root.)
#
if ($WITHSFS && ! -e "$sfsdir/identity") {
if (! -e "$sfsdir" ) {
print "Setting up sfs configuration for $user.\n";
mkdir("$sfsdir", 0700) or
fatal("Could not mkdir $sfsdir: $!");
chown($user_number, $default_groupgid, "$sfsdir") or
fatal("Could not chown $sfsdir: $!");
}
print "Generating sfs key\n";
$UID = 0;
if (system("$SSH -host $CONTROL '$SFSKEYGEN -KPn ".
"$user\@ops.emulab.net $sfsdir/identity'")) {
fatal("Failure in sfskey gen!");
}
# Version 7 stuff for later.
#if (system("$SSH -host $CONTROL '$SFSKEYGEN -KP ".
# "-l $user\@ops.emulab.net $sfsdir/identity'")) {
# fatal("Failure in sfskey gen!");
#}
$UID = $SAVEUID;
chown($user_number, $default_groupgid, "$sfsdir/identity") or
fatal("Could not chown $sfsdir/identity: $!");
chmod(0600, "$sfsdir/identity") or
fatal("Could not chmod $sfsdir/identity: $!");
#
# Grab a copy for the DB. Causes an SFS update key to run so
# that key is inserted into the files.
#
my $ident = `cat $sfsdir/identity`;
if ($ident =~ /.*,.*,.*,(.*),(.*)/) {
# Version 6
DBQueryFatal("replace into user_sfskeys ".
"values ('$user', '$2', '${user}:${1}:${user}::', ".
"now())");
}
elsif ($ident =~ /.*:.*:.*:(.*):(.*)/) {
# Version 7
DBQueryFatal("replace into user_sfskeys ".
"values ('$user', '$2', '${user}:${1}:${user}::', ".
"now())");
}
else {
warn("*** $0:\n".
" Bad emulab SFS public key\n");
}
$sfsupdate = 1;
}
return 0;
}
sub fatal($) {