rad.tacacs.c

来自「RADIUS协议的认证计费服务」· C语言 代码 · 共 487 行

C
487
字号
/* * Copyright [C] The Regents of the University of Michigan and Merit Network, * Inc. 1992, 1993, 1994, 1995, 1996, 1997, 1998 All Rights Reserved * * Permission to use, copy, and modify this software and its documentation  * for any purpose and without fee is hereby granted, provided:  * * 1) that the above copyright notice and this permission notice appear in all *    copies of the software and derivative works or modified versions thereof,  * * 2) that both the copyright notice and this permission and disclaimer notice  *    appear in all supporting documentation, and  * * 3) that all derivative works made from this material are returned to the *    Regents of the University of Michigan and Merit Network, Inc. with *    permission to copy, to display, to distribute, and to make derivative *    works from the provided material in whole or in part for any purpose. * * Users of this code are requested to notify Merit Network, Inc. of such use * by sending email to aaa-admin@merit.edu * * Please also use aaa-admin@merit.edu to inform Merit Network, Inc of any * derivative works. * * Distribution of this software or derivative works or the associated * documentation is not allowed without an additional license. * * Licenses for other uses are available on an individually negotiated * basis.  Contact aaa-license@merit.edu for more information. * * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE REGENTS OF THE * UNIVERSITY OF MICHIGAN AND MERIT NETWORK, INC. DO NOT WARRANT THAT THE * FUNCTIONS CONTAINED IN THE SOFTWARE WILL MEET LICENSEE'S REQUIREMENTS OR * THAT OPERATION WILL BE UNINTERRUPTED OR ERROR FREE.  The Regents of the * University of Michigan and Merit Network, Inc. shall not be liable for any * special, indirect, incidental or consequential damages with respect to any * claim by Licensee or any third party arising from use of the software. * * Merit AAA Server Support * Merit Network, Inc. * 4251 Plymouth Road, Suite C. * Ann Arbor, Michigan, USA 48105-2785 * * attn:  John Vollbrecht * voice: 734-764-9430 * fax:   734-647-3185 * email: aaa-admin@merit.edu * *//* * * Public entry points in this file: * */static char     rcsid[] = "$Id: rad.tacacs.c,v 1.1.1.1 2001/08/10 20:49:28 bonze Exp $";#include	<sys/types.h>#include	<sys/param.h>#include	<sys/socket.h>#include	<sys/time.h>#include	<sys/file.h>#include	<sys/wait.h>#include	<net/if.h>#include	<netinet/in.h>#include	<stdio.h>#include	<netdb.h>#include	<errno.h>#include	<signal.h>#include	<memory.h>#include	<syslog.h>#include	"radius.h"extern char      recv_buffer[RAD_RECV_BUFFER_SIZE];extern char      send_buffer[RAD_SEND_BUFFER_SIZE];extern char      default_tacacs_server[];extern int       debug_flag;extern char     *radius_dir;extern AUTH_REQ_Q global_auth_q;#ifndef TACACSAATVPTR          rad_tacs_aatv = NULL;#else#include	"tacacs.h"static AUTH_REQ *tacs_recv PROTO((int, struct sockaddr_in *, UINT4, u_int, EV *));static void      rad_tacs_init PROTO((AATV *));static int       tacacs_pass PROTO((AUTH_REQ *, int, char *));static int       tacacs_reply PROTO((AUTH_REQ *, u_int, UINT4));static AATV      tacs_aatv = DEF_AATV_SOCKET_TYPE("TACACS", AA_TACACS,						  rad_tacs_init, tacacs_pass,						  tacs_recv);AATVPTR          rad_tacs_aatv = & tacs_aatv;/************************************************************************* * *	Function: rad_tacs_init * *	Purpose: Perform TACACS socket initialization. * *************************************************************************/static voidrad_tacs_init (aatv)AATV            *aatv;{	struct sockaddr_in lclsin;	static char    *func = "rad_tacs_init";	dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: entered", func));	if (aatv->sockfd == -1)	{		aatv->sockfd = setupsock (&lclsin, 0);	}	return;} /* end of rad_tacs_init () *//************************************************************************* * *	Function: tacacs_pass * *	Purpose: Check users password against TACACS authentication system. *		 Use RADIUS style encryption extension to TACACS. * *************************************************************************/static inttacacs_pass (authreq, value, realm)AUTH_REQ       *authreq;int             value;char           *realm;{	u_short         svc_port;	int             i;	int             randno;	int             secretlen;	int             total_length;	UINT4           auth_ipaddr;	char           *ptr;	VALUE_PAIR     *vp;	CLIENT_ENTRY   *ce;	xtacacstype    *TApkt;	struct servent *svp;	struct sockaddr_in sin;	char            id[AUTH_ID_LEN + 1];	char            passwd[AUTH_PASS_LEN + 1];	u_char          md5buf[AUTH_VECTOR_LEN + MAX_SECRET_LENGTH];	static char     zeroes[AUTH_VECTOR_LEN + 1] = { 0 };	static char    *func = "tacacs_pass";	if (authreq == (AUTH_REQ *) NULL)	{		return EV_NAK;	}	dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: entered", func));	/*	 * If no server system DNS name is provided, a default is used.	 * Set #define DEFAULT_TACACS_SERVER to the name of the default	 * server system to use for TACACS authentication.	 */	if ((realm == NULL) || (realm[0] == '\0'))	{		realm = default_tacacs_server;	}	if ((vp = get_vp_vend (authreq->cur_request, PW_USER_ID, VC_MERIT))								== NULL_VP)	{		logit (LOG_DAEMON, LOG_ALERT,			"%s: Improper userid specification", func);		reply_message (authreq, EC_INTERNAL, func);		return EV_NAK;	}	strcpy (id, vp->strvalue);	/* Find tacacs server in the database */	if (find_client_by_name (realm, &auth_ipaddr, &ce) != 0)	{		logit (LOG_DAEMON, LOG_ERR,			"%s: server '%s' not in %s/%s",			 func, realm, radius_dir, RADIUS_CLIENTS);		return EV_NAK;	}	/*	 * Decrypt password, if it's there.  Pass along PW_CHAP_PASSWORD, too.	 * If the PW_USER_PASSWORD value pair is present, this routine will	 * decrypt it in passwd.  The PW_CHAP_PASSWORD is passed along in case	 * the TACACS server can do anything with it.	 */	/*	 *	Allow optional client specific port selection.	 */	if (ce->auth_port != 0)	{		svc_port = ce->auth_port;	}	else	{		svp = getservbyname ("tacacs", "udp");		if (svp == (struct servent *) 0) /* Use default macro value */		{			svc_port = DFLT_TACACS_UDP_PORT;		}		else /* use the value from the /etc/services file */		{			svc_port = ntohs(svp->s_port);		}	}	TApkt = (xtacacstype *) send_buffer;	TApkt->version = XTA_VERSION;		/* Extended tacacs */	TApkt->type = XTA_LOGIN;		/* Login access type */	TApkt->trans = authreq->fwd_id;		/* Transaction number */	TApkt->namelen = strlen (id);	if ((vp = get_vp (authreq->cur_request, PW_CHAP_PASSWORD)) == NULL)	{		TApkt->pwlen = AUTH_VECTOR_LEN + 1;	}	else	{		TApkt->pwlen = CHAP_VALUE_LENGTH + 1 + 1;	}	TApkt->response = 0;	TApkt->reason = 0;	TApkt->uuid = 0;	TApkt->dhost = 0;	TApkt->dport = 0;	TApkt->lport = 0;	TApkt->flags = 0;	TApkt->accesslist = 0;	ptr = send_buffer + XTACACSSIZE;	strcpy (ptr, id);	ptr += strlen (id);	if (vp == NULL)		/* no PW_CHAP_PASSWORD value-pair */	{		memset (passwd, 0, sizeof (passwd));		get_passwd (authreq, passwd, (char *) NULL, (char *) NULL);		*ptr++ = 0;			/* Flag says not CHAP */		/* Calculate the MD5 Digest */		secretlen = strlen (ce->secret);		strncpy ((char *) md5buf, ce->secret, secretlen);		/* Make up a new vector, if there is none. */		if (memcmp ((char *) authreq->fwdvec,				zeroes, AUTH_VECTOR_LEN) == 0)		{			srand (time (0));			for (i = 0; i < AUTH_VECTOR_LEN; i += sizeof (int))			{				randno = rand ();				memcpy ((char *) &authreq->fwdvec[i],					(char *) &randno, sizeof (int));			}		}		memcpy ((char *) md5buf + secretlen, (char *) authreq->fwdvec,			AUTH_VECTOR_LEN);		md5_calc (ptr, md5buf, secretlen + AUTH_VECTOR_LEN);		/* Note that this code doesn't handle long pw's      */		/* since the receiver probably can't deal with them. */		/* Xor the password into the MD5 digest */		for (i = 0; i < AUTH_VECTOR_LEN; i++)		{			*ptr++ ^= passwd[i];		}		memset ((char *) md5buf, 0, sizeof (md5buf));		/* Don't keep password around */		memset (passwd, 0, sizeof (passwd));	}	else			/* CHAP - pass name and challenge response */	{		*ptr++ = 1;			/* Flag to indicate CHAP */		memcpy (ptr, vp->strvalue, CHAP_VALUE_LENGTH + 1);		ptr += CHAP_VALUE_LENGTH + 1;		if ((vp = get_vp (authreq->cur_request,				PW_CHAP_CHALLENGE)) != NULL)		{			memset ((char *) authreq->fwdvec, '\0',				AUTH_VECTOR_LEN);			memcpy ((char *) authreq->fwdvec, vp->strvalue,				MIN(AUTH_VECTOR_LEN, vp->lvalue));		}		else		{			missing_attribute (authreq, func, PW_CHAP_CHALLENGE,				realm);			return EV_NAK;		}	}	memcpy (ptr, (char *) authreq->fwdvec, AUTH_VECTOR_LEN);	ptr += AUTH_VECTOR_LEN;	total_length = ptr - send_buffer;	dprintf(1, (LOG_AUTH, LOG_DEBUG,		"Issuing TACACS_REQ of id %d from %lx (%s) to %s",		authreq->fwd_id, (UINT4) authreq->ipaddr,		ip_hostname (authreq->ipaddr), realm));	memset ((char *) &sin, '\0', sizeof (sin));	sin.sin_family = AF_INET;	sin.sin_addr.s_addr = htonl(auth_ipaddr);	sin.sin_port = htons(svc_port);	sendto (tacs_aatv.sockfd, (char *) send_buffer, (int) total_length,		 (int) 0, (CONST struct sockaddr *) &sin, sizeof (sin));	return EV_WAIT;		/* EV_WAIT says to expect reply later */} /* end of tacacs_pass () *//************************************************************************* * *	Function: tacacs_reply * *	Purpose: Validate and check reply from TACACS server. * *	Returns: EV_ACK if authentication was valid, *		 EV_NAK if authentication was rejected, *		 EV_ERROR if reply was invalid. * *************************************************************************/static inttacacs_reply (authreq, rcvlen, from_ipaddr)AUTH_REQ       *authreq;u_int           rcvlen;UINT4           from_ipaddr;{	u_char          md5buf[AUTH_VECTOR_LEN];	u_char          reply_digest[AUTH_VECTOR_LEN];	CLIENT_ENTRY   *ce;	char           *ptr;	int             secretlen;	xtacacstype    *TApkt;	static char    *func = "tacacs_reply";	dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: entered", func));	if (find_client (from_ipaddr, &ce) != 0)	{		logit (LOG_DAEMON, LOG_ERR,			"%s: server '%s' not in %s/%s", func,			ip_hostname (from_ipaddr), radius_dir, RADIUS_CLIENTS);		return EV_ERROR;	}	TApkt = (xtacacstype *) recv_buffer;	/* Set "ptr" to point to end of fixed part of TApkt. */	/* The MD5 signature is supposed to be hidden there. */	ptr = recv_buffer + XTACACSSIZE;	memcpy ((char *) md5buf, ptr, AUTH_VECTOR_LEN);	memcpy (ptr, (char *) authreq->fwdvec, AUTH_VECTOR_LEN);	secretlen = strlen (ce->secret);	memcpy (recv_buffer + rcvlen, ce->secret, secretlen);	md5_calc (reply_digest, recv_buffer, rcvlen + secretlen);	memset (recv_buffer + rcvlen, 0, secretlen);	if (memcmp ((char *) md5buf, (char *) reply_digest,		    AUTH_VECTOR_LEN) != 0)	{		logit (LOG_DAEMON, LOG_INFO, "%s: Invalid reply digest from %s",			func, ip_hostname (from_ipaddr));		return EV_ERROR;	}	if ((TApkt->trans != authreq->fwd_id) || (TApkt->type != XTA_ANSWER))	{		logit (LOG_DAEMON, LOG_INFO, "%s: Invalid reply from %s",			func, ip_hostname (from_ipaddr));		return EV_ERROR;	}	switch (TApkt->response)	{	    case XTA_A_ACCEPTED:		return EV_ACK;	    case XTA_A_REJECTED:	    default:		return EV_NAK;	}} /* end of tacacs_reply () *//************************************************************************* * *	Function: tacs_recv * *	Purpose: Match TACACS reply with our client's request. *		 Looks for request on global_auth_q.q. *		 Calls tacacs_reply () to validate and check the TACACS reply. * *************************************************************************/static AUTH_REQ *tacs_recv (sockfd, sin, from_ipaddr, rcvlen, ev)int                     sockfd;UINT4                   from_ipaddr;struct sockaddr_in     *sin;u_int                   rcvlen;EV                     *ev;{	u_short         rcv_id;	xtacacstype    *TApkt;	AUTH_REQ       *authreq;	EVENT_ENT      *event;	EVENT_ENT     **prev_event;	static char    *func = "tacs_recv";	dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: entered", func));	TApkt = (xtacacstype *) recv_buffer;	rcv_id = TApkt->trans;	for (authreq = global_auth_q.q;		authreq && authreq->fwd_id != rcv_id;		authreq = authreq->next)	{		;	}	if (authreq == (AUTH_REQ *) NULL)	{		logit (LOG_DAEMON, LOG_INFO,		      "%s: no authreq, odd TACACS reply from %s for request %u",			func, inet_ntoa (sin->sin_addr), rcv_id);		return authreq;	}	dprintf(1, (LOG_AUTH, LOG_DEBUG,		"Received reply from %s to TACACS request %u",		inet_ntoa (sin->sin_addr), rcv_id));	for (prev_event = &authreq->event_q ;		(event = *prev_event) != (EVENT_ENT *) NULL ;		prev_event = &event->next)	{		if (event->sub_aatv == rad_tacs_aatv)		{			ev->state = event->state;			ev->a.aatv = event->fsm_aatv;			ev->isproxy = 0;			ev->value = tacacs_reply (authreq, rcvlen, from_ipaddr);			strcpy (ev->xstring, event->estring);			/* unlink this EVENT_ENT and free the memory */			*prev_event = event->next;			free (event);			break;		}	}	if (event == (EVENT_ENT *) NULL)	{		logit (LOG_DAEMON, LOG_INFO,			"%s: no event, odd TACACS reply from %s for request %u",			func, inet_ntoa (sin->sin_addr), rcv_id);		return (AUTH_REQ *) NULL;	}	return authreq;} /* end of tacs_recv () */#endif	/* TACACS */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?