www.pudn.com > RadiusSrv.rar > RdiusSrv.cpp, change:2003-10-28,size:40603b


#include <errno.h>   //EINTR 
#include <Winsock2.h> 
#include "RadiusSrv.h" 
#include "Radiusd.h" 
#include "libradius.h" 
#include "radius.h" 
#include "md5.h" 
#include "..\common\log.h" 
#include "..\common\profile.h" 
#include "..\database\IPPhoneDB.h" 
#include "..\function\xstring.h" 
 
int rad_process(REQUEST *request, int dospawn); 
int rad_respond(REQUEST *request, RAD_REQUEST_FUNP fun); 
static void rad_reject(REQUEST *request); 
static void rfc_clean(RADIUS_PACKET *packet); 
 
static SOCKET authfd;               //socket句柄 
static SOCKET  proxyfd; 
static SOCKET   acctfd; 
 
static int request_num_counter = 0; /* per-request unique ID */ 
static int spawn_flag = TRUE; 
 
//xinbao 
IPPhoneDB IPPhoneDBLink;   //数据库连接 
 
static struct _GK_OPTIONS _ops;  //配置文件信息     
 
StringArray iPrefixArray;//国际前缀 
StringArray oPrefixArray;//国内前缀 
 
#define GK_PORT_DEFAULT 7000 
 
typedef struct radius_packet_t { 
  uint8_t	code; 
  uint8_t	id; 
  uint8_t	length[2]; 
  uint8_t	vector[AUTH_VECTOR_LEN]; 
  uint8_t	data[1]; 
} radius_packet_t; 
 
static const char *packet_codes[] = { 
  "", 
  "Access-Request", 
  "Access-Accept", 
  "Access-Reject", 
  "Accounting-Request", 
  "Accounting-Response", 
  "Accounting-Status", 
  "Password-Request", 
  "Password-Accept", 
  "Password-Reject", 
  "Accounting-Message", 
  "Access-Challenge", 
  "Status-Server", 
  "Status-Client", 
  "14", 
  "15", 
  "16", 
  "17", 
  "18", 
  "19", 
  "20", 
  "Resource-Free-Request", 
  "Resource-Free-Response", 
  "Resource-Query-Request", 
  "Resource-Query-Response", 
  "Alternate-Resource-Reclaim-Request", 
  "NAS-Reboot-Request", 
  "NAS-Reboot-Response", 
  "28", 
  "Next-Passcode", 
  "New-Pin", 
  "Terminate-Session", 
  "Password-Expired", 
  "Event-Request", 
  "Event-Response", 
  "35", 
  "36", 
  "37", 
  "38", 
  "39", 
  "Disconnect-Request", 
  "Disconnect-ACK", 
  "Disconnect-NAK", 
  "CoF-Request", 
  "CoF-ACK", 
  "CoF-NAK", 
  "46", 
  "47", 
  "48", 
  "49", 
  "IP-Address-Allocate", 
  "IP-Address-Release" 
}; 
//////////////////////////////////////////////////////////////// 
void handlePacketThread() 
{ 
	unsigned int max_fd; 
	int status; 
	struct timeval *tv = NULL; 
	int i; 
	int fd = 0; 
	int sig_hup_block = FALSE; 
	RADIUS_PACKET *packet; 
	REQUEST *request; 
	unsigned char buffer[4096]; 
 
	while(1) 
	{ 
		fd_set readfds; 
		 
		FD_ZERO(&readfds); 
		max_fd = 0; 
		if (authfd >= 0) 
		{ 
			FD_SET(authfd, &readfds); 
			if (authfd > max_fd)  
				max_fd = authfd; 
		} 
		 
		status = select(max_fd + 1, &readfds, NULL, NULL, tv); 
		 
		if (status == -1) { 
		/* 
		*	On interrupts, we clean up the request 
		*	list.  We then continue with the loop, 
		*	so that if we're supposed to exit, 
		*	then the code at the start of the loop 
		*	catches that, and exits. 
			*/ 
			if (errno == EINTR ) {// 
				//	tv = rad_clean_list(time(NULL)); 
				continue; 
			} 
			LOG(1) ("Unexpected error in select(): %s", strerror(errno)); 
			return; 
		} 
		 
		/* 
		*  Loop over the open socket FD's, reading any data. 
		*/ 
		for (i = 0; i < 3; i++) { 
			 
			if (i == 0) fd = authfd; 
			//			if (i == 1) fd = acctfd; 
			if (i == 2) fd = proxyfd; 
			if (fd < 0 || !FD_ISSET(fd, &readfds)) 
				continue; 
				/* 
				*  Receive the packet. 
			*/ 
			if (sig_hup_block != FALSE) { 
				continue; 
			} 
			 
			if (FD_ISSET(authfd, &readfds)) 
				packet = rad_recv(fd); 
			 
			if (packet == NULL) { 
				LOG(3) ("packet error"); 
				continue; 
			} 
			 
			/* 
			*  Check if we know this client for 
			*  authfd and acctfd.   
			*/ 
			 
			if(_ops.clientIP!=0) 
			{ 
				if (packet->src_ipaddr != _ops.clientIP) 
				{ 
					LOG(3) ("Ignoring request from unknown client %s:%d", 
						ip_ntoa((char *)buffer, packet->src_ipaddr), 
						packet->src_port); 
					rad_free(&packet); 
					continue; 
				} 
			}				 
			 
			/* 
			*  Do yet another check, to see if the 
			*  packet code is valid.  We only understand 
			*  a few, so stripping off obviously invalid 
			*  packets here will make our life easier. 
			*/ 
			if (packet->code > PW_STATUS_SERVER) { 
				LOG(3) ("Ignoring request from client %s:%d with unknown code %d", 
					    ip_ntoa((char *)buffer, packet->src_ipaddr), 
					packet->src_port, packet->code); 
				rad_free(&packet); 
				continue; 
			} 
			 
			request = (auth_req *)rad_malloc(sizeof(REQUEST)); 
			memset(request, 0, sizeof(REQUEST)); 
#ifndef NDEBUG 
			request->magic = REQUEST_MAGIC; 
#endif 
			request->packet = packet; 
			request->proxy = NULL; 
			request->reply = NULL; 
			request->proxy_reply = NULL; 
			request->config_items = NULL; 
			request->username = NULL; 
			request->password = NULL; 
			request->timestamp = time(NULL); 
			request->number = request_num_counter++; 
 			request->container = NULL; 
			request->options = RAD_REQUEST_OPTION_NONE; 
			strNcpy(request->secret, _ops.sharedSecret.c_str(), sizeof(request->secret)); 
			rad_process(request, spawn_flag); 
		} /* loop over authfd, acctfd, proxyfd */ 
		 
		  /* 
		  *  After processing all new requests, 
		  *  check if we've got to delete old requests 
		  *  from the request list. 
		*/ 
		//	tv = rad_clean_list(time(NULL)); 
		 
	} /* loop forever */ 
//	return 1; 
} 
 
/* 
 *  Process supported requests: 
 * 
 *  	PW_AUTHENTICATION_REQUEST - Authentication request from 
 *  	 a client network access server. 
 * 
 *  	PW_ACCOUNTING_REQUEST - Accounting request from 
 *  	 a client network access server. 
 * 
 *  	PW_AUTHENTICATION_ACK 
 *  	PW_ACCESS_CHALLENGE 
 *  	PW_AUTHENTICATION_REJECT 
 *  	PW_ACCOUNTING_RESPONSE - Reply from a remote Radius server. 
 *  	 Relay reply back to original NAS. 
 * 
 */ 
int rad_process(REQUEST *request, int dospawn) 
{ 
	RAD_REQUEST_FUNP fun; 
 
	fun = NULL; 
 
//	//(request->magic == REQUEST_MAGIC); 
 
	switch(request->packet->code) { 
		default: 
			printf( "Unknown packet type %d from client %s:%d " 
					"- ID %d : IGNORED", request->packet->code,  
					client_name(request->packet->src_ipaddr), request->packet->src_port, 
					request->packet->id);  
			request_free(&request); 
			return -1; 
			break; 
 
		case PW_AUTHENTICATION_REQUEST: 
			/* 
			 *  Check for requests sent to the wrong port, 
			 *  and ignore them, if so. 
			 */ 
			if (request->packet->sockfd != authfd) { 
				printf( "Authentication-Request sent to a non-authentication port from " 
					"client %s:%d - ID %d : IGNORED", 
					client_name(request->packet->src_ipaddr), request->packet->src_port, 
				request->packet->id); 
				request_free(&request); 
				return -1; 
			} 
			fun = rad_authenticate; 
			break; 
 
		case PW_ACCOUNTING_REQUEST: 
			/* 
			 *  Check for requests sent to the wrong port, 
			 *  and ignore them, if so. 
			 */ 
			if (request->packet->sockfd != acctfd) { 
				printf( "Accounting-Request packet sent to a non-accounting port from " 
					"client %s:%d - ID %d : IGNORED", 
					client_name(request->packet->src_ipaddr), request->packet->src_port, 
					request->packet->id); 
				request_free(&request); 
				return -1; 
			} 
		//	fun = rad_accounting; 
			break; 
 
		case PW_AUTHENTICATION_ACK: 
		case PW_ACCESS_CHALLENGE: 
		case PW_AUTHENTICATION_REJECT: 
		case PW_ACCOUNTING_RESPONSE: 
			/* 
			 *  Replies NOT sent to the proxy port get an 
			 *  error message logged, and the packet is 
			 *  dropped. 
			 */ 
			if (request->packet->sockfd != proxyfd) { 
				printf( "Reply packet code %d sent to a non-proxy reply port from " 
						"client %s:%d - ID %d : IGNORED", request->packet->code, 
						client_name(request->packet->src_ipaddr), request->packet->src_port, 
						request->packet->id); 
				request_free(&request); 
				return -1; 
			} 
			if (request->packet->code != PW_ACCOUNTING_RESPONSE) { 
				//fun = rad_authenticate; 
			} else { 
			//	fun = rad_accounting; 
			} 
			break; 
 
		case PW_STATUS_SERVER: 
/*			if (!mainconfig.status_server) { 
//				DEBUG("WARNING: Ignoring Status-Server request due to security configuration"); 
				request_free(&request); 
				return -1; 
			} else { 
				fun = rad_status_server; 
			}*/ 
			break; 
 
		case PW_PASSWORD_REQUEST: 
			/* 
			 *  We don't support this anymore. 
			 */ 
			printf( "Deprecated password change request from client %s:%d - ID %d : IGNORED", 
					client_name(request->packet->src_ipaddr), request->packet->src_port, 
					request->packet->id); 
			request_free(&request); 
			return -1; 
			break; 
	} 
 
	/* 
	 *  Check for a duplicate, or error. 
	 *  Throw away the the request if so. 
	 */ 
//	request = rad_check_list(request); 
	if (request == NULL) { 
		return 0; 
	} 
	 
	//(request->magic == REQUEST_MAGIC); 
 
	/* 
	 *  This next assertion catches a race condition in the 
	 *  server.  If it core dumps here, then it means that 
	 *  the code WOULD HAVE core dumped elsewhere, but in 
	 *  some random, unpredictable location. 
	 * 
	 *  Having the assert here means that we can catch the problem 
	 *  in a well-known manner, until such time as we fix it. 
	 */ 
//	//(request->child_pid == NO_SUCH_CHILD_PID); 
 
	/* 
	 *  The request passes many of our sanity checks.  From 
	 *  here on in, if anything goes wrong, we send a reject 
	 *  message, instead of dropping the packet. 
	 * 
	 *  Build the reply template from the request template. 
	 */ 
	if (!request->reply) { 
		if ((request->reply = rad_alloc(0)) == NULL) { 
			printf( "No memory"); 
			exit(1); 
		} 
		request->reply->sockfd = request->packet->sockfd; 
		request->reply->dst_ipaddr = request->packet->src_ipaddr; 
		request->reply->dst_port = request->packet->src_port; 
		request->reply->id = request->packet->id; 
		request->reply->code = 0; /* UNKNOWN code */ 
		memcpy(request->reply->vector, request->packet->vector, sizeof(request->reply->vector)); 
		request->reply->vps = NULL; 
		request->reply->data = NULL; 
		request->reply->data_len = 0; 
	} 
 
	/* 
	 *	If we don't have threads, then the child CANNOT save 
	 *	it's state in the memory used by the main server core. 
	 * 
	 *	That is, until someone goes and implements shared 
	 *	memory across processes... 
	 */ 
#ifdef HAVE_PTHREAD_H 
	/* 
	 *  If we're spawning a child thread, let it do all of 
	 *  the work of handling a request, and exit. 
	 */ 
	if (dospawn == TRUE) { 
		/* 
		 *  Maybe the spawn failed.  If so, then we 
		 *  trivially reject the request (because we can't 
		 *  handle it), and return. 
		 */ 
		if (rad_spawn_child(request, fun) < 0) { 
			rad_reject(request); 
			request->finished = TRUE; 
		} 
		return 0; 
	} 
#endif 
 
	rad_respond(request, fun); 
	return 0; 
} 
 
/* 
 *  Respond to a request packet. 
 * 
 *  Maybe we reply, maybe we don't. 
 *  Maybe we proxy the request to another server, or else maybe 
 *  we replicate it to another server. 
 */ 
int rad_respond(REQUEST *request, RAD_REQUEST_FUNP fun) 
{ 
	RADIUS_PACKET *packet, *original; 
	const char *secret; 
	int finished = FALSE; 
	int reprocess = 0; 
	 
	/* 
	 *  Put the decoded packet into it's proper place. 
	 */ 
	if (request->proxy_reply != NULL) { 
		packet = request->proxy_reply; 
		secret = request->proxysecret; 
		original = request->proxy; 
	} else { 
		packet = request->packet; 
		secret = request->secret; 
		original = NULL; 
	} 
 
	//rad_assert(request->magic == REQUEST_MAGIC); 
	 
	/* 
	 *  Decode the packet, verifying it's signature, 
	 *  and parsing the attributes into structures. 
	 * 
	 *  Note that we do this CPU-intensive work in 
	 *  a child thread, not the master.  This helps to 
	 *  spread the load a little bit. 
	 * 
	 *  Internal requests (ones that never go on the 
	 *  wire) have ->data==NULL (data is the wire 
	 *  format) and don't need to be "decoded" 
	 */ 
	if (packet->data && rad_decode(packet, original, secret) != 0) { 
	//	printf("%s", librad_errstr); 
		rad_reject(request); 
		goto finished_request; 
	} 
	 
	/* 
	 *  For proxy replies, remove non-allowed 
	 *  attributes from the list of VP's. 
	 */ 
/*	if (request->proxy) { 
            int rcode; 
            rcode = proxy_receive(request); 
            switch (rcode) { 
                default:  /* Don't Do Anything */ 
             //       break; 
            //    case RLM_MODULE_FAIL: 
                    /* on error just continue with next request */ 
              //      goto next_request; 
             //   case RLM_MODULE_HANDLED: 
                    /* if this was a replicated request, mark it as 
                     * finished first, because it was postponed 
                     */ 
               //     goto finished_request; 
         /*   } 
 
	} else */{ 
		/* 
		 *	This is the initial incoming request which 
		 *	we're processing. 
		 * 
		 *	Some requests do NOT get cached, as they 
		 *	CANNOT possibly have duplicates.  Set the 
		 *	magic option here. 
		 * 
		 *	Status-Server messages are easy to generate, 
		 *	so we toss them as soon as we see a reply. 
		 * 
		 *	Accounting-Request packets WITHOUT an 
		 *	Acct-Delay-Time attribute are NEVER 
		 *	duplicated, as RFC 2866 Section 4.1 says that 
		 *	the Acct-Delay-Time MUST be updated when the 
		 *	packet is re-sent, which means the packet 
		 *	changes, so it MUST have a new identifier and 
		 *	Request Authenticator.  */ 
		if ((request->packet->code == PW_STATUS_SERVER) || 
		    ((request->packet->code == PW_ACCOUNTING_REQUEST) && 
		     (pairfind(request->packet->vps, PW_ACCT_DELAY_TIME) == NULL))) { 
			request->options |= RAD_REQUEST_OPTION_DONT_CACHE; 
		} 
	} 
	 
	/* 
	 *  We should have a User-Name attribute now. 
	 */ 
	if (request->username == NULL) { 
		request->username = pairfind(request->packet->vps, 
				PW_USER_NAME); 
	} 
 
	/* 
	 *  We have the semaphore, and have decoded the packet. 
	 *  Let's process the request. 
	 */ 
//	//rad_assert(request->magic == REQUEST_MAGIC); 
 
	/*  
	 *  FIXME:  All this lowercase/nospace junk will be moved 
	 *  into a module after module failover is fully in place 
	 * 
	 *  See if we have to lower user/pass before processing 
	 */ 
/*	if(strcmp(mainconfig.do_lower_user, "before") == 0) 
		rad_lowerpair(request, request->username); 
	if(strcmp(mainconfig.do_lower_pass, "before") == 0) 
		rad_lowerpair(request, 
			      pairfind(request->packet->vps, PW_PASSWORD)); 
 
	if(strcmp(mainconfig.do_nospace_user, "before") == 0) 
		rad_rmspace_pair(request, request->username); 
	if(strcmp(mainconfig.do_nospace_pass, "before") == 0) 
		rad_rmspace_pair(request, 
				 pairfind(request->packet->vps, PW_PASSWORD)); 
*/ 
	(*fun)(request); 
 
	/* 
	 *	If the request took too long to process, don't do 
	 *	anything else. 
	 */ 
	if (request->options & RAD_REQUEST_OPTION_REJECTED) { 
		finished = TRUE; 
		goto postpone_request; 
	} 
 
	/* 
	 *  Reprocess if we rejected last time 
	 */ 
	if ((fun == rad_authenticate) && 
	    (request->reply->code == PW_AUTHENTICATION_REJECT)) { 
	  /* See if we have to lower user/pass after processing */ 
/*	  if (strcmp(mainconfig.do_lower_user, "after") == 0) { 
		  rad_lowerpair(request, request->username); 
		  reprocess = 1; 
	  } 
	  if (strcmp(mainconfig.do_lower_pass, "after") == 0) { 
		rad_lowerpair(request, 
			      pairfind(request->packet->vps, PW_PASSWORD)); 
		reprocess = 1; 
	  } 
	  if (strcmp(mainconfig.do_nospace_user, "after") == 0) { 
		  rad_rmspace_pair(request, request->username); 
		  reprocess = 1; 
	  } 
	  if (strcmp(mainconfig.do_nospace_pass, "after") == 0) { 
		  rad_rmspace_pair(request, 
				   pairfind(request->packet->vps, PW_PASSWORD)); 
 
		  reprocess = 1; 
	  } 
*/	   
	  /* 
	   *	If we're re-processing the request, re-set it. 
	   */ 
	  if (reprocess) { 
		  pairfree(&request->config_items); 
		  pairfree(&request->reply->vps); 
		  request->reply->code = 0; 
		  (*fun)(request); 
	  } 
	} 
	 
	/* 
	 *  If we don't already have a proxy packet for this request, 
	 *  we MIGHT have to go proxy it. 
	 * 
	 *  Status-Server requests NEVER get proxied. 
	 */ 
/*(	if (mainconfig.proxy_requests) { 
		if ((request->proxy == NULL) && 
		    (request->packet->code != PW_STATUS_SERVER)) { 
			int rcode; 
 
			/* 
			 *  Try to proxy this request. 
			 */ 
		//	rcode = proxy_send(request); 
 
/*			switch (rcode) { 
			default: 
				break; 
				 
			/* 
			 *  There was an error trying to proxy the request. 
			 *  Drop it on the floor. 
			 */ 
/*				case RLM_MODULE_FAIL: 
			printf("Error trying to proxy request %d: Rejecting it", request->number); 
				rad_reject(request); 
				goto finished_request; 
				break; 
 
			/* 
			 *  The pre-proxy module has decided to reject 
			 *  the request.  Do so. 
			 */ 
	/*			case RLM_MODULE_REJECT: 
				printf("Request %d rejected in proxy_send.", request->number); 
				rad_reject(request); 
				goto finished_request; 
				break; 
				 
			/* 
			 *  If the proxy code has handled the request, 
			 *  then postpone more processing, until we get 
			 *  the reply packet from the home server. 
			 */ 
	/*			case RLM_MODULE_HANDLED: 
				/* 
				 *  rad_send?? 
				 */ 
	/*				goto postpone_request; 
				break; 
			} 
 
			/* 
			 *  Else rcode==RLM_MODULE_NOOP 
			 *  and the proxy code didn't do anything, so 
			 *  we continue handling the request here. 
			 */ 
			/*} 
	} else */if ((request->packet->code == PW_AUTHENTICATION_REQUEST) && 
		   (request->reply->code == 0)) { 
		/* 
		 *  We're not configured to reply to the packet, 
		 *  and we're not proxying, so the DEFAULT behaviour 
		 *  is to REJECT the user. 
		 */ 
		LOG(5) ("rejected user %s", request->username->strvalue); 
		rad_reject(request); 
		goto finished_request; 
	} 
 
	/* 
	 *  If we have a reply to send, copy the Proxy-State 
	 *  attributes from the request to the tail of the reply, 
	 *  and send the packet. 
/	 */ 
//	//rad_assert(request->magic == REQUEST_MAGIC); 
	if (request->reply->code != 0) { 
		VALUE_PAIR *vp = NULL; 
 
		/* 
		 *  Perform RFC limitations on outgoing replies. 
		 */ 
		rfc_clean(request->reply); 
 
		/* 
		 *  Need to copy Proxy-State from request->packet->vps 
		 */ 
		vp = paircopy2(request->packet->vps, PW_PROXY_STATE); 
		if (vp != NULL)  
			pairadd(&(request->reply->vps), vp); 
 
		/* 
		 *  If the request isn't an authentication reject, OR 
		 *  it's a reject, but the reject_delay is zero, then 
		 *  send it immediately. 
		 * 
		 *  Otherwise, delay the authentication reject to shut 
		 *  up DoS attacks. 
		 */ 
		if ((request->reply->code != PW_AUTHENTICATION_REJECT) /* || 
		   (mainconfig.reject_delay == 0)*/) { 
			rad_send(request->reply, request->packet, 
				 request->secret); 
		} else { 
	//		printf("Delaying request %d for %d seconds", 
	//		       request->number, mainconfig.reject_delay); 
			request->options |= RAD_REQUEST_OPTION_DELAYED_REJECT; 
		} 
	} 
 
	/* 
	 *  We're done processing the request, set the 
	 *  request to be finished, clean up as necessary, 
	 *  and forget about the request. 
	 */ 
 
finished_request: 
 
	/* 
	 *  We're done handling the request.  Free up the linked 
	 *  lists of value pairs.  This might take a long time, 
	 *  so it's more efficient to do it in a child thread, 
	 *  instead of in the main handler when it eventually 
	 *  gets around to deleting the request. 
	 * 
	 *  Also, no one should be using these items after the 
	 *  request is finished, and the reply is sent.  Cleaning 
	 *  them up here ensures that they're not being used again. 
	 * 
	 *  Hmm... cleaning them up in the child thread also seems 
	 *  to make the server run more efficiently! 
	 * 
	 *  If we've delayed the REJECT, then do NOT clean up the request, 
	 *  as we haven't created the REJECT message yet. 
	 */ 
	if ((request->options & RAD_REQUEST_OPTION_DELAYED_REJECT) == 0) { 
		if (request->packet) { 
			pairfree(&request->packet->vps); 
			request->username = NULL; 
			request->password = NULL; 
		} 
 
		/* 
		 *  If we've sent a reply to the NAS, then this request is 
		 *  pretty much finished, and we have no more need for any 
		 *  of the value-pair's in it, including the proxy stuff. 
		 */ 
		if (request->reply->code != 0) { 
			pairfree(&request->reply->vps); 
		} 
	} 
 
	pairfree(&request->config_items); 
	if (request->proxy) { 
		pairfree(&request->proxy->vps); 
	} 
	if (request->proxy_reply) { 
		pairfree(&request->proxy_reply->vps); 
	} 
 
//	printf("Finished request %d", request->number); 
	finished = TRUE; 
 
	/* 
	 *  Go to the next request, without marking 
	 *  the current one as finished. 
	 * 
	 *  Hmm... this may not be the brightest thing to do. 
	 */ 
//xt_request: 
//rintf("Going to the next request"); 
 
postpone_request: 
#if HAVE_PTHREAD_H 
	/* 
	 *  We are finished with the child thread.  The thread is detached, 
	 *  so that when it exits, there's nothing more for the server 
	 *  to do. 
	 * 
	 *  If we're running with thread pools, then this frees up the 
	 *  thread in the pool for another request. 
	 */ 
	request->child_pid = NO_SUCH_CHILD_PID; 
#endif 
	request->finished = finished; /* do as the LAST thing before exiting */ 
	return 0; 
} 
 
/* 
 *  Reject a request, by sending a trivial reply packet. 
 */ 
static void rad_reject(REQUEST *request) 
{ 
	VALUE_PAIR *vps; 
 
	/* 
	 *	Already rejected.  Don't do anything. 
	 */ 
	if (request->options & RAD_REQUEST_OPTION_REJECTED) { 
		return; 
	} 
	 
//	printf("Server rejecting request %d.", request->number); 
	switch (request->packet->code) { 
		/* 
		 *  Accounting requests, etc. get dropped on the floor. 
		 */ 
		default: 
		case PW_ACCOUNTING_REQUEST: 
		case PW_STATUS_SERVER: 
			break; 
 
		/* 
		 *  Authentication requests get their Proxy-State 
		 *  attributes copied over, and an otherwise blank 
		 *  reject message sent. 
		 */ 
		case PW_AUTHENTICATION_REQUEST: 
			request->reply->code = PW_AUTHENTICATION_REJECT;  
 
			/* 
			 *  Perform RFC limitations on outgoing replies. 
			 */ 
			rfc_clean(request->reply); 
 
			/* 
			 *  Need to copy Proxy-State from request->packet->vps 
			 */ 
			vps = paircopy2(request->packet->vps, PW_PROXY_STATE); 
			if (vps != NULL) 
				pairadd(&(request->reply->vps), vps); 
			break; 
	} 
	 
	/* 
	 *  If a reply exists, send it. 
	 */ 
	if (request->reply->code != 0) { 
		/* 
		 *	If we're not delaying authentication rejects, 
		 *	then send the response immediately.  Otherwise, 
		 *	mark the request as delayed, and do NOT send a 
		 *	response. 
		 */ 
	///*	if (mainconfig.reject_delay == 0) { 
			rad_send(request->reply, request->packet, 
				 request->secret); 
	} 
 
	/* 
	 *	Remember that it was rejected. 
	 */ 
	request->options |= RAD_REQUEST_OPTION_REJECTED; 
} 
 
/* 
 *  Perform any RFC specified cleaning of outgoing replies 
 */ 
static void rfc_clean(RADIUS_PACKET *packet) 
{ 
	VALUE_PAIR *vps = NULL; 
 
	switch (packet->code) { 
		/* 
		 *	In the default case, we just move all of the 
		 *	attributes over. 
		 */ 
	default: 
		vps = packet->vps; 
		packet->vps = NULL; 
		break; 
		 
		/* 
		 *	Accounting responses can only contain 
		 *	Proxy-State and VSA's.  Note that we do NOT 
		 *	move the Proxy-State attributes over, as the 
		 *	Proxy-State attributes in this packet are NOT 
		 *	the right ones to use.  The reply function 
		 *	takes care of copying those attributes from 
		 *	the original request, which ARE the right ones 
		 *	to use. 
		 */ 
	case PW_ACCOUNTING_RESPONSE: 
		pairmove2(&vps, &(packet->vps), PW_VENDOR_SPECIFIC); 
		break; 
 
		/* 
		 *	Authentication REJECT's can have only 
		 *	EAP-Message, Message-Authenticator 
		 *	Reply-Message and Proxy-State. 
		 * 
		 *	We delete everything other than these. 
		 *	Proxy-State is added below, just before the 
		 *	reply is sent. 
		 */ 
	case PW_AUTHENTICATION_REJECT: 
		pairmove2(&vps, &(packet->vps), PW_EAP_MESSAGE); 
		pairmove2(&vps, &(packet->vps), PW_MESSAGE_AUTHENTICATOR); 
		pairmove2(&vps, &(packet->vps), PW_REPLY_MESSAGE); 
		pairmove2(&vps, &(packet->vps), PW_VENDOR_SPECIFIC); 
		break; 
	} 
 
	/* 
	 *	Move the newly cleaned attributes over. 
	 */ 
	pairfree(&packet->vps); 
	packet->vps = vps; 
 
	/* 
	 *	FIXME: Perform other, more generic sanity checks. 
	 */ 
} 
 
/* 
 *	Reply to the request.  Also attach 
 *	reply attribute value pairs and any user message provided. 
 */ 
 
int rad_send(RADIUS_PACKET *packet, const RADIUS_PACKET *original, 
	     const char *secret) 
{ 
	VALUE_PAIR		*reply; 
	struct	sockaddr_in	saremote; 
	struct	sockaddr_in	*sa; 
	const char		*what; 
//	uint8_t			ip_buffer[16]; 
 
	if ((packet->code > 0) && (packet->code < 52)) { 
		what = packet_codes[packet->code]; 
	} else { 
		what = "Reply"; 
	} 
 
	/* 
	 *  First time through, allocate room for the packet 
	 */ 
	if (!packet->data) { 
		  radius_packet_t	*hdr; 
		  uint32_t		lvalue; 
		  uint8_t		*ptr, *length_ptr, *vsa_length_ptr; 
		  uint8_t		digest[16]; 
		  int			secretlen; 
		  int			vendorcode, vendorpec; 
		  u_short		total_length; 
		  int			len, allowed; 
		  int			msg_auth_offset = 0; 
 
		  /* 
		   *	For simplicity in the following logic, we allow 
		   *	the attributes to "overflow" the 4k maximum 
		   *	RADIUS packet size, by one attribute. 
		   */ 
		  uint8_t		data[MAX_PACKET_LEN + 256]; 
		   
		  /* 
		   *	Use memory on the stack, until we know how 
		   *	large the packet will be. 
		   */ 
		  hdr = (radius_packet_t *) data; 
 
		  /* 
		   *	Build standard header 
		   */ 
		  hdr->code = packet->code; 
		  hdr->id = packet->id; 
		  if ((packet->code == PW_ACCOUNTING_REQUEST) || 
		      (packet->code == PW_DISCONNECT_REQUEST)) { 
			  memset(hdr->vector, 0, AUTH_VECTOR_LEN); 
		  } else { 
			  memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN); 
		  } 
 
//		  printf("Sending %s of id %d to %s:%d\n", 
	//		what, packet->id, 
	//		ip_ntoa((char *)ip_buffer, packet->dst_ipaddr), 
	//		packet->dst_port); 
		   
		  total_length = AUTH_HDR_LEN; 
		   
		  /* 
		   *	Load up the configuration values for the user 
		   */ 
		  ptr = hdr->data; 
		  vendorcode = 0; 
		  vendorpec = 0; 
		  vsa_length_ptr = NULL; 
 
		  for (reply = packet->vps; reply; reply = reply->next) { 
			  /* 
			   *	Ignore non-wire attributes 
			   */ 
			  if ((VENDOR(reply->attribute) == 0) && 
			      ((reply->attribute & 0xFFFF) > 0xff)) { 
				  continue; 
			  } 
 
			  /* 
			   *	Check that the packet is no more than 
			   *	4k in size, AFTER over-flowing the 4k 
			   *	boundary.  Note that the 'data' 
			   *	buffer, above, is one attribute longer 
			   *	than necessary, in order to permit 
			   *	this overflow. 
			   */ 
			  if (total_length > MAX_PACKET_LEN) { 
				  printf("ERROR: Too many attributes for packet, result is larger than RFC maximum of 4k"); 
				  return -1; 
			  } 
 
			  /* 
			   *	Do stuff for Message-Authenticator 
			   */ 
			  if (reply->attribute == PW_MESSAGE_AUTHENTICATOR) { 
				  /* 
				   *  Set it to zero! 
				   */ 
				  reply->length = AUTH_VECTOR_LEN; 
				  memset(reply->strvalue, 0, AUTH_VECTOR_LEN); 
				  msg_auth_offset = total_length; 
			  } 
 
			  /* 
			   *	Print out ONLY the attributes which 
			   *	we're sending over the wire, and print 
			   *	them out BEFORE they're encrypted. 
			   */ 
//			  debug_pair(reply); 
 
			  /* 
			   *	We have a different vendor.  Re-set 
			   *	the vendor codes. 
			   */ 
			  if (vendorcode != VENDOR(reply->attribute)) { 
				  vendorcode = 0; 
				  vendorpec = 0; 
				  vsa_length_ptr = NULL; 
			  } 
 
			  /* 
			   *	If the Vendor-Specific attribute is getting 
			   *	full, then create a new VSA attribute 
			   * 
			   *	FIXME: Multiple VSA's per Vendor-Specific 
			   *	SHOULD be configurable.  When that's done, 
			   *	the (1), below, can be changed to point to 
			   *	a configuration variable which is set TRUE 
			   *	if the NAS cannot understand multiple VSA's 
			   *	per Vendor-Specific 
			   */ 
			  if ((1) || /* ALWAYS create a new Vendor-Specific */ 
			      (vsa_length_ptr && 
			       (reply->length + *vsa_length_ptr) >= MAX_STRING_LEN)) { 
				  vendorcode = 0; 
				  vendorpec = 0; 
				  vsa_length_ptr = NULL; 
			  } 
 
			  /* 
			   *	Maybe we have the start of a set of 
			   *	(possibly many) VSA attributes from 
			   *	one vendor.  Set a global VSA wrapper 
			   */ 
			  if ((vendorcode == 0) && 
			      ((vendorcode = VENDOR(reply->attribute)) != 0)) { 
				  vendorpec  = dict_vendorpec(vendorcode); 
				   
				  /* 
				   *	This is a potentially bad error... 
				   *	we can't find the vendor ID! 
				   */ 
				  if (vendorpec == 0) { 
					  /* FIXME: log an error */ 
					  continue; 
				  } 
 
				  /* 
				   *	Build a VSA header. 
				   */ 
				  *ptr++ = PW_VENDOR_SPECIFIC; 
				  vsa_length_ptr = ptr; 
				  *ptr++ = 6; 
				  lvalue = htonl(vendorpec); 
				  memcpy(ptr, &lvalue, 4); 
				  ptr += 4; 
				  total_length += 6; 
			  } 
 
			  if (vendorpec == VENDORPEC_USR) { 
				  lvalue = htonl(reply->attribute & 0xFFFF); 
				  memcpy(ptr, &lvalue, 4); 
 
				  length_ptr = vsa_length_ptr; 
 
				  total_length += 4; 
				  *length_ptr  += 4; 
				  ptr          += 4; 
 
				  /* 
				   *	Each USR attribute gets it's own 
				   *	VSA wrapper, so we re-set the 
				   *	vendor specific information. 
				   */ 
				  vendorcode = 0; 
				  vendorpec = 0; 
				  vsa_length_ptr = NULL; 
 
			  } else { 
				  /* 
				   *	All other attributes are as 
				   *	per the RFC spec. 
				   */ 
 
				  *ptr++ = (reply->attribute & 0xFF); 
				  length_ptr = ptr; 
				  if (vsa_length_ptr) *vsa_length_ptr += 2; 
				  *ptr++ = 2; 
				  total_length += 2; 
			  } 
			   
			  switch(reply->type) { 
				   
				  /* 
				   *	Ascend binary attributes are 
				   *	stored internally in binary form. 
				   */ 
			  case PW_TYPE_ABINARY: 
			  case PW_TYPE_STRING: 
			  case PW_TYPE_OCTETS: 
				  /* 
				   *  FIXME: HACK for non-updated dictionaries. 
				   *  REMOVE in a future release. 
				   */ 
				  if ((strcmp(reply->name, "Ascend-Send-Secret") == 0) || 
				      (strcmp(reply->name, "Ascend-Receive-Secret") == 0)) { 
					  reply->flags.encrypt = FLAG_ENCRYPT_ASCEND_SECRET; 
				  } 
				  if (reply->attribute == PW_USER_PASSWORD) { 
					  reply->flags.encrypt = FLAG_ENCRYPT_USER_PASSWORD; 
				  } 
 
				  /* 
				   *  Encrypt the various password styles 
				   */ 
				  switch (reply->flags.encrypt) { 
				  default: 
					  break; 
 
				  case FLAG_ENCRYPT_USER_PASSWORD: 
				    rad_pwencode((char *)reply->strvalue, 
						 &(reply->length), 
						 (const char *)secret, 
						 (const char *)packet->vector); 
				    break; 
 
				  case FLAG_ENCRYPT_TUNNEL_PASSWORD: 
				/*	  rad_tunnel_pwencode(reply->strvalue, 
							      &(reply->length), 
							      secret, 
							      packet->vector);*/ 
					  break; 
 
 
				  case FLAG_ENCRYPT_ASCEND_SECRET:; 
				/*	  make_secret(digest, packet->vector, 
						      secret, reply->strvalue); 
					  memcpy(reply->strvalue, digest, AUTH_VECTOR_LEN ); 
					  reply->length = AUTH_VECTOR_LEN;*/ 
				  } /* switch over encryption flags */ 
 
				  len = reply->length; 
 
				  /* 
				   *    Set the TAG at the beginning 
				   *    of the string if tagged.  If 
				   *    tag value is not valid for 
				   *    tagged attribute, make it 0x00 
				   *    per RFC 2868.  -cparker 
				   */ 
				  if (reply->flags.has_tag) { 
					  if (TAG_VALID(reply->flags.tag)) { 
						  len++; 
						  *ptr++ = reply->flags.tag; 
 
					  } else if (reply->flags.encrypt == FLAG_ENCRYPT_TUNNEL_PASSWORD) { 
						  /* 
						   *  Tunnel passwords 
						   *  REQUIRE a tag, 
						   *  even if we don't 
						   *  have a valid 
						   *  tag. 
						   */ 
						  len++; 
						  *ptr++ = 0x00; 
					  } /* else don't write a tag */ 
				  } /* else the attribute doesn't have a tag */ 
				  
				  /* 
				   *	Ensure we don't go too far. 
				   *	The 'length' of the attribute 
				   *	may be 0..255, minus whatever 
				   *	octets are used in the attribute 
				   *	header. 
				   */ 
				  allowed = 255; 
				  if (vsa_length_ptr) { 
					  allowed -= *vsa_length_ptr; 
				  } else { 
					  allowed -= *length_ptr; 
				  } 
				   
				  if (len > allowed) { 
					  len = allowed; 
				  } 
				   
				  *length_ptr += len; 
				  if (vsa_length_ptr) *vsa_length_ptr += len; 
				  /* 
				   *  If we have tagged attributes we can't assume that 
				   *  len == reply->length.  Use reply->length for copying 
				   *  the string data into the packet.  Use len for the 
				   *  true length of the string+tags. 
				   */ 
				  memcpy(ptr, reply->strvalue, reply->length); 
				  ptr += reply->length; 
				  total_length += len; 
				  break; 
				   
			  case PW_TYPE_INTEGER: 
			  case PW_TYPE_IPADDR: 
				  *length_ptr += 4; 
				  if (vsa_length_ptr) *vsa_length_ptr += 4; 
 
				  if (reply->type == PW_TYPE_INTEGER ) { 
				          /*  If tagged, the tag becomes the MSB of the value */ 
				          if(reply->flags.has_tag) { 
					         /*  Tag must be ( 0x01 -> 0x1F ) OR 0x00  */ 
					         if(!TAG_VALID(reply->flags.tag)) { 
						       reply->flags.tag = 0x00; 
						 } 
					         lvalue = htonl((reply->lvalue & 0xffffff) | 
								((reply->flags.tag & 0xff) << 24)); 
					  } else { 
					         lvalue = htonl(reply->lvalue); 
					  } 
				  } else { 
					  /* 
					   *  IP address is already in 
					   *  network byte order. 
					   */ 
					  lvalue = reply->lvalue; 
				  } 
				  memcpy(ptr, &lvalue, 4); 
				  ptr += 4; 
				  total_length += 4; 
				  break; 
 
				  /* 
				   *  There are no tagged date attributes. 
				   */ 
			  case PW_TYPE_DATE: 
				  *length_ptr += 4; 
				  if (vsa_length_ptr) *vsa_length_ptr += 4; 
 
				  lvalue = htonl(reply->lvalue); 
				  memcpy(ptr, &lvalue, 4); 
				  ptr += 4; 
				  total_length += 4; 
				  break; 
			  default: 
				  break; 
			  } 
		  } /* done looping over all attributes */ 
 
		  /* 
		   *	Fill in the rest of the fields, and copy 
		   *	the data over from the local stack to 
		   *	the newly allocated memory. 
		   * 
		   *	Yes, all this 'memcpy' is slow, but it means 
		   *	that we only allocate the minimum amount of 
		   *	memory for a request. 
		   */ 
		  packet->data_len = total_length; 
		  packet->data = (uint8_t *) malloc(packet->data_len); 
		  if (!packet->data) { 
			  printf("Out of memory"); 
			  return -1; 
		  } 
		  memcpy(packet->data, data, packet->data_len); 
		  hdr = (radius_packet_t *) packet->data; 
 
		  total_length = htons(total_length); 
		  memcpy(hdr->length, &total_length, sizeof(u_short)); 
 
		  /* 
		   *	If this is not an authentication request, we 
		   *	need to calculate the md5 hash over the entire packet 
		   *	and put it in the vector. 
		   */ 
		  secretlen = strlen(secret); 
		  if (packet->code != PW_AUTHENTICATION_REQUEST && 
		      packet->code != PW_STATUS_SERVER) { 
		    MD5_CTX	context; 
		      /* 
		       *	Set the Message-Authenticator attribute, 
		       *	BEFORE setting the reply authentication vector 
		       *	for CHALLENGE, ACCEPT and REJECT. 
		       */ 
		      if (msg_auth_offset) { 
			      uint8_t calc_auth_vector[AUTH_VECTOR_LEN]; 
 
			      switch (packet->code) { 
			      default: 
				break; 
				 
			      case PW_AUTHENTICATION_ACK: 
			      case PW_AUTHENTICATION_REJECT: 
			      case PW_ACCESS_CHALLENGE: 
				if (original) { 
				  memcpy(hdr->vector, original->vector, AUTH_VECTOR_LEN); 
				} 
				break; 
			      } 
 
			      memset(packet->data + msg_auth_offset + 2, 0, 
				     AUTH_VECTOR_LEN); 
			      lrad_hmac_md5(packet->data, packet->data_len, 
					    (const unsigned char *)secret, secretlen, calc_auth_vector); 
			      memcpy(packet->data + msg_auth_offset + 2, 
				     calc_auth_vector, AUTH_VECTOR_LEN); 
			      memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN); 
		      } 
 
		      MD5Init(&context); 
		      MD5Update(&context, (const unsigned char*)packet->data, packet->data_len); 
		      MD5Update(&context, (const unsigned char*)secret, strlen(secret)); 
		      MD5Final(digest, &context); 
 
		      memcpy(hdr->vector, digest, AUTH_VECTOR_LEN); 
		      memcpy(packet->vector, digest, AUTH_VECTOR_LEN); 
		  } 
 
		  /* 
		   *	Set the Message-Authenticator attribute, 
		   *	AFTER setting the authentication vector 
		   *	only for ACCESS-REQUESTS 
		   */ 
		  else if (msg_auth_offset) { 
			  uint8_t calc_auth_vector[AUTH_VECTOR_LEN]; 
 
			  switch (packet->code) { 
			  default: 
			    break; 
			     
			  case PW_AUTHENTICATION_ACK: 
			  case PW_AUTHENTICATION_REJECT: 
			  case PW_ACCESS_CHALLENGE: 
			    if (original) { 
				    memcpy(hdr->vector, original->vector, 
					   AUTH_VECTOR_LEN); 
			    } 
			    break; 
			  } 
 
			  memset(packet->data + msg_auth_offset + 2, 
				 0, AUTH_VECTOR_LEN); 
			  lrad_hmac_md5(packet->data, packet->data_len, 
					(const unsigned char*)secret, secretlen, calc_auth_vector); 
			  memcpy(packet->data + msg_auth_offset + 2, 
				  calc_auth_vector, AUTH_VECTOR_LEN); 
			  memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN); 
		  } 
 
		  /* 
		   *	If packet->data points to data, then we print out 
		   *	the VP list again only for debugging. 
		   */ 
	}/* else if (librad_debug) { 
	  	printf("Re-sending %s of id %d to %s:%d\n", what, packet->id, 
		      ip_ntoa((char *)ip_buffer, packet->dst_ipaddr), 
		      packet->dst_port); 
		 
		for (reply = packet->vps; reply; reply = reply->next) { 
			/* FIXME: ignore attributes > 0xff */ 
		//	debug_pair(reply); 
	//	} 
//	} 
	 
	/* 
	 *	And send it on it's way. 
	 */ 
	sa = (struct sockaddr_in *) &saremote; 
        memset ((char *) sa, '\0', sizeof (saremote)); 
	sa->sin_family = AF_INET; 
	sa->sin_addr.s_addr = packet->dst_ipaddr; 
	sa->sin_port = htons(packet->dst_port); 
 
	return sendto(packet->sockfd, (const char*)packet->data, (int)packet->data_len, 0, 
		      (struct sockaddr *)&saremote, sizeof(struct sockaddr_in)); 
} 
/////////////////////////////////////////////////////////// 
#define RADIUS_AUTH_PORT_DEFAULT 1812 
 
static bool parseConfig(Section &sec) 
{ 
	const char *name = sec.getName(); 
	 
	if (!strcmp(name, "GK"))  
	{ 
		_ops.GKIP = inet_addr(sec.getString("ip", "www.mocity.com.cn")); 
		_ops.GKPort = htons(sec.getInteger("port", GK_PORT_DEFAULT)); 
	} 
	else if (!strcmp(name, "log")) 
	{ 
		_ops.logFile = sec.getString("file"); 
		_ops.logLevel = sec.getInteger("level", 1); 
	} 
	else if(!strcmp(name, "database")) 
	{ 
		_ops.DB_Info.connection=sec.getString("connection", ""); 
		_ops.DB_Info.user= sec.getString("user", ""); 
		_ops.DB_Info.passwd = sec.getString("passwd" , ""); 
	} 
	else if(!strcmp(name, "GWPrefixes")) 
	{ 
		_ops.internalPrefix=sec.getString("internal", ""); 
		_ops.internationalPrefix= sec.getString("international", ""); 
	} 
	else if(!strcmp(name, "RadiusClient")) 
	{ 
		_ops.authPort=htons(sec.getInteger("authPort", RADIUS_AUTH_PORT_DEFAULT)); 
		_ops.sharedSecret=sec.getString("sharedSecret", ""); 
		_ops.clientIP=inet_addr(sec.getString("clientIP", "")); 
	} 
	else if(!strcmp(name, "RadiusServer")) 
	{ 
		_ops.serverIP=inet_addr(sec.getString("bindAddress", "")); 
	} 
	 
	return true; 
} 
 
//////////////////////////////////////////////////////////// 
 
bool RadiusSrvInit(void) 
{ 
	if(!parseProfile(CONFIG_FILE, parseConfig)) 
	{ 
		printf("未找到配置文件%s\n", CONFIG_FILE); 
		return false; 
	} 
 
	Log::open(_ops.logFile.c_str(), _ops.logLevel); 
 
	iPrefixArray=StringToken(_ops.internalPrefix.c_str(), ";,");//国内前缀 
	oPrefixArray=StringToken(_ops.internationalPrefix.c_str(), ";,"); //国际前缀 
 
	struct sockaddr_in *sa; 
	struct sockaddr salocal; 
	int result; 
	/* 
	 *  Open Authentication socket. 
	 * 
	 */ 
	authfd = socket (AF_INET, SOCK_DGRAM, 0); 
	if (authfd < 0) { 
		LOG(1) ("Socket Error: %d",WSAGetLastError()); 
		exit(1); 
	} 
 
	sa = (struct sockaddr_in *) &salocal; 
	memset ((char *) sa, '\0', sizeof(salocal)); 
	sa->sin_family = AF_INET; 
	sa->sin_addr.s_addr = _ops.serverIP; 
	sa->sin_port = _ops.authPort; 
 
	result = bind (authfd, &salocal, sizeof(*sa)); 
	if (result < 0) { 
		LOG(1) ("Socket Error: %d\n",WSAGetLastError()); 
		return false; 
	} 
	else 
		LOG(2) ("UDP Socket Create"); 
 
	// Initialize database subsystem 
	if (!IPPhoneDBLink.IPPhoneDBInit(_ops.DB_Info)) { 
		LOG(1) ("Cannot connect to database"); 
		return false; 
	} 
	else 
		LOG(2) ("connect to database successfully"); 
 
	return true; 
} 
 
bool RadiusSrvStart(void) 
{ 
//	DWORD id; 
 
	handlePacketThread(); 
 
	return true; 
} 
 
void RadiusSrvDestroy(void) 
{ 
	IPPhoneDBLink.IPPhoneDBDestory(); 
}