Problem with expansion of %{Ldap-UserDn} containing UTF-8 (cf. Bug #411)
Hi, there is a problem at least with LDAP group compares when Ldap-UserDn contains UTF-8 which seems not to be uncommon nowadays :) (see Bug #411) I have a setup where I use Active Directory for authorization via groupmembership_filter. Assume the following: basedn = "dc=example,dc=com" filter = "(userPrincipalName=%{Stripped-User-Name})" base_filter = "(objectclass=user)" groupmembership_filter = "(&(objectClass=group)(member=%{Ldap-UserDn}))" users file: DEFAULT ldap-group == "CN=allow-members-of-this-group,OU=Groups,DC=example,DC=com" The entry in the users file triggers the LDAP group compare function, which in turn first searches for the user (assume Ldap-UserDn has not been set before) and then does a second search using the group DN as base DN and groupmembership_filter as filter. Assume now the first search returns a user_dn containing UTF-8. The %{Ldap-UserDn} in the groupmembership_filter will then be expanded by xlat.c using \ooo (octal) for the 8bit characters. Then, the second search can not match, because the member attribute of the group contains member DNs in UTF-8, but the value to compare has been 'destroyed' by xlat. 1. How can this issue be solved for Ldap-UserDn? Or does a solution already exists that I have overlooked? 2. Is this a general issue for variable expansions handling _all_ 8bit characters as kind of 'non-printable', may be 'unsafe' characters? Remember that most query expansions like in rlm_ldap and rlm_sql have their own notion of unsafe characters and escape again ... Thanks for any ideas. Enrik
Enrik Berkhan wrote:
Assume now the first search returns a user_dn containing UTF-8. The %{Ldap-UserDn} in the groupmembership_filter will then be expanded by xlat.c using \ooo (octal) for the 8bit characters. Then, the second search can not match, because the member attribute of the group contains member DNs in UTF-8, but the value to compare has been 'destroyed' by xlat.
What part of the server has destroyed that? The ldap escaping function implements the requirements of RFC 4514 for escaping LDAP strings. It doesn't mangle UTF-8 strings.
1. How can this issue be solved for Ldap-UserDn? Or does a solution already exists that I have overlooked?
I think the solution is to update src/lib/print.c to handle UTF-8 by default.
2. Is this a general issue for variable expansions handling _all_ 8bit characters as kind of 'non-printable', may be 'unsafe' characters? Remember that most query expansions like in rlm_ldap and rlm_sql have their own notion of unsafe characters and escape again ...
I think so, yes. Alan DeKok.
Hi, Alan DeKok wrote:
Enrik Berkhan wrote:
Assume now the first search returns a user_dn containing UTF-8. The %{Ldap-UserDn} in the groupmembership_filter will then be expanded by xlat.c using \ooo (octal) for the 8bit characters. Then, the second search can not match, because the member attribute of the group contains member DNs in UTF-8, but the value to compare has been 'destroyed' by xlat.
What part of the server has destroyed that? The ldap escaping function implements the requirements of RFC 4514 for escaping LDAP strings. It doesn't mangle UTF-8 strings.
The LDAP-escaping is ok, AFAICS. The octal escapes from librad_safeprint() are the problem. That's what I meant by 'destroyed', bad wording maybe.
1. How can this issue be solved for Ldap-UserDn? Or does a solution already exists that I have overlooked?
I think the solution is to update src/lib/print.c to handle UTF-8 by default.
Ok, so how should this be gone about? Change librad_safeprint() to allow 8bit or UTF-8 only? Change vp_prints_value() to use something else than librad_safeprint()? I don't know because I can't oversee the possible side effects. I don't want to make things worse :) Enrik
Enrik Berkhan wrote:
I think the solution is to update src/lib/print.c to handle UTF-8 by default.
Ok, so how should this be gone about? Change librad_safeprint() to allow 8bit or UTF-8 only?
Change it to allow UTF-8. Most modern systems support this.
Change vp_prints_value() to use something else than librad_safeprint()? I don't know because I can't oversee the possible side effects. I don't want to make things worse :)
There shouldn't be many side effects from this. Alan DeKok.
Alan DeKok schrieb:
Enrik Berkhan wrote:
I think the solution is to update src/lib/print.c to handle UTF-8 by default. Ok, so how should this be gone about? Change librad_safeprint() to allow 8bit or UTF-8 only?
Change it to allow UTF-8. Most modern systems support this.
So, this could be done using iconv(), for example. Would this be ok? Hmm, I've just looked at HEAD: there, vp_prints_value() has a special case (delimitst < 0) used by valuepair2str in xlat.c explicitly to make vp_prints_value() 8bit clean ... now I'm a bit confused ...
RCS file: /source/radiusd/src/lib/print.c,v Working file: print.c head: 1.49 branch: locks: strict access list: symbolic names: [...] keyword substitution: kv total revisions: 54; selected revisions: 1 description: ---------------------------- revision 1.27 date: 2004/08/18 20:58:11; author: aland; state: Exp; lines: +24 -27 If we're printing to a string for xlat's, don't bother escaping characters, as the user-specified escape function will do that for us =============================================================================
May be just put this on the 1.1.x branch instead? Enrik
Enrik Berkhan wrote:
Change it to allow UTF-8. Most modern systems support this.
So, this could be done using iconv(), for example. Would this be ok?
No. iconv() returns error on invalid UTF-8 sequence. What we want is to escape invalid UTF-8 sequences.
Hmm, I've just looked at HEAD: there, vp_prints_value() has a special case (delimitst < 0) used by valuepair2str in xlat.c explicitly to make vp_prints_value() 8bit clean ... now I'm a bit confused ...
That isn't good enough. The input character stream should be sanitized for UTF-8.
May be just put this on the 1.1.x branch instead?
If CVS head is fixed, that's a Good Thing. If 1.1.x is broken, we can release a patched version at some point. Alan DeKok.
Hi, Alan DeKok wrote:
No. iconv() returns error on invalid UTF-8 sequence. What we want is to escape invalid UTF-8 sequences.
The idea would be: try iconv("UTF-8" -> "UTF-8"), escape if that fails. Is there anonther good portable or even standard way of doing this? Clear disadvantage of iconv() is the non-thread-awareness of the state storage, so it should either be re-allocated on every usage (not cheap, I suppose) or be allocated in thread-local-storage somehow. Any better suggestions? Enrik
Enrik Berkhan wrote:
The idea would be: try iconv("UTF-8" -> "UTF-8"), escape if that fails.
And escape what, the whole string? It's probably easier just to sanitize the string ourselves, because iconv() may not be available on all platforms.
Is there anonther good portable or even standard way of doing this? Clear disadvantage of iconv() is the non-thread-awareness of the state storage, so it should either be re-allocated on every usage (not cheap, I suppose) or be allocated in thread-local-storage somehow.
Bleah. There's no need to use a function with local non-thread-aware storage. It's easy to know what a valid UTF-8 character is. We should just check ourselves, and escape anything that isn't valid. Alan DeKok.
Alan DeKok wrote:
Bleah. There's no need to use a function with local non-thread-aware storage. It's easy to know what a valid UTF-8 character is. We should just check ourselves, and escape anything that isn't valid.
You're right. So this could be a start: static int valid_utf8(const unsigned char *p, size_t len) { if (len >= 1 && p[0] < 0x7f) { return 1; } else if (len >= 2 && p[0] >= 0xC0 && p[0] < 0xE0 && (p[1]&0x80) == 0x80) { return 2; } else if (len >= 3 && p[0] >= 0xE0 && p[0] < 0xF0 && (p[1]&0x80) == 0x80 && (p[2]&0x80) == 0x80) { return 3; } else if (len >= 4 && p[0] >= 0xF0 && p[0] < 0xF8 && (p[1]&0x80) == 0x80 && (p[2]&0x80) == 0x80 && (p[3]&0x80) == 0x80) { return 4; } else if (len >= 5 && p[0] >= 0xF8 && p[0] < 0xFC && (p[1]&0x80) == 0x80 && (p[2]&0x80) == 0x80 && (p[3]&0x80) == 0x80 && (p[4]&0x80) == 0x80) { return 5; } else if (len >= 6 && p[0] >= 0xFC && p[0] < 0xFE && (p[1]&0x80) == 0x80 && (p[2]&0x80) == 0x80 && (p[3]&0x80) == 0x80 && (p[4]&0x80) == 0x80 && (p[5]&0x80) == 0x80) { return 6; } return 0; } /* * Check if string contains valid UTF-8, escape violating bytes. * The output string has to be _at least_ 4x the size * of the input string! */ void librad_utf8_sanitize(const char *in, size_t inlen, char *out, size_t outlen) { while (inlen && outlen) { size_t next = valid_utf8(in, inlen); if (next) { if (outlen > next) { inlen -= next; outlen -= next; while(next--) *out++ = *in++; } else { goto no_more; } } else { if (outlen > 4) { /* room for \ooo\0 */ sprintf(out, "\\%03o", (unsigned char)(*in++)&0xff); out += 4; inlen--; outlen -= 4; } else { goto no_more; } } } no_more: *out = 0; } Enrik
Enrik Berkhan wrote: Never post before doing at least _some_ testing :)
static int valid_utf8(const unsigned char *p, size_t len) { if (len >= 1 && p[0] < 0x7f) { return 1; } else if (len >= 2 && p[0] >= 0xC0 && p[0] < 0xE0 && (p[1]&0x80) == 0x80) { Of course, all the masks should be 0xC0 instead of 0x80.
return 2; } else if (len >= 3 && p[0] >= 0xE0 && p[0] < 0xF0 && (p[1]&0x80) == 0x80 && (p[2]&0x80) == 0x80) { return 3; } else if (len >= 4 && p[0] >= 0xF0 && p[0] < 0xF8 && (p[1]&0x80) == 0x80 && (p[2]&0x80) == 0x80 && (p[3]&0x80) == 0x80) { return 4; } else if (len >= 5 && p[0] >= 0xF8 && p[0] < 0xFC && (p[1]&0x80) == 0x80 && (p[2]&0x80) == 0x80 && (p[3]&0x80) == 0x80 && (p[4]&0x80) == 0x80) { return 5; } else if (len >= 6 && p[0] >= 0xFC && p[0] < 0xFE && (p[1]&0x80) == 0x80 && (p[2]&0x80) == 0x80 && (p[3]&0x80) == 0x80 && (p[4]&0x80) == 0x80 && (p[5]&0x80) == 0x80) { return 6; } return 0; }
And the code still allows non shortest possible sequences. Enrik
Enrik Berkhan wrote:
Never post before doing at least _some_ testing :)
Try this patch. Untested, but it builds. :( It also deals with overlong characters, and illegal use of surrogates. Alan DeKok. Index: src/lib/print.c =================================================================== RCS file: /source/radiusd/src/lib/print.c,v retrieving revision 1.49 diff -u -w -r1.49 print.c --- src/lib/print.c 29 May 2007 14:33:26 -0000 1.49 +++ src/lib/print.c 27 Aug 2007 16:01:33 -0000 @@ -28,6 +28,99 @@ #include <ctype.h> /* + * Checks for utf-8, + * taken from: + * + * http://www.w3.org/International/questions/qa-forms-utf-8 + */ +static int utf8_char(uint8_t *str) +{ + if (*str < 0x20) return 0; + + if (*str <= 0x7e) return 1; /* 1 */ + + if (*str <= 0xc1) return 0; + + if ((str[0] >= 0xc2) && /* 2 */ + (str[0] <= 0xdf) && + (str[1] >= 0x80) && + (str[1] <= 0xbf)) { + return 2; + } + + if ((str[0] == 0xe0) && /* 3 */ + (str[1] >= 0xa0) && + (str[1] <= 0xbf) && + (str[2] >= 0x80) && + (str[2] <= 0xbf)) { + return 3; + } + + if ((str[0] >= 0xe1) && /* 4a */ + (str[0] <= 0xec) && + (str[1] >= 0x80) && + (str[1] <= 0xbf) && + (str[2] >= 0x80) && + (str[2] <= 0xbf)) { + return 3; + } + + if ((str[0] >= 0xee) && /* 4b */ + (str[0] <= 0xef) && + (str[1] >= 0x80) && + (str[1] <= 0xbf) && + (str[2] >= 0x80) && + (str[2] <= 0xbf)) { + return 3; + } + + if ((str[0] == 0xed) && /* 5 */ + (str[1] >= 0x80) && + (str[1] <= 0x9f) && + (str[2] >= 0x80) && + (str[2] <= 0xbf)) { + return 3; + } + + if ((str[0] == 0xf0) && /* 6 */ + (str[1] >= 0x90) && + (str[1] <= 0xbf) && + (str[2] >= 0x80) && + (str[2] <= 0xbf) && + (str[3] >= 0x80) && + (str[3] <= 0xbf)) { + return 4; + } + + if ((str[0] >= 0xf1) && /* 6 */ + (str[1] <= 0xf3) && + (str[1] >= 0x80) && + (str[1] <= 0xbf) && + (str[2] >= 0x80) && + (str[2] <= 0xbf) && + (str[3] >= 0x80) && + (str[3] <= 0xbf)) { + return 4; + } + + + if ((str[0] == 0xf4) && /* 7 */ + (str[1] >= 0x80) && + (str[1] <= 0x8f) && + (str[2] >= 0x80) && + (str[2] <= 0xbf) && + (str[3] >= 0x80) && + (str[3] <= 0xbf)) { + return 4; + } + + /* + * Invalid UTF-8 Character + */ + return 0; +} + +/* * Convert a string to something printable. * The output string has to be _at least_ 4x the size * of the input string! @@ -37,6 +130,7 @@ unsigned char *str = (unsigned char *)in; int done = 0; int sp = 0; + int utf8 = 0; if (inlen < 0) inlen = strlen(in); @@ -50,6 +144,7 @@ break; sp = 0; + if (utf8) goto copy; switch (*str) { case '\\': @@ -68,15 +163,18 @@ sp = '"'; break; default: - if (*str < 32 || (*str >= 128)){ + if ((*str < 32) || + ((utf8 = utf8_char((uint8_t *)in)) == 0)) { snprintf(out, outlen, "\\%03o", *str); done += 4; out += 4; outlen -= 4; } else { + copy: *out++ = *str; outlen--; done++; + if (utf8) utf8--; } } if (sp) {
Hi, Alan DeKok wrote:
Enrik Berkhan wrote:
Never post before doing at least _some_ testing :)
Try this patch. Untested, but it builds. :(
It also deals with overlong characters, and illegal use of surrogates.
Thanks! And it actually starts to work :) - I'd add a length parameter and check for str to utf8_char(). - line 167(?) of src/lib/print.c should read ((utf8 = utf8_char((uint8_t *)str)) == 0)) { instead of ((utf8 = utf8_char((uint8_t *)in)) == 0)) { - for testing with HEAD I had to disbable the special case delimitst < 0 in vp_prints_value(). May be this can be eliminated then. And when testing, with a simple test setup like the following, remember that the escaped stuff may show up in the debug output only, as packet values will be translated back before being sent (is this correct? At least looks so ... ) Test setup, very simple again, thanks to unlang: ... strings { utf8 = blä latin1 = blä } ... server { authorize { update reply { Reply-Message := "%{config:strings.utf8}" Reply-Message += "%{config:strings.latin1}" } } } ... (Don't know how the two strings will show up in the mail. Suppose they are valid UTF-8 and Latin1 ... :-) Debug output: ... Sending Access-Reject of id 110 to 127.0.0.1 port 32768 Reply-Message = "blä" Reply-Message = "bl\344" ... (Again: the first one is valid UTF-8 at my (UTF-8-)Terminal over here) I think with a little fixing this can make it into HEAD and 1.1.x to be tested by others. Enrik
Enrik Berkhan wrote:
- I'd add a length parameter and check for str to utf8_char().
Not needed. The C string termination character '\0' is not a valid UTF-8 character.
- line 167(?) of src/lib/print.c should read
((utf8 = utf8_char((uint8_t *)str)) == 0)) {
Yes.
- for testing with HEAD I had to disbable the special case
delimitst < 0
in vp_prints_value(). May be this can be eliminated then.
OK.
And when testing, with a simple test setup like the following, remember that the escaped stuff may show up in the debug output only, as packet values will be translated back before being sent (is this correct? At least looks so ... )
Yes. The server will send exactly what you tell it to send, even if it's garbage.
Test setup, very simple again, thanks to unlang:
<g> I like that.
(Don't know how the two strings will show up in the mail. Suppose they are valid UTF-8 and Latin1 ... :-)
They both show up, but both as UTF-8.
I think with a little fixing this can make it into HEAD and 1.1.x to be tested by others.
Please try the following patch. It's a little clearer. Alan DeKok. Index: src/lib/print.c =================================================================== RCS file: /source/radiusd/src/lib/print.c,v retrieving revision 1.49 diff -u -r1.49 print.c --- src/lib/print.c 29 May 2007 14:33:26 -0000 1.49 +++ src/lib/print.c 28 Aug 2007 08:47:28 -0000 @@ -28,28 +28,122 @@ #include <ctype.h> /* - * Convert a string to something printable. - * The output string has to be _at least_ 4x the size - * of the input string! + * Checks for utf-8, + * taken from: + * + * http://www.w3.org/International/questions/qa-forms-utf-8 + */ +static int utf8_char(uint8_t *str) +{ + if (*str < 0x20) return 0; + + if (*str <= 0x7e) return 1; /* 1 */ + + if (*str <= 0xc1) return 0; + + if ((str[0] >= 0xc2) && /* 2 */ + (str[0] <= 0xdf) && + (str[1] >= 0x80) && + (str[1] <= 0xbf)) { + return 2; + } + + if ((str[0] == 0xe0) && /* 3 */ + (str[1] >= 0xa0) && + (str[1] <= 0xbf) && + (str[2] >= 0x80) && + (str[2] <= 0xbf)) { + return 3; + } + + if ((str[0] >= 0xe1) && /* 4a */ + (str[0] <= 0xec) && + (str[1] >= 0x80) && + (str[1] <= 0xbf) && + (str[2] >= 0x80) && + (str[2] <= 0xbf)) { + return 3; + } + + if ((str[0] >= 0xee) && /* 4b */ + (str[0] <= 0xef) && + (str[1] >= 0x80) && + (str[1] <= 0xbf) && + (str[2] >= 0x80) && + (str[2] <= 0xbf)) { + return 3; + } + + if ((str[0] == 0xed) && /* 5 */ + (str[1] >= 0x80) && + (str[1] <= 0x9f) && + (str[2] >= 0x80) && + (str[2] <= 0xbf)) { + return 3; + } + + if ((str[0] == 0xf0) && /* 6 */ + (str[1] >= 0x90) && + (str[1] <= 0xbf) && + (str[2] >= 0x80) && + (str[2] <= 0xbf) && + (str[3] >= 0x80) && + (str[3] <= 0xbf)) { + return 4; + } + + if ((str[0] >= 0xf1) && /* 6 */ + (str[1] <= 0xf3) && + (str[1] >= 0x80) && + (str[1] <= 0xbf) && + (str[2] >= 0x80) && + (str[2] <= 0xbf) && + (str[3] >= 0x80) && + (str[3] <= 0xbf)) { + return 4; + } + + + if ((str[0] == 0xf4) && /* 7 */ + (str[1] >= 0x80) && + (str[1] <= 0x8f) && + (str[2] >= 0x80) && + (str[2] <= 0xbf) && + (str[3] >= 0x80) && + (str[3] <= 0xbf)) { + return 4; + } + + /* + * Invalid UTF-8 Character + */ + return 0; +} + +/* + * Convert a string to something printable. The output string + * has to be larger than the input string by at least 5 bytes. + * If not, the output is silently truncated... */ void librad_safeprint(char *in, int inlen, char *out, int outlen) { unsigned char *str = (unsigned char *)in; int done = 0; int sp = 0; + int utf8 = 0; if (inlen < 0) inlen = strlen(in); - while (inlen-- > 0 && (done + 3) < outlen) { + /* + * + */ + while ((inlen > 0) && (done + 5) < outlen) { /* * Hack: never print trailing zero. * Some clients send strings with an off-by-one * length (confused with strings in C). */ - if (inlen == 0 && *str == 0) - break; - - sp = 0; + if ((inlen == 0) && (*str == 0)) break; switch (*str) { case '\\': @@ -68,24 +162,37 @@ sp = '"'; break; default: - if (*str < 32 || (*str >= 128)){ - snprintf(out, outlen, "\\%03o", *str); - done += 4; - out += 4; - outlen -= 4; - } else { - *out++ = *str; - outlen--; - done++; - } + sp = 0; + break; } + if (sp) { *out++ = '\\'; *out++ = sp; outlen -= 2; done += 2; + str++; + inlen--; + continue; + } + + utf8 = utf8_char((uint8_t *)str); + if (!utf8) { + snprintf(out, outlen, "\\%03o", *str); + done += 4; + out += 4; + outlen -= 4; + str++; + inlen--; + continue; } - str++; + + do { + *out++ = *str++; + outlen--; + inlen--; + done++; + } while (--utf8 > 0); } *out = 0; } @@ -122,10 +229,6 @@ vp->length, buf + 1, sizeof(buf) - 2); strcat(buf, "\""); - } else if (delimitst < 0) { - strlcpy(out, vp->vp_strvalue, outlen); - return strlen(out); - } else { /* Non-tagged attribute: no delimiter */ librad_safeprint((char *)vp->vp_strvalue, @@ -137,20 +240,21 @@ if ( vp->flags.has_tag ) { /* Attribute value has a tag, need to ignore it */ if ((v = dict_valbyattr(vp->attribute, (vp->vp_integer & 0xffffff))) - != NULL) + != NULL) { a = v->name; + } else { snprintf(buf, sizeof(buf), "%u", (vp->vp_integer & 0xffffff)); a = buf; } } else { - case PW_TYPE_BYTE: - case PW_TYPE_SHORT: + case PW_TYPE_BYTE: + case PW_TYPE_SHORT: /* Normal, non-tagged attribute */ if ((v = dict_valbyattr(vp->attribute, vp->vp_integer)) - != NULL) + != NULL) { a = v->name; - else { + }else { snprintf(buf, sizeof(buf), "%u", vp->vp_integer); a = buf; }
Hi, Alan DeKok wrote:
Enrik Berkhan wrote:
- I'd add a length parameter and check for str to utf8_char().
Not needed. The C string termination character '\0' is not a valid UTF-8 character.
You're right, if it's guaranteed to be called with a terminated string. You might add a comment, though :)
I think with a little fixing this can make it into HEAD and 1.1.x to be tested by others.
Please try the following patch. It's a little clearer.
It works ok with the same little test and actually it is a lot cleaner now. The 'done' counter in librad_safeprint() is not needed AFAICS as 'outlen' is decremented each time 'done' is incremented. Thus, the condition at the top while loop is wrong. Enrik
Enrik Berkhan wrote:
It works ok with the same little test and actually it is a lot cleaner now.
Ok.
The 'done' counter in librad_safeprint() is not needed AFAICS as 'outlen' is decremented each time 'done' is incremented. Thus, the condition at the top while loop is wrong.
Yup. I've deleted "done", and committed the final code. Alan DeKok.
Alan DeKok schrieb:
Yup. I've deleted "done", and committed the final code.
Fine, thanks. Now, I've tried it in 1.1.7 with the original ldap problem ... of course, the UTF-8 part works now, but one problem with LDAP DNs remains: The DNs may contain backslashes! Now these suffer from similar problems being doubled during the Ldap-UserDn expansion. Example: LDAP-Server returns DN: CN=Berkhan\, Enrik, ... where the first comma is part of the CN attribute and thus escaped in the LDAP answer. Search filter expansion containing Ldap-UserDn will change this to CN=Berkhan\\, Enrik, ... and, with LDAP-escaping applied, to CN\3dBerkhan\5c\5c\2c Enrik\2c ... which will fail matching the original DN like in the UTF-8 case before. Currently, I have no idea of how to fix this in a universal robust way besides doing variable expansion completely transparently ... Enrik
Enrik Berkhan wrote:
Now, I've tried it in 1.1.7 with the original ldap problem ... of course, the UTF-8 part works now, but one problem with LDAP DNs remains: The DNs may contain backslashes! Now these suffer from similar problems being doubled during the Ldap-UserDn expansion.
Yes, and commas. Multiple layers of variable expansion have problems. The only way to *really* fix the problem is to track the origin of data, and keep tainted / untainted flags.
Currently, I have no idea of how to fix this in a universal robust way besides doing variable expansion completely transparently ...
I'm not sure what you mean by that. Alan DeKok.
Hi, Alan DeKok wrote:
The only way to *really* fix the problem is to track the origin of data, and keep tainted / untainted flags.
Why not move the escaping that is done by librad_safeprint to the 'default escape function' (xlat_copy) when xlating? This would avoid the double escaping when a module supplied escape function is given to radius_xlat and keep the status quo otherwise. Enrik
Enrik Berkhan wrote:
Why not move the escaping that is done by librad_safeprint to the 'default escape function' (xlat_copy) when xlating? This would avoid the double escaping when a module supplied escape function is given to radius_xlat and keep the status quo otherwise.
I'm not sure what you mean by that. xlat_copy() just copies the data verbatim, so it doesn't affect any escaping rules. In addition, the safeprint() function does escaping ONLY when it's called, and it's not called from xlat.c because -1 is passed to vp_prints_value(). So the only escaping is done by the module's escape function, which is mostly what we want, right? Where does the double escaping come from? Alan DeKok.
Alan DeKok wrote:
In addition, the safeprint() function does escaping ONLY when it's called, and it's not called from xlat.c because -1 is passed to vp_prints_value(). So the only escaping is done by the module's escape function, which is mostly what we want, right?
With the re-introduction of the -1 handling, yes :) Suggesting to remove it was a misunderstanding on my side. Enrik
participants (2)
-
Alan DeKok -
Enrik Berkhan