diff --git a/db/libdb.pm.in b/db/libdb.pm.in index 01ac5b87d8b44d78c8225cd90b78e7e887c5cb05..4a1de73c1df23a1eaf94c3580aaa11b5b9db46d4 100644 --- a/db/libdb.pm.in +++ b/db/libdb.pm.in @@ -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 diff --git a/tbsetup/mkacct.in b/tbsetup/mkacct.in index b3dc3f1c148276c3ada4c7c6242c5ea8d38803d0..53bc29884c2a88265a2699f5652abca09d0e7937 100755 --- a/tbsetup/mkacct.in +++ b/tbsetup/mkacct.in @@ -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; +} diff --git a/tbsetup/node_update.in b/tbsetup/node_update.in index 843d26b37d4285f718723e7602fe9de598e1ca5b..223f6db449f2001737cc3eea6d17dc2a11f40da3 100644 --- a/tbsetup/node_update.in +++ b/tbsetup/node_update.in @@ -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 ) {