From: Shyamsunder Rathi Date: Mon, 13 May 2019 06:06:17 +0000 (-0700) Subject: s3:loadparm: Ensure to truncate FS Volume Label at multibyte boundary X-Git-Tag: tdb-1.4.1~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0fa490e8476a2a5020ff2c253167b8a9454e8b97;p=thirdparty%2Fsamba.git s3:loadparm: Ensure to truncate FS Volume Label at multibyte boundary For FS_VOLUME_INFO/FS_INFO operation, a maximum of 32 characters are sent back. However, since Samba chops off any share name with >32 bytes at 32, it is possible that a multi-byte share name can get chopped off between a full character. This causes the string decoding for unicode failure which sends back NT_STATUS_ILLEGAL_CHARACTER (EILSEQ) to the client applications. On Windows, Notepad doesn't like it, and refuses to open a file in this case and fails with the following error: Invalid character. For multibyte character sets, only the leading byte is included without the trailing byte. For Unicode character sets, include the characters 0xFFFF and 0xFFFE. Proposed fix: - Find the last starting point of a multibyte codepoint if the character at 32nd byte is a subsequent byte of a MB codepoint. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13947 Signed-off-by: Shyamsunder Rathi Reviewed-by: Hemanth Thummala Reviewed-by: Jeremy Allison Reviewed-by: Andreas Schneider --- diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 5af1621fb9b..5104a3408f1 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -4244,15 +4244,47 @@ const char *volume_label(TALLOC_CTX *ctx, int snum) { char *ret; const char *label = lp_volume(ctx, snum); + size_t end = 32; + if (!*label) { label = lp_servicename(ctx, snum); } - /* This returns a 33 byte guarenteed null terminated string. */ - ret = talloc_strndup(ctx, label, 32); + /* + * Volume label can be a max of 32 bytes. Make sure to truncate + * it at a codepoint boundary if it's longer than 32 and contains + * multibyte characters. Windows insists on a volume label being + * a valid mb sequence, and errors out if not. + */ + if (strlen(label) > 32) { + /* + * A MB char can be a max of 5 bytes, thus + * we should have a valid mb character at a + * minimum position of (32-5) = 27. + */ + while (end >= 27) { + /* + * Check if a codepoint starting from next byte + * is valid. If yes, then the current byte is the + * end of a MB or ascii sequence and the label can + * be safely truncated here. If not, keep going + * backwards till a valid codepoint is found. + */ + size_t len = 0; + const char *s = &label[end]; + codepoint_t c = next_codepoint(s, &len); + if (c != INVALID_CODEPOINT) { + break; + } + end--; + } + } + + /* This returns a max of 33 byte guarenteed null terminated string. */ + ret = talloc_strndup(ctx, label, end); if (!ret) { return ""; - } + } return ret; }