Keep Proxy-State attributes in all replies to clients.
authorLinus Nordberg <linus@nordberg.se>
Wed, 28 Aug 2013 11:48:49 +0000 (13:48 +0200)
committerLinus Nordberg <linus@nordberg.se>
Thu, 5 Sep 2013 13:26:11 +0000 (15:26 +0200)
Closes RADSECPROXY-52.

ChangeLog
list.c
list.h
radmsg.c
radmsg.h
radsecproxy.c

index 0f0240e..0d9f9a5 100644 (file)
--- 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 (file)
--- a/list.c
+++ b/list.c
 #include <string.h>
 #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 (file)
--- 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);
 
index 0a46e71..e422f90 100644 (file)
--- 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;
index 8219a5c..074f752 100644 (file)
--- 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 *);
 
index a3a4999..b7b2063 100644 (file)
@@ -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;
     }