From: Alan T. DeKok Date: Fri, 4 May 2018 16:54:56 +0000 (-0400) Subject: added fr_vmps_encode() X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8df3306edd77eba732a43d539b5eae87ebe6c297;p=thirdparty%2Ffreeradius-server.git added fr_vmps_encode() --- diff --git a/src/modules/proto_vmps/proto_vmps.c b/src/modules/proto_vmps/proto_vmps.c index c4751ddd349..381e9f98fa7 100644 --- a/src/modules/proto_vmps/proto_vmps.c +++ b/src/modules/proto_vmps/proto_vmps.c @@ -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; diff --git a/src/modules/proto_vmps/vqp.c b/src/modules/proto_vmps/vqp.c index 70ba8361faa..8fc6a876cf5 100644 --- a/src/modules/proto_vmps/vqp.c +++ b/src/modules/proto_vmps/vqp.c @@ -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); diff --git a/src/modules/proto_vmps/vqp.h b/src/modules/proto_vmps/vqp.h index 9c9359d7961..16a9255e5d9 100644 --- a/src/modules/proto_vmps/vqp.h +++ b/src/modules/proto_vmps/vqp.h @@ -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