tacacs-F4.0.4.28/default_fn.c (613 lines of code) (raw):

/* * $Id: default_fn.c,v 1.14 2009-03-17 18:38:12 heas Exp $ * * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved * Copyright (c) 1995-1998 by Cisco systems, Inc. * * Permission to use, copy, modify, and distribute this software for * any purpose and without fee is hereby granted, provided that this * copyright and permission notice appear on all copies of the * software and supporting documentation, the name of Cisco Systems, * Inc. not be used in advertising or publicity pertaining to * distribution of the program without specific prior permission, and * notice be given in supporting documentation that modification, * copying and distribution is by permission of Cisco Systems, Inc. * * Cisco Systems, Inc. makes no representations about the suitability * of this software for any purpose. THIS SOFTWARE IS PROVIDED ``AS * IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE. */ #include "tac_plus.h" #include "expire.h" #include "md5.h" #ifdef MSCHAP # include "md4.h" # include "mschap.h" #endif #if ARAP_DES || MSCHAP_DES # include "fdes.h" #endif /* internal state variables */ #define STATE_AUTHEN_START 0 /* no requests issued */ #define STATE_AUTHEN_GETUSER 1 /* username has been requested */ #define STATE_AUTHEN_GETPASS 2 /* password has been requested */ struct private_data { char password[MAX_PASSWD_LEN + 1]; int state; }; static void arap_verify(struct authen_data *); static void chap_verify(struct authen_data *); #ifdef MSCHAP static void mschap_challengeresponse(char *, char *, char *); static void mschap_desencrypt(char *, unsigned char *, unsigned char *); static void mschap_deshash(char *, char *); static void mschap_lmpasswordhash(char *, char *); static void mschap_ntpasswordhash(char *, char *); static void mschap_verify(struct authen_data *); static int mschap_unicode_len(char *); #endif /* MSCHAP */ static void pap_verify(struct authen_data *); static void tac_login(struct authen_data *, struct private_data *); /* * Default tacacs login authentication function. Wants a username * and a password, and tries to verify them. * * Choose_authen will ensure that we already have a username before this * gets called. * * We will query for a password and keep it in the method_data. * * Any strings returned via pointers in authen_data must come from the * heap. They will get freed by the caller. * * Return 0 if data->status is valid, otherwise 1 */ int default_fn(struct authen_data *data) { struct private_data *p; char *name = data->NAS_id->username; char *clientip = ((data->NAS_id->NAC_address) && data->NAS_id->NAC_address[0]) ? data->NAS_id->NAC_address : "unknown"; p = (struct private_data *) data->method_data; /* An abort has been received. Clean up and return */ if (data->flags & TAC_PLUS_CONTINUE_FLAG_ABORT) { if (data->method_data) free(data->method_data); data->method_data = NULL; return(1); } /* Initialise method_data if first time through */ if (!p) { p = (struct private_data *) tac_malloc(sizeof(struct private_data)); memset(p, 0, sizeof(struct private_data)); data->method_data = p; p->state = STATE_AUTHEN_START; } if (STREQ(name, DEFAULT_USERNAME)) { /* Never authenticate this user. It's for authorization only */ data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; if (debug) { report(LOG_DEBUG, "authentication query for '%s' port %s from %s rejected", (name != NULL && name[0] != '\0') ? name : "unknown", session.port, session.peer); } return(0); } if (data->action != TAC_PLUS_AUTHEN_LOGIN) { data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; } else { switch (data->type) { case TAC_PLUS_AUTHEN_TYPE_CHAP: /* set status inside chap_verify */ chap_verify(data); if (debug) { report(LOG_DEBUG, "chap-login query for '%s' port %s from %s %s", (name != NULL && name[0] != '\0') ? name : "unknown", session.port, session.peer, (data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ? "accepted" : "rejected"); } break; #ifdef MSCHAP case TAC_PLUS_AUTHEN_TYPE_MSCHAP: /* set status inside mschap_verify */ mschap_verify(data); if (debug) { report(LOG_DEBUG, "mschap-login query for '%s' port %s from %s %s", (name != NULL && name[0] != '\0') ? name : "unknown", session.port, session.peer, (data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ? "accepted" : "rejected"); } break; #endif /* MSCHAP */ case TAC_PLUS_AUTHEN_TYPE_ARAP: /* set status inside arap_verify */ arap_verify(data); if (debug) { report(LOG_DEBUG, "arap query for '%s' port %s from %s %s", (name != NULL && name[0] != '\0') ? name : "unknown", session.port, session.peer, (data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ? "accepted" : "rejected"); } break; case TAC_PLUS_AUTHEN_TYPE_PAP: pap_verify(data); if (debug) { report(LOG_DEBUG, "pap-login query for '%s' port %s from %s %s", (name != NULL && name[0] != '\0') ? name : "unknown", session.port, session.peer, (data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ? "accepted" : "rejected"); } break; case TAC_PLUS_AUTHEN_TYPE_ASCII: tac_login(data, p); switch (data->status) { case TAC_PLUS_AUTHEN_STATUS_GETPASS: case TAC_PLUS_AUTHEN_STATUS_GETUSER: case TAC_PLUS_AUTHEN_STATUS_GETDATA: /* Authentication still in progress. More data required */ return(0); default: /* Authentication finished */ if (debug) report(LOG_DEBUG, "login query for '%s' port %s from %s %s", (name != NULL && name[0] != '\0') ? name : "unknown", session.port, session.peer, (data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ? "accepted" : "rejected"); } break; default: data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; break; } } if (data->method_data) free(data->method_data); data->method_data = NULL; switch (data->status) { case TAC_PLUS_AUTHEN_STATUS_ERROR: return(0); case TAC_PLUS_AUTHEN_STATUS_FAIL: if (session.peer) report(LOG_NOTICE, "login failure: user=%s device=%s ip=%s port=%s client=%s", name == NULL ? "unknown" : name, session.peer, session.peerip, session.port, clientip); else report(LOG_NOTICE, "login failure: user=%s device=%s port=%s", name == NULL ? "unknown" : name, session.peerip, session.port); return(0); case TAC_PLUS_AUTHEN_STATUS_PASS: if (session.peer) report(LOG_NOTICE, "login success: user=%s device=%s ip=%s port=%s client=%s", name == NULL ? "unknown" : name, session.peer, session.peerip, session.port, clientip); else report(LOG_NOTICE, "login failure: user=%s device=%s port=%s", name == NULL ? "unknown" : name, session.peerip, session.port); return(0); default: report(LOG_ERR, "%s %s: default_fn set bogus status value %d", session.peer, session.port, data->status); data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; return(0); } } /* * Do a login requiring a username & password. We already know the * username. We may return GETPASS to get a password if we need it. * The password will be stored in the private data */ static void tac_login(struct authen_data *data, struct private_data *p) { #if HAVE_PAM char *cfg_passwd; #endif char *name, *passwd; int pwlen; name = data->NAS_id->username; if (!name[0]) { /* something awful has happened. Give up and die */ report(LOG_ERR, "%s %s: no username for login", session.peer, session.port); data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; return; } /* Do we have a password? */ passwd = p->password; if (!passwd[0]) { /* * no password yet. Either we need to ask for one and expect to get * called again when it's supplied, or we already asked for one and * we should have a reply. */ switch (p->state) { case STATE_AUTHEN_GETPASS: /* We already asked for a password. This should be the reply */ if (data->client_msg) { pwlen = MIN((int) strlen(data->client_msg), MAX_PASSWD_LEN); } else { pwlen = 0; } strncpy(passwd, data->client_msg, pwlen); passwd[pwlen] = '\0'; break; case STATE_AUTHEN_START: /* * if we're at the username stage, and the user has nopasswd * defined, then return a PASS. */ if (cfg_get_user_nopasswd(name, TAC_PLUS_RECURSE)) { data->status = TAC_PLUS_AUTHEN_STATUS_PASS; return; } #if HAVE_PAM /* if the authen method is PAM, let PAM prompt for the password */ if ((cfg_passwd = cfg_get_login_secret(name, TAC_PLUS_RECURSE)) != NULL) { if (strcmp(cfg_passwd, "PAM") == 0) break; } #endif /* FALL-THRU */ default: data->flags = TAC_PLUS_AUTHEN_FLAG_NOECHO; data->server_msg = tac_strdup("Password: "); data->status = TAC_PLUS_AUTHEN_STATUS_GETPASS; p->state = STATE_AUTHEN_GETPASS; return; } } /* Now we have a username and password. Try validating */ /* Assume the worst */ data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; verify(name, passwd, data, TAC_PLUS_RECURSE); #ifdef ACLS if (verify_host(name, data, S_acl, TAC_PLUS_RECURSE) != S_permit) data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; #endif return; } /* * Process an inbound PAP login. The username & password should be in * the START packet. */ static void pap_verify(struct authen_data *data) { char *name, *passwd; name = data->NAS_id->username; if (name[0] == '\0') { /* something awful has happened. Give up and die */ report(LOG_ERR, "%s %s: no username for inbound PAP login", session.peer, session.port); data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; return; } /* get the password */ passwd = tac_malloc(data->client_dlen + 1); memcpy(passwd, data->client_data, data->client_dlen); passwd[data->client_dlen] = '\0'; /* Assume the worst */ data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; verify(name, passwd, data, TAC_PLUS_RECURSE); #ifdef ACLS if (verify_host(name, data, S_acl, TAC_PLUS_RECURSE) != S_permit) data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; #endif free(passwd); return; } /* Verify the challenge and id against the response by looking up the * chap secret in the config file. Set data->status appropriately. */ static void chap_verify(struct authen_data *data) { char *name, *secret, *chal, digest[TAC_MD5_DIGEST_LEN]; char *exp_date, *p; u_char *mdp; char id; int chal_len, inlen; MD5_CTX mdcontext; if (!(char) data->NAS_id->username[0]) { report(LOG_ERR, "%s %s: no username for chap_verify", session.peer, session.port); data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; return; } name = data->NAS_id->username; id = data->client_data[0]; chal_len = data->client_dlen - 1 - TAC_MD5_DIGEST_LEN; if (chal_len < 0) { data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; return; } if (debug & DEBUG_AUTHEN_FLAG) { report(LOG_DEBUG, "%s %s: chap user=%s, id=%d chal_len=%d", session.peer, session.port, name, (int) id, chal_len); /* report_hex(LOG_DEBUG, (u_char *)data->client_data + 1, chal_len); */ } /* Assume failure */ data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; /* Get the secret */ secret = cfg_get_chap_secret(name, TAC_PLUS_RECURSE); /* * If there is no chap password for this user, see if there is a global * password for her that we can use */ if (!secret) { secret = cfg_get_global_secret(name, TAC_PLUS_RECURSE); } if (!secret) { /* No secret. Fail */ if (debug & DEBUG_AUTHEN_FLAG) { report(LOG_DEBUG, "%s %s: No chap or global secret for %s", session.peer, session.port, name); } data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; return; } p = tac_find_substring("cleartext ", secret); if (!p) { report(LOG_ERR, "%s %s: %s chap secret %s is not cleartext", session.peer, session.port, name, secret); data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; return; } secret = p; /* * We now have the secret, the id, and the challenge value. Put them all * together, and run them through the MD5 digest algorithm. */ inlen = sizeof(u_char) + strlen(secret) + chal_len; mdp = (u_char *) tac_malloc(inlen); mdp[0] = id; memcpy(&mdp[1], secret, strlen(secret)); chal = data->client_data + 1; memcpy(mdp + strlen(secret) + 1, chal, chal_len); MD5Init(&mdcontext); MD5Update(&mdcontext, mdp, inlen); MD5Final((u_char *) digest, &mdcontext); free(mdp); /* * Now compare the received response value with the just calculated * digest value. If they are equal, it's a pass, otherwise it's a * failure */ if (memcmp(digest, data->client_data + 1 + chal_len, TAC_MD5_DIGEST_LEN)) { data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; } else { data->status = TAC_PLUS_AUTHEN_STATUS_PASS; } #ifdef ACLS if (verify_host(name, data, S_acl, TAC_PLUS_RECURSE) != S_permit) data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; #endif exp_date = cfg_get_expires(name, TAC_PLUS_RECURSE); set_expiration_status(exp_date, data); return; } /* * Force the "parity" bit to zero on a password before passing it to * des. This is not documented anywhere. (I believe forcing the parity * to zero reduces the integrity of the encrypted keys but this is * what Apple chose to do). */ void pw_bitshift(char *pw) { int i; unsigned char pws[8]; /* key is 0 padded */ for (i = 0; i < 8; i++) pws[i] = 0; /* parity bit is always zero (this seem bogus) */ for (i = 0; i < 8 && pw[i]; i++) pws[i] = pw[i] << 1; memcpy(pw, pws, 8); return; } static void arap_verify(struct authen_data *data) { char nas_chal[8], r_chal[8], r_resp[8], secret[8]; char *name, *cfg_secret, *exp_date, *p; #ifdef ARAP_DES union LR_block desblk; #endif if (!(char) data->NAS_id->username[0]) { report(LOG_ERR, "%s %s: no username for arap_verify", session.peer, session.port); data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; return; } name = data->NAS_id->username; memcpy(nas_chal, data->client_data, 8); memcpy(r_chal, data->client_data + 8, 8); memcpy(r_resp, data->client_data + 8 + 8, 8); /* Assume failure */ data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; /* Get the secret */ cfg_secret = cfg_get_arap_secret(name, TAC_PLUS_RECURSE); /* * If there is no arap password for this user, see if there is a global * password for her that we can use. */ if (!cfg_secret) { cfg_secret = cfg_get_global_secret(name, TAC_PLUS_RECURSE); } if (!cfg_secret) { /* No secret. Fail */ if (debug & DEBUG_AUTHEN_FLAG) { report(LOG_DEBUG, "%s %s: No arap or global secret for %s", session.peer, session.port, name); } data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; return; } p = tac_find_substring("cleartext ", cfg_secret); if (!p) { report(LOG_ERR, "%s %s: %s arap secret %s is not cleartext", session.peer, session.port, name, cfg_secret); data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; return; } /* need to allocate 8 bytes for secret, even if it's actually shorter */ memset(secret, 0, sizeof(secret)); memcpy(secret, p, strlen(p) <= 8 ? strlen(p) : 8); pw_bitshift(secret); #ifdef ARAP_DES tac_set_des_mode(DES_MODE_ENCRYPT); tac_des_loadkey(secret, DES_KEY_SHIFT); memcpy(desblk.string, nas_chal, 8); tac_des(&desblk); memcpy(nas_chal, desblk.string, 8); #endif /* * Now compare the remote's response value with the one just calculated. * If they are equal, it's a pass, otherwise it's a failure. */ if (memcmp(nas_chal, r_resp, 8)) { data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; } else { data->status = TAC_PLUS_AUTHEN_STATUS_PASS; } #ifdef ARAP_DES /* Now calculate the response to the remote's challenge */ tac_set_des_mode(DES_MODE_ENCRYPT); tac_des_loadkey(secret, DES_KEY_SHIFT); memcpy(desblk.string, r_chal, 8); tac_des(&desblk); memcpy(r_chal, desblk.string, 8); #endif data->server_data = tac_malloc(8); data->server_dlen = 8; memcpy(data->server_data, r_chal, 8); #ifdef ACLS if (verify_host(name, data, S_acl, TAC_PLUS_RECURSE) != S_permit) data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; #endif exp_date = cfg_get_expires(name, TAC_PLUS_RECURSE); set_expiration_status(exp_date, data); return; } #ifdef MSCHAP /* Following code is added for ms-chap */ static void mschap_desencrypt(char *clear, unsigned char *str, unsigned char *cypher) { unsigned char key[8]; #ifdef MSCHAP_DES union LR_block desblk; #endif /* XXX des_state_type *des_state = NULL; */ memset(key, 0, 8); /* Copy the key inserting parity bits */ #ifdef old /* This method makes it obvious what we are doing */ #define getbit(bit,array) ((array[bit/8] & (1 << (7-(bit%8)))) !=0) #define setbit(bit,array) (array[bit/8] |= (1 << (7-(bit%8)))) { int i, j; j = 0; for (i = 0; i < 56; i++) { if (i && (i % 7 == 0)) { j++; } if (getbit(i, str)) setbit(j, key); j++; } } #else /* * this is a little more cryptic, but faster basicly we are inserting a * bit into the stream after every 7 bits. */ key[0] = ((str[0] & 0xfe)); key[1] = ((str[0] & 0x01) << 7) | ((str[1] & 0x0fc) >> 1); key[2] = ((str[1] & 0x03) << 6) | ((str[2] & 0x0f8) >> 2); key[3] = ((str[2] & 0x07) << 5) | ((str[3] & 0x0f0) >> 3); key[4] = ((str[3] & 0x0f) << 4) | ((str[4] & 0x0e0) >> 4); key[5] = ((str[4] & 0x1f) << 3) | ((str[5] & 0x0c0) >> 5); key[6] = ((str[5] & 0x3f) << 2) | ((str[6] & 0x080) >> 6); key[7] = ((str[6] & 0x7f) << 1); #endif /* copy clear to cypher, cause our des encrypts in place */ memcpy(cypher, clear, 8); /* XXX des_init(0,&des_state); des_setkey(des_state,key); des_endes(des_state,cypher); des_done(des_state); */ #ifdef MSCHAP_DES tac_set_des_mode(DES_MODE_ENCRYPT); tac_des_loadkey(key, DES_KEY_SHIFT); memcpy(desblk.string, cypher, 8); tac_des(&desblk); memcpy(cypher, desblk.string, 8); #endif return; } static void mschap_deshash(char *clear, char *cypher) { mschap_desencrypt(MSCHAP_KEY, clear, cypher); return; } static void mschap_lmpasswordhash(char *password, char *passwordhash) { unsigned char upassword[15]; int i = 0; memset(upassword, 0, 15); while (password[i]) { upassword[i] = toupper(password[i]); i++; }; mschap_deshash(&upassword[0], &passwordhash[0]); mschap_deshash(&upassword[7], &passwordhash[8]); return; } static void mschap_challengeresponse(char *challenge, char *passwordhash, char *response) { char zpasswordhash[21]; memset(zpasswordhash, 0, 21); memcpy(zpasswordhash, passwordhash, 16); mschap_desencrypt(challenge, &zpasswordhash[0], &response[0]); mschap_desencrypt(challenge, &zpasswordhash[7], &response[8]); mschap_desencrypt(challenge, &zpasswordhash[14], &response[16]); return; } void mschap_lmchallengeresponse(char *challenge, char *password, char *response) { char passwordhash[16]; mschap_lmpasswordhash(password, passwordhash); mschap_challengeresponse(challenge, passwordhash, response); return; } static int mschap_unicode_len(char *password) { int i; i = 0; while ((password[i] || password[i + 1]) && (i < 512)) { i += 2; } return i; } static void mschap_ntpasswordhash(char *password, char *passwordhash) { MD4_CTX context; int i; char *cp; unsigned char unicode_password[512]; memset(unicode_password, 0, 512); i = 0; memset(unicode_password, 0, 512); cp = password; while (*cp) { unicode_password[i++] = *cp++; unicode_password[i++] = '\0'; } MD4Init(&context); MD4Update(&context, unicode_password, mschap_unicode_len(unicode_password)); MD4Final(passwordhash, &context); return; } void mschap_ntchallengeresponse(char *challenge, char *password, char *response) { char passwordhash[16]; mschap_ntpasswordhash(password, passwordhash); mschap_challengeresponse(challenge, passwordhash, response); return; } /* * Verify the challenge and id against the response by looking up the * ms-chap secret in the config file. Set data->status appropriately. */ static void mschap_verify(struct authen_data *data) { char *name, *secret, *chal, *resp; char *exp_date, *p; char id; int chal_len; char lmresponse[24]; char ntresponse[24]; int memcmp_status; if (!(char) data->NAS_id->username[0]) { report(LOG_ERR, "%s %s: no username for mschap_verify", session.peer, session.port); data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; return; } name = data->NAS_id->username; id = data->client_data[0]; chal_len = data->client_dlen - 1 - MSCHAP_DIGEST_LEN; if (data->client_dlen <= (MSCHAP_DIGEST_LEN + 2)) { /* Invalid packet or NULL challenge */ data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; return; } if (debug & DEBUG_AUTHEN_FLAG) { report(LOG_DEBUG, "%s %s: ms-chap user=%s, id=%d chal_len=%d", session.peer, session.port, name, (int) id, chal_len); /* XXX report_hex(LOG_DEBUG, (u_char *)data->client_data + 1, chal_len); */ } /* Assume failure */ data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; /* Get the secret */ secret = cfg_get_mschap_secret(name, TAC_PLUS_RECURSE); /* * If there is no ms-chap password for this user, see if there is a * global password for her that we can use */ if (!secret) { secret = cfg_get_global_secret(name, TAC_PLUS_RECURSE); } if (!secret) { /* No secret. Fail */ if (debug & DEBUG_AUTHEN_FLAG) { report(LOG_DEBUG, "%s %s: No ms-chap or global secret for %s", session.peer, session.port, name); } data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; return; } p = tac_find_substring("cleartext ", secret); if (!p) { report(LOG_ERR, "%s %s: %s ms-chap secret %s is not cleartext", session.peer, session.port, name, secret); data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; return; } secret = p; /* * We now have the secret, the id, and the challenge value. Put them all * together, and run them through the MD4 digest algorithm. */ chal = data->client_data + 1; resp = data->client_data + 1 + chal_len; mschap_lmchallengeresponse(chal, secret, lmresponse); mschap_ntchallengeresponse(chal, secret, ntresponse); /* * Now compare the received response value with the just calculated * digest value. If they are equal, it's a pass, otherwise it's a * failure. */ if (resp[48]) memcmp_status = memcmp(ntresponse, &resp[24], 24); else memcmp_status = memcmp(lmresponse, &resp[0], 24); if (memcmp_status) { data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; } else { data->status = TAC_PLUS_AUTHEN_STATUS_PASS; } #ifdef ACLS if (verify_host(name, data, S_acl, TAC_PLUS_RECURSE) != S_permit) data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; #endif exp_date = cfg_get_expires(name, TAC_PLUS_RECURSE); set_expiration_status(exp_date, data); return; } #endif /* MSCHAP */ #ifdef ACLS /* * Verify that the NAS's peerip matches the host acl filter. * Return S_deny if session.peerip is invalid, else S_permit */ int verify_host(char *name, struct authen_data *data, int type, int recurse) { char *realname, *val; int status; /* lookup host acl for user */ if (!cfg_user_exists(name) && cfg_user_exists(DEFAULT_USERNAME)) { if (debug & DEBUG_AUTHEN_FLAG) { report(LOG_DEBUG, "Authenticating ACLs for user '%s' instead of " "'%s'", DEFAULT_USERNAME, name); } realname = DEFAULT_USERNAME; } else realname = name; val = cfg_get_pvalue(realname, 1, type, recurse); /* no host acl for user */ if (val == NULL) return(S_permit); if ((status = cfg_acl_check(val, data->NAS_id->NAS_ip)) != S_permit) { if (debug & DEBUG_AUTHEN_FLAG) report(LOG_DEBUG, "host ACLs for user '%s' deny", realname); } else if (debug & DEBUG_AUTHEN_FLAG) report(LOG_DEBUG, "host ACLs for user '%s' permit", realname); return(status); } #endif