home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.shrubbery.net
/
2015-02-07.ftp.shrubbery.net.tar
/
ftp.shrubbery.net
/
pub
/
tac_plus
/
tacacs+-F4.0.4.27a.tar.gz
/
tacacs+-F4.0.4.27a.tar
/
tacacs+-F4.0.4.27a
/
sendauth.c
< prev
next >
Wrap
C/C++ Source or Header
|
2012-01-23
|
9KB
|
348 lines
/*
* $Id: sendauth.c,v 1.7 2009-03-17 18:40:20 heas Exp $
*
* 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"
static int do_sendauth_fn();
static void outbound_chap();
#ifdef MSCHAP
static void outbound_mschap();
#endif /* MSCHAP */
void outbound_pap();
int
sendauth_fn(struct authen_data *data)
{
int status;
char *name, *p;
status = 0;
name = data->NAS_id->username;
if (STREQ(name, DEFAULT_USERNAME)) {
/* This username is only valid for authorization */
data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
} else {
status = do_sendauth_fn(data);
}
if (debug) {
switch (data->type) {
case TAC_PLUS_AUTHEN_TYPE_CHAP:
p = "chap";
break;
#ifdef MSCHAP
case TAC_PLUS_AUTHEN_TYPE_MSCHAP:
p = "ms-chap";
break;
#endif /* MSCHAP */
case TAC_PLUS_AUTHEN_TYPE_PAP:
p = "pap";
break;
default:
p = "unknown";
break;
}
report(LOG_INFO, "%s-sendauth query for '%s' %s from %s %s",
p,
name && name[0] ? name : "unknown",
session.peer, session.port,
(data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ?
"accepted" : "rejected");
}
return(status);
}
/*
* For PAP we need to supply the outgoing PAP cleartext password.
* from the config file.
*
* For CHAP, we expect an id and a challenge. We will return an MD5 hash
* if we're successful,
*
* Return 0 if data->status is valid, otherwise 1
*/
static int
do_sendauth_fn(struct authen_data *data)
{
char *name, *exp_date;
data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
/* We must have a username */
if (!data->NAS_id->username[0]) {
/* Missing username is a gross error */
data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
data->server_msg = tac_strdup("No username supplied");
report(LOG_ERR, "%s: No username for sendauth_fn", session.peer);
return(0);
}
name = data->NAS_id->username;
switch (data->type) {
case TAC_PLUS_AUTHEN_TYPE_CHAP:
outbound_chap(data);
break;
#ifdef MSCHAP
case TAC_PLUS_AUTHEN_TYPE_MSCHAP:
outbound_mschap(data);
break;
#endif /* MSCHAP */
case TAC_PLUS_AUTHEN_TYPE_PAP:
outbound_pap(data);
break;
default:
data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
report(LOG_ERR, "%s %s: %s Illegal data type for sendauth_fn",
session.peer, session.port, name);
return(0);
}
exp_date = cfg_get_expires(name, TAC_PLUS_RECURSE);
set_expiration_status(exp_date, data);
return(0);
}
void
outbound_pap(struct authen_data *data)
{
char *secret, *p, *name;
name = data->NAS_id->username;
/* We must have a username */
if (!name) {
data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
return;
}
/* Return her secret outbound PAP info */
secret = cfg_get_opap_secret(name, TAC_PLUS_RECURSE);
if (!secret) {
if (debug & DEBUG_AUTHEN_FLAG) {
report(LOG_ERR, "%s %s: No opap secret for %s",
session.peer, session.port, name);
}
data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
return;
}
p = tac_find_substring("cleartext ", secret);
if (!p) {
/* Should never happen */
data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
report(LOG_ERR, "%s %s: Illegal opap secret format %s",
session.peer, session.port, secret);
return;
}
data->server_data = tac_strdup(p);
data->server_dlen = strlen(data->server_data);
data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
}
static void
outbound_chap(struct authen_data *data)
{
char *name, *secret, *chal, digest[TAC_MD5_DIGEST_LEN];
char *p;
u_char *mdp;
char id;
int chal_len, inlen;
MD5_CTX mdcontext;
name = data->NAS_id->username;
if (!name) {
report(LOG_ERR, "%s %s: no username for outbound_chap",
session.peer, session.port);
data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
return;
}
id = data->client_data[0];
chal_len = data->client_dlen - 1;
if (chal_len < 0) {
data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
return;
}
if (debug & DEBUG_AUTHEN_FLAG) {
report(LOG_DEBUG, "%s %s: user %s, id=%d chal_len=%d",
session.peer, session.port, name, (int)id, chal_len);
}
/* Assume failure */
data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
/* 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) {
/* Should never happen */
data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
report(LOG_ERR, "%s %s: Illegal opap secret format %s",
session.peer, session.port, secret);
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 return the calculated response value */
data->server_data = tac_malloc(TAC_MD5_DIGEST_LEN);
memcpy(data->server_data, digest, TAC_MD5_DIGEST_LEN);
data->server_dlen = TAC_MD5_DIGEST_LEN;
data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
}
#ifdef MSCHAP
static void
outbound_mschap(struct authen_data *data)
{
char *name, *secret, *chal;
char *p;
char id;
int chal_len;
name = data->NAS_id->username;
if (!name) {
report(LOG_ERR, "%s %s: no username for outbound_mschap",
session.peer, session.port);
data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
return;
}
id = data->client_data[0];
chal_len = data->client_dlen - 1;
if (data->client_dlen <= 2) {
data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
return;
}
if (debug & DEBUG_AUTHEN_FLAG) {
report(LOG_DEBUG, "%s %s: user %s, id=%d chal_len=%d",
session.peer, session.port, name, (int)id, chal_len);
}
/* Assume failure */
data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
/* Get the secret */
secret = cfg_get_mschap_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 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) {
/* Should never happen */
data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
report(LOG_ERR, "%s %s: Illegal ms-chap secret format %s",
session.peer, session.port, secret);
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;
/*
* Now return the calculated response value */
data->server_data = tac_malloc(MSCHAP_DIGEST_LEN);
mschap_lmchallengeresponse(chal,secret,&data->server_data[0]);
mschap_ntchallengeresponse(chal,secret,&data->server_data[24]);
data->server_data[48] = 1; /* Mark it to use the NT response*/
data->server_dlen = MSCHAP_DIGEST_LEN;
data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
}
#endif /* MSCHAP */