Changeset 13844


Ignore:
Timestamp:
2007-02-01T16:30:11+13:00 (17 years ago)
Author:
mdewsnip
Message:

Jeffrey's (DL Consulting) changes to userdb to make it a proper class, so it can be easily extended for collection-specific receptionists.

Location:
trunk/gsdl/src/recpt
Files:
5 edited

Legend:

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

    r9620 r13844  
    169169  if (args["uan"].empty()) return true;
    170170
     171  userdbclass *user_database = new userdbclass(usersfile);
     172  keydbclass *key_database = new keydbclass(keyfile);
    171173
    172174  // failure means we have to redirect to this action to get authentication
     
    187189
    188190  // make sure we have a username
    189   if (!args_un.empty() && get_user_info (usersfile, args_un, thisuser)) {
     191  if (!args_un.empty() && (user_database->get_user_info (args_un, thisuser) == ERRNO_SUCCEED)) {
    190192    if (!args_pw.empty()) {
    191193      // we are authenticating using a password
    192       if (check_passwd (thisuser, args_pw)) args_ua = "1"; // succeeded
     194      if (user_database->check_passwd (thisuser.username, args_pw) == ERRNO_SUCCEED) args_ua = "1"; // succeeded
    193195     
    194196    } else if (!args_ky.empty()) {
    195197      // we are authenticating using a key
    196       if (check_key (keyfile, thisuser, args_ky, args_ug, keydecay)) args_ua = "1";
     198      if (key_database->check_key(thisuser, args_ky, args_ug, keydecay)) args_ua = "1";
    197199      else args_us = "stalekey";
    198200    }
     
    245247     // note: we don't need to set "ug" as it is already set to what it needs to be
    246248     args_us = "enabled";
    247     args_ky = generate_key (keyfile, args_un); // new key
     249     args_ky = key_database->generate_key(args_un); // new key
    248250   
    249251    // delete old keys around every 50 accesses
    250     if (rand()%50 == 1) remove_old_keys (keyfile, keydecay);
     252    if (rand()%50 == 1) key_database->remove_old_keys(keydecay);
    251253   
    252254      } else {
  • trunk/gsdl/src/recpt/userdb.cpp

    r9620 r13844  
    4141#endif
    4242
    43 
    44 // few useful functions
    45 
    46 text_t crypt_text (const text_t &text) {
    47   static const char *salt = "Tp";
    48   text_t crypt_password;
    49 
    50   if (text.empty()) return g_EmptyText;
    51 
    52   // encrypt the password
    53   char *text_cstr = text.getcstr();
    54   if (text_cstr == NULL) return g_EmptyText;
    55   crypt_password = crypt(text_cstr, salt);
    56   delete []text_cstr;
    57 
    58   return crypt_password;
    59 }
    60 
    61 
    62 // username_ok tests to make sure a username is ok. a username
    63 // must be at least 2 characters long, but no longer than 30
    64 // characters long. it can contain the characters a-z A-Z 0-9
    65 // . and _
    66 bool username_ok (const text_t &username) {
    67   if (username.size() < 2 || username.size() > 30) return false;
    68 
    69   text_t::const_iterator here = username.begin();
    70   text_t::const_iterator end = username.end();
    71   while (here != end) {
    72     if ((*here >= 'a' && *here <= 'z') ||
    73     (*here >= 'A' && *here <= 'Z') ||
    74     (*here >= '0' && *here <= '9') ||
    75     *here == '.' ||
    76     *here == '_') {
    77       // ok
    78     } else return false;
    79     ++here;
    80   }
    81 
    82   return true;
    83 }
    84 
    85 // password_ok tests to make sure a password is ok. a password
    86 // must be at least 3 characters long but no longer than 8 characters
    87 // long. it can contain any character in the range 0x20-0x7e
    88 bool password_ok (const text_t &password) {
    89   if (password.size() < 3 || password.size() > 8) return false;
    90 
    91   text_t::const_iterator here = password.begin();
    92   text_t::const_iterator end = password.end();
    93   while (here != end) {
    94     if (*here >= 0x20 && *here <= 0x7e) {
    95       // ok
    96     } else return false;
    97     ++here;
    98   }
    99 
    100   return true;
    101 }
    102 
    103 
    104 
    105 
    106 /////////////
    107 // userinfo_t
    108 /////////////
     43//==========================================//
     44//      userinfo_t functions (Start)        //
     45//==========================================//
     46userinfo_t::userinfo_t()
     47{
     48  clear();
     49}
     50
     51userinfo_t::~userinfo_t(){};
    10952
    11053void userinfo_t::clear () {
     
    12568  return *this;
    12669}
    127 
    128 
    129 
    130 // functions dealing with user databases
    131 
    132 // returns true on success (in which case userinfo will contain
    133 // the information for this user)
    134 bool get_user_info (gdbmclass &userdb, const text_t &username,
    135             userinfo_t &userinfo) {
    136   userinfo.clear();
     70//==========================================//
     71//       userinfo_t functions (END)         //
     72//==========================================//
     73
     74//==========================================//
     75//      userdbclass functions (Start)       //
     76//==========================================//
     77userdbclass::userdbclass(const text_t &userdbfilename)
     78{
     79  activated = (!userdb.opendatabase(userdbfilename, GDBM_WRCREAT, 1000, true)) ? false : true;
     80  external_db = false;
     81}
     82
     83userdbclass::userdbclass(const gdbmclass &external_userdb)
     84{
     85  userdb = external_userdb;
     86  activated = true;
     87  external_db = true;
     88}
     89
     90userdbclass::~userdbclass()
     91{
     92  if (external_db == false) { userdb.closedatabase();}
     93}
     94
     95// few useful functions
     96text_t userdbclass::crypt_text (const text_t &text)
     97{
     98  static const char *salt = "Tp";
     99  text_t crypt_password;
    137100 
    138   infodbclass info;
    139   if (userdb.getinfo (username, info)) {
    140     userinfo.username = info["username"];
    141     userinfo.password = info["password"];
    142     userinfo.enabled = (info["enabled"] == "true");
    143     userinfo.groups = info["groups"];
    144     userinfo.comment = info["comment"];
    145     return true;
     101  if (text.empty()) return g_EmptyText;
     102 
     103  // encrypt the password
     104  char *text_cstr = text.getcstr();
     105  if (text_cstr == NULL) return g_EmptyText;
     106  crypt_password = crypt(text_cstr, salt);
     107  delete []text_cstr;
     108
     109  return crypt_password;
     110}
     111
     112// username_ok tests to make sure a username is ok. a username
     113// must be at least 2 characters long, but no longer than 30
     114// characters long. it can contain the characters a-z A-Z 0-9
     115// . and _
     116bool userdbclass::username_ok (const text_t &username)
     117{
     118  if (username.size() < 2 || username.size() > 30) return false;
     119
     120  text_t::const_iterator here = username.begin();
     121  text_t::const_iterator end = username.end();
     122  while (here != end)
     123    {
     124      if ((*here >= 'a' && *here <= 'z') ||
     125          (*here >= 'A' && *here <= 'Z') ||
     126          (*here >= '0' && *here <= '9') ||
     127          *here == '.' ||
     128          *here == '_')
     129        {
     130          // ok
     131        } else return false;
     132      ++here;
     133    }
     134 
     135  return true;
     136}
     137
     138// password_ok tests to make sure a password is ok. a password
     139// must be at least 3 characters long but no longer than 8 characters
     140// long. it can contain any character in the range 0x20-0x7e
     141bool userdbclass::password_ok (const text_t &password)
     142{
     143  if (password.size() < 3 || password.size() > 8) return false;
     144
     145  text_t::const_iterator here = password.begin();
     146  text_t::const_iterator end = password.end();
     147  while (here != end) {
     148    if (*here >= 0x20 && *here <= 0x7e)
     149      {
     150        // ok
     151      } else return false;
     152    ++here;
    146153  }
    147154
    148   return false;
    149 }
    150 
    151 bool get_user_info (const text_t &userdbfile, const text_t &username,
    152             userinfo_t &userinfo) {
    153   gdbmclass userdb;
    154   if (!userdb.opendatabase(userdbfile, GDBM_READER, 1000, true)) {
    155 /*    if (!userdbfile.empty() && !file_exists (userdbfile) &&
    156     username == "admin") {*/
    157     if (!userdbfile.empty() && username == "admin") {
    158       // no database -- create a database with an initial account
    159       userinfo.clear();
    160       userinfo.username = "admin";
    161       userinfo.password = crypt_text("admin");
    162       userinfo.enabled = true;
    163       userinfo.groups = "administrator,colbuilder";
    164       userinfo.comment = "change the password for this account as soon as possible";
    165       return set_user_info (userdbfile, username, userinfo);
    166     }
    167     return false;
    168   }
    169 
    170   bool success = get_user_info (userdb, username, userinfo);
    171   userdb.closedatabase();
    172 
    173   return success;
    174 }
    175 
    176 // returns true on success
    177 bool set_user_info (gdbmclass &userdb, const text_t &username,
    178             const userinfo_t &userinfo) {
    179   infodbclass info;
    180   info["username"] = userinfo.username;
    181   info["password"] = userinfo.password;
    182   info["enabled"] = userinfo.enabled ? "true" : "false";
    183   info["groups"] = userinfo.groups;
    184   info["comment"] = userinfo.comment;
    185 
    186   return userdb.setinfo (username, info);
    187 }
    188 
    189 bool set_user_info (const text_t &userdbfile, const text_t &username,
    190             const userinfo_t &userinfo) {
    191   gdbmclass userdb;
    192   if (!userdb.opendatabase(userdbfile, GDBM_WRCREAT, 1000, true)) return false;
    193 
    194   bool success = set_user_info (userdb, username, userinfo);
    195   userdb.closedatabase();
    196 
    197   return success;
    198 }
    199 
    200 // removes a user from the user database -- forever
    201 void delete_user (gdbmclass &userdb, const text_t &username) {
    202   userdb.deletekey (username);
    203 }
    204 
    205 void delete_user (const text_t &userdbfile, const text_t &username) {
    206   gdbmclass userdb;
    207   if (!userdb.opendatabase(userdbfile, GDBM_WRCREAT, 1000, true)) return;
    208 
    209   delete_user (userdb, username);
    210   userdb.closedatabase();
    211 }
    212 
    213 // gets a list of all the users in the database. returns true
    214 // on success
    215 void get_user_list (gdbmclass &userdb, text_tarray &userlist) {
    216   userlist.erase (userlist.begin(), userlist.end());
    217  
    218   text_t user = userdb.getfirstkey ();
    219   while (!user.empty()) {
    220     userlist.push_back(user);
    221     user = userdb.getnextkey (user);
    222   }
    223 }
    224 
    225 // returns true if the user's password is correct.
    226 bool check_passwd (const userinfo_t &thisuser, const text_t &password) {
    227   // couple of basic checks
    228   if (thisuser.username.empty() || thisuser.password.empty() ||
    229       password.empty()) return false;
    230 
    231   text_t crypt_password = crypt_text(password);
    232   return (thisuser.password == crypt_password);
     155  return true;
    233156}
    234157
    235158// removes spaces from user groups
    236 text_t format_user_groups(const text_t user_groups){
    237 
     159text_t userdbclass::format_user_groups(const text_t user_groups)
     160{
    238161  text_t new_groups = g_EmptyText;
    239162  text_t::const_iterator here = user_groups.begin();
    240163  text_t::const_iterator end = user_groups.end();
    241164  while (here != end) {
    242     if (*here != ' '&& *here != '\t' && *here != '\n') {
    243       new_groups.push_back(*here);
    244     }
     165    if (*here != ' '&& *here != '\t' && *here != '\n')
     166      {
     167        new_groups.push_back(*here);
     168      }
    245169    ++here;
    246170  }
     
    248172}
    249173
    250 // functions dealing with databases of temporary keys
    251 
     174// functions dealing with user databases
     175// returns true on success (in which case userinfo will contain
     176// the information for this user)
     177// @return 0 success
     178// @return -1 database is not currently connected
     179// @return -2 not defined username
     180int userdbclass::get_user_info (const text_t &username, userinfo_t &userinfo)
     181{
     182  // Let's make sure the connection has been established.
     183  if (activated == true)
     184    {
     185      userinfo.clear();
     186      infodbclass info;
     187      // See if we can get the user's infomration
     188      if (userdb.getinfo (username, info))
     189        {
     190          userinfo.username = info["username"];
     191          userinfo.password = info["password"];
     192          userinfo.enabled = (info["enabled"] == "true");
     193          userinfo.groups = info["groups"];
     194          userinfo.comment = info["comment"];
     195          return ERRNO_SUCCEED;
     196        }
     197      // If we failed to retrieve the users information, we should check if the username is admin or not.
     198      // If it is the admin user, let's create a new account for the admin user.
     199      else if (username == "admin")
     200        {
     201          userinfo.clear();
     202          userinfo.username = "admin";
     203          userinfo.password = crypt_text("admin");
     204          userinfo.enabled = true;
     205          userinfo.groups = "administrator,colbuilder";
     206          userinfo.comment = "change the password for this account as soon as possible";
     207          // Return the set result.
     208          return set_user_info (username, userinfo);
     209        }
     210      // The username is not found, return false
     211      return ERRNO_USERNOTFOUND;
     212    }
     213  // Failed to connect to the database, return false.
     214  return ERRNO_CONNECTIONFAILED;
     215}
     216
     217// returns true on success
     218int userdbclass::set_user_info (const text_t &username, const userinfo_t &userinfo)
     219{
     220  // Let's make sure the connection has been established.
     221  if (activated == true)
     222    {
     223      infodbclass info;
     224      info["username"] = userinfo.username;
     225      info["password"] = userinfo.password;
     226      info["enabled"] = userinfo.enabled ? "true" : "false";
     227      info["groups"] = userinfo.groups;
     228      info["comment"] = userinfo.comment;
     229     
     230      return (userdb.setinfo (username, info)) ? ERRNO_SUCCEED : ERRNO_GDBMACTIONFILED ;
     231    }
     232  return ERRNO_CONNECTIONFAILED;
     233}
     234
     235// returns true if the user's password is correct.
     236int userdbclass::check_passwd (const text_t &username, const text_t &password)
     237{
     238  userinfo_t thisuser;
     239  int returned = get_user_info(username, thisuser);
     240  if(returned != ERRNO_SUCCEED) return returned;
     241  // couple of basic checks
     242  if (thisuser.username.empty() || thisuser.password.empty() ||
     243      password.empty()) return ERRNO_MISSINGPASSWORD;
     244
     245  text_t crypt_password = crypt_text(password);
     246  return (thisuser.password == crypt_password) ? ERRNO_SUCCEED : ERRNO_PASSWORDMISMATCH;
     247}
     248
     249int userdbclass::add_user (const userinfo_t &userinfo)
     250{
     251  // Let's make sure the connection has been established.
     252  if (activated == true)
     253    {
     254      infodbclass info;
     255      if (userdb.getinfo (userinfo.username, info))
     256        {
     257          // There is an existing username already
     258          return ERRNO_EXISTINGUSERNAME;
     259        }
     260      else
     261        {
     262          return set_user_info(userinfo.username, userinfo);
     263        }     
     264    }
     265  return ERRNO_CONNECTIONFAILED;
     266}
     267
     268int userdbclass::edit_user (const userinfo_t &userinfo)
     269{
     270  // Let's make sure the connection has been established.
     271  if (activated == true)
     272    {
     273      infodbclass info;
     274      if (userdb.getinfo (userinfo.username, info))
     275        {
     276          return set_user_info(userinfo.username, userinfo);
     277        }
     278      else
     279        {
     280          // The user does not exist in the database.
     281          return ERRNO_USERNOTFOUND;
     282        }     
     283    }
     284  return ERRNO_CONNECTIONFAILED;
     285}
     286
     287int userdbclass::delete_user (const text_t &username)
     288
     289  // Let's make sure the connection has been established.
     290  if (activated == true)
     291    {
     292      userdb.deletekey (username);
     293      return ERRNO_SUCCEED;
     294    }
     295  return ERRNO_CONNECTIONFAILED;
     296}
     297
     298// gets all the users' information in the database. returns true
     299// on success
     300int userdbclass::get_all_users(userinfo_tarray &userinfo_array)
     301{
     302  // Let's make sure the connection has been established.
     303  if (activated == true)
     304    {
     305      userinfo_array.erase(userinfo_array.begin(), userinfo_array.end());
     306      text_t user = userdb.getfirstkey();
     307      while (!user.empty()) {
     308        userinfo_t one_userinfo;
     309        int returned = get_user_info(user, one_userinfo);
     310        if (returned != ERRNO_SUCCEED) return returned;
     311        userinfo_array.push_back(one_userinfo);
     312        user = userdb.getnextkey(user);
     313      }
     314      return ERRNO_SUCCEED;
     315    }
     316  return ERRNO_CONNECTIONFAILED;
     317}
     318
     319// gets a list of all the users in the database. returns true
     320// on success
     321int userdbclass::get_user_list (text_tarray &userlist)
     322{
     323  // Let's make sure the connection has been established.
     324  if (activated == true)
     325    {
     326      userlist.erase (userlist.begin(), userlist.end());
     327     
     328      text_t user = userdb.getfirstkey ();
     329      while (!user.empty()) {
     330        userlist.push_back(user);
     331        user = userdb.getnextkey (user);
     332      }
     333      return ERRNO_SUCCEED;
     334    }
     335  return ERRNO_CONNECTIONFAILED;
     336}
     337//==========================================//
     338//       userdbclass functions (End)        //
     339//==========================================//
     340
     341//==========================================//
     342//      keydbclass functions (Start)        //
     343//==========================================//
     344keydbclass::keydbclass(const text_t &keydbfilename)
     345{
     346  activated = (!keydb.opendatabase(keydbfilename, GDBM_WRCREAT, 1000, true)) ? false : true;
     347  external_db = false;
     348}
     349
     350keydbclass::keydbclass(const gdbmclass &external_keydb)
     351{
     352  keydb = external_keydb;
     353  activated = true;
     354  external_db = true;
     355}
     356
     357keydbclass::~keydbclass()
     358{
     359  if (external_db == false) { keydb.closedatabase();}
     360}
    252361// generates a random key for the user, stores it in the database and
    253362// returns it so that it can be used in page generation
    254363// returns "" on failure
    255 text_t generate_key (gdbmclass &keydb, const text_t &username) {
    256   static const char *numconvert = "0123456789abcdefghijklmnopqrstuvwxyz"
    257     "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    258 
    259   // loop looking for a suitable new key
    260   text_t userkey;
    261   text_t crypt_userkey;
    262   do {
    263     // convert to base 62 :-)
    264     int userkey_int = rand ();
    265     while (userkey_int > 0) {
    266       userkey.push_back (numconvert[userkey_int%62]);
    267       userkey_int /= 62;
    268     }
    269 
    270     // make sure this key is not in the database
    271     crypt_userkey = crypt_text(userkey);
    272     if (keydb.exists (crypt_userkey)) userkey.clear();
    273   } while (userkey.empty());
    274 
    275   // enter the key into the database
    276   infodbclass keydata;
    277   keydata["user"] = username;
    278   keydata["time"] = time2text(time(NULL));
    279  
    280   if (!keydb.setinfo (crypt_userkey, keydata)) {
    281     userkey.clear(); // failed
    282   }
    283  
    284   return userkey;
    285 }
    286 
    287 text_t generate_key (const text_t &keydbfile, const text_t &username) {
    288   gdbmclass keydb;
    289   if (!keydb.opendatabase(keydbfile, GDBM_WRCREAT, 1000, true)) return g_EmptyText;
    290 
    291   text_t key = generate_key (keydb, username);
    292   keydb.closedatabase();
    293 
    294   return key;
    295 }
    296 
     364text_t keydbclass::generate_key (const text_t &username)
     365{
     366  // Let's make sure the connection has been established.
     367  if (activated == true)
     368    {
     369      static const char *numconvert = "0123456789abcdefghijklmnopqrstuvwxyz"
     370        "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
     371     
     372      // loop looking for a suitable new key
     373      text_t userkey;
     374      text_t crypt_userkey;
     375      do {
     376        // convert to base 62 :-)
     377        int userkey_int = rand ();
     378        while (userkey_int > 0)
     379          {
     380            userkey.push_back (numconvert[userkey_int%62]);
     381            userkey_int /= 62;
     382          }
     383       
     384        // make sure this key is not in the database
     385        crypt_userkey = userdbclass::crypt_text(userkey);
     386        if (keydb.exists (crypt_userkey)) userkey.clear();
     387      } while (userkey.empty());
     388     
     389      // enter the key into the database
     390      infodbclass keydata;
     391      keydata["user"] = username;
     392      keydata["time"] = time2text(time(NULL));
     393     
     394      if (!keydb.setinfo (crypt_userkey, keydata))
     395        {
     396          userkey.clear(); // failed
     397        }
     398     
     399      return userkey;
     400    }
     401  return "";
     402}
    297403
    298404// checks to see if there is a key for this particular user in the
    299405// database that hasn't decayed. a short decay is used when group
    300406// is set to administrator
    301 bool check_key (gdbmclass &keydb, const userinfo_t &thisuser,
    302         const text_t &key, const text_t &group, int keydecay) {
    303   if (thisuser.username.empty() || key.empty()) return false;
    304 
    305   // the keydecay is set to 5 minute for things requiring the
    306   // administrator
    307   //  if (group == "administrator") keydecay = 300;
    308  
    309   // success if there is a key in the key database that is owned by this
    310   // user whose creation time is less that keydecay
    311   text_t crypt_key = crypt_text(key);
    312   infodbclass info;
    313   if (keydb.getinfo (crypt_key, info))  {
    314     if (info["user"] == thisuser.username) {
    315       time_t keycreation = text2time (info["time"]);
    316       if (keycreation != (time_t)-1 && difftime (text2time(time2text(time(NULL))),
    317                          keycreation) <= keydecay) {
    318     // succeeded, update the key's time
    319     info["time"] = time2text(time(NULL));
    320     keydb.setinfo (crypt_key, info);
    321     return true;
    322       }
    323     }
    324   }
    325  
    326   return false;;
    327 }
    328 
    329 bool check_key (const text_t &keydbfile, const userinfo_t &thisuser,
    330         const text_t &key, const text_t &group, int keydecay) {
    331   gdbmclass keydb;
    332   if (!keydb.opendatabase(keydbfile, GDBM_WRCREAT, 1000, true)) return false;
    333 
    334   bool success = check_key (keydb, thisuser, key, group, keydecay);
    335   keydb.closedatabase();
    336 
    337   return success;
    338 }
    339 
     407bool keydbclass::check_key (const userinfo_t &thisuser, const text_t &key, const text_t &group, int keydecay)
     408{
     409  // Let's make sure the connection has been established.
     410  if (activated == true)
     411    {
     412      if (thisuser.username.empty() || key.empty()) return false;
     413     
     414      // the keydecay is set to 5 minute for things requiring the
     415      // administrator
     416      //  if (group == "administrator") keydecay = 300;
     417     
     418      // success if there is a key in the key database that is owned by this
     419      // user whose creation time is less that keydecay
     420      text_t crypt_key = userdbclass::crypt_text(key);
     421      infodbclass info;
     422      if (keydb.getinfo (crypt_key, info))  {
     423        if (info["user"] == thisuser.username) {
     424          time_t keycreation = text2time (info["time"]);
     425          if (keycreation != (time_t)-1 && difftime (text2time(time2text(time(NULL))),
     426                                                     keycreation) <= keydecay) {
     427            // succeeded, update the key's time
     428            info["time"] = time2text(time(NULL));
     429            keydb.setinfo (crypt_key, info);
     430            return true;
     431          }
     432        }
     433      }
     434    }
     435  return false;
     436}
    340437
    341438// remove_old_keys will remove all keys created more than keydecay ago.
    342439// use sparingly, it can be quite an expensive function
    343 void remove_old_keys (const text_t &keydbfile, int keydecay) {
    344   // open the key database
    345   gdbmclass keydb;
    346   if (!keydb.opendatabase(keydbfile, GDBM_WRCREAT, 1000, true)) return;
    347 
    348   // get a list of keys created more than keydecay seconds agon
    349   text_tarray oldkeys;
    350   text_t key = keydb.getfirstkey ();
    351   infodbclass info;
    352   time_t timenow = text2time(time2text(time(NULL)));
    353   time_t keycreation = (time_t)-1;
    354   while (!key.empty()) {
    355     if (keydb.getinfo (key, info))  {
    356       keycreation = text2time (info["time"]);
    357       if (keycreation != (time_t)-1 && difftime (timenow, keycreation) > keydecay) {
    358     // found an old key
    359     oldkeys.push_back(key);
    360       }
    361     }
    362    
    363     key = keydb.getnextkey (key);
    364   }
    365 
    366   // delete the keys
    367   text_tarray::iterator keys_here = oldkeys.begin();
    368   text_tarray::iterator keys_end = oldkeys.end();
    369   while (keys_here != keys_end) {
    370     keydb.deletekey(*keys_here);
    371     ++keys_here;
    372   }
    373  
    374   // close the key database
    375   keydb.closedatabase();
    376 }
     440void keydbclass::remove_old_keys (int keydecay)
     441{
     442  // Let's make sure the connection has been established.
     443  if (activated == true)
     444    { 
     445      // get a list of keys created more than keydecay seconds agon
     446      text_tarray oldkeys;
     447      text_t key = keydb.getfirstkey ();
     448      infodbclass info;
     449      time_t timenow = text2time(time2text(time(NULL)));
     450      time_t keycreation = (time_t)-1;
     451      while (!key.empty()) {
     452        if (keydb.getinfo (key, info))  {
     453          keycreation = text2time (info["time"]);
     454          if (keycreation != (time_t)-1 && difftime (timenow, keycreation) > keydecay) {
     455            // found an old key
     456            oldkeys.push_back(key);
     457          }
     458        }
     459       
     460        key = keydb.getnextkey (key);
     461      }
     462     
     463      // delete the keys
     464      text_tarray::iterator keys_here = oldkeys.begin();
     465      text_tarray::iterator keys_end = oldkeys.end();
     466      while (keys_here != keys_end) {
     467        keydb.deletekey(*keys_here);
     468        ++keys_here;
     469      }
     470    }
     471}
     472//==========================================//
     473//       keydbclass functions (End)         //
     474//==========================================//
  • trunk/gsdl/src/recpt/userdb.h

    r2750 r13844  
    2828#define USERDB_H
    2929
     30#define ERRNO_SUCCEED           0
     31#define ERRNO_CONNECTIONFAILED -1
     32#define ERRNO_USERNOTFOUND     -2
     33#define ERRNO_EXISTINGUSERNAME -3
     34#define ERRNO_MISSINGPASSWORD  -4
     35#define ERRNO_PASSWORDMISMATCH -5
     36#define ERRNO_GDBMACTIONFILED  -6
     37
     38
    3039#include "infodbclass.h"
    3140
    32 
    33 // the password line in the userinfo_t must be encrypted using
    34 // this function
    35 text_t crypt_text (const text_t &text);
    36 
    37 // username_ok tests to make sure a username is ok. a username
    38 // must be at least 2 characters long, but no longer than 30
    39 // characters long. it can contain the characters a-z A-Z 0-9
    40 // . and _
    41 bool username_ok (const text_t &username);
    42 
    43 // password_ok tests to make sure a password is ok. a password
    44 // must be at least 3 characters long but no longer than 8 characters
    45 // long. it can contain any character in the range 0x20-0x7e
    46 bool password_ok (const text_t &password);
    47 
    48 
    49 // information about a single user
    50 struct userinfo_t {
    51   void clear ();
    52   userinfo_t () {clear();}
    53   userinfo_t &operator=(const userinfo_t &x);
    54  
     41// The user information object and it provides basic functions for the information object, such as clear and copy (=) functions;
     42class userinfo_t
     43{
     44 public:
    5545  text_t username;
    5646  text_t password;
     
    5848  text_t groups; // comma separated list
    5949  text_t comment;
     50
     51  userinfo_t ();
     52  virtual ~userinfo_t();
     53  userinfo_t &operator=(const userinfo_t &x);
     54  void clear ();
    6055};
    6156
     57typedef vector<userinfo_t> userinfo_tarray; // more space efficient than text_tlist
    6258
    63 // these functions deal with user and key databases that are already open
    64 // they should have been opened with gdbmclass::opendatabase
    65 // as soon as the databases are finished with they should be closed with
    66 // gdbmclass::closedatabase so that another process can access the database
    67 //
    68 // some of the functions need the databases opened with write access, an
    69 // appropriate call would be something like:
    70 //
    71 //   success = keydb.opendatabase (keyfile, GDBM_WRCREAT, 1000);
    72 //
    73 // note: passwords and keys are encrypted, so you can't just compare passwords
    74 // in a userinfo_t with a password given by the user. use check_passwd
     59class userdbclass
     60{
     61 protected:
     62  // The internal storage for the userdbfilename and the userdb object
     63  gdbmclass userdb;
     64  bool external_db;
     65  bool activated;
     66 
     67 public:
     68  userdbclass (const text_t &userdbfilename);
     69  userdbclass (const gdbmclass &external_userdb);
     70  virtual ~userdbclass();
    7571
     72  //======== the static methods========//
     73  // the password line in the userinfo_t must be encrypted using
     74  // this function
     75  static text_t crypt_text (const text_t &text);
     76  // username_ok tests to make sure a username is ok. a username
     77  // must be at least 2 characters long, but no longer than 30
     78  // characters long. it can contain the characters a-z A-Z 0-9
     79  // . and _
     80  static bool username_ok (const text_t &username);
     81  // password_ok tests to make sure a password is ok. a password
     82  // must be at least 3 characters long but no longer than 8 characters
     83  // long. it can contain any character in the range 0x20-0x7e
     84  static bool password_ok (const text_t &password);
     85  // removes spaces from user groups
     86  static text_t format_user_groups(const text_t user_groups);
     87 
     88  //======== functions dealing with single user in the user databases ========//
     89  // returns true on success (in which case userinfo will contain
     90  // the information for this user)
     91  int get_user_info (const text_t &username, userinfo_t &userinfo);
     92 
     93  // returns true on success
     94  int set_user_info (const text_t &username, const userinfo_t &userinfo);
     95 
     96  // returns true if the user's password is correct.
     97  int check_passwd (const text_t &username, const text_t &password);
     98 
     99  // adds a user from the user database -- forever
     100  int add_user (const userinfo_t &userinfo);
     101 
     102  // edits a user from the user database -- forever
     103  int edit_user (const userinfo_t &userinfo);
     104 
     105  // removes a user from the user database -- forever
     106  int delete_user (const text_t &username);
     107 
     108  //======== functions dealing with multiple users in the user databases ========//
     109  // gets all the users' information in the database. returns true
     110  // on success
     111  int get_all_users(userinfo_tarray &userinfo_array);
     112 
     113  // gets a list of all the users in the database. returns true
     114  // on success
     115  int get_user_list (text_tarray &userlist);
     116};
    76117
    77 // functions dealing with user databases
    78 
    79 // returns true on success (in which case userinfo will contain
    80 // the information for this user)
    81 bool get_user_info (gdbmclass &userdb, const text_t &username,
    82             userinfo_t &userinfo);
    83 bool get_user_info (const text_t &userdbfile, const text_t &username,
    84             userinfo_t &userinfo);
    85 
    86 // returns true on success
    87 bool set_user_info (gdbmclass &userdb, const text_t &username,
    88             const userinfo_t &userinfo);
    89 bool set_user_info (const text_t &userdbfile, const text_t &username,
    90             const userinfo_t &userinfo);
    91 
    92 // removes a user from the user database -- forever
    93 void delete_user (gdbmclass &userdb, const text_t &username);
    94 void delete_user (const text_t &userdbfile, const text_t &username);
    95 
    96 // gets a list of all the users in the database. returns true
    97 // on success
    98 void get_user_list (gdbmclass &userdb, text_tarray &userlist);
    99 
    100 // returns true if the user's password is correct.
    101 bool check_passwd (const userinfo_t &thisuser, const text_t &password);
    102 
    103 // removes spaces from user groups
    104 text_t format_user_groups(const text_t user_groups);
    105 
    106 // functions dealing with databases of temporary keys
    107 
    108 // generates a random key for the user, stores it in the database and
    109 // returns it so that it can be used in page generation
    110 // returns "" on failure
    111 text_t generate_key (gdbmclass &keydb, const text_t &username);
    112 text_t generate_key (const text_t &keydbfile, const text_t &username);
    113 
    114 // checks to see if there is a key for this particular user in the
    115 // database that hasn't decayed. a short decay is used when group
    116 // is set to administrator
    117 bool check_key (gdbmclass &keydb, const userinfo_t &thisuser,
    118         const text_t &key, const text_t &group, int keydecay);
    119 bool check_key (const text_t &keydbfile, const userinfo_t &thisuser,
    120         const text_t &key, const text_t &group, int keydecay);
    121 
    122 // remove_old_keys will remove all keys created more than keydecay ago.
    123 // use sparingly, it can be quite an expensive function
    124 void remove_old_keys (const text_t &keydbfile, int keydecay);
    125 
     118class keydbclass
     119{
     120 protected:
     121  // The internal storage for the userdbfilename and the userdb object
     122  gdbmclass keydb;
     123  bool external_db;
     124  bool activated;
     125 
     126 public:
     127  keydbclass (const text_t &keydbfilename);
     128  keydbclass (const gdbmclass &external_keydb);
     129  virtual ~keydbclass();
     130  // functions dealing with databases of temporary keys
     131 
     132  // generates a random key for the user, stores it in the database and
     133  // returns it so that it can be used in page generation
     134  // returns "" on failure
     135  text_t generate_key (const text_t &username);
     136 
     137  // checks to see if there is a key for this particular user in the
     138  // database that hasn't decayed. a short decay is used when group
     139  // is set to administrator
     140  bool check_key (const userinfo_t &thisuser, const text_t &key, const text_t &group, int keydecay);
     141 
     142  // remove_old_keys will remove all keys created more than keydecay ago.
     143  // use sparingly, it can be quite an expensive function
     144  void remove_old_keys (int keydecay);
     145};
    126146
    127147#endif
  • trunk/gsdl/src/recpt/usersaction.cpp

    r9620 r13844  
    2929#include "usersaction.h"
    3030#include "fileutil.h"
    31 #include "userdb.h"
    3231
    3332
     
    195194                 ostream &logout) {
    196195
     196  // open the user database (it will be used a lot)
     197  user_database = new userdbclass(usersfile);
     198
    197199  if (args["uma"] == "adduser" || args["uma"] == "edituser") {
    198200    // adduser is handled by edituser
     
    217219      << "_userslistusers:header_\n_userslistusers:contentstart_\n";
    218220
    219 
    220   // open the user database (it will be used a lot)
    221   gdbmclass userdb;
    222221  text_tarray userlist;
    223   if (userdb.opendatabase(usersfile, GDBM_READER, 1000, true)) {
    224     // get user list
    225     get_user_list (userdb, userlist);
    226   }
     222  // get user list
     223  user_database->get_user_list (userlist);
    227224
    228225  // sort the list
     
    234231  text_tarray::iterator users_end = userlist.end();
    235232  while (users_here != users_end) {
    236     if (get_user_info (userdb, *users_here, userinfo)) {
     233    if (user_database->get_user_info(*users_here, userinfo) == ERRNO_SUCCEED) {
    237234      textout << outconvert << disp
    238235          << "<tr><td bgcolor=\"\\#eeeeee\">" << userinfo.username << "</td>\n"
     
    257254    ++users_here;
    258255  }
    259 
    260   userdb.closedatabase();
    261256 
    262257  textout << outconvert << disp
     
    277272                   outconvertclass &outconvert, ostream &textout,
    278273                   ostream &logout) {
     274
    279275  userinfo_t userinfo;
    280276  text_t messagestatus;
     
    285281    noproblems = false;
    286282   
    287   } else if (!username_ok (args["umun"])) {
     283  } else if (!userdbclass::username_ok (args["umun"])) {
    288284    // problem with username
    289285    noproblems = false;
    290286    messagestatus += "_users:messageinvalidusername_";
    291287   
    292   } else if (get_user_info (usersfile, args["umun"], userinfo)) {
     288  } else if (user_database->get_user_info (args["umun"], userinfo) == ERRNO_SUCCEED) {
    293289    if (args["uma"] == "adduser") {
    294290      // must not add a user that has the same name as another user
     
    321317    }
    322318   
    323   } else if (!password_ok(args["umpw"])) {
     319  } else if (!userdbclass::password_ok(args["umpw"])) {
    324320    noproblems = false;
    325321    messagestatus += "_users:messageinvalidpassword_";
     
    332328    if (!args["umpw"].empty()) {
    333329      // only set the password if it is not empty
    334       userinfo.password = crypt_text(args["umpw"]);
     330      userinfo.password = userdbclass::crypt_text(args["umpw"]);
    335331    }
    336332    userinfo.enabled = (args["umus"] == "enabled");   
    337     userinfo.groups = format_user_groups(args["umug"]);
     333    userinfo.groups = userdbclass::format_user_groups(args["umug"]);
    338334    userinfo.comment = args["umc"];
    339335   
    340     set_user_info (usersfile, args["umun"], userinfo);
     336    user_database->set_user_info (args["umun"], userinfo);
    341337   
    342338    // show list of users
     
    360356    if (args["cm"] == "yes" && !args["umun"].empty()) {
    361357      // user confirmed the deletion of the user
    362       delete_user (usersfile, args["umun"]);
     358      user_database->delete_user(args["umun"]);
    363359    }
    364360   
     
    390386    } else if (args["umnpw1"] != args["umnpw2"]) {
    391387      messagestatus = "_users:messagenewpassmismatch_";
    392     } else if (!password_ok(args["umnpw1"])) {
     388    } else if (!userdbclass::password_ok(args["umnpw1"])) {
    393389      messagestatus = "_users:messageinvalidpassword_";
    394390    } else {
    395391      userinfo_t userinfo;
    396       if (get_user_info (usersfile, args["un"], userinfo)) {
     392      if (user_database->get_user_info (args["un"], userinfo) == ERRNO_SUCCEED) {
    397393    // check old password
    398     if (userinfo.password != crypt_text(args["umpw"])) {
     394    if (userinfo.password != userdbclass::crypt_text(args["umpw"])) {
    399395      messagestatus = "_users:messagefailed_";
    400396     
    401397    } else {
    402       userinfo.password = crypt_text(args["umnpw1"]);
    403       if (set_user_info (usersfile, args["un"], userinfo)) {
     398      userinfo.password = userdbclass::crypt_text(args["umnpw1"]);
     399      if (user_database->set_user_info (args["un"], userinfo) == ERRNO_SUCCEED) {
    404400        // everything is ok
    405401        textout << outconvert << disp
  • trunk/gsdl/src/recpt/usersaction.h

    r7375 r13844  
    3333#include "action.h"
    3434#include "text_t.h"
     35#include "userdb.h"
    3536
    3637
     
    3839protected:
    3940  text_t usersfile;
     41  userdbclass* user_database;
    4042
    4143public:
Note: See TracChangeset for help on using the changeset viewer.