diff --git a/wiki/GNUmakefile.in b/wiki/GNUmakefile.in index cdf9536049e7c6913259768c7cf064e0888ad455..26000ecab9b7a99cf29d5d7e7ca5f67ed640f5a0 100644 --- a/wiki/GNUmakefile.in +++ b/wiki/GNUmakefile.in @@ -13,6 +13,7 @@ include $(OBJDIR)/Makeconf SBIN_SCRIPTS = addwikiuser addwikiproj wikisetup delwikiuser \ setwikigroups +LIBEXEC_SCRIPTS = wikixlogin CTRL_SBIN_SCRIPTS = wikiproxy CTRL_LIB_FILES = usertemplate webhometemplate @@ -21,11 +22,13 @@ CTRL_LIB_FILES = usertemplate webhometemplate # Force dependencies on the scripts so that they will be rerun through # configure if the .in file is changed. # -all: $(SBIN_SCRIPTS) $(CTRL_SBIN_SCRIPTS) $(CTRL_LIB_FILES) +all: $(SBIN_SCRIPTS) $(CTRL_SBIN_SCRIPTS) $(CTRL_LIB_FILES) \ + $(LIBEXEC_SCRIPTS) include $(TESTBED_SRCDIR)/GNUmakerules install: $(addprefix $(INSTALL_SBINDIR)/, $(SBIN_SCRIPTS)) \ + $(addprefix $(INSTALL_LIBEXECDIR)/, $(LIBEXEC_SCRIPTS)) \ $(addprefix $(INSTALL_DIR)/opsdir/sbin/, $(CTRL_SBIN_SCRIPTS)) \ $(addprefix $(INSTALL_DIR)/opsdir/lib/wiki/, $(CTRL_LIB_FILES)) @@ -42,6 +45,8 @@ post-install: chmod u+s $(INSTALL_SBINDIR)/addwikiproj chown root $(INSTALL_SBINDIR)/setwikigroups chmod u+s $(INSTALL_SBINDIR)/setwikigroups + chown root $(INSTALL_LIBEXECDIR)/wikixlogin + chmod u+s $(INSTALL_LIBEXECDIR)/wikixlogin # # Control node installation (okay, plastic) diff --git a/wiki/newlogon b/wiki/newlogon index 1c9651fbf9fcf5f7f59718e627ed2457d698a2bb..8fc4e21ae3cd9354f6a6a143ea14611115e28d05 100755 --- a/wiki/newlogon +++ b/wiki/newlogon @@ -24,9 +24,18 @@ use TWiki; use TWiki::Plugins::SessionPlugin; my $oopsurl = "oopsloginfail"; +my $CREDDIR = "/var/db/cgisess"; $query= new CGI; +sub myerror($) +{ + my ($msg) = @_; + + my $url = &TWiki::getOopsUrl(undef, "", $oopsurl, $msg); + TWiki::redirect($query, $url); +} + &main(); sub main @@ -34,17 +43,61 @@ sub main my $username = $query->param('username'); my $password = $query->param('password'); my $redurl = $query->param('redurl'); + my $bosscred = $query->param('bosscred'); - chomp($username); - chomp($password); + # + # If bosscred provided, boss is trying to autologin the user using + # a key that it sent across via a backend script and stashed in the + # cookie dir. Find that file, compare the keys and if the key is not + # too terribly old, give the user the nod. + # + if (defined($bosscred)) { + if (!defined($username) || $username eq "") { + myerror("Missing username argument"); + return; + } + + my $file = "${CREDDIR}/$username"; + + if (! -e $file) { + myerror("Cred file does not exist!"); + return; + } + if (!open(COK, $file)) { + myerror("Cannot open cred file!"); + return; + } + my $cred = <COK>; + my $stamp = <COK>; + close(COK); + + # Compare credentials. + if (defined($cred)) { + chomp($cred); + if ($cred eq $bosscred) { + goto accepted; + } + } + # Does not match. Redirect to login page. + dologon: + my $url = &TWiki::getViewUrl("TWiki", "DoLogin"); + $url .= "?username=${username}"; + $url .= "&redurl=${redurl}" + if (defined($redurl) && $redurl ne ""); + + TWiki::redirect($query, $url); + return; + } + # + # Normal login. + # if (! ($username && $password)) { - my $url = &TWiki::getOopsUrl(undef, "", $oopsurl, - "Missing arguments (username or password)"); - - TWiki::redirect( $query, $url ); + myerror("Missing arguments (username or password)"); return; } + chomp($username); + chomp($password); # # Suck out the password entry. @@ -63,9 +116,7 @@ sub main close(HTP); if (!defined($pwentry)) { - my $url = &TWiki::getOopsUrl(undef, "", $oopsurl, - "No such user: '$username'"); - TWiki::redirect( $query, $url ); + myerror("No such user: '$username'"); return; } @@ -78,15 +129,14 @@ sub main my $str = crypt($password, $encryptedpasswd); if ($str ne $encryptedpasswd) { - my $url = &TWiki::getOopsUrl(undef, "", $oopsurl, - "Incorrect Password"); - TWiki::redirect( $query, $url ); + myerror("Incorrect Password"); return; } - + # This causes the query object to suddenly have a remote_user() value. # SessionPlugin uses that ... - $ENV{REMOTE_USER} = $username; + accepted: + $ENV{REMOTE_USER} = $username; # # Stuff we need to pass down. Note that I am not bothering with the diff --git a/wiki/wikiproxy.in b/wiki/wikiproxy.in index 3e0cde7b52dd7334764ccd6dd993b9acfb7a88e9..a2b80c89cfcd4068b3ab953f9db5c8a05cd82368 100644 --- a/wiki/wikiproxy.in +++ b/wiki/wikiproxy.in @@ -40,6 +40,7 @@ my $WIKIGROUPDIR = "$WIKIDATADIR/Main"; my $WIKIARCHIVE = "$WIKIDATADIR/_archive"; my $WIKIPASSWD = "$WIKIDIR/data/.htpasswd"; my $USERMAPDB = "$WIKIDIR/data/.usermap"; +my $COOKIEDIR = "/var/db/cgisess"; my $WIKIUSER = "nobody"; my $WIKIGROUP = "nobody"; my $CI = "ci"; @@ -99,6 +100,9 @@ elsif ($action eq "addproject") { elsif ($action eq "setgroups") { exit(SetWikiGroups(@ARGV)); } +elsif ($action eq "xlogin") { + exit(WikixLogin(@ARGV)); +} else { die("*** $0:\n". " Do not know what to do with '$action'!\n"); @@ -724,6 +728,31 @@ sub CI($$) { } return $? >> 8; } + +# +# Backdoor Login +# +sub WikixLogin(@) +{ + usage() + if (@_ != 2); + + my ($user, $secretkey) = @_; + + # + # Create a little file that holds the secret key, named by the user. + # The TWiki login script will check for the existence of this file, + # and use the key inside it to match against the key provided by the + # client browser. + # + open(KEY, ">${COOKIEDIR}/$user") or + fatal("Could not open ${COOKIEDIR}/$user for writing!"); + + print KEY "$secretkey\n"; + print KEY time() . "\n"; + close(KEY); + return 0; +} sub fatal($) { diff --git a/wiki/wikixlogin.in b/wiki/wikixlogin.in new file mode 100644 index 0000000000000000000000000000000000000000..6c865130a167826ae611300968af7000f96515f1 --- /dev/null +++ b/wiki/wikixlogin.in @@ -0,0 +1,127 @@ +#!/usr/bin/perl -wT +# +# EMULAB-COPYRIGHT +# Copyright (c) 2005 University of Utah and the Flux Group. +# All rights reserved. +# +use English; +use Getopt::Std; +use Fcntl ':flock'; + +# +# Add a user to the wiki on ops. Also allow update of password. +# +sub usage() +{ + print STDOUT "Usage: wikixlogin <uid> <key>\n"; + exit(-1); +} +my $optlist = "d"; +my $debug = 0; + +# +# Configure variables +# +my $TB = "@prefix@"; +my $TBOPS = "@TBOPSEMAIL@"; +my $CONTROL = "@USERNODE@"; +my $BOSSNODE = "@BOSSNODE@"; +my $WIKISUPPORT = @WIKISUPPORT@; +my $SSH = "$TB/bin/sshtb"; +my $WIKIPROXY = "$TB/sbin/wikiproxy"; + +# +# 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; + +# +# We do not 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"); +} + +# +# If no wiki support, just exit. +# +if (! $WIKISUPPORT) { + print "WIKI support is not enabled. Exit ...\n"; + exit(0); +} + +# +# Parse command arguments. Once we return from getopts, all that should be +# left are the required arguments. +# +%options = (); +if (! getopts($optlist, \%options)) { + usage(); +} +if (defined($options{"d"})) { + $debug = 1; +} +if (@ARGV != 2) { + usage(); +} +my $user = $ARGV[0]; +my $key = $ARGV[1]; + +# +# Untaint args. +# +if ($user =~ /^([-\w]+)$/) { + $user = $1; +} +else { + die("Bad data in user: $user."); +} +if ($key =~ /^([\w]+)$/) { + $key = $1; +} +else { + fatal("Bad data in secretkey!"); +} + +# +# For ssh. +# +$UID = $EUID; + +if ($CONTROL ne $BOSSNODE) { + if (system("$SSH -host $CONTROL $WIKIPROXY xlogin $user '$key'")) { + fatal("$WIKIPROXY failed on $CONTROL!"); + } +} +exit(0); + +sub fatal($) +{ + my($mesg) = $_[0]; + + die("*** $0:\n". + " $mesg\n"); +} diff --git a/www/defs.php3.in b/www/defs.php3.in index 747746fb77daa4b1052c0919ad314a6fa9dc5462..031e1f649c4b381bbe4b3d8f8fb5df17991cf138 100644 --- a/www/defs.php3.in +++ b/www/defs.php3.in @@ -16,7 +16,8 @@ $TBWWW = "@TBWWW@"; $THISHOMEBASE = "@THISHOMEBASE@"; $ELABINELAB = @ELABINELAB@; $WIKISUPPORT = @WIKISUPPORT@; -$WIKIURL = "https://${USERNODE}/twiki/bin/view"; +$WIKIURL = "https://${USERNODE}/twiki/bin/newlogon"; +$WIKICOOKIENAME = "WikiCookie"; $TBMAILADDR_OPS = "@TBOPSEMAIL_NOSLASH@"; $TBMAILADDR_WWW = "@TBWWWEMAIL_NOSLASH@"; diff --git a/www/gotowiki.php3 b/www/gotowiki.php3 new file mode 100644 index 0000000000000000000000000000000000000000..97d8346488840104dda5c5e28116dd111fe79610 --- /dev/null +++ b/www/gotowiki.php3 @@ -0,0 +1,49 @@ +<?php +# +# EMULAB-COPYRIGHT +# Copyright (c) 2000-2005 University of Utah and the Flux Group. +# All rights reserved. +# +include("defs.php3"); + +if (!$WIKISUPPORT) { + header("Location: index.php3"); + return; +} + +# No Pageheader since we spit out a redirection below. +$uid = GETLOGIN(); +LOGGEDINORDIE($uid, CHECKLOGIN_USERSTATUS| + CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY); + +# +# The page to zap to on the other side +# +if (isset($redurl) && $redurl == "") { + unset($redurl); +} + +# +# Look for our wikicookie. If the browser has it, then there is nothing +# more to do; just redirect the user over to the wiki. +# +if (isset($_COOKIE[$WIKICOOKIENAME])) { + $wikihash = $_COOKIE[$WIKICOOKIENAME]; + + header("Location: ${WIKIURL}?username=${uid}&bosscred=${wikihash}" . + (isset($redurl) ? "&redurl=${redurl}" : "")); + return; +} + +# +# Generate a cookie. Send it over to the wiki server and stash it into +# the users browser for subsequent requests (until logout). +# +$wikihash = GENHASH(); + +SUEXEC("nobody", "nobody", "wikixlogin $uid $wikihash", SUEXEC_ACTION_DIE); + +setcookie($WIKICOOKIENAME, $wikihash, 0, "/", $TBAUTHDOMAIN, $TBSECURECOOKIES); +header("Location: ${WIKIURL}?username=${uid}&bosscred=${wikihash}" . + (isset($redurl) ? "&redurl=${redurl}" : "")); +?> diff --git a/www/menu.php3 b/www/menu.php3 index 00e8527f80f5cb38e16213cac1598d8eaba67ba9..345d9f54aec7b9a6c6be69e6a001e2b3f1d636e5 100644 --- a/www/menu.php3 +++ b/www/menu.php3 @@ -366,8 +366,8 @@ function WRITESIDEBAR() { $wikiname = $CHECKLOGIN_WIKINAME; WRITESIDEBARBUTTON_ABSCOOL("My Wikis", - "${WIKIURL}/Main/$wikiname", - "${WIKIURL}/Main/$wikiname"); + "gotowiki.php3?redurl=Main/$wikiname", + "gotowiki.php3?redurl=Main/$wikiname"); } WRITESIDEBARBUTTON("Update User Information", @@ -391,8 +391,8 @@ function WRITESIDEBAR() { $wikiname = $CHECKLOGIN_WIKINAME; WRITESIDEBARBUTTON_ABSCOOL("My Wikis", - "${WIKIURL}/Main/$wikiname", - "${WIKIURL}/Main/$wikiname"); + "gotowiki.php3?redurl=Main/$wikiname", + "gotowiki.php3?redurl=Main/$wikiname"); } # Since a user can be a member of more than one project, diff --git a/www/showstuff.php3 b/www/showstuff.php3 index 9cab86341d0220733bcd93db6c3135b2e8c4b8c7..f2c80c87ced3214c65f9b169f0ada6d6c8db709d 100644 --- a/www/showstuff.php3 +++ b/www/showstuff.php3 @@ -14,7 +14,7 @@ # A project # function SHOWPROJECT($pid, $thisuid) { - global $WIKISUPPORT, $WIKIURL; + global $WIKISUPPORT; $query_result = DBQueryFatal("select p.*,g.wikiname from projects as p ". @@ -92,7 +92,7 @@ function SHOWPROJECT($pid, $thisuid) { </tr>\n"; if ($WIKISUPPORT && isset($wikiname)) { - $wikiurl = "${WIKIURL}/$wikiname/WebHome"; + $wikiurl = "gotowiki.php3?redurl=$wikiname/WebHome"; echo "<tr> <td>Project Wiki:</td> @@ -383,7 +383,7 @@ function SHOWGROUPMEMBERSHIP($uid) { # A User # function SHOWUSER($uid) { - global $WIKISUPPORT, $WIKIURL; + global $WIKISUPPORT; $userinfo_result = DBQueryFatal("SELECT * from users where uid='$uid'"); @@ -468,7 +468,7 @@ function SHOWUSER($uid) { </tr>\n"; if ($WIKISUPPORT && isset($wikiname)) { - $wikiurl = "${WIKIURL}/Main/$wikiname"; + $wikiurl = "gotowiki.php3?redurl=Main/$wikiname"; echo "<tr> <td>Emulab Wiki Page:</td> diff --git a/www/tbauth.php3 b/www/tbauth.php3 index 9424c7ff3071f2d4ea964182f68fe2b976a3540a..7e0185bbf694a61ea3b797e6e6c219c0bd6157c6 100644 --- a/www/tbauth.php3 +++ b/www/tbauth.php3 @@ -530,6 +530,7 @@ function DOLOGIN($token, $password, $adminmode = 0) { global $TBAUTHCOOKIE, $TBAUTHDOMAIN, $TBAUTHTIMEOUT; global $TBNAMECOOKIE, $TBLOGINCOOKIE, $TBSECURECOOKIES; global $TBMAIL_OPS, $TBMAIL_AUDIT, $TBMAIL_WWW; + global $WIKISUPPORT, $WIKICOOKIENAME; # Caller makes these checks too. if ((!TBvalid_uid($token) && !TBvalid_email($token)) || @@ -785,6 +786,7 @@ function VERIFYPASSWD($uid, $password) { # function DOLOGOUT($uid) { global $CHECKLOGIN_STATUS, $TBAUTHCOOKIE, $TBLOGINCOOKIE, $TBAUTHDOMAIN; + global $WIKISUPPORT, $WIKICOOKIENAME; # Pedantic check. if (!TBvalid_uid($uid)) { @@ -811,6 +813,9 @@ function DOLOGOUT($uid) { # setcookie($TBAUTHCOOKIE, "", $timeout, "/", $TBAUTHDOMAIN, 0); setcookie($TBLOGINCOOKIE, "", $timeout, "/", $TBAUTHDOMAIN, 0); + if ($WIKISUPPORT) { + setcookie($WIKICOOKIENAME, "", $timeout, "/", $TBAUTHDOMAIN, 0); + } return 0; }