2 Copyright (c) 1995-1998 by Cisco systems, Inc.
4 Permission to use, copy, modify, and distribute this software for
5 any purpose and without fee is hereby granted, provided that this
6 copyright and permission notice appear on all copies of the
7 software and supporting documentation, the name of Cisco Systems,
8 Inc. not be used in advertising or publicity pertaining to
9 distribution of the program without specific prior permission, and
10 notice be given in supporting documentation that modification,
11 copying and distribution is by permission of Cisco Systems, Inc.
13 Cisco Systems, Inc. makes no representations about the suitability
14 of this software for any purpose. THIS SOFTWARE IS PROVIDED ``AS
15 IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
16 WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS FOR A PARTICULAR PURPOSE.
27 #include <sys/types.h>
33 #ifdef SHADOW_PASSWORDS
41 #include "time_limit.h"
46 #include "choose_authen.h" /* for "struct authen_data" */
55 #include "db.h" /* For database verification */
58 #include "ldap_author.h" /* For LDAP verification */
62 static int passwd_file_verify TAC_ARGS((const char *user, const char *supplied_passwd, struct authen_data *data, const char *filename));
65 /* Generic password verification routines for des, file and cleartext
68 /* Adjust data->status depending on whether a user has expired or not */
70 void set_expiration_status TAC_ARGS((const char *exp_date, struct authen_data *data));
73 set_expiration_status(exp_date, data)
75 struct authen_data *data;
79 /* if the status is anything except pass, there's no point proceeding */
80 if (data->status != TAC_PLUS_AUTHEN_STATUS_PASS) {
84 /* Check the expiration date, if any. If NULL, this check will return
86 expired = check_expiration(exp_date);
90 if (debug & DEBUG_PASSWD_FLAG)
91 report(LOG_DEBUG, "Password has not expired %s",
92 exp_date ? exp_date : "<no expiry date set>");
94 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
98 if (debug & DEBUG_PASSWD_FLAG)
99 report(LOG_DEBUG, "Password will expire soon %s",
100 exp_date ? exp_date : "<no expiry date set>");
101 if (data->server_msg)
102 free(data->server_msg);
103 data->server_msg = tac_strdup("Password will expire soon");
104 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
108 if (debug & DEBUG_PASSWD_FLAG)
109 report(LOG_DEBUG, "Password has expired %s",
110 exp_date ? exp_date : "<no expiry date set>");
111 if (data->server_msg)
112 free(data->server_msg);
113 data->server_msg = tac_strdup("Password has expired");
114 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
118 report(LOG_ERR, "%s: Bogus return value %d from check_expiration",
119 session.peer, expired);
120 data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
125 /* Verify that this user/password is valid. Works only for cleartext,
126 file and des passwords.
128 Return 1 if password is valid */
130 int verify TAC_ARGS((const char *name, const char *passwd, struct authen_data *data, int recurse));
133 verify(name, passwd, data, recurse)
136 struct authen_data *data;
139 const char *exp_date, *cfg_passwd, *p, *timestamp;
141 timestamp = cfg_get_timestamp(name, recurse);
142 if ( timestamp != NULL ) {
143 if( time_limit_process(timestamp) == 0 ) {
144 if ( debug & DEBUG_AUTHEN_FLAG )
145 report(LOG_DEBUG,"Timestamp check failed");
146 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
151 if (data->type == TAC_PLUS_AUTHEN_TYPE_PAP) {
152 cfg_passwd = cfg_get_pap_secret(name, recurse);
154 cfg_passwd = cfg_get_login_secret(name, recurse);
157 /* If there is no login or pap password for this user, see if there is
158 a global password for her that we can use */
161 cfg_passwd = cfg_get_global_secret(name, recurse);
164 /* If we still have no password for this user (or no user for that
165 matter) but the default authentication = file <file> statement
166 has been issued, attempt to use this password file */
169 const char *file = cfg_get_authen_default();
170 switch (cfg_get_authen_default_method()) {
174 return (passwd_file_verify(name, passwd, data, file));
179 /* ugly check for database connect string */
180 if( strstr(file, "://") ) {
181 if (debug & DEBUG_PASSWD_FLAG)
182 report(LOG_DEBUG,"%s %s: DB access to %s for user %s",session.peer, session.port, file, name);
183 if (!db_verify(name, passwd, file)) {
184 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
187 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
190 set_expiration_status(exp_date, data);
191 return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
198 if (ldap_verify(name, passwd, file)==1) {
199 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
202 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
205 set_expiration_status(exp_date, data);
206 return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
208 #endif /* USE_LDAP */
212 if (debug & DEBUG_PASSWD_FLAG)
213 report(LOG_DEBUG, "PAM verify daemon [PAM] == NAS %s", passwd);
214 if (tac_pam_auth(name, passwd, data, file)) {
215 if (debug & DEBUG_PASSWD_FLAG)
216 report(LOG_DEBUG, "PAM default authentication fail");
217 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
220 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
222 if (debug & DEBUG_PASSWD_FLAG)
223 report(LOG_DEBUG, " PAM default authentication pass");
226 exp_date = cfg_get_expires(name, recurse);
227 set_expiration_status(exp_date, data);
228 return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
232 /* otherwise, we fail */
233 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
238 /* We have a configured password. Deal with it depending on its
242 p = tac_find_substring("cleartext ", cfg_passwd);
244 if (debug & DEBUG_PASSWD_FLAG)
245 report(LOG_DEBUG, "verify daemon %s == NAS %s", p, passwd);
247 if (strcmp(passwd, p)) {
248 if (debug & DEBUG_PASSWD_FLAG)
249 report(LOG_DEBUG, "Password is incorrect");
250 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
253 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
255 if (debug & DEBUG_PASSWD_FLAG)
256 report(LOG_DEBUG, "Password is correct");
259 exp_date = cfg_get_expires(name, recurse);
260 set_expiration_status(exp_date, data);
261 return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
265 p = tac_find_substring("pam ", cfg_passwd);
267 if (debug & DEBUG_PASSWD_FLAG)
268 report(LOG_DEBUG, "PAM verify daemon %s == NAS %s", p,passwd);
270 if (tac_pam_auth(name, passwd, data,p)) {
271 if (debug & DEBUG_PASSWD_FLAG)
272 report(LOG_DEBUG, "PAM Password is incorrect");
273 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
276 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
278 if (debug & DEBUG_PASSWD_FLAG)
279 report(LOG_DEBUG, "PAM Password is correct");
282 exp_date = cfg_get_expires(name, recurse);
283 set_expiration_status(exp_date, data);
284 return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
289 p = tac_find_substring("des ", cfg_passwd);
291 /* try to verify this des password */
292 if (!des_verify(passwd, p)) {
293 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
296 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
299 exp_date = cfg_get_expires(name, recurse);
300 set_expiration_status(exp_date, data);
301 return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
305 p = tac_find_substring("db ", cfg_passwd);
307 /* try to verify this password from database */
308 if (debug & DEBUG_PASSWD_FLAG)
309 report(LOG_DEBUG, "DB verify daemon %s == NAS %s", p, passwd);
311 if (!db_verify(name, passwd, p)) {
312 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
314 if (debug & DEBUG_PASSWD_FLAG)
315 report(LOG_DEBUG, "DB Password is incorrect");
320 if (debug & DEBUG_PASSWD_FLAG)
321 report(LOG_DEBUG, "DB Password is correct");
322 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
324 exp_date = cfg_get_expires(name, recurse);
325 set_expiration_status(exp_date, data);
326 return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
330 p = tac_find_substring("file ", cfg_passwd);
332 return (passwd_file_verify(name, passwd, data, p));
335 /* Oops. No idea what kind of password this is. This should never
336 happen as the parser should never create such passwords. */
338 report(LOG_ERR, "%s: Error cannot identify password type %s for %s",
340 cfg_passwd && cfg_passwd[0] ? cfg_passwd : "<NULL>",
341 name ? name : "<unknown>");
343 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
347 static int etc_passwd_file_verify TAC_ARGS((const char *user, const char *supplied_passwd, struct authen_data *data));
349 /* verify that this user/password is valid per /etc/passwd.
350 * Return 0 if invalid.
353 etc_passwd_file_verify(user, supplied_passwd, data)
355 const char *supplied_passwd;
356 struct authen_data *data;
361 #ifdef SHADOW_PASSWORDS
363 #endif /* SHADOW_PASSWORDS */
365 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
372 /* no entry exists */
376 if (*pw->pw_passwd == '\0' ||
377 supplied_passwd == NULL ||
378 *supplied_passwd == '\0') {
379 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
382 cfg_passwd = pw->pw_passwd;
383 exp_date = pw->pw_shell;
385 #ifdef SHADOW_PASSWORDS
386 if (STREQ(pw->pw_passwd, "x")) {
387 struct spwd *spwd = getspnam(user);
390 if (debug & DEBUG_PASSWD_FLAG) {
391 report(LOG_DEBUG, "No entry for %s in shadow file", user);
393 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
396 if (debug & DEBUG_PASSWD_FLAG) {
397 report(LOG_DEBUG, "Found entry for %s in shadow file", user);
399 cfg_passwd = spwd->sp_pwdp;
402 * Sigh. The Solaris shadow password file contains its own
403 * expiry date as the number of days after the epoch
404 * (January 1, 1970) when the password expires.
405 * Convert this to ascii so that the traditional tacacs
406 * password expiration routines work correctly.
409 if (spwd->sp_expire > 0) {
410 long secs = spwd->sp_expire * 24 * 60 * 60;
411 char *p = ctime(&secs);
413 bcopy(p+20, buf+7, 4);
418 #endif /* SHADOW_PASSWORDS */
420 /* try to verify the password */
421 if (!des_verify(supplied_passwd, cfg_passwd)) {
422 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
425 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
428 /* password ok. Check expiry field */
429 set_expiration_status(exp_date, data);
431 return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
434 /* verify that this user/password is valid per a passwd(5) style
435 database. Return 0 if invalid. */
437 static int passwd_file_verify TAC_ARGS((const char *user, const char *supplied_passwd, struct authen_data *data, const char *filename));
440 passwd_file_verify(user, supplied_passwd, data, filename)
442 const char *supplied_passwd;
443 struct authen_data *data;
444 const char *filename;
450 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
452 if (filename && (STREQ(filename, "/etc/passwd")|| STREQ(filename,"/etc/shadow") )) {
453 return(etc_passwd_file_verify(user, supplied_passwd, data));
458 /* an alternate filename */
459 if (!(access(filename, R_OK) == 0)) {
460 report(LOG_ERR, "%s %s: Cannot access %s for user %s -- %s",
461 session.peer, session.port, filename, user, sys_errlist[errno]);
465 pw = tac_passwd_lookup(user, filename);
468 /* no entry exists */
471 if (*pw->pw_passwd == '\0' ||
472 supplied_passwd == NULL ||
473 *supplied_passwd == '\0') {
474 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
477 cfg_passwd = pw->pw_passwd;
478 exp_date = pw->pw_shell;
480 /* try to verify the password */
481 if (!des_verify(supplied_passwd, cfg_passwd)) {
482 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
485 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
488 /* password ok. Check expiry field */
489 set_expiration_status(exp_date, data);
490 return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
494 * verify a provided password against a des encrypted one
495 * return 1 if verified, 0 otherwise.
498 int des_verify TAC_ARGS((const char *users_passwd, const char *encrypted_passwd));
501 des_verify(users_passwd, encrypted_passwd)
502 const char *users_passwd;
503 const char *encrypted_passwd;
507 if (debug & DEBUG_PASSWD_FLAG)
508 report(LOG_DEBUG, "verify %s %s", users_passwd, encrypted_passwd);
510 if (users_passwd == NULL ||
511 *users_passwd == '\0' ||
512 encrypted_passwd == NULL ||
513 *encrypted_passwd == '\0') {
514 if (debug & DEBUG_PASSWD_FLAG)
515 report(LOG_DEBUG, "verify returns 0");
519 ep = (char *) crypt(users_passwd, encrypted_passwd);
521 if (debug & DEBUG_PASSWD_FLAG)
522 report(LOG_DEBUG, "%s encrypts to %s", users_passwd, ep);
524 if (strcmp(ep, encrypted_passwd) == 0) {
525 if (debug & DEBUG_PASSWD_FLAG)
526 report(LOG_DEBUG, "Password is correct");
530 if (debug & DEBUG_PASSWD_FLAG)
531 report(LOG_DEBUG, "Password is incorrect");