Re: \000 in "octets" attribute?
On 2006-06-15 07:50, Stefan Winter <stefan.winter@restena.lu> wrote:
Hi,
I'm having a curious problem with a vendor-specific single-byte "octets"-attribute and attr_rewrite.
Essentially, I'm trying to rewrite an ascii "0" to a single-byte 0x00 value. But after this rewrite rule, a zero-byte value is returned instead. Any way to get around this?
With \001, \002, etc, all's well.
(incidentally, this is freeradius version 1.0.1 in RHEL4)
the RADIUS RFC forbids attributes with a terminating \000. The server knows that, and will shorten the octet attribute by cutting off the \000 - leaving an empty string behind. If your NAS really requires a trailing \000: fix the NAS. It is not RFC-compliant then.
Essentially, the vendor-specific attribute value is a 1-byte unsigned integer, not a string. Haven't done a live test yet, so I do not know how it handles the empty value. Perhaps all goes well. I'll let you know. My rfc-reading seems to contradict you a little bit, though? RFC2869 section 5: Note that none of the types in RADIUS terminate with a NUL (hex 00). In particular, types "text" and "string" in RADIUS do not terminate with a NUL (hex 00). The Attribute has a length field and does not use a terminator. Text contains UTF-8 encoded 10646 [8] characters and String contains 8-bit binary data. Servers and servers and clients MUST be able to deal with embedded nulls. RADIUS implementers using C are cautioned not to use strcpy() when handling strings. -- Erik Bolsø Linpro AS
Essentially, the vendor-specific attribute value is a 1-byte unsigned integer, not a string. Haven't done a live test yet, so I do not know how it handles the empty value. Perhaps all goes well. I'll let you know.
Then you are supposed to use the "integer" type, not "octets" (then, you don't even have to jump through hoops to achieve a "0": just use the integer 0, no need for \000).
My rfc-reading seems to contradict you a little bit, though?
No. I read this section quite a few times. octets is another word for string, i.e. treat what is in there as undistinguished octets (as opposed to: treat it as an integer). And that's why the section of RFC 2869 is perfectly right: you wanted to send a string that has a \000 (= hex 00, = NUL) as last character. And that's forbidden:
RFC2869 section 5: Note that none of the types in RADIUS terminate with a NUL (hex 00). In particular, types "text" and "string" in RADIUS do not terminate with a NUL (hex 00). The Attribute has a length field and does not use a terminator. Text contains UTF-8 encoded 10646 [8] characters and String contains 8-bit binary data. Servers and servers and clients MUST be able to deal with embedded nulls. RADIUS implementers using C are cautioned not to use strcpy() when handling strings.
Greetings, Stefan Winter -- Stefan WINTER Stiftung RESTENA - Réseau Téléinformatique de l'Education Nationale et de la Recherche Ingenieur Forschung & Entwicklung 6, rue Richard Coudenhove-Kalergi L-1359 Luxembourg E-Mail: stefan.winter@restena.lu Tel.: +352 424409-1 http://www.restena.lu Fax: +352 422473
Stefan Winter <stefan.winter@restena.lu> writes:
Essentially, the vendor-specific attribute value is a 1-byte unsigned integer, not a string. Haven't done a live test yet, so I do not know how it handles the empty value. Perhaps all goes well. I'll let you know.
Then you are supposed to use the "integer" type, not "octets"
No, that would be 4 octets. A 1-octet attribute allowing any value must be of type "string" (in RFC language, "octets" in FreeRADIUS). Bjørn
Hi,
Then you are supposed to use the "integer" type, not "octets"
No, that would be 4 octets. A 1-octet attribute allowing any value must be of type "string" (in RFC language, "octets" in FreeRADIUS).
Ah. Then you are in the unlucky position that you are not allowed to send a \000 to your NAS. Integer is too long, String may not terminate with a \000. Seems a bit braindead from the NAS to require that its integers are one octet only. Why not take a normal integer and restrict the allowed values to 0-255? Are bits a scarce resource where this thing comes from? I'd really like to hear what client exactly this is... Stefan -- Stefan WINTER Stiftung RESTENA - Réseau Téléinformatique de l'Education Nationale et de la Recherche Ingenieur Forschung & Entwicklung 6, rue Richard Coudenhove-Kalergi L-1359 Luxembourg E-Mail: stefan.winter@restena.lu Tel.: +352 424409-1 http://www.restena.lu Fax: +352 422473
On 2006-06-15 12:05, Stefan Winter <stefan.winter@restena.lu> wrote:
Hi,
Then you are supposed to use the "integer" type, not "octets"
No, that would be 4 octets. A 1-octet attribute allowing any value must be of type "string" (in RFC language, "octets" in FreeRADIUS).
Ah. Then you are in the unlucky position that you are not allowed to send a \000 to your NAS. Integer is too long, String may not terminate with a \000.
So I must do source-level hacks to be able to send a 1-octet \000 attribute, with current FreeRADIUS? Have I understood you correctly? No criticism implied, of course. Thanks for the help so far. -- Erik Bolsø Linpro AS
Hi,
So I must do source-level hacks to be able to send a 1-octet \000 attribute, with current FreeRADIUS? Have I understood you correctly?
At least, a more pragmatic reply. :-) Yes, in my understanding of the FR code, this would need source code modifications. Still my opinion is to instead hack the vendor of that other strange NAS/RADIUS server to not artificially require an 8-Bit integer. I'm still interested in the name of the product that behaves like that. Just to make sure I won't accidently buy it. Stefan -- Stefan WINTER Stiftung RESTENA - Réseau Téléinformatique de l'Education Nationale et de la Recherche Ingenieur Forschung & Entwicklung 6, rue Richard Coudenhove-Kalergi L-1359 Luxembourg E-Mail: stefan.winter@restena.lu Tel.: +352 424409-1 http://www.restena.lu Fax: +352 422473
Erik Bolsø <erik@linpro.no> writes:
So I must do source-level hacks to be able to send a 1-octet \000 attribute, with current FreeRADIUS? Have I understood you correctly?
Seems to work here, as long as the attribute is of type "octets". This test file: bjorn@obelix:/usr/local/test$ cat testfiles/3 User-Name = ppp1@example.com Password = b NAS-Port-Type = xDSL Calling-Station-Id =\000 MS-CHAP-Challenge = 0x00 results in: bjorn@obelix:/usr/local/test$ bin/radclient -x localhost:1812 auth testing123 -f testfiles/3 Sending Access-Request of id 178 to 127.0.0.1 port 1812 User-Name = "ppp1@example.com" Password = "b" NAS-Port-Type = xDSL Calling-Station-Id = "" MS-CHAP-Challenge = 0x00 rad_recv: Access-Reject packet from host 127.0.0.1 port 1812, id=178, length=20 Received on the server as: Packet-Type = Access-Request Thu Jun 15 13:55:14 2006 User-Name = "ppp1@example.com" User-Password = "b" NAS-Port-Type = xDSL MS-CHAP-Challenge = 0x00 NAS-IP-Address = 127.0.0.1 Stripped-User-Name = "ppp1" Realm = "example.com" Calling-Station-Id is a FreeRADIUS "string", not to be confused with a RFC2865 "string". MS-CHAP-Challenge is a FreeRADIUS "octets" type. Bjørn
Hi,
Seems to work here, as long as the attribute is of type "octets".
Hm, what exactly do you mean?
Calling-Station-Id =\000
results in:
Calling-Station-Id = ""
This is the behaviour I described as fine (the \000 is kicked since it is the last character, and what remains is a completely empty attribute), and what your colleague would probably describe as bad: he thinks, the \000 should be sent in the packet. Actually, I don't think that Calling-Station-Id is on the wire at all, since empty attributes are supposed to be suppressed. And that's why the packet arrives on the server without this attribute:
Received on the server as:
Packet-Type = Access-Request Thu Jun 15 13:55:14 2006 User-Name = "ppp1@example.com" User-Password = "b" NAS-Port-Type = xDSL MS-CHAP-Challenge = 0x00 NAS-IP-Address = 127.0.0.1 Stripped-User-Name = "ppp1" Realm = "example.com"
Since you _want_ the \000 to be sent, I don't see why it "seems to work here"? Maybe the only thing that would really give clarity about what is really happening is a pcap capture with ethereal or similar. Greetings, Stefan -- Stefan WINTER Stiftung RESTENA - Réseau Téléinformatique de l'Education Nationale et de la Recherche Ingenieur Forschung & Entwicklung 6, rue Richard Coudenhove-Kalergi L-1359 Luxembourg E-Mail: stefan.winter@restena.lu Tel.: +352 424409-1 http://www.restena.lu Fax: +352 422473
Stefan Winter <stefan.winter@restena.lu> writes:
Seems to work here, as long as the attribute is of type "octets".
Hm, what exactly do you mean?
Calling-Station-Id =\000
results in:
Calling-Station-Id = ""
This is the behaviour I described as fine (the \000 is kicked since it is the last character,
In fact, the string will always be cut off at \000. But I guess this may be caused by the files parser and/or radclient.
and what remains is a completely empty attribute), and what your colleague would probably describe as bad: he thinks, the \000 should be sent in the packet.
Actually, I don't think that Calling-Station-Id is on the wire at all, since empty attributes are supposed to be suppressed. And that's why the packet arrives on the server without this attribute:
Correct. And as long as the resulting string on the client is "", then that's also correct behaviour. No discussion there
Received on the server as:
Packet-Type = Access-Request Thu Jun 15 13:55:14 2006 User-Name = "ppp1@example.com" User-Password = "b" NAS-Port-Type = xDSL MS-CHAP-Challenge = 0x00 NAS-IP-Address = 127.0.0.1 Stripped-User-Name = "ppp1" Realm = "example.com"
Since you _want_ the \000 to be sent, I don't see why it "seems to work here"? Maybe the only thing that would really give clarity about what is really happening is a pcap capture with ethereal or similar.
Notice the MS-CHAP-Challenge. That's why I said "as long as the attribute is of type "octets"". Calling-Station-Id is truncated at the first NUL. MS-CHAP-Challenge is transmitted, even if it contains just a single NUL octet Bjørn
Notice the MS-CHAP-Challenge. That's why I said "as long as the attribute is of type "octets"".
Calling-Station-Id is truncated at the first NUL.
MS-CHAP-Challenge is transmitted, even if it contains just a single NUL octet
Okay, could you try to put 0x00 into the Calling-Station-Id and \000 into the MS-CHAP-Chellenge? Just to make sure it's not the notation or something, like that MS-CHAP-Challenge transmits the four characters 0,x,0,0. Or something similar. Still an ethereal capture would be great. Greetings, Stefan Winter -- Stefan WINTER Stiftung RESTENA - Réseau Téléinformatique de l'Education Nationale et de la Recherche Ingenieur Forschung & Entwicklung 6, rue Richard Coudenhove-Kalergi L-1359 Luxembourg E-Mail: stefan.winter@restena.lu Tel.: +352 424409-1 http://www.restena.lu Fax: +352 422473
Stefan Winter <stefan.winter@restena.lu> writes:
Notice the MS-CHAP-Challenge. That's why I said "as long as the attribute is of type "octets"".
Calling-Station-Id is truncated at the first NUL.
MS-CHAP-Challenge is transmitted, even if it contains just a single NUL octet
Okay, could you try to put 0x00 into the Calling-Station-Id
That will be parsed as the 4 octet string "0x00".
and \000 into the MS-CHAP-Chellenge? Just to make sure it's not the notation or something, like that MS-CHAP-Challenge transmits the four characters 0,x,0,0. Or something similar. Still an ethereal capture would be great.
Capturing using Proxy-State should illustrate it: Capturing on lo Frame 1 (113 bytes on wire, 113 bytes captured) Arrival Time: Jun 15, 2006 15:27:14.775347000 Time delta from previous packet: 0.000000000 seconds Time since reference or first frame: 0.000000000 seconds Frame Number: 1 Packet Length: 113 bytes Capture Length: 113 bytes Protocols in frame: eth:ip:udp:radius Ethernet II, Src: 00:00:00:00:00:00, Dst: 00:00:00:00:00:00 Destination: 00:00:00:00:00:00 (00:00:00_00:00:00) Source: 00:00:00:00:00:00 (00:00:00_00:00:00) Type: IP (0x0800) Internet Protocol, Src Addr: 127.0.0.1 (127.0.0.1), Dst Addr: 127.0.0.1 (127.0.0.1) Version: 4 Header length: 20 bytes Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00) 0000 00.. = Differentiated Services Codepoint: Default (0x00) .... ..0. = ECN-Capable Transport (ECT): 0 .... ...0 = ECN-CE: 0 Total Length: 99 Identification: 0x0000 (0) Flags: 0x04 (Don't Fragment) 0... = Reserved bit: Not set .1.. = Don't fragment: Set ..0. = More fragments: Not set Fragment offset: 0 Time to live: 64 Protocol: UDP (0x11) Header checksum: 0x3c88 (correct) Source: 127.0.0.1 (127.0.0.1) Destination: 127.0.0.1 (127.0.0.1) User Datagram Protocol, Src Port: 32921 (32921), Dst Port: radius (1812) Source port: 32921 (32921) Destination port: radius (1812) Length: 79 Checksum: 0xfe62 (incorrect, should be 0x4ab0) Radius Protocol Code: Access Request (1) Packet identifier: 0x1c (28) Length: 71 Authenticator: 0x05D6BB4C4F13A6F3462324A77500B3CC Attribute value pairs t:User Name(1) l:18, Value:"ppp1@example.com" User-Name: ppp1@example.com t:User Password(2) l:18, Value:6B46A0A335701FC95CED632EFBD6708E t:NAS Port Type(61) l:6, Value:xDSL(16) t:Calling Station Id(31) l:6, Value:"blah" Calling-Station-Id: blah t:Proxy State(33) l:3, Value:00 Frame 2 (65 bytes on wire, 65 bytes captured) Arrival Time: Jun 15, 2006 15:27:15.792309000 Time delta from previous packet: 1.016962000 seconds Time since reference or first frame: 1.016962000 seconds Frame Number: 2 Packet Length: 65 bytes Capture Length: 65 bytes Protocols in frame: eth:ip:udp:radius Ethernet II, Src: 00:00:00:00:00:00, Dst: 00:00:00:00:00:00 Destination: 00:00:00:00:00:00 (00:00:00_00:00:00) Source: 00:00:00:00:00:00 (00:00:00_00:00:00) Type: IP (0x0800) Internet Protocol, Src Addr: 127.0.0.1 (127.0.0.1), Dst Addr: 127.0.0.1 (127.0.0.1) Version: 4 Header length: 20 bytes Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00) 0000 00.. = Differentiated Services Codepoint: Default (0x00) .... ..0. = ECN-Capable Transport (ECT): 0 .... ...0 = ECN-CE: 0 Total Length: 51 Identification: 0x0000 (0) Flags: 0x04 (Don't Fragment) 0... = Reserved bit: Not set .1.. = Don't fragment: Set ..0. = More fragments: Not set Fragment offset: 0 Time to live: 64 Protocol: UDP (0x11) Header checksum: 0x3cb8 (correct) Source: 127.0.0.1 (127.0.0.1) Destination: 127.0.0.1 (127.0.0.1) User Datagram Protocol, Src Port: radius (1812), Dst Port: 32921 (32921) Source port: radius (1812) Destination port: 32921 (32921) Length: 31 Checksum: 0xfe32 (incorrect, should be 0xf019) Radius Protocol Code: Access Reject (3) Packet identifier: 0x1c (28) Length: 23 Authenticator: 0x9696A6B7A298FC56A04A283D9C0124E9 Attribute value pairs t:Proxy State(33) l:3, Value:00 Bjørn
Great, thanks. Then my guess is that xlat (which is invoked in radiusd to mangle strings) strips the value, while things work good on the client side, which doesn't use xlat. I think xlat also isn't involved with Proxy-State and friends, so these are untouched. But this is getting beyond my knowledge. Maybe someone with more karma can jump in here? Especially if it's even *desired* to generate \000 octet values... Greetings, Stefan Winter -- Stefan WINTER Stiftung RESTENA - Réseau Téléinformatique de l'Education Nationale et de la Recherche Ingenieur Forschung & Entwicklung 6, rue Richard Coudenhove-Kalergi L-1359 Luxembourg E-Mail: stefan.winter@restena.lu Tel.: +352 424409-1 http://www.restena.lu Fax: +352 422473
On 2006-06-15 14:00, Bjørn Mork <bjorn@mork.no> wrote:
Erik Bolsø <erik@linpro.no> writes:
So I must do source-level hacks to be able to send a 1-octet \000 attribute, with current FreeRADIUS? Have I understood you correctly?
Seems to work here, as long as the attribute is of type "octets". Calling-Station-Id is a FreeRADIUS "string", not to be confused with a RFC2865 "string". MS-CHAP-Challenge is a FreeRADIUS "octets" type.
Actually, it's the response from the server that needs to be single-byte 0x00 - if the ldap attribute in question is 0. Do tell if you find out how :) -- Erik Bolsø Linpro AS
Erik Bolsø <erik@linpro.no> writes:
On 2006-06-15 14:00, Bjørn Mork <bjorn@mork.no> wrote:
Seems to work here, as long as the attribute is of type "octets". Calling-Station-Id is a FreeRADIUS "string", not to be confused with a RFC2865 "string". MS-CHAP-Challenge is a FreeRADIUS "octets" type.
Actually, it's the response from the server that needs to be single-byte 0x00 - if the ldap attribute in question is 0. Do tell if you find out how :)
Seems to work as expected too. Proxy-State is of "octets" type and RFC2865 requires the server to return it unchanged, which it does: bjorn@obelix:/usr/local/test$ bin/radclient -x localhost:1812 auth testing123 -f testfiles/3 Sending Access-Request of id 20 to 127.0.0.1 port 1812 User-Name = "ppp1@example.com" Password = "b" NAS-Port-Type = xDSL Calling-Station-Id = "blah" Proxy-State = 0x00 rad_recv: Access-Reject packet from host 127.0.0.1 port 1812, id=20, length=23 Proxy-State = 0x00 Bjørn
So I must do source-level hacks to be able to send a 1-octet \000 attribute, with current FreeRADIUS? Have I understood you correctly?
No. Use the "octets" type, and set the value to 0x00. The problem comes because you're either using "string" type, or you're using "octets", but assigning a string value of "0" to it. Don't. Use the native octets hex data, as documented. Alan DeKok.
On 2006-06-15 11:09, Stefan Winter <stefan.winter@restena.lu> wrote:
Essentially, the vendor-specific attribute value is a 1-byte unsigned integer, not a string. Haven't done a live test yet, so I do not know how it handles the empty value. Perhaps all goes well. I'll let you know.
Then you are supposed to use the "integer" type, not "octets" (then, you don't even have to jump through hoops to achieve a "0": just use the integer 0, no need for \000).
But the radius integer type is a 4-byte value, which is three bytes too long. I've tested that, it doesn't work.
My rfc-reading seems to contradict you a little bit, though?
No. I read this section quite a few times. octets is another word for string, i.e. treat what is in there as undistinguished octets (as opposed to: treat it as an integer). And that's why the section of RFC 2869 is perfectly right: you wanted to send a string that has a \000 (= hex 00, = NUL) as last character. And that's forbidden:
Nothing forbidding a NUL here... "servers and clients MUST be able to deal with embedded nulls". A 1-byte string containing just \000 seems perfectly valid to me.
RFC2869 section 5: Note that none of the types in RADIUS terminate with a NUL (hex 00). In particular, types "text" and "string" in RADIUS do not terminate with a NUL (hex 00). The Attribute has a length field and does not use a terminator. Text contains UTF-8 encoded 10646 [8] characters and String contains 8-bit binary data. Servers and servers and clients MUST be able to deal with embedded nulls. RADIUS implementers using C are cautioned not to use strcpy() when handling strings.
Nothing forbidding a NUL here... "servers and clients MUST be able to deal with embedded nulls". A 1-byte string containing just \000 seems perfectly valid to me.
Did you read what I wrote about "embedded" vs "terminating"? I'm closing this incredibly pointless discussion, don't expect to hear from me again. Stefan Winter -- Stefan WINTER Stiftung RESTENA - Réseau Téléinformatique de l'Education Nationale et de la Recherche Ingenieur Forschung & Entwicklung 6, rue Richard Coudenhove-Kalergi L-1359 Luxembourg E-Mail: stefan.winter@restena.lu Tel.: +352 424409-1 http://www.restena.lu Fax: +352 422473
Stefan Winter <stefan.winter@restena.lu> writes:
Nothing forbidding a NUL here... "servers and clients MUST be able to deal with embedded nulls". A 1-byte string containing just \000 seems perfectly valid to me.
Did you read what I wrote about "embedded" vs "terminating"? I'm closing this incredibly pointless discussion, don't expect to hear from me again.
Too bad. I was hoping you would clarify why you think "embedded" excludes "ending with" and why you think "terminating" equals "ending". BTW, would that mean that "embedded" also excludes "starting with"? Sorry, I know this may seem like an attempt to start a flame war. Believe me, it's not. I truly think you're misinterpreting the RFC, concluding exactly opposite to the intended meaning. Stripping NULs off the end of a string is interpreting them as string terminators. The RFC forbids this. It demands that implementations deal with embedded NULs. If FreeRADIUS strips any NULs, anywhere in the string, then FreeRADIUS is violating the RFC. IMHO. Bjørn
=?iso-8859-1?Q?Bj=F8rn_Mork?= <bjorn@mork.no> wrote:
Stripping NULs off the end of a string is interpreting them as string terminators. The RFC forbids this.
No, it doesn't. And even if it did, who cares?
It demands that implementations deal with embedded NULs. If FreeRADIUS strips any NULs, anywhere in the string, then FreeRADIUS is violating the RFC. IMHO.
Perhaps you could try understand what the server actually does, and why. a) type "octets" is treated as opaque binary blobs b) type "string" can't have embedded NUL's, because they are used in C as end-of-string markers. This is perfectly compatible with the RFC's, because FreeRADIUS used type "string" for printable data, and NUL isn't printable. The RFC's use type "text" for printable and "string" for octets, because the original RFC's used "string" for both, which was wrong. FreeRADIUS used "string" for printable, and "octets" for non-printable, because it was started before the RFC's were fixed. And as for RFC violations, the RFC's document a recommended way to do things. Nothing more. You can violate them at will if they're wrong. (As seen in the "string" -> "string, text" change above.) If the original RFC was perfect, why was it changed? FreeRADIUS violates a number of other recommendations in the RFC's, because time has shown those recommendations to be wrong or inefficient. e.g. the RFC 3579, section 2.6.1. It recommends keeping track of EAP sessions through some convoluted and fragile method. When Raghu did the original EAP implementation, he came up with a much better scheme. So much better, in fact, the there will be a new RFC within a year documenting his method as used in FreeRADIUS, and suggesting that it's probably a better way to do things. So don't get picky about RFC violations. Blind adherence to a specification is counter-productive. And if nothing else, the collective RADIUS experience of the FreeRADIUS developers is approaching the century mark. I'd be careful about arguing with people who have more experience than you in a field. Alan DeKok.
"Alan DeKok" <aland@nitros9.org> writes:
So don't get picky about RFC violations. Blind adherence to a specification is counter-productive.
Absolutely. I do acknowledge that RADIUS is one of many protocols where real-life experience and common practice is much more important than the actual specifications.
And if nothing else, the collective RADIUS experience of the FreeRADIUS developers is approaching the century mark. I'd be careful about arguing with people who have more experience than you in a field.
I don't like to be careful. I prefer getting burned and learn a lesson that way :-) Your explanation of the "string" and "octets" types in FreeRADIUS cleared up a lot for me. Thanks. Bjørn
participants (4)
-
Alan DeKok -
Bjørn Mork -
Erik Bolsø -
Stefan Winter