2 * Redistribution and use in source and binary forms, with or without
3 * modification, are permitted provided that the following conditions
5 * 1. Redistributions of source code must retain the above copyright
6 * notice, and the entire permission notice in its entirety,
7 * including the disclaimer of warranties.
8 * 2. Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 * 3. The name of the author may not be used to endorse or promote
12 * products derived from this software without specific prior
15 * ALTERNATIVELY, this product may be distributed under the terms of
16 * the GNU Public License, in which case the provisions of the GPL are
17 * required INSTEAD OF the above restrictions. (This clause is
18 * necessary due to a potential bad interaction between the GPL and
19 * the restrictions contained in a BSD-style copyright.)
21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31 * OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include "pam_private.h"
37 #include <security/pam_ext.h>
39 #define PROMPT _("Password: ")
40 /* For Translators: "%s%s" could be replaced with "<service> " or "". */
41 #define PROMPTCURRENT _("Current %s%spassword: ")
42 /* For Translators: "%s%s" could be replaced with "<service> " or "". */
43 #define PROMPT1 _("New %s%spassword: ")
44 /* For Translators: "%s%s" could be replaced with "<service> " or "". */
45 #define PROMPT2 _("Retype new %s%spassword: ")
46 #define MISTYPED_PASS _("Sorry, passwords do not match.")
48 #define PAM_GETAUTHTOK_NOVERIFY 1
51 get_option (pam_handle_t *pamh, const char *option)
57 if (option == NULL || pamh == NULL ||
58 pamh->mod_argc == 0 || pamh->mod_argv == NULL)
61 len = strlen (option);
63 for (i = 0; i < pamh->mod_argc; i++)
65 if (strncmp (option, pamh->mod_argv[i], len) == 0)
67 if (pamh->mod_argv[i][len] == '=')
68 return &(pamh->mod_argv[i][len+1]);
69 else if (pamh->mod_argv[i][len] == '\0')
78 pam_get_authtok_internal (pam_handle_t *pamh, int item,
79 const char **authtok, const char *prompt,
83 char *resp[2] = {NULL, NULL};
84 const void *prevauthtok;
85 const char *authtok_type = "";
86 int chpass = 0; /* Password change, ask twice for it */
90 return PAM_SYSTEM_ERR;
92 /* PAM_AUTHTOK in password stack returns new password,
93 which needs to be verified. */
94 if (pamh->choice == PAM_CHAUTHTOK)
96 if (item == PAM_AUTHTOK)
99 if (!(flags & PAM_GETAUTHTOK_NOVERIFY))
102 authtok_type = get_option (pamh, "authtok_type");
103 if (authtok_type == NULL)
105 retval = pam_get_item (pamh, PAM_AUTHTOK_TYPE, (const void **)&authtok_type);
106 if (retval != PAM_SUCCESS || authtok_type == NULL)
110 pam_set_item(pamh, PAM_AUTHTOK_TYPE, authtok_type);
113 retval = pam_get_item (pamh, item, &prevauthtok);
114 if (retval == PAM_SUCCESS && prevauthtok != NULL)
116 *authtok = prevauthtok;
119 else if (get_option (pamh, "use_first_pass") ||
120 (chpass && get_option (pamh, "use_authtok")))
122 if (prevauthtok == NULL)
125 return PAM_AUTHTOK_ERR;
135 retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[0],
137 if (retval == PAM_SUCCESS && chpass > 1 && resp[0] != NULL)
138 retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[1],
139 _("Retype %s"), prompt);
143 pamh->authtok_verified = 0;
145 retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[0],
146 PROMPT1, authtok_type,
147 strlen (authtok_type) > 0?" ":"");
148 if (retval == PAM_SUCCESS && chpass > 1 && resp[0] != NULL)
149 retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[1],
150 PROMPT2, authtok_type,
151 strlen (authtok_type) > 0?" ":"");
153 else if (item == PAM_OLDAUTHTOK)
154 retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[0],
155 PROMPTCURRENT, authtok_type,
156 strlen (authtok_type) > 0?" ":"");
158 retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[0], "%s",
161 if (retval != PAM_SUCCESS || resp[0] == NULL ||
162 (chpass > 1 && resp[1] == NULL))
164 /* We want to abort */
166 pam_error (pamh, _("Password change has been aborted."));
167 return PAM_AUTHTOK_ERR;
170 if (chpass > 1 && strcmp (resp[0], resp[1]) != 0)
172 pam_error (pamh, MISTYPED_PASS);
173 _pam_overwrite (resp[0]);
175 _pam_overwrite (resp[1]);
177 return PAM_TRY_AGAIN;
180 _pam_overwrite (resp[1]);
183 retval = pam_set_item (pamh, item, resp[0]);
184 _pam_overwrite (resp[0]);
186 if (retval != PAM_SUCCESS)
190 pamh->authtok_verified = 1;
192 return pam_get_item(pamh, item, (const void **)authtok);
196 pam_get_authtok (pam_handle_t *pamh, int item, const char **authtok,
199 return pam_get_authtok_internal (pamh, item, authtok, prompt, 0);
204 pam_get_authtok_noverify (pam_handle_t *pamh, const char **authtok,
207 return pam_get_authtok_internal (pamh, PAM_AUTHTOK, authtok, prompt,
208 PAM_GETAUTHTOK_NOVERIFY);
212 pam_get_authtok_verify (pam_handle_t *pamh, const char **authtok,
216 const char *authtok_type = "";
219 if (authtok == NULL || pamh->choice != PAM_CHAUTHTOK)
220 return PAM_SYSTEM_ERR;
222 if (pamh->authtok_verified)
223 return pam_get_item (pamh, PAM_AUTHTOK, (const void **)authtok);
227 retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp,
228 _("Retype %s"), prompt);
232 retval = pam_get_item (pamh, PAM_AUTHTOK_TYPE, (const void **)&authtok_type);
233 if (retval != PAM_SUCCESS || authtok_type == NULL)
235 retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp,
236 PROMPT2, authtok_type,
237 strlen (authtok_type) > 0?" ":"");
240 if (retval != PAM_SUCCESS || resp == NULL)
242 /* We want to abort the password change */
243 pam_set_item (pamh, PAM_AUTHTOK, NULL);
244 pam_error (pamh, _("Password change has been aborted."));
245 return PAM_AUTHTOK_ERR;
248 if (strcmp (*authtok, resp) != 0)
250 pam_set_item (pamh, PAM_AUTHTOK, NULL);
251 pam_error (pamh, MISTYPED_PASS);
252 _pam_overwrite (resp);
254 return PAM_TRY_AGAIN;
257 retval = pam_set_item (pamh, PAM_AUTHTOK, resp);
258 _pam_overwrite (resp);
260 if (retval != PAM_SUCCESS)
263 pamh->authtok_verified = 1;
265 return pam_get_item(pamh, PAM_AUTHTOK, (const void **)authtok);