Commit a9909c42 authored by Leigh Stoller's avatar Leigh Stoller

libdb: Add a couple of support routines to update the account_update

flag in the nodes table when a user changes his info. Two routines,
one to do it by type (as for widearea nodes) and another to do it by
project (as for local) nodes. This last is kinda inefficient, but
probably not too big a deal.

mkacct: Two changes.
1. Use the above changes in libdb when a user changes his info. With
   this change, no longer need to do an account update in the
   experiment page for the ron/wa nodes. The nodes are marked as
   needing the update in mkacct, based on the nodes the user has
   access to. Note, this change applies only to widearea nodes; still
   need to use the update option in the experiment menu for local
   nodes, although I plan to change that to at some point by adding a
   watchdog on the local nodes.

2. ssh2 key support. The DB can now store both ssh1 and ssh2 keys,
   however those keys are handled differently when creating the auth
   keys files for users. There are actually two files created now, the
   second being the ssh2 key file call authorized_keys2. This change
   is mirrored in the client side code as well.
parent c3f9be20
......@@ -97,6 +97,7 @@ use Exporter;
TBIsNodeRemote TBExptSetLogFile TBExptClearLogFile TBExptGetLogFile
TBIsNodeVirtual TBControlNetIP TBPhysNodeID
TBExptOpenLogFile TBExptCloseLogFile TBExptCreateLogFile
TBNodeUpdateAccountsByPid TBNodeUpdateAccountsByType
TBDB_WIDEAREA_LOCALNODE
TBWideareaNodeID
......@@ -1819,6 +1820,61 @@ sub TBWideareaNodeID($$)
return 1;
}
#
# Mark a node as needing account updates. This variant does it based
# on node type, and all of the nodes of that type are marked. This is
# used for marking widearea nodes.
#
# usage TBNodeUpdateAccountsByType(char type)
# Returns 1 all the time.
#
sub TBNodeUpdateAccountsByType($)
{
my ($nodetype) = @_;
#
# No point in incrementing the flag past 2 since all that does is
# cause needless updates.
#
DBQueryFatal("update nodes set update_accounts=update_accounts+1 ".
"where type='$nodetype' and update_accounts<2");
return 1;
}
#
# Mark a node as needing account updates. This variant does it based
# on pid; all of the nodes in that pid are marked. Not very efficient!
#
# usage TBNodeUpdateAccountsByPid(char pid)
# Returns 1 all the time.
#
sub TBNodeUpdateAccountsByPid($)
{
my ($pid) = @_;
my $query_result =
DBQueryWarn("select r.node_id from reserved as r ".
"left join nodes as n on r.node_id=n.node_id ".
"where r.pid='$pid' and n.update_accounts=0");
if (! $query_result ||
! $query_result->numrows) {
return 1;
}
while (@row = $query_result->fetchrow_array()) {
my $nodeid = $row[0];
#
# No point in incrementing the flag past 2 since all that does is
# cause needless updates.
#
DBQueryFatal("update nodes set update_accounts=update_accounts+1 ".
"where node_id='$nodeid' and update_accounts<2");
}
return 1;
}
#
# Issue a DB query. Argument is a string. Returns the actual query object, so
......
......@@ -315,57 +315,58 @@ if ($control_node ne $BOSSNODE) {
#
# Create a new authorized keys file from DB.
#
# Grab pub keys.
# Grab pub keys and split into P1 and P2.
#
$query_result =
DBQueryFatal("select * from user_pubkeys where uid='$user'");
#
# Okay, regen it.
#
if (open(AKEYS, "> $SSHDIR/authorized_keys.new")) {
print "Generating a new authorized_keys file for $user\n";
print AKEYS "#\n";
print AKEYS "# DO NOT EDIT! This file auto generated by ".
"Emulab.Net account software.\n";
print AKEYS "#\n";
print AKEYS "# Please use the web interface to edit your ".
"public key list.\n";
print AKEYS "#\n";
my @p1keys = ();
my @p2keys = ();
while (my %row = $query_result->fetchhash()) {
my $pubkey = $row{'pubkey'};
while (my %row = $query_result->fetchhash()) {
my $key = $row{'pubkey'};
print AKEYS "$pubkey\n";
if ($key =~ /^\d+\s+.*$/) {
push(@p1keys, $key);
}
close(AKEYS);
chmod(0600, "$SSHDIR/authorized_keys.new") or
fatal("Could not chmod authorized_keys.new for $user: $!");
chown($user_number, $default_groupgid, "$SSHDIR/authorized_keys.new") or
fatal("Could not chown authorized_keys.new for $user: $!");
if (-e "$SSHDIR/authorized_keys") {
if (system("cp -f -p $SSHDIR/authorized_keys ".
"$SSHDIR/authorized_keys.old")) {
fatal("Could not save authorized_keys for $user: $!");
}
chmod(0600, "$SSHDIR/authorized_keys.old") or
fatal("Could not chmod authorized_keys.old for $user: $!");
chown($user_number, $default_groupgid,
"$SSHDIR/authorized_keys.old") or
fatal("Could not chown authorized_keys.old for $user: $!");
}
if (system("mv -f $SSHDIR/authorized_keys.new ".
"$SSHDIR/authorized_keys")) {
fatal("Could not mv authorized_keys.new for $user: $!");
else {
push(@p2keys, $key);
}
}
else {
warn("*** $0:\n".
" Could not open new authorized_keys file for $user!\n");
NewsshKeyfile($SSHDIR, $user_number, $default_groupgid, 1, @p1keys);
NewsshKeyfile($SSHDIR, $user_number, $default_groupgid, 2, @p2keys);
#
# Now schedule account updates on all the nodes that this person has
# an account on.
#
# There are two sets of nodes. The first is all of the local nodes in all of
# projects the user is a member of. The second is all of the widearea nodes
# that the project has access to. Rather than operate on a per node basis.
# grab the project names (for the reserved table) and the remote types
# to match against the node types. Of course, the pcremote_ok slot is a
# set, so need to parse that.
#
$query_result =
DBQueryFatal("select p.pid,pcremote_ok from users as u ".
"left join group_membership as g on ".
" u.uid=g.uid and g.pid=g.gid ".
"left join projects as p on p.pid=g.pid ".
"where u.uid='$user'");
while (my %row = $query_result->fetchhash()) {
my $pid = $row{'pid'};
my $pcremote = $row{'pcremote_ok'};
if (defined($pcremote)) {
my @typelist = split(',', $pcremote);
foreach my $nodetype (@typelist) {
TBNodeUpdateAccountsByType($nodetype);
}
}
TBNodeUpdateAccountsByPid($pid);
}
if ($auditmode) {
......@@ -504,3 +505,69 @@ sub FirstTime()
exit(0);
}
#
# Generate ssh authorized_keys files. Either protocol 1 or 2.
# Returns 0 on success, -1 on failure.
#
sub NewsshKeyfile($$$$$)
{
my ($sshdir, $uid, $gid, $protocol, @pkeys) = @_;
my $keyfile = "$sshdir/authorized_keys";
if (! -e $sshdir) {
if (! mkdir($sshdir, 0700)) {
warn("*** WARNING: Could not mkdir $sshdir: $!\n");
return -1;
}
if (!chown($uid, $gid, $sshdir)) {
warn("*** WARNING: Could not chown $sshdir: $!\n");
return -1;
}
}
if ($protocol == 2) {
$keyfile .= "2";
}
if (!open(AUTHKEYS, "> ${keyfile}.new")) {
warn("*** WARNING: Could not open ${keyfile}.new: $!\n");
return -1;
}
print AUTHKEYS "#\n";
print AUTHKEYS "# DO NOT EDIT! This file auto generated by ".
"Emulab.Net account software.\n";
print AUTHKEYS "#\n";
print AUTHKEYS "# Please use the web interface to edit your ".
"public key list.\n";
print AUTHKEYS "#\n";
foreach my $key (@pkeys) {
print AUTHKEYS "$key\n";
}
close(AUTHKEYS);
if (!chown($uid, $gid, "${keyfile}.new")) {
warn("*** WARNING: Could not chown ${keyfile}.new: $!\n");
return -1;
}
if (!chmod(0600, "${keyfile}.new")) {
warn("*** WARNING: Could not chmod ${keyfile}.new: $!\n");
return -1;
}
if (-e "${keyfile}") {
if (system("cp -p -f ${keyfile} ${keyfile}.old")) {
warn("*** Could not save off ${keyfile}: $!\n");
return -1;
}
if (!chown($uid, $gid, "${keyfile}.old")) {
warn("*** Could not chown ${keyfile}.old: $!\n");
}
if (!chmod(0600, "${keyfile}.old")) {
warn("*** Could not chmod ${keyfile}.old: $!\n");
}
}
if (system("mv -f ${keyfile}.new ${keyfile}")) {
warn("*** Could not mv ${keyfile} to ${keyfile}.new: $!\n");
}
return 0;
}
......@@ -204,7 +204,7 @@ if (! @nodes) {
}
#
# For widearea nodes, just update flag them in the DB. The nodes will
# For widearea nodes, just flag them in the DB. The nodes will
# notice this and suck the data over when they can.
#
foreach my $node ( @nodes ) {
......
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