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.
22 #include "time_limit.h"
24 #ifdef SHADOW_PASSWORDS
30 tac_pam_auth(char *UserName,char *Password,struct authen_data *data,char *Service);
33 /* For database verification */
38 /* For LDAP verification */
43 /* Generic password verification routines for des, file and cleartext
46 static int passwd_file_verify();
48 /* Adjust data->status depending on whether a user has expired or not */
51 set_expiration_status(exp_date, data)
53 struct authen_data *data;
57 /* if the status is anything except pass, there's no point proceeding */
58 if (data->status != TAC_PLUS_AUTHEN_STATUS_PASS) {
62 /* Check the expiration date, if any. If NULL, this check will return
64 expired = check_expiration(exp_date);
68 if (debug & DEBUG_PASSWD_FLAG)
69 report(LOG_DEBUG, "Password has not expired %s",
70 exp_date ? exp_date : "<no expiry date set>");
72 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
76 if (debug & DEBUG_PASSWD_FLAG)
77 report(LOG_DEBUG, "Password will expire soon %s",
78 exp_date ? exp_date : "<no expiry date set>");
80 free(data->server_msg);
81 data->server_msg = tac_strdup("Password will expire soon");
82 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
86 if (debug & DEBUG_PASSWD_FLAG)
87 report(LOG_DEBUG, "Password has expired %s",
88 exp_date ? exp_date : "<no expiry date set>");
90 free(data->server_msg);
91 data->server_msg = tac_strdup("Password has expired");
92 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
96 report(LOG_ERR, "%s: Bogus return value %d from check_expiration",
97 session.peer, expired);
98 data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
103 /* Verify that this user/password is valid. Works only for cleartext,
104 file and des passwords.
106 Return 1 if password is valid */
109 verify(name, passwd, data, recurse)
111 struct authen_data *data;
119 timestamp = (char *)cfg_get_timestamp(name, recurse);
120 if ( timestamp != NULL ) {
121 if( time_limit_process(timestamp) == 0 ) {
122 if ( debug & DEBUG_AUTHEN_FLAG )
123 report(LOG_DEBUG,"Timestamp check failed");
124 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
129 if (data->type == TAC_PLUS_AUTHEN_TYPE_PAP) {
130 cfg_passwd = cfg_get_pap_secret(name, recurse);
132 cfg_passwd = cfg_get_login_secret(name, recurse);
135 /* If there is no login or pap password for this user, see if there is
136 a global password for her that we can use */
139 cfg_passwd = cfg_get_global_secret(name, recurse);
142 /* If we still have no password for this user (or no user for that
143 matter) but the default authentication = file <file> statement
144 has been issued, attempt to use this password file */
147 char *file = cfg_get_authen_default();
148 switch (cfg_get_authen_default_method()) {
152 return (passwd_file_verify(name, passwd, data, file));
157 /* ugly check for database connect string */
158 if( strstr(file, "://") ){
159 if (debug & DEBUG_PASSWD_FLAG)
160 report(LOG_DEBUG,"%s %s: DB access to %s for user %s",session.peer, session.port, file, name);
161 if (!db_verify(name, passwd, file)) {
162 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
165 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
168 set_expiration_status(exp_date, data);
169 return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
176 if (ldap_verify(name, passwd, file)==1) {
177 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
180 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
183 set_expiration_status(exp_date, data);
184 return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
186 #endif /* USE_LDAP */
190 if (debug & DEBUG_PASSWD_FLAG)
191 report(LOG_DEBUG, "PAM verify daemon %s == NAS %s", p,passwd);
192 if (tac_pam_auth(name, passwd, data,file)) {
193 if (debug & DEBUG_PASSWD_FLAG)
194 report(LOG_DEBUG, "PAM default authentication fail");
195 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
198 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
200 if (debug & DEBUG_PASSWD_FLAG)
201 report(LOG_DEBUG, " PAM default authentication pass");
204 exp_date = cfg_get_expires(name, recurse);
205 set_expiration_status(exp_date, data);
206 return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
210 /* otherwise, we fail */
211 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
217 /* We have a configured password. Deal with it depending on its
221 p = tac_find_substring("cleartext ", cfg_passwd);
223 if (debug & DEBUG_PASSWD_FLAG)
224 report(LOG_DEBUG, "verify daemon %s == NAS %s", p, passwd);
226 if (strcmp(passwd, p)) {
227 if (debug & DEBUG_PASSWD_FLAG)
228 report(LOG_DEBUG, "Password is incorrect");
229 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
232 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
234 if (debug & DEBUG_PASSWD_FLAG)
235 report(LOG_DEBUG, "Password is correct");
238 exp_date = cfg_get_expires(name, recurse);
239 set_expiration_status(exp_date, data);
240 return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
244 p = tac_find_substring("pam ", cfg_passwd);
246 if (debug & DEBUG_PASSWD_FLAG)
247 report(LOG_DEBUG, "PAM verify daemon %s == NAS %s", p,passwd);
249 if (tac_pam_auth(name, passwd, data,p)) {
250 if (debug & DEBUG_PASSWD_FLAG)
251 report(LOG_DEBUG, "PAM Password is incorrect");
252 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
255 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
257 if (debug & DEBUG_PASSWD_FLAG)
258 report(LOG_DEBUG, "PAM Password is correct");
261 exp_date = cfg_get_expires(name, recurse);
262 set_expiration_status(exp_date, data);
263 return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
268 p = tac_find_substring("des ", cfg_passwd);
270 /* try to verify this des password */
271 if (!des_verify(passwd, p)) {
272 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
275 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
278 exp_date = cfg_get_expires(name, recurse);
279 set_expiration_status(exp_date, data);
280 return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
284 p = tac_find_substring("db ", cfg_passwd);
286 /* try to verify this password from database */
287 if (debug & DEBUG_PASSWD_FLAG)
288 report(LOG_DEBUG, "DB verify daemon %s == NAS %s", p, passwd);
290 if (!db_verify(name, passwd, p)) {
291 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
293 if (debug & DEBUG_PASSWD_FLAG)
294 report(LOG_DEBUG, "DB Password is incorrect");
299 if (debug & DEBUG_PASSWD_FLAG)
300 report(LOG_DEBUG, "DB Password is correct");
301 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
303 exp_date = cfg_get_expires(name, recurse);
304 set_expiration_status(exp_date, data);
305 return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
309 p = tac_find_substring("file ", cfg_passwd);
311 return (passwd_file_verify(name, passwd, data, p));
314 /* Oops. No idea what kind of password this is. This should never
315 happen as the parser should never create such passwords. */
317 report(LOG_ERR, "%s: Error cannot identify password type %s for %s",
319 cfg_passwd && cfg_passwd[0] ? cfg_passwd : "<NULL>",
320 name ? name : "<unknown>");
322 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
326 /* verify that this user/password is valid per /etc/passwd.
327 Return 0 if invalid. */
329 etc_passwd_file_verify(user, supplied_passwd, data)
330 char *user, *supplied_passwd;
331 struct authen_data *data;
336 #ifdef SHADOW_PASSWORDS
338 #endif /* SHADOW_PASSWORDS */
340 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
347 /* no entry exists */
351 if (*pw->pw_passwd == '\0' ||
352 supplied_passwd == NULL ||
353 *supplied_passwd == '\0') {
354 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
357 cfg_passwd = pw->pw_passwd;
358 exp_date = pw->pw_shell;
360 #ifdef SHADOW_PASSWORDS
361 if (STREQ(pw->pw_passwd, "x")) {
362 struct spwd *spwd = getspnam(user);
365 if (debug & DEBUG_PASSWD_FLAG) {
366 report(LOG_DEBUG, "No entry for %s in shadow file", user);
368 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
371 if (debug & DEBUG_PASSWD_FLAG) {
372 report(LOG_DEBUG, "Found entry for %s in shadow file", user);
374 cfg_passwd = spwd->sp_pwdp;
377 * Sigh. The Solaris shadow password file contains its own
378 * expiry date as the number of days after the epoch
379 * (January 1, 1970) when the password expires.
380 * Convert this to ascii so that the traditional tacacs
381 * password expiration routines work correctly.
384 if (spwd->sp_expire > 0) {
385 long secs = spwd->sp_expire * 24 * 60 * 60;
386 char *p = ctime(&secs);
388 bcopy(p+20, buf+7, 4);
393 #endif /* SHADOW_PASSWORDS */
395 /* try to verify the password */
396 if (!des_verify(supplied_passwd, cfg_passwd)) {
397 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
400 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
403 /* password ok. Check expiry field */
404 set_expiration_status(exp_date, data);
406 return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
409 /* verify that this user/password is valid per a passwd(5) style
410 database. Return 0 if invalid. */
413 passwd_file_verify(user, supplied_passwd, data, filename)
414 char *user, *supplied_passwd;
415 struct authen_data *data;
422 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
424 if (filename && (STREQ(filename, "/etc/passwd")|| STREQ(filename,"/etc/shadow") )) {
425 return(etc_passwd_file_verify(user, supplied_passwd, data));
430 /* an alternate filename */
431 if (!(access(filename, R_OK) == 0)) {
432 report(LOG_ERR, "%s %s: Cannot access %s for user %s -- %s",
433 session.peer, session.port, filename, user, sys_errlist[errno]);
437 pw = tac_passwd_lookup(user, filename);
440 /* no entry exists */
443 if (*pw->pw_passwd == '\0' ||
444 supplied_passwd == NULL ||
445 *supplied_passwd == '\0') {
446 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
449 cfg_passwd = pw->pw_passwd;
450 exp_date = pw->pw_shell;
452 /* try to verify the password */
453 if (!des_verify(supplied_passwd, cfg_passwd)) {
454 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
457 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
460 /* password ok. Check expiry field */
461 set_expiration_status(exp_date, data);
462 return (data->status == TAC_PLUS_AUTHEN_STATUS_PASS);
466 * verify a provided password against a des encrypted one
467 * return 1 if verified, 0 otherwise.
471 des_verify(users_passwd, encrypted_passwd)
472 char *users_passwd, *encrypted_passwd;
476 if (debug & DEBUG_PASSWD_FLAG)
477 report(LOG_DEBUG, "verify %s %s", users_passwd, encrypted_passwd);
479 if (users_passwd == NULL ||
480 *users_passwd == '\0' ||
481 encrypted_passwd == NULL ||
482 *encrypted_passwd == '\0') {
483 if (debug & DEBUG_PASSWD_FLAG)
484 report(LOG_DEBUG, "verify returns 0");
488 ep = (char *) crypt(users_passwd, encrypted_passwd);
490 if (debug & DEBUG_PASSWD_FLAG)
491 report(LOG_DEBUG, "%s encrypts to %s", users_passwd, ep);
493 if (strcmp(ep, encrypted_passwd) == 0) {
494 if (debug & DEBUG_PASSWD_FLAG)
495 report(LOG_DEBUG, "Password is correct");
499 if (debug & DEBUG_PASSWD_FLAG)
500 report(LOG_DEBUG, "Password is incorrect");