4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include "ldap_headers.h"
38 free((ldap_authtok_data
*)data
);
42 * warn_user_passwd_will_expire - warn the user when the password will
47 warn_user_passwd_will_expire(
49 int sec_until_expired
)
51 char messages
[PAM_MAX_NUM_MSG
][PAM_MAX_MSG_SIZE
];
52 int days
= 0, hours
= 0;
53 int seconds_d
= 0, seconds_h
= 0;
55 days
= sec_until_expired
/ 86400;
56 seconds_d
= sec_until_expired
% 86400;
57 hours
= (days
* 24) + seconds_d
/ 3600;
58 seconds_h
= seconds_d
% 3600;
60 if (sec_until_expired
<= (86400 * 2)) {
61 if (seconds_d
<= 3600 && days
== 0)
62 (void) snprintf(messages
[0], sizeof (messages
[0]),
64 "Your password will expire within one hour."));
66 (void) snprintf(messages
[0], sizeof (messages
[0]),
68 "Your password will expire in %d hours."),
69 (seconds_h
== 0) ? hours
: hours
+ 1);
71 (void) snprintf(messages
[0], sizeof (messages
[0]),
73 "Your password will expire in %d days."),
74 (seconds_d
== 0) ? days
: days
+ 1);
77 (void) __pam_display_msg(pamh
, PAM_TEXT_INFO
, 1, messages
, NULL
);
81 * display_acct_unlock_time - Display the time left for the account to
82 * get auto unlocked after the maximum login failures has reached.
85 display_acct_unlock_time(pam_handle_t
*pamh
, int sec_b4_unlock
)
87 char messages
[PAM_MAX_NUM_MSG
][PAM_MAX_MSG_SIZE
];
88 int days
= 0, hours
= 0;
89 int seconds_d
= 0, seconds_h
= 0;
91 /* Account is locked forever */
92 if (sec_b4_unlock
== -1) {
93 (void) snprintf(messages
[0], sizeof (messages
[0]),
95 "Your account is locked, please contact administrator."));
96 (void) __pam_display_msg(pamh
, PAM_TEXT_INFO
, 1,
101 days
= sec_b4_unlock
/ 86400;
102 seconds_d
= sec_b4_unlock
% 86400;
103 hours
= (days
* 24) + seconds_d
/ 3600;
104 seconds_h
= seconds_d
% 3600;
106 if (sec_b4_unlock
<= (86400 * 2)) {
107 if (seconds_d
<= 3600 && days
== 0)
108 (void) snprintf(messages
[0], sizeof (messages
[0]),
109 dgettext(TEXT_DOMAIN
,
110 "Your account is locked and will be unlocked"
111 " within one hour."));
113 (void) snprintf(messages
[0], sizeof (messages
[0]),
114 dgettext(TEXT_DOMAIN
,
115 "Your account is locked and will be unlocked"
117 (seconds_h
== 0) ? hours
: hours
+ 1);
119 (void) snprintf(messages
[0], sizeof (messages
[0]),
120 dgettext(TEXT_DOMAIN
,
121 "Your account is locked and will be unlocked"
123 (seconds_d
== 0) ? days
: days
+ 1);
126 (void) __pam_display_msg(pamh
, PAM_TEXT_INFO
, 1, messages
, NULL
);
130 * warn_user_passwd_expired - warn the user that the password has expired
133 warn_user_passwd_expired(pam_handle_t
*pamh
, int grace
)
135 char messages
[PAM_MAX_NUM_MSG
][PAM_MAX_MSG_SIZE
];
138 (void) snprintf(messages
[0], sizeof (messages
[0]),
139 dgettext(TEXT_DOMAIN
,
140 "Your password has expired. "
141 "Number of grace logins allowed are %d."),
144 (void) snprintf(messages
[0], sizeof (messages
[0]),
145 dgettext(TEXT_DOMAIN
,
146 "Your password has expired."));
148 (void) __pam_display_msg(pamh
, PAM_TEXT_INFO
, 1, messages
, NULL
);
152 * display_passwd_reset_msg - tell user that password has been reset by
156 display_passwd_reset_msg(pam_handle_t
*pamh
)
158 char messages
[PAM_MAX_NUM_MSG
][PAM_MAX_MSG_SIZE
];
160 (void) snprintf(messages
[0], sizeof (messages
[0]),
161 dgettext(TEXT_DOMAIN
,
162 "Your password has been reset by administrator."));
164 (void) __pam_display_msg(pamh
, PAM_TEXT_INFO
, 1, messages
, NULL
);
168 * Retreives account management related attributes for the user using
169 * default binding and does local account checks .
171 * Return Value: PAM_SUCCESS - If account is valid, seconds param will have
172 * seconds left for password to expire
173 * PAM_ACCT_EXPIRED - If account is inactive
174 * PAM_NEW_AUTHTOK_REQD - Password is reset by admin
175 * PAM_AUTHTOK_EXPIRED - User password has expired, grace
176 * param will have no. of grace logins allowed
177 * PAM_MAXTRIES - If maximum failure of wrong password has reached
178 * seconds param will have no. of seconds for the
179 * account to get unlocked
180 * PAM_AUTH_ERR - Failure return code
183 get_account_mgmt(char *user
, int *seconds
, int *grace
)
185 int rc
= PAM_AUTH_ERR
;
186 AcctUsableResponse_t acctResp
;
188 memset(&acctResp
, 0, sizeof (acctResp
));
189 /* get the values for local account checking */
190 if ((rc
= __ns_ldap_getAcctMgmt(user
, &acctResp
))
191 != NS_LDAP_SUCCESS
) {
193 "__ns_ldap_getAcctMgmt() failed for %s with error %d",
195 return (PAM_AUTH_ERR
);
198 if (acctResp
.choice
== 0) {
199 /* should be able to login */
201 acctResp
.AcctUsableResp
.seconds_before_expiry
;
202 return (PAM_SUCCESS
);
203 } else if (acctResp
.choice
== 1) {
205 if (acctResp
.AcctUsableResp
.more_info
.inactive
)
207 return (PAM_ACCT_EXPIRED
);
208 if (acctResp
.AcctUsableResp
.more_info
.reset
)
209 /* password reset by administrator */
210 return (PAM_NEW_AUTHTOK_REQD
);
211 if (acctResp
.AcctUsableResp
.more_info
.expired
) {
213 * password expired, check for grace logins.
216 acctResp
.AcctUsableResp
.more_info
.rem_grace
;
217 return (PAM_AUTHTOK_EXPIRED
);
219 if (acctResp
.AcctUsableResp
.more_info
.sec_b4_unlock
) {
220 /* max failures reached, seconds before unlock */
222 acctResp
.AcctUsableResp
.more_info
.sec_b4_unlock
;
223 return (PAM_MAXTRIES
);
226 return (PAM_AUTH_ERR
);
230 * pam_sm_acct_mgmt main account managment routine.
231 * This routine relies on the LDAP
232 * directory server to provide the
233 * password aging and account lockout
234 * information. This is done by first
235 * trying to authenticate the user and
236 * then checking the password status
239 * Returns: module error or specific
252 int result
= PAM_AUTH_ERR
;
255 char *password
= NULL
;
256 ns_cred_t
*credp
= NULL
;
258 int seconds
= 0, grace
= 0;
259 ldap_authtok_data
*status
;
261 for (i
= 0; i
< argc
; i
++) {
262 if (strcmp(argv
[i
], "debug") == 0)
264 else if (strcasecmp(argv
[i
], "nowarn") == 0) {
266 flags
= flags
| PAM_SILENT
;
270 "pam_ldap pam_sm_acct_mgmt: "
275 if ((result
= pam_get_item(pamh
, PAM_USER
, (void **)&user
))
281 "ldap pam_sm_acct_mgmt(%s), flags = %x %s",
282 (user
)?user
:"no-user", flags
,
283 (nowarn
)? ", nowarn": "");
286 result
= PAM_USER_UNKNOWN
;
290 /* retrieve the password from the PAM handle */
291 result
= pam_get_item(pamh
, PAM_AUTHTOK
, (void **) &password
);
292 if (password
== NULL
) {
294 syslog(LOG_DEBUG
, "ldap pam_sm_acct_mgmt: "
295 "no password for user %s", user
);
296 /* Do local account checking */
297 result
= get_account_mgmt(user
, &seconds
, &grace
);
299 /* Try to authenticate to get password management info */
300 result
= authenticate(&credp
, user
,
305 * process the password management info.
306 * If user needs to change the password immediately,
307 * just return the rc.
308 * Otherwise, reset rc to the appropriate PAM error or
309 * warn the user about password expiration.
311 if (result
== PAM_MAXTRIES
) {
312 /* exceed retry limit, denied access to account */
313 if (!(flags
& PAM_SILENT
))
314 display_acct_unlock_time(pamh
, seconds
);
315 result
= PAM_PERM_DENIED
;
316 } else if (result
== PAM_ACCT_EXPIRED
)
317 /* account is inactivated */
318 result
= PAM_ACCT_EXPIRED
;
319 else if (result
== PAM_AUTHTOK_EXPIRED
) {
320 if (!(flags
& PAM_SILENT
))
321 warn_user_passwd_expired(pamh
, grace
);
322 /* password expired, check for grace logins */
324 result
= PAM_SUCCESS
;
326 result
= PAM_AUTHTOK_EXPIRED
;
327 } else if (result
== PAM_NEW_AUTHTOK_REQD
) {
328 /* password has been reset by administrator */
329 if (!(flags
& PAM_SILENT
))
330 display_passwd_reset_msg(pamh
);
331 result
= PAM_NEW_AUTHTOK_REQD
;
332 } else if (result
== PAM_SUCCESS
) {
334 * warn the user if the password
335 * is about to expire.
337 if (!(flags
& PAM_SILENT
) &&
339 warn_user_passwd_will_expire(pamh
,
346 (void) __ns_ldap_freeCred(&credp
);
348 /* store the password aging status in the pam handle */
349 if (result
!= PAM_SUCCESS
) {
351 ldap_authtok_data
*authtok_data
;
353 pam_res
= pam_get_data(
354 pamh
, LDAP_AUTHTOK_DATA
, (const void **)&authtok_data
);
356 if ((status
= (ldap_authtok_data
*)calloc
357 (1, sizeof (ldap_authtok_data
))) == NULL
) {
358 return (PAM_BUF_ERR
);
361 if (pam_res
== PAM_SUCCESS
)
362 (void) memcpy(status
, authtok_data
,
363 sizeof (ldap_authtok_data
));
365 status
->age_status
= result
;
366 if (pam_set_data(pamh
, LDAP_AUTHTOK_DATA
, status
, ldap_cleanup
)
369 return (PAM_SERVICE_ERR
);