Problems decoding a vendor-specified attribute on the client side

JCA 1.41421 at
Thu Dec 27 02:03:25 CET 2012

   I already sent this but forgot to include a subject line -  and
Gmail couldn't be bothered to remind me :-( Here it is again.

   I have a FreeRADIUS server 2.2.0 on a Linux box A, and a RADIUS
client on a different Linux box B. The client in B has been
constructed using as a basis one of the examples distributed with the
FreeRADIUS 1.1.6 client code.  The client uses the RADIUS library
distributed with this code.

Things seem to work fine, in that I can carry out authentications on A
on behalf of B all right. I am having problems when trying to decode
on B a vendor-specific attribute sent by A. Initially I had my users
defined in /etc/freeradius/users in A along the following lines:

     user1      User-Password != "User1Password"
     user1      Cleartext-Password := "User1Password"
          Reply-Message = "Authentication successful."

With this, the string associated with the Reply-Message attribute is
sent by the server only when the authentication succeeds. On the
FreeRADIUS 1.1.6 client the rc_send_server() function detects that the
response payload contains more information than just the
authentication diagnostic, and proceeds to decode it by invoking
rc_avpair_gen(), which in turn recognizes the Reply-Message attribute
identifier and the associated string value without any problems.

I would like to be able to use a vendor-specified attribute, rather
than Reply-Message, and to that end I added the following entry to the
dictionary files in both client and server:

       VENDOR          MyVendorID    29688

       BEGIN-VENDOR    MyVendorID
       ATTRIBUTE            Vendor-Attr  1    string
       END-VENDOR      MyVendorID

(the vendor ID used here is bogus.)  I also changed my users on the
server as follows:

     user1      User-Password != "User1Password"
     user1      Cleartext-Password := "User1Password"
          Vendor-Attr = "Authentication successful."

After launching the server on A again, and attempting an
authentication from B, debugging the client on B reveals that the
server is indeed sending the Vendor-Attr attribute with the value
specified in the users file. The rc_avpair_gen() function in the
client code on B detects a vendor-specified attribute, and after
properly identifying it as MyVendorID it attempts to decode the
attribute that follows by recursively invoking itself. In more detail:

The first few bytes of the data received from the server is

      0x1a    0x1b    0x00    0x00    0x73    0xf8    0x01    0x15

rc_avpair_gen() correctly identifies that this is a vendor-specified
attribute (byte 0x1a) and then extracts the vendor ID itself (bytes
0x73 0xf8, or 29688 in decimal.) After verifying that this is a vendor
ID that it knows about, rc_avpair_gen() invokes itself recursively on
the input data offset by 7 bytes (i.e. starting at the 0x01 byte that
follows the 0xf8 byte) and with the 29688 vendor ID already retrieved.
rc_avpair_gen() then executes the following line:

      attribute = ptr[0] | (vendorpec << 16)

where ptr[0] is 0x01, and vendorpec is 0x73f8. After this, attribute
takes the value 0x73f80001.

      The code then proceeds to invoking rc_dict_getattr() in order to
get the attribute, using as arguments the dictionary data previously
loaded when launching the client, plus the value of the attribute
variable obtained above. rc_dict_getattr() will just loop over all
entries in the dictionary data, trying to find a match. This is a very
simple function:

       DICT_ATTR *rc_dict_getattr (const rc_handle *rh, int attribute)
         DICT_ATTR      *attr;

         attr = rh->dictionary_attributes;
         while (attr != NULL)
           if (attr->value == attribute)
             return attr;
           attr = attr->next;
         return NULL;

Now the attr entry for the matching attribute is

       $53 = {name = "Vendor-Attr", '\000' <repeats 19 times>, value =
1, type = 0, next = 0x804bc90}

as obtained with gdb.

       The comparison in the loop above will not succeed, because
attr->value is 1, whereas attribute is 0x73f80001. Therefore no match
will be found, and rc_dict_getattr() will return a NULL pointer, thus
causing rc_avpair_gen() to generate an error message as follows:

        received unknown VSA attribute 1, vendor 29688 of length xx

where xx is the length of the "Authentication successful." string.

        Thus, it would seem that the data was received correctly, but
can't somehow be decoded.

        Notice that fudging things with gdb so that the value of
attribute is set to what it should be (1) also does not work, for in
that case the attribute is identified as a User-Name, instead of the
vendor-specific attribute Vendor-Attr.

        Anybody know what is going on here? I would be tempted to say
that the rc_dict_getattr() implementation is wrong, but I find it
difficult to believe that it is THAT wrong - this wouldn't be just a
bug, but a huge implementation error. Therefore, I must be doing
something wrong myself instead. But, what? How do I define my simple
vendor-specific attribute so that rc_get_attr() can identify and
decode it correctly?

More information about the Freeradius-Devel mailing list