diff --git a/ChangeLog b/ChangeLog index 0e24da7..3bbefa3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -19,6 +19,8 @@ Changes between 1.6.2 and the master branch Mauchle. - Timing out on TLS clients not closing the connection properly. Patch by Fabian Mauchle. + - Keeping Proxy-State attributes in all replies to clients + (RADSECPROXY-52). Reported by Stefan Winter. 2012-10-25 1.6.2 Bug fixes (security): diff --git a/list.c b/list.c index 0a193ef..d9612b8 100644 --- a/list.c +++ b/list.c @@ -5,29 +5,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 d9c5199..38169c7 100644 --- a/list.h +++ b/list.h @@ -23,6 +23,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 432f88d..0289bba 100644 --- a/radmsg.c +++ b/radmsg.c @@ -57,6 +57,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; @@ -72,6 +96,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 1bef59b..7cfcc75 100644 --- a/radmsg.h +++ b/radmsg.h @@ -15,6 +15,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 @@ -32,6 +33,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 5dfe241..563c4a8 100644 --- a/radsecproxy.c +++ b/radsecproxy.c @@ -1274,7 +1274,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; @@ -1292,6 +1294,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; @@ -1461,7 +1469,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; } @@ -1480,7 +1488,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; @@ -1506,10 +1514,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; }