diff options
Diffstat (limited to 'libpam/pam_get_authtok.c')
-rw-r--r-- | libpam/pam_get_authtok.c | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/libpam/pam_get_authtok.c b/libpam/pam_get_authtok.c new file mode 100644 index 0000000..3fa7f7d --- /dev/null +++ b/libpam/pam_get_authtok.c @@ -0,0 +1,280 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "pam_private.h" + +#include <security/pam_ext.h> + +#define PROMPT _("Password: ") +/* For Translators: "%s" is replaced with "<service>". */ +#define PROMPT_CURRENT_ARG _("Current %s password: ") +#define PROMPT_CURRENT_NOARG _("Current password: ") +/* For Translators: "%s" is replaced with "<service>". */ +#define PROMPT_NEW_ARG _("New %s password: ") +#define PROMPT_NEW_NOARG _("New password: ") +/* For Translators: "%s" is replaced with "<service>". */ +#define PROMPT_RETYPE_ARG _("Retype new %s password: ") +#define PROMPT_RETYPE_NOARG _("Retype new password: ") +#define MISTYPED_PASS _("Sorry, passwords do not match.") + +#define PAM_GETAUTHTOK_NOVERIFY 1 + +static const char * +get_option (pam_handle_t *pamh, const char *option) +{ + int i; + size_t len; + + + if (option == NULL || pamh == NULL || + pamh->mod_argc == 0 || pamh->mod_argv == NULL) + return NULL; + + len = strlen (option); + + for (i = 0; i < pamh->mod_argc; i++) + { + if (strncmp (option, pamh->mod_argv[i], len) == 0) + { + if (pamh->mod_argv[i][len] == '=') + return &(pamh->mod_argv[i][len+1]); + else if (pamh->mod_argv[i][len] == '\0') + return ""; + } + } + return NULL; +} + + +static int +pam_get_authtok_internal (pam_handle_t *pamh, int item, + const char **authtok, const char *prompt, + unsigned int flags) + +{ + char *resp[2] = {NULL, NULL}; + const void *prevauthtok; + const char *authtok_type = ""; + int chpass = 0; /* Password change, ask twice for it */ + int retval; + + if (authtok == NULL) + return PAM_SYSTEM_ERR; + + /* PAM_AUTHTOK in password stack returns new password, + which needs to be verified. */ + if (pamh->choice == PAM_CHAUTHTOK) + { + if (item == PAM_AUTHTOK) + { + chpass = 1; + if (!(flags & PAM_GETAUTHTOK_NOVERIFY)) + ++chpass; + } + authtok_type = get_option (pamh, "authtok_type"); + if (authtok_type == NULL) + { + retval = pam_get_item (pamh, PAM_AUTHTOK_TYPE, (const void **)&authtok_type); + if (retval != PAM_SUCCESS || authtok_type == NULL) + authtok_type = ""; + } + else + pam_set_item(pamh, PAM_AUTHTOK_TYPE, authtok_type); + } + + retval = pam_get_item (pamh, item, &prevauthtok); + if (retval == PAM_SUCCESS && prevauthtok != NULL) + { + *authtok = prevauthtok; + return PAM_SUCCESS; + } + else if (get_option (pamh, "use_first_pass") || + (chpass && get_option (pamh, "use_authtok"))) + { + if (prevauthtok == NULL) + { + if (chpass) + return PAM_AUTHTOK_ERR; + else + return PAM_AUTH_ERR; + } + else + return retval; + } + + if (prompt != NULL) + { + retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[0], + "%s", prompt); + if (retval == PAM_SUCCESS && chpass > 1 && resp[0] != NULL) + retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[1], + _("Retype %s"), prompt); + } + else if (chpass) + { + pamh->authtok_verified = 0; + + retval = *authtok_type ? + pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[0], + PROMPT_NEW_ARG, authtok_type) : + pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[0], + "%s", PROMPT_NEW_NOARG); + if (retval == PAM_SUCCESS && chpass > 1 && resp[0] != NULL) + { + retval = *authtok_type ? + pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[1], + PROMPT_RETYPE_ARG, authtok_type) : + pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[1], + "%s", PROMPT_RETYPE_NOARG); + } + } + else if (item == PAM_OLDAUTHTOK) + { + retval = *authtok_type ? + pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[0], + PROMPT_CURRENT_ARG, authtok_type) : + pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[0], + "%s", PROMPT_CURRENT_NOARG); + } + else + retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[0], "%s", PROMPT); + + if (retval != PAM_SUCCESS || resp[0] == NULL || + (chpass > 1 && resp[1] == NULL)) + { + /* We want to abort */ + if (chpass) + pam_error (pamh, _("Password change has been aborted.")); + return PAM_AUTHTOK_ERR; + } + + if (chpass > 1 && strcmp (resp[0], resp[1]) != 0) + { + pam_error (pamh, MISTYPED_PASS); + _pam_overwrite (resp[0]); + _pam_drop (resp[0]); + _pam_overwrite (resp[1]); + _pam_drop (resp[1]); + return PAM_TRY_AGAIN; + } + + _pam_overwrite (resp[1]); + _pam_drop (resp[1]); + + retval = pam_set_item (pamh, item, resp[0]); + _pam_overwrite (resp[0]); + _pam_drop (resp[0]); + if (retval != PAM_SUCCESS) + return retval; + + if (chpass > 1) + pamh->authtok_verified = 1; + + return pam_get_item(pamh, item, (const void **)authtok); +} + +int +pam_get_authtok (pam_handle_t *pamh, int item, const char **authtok, + const char *prompt) +{ + return pam_get_authtok_internal (pamh, item, authtok, prompt, 0); +} + + +int +pam_get_authtok_noverify (pam_handle_t *pamh, const char **authtok, + const char *prompt) +{ + return pam_get_authtok_internal (pamh, PAM_AUTHTOK, authtok, prompt, + PAM_GETAUTHTOK_NOVERIFY); +} + +int +pam_get_authtok_verify (pam_handle_t *pamh, const char **authtok, + const char *prompt) +{ + char *resp = NULL; + const char *authtok_type = ""; + int retval; + + if (authtok == NULL || pamh->choice != PAM_CHAUTHTOK) + return PAM_SYSTEM_ERR; + + if (pamh->authtok_verified) + return pam_get_item (pamh, PAM_AUTHTOK, (const void **)authtok); + + if (prompt != NULL) + { + retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp, + _("Retype %s"), prompt); + } + else + { + retval = pam_get_item (pamh, PAM_AUTHTOK_TYPE, (const void **)&authtok_type); + if (retval != PAM_SUCCESS || authtok_type == NULL) + authtok_type = ""; + retval = *authtok_type ? + pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp, + PROMPT_RETYPE_ARG, authtok_type) : + pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp, + "%s", PROMPT_RETYPE_NOARG); + } + + if (retval != PAM_SUCCESS || resp == NULL) + { + /* We want to abort the password change */ + pam_set_item (pamh, PAM_AUTHTOK, NULL); + pam_error (pamh, _("Password change has been aborted.")); + return PAM_AUTHTOK_ERR; + } + + if (strcmp (*authtok, resp) != 0) + { + pam_set_item (pamh, PAM_AUTHTOK, NULL); + pam_error (pamh, MISTYPED_PASS); + _pam_overwrite (resp); + _pam_drop (resp); + return PAM_TRY_AGAIN; + } + + retval = pam_set_item (pamh, PAM_AUTHTOK, resp); + _pam_overwrite (resp); + _pam_drop (resp); + if (retval != PAM_SUCCESS) + return retval; + + pamh->authtok_verified = 1; + + return pam_get_item(pamh, PAM_AUTHTOK, (const void **)authtok); +} |