Commit 5ef8f70a authored by Leigh Stoller's avatar Leigh Stoller

Major rework of the script interface to Emulab. Up to now we have been

supporting both a shell script driven interface, plus the newer XMLRPC
interface. This change removes the script driven interface from boss,
replacing it with just the XMLRPC interface. Since we like to maintain
backwards compatability with interfaces we have advertised to users (and
which we know are being used), I have implemented a script wrapper that
exports the same interface, but which converts the operations into XMLRPC
requests to the server. This wrapper is written in python and uses our
locally grown xmlrpc-over-ssh library. Like the current "demonstation"
client, you can take this wrapper to your machine that has python and ssh
installed, and use it there; you do not need to use these services from
just users.emulab.net. Other things to note:

* The wrapper is a single python script that has a "class" for each wrapped
  script. Running the wrapper without any arguments will list all of the
  operations it supports. You can invoke the wrapper with the operation as
  its argument:

    {987} stoller$ script_wrapper.py swapexp --help
    swapexp -e pid,eid in|out
    swapexp pid eid in|out
    where:
         -w   - Wait for experiment to finish swapping
         -e   - Project and Experiment ID
         in   - Swap experiment in  (must currently be swapped out)
        out   - Swap experiment out (must currently be swapped in)

    Wrapper Options:
        --help      Display this help message
        --server    Set the server hostname
        --login     Set the login id (defaults to $USER)
        --debug     Turn on semi-useful debugging

   But more convenient is to create a set of symlinks so that you can just
   invoke the operation by its familiar scriptname. This is what I have
   done on users.emulab.net.

    {987} stoller$ /usr/tesbed/bin/swapexp --help
    swapexp -e pid,eid in|out
    swapexp pid eid in|out


* For those of you talking directly to the RPC server from python, I have
  added a wrapper class so that you can issue requests to any of the
  modules from a single connection. Instead using /xmlrpc/modulename, you
  can use just /xmlrpc, and use method names of the form experiment.swapexp,
  node.reboot, etc.

  Tim this should be useful for the netlab client which I think opens up
  multiple ssh connections?

* I have replaced the paperbag shell with a stripped down xmlrpcbag shell
  that is quite a bit simpler since we no longer allow access to anything
  but the RPC server. No interactive mode, no argument processing, no
  directory changing, etc. My main reason for reworking the bag is to make
  it easier to understand, maintain, and verify that it is secure. The new
  bag also logs all connections to syslog (something we should have done in
  the orginal). I also added some setrlimit calls (core, maxcpu). I also
  thought about niceing the server down, but that would put RPC users at a
  disadvantage relative to web interface users. When we switch the web
  interface to use the XMLRPC backend, we can add this (reniceing from the
  web server would be a pain cause of its scattered implementation).
parent 38f90bb3
......@@ -1398,7 +1398,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
db/sitevarscheck db/dbfillcheck \
db/grabron db/webnfree db/stategraph db/readycount \
db/idletimes db/idlemail db/webidlemail db/xmlconvert \
db/node_list db/webnewwanode \
db/webnewwanode \
ipod/GNUmakefile \
lib/GNUmakefile lib/libtb/GNUmakefile \
os/GNUmakefile os/split-image.sh os/imagezip/GNUmakefile \
......@@ -1407,8 +1407,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
os/syncd/GNUmakefile os/dijkstra/GNUmakefile \
os/genhostsfile/GNUmakefile \
pxe/GNUmakefile pxe/bootinfo.restart \
security/GNUmakefile security/paperbag security/lastlog_daemon \
security/plasticwrap \
security/GNUmakefile security/lastlog_daemon \
sensors/GNUmakefile sensors/slothd/GNUmakefile \
sensors/slothd/sdisrunning sensors/slothd/sddeploy \
sensors/canaryd/GNUmakefile \
......@@ -1497,7 +1496,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
xmlrpc/sshxmlrpc_client.py xmlrpc/sshxmlrpc_server.py \
xmlrpc/webxmlrpc \
xmlrpc/emulab xmlrpc/node xmlrpc/experiment xmlrpc/fs xmlrpc/user \
xmlrpc/imageid xmlrpc/osid \
xmlrpc/imageid xmlrpc/osid xmlrpc/server xmlrpc/xmlrpxbag \
cdrom/GNUmakefile cdrom/tbbootconfig/GNUmakefile \
install/ops-install install/boss-install \
install/newnode_sshkeys/GNUmakefile "
......
......@@ -440,7 +440,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
db/sitevarscheck db/dbfillcheck \
db/grabron db/webnfree db/stategraph db/readycount \
db/idletimes db/idlemail db/webidlemail db/xmlconvert \
db/node_list db/webnewwanode \
db/webnewwanode \
ipod/GNUmakefile \
lib/GNUmakefile lib/libtb/GNUmakefile \
os/GNUmakefile os/split-image.sh os/imagezip/GNUmakefile \
......@@ -449,8 +449,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
os/syncd/GNUmakefile os/dijkstra/GNUmakefile \
os/genhostsfile/GNUmakefile \
pxe/GNUmakefile pxe/bootinfo.restart \
security/GNUmakefile security/paperbag security/lastlog_daemon \
security/plasticwrap \
security/GNUmakefile security/lastlog_daemon \
sensors/GNUmakefile sensors/slothd/GNUmakefile \
sensors/slothd/sdisrunning sensors/slothd/sddeploy \
sensors/canaryd/GNUmakefile \
......@@ -539,7 +538,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
xmlrpc/sshxmlrpc_client.py xmlrpc/sshxmlrpc_server.py \
xmlrpc/webxmlrpc \
xmlrpc/emulab xmlrpc/node xmlrpc/experiment xmlrpc/fs xmlrpc/user \
xmlrpc/imageid xmlrpc/osid \
xmlrpc/imageid xmlrpc/osid xmlrpc/server xmlrpc/xmlrpxbag \
cdrom/GNUmakefile cdrom/tbbootconfig/GNUmakefile \
install/ops-install install/boss-install \
install/newnode_sshkeys/GNUmakefile "
......
......@@ -6,6 +6,20 @@ This file is in the same format at the FreeBSD UPDATING file, whis is
to say, in reverse chronological order, with the date of the change
in YYYYMMDD format.
20040809:
New syslog file for logging requests to the XMLRPC server.
sudo touch /usr/testbed/log/xmlrpcbag.log
Add these two lines to /etc/syslog.conf and then HUP syslogd:
!xmlrpcbag
*.* /usr/testbed/log/xmlrpcbag.log
Add this line to /etc/newsyslog.conf:
/usr/testbed/log/xmlrpcbag.log 640 7 1000 * Z
20040805:
Add a new CNAME for boss to /etc/namedb/<OURDMAIN>.db.head -
event-server . Re-run named_setup on boss to make this change
......
......@@ -12,14 +12,13 @@ SUBDIR = security
include $(OBJDIR)/Makeconf
BINS = suexec
SCRIPTS = plasticwrap
SBINS = paperbag genlastlog lastlog_daemon
SBINS = genlastlog lastlog_daemon
#
# Force dependencies on the scripts so that they will be rerun through
# configure if the .in file is changed.
#
all: $(BINS) $(SCRIPTS) $(SBINS)
all: $(BINS) $(SBINS)
include $(TESTBED_SRCDIR)/GNUmakerules
......@@ -52,7 +51,7 @@ post-install:
#
# Control node installation (okay, plastic)
#
control-install: $(addprefix $(INSTALL_BINDIR)/, plasticwrap)
control-install:
clean:
rm -f *.o genlastlog suexec core
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2004 University of Utah and the Flux Group.
# All rights reserved.
#
# paperbag - Limited shell for use on ops.emulab.net
# Allows execution of commands found in a permitted list
# Also checks arguments for potentially dangerous characters (semicolons,
# pipes, redirects, etc)
# Robert Ricci, <ricci@cs.utah.edu>
# Novemeber 17, 2000
# TODO:
# Turn off coredumps in ourself, and our children
# Check to make sure only files/directories under user's $HOME can be
# passed as arguments, CD'ed to, etc
#
# Configure variables
#
my $TB = "@prefix@";
my $USERNODE = "@USERNODE@";
# List of allowed commands - Mapping is from command entered by the user
# to the actual binary to run
%allowed = ( "node_reboot" => "$TB/bin/node_reboot",
"node_update" => "$TB/bin/node_update",
"node_control" => "$TB/bin/node_control",
"os_load" => "$TB/bin/os_load",
"create_image" => "$TB/bin/create_image",
"node_admin" => "$TB/bin/node_admin",
"node_list" => "$TB/bin/node_list",
"delay_config" => "$TB/bin/delay_config",
"link_config" => "$TB/bin/link_config",
"savelogs" => "$TB/bin/savelogs",
"portstats" => "$TB/bin/portstats",
"readycount" => "$TB/bin/readycount",
"eventsys_control" => "$TB/bin/eventsys_control",
"batchexp" => "$TB/bin/batchexp",
"nscheck" => "$TB/bin/nscheck",
"swapexp" => "$TB/bin/swapexp",
"endexp" => "$TB/bin/endexp",
"tbreport" => "$TB/bin/tbreport",
"xmlrpc" => "$TB/sbin/sshxmlrpc_server.py",
"xmlrpc/experiment" => "$TB/sbin/sshxmlrpc_server.py",
"xmlrpc/node" => "$TB/sbin/sshxmlrpc_server.py",
"xmlrpc/imageid" => "$TB/sbin/sshxmlrpc_server.py",
"xmlrpc/osid" => "$TB/sbin/sshxmlrpc_server.py",
"xmlrpc/fs" => "$TB/sbin/sshxmlrpc_server.py",
"xmlrpc/user" => "$TB/sbin/sshxmlrpc_server.py",
"xmlrpc/emulab" => "$TB/sbin/sshxmlrpc_server.py",
);
#
# Scrub the environment - delete all but a few variables we consider to be
# safe.
#
my %SAFE_ENV_VARS = (LOGNAME => 1, TERM => 1, SHELL => 1, HOME => 1, USER => 1,
SSH_CLIENT => 1, SSH_CONNECTION => 1, SSH_AUTH_SOCK => 1, SSH_TTY => 1);
foreach my $var (keys %ENV) {
if (!$SAFE_ENV_VARS{$var}) {
delete $ENV{$var};
}
}
# Need to provide a simple path, because some scripts we call need one
$ENV{PATH} = "$TB/bin:/bin:/usr/bin:/usr/local/bin";
$prompt = "paperbag> "; # Prompt for interactive commands
# Following message gets displayed to interactive users
$message = "This is a restricted shell, and will only allow you to run
a limited set of commands. For an unrestrictive shell, log into
$USERNODE\n";
# Whether or not to allow interactive sessions
$allow_interactive = 0;
$debug = 0;
$| = 1; # No line buffering, so that we can see the prompt
if ($allow_interactive) {
$interactive = 1;
} else {
$interactive = 0;
}
if (@ARGV && ($ARGV[0] eq "-c")) { # We were called by sshd - transform args into a useful form
my $bigarg = pop @ARGV;
push(@ARGV,split(/\s+/,$bigarg));
shift @ARGV; # Dispose of -c
$interactive = 0;
&debug("New args are: " . join(",",@ARGV) . "\n");
}
# Check for a leading dir= option, which tells us which directory to start from
if (@ARGV && ($ARGV[0] =~ /dir=(.*)/)) {
shift @ARGV;
&cd($1); # Change to given directory
} elsif(@ARGV && ($ARGV[0] eq "cd")) { # also understand 'cd dir &&' or 'cd dir ;' syntax to be a little more compatible
# with other shells
# Discard the cd
shift @ARGV;
my $dir = shift @ARGV;
my $trash = shift @ARGV;
if (($trash ne "&&") && ($trash ne ";")) {
die "Syntax error: expected && or ; after cd <dir>\n";
}
# Untaint directory name - changing directories isn't a security risk in our situation
if ($dir =~ /^(.*)$/) {
&cd($1);
}
}
if (@ARGV) { # We were given command line arguments
$interactive = 0;
$command = $ARGV[0];
&debug("NON-INTERACTIVE: command is $command\n");
@args = @ARGV[1 .. $#ARGV];
&debug("NON-INTERACTIVE: args are " . join(",",@args) ."\n");
}
if ($interactive) {
print $message;
}
do {{
if ($interactive) {
print $prompt;
($command, @args) = split /\s+/,<>;
}
next unless $command; # Don't complain if they leave a blank command
# Don't allow any naughty characters - kick the user off if they try
foreach $string ($command, @args) {
if ($string !~ m|^([A-Za-z0-9._\-/=\+,\,]*)$|) {
print "Sorry, you used a forbidden character in your command line\n";
print "Please contact testbed-ops\@emulab.net if you believe this message is in error\n";
&debug("String was $string\n");
exit(-1);
} else {
$string = $1; # Untaint
&debug("No forbidden characters\n");
}
}
# xmlrpc is special for now, while we use paperbag for it.
# Pass the second token as the first arg to the server.
if ($command =~ /^xmlrpc\/(\w*)$/) {
@args = ($1);
$command = "xmlrpc/$1";
}
elsif ($command eq "xmlrpc") {
@args = ();
}
else {
# Strip off all path information from the command
$command =~ /([^\/]+)$/; $command = $1;
}
next unless $command; # Don't complain if they leave a blank command
&debug("Command = $command, @args = " . join ",",@args . "\n");
# 'builtin' commands
if ($command eq "exit") { $interactive = 0; last; } # Quit loop
if ($command eq "cd") {
if (@args > 1) {
print "cd: Too many arguments\n";
} else {
&cd($args[0]);
}
next;
}
if (!$allowed{$command}) {
print "$command is not in the allowed list, sorry\n";
} else {
# Exec ourselves to be SURE that a shell doesn't get called
# and do something insecure
my $pid = fork();
if ($pid == -1) { # fork failed
print "Unable to fork process - Error number $?\n";
} elsif ($pid) { # parent - wait for child to exit
wait;
} else { # child process
exec ($allowed{$command},@args) or
die "Unable to execute $command: $?\n";
}
}
}} while ($interactive);
# Change directory to the given directory, (TODO) checking whether
# it is appropriate to do so or not
sub cd {
my $dirname = shift;
chdir $dirname or warn "Unable to change directories to $dirname\n";
}
sub debug {
if ($debug) { print @_; }
}
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2004 University of Utah and the Flux Group.
# All rights reserved.
#
#
# Configure variables
#
my $BOSSNODE = "@BOSSNODE@";
my $TBOPSEMAIL = "@TBOPSEMAIL@";
# Location of ssh program
if (-x "/usr/local/bin/ssh" ) {
$ssh = "/usr/local/bin/ssh";
} elsif (-x "/usr/bin/ssh" ) {
$ssh = "/usr/bin/ssh";
} else {
die "Unable to find ssh - please send mail to $TBOPSEMAIL\n";
}
# Remote host to connect to
$host = $BOSSNODE;
# String to turn off password authentications
$nopass = "-o 'BatchMode yes'";
# Turn off host key checking.... for now.
$nokeycheck = "-o 'StrictHostKeyChecking no'";
# Make sure we use the right identity file
$identity = "-i $ENV{HOME}/.ssh/identity";
# Current working directory:
$cwd = $ENV{PWD};
# We only want to actually change to $CWD if it will actually
# be accesible on the other machine - if it's in /users or /proj
if (!($cwd =~ qr|/users|) &&
!($cwd =~ qr|/groups|) &&
!($cwd =~ qr|/proj|)) {
warn "In order to make sure that this command has access to any\n";
warn "files it may need to read, please change directories into\n";
warn "your home directory (in /users/) or your project/group\n";
warn "directory (in /proj/ or /groups/).\n";
exit (-1);
}
# Now, do the magic
$sshcmd = "$ssh $identity $nopass $nokeycheck $host 'cd $cwd \; $0 @ARGV'";
#print "About to run $sshcmd\n";
$rv = system $sshcmd;
exit($rv >> 8);
......@@ -21,11 +21,6 @@ BIN_STUFF = power snmpit tbend tbprerun tbreport \
portstats checkports eventsys_control os_select tbrestart \
tbswap nseswap tarfiles_setup
# Stuff that mere users get on plastic.
USERBINS = os_load node_reboot nscheck node_update savelogs \
node_control portstats batchexp eventsys_control \
swapexp endexp tbreport
SBIN_STUFF = resetvlans console_setup.proxy sched_reload named_setup \
batch_daemon exports_setup reload_daemon sched_reserve \
console_reset db2ns bwconfig frisbeelauncher \
......@@ -163,13 +158,6 @@ post-install:
#
# Control node installation (okay, plastic)
#
ifneq ($(UNIFIED),1)
LINKS= cd $(INSTALL_BINDIR) && \
list='$(USERBINS)'; for file in $$list; do \
rm -f $$file; \
ln -s plasticwrap $$file; \
done;
endif
control-install: $(addprefix $(INSTALL_SBINDIR)/, console_setup.proxy) \
$(addprefix $(INSTALL_SBINDIR)/, exports_setup.proxy) \
$(addprefix $(INSTALL_SBINDIR)/, sfskey_update.proxy) \
......@@ -178,7 +166,6 @@ control-install: $(addprefix $(INSTALL_SBINDIR)/, console_setup.proxy) \
$(addprefix $(INSTALL_LIBDIR)/, libtestbed.pm)
@$(MAKE) -C ns2ir control-install
@$(MAKE) -C nseparse control-install
$(LINKS)
#
# Tip servers get very little
......
......@@ -19,11 +19,6 @@ SBIN_SCRIPTS = vlandiff vlansync withadminprivs export_tables cvsupd.pl \
eventping grantnodetype import_commitlog dhcpd_wrapper
LIBEXEC_SCRIPTS = webcreateimage newnode
#
# These are the ones installed on plastic (users, control, etc).
#
USERBINS = create_image delay_config node_admin link_config
#
# Force dependencies on the scripts so that they will be rerun through
# configure if the .in file is changed.
......@@ -40,17 +35,7 @@ install: $(addprefix $(INSTALL_BINDIR)/, $(BIN_SCRIPTS)) \
#
# Control node installation (okay, plastic)
#
ifneq ($(UNIFIED),1)
LINKS= cd $(INSTALL_BINDIR) && \
list='$(USERBINS)'; for file in $$list; do \
rm -f $$file; \
ln -s plasticwrap $$file; \
done;
endif
control-install:
$(LINKS)
#
# Automate this part at some point.
......
......@@ -13,11 +13,12 @@ UNIFIED = @UNIFIED_BOSS_AND_OPS@
include $(OBJDIR)/Makeconf
BIN_SCRIPTS = sshxmlrpc_client.py
SBIN_SCRIPTS = sshxmlrpc_server.py
SBIN_SCRIPTS = sshxmlrpc_server.py xmlrpcbag
LIB_STUFF = sshxmlrpc.py emulabserver.py emulabclient.py
LIBEXEC_STUFF = webxmlrpc
WWW_STUFF = xmlrpcapi.php3
DOWNLOAD_STUFF = sshxmlrpc.py sshxmlrpc_client.py emulabclient.py README
DOWNLOAD_STUFF = sshxmlrpc.py sshxmlrpc_client.py emulabclient.py README \
script_wrapper.py
DEBUG_STUFF = experiment node imageid osid fs user emulab server
EXPANDCOPYRIGHT = /usr/site/lib/copyright/expand-copyr
......@@ -25,15 +26,19 @@ EXPANDCOPYRIGHT = /usr/site/lib/copyright/expand-copyr
#
# These are the ones installed on plastic (users, control, etc).
#
CLIENTBIN = sshxmlrpc_client.py
USERLIBS = sshxmlrpc.py emulabclient.py
CLIENTBIN = sshxmlrpc_client.py script_wrapper.py
USERLIBS = sshxmlrpc.py emulabclient.py
SYMLINKS = node_admin node_reboot os_load create_image node_list \
delay_config link_config savelogs portstats eventsys_control \
readycount nscheck startexp batchexp startexp swapexp endexp \
modexp expinfo
#
# Force dependencies on the scripts so that they will be rerun through
# configure if the .in file is changed.
#
all: $(BIN_SCRIPTS) $(SBIN_SCRIPTS) $(LIB_STUFF) $(LIBEXEC_STUFF) \
$(DOWNLOAD_STUFF) $(DEBUG_STUFF)
$(DOWNLOAD_STUFF) $(DEBUG_STUFF) $(CLIENTBIN)
include $(TESTBED_SRCDIR)/GNUmakerules
......@@ -44,6 +49,8 @@ install: $(addprefix $(INSTALL_BINDIR)/, $(BIN_SCRIPTS)) \
$(addprefix $(INSTALL_WWWDIR)/, $(WWW_STUFF)) \
$(addprefix $(INSTALL_WWWDIR)/downloads/xmlrpc/, $(DOWNLOAD_STUFF)) \
$(addprefix $(INSTALL_LIBDIR)/, $(LIB_STUFF))
-rm -f $(INSTALL_SBINDIR)/paperbag
ln -s xmlrpcbag $(INSTALL_SBINDIR)/paperbag
$(INSTALL_WWWDIR)/%: %
@echo "Installing $<"
......@@ -63,7 +70,15 @@ $(INSTALL_SBINDIR)/xmlrpc/%: %
#
# Control node installation (okay, plastic)
#
ifneq ($(UNIFIED),1)
LINKS= cd $(INSTALL_BINDIR) && \
list='$(SYMLINKS)'; for file in $$list; do \
rm -f $$file; \
ln -s script_wrapper.py $$file; \
done;
endif
control-install: $(addprefix $(INSTALL_LIBDIR)/, $(USERLIBS)) \
$(addprefix $(INSTALL_BINDIR)/, $(CLIENTBIN))
$(addprefix $(INSTALL_BINDIR)/, $(CLIENTBIN))
$(LINKS)
clean:
......@@ -13,3 +13,56 @@ information can be found at http://www.emulab.net/xmlrpcapi.php3
* emulabclient.py: Another small library that you need to put in your
python library directory.
* script_wrapper.py: A slightly more advanced client that implements a
"shell" script style interface to emulab. To get a list of "shell"
commands:
{1} stoller$ script_wrapper.py
Usage: wrapper [wrapper options] command [command args and opts]
Commands:
readycount Get readycounts for nodes in experiment (deprecated).
startexp Start an Emulab experiment.
savelogs Save console tip logs to experiment directory.
endexp Terminate an experiment.
eventsys_control Start/Stop/Restart the event system.
batchexp Synonym for startexp.
node_list Print physical mapping of nodes in an experiment.
expinfo Get information about an experiment.
node_admin Boot selected nodes into FreeBSD MFS.
create_image Create a disk image from a node.
delay_config Change the link shaping characteristics for a link or lan.
modexp Modify experiment.
nscheck Check and NS file for parser errors.
swapexp Swap experiment in or out.
os_load Reload disks on selected nodes or all nodes.
portstats Get portstats from the switches.
link_config Change interface parameters for a wireless link.
node_reboot Reboot selected nodes or all nodes in an experiment.
(Specify the --help option to specific commands for more help)
Wrapper Options:
--help Display this help message
--server Set the server hostname
--login Set the login id (defaults to $USER)
--debug Turn on semi-useful debugging
Example:
script_wrapper --server=boss.emulab.net node_admin -n testbed one-node
You can also pass --help to individual commands to see how to use it:
{12} stoller$ script_wrapper.py swapexp --help
swapexp -e pid,eid in|out
swapexp pid eid in|out
where:
-w - Wait for experiment to finish swapping
-e - Project and Experiment ID
in - Swap experiment in (must currently be swapped out)
out - Swap experiment out (must currently be swapped in)
By default, swapexp runs in the background, sending you email
when the transition has completed. Use the -w option to wait
in the foreground, returning exit status. Email is still sent.
......@@ -1532,6 +1532,13 @@ class experiment:
if (argerror):
return argerror
#
# Check permission. This will check proj/exp for illegal chars.
#
permerror = CheckExptPermission(argdict["proj"], argdict["exp"])
if (permerror):
return permerror
argstr = ""
for opt, val in argdict.items():
if opt == "persist":
......@@ -1578,6 +1585,13 @@ class experiment:
if (argerror):
return argerror
#
# Check permission. This will check proj/exp for illegal chars.
#
permerror = CheckExptPermission(argdict["proj"], argdict["exp"])
if (permerror):
return permerror
argstr = ""
for opt, val in argdict.items():
if opt == "persist":
......@@ -1629,6 +1643,13 @@ class experiment:
if (argerror):
return argerror
#
# Check permission. This will check proj/exp for illegal chars.
#
permerror = CheckExptPermission(argdict["proj"], argdict["exp"])
if (permerror):
return permerror
argstr = ""
for opt, val in argdict.items():
if opt == "wait":
......@@ -1675,6 +1696,13 @@ class experiment:
if (argerror):
return argerror
#
# Check permission. This will check proj/exp for illegal chars.
#
permerror = CheckExptPermission(argdict["proj"], argdict["exp"])
if (permerror):
return permerror
argstr = ""
for opt, val in argdict.items():
if opt == "wait":
......@@ -1909,6 +1937,13 @@ class experiment:
return EmulabResponse(RESPONSE_BADARGS,
output="Improperly formed proj/exp!")
#
# Check permission. This will check proj/exp for illegal chars.
#
permerror = CheckExptPermission(argdict["proj"], argdict["exp"])
if (permerror):
return permerror
dbres = DBQueryFatal(
"select s.rsrcidx from experiments as e "
"left join experiment_stats as s on s.exptidx=e.idx "
......
This diff is collapsed.
......@@ -148,7 +148,7 @@ class SSHConnection:
# Use the PyTTY plink, equivalent to the ssh command.
cmd = "plink -x -C " + args
pass
if not nt:
# Popen3 objects, and the wait method, are Unix-only.
self.myChild = popen2.Popen3(cmd, 1)
......@@ -197,7 +197,6 @@ class SSHConnection:
#
def close(self):
self.wfile.close()
self.errfile.close()
self.rfile.close()
if self.myChild:
self.myChild.wait()
......
......@@ -4,54 +4,59 @@
# Copyright (c) 2000-2004 University of Utah and the Flux Group.
# All rights reserved.
#
use Sys::Syslog;
use BSD::Resource;
# paperbag - Limited shell for use on ops.emulab.net
# Allows execution of commands found in a permitted list
# Also checks arguments for potentially dangerous characters (semicolons,
# pipes, redirects, etc)
# Robert Ricci, <ricci@cs.utah.edu>
# Novemeber 17, 2000
# TODO:
# Turn off coredumps in ourself, and our children
# Check to make sure only files/directories under user's $HOME can be
# passed as arguments, CD'ed to, etc
# xmlrpcbag - This is a rework of security/paperbag.in, which was written
# by Robert Ricci <ricci@cs.utah.edu> on November 17, 2000. This version
# is tailored to invoking the xmlrpc server, and is quite a bit simpler
# since we do not have to worry about the command line, interactive mode,
# directory changing, etc.
#
# Configure variables
#
my $TB = "@prefix@";
my $USERNODE = "@USERNODE@";
my $XMLRPC = "$TB/sbin/sshxmlrpc_server.py";
my $TBLOG = "@TBLOGFACIL@";
# Locals.
my $debug = 0;
my $module;
# List of allowed commands - Mapping is from command entered by the user
# to the actual binary to run
%allowed = ( "node_reboot" => "$TB/bin/node_reboot",
"node_update" => "$TB/bin/node_update",
"node_control" => "$TB/bin/node_control",
"os_load" => "$TB/bin/os_load",
"create_image" => "$TB/bin/create_image",
"node_admin" => "$TB/bin/node_admin",
"node_list" => "$TB/bin/node_list",
"delay_config" => "$TB/bin/delay_config",
"link_config" => "$TB/bin/link_config",
"savelogs" => "$TB/bin/savelogs",
"portstats" => "$TB/bin/portstats",
"readycount" => "$TB/bin/readycount",
"eventsys_control" => "$TB/bin/eventsys_control",
"batchexp" => "$TB/bin/batchexp",
"nscheck" => "$TB/bin/nscheck",
"swapexp" => "$TB/bin/swapexp",
"endexp" => "$TB/bin/endexp",
"tbreport" => "$TB/bin/tbreport",
"xmlrpc" => "$TB/sbin/sshxmlrpc_server.py",
"xmlrpc/experiment" => "$TB/sbin/sshxmlrpc_server.py",
"xmlrpc/node" => "$TB/sbin/sshxmlrpc_server.py",
"xmlrpc/imageid" => "$TB/sbin/sshxmlrpc_server.py",
"xmlrpc/osid" => "$TB/sbin/sshxmlrpc_server.py",
"xmlrpc/fs" => "$TB/sbin/sshxmlrpc_server.py",
"xmlrpc/user" => "$TB/sbin/sshxmlrpc_server.py",
"xmlrpc/emulab" => "$TB/sbin/sshxmlrpc_server.py",
);
# Turn off line buffering.
$| = 1;
#
# Debugging goes to syslog. There is generally no reason to invoke this
# interactively, except during debugging, and in that case you can go
# look at the log file.
#
sub debug($) {
my ($mesg) = @_;
syslog("debug", $mesg)
if ($debug);
}
#
# List of allowed RPC modules. The current usage is that the bag is
# invoked as /xmlrpc/module. We split out the module name and pass it
# to the server as the first and only argument. In reality, we could
# skip this check, and just pass the single token to the server and let
# it validate it. But, might as well be careful.
#
my %modules = ( "experiment" => "experiment",
"node" => "node",
"imageid" => "imageid",
"osid" => "osid",
"fs" => "fs",
"user" => "user",
"emulab" => "emulab",
# Wrapper class.
"server" => "EmulabServer",
);
#
# Scrub the environment - delete all but a few variables we consider to be
......@@ -66,137 +71,99 @@ foreach my $var (keys %ENV) {
}
}
# Need to provide a simple path, because some scripts we call need one
$ENV{PATH} = "$TB/bin:/bin:/usr/bin:/usr/local/bin";
$prompt = "paperbag> "; # Prompt for interactive commands
# Following message gets displayed to interactive users
$message = "This is a restricted shell, and will only allow you to run
a limited set of commands. For an unrestrictive shell, log into
$USERNODE\n";
#
# Provide a simple path. Note though that the server will not call anything
# without giving it an absolute path.
#
$ENV{PATH} = "/bin:/usr/bin:/usr/local/bin";
# Whether or not to allow interactive sessions
$allow_interactive = 0;
Sys::Syslog::setlogsock('unix');
openlog("xmlrpcbag", "pid", $TBLOG);
$debug = 0;
$| = 1; # No line buffering, so that we can see the prompt