The branch, master has been updated via 8c83347 util/rfc1738: update preamble via 7a06cfa util/rfc1738: simplify and fix rfc1738_escape_part() via d99a075 util/rfc1738: remove unused versions of rfc1738_escape via c20a369 util/rfc1738: simplify and fix rfc1738_unescape() via 9f3e20d util/tests: add rfc1738 cmocka tests via a4c853a util/rfc1738_unescape(): return end pointer or NULL on error via 6ef6ddc shift read_hex_bytes() and parse_guid_string() into lib/util via 33ef0e5 selftest/tests.py: remove always-needed, never-set with_cmocka flag via cb5f1f3 unittests.lib_util_modules: test module probe with "skel", not "unix" via 7d79575 selftest: subunithelper needs to follow the subunit spec more closely from 5d113f8 s4:rpc_server: fix call_id truncation in dcesrv_find_fragmented_call()
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 8c833470fc52332c62220ec9cc38c8a4fd7721f1 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Mon Feb 19 14:24:42 2018 +1300 util/rfc1738: update preamble Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> Autobuild-User(master): Douglas Bagnall <dbagn...@samba.org> Autobuild-Date(master): Thu Feb 22 06:13:49 CET 2018 on sn-devel-144 commit 7a06cfa2e2caed2067bf9030408cf56de7b89d65 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Tue Feb 20 23:56:11 2018 +1300 util/rfc1738: simplify and fix rfc1738_escape_part() We now encode according to RFC 3986 (section 2.1 - 2.3). Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit d99a075239588170be5a26453219d3cac5425885 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Sat Feb 17 11:23:44 2018 +1300 util/rfc1738: remove unused versions of rfc1738_escape Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit c20a3699075369e5516af47100220dab18435a91 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Mon Feb 19 14:12:03 2018 +1300 util/rfc1738: simplify and fix rfc1738_unescape() Improvements: * NULL is returned when the string is incorrectly formed. * Badly formed escapes like "% b" that were accepted by sscanf() are now rejected. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 9f3e20d98bdc04d6301ab0560cc7fde6ec9cc796 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Sun Feb 18 09:53:32 2018 +1300 util/tests: add rfc1738 cmocka tests These don't pass yet. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit a4c853a7deb080dd44e3c54eb45935ff0df91baf Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Sat Feb 17 10:46:44 2018 +1300 util/rfc1738_unescape(): return end pointer or NULL on error At present we don't detect errors, but when we do we'll return NULL. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 6ef6ddce5a64c55729c2e3d423757f504b0ab15e Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Fri Feb 16 17:53:15 2018 +1300 shift read_hex_bytes() and parse_guid_string() into lib/util read_hex_bytes() is going to be used in lib/util/rfc1738.c. parse_guid_string() is shifted for two reasons: Firstly, it is called very often in some operations, sometimes constituting a few percent of the CPU load, and it makes several calls to read_hex_bytes(). We want the compiler to be able to inline those calls if it thinks that is wise. Secondly, there are other places that could do with fast GUID parsing. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 33ef0e57a4f08eae5ea06f482374fbc0a1014de6 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Thu Feb 22 11:54:45 2018 +1300 selftest/tests.py: remove always-needed, never-set with_cmocka flag We have cmocka in third_party, so we are never without it. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit cb5f1f3b262467faba59b3b323e240d1351d5fc0 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Thu Feb 22 11:26:00 2018 +1300 unittests.lib_util_modules: test module probe with "skel", not "unix" The unix module is not available as a module on some systems. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 7d79575de8e47a0ce03e30c3ea84176be696269f Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Thu Feb 22 12:46:47 2018 +1300 selftest: subunithelper needs to follow the subunit spec more closely In particular allow ]\n without \n]\n as used by cmocka Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> ----------------------------------------------------------------------- Summary of changes: lib/util/rfc1738.c | 289 +++++++++---------- lib/util/samba_util.h | 18 +- lib/util/tests/rfc1738.c | 411 ++++++++++++++++++++++++++++ lib/util/util_str_hex.c | 100 +++++++ lib/util/util_str_hex.h | 10 + lib/util/wscript_build | 13 +- librpc/ndr/uuid.c | 98 +------ librpc/wscript_build | 2 +- selftest/subunithelper.py | 3 +- selftest/tests.py | 25 +- source3/client/smbspool.c | 8 +- source3/utils/ntlm_auth.c | 18 +- source4/libcli/ldap/ldap_client.c | 11 +- testsuite/unittests/test_lib_util_modules.c | 2 +- 14 files changed, 711 insertions(+), 297 deletions(-) create mode 100644 lib/util/tests/rfc1738.c create mode 100644 lib/util/util_str_hex.c create mode 100644 lib/util/util_str_hex.h Changeset truncated at 500 lines: diff --git a/lib/util/rfc1738.c b/lib/util/rfc1738.c index b285ae9..a6c54ce 100644 --- a/lib/util/rfc1738.c +++ b/lib/util/rfc1738.c @@ -1,19 +1,14 @@ /* - * NOTE: + * Functions for RFC 3986 percent-encoding. * - * This file imported from the Squid project. The licence below is - * reproduced intact, but refers to files in Squid's repository, not - * in Samba. See COPYING for the GPLv3 notice (being the later - * version mentioned below). - * - * This file has also been modified, in particular to use talloc to - * allocate in rfc1738_escape() - * - * - Andrew Bartlett Oct-2009 + * NOTE: * + * This file was originally imported from the Squid project but has been + * significantly altered. The licence below is reproduced intact, but refers + * to files in Squid's repository, not in Samba. See COPYING for the GPLv3 + * notice (being the later version mentioned below). */ - /* * $Id$ * @@ -51,175 +46,153 @@ #include "replace.h" #include <talloc.h> #include "lib/util/samba_util.h" +#include "lib/util/util_str_hex.h" + +#define RFC1738_ENCODE 1 +#define RFC1738_RESERVED 2 /* - * RFC 1738 defines that these characters should be escaped, as well - * any non-US-ASCII character or anything between 0x00 - 0x1F. + * According to RFC 1738, "$-_.+!*'()," are not reserved or unsafe, but as + * that has been obsolete since 2004, we sm instead for RFC 3986, where: + * + * reserved = : / ? # [ ] @ ! $ & ' ( ) * + , ; = + * unreserved = ALPHA DIGIT - . _ ~ + * + * and whatever is not in either of those are what RFC 1738 called "unsafe", + * meaning that they should are canonically but not mandatorily escaped. + * + * Characters below 0x20 or above 0x7E are always enocded. */ -static char rfc1738_unsafe_chars[] = { - (char) 0x3C, /* < */ - (char) 0x3E, /* > */ - (char) 0x22, /* " */ - (char) 0x23, /* # */ -#if 0 /* done in code */ - (char) 0x25, /* % */ -#endif - (char) 0x7B, /* { */ - (char) 0x7D, /* } */ - (char) 0x7C, /* | */ - (char) 0x5C, /* \ */ - (char) 0x5E, /* ^ */ - (char) 0x7E, /* ~ */ - (char) 0x5B, /* [ */ - (char) 0x5D, /* ] */ - (char) 0x60, /* ` */ - (char) 0x27, /* ' */ - (char) 0x20 /* space */ -}; -static char rfc1738_reserved_chars[] = { - (char) 0x3b, /* ; */ - (char) 0x2f, /* / */ - (char) 0x3f, /* ? */ - (char) 0x3a, /* : */ - (char) 0x40, /* @ */ - (char) 0x3d, /* = */ - (char) 0x26 /* & */ +static const unsigned char escapees[127] = { + [' '] = RFC1738_ENCODE, + ['"'] = RFC1738_ENCODE, + ['%'] = RFC1738_ENCODE, + ['<'] = RFC1738_ENCODE, + ['>'] = RFC1738_ENCODE, + ['\\'] = RFC1738_ENCODE, + ['^'] = RFC1738_ENCODE, + ['`'] = RFC1738_ENCODE, + ['{'] = RFC1738_ENCODE, + ['|'] = RFC1738_ENCODE, + ['}'] = RFC1738_ENCODE, + /* reserved : / ? # [ ] @ ! $ & ' ( ) * + , ; = */ + [':'] = RFC1738_RESERVED, + ['/'] = RFC1738_RESERVED, + ['?'] = RFC1738_RESERVED, + ['#'] = RFC1738_RESERVED, + ['['] = RFC1738_RESERVED, + [']'] = RFC1738_RESERVED, + ['@'] = RFC1738_RESERVED, + ['!'] = RFC1738_RESERVED, + ['$'] = RFC1738_RESERVED, + ['&'] = RFC1738_RESERVED, + ['\''] = RFC1738_RESERVED, + ['('] = RFC1738_RESERVED, + [')'] = RFC1738_RESERVED, + ['*'] = RFC1738_RESERVED, + ['+'] = RFC1738_RESERVED, + [','] = RFC1738_RESERVED, + [';'] = RFC1738_RESERVED, + ['='] = RFC1738_RESERVED, }; /* - * rfc1738_escape - Returns a static buffer contains the RFC 1738 - * compliant, escaped version of the given url. + * rfc1738_do_escape - fills a preallocated buffer with an escaped version of + * the given string. * + * For canonical escaping, mask should be RFC1738_ENCODE | RFC1738_RESERVED. + * For mandatory escaping, mask should be RFC1738_RESERVED. */ static char * -rfc1738_do_escape(TALLOC_CTX *mem_ctx, const char *url, int encode_reserved) +rfc1738_do_escape(char *buf, size_t bufsize, + const char *url, size_t len, unsigned char mask) { - size_t bufsize = 0; - const char *p; - char *buf; - char *q; - unsigned int i, do_escape; - - bufsize = strlen(url) * 3 + 1; - buf = talloc_array(mem_ctx, char, bufsize); - if (!buf) { - return NULL; - } - - talloc_set_name_const(buf, buf); - buf[0] = '\0'; - - for (p = url, q = buf; *p != '\0' && q < (buf + bufsize - 1); p++, q++) { - do_escape = 0; - - /* RFC 1738 defines these chars as unsafe */ - for (i = 0; i < sizeof(rfc1738_unsafe_chars); i++) { - if (*p == rfc1738_unsafe_chars[i]) { - do_escape = 1; - break; - } - } - /* Handle % separately */ - if (encode_reserved >= 0 && *p == '%') - do_escape = 1; - /* RFC 1738 defines these chars as reserved */ - for (i = 0; i < sizeof(rfc1738_reserved_chars) && encode_reserved > 0; i++) { - if (*p == rfc1738_reserved_chars[i]) { - do_escape = 1; - break; - } - } - /* RFC 1738 says any control chars (0x00-0x1F) are encoded */ - if ((unsigned char) *p <= (unsigned char) 0x1F) { - do_escape = 1; - } - /* RFC 1738 says 0x7f is encoded */ - if (*p == (char) 0x7F) { - do_escape = 1; - } - /* RFC 1738 says any non-US-ASCII are encoded */ - if (((unsigned char) *p >= (unsigned char) 0x80)) { - do_escape = 1; - } - /* Do the triplet encoding, or just copy the char */ - /* note: while we do not need snprintf here as q is appropriately - * allocated, Samba does to avoid our macro banning it -- abartlet */ - - if (do_escape == 1) { - (void) snprintf(q, 4, "%%%02X", (unsigned char) *p); - q += sizeof(char) * 2; - } else { - *q = *p; - } - } - *q = '\0'; - return (buf); + size_t i; + size_t j = 0; + for (i = 0; i < len; i++) { + unsigned int c = (unsigned char) url[i]; + if (c > 126 || c < 32 || (escapees[c] & mask)) { + if (j + 3 >= bufsize) { + return NULL; + } + (void) snprintf(&buf[j], 4, "%%%02X", c); + j += 3; + } else { + if (j + 1 >= bufsize) { + return NULL; + } + buf[j] = c; + j++; + } + } + buf[j] = '\0'; + return buf; } /* - * rfc1738_escape - Returns a buffer that contains the RFC - * 1738 compliant, escaped version of the given url. (escapes unsafe and % characters) + * rfc1738_escape_part - Returns a talloced buffer that contains the RFC 3986 + * compliant, escaped version of the given url segment. */ char * -rfc1738_escape(TALLOC_CTX *mem_ctx, const char *url) +rfc1738_escape_part(TALLOC_CTX *mem_ctx, const char *url) { - return rfc1738_do_escape(mem_ctx, url, 0); -} + size_t bufsize = 0; + char *buf = NULL; -/* - * rfc1738_escape_unescaped - Returns a buffer that contains - * the RFC 1738 compliant, escaped version of the given url (escapes unsafe chars only) - */ -char * -rfc1738_escape_unescaped(TALLOC_CTX *mem_ctx, const char *url) -{ - return rfc1738_do_escape(mem_ctx, url, -1); -} + size_t len = strlen(url); + if (len >= SIZE_MAX / 3) { + return NULL; + } -/* - * rfc1738_escape_part - Returns a buffer that contains the RFC - * 1738 compliant, escaped version of the given url segment. (escapes - * unsafe, reserved and % chars) It would mangle the :// in http://, - * and mangle paths (because of /). - */ -char * -rfc1738_escape_part(TALLOC_CTX *mem_ctx, const char *url) -{ - return rfc1738_do_escape(mem_ctx, url, 1); + bufsize = len * 3 + 1; + buf = talloc_array(mem_ctx, char, bufsize); + if (buf == NULL) { + return NULL; + } + + talloc_set_name_const(buf, buf); + + return rfc1738_do_escape(buf, bufsize, url, len, + RFC1738_ENCODE | RFC1738_RESERVED); } /* - * rfc1738_unescape() - Converts escaped characters (%xy numbers) in - * given the string. %% is a %. %ab is the 8-bit hexadecimal number "ab" + * rfc1738_unescape() - Converts url-escaped characters in the string. + * + * The two characters following a '%' in a string should be hex digits that + * describe an encoded byte. For example, "%25" is hex 0x25 or '%' in ASCII; + * this is the only way to include a % in the unescaped string. Any character + * can be escaped, including plain letters (e.g. "%61" for "a"). Anything + * other than 2 hex characters following the % is an error. + * + * The conversion is done in-place, which is always safe as unescapes can only + * shorten the string. + * + * Returns a pointer to the end of the string (that is, the '\0' byte), or + * NULL on error, at which point s is in an undefined state. + * + * Note that after `char *e = rfc_unescape(s)`, `strlen(s)` will not equal + * `e - s` if s originally contained "%00". You might want to check for this. */ -_PUBLIC_ void -rfc1738_unescape(char *s) + +_PUBLIC_ char *rfc1738_unescape(char *s) { - char hexnum[3]; - int i, j; /* i is write, j is read */ - unsigned int x; - for (i = j = 0; s[j]; i++, j++) { - s[i] = s[j]; - if (s[i] != '%') - continue; - if (s[j + 1] == '%') { /* %% case */ - j++; - continue; - } - if (s[j + 1] && s[j + 2]) { - if (s[j + 1] == '0' && s[j + 2] == '0') { /* %00 case */ - j += 2; - continue; - } - hexnum[0] = s[j + 1]; - hexnum[1] = s[j + 2]; - hexnum[2] = '\0'; - if (1 == sscanf(hexnum, "%x", &x)) { - s[i] = (char) (0x0ff & x); - j += 2; - } - } - } - s[i] = '\0'; + size_t i, j; /* i is write, j is read */ + uint64_t x; + NTSTATUS status; + for (i = 0, j = 0; s[j] != '\0'; i++, j++) { + if (s[j] == '%') { + status = read_hex_bytes(&s[j + 1], 2, &x); + if (! NT_STATUS_IS_OK(status)) { + return NULL; + } + j += 2; /* OK; read_hex_bytes() has checked ahead */ + s[i] = (unsigned char)x; + } else { + s[i] = s[j]; + } + } + s[i] = '\0'; + return s + i; } diff --git a/lib/util/samba_util.h b/lib/util/samba_util.h index 3daf3df..b782523 100644 --- a/lib/util/samba_util.h +++ b/lib/util/samba_util.h @@ -225,23 +225,7 @@ _PUBLIC_ char *hex_encode_talloc(TALLOC_CTX *mem_ctx, const unsigned char *buff_ /** Unescape a URL encoded string, in place. **/ -_PUBLIC_ void rfc1738_unescape(char *buf); - - -/** - * rfc1738_escape - * Returns a static buffer that contains the RFC - * 1738 compliant, escaped version of the given url. (escapes unsafe and % characters) - **/ -_PUBLIC_ char *rfc1738_escape(TALLOC_CTX *mem_ctx, const char *url); - -/** - * rfc1738_escape_unescaped - * - * Returns a static buffer that contains - * the RFC 1738 compliant, escaped version of the given url (escapes unsafe chars only) - **/ -_PUBLIC_ char *rfc1738_escape_unescaped(TALLOC_CTX *mem_ctx, const char *url); +_PUBLIC_ char *rfc1738_unescape(char *buf); /** * rfc1738_escape_part diff --git a/lib/util/tests/rfc1738.c b/lib/util/tests/rfc1738.c new file mode 100644 index 0000000..6e96037 --- /dev/null +++ b/lib/util/tests/rfc1738.c @@ -0,0 +1,411 @@ +#include <stdarg.h> +#include <stddef.h> +#include <setjmp.h> +#include <stdint.h> +#include <cmocka.h> +#include "lib/replace/replace.h" + +#include <errno.h> +#include <unistd.h> +#include <talloc.h> +#include <ctype.h> +#include <string.h> +#include "lib/util/samba_util.h" + +/* These flags say what can be asserted about a relationship between a string + and its supposedly escaped equivalent. + + The first part of the flag name indicates the direction of transformation; + tyhe second part is the expected result. For example, ESCAPE_EQ means the + escape is expected to succeed and result is expected to be equal to the + given answer. ESCAPE_EQ_CASECMP is only equal when compared + case-insensitively. UNESCAPE_ERR means unescaping the escaped string should + result in an error. +*/ +#define UNESCAPE_ERR 1 +#define ESCAPE_ERR 2 +#define ESCAPE_EQ 4 +#define UNESCAPE_EQ 8 +#define ESCAPE_NE 16 +#define UNESCAPE_NE 32 +#define ESCAPE_EQ_CASECMP 64 + +struct rfc1738_test { + const char *escaped; /* original for unescape; result for escape */ + const char *unescaped; /* result in unescape; original for escape */ + uint32_t flags; /* see above */ + int unesc_len; /* end - start will be this */ + int unesc_strlen; /* strlen() will say this */ + int esc_len; /* escaped string length */ +}; + +/* unreserved = ALPHA DIGIT - . _ ~ */ + +char spectrum[255 + 1]; +char spectrum_escaped[255 * 3 + 1]; + +struct rfc1738_test examples[] = { + +#define SIMPLE1 "this_is_a_simple-string._With_no_escapes~" /* maps to self */ + { + SIMPLE1, + SIMPLE1, + ESCAPE_EQ | UNESCAPE_EQ, /* round trip should work */ + sizeof(SIMPLE1) - 1, + sizeof(SIMPLE1) - 1, + sizeof(SIMPLE1) - 1, + }, +#define SIMPLE2 "no escapes, but\n non-printables \xc5\x8d\x99" +#define SIMPLE2_ESC "no%20escapes%2C%20but%0A%20non-printables%20%C5%8D%99" + { + SIMPLE2_ESC, + SIMPLE2, + ESCAPE_EQ | UNESCAPE_EQ, + sizeof(SIMPLE2) - 1, + sizeof(SIMPLE2) - 1, + sizeof(SIMPLE2_ESC) - 1, + }, +#define SIMPLE3 "this @#$^&*()_+{}:;" +#define SIMPLE3_ESC "this%20%40%23%24%5E%26%2A%28%29_%2B%7B%7D%3A%3B" + { + SIMPLE3_ESC, + SIMPLE3, + ESCAPE_EQ | UNESCAPE_EQ, + sizeof(SIMPLE3) - 1, + sizeof(SIMPLE3) - 1, + sizeof(SIMPLE3_ESC) - 1, + }, + +#define ESCAPE1 "%/\x06this string has expected escapes" +#define ESCAPE1_ESC "%25%2F%06this%20string%20has%20expected%20escapes" +#define ESCAPE1_ESC_ESC "%2525%252F%2506this%2520string%2520has%2520expected"\ + "%2520escapes" + { + ESCAPE1_ESC, + ESCAPE1, + ESCAPE_EQ | UNESCAPE_EQ, + sizeof(ESCAPE1) - 1, + sizeof(ESCAPE1) - 1, + sizeof(ESCAPE1_ESC) - 1, + }, + { + ESCAPE1_ESC_ESC, /*re-escaping */ + ESCAPE1_ESC, + ESCAPE_EQ | UNESCAPE_EQ, + sizeof(ESCAPE1_ESC) - 1, + sizeof(ESCAPE1_ESC) - 1, + sizeof(ESCAPE1_ESC_ESC) - 1, + }, +#define ESCAPE2 "%25%2f%06-this-string-has-expected-lowercase-escapes-%ab" +#define ESCAPE2_UNESC "%/\x06-this-string-has-expected-lowercase-escapes-\xab" + { + ESCAPE2, + ESCAPE2_UNESC, + ESCAPE_EQ_CASECMP | UNESCAPE_EQ, /* escape won't match case */ + sizeof(ESCAPE2_UNESC) - 1, + sizeof(ESCAPE2_UNESC) - 1, + sizeof(ESCAPE2) - 1, + }, +#define ESCAPE3 "%25%2f%06 %32 %44 %6a%AA THIS string h%61s random escapes %ab" +#define ESCAPE3_UNESC "%/\x06 2 D j\xAA THIS string has random escapes \xab" + { + ESCAPE3, + ESCAPE3_UNESC, + ESCAPE_NE | UNESCAPE_EQ, /* escape will have escaped spaces */ + sizeof(ESCAPE3_UNESC) - 1, + sizeof(ESCAPE3_UNESC) - 1, + sizeof(ESCAPE3) - 1, + }, +#define ESCAPE4 "%25%25%25" /* */ +#define ESCAPE4_UNESC "%%%" /* */ +#define ESCAPE4_ESC "%2525%2525%2525" + { + ESCAPE4, + ESCAPE4_UNESC, + ESCAPE_EQ | UNESCAPE_EQ, + sizeof(ESCAPE4_UNESC) - 1, + sizeof(ESCAPE4_UNESC) - 1, + sizeof(ESCAPE4) - 1, + }, + { + ESCAPE4_ESC, + ESCAPE4, + ESCAPE_EQ | UNESCAPE_EQ, + sizeof(ESCAPE4) - 1, -- Samba Shared Repository