]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
move to using decode_ctx for public APIs.
authorAlan T. DeKok <aland@freeradius.org>
Wed, 24 Jan 2024 17:25:52 +0000 (12:25 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Wed, 24 Jan 2024 22:02:26 +0000 (17:02 -0500)
src/listen/radius/proto_radius.c
src/modules/rlm_radius/rlm_radius_udp.c
src/protocols/radius/base.c
src/protocols/radius/decode.c
src/protocols/radius/radius.h

index d26e516fdd79c5a16c06214d3d001ceb1e710aa7..5166f816565723e21e5085327eb1870cefee2721 100644 (file)
@@ -201,7 +201,9 @@ static int mod_decode(UNUSED void const *instance, request_t *request, uint8_t *
 {
        fr_io_track_t const     *track = talloc_get_type_abort_const(request->async->packet_ctx, fr_io_track_t);
        fr_io_address_t const   *address = track->address;
-       fr_client_t const               *client;
+       fr_client_t const       *client;
+       fr_radius_ctx_t         common_ctx;
+       fr_radius_decode_ctx_t  decode_ctx;
 
        fr_assert(data[0] < FR_RADIUS_CODE_MAX);
 
@@ -214,19 +216,23 @@ static int mod_decode(UNUSED void const *instance, request_t *request, uint8_t *
 
        client = address->radclient;
 
-       /*
-        *      !client->active means a fake packet defining a dynamic client - so there will
-        *      be no secret defined yet - so can't verify.
-        */
-       if (client->active &&
-           fr_radius_verify(data, NULL, (uint8_t const *) client->secret, talloc_array_length(client->secret) - 1,
-                            client->message_authenticator) < 0) {
-               RPEDEBUG("Failed verifying packet signature.");
-               return -1;
-       }
+       common_ctx = (fr_radius_ctx_t) {
+               .secret = client->secret,
+               .secret_length = talloc_array_length(client->secret) - 1,
+       };
+
+       decode_ctx = (fr_radius_decode_ctx_t) {
+               .common = &common_ctx,
+               .tmp_ctx = talloc(request, uint8_t),
+               .end = data + data_len,
+               .verify = client->active,
+               .require_message_authenticator = client->message_authenticator,
+       };
 
        /*
-        *      Hacks for now until we have a lower-level decode routine.
+        *      The verify() routine over-writes the request packet vector.
+        *
+        *      @todo - That needs to be changed.
         */
        request->packet->code = data[0];
        request->packet->id = data[1];
@@ -237,16 +243,16 @@ static int mod_decode(UNUSED void const *instance, request_t *request, uint8_t *
        request->packet->data_len = data_len;
 
        /*
-        *      Note that we don't set a limit on max_attributes here.
-        *      That MUST be set and checked in the underlying
-        *      transport, via a call to fr_radius_ok().
+        *      !client->active means a fake packet defining a dynamic client - so there will
+        *      be no secret defined yet - so can't verify.
         */
        if (fr_radius_decode(request->request_ctx, &request->request_pairs,
-                            request->packet->data, request->packet->data_len, NULL,
-                            client->secret, talloc_array_length(client->secret) - 1) < 0) {
-               RPEDEBUG("Failed decoding packet");
+                            data, data_len, &decode_ctx) < 0) {
+               talloc_free(decode_ctx.tmp_ctx);
+               RPEDEBUG("Failed reading packet");
                return -1;
        }
+       talloc_free(decode_ctx.tmp_ctx);
 
        /*
         *      Set the rest of the fields.
index a5e6a2f6745cd89cd6dd3b5a3611c076e6618ce1..48f60c204b4e612f648ccb94df57a3fc9014d289 100644 (file)
@@ -1159,6 +1159,8 @@ static decode_fail_t decode(TALLOC_CTX *ctx, fr_pair_list_t *reply, uint8_t *res
        rlm_radius_udp_t const *inst = h->thread->inst;
        size_t                  packet_len;
        uint8_t                 code;
+       fr_radius_ctx_t         common_ctx;
+       fr_radius_decode_ctx_t  decode_ctx;
 
        *response_code = 0;     /* Initialise to keep the rest of the code happy */
 
@@ -1187,23 +1189,31 @@ static decode_fail_t decode(TALLOC_CTX *ctx, fr_pair_list_t *reply, uint8_t *res
                return DECODE_FAIL_UNKNOWN_PACKET_CODE;
        }
 
-       if (fr_radius_verify(data, request_authenticator,
-                            (uint8_t const *) inst->secret, talloc_array_length(inst->secret) - 1, false) < 0) {
-               RPWDEBUG("Ignoring response with invalid signature");
-               return DECODE_FAIL_MA_INVALID;
-       }
+       common_ctx = (fr_radius_ctx_t) {
+               .secret = inst->secret,
+               .secret_length = talloc_array_length(inst->secret) - 1,
+       };
+
+       decode_ctx = (fr_radius_decode_ctx_t) {
+               .common = &common_ctx,
+               .request_code = u->code,
+               .vector = &request_authenticator[0],
+               .tmp_ctx = talloc(ctx, uint8_t),
+               .end = data + packet_len,
+               .verify = true,
+       };
 
        /*
-        *      Decode the attributes, in the context of the reply.
-        *      This only fails if the packet is strangely malformed,
-        *      or if we run out of memory.
+        *      !client->active means a fake packet defining a dynamic client - so there will
+        *      be no secret defined yet - so can't verify.
         */
-       if (fr_radius_decode(ctx, reply, data, packet_len, request_authenticator,
-                            inst->secret, talloc_array_length(inst->secret) - 1) < 0) {
-               REDEBUG("Failed decoding attributes for packet");
-               fr_pair_list_free(reply);
+       if (fr_radius_decode(request->request_ctx, &request->request_pairs,
+                            data, data_len, &decode_ctx) < 0) {
+               talloc_free(decode_ctx.tmp_ctx);
+               RPEDEBUG("Failed reading packet");
                return DECODE_FAIL_UNKNOWN;
        }
+       talloc_free(decode_ctx.tmp_ctx);
 
        RDEBUG("Received %s ID %d length %ld reply packet on connection %s",
               fr_radius_packet_names[code], code, packet_len, h->name);
index 40246c2928d5da7203d9324752b8c13bc4e83e86..48dca3119f4ec4b0670ca547db5c8100a4cf9722 100644 (file)
@@ -973,25 +973,24 @@ ssize_t fr_radius_encode_dbuff(fr_dbuff_t *dbuff, uint8_t const *original,
        return fr_dbuff_set(dbuff, &work_dbuff);
 }
 
-/** Decode a raw RADIUS packet into VPs.
- *
- */
-ssize_t fr_radius_decode(TALLOC_CTX *ctx, fr_pair_list_t *out,
-                        uint8_t const *packet, size_t packet_len, uint8_t const *vector,
-                        char const *secret, size_t secret_len)
+ssize_t        fr_radius_decode(TALLOC_CTX *ctx, fr_pair_list_t *out,
+                        uint8_t *packet, size_t packet_len,
+                        fr_radius_decode_ctx_t *decode_ctx)
 {
        ssize_t                 slen;
        uint8_t const           *attr, *end;
-       fr_radius_ctx_t         common_ctx = {};
-       fr_radius_decode_ctx_t  packet_ctx = {};
-
-       common_ctx.secret = secret;
-       common_ctx.secret_length = secret_len;
-       memcpy(common_ctx.vector, vector ? vector : packet + 4, sizeof(common_ctx.vector));
 
-       packet_ctx.common = &common_ctx;
-       packet_ctx.tmp_ctx = talloc_init_const("tmp");
-       packet_ctx.end = packet + packet_len;
+       /*
+        *      We can skip verification for dynamic client checks, and where packets are unsigned as with
+        *      RADIUS/1.1.
+        */
+       if (decode_ctx->verify) {
+               if (fr_radius_verify(packet, decode_ctx->vector,
+                                    (uint8_t const *) decode_ctx->common->secret, decode_ctx->common->secret_length,
+                                    decode_ctx->require_message_authenticator) < 0) {
+                       return -1;
+               }
+       }
 
        attr = packet + 20;
        end = packet + packet_len;
@@ -1001,34 +1000,28 @@ ssize_t fr_radius_decode(TALLOC_CTX *ctx, fr_pair_list_t *out,
         *      he doesn't, all hell breaks loose.
         */
        while (attr < end) {
-               slen = fr_radius_decode_pair(ctx, out, attr, (end - attr), &packet_ctx);
-               if (slen < 0) {
-               fail:
-                       talloc_free(packet_ctx.tmp_ctx);
-                       talloc_free(packet_ctx.tags);
-                       return slen;
-               }
+               slen = fr_radius_decode_pair(ctx, out, attr, (end - attr), decode_ctx);
+               if (slen < 0) return slen;
 
                /*
                 *      If slen is larger than the room in the packet,
                 *      all kinds of bad things happen.
                 */
                 if (!fr_cond_assert(slen <= (end - attr))) {
-                        goto fail;
+                        return -slen;
                 }
 
                attr += slen;
-               talloc_free_children(packet_ctx.tmp_ctx);
+               talloc_free_children(decode_ctx->tmp_ctx);
        }
 
        /*
         *      We've parsed the whole packet, return that.
         */
-       talloc_free(packet_ctx.tmp_ctx);
-       talloc_free(packet_ctx.tags);
        return packet_len;
 }
 
+
 int fr_radius_init(void)
 {
        if (instance_count > 0) {
index fdf3c77f69d84aaab4e8d0557ed0864d8c26b4a0..de4e5ff4a7d386c27a524011d875b3db2ad5eac2 100644 (file)
@@ -2121,8 +2121,7 @@ static ssize_t fr_radius_decode_proto(TALLOC_CTX *ctx, fr_pair_list_t *out,
 
        test_ctx->end = data + packet_len;
 
-       return fr_radius_decode(ctx, out, data, packet_len, test_ctx->common->vector,
-                               test_ctx->common->secret, talloc_array_length(test_ctx->common->secret) - 1);
+       return fr_radius_decode(ctx, out, UNCONST(uint8_t *, data), packet_len, test_ctx);
 }
 
 static ssize_t decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *out, NDEBUG_UNUSED fr_dict_attr_t const *parent,
index c8dcc1487a0d390af38b47fd8a4fa44dda8f2bab..1e71854ee8b8561be52e393c00fdcb694248dbc9 100644 (file)
@@ -102,6 +102,54 @@ enum {
 #define flag_long_extended(_flags)   (!(_flags)->extra && (_flags)->subtype == FLAG_LONG_EXTENDED_ATTR)
 #define flag_tunnel_password(_flags) (!(_flags)->extra && (((_flags)->subtype == FLAG_ENCRYPT_TUNNEL_PASSWORD) || ((_flags)->subtype == FLAG_TAGGED_TUNNEL_PASSWORD)))
 
+typedef struct {
+       fr_pair_t       *parent;
+       fr_dcursor_t    cursor;
+} fr_radius_tag_ctx_t;
+
+typedef struct {
+       char const      *secret;
+       size_t          secret_length;
+
+       bool            add_proxy_state;                //!< do we add a Proxy-State?
+       uint64_t        my_proxy_state;                 //!< if so, this is its value
+
+       uint32_t        acct_delay_time;                //!< additional time to add to acct_delay_time
+
+       uint8_t         vector[RADIUS_AUTH_VECTOR_LENGTH]; //!< vector for authenticating the reply
+} fr_radius_ctx_t;
+
+typedef struct {
+       fr_radius_ctx_t         *common;
+
+       fr_fast_rand_t          rand_ctx;               //!< for tunnel passwords
+       int                     salt_offset;            //!< for tunnel passwords
+
+       uint8_t                 tag;                    //!< current tag for encoding
+
+       bool                    disallow_tunnel_passwords; //!< not all packets can have tunnel passwords
+       bool                    seen_message_authenticator;
+} fr_radius_encode_ctx_t;
+
+typedef struct {
+       fr_radius_ctx_t         *common;
+
+       uint8_t const           *vector;                //!< of the request packet
+
+       TALLOC_CTX              *tmp_ctx;               //!< for temporary things cleaned up during decoding
+       uint8_t const           *end;                   //!< end of the packet
+
+       uint8_t                 request_code;           //!< original code for the request.
+
+       bool                    tunnel_password_zeros;  //!< check for trailing zeros on decode
+       bool                    verify;                 //!< can skip verify for dynamic clients
+       bool                    require_message_authenticator;
+
+       fr_radius_tag_ctx_t     **tags;                 //!< for decoding tagged attributes
+       fr_pair_list_t          *tag_root;              //!< Where to insert tag attributes.
+       TALLOC_CTX              *tag_root_ctx;          //!< Where to allocate new tag attributes.
+} fr_radius_decode_ctx_t;
+
 /*
  *     protocols/radius/base.c
  */
@@ -124,8 +172,8 @@ ssize_t             fr_radius_encode_dbuff(fr_dbuff_t *dbuff, uint8_t const *original,
                                 char const *secret, UNUSED size_t secret_len, int code, int id, fr_pair_list_t *vps);
 
 ssize_t                fr_radius_decode(TALLOC_CTX *ctx, fr_pair_list_t *out,
-                                uint8_t const *packet, size_t packet_len, uint8_t const *vector,
-                                char const *secret, UNUSED size_t secret_len) CC_HINT(nonnull(1,2,3,6));
+                                uint8_t *packet, size_t packet_len,
+                                fr_radius_decode_ctx_t *decode_ctx) CC_HINT(nonnull);
 
 int            fr_radius_init(void);
 
@@ -157,47 +205,6 @@ int                fr_radius_packet_send(fr_radius_packet_t *packet, fr_pair_list_t *list,
 #define fr_radius_packet_log_hex(_log, _packet) _fr_radius_packet_log_hex(_log, _packet, __FILE__, __LINE__)
 void           _fr_radius_packet_log_hex(fr_log_t const *log, fr_radius_packet_t const *packet, char const *file, int line) CC_HINT(nonnull);
 
-typedef struct {
-       fr_pair_t       *parent;
-       fr_dcursor_t    cursor;
-} fr_radius_tag_ctx_t;
-
-typedef struct {
-       char const      *secret;
-       size_t          secret_length;
-
-       bool            add_proxy_state;                //!< do we add a Proxy-State?
-       uint64_t        my_proxy_state;                 //!< if so, this is its value
-
-       uint32_t        acct_delay_time;                //!< additional time to add to acct_delay_time
-
-       uint8_t         vector[RADIUS_AUTH_VECTOR_LENGTH]; //!< vector for authenticating the reply
-} fr_radius_ctx_t;
-
-typedef struct {
-       fr_radius_ctx_t         *common;
-
-       fr_fast_rand_t          rand_ctx;               //!< for tunnel passwords
-       int                     salt_offset;            //!< for tunnel passwords
-
-       uint8_t                 tag;                    //!< current tag for encoding
-       bool                    disallow_tunnel_passwords; //!< not all packets can have tunnel passwords
-       bool                    seen_message_authenticator;
-} fr_radius_encode_ctx_t;
-
-typedef struct {
-       fr_radius_ctx_t         *common;
-
-       TALLOC_CTX              *tmp_ctx;               //!< for temporary things cleaned up during decoding
-       uint8_t const           *end;                   //!< end of the packet
-
-       bool                    tunnel_password_zeros;  //!< check for trailing zeros on decode
-
-       fr_radius_tag_ctx_t     **tags;                 //!< for decoding tagged attributes
-       fr_pair_list_t          *tag_root;              //!< Where to insert tag attributes.
-       TALLOC_CTX              *tag_root_ctx;          //!< Where to allocate new tag attributes.
-} fr_radius_decode_ctx_t;
-
 /*
  *     protocols/radius/abinary.c
  */