]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
pass dbuff && packet_ctx to encode function
authorAlan T. DeKok <aland@freeradius.org>
Sun, 11 Aug 2024 18:18:25 +0000 (14:18 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Sun, 11 Aug 2024 18:18:25 +0000 (14:18 -0400)
which makes it easier to add more functionality

src/listen/radius/proto_radius.c
src/modules/rlm_radius/rlm_radius_udp.c
src/protocols/radius/base.c
src/protocols/radius/encode.c
src/protocols/radius/packet.c
src/protocols/radius/radius.h

index 2d804e7bba157f090e7252de285e6e8cd91294fe..e1ea57bd92612123e6336e406ba6e355422fb59e 100644 (file)
@@ -395,6 +395,8 @@ static ssize_t mod_encode(UNUSED void const *instance, request_t *request, uint8
        fr_io_address_t const   *address = track->address;
        ssize_t                 data_len;
        fr_client_t const       *client;
+       fr_radius_ctx_t         common_ctx = {};
+       fr_radius_encode_ctx_t  encode_ctx;
 
        /*
         *      Process layer NAK, or "Do not respond".
@@ -457,9 +459,23 @@ static ssize_t mod_encode(UNUSED void const *instance, request_t *request, uint8
                request->reply->socket.inet.src_ipaddr = client->src_ipaddr;
        }
 
-       data_len = fr_radius_encode(buffer, buffer_len, request->packet->data,
-                                   client->secret, talloc_array_length(client->secret) - 1,
-                                   request->reply->code, request->reply->id, &request->reply_pairs);
+       common_ctx = (fr_radius_ctx_t) {
+               .secret = client->secret,
+               .secret_length = talloc_array_length(client->secret) - 1,
+       };
+       encode_ctx = (fr_radius_encode_ctx_t) {
+               .common = &common_ctx,
+               .request_authenticator = request->packet->data + 4,
+               .rand_ctx = (fr_fast_rand_t) {
+                       .a = fr_rand(),
+                       .b = fr_rand(),
+               },
+               .request_code = request->packet->data[0],
+               .code = request->reply->code,
+               .id = request->reply->id,
+       };
+
+       data_len = fr_radius_encode(&FR_DBUFF_TMP(buffer, buffer_len), &request->reply_pairs, &encode_ctx);
        if (data_len < 0) {
                RPEDEBUG("Failed encoding RADIUS reply");
                return -1;
index efb72ecad2a14efa6051ec91f262e08fab6e1f16..46303a216e6b3126e41933054f29d2d8e6ea2dfb 100644 (file)
@@ -1209,6 +1209,7 @@ static int encode(rlm_radius_udp_t const *inst, request_t *request, udp_request_
        uint8_t                 *msg = NULL;
        int                     message_authenticator = u->require_message_authenticator * (RADIUS_MESSAGE_AUTHENTICATOR_LENGTH + 2);
        int                     proxy_state = 6;
+       fr_radius_encode_ctx_t  encode_ctx;
 
        fr_assert(inst->parent->allowed[u->code]);
        fr_assert(!u->packet);
@@ -1237,19 +1238,8 @@ static int encode(rlm_radius_udp_t const *inst, request_t *request, udp_request_
        switch (u->code) {
        case FR_RADIUS_CODE_ACCESS_REQUEST:
        case FR_RADIUS_CODE_STATUS_SERVER:
-       {
-               size_t i;
-               uint32_t hash, base;
-
                message_authenticator = RADIUS_MESSAGE_AUTHENTICATOR_LENGTH + 2;
-
-               base = fr_rand();
-               for (i = 0; i < RADIUS_AUTH_VECTOR_LENGTH; i += sizeof(uint32_t)) {
-                       hash = fr_rand() ^ base;
-                       memcpy(u->packet + RADIUS_AUTH_VECTOR_OFFSET + i, &hash, sizeof(hash));
-               }
-       }
-               FALL_THROUGH;
+               break;
 
        default:
                break;
@@ -1284,13 +1274,22 @@ static int encode(rlm_radius_udp_t const *inst, request_t *request, udp_request_
         */
        fr_assert(u->packet_len >= (size_t) (RADIUS_HEADER_LENGTH + proxy_state + message_authenticator));
 
+       encode_ctx = (fr_radius_encode_ctx_t) {
+               .common = &inst->common_ctx,
+               .rand_ctx = (fr_fast_rand_t) {
+                       .a = fr_rand(),
+                       .b = fr_rand(),
+               },
+               .code = u->code,
+               .id = id,
+       };
+
        /*
         *      Encode it, leaving room for Proxy-State and
         *      Message-Authenticator if necessary.
         */
-       packet_len = fr_radius_encode(u->packet, u->packet_len - (proxy_state + message_authenticator), NULL,
-                                     inst->secret, talloc_array_length(inst->secret) - 1,
-                                     u->code, id, &request->request_pairs);
+       packet_len = fr_radius_encode(&FR_DBUFF_TMP(u->packet, u->packet_len - (proxy_state + message_authenticator)),
+                                     &request->request_pairs, &encode_ctx);
        if (fr_pair_encode_is_error(packet_len)) {
                RPERROR("Failed encoding packet");
 
index f7eaf6ffd7e2f9b3dced3d28b26d5261e27f7271..07090faefbf5d266a227dad9c0eeb7bdabe4b2c0 100644 (file)
@@ -910,41 +910,29 @@ static const bool disallow_tunnel_passwords[FR_RADIUS_CODE_MAX] = {
        [ FR_RADIUS_CODE_PROTOCOL_ERROR ] = true,
 };
 
-ssize_t fr_radius_encode(uint8_t *packet, size_t packet_len, uint8_t const *original,
-                        char const *secret, size_t secret_len, int code, int id, fr_pair_list_t *vps)
+ssize_t fr_radius_encode(fr_dbuff_t *dbuff, fr_pair_list_t *vps, fr_radius_encode_ctx_t *packet_ctx)
 {
        ssize_t                 slen;
        fr_pair_t const         *vp;
        fr_dcursor_t            cursor;
-       fr_radius_ctx_t         common_ctx = {};
-       fr_radius_encode_ctx_t  packet_ctx = {};
        fr_dbuff_t              work_dbuff, length_dbuff;
 
-       common_ctx.secret = secret;
-       common_ctx.secret_length = secret_len;
-
-       packet_ctx.common = &common_ctx;
-       if (original) {
-               packet_ctx.request_authenticator = original + 4;
-       } else {
-               packet_ctx.request_authenticator = packet + 4;
-       }
-       packet_ctx.rand_ctx.a = fr_rand();
-       packet_ctx.rand_ctx.b = fr_rand();
-       packet_ctx.disallow_tunnel_passwords = disallow_tunnel_passwords[code];
+       packet_ctx->disallow_tunnel_passwords = disallow_tunnel_passwords[packet_ctx->request_code];
 
        /*
         *      The RADIUS header can't do more than 64K of data.
         */
-       work_dbuff = FR_DBUFF_TMP(packet, packet_len);
+       work_dbuff = FR_DBUFF_MAX(dbuff, 65535);
 
-       FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, code, id);
+       FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, packet_ctx->code, packet_ctx->id);
        length_dbuff = FR_DBUFF(&work_dbuff);
        FR_DBUFF_IN_RETURN(&work_dbuff, (uint16_t) RADIUS_HEADER_LENGTH);
 
-       switch (code) {
+       switch (packet_ctx->code) {
        case FR_RADIUS_CODE_ACCESS_REQUEST:
        case FR_RADIUS_CODE_STATUS_SERVER:
+               packet_ctx->request_authenticator = fr_dbuff_current(&work_dbuff);
+
                /*
                 *      Allow over-rides of the authentication vector for testing.
                 */
@@ -969,11 +957,11 @@ ssize_t fr_radius_encode(uint8_t *packet, size_t packet_len, uint8_t const *orig
        case FR_RADIUS_CODE_DISCONNECT_NAK:
        case FR_RADIUS_CODE_PROTOCOL_ERROR:
        case FR_RADIUS_CODE_ACCESS_ACCEPT:
-               if (!original) {
+               if (!packet_ctx->request_authenticator) {
                        fr_strerror_const("Cannot encode response without request");
                        return -1;
                }
-               FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, original + 4, RADIUS_AUTH_VECTOR_LENGTH);
+               FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, packet_ctx->request_authenticator, RADIUS_AUTH_VECTOR_LENGTH);
                break;
 
        case FR_RADIUS_CODE_ACCOUNTING_REQUEST:
@@ -988,11 +976,13 @@ ssize_t fr_radius_encode(uint8_t *packet, size_t packet_len, uint8_t const *orig
                 *      to say "don't do that!"
                 */
        case FR_RADIUS_CODE_COA_REQUEST:
+               packet_ctx->request_authenticator = fr_dbuff_current(&work_dbuff);
+
                FR_DBUFF_MEMSET_RETURN(&work_dbuff, 0, RADIUS_AUTH_VECTOR_LENGTH);
                break;
 
        default:
-               fr_strerror_printf("Cannot encode unknown packet code %d", code);
+               fr_strerror_printf("Cannot encode unknown packet code %d", packet_ctx->code);
                return -1;
        }
 
@@ -1001,9 +991,9 @@ ssize_t fr_radius_encode(uint8_t *packet, size_t packet_len, uint8_t const *orig
         *      Original-Packet-Code manually.  If the user adds it
         *      later themselves, well, too bad.
         */
-       if (code == FR_RADIUS_CODE_PROTOCOL_ERROR) {
+       if (packet_ctx->code == FR_RADIUS_CODE_PROTOCOL_ERROR) {
                FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, FR_EXTENDED_ATTRIBUTE_1, 0x07, 0x04 /* Original-Packet-Code */,
-                                        0x00, 0x00, 0x00, original[0]);
+                                        0x00, 0x00, 0x00, packet_ctx->request_code);
        }
 
        /*
@@ -1016,7 +1006,7 @@ ssize_t fr_radius_encode(uint8_t *packet, size_t packet_len, uint8_t const *orig
                /*
                 *      Encode an individual VP
                 */
-               slen = fr_radius_encode_pair(&work_dbuff, &cursor, &packet_ctx);
+               slen = fr_radius_encode_pair(&work_dbuff, &cursor, packet_ctx);
                if (slen < 0) return slen;
        } /* done looping over all attributes */
 
@@ -1028,7 +1018,7 @@ ssize_t fr_radius_encode(uint8_t *packet, size_t packet_len, uint8_t const *orig
 
        FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "%s encoded packet", __FUNCTION__);
 
-       return fr_dbuff_used(&work_dbuff);
+       return fr_dbuff_set(dbuff, &work_dbuff);
 }
 
 ssize_t        fr_radius_decode(TALLOC_CTX *ctx, fr_pair_list_t *out,
index 20cc6deb67424ebc3a353bb5688e25bbb0fbe21a..2c3b438e5adc89e324820039cac78dcc43b483f9 100644 (file)
@@ -1738,12 +1738,13 @@ static ssize_t fr_radius_encode_proto(TALLOC_CTX *ctx, fr_pair_list_t *vps, uint
                }
        }
 
+       packet_ctx->code = packet_type;
+
        /*
         *      @todo - pass in packet_ctx to this function, so that we
         *      can leverage a consistent random number generator.
         */
-       slen = fr_radius_encode(data, data_len, NULL, packet_ctx->common->secret, talloc_array_length(packet_ctx->common->secret) - 1,
-                               packet_type, 0, vps);
+       slen = fr_radius_encode(&FR_DBUFF_TMP(data, data_len), vps, packet_ctx);
        if (slen <= 0) return slen;
 
        if (fr_radius_sign(data, NULL, (uint8_t const *) packet_ctx->common->secret, talloc_array_length(packet_ctx->common->secret) - 1) < 0) {
index 511ebe2bce7d034340ec605b4e35813e3e9cc48f..5c41f797379280cba425b7405acb7e03dba1be27 100644 (file)
@@ -52,8 +52,9 @@ typedef struct {
 ssize_t fr_packet_encode(fr_packet_t *packet, fr_pair_list_t *list,
                                fr_packet_t const *original, char const *secret)
 {
-       uint8_t const *original_data;
        ssize_t slen;
+       fr_radius_ctx_t common = {};
+       fr_radius_encode_ctx_t packet_ctx;
 
        /*
         *      A 4K packet, aligned on 64-bits.
@@ -64,19 +65,22 @@ ssize_t fr_packet_encode(fr_packet_t *packet, fr_pair_list_t *list,
        if (fr_debug_lvl >= L_DBG_LVL_4) fr_packet_log_hex(&default_log, packet);
 #endif
 
-       if (original) {
-               original_data = original->data;
-       } else {
-               original_data = NULL;
-       }
-
-       /*
-        *      This has to be initialized for Access-Request packets
-        */
-       memcpy(data + 4, packet->vector, sizeof(packet->vector));
-
-       slen = fr_radius_encode(data, sizeof(data), original_data, secret, talloc_array_length(secret) - 1,
-                               packet->code, packet->id, list);
+       common.secret = secret;
+       common.secret_length = talloc_array_length(secret) - 1;
+
+       packet_ctx = (fr_radius_encode_ctx_t) {
+               .common = &common,
+               .request_authenticator = original ? original->data + 4 : NULL,
+               .rand_ctx = (fr_fast_rand_t) {
+                       .a = fr_rand(),
+                       .b = fr_rand(),
+               },
+               .request_code = original ? original->data[0] : 0,
+               .code = packet->code,
+               .id = packet->id,
+       };
+
+       slen = fr_radius_encode(&FR_DBUFF_TMP(data, sizeof(data)), list, &packet_ctx);
        if (slen < 0) return slen;
 
        /*
index 852714c80d65081f0153350a6c4343254c595686..ce8cdaa49edf64ffd0d4b8e725905027e3f1aa18 100644 (file)
@@ -156,6 +156,11 @@ typedef struct {
 
        uint8_t                 tag;                    //!< current tag for encoding
 
+       uint8_t                 request_code;
+
+       uint8_t                 code;
+       uint32_t                id;
+
        bool                    disallow_tunnel_passwords; //!< not all packets can have tunnel passwords
        bool                    seen_message_authenticator;
 } fr_radius_encode_ctx_t;
@@ -211,8 +216,7 @@ ssize_t             fr_radius_ascend_secret(fr_dbuff_t *dbuff, uint8_t const *in, size_t in
 
 ssize_t                fr_radius_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, unsigned int *code);
 
-ssize_t                fr_radius_encode(uint8_t *packet, size_t packet_len, uint8_t const *original,
-                                char const *secret, size_t secret_len, int code, int id, fr_pair_list_t *vps);
+ssize_t                fr_radius_encode(fr_dbuff_t *dbuff, fr_pair_list_t *vps, fr_radius_encode_ctx_t *packet_ctx) CC_HINT(nonnull);
 
 ssize_t                fr_radius_decode(TALLOC_CTX *ctx, fr_pair_list_t *out,
                                 uint8_t *packet, size_t packet_len,