]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
copy original header if we have it
authorAlan T. DeKok <aland@freeradius.org>
Wed, 19 Aug 2020 21:29:59 +0000 (17:29 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Wed, 19 Aug 2020 21:29:59 +0000 (17:29 -0400)
and if there's no VPs parented by TACACS-Packet.  This lets us
avoid some extra work, so we don't have to copy VPs from the
request to the reply

src/protocols/tacacs/encode.c

index 74281784f57243d6502f22f2032df5e4e5c5bd56..d8ca6d131e3d5db78f6debe8e789b1dd7dce3b0b 100644 (file)
@@ -155,6 +155,11 @@ ssize_t fr_tacacs_encode(uint8_t *buffer, size_t buffer_len, uint8_t const *orig
                return -1;
        }
 
+       /*
+        *      Handle directly in the allocated buffer
+        */
+       packet = (fr_tacacs_packet_t *)buffer;
+
        /*
         *      Find the first attribute which is parented by TACACS-Packet.
         */
@@ -165,28 +170,35 @@ ssize_t fr_tacacs_encode(uint8_t *buffer, size_t buffer_len, uint8_t const *orig
        }
 
        if (!vp) {
-               fr_strerror_printf("No TACACS+ %s in the attribute list",
-                       attr_tacacs_packet->name);
-               return -1;
-       }
+               if (!original) {
+                       fr_strerror_printf("No TACACS+ %s in the attribute list",
+                                          attr_tacacs_packet->name);
+                       return -1;
+               }
 
-       fr_proto_da_stack_build(&da_stack, attr_tacacs_packet);
-       FR_PROTO_STACK_PRINT(&da_stack, 0);
+               /*
+                *      Initialize the reply from the request.
+                */
+               memset(buffer, 0, sizeof(packet->hdr));
+               packet->hdr.version = original->version;
+               packet->hdr.type = original->type;
+               packet->hdr.flags = original->flags;
+               packet->hdr.session_id = original->session_id;
 
-       /*
-        *      Call the struct encoder to do the actual work.
-        */
-       len = fr_struct_to_network(buffer, buffer_len, &da_stack, 0, &cursor, NULL, NULL);
-       if (len != sizeof(fr_tacacs_packet_hdr_t)) {
-               fr_strerror_printf("Failed encoding %s using fr_struct_to_network()",
-                                  attr_tacacs_packet->name);
-               return -1;
-       }
+       } else {
+               fr_proto_da_stack_build(&da_stack, attr_tacacs_packet);
+               FR_PROTO_STACK_PRINT(&da_stack, 0);
 
-       /*
-        *      Handle directly in the allocated buffer
-        */
-       packet = (fr_tacacs_packet_t *)buffer;
+               /*
+                *      Call the struct encoder to do the actual work.
+                */
+               len = fr_struct_to_network(buffer, buffer_len, &da_stack, 0, &cursor, NULL, NULL);
+               if (len != sizeof(fr_tacacs_packet_hdr_t)) {
+                       fr_strerror_printf("Failed encoding %s using fr_struct_to_network()",
+                                          attr_tacacs_packet->name);
+                       return -1;
+               }
+       }
 
        /*
         *      Encode 8 octets of various fields not members of STRUCT
@@ -565,6 +577,19 @@ ssize_t fr_tacacs_encode(uint8_t *buffer, size_t buffer_len, uint8_t const *orig
        fr_assert(packet_len < FR_TACACS_MAX_PACKET_SIZE);
        packet->hdr.length = htonl(packet_len - sizeof(fr_tacacs_packet_hdr_t));
 
+       /*
+        *      If the original packet is encrypted, then the reply
+        *      MUST be encrypted too.
+        *
+        *      On the other hand, if the request is unencrypted,
+        *      we're OK with sending an encrypted reply.  Because,
+        *      whatever.
+        */
+       if (original &&
+           ((original->flags & FR_TAC_PLUS_UNENCRYPTED_FLAG) == 0)) {
+               packet->hdr.flags &= ~FR_TAC_PLUS_UNENCRYPTED_FLAG;
+       }
+
        /*
         *      3.6. Encryption
         *