Commit 3e2bb386 authored by Leigh B. Stoller's avatar Leigh B. Stoller
Browse files

More inventive ways to avoid real work; add password expiration

capability. New DB field in the users table (pswd_expires) which is a
date field that initially gets set to one year after the user account
is created. When the password is changed via the web form, it gets
bumped 1 more year into the future *unless* the current uid is
different from the target_uid (ie: you are changing a password for
someone else). In that case, the expiration is set to the current
date, which forces the target user to change his password next time he
logs in. I've changed the menu/auth code to look for password
expiration, and when expired the menu options contain just a single
option to change the password. All other https pages will fail with a
password expired message. Normal text pages will work of course.
parent a1dc57a9
...@@ -14,9 +14,8 @@ $uid = GETLOGIN(); ...@@ -14,9 +14,8 @@ $uid = GETLOGIN();
# personal information for some random ?uid argument. # personal information for some random ?uid argument.
# #
if ($uid) { if ($uid) {
if (CHECKLOGIN($uid) != 1) { LOGGEDINORDIE($uid);
USERERROR("You are not logged in. Please log in and try again.", 1);
}
$query_result = mysql_db_query($TBDBNAME, $query_result = mysql_db_query($TBDBNAME,
"SELECT * FROM users WHERE uid='$uid'"); "SELECT * FROM users WHERE uid='$uid'");
if (! $query_result) { if (! $query_result) {
......
...@@ -980,11 +980,8 @@ function DBFatal($message) ...@@ -980,11 +980,8 @@ function DBFatal($message)
DBWarn($message); DBWarn($message);
echo "<p><p> PAGEERROR("<p><p>".
Unexpected Error. Could not continue. Please contact $TBMAILADDR\n"; "Unexpected Error. Could not continue. ".
"Please contact $TBMAILADDR\n");
PAGEFOOTER();
die("");
} }
?> ?>
...@@ -77,16 +77,14 @@ function TBERROR ($message, $death) { ...@@ -77,16 +77,14 @@ function TBERROR ($message, $death) {
sleep(1); sleep(1);
if ($death) { if ($death) {
echo "<h3><br><br> $msg = "<h3><br><br>
$message $message
<br> <br>
</h3>"; </h3>
<p><p>
echo "<p><p> Could not continue. Please contact $TBMAILADDR\n";
Could not continue. Please contact $TBMAILADDR\n";
PAGEERROR($msg);
PAGEFOOTER();
die("");
} }
return 0; return 0;
} }
...@@ -97,18 +95,18 @@ function TBERROR ($message, $death) { ...@@ -97,18 +95,18 @@ function TBERROR ($message, $death) {
function USERERROR($message, $death) { function USERERROR($message, $death) {
global $TBMAILADDR; global $TBMAILADDR;
echo "<h3><br><br> $msg = "<h3><br><br>
$message $message
<br> <br>
</h3>"; </h3>
<p><p>
echo "<p><p> Please contact $TBMAILADDR if you feel this message is an error.";
Please contact $TBMAILADDR if you feel this message is an error.";
if ($death) { if ($death) {
PAGEFOOTER(); PAGEERROR($msg);
die("");
} }
else
echo "$msg\n";
} }
# #
......
...@@ -7,9 +7,11 @@ $STATUS_LOGINFAIL = 3; ...@@ -7,9 +7,11 @@ $STATUS_LOGINFAIL = 3;
$STATUS_TIMEDOUT = 4; $STATUS_TIMEDOUT = 4;
$STATUS_NOLOGINS = 5; $STATUS_NOLOGINS = 5;
$login_status = $STATUS_NOSTATUS; $login_status = $STATUS_NOSTATUS;
$pswd_expired = 0;
$login_message = ""; $login_message = "";
$error_message = 0; $error_message = 0;
$login_uid = 0; $login_uid = 0;
$drewheader = 0;
$javacode = file("java.html"); $javacode = file("java.html");
# #
...@@ -50,7 +52,7 @@ function WRITESIDEBAR() { ...@@ -50,7 +52,7 @@ function WRITESIDEBAR() {
global $login_status, $login_message, $error_message, $login_uid; global $login_status, $login_message, $error_message, $login_uid;
global $STATUS_NOSTATUS, $STATUS_LOGGEDIN, $STATUS_LOGGEDOUT; global $STATUS_NOSTATUS, $STATUS_LOGGEDIN, $STATUS_LOGGEDOUT;
global $STATUS_LOGINFAIL, $STATUS_TIMEDOUT, $STATUS_NOLOGINS; global $STATUS_LOGINFAIL, $STATUS_TIMEDOUT, $STATUS_NOLOGINS;
global $TBBASE, $TBDOCBASE, $TBDBNAME, $BASEPATH; global $TBBASE, $TBDOCBASE, $TBDBNAME, $BASEPATH, $pswd_expired;
# #
# The document base cannot be a mix of secure and nonsecure. # The document base cannot be a mix of secure and nonsecure.
...@@ -94,12 +96,12 @@ function WRITESIDEBAR() { ...@@ -94,12 +96,12 @@ function WRITESIDEBAR() {
</tr>\n"; </tr>\n";
} }
elseif ($login_status == $STATUS_LOGGEDIN) { elseif ($login_status == $STATUS_LOGGEDIN) {
$query_result = mysql_db_query($TBDBNAME, $query_result =
"SELECT status,admin,stud FROM users WHERE uid='$login_uid'"); DBQueryFatal("SELECT status,admin ".
"FROM users WHERE uid='$login_uid'");
$row = mysql_fetch_row($query_result); $row = mysql_fetch_row($query_result);
$status = $row[0]; $status = $row[0];
$admin = $row[1]; $admin = $row[1];
$stud = $row[2];
# #
# See if group_root in any projects, not just the last one in the DB! # See if group_root in any projects, not just the last one in the DB!
...@@ -115,7 +117,11 @@ function WRITESIDEBAR() { ...@@ -115,7 +117,11 @@ function WRITESIDEBAR() {
$trusted = 0; $trusted = 0;
} }
if ($status == "active") { if ($status == "active" && $pswd_expired) {
WRITESIDEBARBUTTON("Change your Password",
$TBBASE, "modusr_form.php3");
}
elseif ($status == "active") {
if ($admin) { if ($admin) {
WRITESIDEBARBUTTON("New Project Approval", WRITESIDEBARBUTTON("New Project Approval",
$TBBASE, "approveproject_list.php3"); $TBBASE, "approveproject_list.php3");
...@@ -174,6 +180,8 @@ function WRITESIDEBAR() { ...@@ -174,6 +180,8 @@ function WRITESIDEBAR() {
switch ($login_status) { switch ($login_status) {
case $STATUS_LOGGEDIN: case $STATUS_LOGGEDIN:
$login_message = "$login_uid Logged In"; $login_message = "$login_uid Logged In";
if ($pswd_expired)
$login_message = "$login_message<br>(Password Expired!)";
break; break;
case $STATUS_LOGGEDOUT: case $STATUS_LOGGEDOUT:
$login_message = "Logged Out"; $login_message = "Logged Out";
...@@ -326,7 +334,10 @@ function PAGEHEADER($title) { ...@@ -326,7 +334,10 @@ function PAGEHEADER($title) {
global $TBBASE, $TBDOCBASE, $TBDBNAME; global $TBBASE, $TBDOCBASE, $TBDBNAME;
global $CHECKLOGIN_NOTLOGGEDIN, $CHECKLOGIN_LOGGEDIN; global $CHECKLOGIN_NOTLOGGEDIN, $CHECKLOGIN_LOGGEDIN;
global $CHECKLOGIN_TIMEDOUT, $CHECKLOGIN_MAYBEVALID; global $CHECKLOGIN_TIMEDOUT, $CHECKLOGIN_MAYBEVALID;
global $BASEPATH, $SSL_PROTOCOL, $javacode; global $CHECKLOGIN_PSWDEXPIRED;
global $BASEPATH, $SSL_PROTOCOL, $javacode, $drewheader, $pswd_expired;
$drewheader = 1;
# #
# Determine the proper basepath, which depends on whether the page # Determine the proper basepath, which depends on whether the page
...@@ -357,6 +368,8 @@ function PAGEHEADER($title) { ...@@ -357,6 +368,8 @@ function PAGEHEADER($title) {
$login_status = $STATUS_NOSTATUS; $login_status = $STATUS_NOSTATUS;
$login_uid = 0; $login_uid = 0;
break; break;
case $CHECKLOGIN_PSWDEXPIRED:
$pswd_expired = 1;
case $CHECKLOGIN_LOGGEDIN: case $CHECKLOGIN_LOGGEDIN:
case $CHECKLOGIN_MAYBEVALID: case $CHECKLOGIN_MAYBEVALID:
$login_status = $STATUS_LOGGEDIN; $login_status = $STATUS_LOGGEDIN;
...@@ -493,4 +506,16 @@ function PAGEFOOTER() { ...@@ -493,4 +506,16 @@ function PAGEFOOTER() {
</body> </body>
</html>\n"; </html>\n";
} }
function PAGEERROR($msg) {
global $drewheader;
if (! $drewheader)
PAGEHEADER("");
echo "$msg\n";
PAGEFOOTER();
die("");
}
?> ?>
...@@ -9,8 +9,11 @@ PAGEHEADER("Modify User Information Form"); ...@@ -9,8 +9,11 @@ PAGEHEADER("Modify User Information Form");
# #
# Only known and logged in users can modify info. # 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.
#
$uid = GETLOGIN(); $uid = GETLOGIN();
LOGGEDINORDIE($uid); LOGGEDINORDIE_SPECIAL($uid);
$isadmin = ISADMIN($uid); $isadmin = ISADMIN($uid);
# #
......
...@@ -5,15 +5,17 @@ include("showstuff.php3"); ...@@ -5,15 +5,17 @@ include("showstuff.php3");
$changed_password = "No"; $changed_password = "No";
# #
# Standard Testbed Header # Hold off drawing header until later!
# #
PAGEHEADER("Modify User Information");
# #
# Only known and logged in users can modify info. # 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.
#
$uid = GETLOGIN(); $uid = GETLOGIN();
LOGGEDINORDIE($uid); LOGGEDINORDIE_SPECIAL($uid);
# #
# The target_uid comes in as a POST var. It must be set. We allow # The target_uid comes in as a POST var. It must be set. We allow
...@@ -111,7 +113,8 @@ VERIFYURL($usr_url); ...@@ -111,7 +113,8 @@ VERIFYURL($usr_url);
# checks to make sure the two fields agree and that it passes our tests for # checks to make sure the two fields agree and that it passes our tests for
# safe passwords. # safe passwords.
# #
if (isset($new_password1) && strcmp($new_password2, "")) { if ((isset($new_password1) && strcmp($new_password1, "")) ||
(isset($new_password2) && strcmp($new_password2, ""))) {
if (strcmp($new_password1, $new_password2)) { if (strcmp($new_password1, $new_password2)) {
USERERROR("You typed different passwords in each of the two password ". USERERROR("You typed different passwords in each of the two password ".
"entry fields. <br> Please go back and correct them.", 1); "entry fields. <br> Please go back and correct them.", 1);
...@@ -137,17 +140,26 @@ if (isset($new_password1) && strcmp($new_password2, "")) { ...@@ -137,17 +140,26 @@ if (isset($new_password1) && strcmp($new_password2, "")) {
# Password is good. Insert into database. # Password is good. Insert into database.
# #
$encoding = crypt("$new_password1"); $encoding = crypt("$new_password1");
$insert_result = mysql_db_query($TBDBNAME, if ($uid != $target_uid)
"UPDATE users SET usr_pswd=\"$encoding\" ". $expires = "now()";
"WHERE uid=\"$target_uid\""); else
$expires = "date_add(now(), interval 1 year)";
$insert_result =
DBQueryFatal("UPDATE users SET usr_pswd='$encoding', ".
"pswd_expires=$expires ".
"WHERE uid='$target_uid'");
if (! $insert_result) {
$err = mysql_error();
TBERROR("Database Error changing password for $target_uid: $err", 1);
}
$changed_password = "Yes"; $changed_password = "Yes";
} }
#
# Okay, draw the header now that the password has been changed.
# This is a convenience to avoid asking the user to refresh after
# an expired password.
#
PAGEHEADER("Modify User Information");
# #
# Add slashes. These should really be ereg checks, kicking back special # Add slashes. These should really be ereg checks, kicking back special
# chars since they are more trouble then they are worth. # chars since they are more trouble then they are worth.
...@@ -161,20 +173,15 @@ $usr_phone = addslashes($usr_phone); ...@@ -161,20 +173,15 @@ $usr_phone = addslashes($usr_phone);
# #
# Now change the rest of the information. # Now change the rest of the information.
# #
$insert_result = mysql_db_query($TBDBNAME, $insert_result =
"UPDATE users SET ". DBQueryFatal("UPDATE users SET ".
"usr_name=\"$usr_name\", ". "usr_name=\"$usr_name\", ".
"usr_URL=\"$usr_url\", ". "usr_URL=\"$usr_url\", ".
"usr_addr=\"$usr_addr\", ". "usr_addr=\"$usr_addr\", ".
"usr_phone=\"$usr_phone\", ". "usr_phone=\"$usr_phone\", ".
"usr_title=\"$usr_title\", ". "usr_title=\"$usr_title\", ".
"usr_affil=\"$usr_affil\" ". "usr_affil=\"$usr_affil\" ".
"WHERE uid=\"$target_uid\""); "WHERE uid=\"$target_uid\"");
if (! $insert_result) {
$err = mysql_error();
TBERROR("Database Error changing user info for $target_uid: $err", 1);
}
# #
# Audit # Audit
......
...@@ -253,10 +253,12 @@ if (! $returning) { ...@@ -253,10 +253,12 @@ if (! $returning) {
$newuser_command = "INSERT INTO users ". $newuser_command = "INSERT INTO users ".
"(uid,usr_created,usr_expires,usr_name,usr_email,usr_addr,". "(uid,usr_created,usr_expires,usr_name,usr_email,usr_addr,".
"usr_URL,usr_title,usr_affil,usr_phone,usr_pswd,unix_uid,status) ". " usr_URL,usr_title,usr_affil,usr_phone,usr_pswd,unix_uid,".
" status,pswd_expires) ".
"VALUES ('$proj_head_uid', now(), '$proj_expires', '$usr_name', ". "VALUES ('$proj_head_uid', now(), '$proj_expires', '$usr_name', ".
"'$usr_email', '$usr_addr', '$usr_url', '$usr_title', '$usr_affil', ". "'$usr_email', '$usr_addr', '$usr_url', '$usr_title', '$usr_affil', ".
"'$usr_phones', '$encoding', NULL, 'newuser')"; "'$usr_phones', '$encoding', NULL, 'newuser', ".
"date_add(now(), interval 1 year))";
DBQueryFatal($newuser_command); DBQueryFatal($newuser_command);
......
...@@ -14,9 +14,8 @@ $uid = GETLOGIN(); ...@@ -14,9 +14,8 @@ $uid = GETLOGIN();
# personal information for some random ?uid argument. # personal information for some random ?uid argument.
# #
if ($uid) { if ($uid) {
if (CHECKLOGIN($uid) != 1) { LOGGEDINORDIE($uid);
USERERROR("You are not logged in. Please log in and try again.", 1);
}
$query_result = mysql_db_query($TBDBNAME, $query_result = mysql_db_query($TBDBNAME,
"SELECT * FROM users WHERE uid=\"$uid\""); "SELECT * FROM users WHERE uid=\"$uid\"");
if (! $query_result) { if (! $query_result) {
......
...@@ -7,6 +7,7 @@ $CHECKLOGIN_NOTLOGGEDIN = 0; ...@@ -7,6 +7,7 @@ $CHECKLOGIN_NOTLOGGEDIN = 0;
$CHECKLOGIN_LOGGEDIN = 1; $CHECKLOGIN_LOGGEDIN = 1;
$CHECKLOGIN_TIMEDOUT = -1; $CHECKLOGIN_TIMEDOUT = -1;
$CHECKLOGIN_MAYBEVALID = 2; $CHECKLOGIN_MAYBEVALID = 2;
$CHECKLOGIN_PSWDEXPIRED = 3;
# #
# Generate a hash value suitable for authorization. We use the results of # Generate a hash value suitable for authorization. We use the results of
...@@ -31,12 +32,15 @@ function GENHASH() { ...@@ -31,12 +32,15 @@ function GENHASH() {
# logged in. # logged in.
# #
function GETLOGIN() { function GETLOGIN() {
global $CHECKLOGIN_LOGGEDIN; global $CHECKLOGIN_LOGGEDIN, $CHECKLOGIN_PSWDEXPIRED;
if (($uid = GETUID()) == FALSE) if (($uid = GETUID()) == FALSE)
return FALSE; return FALSE;
if (CHECKLOGIN($uid) == $CHECKLOGIN_LOGGEDIN) $check = CHECKLOGIN($uid);
if ($check == $CHECKLOGIN_LOGGEDIN ||
$check == $CHECKLOGIN_PSWDEXPIRED)
return $uid; return $uid;
return FALSE; return FALSE;
...@@ -68,28 +72,36 @@ function GETUID() { ...@@ -68,28 +72,36 @@ function GETUID() {
# if login record exists, is not timed out, but no hash cookie. # if login record exists, is not timed out, but no hash cookie.
# this case will be caught later when the user tries to do # this case will be caught later when the user tries to do
# something for which a valid login is required. # something for which a valid login is required.
# if logged in okay but password is expired.
# #
function CHECKLOGIN($uid) { function CHECKLOGIN($uid) {
global $TBDBNAME, $TBAUTHCOOKIE, $HTTP_COOKIE_VARS, $TBAUTHTIMEOUT; global $TBDBNAME, $TBAUTHCOOKIE, $HTTP_COOKIE_VARS, $TBAUTHTIMEOUT;
global $CHECKLOGIN_NOTLOGGEDIN, $CHECKLOGIN_LOGGEDIN; global $CHECKLOGIN_NOTLOGGEDIN, $CHECKLOGIN_LOGGEDIN;
global $CHECKLOGIN_TIMEDOUT, $CHECKLOGIN_MAYBEVALID; global $CHECKLOGIN_TIMEDOUT, $CHECKLOGIN_MAYBEVALID;
global $CHECKLOGIN_PSWDEXPIRED;
$curhash = $HTTP_COOKIE_VARS[$TBAUTHCOOKIE]; $curhash = $HTTP_COOKIE_VARS[$TBAUTHCOOKIE];
$query_result = mysql_db_query($TBDBNAME, $query_result =
"SELECT hashkey, timeout FROM login WHERE uid=\"$uid\""); DBQueryFatal("select NOW()>=u.pswd_expires,l.hashkey,l.timeout ".
if (! $query_result) { " from users as u ".
$err = mysql_error(); "left join login as l on l.uid=u.uid ".
TBERROR("Database Error retrieving login info for $uid: $err\n", 1); "where u.uid='$uid'");
}
# Not logged in. # No such user.
if (($row = mysql_fetch_array($query_result)) == 0) { if (($row = mysql_fetch_row($query_result)) == 0) {
return $CHECKLOGIN_NOTLOGGEDIN; return $CHECKLOGIN_NOTLOGGEDIN;
} }
$hashkey = $row[hashkey]; $expired = $row[0];
$timeout = $row[timeout]; $hashkey = $row[1];
$timeout = $row[2];
#
# If user exists, but login has no entry, quit now.
#
if (!$hashkey)
return $CHECKLOGIN_NOTLOGGEDIN;
# A match? # A match?
if ($timeout > time()) { if ($timeout > time()) {
...@@ -101,34 +113,32 @@ function CHECKLOGIN($uid) { ...@@ -101,34 +113,32 @@ function CHECKLOGIN($uid) {
# #
$timeout = time() + $TBAUTHTIMEOUT; $timeout = time() + $TBAUTHTIMEOUT;
$query_result = mysql_db_query($TBDBNAME, $query_result =
"UPDATE login set timeout='$timeout' ". DBQueryFatal("UPDATE login set timeout='$timeout' ".
"WHERE uid=\"$uid\""); "WHERE uid='$uid'");
if (! $query_result) {
$err = mysql_error(); if ($expired)
TBERROR("Database Error updating login timeout for ". return $CHECKLOGIN_PSWDEXPIRED;
"$uid: $err", 1); else
} return $CHECKLOGIN_LOGGEDIN;
return $CHECKLOGIN_LOGGEDIN;
} }
elseif (!isset($curhash) || !$curhash || $curhash == NULL) { elseif (!isset($curhash) || !$curhash || $curhash == NULL) {
# #
# A login is valid, but we have no proof yet. Proof will be # A login is valid, but we have no proof yet. Proof will be
# demanded later by whatever page wants it. # demanded later by whatever page wants it.
# #
return $CHECKLOGIN_MAYBEVALID; if ($expired)
return $CHECKLOGIN_PSWDEXPIRED;
else
return $CHECKLOGIN_MAYBEVALID;
} }
} }
# #
# Clear out the database entry for completeness. # Clear out the database entry for completeness.
# #
$query_result = mysql_db_query($TBDBNAME, $query_result =
"DELETE FROM login WHERE uid=\"$uid\""); DBQueryFatal("DELETE FROM login WHERE uid='$uid'");
if (! $query_result) {
$err = mysql_error();
TBERROR("Database Error deleting login info for $uid: $err\n", 1);
}
return $CHECKLOGIN_TIMEDOUT; return $CHECKLOGIN_TIMEDOUT;
} }
...@@ -140,6 +150,36 @@ function CHECKLOGIN($uid) { ...@@ -140,6 +150,36 @@ function CHECKLOGIN($uid) {
function LOGGEDINORDIE($uid) { function LOGGEDINORDIE($uid) {
global $CHECKLOGIN_NOTLOGGEDIN, $CHECKLOGIN_LOGGEDIN; global $CHECKLOGIN_NOTLOGGEDIN, $CHECKLOGIN_LOGGEDIN;
global $CHECKLOGIN_TIMEDOUT, $CHECKLOGIN_MAYBEVALID; global $CHECKLOGIN_TIMEDOUT, $CHECKLOGIN_MAYBEVALID;
global $CHECKLOGIN_PSWDEXPIRED;
$status = CHECKLOGIN($uid);
switch ($status) {
case $CHECKLOGIN_NOTLOGGEDIN:
USERERROR("You do not appear to be logged in!", 1);
break;
case $CHECKLOGIN_LOGGEDIN:
return $uid;
break;
case $CHECKLOGIN_TIMEDOUT:
USERERROR("Your login has timed out! Please log in again.", 1);
break;
case $CHECKLOGIN_MAYBEVALID:
USERERROR("Your login cannot be verified. Are cookies turned on?", 1);
break;
case $CHECKLOGIN_PSWDEXPIRED:
USERERROR("Your password has expired. Please change it now!", 1);
break;
}
TBERROR("LOGGEDINORDIE failed mysteriously", 1);
}
#
# Special function for changing passwords.
#
function LOGGEDINORDIE_SPECIAL($uid) {
global $CHECKLOGIN_NOTLOGGEDIN, $CHECKLOGIN_LOGGEDIN;
global $CHECKLOGIN_TIMEDOUT, $CHECKLOGIN_MAYBEVALID;
global $CHECKLOGIN_PSWDEXPIRED;
$status = CHECKLOGIN($uid); $status = CHECKLOGIN($uid);
switch ($status) { switch ($status) {
...@@ -147,6 +187,7 @@ function LOGGEDINORDIE($uid) { ...@@ -147,6 +187,7 @@ function LOGGEDINORDIE($uid) {
USERERROR("You do not appear to be logged in!", 1); USERERROR("You do not appear to be logged in!", 1);
break; break;
case $CHECKLOGIN_LOGGEDIN: case $CHECKLOGIN_LOGGEDIN:
case $CHECKLOGIN_PSWDEXPIRED:
return $uid; return $uid;
break; break;
case $CHECKLOGIN_TIMEDOUT: case $CHECKLOGIN_TIMEDOUT:
......
...@@ -205,11 +205,13 @@ if (! $returning) { ...@@ -205,11 +205,13 @@ if (! $returning) {
$newuser_command = "INSERT INTO users ". $newuser_command = "INSERT INTO users ".
"(uid,usr_created,usr_expires,usr_name,usr_email,usr_addr,". "(uid,usr_created,usr_expires,usr_name,usr_email,usr_addr,".
"usr_URL,usr_phone,usr_title,usr_affil,usr_pswd,unix_uid,status) ". " usr_URL,usr_phone,usr_title,usr_affil,usr_pswd,unix_uid,".
" status,pswd_expires) ".