int pam_setenv(pam_handle_t *pamh, const char *name, const char *value, int overwrite) { char *env; int r; ENTER(); if (pamh == NULL) RETURNC(PAM_SYSTEM_ERR); /* sanity checks */ if (name == NULL || value == NULL || strchr(name, '=') != NULL) RETURNC(PAM_SYSTEM_ERR); /* is it already there? */ if (!overwrite && openpam_findenv(pamh, name, strlen(name)) >= 0) RETURNC(PAM_SUCCESS); /* set it... */ if (asprintf(&env, "%s=%s", name, value) < 0) RETURNC(PAM_BUF_ERR); r = pam_putenv(pamh, env); FREE(env); RETURNC(r); }
int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt) { const void *promptp; char *resp; int r; ENTER(); if (pamh == NULL || user == NULL) RETURNC(PAM_SYSTEM_ERR); r = pam_get_item(pamh, PAM_USER, (const void **)user); if (r == PAM_SUCCESS && *user != NULL) RETURNC(PAM_SUCCESS); if (prompt == NULL) { r = pam_get_item(pamh, PAM_USER_PROMPT, &promptp); if (r != PAM_SUCCESS || promptp == NULL) prompt = user_prompt; else prompt = promptp; } r = pam_prompt(pamh, PAM_PROMPT_ECHO_ON, &resp, "%s", prompt); if (r != PAM_SUCCESS) RETURNC(r); r = pam_set_item(pamh, PAM_USER, resp); FREE(resp); if (r != PAM_SUCCESS) RETURNC(r); r = pam_get_item(pamh, PAM_USER, (const void **)user); RETURNC(r); }
int openpam_configure(pam_handle_t *pamh, const char *service) { pam_facility_t fclt; int serrno; ENTERS(service); if (!valid_service_name(service)) { openpam_log(PAM_LOG_ERROR, "invalid service name"); RETURNC(PAM_SYSTEM_ERR); } if (openpam_load_chain(pamh, service, PAM_FACILITY_ANY) < 0) { if (errno != ENOENT) goto load_err; } for (fclt = 0; fclt < PAM_NUM_FACILITIES; ++fclt) { if (pamh->chains[fclt] != NULL) continue; if (openpam_load_chain(pamh, PAM_OTHER, fclt) < 0) goto load_err; } RETURNC(PAM_SUCCESS); load_err: serrno = errno; openpam_clear_chains(pamh->chains); errno = serrno; RETURNC(PAM_SYSTEM_ERR); }
int pam_get_item(const pam_handle_t *pamh, int item_type, const void **item) { ENTERI(item_type); if (pamh == NULL) RETURNC(PAM_SYSTEM_ERR); switch (item_type) { case PAM_SERVICE: case PAM_USER: case PAM_AUTHTOK: case PAM_OLDAUTHTOK: case PAM_TTY: case PAM_RHOST: case PAM_RUSER: case PAM_CONV: case PAM_USER_PROMPT: case PAM_REPOSITORY: case PAM_AUTHTOK_PROMPT: case PAM_OLDAUTHTOK_PROMPT: case PAM_HOST: *item = pamh->item[item_type]; RETURNC(PAM_SUCCESS); default: RETURNC(PAM_SYMBOL_ERR); } }
int pam_start(const char *service, const char *user, const struct pam_conv *pam_conv, pam_handle_t **pamh) { char hostname[HOST_NAME_MAX + 1]; struct pam_handle *ph; int r; ENTER(); if ((ph = calloc(1, sizeof *ph)) == NULL) RETURNC(PAM_BUF_ERR); if ((r = pam_set_item(ph, PAM_SERVICE, service)) != PAM_SUCCESS) goto fail; if (gethostname(hostname, sizeof hostname) != 0) strlcpy(hostname, "localhost", sizeof hostname); if ((r = pam_set_item(ph, PAM_HOST, hostname)) != PAM_SUCCESS) goto fail; if ((r = pam_set_item(ph, PAM_USER, user)) != PAM_SUCCESS) goto fail; if ((r = pam_set_item(ph, PAM_CONV, pam_conv)) != PAM_SUCCESS) goto fail; if ((r = openpam_configure(ph, service)) != PAM_SUCCESS) goto fail; *pamh = ph; openpam_log(PAM_LOG_DEBUG, "pam_start(\"%s\") succeeded", service); RETURNC(PAM_SUCCESS); fail: pam_end(ph, r); RETURNC(r); }
int pam_vprompt(const pam_handle_t *pamh, int style, char **resp, const char *fmt, va_list ap) { char msgbuf[PAM_MAX_MSG_SIZE]; struct pam_message msg; const struct pam_message *msgp; struct pam_response *rsp; const struct pam_conv *conv; const void *convp; int r; ENTER(); r = pam_get_item(pamh, PAM_CONV, &convp); if (r != PAM_SUCCESS) RETURNC(r); conv = convp; if (conv == NULL || conv->conv == NULL) { openpam_log(PAM_LOG_ERROR, "no conversation function"); RETURNC(PAM_SYSTEM_ERR); } vsnprintf(msgbuf, (size_t)PAM_MAX_MSG_SIZE, fmt, ap); msg.msg_style = style; msg.msg = msgbuf; msgp = &msg; rsp = NULL; r = (conv->conv)(1, &msgp, &rsp, conv->appdata_ptr); *resp = rsp == NULL ? NULL : rsp->resp; FREE(rsp); RETURNC(r); /*NOTREACHED*/ }
int pam_set_data(pam_handle_t *pamh, const char *module_data_name, void *data, void (*cleanup)(pam_handle_t *pamh, void *data, int pam_end_status)) { pam_data_t *dp; ENTERS(module_data_name); if (pamh == NULL) RETURNC(PAM_SYSTEM_ERR); for (dp = pamh->module_data; dp != NULL; dp = dp->next) { if (strcmp(dp->name, module_data_name) == 0) { if (dp->cleanup) (dp->cleanup)(pamh, dp->data, PAM_SUCCESS); dp->data = data; dp->cleanup = cleanup; RETURNC(PAM_SUCCESS); } } if ((dp = malloc(sizeof *dp)) == NULL) RETURNC(PAM_BUF_ERR); if ((dp->name = strdup(module_data_name)) == NULL) { FREE(dp); RETURNC(PAM_BUF_ERR); } dp->data = data; dp->cleanup = cleanup; dp->next = pamh->module_data; pamh->module_data = dp; RETURNC(PAM_SUCCESS); }
int pam_set_item(pam_handle_t *pamh, int item_type, const void *item) { void **slot, *tmp; size_t nsize, osize; ENTERI(item_type); if (pamh == NULL) RETURNC(PAM_SYSTEM_ERR); slot = &pamh->item[item_type]; osize = nsize = 0; switch (item_type) { case PAM_SERVICE: /* set once only, by pam_start() */ if (*slot != NULL) RETURNC(PAM_SYSTEM_ERR); /* fall through */ case PAM_USER: case PAM_AUTHTOK: case PAM_OLDAUTHTOK: case PAM_TTY: case PAM_RHOST: case PAM_RUSER: case PAM_USER_PROMPT: case PAM_AUTHTOK_PROMPT: case PAM_OLDAUTHTOK_PROMPT: case PAM_HOST: if (*slot != NULL) osize = strlen(*slot) + 1; if (item != NULL) nsize = strlen(item) + 1; break; case PAM_REPOSITORY: osize = nsize = sizeof(struct pam_repository); break; case PAM_CONV: osize = nsize = sizeof(struct pam_conv); break; default: RETURNC(PAM_SYMBOL_ERR); } if (*slot != NULL) { memset(*slot, 0xd0, osize); FREE(*slot); } if (item != NULL) { if ((tmp = malloc(nsize)) == NULL) RETURNC(PAM_BUF_ERR); memcpy(tmp, item, nsize); } else { tmp = NULL; } *slot = tmp; RETURNC(PAM_SUCCESS); }
int openpam_get_feature(int feature, int *onoff) { ENTERF(feature); if (feature < 0 || feature >= OPENPAM_NUM_FEATURES) RETURNC(PAM_SYMBOL_ERR); *onoff = openpam_features[feature].onoff; RETURNC(PAM_SUCCESS); }
int pam_open_session(pam_handle_t *pamh, int flags) { int r; ENTER(); if (flags & ~(PAM_SILENT)) RETURNC(PAM_SYMBOL_ERR); r = openpam_dispatch(pamh, PAM_SM_OPEN_SESSION, flags); RETURNC(r); }
int pam_authenticate(pam_handle_t *pamh, int flags) { int r; ENTER(); if (flags & ~(PAM_SILENT|PAM_DISALLOW_NULL_AUTHTOK)) RETURNC(PAM_SYMBOL_ERR); r = openpam_dispatch(pamh, PAM_SM_AUTHENTICATE, flags); pam_set_item(pamh, PAM_AUTHTOK, NULL); RETURNC(r); }
int pam_setcred(pam_handle_t *pamh, int flags) { int r; ENTER(); if (flags & ~(PAM_SILENT|PAM_ESTABLISH_CRED|PAM_DELETE_CRED| PAM_REINITIALIZE_CRED|PAM_REFRESH_CRED)) RETURNC(PAM_SYMBOL_ERR); /* XXX enforce exclusivity */ r = openpam_dispatch(pamh, PAM_SM_SETCRED, flags); RETURNC(r); /*NOTREACHED*/ }
int openpam_configure(pam_handle_t *pamh, const char *service) { pam_facility_t fclt; int serrno; ENTERS(service); if (!valid_service_name(service)) { openpam_log(PAM_LOG_ERROR, "invalid service name"); RETURNC(PAM_SYSTEM_ERR); } if (openpam_load_chain(pamh, service, PAM_FACILITY_ANY) < 0) goto load_err; for (fclt = 0; fclt < PAM_NUM_FACILITIES; ++fclt) { if (pamh->chains[fclt] != NULL) continue; if (openpam_load_chain(pamh, PAM_OTHER, fclt) < 0) goto load_err; } #ifdef __NetBSD__ /* * On NetBSD we require the AUTH chain to have a binding * or a required module. */ { pam_chain_t *this = pamh->chains[PAM_AUTH]; for (; this != NULL; this = this->next) if (this->flag == PAM_BINDING || this->flag == PAM_REQUIRED) break; if (this == NULL) { openpam_log(PAM_LOG_ERROR, "No required or binding component " "in service %s, facility %s", service, pam_facility_name[PAM_AUTH]); goto load_err; } } #endif RETURNC(PAM_SUCCESS); load_err: serrno = errno; openpam_clear_chains(pamh->chains); errno = serrno; RETURNC(PAM_SYSTEM_ERR); }
int pam_start(const char *service, const char *user, const struct pam_conv *pam_conv, pam_handle_t **pamh) { char *hostname = NULL; struct pam_handle *ph; int r; size_t hostname_size; long h; #ifdef _SC_HOST_NAME_MAX h = sysconf(_SC_HOST_NAME_MAX); #else h = -1; #endif hostname_size = (size_t)(h < 10 ? 1024 : h) + 1; ENTER(); if ((ph = calloc((size_t)1, sizeof *ph)) == NULL) RETURNC(PAM_BUF_ERR); if ((r = pam_set_item(ph, PAM_SERVICE, service)) != PAM_SUCCESS) goto fail; if ((hostname = malloc(hostname_size)) == NULL) goto fail; if (gethostname(hostname, hostname_size) != 0) strlcpy(hostname, "localhost", hostname_size); if ((r = pam_set_item(ph, PAM_HOST, hostname)) != PAM_SUCCESS) goto fail; if ((r = pam_set_item(ph, PAM_USER, user)) != PAM_SUCCESS) goto fail; if ((r = pam_set_item(ph, PAM_CONV, pam_conv)) != PAM_SUCCESS) goto fail; if ((r = openpam_configure(ph, service)) != PAM_SUCCESS) goto fail; free(hostname); *pamh = ph; openpam_log(PAM_LOG_DEBUG, "pam_start(\"%s\") succeeded", service); RETURNC(PAM_SUCCESS); fail: free(hostname); pam_end(ph, r); RETURNC(r); }
int pam_chauthtok(pam_handle_t *pamh, int flags) { int r; ENTER(); if (flags & ~(PAM_SILENT|PAM_CHANGE_EXPIRED_AUTHTOK)) RETURNC(PAM_SYMBOL_ERR); r = openpam_dispatch(pamh, PAM_SM_CHAUTHTOK, flags | PAM_PRELIM_CHECK); if (r == PAM_SUCCESS) r = openpam_dispatch(pamh, PAM_SM_CHAUTHTOK, flags | PAM_UPDATE_AUTHTOK); pam_set_item(pamh, PAM_OLDAUTHTOK, NULL); pam_set_item(pamh, PAM_AUTHTOK, NULL); RETURNC(r); }
int pam_get_data(const pam_handle_t *pamh, const char *module_data_name, const void **data) { pam_data_t *dp; ENTERS(module_data_name); if (pamh == NULL) RETURNC(PAM_SYSTEM_ERR); for (dp = pamh->module_data; dp != NULL; dp = dp->next) { if (strcmp(dp->name, module_data_name) == 0) { *data = (void *)dp->data; RETURNC(PAM_SUCCESS); } } RETURNC(PAM_NO_MODULE_DATA); }
int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt) { char prompt_buf[1024]; size_t prompt_size; const void *promptp; char *resp; int r; ENTER(); if (pamh == NULL || user == NULL) RETURNC(PAM_SYSTEM_ERR); r = pam_get_item(pamh, PAM_USER, (const void **)user); if (r == PAM_SUCCESS && *user != NULL) RETURNC(PAM_SUCCESS); /* pam policy overrides the module's choice */ if ((promptp = openpam_get_option(pamh, "user_prompt")) != NULL) prompt = promptp; /* no prompt provided, see if there is one tucked away somewhere */ if (prompt == NULL) if (pam_get_item(pamh, PAM_USER_PROMPT, &promptp) && promptp != NULL) prompt = promptp; /* fall back to hardcoded default */ if (prompt == NULL) prompt = user_prompt; /* expand */ prompt_size = sizeof prompt_buf; r = openpam_subst(pamh, prompt_buf, &prompt_size, prompt); if (r == PAM_SUCCESS && prompt_size <= sizeof prompt_buf) prompt = prompt_buf; r = pam_prompt(pamh, PAM_PROMPT_ECHO_ON, &resp, "%s", prompt); if (r != PAM_SUCCESS) RETURNC(r); r = pam_set_item(pamh, PAM_USER, resp); FREE(resp); if (r != PAM_SUCCESS) RETURNC(r); r = pam_get_item(pamh, PAM_USER, (const void **)user); RETURNC(r); }
int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { ENTER(); RETURNC(PAM_SYSTEM_ERR); }
int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { ENTER(); RETURNC(PAM_SYSTEM_ERR); }
int pam_acct_mgmt(pam_handle_t *pamh, int flags) { int r; ENTER(); r = openpam_dispatch(pamh, PAM_SM_ACCT_MGMT, flags); RETURNC(r); }
int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) { ENTER(); RETURNC(PAM_SYSTEM_ERR); }
int pam_sm_set_mapped_username(pam_handle_t *pamh, char *target_module_username, char *target_module_type, char *target_authn_domain, int argc, const char **argv) { ENTER(); RETURNC(PAM_SYSTEM_ERR); }
int pam_set_mapped_authtok(pam_handle_t *pamh, const char *target_module_username, size_t target_authtok_len, unsigned char *target_module_authtok, const char *target_module_type, const char *target_authn_domain) { ENTER(); RETURNC(PAM_SYSTEM_ERR); }
int pam_authenticate_secondary(pam_handle_t *pamh, char *target_username, char *target_module_type, char *target_authn_domain, char *target_supp_data, char *target_module_authtok, int flags) { ENTER(); RETURNC(PAM_SYSTEM_ERR); }
int pam_set_mapped_username(pam_handle_t *pamh, char *src_username, char *src_module_type, char *src_authn_domain, char *target_module_username, char *target_module_type, char *target_authn_domain) { ENTER(); RETURNC(PAM_SYSTEM_ERR); }
int openpam_nullconv(int n, const struct pam_message **msg, struct pam_response **resp, void *data) { ENTER(); (void)n; (void)msg; (void)resp; (void)data; RETURNC(PAM_CONV_ERR); }
int openpam_restore_cred(pam_handle_t *pamh) { const struct pam_saved_cred *scred; const void *scredp; int r; ENTER(); r = pam_get_data(pamh, PAM_SAVED_CRED, &scredp); if (r != PAM_SUCCESS) RETURNC(r); if (scredp == NULL) RETURNC(PAM_SYSTEM_ERR); scred = scredp; if (scred->euid != geteuid()) { if (seteuid(scred->euid) < 0 || setgroups(scred->ngroups, scred->groups) < 0 || setegid(scred->egid) < 0) RETURNC(PAM_SYSTEM_ERR); } pam_set_data(pamh, PAM_SAVED_CRED, NULL, NULL); RETURNC(PAM_SUCCESS); }
int pam_sm_get_mapped_authtok(pam_handle_t *pamh, char *target_module_username, char *target_module_type, char *target_authn_domain, size_t *target_authtok_len, unsigned char **target_module_authtok, int argc, char *argv) { ENTER(); RETURNC(PAM_SYSTEM_ERR); }
int openpam_borrow_cred(pam_handle_t *pamh, const struct passwd *pwd) { struct pam_saved_cred *scred; const void *scredp; int r; ENTERI(pwd->pw_uid); r = pam_get_data(pamh, PAM_SAVED_CRED, &scredp); if (r == PAM_SUCCESS && scredp != NULL) { openpam_log(PAM_LOG_DEBUG, "already operating under borrowed credentials"); RETURNC(PAM_SYSTEM_ERR); } if (geteuid() != 0 && geteuid() != pwd->pw_uid) { openpam_log(PAM_LOG_DEBUG, "called with non-zero euid: %d", (int)geteuid()); RETURNC(PAM_PERM_DENIED); } scred = calloc((size_t)1, sizeof *scred); if (scred == NULL) RETURNC(PAM_BUF_ERR); scred->euid = geteuid(); scred->egid = getegid(); r = getgroups(NGROUPS_MAX, scred->groups); if (r < 0) { FREE(scred); RETURNC(PAM_SYSTEM_ERR); } scred->ngroups = r; r = pam_set_data(pamh, PAM_SAVED_CRED, scred, &openpam_free_data); if (r != PAM_SUCCESS) { FREE(scred); RETURNC(r); } if (geteuid() == pwd->pw_uid) RETURNC(PAM_SUCCESS); if (initgroups(pwd->pw_name, pwd->pw_gid) < 0 || setegid(pwd->pw_gid) < 0 || seteuid(pwd->pw_uid) < 0) { openpam_restore_cred(pamh); RETURNC(PAM_SYSTEM_ERR); } RETURNC(PAM_SUCCESS); /*NOTREACHED*/ }
int openpam_set_option(pam_handle_t *pamh, const char *option, const char *value) { pam_chain_t *cur; char *opt, **optv; size_t len; int i; ENTERS(option); if (pamh == NULL || pamh->current == NULL || option == NULL) RETURNC(PAM_SYSTEM_ERR); cur = pamh->current; for (len = 0; option[len] != '\0'; ++len) if (option[len] == '=') break; for (i = 0; i < cur->optc; ++i) { if (strncmp(cur->optv[i], option, len) == 0 && (cur->optv[i][len] == '\0' || cur->optv[i][len] == '=')) break; } if (value == NULL) { /* remove */ if (i == cur->optc) RETURNC(PAM_SUCCESS); for (free(cur->optv[i]); i < cur->optc; ++i) cur->optv[i] = cur->optv[i + 1]; cur->optv[i] = NULL; RETURNC(PAM_SUCCESS); } if (asprintf(&opt, "%.*s=%s", (int)len, option, value) < 0) RETURNC(PAM_BUF_ERR); if (i == cur->optc) { /* add */ optv = realloc(cur->optv, sizeof(*optv) * ((size_t)cur->optc + 2)); if (optv == NULL) { FREE(opt); RETURNC(PAM_BUF_ERR); } optv[i] = opt; optv[i + 1] = NULL; cur->optv = optv; ++cur->optc; } else { /* replace */ FREE(cur->optv[i]); cur->optv[i] = opt; } RETURNC(PAM_SUCCESS); }