diff options
Diffstat (limited to 'source3/auth')
-rw-r--r-- | source3/auth/pampass.c | 184 |
1 files changed, 140 insertions, 44 deletions
diff --git a/source3/auth/pampass.c b/source3/auth/pampass.c index e27e15f24f..53d2a062fd 100644 --- a/source3/auth/pampass.c +++ b/source3/auth/pampass.c @@ -71,6 +71,7 @@ static BOOL smb_pam_error_handler(pam_handle_t *pamh, int pam_error, char *msg, if( pam_error != PAM_SUCCESS) { DEBUG(dbglvl, ("smb_pam_error_handler: PAM: %s : %s\n", msg, pam_strerror(pamh, pam_error))); + return False; } return True; @@ -130,6 +131,8 @@ static int smb_pam_conv(int num_msg, if (!reply) return PAM_CONV_ERR; + memset(reply, '\0', sizeof(struct pam_response) * num_msg); + for (replies = 0; replies < num_msg; replies++) { switch (msg[replies]->msg_style) { case PAM_PROMPT_ECHO_ON: @@ -170,6 +173,82 @@ static int smb_pam_conv(int num_msg, * echo off means password. */ +static void special_char_sub(char *buf) +{ + all_string_sub(buf, "\\n", "", 0); + all_string_sub(buf, "\\r", "", 0); + all_string_sub(buf, "\\s", " ", 0); + all_string_sub(buf, "\\t", "\t", 0); +} + +static void pwd_sub(char *buf, char *username, char *oldpass, char *newpass) +{ + pstring_sub(buf, "%u", username); + all_string_sub(buf, "%o", oldpass, sizeof(fstring)); + all_string_sub(buf, "%n", newpass, sizeof(fstring)); +} + + +struct chat_struct { + struct chat_struct *next, *prev; + fstring prompt; + fstring reply; +}; + +/************************************************************** + Create a linked list containing chat data. +***************************************************************/ + +static struct chat_struct *make_pw_chat(char *p) +{ + fstring prompt; + fstring reply; + struct chat_struct *list = NULL; + struct chat_struct *t; + struct chat_struct *tmp; + + while (1) { + t = (struct chat_struct *)malloc(sizeof(*t)); + if (!t) { + DEBUG(0,("make_pw_chat: malloc failed!\n")); + return NULL; + } + + ZERO_STRUCTP(t); + + DLIST_ADD_END(list, t, tmp); + + if (!next_token(&p, prompt, NULL, sizeof(fstring))) + break; + + if (strequal(prompt,".")) + fstrcpy(prompt,"*"); + + special_char_sub(prompt); + fstrcpy(t->prompt, prompt); + + if (!next_token(&p, reply, NULL, sizeof(fstring))) + break; + + if (strequal(reply,".")) + fstrcpy(reply,""); + + special_char_sub(reply); + fstrcpy(t->reply, reply); + + } + return list; +} + +static void free_pw_chat(struct chat_struct *list) +{ + while (list) { + struct chat_struct *old_head = list; + DLIST_REMOVE(list, list); + free(old_head); + } +} + static int smb_pam_passchange_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, @@ -177,18 +256,22 @@ static int smb_pam_passchange_conv(int num_msg, { int replies = 0; struct pam_response *reply = NULL; - fstring oldpw_prompt; - fstring newpw_prompt; - fstring repeatpw_prompt; - fstring prompt_ret; - char *p = lp_passwd_chat(); + fstring current_prompt; + fstring current_reply; struct smb_pam_userdata *udp = (struct smb_pam_userdata *)appdata_ptr; - + struct chat_struct *pw_chat= make_pw_chat(lp_passwd_chat()); + struct chat_struct *t; + BOOL found; *resp = NULL; + + DEBUG(10,("smb_pam_passchange_conv: starting converstation for %d messages\n", num_msg)); if (num_msg <= 0) return PAM_CONV_ERR; + if (pw_chat == NULL) + return PAM_CONV_ERR; + /* * Apparantly HPUX has a buggy PAM that doesn't support the * appdata_ptr. Fail if this is the case. JRA. @@ -196,62 +279,73 @@ static int smb_pam_passchange_conv(int num_msg, if (udp == NULL) { DEBUG(0,("smb_pam_passchange_conv: PAM on this system is broken - appdata_ptr == NULL !\n")); + free_pw_chat(pw_chat); return PAM_CONV_ERR; } - /* Get the prompts. */ - - if (!next_token(&p, oldpw_prompt, NULL, sizeof(fstring))) - return PAM_CONV_ERR; - strlower(oldpw_prompt); - if (!next_token(&p, newpw_prompt, NULL, sizeof(fstring))) - return PAM_CONV_ERR; - strlower(newpw_prompt); - if (!next_token(&p, repeatpw_prompt, NULL, sizeof(fstring))) - return PAM_CONV_ERR; - strlower(repeatpw_prompt); - reply = malloc(sizeof(struct pam_response) * num_msg); - if (!reply) + if (!reply) { + DEBUG(0,("smb_pam_passchange_conv: malloc for reply failed!\n")); + free_pw_chat(pw_chat); return PAM_CONV_ERR; + } for (replies = 0; replies < num_msg; replies++) { + found = False; + DEBUG(10,("smb_pam_passchange_conv: Processing message %d\n", replies)); switch (msg[replies]->msg_style) { case PAM_PROMPT_ECHO_ON: - DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: Replied: %s\n", msg[replies]->msg)); - reply[replies].resp_retcode = PAM_SUCCESS; - reply[replies].resp = COPY_STRING(udp->PAM_username); + DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: PAM said: %s\n", msg[replies]->msg)); + fstrcpy(current_prompt, msg[replies]->msg); + strlower(current_prompt); + for (t=pw_chat; t; t=t->next) { + if (ms_fnmatch(t->prompt, current_prompt) == 0) { + fstrcpy(current_reply, t->reply); + pwd_sub(current_reply, udp->PAM_username, udp->PAM_password, udp->PAM_newpassword); + DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: We sent: %s\n", current_reply)); + reply[replies].resp_retcode = PAM_SUCCESS; + reply[replies].resp = COPY_STRING(current_reply); + found = True; + break; + } + } /* PAM frees resp */ - break; - - case PAM_PROMPT_ECHO_OFF: - reply[replies].resp_retcode = PAM_SUCCESS; - if (!msg[replies]->msg) { + if (!found) { + DEBUG(3,("smb_pam_passchange_conv: Could not find reply for PAM prompt: %s\n",msg[replies]->msg)); + free_pw_chat(pw_chat); free(reply); reply = NULL; return PAM_CONV_ERR; } + break; - DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: Replied: %s\n", msg[replies]->msg)); - - fstrcpy(prompt_ret, msg[replies]->msg); - strlower(prompt_ret); - - if (ms_fnmatch( oldpw_prompt, prompt_ret) == 0) { - reply[replies].resp = COPY_STRING(udp->PAM_password); - } else if (ms_fnmatch( newpw_prompt, prompt_ret) == 0) { - reply[replies].resp = COPY_STRING(udp->PAM_newpassword); - } else if (ms_fnmatch(repeatpw_prompt, prompt_ret) == 0) { - reply[replies].resp = COPY_STRING(udp->PAM_newpassword); - } else { + case PAM_PROMPT_ECHO_OFF: + DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: PAM said: %s\n", msg[replies]->msg)); + fstrcpy(current_prompt, msg[replies]->msg); + strlower(current_prompt); + for (t=pw_chat; t; t=t->next) { + if (ms_fnmatch(t->prompt, current_prompt) == 0) { + fstrcpy(current_reply, t->reply); + DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: We sent: %s\n", current_reply)); + pwd_sub(current_reply, udp->PAM_username, udp->PAM_password, udp->PAM_newpassword); + reply[replies].resp_retcode = PAM_SUCCESS; + reply[replies].resp = COPY_STRING(current_reply); +#ifdef DEBUG_PASSWORD + DEBUG(100,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: We actualy sent: %s\n", current_reply)); +#endif + found = True; + break; + } + } + /* PAM frees resp */ + + if (!found) { DEBUG(3,("smb_pam_passchange_conv: Could not find reply for PAM prompt: %s\n",msg[replies]->msg)); - DEBUG(5,("smb_pam_passchange_conv: Prompts available:\n OldPW: \"%s\"\nNewPW: \"%s\"\n \ -RepeatPW: \"%s\"\n",oldpw_prompt, newpw_prompt,repeatpw_prompt)); + free_pw_chat(pw_chat); free(reply); reply = NULL; return PAM_CONV_ERR; } - /* PAM frees resp */ break; case PAM_TEXT_INFO: @@ -262,15 +356,17 @@ RepeatPW: \"%s\"\n",oldpw_prompt, newpw_prompt,repeatpw_prompt)); reply[replies].resp_retcode = PAM_SUCCESS; reply[replies].resp = NULL; break; - + default: /* Must be an error of some sort... */ + free_pw_chat(pw_chat); free(reply); reply = NULL; return PAM_CONV_ERR; } } - + + free_pw_chat(pw_chat); if (reply) *resp = reply; return PAM_SUCCESS; |