Commit 3a9d0ae9 authored by Jonathon Duerig's avatar Jonathon Duerig

Merge branch 'master' of

parents b937af9f fdbe7c05
VERSION export-subst
# Files that already had DOS-style line endings and those
# that require them should be added to the list below.
delay/linux/iptables_mods/iptables-1.3.6-imq.diff -crlf
......@@ -203,8 +203,24 @@ endif
subboss: client
@$(MAKE) -C utils subboss
subboss-install: subboss client-install
subboss-install: subboss
ifeq ($(EVENTSYS),1)
@$(MAKE) -C event client-install
@$(MAKE) -C os client-install
ifneq ($(SYSTEM),CYGWIN_NT-5.1)
@$(MAKE) -C capture client-install
@$(MAKE) -C tip client-install
@$(MAKE) -C tools client-install
@$(MAKE) -C sensors client-install
@$(MAKE) -C utils subboss-install
@$(MAKE) -C db subboss-install
@$(MAKE) -C tmcd subboss-install
@$(MAKE) -C rc.d subboss-install
# Hack: this should probably be done by a subboss-install
# script, but there isn't a huge need for that yet
@rm -f $(INSTALL_RCDIR)/isc-dhcpd
TARBALLDESTDIR = /var/tmp/emulab-client
......@@ -90,3 +90,5 @@ HAVE_ULXMLRPCPP = @HAVE_ULXMLRPCPP@
Version: $Format:%H %ci$
* Copyright (c) 2000-2003, 2005, 2006, 2007 University of Utah and the Flux Group.
* Copyright (c) 2000-2010 University of Utah and the Flux Group.
* All rights reserved.
......@@ -10,6 +10,7 @@
#include <arpa/inet.h>
#include <fcntl.h>
#include <stdio.h>
#include <paths.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
......@@ -19,6 +20,7 @@
#include <errno.h>
#include <mysql/mysql.h>
#include <sys/time.h>
#include <signal.h>
#include <grp.h>
#include "capdecls.h"
#include "config.h"
......@@ -29,6 +31,9 @@
static int debug = 0;
static int portnum = SERVERPORT;
static gid_t admingid;
char *Pidname;
void sigterm(int);
void cleanup(void);
char *usagestr =
"usage: capserver [-d] [-p #]\n"
......@@ -53,6 +58,8 @@ main(int argc, char **argv)
struct sockaddr_in name;
struct timeval timeout;
struct group *group;
struct sigaction sa;
sigset_t actionsigmask;
while ((ch = getopt(argc, argv, "dp:")) != -1)
switch(ch) {
......@@ -84,6 +91,15 @@ main(int argc, char **argv)
sigaddset(&actionsigmask, SIGINT);
sigaddset(&actionsigmask, SIGTERM);
memset(&sa, 0, sizeof sa);
sa.sa_handler = sigterm;
sa.sa_mask = actionsigmask;
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
* Grab the GID for the default group.
......@@ -129,6 +145,19 @@ main(int argc, char **argv)
syslog(LOG_NOTICE, "listening on TCP port %d", ntohs(name.sin_port));
if (!getuid()) {
FILE *fp;
char mybuf[BUFSIZ];
sprintf(mybuf, "%s/", _PATH_VARRUN);
fp = fopen(mybuf, "w");
if (fp != NULL) {
fprintf(fp, "%d\n", getpid());
(void) fclose(fp);
Pidname = strdup(mybuf);
while (1) {
struct sockaddr_in client;
int clientsock, length = sizeof(client);
......@@ -295,6 +324,22 @@ main(int argc, char **argv)
syslog(LOG_NOTICE, "daemon terminating");
sigterm(int sig)
syslog(LOG_NOTICE, "daemon exiting by signal");
if (Pidname)
(void) unlink(Pidname);
......@@ -12,6 +12,9 @@ SUBDIR = collab
include $(OBJDIR)/Makeconf
SUBDIRS = mailman cvstools jabber trac
ifeq ($(EXP_VIS_SUPPORT),1)
SUBDIRS += exp-vis
all: all-subdirs
......@@ -31,6 +34,9 @@ post-install:
@$(MAKE) -C cvstools post-install
@$(MAKE) -C jabber post-install
@$(MAKE) -C trac post-install
ifeq ($(EXP_VIS_SUPPORT),1)
@$(MAKE) -C exp-vis post-install
# How to recursively descend into subdirectories to make general
# targets such as `all'.
# Copyright (c) 2009 University of Utah and the Flux Group.
# All rights reserved.
SRCDIR = @srcdir@
TESTBED_SRCDIR = @top_srcdir@
OBJDIR = ../..
SUBDIR = collab/exp-vis
include $(OBJDIR)/Makeconf
CGI_SCRIPTS = fetch-vis
LIBEXEC_SCRIPTS = write-vis-auth
CTRL_LIBEXEC_SCRIPTS = write-vis-auth.proxy
SETUID_LIBX_SCRIPTS = write-vis-auth
# Force dependencies on the scripts so that they will be rerun through
# configure if the .in file is changed.
include $(TESTBED_SRCDIR)/GNUmakerules
install: \
$(addprefix $(TBROOT)/opsdir/www/cgi-bin/, $(CGI_SCRIPTS)) \
$(addprefix $(INSTALL_DIR)/opsdir/libexec/, $(CTRL_LIBEXEC_SCRIPTS))
$(TBROOT)/opsdir/www/cgi-bin/fetch-vis: fetch-vis
-$(SUDO) mkdir -m 775 $(TBROOT)/opsdir/www/cgi-bin
$(SUDO) $(INSTALL) -o root -m 4775 $< $@
$(INSTALL_DIR)/opsdir/libexec/write-vis-auth.proxy: write-vis-auth.proxy
-mkdir -p $(INSTALL_DIR)/opsdir/libexec
$(INSTALL) $< $@
#!/usr/bin/perl -T
use strict;
use warnings;
use POSIX qw(setuid setgid);
use Cwd qw(realpath);
use CGI;
use CGI::Cookie;
use HTTP::Date;
#use Data::Dumper;
#print "\n\n";
#print STDERR Dumper(\%ENV);
sub error($) {
print "Content-Type: text/plain\n";
print "Status: 404 Not Found\n\n";
print "$_[0]\n";
#die "$_[0]\n";
exit 1;
# Parse URL
my ($proj,$group,$exp,$dir,$file);
local $_ = $SCRIPT_URL;
if (/^\/proj-vis\/([a-zA-Z0-9-]+)\/?(.*)$/) {
$proj = $1;
$group = $1;
$file = $2;
} elsif (/^\/group-vis\/([a-zA-Z0-9-]+)\/?([a-zA-Z0-9-]+)\/?(.*)$/) {
$proj = $1;
$group = $2;
$file = $3;
} elsif (/^\/exp-vis\/([a-zA-Z0-9-]+)\/?([a-zA-Z0-9-]+)\/?(.*)$/) {
$proj = $1;
$exp = $2;
$file = $3;
} else {
error("Malformed URL");
if (defined $exp) {
my $exp_dir = "/proj/$proj/exp/$exp";
local $_ = realpath $exp_dir;
if (/^$FSDIR_PROJ\/$proj\//) {
$group = $proj;
} elsif (/^$FSDIR_GROUPS\/$proj\/(.+?)\//) {
$group = $1;
$dir = "/groups/$proj/$group/www/exp-vis/$exp";
} else {
$dir = "/groups/$proj/$group/www/group-vis";
# Lookup up the Unix GID for the proj and the group
my (undef,undef,undef,undef,undef,$gid) = stat("/proj/$proj") or die;
my ($gid_name,undef,undef,$gid_members) = getgrgid($gid);
die "Error: Bad proj GID: $gid_name != $proj" unless $gid_name eq $proj;
my (undef,undef,undef,undef,undef,$gid2) = stat("/groups/$proj/$group") or die;
my ($gid2_name,undef,undef,$gid2_members) = getgrgid($gid2);
# For security remove any ".." from the path and abort if we would
# leave $dir
my @dirs = split /\//, $file;
my @res;
foreach my $d (@dirs) {
if ($d eq '' || $d eq '.') {
# nothing to do
} elsif ($d eq '..') {
error("Malformed URL") if @res == 0;
pop @res;
} else {
push @res, $d;
# Create the path
$file = join ('/', @res);
my $path = "$dir/$file";
if (-d $path) {
my $orig_path = $path;
$path .= "/index.html" if -e "$path/index.html";
$path .= "/index.htm" if -e "$path/index.htm";
error("Can't index dir: $path") unless $path ne $orig_path;
error("File Doesn't Exist: $path") unless -e $path;
# Make sure that the path, after resolving any symbolic links,
# still resides is /proj/<proj> or /groups/<proj>/<group>
my $realpath = realpath $path;
error("Invalid path: $realpath") unless $realpath =~ /^$FSDIR_PROJ\/$proj|^$FSDIR_GROUPS\/$proj\/$group/;
# Special rule for boss. Since we are bypassing authorization, don't
# show anything, just let boss know that the url is valid.
print "Content-Type: text/plain\n\n";
print "I exist!\n";
# Get session cookie and make sure user is logged in and authorized to
# view.
my %cookies = raw_fetch CGI::Cookie;
my $session_key = $cookies{exp_vis_session};
error("Not logged in.") unless defined $session_key;
my $user;
open F, "/var/run/exp-vis.auth" or die;
foreach (<F>) {
my ($key, $u) = split / /;
if ($key eq $session_key) {
$user = $u;
error("Login Timed Out.") unless defined $user;
my (undef, undef, $uid, $user_gid) = getpwnam($user);
die if $user_gid == 0;
error("You do not have permission to view $proj files")
unless $gid == $user_gid || grep {$_ eq $user} split /\s+/, $gid_members;
error("You do not have permission to view $proj/$group files")
unless $gid2 == $user_gid || grep {$_ eq $user} split /\s+/, $gid2_members;
# OK, Now we are sure the user has permission to view this file.
# Now become a member of the GID for the proj and group and clear out
# any other GIDs
undef $!;
$) = "$gid $gid $gid2";
die $! if $!;
# Now drop privileges, using setuid to make sure the saved uid
# is also changes, ie, so that the change is permanent.
setuid($<) or die $!;
my %mime_map =
qw(html text/html htm text/html
txt text/plain
png image/png
gif image/gif
jpg image/jpeg jpeg image/jpeg
zip application/zip);
my ($ext) = $path =~ /\.([^.]+)$/;
$ext = lc $ext;
my $mime_type = $mime_map{$ext};
$/ = undef;
open F, "$path" or error "Can't read file: $path";
my ($dev,$ino,$mode,$nlink,undef,undef,$rdev,$size,
$atime,$mtime,$ctime,$blksize,$blocks) = stat F;
my $if_mod_since = 0;
$if_mod_since = str2time($ENV{HTTP_IF_MODIFIED_SINCE})
if ($if_mod_since > 0 && $if_mod_since <= $mtime) {
print "Status: 304 Not Modified\n\n";
} else {
print "Content-Type: $mime_type\n" if defined $mime_type;
print "Content-Length: ", $size, "\n";
print "Last-Modified: ", time2str($mtime), "\n";
print "\n";
print <F> unless $ENV{REQUEST_METHOD} eq 'HEAD';
exit 0;
#!/usr/bin/perl -wT
# Copyright (c) 2000-2007 University of Utah and the Flux Group.
# All rights reserved.
use strict;
use Getopt::Std;
# Configure variables
my $TB = "@prefix@";
my $SSH = "$TB/bin/sshtb -l root -host $USERNODE";
my $background = 0;
# un-taint path
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
# Turn off line buffering on output
$| = 1;
# Capture stdout and stderr to a file so if we die we can mail the output to
# testbed-ops
# XXX: Don't hardcode
my $logfile = "/tmp/write-vis-auth.$$";
use vars qw(*OLDOUT *OLDERR);
open OLDOUT, ">&STDOUT" or die "Can't dup STDOUT $!";
open OLDERR, ">&STDERR" or die "Can't dup STDERR $!";
open STDOUT, ">$logfile" or die "Can't open $logfile: $!";
open STDERR, ">&STDOUT" or die "Can't dup STDERR $!";
$SIG{__DIE__} = sub {
return unless defined $^S; # In Parser
return if $^S; # In Eval Block
local $_ = $_[0];
open STDOUT, ">&OLDOUT";
open STDERR, ">&OLDERR";
SENDMAIL($TBOPS, "write-vis-auth failed", $_, undef, undef, $logfile);
unlink $logfile;
print STDERR "write-vis-auth failed, see testbed-ops mail\n";
# Load the Testbed support stuff.
use lib "@prefix@/lib";
use libdb;
use libtestbed;
if ((my $locked = TBScriptLock("write-vis-auth", 1)) != TBSCRIPTLOCK_OKAY()) {
if ($locked == TBSCRIPTLOCK_IGNORE);
die("Could not get the lock after a long time!\n");
# become root, needed for ssh
$< = $>;
my $db_result =
DBQueryFatal("select opskey, uid from login");
open O, "| $SSH $TB/libexec/write-vis-auth.proxy"
or die "ssh to ops failed: $!\n";
my $prev_opskey = '';
while (my ($opskey,$uid) = $db_result->fetchrow_array) {
$opskey = "00000000000000000000000000000000" if $opskey eq '';
print O "$opskey $uid\n";
close O;
die "ssh to ops failed: $!\n" if $!;
die "ssh to ops failed with exit code $?\n" if $? != 0;
unlink $logfile;
set -e
if [ "$USER" != "root" ]; then
echo "Must be root." 1>&2
exit 1
TEMPFILE=`mktemp /var/run/exp-vis.XXXXXX`
mv $TEMPFILE /var/run/exp-vis.auth
# Copyright (C) 2001-2003 by the Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""Posting moderation filter.
import re
from email.MIMEMessage import MIMEMessage
from email.MIMEText import MIMEText
from Mailman import mm_cfg
from Mailman import Utils
from Mailman import Message
from Mailman import Errors
from Mailman.i18n import _
from Mailman.Handlers import Hold
from Mailman.Logging.Syslog import syslog
class ModeratedMemberPost(Hold.ModeratedPost):
# BAW: I wanted to use the reason below to differentiate between this
# situation and normal ModeratedPost reasons. Greg Ward and Stonewall
# Ballard thought the language was too harsh and mentioned offense taken
# by some list members. I'd still like this class's reason to be
# different than the base class's reason, but we'll use this until someone
# can come up with something more clever but inoffensive.
# reason = _('Posts by member are currently quarantined for moderation')
def process(mlist, msg, msgdata):
if msgdata.get('approved') or msgdata.get('fromusenet'):
# First of all, is the poster a member or not?
for sender in msg.get_senders():
if mlist.isMember(sender):
sender = None
if sender:
# If the member's moderation flag is on, then perform the moderation
# action.
if mlist.getMemberOption(sender, mm_cfg.Moderate):
# Note that for member_moderation_action, 0==Hold, 1=Reject,
# 2==Discard
if mlist.member_moderation_action == 0:
# Hold. BAW: WIBNI we could add the member_moderation_notice
# to the notice sent back to the sender?
msgdata['sender'] = sender
Hold.hold_for_approval(mlist, msg, msgdata,
elif mlist.member_moderation_action == 1:
# Reject
text = mlist.member_moderation_notice
if text:
text = Utils.wrap(text)
# Use the default RejectMessage notice string
text = None
raise Errors.RejectMessage, text
elif mlist.member_moderation_action == 2:
# Discard. BAW: Again, it would be nice if we could send a
# discard notice to the sender
raise Errors.DiscardMessage
assert 0, 'bad member_moderation_action'
# Should we do anything explict to mark this message as getting past
# this point? No, because further pipeline handlers will need to do
# their own thing.
sender = msg.get_sender()
# From here on out, we're dealing with non-members.
# XXX Emulab change; look for X-Netbed header.
if msg.get('X-NetBed'):
if matches_p(sender, mlist.accept_these_nonmembers):
if matches_p(sender, mlist.hold_these_nonmembers):
Hold.hold_for_approval(mlist, msg, msgdata, Hold.NonMemberPost)
# No return
if matches_p(sender, mlist.reject_these_nonmembers):
# No return
if matches_p(sender, mlist.discard_these_nonmembers):
do_discard(mlist, msg)
# No return
# Okay, so the sender wasn't specified explicitly by any of the non-member
# moderation configuration variables. Handle by way of generic non-member
# action.
assert 0 <= mlist.generic_nonmember_action <= 4
if mlist.generic_nonmember_action == 0:
# Accept
elif mlist.generic_nonmember_action == 1:
Hold.hold_for_approval(mlist, msg, msgdata, Hold.NonMemberPost)
elif mlist.generic_nonmember_action == 2:
elif mlist.generic_nonmember_action == 3:
do_discard(mlist, msg)
def matches_p(sender, nonmembers):
# First strip out all the regular expressions
plainaddrs = [addr for addr in nonmembers if not addr.startswith('^')]
addrdict = Utils.List2Dict(plainaddrs, foldcase=1)
if addrdict.has_key(sender):
return 1
# Now do the regular expression matches
for are in nonmembers:
if are.startswith('^'):
cre = re.compile(are, re.IGNORECASE)
except re.error:
return 1
return 0
def do_reject(mlist):
listowner = mlist.GetOwnerEmail()
if mlist.nonmember_rejection_notice:
raise Errors.RejectMessage, \
raise Errors.RejectMessage, Utils.wrap(_("""\
You are not allowed to post to this mailing list, and your message has been
automatically rejected. If you think that your messages are being rejected in
error, contact the mailing list owner at %(listowner)s."""))
def do_discard(mlist, msg):
sender = msg.get_sender()
# Do we forward auto-discards to the list owners?
if mlist.forward_auto_discards:
lang = mlist.preferred_language
varhelp = '%s/?VARHELP=privacy/sender/discard_these_nonmembers' % \
mlist.GetScriptURL('admin', absolute=1)
nmsg = Message.UserNotification(mlist.GetOwnerEmail(),
_('Auto-discard notification'),
text = MIMEText(Utils.wrap(_(
'The attached message has been automatically discarded.')),