Ignore:
Timestamp:
1999-07-14T11:23:26+12:00 (25 years ago)
Author:
rjmcnab
Message:

Put users in their own gdbm database. Moved a lot of functionality to usersdb

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/gsdl/src/recpt/authenaction.cpp

    r369 r374  
    1212/*
    1313   $Log$
     14   Revision 1.3  1999/07/13 23:23:26  rjmcnab
     15   Put users in their own gdbm database. Moved a lot of functionality to usersdb
     16
    1417   Revision 1.2  1999/07/11 10:47:32  rjmcnab
    1518   Got something basic working.
     
    2831#include "infodbclass.h"
    2932#include "gsdltimes.h"
    30 
    31 
    32 /////////////////////////
    33 // a few useful functions
    34 /////////////////////////
    35 
    36 
    37 // reads in the password file. It returns true if successful
    38 // format is: username password status [groups]
    39 static bool read_passwd (const text_t &passwd_filename, userinfo_tmap &userinfo) {
    40   text_tarray passwdline;
    41   userinfo_t thisuserinfo;
    42 
    43   userinfo.erase(userinfo.begin(), userinfo.end());
    44  
    45   char *cstr = passwd_filename.getcstr();
    46   ifstream passwdin (cstr);
    47   delete cstr;
    48 
    49   if (passwdin) {
    50     while (read_cfg_line(passwdin, passwdline) >= 0) {
    51       if (passwdline.size () >= 3) {
    52     // get the information about the user
    53     thisuserinfo.clear();
    54     thisuserinfo.username = passwdline[0];
    55     thisuserinfo.password = passwdline[1];
    56     if (passwdline[2] == "enabled") thisuserinfo.status = userinfo_t::enabled;
    57     else thisuserinfo.status = userinfo_t::disabled;
    58     if (passwdline.size() >= 4) thisuserinfo.groups = passwdline[3];
    59 
    60     // insert the user information into the map
    61     if (!thisuserinfo.username.empty()) {
    62       userinfo[thisuserinfo.username] = thisuserinfo;
    63     }
    64       }
    65     }
    66    
    67     passwdin.close ();
    68     return true;
    69   }
    70 
    71   return false;
    72 }
    73 
    74 // returns true if the user was found, false otherwise
    75 static bool get_user_info (const userinfo_tmap &userinfo, const text_t &username,
    76                userinfo_t &thisuser) {
    77   thisuser.clear();
    78 
    79   userinfo_tmap::const_iterator thisuser_here = userinfo.find (username);
    80   if (thisuser_here != userinfo.end()) {
    81     thisuser = (*thisuser_here).second;
    82     return true;
    83   }
    84  
    85   return false;
    86 }
    87 
    88 // return true if the password matches, false if it doesn't
    89 static bool check_passwd (const userinfo_t &thisuser, const text_t &password) {
    90   if (!thisuser.username.empty() && !thisuser.password.empty() &&
    91       !password.empty() && thisuser.password == password) return true;
    92 
    93   return false;
    94 }
    95 
    96 // returns true if the key is still valid for this user,
    97 // and false otherwise
    98 static bool check_key (const text_t &keyfile, const userinfo_t &thisuser,
    99                const text_t &key, const text_t &group, int keydecay,
    100                ostream &logout) {
    101   outconvertclass text_t2ascii;
    102 
    103   if (keyfile.empty() || thisuser.username.empty() ||
    104       key.empty()) return false;
    105 
    106   // the keydecay is set to 1/2 minute for things requiring the
    107   // administrator
    108   if (group == "administrator") keydecay = 30;
    109  
    110   // open the key database
    111   gdbmclass keydb;
    112   if (!keydb.opendatabase (keyfile, GDBM_WRCREAT, 1000)) {
    113     logout << text_t2ascii << "Error: write open failed for key database \""
    114        << keyfile << "\"\n";
    115     return false; // failed
    116   }
    117 
    118   // success if there is a key in the key database that is owned by this
    119   // user whose creation time is less that keydecay
    120   infodbclass info;
    121   bool success = false;
    122   if (keydb.getinfo (key, info))  {
    123     if (info["user"] == thisuser.username) {
    124       time_t keycreation = text2time (info["time"]);
    125       if (keycreation == (time_t)-1) {
    126     logout << text_t2ascii << "Error: failed to convert an authentication "
    127       "key into its equivalent time_t. Time text was \"" << info["time"]
    128            << "\" for key \"" << key << "\"\n";
    129 
    130       } else if (difftime (time(NULL), keycreation) <= keydecay) {
    131     // succeeded, update the key's time
    132     success = true;
    133     info["time"] = time2text(time(NULL));
    134     if (!keydb.setinfo (key, info)) {
    135       logout << text_t2ascii << "Error: setinfo failed for key database \""
    136          << keyfile << "\"\n";
    137     }
    138       }
    139     }
    140   }
    141 
    142   // close the database
    143   keydb.closedatabase();
    144 
    145   return success;
    146 }
    147 
    148 
    149 static text_t generate_key (const text_t &keyfile, const text_t &username,
    150                 ostream &logout) {
    151   static const char *numconvert = "0123456789abcdefghijklmnopqrstuvwxyz"
    152     "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    153   outconvertclass text_t2ascii;
    154  
    155   // open the key database
    156   gdbmclass keydb;
    157   if (!keydb.opendatabase (keyfile, GDBM_WRCREAT, 1000)) {
    158     logout << text_t2ascii << "Error: write open failed for key database \""
    159        << keyfile << "\"\n";
    160     return ""; // failed
    161   }
    162 
    163   // loop looking for a suitable new key
    164   text_t userkey;
    165   do {
    166     int userkey_int = rand ();
    167     while (userkey_int > 0) {
    168       userkey.push_back (numconvert[userkey_int%62]);
    169       userkey_int /= 62;
    170     }
    171 
    172     // make sure this key is not in the database
    173     if (keydb.exists (userkey)) userkey.clear();
    174   } while (userkey.empty());
    175 
    176   // enter the key into the database
    177   infodbclass keydata;
    178   keydata["user"] = username;
    179   keydata["time"] = time2text(time(NULL));
    180  
    181   if (!keydb.setinfo (userkey, keydata)) {
    182     logout << text_t2ascii << "Error: setinfo failed for key database \""
    183        << keyfile << "\"\n";
    184     userkey.clear(); // failed
    185   }
    186  
    187   // close the database
    188   keydb.closedatabase();
    189  
    190   return userkey;
    191 }
    192 
    193 
    194 /////////////
    195 // userinfo_t
    196 /////////////
    197 
    198 
    199 void userinfo_t::clear () {
    200   username.clear();
    201   password.clear();
    202   status = invalid;
    203   groups.clear();
    204 }
    205 
     33#include "userdb.h"
    20634
    20735
     
    301129  // get the password filename
    302130  if (cfgline.size() == 1) {
    303     if (key == "passwdfile") passwdfile = cfgline[0];
     131    if (key == "usersfile") usersfile = cfgline[0];
    304132    else if (key == "keyfile") keyfile = cfgline[0];
    305133    else if (key == "keydecay") keydecay = cfgline[0].getint();
    306134    else if (key == "gsdlhome") {
    307       if (passwdfile.empty())
    308     passwdfile = filename_cat (cfgline[0], "etc", "passwd");
     135      if (usersfile.empty())
     136    usersfile = filename_cat (cfgline[0], "etc", "users.db");
    309137      if (keyfile.empty())
    310138    keyfile = filename_cat (cfgline[0], "etc", "key.db");
     
    316144
    317145bool authenaction::init (ostream &logout) {
    318   outconvertclass text_t2ascii;
    319    
    320   // read in the password file
    321   if (!read_passwd (passwdfile, userinfo)) {
    322     logout << text_t2ascii << "Error: could not read in the password file "
    323        << passwdfile << "\n";
    324     return false;
    325   }
    326    
    327146  return action::init (logout);
    328147}
     
    340159                       const text_t &saveconf,
    341160                       ostream &logout) {
    342   // success will be dealt with using a redirect in get_cgihead_info if neede
    343161  // failure means we have to redirect to this action to get authentication
    344162  // (if we are not already doing this)
     
    346164  userinfo_t thisuser;
    347165
    348   text_t &args_uan = args["uan"];
    349   text_t &args_un = args["un"];
    350   text_t &args_pw = args["pw"];
    351   text_t &args_us = args["us"];
    352   text_t &args_ug = args["ug"];
    353   text_t &args_ky = args["ky"];
     166  text_t &args_uan = args["uan"];  text_t &args_un = args["un"];
     167  text_t &args_pw = args["pw"];    text_t &args_us = args["us"];
     168  text_t &args_ug = args["ug"];    text_t &args_ky = args["ky"];
    354169  text_t &args_ua = args["ua"];
    355  
     170
     171  // we must have a username and a password or a key to
     172  // do any authentication
    356173  args_ua.clear(); // default = false;
    357174  if (args_un.empty() || args_pw.empty()) args_us = "invalid";
     
    359176
    360177  // make sure we have a username
    361   if (!args_un.empty() && get_user_info (userinfo, args_un, thisuser)) {
     178  if (!args_un.empty() && get_user_info (usersfile, args_un, thisuser)) {
    362179    if (!args_pw.empty()) {
    363180      // we are authenticating using a password
    364       if (check_passwd (thisuser, args_pw)) {
    365     args_ua = "1"; // succeeded
    366       }
     181      if (check_passwd (thisuser, args_pw)) args_ua = "1"; // succeeded
    367182     
    368183    } else if (!args_ky.empty()) {
    369184      // we are authenticating using a key
    370       if (check_key (keyfile, thisuser, args_ky, args_ug, keydecay, logout))
    371     args_ua = "1";
     185      if (check_key (keyfile, thisuser, args_ky, args_ug, keydecay)) args_ua = "1";
    372186      else args_us = "stalekey";
    373187    }
     
    375189
    376190  args_pw.clear(); // password goes no further
    377  
    378191  if (!args_ua.empty()) {
    379     if (thisuser.status==userinfo_t::enabled) {
     192    if (thisuser.enabled) {
     193      bool haspermission = true;
    380194      // check to make sure the user is in the required group
    381195      if (!args_ug.empty()) {
    382     thisuser.status = userinfo_t::permissiondenied;
     196    haspermission = false;
    383197    text_t::const_iterator group_here = thisuser.groups.begin();
    384198    text_t::const_iterator group_end = thisuser.groups.end();
     
    387201      group_here = getdelimitstr (group_here, group_end, ',', thisgroup);
    388202      if (thisgroup == args_ug) {
    389         thisuser.status = userinfo_t::enabled;
     203        haspermission = true;
    390204        break;
    391205      }
     
    393207      }
    394208
    395       if (thisuser.status==userinfo_t::enabled) {
     209      if (haspermission) {
    396210    // succeeded, get info about this user
    397     // note: we don't need to set "ug" as it is already set to
    398     // what it needs to be
     211    // note: we don't need to set "ug" as it is already set to what it needs to be
    399212    args_us = "enabled";
    400     args_ky = generate_key (keyfile, args_un, logout); // new key
     213    args_ky = generate_key (keyfile, args_un); // new key
     214
     215    // delete old keys around every 50 accesses
     216    if (rand()%50 == 1) remove_old_keys (keyfile, keydecay);
    401217   
    402218      } else {
     
    406222    args_ug.clear();
    407223    args_ky.clear();
    408    
    409224      }
     225
    410226    } else {
    411227      // succeeded, however, the account is disabled
Note: See TracChangeset for help on using the changeset viewer.