1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Some of the source code in this file came from fs/cifs/cifs_unicode.c
5 * Copyright (c) International Business Machines Corp., 2000,2009
10 #include <linux/slab.h>
11 #include <asm/unaligned.h>
15 #include "smb_common.h"
18 * smb_utf16_bytes() - how long will a string be after conversion?
19 * @from: pointer to input string
20 * @maxbytes: don't go past this many bytes of input string
21 * @codepage: destination codepage
23 * Walk a utf16le string and return the number of bytes that the string will
24 * be after being converted to the given charset, not including any null
25 * termination required. Don't walk past maxbytes in the source buffer.
27 * Return: string length after conversion
29 static int smb_utf16_bytes(const __le16 *from, int maxbytes,
30 const struct nls_table *codepage)
33 int charlen, outlen = 0;
34 int maxwords = maxbytes / 2;
35 char tmp[NLS_MAX_CHARSET_SIZE];
38 for (i = 0; i < maxwords; i++) {
39 ftmp = get_unaligned_le16(&from[i]);
43 charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE);
54 * cifs_mapchar() - convert a host-endian char to proper char in codepage
55 * @target: where converted character should be copied
56 * @src_char: 2 byte host-endian source character
57 * @cp: codepage to which character should be converted
58 * @mapchar: should character be mapped according to mapchars mount option?
60 * This function handles the conversion of a single character. It is the
61 * responsibility of the caller to ensure that the target buffer is large
62 * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE).
64 * Return: string length after conversion
67 cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
76 * BB: Cannot handle remapping UNI_SLASH until all the calls to
77 * build_path_from_dentry are modified, as they use slash as
107 len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE);
117 * smb_from_utf16() - convert utf16le string to local charset
118 * @to: destination buffer
119 * @from: source buffer
120 * @tolen: destination buffer size (in bytes)
121 * @fromlen: source buffer size (in bytes)
122 * @codepage: codepage to which characters should be converted
123 * @mapchar: should characters be remapped according to the mapchars option?
125 * Convert a little-endian utf16le string (as sent by the server) to a string
126 * in the provided codepage. The tolen and fromlen parameters are to ensure
127 * that the code doesn't walk off of the end of the buffer (which is always
128 * a danger if the alignment of the source buffer is off). The destination
129 * string is always properly null terminated and fits in the destination
130 * buffer. Returns the length of the destination string in bytes (including
133 * Note that some windows versions actually send multiword UTF-16 characters
134 * instead of straight UTF16-2. The linux nls routines however aren't able to
135 * deal with those characters properly. In the event that we get some of
136 * those characters, they won't be translated properly.
138 * Return: string length after conversion
140 static int smb_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
141 const struct nls_table *codepage, bool mapchar)
143 int i, charlen, safelen;
145 int nullsize = nls_nullsize(codepage);
146 int fromwords = fromlen / 2;
147 char tmp[NLS_MAX_CHARSET_SIZE];
151 * because the chars can be of varying widths, we need to take care
152 * not to overflow the destination buffer when we get close to the
153 * end of it. Until we get to this offset, we don't need to check
154 * for overflow however.
156 safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize);
158 for (i = 0; i < fromwords; i++) {
159 ftmp = get_unaligned_le16(&from[i]);
164 * check to see if converting this character might make the
165 * conversion bleed into the null terminator
167 if (outlen >= safelen) {
168 charlen = cifs_mapchar(tmp, ftmp, codepage, mapchar);
169 if ((outlen + charlen) > (tolen - nullsize))
173 /* put converted char into 'to' buffer */
174 charlen = cifs_mapchar(&to[outlen], ftmp, codepage, mapchar);
178 /* properly null-terminate string */
179 for (i = 0; i < nullsize; i++)
186 * smb_strtoUTF16() - Convert character string to unicode string
187 * @to: destination buffer
188 * @from: source buffer
189 * @len: destination buffer size (in bytes)
190 * @codepage: codepage to which characters should be converted
192 * Return: string length after conversion
194 int smb_strtoUTF16(__le16 *to, const char *from, int len,
195 const struct nls_table *codepage)
199 wchar_t wchar_to; /* needed to quiet sparse */
201 /* special case for utf8 to handle no plane0 chars */
202 if (!strcmp(codepage->charset, "utf8")) {
204 * convert utf8 -> utf16, we assume we have enough space
205 * as caller should have assumed conversion does not overflow
206 * in destination len is length in wchar_t units (16bits)
208 i = utf8s_to_utf16s(from, len, UTF16_LITTLE_ENDIAN,
211 /* if success terminate and exit */
215 * if fails fall back to UCS encoding as this
216 * function should not return negative values
217 * currently can fail only if source contains
218 * invalid encoded characters
222 for (i = 0; len > 0 && *from; i++, from += charlen, len -= charlen) {
223 charlen = codepage->char2uni(from, len, &wchar_to);
225 /* A question mark */
229 put_unaligned_le16(wchar_to, &to[i]);
233 put_unaligned_le16(0, &to[i]);
238 * smb_strndup_from_utf16() - copy a string from wire format to the local
240 * @src: source string
241 * @maxlen: don't walk past this many bytes in the source string
242 * @is_unicode: is this a unicode string?
243 * @codepage: destination codepage
245 * Take a string given by the server, convert it to the local codepage and
246 * put it in a new buffer. Returns a pointer to the new string or NULL on
249 * Return: destination string buffer or error ptr
251 char *smb_strndup_from_utf16(const char *src, const int maxlen,
252 const bool is_unicode,
253 const struct nls_table *codepage)
259 len = smb_utf16_bytes((__le16 *)src, maxlen, codepage);
260 len += nls_nullsize(codepage);
261 dst = kmalloc(len, GFP_KERNEL);
263 return ERR_PTR(-ENOMEM);
264 ret = smb_from_utf16(dst, (__le16 *)src, len, maxlen, codepage,
268 return ERR_PTR(-EINVAL);
271 len = strnlen(src, maxlen);
273 dst = kmalloc(len, GFP_KERNEL);
275 return ERR_PTR(-ENOMEM);
276 strscpy(dst, src, len);
283 * Convert 16 bit Unicode pathname to wire format from string in current code
284 * page. Conversion may involve remapping up the six characters that are
285 * only legal in POSIX-like OS (if they are present in the string). Path
286 * names are little endian 16 bit Unicode on the wire
289 * smbConvertToUTF16() - convert string from local charset to utf16
290 * @target: destination buffer
291 * @source: source buffer
292 * @srclen: source buffer size (in bytes)
293 * @cp: codepage to which characters should be converted
294 * @mapchar: should characters be remapped according to the mapchars option?
296 * Convert 16 bit Unicode pathname to wire format from string in current code
297 * page. Conversion may involve remapping up the six characters that are
298 * only legal in POSIX-like OS (if they are present in the string). Path
299 * names are little endian 16 bit Unicode on the wire
301 * Return: char length after conversion
303 int smbConvertToUTF16(__le16 *target, const char *source, int srclen,
304 const struct nls_table *cp, int mapchars)
312 return smb_strtoUTF16(target, source, srclen, cp);
314 for (i = 0, j = 0; i < srclen; j++) {
315 src_char = source[i];
319 put_unaligned(0, &target[j]);
322 dst_char = cpu_to_le16(UNI_COLON);
325 dst_char = cpu_to_le16(UNI_ASTERISK);
328 dst_char = cpu_to_le16(UNI_QUESTION);
331 dst_char = cpu_to_le16(UNI_LESSTHAN);
334 dst_char = cpu_to_le16(UNI_GRTRTHAN);
337 dst_char = cpu_to_le16(UNI_PIPE);
340 * FIXME: We can not handle remapping backslash (UNI_SLASH)
341 * until all the calls to build_path_from_dentry are modified,
342 * as they use backslash as separator.
345 charlen = cp->char2uni(source + i, srclen - i, &tmp);
346 dst_char = cpu_to_le16(tmp);
349 * if no match, use question mark, which at least in
350 * some cases serves as wild card
353 dst_char = cpu_to_le16(0x003f);
358 * character may take more than one byte in the source string,
359 * but will take exactly two bytes in the target string
362 put_unaligned(dst_char, &target[j]);