diff --git a/www/approveproject.php3 b/www/approveproject.php3
index 86153d00caf061e3a9568db61cc2b393bf914b27..48edeca0e8f0e04dd8b0f89115f7254004c1a6a0 100644
--- a/www/approveproject.php3
+++ b/www/approveproject.php3
@@ -14,13 +14,13 @@ PAGEHEADER("New Project Approved");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
 
 #
 # Of course verify that this uid has admin privs!
 #
-$isadmin = ISADMIN($uid);
+$isadmin = ISADMIN();
 if (! $isadmin) {
     USERERROR("You do not have admin privileges to approve projects!", 1);
 }
@@ -37,22 +37,27 @@ echo "<center><h1>
 #
 # Grab the head_uid for this project. This verifies it is a valid project.
 #
-$query_result = 
-    DBQueryFatal("SELECT head_uid from projects where pid='$pid'");
-if (($row = mysql_fetch_row($query_result)) == 0) {
+if (! ($this_project = Project::Lookup($pid))) {
     TBERROR("Unknown project $pid", 1);
 }
-$headuid = $row[0];
+if (! ($leader = $this_project->GetLeader())) {
+    TBERROR("Error getting leader for $pid", 1);
+}
+$headuid = $this_project->head_uid();
 
 #
 # If the user wanted to change the head uid, do that now (we change both
 # the head_uid and the leader of the default project)
 #
-if (isset($head_uid) && strcmp($head_uid,"")) {
+if (isset($head_uid) && $head_uid != "") {
+    if (! ($newleader = User::Lookup($head_uid))) {
+	TBERROR("Unknown user $head_uid", 1);
+    }
+    if ($this_project->ChangeLeader($newleader) < 0) {
+	TBERROR("Error changing leader to $head_uid", 1);
+    }
+    $leader  = $newleader;
     $headuid = $head_uid;
-    DBQueryFatal("UPDATE projects set head_uid='$headuid' where pid='$pid'");
-    DBQueryFatal("UPDATE groups set leader='$headuid' where pid='$pid' and " .
-	    "gid='$pid'");
 }
 
 if (!isset($user_interface) ||
@@ -70,26 +75,16 @@ if (!isset($user_interface) ||
 # and we will change it to "unapproved" or "active", respectively.
 # If the status is "active", we leave it alone. 
 #
-$query_result = 
-    DBQueryFatal("SELECT status,usr_email,usr_name from users ".
-		 "where uid='$headuid'");
-if (mysql_num_rows($query_result) == 0) {
-    TBERROR("Unknown user $headuid", 1);
-}
-$row = mysql_fetch_row($query_result);
-$curstatus     = $row[0];
-$headuid_email = $row[1];
-$headname      = $row[2];
+$curstatus     = $leader->status();
+$headuid_email = $leader->email();
+$headname      = $leader->name();
 #echo "Status = $curstatus, Email = $headuid_email<br>\n";
 
 #
 # Then we check that the headuid is really listed in the group_membership
 # table (default group), just to be sure. 
 #
-$query_result =
-    DBQueryFatal("SELECT trust from group_membership where ".
-		 "uid='$headuid' and pid='$pid' and gid='$pid'");
-if (mysql_num_rows($query_result) == 0) {
+if (! $this_project->IsMember($leader, $ignore)) {
     USERERROR("User $headuid is not the leader of project $pid.", 1);
 }
 
@@ -194,17 +189,14 @@ elseif (strcmp($approval, "approve") == 0) {
 	    TBERROR("Invalid $headuid status $curstatus in ".
                     "approveproject.php3", 1);
         }
-	DBQueryFatal("UPDATE users set status='$newstatus', ".
-		     "       user_interface='$user_interface' ".
-		     "WHERE uid='$headuid'");
+	$leader->SetUserInterface($user_interface);
+	$leader->SetStatus($newstatus);
     }
 
     #
     # Set the project "approved" field to true. 
     #
-    DBQueryFatal("update projects set approved='1', ".
-		 "       default_user_interface='$user_interface' ".
-		 "where pid='$pid'");
+    $this_project->SetApproved(1);
 
     #
     # XXX
@@ -223,8 +215,7 @@ elseif (strcmp($approval, "approve") == 0) {
     }
     if (count($pcremote_ok)) {
 	    $foo = implode(",", $pcremote_ok);
-	    DBQueryFatal("UPDATE projects set pcremote_ok='$foo' ".
-			 "WHERE pid='$pid'");
+	    $this_project->SetRemoteOK($foo);
     }
 
     #
diff --git a/www/approveproject_form.php3 b/www/approveproject_form.php3
index 7b3092d12a62b534d7a72808319324b50f1f3bbf..ecaf9a043275245073b285bbeea91a9ce3eddafb 100755
--- a/www/approveproject_form.php3
+++ b/www/approveproject_form.php3
@@ -15,13 +15,13 @@ PAGEHEADER("New Project Approval");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Of course verify that this uid has admin privs!
 #
-$isadmin = ISADMIN($uid);
 if (! $isadmin) {
     USERERROR("You do not have admin privileges to approve projects!", 1);
 }
@@ -37,8 +37,8 @@ if (!isset($pid) ||
 #
 # Check to make sure thats this is a valid PID.
 #
-if (! TBValidProject($pid)) {
-    USERERROR("The project $pid is not a valid project.", 1);
+if (! ($this_project = Project::Lookup($pid))) {
+    USERERROR("Unknown project $pid", 1);
 }
 
 echo "<center><h3>You have the following choices:</h3></center>
@@ -79,19 +79,19 @@ echo "<center><h3>You have the following choices:</h3></center>
 #
 SHOWPROJECT($pid, $uid);
 
-TBProjLeader($pid, $projleader);
+$projleader = $this_project->GetLeader();
 
 echo "<center>
       <h3>Project Leader Information</h3>
       </center>
       <table align=center border=0>\n";
 
-SHOWUSER($projleader);
+SHOWUSER($projleader->uid());
 
 #
 # Check to make sure that the head user is 'unapproved' or 'active'
 #
-$headstatus = TBUserStatus($projleader);
+$headstatus = $projleader->status();
 if (!strcmp($headstatus,TBDB_USERSTATUS_UNAPPROVED) ||
 	!strcmp($headstatus,TBDB_USERSTATUS_ACTIVE)) {
     $approvable = 1;
@@ -136,7 +136,7 @@ echo "<tr>
        </tr>\n";
 
 #
-# Allow the approver to change the project's head UID - gotta find everyone in
+# Allow the approver to change the projects head UID - gotta find everyone in
 # the default group, first
 #
 echo "<tr>
@@ -144,12 +144,14 @@ echo "<tr>
 	      Head UID:
               <select name=head_uid>
                       <option value=''>(Unchanged)</option>";
-$query_result =
-    DBQueryFatal("select uid from group_membership where pid='$pid' and " .
-	    "gid='$pid'");
-while ($row = mysql_fetch_array($query_result)) {
-    $thisuid = $row[uid];
-    echo "                      <option value='$thisuid'>$thisuid</option>\n";
+
+$allmembers = $this_project->MemberList();
+
+foreach ($allmembers as $other_user) {
+    $this_uid   = $other_user->uid();
+    $this_webid = $other_user->webid();
+    
+    echo "                   <option value='$this_webid'>$this_uid</option>\n";
 }
 echo "        </select>
           </td>
diff --git a/www/approveproject_list.php3 b/www/approveproject_list.php3
index 62322fcfa03625730b0e186b2c2b19f44f47461f..7ad7876047d2ec75a62e81a619bcd38b87c395f4 100755
--- a/www/approveproject_list.php3
+++ b/www/approveproject_list.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,13 +14,13 @@ PAGEHEADER("New Project Approval List");
 #
 # Only known and logged in users can do this. uid came in with the URI.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
 
 #
 # Of course verify that this uid has admin privs!
 #
-$isadmin = ISADMIN($uid);
+$isadmin = ISADMIN();
 if (! $isadmin) {
     USERERROR("You do not have admin privileges to approve projects!", 1);
 }
@@ -32,7 +32,7 @@ if (! $isadmin) {
 # implies denying the project leader account, when there is just a single
 # project pending for that project leader. 
 #
-$query_result = DBQueryFatal("SELECT *, ".
+$query_result = DBQueryFatal("SELECT pid_idx, ".
 			     " DATE_FORMAT(created, '%m/%d/%y') as day_created ".
 			     " from projects ".
 			     "where approved='0' order by created desc");
@@ -64,36 +64,42 @@ echo "<tr>
       </tr>\n";
 
 while ($projectrow = mysql_fetch_array($query_result)) {
-    $pid      = $projectrow[pid];
-    $headuid  = $projectrow[head_uid];
-    $Purl     = $projectrow[URL];
-    $Pname    = $projectrow[name];
-    $Pcreated = $projectrow[day_created];
+    $pid_idx  = $projectrow["pid_idx"];
+    $Pcreated = $projectrow["day_created"];
 
-    $userinfo_result =
-	DBQueryFatal("SELECT * from users where uid='$headuid'");
+    if (! ($project = Project::Lookup($pid_idx))) {
+	TBERROR("Could not lookup project $pid_idx", 1);
+    }
+    if (! ($leader = $project->GetLeader())) {
+	TBERROR("Could not get leader for project $pid_idx", 1);
+    }
+    $pid        = $project->pid();
+    $Purl       = $project->URL();
+    $Pname      = $project->name();
+    $headuid    = $leader->uid();
+    $name	= $leader->name();
+    $email	= $leader->email();
+    $title	= $leader->title();
+    $affil	= $leader->affil();
+    $phone	= $leader->phone();
+    $status     = $leader->status();
 
-    $row	= mysql_fetch_array($userinfo_result);
-    $name	= $row[usr_name];
-    $email	= $row[usr_email];
-    $title	= $row[usr_title];
-    $affil	= $row[usr_affil];
-    $phone	= $row[usr_phone];
-    $status     = $row[status];
+    $apprproj_url = CreateURL("approveproject_form", $project);
+    $showproj_url = CreateURL("showproject", $project);
+    $showuser_url = CreateURL("showuser", $leader);
 
     echo "<tr>
               <td height=15 colspan=6></td>
           </tr>
           <tr>
               <td align=center valign=center rowspan=2>
-                  <A href='approveproject_form.php3?pid=$pid'>
+                  <A href='$apprproj_url'>
                      <img alt=\"o\" src=\"redball.gif\"></A></td>
               <td rowspan=2>
-                  <A href='showproject.php3?pid=$pid'>$pid</A>
+                  <A href='$showproj_url'>$pid</A>
                   <br>$Pcreated</td>
               <td rowspan=2>
-                  <A href='showuser.php3?target_uid=$headuid'>
-                     $headuid</A></td>
+                  <A href='$showuser_url'>$headuid</A></td>
               <td>$name";
     if ($status == TBDB_USERSTATUS_NEWUSER) {
 	echo " (<font color=red>unverified</font>)";
diff --git a/www/approveuser.php3 b/www/approveuser.php3
index b953cf41665f71786f549b14abd01e08370aca84..dc2eee671d56bd94702e46a8f7e00f5d16b9e453 100644
--- a/www/approveuser.php3
+++ b/www/approveuser.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2003, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2003, 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -12,10 +12,10 @@ include("defs.php3");
 PAGEHEADER("New Users Approved");
 
 #
-# Only known and logged in users can be verified.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
 
 $projectchecks = array();
 
@@ -92,34 +92,42 @@ while (list ($header, $value) = each ($HTTP_POST_VARS)) {
     #
     # Verify an actual user that is being approved.
     #
-    if (! TBCurrentUser($user)) {
+    if (! ($target_user = User::Lookup($user))) {
 	TBERROR("Trying to approve unknown user $user.", 1);
     }
+
+    # Ditto the project.
+    if (! ($target_project = Project::Lookup($project))) {
+	TBERROR("Trying to approve user into unknown project $project.", 1);
+    }
+
+    # Ditto the group.
+    if (! ($target_group = Group::LookupByPidGid($project, $group))) {
+	TBERROR("Trying to approve user into unknown group $group", 1);
+    }
     
     #
     # Check that the current uid has the necessary trust level
     # to approver users in the project/group. Also, only project leaders
     # can add someone to the default group as group_root.
     #
-    if (! TBProjAccessCheck($uid, $project, $group, $TB_PROJECT_ADDUSER)) {
+    if (! $target_group->AccessCheck($this_user, $TB_PROJECT_ADDUSER)) {
 	USERERROR("You are not allowed to approve users in ".
 		  "$project/$group!", 1);
     }
 
-    if (strcmp($newtrust, "group_root") == 0 &&
-	strcmp($group, $project) == 0) {
-	if (! TBProjAccessCheck($uid, $project, $group, 
-                                $TB_PROJECT_BESTOWGROUPROOT)) {
-	    USERERROR("You do not have permission to add new users with group ".
-		      "root trust to the default group!", 1);
-	}
+    if ($newtrust == "group_root" && $project == $group &&
+	!$target_project->AccessCheck($this_user,
+				      $TB_PROJECT_BESTOWGROUPROOT)) {
+	USERERROR("You do not have permission to add new users with group ".
+		  "root trust to the default group!", 1);
     }
     
     #
     # Check if already approved in the project/group. If already an
     # approved member, something went wrong.
     #
-    TBGroupMember($user, $project, $group, $isapproved);
+    $target_group->IsMember($target_user, $isapproved);
     if ($isapproved) {
 	USERERROR("$user is already an approved member of ".
 		  "$project/$group!", 1);
@@ -146,12 +154,12 @@ while (list ($header, $value) = each ($HTTP_POST_VARS)) {
     if (strcmp($project, $group) == 0 &&
 	(strcmp($approval, "deny") == 0 ||
 	 strcmp($approval, "nuke") == 0)) {
-	$query_result =
-	    DBQueryFatal("select gid from group_membership ".
-			 "where uid='$user' and pid='$project' and pid!=gid");
-	
-	while ($row = mysql_fetch_array($query_result)) {
-	    $gid = $row[gid];
+
+	# List of subgroup membership in this project.
+	$grouplist = $target_project->GroupList($target_user);
+
+	foreach ($grouplist as $subgroup) {
+	    $gid = $subgroup->gid();
 
             #
             # Create and indirect through post var for subgroup approval value.
@@ -183,7 +191,7 @@ while (list ($header, $value) = each ($HTTP_POST_VARS)) {
     if (strcmp($project, $group) == 0)
 	continue;
 
-    TBGroupMember($user, $project, $project, $isapproved);
+    $target_project->IsMember($target_user, $isapproved);
     if ($isapproved)
 	continue;
 
@@ -236,6 +244,14 @@ while (list ($user, $value) = each ($projectchecks)) {
 
 	#echo "$user $pid $gid $trust $foo $bar<br>\n";
 
+	if (! ($target_group = Group::LookupByPidGid($pid, $gid))) {
+	    TBERROR("Could not find group object for $project/$group", 1);
+	}
+
+	if (! ($target_user = User::Lookup($user))) {
+	    TBERROR("Could not find user object for $user", 1);
+	}
+	
 	#
 	# This looks for different trust levels in different subgroups
 	# of the same project. We are only checking the form arguments
@@ -258,8 +274,7 @@ while (list ($user, $value) = each ($projectchecks)) {
 	}
 	$pidlist[$pid] = $pid;
 
-	# Check vs. the database
-	TBCheckGroupTrustConsistency($user, $pid, $gid, $trust, 1);
+	$target_group->CheckTrustConsistency($target_user, $trust, 1);
     }
     
     reset($value);
@@ -298,27 +313,32 @@ while (list ($header, $value) = each ($POST_VARS_COPY)) {
     # and we will change it to "unapproved" or "active", respectively.
     # If the status is "active", we leave it alone. 
     #
-    $query_result =
-        DBQueryFatal("SELECT status,usr_email,usr_name from users where ".
-		     "uid='$user'");
-    if (mysql_num_rows($query_result) == 0) {
-	TBERROR("Unknown user $user", 1);
+    if (! ($target_user = User::Lookup($user))) {
+	TBERROR("Trying to approve unknown user $user.", 1);
     }
-    $row = mysql_fetch_row($query_result);
-    $curstatus  = $row[0];
-    $user_email = $row[1];
-    $user_name  = $row[2];
+    $curstatus  = $target_user->status();
+    $user_email = $target_user->email();
+    $user_name  = $target_user->name();
     #echo "Status = $curstatus, Email = $user_email<br>\n";
 
+    # Ditto the project and group
+    if (! ($target_project = Project::Lookup($project))) {
+	TBERROR("Trying to approve user into unknown project $project.", 1);
+    }
+    if (! ($target_group = Group::LookupByPidGid($project, $group))) {
+	TBERROR("Trying to approve user into unknown group $group", 1);
+    }
+
     #
     # Email info for current user.
-    # 
-    TBUserInfo($uid, $uid_name, $uid_email);
+    #
+    $uid_name  = $this_user->name();
+    $uid_email = $this_user->email();
 
     #
     # Email info for the proj/group leaders too.
     #
-    $leaders = TBLeaderMailList($project,$group);
+    $leaders = $target_group->LeaderMailList();
     
     #
     # Well, looks like everything is okay. Change the project membership
@@ -335,10 +355,7 @@ while (list ($header, $value) = each ($POST_VARS_COPY)) {
         # Must delete the group_membership record since we require that the 
         # user reapply once denied. Send the luser email to let him know.
         #
-        $query_result =
-	    DBQueryFatal("delete from group_membership ".
-			 "where uid='$user' and pid='$project' and ".
-			 "      gid='$group'");
+	$target_group->DeleteMember($target_user);
 
         TBMAIL("$user_name '$user' <$user_email>",
              "Membership Denied in '$project/$group'",
@@ -365,21 +382,17 @@ while (list ($header, $value) = each ($POST_VARS_COPY)) {
         # Must delete the group_membership record since we require that the 
         # user reapply once denied. Send the luser email to let him know.
         #
-        $query_result =
-	    DBQueryFatal("delete from group_membership ".
-			 "where uid='$user' and pid='$project' and ".
-			 "      gid='$group'");
+	$target_group->DeleteMember($target_user);
 
 	#
 	# See if user is in any other projects (even unapproved).
 	#
-        $query_result =
-	    DBQueryFatal("select * from group_membership where uid='$user'");
+	$project_list = $target_user->ProjectMembershipList();
 
 	#
 	# If yes, then we cannot safely delete the user account.
 	#
-	if (mysql_num_rows($query_result)) {
+	if (count($project_list)) {
 	    echo "<p>
                   User $user was <b>denied</b> membership in $project/$group.
                   <br>
@@ -436,11 +449,9 @@ while (list ($header, $value) = each ($POST_VARS_COPY)) {
 	    }
 	    if (!($user_interface = TBGetDefaultProjectUserInterface($project)))
 		$user_interface = TBDB_USER_INTERFACE_EMULAB;
-	    
-	    DBQueryFatal("UPDATE users set ".
-			 "       status='$newstatus', ".
-			 "       user_interface='$user_interface' ".
-			 "WHERE uid='$user'");
+
+	    $target_user->SetUserInterface($user_interface);
+	    $target_user->SetStatus($newstatus);
 
             #
             # Create user account on control node.
diff --git a/www/approveuser_form.php3 b/www/approveuser_form.php3
index a4e27c9b6b5a92041b0b321880c5846fcb9a765a..8d412575e399bf4fa9d4154ced016e55377daec6 100755
--- a/www/approveuser_form.php3
+++ b/www/approveuser_form.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2003 University of Utah and the Flux Group.
+# Copyright (c) 2000-2003, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -9,13 +9,25 @@ include("defs.php3");
 #
 # Standard Testbed Header
 #
-PAGEHEADER("New Users Approval Form");
+PAGEHEADER("New User Approval");
 
 #
 # Only known and logged in users can be verified.
 #
-$auth_usr = GETLOGIN();
-LOGGEDINORDIE($auth_usr);
+$this_user   = CheckLoginOrDie();
+$auth_usr    = $this_user->uid();
+$auth_usridx = $this_user->uid_idx();
+
+#
+# Find all of the groups that this person has project/group root in, and 
+# then in all of those groups, all of the people who are awaiting to be
+# approved (status = none).
+#
+$approvelist = $this_user->ApprovalList(1);
+
+if (count($approvelist) == 0) {
+    USERERROR("You have no new project members who need approval.", 1);
+}
 
 echo "
       <h2>Approve new users in your Project or Group</h2>
@@ -79,44 +91,6 @@ echo "
 
       \n";
 
-#
-# Find all of the groups that this person has project/group root in, and 
-# then in all of those groups, all of the people who are awaiting to be
-# approved (status = none).
-#
-# First off, just determine if this person has group/project root anywhere.
-#
-$query_result =
-    DBQueryFatal("SELECT pid FROM group_membership WHERE uid='$auth_usr' ".
-		 "and (trust='group_root' or trust='project_root')");
-if (mysql_num_rows($query_result) == 0) {
-    USERERROR("You do not have Root permissions in any Project or Group.", 1);
-}
-
-#
-# Okay, so this operation sucks out the right people by joining the
-# group_membership table with itself. Kinda obtuse if you are not a natural
-# DB guy. Sorry. Well, obtuse to me.
-# 
-$query_result =
-    DBQueryFatal("select g.* from group_membership as authed ".
-		 "left join group_membership as g on ".
-		 " g.pid=authed.pid and g.gid=authed.gid ".
-		 "left join users as u on u.uid=g.uid ".
-		 "where u.status!='".
-		 TBDB_USERSTATUS_UNVERIFIED . "' and ".
-		 " u.status!='" . TBDB_USERSTATUS_NEWUSER . 
-		 "' and g.uid!='$auth_usr' and ".
-		 "  g.trust='". TBDB_TRUSTSTRING_NONE . "' ".
-		 "  and authed.uid='$auth_usr' and ".
-		 "  (authed.trust='group_root' or ".
-		 "   authed.trust='project_root') ".
-		 "ORDER BY g.uid,g.pid,g.gid");
-
-if (mysql_num_rows($query_result) == 0) {
-    USERERROR("You have no new project members who need approval.", 1);
-}
-
 #
 # Now build a table with a bunch of selections. The thing to note about the
 # form inside this table is that the selection fields are constructed with
@@ -151,11 +125,22 @@ echo "<tr>
 
 echo "<form action='approveuser.php3' method='post'>\n";
 
-while ($usersrow = mysql_fetch_array($query_result)) {
-    $newuid        = $usersrow[uid];
-    $pid           = $usersrow[pid];
-    $gid           = $usersrow[gid];
-    $date_applied  = $usersrow[date_applied];
+while (list ($uid_idx, $grouplist) = each ($approvelist)) {
+  if (! ($user = User::Lookup($uid_idx))) {
+    TBERROR("Could not lookup user $uid_idx", 1);
+  }
+
+  # Iterate over groups for this user.
+  for ($i = 0; $i < count($grouplist); $i++) {
+    $group        = $grouplist[$i];
+    
+    $newuid       = $user->uid();
+    $gid          = $group->gid();
+    $gid_idx      = $group->gid_idx();
+    $pid          = $group->pid();
+    $pid_idx      = $group->pid_idx();
+
+    $group->MemberShipInfo($user, $trust, $date_applied, $date_approved);
 
     #
     # Cause this field was added late and might be null.
@@ -164,21 +149,17 @@ while ($usersrow = mysql_fetch_array($query_result)) {
 	$date_applied = "--";
     }
 
-    $userinfo_result =
-	DBQueryFatal("SELECT * from users where uid='$newuid'");
-
-    $row	= mysql_fetch_array($userinfo_result);
-    $name	= $row[usr_name];
-    $email	= $row[usr_email];
-    $title	= $row[usr_title];
-    $affil	= $row[usr_affil];
-    $addr	= $row[usr_addr];
-    $addr2	= $row[usr_addr2];
-    $city	= $row[usr_city];
-    $state	= $row[usr_state];
-    $zip	= $row[usr_zip];
-    $country	= $row[usr_country];
-    $phone	= $row[usr_phone];
+    $name	= $user->name();
+    $email	= $user->email();
+    $title	= $user->title();
+    $affil	= $user->affil();
+    $addr	= $user->addr();
+    $addr2	= $user->addr2();
+    $city	= $user->city();
+    $state	= $user->state();
+    $zip	= $user->zip();
+    $country	= $user->country();
+    $phone	= $user->phone();
 
      echo "<tr>
               <td rowspan=2>$newuid</td>
@@ -195,14 +176,16 @@ while ($usersrow = mysql_fetch_array($query_result)) {
               </td>
               <td rowspan=2>
                   <select name=\"$newuid\$\$trust-$pid/$gid\">\n";
-    if (TBCheckGroupTrustConsistency($newuid, $pid, $gid, "user", 0)) {
+     
+    if ($group->CheckTrustConsistency($user, TBDB_TRUSTSTRING_USER, 0)) {
 	echo  "<option value='user'>User </option>\n";
     }
-    if (TBCheckGroupTrustConsistency($newuid, $pid, $gid, "local_root", 0)) {       
+    if ($group->CheckTrustConsistency($user, TBDB_TRUSTSTRING_LOCALROOT, 0)) {
 	# local_root means any root is valid.
         echo  "<option value='local_root'>Local Root </option>\n";
-	if (TBProjAccessCheck($auth_usr, $pid, $gid,
-                              $TB_PROJECT_BESTOWGROUPROOT)) {
+
+	# Allowed to set to group root?
+	if ($group->AccessCheck($this_user, $TB_PROJECT_BESTOWGROUPROOT)) {
 	    echo  "<option value='group_root'>Group Root </option>\n";
 	}
     }	
@@ -225,6 +208,7 @@ while ($usersrow = mysql_fetch_array($query_result)) {
                             &nbsp;$zip&nbsp;
                             &nbsp;$country&nbsp;</td>
           </tr>\n";
+  }
 }
 echo "<tr>
           <td align=center colspan=11>
diff --git a/www/approvewauser.php3 b/www/approvewauser.php3
index cd8a4343c05b7e62633f404585b7549ce286be83..0254350ab2b6cd5899bb608cd99a2df7773db498 100644
--- a/www/approvewauser.php3
+++ b/www/approvewauser.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002 University of Utah and the Flux Group.
+# Copyright (c) 2000-2002, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,9 +14,11 @@ PAGEHEADER("Widearea Accounts Approval Form");
 #
 # Only known and logged in users can be verified.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-if (! ISADMIN($uid)) {
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
+
+if (! $isadmin) {
     USERERROR("Only testbed administrators people can access this page!", 1);
 }
 ignore_user_abort(1);
@@ -77,7 +79,7 @@ while (list ($header, $value) = each ($HTTP_POST_VARS)) {
     #
     # Verify an actual user that is being approved.
     #
-    if (! TBCurrentUser($user)) {
+    if (! ($target_user = User::Lookup($user))) {
 	TBERROR("Trying to approve unknown user $user.", 1);
     }
     
@@ -138,22 +140,19 @@ while (list ($header, $value) = each ($HTTP_POST_VARS)) {
     # and we will change it to "unapproved" or "active", respectively.
     # If the status is "active", we leave it alone. 
     #
-    $query_result =
-        DBQueryFatal("SELECT status,usr_email,usr_name from users where ".
-		     "uid='$user'");
-    if (mysql_num_rows($query_result) == 0) {
-	TBERROR("Unknown user $user", 1);
+    if (! ($target_user = User::Lookup($user))) {
+	TBERROR("Trying to approve unknown user $user.", 1);
     }
-    $row = mysql_fetch_row($query_result);
-    $curstatus  = $row[0];
-    $user_email = $row[1];
-    $user_name  = $row[2];
+    $curstatus  = $target_user->status();
+    $user_email = $target_user->email();
+    $user_name  = $target_user->name();
     #echo "Status = $curstatus, Email = $user_email<br>\n";
 
     #
     # Email info for current user.
-    # 
-    TBUserInfo($uid, $uid_name, $uid_email);
+    #
+    $uid_name  = $this_user->name();
+    $uid_email = $this_user->email();
 
     #
     # Well, looks like everything is okay. Change the project membership
@@ -206,13 +205,12 @@ while (list ($header, $value) = each ($HTTP_POST_VARS)) {
 	#
 	# See if user is in any other projects (even unapproved).
 	#
-        $query_result =
-	    DBQueryFatal("select * from group_membership where uid='$user'");
+	$project_list = $target_user->ProjectMembershipList();
 
 	#
 	# If yes, then we cannot safely delete the user account.
 	#
-	if (mysql_num_rows($query_result)) {
+	if (count($project_list)) {
 	    echo "<p>
                   User $user was <b>denied</b> an account on $node_id.
                   <br>
@@ -238,8 +236,7 @@ while (list ($header, $value) = each ($HTTP_POST_VARS)) {
                   \n";
 	    continue;
 	}
-	
-	$query_result = DBQueryFatal("delete FROM users where uid='$user'");
+	$target_user->Delete();
 	
 	echo "<p>
                 User $user was <b>denied</b> an account on $node_id.
@@ -275,11 +272,11 @@ while (list ($header, $value) = each ($HTTP_POST_VARS)) {
 	    else {
 	        TBERROR("Invalid $user status $curstatus!", 1);
 	    }
-	    $query_result =
-		DBQueryFatal("UPDATE users set status='$newstatus' ".
-			     "WHERE uid='$user'");
+	    $target_user->SetStatus($newstatus);
 	}
 
+	$url = CreateURL("showpubkeys", $target_user);
+
         TBMAIL("$user_name '$user' <$user_email>",
 	       "Widearea account granted on '$node_id' ",
 	       "\n".
@@ -287,7 +284,7 @@ while (list ($header, $value) = each ($HTTP_POST_VARS)) {
 	       "account on $node_id with $newtrust permissions.\n".
 	       "\n".
 	       "In order to log into this node, you must upload an ssh key\n".
-	       "via: ${TBBASE}/showpubkeys.php3?target_uid=$user\n".
+	       "via: ${TBBASE}/$url\n".
 	       "\n\n".
 	       "Thanks,\n".
 	       "Testbed Operations\n",
diff --git a/www/approvewauser_form.php3 b/www/approvewauser_form.php3
index 9e8b8487794dcd12af9a219d412dc7132258c133..56af9af04efdf3d0e9c49f7cfe7cc917c8a6b230 100755
--- a/www/approvewauser_form.php3
+++ b/www/approvewauser_form.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2003 University of Utah and the Flux Group.
+# Copyright (c) 2000-2003, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,9 +14,11 @@ PAGEHEADER("Widearea Accounts Approval Form");
 #
 # Only admin types can use this page.
 #
-$auth_usr = GETLOGIN();
-LOGGEDINORDIE($auth_usr);
-if (! ISADMIN($auth_usr)) {
+$this_user = CheckLoginOrDie();
+$auth_usr  = $this_user->uid();
+$isadmin   = ISADMIN();
+
+if (! $isadmin) {
     USERERROR("Only testbed administrators people can access this page!", 1);
 }
 
@@ -109,9 +111,9 @@ echo "<tr>
 echo "<form action='approvewauser.php3' method='post'>\n";
 
 while ($usersrow = mysql_fetch_array($query_result)) {
-    $newuid        = $usersrow[uid];
-    $node_id       = $usersrow[node_id];
-    $date_applied  = $usersrow[date_applied];
+    $newuid        = $usersrow["uid"];
+    $node_id       = $usersrow["node_id"];
+    $date_applied  = $usersrow["date_applied"];
 
     #
     # Cause this field was added late and might be null.
@@ -120,21 +122,21 @@ while ($usersrow = mysql_fetch_array($query_result)) {
 	$date_applied = "--";
     }
 
-    $userinfo_result =
-	DBQueryFatal("SELECT * from users where uid='$newuid'");
-
-    $row	= mysql_fetch_array($userinfo_result);
-    $name	= $row[usr_name];
-    $email	= $row[usr_email];
-    $title	= $row[usr_title];
-    $affil	= $row[usr_affil];
-    $addr	= $row[usr_addr];
-    $addr2	= $row[usr_addr2];
-    $city	= $row[usr_city];
-    $state	= $row[usr_state];
-    $zip	= $row[usr_zip];
-    $country	= $row[usr_country];
-    $phone	= $row[usr_phone];
+    if (! ($user = User::Lookup($newuid))) {
+	TBERROR("Could not lookup user $uid_idx", 1);
+    }
+
+    $name	= $user->name();
+    $email	= $user->email();
+    $title	= $user->title();
+    $affil	= $user->affil();
+    $addr	= $user->addr();
+    $addr2	= $user->addr2();
+    $city	= $user->city();
+    $state	= $user->state();
+    $zip	= $user->zip();
+    $country	= $user->country();
+    $phone	= $user->phone();
 
     echo "<tr>
               <td colspan=10> </td>
diff --git a/www/archive_control.php3 b/www/archive_control.php3
index a5358abf3c24e559f78ee770a1f4409e14806810..5b65c9b8b40e8d09debf6a0137f5a0aacc49730e 100644
--- a/www/archive_control.php3
+++ b/www/archive_control.php3
@@ -10,9 +10,9 @@ include("showstuff.php3");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/archive_missing.php3 b/www/archive_missing.php3
index 113d4c029f006b44696c81b3100941a70aad4e5b..8c78811f6dd869c0e1ce55ffbb731b8341bd2272 100644
--- a/www/archive_missing.php3
+++ b/www/archive_missing.php3
@@ -10,9 +10,9 @@ include("showstuff.php3");
 #
 # Only known and logged in users can end experiments.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/archive_tag.php3 b/www/archive_tag.php3
index 76f665ce9f9e47c7ee7bd957b05903d954228c89..80f06bf2c5c524c007fd64058b57d018e6b1525d 100644
--- a/www/archive_tag.php3
+++ b/www/archive_tag.php3
@@ -15,9 +15,9 @@ PAGEHEADER("Commit and Tag");
 #
 # Only known and logged in users can look at experiments.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/archive_tags.php3 b/www/archive_tags.php3
index 9727e59c99b3e5e5f06aa42a4ed4ecfab9a997e5..a032089e8dee16d1db7b79ff50df82c0c0493d20 100644
--- a/www/archive_tags.php3
+++ b/www/archive_tags.php3
@@ -15,9 +15,9 @@ PAGEHEADER("Experiment Tags");
 #
 # Only known and logged in users can end experiments.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 # Show just the last N records unless request is different.
 if (!isset($records) || !strcmp($records, "")) {
diff --git a/www/archive_view.php3 b/www/archive_view.php3
index f7dfcee75d86359303466480bf1cbd593fab4f02..bd8c1b48ff25188954c3b07fe32d74e1f230cf80 100644
--- a/www/archive_view.php3
+++ b/www/archive_view.php3
@@ -11,9 +11,9 @@ include_once("template_defs.php");
 #
 # Only known and logged in users can look at experiments.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Standard Testbed Header.
diff --git a/www/beginexp_html.php3 b/www/beginexp_html.php3
index fb47acc7a1731e87ca02c06eb2e675113527e38e..89519998704ddb693f8a085bdcaf9aa712123fd7 100644
--- a/www/beginexp_html.php3
+++ b/www/beginexp_html.php3
@@ -25,10 +25,10 @@ function EXPERROR()
 #
 # Only known and logged in users can begin experiments.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
-# This will not return if its a sajax request.
 include("showlogfile_sup.php3");
 
 #
@@ -48,7 +48,7 @@ $idleswaptimeout = TBGetSiteVar("idle/threshold");
 #
 # See what projects the uid can create experiments in. Must be at least one.
 #
-$projlist = TBProjList($uid, $TB_PROJECT_CREATEEXPT);
+$projlist = $this_user->ProjectAccessList($TB_PROJECT_CREATEEXPT);
 
 if (! count($projlist)) {
     USERERROR("You do not appear to be a member of any Projects in which ".
diff --git a/www/beginexp_xml.php3 b/www/beginexp_xml.php3
index b79e54b8ca027bfe34b940dac9dc9997023f88a8..ccf26d3dcc71b338af793107f5708f790cc5ade5 100644
--- a/www/beginexp_xml.php3
+++ b/www/beginexp_xml.php3
@@ -55,11 +55,12 @@ function XMLSTATUS($status, $message)
 # need to investigate how to make this cleaner, perhaps with a global variable
 # that changes how TBERROR and USERERROR operate. Needs more thought.
 #
-$uid    = GETLOGIN();
-$status = CHECKLOGIN($uid);
-if (($status & CHECKLOGIN_LOGGEDIN) != CHECKLOGIN_LOGGEDIN) {
+$this_user = CheckLogin($status);
+if (!$this_user ||
+    (($status & CHECKLOGIN_LOGGEDIN) != CHECKLOGIN_LOGGEDIN)) {
     EXPERROR("autherror", "Not logged in");
 }
+$uid = $this_user->uid();
 
 # Need this below;
 $idleswaptimeout = TBGetSiteVar("idle/threshold");
@@ -190,7 +191,7 @@ else {
     # I am going to allow shell experiments to be created (No NS file),
     # but only by admin types.
     #
-    if (! ISADMIN($uid)) {
+    if (! ISADMIN()) {
 	$errors["NS File"] = "You must provide an NS file";
     }
 }
@@ -206,7 +207,7 @@ if (!isset($formfields[exp_swappable]) ||
     if (!isset($formfields[exp_noswap_reason]) ||
         !strcmp($formfields[exp_noswap_reason], "")) {
 
-        if (! ISADMIN($uid)) {
+        if (! ISADMIN()) {
 	    $errors["Not Swappable"] = "No justification provided";
         }
 	else {
@@ -228,7 +229,7 @@ if (!isset($formfields[exp_idleswap]) ||
 
     if (!isset($formfields[exp_noidleswap_reason]) ||
 	!strcmp($formfields[exp_noidleswap_reason], "")) {
-	if (! ISADMIN($uid)) {
+	if (! ISADMIN()) {
 	    $errors["Not Idle-Swappable"] = "No justification provided";
 	}
 	else {
@@ -422,11 +423,6 @@ if (isset($formfields[exp_linktest]) && $formfields[exp_linktest] != "") {
     $linktestarg   = "-t " . $formfields[exp_linktest];
 }
 
-#
-# We need the email address for messages below.
-#
-TBUserInfo($uid, $user_name, $user_email);
-
 #
 # Grab the unix GID for running scripts.
 #
diff --git a/www/boot.php3 b/www/boot.php3
index 27af5a04b6004d92c75cd4ab344a2fc9512bf46d..a14e75f98f44e636b09829931c24c063fdbe6e7c 100644
--- a/www/boot.php3
+++ b/www/boot.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,8 +14,9 @@ include("showstuff.php3");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Check to make sure a valid nodeid, *or* a valid experiment.
@@ -105,11 +106,6 @@ if (!$confirmed) {
     return;
 }
 
-#
-# For the audit message.
-#
-TBUserInfo($uid, $uid_name, $uid_email);
-
 if ($nodemode) {
     $message = "$node_id was rebooted via the web interface by $uid\n";
     $subject = "Node Reboot: $node_id";
@@ -150,11 +146,6 @@ if (! $fp) {
     USERERROR("Reboot failed!", 1);
 }
 
-#TBMAIL($TBMAIL_AUDIT,
-#       $subject, $message,
-#       "From: $uid_name <$uid_email>\n".
-#       "Errors-To: $TBMAIL_WWW");
-
 header("Content-Type: text/plain");
 header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
 header("Cache-Control: no-cache, must-revalidate");
diff --git a/www/bootlog.php3 b/www/bootlog.php3
index 7302e650500b65059904d6a94179921aff1f4f83..4a667aeaaacb60c7337c68e8a0d4b99604eb92ef 100644
--- a/www/bootlog.php3
+++ b/www/bootlog.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,9 +14,9 @@ include("showstuff.php3");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Check to make sure a valid nodeid.
diff --git a/www/buildui/bui.php3 b/www/buildui/bui.php3
index 1fd3369ad50b0bb85b0660f8443773084044767f..a1b9c3e0410845f6a5638f5178f69de8825033c0 100644
--- a/www/buildui/bui.php3
+++ b/www/buildui/bui.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2002, 2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 chdir("..");
@@ -12,9 +12,9 @@ PAGEHEADER("NetBuild");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #if (!$isadmin) {
 #    USERERROR("You do not have permission to use this interface!", 1);
diff --git a/www/buildui/nssave.php3 b/www/buildui/nssave.php3
index 88f046e789a1bbc7800fd48e091349ab78d63060..f245fc91ba61edbd01db25c9a3855eb77d589617 100644
--- a/www/buildui/nssave.php3
+++ b/www/buildui/nssave.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002 University of Utah and the Flux Group.
+# Copyright (c) 2000-2002, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 
@@ -11,16 +11,17 @@ include("defs.php3");
 # this is just saving data; it isnt human readable.
 
 #
-# Only known and logged in users can begin experiments.
+# Only known and logged in users.
 #
-
 if (isset($guid) && ereg("^[0-9]+$", $guid)) {
 	$uid = $guid;
-} else {
+}
+else {
 	if (isset($uid)) {
-		$uid = GETLOGIN();
-		LOGGEDINORDIE($uid);
-	} else {
+	        $this_user = CheckLoginOrDie();
+	        $uid       = $this_user->uid();
+	}
+	else {
 		USERERROR( "Need to send guid or uid!" );
         } 
 }
@@ -33,24 +34,6 @@ if (!isset($nsref) || !ereg("^[0-9]+$", $nsref)) {
 	USERERROR( "Need to send valid NSREF!" );
 }
 
-#if (isset($nsdata)) {
-#    if (strcmp($nsdata, "") == 0) 
-#	unset($nsdata);
-#   elseif (! isset($submit))
-# 	$nsdata = rawurlencode($nsdata);
-#}
-
-#$nsfile_safe = addslashes($nsdata);
-#$nsref_safe = addslashes($nsref);
-
-#DBQueryFatal("INSERT INTO nsfiles_transient ".
-#	     "(nsfileid, time, uid, nsfile) ".
-#	     "VALUES ('$nsref_safe', now(), '$uid', '$nsfile_safe') " );
-
-#echo "INSERT INTO nsfiles_transient ".
-#     "(nsfileid, time, uid, nsfile) ".
-#     "VALUES ('$nsref_safe', now(), '$uid', '$nsfile_safe') "; 	 
-
 $nsfilename = "/tmp/$uid-$nsref.nsfile";
 
 if (! ($fp = fopen($nsfilename, "w"))) {
diff --git a/www/cdromqueue.php3 b/www/cdromqueue.php3
index 17ec31712e1b6a5db849676ccf7f7e0bc86b1a0f..4e9446e2d8c5d1423fc36d6267e87967c59acfa8 100644
--- a/www/cdromqueue.php3
+++ b/www/cdromqueue.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002 University of Utah and the Flux Group.
+# Copyright (c) 2000-2002, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -10,9 +10,9 @@ include("showstuff.php3");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 if (!$isadmin) {
     USERERROR("You do not have permission to view this page!", 1);
diff --git a/www/changeuid.php b/www/changeuid.php
index 88cfc01ad022314751ca51646e6d11ef13e406c7..ec7cbfaf5367c233fad16280f59165f6f6226d84 100644
--- a/www/changeuid.php
+++ b/www/changeuid.php
@@ -10,9 +10,9 @@ include("showstuff.php3");
 #
 # Only admin users ...
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 if (!$isadmin) {
     USERERROR("You do not have permission to login names!", 1);
@@ -24,40 +24,43 @@ if (!$isadmin) {
 #
 if (! isset($_POST['submit'])) {
     # First page load. Default to current user.
-    if (! isset($_GET['target_uid']))
-	$target_uid = $uid;
+    if (! isset($_GET['user']))
+	$user = $uid;
     else
-	$target_uid = $_GET['target_uid'];
+	$user = $_GET['user'];
 }
 else {
-    # Form submitted. Make sure we have a target_uid and a new_uid.
-    if (! isset($_POST['target_uid']) || $_POST['target_uid'] == "" ||
+    # Form submitted. Make sure we have a target user and a new_uid.
+    if (! isset($_POST['user']) || $_POST['user'] == "" ||
 	! isset($_POST['new_uid']) || $_POST['new_uid'] == "") {
 	PAGEARGERROR("Invalid form arguments.");
     }
-    $target_uid = $_POST['target_uid'];
-    $new_uid    = $_POST['new_uid'];
+    $user    = $_POST['user'];
+    $new_uid = $_POST['new_uid'];
 }
 
 # Pedantic check of uid before continuing.
-if ($target_uid == "" || !TBvalid_uid($target_uid)) {
-    PAGEARGERROR("Invalid uid: '$target_uid'");
+if ($user == "" || !User::ValidWebID($user)) {
+    PAGEARGERROR("Invalid uid: 'user'");
 }
 
 # Find user. Must be unapproved (verified user). Any other state is too hard.
-if (! ($user = User::LookupByUid($target_uid))) {
-    USERERROR("The user $target_uid is not a valid user", 1);
+if (! ($target_user = User::Lookup($user))) {
+    USERERROR("The user $user is not a valid user", 1);
 }
-if ($user->status() != TBDB_USERSTATUS_UNAPPROVED) {
+$target_uid = $target_user->uid();
+
+if ($target_user->status() != TBDB_USERSTATUS_UNAPPROVED) {
     USERERROR("The user $target_uid must be ".
 	      "unapproved (but verified) to change!", 1);
 }
 
-function SPITFORM($user, $new_uid, $error)
+function SPITFORM($target_user, $new_uid, $error)
 {
     global $TBDB_UIDLEN;
     
-    $target_uid = $user->uid();
+    $target_uid   = $target_user->uid();
+    $target_webid = $target_user->webid();
     
     #
     # Standard Testbed Header.
@@ -93,7 +96,7 @@ function SPITFORM($user, $new_uid, $error)
                            name=submit></b>
              </td>
           </tr>
-	  <input type=hidden name=target_uid value=$target_uid>
+	  <input type=hidden name=user value=$target_webid>
           </form>
           </table>\n";
 
@@ -110,7 +113,7 @@ function SPITFORM($user, $new_uid, $error)
 # If not clicked, then put up a form.
 #
 if (! isset($_POST['submit'])) {
-    SPITFORM($user, "", null);
+    SPITFORM($target_user, "", null);
     return;
 }
 
@@ -120,12 +123,12 @@ $error = null;
 if (!TBvalid_uid($new_uid)) {
     $error = "UID: " . TBFieldErrorString();
 }
-elseif (User::LookupByUid($new_uid) || posix_getpwnam($new_uid)) {
+elseif (User::Lookup($new_uid) || posix_getpwnam($new_uid)) {
     $error = "UID: Already in use. Pick another";
 }
 
 if ($error) {
-    SPITFORM($user, $new_uid, $error);
+    SPITFORM($target_user, $new_uid, $error);
     return;
 }
 
@@ -146,7 +149,7 @@ SUEXEC($uid, $TBADMINGROUP,
 
 # Stop the busy indicator and zap to user page.
 STOPBUSY();
-PAGEREPLACE("showuser.php3?target_uid=$new_uid");
+PAGEREPLACE(CreateURL("showuser", $target_user));
 
 #
 # Standard Testbed Footer
diff --git a/www/chpasswd.php3 b/www/chpasswd.php3
index c8040aa65708ecb683e8fed9929094e7da134193..4cc42a964f8307a940e018cadbc386eea0570261 100644
--- a/www/chpasswd.php3
+++ b/www/chpasswd.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2003, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2003, 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -13,7 +13,7 @@ if (isset($_REQUEST['simple'])) {
 }
 
 # Form arguments.
-$reset_uid = $_REQUEST['reset_uid'];
+$user      = $_REQUEST['user'];
 $keyB      = $_REQUEST['key'];
 # We also need the other half of the key from the browser.
 $keyA      = $HTTP_COOKIE_VARS[$TBAUTHCOOKIE];
@@ -28,7 +28,7 @@ if ((isset($keyB) && $keyB != "") && (!isset($keyA) || $keyA == "")) {
 	      "Knowledge Base Entry</a> to see what the likely cause is.", 1);
 }
 
-if (!isset($reset_uid) || $reset_uid == "" || !TBvalid_uid($reset_uid) ||
+if (!isset($user) || $user == "" || !User::ValidWebID($user) ||
     !isset($keyA) || $keyA == "" || !preg_match("/^[\w]+$/", $keyA) ||
     !isset($keyB) || $keyB == "" || !preg_match("/^[\w]+$/", $keyB)) {
     PAGEARGERROR();
@@ -55,25 +55,25 @@ if ($simple) {
 #
 # Must not be logged in.
 # 
-if (($known_uid = GETUID()) != FALSE) {
-    if (CHECKLOGIN($known_uid) & CHECKLOGIN_LOGGEDIN) {
-	PAGEHEADER("Reset Your Password", $view);
+if (GETLOGIN() != FALSE) {
+    PAGEHEADER("Reset Your Password", $view);
 
-	echo "<h3>
+    echo "<h3>
               You are logged in. You must already know your password!
-              </h3>\n";
+          </h3>\n";
 
-	PAGEFOOTER($view);
-	die("");
-    }
+    PAGEFOOTER($view);
+    die("");
 }
 
 #
 # Spit out the form.
 # 
-function SPITFORM($uid, $key, $failed, $simple, $view)
+function SPITFORM($target_user, $key, $failed, $simple, $view)
 {
     global	$TBBASE;
+
+    $uid = $target_user->uid();
     
     PAGEHEADER("Reset Your Password", $view);
 
@@ -92,10 +92,11 @@ function SPITFORM($uid, $key, $failed, $simple, $view)
               </center>\n";
     }
 
-    $args = "reset_uid=$uid&key=$key&simple=$simple";
+    $chpass_url = CreateURL("chpasswd", $target_user,
+			    "key", $key, "simple", $simple);
 	
     echo "<table align=center border=1>
-          <form action=${TBBASE}/chpasswd.php3?${args} method=post>\n";
+          <form action='${TBBASE}/$chpass_url' method=post>\n";
 
     echo "<tr>
               <td>Password:</td>
@@ -128,26 +129,22 @@ function SPITFORM($uid, $key, $failed, $simple, $view)
 # Check to make sure that the key is valid and that the timeout has not
 # expired.
 #
-$query_result =
-    DBQueryFatal("select chpasswd_key,chpasswd_expires,usr_email,usr_name ".
-		 "   from users ".
-		 "where uid='$reset_uid'");
-# Silent error about invalid users.
-if (!mysql_num_rows($query_result)) {
-    PAGEARGERROR();    
-}
-$row       = mysql_fetch_row($query_result);
-$usr_email = $row[2];
-$usr_name  = $row[3];
+if (! ($target_user = User::Lookup($user))) {
+    # Silent error about invalid users.
+    PAGEARGERROR();
+}
+$usr_email  = $target_user->email();
+$usr_name   = $target_user->name();
+$target_uid = $target_user->uid();
 
 # Silent error when there is no key/timeout set for the user.
-if (!isset($row[0]) || !$row[1]) {
-    PAGEARGERROR();    
+if (!$target_user->chpasswd_key() || !$target_user->chpasswd_expires()) {
+    PAGEARGERROR();
 }
-if ($row[0] != $key) {
+if ($target_user->chpasswd_key() != $key) {
     USERERROR("You do not have permission to change your password!", 1);
 }
-if (time() > $row[1]) {
+if (time() > $target_user->chpasswd_expires()) {
     USERERROR("Your key has expired. Please request a
                <a href='password.php3'>new key</a>.", 1);
 }
@@ -156,7 +153,8 @@ if (time() > $row[1]) {
 # If not clicked, then put up a form.
 #
 if (! isset($reset)) {
-    SPITFORM($reset_uid, $keyB, 0, $simple, $view);
+    SPITFORM($target_user, $keyB, 0, $simple, $view);
+    PAGEFOOTER();
     return;
 }
 
@@ -168,15 +166,21 @@ $password2 = $_POST['password2'];
 
 if (!isset($password1) || $password1 == "" ||
     !isset($password2) || $password2 == "") {
-    SPITFORM($reset_uid, $keyB, "You must supply a password", $simple, $view);
+    SPITFORM($target_user, $keyB,
+	     "You must supply a password", $simple, $view);
+    PAGEFOOTER();
     return;
 }
 if ($password1 != $password2) {
-    SPITFORM($reset_uid, $keyB, "Two passwords do not match", $simple, $view);
+    SPITFORM($target_user, $keyB,
+	     "Two passwords do not match", $simple, $view);
+    PAGEFOOTER();
     return;
 }
-if (! CHECKPASSWORD($reset_uid, $password1, $usr_name, $usr_email, $checkerror)){
-    SPITFORM($reset_uid, $keyB, $checkerror, $simple, $view);
+if (! CHECKPASSWORD($target_uid,
+		    $password1, $usr_name, $usr_email, $checkerror)){
+    SPITFORM($target_user, $keyB, $checkerror, $simple, $view);
+    PAGEFOOTER();
     return;
 }
 
@@ -189,19 +193,21 @@ PAGEHEADER("Reset Your Password", $view);
 $encoding = crypt("$password1");
 $expires  = "date_add(now(), interval 1 year)";
 
-DBQueryFatal("update users set ".
-	     "       chpasswd_key=NULL,chpasswd_expires=0, ".
-	     "       usr_pswd='$encoding',pswd_expires=$expires ".
-	     "where uid='$reset_uid'");
+$target_user->SetPassword($encoding, $expires);
 
-if (HASREALACCOUNT($reset_uid)) {
-    SUEXEC($reset_uid, "nobody", "webtbacct passwd $reset_uid", 1);
+if (HASREALACCOUNT($target_uid)) {
+    STARTBUSY("Resetting your password");
+
+    SUEXEC($target_uid, "nobody", "webtbacct passwd $target_uid",
+	   SUEXEC_ACTION_DIE);
+    
+    CLEARBUSY();
 }
 
 TBMAIL("$usr_name <$usr_email>",
-       "Password Reset for '$reset_uid'",
+       "Password Reset for '$target_uid'",
        "\n".
-       "The password for '$reset_uid' has been reset via the web interface.\n".
+       "The password for '$target_uid' has been reset via the web interface.\n".
        "If this message is unexpected, please contact Testbed Operations\n".
        "($TBMAILADDR_OPS) immediately!\n".
        "\n".
diff --git a/www/clientui.php3 b/www/clientui.php3
index da05af74d9989a79dc47da970345f61380e4ce0a..867e58ff7c0b8fd4fd19940d8c513480090ca888 100644
--- a/www/clientui.php3
+++ b/www/clientui.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2004, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 require("defs.php3");
@@ -20,9 +20,9 @@ PAGEHEADER("NetlabClient", $view);
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 ?>
 
diff --git a/www/currentusage.php3 b/www/currentusage.php3
index d7b6cad42d9bb6171f701f278d82e95e94ee0224..6bbe8dde7122ecfc6fc065b432b611a87cf3d53f 100644
--- a/www/currentusage.php3
+++ b/www/currentusage.php3
@@ -12,8 +12,8 @@ require("Sajax.php");
 
 #
 # Get current user.
-# 
-$uid = GETLOGIN();
+#
+$this_user = CheckLogin($check_status);
 
 #
 # For anonymous users, show experiment stats.
@@ -184,9 +184,9 @@ function SHOWFREENODES()
 # This is for the Sajax request.
 #
 function FreeNodeHtml() {
-    global $uid;
+    global $this_user;
 
-    if ($uid) {
+    if ($this_user) {
 	return SHOWFREENODES();
     }
     else {
@@ -208,7 +208,7 @@ function handle_error($message, $death)
 #
 # If user is anonymous, show experiment stats, otherwise useful info.
 # 
-if ($uid) {
+if ($this_user) {
     sajax_init();
     sajax_export("FreeNodeHtml");
 
diff --git a/www/cvsweb/cvsweb.php3 b/www/cvsweb/cvsweb.php3
index 041952661fd04c8c3947d8ffeacad8d3c481840f..a198fa7c24dea4661c07f88af8233e863158cc57 100644
--- a/www/cvsweb/cvsweb.php3
+++ b/www/cvsweb/cvsweb.php3
@@ -11,12 +11,16 @@
 chdir("../");
 require("defs.php3");
 
+unset($uid);
+unset($repodir);
+
 #
 # We look for anon access, and if so, redirect to ops web server.
 # WARNING: See the LOGGEDINORDIE() calls below.
 #
-$uid = GETLOGIN();
-unset($repodir);
+if (($this_user = CheckLogin($check_status))) {
+     $uid = $this_user->uid();
+}
 
 # Tell system we do not want any headers drawn on errors.
 $noheaders = 1;
@@ -35,8 +39,8 @@ if (isset($pid) && $pid != "") {
 	PAGEARGERROR("Invalid project ID.");
     }
     # Redirect now, to avoid phishing.
-    if ($uid) {
-	LOGGEDINORDIE($uid);
+    if ($this_user) {
+	CheckLoginOrDie();
     }
     else {
 	$url = $OPSCVSURL . "?cvsroot=$pid";
@@ -57,7 +61,7 @@ if (isset($pid) && $pid != "") {
 	if (! TBValidExperiment($pid, $eid)) {
 	    USERERROR("Experiment '$pid/$eid' is not a valid experiment", 1);
 	}
-	if (! ISADMIN($uid) &&
+	if (! ISADMIN() &&
 	    ! TBExptAccessCheck($uid, $pid, $eid, $TB_EXPT_READINFO)) {
 	    USERERROR("Not enough permission to view '$pid/$eid'", 1);
 	}
@@ -82,7 +86,7 @@ if (isset($pid) && $pid != "") {
 	#
 	# Wants access to the project repo.
 	#
-	if (! ISADMIN($uid) &&
+	if (! ISADMIN() &&
 	    ! TBProjAccessCheck($uid, $pid, $gid, $TB_PROJECT_READINFO)) {
             # Then check to see if the project cvs repo is public.
 	    $query_result =
@@ -108,8 +112,8 @@ elseif (isset($exptidx) && $exptidx != "") {
     }
 
     # Must be logged in for this!
-    if ($uid) {
-	LOGGEDINORDIE($uid);
+    if ($this_user) {
+	CheckLoginOrDie();
     }
     
     # Need the pid/eid/gid. Access the stats table since we want to provide
@@ -131,14 +135,14 @@ elseif (isset($exptidx) && $exptidx != "") {
 
     # Lets do group level check since it might not be a current experiment.
     if (!$archived) {
-	if (! ISADMIN($uid) &&
+	if (! ISADMIN() &&
 	    ! TBProjAccessCheck($uid, $pid, $gid, $TB_PROJECT_READINFO)) {
 	    USERERROR("Not enough permission to view '$pid/$eid'", 1);
 	}
 	$repodir = "/usr/testbed/exparchive/$repoidx/repo/";
     }
     else {
-	if (! ISADMIN($uid)) {
+	if (! ISADMIN()) {
 	    USERERROR("Must be administrator to view historical archives!", 1);
 	}
 	$repodir = "/usr/testbed/exparchive/Archive/$repoidx/repo/";
@@ -146,8 +150,8 @@ elseif (isset($exptidx) && $exptidx != "") {
     $use_viewvc = 1;
 }
 else {
-    LOGGEDINORDIE($uid);
-    if (! TBCvswebAllowed($uid)) {
+    $this_user = CheckLoginOrDie();
+    if (! $this_user->cvsweb()) {
         USERERROR("You do not have permission to use cvsweb!", 1);
     }
     unset($pid);
diff --git a/www/cvsweb/cvswebwrap.php3 b/www/cvsweb/cvswebwrap.php3
index a1ff697e592bb1e0406951372019adfee9b76192..7a2a4e745ea52efcc81789f8cd109c099dc026ab 100644
--- a/www/cvsweb/cvswebwrap.php3
+++ b/www/cvsweb/cvswebwrap.php3
@@ -15,11 +15,11 @@ require("defs.php3");
 # We look for anon access, and if so, redirect to ops web server.
 # WARNING: See the LOGGEDINORDIE() calls below.
 #
-$uid = GETLOGIN();
+$this_user = CheckLogin($check_status);
 
 # Redirect now, to avoid phishing.
-if ($uid) {
-    LOGGEDINORDIE($uid);
+if ($this_user) {
+    CheckLoginOrDie();
 }
 else {
     $url = $OPSCVSURL . "?cvsroot=$pid";
diff --git a/www/dbcheck.php3 b/www/dbcheck.php3
index e9b19ab9ad5f9e3829bbad566cb4ef8cd4f1bb58..83ebd081f78ae3f8c9334e7f68783658623381b5 100644
--- a/www/dbcheck.php3
+++ b/www/dbcheck.php3
@@ -184,6 +184,9 @@ function TBvalid_uid($token) {
     return TBcheck_dbslot($token, "users", "uid",
 			  TBDB_CHECKDBSLOT_WARN|TBDB_CHECKDBSLOT_ERROR);
 }
+function TBvalid_uididx($token) {
+    return TBvalid_integer($token);
+}
 #
 # Used to allow _ (underscore), but no more.
 # 
diff --git a/www/dbdefs.php3.in b/www/dbdefs.php3.in
index bf93b21daf4a85c1e1224541a67a4746e0810377..35f9426e83bb6cb2587ef6e61ae51a36bbca1174 100644
--- a/www/dbdefs.php3.in
+++ b/www/dbdefs.php3.in
@@ -54,6 +54,14 @@ define("TBDB_USERSTATUS_UNAPPROVED",	"unapproved");
 define("TBDB_USERSTATUS_UNVERIFIED",	"unverified");
 define("TBDB_USERSTATUS_FROZEN",	"frozen");
 
+#
+# Type of new account.
+#
+define("TBDB_NEWACCOUNT_REGULAR",	0x0);
+define("TBDB_NEWACCOUNT_PROJLEADER",	0x1);
+define("TBDB_NEWACCOUNT_WIKIONLY",	0x2);
+define("TBDB_NEWACCOUNT_WEBONLY",	0x4);
+
 #
 # Trust. Define the trust level as an increasing value. Then define a
 # function to return whether the given trust is high enough.
@@ -247,8 +255,6 @@ function TBMinTrust($trust_value, $minimum)
 # 
 function TBGrpTrust($uid, $pid, $gid)
 {
-    global $TBDB_TRUST_NONE;
-
     #
     # No group, then use the default group.
     #
@@ -256,20 +262,17 @@ function TBGrpTrust($uid, $pid, $gid)
 	$gid = $pid;
     }
 
-    $query_result =
-	DBQueryFatal("select trust from group_membership ".
-		     "where uid='$uid' and pid='$pid' and gid='$gid'");
-
     #
-    # No membership is the same as no trust. True? Maybe an error instead?
-    # 
-    if (mysql_num_rows($query_result) == 0) {
-	return $TBDB_TRUST_NONE;
+    # Until all this code is fixed, pass this off to the group object
+    #
+    if (! ($group = Group::LookupByPidGid($pid, $gid))) {
+        TBERROR("TBGrpTrust: Could not look up group object for $pid/$eid!",1);
     }
-    $row = mysql_fetch_array($query_result);
-    $trust_string = $row[trust];
-
-    return TBTrustConvert($trust_string);
+    
+    if (! ($user = User::Lookup($uid))) {
+        TBERROR("TBGrpTrust: Could not look up user object for $uid!", 1);
+    }
+    return $group->UserTrust($user);
 }
 
 #
@@ -321,7 +324,7 @@ function TBProjAccessCheck($uid, $pid, $gid, $access_type)
     #
     # Admins do whatever they want!
     # 
-    if (ISADMIN($uid)) {
+    if (ISADMIN()) {
 	return 1;
     }
 
@@ -416,103 +419,6 @@ function TBProjAccessCheck($uid, $pid, $gid, $access_type)
 }
 
 
-#
-# Checks proposed Group trust change for consistency.
-#
-# Usage: TBCheckGroupTrustConsistency($user, $pid, $gid, $newtrust, $fail) 
-#        returns 1 if proposed change is valid
-#        returns 0 if proposed change is invalid and $fail == 0
-#        does not return if proposed change is invalid and $fail == 1.
-#
-
-function TBCheckGroupTrustConsistency($user, $pid, $gid, $newtrust, $fail)
-{
-    global $TBDB_TRUST_USER;
-
-    # 
-    # set $newtrustisroot to 1 if attempting to set a rootful trust,
-    # 0 otherwise.
-    #
-    $newtrustisroot = TBTrustConvert($newtrust) > $TBDB_TRUST_USER ? 1 : 0;
-
-    #
-    # If changing subgroup trust level, then compare levels.
-    # A user may not have root privs in the project and user privs
-    # in the subgroup; it makes no sense to do that and can violate trust.
-    #
-    if (strcmp($pid, $gid)) {
-	#
-	# Setting non-default "sub"group.
-	# Verify that if user has root in project,
-	# we are setting a rootful trust for him in 
-	# the subgroup as well.
-	#
-	$projtrustisroot = TBProjTrust($user, $pid) > $TBDB_TRUST_USER ? 1 : 0;
-
-	if ($projtrustisroot > $newtrustisroot) {
-	    if (!$fail) { return 0; }
-	    TBERROR("User $user may not have a root trust level in ".
-		      "the default group of $pid, ".
-		      "yet be non-root in subgroup $gid!", 1);
-	}
-    }
-    else {
-	#
-	# Setting default group.
-	# Do not verify anything (yet.)
-	#
-	$projtrustisroot = $newtrustisroot;
-    }
-
-    #
-    # Get all the subgroups not equal to the subgroup being changed.
-    # 
-    $query_result =
-	DBQueryFatal("select trust,gid from group_membership ".
-		     "where uid='$user' and pid='$pid' and trust!='none' ".
-		     " and gid!=pid and gid!='$gid'");
-
-    while ($row = mysql_fetch_array($query_result)) {
-	$grptrust = $row[0];
-	$ogid     = $row[1];
-	
-	# 
-	# Get what the users trust level is in the 
-	# current subgroup we're looking at.
-	#
-	$grptrustisroot = 
-	    TBTrustConvert( $grptrust ) > $TBDB_TRUST_USER ? 1 : 0;
-
-	#
-	# If users trust level is higher in the default group than in the
-	# subgroup we are looking at, this is wrong.
-	#
-	if ($projtrustisroot > $grptrustisroot) {
-	    if (!$fail) { return 0; }
-	    TBERROR("User $user may not have a root trust level in ".
-		      "the default group of $pid, ".
-		      "yet be non-root in subgroup $ogid!", 1);
-	}
-
-	if (strcmp($pid, $gid)) {
-            #
-	    # Iff we are modifying a subgroup, 
-	    # Make sure that the trust we are setting is as
-	    # rootful as the trust we already have set in
-	    # every other subgroup.
-	    # 
-	    if ($newtrustisroot != $grptrustisroot) { 
-		if (!$fail) { return 0; }
-		TBERROR("User $user may not mix root and ".
-			  "non-root trust levels in ".
-			  "different subgroups of $pid!", 1);
-	    }
-	}
-    }
-    return 1;
-}
-
-
 # Usage: TBExptGroup($pid, $eid, &$gid)
 #	 returns 0 if expt does not exist.
 #        returns 1 if expt exists.
@@ -558,20 +464,19 @@ function TBExptAccessCheck($uid, $pid, $eid, $access_type)
     #
     # Admins do whatever they want!
     # 
-    if (ISADMIN($uid)) {
+    if (ISADMIN()) {
 	return 1;
     }
 
     $query_result =
-	DBQueryFatal("SELECT gid,expt_head_uid FROM experiments WHERE ".
+	DBQueryFatal("SELECT gid FROM experiments WHERE ".
 		     "eid='$eid' and pid='$pid'");
     
     if (mysql_num_rows($query_result) == 0) {
 	return 0;
     }
     $row  = mysql_fetch_array($query_result);
-    $gid  = $row[gid];
-    $head = $row[expt_head_uid];
+    $gid  = $row["gid"];
 
     if ($access_type == $TB_EXPT_READINFO) {
 	$mintrust = $TBDB_TRUST_USER;
@@ -610,6 +515,7 @@ function TBNodeAccessCheck($uid, $node_id, $access_type)
     global $TBDB_TRUST_GROUPROOT;
     global $TBDB_TRUST_LOCALROOT;
     global $TBOPSPID;
+    global $CHECKLOGIN_USER;
     $mintrust;
 
     if ($access_type < $TB_NODEACCESS_MIN ||
@@ -628,7 +534,7 @@ function TBNodeAccessCheck($uid, $node_id, $access_type)
 	# If the current user is in the emulab-ops project and has sufficient
 	# privs, then he can muck with free nodes as if he were an admin type.
 	#
-	if ($uid == GETUID() && OPSGUY()) {
+	if ($uid == $CHECKLOGIN_USER->uid() && OPSGUY()) {
 	    return(TBMinTrust(TBGrpTrust($uid, $TBOPSPID, $TBOPSPID),
 			      $TBDB_TRUST_LOCALROOT));
 	}
@@ -648,54 +554,6 @@ function TBNodeAccessCheck($uid, $node_id, $access_type)
 	TBMinTrust(TBGrpTrust($uid, $pid, $pid), $TBDB_TRUST_GROUPROOT);
 }
 
-#
-# Determine if uid can access a another user record (read or modify).
-#
-# Usage: TBUserInfoAccessCheck($uid, $target_uid, $access_type)
-#	 returns 0 if not allowed.
-#        returns 1 if allowed.
-# 
-function TBUserInfoAccessCheck($uid, $target_uid, $access_type)
-{
-    global $TB_USERINFO_READINFO;
-    global $TB_USERINFO_MODIFYINFO;
-    global $TB_USERINFO_MIN;
-    global $TB_USERINFO_MAX;
-
-    if ($access_type < $TB_USERINFO_MIN || $access_type > $TB_USERINFO_MAX) {
-	TBERROR("Invalid access type $access_type!", 1);
-    }
-
-    if (strcmp($uid, $target_uid) == 0) {
-	return 1;
-    }
-
-    #
-    # Admins do whatever they want!
-    # 
-    if (ISADMIN($uid)) {
-	return 1;
-    }
-
-    #
-    # This join will allow the operation if the current user is in the same
-    # group (any group) as the target user, but with root permissions.
-    # 
-    $query_result =
-	DBQueryFatal("select g.trust from group_membership as g ".
-		     "left join group_membership as authed on ".
-		     "     g.pid=authed.pid and g.gid=authed.gid and ".
-		     "     g.uid='$target_uid' ".
-		     "where authed.uid='$uid' and ".
-		     "      (authed.trust='group_root' or ".
-		     "       authed.trust='project_root')");
-
-    if (mysql_num_rows($query_result) == 0) {
-	return 0;
-    }
-    return 1;
-}
-
 #
 # Access checks for an OSID. Tests for tbadmin.
 #
@@ -721,7 +579,7 @@ function TBOSIDAccessCheck($uid, $osid, $access_type)
     #
     # Admins do whatever they want!
     # 
-    if (ISADMIN($uid)) {
+    if (ISADMIN()) {
 	return 1;
     }
 
@@ -788,7 +646,7 @@ function TBImageIDAccessCheck($uid, $imageid, $access_type)
     #
     # Admins do whatever they want!
     # 
-    if (ISADMIN($uid)) {
+    if (ISADMIN()) {
 	return 1;
     }
 
@@ -854,91 +712,6 @@ function TBGroupUnixInfo($pid, $gid, &$unix_gid, &$unix_name)
     $unix_name = $row[unix_name];
 }
 
-#
-# Get name and email info for a uid. Args are pass by reference.
-#
-# usage: TBUserInfo($uid, $user_name, $user_email)
-#
-function TBUserInfo($uid, &$user_name, &$user_email)
-{
-    $query_result =
-	DBQueryFatal("select usr_name,usr_email from users where uid='$uid'");
-
-    if (mysql_num_rows($query_result) == 0) {
-	TBERROR("No such user $uid!", 1);
-    }
-    $row = mysql_fetch_array($query_result);
-    $user_name  = $row[usr_name];
-    $user_email = $row[usr_email];
-}
-
-#
-# Confirm a current user or not.
-#
-# usage TBCurrentUser($uid)
-#       returns 1 if a valid user.
-#       returns 0 if not a valid user.
-#
-function TBCurrentUser($uid)
-{
-    $current_result =
-	DBQueryFatal("SELECT usr_pswd FROM users WHERE uid='$uid'");
-
-    $deleted_result =
-	DBQueryFatal("SELECT usr_name FROM deleted_users WHERE uid='$uid'");
-
-    return mysql_num_rows($current_result) + mysql_num_rows($deleted_result);
-}
-
-#
-# Confirm a current WikiName or not.
-#
-# usage TBCurrentWikiName($uid)
-#       returns 1 if a current wikiname.
-#       returns 0 if not a current wikiname
-#
-function TBCurrentWikiName($wikiname)
-{
-    $query_result =
-	DBQueryFatal("SELECT usr_pswd FROM users WHERE wikiname='$wikiname'");
-
-    return mysql_num_rows($query_result);
-}
-
-#
-# Check to see if an email is being used twice.
-#
-# usage TBCurrentEmail($email)
-#       returns 1 if a valid email for someone.
-#       returns 0 if no such email address used by anyone.
-#
-function TBCurrentEmail($email)
-{
-    $query_result =
-	DBQueryFatal("SELECT uid FROM users WHERE usr_email='$email'");
-
-    return mysql_num_rows($query_result);
-}
-
-#
-# Get user status,
-#
-# usage TBUserStatus($uid)
-#       returns status if a valid user.
-#       returns 0 if not a valid user.
-#
-function TBUserStatus($uid)
-{
-    $query_result =
-	DBQueryFatal("SELECT status FROM users WHERE uid='$uid'");
-
-    if (! mysql_num_rows($query_result)) {
-	return 0;
-    }
-    $row = mysql_fetch_row($query_result);
-    return $row[0];
-}
-
 #
 # Confirm a valid pid/gid
 #
@@ -979,33 +752,6 @@ function TBValidProject($pid)
     return TBValidGroup($pid, $pid);
 }
 
-#
-# Confirm a group member.
-#
-# usage TBGroupMember($uid, $pid, $gid, &$approved)
-#       returns 1 if a member.
-#       returns 0 if not a member.
-#
-function TBGroupMember($uid, $pid, $gid, &$approved)
-{
-    global $TBDB_TRUST_USER;
-	
-    $approved = 0;
-    
-    $query_result =
-	DBQueryFatal("select trust from group_membership ".
-		     "where uid='$uid' and pid='$pid' and gid='$gid'");
-
-    if (mysql_num_rows($query_result) == 0) {
-	return 0;
-    }
-    $row = mysql_fetch_row($query_result);
-    $trust = $row[0];
-
-    $approved = TBMinTrust($trust, $TBDB_TRUST_USER);
-    return 1;
-}
-
 #
 # Confirm a valid OS Descriptor in the specified project.
 #
@@ -1193,37 +939,6 @@ function TBValidNodeType($type)
     return 1;
 }
 
-#
-# Return mail addresses for project_root and group_root people.
-#
-# usage TBLeaderMailList($pid, $gid)
-#       Uses default group (pid=gid) if gid not given.
-#       returns string like "Leader Name (uid) <email>[, ...]"
-#       returns the empty string if not valid
-function TBLeaderMailList($pid, $gid)
-{
-  # No group, then use the default group.
-  if (! $gid) { $gid = $pid; }
-  
-  $query_result =
-    DBQueryFatal("select distinct usr_name,u.uid,usr_email from users as u ".
-		 "left join group_membership as gm on gm.uid=u.uid ".
-		 "where (trust='". TBDB_TRUSTSTRING_PROJROOT .
-		 "' and pid='$pid') or (trust='". TBDB_TRUSTSTRING_GROUPROOT .
-		 "' and pid='$pid' and gid='$gid') ".
-		 "order by trust DESC, usr_name");
-  
-  if (mysql_num_rows($query_result) == 0) {
-    return "";
-  }
-  $mailstr="";
-  while ($row = mysql_fetch_array($query_result)) {
-    if ($mailstr != "") { $mailstr .=", "; }
-    $mailstr .= '"'.$row[usr_name]." (".$row[uid].")\" <".$row[usr_email].">";
-  }
-  return $mailstr;
-}
-
 #
 # Return Project Leader.
 #
@@ -1289,68 +1004,6 @@ function TBExpLeader($pid, $eid, &$expleader)
     return 1;
 }
 
-#
-# Return a list of projects for which the uid is allowed to perform the
-# requested operation. Only a couple of access options are supported since
-# to be totally general would require too many DB operations. Not worth
-# the effort or the expense.
-#
-# Returns an indexed array (by pid) of lists (of gids).
-#
-function TBProjList($uid, $access_type)
-{
-    global $TB_PROJECT_CREATEEXPT;
-    global $TB_PROJECT_MAKEOSID;
-    global $TB_PROJECT_MAKEIMAGEID;
-    global $TB_PROJECT_MAKEGROUP;
-    global $TB_PROJECT_READINFO;
-    $result = array();
-    $user_clause = "where uid='$uid' and";
-    
-    if ($access_type == $TB_PROJECT_READINFO) {
-	$trust_clause = "trust!='none'";
-    }
-    elseif ($access_type == $TB_PROJECT_MAKEGROUP) {
-	$trust_clause = "trust='project_root'";
-    }
-    elseif ($access_type == $TB_PROJECT_CREATEEXPT) {
-	$trust_clause = "(trust='project_root' or trust='group_root' or ".
-	                " trust='local_root')";
-    }
-    elseif ($access_type == $TB_PROJECT_MAKEOSID ||
-	    $access_type == $TB_PROJECT_MAKEIMAGEID) {
-        if (ISADMIN($uid)) {
-            $user_clause = "";
-	}
-        else {
-  	    $trust_clause = "(trust='project_root' or trust='group_root' or ".
-	                    " trust='local_root')";
-        }
-    }
-    else {
-	TBERROR("Invalid access type $access_type!", 1);
-    }
-    
-    $query_result =
-	DBQueryFatal("SELECT distinct pid,gid FROM group_membership ".
-		     "$user_clause $trust_clause order by pid");
-
-    if (mysql_num_rows($query_result) == 0) {
-	return $result;
-    }
-
-    $i = 0;
-    while ($row = mysql_fetch_array($query_result)) {
-	$pid = $row['pid'];
-	$gid = $row['gid'];
-	
-	$result[$pid][] = $gid;
-
-	$i++;
-    }
-    return $result;
-}
-
 function TBExptState($pid, $eid)
 {
     $query_result =
@@ -1596,30 +1249,6 @@ function TBExptLogFile($pid, $eid)
     return $row[0];
 }
 
-function TBWebdbAllowed($uid) {
-    $query_result =
-        DBQueryFatal("select dbedit from users ".
-		     "WHERE uid='$uid' and dbedit=1");
-
-    return mysql_num_rows($query_result);
-}
-
-function TBCvswebAllowed($uid) {
-    $query_result =
-        DBQueryFatal("select cvsweb from users ".
-		     "WHERE uid='$uid' and cvsweb=1");
-
-    return mysql_num_rows($query_result);
-}
-
-function TBWikiOnlyUser($uid) {
-    $query_result =
-        DBQueryFatal("select wikionly from users ".
-		     "WHERE uid='$uid' and wikionly=1");
-
-    return mysql_num_rows($query_result);
-}
-
 #
 # Returns > 0 if a node has a serial console, 0 if it does not
 #
@@ -1629,30 +1258,6 @@ function TBHasSerialConsole($node_id) {
     return mysql_num_rows($query_result);
 }
 
-#
-# Generate a verification key, and stash it in the database
-#
-function TBGenVerificationKey($name) {
-    $key = md5(uniqid(rand(),1));
-    DBQueryFatal("update users set verify_key='$key' where uid='$name'");
-    return $key;
-}
-
-#
-# Get a verification key from the database
-#
-function TBGetVerificationKey($name) {
-    $query_result =
-	DBQueryFatal("select verify_key from users where uid='$name'");
-
-    if (mysql_num_rows($query_result) == 0) {
-	# Can we signal error somehow?
-	return "";
-    }
-    $row   = mysql_fetch_array($query_result);
-    return $row[verify_key];
-}
-
 #
 # Map IP to nodeid.
 #
@@ -2020,20 +1625,6 @@ function TBExptFirewall($pid, $eid) {
     return 1;
 }
 
-#
-# See if user has enough permission to view the webcams. If not an admin
-# person, then must be a project with permission to use the robots.
-# Eventually this needs to be a much more restrictive test.
-#
-function TBWebCamAllowed($uid) {
-    $query_result =
-	DBQueryFatal("select distinct class from group_membership as g ".
-		     "left join nodetypeXpid_permissions as p on g.pid=p.pid ".
-		     "left join node_types as nt on nt.type=p.type ".
-		     "where uid='$uid' and class='robot'");
-    return mysql_num_rows($query_result);
-}
-
 #
 # Return lockeddown bit
 #
@@ -2121,20 +1712,6 @@ function NodeTypeAttribute($type, $key, &$value)
     return 1;
 }
 
-#
-# Is email address unique?
-#
-function TBUniqueEmail($uid, $email)
-{
-    $query_result =
-	DBQueryFatal("select usr_email from users where ".
-		     "usr_email='$email' and uid!='$uid'");
-
-    if (mysql_num_rows($query_result))
-	return 0;
-    return 1;
-}
-
 #
 # Return a unique index from emulab_indicies for the indicated name.
 # Updates the index to be, well, unique.
diff --git a/www/defs.php3.in b/www/defs.php3.in
index 9f735e29862ebd005ab6f138193a87c19ecd1592..52f9ab3e0111d17d403f7904cf02b483bdc50a16 100644
--- a/www/defs.php3.in
+++ b/www/defs.php3.in
@@ -120,6 +120,7 @@ $RSS_HEADER_NEWS = "<link rel=\"alternate\" type=\"application/rss+xml\" " .
 # Database constants and the like.
 #
 include("dbdefs.php3");
+include("url_defs.php");
 include("user_defs.php");
 include("group_defs.php");
 include("project_defs.php");
diff --git a/www/delaycontrol.php3 b/www/delaycontrol.php3
index aa0ba3e37564e4bf2fca1f82b930469129097e7f..21f693c1d6031ddc47af84a27fb13a6cd0e45135 100644
--- a/www/delaycontrol.php3
+++ b/www/delaycontrol.php3
@@ -14,9 +14,9 @@ PAGEHEADER("Delay Control");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Must provide the PID/EID!
diff --git a/www/deletegroup.php3 b/www/deletegroup.php3
index b1194f57f73bb5821683599baf8db7abf4f74a23..2277c5959fce3e55069b0d7cc4bf1228b693634b 100644
--- a/www/deletegroup.php3
+++ b/www/deletegroup.php3
@@ -14,8 +14,9 @@ PAGEHEADER("Delete a Group");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # First off, sanity check page args.
diff --git a/www/deleteimageid.php3 b/www/deleteimageid.php3
index 9f5f1a6fe48e80436b8771b7c3ce032d2350e8b3..1ddee2d5ffd1d4c22e8d3baf9120c2ed0c312f1b 100644
--- a/www/deleteimageid.php3
+++ b/www/deleteimageid.php3
@@ -14,8 +14,9 @@ PAGEHEADER("Delete an Image Descriptor");
 #
 # Only known and logged in users can end experiments.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Must provide the ImageID.
diff --git a/www/deletenodelog.php3 b/www/deletenodelog.php3
index 1cb97c474053c43815826fe64326672761e0e0b7..d24533e3a452ae0036fef4ec8e6ece737337874d 100644
--- a/www/deletenodelog.php3
+++ b/www/deletenodelog.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2002, 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -15,9 +15,9 @@ PAGEHEADER("Delete a Node Log Entry");
 #
 # Only known and logged in users can end experiments.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Must provide the IDs
diff --git a/www/deleteosid.php3 b/www/deleteosid.php3
index 260e64558f9c791996741c4524b0c470cdf79ca3..955af1d63c9fa9964f3aaa9cee7a954495eeea38 100644
--- a/www/deleteosid.php3
+++ b/www/deleteosid.php3
@@ -14,8 +14,9 @@ PAGEHEADER("Delete an OS Descriptor");
 #
 # Only known and logged in users can end experiments.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Must provide the OSID!
diff --git a/www/deleteproject.php3 b/www/deleteproject.php3
index d7fa2ce042de3d2c01bb06f098742d021901b2f5..b4152a6399aea0a425e2effa6fdd76c702c0ceea 100644
--- a/www/deleteproject.php3
+++ b/www/deleteproject.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2003 University of Utah and the Flux Group.
+# Copyright (c) 2000-2003, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,13 +14,13 @@ PAGEHEADER("Terminating Project and Remove all Trace");
 #
 # Only known and logged in users can end experiments.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Currently, only admin users can do this. Change later.
 #
-$isadmin = ISADMIN($uid);
 if (! $isadmin) {
     USERERROR("You do not have permission to remove project '$pid'", 1);
 }
diff --git a/www/deletepubkey.php3 b/www/deletepubkey.php3
index 93a2675ddbec31483ab3ec727f03e4edb1512dd3..b596b99fff0d3e0ea322f3601f3c5712c2cb41ed 100644
--- a/www/deletepubkey.php3
+++ b/www/deletepubkey.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2003 University of Utah and the Flux Group.
+# Copyright (c) 2000-2003, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,16 +14,16 @@ include("showstuff.php3");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid, CHECKLOGIN_USERSTATUS|CHECKLOGIN_WEBONLY);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie(CHECKLOGIN_USERSTATUS|CHECKLOGIN_WEBONLY);
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 # Page arguments.
-$target_uid = $_GET['target_uid'];
-$key        = $_GET['key'];
+$user = $_GET['user'];
+$key  = $_GET['key'];
 
 # Pedantic argument checking.
-if (!isset($target_uid) || $target_uid == "" || !TBvalid_uid($target_uid) ||
+if (!isset($user) || $user == "" || !User::ValidWebID($user) ||
     !isset($key) || $key == "" || !preg_match("/^[\d]+$/", $key)) {
     PAGEARGERROR();
 }
@@ -31,20 +31,19 @@ if (!isset($target_uid) || $target_uid == "" || !TBvalid_uid($target_uid) ||
 #
 # Check to make sure thats this is a valid UID.
 #
-if (! TBCurrentUser($target_uid)) {
-    USERERROR("The user $target_uid is not a valid user", 1);
+if (! ($target_user = User::Lookup($user))) {
+    USERERROR("The user $user is not a valid user", 1);
 }
+$target_dbuid = $target_user->uid();
+$target_uid   = $target_user->uid();
 
 #
 # Verify that this uid is a member of one of the projects that the
-# target_uid is in. Must have proper permission in that group too. 
+# user is in. Must have proper permission in that group too. 
 #
-if (!$isadmin &&
-    strcmp($uid, $target_uid)) {
-
-    if (! TBUserInfoAccessCheck($uid, $target_uid, $TB_USERINFO_MODIFYINFO)) {
-	USERERROR("You do not have permission to change ${user}'s keys!", 1);
-    }
+if (!$isadmin && 
+    !$target_user->AccessCheck($this_user, $TB_USERINFO_MODIFYINFO)) {
+    USERERROR("You do not have permission!", 1);
 }
 
 #
@@ -52,7 +51,7 @@ if (!$isadmin &&
 #
 $query_result =
     DBQueryFatal("select * from user_pubkeys ".
-		 "where uid='$target_uid' and idx='$key'");
+		 "where uid='$target_dbuid' and idx='$key'");
 
 if (! mysql_num_rows($query_result)) {
     USERERROR("Public Key for user '$target_uid' does not exist!", 1);
@@ -75,9 +74,10 @@ if ($canceled) {
           SSH Public Key deletion canceled!
           </h2></center>\n";
 
+    $url = CreateURL("showpubkeys", $target_user);
+
     echo "<br>
-          Back to <a href='showpubkeys.php3?target_uid=$target_uid'>
-                 ssh public keys</a> for user '$uid'.\n";
+          Back to <a href='$url'>ssh public keys</a> for user '$uid'.\n";
     
     PAGEFOOTER();
     return;
@@ -90,9 +90,10 @@ if (!$confirmed) {
           Are you <b>REALLY</b>
           sure you want to delete this SSH Public Key for user '$target_uid'?
           </h3>\n";
+
+    $url = CreateURL("deletepubkey", $target_user, "key", $key);
     
-    echo "<form action='deletepubkey.php3?target_uid=$target_uid&key=$key'
-                method=post>";
+    echo "<form action='$url' method=post>";
     echo "<b><input type=submit name=confirmed value=Confirm></b>\n";
     echo "<b><input type=submit name=canceled value=Cancel></b>\n";
     echo "</form>\n";
@@ -111,8 +112,11 @@ if (!$confirmed) {
 #
 # Audit
 #
-TBUserInfo($uid, $uid_name, $uid_email);
-TBUserInfo($target_uid, $targuid_name, $targuid_email);
+$uid_name  = $this_user->name();
+$uid_email = $this_user->email();
+
+$targuid_name  = $target_user->name();
+$targuid_email = $target_user->email();
 
 TBMAIL("$targuid_name <$targuid_email>",
      "SSH Public Key for '$target_uid' Deleted",
@@ -128,7 +132,7 @@ TBMAIL("$targuid_name <$targuid_email>",
      "Errors-To: $TBMAIL_WWW");
 
 DBQueryFatal("delete from user_pubkeys ".
-	     "where uid='$target_uid' and idx='$key'");
+	     "where uid='$target_dbuid' and idx='$key'");
 
 #
 # update authkeys files and nodes, but only if user has a real account.
@@ -140,6 +144,6 @@ if (HASREALACCOUNT($target_uid)) {
     ADDPUBKEY($uid, "webaddpubkey -w $target_uid");
 }
 
-header("Location: showpubkeys.php3?target_uid=$target_uid");
+header("Location: " . CreateURL("showpubkeys", $target_user));
 
 ?>
diff --git a/www/deletesfskey.php3 b/www/deletesfskey.php3
index 8792552cd7e39b3c2b9d66065caff84c22516362..493ad2c2513da3d06a6a9a2a9935ce956cffc763 100644
--- a/www/deletesfskey.php3
+++ b/www/deletesfskey.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2003 University of Utah and the Flux Group.
+# Copyright (c) 2000-2003, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,16 +14,16 @@ include("showstuff.php3");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid, CHECKLOGIN_USERSTATUS|CHECKLOGIN_WEBONLY);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie(CHECKLOGIN_USERSTATUS|CHECKLOGIN_WEBONLY);
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 # Page arguments.
-$target_uid = $_GET['target_uid'];
-$key        = $_GET['key'];
+$user = $_GET['user'];
+$key  = $_GET['key'];
 
 # Pedantic argument checking.
-if (!isset($target_uid) || $target_uid == "" || !TBvalid_uid($target_uid) ||
+if (!isset($user) || $user == "" || !User::ValidWebID($user) ||
     !isset($key) || $key == "" || !preg_match("/^[-\w\.\@\#]+$/", $key)) {
     PAGEARGERROR();
 }
@@ -31,20 +31,19 @@ if (!isset($target_uid) || $target_uid == "" || !TBvalid_uid($target_uid) ||
 #
 # Check to make sure thats this is a valid UID.
 #
-if (! TBCurrentUser($target_uid)) {
-    USERERROR("The user $target_uid is not a valid user", 1);
+if (! ($target_user = User::Lookup($user))) {
+    USERERROR("The user $user is not a valid user", 1);
 }
+$target_dbuid = $target_user->uid();
+$target_uid   = $target_user->uid();
 
 #
 # Verify that this uid is a member of one of the projects that the
 # target_uid is in. Must have proper permission in that group too. 
 #
-if (!$isadmin &&
-    strcmp($uid, $target_uid)) {
-
-    if (! TBUserInfoAccessCheck($uid, $target_uid, $TB_USERINFO_MODIFYINFO)) {
-	USERERROR("You do not have permission to change ${user}'s keys!", 1);
-    }
+if (!$isadmin && 
+    !$target_user->AccessCheck($this_user, $TB_USERINFO_MODIFYINFO)) {
+    USERERROR("You do not have permission!", 1);
 }
 
 #
@@ -52,7 +51,7 @@ if (!$isadmin &&
 #
 $query_result =
     DBQueryFatal("select * from user_sfskeys ".
-		 "where uid='$target_uid' and comment='$key'");
+		 "where uid='$target_dbuid' and comment='$key'");
 
 if (! mysql_num_rows($query_result)) {
     USERERROR("SFS Key '$key' for user '$target_uid' does not exist!", 1);
@@ -76,9 +75,10 @@ if ($canceled) {
           SFS Public Key deletion canceled!
           </h2></center>\n";
 
+    $url = CreateURL("deletesfskey", $target_user);
+
     echo "<br>
-          Back to <a href='showsfskeys.php3?target_uid=$target_uid'>
-                 sfs public keys</a> for user '$uid'.\n";
+          Back to <a href='$url'>sfs public keys</a> for user '$uid'.\n";
     
     PAGEFOOTER();
     return;
@@ -91,9 +91,10 @@ if (!$confirmed) {
           Are you <b>REALLY</b>
           sure you want to delete this SFS Public Key for user '$target_uid'?
           </h3>\n";
+
+    $url = CreateURL("deletesfskey", $target_user, "key", $key);
     
-    echo "<form action='deletesfskey.php3?target_uid=$target_uid&key=$key'
-                method=post>";
+    echo "<form action='$url' method=post>";
     echo "<b><input type=submit name=confirmed value=Confirm></b>\n";
     echo "<b><input type=submit name=canceled value=Cancel></b>\n";
     echo "</form>\n";
@@ -112,8 +113,11 @@ if (!$confirmed) {
 #
 # Audit
 #
-TBUserInfo($uid, $uid_name, $uid_email);
-TBUserInfo($target_uid, $targuid_name, $targuid_email);
+$uid_name  = $this_user->name();
+$uid_email = $this_user->email();
+
+$targuid_name  = $target_user->name();
+$targuid_email = $target_user->email();
 
 TBMAIL("$targuid_name <$targuid_email>",
      "SFS Public Key for '$target_uid' Deleted",
@@ -129,7 +133,7 @@ TBMAIL("$targuid_name <$targuid_email>",
      "Errors-To: $TBMAIL_WWW");
 
 DBQueryFatal("delete from user_sfskeys ".
-	     "where uid='$target_uid' and comment='$key'");
+	     "where uid='$target_dbuid' and comment='$key'");
 
 #
 # update sfs_users files and nodes if appropriate.
@@ -141,6 +145,6 @@ else {
     SUEXEC("nobody", "nobody", "webaddsfskey -w $target_uid", 0);
 }
 
-header("Location: showsfskeys.php3?target_uid=$target_uid");
+PAGEREPLACE(CreateURL("showsfskeys", $target_user));
 
 ?>
diff --git a/www/deleteuser.php3 b/www/deleteuser.php3
index 25a424cddaf77929a1e5640b32db739fef7ba795..e879608dc548a18875e89bdf25fcd09760bb8d93 100644
--- a/www/deleteuser.php3
+++ b/www/deleteuser.php3
@@ -14,34 +14,36 @@ PAGEHEADER("Remove User");
 #
 # Only known and logged in users allowed.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify arguments.
 # 
-if (!isset($target_uid) ||
-    strcmp($target_uid, "") == 0) {
+if (!isset($user) || $user == "") {
     USERERROR("You must provide a User ID.", 1);
 }
 if (isset($target_pid) &&
     strcmp($target_pid, "") == 0) {
     USERERROR("You must provide a valid project ID.", 1);
 }
-$isadmin = ISADMIN($uid);
 
 #
 # Confirm target is a real user.
 #
-if (! TBCurrentUser($target_uid)) {
-    USERERROR("No such user '$target_uid'", 1);
+if (! ($target_user = User::Lookup($user))) {
+    USERERROR("The user $user is not a valid user", 1);
 }
+$target_dbuid = $target_user->uid();
+$target_uid   = $target_user->uid();
 
 #
 # Requesting? Fire off email and we are done. 
 # 
 if (isset($request) && $request) {
-    TBUserInfo($uid, $uid_name, $uid_email);
+    $uid_name  = $this_user->name();
+    $uid_email = $this_user->email();
 
     TBMAIL($TBMAIL_OPS,
 	   "Delete User Request: '$target_uid'",
@@ -63,21 +65,16 @@ if (isset($request) && $request) {
 }
 
 #
-# Confirm optional pid is a real pid.
+# Confirm optional pid is a real pid and check permission
 #
-if (isset($target_pid) && !TBValidProject($target_pid)) {
-    USERERROR("No such project '$target_pid'", 1);
-}
-
-#
-# Check user. Proj leaders can remove users from their project, but thats
-# all we allow. Deleting user accounts is left to admin people only.
-#
-if (!$isadmin) {
-    if (! isset($target_pid) ||
-	! TBProjAccessCheck($uid, $target_pid, 0, $TB_PROJECT_DELUSER)) {
-	USERERROR("You do not have permission to remove user '$target_uid'",
-		  1);
+if (isset($target_pid)) {
+    if (! ($target_project = Project::Lookup($target_pid))) {
+	USERERROR("No such project '$target_pid'", 1);
+    }
+    if (! $isadmin &&
+	! $target_project->AccessCheck($this_user, $TB_PROJECT_DELUSER)) {
+	USERERROR("You do not have permission to remove user ".
+		  "$target_uid from project $target_pid!", 1);
     }
 }
 
@@ -93,7 +90,8 @@ if (isset($target_pid)) {
 }
 else {
     $query_result =
-	DBQueryFatal("select pid from projects where head_uid='$target_uid'");
+	DBQueryFatal("select pid from projects ".
+		     "where head_uid='$target_dbuid'");
 
     if (mysql_num_rows($query_result)) {
 	USERERROR("$target_uid is still heading up projects!", 1);
@@ -130,7 +128,7 @@ else {
 # 
 $query_result =
     DBQueryFatal("SELECT * FROM experiments ".
-		 "where expt_head_uid='$target_uid' ".
+		 "where expt_head_uid='$target_dbuid' ".
 		 (isset($target_pid) ? "and pid='$target_pid'" : ""));
 
 if (mysql_num_rows($query_result)) {
@@ -194,7 +192,7 @@ if (!$confirmed) {
     }
     
     echo "<form action=deleteuser.php3 method=post>";
-    echo "<input type=hidden name=target_uid value=\"$target_uid\">\n";
+    echo "<input type=hidden name=user value=\"$user\">\n";
     if (isset($target_pid)) {
 	echo "<input type=hidden name=target_pid value=\"$target_pid\">\n";
     }
@@ -221,7 +219,7 @@ if (!$confirmed_twice) {
     }
     
     echo "<form action=deleteuser.php3 method=post>";
-    echo "<input type=hidden name=target_uid value=\"$target_uid\">\n";
+    echo "<input type=hidden name=user value=\"$user\">\n";
     if (isset($target_pid)) {
 	echo "<input type=hidden name=target_pid value=\"$target_pid\">\n";
     }
@@ -254,28 +252,27 @@ STOPBUSY();
 # project leaders, must send us a request for it.
 #
 if (isset($target_pid)) {
-    $query_result =
-	DBQueryFatal("select pid,gid from group_membership ".
-		     "where uid='$target_uid' and pid=gid");
+    $projlist = $target_user->ProjectMembershipList();
+    
+    if (! count($projlist)) {
+	echo "<b>User 'target_uid' is no longer a member of any projects.\n";
 
-    if (! mysql_num_rows($query_result)) {
-	echo "<b>User '$target_uid' is no longer a member of any projects.\n";
+	$url = CreateURL("deleteuser", $target_user);
 	    
 	if ($isadmin) {
 	    echo "Do you want to
-                  <A href='deleteuser.php3?target_uid=$target_uid'>
-                     delete this user from the testbed?</a>\n";
+                  <A href='$url'>delete this user from the testbed?</a>\n";
 	}
 	else {
 	    echo "You can 
-                  <A href='deleteuser.php3?target_uid=$target_uid&request=1'>
-                     request</a>
+                  <A href='${url}&request=1'>request</a>
                      that we delete this user from the testbed</a></b>\n";
 	}
     }
     else {
 	if (isset($target_pid)) {
-	    PAGEREPLACE("showgroup.php3?pid=$target_pid&gid=$target_pid");
+	    PAGEREPLACE(CreateURL("showgroup", URLARG_PID, $target_pid,
+				  URLARG_GID, $target_pid));
 	}
     }
 }
diff --git a/www/delmmlist.php3 b/www/delmmlist.php3
index d6c92c23ac33426aeb7098b19878da2031d5c003..8e7078de20e240a707090d4104ffbd79fd0fb774 100644
--- a/www/delmmlist.php3
+++ b/www/delmmlist.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2005 University of Utah and the Flux Group.
+# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -13,9 +13,9 @@ include("defs.php3");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # First off, sanity check page args.
diff --git a/www/editexp.php3 b/www/editexp.php3
index 86a706c6de19574942d64f5c6d4b3c1154797f75..384b10339d0be9289853248ecbf6c613b48be95b 100644
--- a/www/editexp.php3
+++ b/www/editexp.php3
@@ -13,8 +13,9 @@ include("defs.php3");
 #
 # Only known and logged in users can end experiments.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 $idleswaptimeout = TBGetSiteVar("idle/threshold");
 
 #
@@ -33,15 +34,14 @@ if (!isset($eid) ||
 #
 # Check to make sure this is a valid PID/EID tuple.
 #
-if (! TBValidExperiment($pid, $eid)) {
-    USERERROR("The experiment $eid is not a valid experiment ".
-	      "in project $pid.", 1);
+if (! ($experiment = Experiment::Lookup($pid, $eid))) {
+    USERERROR("The experiment $pid/$eid is not a valid experiment!", 1);
 }
 
 #
 # Verify Permission.
 #
-if (! TBExptAccessCheck($uid, $pid, $eid, $TB_EXPT_MODIFY)) {
+if (! $experiment->AccessCheck($this_user, $TB_EXPT_MODIFY)) {
     USERERROR("You do not have permission to modify experiment $pid/$eid!", 1);
 }
 
@@ -632,9 +632,15 @@ if ($doemail &&
     ! (ISADMINISTRATOR() &&
        (!strcmp($uid, $creator) || !strcmp($uid, $swapper)))) {
 
-    TBUserInfo($uid,     $user_name, $user_email);
-    TBUserInfo($creator, $cname, $cemail);
-    TBUserInfo($swapper, $sname, $semail);
+    $target_creator = $experiment->GetCreator();
+    $target_swapper = $experiment->GetSwapper();
+
+    $user_name  = $this_user->name();
+    $user_email = $this_user->email();
+    $cname      = $target_creator->name();
+    $cemail     = $target_creator->email();
+    $sname      = $target_swapper->name();
+    $semail     = $target_swapper->email();
 
     $olds = ($defaults[swappable] ? "Yes" : "No");
     $oldsr= $defaults[noswap_reason];
diff --git a/www/editgroup.php3 b/www/editgroup.php3
index c2e74d716457034854dc5935ba45844b0d55f5c0..b55b3f5fec8d7323216e40d939dcf910f56d3e1a 100644
--- a/www/editgroup.php3
+++ b/www/editgroup.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2003, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2003, 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -15,8 +15,9 @@ ignore_user_abort(1);
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # First off, sanity check page args.
@@ -38,6 +39,10 @@ if (strcmp($gid, $pid) == 0) {
     $defaultgroup = 1;
 }
 
+if (! ($group = Group::LookupByPidGid($pid, $gid))) {
+    USERERROR("No such group group $gid in project $pid!", 1);
+}
+
 #
 # Verify permission. 
 #
@@ -99,9 +104,9 @@ $nonmembers_result =
 # 
 if (mysql_num_rows($curmembers_result)) {
     while ($row = mysql_fetch_array($curmembers_result)) {
-	$user = $row[0];
+	$user     = $row[0];
 	$oldtrust = $row[1];
-	$foo  = "change_$user";
+	$foo      = "change_$user";
 
 	#
 	# Is member to be deleted?
@@ -111,6 +116,10 @@ if (mysql_num_rows($curmembers_result)) {
 	    continue;
 	}
 
+	if (! ($target_user = User::Lookup($user))) {
+	    TBERROR("Could not find user object for $user", 1);
+	}
+
         #
         # There should be a corresponding trust variable in the POST vars.
         # Note that we construct the variable name and indirect to it.
@@ -140,7 +149,7 @@ if (mysql_num_rows($curmembers_result)) {
 		      "trust to users in $pid/$gid!", 1 );
 	}
 
-	TBCheckGroupTrustConsistency($user, $pid, $gid, $newtrust, 1);
+	$group->CheckTrustConsistency($target_user, $newtrust, 1);
     }
 }
 
@@ -181,8 +190,12 @@ if ($grabusers && !$defaultgroup && mysql_num_rows($nonmembers_result)) {
 		USERERROR("You do not have permission to bestow group root".
 			  "trust to users in $pid/$gid!", 1 );
 	    }
-	    
-	    TBCheckGroupTrustConsistency($user, $pid, $gid, $newtrust, 1);
+
+	    if (! ($target_user = User::Lookup($user))) {
+		TBERROR("Could not find user object for $user", 1);
+	    }
+
+	    $group->CheckTrustConsistency($target_user, $newtrust, 1);
 	}
     }
 }
diff --git a/www/editgroup_form.php3 b/www/editgroup_form.php3
index ba2758252f135997b0f177a3274830621214bbab..c72875ca540363498371ea848ebb84fca8db3c24 100644
--- a/www/editgroup_form.php3
+++ b/www/editgroup_form.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2003, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2003, 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -15,8 +15,9 @@ PAGEHEADER("Edit Group Membership");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # First off, sanity check page args.
@@ -38,6 +39,10 @@ if (strcmp($gid, $pid) == 0) {
     $defaultgroup = 1;
 }
 
+if (! ($group = Group::LookupByPidGid($pid, $gid))) {
+    USERERROR("No such group group $gid in project $pid!", 1);
+}
+
 #
 # Verify permission.
 #
@@ -130,12 +135,16 @@ if (mysql_num_rows($curmembers_result)) {
 	$user  = $row[0];
 	$trust = $row[1];
 
+	if (! ($target_user = User::Lookup($user))) {
+	    TBERROR("Could not look up user object for $user", 1);
+	}
+	$showurl = CreateURL("showuser", $target_user);
+
 	if ($defaultgroup) {
 	    echo "<tr>
                      <td>
                        <input type=hidden name='change_$user' value=permit>
-                          <A href='showuser.php3?target_uid=$user'>
-                             $user &nbsp</A>
+                          <A href='$showurl'>$user &nbsp</A>
                      </td>\n";
 	}
 	else {
@@ -143,8 +152,7 @@ if (mysql_num_rows($curmembers_result)) {
                      <td>   
                        <input checked type=checkbox value=permit
                               name='change_$user'>
-                          <A href='showuser.php3?target_uid=$user'>
-                             $user &nbsp</A>
+                          <A href='$showurl'>$user &nbsp</A>
                      </td>\n";
 	}
 
@@ -154,19 +162,21 @@ if (mysql_num_rows($curmembers_result)) {
 	#
 	# We want to have the current trust value selected in the menu.
 	#
-	if (TBCheckGroupTrustConsistency($user, $pid, $gid, "user", 0)) {
+	if ($group->CheckTrustConsistency($target_user,
+					  TBDB_TRUSTSTRING_USER, 0)) {
 	    echo "<option value='user' " .
 		((strcmp($trust, "user") == 0) ? "selected" : "") .
 		    ">User </option>\n";
 	}
-	if (TBCheckGroupTrustConsistency($user, $pid, $gid, "local_root", 0)) {
+	if ($group->CheckTrustConsistency($target_user,
+					  TBDB_TRUSTSTRING_LOCALROOT, 0)) {
 	    echo "<option value='local_root' " .
 		((strcmp($trust, "local_root") == 0) ? "selected" : "") .
 		    ">Local Root </option>\n";
 
 	    #
-	    # If group_root is already selected, or we have permission to set it,
-	    # show it. Otherwise do not.
+	    # If group_root is already selected, or we have permission to set
+	    # it, show it. Otherwise do not.
 	    #
 	    if (strcmp($trust, "group_root") == 0 || $bestowgrouproot) {
 		echo "<option value='group_root' " .
@@ -193,21 +203,28 @@ if ($grabusers && mysql_num_rows($nonmembers_result)) {
 	$user  = $row[0];
 	$trust = $row[1];
 	
+	if (! ($target_user = User::Lookup($user))) {
+	    TBERROR("Could not look up user object for $user", 1);
+	}
+	$showurl = CreateURL("showuser", $target_user);
+
 	echo "<tr>
                  <td>
                    <input type=checkbox value=permit name='add_$user'>
-                      <A href='showuser.php3?target_uid=$user'>$user &nbsp</A>
+                      <A href='$showurl'>$user &nbsp</A>
                  </td>\n";
 
 	echo "   <td align=center>
                    <select name='$user\$\$trust'>\n";
 
-	if (TBCheckGroupTrustConsistency($user, $pid, $gid, "user", 0)) {
+	if ($group->CheckTrustConsistency($target_user,
+					  TBDB_TRUSTSTRING_USER, 0)) {
 	    echo "<option value='user' " .
 		((strcmp($trust, "user") == 0) ? "selected" : "") .
 		    ">User</option>\n";
 	}
-	if (TBCheckGroupTrustConsistency($user, $pid, $gid, "local_root", 0)) {
+	if ($group->CheckTrustConsistency($target_user,
+					  TBDB_TRUSTSTRING_LOCALROOT, 0)) {
 	    echo "<option value='local_root' " .
 		((strcmp($trust, "local_root") == 0) ? "selected" : "") .
 		    ">Local Root</option>\n";
diff --git a/www/editimageid.php3 b/www/editimageid.php3
index 33fb741ba80b052a063b5a26a6da469ab9f9547a..4d8e7d05b419aa40f4073ae78487b386aa670896 100644
--- a/www/editimageid.php3
+++ b/www/editimageid.php3
@@ -16,9 +16,9 @@ PAGEHEADER("Edit Image Descriptor");
 #
 # Only known and logged in users!
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Must get the imageid as a page argument.
diff --git a/www/editnodetype.php3 b/www/editnodetype.php3
index a2a2445c2d82c8615d875a10564ed2169f032f1f..c017de6888bd468b9b3b26c0203e6d30b056725a 100644
--- a/www/editnodetype.php3
+++ b/www/editnodetype.php3
@@ -14,13 +14,9 @@ include("osiddefs.php3");
 #
 # Only known and logged in users can end experiments.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-
-#
-# Admin users only
-#
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 if (! $isadmin) {
     USERERROR("You do not have permission to edit node types!", 1);
diff --git a/www/editsitevars.php3 b/www/editsitevars.php3
index 21558d90b9212877ecad4ee19f37a8d612a8cd05..7948404fd53d496111ab960cfaf4675391e0f90e 100644
--- a/www/editsitevars.php3
+++ b/www/editsitevars.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,13 +14,10 @@ PAGEHEADER("Edit Site Variables");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
-#
-# Of course verify that this uid has admin privs!
-#
-$isadmin = ISADMIN($uid);
 if (! $isadmin) {
     USERERROR("You do not have admin privileges to edit site variables!", 1);
 }
diff --git a/www/endexp.php3 b/www/endexp.php3
index cb114e547bca5bf8d6577253413cd3e6e9a7549a..78d3652710e791c827099519a7455ae7235d0862 100644
--- a/www/endexp.php3
+++ b/www/endexp.php3
@@ -10,8 +10,9 @@ include("showstuff.php3");
 #
 # Only known and logged in users can end experiments.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 # This will not return if its a sajax request.
 include("showlogfile_sup.php3");
@@ -56,7 +57,7 @@ $exptidx  = $experiment->idx();
 #
 # Verify permissions.
 #
-if (! $experiment->AccessCheck($uid, $TB_EXPT_DESTROY)) {
+if (! $experiment->AccessCheck($this_user, $TB_EXPT_DESTROY)) {
     USERERROR("You do not have permission to end experiment $pid/$eid!", 1);
 }
 
diff --git a/www/expaccess.php3 b/www/expaccess.php3
index 1743f65ac75a02d6b2503301483cc99a509db16f..aa836b395b2772a4e8d2ca87dab0f3f67f1bc9f8 100644
--- a/www/expaccess.php3
+++ b/www/expaccess.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002 University of Utah and the Flux Group.
+# Copyright (c) 2000-2002, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,8 +14,9 @@ PAGEHEADER("Manage Shared Access to your Experiment");
 #
 # Only known and logged in users can do this. 
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # We must get a valid PID/EID.
@@ -49,7 +50,7 @@ if (!$row[0]) {
 # the experiment creator or the project leader has permission to mess
 # with this. 
 #
-if (! ($isadmin = ISADMIN($uid))) {
+if (! $isadmin) {
     #
     # One of them better be you!
     #
diff --git a/www/expaccess_form.php3 b/www/expaccess_form.php3
index f567ccac8e37e6cc5747bc8204d60da44a0e5aeb..16f9a956dc5e6189e2c8939efae60e432e0ee367 100644
--- a/www/expaccess_form.php3
+++ b/www/expaccess_form.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002 University of Utah and the Flux Group.
+# Copyright (c) 2000-2002, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,8 +14,9 @@ PAGEHEADER("Manage Shared Access to your Experiment");
 #
 # Only known and logged in users can do this. 
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # We must get a valid PID/EID.
@@ -49,7 +50,7 @@ if (!$row[0]) {
 # the experiment creator or the project leader has permission to mess
 # with this. 
 #
-if (! ($isadmin = ISADMIN($uid))) {
+if (! $isadmin) {
     #
     # One of them better be you!
     #
diff --git a/www/experiment_defs.php b/www/experiment_defs.php
index 8ee62f7dbc7f962c759d914e80a03addcb54c5e2..894d8a33f56b1d3ad7a82e99dc311f32c68c6dd4 100644
--- a/www/experiment_defs.php
+++ b/www/experiment_defs.php
@@ -37,12 +37,25 @@ class Experiment
 	return !is_null($this->experiment);
     }
 
-    # Lookup by exptidx.
+    # Lookup by exptidx, but allow for lookup by pid,eid with variable args.
     function Lookup($exptidx) {
+	$args = func_get_args();
+
 	$foo = new Experiment($exptidx);
 
 	if ($foo->IsValid())
 	    return $foo;
+
+        # Try lookup with pid,eid.
+	if (count($args) == 2) {
+	    $pid = array_shift($args);
+	    $eid = array_shift($args);
+
+	    $foo = Experiment::LookupByPidEid($pid, $eid);
+
+	    if ($foo->IsValid())
+		return $foo;
+	}
 	return null;
     }
 
@@ -102,6 +115,16 @@ class Experiment
 	return $this->group;
     }
 
+    #
+    # Get the creator for a project.
+    #
+    function GetCreator() {
+	return User::Lookup($this->creator());
+    }
+    function GetSwapper() {
+	return User::Lookup($this->swapper());
+    }
+
     # accessors
     function field($name) {
 	return (is_null($this->experiment) ? -1 : $this->experiment[$name]);
@@ -139,9 +162,10 @@ class Experiment
     # Access Check. This is not code I want to duplicate, so hand off to
     # global routine until all code converted.
     #
-    function AccessCheck ($uid, $access_type) {
+    function AccessCheck ($user, $access_type) {
 	$pid = $this->pid();
 	$eid = $this->eid();
+	$uid = $user->uid();
 	
 	return TBExptAccessCheck($uid, $pid, $eid, $access_type);
     }
diff --git a/www/experimentrun_show.php b/www/experimentrun_show.php
index ee207e5536d8fed5fa86aaeec78cb47e37b3d020..eb569bbf2d83b967f954861b14cf546f0a8b8413 100644
--- a/www/experimentrun_show.php
+++ b/www/experimentrun_show.php
@@ -13,9 +13,9 @@ sajax_export("GraphShow");
 #
 # Only known and logged in users ...
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/feedback.php3 b/www/feedback.php3
index 15ce6ed8d55b1c626cd78e28e398b8a72db6f61e..a8dd9ed265ebfd9fb19362c00b5e220466b2017b 100644
--- a/www/feedback.php3
+++ b/www/feedback.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,8 +14,9 @@ include("showstuff.php3");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Check to make sure a valid experiment.
diff --git a/www/floormap.php3 b/www/floormap.php3
index 625de36bc7a7c69401409ae9ae9fbe96d7476e29..950c582fe6e89c8a3f499da38dfbbeedc90e0199 100755
--- a/www/floormap.php3
+++ b/www/floormap.php3
@@ -14,9 +14,9 @@ PAGEHEADER("Wireless PC Map" . ((isset($feature) && $feature != "")?" ($feature)
 #
 # Only logged in people at the moment; might open up at some point.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 # Careful with this local variable
 unset($prefix);
diff --git a/www/floormap_aux.php3 b/www/floormap_aux.php3
index 1340bc4e66f4dbe99e7381bc098315788f40471a..2af1550daab6b4d19f776cef0339fa40e07d5a08 100755
--- a/www/floormap_aux.php3
+++ b/www/floormap_aux.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2004 University of Utah and the Flux Group.
+# Copyright (c) 2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,9 +14,9 @@ include("defs.php3");
 #
 # Only logged in people at the moment; might open up at some point.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify arguments.
diff --git a/www/freenode.php3 b/www/freenode.php3
index 6b3730b67b5eceae89f023d833c6ec0ae5ee9352..e14bc25da5a14f2df82add906a9b8e58e67743ee 100644
--- a/www/freenode.php3
+++ b/www/freenode.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2004, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2002, 2004, 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,9 +14,9 @@ include("showstuff.php3");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Check to make sure a valid nodeid
@@ -90,7 +90,8 @@ SUEXEC($uid, "nobody", "webnfree $pid $eid $node_id", 1);
 #
 # And send an audit message.
 #
-TBUserInfo($uid, $uid_name, $uid_email);
+$uid_name  = $this_user->name();
+$uid_email = $this_user->email();
 
 TBMAIL($TBMAIL_AUDIT,
        "Node Free: $node_id",
diff --git a/www/freezeuser.php3 b/www/freezeuser.php3
index 3c5b527df4d66c03c10321e1b020de7464c3ed9a..127f1d414789f07d44fae0faca413933ac8b20dc 100644
--- a/www/freezeuser.php3
+++ b/www/freezeuser.php3
@@ -14,14 +14,14 @@ PAGEHEADER("Freeze User Account");
 #
 # Only known and logged in users allowed.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify arguments.
 # 
-if (!isset($target_uid) ||
-    strcmp($target_uid, "") == 0) {
+if (!isset($user) || $user == "") {
     USERERROR("You must provide a User ID.", 1);
 }
 if (isset($action)) {
@@ -41,19 +41,19 @@ else {
     $tag      = "frozen";
     $dbaction = TBDB_USERSTATUS_FROZEN;
 }
-$isadmin = ISADMIN($uid);
 
 #
 # Confirm target is a real user.
 #
-if (! TBCurrentUser($target_uid)) {
-    USERERROR("No such user '$target_uid'", 1);
+if (! ($target_user = User::Lookup($user))) {
+    USERERROR("No such user '$user'", 1);
 }
+$target_uid = $target_user->uid();
 
 #
 # Confirm a valid op.
 #
-$userstatus = TBUserStatus($target_uid);
+$userstatus = $target_user->status();
 if (!strcmp($action, "thaw") &&
      strcmp($userstatus, TBDB_USERSTATUS_FROZEN)) {
     USERERROR("You cannot thaw someone who is not frozen!", 1);
@@ -71,7 +71,8 @@ if (!strcmp($action, "freeze")) {
 # Requesting? Fire off email and we are done. 
 # 
 if (isset($request) && $request) {
-    TBUserInfo($uid, $uid_name, $uid_email);
+    $uid_name  = $this_user->name();
+    $uid_email = $this_user->email();
 
     TBMAIL($TBMAIL_OPS,
 	   "$action User Request: '$target_uid'",
@@ -115,7 +116,7 @@ if (!$confirmed) {
     echo "Are you <b>REALLY</b> sure you want to $action user '$target_uid'\n";
     
     echo "<form action=freezeuser.php3 method=post>";
-    echo "<input type=hidden name=target_uid value=\"$target_uid\">\n";
+    echo "<input type=hidden name=user value=\"$user\">\n";
     echo "<input type=hidden name=action value=\"$action\">\n";
     echo "<b><input type=submit name=confirmed value=Confirm></b>\n";
     echo "<b><input type=submit name=canceled value=Cancel></b>\n";
@@ -134,7 +135,7 @@ if (!$confirmed_twice) {
               '$target_uid'\n";
     
     echo "<form action=freezeuser.php3 method=post>";
-    echo "<input type=hidden name=target_uid value=\"$target_uid\">\n";
+    echo "<input type=hidden name=user value=\"$user\">\n";
     echo "<input type=hidden name=confirmed value=Confirm>\n";
     echo "<input type=hidden name=action value=\"$action\">\n";
     echo "<b><input type=submit name=confirmed_twice value=Confirm></b>\n";
@@ -146,8 +147,8 @@ if (!$confirmed_twice) {
     return;
 }
 
-DBQueryFatal("update users set status='$dbaction' ".
-	     "where uid='$target_uid'");
+# Change the DB first; backend requires it.
+$target_user->SetStatus($dbaction);
 
 STARTBUSY("User '$target_uid' is being ${tag}!");
 
diff --git a/www/gensslcert.php3 b/www/gensslcert.php3
index 423d4b7635113f992c9f03151552e6815263d427..ee274ce41f0fa8d9bd758ccc30d45b366df5412a 100644
--- a/www/gensslcert.php3
+++ b/www/gensslcert.php3
@@ -9,9 +9,9 @@ include("defs.php3");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # The conclusion.
@@ -19,10 +19,15 @@ $isadmin = ISADMIN($uid);
 if (isset($_GET['finished'])) {
     PAGEHEADER("Generate SSL Certificate");
 
-    $target_uid = $_GET['target_uid'];
+    $user = $_GET['user'];
+
+    if (! ($target_user = User::Lookup($user))) {
+	USERERROR("The user $user is not a valid user", 1);
+    }
+    $url = CreateURL("getsslcert", $target_user);
     
     echo "Your new SSL certificate has been created. You can
-          <a href=getsslcert.php3?target_uid=$target_uid>download</a> your 
+          <a href='$url'>download</a> your 
           certificate and private key in PEM format, and then save
           it to a file in your .ssl directory.\n";
 	    
@@ -36,55 +41,54 @@ if (isset($_GET['finished'])) {
 #
 if (! isset($_POST['submit'])) {
     # First page load. Default to current user.
-    if (! isset($_GET['target_uid']))
-	$target_uid = $uid;
+    if (! isset($_GET['user']))
+	$user = $uid;
     else
-	$target_uid = $_GET['target_uid'];
+	$user = $_GET['user'];
 }
 else {
-    # Form submitted. Make sure we have a formfields array and a target_uid.
+    # Form submitted. Make sure we have a formfields array and a user.
     if (!isset($_POST['formfields']) ||
 	!is_array($_POST['formfields']) ||
-	!isset($_POST['formfields']['target_uid'])) {
+	!isset($_POST['formfields']['user'])) {
 	PAGEARGERROR("Invalid form arguments.");
     }
     $formfields = $_POST['formfields'];
-    $target_uid = $formfields['target_uid'];
+    $user = $formfields['user'];
 }
 
 # Pedantic check of uid before continuing.
-if ($target_uid == "" || !TBvalid_uid($target_uid)) {
-    PAGEARGERROR("Invalid uid: '$target_uid'");
+if ($user == "" || !User::ValidWebID($user)) {
+    PAGEARGERROR("Invalid uid: '$user'");
 }
 
 #
 # Check to make sure thats this is a valid UID.
 #
-if (! TBCurrentUser($target_uid)) {
-    USERERROR("The user $target_uid is not a valid user", 1);
+if (! ($target_user = User::Lookup($user))) {
+    USERERROR("The user $user is not a valid user", 1);
 }
+$target_uid = $target_user->uid();
 
 #
 # Only admin people can create SSL certs for another user.
 #
-if (!$isadmin &&
-    strcmp($uid, $target_uid)) {
-    USERERROR("You do not have permission to create SSL certs for $user!", 1);
+if (!$isadmin && !$target_user->SameUser($this_user)) {
+    USERERROR("You do not have permission to create SSL certs ".
+	      "for $target_uid!", 1);
 }
 
 function SPITFORM($formfields, $errors)
 {
-    global $isadmin, $target_uid, $BOSSNODE;
+    global $isadmin, $target_user, $BOSSNODE;
+
+    $target_uid    = $target_user->uid();
+    $target_webid  = $target_user->webid();
 
     #
     # Standard Testbed Header, now that we know what we want to say.
     #
-    if (strcmp($uid, $target_uid)) {
-	PAGEHEADER("Generate SSL Certificate for user: $target_uid");
-    }
-    else {
-	PAGEHEADER("Generate SSL Certificate");
-    }
+    PAGEHEADER("Generate SSL Certificate for user: $target_uid");
 
     echo "<blockquote>
           By downloading an encrypted SSL certificate, you are able to use
@@ -122,8 +126,8 @@ function SPITFORM($formfields, $errors)
     echo "<table align=center border=1> 
           <form enctype=multipart/form-data
                 action=gensslcert.php3 method=post>\n";
-    echo "<input type=hidden name=\"formfields[target_uid]\" ".
-	         "value=$target_uid>\n";
+    echo "<input type=hidden name=\"formfields[user]\" ".
+	         "value=$target_webid>\n";
 
     echo "<tr>
               <td>PassPhrase[<b>1</b>]:</td>
@@ -195,7 +199,8 @@ $errors = array();
 #
 # Need this for checkpass.
 #
-TBUserInfo($target_uid, $user_name, $user_email);
+$user_name  = $target_user->name();
+$user_email = $target_user->email();
 
 #TBERROR("$target_uid, $user_name, $user_email, " .
 #	$formfields[passphrase1], 0); 
@@ -252,5 +257,6 @@ SUEXEC($target_uid, "nobody",
 #
 # Redirect back, avoiding a POST in the history.
 # 
-header("Location: gensslcert.php3?finished=1&target_uid=$target_uid");
+header("Location: ". CreateURL("getsslcert", $target_user, "finished", 1));
+
 ?>
diff --git a/www/getsslcert.php3 b/www/getsslcert.php3
index c8c9ee0d4d1c164a7ca32c40835aa112c23dc8ce..bdcdc9e3cf5eb06ed1ff4a942e4bea190cd9c750 100644
--- a/www/getsslcert.php3
+++ b/www/getsslcert.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -9,41 +9,43 @@ include("defs.php3");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page/form arguments.
 #
-if (! isset($_GET['target_uid']))
-    $target_uid = $uid;
+if (! isset($_GET['user']))
+    $user = $uid;
 else
-    $target_uid = $_GET['target_uid'];
+    $user = $_GET['user'];
 
 # Pedantic check of uid before continuing.
-if ($target_uid == "" || !TBvalid_uid($target_uid)) {
-    PAGEARGERROR("Invalid uid: '$target_uid'");
+if ($user == "" || !User::ValidWebID($user)) {
+    PAGEARGERROR("Invalid uid: '$user'");
 }
 
 #
 # Check to make sure thats this is a valid UID.
 #
-if (! TBCurrentUser($target_uid)) {
-    USERERROR("The user $target_uid is not a valid user", 1);
+if (! ($target_user = User::Lookup($user))) {
+    USERERROR("The user $user is not a valid user", 1);
 }
+$target_uid   = $target_user->uid();
+$target_dbuid = $target_user->uid();
 
 #
 # Only admin people can create SSL certs for another user.
 #
-if (!$isadmin &&
-    strcmp($uid, $target_uid)) {
-    USERERROR("You do not have permission to download SSL cert for $user!", 1);
+if (!$isadmin && !$target_user->SameUser($this_user)) {
+    USERERROR("You do not have permission to download SSL cert ".
+	      "for $user!", 1);
 }
 
 $query_result =
     DBQueryFatal("select cert,privkey from user_sslcerts ".
-		 "where uid='$target_uid' and encrypted=1");
+		 "where uid='$target_dbuid' and encrypted=1");
 
 if (!mysql_num_rows($query_result)) {
     PAGEHEADER("Download SSL Certificate for $target_uid");
diff --git a/www/gotobugdb.php3 b/www/gotobugdb.php3
index 1b9db0b5237d665776baef6269c9e4ba81e34e74..42da644b30a42b299eb6454da87fa9674ec9a45d 100644
--- a/www/gotobugdb.php3
+++ b/www/gotobugdb.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -12,9 +12,10 @@ if (!$BUGDBSUPPORT) {
 }
 
 # No Pageheader since we spit out a redirection below.
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid, CHECKLOGIN_USERSTATUS|
-	      CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY); # XXX BUGDBONLY ?
+$this_user = CheckLoginOrDie(CHECKLOGIN_USERSTATUS|
+		     CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY); # XXX BUGDBONLY ?
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # The project to zap to on the other side
diff --git a/www/gotochat.php3 b/www/gotochat.php3
index fa6ab3bd55e3a148a23b8162cfc953f41774b7f4..875678a11cfe311b9349db817cf6251723aa3ae2 100644
--- a/www/gotochat.php3
+++ b/www/gotochat.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -12,19 +12,11 @@ if (!$CHATSUPPORT) {
 }
 
 # No Pageheader since we spit out a redirection below.
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
 
-$query_result =
-    DBQueryFatal("select mailman_password from users where uid='$uid'");
-
-if (!mysql_num_rows($query_result)) {
-    USERERROR("No such user $uid!", 1);
-}
-$row = mysql_fetch_array($query_result);
-$password = $row['mailman_password'];
-$url = "${OPSJETIURL}?user=$uid&password=$password";
+$password  = $this_user->mailman_password();
+$url       = "${OPSJETIURL}?user=$uid&password=$password";
 
 header("Location: ${url}");
 ?>
diff --git a/www/gotommlist.php3 b/www/gotommlist.php3
index 2abeeabbf508effe83f736413b4344ee563d82f9..5c292dd7df10a14437611c6da972b33602397edf 100644
--- a/www/gotommlist.php3
+++ b/www/gotommlist.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -12,10 +12,10 @@ if (!$MAILMANSUPPORT) {
 }
 
 # No Pageheader since we spit out a redirection below.
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid, CHECKLOGIN_USERSTATUS|
-	      CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie(CHECKLOGIN_USERSTATUS|
+			     CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY);
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # We will either show a specific list.
@@ -56,7 +56,8 @@ if (isset($pid) && $pid != "") {
     # admin can request access to the list admin interface, and we need
     # a different cookie for that.
     #
-    TBUserInfo($uid, $user_name, $user_email);
+    $user_name  = $this_user->name();
+    $user_email = $this_user->email();
     $user_email = rawurlencode($user_email);
     
     $cookietype = "user";
@@ -118,7 +119,8 @@ elseif (isset($listname) && $listname != "") {
     if (! TBvalid_mailman_listname($listname)) {
 	PAGEARGERROR("Invalid characters in $listname!");
     }
-    TBUserInfo($uid, $user_name, $user_email);
+    $user_name  = $this_user->name();
+    $user_email = $this_user->email();
     $user_email = rawurlencode($user_email);
 	
     $optargs = "";
diff --git a/www/gotowiki.php3 b/www/gotowiki.php3
index 97d8346488840104dda5c5e28116dd111fe79610..6c4abb0bf306d4b03d937cf250eb40879775e8a6 100644
--- a/www/gotowiki.php3
+++ b/www/gotowiki.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -12,9 +12,9 @@ if (!$WIKISUPPORT) {
 }
 
 # No Pageheader since we spit out a redirection below.
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid, CHECKLOGIN_USERSTATUS|
-	      CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY);
+$this_user = CheckLoginOrDie(CHECKLOGIN_USERSTATUS|
+			     CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY);
+$uid       = $this_user->uid();
 
 #
 # The page to zap to on the other side
diff --git a/www/group_defs.php b/www/group_defs.php
index 1e4553bb1ff68e10fed28cb63dde853e7fc0566d..3764283397a7978f27b8478a920b301970a70244 100644
--- a/www/group_defs.php
+++ b/www/group_defs.php
@@ -4,6 +4,11 @@
 # Copyright (c) 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
+#
+# A cache of groups to avoid lookups. Indexed by gid_idx;
+#
+$group_cache = array();
+
 class Group
 {
     var	$group;
@@ -23,8 +28,8 @@ class Group
 	    $this->group = NULL;
 	    return;
 	}
-	$this->group   = mysql_fetch_array($query_result);
-	$this->project = null;
+	$this->group   =& mysql_fetch_array($query_result);
+	$this->project =  null;
     }
 
     # Hmm, how does one cause an error in a php constructor?
@@ -34,11 +39,20 @@ class Group
 
     # Lookup by gid_idx.
     function Lookup($gid_idx) {
+	global $group_cache;
+
+        # Look in cache first
+	if (array_key_exists("$gid_idx", $group_cache))
+	    return $group_cache["$gid_idx"];
+	
 	$foo = new Group($gid_idx);
 
-	if ($foo->IsValid())
-	    return $foo;
-	return null;
+	if (! $foo->IsValid())
+	    return null;
+
+	# Insert into cache.
+	$group_cache["$gid_idx"] = $foo;
+	return $foo;
     }
 
     # Backwards compatable lookup by pid,gid. Will eventually flush this.
@@ -56,12 +70,7 @@ class Group
 	$row = mysql_fetch_array($query_result);
 	$idx = $row['gid_idx'];
 
-	$foo = new Group($idx); 
-
-	if ($foo->IsValid())
-	    return $foo;
-	
-	return null;
+	return Group::Lookup($idx);	
     }
     
     #
@@ -80,7 +89,7 @@ class Group
 	    $this->group = NULL;
 	    return -1;
 	}
-	$this->group = mysql_fetch_array($query_result);
+	$this->group =& mysql_fetch_array($query_result);
 	return 0;
     }
 
@@ -96,6 +105,61 @@ class Group
 	$this->project = $project;
 	return 0;
     }
+    function Project() {
+	if (! $this->project) {
+	    $this->LoadProject();
+	}
+	return $this->project;
+    }
+    
+    #
+    # Return user object for leader.
+    #
+    function GetLeader() {
+	$head_uid = $this->leader();
+
+	if (! ($leader = User::Lookup($head_uid))) {
+	    TBERROR("Could not find user object for $head_uid", 1);
+	}
+	return $leader;
+    }
+
+    #
+    # Access Check, which for now uses the global function to avoid duplication
+    # until all code is changed.
+    #
+    function AccessCheck($user, $access_type) {
+	return TBProjAccessCheck($user->uid(), $this->pid(), $this->gid(),
+				 $access_type);
+    }
+
+    #
+    # Return a users trust within the group.
+    #
+    function UserTrust($user) {
+	global $TBDB_TRUST_NONE;
+	
+	$uid_idx = $user->uid_idx();
+	$pid_idx = $this->pid_idx();
+	$gid_idx = $this->gid_idx();
+
+	$query_result =
+	    DBQueryFatal("select trust from group_membership ".
+			 "where uid_idx='$uid_idx' and ".
+			 "      pid_idx='$pid_idx' and gid_idx='$gid_idx'");
+
+        #
+        # No membership is the same as no trust. True? Maybe an error instead?
+        # 
+	if (mysql_num_rows($query_result) == 0) {
+	    return $TBDB_TRUST_NONE;
+	}
+	$row = mysql_fetch_array($query_result);
+	$trust_string = $row[trust];
+
+	# Convert string to number.      
+	return TBTrustConvert($trust_string);
+    }
 
     # accessors
     function field($name) {
@@ -210,7 +274,7 @@ class Group
 	    TBERROR("Group::Initialize: Could not find $TBOPSPID!", 1);
 	}
 
-	$user = User::LookupByUid($uid);
+	$user = User::Lookup($uid);
 
 	if (! $user) {
 	    TBERROR("Group::Initialize: Could not find user $uid!", 1);
@@ -254,6 +318,24 @@ class Group
 	return 0;
     }
 
+    #
+    # And a delete function.
+    #
+    function DeleteMember($user) {
+	$uid     = $user->uid();
+	$uid_idx = $user->uid_idx();
+	$pid     = $this->pid();
+	$pid_idx = $this->pid_idx();
+	$gid     = $this->gid();
+	$gid_idx = $this->gid_idx();
+
+	DBQueryFatal("delete from group_membership ".
+		     "where uid_idx='$uid_idx' and pid_idx='$pid_idx' and ".
+		     "      gid_idx='$gid_idx'");
+	
+	return 0;
+    }
+
     #
     # Notify leaders of new (and verified) group member.
     #
@@ -270,7 +352,7 @@ class Group
 	$leader_name	= $leader->name();
 	$leader_email	= $leader->email();
 	$leader_uid	= $leader->uid();
-	$allleaders	= TBLeaderMailList($pid, $gid);
+	$allleaders	= $this->LeaderMailList();
 	$joining_uid    = $user->uid();
 	$usr_title	= $user->title();
 	$usr_name	= $user->name();
@@ -320,7 +402,9 @@ class Group
     #
     # Check if user is a member of this group.
     #
-    function IsMember($user) {
+    function IsMember($user, &$approved) {
+	global $TBDB_TRUST_USER;
+	
 	$uid     = $user->uid();
 	$uid_idx = $user->uid_idx();
 	$gid     = $this->gid();
@@ -330,6 +414,196 @@ class Group
 	    DBQueryFatal("select trust from group_membership ".
 			 "where uid_idx='$uid_idx' and gid_idx='$gid_idx'");
 
-	return mysql_num_rows($query_result);
+	if (mysql_num_rows($query_result) == 0) {
+	    $approved = 0;
+	    return 0;
+	}
+
+	$row      = mysql_fetch_row($query_result);
+	$trust    = $row[0];
+	$approved = TBMinTrust($trust, $TBDB_TRUST_USER);
+
+	return 1;
+    }
+
+    #
+    # Change the leader for a group.
+    #
+    function ChangeLeader($leader) {
+	$idx   = $this->gid_idx();
+	$uid   = $leader->uid();
+
+	DBQueryFatal("update groups set leader='$uid' ".
+		     "where gid_idx='$idx'");
+
+	$this->group["leader"] = $uid;
+	return 0;
+    }
+
+    #
+    # Trust consistency.
+    #
+    function CheckTrustConsistency($user, $newtrust, $fail) {
+	global $TBDB_TRUST_USER;
+	
+	$uid = $user->uid();
+	$pid = $this->pid();
+	$gid = $this->gid();
+	$uid_idx = $user->uid_idx();
+	$pid_idx = $this->pid_idx();
+	$gid_idx = $this->gid_idx();
+	$trust_none = TBDB_TRUSTSTRING_NONE;
+	
+        # 
+        # set $newtrustisroot to 1 if attempting to set a rootful trust,
+        # 0 otherwise.
+        #
+	$newtrustisroot = TBTrustConvert($newtrust) > $TBDB_TRUST_USER ? 1 : 0;
+
+        #
+        # If changing subgroup trust level, then compare levels.
+        # A user may not have root privs in the project and user privs
+        # in the subgroup; it makes no sense to do that and can violate trust.
+        #
+	if ($pid_idx != $gid_idx) {
+            #
+            # Setting non-default "sub"group.
+	    # Verify that if user has root in project,
+	    # we are setting a rootful trust for him in 
+	    # the subgroup as well.
+	    #
+	    $projtrustisroot =
+		TBProjTrust($uid, $pid) > $TBDB_TRUST_USER ? 1 : 0;
+
+	    if ($projtrustisroot > $newtrustisroot) {
+		if (!$fail)
+		    return 0;
+		
+		TBERROR("User $uid may not have a root trust level in ".
+			"the default group of $pid, ".
+			"yet be non-root in subgroup $gid!", 1);
+	    }
+	}
+	else {
+            #
+	    # Setting default group.
+	    # Do not verify anything (yet.)
+	    #
+	    $projtrustisroot = $newtrustisroot;
+	}
+
+        #
+        # Get all the subgroups not equal to the subgroup being changed.
+        # 
+	$query_result =
+	    DBQueryFatal("select trust,gid from group_membership ".
+			 "where uid_idx='$uid_idx' and ".
+			 "      pid_idx='$pid_idx' and ".
+			 "      gid_idx!=pid_idx and ".
+			 "      gid_idx!='$gid_idx' and ".
+			 "      trust!='$trust_none'");
+
+	while ($row = mysql_fetch_array($query_result)) {
+	    $grptrust = $row[0];
+	    $ogid     = $row[1];
+	
+  	    # 
+	    # Get what the users trust level is in the 
+	    # current subgroup we are looking at.
+	    #
+	    $grptrustisroot = 
+		TBTrustConvert($grptrust) > $TBDB_TRUST_USER ? 1 : 0;
+
+ 	    #
+	    # If users trust level is higher in the default group than in the
+	    # subgroup we are looking at, this is wrong.
+ 	    #
+	    if ($projtrustisroot > $grptrustisroot) {
+	        if (!$fail)
+		    return 0;
+
+		TBERROR("User $uid may not have a root trust level in ".
+			"the default group of $pid, ".
+			"yet be non-root in subgroup $ogid!", 1);
+	    }
+
+	    if ($pid_idx != $gid_idx) {
+                #
+	        # Iff we are modifying a subgroup, 
+	        # Make sure that the trust we are setting is as
+	        # rootful as the trust we already have set in
+	        # every other subgroup.
+	        # 
+		if ($newtrustisroot != $grptrustisroot) { 
+		    if (!$fail)
+			return 0;
+		    
+		    TBERROR("User $uid may not mix root and ".
+			    "non-root trust levels in ".
+			    "different subgroups of $pid!", 1);
+		}
+	    }
+	}
+	return 1;
+    }
+
+    #
+    # Hmm, this is really a grooup_membership query. Needs different treatment.
+    #
+    function MemberShipInfo($user, &$trust, &$date_applied, &$date_approved) {
+	$uid_idx = $user->uid_idx();
+	$gid_idx = $this->gid_idx();
+
+	$query_result =
+	    DBQueryFatal("select trust,date_applied,date_approved ".
+			 "  from group_membership ".
+			 "where uid_idx='$uid_idx' and gid_idx='$gid_idx'");
+
+	if (! mysql_num_rows($query_result)) {
+	    TBERROR("Group::MemberShipInfo: ".
+		    "Lookup failed for $uid_idx/$gid_idx", 1);
+	}
+	$row      = mysql_fetch_row($query_result);
+	$trust    = $row[0];
+	$date_applied  = $row[1];
+	$date_approved = $row[2];
+	
+	return 0;
+    }
+
+    #
+    # Return mail addresses for project_root and group_root people.
+    #
+    function LeaderMailList() {
+	$gid_idx = $this->gid_idx();
+	$pid_idx = $this->pid_idx();
+
+	# Constants.
+	$trust_group  = TBDB_TRUSTSTRING_GROUPROOT;
+	$trust_project= TBDB_TRUSTSTRING_PROJROOT;
+
+	$query_result =
+	    DBQueryFatal("select distinct usr_name,u.uid,usr_email ".
+			 "   from users as u ".
+			 "left join group_membership as gm on ".
+			 "     gm.uid_idx=u.uid_idx ".
+			 "where (trust='$trust_project' and ".
+			 "       pid_idx='$pid_idx') or ".
+			 "      (trust='$trust_group' and ".
+			 "       pid_idx='$pid_idx' and gid_idx='$gid_idx') ".
+			 "order by trust DESC, usr_name");
+  
+	if (mysql_num_rows($query_result) == 0) {
+	    return "";
+	}
+	
+	$mailstr="";
+	while ($row = mysql_fetch_array($query_result)) {
+	    if ($mailstr != "")
+		$mailstr .= ", ";
+	    
+	    $mailstr .= '"' . $row[usr_name] . " (". $row[uid] . ")\" <" .
+		$row[usr_email] . ">";
+	}
     }
 }
diff --git a/www/index.php3 b/www/index.php3
index 019482768154c848b9f12fad92b0e075da10f46d..1246682c4abadf72e2de1bda57cd25bd56ca732e 100755
--- a/www/index.php3
+++ b/www/index.php3
@@ -10,9 +10,9 @@ require("defs.php3");
 # The point of this is to redirect logged in users to their My Emulab
 # page. 
 #
-if ($uid = GETUID()) {
-    $check_status = CHECKLOGIN($uid) & CHECKLOGIN_STATUSMASK;
-
+if (($this_user = CheckLogin($check_status))) {
+    $check_status = $check_status & CHECKLOGIN_STATUSMASK;
+    
     if (($firstinitstate = TBGetFirstInitState())) {
 	unset($stayhome);
     }
@@ -24,7 +24,8 @@ if ($uid = GETUID()) {
 	    }
 	    else {
 		# Zap to My Emulab page.
-		header("Location: $TBBASE/showuser.php3?target_uid=$uid");
+		header("Location: $TBBASE/".
+		       CreateURL("showuser", $this_user));
 	    }
 	    return;
 	}
diff --git a/www/instance_show.php b/www/instance_show.php
index 28e23320c6c58beca44e3118373e1b9c351408c0..f590dd591f22fbdb8fc485a2d00d2a5f2e4a3809 100644
--- a/www/instance_show.php
+++ b/www/instance_show.php
@@ -13,9 +13,9 @@ sajax_export("GraphShow");
 #
 # Only known and logged in users ...
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/joinproject.php3 b/www/joinproject.php3
index d63a0c1c23b869e74db36c648ecd1e0a0a666b20..c8d45b6e0a20ac729083c9b3b7c81e1d362f1eab 100644
--- a/www/joinproject.php3
+++ b/www/joinproject.php3
@@ -12,19 +12,19 @@ include("defs.php3");
 
 #
 # Get current user.
-# 
-$uid = GETLOGIN();
+#
+$this_user = CheckLogin($check_status);
 
 #
 # If a uid came in, then we check to see if the login is valid.
 # We require that the user be logged in to start a second project.
 #
-if ($uid) {
+if ($this_user) {
     # Allow unapproved users to join multiple groups ...
     # Must be verified though.
-    LOGGEDINORDIE($uid, CHECKLOGIN_UNAPPROVED|
-		  CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY);
-    $joining_uid = $uid;
+    CheckLoginOrDie(CHECKLOGIN_UNAPPROVED|
+		    CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY);
+    $joining_uid = $this_user->uid();
     $returning = 1;
 }
 else {
@@ -489,7 +489,7 @@ if (! isset($_POST['submit'])) {
     return;
 }
 else {
-    # Form submitted. Make sure we have a formfields array and a target_uid.
+    # Form submitted. Make sure we have a formfields array.
     if (!isset($_POST['formfields']) ||
 	!is_array($_POST['formfields'])) {
 	PAGEARGERROR("Invalid form arguments.");
@@ -514,7 +514,7 @@ if (! $returning) {
 	elseif (!TBvalid_uid($formfields[joining_uid])) {
 	    $errors["UserName"] = TBFieldErrorString();
 	}
-	elseif (TBCurrentUser($formfields[joining_uid]) ||
+	elseif (User::Lookup($formfields[joining_uid]) ||
 		posix_getpwnam($formfields[joining_uid])) {
 	    $errors["UserName"] = "Already in use. Pick another";
 	}
@@ -540,7 +540,7 @@ if (! $returning) {
 	elseif (! TBvalid_wikiname($formfields[wikiname])) {
 	    $errors["WikiName"] = TBFieldErrorString();
 	}
-	elseif (TBCurrentWikiName($formfields[wikiname])) {
+	elseif (User::LookupByWikiName($formfields[wikiname])) {
 	    $errors["WikiName"] = "Already in use. Pick another";
 	}
     }
@@ -567,7 +567,7 @@ if (! $returning) {
     elseif (! TBvalid_email($formfields[usr_email])) {
 	$errors["Email Address"] = TBFieldErrorString();
     }
-    elseif (TBCurrentEmail($formfields[usr_email])) {
+    elseif (User::LookupByEmail($formfields[usr_email])) {
 	$errors["Email Address"] =
 	    "Already in use. <b>Did you forget to login?</b>";
     }
@@ -747,17 +747,15 @@ if (!$returning && !$forwikionly) {
 # Need the user, project and group objects for the rest of this.
 #
 if (!$forwikionly) {
-    if (! ($project = Project::LookupByPid($pid))) {
+    if (! ($project = Project::Lookup($pid))) {
 	TBERROR("Could not lookup object for $pid!", 1);
     }
     if (! ($group = Group::LookupByPidGid($pid, $gid))) {
 	TBERROR("Could not lookup object for $pid/$gid!", 1);
     }
     if ($returning) {
-	if (! ($user = User::LookupByUid($joining_uid))) {
-	    TBERROR("Could not lookup user '$joining_uid'!", 1);
-	}
-	if ($group->IsMember($user)) {
+	$user = $this_user;
+	if ($group->IsMember($user, $ignore)) {
 	    $errors["Membership"] = "You are already a member";
 	}
     }
@@ -839,7 +837,8 @@ if (! $returning) {
     $args["usr_pswd"]      = crypt("$password1");
     $args["wikiname"]      = $wikiname;
 
-    if (! ($user = User::NewUser($joining_uid, 0, $forwikionly, $args))) {
+    if (! ($user = User::NewUser($joining_uid,
+				 TBDB_NEWACCOUNT_WIKIONLY, $args))) {
 	TBERROR("Could not create new user '$usr_email'!", 1);
     }
     $joining_uid = $user->uid();
@@ -860,7 +859,7 @@ if ($forwikionly) {
 #
 # If joining a subgroup, also add to project group.
 #
-if ($pid != $gid && ! $project->IsMember($user)) {
+if ($pid != $gid && ! $project->IsMember($user, $ignore)) {
     if ($project->AddNewMember($user) < 0) {
 	TBERROR("Could not add user $joining_uid to project group $pid", 1);
     }
diff --git a/www/kb-browse.php3 b/www/kb-browse.php3
index d39c6be9c1325a9afe90b9c5a9db1c9e3fe9f17e..25ba6c921563279852e715fb45d33ceb2a696b5d 100644
--- a/www/kb-browse.php3
+++ b/www/kb-browse.php3
@@ -1,14 +1,17 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2005 University of Utah and the Flux Group.
+# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 require("defs.php3");
 
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
+
 # Some Knowledge Base entries are visible only to admins.
-$uid = GETLOGIN();
-$admin_access = ISADMIN($uid) || ISFOREIGN_ADMIN($uid);
+$admin_access = $isadmin || ISFOREIGN_ADMIN();
 
 # Page arguments.
 $printable = $_GET['printable'];
diff --git a/www/kb-manage.php3 b/www/kb-manage.php3
index 7350ebe89fe92def3763e6aa11e0382d8c1b59e8..6e8423e9b2e4033c2fcc6442517d062857ea6199 100644
--- a/www/kb-manage.php3
+++ b/www/kb-manage.php3
@@ -19,12 +19,11 @@ define("TBDB_KB_BODYLEN",	10000);
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
-# Summary data for admins only.
-if (!ISADMIN()) {
+if (!$isadmin) {
     USERERROR("You are not allowed to view this page!", 1);
 }
 
diff --git a/www/kb-search.php3 b/www/kb-search.php3
index 2dbfd4532a611a0d0f964753f6f414e7b5c14cfd..31f4a1b094d4d8e3635f93c78361582f0eb2c0db 100644
--- a/www/kb-search.php3
+++ b/www/kb-search.php3
@@ -8,8 +8,8 @@ if (!isset($embedded)) {
     require("defs.php3");
 
     # Some Knowledge Base entries are visible only to admins.
-    $uid = GETLOGIN();
-    $admin_access = ISADMIN($uid) || ISFOREIGN_ADMIN($uid);
+    $this_user = CheckLogin($check_status);
+    $admin_access = ISADMIN() || ISFOREIGN_ADMIN();
 }
 
 #
diff --git a/www/kb-show.php3 b/www/kb-show.php3
index 7ad815fcdbb962c788fd9a908674e1abdfec2c9a..23e55679f7088029ef25bdd49b7f48b1c3f0392f 100644
--- a/www/kb-show.php3
+++ b/www/kb-show.php3
@@ -36,12 +36,11 @@ else {
 #
 # Admin users get a menu.
 #
-if (!$printable) {
-    $uid     = GETLOGIN();
+if (($this_user = CheckLogin($ignore))) {
+    $isadmin = ISADMIN();
+}
+else {
     $isadmin = 0;
-    if (CHECKLOGIN($uid) & CHECKLOGIN_LOGGEDIN) {
-	$isadmin = ISADMIN();
-    }
 }
 
 #
diff --git a/www/ledpipe.php3 b/www/ledpipe.php3
index 18f264a4a7612aa66cce30efa06fe85e6278b6a4..191e429fe86b223a99e75db3e50d104ed073ecd0 100644
--- a/www/ledpipe.php3
+++ b/www/ledpipe.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2004, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -9,8 +9,9 @@ include("defs.php3");
 #
 # Only known and logged in users can watch LEDs
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/linkgraph_image.php b/www/linkgraph_image.php
index c0ab9216f7a917a55578620daf8fb76c14aa4314..94774a2a541161d3d47a9588ac259fb83fc6caf4 100644
--- a/www/linkgraph_image.php
+++ b/www/linkgraph_image.php
@@ -10,9 +10,9 @@ include_once("template_defs.php");
 #
 # Only known and logged in users ...
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/linkmon_ctl.php3 b/www/linkmon_ctl.php3
index 4ab02bb543b56da65e051a45c2bec4202db0fffc..72760508ae12cbf0a9309209c5951e3bb132438a 100644
--- a/www/linkmon_ctl.php3
+++ b/www/linkmon_ctl.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2005 University of Utah and the Flux Group.
+# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -9,8 +9,9 @@ include("defs.php3");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Check to make sure a valid experiment.
diff --git a/www/linkmon_list.php3 b/www/linkmon_list.php3
index 41748c8b77720cafcc713ff3582bdc85c4202f42..34ab5b7e249851ce6803f9dfa73db28187861da4 100644
--- a/www/linkmon_list.php3
+++ b/www/linkmon_list.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2005 University of Utah and the Flux Group.
+# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,8 +14,9 @@ PAGEHEADER("Link Monitoring");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Check to make sure a valid experiment.
diff --git a/www/linkmon_mon.php3 b/www/linkmon_mon.php3
index 1b5c7e077387a480aefc8086c5eece1f3a98c294..18a4c51295cdaff68f3781b8adf26027c1cc60c3 100644
--- a/www/linkmon_mon.php3
+++ b/www/linkmon_mon.php3
@@ -9,8 +9,9 @@ include("defs.php3");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Check to make sure a valid experiment.
diff --git a/www/linktest.php3 b/www/linktest.php3
index 627f31cf47f01104ccef3d65d92ba6b09ff4de90..348cc46d9b067ecdde82454a484a91247d5c5f95 100644
--- a/www/linktest.php3
+++ b/www/linktest.php3
@@ -35,8 +35,9 @@ if (sajax_client_request()) {
 }
 
 # Now check login status.
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Need this argument checking in a function so it can called from the
diff --git a/www/listrepos.php3 b/www/listrepos.php3
index 9ca3fb45a6594589899bae638a0fc341bd78bb8c..a63eb1fb29ebf4d7a8a1ab56287789bb1ea9af8b 100644
--- a/www/listrepos.php3
+++ b/www/listrepos.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2005 University of Utah and the Flux Group.
+# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -18,57 +18,54 @@ if (!$CVSSUPPORT) {
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify form arguments.
 # 
-if (!isset($target_uid) ||
-    strcmp($target_uid, "") == 0) {
+if (!isset($user) ||
+    strcmp($user, "") == 0) {
     PAGEARGERROR("You must provide a User ID!");
 }
 else {
-    if (! TBvalid_uid($target_uid)) {
-	PAGEARGERROR("Invalid characters in $target_uid!");
+    if (! User::ValidWebID($user)) {
+	PAGEARGERROR("Invalid characters in $user!");
     }
 }
 
+#
+# Check to make sure thats this is a valid UID.
+#
+if (! ($target_user = User::Lookup($user))) {
+    USERERROR("The user $user is not a valid user", 1);
+}
+$userstatus = $target_user->status();
+$target_uid = $target_user->uid();
+
 #
 # Standard Testbed Header, now that we know what we want to say.
 #
-if (strcmp($uid, $target_uid)) {
+if (strcmp($uid, $user)) {
     PAGEHEADER("CVS Repositories for: $target_uid");
 }
 else {
     PAGEHEADER("My CVS Repositories");
 }
 
-#
-# Check to make sure thats this is a valid UID. Getting the status works,
-# and we need that later. 
-#
-if (! ($userstatus = TBUserStatus($target_uid))) {
-    USERERROR("The user $target_uid is not a valid user", 1);
-}
-
 #
 # Verify Permission.
 #
-if (!$isadmin &&
-    strcmp($uid, $target_uid)) {
-
-    if (! TBUserInfoAccessCheck($uid, $target_uid, $TB_USERINFO_READINFO)) {
-	USERERROR("You do not have permission to view this user's ".
-		  "information!", 1);
-    }
+if (!$isadmin && 
+    !$target_user->AccessCheck($this_user, $TB_USERINFO_READINFO)) {
+    USERERROR("You do not have permission to view ${uid}'s information!", 1);
 }
 
 #
 # See what projects the uid is a member of, and print some repo pointers
 #
-$projlist = TBProjList($target_uid, $TB_PROJECT_READINFO);
+$projlist = $target_user->ProjectAccessList($TB_PROJECT_READINFO);
 
 if (! count($projlist)) {
     USERERROR("$target_uid is not a member of any Projects!", 1);
@@ -101,7 +98,7 @@ while (list($pid) = each($projlist)) {
 }
 echo "</table>\n";
 
-if (TBCvswebAllowed($uid)) {
+if ($target_user->cvsweb()) {
     echo "<br><center>
           You also have CVSweb access to the
           <a href=cvsweb/cvswebwrap.php3>Emulab Source Repository</a>.
diff --git a/www/loadimage.php3 b/www/loadimage.php3
index 26cb516af10c4651cde26eab96e245d629b71d3a..be757f654d052aa6cb79b9c751edc4d6aa311c44 100644
--- a/www/loadimage.php3
+++ b/www/loadimage.php3
@@ -18,9 +18,9 @@ PAGEHEADER("Snapshot Node Disk into Existing Image Descriptor");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 if (! isset($imageid)) {
     USERERROR("Must pass image name to page as 'imageid'.", 1 );
diff --git a/www/login.php3 b/www/login.php3
index fbf165aabea9806a87b78b0dc84b9e9d257ae5a7..27da4da1945f8420b680d38c0533dc9cee1aa6d5 100644
--- a/www/login.php3
+++ b/www/login.php3
@@ -47,15 +47,17 @@ if ($simple) {
 
 
 #
-# Must not be logged in already!
-# 
-if (($known_uid = GETUID()) != FALSE) {
-    if (CHECKLOGIN($known_uid) & CHECKLOGIN_LOGGEDIN) {
+# Must not be logged in already.
+#
+if (($this_user = CheckLogin($status))) {
+    $this_webid = $this_user->webid();
+    
+    if ($status & CHECKLOGIN_LOGGEDIN) {
 	#
 	# If doing a verification for the logged in user, zap to that page.
 	# If doing a verification for another user, then must login in again.
 	#
-	if (isset($key) && (!isset($vuid) || $vuid == $known_uid)) {
+	if (isset($key) && (!isset($vuid) || $vuid == $this_webid)) {
 	    header("Location: $TBBASE/verifyusr.php3?key=$key");
 	    return;
 	}
diff --git a/www/login_redirect.php b/www/login_redirect.php
index ea69de5418fe9f6e38cdadcdfff9b38a43569d57..d7c194585b5ae72f12a2d46f1bb353e3ff2f6fba 100644
--- a/www/login_redirect.php
+++ b/www/login_redirect.php
@@ -1,13 +1,12 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
 
 # No Pageheader since we spit out a redirection below.
-$uid = GETLOGIN();
 
 #
 # We must get the redirection target.
@@ -37,7 +36,9 @@ if ($redirect_host != "www.datapository.net" &&
 # Okay, now see if the user is logged in. If not, the user will be
 # be brought back here after logging in.
 #
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Generate a cookie. 
diff --git a/www/logout.php3 b/www/logout.php3
index 8727b9b0efbc1ecff45558a2bd16185d0903435d..fbd33f03aaee06633476db71e2f21f0a507b301f 100644
--- a/www/logout.php3
+++ b/www/logout.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2003 University of Utah and the Flux Group.
+# Copyright (c) 2000-2003, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 #
@@ -14,32 +14,44 @@ require("defs.php3");
 #
 # $uid optionally comes in as a variable so admins can logout other users.
 #
-$target_uid = $_GET['target_uid'];
-$next_page  = $_GET['next_page'];
+$user      = $_GET['user'];
+$next_page = $_GET['next_page'];
 
-# Pedantic page argument checking. Good practice!
-if (isset($target_uid) && $target_uid == "") {
-    PAGEARGERROR();
+# Pedantic page argument checking.
+if (isset($user) && ($user == "" || !User::ValidWebID($user))) {
+    PAGEARGERROR("Illegal characters in '$user'");
 }
 
 # Get current login.
 # Only admin users can logout someone other then themself.
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid, CHECKLOGIN_MODMASK);
+$this_user = CheckLoginOrDie(CHECKLOGIN_MODMASK);
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
-if (!isset($target_uid))
-    $target_uid = $uid;
-
-if ($target_uid != $uid && !ISADMIN($uid)) {
-    PAGEHEADER("Logout");
-    echo "<center>
-          <h3>You do not have permission to logout '$target_uid'
-          </h3></center>\n";
-    PAGEFOOTER();
-    return;
+if (isset($user)) {
+    if (! ($target_user = User::Lookup($user))) {
+	PAGEHEADER("Logout");
+	USERERROR("The user $user is not a valid user", 1);
+	PAGEFOOTER();
+	return;
+    }
+    $target_uid = $target_user->uid();
+    
+    if (! $isadmin) {
+	PAGEHEADER("Logout");
+	echo "<center>
+                  <h3>You do not have permission to logout '$target_uid'</h3>
+              </center>\n";
+	PAGEFOOTER();
+	return;
+    }
+}
+else {
+    $target_user = $this_user;
+    $target_uid  = $uid;
 }
 
-if (DOLOGOUT($target_uid) != 0) {
+if (DOLOGOUT($target_user) != 0) {
     PAGEHEADER("Logout");
     echo "<center><h3>Logout '$target_uid' failed!</h3></center>\n";
     PAGEFOOTER();
diff --git a/www/menu.php3 b/www/menu.php3
index 3e88baa1b489656c8220898cf836de3ba1503121..8dbab386e7b3e1bfec3cdc40cde09fac362a9d35 100644
--- a/www/menu.php3
+++ b/www/menu.php3
@@ -5,8 +5,8 @@
 # All rights reserved.
 #
 
+$login_user       = null;
 $login_status     = CHECKLOGIN_NOTLOGGEDIN;
-$login_uid        = 0;
 $drewheader       = 0;
 $noheaders	  = 0;
 $autorefresh      = 0;
@@ -130,7 +130,7 @@ function WRITESIDEBARNOTICE($text) {
 #
 function WRITEPLABTOPBAR() {
     echo "<table class=\"topbar\" width=\"100%\" cellpadding=\"2\" cellspacing=\"0\" align=\"center\">\n";
-    global $login_status, $login_uid;
+    global $login_status, $login_user;
     global $TBBASE, $TBDOCBASE, $BASEPATH;
     global $THISHOMEBASE;
 
@@ -141,37 +141,14 @@ function WRITEPLABTOPBAR() {
         $TBBASE, "plabmetrics.php3");
 
     WRITETOPBARBUTTON("My Testbed",
-	$TBBASE,
-	"showuser.php3?target_uid=$login_uid");
-
+		      $TBBASE, CreateURL("showuser", $login_user));
 
     WRITETOPBARBUTTON("Advanced Experiment",
         $TBBASE, "beginexp_html.php3");
 
-    if ($login_status & CHECKLOGIN_TRUSTED) {
-	# Only project/group leaders can do these options
-	# Show a "new" icon if there are people waiting for approval
-	$query_result =
-	DBQueryFatal("select g.* from group_membership as authed ".
-		     "left join group_membership as g on ".
-		     " g.pid=authed.pid and g.gid=authed.gid ".
-		     "left join users as u on u.uid=g.uid ".
-		     "where u.status!='".
-		     TBDB_USERSTATUS_UNVERIFIED . "' and ".
-		     " u.status!='" . TBDB_USERSTATUS_NEWUSER . 
-		     "' and g.uid!='$login_uid' and ".
-		     "  g.trust='". TBDB_TRUSTSTRING_NONE . "' ".
-		     "  and authed.uid='$login_uid' and ".
-		     "  (authed.trust='group_root' or ".
-		     "   authed.trust='project_root') ".
-		     "ORDER BY g.uid,g.pid,g.gid");
-	if (mysql_num_rows($query_result) > 0) {
-	     WRITETOPBARBUTTON_NEW("Approve Users",
-				   $TBBASE, "approveuser_form.php3");
-	} else {
-	    WRITETOPBARBUTTON("Approve Users",
+    if ($login_status & CHECKLOGIN_TRUSTED && $login_user->ApprovalList(0)) {
+	WRITESIDEBARBUTTON_NEW("Approve Users",
 			       $TBBASE, "approveuser_form.php3");
-	}
     }
 
     WRITETOPBARBUTTON("Log Out", $TBBASE, "logout.php3?next_page=" .
@@ -188,11 +165,11 @@ function WRITEPLABTOPBAR() {
 # across the bottom of the page rather than the top
 #
 function WRITEPLABBOTTOMBAR() {
-    global $login_status, $login_uid;
+    global $login_status, $login_user;
     global $TBBASE, $TBDOCBASE, $BASEPATH;
     global $THISHOMEBASE;
 
-    if ($login_uid) {
+    if ($login_user) {
 	$newsBase = $TBBASE; 
     } else {
 	$newsBase = $TBDOCBASE;
@@ -220,7 +197,7 @@ function WRITEPLABBOTTOMBAR() {
 # sees depends on the login status and the DB status.
 #
 function WRITESIDEBAR() {
-    global $login_status, $login_uid, $pid, $gid;
+    global $login_status, $login_user, $pid, $gid;
     global $TBBASE, $TBDOCBASE, $BASEPATH, $WIKISUPPORT, $MAILMANSUPPORT;
     global $BUGDBSUPPORT, $BUGDBURL, $CVSSUPPORT, $CHATSUPPORT;
     global $CHECKLOGIN_WIKINAME;
@@ -251,7 +228,7 @@ function WRITESIDEBAR() {
     #
     # This is so an admin can use the editing features of news.
     #
-    if ($login_uid) { # && ISADMIN($login_uid)) { 
+    if ($login_user) {
 	$newsBase = $TBBASE; 
     } else {
 	$newsBase = $TBDOCBASE;
@@ -406,7 +383,7 @@ function WRITESIDEBAR() {
 	echo "<a id='webdisabled' href='$TBDOCBASE/nologins.php3'>".
 	    "Web Interface Temporarily Unavailable</a>";
 
-        if (!$login_uid || !ISADMIN($login_uid)) {	
+        if (!$login_user || !ISADMIN()) {	
 	    WRITESIDEBARNOTICE("Please Try Again Later");
         }
     }
@@ -440,8 +417,8 @@ function WRITESIDEBAR() {
 	    elseif ($login_status & (CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY)) {
 		WRITESIDEBARBUTTON("My Emulab",
 				   $TBBASE,
-				   "showuser.php3?target_uid=$login_uid");
-
+				   CreateURL("showuser", $login_user));
+					     
 		if ($WIKISUPPORT && $CHECKLOGIN_WIKINAME != "") {
 		    $wikiname = $CHECKLOGIN_WIKINAME;
 		
@@ -451,12 +428,13 @@ function WRITESIDEBAR() {
 		}
 
 		WRITESIDEBARBUTTON("Update User Information",
-				   $TBBASE, "moduserinfo.php3");
+				   $TBBASE,
+				   CreateURL("moduserinfo", $login_user));
 	    }
 	    else {
 		WRITESIDEBARBUTTON("My Emulab",
 				   $TBBASE,
-				   "showuser.php3?target_uid=$login_uid");
+				   CreateURL("showuser", $login_user));
 
 		#
                 # Since a user can be a member of more than one project,
@@ -488,32 +466,11 @@ function WRITESIDEBAR() {
 	        	"ImageIDs</a> or <a " .
 	                "href=\"$TBBASE/showosid_list.php3\">OSIDs</a></li>";
 
-		if ($login_status & CHECKLOGIN_TRUSTED) {
-		  WRITESIDEBARDIVIDER();
-                  # Only project/group leaders can do these options
-                  # Show a "new" icon if there are people waiting for approval
-		  $query_result =
-		    DBQueryFatal("select g.* from group_membership as authed ".
-				 "left join group_membership as g on ".
-				 " g.pid=authed.pid and g.gid=authed.gid ".
-				 "left join users as u on u.uid=g.uid ".
-				 "where u.status!='".
-				 TBDB_USERSTATUS_UNVERIFIED . "' and ".
-				 " u.status!='" . TBDB_USERSTATUS_NEWUSER . 
-				 "' and g.uid!='$login_uid' and ".
-				 "  g.trust='". TBDB_TRUSTSTRING_NONE . "' ".
-				 "  and authed.uid='$login_uid' and ".
-				 "  (authed.trust='group_root' or ".
-				 "   authed.trust='project_root') ".
-				 "ORDER BY g.uid,g.pid,g.gid");
-		  if (mysql_num_rows($query_result) > 0) {
+		if ($login_status & CHECKLOGIN_TRUSTED &&
+		    $login_user->ApprovalList(0)) {
+		    WRITESIDEBARDIVIDER();
 		    WRITESIDEBARBUTTON_NEW("New User Approval",
 					   $TBBASE, "approveuser_form.php3");
-		  } else {
-
-		      WRITESIDEBARBUTTON("New User Approval",
-				       $TBBASE, "approveuser_form.php3");
-		  }
 		}
 	    }
 	}
@@ -521,11 +478,14 @@ function WRITESIDEBAR() {
 	    WRITESIDEBARBUTTON("New User Verification",
 			       $TBBASE, "verifyusr_form.php3");
 	    WRITESIDEBARBUTTON("Update User Information",
-			       $TBBASE, "moduserinfo.php3");
+			       $TBBASE,
+			       CreateURL("moduserinfo", $login_user));
 	}
 	elseif ($login_status & (CHECKLOGIN_UNAPPROVED)) {
 	    WRITESIDEBARBUTTON("Update User Information",
-			       $TBBASE, "moduserinfo.php3");
+			       $TBBASE,
+			       CreateURL("moduserinfo", $login_user));
+			       
 	}
 	#
 	# Standard options for logged in users!
@@ -542,8 +502,8 @@ function WRITESIDEBAR() {
     if ($login_status & (CHECKLOGIN_LOGGEDIN|CHECKLOGIN_MAYBEVALID)) {
         # Logout option. No longer take up space with an image.
 	WRITESIDEBARBUTTON("<b>Logout</b>",
-			   $TBBASE, "logout.php3?target_uid=$login_uid");
-	
+			   $TBBASE,
+			   CreateURL("logout", $login_user));
 	echo "</ul>\n";
     }
 
@@ -562,20 +522,14 @@ function WRITESIDEBAR() {
 	}
 	if ($MAILMANSUPPORT || $BUGDBSUPPORT) {
 	    if (!isset($pid) || $pid == "") {
-		$query_result =
-		    DBQueryFatal("select pid from group_membership where ".
-				 "uid='$login_uid' and pid=gid and ".
-				 "trust!='none' ".
-				 "order by date_approved asc limit 1");
-		if (mysql_num_rows($query_result)) {
-		    $row = mysql_fetch_array($query_result);
-		    $firstpid = $row[pid];
+		if (($project = $login_user->FirstApprovedProject())) {
+		    $firstpid = $project->pid();
 		}
 	    }
 	}
 	if ($MAILMANSUPPORT) {
-	    $mmurl  = "showmmlists.php3?target_uid=$login_uid";
-	    WRITESIDEBARBUTTON("My Mailing Lists", $TBBASE, $mmurl);
+	     WRITESIDEBARBUTTON("My Mailing Lists", $TBBASE,
+				CreateURL("showmmlists", $login_user));
 	}
 	if ($BUGDBSUPPORT) {
 	    $bugdburl = "gotobugdb.php3";
@@ -590,17 +544,17 @@ function WRITESIDEBAR() {
 	}
 	if ($CVSSUPPORT) {
 	    WRITESIDEBARBUTTON("My CVS Repositories", $TBBASE,
-			       "listrepos.php3?target_uid=$login_uid");
+			       CreateURL("listrepos", $login_user));
 	}
 	if ($CHATSUPPORT) {
 	    WRITESIDEBARBUTTON("My Chat Buddies", $TBBASE,
-			       "mychat.php3?target_uid=$login_uid");
+			       CreateURL("mychat", $login_user));
 	}
 	echo "</ul>\n";
     }
 
     # Optional ADMIN menu.
-    if ($login_status & CHECKLOGIN_LOGGEDIN && ISADMIN($login_uid)) {
+    if ($login_status & CHECKLOGIN_LOGGEDIN && ISADMIN()) {
 	echo "<h3 class='menuheader'>Administration</h3>
               <ul class='menu'>";
 	
@@ -750,7 +704,7 @@ function PAGEBEGINNING( $title, $nobanner = 0, $nocontent = 0,
 #
 function FINISHSIDEBAR($contentname = "content", $nocontent = 0)
 {
-    global $TBMAINSITE, $login_uid;
+    global $TBMAINSITE, $login_user;
 
     if (!$nocontent) {
 	if (!$TBMAINSITE) {
@@ -761,7 +715,7 @@ function FINISHSIDEBAR($contentname = "content", $nocontent = 0)
 	    echo "       <a class='builtwith' href='http://www.emulab.net'>
                          <img src='$BASEPATH/builtwith.png'></a>";
 	}
-	elseif ($login_uid) {
+	elseif ($login_user) {
 	    echo "<span class=gripe><a href='$TBBASE/gotobugdb.php3".
 	                    "?do=newtask&project_title=Emulab'>";
 	    echo "Report Bug, Gripe, Request Feature</a>";
@@ -780,7 +734,8 @@ function FINISHSIDEBAR($contentname = "content", $nocontent = 0)
 # Spit out a vanilla page header.
 #
 function PAGEHEADER($title, $view = NULL, $extra_headers = NULL) {
-    global $login_status, $login_uid, $TBBASE, $TBDOCBASE, $THISHOMEBASE;
+    global $login_status, $login_user;
+    global $TBBASE, $TBDOCBASE, $THISHOMEBASE;
     global $BASEPATH, $SSL_PROTOCOL, $drewheader, $autorefresh;
     global $TBMAINSITE;
 
@@ -791,15 +746,10 @@ function PAGEHEADER($title, $view = NULL, $extra_headers = NULL) {
 
     #
     # Figure out who is logged in, if anyone.
-    # 
-    if (($known_uid = GETUID()) != FALSE) {
-        #
-        # Check to make sure the UID is logged in (not timed out).
-        #
-        $login_status = CHECKLOGIN($known_uid);
-	if ($login_status & (CHECKLOGIN_LOGGEDIN|CHECKLOGIN_MAYBEVALID)) {
-	    $login_uid = $known_uid;
-	}
+    #
+    if (($login_user = CheckLogin($status)) != null) {
+	$login_status = $status;
+	$login_uid    = $login_user->uid();
     }
 
     #
@@ -814,10 +764,10 @@ function PAGEHEADER($title, $view = NULL, $extra_headers = NULL) {
     # We want to allow admin types to continue using the web interface,
     # and logout anyone else that is currently logged in!
     #
-    if (NOLOGINS() && $login_uid && !ISADMIN($login_uid)) {
-	DOLOGOUT($login_uid);
+    if (NOLOGINS() && $login_user && !ISADMIN()) {
+	DOLOGOUT($login_user);
 	$login_status = CHECKLOGIN_NOTLOGGEDIN;
-	$login_uid    = 0;
+	$login_user   = null;
     }
     
     header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
@@ -856,7 +806,7 @@ function PAGEHEADER($title, $view = NULL, $extra_headers = NULL) {
     echo "<div id='logintime'>";
     echo "<span id='loggedin'>";
     $now = date("D M d g:ia T");
-    if ($login_uid) {
+    if ($login_user) {
 	echo "<span class='uid'>$login_uid</span> Logged in.";
     }
     echo "</span>";
@@ -874,13 +824,21 @@ function PAGEHEADER($title, $view = NULL, $extra_headers = NULL) {
     echo "<div id='versioninfo'>$versioninfo</div>";
 
     echo "<h2 class='contenttitle'>\n";
-    if ($login_uid && ISADMINISTRATOR()) {
-	if (ISADMIN($login_uid)) {
-	    echo "<a href=\"$TBBASE/toggle.php?target_uid=$login_uid&type=adminon&value=0\"><img src='/redball.gif'
+    if ($login_user && ISADMINISTRATOR()) {
+	if (ISADMIN()) {
+	    $url = CreateURL("toggle", $login_user,
+			     "type", "adminon", "value", 0);
+
+	    echo "<a href=\"$TBBASE/$url\">
+                      <img src='/redball.gif'
                           border='0' alt='Admin On'></a>\n";
 	}
 	else {
-	    echo "<a href=\"$TBBASE/toggle.php?target_uid=$login_uid&type=adminon&value=1\"><img src='/greenball.gif'
+	    $url = CreateURL("toggle", $login_user,
+			     "type", "adminon", "value", 1);
+
+	    echo "<a href=\"$TBBASE/$url\">
+                       <img src='/greenball.gif'
                           border='0' alt='Admin Off'></a>\n";
 	}
     }
@@ -905,7 +863,7 @@ function ENDPAGE() {
 function PAGEFOOTER($view = NULL) {
     global $TBDOCBASE, $TBMAILADDR, $THISHOMEBASE, $BASEPATH, $TBBASE;
     global $TBMAINSITE, $SSL_PROTOCOL, $bodyclosestring, $currently_busy;
-    global $login_uid;
+    global $login_user;
 
     if ($currently_busy) {
 	CLEARBUSY();
@@ -948,7 +906,7 @@ function PAGEFOOTER($view = NULL) {
 	               "border='0' cellspacing='0' cellpadding='0'>";
     echo "       <tr>\n";
     
-    if ($login_uid) {
+    if ($login_user) {
 	echo "    <td class=reportbug>";
 	echo "      <a href='$TBBASE/gotobugdb.php3".
 	                    "?do=newtask&project_title=Emulab'>";
diff --git a/www/modifyexp.php3 b/www/modifyexp.php3
index 1b71302c7cf9e07cdb019d09c9fd17d3a2ce1f06..d57a1e249f01cd006a73984c78fbcf756fdd7d7e 100644
--- a/www/modifyexp.php3
+++ b/www/modifyexp.php3
@@ -11,11 +11,11 @@ $parser   = "$TB/libexec/ns2ir/parse-ns";
 $TMPDIR   = "/tmp/";
 
 #
-# Only known and logged in users can modify experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 if (isset($formfields['exp_localnsfile'])) {
     $exp_localnsfile = $formfields['exp_localnsfile'];
diff --git a/www/modnodeattributes.php3 b/www/modnodeattributes.php3
index 875c3c3c1f0dbba6faca74f4842496730c4cf220..e1cec42c0c0c2d6ff1286ad416edd021cbbd9026 100644
--- a/www/modnodeattributes.php3
+++ b/www/modnodeattributes.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -15,8 +15,9 @@ PAGEHEADER("Modify Node Attributes Form");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Check to make sure that this is a valid nodeid
@@ -42,7 +43,6 @@ while($row = mysql_fetch_array($attr_result)) {
 #
 # Only admin users may modify node attributes.
 #
-$isadmin = ISADMIN($uid);
 if (! $isadmin) {
   USERERROR("You do not have permission to modify node $node_id!", 1);
 }
diff --git a/www/modnodeattributes_form.php3 b/www/modnodeattributes_form.php3
index ba0dc227f6dea106ae77354efd7b28ed9b16bee4..6951924b7fc91b2281a4d06e5120edb517c21571 100644
--- a/www/modnodeattributes_form.php3
+++ b/www/modnodeattributes_form.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,8 +14,9 @@ PAGEHEADER("Modify Node Attributes Form");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify form arguments.
@@ -38,7 +39,6 @@ $noderow = mysql_fetch_array($query_result);
 #
 # Only admin users can modify node attributes.
 #
-$isadmin = ISADMIN($uid);
 if (! $isadmin) {
   USERERROR("You do not have permission to modify node $node_id!", 1);
 }
diff --git a/www/moduserinfo.php3 b/www/moduserinfo.php3
index 1338470b3d5ca225b851229c71867cbe5497a1a0..9123b0e3500ed4d6bcf8e098011b0c8bc43f2320 100644
--- a/www/moduserinfo.php3
+++ b/www/moduserinfo.php3
@@ -10,19 +10,12 @@ include("showstuff.php3");
 #
 # No PAGEHEADER since we spit out a Location header later. See below.
 # 
-
-#
-# Only known and logged in users can modify info.
-#
-# Note different test though, since we want to allow logged in
-# users with expired passwords to change them.
+# We want to allow logged in users with expired passwords to change them.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid,
-	      CHECKLOGIN_USERSTATUS|CHECKLOGIN_PSWDEXPIRED|
-	      CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY);
-$isadmin = ISADMIN($uid);
-
+$this_user = CheckLoginOrDie(CHECKLOGIN_USERSTATUS|CHECKLOGIN_PSWDEXPIRED|
+			     CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY);
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 # Shell options we support. Maybe stick in DB someday.
 $shelllist = array( 'tcsh', 'bash', 'csh', 'sh' );
@@ -39,8 +32,12 @@ $wikionly = 0;
 function SPITFORM($formfields, $errors)
 {
     global $TBDB_UIDLEN, $TBDB_PIDLEN, $TBDB_GIDLEN, $isadmin;
-    global $target_uid, $wikionly;
+    global $target_user, $wikionly;
     global $shelllist, $defaultshell;
+
+    $username = $target_user->uid();
+    $uid_idx  = $target_user->uid_idx();
+    $webid    = $target_user->webid();
     
     #
     # Standard Testbed Header. Written late cause of password
@@ -87,13 +84,11 @@ function SPITFORM($formfields, $errors)
         #
         echo "<tr>
                   <td colspan=2>Username:</td>
-                  <td class=left>
-                      $formfields[target_uid]
+                  <td class=left>$username ($uid_idx)
                       <input type=hidden
-                             name=\"formfields[target_uid]\"
-                             value=\"" . $formfields[target_uid] . "\"
-                             size=$TBDB_UIDLEN
-   	                     maxlength=$TBDB_UIDLEN>
+                             name=\"formfields[user]\"
+                             value=\"" . $webid . "\"
+                             size=$TBDB_UIDLEN>
               </td>
              </tr>\n";
 
@@ -341,10 +336,10 @@ function SPITFORM($formfields, $errors)
                  security policies</a> for information
                  regarding passwords and email addresses.\n";
     if (!$wikionly) {
+	$pubkey_url = CreateURL("showpubkeys", $target_user);
+	
 	echo "<li> You can also
-                 <a href='showpubkeys.php3?target_uid=$target_uid'>
-                 edit your ssh public keys</a> and your
-                 <a href='showsfskeys.php3?target_uid=$target_uid'>
+                 <a href='$pubkey_url'>edit your ssh public keys</a>.
 		 sfs public keys</a>.
             <li> The City, State, ZIP/Postal Code, and Country fields 
                  were added later, so
@@ -369,82 +364,81 @@ function SPITFORM($formfields, $errors)
 #
 if (! isset($_POST['submit'])) {
     # First page load. Default to current user.
-    if (! isset($_GET['target_uid']))
-	$target_uid = $uid;
+    if (! isset($_GET['user']))
+	$user = $uid;
     else
-	$target_uid = $_GET['target_uid'];
+	$user = $_GET['user'];
 }
 else {
-    # Form submitted. Make sure we have a formfields array and a target_uid.
+    # Form submitted. Make sure we have a formfields array and a user.
     if (!isset($_POST['formfields']) ||
 	!is_array($_POST['formfields']) ||
-	!isset($_POST['formfields']['target_uid'])) {
+	!isset($_POST['formfields']['user'])) {
 	PAGEARGERROR("Invalid form arguments!");
     }
     $formfields = $_POST['formfields'];
-    $target_uid = $formfields['target_uid'];
+    $user       = $formfields['user'];
 }
 
 # Pedantic check of uid before continuing.
-if ($target_uid == "" || !TBvalid_uid($target_uid)) {
-    PAGEARGERROR("Invalid uid: '$target_uid'");
+if ($user == "" || !User::ValidWebID($user)) {
+    PAGEARGERROR("Invalid uid: '$user'");
 }
 
 #
-# Admin types can change anyone. 
+# Confirm target is a real user.
 #
-if (! $isadmin &&
-    $uid != $target_uid &&
-    ! TBUserInfoAccessCheck($uid, $target_uid, $TB_USERINFO_MODIFYINFO)) {
-    USERERROR("You do not have permission to modify information for ".
-	      "user: $target_uid!", 1);
+if (! ($target_user = User::Lookup($user))) {
+    USERERROR("No such user '$user'", 1);
 }
+$target_uid = $target_user->uid();
 
 #
-# Suck the current info out of the database.
+# Admin types can change anyone. 
 #
-$query_result =
-    DBQueryFatal("select * from users where uid='$target_uid'");
-
-if (mysql_num_rows($query_result) == 0) {
-    USERERROR("No such user: $target_uid", 1);
+if (!$isadmin && 
+    !$target_user->AccessCheck($this_user, $TB_USERINFO_MODIFYINFO)) {
+    USERERROR("You do not have permission to modify information for ".
+	      "user: $target_uid!", 1);
 }
 
-$defaults = array();
-    
 #
 # Construct a defaults array based on current DB info. Used for the initial
 # form, and to determine if any changes were made. This is to avoid churning
 # the passwd file for no reason, given that most people use this page
 # simply to change their password. 
-# 
-$row = mysql_fetch_array($query_result);
-$defaults[target_uid]  = $target_uid;
-$defaults[usr_email]   = $row[usr_email];
-$defaults[usr_URL]     = $row[usr_URL];
-$defaults[usr_addr]    = $row[usr_addr];
-$defaults[usr_addr2]   = $row[usr_addr2];
-$defaults[usr_city]    = $row[usr_city];
-$defaults[usr_state]   = $row[usr_state];
-$defaults[usr_zip]     = $row[usr_zip];
-$defaults[usr_country] = $row[usr_country];
-$defaults[usr_name]    = $row[usr_name];
-$defaults[usr_phone]   = $row[usr_phone];
-$defaults[usr_title]   = $row[usr_title];
-$defaults[usr_affil]   = $row[usr_affil];
-$defaults[usr_shell]   = $row[usr_shell];
-$defaults[notes]       = $row[notes];
-$defaults[user_interface] = $row[user_interface];
-$wikionly              = $row[wikionly];
-
-# Show and keep the Windows password if user-set, otherwise fill in the random one.
-if (strcmp($row[usr_w_pswd],""))
-    $defaults[w_password1] = $defaults[w_password2] = $row[usr_w_pswd];
+#
+$defaults	       = array();
+$defaults[user]        = $target_user->webid();
+$defaults[usr_email]   = $target_user->email();
+$defaults[usr_URL]     = $target_user->URL();
+$defaults[usr_addr]    = $target_user->addr();
+$defaults[usr_addr2]   = $target_user->addr2();
+$defaults[usr_city]    = $target_user->city();
+$defaults[usr_state]   = $target_user->state();
+$defaults[usr_zip]     = $target_user->zip();
+$defaults[usr_country] = $target_user->country();
+$defaults[usr_name]    = $target_user->name();
+$defaults[usr_phone]   = $target_user->phone();
+$defaults[usr_title]   = $target_user->title();
+$defaults[usr_affil]   = $target_user->affil();
+$defaults[usr_shell]   = $target_user->shell();
+$defaults[notes]       = $target_user->notes();
+$defaults[user_interface] = $target_user->user_interface();
+$wikionly              = $target_user->wikionly();
+
+# Show and keep the Windows password if user-set, otherwise fill in the
+# random one. 
+if ($target_user->w_pswd() != "") {
+    $defaults[w_password1] = $defaults[w_password2] = $target_user->w_pswd();
+}
 else {
+    #
     # The initial random default for the Windows Password is based on the Unix
     # encrypted password, in particular the random salt if it's an MD5 crypt,
-    # consisting of the 8 characters after an initial "$1$" and followed by a "$". 
-    $unixpwd = explode('$', $row[usr_pswd]);
+    # consisting of the 8 chars after an initial "$1$" and followed by "$".
+    #
+    $unixpwd = explode('$', $target_user->pswd());
     if (strlen($unixpwd[0]) > 0)
 	# When there's no $ at the beginning, its not an MD5 hash.
 	$randpwd = substr($unixpwd[0],0,8);
@@ -519,7 +513,8 @@ if (!isset($formfields[usr_email]) ||
 elseif (! TBvalid_email($formfields[usr_email])) {
     $errors["Email Address"] = TBFieldErrorString();
 }
-elseif (! TBUniqueEmail($target_uid, $formfields[usr_email])) {
+elseif (($temp_user = User::LookupByEmail($formfields[usr_email])) &&
+	!$target_user->SameUser($temp_user)) {
     $errors["Email Address"] = "Already in use by another user!";
 }
 if (!$isadmin && !$wikionly) {
@@ -587,7 +582,7 @@ if (isset($formfields[password1]) &&
     elseif (strcmp($formfields[password1], $formfields[password2])) {
 	$errors["Retype Password"] = "Two Passwords Do Not Match";
     }
-    elseif (! CHECKPASSWORD($formfields[target_uid],
+    elseif (! CHECKPASSWORD($target_uid,
 			    $formfields[password1],
 			    $formfields[usr_name],
 			    $formfields[usr_email], $checkerror)) {
@@ -604,7 +599,7 @@ if (isset($formfields[w_password1]) &&
     elseif (strcmp($formfields[w_password1], $formfields[w_password2])) {
 	$errors["Retype Windows Password"] = "Two Windows Passwords Do Not Match";
     }
-    elseif (! CHECKPASSWORD($formfields[target_uid],
+    elseif (! CHECKPASSWORD($target_uid,
 			    $formfields[w_password1],
 			    $formfields[usr_name],
 			    $formfields[usr_email], $checkerror)) {
@@ -618,78 +613,46 @@ if (count($errors)) {
 }
 
 PAGEHEADER("Modify User Information");
-
-$usr_name     = addslashes($formfields[usr_name]);
-$usr_email    = $formfields[usr_email];
-$password1    = $formfields[password1];
-$password2    = $formfields[password2];
-$usr_title    = addslashes($formfields[usr_title]);
-$usr_affil    = addslashes($formfields[usr_affil]);
-$usr_addr     = addslashes($formfields[usr_addr]);
-$usr_city     = addslashes($formfields[usr_city]);
-$usr_state    = addslashes($formfields[usr_state]);
-$usr_zip      = addslashes($formfields[usr_zip]);
-$usr_country  = addslashes($formfields[usr_country]);
-$usr_phone    = $formfields[usr_phone];
-$usr_shell    = $formfields[usr_shell];
-$w_password1  = $formfields[w_password1];
-$w_password2  = $formfields[w_password2];
-
-if (! isset($formfields[usr_URL]) ||
-    strcmp($formfields[usr_URL], "") == 0 ||
-    strcmp($formfields[usr_URL], $HTTPTAG) == 0) {
-    $usr_URL = "";
-}
-else {
-    $usr_URL = addslashes($formfields[usr_URL]);
-}
-
-if (! isset($formfields[usr_addr2])) {
-    $usr_addr2 = "";
-}
-else {
-    $usr_addr2 = addslashes($formfields[usr_addr2]);
-}
+STARTBUSY("Making user profile changes");
 
 #
 # Only admin types can change the email address. If its different, the
 # user circumvented the form, and so its okay to blast it.
 #
-TBUserInfo($target_uid, $dbusr_name, $dbusr_email);
-
-if (strcmp($usr_email, $dbusr_email)) {
+if ($target_user->email() != $formfields["usr_email"]) {
     if (!$isadmin) {
 	USERERROR("You are not allowed to change your email address. <br> ".
 		  "Please contact Testbed Operations.", 1);
     }
-    DBQueryFatal("update users set usr_email='$usr_email' ".
-		 "where uid='$target_uid'");
-}
+    $target_user->SetEmail($formfields["usr_email"]);
 
-STARTBUSY("Making user profile changes");
+    TBMAIL($TBMAIL_AUDIT,
+	   "Email Address for '$target_uid' Modified",
+	   "\n".
+	   "Email Address for '$target_uid' changed by '$uid'.\n".
+	   "\n".
+	   "Name:              " . $target_user->name()  . "\n".
+	   "IDX:               " . $target_user->uid_idx()  . "\n".
+	   "Email:             " . $target_user->email() . "\n",
+	   "From: $TBMAIL_OPS\n".
+	   "Errors-To: $TBMAIL_WWW");
+}
 
 #
 # Now see if the user is requesting to change the password. We checked
 # them above when the form was submitted.
 #
-if ((isset($password1) && strcmp($password1, "")) &&
-    (isset($password2) && strcmp($password2, ""))) {
+if ((isset($formfields["password1"]) && $formfields["password1"] != "") &&
+    (isset($formfields["password2"]) && $formfields["password2"] != "")) {
 
-    $query_result =
-	DBQueryFatal("select usr_pswd from users WHERE uid='$target_uid'");
-    if (! mysql_num_rows($query_result)) {
-	TBERROR("Error getting usr_pswd for $target_uid", 1);
-    }
-    $row = mysql_fetch_array($query_result);
-    $old_encoding = $row[usr_pswd];
-    $new_encoding = crypt("$password1", $old_encoding);
+    $old_encoding = $target_user->pswd();
+    $new_encoding = crypt($formfields["password1"], $old_encoding);
 
     #
     # Compare. Must change it!
     # 
     if (! strcmp($old_encoding, $new_encoding)) {
 	$errors["New Password"] = "New password is the same as old password";
-
 	SPITFORM($formfields, $errors);
 	PAGEFOOTER();
 	return;
@@ -699,23 +662,20 @@ if ((isset($password1) && strcmp($password1, "")) &&
     # Do it again. This ensures we use the current algorithm, not whatever
     # it was encoded with last time.
     #
-    $new_encoding = crypt("$password1");
+    $new_encoding = crypt($formfields["password1"]);
 
     #
     # Insert into database. When changing password for someone else,
     # always set the expiration to right now so that the target user
     # is "forced" to change it. 
     #
-    if ($uid != $target_uid)
+    if (! $target_user->SameUser($this_user))
 	$expires = "now()";
     else
 	$expires = "date_add(now(), interval 1 year)";
-    
-    $insert_result =
-	DBQueryFatal("UPDATE users SET usr_pswd='$new_encoding', ".
-		     "pswd_expires=$expires ".
-		     "WHERE uid='$target_uid'");
 
+    $target_user->SetPassword($new_encoding, $expires);
+    
     if ($wikionly) {
 	if ($CHECKLOGIN_STATUS & CHECKLOGIN_ACTIVE) {
 	    SUEXEC("nobody", "nobody", "webtbacct passwd $target_uid",
@@ -733,15 +693,11 @@ if ((isset($password1) && strcmp($password1, "")) &&
 # them above when the form was submitted.
 #
 if (!$wikionly &&
-    ((isset($w_password1) && strcmp($w_password1, "")) &&
-     (isset($w_password2) && strcmp($w_password2, "")))) {
-
-    #
-    # Insert into database.
-    $insert_result =
-	DBQueryFatal("UPDATE users SET usr_w_pswd='$w_password1' ".
-		     "WHERE uid='$target_uid'");
+    ((isset($formfields["w_password1"]) && $formfields["w_password1"] != "") &&
+     (isset($formfields["w_password2"]) && $formfields["w_password2"] != ""))){
 
+    $target_user->SetWindowsPassword($formfields["w_password1"]);
+    
     if (HASREALACCOUNT($uid) && HASREALACCOUNT($target_uid)) {
 	SUEXEC($uid, "nobody", "webtbacct wpasswd $target_uid", 1);
     }
@@ -751,12 +707,8 @@ if (!$wikionly &&
 # Only admins can change the notes field. We do not bother to generate
 # any email or external updates for this.
 #
-if ($isadmin &&
-    strcmp($defaults[notes], $formfields[notes])) {
-    $notes = addslashes($formfields[notes]);
-
-    DBQueryFatal("UPDATE users SET notes='$notes' ".
-		 "WHERE uid='$target_uid'");
+if ($isadmin && $target_user->notes() != $formfields["notes"]) {
+    $target_user->SetNotes($formfields["notes"]);
 }
 
 #
@@ -769,60 +721,53 @@ if (isset($formfields[user_interface]) &&
 else {
     $user_interface = TBDB_USER_INTERFACE_EMULAB;
 }
-if ($defaults[user_interface] != $user_interface) {
-    DBQueryFatal("update users set ".
-		 "user_interface='$user_interface' ".
-		 "where uid=\"$target_uid\"");
-}
-
-#
-# Now change the rest of the information, but only if the user actually
-# changed the info. We use the original info in the defaults array and
-# the value in the formfields array to compare, cause of addslashes stuff. 
-#
-if (strcmp($defaults[usr_name],  $formfields[usr_name]) ||
-    strcmp($defaults[usr_URL],   $formfields[usr_URL]) ||
-    strcmp($defaults[usr_addr],  $formfields[usr_addr]) ||
-    strcmp($defaults[usr_addr2], $formfields[usr_addr2]) ||
-    strcmp($defaults[usr_city],  $formfields[usr_city]) ||
-    strcmp($defaults[usr_state], $formfields[usr_state]) ||
-    strcmp($defaults[usr_zip],   $formfields[usr_zip]) ||
-    strcmp($defaults[usr_country],   $formfields[usr_country]) ||
-    strcmp($defaults[usr_phone], $formfields[usr_phone]) ||
-    strcmp($defaults[usr_title], $formfields[usr_title]) ||
-    strcmp($defaults[usr_affil], $formfields[usr_affil]) ||
-    strcmp($defaults[usr_shell], $formfields[usr_shell]) ||
-    # Check this too, since we want to call out if the email addr changed.
-    strcmp($defaults[usr_email], $formfields[usr_email])) {
-
-    DBQueryFatal("UPDATE users SET ".
-		 "usr_name=\"$usr_name\",       ".
-		 "usr_URL=\"$usr_URL\",         ".
-		 "usr_addr=\"$usr_addr\",       ".
-		 "usr_addr2=\"$usr_addr2\",     ".
-		 "usr_city=\"$usr_city\",       ".
-		 "usr_state=\"$usr_state\",     ".
-		 "usr_zip=\"$usr_zip\",         ".
-		 "usr_country=\"$usr_country\", ".
-		 "usr_phone=\"$usr_phone\",     ".
-		 "usr_title=\"$usr_title\",     ".
-		 "usr_affil=\"$usr_affil\",     ".
-		 "usr_shell=\"$usr_shell\",     ".
-		 "usr_modified=now()            ".
-		 "WHERE uid=\"$target_uid\"");
-
-    # Only to user. We care about password and email changes only.
-    $BCC = "";
-    if (strcmp($usr_email, $dbusr_email)) {
-	$BCC = "\nBcc: $TBMAIL_AUDIT";
-    }
-    
+if ($target_user->user_interface() != $user_interface) {
+    $target_user->SetUserInterface($user_interface);
+}
+
+#
+# Now change the rest of the information.
+$usr_name     = $formfields[usr_name];
+$usr_email    = $formfields[usr_email];
+$usr_title    = $formfields[usr_title];
+$usr_affil    = $formfields[usr_affil];
+$usr_addr     = $formfields[usr_addr];
+$usr_city     = $formfields[usr_city];
+$usr_state    = $formfields[usr_state];
+$usr_zip      = $formfields[usr_zip];
+$usr_country  = $formfields[usr_country];
+$usr_phone    = $formfields[usr_phone];
+$usr_shell    = $formfields[usr_shell];
+
+if (! isset($formfields[usr_URL]) ||
+    strcmp($formfields[usr_URL], "") == 0 ||
+    strcmp($formfields[usr_URL], $HTTPTAG) == 0) {
+    $usr_URL = "";
+}
+else {
+    $usr_URL = $formfields[usr_URL];
+}
+
+if (! isset($formfields[usr_addr2])) {
+    $usr_addr2 = "";
+}
+else {
+    $usr_addr2 = $formfields[usr_addr2];
+}
+
+$modified = $target_user->ChangeProfile($usr_name,  $usr_title,
+					$usr_affil, $usr_addr,
+					$usr_addr2, $usr_city,
+					$usr_state, $usr_zip, $usr_country,
+					$usr_phone, $usr_shell, $usr_URL);
+if ($modified) {
     TBMAIL("$usr_name <$usr_email>",
 	   "User Information for '$target_uid' Modified",
 	   "\n".
 	   "User information for '$target_uid' changed by '$uid'.\n".
 	   "\n".
 	   "Name:              $usr_name\n".
+	   "IDX:               " . $target_user->uid_idx()  . "\n".
 	   "Email:             $usr_email\n".
 	   "URL:               $usr_URL\n".
 	   "Affiliation:       $usr_affil\n".
@@ -836,8 +781,8 @@ if (strcmp($defaults[usr_name],  $formfields[usr_name]) ||
 	   "Job Title:         $usr_title\n".
 	   "Shell:             $usr_shell\n",
 	   "WikiOnly:	       $wikionly\n",
-	   "From: $TBMAIL_OPS".
-	   $BCC .
+	   "From: $TBMAIL_OPS\n".
+	   "Bcc: $TBMAIL_AUDIT\n" .
 	   "Errors-To: $TBMAIL_WWW");
 
     #
@@ -854,7 +799,7 @@ STOPBUSY();
 # 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.
 # 
-PAGEREPLACE("showuser.php3?target_uid=$target_uid#PROFILE");
+PAGEREPLACE(CreateURL("showuser", $target_user) . "#PROFILE");
 
 #
 # Standard Testbed Footer
diff --git a/www/moteleds.php3 b/www/moteleds.php3
index a463f2d2bea795a8b949d38f2c220b4661614e22..5c1dbef22f3ede1a8da0085fc97d2cf5aa94ea53 100644
--- a/www/moteleds.php3
+++ b/www/moteleds.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2004, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2004, 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 
@@ -11,8 +11,9 @@ include("showstuff.php3");
 #
 # Make sure they are logged in
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/mychat.php3 b/www/mychat.php3
index 606709a7647fa44b4662c0fdba763b61befdfdca..d3dbbedc213367296932e50b506c589f6be9872f 100644
--- a/www/mychat.php3
+++ b/www/mychat.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,18 +14,11 @@ if (!$CHATSUPPORT) {
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
-$query_result =
-    DBQueryFatal("select mailman_password from users where uid='$uid'");
-
-if (!mysql_num_rows($query_result)) {
-    USERERROR("No such user $uid!", 1);
-}
-$row = mysql_fetch_array($query_result);
-$password = $row['mailman_password'];
+$password = $this_user->mailman_password();
 
 PAGEHEADER("My Instant Messaging");
 
diff --git a/www/newgroup.php3 b/www/newgroup.php3
index b68616edbc1a0465f92b08a62de0d6238b799e58..6d498dec003413ffa770dca6d54c0ddc5388b598 100644
--- a/www/newgroup.php3
+++ b/www/newgroup.php3
@@ -43,8 +43,9 @@ if (!isset($group_leader) ||
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Check ID for sillyness.
@@ -116,11 +117,11 @@ if ($count == $maxtries) {
 }
 
 # Need the user object for creating the group.
-if (! ($leader = User::LookupByUid($group_leader))) {
+if (! ($leader = User::Lookup($group_leader))) {
     TBERROR("Could not lookup user '$group_leader'!", 1);
 }
 # and the project.
-if (! ($project = Project::LookupByPid($group_pid))) {
+if (! ($project = Project::Lookup($group_pid))) {
     TBERROR("Could not lookup project '$group_pid'!", 1);
 }
 
@@ -158,8 +159,10 @@ STOPBUSY();
 #
 # Send an email message with a join link.
 #
-TBUserInfo($group_leader, $group_leader_name, $group_leader_email);
-TBUserInfo($uid, $user_name, $user_email);
+$group_leader_name  = $leader->name();
+$group_leader_email = $leader->email();
+$user_name          = $this_user->name();
+$user_email         = $this_user->email();
 
 TBMAIL("$group_leader_name '$group_leader' <$group_leader_email>",
        "New Group '$group_pid/$group_id' Created",
diff --git a/www/newgroup_form.php3 b/www/newgroup_form.php3
index 6bdb2831abb41a266fc6d723dc67dac9b804c0bf..c7c3de3a702a38bede0c62ea0489620865c091dc 100644
--- a/www/newgroup_form.php3
+++ b/www/newgroup_form.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2002, 2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,8 +14,9 @@ PAGEHEADER("Create a Project Group");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
@@ -26,7 +27,7 @@ if (!isset($pid) || strcmp($pid, "") == 0) {
     #
     # See what projects the uid can do this in.
     #
-    $projlist = TBProjList($uid, $TB_PROJECT_MAKEGROUP);
+    $projlist = $this_user->ProjectAccessList($TB_PROJECT_MAKEGROUP);
 
     if (! count($projlist)) {
 	USERERROR("You do not appear to be a member of any Projects in which ".
diff --git a/www/newimageid.php3 b/www/newimageid.php3
index 46b9f402ad74c3eae29792d7d9b82915e7d4846a..99b64dff282e40d4e0844d37fa7e1bbfb058f576 100644
--- a/www/newimageid.php3
+++ b/www/newimageid.php3
@@ -16,14 +16,14 @@ PAGEHEADER("Create a new Image Descriptor (long form)");
 #
 # Only known and logged in users!
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # See what projects the uid can do this in.
 #
-$projlist = TBProjList($uid, $TB_PROJECT_MAKEIMAGEID);
+$projlist = $this_user->ProjectAccessList($TB_PROJECT_MAKEIMAGEID);
 
 if (! count($projlist)) {
     USERERROR("You do not appear to be a member of any Projects in which ".
diff --git a/www/newimageid_ez.php3 b/www/newimageid_ez.php3
index b57ec14aeaea074f3d66481ec7b5de2f2573617f..b2bc88199471d0fe9c8f75179e4eb2fdcbdee847 100644
--- a/www/newimageid_ez.php3
+++ b/www/newimageid_ez.php3
@@ -49,14 +49,14 @@ PAGEHEADER("Create a new Image Descriptor ($title)");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # See what projects the uid can do this in.
 #
-$projlist = TBProjList($uid, $TB_PROJECT_MAKEIMAGEID);
+$projlist = $this_user->ProjectAccessList($TB_PROJECT_MAKEIMAGEID);
 
 if (! count($projlist)) {
     USERERROR("You do not appear to be a member of any Projects in which ".
diff --git a/www/newmmlist.php3 b/www/newmmlist.php3
index e987aabace4e4776624fdb7da1eaf8cd85ab9e8b..f476ae4c196de141a455a6e6f625d7efc158b4f5 100644
--- a/www/newmmlist.php3
+++ b/www/newmmlist.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -13,14 +13,14 @@ include("defs.php3");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # See what projects the uid can do this in.
 #
-$projlist = TBProjList($uid, $TB_PROJECT_READINFO);
+$projlist = $this_user->ProjectAccessList($TB_PROJECT_READINFO);
 
 if (! count($projlist)) {
     USERERROR("You do not appear to be a member of any Projects in which ".
diff --git a/www/newnode_edit.php3 b/www/newnode_edit.php3
index 5b22197d64ea4650a1cd356109ab50a337e7fff0..1194db579a2482d209f663e8f0fa2f77861f5933 100644
--- a/www/newnode_edit.php3
+++ b/www/newnode_edit.php3
@@ -1,7 +1,7 @@
 <?PHP
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2003, 2004 University of Utah and the Flux Group.
+# Copyright (c) 2003, 2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 require("defs.php3");
@@ -19,9 +19,10 @@ PAGEHEADER("New Testbed Node");
 #
 # Only admins can see this page
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
+
 if (! $isadmin) {
     USERERROR("You do not have admin privileges!", 1);
 }
diff --git a/www/newnodelog.php3 b/www/newnodelog.php3
index 9ab6ab68f951f5170a3a350dbcbb34149322477e..db9178c4542d68e9948eee5bedaa3a35ebcc74df 100644
--- a/www/newnodelog.php3
+++ b/www/newnodelog.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2002, 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -13,11 +13,11 @@ include("showstuff.php3");
 PAGEHEADER("Enter Node Log Entry");
 
 #
-# Only known and logged in users can create an OSID.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # First off, sanity check the form to make sure all the required fields
diff --git a/www/newnodelog_form.php3 b/www/newnodelog_form.php3
index d609baafd918ca2b8e72fc581928279a913bc599..f8da96858ffdb5fa88efc241ea1904c7b3afa1c7 100644
--- a/www/newnodelog_form.php3
+++ b/www/newnodelog_form.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2002, 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,9 +14,9 @@ PAGEHEADER("Enter Node Log Entry");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify form arguments.
diff --git a/www/newnodes_list.php3 b/www/newnodes_list.php3
index 257038d8623eed264ce53c54a54429c49d08a6a3..2f2cef2d1916b8a283d954dcf8be23db13440cdf 100644
--- a/www/newnodes_list.php3
+++ b/www/newnodes_list.php3
@@ -20,9 +20,10 @@ PAGEHEADER("New Testbed Nodes");
 #
 # Only admins can see this page
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
+
 if (! $isadmin) {
     USERERROR("You do not have admin privileges!", 1);
 }
diff --git a/www/newosid.php3 b/www/newosid.php3
index f12b4b9cd9b2931ffe5ace8055bca6eed0e6cc05..3ac9f034f2a2fedf453c1b48770e297d4e6e8997 100644
--- a/www/newosid.php3
+++ b/www/newosid.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,11 +14,11 @@ include("osiddefs.php3");
 PAGEHEADER("Create a new OS Descriptor");
 
 #
-# Only known and logged in users can create an OSID.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # First off, sanity check the form to make sure all the required fields
diff --git a/www/newosid_form.php3 b/www/newosid_form.php3
index 3b0d1fae39502b9a679746cd358f0d97d8052d7d..1099664f3fa32cf42c5b61ab198f582ced1f3a9c 100644
--- a/www/newosid_form.php3
+++ b/www/newosid_form.php3
@@ -15,14 +15,14 @@ PAGEHEADER("Create a new OS Descriptor");
 #
 # Only known and logged in users
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # See what projects the uid can do this in.
 #
-$projlist = TBProjList($uid, $TB_PROJECT_MAKEOSID);
+$projlist = $this_user->ProjectAccessList($TB_PROJECT_MAKEOSID);
 
 if (! count($projlist)) {
     USERERROR("You do not appear to be a member of any Projects in which ".
diff --git a/www/newproject.php3 b/www/newproject.php3
index 3ab2de6fd2b51f80a7d3f4fb862de0c5702f30db..11605f10f11ecc3dcc09d429aae65f1578981d3b 100755
--- a/www/newproject.php3
+++ b/www/newproject.php3
@@ -12,8 +12,8 @@ include("defs.php3");
 
 #
 # Get current user.
-# 
-$uid = GETLOGIN();
+#
+$this_user = CheckLogin($check_status);
 
 #
 # See if we are in an initial Emulab setup.
@@ -25,11 +25,11 @@ $FirstInitState = (TBGetFirstInitState() == "createproject");
 # If the login is not valid. We require that the user be logged in
 # to start a second project.
 #
-if ($uid && !$FirstInitState) {
+if ($this_user && !$FirstInitState) {
     # Allow unapproved users to create multiple projects ...
     # Must be verified though.
-    LOGGEDINORDIE($uid, CHECKLOGIN_UNAPPROVED|CHECKLOGIN_WEBONLY);
-    $proj_head_uid = $uid;
+    CheckLoginOrDie(CHECKLOGIN_UNAPPROVED|CHECKLOGIN_WEBONLY);
+    $proj_head_uid = $this_user->uid();
     $returning = 1;
 }
 else {
@@ -625,7 +625,7 @@ if (! isset($_POST['submit'])) {
     return;
 }
 else {
-    # Form submitted. Make sure we have a formfields array and a target_uid.
+    # Form submitted. Make sure we have a formfields array.
     if (!isset($_POST['formfields']) ||
 	!is_array($_POST['formfields'])) {
 	PAGEARGERROR("Invalid form arguments.");
@@ -650,7 +650,7 @@ if (! $returning) {
 	elseif (!TBvalid_uid($formfields[proj_head_uid])) {
 	    $errors["UserName"] = TBFieldErrorString();
 	}
-	elseif (TBCurrentUser($formfields[proj_head_uid]) ||
+	elseif (User::Lookup($formfields[proj_head_uid]) ||
 		posix_getpwnam($formfields[proj_head_uid])) {
 	    $errors["UserName"] = "Already in use. Pick another";
 	}
@@ -683,7 +683,7 @@ if (! $returning) {
 	elseif (! TBvalid_wikiname($formfields[wikiname])) {
 	    $errors["WikiName"] = TBFieldErrorString();
 	}
-	elseif (TBCurrentWikiName($formfields[wikiname])) {
+	elseif (User::LookupByWikiName($formfields[wikiname])) {
 	    $errors["WikiName"] = "Already in use. Pick another";
 	}
     }
@@ -701,7 +701,7 @@ if (! $returning) {
     elseif (! TBvalid_email($formfields[usr_email])) {
 	$errors["Email Address"] = TBFieldErrorString();
     }
-    elseif (TBCurrentEmail($formfields[usr_email])) {
+    elseif (User::LookupByEmail($formfields[usr_email])) {
         #
         # Treat this error separate. Not allowed.
         #
@@ -1000,7 +1000,8 @@ if (!$returning) {
     $args["usr_pswd"]      = crypt("$password1");
     $args["wikiname"]      = $wikiname;
 
-    if (! ($leader = User::NewUser($proj_head_uid, 1, 0, $args))) {
+    if (! ($leader = User::NewUser($proj_head_uid,
+				   TBDB_NEWACCOUNT_PROJLEADER, $args))) {
 	TBERROR("Could not create new user '$usr_email'!", 1);
     }
     # If null; used below
@@ -1012,10 +1013,7 @@ if (!$returning) {
     }
 }
 else {
-    if (! ($leader = User::LookupByUid($proj_head_uid))) {
-	TBERROR("Could not lookup project leader '$proj_head_uid'!", 1);
-    }
-
+    $leader = $this_user;
     $usr_title	   = $leader->title();
     $usr_name	   = $leader->name();
     $usr_affil	   = $leader->affil();
diff --git a/www/news.php3 b/www/news.php3
index 74b672cf2b7e90dd1e5bec7aefa27636197b431c..8a9560dd976910ea2017e58699af7802d48ade64 100644
--- a/www/news.php3
+++ b/www/news.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -12,16 +12,18 @@ include("defs.php3");
 #
 # If user is an admin, present edit options.
 #
-$uid = GETLOGIN();
+$this_user = CheckLogin($check_status);
 
 if (! isset($show_archived)) {
     $show_archived = 0;
 }
 $show_archived = ($show_archived ? 1 : 0);
 
-if ($uid) {
-    $isadmin = ISADMIN($uid);
-} else {
+if ($this_user) {
+    $uid     = $this_user->uid();
+    $isadmin = ISADMIN();
+}
+else {
     $isadmin = 0;
 }
 
diff --git a/www/nodecontrol.php3 b/www/nodecontrol.php3
index 54b0f0f35eff5eae4912a83c2da016d4f3035a90..68086f8d55f24fcdb7678568858085aa051b58d4 100644
--- a/www/nodecontrol.php3
+++ b/www/nodecontrol.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2002, 2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -15,8 +15,9 @@ PAGEHEADER("Node Control Form");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Check to make sure that this is a valid nodeid
@@ -32,7 +33,6 @@ $row = mysql_fetch_array($query_result);
 # Admin users can control any node, but normal users can only control
 # nodes in their own experiments.
 #
-$isadmin = ISADMIN($uid);
 if (! $isadmin) {
     if (! TBNodeAccessCheck($uid, $node_id, $TB_NODEACCESS_MODIFYINFO)) {
         USERERROR("You do not have permission to modify node $node_id!", 1);
diff --git a/www/nodecontrol_form.php3 b/www/nodecontrol_form.php3
index d181defc7f835d732a316f70b943a12bbbbdc14d..dc80fd13f49abfdbc8ac81e8db3e994ce1834734 100644
--- a/www/nodecontrol_form.php3
+++ b/www/nodecontrol_form.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2002, 2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,8 +14,9 @@ PAGEHEADER("Node Control Form");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify form arguments.
@@ -41,7 +42,6 @@ $row = mysql_fetch_array($query_result);
 # Admin users can control any node, but normal users can only control
 # nodes in their own experiments.
 #
-$isadmin = ISADMIN($uid);
 if (! $isadmin) {
     if (! TBNodeAccessCheck($uid, $node_id, $TB_NODEACCESS_MODIFYINFO)) {
         USERERROR("You do not have permission to modify node $node_id!", 1);
diff --git a/www/nodecontrol_list.php3 b/www/nodecontrol_list.php3
index e18d066eaf526568af1033ec1f90caa3d4a6d204..bae068ce6db961f579b56b2bda9fafed501b9140 100644
--- a/www/nodecontrol_list.php3
+++ b/www/nodecontrol_list.php3
@@ -20,27 +20,33 @@ PAGEHEADER("Node Control Center");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
 # 
-if (isset($target_uid)) {
-    if ($target_uid == "") {
-	$target_uid = $uid;
+if (isset($user)) {
+    if ($user == "") {
+	$user = $uid;
     }
-    elseif (! TBvalid_uid($target_uid)) {
-	PAGEARGERROR("Invalid characters in '$target_uid'");
+    elseif (! User::ValidWebID($user)) {
+	PAGEARGERROR("Invalid characters in '$user'");
     }
-    elseif (! TBUserInfoAccessCheck($uid, $target_uid, $TB_USERINFO_READINFO)) {
-	USERERROR("You do not have permission to view this user's ".
-		  "information!", 1);
+    elseif (! ($target_user = User::Lookup($user))) {
+	USERERROR("The user $user is not a valid user", 1);
     }
+    elseif (! $target_user->AccessCheck($this_user, $TB_USERINFO_READINFO)) {
+	USERERROR("You do not have permission to do this!", 1);
+    }
+    $target_uid  = $target_user->uid();
+    $target_idx  = $target_user->uid_idx();
 }
 else {
-    $target_uid = $uid;
+    $target_uid  = $uid;
+    $target_idx  = $this_user->uid_idx();
+    $target_user = $this_user;
 }
 
 echo "<b>Show: <a href='nodecontrol_list.php3?showtype=summary'>summary</a>,
@@ -177,7 +183,7 @@ if (! strcmp($showtype, "summary")) {
 		DBQueryFatal("select distinct type from group_membership as g ".
 			     "left join nodetypeXpid_permissions as p ".
 			     "     on g.pid=p.pid ".
-			     "where uid='$target_uid' $pidclause");
+			     "where uid_idx='$target_idx' $pidclause");
 	}
 	
 	while ($row = mysql_fetch_array($query_result)) {
@@ -236,7 +242,7 @@ if (! strcmp($showtype, "summary")) {
 	}
     }
 
-    $projlist = TBProjList($target_uid, $TB_PROJECT_CREATEEXPT);
+    $projlist = $target_user->ProjectAccessList($TB_PROJECT_CREATEEXPT);
     if (count($projlist) > 1) {
 	echo "<b>By Project Permission: ";
 	while (list($project) = each($projlist)) {
diff --git a/www/noderdp.php3 b/www/noderdp.php3
index 3188fa220bec7ee21b20c2c20807754e887800ee..1b273a03038aa1e6be0bffb7479c822f1c011f68 100644
--- a/www/noderdp.php3
+++ b/www/noderdp.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,20 +14,18 @@ include("defs.php3");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
 
-# Get the windows password from the database, or use a random default.
-$query_result =
-    DBQueryFatal("select usr_pswd, usr_w_pswd from users where uid='$uid'");
-$row = mysql_fetch_array($query_result);
-if (strcmp($row[usr_w_pswd],""))
-    $pswd = $row[usr_w_pswd];
+if ($this_user->w_pswd() != "") {
+    $pswd = $this_user->w_pswd();
+}
 else {
     # The initial random default for the Windows Password is based on the Unix
     # encrypted password, in particular the random salt if it's an MD5 crypt,
-    # consisting of the 8 characters after an initial "$1$" and followed by a "$". 
-    $unixpwd = explode('$', $row[usr_pswd]);
+    # consisting of the 8 characters after an initial "$1$" and followed by a
+    # "$". 
+    $unixpwd = explode('$', $this_user->pswd());
     if (strlen($unixpwd[0]) > 0)
 	# When there's no $ at the beginning, it's not an MD5 hash.
 	$pswd = substr($unixpwd[0],0,8);
diff --git a/www/nodessh.php3 b/www/nodessh.php3
index bcf26003cecc60e820577a02343ca1fd54987f8d..3e41e8dea7422eb647cc43d3b3895a4a21032fec 100644
--- a/www/nodessh.php3
+++ b/www/nodessh.php3
@@ -14,8 +14,9 @@ include("defs.php3");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify form arguments.
diff --git a/www/nodetipacl.php3 b/www/nodetipacl.php3
index 08d48ed1bfd73d459196aa2a35bf92f153c5c507..d636c4baa75467438be777a26a3b6faa3de6b505 100644
--- a/www/nodetipacl.php3
+++ b/www/nodetipacl.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2002, 2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,8 +14,9 @@ include("xmlrpc.php3");
 #
 # Only known and logged in users can get acls..
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify form arguments.
@@ -30,7 +31,7 @@ if (!isset($node_id) ||
 # nodes in their own experiments.
 #
 # XXX is MODIFYINFO the correct one to check? (probably)
-$isadmin = ISADMIN($uid);
+#
 if (! $isadmin) {
     if (! TBNodeAccessCheck($uid, $node_id, $TB_NODEACCESS_READINFO)) {
         USERERROR("You do not have permission to tip to node $node_id!", 1);
diff --git a/www/nscheck.php3 b/www/nscheck.php3
index 3417d771565f18dfdb9169d72c2b760c0f38e569..45da9aac263d7d681202095ac4a8cb99b0c91619 100644
--- a/www/nscheck.php3
+++ b/www/nscheck.php3
@@ -23,8 +23,9 @@ PAGEHEADER("Syntax Check an NS File", $view);
 #
 # Only known and logged in users can begin experiments.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Not allowed to specify both a local and an upload!
diff --git a/www/nscheck_form.php3 b/www/nscheck_form.php3
index d1a2b7f2b33390256d1366c14a6e4fdd6fe0bebc..9044e02e0d7d0726febc07bf6f8f7d27470c7c00 100644
--- a/www/nscheck_form.php3
+++ b/www/nscheck_form.php3
@@ -14,8 +14,9 @@ PAGEHEADER("Syntax Check your NS file");
 #
 # Only known and logged in users can begin experiments.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 ?>
 <table align="center" border="1"> 
diff --git a/www/nsgen.php3 b/www/nsgen.php3
index 7e4b52cd19a1847c8f239f3f9b184c8fd2e5956c..85d49e4ca01d462e6184b7f252326c84d216cd3e 100644
--- a/www/nsgen.php3
+++ b/www/nsgen.php3
@@ -21,8 +21,9 @@ if (!isset($template)) {
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Check to see if the template file actually exists
@@ -69,7 +70,7 @@ if ($submit == "Begin Experiment" || $submit == "Show NS File") {
     if ($submit == "Begin Experiment") {
         BEGINEXP($nsref);
     } else {
-        $filename =  $TMPDIR . GETUID() . "-$nsref.nsfile";
+        $filename =  $TMPDIR . $uid . "-$nsref.nsfile";
         header("Content-type: text/plain");
         readfile($filename);
         unlink($filename);
@@ -227,7 +228,7 @@ function startElement($parser,$name,$attrs)
         $templateauthor = "";
         if (isset($attrs['AUTHOR'])) {
             if (isset($attrs['AUTHORUID'])) {
-                $templateauthor = "<a href='showuser.php3?target_uid=$attrs[AUTHORUID]'>";
+                $templateauthor = "<a href='showuser.php3?user=$attrs[AUTHORUID]'>";
                 $templateauthor .= $attrs['AUTHOR'] . "</a>";
             } else {
                 $templateauthor = isset($attrs['AUTHOR']);
@@ -247,7 +248,7 @@ function startElement($parser,$name,$attrs)
 function MAKENS($template,$templatefields,$templatevalues) {
     global $NSGEN;
     global $TMPDIR;
-    global $templatefile;
+    global $templatefile, $uid;
     
     #
     # Pick out some defaults for the exp. creation page
@@ -259,7 +260,7 @@ function MAKENS($template,$templatefields,$templatevalues) {
     list($usec, $sec) = explode(' ', microtime());
     srand((float) $sec + ((float) $usec * 100000));
     $nsref = rand();
-    $outfile = $TMPDIR . GETUID() . "-$nsref.nsfile";
+    $outfile = $TMPDIR . $uid . "-$nsref.nsfile";
 
     #
     # Pick out the parameters for command-line arguments
diff --git a/www/obstacle_list.php3 b/www/obstacle_list.php3
index 0ea5726185b4bcc293844482caafdafbcc03d14d..ee8244dcdf03d721fadf9598e4dc7848d15251f7 100644
--- a/www/obstacle_list.php3
+++ b/www/obstacle_list.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2005 University of Utah and the Flux Group.
+# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -15,9 +15,9 @@ PAGEHEADER("Obstacle List");
 #
 # Only known and logged in users allowed.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Spit out all the obstacles. At some point this page should take
diff --git a/www/panicbutton.php3 b/www/panicbutton.php3
index 62da119287714823d2bc809dd5cb2d95823ac0d3..7343590d387dc4158086238f2b31b04b3f081e23 100644
--- a/www/panicbutton.php3
+++ b/www/panicbutton.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -10,8 +10,9 @@ include("showstuff.php3");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Must provide the EID!
diff --git a/www/password.php3 b/www/password.php3
index 6f4bacc72cee5652fe10dbd8267fb36927ad1baf..5bc68b5f82f4e9d8bfef933cef88f20e7629b83e 100644
--- a/www/password.php3
+++ b/www/password.php3
@@ -38,17 +38,15 @@ if (!isset($SSL_PROTOCOL)) {
 #
 # Must not be logged in.
 # 
-if (($known_uid = GETUID()) != FALSE) {
-    if (CHECKLOGIN($known_uid) & CHECKLOGIN_LOGGEDIN) {
-	PAGEHEADER("Forgot Your Password?", $view);
+if (CheckLogin($check_status)) {
+    PAGEHEADER("Forgot Your Password?", $view);
 
-	echo "<h3>
+    echo "<h3>
               You are logged in. You must already know your password!
-              </h3>\n";
-
-	PAGEFOOTER($view);
-	die("");
-    }
+          </h3>\n";
+    
+    PAGEFOOTER($view);
+    die("");
 }
 
 #
@@ -143,17 +141,14 @@ if (!isset($phone) || $phone == "" || !TBvalid_phone($phone) ||
     return;
 }
 
-$query_result =
-    DBQueryFatal("select uid,usr_phone from users ".
-		 "where LCASE(usr_email)=LCASE('$email')");
-
-if (! mysql_num_rows($query_result)) {
+if (! ($user = User::LookupByEmail($email))) {
     SPITFORM($email, $phone, 2, $simple, $view);
     return;
 }
-$row = mysql_fetch_row($query_result);
-$uid = $row[0];
-$usr_phone = $row[1];
+$uid       = $user->uid();
+$usr_phone = $user->phone();
+$uid_name  = $user->name();
+$uid_email = $user->email();
 
 #
 # Compare phone by striping out anything but the numbers.
@@ -164,8 +159,6 @@ if (preg_replace("/[^0-9]/", "", $phone) !=
     return;
 }
 
-TBUserInfo($uid, $uid_name, $uid_email);
-
 #
 # Yep. Generate a random key and send the user an email message with a URL
 # that will allow them to change their password. 
@@ -181,10 +174,7 @@ setcookie($TBAUTHCOOKIE, $keyA, 0, "/",
 # It is okay to spit this now that we have sent the cookie.
 PAGEHEADER("Forgot Your Password?", $view);
 
-DBQueryFatal("update users set ".
-	     "       chpasswd_key='$key', ".
-	     "       chpasswd_expires=UNIX_TIMESTAMP(now())+(60*30) ".
-	     "where uid='$uid'");
+$user->SetChangePassword($key, "UNIX_TIMESTAMP(now())+(60*30)");
 
 TBMAIL("$uid_name <$uid_email>",
        "Password Reset requested by '$uid'",
diff --git a/www/plab_ez.php3 b/www/plab_ez.php3
index b33fb161e9987f0e693fc0b5e4ad514998a7d4f2..2118a6f3bef9652bed6917f83ef8cebba98e702e 100644
--- a/www/plab_ez.php3
+++ b/www/plab_ez.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2003, 2004 University of Utah and the Flux Group.
+# Copyright (c) 2003, 2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -23,8 +23,9 @@ if (isset($advanced) || $advanced || (isset($submit)
 #
 # Only known and logged in users can get this page
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid,0,"$TBBASE/login_plab.php3?refer=1");
+$this_user = CheckLoginOrDie(0, "$TBBASE/login_plab.php3?refer=1");
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # The reason for this apparently redundant pair of arrays is so that we can
@@ -489,7 +490,8 @@ function CHECKTARS($formfields) {
 # Make an NS file with the supplied data
 #
 function MAKENS($formfields) {
-    global $NSGEN, $PLAB_TEMPLATE;
+    global $NSGEN, $PLAB_TEMPLATE, $uid;
+    
     #
     # Pick out some defaults for the exp. creation page
     #
@@ -536,7 +538,7 @@ function MAKENS($formfields) {
     srand((float) $sec + ((float) $usec * 100000));
     $nsref = rand();
     $url .= "&nsref=$nsref";
-    $outfile = "/tmp/" . GETUID() . "-$nsref.nsfile";
+    $outfile = "/tmp/" . $uid . "-$nsref.nsfile";
     $nsgen_args = "";
     if ($formfields['count']) {
 	$nsgen_args .= "-v Count='$formfields[count]' ";
diff --git a/www/plabmetrics.php3 b/www/plabmetrics.php3
index ccd03573344fbb9efc919d27e3c0fefc2e0fd47b..b28a947a0c7a595f79850eb0f8a7d94ce5699b2e 100644
--- a/www/plabmetrics.php3
+++ b/www/plabmetrics.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2003, 2004 University of Utah and the Flux Group.
+# Copyright (c) 2003, 2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -15,8 +15,9 @@ PAGEHEADER("PlanetLab Metrics");
 #
 # Only known and logged in users can get plab data.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # This is very simple; just invoke the script and spit the results back
diff --git a/www/plabstats.php3 b/www/plabstats.php3
index de5159dd09ba79b4f62529ce871e92308c6a06f7..8f3bfb5f9d3d2120be2a283ae7d949812479492f 100644
--- a/www/plabstats.php3
+++ b/www/plabstats.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2003 University of Utah and the Flux Group.
+# Copyright (c) 2000-2003, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -17,11 +17,14 @@ if (!isset($xml)) {
 #
 # Get current user, if any. We return info to logged in admin users,
 # or to someone who has the right key.
-# 
-$uid = GETLOGIN();
-if ($uid) {
-    LOGGEDINORDIE($uid);
-    if (!ISADMIN($uid)) {
+#
+$this_user = CheckLogin($check_status);
+
+if ($this_user) {
+    CheckLoginOrDie();
+    $isadmin = ISADMIN();
+
+    if (!$isadmin)) {
 	USERERROR("You do not have permission to view this page!", 1);
     }
 }
diff --git a/www/powertime.php3 b/www/powertime.php3
index bf1f23e57565329bab74c65af7c87142751a00ef..9a3bee292582374b9d574b2e3e2139fb465f6fb1 100644
--- a/www/powertime.php3
+++ b/www/powertime.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2005 University of Utah and the Flux Group.
+# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -9,9 +9,9 @@ include("defs.php3");
 #
 # Only known and logged in admins can update last_power times.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 if (!$isadmin && !STUDLY()) {
     USERERROR("Not enough permission.", 1);
diff --git a/www/prereserve_node.php3 b/www/prereserve_node.php3
index b9ef0a6535623d2d2f2b1e560678bf1f11764e19..d040b247b685434fee475b4ef4adea8e7b6db4f7 100644
--- a/www/prereserve_node.php3
+++ b/www/prereserve_node.php3
@@ -9,9 +9,9 @@ include("defs.php3");
 #
 # Only admin people!
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 if (! $isadmin) {
     USERERROR("You do not have permission to pre-reserve nodes!", 1);
diff --git a/www/project_defs.php b/www/project_defs.php
index 1cf81ae96ab1dd4138652d733c3f2694d5a400d1..3bd69cabd02613a401b9546169847de682e48e04 100644
--- a/www/project_defs.php
+++ b/www/project_defs.php
@@ -36,9 +36,17 @@ class Project
     function Lookup($pid_idx) {
 	$foo = new Project($pid_idx);
 
-	if ($foo->IsValid())
+	if (! $foo->IsValid()) {
+	    # Try lookup by plain uid.
+	    $foo = Project::LookupByPid($pid_idx);
+	    
+	    if (! $foo->IsValid())
+		return null;
+
+	    # Return here, in case I add a cache and forget to do this.
 	    return $foo;
-	return null;
+	}
+	return $foo;
     }
 
     # Backwards compatable lookup by pid. Will eventually flush this.
@@ -127,6 +135,14 @@ class Project
 	return $group->unix_name();
     }
 
+    #
+    # At some point we will stop passing pid and start using pid_idx.
+    # Use this function to avoid having to change a bunch of code twice.
+    #
+    function URLParam() {
+	return $this->pid();
+    }
+
     #
     # Class function to create new project and return object.
     #
@@ -189,6 +205,16 @@ class Project
 	return $newproject;
     }
 
+    #
+    # Access Check, which for now uses the global function to avoid duplication
+    # until all code is changed.
+    #
+    function AccessCheck($user, $access_type) {
+	return TBProjAccessCheck($user->uid(),
+				 $this->pid(), $this->pid(),
+				 $access_type);
+    }
+
     #
     # Load the default group for a project lazily.
     #
@@ -203,6 +229,18 @@ class Project
 	return $group;
     }
 
+    #
+    # Return user object for leader.
+    #
+    function GetLeader() {
+	$head_uid = $this->head_uid();
+
+	if (! ($leader = User::Lookup($head_uid))) {
+	    TBERROR("Could not find user object for $head_uid", 1);
+	}
+	return $leader;
+    }
+
     #
     # Add *new* member to project group; starts out with trust=none.
     #
@@ -215,22 +253,104 @@ class Project
     #
     # Check if user is a member of this project (well, group)
     #
-    function IsMember($user) {
+    function IsMember($user, &$approved) {
 	$group = $this->LoadGroup();
 
-	return $group->IsMember($user);
+	return $group->IsMember($user, $approved);
     }
 
     #
-    # Return user object for the leader.
+    # Member list for a group.
     #
-    function Leader() {
-	$head_uid = $this->head_uid();
+    function MemberList() {
+	$pid_idx = $this->pid_idx();
+	$result  = array();
 
-	if (! ($leader = User::LookupByUid($head_uid))) {
-	    TBERROR("Project::Leader: Could not lookup leader $head_uid!", 1);
+	$query_result =
+	    DBQueryFatal("select uid_idx from group_membership ".
+			 "where pid_idx='$pid_idx' and gid_idx=pid_idx");
+
+	while ($row = mysql_fetch_array($query_result)) {
+	    $uid_idx = $row["uid_idx"];
+
+	    if (! ($user =& User::Lookup($uid_idx))) {
+		TBERROR("Project::MemberList: ".
+			"Could not load user $uid_idx!", 1);
+	    }
+	    $result[] =& $user;
 	}
-	return $leader;
+	return $result;
+    }
+
+    #
+    # List of subgroups for a project member (not including default group).
+    #
+    function GroupList($user) {
+	$pid_idx = $this->pid_idx();
+	$uid_idx = $user->uid_idx();
+	$result  = array();
+
+	$query_result =
+	    DBQueryFatal("select gid_idx from group_membership ".
+			 "where pid_idx='$pid_idx' and pid_idx!=gid_idx and ".
+			 "      uid_idx='$uid_idx'");
+
+	while ($row = mysql_fetch_array($query_result)) {
+	    $gid_idx = $row["gid_idx"];
+
+	    if (! ($group = Group::Lookup($gid_idx))) {
+		TBERROR("Project::GroupList: ".
+			"Could not load group $gid_idx!", 1);
+	    }
+	    $result[] = $group;
+	}
+	return $result;
+    }
+
+    #
+    # Change the leader for a project. Done *only* before project is
+    # approved.
+    #
+    function ChangeLeader($leader) {
+	$group = $this->LoadGroup();
+	$idx   = $this->pid_idx();
+	$uid   = $leader->uid();
+
+	DBQueryFatal("update projects set head_uid='$uid' ".
+		     "where pid_idx='$idx'");
+
+	$this->project["head_uid"] = $uid;
+	return $group->ChangeLeader($leader);
     }
     
+    #
+    # Change various fields.
+    #
+    function SetApproved($approved) {
+	$idx   = $this->pid_idx();
+
+	if ($approved)
+	    $approved = 1;
+	else
+	    $approved = 0;
+	
+	DBQueryFatal("update projects set approved='$approved' ".
+		     "where pid_idx='$idx'");
+
+	$this->project["approved"] = $approved;
+	return 0;
+    }
+    function SetRemoteOK($ok) {
+	$idx    = $this->pid_idx();
+	$safeok = addslashes($ok);
+
+	DBQueryFatal("update projects set pcremote_ok='$safeok' ".
+		     "where pid_idx='$idx'");
+
+	$this->project["pcremote_ok"] = $ok;
+	return 0;
+	
+
+    }
+
 }
diff --git a/www/remapexp.php3 b/www/remapexp.php3
index 12b2725d3158065f4e373640289ab88374b9819a..c2d4a8cb252754a88a05445dd21349446794ff63 100644
--- a/www/remapexp.php3
+++ b/www/remapexp.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -12,8 +12,9 @@ PAGEHEADER("Remap Virtual Nodes");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Check to make sure a valid experiment.
diff --git a/www/replayexp.php3 b/www/replayexp.php3
index 63a4c07728209b62f1f15e6bc0511040add933ca..209c6881b73ff278929627bd3f714ad034371a53 100644
--- a/www/replayexp.php3
+++ b/www/replayexp.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -10,8 +10,9 @@ include("showstuff.php3");
 #
 # Only known and logged in users can end experiments.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Must provide the EID!
diff --git a/www/request_idleinfo.php3 b/www/request_idleinfo.php3
index e30bdff24b9a865eaa4c37fb5992ff066729a3df..9476643edcce9bb759601b24d18b4a20bd1051e1 100644
--- a/www/request_idleinfo.php3
+++ b/www/request_idleinfo.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2005 University of Utah and the Flux Group.
+# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -13,10 +13,11 @@ include("showstuff.php3");
 PAGEHEADER("Request info about possibly Idle experiment");
 
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
@@ -34,16 +35,15 @@ if (!isset($eid) ||
 #
 # Only admins can do this!
 #
-if (! ISADMIN($uid)) {
+if (!$isadmin) {
     USERERROR("Only TB admins can do this!", 1);
 }
 
 #
 # Check to make sure this is a valid PID/EID tuple.
 #
-if (! TBValidExperiment($pid, $eid)) {
-    USERERROR("The experiment $eid is not a valid experiment ".
-	      "in project $pid.", 1);
+if (! ($experiment = Experiment::LookupByPidEid($pid, $eid))) {
+    USERERROR("The experiment $pid/$eid is not a valid experiment!", 1);
 }
 
 #
@@ -106,7 +106,7 @@ if (!$confirmed) {
 
 # Info about experiment.
 $query_result =
-    DBQueryFatal("select e.gid,e.expt_swap_uid as swapper, ".
+    DBQueryFatal("select e.expt_swap_uid as swapper, ".
 		 "       e.expt_head_uid as creator, ".
 		 "       UNIX_TIMESTAMP(now())-UNIX_TIMESTAMP(e.expt_swapped)".
 		 "   as swapseconds, r.pnodes ".
@@ -117,22 +117,29 @@ $query_result =
 		 "where e.pid='$pid' and e.eid='$eid'");
 
 $row = mysql_fetch_array($query_result);
-$gid     = $row["gid"];
 $swapper = $row["swapper"];
 $creator = $row["creator"];
 $pcs     = $row["pnodes"];
 $seconds = $row["swapseconds"];
 $hours   = intval($seconds / 3600);
 
+if (! ($creator_user = User::Lookup($creator))) {
+    TBERROR("Could not lookup object for user $creator!", 1);
+}
+if (! ($swapper_user = User::Lookup($swapper))) {
+    TBERROR("Could not lookup object for user $swapper!", 1);
+}
+if (! ($group = $experiment->Group())) {
+    TBERROR("Could not lookup object for experiment group!", 1);
+}
+
 # Lots of email addresses!
-$allleaders    = TBLeaderMailList($pid, $gid);
-$swapper_name  = "";
-$swapper_email = "";
-TBUserInfo($swapper, $swapper_name, $swapper_email);
-$creator_name  = "";
-$creator_email = "";
+$allleaders    = $group->LeaderMailList();
+$swapper_name  = $swapper_user->name();
+$swapper_email = $swapper_user->mail();
+$creator_name  = $creator_user->name();
+$creator_email = $creator_user->email();
 if ($swapper != $creator) {
-    TBUserInfo($creator, $creator_name, $creator_email);
     $allleaders .= ", \"$creator_name\" <$creator_email>";
 }
 
diff --git a/www/request_swapexp.php3 b/www/request_swapexp.php3
index f7f51a1fb3fbb0a895f2d85d06f17c64cc26de66..5e15d1ebd48ff0315ca893fa5578de16e975cb1e 100644
--- a/www/request_swapexp.php3
+++ b/www/request_swapexp.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2003, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2003, 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -13,10 +13,11 @@ include("showstuff.php3");
 PAGEHEADER("Request a Swap/Terminate");
 
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
@@ -34,7 +35,7 @@ if (!isset($eid) ||
 #
 # Only admins can do this!
 #
-if (! ISADMIN($uid)) {
+if (! !$isadmin) {
     USERERROR("Only TB admins can do this!", 1);
 }
 
diff --git a/www/resendkey.php3 b/www/resendkey.php3
index d8637c3281132f390ecfecd66558bc951ae99bad..a6162c66a65f8043ab3e4e34a07eb99658783493 100644
--- a/www/resendkey.php3
+++ b/www/resendkey.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2003 University of Utah and the Flux Group.
+# Copyright (c) 2000-2003, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -9,15 +9,15 @@ include("defs.php3");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify form arguments.
 # 
-if (!isset($target_uid) ||
-    strcmp($target_uid, "") == 0) {
+if (!isset($user) ||
+    strcmp($user, "") == 0) {
     USERERROR("You must provide a User ID.", 1);
 }
 
@@ -27,13 +27,19 @@ if (!$isadmin) {
     USERERROR("You do not have permission to view this page!", 1);
 }
 
-if (! TBCurrentUser($target_uid)) {
-    USERERROR("$target_uid is not a valid user ID!", 1);
+#
+# Confirm target is a real user.
+#
+if (! ($target_user = User::Lookup($user))) {
+    USERERROR("The user $target_uid is not a valid user", 1);
 }
+$target_uid = $target_user->uid();
 
 # Get email info and Key,
-TBUserInfo($target_uid, $usr_name, $usr_email);
-$key = TBGetVerificationKey($target_uid);
+$usr_name  = $target_user->name();
+$usr_email = $target_user->email();
+$key       = $target_user->verify_key();
+
 if (!$key || !strcmp($key, "")) {
     USERERROR("$target_uid does not have a valid verification key!", 1);
 }
@@ -46,7 +52,7 @@ TBMAIL("$usr_name '$target_uid' <$usr_email>",
        "This is your account verification key: $key\n\n".
        "Please use this link to verify your user account:\n".
        "\n".
-       "    ${TBBASE}/login.php3?vuid=$target_uid&key=$key\n".
+       "    ${TBBASE}/login.php3?vuid=$user&key=$key\n".
        "\n".
        "You will then be verified as a user.\n".
        "\n".
diff --git a/www/robotmap.php3 b/www/robotmap.php3
index 400388eb1b6647ffc97c15698c6d191de256367c..212a62307a78b24533b0380d34ca1ffa0d49ee85 100755
--- a/www/robotmap.php3
+++ b/www/robotmap.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2004, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2004, 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,9 +14,9 @@ PAGEHEADER("Robot Map");
 #
 # Only logged in people at the moment; might open up at some point.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 # Careful with this local variable
 unset($prefix);
@@ -257,7 +257,7 @@ echo "<form method=post action='robotmap.php3" .
 
 echo "Click on the image to get its X,Y coordinates<br>\n";
 # The image may be clicked to get node info or set a new center-point.
-if ($isadmin || TBWebCamAllowed($uid)) {
+if ($isadmin || $this_user->WebCamAllowed()) {
     echo "  <a href=webcam.php3>Webcam View</a> (Updated in real time)";
     echo "  <br>\n";
 }
diff --git a/www/robotrack/assignnodes.php3 b/www/robotrack/assignnodes.php3
index 2488f4236b174e2cfe1c5c543bfdc0bf9e9f0b71..2af13cdc1af7099274c6ff0f29a040b813b3bb9d 100644
--- a/www/robotrack/assignnodes.php3
+++ b/www/robotrack/assignnodes.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2004, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 chdir("..");
@@ -10,8 +10,9 @@ include("defs.php3");
 #
 # Only known and logged in users can watch LEDs
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # When called from the applet, the variable "fromapplet" will be set.
diff --git a/www/robotrack/cameras.php3 b/www/robotrack/cameras.php3
index 0888e885a3a85606637c49d818b64b0d22213a44..fea8a1d569466cebe0d8dca96a8b531df4bd20e0 100644
--- a/www/robotrack/cameras.php3
+++ b/www/robotrack/cameras.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2004, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 chdir("..");
@@ -10,8 +10,9 @@ include("defs.php3");
 #
 # Only known and logged in users can watch LEDs
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments. Allow user to optionally specify building/floor.
diff --git a/www/robotrack/flooricon.php3 b/www/robotrack/flooricon.php3
index 2e91b8a98990236ad25584bcaae1da460f8b82f5..d7ef5b394b56705c24a00facf3bffc8242780bc7 100644
--- a/www/robotrack/flooricon.php3
+++ b/www/robotrack/flooricon.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 chdir("..");
@@ -10,8 +10,9 @@ include("defs.php3");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments. Allow user to optionally specify building/floor.
diff --git a/www/robotrack/nodeinfo.php3 b/www/robotrack/nodeinfo.php3
index 816b5798d2e5da0a78a1178dc42cf11afe310dee..dd16ed43282d5e9a82db951850a05164100710a6 100644
--- a/www/robotrack/nodeinfo.php3
+++ b/www/robotrack/nodeinfo.php3
@@ -1,17 +1,18 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2004, 2005, 2006 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 chdir("..");
 include("defs.php3");
 
 #
-# Only known and logged in users can watch LEDs
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments. Allow user to optionally specify building/floor.
diff --git a/www/robotrack/obstacles.php3 b/www/robotrack/obstacles.php3
index 589eacf7a55d1df605ea0d4e3675109147551990..edb41c647dd1797db2291b85f5854682e98414ff 100644
--- a/www/robotrack/obstacles.php3
+++ b/www/robotrack/obstacles.php3
@@ -1,17 +1,18 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2004, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 chdir("..");
 include("defs.php3");
 
 #
-# Only known and logged in users can watch LEDs
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments. Allow user to optionally specify building/floor.
diff --git a/www/robotrack/robopipe.php3 b/www/robotrack/robopipe.php3
index 393b412f90567ecb0f389032ba5c9fd296230c0b..345017c80f247446ed744f18c3271479ebd7b41e 100644
--- a/www/robotrack/robopipe.php3
+++ b/www/robotrack/robopipe.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2004, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 chdir("..");
@@ -14,14 +14,13 @@ function SPITERROR($code, $msg)
 }
 
 #
-# Only known and logged in users can watch LEDs
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-
-$status = CHECKLOGIN($uid);
-if (($status & CHECKLOGIN_LOGGEDIN) != CHECKLOGIN_LOGGEDIN) {
+if (! ($this_user = CheckLogin($check_status)) ||
+    ($check_status & CHECKLOGIN_LOGGEDIN) != CHECKLOGIN_LOGGEDIN) {
     SPITERROR(401, "Not logged in");
 }
+$uid = $this_user->uid();
 
 #
 # Optional pid,eid. Without a building/floor, show all the nodes for the
diff --git a/www/robotrack/robotrack.php3 b/www/robotrack/robotrack.php3
index ff9663bae3f4a93fd98cebdf1338213d06247aae..29f71dbe3b5d35a810054a9e9986065bbf546634 100644
--- a/www/robotrack/robotrack.php3
+++ b/www/robotrack/robotrack.php3
@@ -1,17 +1,18 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 chdir("..");
 include("defs.php3");
 
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-
 PAGEHEADER("Real Time Robot Tracking Applet");
 
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
+
 #
 # Optional pid,eid. Without a building/floor, show all the nodes for the
 # experiment in all buildings/floors. Without pid,eid show all wireless
diff --git a/www/robotrack/selector.php3 b/www/robotrack/selector.php3
index c1c9c52bfe3ec0c4821c682ee6c42b74af93195d..62a7444b7fead8ab6b0c72be0971b5d70ef06393 100644
--- a/www/robotrack/selector.php3
+++ b/www/robotrack/selector.php3
@@ -1,17 +1,18 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 chdir("..");
 include("defs.php3");
 
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-
 PAGEHEADER("Node Selector Applet");
 
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
+
 #
 # Verify page arguments. Allow user to optionally specify building/floor.
 #
diff --git a/www/robotrack/setdest.php3 b/www/robotrack/setdest.php3
index ecc56855958f31b249053758c0ea5a0cfad150a3..ae98869e36d0d035e71ddd08efdf51f31042daba 100644
--- a/www/robotrack/setdest.php3
+++ b/www/robotrack/setdest.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2005 University of Utah and the Flux Group.
+# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 chdir("..");
@@ -34,8 +34,9 @@ function handle_error($message, $death)
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Check to make sure a valid nodeid.
diff --git a/www/robotrack/virtinfo.php3 b/www/robotrack/virtinfo.php3
index 46a8a5dbb6881d394c571f6603a3312d12f6fa6d..497ef38398d554e947a1fb4b20465d9b7a879270 100644
--- a/www/robotrack/virtinfo.php3
+++ b/www/robotrack/virtinfo.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2004, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 chdir("..");
@@ -10,8 +10,9 @@ include("defs.php3");
 #
 # Only known and logged in users can watch LEDs
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments. Allow user to optionally specify building/floor.
diff --git a/www/sdr/preorder_list.php b/www/sdr/preorder_list.php
index 28d134e6cc4dff360cce71278d6744ed9c3ef227..7811d18118044ce784034c744516ce4e6ed71b5a 100644
--- a/www/sdr/preorder_list.php
+++ b/www/sdr/preorder_list.php
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2004 University of Utah and the Flux Group.
+# Copyright (c) 2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 chdir("..");
@@ -15,9 +15,9 @@ PAGEHEADER("USRP Preorder List");
 #
 # Only known and logged in users allowed.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 if (! $isadmin) {
     USERERROR("You do not have permission to view the USRP preorder list!", 1);
diff --git a/www/sendtestmsg.php3 b/www/sendtestmsg.php3
index 9047378b6a7606d5ef509fc7f51531bc0c46cdf7..8c9a8ff7a478efcac78c5cc972b19c2c8ba60c6d 100644
--- a/www/sendtestmsg.php3
+++ b/www/sendtestmsg.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2003, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2003, 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -9,15 +9,15 @@ include("defs.php3");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify form arguments.
 # 
-if (!isset($target_uid) ||
-    strcmp($target_uid, "") == 0) {
+if (!isset($user) ||
+    strcmp($user, "") == 0) {
     USERERROR("You must provide a User ID.", 1);
 }
 
@@ -27,12 +27,14 @@ if (!$isadmin) {
     USERERROR("You do not have permission to view this page!", 1);
 }
 
-if (! TBCurrentUser($target_uid)) {
-    USERERROR("$target_uid is not a valid user ID!", 1);
+if (! ($target_user = User::Lookup($user))) {
+    USERERROR("The user $user is not a valid user", 1);
 }
+$target_uid = $target_user->uid();
 
-# Get email info and Key,
-TBUserInfo($target_uid, $usr_name, $usr_email);
+# Get email info.
+$usr_name  = $target_user->name();
+$usr_email = $target_user->email();
 
 # Send the email.
 TBMAIL("$usr_name '$target_uid' <$usr_email>",
diff --git a/www/servicepipe.php3 b/www/servicepipe.php3
index 370008f99a77074acc5bc9b19623f98a5e844f1c..503ede93f3dc51343d6dde226ded8c77922ffbfd 100644
--- a/www/servicepipe.php3
+++ b/www/servicepipe.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2005 University of Utah and the Flux Group.
+# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -9,8 +9,9 @@ include("defs.php3");
 #
 # Only known and logged in users can watch LEDs
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/setnodeloc.php3 b/www/setnodeloc.php3
index 83b08d9eb151444acf9f64862d2bcf7801eaed70..c22942b037d7aec62d8b4979ec00ea4c190c9b86 100644
--- a/www/setnodeloc.php3
+++ b/www/setnodeloc.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2004 University of Utah and the Flux Group.
+# Copyright (c) 2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -9,9 +9,9 @@ include("defs.php3");
 #
 # Only admins.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # This is a multistep process.
diff --git a/www/showconlog.php3 b/www/showconlog.php3
index cf7adbc49884ab4057fc43227106c13846888ad6..500caa122168989676f4d7cc51fe73ec2aa1508e 100644
--- a/www/showconlog.php3
+++ b/www/showconlog.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2005 University of Utah and the Flux Group.
+# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -15,9 +15,9 @@ PAGEHEADER("Console Log for $node_id");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Check to make sure a valid nodeid.
diff --git a/www/showevents.php b/www/showevents.php
index 20c5ac73283fb4513ce06b93005eb8149818ad4b..0faed6637c1b0adbd2e5d4333aa8c58247626e9d 100644
--- a/www/showevents.php
+++ b/www/showevents.php
@@ -15,10 +15,9 @@ PAGEHEADER("Watch Event Log");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/showexp.php3 b/www/showexp.php3
index de55cd481ad3b2475c08b4d7fa5eb9499510ffd1..fba67ef0ce15e177d30778a1f964255a37c5539e 100644
--- a/www/showexp.php3
+++ b/www/showexp.php3
@@ -13,9 +13,10 @@ sajax_export("GetExpState", "Show");
 #
 # Only known and logged in users can look at experiments.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
+
 $tag = "Experiment";
 
 #
diff --git a/www/showexp_list.php3 b/www/showexp_list.php3
index 3bc9a8fb9e44415e591e1e8cf0cfb14627f5d353..19342fb55b05c58cdb9c158648e7a2eb00c8e2eb 100644
--- a/www/showexp_list.php3
+++ b/www/showexp_list.php3
@@ -12,12 +12,12 @@ include("defs.php3");
 PAGEHEADER("Experiment Information Listing");
 
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
-$isadmin     = ISADMIN($uid);
 $clause      = 0;
 $having      = "";
 $active      = 0;
@@ -375,6 +375,11 @@ if ($thumb && !$idle) {
 	$name = stripslashes($row["expt_name"]);
 	$date = $row["dshort"];
         $rsrcidx = $row["rsrcidx"];
+
+	if (! ($head_user = User::Lookup($huid))) {
+	    TBERROR("Could not lookup object for user $huid", 1);
+	}
+	$showuser_url = CreateURL("showuser", $head_user);
 	
 	if ($idle && ($str=="&nbsp;" || !$pcs)) { continue; }
 
@@ -437,7 +442,7 @@ if ($thumb && !$idle) {
 	    }	
 
 	    echo "<font size=-2><b>Created by:</b> ".
-		 "<a href='showuser.php3?target_uid=$huid'>$huid</a>".
+		 "<a href='$showuser_url'>$huid</a>".
 		 "</font><br />\n";
 
 	    $special = 0;
@@ -526,6 +531,11 @@ if ($thumb && !$idle) {
 	$idletime = ($idlesec > 300 ? round($idlesec/3600,1) : 0);
 	# reset pcs
 	$pcs=0;
+
+	if (! ($head_user = User::Lookup($huid))) {
+	    TBERROR("Could not lookup object for user $huid", 1);
+	}
+	$showuser_url = CreateURL("showuser", $head_user);
 	
 	if ($swapreqs && !$isidle) {
 	    $swapreqs = "";
@@ -677,7 +687,7 @@ if ($thumb && !$idle) {
 	    echo "<td>$name</td>\n";
 	}
 	
-        echo "<td><A href='showuser.php3?target_uid=$huid'>$huid</A></td>\n";
+        echo "<td><A href='$showuser_url'>$huid</A></td>\n";
 	echo "</tr>\n";
     }
     echo "</table>\n";
diff --git a/www/showexpstats.php3 b/www/showexpstats.php3
index 7e6433eb713344c1aaefe1e2fc314d7f0aa78a58..693e4b0755c1f44589bc04c3baf6a4a311148884 100644
--- a/www/showexpstats.php3
+++ b/www/showexpstats.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2003, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2003, 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -18,11 +18,11 @@ include("showstuff.php3");
 PAGEHEADER("Show Experiment Information");
 
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Right now we show just the last N records entered, unless the user
diff --git a/www/showgroup.php3 b/www/showgroup.php3
index 664064a5901767d5d64e9aa8394c60c51d14e6a3..dc058075606f4807ed021a75d2bf81b42e575492 100644
--- a/www/showgroup.php3
+++ b/www/showgroup.php3
@@ -21,12 +21,11 @@ PAGEHEADER("Show Group Information");
 #
 
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify form arguments.
diff --git a/www/showimageid.php3 b/www/showimageid.php3
index 86f1243831848a1e8d7604be883469bcf970f061..99791fd140bf5cd9683ad0b9fc9e5fbd189f29c1 100644
--- a/www/showimageid.php3
+++ b/www/showimageid.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -13,11 +13,11 @@ include("showstuff.php3");
 PAGEHEADER("Image Descriptor");
 
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify form arguments.
diff --git a/www/showimageid_list.php3 b/www/showimageid_list.php3
index 4f6a0a6d4b0bf8c3a072fc37f7bdb2677ddc3052..d8e3c4987f11fabeb97e9d96bd7c577f40599a75 100644
--- a/www/showimageid_list.php3
+++ b/www/showimageid_list.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -15,14 +15,14 @@ PAGEHEADER("Image List");
 #
 # Only known and logged in users allowed.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Admin users can see all ImageIDs, while normal users can only see
 # ones in their projects or ones that are globally available.
 #
-$isadmin = ISADMIN($uid);
 
 if (! isset($sortby))
     $sortby = "normal";
@@ -42,7 +42,7 @@ $extraclause = "";
 # Allow for creator restriction
 #
 if (isset($creator) && $creator != "") {
-    if (! TBvalid_uid($creator)) {
+    if (! User::ValidWebID($creator)) {
 	PAGEARGERROR("Invalid characters in creator");
     }
     if ($isadmin) 
diff --git a/www/showlasterror.php3 b/www/showlasterror.php3
index 6d851fdb2645d724f417de0f59687292fc8bf5e2..7bd2b11771eaea66d2232dc7b045d666e7090c3e 100644
--- a/www/showlasterror.php3
+++ b/www/showlasterror.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -13,12 +13,11 @@ include("showstuff.php3");
 PAGEHEADER("Last Error");
 
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/showlogfile.php3 b/www/showlogfile.php3
index 1812491fb428d2ca65e01970e261f50a3d52a391..ee7c9029f4edabca397996f2ead2c7de9aa76421 100644
--- a/www/showlogfile.php3
+++ b/www/showlogfile.php3
@@ -1,18 +1,18 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2005 University of Utah and the Flux Group.
+# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
 include("showstuff.php3");
 
 #
-# Only known and logged in users can look at experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 # This will not return if its a sajax request.
 include("showlogfile_sup.php3");
diff --git a/www/showmmlists.php3 b/www/showmmlists.php3
index f949663512ba513f295e5ce44ee8c0a975cff766..38e9df31c47aa52dc304ca29cfb8abc6972e220c 100644
--- a/www/showmmlists.php3
+++ b/www/showmmlists.php3
@@ -15,10 +15,10 @@ PAGEHEADER("Mailman Lists");
 #
 # Only known and logged in users allowed.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
-TBUserInfo($uid, $user_name, $user_email);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
+$user_email = $this_user->email();
 
 if (! isset($sortby)) {
     $sortby = "listname";
@@ -37,22 +37,27 @@ else {
 #
 # Allow admin users to view the lists for a specific uid.
 #
-if (isset($target_uid) && $target_uid != "") {
-    if ($target_uid != $uid && !$isadmin) {
+if (isset($user)) {
+    if ($user == "" || !User::ValidWebID($user)) {
+	PAGEARGERROR("Invalid characters in $target_uid");
+    }
+    if (! ($target_user = User::Lookup($user))) {
+	USERERROR("The user $user is not a valid user", 1);
+    }
+    if (!$isadmin &&
+	!$target_user->SameUser($this_user)) {
 	USERERROR("You do not have permission to list mailman lists for ".
 		  "other users!", 1);
     }
+    $target_uid   = $target_user->uid();
+    $target_dbuid = $target_user->uid();
 }
 else {
-    $target_uid = $uid;
-}
-
-# Sanity check the uid.
-if (! TBvalid_uid($target_uid)) {
-    PAGEARGERROR("Invalid characters in $target_uid");
+    $target_user  = $this_user;
+    $target_uid   = $uid;
+    $target_dbuid = $uid;
 }
 
-
 SUBPAGESTART();
 SUBMENUSTART("More Options");
 WRITESUBMENUBUTTON("Create a Mailman List", "newmmlist.php3");
@@ -121,7 +126,7 @@ else {
     # 
     $query_result =
 	DBQueryFatal("select mm.* from mailman_listnames as mm ".
-		     "where mm.owner_uid='$target_uid' ".
+		     "where mm.owner_uid='$target_dbuid' ".
 		     "order by $order");
 }
 
@@ -140,13 +145,11 @@ if (mysql_num_rows($query_result)) {
     echo "<table border=2 cellpadding=0 cellspacing=2
            align='center'>\n";
 
+    $showmmlists_url = CreateUrl("showmmlists", $target_user)
+
     echo "<tr>
-              <th><a href='showmmlists.php3?&sortby=listname".
-	           "&target_uid=$target_uid'>
-                  List Name</th>
-              <th><a href='showmmlists.php3?&sortby=uid'".
-	           "&target_uid=$target_uid'>
-                  Owner</th>
+              <th><a href='${showmmlists_url}&sortby=listname'>List Name</th>
+              <th><a href='${showmmlists_url}&sortby=uid'>Owner</th>
               <th>Admin Page</th>
               <th>Reset Password</th>
               <th>Delete List</th>
@@ -156,12 +159,16 @@ if (mysql_num_rows($query_result)) {
 	$listname  = $row['listname'];
 	$owner_uid = $row['owner_uid'];
 	$mmurl     = "gotommlist?listname=${listname}";
+
+	if (! ($owner_user = User::Lookup($owner_uid))) {
+	    TBERROR("Could not lookup object for user $owner_uid", 1);
+	}
+	$showuser_url = CreateURL("showuser", $owner_user);
 	
 	echo "<tr>
                   <td><a href='mailto:$listname@${OURDOMAIN}'>$listname</a>
                        </td>
-                  <td><A href='showuser.php3?target_uid=$owner_uid'>
-                            $owner_uid</A></td>
+                  <td><A href='$showuser_url'>$owner_uid</A></td>
                   <td align=center><A href='${mmurl}&wantadmin=1'>
                          <img src=\"arrow4.ico\"
                               border=0 alt='admin'></A></td>
diff --git a/www/shownode.php3 b/www/shownode.php3
index a344dd07c0c4fcf4bbeae8768033aae286e6f046..470a2b733dfc0c9649f985162be90c9d3b2afb18 100644
--- a/www/shownode.php3
+++ b/www/shownode.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -15,9 +15,9 @@ PAGEHEADER("Node Information");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify form arguments.
diff --git a/www/shownodehistory.php3 b/www/shownodehistory.php3
index 5b4f62e17de4de9a464794d7fd7eb4b0a64c5206..b51717b9fc52a6d21b006a5383c503bfacc0ad66 100644
--- a/www/shownodehistory.php3
+++ b/www/shownodehistory.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -15,9 +15,9 @@ PAGEHEADER("Node History");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 if (! ($isadmin || OPSGUY())) {
     USERERROR("Cannot view node history.", 1);
diff --git a/www/shownodelog.php3 b/www/shownodelog.php3
index f2117f458bde2c8f83ef34647bdf0dd91d993943..d9ca718c8be945cc8cbac6172b9b850b50615d03 100644
--- a/www/shownodelog.php3
+++ b/www/shownodelog.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2002, 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -15,9 +15,9 @@ PAGEHEADER("Node Log");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify form arguments.
diff --git a/www/shownsfile.php3 b/www/shownsfile.php3
index 97931652a240bc570af5e1deba1fae84a100126c..f28df1c457dc1b131a9c1965837ed7b8a3084fd0 100644
--- a/www/shownsfile.php3
+++ b/www/shownsfile.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -18,15 +18,12 @@ if (!$justns) {
     PAGEHEADER("Visualization, NS File, and Details");
 }
 
-
-
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/showobstacle.php3 b/www/showobstacle.php3
index 70e747c4598038c82035baa65dc13c712c24d573..95318f36d00bf7eb2bfb4ebc7316bcd8cc0614c6 100644
--- a/www/showobstacle.php3
+++ b/www/showobstacle.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2005 University of Utah and the Flux Group.
+# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -15,9 +15,9 @@ PAGEHEADER("Obstacle Information");
 #
 # Only known and logged in users allowed.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify form arguments.
diff --git a/www/showosid_list.php3 b/www/showosid_list.php3
index 4ee1f9b942812d868d9f529bc7e74455dd031a91..6d5092d3011ad6254a7d2a2feb391c7781c1cf06 100644
--- a/www/showosid_list.php3
+++ b/www/showosid_list.php3
@@ -15,14 +15,14 @@ PAGEHEADER("OS Descriptor List");
 #
 # Only known and logged in users allowed.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Admin users can see all OSIDs, while normal users can only see
 # ones in their projects or ones that are globally available.
 #
-$isadmin = ISADMIN($uid);
 
 if (! isset($sortby))
     $sortby = "normal";
@@ -42,7 +42,7 @@ else
 #
 $extraclause = "";
 if (isset($creator) && $creator != "") {
-    if (! TBvalid_uid($creator)) {
+    if (! User::ValidWebID($creator)) {
 	PAGEARGERROR("Invalid characters in creator");
     }
     if ($isadmin) 
diff --git a/www/showosinfo.php3 b/www/showosinfo.php3
index eea429c8ba3ba91ef416ab7f31a978217ace8fab..c7db0433e9f11e23da80250774d8463d2167072c 100644
--- a/www/showosinfo.php3
+++ b/www/showosinfo.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -13,11 +13,11 @@ include("showstuff.php3");
 PAGEHEADER("OS Descriptor Information");
 
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify form arguments.
diff --git a/www/showpolicies.php3 b/www/showpolicies.php3
index 6319e2453a6b402c61483b43920e742c57f08762..cc7a57f2502c4b5d81a4ba9ec9ea1fc3a694d96a 100644
--- a/www/showpolicies.php3
+++ b/www/showpolicies.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2005 University of Utah and the Flux Group.
+# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -15,9 +15,9 @@ PAGEHEADER("Experiment Admission Control Policies");
 #
 # Only known and logged in users allowed.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Only admin people can see this page.
@@ -127,11 +127,16 @@ if (mysql_num_rows($query_result)) {
         $count   = $row["count"];
         $auxdata = $row["auxdata"];
 
+	if (! ($user = User::Lookup($puid))) {
+	    TBERROR("Could not lookup object for user $puid", 1);
+	}
+	$showuser_url = CreateURL("showuser", $user);
+	
 	if (!$auxdata)
 	    $auxdata = "&nbsp";
     
         echo "<tr>
-                  <td><A href='showuser.php3?target_uid=$puid'>$puid</a></td>
+                  <td><A href='$showuser_url'>$puid</a></td>
                   <td>$policy</td>
                   <td>$count</td>
                   <td>$auxdata</td>\n";
diff --git a/www/showproject.php3 b/www/showproject.php3
index 2da39d2b40c039943c16809ff46ae0777f263e21..0aa747a5c8cbc5e1954b7a3f0247569b1579886f 100644
--- a/www/showproject.php3
+++ b/www/showproject.php3
@@ -22,12 +22,11 @@ PAGEHEADER("Show Project Information");
 #
 
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify form arguments.
@@ -118,10 +117,15 @@ while ($row = mysql_fetch_array($query_result)) {
     $desc     = stripslashes($row[description]);
     $leader   = $row[leader];
 
+    if (! ($leader_user = User::Lookup($leader))) {
+	TBERROR("Could not lookup object for user $leader", 1);
+    }
+    $showuser_url = CreateURL("showuser", $leader_user);
+
     echo "<tr>
               <td><A href='showgroup.php3?pid=$pid&gid=$gid'>$gid</a></td>
               <td>$desc</td>
-              <td><A href='showuser.php3?target_uid=$leader'>$leader</A></td>
+              <td><A href='$showuser_url'>$leader</A></td>
           </tr>\n";
 }
 echo "</table>\n";
diff --git a/www/showproject_list.php3 b/www/showproject_list.php3
index 9124fabb4e1c10adf6e24dcc6a4b3ae5c9b1a65c..93dbf67c2efba97817469fe7633965df52914eb0 100644
--- a/www/showproject_list.php3
+++ b/www/showproject_list.php3
@@ -14,8 +14,9 @@ PAGEHEADER("Project Information List");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Admin users can see all projects, while normal users can only see
@@ -23,7 +24,6 @@ LOGGEDINORDIE($uid);
 #
 # XXX Should we form the list from project members instead of leaders?
 #
-$isadmin = ISADMIN($uid);
 
 if (!isset($splitview) || !$isadmin)
     $splitview = 0;
@@ -253,6 +253,11 @@ function GENPLIST ($query_result)
 	$ncount     = $ncounts[$pid];
 	$pcount     = $pcounts[$pid];
 
+	if (! ($head_user = User::Lookup($headuid))) {
+	    TBERROR("Could not lookup object for user $headuid", 1);
+	}
+	$showuser_url = CreateURL("showuser", $head_user);
+	
 	echo "<tr>
                   <td><A href='showproject.php3?pid=$pid'>$pid</A></td>
                   <td>\n";
@@ -263,8 +268,7 @@ function GENPLIST ($query_result)
 	    echo "    <img alt='N' src='redball.gif'>\n";
 	}
 	echo "             $Pname</td>
-                  <td><A href='showuser.php3?target_uid=$headuid'>
-                         $headuid</A></td>\n";
+                  <td><A href='$showuser_url'>$headuid</A></td>\n";
 
 	echo "<td>$idle</td>\n";
 	echo "<td>$expt_count</td>\n";
diff --git a/www/showpubkeys.php3 b/www/showpubkeys.php3
index 90ea996e4ff224b955aafc4ffa533413e8ef8cc0..c2b9bb98fa57eb3e50ef0a1b99a9c14dcf9ee714 100644
--- a/www/showpubkeys.php3
+++ b/www/showpubkeys.php3
@@ -9,9 +9,9 @@ include("defs.php3");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid, CHECKLOGIN_USERSTATUS|CHECKLOGIN_WEBONLY);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie(CHECKLOGIN_USERSTATUS|CHECKLOGIN_WEBONLY);
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page/form arguments. Note that the target uid comes initially as a
@@ -19,59 +19,56 @@ $isadmin = ISADMIN($uid);
 #
 if (! isset($_POST['submit'])) {
     # First page load. Default to current user.
-    if (! isset($_GET['target_uid']))
-	$target_uid = $uid;
+    if (! isset($_GET['user']))
+	$user = $uid;
     else
-	$target_uid = $_GET['target_uid'];
+	$user = $_GET['user'];
 }
 else {
-    # Form submitted. Make sure we have a formfields array and a target_uid.
+    # Form submitted. Make sure we have a formfields array and a user.
     if (!isset($_POST['formfields']) ||
 	!is_array($_POST['formfields']) ||
-	!isset($_POST['formfields']['target_uid'])) {
+	!isset($_POST['formfields']['user'])) {
 	PAGEARGERROR("Invalid form arguments.");
     }
     $formfields = $_POST['formfields'];
-    $target_uid = $formfields['target_uid'];
+    $user       = $formfields['user'];
 }
 
 # Pedantic check of uid before continuing.
-if ($target_uid == "" || !TBvalid_uid($target_uid)) {
-    PAGEARGERROR("Invalid uid: '$target_uid'");
+if ($user == "" || !User::ValidWebID($user)) {
+    PAGEARGERROR("Invalid uid: '$user'");
 }
 
 #
 # Check to make sure thats this is a valid UID.
 #
-if (! TBCurrentUser($target_uid)) {
-    USERERROR("The user $target_uid is not a valid user", 1);
+if (! ($target_user = User::Lookup($user))) {
+    USERERROR("The user $user is not a valid user", 1);
 }
+$target_uid = $target_user->uid();
 
 #
 # Verify that this uid is a member of one of the projects that the
 # target_uid is in. Must have proper permission in that group too. 
 #
-if (!$isadmin &&
-    strcmp($uid, $target_uid)) {
-
-    if (! TBUserInfoAccessCheck($uid, $target_uid, $TB_USERINFO_READINFO)) {
-	USERERROR("You do not have permission to view ${user}'s keys!", 1);
-    }
+if (!$isadmin && 
+    !$target_user->AccessCheck($this_user, $TB_USERINFO_READINFO)) {
+    USERERROR("You do not have permission to view ${user}'s keys!", 1);
 }
 
 function SPITFORM($formfields, $errors)
 {
-    global $isadmin, $target_uid, $BOSSNODE;
+    global $isadmin, $target_user, $BOSSNODE;
+
+    $target_uid = $target_user->uid();
+    $uid_idx    = $target_user->uid_idx();
+    $webid      = $target_user->webid();
 
     #
     # Standard Testbed Header, now that we know what we want to say.
     #
-    if (strcmp($uid, $target_uid)) {
-	PAGEHEADER("SSH Public Keys for user: $target_uid");
-    }
-    else {
-	PAGEHEADER("My SSH Public Keys");
-    }
+    PAGEHEADER("SSH Public Keys for user: $target_uid");
 
     #
     # Get the list and show it.
@@ -103,10 +100,12 @@ function SPITFORM($formfields, $errors)
 	    }
 	    $chunky  = chunk_split("$pubkey $fnote", 75, "<br>\n");
 
+	    $delurl = CreateURL("deletepubkey", $target_user, "key", $idx);
+
 	    echo "<tr>
                      <td align=center>
-                       <A href='deletepubkey.php3?target_uid=$target_uid" .
-	                  "&key=$idx'><img alt=X src=redball.gif></A>
+                       <A href='$delurl'>
+                          <img alt='Delete Key' src=redball.gif></A>
                      </td>
                      <td>$chunky</td>
                   </tr>\n";
@@ -158,8 +157,8 @@ function SPITFORM($formfields, $errors)
     echo "<table align=center border=1> 
           <form enctype=multipart/form-data
                 action=showpubkeys.php3 method=post>\n";
-    echo "<input type=hidden name=\"formfields[target_uid]\" ".
-	         "value=$target_uid>\n";
+    echo "<input type=hidden name=\"formfields[user]\" ".
+	         "value=$webid>\n";
 
     #
     # SSH public key
@@ -339,5 +338,5 @@ ADDPUBKEY($uid, "webaddpubkey -u $target_uid $addpubkeyargs");
 #
 # Redirect back, avoiding a POST in the history.
 # 
-header("Location: showpubkeys.php3?target_uid=$target_uid");
+header("Location: ". CreateURL("showpubkeys", $target_user));
 ?>
diff --git a/www/showsfskeys.php3 b/www/showsfskeys.php3
index 329c0d1dc9318fbaaeca8a2c50981d24eca3af37..9a3055bc9fab8e37bc9375adc4382dee0c7e153b 100644
--- a/www/showsfskeys.php3
+++ b/www/showsfskeys.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2003 University of Utah and the Flux Group.
+# Copyright (c) 2000-2003, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -10,9 +10,9 @@ include("showstuff.php3");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid, CHECKLOGIN_USERSTATUS|CHECKLOGIN_WEBONLY);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie(CHECKLOGIN_USERSTATUS|CHECKLOGIN_WEBONLY);
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page/form arguments. Note that the target uid comes initially as a
@@ -20,59 +20,56 @@ $isadmin = ISADMIN($uid);
 #
 if (! isset($_POST['submit'])) {
     # First page load. Default to current user.
-    if (! isset($_GET['target_uid']))
-	$target_uid = $uid;
+    if (! isset($_GET['user']))
+	$user = $uid;
     else
-	$target_uid = $_GET['target_uid'];
+	$user = $_GET['user'];
 }
 else {
-    # Form submitted. Make sure we have a formfields array and a target_uid.
+    # Form submitted. Make sure we have a formfields array and a user.
     if (!isset($_POST['formfields']) ||
 	!is_array($_POST['formfields']) ||
-	!isset($_POST['formfields']['target_uid'])) {
+	!isset($_POST['formfields']['user'])) {
 	PAGEARGERROR("Invalid form arguments.");
     }
     $formfields = $_POST['formfields'];
-    $target_uid = $formfields['target_uid'];
+    $user       = $formfields['user'];
 }
 
 # Pedantic check of uid before continuing.
-if ($target_uid == "" || !TBvalid_uid($target_uid)) {
-    PAGEARGERROR("Invalid uid: '$target_uid'");
+if ($user == "" || !User::ValidWebID($user)) {
+    PAGEARGERROR("Invalid uid: '$user'");
 }
 
 #
 # Check to make sure thats this is a valid UID.
 #
-if (! TBCurrentUser($target_uid)) {
-    USERERROR("The user $target_uid is not a valid user", 1);
+if (! ($target_user = User::Lookup($user))) {
+    USERERROR("The user $user is not a valid user", 1);
 }
+$target_uid = $target_user->uid();
 
 #
 # Verify that this uid is a member of one of the projects that the
 # target_uid is in. Must have proper permission in that group too. 
 #
-if (!$isadmin &&
-    strcmp($uid, $target_uid)) {
-
-    if (! TBUserInfoAccessCheck($uid, $target_uid, $TB_USERINFO_READINFO)) {
-	USERERROR("You do not have permission to view ${user}'s keys!", 1);
-    }
+if (!$isadmin && 
+    !$target_user->AccessCheck($this_user, $TB_USERINFO_READINFO)) {
+    USERERROR("You do not have permission to view ${uid}'s keys!", 1);
 }
 
 function SPITFORM($formfields, $errors)
 {
-    global $isadmin, $target_uid, $BOSSNODE;
+    global $isadmin, $target_user, $BOSSNODE;
+
+    $target_uid = $target_user->uid();
+    $uid_idx    = $target_user->uid_idx();
+    $webid      = $target_user->webid();
 
     #
     # Standard Testbed Header, now that we know what we want to say.
     #
-    if (strcmp($uid, $target_uid)) {
-	PAGEHEADER("SFS Public Keys for user: $target_uid");
-    }
-    else {
-	PAGEHEADER("My SFS Public Keys");
-    }
+    PAGEHEADER("SFS Public Keys for user: $target_uid");
 
     #
     # Get the list and show it.
@@ -104,10 +101,12 @@ function SPITFORM($formfields, $errors)
 	    }
 	    $chunky  = chunk_split("$pubkey $comment $fnote", 75, "<br>\n");
 
+	    $delurl  = CreateURL("deletesfskey", $target_user, "key", $foo);
+
 	    echo "<tr>
                      <td align=center>
-                       <A href=deletesfskey.php3?target_uid=$target_uid" .
-	                  "&key=$foo><img alt=X src=redball.gif></A>
+                       <A href='$delurl'>
+                            <img alt='Delete Key' src=redball.gif></A>
                      </td>
                      <td>$chunky</td>
                   </tr>\n";
@@ -156,8 +155,8 @@ function SPITFORM($formfields, $errors)
     echo "<table align=center border=1> 
           <form enctype=multipart/form-data
                 action=showsfskeys.php3 method=post>\n";
-    echo "<input type=hidden name=\"formfields[target_uid]\" ".
-	         "value=$target_uid>\n";
+    echo "<input type=hidden name=\"formfields[user]\" ".
+	         "value=$webid>\n";
 
     #
     # SFS public key
@@ -303,8 +302,12 @@ DBQueryFatal("replace into user_sfskeys ".
 #
 # Audit
 #
-TBUserInfo($uid, $uid_name, $uid_email);
-TBUserInfo($target_uid, $targuid_name, $targuid_email);
+$uid_name  = $this_user->name();
+$uid_email = $this_user->email();
+
+$targuid_name  = $target_user->name();
+$targuid_email = $target_user->email();
+
 $chunky = chunk_split("$usr_key $comment", 75, "\n");
 
 TBMAIL("$targuid_name <$targuid_email>",
@@ -330,5 +333,6 @@ else {
     SUEXEC("nobody", "nobody", "webaddsfskey -w $target_uid", 0);
 }
 
-header("Location: showsfskeys.php3?target_uid=$target_uid");
+header("Location: ". CreateURL("showsfskeys", $target_user));
+
 ?>
diff --git a/www/showstats.php3 b/www/showstats.php3
index c712ff6b09c8504f804ee7b96ad6db497eb9ec5b..e18ac0812d7bc72eea71756b432c66e8a2758701 100644
--- a/www/showstats.php3
+++ b/www/showstats.php3
@@ -15,9 +15,9 @@ PAGEHEADER("Testbed Wide Stats");
 #
 # Only known and logged in users can end experiments.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 if (!isset($verbose)) {
      $verbose = 0;
@@ -92,11 +92,14 @@ echo "<br>\n";
 
 # Determine what to do.
 if ($showby == "user") {
-    if ($which) {
-	if ($which != $uid &&
-	    ! TBUserInfoAccessCheck($uid, $which, $TB_USERINFO_READINFO)) {
-	    USERERROR("You do not have permission to view stats for ".
-		      "user $which!", 1);
+    if ($which && $which != $uid) {
+	if (! ($target_user = User::Lookup($which))) {
+	    USERERROR("The user $which is not a valid user", 1);
+	}
+	elseif (! $target_user->AccessCheck($this_user,
+					    $TB_USERINFO_READINFO)) {
+	    USERERROR("You do not have permission to view ${which}'s stats!",
+		      1);
 	}
     }
     else
@@ -169,7 +172,7 @@ elseif ($showby == "all") {
         #
         # Get a project list for which the user has read permission.
         #
-        $projlist = TBProjList($uid, $TB_PROJECT_READINFO);
+        $projlist = $this_user->ProjectAccessList($TB_PROJECT_READINFO);
 	if (! count($projlist)) {
 	    USERERROR("You do not have permission to view stats for any ".
 		      "project!", 1);
diff --git a/www/showstuff.php3 b/www/showstuff.php3
index 5783bd769b785501943244243fe9d7bdd2240998..dba539d103b205142d019ff30202d22fe85f899a 100644
--- a/www/showstuff.php3
+++ b/www/showstuff.php3
@@ -14,7 +14,7 @@ include_once("template_defs.php");
 #
 # A project
 #
-function SHOWPROJECT($pid, $thisuid) {
+function SHOWPROJECT($pid, $ignore) {
     global $WIKISUPPORT, $CVSSUPPORT, $TBPROJ_DIR, $TBCVSREPO_DIR;
     global $MAILMANSUPPORT, $OPSCVSURL, $USERNODE;
     global $TBDB_TRUST_GROUPROOT;
@@ -53,6 +53,11 @@ function SHOWPROJECT($pid, $thisuid) {
     $wikiname           = $row[wikiname];
     $cvsrepo_public     = $row[cvsrepo_public];
 
+    if (! ($head_user = User::Lookup($proj_head_uid))) {
+	TBERROR("Could not lookup object for user $proj_head_uid", 1);
+    }
+    $showuser_url = CreateURL("showuser", $head_user);
+
     if ($proj_public) {
 	$proj_public = "Yes";
     }
@@ -102,8 +107,7 @@ function SHOWPROJECT($pid, $thisuid) {
     echo "<tr>
               <td>Project Head: </td>
               <td class=\"left\">
-                <a href='showuser.php3?target_uid=$proj_head_uid'>
-                     $proj_head_uid</a></td>
+                <a href='$showuser_url'>$proj_head_uid</a></td>
           </tr>\n";
     
     echo "<tr>
@@ -250,7 +254,7 @@ function SHOWPROJECT($pid, $thisuid) {
 #
 # A Group
 #
-function SHOWGROUP($pid, $gid, $thisuid) {
+function SHOWGROUP($pid, $gid, $ignore) {
     global $OURDOMAIN;
     global $MAILMANSUPPORT;
     global $TBDB_TRUST_GROUPROOT;
@@ -282,6 +286,11 @@ function SHOWGROUP($pid, $gid, $thisuid) {
 	$expt_last = "&nbsp;";
     }
 
+    if (! ($leader_user = User::Lookup($leader))) {
+	TBERROR("Could not lookup object for user $leader", 1);
+    }
+    $showuser_url = CreateURL("showuser", $leader_user);
+
     #
     # Generate the table.
     #
@@ -316,7 +325,7 @@ function SHOWGROUP($pid, $gid, $thisuid) {
     echo "<tr>
               <td>Group Leader: </td>
               <td class=\"left\">
-                <a href='showuser.php3?target_uid=$leader'>$leader</a></td>
+                <a href='$showuser_url'>$leader</a></td>
           </tr>\n";
     
     if ($MAILMANSUPPORT) {
@@ -365,7 +374,7 @@ function SHOWGROUP($pid, $gid, $thisuid) {
 function SHOWGROUPMEMBERS($pid, $gid, $prived = 0) {
     $query_result =
 	DBQueryFatal("SELECT m.*,u.* FROM group_membership as m ".
-		     "left join users as u on u.uid=m.uid ".
+		     "left join users as u on u.uid_idx=m.uid_idx ".
 		     "WHERE pid='$pid' and gid='$gid'");
     
     if (! mysql_num_rows($query_result)) {
@@ -401,14 +410,19 @@ function SHOWGROUPMEMBERS($pid, $gid, $prived = 0) {
 	$usr_email  = $row[usr_email];
 	$trust      = $row[trust];
 
+	if (! ($target_user = User::Lookup($target_uid))) {
+	    TBERROR("Could not lookup object for user $target_uid", 1);
+	}
+	$showuser_url = CreateURL("showuser", $target_user);
+	$deluser_url  = CreateURL("deleteuser", $target_user, URLARG_PID,$pid);
+
         echo "<tr>
                   <td>$usr_name</td>\n";
 	if (strcmp($pid, $gid)) {
 	    echo "<td>$usr_email</td>\n";
 	}
 	echo "    <td>
-                    <a href='showuser.php3?target_uid=$target_uid'>
-                       $target_uid</a>
+                    <a href='$showuser_url'>$target_uid</a>
                   </td>\n";
 	
 	if (TBTrustConvert($trust) != $TBDB_TRUST_NONE) {
@@ -419,9 +433,8 @@ function SHOWGROUPMEMBERS($pid, $gid, $prived = 0) {
 	}
 	if ($showdel) {
 	    echo "<td align=center>
-		      <a href='deleteuser.php3?target_uid=$target_uid";
-	    echo         "&target_pid=$pid'>
-                         <img alt=N src=redball.gif></td>\n";
+		      <a href='$deluser_url'>
+                         <img alt='Delete User' src=redball.gif></td>\n";
 	}
 	echo "</tr>\n";
     }
@@ -431,12 +444,17 @@ function SHOWGROUPMEMBERS($pid, $gid, $prived = 0) {
 #
 # A list of groups for a user.
 #
-function SHOWGROUPMEMBERSHIP($uid) {
+function SHOWGROUPMEMBERSHIP($webid) {
     $none = TBDB_TRUSTSTRING_NONE;
+
+    if (! ($user = User::Lookup($webid))) {
+	TBERROR("Error getting object for user $webid", 1);
+    }
+    $idx = $user->uid_idx();
     
     $query_result =
 	DBQueryFatal("SELECT * FROM group_membership ".
-		     "WHERE uid='$uid' and trust!='$none' ".
+		     "WHERE uid_idx='$idx' and trust!='$none' ".
 		     "order by pid");
     
     if (! mysql_num_rows($query_result)) {
@@ -473,224 +491,12 @@ function SHOWGROUPMEMBERSHIP($uid) {
 #
 # A User
 #
-function SHOWUSER($uid) {
-    global $WIKISUPPORT;
-
-    $userinfo_result =
-	DBQueryFatal("SELECT * from users where uid='$uid'");
-
-    $row	= mysql_fetch_array($userinfo_result);
-    #$usr_expires = $row[usr_expires];
-    $uid_idx     = $row["uid_idx"];
-    $usr_email   = $row[usr_email];
-    $usr_URL     = $row[usr_URL];
-    $usr_addr    = $row[usr_addr];
-    $usr_addr2   = $row[usr_addr2];
-    $usr_city    = $row[usr_city];
-    $usr_state   = $row[usr_state];
-    $usr_zip     = $row[usr_zip];
-    $usr_country = $row[usr_country];
-    $usr_name    = $row[usr_name];
-    $usr_phone   = $row[usr_phone];
-    $usr_shell   = $row[usr_shell];
-    $usr_title   = $row[usr_title];
-    $usr_affil   = $row[usr_affil];
-    $status      = $row[status];
-    $admin       = $row[admin];
-    $notes       = $row[notes];
-    $frozen      = $row['weblogin_frozen'];
-    $failcount   = $row['weblogin_failcount'];
-    $failstamp   = $row['weblogin_failstamp'];
-    $wikiname    = $row['wikiname'];
-    $cvsweb      = $row['cvsweb'];
-    $wikionly    = $row['wikionly'];
-
-    if (!strcmp($usr_addr2, ""))
-	$usr_addr2 = "&nbsp;";
-    if (!strcmp($usr_city, ""))
-	$usr_city = "&nbsp;";
-    if (!strcmp($usr_state, ""))
-	$usr_state = "&nbsp;";
-    if (!strcmp($usr_zip, ""))
-	$usr_zip = "&nbsp;";
-    if (!strcmp($usr_country, ""))
-	$usr_country = "&nbsp;";
-    if (!strcmp($notes, ""))
-	$notes = "&nbsp;";
-
-    #
-    # Last Login info.
-    #
-    if (($lastweblogin = LASTWEBLOGIN($uid)) == 0)
-	$lastweblogin = "&nbsp;";
-    if (($lastuserslogininfo = TBUsersLastLogin($uid)) == 0)
-	$lastuserslogin = "N/A";
-    else {
-	$lastuserslogin = $lastuserslogininfo["date"] . " " .
-		          $lastuserslogininfo["time"];
-    }
-    
-    if (($lastnodelogininfo = TBUidNodeLastLogin($uid)) == 0)
-	$lastnodelogin = "N/A";
-    else {
-	$lastnodelogin = $lastnodelogininfo["date"] . " " .
-		         $lastnodelogininfo["time"] . " " .
-                         "(" . $lastnodelogininfo["node_id"] . ")";
-    }
-    
-    echo "<table align=center border=1>\n";
-    
-    echo "<tr>
-              <td>Username:</td>
-              <td>$uid ($uid_idx)</td>
-          </tr>\n";
-    
-    echo "<tr>
-              <td>Full Name:</td>
-              <td>$usr_name</td>
-          </tr>\n";
-    
-    echo "<tr>
-              <td>Email Address:</td>
-              <td>$usr_email</td>
-          </tr>\n";
-
-    echo "<tr>
-              <td>Home Page URL:</td>
-              <td><a href='$usr_URL'>$usr_URL</a></td>
-          </tr>\n";
-
-    if ($WIKISUPPORT && isset($wikiname)) {
-	$wikiurl = "gotowiki.php3?redurl=Main/$wikiname";
-	
-	echo "<tr>
-                  <td>Emulab Wiki Page:</td>
-                  <td class=\"left\">
-                      <a href='$wikiurl'>$wikiname</a></td>
-              </tr>\n";
-    }
-    
-    #echo "<tr>
-    #          <td>Expiration date:</td>
-    #          <td>$usr_expires</td>
-    #      </tr>\n";
-    
-    echo "<tr>
-              <td>Address 1:</td>
-              <td>$usr_addr</td>
-          </tr>\n";
-    
-    echo "<tr>
-              <td>Address 2:</td>
-              <td>$usr_addr2</td>
-          </tr>\n";
-    
-    echo "<tr>
-              <td>City:</td>
-              <td>$usr_city</td>
-          </tr>\n";
-    
-    echo "<tr>
-              <td>State:</td>
-              <td>$usr_state</td>
-          </tr>\n";
-    
-    echo "<tr>
-              <td>ZIP:</td>
-              <td>$usr_zip</td>
-          </tr>\n";
-
-    echo "<tr>
-              <td>Country:</td>
-              <td>$usr_country</td>
-          </tr>\n";
-    
-    echo "<tr>
-              <td>Phone #:</td>
-              <td>$usr_phone</td>
-          </tr>\n";
-
-    echo "<tr>
-	      <td>Shell:</td>
-	      <td>$usr_shell</td>
-          </tr>\n";
-    
-    echo "<tr>
-              <td>Title/Position:</td>
-              <td>$usr_title</td>
-         </tr>\n";
-    
-    echo "<tr>
-              <td>Institutional Affiliation:</td>
-              <td>$usr_affil</td>
-          </tr>\n";
-    
-    echo "<tr>
-              <td>Status:</td>
-              <td>$status</td>
-          </tr>\n";
-
-    if ($wikionly) {
-	echo "<tr>
-                  <td><b>Wikionly</b>:</td>
-                  <td>Yes</td>
-              </tr>\n";
-    }
+function SHOWUSER($webid) {
 
-    if ($admin) {
-	echo "<tr>
-                  <td>Administrator:</td>
-                  <td>Yes</td>
-              </tr>\n";
+    if (! ($user = User::Lookup($webid))) {
+	TBERROR("Error getting object for user $webid", 1);
     }
-    
-    echo "<tr>
-              <td>Last Web Login:</td>
-              <td>$lastweblogin</td>
-          </tr>\n";
-    
-    echo "<tr>
-              <td>Last Users Login:</td>
-              <td>$lastuserslogin</td>
-          </tr>\n";
-    
-    echo "<tr>
-              <td>Last Node Login:</td>
-              <td>$lastnodelogin</td>
-          </tr>\n";
-
-    if (ISADMIN()) {
-	$cvswebflip = ($cvsweb ? 0 : 1);
-
-	echo "<tr>
-                  <td>CVSWeb Access:</td>
-                  <td>$cvsweb (<a href=toggle.php?target_uid=$uid".
-	                      "&type=cvsweb&value=$cvswebflip>Toggle</a>)
-              </tr>\n";
-	
-	$freezeflip = ($frozen ? 0 : 1);
-	
-	echo "<tr>
-                  <td>Web Freeze:</td>
-                  <td>$frozen (<a href=toggle.php?target_uid=$uid".
-	                          "&type=webfreeze&value=$freezeflip>Toggle</a>)
-              </tr>\n";
-	
-	if ($frozen && $failstamp && $failcount) {
-	    $when = strftime("20%y-%m-%d %H:%M:%S", $failstamp);
-	    
-	    echo "<tr>
-                      <td>Login Failures:</td>
-                      <td>$failcount ($when)</td>
-                  </tr>\n";
-	}
-	echo "<tr>
-                  <td>Notes:</td>
-                  <td>$notes</td>
-              </tr>\n";
-    }
-    echo "</table>\n";
-
+    return $user->Show();
 }
 
 #
@@ -779,6 +585,11 @@ function SHOWEXP($pid, $eid, $short = 0, $sortby = "") {
     $autoswap_str= $autoswap_hrs." hour".($autoswap_hrs==1 ? "" : "s");
     $idleswap_str= $idleswap_hrs." hour".($idleswap_hrs==1 ? "":"s");
 
+    if (! ($head_user = User::Lookup($exp_head))) {
+	TBERROR("Error getting object for user $exp_head", 1);
+    }
+    $showuser_url = CreateURL("showuser", $head_user);
+
     if ($swappable)
 	$swappable = "Yes";
     else
@@ -862,7 +673,7 @@ function SHOWEXP($pid, $eid, $short = 0, $sortby = "") {
     echo "<tr>
             <td>Experiment Head: </td>
             <td class=\"left\">
-              <a href='showuser.php3?target_uid=$exp_head'>$exp_head</a></td>
+              <a href='$showuser_url'>$exp_head</a></td>
           </tr>\n";
 
     if (!$short) {
@@ -1132,11 +943,21 @@ function SHOWEXPLIST($type, $fromuid, $id, $gid = "") {
 }
 
 
-function showexplist_internal($templates_only, $type, $fromuid, $id, $gid) {
+function showexplist_internal($templates_only, $type, $fromwebid, $id, $gid) {
     global $TB_EXPTSTATE_SWAPPED, $TB_EXPTSTATE_SWAPPING;
 
+    if (! ($this_user = User::Lookup($fromwebid))) {
+	TBERROR("Error getting object for user $fromwebid", 1);
+    }
+    $from_idx = $this_user->uid_idx();
+
     if ($type == "USER") {
-	$where = "expt_head_uid='$id'";
+	if (! ($target_user = User::Lookup($id))) {
+	    TBERROR("Error getting object for user $id", 1);
+	}
+	$uid = $target_user->uid();
+	
+	$where = "expt_head_uid='$uid'";
 	$title = "Current";
     } elseif ($type == "PROJ") {
 	$where = "e.pid='$id'";
@@ -1182,7 +1003,7 @@ function showexplist_internal($templates_only, $type, $fromuid, $id, $gid) {
 			 "left join reserved as r on e.pid=r.pid and ".
 			 "     e.eid=r.eid ".
  			 "left join group_membership as g on g.pid=e.pid and ".
-	 		 "     g.gid=e.gid and g.uid='$fromuid' ".
+	 		 "     g.gid=e.gid and g.uid_idx='$from_idx' ".
 			 "where g.uid is not null and ($where) ".
 			 "      and t.guid is null $template_clause " .
 			 "group by e.pid,e.eid order by e.state,e.eid");
@@ -1611,6 +1432,11 @@ function SHOWOSINFO($osid) {
     $max_concurrent = $osrow[max_concurrent];
     $reboot_waittime= $osrow[reboot_waittime];
 
+    if (! ($creator_user = User::Lookup($creator))) {
+	TBERROR("Error getting object for user $creator", 1);
+    }
+    $showuser_url = CreateURL("showuser", $creator_user);
+
     if (!$os_description)
 	$os_description = "&nbsp;";
     if (!$os_version)
@@ -1647,7 +1473,7 @@ function SHOWOSINFO($osid) {
     echo "<tr>
             <td>Creator: </td>
             <td class=left>
-              <a href='showuser.php3?target_uid=$creator'>$creator</a></td>
+              <a href='$showuser_url'>$creator</a></td>
  	  </tr>\n";
 
     echo "<tr>
@@ -2015,10 +1841,15 @@ function SHOWIMAGEID($imageid, $edit, $isadmin = 0) {
 #
 # Show all experiments using a particular OSID
 #
-function SHOWOSIDEXPTS($pid, $osname, $uid) {
+function SHOWOSIDEXPTS($pid, $osname, $webid) {
     global $TBOPSPID;
     global $TB_EXPT_READINFO;
 
+    if (! ($user = User::Lookup($webid))) {
+	TBERROR("Error getting object for user $webid", 1);
+    }
+    $uid = $user->uid();
+
     #
     # Due to the funny way we handle 'global' images in the emulab-ops project,
     # we have to treat its images specially - namely, we have to make sure
@@ -2914,8 +2745,13 @@ function SPITOSINFOLINK($osid)
 #
 # A list of widearea accounts.
 #
-function SHOWWIDEAREAACCOUNTS($uid) {
+function SHOWWIDEAREAACCOUNTS($webid) {
     $none = TBDB_TRUSTSTRING_NONE;
+
+    if (! ($user = User::Lookup($webid))) {
+	TBERROR("Error getting object for user $webid", 1);
+    }
+    $uid = $user->uid();
     
     $query_result =
 	DBQueryFatal("SELECT * FROM widearea_accounts ".
@@ -2977,6 +2813,11 @@ function SHOWWIDEAREANODE($node_id, $embedded = 0) {
     $hostname		= $row[hostname];
     $site		= $row[site];
 
+    if (! ($user = User::Lookup($contact_uid))) {
+	TBERROR("Error getting object for user $contact_uid", 1);
+    }
+    $showuser_url = CreateURL("showuser", $user);
+
     if (! $embedded) {
 	echo "<table border=2 cellpadding=0 cellspacing=2
                      align=center>\n";
@@ -2992,8 +2833,7 @@ function SHOWWIDEAREANODE($node_id, $embedded = 0) {
     echo "<tr>
               <td>Contact UID:</td>
               <td class=left>
-                  <a href='showuser.php3?target_uid=$contact_uid'>
-		     $contact_uid</a></td>
+                  <a href='$showuser_url'>$contact_uid</a></td>
           </tr>\n";
 
     echo "<tr>
diff --git a/www/showsumstats.php3 b/www/showsumstats.php3
index 820bea95a546bde4a5bb4170e0f5be69303297dc..48791daa7eb22ae4a0dc55bff2f52ef6f2a22b24 100644
--- a/www/showsumstats.php3
+++ b/www/showsumstats.php3
@@ -15,11 +15,12 @@ PAGEHEADER("Testbed Summary Stats");
 #
 # Only known and logged in users can end experiments.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 # Summary data for admins only.
-if (!ISADMIN() && !STUDLY()) {
+if (!$isadmin && !STUDLY()) {
     USERERROR("You are not allowed to view this page!", 1);
 }
 
@@ -126,7 +127,7 @@ function showsummary ($showby, $sortby) {
 	    $which = "uid";
 	    $table = "user_stats";
 	    $title = "User Summary Stats (Epoch)";
-	    $link  = "showuser.php3?target_uid=";
+	    $link  = "showuser.php3?user=";
 	    break;
         default:
 	    USERERROR("Invalid showby argument: $showby!", 1);
@@ -166,9 +167,9 @@ function showsummary ($showby, $sortby) {
 			 "allexpt_duration / (24 * 3600) as expt_days, ".
 			 "exptswapin_count+exptstart_count as expt_swapins, ".
 			 "exptpreload_count+exptstart_count as expt_new, ".
-			 "u.usr_name ".
+			 "u.usr_name, s.uid_idx ".
 			 "from user_stats as s ".
-			 "left join users as u on u.unix_uid=s.uid_idx ".
+			 "left join users as u on u.uid_idx=s.uid_idx ".
 			 "$wclause ".
 			 "order by $order");
     }
@@ -178,7 +179,8 @@ function showsummary ($showby, $sortby) {
 			 "allexpt_pnode_duration / (24 * 3600) as pnode_days,".
 			 "allexpt_duration / (24 * 3600) as expt_days, ".
 			 "exptswapin_count+exptstart_count as expt_swapins, ".
-			 "exptpreload_count+exptstart_count as expt_new ".
+			 "exptpreload_count+exptstart_count as expt_new, ".
+			 "${which}_idx ".
 			 "from $table  ".
 			 "$wclause ".
 			 "order by $order");
@@ -260,6 +262,7 @@ function showsummary ($showby, $sortby) {
     mysql_data_seek($query_result, 0);    
     while ($row = mysql_fetch_assoc($query_result)) {
 	$heading = $row[$which];
+	$idx     = $row["${which}_idx"];
 	$pnodes  = $row["allexpt_pnodes"];
 	$phours  = $row["pnode_days"];
 	$ehours  = $row["expt_days"];
@@ -664,7 +667,7 @@ function showrange ($showby, $sortby, $range) {
 	    $which = "uid";
 	    $table = $uid_summary;
 	    $title = "User Summary Stats ($range)";
-	    $link  = "showuser.php3?target_uid=";
+	    $link  = "showuser.php3?user=";
 	    break;
         default:
 	    USERERROR("Invalid showby argument: $showby!", 1);
diff --git a/www/showuser.php3 b/www/showuser.php3
index f19ad0bab9135492914d870268b8e09bb7809e1a..2d175a322d04ab35c80f7b4fa46f7033a9593799 100644
--- a/www/showuser.php3
+++ b/www/showuser.php3
@@ -11,49 +11,47 @@ include_once("template_defs.php");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid, CHECKLOGIN_USERSTATUS|
-	      CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie(CHECKLOGIN_USERSTATUS|
+			     CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY);
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify form arguments.
 # 
-if (!isset($target_uid) ||
-    strcmp($target_uid, "") == 0) {
+if (!isset($user) ||
+    strcmp($user, "") == 0) {
     USERERROR("You must provide a User ID.", 1);
 }
 
+#
+# Check to make sure thats this is a valid UID.
+#
+if (! ($target_user = User::Lookup($user))) {
+    USERERROR("Could not lookup user '$user'!", 1);
+}
+$userstatus = $target_user->status();
+$wikionly   = $target_user->wikionly();
+$target_idx = $target_user->uid_idx();
+$target_uid = $target_user->uid();
+
 #
 # Standard Testbed Header, now that we know what we want to say.
 #
-if (strcmp($uid, $target_uid)) {
+if (! $this_user->SameUser($target_user)) {
     PAGEHEADER("Information for User: $target_uid");
 }
 else {
     PAGEHEADER("My Emulab.Net");
 }
 
-#
-# Check to make sure thats this is a valid UID. Getting the status works,
-# and we need that later. 
-#
-if (! ($userstatus = TBUserStatus($target_uid))) {
-    USERERROR("The user $target_uid is not a valid user", 1);
-}
-$wikionly = TBWikiOnlyUser($target_uid);
-
 #
 # Verify that this uid is a member of one of the projects that the
 # target_uid is in. Must have proper permission in that group too. 
 #
-if (!$isadmin &&
-    strcmp($uid, $target_uid)) {
-
-    if (! TBUserInfoAccessCheck($uid, $target_uid, $TB_USERINFO_READINFO)) {
-	USERERROR("You do not have permission to view this user's ".
-		  "information!", 1);
-    }
+if (!$isadmin && 
+    !$target_user->AccessCheck($this_user, $TB_USERINFO_READINFO)) {
+    USERERROR("You do not have permission to view this user's information!", 1);
 }
 
 #
@@ -69,12 +67,12 @@ if ($message != "") {
 #
 # Tell the user how many PCs he is using.
 #
-$yourpcs = TBUserPCs($target_uid);
+$yourpcs = $target_user->PCsInUse();
 
 if ($yourpcs) {
     echo "<center><font color=Red size=+2>\n";
     
-    if (strcmp($uid, $target_uid))
+    if (! $this_user->SameUser($target_user))
 	echo "$target_uid is using $yourpcs PCs!\n";
     else
 	echo "You are using $yourpcs PCs!\n";
@@ -108,9 +106,10 @@ $query_result =
 		 "left join experiments as e on g.pid=e.pid and g.gid=e.gid ".
 		 "left join reserved as r on e.pid=r.pid and e.eid=r.eid ".
 		 "left join group_membership as g2 on g2.pid=g.pid and ".
-		 "     g2.gid=g.gid and g2.uid='$uid' ".
-		 "where g.uid='$target_uid' and ".
-		 ($isadmin ? "" : "g2.uid is not null and ") .
+		 "     g2.gid=g.gid and ".
+		 "     g2.uid_idx='" . $this_user->uid_idx() . "' ".
+		 "where g.uid_idx='$target_idx' and ".
+		 ($isadmin ? "" : "g2.uid_idx is not null and ") .
 		 "g.trust!='" . TBDB_TRUSTSTRING_NONE . "' ".
 		 "group by g.pid, g.gid ".
 		 "order by g.pid,gr.created");
@@ -200,61 +199,66 @@ SUBMENUSTART("User Options");
 # Permission check not needed; if the user can view this page, they can
 # generally access these subpages, but if not, the subpage will still whine.
 # 
-WRITESUBMENUBUTTON("Edit Profile",  "moduserinfo.php3?target_uid=$target_uid");
+WRITESUBMENUBUTTON("Edit Profile",
+		   CreateURL("moduserinfo", $target_user));
 
-if (!$wikionly && ($isadmin || !strcmp($uid, $target_uid))) {
+if (!$wikionly && ($isadmin || $target_user->SameUser($this_user))) {
     WRITESUBMENUBUTTON("Edit SSH Keys",
-		       "showpubkeys.php3?target_uid=$target_uid");
+		       CreateURL("showpubkeys", $target_user));
+    
     WRITESUBMENUBUTTON("Edit SFS Keys",
-		       "showsfskeys.php3?target_uid=$target_uid");
+		       CreateURL("showsfskeys", $target_user));
 
     WRITESUBMENUBUTTON("Generate SSL Cert",
-		       "gensslcert.php3?target_uid=$target_uid");
+		       CreateURL("gensslcert", $target_user));
 
     WRITESUBMENUBUTTON("Show History",
-		       "showstats.php3?showby=user&which=$target_uid");
+		       CreateURL("showstats", $target_user, "showby", "user"));
 
     if ($MAILMANSUPPORT && mysql_num_rows($mm_result)) {
 	WRITESUBMENUBUTTON("Show Mailman Lists",
-			   "showmmlists.php3?target_uid=$target_uid");
+			   CreateURL("showmmlists", $target_user));
     }
 }
 
 if ($isadmin) {
     SUBMENUSECTION("Admin Options");
     
-    if (!strcmp(TBUserStatus($target_uid), TBDB_USERSTATUS_FROZEN)) {
+    if (!strcmp($userstatus, TBDB_USERSTATUS_FROZEN)) {
 	WRITESUBMENUBUTTON("Thaw User",
-		   "freezeuser.php3?target_uid=$target_uid&action=thaw");
+			   CreateURL("freezeuser", $target_user,
+				     "action", "thaw"));
     }
     else {
 	WRITESUBMENUBUTTON("Freeze User",
-		   "freezeuser.php3?target_uid=$target_uid&action=freeze");
+			   CreateURL("freezeuser", $target_user,
+				     "action", "freeze"));
     }
     WRITESUBMENUBUTTON("Delete User",
-		       "deleteuser.php3?target_uid=$target_uid");
+		       CreateURL("deleteuser", $target_user));
 
     WRITESUBMENUBUTTON("SU as User",
-		       "suuser.php?target_uid=$target_uid");
+		       CreateURL("suuser", $target_user));
 
     if ($userstatus == TBDB_USERSTATUS_UNAPPROVED) {
 	WRITESUBMENUBUTTON("Change UID",
-			   "changeuid.php?target_uid=$target_uid");
+			   CreateURL("changeuid", $this_user));
     }
 
     if (! strcmp($userstatus, TBDB_USERSTATUS_NEWUSER) ||
 	! strcmp($userstatus, TBDB_USERSTATUS_UNVERIFIED)) {
 	WRITESUBMENUBUTTON("Resend Verification Key",
-			   "resendkey.php3?target_uid=$target_uid");
+			   CreateURL("resendkey", $this_user));
     }
     else {
 	WRITESUBMENUBUTTON("Send Test Email Message",
-			   "sendtestmsg.php3?target_uid=$target_uid");
+			   CreateURL("sendtestmsg", $this_user));
     }
 }
 SUBMENUEND();
 
-SHOWUSER($target_uid);
+$target_user->Show();
+
 SUBPAGEEND();
 
 if ($isadmin) {
@@ -262,13 +266,7 @@ if ($isadmin) {
           <h3>User Stats</h3>
          </center>\n";
 
-    #
-    # XXX: need to redo this entire script ...
-    #
-    if (! ($user = User::LookupByUid($target_uid))) {
-	TBERROR("Could not lookup user '$target_uid'!", 1);
-    }
-    echo $user->ShowStats();
+    echo $target_user->ShowStats();
 }
 
 #
diff --git a/www/showuser_list.php3 b/www/showuser_list.php3
index 338e64805237f6ae26869b3f8997b34bcf9f63a5..be9e8a64e9d67ca5319c2f19edd0f1595e4ee3a2 100644
--- a/www/showuser_list.php3
+++ b/www/showuser_list.php3
@@ -15,14 +15,9 @@ PAGEHEADER("User List");
 #
 # Only known and logged in users allowed.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-
-#
-# Admin users can see all users, while normal users can only see
-# users in their projects.
-#
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 # For "recent" stuff below.
 $dorecent = 0;
@@ -191,12 +186,15 @@ echo "</tr>\n";
 
 while ($row = mysql_fetch_array($query_result)) {
     $thisuid  = $row[uid];
+    $webid    = $row[uid_idx];
     $name     = $row[usr_name];
     $status   = $row[status];
     $unix_uid = $row[unix_uid];
     $webidle  = $row[webidle];
     $usersidle= $row[usersidle];
 
+    $showuser_url = CreateURL("showuser", URLARG_UID, $webid);
+
     echo "<tr>\n";
 
     if (strcmp($status, "active") == 0) {
@@ -206,7 +204,7 @@ while ($row = mysql_fetch_array($query_result)) {
 	echo "<td align=center><img alt=\"N\" src=\"redball.gif\"></td>\n";
     }
 
-    echo "<td><A href='showuser.php3?target_uid=$thisuid'>$thisuid</A></td>
+    echo "<td><A href='$showuser_url'>$thisuid</A></td>
               <td>$name</td>\n";
 
     # List of projects.
diff --git a/www/spewconlog.php3 b/www/spewconlog.php3
index 6d2915d15505fdc8678f2e85e43ac345d3914a49..6a8f7a74773b3b92cab8ef34af225d42a43433d7 100644
--- a/www/spewconlog.php3
+++ b/www/spewconlog.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2005 University of Utah and the Flux Group.
+# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,9 +14,9 @@ include("showstuff.php3");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Check to make sure a valid nodeid.
diff --git a/www/spewevents.php b/www/spewevents.php
index ef0633ad6c5c61d10cbff15adac103325f8a4a62..613ebc3f3530f7d2ccaa3e834db12d78a632dc3c 100644
--- a/www/spewevents.php
+++ b/www/spewevents.php
@@ -10,10 +10,9 @@ include("showstuff.php3");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/spewlogfile.php3 b/www/spewlogfile.php3
index cdb00f90837b3f72f04b52a1d2a95afb2dd40a52..64d652a1a1175980da68a3afa3a487a5ede0b95c 100644
--- a/www/spewlogfile.php3
+++ b/www/spewlogfile.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002 University of Utah and the Flux Group.
+# Copyright (c) 2000-2002, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -13,12 +13,11 @@ include("showstuff.php3");
 #PAGEHEADER("Watch Experiment Log");
 
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/spitnsdata.php3 b/www/spitnsdata.php3
index a4d5262d03f82f708afa3299805c4d8e4a2b7802..c3523295c8c6d59f72e466769c7ef9db4514b53e 100644
--- a/www/spitnsdata.php3
+++ b/www/spitnsdata.php3
@@ -8,10 +8,11 @@ include("defs.php3");
 include_once("template_defs.php");
 
 #
-# Only known and logged in users can begin experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # This comes from the begin_experiment page, when cloning an experiment
diff --git a/www/spitreport.php b/www/spitreport.php
index f1f01188e99fa6e24020d0a634837b11ec69da9a..aa68bfa51b92e0b3ae95dac4e969f5c46ec6b661 100644
--- a/www/spitreport.php
+++ b/www/spitreport.php
@@ -5,11 +5,13 @@
 # All rights reserved.
 #
 include("defs.php3");
+
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/statechange.php b/www/statechange.php
index a9c4efc17e4e6e965f9c0e0e666de2d19891db2f..b8c90022909f5963c71fc8438d2a363e7b71be50 100644
--- a/www/statechange.php
+++ b/www/statechange.php
@@ -9,10 +9,11 @@ include("defs.php3");
 $currentusage  = 0;
 
 #
-# Only known and logged in users can look at experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 PAGEBEGINNING("Experiment State Change", 0, 1);
 
diff --git a/www/suuser.php b/www/suuser.php
index 401b526e79747b8e658845db677474cf11092b6a..22048fdcea04ef6e6057e7a1a4cd35a63c197ee6 100644
--- a/www/suuser.php
+++ b/www/suuser.php
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2003 University of Utah and the Flux Group.
+# Copyright (c) 2000-2003, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -9,37 +9,32 @@ include("defs.php3");
 #
 # Only known and logged in users allowed.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
 
 #
 # Verify arguments.
 # 
-if (!isset($target_uid) ||
-    strcmp($target_uid, "") == 0) {
+if (!isset($user) ||
+    strcmp($user, "") == 0) {
     USERERROR("You must provide a User ID.", 1);
 }
-if (!TBvalid_uid($target_uid)) {
-    PAGEARGERROR("Invalid characters in UID");
-}
-$isadmin = ISADMIN($uid);
 
-if (!$isadmin) {
+if (!ISADMIN()) {
     USERERROR("You do not have permission to do this!", 1);
 }
 
 #
 # Confirm target is a real user.
 #
-if (! TBCurrentUser($target_uid)) {
-    USERERROR("No such user '$target_uid'", 1);
+if (! ($target_user = User::Lookup($user))) {
+    USERERROR("No such user '$user'", 1);
 }
 
-if (DOLOGIN_MAGIC($target_uid) < 0) {
+if (DOLOGIN_MAGIC($target_user->uid(), $target_user->uid_idx()) < 0) {
     USERERROR("Could not log you in as $target_uid", 1);
 }
 # So the menu and headers get spit out properly.
-$_COOKIE[$TBNAMECOOKIE] = $target_uid;
+$_COOKIE[$TBNAMECOOKIE] = $target_user->webid();
 
 PAGEHEADER("SU as User");
 
diff --git a/www/swapexp.php3 b/www/swapexp.php3
index 91911120bc50c87e0f11df019618fde88c45952f..ce305b8c0d723b42ca375c2d4383b0b5620013a7 100644
--- a/www/swapexp.php3
+++ b/www/swapexp.php3
@@ -9,10 +9,11 @@ include("showstuff.php3");
 include_once("template_defs.php");
 
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 # This will not return if its a sajax request.
 include("showlogfile_sup.php3");
@@ -52,7 +53,7 @@ PAGEHEADER("Swap Control");
 # Only admins can issue a force swapout
 # 
 if (isset($force) && $force == 1) {
-	if (! ISADMIN($uid)) {
+	if (! $isadmin) {
 		USERERROR("Only testbed administrators can forcibly swap ".
 			  "an experiment out!", 1);
 	}
diff --git a/www/tbauth.php3 b/www/tbauth.php3
index 3e318c643bc4c8b5827025cd35c8a8dd3ec40116..483d35b65d09776af6f27b59208839307a1737c3 100644
--- a/www/tbauth.php3
+++ b/www/tbauth.php3
@@ -12,11 +12,13 @@
 #
 $CHECKLOGIN_STATUS		= -1;
 $CHECKLOGIN_UID			= 0;
+$CHECKLOGIN_IDX			= null;
 $CHECKLOGIN_NOLOGINS		= -1;
 $CHECKLOGIN_WIKINAME            = "";
 $CHECKLOGIN_IDLETIME            = 0;
 $CHECKLOGIN_HASHKEY             = null;
 $CHECKLOGIN_HASHHASH            = null;
+$CHECKLOGIN_USER                = null;
 
 #
 # New Mapping. 
@@ -88,18 +90,13 @@ function REMEMBERED_ID() {
 
 #
 # Return the value of the currently logged in uid, or null if not
-# logged in. Basically, check the browser to see if its sending a UID
-# and HASH back, and then check the DB to see if the user is really
-# logged in.
+# logged in. This interface is deprecated and being replaced.
 # 
 function GETLOGIN() {
-    if (($uid = GETUID()) == FALSE)
-	    return FALSE;
-
-    $check = CHECKLOGIN($uid);
-
-    if ($check & (CHECKLOGIN_LOGGEDIN|CHECKLOGIN_MAYBEVALID))
-	    return $uid;
+    global $CHECKLOGIN_USER;
+    
+    if (CheckLogin($status))
+	return $CHECKLOGIN_USER->uid();
 
     return FALSE;
 }
@@ -111,44 +108,59 @@ function GETLOGIN() {
 # 
 function GETUID() {
     global $TBNAMECOOKIE;
-    global $nocookieuid;
 
-    $curname = FALSE;
-
-    # XXX - nocookieuid is sent by netbuild applet in URL.
     if (isset($_GET['nocookieuid'])) {
-	$curname = $_GET['nocookieuid'];
+	$uid = $_GET['nocookieuid'];
+	
+	#
+	# XXX - nocookieuid is sent by netbuild applet in URL. A few other java
+        # apps as well, and we retain this for backwards compatability.
+	#
+        # Pedantic check
+	if (! preg_match("/^[-\w]+$/", $uid)) {
+	    return FALSE;
+	}
+	$safe_uid = addslashes($uid);
+
+	#
+	# Map this to an index (from a uid).
+	#
+	$query_result =
+	    DBQueryFatal("select uid_idx from users where uid='$safe_uid'");
+    
+	if (! mysql_num_rows($query_result))
+	    return FALSE;
+	
+	$row = mysql_fetch_array($query_result);
+	return $row[0];
     }
     elseif (isset($_COOKIE[$TBNAMECOOKIE])) {
-	$curname = $_COOKIE[$TBNAMECOOKIE];
-    }
-    else
-	return FALSE;
-
-    # Verify valid string (no special chars like single/double quotes!).
-    # We do not use the standard check function here, since we want to
-    # avoid a DB access on each page until its required. Thats okay since
-    # since we just need to ensure that we feed to the DB query is safe.
-    if (! preg_match("/^[-\w]+$/", $curname)) {
-	return FALSE;
+	$idx = $_COOKIE[$TBNAMECOOKIE];
+
+        # Pedantic check
+	if (! preg_match("/^[-\w]+$/", $idx)) {
+	    return FALSE;
+	}
+
+	return $idx;
     }
-    return $curname;
+    return FALSE;
 }
 
 #
-# Verify a login by sucking a UIDs current hash value out of the database.
+# Verify a login by sucking UIDs current hash value out of the database.
 # If the login has expired, or of the hashkey in the database does not
 # match what came back in the cookie, then the UID is no longer logged in.
 #
 # Returns a combination of the CHECKLOGIN values above.
 #
-function CHECKLOGIN($uid) {
+function LoginStatus() {
     global $TBAUTHCOOKIE, $TBLOGINCOOKIE, $HTTP_COOKIE_VARS, $TBAUTHTIMEOUT;
     global $CHECKLOGIN_STATUS, $CHECKLOGIN_UID, $CHECKLOGIN_NODETYPES;
     global $CHECKLOGIN_WIKINAME, $TBOPSPID;
     global $EXPOSEARCHIVE, $EXPOSETEMPLATES;
     global $CHECKLOGIN_HASHKEY, $CHECKLOGIN_HASHHASH;
-    global $nocookieauth;
+    global $nocookieauth, $CHECKLOGIN_IDX, $CHECKLOGIN_USER;
     
     #
     # If we already figured this out, do not duplicate work!
@@ -156,7 +168,13 @@ function CHECKLOGIN($uid) {
     if ($CHECKLOGIN_STATUS != CHECKLOGIN_NOSTATUS) {
 	return $CHECKLOGIN_STATUS;
     }
-    $CHECKLOGIN_UID = $uid;
+
+    # No UID in the browser? Obviously not logged in!
+    if (($uid_idx = GETUID()) == FALSE) {
+	$CHECKLOGIN_STATUS = CHECKLOGIN_NOTLOGGEDIN;
+	return $CHECKLOGIN_STATUS;
+    }
+    $CHECKLOGIN_IDX = $uid_idx;
 
     # for java applet, we can send the key in the $auth variable,
     # rather than passing it is a cookie.
@@ -192,7 +210,7 @@ function CHECKLOGIN($uid) {
     if (isset($hashhash)) {
 	$CHECKLOGIN_HASHHASH = $safe_hashhash = addslashes($hashhash);
     }
-    $safe_uid = addslashes($uid);
+    $safe_idx = addslashes($uid_idx);
     
     #
     # Note that we get multiple rows back because of the group_membership
@@ -202,12 +220,12 @@ function CHECKLOGIN($uid) {
 	DBQueryFatal("select NOW()>=u.pswd_expires,l.hashkey,l.timeout, ".
 		     "       status,admin,cvsweb,g.trust,l.adminon,webonly, " .
 		     "       user_interface,n.type,u.stud,u.wikiname, ".
-		     "       u.wikionly,g.pid,u.foreign_admin " .
+		     "       u.wikionly,g.pid,u.foreign_admin,u.uid_idx " .
 		     " from users as u ".
-		     "left join login as l on l.uid=u.uid ".
-		     "left join group_membership as g on g.uid=u.uid ".
+		     "left join login as l on l.uid_idx=u.uid_idx ".
+		     "left join group_membership as g on g.uid_idx=u.uid_idx ".
 		     "left join nodetypeXpid_permissions as n on g.pid=n.pid ".
-		     "where u.uid='$safe_uid' and ".
+		     "where u.uid_idx='$safe_idx' and ".
 		     (isset($curhash) ?
 		      "l.hashkey='$safe_curhash'" :
 		      "l.hashhash='$safe_hashhash'"));
@@ -254,6 +272,7 @@ function CHECKLOGIN($uid) {
 
 	# Set foreign_admin=1 for admins of another Emulab.
 	$foreign_admin   = $row[15];
+	$uid_idx         = $row[16];
 
 	$CHECKLOGIN_NODETYPES[$type] = 1;
     }
@@ -270,17 +289,18 @@ function CHECKLOGIN($uid) {
     # Check for frozen account. Might do something interesting later.
     #
     if (! strcmp($status, TBDB_USERSTATUS_FROZEN)) {
-	DBQueryFatal("DELETE FROM login WHERE uid='$safe_uid'");
+	DBQueryFatal("DELETE FROM login WHERE uid_idx='$uid_idx'");
 	$CHECKLOGIN_STATUS = CHECKLOGIN_NOTLOGGEDIN;
 	return $CHECKLOGIN_STATUS;
     }
 
     #
-    # Check for expired login. It does not matter if the cookie matches,
-    # kill the entry anyway so the user is officially logged out.
+    # Check for expired login. Remove this entry from the logins table to
+    # keep it from getting cluttered.
     #
     if (time() > $timeout) {
-	DBQueryFatal("DELETE FROM login WHERE uid='$safe_uid'");
+	DBQueryFatal("delete from login where ".
+		     "uid_idx='$uid_idx' and hashkey='$hashkey'");
 	$CHECKLOGIN_STATUS = CHECKLOGIN_TIMEDOUT;
 	return $CHECKLOGIN_STATUS;
     }
@@ -341,6 +361,13 @@ function CHECKLOGIN($uid) {
 	}
     }
 
+    # Cache this now; someone will eventually want it.
+    $CHECKLOGIN_USER = User::Lookup($uid_idx);
+    if (! $CHECKLOGIN_USER) {
+	$CHECKLOGIN_STATUS = CHECKLOGIN_NOTLOGGEDIN;
+	return $CHECKLOGIN_STATUS;
+    }
+
     #
     # Now add in the modifiers.
     #
@@ -399,29 +426,15 @@ function CHECKLOGIN($uid) {
 # conditions. 
 #
 function LOGGEDINORDIE($uid, $modifier = 0, $login_url = NULL) {
-    global $TBBASE, $BASEPATH, $HTTP_COOKIE_VARS, $TBNAMECOOKIE;
+    global $TBBASE, $BASEPATH;
     global $TBAUTHTIMEOUT, $CHECKLOGIN_HASHKEY;
 
-    # If our login is not valid, then the uid is already set to "",
-    # so refresh it to the cookie value. Then we can pass the right
-    # uid to checklogin, so we can give the right error message.
-    if ($uid == "") {
-	$uid = $HTTP_COOKIE_VARS[$TBNAMECOOKIE];
-
-	if ($uid == "") {
-		$uid = FALSE;
-	}
-	else {
-            # Verify valid string (no special chars like single/double quotes!)
-	    if (! preg_match("/^[-\w]+$/", $uid)) {
-		TBERROR("LOGGEDINORDIE: Illegal characters in $uid", 1);
-	    }
-	}
-    }
-
     #
-    # Allow the caller to specify a different URL to direct the user
-    # to
+    # We now ignore the $uid argument and let LoginStatus figure it out.
+    #
+    
+    #
+    # Allow the caller to specify a different URL to direct the user to
     #
     if (!$login_url) {
 	$login_url = "$TBBASE/login.php3?refer=1";
@@ -430,10 +443,7 @@ function LOGGEDINORDIE($uid, $modifier = 0, $login_url = NULL) {
     $link = "\n<a href=\"$login_url\">Please ".
 	"log in again.</a>\n";
 
-    if ($uid == FALSE)
-        USERERROR("You do not appear to be logged in! $link", 1);
-    
-    $status = CHECKLOGIN($uid);
+    $status = LoginStatus();
 
     switch ($status & CHECKLOGIN_STATUSMASK) {
     case CHECKLOGIN_NOTLOGGEDIN:
@@ -458,7 +468,8 @@ function LOGGEDINORDIE($uid, $modifier = 0, $login_url = NULL) {
 	    $timeout = time() + $TBAUTHTIMEOUT;
 
 	    DBQueryFatal("UPDATE login set timeout='$timeout' ".
-			 "where uid='$uid' and hashkey='$CHECKLOGIN_HASHKEY'");
+			 "where uid_idx='$CHECKLOGIN_IDX' and ".
+			 "      hashkey='$CHECKLOGIN_HASHKEY'");
 	}
 	break;
     default:
@@ -479,20 +490,53 @@ function LOGGEDINORDIE($uid, $modifier = 0, $login_url = NULL) {
         USERERROR("You have not verified your account yet!", 1);
     if ($status & CHECKLOGIN_UNAPPROVED)
         USERERROR("Your account has not been approved yet!", 1);
-    if (($status & CHECKLOGIN_WEBONLY) && ! ISADMIN($uid))
+    if (($status & CHECKLOGIN_WEBONLY) && ! ISADMIN())
         USERERROR("Your account does not permit you to access this page!", 1);
-    if (($status & CHECKLOGIN_WIKIONLY) && ! ISADMIN($uid))
+    if (($status & CHECKLOGIN_WIKIONLY) && ! ISADMIN())
         USERERROR("Your account does not permit you to access this page!", 1);
 
     #
     # Lastly, check for nologins here. This heads off a bunch of other
     # problems and checks we would need.
     #
-    if (NOLOGINS() && !ISADMIN($uid))
+    if (NOLOGINS() && !ISADMIN())
         USERERROR("Sorry. The Web Interface is ".
 		  "<a href=nologins.php3>Temporarily Unavailable!</a>", 1);
 
-    return $uid;
+    # No one should ever look at the return value of this function.
+    return null;
+}
+
+#
+# This is the new interface to the above function. 
+#
+function CheckLoginOrDie($modifier = 0, $login_url = NULL)
+{
+    global $CHECKLOGIN_USER;
+    
+    LOGGEDINORDIE(GETUID(), $modifier, $login_url);
+
+    #
+    # If this returns, login is valid. Return the user object to caller.
+    #
+    return $CHECKLOGIN_USER;
+}
+
+#
+# This interface allows the return of the actual status. I know, its a
+# global variable, but this interface is cleaner. 
+#
+function CheckLogin(&$status)
+{
+    global $CHECKLOGIN_USER;
+
+    $status = LoginStatus();
+
+    # If login looks valid, return the user. 
+    if ($status & (CHECKLOGIN_LOGGEDIN|CHECKLOGIN_MAYBEVALID))
+	    return $CHECKLOGIN_USER;
+
+    return null;
 }
 
 #
@@ -501,7 +545,7 @@ function LOGGEDINORDIE($uid, $modifier = 0, $login_url = NULL) {
 # in user that has to be admin. So ignore the uid and make sure
 # there is a login status.
 #
-function ISADMIN($uid = 1) {
+function ISADMIN() {
     global $CHECKLOGIN_STATUS;
     
     if ($CHECKLOGIN_STATUS == CHECKLOGIN_NOSTATUS) {
@@ -532,8 +576,7 @@ function STUDLY() {
     global $CHECKLOGIN_STATUS;
     
     if ($CHECKLOGIN_STATUS == CHECKLOGIN_NOSTATUS) {
-	$uid=GETUID();
-	TBERROR("STUDLY: $uid is not logged in!", 1);
+	TBERROR("STUDLY: user is not logged in!", 1);
     }
 
     return (($CHECKLOGIN_STATUS &
@@ -545,8 +588,7 @@ function OPSGUY() {
     global $CHECKLOGIN_STATUS;
     
     if ($CHECKLOGIN_STATUS == CHECKLOGIN_NOSTATUS) {
-	$uid=GETUID();
-	TBERROR("OPSGUY: $uid is not logged in!", 1);
+	TBERROR("OPSGUY: user is not logged in!", 1);
     }
 
     return (($CHECKLOGIN_STATUS &
@@ -558,8 +600,7 @@ function WIKIONLY() {
     global $CHECKLOGIN_STATUS;
     
     if ($CHECKLOGIN_STATUS == CHECKLOGIN_NOSTATUS) {
-	$uid=GETUID();
-	TBERROR("WIKIONLY: $uid is not logged in!", 1);
+	TBERROR("WIKIONLY: user is not logged in!", 1);
     }
 
     return (($CHECKLOGIN_STATUS &
@@ -582,25 +623,23 @@ function ISADMINISTRATOR() {
 #
 # Toggle current login admin bit. Must be an administrator of course!
 #
-function SETADMINMODE($uid, $onoff) {
-    global $HTTP_COOKIE_VARS, $TBAUTHCOOKIE;
+function SETADMINMODE($onoff) {
+    global $CHECKLOGIN_HASHKEY, $CHECKLOGIN_IDX;
     
     # This makes sure the user is actually logged in secure (https).
     if (! ISADMINISTRATOR())
 	return;
 
-    $curhash = $HTTP_COOKIE_VARS[$TBAUTHCOOKIE];
-
-    if (!isset($curhash) ||
-	!preg_match("/^[\w]+$/", $curhash)) {
+    # Be pedantic.
+    if (! ($CHECKLOGIN_HASHKEY && $CHECKLOGIN_IDX))
 	return;
-    }
+
     $onoff   = addslashes($onoff);
-    $curhash = addslashes($curhash);
-    $uid     = addslashes($uid);
+    $curhash = addslashes($CHECKLOGIN_HASHKEY);
+    $uid_idx = $CHECKLOGIN_IDX;
     
     DBQueryFatal("update login set adminon='$onoff' ".
-		 "where uid='$uid' and hashkey='$curhash'");
+		 "where uid_idx='$uid_idx' and hashkey='$curhash'");
 }
 
 # Is this user a planetlab user? Returns 1 if they are, 0 if not.
@@ -615,16 +654,14 @@ function ISPLABUSER() {
 	if (!$uid) {
 	    return 0;
 	}
-	$query_result =
-	    DBQueryFatal("SELECT user_interface FROM users WHERE uid='$uid'");
-	if (!mysql_num_rows($query_result)) {
+	# Lookup sanitizes argument.
+	if (! ($user = User::Lookup($uid)))
 	    return 0;
-	}
 
-	$row = mysql_fetch_row($query_result);
-	if ($row[0]) {
-	    return ($row[0] == TBDB_USER_INTERFACE_PLAB);
-	} else {
+	if ($user->user_interface()) {
+	    return ($user->user_interface() == TBDB_USER_INTERFACE_PLAB);
+	}
+	else {
 	    return 0;
 	}
     } else {
@@ -649,10 +686,10 @@ function ISPLABUSER() {
 #
 function NODETYPE_ALLOWED($type) {
     global $CHECKLOGIN_NODETYPES;
-    $uid = GETUID();
-    if (!$uid) {
+
+    if (! GETUID())
 	return 0;
-    }
+
     if ($CHECKLOGIN_NODETYPES[$type]) {
 	return 1;
     } else {
@@ -702,38 +739,33 @@ function DOLOGIN($token, $password, $adminmode = 0) {
 	}
     }
 
-    $user_result =
-	DBQueryFatal("select uid,usr_pswd,admin,weblogin_frozen,".
-		     "       weblogin_failcount,weblogin_failstamp, ".
-		     "       usr_email,usr_name,unix_uid,usr_email ".
-		     "from users where ".
-		     (TBvalid_email($token) ?
-		      "usr_email='$token'" :
-		      "uid='$token'"));
-
+    if (TBvalid_email($token)) {
+	$user = User::LookupByEmail($token);
+    }
+    else {
+	$user = User::Lookup($token);
+    }
+	    
     #
     # Check password in the database against provided. 
     #
     do {
-      if ($row = mysql_fetch_array($user_result)) {
-	$uid         = $row['uid'];
-        $db_encoding = $row['usr_pswd'];
-	$isadmin     = $row['admin'];
-	$frozen      = $row['weblogin_frozen'];
-	$failcount   = $row['weblogin_failcount'];
-	$failstamp   = $row['weblogin_failstamp'];
-	$usr_email   = $row['usr_email'];
-	$usr_name    = $row['usr_name'];
-	$uid_idx     = $row['unix_uid'];
-	$usr_email   = $row['usr_email'];
+      if ($user) {
+	$uid         = $user->uid();
+        $db_encoding = $user->pswd();
+	$isadmin     = $user->admin();
+	$frozen      = $user->weblogin_frozen();
+	$failcount   = $user->weblogin_failcount();
+	$failstamp   = $user->weblogin_failstamp();
+	$usr_email   = $user->email();
+	$usr_name    = $user->name();
+	$uid_idx     = $user->unix_uid();
+	$usr_email   = $user->email();
 
 	# Check for frozen accounts. We do not update the IP record when
 	# an account is frozen.
 	if ($frozen) {
-	    DBQueryFatal("update users set ".
-			 "       weblogin_failcount=weblogin_failcount+1, ".
-			 "       weblogin_failstamp='$now' ".
-			 "where uid='$uid'");
+	    $user->UpdateWebLoginFail();
 	    return -1;
 	}
 	
@@ -744,8 +776,8 @@ function DOLOGIN($token, $password, $adminmode = 0) {
 	    #
 	    $failcount++;
 	    if ($failcount > DOLOGIN_MAXUSERATTEMPTS) {
-		$frozen = 1;
-	    
+		$user->SetWebFreeze(1);
+		
 		TBMAIL("$usr_name '$uid' <$usr_email>",
 		   "Web Login Freeze: '$uid'",
 		   "Your login has been frozen because there were too many\n".
@@ -756,11 +788,7 @@ function DOLOGIN($token, $password, $adminmode = 0) {
 		   "Bcc: $TBMAIL_AUDIT\n".
 		   "Errors-To: $TBMAIL_WWW");
 	    }
-
-	    DBQueryFatal("update users set weblogin_frozen='$frozen', ".
-			 "       weblogin_failcount='$failcount', ".
-			 "       weblogin_failstamp='$now' ".
-			 "where uid='$uid'");
+	    $user->UpdateWebLoginFail();
             break;
         }
 	#
@@ -782,7 +810,7 @@ function DOLOGIN($token, $password, $adminmode = 0) {
         #
         # Insert a record in the login table for this uid.
 	#
-	if (DOLOGIN_MAGIC($uid, $usr_email, $adminon) < 0) {
+	if (DOLOGIN_MAGIC($uid, $uid_idx, $usr_email, $adminon) < 0) {
 	    return -1;
 	}
 
@@ -807,7 +835,7 @@ function DOLOGIN($token, $password, $adminmode = 0) {
     if (!isset($IP)) {
 	return -1;
     }
-	
+
     $ipfrozen = 0;
     if (isset($iprow)) {
 	$ipfailcount = $iprow['failcount'];
@@ -846,7 +874,7 @@ function DOLOGIN($token, $password, $adminmode = 0) {
     return -1;
 }
 
-function DOLOGIN_MAGIC($uid, $email = null, $adminon = 0)
+function DOLOGIN_MAGIC($uid, $uid_idx, $email = null, $adminon = 0)
 {
     global $TBAUTHCOOKIE, $TBAUTHDOMAIN, $TBAUTHTIMEOUT;
     global $TBNAMECOOKIE, $TBLOGINCOOKIE, $TBSECURECOOKIES, $TBEMAILCOOKIE;
@@ -858,6 +886,9 @@ function DOLOGIN_MAGIC($uid, $email = null, $adminon = 0)
     if (!TBvalid_uid($uid)) {
 	return -1;
     }
+    if (!TBvalid_uididx($uid_idx)) {
+	return -1;
+    }
     $now = time();
 
     #
@@ -869,8 +900,9 @@ function DOLOGIN_MAGIC($uid, $email = null, $adminon = 0)
     $hashkey = GENHASH();
     $crc     = bin2hex(mhash(MHASH_CRC32, $hashkey));
 
-    DBQueryFatal("replace into login (uid,hashkey,hashhash,timeout,adminon) ".
-		 "values ('$uid', '$hashkey', '$crc', '$timeout', $adminon)");
+    DBQueryFatal("replace into login ".
+		 "  (uid,uid_idx,hashkey,hashhash,timeout,adminon) values ".
+		 "  ('$uid', $uid_idx, '$hashkey', '$crc', '$timeout', $adminon)");
 
     #
     # Issue the cookie requests so that subsequent pages come back
@@ -900,7 +932,7 @@ function DOLOGIN_MAGIC($uid, $email = null, $adminon = 0)
     # NOTE: This cookie is integral to authorization, since we do not pass
     # around the UID anymore, but look for it in the cookie.
     #
-    setcookie($TBNAMECOOKIE, $uid, 0, "/", $TBAUTHDOMAIN, 0);
+    setcookie($TBNAMECOOKIE, $uid_idx, 0, "/", $TBAUTHDOMAIN, 0);
 
     #
     # This is a long term cookie so we can remember who the user was, and
@@ -934,7 +966,7 @@ function DOLOGIN_MAGIC($uid, $email = null, $adminon = 0)
 	
     DBQueryFatal("update users set ".
 		 "       weblogin_failcount=0,weblogin_failstamp=0 ".
-		 "where uid='$uid'");
+		 "where uid_idx='$uid_idx'");
 
     return 0;
 }
@@ -943,24 +975,19 @@ function DOLOGIN_MAGIC($uid, $email = null, $adminon = 0)
 # Verify a password
 # 
 function VERIFYPASSWD($uid, $password) {
-    if (! isset($password) ||
-	strcmp($password, "") == 0) {
+    if (! isset($password) || $password == "") {
 	return -1;
     }
 
-    $query_result =
-	DBQueryFatal("SELECT usr_pswd FROM users WHERE uid='$uid'");
+    if (! ($user = User::Lookup($uid)))
+	return -1;
 
     #
     # Check password in the database against provided. 
     #
-    if ($row = mysql_fetch_row($query_result)) {
-        $db_encoding = $row[0];
-        $encoding = crypt("$password", $db_encoding);
+    $encoding = crypt("$password", $user->pswd());
 	
-        if (strcmp($encoding, $db_encoding)) {
-            return -1;
-	}
+    if ($encoding == $user->pswd()) {
 	return 0;
     }
     return -1;
@@ -969,15 +996,25 @@ function VERIFYPASSWD($uid, $password) {
 #
 # Log out a UID.
 #
-function DOLOGOUT($uid) {
-    global $CHECKLOGIN_STATUS, $TBAUTHCOOKIE, $TBLOGINCOOKIE, $TBAUTHDOMAIN;
+function DOLOGOUT($user) {
+    global $CHECKLOGIN_STATUS, $CHECKLOGIN_USER;
+    global $TBAUTHCOOKIE, $TBLOGINCOOKIE, $TBAUTHDOMAIN;
     global $WIKISUPPORT, $WIKICOOKIENAME, $HTTP_COOKIE_VARS;
     global $BUGDBSUPPORT, $BUGDBCOOKIENAME;
 
-    # Pedantic check.
-    if (!TBvalid_uid($uid)) {
+    if (! $CHECKLOGIN_USER)
 	return 1;
+
+    $uid_idx = $user->uid_idx();
+
+    #
+    # An admin logging out another user. Nothing else to do.
+    #
+    if (! $user->SameUser($CHECKLOGIN_USER)) {
+	DBQueryFatal("delete from login where uid_idx='$uid_idx'");
+	return 0;
     }
+
     $CHECKLOGIN_STATUS = CHECKLOGIN_NOTLOGGEDIN;
 
     $curhash = $HTTP_COOKIE_VARS[$TBAUTHCOOKIE];
@@ -1001,7 +1038,7 @@ function DOLOGOUT($uid) {
     $safe_hashhash = addslashes($hashhash);
 
     DBQueryFatal("delete from login ".
-		 " where uid='$uid' and ".
+		 " where uid_idx='$uid_idx' and ".
 		 (isset($curhash) ?
 		  "hashkey='$safe_curhash'" :
 		  "hashhash='$safe_hashhash'"));
@@ -1039,7 +1076,7 @@ function LASTWEBLOGIN($uid) {
 
     $query_result =
         DBQueryFatal("select weblogin_last from users as u ".
-		     "left join user_stats as s on s.uid_idx=u.unix_uid ".
+		     "left join user_stats as s on s.uid_idx=u.uid_idx ".
 		     "where u.uid='$uid'");
     
     if (mysql_num_rows($query_result)) {
@@ -1050,17 +1087,12 @@ function LASTWEBLOGIN($uid) {
 }
 
 function HASREALACCOUNT($uid) {
-    $query_result =
-	DBQueryFatal("select status,webonly,wikionly from users ".
-		     "where uid='$uid'");
-
-    if (!mysql_num_rows($query_result)) {
+    if (! ($user = User::Lookup($uid)))
 	return 0;
-    }
-    $row = mysql_fetch_array($query_result);
-    $status   = $row[0];
-    $webonly  = $row[1];
-    $wikionly = $row[2];
+
+    $status   = $user->status();
+    $webonly  = $user->webonly();
+    $wikionly = $user->wikionly();
 
     if ($webonly || $wikionly ||
 	(strcmp($status, TBDB_USERSTATUS_ACTIVE) &&
diff --git a/www/telemetry.php3 b/www/telemetry.php3
index 0d0e9f18b3b31a881313f419a78c8fce5a35a58d..26eb2624b86e10cccf6cd74f0834a9a829ad828c 100644
--- a/www/telemetry.php3
+++ b/www/telemetry.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2005 University of Utah and the Flux Group.
+# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 
@@ -11,8 +11,9 @@ include("showstuff.php3");
 #
 # Make sure they are logged in
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/template_analyze.php b/www/template_analyze.php
index cb6dd811005574332eb814c96daedc95fd529774..570a7f05a20e97c5358b8e38387372769926e875 100644
--- a/www/template_analyze.php
+++ b/www/template_analyze.php
@@ -8,10 +8,11 @@ include("defs.php3");
 include_once("template_defs.php");
 
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/template_commit.php b/www/template_commit.php
index 250651d2d15155380d78326c2b9ef23ab5971393..d7842686d9218705e6b828b443bd46680cd0fb2a 100644
--- a/www/template_commit.php
+++ b/www/template_commit.php
@@ -8,10 +8,11 @@ include("defs.php3");
 include_once("template_defs.php");
 
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/template_create.php b/www/template_create.php
index 3460b504cc1b651284f96213967f4ebb5eae9fcb..9c97874744b81a16721a72496bcc5d70082d7711 100644
--- a/www/template_create.php
+++ b/www/template_create.php
@@ -14,9 +14,9 @@ include_once("template_defs.php");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Spit the form out using the array of data.
@@ -225,7 +225,7 @@ function SPITFORM($formfields, $errors)
 #
 # See what projects the uid can create experiments in. Must be at least one.
 #
-$projlist = TBProjList($uid, $TB_PROJECT_CREATEEXPT);
+$projlist = $this_user->ProjectAccessList($TB_PROJECT_CREATEEXPT);
 
 if (! count($projlist)) {
     USERERROR("You do not appear to be a member of any Projects in which ".
diff --git a/www/template_defs.php b/www/template_defs.php
index 6f3f5726a387442061a45a0a8c542a11d832337c..4d399bf1df8e876383896488a01a4c235d74b587 100644
--- a/www/template_defs.php
+++ b/www/template_defs.php
@@ -220,6 +220,11 @@ class Template
 	$description = $this->description();
 	$path        = $this->path();
 
+	if (! ($user = User::Lookup($uid))) {
+	    TBERROR("Could not lookup object for user $uid", 1);
+	}
+	$showuser_url = CreateURL("showuser", $user);
+	
         #
         # We need the metadata guid/version for the TID and description since
         # they are mungable metadata.
@@ -259,7 +264,7 @@ class Template
 	
 	ShowItem("Project", MakeLink("project", "pid=$pid", $pid));
 	ShowItem("Group",   $gid);
-	ShowItem("Creator", MakeLink("user", "target_uid=$uid", $uid));
+	ShowItem("Creator", MakeAnchor($showuser_url, $uid));
 	ShowItem("Created", $created);
 
 	echo "<tr><td align=center colspan=2>Datastore Directory</td></tr>\n";
@@ -1090,6 +1095,11 @@ class TemplateInstance
 	$template= $this->template();
 	$pcount  = $template->ParameterCount();
 
+	if (! ($user = User::Lookup($uid))) {
+	    TBERROR("Could not lookup object for user $uid", 1);
+	}
+	$showuser_url = CreateURL("showuser", $user);
+	
 	if ($detailed && $pcount) {
 	    echo "<table border=0 bgcolor=#000 color=#000 class=stealth ".
 		 " cellpadding=0 cellspacing=0 align=center>\n";
@@ -1107,7 +1117,7 @@ class TemplateInstance
 			  "guid=$guid&version=$vers", "$guid/$vers"));
 	ShowItem("ID",          $exptidx);
 	ShowItem("Project",     MakeLink("project", "pid=$pid", $pid));
-	ShowItem("Creator",     MakeLink("user", "target_uid=$uid", $uid));
+	ShowItem("Creator",     MakeAnchor($url, $uid));
 	ShowItem("Started",     $start);
 	ShowItem("Stopped",     (isset($stop) ? $stop : "&nbsp"));
 	ShowItem("Current Run", (isset($runidx) ? $runidx : "&nbsp"));
@@ -1938,6 +1948,14 @@ function MakeLink($which, $args, $text)
     return "<a href=${page}?${args}>$text</a>";
 }
 
+#
+# New version of above function, will replace it eventually.
+#
+function MakeAnchor($url, $text)
+{
+    return "<a href='${url}'>$text</a>";
+}
+
 #
 # Display a list of templates in its own table. Optional 
 #
diff --git a/www/template_editevents.php b/www/template_editevents.php
index e7714c7868ef1065aa6859c229f595df7bf5dc71..fca404864927c4ce9f2d75bdd89f2acfabc9a4c0 100644
--- a/www/template_editevents.php
+++ b/www/template_editevents.php
@@ -10,9 +10,9 @@ include_once("template_defs.php");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Spit the form out using the array of data.
diff --git a/www/template_export.php b/www/template_export.php
index 2f62d2a24da4858d533a69ca8d063d34afda8c09..43c8851f34583b23b36376e87caf1c37d4a4f75e 100644
--- a/www/template_export.php
+++ b/www/template_export.php
@@ -8,10 +8,11 @@ include("defs.php3");
 include_once("template_defs.php");
 
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/template_exprun.php b/www/template_exprun.php
index 407b4e4c72c11ca63e9b2201c5e54f1afccbd4cf..c7851b32588777c97942d75ee80c0564d06047d6 100644
--- a/www/template_exprun.php
+++ b/www/template_exprun.php
@@ -14,9 +14,9 @@ include_once("template_defs.php");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 # This will not return if its a sajax request.
 include("showlogfile_sup.php3");
diff --git a/www/template_history.php b/www/template_history.php
index d2142238dd500831261620419be04c23b0c09801..aa712ab8ece7ad9aabf685eb75d564c0ec2ad092 100644
--- a/www/template_history.php
+++ b/www/template_history.php
@@ -10,9 +10,9 @@ include_once("template_defs.php");
 #
 # Only known and logged in users can look at experiments.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/template_metadata.php b/www/template_metadata.php
index 84085602bf1edf40369c39ef3d65eddb6cd60577..d41b190ba36cdeb5ea63ac9dd20f06d1870175e6 100644
--- a/www/template_metadata.php
+++ b/www/template_metadata.php
@@ -14,9 +14,9 @@ include_once("template_defs.php");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin  = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Spit the form out using the array of data.
diff --git a/www/template_modify.php b/www/template_modify.php
index 0897428a40f56c7743bb8a44bd372941ed56dae3..bf8068f6baa3cfb36ac9a4e4200516a4ef69b5e0 100644
--- a/www/template_modify.php
+++ b/www/template_modify.php
@@ -10,10 +10,9 @@ include_once("template_defs.php");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
-
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Spit the form out using the array of data.
diff --git a/www/template_show.php b/www/template_show.php
index 2e56ddfd097be211fcfed6bca720435d6ca07419..09cb96e7b6a2d9d891cc1ac441fb96076f745f4c 100644
--- a/www/template_show.php
+++ b/www/template_show.php
@@ -13,9 +13,9 @@ sajax_export("Show", "GraphChange");
 #
 # Only known and logged in users ...
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 # Need these below, set in CheckArguments.
 $pid = "";
@@ -307,7 +307,7 @@ if (isset($action) && $action == "deletetemplate" &&
     # Okay, lets zap back to the root, unless this was the root.
     #
     if ($template->IsRoot()) {
-	PAGEREPLACE("showuser.php3?target_uid=$uid");
+	PAGEREPLACE(CreateURL("showuser", $this_user));
     }
     else {
 	PAGEREPLACE("template_show.php?guid=$guid&version=1");
diff --git a/www/template_swapin.php b/www/template_swapin.php
index 2b914a80aa36cc8e1eafecc8eb06e93491af5ea5..99dbaa60740bbbc891541fa6c961ba0ac19bd66b 100644
--- a/www/template_swapin.php
+++ b/www/template_swapin.php
@@ -14,9 +14,9 @@ include_once("template_defs.php");
 #
 # Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 # This will not return if its a sajax request.
 include("showlogfile_sup.php3");
@@ -465,7 +465,7 @@ if (!isset($formfields[exp_swappable]) ||
     if (!isset($formfields[exp_noswap_reason]) ||
         !strcmp($formfields[exp_noswap_reason], "")) {
 
-        if (! ISADMIN($uid)) {
+        if (! $isadmin) {
 	    $errors["Not Swappable"] = "No justification provided";
         }
 	else {
@@ -495,7 +495,7 @@ if (!isset($formfields[exp_idleswap]) ||
 
     if (!isset($formfields[exp_noidleswap_reason]) ||
 	!strcmp($formfields[exp_noidleswap_reason], "")) {
-	if (! ISADMIN($uid)) {
+	if (! $isadmin) {
 	    $errors["Not Idle-Swappable"] = "No justification provided";
 	}
 	else {
diff --git a/www/toggle.php b/www/toggle.php
index 2d9a3ade59351c3528d134d46fcc0c15502418ec..476700fef575b764a07bb12791173b8c102bf709 100644
--- a/www/toggle.php
+++ b/www/toggle.php
@@ -18,9 +18,9 @@ include("defs.php3");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid, CHECKLOGIN_USERSTATUS|CHECKLOGIN_WEBONLY);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie(CHECKLOGIN_USERSTATUS|CHECKLOGIN_WEBONLY);
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 # List of valid toggles
 $toggles = array("adminon", "webfreeze", "cvsweb", "lockdown",
@@ -35,8 +35,8 @@ $values  = array("adminon"        => array(0,1),
 
 # list of valid extra variables for the each toggle, and mandatory flag.
 $optargs = array("adminon"        => array(),
-		 "webfreeze"      => array("target_uid" => 1),
-		 "cvsweb"         => array("target_uid" => 1),
+		 "webfreeze"      => array("user" => 1),
+		 "cvsweb"         => array("user" => 1),
 		 "lockdown"       => array("pid" => 1, "eid" => 1),
 		 "cvsrepo_public" => array("pid" => 1));
 
@@ -79,29 +79,27 @@ if ($type == "adminon") {
     if (! ($CHECKLOGIN_STATUS & CHECKLOGIN_ISADMIN) ) {
 	USERERROR("You do not have permission to toggle $type!", 1);
     }
-    SETADMINMODE($uid, $value);
+    SETADMINMODE($value);
 }
 elseif ($type == "webfreeze") {
     # must be admin
     if (! $isadmin) {
 	USERERROR("You do not have permission to toggle $type!", 1);
     }
-    if (!TBCurrentUser($target_uid)) {
-	PAGEARGERROR("Target user '$target_uid' is not a valid user!");
+    if (! ($target_user = User::Lookup($user))) {
+	PAGEARGERROR("Target user '$user' is not a valid user!");
     }
-    DBQueryFatal("update users set weblogin_frozen='$value' ".
-		 "where uid='$target_uid'");
+    $target_user->SetWebFreeze($value);
 }
 elseif ($type == "cvsweb") {
     # must be admin
     if (! $isadmin) {
 	USERERROR("You do not have permission to toggle $type!", 1);
     }
-    if (!TBCurrentUser($target_uid)) {
-	PAGEARGERROR("Target user '$target_uid' is not a valid user!");
+    if (! ($target_user = User::Lookup($user))) {
+	PAGEARGERROR("Target user '$user' is not a valid user!");
     }
-    DBQueryFatal("update users set cvsweb='$value' ".
-		 "where uid='$target_uid'");
+    $target_user->SetCVSWeb($value);
 }
 elseif ($type == "lockdown") {
     # must be admin
@@ -140,12 +138,12 @@ else {
 #
 if (isset($HTTP_REFERER) && $HTTP_REFERER != "" &&
     strpos($HTTP_REFERER,$_SERVER[SCRIPT_NAME])===false) {
-    # Make sure the referer isn't me!
+    # Make sure the referer is not me!
     header("Location: $HTTP_REFERER");
 }
 else {
-    if (isset($target_uid)) {
-	header("Location: $TBBASE/showuser.php3?target_uid=$target_uid");
+    if (isset($user)) {
+	header("Location: " . CreateURL("showuser", $target_user));
     } elseif (isset($pid) && isset($eid)) {
 	header("Location: $TBBASE/showexp.php3?pid=$pid&eid=$eid");
     } else {
diff --git a/www/top2image.php3 b/www/top2image.php3
index 4c650664e19c80bc5122cec37ef81c0770cc9de2..8a9088f8c403998a5557c0212ba447ef1e16d200 100644
--- a/www/top2image.php3
+++ b/www/top2image.php3
@@ -12,10 +12,11 @@ include("defs.php3");
 #
 
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
diff --git a/www/updateaccounts.php3 b/www/updateaccounts.php3
index 125d7711e23d19bd9c38375a49489d4b7da7d8a6..9ae482ace2b0d2fbc0055112eb9b96d3fbaf98e8 100644
--- a/www/updateaccounts.php3
+++ b/www/updateaccounts.php3
@@ -1,17 +1,18 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
 include("showstuff.php3");
 
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Must provide the EID!
diff --git a/www/url_defs.php b/www/url_defs.php
new file mode 100644
index 0000000000000000000000000000000000000000..53a7ff853668d3ec8b4f91de677ab3be1ffe8222
--- /dev/null
+++ b/www/url_defs.php
@@ -0,0 +1,164 @@
+<?php
+#
+# EMULAB-COPYRIGHT
+# Copyright (c) 2006 University of Utah and the Flux Group.
+# All rights reserved.
+#
+
+#
+# This is my attempt at factoring our the zillions of URL addresses and
+# their arguments. This will hopefully make it easier to change how we
+# address things, like when I change the uid,pid,gid arguments to numeric
+# IDs instead of names.
+#
+define("URLARG_UID",	"__uid");
+define("URLARG_PID",	"__pid");
+define("URLARG_GID",	"__gid");
+define("URLARG_EID",	"__eid");
+
+#
+# Map page "ids" to the actual script names.
+#
+$url_mapping				= array();
+$url_mapping["showuser"]		= "showuser.php3";
+$url_mapping["deleteuser"]		= "deleteuser.php3";
+$url_mapping["showpubkeys"]		= "showpubkeys.php3";
+$url_mapping["deletepubkey"]		= "deletepubkey.php3";
+$url_mapping["showsfskeys"]		= "showsyskeys.php3";
+$url_mapping["deletesfskey"]		= "deletesfskey.php3";
+$url_mapping["moduserinfo"]   		= "moduserinfo.php3";
+$url_mapping["showproject"]		= "showproject.php3";
+$url_mapping["showgroup"]		= "showgroup.php3";
+$url_mapping["suuser"]			= "suuser.php";
+$url_mapping["approveproject_form"]	= "approveproject_form.php3";
+$url_mapping["showpubkeys"]		= "showpubkeys.php3";
+$url_mapping["toggle"]			= "toggle.php";
+$url_mapping["logout"]			= "logout.php3";
+$url_mapping["listrepos"]		= "listrepos.php3";
+$url_mapping["mychat"]			= "mychat.php3";
+$url_mapping["showmmlists"]		= "showmmlists.php3";
+$url_mapping["getsslcert"]		= "getsslcert.php3";
+$url_mapping["gensslcert"]		= "gensslcert.php3";
+$url_mapping["showstats"]		= "showstats.php3";
+$url_mapping["freezeuser"]		= "freezeuser.php3";
+$url_mapping["changeuid"]		= "changeuid.php";
+$url_mapping["resendkey"]		= "resendkey.php3";
+$url_mapping["sendtestmsg"]		= "sendtestmsg.php3";
+	     
+#
+# The caller will pass in a page id, and a list of things. If the thing
+# is a class we know about, then we generate the argument directly from
+# it. For example, if the argument is a User instance, we know to append
+# "user=$user->uid()" cause all pages that take uid arguments use
+# the same protocol.
+#
+# If the thing is not something we know about, then its a key/value pair,
+# with the next argument being the value.
+# The key (say, "uid") is the kind of argument to be added to the URL,
+# and the value (a string or an user class instance) is where we get
+# the argument from. To be consistent across all pages, something like "uid"
+# is mapped to "?user=$value" rather then "uid".
+#
+# Note that this idea comes from a google search for ways to deal with
+# this problem. Nothing fancy.
+#
+function CreateURL($page_id)
+{
+    global $url_mapping;
+    
+    $pageargs = func_get_args();
+    # drop the required argument.
+    array_shift($pageargs);
+
+    if (! array_key_exists($page_id, $url_mapping)) {
+	TBERROR("CreateURL: Could not map $page_id to a page", 1);
+	return null;
+    }
+
+    $newurl = $url_mapping[$page_id];
+
+    # No args?
+    if (! count($pageargs)) {
+	return $newurl;
+    }
+
+    # Form an array of arguments to append.
+    $url_args = array();
+
+    while ($pageargs and count($pageargs)) {
+	$key = array_shift($pageargs);
+
+	#
+	# Do we know about the object itself.
+	#
+	if (gettype($key) == "object") {
+	    #
+	    # Make up the key/value pair for below.
+	    #
+	    $val = $key;
+	    
+	    switch (get_class($key)) {
+	    case "user":
+		$key = URLARG_UID;
+		break;
+	    case "project":
+		$key = URLARG_PID;
+		break;
+	    case "group":
+		$key = URLARG_GID;
+		break;
+	    case "experiment":
+		$key = URLARG_EID;
+		break;
+	    default:
+		TBERROR("CreateURL: ".
+			"Unknown object class - " . get_class($key), 1);
+	    }
+	}
+	elseif (count($pageargs)) {
+	    #
+	    # A key/value pair so get the value from next argument.
+	    #
+	    $val = array_shift($pageargs);
+	}
+	else {
+	    TBERROR("CreateURL: Malformed arguments for $key", 1);
+	}
+
+	#
+	# Now process the key/value.
+	#
+	switch ($key) {
+	case URLARG_UID:
+	    $key = "user";
+	    if (is_a($val, 'User')) {
+		$val = $val->webid();
+	    }
+	    break;
+	case URLARG_PID:
+	    $key = "pid";
+	    if (is_a($val, 'Project')) {
+		$val = $val->pid();
+	    }
+	    break;
+	case URLARG_GID:
+	    $key = "gid";
+	    if (is_a($val, 'Group')) {
+		$val = $val->gid();
+	    }
+	    break;
+	case URLARG_EID:
+	    $key = "eid";
+	    if (is_a($val, 'Experiment')) {
+		$val = $val->eid();
+	    }
+	    break;
+	default:
+            # Use whatever it was we got.
+	    ;
+	}
+	$url_args[] = "${key}=${val}";
+    }
+    $newurl .= "?" . implode("&", $url_args);
+    return $newurl;
+}
diff --git a/www/user_defs.php b/www/user_defs.php
index 08de42447991044301ad3165a40b913d249720e3..5c3898d32c1ace31c2732a3a420265328db8495a 100644
--- a/www/user_defs.php
+++ b/www/user_defs.php
@@ -4,14 +4,30 @@
 # Copyright (c) 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
+
+#
+# A cache of users to avoid lookups. Indexed by uid_idx.
+#
+$user_cache = array();
+
 class User
 {
     var	$user;
 
+    #
+    # For pedantic checks early in pages.
+    #
+    function ValidWebID($token) {
+	if (! preg_match("/^[-\w]+$/", $token)) {
+	    return 0;
+	}
+	return 1;
+    }
+
     #
     # Constructor by lookup on unique index.
     #
-    function User($uid_idx) {
+    function &User($uid_idx) {
 	$safe_uid_idx = addslashes($uid_idx);
 
 	$query_result =
@@ -21,7 +37,7 @@ class User
 	    $this->user = NULL;
 	    return;
 	}
-	$this->user = mysql_fetch_array($query_result);
+	$this->user =& mysql_fetch_array($query_result);
     }
 
     # Hmm, how does one cause an error in a php constructor?
@@ -30,16 +46,32 @@ class User
     }
 
     # Lookup by uid_idx.
-    function Lookup($uid_idx) {
-	$foo = new User($uid_idx);
+    function &Lookup($uid_idx) {
+	global $user_cache;
+
+        # Look in cache first
+	if (array_key_exists("$uid_idx", $user_cache))
+	    return $user_cache["$uid_idx"];
 
-	if ($foo->IsValid())
+	$foo =& new User($uid_idx);
+
+	if (! $foo->IsValid()) {
+	    # Try lookup by plain uid.
+	    $foo =& User::LookupByUid($uid_idx);
+	    
+	    if (! $foo->IsValid())
+		return null;
+	    
+	    # Already in the cache from LookupByUid() so just return it.
 	    return $foo;
-	return null;
+	}
+	# Insert into cache.
+	$user_cache["$uid_idx"] =& $foo;
+	return $foo;
     }
 
     # Backwards compatable lookup by uid. Will eventually flush this.
-    function LookupByUid($uid) {
+    function &LookupByUid($uid) {
 	$safe_uid = addslashes($uid);
 
 	$query_result =
@@ -51,12 +83,43 @@ class User
 	$row = mysql_fetch_array($query_result);
 	$idx = $row['uid_idx'];
 
-	$foo = new User($idx); 
+	return User::Lookup($idx);
+    }
 
-	if ($foo->IsValid())
-	    return $foo;
-	
-	return null;
+    # Used in the change password code and to make sure that emails are
+    # locally unique.
+    function &LookupByEmail($email) {
+	$safe_email = addslashes($email);
+
+	$query_result =
+	    DBQueryWarn("select uid_idx from users ".
+			"where LCASE(usr_email)=LCASE('$safe_email')");
+
+	if (!$query_result || !mysql_num_rows($query_result)) {
+	    return null;
+	}
+	$row = mysql_fetch_array($query_result);
+	$idx = $row['uid_idx'];
+
+	return User::Lookup($idx);
+    }
+    
+    # Used in new/join project code to make sure that wikinames are
+    # locally unique.
+    function &LookupByWikiName($wikiname) {
+	$safe_wikiname = addslashes($wikiname);
+
+	$query_result =
+	    DBQueryWarn("select uid_idx from users ".
+			"where wikiname='$safe_wikiname')");
+
+	if (!$query_result || !mysql_num_rows($query_result)) {
+	    return null;
+	}
+	$row = mysql_fetch_array($query_result);
+	$idx = $row['uid_idx'];
+
+	return User::Lookup($idx);
     }
     
     #
@@ -75,16 +138,32 @@ class User
 	    $this->user = NULL;
 	    return -1;
 	}
-	$this->user = mysql_fetch_array($query_result);
+	$this->user =& mysql_fetch_array($query_result);
 	return 0;
     }
 
+    #
+    # Equality test.
+    #
+    function SameUser($user) {
+	return $user->uid_idx() == $this->uid_idx();
+    }
+
+    #
+    # At some point we will stop passing uid and start using uid_idx.
+    # Use this function to avoid having to change a bunch of code twice.
+    #
+    function URLParam() {
+	return $this->uid();
+    }
+
     # accessors
     function field($name) {
 	return (is_null($this->user) ? -1 : $this->user[$name]);
     }
     function uid_idx()		{ return $this->field("uid_idx"); }
     function uid()		{ return $this->field("uid"); }
+    function webid()		{ return $this->field("uid_idx"); }
     function created()		{ return $this->field("usr_created"); }
     function expires()		{ return $this->field("usr_expires"); }
     function modified()		{ return $this->field("usr_modified"); }
@@ -133,10 +212,14 @@ class User
     #
     # Class function to create new user and return object.
     #
-    function NewUser($uid, $isleader, $wikionly, $args) {
+    function NewUser($uid, $flags, $args) {
 	global $TBBASE, $TBMAIL_APPROVAL, $TBMAIL_AUDIT, $TBMAIL_WWW;
 	global $MIN_UNIX_UID;
 
+	$isleader = ($flags & TBDB_NEWACCOUNT_PROJLEADER ? 1 : 0);
+	$wikionly = ($flags & TBDB_NEWACCOUNT_WIKIONLY   ? 1 : 0);
+	$webonly  = ($flags & TBDB_NEWACCOUNT_WEBONLY    ? 1 : 0);
+
 	#
 	# If no uid, we need to generate a unique one for the user.
 	#
@@ -245,7 +328,11 @@ class User
 	$verify_key = md5(uniqid(rand(),1));
 
 	# Now tack on other stuff we need.
-	$insert_data[] = "wikionly='$wikionly'";
+	if ($wikionly)
+	    $insert_data[] = "wikionly='1'";
+	if ($webonly)
+	    $insert_data[] = "webonly='1'";
+	
 	$insert_data[] = "usr_created=now()";
 	$insert_data[] = "usr_modified=now()";
 	$insert_data[] = "pswd_expires=date_add(now(), interval 1 year)";
@@ -297,6 +384,10 @@ class User
 	"Once you have verified your account, you will be able to access\n".
 	"the Wiki. You MUST verify your account first!"
 	:
+	($webonly ?
+	 "Once you have verified your account, Testbed Operations will be\n".
+	 "able to approve you. You MUST verify your account first!"
+	 :
 	($isleader ?
 	 "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".
@@ -308,7 +399,7 @@ class User
 	 "You MUST verify your account before the project leader can ".
 	 "approve you\n".
 	 "After project approval, you will be marked as an active user, and\n".
-	 "will be granted full access to your user account.")) .
+	 "will be granted full access to your user account."))) .
        "\n\n".
        "Thanks,\n".
        "Testbed Operations\n",
@@ -319,6 +410,22 @@ class User
 	return $newuser;
     }
 
+    #
+    # Delete a user, but JUST from the users table. 
+    #
+    function Delete() {
+	global $user_cache;
+
+	$uid_idx = $this->uid_idx();
+
+	DBQueryFatal("delete from users where uid_idx='$uid_idx'");
+
+	if (array_key_exists("$uid_idx", $user_cache))
+	    unset($user_cache["$uid_idx"]);
+	
+	return 0;
+    }
+
     #
     # Stats
     #
@@ -345,4 +452,612 @@ class User
 	$html .= "</table>\n";
 	return $html;
     }
+
+    function Show() {
+	global $WIKISUPPORT;
+
+	$user = $this;
+
+	$uid         = $user->uid();
+	$webid       = $user->webid();
+	$uid_idx     = $user->uid_idx();
+	$usr_email   = $user->email();
+	$usr_URL     = $user->URL();
+	$usr_addr    = $user->addr();
+	$usr_addr2   = $user->addr2();
+	$usr_city    = $user->city();
+	$usr_state   = $user->state();
+	$usr_zip     = $user->zip();
+	$usr_country = $user->country();
+	$usr_name    = $user->name();
+	$usr_phone   = $user->phone();
+	$usr_shell   = $user->shell();
+	$usr_title   = $user->title();
+	$usr_affil   = $user->affil();
+	$status      = $user->status();
+	$admin       = $user->admin();
+	$notes       = $user->notes();
+	$frozen      = $user->weblogin_frozen();
+	$failcount   = $user->weblogin_failcount();
+	$failstamp   = $user->weblogin_failstamp();
+	$wikiname    = $user->wikiname();
+	$cvsweb      = $user->cvsweb();
+	$wikionly    = $user->wikionly();
+
+	if (!strcmp($usr_addr2, ""))
+	    $usr_addr2 = "&nbsp;";
+	if (!strcmp($usr_city, ""))
+	    $usr_city = "&nbsp;";
+	if (!strcmp($usr_state, ""))
+	    $usr_state = "&nbsp;";
+	if (!strcmp($usr_zip, ""))
+	    $usr_zip = "&nbsp;";
+	if (!strcmp($usr_country, ""))
+	    $usr_country = "&nbsp;";
+	if (!strcmp($notes, ""))
+	    $notes = "&nbsp;";
+
+        #
+        # Last Login info.
+        #
+	if (($lastweblogin = LASTWEBLOGIN($uid)) == 0)
+	    $lastweblogin = "&nbsp;";
+	if (($lastuserslogininfo = TBUsersLastLogin($uid)) == 0)
+	    $lastuserslogin = "N/A";
+	else {
+	    $lastuserslogin = $lastuserslogininfo["date"] . " " .
+		$lastuserslogininfo["time"];
+	}
+    
+	if (($lastnodelogininfo = TBUidNodeLastLogin($uid)) == 0)
+	    $lastnodelogin = "N/A";
+	else {
+	    $lastnodelogin = $lastnodelogininfo["date"] . " " .
+		$lastnodelogininfo["time"] . " " .
+		"(" . $lastnodelogininfo["node_id"] . ")";
+	}
+    
+	echo "<table align=center border=1>\n";
+    
+	echo "<tr>
+                  <td>Username:</td>
+                  <td>$uid ($uid_idx)</td>
+              </tr>\n";
+    
+        echo "<tr>
+                  <td>Full Name:</td>
+                  <td>$usr_name</td>
+              </tr>\n";
+    
+        echo "<tr>
+                  <td>Email Address:</td>
+                  <td>$usr_email</td>
+              </tr>\n";
+
+        echo "<tr>
+                  <td>Home Page URL:</td>
+                  <td><a href='$usr_URL'>$usr_URL</a></td>
+              </tr>\n";
+
+	if ($WIKISUPPORT && isset($wikiname)) {
+	    $wikiurl = "gotowiki.php3?redurl=Main/$wikiname";
+	
+	    echo "<tr>
+                      <td>Emulab Wiki Page:</td>
+                      <td class=\"left\">
+                          <a href='$wikiurl'>$wikiname</a></td>
+                  </tr>\n";
+	}
+    
+	echo "<tr>
+                  <td>Address 1:</td>
+                  <td>$usr_addr</td>
+             </tr>\n";
+    
+        echo "<tr>
+                  <td>Address 2:</td>
+                  <td>$usr_addr2</td>
+              </tr>\n";
+    
+        echo "<tr>
+                  <td>City:</td>
+                  <td>$usr_city</td>
+              </tr>\n";
+    
+	echo "<tr>
+                  <td>State:</td>
+                  <td>$usr_state</td>
+              </tr>\n";
+    
+        echo "<tr>
+                  <td>ZIP:</td>
+                  <td>$usr_zip</td>
+              </tr>\n";
+
+        echo "<tr>
+                  <td>Country:</td>
+                  <td>$usr_country</td>
+              </tr>\n";
+    
+        echo "<tr>
+                  <td>Phone #:</td>
+                  <td>$usr_phone</td>
+              </tr>\n";
+
+	echo "<tr>
+	          <td>Shell:</td>
+	          <td>$usr_shell</td>
+              </tr>\n";
+    
+        echo "<tr>
+                  <td>Title/Position:</td>
+                  <td>$usr_title</td>
+             </tr>\n";
+    
+	echo "<tr>
+                  <td>Institutional Affiliation:</td>
+                  <td>$usr_affil</td>
+              </tr>\n";
+    
+        echo "<tr>
+                  <td>Status:</td>
+                  <td>$status</td>
+              </tr>\n";
+
+	if ($wikionly) {
+	    echo "<tr>
+                      <td><b>Wikionly</b>:</td>
+                      <td>Yes</td>
+                  </tr>\n";
+	}
+
+	if ($admin) {
+	    echo "<tr>
+                      <td>Administrator:</td>
+                      <td>Yes</td>
+                  </tr>\n";
+	}
+    
+	echo "<tr>
+                  <td>Last Web Login:</td>
+                  <td>$lastweblogin</td>
+              </tr>\n";
+    
+	echo "<tr>
+                  <td>Last Users Login:</td>
+                  <td>$lastuserslogin</td>
+              </tr>\n";
+    
+        echo "<tr>
+                  <td>Last Node Login:</td>
+                  <td>$lastnodelogin</td>
+              </tr>\n";
+
+	if (ISADMIN()) {
+	    $cvswebflip = ($cvsweb ? 0 : 1);
+
+	    $toggle_url = CreateURL("toggle", $user,
+				    "type", "cvsweb", "value", $cvswebflip);
+
+	    echo "<tr>
+                      <td>CVSWeb Access:</td>
+                      <td>$cvsweb (<a href='$toggle_url'>Toggle</a>)
+                  </tr>\n";
+	
+	    $freezeflip = ($frozen ? 0 : 1);
+	    $toggle_url = CreateURL("toggle", $user,
+				    "type", "webfreeze", "value", $freezeflip);
+
+	    echo "<tr>
+                      <td>Web Freeze:</td>
+                      <td>$frozen (<a href='$toggle_url'>Toggle</a>)
+                  </tr>\n";
+	
+	    if ($frozen && $failstamp && $failcount) {
+		$when = strftime("20%y-%m-%d %H:%M:%S", $failstamp);
+	    
+		echo "<tr>
+                          <td>Login Failures:</td>
+                          <td>$failcount ($when)</td>
+                      </tr>\n";
+	    }
+	    echo "<tr>
+                      <td>Notes:</td>
+                      <td>$notes</td>
+                  </tr>\n";
+	}
+	echo "</table>\n";
+    }
+
+    #
+    # Access Check, determines if $user can access $this record.
+    #
+    #	returns 0 if not allowed.
+    #   returns 1 if allowed.
+    # 
+    function AccessCheck($user, $access_type) {
+	global $TB_USERINFO_READINFO;
+	global $TB_USERINFO_MODIFYINFO;
+	global $TB_USERINFO_MIN;
+	global $TB_USERINFO_MAX;
+
+	$this_idx = $this->uid_idx();
+	$auth_idx = $user->uid_idx();
+
+	if ($access_type < $TB_USERINFO_MIN ||
+	    $access_type > $TB_USERINFO_MAX) {
+	    TBERROR("UserAccessCheck: Invalid access type $access_type!", 1);
+	}
+
+	if ($this->uid_idx() == $user->uid_idx()) {
+	    return 1;
+	}
+
+        #
+        # Admins do whatever they want.
+        # 
+        if (ISADMIN()) {
+	    return 1;
+	}
+
+        #
+        # This join will allow the operation if the current user is in the 
+        # same group (any group) as the target user, but with root permissions.
+        # 
+	$query_result =
+	    DBQueryFatal("select g.trust from group_membership as g ".
+			 "left join group_membership as authed on ".
+			 "     g.pid_idx=authed.pid_idx and ".
+			 "     g.gid_idx=authed.gid_idx and ".
+			 "     g.uid_idx='$uid_idx' ".
+			 "where authed.uid_idx='$auth_idx' and ".
+			 "      (authed.trust='group_root' or ".
+			 "       authed.trust='project_root')");
+
+	if (mysql_num_rows($query_result) == 0) {
+	    return 0;
+	}
+	return 1;
+    }
+
+    #
+    # How many PCs is user using. Again, use global function for now.
+    #
+    function PCsInUse() {
+	return TBUserPCs($this->uid());
+    }
+
+    #
+    # Functions to change various DB values.
+    #
+    function SetStatus($status) {
+	$idx = $this->uid_idx();
+
+	DBQueryFatal("update users set status='$status' ".
+		     "where uid_idx='$idx'");
+	$this->user["status"] = $status;
+	return 0;
+    }
+    function SetEmail($email) {
+	$idx = $this->uid_idx();
+
+	DBQueryFatal("update users set usr_email='$email' ".
+		     "where uid_idx='$idx'");
+	$this->user["usr_email"] = $email;
+	return 0;
+    }
+    function SetPassword($encoding, $expires) {
+	$idx = $this->uid_idx();
+
+	# Clear the chpasswd stuff anytime passwd is set.
+	DBQueryFatal("update users set ".
+		     "  usr_pswd='$encoding', pswd_expires=$expires, ".
+		     "  chpasswd_key=NULL,chpasswd_expires=0 ".
+		     "where uid_idx='$idx'");
+	$this->user["usr_pswd"] = $encoding;
+	return 0;
+    }
+    function SetChangePassword($key, $expires) {
+	$idx = $this->uid_idx();
+
+	DBQueryFatal("update users set ".
+		     "  chpasswd_key='$key',chpasswd_expires=$expires ".
+		     "where uid_idx='$idx'");
+	return 0;
+    }
+    function SetWindowsPassword($password) {
+	$idx = $this->uid_idx();
+
+	DBQueryFatal("update users set ".
+		     "  usr_w_pswd='$password' ".
+		     "where uid_idx='$idx'");
+	$this->user["usr_w_pswd"] = $password;
+	return 0;
+    }
+    function SetNotes($notes) {
+	$idx   = $this->uid_idx();
+	$notes = addslashes($notes);
+			    
+	DBQueryFatal("update users set ".
+		     "  notes='$notes' ".
+		     "where uid_idx='$idx'");
+	$this->user["notes"] = $notes;
+	return 0;
+    }
+    function SetUserInterface($interface) {
+	$idx   = $this->uid_idx();
+			    
+	DBQueryFatal("update users set ".
+		     "  user_interface='$interface' ".
+		     "where uid_idx='$idx'");
+	$this->user["user_interface"] = $interface;
+	return 0;
+    }
+    function SetWebFreeze($freeze) {
+	$idx   = $this->uid_idx();
+
+	$freeze = ($freeze ? 1 : 0);
+			    
+	DBQueryFatal("update users set ".
+		     "   weblogin_frozen='$freeze' ".
+		     "where uid_idx='$idx'");
+	$this->user["weblogin_frozen"] = $freeze;
+	return 0;
+    }
+    function SetCVSWeb($onoff) {
+	$idx   = $this->uid_idx();
+
+	$onoff = ($onoff ? 1 : 0);
+			    
+	DBQueryFatal("update users set ".
+		     "   cvsweb='$onoff' ".
+		     "where uid_idx='$idx'");
+	$this->user["cvsweb"] = $onoff;
+	return 0;
+    }
+    function UpdateWebLoginFail() {
+	$idx   = $this->uid_idx();
+
+	DBQueryFatal("update users set ".
+		     "       weblogin_failcount=weblogin_failcount+1, ".
+		     "       weblogin_failstamp='$now' ".
+		     "where uid_idx='$idx'");
+
+	return $this->Refresh();
+    }
+    function ChangeProfile($usr_name,  $usr_title,
+			   $usr_affil, $usr_addr,
+			   $usr_addr2, $usr_city,
+			   $usr_state, $usr_zip, $usr_country,
+			   $usr_phone, $usr_shell, $usr_URL) {
+
+	$idx          = $this->uid_idx();
+	$usr_name     = addslashes($usr_name);
+	$usr_title    = addslashes($usr_title);
+	$usr_affil    = addslashes($usr_affil);
+	$usr_addr     = addslashes($usr_addr);
+	$usr_addr2    = addslashes($usr_addr2);
+	$usr_city     = addslashes($usr_city);
+	$usr_state    = addslashes($usr_state);
+	$usr_zip      = addslashes($usr_zip);
+	$usr_country  = addslashes($usr_country);
+	$usr_phone    = addslashes($usr_phone);
+	$usr_shell    = addslashes($usr_shell);
+	$usr_URL      = addslashes($usr_URL);
+
+	$query_result =
+	    DBQueryFatal("UPDATE users SET ".
+			 "usr_name=\"$usr_name\",       ".
+			 "usr_URL=\"$usr_URL\",         ".
+			 "usr_addr=\"$usr_addr\",       ".
+			 "usr_addr2=\"$usr_addr2\",     ".
+			 "usr_city=\"$usr_city\",       ".
+			 "usr_state=\"$usr_state\",     ".
+			 "usr_zip=\"$usr_zip\",         ".
+			 "usr_country=\"$usr_country\", ".
+			 "usr_phone=\"$usr_phone\",     ".
+			 "usr_title=\"$usr_title\",     ".
+			 "usr_affil=\"$usr_affil\",     ".
+			 "usr_shell=\"$usr_shell\"      ".
+			 "WHERE uid_idx=\"$idx\"");
+
+	if (mysql_affected_rows()) {
+	    DBQueryFatal("update users set usr_modified=now() ".
+			 "where uid_idx='$idx'");
+	    
+	    return 1;
+	}
+	return 0;
+    }
+
+    #
+    # Return project access list for a user. This returns just pid,eid for
+    # now, later return actual objects. 
+    #
+    function ProjectAccessList($access_type) {
+	global $TB_PROJECT_CREATEEXPT;
+	global $TB_PROJECT_MAKEOSID;
+	global $TB_PROJECT_MAKEIMAGEID;
+	global $TB_PROJECT_MAKEGROUP;
+	global $TB_PROJECT_READINFO;
+
+	$uid_idx     = $this->uid_idx();
+	$result      = array();
+	$user_clause = "where uid_idx='$uid_idx' and";
+	$trust_clause= "";
+
+	# Constants.
+	$trust_none   = TBDB_TRUSTSTRING_NONE;
+	$trust_user   = TBDB_TRUSTSTRING_USER;
+	$trust_local  = TBDB_TRUSTSTRING_LOCALROOT;
+	$trust_group  = TBDB_TRUSTSTRING_GROUPROOT;
+	$trust_project= TBDB_TRUSTSTRING_PROJROOT;
+	
+	if ($access_type == $TB_PROJECT_READINFO) {
+	    $trust_clause = "trust!='$trust_none'";
+	}
+	elseif ($access_type == $TB_PROJECT_MAKEGROUP) {
+	    $trust_clause = "trust='$trust_project'";
+	}
+	elseif ($access_type == $TB_PROJECT_CREATEEXPT) {
+	    $trust_clause =
+		"(trust='$trust_project' or trust='$trust_group' or ".
+		" trust='$trust_local')";
+	}
+	elseif ($access_type == $TB_PROJECT_MAKEOSID ||
+		$access_type == $TB_PROJECT_MAKEIMAGEID) {
+	    if (ISADMIN()) {
+		$user_clause = "";
+	    }
+	    else {
+		$trust_clause =
+		    "(trust='$trust_project' or trust='$trust_group' or ".
+		    " trust='$trust_local')";
+	    
+	    }
+	}
+	else {
+	    TBERROR("Invalid access type $access_type!", 1);
+	}
+    
+	$query_result =
+	    DBQueryFatal("SELECT distinct pid,gid FROM group_membership ".
+			 "$user_clause $trust_clause order by pid");
+
+	if (mysql_num_rows($query_result) == 0) {
+	    return $result;
+	}
+
+	while ($row = mysql_fetch_array($query_result)) {
+	    $pid = $row['pid'];
+	    $gid = $row['gid'];
+	
+	    $result[$pid][] = $gid;
+	}
+	return $result;
+    }
+
+    #
+    # Return project membership list for a user.
+    #
+    function ProjectMembershipList() {
+	$uid_idx = $this->uid_idx();
+	$result  = array();
+
+	$query_result =
+	    DBQueryFatal("select pid_idx from group_membership ".
+			 "where pid_idx=gid_idx and ".
+			 "      uid_idx='$uid_idx'");
+
+	while ($row = mysql_fetch_array($query_result)) {
+	    $pid_idx = $row["pid_idx"];
+
+	    if (! ($project = Project::Lookup($pid_idx))) {
+		TBERROR("User::ProjectMembershipList: ".
+			"Could not load project $pid_idx!", 1);
+	    }
+	    $result[] = $project;
+	}
+	return $result;
+    }
+
+    #
+    # First approved project.
+    #
+    function FirstApprovedProject() {
+	$uid_idx = $this->uid_idx();
+
+	$query_result =
+	    DBQueryFatal("select pid_idx from group_membership ".
+			 "where uid_idx='$uid_idx' and pid=gid and ".
+			 "      trust!='". TBDB_TRUSTSTRING_NONE . "' ".
+			 "order by date_approved asc limit 1");
+	
+	if (mysql_num_rows($query_result) == 0) {
+	    return null;
+	}
+	$row = mysql_fetch_array($query_result);
+	$pid_idx = $row["pid_idx"];
+
+	if (! ($project = Project::Lookup($pid_idx))) {
+	    TBERROR("User::FirstApprovedProject: ".
+		    "Could not load project $pid_idx!", 1);
+	}
+	return $project;
+    }
+
+    #
+    # Are there users waiting to be approved by this user?
+    #
+    function ApprovalList($listify = 1) {
+	$uid_idx = $this->uid_idx();
+
+	#
+        # Find all of the groups that this person has project/group root in,
+	# and then in all of those groups, all of the people who are awaiting
+	# to be approved (status = none).
+	#
+        # Okay, so this operation sucks out the right people by joining the
+        # group_membership table with itself.
+	#
+	$query_result =
+	    DBQueryFatal("select g.uid_idx,g.gid_idx ".
+			 "   from group_membership as authed ".
+			 "left join group_membership as g on ".
+			 "    g.pid_idx=authed.pid_idx and ".
+			 "    g.gid_idx=authed.gid_idx ".
+			 "left join users as u on u.uid_idx=g.uid_idx ".
+			 "where u.status!='". TBDB_USERSTATUS_UNVERIFIED . "'".
+			 "  and u.status!='". TBDB_USERSTATUS_NEWUSER . "'".
+			 "  and g.uid_idx!='$uid_idx' and ".
+			 "      g.trust='". TBDB_TRUSTSTRING_NONE . "' ".
+			 "  and authed.uid_idx='$uid_idx' and ".
+			 "     (authed.trust='group_root' or ".
+			 "      authed.trust='project_root') ".
+			 "ORDER BY g.uid,g.pid,g.gid");
+
+	if (! $listify) {
+	    return mysql_num_rows($query_result);
+	}
+	
+	# Else, create a list of the groups.
+	$result  = array();
+
+	while ($row = mysql_fetch_array($query_result)) {
+	    $uid_idx = $row["uid_idx"];
+	    $gid_idx = $row["gid_idx"];
+
+	    if (! ($group = Group::Lookup($gid_idx))) {
+		TBERROR("User::ApprovalList: ".
+			"Could not load group $gid_idx!", 1);
+	    }
+	    if (! ($user = User::Lookup($uid_idx))) {
+		TBERROR("User::ApprovalList: ".
+			"Could not load user $uid_idx!", 1);
+	    }
+	    if (! array_key_exists("$uid_idx", $result)) {
+		$result["$uid_idx"] = array();
+	    }
+	    $result["$uid_idx"][] =& $group;
+	}
+	return $result;
+    }
+
+    #
+    # See if user has enough permission to view the webcams. If not an admin
+    # person, then must be a project with permission to use the robots.
+    # Eventually this needs to be a much more restrictive test.
+    #
+    function WebCamAllowed() {
+	$uid_idx = $this->uid_idx();
+	
+	$query_result =
+	    DBQueryFatal("select distinct class from group_membership as g ".
+			 "left join nodetypeXpid_permissions as p on ".
+			 "     g.pid=p.pid ".
+			 "left join node_types as nt on nt.type=p.type ".
+			 "where g.uid_idx='$uid_idx' and class='robot'");
+	
+	return mysql_num_rows($query_result);
+    }
 }
diff --git a/www/verifyusr.php3 b/www/verifyusr.php3
index 6e080a5b28f4fbfc10ffe86d3123ad507723a00e..aba93a5fdc2f77e06addf345b66ff4c4f81daacc 100644
--- a/www/verifyusr.php3
+++ b/www/verifyusr.php3
@@ -14,10 +14,9 @@ PAGEHEADER("Confirm Verification");
 #
 # Only known and logged in users can be verified. 
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid,
-	      CHECKLOGIN_UNVERIFIED|CHECKLOGIN_NEWUSER|
-	      CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY);
+$this_user = CheckLoginOrDie(CHECKLOGIN_UNVERIFIED|CHECKLOGIN_NEWUSER|
+			     CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY);
+$uid       = $this_user->uid();
 
 #
 # Must provide the key!
@@ -30,18 +29,11 @@ if (!isset($key) || strcmp($key, "") == 0) {
 #
 # Grab the status and do the modification.
 #
-$query_result =
-    DBQueryFatal("select status,wikionly from users ".
-		 "where uid='$uid'");
-
-if (($row = mysql_fetch_row($query_result)) == 0) {
-    TBERROR("Database Error retrieving status for $uid!", 1);
-}
-$status   = $row[0];
-$wikionly = $row[1];
+$status   = $this_user->status();
+$wikionly = $this_user->wikionly();
 
 #
-# No multiple verifications!
+# No multiple verifications.
 # 
 if (! strcmp($status, TBDB_USERSTATUS_ACTIVE) ||
     ! strcmp($status, TBDB_USERSTATUS_UNAPPROVED)) {
@@ -51,77 +43,71 @@ if (! strcmp($status, TBDB_USERSTATUS_ACTIVE) ||
 
 #
 # The user is logged in, so all we need to do is confirm the key.
-# Make sure it matches.
 #
-$keymatch = TBGetVerificationKey($uid);
-
-if (strcmp($key, $keymatch)) {
+if ($key != $this_user->verify_key()) {
     USERERROR("The given key \"$key\" is incorrect. ".
 	      "Please enter the correct key.", 1);
 }
 
-function INFORMLEADERS($uid) {
+function INFORMLEADERS($this_user) {
     global $TBWWW, $TBMAIL_APPROVAL, $TBMAIL_AUDIT, $TBMAIL_WWW;
 
+    #
+    # Grab user info.
+    #
+    $usr_email   = $this_user->email();
+    $usr_URL     = $this_user->URL();
+    $usr_addr    = $this_user->addr();
+    $usr_addr2	 = $this_user->addr2();
+    $usr_city	 = $this_user->city();
+    $usr_state	 = $this_user->state();
+    $usr_zip	 = $this_user->zip();
+    $usr_country = $this_user->country();
+    $usr_name    = $this_user->name();
+    $usr_phone   = $this_user->phone();
+    $usr_title   = $this_user->title();
+    $usr_affil   = $this_user->affil();
+    $uid_idx     = $this_user->uid_idx();
+    $uid         = $this_user->uid();
+
     #
     # Get the list of all project/groups this users has tried to join
     # but whose membership messages where delayed until the user verified
     # himself.
     #
     $group_result =
-	DBQueryFatal("select * from group_membership ".
-		     "where uid='$uid' and trust='none'");
-
-    #
-    # Grab user info.
-    #
-    $userinfo_result =
-	DBQueryFatal("select * from users where uid='$uid'");
-
-    $row	 = mysql_fetch_array($userinfo_result);
-    $usr_email   = $row[usr_email];
-    $usr_URL     = $row[usr_URL];
-    $usr_addr    = stripslashes($row[usr_addr]);
-    $usr_addr2	 = stripslashes($row[usr_addr2]);
-    $usr_city	 = stripslashes($row[usr_city]);
-    $usr_state	 = stripslashes($row[usr_state]);
-    $usr_zip	 = stripslashes($row[usr_zip]);
-    $usr_country = stripslashes($row[usr_country]);
-    $usr_name    = stripslashes($row[usr_name]);
-    $usr_phone   = $row[usr_phone];
-    $usr_title   = stripslashes($row[usr_title]);
-    $usr_affil   = stripslashes($row[usr_affil]);
-
+	DBQueryFatal("select gid_idx from group_membership ".
+		     "where uid_idx='$uid_idx' and trust='none'");
+				     
      while ($row = mysql_fetch_array($group_result)) {
-	 $pid = $row[pid];
-	 $gid = $row[gid];
+	 $gid_idx = $row["gid_idx"];
 
-	 TBProjLeader($pid, $projleader_uid);
-	 TBGroupLeader($pid, $gid, $grpleader_uid);
+	 if (! ($group = Group::Lookup($gid_idx))) {
+	     TBERROR("Could not find group record for $gid_idx", 1);
+	 }
+	 $project     = $group->Project();
+	 $projleader  = $project->GetLeader();
+	 $groupleader = $group->GetLeader();
+	 $pid         = $project->pid();
+	 $gid         = $group->gid();
 
-	 if (!strcmp($projleader_uid, $uid)) {
+	 if ($this_user->SameUser($projleader)) {
 	     #
 	     # Project leader verifying himself. 
 	     # 
-	     TBUserInfo($projleader_uid, $leader_name, $leader_email);
-	     TBGroupUnixInfo($pid, $pid, $unix_gid, $unix_name);
-
-	     $projinfo_result =
-		 DBQueryFatal("select * from projects where pid='$pid'");
-
-	     $row		= mysql_fetch_array($projinfo_result);
-	     $proj_name		= stripslashes($row[name]);
-	     $proj_URL          = $row[URL];
-	     $proj_funders      = stripslashes($row[funders]);
-	     $proj_public       = ($row[public] ? "Yes" : "No");
-	     $proj_linked       = ($row[linked_to_us] ? "Yes" : "No");
-	     $proj_whynotpublic = stripslashes($row[public_whynot]);
-	     $proj_members      = $row[num_members];
-	     $proj_pcs          = $row[num_pcs];
-	     $proj_plabpcs      = $row[num_pcplab];
-	     $proj_ronpcs       = $row[num_ron];
-	     $proj_why		= stripslashes($row[why]);
-	     $proj_expires      = $row[expires];
+	     $proj_name		= $project->name();
+	     $proj_URL          = $project->URL();
+	     $proj_funders      = $project->funders();
+	     $proj_public       = ($project->public() ? "Yes" : "No");
+	     $proj_linked       = ($project->linked_to_us() ? "Yes" : "No");
+	     $proj_whynotpublic = $project->public_whynot();
+	     $proj_members      = $project->num_members();
+	     $proj_pcs          = $project->num_pcs();
+	     $proj_plabpcs      = $project->num_pcplab();
+	     $proj_ronpcs       = $project->num_ron();
+	     $proj_why		= $project->why();
+	     $unix_gid          = $group->unix_gid();
+	     $unix_name         = $group->unix_name();
 	     
 	     TBMAIL($TBMAIL_APPROVAL,
 		"New Project '$pid' ($uid)",
@@ -132,7 +118,6 @@ function INFORMLEADERS($uid) {
 		"Email:           $usr_email\n".
 		"User URL:        $usr_URL\n".
 		"Project:         $proj_name\n".
-		"Expires:         $proj_expires\n".
 		"Project URL:     $proj_URL\n".
 		"Public URL:      $proj_public\n".
 		"Why Not Public:  $proj_whynotpublic\n".
@@ -162,10 +147,12 @@ function INFORMLEADERS($uid) {
 		"Errors-To: $TBMAIL_WWW");
 	 }
 	 else {
-	     TBUserInfo($grpleader_uid, $leader_name, $leader_email);
-	     $allleaders = TBLeaderMailList($pid,$gid);
+	     $leader_name  = $groupleader->name();
+	     $leader_email = $groupleader->email();
+	     $leader_uid   = $groupleader->uid();
+	     $allleaders   = TBLeaderMailList($pid,$gid);
 	     
-	     TBMAIL("$leader_name '$grpleader_uid' <$leader_email>",
+	     TBMAIL("$leader_name '$leader_uid' <$leader_email>",
 		"$uid $pid Project Join Request",
 		"$usr_name is trying to join your group $gid in project $pid.".
 		"\n".
@@ -200,8 +187,8 @@ function INFORMLEADERS($uid) {
 }
 
 if (strcmp($status, TBDB_USERSTATUS_UNVERIFIED) == 0) {
-    DBQueryFatal("update users set status='active' where uid='$uid'");
-
+    $this_user->SetStatus(TBDB_USERSTATUS_ACTIVE());
+    
     TBMAIL($TBMAIL_AUDIT,
 	   "User '$uid' has been verified",
 	   "\n".
@@ -219,9 +206,10 @@ if (strcmp($status, TBDB_USERSTATUS_UNVERIFIED) == 0) {
 	 "that are now available to you will appear.\n";
 }
 elseif (strcmp($status, TBDB_USERSTATUS_NEWUSER) == 0) {
-    $newstatus = ($wikionly ? "active" : "unapproved");
+    $newstatus = ($wikionly ?
+		  TBDB_USERSTATUS_ACTIVE() : TBDB_USERSTATUS_UNAPPROVED());
     
-    DBQueryFatal("update users set status='$newstatus' where uid='$uid'");
+    $this_user->SetStatus(TBDB_USERSTATUS_UNAPPROVED());
 
     TBMAIL($TBMAIL_AUDIT,
 	   "User '$uid' has been verified",
@@ -243,20 +231,15 @@ elseif (strcmp($status, TBDB_USERSTATUS_NEWUSER) == 0) {
 
 	#
 	# The backend sets the actual WikiName
-	# 
-	$query_result =
-	    DBQueryFatal("select wikiname from users where uid='$uid'");
-
-	if (($row = mysql_fetch_row($query_result)) == 0) {
-	    TBERROR("Database Error retrieving status for $uid!", 1);
-	}
-	$wikiname = $row[0];
+	#
+	$this_user->Refresh();
+	$wikiname = $this_user->wikiname();
 
 	echo "You have been verified. You may now access the Wiki at<br>".
 	    "<a href='$WIKIURL/$wikiname'>$WIKIURL/$wikiname</a>\n";
     }
     else {
-	INFORMLEADERS($uid);
+	INFORMLEADERS($this_user);
 
 	echo "<p>".
 	     "You have now been verified. However, your application ".
diff --git a/www/verifyusr_form.php3 b/www/verifyusr_form.php3
index c47a0f309602a92f39508b8271f0e1d068ef5cd7..1079b6d7b00397cc08ce47f7903a03717dc27b26 100644
--- a/www/verifyusr_form.php3
+++ b/www/verifyusr_form.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2000-2002, 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -14,10 +14,9 @@ PAGEHEADER("New User Verification");
 #
 # Only known and logged in users can be verified.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid,
-	      CHECKLOGIN_UNVERIFIED|CHECKLOGIN_NEWUSER|
-	      CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY);
+$this_user = CheckLoginOrDie(CHECKLOGIN_UNVERIFIED|CHECKLOGIN_NEWUSER|
+			     CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY);
+$uid       = $this_user->uid();
 
 echo "<p>
       The purpose of this page is to verify, for security purposes, that
diff --git a/www/webcam.php3 b/www/webcam.php3
index 801cf8df6247e0d493673cc21499b4bd53f7be0b..84dfc235b1cb2f3d8c91e15a981d7673b52d4785 100644
--- a/www/webcam.php3
+++ b/www/webcam.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2005 University of Utah and the Flux Group.
+# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -12,11 +12,11 @@ include("defs.php3");
 PAGEHEADER("Robot Web Cams");
 
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 # Helper function.
 function MyError($msg)
@@ -39,7 +39,7 @@ if (!$admins_can_view || (!$anyone_can_view && !$isadmin)) {
 #
 # Now check permission.
 #
-if (!$isadmin && !TBWebCamAllowed($uid)) {
+if (!$isadmin && !$this_user->WebCamAllowed()) {
     MyError("Not enough permission to view the robot cameras!");
 }
 
diff --git a/www/webcamimg.php3 b/www/webcamimg.php3
index 5de0c74e3165169e9b3e18c684a53259a7437f89..2e7a96fb8e7e0cb929e34130678e23e46b9694be 100644
--- a/www/webcamimg.php3
+++ b/www/webcamimg.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2005 University of Utah and the Flux Group.
+# Copyright (c) 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -21,11 +21,11 @@ function MyError($msg)
 
 
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Verify page arguments.
@@ -87,7 +87,7 @@ if (!$admins_can_view || (!$anyone_can_view && !$isadmin)) {
 #
 # Now check permission.
 #
-if (!$isadmin && !TBWebCamAllowed($uid)) {
+if (!$isadmin && !$this_user->WebCamAllowed()) {
     MyError("Not enough permission to view the robot cameras!");
 }
 
diff --git a/www/webdb/webdb.php3 b/www/webdb/webdb.php3
index c70619e3000a0f9f92c07d42151e36a81f8394a0..b72e362add3467f75f1e6b440de6deb8239b587f 100644
--- a/www/webdb/webdb.php3
+++ b/www/webdb/webdb.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2002 University of Utah and the Flux Group.
+# Copyright (c) 2000-2002, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 
@@ -11,10 +11,12 @@ require("defs.php3");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
+$dbedit    = $this_user->dbedit();
 
-if (! TBWebdbAllowed($uid)) {
+if (! $dbedit) {
     USERERROR("You do not have permission to use WEBDB!", 1);
 }
 
diff --git a/www/widearea_info.php3 b/www/widearea_info.php3
index 2e21dfefabd0a859a899e0d42cdf479405e9e4da..3435e900d5c8c1d389359b95c986c4c599305c3d 100644
--- a/www/widearea_info.php3
+++ b/www/widearea_info.php3
@@ -1,17 +1,18 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2003 University of Utah and the Flux Group.
+# Copyright (c) 2000-2003, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
 include("showstuff.php3");
 
 #
-# Only known and logged in users can end experiments.
+# Only known and logged in users.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Show argument.
diff --git a/www/widearea_nodeinfo.php3 b/www/widearea_nodeinfo.php3
index cf17eeaade0458c5cb1823f75ade5d88d279bd15..f640b77dcb20e3acd24980897a80841ed2ab51de 100644
--- a/www/widearea_nodeinfo.php3
+++ b/www/widearea_nodeinfo.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2004 University of Utah and the Flux Group.
+# Copyright (c) 2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -10,8 +10,9 @@ include("showstuff.php3");
 #
 # Only known and logged in users can see this information
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 if ($node_id) {
     PAGEHEADER("Wide Area Link Characteristics For $node_id");
diff --git a/www/widearea_register.php b/www/widearea_register.php
index e4be35cb08e7ecbad3590eb80bb5eb007e6a1b39..70354afa99a1e3f3566d2a3cec875a8a30159c25 100644
--- a/www/widearea_register.php
+++ b/www/widearea_register.php
@@ -12,16 +12,16 @@ include("defs.php3");
 
 #
 # Get current user.
-# 
-$uid = GETLOGIN();
+#
+$this_user = CheckLoginOrDie();
 
 #
 # 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.
 #
-if ($uid) {
-    LOGGEDINORDIE($uid, CHECKLOGIN_UNAPPROVED);
-    $usr_uid = $uid;
+if ($this_user) {
+    CheckLoginOrDie(CHECKLOGIN_UNAPPROVED);
+    $usr_uid = $this_user->uid();
     $returning = 1;
 }
 else {
@@ -31,6 +31,7 @@ else {
     $returning = 0;
 }
 $haveinfo = 0;
+unset($addpubkeyargs);
 
 #
 # Default connection type strings,
@@ -523,7 +524,7 @@ if (! $returning) {
 	    $errors["UserName"] =
 		"Too long! Must be less than or equal to $TBDB_UIDLEN";
 	}
-	elseif (TBCurrentUser($formfields[usr_uid])) {
+	elseif (User::Lookup($formfields[usr_uid])) {
 	    $errors["UserName"] =
 		"Already in use. Select another";
 	}
@@ -544,16 +545,12 @@ if (! $returning) {
 	strcmp($formfields[usr_email], "") == 0) {
 	$errors["Email Address"] = "Missing Field";
     }
-    else {
-	$usr_email    = $formfields[usr_email];
-	$email_domain = strstr($usr_email, "@");
-    
-	if (! $email_domain ||
-	    strcmp($usr_email, $email_domain) == 0 ||
-	    strlen($email_domain) <= 1 ||
-	    ! strstr($email_domain, ".")) {
-	    $errors["Email Address"] = "Looks invalid!";
-	}
+    elseif (! TBvalid_email($formfields[usr_email])) {
+	$errors["Email Address"] = TBFieldErrorString();
+    }
+    elseif (User::LookupByEmail($formfields[usr_email])) {
+	$errors["Email Address"] =
+	    "Already in use. <b>Did you forget to login?</b>";
     }
     if (isset($formfields[usr_URL]) &&
 	strcmp($formfields[usr_URL], "") &&
@@ -696,6 +693,108 @@ if (count($errors)) {
     return;
 }
 
+# Okay, do pubkey checks.
+if (!$returning) {
+    #
+    # Pub key provided in form (paste in).
+    #
+    if (isset($formfields[usr_key]) &&
+	strcmp($formfields[usr_key], "")) {
+        #
+        # This is passed off to the shell, so taint check it.
+        # 
+	if (! preg_match("/^[-\w\s\.\@\+\/\=]*$/", $formfields[usr_key])) {
+	    $errors["PubKey"] = "Invalid characters";
+	}
+	else {
+            #
+            # Replace any embedded newlines first.
+            #
+	    $formfields[usr_key] =
+		ereg_replace("[\n]", "", $formfields[usr_key]);
+	    $usr_key = $formfields[usr_key];
+
+            #
+            # Verify key format.
+            #
+	    if (ADDPUBKEY(null, "webaddpubkey -n -k '$usr_key' ")) {
+		$errors["Pubkey Format"] =
+		    "Could not be parsed. Is it a public key?";
+	    }
+	    else {
+		$addpubkeyargs = "-k '$usr_key' ";
+	    }
+	}
+    }
+
+    #
+    # If usr provided a file for the key, it overrides the paste in text.
+    #
+    if (isset($_FILES['usr_keyfile']) &&
+	$_FILES['usr_keyfile']['name'] != "" &&
+	$_FILES['usr_keyfile']['name'] != "none") {
+
+	$localfile = $_FILES['usr_keyfile']['tmp_name'];
+
+	if (! stat($localfile)) {
+	    $errors["PubKey File"] = "No such file";
+	}
+        # Taint check shell arguments always! 
+	elseif (! preg_match("/^[-\w\.\/]*$/", $localfile)) {
+	    $errors["PubKey File"] = "Invalid characters";
+	}
+	else {
+	    chmod($localfile, 0644);
+
+            #
+            # Verify key format.
+            #
+	    if (ADDPUBKEY(null, "webaddpubkey -n $localfile ")) {
+		$errors["Pubkey Format"] =
+		    "Could not be parsed. Is it a public key?";
+	    }
+	    else {
+		$addpubkeyargs = "$localfile";
+	    }
+	}
+    }
+}
+
+if (count($errors)) {
+    SPITFORM($formfields, $returning, $errors);
+    PAGEFOOTER();
+    return;
+}
+
+#
+# Verify that the key is valid. This will weed out bozos who like to
+# fill in random forms. 
+#
+$query_result =
+    DBQueryFatal("select * from widearea_privkeys as w ".
+		 "where w.lockkey='$cdkey' and w.IP='$IP'");
+
+if (!mysql_num_rows($query_result)) {
+    $errors["CD Key"] = "Invalid CD Key for $node_id";
+}
+
+#
+# Check for an existing entry in widearea_accounts.
+#
+$query_result =
+    DBQueryFatal("select * from widearea_accounts ".
+		 "where uid='$usr_uid' and node_id='$node_id'");
+
+if (mysql_num_rows($query_result)) {
+    $errors["IP Address"] = "You have already requested an account on $IP";
+}
+
+if (count($errors)) {
+    SPITFORM($formfields, $returning, $errors);
+    PAGEFOOTER();
+    return;
+}
+
 #
 # Certain of these values must be escaped or otherwise sanitized.
 #
@@ -713,18 +812,6 @@ if (! $haveinfo) {
     $node_country  = addslashes($formfields[node_country]);
 }
 
-#
-# Verify that the key is valid. This will weed out bozos who like to
-# fill in random forms. 
-#
-$query_result =
-    DBQueryFatal("select * from widearea_privkeys as w ".
-		 "where w.lockkey='$cdkey' and w.IP='$IP'");
-
-if (!mysql_num_rows($query_result)) {
-    $errors["CD Key"] = "Invalid CD Key for $node_id";
-}
-
 if (!$returning) {
     $usr_uid           = $formfields[usr_uid];
     $usr_title         = addslashes($formfields[usr_title]);
@@ -747,7 +834,7 @@ if (!$returning) {
 	$usr_URL = "";
     }
     else {
-	$usr_URL = $formfields[usr_URL];
+	$usr_URL = addslashes($formfields[usr_URL]);
     }
     
     if (! isset($formfields[usr_addr2])) {
@@ -757,150 +844,51 @@ if (!$returning) {
 	$usr_addr2 = addslashes($formfields[usr_addr2]);
     }
 
-    #
-    # Pub Key.
-    #
-    if (isset($formfields[usr_key]) &&
-	strcmp($formfields[usr_key], "")) {
-        #
-        # This is passed off to the shell, so taint check it.
-        # 
-	if (! preg_match("/^[-\w\s\.\@\+\/\=]*$/", $formfields[usr_key])) {
-	    $errors["PubKey"] = "Invalid characters";
-	}
-	else {
-            #
-            # Replace any embedded newlines first.
-            #
-	    $formfields[usr_key] =
-		ereg_replace("[\n]", "", $formfields[usr_key]);
-	    $usr_key = $formfields[usr_key];
-	    $addpubkeyargs = "-k '$usr_key' ";
-	}
-    }
+    $args = array();
+    $args["usr_name"]	   = $usr_name;
+    $args["usr_email"]     = $usr_email;
+    $args["usr_addr"]      = $usr_addr;
+    $args["usr_addr2"]     = $usr_addr2;
+    $args["usr_city"]      = $usr_city;
+    $args["usr_state"]     = $usr_state;
+    $args["usr_zip"]       = $usr_zip;
+    $args["usr_country"]   = $usr_country;
+    $args["usr_URL"]       = $usr_URL;
+    $args["usr_phone"]     = $usr_phone;
+    $args["usr_shell"]     = 'tcsh';
+    $args["usr_title"]     = $usr_title;
+    $args["usr_affil"]     = $usr_affil;
+    $args["usr_pswd"]      = crypt("$password1");
 
-    #
-    # If usr provided a file for the key, it overrides the paste in text.
-    #
-    if (isset($usr_keyfile) &&
-	strcmp($usr_keyfile, "") &&
-	strcmp($usr_keyfile, "none")) {
-
-	if (! stat($usr_keyfile)) {
-	    $errors["PubKey File"] = "No such file";
-	}
-	else {
-	    $addpubkeyargs = "$usr_keyfile";
-	    chmod($usr_keyfile, 0644);	
-	}
+    if (! ($user = User::NewUser($usr_uid, TBDB_NEWACCOUNT_WEBONLY, $args))) {
+	TBERROR("Could not create new user '$usr_email'!", 1);
     }
-    #
-    # Verify key format.
-    #
-    if (isset($addpubkeyargs) &&
-	ADDPUBKEY($usr_uid, "webaddpubkey -n -u $usr_uid $addpubkeyargs")) {
-	$errors["Pubkey Format"] = "Could not be parsed. Is it a public key?";
+    $usr_uid = $user->uid();
+
+    if (isset($addpubkeyargs)) {
+	ADDPUBKEY($usr_uid, "webaddpubkey -u $usr_uid $addpubkeyargs");
     }
 }
 else {
     #
     # Grab info from the DB for the email message below. Kinda silly.
     #
-    $query_result =
-	DBQueryFatal("select * from users where uid='$usr_uid'");
-    
-    $row = mysql_fetch_array($query_result);
-    
-    $usr_title	   = $row[usr_title];
-    $usr_name	   = $row[usr_name];
-    $usr_affil	   = $row[usr_affil];
-    $usr_email	   = $row[usr_email];
-    $usr_addr	   = $row[usr_addr];
-    $usr_addr2     = $row[usr_addr2];
-    $usr_city	   = $row[usr_city];
-    $usr_state	   = $row[usr_state];
-    $usr_zip	   = $row[usr_zip];
-    $usr_country   = $row[usr_country];
-    $usr_phone	   = $row[usr_phone];
-    $usr_URL       = $row[usr_URL];
+    $user = $this_user;
+    $usr_title	   = $user->title();
+    $usr_name	   = $user->name();
+    $usr_affil	   = $user->affil();
+    $usr_email	   = $user->email();
+    $usr_addr	   = $user->addr();
+    $usr_addr2     = $user->addr2();
+    $usr_city	   = $user->city();
+    $usr_state	   = $user->state();
+    $usr_zip	   = $user->zip();
+    $usr_country   = $user->country();
+    $usr_phone	   = $user->phone();
+    $usr_URL       = $user->URL();
     $usr_returning = "Yes";
 }
 
-#
-# Check for an existing entry in widearea_accounts.
-#
-$query_result =
-    DBQueryFatal("select * from widearea_accounts ".
-		 "where uid='$usr_uid' and node_id='$node_id'");
-
-if (mysql_num_rows($query_result)) {
-    $errors["IP Address"] = "You have already requested an account on $IP";
-}
-
-if (count($errors)) {
-    SPITFORM($formfields, $returning, $errors);
-    PAGEFOOTER();
-    return;
-}
-
-#
-# For a new user:
-# * Create a new account in the database.
-# * Generate a mail message to the user with the verification key.
-# 
-if (! $returning) {
-    $encoding = crypt("$password1");
-
-    #
-    # Must be done before user record is inserted!
-    # XXX Since, user does not exist, must run as nobody. Script checks. 
-    # 
-    if (isset($addpubkeyargs)) {
-	ADDPUBKEY($usr_uid, "webaddpubkey -u $usr_uid $addpubkeyargs");
-    }
-
-    # Unique Unix UID.
-    $unix_uid = TBGetUniqueIndex('next_uid');
-
-    DBQueryFatal("INSERT INTO users ".
-	 "(uid,usr_created,usr_expires,usr_name,usr_email,usr_addr,".
-	 " usr_addr2,usr_city,usr_state,usr_zip,usr_country, ".
-	 " usr_URL,usr_title,usr_affil,usr_phone,usr_pswd,unix_uid,".
-	 " status,pswd_expires,usr_modified,webonly) ".
-	 "VALUES ('$usr_uid', now(), '$usr_expires', '$usr_name', ".
-         "'$usr_email', ".
-	 "'$usr_addr', '$usr_addr2', '$usr_city', '$usr_state', '$usr_zip', ".
-	 "'$usr_country', ".
-	 "'$usr_URL', '$usr_title', '$usr_affil', ".
-	 "'$usr_phone', '$encoding', $unix_uid, 'newuser', ".
-	 "date_add(now(), interval 1 year), now(), 1)");
-    
-    DBQueryFatal("INSERT INTO user_stats (uid, uid_idx) ".
-		 "VALUES ('$usr_uid', $unix_uid)");
-
-    $key = TBGenVerificationKey($usr_uid);
-
-    TBMAIL("$usr_name '$usr_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=$usr_uid&key=$key\n".
-      "\n".
-      "Once you have verified your account, Testbed Operations will be\n".
-      "able to approve you. You MUST verify your account first! After you\n".
-      "have been approved by Testbed Operations, an acount will be created\n".
-      "for you on $node_id.\n".
-      "\n".
-      "Thanks,\n".
-      "Testbed Operations\n",
-      "From: $TBMAIL_APPROVAL\n".
-      "Bcc: $TBMAIL_AUDIT\n".
-      "Errors-To: $TBMAIL_WWW");
-}
-
 #
 # Enter a new widearea_accounts record. To be approved later.
 #
diff --git a/www/wideareakeys.php3 b/www/wideareakeys.php3
index 9a88cb3c7df50703ad10e6518ede921cf9c19b38..76ba2d99745388eb9c06c91a1945b9bf8491f8a8 100644
--- a/www/wideareakeys.php3
+++ b/www/wideareakeys.php3
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2004, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 include("defs.php3");
@@ -10,9 +10,9 @@ include("showstuff.php3");
 #
 # Only known and logged in users can do this.
 #
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 if (!$isadmin) {
     USERERROR("You do not have permission to view this page!", 1);
diff --git a/www/wireless-stats/getdata.php3 b/www/wireless-stats/getdata.php3
index 28a3a3b2379e81bf40247ec8043c95b7a2987f7b..80aa34f604aa47b7b05ed9db08e6d14398b0ab98 100644
--- a/www/wireless-stats/getdata.php3
+++ b/www/wireless-stats/getdata.php3
@@ -7,8 +7,9 @@
 chdir("..");
 include("defs.php3");
 
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 function death($msg) {
     PAGEHEADER("Wireless Connectivity Data");
diff --git a/www/wireless-stats/statsapp.php3 b/www/wireless-stats/statsapp.php3
index d1f2c8f757e1c9c84073afbf563b944d703c114e..b1ff9f36da301f11a204706f5676d89a79162e5d 100644
--- a/www/wireless-stats/statsapp.php3
+++ b/www/wireless-stats/statsapp.php3
@@ -7,8 +7,9 @@
 chdir("..");
 include("defs.php3");
 
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 PAGEHEADER("Wireless/WSN Testbed Connectivity Statistics");
 
diff --git a/www/xmlrpcpipe.php3.in b/www/xmlrpcpipe.php3.in
index 0a93870990151fc0eca1080060f362513e77f0bc..bb19057c79579afa5e67f6dfd944aa328e40abd9 100644
--- a/www/xmlrpcpipe.php3.in
+++ b/www/xmlrpcpipe.php3.in
@@ -1,7 +1,7 @@
 <?php
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2004, 2005 University of Utah and the Flux Group.
+# Copyright (c) 2004, 2005, 2006 University of Utah and the Flux Group.
 # All rights reserved.
 #
 # This is an included file. No headers or footers.
@@ -35,9 +35,9 @@ define("XMLRPC_RESPONSE_TIMEDOUT",	8);
 #
 define("XMLRPC_PACKAGE_VERSION",	0.1);
 
-$uid = GETLOGIN();
-LOGGEDINORDIE($uid);
-$isadmin = ISADMIN($uid);
+$this_user = CheckLoginOrDie();
+$uid       = $this_user->uid();
+$isadmin   = ISADMIN();
 
 #
 # Invoke the ssl xmlrpc client in raw mode, passing it an encoded XMLRPC