Commit bf77e242 authored by Leigh Stoller's avatar Leigh Stoller

Various fixes to deactivate/reactivate code, mostly to deal with not

wanting to call setgroups cause it is so slow. also refactor the code to
chown/chgrp user dot files so we can call it from reactivate.

Refactor the code that bumps user/project activity and calls exports
setup so that we can call it from reactivate.

When deleting a ZFS home/proj directory, do the ZFS rename and then
set the mountpoint=none, no need to have it mounted.
parent 9c3a44cb
...@@ -134,6 +134,7 @@ sub CreateSSHKey(); ...@@ -134,6 +134,7 @@ sub CreateSSHKey();
sub ReactivateUser(); sub ReactivateUser();
sub DeactivateUser(); sub DeactivateUser();
sub fatal($); sub fatal($);
sub SetDotGroup($$);
sub ZFSexists($); sub ZFSexists($);
sub MakeDir($$); sub MakeDir($$);
sub WhackDir($$); sub WhackDir($$);
...@@ -338,30 +339,10 @@ sub ModifyUser() ...@@ -338,30 +339,10 @@ sub ModifyUser()
if (@ARGV > 0) { if (@ARGV > 0) {
$grouplist = "-G '" . join(',', @ARGV) . "'"; $grouplist = "-G '" . join(',', @ARGV) . "'";
} }
if (mysystem("$USERMOD $user -g $pgroup $grouplist")) { if (mysystem("$USERMOD $user -g $pgroup $grouplist")) {
fatal("Could not modify user $user to add groups!\n"); fatal("Could not modify user $user to add groups!\n");
} }
SetDotGroup($user, $pgroup);
#
# 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.
#
my @dots = (".login", ".profile", ".cshrc", ".ssl", ".ssh");
my $homedir = USERROOT() . "/$user";
mysystem("$CHOWN $user:$pgroup $homedir") == 0
or fatal("Could not chown home dir to $user:$pgroup");
foreach my $dot (@dots) {
if (-e "$homedir/$dot") {
mysystem("$CHOWN -R $user:$pgroup $homedir/$dot") == 0
or fatal("Could not chown $homedir/$dot to $user:$pgroup");
}
}
return 0; return 0;
} }
...@@ -412,6 +393,16 @@ sub ReactivateUser() ...@@ -412,6 +393,16 @@ sub ReactivateUser()
if (mysystem("$USERMOD $user -d $hdir")) { if (mysystem("$USERMOD $user -d $hdir")) {
fatal("Could not set home directory back to $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; return 0;
} }
...@@ -750,6 +741,36 @@ sub CreateSSHKey() ...@@ -750,6 +741,36 @@ sub CreateSSHKey()
return 0; 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");
}
}
}
# #
# Check for ZFS existence. # Check for ZFS existence.
# #
...@@ -883,7 +904,15 @@ sub WhackDir($$) ...@@ -883,7 +904,15 @@ sub WhackDir($$)
# Since we reuse uid/gids let's make the dir root/0700 # Since we reuse uid/gids let's make the dir root/0700
$path = "$fs/$dir$suffix"; $path = "$fs/$dir$suffix";
if (!chown(0, 0, $path) || !chmod(0700, $path)) { if (!chown(0, 0, $path) || !chmod(0700, $path)) {
print STDERR "WARNING: could not chown/chmod '$path'!\n"; 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";
} }
} }
# #
......
...@@ -1151,9 +1151,11 @@ sub ReactivateUser() ...@@ -1151,9 +1151,11 @@ sub ReactivateUser()
# #
if ($status ne USERSTATUS_ACTIVE) { if ($status ne USERSTATUS_ACTIVE) {
fatal("$user is not active! Cannot reactivate the account!") fatal("$user is not active! Cannot reactivate the account!")
if (!$update); if (! ($update || $force));
$target_user->SetStatus(USERSTATUS_ACTIVE()); if ($update) {
$status = USERSTATUS_ACTIVE(); $target_user->SetStatus(USERSTATUS_ACTIVE());
$status = USERSTATUS_ACTIVE();
}
} }
$UID = 0; $UID = 0;
if ($CONTROL ne $BOSSNODE) { if ($CONTROL ne $BOSSNODE) {
......
...@@ -50,8 +50,12 @@ my $TBAUDIT = "@TBAUDITEMAIL@"; ...@@ -50,8 +50,12 @@ my $TBAUDIT = "@TBAUDITEMAIL@";
my $TBBASE = "@TBBASE@"; my $TBBASE = "@TBBASE@";
my $TBWWW = "@TBWWW@"; my $TBWWW = "@TBWWW@";
my $WIKISUPPORT = @WIKISUPPORT@; my $WIKISUPPORT = @WIKISUPPORT@;
my $WITHZFS = @WITHZFS@;
my $WITHAMD = @WITHAMD@;
my $ZFS_NOEXPORT= @ZFS_NOEXPORT@;
my $MAILMANSUPPORT = @MAILMANSUPPORT@; my $MAILMANSUPPORT = @MAILMANSUPPORT@;
my $ADDPROJADMINLIST = "$TB/sbin/addprojadminlist"; my $ADDPROJADMINLIST = "$TB/sbin/addprojadminlist";
my $EXPORTS_SETUP = "$TB/sbin/exports_setup";
# Cache of instances to avoid regenerating them. # Cache of instances to avoid regenerating them.
my %projects = (); my %projects = ();
...@@ -862,5 +866,51 @@ sub PeerExports($$) ...@@ -862,5 +866,51 @@ sub PeerExports($$)
return $self->{'GROUP'}->PeerExports($pref); return $self->{'GROUP'}->PeerExports($pref);
} }
#
# Do an exports setup if needed (ZFS). See exports_setup, when ZFS is on
# we do not export all projects, only recently active ones.
#
sub UpdateExports($)
{
my ($self) = @_;
my $pid_idx = $self->pid_idx();
return 0
if (! ($WITHZFS && ($ZFS_NOEXPORT || !$WITHAMD)));
my $query_result =
DBQueryWarn("select UNIX_TIMESTAMP(last_activity) from project_stats ".
"where pid_idx='$pid_idx'");
# Hmm.
return 0
if (!$query_result->numrows);
my ($lastactivity) = $query_result->fetchrow_array();
if (!defined($lastactivity) ||
time() - $lastactivity > (24 * 3600)) {
# Update last_activity first so exports_setup will do something.
DBQueryWarn("update project_stats set last_activity=now() ".
"where pid_idx='$pid_idx'")
or return -1;
if ($ZFS_NOEXPORT) {
mysystem($EXPORTS_SETUP);
}
elsif (!$WITHAMD) {
mysystem($EXPORTS_SETUP . " -B");
}
# failed, reset the timestamp
if ($? && defined($lastactivity)) {
DBQueryWarn("update project_stats set ".
" last_activity=FROM_UNIXTIME($lastactivity) ".
"where pid_idx='$pid_idx'");
return -1;
}
}
return 0;
}
# _Always_ make sure that this 1 is at the end of the file... # _Always_ make sure that this 1 is at the end of the file...
1; 1;
...@@ -40,7 +40,7 @@ use overload ('""' => 'Stringify'); ...@@ -40,7 +40,7 @@ use overload ('""' => 'Stringify');
use vars qw($NEWUSER_FLAGS_PROJLEADER $NEWUSER_FLAGS_WIKIONLY use vars qw($NEWUSER_FLAGS_PROJLEADER $NEWUSER_FLAGS_WIKIONLY
$NEWUSER_FLAGS_WEBONLY $NEWUSER_FLAGS_ARCHIVED $NEWUSER_FLAGS_WEBONLY $NEWUSER_FLAGS_ARCHIVED
$NEWUSER_FLAGS_NOUUID $NEWUSER_FLAGS_NONLOCAL $NEWUSER_FLAGS_NOUUID $NEWUSER_FLAGS_NONLOCAL
$USERSTATUS_ACTIVE $USERSTATUS_FROZEN $USERSTATUS_ACTIVE $USERSTATUS_FROZEN $USERSTATUS_INACTIVE
$USERSTATUS_UNAPPROVED $USERSTATUS_UNVERIFIED $USERSTATUS_UNAPPROVED $USERSTATUS_UNVERIFIED
$USERSTATUS_NEWUSER $USERSTATUS_ARCHIVED $USERSTATUS_NONLOCAL $USERSTATUS_NEWUSER $USERSTATUS_ARCHIVED $USERSTATUS_NONLOCAL
@EXPORT_OK); @EXPORT_OK);
...@@ -53,6 +53,9 @@ my $TBAUDIT = "@TBAUDITEMAIL@"; ...@@ -53,6 +53,9 @@ my $TBAUDIT = "@TBAUDITEMAIL@";
my $TBBASE = "@TBBASE@"; my $TBBASE = "@TBBASE@";
my $TBWWW = "@TBWWW@"; my $TBWWW = "@TBWWW@";
my $WIKISUPPORT = @WIKISUPPORT@; my $WIKISUPPORT = @WIKISUPPORT@;
my $WITHZFS = @WITHZFS@;
my $ZFS_NOEXPORT = @ZFS_NOEXPORT@;
my $WITHAMD = @WITHAMD@;
my $BOSSNODE = "@BOSSNODE@"; my $BOSSNODE = "@BOSSNODE@";
my $CONTROL = "@USERNODE@"; my $CONTROL = "@USERNODE@";
my $OURDOMAIN = "@OURDOMAIN@"; my $OURDOMAIN = "@OURDOMAIN@";
...@@ -61,6 +64,7 @@ my $MIN_UNIX_GID = @MIN_UNIX_GID@; ...@@ -61,6 +64,7 @@ my $MIN_UNIX_GID = @MIN_UNIX_GID@;
my $tbacct = "$TB/sbin/tbacct"; my $tbacct = "$TB/sbin/tbacct";
my $MKUSERCERT = "$TB/sbin/mkusercert"; my $MKUSERCERT = "$TB/sbin/mkusercert";
my $EXPIRE_PASSWORDS = @EXPIRE_PASSWORDS@; my $EXPIRE_PASSWORDS = @EXPIRE_PASSWORDS@;
my $EXPORTS_SETUP = "$TB/sbin/exports_setup";
# Create() flags. # Create() flags.
$NEWUSER_FLAGS_PROJLEADER = 0x01; $NEWUSER_FLAGS_PROJLEADER = 0x01;
...@@ -78,12 +82,13 @@ $USERSTATUS_UNVERIFIED = "unverified"; ...@@ -78,12 +82,13 @@ $USERSTATUS_UNVERIFIED = "unverified";
$USERSTATUS_NEWUSER = "newuser"; $USERSTATUS_NEWUSER = "newuser";
$USERSTATUS_ARCHIVED = "archived"; $USERSTATUS_ARCHIVED = "archived";
$USERSTATUS_NONLOCAL = "nonlocal"; $USERSTATUS_NONLOCAL = "nonlocal";
$USERSTATUS_INACTIVE = "inactive";
# Why, why, why? # Why, why, why?
@EXPORT_OK = qw($NEWUSER_FLAGS_PROJLEADER $NEWUSER_FLAGS_WIKIONLY @EXPORT_OK = qw($NEWUSER_FLAGS_PROJLEADER $NEWUSER_FLAGS_WIKIONLY
$NEWUSER_FLAGS_WEBONLY $NEWUSER_FLAGS_ARCHIVED $NEWUSER_FLAGS_WEBONLY $NEWUSER_FLAGS_ARCHIVED
$NEWUSER_FLAGS_NOUUID $NEWUSER_FLAGS_NOUUID
$USERSTATUS_ACTIVE $USERSTATUS_FROZEN $USERSTATUS_ACTIVE $USERSTATUS_FROZEN $USERSTATUS_INACTIVE
$USERSTATUS_UNAPPROVED $USERSTATUS_UNVERIFIED $USERSTATUS_UNAPPROVED $USERSTATUS_UNVERIFIED
$USERSTATUS_NEWUSER $USERSTATUS_ARCHIVED $USERSTATUS_NONLOCAL); $USERSTATUS_NEWUSER $USERSTATUS_ARCHIVED $USERSTATUS_NONLOCAL);
...@@ -2210,6 +2215,53 @@ sub GetStoredCredential($) ...@@ -2210,6 +2215,53 @@ sub GetStoredCredential($)
return ($cred, $cert); return ($cred, $cert);
} }
#
# Do an exports setup if needed (ZFS). See exports_setup, when ZFS is on
# we do not export all users, only recently active ones.
#
sub UpdateExports($)
{
my ($self) = @_;
my $uid_idx = $self->uid_idx();
return 0
if (! ($WITHZFS && ($ZFS_NOEXPORT || !$WITHAMD)));
my $query_result =
DBQueryWarn("select UNIX_TIMESTAMP(weblogin_last) from users as u ".
"left join user_stats as s on s.uid_idx=u.uid_idx ".
"where u.uid_idx='$uid_idx'");
# Hmm.
return 0
if (!$query_result->numrows);
my ($lastlogin) = $query_result->fetchrow_array();
if (!defined($lastlogin) ||
time() - $lastlogin > (24 * 3600)) {
# Update weblogin_last first so exports_setup will do something.
DBQueryWarn("update user_stats set ".
" weblogin_last=now() ".
"where uid_idx='$uid_idx'")
or return -1;
if ($ZFS_NOEXPORT) {
mysystem($EXPORTS_SETUP);
}
elsif (!$WITHAMD) {
mysystem($EXPORTS_SETUP . " -B");
}
# failed, reset the timestamp
if ($? && defined($lastlogin)) {
DBQueryWarn("update user_stats set ".
" weblogin_last=FROM_UNIXTIME($lastlogin) ".
"where uid_idx='$uid_idx'");
return -1;
}
}
return 0;
}
# _Always_ make sure that this 1 is at the end of the file... # _Always_ make sure that this 1 is at the end of the file...
1; 1;
...@@ -817,6 +817,7 @@ sub admin($) { return $_[0]->{'USER'}->admin(); } ...@@ -817,6 +817,7 @@ sub admin($) { return $_[0]->{'USER'}->admin(); }
sub BumpActivity($) { return $_[0]->{'USER'}->BumpActivity(); } sub BumpActivity($) { return $_[0]->{'USER'}->BumpActivity(); }
sub DefaultProject($) { return $_[0]->{'USER'}->DefaultProject(); } sub DefaultProject($) { return $_[0]->{'USER'}->DefaultProject(); }
sub FlipTo($$) { return $_[0]->{'USER'}->FlipTo($_[1]); } sub FlipTo($$) { return $_[0]->{'USER'}->FlipTo($_[1]); }
sub UpdateExports($) { return $_[0]->{'USER'}->UpdateExports(); }
# Need to construct this since not in User structure. # Need to construct this since not in User structure.
sub hrn($) { return "${PGENIDOMAIN}." . $_[0]->uid(); } sub hrn($) { return "${PGENIDOMAIN}." . $_[0]->uid(); }
......
...@@ -112,6 +112,7 @@ sub FlipToUser($$;$) ...@@ -112,6 +112,7 @@ sub FlipToUser($$;$)
$default_gid = $unix_gid; $default_gid = $unix_gid;
$glist = "$unix_gid $unix_gid"; $glist = "$unix_gid $unix_gid";
} }
$GID = $default_gid; $GID = $default_gid;
$EGID = $glist; $EGID = $glist;
$EUID = $UID = $unix_uid; $EUID = $UID = $unix_uid;
...@@ -564,27 +565,10 @@ sub GetHoldingProject($$) ...@@ -564,27 +565,10 @@ sub GetHoldingProject($$)
$ENV{'EMULAB_REAL_USER'} = $creator->emulab_user()->uid_idx(); $ENV{'EMULAB_REAL_USER'} = $creator->emulab_user()->uid_idx();
} }
done: done:
if ($WITHZFS) { if ($creator->IsLocal()) {
if ($ZFS_NOEXPORT) { $creator->UpdateExports();
#
# Have to force the new directories to be exported.
# See ZFS code in exports_setup
#
$project->BumpActivity();
system($EXPORTSSETUP) == 0 or
fatal("$EXPORTSSETUP failed");
} elsif (!$WITHAMD) {
#
# If we are using autofs, we need to recreate the local autofs
# mapfile so it includes the newly created directories. Otherwise,
# accesses to those new directories will not force a mount and
# the waitForMount() calls below will always fail.
#
$project->BumpActivity();
system("$EXPORTSSETUP -B") == 0 or
fatal("$EXPORTSSETUP -B failed");
}
} }
$project->UpdateExports();
return $group; return $group;
} }
......
...@@ -56,7 +56,7 @@ my $PGENISUPPORT = @PROTOGENI_SUPPORT@; ...@@ -56,7 +56,7 @@ my $PGENISUPPORT = @PROTOGENI_SUPPORT@;
my $PORTAL_ENABLE = @PORTAL_ENABLE@; my $PORTAL_ENABLE = @PORTAL_ENABLE@;
my $PORTAL_PRIMARY = @PORTAL_ISPRIMARY@; my $PORTAL_PRIMARY = @PORTAL_ISPRIMARY@;
my $MODGROUPS = "$TB/sbin/modgroups"; my $MODGROUPS = "$TB/sbin/modgroups";
my $DELACCT = "$TB/sbin/tbacct del"; my $TBACCT = "$TB/sbin/tbacct";
my $POSTCRL = "$TB/sbin/protogeni/postcrl"; my $POSTCRL = "$TB/sbin/protogeni/postcrl";
# Locals # Locals
...@@ -136,6 +136,7 @@ if (! defined($target_user)) { ...@@ -136,6 +136,7 @@ if (! defined($target_user)) {
} }
my $target_dbid = $target_user->dbid(); my $target_dbid = $target_user->dbid();
my $target_uid = $target_user->uid(); my $target_uid = $target_user->uid();
my $reactivate = $target_user->status() eq $User::USERSTATUS_INACTIVE;
# Map invoking user to object. # Map invoking user to object.
my $this_user = User->ThisUser(); my $this_user = User->ThisUser();
...@@ -359,8 +360,15 @@ $target_user->Purge() == 0 ...@@ -359,8 +360,15 @@ $target_user->Purge() == 0
if (! $nuke) { if (! $nuke) {
$EUID = $UID; $EUID = $UID;
system("$DELACCT $target_uid") == 0 or #
fatal("$DELACCT $target_uid failed!"); # Before we can do anything, we have to reactivate.
#
if ($reactivate &&
system("$TBACCT -f reactivate $target_uid")) {
fatal("$TBACCT -f reactivate $target_uid failed!");
}
system("$TBACCT del $target_uid") == 0 or
fatal("$TBACCT del $target_uid failed!");
$EUID = 0; $EUID = 0;
} }
......
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