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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/varargs.h>
31 #include <security/pam_appl.h>
32 #include <security/pam_modules.h>
33 #include <security/pam_impl.h>
39 #include <passwdutil.h>
43 error(pam_handle_t
*pamh
, char *fmt
, ...)
46 char messages
[PAM_MAX_NUM_MSG
][PAM_MAX_MSG_SIZE
];
49 (void) vsnprintf(messages
[0], sizeof (messages
[0]), fmt
, ap
);
50 (void) __pam_display_msg(pamh
, PAM_ERROR_MSG
, 1, messages
, NULL
);
55 read_authtok(pam_handle_t
*pamh
, int debug
)
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
67 res
= pam_get_item(pamh
, PAM_OLDAUTHTOK
, (void **)&authtok
);
68 if (res
!= PAM_SUCCESS
)
71 if (authtok
== NULL
) {
72 res
= pam_get_item(pamh
, PAM_AUTHTOK
, (void **)&authtok
);
73 if (res
!= PAM_SUCCESS
)
75 if (authtok
!= NULL
) {
76 res
= pam_set_item(pamh
, PAM_OLDAUTHTOK
,
78 if (res
== PAM_SUCCESS
)
79 res
= pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
82 __pam_log(LOG_AUTH
| LOG_DEBUG
,
83 "read_authtok: Copied AUTHTOK to "
86 if (res
!= PAM_SUCCESS
)
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
98 res
= pam_get_item(pamh
, PAM_AUTHTOK
, (void **)&pwd
);
99 if (res
!= PAM_SUCCESS
)
107 * Make sure PAM_AUTHTOK is empty, or the framework will not
108 * put the value read by __pam_get_authtok into it
110 (void) pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
112 res
= __pam_get_authtok(pamh
, PAM_PROMPT
, PAM_AUTHTOK
,
113 dgettext(TEXT_DOMAIN
, "New Password: "), &pwd
);
115 if (res
!= PAM_SUCCESS
)
120 if ((pam_get_item(pamh
, PAM_SERVICE
, (void **)&service
) ==
121 PAM_SUCCESS
) && service
!= NULL
) {
122 error(pamh
, dgettext(TEXT_DOMAIN
, "%s: Sorry."),
125 res
= PAM_PERM_DENIED
;
127 (void) memset(pwd
, 0, strlen(pwd
));
131 if (res
!= PAM_SUCCESS
) {
132 (void) pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
133 (void) pam_set_item(pamh
, PAM_OLDAUTHTOK
, NULL
);
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.
147 verify_authtok(pam_handle_t
*pamh
, int debug
)
154 __pam_log(LOG_AUTH
| LOG_DEBUG
,
155 "pam_authtok_get: verifying authtok");
158 * All we need to do, is make sure that the user re-enters
159 * the password correctly.
162 res
= pam_get_item(pamh
, PAM_AUTHTOK
, (void **)&authtok
);
163 if (res
!= PAM_SUCCESS
|| authtok
== NULL
)
164 return (PAM_AUTHTOK_ERR
);
166 res
= __pam_get_authtok(pamh
, PAM_PROMPT
, 0, dgettext(TEXT_DOMAIN
,
167 "Re-enter new Password: "), &pwd
);
169 if (res
!= PAM_SUCCESS
)
172 if (strcmp(authtok
, pwd
) != 0) {
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
);
180 (void) pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
181 (void) memset(pwd
, 0, strlen(pwd
));
183 return (PAM_AUTHTOK_ERR
);
187 __pam_log(LOG_AUTH
| LOG_DEBUG
,
188 "pam_authtok_get: new password verified");
190 (void) memset(pwd
, 0, strlen(pwd
));
196 pam_sm_chauthtok(pam_handle_t
*pamh
, int flags
, int argc
, const char **argv
)
202 for (i
= 0; i
< argc
; i
++)
203 if (strcmp(argv
[i
], "debug") == 0)
206 if ((flags
& PAM_PRELIM_CHECK
) == PAM_PRELIM_CHECK
)
207 res
= read_authtok(pamh
, debug
);
209 res
= verify_authtok(pamh
, debug
);
215 * int pam_sm_authenticate(pamh, flags, argc, argv)
217 * Read authentication token from user.
220 pam_sm_authenticate(pam_handle_t
*pamh
, int flags
, int argc
, const char **argv
)
231 pam_repository_t
*auth_rep
= NULL
;
232 pwu_repository_t
*pwu_rep
= NULL
;
234 for (i
= 0; i
< argc
; i
++)
235 if (strcmp(argv
[i
], "debug") == 0)
239 __pam_log(LOG_AUTH
| LOG_DEBUG
,
240 "pam_authtok_get:pam_sm_authenticate: flags = %d", flags
);
242 if ((res
= pam_get_user(pamh
, &user
, NULL
)) != PAM_SUCCESS
) {
244 __pam_log(LOG_AUTH
| LOG_DEBUG
,
245 "pam_authtok_get: get user failed: %s",
246 pam_strerror(pamh
, res
));
250 if (user
== NULL
|| *user
== '\0') {
251 __pam_log(LOG_AUTH
| LOG_ERR
,
252 "pam_authtok_get: pam_sm_authenticate: PAM_USER NULL or "
254 return (PAM_SYSTEM_ERR
);
257 res
= pam_get_item(pamh
, PAM_AUTHTOK
, (void **)&password
);
258 if (res
!= PAM_SUCCESS
)
261 if (password
!= NULL
)
265 * No password has been entered yet. Check to see if we need
266 * to obtain a password
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
);
276 if (auth_rep
== NULL
) {
277 pwu_rep
= PWU_DEFAULT_REP
;
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
;
286 (void) memset(&al
, 0, sizeof (al
));
287 al
[0].type
= ATTR_PASSWD
;
290 res
= __get_authtoken_attr(user
, pwu_rep
, al
);
292 if (pwu_rep
!= PWU_DEFAULT_REP
)
295 if (res
== PWU_SUCCESS
&&
296 (al
[0].data
.val_s
== NULL
|| al
[0].data
.val_s
[0] == '\0')) {
297 char *service
= NULL
;
301 * if PAM_DIASALLOW_NULL_AUTHTOK has not been set, we
302 * simply return IGNORE
304 if ((flags
& PAM_DISALLOW_NULL_AUTHTOK
) == 0)
308 * NULL authtoks are not allowed, so we need to fail.
309 * We will ask for a password to mask the failure however.
311 (void) pam_get_item(pamh
, PAM_RHOST
, (void **)&rhost
);
312 (void) pam_get_item(pamh
, PAM_SERVICE
, (void **)&service
);
315 if (rhost
== NULL
|| *rhost
== '\0')
317 __pam_log(LOG_AUTH
| LOG_NOTICE
,
318 "pam_authtok_get: %s: empty password not allowed for "
319 "%s from %s.", service
, user
, rhost
);
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
);
327 res
= __pam_get_authtok(pamh
, PAM_PROMPT
, PAM_AUTHTOK
,
328 dgettext(TEXT_DOMAIN
, "Password: "), &password
);
329 if (res
!= PAM_SUCCESS
)
332 if (password
!= NULL
) {
333 (void) pam_set_item(pamh
, PAM_AUTHTOK
, (void *)password
);
334 (void) memset(password
, 0, strlen(password
));
337 __pam_log(LOG_AUTH
| LOG_DEBUG
,
338 "pam_authtok_get: pam_sm_authenticate: "
339 "got NULL password from get_authtok()");
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
);
353 pam_sm_setcred(pam_handle_t
*pamh
, int flags
, int argc
, const char **argv
)