Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 11 Sep 2009 11:42:57 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r197086 - head/lib/libradius
Message-ID:  <200909111142.n8BBgvIV051117@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Fri Sep 11 11:42:56 2009
New Revision: 197086
URL: http://svn.freebsd.org/changeset/base/197086

Log:
  Add simple embedded RADIUS server support to libradius, by extending existing
  API, keeping backward compatibility.
  
  First consumer for this functionality is going to become forthcoming MPD-5.4,
  supporting CoA and DR of RFC 3576: Dynamic Authorization Extensions to RADIUS.
  
  MFC after:	1 month

Modified:
  head/lib/libradius/libradius.3
  head/lib/libradius/radlib.c
  head/lib/libradius/radlib.h
  head/lib/libradius/radlib_private.h

Modified: head/lib/libradius/libradius.3
==============================================================================
--- head/lib/libradius/libradius.3	Fri Sep 11 02:07:24 2009	(r197085)
+++ head/lib/libradius/libradius.3	Fri Sep 11 11:42:56 2009	(r197086)
@@ -1,4 +1,5 @@
 .\" Copyright 1998 Juniper Networks, Inc.
+.\" Copyright 2009 Alexander Motin <mav@FreeBSD.org>.
 .\" All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
@@ -24,12 +25,12 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd April 27, 2004
+.Dd August 5, 2009
 .Dt LIBRADIUS 3
 .Os
 .Sh NAME
 .Nm libradius
-.Nd RADIUS client library
+.Nd RADIUS client/server library
 .Sh SYNOPSIS
 .In radlib.h
 .Ft "struct rad_handle *"
@@ -46,6 +47,8 @@
 .Fn rad_continue_send_request "struct rad_handle *h" "int selected" "int *fd" "struct timeval *tv"
 .Ft int
 .Fn rad_create_request "struct rad_handle *h" "int code"
+.Ft int
+.Fn rad_create_response "struct rad_handle *h" "int code"
 .Ft "struct in_addr"
 .Fn rad_cvt_addr "const void *data"
 .Ft u_int32_t
@@ -79,7 +82,13 @@
 .Ft ssize_t
 .Fn rad_request_authenticator "struct rad_handle *h" "char *buf" "size_t len"
 .Ft int
+.Fn rad_receive_request "struct rad_handle *h"
+.Ft int
 .Fn rad_send_request "struct rad_handle *h"
+.Ft int
+.Fn rad_send_response "struct rad_handle *h"
+.Ft "struct rad_handle *"
+.Fn rad_server_open "int fd"
 .Ft "const char *"
 .Fn rad_server_secret "struct rad_handle *h"
 .Ft u_char *
@@ -91,16 +100,17 @@
 .Sh DESCRIPTION
 The
 .Nm
-library implements the client side of the Remote Authentication Dial
-In User Service (RADIUS).
+library implements the Remote Authentication Dial In User Service (RADIUS).
 RADIUS, defined in RFCs 2865 and 2866,
 allows clients to perform authentication and accounting by means of
 network requests to remote servers.
 .Ss Initialization
 To use the library, an application must first call
 .Fn rad_auth_open
-or
+,
 .Fn rad_acct_open
+or
+.Fn rad_server_open
 to obtain a
 .Vt "struct rad_handle *" ,
 which provides the context for subsequent operations.
@@ -108,8 +118,10 @@ The former function is used for RADIUS a
 latter is used for RADIUS accounting.
 Calls to
 .Fn rad_auth_open
-and
+,
 .Fn rad_acct_open
+and
+.Fn rad_server_open
 always succeed unless insufficient virtual memory is available.
 If
 the necessary memory cannot be allocated, the functions return
@@ -451,6 +463,25 @@ subsequent library calls using the same 
 .Ss Cleanup
 To free the resources used by the RADIUS library, call
 .Fn rad_close .
+.Ss Server operation
+Server mode operates much alike to client mode, except packet send and receieve
+steps are swapped. To operate as server you should obtain server context with
+.Fn rad_server_open
+function, passing opened and bound UDP socket file descriptor as argument.
+You should define allowed clients and their secrets using
+.Fn rad_add_server
+function. port, timeout and max_tries arguments are ignored in server mode.
+You should call
+.Fn rad_receive_request
+function to receive request from client. If you do not want to block on socket
+read, you are free to use any poll(), select() or non-blocking sockets for
+the socket.
+Received request can be parsed with same parsing functions as for client.
+To respond to the request you should call
+.Fn rad_create_response
+and fill response content with same packet writing functions as for client.
+When packet is ready, it should be sent with
+.Fn rad_send_response
 .Sh RETURN VALUES
 The following functions return a non-negative value on success.
 If
@@ -466,6 +497,8 @@ which can be retrieved using
 .It
 .Fn rad_create_request
 .It
+.Fn rad_create_response
+.It
 .Fn rad_get_attr
 .It
 .Fn rad_put_addr
@@ -483,6 +516,8 @@ which can be retrieved using
 .Fn rad_continue_send_request
 .It
 .Fn rad_send_request
+.It
+.Fn rad_send_response
 .El
 .Pp
 The following functions return a
@@ -499,6 +534,8 @@ without recording an error message.
 .It
 .Fn rad_auth_open
 .It
+.Fn rad_server_open
+.It
 .Fn rad_cvt_string
 .El
 .Pp
@@ -553,3 +590,5 @@ subsequently added the ability to perfor
 accounting.
 Later additions and changes by
 .An Michael Bretterklieber .
+Server mode support was added by
+.An Alexander Motin .

Modified: head/lib/libradius/radlib.c
==============================================================================
--- head/lib/libradius/radlib.c	Fri Sep 11 02:07:24 2009	(r197085)
+++ head/lib/libradius/radlib.c	Fri Sep 11 11:42:56 2009	(r197086)
@@ -103,7 +103,7 @@ insert_scrambled_password(struct rad_han
 	srvp = &h->servers[srv];
 	padded_len = h->pass_len == 0 ? 16 : (h->pass_len+15) & ~0xf;
 
-	memcpy(md5, &h->request[POS_AUTH], LEN_AUTH);
+	memcpy(md5, &h->out[POS_AUTH], LEN_AUTH);
 	for (pos = 0;  pos < padded_len;  pos += 16) {
 		int i;
 
@@ -120,49 +120,55 @@ insert_scrambled_password(struct rad_han
 		 * in calculating the scrambler for next time.
 		 */
 		for (i = 0;  i < 16;  i++)
-			h->request[h->pass_pos + pos + i] =
+			h->out[h->pass_pos + pos + i] =
 			    md5[i] ^= h->pass[pos + i];
 	}
 }
 
 static void
-insert_request_authenticator(struct rad_handle *h, int srv)
+insert_request_authenticator(struct rad_handle *h, int resp)
 {
 	MD5_CTX ctx;
 	const struct rad_server *srvp;
 
-	srvp = &h->servers[srv];
+	srvp = &h->servers[h->srv];
 
 	/* Create the request authenticator */
 	MD5Init(&ctx);
-	MD5Update(&ctx, &h->request[POS_CODE], POS_AUTH - POS_CODE);
-	MD5Update(&ctx, memset(&h->request[POS_AUTH], 0, LEN_AUTH), LEN_AUTH);
-	MD5Update(&ctx, &h->request[POS_ATTRS], h->req_len - POS_ATTRS);
+	MD5Update(&ctx, &h->out[POS_CODE], POS_AUTH - POS_CODE);
+	if (resp)
+	    MD5Update(&ctx, &h->in[POS_AUTH], LEN_AUTH);
+	else
+	    MD5Update(&ctx, &h->out[POS_AUTH], LEN_AUTH);
+	MD5Update(&ctx, &h->out[POS_ATTRS], h->out_len - POS_ATTRS);
 	MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
-	MD5Final(&h->request[POS_AUTH], &ctx);
+	MD5Final(&h->out[POS_AUTH], &ctx);
 }
 
 static void
-insert_message_authenticator(struct rad_handle *h, int srv)
+insert_message_authenticator(struct rad_handle *h, int resp)
 {
 #ifdef WITH_SSL
 	u_char md[EVP_MAX_MD_SIZE];
 	u_int md_len;
 	const struct rad_server *srvp;
 	HMAC_CTX ctx;
-	srvp = &h->servers[srv];
+	srvp = &h->servers[h->srv];
 
 	if (h->authentic_pos != 0) {
 		HMAC_CTX_init(&ctx);
 		HMAC_Init(&ctx, srvp->secret, strlen(srvp->secret), EVP_md5());
-		HMAC_Update(&ctx, &h->request[POS_CODE], POS_AUTH - POS_CODE);
-		HMAC_Update(&ctx, &h->request[POS_AUTH], LEN_AUTH);
-		HMAC_Update(&ctx, &h->request[POS_ATTRS],
-		    h->req_len - POS_ATTRS);
+		HMAC_Update(&ctx, &h->out[POS_CODE], POS_AUTH - POS_CODE);
+		if (resp)
+		    HMAC_Update(&ctx, &h->in[POS_AUTH], LEN_AUTH);
+		else
+		    HMAC_Update(&ctx, &h->out[POS_AUTH], LEN_AUTH);
+		HMAC_Update(&ctx, &h->out[POS_ATTRS],
+		    h->out_len - POS_ATTRS);
 		HMAC_Final(&ctx, md, &md_len);
 		HMAC_CTX_cleanup(&ctx);
 		HMAC_cleanup(&ctx);
-		memcpy(&h->request[h->authentic_pos + 2], md, md_len);
+		memcpy(&h->out[h->authentic_pos + 2], md, md_len);
 	}
 #endif
 }
@@ -195,20 +201,20 @@ is_valid_response(struct rad_handle *h, 
 		return 0;
 
 	/* Check the message length */
-	if (h->resp_len < POS_ATTRS)
+	if (h->in_len < POS_ATTRS)
 		return 0;
-	len = h->response[POS_LENGTH] << 8 | h->response[POS_LENGTH+1];
-	if (len > h->resp_len)
+	len = h->in[POS_LENGTH] << 8 | h->in[POS_LENGTH+1];
+	if (len > h->in_len)
 		return 0;
 
 	/* Check the response authenticator */
 	MD5Init(&ctx);
-	MD5Update(&ctx, &h->response[POS_CODE], POS_AUTH - POS_CODE);
-	MD5Update(&ctx, &h->request[POS_AUTH], LEN_AUTH);
-	MD5Update(&ctx, &h->response[POS_ATTRS], len - POS_ATTRS);
+	MD5Update(&ctx, &h->in[POS_CODE], POS_AUTH - POS_CODE);
+	MD5Update(&ctx, &h->out[POS_AUTH], LEN_AUTH);
+	MD5Update(&ctx, &h->in[POS_ATTRS], len - POS_ATTRS);
 	MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
 	MD5Final(md5, &ctx);
-	if (memcmp(&h->response[POS_AUTH], md5, sizeof md5) != 0)
+	if (memcmp(&h->in[POS_AUTH], md5, sizeof md5) != 0)
 		return 0;
 
 #ifdef WITH_SSL
@@ -216,42 +222,111 @@ is_valid_response(struct rad_handle *h, 
 	 * For non accounting responses check the message authenticator,
 	 * if any.
 	 */
-	if (h->response[POS_CODE] != RAD_ACCOUNTING_RESPONSE) {
+	if (h->in[POS_CODE] != RAD_ACCOUNTING_RESPONSE) {
 
-		memcpy(resp, h->response, MSGSIZE);
+		memcpy(resp, h->in, MSGSIZE);
 		pos = POS_ATTRS;
 
 		/* Search and verify the Message-Authenticator */
 		while (pos < len - 2) {
 
-			if (h->response[pos] == RAD_MESSAGE_AUTHENTIC) {
+			if (h->in[pos] == RAD_MESSAGE_AUTHENTIC) {
 				/* zero fill the Message-Authenticator */
 				memset(&resp[pos + 2], 0, MD5_DIGEST_LENGTH);
 
 				HMAC_CTX_init(&hctx);
 				HMAC_Init(&hctx, srvp->secret,
 				    strlen(srvp->secret), EVP_md5());
-				HMAC_Update(&hctx, &h->response[POS_CODE],
+				HMAC_Update(&hctx, &h->in[POS_CODE],
 				    POS_AUTH - POS_CODE);
-				HMAC_Update(&hctx, &h->request[POS_AUTH],
+				HMAC_Update(&hctx, &h->out[POS_AUTH],
 				    LEN_AUTH);
 				HMAC_Update(&hctx, &resp[POS_ATTRS],
-				    h->resp_len - POS_ATTRS);
+				    h->in_len - POS_ATTRS);
 				HMAC_Final(&hctx, md, &md_len);
 				HMAC_CTX_cleanup(&hctx);
 				HMAC_cleanup(&hctx);
-				if (memcmp(md, &h->response[pos + 2],
+				if (memcmp(md, &h->in[pos + 2],
 				    MD5_DIGEST_LENGTH) != 0)
 					return 0;
 				break;
 			}
-			pos += h->response[pos + 1];
+			pos += h->in[pos + 1];
 		}
 	}
 #endif
 	return 1;
 }
 
+/*
+ * Return true if the current request is valid for the specified server.
+ */
+static int
+is_valid_request(struct rad_handle *h)
+{
+	MD5_CTX ctx;
+	unsigned char md5[MD5_DIGEST_LENGTH];
+	const struct rad_server *srvp;
+	int len;
+#ifdef WITH_SSL
+	HMAC_CTX hctx;
+	u_char resp[MSGSIZE], md[EVP_MAX_MD_SIZE];
+	u_int md_len;
+	int pos;
+#endif
+
+	srvp = &h->servers[h->srv];
+
+	/* Check the message length */
+	if (h->in_len < POS_ATTRS)
+		return (0);
+	len = h->in[POS_LENGTH] << 8 | h->in[POS_LENGTH+1];
+	if (len > h->in_len)
+		return (0);
+
+	if (h->in[POS_CODE] != RAD_ACCESS_REQUEST) {
+		uint32_t zeroes[4] = { 0, 0, 0, 0 };
+		/* Check the request authenticator */
+		MD5Init(&ctx);
+		MD5Update(&ctx, &h->in[POS_CODE], POS_AUTH - POS_CODE);
+		MD5Update(&ctx, zeroes, LEN_AUTH);
+		MD5Update(&ctx, &h->in[POS_ATTRS], len - POS_ATTRS);
+		MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
+		MD5Final(md5, &ctx);
+		if (memcmp(&h->in[POS_AUTH], md5, sizeof md5) != 0)
+			return (0);
+	}
+
+#ifdef WITH_SSL
+	/* Search and verify the Message-Authenticator */
+	pos = POS_ATTRS;
+	while (pos < len - 2) {
+		if (h->in[pos] == RAD_MESSAGE_AUTHENTIC) {
+			memcpy(resp, h->in, MSGSIZE);
+			/* zero fill the Request-Authenticator */
+			if (h->in[POS_CODE] != RAD_ACCESS_REQUEST)
+				memset(&resp[POS_AUTH], 0, LEN_AUTH);
+			/* zero fill the Message-Authenticator */
+			memset(&resp[pos + 2], 0, MD5_DIGEST_LENGTH);
+
+			HMAC_CTX_init(&hctx);
+			HMAC_Init(&hctx, srvp->secret,
+			    strlen(srvp->secret), EVP_md5());
+			HMAC_Update(&hctx, resp, h->in_len);
+			HMAC_Final(&hctx, md, &md_len);
+			HMAC_CTX_cleanup(&hctx);
+			HMAC_cleanup(&hctx);
+			if (memcmp(md, &h->in[pos + 2],
+			    MD5_DIGEST_LENGTH) != 0)
+				return (0);
+			break;
+		}
+		pos += h->in[pos + 1];
+	}
+#endif
+	return (1);
+}
+
 static int
 put_password_attr(struct rad_handle *h, int type, const void *value, size_t len)
 {
@@ -273,7 +348,7 @@ put_password_attr(struct rad_handle *h, 
 	 */
 	clear_password(h);
 	put_raw_attr(h, type, h->pass, padded_len);
-	h->pass_pos = h->req_len - padded_len;
+	h->pass_pos = h->out_len - padded_len;
 
 	/* Save the cleartext password, padded as necessary */
 	memcpy(h->pass, value, len);
@@ -289,14 +364,14 @@ put_raw_attr(struct rad_handle *h, int t
 		generr(h, "Attribute too long");
 		return -1;
 	}
-	if (h->req_len + 2 + len > MSGSIZE) {
+	if (h->out_len + 2 + len > MSGSIZE) {
 		generr(h, "Maximum message length exceeded");
 		return -1;
 	}
-	h->request[h->req_len++] = type;
-	h->request[h->req_len++] = len + 2;
-	memcpy(&h->request[h->req_len], value, len);
-	h->req_len += len;
+	h->out[h->out_len++] = type;
+	h->out[h->out_len++] = len + 2;
+	memcpy(&h->out[h->out_len], value, len);
+	h->out_len += len;
 	return 0;
 }
 
@@ -523,22 +598,26 @@ rad_continue_send_request(struct rad_han
 {
 	int n;
 
+	if (h->type == RADIUS_SERVER) {
+		generr(h, "denied function call");
+		return (-1);
+	}
 	if (selected) {
 		struct sockaddr_in from;
 		socklen_t fromlen;
 
 		fromlen = sizeof from;
-		h->resp_len = recvfrom(h->fd, h->response,
+		h->in_len = recvfrom(h->fd, h->in,
 		    MSGSIZE, MSG_WAITALL, (struct sockaddr *)&from, &fromlen);
-		if (h->resp_len == -1) {
+		if (h->in_len == -1) {
 			generr(h, "recvfrom: %s", strerror(errno));
 			return -1;
 		}
 		if (is_valid_response(h, h->srv, &from)) {
-			h->resp_len = h->response[POS_LENGTH] << 8 |
-			    h->response[POS_LENGTH+1];
-			h->resp_pos = POS_ATTRS;
-			return h->response[POS_CODE];
+			h->in_len = h->in[POS_LENGTH] << 8 |
+			    h->in[POS_LENGTH+1];
+			h->in_pos = POS_ATTRS;
+			return h->in[POS_CODE];
 		}
 	}
 
@@ -556,21 +635,22 @@ rad_continue_send_request(struct rad_han
 		if (++h->srv >= h->num_servers)
 			h->srv = 0;
 
-	if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST)
-		/* Insert the request authenticator into the request */
-		insert_request_authenticator(h, h->srv);
-	else
+	if (h->out[POS_CODE] == RAD_ACCESS_REQUEST) {
 		/* Insert the scrambled password into the request */
 		if (h->pass_pos != 0)
 			insert_scrambled_password(h, h->srv);
-
-	insert_message_authenticator(h, h->srv);
+	}
+	insert_message_authenticator(h, 0);
+	if (h->out[POS_CODE] != RAD_ACCESS_REQUEST) {
+		/* Insert the request authenticator into the request */
+		insert_request_authenticator(h, h->srv);
+	}
 
 	/* Send the request */
-	n = sendto(h->fd, h->request, h->req_len, 0,
+	n = sendto(h->fd, h->out, h->out_len, 0,
 	    (const struct sockaddr *)&h->servers[h->srv].addr,
 	    sizeof h->servers[h->srv].addr);
-	if (n != h->req_len) {
+	if (n != h->out_len) {
 		if (n == -1)
 			generr(h, "sendto: %s", strerror(errno));
 		else
@@ -588,22 +668,117 @@ rad_continue_send_request(struct rad_han
 }
 
 int
+rad_receive_request(struct rad_handle *h)
+{
+	struct sockaddr_in from;
+	socklen_t fromlen;
+	int n;
+
+	if (h->type != RADIUS_SERVER) {
+		generr(h, "denied function call");
+		return (-1);
+	}
+	h->srv = -1;
+	fromlen = sizeof(from);
+	h->in_len = recvfrom(h->fd, h->in,
+	    MSGSIZE, MSG_WAITALL, (struct sockaddr *)&from, &fromlen);
+	if (h->in_len == -1) {
+		generr(h, "recvfrom: %s", strerror(errno));
+		return (-1);
+	}
+	for (n = 0; n < h->num_servers; n++) {
+		if (h->servers[n].addr.sin_addr.s_addr == from.sin_addr.s_addr) {
+			h->servers[n].addr.sin_port = from.sin_port;
+			h->srv = n;
+			break;
+		}
+	}
+	if (h->srv == -1)
+		return (-2);
+	if (is_valid_request(h)) {
+		h->in_len = h->in[POS_LENGTH] << 8 |
+		    h->in[POS_LENGTH+1];
+		h->in_pos = POS_ATTRS;
+		return (h->in[POS_CODE]);
+	}
+	return (-3);
+}
+
+int
+rad_send_response(struct rad_handle *h)
+{
+	int n;
+
+	if (h->type != RADIUS_SERVER) {
+		generr(h, "denied function call");
+		return (-1);
+	}
+	/* Fill in the length field in the message */
+	h->out[POS_LENGTH] = h->out_len >> 8;
+	h->out[POS_LENGTH+1] = h->out_len;
+
+	insert_message_authenticator(h,
+	    (h->in[POS_CODE] == RAD_ACCESS_REQUEST) ? 1 : 0);
+	insert_request_authenticator(h, 1);
+
+	/* Send the request */
+	n = sendto(h->fd, h->out, h->out_len, 0,
+	    (const struct sockaddr *)&h->servers[h->srv].addr,
+	    sizeof h->servers[h->srv].addr);
+	if (n != h->out_len) {
+		if (n == -1)
+			generr(h, "sendto: %s", strerror(errno));
+		else
+			generr(h, "sendto: short write");
+		return -1;
+	}
+
+	return 0;
+}
+
+int
 rad_create_request(struct rad_handle *h, int code)
 {
 	int i;
 
-	h->request[POS_CODE] = code;
-	h->request[POS_IDENT] = ++h->ident;
-	/* Create a random authenticator */
-	for (i = 0;  i < LEN_AUTH;  i += 2) {
-		long r;
-		r = random();
-		h->request[POS_AUTH+i] = (u_char)r;
-		h->request[POS_AUTH+i+1] = (u_char)(r >> 8);
+	if (h->type == RADIUS_SERVER) {
+		generr(h, "denied function call");
+		return (-1);
+	}
+	h->out[POS_CODE] = code;
+	h->out[POS_IDENT] = ++h->ident;
+	if (code == RAD_ACCESS_REQUEST) {
+		/* Create a random authenticator */
+		for (i = 0;  i < LEN_AUTH;  i += 2) {
+			long r;
+			r = random();
+			h->out[POS_AUTH+i] = (u_char)r;
+			h->out[POS_AUTH+i+1] = (u_char)(r >> 8);
+		}
+	} else
+		memset(&h->out[POS_AUTH], 0, LEN_AUTH);
+	h->out_len = POS_ATTRS;
+	clear_password(h);
+	h->authentic_pos = 0;
+	h->out_created = 1;
+	return 0;
+}
+
+int
+rad_create_response(struct rad_handle *h, int code)
+{
+
+	if (h->type != RADIUS_SERVER) {
+		generr(h, "denied function call");
+		return (-1);
 	}
-	h->req_len = POS_ATTRS;
+	h->out[POS_CODE] = code;
+	h->out[POS_IDENT] = h->in[POS_IDENT];
+	memset(&h->out[POS_AUTH], 0, LEN_AUTH);
+	h->out_len = POS_ATTRS;
 	clear_password(h);
-	h->request_created = 1;
+	h->authentic_pos = 0;
+	h->out_created = 1;
 	return 0;
 }
 
@@ -647,20 +822,20 @@ rad_get_attr(struct rad_handle *h, const
 {
 	int type;
 
-	if (h->resp_pos >= h->resp_len)
+	if (h->in_pos >= h->in_len)
 		return 0;
-	if (h->resp_pos + 2 > h->resp_len) {
+	if (h->in_pos + 2 > h->in_len) {
 		generr(h, "Malformed attribute in response");
 		return -1;
 	}
-	type = h->response[h->resp_pos++];
-	*len = h->response[h->resp_pos++] - 2;
-	if (h->resp_pos + (int)*len > h->resp_len) {
+	type = h->in[h->in_pos++];
+	*len = h->in[h->in_pos++] - 2;
+	if (h->in_pos + (int)*len > h->in_len) {
 		generr(h, "Malformed attribute in response");
 		return -1;
 	}
-	*value = &h->response[h->resp_pos];
-	h->resp_pos += *len;
+	*value = &h->in[h->in_pos];
+	h->in_pos += *len;
 	return type;
 }
 
@@ -672,6 +847,10 @@ rad_init_send_request(struct rad_handle 
 {
 	int srv;
 
+	if (h->type == RADIUS_SERVER) {
+		generr(h, "denied function call");
+		return (-1);
+	}
 	/* Make sure we have a socket to use */
 	if (h->fd == -1) {
 		struct sockaddr_in sin;
@@ -694,7 +873,7 @@ rad_init_send_request(struct rad_handle 
 		}
 	}
 
-	if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
+	if (h->out[POS_CODE] != RAD_ACCESS_REQUEST) {
 		/* Make sure no password given */
 		if (h->pass_pos || h->chap_pass) {
 			generr(h, "User or Chap Password"
@@ -718,8 +897,8 @@ rad_init_send_request(struct rad_handle 
 	}
 
 	/* Fill in the length field in the message */
-	h->request[POS_LENGTH] = h->req_len >> 8;
-	h->request[POS_LENGTH+1] = h->req_len;
+	h->out[POS_LENGTH] = h->out_len >> 8;
+	h->out[POS_LENGTH+1] = h->out_len;
 
 	/*
 	 * Count the total number of tries we will make, and zero the
@@ -763,7 +942,7 @@ rad_auth_open(void)
 		h->chap_pass = 0;
 		h->authentic_pos = 0;
 		h->type = RADIUS_AUTH;
-		h->request_created = 0;
+		h->out_created = 0;
 		h->eap_msg = 0;
 	}
 	return h;
@@ -781,6 +960,19 @@ rad_acct_open(void)
 }
 
 struct rad_handle *
+rad_server_open(int fd)
+{
+	struct rad_handle *h;
+
+	h = rad_open();
+	if (h != NULL) {
+	        h->type = RADIUS_SERVER;
+	        h->fd = fd;
+	}
+	return h;
+}
+
+struct rad_handle *
 rad_open(void)
 {
     return rad_auth_open();
@@ -797,13 +989,13 @@ rad_put_attr(struct rad_handle *h, int t
 {
 	int result;
 
-	if (!h->request_created) {
+	if (!h->out_created) {
 		generr(h, "Please call rad_create_request()"
 		    " before putting attributes");
 		return -1;
 	}
 
-	if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
+	if (h->out[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
 		if (type == RAD_EAP_MESSAGE) {
 			generr(h, "EAP-Message attribute is not valid"
 			    " in accounting requests");
@@ -858,14 +1050,14 @@ rad_put_message_authentic(struct rad_han
 #ifdef WITH_SSL
 	u_char md_zero[MD5_DIGEST_LENGTH];
 
-	if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
+	if (h->out[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
 		generr(h, "Message-Authenticator is not valid"
 		    " in accounting requests");
 		return -1;
 	}
 
 	if (h->authentic_pos == 0) {
-		h->authentic_pos = h->req_len;
+		h->authentic_pos = h->out_len;
 		memset(md_zero, 0, sizeof(md_zero));
 		return (put_raw_attr(h, RAD_MESSAGE_AUTHENTIC, md_zero,
 		    sizeof(md_zero)));
@@ -1041,7 +1233,7 @@ rad_put_vendor_attr(struct rad_handle *h
 	struct vendor_attribute *attr;
 	int res;
 
-	if (!h->request_created) {
+	if (!h->out_created) {
 		generr(h, "Please call rad_create_request()"
 		    " before putting attributes");
 		return -1;
@@ -1088,7 +1280,7 @@ rad_request_authenticator(struct rad_han
 {
 	if (len < LEN_AUTH)
 		return (-1);
-	memcpy(buf, h->request + POS_AUTH, LEN_AUTH);
+	memcpy(buf, h->out + POS_AUTH, LEN_AUTH);
 	if (len > LEN_AUTH)
 		buf[LEN_AUTH] = '\0';
 	return (LEN_AUTH);

Modified: head/lib/libradius/radlib.h
==============================================================================
--- head/lib/libradius/radlib.h	Fri Sep 11 02:07:24 2009	(r197085)
+++ head/lib/libradius/radlib.h	Fri Sep 11 11:42:56 2009	(r197086)
@@ -42,6 +42,12 @@
 #define RAD_ACCOUNTING_REQUEST		4
 #define RAD_ACCOUNTING_RESPONSE		5
 #define RAD_ACCESS_CHALLENGE		11
+#define RAD_DISCONNECT_REQUEST		40
+#define RAD_DISCONNECT_ACK		41
+#define RAD_DISCONNECT_NAK		42
+#define RAD_COA_REQUEST			43
+#define RAD_COA_ACK			44
+#define RAD_COA_NAK			45
 
 /* Attribute types and values */
 #define RAD_USER_NAME			1	/* String */
@@ -179,6 +185,8 @@
 #define	RAD_ACCT_MULTI_SESSION_ID	50	/* String */
 #define	RAD_ACCT_LINK_COUNT		51	/* Integer */
 
+#define	RAD_ERROR_CAUSE			101	/* Integer */
+
 struct rad_handle;
 struct timeval;
 
@@ -192,6 +200,7 @@ int			 rad_config(struct rad_handle *, c
 int			 rad_continue_send_request(struct rad_handle *, int,
 			    int *, struct timeval *);
 int			 rad_create_request(struct rad_handle *, int);
+int			 rad_create_response(struct rad_handle *, int);
 struct in_addr		 rad_cvt_addr(const void *);
 u_int32_t		 rad_cvt_int(const void *);
 char			*rad_cvt_string(const void *, size_t);
@@ -209,7 +218,10 @@ int			 rad_put_string(struct rad_handle 
 int			 rad_put_message_authentic(struct rad_handle *);
 ssize_t			 rad_request_authenticator(struct rad_handle *, char *,
 			    size_t);
+int			 rad_receive_request(struct rad_handle *);
 int			 rad_send_request(struct rad_handle *);
+int			 rad_send_response(struct rad_handle *);
+struct rad_handle	*rad_server_open(int fd);
 const char		*rad_server_secret(struct rad_handle *);
 const char		*rad_strerror(struct rad_handle *);
 u_char			*rad_demangle(struct rad_handle *, const void *,

Modified: head/lib/libradius/radlib_private.h
==============================================================================
--- head/lib/libradius/radlib_private.h	Fri Sep 11 02:07:24 2009	(r197085)
+++ head/lib/libradius/radlib_private.h	Fri Sep 11 11:42:56 2009	(r197086)
@@ -38,6 +38,7 @@
 /* Handle types */
 #define RADIUS_AUTH		0   /* RADIUS authentication, default */
 #define RADIUS_ACCT		1   /* RADIUS accounting */
+#define RADIUS_SERVER		2   /* RADIUS server */
 
 /* Defaults */
 #define MAXTRIES		3
@@ -75,18 +76,18 @@ struct rad_handle {
 	int		 num_servers;	/* Number of valid server entries */
 	int		 ident;		/* Current identifier value */
 	char		 errmsg[ERRSIZE];	/* Most recent error message */
-	unsigned char	 request[MSGSIZE];	/* Request to send */
-	char	 	 request_created; /* rad_create_request() called? */
-	int		 req_len;	/* Length of request */
+	unsigned char	 out[MSGSIZE];	/* Request to send */
+	char		 out_created;	/* rad_create_request() called? */
+	int		 out_len;	/* Length of request */
 	char		 pass[PASSSIZE];	/* Cleartext password */
 	int		 pass_len;	/* Length of cleartext password */
 	int		 pass_pos;	/* Position of scrambled password */
-	char	 	 chap_pass;	/* Have we got a CHAP_PASSWORD ? */
+	char		 chap_pass;	/* Have we got a CHAP_PASSWORD ? */
 	int		 authentic_pos;	/* Position of message authenticator */
 	char		 eap_msg;	/* Are we an EAP Proxy? */
-	unsigned char	 response[MSGSIZE];	/* Response received */
-	int		 resp_len;	/* Length of response */
-	int		 resp_pos;	/* Current position scanning attrs */
+	unsigned char	 in[MSGSIZE];	/* Response received */
+	int		 in_len;	/* Length of response */
+	int		 in_pos;	/* Current position scanning attrs */
 	int		 total_tries;	/* How many requests we'll send */
 	int		 try;		/* How many requests we've sent */
 	int		 srv;		/* Server number we did last */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200909111142.n8BBgvIV051117>