# HG changeset patch # User Sebastien Decugis # Date 1243577069 -32400 # Node ID 9d9c37868957ee47bc165d0e1903848e8f76e593 # Parent 0bd2a40ca008f17fb67ae14505228e3f53bc3299 Added code to send RADIUS answers diff -r 0bd2a40ca008 -r 9d9c37868957 extensions/radius_gw/radius_gw.h --- 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); diff -r 0bd2a40ca008 -r 9d9c37868957 extensions/radius_gw/rgw_clients.c --- 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; +} + + diff -r 0bd2a40ca008 -r 9d9c37868957 extensions/radius_gw/rgw_extensions.c --- 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) { diff -r 0bd2a40ca008 -r 9d9c37868957 extensions/radius_gw/rgw_msg.c --- 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; diff -r 0bd2a40ca008 -r 9d9c37868957 extensions/radius_gw/rgw_servers.c --- 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;