changeset 390:9d9c37868957

Added code to send RADIUS answers
author Sebastien Decugis <sdecugis@nict.go.jp>
date Fri, 29 May 2009 15:04:29 +0900
parents 0bd2a40ca008
children 9907abba8681
files extensions/radius_gw/radius_gw.h extensions/radius_gw/rgw_clients.c extensions/radius_gw/rgw_extensions.c extensions/radius_gw/rgw_msg.c extensions/radius_gw/rgw_servers.c
diffstat 5 files changed, 103 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/extensions/radius_gw/radius_gw.h	Fri May 29 13:50:31 2009 +0900
+++ b/extensions/radius_gw/radius_gw.h	Fri May 29 15:04:29 2009 +0900
@@ -70,6 +70,7 @@
 int rgw_servers_init(void);
 int rgw_servers_start(void);
 void rgw_servers_dump(void);
+int rgw_servers_send(int type, unsigned char *buf, size_t buflen, struct sockaddr *to, uint16_t to_port);
 void rgw_servers_fini(void);
 
 
@@ -111,6 +112,7 @@
 int rgw_clients_check_dup(struct rgw_radius_msg_meta **msg, struct rgw_client *cli);
 int rgw_clients_check_origin(struct rgw_radius_msg_meta *msg, struct rgw_client *cli);
 int rgw_clients_get_origin(struct rgw_client *cli, char * oh, size_t oh_len, char * or, size_t or_len,  char **fqdn, char **realm, int strict);
+int rgw_client_finish_send(struct radius_msg ** msg, struct rgw_radius_msg_meta * req, struct rgw_client * cli);
 void rgw_clients_dispose(struct rgw_client ** ref);
 void rgw_clients_dump(void);
 void rgw_clients_fini(void);
--- a/extensions/radius_gw/rgw_clients.c	Fri May 29 13:50:31 2009 +0900
+++ b/extensions/radius_gw/rgw_clients.c	Fri May 29 15:04:29 2009 +0900
@@ -286,7 +286,7 @@
 		TRACE_DEBUG(INFO, "Received duplicated RADIUS message (id: %02hhx, port: %hu).", (*msg)->radius.hdr->identifier, ntohs((*msg)->port));
 		if (cli->last[idx].ans) {
 			/* Resend the answer */
-			ASSERT(0);
+			CHECK_FCT_DO( rgw_servers_send((*msg)->serv_type, cli->last[idx].ans->buf, cli->last[idx].ans->buf_used, cli->sa, (*msg)->port),  );
 		}
 		rgw_msg_free(msg);
 	} else {
@@ -601,3 +601,49 @@
 	
 }
 
+int rgw_client_finish_send(struct radius_msg ** msg, struct rgw_radius_msg_meta * req, struct rgw_client * cli)
+{
+	int idx;
+	
+	TRACE_ENTRY("%p %p %p", msg, req, cli);
+	CHECK_PARAMS( msg && *msg && cli );
+	
+	if (!req) {
+		/* We don't support this case yet */
+		ASSERT(0);
+		return ENOTSUP;
+	}
+	
+	if (radius_msg_finish_srv(*msg, cli->key.data, cli->key.len, req->radius.hdr->authenticator)) {
+		TRACE_DEBUG(INFO, "An error occurred while preparing the RADIUS answer");
+		radius_msg_free(*msg);
+		free(*msg);
+		*msg = NULL;
+		return EINVAL;
+	}
+	
+	/* Debug */
+	TRACE_DEBUG(FULL, "RADIUS message ready for sending:");
+	rgw_msg_dump((struct rgw_radius_msg_meta *)*msg);
+
+	/* Send the message */
+	CHECK_FCT( rgw_servers_send(req->serv_type, (*msg)->buf, (*msg)->buf_used, cli->sa, req->port) );
+
+	/* update the duplicate cache in rgw_clients */
+	if (req->serv_type == RGW_EXT_TYPE_AUTH)
+		idx = 0;
+	else
+		idx = 1;
+	if (cli->last[idx].ans) {
+		/* Free it */
+		radius_msg_free(cli->last[idx].ans);
+		free(cli->last[idx].ans);
+	}
+	cli->last[idx].ans = *msg;
+	*msg = NULL;
+	
+	/* Finished */
+	return 0;
+}
+
+
--- a/extensions/radius_gw/rgw_extensions.c	Fri May 29 13:50:31 2009 +0900
+++ b/extensions/radius_gw/rgw_extensions.c	Fri May 29 15:04:29 2009 +0900
@@ -385,15 +385,8 @@
 	}
 	
 	/* Send the radius message back if required */
-	if (((ret == -3) || (ret == -4)) && rad_ans) {
-		/* destination port: (*rad)->port */
-		/* destination ip: derived from cli */
-		/* post-processing: depends on (*rad)->serv_type */
-		/* message content: rad_ans */
-		/* update the duplicate cache in rgw_clients */
-		
-		/* not implemented */
-		ASSERT(0);
+	if (((ret == -3) || (ret == -4)) && rad_ans && rad) {
+		CHECK_FCT_DO( rgw_client_finish_send(&rad_ans, *rad, cli), /* It failed, it can't be helped... */);
 	}
 	
 	if (ret > 0) {
--- a/extensions/radius_gw/rgw_msg.c	Fri May 29 13:50:31 2009 +0900
+++ b/extensions/radius_gw/rgw_msg.c	Fri May 29 15:04:29 2009 +0900
@@ -113,7 +113,7 @@
 	return 0;
 }
 
-/* Dump a message (inspired from radius_msg_dump) */
+/* Dump a message (inspired from radius_msg_dump) -- can be used safely with a struct radius_msg as parameter (we don't dump the metadata) */
 void rgw_msg_dump(struct rgw_radius_msg_meta * msg)
 {
 	unsigned char *auth;
--- a/extensions/radius_gw/rgw_servers.c	Fri May 29 13:50:31 2009 +0900
+++ b/extensions/radius_gw/rgw_servers.c	Fri May 29 15:04:29 2009 +0900
@@ -73,6 +73,7 @@
 
 static struct servers_data {
 	int	type; /* auth or acct */
+	int	family; /* AF_INET or AF_INET6 */
 	int	sock; /* the socket number */
 	pthread_t th; /* the running server thread, or NULL */
 	char    name[10];
@@ -214,6 +215,7 @@
 					(struct sockaddr *)&sin ## _family_,					\
 					sizeof(struct sockaddr_in ## _family_) ) );				\
 			SERVERS[idx].type = _portval_;								\
+			SERVERS[idx].family = AF_INET ## _family_;						\
 			snprintf(&SERVERS[idx].name[0], sizeof(SERVERS[idx].name), # _type_ "/ip" #_family_);	\
 			CHECK_POSIX( pthread_create(&SERVERS[idx].th, NULL, server_thread, &SERVERS[idx]) );	\
 			idx++;											\
@@ -236,6 +238,55 @@
 	return 0;
 }
 
+int rgw_servers_send(int type, unsigned char *buf, size_t buflen, struct sockaddr *to, uint16_t to_port)
+{
+	int idx = 0;
+	int ret = 0;
+	struct sockaddr_storage sto;
+	size_t sto_len = 0;
+	
+	/* Find the appropriate server */
+	for (idx = 0; idx < sizeof(SERVERS) / sizeof(SERVERS[0]); idx++) {
+		if ( SERVERS[idx].sock && (type == SERVERS[idx].type) && (to->sa_family == SERVERS[idx].family) ) {
+			ret = 1;
+			break;
+		}
+	}
+	
+	if (!ret) {
+		TRACE_DEBUG(INFO, "Trying to send a message with a disabled server: %s / %s", 
+				(type == RGW_EXT_TYPE_AUTH) ? "Auth" : "Acct",
+				(to->sa_family == AF_INET)  ? "IPv4" : "IPv6");
+		return EINVAL;
+	}
+	
+	/* Prepare the destination info */
+	memset(&sto, 0, sizeofs(to));
+	if (to->sa_family == AF_INET) {
+		memcpy(&sto, to, sizeof(struct sockaddr_in));
+		((struct sockaddr_in *)&sto)->sin_port = to_port;
+		sto_len = sizeof(struct sockaddr_in);
+	} else {
+		memcpy(&sto, to, sizeof(struct sockaddr_in6));
+		((struct sockaddr_in6 *)&sto)->sin6_port = to_port;
+		sto_len = sizeof(struct sockaddr_in6);
+	}
+	
+	/* Send */
+	ret = sendto(SERVERS[idx].sock, buf, buflen, 0, (struct sockaddr *)&sto, sto_len);
+	if (ret < 0) {
+		TRACE_DEBUG(INFO, "An error occurred while sending the RADIUS message: %s", strerror(errno));
+		return errno;
+	}
+	if (ret != buflen) {
+		TRACE_DEBUG(INFO, "The message was not sent properly: %d bytes / %g", ret, buflen);
+		return EAGAIN;
+	}
+	
+	/* Done :) */
+	return 0;
+}
+
 void rgw_servers_fini(void)
 {
 	int idx = 0;
"Welcome to our mercurial repository"