1/*
2 * Copyright (c) 2008 - 2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <sys/param.h>
25#include <sys/kernel.h>
26#include <sys/systm.h>
27#include <sys/malloc.h>
28#include <sys/smb_apple.h>
29
30#include <netsmb/smb.h>
31#include <netsmb/smb_2.h>
32#include <netsmb/smb_conn.h>
33#include <netsmb/smb_subr.h>
34#include <netsmb/smb_converter.h>
35#include <sys/smb_byte_order.h>
36
37/* UCS2 to CodePage Conversion Data */
38typedef struct _UCSTo8BitCharMap {
39    uint16_t _u;
40    uint8_t _c;
41} UCSTo8BitCharMap;
42
43/* CodePage to UCS2 Conversion Data */
44static const uint16_t cp437_to_ucs2[128] = {
45	0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
46	0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
47	0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
48	0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
49	0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
50	0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
51	0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
52	0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
53	0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
54	0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
55	0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
56	0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
57	0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
58	0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
59	0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
60	0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
61};
62
63/* DOS Latin US (Code Page 437) */
64static const UCSTo8BitCharMap cp437_from_ucs2[128] = {
65	{0x00a0, 0xff}, // NO-BREAK SPACE
66	{0x00a1, 0xad}, // INVERTED EXCLAMATION MARK
67	{0x00a2, 0x9b}, // CENT SIGN
68	{0x00a3, 0x9c}, // POUND SIGN
69	{0x00a5, 0x9d}, // YEN SIGN
70	{0x00aa, 0xa6}, // FEMININE ORDINAL INDICATOR
71	{0x00ab, 0xae}, // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
72	{0x00ac, 0xaa}, // NOT SIGN
73	{0x00b0, 0xf8}, // DEGREE SIGN
74	{0x00b1, 0xf1}, // PLUS-MINUS SIGN
75	{0x00b2, 0xfd}, // SUPERSCRIPT TWO
76	{0x00b5, 0xe6}, // MICRO SIGN
77	{0x00b7, 0xfa}, // MIDDLE DOT
78	{0x00ba, 0xa7}, // MASCULINE ORDINAL INDICATOR
79	{0x00bb, 0xaf}, // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
80	{0x00bc, 0xac}, // VULGAR FRACTION ONE QUARTER
81	{0x00bd, 0xab}, // VULGAR FRACTION ONE HALF
82	{0x00bf, 0xa8}, // INVERTED QUESTION MARK
83	{0x00c4, 0x8e}, // LATIN CAPITAL LETTER A WITH DIAERESIS
84	{0x00c5, 0x8f}, // LATIN CAPITAL LETTER A WITH RING ABOVE
85	{0x00c6, 0x92}, // LATIN CAPITAL LIGATURE AE
86	{0x00c7, 0x80}, // LATIN CAPITAL LETTER C WITH CEDILLA
87	{0x00c9, 0x90}, // LATIN CAPITAL LETTER E WITH ACUTE
88	{0x00d1, 0xa5}, // LATIN CAPITAL LETTER N WITH TILDE
89	{0x00d6, 0x99}, // LATIN CAPITAL LETTER O WITH DIAERESIS
90	{0x00dc, 0x9a}, // LATIN CAPITAL LETTER U WITH DIAERESIS
91	{0x00df, 0xe1}, // LATIN SMALL LETTER SHARP S
92	{0x00e0, 0x85}, // LATIN SMALL LETTER A WITH GRAVE
93	{0x00e1, 0xa0}, // LATIN SMALL LETTER A WITH ACUTE
94	{0x00e2, 0x83}, // LATIN SMALL LETTER A WITH CIRCUMFLEX
95	{0x00e4, 0x84}, // LATIN SMALL LETTER A WITH DIAERESIS
96	{0x00e5, 0x86}, // LATIN SMALL LETTER A WITH RING ABOVE
97	{0x00e6, 0x91}, // LATIN SMALL LIGATURE AE
98	{0x00e7, 0x87}, // LATIN SMALL LETTER C WITH CEDILLA
99	{0x00e8, 0x8a}, // LATIN SMALL LETTER E WITH GRAVE
100	{0x00e9, 0x82}, // LATIN SMALL LETTER E WITH ACUTE
101	{0x00ea, 0x88}, // LATIN SMALL LETTER E WITH CIRCUMFLEX
102	{0x00eb, 0x89}, // LATIN SMALL LETTER E WITH DIAERESIS
103	{0x00ec, 0x8d}, // LATIN SMALL LETTER I WITH GRAVE
104	{0x00ed, 0xa1}, // LATIN SMALL LETTER I WITH ACUTE
105	{0x00ee, 0x8c}, // LATIN SMALL LETTER I WITH CIRCUMFLEX
106	{0x00ef, 0x8b}, // LATIN SMALL LETTER I WITH DIAERESIS
107	{0x00f1, 0xa4}, // LATIN SMALL LETTER N WITH TILDE
108	{0x00f2, 0x95}, // LATIN SMALL LETTER O WITH GRAVE
109	{0x00f3, 0xa2}, // LATIN SMALL LETTER O WITH ACUTE
110	{0x00f4, 0x93}, // LATIN SMALL LETTER O WITH CIRCUMFLEX
111	{0x00f6, 0x94}, // LATIN SMALL LETTER O WITH DIAERESIS
112	{0x00f7, 0xf6}, // DIVISION SIGN
113	{0x00f9, 0x97}, // LATIN SMALL LETTER U WITH GRAVE
114	{0x00fa, 0xa3}, // LATIN SMALL LETTER U WITH ACUTE
115	{0x00fb, 0x96}, // LATIN SMALL LETTER U WITH CIRCUMFLEX
116	{0x00fc, 0x81}, // LATIN SMALL LETTER U WITH DIAERESIS
117	{0x00ff, 0x98}, // LATIN SMALL LETTER Y WITH DIAERESIS
118	{0x0192, 0x9f}, // LATIN SMALL LETTER F WITH HOOK
119	{0x0393, 0xe2}, // GREEK CAPITAL LETTER GAMMA
120	{0x0398, 0xe9}, // GREEK CAPITAL LETTER THETA
121	{0x03a3, 0xe4}, // GREEK CAPITAL LETTER SIGMA
122	{0x03a6, 0xe8}, // GREEK CAPITAL LETTER PHI
123	{0x03a9, 0xea}, // GREEK CAPITAL LETTER OMEGA
124	{0x03b1, 0xe0}, // GREEK SMALL LETTER ALPHA
125	{0x03b4, 0xeb}, // GREEK SMALL LETTER DELTA
126	{0x03b5, 0xee}, // GREEK SMALL LETTER EPSILON
127	{0x03c0, 0xe3}, // GREEK SMALL LETTER PI
128	{0x03c3, 0xe5}, // GREEK SMALL LETTER SIGMA
129	{0x03c4, 0xe7}, // GREEK SMALL LETTER TAU
130	{0x03c6, 0xed}, // GREEK SMALL LETTER PHI
131	{0x207f, 0xfc}, // SUPERSCRIPT LATIN SMALL LETTER N
132	{0x20a7, 0x9e}, // PESETA SIGN
133	{0x2219, 0xf9}, // BULLET OPERATOR
134	{0x221a, 0xfb}, // SQUARE ROOT
135	{0x221e, 0xec}, // INFINITY
136	{0x2229, 0xef}, // INTERSECTION
137	{0x2248, 0xf7}, // ALMOST EQUAL TO
138	{0x2261, 0xf0}, // IDENTICAL TO
139	{0x2264, 0xf3}, // LESS-THAN OR EQUAL TO
140	{0x2265, 0xf2}, // GREATER-THAN OR EQUAL TO
141	{0x2310, 0xa9}, // REVERSED NOT SIGN
142	{0x2320, 0xf4}, // TOP HALF INTEGRAL
143	{0x2321, 0xf5}, // BOTTOM HALF INTEGRAL
144	{0x2500, 0xc4}, // BOX DRAWINGS LIGHT HORIZONTAL
145	{0x2502, 0xb3}, // BOX DRAWINGS LIGHT VERTICAL
146	{0x250c, 0xda}, // BOX DRAWINGS LIGHT DOWN AND RIGHT
147	{0x2510, 0xbf}, // BOX DRAWINGS LIGHT DOWN AND LEFT
148	{0x2514, 0xc0}, // BOX DRAWINGS LIGHT UP AND RIGHT
149	{0x2518, 0xd9}, // BOX DRAWINGS LIGHT UP AND LEFT
150	{0x251c, 0xc3}, // BOX DRAWINGS LIGHT VERTICAL AND RIGHT
151	{0x2524, 0xb4}, // BOX DRAWINGS LIGHT VERTICAL AND LEFT
152	{0x252c, 0xc2}, // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
153	{0x2534, 0xc1}, // BOX DRAWINGS LIGHT UP AND HORIZONTAL
154	{0x253c, 0xc5}, // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
155	{0x2550, 0xcd}, // BOX DRAWINGS DOUBLE HORIZONTAL
156	{0x2551, 0xba}, // BOX DRAWINGS DOUBLE VERTICAL
157	{0x2552, 0xd5}, // BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
158	{0x2553, 0xd6}, // BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
159	{0x2554, 0xc9}, // BOX DRAWINGS DOUBLE DOWN AND RIGHT
160	{0x2555, 0xb8}, // BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
161	{0x2556, 0xb7}, // BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
162	{0x2557, 0xbb}, // BOX DRAWINGS DOUBLE DOWN AND LEFT
163	{0x2558, 0xd4}, // BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
164	{0x2559, 0xd3}, // BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
165	{0x255a, 0xc8}, // BOX DRAWINGS DOUBLE UP AND RIGHT
166	{0x255b, 0xbe}, // BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
167	{0x255c, 0xbd}, // BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
168	{0x255d, 0xbc}, // BOX DRAWINGS DOUBLE UP AND LEFT
169	{0x255e, 0xc6}, // BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
170	{0x255f, 0xc7}, // BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
171	{0x2560, 0xcc}, // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
172	{0x2561, 0xb5}, // BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
173	{0x2562, 0xb6}, // BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
174	{0x2563, 0xb9}, // BOX DRAWINGS DOUBLE VERTICAL AND LEFT
175	{0x2564, 0xd1}, // BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
176	{0x2565, 0xd2}, // BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
177	{0x2566, 0xcb}, // BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
178	{0x2567, 0xcf}, // BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
179	{0x2568, 0xd0}, // BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
180	{0x2569, 0xca}, // BOX DRAWINGS DOUBLE UP AND HORIZONTAL
181	{0x256a, 0xd8}, // BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
182	{0x256b, 0xd7}, // BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
183	{0x256c, 0xce}, // BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
184	{0x2580, 0xdf}, // UPPER HALF BLOCK
185	{0x2584, 0xdc}, // LOWER HALF BLOCK
186	{0x2588, 0xdb}, // FULL BLOCK
187	{0x258c, 0xdd}, // LEFT HALF BLOCK
188	{0x2590, 0xde}, // RIGHT HALF BLOCK
189	{0x2591, 0xb0}, // LIGHT SHADE
190	{0x2592, 0xb1}, // MEDIUM SHADE
191	{0x2593, 0xb2}, // DARK SHADE
192	{0x25a0, 0xfe}, // BLACK SQUARE
193};
194
195static int
196codepage_to_ucs2(const uint16_t *convtbl, const uint8_t *src, size_t srclen,
197				 size_t bufsize, uint16_t *unibuf, size_t *unilen)
198{
199	uint8_t byte;
200	size_t n, r;
201
202	r = n = MIN(srclen, bufsize/2);
203
204	while (r--) {
205		byte = *src++;
206		if (byte < 0x80)
207			*unibuf++ = (uint16_t)byte;
208		else
209			*unibuf++ = convtbl[byte - 0x80];
210	}
211	*unilen = n * 2;
212
213	return 0;
214}
215
216/*
217 * UCSTo8BitEncoding
218 * Binary searches UCSTo8BitCharMap to find char mapping
219 */
220static int
221UCSTo8BitEncoding(const UCSTo8BitCharMap *theTable, int numElem,
222				  uint16_t character, uint8_t *ch)
223{
224    const UCSTo8BitCharMap *p, *q, *divider;
225
226    if ((character < theTable[0]._u) || (character > theTable[numElem-1]._u)) {
227        return 0;
228    }
229    p = theTable;
230    q = p + (numElem-1);
231    while (p <= q) {
232        divider = p + ((q - p) >> 1);
233        if (character < divider->_u) { q = divider - 1; }
234        else if (character > divider->_u) { p = divider + 1; }
235        else { *ch = divider->_c; return 1; }
236    }
237	return 0;
238}
239
240static void
241ucs2_to_codepage(const uint16_t *convtbl, const uint16_t *src, size_t srclen,
242				 size_t bufsize, char *buf, size_t *buflen)
243{
244	uint16_t character;
245	uint8_t byte;
246	size_t n, r;
247
248	r = n = MIN(srclen/2, bufsize);
249
250	while (r--) {
251		character = *src++;
252		if (character < 0x80)
253			*buf++ = (uint8_t)character;
254		else if (UCSTo8BitEncoding((const UCSTo8BitCharMap *)convtbl, 128,
255								   character, &byte))
256			*buf++ = byte;
257		else
258			*buf++ = '_';
259	}
260	*buflen = n;
261}
262
263/*
264 * smb_convert_to_network
265 *
266 * Convert a UTF8 String to a Network String either UTF16 or Code Page 437. This
267 * routine should be used when dealing with file type names. We always set the
268 * precomposed flag, so this routine should not be call for non file type names.
269 * The calling routine needs to set the UTF_SFM_CONVERSIONS if they want SFM
270 * style mappings for illegal NTFS characters. This routine will handle any
271 * endian issues.
272 *
273 * NOTE: The UTF_NO_NULL_TERM flags does not apply when to this routine. The old
274 *		 code passed this flag in, but it was always ignored.
275 */
276int
277smb_convert_to_network(const char **inbuf, size_t *inbytesleft, char **outbuf,
278						   size_t *outbytesleft, int flags, int usingUnicode)
279{
280	int error;
281	size_t inlen;
282	size_t outlen;
283
284	DBG_ASSERT(inbuf);
285	DBG_ASSERT(*inbuf);
286	DBG_ASSERT(outbuf);
287	DBG_ASSERT(*outbuf);
288
289	inlen = *inbytesleft;
290	outlen = 0;
291
292	flags |= UTF_PRECOMPOSED;
293
294	if (usingUnicode) {
295		/* Little endian Unicode over the wire */
296		if (BYTE_ORDER != LITTLE_ENDIAN)
297			flags |= UTF_REVERSE_ENDIAN;
298		error = utf8_decodestr((const uint8_t*)*inbuf, inlen, (uint16_t *)*outbuf,
299							   &outlen, *outbytesleft, 0, flags);
300
301	} else {
302		const uint16_t *cptable = (const uint16_t *)cp437_from_ucs2;
303		uint16_t buf[256];	/* When using code pages we only support 256 file names */
304
305		error = utf8_decodestr((const uint8_t*)*inbuf, inlen, buf, &outlen,
306							   sizeof(buf), 0, flags);
307		if (!error)
308			ucs2_to_codepage(cptable, buf, outlen, *outbytesleft, *outbuf, &outlen);
309
310	}
311	if (error)
312		return error;
313
314	*inbuf += inlen;
315	*outbuf += outlen;
316	*inbytesleft -= inlen;
317	*outbytesleft -= outlen;
318	return 0;
319}
320
321/*
322 * smb_convert_from_network
323 *
324 * Convert a Network String either UTF16 or Code Page 437 to UTF8 String. This
325 * routine should be used when dealing with file type names. We always set the
326 * decomposed flag, so this routine should not be call for non file type names.
327 * Currently we always set the UTF_NO_NULL_TERM, may want to change that in the
328 * future. The calling routine needs to set the UTF_SFM_CONVERSIONS if they want
329 * SFM style mappings for illegal NTFS characters. This routine will handle any
330 * endian issues.
331 */
332int
333smb_convert_from_network(const char **inbuf, size_t *inbytesleft, char **outbuf,
334							 size_t *outbytesleft, int flags, int usingUnicode)
335{
336	int error;
337	size_t inlen;
338	size_t outlen;
339
340	DBG_ASSERT(inbuf);
341	DBG_ASSERT(*inbuf);
342	DBG_ASSERT(outbuf);
343	DBG_ASSERT(*outbuf);
344
345	inlen = *inbytesleft;
346	outlen = 0;
347
348	flags |= UTF_DECOMPOSED | UTF_NO_NULL_TERM;
349	if (usingUnicode) {
350		/* Little endian Unicode over the wire */
351		if (BYTE_ORDER != LITTLE_ENDIAN)
352			flags |= UTF_REVERSE_ENDIAN;
353		error = utf8_encodestr((uint16_t *)*inbuf, inlen, (uint8_t *)*outbuf, &outlen, *outbytesleft, 0, flags);
354	} else {
355		const uint16_t *cptable = (const uint16_t *)cp437_to_ucs2;
356		uint16_t buf[SMB_MAXFNAMELEN*2];	/* When using code pages we only support 256 file names */
357
358		codepage_to_ucs2(cptable, (uint8_t *)*inbuf, inlen, sizeof(buf), buf, &outlen);
359		error = utf8_encodestr(buf, outlen, (uint8_t *)*outbuf, &outlen, *outbytesleft, 0, flags);
360	}
361	if (error)
362		return error;
363
364	*inbuf += inlen;
365	*outbuf += outlen;
366	*inbytesleft -= inlen;
367	*outbytesleft -= outlen;
368	return 0;
369}
370
371/*
372 * smb_strtouni
373 *
374 * Convert a UTF8 String to a UTF16 String. This routine should be used when
375 * dealing with strings that need to go across the wire as UTF16. We never set
376 * the precomposed/decomposed flag, so the calling routine should pass in
377 * the correct flag.
378 *
379 * NOTE: The UTF_NO_NULL_TERM flags does not apply when used with this routine.
380 *		  The old code passed this flag in, but it was always ignored.
381 */
382size_t
383smb_strtouni(uint16_t *dst, const char *src, size_t inlen, int flags)
384{
385	size_t outlen;
386
387	if (BYTE_ORDER != LITTLE_ENDIAN)
388		flags |= UTF_REVERSE_ENDIAN;
389	if (utf8_decodestr((uint8_t *)src, inlen, dst, &outlen, inlen * 2, 0, flags) != 0)
390		outlen = 0;
391	return (outlen);
392}
393
394/*
395 * smb_unitostr
396 *
397 * Converts the network UTF-16 string to a UTF-8 string. This routine should be
398 * used when dealing with strings that have come across the wire as UTF16. We never
399 * set the precomposed/decomposed flag, so the calling routine should pass in
400 * the correct flag.
401 */
402size_t
403smb_unitostr(char *dst, const uint16_t *src, size_t inlen, size_t maxlen, int flags)
404{
405	size_t outlen;
406
407	if (BYTE_ORDER != LITTLE_ENDIAN)
408		flags |= UTF_REVERSE_ENDIAN;
409
410	if (utf8_encodestr(src, inlen, (uint8_t *)dst, &outlen, maxlen, 0, flags) != 0)
411		outlen = 0;
412
413	return (outlen);
414}
415
416/*
417 * Does the same thing as strnlen, except on a utf16 string. The n_bytes is the
418 * max number of bytes in the buffer. This routine always return the size in
419 * the number of bytes.
420 */
421size_t
422smb_utf16_strnsize(const uint16_t *s, size_t n_bytes)
423{
424	const uint16_t *es = s, *p = s;
425
426	/* Make sure es is on even boundry */
427	es += (n_bytes / 2);
428	while(*p && p != es)  {
429		p++;
430	}
431	return (uint8_t *)p - (uint8_t *)s;
432}
433
434/*
435 * Internal strlchr that checks for buffer overflows.
436 */
437static void *
438smb_strlchr(const void *s, uint8_t ch, size_t max)
439{
440	const uint8_t *str = s;
441	const uint8_t *es = str + max;
442
443	while(*str && (str != es))  {
444		if (*str == ch)
445			return (void *)str;
446		str++;
447	}
448
449	return NULL;
450}
451
452/*
453 * Does the same thing as smb_strlchr, except on a utf16 string.
454 */
455static void *
456smb_utf16_strlchr(const uint16_t *s, uint16_t ch, size_t max)
457{
458	const uint16_t *es = s, *str = s;
459
460	/* Make sure es is on even boundry */
461	es += (max / 2);
462	while((str != es) && *str)  {
463		if (*str == ch)
464			return (void *)str;
465		str++;
466	}
467
468	return NULL;
469}
470
471static char *
472set_network_delimiter(char *network, char ntwrk_delimiter, size_t delimiter_size,
473					  size_t *resid)
474{
475	if (*resid < delimiter_size)
476		return NULL;
477	*resid -= delimiter_size;
478	if (delimiter_size == 2) {
479		uint16_t *utf16_ptr = (uint16_t *)network;
480
481		*utf16_ptr++ = htoles((uint16_t)ntwrk_delimiter);
482		return (char *)utf16_ptr;
483	} else {
484		*network++ = ntwrk_delimiter;
485		return network;
486	}
487}
488
489/*
490 * Given a UTF8 path create a network path
491 *
492 * path				- A UTF8 string.
493 * max_path_len		- Number of bytes in the path string
494 * network			- Either  UTF16 or ASCII string
495 * ntwrk_len		- On input max buffer size, on output length of network buffer
496 * ntwrk_delimiter	- Delimiter to use
497 * inflags			-
498 *					  SMB_UTF_SFM_CONVERSIONS - Indicates that we should set the
499 *					  kernel UTF_SFM_CONVERSIONS (Use SFM mappings for illegal NTFS chars)
500 *					  flag.
501 *					  SMB_FULLPATH_CONVERSIONS - Indicates they want a full path,
502 *					  if the output doesn't start with a delimiter, one should be
503 *					  add.
504 */
505int
506smb_convert_path_to_network(char *path, size_t max_path_len, char *network,
507							size_t *ntwrk_len, char ntwrk_delimiter, int inflags,
508							int usingUnicode)
509{
510	int error = 0;
511	char * delimiter;
512	size_t component_len;	/* component length */
513	size_t path_resid;
514	size_t resid = *ntwrk_len;	/* Room left in the the network buffer */
515	size_t delimiter_size = (usingUnicode) ? 2 : 1;
516	int flags = (inflags & SMB_UTF_SFM_CONVERSIONS) ? UTF_SFM_CONVERSIONS : 0;
517
518	if ((inflags & SMB_FULLPATH_CONVERSIONS) && (*path != '/')) {
519		network = set_network_delimiter(network, ntwrk_delimiter, delimiter_size,
520										&resid);
521		if (network == NULL)
522			return E2BIG;
523	}
524
525	while (path && resid && max_path_len) {
526		DBG_ASSERT(resid > 0);	/* Should never fail */
527		/* Find the next delimiter in the utf-8 string */
528		delimiter = smb_strlchr(path, '/', max_path_len);
529		/* Remove the delimiter so we can get the component */
530		if (delimiter) {
531			max_path_len -= 1; /* consume the delimiter */
532			*delimiter = 0;
533		}
534		/* Get the size of this component */
535		path_resid = component_len = strnlen(path, max_path_len);
536		/* Never SFM dot or dotdot */
537		if (((component_len == 1) && (*path == '.'))  ||
538			((component_len == 2) && (*path == '.') && (*(path+1) == '.'))) {
539			error = smb_convert_to_network((const char **)&path, &path_resid,
540										   &network, &resid, 0, usingUnicode);
541
542		} else {
543			error = smb_convert_to_network((const char **)&path, &path_resid,
544										   &network, &resid, flags, usingUnicode);
545		}
546		if (error)
547			return error;
548		/* Put the path delimiter back and move the pointer pass it */
549		if (delimiter)
550			*delimiter++ = '/';
551		path = delimiter;
552		/* Remove the amount that was consumed by smb_convert_to_network */
553		max_path_len -= (component_len - path_resid);
554		/* If we have more to process then add a network delimiter */
555		if (path) {
556			network = set_network_delimiter(network, ntwrk_delimiter,
557											delimiter_size, &resid);
558			if (network == NULL)
559				return E2BIG;
560		}
561	}
562	*ntwrk_len -= resid;
563	DBG_ASSERT((ssize_t)(*ntwrk_len) >= 0);
564	return error;
565}
566
567/*
568 * Given a network string path create a UTF8 path
569 *
570 * network			- Either UTF16 or ASCII string
571 * max_ntwrk_len	- Number of bytes in the network string
572 * path				- UTF8 string.
573 * path_len			- On input max buffer size, on output length of UTF8 string
574 * ntwrk_delimiter	- Delimiter to use
575 * inflags			-
576 *					  SMB_UTF_SFM_CONVERSIONS - Indicates that we should set the
577 *					  kernel UTF_SFM_CONVERSIONS (Use SFM mappings for illegal NTFS chars)
578 *					  flag.
579 *					  SMB_FULLPATH_CONVERSIONS - Indicates they want a full path,
580 *					  if the output doesn't start with a delimiter, one should be
581 *					  add. (Not currently supported, if required should be added.
582 */
583int
584smb_convert_network_to_path(char *network, size_t max_ntwrk_len, char *path,
585							size_t *path_len, char ntwrk_delimiter, int flags,
586							int usingUnicode)
587{
588	int error = 0;
589	char * delimiter;
590	size_t component_len;	/* component length*/
591	size_t resid = *path_len;	/* Room left in the the path buffer */
592	size_t ntwrk_resid;
593
594	while (network && resid && max_ntwrk_len) {
595		DBG_ASSERT(resid > 0);	/* Should never fail */
596		/* Find the next delimiter in the network string */
597		if (usingUnicode) {
598			delimiter = smb_utf16_strlchr((const uint16_t *)network,
599										 htoles((uint16_t)ntwrk_delimiter),
600										 max_ntwrk_len);
601			/* Remove the delimiter so we can get the component */
602			if (delimiter) {
603				max_ntwrk_len -= 2; /* consume the delimiter */
604				*((uint16_t *)delimiter) = 0;
605			}			/* Get the size of this component */
606			component_len = smb_utf16_strnsize((const uint16_t *)network, max_ntwrk_len);
607
608		} else {
609			delimiter = smb_strlchr((const uint8_t *)network, ntwrk_delimiter, max_ntwrk_len);
610			/* Remove the delimiter so we can get the component */
611			if (delimiter) {
612				max_ntwrk_len -= 1; /* consume the delimiter */
613				*((uint8_t *)delimiter) = 0;
614			}
615			/* Get the size of this component */
616			component_len = strnlen(network, max_ntwrk_len);
617		}
618		ntwrk_resid = component_len; /* Amount that we want them to consume */
619		error = smb_convert_from_network((const char **)&network, &ntwrk_resid,
620										 &path, &resid, flags, usingUnicode);
621		if (error) {
622			SMBDEBUG("smb_convert_from_network = %d\n", error);
623			return error;
624		}
625		/* Put the network delimiter back and move the pointer pass it */
626		if (delimiter) {
627			if (usingUnicode) {
628				*((uint16_t *)delimiter) = htoles(ntwrk_delimiter);
629				delimiter++;
630			} else {
631				*((uint8_t *)delimiter) = ntwrk_delimiter;
632			}
633			delimiter++;
634		}
635		network = delimiter;
636		/* Remove the amount that was consumed by smb_convert_from_network */
637		max_ntwrk_len -= (component_len - ntwrk_resid);
638		/* If we have more to process then add a UNIX delimiter */
639		if (network) {
640			if (!resid)
641				return E2BIG;
642			resid -= 1;
643			*path++ = '/';
644		}
645	}
646	*path_len -= resid;
647	DBG_ASSERT((ssize_t)(*path_len) >= 0);
648	return error;
649}
650