cifs: account for primary channel in the interface list
[platform/kernel/linux-rpi.git] / fs / smb / server / unicode.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *   Some of the source code in this file came from fs/cifs/cifs_unicode.c
4  *
5  *   Copyright (c) International Business Machines  Corp., 2000,2009
6  *   Modified by Steve French (sfrench@us.ibm.com)
7  *   Modified by Namjae Jeon (linkinjeon@kernel.org)
8  */
9 #include <linux/fs.h>
10 #include <linux/slab.h>
11 #include <asm/unaligned.h>
12 #include "glob.h"
13 #include "unicode.h"
14 #include "smb_common.h"
15
16 /*
17  * smb_utf16_bytes() - how long will a string be after conversion?
18  * @from:       pointer to input string
19  * @maxbytes:   don't go past this many bytes of input string
20  * @codepage:   destination codepage
21  *
22  * Walk a utf16le string and return the number of bytes that the string will
23  * be after being converted to the given charset, not including any null
24  * termination required. Don't walk past maxbytes in the source buffer.
25  *
26  * Return:      string length after conversion
27  */
28 static int smb_utf16_bytes(const __le16 *from, int maxbytes,
29                            const struct nls_table *codepage)
30 {
31         int i;
32         int charlen, outlen = 0;
33         int maxwords = maxbytes / 2;
34         char tmp[NLS_MAX_CHARSET_SIZE];
35         __u16 ftmp;
36
37         for (i = 0; i < maxwords; i++) {
38                 ftmp = get_unaligned_le16(&from[i]);
39                 if (ftmp == 0)
40                         break;
41
42                 charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE);
43                 if (charlen > 0)
44                         outlen += charlen;
45                 else
46                         outlen++;
47         }
48
49         return outlen;
50 }
51
52 /*
53  * cifs_mapchar() - convert a host-endian char to proper char in codepage
54  * @target:     where converted character should be copied
55  * @src_char:   2 byte host-endian source character
56  * @cp:         codepage to which character should be converted
57  * @mapchar:    should character be mapped according to mapchars mount option?
58  *
59  * This function handles the conversion of a single character. It is the
60  * responsibility of the caller to ensure that the target buffer is large
61  * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE).
62  *
63  * Return:      string length after conversion
64  */
65 static int
66 cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
67              bool mapchar)
68 {
69         int len = 1;
70
71         if (!mapchar)
72                 goto cp_convert;
73
74         /*
75          * BB: Cannot handle remapping UNI_SLASH until all the calls to
76          *     build_path_from_dentry are modified, as they use slash as
77          *     separator.
78          */
79         switch (src_char) {
80         case UNI_COLON:
81                 *target = ':';
82                 break;
83         case UNI_ASTERISK:
84                 *target = '*';
85                 break;
86         case UNI_QUESTION:
87                 *target = '?';
88                 break;
89         case UNI_PIPE:
90                 *target = '|';
91                 break;
92         case UNI_GRTRTHAN:
93                 *target = '>';
94                 break;
95         case UNI_LESSTHAN:
96                 *target = '<';
97                 break;
98         default:
99                 goto cp_convert;
100         }
101
102 out:
103         return len;
104
105 cp_convert:
106         len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE);
107         if (len <= 0) {
108                 *target = '?';
109                 len = 1;
110         }
111
112         goto out;
113 }
114
115 /*
116  * smb_from_utf16() - convert utf16le string to local charset
117  * @to:         destination buffer
118  * @from:       source buffer
119  * @tolen:      destination buffer size (in bytes)
120  * @fromlen:    source buffer size (in bytes)
121  * @codepage:   codepage to which characters should be converted
122  * @mapchar:    should characters be remapped according to the mapchars option?
123  *
124  * Convert a little-endian utf16le string (as sent by the server) to a string
125  * in the provided codepage. The tolen and fromlen parameters are to ensure
126  * that the code doesn't walk off of the end of the buffer (which is always
127  * a danger if the alignment of the source buffer is off). The destination
128  * string is always properly null terminated and fits in the destination
129  * buffer. Returns the length of the destination string in bytes (including
130  * null terminator).
131  *
132  * Note that some windows versions actually send multiword UTF-16 characters
133  * instead of straight UTF16-2. The linux nls routines however aren't able to
134  * deal with those characters properly. In the event that we get some of
135  * those characters, they won't be translated properly.
136  *
137  * Return:      string length after conversion
138  */
139 static int smb_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
140                           const struct nls_table *codepage, bool mapchar)
141 {
142         int i, charlen, safelen;
143         int outlen = 0;
144         int nullsize = nls_nullsize(codepage);
145         int fromwords = fromlen / 2;
146         char tmp[NLS_MAX_CHARSET_SIZE];
147         __u16 ftmp;
148
149         /*
150          * because the chars can be of varying widths, we need to take care
151          * not to overflow the destination buffer when we get close to the
152          * end of it. Until we get to this offset, we don't need to check
153          * for overflow however.
154          */
155         safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize);
156
157         for (i = 0; i < fromwords; i++) {
158                 ftmp = get_unaligned_le16(&from[i]);
159                 if (ftmp == 0)
160                         break;
161
162                 /*
163                  * check to see if converting this character might make the
164                  * conversion bleed into the null terminator
165                  */
166                 if (outlen >= safelen) {
167                         charlen = cifs_mapchar(tmp, ftmp, codepage, mapchar);
168                         if ((outlen + charlen) > (tolen - nullsize))
169                                 break;
170                 }
171
172                 /* put converted char into 'to' buffer */
173                 charlen = cifs_mapchar(&to[outlen], ftmp, codepage, mapchar);
174                 outlen += charlen;
175         }
176
177         /* properly null-terminate string */
178         for (i = 0; i < nullsize; i++)
179                 to[outlen++] = 0;
180
181         return outlen;
182 }
183
184 /*
185  * smb_strtoUTF16() - Convert character string to unicode string
186  * @to:         destination buffer
187  * @from:       source buffer
188  * @len:        destination buffer size (in bytes)
189  * @codepage:   codepage to which characters should be converted
190  *
191  * Return:      string length after conversion
192  */
193 int smb_strtoUTF16(__le16 *to, const char *from, int len,
194                    const struct nls_table *codepage)
195 {
196         int charlen;
197         int i;
198         wchar_t wchar_to; /* needed to quiet sparse */
199
200         /* special case for utf8 to handle no plane0 chars */
201         if (!strcmp(codepage->charset, "utf8")) {
202                 /*
203                  * convert utf8 -> utf16, we assume we have enough space
204                  * as caller should have assumed conversion does not overflow
205                  * in destination len is length in wchar_t units (16bits)
206                  */
207                 i  = utf8s_to_utf16s(from, len, UTF16_LITTLE_ENDIAN,
208                                      (wchar_t *)to, len);
209
210                 /* if success terminate and exit */
211                 if (i >= 0)
212                         goto success;
213                 /*
214                  * if fails fall back to UCS encoding as this
215                  * function should not return negative values
216                  * currently can fail only if source contains
217                  * invalid encoded characters
218                  */
219         }
220
221         for (i = 0; len > 0 && *from; i++, from += charlen, len -= charlen) {
222                 charlen = codepage->char2uni(from, len, &wchar_to);
223                 if (charlen < 1) {
224                         /* A question mark */
225                         wchar_to = 0x003f;
226                         charlen = 1;
227                 }
228                 put_unaligned_le16(wchar_to, &to[i]);
229         }
230
231 success:
232         put_unaligned_le16(0, &to[i]);
233         return i;
234 }
235
236 /*
237  * smb_strndup_from_utf16() - copy a string from wire format to the local
238  *              codepage
239  * @src:        source string
240  * @maxlen:     don't walk past this many bytes in the source string
241  * @is_unicode: is this a unicode string?
242  * @codepage:   destination codepage
243  *
244  * Take a string given by the server, convert it to the local codepage and
245  * put it in a new buffer. Returns a pointer to the new string or NULL on
246  * error.
247  *
248  * Return:      destination string buffer or error ptr
249  */
250 char *smb_strndup_from_utf16(const char *src, const int maxlen,
251                              const bool is_unicode,
252                              const struct nls_table *codepage)
253 {
254         int len, ret;
255         char *dst;
256
257         if (is_unicode) {
258                 len = smb_utf16_bytes((__le16 *)src, maxlen, codepage);
259                 len += nls_nullsize(codepage);
260                 dst = kmalloc(len, GFP_KERNEL);
261                 if (!dst)
262                         return ERR_PTR(-ENOMEM);
263                 ret = smb_from_utf16(dst, (__le16 *)src, len, maxlen, codepage,
264                                      false);
265                 if (ret < 0) {
266                         kfree(dst);
267                         return ERR_PTR(-EINVAL);
268                 }
269         } else {
270                 len = strnlen(src, maxlen);
271                 len++;
272                 dst = kmalloc(len, GFP_KERNEL);
273                 if (!dst)
274                         return ERR_PTR(-ENOMEM);
275                 strscpy(dst, src, len);
276         }
277
278         return dst;
279 }
280
281 /*
282  * Convert 16 bit Unicode pathname to wire format from string in current code
283  * page. Conversion may involve remapping up the six characters that are
284  * only legal in POSIX-like OS (if they are present in the string). Path
285  * names are little endian 16 bit Unicode on the wire
286  */
287 /*
288  * smbConvertToUTF16() - convert string from local charset to utf16
289  * @target:     destination buffer
290  * @source:     source buffer
291  * @srclen:     source buffer size (in bytes)
292  * @cp:         codepage to which characters should be converted
293  * @mapchar:    should characters be remapped according to the mapchars option?
294  *
295  * Convert 16 bit Unicode pathname to wire format from string in current code
296  * page. Conversion may involve remapping up the six characters that are
297  * only legal in POSIX-like OS (if they are present in the string). Path
298  * names are little endian 16 bit Unicode on the wire
299  *
300  * Return:      char length after conversion
301  */
302 int smbConvertToUTF16(__le16 *target, const char *source, int srclen,
303                       const struct nls_table *cp, int mapchars)
304 {
305         int i, j, charlen;
306         char src_char;
307         __le16 dst_char;
308         wchar_t tmp;
309
310         if (!mapchars)
311                 return smb_strtoUTF16(target, source, srclen, cp);
312
313         for (i = 0, j = 0; i < srclen; j++) {
314                 src_char = source[i];
315                 charlen = 1;
316                 switch (src_char) {
317                 case 0:
318                         put_unaligned(0, &target[j]);
319                         return j;
320                 case ':':
321                         dst_char = cpu_to_le16(UNI_COLON);
322                         break;
323                 case '*':
324                         dst_char = cpu_to_le16(UNI_ASTERISK);
325                         break;
326                 case '?':
327                         dst_char = cpu_to_le16(UNI_QUESTION);
328                         break;
329                 case '<':
330                         dst_char = cpu_to_le16(UNI_LESSTHAN);
331                         break;
332                 case '>':
333                         dst_char = cpu_to_le16(UNI_GRTRTHAN);
334                         break;
335                 case '|':
336                         dst_char = cpu_to_le16(UNI_PIPE);
337                         break;
338                 /*
339                  * FIXME: We can not handle remapping backslash (UNI_SLASH)
340                  * until all the calls to build_path_from_dentry are modified,
341                  * as they use backslash as separator.
342                  */
343                 default:
344                         charlen = cp->char2uni(source + i, srclen - i, &tmp);
345                         dst_char = cpu_to_le16(tmp);
346
347                         /*
348                          * if no match, use question mark, which at least in
349                          * some cases serves as wild card
350                          */
351                         if (charlen < 1) {
352                                 dst_char = cpu_to_le16(0x003f);
353                                 charlen = 1;
354                         }
355                 }
356                 /*
357                  * character may take more than one byte in the source string,
358                  * but will take exactly two bytes in the target string
359                  */
360                 i += charlen;
361                 put_unaligned(dst_char, &target[j]);
362         }
363
364         return j;
365 }