/* pam_item.c */ /* * $Id$ */ #include "pam_private.h" #include #include #include #include #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_PERM_DENIED; } else *user = NULL; if (pamh->pam_conversation == NULL) { pam_syslog(pamh, LOG_ERR, "pam_get_user: no conv element in pamh"); return PAM_SERVICE_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); if (retval == 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); } else if (resp == NULL || resp->resp == NULL) { /* * conversation should have given a response */ D(("pam_get_user: no response provided")); retval = PAM_CONV_ERR; pamh->former.fail_user = retval; } else if (retval == PAM_SUCCESS) { /* copy the username */ /* * 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; } else 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 */ }