--- Makefile.orig	Sat May 15 10:38:13 1999
+++ Makefile	Sat May 15 09:44:05 1999
@@ -4,18 +4,26 @@
 #
 
+CC	= gcc
+CFLAGS	= -Wall -g
+LDFLAGS	= # -s # tatic
+LIBS	= 
+
 #
 #	Autoselect -lshadow and -lcrypt
 #
 ifneq ($(wildcard /usr/lib/libshadow.a),)
-LSHADOW	= -lshadow
+LIBS	+= -lshadow
+else
+CFLAGS	+= -DNOSHADOW
 endif
+
 ifneq ($(wildcard /usr/lib/libcrypt.a),)
-LCRYPT	= -lcrypt
+LIBS	+= -lcrypt
 endif
 
-CC	= gcc
-CFLAGS	= -Wall -g # -DNOSHADOW
-LDFLAGS	= # -s # tatic
-LIBS	= $(LSHADOW)
+ifneq ($(wildcard /usr/lib/libpthread.so),)
+LIBS	+= -lpthread
+CFLAGS	+= -DHAVE_THREADS
+endif
 
 DBM	= -DNDBM
--- acct.c.orig	Sat May 15 10:38:13 1999
+++ acct.c	Sat May 15 09:57:24 1999
@@ -687,5 +687,5 @@
  *	rad_accounting: call both the old and new style accounting functions.
  */
-int rad_accounting(AUTH_REQ *authreq, int activefd)
+int rad_accounting(AUTH_REQ *authreq)
 {
 	int reply = 0;
@@ -700,5 +700,5 @@
 
 	if (auth < 0) {
-		authfree(authreq);
+		authreq->finished = TRUE;
 		return -1;
 	}
@@ -730,8 +730,8 @@
 		 */
 		rad_send_reply(PW_ACCOUNTING_RESPONSE,
-			authreq, NULL, NULL, activefd);
+			authreq, NULL, NULL);
 	}
 
-	authfree(authreq);
+	authreq->finished = TRUE;
 
 	return reply ? 0 : -1;
--- auth.c.orig	Sat May 15 10:38:13 1999
+++ auth.c	Sat May 15 10:26:55 1999
@@ -222,5 +222,5 @@
  *			1  End check & return.
  */
-static int rad_check_password(AUTH_REQ *authreq, int activefd,
+static int rad_check_password(AUTH_REQ *authreq,
 	VALUE_PAIR *check_item,
 	VALUE_PAIR *namepair,
@@ -460,5 +460,5 @@
  *	process the hints and huntgroups file.
  */
-int rad_auth_init(AUTH_REQ *authreq, int activefd)
+int rad_auth_init(AUTH_REQ *authreq)
 {
 	VALUE_PAIR	*namepair;
@@ -474,7 +474,5 @@
 		log(L_ERR, "No username: [] (from nas %s)",
 			nas_name2(authreq));
-		pairfree(authreq->request);
-		memset(authreq, 0, sizeof(AUTH_REQ));
-		free(authreq);
+		authfree(authreq);
 		return -1;
 	}
@@ -512,5 +510,5 @@
 			namepair->strvalue, auth_name(authreq, 1));
 		rad_send_reply(PW_AUTHENTICATION_REJECT, authreq,
-			authreq->request, NULL, activefd);
+			authreq->request, NULL);
 		authfree(authreq);
 		return -1;
@@ -523,5 +521,5 @@
  *	Process and reply to an authentication request
  */
-int rad_authenticate(AUTH_REQ *authreq, int activefd)
+int rad_authenticate(AUTH_REQ *authreq)
 {
 	VALUE_PAIR	*namepair;
@@ -598,8 +596,8 @@
 			namepair->strvalue, auth_name(authreq, 1));
 		rad_send_reply(PW_AUTHENTICATION_REJECT, authreq,
-			proxy_pairs, NULL, activefd);
+			proxy_pairs, NULL);
 		pairfree(proxy_pairs);
 		pairfree(user_reply);
-		authfree(authreq);
+		authreq->finished = TRUE;
 		return -1;
 	}
@@ -613,5 +611,5 @@
 		if ((result = check_expiration(user_check, umsg, &user_msg))<0)
 				break;
-		result = rad_check_password(authreq, activefd, user_check,
+		result = rad_check_password(authreq, user_check,
 			namepair, pw_digest, &user_msg, userpass);
 		if (result > 0) {
@@ -621,7 +619,7 @@
 			 *	doesn't work anyway, so ..
 			 */
-			authfree(authreq);
 			pairfree(proxy_pairs);
 			pairfree(user_reply);
+			authreq->finished = TRUE;
 			return -1;
 		}
@@ -640,5 +638,5 @@
 		 */
 		rad_send_reply(PW_AUTHENTICATION_REJECT, authreq,
-			user_reply, user_msg, activefd);
+			user_reply, user_msg);
 		if (log_auth) {
 			log(L_AUTH,
@@ -672,5 +670,5 @@
 			}
 			rad_send_reply(PW_AUTHENTICATION_REJECT, authreq,
-				user_reply, user_msg, activefd);
+				user_reply, user_msg);
 		log(L_ERR, "Multiple logins: [%s] (from nas %s) max. %d%s",
 				namepair->strvalue,
@@ -704,5 +702,5 @@
 			"You are calling outside your allowed timespan\r\n";
 			rad_send_reply(PW_AUTHENTICATION_REJECT, authreq,
-				user_reply, user_msg, activefd);
+				user_reply, user_msg);
 			log(L_ERR, "Outside allowed timespan: [%s]"
 				   " (from nas %s) time allowed: %s",
@@ -738,7 +736,7 @@
 	 */
 	if (result < 0) {
-		authfree(authreq);
 		pairfree(user_check);
 		pairfree(user_reply);
+		authreq->finished = TRUE;
 		return 0;
 	}
@@ -792,5 +790,5 @@
 		user_msg = "\r\nAccess denied (external check failed).";
 			rad_send_reply(PW_AUTHENTICATION_REJECT, authreq,
-				user_reply, user_msg, activefd);
+				user_reply, user_msg);
 			if (log_auth) {
 				log(L_AUTH,
@@ -800,7 +798,7 @@
 					auth_name(authreq, 1));
 			}
-			authfree(authreq);
 			pairfree(user_check);
 			pairfree(user_reply);
+			authreq->finished = TRUE;
 			return 0;
 		}
@@ -844,5 +842,5 @@
 
 	rad_send_reply(PW_AUTHENTICATION_ACK, authreq,
-			user_reply, user_msg, activefd);
+			user_reply, user_msg);
 	if (log_auth) {
 #if 1 /* Hide the password for `miquels' :) */
@@ -866,7 +864,7 @@
 
 	if (exec_program) free(exec_program);
-	authfree(authreq);
 	pairfree(user_check);
 	pairfree(user_reply);
+	authreq->finished = TRUE;
 
 	return 0;
--- radius.c.orig	Sat May 15 10:38:14 1999
+++ radius.c	Sat May 15 10:26:09 1999
@@ -23,9 +23,23 @@
 #include	"radiusd.h"
 
-/*
- *	Make sure our buffer is aligned.
- */
-static int	i_send_buffer[1024];
-static char	*send_buffer = (char *)i_send_buffer;
+int send_packet(AUTH_REQ *authreq)
+{
+	struct	sockaddr	saremote;
+	struct	sockaddr_in	*sin;
+
+	sin = (struct sockaddr_in *) &saremote;
+        memset ((char *) sin, '\0', sizeof (saremote));
+	sin->sin_family = AF_INET;
+	sin->sin_addr.s_addr = htonl(authreq->ipaddr);
+	sin->sin_port = htons(authreq->udp_port);
+
+	/*
+	 *	Send it to the user
+	 */
+	return sendto(authreq->activefd, (char *)authreq->reply,
+		      (int) ntohs(authreq->reply->length),
+		      (int)0, &saremote, sizeof(struct sockaddr_in));
+
+}
 
 /*
@@ -34,5 +48,5 @@
  */
 int rad_send_reply(int code, AUTH_REQ *authreq, VALUE_PAIR *oreply,
-			char *msg, int activefd)
+			char *msg)
 {
 	AUTH_HDR		*auth;
@@ -48,6 +62,13 @@
 	VALUE_PAIR		*reply;
 	int			vendorcode, vendorpec;
+	char			*send_buffer;
+
+	send_buffer = malloc(4096);
+	if (!send_buffer) {
+	  exit(1);
+	}
 
 	auth = (AUTH_HDR *)send_buffer;
+	authreq->reply = auth;
 	reply = oreply;
 
@@ -212,5 +233,5 @@
 	 *	Send it to the user
 	 */
-	sendto(activefd, (char *)auth, (int)total_length, (int)0,
+	sendto(authreq->activefd, (char *)auth, (int)total_length, (int)0,
 			&saremote, sizeof(struct sockaddr_in));
 
@@ -362,4 +383,6 @@
 	authreq->data = buffer;
 	authreq->data_len = length;
+	authreq->reply = NULL;
+	authreq->finished = FALSE;
 
 	/*
@@ -499,5 +522,5 @@
  */
 static void send_challenge(AUTH_REQ *authreq, char *msg,
-				char *state, int activefd)
+				char *state)
 {
 	AUTH_HDR		*auth;
@@ -574,5 +597,5 @@
 	 *	Send it to the user
 	 */
-	sendto(activefd, (char *)auth, (int)total_length, (int)0,
+	sendto(authreq->activefd, (char *)auth, (int)total_length, (int)0,
 			&saremote, sizeof(struct sockaddr_in));
 }
--- radiusd.c.orig	Sat May 15 10:38:14 1999
+++ radiusd.c	Sat May 15 10:31:28 1999
@@ -74,10 +74,4 @@
 int			acct_port;
 
-/*
- *	Make sure recv_buffer is aligned properly.
- */
-static int		i_recv_buffer[1024];
-static char		*recv_buffer = (char *)i_recv_buffer;
-
 static int		got_chld = 0;
 static int		request_list_busy = 0;
@@ -85,5 +79,5 @@
 static int		acctfd;
 static int		spawn_flag;
-static int		acct_pid;
+static int		acct_pid = 0;
 static int		radius_pid;
 static int		need_reload = 0;
@@ -95,5 +89,5 @@
 #endif
 
-typedef		int (*FUNP)(AUTH_REQ *, int);
+typedef		int (*FUNP)(AUTH_REQ *);
 
 static int	config_init(void);
@@ -104,5 +98,5 @@
 
 static int	radrespond (AUTH_REQ *, int);
-static void	rad_spawn_child (AUTH_REQ *, int, FUNP);
+static void	rad_spawn_child (AUTH_REQ *, FUNP);
 
 /*
@@ -384,8 +378,12 @@
 	}
 #endif
+
+#ifndef HAVE_THREADS
 	/*
 	 *	If we are in forking mode, we will start a child
 	 *	to listen for Accounting requests.  If not, we will 
 	 *	listen for them ourself.
+	 *
+	 *	Threads: listen to all requests ourselves.
 	 */
 	if (spawn_flag) {
@@ -405,4 +403,5 @@
 		}
 	} else
+#endif
 		log(L_INFO, "Ready to process requests.");
 
@@ -437,7 +436,10 @@
 		}
 		if (sockfd >= 0 && FD_ISSET(sockfd, &readfds)) {
+			char *recv_buffer = malloc(4096);
+			if (!recv_buffer) exit(1);
+
 			salen = sizeof (saremote);
 			result = recvfrom (sockfd, (char *) recv_buffer,
-				(int) sizeof(i_recv_buffer),
+				(int) 4096,
 				(int) 0, &saremote, &salen);
 
@@ -450,11 +452,15 @@
 			}
 			else if (result < 0 && errno == EINTR) {
+				free(recv_buffer);
 				result = 0;
 			}
 		}
 		if (acctfd >=0 && FD_ISSET(acctfd, &readfds)) {
+			char *recv_buffer = malloc(4096);
+			if (!recv_buffer) exit(1);
+
 			salen = sizeof (saremote);
 			result = recvfrom (acctfd, (char *) recv_buffer,
-				(int) sizeof(i_recv_buffer),
+				(int) 4096,
 				(int) 0, &saremote, &salen);
 
@@ -467,4 +473,5 @@
 			}
 			else if (result < 0 && errno == EINTR) {
+				free(recv_buffer);
 				result = 0;
 			}
@@ -498,4 +505,5 @@
 	dospawn = 0;
 	fun = NULL;
+	authreq->activefd = activefd;
 
 	/*
@@ -508,5 +516,5 @@
 		 *	Check request against hints and huntgroups.
 		 */
-		if ((e = rad_auth_init(authreq, activefd)) < 0)
+		if ((e = rad_auth_init(authreq)) < 0)
 			return e;
 		/*FALLTHRU*/
@@ -543,4 +551,7 @@
 	
 	case PW_ACCOUNTING_REQUEST:
+#ifdef HAVE_THREADS
+		dospawn = spawn_flag;
+#endif
 		fun = rad_accounting;
 		break;
@@ -565,7 +576,9 @@
 	if (fun) {
 		if (dospawn)
-			rad_spawn_child(authreq, activefd, fun);
-		else
-			(*fun)(authreq, activefd);
+			rad_spawn_child(authreq, fun);
+		else {
+			(*fun)(authreq);
+			authfree(authreq);
+		}
 	}
 
@@ -581,5 +594,5 @@
  *	requests are filtered out).
  */
-static void rad_spawn_child(AUTH_REQ *authreq, int activefd, FUNP fun)
+static void rad_spawn_child(AUTH_REQ *authreq, FUNP fun)
 {
 	AUTH_REQ	*curreq;
@@ -587,5 +600,9 @@
 	UINT4		curtime;
 	int		request_count;
+#ifndef HAVE_THREADS
 	int		child_pid;
+#else
+	pthread_t	child_pid;
+#endif
 
 	curtime = (UINT4)time(NULL);
@@ -602,5 +619,15 @@
 
 	while(curreq != (AUTH_REQ *)NULL) {
-		if (curreq->child_pid == -1 &&
+#ifdef HAVE_THREADS
+		/*
+		 *  Child thread has told us it's finished: clean it up
+		 */
+		if (curreq->finished) {
+			pthread_join(curreq->child_pid, NULL);
+			curreq->child_pid = 0;
+		}
+#endif
+
+		if (curreq->child_pid == 0 &&
 		    curreq->timestamp + CLEANUP_DELAY <= curtime) {
 			/*
@@ -609,11 +636,9 @@
 			if (prevreq == (AUTH_REQ *)NULL) {
 				first_request = curreq->next;
-				pairfree(curreq->request);
-				free(curreq);
+				authfree(curreq);
 				curreq = first_request;
 			} else {
 				prevreq->next = curreq->next;
-				pairfree(curreq->request);
-				free(curreq);
+				authfree(curreq);
 				curreq = prevreq->next;
 			}
@@ -625,4 +650,19 @@
 			 */
 			if (memcmp(curreq->vector, authreq->vector, 16) == 0) {
+#ifdef HAVE_THREADS
+			  if (curreq->reply) {
+			    curreq->udp_port = authreq->udp_port;
+			    send_packet(curreq);
+				log(L_ERR,
+				"Sending duplicate authentication response"
+				" to client %s - ID: %d",
+				client_name(authreq->ipaddr), authreq->id);
+
+				authfree(authreq);
+				request_list_busy = 0;
+				sig_cleanup(SIGCHLD);
+				return;
+			  }
+#endif
 				/*
 				 * This is a duplicate request - just drop it
@@ -632,6 +672,5 @@
 				" from client %s - ID: %d",
 				client_name(authreq->ipaddr), authreq->id);
-				pairfree(authreq->request);
-				free(authreq);
+				authfree(authreq);
 				request_list_busy = 0;
 				sig_cleanup(SIGCHLD);
@@ -643,5 +682,5 @@
 			 *	delete it right now.
 			 */
-			if (curreq->child_pid == -1) {
+			if (curreq->child_pid == 0) {
 				curreq->timestamp = curtime - CLEANUP_DELAY;
 				continue;
@@ -656,5 +695,5 @@
 		} else {
 			if (curreq->timestamp + MAX_REQUEST_TIME <= curtime &&
-			    curreq->child_pid != -1) {
+			    curreq->child_pid != 0) {
 				/*
 				 *	This request seems to have hung -
@@ -665,5 +704,5 @@
 					"Killing unresponsive child pid %d",
 								child_pid);
-				curreq->child_pid = -1;
+				curreq->child_pid = 0;
 				kill(child_pid, SIGTERM);
 			}
@@ -680,6 +719,5 @@
 		log(L_ERR, "Dropping request (too many): from client %s - ID: %d",
 				client_name(authreq->ipaddr), authreq->id);
-		pairfree(authreq->request);
-		free(authreq);
+		authfree(authreq);
 
 		request_list_busy = 0;
@@ -693,5 +731,5 @@
 	 */
 	authreq->next = (AUTH_REQ *)NULL;
-	authreq->child_pid = -1;
+	authreq->child_pid = 0;
 	authreq->timestamp = curtime;
 
@@ -701,4 +739,5 @@
 		prevreq->next = authreq;
 
+#ifndef HAVE_THREADS
 	/*
 	 *	fork our child
@@ -714,5 +753,5 @@
 		request_list_busy = 0;
 		signal(SIGCHLD, SIG_DFL);
-		(*fun)(authreq, activefd);
+		(*fun)(authreq);
 		exit(0);
 	}
@@ -722,5 +761,13 @@
 	 */
 	authreq->child_pid = child_pid;
-
+#else
+	/*
+	 *	fork our child thread
+	 */
+	if (pthread_create(&authreq->child_pid, NULL, fun, authreq) < 0) {
+		log(L_ERR, "Thread create failed for request from nas %s - ID: %d",
+				nas_name2(authreq), authreq->id);
+	}
+#endif
 	request_list_busy = 0;
 	sig_cleanup(SIGCHLD);
@@ -767,5 +814,5 @@
 		while (curreq != (AUTH_REQ *)NULL) {
 			if (curreq->child_pid == pid) {
-				curreq->child_pid = -1;
+				curreq->child_pid = 0;
 				/*
 				 *	FIXME: UINT4 ?
--- radiusd.h.orig	Sat May 15 10:38:14 1999
+++ radiusd.h	Sat May 15 10:18:00 1999
@@ -71,4 +71,5 @@
 
 typedef struct auth_req {
+	int			activefd;
 	UINT4			ipaddr;
 	u_short			udp_port;
@@ -79,6 +80,12 @@
 	u_char			username[AUTH_STRING_LEN];
 	VALUE_PAIR		*request;
+#ifndef HAVE_THREADS
 	int			child_pid;	/* Process ID of child */
+#else
+	pthread_t      		child_pid;	/* thread ID of child */
+#endif
+	AUTH_HDR		*reply;		/* reply to the client */
 	UINT4			timestamp;
+	int			finished;
 	u_char			*data;		/* Raw received data */
 	int			data_len;
@@ -149,4 +156,12 @@
 #define VENDOR(x) (x >> 16)
 
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
 /*
  *	Global variables.
@@ -177,5 +192,5 @@
 
 /* acct.c */
-int		rad_accounting(AUTH_REQ *, int);
+int		rad_accounting(AUTH_REQ *);
 int		rad_accounting_orig(AUTH_REQ *, int, char *);
 int		radzap(UINT4 nas, int port, char *user, time_t t);
@@ -224,5 +239,6 @@
 
 /* radius.c */
-int		rad_send_reply(int, AUTH_REQ *, VALUE_PAIR *, char *, int);
+int		send_packet(AUTH_REQ *authreq);
+int		rad_send_reply(int, AUTH_REQ *, VALUE_PAIR *, char *);
 AUTH_REQ	*radrecv (UINT4, u_short, u_char *, int);
 int		calc_digest (u_char *, AUTH_REQ *);
@@ -268,6 +284,6 @@
 
 /* auth.c */
-int		rad_auth_init(AUTH_REQ *authreq, int activefd);
-int		rad_authenticate (AUTH_REQ *, int);
+int		rad_auth_init(AUTH_REQ *authreq);
+int		rad_authenticate (AUTH_REQ *);
 
 /* exec.c */
--- radtest.c.orig	Sat May 15 10:38:14 1999
+++ radtest.c	Sat May 15 10:31:59 1999
@@ -99,5 +99,5 @@
 
 	printf("radrecv: Reply from host %lx code=%d, id=%d, length=%d\n",
-				(u_long)host, auth->code, auth->id, totallen);
+				(u_long)ntohl(host), auth->code, auth->id, totallen);
 
 	/*
--- sysdep.h.orig	Sat May 15 10:38:14 1999
+++ sysdep.h	Sat May 15 10:00:19 1999
@@ -54,3 +54,8 @@
 #endif
 
+#ifdef HAVE_THREADS
+#include <pthread.h>
+#define kill pthread_kill
+#endif
+
 #endif /* SYSDEP_H_INCLUDED */
--- util.c.orig	Sat May 15 10:38:14 1999
+++ util.c	Sat May 15 10:15:38 1999
@@ -279,4 +279,6 @@
 {
 	pairfree(authreq->request);
+	free(authreq->data);
+	if (authreq->reply) free(authreq->reply);
 	memset(authreq, 0, sizeof(AUTH_REQ));
 	free(authreq);
