From 506b4eea8641e69ccf1ad35c185346299019afda Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 28 Aug 2013 13:48:49 +0200 Subject: [PATCH] Keep Proxy-State attributes in all replies to clients. Closes RADSECPROXY-52. --- ChangeLog | 5 +++++ list.c | 39 ++++++++++++++++++++++++++++----------- list.h | 3 +++ radmsg.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ radmsg.h | 5 +++++ radsecproxy.c | 18 +++++++++++++----- 6 files changed, 105 insertions(+), 16 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0f0240e..0d9f9a5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2013-09-05 1.6.4 + Bug fixes: + - Keeping Proxy-State attributes in all replies to clients + (RADSECPROXY-52). Reported by Stefan Winter. + 2013-09-05 1.6.3 Enhancements: - Threads are allocated with a 32 KB stack rather than what diff --git a/list.c b/list.c index 58ab7aa..be59fff 100644 --- a/list.c +++ b/list.c @@ -10,29 +10,46 @@ #include #include "list.h" -/* allocates and initialises list structure; returns NULL if malloc fails */ -struct list *list_create() { - struct list *list = malloc(sizeof(struct list)); - if (list) - memset(list, 0, sizeof(struct list)); - return list; -} - -/* frees all memory associated with the list */ -void list_destroy(struct list *list) { +/* Private helper functions. */ +static void list_free_helper_(struct list *list, int free_data_flag) { struct list_node *node, *next; if (!list) return; for (node = list->first; node; node = next) { - free(node->data); + if (free_data_flag) + free(node->data); next = node->next; free(node); } free(list); } +/* Public functions. */ + +/* allocates and initialises list structure; returns NULL if malloc fails */ +struct list *list_create() { + struct list *list = malloc(sizeof(struct list)); + if (list) + memset(list, 0, sizeof(struct list)); + return list; +} + +/* frees all memory associated with the list + note that the data pointed at from each node is also freed + use list_free() to free only the memory used by the list itself */ +void list_destroy(struct list *list) { + list_free_helper_(list, 1); +} + +/* frees the meory used by the list itself + note that the data pointed at from each node is not freed + use list_destroy() to free all the data associated with the list */ +void list_free(struct list *list) { + list_free_helper_(list, 0); +} + /* appends entry to list; returns 1 if ok, 0 if malloc fails */ int list_push(struct list *list, void *data) { struct list_node *node; diff --git a/list.h b/list.h index 80c0128..225f54f 100644 --- a/list.h +++ b/list.h @@ -28,6 +28,9 @@ struct list *list_create(); /* frees all memory associated with the list */ void list_destroy(struct list *list); +/* frees memory allocated for the list itself */ +void list_free(struct list *list); + /* appends entry to list; returns 1 if ok, 0 if malloc fails */ int list_push(struct list *list, void *data); diff --git a/radmsg.c b/radmsg.c index 0a46e71..e422f90 100644 --- a/radmsg.c +++ b/radmsg.c @@ -62,6 +62,30 @@ int radmsg_add(struct radmsg *msg, struct tlv *attr) { return list_push(msg->attrs, attr); } +/** Return a new list with all tlv's in \a msg of type \a type. The + * caller is responsible for freeing the list by calling \a + * list_free(). */ +struct list * +radmsg_getalltype(const struct radmsg *msg, uint8_t type) +{ + struct list *list = NULL; + struct list_node *node = NULL; + + if (!msg || !msg->attrs) + return NULL; + list = list_create(); + if (!list) + return NULL; + + for (node = list_first(msg->attrs); node; node = list_next(node)) + if (((struct tlv *) node->data)->t == type) + if (list_push(list, node->data) != 1) { + list_free(list); + return NULL; + } + return list; +} + /* returns first tlv of the given type */ struct tlv *radmsg_gettype(struct radmsg *msg, uint8_t type) { struct list_node *node; @@ -77,6 +101,33 @@ struct tlv *radmsg_gettype(struct radmsg *msg, uint8_t type) { return NULL; } +/** Copy all attributes of type \a type from \a src to \a dst. + * + * If all attributes were copied successfully, the number of + * attributes copied is returned. + * + * If copying failed, a negative number is returned. The number + * returned is 0 minus the number of attributes successfully copied + * before the failure. */ +int radmsg_copy_attrs(struct radmsg *dst, + const struct radmsg *src, + uint8_t type) +{ + struct list_node *node = NULL; + struct list *list = radmsg_getalltype(src, type); + int n = 0; + + for (node = list_first(list); node; node = list_next(node)) { + if (radmsg_add(dst, (struct tlv *) node->data) != 1) { + n = -n; + break; + } + n++; + } + list_free(list); + return n; +} + int _checkmsgauth(unsigned char *rad, uint8_t *authattr, uint8_t *secret) { static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; static unsigned char first = 1; diff --git a/radmsg.h b/radmsg.h index 8219a5c..074f752 100644 --- a/radmsg.h +++ b/radmsg.h @@ -20,6 +20,7 @@ #define RAD_Attr_Reply_Message 18 #define RAD_Attr_Vendor_Specific 26 #define RAD_Attr_Calling_Station_Id 31 +#define RAD_Proxy_State 33 #define RAD_Attr_Tunnel_Password 69 #define RAD_Attr_Message_Authenticator 80 @@ -37,6 +38,10 @@ void radmsg_free(struct radmsg *); struct radmsg *radmsg_init(uint8_t, uint8_t, uint8_t *); int radmsg_add(struct radmsg *, struct tlv *); struct tlv *radmsg_gettype(struct radmsg *, uint8_t); +struct list *radmsg_getalltype(const struct radmsg *msg, uint8_t type); +int radmsg_copy_attrs(struct radmsg *dst, + const struct radmsg *src, + uint8_t type); uint8_t *radmsg2buf(struct radmsg *msg, uint8_t *); struct radmsg *buf2radmsg(uint8_t *, uint8_t *, uint8_t *); diff --git a/radsecproxy.c b/radsecproxy.c index a3a4999..b7b2063 100644 --- a/radsecproxy.c +++ b/radsecproxy.c @@ -1287,7 +1287,9 @@ void acclog(struct radmsg *msg, struct client *from) { } } -void respond(struct request *rq, uint8_t code, char *message) { +void respond(struct request *rq, uint8_t code, char *message, + int copy_proxystate_flag) +{ struct radmsg *msg; struct tlv *attr; @@ -1305,6 +1307,12 @@ void respond(struct request *rq, uint8_t code, char *message) { return; } } + if (copy_proxystate_flag) { + if (radmsg_copy_attrs(msg, rq->msg, RAD_Proxy_State) < 0) { + debug(DBG_ERR, "%s: unable to copy all Proxy-State attributes", + __func__); + } + } radmsg_free(rq->msg); rq->msg = msg; @@ -1474,7 +1482,7 @@ int radsrv(struct request *rq) { goto exit; if (msg->code == RAD_Status_Server) { - respond(rq, RAD_Access_Accept, NULL); + respond(rq, RAD_Access_Accept, NULL, 0); goto exit; } @@ -1493,7 +1501,7 @@ int radsrv(struct request *rq) { if (!attr) { if (msg->code == RAD_Accounting_Request) { acclog(msg, from); - respond(rq, RAD_Accounting_Response, NULL); + respond(rq, RAD_Accounting_Response, NULL, 1); } else debug(DBG_INFO, "radsrv: ignoring access request, no username attribute"); goto exit; @@ -1519,10 +1527,10 @@ int radsrv(struct request *rq) { if (!to) { if (realm->message && msg->code == RAD_Access_Request) { debug(DBG_INFO, "radsrv: sending reject to %s (%s) for %s", from->conf->name, addr2string(from->addr), userascii); - respond(rq, RAD_Access_Reject, realm->message); + respond(rq, RAD_Access_Reject, realm->message, 1); } else if (realm->accresp && msg->code == RAD_Accounting_Request) { acclog(msg, from); - respond(rq, RAD_Accounting_Response, NULL); + respond(rq, RAD_Accounting_Response, NULL, 1); } goto exit; } -- 2.1.4