Index: trunk/gsdl/src/recpt/authenaction.cpp
===================================================================
--- trunk/gsdl/src/recpt/authenaction.cpp	(revision 373)
+++ trunk/gsdl/src/recpt/authenaction.cpp	(revision 374)
@@ -12,4 +12,7 @@
 /*
    $Log$
+   Revision 1.3  1999/07/13 23:23:26  rjmcnab
+   Put users in their own gdbm database. Moved a lot of functionality to usersdb
+
    Revision 1.2  1999/07/11 10:47:32  rjmcnab
    Got something basic working.
@@ -28,180 +31,5 @@
 #include "infodbclass.h"
 #include "gsdltimes.h"
-
-
-/////////////////////////
-// a few useful functions
-/////////////////////////
-
-
-// reads in the password file. It returns true if successful
-// format is: username password status [groups]
-static bool read_passwd (const text_t &passwd_filename, userinfo_tmap &userinfo) {
-  text_tarray passwdline;
-  userinfo_t thisuserinfo;
-
-  userinfo.erase(userinfo.begin(), userinfo.end());
-  
-  char *cstr = passwd_filename.getcstr();
-  ifstream passwdin (cstr);
-  delete cstr;
-
-  if (passwdin) {
-    while (read_cfg_line(passwdin, passwdline) >= 0) {
-      if (passwdline.size () >= 3) {
-	// get the information about the user
-	thisuserinfo.clear();
-	thisuserinfo.username = passwdline[0];
-	thisuserinfo.password = passwdline[1];
-	if (passwdline[2] == "enabled") thisuserinfo.status = userinfo_t::enabled;
-	else thisuserinfo.status = userinfo_t::disabled;
-	if (passwdline.size() >= 4) thisuserinfo.groups = passwdline[3];
-
-	// insert the user information into the map
-	if (!thisuserinfo.username.empty()) {
-	  userinfo[thisuserinfo.username] = thisuserinfo;
-	}
-      }
-    }
-    
-    passwdin.close ();
-    return true;
-  }
-
-  return false;
-}
-
-// returns true if the user was found, false otherwise
-static bool get_user_info (const userinfo_tmap &userinfo, const text_t &username,
-			   userinfo_t &thisuser) {
-  thisuser.clear();
-
-  userinfo_tmap::const_iterator thisuser_here = userinfo.find (username);
-  if (thisuser_here != userinfo.end()) {
-    thisuser = (*thisuser_here).second;
-    return true;
-  }
-  
-  return false;
-}
-
-// return true if the password matches, false if it doesn't
-static bool check_passwd (const userinfo_t &thisuser, const text_t &password) {
-  if (!thisuser.username.empty() && !thisuser.password.empty() &&
-      !password.empty() && thisuser.password == password) return true;
-
-  return false;
-}
-
-// returns true if the key is still valid for this user,
-// and false otherwise
-static bool check_key (const text_t &keyfile, const userinfo_t &thisuser,
-		       const text_t &key, const text_t &group, int keydecay,
-		       ostream &logout) {
-  outconvertclass text_t2ascii;
-
-  if (keyfile.empty() || thisuser.username.empty() ||
-      key.empty()) return false;
-
-  // the keydecay is set to 1/2 minute for things requiring the
-  // administrator
-  if (group == "administrator") keydecay = 30;
-  
-  // open the key database
-  gdbmclass keydb;
-  if (!keydb.opendatabase (keyfile, GDBM_WRCREAT, 1000)) {
-    logout << text_t2ascii << "Error: write open failed for key database \""
-	   << keyfile << "\"\n";
-    return false; // failed
-  }
-
-  // success if there is a key in the key database that is owned by this
-  // user whose creation time is less that keydecay
-  infodbclass info;
-  bool success = false;
-  if (keydb.getinfo (key, info))  {
-    if (info["user"] == thisuser.username) {
-      time_t keycreation = text2time (info["time"]);
-      if (keycreation == (time_t)-1) {
-	logout << text_t2ascii << "Error: failed to convert an authentication "
-	  "key into its equivalent time_t. Time text was \"" << info["time"]
-	       << "\" for key \"" << key << "\"\n";
-
-      } else if (difftime (time(NULL), keycreation) <= keydecay) {
-	// succeeded, update the key's time
-	success = true;
-	info["time"] = time2text(time(NULL));
-	if (!keydb.setinfo (key, info)) {
-	  logout << text_t2ascii << "Error: setinfo failed for key database \""
-		 << keyfile << "\"\n";
-	}
-      }
-    }
-  }
-
-  // close the database
-  keydb.closedatabase();
-
-  return success;
-}
-
-
-static text_t generate_key (const text_t &keyfile, const text_t &username,
-			    ostream &logout) {
-  static const char *numconvert = "0123456789abcdefghijklmnopqrstuvwxyz"
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-  outconvertclass text_t2ascii;
-  
-  // open the key database
-  gdbmclass keydb;
-  if (!keydb.opendatabase (keyfile, GDBM_WRCREAT, 1000)) {
-    logout << text_t2ascii << "Error: write open failed for key database \""
-	   << keyfile << "\"\n";
-    return ""; // failed
-  }
-
-  // loop looking for a suitable new key
-  text_t userkey;
-  do {
-    int userkey_int = rand ();
-    while (userkey_int > 0) {
-      userkey.push_back (numconvert[userkey_int%62]);
-      userkey_int /= 62;
-    }
-
-    // make sure this key is not in the database
-    if (keydb.exists (userkey)) userkey.clear();
-  } while (userkey.empty());
-
-  // enter the key into the database
-  infodbclass keydata;
-  keydata["user"] = username;
-  keydata["time"] = time2text(time(NULL));
-  
-  if (!keydb.setinfo (userkey, keydata)) {
-    logout << text_t2ascii << "Error: setinfo failed for key database \""
-	   << keyfile << "\"\n";
-    userkey.clear(); // failed
-  }
-  
-  // close the database
-  keydb.closedatabase();
-  
-  return userkey;
-}
-
-
-/////////////
-// userinfo_t
-/////////////
-
-
-void userinfo_t::clear () {
-  username.clear();
-  password.clear();
-  status = invalid;
-  groups.clear();
-}
-
+#include "userdb.h"
 
 
@@ -301,10 +129,10 @@
   // get the password filename
   if (cfgline.size() == 1) {
-    if (key == "passwdfile") passwdfile = cfgline[0];
+    if (key == "usersfile") usersfile = cfgline[0];
     else if (key == "keyfile") keyfile = cfgline[0];
     else if (key == "keydecay") keydecay = cfgline[0].getint();
     else if (key == "gsdlhome") {
-      if (passwdfile.empty())
-	passwdfile = filename_cat (cfgline[0], "etc", "passwd");
+      if (usersfile.empty())
+	usersfile = filename_cat (cfgline[0], "etc", "users.db");
       if (keyfile.empty())
 	keyfile = filename_cat (cfgline[0], "etc", "key.db");
@@ -316,13 +144,4 @@
 
 bool authenaction::init (ostream &logout) {
-  outconvertclass text_t2ascii;
-    
-  // read in the password file
-  if (!read_passwd (passwdfile, userinfo)) {
-    logout << text_t2ascii << "Error: could not read in the password file "
-	   << passwdfile << "\n";
-    return false;
-  }
-    
   return action::init (logout);
 }
@@ -340,5 +159,4 @@
 					   const text_t &saveconf,
 					   ostream &logout) {
-  // success will be dealt with using a redirect in get_cgihead_info if neede
   // failure means we have to redirect to this action to get authentication
   // (if we are not already doing this)
@@ -346,12 +164,11 @@
   userinfo_t thisuser;
 
-  text_t &args_uan = args["uan"];
-  text_t &args_un = args["un"];
-  text_t &args_pw = args["pw"];
-  text_t &args_us = args["us"];
-  text_t &args_ug = args["ug"];
-  text_t &args_ky = args["ky"];
+  text_t &args_uan = args["uan"];  text_t &args_un = args["un"];
+  text_t &args_pw = args["pw"];    text_t &args_us = args["us"];
+  text_t &args_ug = args["ug"];    text_t &args_ky = args["ky"];
   text_t &args_ua = args["ua"];
-  
+
+  // we must have a username and a password or a key to
+  // do any authentication
   args_ua.clear(); // default = false;
   if (args_un.empty() || args_pw.empty()) args_us = "invalid";
@@ -359,15 +176,12 @@
 
   // make sure we have a username
-  if (!args_un.empty() && get_user_info (userinfo, args_un, thisuser)) {
+  if (!args_un.empty() && get_user_info (usersfile, args_un, thisuser)) {
     if (!args_pw.empty()) {
       // we are authenticating using a password
-      if (check_passwd (thisuser, args_pw)) {
-	args_ua = "1"; // succeeded
-      }
+      if (check_passwd (thisuser, args_pw)) args_ua = "1"; // succeeded
       
     } else if (!args_ky.empty()) {
       // we are authenticating using a key
-      if (check_key (keyfile, thisuser, args_ky, args_ug, keydecay, logout))
-	args_ua = "1";
+      if (check_key (keyfile, thisuser, args_ky, args_ug, keydecay)) args_ua = "1";
       else args_us = "stalekey";
     }
@@ -375,10 +189,10 @@
 
   args_pw.clear(); // password goes no further
-  
   if (!args_ua.empty()) {
-    if (thisuser.status==userinfo_t::enabled) {
+    if (thisuser.enabled) {
+      bool haspermission = true;
       // check to make sure the user is in the required group
       if (!args_ug.empty()) {
-	thisuser.status = userinfo_t::permissiondenied;
+	haspermission = false;
 	text_t::const_iterator group_here = thisuser.groups.begin();
 	text_t::const_iterator group_end = thisuser.groups.end();
@@ -387,5 +201,5 @@
 	  group_here = getdelimitstr (group_here, group_end, ',', thisgroup);
 	  if (thisgroup == args_ug) {
-	    thisuser.status = userinfo_t::enabled;
+	    haspermission = true;
 	    break;
 	  }
@@ -393,10 +207,12 @@
       }
 
-      if (thisuser.status==userinfo_t::enabled) {
+      if (haspermission) {
 	// succeeded, get info about this user
-	// note: we don't need to set "ug" as it is already set to
-	// what it needs to be
+	// note: we don't need to set "ug" as it is already set to what it needs to be
 	args_us = "enabled";
-	args_ky = generate_key (keyfile, args_un, logout); // new key
+	args_ky = generate_key (keyfile, args_un); // new key
+
+	// delete old keys around every 50 accesses
+	if (rand()%50 == 1) remove_old_keys (keyfile, keydecay);
 	
       } else {
@@ -406,6 +222,6 @@
 	args_ug.clear();
 	args_ky.clear();
-	
       }
+
     } else {
       // succeeded, however, the account is disabled
Index: trunk/gsdl/src/recpt/authenaction.h
===================================================================
--- trunk/gsdl/src/recpt/authenaction.h	(revision 373)
+++ trunk/gsdl/src/recpt/authenaction.h	(revision 374)
@@ -19,21 +19,4 @@
 #include "receptionist.h"
 
-// information about a single user
-struct userinfo_t {
-  void clear ();
-  userinfo_t () {clear();}
-
-  enum status_t {enabled, disabled, invalid, failed, permissiondenied};
-  
-  text_t username;
-  text_t password;
-  status_t status;
-  text_t groups; // comma separated list
-};
-
-// information about all the users
-typedef map<text_t, userinfo_t, lttext_t> userinfo_tmap;
-
-
 
 // note: you need to tell this action about the receptionist
@@ -42,9 +25,7 @@
 class authenaction : public action {
 protected:
-  text_t passwdfile;
+  text_t usersfile;
   text_t keyfile;
   int keydecay;
-
-  userinfo_tmap userinfo;
 
   receptionist *recpt;
