]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
added fr_vmps_encode()
authorAlan T. DeKok <aland@freeradius.org>
Fri, 4 May 2018 16:54:56 +0000 (12:54 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Fri, 4 May 2018 16:54:56 +0000 (12:54 -0400)
src/modules/proto_vmps/proto_vmps.c
src/modules/proto_vmps/vqp.c
src/modules/proto_vmps/vqp.h

index c4751ddd349223e7e2fc9960673d5e864d6d8a57..381e9f98fa7beac4d1fd57ea26dcc5ec4b86eb55 100644 (file)
@@ -348,14 +348,8 @@ static ssize_t mod_encode(void const *instance, REQUEST *request, uint8_t *buffe
        }
 #endif
 
-#if 0
        data_len = fr_vmps_encode(buffer, buffer_len, request->packet->data,
-                                   client->secret, talloc_array_length(client->secret) - 1,
-                                   request->reply->code, request->reply->id, request->reply->vps);
-#else
-       // @todo - redo vqp encode/decode as per RADIUS
-       data_len = -1;
-#endif
+                                 request->reply->code, request->reply->id, request->reply->vps);
        if (data_len < 0) {
                RPEDEBUG("Failed encoding VMPS reply");
                return -1;
index 70ba8361faa09a4526e3992a1b9d622ba995e1c4..8fc6a876cf50a9cece155415866858b63c1290f0 100644 (file)
@@ -413,6 +413,136 @@ static int contents[5][VQP_MAX_ATTRIBUTES] = {
        { 0x0c03, 0x0c08, 0,      0,      0,      0 }
 };
 
+
+ssize_t fr_vmps_encode(uint8_t *buffer, size_t buflen, uint8_t const *original,
+                      int code, uint32_t id, VALUE_PAIR *vps)
+{
+       uint8_t *attr;
+       VALUE_PAIR *vp;
+       fr_cursor_t cursor;
+
+       if (buflen < 8) {
+               fr_strerror_printf("Output buffer is too small for VMPS header.");
+               return -1;
+       }
+
+       buffer[0] = VQP_VERSION;
+       buffer[1] = code;
+       buffer[2] = 0;
+
+       /*
+        *      The number of attributes is hard-coded.
+        */
+       if ((code == 1) || (code == 3)) {
+               uint32_t sequence;
+
+               buffer[3] = VQP_MAX_ATTRIBUTES;
+
+               sequence = htonl(id);
+               memcpy(buffer + 4, &sequence, 4);
+       } else {
+               if (!original) {
+                       fr_strerror_printf("Cannot send VQP response without request");
+                       return -1;
+               }
+
+               /*
+                *      Packet Sequence Number
+                */
+               memcpy(buffer + 4, original + 4, 4);
+
+               buffer[3] = 2;
+       }
+
+       attr = buffer + 8;
+
+       /*
+        *      Encode the VP's.
+        */
+       fr_cursor_init(&cursor, &vps);
+       while ((vp = fr_cursor_current(&cursor))) {
+               size_t len;
+
+               if (vp->da->flags.internal) goto next;
+
+               /*
+                *      Skip non-VMPS attributes/
+                */
+               if (!((vp->da->attr >= 0x2c01) && (vp->da->attr <= 0x2c08))) goto next;
+
+               if (attr >= (buffer + buflen)) break;
+
+               debug_pair(vp);
+
+               switch (vp->vp_type) {
+               case FR_TYPE_IPV4_ADDR:
+                       len = fr_vqp_attr_sizes[vp->vp_type][0];
+                       break;
+
+               case FR_TYPE_ETHERNET:
+                       len = fr_vqp_attr_sizes[vp->vp_type][0];
+                       break;
+
+               case FR_TYPE_OCTETS:
+               case FR_TYPE_STRING:
+                       len = vp->vp_length;
+                       break;
+
+               default:
+                       return -1;
+               }
+
+               /*
+                *      If the attribute overflows the buffer, stop.
+                */
+               if ((attr + 6 + len) >= (buffer + buflen)) break;
+
+               /*
+                *      Type.  Note that we look at only the lower 8
+                *      bits, as the upper 8 bits have been hacked.
+                *      See also dictionary.vqp
+                */
+               attr[0] = 0;
+               attr[1] = 0;
+               attr[2] = 0x0c;
+               attr[3] = vp->da->attr & 0xff;
+
+               /* Length */
+               attr[4] = (len >> 8) & 0xff;
+               attr[5] = len & 0xff;
+
+               attr += 6;
+
+               /* Data */
+               switch (vp->vp_type) {
+               case FR_TYPE_IPV4_ADDR:
+                       memcpy(attr, &vp->vp_ipv4addr, len);
+                       attr += len;
+                       break;
+
+               case FR_TYPE_ETHERNET:
+                       memcpy(attr, vp->vp_ether, len);
+                       attr += len;
+                       break;
+
+               case FR_TYPE_OCTETS:
+               case FR_TYPE_STRING:
+                       memcpy(attr, vp->vp_octets, len);
+                       attr += len;
+                       break;
+
+               default:
+                       return -1;
+               }
+
+next:
+               fr_cursor_next(&cursor);
+       }
+
+       return attr - buffer;
+}
+
+
 int vqp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
 {
        int             i, code, length;
@@ -427,7 +557,6 @@ int vqp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
 
        if (packet->data) return 0;
 
-
        code = packet->code;
        if (!code) {
                vp = fr_pair_find_by_num(packet->vps, 0, FR_VQP_PACKET_TYPE, TAG_ANY);
index 9c9359d7961eceee47ecf4b74b784320ce75b758..16a9255e5d9687d3f64a421b1d3a180c1ad50f3a 100644 (file)
@@ -43,6 +43,9 @@ int vqp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original);
 ssize_t vqp_packet_size(uint8_t const *data, size_t data_len);
 void fr_vmps_print_hex(FILE *fp, uint8_t const *packet, size_t packet_len);
 
+ssize_t fr_vmps_encode(uint8_t *buffer, size_t buflen, uint8_t const *original,
+                      int code, uint32_t id, VALUE_PAIR *vps) CC_HINT(nonnull(1));
+
 extern char const *fr_vmps_codes[FR_MAX_VMPS_CODE];
 
 #ifdef __cplusplus