summaryrefslogtreecommitdiffstats
path: root/libpam/pam_get_authtok.c
diff options
context:
space:
mode:
Diffstat (limited to 'libpam/pam_get_authtok.c')
-rw-r--r--libpam/pam_get_authtok.c280
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);
+}