1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <sys/varargs.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <syslog.h>
30
31 #include <security/pam_appl.h>
32 #include <security/pam_modules.h>
33 #include <security/pam_impl.h>
34
35 #include <sys/note.h>
36
37 #include <libintl.h>
38
39 #include <passwdutil.h>
40
41 /*PRINTFLIKE2*/
42 void
error(pam_handle_t * pamh,char * fmt,...)43 error(pam_handle_t *pamh, char *fmt, ...)
44 {
45 va_list ap;
46 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
47
48 va_start(ap, fmt);
49 (void) vsnprintf(messages[0], sizeof (messages[0]), fmt, ap);
50 (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, messages, NULL);
51 va_end(ap);
52 }
53
54 int
read_authtok(pam_handle_t * pamh,int debug)55 read_authtok(pam_handle_t *pamh, int debug)
56 {
57 int res;
58 char *authtok;
59 char *pwd;
60
61 /*
62 * We are about to read the new AUTHTOK. Store the AUTHTOK that
63 * the user used to authenticate in OLDAUTHTOK, so it is available
64 * to future modules. If OLDAUTHTOK is already set, we leave it alone
65 */
66
67 res = pam_get_item(pamh, PAM_OLDAUTHTOK, (void **)&authtok);
68 if (res != PAM_SUCCESS)
69 return (res);
70
71 if (authtok == NULL) {
72 res = pam_get_item(pamh, PAM_AUTHTOK, (void **)&authtok);
73 if (res != PAM_SUCCESS)
74 return (res);
75 if (authtok != NULL) {
76 res = pam_set_item(pamh, PAM_OLDAUTHTOK,
77 (void *)authtok);
78 if (res == PAM_SUCCESS)
79 res = pam_set_item(pamh, PAM_AUTHTOK, NULL);
80
81 if (debug)
82 __pam_log(LOG_AUTH | LOG_DEBUG,
83 "read_authtok: Copied AUTHTOK to "
84 "OLDAUTHTOK");
85
86 if (res != PAM_SUCCESS)
87 goto out;
88 }
89 } else {
90 /*
91 * OLDAUTHTOK was filled in. If AUTHTOK is also filled
92 * in, we either succeed a module that has done our
93 * work, or we're here because one of the modules
94 * that are stacked beyond us has returned PAM_TRY_AGAIN.
95 * In either case, we should *not* prompt for another
96 * password.
97 */
98 res = pam_get_item(pamh, PAM_AUTHTOK, (void **)&pwd);
99 if (res != PAM_SUCCESS)
100 goto out;
101 if (pwd != NULL) {
102 goto out;
103 }
104 }
105
106 /*
107 * Make sure PAM_AUTHTOK is empty, or the framework will not
108 * put the value read by __pam_get_authtok into it
109 */
110 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
111
112 res = __pam_get_authtok(pamh, PAM_PROMPT, PAM_AUTHTOK,
113 dgettext(TEXT_DOMAIN, "New Password: "), &pwd);
114
115 if (res != PAM_SUCCESS)
116 goto out;
117
118 if (pwd == NULL) {
119 char *service;
120 if ((pam_get_item(pamh, PAM_SERVICE, (void **)&service) ==
121 PAM_SUCCESS) && service != NULL) {
122 error(pamh, dgettext(TEXT_DOMAIN, "%s: Sorry."),
123 service);
124 }
125 res = PAM_PERM_DENIED;
126 } else {
127 (void) memset(pwd, 0, strlen(pwd));
128 free(pwd);
129 }
130 out:
131 if (res != PAM_SUCCESS) {
132 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
133 (void) pam_set_item(pamh, PAM_OLDAUTHTOK, NULL);
134 } else {
135 /*
136 * Since we don't actually check the password, we should
137 * not return PAM_SUCCESS if everything went OK.
138 * We should return PAM_IGNORE instead.
139 */
140 res = PAM_IGNORE;
141 }
142
143 return (res);
144 }
145
146 int
verify_authtok(pam_handle_t * pamh,int debug)147 verify_authtok(pam_handle_t *pamh, int debug)
148 {
149 int res;
150 char *authtok;
151 char *pwd;
152
153 if (debug)
154 __pam_log(LOG_AUTH | LOG_DEBUG,
155 "pam_authtok_get: verifying authtok");
156
157 /*
158 * All we need to do, is make sure that the user re-enters
159 * the password correctly.
160 */
161
162 res = pam_get_item(pamh, PAM_AUTHTOK, (void **)&authtok);
163 if (res != PAM_SUCCESS || authtok == NULL)
164 return (PAM_AUTHTOK_ERR);
165
166 res = __pam_get_authtok(pamh, PAM_PROMPT, 0, dgettext(TEXT_DOMAIN,
167 "Re-enter new Password: "), &pwd);
168
169 if (res != PAM_SUCCESS)
170 return (res);
171
172 if (strcmp(authtok, pwd) != 0) {
173 char *service;
174
175 if ((pam_get_item(pamh, PAM_SERVICE, (void **)&service) ==
176 PAM_SUCCESS) && service != NULL) {
177 error(pamh, dgettext(TEXT_DOMAIN,
178 "%s: They don't match."), service);
179 }
180 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
181 (void) memset(pwd, 0, strlen(pwd));
182 free(pwd);
183 return (PAM_AUTHTOK_ERR);
184 }
185
186 if (debug)
187 __pam_log(LOG_AUTH | LOG_DEBUG,
188 "pam_authtok_get: new password verified");
189
190 (void) memset(pwd, 0, strlen(pwd));
191 free(pwd);
192 return (PAM_IGNORE);
193 }
194
195 int
pam_sm_chauthtok(pam_handle_t * pamh,int flags,int argc,const char ** argv)196 pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
197 {
198 int i;
199 int debug = 0;
200 int res;
201
202 for (i = 0; i < argc; i++)
203 if (strcmp(argv[i], "debug") == 0)
204 debug = 1;
205
206 if ((flags & PAM_PRELIM_CHECK) == PAM_PRELIM_CHECK)
207 res = read_authtok(pamh, debug);
208 else
209 res = verify_authtok(pamh, debug);
210
211 return (res);
212 }
213
214 /*
215 * int pam_sm_authenticate(pamh, flags, argc, argv)
216 *
217 * Read authentication token from user.
218 */
219 int
pam_sm_authenticate(pam_handle_t * pamh,int flags,int argc,const char ** argv)220 pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
221 {
222
223 char *user;
224 char *password;
225 int i;
226 int debug = 0;
227 int res;
228 int fail = 0;
229
230 attrlist al[1];
231 pam_repository_t *auth_rep = NULL;
232 pwu_repository_t *pwu_rep = NULL;
233
234 for (i = 0; i < argc; i++)
235 if (strcmp(argv[i], "debug") == 0)
236 debug = 1;
237
238 if (debug)
239 __pam_log(LOG_AUTH | LOG_DEBUG,
240 "pam_authtok_get:pam_sm_authenticate: flags = %d", flags);
241
242 if ((res = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) {
243 if (debug)
244 __pam_log(LOG_AUTH | LOG_DEBUG,
245 "pam_authtok_get: get user failed: %s",
246 pam_strerror(pamh, res));
247 return (res);
248 }
249
250 if (user == NULL || *user == '\0') {
251 __pam_log(LOG_AUTH | LOG_ERR,
252 "pam_authtok_get: pam_sm_authenticate: PAM_USER NULL or "
253 "empty");
254 return (PAM_SYSTEM_ERR);
255 }
256
257 res = pam_get_item(pamh, PAM_AUTHTOK, (void **)&password);
258 if (res != PAM_SUCCESS)
259 return (res);
260
261 if (password != NULL)
262 return (PAM_IGNORE);
263
264 /*
265 * No password has been entered yet. Check to see if we need
266 * to obtain a password
267 */
268
269 res = pam_get_item(pamh, PAM_REPOSITORY, (void **)&auth_rep);
270 if (res != PAM_SUCCESS) {
271 __pam_log(LOG_AUTH | LOG_ERR,
272 "pam_authtok_get: error getting repository");
273 return (PAM_SYSTEM_ERR);
274 }
275
276 if (auth_rep == NULL) {
277 pwu_rep = PWU_DEFAULT_REP;
278 } else {
279 if ((pwu_rep = calloc(1, sizeof (*pwu_rep))) == NULL)
280 return (PAM_BUF_ERR);
281 pwu_rep->type = auth_rep->type;
282 pwu_rep->scope = auth_rep->scope;
283 pwu_rep->scope_len = auth_rep->scope_len;
284 }
285
286 (void) memset(&al, 0, sizeof (al));
287 al[0].type = ATTR_PASSWD;
288 al[0].next = NULL;
289
290 res = __get_authtoken_attr(user, pwu_rep, al);
291
292 if (pwu_rep != PWU_DEFAULT_REP)
293 free(pwu_rep);
294
295 if (res == PWU_SUCCESS &&
296 (al[0].data.val_s == NULL || al[0].data.val_s[0] == '\0')) {
297 char *service = NULL;
298 char *rhost = NULL;
299
300 /*
301 * if PAM_DIASALLOW_NULL_AUTHTOK has not been set, we
302 * simply return IGNORE
303 */
304 if ((flags & PAM_DISALLOW_NULL_AUTHTOK) == 0)
305 return (PAM_IGNORE);
306
307 /*
308 * NULL authtoks are not allowed, so we need to fail.
309 * We will ask for a password to mask the failure however.
310 */
311 (void) pam_get_item(pamh, PAM_RHOST, (void **)&rhost);
312 (void) pam_get_item(pamh, PAM_SERVICE, (void **)&service);
313 if (service == NULL)
314 service = "unknown";
315 if (rhost == NULL || *rhost == '\0')
316 rhost = "localhost";
317 __pam_log(LOG_AUTH | LOG_NOTICE,
318 "pam_authtok_get: %s: empty password not allowed for "
319 "%s from %s.", service, user, rhost);
320 fail = 1;
321 }
322 if (al[0].data.val_s != NULL) {
323 (void) memset(al[0].data.val_s, 0, strlen(al[0].data.val_s));
324 free(al[0].data.val_s);
325 }
326
327 res = __pam_get_authtok(pamh, PAM_PROMPT, PAM_AUTHTOK,
328 dgettext(TEXT_DOMAIN, "Password: "), &password);
329 if (res != PAM_SUCCESS)
330 return (res);
331
332 if (password != NULL) {
333 (void) pam_set_item(pamh, PAM_AUTHTOK, (void *)password);
334 (void) memset(password, 0, strlen(password));
335 free(password);
336 } else if (debug) {
337 __pam_log(LOG_AUTH | LOG_DEBUG,
338 "pam_authtok_get: pam_sm_authenticate: "
339 "got NULL password from get_authtok()");
340 }
341
342 if (fail) {
343 __pam_log(LOG_AUTH | LOG_DEBUG,
344 "pam_authtok_get:pam_sm_authenticate: "
345 "failing because NULL authtok not allowed");
346 return (PAM_AUTH_ERR);
347 } else
348 return (PAM_IGNORE);
349 }
350
351 /*ARGSUSED*/
352 int
pam_sm_setcred(pam_handle_t * pamh,int flags,int argc,const char ** argv)353 pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
354 {
355 return (PAM_IGNORE);
356 }
357