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 + -
显示快捷键?