#include "pam.h" #include #include #include #include #include "mod_insert.h" #include "pam/libpam/include/security/_pam_types.h" #include "pam_c.h" // IWYU pragma: keep #include extern "C" { #ifndef PAM_STATIC #define PAM_STATIC #endif #include #include #include "../libpam/pam_private.h" } #include #include #include #include using std::pair; using std::set; using std::string; using std::vector; extern struct pam_module_list *_pam_static_modules; extern struct pam_default_conf *_pam_default_conf_list; void pamcfg_iterator::default_imp() { set_default_arguments(""); set_default_sequence(1); } smdb_error pamcfg_iterator::notify_imp(smdb_cdb_iterator::operation op) { if (have_sequence() && (get_sequence() > 999)) { return invalid_sequence(); } if (have_module()) { pam_module_list *mlp; for (mlp = _pam_static_modules; ; mlp = mlp->next) { if (mlp == NULL) { return invalid_module(); } if (get_module() == mlp->modp->name) { break; } } } return Ok; } void pamdefault_iterator::getrow(char **nexttok, pamdefault_iterator &row) { (void)row.fromString(1, _pam_StrTok(0, " \n\t", nexttok)); (void)row.fromString(3, _pam_StrTok(0, " \n\t", nexttok)); (void)row.fromString(4, _pam_StrTok(0, " \n\t", nexttok)); if (*nexttok != NULL) { (void)row.fromString(5, *nexttok); } else { (void)row.fromString(5, ""); } } smdb_error pamdefault_iterator::get_imp() { pam_default_conf *dcp; if (!have_service()) { return smdb_error::KeyNotFound; } for (dcp = _pam_default_conf_list; dcp != NULL; dcp = dcp->next) { if (get_service() == dcp->module) { char buf[strlen(dcp->conf)+1]; char *ptr1, *ptr2; strcpy(&buf[0], dcp->conf); ptr1 = &buf[0]; // Split dcp->conf into rows, then rows into fields, // then look for the row we want. We must invent a // sequence number. unsigned seq[9]; // XXX Largest value for enum pamModType memset(seq, 0, sizeof(seq)); while(ptr1 < &buf[strlen(dcp->conf)]) { pamdefault_iterator temprow(0); ptr2 = strchr(ptr1, '\n'); if (ptr2 == NULL) { ptr2 = ptr1 + strlen(ptr1); } else { *ptr2 = (char)0; } getrow(&ptr1, temprow); seq[temprow.get_type()] += 10; // Is this the row we want? if (get_type() == temprow.get_type()) { if (get_sequence() == seq[temprow.get_type()]) { // This is the one we want! Return it. set_control(temprow.get_control()); set_module(temprow.get_module()); set_arguments(temprow.get_arguments()); return Ok; } } // Setting up next iteration. ptr1 = ptr2 + 1; } return KeyNotFound; } } return KeyNotFound; } smdb_error pamdefault_iterator::next_imp() { pam_default_conf *dcp; pamdefault_iterator nextrow(0); for (dcp = _pam_default_conf_list; dcp != NULL; dcp = dcp->next) { if (get_service() > dcp->module) { continue; } if (nextrow.have_service() && nextrow.get_service() <= dcp->module) { continue; } char buf[strlen(dcp->conf)+1]; char *ptr1, *ptr2; strcpy(&buf[0], dcp->conf); ptr1 = &buf[0]; // Split dcp->conf into rows, then rows into fields, // then look for the row we want. We must invent a // sequence number. unsigned seq[9]; // XXX Largest value for enum pamModType memset(seq, 0, sizeof(seq)); while(ptr1 < &buf[strlen(dcp->conf)]) { pamdefault_iterator temprow(0); ptr2 = strchr(ptr1, '\n'); if (ptr2 == NULL) { ptr2 = ptr1 + strlen(ptr1); } else { *ptr2 = (char)0; } temprow.set_service(dcp->module); getrow(&ptr1, temprow); seq[temprow.get_type()] += 10; temprow.set_sequence(seq[temprow.get_type()]); // Is this the row we want? // Here's the "if" statement from hell bool service_is_next, service_is_equal, type_is_next, type_is_equal, seq_is_next; if (nextrow.have_service()) { service_is_next = ((get_service() < dcp->module) && (nextrow.get_service() > dcp->module)); service_is_equal = (get_service() == dcp->module); type_is_next = ((get_type() < temprow.get_type()) && (nextrow.get_type() > temprow.get_type())); type_is_equal = (get_type() == temprow.get_type()); seq_is_next = (get_sequence() < temprow.get_sequence()) && (nextrow.get_sequence() > temprow.get_sequence()); } else { service_is_next = (get_service() < dcp->module); service_is_equal = (get_service() == dcp->module); type_is_next = (get_type() < temprow.get_type()); type_is_equal = (get_type() == temprow.get_type()); seq_is_next = (get_sequence() < temprow.get_sequence()); } if (service_is_next || (service_is_equal && (type_is_next || (type_is_equal && (seq_is_next))))) { nextrow.set_service(temprow.get_service()); nextrow.set_type(temprow.get_type()); nextrow.set_sequence(temprow.get_sequence()); nextrow.set_control(temprow.get_control()); nextrow.set_module(temprow.get_module()); nextrow.set_arguments(temprow.get_arguments()); } // Setting up next iteration. ptr1 = ptr2 + 1; } } if (!nextrow.have_service()) { return KeyNotFound; } set_service(nextrow.get_service()); set_type(nextrow.get_type()); set_sequence(nextrow.get_sequence()); set_control(nextrow.get_control()); set_module(nextrow.get_module()); set_arguments(nextrow.get_arguments()); return Ok; } smdb_error pamstate_iterator::get_imp() { if (!have_service() || !have_type() || !have_sequence()) { return smdb_error::KeyNotFound; } citr.set_service(get_service()); citr.set_type(get_type()); citr.set_sequence(get_sequence()); if (citr.get()) { set_control(citr.get_control()); set_module(citr.get_module()); set_arguments(citr.get_arguments()); return Ok; } ditr.set_service(get_service()); ditr.set_type(get_type()); ditr.set_sequence(get_sequence()); if (ditr.get()) { set_control(ditr.get_control()); set_module(ditr.get_module()); set_arguments(ditr.get_arguments()); return Ok; } return KeyNotFound; } smdb_error pamstate_iterator::next_imp() { bool crslt, drslt; bool conf_first; // Abusing a loop so as not to use a goto. while (1) { citr.set_service(get_service()); citr.set_type(get_type()); citr.set_sequence(get_sequence()); ditr.set_service(get_service()); ditr.set_type(get_type()); ditr.set_sequence(get_sequence()); crslt = citr.next(); drslt = ditr.next(); if (!crslt && !drslt) { return KeyNotFound; } if (crslt) { conf_first = !drslt || ((citr.get_service() < ditr.get_service()) || ((citr.get_service() == ditr.get_service()) && (citr.get_type() <= ditr.get_type()))); } else { conf_first = false; } if (!conf_first) { bool temprslt; pamcfg_iterator temp(0); temp.set_service(ditr.get_service()); temp.set_type(ditr.get_type()); temprslt = temp.next(); if ( temprslt && (ditr.get_service() == temp.get_service()) && (ditr.get_type() == temp.get_type()) ) { if (!crslt) { // if citr.next() didn't work, then try again. set_service(ditr.get_service()); set_type(ditr.get_type()); set_sequence(ditr.get_sequence()); continue; } conf_first = true; } } break; } if (conf_first) { set_service(citr.get_service()); set_type(citr.get_type()); set_sequence(citr.get_sequence()); set_control(citr.get_control()); set_module(citr.get_module()); set_arguments(citr.get_arguments()); } else { set_service(ditr.get_service()); set_type(ditr.get_type()); set_sequence(ditr.get_sequence()); set_control(ditr.get_control()); set_module(ditr.get_module()); set_arguments(ditr.get_arguments()); } return Ok; } smdb_error pammods_iterator::get_imp() { pam_module_list *mlp; for (mlp = _pam_static_modules; mlp != NULL; mlp = mlp->next) { if (get_module() == mlp->modp->name) { return Ok; } } return KeyNotFound; } smdb_error pammods_iterator::next_imp() { pam_module_list *mlp; string nextmodname; for (mlp = _pam_static_modules; mlp != NULL; mlp = mlp->next) { if ( (get_module() < mlp->modp->name) && ((nextmodname > mlp->modp->name) || (nextmodname == "")) ) { nextmodname = mlp->modp->name; } } if (nextmodname != "") { set_module(nextmodname); return Ok; } return KeyNotFound; } /* * Implementation of authmethods table iterator */ smdb_error authmethods_iterator::get_imp() { if (smf_authstrings == 0) { return KeyNotFound; } set::iterator itr; itr = smf_authstrings->find(get_method()); if (itr == smf_authstrings->end()) { return KeyNotFound; } return Ok; } smdb_error authmethods_iterator::next_imp() { if (smf_authstrings == 0) { return KeyNotFound; } set::iterator itr; itr = smf_authstrings->upper_bound(get_method()); if (itr == smf_authstrings->end()) { return KeyNotFound; } set_method(*itr); return Ok; } /* * Implementation of authclients table iterator */ static set* smf_clients = 0; smdb_error authclients_iterator::get_imp() { if (smf_clients == 0) { return KeyNotFound; } set::iterator itr; itr = smf_clients->find(get_app()); if (itr == smf_clients->end()) { return KeyNotFound; } return Ok; } smdb_error authclients_iterator::next_imp() { if (smf_clients == 0) { return KeyNotFound; } set::iterator itr; itr = smf_clients->upper_bound(get_app()); if (itr == smf_clients->end()) { return KeyNotFound; } set_app(*itr); return Ok; } /* * Take all the clients that have been added to the authclients table, * and initialize the authmap table based on them. * This is done indirectly by calling pam_start. * This must be done after reading in the cdb. */ class auth_init : public smf_auth_modules { private: bool init_; public: auth_init() : smf_auth_modules(smf_authentication, "smf_authentication"), init_(false) {} virtual ~auth_init() {} void module_init(); bool init() { return init_; } }; void auth_init::module_init() { set::iterator itr; if (smf_clients != 0) { for (itr = smf_clients->begin(); itr != smf_clients->end(); ++itr) { pam_handle_t* pamh = 0; struct pam_conv dummy_conv; bzero(&dummy_conv,sizeof(dummy_conv)); (void) pam_start((*itr).c_str(), 0, &dummy_conv, &pamh); if (pamh) { (void) pam_end(pamh, PAM_ABORT); } } } init_ = true; } static auth_init auth_init_instance; void smf_addclient(const char* appname) { if (smf_clients == 0) { smf_clients = new set; } smf_clients->insert(appname); if (auth_init_instance.init()) { pam_handle_t* pamh = 0; struct pam_conv dummy_conv; bzero(&dummy_conv,sizeof(dummy_conv)); (void) pam_start(appname, 0, &dummy_conv, &pamh); if (pamh) { (void) pam_end(pamh, PAM_ABORT); } } } /* * Implementation of authmap table iterator */ static set >* auth_mapping = 0; smdb_error authmap_iterator::get_imp() { if (auth_mapping == 0) { return KeyNotFound; } set >::iterator itr; itr = auth_mapping->find(pair(get_app(), get_method())); if (itr == auth_mapping->end()) { return KeyNotFound; } return Ok; } smdb_error authmap_iterator::next_imp() { if (auth_mapping == 0) { return KeyNotFound; } set >::iterator itr; itr = auth_mapping->upper_bound(pair(get_app(), get_method())); if (itr == auth_mapping->end()) { return KeyNotFound; } set_app((*itr).first); set_method((*itr).second); return Ok; } void smf_auth_addmap(const char* app, const char* method) { if (auth_mapping == 0) { auth_mapping = new set >; } auth_mapping->insert(pair(app, method)); }