/* Ask the application to display a short text string for us. */ static int make_remark(pam_handle_t * pamh, int ctrl, const char *remark) { int retval; if ((ctrl & MKHOMEDIR_QUIET) != MKHOMEDIR_QUIET) { struct pam_message msg[1], *mesg[1]; struct pam_response *resp = NULL; mesg[0] = &msg[0]; msg[0].msg_style = PAM_TEXT_INFO; msg[0].msg = remark; retval = converse(pamh, ctrl, 1, mesg, &resp); msg[0].msg = NULL; if (resp) { _pam_drop_reply(resp, 1); } } else { D(("keeping quiet")); retval = PAM_SUCCESS; } D(("returning %s", pam_strerror(pamh, retval))); return retval; }
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { int retval = PAM_SUCCESS; int fd; const char *username; char *mtmp=NULL; struct passwd *user_pwd; struct pam_conv *conversation; struct pam_message message; struct pam_message *pmessage = &message; struct pam_response *resp = NULL; struct stat st; if ((fd = open("/etc/nologin", O_RDONLY, 0)) >= 0) { /* root can still log in; lusers cannot */ if ((pam_get_user(pamh, &username, NULL) != PAM_SUCCESS) || !username) { return PAM_SERVICE_ERR; } user_pwd = getpwnam(username); if (user_pwd && user_pwd->pw_uid == 0) { message.msg_style = PAM_TEXT_INFO; } else { if (!user_pwd) { retval = PAM_USER_UNKNOWN; } else { retval = PAM_AUTH_ERR; } message.msg_style = PAM_ERROR_MSG; } /* fill in message buffer with contents of /etc/nologin */ if (fstat(fd, &st) < 0) /* give up trying to display message */ return retval; message.msg = mtmp = malloc(st.st_size+1); /* if malloc failed... */ if (!message.msg) return retval; read(fd, mtmp, st.st_size); mtmp[st.st_size] = '\000'; /* Use conversation function to give user contents of /etc/nologin */ pam_get_item(pamh, PAM_CONV, (const void **)&conversation); conversation->conv(1, (const struct pam_message **)&pmessage, &resp, conversation->appdata_ptr); free(mtmp); if (resp) _pam_drop_reply(resp, 1); } return retval; }
static int report_mail(pam_handle_t *pamh, int ctrl , const char *type, const char *folder) { int retval; if (!(ctrl & PAM_MAIL_SILENT) || ((ctrl & PAM_QUIET_MAIL) && strcmp(type, "new"))) { char *remark; if (ctrl & PAM_STANDARD_MAIL) if (!strcmp(type, "no")) remark = malloc(strlen(NO_MAIL_STANDARD_FORMAT)+1); else remark = malloc(strlen(YOUR_MAIL_STANDARD_FORMAT)+strlen(type)+1); else remark = malloc(strlen(YOUR_MAIL_VERBOSE_FORMAT)+strlen(type)+strlen(folder)+1); if (remark == NULL) { retval = PAM_BUF_ERR; } else { struct pam_message msg[1], *mesg[1]; struct pam_response *resp=NULL; if (ctrl & PAM_STANDARD_MAIL) if (!strcmp(type, "no")) sprintf(remark, NO_MAIL_STANDARD_FORMAT); else sprintf(remark, YOUR_MAIL_STANDARD_FORMAT, type); else sprintf(remark, YOUR_MAIL_VERBOSE_FORMAT, type, folder); mesg[0] = &msg[0]; msg[0].msg_style = PAM_TEXT_INFO; msg[0].msg = remark; retval = converse(pamh, ctrl, 1, mesg, &resp); _pam_overwrite(remark); _pam_drop(remark); if (resp) _pam_drop_reply(resp, 1); } } else { D(("keeping quiet")); retval = PAM_SUCCESS; } D(("returning %s", pam_strerror(pamh, retval))); return retval; }
static int conversation( pam_handle_t * pamh ) { struct pam_message msg[2], *pmsg[2]; struct pam_response * resp; int retval; char * token = NULL; pmsg[0] = &msg[0]; msg[0].msg_style = PAM_PROMPT_ECHO_OFF; msg[0].msg = "Password: "; // Call the conversation expecting 1 response resp = NULL; retval = converse( pamh, pmsg, &resp ); if( resp != NULL ) { void const * item; // interpret the response if( retval == PAM_SUCCESS ) { token = x_strdup( resp[0].resp ); if( token == NULL ) { return PAM_AUTHTOK_RECOVER_ERR; } } // Set the auth token retval = pam_set_item( pamh, PAM_AUTHTOK, token ); token = _pam_delete( token ); if( retval != PAM_SUCCESS || (retval = pam_get_item( pamh, PAM_AUTHTOK, & item )) != PAM_SUCCESS ) { return retval; } _pam_drop_reply( resp, 1 ); } else if( retval == PAM_SUCCESS ) { retval = PAM_AUTHTOK_RECOVER_ERR; } return retval; }
static int make_remark(pam_handle_t *pamh, unsigned int ctrl, int type, const char *text) { struct pam_message *pmsg[1], msg[1]; struct pam_response *resp; int retval; pmsg[0] = &msg[0]; msg[0].msg = text; msg[0].msg_style = type; resp = NULL; retval = converse(pamh, ctrl, 1, pmsg, &resp); if (retval == PAM_SUCCESS) _pam_drop_reply(resp, 1); return retval; }
static int _make_remark(pam_handle_t * pamh, int type, const char *text) { int retval = PAM_SUCCESS; struct pam_message *pmsg[1], msg[1]; struct pam_response *resp; pmsg[0] = &msg[0]; msg[0].msg = text; msg[0].msg_style = type; resp = NULL; retval = converse(pamh, 1, pmsg, &resp); if (resp) { _pam_drop_reply(resp, 1); } return retval; }
int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt) { const char *use_prompt; int retval; struct pam_message msg,*pmsg; struct pam_response *resp; D(("called.")); IF_NO_PAMH("pam_get_user", pamh, PAM_SYSTEM_ERR); if (pamh->pam_conversation == NULL) { _pam_system_log(LOG_ERR, "pam_get_user: no conv element in pamh"); return PAM_SERVICE_ERR; } if (user == NULL) { /* ensure the the module has suplied a destination */ _pam_system_log(LOG_ERR, "pam_get_user: nowhere to record username"); return PAM_PERM_DENIED; } else *user = NULL; if (pamh->user) { /* have one so return it */ *user = pamh->user; return PAM_SUCCESS; } /* will need a prompt */ use_prompt = prompt; if (use_prompt == NULL) { use_prompt = pamh->prompt; if (use_prompt == NULL) { use_prompt = PAM_DEFAULT_PROMPT; } } /* 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_system_log(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_system_log(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, (const struct pam_message **) &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) { /* * conversation should have given a response */ D(("pam_get_user: no response provided")); retval = PAM_CONV_ERR; } 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. */ RESET(pamh->user, resp->resp); *user = pamh->user; } if (resp) { /* * 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 */ }
PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) { params_t params; struct pam_response *resp; struct passwd *pw, fake_pw; #ifdef HAVE_SHADOW struct spwd *spw; #endif char *user, *oldpass, *newpass, *randompass; const char *reason; int ask_oldauthtok; int randomonly, enforce, retries_left, retry_wanted; int status; params = defaults; status = parse(¶ms, pamh, argc, argv); if (status != PAM_SUCCESS) return status; ask_oldauthtok = 0; if (flags & PAM_PRELIM_CHECK) { if (params.flags & F_ASK_OLDAUTHTOK_PRELIM) ask_oldauthtok = 1; } else if (flags & PAM_UPDATE_AUTHTOK) { if (params.flags & F_ASK_OLDAUTHTOK_UPDATE) ask_oldauthtok = 1; } else return PAM_SERVICE_ERR; if (ask_oldauthtok && getuid() != 0) { status = converse(pamh, PAM_PROMPT_ECHO_OFF, PROMPT_OLDPASS, &resp); if (status == PAM_SUCCESS) { if (resp && resp->resp) { status = pam_set_item(pamh, PAM_OLDAUTHTOK, resp->resp); _pam_drop_reply(resp, 1); } else status = PAM_AUTHTOK_RECOVERY_ERR; } if (status != PAM_SUCCESS) return status; } if (flags & PAM_PRELIM_CHECK) return status; status = pam_get_item(pamh, PAM_USER, (pam_item_t *)&user); if (status != PAM_SUCCESS) return status; status = pam_get_item(pamh, PAM_OLDAUTHTOK, (pam_item_t *)&oldpass); if (status != PAM_SUCCESS) return status; if (params.flags & F_NON_UNIX) { pw = &fake_pw; pw->pw_name = user; pw->pw_gecos = ""; } else { pw = getpwnam(user); endpwent(); if (!pw) return PAM_USER_UNKNOWN; if ((params.flags & F_CHECK_OLDAUTHTOK) && getuid() != 0) { if (!oldpass) status = PAM_AUTH_ERR; else #ifdef HAVE_SHADOW if (!strcmp(pw->pw_passwd, "x")) { spw = getspnam(user); endspent(); if (spw) { if (strcmp(crypt(oldpass, spw->sp_pwdp), spw->sp_pwdp)) status = PAM_AUTH_ERR; memset(spw->sp_pwdp, 0, strlen(spw->sp_pwdp)); } else status = PAM_AUTH_ERR; } else #endif if (strcmp(crypt(oldpass, pw->pw_passwd), pw->pw_passwd)) status = PAM_AUTH_ERR; } memset(pw->pw_passwd, 0, strlen(pw->pw_passwd)); if (status != PAM_SUCCESS) return status; } randomonly = params.qc.min[4] > params.qc.max; if (getuid() != 0) enforce = params.flags & F_ENFORCE_USERS; else enforce = params.flags & F_ENFORCE_ROOT; if (params.flags & F_USE_AUTHTOK) { status = pam_get_item(pamh, PAM_AUTHTOK, (pam_item_t *)&newpass); if (status != PAM_SUCCESS) return status; if (!newpass || (check_max(¶ms, pamh, newpass) && enforce)) return PAM_AUTHTOK_ERR; reason = _passwdqc_check(¶ms.qc, newpass, oldpass, pw); if (reason) { say(pamh, PAM_ERROR_MSG, MESSAGE_WEAKPASS, reason); if (enforce) status = PAM_AUTHTOK_ERR; } return status; } retries_left = params.retry; retry: retry_wanted = 0; if (!randomonly && params.qc.passphrase_words && params.qc.min[2] <= params.qc.max) status = say(pamh, PAM_TEXT_INFO, MESSAGE_INTRO_BOTH); else status = say(pamh, PAM_TEXT_INFO, MESSAGE_INTRO_PASSWORD); if (status != PAM_SUCCESS) return status; if (!randomonly && params.qc.min[3] <= params.qc.min[4]) status = say(pamh, PAM_TEXT_INFO, MESSAGE_EXPLAIN_PASSWORD_1, params.qc.min[3] == 8 || params.qc.min[3] == 11 ? "n" : "", params.qc.min[3]); else if (!randomonly) status = say(pamh, PAM_TEXT_INFO, MESSAGE_EXPLAIN_PASSWORD_2, params.qc.min[3] == 8 || params.qc.min[3] == 11 ? "n" : "", params.qc.min[3], params.qc.min[4] == 8 || params.qc.min[4] == 11 ? "n" : "", params.qc.min[4]); if (status != PAM_SUCCESS) return status; if (!randomonly && params.qc.passphrase_words && params.qc.min[2] <= params.qc.max) { status = say(pamh, PAM_TEXT_INFO, MESSAGE_EXPLAIN_PASSPHRASE, params.qc.passphrase_words, params.qc.min[2], params.qc.max); if (status != PAM_SUCCESS) return status; } randompass = _passwdqc_random(¶ms.qc); if (randompass) { status = say(pamh, PAM_TEXT_INFO, randomonly ? MESSAGE_RANDOMONLY : MESSAGE_RANDOM, randompass); if (status != PAM_SUCCESS) { _pam_overwrite(randompass); randompass = NULL; } } else if (randomonly) { say(pamh, PAM_ERROR_MSG, getuid() != 0 ? MESSAGE_MISCONFIGURED : MESSAGE_RANDOMFAILED); return PAM_AUTHTOK_ERR; } status = converse(pamh, PAM_PROMPT_ECHO_OFF, PROMPT_NEWPASS1, &resp); if (status == PAM_SUCCESS && (!resp || !resp->resp)) status = PAM_AUTHTOK_ERR; if (status != PAM_SUCCESS) { if (randompass) _pam_overwrite(randompass); return status; } newpass = strdup(resp->resp); _pam_drop_reply(resp, 1); if (!newpass) { if (randompass) _pam_overwrite(randompass); return PAM_AUTHTOK_ERR; } if (check_max(¶ms, pamh, newpass) && enforce) { status = PAM_AUTHTOK_ERR; retry_wanted = 1; } reason = NULL; if (status == PAM_SUCCESS && (!randompass || !strstr(newpass, randompass)) && (randomonly || (reason = _passwdqc_check(¶ms.qc, newpass, oldpass, pw)))) { if (randomonly) say(pamh, PAM_ERROR_MSG, MESSAGE_NOTRANDOM); else say(pamh, PAM_ERROR_MSG, MESSAGE_WEAKPASS, reason); if (enforce) { status = PAM_AUTHTOK_ERR; retry_wanted = 1; } } if (status == PAM_SUCCESS) status = converse(pamh, PAM_PROMPT_ECHO_OFF, PROMPT_NEWPASS2, &resp); if (status == PAM_SUCCESS) { if (resp && resp->resp) { if (strcmp(newpass, resp->resp)) { status = say(pamh, PAM_ERROR_MSG, MESSAGE_MISTYPED); if (status == PAM_SUCCESS) { status = PAM_AUTHTOK_ERR; retry_wanted = 1; } } _pam_drop_reply(resp, 1); } else status = PAM_AUTHTOK_ERR; } if (status == PAM_SUCCESS) status = pam_set_item(pamh, PAM_AUTHTOK, newpass); if (randompass) _pam_overwrite(randompass); _pam_overwrite(newpass); free(newpass); if (retry_wanted && --retries_left > 0) { status = say(pamh, PAM_TEXT_INFO, MESSAGE_RETRY); if (status == PAM_SUCCESS) goto retry; } return status; }
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc ,const char **argv) { int retval, anon=0, ctrl; const char *user; char *users=NULL; /* * this module checks if the user name is ftp or annonymous. If * this is the case, it can set the PAM_RUSER to the entered email * address and SUCCEEDS, otherwise it FAILS. */ ctrl = _pam_parse(argc, argv, &users); retval = pam_get_user(pamh, &user, NULL); if (retval != PAM_SUCCESS || user == NULL) { _pam_log(LOG_ERR, "no user specified"); return PAM_USER_UNKNOWN; } if (!(ctrl & PAM_NO_ANON)) { anon = lookup(user, users, &user); } if (anon) { retval = pam_set_item(pamh, PAM_USER, (const void *)user); if (retval != PAM_SUCCESS || user == NULL) { _pam_log(LOG_ERR, "user resetting failed"); return PAM_USER_UNKNOWN; } } /* * OK. we require an email address for user or the user's password. * - build conversation and get their input. */ { struct pam_message msg[1], *mesg[1]; struct pam_response *resp=NULL; const char *token; char *prompt=NULL; int i=0; if (!anon) { prompt = malloc(strlen(PLEASE_ENTER_PASSWORD) + strlen(user)); if (prompt == NULL) { D(("out of memory!?")); return PAM_BUF_ERR; } else { sprintf(prompt, PLEASE_ENTER_PASSWORD, user); msg[i].msg = prompt; } } else { msg[i].msg = GUEST_LOGIN_PROMPT; } msg[i].msg_style = PAM_PROMPT_ECHO_OFF; mesg[i] = &msg[i]; retval = converse(pamh, ++i, mesg, &resp); if (prompt) { _pam_overwrite(prompt); _pam_drop(prompt); } if (retval != PAM_SUCCESS) { if (resp != NULL) _pam_drop_reply(resp,i); return ((retval == PAM_CONV_AGAIN) ? PAM_INCOMPLETE:PAM_AUTHINFO_UNAVAIL); } if (anon) { /* XXX: Some effort should be made to verify this email address! */ if (!(ctrl & PAM_IGNORE_EMAIL)) { token = strtok(resp->resp, "@"); retval = pam_set_item(pamh, PAM_RUSER, token); if ((token) && (retval == PAM_SUCCESS)) { token = strtok(NULL, "@"); retval = pam_set_item(pamh, PAM_RHOST, token); } } /* we are happy to grant annonymous access to the user */ retval = PAM_SUCCESS; } else { /* * we have a password so set AUTHTOK */ (void) pam_set_item(pamh, PAM_AUTHTOK, resp->resp); /* * this module failed, but the next one might succeed with * this password. */ retval = PAM_AUTH_ERR; } if (resp) { /* clean up */ _pam_drop_reply(resp, i); } /* success or failure */ return retval; } }
static int _winbind_read_password(pam_handle_t * pamh ,unsigned int ctrl ,const char *comment ,const char *prompt1 ,const char *prompt2 ,const char **pass) { int authtok_flag; int retval; const char *item; char *token; /* * make sure nothing inappropriate gets returned */ *pass = token = NULL; /* * which authentication token are we getting? */ authtok_flag = on(WINBIND__OLD_PASSWORD, ctrl) ? PAM_OLDAUTHTOK : PAM_AUTHTOK; /* * should we obtain the password from a PAM item ? */ if (on(WINBIND_TRY_FIRST_PASS_ARG, ctrl) || on(WINBIND_USE_FIRST_PASS_ARG, ctrl)) { retval = pam_get_item(pamh, authtok_flag, (const void **) &item); if (retval != PAM_SUCCESS) { /* very strange. */ _pam_log(LOG_ALERT, "pam_get_item returned error to unix-read-password" ); return retval; } else if (item != NULL) { /* we have a password! */ *pass = item; item = NULL; return PAM_SUCCESS; } else if (on(WINBIND_USE_FIRST_PASS_ARG, ctrl)) { return PAM_AUTHTOK_RECOVER_ERR; /* didn't work */ } else if (on(WINBIND_USE_AUTHTOK_ARG, ctrl) && off(WINBIND__OLD_PASSWORD, ctrl)) { return PAM_AUTHTOK_RECOVER_ERR; } } /* * getting here implies we will have to get the password from the * user directly. */ { struct pam_message msg[3], *pmsg[3]; struct pam_response *resp; int i, replies; /* prepare to converse */ if (comment != NULL) { pmsg[0] = &msg[0]; msg[0].msg_style = PAM_TEXT_INFO; msg[0].msg = comment; i = 1; } else { i = 0; } pmsg[i] = &msg[i]; msg[i].msg_style = PAM_PROMPT_ECHO_OFF; msg[i++].msg = prompt1; replies = 1; if (prompt2 != NULL) { pmsg[i] = &msg[i]; msg[i].msg_style = PAM_PROMPT_ECHO_OFF; msg[i++].msg = prompt2; ++replies; } /* so call the conversation expecting i responses */ resp = NULL; retval = converse(pamh, i, pmsg, &resp); if (resp != NULL) { /* interpret the response */ if (retval == PAM_SUCCESS) { /* a good conversation */ token = x_strdup(resp[i - replies].resp); if (token != NULL) { if (replies == 2) { /* verify that password entered correctly */ if (!resp[i - 1].resp || strcmp(token, resp[i - 1].resp)) { _pam_delete(token); /* mistyped */ retval = PAM_AUTHTOK_RECOVER_ERR; _make_remark(pamh ,PAM_ERROR_MSG, MISTYPED_PASS); } } } else { _pam_log(LOG_NOTICE ,"could not recover authentication token"); } } /* * tidy up the conversation (resp_retcode) is ignored * -- what is it for anyway? AGM */ _pam_drop_reply(resp, i); } else { retval = (retval == PAM_SUCCESS) ? PAM_AUTHTOK_RECOVER_ERR : retval; } } if (retval != PAM_SUCCESS) { if (on(WINBIND_DEBUG_ARG, ctrl)) _pam_log(LOG_DEBUG, "unable to obtain a password"); return retval; } /* 'token' is the entered password */ /* we store this password as an item */ retval = pam_set_item(pamh, authtok_flag, token); _pam_delete(token); /* clean it up */ if (retval != PAM_SUCCESS || (retval = pam_get_item(pamh, authtok_flag ,(const void **) &item)) != PAM_SUCCESS) { _pam_log(LOG_CRIT, "error manipulating password"); return retval; } *pass = item; item = NULL; /* break link to password */ return PAM_SUCCESS; }