Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • alex_orange/emulab-devel
  • hakasapl/emulab-devel
  • cecchet/emulab-devel
  • srirams/emulab-devel
  • chuck/emulab-devel
  • crd/emulab-devel
  • kwebb/emulab-devel
  • moate/emulab-devel
  • grubb/emulab-devel
  • nasir/emulab-devel
  • asydney/emulab-devel
  • kdownie/emulab-devel
  • wvdemeer/emulab-devel
  • anilmr/emulab-devel
  • bvermeul/emulab-devel
  • emulab/emulab-devel
16 results
Show changes
Showing
with 4516 additions and 3312 deletions
#!/usr/bin/perl -w
#
# Copyright (c) 2010-2020 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use English;
use strict;
use Getopt::Std;
use CGI;
use Data::Dumper;
#
# Dump a user in XML format suitable for reading into newuser script.
#
sub usage()
{
print("Usage: dumpuser [-d] [-p] <uid>\n");
exit(-1);
}
my $optlist = "dp";
my $debug = 0;
my $nopswd = 0;
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $PGENISUPPORT= @PROTOGENI_SUPPORT@;
my $OURDOMAIN = "@OURDOMAIN@";
#
# Untaint the path
#
$ENV{'PATH'} = "$TB/bin:$TB/sbin:/bin:/usr/bin:/usr/bin:/usr/sbin";
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;
use User;
use Project;
if ($PGENISUPPORT) {
require GeniHRN;
}
# Protos
sub fatal($);
sub DumpUser($);
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"p"})) {
$nopswd = 1;
}
if (@ARGV != 1) {
usage();
}
my $user = $ARGV[0];
# Map invoking user to object.
my $this_user = User->ThisUser();
if (! defined($this_user)) {
fatal("You ($UID) do not exist!");
}
# Map target user to object.
my $target_user = User->Lookup($user);
if (! defined($target_user)) {
fatal("$user does not exist!");
}
DumpUser($target_user);
exit(0);
#
# Dump the user in XML.
#
sub DumpUser($)
{
my ($user) = @_;
my @keys = ();
# Array of string values to print.
my %xmlnames = (
"name" => {"tag" => "name",
"optional" => 0 },
"email" => {"tag" => "email",
"optional" => 0 },
"pswd" => {"tag" => "passhash",
"optional" => 0 },
"uid" => {"tag" => "uid",
"optional" => 0 },
"URL" => {"tag" => "URL",
"optional" => 1 },
"addr" => {"tag" => "address",
"optional" => 1 },
"addr2" => {"tag" => "address2",
"optional" => 1 },
"city" => {"tag" => "city",
"optional" => 0 },
"state" => {"tag" => "state",
"optional" => 0 },
"zip" => {"tag" => "zip",
"optional" => 1 },
"country" => {"tag" => "country",
"optional" => 0 },
"phone" => {"tag" => "phone",
"optional" => 1 },
"title" => {"tag" => "title",
"optional" => 1 },
"affil" => {"tag" => "affiliation",
"optional" => 0 },
"shell" => {"tag" => "shell",
"optional" => 1 },
"wikiname" => {"tag" => "wikiname",
"optional" => 1 },
"affil_abbrev" => {"tag" => "affiliation_abbreviation",
"optional" => 0 },
);
$user->GetSSHKeys(\@keys) == 0
or fatal("Could not net ssh keys");
print "<userinfo>\n";
foreach my $key (keys(%xmlnames)) {
my $ref = $xmlnames{$key};
my $tag = $ref->{'tag'};
my $optional = $ref->{'optional'};
my $val = $user->$key();
next
if ($optional && (!defined($val) || $val eq ""));
$val = "None"
if (!defined($val) && $key eq "affil_abbrev");
next
if ($nopswd && $key eq "pswd");
print " <attribute name=\"$tag\">";
print "<value>" . CGI::escapeHTML($val) . "</value>";
print "</attribute>\n";
}
# Pubkeys are special.
if (@keys) {
foreach my $key (@keys) {
next
if ($key =~ /^ssh-dss/);
print "<pubkeys>$key</pubkeys>\n";
}
}
print "</userinfo>\n";
}
sub fatal($)
{
my ($mesg) = @_;
print STDERR "*** $0:\n".
" $mesg\n";
exit(-1);
}
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2005 University of Utah and the Flux Group.
# All rights reserved.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use English;
use Getopt::Std;
......
#!/usr/bin/perl -w
#
# Copyright (c) 2005-2022 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use English;
use strict;
use Getopt::Std;
use Data::Dumper;
use File::Temp qw(tempfile);
use JSON;
#
# Ask https://ipinfo.io/ for IP info
#
# select cc.country,sum(t.count) as count from
# (select country,count(distinct(uid)) as count from login_history
# where IP is not null and location is not null and portal='cloudlab'
# group by country,uid) as t
# left join ccodes.ccodes as cc on cc.code=t.country
# group by cc.country order by count desc;
#
#select region,sum(t.count) as count from
# (select region,count(distinct(uid)) as count from login_history
# where IP is not null and location is not null and country='US' and
# portal='cloudlab'
# group by region,uid) as t
#group by region order by count desc;
#
#
sub usage()
{
print "Usage: getipinfo [-n]\n";
print " getipinfo [-n] -p portal\n";
exit(1);
}
my $optlist = "ndp:";
my $impotent = 0;
my $debug = 0;
my $limit = 200;
#
# Configure variables
#
my $TB = "@prefix@";
my $token = "850749cc3b77dc";
my $URL = "http://ipinfo.io/batch?token=${token}";
my $CURL = "/usr/local/bin/curl";
# Load the Testbed support stuff.
use lib "@prefix@/lib";
use emdb;
use User;
use emutil;
# Protos
sub fatal($);
sub WriteResults($);
#
# Turn off line buffering on output
#
$| = 1;
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"n"})) {
$impotent++;
}
if (defined($options{"d"})) {
$debug++;
}
if (defined($options{"p"})) {
my $portal = $options{"p"};
if ($portal ne "cloudlab" && $portal ne "powder") {
fatal("Only cloudlab or powder portal please");
}
exit(WriteResults($portal));
}
#
# Find unmatched IPs in the login_history table and batch them up
# for the request.
#
my $count = 0;
while ($limit) {
$limit--;
my $query_result =
DBQueryFatal("select distinct IP from login_history ".
"where location is null and IP is not null ".
"limit 100");
last
if ($query_result->numrows == 0);
my %IPs = ();
while (my ($IP) = $query_result->fetchrow_array()) {
$IPs{$IP} = $IP;
}
if (keys(%IPs)) {
# Create a temporary files for curl
my ($fpIn, $fnameIn) = tempfile("/tmp/iplistInXXXXX", UNLINK => 0);
if (!defined($fpIn)) {
fatal("Could not create temp file for IPs");
}
my ($fpOut, $fnameOut) = tempfile("/tmp/iplistOutXXXXX", UNLINK => 0);
if (!defined($fpOut)) {
fatal("Could not create temp file for IPs");
}
foreach my $IP (keys(%IPs)) {
print $fpIn "$IP\n";
}
my $command =
"$CURL -s -o $fnameOut -XPOST --data-binary \@${fnameIn} $URL";
if ($debug) {
print "$command\n";
}
system($command);
if ($?) {
fatal("curl failure: '$command'\n");
}
my $json = emutil::ReadFile($fnameOut);
if (!$json || $json eq "") {
fatal("No json received");
}
my $results = eval { decode_json($json) };
if ($@) {
fatal("Could not decode json data");
}
if ($debug) {
print Dumper($results);
}
foreach my $IP (keys(%IPs)) {
my $ref = $results->{$IP};
if (!defined($ref)) {
print STDERR "No data for $IP\n";
next;
}
my $loc = $ref->{'loc'};
my $country = $ref->{'country'};
my $region = $ref->{'region'};
if (!defined($loc)) {
print STDERR "No data for $IP\n";
DBQueryFatal("update login_history set ".
" location='' ".
"where IP='$IP'");
next;
}
$count++;
if ($impotent) {
print "Would set $IP: $loc,$country,$region\n";
next;
}
else {
print "$IP: $loc,$country,$region\n";
DBQueryFatal("update login_history set ".
" location=" . DBQuoteSpecial($loc) . ", ".
" country=" . DBQuoteSpecial($country) . ", ".
" region=" . DBQuoteSpecial($region) . " ".
"where IP='$IP'");
}
}
unlink($fnameIn);
unlink($fnameOut);
}
print "$count IPs completed\n";
last
if (!$count);
sleep(10);
}
exit(0);
#
# Write per portal results files. Queries take a while.
#
sub WriteResults($)
{
my ($portal) = @_;
print "These queries take time, get a cup of coffee.\n";
my $query_result =
DBQueryFatal("select cc.country,sum(t.count) as count from ".
" (select country,count(distinct(uid)) as count ".
" from login_history ".
" where IP is not null and location is not null and ".
" portal='$portal' ".
" group by country,uid) as t ".
"left join ccodes.ccodes as cc on cc.code=t.country ".
"group by cc.country order by count desc");
my $fname = "world-counts-${portal}.csv";
print "Writing $fname ... \n";
if (open(WORLD, ">$fname")) {
print WORLD "name,count\n";
while (my ($country,$count) = $query_result->fetchrow_array()) {
next
if (!defined($country));
$country = "USA"
if ($country eq "United States");
print WORLD "$country,$count\n";
}
close(WORLD);
}
else {
fatal("Could not open $fname for writing: $!\n");
}
$query_result =
DBQueryFatal("select region,sum(t.count) as count from ".
" (select region,count(distinct(uid)) as count ".
" from login_history ".
" where IP is not null and location is not null and ".
" country='US' and portal='$portal' ".
" group by region,uid) as t ".
"group by region order by count desc");
$fname = "us-counts-${portal}.csv";
print "Writing $fname ... \n";
if (open(STATES, ">$fname")) {
print STATES "name,count\n";
while (my ($region,$count) = $query_result->fetchrow_array()) {
next
if (!defined($region));
print STATES "$region,$count\n";
}
close(STATES);
}
else {
fatal("Could not open $fname for writing: $!\n");
}
exit(0);
}
sub fatal($) {
my($mesg) = $_[0];
die("*** $0:\n".
" $mesg\n");
}
#!/usr/bin/perl -w
#
# Copyright (c) 2010-2016, 2019 University of Utah and the Flux Group.
#
# {{{GENIPUBLIC-LICENSE
#
# GENI Public License
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and/or hardware specification (the "Work") to
# deal in the Work without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Work, and to permit persons to whom the Work
# is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Work.
#
# THE WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE WORK OR THE USE OR OTHER DEALINGS
# IN THE WORK.
#
# }}}
#
use strict;
use English;
use Getopt::Std;
use Data::Dumper;
use CGI;
#
#
#
sub usage()
{
print "Usage: manageremote version <remote>\n";
print " manageremote addpeer <remote> <urn> <url> [is_primary]\n";
print " manageremote adduser <remote> <uid>\n";
print " manageremote deluser <remote> <uid>\n";
print " manageremote moduser <remote> <uid>\n";
print " manageremote setgroups <remote> <uid>\n";
print " manageremote xlogin <remote> <uid>\n";
print " manageremote addproject <remote> <pid>\n";
print " manageremote addgroup <remote> <gid>\n";
exit(1);
}
my $optlist = "dnfp";
my $debug = 0;
my $force = 0;
my $impotent = 0;
my $locked = 0;
my $fromdaemon = 0;
#
# Function prototypes
#
sub Version();
sub AddUser(;$);
sub AddPeer();
sub DeleteUser();
sub ModifyUser();
sub SetGroups(;$);
sub CrossLogin();
sub AddProject();
sub AddGroup();
sub fatal($);
sub do_method($$;$);
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $TBLOGS = "@TBLOGSEMAIL@";
my $PGENISUPPORT = @PROTOGENI_SUPPORT@;
my $PEER_ENABLE = @PEER_ENABLE@;
my $PEER_PRIMARY = @PEER_ISPRIMARY@;
my $OURDOMAIN = "@OURDOMAIN@";
my $DUMPUSER = "$TB/sbin/dumpuser";
my $DUMPPROJ = "$TB/sbin/dumpproject";
my $SACERT = "$TB/etc/genisa.pem";
# un-taint path
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin:/usr/site/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Turn off line buffering on output
#
$| = 1;
use lib '@prefix@/lib';
use emdb;
use libtestbed;
use User;
use Project;
use Group;
use emutil;
use GeniHRN;
use Genixmlrpc;
use GeniResponse;
use GeniCredential;
use GeniAuthority;
#
# Check args.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"f"})) {
$force = 1;
}
if (defined($options{"n"})) {
$impotent = 1;
}
if (defined($options{"p"})) {
$fromdaemon = 1;
}
usage()
if (@ARGV < 2 || @ARGV > 5);
my $cmd = shift(@ARGV);
my $peername = shift(@ARGV);
my $peerurn;
if (! $PEER_ENABLE) {
fatal("Peer mode is not enabled");
}
if (! ($PEER_PRIMARY || $cmd eq "addpeer")) {
fatal("You can only run addpeer on this boss");
}
#
# Map invoking user to object.
#
my $this_user = User->ThisUser();
if (! defined($this_user)) {
fatal("You ($UID) do not exist!");
}
#
# Mere users can call only one function.
#
if (!$this_user->IsAdmin() && $cmd ne "xlogin") {
fatal("You must be a TB administrator to run this script!");
}
#
# Load the SA cert to act as caller context.
#
my $certificate = GeniCertificate->LoadFromFile($SACERT);
if (!defined($certificate)) {
fatal("Could not load certificate from $SACERT\n");
}
my $context = Genixmlrpc->Context($certificate);
if (!defined($context)) {
fatal("Could not create context to talk to clearinghouse");
}
Genixmlrpc->SetContext($context);
my $me = GeniAuthority->Lookup($certificate->uuid());
if (!defined($me)) {
fatal("Could not find my own authority object");
}
my $credential = GeniCredential->GetSelfCredential($me);
if (!defined($credential)) {
fatal("Could not create self credential for $me");
}
my $authority;
#
# All operations other then AddPeer require that the peer be
# in the DB.
#
if ($cmd ne "addpeer") {
my $query_result =
DBQueryFatal("select name,urn from emulab_peers ".
"where name='$peername' or urn='$peername'");
fatal("Unknown peer")
if (!$query_result->numrows);
($peername,$peerurn) = $query_result->fetchrow_array();
$authority = GeniAuthority->CreateFromRegistry("sa", $peerurn);
if (!defined($authority)) {
fatal("Could not locate authority for $peername");
}
}
#
# All operations other then xlogin require locking to avoid a
# race with the peer_daemon.
#
if ($cmd ne "xlogin" && !$fromdaemon) {
while (TBScriptLock("portal_op", 0, 5) != TBSCRIPTLOCK_OKAY()) {
print "Could not get the lock; trying again ... ^C to stop trying.\n";
next;
}
$locked = 1;
}
#
# Now dispatch operation.
#
SWITCH: for ($cmd) {
/^version$/ && do {
Version();
last SWITCH;
};
/^adduser$/ && do {
AddUser();
last SWITCH;
};
/^addpeer$/ && do {
AddPeer();
last SWITCH;
};
/^deluser$/ && do {
DeleteUser();
last SWITCH;
};
/^moduser$/ && do {
ModifyUser();
last SWITCH;
};
/^setgroups$/ && do {
SetGroups();
last SWITCH;
};
/^xlogin$/ && do {
CrossLogin();
last SWITCH;
};
/^addproject$/ && do {
AddProject();
last SWITCH;
};
/^addgroup$/ && do {
AddGroup();
last SWITCH;
};
# Default
TBScriptUnlock()
if ($locked);
usage();
}
TBScriptUnlock()
if ($locked);
exit(0);
#
# Get the version.
#
sub Version()
{
my $response = do_method($authority, "GetVersion");
fatal("Could not get version from $authority")
if (! (defined($response) &&
$response->code() == GENIRESPONSE_SUCCESS));
my $version = $response->value();
print "Version: $version\n";
return 0;
}
#
# Add a peer to the list
#
sub AddPeer()
{
usage()
if (@ARGV < 2);
my $urn = shift(@ARGV);
my $url = shift(@ARGV);
my $primary = (@ARGV ? shift(@ARGV) : 0);
my $safe_url = DBQuoteSpecial($url);
$primary = ($primary ? 1 : 0);
fatal("Invalid URN")
if (!GeniHRN::IsValid($urn));
fatal("Invalid peer name")
if (! ($peername =~ /^[-\w]*$/));
my $authority = GeniAuthority->CreateFromRegistry("sa", $urn);
if (!defined($authority)) {
fatal("Could not locate authority for $peername");
}
my $query_result =
DBQueryFatal("select * from emulab_peers ".
"where name='$peername' or urn='$urn' or ".
" weburl=$safe_url");
fatal("Peer already exists. Please delete first")
if ($query_result->numrows);
fatal("Could not add new peer")
if (!DBQueryWarn("insert into emulab_peers set ".
" name='$peername', urn='$urn', weburl=$safe_url, ".
" is_primary='$primary'"));
return 0;
}
#
# Add a user.
#
sub AddUser(;$)
{
my ($token) = @_;
if (! defined($token)) {
usage()
if (! @ARGV);
$token = $ARGV[0];
}
my $user = User->Lookup($token);
if (!defined($user)) {
fatal("No such user");
}
my $uid_idx = $user->uid_idx();
my $uid = $user->uid();
# Check for existing export.
my $query_result =
DBQueryFatal("select * from user_exports ".
"where uid_idx='$uid_idx' and peer='$peername'");
if ($query_result->numrows && !$force) {
fatal("User already exported to peer. Use -f option");
}
my $urn = GeniHRN::Generate($OURDOMAIN, "user", $user->uid());
my $xmlgoo = emutil::ExecQuiet("$DUMPUSER $uid");
if ($?) {
print STDERR "$xmlgoo";
fatal("$DUMPUSER failed");
}
my $args = {"xmlstring" => $xmlgoo,
"urn" => $urn};
my $response = do_method($authority, "AddUser", $args);
fatal("Could not add user to $authority")
if (! (defined($response) &&
($response->code() == GENIRESPONSE_SUCCESS ||
$response->code() == GENIRESPONSE_ALREADYEXISTS)));
DBQueryFatal("replace into user_exports set ".
" uid='$uid', uid_idx='$uid_idx', peer='$peername', ".
" exported=now()");
return 0;
}
#
# Delete a user.
#
sub DeleteUser()
{
usage()
if (! @ARGV);
my $user = User->Lookup($ARGV[0]);
if (!defined($user)) {
fatal("No such user");
}
my $uid = $user->uid();
my $uid_idx = $user->uid_idx();
my $query_result =
DBQueryFatal("select * from user_exports ".
"where uid_idx='$uid_idx' and peer='$peername'");
if (!$query_result->numrows && !$force) {
fatal("User has not been exported to peer. Use -f option");
}
my $urn = GeniHRN::Generate($OURDOMAIN, "user", $user->uid());
my $args = {"urn" => $urn};
my $response = do_method($authority, "DeleteUser", $args);
fatal("Could not delete user from $authority")
if (! (defined($response) &&
($response->code() == GENIRESPONSE_SUCCESS ||
$response->code() == GENIRESPONSE_SEARCHFAILED)));
DBQueryFatal("delete from user_exports ".
"where uid_idx='$uid_idx' and peer='$peername'");
return 0;
}
#
# Modify a user.
#
sub ModifyUser()
{
usage()
if (! @ARGV);
my $user = User->Lookup($ARGV[0]);
if (!defined($user)) {
fatal("No such user");
}
my $uid = $user->uid();
my $uid_idx = $user->uid_idx();
my $query_result =
DBQueryFatal("select * from user_exports ".
"where uid_idx='$uid_idx' and peer='$peername'");
if (!$query_result->numrows && !$force) {
fatal("User has not been exported to peer. Use -f option");
}
my $urn = GeniHRN::Generate($OURDOMAIN, "user", $user->uid());
my $xmlgoo = emutil::ExecQuiet("$DUMPUSER $uid");
if ($?) {
fatal("$DUMPUSER failed");
}
my $args = {"xmlstring" => $xmlgoo,
"urn" => $urn};
my $response = do_method($authority, "ModifyUser", $args);
fatal("Could not modify user at $authority")
if (! (defined($response) &&
$response->code() == GENIRESPONSE_SUCCESS));
return 0;
}
#
# Set the groups for a user.
#
sub SetGroups(;$)
{
my ($token) = @_;
if (! defined($token)) {
usage()
if (! @ARGV);
$token = $ARGV[0];
}
my $user = User->Lookup($token);
if (!defined($user)) {
fatal("No such user");
}
my $uid = $user->uid();
my $uid_idx = $user->uid_idx();
my $query_result =
DBQueryFatal("select * from user_exports ".
"where uid_idx='$uid_idx' and peer='$peername'");
if (!$query_result->numrows && !$force) {
fatal("User has not been exported to peer. Use -f option");
}
my $urn = GeniHRN::Generate($OURDOMAIN, "user", $user->uid());
my @grouplist = ();
if ($user->GroupMembershipList(\@grouplist)) {
fatal("Could not get group list for user");
}
if (! @grouplist) {
print STDERR "$user is not a member of any groups";
return 0;
}
my %grouparray = ();
foreach my $group (@grouplist) {
my $pid_idx = $group->pid_idx();
my $gid_idx = $group->gid_idx();
#
# See if this group has been exported. Skip if not.
#
$query_result =
DBQueryFatal("select pid_idx,gid_idx from group_exports ".
"where pid_idx='$pid_idx' and gid_idx='$gid_idx' and ".
" peer='$peername'");
next
if (!$query_result->numrows);
my $membership = $group->LookupUser($user);
if (!defined($membership)) {
fatal("Could not get membership for $user in $group");
}
my $pid = $group->pid();
my $gid = $group->gid();
my $trust = $membership->trust();
$grouparray{"$pid,$gid"} = $trust;
}
print STDERR Dumper(\%grouparray) if ($debug);
my $args = {"groups" => \%grouparray,
"urn" => $urn};
my $response = do_method($authority, "SetGroups", $args);
fatal("Could not setgroups for user at $authority")
if (! (defined($response) &&
$response->code() == GENIRESPONSE_SUCCESS));
return 0;
}
#
# Cross Login
#
sub CrossLogin()
{
usage()
if (! @ARGV);
my $user = User->Lookup($ARGV[0]);
if (!defined($user)) {
fatal("No such user");
}
my $uid = $user->uid();
my $uid_idx = $user->uid_idx();
my $query_result =
DBQueryFatal("select * from user_exports ".
"where uid_idx='$uid_idx' and peer='$peername'");
if (!$query_result->numrows && !$force) {
fatal("User has not been exported to peer. Use -f option");
}
my $urn = GeniHRN::Generate($OURDOMAIN, "user", $user->uid());
my $args = {"urn" => $urn};
#
# Since this is coming from the web interface, want to limit
# how long we wait, and return status if timed out.
#
Genixmlrpc->SetTimeout(20);
my $response = do_method($authority, "CrossLogin", $args);
fatal("Could not xlogin user at $authority")
if (! (defined($response) &&
$response->code() == GENIRESPONSE_SUCCESS));
my $key = $response->value();
print "$key\n";
return 0;
}
#
# Add a Project
#
sub AddProject()
{
usage()
if (! @ARGV);
my $project = Project->Lookup($ARGV[0]);
if (!defined($project)) {
fatal("No such project");
}
my $pid = $project->pid();
my $pid_idx = $project->pid_idx();
my $leader_uid = $project->head_uid();
my $leader_idx = $project->head_idx();
my $query_result =
DBQueryFatal("select * from group_exports ".
"where pid_idx='$pid_idx' and gid_idx='$pid_idx' and ".
" peer='$peername'");
if ($query_result->numrows && !$force) {
fatal("Project has already been exported to peer. Use -f option");
}
#
# Check that the leader has been exported, and if not do that first.
#
my $leader_result =
DBQueryFatal("select * from user_exports ".
"where uid_idx='$leader_idx' and peer='$peername'");
if (!$leader_result->numrows) {
AddUser($leader_idx);
}
my $xmlgoo = emutil::ExecQuiet("$DUMPPROJ $pid");
if ($?) {
fatal("$DUMPPROJ failed");
}
my $args = {"xmlstring" => $xmlgoo};
my $response = do_method($authority, "AddProject", $args);
fatal("Could not add project to $authority")
if (! (defined($response) &&
($response->code() == GENIRESPONSE_SUCCESS ||
$response->code() == GENIRESPONSE_ALREADYEXISTS)));
DBQueryFatal("replace into group_exports set ".
" pid='$pid', pid_idx='$pid_idx', ".
" gid='$pid', gid_idx='$pid_idx', ".
" exported=now(), updated=now(), ".
" peer='$peername'");
SetGroups($leader_idx);
return 0;
}
#
# Add a Group
#
sub AddGroup()
{
usage()
if (! @ARGV);
my $group = Group->Lookup($ARGV[0]);
if (!defined($group)) {
fatal("No such group");
}
if ($group->IsProjectGroup()) {
fatal("Please use addproject instead.");
}
my $pid_idx = $group->pid_idx();
my $gid_idx = $group->gid_idx();
my $pid = $group->pid();
my $gid = $group->gid();
my $query_result =
DBQueryFatal("select * from group_exports ".
"where pid_idx='$pid_idx' and gid_idx='$pid_idx' and ".
" peer='$peername'");
if (!$query_result->numrows) {
fatal("Project has not been exported to peer.\n");
}
$query_result =
DBQueryFatal("select * from group_exports ".
"where pid_idx='$pid_idx' and gid_idx='$gid_idx' and ".
" peer='$peername'");
if ($query_result->numrows && !$force) {
fatal("Group has already been exported to peer. Use -f option");
}
my %tags = (
"project" => $group->pid(),
"group_id" => $group->gid(),
"group_leader" => $group->leader(),
"group_description" => $group->description() || "",
);
my $args = {"tags" => \%tags};
my $response = do_method($authority, "AddGroup", $args);
fatal("Could not add group to $authority")
if (! (defined($response) &&
($response->code() == GENIRESPONSE_SUCCESS ||
$response->code() == GENIRESPONSE_ALREADYEXISTS)));
DBQueryFatal("replace into group_exports set ".
" pid='$pid', pid_idx='$pid_idx', ".
" gid='$gid', gid_idx='$gid_idx', ".
" exported=now(), updated=now(), ".
" peer='$peername'");
return 0;
}
#
# Make an rpc call to the Emulab interface on the remote authority.
#
sub do_method($$;$)
{
my ($authority, $method, $args) = @_;
$args = {} if (!defined($args));
#
# The URL refers to the sa, but we want the emulab interface.
#
my $url = $authority->url();
$url =~ s/\/sa$/\/emulab/;
$args->{'credentials'} = [$credential->asString()];
my $response =
Genixmlrpc::CallMethod($url, undef, $method, $args);
if (!defined($response)) {
print STDERR "*** Internal error at $authority\n";
return undef;
}
if ($response->code() != GENIRESPONSE_SUCCESS) {
print STDERR "Error at $authority:";
print STDERR " " . $response->output() . "\n";
}
return $response;
}
sub fatal($) {
my ($msg) = @_;
print STDERR "$msg\n";
exit(-1);
}
#!/usr/bin/perl -w
#
# Copyright (c) 2000-2024 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use strict;
use English;
use Getopt::Long qw(:config no_ignore_case);
use POSIX qw(strftime);
use Date::Parse;
#
# Load the Testbed support stuff.
#
use lib "@prefix@/lib";
use libaudit;
use emutil;
use libtestbed;
#
# Create system SSL certificates.
#
sub usage()
{
print("Usage: mksyscert [-d] [-o file] [-p password] [-e email] ".
"[-u url] [-i urn] [-k keyfile] [-a authority] <orgunit> " .
"[-n] [-U] [uuid]\n");
exit(-1);
}
my $debug = 0;
my $printcert= 0;
my $outfile;
my $password = "";
my $email;
my @urls;
my $urn;
my $oldkeyfile;
my $authority;
my $notca = 0;
my $days = 2000;
my $include_uuid = 0;
my %optlist = ( "debug" => \$debug,
"password=s" => \$password,
"output=s" => \$outfile,
"verbose" => \$printcert,
"email=s" => \$email,
"url=s" => \@urls,
"identifier=s" => \$urn,
"keyfile=s" => \$oldkeyfile,
"authority=s" => \$authority,
"UUID" => \$include_uuid,
"notca" => \$notca );
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $TBLOGS = "@TBLOGSEMAIL@";
my $OURDOMAIN = "@OURDOMAIN@";
my $PGENIDOMAIN = "@PROTOGENI_DOMAIN@";
my $PGENISUPPORT= @PROTOGENI_SUPPORT@;
# Locals
my $SSLDIR = "$TB/lib/ssl";
my $TEMPLATE = "$SSLDIR/syscert.cnf";
my $CACONFIG = "$SSLDIR/ca.cnf";
my $EMULAB_CERT = "$TB/etc/emulab.pem";
my $EMULAB_KEY = "$TB/etc/emulab.key";
my $OPENSSL = "/usr/bin/openssl";
my $WORKDIR = "$TB/ssl";
my $RANDFILE = "./.rnd";
my $SAVEUID = $UID;
my $certfile = $EMULAB_CERT;
my $keyfile = $EMULAB_KEY;
# Locals
my $encrypted = 0;
my $sh_password = "";
#
# 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'} = "$TB/bin:$TB/sbin:/bin:/usr/bin:/usr/bin:/usr/sbin";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Turn off line buffering on output
#
$| = 1;
#
# Function prototypes
#
sub fatal($);
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
GetOptions( %optlist ) or usage();
if( defined( $outfile ) ) {
if ($outfile =~ /^([-\w\.\/]+)$/) {
$outfile = $1;
}
else {
die("Tainted arguments: $outfile\n");
}
}
if( defined( $oldkeyfile ) ) {
if ($oldkeyfile =~ /^([-\w\.\/]+)$/) {
$oldkeyfile = $1;
}
else {
die("Tainted arguments: $oldkeyfile\n");
}
}
if( defined( $authority ) ) {
if ($authority =~ /^([-\w\.\/]+)$/) {
$authority = $1;
}
else {
die("Tainted arguments: $authority\n");
}
$certfile = $authority;
$keyfile = $authority;
}
if( $password ) {
#
# Make sure its all escaped since any printable char is allowed.
#
if ($password =~ /^([\040-\176]*)$/) {
$password = $1;
}
else {
die("Tainted argument: $password\n");
}
$sh_password = $password;
$sh_password =~ s/\'/\'\\\'\'/g;
$sh_password = "$sh_password";
$encrypted = 1;
}
if (@ARGV < 1) {
usage();
}
my $orgunit = shift(@ARGV);
my $uuid = (@ARGV ? shift(@ARGV) : undef);
my $is_ca = !$notca;
# Moved before uuid generation. Might be a race, might not.
TBScriptLock("mkusercert") == 0 or
fatal("Could not get the lock!");
# Generate/confirm uuid
if (!defined($uuid)) {
$uuid = NewUUID();
if (!defined($uuid)) {
fatal("Could not generate a new uuid");
}
}
if (!defined($email)) {
$email = $TBOPS;
}
#
# CD to the workdir, and then serialize on the lock file since there is
# some shared goop that the ssl tools muck with (serial number, index, etc.).
#
chdir("$WORKDIR") or
fatal("Could not chdir to $WORKDIR: $!");
#
# Some sillyness to deal with changes to .rnd file handling across
# versions of openssl.
#
if (! -e $RANDFILE) {
system("/bin/dd if=/dev/urandom of=${RANDFILE} bs=256 count=4");
if ($?) {
fatal("Could not generate $RANDFILE");
}
}
#
# Older versions of openssl ignore -rand option, but use this environment
# variable. New versions ignore the environment variable but use -rand.
#
$ENV{"RANDFILE"} = $RANDFILE;
#
# Need an index file, which is the openssl version of the DB.
#
if (! -e "index.txt") {
open(IND, ">index.txt")
or fatal("Could not create index.txt");
close(IND);
}
#
# We have to figure out what the next serial number will be and write
# that into the file. We could let "ca' keep track, but with devel
# trees, we might end up with duplicate serial numbers.
#
# XXX Shared with mkusercert ...
#
my $serial = TBGetUniqueIndex("user_sslcerts");
open(SER, ">serial")
or fatal("Could not create new serial file");
printf SER "%08x\n", $serial;
close(SER);
#
# Create a template conf file.
#
system("cp -f $TEMPLATE syscert.cnf") == 0
or fatal("Could not copy $TEMPLATE to current dir");
open(TEMP, ">>syscert.cnf")
or fatal("Could not open $TEMPLATE for append: $!");
if (defined($urn)) {
print TEMP "subjectAltName=\@req_altname\n";
}
print TEMP "basicConstraints=critical,CA:" .
( $is_ca ? "TRUE" : "FALSE" ) . "\n\n";
if (@urls) {
my $count = 0;
foreach( @urls ) {
# unregistered OID 2.25.305821105408246119474742976030998643995
# (corresponding to UUID e61300a0-c4c5-11de-b14e-0002a5d5c51b)
# is used to indicate generic ProtoGENI XMLRPC servers.
# print TEMP "authorityInfoAccess=2.25.305821105408246119474742976030998643995;URI:$_\n";
print TEMP
"authorityInfoAccess=2.25.305821105.408246119.47474297.603099864.3995;URI:$_\n";
}
}
print TEMP "\n";
print TEMP "[ req_distinguished_name ]\n";
print TEMP "C\t\t=@SSLCERT_COUNTRY@\n";
print TEMP "ST\t\t=@SSLCERT_STATE@\n";
print TEMP "L\t\t=@SSLCERT_LOCALITY@\n";
print TEMP "O\t\t=@SSLCERT_ORGNAME@\n";
print TEMP "OU\t\t= \"$orgunit\"\n";
print TEMP "CN\t\t= $uuid\n";
print TEMP "emailAddress\t= $email\n";
if (defined($urn)) {
print TEMP "\n";
print TEMP "[ req_altname ]\n";
print TEMP "URI.1=$urn\n";
if( $include_uuid ) {
print TEMP "URI.2=urn:uuid:$uuid\n";
}
print TEMP "\n";
}
close(TEMP)
or fatal("Could not close syscert.cnf: $!");
# Redirect output unless in debugging mode.
my $outline = ($debug ? "" : ">/dev/null 2>&1");
if( defined( $oldkeyfile ) ) {
#
# Create a certificate request using the specified key.
#
system("$OPENSSL req -text -new -key $oldkeyfile -config syscert.cnf ".
($encrypted ? " -passout 'pass:${sh_password}' " : " -nodes ") .
" -out syscert_req.pem $outline") == 0
or fatal("Could not create certificate request");
system("$OPENSSL rsa -in $oldkeyfile -out syscert_key.pem $outline") == 0
or fatal("Could not suck key out of old keyfile");
} else {
#
# Create a client side private key and certificate request.
#
my $genopts = " -rand $RANDFILE " .
($encrypted ? " -passout 'pass:${sh_password}' -des3 " : "");
my $output =
emutil::ExecQuiet("$OPENSSL genrsa $genopts -out syscert_key.pem 2048");
if ($?) {
print STDERR $output;
fatal("Could generate new key");
}
$output =
emutil::ExecQuiet("$OPENSSL req -text -new -config syscert.cnf ".
($encrypted ? " -passin 'pass:${sh_password}' " : "") .
" -key syscert_key.pem -out syscert_req.pem $outline");
if ($?) {
print STDERR $output;
fatal("Could not create certificate request");
}
}
#
# Sign the client cert request, creating a client certificate.
# We set the start date an hour in the past, to avoid clock skew
# problems.
#
my $startdate = POSIX::strftime("%y%m%d%H%M%SZ", gmtime(time() - 3600));
#
# Check the expiration on the CA cert, we do not want the new
# certificate to expire after the CA (signer) cert expires.
#
$UID = 0;
my $expires = `$OPENSSL x509 -enddate -noout -in $certfile`;
if ($?) {
fatal("Could not get expiration from $certfile");
}
if ($expires =~ /^notAfter=(.*)$/i) {
my $tmp = str2time($1);
if (!defined($tmp)) {
fatal("Could not convert $certfile expiration to time: $1");
}
$expires = $tmp;
}
else {
fatal("Could not parse $certfile expiration: $expires");
}
if ($expires < time()) {
fatal("$certfile certificate has expired!");
}
# If the CA expires in less then 30 days, grind to a halt.
my $daystoexpire = int(($expires - time()) / (3600 * 24));
if ($daystoexpire <= 30) {
fatal("Refusing to sign new certificate; the $certfile expires in less ".
"then 30 days!");
}
if ($debug) {
print "CA certificate expires in $daystoexpire days.\n";
}
if ($days > $daystoexpire) {
$days = $daystoexpire - 1;
print "Shortening certificate expiration to $days days\n";
}
system("$OPENSSL ca -batch -policy policy_sslxmlrpc -startdate $startdate ".
" -days $days ".
" -name CA_syscerts -config $CACONFIG ".
" -out syscert_cert.pem -cert $certfile -keyfile $keyfile ".
" -infiles syscert_req.pem $outline") == 0
or fatal("Could not sign certificate request");
$UID = $SAVEUID;
#
# Combine the key and the certificate into one file
#
if (defined($outfile)) {
system("cat syscert_key.pem syscert_cert.pem > $outfile") == 0
or fatal("Could not combine cert and key into one file");
if ($printcert) {
system("cat syscert_cert.pem");
}
}
else {
system("cat syscert_key.pem syscert_cert.pem") == 0
or fatal("Could not combine cert and key");
}
TBScriptUnlock();
exit(0);
sub fatal($) {
my($mesg) = $_[0];
TBScriptUnlock();
die("*** $0:\n".
" $mesg\n");
}
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2004 University of Utah and the Flux Group.
# All rights reserved.
# Copyright (c) 2000-2024 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use strict;
use English;
use Getopt::Std;
use Fcntl ':flock';
use Date::Parse;
#
# Load the Testbed support stuff.
......@@ -16,19 +33,24 @@ use lib "@prefix@/lib";
use libaudit;
use libdb;
use libtestbed;
use User;
use emutil;
#
# Create user SSL certificates.
#
sub usage()
{
print("Usage: mkusercert [-d] [-o] [-p password] <user>\n");
print("Usage: mkusercert [-d] [-o] [-r] [-g] [-p password] <user>\n");
exit(-1);
}
my $optlist = "dp:o";
my $debug = 0;
my $output = 0;
my $password;
my $optlist = "dp:ogrc:CPG";
my $debug = 0;
my $output = 0;
my $password = "";
my $geniflag = 0;
my $reusekey = 0;
my $old_password;
#
# Configure variables
......@@ -37,8 +59,12 @@ my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $TBLOGS = "@TBLOGSEMAIL@";
my $OURDOMAIN = "@OURDOMAIN@";
my $PGENIDOMAIN = "@PROTOGENI_DOMAIN@";
my $PGENISUPPORT= @PROTOGENI_SUPPORT@;
my $CONTROL = "@USERNODE@";
my $BOSSNODE = "@BOSSNODE@";
my $OU = "sslxmlrpc"; # orgunit
my $RANDFILE = "./.rnd";
# Locals
my $USERDIR = USERROOT();
......@@ -48,10 +74,20 @@ my $CACONFIG = "$SSLDIR/ca.cnf";
my $EMULAB_CERT = "$TB/etc/emulab.pem";
my $EMULAB_KEY = "$TB/etc/emulab.key";
my $OPENSSL = "/usr/bin/openssl";
my $lockfile = "/var/tmp/testbed_mkusercert_lockfile";
my $KEYGEN = "/usr/bin/ssh-keygen";
my $ADDKEY = "$TB/sbin/addpubkey";
my $SSH = "$TB/bin/sshtb";
my $ACCOUNTPROXY= "$TB/sbin/accountsetup";
my $WORKDIR = "$TB/ssl";
my $SAVEUID = $UID;
# Locals
my $encrypted = 0;
my $db_password = "''";
my $sh_password = "";
my $days = 1000;
my $serial;
#
# We don't want to run this script unless its the real version.
#
......@@ -84,13 +120,16 @@ $| = 1;
# Function prototypes
#
sub fatal($);
sub UserFatal($);
sub CreateNewCert();
sub ChangePassPhrase();
#
# Rewrite audit version of ARGV to prevent password in mail logs.
#
my @NEWARGV = @ARGV;
for ($i = 0; $i < scalar(@NEWARGV); $i++) {
if ($NEWARGV[$i] eq "-p") {
for (my $i = 0; $i < scalar(@NEWARGV); $i++) {
if ($NEWARGV[$i] eq "-p" || $NEWARGV[$i] eq "-c") {
$NEWARGV[$i + 1] = "**********";
}
}
......@@ -100,31 +139,31 @@ AuditSetARGV(@NEWARGV);
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
%options = ();
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"p"})) {
$password = $options{"p"};
#
# Make sure its all escaped since any printable char is allowed.
#
if ($password =~ /^([\040-\176]*)$/) {
$password = $1;
}
else {
die("Tainted argument: $password\n");
}
$password =~ s/\'/\'\\\'\'/g;
$password = "'$password'";
if (defined($options{"r"})) {
$reusekey = 1;
}
if (defined($options{"g"})) {
$geniflag = 1;
}
if (defined($options{"p"}) || defined($options{"P"})) {
$encrypted = 1;
}
if (@ARGV != 1) {
usage();
}
if ($geniflag && !$encrypted) {
fatal("GENI certs must be encrypted (use -p password).");
}
if ($reusekey && !$encrypted) {
fatal("Cannot reuse the key for an unencrypted cert (use -p password).");
}
my $user = $ARGV[0];
#
......@@ -137,16 +176,82 @@ else {
die("Tainted argument: $user\n");
}
#
# This script is always audited. Mail is sent automatically upon exit.
#
if (AuditStart(0)) {
# Figure out what version of OpenSSL
my $sslversion = `$OPENSSL version`;
if ($sslversion =~ /^OpenSSL\s+(\d+)\.(\d+)\./) {
$sslversion = "$1.$2";
} else {
print STDERR "Cannot parse OpenSSL version, assuming 1.0\n";
$sslversion = "1.0";
}
# Map target user to object.
my $target_user = User->Lookup($user);
if (! defined($target_user)) {
fatal("$user does not exist!");
}
# Map invoking user to object.
my $this_user = User->LookupByUnixId($UID);
if (! defined($this_user)) {
fatal("You ($UID) do not exist!");
}
if (defined($options{"p"}) || defined($options{"P"})) {
if (defined($options{"p"})) {
$password = $options{"p"};
}
elsif ($target_user->SSLPassPhrase(1, \$password)) {
if (defined($options{"G"})) {
$password = substr(TBGenSecretKey(), 0, 12);
if (!defined($password) || $password eq "") {
fatal("Could not generate a random passphrase for -P -G");
}
}
else {
fatal("No stored passphrase for -P option");
}
}
#
# Parent exits normally
# Make sure its all escaped since any printable char is allowed.
#
exit(0);
if ($password =~ /^([\040-\176]*)$/) {
$password = $1;
}
else {
die("Tainted argument: $password\n");
}
$db_password = DBQuoteSpecial($password);
$sh_password = $password;
$sh_password =~ s/\'/\'\\\'\'/g;
$sh_password = "$sh_password";
}
# This option is for changing the passphrase on existing key.
# Might need the target user (-C options).
if (defined($options{"c"}) || defined($options{"C"})) {
if (defined($options{"c"})) {
$old_password = $options{"c"};
}
elsif ($target_user->SSLPassPhrase(1, \$old_password)) {
$old_password = undef;
}
if (defined($old_password)) {
#
# Make sure its all escaped since any printable char is allowed.
#
if ($old_password =~ /^([\040-\176]*)$/) {
$old_password = $1;
}
else {
fatal("Tainted password: $old_password");
}
$old_password =~ s/\'/\'\\\'\'/g;
}
}
#
# CD to the workdir, and then serialize on the lock file since there is
# some shared goop that the ssl tools muck with (serial number, index, etc.).
......@@ -154,248 +259,525 @@ if (AuditStart(0)) {
chdir("$WORKDIR") or
fatal("Could not chdir to $WORKDIR: $!");
open(LOCK, ">>$lockfile") || fatal("Couldn't open $lockfile\n");
$count = 0;
if (flock(LOCK, LOCK_EX|LOCK_NB) == 0) {
#
# If we don't get it the first time, we wait for:
# 1) The lock to become free, in which case we do our thing
# 2) The time on the lock to change, in which case we wait for that process
# to finish
#
my $oldlocktime = (stat(LOCK))[9];
my $gotlock = 0;
while (1) {
print "Another exports update in progress, waiting for it to finish\n";
if (flock(LOCK, LOCK_EX|LOCK_NB) != 0) {
# OK, got the lock, we can do what we're supposed to
$gotlock = 1;
last;
}
$locktime = (stat(LOCK))[9];
if ($locktime != $oldlocktime) {
$oldlocktime = $locktime;
last;
}
if ($count++ > 60) {
fatal("Could not get the lock after a long time!\n");
}
sleep(1);
TBScriptLock("mkusercert") == 0 or
fatal("Could not get the lock!");
#
# Some sillyness to deal with changes to .rnd file handling across
# versions of openssl.
#
if (! -e $RANDFILE) {
system("/bin/dd if=/dev/urandom of=${RANDFILE} bs=256 count=4");
if ($?) {
fatal("Could not generate $RANDFILE");
}
}
#
# Older versions of openssl ignore -rand option, but use this environment
# variable. New versions ignore the environment variable but use -rand.
#
$ENV{"RANDFILE"} = $RANDFILE;
#
# Create a client side cert. Reuse the original key if are told to,
# and it actually exists, and the password is valid.
#
# Do this before the AuditStart() so that user error goes back to web.
#
my $reqargs = "";
if ($reusekey) {
my $privkey;
my $cert;
if ($target_user->SSLCert(1, \$cert, \$privkey)) {
$reusekey = 0;
goto newkey;
}
$count = 0;
open(KEYF, "> usercert_key.pem") or
fatal("Could not create file to store existing private key");
print KEYF "-----BEGIN RSA PRIVATE KEY-----\n";
print KEYF $privkey;
print KEYF "-----END RSA PRIVATE KEY-----\n";
close(KEYF);
#
# If we didn't get the lock, wait for the processes that did to finish
# Make sure the user provided the proper passphrase.
#
if (!$gotlock) {
while (1) {
if ((stat(LOCK))[9] != $oldlocktime) {
exit(0);
}
if (flock(LOCK, LOCK_EX|LOCK_NB) != 0) {
close(LOCK);
exit(0);
}
if ($count++ > 20) {
fatal("Process with the lock did not finish after ".
"a long time!\n");
}
sleep(1);
}
my $output =
emutil::ExecQuiet("$OPENSSL rsa -check -in usercert_key.pem ".
" -passin 'pass:${sh_password}'");
if ($?) {
print STDERR $output;
UserFatal("Cannot decrypt private key. Correct pass phrase?");
}
$reqargs = "-key usercert_key.pem -passin 'pass:${sh_password}' ";
newkey:
}
#
# Perl-style touch(1)
# This script is always audited. Mail is sent automatically upon exit.
#
my $now = time;
utime $now, $now, $lockfile;
if (AuditStart(0)) {
#
# Parent exits normally
#
exit(0);
}
#
# Get the user info (the user being operated on).
#
my $query_result =
DBQueryFatal("select u.usr_name,u.usr_email,u.admin,u.unix_uid ".
"from users as u ".
"where u.uid='$user'");
if ($query_result->numrows == 0) {
fatal("$user is not in the DB. This is bad.\n");
}
my @row = $query_result->fetchrow_array();
my $fullname = $row[0];
my $user_email = $row[1];
my $usr_admin = $row[2];
my $user_number = $row[3];
my $user_uuid = $target_user->uuid();
my $user_number = $target_user->unix_uid();
my $user_uid = $target_user->uid();
my $user_dbid = $target_user->dbid();
#
# Get the users earliest project membership to use as the default group
# for the case that the account is being (re)created. We convert that to
# the unix info.
#
my $default_groupname;
my $default_project;
my $default_groupgid;
$query_result =
DBQueryFatal("select m.pid from group_membership as m ".
"where m.uid='$user' and m.pid=m.gid and m.trust!='none' ".
"order by date_approved asc limit 1");
if ($target_user->FirstApprovedProject(\$default_project) < 0) {
fatal("Could not locate default project for $target_user");
}
if (my ($defpid) = $query_result->fetchrow_array) {
if (! TBGroupUnixInfo($defpid, $defpid,
\$default_groupgid, \$default_groupname)) {
fatal("No info for default project $defpid!");
}
if (defined($default_project)) {
$default_groupgid = $default_project->unix_gid();
}
else {
print "No group membership for $user; using the guest group!\n";
print "No group membership for $target_user; using the guest group!\n";
($default_groupname,undef,$default_groupgid,undef) = getgrnam("guest");
(undef,undef,$default_groupgid,undef) = getgrnam("guest");
}
#
# Create a template conf file. We tack on the DN record based on the
# user particulars.
#
system("cp -f $TEMPLATE usercert.cnf") == 0
or fatal("Could not copy $TEMPLATE to current dir");
sub CreateNewCert() {
#
# Need an index file, which is the openssl version of the DB.
#
if (! -e "index.txt") {
open(IND, ">index.txt")
or fatal("Could not create index.txt");
close(IND);
}
open(TEMP, ">>usercert.cnf")
or fatal("Could not open $TEMPLATE for append: $!");
#
# We have to figure out what the next serial number will be and write
# that into the file. We could let "ca' keep track, but with devel
# trees, we might end up with duplicate serial numbers.
#
$serial = TBGetUniqueIndex("user_sslcerts");
print TEMP "OU\t\t= sslxmlrpc\n";
print TEMP "CN\t\t= $user\n";
print TEMP "emailAddress\t= $user" . "\@" . "$OURDOMAIN\n";
close(TEMP)
or fatal("Could not close usercert.cnf: $!");
open(SER, ">serial")
or fatal("Could not create new serial file");
printf SER "%08x\n", $serial;
close(SER);
#
# Create a client side private key and certificate request.
#
system("$OPENSSL req -new -config usercert.cnf ".
(defined($password) ? " -passout pass:${password} " : " -nodes ") .
" -keyout usercert_key.pem -out usercert_req.pem") == 0
or fatal("Could not create certificate request");
#
# Create a template conf file. We tack on the DN record based on the
# user particulars.
#
system("cp -f $TEMPLATE usercert.cnf") == 0
or fatal("Could not copy $TEMPLATE to current dir");
open(TEMP, ">>usercert.cnf")
or fatal("Could not open $TEMPLATE for append: $!");
if ($PGENISUPPORT) {
my $url = "@PROTOGENI_URL@/sa";
# unregistered OID 2.25.305821105408246119474742976030998643995
# (corresponding to UUID e61300a0-c4c5-11de-b14e-0002a5d5c51b)
# is used to indicate generic ProtoGENI XMLRPC servers.
print TEMP
"authorityInfoAccess=2.25.305821105.408246119.47474297.603099864.3995;URI:$url\n";
}
#
# Remove the index file. We keep track of things ourselves. We also have to
# figure out what the next serial number will be and write that into the
# file. We could let "ca' keep track, but with devel trees, we might end
# up with duplicate serial numbers.
#
open(IND, ">index.txt")
or fatal("Could not clear index.txt");
close(IND);
print TEMP "\n";
print TEMP "[ req_distinguished_name ]\n";
print TEMP "C\t\t=@SSLCERT_COUNTRY@\n";
print TEMP "ST\t\t=@SSLCERT_STATE@\n";
print TEMP "L\t\t=@SSLCERT_LOCALITY@\n";
print TEMP "O\t\t=@SSLCERT_ORGNAME@\n";
my $curidx = TBGetUniqueIndex("user_sslcerts");
if ($PGENISUPPORT && $encrypted) {
print TEMP "OU\t\t= $PGENIDOMAIN.$user_uid\n";
}
else {
print TEMP "OU\t\t= $OU\n";
}
print TEMP "CN\t\t= $user_uuid\n";
print TEMP "emailAddress\t= $user_uid" . "\@" . "$OURDOMAIN\n";
open(SER, ">serial")
or fatal("Could not create new serial file");
printf SER "%08x\n", $curidx;
close(SER);
print TEMP "\n[ req_altname ]\nURI.1=urn:publicid:IDN+$OURDOMAIN" .
"+user+$user_uid\n" .
"email=$user_uid" . "\@" . "$OURDOMAIN\n" .
"URI.2=urn:uuid:$user_uuid\n\n";
#
# Sign the client cert request, creating a client certificate.
#
$UID = 0;
system("$OPENSSL ca -batch -policy policy_sslxmlrpc -config $CACONFIG ".
" -name CA_usercerts ".
" -out usercert_cert.pem -cert $EMULAB_CERT -keyfile $EMULAB_KEY ".
" -infiles usercert_req.pem") == 0
or fatal("Could not sign certificate request");
$UID = $SAVEUID;
close(TEMP)
or fatal("Could not close usercert.cnf: $!");
#
# For now, there can be just one cert of each kind (encrypted, and
# unencrypted). Might change that at some point.
#
DBQueryFatal("delete from user_sslcerts ".
"where uid='$user' and ".
" encrypted=" . (defined($password) ? 1 : 0));
#
# Create a client side private key and certificate request.
#
if (!$reusekey) {
my $genopts = " -rand $RANDFILE " .
($encrypted ? " -passout 'pass:${sh_password}' -des3 " : "");
#
# Create a new entry in the table.
#
DBQueryFatal("insert into user_sslcerts (uid, idx, created, encrypted) ".
" values ('$user', $curidx, now(), ".
(defined($password) ? 1 : 0) . ")");
system("$OPENSSL genrsa $genopts -out usercert_key.pem 2048")
== 0 or fatal("Could not generate new key");
}
my $reqopts = ($encrypted ? "-passin 'pass:${sh_password}' " : "");
system("$OPENSSL req $reqopts -new -config usercert.cnf ".
"-key usercert_key.pem -out usercert_req.pem")
== 0 or fatal("Could not create certificate request");
#
# Grab the cert path and strip off the header goo, then insert into
# the DB.
#
my $certstring = "";
#
# Check the expiration on the CA cert, we do not want the new
# certificate to expire after the CA (signer) cert expires.
#
$UID = 0;
my $expires = `$OPENSSL x509 -enddate -noout -in $EMULAB_CERT`;
if ($?) {
fatal("Could not get expiration from $EMULAB_CERT");
}
if ($expires =~ /^notAfter=(.*)$/i) {
my $tmp = str2time($1);
if (!defined($tmp)) {
fatal("Could not convert CA expiration to time: $1");
}
$expires = $tmp;
}
else {
fatal("Could not parse CA expiration: $expires");
}
if ($expires < time()) {
fatal("CA certificate has expired!");
}
# If the CA expires in less then 30 days, grind to a halt.
my $daystoexpire = int(($expires - time()) / (3600 * 24));
if ($daystoexpire <= 30) {
fatal("Refusing to sign new certificate; the CA expires in less ".
"then 30 days!");
}
if ($debug) {
print "CA certificate expires in $daystoexpire days.\n";
}
if ($days > $daystoexpire) {
$days = $daystoexpire - 1;
print "Shortening certificate expiration to $days days\n";
}
#
# Sign the client cert request, creating a client certificate.
#
system("$OPENSSL ca -batch -policy policy_sslxmlrpc -days $days ".
" -name CA_usercerts -config $CACONFIG ".
" -out usercert_cert.pem -cert $EMULAB_CERT -keyfile $EMULAB_KEY ".
" -infiles usercert_req.pem") == 0
or fatal("Could not sign certificate request");
$UID = $SAVEUID;
open(CERT, "$OPENSSL x509 -in usercert_cert.pem |")
or fatal("Could not start x509 on usercert_cert.pem");
#
# We store the DN in the DB too, for creating the crl index file without
# having to reparse all the certs.
#
my $args = "-subject -noout";
if ($sslversion > 1.0) {
$args .= " -nameopt=compat";
}
my $DN = `$OPENSSL x509 $args -in usercert_cert.pem`;
chomp($DN);
if ($DN =~ /^subject=\s*(\/[-\/\=\w\@\.,\s]+)$/) {
$DN = $1;
}
else {
fatal("Could not parse DN from certificate");
}
while (<CERT>) {
next
if ($_ =~ /^--.*--$/);
$certstring .= $_;
}
close(CERT);
#
# Grab the cert path and strip off the header goo, then insert into
# the DB.
#
my $certstring = "";
#
# Now suck in the priv key.
#
my $pkeystring = "";
open(PKEY, "usercert_key.pem")
or fatal("Could open usercert_key.pem");
open(CERT, "$OPENSSL x509 -in usercert_cert.pem |")
or fatal("Could not start x509 on usercert_cert.pem");
while (<PKEY>) {
next
if ($_ =~ /^--.*--$/);
$pkeystring .= $_;
}
close(PKEY);
while (<CERT>) {
next
if ($_ =~ /^--.*--$/);
$certstring .= $_;
}
close(CERT);
$pkeystring = DBQuoteSpecial($pkeystring);
$certstring = DBQuoteSpecial($certstring);
DBQueryFatal("update user_sslcerts set cert=$certstring,privkey=$pkeystring ".
"where uid='$user' and idx=$curidx");
#
# Now suck in the priv key.
#
my $pkeystring = "";
open(PKEY, "usercert_key.pem")
or fatal("Could open usercert_key.pem");
while (<PKEY>) {
next
if ($_ =~ /^--.*--$/);
$pkeystring .= $_;
}
close(PKEY);
#
# Combine the key and the certificate into one file which is installed
# on each remote node and used by tmcc. Installed on boss too so
# we can test tmcc there.
#
system("cat usercert_key.pem usercert_cert.pem > usercert.pem") == 0
or fatal("Could not combine cert and key into one file");
$pkeystring = DBQuoteSpecial($pkeystring);
$certstring = DBQuoteSpecial($certstring);
my $dnstring = DBQuoteSpecial($DN);
# Ensure we keep it past revocation.
$days++;
#
# We save all of the encrypted certs in the DB since we are going to issue
# CRLs for protogeni. We do not bother to save old unencrypted certs since
# they have a different OU and so protogeni will not accept them, they
# do not need to be revoked. The sslxmlrpc server checks the table directly
# so only the most recent is needed.
#
DBQueryFatal("insert into user_sslcerts ".
"(uid,uid_idx,idx,created,expires,encrypted,password, ".
" cert,privkey,DN) ".
"values ('$user_uid', '$user_dbid', $serial, now(), ".
" DATE_ADD(now(), INTERVAL $days DAY), ".
" $encrypted, $db_password, ".
" $certstring, $pkeystring, $dnstring)");
if ($encrypted) {
DBQueryFatal("update user_sslcerts set ".
" revoked=now() ".
"where uid_idx='$user_dbid' and idx!=$serial and ".
" encrypted=1 and revoked is null");
#
# We also want to get rid of the associated ssh pub key that
# we add below. We use the comment to get rid of anything
# that looks like "sslcert:" since up to now we have been leaving
# old ones behind.
#
DBQueryFatal("delete from user_pubkeys ".
"where uid_idx='$user_dbid' and comment like 'sslcert:%'");
}
else {
DBQueryFatal("delete from user_sslcerts ".
"where uid_idx='$user_dbid' and idx!=$serial and ".
" encrypted=0");
}
#
# Combine the key and the certificate into one file which is
# installed in the users home directory.
#
system("cat usercert_key.pem usercert_cert.pem > usercert.pem") == 0
or fatal("Could not combine cert and key into one file");
}
#
# Copy the certificate to the users .ssl directory.
# Change passphrase on the key, and create new pem file.
#
my $ssldir = "$USERDIR/$user/.ssl";
if (! -d $ssldir) {
mkdir($ssldir, 0700) or
fatal("Could not mkdir $ssldir: $!");
sub ChangePassPhrase()
{
my $privkey;
my $cert;
if ($target_user->SSLCert(1, \$cert, \$privkey)) {
UserFatal("No encrypted key for pass phrase change!");
}
chown($user_number, $default_groupgid, $ssldir)
or fatal("Could not chown $ssldir: $!");
}
open(KEYF, "> old_key.pem") or
fatal("Could not create file to store existing private key");
print KEYF "-----BEGIN RSA PRIVATE KEY-----\n";
print KEYF $privkey;
print KEYF "-----END RSA PRIVATE KEY-----\n";
close(KEYF);
#
# Make sure the user provided the proper passphrase.
#
system("$OPENSSL rsa -des3 -in old_key.pem -out usercert_key.pem ".
" -passout 'pass:${sh_password}' ".
" -passin 'pass:${old_password}' >/dev/null 2>&1") == 0
or UserFatal("Cannot decrypt private key. Correct pass phrase?");
#
# Stick the cert into a file too, for changing the pass phrase.
# See below.
#
open(CERTF, "> usercert_cert.pem") or
fatal("Could not create file to store existing certificate");
print CERTF "-----BEGIN CERTIFICATE-----\n";
print CERTF $cert;
print CERTF "-----END CERTIFICATE-----\n";
close(CERTF);
#
# Need to figure which row for update.
#
my $query_result =
DBQueryFatal("select idx from user_sslcerts ".
"where uid_idx='$user_dbid' and ".
" cert=". DBQuoteSpecial($cert));
if (!$query_result->numrows) {
fatal("Could not find idx for certificate");
}
($serial) = $query_result->fetchrow_array();
#
# Now suck in the priv key.
#
my $pkeystring = "";
open(PKEY, "usercert_key.pem")
or fatal("Could open usercert_key.pem");
while (<PKEY>) {
next
if ($_ =~ /^--.*--$/);
$pkeystring .= $_;
}
close(PKEY);
my $target;
$pkeystring = DBQuoteSpecial($pkeystring);
if (defined($password)) {
$target = "$ssldir/encrypted.pem";
DBQueryFatal("update user_sslcerts set ".
" password=$db_password,privkey=$pkeystring ".
"where uid_idx='$user_dbid' and idx=$serial");
#
# Combine the key and the certificate into one file which is
# installed in the users home directory.
#
system("cat usercert_key.pem usercert_cert.pem > usercert.pem") == 0
or fatal("Could not combine cert and key into one file");
}
if (defined($old_password)) {
ChangePassPhrase();
}
else {
$target = "$ssldir/emulab.pem";
CreateNewCert();
}
system("cp -f usercert.pem $target") == 0
or fatal("Could not copy usercert.pem to $target");
# Drop the file into the user .ssl directory.
my $ssldir = "$USERDIR/$user_uid/.ssl";
$UID = $EUID;
system("$SSH -host $CONTROL ".
"'$ACCOUNTPROXY dropfile $user_uid $default_groupgid 0600 $ssldir ".
($encrypted ? "encrypted.pem" : "emulab.pem") . "' < usercert.pem") == 0
or fatal("Could not copy certificate file to $CONTROL");
$UID = $SAVEUID;
if ($encrypted) {
#
# Convert to pkcs12 format, strictly for the geni xmlrpc code, whichs
# does not provide a way to give the passphrase for encrypted x509 keys.
#
system("$OPENSSL pkcs12 -export -in usercert.pem -des3 ".
"-passin 'pass:${sh_password}' -passout 'pass:${sh_password}' ".
"-out usercert.p12 -rand $RANDFILE")
== 0 or fatal("Could not create usercert.p12");
# Drop the file into the user .ssl directory.
$UID = $EUID;
system("$SSH -host $CONTROL ".
"'$ACCOUNTPROXY dropfile $user_uid $default_groupgid 0600 $ssldir ".
"encrypted.p12' < usercert.p12")
== 0 or fatal("Could not copy .p12 file to $CONTROL");
$UID = $SAVEUID;
goto skipssh
if ($target_user->IsNonLocal());
#
# Create an SSH key from the private key. Mostly for geni users,
# who tend not to know how to do such things.
#
my $pemfile = "usercert.pem";
my $sshdir = "$USERDIR/$user_uid/.ssh";
my $pphrase = User::escapeshellarg($password);
# This comment is special. It functions as a cross table reference
# between pubkeys and sslcerts. I might do this differently later.
my $comment = User::escapeshellarg("sslcert:${serial}");
# ssh-keygen whines and refuses to extract unless the mode is 600.
chmod(0600, $pemfile)
or fatal("Could not chmod $pemfile: $!");
#
# The key format is identical to openssh, so just copy it over.
#
$UID = $EUID;
system("$SSH -host $CONTROL '$ACCOUNTPROXY ".
" dropfile $user_uid $default_groupgid 0600 $sshdir ".
" encrypted.key' < usercert_key.pem")
== 0 or fatal("Could not copy ssh key file to $CONTROL");
$UID = $SAVEUID;
chown($user_number, $default_groupgid, "$target")
or fatal("Could not chown $target: $!");
#
# No need to do this when just changing the passphrase.
#
if (!defined($old_password)) {
#
# Extract a public key.
#
system("$KEYGEN -P $pphrase -y -f $pemfile > encrypted.pub")
== 0
or fatal("Could not extract ssh pubkey from $pemfile");
$UID = $EUID;
system("$SSH -host $CONTROL '$ACCOUNTPROXY ".
" dropfile $user_uid $default_groupgid 0644 $sshdir ".
" encrypted.pub' < encrypted.pub")
== 0 or fatal("Could not copy ssh pub key file to $CONTROL");
$UID = $SAVEUID;
#
# Need to remove the current ssh pubkey from the database, but we just
# updated the new serial number so the comment is no longer valid for
# lookup.
#
$target_user->DeleteSSLCertSSHKey();
#
# And add the pubkey to the DB. Mark it as nodelete and
# as internal since we do not want to delete these except when
# creating a new certificate.
#
$EUID = $UID;
system("$ADDKEY -s -N -I -C $comment -u $user_uid ".
" -f encrypted.pub")
== 0 or fatal("Could not add ssh pubkey");
}
skipssh:
}
close(LOCK);
TBScriptUnlock();
exit(0);
sub fatal($) {
my($mesg) = $_[0];
TBScriptUnlock();
die("*** $0:\n".
" $mesg\n");
}
sub UserFatal($) {
my($mesg) = $_[0];
TBScriptUnlock();
print STDERR $mesg;
# Need to do this so that the web interface sees the message.
LogEnd(1);
# And again since the above print went to the the log.
print STDERR $mesg;
# Tell web interface to tell user.
exit(1);
}
#!/usr/bin/perl -wT
#
# Copyright (c) 2000-2021, 2024 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use English;
use strict;
use Getopt::Std;
use XML::Simple;
use Data::Dumper;
use Cwd qw(realpath);
#
# Create a new user from a XML description.
#
sub usage()
{
print("Usage: newproj <xmlfile>\n");
print(" newproj -l -m <pid_idx>\n");
exit(-1);
}
my $optlist = "dm:lns";
my $debug = 0;
my $nonlocal= 0;
my $impotent= 0;
my $silent = 0;
my $portal;
my $resend;
my %licenses = ();
my %nsf_awards = ();
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $TBAUDIT = "@TBAUDITEMAIL@";
my $TBBASE = "@TBBASE@";
my $TBWWW = "@TBWWW@";
my $LICENSES = "$TB/sbin/manage_licenses";
#
# This script is setuid, so please do not run it as root. Hard to track
# what has happened.
#
if ($EUID == 0) {
die("*** $0:\n".
" Please do not run this as root!\n");
}
#
# Untaint the path
#
$ENV{'PATH'} = "$TB/bin:$TB/sbin:/bin:/usr/bin:/usr/bin:/usr/sbin";
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;
use Project;
use User;
use Brand;
# Protos
sub fatal($);
sub UserError($);
# Locals
my $SAVEUID = $UID;
my $xmlfile;
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"n"})) {
$impotent = 1;
}
if (defined($options{"s"})) {
$silent = 1;
}
if (defined($options{"l"})) {
$nonlocal = 1;
}
if (defined($options{"m"})) {
$resend = $options{"m"};
if ($resend =~ /^(\d*)$/) {
$resend = $1;
}
else {
fatal("Bad characters in -m option: $resend");
}
}
else {
usage()
if (@ARGV != 1);
$xmlfile = shift(@ARGV);
}
#
# Map invoking user to object.
# If invoked as "nobody" we are coming from the web interface and there
# is no current user context.
#
my $this_user;
if (getpwuid($UID) ne "nobody") {
$this_user = User->ThisUser();
if (! defined($this_user)) {
fatal("You ($UID) do not exist!");
}
fatal("You must have admin privledges to create new projects!")
if (!TBAdmin());
}
#
# Resend email message and exit.
#
if (defined($resend)) {
my $project = Project->Lookup($resend);
fatal("Could not map project $resend to object!")
if (!defined($project));
exit($project->SendNewProjectEmail());
}
#
# Check the filename when invoked from the web interface; must be a
# file in /tmp.
#
if (! defined($this_user)) {
if ($xmlfile =~ /^([-\w\.\/]+)$/) {
$xmlfile = $1;
}
else {
fatal("Bad data in pathname: $xmlfile");
}
# Use realpath to resolve any symlinks.
my $translated = realpath($xmlfile);
if ($translated =~ /^(\/tmp\/[-\w\.\/]+)$/) {
$xmlfile = $1;
}
else {
fatal("Bad data in translated pathname: $xmlfile");
}
}
#
# These are the fields that we allow to come in from the XMLfile.
#
my %required = ("name" => "pid",
"short description" => "name");
if ($nonlocal) {
%required =
(%required, ("nonlocal_id" => "nonlocal_id",
"nonlocal_type" => "nonlocal_type"));
}
else {
%required =
(%required, ("URL" => "URL",
"funders" => "funders",
"long description" => "why",
"public" => "public",
"num_pcs" => "num_pcs",
"linkedtous" => "linked_to_us"));
}
my %optional = ("newuser_xml" => "newuser_xml",
"leader" => "head_uid", # May be chosen by newuser.
"members" => "num_members",
"ron" => "num_ron",
"plab" => "num_pcplab",
"class" => "forClass",
"whynotpublic" => "public_whynot",
"user_interface" => "default_user_interface",
"nsf_funded" => "nsf_funded",
"nsf_awards" => "nsf_awards",
"nsf_supplement" => "nsf_supplement",
);
#
# This script is not audited cause we want the output to be sent back
# to the web interface. Thats okay since we send email from the script
# anyway.
#
#
# Must wrap the parser in eval since it exits on error.
#
my $xmlparse = eval { XMLin($xmlfile,
VarAttr => 'name',
ContentKey => '-content',
SuppressEmpty => undef); };
fatal($@)
if ($@);
# APT flag. Notice and delete.
if (exists($xmlparse->{'attribute'}->{"portal"})) {
$portal = $xmlparse->{'attribute'}->{"portal"}->{'value'};
delete($xmlparse->{'attribute'}->{"portal"});
my $brand = Brand->Create($portal);
if (!defined($brand)) {
fatal("Bad portal: $portal");
}
}
# Licenses. Save for later, but need to delete.
foreach my $key (keys(%{ $xmlparse->{'attribute'} })) {
if ($key =~ /^license_([-\w]+)$/) {
my $value = $xmlparse->{'attribute'}->{"$key"}->{'value'};
my $name = $1;
if (lc($value) eq "yes") {
system("$LICENSES show $name");
if ($?) {
fatal("Invalid license name: $name");
}
$licenses{$name} = $name;
print "requested license $name\n";
}
delete($xmlparse->{'attribute'}->{"$key"});
}
}
#
# Make sure all the required arguments were provided.
#
foreach my $key (keys(%required)) {
fatal("Missing required attribute '$key'")
if (! exists($xmlparse->{'attribute'}->{"$key"}));
}
#
# We build up an array of arguments to pass to Project->Create() as we check
# the attributes.
#
my %newproj_args = ();
foreach my $key (keys(%{ $xmlparse->{'attribute'} })) {
my $value = $xmlparse->{'attribute'}->{"$key"}->{'value'};
if (!defined($value)) { # Empty string comes from XML as an undef value.
$xmlparse->{'attribute'}->{"$key"}->{'value'} = $value = "";
}
if ($debug) {
my $prval = (defined($value) ? $value : "NULL");
print STDERR "Project attribute: '$key' -> '$prval'\n";
}
my $dbslot;
# Must be in the allowed lists above, with exceptions handled below
if (exists($required{$key})) {
$dbslot = $required{$key};
next
if (!defined($dbslot));
fatal("Null value for required field $key")
if (!defined($value));
}
elsif (exists($optional{$key})) {
$dbslot = $optional{$key};
next
if (!defined($dbslot) || !defined($value));
}
else {
fatal("Invalid attribute in XML: '$key' -> '$value'\n");
}
# Now check that the value is legal.
if (! TBcheck_dbslot($value, "projects", $dbslot,
TBDB_CHECKDBSLOT_WARN|TBDB_CHECKDBSLOT_ERROR)) {
UserError("Illegal data: $key - $value");
}
#
# Do a taint check to avoid warnings, since the values are abviously okay.
#
if ($value =~ /^(.*)$/) {
$value = $1;
}
$newproj_args{$dbslot} = $value;
}
#
# Create the user if an XML file for newuser was supplied.
#
my $newuser_xml;
if (exists($newproj_args{'newuser_xml'})) {
$newuser_xml = $newproj_args{'newuser_xml'};
delete($newproj_args{'newuser_xml'});
#
# Check the filename when invoked from the web interface; must be a
# file in /tmp.
#
if (! defined($this_user)) {
if ($newuser_xml =~ /^([-\w\.\/]+)$/) {
$newuser_xml = $1;
}
else {
fatal("Bad data in pathname: $newuser_xml");
}
# Use realpath to resolve any symlinks.
my $translated = realpath($newuser_xml);
if ($translated =~ /^(\/tmp\/[-\w\.\/]+)$/) {
$newuser_xml = $1;
}
else {
fatal("Bad data in translated pathname: $newuser_xml");
}
}
#
# We can't pass the user type to the newuser script in xml, because it
# determines which args are required or optional in the xml data! The
# user type is always "project leader" for new users under newproj.
#
my $opt = ($impotent ? "-n" : "");
$opt .= " -d"
if ($debug);
my $cmd = "newuser $opt -t leader $newuser_xml";
print $cmd . "\n"
if ($debug);
my $cmd_out = `$cmd`;
if ($?) {
if (($? >> 8) > 0) {
UserError($cmd_out);
}
fatal("Error creating new user: (3, $?, $cmd) $cmd_out");
}
#
# Parse the last line of output. Ick.
#
my @out_lines = split(/^/, $cmd_out);
if (!( $out_lines[@out_lines-1] =~ /^User\s+(\w+)\/(\d+)\s+/)) {
UserError("Transient error: (4, $cmd) $cmd_out");
}
$newproj_args{'head_uid'} = $2;
}
# NSF award. Only one allowed. Change later.
if (exists($newproj_args{'nsf_funded'})) {
my $funded = $newproj_args{'nsf_funded'};
if ($funded == 1) {
my $award = $newproj_args{'nsf_awards'};
my $sup = $newproj_args{'nsf_supplement'};
$nsf_awards{$award} = $sup;
}
delete($newproj_args{'nsf_funded'});
delete($newproj_args{'nsf_awards'});
delete($newproj_args{'nsf_supplement'});
}
if (exists($newproj_args{'forClass'}) && $newproj_args{'forClass'} == 1) {
$newproj_args{'shared_reservations'} = 1;
}
else {
$newproj_args{'shared_reservations'} = 0;
}
#
# Now do special checks.
#
my $leader = User->Lookup($newproj_args{'head_uid'});
UserError("Project leader does not exist!")
if (!defined($leader));
#
# Need a big lock to avoid double click errors, too much stuff going on in
# Project->Create() to lock tables. This lock is automatically dropped.
#
my $lock_result = DBQueryWarn("select GET_LOCK('NewProjectLock', 60)");
if (!$lock_result ||
!$lock_result->numrows) {
fatal("Could not get the new project lock for a long time");
}
UserError("Project already exists; pick another name!")
if (Project->Lookup($newproj_args{'pid'}));
exit(0)
if ($impotent);
#
# Now safe to create the project. Move the pid out of the argument array
# since its actually an argument to the Create() routine. Ditto for the
# project leader.
#
my $new_pid = $newproj_args{'pid'};
delete($newproj_args{'pid'});
delete($newproj_args{'head_uid'});
# Portal (Emulab, APT, CloudLab, or PhantomNet)
$newproj_args{'portal'} = $portal
if (defined($portal));
my $newproj = Project->Create($new_pid, $leader, \%newproj_args);
if (!defined($newproj)) {
fatal("Could not create new project!");
}
my $new_idx = $newproj->pid_idx();
DBQueryWarn("select RELEASE_LOCK('NewProjectLock')");
#
# Add any licenses.
#
if (keys(%licenses)) {
foreach my $name (keys(%licenses)) {
system("$LICENSES require $name $new_pid");
if ($?) {
fatal("Invalid license name: $name");
}
}
}
# And NSF awards
if (keys(%nsf_awards)) {
foreach my $award (keys(%nsf_awards)) {
my $sup = $nsf_awards{$award};
$newproj->AddNSFAward($award, $sup);
}
}
#
# See if we are in an initial Emulab setup. If so, no email sent.
#
my $firstinitstate;
TBGetSiteVar("general/firstinit/state", \$firstinitstate);
#
# Send the email notification.
#
$newproj->SendNewProjectEmail($firstinitstate eq "createproject")
if (! ($nonlocal || $silent));
# Unlink this here, so that the newuser file is left behind in case of error.
# We can then create the user by hand from the xmlfile, if desired.
unlink($newuser_xml)
if (defined($newuser_xml));
# The web interface requires this line to be printed!
print "Project $new_pid/$new_idx has been created\n";
exit(0);
sub fatal($) {
my($mesg) = $_[0];
print STDERR "*** $0:\n".
" $mesg\n";
exit(-1);
}
sub UserError($) {
my($mesg) = $_[0];
print $mesg;
exit(1);
}
sub escapeshellarg($)
{
my ($str) = @_;
$str =~ s/(')/'\\''/g;
return $str;
}
#!/usr/bin/perl -w
#
# Copyright (c) 2000-2022 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use English;
use strict;
use Getopt::Std;
use XML::Simple;
use Data::Dumper;
use Cwd qw(realpath);
#
# Create a new user from a XML description.
#
sub usage()
{
print("Usage: newuser [-s] -t <type> <xmlfile>\n");
exit(-1);
}
my $optlist = "dt:nsprGP";
my $debug = 0;
my $impotent= 0;
my $type = "";
my $silent = 0;
my $relaxed = 0;
my $dopass = 0;
my $genuser = 0;
my $portal;
my $passhash;
my @keyfiles = ();
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $TBAPPROVAL = "@TBAPPROVALEMAIL@";
my $TBAUDIT = "@TBAUDITEMAIL@";
my $TBBASE = "@TBBASE@";
my $TBWWW = "@TBWWW@";
my $WIKISUPPORT = @WIKISUPPORT@;
my $TBADMINGROUP= "@TBADMINGROUP@";
my $checkpass = "$TB/libexec/checkpass";
my $addpubkey = "$TB/sbin/addpubkey";
#
# This script is setuid, so please do not run it as root. Hard to track
# what has happened.
#
if ($EUID == 0) {
die("*** $0:\n".
" Please do not run this as root!\n");
}
#
# Untaint the path
#
$ENV{'PATH'} = "$TB/bin:$TB/sbin:/bin:/usr/bin:/usr/bin:/usr/sbin";
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;
use User;
use EmulabConstants();
use emutil;
use Brand;
# Protos
sub fatal($);
sub UserError($);
sub escapeshellarg($);
# Locals
my $SAVEUID = $UID;
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"n"})) {
$impotent = 1;
}
if (defined($options{"s"})) {
$silent = 1;
}
if (defined($options{"t"})) {
$type = $options{"t"};
}
if (defined($options{"r"})) {
$relaxed = 1;
}
if (defined($options{"P"})) {
$dopass = 1;
}
if (defined($options{"G"})) {
$genuser = 1;
}
if (@ARGV != 1) {
usage();
}
my $xmlfile = shift(@ARGV);
#
# Map invoking user to object.
# If invoked as "nobody" we are coming from the web interface and there
# is no current user context.
#
my $this_user;
if (getpwuid($UID) ne "nobody") {
$this_user = User->ThisUser();
if (! defined($this_user)) {
fatal("You ($UID) do not exist!");
}
fatal("You must have admin privledges to create new users")
if (!$this_user->IsAdmin());
}
else {
#
# Check the filename when invoked from the web interface; must be a
# file in /tmp.
#
if ($xmlfile =~ /^([-\w\.\/]+)$/) {
$xmlfile = $1;
}
else {
fatal("Bad data in pathname: $xmlfile");
}
# Use realpath to resolve any symlinks.
my $translated = realpath($xmlfile);
if ($translated =~ /^(\/tmp\/[-\w\.\/]+)$/) {
$xmlfile = $1;
}
else {
fatal("Bad data in translated pathname: $xmlfile");
}
}
#
# These are the fields that we allow to come in from the XMLfile.
# This first set is required by all types of users
#
my %required = ("name" => "usr_name",
"email" => "usr_email");
my %optional = ("uid" => "uid",
"address2" => "usr_addr2",
"URL" => "usr_URL",
"shell" => "usr_shell",
"password" => undef,
"passphrase" => "initial_passphrase",
"pubkey" => undef,
"pubkeys" => undef);
my %relaxed_fields = ("affiliation_abbreviation" => 1,
"phone" => 1,
"title" => 1,
"address" => 1,
"zip" => 1,
"wikiname" => 1);
#
# These are required for most users, but are optional for wiki-only users
#
my %usually_required = ("address" => "usr_addr",
"city" => "usr_city",
"state" => "usr_state",
"zip" => "usr_zip",
"country" => "usr_country",
"phone" => "usr_phone",
"title" => "usr_title",
"affiliation" => "usr_affil",
"affiliation_abbreviation" => "usr_affil_abbrev");
if ($type eq "wikionly") {
%optional = (%optional, %usually_required);
}
elsif ($type ne "nonlocal") {
%required = (%required, %usually_required);
}
($WIKISUPPORT ? \%required : \%optional)->{"wikiname"} = "wikiname";
#
# Must wrap the parser in eval since it exits on error.
#
my $xmlparse = eval { XMLin($xmlfile,
ForceArray => ["pubkeys"],
VarAttr => 'name',
ContentKey => '-content',
SuppressEmpty => undef); };
fatal($@)
if ($@);
print STDERR Dumper($xmlparse)
if ($debug);
# APT flag. Notice and delete.
if (exists($xmlparse->{'attribute'}->{"portal"})) {
$portal = $xmlparse->{'attribute'}->{"portal"}->{'value'};
delete($xmlparse->{'attribute'}->{"portal"});
my $brand = Brand->Create($portal);
if (!defined($brand)) {
fatal("Bad portal: $portal");
}
$relaxed = 1;
}
#
# Make sure all the required arguments were provided.
#
foreach my $key (keys(%required)) {
next
if ($relaxed && exists($relaxed_fields{$key}));
fatal("Missing required attribute '$key'")
if (! exists($xmlparse->{'attribute'}->{"$key"}));
}
#
# Used by the portal code but we ignore it unless explicitly told
# not to.
#
if (exists($xmlparse->{'attribute'}->{"passhash"})) {
if ($dopass) {
$passhash = $xmlparse->{'attribute'}->{"passhash"}->{'value'};
}
delete($xmlparse->{'attribute'}->{"passhash"});
}
#
# We build up an array of arguments to pass to User->Create() as we check
# the attributes.
#
my %newuser_args = ();
foreach my $key (keys(%{ $xmlparse->{'attribute'} })) {
my $value = $xmlparse->{'attribute'}->{"$key"}->{'value'};
if (!defined($value)) { # Empty string comes from XML as an undef value.
$xmlparse->{'attribute'}->{"$key"}->{'value'} = $value = "";
}
if ($debug) {
print STDERR "User attribute: '$key' -> '$value'\n";
}
my $dbslot;
# Must be in the allowed lists above, with exceptions handled below
if (exists($required{$key})) {
$dbslot = $required{$key};
next
if (!defined($dbslot));
fatal("Null value for required field $key")
if (!defined($value));
}
elsif (exists($optional{$key})) {
$dbslot = $optional{$key};
next
if (!defined($dbslot) || !defined($value));
}
else {
fatal("Invalid attribute in XML: '$key' -> '$value'\n");
}
# Now check that the value is legal.
if (! TBcheck_dbslot($value, "users", $dbslot,
TBDB_CHECKDBSLOT_WARN|TBDB_CHECKDBSLOT_ERROR)) {
UserError("Illegal data: $key - $value");
}
#
# Do a taint check to avoid warnings, since the values are abviously okay.
#
if ($value =~ /^(.*)$/) {
$value = $1;
}
$newuser_args{$dbslot} = $value;
}
#
# Now do special checks.
#
#
# If user selected his own uid, must be unique.
#
if (exists($newuser_args{'uid'})) {
UserError("User already exists; pick another login name!")
if (User->Lookup($newuser_args{'uid'}));
UserError("Reserved user name; pick another login name!")
if (getpwnam($newuser_args{'uid'}));
}
#
# User name must be at least two tokens.
#
my @foo = split(/\s+/, $newuser_args{'usr_name'});
UserError("User name must be more then a single token!")
if (@foo < 2);
#
# Wikiname must be unique.
#
if ($WIKISUPPORT) {
UserError("Wikiname already in use; please pick another!")
if (exists($newuser_args{'wikiname'}) &&
User->LookupByWikiName($newuser_args{'wikiname'}));
}
#
# And the email address has to be unique.
#
UserError("Email address already in use; please pick another!")
if (!$genuser &&
$newuser_args{'usr_email'} ne $TBOPS &&
User->LookupByEmail($newuser_args{'usr_email'}));
#
# Check the password.
#
my $pswd = (exists($xmlparse->{'attribute'}->{'password'}) ?
$xmlparse->{'attribute'}->{'password'}->{'value'} : "*");
# Admins can "star" the password entry.
if ($pswd eq "*") {
if ($type ne "nonlocal" && defined($this_user) && $this_user->IsAdmin()) {
$newuser_args{'usr_pswd'} = "*";
}
else {
UserError("Only admins can star the password entry");
}
}
else {
my $checkpass_args = escapeshellarg($pswd);
$checkpass_args .= " " .
(exists($newuser_args{'uid'}) ? $newuser_args{'uid'} : "ignored");
$checkpass_args .= escapeshellarg($newuser_args{'usr_name'} . ":" .
$newuser_args{'usr_email'});
my $pwokay = `$checkpass $checkpass_args`;
if ($?) {
chomp($pwokay);
if (! ($pwokay =~ /^ok$/)) {
UserError("$pwokay");
}
fatal("Checkpass failed with $?");
}
$newuser_args{'usr_pswd'} = PassWordHash($pswd);
}
#
# Check the passphrase if supplied.
#
if (exists($xmlparse->{'attribute'}->{'passphrase'}) &&
$xmlparse->{'attribute'}->{'passphrase'}->{'value'} ne "") {
my $passphrase = $xmlparse->{'attribute'}->{'passphrase'}->{'value'};
my $checkpass_args = escapeshellarg($passphrase);
$checkpass_args .= " " .
(exists($newuser_args{'uid'}) ? $newuser_args{'uid'} : "ignored");
$checkpass_args .= escapeshellarg($newuser_args{'usr_name'} . ":" .
$newuser_args{'usr_email'});
my $pwokay = `$checkpass $checkpass_args`;
if ($?) {
chomp($pwokay);
if (! ($pwokay =~ /^ok$/)) {
UserError("$pwokay");
}
fatal("Checkpass failed with $?");
}
$newuser_args{'initial_passphrase'} = $passphrase;
}
#
# Do a check on the pubkey if supplied. The safest thing to do is generate
# a temporary file and pass that to addpubkey to check.
#
if (exists($xmlparse->{'attribute'}->{'pubkey'}) ||
exists($xmlparse->{'pubkeys'})) {
my @keys = (exists($xmlparse->{'pubkeys'}) ?
@{ $xmlparse->{'pubkeys'} } :
($xmlparse->{'attribute'}->{'pubkey'}->{'value'}));
foreach my $key (@keys) {
my $keyfile = TBMakeTempFile("addpubkey");
fatal("Could not create tempfile")
if ($?);
open(KEY, ">> $keyfile") or
fatal("Could not open $keyfile");
print KEY $key;
close($keyfile);
if ($debug) {
print STDERR "Checking key in $keyfile ...\n";
}
my $result = `$addpubkey -n -f $keyfile`;
chomp($result);
UserError("Could not parse public key")
if ($?);
push(@keyfiles, $keyfile);
}
}
#
# Now safe to create the user. Move the uid out of the argument array
# since its actually an argument to the Create() routine.
#
exit(0)
if ($impotent);
my $new_uid;
if (exists($newuser_args{'uid'})) {
$new_uid = $newuser_args{'uid'};
delete($newuser_args{'uid'});
}
# Portal (Emulab, APT, CloudLab or PhantomNet)
$newuser_args{'portal'} = $portal
if (defined($portal));
#
# The type modifier comes in on the command line since this is available
# only from the web interface or locally. The usual case is to create a
# normal user.
#
my $flags = 0;
if ($type eq "webonly") {
$flags = $User::NEWUSER_FLAGS_WEBONLY;
}
elsif ($type eq "wikionly") {
$flags = $User::NEWUSER_FLAGS_WIKIONLY;
}
elsif ($type eq "leader") {
$flags = $User::NEWUSER_FLAGS_PROJLEADER;
}
elsif ($type eq "nonlocal") {
$flags = $User::NEWUSER_FLAGS_NONLOCAL;
}
my $newuser = User->Create($new_uid, $flags, \%newuser_args);
if (!defined($newuser)) {
fatal("Could not create new user!");
}
if (defined($portal)) {
$newuser->SetStatus(USERSTATUS_UNAPPROVED());
}
if (defined($passhash)) {
$newuser->SetPassword($passhash);
}
my $key = $newuser->verify_key();
my $usr_uid = $newuser->uid();
my $usr_idx = $newuser->uid_idx();
my $usr_name = $newuser->name();
my $usr_email = $newuser->email();
#
# See if we are in an initial Emulab setup. If so, no email sent.
#
my $firstinitstate;
if (TBGetSiteVar("general/firstinit/state", \$firstinitstate)) {
#
# These initial users gets admin status and some extra groups, etc.
#
if ($firstinitstate eq "createproject" &&
$new_uid ne EmulabConstants::GENIUSER()) {
DBQueryFatal("update users set ".
" admin=1,status='". $User::USERSTATUS_UNAPPROVED . "' " .
"where uid_idx='$usr_idx'");
DBQueryFatal("insert into unixgroup_membership set ".
"uid='$new_uid', uid_idx='$usr_idx', gid='wheel'");
DBQueryFatal("insert into unixgroup_membership set ".
"uid='$new_uid', uid_idx='$usr_idx', gid='$TBADMINGROUP'");
# The web interface requires this line to be printed!
print "User $usr_uid/$usr_idx has been created\n";
exit(0);
}
}
#
# Send the email notification.
#
SENDMAIL("$usr_name '$usr_uid' <$usr_email>",
"Your New User Key",
"\n".
"Dear $usr_name ($usr_uid):\n\n".
"This is your account verification key: $key\n\n".
"Please use this link to verify your user account:\n".
"\n".
" ${TBBASE}/login.php3?vuid=$usr_uid&key=$key\n".
"\n".
($type eq "wikionly" ?
"Once you have verified your account, you will be able to access\n".
"the Wiki. You MUST verify your account first!"
:
($type eq "webonly" ?
"Once you have verified your account, Testbed Operations will be\n".
"able to approve you. You MUST verify your account first!"
:
($type eq "leader" ?
"You will then be verified as a user. When you have been both\n".
"verified and approved by Testbed Operations, you will be marked\n".
"as an active user and granted full access to your account.\n".
"You MUST verify your account before your project can be approved!\n"
:
"Once you have verified your account, the project leader will\n".
"be able to approve you.\n\n".
"You MUST verify your account before the project leader can ".
"approve you\n".
"After project approval, you will be marked as an active user,\n".
"and will be granted full access to your user account."))) .
"\n\n".
"Thanks,\n".
"Testbed Operations\n",
"$TBAPPROVAL",
"Bcc: $TBAUDIT")
if (!($silent || defined($portal)));
#
# Do we have a keyfile? If so, rerun addpubkey for real now that the
# user is created and email is sent.
#
if (@keyfiles) {
# Set the implied user for addpubkey.
$ENV{'HTTP_INVOKING_USER'} = $usr_idx;
my $opt = ($silent ? "-s" : "");
foreach my $keyfile (@keyfiles) {
my $result = `$addpubkey $opt -u $usr_uid -f $keyfile`;
chomp($result);
fatal("Could not parse public key: $result")
if ($?);
unlink($keyfile)
if (! $debug);
}
}
# The web interface requires this line to be printed!
print "User $usr_uid/$usr_idx has been created\n";
exit(0);
sub fatal($) {
my($mesg) = $_[0];
if (@keyfiles && !$debug) {
foreach my $keyfile (@keyfiles) {
unlink($keyfile)
}
}
print STDERR "*** $0:\n".
" $mesg\n";
exit(-1);
}
sub UserError($) {
my($mesg) = $_[0];
if (@keyfiles && !$debug) {
foreach my $keyfile (@keyfiles) {
unlink($keyfile)
}
}
print $mesg;
exit(1);
}
sub escapeshellarg($)
{
my ($str) = @_;
$str =~ s/[^[:alnum:]]/\\$&/g;
return $str;
}
#!/bin/sh
#
# EMULAB-COPYRIGHT
# Copyright (c) 2003-2006 University of Utah and the Flux Group.
# All rights reserved.
# Copyright (c) 2003-2014 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
# Found on the internet, and customized for Emulab
......@@ -29,6 +46,12 @@ else
SCRATCHSTR=""
fi
MAINSITE=@TBMAINSITE@
if [ $MAINSITE -ne 0 ]; then
QUOTAHELP="See https://wiki.emulab.net/wikidocs/wiki/kb81 for more info on quotas."
else
QUOTAHELP=""
fi
for i in `/usr/sbin/repquota -v @FS_WITH_QUOTAS@ | awk '$2 ~ /\+/ {print $1}'`
do
......@@ -64,11 +87,13 @@ PLEASE NOTE: just login to @USERNODE@ directly to do the cleanup!
You will not be able to swapin an experiment to access these directories
while over quota.
$QUOTAHELP
Thanks,
@THISHOMEBASE@ Testbed Operations
@TBOPSEMAIL_NOSLASH@
MESSAGE
) | /usr/sbin/sendmail -t
) | /usr/sbin/sendmail -i -t
done
#!/usr/bin/perl -w
#
# Copyright (c) 2000-2024 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use English;
use Getopt::Std;
#
# This script will generate new Emulab keys for all users who do not
# already have them or if the cert is expired.
#
sub usage()
{
print("Usage: regencerts [-n]\n");
exit(-1);
}
my $optlist = "n";
my $impotent = 0;
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $TBAUDIT = "@TBAUDITEMAIL@";
my $OURDOMAIN = "@OURDOMAIN@";
my $MKCERT = "$TB/sbin/mkusercert";
my $CHECKQUOTA = "$TB/sbin/checkquota";
my $SUDO = "/usr/local/bin/sudo";
my $PROTOUSER = "elabman";
#
# Testbed Support libraries
#
use lib "@prefix@/lib";
use libaudit;
use libdb;
use libtestbed;
use emutil;
use libEmulab;
#
# Turn off line buffering on output
#
$| = 1;
#
# Untaint the path
#
$ENV{'PATH'} = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"n"})) {
$impotent = 1;
}
#
# Grab all active/frozen users.
#
my $query_result =
DBQueryFatal("select u.uid,u.uid_idx,encrypted,c.idx,s.last_activity ".
" from user_sslcerts as c ".
"left join users as u on u.uid_idx=c.uid_idx ".
"left join user_stats as s on s.uid_idx=u.uid_idx ".
"where webonly=0 and wikionly=0 and ".
" (u.status='active' or u.status='frozen') and ".
" revoked is null ".
"order by u.uid");
while (my ($uid,$uid_idx,$encrypted) = $query_result->fetchrow_array()) {
system("$CHECKQUOTA $uid");
if ($?) {
print STDERR "User $uid over quota, not generating certificate!\n";
next;
}
if (!$encrypted) {
print "Regenerating unencrypted certificate for $uid.\n";
if (!$impotent) {
system("$SUDO -u $PROTOUSER $MKCERT $uid_idx");
if ($?) {
print STDERR "Could not regenerate unencrypted cert ".
"for $uid ($uid_idx)\n";
}
}
}
else {
print "Regenerating encrypted certificate for $uid.\n";
if (!$impotent) {
system("$SUDO -u $PROTOUSER $MKCERT -P $uid_idx");
if ($?) {
print STDERR "Could not regenerate encrypted cert ".
"for $uid ($uid_idx)\n";
}
}
}
}
exit(0);
#!/usr/bin/perl -wT
#
# Copyright (c) 2009 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use strict;
use English;
use Getopt::Std;
#
# Spew encypted certificate for invoking user.
#
sub usage()
{
print(STDOUT "Usage: spewcert\n");
exit(-1);
}
my $optlist = "";
my $debug = 0;
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $ELABINELAB = @ELABINELAB@;
# un-taint path
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin:/usr/site/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
# Protos
sub fatal($);
sub UserError($);
#
# Turn off line buffering on output. Very important for this script!
#
$| = 1;
# Load the Testbed support stuff.
use lib "@prefix@/lib";
use libdb;
use libtestbed;
use User;
my $USERDIR = USERROOT();
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"d"})) {
$debug = 1;
}
usage()
if (@ARGV);
# Map invoking user to object.
my $this_user = User->LookupByUnixId($UID);
if (! defined($this_user)) {
fatal("You ($UID) do not exist!");
}
my $user_uid = $this_user->uid();
my $ssldir = "$USERDIR/$user_uid/.ssl";
my $sslfile = "$USERDIR/$user_uid/.ssl/encrypted.p12";
if (! -d $ssldir) {
fatal("$ssldir does not exist");
}
if (! -e $sslfile) {
UserError("You do not have an encrypted certificate. Please create one");
}
my $certificate = `cat $sslfile`;
if ($?) {
fatal("Failed to cat $sslfile");
}
print $certificate;
exit(0);
sub fatal($) {
my($mesg) = $_[0];
print STDERR "*** $0:\n".
" $mesg\n";
exit(-1);
}
sub UserError($) {
my($mesg) = $_[0];
print $mesg;
exit(1);
}
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2006 University of Utah and the Flux Group.
# All rights reserved.
# Copyright (c) 2000-2021 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
use English;
use Getopt::Std;
......@@ -19,17 +36,28 @@ use Getopt::Std;
# allows users to do things on behalf of other users, and we want to track
# that in the audit log.
#
# This script always does the right thing ...
# Use -u for update mode, which skips the checks on current status,
# and forces the target user into that state. Eventually, this should
# be the default mode of operation (independent of web interface).
#
# Use -e with passwd to apply the default password expire interval to
# the new password, otherwise the password is expired immediately to
# force a change.
#
sub usage()
{
print("Usage: tbacct [-f] [-b] ".
"<add|del|mod|passwd|wpasswd|freeze|thaw> <user>\n");
print("Usage: tbacct [-e] [-f] [-b] [-u] [-v] ".
"<add|del|mod|passwd|wpasswd|email|freeze|thaw|verify|revoke|dots|deactivate|reactivate> ".
"<user> [args]\n");
exit(-1);
}
my $optlist = "fb";
my $optlist = "efbuvs";
my $expok = 0;
my $force = 0;
my $batch = 0;
my $update = 0;
my $verified= 0;
my $silent = 0;
#
# Configure variables
......@@ -37,15 +65,25 @@ my $batch = 0;
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $TBLOGS = "@TBLOGSEMAIL@";
my $MAINSITE = @TBMAINSITE@;
my $TBAUDIT = "@TBAUDITEMAIL@";
my $CONTROL = "@USERNODE@";
my $BOSSNODE = "@BOSSNODE@";
my $WITHSFS = @SFSSUPPORT@;
my $WINSUPPORT = @WINSUPPORT@;
my $WITHZFS = @WITHZFS@;
my $ZFS_NOEXPORT= @ZFS_NOEXPORT@;
my $WIKISUPPORT = @WIKISUPPORT@;
my $TRACSUPPORT = @TRACSUPPORT@;
my $BUGDBSUPPORT= @BUGDBSUPPORT@;
my $OPSDBSUPPORT= @OPSDBSUPPORT@;
my $CHATSUPPORT = @CHATSUPPORT@;
my $MAILMANSUPPORT= @MAILMANSUPPORT@;
my $EXPIRE_PASSWORDS = @EXPIRE_PASSWORDS@;
my $THISHOMEBASE= "@THISHOMEBASE@";
my $PROTOUSER = 'elabman';
my $ELABINELAB = @ELABINELAB@;
my $PGENISUPPORT= @PROTOGENI_SUPPORT@;
my $CONFIG_TARGETSYS = @CONFIG_TARGETSYS@;
my $SAMBANODE = "fs"; # DNS makes this do the right thing in E-in-E.
my $SMBPASSWD = "/usr/local/bin/smbpasswd";
......@@ -56,14 +94,15 @@ my $USERADD = "/usr/sbin/pw useradd";
my $USERDEL = "/usr/sbin/pw userdel";
my $USERMOD = "/usr/sbin/pw usermod";
my $CHPASS = "/usr/bin/chpass";
my $SFSKEYGEN = "/usr/local/bin/sfskey gen";
my $ACCOUNTPROXY= "$TB/sbin/accountsetup";
my $GENELISTS = "$TB/sbin/genelists";
my $MKUSERCERT = "$TB/sbin/mkusercert";
my $SFSUPDATE = "$TB/sbin/sfskey_update";
my $PBAG = "$TB/sbin/paperbag";
my $EXPORTSSETUP= "$TB/sbin/exports_setup";
my $ADDWIKIUSER = "$TB/sbin/addwikiuser";
my $DELWIKIUSER = "$TB/sbin/delwikiuser";
my $ADDTRACUSER = "$TB/sbin/tracuser";
my $DELTRACUSER = "$TB/sbin/tracuser -r";
my $ADDBUGDBUSER= "$TB/sbin/addbugdbuser";
my $DELBUGDBUSER= "$TB/sbin/delbugdbuser";
my $ADDCHATUSER = "$TB/sbin/addjabberuser";
......@@ -72,17 +111,21 @@ my $MMMODIFYUSER= "$TB/sbin/mmmodifymember";
my $ADDMMUSER = "$TB/sbin/addmmuser";
my $DELMMUSER = "$TB/sbin/delmmuser";
my $OPSDBCONTROL= "$TB/sbin/opsdb_control";
my $ADDHOOK = "$TB/sbin/adduserhook";
my $SETGROUPS = "$TB/sbin/setgroups";
my $NOLOGIN = "/sbin/nologin";
my $POSTCRL = "$TB/sbin/protogeni/postcrl";
my $SSH = "$TB/bin/sshtb";
my $SAVEUID = $UID;
my $NOSUCHUSER = 67;
my $USEREXISTS = 65;
# Nasty. Should do this with /etc/pw.conf shellpath.
my %shellpaths = ("csh" => "/bin/csh", "sh" => "/bin/sh",
"tcsh" => "/bin/tcsh", "bash" => "/usr/local/bin/bash");
"tcsh" => "/bin/tcsh", "bash" => "/usr/local/bin/bash",
"zsh" => "/usr/local/bin/zsh",
"nologin" => "/usr/sbin/nologin");
my $errors = 0;
my $sfsupdate = 0;
my @row;
my $query_result;
......@@ -121,6 +164,9 @@ use lib "@prefix@/lib";
use libaudit;
use libdb;
use libtestbed;
use User;
use Project;
use emutil;
#
# Function prototypes
......@@ -132,12 +178,26 @@ sub UpdateWindowsPassword();
sub UpdateUser(;$);
sub FreezeUser();
sub ThawUser();
sub DeactivateUser();
sub ReactivateUser();
sub VerifyUser();
sub UpdateEmail();
sub CheckDotFiles();
sub GenerateSFSKey();
sub RevokeUser();
sub fatal($);
my $HOMEDIR = USERROOT();
#
# Rewrite audit version of ARGV to prevent password in mail logs.
#
if (scalar(@ARGV) == 3 && $ARGV[0] eq "passwd") {
my @NEWARGV = @ARGV;
$NEWARGV[scalar(@NEWARGV) - 1] = "**********";
AuditSetARGV(@NEWARGV);
}
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
......@@ -146,17 +206,29 @@ my $HOMEDIR = USERROOT();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"e"})) {
$expok = 1;
}
if (defined($options{"f"})) {
$force = 1;
}
if (defined($options{"b"})) {
$batch = 1;
}
if (@ARGV != 2) {
if (defined($options{"u"})) {
$update = 1;
}
if (defined($options{"v"})) {
$verified = 1;
}
if (defined($options{"s"})) {
$silent = 1;
}
if (@ARGV < 2) {
usage();
}
my $cmd = $ARGV[0];
my $user = $ARGV[1];
my $cmd = shift(@ARGV);
my $user = shift(@ARGV);
#
# Untaint the arguments.
......@@ -167,7 +239,8 @@ if ($user =~ /^([-\w]+)$/i) {
else {
die("Tainted argument: $user\n");
}
if ($cmd =~ /^(add|del|mod|freeze|passwd|wpasswd|thaw)$/) {
if ($cmd =~
/^(add|del|mod|freeze|passwd|wpasswd|thaw|email|verify|revoke|dots|deactivate|reactivate)$/) {
$cmd = $1;
}
else {
......@@ -179,10 +252,40 @@ if ($force && ! TBAdmin($UID)) {
fatal("Only admins can use force mode!");
}
# Map target user to object.
my $target_user = User->Lookup($user);
if (! defined($target_user)) {
fatal("$user does not exist!");
}
#
# Map invoking user to object.
# If invoked as "nobody" its for a user with no actual account, and so
# just set the current user to that user. If we make any callouts it will
# fail (verbosely of course).
#
my $this_user;
if (getpwuid($UID) eq "nobody") {
# The web interface sets this.
$this_user = User->ImpliedUser();
# This can happen using the forget password link; user not logged in.
if (!defined($this_user)) {
$this_user = $target_user;
}
}
else {
$this_user = User->ThisUser();
if (! defined($this_user)) {
fatal("You ($UID) do not exist!");
}
}
#
# This script is always audited. Mail is sent automatically upon exit.
#
if (AuditStart(0)) {
if (!$silent && AuditStart(0)) {
#
# Parent exits normally
#
......@@ -192,46 +295,40 @@ if (AuditStart(0)) {
#
# Get the user info (the user being operated on).
#
$query_result =
DBQueryFatal("select u.usr_pswd,u.unix_uid,u.usr_name, ".
" u.usr_email,u.status,u.webonly,u.usr_shell,admin, ".
" u.usr_w_pswd,u.wikionly ".
"from users as u ".
"where u.uid='$user'");
if ($query_result->numrows == 0) {
fatal("$user is not in the DB. This is bad.\n");
}
@row = $query_result->fetchrow_array();
my $pswd = $row[0];
my $user_number = $row[1];
my $fullname = $row[2];
my $user_email = $row[3];
my $status = $row[4];
my $webonly = $row[5];
my $usr_shell = $row[6];
my $usr_admin = $row[7];
my $wpswd = $row[8];
my $wikionly = $row[9];
my $dbid = $target_user->dbid();
my $pswd = $target_user->pswd();
my $user_number = $target_user->unix_uid();
my $fullname = $target_user->name();
my $user_email = $target_user->email();
my $status = $target_user->status();
my $webonly = $target_user->webonly();
my $usr_shell = $target_user->shell();
my $usr_admin = $target_user->admin();
my $usr_uid = $target_user->uid();
my $wpswd = $target_user->w_pswd();
my $wikionly = $target_user->wikionly();
my $isnonlocal = $target_user->IsNonLocal();
my $nocollabtools = $target_user->nocollabtools();
# Geni users should not get an account on ops.
$usr_shell = "nologin"
if (!defined($usr_shell) || $isnonlocal);
#
# Get the users earliest project membership to use as the default group
# for the case that the account is being (re)created. We convert that to
# the unix info.
#
my $firstproject;
my $default_groupname;
my $default_groupgid;
$query_result =
DBQueryFatal("select m.pid from group_membership as m ".
"where m.uid='$user' and m.pid=m.gid and m.trust!='none' ".
"order by date_approved asc limit 1");
if ($target_user->FirstApprovedProject(\$firstproject) < 0) {
fatal("Could not determine first approved project for $target_user");
}
if (my ($defpid) = $query_result->fetchrow_array) {
if (! TBGroupUnixInfo($defpid, $defpid,
\$default_groupgid, \$default_groupname)) {
fatal("No info for default project $defpid!");
}
if (defined($firstproject)) {
$default_groupname = $firstproject->unix_name();
$default_groupgid = $firstproject->unix_gid();
}
else {
print "No group membership for $user; using the guest group!\n";
......@@ -259,6 +356,10 @@ SWITCH: for ($cmd) {
UpdateWindowsPassword();
last SWITCH;
};
/^email$/ && do {
UpdateEmail();
last SWITCH;
};
/^mod$/ && do {
UpdateUser();
last SWITCH;
......@@ -271,19 +372,26 @@ SWITCH: for ($cmd) {
ThawUser();
last SWITCH;
};
}
# Always do this!
CheckDotFiles();
#
# Invoke as real user for auditing (and cause of perl).
#
if ($WITHSFS && $sfsupdate) {
$EUID = $UID;
system($SFSUPDATE) == 0
or fatal("$SFSUPDATE failed!");
$EUID = 0;
/^deactivate$/ && do {
DeactivateUser();
last SWITCH;
};
/^reactivate$/ && do {
ReactivateUser();
last SWITCH;
};
/^revoke$/ && do {
RevokeUser();
last SWITCH;
};
/^verify$/ && do {
VerifyUser();
last SWITCH;
};
/^dots$/ && do {
CheckDotFiles();
last SWITCH;
};
}
#
......@@ -291,6 +399,10 @@ if ($WITHSFS && $sfsupdate) {
# an account on.
#
TBNodeUpdateAccountsByUID($user);
if ($PGENISUPPORT) {
require APT_Utility;
APT_Utility::UpdateInstancesByUser($target_user);
}
exit(0);
......@@ -306,6 +418,13 @@ sub AddUser()
if ($webonly) {
return 0;
}
#
# Allow for users to be initialized to frozen in an inner Emulab.
#
if ($ELABINELAB && $status eq USERSTATUS_FROZEN) {
print STDERR "Ignoring frozen user in elabinelab\n";
return 0;
}
if ($wikionly) {
$EUID = $UID;
......@@ -320,15 +439,22 @@ sub AddUser()
$EUID = 0;
return 0;
}
fatal("$user is not active! Cannot build an account!");
if ($force) {
$target_user->SetStatus(USERSTATUS_ACTIVE());
$status = USERSTATUS_ACTIVE();
}
else {
fatal("$user is not active! ".
"Cannot build an account! Use -f option.");
}
}
$UID = 0;
if (system("egrep -q -s '^${user}:' /etc/passwd")) {
print "Adding user $user ($user_number) to local node.\n";
if (system("$USERADD $user -u $user_number -c \"$fullname\" ".
"-k /usr/share/skel -h - -m -d $HOMEDIR/$user ".
if (runBusyLoop("$USERADD $user -u $user_number -c \"$fullname\" ".
"-h - -d $HOMEDIR/$user ".
"-g $default_groupname -s $PBAG")) {
fatal("Could not add user $user to local node.");
}
......@@ -340,54 +466,128 @@ sub AddUser()
$fullname =~ s/\"/\'/g;
$fullname =~ s/([^\\])([\'\"\(\)])/$1\\$2/g;
if ($CONTROL ne $BOSSNODE) {
if (1) {
print "Adding user $user ($user_number) to $CONTROL.\n";
if (system("$SSH -host $CONTROL ".
"'$USERADD $user -u $user_number -c \"$fullname\" ".
"-k /usr/share/skel -h - -m -d $HOMEDIR/$user ".
"-g $default_groupname -s /bin/tcsh'")) {
if (($? >> 8) != $USEREXISTS) {
"'$ACCOUNTPROXY adduser $user $user_number \"$fullname\" ".
"$HOMEDIR/$user $default_groupname ".
"$shellpaths{$usr_shell}'")) {
if ($?) {
fatal("Could not add user $user ($user_number) to $CONTROL.");
}
}
#
# Leave the password "starred" on elabinelab; safer.
#
if (!$ELABINELAB && !$CONFIG_TARGETSYS) {
# shell escape.
$pswd =~ s/\$/\\\$/g;
$pswd =~ s/\*/\\\*/g;
print "Initializing user $user password on $CONTROL.\n";
if (system("$SSH -host $CONTROL ".
" \"$ACCOUNTPROXY chpass $user '$pswd'\"")) {
fatal("Could not initialize password for $user on $CONTROL!");
}
}
#
# Extra hook added for CMU. Generalize later.
#
if ($THISHOMEBASE =~ /^cmuemulab$/i) {
print "Running post create hook for user $user on $CONTROL.\n";
# Do not worry about failure.
system("$SSH -host $CONTROL $ADDHOOK $user");
}
}
$UID = $SAVEUID;
$EUID = $UID;
if (0 && $WITHZFS) {
if ($ZFS_NOEXPORT) {
#
# Have to force the new directories to be exported.
# See ZFS code in exports_setup
#
$target_user->BumpActivity();
system($EXPORTSSETUP) == 0 or
fatal("$EXPORTSSETUP failed");
}
#
# There is some lag before the automounter can mount the new volume.
#
if (emutil::waitForMount("$HOMEDIR/$user") < 0) {
fatal("Could not access new user directory");
}
}
$UID = $SAVEUID;
#
# Do the ssh thing. Invoke as real user for auditing.
# Do the ssh thing.
#
$EUID = $UID;
if (system("$ADDKEY -i $user")) {
if ($user ne $PROTOUSER && system("$ADDKEY -i $user")) {
fatal("Could not generate initial ssh key for $user");
}
# Add to elists.
system("$GENELISTS -u $user")
if (! $batch);
# And to the wiki if enabled.
system("$ADDWIKIUSER $user")
if ($WIKISUPPORT && $user ne $PROTOUSER);
# And to the bugdb if enabled.
system("$ADDBUGDBUSER $user")
if ($BUGDBSUPPORT && $user ne $PROTOUSER);
# And to the OPS db if enabled.
system("$OPSDBCONTROL adduser $user")
if ($OPSDBSUPPORT && $user ne $PROTOUSER);
# And to the chat server if enabled.
system("$ADDCHATUSER $user")
if ($CHATSUPPORT && $user ne $PROTOUSER);
# And the mailman lists if enabled.
#
# And the mailman lists if enabled. All users must get this cause
# mailman is used for project mail lists when MAILMANSUPPORT=1.
#
system("$ADDMMUSER $user")
if ($MAILMANSUPPORT);
# Generate the SSL cert for the user.
system("$MKUSERCERT $user");
if ($isnonlocal) {
$EUID = 0;
goto skipstuff;
}
#
# If the user requested an initial encrypted SSL certificate, create
# that too. Need to delete the initial_passphrase slot though, so that
# we do not try to recreate it at some future time.
#
if (defined($target_user->initial_passphrase())) {
my $pphrase = User::escapeshellarg($target_user->initial_passphrase());
system("$MKUSERCERT -p $pphrase $user");
if ($?) {
fatal("Could not create initial encrypted SSL certificate");
}
$target_user->Update({'initial_passphrase' => "NULL"});
}
if (!$nocollabtools) {
# Add to elists.
system("$GENELISTS -u $user")
if (! $batch);
# And to the wiki if enabled.
system("$ADDWIKIUSER $user")
if ($WIKISUPPORT && $user ne $PROTOUSER);
# And to the bugdb if enabled.
system("$ADDBUGDBUSER $user")
if ($BUGDBSUPPORT && $user ne $PROTOUSER);
# And to the OPS db if enabled.
system("$OPSDBCONTROL adduser $user")
if ($OPSDBSUPPORT && $user ne $PROTOUSER);
# And to the chat server if enabled.
system("$ADDCHATUSER $user")
if ($CHATSUPPORT && $user ne $PROTOUSER);
# And to the trac system if enabled.
system("$ADDTRACUSER $user")
if ($TRACSUPPORT && $user ne $PROTOUSER);
}
#
# Must update the exports file or else nodes will complain. There
# is a bit of race in here since this update happens after the
......@@ -398,17 +598,15 @@ sub AddUser()
# do not like this.
#
if (! $batch) {
$target_user->BumpActivity();
print "Updating exports file.\n";
system("$EXPORTSSETUP");
}
$EUID = 0;
# SFS key.
if ($CONTROL ne $BOSSNODE) {
GenerateSFSKey();
}
return UpdatePassword();
skipstuff:
CheckDotFiles();
return 0;
}
#
......@@ -433,23 +631,27 @@ sub DelUser()
$UID = 0;
if (system("$USERDEL $user")) {
if (runBusyLoop("$USERDEL $user")) {
if (($? >> 8) != $NOSUCHUSER) {
fatal("Could not remove user $user from local node.");
}
}
if ($CONTROL ne $BOSSNODE) {
if (1) {
print "Removing user $user from $CONTROL\n";
if (system("$SSH -host $CONTROL '$USERDEL $user'")) {
if (($? >> 8) != $NOSUCHUSER) {
if (system("$SSH -host $CONTROL ".
" '$ACCOUNTPROXY deluser $user $HOMEDIR/$user'")) {
if ($?) {
fatal("Could not remove user $user from $CONTROL.");
}
}
}
$UID = $SAVEUID;
goto skipstuff
if ($isnonlocal || $nocollabtools);
$EUID = $UID;
#
# Must update the exports file or else nodes will complain. Note
......@@ -473,9 +675,13 @@ sub DelUser()
system("$DELMMUSER $user")
if ($MAILMANSUPPORT);
# And to the trac system if enabled.
system("$DELTRACUSER $user")
if ($TRACSUPPORT);
$EUID = 0;
$sfsupdate = 1;
skipstuff:
return 0;
}
......@@ -485,45 +691,123 @@ sub DelUser()
#
sub UpdatePassword()
{
# shell escape.
$pswd =~ s/\$/\\\$/g;
$pswd =~ s/\*/\\\*/g;
#
# Check status. Ignore if user is not active.
# New password (encrypted) comes in on the command line.
#
if ($status ne USERSTATUS_ACTIVE) {
print("$user is not active! Not updating the password!\n");
usage()
if (! @ARGV);
my $new_pswd = shift(@ARGV);
# Lets not do this if no changes.
if ($new_pswd eq $target_user->pswd() && !$force) {
print "Password has not changed ...\n";
return 0;
}
if (! $wikionly) {
# Lets prevent any odd characters.
if ($new_pswd =~ /[\'\\\"\&]+/) {
fatal("Invalid characters in new password encryption string!");
}
#
# Insert into database. When changing password for someone else
# and "-e" (expok) isn't set, then set the expiration to right
# now so that the target user is "forced" to change it.
#
my $expires;
if (!$expok && ! $target_user->SameUser($this_user)) {
$expires = "now()";
}
elsif ($EXPIRE_PASSWORDS) {
$expires = "date_add(now(), interval 1 year)";
}
if ($target_user->SetPassword($new_pswd, $expires)) {
fatal("Could not update password encryption string for $target_user");
}
# Go no further if a nonlocal user.
return 0
if ($isnonlocal);
# Send auditing email before next step in case of failure.
$target_user->SendEmail(
"Password for '$user' has been changed",
"\n".
"Password for '$user' has been changed by " .
$this_user->uid() ."\n".
"\n".
"Name: " . $target_user->name() . "\n".
"IDX: " . $target_user->uid_idx() . "\n".
"\n".
"If this is unexpected, please contact support ".
"(" . $target_user->OpsEmailAddress() . ") immediately!\n".
"\n");
# Go no further if a webonly user.
return 0
if ($webonly);
#
# Go no further if user is not active or frozen.
#
return 0
if (! ($status eq USERSTATUS_ACTIVE || $status eq USERSTATUS_FROZEN));
#
# Change on ops only if there is a real account there.
# For ELABINELAB, safer to leave the password "starred".
#
if (!$wikionly && !$ELABINELAB && !$CONFIG_TARGETSYS) {
#
# Grab from the DB to avoid taint checking sillyness.
#
my $safe_pswd = $target_user->pswd();
# shell escape.
$safe_pswd =~ s/\$/\\\$/g;
$safe_pswd =~ s/\*/\\\*/g;
$UID = 0;
if ($CONTROL ne $BOSSNODE) {
print "Updating user $user password on $CONTROL.\n";
if (system("$SSH -host $CONTROL $CHPASS -p '$pswd' $user")) {
fatal("Could not change password for user $user on $CONTROL!");
if (system("$SSH -host $CONTROL ".
" \"$ACCOUNTPROXY chpass $user '$safe_pswd'\"")) {
fatal("Could not change password for $user on $CONTROL!");
}
}
$UID = $SAVEUID;
}
#
# Ick. If invoked as "nobody" then the user was either frozen or
# inactive. Lets skip the rest of this for now. Needs more thought
# and cleanup in the web interface to this, since we cannot call
# out to these scripts as "nobody" (yet).
#
return 0
if (getpwuid($UID) eq "nobody");
return 0
if ($isnonlocal || $nocollabtools);
$EUID = $UID;
# And to the wiki if enabled.
# And the wiki if enabled.
system("$ADDWIKIUSER -u $user")
if ($WIKISUPPORT && $user ne $PROTOUSER);
if ($WIKISUPPORT && $user ne $PROTOUSER && !$webonly);
# And to the bugdb if enabled.
system("$ADDBUGDBUSER -m $user")
if ($BUGDBSUPPORT && $user ne $PROTOUSER);
if ($BUGDBSUPPORT && $user ne $PROTOUSER && ! ($wikionly || $webonly));
system("$ADDTRACUSER -u $user")
if ($TRACSUPPORT && $user ne $PROTOUSER && !$webonly);
# And to the OPS db if enabled.
system("$OPSDBCONTROL adduser $user")
if ($OPSDBSUPPORT && $user ne $PROTOUSER);
$EUID = 0;
CheckDotFiles();
return 0;
}
......@@ -533,28 +817,62 @@ sub UpdatePassword()
#
sub UpdateWindowsPassword()
{
# shell escape.
$wpswd =~ s/\$/\\\$/g;
#
# Check status. Ignore if user is not active.
# New password (encrypted) comes in on the command line.
#
if ($status ne USERSTATUS_ACTIVE) {
print("$user is not active! Not updating the password!\n");
usage()
if (! @ARGV);
my $new_wpswd = shift(@ARGV);
# Lets not do this if no changes.
if (defined($target_user->w_pswd()) &&
$new_wpswd eq $target_user->w_pswd()) {
print "Password has not changed ...\n";
return 0;
}
$UID = 0;
print "Updating user $user Samba password on $SAMBANODE.\n";
# -s = silent, -a = add user if necessary.
open( SPCMD, "| $SSH -host $SAMBANODE $SMBPASSWD -s -a $user")
|| fatal("Opening $SMBPASSWD pipe, user $user on $SAMBANODE: $! $?");
local $SIG{PIPE} = sub { die "smbpasswd spooler pipe broke" };
print SPCMD "$wpswd\n$wpswd\n";
close SPCMD
|| fatal("Closing $SMBPASSWD pipe, user $user on $SAMBANODE: $! $?");
#
# Insert into database.
#
if ($target_user->SetWindowsPassword($new_wpswd)) {
fatal("Could not update Windows password string for $target_user");
}
$UID = $SAVEUID;
# Go no further if a webonly user.
return 0
if ($webonly);
#
# Go no further if user is not active or frozen.
#
return 0
if (! ($status eq USERSTATUS_ACTIVE || $status eq USERSTATUS_FROZEN));
#
# Do nothing if we are not even doing windoze.
#
return 0
if (! $WINSUPPORT);
#
# Change on ops for Samba only if there is a real account there.
#
if (! $wikionly) {
# shell escape.
$new_wpswd =~ s/\$/\\\$/g;
$UID = 0;
print "Updating user $user Samba password on $SAMBANODE.\n";
# -s = silent, -a = add user if necessary.
open( SPCMD, "| $SSH -host $SAMBANODE $SMBPASSWD -s -a $user")
|| fatal("Opening $SMBPASSWD pipe, user $user on $SAMBANODE: $! $?");
local $SIG{PIPE} = sub { die "smbpasswd spooler pipe broke" };
print SPCMD "$new_wpswd\n$new_wpswd\n";
close SPCMD
|| fatal("Closing $SMBPASSWD pipe, user $user on $SAMBANODE: $! $?");
$UID = $SAVEUID;
}
return 0;
}
......@@ -566,47 +884,63 @@ sub UpdateUser(;$)
my ($freezeopt) = @_;
my $locshellarg = "";
my $remshellarg = "";
$freezeopt = 0 if (!defined($freezeopt));
#
# Sanity check.
#
if ($webonly) {
if ($webonly || $isnonlocal) {
return 0;
}
if (!defined($freezeopt) && ($status ne USERSTATUS_ACTIVE)) {
if (!$freezeopt && ($status ne USERSTATUS_ACTIVE)) {
#
# If doing a modification to a frozen user, then just ignore
# it; the modification will happen later when the user is thawed.
#
if ($status eq USERSTATUS_FROZEN) {
print "Ignoring update of frozen user $user\n";
if ($status eq USERSTATUS_FROZEN || $status eq USERSTATUS_INACTIVE) {
print "Ignoring update of frozen/inactive user $user\n";
return 0;
}
fatal("$user is not active! Cannot update the account!");
}
# Shell is different on local vs control node.
if ((defined($freezeopt) && $freezeopt) || $user eq $PROTOUSER) {
if ($freezeopt) {
$locshellarg = "-s $NOLOGIN";
$remshellarg = "-s $NOLOGIN";
$remshellarg = "$NOLOGIN";
}
else {
# Leave local shell alone if an admin.
$locshellarg = "-s $PBAG"
if (!$usr_admin);
# Admin users get a local shell.
if ($usr_admin) {
$locshellarg = "-s " . $shellpaths{"tcsh"};
if ($MAINSITE) {
$locshellarg .= " -d /home/$usr_uid";
if (! -e "/home/$usr_uid") {
$locshellarg .= " -m";
}
}
}
else {
$locshellarg = "-s $PBAG";
if ($MAINSITE) {
my $homedir = (getpwnam($usr_uid))[7];
if ($homedir eq "/home/$usr_uid") {
$locshellarg .= " -d $HOMEDIR/$usr_uid";
}
}
}
if (!defined($usr_shell) ||
!exists($shellpaths{$usr_shell})) {
$remshellarg = "-s " . $shellpaths{"tcsh"};
$remshellarg = $shellpaths{"tcsh"};
}
else {
$remshellarg = "-s " . $shellpaths{$usr_shell};
$remshellarg = $shellpaths{$usr_shell};
}
}
print "Updating user $user ($user_number) on local node.\n";
$UID = 0;
if (system("$USERMOD $user $locshellarg -c \"$fullname\" ")) {
if (runBusyLoop("$USERMOD $user $locshellarg -c \"$fullname\" ")) {
fatal("Could not modify user $user on local node.");
}
......@@ -620,12 +954,15 @@ sub UpdateUser(;$)
print "Updating user $user ($user_number) on $CONTROL\n";
if (system("$SSH -host $CONTROL ".
"'$USERMOD $user $remshellarg -c \"$fullname\"'")) {
"'$ACCOUNTPROXY moduser $user $remshellarg \"$fullname\"'")){
fatal("Could not modify user $user record on $CONTROL.");
}
}
$UID = $SAVEUID;
return 0
if ($isnonlocal || $nocollabtools);
$EUID = $UID;
# Update elists in case email changed.
system("$MMMODIFYUSER $user")
......@@ -634,7 +971,84 @@ sub UpdateUser(;$)
# Update elists in case email changed.
system("$GENELISTS -m -u $user");
$EUID = 0;
CheckDotFiles()
if (! $freezeopt);
return 0;
}
#
# Change email address for user.
#
sub UpdateEmail()
{
#
# Only admin people can do this.
#
if (!TBAdmin($UID) && !$verified) {
fatal("You do not have permission to update email for user $user.");
}
#
# New email comes in on the command line.
#
usage()
if (! @ARGV);
my $new_email = shift(@ARGV);
# Lets not do this if no changes.
return 0
if ($new_email eq $user_email);
# Must be valid.
if (! TBcheck_dbslot($new_email, "users", "usr_email",
TBDB_CHECKDBSLOT_WARN|TBDB_CHECKDBSLOT_ERROR)) {
fatal("Invalid characters in email address!");
}
my %args = ();
$args{"usr_email"} = $new_email;
if ($target_user->Update(\%args)) {
fatal("Could not update email address for $target_user");
}
return 0
if ($isnonlocal);
# Send auditing email before next step in case of failure.
SENDMAIL("$fullname <$user_email>",
"Email Address for '$user' Modified",
"\n".
"Email Address for '$user' changed by " . $this_user->uid() ."\n".
"\n".
"Name: " . $target_user->name() . "\n".
"IDX: " . $target_user->uid_idx() . "\n".
"Old Email: " . $user_email . "\n".
"New Email: " . $new_email . "\n".
"\n".
"If this is unexpected, please contact Testbed Operations\n".
"($TBOPS) immediately!\n".
"\n",
"$TBOPS",
"CC: $new_email\n".
"Bcc: $TBAUDIT");
# Change global in this script.
$user_email = $target_user->email();
$EUID = $UID;
# Update mailman elists.
system("$MMMODIFYUSER $user")
if ($MAILMANSUPPORT);
# Update system elists.
system("$GENELISTS -m -u $user");
$EUID = 0;
CheckDotFiles();
return 0;
}
......@@ -653,9 +1067,12 @@ sub FreezeUser()
# Check status.
#
if ($status ne USERSTATUS_FROZEN) {
fatal("$user is still active! Cannot freeze the account!");
fatal("$user is still active! Cannot freeze the account!")
if (!$update);
$target_user->SetStatus(USERSTATUS_FROZEN());
$status = USERSTATUS_FROZEN();
}
$sfsupdate = 1;
return UpdateUser(1);
}
......@@ -675,145 +1092,186 @@ sub ThawUser()
# Check status.
#
if ($status ne USERSTATUS_ACTIVE) {
fatal("$user is not active! Cannot thaw the account!");
fatal("$user is not active! Cannot thaw the account!")
if (!$update);
$target_user->SetStatus(USERSTATUS_ACTIVE());
$status = USERSTATUS_ACTIVE();
}
$sfsupdate = 1;
return UpdateUser(0);
#
# This lets users start off as frozen in an ELABINELAB, and then
# get created later. Saves a lot of time.
#
if ($ELABINELAB &&
system("egrep -q -s '^${user}:' /etc/passwd")) {
AddUser() == 0
or fatal("Cannot thaw $user");
runBusyLoop("$USERMOD -n $user -s /bin/tcsh");
}
else {
UpdateUser(0) == 0
or fatal("Cannot thaw $user");
}
#
# Invoke as real user for auditing.
#
$EUID = $UID;
system("$SETGROUPS $user");
$EUID = 0;
return 0;
}
#
# Check dot files. We do this over and over ...
# Deactivate a user.
#
sub CheckDotFiles()
sub DeactivateUser()
{
my $forward = "$HOMEDIR/$user/.forward";
my $cshrc = "$HOMEDIR/$user/.cshrc";
my $profile = "$HOMEDIR/$user/.profile";
if (! -d "$HOMEDIR/$user") {
return 0;
#
# Only admin people can do this.
#
if (! TBAdmin($UID)) {
fatal("You do not have permission to deactivate user $user.");
}
#
# Check status.
#
if ($status ne USERSTATUS_INACTIVE) {
fatal("$user is still active! Cannot deactivate the account!")
if (!$update);
# As the user.
$UID = $user_number;
$target_user->SetStatus(USERSTATUS_INACTIVE());
$status = USERSTATUS_INACTIVE();
}
#
# Set up a .forward file so that any email to them gets forwarded off.
# Shell goes to nologin on the CONTROL node.
#
if (! -e $forward) {
print "Setting up .forward file for $user.\n";
$UID = 0;
if (runBusyLoop("$USERMOD $user -s $NOLOGIN")) {
fatal("Could not set shell to $NOLOGIN for $user on local node.");
}
if ($CONTROL ne $BOSSNODE) {
print "Deactivating user $user ($user_number) on $CONTROL\n";
if (system("echo \"$user_email\" > $forward")) {
fatal("Could not create $forward!");
}
chmod(0644, "$HOMEDIR/$user/.forward") or
fatal("Could not chmod $forward: $!");
$fileowner= (stat($forward))[4];
$dochown=0;
if ($fileowner==0) {
chown($user_number,$default_groupgid,"$HOMEDIR/$user/.forward") or
do {
warn("Could not chown $forward: $!");
$dochown=1;
};
if (system("$SSH -host $CONTROL '$ACCOUNTPROXY deactivateuser $user'")){
fatal("Could not deactivate $user on $CONTROL.");
}
}
$UID = $SAVEUID;
return 0;
}
#
# Reactivate a user.
#
sub ReactivateUser()
{
#
# Add testbed path to .cshrc and .profile.
# Plus a conditional Cygwin section for the Windows system path.
# Only admin people can do this to another user, but we do allow a
# user to reactivate themselves, as from the web interface when they
# log in and the account has been deactivated for lack of use.
#
if (! (TBAdmin($UID) ||
($target_user->SameUser($this_user) &&
$status eq USERSTATUS_ACTIVE))) {
fatal("You do not have permission to reactivate user $user.");
}
#
my $cpathstr = "set path = ($USERPATH \$path)\n" .
'if ( `uname -s` =~ CYGWIN* ) then' . "\n" .
' setenv PATH "${PATH}:/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS"' . "\n" .
'endif';
if (-e $cshrc && system("egrep -q -s '$USERPATH' $cshrc")) {
system("echo '$cpathstr' >> $cshrc");
# Check status.
#
if ($status ne USERSTATUS_ACTIVE) {
fatal("$user is not active! Cannot reactivate the account!")
if (! ($update || $force));
if ($update) {
$target_user->SetStatus(USERSTATUS_ACTIVE());
$status = USERSTATUS_ACTIVE();
}
}
$UID = 0;
if ($CONTROL ne $BOSSNODE) {
print "Reactivating user $user ($user_number) on $CONTROL\n";
my $spathstr = "PATH=$USERPATH:\$PATH\n" .
'if [[ `uname -s` == CYGWIN* ]]; then' . "\n" .
' PATH="$PATH":/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS' . "\n" .
'fi';
if (-e $profile && system("egrep -q -s '$USERPATH' $profile")) {
system("echo '$spathstr' >> $profile");
if (system("$SSH -host $CONTROL '$ACCOUNTPROXY reactivateuser $user'")){
fatal("Could not reactivate $user on $CONTROL.");
}
}
$UID = $SAVEUID;
# Similar to freeze/thaw for our purposes.
UpdateUser(0) == 0
or fatal("Cannot reactivate $user");
return 0;
}
#
# Verify a user. Converts status and sends email
#
sub VerifyUser()
{
#
# Only admin people can do this unless its the user himself.
#
if (! $target_user->SameUser($this_user) && ! TBAdmin()) {
fatal("You do not have permission to verify user $user.");
}
if (defined($dochown) && $dochown!=0) {
chown($user_number,$default_groupgid,"$HOMEDIR/$user/.forward") or
warn("Could not chown $forward: $!");
if ($target_user->status() ne USERSTATUS_NEWUSER) {
fatal("$target_user is not a newuser! Cannot verify the account!");
}
my $newstatus = ($target_user->wikionly() ?
USERSTATUS_ACTIVE() : USERSTATUS_UNAPPROVED());
$target_user->SetStatus($newstatus) == 0 or
fatal("Could not set user status to '$newstatus' for $target_user");
$target_user->SendVerifiedEmail() == 0 or
fatal("Could not send verified email for $target_user");
return 0;
}
#
# Do SFS stuff. Might move this out to its own script at some point.
# Revoke user ssl certs
#
sub GenerateSFSKey()
sub RevokeUser()
{
my $sfsdir = "$HOMEDIR/$user/.sfs";
#
# Set up the sfs key, but only if not done so already.
# This has to be done from root because the sfs_users file needs
# to be updated (and "sfskey register" won't work because it
# prompts for the user's UNIX password if not run from root.)
# Only admin people can do this.
#
if ($WITHSFS && ! -e "$sfsdir/identity") {
if (! -e "$sfsdir" ) {
print "Setting up sfs configuration for $user.\n";
mkdir("$sfsdir", 0700) or
fatal("Could not mkdir $sfsdir: $!");
chown($user_number, $default_groupgid, "$sfsdir") or
fatal("Could not chown $sfsdir: $!");
}
if (! TBAdmin($UID)) {
fatal("You do not have permission to thaw user $user.");
}
$target_user->RevokeSSLCerts();
print "Generating sfs key\n";
if ($PGENISUPPORT) {
$UID = 0;
if (system("$SSH -host $CONTROL '$SFSKEYGEN -KPn ".
"$user\@ops.emulab.net $sfsdir/identity'")) {
fatal("Failure in sfskey gen!");
system("$POSTCRL");
if ($? >> 8 < 0) {
fatal("Could not post updated CRL");
}
# Version 7 stuff for later.
#if (system("$SSH -host $CONTROL '$SFSKEYGEN -KP ".
# "-l $user\@ops.emulab.net $sfsdir/identity'")) {
# fatal("Failure in sfskey gen!");
#}
$UID = $SAVEUID;
}
return 0;
}
chown($user_number, $default_groupgid, "$sfsdir/identity") or
fatal("Could not chown $sfsdir/identity: $!");
chmod(0600, "$sfsdir/identity") or
fatal("Could not chmod $sfsdir/identity: $!");
#
# Grab a copy for the DB. Causes an SFS update key to run so
# that key is inserted into the files.
#
my $ident = `cat $sfsdir/identity`;
if ($ident =~ /.*,.*,.*,(.*),(.*)/) {
# Version 6
DBQueryFatal("replace into user_sfskeys ".
"values ('$user', '$2', '${user}:${1}:${user}::', ".
"now())");
}
elsif ($ident =~ /.*:.*:.*:(.*):(.*)/) {
# Version 7
DBQueryFatal("replace into user_sfskeys ".
"values ('$user', '$2', '${user}:${1}:${user}::', ".
"now())");
}
else {
warn("*** $0:\n".
" Bad emulab SFS public key\n");
}
$sfsupdate = 1;
#
# Check dot files. We do this over and over ...
#
sub CheckDotFiles()
{
$UID = 0;
system("$SSH -host $CONTROL ".
" '$ACCOUNTPROXY checkdotfiles $user $default_groupgid ".
" $user_email'");
if ($?) {
fatal("Could not check dotfiles for user $user on $CONTROL.");
}
$UID = $SAVEUID;
return 0;
}
......
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2003 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
#
# This gets invoked from the Web interface. Simply a wrapper ...
#
#
# Configure variables
#
my $TB = "@prefix@";
#
# Run the real thing, and never return.
#
exec "$TB/sbin/addpubkey", @ARGV;
die("webaddpubkey: Could not exec addpubkey: $!");
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2003 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
#
# This gets invoked from the Web interface. Simply a wrapper ...
#
#
# Configure variables
#
my $TB = "@prefix@";
#
# Run the real thing, and never return.
#
exec "$TB/sbin/addsfskey", @ARGV;
die("webmkacct: Could not exec addsfskey: $!");
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2004 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
#
# This gets invoked from the Web interface. Simply a wrapper ...
#
#
# Configure variables
#
my $TB = "@prefix@";
#
# Run the real thing, and never return.
#
exec "$TB/sbin/mkusercert", @ARGV;
die("webmkusercert: Could not exec mkusercert: $!");
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2003 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
#
# This gets invoked from the Web interface. Simply a wrapper ...
#
#
# Configure variables
#
my $TB = "@prefix@";
#
# Run the real thing, and never return.
#
exec "$TB/sbin/tbacct", @ARGV;
die("webmkacct: Could not exec tbacct: $!");
#
# EMULAB-COPYRIGHT
# Copyright (c) 2002-2006 University of Utah and the Flux Group.
# All rights reserved.
# Copyright (c) 2002-2017, 2020 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
#
# For installation only.
......@@ -10,10 +27,40 @@ SRCDIR = @srcdir@
TESTBED_SRCDIR = @top_srcdir@
OBJDIR = ..
SUBDIR = apache
PGENISUPPORT = @PROTOGENI_SUPPORT@
SYSTEM := $(shell uname -s)
ifeq ($(SYSTEM),FreeBSD)
FBSDREL := $(shell uname -r | sed -e 's/\([^-][^-]*\)-.*/\1/')
FBSDMAJ := $(basename $(FBSDREL))
ifeq ($(FBSDMAJ),7)
SCRIPT_HACK = 1
endif
endif
include $(OBJDIR)/Makeconf
CONFIG_FILES = httpd.conf httpd.conf-ops
OPS_FILES = httpd.conf-ops php.ini
CONFIG_FILES = httpd.conf $(OPS_FILES)
ifeq ($(PGENISUPPORT),1)
CONFIG_GENI = httpd-geni.conf
CONFIG_FILES += $(CONFIG_GENI)
endif
ifeq ($(APACHE_VERSION),24)
# For VPATH.
MOSTLY_SRCDIRS = ${SRCDIR}/v24
SCRIPT_HACK = 0
else
ifeq ($(APACHE_VERSION),22)
# For VPATH.
MOSTLY_SRCDIRS = ${SRCDIR}/v2
SCRIPT_HACK = 0
else
MOSTLY_SRCDIRS = ${SRCDIR}/v1
endif
endif
INSTALL_PHP_CONFIG = /usr/local/etc
#
# Force dependencies to make sure configure regenerates if the .in file
......@@ -21,8 +68,19 @@ CONFIG_FILES = httpd.conf httpd.conf-ops
#
all: $(CONFIG_FILES)
control-build: $(OPS_FILES)
include $(TESTBED_SRCDIR)/GNUmakerules
#
# Override version from GNUmakerules since the source is kept in a
# different place, and the config script is a pain to work with.
# Maybe we can just make this the default in GNUmakerules.
#
%: %.in $(OBJDIR)/config.status
@echo "Regenerating $@ from $(subst $(TESTBED_SRCDIR)/,,$<)"
cd $(OBJDIR) && CONFIG_FILES=$(SUBDIR)/$@:$(subst $(TESTBED_SRCDIR)/,,$<) ./config.status
# Like the INSTALL_ETCDIR target
$(INSTALL_APACHE_CONFIG)/%: %
@echo "Installing $<"
......@@ -30,9 +88,92 @@ $(INSTALL_APACHE_CONFIG)/%: %
$(INSTALL_DATA) $< $@
install: $(addprefix $(INSTALL_APACHE_CONFIG)/, $(CONFIG_FILES))
#
# XXX hack, hack: need to fix the path to the auth_mysql_module
# This could (should?) be done with configure, but apache port might
# not be installed when we configure our software.
#
# XXX ugh, do the same thing to detect php5...
#
# Note that this is not needed for apache22.
#
httpd.conf.fixed: httpd.conf
-@cp httpd.conf httpd.conf.fixed
@if [ -x /usr/local/libexec/apache/mod_auth_mysql.so ]; then \
sed -i "" -e '/^LoadModule auth_mysql/s/libauth/mod_auth/' httpd.conf.fixed; \
echo "Updated httpd.conf for auth_mysql"; \
fi
@if [ -x /usr/local/libexec/apache/libphp5.so ]; then \
sed -i "" -e 's/php4/php5/g' httpd.conf.fixed; \
echo "Updated httpd.conf for php5"; \
fi
httpd.conf-ops.fixed: httpd.conf-ops
-@cp httpd.conf-ops httpd.conf-ops.fixed
@if [ true -o -x /usr/local/libexec/apache/libphp5.so ]; then \
sed -i "" -e 's/php4/php5/g' httpd.conf-ops.fixed; \
echo "Updated httpd.conf-ops for php5"; \
fi
install-dirs:
-mkdir -p $(INSTALL_TOPDIR)/www
control-install: httpd.conf-ops
#
# Well, this is awkward. Make sure we don't try to install anything from
# a dev tree both because it doesn't make any sense and because it would
# clobber the "real" version.
#
ifeq ($(TBROOT),/usr/testbed)
#
# XXX another woeful hack. There appears to be a well-documented problem
# with Apache and PHP4, where loading PHP with certain extensions will cause
# Apache to crash immediately. However, if you start it without PHP and then
# use apachectl to restart it *with* PHP, all is well. Go figure...
# We install this script which accomodates that...ahem, "behavior."
# Since we have only seen this on FBSD7, we only do it there.
#
# Note that we install apache-emulab as apache.sh to be consistant with
# with what {boss,ops}-install expect.
#
install-scripts: apache-emulab
ifeq ($(SCRIPT_HACK),1)
@if [ -f /usr/local/etc/rc.d/apache -a ! -f /usr/local/etc/rc.d/.apache.real ]; then \
mv /usr/local/etc/rc.d/apache /usr/local/etc/rc.d/.apache.real; \
fi
$(INSTALL) -m 755 $(SRCDIR)/apache-emulab /usr/local/etc/rc.d/apache.sh
endif
ifeq ($(APACHE_VERSION),1.3)
install: install-dirs install-scripts httpd.conf.fixed
$(INSTALL_DATA) httpd.conf.fixed $(INSTALL_APACHE_CONFIG)/httpd.conf
control-install: install-dirs install-scripts httpd.conf-ops.fixed
$(INSTALL_DATA) httpd.conf-ops.fixed $(INSTALL_APACHE_CONFIG)/httpd.conf
else
install: install-dirs install-scripts httpd.conf pgeni-install
$(INSTALL_DATA) httpd.conf $(INSTALL_APACHE_CONFIG)/httpd.conf
install-utah-nets:
$(INSTALL_DATA) $(SRCDIR)/utah-nets.conf \
$(INSTALL_APACHE_CONFIG)/utah-nets.conf
control-install: install-dirs install-scripts httpd.conf-ops
$(INSTALL_DATA) httpd.conf-ops $(INSTALL_APACHE_CONFIG)/httpd.conf
pgeni-install: $(CONFIG_GENI)
ifeq ($(PGENISUPPORT),1)
$(INSTALL_DATA) httpd-geni.conf $(INSTALL_APACHE_CONFIG)/httpd-geni.conf
endif
utah: httpd.conf.utah httpd.conf-ops.utah
endif
install-php-ini: php.ini
$(INSTALL_DATA) php.ini $(INSTALL_PHP_CONFIG)/php.ini
else
install-scripts install control-install:
@echo "Cannot install Apache config in dev tree"
endif
clean:
rm -f $(CONFIG_FILES) *.fixed php.ini
#!/bin/sh
# PROVIDE: apache
# REQUIRE: DAEMON
# BEFORE: LOGIN
# KEYWORD: shutdown
# if real apache startup file hasn't been moved, we do nothing
if [ -f /usr/local/etc/rc.d/apache -o ! -f /usr/local/etc/rc.d/.apache.real ]
then
return 0
fi
ARGS=$*
CFFILE=/usr/local/etc/apache/httpd.conf
command=/usr/local/sbin/httpd
pidfile=/var/run/httpd.pid
. /etc/rc.subr
#
# It seems to be well documented that some combinations of apache and PHP
# extensions result in immediate crash of the server. There is also a
# work around that involves "apachectl restart". So if apache fails to
# start up, we enact the hack.
#
case $1 in
*start)
# (re)start it
/usr/local/etc/rc.d/.apache.real $ARGS
# give it time to crash
sleep 2
# still running? all done
rc_pid=$(check_pidfile $pidfile $command)
if [ -n "$rc_pid" ]; then
return 0
fi
# otherwise tweak the config file and start again
echo "Apache did not start; trying PHP restart hack..."
rm -f $CFFILE.orig
sed -i .orig -e '/^LoadModule php4_module/s/^/#/' -e '/^AddModule mod_php4.c/s/^/#/' $CFFILE || return 1
/usr/local/etc/rc.d/.apache.real $ARGS
sleep 2
# still not running? we have bigger problems
rc_pid=$(check_pidfile $pidfile $command)
if [ -z "$rc_pid" ]; then
echo "PHP restart hack failed, exiting..."
mv $CFFILE.orig $CFFILE
return 1
fi
# otherwise restore config and use apachectl to restart
mv $CFFILE.orig $CFFILE
/usr/local/sbin/apachectl restart
;;
*)
/usr/local/etc/rc.d/.apache.real $ARGS
;;
esac
return $?
##
## httpd.conf -- Apache HTTP server configuration file
##
##
## This file is intended for use by sites running the emulab software. It
## was installed by the testbed installation process.
##
#
# Based upon the NCSA server configuration files originally by Rob McCool.
#
# This is the main Apache server configuration file. It contains the
# configuration directives that give the server its instructions.
# See <URL:http://httpd.apache.org/docs/> for detailed information about
# the directives.
#
# Do NOT simply read the instructions in here without understanding
# what they do. They're here only as hints or reminders. If you are unsure
# consult the online docs. You have been warned.
#
# After this file is processed, the server will look for and process
# /usr/local/etc/apache/srm.conf and then /usr/local/etc/apache/access.conf
# unless you have overridden these with ResourceConfig and/or
# AccessConfig directives here.
#
# The configuration directives are grouped into three basic sections:
# 1. Directives that control the operation of the Apache server process as a
# whole (the 'global environment').
# 2. Directives that define the parameters of the 'main' or 'default' server,
# which responds to requests that aren't handled by a virtual host.
# These directives also provide default values for the settings
# of all virtual hosts.
# 3. Settings for virtual hosts, which allow Web requests to be sent to
# different IP addresses or hostnames and have them handled by the
# same Apache server process.
#
# Configuration and logfile names: If the filenames you specify for many
# of the server's control files begin with "/" (or "drive:/" for Win32), the
# server will use that explicit path. If the filenames do *not* begin
# with "/", the value of ServerRoot is prepended -- so "logs/foo.log"
# with ServerRoot set to "/usr/local/apache" will be interpreted by the
# server as "/usr/local/apache/logs/foo.log".
#
### Section 1: Global Environment
#
# The directives in this section affect the overall operation of Apache,
# such as the number of concurrent requests it can handle or where it
# can find its configuration files.
#
#
# ServerType is either inetd, or standalone. Inetd mode is only supported on
# Unix platforms.
#
ServerType standalone
#
# ServerRoot: The top of the directory tree under which the server's
# configuration, error, and log files are kept.
#
# NOTE! If you intend to place this on an NFS (or otherwise network)
# mounted filesystem then please read the LockFile documentation
# (available at <URL:http://www.apache.org/docs/mod/core.html#lockfile>);
# you will save yourself a lot of trouble.
#
ServerRoot "/usr/local"
#
# The LockFile directive sets the path to the lockfile used when Apache
# is compiled with either USE_FCNTL_SERIALIZED_ACCEPT or
# USE_FLOCK_SERIALIZED_ACCEPT. This directive should normally be left at
# its default value. The main reason for changing it is if the logs
# directory is NFS mounted, since the lockfile MUST BE STORED ON A LOCAL
# DISK. The PID of the main server process is automatically appended to
# the filename.
#
#LockFile /var/run/httpd.lock
#
# PidFile: The file in which the server should record its process
# identification number when it starts.
#
PidFile /var/run/httpd.pid
#
# ScoreBoardFile: File used to store internal server process information.
# Not all architectures require this. But if yours does (you'll know because
# this file will be created when you run Apache) then you *must* ensure that
# no two invocations of Apache share the same scoreboard file.
#
ScoreBoardFile /var/run/httpd.scoreboard
#
# In the standard configuration, the server will process httpd.conf (this
# file, specified by the -f command line option), srm.conf, and access.conf
# in that order. The latter two files are now distributed empty, as it is
# recommended that all directives be kept in a single file for simplicity.
# The commented-out values below are the built-in defaults. You can have the
# server ignore these files altogether by using "/dev/null" (for Unix) or
# "nul" (for Win32) for the arguments to the directives.
#
ResourceConfig /dev/null
AccessConfig /dev/null
#
# Timeout: The number of seconds before receives and sends time out.
#
Timeout 30
#
# KeepAlive: Whether or not to allow persistent connections (more than
# one request per connection). Set to "Off" to deactivate.
#
KeepAlive On
#
# MaxKeepAliveRequests: The maximum number of requests to allow
# during a persistent connection. Set to 0 to allow an unlimited amount.
# We recommend you leave this number high, for maximum performance.
#
MaxKeepAliveRequests 100
#
# KeepAliveTimeout: Number of seconds to wait for the next request from the
# same client on the same connection.
#
KeepAliveTimeout 15
#
# Server-pool size regulation. Rather than making you guess how many
# server processes you need, Apache dynamically adapts to the load it
# sees --- that is, it tries to maintain enough server processes to
# handle the current load, plus a few spare servers to handle transient
# load spikes (e.g., multiple simultaneous requests from a single
# Netscape browser).
#
# It does this by periodically checking how many servers are waiting
# for a request. If there are fewer than MinSpareServers, it creates
# a new spare. If there are more than MaxSpareServers, some of the
# spares die off. The default values are probably OK for most sites.
#
MinSpareServers 10
MaxSpareServers 30
#
# Number of servers to start initially --- should be a reasonable ballpark
# figure.
#
StartServers 10
#
# Limit on total number of servers running, i.e., limit on the number
# of clients who can simultaneously connect --- if this limit is ever
# reached, clients will be LOCKED OUT, so it should NOT BE SET TOO LOW.
# It is intended mainly as a brake to keep a runaway server from taking
# the system with it as it spirals down...
#
MaxClients 150
#
# MaxRequestsPerChild: the number of requests each child process is
# allowed to process before the child dies. The child will exit so
# as to avoid problems after prolonged use when Apache (and maybe the
# libraries it uses) leak memory or other resources. On most systems, this
# isn't really needed, but a few (such as Solaris) do have notable leaks
# in the libraries. For these platforms, set to something like 10000
# or so; a setting of 0 means unlimited.
#
# NOTE: This value does not include keepalive requests after the initial
# request per connection. For example, if a child process handles
# an initial request and 10 subsequent "keptalive" requests, it
# would only count as 1 request towards this limit.
#
MaxRequestsPerChild 0
#
# Listen: Allows you to bind Apache to specific IP addresses and/or
# ports, instead of the default. See also the <VirtualHost>
# directive.
#
#Listen 3000
#Listen 12.34.56.78:80
#
# BindAddress: You can support virtual hosts with this option. This directive
# is used to tell the server which IP address to listen to. It can either
# contain "*", an IP address, or a fully qualified Internet domain name.
# See also the <VirtualHost> and Listen directives.
#
#BindAddress *
#
# Dynamic Shared Object (DSO) Support
#
# To be able to use the functionality of a module which was built as a DSO you
# have to place corresponding `LoadModule' lines at this location so the
# directives contained in it are actually available _before_ they are used.
# Please read the file http://httpd.apache.org/docs/dso.html for more
# details about the DSO mechanism and run `httpd -l' for the list of already
# built-in (statically linked and thus always available) modules in your httpd
# binary.
#
# Note: The order in which modules are loaded is important. Don't change
# the order below without expert advice.
#
# Example:
# LoadModule foo_module libexec/mod_foo.so
LoadModule mmap_static_module libexec/apache/mod_mmap_static.so
LoadModule vhost_alias_module libexec/apache/mod_vhost_alias.so
LoadModule env_module libexec/apache/mod_env.so
LoadModule config_log_module libexec/apache/mod_log_config.so
LoadModule mime_magic_module libexec/apache/mod_mime_magic.so
LoadModule mime_module libexec/apache/mod_mime.so
LoadModule negotiation_module libexec/apache/mod_negotiation.so
LoadModule status_module libexec/apache/mod_status.so
LoadModule info_module libexec/apache/mod_info.so
LoadModule includes_module libexec/apache/mod_include.so
LoadModule autoindex_module libexec/apache/mod_autoindex.so
LoadModule dir_module libexec/apache/mod_dir.so
LoadModule cgi_module libexec/apache/mod_cgi.so
LoadModule asis_module libexec/apache/mod_asis.so
LoadModule imap_module libexec/apache/mod_imap.so
LoadModule action_module libexec/apache/mod_actions.so
LoadModule speling_module libexec/apache/mod_speling.so
LoadModule userdir_module libexec/apache/mod_userdir.so
LoadModule alias_module libexec/apache/mod_alias.so
LoadModule rewrite_module libexec/apache/mod_rewrite.so
LoadModule access_module libexec/apache/mod_access.so
LoadModule auth_module libexec/apache/mod_auth.so
LoadModule anon_auth_module libexec/apache/mod_auth_anon.so
LoadModule db_auth_module libexec/apache/mod_auth_db.so
LoadModule digest_module libexec/apache/mod_digest.so
LoadModule proxy_module libexec/apache/libproxy.so
LoadModule cern_meta_module libexec/apache/mod_cern_meta.so
LoadModule expires_module libexec/apache/mod_expires.so
LoadModule headers_module libexec/apache/mod_headers.so
LoadModule usertrack_module libexec/apache/mod_usertrack.so
LoadModule log_forensic_module libexec/apache/mod_log_forensic.so
LoadModule unique_id_module libexec/apache/mod_unique_id.so
LoadModule setenvif_module libexec/apache/mod_setenvif.so
LoadModule php4_module libexec/apache/libphp4.so
<IfDefine SSL>
LoadModule ssl_module libexec/apache/libssl.so
</IfDefine>
# Reconstruction of the complete module list from all available modules
# (static and shared ones) to achieve correct module execution order.
# [WHENEVER YOU CHANGE THE LOADMODULE SECTION ABOVE UPDATE THIS, TOO]
ClearModuleList
AddModule mod_mmap_static.c
AddModule mod_vhost_alias.c
AddModule mod_env.c
AddModule mod_log_config.c
AddModule mod_mime_magic.c
AddModule mod_mime.c
AddModule mod_negotiation.c
AddModule mod_status.c
AddModule mod_info.c
AddModule mod_include.c
AddModule mod_autoindex.c
AddModule mod_dir.c
AddModule mod_cgi.c
AddModule mod_asis.c
AddModule mod_imap.c
AddModule mod_actions.c
AddModule mod_speling.c
AddModule mod_userdir.c
AddModule mod_alias.c
AddModule mod_rewrite.c
AddModule mod_access.c
AddModule mod_auth.c
AddModule mod_auth_anon.c
AddModule mod_auth_db.c
AddModule mod_digest.c
AddModule mod_proxy.c
AddModule mod_cern_meta.c
AddModule mod_expires.c
AddModule mod_headers.c
AddModule mod_usertrack.c
AddModule mod_log_forensic.c
AddModule mod_unique_id.c
AddModule mod_so.c
AddModule mod_setenvif.c
AddModule mod_php4.c
<IfDefine SSL>
AddModule mod_ssl.c
</IfDefine>
#
# ExtendedStatus controls whether Apache will generate "full" status
# information (ExtendedStatus On) or just basic information (ExtendedStatus
# Off) when the "server-status" handler is called. The default is Off.
#
#ExtendedStatus On
### Section 2: 'Main' server configuration
#
# The directives in this section set up the values used by the 'main'
# server, which responds to any requests that aren't handled by a
# <VirtualHost> definition. These values also provide defaults for
# any <VirtualHost> containers you may define later in the file.
#
# All of these directives may appear inside <VirtualHost> containers,
# in which case these default settings will be overridden for the
# virtual host being defined.
#
#
# If your ServerType directive (set earlier in the 'Global Environment'
# section) is set to "inetd", the next few directives don't have any
# effect since their settings are defined by the inetd configuration.
# Skip ahead to the ServerAdmin directive.
#
#
# Port: The port to which the standalone server listens. For
# ports < 1023, you will need httpd to be run as root initially.
#
Port 80
##
## SSL Support
##
## When we also provide SSL we have to listen to the
## standard HTTP port (see above) and to the HTTPS port
##
<IfDefine SSL>
Listen 80
Listen 443
</IfDefine>
#
# If you wish httpd to run as a different user or group, you must run
# httpd as root initially and it will switch.
#
# User/Group: The name (or #number) of the user/group to run httpd as.
# . On SCO (ODT 3) use "User nouser" and "Group nogroup".
# . On HPUX you may not be able to use shared memory as nobody, and the
# suggested workaround is to create a user www and use that user.
# NOTE that some kernels refuse to setgid(Group) or semctl(IPC_SET)
# when the value of (unsigned)Group is above 60000;
# don't use Group "#-1" on these systems!
#
User nobody
Group nobody
#
# ServerAdmin: Your address, where problems with the server should be
# e-mailed. This address appears on some server-generated pages, such
# as error documents.
#
ServerAdmin @TBOPSEMAIL_NOSLASH@
#
# ServerName allows you to set a host name which is sent back to clients for
# your server if it's different than the one the program would get (i.e., use
# "www" instead of the host's real name).
#
# Note: You cannot just invent host names and hope they work. The name you
# define here must be a valid DNS name for your host. If you don't understand
# this, ask your network administrator.
# If your host doesn't have a registered DNS name, enter its IP address here.
# You will have to access it by its address (e.g., http://123.45.67.89/)
# anyway, and this will make redirections work in a sensible way.
#
# 127.0.0.1 is the TCP/IP local loop-back address, often named localhost. Your
# machine always knows itself by this address. If you use Apache strictly for
# local testing and development, you may use 127.0.0.1 as the server name.
#
#ServerName www.example.com
#
# Turn off the TRACE and TRACK debug methods. These have apparently
# been shown to support other XSS vulnerabilities (caught by nessus)
#
RewriteEngine on
RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)
RewriteRule .* - [F]
#
# DocumentRoot: The directory out of which you will serve your
# documents. By default, all requests are taken from this directory, but
# symbolic links and aliases may be used to point to other locations.
#
DocumentRoot "/usr/local/www/data"
#
# Each directory to which Apache has access, can be configured with respect
# to which services and features are allowed and/or disabled in that
# directory (and its subdirectories).
#
# First, we configure the "default" to be a very restrictive set of
# permissions.
#
<Directory />
Options None
AllowOverride None
Order deny,allow
Deny from all
</Directory>
#
# Note that from this point forward you must specifically allow
# particular features to be enabled - so if something's not working as
# you might expect, make sure that you have specifically enabled it
# below.
#
#
# This should be changed to whatever you set DocumentRoot to.
#
<Directory "/usr/local/www/data">
#
# This may also be "None", "All", or any combination of "Indexes",
# "Includes", "FollowSymLinks", "ExecCGI", or "MultiViews".
#
# Note that "MultiViews" must be named *explicitly* --- "Options All"
# doesn't give it to you.
#
Options All +MultiViews -Indexes
#
# This controls which options the .htaccess files in directories can
# override. Can also be "All", or any combination of "Options", "FileInfo",
# "AuthConfig", and "Limit"
#
AllowOverride All
#
# Controls who can get stuff from this server.
#
Order allow,deny
Allow from all
</Directory>
#
# UserDir: The name of the directory which is appended onto a user's home
# directory if a ~user request is received.
#
<IfModule mod_userdir.c>
UserDir public_html
</IfModule>
#
# Twiki-related entries
#
<Directory "/usr/local/www/data/twiki/bin">
Options +ExecCGI
SetHandler cgi-script
Allow from all
SetEnv USER "www"
</Directory>
<Directory "/usr/local/www/data/twiki/pub">
Options FollowSymLinks +Includes
AllowOverride None
Allow from all
</Directory>
<Directory /usr/local/www/data/twiki/data>
Options None
AllowOverride None
Order deny,allow
Deny from all
</Directory>
<Directory /usr/local/www/data/twiki/lib>
Options None
AllowOverride None
Order deny,allow
Deny from all
</Directory>
<Directory /usr/local/www/data/twiki/templates>
Options None
AllowOverride None
Order deny,allow
Deny from all
</Directory>
#
# Flyspray
#
<Directory /usr/local/www/data/flyspray>
Options FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
SSLRequireSSL
Satisfy all
</Directory>
#
# CVSWEB
#
<Directory /usr/testbed/www/cvsweb>
Options +ExecCGI
SetHandler cgi-script
SetEnv USER "nobody"
AllowOverride None
Order allow,deny
Allow from all
</Directory>
#
# Jeti
#
<Directory /usr/local/www/data/jeti>
Options None
AllowOverride None
Order allow,deny
Allow from all
</Directory>
<Directory /usr/testbed/www/jabber>
Options None
AllowOverride None
Order allow,deny
Allow from all
</Directory>
#
# Control access to UserDir directories. The following is an example
# for a site where these directories are restricted to read-only.
#
#<Directory /home/*/public_html>
# AllowOverride FileInfo AuthConfig Limit
# Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
# <Limit GET POST OPTIONS PROPFIND>
# Order allow,deny
# Allow from all
# </Limit>
# <LimitExcept GET POST OPTIONS PROPFIND>
# Order deny,allow
# Deny from all
# </LimitExcept>
#</Directory>
#
# DirectoryIndex: Name of the file or files to use as a pre-written HTML
# directory index. Separate multiple entries with spaces.
#
<IfModule mod_dir.c>
<IfModule mod_php3.c>
<IfModule mod_php4.c>
DirectoryIndex index.php index.php3 index.html
</IfModule>
<IfModule !mod_php4.c>
DirectoryIndex index.php3 index.html
</IfModule>
</IfModule>
<IfModule !mod_php3.c>
<IfModule mod_php4.c>
DirectoryIndex index.php index.html
</IfModule>
<IfModule !mod_php4.c>
DirectoryIndex index.html
</IfModule>
</IfModule>
</IfModule>
#
# AccessFileName: The name of the file to look for in each directory
# for access control information.
#
AccessFileName .htaccess
#
# The following lines prevent .htaccess files from being viewed by
# Web clients. Since .htaccess files often contain authorization
# information, access is disallowed for security reasons. Comment
# these lines out if you want Web visitors to see the contents of
# .htaccess files. If you change the AccessFileName directive above,
# be sure to make the corresponding changes here.
#
# Also, folks tend to use names such as .htpasswd for password
# files, so this will protect those as well.
#
<Files ~ "^\.ht">
Order allow,deny
Deny from all
Satisfy All
</Files>
#
# CacheNegotiatedDocs: By default, Apache sends "Pragma: no-cache" with each
# document that was negotiated on the basis of content. This asks proxy
# servers not to cache the document. Uncommenting the following line disables
# this behavior, and proxies will be allowed to cache the documents.
#
#CacheNegotiatedDocs
#
# UseCanonicalName: (new for 1.3) With this setting turned on, whenever
# Apache needs to construct a self-referencing URL (a URL that refers back
# to the server the response is coming from) it will use ServerName and
# Port to form a "canonical" name. With this setting off, Apache will
# use the hostname:port that the client supplied, when possible. This
# also affects SERVER_NAME and SERVER_PORT in CGI scripts.
#
UseCanonicalName On
#
# TypesConfig describes where the mime.types file (or equivalent) is
# to be found.
#
<IfModule mod_mime.c>
TypesConfig /usr/local/etc/apache/mime.types
</IfModule>
#
# DefaultType is the default MIME type the server will use for a document
# if it cannot otherwise determine one, such as from filename extensions.
# If your server contains mostly text or HTML documents, "text/plain" is
# a good value. If most of your content is binary, such as applications
# or images, you may want to use "application/octet-stream" instead to
# keep browsers from trying to display binary files as though they are
# text.
#
DefaultType text/plain
#
# The mod_mime_magic module allows the server to use various hints from the
# contents of the file itself to determine its type. The MIMEMagicFile
# directive tells the module where the hint definitions are located.
# mod_mime_magic is not part of the default server (you have to add
# it yourself with a LoadModule [see the DSO paragraph in the 'Global
# Environment' section], or recompile the server and include mod_mime_magic
# as part of the configuration), so it's enclosed in an <IfModule> container.
# This means that the MIMEMagicFile directive will only be processed if the
# module is part of the server.
#
<IfModule mod_mime_magic.c>
MIMEMagicFile /usr/local/etc/apache/magic
</IfModule>
#
# HostnameLookups: Log the names of clients or just their IP addresses
# e.g., www.apache.org (on) or 204.62.129.132 (off).
# The default is off because it'd be overall better for the net if people
# had to knowingly turn this feature on, since enabling it means that
# each client request will result in AT LEAST one lookup request to the
# nameserver.
#
HostnameLookups Off
#
# ErrorLog: The location of the error log file.
# If you do not specify an ErrorLog directive within a <VirtualHost>
# container, error messages relating to that virtual host will be
# logged here. If you *do* define an error logfile for a <VirtualHost>
# container, that host's errors will be logged there and not here.
#
ErrorLog /var/log/httpd-error.log
#
# LogLevel: Control the number of messages logged to the error_log.
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
#
LogLevel warn
#
# The following directives define some format nicknames for use with
# a CustomLog directive (see below).
#
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
#
# The location and format of the access logfile (Common Logfile Format).
# If you do not define any access logfiles within a <VirtualHost>
# container, they will be logged here. Contrariwise, if you *do*
# define per-<VirtualHost> access logfiles, transactions will be
# logged therein and *not* in this file.
#
#CustomLog /var/log/httpd-access.log common
#
# If you would like to have agent and referer logfiles, uncomment the
# following directives.
#
#CustomLog /var/log/httpd-referer.log referer
#CustomLog /var/log/httpd-agent.log agent
#
# If you prefer a single logfile with access, agent, and referer information
# (Combined Logfile Format) you can use the following directive.
#
CustomLog /var/log/httpd-access.log combined
#
# Optionally add a line containing the server version and virtual host
# name to server-generated pages (error documents, FTP directory listings,
# mod_status and mod_info output etc., but not CGI generated documents).
# Set to "EMail" to also include a mailto: link to the ServerAdmin.
# Set to one of: On | Off | EMail
#
ServerSignature On
# EBCDIC configuration:
# (only for mainframes using the EBCDIC codeset, currently one of:
# Fujitsu-Siemens' BS2000/OSD, IBM's OS/390 and IBM's TPF)!!
# The following default configuration assumes that "text files"
# are stored in EBCDIC (so that you can operate on them using the
# normal POSIX tools like grep and sort) while "binary files" are
# stored with identical octets as on an ASCII machine.
#
# The directives are evaluated in configuration file order, with
# the EBCDICConvert directives applied before EBCDICConvertByType.
#
# If you want to have ASCII HTML documents and EBCDIC HTML documents
# at the same time, you can use the file extension to force
# conversion off for the ASCII documents:
# > AddType text/html .ahtml
# > EBCDICConvert Off=InOut .ahtml
#
# EBCDICConvertByType On=InOut text/* message/* multipart/*
# EBCDICConvertByType On=In application/x-www-form-urlencoded
# EBCDICConvertByType On=InOut application/postscript model/vrml
# EBCDICConvertByType Off=InOut */*
#
# Aliases: Add here as many aliases as you need (with no limit). The format is
# Alias fakename realname
#
<IfModule mod_alias.c>
#
# Note that if you include a trailing / on fakename then the server will
# require it to be present in the URL. So "/icons" isn't aliased in this
# example, only "/icons/". If the fakename is slash-terminated, then the
# realname must also be slash terminated, and if the fakename omits the
# trailing slash, the realname must also omit it.
#
Alias /icons/ "/usr/local/www/icons/"
<Directory "/usr/local/www/icons">
Options Indexes MultiViews
AllowOverride None
Order allow,deny
Allow from all
</Directory>
# This Alias will project the on-line documentation tree under /manual/
# even if you change the DocumentRoot. Comment it if you don't want to
# provide access to the on-line documentation.
#
# Alias /manual/ "/usr/local/share/doc/apache/"
# <Directory "/usr/local/share/doc/apache">
# Options Indexes FollowSymlinks MultiViews
# AllowOverride None
# Order allow,deny
# Allow from all
# </Directory>
#
# ScriptAlias: This controls which directories contain server scripts.
# ScriptAliases are essentially the same as Aliases, except that
# documents in the realname directory are treated as applications and
# run by the server when requested rather than as documents sent to the client.
# The same rules about trailing "/" apply to ScriptAlias directives as to
# Alias.
#
ScriptAlias /cgi-bin/ "/usr/local/www/cgi-bin/"
#
# "/usr/local/www/cgi-bin" should be changed to whatever your ScriptAliased
# CGI directory exists, if you have that configured.
#
<Directory "/usr/local/www">
Options SymLinksIfOwnerMatch
</Directory>
<Directory "/usr/local/www/cgi-bin">
AllowOverride None
Options None
Order allow,deny
Allow from all
</Directory>
ScriptAlias /mailman "/usr/local/mailman/cgi-bin"
Alias /pipermail "/usr/local/mailman/archives/public"
<Directory "/usr/local/mailman/cgi-bin">
AllowOverride None
Options None
Order allow,deny
Allow from all
</Directory>
ScriptAlias /cvsweb/ "/usr/testbed/www/cvsweb/"
Alias /jabber/ "/usr/testbed/www/jabber/"
</IfModule>
# End of aliases.
#
# Redirect allows you to tell clients about documents which used to exist in
# your server's namespace, but do not anymore. This allows you to tell the
# clients where to look for the relocated document.
# Format: Redirect old-URI new-URL
#
#
# Directives controlling the display of server-generated directory listings.
#
<IfModule mod_autoindex.c>
#
# FancyIndexing is whether you want fancy directory indexing or standard
#
IndexOptions FancyIndexing
#
# AddIcon* directives tell the server which icon to show for different
# files or filename extensions. These are only displayed for
# FancyIndexed directories.
#
AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip
AddIconByType (TXT,/icons/text.gif) text/*
AddIconByType (IMG,/icons/image2.gif) image/*
AddIconByType (SND,/icons/sound2.gif) audio/*
AddIconByType (VID,/icons/movie.gif) video/*
AddIcon /icons/binary.gif .bin .exe
AddIcon /icons/binhex.gif .hqx
AddIcon /icons/tar.gif .tar
AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv
AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip
AddIcon /icons/a.gif .ps .ai .eps
AddIcon /icons/layout.gif .html .shtml .htm .pdf
AddIcon /icons/text.gif .txt
AddIcon /icons/c.gif .c
AddIcon /icons/p.gif .pl .py
AddIcon /icons/f.gif .for
AddIcon /icons/dvi.gif .dvi
AddIcon /icons/uuencoded.gif .uu
AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl
AddIcon /icons/tex.gif .tex
AddIcon /icons/bomb.gif core
AddIcon /icons/back.gif ..
AddIcon /icons/hand.right.gif README
AddIcon /icons/folder.gif ^^DIRECTORY^^
AddIcon /icons/blank.gif ^^BLANKICON^^
#
# DefaultIcon is which icon to show for files which do not have an icon
# explicitly set.
#
DefaultIcon /icons/unknown.gif
#
# AddDescription allows you to place a short description after a file in
# server-generated indexes. These are only displayed for FancyIndexed
# directories.
# Format: AddDescription "description" filename
#
#AddDescription "GZIP compressed document" .gz
#AddDescription "tar archive" .tar
#AddDescription "GZIP compressed tar archive" .tgz
#
# ReadmeName is the name of the README file the server will look for by
# default, and append to directory listings.
#
# HeaderName is the name of a file which should be prepended to
# directory indexes.
#
ReadmeName README
HeaderName HEADER
#
# IndexIgnore is a set of filenames which directory indexing should ignore
# and not include in the listing. Shell-style wildcarding is permitted.
#
IndexIgnore .??* *~ *# HEADER* README* RCS CVS *,v *,t
</IfModule>
# End of indexing directives.
#
# Document types.
#
<IfModule mod_mime.c>
#
# AddLanguage allows you to specify the language of a document. You can
# then use content negotiation to give a browser a file in a language
# it can understand.
#
# Note 1: The suffix does not have to be the same as the language
# keyword --- those with documents in Polish (whose net-standard
# language code is pl) may wish to use "AddLanguage pl .po" to
# avoid the ambiguity with the common suffix for perl scripts.
#
# Note 2: The example entries below illustrate that in quite
# some cases the two character 'Language' abbreviation is not
# identical to the two character 'Country' code for its country,
# E.g. 'Danmark/dk' versus 'Danish/da'.
#
# Note 3: In the case of 'ltz' we violate the RFC by using a three char
# specifier. But there is 'work in progress' to fix this and get
# the reference data for rfc1766 cleaned up.
#
# Danish (da) - Dutch (nl) - English (en) - Estonian (ee)
# French (fr) - German (de) - Greek-Modern (el)
# Italian (it) - Korean (kr) - Norwegian (no) - Norwegian Nynorsk (nn)
# Portugese (pt) - Luxembourgeois* (ltz)
# Spanish (es) - Swedish (sv) - Catalan (ca) - Czech(cs)
# Polish (pl) - Brazilian Portuguese (pt-br) - Japanese (ja)
# Russian (ru)
#
AddLanguage da .dk
AddLanguage nl .nl
AddLanguage en .en
AddLanguage et .ee
AddLanguage fr .fr
AddLanguage de .de
AddLanguage el .el
AddLanguage he .he
AddCharset ISO-8859-8 .iso8859-8
AddLanguage it .it
AddLanguage ja .ja
AddCharset ISO-2022-JP .jis
AddLanguage kr .kr
AddCharset ISO-2022-KR .iso-kr
AddLanguage nn .nn
AddLanguage no .no
AddLanguage pl .po
AddCharset ISO-8859-2 .iso-pl
AddLanguage pt .pt
AddLanguage pt-br .pt-br
AddLanguage ltz .lu
AddLanguage ca .ca
AddLanguage es .es
AddLanguage sv .sv
AddLanguage cs .cz .cs
AddLanguage ru .ru
AddLanguage zh-TW .zh-tw
AddCharset Big5 .Big5 .big5
AddCharset WINDOWS-1251 .cp-1251
AddCharset CP866 .cp866
AddCharset ISO-8859-5 .iso-ru
AddCharset KOI8-R .koi8-r
AddCharset UCS-2 .ucs2
AddCharset UCS-4 .ucs4
AddCharset UTF-8 .utf8
# LanguagePriority allows you to give precedence to some languages
# in case of a tie during content negotiation.
#
# Just list the languages in decreasing order of preference. We have
# more or less alphabetized them here. You probably want to change this.
#
<IfModule mod_negotiation.c>
LanguagePriority en da nl et fr de el it ja kr no pl pt pt-br ru ltz ca es sv tw
</IfModule>
<IfModule mod_php3.c>
AddType application/x-httpd-php3 .php3
AddType application/x-httpd-php3-source .php3s
</IfModule>
<IfModule mod_php4.c>
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps
</IfModule>
#
# AddType allows you to tweak mime.types without actually editing it, or to
# make certain files to be certain types.
#
AddType application/x-tar .tgz
#
# AddEncoding allows you to have certain browsers uncompress
# information on the fly. Note: Not all browsers support this.
# Despite the name similarity, the following Add* directives have nothing
# to do with the FancyIndexing customization directives above.
#
AddEncoding x-compress .Z
AddEncoding x-gzip .gz .tgz
#
# If the AddEncoding directives above are commented-out, then you
# probably should define those extensions to indicate media types:
#
#AddType application/x-compress .Z
#AddType application/x-gzip .gz .tgz
#
# AddHandler allows you to map certain file extensions to "handlers",
# actions unrelated to filetype. These can be either built into the server
# or added with the Action command (see below)
#
# If you want to use server side includes, or CGI outside
# ScriptAliased directories, uncomment the following lines.
#
# To use CGI scripts:
#
AddHandler cgi-script .cgi
#
# To use server-parsed HTML files
#
AddType text/html .shtml
AddHandler server-parsed .shtml
#
# Uncomment the following line to enable Apache's send-asis HTTP file
# feature
#
#AddHandler send-as-is asis
#
# If you wish to use server-parsed imagemap files, use
#
#AddHandler imap-file map
#
# To enable type maps, you might want to use
#
#AddHandler type-map var
</IfModule>
# End of document types.
#
# Action lets you define media types that will execute a script whenever
# a matching file is called. This eliminates the need for repeated URL
# pathnames for oft-used CGI file processors.
# Format: Action media/type /cgi-script/location
# Format: Action handler-name /cgi-script/location
#
#
# MetaDir: specifies the name of the directory in which Apache can find
# meta information files. These files contain additional HTTP headers
# to include when sending the document
#
#MetaDir .web
#
# MetaSuffix: specifies the file name suffix for the file containing the
# meta information.
#
#MetaSuffix .meta
#
# Customizable error response (Apache style)
# these come in three flavors
#
# 1) plain text
#ErrorDocument 500 "The server made a boo boo.
# n.b. the single leading (") marks it as text, it does not get output
#
# 2) local redirects
#ErrorDocument 404 /missing.html
# to redirect to local URL /missing.html
#ErrorDocument 404 /cgi-bin/missing_handler.pl
# N.B.: You can redirect to a script or a document using server-side-includes.
#
# 3) external redirects
#ErrorDocument 402 http://www.example.com/subscription_info.html
# N.B.: Many of the environment variables associated with the original
# request will *not* be available to such a script.
#
# Customize behaviour based on the browser
#
<IfModule mod_setenvif.c>
#
# The following directives modify normal HTTP response behavior.
# The first directive disables keepalive for Netscape 2.x and browsers that
# spoof it. There are known problems with these browser implementations.
# The second directive is for Microsoft Internet Explorer 4.0b2
# which has a broken HTTP/1.1 implementation and does not properly
# support keepalive when it is used on 301 or 302 (redirect) responses.
#
BrowserMatch "Mozilla/2" nokeepalive
BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0
#
# The following directive disables HTTP/1.1 responses to browsers which
# are in violation of the HTTP/1.0 spec by not being able to grok a
# basic 1.1 response.
#
BrowserMatch "RealPlayer 4\.0" force-response-1.0
BrowserMatch "Java/1\.0" force-response-1.0
BrowserMatch "JDK/1\.0" force-response-1.0
</IfModule>
# End of browser customization directives
#
# Allow server status reports, with the URL of http://servername/server-status
# Change the ".example.com" to match your domain to enable.
#
#<Location /server-status>
# SetHandler server-status
# Order deny,allow
# Deny from all
# Allow from .example.com
#</Location>
#
# Allow remote server configuration reports, with the URL of
# http://servername/server-info (requires that mod_info.c be loaded).
# Change the ".example.com" to match your domain to enable.
#
#<Location /server-info>
# SetHandler server-info
# Order deny,allow
# Deny from all
# Allow from .example.com
#</Location>
#
# There have been reports of people trying to abuse an old bug from pre-1.1
# days. This bug involved a CGI script distributed as a part of Apache.
# By uncommenting these lines you can redirect these attacks to a logging
# script on phf.apache.org. Or, you can record them yourself, using the script
# support/phf_abuse_log.cgi.
#
#<Location /cgi-bin/phf*>
# Deny from all
# ErrorDocument 403 http://phf.apache.org/phf_abuse_log.cgi
#</Location>
### Section 3: Virtual Hosts
#
# VirtualHost: If you want to maintain multiple domains/hostnames on your
# machine you can setup VirtualHost containers for them. Most configurations
# use only name-based virtual hosts so the server doesn't need to worry about
# IP addresses. This is indicated by the asterisks in the directives below.
#
# Please see the documentation at <URL:http://www.apache.org/docs/vhosts/>
# for further details before you try to setup virtual hosts.
#
# You may use the command line option '-S' to verify your virtual host
# configuration.
#
# Use name-based virtual hosting.
#
#NameVirtualHost *:80
#
# VirtualHost example:
# Almost any Apache directive may go into a VirtualHost container.
# The first VirtualHost section is used for requests without a known
# server name.
#
#<VirtualHost *:80>
# ServerAdmin webmaster@dummy-host.example.com
# DocumentRoot /www/docs/dummy-host.example.com
# ServerName dummy-host.example.com
# ErrorLog logs/dummy-host.example.com-error_log
# CustomLog logs/dummy-host.example.com-access_log common
#</VirtualHost>
##
## SSL Global Context
##
## All SSL configuration in this context applies both to
## the main server and all SSL-enabled virtual hosts.
##
#
# Some MIME-types for downloading Certificates and CRLs
#
<IfDefine SSL>
AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl .crl
</IfDefine>
<IfModule mod_ssl.c>
# Pass Phrase Dialog:
# Configure the pass phrase gathering process.
# The filtering dialog program (`builtin' is a internal
# terminal dialog) has to provide the pass phrase on stdout.
SSLPassPhraseDialog builtin
# Inter-Process Session Cache:
# Configure the SSL Session Cache: First either `none'
# or `dbm:/path/to/file' for the mechanism to use and
# second the expiring timeout (in seconds).
#SSLSessionCache none
#SSLSessionCache shm:/var/run/apache_ssl_scache(512000)
SSLSessionCache dbm:/var/run/apache_ssl_scache
SSLSessionCacheTimeout 300
# Semaphore:
# Configure the path to the mutual explusion semaphore the
# SSL engine uses internally for inter-process synchronization.
SSLMutex file:/var/run/apache_ssl_mutex
# Pseudo Random Number Generator (PRNG):
# Configure one or more sources to seed the PRNG of the
# SSL library. The seed data should be of good random quality.
# WARNING! On some platforms /dev/random blocks if not enough entropy
# is available. This means you then cannot use the /dev/random device
# because it would lead to very long connection times (as long as
# it requires to make more entropy available). But usually those
# platforms additionally provide a /dev/urandom device which doesn't
# block. So, if available, use this one instead. Read the mod_ssl User
# Manual for more details.
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
#SSLRandomSeed startup file:/dev/random 512
#SSLRandomSeed startup file:/dev/urandom 512
#SSLRandomSeed connect file:/dev/random 512
#SSLRandomSeed connect file:/dev/urandom 512
# Logging:
# The home of the dedicated SSL protocol logfile. Errors are
# additionally duplicated in the general error log file. Put
# this somewhere where it cannot be used for symlink attacks on
# a real server (i.e. somewhere where only root can write).
# Log levels are (ascending order: higher ones include lower ones):
# none, error, warn, info, trace, debug.
SSLLog /var/log/apache_ssl_engine_log
SSLLogLevel info
</IfModule>
<IfDefine SSL>
##
## SSL Virtual Host Context
##
<VirtualHost _default_:443>
# General setup for the virtual host
DocumentRoot "/usr/local/www/data"
ServerName @USERNODE@
ServerAdmin @TBOPSEMAIL_NOSLASH@
ErrorLog /var/log/apache_error_log
TransferLog /var/log/apache_access_log
#
# Turn off TRACE and TRACK in the SSL virt host too
#
RewriteEngine on
RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)
RewriteRule .* - [F]
# SSL Engine Switch:
# Enable/Disable SSL for this virtual host.
SSLEngine on
# SSL Cipher Suite:
# List the ciphers that the client is permitted to negotiate.
# See the mod_ssl documentation for a complete list.
#SSLCipherSuite ALL:!ADH:!EXP56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
# Server Certificate:
# Point SSLCertificateFile at a PEM encoded certificate. If
# the certificate is encrypted, then you will be prompted for a
# pass phrase. Note that a kill -HUP will prompt again. A test
# certificate can be generated with `make certificate' under
# built time. Keep in mind that if you've both a RSA and a DSA
# certificate you can configure both in parallel (to also allow
# the use of DSA ciphers, etc.)
SSLCertificateFile /usr/local/etc/apache/ssl.crt/@USERNODE@.crt
#SSLCertificateFile /usr/local/etc/apache/ssl.crt/server.crt
#SSLCertificateFile /usr/local/etc/apache/ssl.crt/server-dsa.crt
# Server Private Key:
# If the key is not combined with the certificate, use this
# directive to point at the key file. Keep in mind that if
# you've both a RSA and a DSA private key you can configure
# both in parallel (to also allow the use of DSA ciphers, etc.)
SSLCertificateKeyFile /usr/local/etc/apache/ssl.key/@USERNODE@.key
#SSLCertificateKeyFile /usr/local/etc/apache/ssl.key/server.key
#SSLCertificateKeyFile /usr/local/etc/apache/ssl.key/server.pem
#SSLCertificateKeyFile /usr/local/etc/apache/ssl.key/server-dsa.key
# Server Certificate Chain:
# Point SSLCertificateChainFile at a file containing the
# concatenation of PEM encoded CA certificates which form the
# certificate chain for the server certificate. Alternatively
# the referenced file can be the same as SSLCertificateFile
# when the CA certificates are directly appended to the server
# certificate for convinience.
#SSLCertificateChainFile /usr/local/etc/apache/ssl.crt/ca.crt
# Certificate Authority (CA):
# Set the CA certificate verification path where to find CA
# certificates for client authentication or alternatively one
# huge file containing all of them (file must be PEM encoded)
# Note: Inside SSLCACertificatePath you need hash symlinks
# to point to the certificate files. Use the provided
# Makefile to update the hash symlinks after changes.
#SSLCACertificatePath /usr/local/etc/apache/ssl.crt
#SSLCACertificateFile /usr/local/etc/apache/ssl.crt/ca-bundle.crt
# Certificate Revocation Lists (CRL):
# Set the CA revocation path where to find CA CRLs for client
# authentication or alternatively one huge file containing all
# of them (file must be PEM encoded)
# Note: Inside SSLCARevocationPath you need hash symlinks
# to point to the certificate files. Use the provided
# Makefile to update the hash symlinks after changes.
#SSLCARevocationPath /usr/local/etc/apache/ssl.crl
#SSLCARevocationFile /usr/local/etc/apache/ssl.crl/ca-bundle.crl
# Client Authentication (Type):
# Client certificate verification type and depth. Types are
# none, optional, require and optional_no_ca. Depth is a
# number which specifies how deeply to verify the certificate
# issuer chain before deciding the certificate is not valid.
#SSLVerifyClient require
#SSLVerifyDepth 10
# Access Control:
# With SSLRequire you can do per-directory access control based
# on arbitrary complex boolean expressions containing server
# variable checks and other lookup directives. The syntax is a
# mixture between C and Perl. See the mod_ssl documentation
# for more details.
#<Location />
#SSLRequire ( %{SSL_CIPHER} !~ m/^(EXP|NULL)-/ \
# and %{SSL_CLIENT_S_DN_O} eq "Snake Oil, Ltd." \
# and %{SSL_CLIENT_S_DN_OU} in {"Staff", "CA", "Dev"} \
# and %{TIME_WDAY} >= 1 and %{TIME_WDAY} <= 5 \
# and %{TIME_HOUR} >= 8 and %{TIME_HOUR} <= 20 ) \
# or %{REMOTE_ADDR} =~ m/^192\.76\.162\.[0-9]+$/
#</Location>
# SSL Engine Options:
# Set various options for the SSL engine.
# o FakeBasicAuth:
# Translate the client X.509 into a Basic Authorisation. This means that
# the standard Auth/DBMAuth methods can be used for access control. The
# user name is the `one line' version of the client's X.509 certificate.
# Note that no password is obtained from the user. Every entry in the user
# file needs this password: `xxj31ZMTZzkVA'.
# o ExportCertData:
# This exports two additional environment variables: SSL_CLIENT_CERT and
# SSL_SERVER_CERT. These contain the PEM-encoded certificates of the
# server (always existing) and the client (only existing when client
# authentication is used). This can be used to import the certificates
# into CGI scripts.
# o StdEnvVars:
# This exports the standard SSL/TLS related `SSL_*' environment variables.
# Per default this exportation is switched off for performance reasons,
# because the extraction step is an expensive operation and is usually
# useless for serving static content. So one usually enables the
# exportation for CGI and SSI requests only.
# o CompatEnvVars:
# This exports obsolete environment variables for backward compatibility
# to Apache-SSL 1.x, mod_ssl 2.0.x, Sioux 1.0 and Stronghold 2.x. Use this
# to provide compatibility to existing CGI scripts.
# o StrictRequire:
# This denies access when "SSLRequireSSL" or "SSLRequire" applied even
# under a "Satisfy any" situation, i.e. when it applies access is denied
# and no other module can change it.
# o OptRenegotiate:
# This enables optimized SSL connection renegotiation handling when SSL
# directives are used in per-directory context.
#SSLOptions +FakeBasicAuth +ExportCertData +CompatEnvVars +StrictRequire
<Files ~ "\.(cgi|shtml|phtml|php3?|php?)$">
SSLOptions +StdEnvVars
</Files>
<Directory "/usr/local/www/cgi-bin">
SSLOptions +StdEnvVars
</Directory>
# SSL Protocol Adjustments:
# The safe and default but still SSL/TLS standard compliant shutdown
# approach is that mod_ssl sends the close notify alert but doesn't wait for
# the close notify alert from client. When you need a different shutdown
# approach you can use one of the following variables:
# o ssl-unclean-shutdown:
# This forces an unclean shutdown when the connection is closed, i.e. no
# SSL close notify alert is send or allowed to received. This violates
# the SSL/TLS standard but is needed for some brain-dead browsers. Use
# this when you receive I/O errors because of the standard approach where
# mod_ssl sends the close notify alert.
# o ssl-accurate-shutdown:
# This forces an accurate shutdown when the connection is closed, i.e. a
# SSL close notify alert is send and mod_ssl waits for the close notify
# alert of the client. This is 100% SSL/TLS standard compliant, but in
# practice often causes hanging connections with brain-dead browsers. Use
# this only for browsers where you know that their SSL implementation
# works correctly.
# Notice: Most problems of broken clients are also related to the HTTP
# keep-alive facility, so you usually additionally want to disable
# keep-alive for those clients, too. Use variable "nokeepalive" for this.
# Similarly, one has to force some clients to use HTTP/1.0 to workaround
# their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and
# "force-response-1.0" for this.
SetEnvIf User-Agent ".*MSIE.*" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0
# Per-Server Logging:
# The home of a custom SSL log file. Use this when you want a
# compact non-error SSL logfile on a virtual host basis.
CustomLog /var/log/apache_ssl_request_log \
"%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
</VirtualHost>
</IfDefine>
##
## apache.conf -- Apache HTTP server configuration file
##
##
## This file is intended for use by sites running the emulab software. It
## was installed by the testbed installation process.
##
#
# Based upon the NCSA server configuration files originally by Rob McCool.
#
# This is the main Apache server configuration file. It contains the
# configuration directives that give the server its instructions.
# See <URL:http://www.apache.org/docs/> for detailed information about
# the directives.
#
# Do NOT simply read the instructions in here without understanding
# what they do. They're here only as hints or reminders. If you are unsure
# consult the online docs. You have been warned.
#
# After this file is processed, the server will look for and process
# /usr/local/conf/srm.conf and then /usr/local/conf/access.conf
# unless you have overridden these with ResourceConfig and/or
# AccessConfig directives here.
#
# The configuration directives are grouped into three basic sections:
# 1. Directives that control the operation of the Apache server process as a
# whole (the 'global environment').
# 2. Directives that define the parameters of the 'main' or 'default' server,
# which responds to requests that aren't handled by a virtual host.
# These directives also provide default values for the settings
# of all virtual hosts.
# 3. Settings for virtual hosts, which allow Web requests to be sent to
# different IP addresses or hostnames and have them handled by the
# same Apache server process.
#
# Configuration and logfile names: If the filenames you specify for many
# of the server's control files begin with "/" (or "drive:/" for Win32), the
# server will use that explicit path. If the filenames do *not* begin
# with "/", the value of ServerRoot is prepended -- so "logs/foo.log"
# with ServerRoot set to "/usr/local/apache" will be interpreted by the
# server as "/usr/local/apache/logs/foo.log".
#
### Section 1: Global Environment
#
# The directives in this section affect the overall operation of Apache,
# such as the number of concurrent requests it can handle or where it
# can find its configuration files.
#
#
# ServerType is either inetd, or standalone. Inetd mode is only supported on
# Unix platforms.
#
ServerType standalone
#
# ServerRoot: The top of the directory tree under which the server's
# configuration, error, and log files are kept.
#
# NOTE! If you intend to place this on an NFS (or otherwise network)
# mounted filesystem then please read the LockFile documentation
# (available at <URL:http://www.apache.org/docs/mod/core.html#lockfile>);
# you will save yourself a lot of trouble.
#
# Do NOT add a slash at the end of the directory path.
#
ServerRoot "/usr/local"
#
# The LockFile directive sets the path to the lockfile used when Apache
# is compiled with either USE_FCNTL_SERIALIZED_ACCEPT or
# USE_FLOCK_SERIALIZED_ACCEPT. This directive should normally be left at
# its default value. The main reason for changing it is if the logs
# directory is NFS mounted, since the lockfile MUST BE STORED ON A LOCAL
# DISK. The PID of the main server process is automatically appended to
# the filename.
#
#LockFile /var/run/apache.lock
#
# PidFile: The file in which the server should record its process
# identification number when it starts.
#
#PidFile /var/run/apache.pid
#
# ScoreBoardFile: File used to store internal server process information.
# Not all architectures require this. But if yours does (you'll know because
# this file will be created when you run Apache) then you *must* ensure that
# no two invocations of Apache share the same scoreboard file.
#
ScoreBoardFile /var/run/apache.scoreboard
#
# In the standard configuration, the server will process this file,
# srm.conf, and access.conf in that order. The latter two files are
# now distributed empty, as it is recommended that all directives
# be kept in a single file for simplicity. The commented-out values
# below are the built-in defaults. You can have the server ignore
# these files altogether by using "/dev/null" (for Unix) or
# "nul" (for Win32) for the arguments to the directives.
#
ResourceConfig /dev/null
AccessConfig /dev/null
#
# Timeout: The number of seconds before receives and sends time out.
#
Timeout 30
#
# KeepAlive: Whether or not to allow persistent connections (more than
# one request per connection). Set to "Off" to deactivate.
#
KeepAlive On
#
# MaxKeepAliveRequests: The maximum number of requests to allow
# during a persistent connection. Set to 0 to allow an unlimited amount.
# We recommend you leave this number high, for maximum performance.
#
MaxKeepAliveRequests 100
#
# KeepAliveTimeout: Number of seconds to wait for the next request from the
# same client on the same connection.
#
KeepAliveTimeout 15
#
# Server-pool size regulation. Rather than making you guess how many
# server processes you need, Apache dynamically adapts to the load it
# sees --- that is, it tries to maintain enough server processes to
# handle the current load, plus a few spare servers to handle transient
# load spikes (e.g., multiple simultaneous requests from a single
# Netscape browser).
#
# It does this by periodically checking how many servers are waiting
# for a request. If there are fewer than MinSpareServers, it creates
# a new spare. If there are more than MaxSpareServers, some of the
# spares die off. The default values are probably OK for most sites.
#
MinSpareServers 30
MaxSpareServers 45
#
# Number of servers to start initially --- should be a reasonable ballpark
# figure.
#
StartServers 30
#
# Limit on total number of servers running, i.e., limit on the number
# of clients who can simultaneously connect --- if this limit is ever
# reached, clients will be LOCKED OUT, so it should NOT BE SET TOO LOW.
# It is intended mainly as a brake to keep a runaway server from taking
# the system with it as it spirals down...
#
# Changed for testbed/mysql.
MaxClients 200
#
# MaxRequestsPerChild: the number of requests each child process is
# allowed to process before the child dies. The child will exit so
# as to avoid problems after prolonged use when Apache (and maybe the
# libraries it uses) leak memory or other resources. On most systems, this
# isn't really needed, but a few (such as Solaris) do have notable leaks
# in the libraries. For these platforms, set to something like 10000
# or so; a setting of 0 means unlimited.
#
# NOTE: This value does not include keepalive requests after the initial
# request per connection. For example, if a child process handles
# an initial request and 10 subsequent "keptalive" requests, it
# would only count as 1 request towards this limit.
#
MaxRequestsPerChild 0
#
# Listen: Allows you to bind Apache to specific IP addresses and/or
# ports, in addition to the default. See also the <VirtualHost>
# directive.
#
#Listen 3000
#Listen 12.34.56.78:80
#
# BindAddress: You can support virtual hosts with this option. This directive
# is used to tell the server which IP address to listen to. It can either
# contain "*", an IP address, or a fully qualified Internet domain name.
# See also the <VirtualHost> and Listen directives.
#
#BindAddress *
#
# Dynamic Shared Object (DSO) Support
#
# To be able to use the functionality of a module which was built as a DSO you
# have to place corresponding `LoadModule' lines at this location so the
# directives contained in it are actually available _before_ they are used.
# Please read the file README.DSO in the Apache 1.3 distribution for more
# details about the DSO mechanism and run `httpd -l' for the list of already
# built-in (statically linked and thus always available) modules in your httpd
# binary.
#
# Note: The order is which modules are loaded is important. Don't change
# the order below without expert advice.
#
# Example:
# LoadModule foo_module libexec/mod_foo.so
LoadModule vhost_alias_module libexec/apache/mod_vhost_alias.so
LoadModule env_module libexec/apache/mod_env.so
LoadModule define_module libexec/apache/mod_define.so
LoadModule config_log_module libexec/apache/mod_log_config.so
LoadModule mime_magic_module libexec/apache/mod_mime_magic.so
LoadModule mime_module libexec/apache/mod_mime.so
LoadModule negotiation_module libexec/apache/mod_negotiation.so
LoadModule status_module libexec/apache/mod_status.so
LoadModule info_module libexec/apache/mod_info.so
LoadModule includes_module libexec/apache/mod_include.so
LoadModule autoindex_module libexec/apache/mod_autoindex.so
LoadModule dir_module libexec/apache/mod_dir.so
LoadModule cgi_module libexec/apache/mod_cgi.so
LoadModule asis_module libexec/apache/mod_asis.so
LoadModule imap_module libexec/apache/mod_imap.so
LoadModule action_module libexec/apache/mod_actions.so
LoadModule speling_module libexec/apache/mod_speling.so
LoadModule userdir_module libexec/apache/mod_userdir.so
LoadModule alias_module libexec/apache/mod_alias.so
LoadModule rewrite_module libexec/apache/mod_rewrite.so
LoadModule access_module libexec/apache/mod_access.so
LoadModule auth_module libexec/apache/mod_auth.so
LoadModule anon_auth_module libexec/apache/mod_auth_anon.so
LoadModule db_auth_module libexec/apache/mod_auth_db.so
LoadModule digest_module libexec/apache/mod_digest.so
LoadModule proxy_module libexec/apache/libproxy.so
LoadModule cern_meta_module libexec/apache/mod_cern_meta.so
LoadModule expires_module libexec/apache/mod_expires.so
LoadModule headers_module libexec/apache/mod_headers.so
LoadModule usertrack_module libexec/apache/mod_usertrack.so
LoadModule unique_id_module libexec/apache/mod_unique_id.so
LoadModule setenvif_module libexec/apache/mod_setenvif.so
LoadModule php4_module libexec/apache/libphp4.so
LoadModule auth_mysql_module libexec/apache/libauth_mysql.so
<IfDefine SSL>
LoadModule ssl_module libexec/apache/libssl.so
</IfDefine>
# Reconstruction of the complete module list from all available modules
# (static and shared ones) to achieve correct module execution order.
# [WHENEVER YOU CHANGE THE LOADMODULE SECTION ABOVE UPDATE THIS, TOO]
ClearModuleList
AddModule mod_vhost_alias.c
AddModule mod_env.c
AddModule mod_define.c
AddModule mod_log_config.c
AddModule mod_mime_magic.c
AddModule mod_mime.c
AddModule mod_negotiation.c
AddModule mod_status.c
AddModule mod_info.c
AddModule mod_include.c
AddModule mod_autoindex.c
AddModule mod_dir.c
AddModule mod_cgi.c
AddModule mod_asis.c
AddModule mod_imap.c
AddModule mod_actions.c
AddModule mod_speling.c
AddModule mod_userdir.c
AddModule mod_alias.c
AddModule mod_rewrite.c
AddModule mod_access.c
AddModule mod_auth.c
AddModule mod_auth_anon.c
AddModule mod_auth_db.c
AddModule mod_digest.c
AddModule mod_proxy.c
AddModule mod_cern_meta.c
AddModule mod_expires.c
AddModule mod_headers.c
AddModule mod_usertrack.c
AddModule mod_unique_id.c
AddModule mod_so.c
AddModule mod_setenvif.c
AddModule mod_php4.c
AddModule mod_auth_mysql.c
<IfDefine SSL>
AddModule mod_ssl.c
</IfDefine>
#
# ExtendedStatus controls whether Apache will generate "full" status
# information (ExtendedStatus On) or just basic information (ExtendedStatus
# Off) when the "server-status" handler is called. The default is Off.
#
#ExtendedStatus On
### Section 2: 'Main' server configuration
#
# The directives in this section set up the values used by the 'main'
# server, which responds to any requests that aren't handled by a
# <VirtualHost> definition. These values also provide defaults for
# any <VirtualHost> containers you may define later in the file.
#
# All of these directives may appear inside <VirtualHost> containers,
# in which case these default settings will be overridden for the
# virtual host being defined.
#
#
# If your ServerType directive (set earlier in the 'Global Environment'
# section) is set to "inetd", the next few directives don't have any
# effect since their settings are defined by the inetd configuration.
# Skip ahead to the ServerAdmin directive.
#
#
# Port: The port to which the standalone server listens. For
# ports < 1023, you will need httpd to be run as root initially.
#
Port 80
##
## SSL Support
##
## When we also provide SSL we have to listen to the
## standard HTTP port (see above) and to the HTTPS port
##
<IfDefine SSL>
Listen 80
Listen 443
</IfDefine>
#
# If you wish httpd to run as a different user or group, you must run
# httpd as root initially and it will switch.
#
# User/Group: The name (or #number) of the user/group to run httpd as.
# . On SCO (ODT 3) use "User nouser" and "Group nogroup".
# . On HPUX you may not be able to use shared memory as nobody, and the
# suggested workaround is to create a user www and use that user.
# NOTE that some kernels refuse to setgid(Group) or semctl(IPC_SET)
# when the value of (unsigned)Group is above 60000;
# don't use Group nobody on these systems!
#
User nobody
Group nobody
#
# ServerAdmin: Your address, where problems with the server should be
# e-mailed. This address appears on some server-generated pages, such
# as error documents.
#
ServerAdmin @TBOPSEMAIL_NOSLASH@
#
# ServerName allows you to set a host name which is sent back to clients for
# your server if it's different than the one the program would get (i.e., use
# "www" instead of the host's real name).
#
# Note: You cannot just invent host names and hope they work. The name you
# define here must be a valid DNS name for your host. If you don't understand
# this, ask your network administrator.
# If your host doesn't have a registered DNS name, enter its IP address here.
# You will have to access it by its address (e.g., http://123.45.67.89/)
# anyway, and this will make redirections work in a sensible way.
#
#ServerName new.host.name
#
# DocumentRoot: The directory out of which you will serve your
# documents. By default, all requests are taken from this directory, but
# symbolic links and aliases may be used to point to other locations.
#
DocumentRoot "@prefix@/www"
#
# Each directory to which Apache has access, can be configured with respect
# to which services and features are allowed and/or disabled in that
# directory (and its subdirectories).
#
# First, we configure the "default" to be a very restrictive set of
# permissions.
#
<Directory />
Options None
AllowOverride None
Order deny,allow
Deny from all
# Allow from 155.98.60.
</Directory>
#
# Note that from this point forward you must specifically allow
# particular features to be enabled - so if something's not working as
# you might expect, make sure that you have specifically enabled it
# below.
#
#
# When granting access, try to minimize the number of entries and hence
# complexity of the config file. Also, remember these rules:
#
# 1) <directory> directive options & authconfigs are inherited by subdirs
# 2) Putting a '+' before an option on the 'Options' line adds it to the
# existing set (likely inherited from a dir below it).
# 3) Putting a '-' before an option removes it from the existing options set.
# 4) The 'AllowOverride' directive describes how a .htaccess file can
# override configuration file settings for a directory.
# 5) Allowing a .htaccess file to override 'options' is a security hazard.
#
# People who are involved with testbed devel can get at
# stuff under /usr/testbed, but not "outsiders". If exceptions need
# to be made under /usr/testbed, create a <Directory> entry for them
# below. Try to work under the least req'd privilige model whenever
# possible. Add people's cable modems, etc. that need general devel
# access to the /usr/testbed <Directory> entry.
#
<Directory @prefix@>
Order allow,deny
deny from all
allow from 155.99.212.
allow from 155.98.60.
allow from 69.59.212.104
allow from 18.31.0.114
allow from 18.31.0.144
allow from 24.254.69.120
# Jay's machines.
allow from 207.173.21.122
allow from 207.173.21.123
allow from 207.173.21.126
# Tim Stack
allow from 66.219.220.49
</Directory>
<Directory @prefix@/webglimpse>
Options All MultiViews
AllowOverride All
Order allow,deny
Allow from all
</Directory>
<Directory @prefix@/www/cricket>
Options ExecCGI SymLinksIfOwnerMatch
AddHandler cgi-script .cgi
</Directory>
<Directory @prefix@/devel/*/www>
Options +ExecCGI
AllowOverride All
</Directory>
#
# This should be changed to whatever you set DocumentRoot to.
#
<Directory "@prefix@/www">
#
# This may also be "None", "All", or any combination of "Indexes",
# "Includes", "FollowSymLinks", "ExecCGI", or "MultiViews".
#
# Note that "MultiViews" must be named *explicitly* --- "Options All"
# doesn't give it to you.
#
Options All +MultiViews -Indexes
#
# This controls which options the .htaccess files in directories can
# override. Can also be "All", or any combination of "Options", "FileInfo",
# "AuthConfig", and "Limit"
#
AllowOverride All
#
# Controls who can get stuff from this server.
#
Order allow,deny
Allow from all
</Directory>
#
# UserDir: The name of the directory which is appended onto a user's home
# directory if a ~user request is received.
#
<IfModule mod_userdir.c>
# UserDir public_html
UserDir disabled
</IfModule>
#
# Control access to UserDir directories. The following is an example
# for a site where these directories are restricted to read-only.
#
#
# DirectoryIndex: Name of the file or files to use as a pre-written HTML
# directory index. Separate multiple entries with spaces.
#
<IfModule mod_dir.c>
DirectoryIndex index.php3 index.html
</IfModule>
#
# AccessFileName: The name of the file to look for in each directory
# for access control information.
#
AccessFileName .htaccess
#
# The following lines prevent .htaccess files from being viewed by
# Web clients. Since .htaccess files often contain authorization
# information, access is disallowed for security reasons. Comment
# these lines out if you want Web visitors to see the contents of
# .htaccess files. If you change the AccessFileName directive above,
# be sure to make the corresponding changes here.
#
# Also, folks tend to use names such as .htpasswd for password
# files, so this will protect those as well.
#
<Files ~ "^\.ht">
Order allow,deny
Deny from all
</Files>
#
# CacheNegotiatedDocs: By default, Apache sends "Pragma: no-cache" with each
# document that was negotiated on the basis of content. This asks proxy
# servers not to cache the document. Uncommenting the following line disables
# this behavior, and proxies will be allowed to cache the documents.
#
#CacheNegotiatedDocs
#
# UseCanonicalName: (new for 1.3) With this setting turned on, whenever
# Apache needs to construct a self-referencing URL (a URL that refers back
# to the server the response is coming from) it will use ServerName and
# Port to form a "canonical" name. With this setting off, Apache will
# use the hostname:port that the client supplied, when possible. This
# also affects SERVER_NAME and SERVER_PORT in CGI scripts.
#
UseCanonicalName On
#
# TypesConfig describes where the mime.types file (or equivalent) is
# to be found.
#
<IfModule mod_mime.c>
TypesConfig /usr/local/etc/apache/mime.types
</IfModule>
#
# DefaultType is the default MIME type the server will use for a document
# if it cannot otherwise determine one, such as from filename extensions.
# If your server contains mostly text or HTML documents, "text/plain" is
# a good value. If most of your content is binary, such as applications
# or images, you may want to use "application/octet-stream" instead to
# keep browsers from trying to display binary files as though they are
# text.
#
DefaultType text/plain
#
# The mod_mime_magic module allows the server to use various hints from the
# contents of the file itself to determine its type. The MIMEMagicFile
# directive tells the module where the hint definitions are located.
# mod_mime_magic is not part of the default server (you have to add
# it yourself with a LoadModule [see the DSO paragraph in the 'Global
# Environment' section], or recompile the server and include mod_mime_magic
# as part of the configuration), so it's enclosed in an <IfModule> container.
# This means that the MIMEMagicFile directive will only be processed if the
# module is part of the server.
#
<IfModule mod_mime_magic.c>
MIMEMagicFile /usr/local/etc/apache/magic
</IfModule>
#
# HostnameLookups: Log the names of clients or just their IP addresses
# e.g., www.apache.org (on) or 204.62.129.132 (off).
# The default is off because it'd be overall better for the net if people
# had to knowingly turn this feature on, since enabling it means that
# each client request will result in AT LEAST one lookup request to the
# nameserver.
#
HostnameLookups Off
#
# ErrorLog: The location of the error log file.
# If you do not specify an ErrorLog directive within a <VirtualHost>
# container, error messages relating to that virtual host will be
# logged here. If you *do* define an error logfile for a <VirtualHost>
# container, that host's errors will be logged there and not here.
#
ErrorLog @prefix@/log/apache_error_log
#
# LogLevel: Control the number of messages logged to the error_log.
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
#
LogLevel warn
#
# The following directives define some format nicknames for use with
# a CustomLog directive (see below).
#
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
#
# The location and format of the access logfile (Common Logfile Format).
# If you do not define any access logfiles within a <VirtualHost>
# container, they will be logged here. Contrariwise, if you *do*
# define per-<VirtualHost> access logfiles, transactions will be
# logged therein and *not* in this file.
#
#CustomLog /usr/testbed/log/apache_access_log common
#
# If you would like to have agent and referer logfiles, uncomment the
# following directives.
#
#CustomLog @prefix@/log/apache_referer_log referer
#CustomLog @prefix@/log/apache_agent_log agent
#
# If you prefer a single logfile with access, agent, and referer information
# (Combined Logfile Format) you can use the following directive.
#
CustomLog @prefix@/log/apache_access_log combined
#
# Optionally add a line containing the server version and virtual host
# name to server-generated pages (error documents, FTP directory listings,
# mod_status and mod_info output etc., but not CGI generated documents).
# Set to "EMail" to also include a mailto: link to the ServerAdmin.
# Set to one of: On | Off | EMail
#
ServerSignature On
#
# Aliases: Add here as many aliases as you need (with no limit). The format is
# Alias fakename realname
#
<IfModule mod_alias.c>
#
# Note that if you include a trailing / on fakename then the server will
# require it to be present in the URL. So "/icons" isn't aliased in this
# example, only "/icons/"..
#
Alias /icons/ "/usr/local/www/icons/"
<Directory "/usr/local/www/icons">
Options Indexes MultiViews
AllowOverride None
Order allow,deny
Allow from all
</Directory>
#
# ScriptAlias: This controls which directories contain server scripts.
# ScriptAliases are essentially the same as Aliases, except that
# documents in the realname directory are treated as applications and
# run by the server when requested rather than as documents sent to the
# client.
# The same rules about trailing "/" apply to ScriptAlias directives as to
# Alias.
#
ScriptAlias /cgi-bin/ "/usr/local/www/cgi-bin/"
#
# "/usr/local/www/cgi-bin" should be changed to whatever your ScriptAliased
# CGI directory exists, if you have that configured.
#
<Directory "/usr/local/www/cgi-bin">
AllowOverride None
Options None
Order allow,deny
Allow from all
</Directory>
</IfModule>
# End of aliases.
#
# Redirect allows you to tell clients about documents which used to exist in
# your server's namespace, but do not anymore. This allows you to tell the
# clients where to look for the relocated document.
# Format: Redirect old-URI new-URL
#
#
# Directives controlling the display of server-generated directory listings.
#
<IfModule mod_autoindex.c>
#
# FancyIndexing is whether you want fancy directory indexing or standard
#
IndexOptions FancyIndexing
#
# AddIcon* directives tell the server which icon to show for different
# files or filename extensions. These are only displayed for
# FancyIndexed directories.
#
AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip
AddIconByType (TXT,/icons/text.gif) text/*
AddIconByType (IMG,/icons/image2.gif) image/*
AddIconByType (SND,/icons/sound2.gif) audio/*
AddIconByType (VID,/icons/movie.gif) video/*
AddIcon /icons/binary.gif .bin .exe
AddIcon /icons/binhex.gif .hqx
AddIcon /icons/tar.gif .tar
AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv
AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip
AddIcon /icons/a.gif .ps .ai .eps
AddIcon /icons/layout.gif .html .shtml .htm .pdf
AddIcon /icons/text.gif .txt
AddIcon /icons/c.gif .c
AddIcon /icons/p.gif .pl .py
AddIcon /icons/f.gif .for
AddIcon /icons/dvi.gif .dvi
AddIcon /icons/uuencoded.gif .uu
AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl
AddIcon /icons/tex.gif .tex
AddIcon /icons/bomb.gif core
AddIcon /icons/back.gif ..
AddIcon /icons/hand.right.gif README
AddIcon /icons/folder.gif ^^DIRECTORY^^
AddIcon /icons/blank.gif ^^BLANKICON^^
#
# DefaultIcon is which icon to show for files which do not have an icon
# explicitly set.
#
DefaultIcon /icons/unknown.gif
#
# AddDescription allows you to place a short description after a file in
# server-generated indexes. These are only displayed for FancyIndexed
# directories.
# Format: AddDescription "description" filename
#
#AddDescription "GZIP compressed document" .gz
#AddDescription "tar archive" .tar
#AddDescription "GZIP compressed tar archive" .tgz
#
# ReadmeName is the name of the README file the server will look for by
# default, and append to directory listings.
#
# HeaderName is the name of a file which should be prepended to
# directory indexes.
#
# If MultiViews are amongst the Options in effect, the server will
# first look for name.html and include it if found. If name.html
# doesn't exist, the server will then look for name.txt and include
# it as plaintext if found.
#
ReadmeName README
HeaderName HEADER
#
# IndexIgnore is a set of filenames which directory indexing should ignore
# and not include in the listing. Shell-style wildcarding is permitted.
#
IndexIgnore .??* *~ *# HEADER* README* RCS CVS *,v *,t
</IfModule>
# End of indexing directives.
#
# Document types.
#
<IfModule mod_mime.c>
#
# AddEncoding allows you to have certain browsers (Mosaic/X 2.1+) uncompress
# information on the fly. Note: Not all browsers support this.
# Despite the name similarity, the following Add* directives have nothing
# to do with the FancyIndexing customization directives above.
#
AddEncoding x-compress Z
AddEncoding x-gzip gz tgz
#
# AddLanguage allows you to specify the language of a document. You can
# then use content negotiation to give a browser a file in a language
# it can understand.
#
# Note 1: The suffix does not have to be the same as the language
# keyword --- those with documents in Polish (whose net-standard
# language code is pl) may wish to use "AddLanguage pl .po" to
# avoid the ambiguity with the common suffix for perl scripts.
#
# Note 2: The example entries below illustrate that in quite
# some cases the two character 'Language' abbriviation is not
# identical to the two character 'Country' code for its country,
# E.g. 'Danmark/dk' versus 'Danish/da'.
#
# Note 3: In the case of 'ltz' we violate the RFC by using a three char
# specifier. But there is 'work in progress' to fix this and get
# the reference data for rfc1766 cleaned up.
#
# Danish (da) - Dutch (nl) - English (en) - Estonian (ee)
# French (fr) - German (de) - Greek-Modern (el)
# Italian (it) - Portugese (pt) - Luxembourgeois* (ltz)
# Spanish (es) - Swedish (sv) - Catalan (ca) - Czech(cz)
# Polish (pl) - Brazilian Portuguese (pt-br) - Japanese (ja)
#
AddLanguage da .dk
AddLanguage nl .nl
AddLanguage en .en
AddLanguage et .ee
AddLanguage fr .fr
AddLanguage de .de
AddLanguage el .el
AddLanguage it .it
AddLanguage ja .ja
AddCharset ISO-2022-JP .jis
AddLanguage pl .po
AddCharset ISO-8859-2 .iso-pl
AddLanguage pt .pt
AddLanguage pt-br .pt-br
AddLanguage ltz .lu
AddLanguage ca .ca
AddLanguage es .es
AddLanguage sv .se
AddLanguage cz .cz
# LanguagePriority allows you to give precedence to some languages
# in case of a tie during content negotiation.
#
# Just list the languages in decreasing order of preference. We have
# more or less alphabetized them here. You probably want to change this.
#
<IfModule mod_negotiation.c>
LanguagePriority en da nl et fr de el it ja pl pt pt-br ltz ca es sv
</IfModule>
#
# AddType allows you to tweak mime.types without actually editing it, or to
# make certain files to be certain types.
#
# For example, the PHP 3.x module (not part of the Apache distribution -
# see http://www.php.net) will typically use:
#
<IfModule mod_php3.c>
AddType application/x-httpd-php3 .php3
AddType application/x-httpd-php3-source .php3s
</IfModule>
#
# And for PHP 4.x, use:
#
<IfModule mod_php4.c>
AddType application/x-httpd-php .php .php3
AddType application/x-httpd-php-source .phps
</IfModule>
AddType application/x-tar .tgz
#
# AddHandler allows you to map certain file extensions to "handlers",
# actions unrelated to filetype. These can be either built into the server
# or added with the Action command (see below)
#
# If you want to use server side includes, or CGI outside
# ScriptAliased directories, uncomment the following lines.
#
# To use CGI scripts:
#
AddHandler cgi-script .cgi
#
# To use server-parsed HTML files
#
AddType text/html .shtml
AddHandler server-parsed .shtml
#
# Uncomment the following line to enable Apache's send-asis HTTP file
# feature
#
#AddHandler send-as-is asis
#
# If you wish to use server-parsed imagemap files, use
#
#AddHandler imap-file map
#
# To enable type maps, you might want to use
#
#AddHandler type-map var
</IfModule>
# End of document types.
#
# Action lets you define media types that will execute a script whenever
# a matching file is called. This eliminates the need for repeated URL
# pathnames for oft-used CGI file processors.
# Format: Action media/type /cgi-script/location
# Format: Action handler-name /cgi-script/location
#
#
# MetaDir: specifies the name of the directory in which Apache can find
# meta information files. These files contain additional HTTP headers
# to include when sending the document
#
#MetaDir .web
#
# MetaSuffix: specifies the file name suffix for the file containing the
# meta information.
#
#MetaSuffix .meta
#
# Customizable error response (Apache style)
# these come in three flavors
#
# 1) plain text
#ErrorDocument 500 "The server made a boo boo.
# n.b. the (") marks it as text, it does not get output
#
# 2) local redirects
#ErrorDocument 404 /missing.html
# to redirect to local URL /missing.html
#ErrorDocument 404 /cgi-bin/missing_handler.pl
# N.B.: You can redirect to a script or a document using server-side-includes.
#
# 3) external redirects
#ErrorDocument 402 http://some.other_server.com/subscription_info.html
# N.B.: Many of the environment variables associated with the original
# request will *not* be available to such a script.
#
# Customize behaviour based on the browser
#
<IfModule mod_setenvif.c>
#
# The following directives modify normal HTTP response behavior.
# The first directive disables keepalive for Netscape 2.x and browsers that
# spoof it. There are known problems with these browser implementations.
# The second directive is for Microsoft Internet Explorer 4.0b2
# which has a broken HTTP/1.1 implementation and does not properly
# support keepalive when it is used on 301 or 302 (redirect) responses.
#
BrowserMatch "Mozilla/2" nokeepalive
BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0
#
# The following directive disables HTTP/1.1 responses to browsers which
# are in violation of the HTTP/1.0 spec by not being able to grok a
# basic 1.1 response.
#
BrowserMatch "RealPlayer 4\.0" force-response-1.0
BrowserMatch "Java/1\.0" force-response-1.0
BrowserMatch "JDK/1\.0" force-response-1.0
</IfModule>
#
# Allow server status reports, with the URL of http://servername/server-status
# Change the ".your_domain.com" to match your domain to enable.
#
#<Location /server-status>
# SetHandler server-status
# Order deny,allow
# Deny from all
# Allow from .your_domain.com
#</Location>
#
# Allow remote server configuration reports, with the URL of
# http://servername/server-info (requires that mod_info.c be loaded).
# Change the ".your_domain.com" to match your domain to enable.
#
#<Location /server-info>
# SetHandler server-info
# Order deny,allow
# Deny from all
# Allow from .your_domain.com
#</Location>
#
# There have been reports of people trying to abuse an old bug from pre-1.1
# days. This bug involved a CGI script distributed as a part of Apache.
# By uncommenting these lines you can redirect these attacks to a logging
# script on phf.apache.org. Or, you can record them yourself, using the script
# support/phf_abuse_log.cgi.
#
#<Location /cgi-bin/phf*>
# Deny from all
# ErrorDocument 403 http://phf.apache.org/phf_abuse_log.cgi
#</Location>
#
# Proxy Server directives. Uncomment the following lines to
# enable the proxy server:
#
#<IfModule mod_proxy.c>
#ProxyRequests On
#
#<Directory proxy:*>
# Order deny,allow
# Deny from all
# Allow from .your_domain.com
#</Directory>
#
# Enable/disable the handling of HTTP/1.1 "Via:" headers.
# ("Full" adds the server version; "Block" removes all outgoing Via: headers)
# Set to one of: Off | On | Full | Block
#
#ProxyVia On
#
# To enable the cache as well, edit and uncomment the following lines:
# (no cacheing without CacheRoot)
#
#CacheRoot "/var/spool/apache"
#CacheSize 5
#CacheGcInterval 4
#CacheMaxExpire 24
#CacheLastModifiedFactor 0.1
#CacheDefaultExpire 1
#NoCache a_domain.com another_domain.edu joes.garage_sale.com
#</IfModule>
# End of proxy directives.
### Section 3: Virtual Hosts
#
# VirtualHost: If you want to maintain multiple domains/hostnames on your
# machine you can setup VirtualHost containers for them.
# Please see the documentation at <URL:http://www.apache.org/docs/vhosts/>
# for further details before you try to setup virtual hosts.
# You may use the command line option '-S' to verify your virtual host
# configuration.
#
# If you want to use name-based virtual hosts you need to define at
# least one IP address (and port number) for them.
#
#NameVirtualHost 12.34.56.78:80
#NameVirtualHost 12.34.56.78
#
# VirtualHost example:
# Almost any Apache directive may go into a VirtualHost container.
#
#<VirtualHost ip.address.of.host.some_domain.com>
# ServerAdmin webmaster@host.some_domain.com
# DocumentRoot /www/docs/host.some_domain.com
# ServerName host.some_domain.com
# ErrorLog logs/host.some_domain.com-error_log
# CustomLog logs/host.some_domain.com-access_log common
#</VirtualHost>
#<VirtualHost _default_:*>
#</VirtualHost>
##
## SSL Global Context
##
## All SSL configuration in this context applies both to
## the main server and all SSL-enabled virtual hosts.
##
#
# Some MIME-types for downloading Certificates and CRLs
#
<IfDefine SSL>
AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl .crl
</IfDefine>
<IfModule mod_ssl.c>
# Pass Phrase Dialog:
# Configure the pass phrase gathering process.
# The filtering dialog program (`builtin' is a internal
# terminal dialog) has to provide the pass phrase on stdout.
SSLPassPhraseDialog builtin
# Inter-Process Session Cache:
# Configure the SSL Session Cache: First either `none'
# or `dbm:/path/to/file' for the mechanism to use and
# second the expiring timeout (in seconds).
#SSLSessionCache none
#SSLSessionCache shm:/var/run/apache_ssl_scache(512000)
SSLSessionCache dbm:/var/run/apache_ssl_scache
SSLSessionCacheTimeout 300
# Semaphore:
# Configure the path to the mutual explusion semaphore the
# SSL engine uses internally for inter-process synchronization.
SSLMutex file:/var/run/apache_ssl_mutex
# Pseudo Random Number Generator (PRNG):
# Configure one or more sources to seed the PRNG of the
# SSL library. The seed data should be of good random quality.
# WARNING! On some platforms /dev/random blocks if not enough entropy
# is available. This means you then cannot use the /dev/random device
# because it would lead to very long connection times (as long as
# it requires to make more entropy available). But usually those
# platforms additionally provide a /dev/urandom device which doesn't
# block. So, if available, use this one instead. Read the mod_ssl User
# Manual for more details.
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
#SSLRandomSeed startup file:/dev/random 512
#SSLRandomSeed startup file:/dev/urandom 512
#SSLRandomSeed connect file:/dev/random 512
#SSLRandomSeed connect file:/dev/urandom 512
# Logging:
# The home of the dedicated SSL protocol logfile. Errors are
# additionally duplicated in the general error log file. Put
# this somewhere where it cannot be used for symlink attacks on
# a real server (i.e. somewhere where only root can write).
# Log levels are (ascending order: higher ones include lower ones):
# none, error, warn, info, trace, debug.
SSLLog @prefix@/log/apache_ssl_engine_log
SSLLogLevel info
</IfModule>
<IfDefine SSL>
##
## SSL Virtual Host Context
##
<VirtualHost _default_:443>
# General setup for the virtual host
DocumentRoot "@prefix@/www"
ServerName @WWWHOST@
ServerAdmin @TBOPSEMAIL_NOSLASH@
ErrorLog @prefix@/log/apache_error_log
TransferLog @prefix@/log/apache_access_log
# SSL Engine Switch:
# Enable/Disable SSL for this virtual host.
SSLEngine on
# SSL Cipher Suite:
# List the ciphers that the client is permitted to negotiate.
# See the mod_ssl documentation for a complete list.
#SSLCipherSuite ALL:!ADH:!EXP56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
# Server Certificate:
# Point SSLCertificateFile at a PEM encoded certificate. If
# the certificate is encrypted, then you will be prompted for a
# pass phrase. Note that a kill -HUP will prompt again. A test
# certificate can be generated with `make certificate' under
# built time. Keep in mind that if you've both a RSA and a DSA
# certificate you can configure both in parallel (to also allow
# the use of DSA ciphers, etc.)
SSLCertificateFile /usr/local/etc/apache/ssl.crt/www.@OURDOMAIN@.crt
#SSLCertificateFile /usr/local/etc/apache/ssl.crt/server.crt
#SSLCertificateFile /usr/local/etc/apache/ssl.crt/server-dsa.crt
# Server Private Key:
# If the key is not combined with the certificate, use this
# directive to point at the key file. Keep in mind that if
# you've both a RSA and a DSA private key you can configure
# both in parallel (to also allow the use of DSA ciphers, etc.)
SSLCertificateKeyFile /usr/local/etc/apache/ssl.key/www.@OURDOMAIN@.key
#SSLCertificateKeyFile /usr/local/etc/apache/ssl.key/server.key
#SSLCertificateKeyFile /usr/local/etc/apache/ssl.key/server.pem
#SSLCertificateKeyFile /usr/local/etc/apache/ssl.key/server-dsa.key
# Server Certificate Chain:
# Point SSLCertificateChainFile at a file containing the
# concatenation of PEM encoded CA certificates which form the
# certificate chain for the server certificate. Alternatively
# the referenced file can be the same as SSLCertificateFile
# when the CA certificates are directly appended to the server
# certificate for convinience.
#SSLCertificateChainFile /usr/local/etc/apache/ssl.crt/ca.crt
# Certificate Authority (CA):
# Set the CA certificate verification path where to find CA
# certificates for client authentication or alternatively one
# huge file containing all of them (file must be PEM encoded)
# Note: Inside SSLCACertificatePath you need hash symlinks
# to point to the certificate files. Use the provided
# Makefile to update the hash symlinks after changes.
#SSLCACertificatePath /usr/local/etc/apache/ssl.crt
#SSLCACertificateFile /usr/local/etc/apache/ssl.crt/ca-bundle.crt
# Certificate Revocation Lists (CRL):
# Set the CA revocation path where to find CA CRLs for client
# authentication or alternatively one huge file containing all
# of them (file must be PEM encoded)
# Note: Inside SSLCARevocationPath you need hash symlinks
# to point to the certificate files. Use the provided
# Makefile to update the hash symlinks after changes.
#SSLCARevocationPath /usr/local/etc/apache/ssl.crl
#SSLCARevocationFile /usr/local/etc/apache/ssl.crl/ca-bundle.crl
# Client Authentication (Type):
# Client certificate verification type and depth. Types are
# none, optional, require and optional_no_ca. Depth is a
# number which specifies how deeply to verify the certificate
# issuer chain before deciding the certificate is not valid.
#SSLVerifyClient require
#SSLVerifyDepth 10
# Access Control:
# With SSLRequire you can do per-directory access control based
# on arbitrary complex boolean expressions containing server
# variable checks and other lookup directives. The syntax is a
# mixture between C and Perl. See the mod_ssl documentation
# for more details.
#<Location />
#SSLRequire ( %{SSL_CIPHER} !~ m/^(EXP|NULL)-/ \
# and %{SSL_CLIENT_S_DN_O} eq "Snake Oil, Ltd." \
# and %{SSL_CLIENT_S_DN_OU} in {"Staff", "CA", "Dev"} \
# and %{TIME_WDAY} >= 1 and %{TIME_WDAY} <= 5 \
# and %{TIME_HOUR} >= 8 and %{TIME_HOUR} <= 20 ) \
# or %{REMOTE_ADDR} =~ m/^192\.76\.162\.[0-9]+$/
#</Location>
# SSL Engine Options:
# Set various options for the SSL engine.
# o FakeBasicAuth:
# Translate the client X.509 into a Basic Authorisation. This means that
# the standard Auth/DBMAuth methods can be used for access control. The
# user name is the `one line' version of the client's X.509 certificate.
# Note that no password is obtained from the user. Every entry in the user
# file needs this password: `xxj31ZMTZzkVA'.
# o ExportCertData:
# This exports two additional environment variables: SSL_CLIENT_CERT and
# SSL_SERVER_CERT. These contain the PEM-encoded certificates of the
# server (always existing) and the client (only existing when client
# authentication is used). This can be used to import the certificates
# into CGI scripts.
# o StdEnvVars:
# This exports the standard SSL/TLS related `SSL_*' environment variables.
# Per default this exportation is switched off for performance reasons,
# because the extraction step is an expensive operation and is usually
# useless for serving static content. So one usually enables the
# exportation for CGI and SSI requests only.
# o CompatEnvVars:
# This exports obsolete environment variables for backward compatibility
# to Apache-SSL 1.x, mod_ssl 2.0.x, Sioux 1.0 and Stronghold 2.x. Use this
# to provide compatibility to existing CGI scripts.
# o StrictRequire:
# This denies access when "SSLRequireSSL" or "SSLRequire" applied even
# under a "Satisfy any" situation, i.e. when it applies access is denied
# and no other module can change it.
# o OptRenegotiate:
# This enables optimized SSL connection renegotiation handling when SSL
# directives are used in per-directory context.
#SSLOptions +FakeBasicAuth +ExportCertData +CompatEnvVars +StrictRequire
<Files ~ "\.(cgi|shtml|phtml|php3?)$">
SSLOptions +StdEnvVars
</Files>
<Directory "/usr/local/www/cgi-bin">
SSLOptions +StdEnvVars
</Directory>
# SSL Protocol Adjustments:
# The safe and default but still SSL/TLS standard compliant shutdown
# approach is that mod_ssl sends the close notify alert but doesn't wait for
# the close notify alert from client. When you need a different shutdown
# approach you can use one of the following variables:
# o ssl-unclean-shutdown:
# This forces an unclean shutdown when the connection is closed, i.e. no
# SSL close notify alert is send or allowed to received. This violates
# the SSL/TLS standard but is needed for some brain-dead browsers. Use
# this when you receive I/O errors because of the standard approach where
# mod_ssl sends the close notify alert.
# o ssl-accurate-shutdown:
# This forces an accurate shutdown when the connection is closed, i.e. a
# SSL close notify alert is send and mod_ssl waits for the close notify
# alert of the client. This is 100% SSL/TLS standard compliant, but in
# practice often causes hanging connections with brain-dead browsers. Use
# this only for browsers where you know that their SSL implementation
# works correctly.
# Notice: Most problems of broken clients are also related to the HTTP
# keep-alive facility, so you usually additionally want to disable
# keep-alive for those clients, too. Use variable "nokeepalive" for this.
# Similarly, one has to force some clients to use HTTP/1.0 to workaround
# their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and
# "force-response-1.0" for this.
SetEnvIf User-Agent ".*MSIE.*" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0
# Per-Server Logging:
# The home of a custom SSL log file. Use this when you want a
# compact non-error SSL logfile on a virtual host basis.
CustomLog @prefix@/log/apache_ssl_request_log \
"%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
</VirtualHost>
</IfDefine>