Commit 3e05832d authored by Leigh Stoller's avatar Leigh Stoller

The Big group thing!

parent a1f22169
......@@ -1047,7 +1047,8 @@ outfiles="$outfiles Makeconf GNUmakefile \
tbsetup/tbreport tbsetup/named_setup tbsetup/exports_setup \
tbsetup/checkpass/GNUmakefile tbsetup/assign_wrapper tbsetup/ptopgen \
tbsetup/frisbeelauncher tbsetup/node_update tbsetup/webnodeupdate \
tbsetup/savelogs \
tbsetup/savelogs tbsetup/group-update tbsetup/webgroupupdate \
tbsetup/rmgroup tbsetup/webrmgroup tbsetup/mkexpdir \
tip/GNUmakefile \
tmcd/GNUmakefile tmcd/freebsd/GNUmakefile tmcd/linux/GNUmakefile \
tmcd/netbsd/GNUmakefile \
......
......@@ -169,7 +169,8 @@ outfiles="$outfiles Makeconf GNUmakefile \
tbsetup/tbreport tbsetup/named_setup tbsetup/exports_setup \
tbsetup/checkpass/GNUmakefile tbsetup/assign_wrapper tbsetup/ptopgen \
tbsetup/frisbeelauncher tbsetup/node_update tbsetup/webnodeupdate \
tbsetup/savelogs \
tbsetup/savelogs tbsetup/group-update tbsetup/webgroupupdate \
tbsetup/rmgroup tbsetup/webrmgroup tbsetup/mkexpdir \
tip/GNUmakefile \
tmcd/GNUmakefile tmcd/freebsd/GNUmakefile tmcd/linux/GNUmakefile \
tmcd/netbsd/GNUmakefile \
......
......@@ -39,11 +39,13 @@ use libtestbed;
# We don't want to run this script unless its the real version.
#
if ($EUID != 0) {
die("Must be root! Maybe its a development version?\n");
die("*** $0:\n".
" Must be root! Maybe its a development version?\n");
}
# XXX Hacky!
if ($TB ne "/usr/testbed") {
die("Wrong version. Maybe its a development version?\n");
die("*** $0:\n".
" Wrong version. Maybe its a development version?\n");
}
#
......@@ -76,7 +78,8 @@ foreach my $active ( 0, 1 ) {
# All active users on the testbed
if (! ($query_result =
DBQuery("SELECT DISTINCT u.usr_email from experiments as e ".
"left join proj_memb as p on e.pid=p.pid ".
"left join group_membership as p ".
" on e.pid=p.pid and p.pid=p.gid ".
"left join users as u on u.uid=p.uid ".
"where u.status='active' order by u.usr_email"))) {
DBFatal("Getting Active Users!");
......
This diff is collapsed.
......@@ -41,17 +41,20 @@ my @nodes= ();
if ($debug) { print "Expt '$eid', proj '$pid'\n"; }
#
# Make sure the user is a member of the correct project, and that the
# experiment exists
# Experiment must exist.
#
if (!ExpState($pid,$eid)) {
die "There is no experiment $eid in project $pid\n";
}
#
# User must have permission to modify the experiment.
#
if ($UID) {
if (!ProjMember($pid)) {
die "You are not a member of project $pid\n";
if (!TBExptAccessCheck($UID, $pid, $eid, TB_EXPT_MODIFY)) {
die("*** You not have permission to allocate nodes in $pid/$eid!\n");
}
}
if (!ExpState($pid,$eid)) {
die "There is no experiment $eid in project $pid\n";
}
######################################################################
# Step 1 - Make a list of nodes to reserve
......
......@@ -261,7 +261,7 @@ int main(int argc, char *argv[])
{
int userdir = 0; /* ~userdir flag */
uid_t uid; /* user information */
gid_t gid; /* target group placeholder */
gid_t gid, primary_gid; /* target group placeholder */
char *target_uname; /* target user name */
char *target_gname; /* target group name */
char *target_homedir; /* target home directory */
......@@ -411,6 +411,7 @@ int main(int argc, char *argv[])
* Save these for later since initgroups will hose the struct
*/
uid = pw->pw_uid;
primary_gid = pw->pw_gid;
actual_uname = strdup(pw->pw_name);
target_homedir = strdup(pw->pw_dir);
......@@ -441,6 +442,30 @@ int main(int argc, char *argv[])
exit(108);
}
#ifdef TESTBED
{
int groups[NGROUPS], ngroups, i;
ngroups = NGROUPS;
getgrouplist(actual_uname, primary_gid, groups, &ngroups);
if (ngroups == NGROUPS) {
log_err("emerg: failed to getgroups (%ld: %s)\n", gid, cmd);
exit(109);
}
for (i = 0; i < ngroups; i++) {
if (groups[i] == gid)
break;
}
if (i == ngroups)
groups[ngroups++] = gid;
if (((setgid(primary_gid)) != 0) ||
(setgroups(ngroups, groups) != 0)) {
log_err("emerg: failed to setgid (%ld: %s)\n", gid, cmd);
exit(109);
}
}
#else
/*
* Change UID/GID here so that the following tests work over NFS.
*
......@@ -451,6 +476,7 @@ int main(int argc, char *argv[])
log_err("emerg: failed to setgid (%ld: %s)\n", gid, cmd);
exit(109);
}
#endif
/*
* setuid() to the target user. Error out on fail.
......
......@@ -19,12 +19,14 @@ USERBINS = os_load node_reboot nscheck node_update savelogs
SBIN_STUFF = resetvlans console_setup.proxy sched_reload named_setup \
batch_daemon exports_setup reload_daemon sched_reserve \
console_reset db2ns bwconfig frisbeelauncher
console_reset db2ns bwconfig frisbeelauncher group-update \
rmgroup
LIBEXEC_STUFF = mkprojdir rmproj mkacct-ctrl rmacct-ctrl \
os_setup mkexpdir console_setup webnscheck webreport \
webstartexp webendexp webbatchexp webkillbatchexp \
assign_wrapper ptopgen webnodeupdate
assign_wrapper ptopgen webnodeupdate webgroupupdate \
webrmgroup
LIB_STUFF = libtbsetup.pm exitonwarn.pm libtestbed.pm snmpit_intel.pm \
snmpit_cisco.pm snmpit_lib.pm snmpit_apc.pm power_rpc27.pm
......@@ -68,6 +70,8 @@ post-install:
chmod u+s $(INSTALL_LIBEXECDIR)/mkprojdir
chown root $(INSTALL_LIBEXECDIR)/rmproj
chmod u+s $(INSTALL_LIBEXECDIR)/rmproj
chown root $(INSTALL_SBINDIR)/rmgroup
chmod u+s $(INSTALL_SBINDIR)/rmgroup
chown root $(INSTALL_LIBEXECDIR)/mkacct-ctrl
chmod u+s $(INSTALL_LIBEXECDIR)/mkacct-ctrl
chown root $(INSTALL_LIBEXECDIR)/rmacct-ctrl
......@@ -78,6 +82,8 @@ post-install:
chmod u+s $(INSTALL_SBINDIR)/exports_setup
chown root $(INSTALL_BINDIR)/savevlans
chmod u+s $(INSTALL_BINDIR)/savevlans
chown root $(INSTALL_SBINDIR)/group-update
chmod u+s $(INSTALL_SBINDIR)/group-update
chown root $(INSTALL_LIBEXECDIR)/console_setup
chmod u+s $(INSTALL_LIBEXECDIR)/console_setup
chown root $(INSTALL_BINDIR)/node_reboot
......
......@@ -54,6 +54,7 @@ my $dirname;
#
my $eid;
my $pid;
my $gid;
my $logname;
my $nsfile;
my $user_name = "Testbed Operations";
......@@ -209,11 +210,12 @@ sub dosomething($$)
{
my($dowhat) = shift;
my(%exphash) = @_;
my($uid, $gid, $row, $query_result);
my($unix_uid, $unix_gid, $row, $query_result);
# Global vars
$eid = $exphash{'eid'};
$pid = $exphash{'pid'};
$gid = $exphash{'gid'};
print "Doing a '$dowhat' to batch experiment $pid/$eid\n";
......@@ -277,19 +279,19 @@ sub dosomething($$)
# Figure out the unix uid/gid that the experiment configuration is
# going to run as.
#
(undef,undef,$uid) = getpwnam($creator) or
(undef,undef,$unix_uid) = getpwnam($creator) or
fatal("No such user $creator");
(undef,undef,$gid) = getgrnam($pid) or
fatal("No such group $pid");
(undef,undef,$unix_gid) = getgrnam($gid) or
fatal("No such group $gid");
#
# Change the ownership of the log file before we flip.
#
chown($uid, $gid, $logname);
chown($unix_uid, $unix_gid, $logname);
# Flip to the user. We never flip back.
$EGID = $GID = $gid;
$EUID = $UID = $uid;
$EGID = $GID = $unix_gid;
$EUID = $UID = $unix_uid;
$ENV{'USER'} = $creator;
if ($dowhat eq "start") {
......@@ -323,15 +325,16 @@ sub startexp($)
#
$query_result =
DBQueryFatal("insert into experiments ".
"(eid, pid, expt_created, expt_name, ".
"(eid, pid, gid, expt_created, expt_name, ".
"expt_head_uid, expt_expires, state, batchmode) ".
"VALUES ('$eid', '$pid', '$rightnow', '$longname', ".
"'$creator', '$expires', 'new', 1)");
"VALUES ('$eid', '$pid', '$gid', '$rightnow', ".
" '$longname', ".
" '$creator', '$expires', 'new', 1)");
#
# Try to start the experiment. If it fails, the experiment is gone.
#
system("$startexp -b $logname $pid $eid $nsfile");
system("$startexp -b $logname -g $gid $pid $eid $nsfile");
$exit_status = $? >> 8;
$running = 1;
if ($exit_status) {
......
......@@ -5,8 +5,6 @@ use Getopt::Std;
#
# Create a batch experiment.
#
# usage: batchexp <batchfile>
#
sub usage()
{
print STDOUT "Usage: batchexp <batchfile>\n";
......@@ -29,7 +27,7 @@ use libtestbed;
my $tbbindir = "$TB/bin/";
my $batchdir = "$TB/batch";
my $parser = "/usr/testbed/libexec/ns2ir/parse.tcl";
my $parser = "$TB/libexec/ns2ir/parse.tcl";
my $projroot = "/proj";
my $dirname;
......@@ -74,19 +72,21 @@ else {
#
my $eid;
my $pid;
my $gid;
my $dbuid;
my $longname;
my $expires;
my $webnsfile;
parse_batchfile($tempfile) or
fatal("Could not parse batchfile $tempfile");
fatal("*** Could not parse batchfile $tempfile");
#
# Sanity check a few things.
#
if (!defined($eid) || !defined($pid) || !defined($longname) ||
!defined($expires) || !defined($webnsfile)) {
fatal("Batchfile is incomplete!");
fatal("*** Batchfile is incomplete!");
}
$nsfile = "$eid.ns";
......@@ -96,50 +96,33 @@ $nsfile = "$eid.ns";
$dirname = "$batchdir/$pid-$eid";
mkdir($dirname, 0775) or
fatal("Could not mkdir $dirname: $!");
fatal("*** Could not mkdir $dirname: $!");
chdir($dirname) or
fatal("Could not chdir to $dirname: $!");
fatal("*** Could not chdir to $dirname: $!");
#
# Copy in the batch file. Web script is responsible for removing the
# original.
#
if (system("/bin/cp", "$tempfile", "batchfile")) {
fatal("Could not copy $tempfile to $dirname");
fatal("*** Could not copy $tempfile to $dirname");
}
#
# Now a bunch of DB checks.
#
# First off, get some user information.
# Verify user and get his DB uid.
#
$query_result =
DBQuery("SELECT uid from users WHERE unix_uid='$EUID'");
if ($query_result->numrows < 1) {
fatal("Go Away! You do not exist in the Emulab Database.");
if (! UNIX2DBUID($UID, \$dbuid)) {
fatal("*** You do not exist in the Emulab Database!");
}
@row = $query_result->fetchrow_array();
$uid = $row[0];
#
# Make sure UID is allowed to create experiments in this project.
#
$query_result =
DBQuery("SELECT trust from proj_memb WHERE uid='$uid' and pid='$pid'");
if ($query_result->numrows == 0) {
fatal("Go Away! You are not a member of project $pid!");
}
@row = $query_result->fetchrow_array();
$trust = $row[0];
if ($trust ne "local_root" &&
$trust ne "group_root") {
fatal("Go Away! You are not a trusted member of project $pid!");
if (!TBAdmin($UID) &&
!TBProjAccessCheck($dbuid, $pid, $gid, TB_PROJECT_CREATEEXPT)) {
fatal("*** You do not have permission to create experiments ".
"in project $pid";
}
#
......@@ -150,7 +133,7 @@ $query_result =
"WHERE eid='$eid' and pid='$pid'");
if ($query_result->numrows) {
fatal("Experiment $eid in project $pid already exists!");
fatal("*** Experiment $eid in project $pid already exists!");
}
$query_result =
......@@ -158,21 +141,21 @@ $query_result =
"WHERE eid='$eid' and pid='$pid'");
if ($query_result->numrows) {
fatal("Batch experiment $eid in project $pid already exists!");
fatal("*** Batch experiment $eid in project $pid already exists!");
}
#
# Now we can get the NS file!
#
if (system("/bin/cp", "$webnsfile", "$nsfile")) {
fatal("Could not copy $webnsfile to $dirname/$nsfile");
fatal("*** Could not copy $webnsfile to $dirname/$nsfile");
}
# Run parse in impotent mode on the NS file. This has no effect but
# will display any errors.
if (system("$parser -n -a $nsfile") != 0) {
fatal("NS Parse failed!");
fatal("*** NS Parse failed!");
}
#
......@@ -185,10 +168,10 @@ $created = DBDateTime();
# is looking for batch experiments to run. Easy race avoidance.
#
DBQueryFatal("INSERT INTO batch_experiments ".
"(eid, pid, created, expires, ".
"(eid, pid, gid, created, expires, ".
" name, creator_uid, status) ".
"VALUES ('$eid', '$pid', '$created', '$expires', ".
"'$longname', '$uid', 'new')");
"VALUES ('$eid', '$pid', '$gid', '$created', '$expires', ".
"'$longname', '$dbuid', 'new')");
exit 0;
......@@ -224,6 +207,10 @@ sub parse_batchfile()
$pid = $1;
next;
}
if ($_ =~ /^GID:\s+([-\@\w.]*)/) {
$gid = $1;
next;
}
if ($_ =~ /^name:\s+([-\@\w. ]*)/) {
$longname = $1;
next;
......
......@@ -50,7 +50,8 @@ my @nodes = @ARGV;
# nodes are specified since this script always does the right thing.
#
if ($EUID != 0) {
die("Must be root! Maybe its a development version?\n");
die("*** $0:\n".
" Must be root! Maybe its a development version?\n");
}
#
......@@ -83,7 +84,12 @@ foreach my $node (@nodes) {
}
else {
$db_result =
DBQueryFatal("select pid from reserved where node_id='$node'");
DBQueryFatal("select g.unix_name from groups as g ".
"left join experiments as e ".
" on g.pid=e.pid and g.gid=e.gid ".
"left join reserved as r ".
" on e.pid=r.pid and e.eid=r.eid ".
"where r.node_id='$node'");
}
if ($db_result->numrows > 0) {
@row = $db_result->fetchrow_array();
......
#!/usr/bin/perl -w
use English;
# This is a very simple program that convers the virt_* tables in the DB
# into a NS file. Not the original NS file, but a NS file that, if parsed
......@@ -16,17 +17,18 @@ if ($#ARGV != 1) {
($pid,$eid) = @ARGV;
#
# Make sure they have access to the experiment
# Make sure the experiment exists
#
if ((!TBAdmin()) && (!ProjMember($pid))) {
die "You are not a member of project %pid";
if (!ExpState($pid,$eid)) {
die "There is no experiment $eid in project $pid\n";
}
#
# Make sure the experiment exists
# Make sure they have access to the experiment
#
if (!ExpState($pid,$eid)) {
die "There is no experiment $eid in project $pid\n";
if (!TBAdmin($UID) &&
!TBExptAccessCheck($UID, $pid, $eid, TB_EXPT_READINFO)) {
die("*** You do not have permission to access this experiment!\n");
}
print "source tb_compat.tcl\n";
......
......@@ -106,15 +106,12 @@ if (! UserDBInfo($user_login, \$user_name, \$user_email)) {
}
#
# Verify that this person is allowed to end the experiment. Must be
# in the project membership table, or must be an admin type. Note that
# any script down the line has to do an admin check also.
# Verify that this person is allowed to end the experiment.
# Note that any script down the line has to do an admin check also.
#
if ($EUID && !TBAdmin($EUID) &&
ProjMember($pid, $user_login) != PROJMEMBERTRUST_ROOT) {
print STDOUT "Go Away! You do not have permission to end experiments ".
"in project $pid\n";
!TBExptAccessCheck($user_login, $pid, $eid, TB_EXPT_DESTROY)) {
print STDOUT "You do not have permission to end this experiment!\n";
exit(1);
}
......@@ -314,6 +311,12 @@ sub fatal($)
print STDOUT $mesg;
#
# Kill this for convenience later.
#
DBQueryWarn("update experiments set expt_terminating=NULL ".
"WHERE eid='$eid' and pid='$pid'");
#
# In batch mode, exit without sending the email.
#
......
......@@ -33,12 +33,18 @@ my @row;
# We don't want to run this script unless its the real version.
#
if ($EUID != 0) {
die("Must be root! Maybe its a development version?\n");
die("*** $0:\n".
" Must be root! Maybe its a development version?\n");
}
# XXX Hacky!
#if ($TB ne "/usr/testbed") {
# die("Wrong version. Maybe its a development version?\n");
#}
if ($TB ne "/usr/testbed") {
# print STDERR "*** $0:\n".
# " Wrong version. Maybe its a development version?\n";
#
# Let experiment continue setting up.
#
# exit(0);
}
# un-taint path
$ENV{'PATH'} = '/bin:/usr/bin:/usr/sbin:/usr/local/bin';
......@@ -199,16 +205,16 @@ if (@ipseq) {
#
$db_result =
DBQueryFatal("select distinct reserved.node_id,reserved.pid,".
"proj_memb.uid,interfaces.IP from reserved ".
"g.uid,interfaces.IP from reserved ".
"left join exppid_access as a ".
" on a.exp_pid=reserved.pid and a.exp_eid=reserved.eid ".
"left join proj_memb on proj_memb.pid=reserved.pid ".
" or proj_memb.pid=a.pid ".
"left join group_membership as g on g.pid=a.pid or ".
" (g.pid=reserved.pid and g.gid=g.pid) ".
"left join nodes on reserved.node_id=nodes.node_id ".
"left join node_types on node_types.type=nodes.type ".
"left join interfaces on reserved.node_id=interfaces.node_id ".
"and interfaces.card=node_types.control_net ".
"where interfaces.IP!='NULL' and proj_memb.trust!='none' ".
"where interfaces.IP!='NULL' and g.trust!='none' ".
"order by reserved.pid,reserved.node_id");
%iphash = ();
......
#!/usr/bin/perl -wT
use English;
use Errno;
use Fcntl ':flock';
#
......@@ -94,8 +95,9 @@ $mpid =~ s/\n//;
if ($mpid =~ /^([-\@\w.]+)$/) {
$mpid = $1;
}
kill('HUP', $mpid) or
if (kill('HUP', $mpid) == 0) {
fatal("Could not kill(HUP) process $mpid (mountd): $!");
}
#
# Allow time to react since HUP'ing mountd causes all mounts to briefly
......
#!/usr/bin/perl -wT
use English;
use Errno;
use Fcntl ':flock';
#
......@@ -94,8 +95,9 @@ $mpid =~ s/\n//;
if ($mpid =~ /^([-\@\w.]+)$/) {
$mpid = $1;
}
kill('HUP', $mpid) or
if (kill('HUP', $mpid) == 0) {
fatal("Could not kill(HUP) process $mpid (mountd): $!");
}
#
# Allow time to react since HUP'ing mountd causes all mounts to briefly
......
#!/usr/bin/perl -wT
use English;
use Getopt::Std;
#
# Create/Update a group.
#
# usage: group-update [-b] <pid> <gid>
#
sub usage()
{
print STDOUT "Usage: group-update -b <pid> <gid>\n";
exit(-1);
}
my $optlist = "b";
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $TBLOGS = "@TBLOGSEMAIL@";
my $CONTROL = "@USERNODE@";
my $PROJROOT = "/proj";
my $SSH = "$TB/bin/sshtb";
my $GROUPADD = "/usr/sbin/pw groupadd";
my $USERMOD = "/usr/sbin/pw usermod";
my $mkacct = "$TB/libexec/mkacct-ctrl";
my $batchmode = 0;
my $dbuid;
my $user;
my @db_row;
my $query_result;
my $leader;
my $groupdir;
my $logname;
my $user_name;
my $user_email;
#
# Note hardwired control node.
#
my $control_node = $CONTROL;
#
# We don't want to run this script unless its the real version.
#
if ($EUID != 0) {
die("*** $0:\n".
" Must be setuid! Maybe its a development version?\n");
}
#
# This script is setuid, so please do not run it as root. Hard to track
# what has happened.
#
if ($UID == 0) {
die("*** $0:\n".
" Please do not run this as root! Its already setuid!\n");
}
#
# Untaint the path
#
$ENV{'PATH'} = "/bin:/usr/bin";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Turn off line buffering on output
#
$| = 1;
#
# Load the Testbed support stuff.
#
use lib "@prefix@/lib";
use libdb;
use libtestbed;
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
%options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (@ARGV != 2) {
usage();
}
if (defined($options{"b"})) {
$batchmode = 1;
}
my $pid = $ARGV[0];
my $gid = $ARGV[1];
#
# Untaint args.
#
if ($pid =~ /^([-\@\w]+)$/) {
$pid = $1;
}
else {
die("Bad data in pid: $pid.");
}
if ($gid =~ /^([-\@\w]+)$/) {
$gid = $1;
}
else {
die("Bad data in gid: $gid.");
}
#
# Get user DB uid.
#
if (! UNIX2DBUID($UID, \$dbuid)) {
die("*** You do not exist in the Emulab Database!\n");
}
#
# Get email info for mail.
#
if (! UserDBInfo($dbuid, \$user_name, \$user_email)) {
die("*** Cannot determine email info for you!\n");
}
#
# This script always does the right thing, so it does not matter who
# calls it. But we guard it anyway in the case where ops/boss are the
# same.
#
if (!TBAdmin($UID)) {
#
# Must be project root for the project or group root for the group.
#
$query_result =
DBQueryFatal("select trust from group_membership ".
"where pid='$pid' and uid='$dbuid' and gid='$pid' and ".
"trust='project_root'");
if ($query_result->numrows == 0) {
$query_result =
DBQueryFatal("select trust from group_membership ".
"where pid='$pid' and uid='$dbuid' and gid='$gid' ".
"and trust='group_root'");
if ($query_result->numrows == 0) {
die("*** $dbuid does not have permission to update groups!\n");
}
}
}
if (! ($leader = GroupLeader($pid, $gid))) {
die("*** Could not determine group leader for $pid/$gid!\n");
}