123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 |
- /* pam_item.c */
- /*
- * $Id$
- */
- #include "pam_private.h"
- #include <ctype.h>
- #include <stdlib.h>
- #include <string.h>
- #include <syslog.h>
- #define TRY_SET(X, Y) \
- { \
- if ((X) != (Y)) { \
- char *_TMP_ = _pam_strdup(Y); \
- if (_TMP_ == NULL && (Y) != NULL) \
- return PAM_BUF_ERR; \
- free(X); \
- (X) = _TMP_; \
- } \
- }
- /* functions */
- int pam_set_item (pam_handle_t *pamh, int item_type, const void *item)
- {
- int retval;
- D(("called"));
- IF_NO_PAMH("pam_set_item", pamh, PAM_SYSTEM_ERR);
- retval = PAM_SUCCESS;
- switch (item_type) {
- case PAM_SERVICE:
- /* Setting handlers_loaded to 0 will cause the handlers
- * to be reloaded on the next call to a service module.
- */
- pamh->handlers.handlers_loaded = 0;
- TRY_SET(pamh->service_name, item);
- {
- char *tmp;
- for (tmp=pamh->service_name; *tmp; ++tmp)
- *tmp = tolower(*tmp); /* require lower case */
- }
- break;
- case PAM_USER:
- TRY_SET(pamh->user, item);
- pamh->former.fail_user = PAM_SUCCESS;
- break;
- case PAM_USER_PROMPT:
- TRY_SET(pamh->prompt, item);
- pamh->former.fail_user = PAM_SUCCESS;
- break;
- case PAM_TTY:
- D(("setting tty to %s", item));
- TRY_SET(pamh->tty, item);
- break;
- case PAM_RUSER:
- TRY_SET(pamh->ruser, item);
- break;
- case PAM_RHOST:
- TRY_SET(pamh->rhost, item);
- break;
- case PAM_AUTHTOK:
- /*
- * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
- * modules.
- */
- if (__PAM_FROM_MODULE(pamh)) {
- if (pamh->authtok != item) {
- _pam_overwrite(pamh->authtok);
- TRY_SET(pamh->authtok, item);
- }
- } else {
- retval = PAM_BAD_ITEM;
- }
- break;
- case PAM_OLDAUTHTOK:
- /*
- * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
- * modules.
- */
- if (__PAM_FROM_MODULE(pamh)) {
- if (pamh->oldauthtok != item) {
- _pam_overwrite(pamh->oldauthtok);
- TRY_SET(pamh->oldauthtok, item);
- }
- } else {
- retval = PAM_BAD_ITEM;
- }
- break;
- case PAM_CONV: /* want to change the conversation function */
- if (item == NULL) {
- pam_syslog(pamh, LOG_ERR,
- "pam_set_item: attempt to set conv() to NULL");
- retval = PAM_PERM_DENIED;
- } else {
- struct pam_conv *tconv;
- if ((tconv=
- (struct pam_conv *) malloc(sizeof(struct pam_conv))
- ) == NULL) {
- pam_syslog(pamh, LOG_CRIT,
- "pam_set_item: malloc failed for pam_conv");
- retval = PAM_BUF_ERR;
- } else {
- memcpy(tconv, item, sizeof(struct pam_conv));
- _pam_drop(pamh->pam_conversation);
- pamh->pam_conversation = tconv;
- pamh->former.fail_user = PAM_SUCCESS;
- }
- }
- break;
- case PAM_FAIL_DELAY:
- pamh->fail_delay.delay_fn_ptr = item;
- break;
- case PAM_XDISPLAY:
- TRY_SET(pamh->xdisplay, item);
- break;
- case PAM_XAUTHDATA:
- if (&pamh->xauth == item)
- break;
- if (pamh->xauth.namelen) {
- _pam_overwrite(pamh->xauth.name);
- free(pamh->xauth.name);
- }
- if (pamh->xauth.datalen) {
- _pam_overwrite_n(pamh->xauth.data,
- (unsigned int) pamh->xauth.datalen);
- free(pamh->xauth.data);
- }
- pamh->xauth = *((const struct pam_xauth_data *) item);
- if ((pamh->xauth.name=_pam_strdup(pamh->xauth.name)) == NULL) {
- memset(&pamh->xauth, '\0', sizeof(pamh->xauth));
- return PAM_BUF_ERR;
- }
- if ((pamh->xauth.data=_pam_memdup(pamh->xauth.data,
- pamh->xauth.datalen)) == NULL) {
- _pam_overwrite(pamh->xauth.name);
- free(pamh->xauth.name);
- memset(&pamh->xauth, '\0', sizeof(pamh->xauth));
- return PAM_BUF_ERR;
- }
- break;
- case PAM_AUTHTOK_TYPE:
- TRY_SET(pamh->authtok_type, item);
- break;
- default:
- retval = PAM_BAD_ITEM;
- }
- return retval;
- }
- int pam_get_item (const pam_handle_t *pamh, int item_type, const void **item)
- {
- int retval = PAM_SUCCESS;
- D(("called."));
- IF_NO_PAMH("pam_get_item", pamh, PAM_SYSTEM_ERR);
- if (item == NULL) {
- pam_syslog(pamh, LOG_ERR,
- "pam_get_item: nowhere to place requested item");
- return PAM_PERM_DENIED;
- }
- else
- *item = NULL;
- switch (item_type) {
- case PAM_SERVICE:
- *item = pamh->service_name;
- break;
- case PAM_USER:
- D(("returning user=%s", pamh->user));
- *item = pamh->user;
- break;
- case PAM_USER_PROMPT:
- D(("returning userprompt=%s", pamh->user));
- *item = pamh->prompt;
- break;
- case PAM_TTY:
- D(("returning tty=%s", pamh->tty));
- *item = pamh->tty;
- break;
- case PAM_RUSER:
- *item = pamh->ruser;
- break;
- case PAM_RHOST:
- *item = pamh->rhost;
- break;
- case PAM_AUTHTOK:
- /*
- * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
- * modules.
- */
- if (__PAM_FROM_MODULE(pamh)) {
- *item = pamh->authtok;
- } else {
- retval = PAM_BAD_ITEM;
- }
- break;
- case PAM_OLDAUTHTOK:
- /*
- * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
- * modules.
- */
- if (__PAM_FROM_MODULE(pamh)) {
- *item = pamh->oldauthtok;
- } else {
- retval = PAM_BAD_ITEM;
- }
- break;
- case PAM_CONV:
- *item = pamh->pam_conversation;
- break;
- case PAM_FAIL_DELAY:
- *item = pamh->fail_delay.delay_fn_ptr;
- break;
- case PAM_XDISPLAY:
- *item = pamh->xdisplay;
- break;
- case PAM_XAUTHDATA:
- *item = &pamh->xauth;
- break;
- case PAM_AUTHTOK_TYPE:
- *item = pamh->authtok_type;
- break;
- default:
- retval = PAM_BAD_ITEM;
- }
- return retval;
- }
- /*
- * This function is the 'preferred method to obtain the username'.
- */
- int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt)
- {
- const char *use_prompt;
- int retval;
- struct pam_message msg;
- const struct pam_message *pmsg;
- struct pam_response *resp;
- D(("called."));
- IF_NO_PAMH("pam_get_user", pamh, PAM_SYSTEM_ERR);
- if (user == NULL) {
- /* ensure that the module has supplied a destination */
- pam_syslog(pamh, LOG_ERR, "pam_get_user: nowhere to record username");
- return PAM_SYSTEM_ERR;
- } else
- *user = NULL;
- if (pamh->pam_conversation == NULL) {
- pam_syslog(pamh, LOG_ERR, "pam_get_user: no conv element in pamh");
- return PAM_SYSTEM_ERR;
- }
- if (pamh->user) { /* have one so return it */
- *user = pamh->user;
- return PAM_SUCCESS;
- }
- if (pamh->former.fail_user != PAM_SUCCESS)
- return pamh->former.fail_user;
- /* will need a prompt */
- if (prompt != NULL)
- use_prompt = prompt;
- else if (pamh->prompt != NULL)
- use_prompt = pamh->prompt;
- else
- use_prompt = _("login:");
- /* If we are resuming an old conversation, we verify that the prompt
- is the same. Anything else is an error. */
- if (pamh->former.want_user) {
- /* must have a prompt to resume with */
- if (! pamh->former.prompt) {
- pam_syslog(pamh, LOG_ERR,
- "pam_get_user: failed to resume with prompt"
- );
- return PAM_ABORT;
- }
- /* must be the same prompt as last time */
- if (strcmp(pamh->former.prompt, use_prompt)) {
- pam_syslog(pamh, LOG_ERR,
- "pam_get_user: resumed with different prompt");
- return PAM_ABORT;
- }
- /* ok, we can resume where we left off last time */
- pamh->former.want_user = PAM_FALSE;
- _pam_overwrite(pamh->former.prompt);
- _pam_drop(pamh->former.prompt);
- }
- /* converse with application -- prompt user for a username */
- pmsg = &msg;
- msg.msg_style = PAM_PROMPT_ECHO_ON;
- msg.msg = use_prompt;
- resp = NULL;
- retval = pamh->pam_conversation->
- conv(1, &pmsg, &resp, pamh->pam_conversation->appdata_ptr);
- switch (retval) {
- case PAM_SUCCESS:
- case PAM_BUF_ERR:
- case PAM_CONV_AGAIN:
- case PAM_CONV_ERR:
- break;
- default:
- retval = PAM_CONV_ERR;
- }
- switch (retval) {
- case PAM_CONV_AGAIN:
- /* conversation function is waiting for an event - save state */
- D(("conversation function is not ready yet"));
- pamh->former.want_user = PAM_TRUE;
- pamh->former.prompt = _pam_strdup(use_prompt);
- break;
- case PAM_SUCCESS:
- if (resp != NULL && resp->resp != NULL) {
- /*
- * now we set the PAM_USER item -- this was missing from pre.53
- * releases. However, reading the Sun manual, it is part of
- * the standard API.
- */
- retval = pam_set_item(pamh, PAM_USER, resp->resp);
- *user = pamh->user;
- break;
- } else {
- /* conversation should have given a response */
- D(("pam_get_user: no response provided"));
- retval = PAM_CONV_ERR;
- }
- /* fallthrough */
- default:
- pamh->former.fail_user = retval;
- }
- if (resp) {
- if (retval != PAM_SUCCESS)
- pam_syslog(pamh, LOG_WARNING,
- "unexpected response from failed conversation function");
- /*
- * note 'resp' is allocated by the application and is
- * correctly free()'d here
- */
- _pam_drop_reply(resp, 1);
- }
- D(("completed"));
- return retval; /* pass on any error from conversation */
- }
|