Commit dd1b57bc authored by Leigh Stoller's avatar Leigh Stoller

Automate initial user/project setup from setup-db.txt. Rather then

have the user go through a set of hard to explain steps, just push
them through it using the web interface.

* New sitevars to control a little state machine used by the web
  interface.

* When first setting up a testbed, the sitevar value will force the
  web interface to present the user with a single menu option "Create
  New Project" and the "Home" link will take the user to that page.
  The user is instructed to login is as elabman.

* The user fills in the form as directed in setup-ops.txt. Even though
  he is logged in as elabman, the newproject form has been altered to
  operate as if no one is logged in. I also default a bunch more of
  the fields in this case.

* The user submits the form. Rather then pend the new project, just
  jump straight into approveproject. That grinds along as usual, and
  when it is done, the elabman account is frozen and the user logged
  out. The user gets a link inviting him to log back in as the user
  just created.

* Side effects of this new process:

	* The user is made an admin user (admin=1) automatically.
	* The user is added to the emulab-ops project as group_root.
	* The user verification process is skipped.
	* The user is added to the unixgroups wheel and tbadmin.

* I reworked this entire section of setup-db.txt ...

* The user still needs to give himself a real shell and password on
  boss, but I left that for the user to do explicitly. I also drop in
  a pointer to the shellonboss.txt. I might automate this part too at
  some point. Not sure yet.
parent 99f18ce3
......@@ -21,7 +21,7 @@ ops setup documentation):
NFS mounts between boss and ops
Root ssh keys (so that root on boss can ssh to ops without a password)
The web interface (you don't need to be able to log in yet)
The web interface
Make sure you can log into the web interface using the 'elabman' account.
The password for the elabman account is the same as the root password on
......@@ -35,83 +35,85 @@ logged in as a user who is allowed to become an admin, you will see a green
dot one the left side of the header above the main page content. The green
dot means that although you are allowed admin powers, they are currently
turned off, and you see the same web pages that a regular user sees, and
can use the sam actions. If you click on the dot, it will turn red, and you
can use the same actions. If you click on the dot, it will turn red, and you
will have full administrator privileges; we call this 'going red dot'.
Many of the procedures in this file require you to be in red dot mode.
Now, we'll use the elabman user to bootstrap your own account. Note that
it is IMPORTANT that you create another account at this time since the
elabman account does not have the power to perform certain actions that
are required later (such as adding nodes to the testbed). So log out of the
web interface, and use the 'Request Account' button to start a new project.
Create a project that you can use for the faculty/students/staff involved in
running your testbed - you can name it anything you'd like. Fill in your own
information in the 'Project Head Information' section. If you have created an
account for yourself by hand on boss and/or ops, it is important that you
either user a different username on this form, or delete your handmade account
(using 'pw userdel <username>') on BOTH boss AND ops. Shortly after submitting
this form, you should get email at the address you included on the form -
follow the instructions it gives for verifying your email address. After
entering your password, while still logged in to your new account, use the
'Join project' link in the menu to join the 'emulab-ops' project (leave the
'group' field blank.)
Okay, now log out of the web interface, log back on as elabman, and go 'red
dot'. Use the 'Approve New Projects' link on the menu to approve the project
you just started. Also, use the 'New User Approval' page to approve your new
account in the the 'emulab-ops' project - give yourself trust 'group root', so
that you can approve others into this project too.
Go to the web interface, and log in as the admin account you created. Create a
project for the administrators at your site (we call ours 'testbed', you can
call yours whatever you call your project or group). As soon as you've sent
the request to sart the project, you can use the 'New Project Approval' link to
make it active.
Now, that you have an account, there a few things you're going to want to do -
you'll also want to do these things to other admin-types too, when their
accounts get created:
1) Set your 'admin bit' - set the 'admin' column for your account in the users
table to '1' - you can do this, on boss, with:
If you click on the dot again, it will go back to green, thus you can
easily flip back and forth between normal privs and admin privs. Note
that most of the procedures in this file require you to be in red dot mode.
Now, we will use the elabman user to bootstrap your first real account and
project. Note that while you will use the elabman account to do this, the
elabman account should not be considered a real account; it is intended to
help bootstrap only and as such, does not have the power to perform many
actions that are required later (such as adding nodes to the testbed).
Login as user 'elabman' if you have not already done so. Go into 'red dot'
mode by clicking on the green dot. You should see the "Start New Project"
page. Fill in your own information in the 'Project Head Information'
section. It is important that you provide a working email address! Select
your initial Project Name in the 'Project Information' section (we call
ours 'testbed', but you can call yours whatever you call your project or
research group). Also specify a *working* URL (it is required) for the
project. Submit the form using the Submit button at the bottom of the page.
The web interface will grind along for a minute or so. DO NOT CLICK THE
STOP BUTTON! When it is done, you will see a message that invites you to
login as the user you just created. Do this now so that you can continue
with setting up your testbed. Note that the elabman account has been
deactivated during this process to avoid problems later on (and potential
security breaches).
Before we continue. lets explain a few more important items:
* Project Membership: In addition to the project you just created, you have
automatically been added to the "emulab-ops" project with trust value
"group_root". This allows you to approve new members to that project as
well as your own project.
* Admin Mode: Your new account has been given "administrator" mode, as
described above. To change that value for other users after their
accounts are created, you can do this on boss:
echo 'update users set admin=1 where uid="<username>"' | mysql tbdb
2) Give yourself the ability to log in to boss - most users have a restricted
shell on boss, and are not allowed to log in using a password. Edit the
password file (use 'vipw', FreeBSD requires some special processing on the
password file after editing). Give yourself a real shell, and paste in your
encrypted password string from ops (although in general, it is safer to
have a different password on boss then on ops!)
3) If you were logged into boss as root, go ahead and log out and then back
in as yourself. In general, it is safer and better to not do things as
root. In fact, many testbed programs will complain if you invoke them as
root cause then it makes accounting and auditing more difficult.
4) Add yourself to important groups - If you want to be a member of any
UNIX groups on boss, use the 'unixgroups' command (our automated account
tools may wipe out groups added by hand.) You will need to be logged in
as yourself (not root) on boss to run this command. You will want to be
a member of at least the 'tbadmin' and 'wheel' groups. The syntax for
this command is:
unixgroups -a <username> <groupname> ...
Just as you need to go 'red dot' to use admin privileges on the web interface,
you must also explicitly enable them on the command line. To do this, prefix
the command you want to run with 'withadminprivs'. For example, I might invoke
unixgroups like this:
withadminprivs unixgroups -a ricci tbadmin wheel
(Note: withadminprivs and many other admin-type commands live in
/usr/testbed/sbin - you'll want to put this and /usr/testbed/bin in your
$PATH.)
Now that you are an admin, you don't need the elabman account anymore. Log into
the web interface as yourself, go red dot, and go to the user list. Find
elabman (you may need to click on 'Show: all' a the top of the page). Go to
elabman's profile page (by clicking on the uid) and "freeze" the user.
* Shell on Boss: Give yourself the ability to login to boss - most users
have a restricted shell on boss, and are not allowed to log in using a
password. Login to boss as root, and edit the password file (use 'vipw',
FreeBSD requires some special processing on the password file after
editing). Give yourself a real shell (say, /bin/csh) and then exit the
editor. Then give yourself a password (in general, it is safer to have a
different password on boss then on ops!). Use this command:
passwd <your username>
NOTE: See doc/shelloboss.txt for important security issues wrt giving
real shells on boss. Before you give a real shell to someone, it is a
good idea for them to read this file!
* Now logout and back in as yourself. In general, it is safer and better to
not do things as root. In fact, many testbed programs will complain if
you invoke them as root cause then it makes accounting and auditing more
difficult.
* Unix Group Membership: The Emulab account system manages both the
password file and the group file (/etc/group) on both boss and ops. If
you edit it directly, those changes will likely be lost. If you want to be
a member of any UNIX groups on boss, use our 'unixgroups' command. For
example, to add yourself to the "operator" group, do this on boss (as
yourself, not root):
withadminprivs unixgroups -a <username> operator
NOTE: Your initial account created above was already placed in the wheel
and tbadmin groups.
NOTE: Just as you need to go 'red dot' to use admin privileges on the web
interface, you must also explicitly enable them on the command line. To
do this, prefix the command you want to run with 'withadminprivs'.
* Set you path: withadminprivs and many other admin-type commands live in
/usr/testbed/sbin - you'll want to put this and /usr/testbed/bin in your
$PATH.
Others at your site can now apply to join your project, or start their own.
......
......@@ -61,8 +61,10 @@ symlinks to the appropriate places. ie., if you make one big filesystem called
ln -s /z/proj /proj
... etc.
Do *not* create any users yet, and just log in a root for the time being. Our
software will create users later, once you get boss set up.
Do *not* create any users yet, and just log in a root for the time being.
Our software will create users later, once you get boss set up. If you
already created users, then delete them with the "pw" command and make sure
the home directories for them are removed as well.
##### Step 1 - Installing packages
......
......@@ -93,6 +93,9 @@ Our software will create users later, once you get boss set up. BE SURE to
give root a password and REMEMBER it! You are going to need it later. To
set the root password use "passwd root".
If you already created users, then delete them with the "pw" command
and make sure the home directories for them are removed as well!
##### Step 1 - Installing packages
Again, almost the same as on ops. Download the same tarball, and follow
......
......@@ -10,6 +10,8 @@
INSERT INTO sitevariables VALUES ('general/testvar',NULL,'43','A test variable');
INSERT INTO sitevariables VALUES ('general/firstinit/state',NULL,'Ready','Indicates that a new emulab is not setup yet. Moves through several states.');
INSERT INTO sitevariables VALUES ('general/firstinit/pid',NULL,'testbed','The Project Name of the first project.');
INSERT INTO sitevariables VALUES ('web/nologins',NULL,'0','Non-zero value indicates that no user may log into the Web Interface; non-admin users are auto logged out.');
INSERT INTO sitevariables VALUES ('web/message',NULL,'','Message to place in large lettering under the login message on the Web Interface.');
INSERT INTO sitevariables VALUES ('web/banner',NULL,'','Message to place in large lettering at top of home page (typically a special message)');
......
......@@ -23,6 +23,7 @@ use English;
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $MKGROUP = "$TB/sbin/mkgroup";
my $SETGROUPS= "$TB/sbin/setgroups";
my $MKACCT = "$TB/sbin/tbacct add";
my $GRANTTYPE= "$TB/sbin/grantnodetype -d";
my $WIKISUPPORT = @WIKISUPPORT@;
......@@ -135,6 +136,9 @@ if ($WIKISUPPORT) {
system("$MKACCT $projhead") == 0 or
fatal("$MKACCT $projhead failed!");
system("$SETGROUPS $projhead") == 0 or
fatal("$SETGROUPS $projhead failed!");
$EUID = 0;
#
......
<?php
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2003 University of Utah and the Flux Group.
# Copyright (c) 2000-2003, 2005 University of Utah and the Flux Group.
# All rights reserved.
#
include("defs.php3");
......@@ -25,6 +25,11 @@ if (! $isadmin) {
USERERROR("You do not have admin privileges to approve projects!", 1);
}
#
# See if we are in an initial Emulab setup.
#
$FirstInitState = (TBGetFirstInitState() == "approveproject");
echo "<center><h1>
Approving Project '$pid' ...
</h1></center>";
......@@ -252,11 +257,33 @@ elseif (strcmp($approval, "approve") == 0) {
a reasonable amount of time, please contact $TBMAILADDR.\n";
flush();
SUEXEC($uid, $TBADMINGROUP, "webmkproj $pid", 1);
SUEXEC($uid, $TBADMINGROUP, "webmkproj $pid", SUEXEC_ACTION_DIE);
echo "<p><b>
Project $pid (User: $headuid) has been approved.
</b>\n";
if (!$FirstInitState) {
echo "<p><b>
Project $pid (User: $headuid) has been approved.
</b>\n";
}
else {
echo "<br><br><font size=+1>\n";
echo "Congratulations! You have successfully setup your initial Emulab
Project. You should now ".
"<a href=login.php3?vuid=$headuid>login</a>
using the account you just
created so that you can continue setting up your new Emulab!
</font><br>\n";
#
# Freeze the initial user.
#
DBQueryFatal("update users set ".
" status='" . TBDB_USERSTATUS_FROZEN . "' ".
"where uid='$FIRSTUSER'");
#
# Move to next phase.
#
TBSetFirstInitState("Ready");
}
}
else {
TBERROR("Invalid approval value $approval in approveproject.php3.", 1);
......
......@@ -8,6 +8,7 @@ $TBDBNAME = "@TBDBNAME@";
$TBOPSPID = "emulab-ops";
$NODEDEAD_PID = $TBOPSPID;
$NODEDEAD_EID = "hwdown";
$FIRSTUSER = "elabman";
# All these constants need to go at some point, replaced by data from
# the regex table.
......@@ -1967,6 +1968,33 @@ function TBExptLockedDown($pid, $eid)
return $row[0];
}
#
# Return firstinit state.
#
function TBGetFirstInitState()
{
$firstinit = TBGetSiteVar("general/firstinit/state");
if ($firstinit == "Ready")
return null;
return $firstinit;
}
function TBSetFirstInitState($newstate)
{
$query_result =
DBQueryFatal("update sitevariables set value='$newstate' ".
"where name='general/firstinit/state'");
}
function TBGetFirstInitPid()
{
return TBGetSiteVar("general/firstinit/pid");
}
function TBSetFirstInitPid($pid)
{
$query_result =
DBQueryFatal("update sitevariables set value='$pid' ".
"where name='general/firstinit/pid'");
}
#
# DB Interface.
#
......
<?php
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2004 University of Utah and the Flux Group.
# Copyright (c) 2000-2005 University of Utah and the Flux Group.
# All rights reserved.
#
require("defs.php3");
......@@ -10,21 +10,32 @@ require("defs.php3");
# The point of this is to redirect logged in users to their My Emulab
# page.
#
if (!isset($stayhome) && ($uid = GETUID())) {
if ($uid = GETUID()) {
$check_status = CHECKLOGIN($uid) & CHECKLOGIN_STATUSMASK;
if (!isset($stayhome) && $check_status == CHECKLOGIN_LOGGEDIN) {
# Zap to My Emulab page.
header("Location: $TBBASE/showuser.php3?target_uid=$uid");
return;
if (($firstinitstate = TBGetFirstInitState())) {
unset($stayhome);
}
elseif (isset($SSL_PROTOCOL)) {
# Fall through; display the page.
;
}
elseif ($check_status == CHECKLOGIN_MAYBEVALID) {
# Not in SSL mode, so reload using https to see if really logged in.
header("Location: $TBBASE/index.php3");
if (!isset($stayhome)) {
if ($check_status == CHECKLOGIN_LOGGEDIN) {
if ($firstinitstate == "createproject") {
# Zap to NewProject Page,
header("Location: $TBBASE/newproject.php3");
}
else {
# Zap to My Emulab page.
header("Location: $TBBASE/showuser.php3?target_uid=$uid");
}
return;
}
elseif (isset($SSL_PROTOCOL)) {
# Fall through; display the page.
;
}
elseif ($check_status == CHECKLOGIN_MAYBEVALID) {
# Not in SSL mode, so reload using https to see if logged in.
header("Location: $TBBASE/index.php3");
}
}
# Fall through; display the page.
}
......
......@@ -224,6 +224,7 @@ function WRITESIDEBAR() {
global $TBBASE, $TBDOCBASE, $BASEPATH, $WIKISUPPORT, $WIKIURL;
global $CHECKLOGIN_WIKINAME;
global $THISHOMEBASE;
$firstinitstate = TBGetFirstInitState();
#
# The document base cannot be a mix of secure and nonsecure.
......@@ -352,7 +353,21 @@ function WRITESIDEBAR() {
}
if ($login_status & (CHECKLOGIN_LOGGEDIN|CHECKLOGIN_MAYBEVALID)) {
if ($login_status & CHECKLOGIN_ACTIVE) {
if ($firstinitstate != null) {
if ($firstinitstate == "createproject") {
WRITESIDEBARBUTTON("Create First Project",
$TBBASE, "newproject.php3");
}
elseif ($firstinitstate == "approveproject") {
$firstinitpid = TBGetFirstInitPid();
WRITESIDEBARBUTTON("Approve First Project",
$TBBASE,
"approveproject.php3?pid=$firstinitpid".
"&approval=approve");
}
}
elseif ($login_status & CHECKLOGIN_ACTIVE) {
if ($login_status & CHECKLOGIN_PSWDEXPIRED) {
WRITESIDEBARBUTTON("Change Your Password",
$TBBASE, "moduserinfo.php3");
......@@ -499,11 +514,13 @@ function WRITESIDEBAR() {
}
#
# Standard options for logged in users!
#
WRITESIDEBARDIVIDER();
SIDEBARCELL("<a href=\"$TBBASE/newproject.php3\">Start</a> or " .
"<a href=\"$TBBASE/joinproject.php3\">Join</a> a Project",
1);
#
if (!$firstinitstate) {
WRITESIDEBARDIVIDER();
SIDEBARCELL("<a href=\"$TBBASE/newproject.php3\">Start</a> or " .
"<a href=\"$TBBASE/joinproject.php3\">Join</a> a Project",
1);
}
}
#WRITESIDEBARLASTBUTTON_COOL("Take our Survey",
......@@ -552,20 +569,22 @@ function WRITESIDEBAR() {
echo "</td></tr>\n";
}
elseif (!NOLOGINS()) {
echo "<tr>";
echo "<td class=\"menufooter\" align=center valign=center>";
echo "<tr>";
echo "<td class=\"menufooter\" align=center valign=center>";
echo "<a href=\"$TBBASE/reqaccount.php3\">";
echo "<img alt=\"Request Account\" border=0 ";
echo "src=\"$BASEPATH/requestaccount.gif\"></a>";
if (!$firstinitstate) {
echo "<a href=\"$TBBASE/reqaccount.php3\">";
echo "<img alt=\"Request Account\" border=0 ";
echo "src=\"$BASEPATH/requestaccount.gif\"></a>";
echo "<br /><b>or</b><br />";
echo "<br /><b>or</b><br />";
}
echo "<a href=\"$TBBASE/login.php3\">";
echo "<img alt=\"logon\" border=0 ";
echo "src=\"$BASEPATH/logon.gif\"></a>\n";
echo "<a href=\"$TBBASE/login.php3\">";
echo "<img alt=\"logon\" border=0 ";
echo "src=\"$BASEPATH/logon.gif\"></a>\n";
echo "</td></tr>\n";
echo "</td></tr>\n";
}
#
......
......@@ -15,12 +15,17 @@ include("defs.php3");
#
$uid = GETLOGIN();
#
# See if we are in an initial Emulab setup.
#
$FirstInitState = (TBGetFirstInitState() == "createproject");
#
# If a uid came in, then we check to see if the login is valid.
# If the login is not valid. We require that the user be logged in
# to start a second project.
#
if ($uid) {
if ($uid && !$FirstInitState) {
# Allow unapproved users to create multiple projects ...
# Must be verified though.
LOGGEDINORDIE($uid, CHECKLOGIN_UNAPPROVED|CHECKLOGIN_WEBONLY);
......@@ -50,26 +55,38 @@ $EMAILWARNING =
function SPITFORM($formfields, $returning, $errors)
{
global $TBDB_UIDLEN, $TBDB_PIDLEN, $TBDOCBASE, $WWWHOST;
global $usr_keyfile;
global $usr_keyfile, $FirstInitState;
global $ACCOUNTWARNING, $EMAILWARNING;
global $WIKISUPPORT, $WIKIURL;
PAGEHEADER("Start a New Testbed Project");
echo "<center><font size=+1>
If you are a <font color=red>student
(undergrad or graduate)</font>, please
do not try to start a project! <br>Your advisor must do it.
<a href=docwrapper.php3?docname=auth.html>
Read this for more info.</a>
</font></center><br>\n";
if (! $returning) {
#
# First initialization gets different text
#
if ($FirstInitState == "createproject") {
echo "<center><font size=+1>
Please create your initial project.<br> A good Project Name
for your first project is probably 'testbed', but you can
choose anything you like.
</font></center><br>\n";
}
else {
echo "<center><font size=+1>
If you already have an Emulab account,
<a href=login.php3?refer=1>
<font color=red>please log on first!</font></a>
If you are a <font color=red>student
(undergrad or graduate)</font>, please
do not try to start a project! <br>Your advisor must do it.
<a href=docwrapper.php3?docname=auth.html>
Read this for more info.</a>
</font></center><br>\n";
if (! $returning) {
echo "<center><font size=+1>
If you already have an Emulab account,
<a href=login.php3?refer=1>
<font color=red>please log on first!</font></a>
</font></center><br>\n";
}
}
if ($errors) {
......@@ -584,6 +601,16 @@ if (! isset($_POST['submit'])) {
$defaults[proj_plabpcs] = "0";
$defaults[proj_public] = "checked";
$defaults[proj_linked] = "checked";
if ($FirstInitState == "createproject") {
$defaults[pid] = "testbed";
$defaults[proj_pcs] = "256";
$defaults[proj_members] = "256";
$defaults[proj_funders] = "none";
$defaults[proj_name] = "Your Testbed Project";
$defaults[proj_why] = "This project is used for testbed ".
"administrators to develop and test new software. ";
}
SPITFORM($defaults, $returning, 0);
PAGEFOOTER();
......@@ -999,7 +1026,7 @@ if (mysql_num_rows($query_result)) {
# * Generate a mail message to the user with the verification key.
#
if (! $returning) {
$encoding = crypt("$password1");
$encoding = crypt("$password1");
#
# Must be done before user record is inserted!
......@@ -1023,27 +1050,29 @@ if (! $returning) {
"date_add(now(), interval 1 year), now(), '$wikiname')");
DBQueryFatal("INSERT INTO user_stats (uid) VALUES ('$proj_head_uid')");
$key = TBGenVerificationKey($proj_head_uid);
TBMAIL("$usr_name '$proj_head_uid' <$usr_email>",
"Your New User Key",
"\n".
"Dear $usr_name:\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=$proj_head_uid&key=$key\n".
"\n".
"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".
"\n".
"Thanks,\n".
"Testbed Operations\n",
"From: $TBMAIL_APPROVAL\n".
"Bcc: $TBMAIL_AUDIT\n".
"Errors-To: $TBMAIL_WWW");
if (! $FirstInitState) {
$key = TBGenVerificationKey($proj_head_uid);
TBMAIL("$usr_name '$proj_head_uid' <$usr_email>",
"Your New User Key",
"\n".
"Dear $usr_name:\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=$proj_head_uid&key=$key\n".
"\n".
"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".
"\n".
"Thanks,\n".
"Testbed Operations\n",
"From: $TBMAIL_APPROVAL\n".
"Bcc: $TBMAIL_AUDIT\n".
"Errors-To: $TBMAIL_WWW");
}
}
#
......@@ -1079,7 +1108,7 @@ DBQueryFatal("insert into group_membership ".
#
# If a new user, do not send the full blown message until verified.
#
if ($returning) {
if ($returning || $FirstInitState) {
#
# Grab the unix GID that was assigned.
#
......@@ -1140,6 +1169,38 @@ else {
"Errors-To: $TBMAIL_WWW");
}
if ($FirstInitState) {
#
# The first user gets admin status and some extra groups, etc.
#
DBQueryFatal("update users set ".
" admin=1,status='". TBDB_USERSTATUS_UNAPPROVED . "' " .
"where uid='$proj_head_uid'");
DBQueryFatal("insert into unixgroup_membership set ".
"uid='$proj_head_uid', gid='wheel'");
DBQueryFatal("insert into unixgroup_membership set ".
"uid='$proj_head_uid', gid='$TBADMINGROUP'");
DBQueryFatal("insert into group_membership ".
"(uid, gid, pid, trust, date_applied) ".
"values ('$proj_head_uid','$TBOPSPID','$TBOPSPID', ".
"'" . TBDB_TRUSTSTRING_GROUPROOT . "', now())");
DBQueryFatal("update group_membership set ".
" trust='" . TBDB_TRUSTSTRING_PROJROOT . "' ".
"where uid='$proj_head_uid' and pid='$pid'");
#
# Move to next phase.
#
TBSetFirstInitPid($pid);
TBSetFirstInitState("approveproject");
header("Location: approveproject.php3?pid=$pid&approval=approve");
return;
}
#
# Spit out a redirect so that the history does not include a post
# in it. The back button skips over the post and to the form.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment