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