⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 proxy.c

📁 This program is a RADIUS RFC-compliant daemon, which is derived from original Livingston Enterprise
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 1999-2002 Francesco P. Lovergine.  * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms stated in the LICENSE file which should be * enclosed with sources. */static char rcsid[] = "$Id: proxy.c,v 1.5.4.2 2004/08/27 21:45:16 flovergine Exp $";#include "yard.h"#include "global.h"static  AUTH_REQ *first_forwarded = (AUTH_REQ *)NULL;static	PEER	*servers;static	PEER	*server_default;static	PEER	*server_norealm;/************************************************************************* *************************************************************************	Subroutines related to forwarding a Proxy reply from a server	to the client:	rad_proxy(fd)	pop_proxy(authreq, pstate)	send_proxy2client(fd, authreq, server, pstate)	update_proxy()	find_server() ************************************************************************* *************************************************************************//************************************************************************* * *	Function: rad_proxy * *	Purpose: Receive UDP Proxy server replies and forward to client * *	Uses External: sockfd, acctfd * *************************************************************************/void rad_proxy(int fd){	extern AUTH_REQ		*first_forwarded;	extern int		max_proxy_time;	AUTH_HDR		*auth;	AUTH_REQ		*authreq;	AUTH_REQ		*oldqp;	AUTH_REQ		*qp;	AUTH_REQ		*qpop;	PEER			*server;	UINT4			host;	char			digest[AUTH_VECTOR_LEN];	char			hold_digest[AUTH_VECTOR_LEN];	char			*sentreqauth;	int			result;	int			secretlen;	size_t			salen;	struct	sockaddr_in	*sin;	struct  sockaddr_in     rad_saremote;	u_short			port;	salen = sizeof(rad_saremote);	sin = (struct sockaddr_in *) & rad_saremote;	auth = (AUTH_HDR *)recv_buffer;	result = recvfrom (fd, (char *) recv_buffer,		(int) sizeof(recv_buffer),		(int) 0, (struct sockaddr *)&rad_saremote, &salen);	host = ntohl(sin->sin_addr.s_addr);	port = ntohs(sin->sin_port);	/* Drop the packet if we do not know the proxy */	if ((server = find_server_byaddr(host, port)) == (PEER *)NULL) {		log_err("auth: packet from unknown proxy server %s.%d ignored\n", ipaddr2strp(host), port);		return;	}	authreq = radrecv( host, port, server->secret, recv_buffer, result);	secretlen = strlen(server->secret);        if (authreq == (AUTH_REQ *)NULL) {                return;        }	/* Security check: next memcpy() must not overflow */	if ((size_t)(result+secretlen)>sizeof(recv_buffer)) {		log_err("rad_proxy: exceeding size of receiving buffer");		return;	}	/* Verify response authenticator */	switch (authreq->code) {		case  PW_AUTHENTICATION_ACK:		case  PW_AUTHENTICATION_REJECT:		case  PW_ACCESS_CHALLENGE:			fd = sockfd;			break;		case  PW_ACCOUNTING_RESPONSE:			fd = acctfd;			break;		case  PW_AUTHENTICATION_REQUEST:		case  PW_ACCOUNTING_REQUEST:		default:			log_err("rad_proxy: proxy server %s/%d.%d sent back invalid packet type %d, ignoring\n", ipaddr2strp(host), port, authreq->id, authreq->code);			reqfree(authreq, "rad_proxy");			return;			break;	}	debug("proxy server %s/%d.%d replied with code=%d, length=%d\n", ipaddr2strp(host), port, authreq->id, authreq->code, result);	if (debug_flag > 2) {		hexdump((u_char*)recv_buffer,result);	}	/* Find original request authenticator */	oldqp = (AUTH_REQ *)NULL;	qp = first_forwarded;	while ((qp != (AUTH_REQ *)NULL) && (qp->forw_id != authreq->id)) {		oldqp = qp;		if (qp == qp->next) {	/* should never happen */			log_err("ERROR: circular queue detected at %d\n", __LINE__);			qp->next = (AUTH_REQ *)NULL;		}		qp = qp->next;	}	if (qp != (AUTH_REQ *)NULL) {		if (oldqp == (AUTH_REQ *)NULL) {			first_forwarded = qp->next;		} else {			oldqp->next = qp->next;		}		qp->next = (AUTH_REQ *)NULL;		sentreqauth = qp->forw_vector;	}	qpop = (AUTH_REQ *)NULL;	if (server->flags & PEER_NOPROXY) { /* server can't do proxy */		if (qp == (AUTH_REQ *)NULL) {	/* not found in queue */			debug("rad_proxy: response from %s/%d.%d not matched in forwarded queue, dropped\n", ipaddr2strp(host), port, authreq->id);			reqfree(authreq, "rad_proxy");			return;		} else {			qpop = qp;		}	} else { /* proxy-capable server */		 /* pop last Proxy-State and fill in qp, if needed */	    	if ((qpop = pop_proxy(authreq, qp)) == (AUTH_REQ *)NULL) {			log_err("rad_proxy: invalid Proxy-State from proxy server %s/%d.%d, dropped\n", ipaddr2strp(host), port, authreq->id);			if (debug_flag > 0) {				hexdump((u_char*)authreq->packet,result);			}			reqfree(authreq, "rad_proxy");			return;		}	}	if (qp == (AUTH_REQ *)NULL) {		if (authreq->code == PW_ACCOUNTING_RESPONSE) {			/* radiusd has restarted or we've already			   forwarded this response, so drop this response			 */			debug("rad_proxy: accounting-response from %s/%d.%d not matched in forwarded queue, dropped\n",				ipaddr2strp(host), port, authreq->id);			reqfree(authreq, "rad_proxy");			reqfree(qpop, "rad_proxy");			return;		} else {			/* for access-responses, we can use the Request			 * authenticator we included in the proxy, if we			 * do not find it in our queue			 */			qp = qpop;			sentreqauth = qp->vector;		}	}	if ((authreq->code == PW_ACCOUNTING_RESPONSE) &&	    (server->flags & PEER_OLDACCT)) {	/* ignore acct signature */		send_proxy2client(fd, authreq, server, qp);		reqfree(qp,"rad_proxy");	} else {			/* Check response authenticator */		memcpy(hold_digest, auth->vector, AUTH_VECTOR_LEN);		memcpy(auth->vector, sentreqauth, AUTH_VECTOR_LEN);		memcpy(recv_buffer + result, server->secret, secretlen);		md5_calc((u_char*)digest, (u_char *)auth, result + secretlen);		memset(recv_buffer + result, 0, secretlen);		/* no need to restore auth->vector */		if (memcmp(hold_digest, digest, AUTH_VECTOR_LEN) == 0) {			send_proxy2client(fd, authreq, server, qp);			reqfree(qp,"rad_proxy");		} else {			log_err("rad_proxy: remote server %s/%d.%d sent invalid reply, dropping\n", ipaddr2strp(host), port, authreq->id);			if (debug_flag > 0) {				hexdump((u_char*)authreq->packet,result);			}			/* requeue qp if it hasn't timed out */			if (qp != (AUTH_REQ *)NULL) {				if (qp->timestamp + max_proxy_time > now) {					qp->next = first_forwarded;					first_forwarded = qp;				} else {					reqfree(qp,"rad_proxy");				}                	}		}	}	reqfree(authreq,"rad_proxy");	return;}/************************************************************************* * *	Function: pop_proxy * *      Purpose: Remove the last proxy-state attribute from authreq->request, *	and returns a pointer to qp, allocating it if necessary. * *	Any format changes made here must also be made in push_proxy() * *************************************************************************/AUTH_REQ *pop_proxy(AUTH_REQ *authreq,AUTH_REQ *qp){	VALUE_PAIR	*value_list;	VALUE_PAIR	*old_value;	VALUE_PAIR	*prev_value;	VALUE_PAIR	*lastproxy;	UINT4		tmp;	u_short		tmps;	u_char		hostnm[256];	/* passed as an argument, but unused */	old_value = (VALUE_PAIR *) NULL;	prev_value = (VALUE_PAIR *) NULL;	lastproxy = (VALUE_PAIR *) NULL;	value_list = authreq->request;	while(value_list != (VALUE_PAIR *)NULL) {		if(value_list->attribute == PW_PROXY) {			lastproxy = value_list;			prev_value = old_value;		}		old_value = value_list;		value_list = value_list->next;	}	if (lastproxy == (VALUE_PAIR *)NULL) { /* not found */		return (qp);	}	/* pop lastproxy from linked list */	if (prev_value != (VALUE_PAIR *)NULL) {		prev_value->next = lastproxy->next;	} else {		authreq->request = lastproxy->next;	}	lastproxy->next = (VALUE_PAIR *)NULL;	/* Proxy-State contains: Timestamp, Client, Port, Id in network order,	   a pad byte, and 16 octets of Request Authenticator */	if (lastproxy->lvalue < 28) {		log_err("pop_proxy: Proxy-State from %s has too short length %d < 28, ignoring\n", req2strp(authreq), lastproxy->lvalue);	}	if (qp != (AUTH_REQ *)NULL) {		pairfree(lastproxy, "pop_proxy");		return (qp);	} else {		qp = reqalloc("pop_proxy");	}	memcpy((char *)&tmp, lastproxy->strvalue, 4);	qp->timestamp = ntohl(tmp);	memcpy((char *)&tmp, lastproxy->strvalue+4, 4);	qp->ipaddr = ntohl(tmp);	memcpy((char *)&tmps, lastproxy->strvalue+8, 2);	qp->udp_port = ntohs(tmps);	memcpy((char *)&(qp->id), lastproxy->strvalue+10, 1);	memcpy((char *)qp->vector, lastproxy->strvalue+12, AUTH_VECTOR_LEN);	pairfree(lastproxy, "pop_proxy");	if(find_client(qp->ipaddr, qp->secret, AUTH_REQ_FORW_SECRET_LEN, hostnm, sizeof(hostnm)) != 0) {		reqfree(qp, "pop_proxy");		qp = (AUTH_REQ *)NULL;	}	return qp;}/************************************************************************* * *	Function: send_proxy2client * *	Purpose: Forward a proxy reply to a client defined in qp. *		 Calling routine has already removed our Proxy-State * *************************************************************************/void send_proxy2client(int fd,AUTH_REQ*authreq,PEER*server,AUTH_REQ*qp){	AUTH_HDR		*auth;	VALUE_PAIR		*curpair;	VALUE_PAIR		*pair;	VALUE_PAIR		*reply;	char			ip_str[32];	u_short			total_length;	auth = (AUTH_HDR *)send_buffer;	reply = authreq->request;	req2str(ip_str,sizeof(ip_str),authreq);	/* if realm is marked insecure and has returned a Admin or NAS-Prompt	   service type, send a reject to the client instead, and log it */	if ( (!(server->flags & PEER_ADMINOK))	     && (((pair = get_attribute(authreq->request,			PW_USER_SERVICE_TYPE)) != (VALUE_PAIR *)NULL)		    && ((pair->lvalue == PW_ADMIN_USER)		       || (pair->lvalue == PW_PROMPT_USER)))) {		authreq->code = PW_AUTHENTICATION_REJECT;		log_err("remote server %s returned insecure service for client %s, sending reject instead\n",			ip_str, req2strp(qp));		/* copy over only proxy-states */		authreq->request = (VALUE_PAIR *)NULL;		curpair = (VALUE_PAIR *)NULL;		while(reply != (VALUE_PAIR *)NULL) {			if (reply->attribute == PW_PROXY) {				if (curpair == (VALUE_PAIR *)NULL) {					curpair = reply;					authreq->request = reply;				} else {					curpair->next = reply;					curpair = reply;				}			} else {				pairfree(reply, "send_proxy2client");			}			reply=reply->next;		}		if (curpair != (VALUE_PAIR *)NULL) {			curpair->next = (VALUE_PAIR *)NULL;		}	}	debug("forwarding reply code %d from %s to %s\n",		authreq->code, ip_str, req2strp(qp));	/* Load up the configuration values for the user */	total_length = build_packet(qp, authreq->request, (char *)NULL,				    authreq->code, FW_CLIENT, send_buffer, sizeof(send_buffer));	/* send it to the client */	send_packet(fd, qp->ipaddr, qp->udp_port, send_buffer, total_length);}/************************************************************************* * *	Function: update_proxy * *	Purpose: Check last modified time on proxy file and build a *		 new servers list if the file has been changed. * *************************************************************************/int update_proxy(void){	extern u_short	radacct_port;	extern u_short	radius_port;	static UINT4	ouraddress = 0;	static int	first = 0;	static time_t	last_update_time;	FILE		*fd;	PEER		*curserv;	PEER		*server;	UINT4		ipaddr;	char		*arg;	char		*hostnm;	char		*realm;	char		*secret;	char		ourname[256];	int		lineno;	int		nproxy;	struct stat 	statbuf;	u_char		buffer[PATH_MAX];	u_short		rport;	nproxy = 0;	/* Check last modified time of proxy file */	snprintf((char *)buffer,sizeof(buffer),"%s/%s", radius_dir, RADIUS_PROXY);	if(stat(buffer, &statbuf) != 0) {		if (first == 0) {			log_err("proxy file %s not found; not using proxy\n", 			buffer);			first++;		}		return(0);	}	if(statbuf.st_mtime == last_update_time) {		/* nothing to update */		return(0);	}	/* Get our address if we have not already */	/* This will need to be changed to support multi-homed hosts */	if (ouraddress == 0) {		errno = 0;		if (gethostname(ourname, 128) != 0) {			log_err("update_proxy: unable to get own hostname; %s\n",				strerror(errno));		}		ouraddress = get_ipaddr(ourname);		if (ouraddress == 0) {			log_err("update_proxy: unable to resolve own hostname \"%s\"\n",ourname);		}	}	/* Proxy file format:	 *	hostname secret realm options...	 *	 * realm can be user@realm or a Called-Station-Id	 *	 */	/* Open the proxy file */	if((fd = fopen((const char *)buffer, "r")) == (FILE *)NULL) {		log_err("Error: could not read proxy file %s; %s\n", buffer,			strerror(errno));		return(-1);	}	/* free up existing linked list of servers */	while (servers != (PEER *)NULL) {		server = servers;		servers = servers->next;		server->next = (PEER *)NULL;		peerfree(server, "update_proxy");	}	server = (PEER *)NULL;	server_default = (PEER *)NULL;	server_norealm = (PEER *)NULL;	lineno=0;	while (fgets((char *)buffer, sizeof(buffer), fd) != (char *)NULL) {		lineno++;		if(*buffer == '#' || *buffer == ' ' || *buffer == '\t'		   || *buffer == '\n') {			continue;		}		hostnm = strtok(buffer, " \t\n");		secret = strtok((char *)NULL, " \t\n");		realm = strtok((char *)NULL, " \t\n");		if (realm == (char *)NULL) {			log_err("syntax error on line %d in proxy file\n", lineno);			continue;		}		if((ipaddr = get_ipaddr(hostnm)) == (UINT4)0) {			log_err("could not resolve proxy hostname %s at line %d\n", hostnm, lineno);			continue;		}		/* store in realm linked list */		server = peeralloc("update_proxy");		/* parse arguments to proxy line */		while ((arg = strtok((char *)NULL, " \t\n, ")) != (char *)NULL) {			if (isdigit(arg[0])) {				rport = atoi(arg);				if (rport > 0) {					if (server->radport == 0) {						server->radport = rport;					} else if (server->acctport == 0) {						server->acctport = rport;					} else {						log_err("unknown argument \"%s\" on line %d in proxy file\n", arg, lineno);					}				}				continue;			}			if (strcmp(arg, "old") == 0) {				server->flags |= PEER_NOPROXY;				server->flags |= PEER_OLDACCT;			}			else if (strcmp(arg, "secure") == 0) {				server->flags |= PEER_ADMINOK;			}			else if (strcmp(arg, "ipass") == 0) {				server->flags |= PEER_IPASS;			} else {				log_err("unknown argument \"%s\" on line %d in proxy file ignored\n", arg, lineno);			}		}

⌨️ 快捷键说明

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