// // aegis - project change supervisor // Copyright (C) 2001-2008, 2012, 2014 Peter Miller // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or (at // your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // #include #include #include #include #include #include #include #include static symtab_ty *login_table; static itab_ty *uid_table; static passwd * passwd_null(void) { passwd *result = new passwd; // // This isn't portable, it assumes that NULL pointers are // all-bits-zero, but this is only to cover all the fields we // don't care about. We set the ones we -do- care about to // NULL explicitly. // memset(result, 0, sizeof(*result)); #ifndef SOURCE_FORGE_HACK result->pw_name = 0; result->pw_passwd = 0; result->pw_uid = 0; result->pw_gid = 0; result->pw_gecos = 0; #ifdef HAVE_pw_comment result->pw_comment = 0; #endif result->pw_dir = 0; result->pw_shell = 0; #else // // This is used to fake a user account, because on SourceForge.net // the Apache servers don't have access to /etc/passwd. The fake // information will be further taylored below. // result->pw_name = "nobody"; result->pw_passwd = "x"; result->pw_uid = AEGIS_MIN_UID; result->pw_gid = AEGIS_MIN_GID; result->pw_gecos = "nobody"; #ifdef HAVE_pw_comment result->pw_comment = 0; #endif result->pw_dir = "/home/nobody"; result->pw_shell = "/bin/sh"; #endif // // All done. // return result; } static passwd * passwd_copy(passwd *pw) { passwd *result = passwd_null(); // // Copy values onto the heap, because the next call to getpwnam // will trash the ones in *pw. // result->pw_name = mem_copy_string(pw->pw_name); result->pw_uid = pw->pw_uid; result->pw_gid = pw->pw_gid; result->pw_gecos = mem_copy_string(pw->pw_gecos); #ifdef HAVE_pw_comment result->pw_comment = pw->pw_comment ? mem_copy_string(pw->pw_comment) : 0; #endif result->pw_dir = mem_copy_string(pw->pw_dir); result->pw_shell = mem_copy_string(pw->pw_shell); // // All done. // return result; } passwd * getpwnam_cached(string_ty *name) { return getpwnam_cached(nstring(name)); } passwd * getpwnam_cached(const nstring &name) { // // Create the tables if they don't exist already. // if (!login_table) { login_table = new symtab_ty(5); uid_table = itab_alloc(); } // // Look for the data in the name table. // passwd *data = (passwd *)login_table->query(name); // // If the data isn't there, ask the system for it. // if (!data) { passwd *pw = getpwnam(name.c_str()); if (pw) { data = passwd_copy(pw); itab_assign(uid_table, data->pw_uid, data); } else { data = passwd_null(); #ifdef SOURCE_FORGE_HACK data->pw_name = mem_copy_string(name.c_str()); data->pw_gecos = data->pw_name; #endif } login_table->assign(name, data); } // // Negative search results are also cached. // They have NULL pointers for all the fields. // if (!data->pw_name) return 0; // // Success. // return data; } passwd * getpwuid_cached(int uid) { // // Create the tables if they don't exist already. // if (!login_table) { login_table = new symtab_ty(5); uid_table = itab_alloc(); } // // Look for the data in the name table. // passwd *data = (passwd *)itab_query(uid_table, uid); // // If the data isn't there, ask the system for it. // if (!data) { passwd *pw = getpwuid(uid); if (pw) { data = passwd_copy(pw); nstring name = pw->pw_name; login_table->assign(name, data); } else { data = passwd_null(); data->pw_uid = uid; } itab_assign(uid_table, uid, data); } // // Negative search results are also cached. // They have NULL pointers for all the fields. // if (!data->pw_name) return 0; // // Success. // return data; } nstring getpwnam_fuzzy(const nstring &name) { nstring best; double best_weight = 0.6; setpwent(); for (;;) { passwd *pw = getpwent(); if (!pw) break; double weight = fstrcmp(name.c_str(), pw->pw_name); if (weight > best_weight) { best = nstring(pw->pw_name); best_weight = weight; } } if (best == name) { error_raw ( "warning: your name service seems to be broken: it can't " "find user %s by name (via getpwnam), but this user " "is present when scanning through all users (via " "getpwent)", name.quote_c().c_str() ); } return best; } // vim: set ts=8 sw=4 et :