1/* 2 Unix SMB/CIFS implementation. 3 4 routines for marshalling/unmarshalling string types 5 6 Copyright (C) Andrew Tridgell 2003 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21*/ 22 23#include "includes.h" 24 25/** 26 pull a general string from the wire 27*/ 28NTSTATUS ndr_pull_string(struct ndr_pull *ndr, int ndr_flags, const char **s) 29{ 30 char *as=NULL; 31 uint32_t len1, ofs, len2; 32 uint16_t len3; 33 int ret; 34 charset_t chset = CH_UTF16LE; 35 unsigned byte_mul = 2; 36 unsigned flags = ndr->flags; 37 unsigned c_len_term = 0; 38 39 if (!(ndr_flags & NDR_SCALARS)) { 40 return NT_STATUS_OK; 41 } 42 43 if (NDR_BE(ndr)) { 44 chset = CH_UTF16BE; 45 } 46 47 if (flags & LIBNDR_FLAG_STR_ASCII) { 48 chset = CH_DOS; 49 byte_mul = 1; 50 flags &= ~LIBNDR_FLAG_STR_ASCII; 51 } 52 53 if (flags & LIBNDR_FLAG_STR_UTF8) { 54 chset = CH_UTF8; 55 byte_mul = 1; 56 flags &= ~LIBNDR_FLAG_STR_UTF8; 57 } 58 59 flags &= ~LIBNDR_FLAG_STR_CONFORMANT; 60 if (flags & LIBNDR_FLAG_STR_CHARLEN) { 61 c_len_term = 1; 62 flags &= ~LIBNDR_FLAG_STR_CHARLEN; 63 } 64 65 switch (flags & LIBNDR_STRING_FLAGS) { 66 case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4: 67 case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM: 68 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1)); 69 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs)); 70 if (ofs != 0) { 71 return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n", 72 ndr->flags & LIBNDR_STRING_FLAGS); 73 } 74 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len2)); 75 if (len2 > len1) { 76 return ndr_pull_error(ndr, NDR_ERR_STRING, 77 "Bad string lengths len1=%u ofs=%u len2=%u\n", 78 len1, ofs, len2); 79 } 80 NDR_PULL_NEED_BYTES(ndr, (len2 + c_len_term)*byte_mul); 81 if (len2 == 0) { 82 as = talloc_strdup(ndr->current_mem_ctx, ""); 83 } else { 84 ret = convert_string_talloc(ndr->current_mem_ctx, 85 chset, CH_UNIX, 86 ndr->data+ndr->offset, 87 (len2 + c_len_term)*byte_mul, 88 &as, True); 89 if (ret == -1) { 90 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 91 "Bad character conversion"); 92 } 93 } 94 NDR_CHECK(ndr_pull_advance(ndr, (len2 + c_len_term)*byte_mul)); 95 96 if (len1 != len2) { 97 DEBUG(6,("len1[%u] != len2[%u] '%s'\n", len1, len2, as)); 98 } 99 100 /* this is a way of detecting if a string is sent with the wrong 101 termination */ 102 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) { 103 if (strlen(as) < (len2 + c_len_term)) { 104 DEBUG(6,("short string '%s'\n", as)); 105 } 106 } else { 107 if (strlen(as) == (len2 + c_len_term)) { 108 DEBUG(6,("long string '%s'\n", as)); 109 } 110 } 111 *s = as; 112 break; 113 114 case LIBNDR_FLAG_STR_SIZE4: 115 case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM: 116 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1)); 117 NDR_PULL_NEED_BYTES(ndr, (len1 + c_len_term)*byte_mul); 118 if (len1 == 0) { 119 as = talloc_strdup(ndr->current_mem_ctx, ""); 120 } else { 121 ret = convert_string_talloc(ndr->current_mem_ctx, 122 chset, CH_UNIX, 123 ndr->data+ndr->offset, 124 (len1 + c_len_term)*byte_mul, 125 &as, False); 126 if (ret == -1) { 127 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 128 "Bad character conversion"); 129 } 130 } 131 NDR_CHECK(ndr_pull_advance(ndr, (len1 + c_len_term)*byte_mul)); 132 133 /* this is a way of detecting if a string is sent with the wrong 134 termination */ 135 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) { 136 if (strlen(as) < (len1 + c_len_term)) { 137 DEBUG(6,("short string '%s'\n", as)); 138 } 139 } else { 140 if (strlen(as) == (len1 + c_len_term)) { 141 DEBUG(6,("long string '%s'\n", as)); 142 } 143 } 144 *s = as; 145 break; 146 147 case LIBNDR_FLAG_STR_LEN4: 148 case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM: 149 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs)); 150 if (ofs != 0) { 151 return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n", 152 ndr->flags & LIBNDR_STRING_FLAGS); 153 } 154 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1)); 155 NDR_PULL_NEED_BYTES(ndr, (len1 + c_len_term)*byte_mul); 156 if (len1 == 0) { 157 as = talloc_strdup(ndr->current_mem_ctx, ""); 158 } else { 159 ret = convert_string_talloc(ndr->current_mem_ctx, 160 chset, CH_UNIX, 161 ndr->data+ndr->offset, 162 (len1 + c_len_term)*byte_mul, 163 &as, False); 164 if (ret == -1) { 165 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 166 "Bad character conversion"); 167 } 168 } 169 NDR_CHECK(ndr_pull_advance(ndr, (len1 + c_len_term)*byte_mul)); 170 171 /* this is a way of detecting if a string is sent with the wrong 172 termination */ 173 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) { 174 if (strlen(as) < (len1 + c_len_term)) { 175 DEBUG(6,("short string '%s'\n", as)); 176 } 177 } else { 178 if (strlen(as) == (len1 + c_len_term)) { 179 DEBUG(6,("long string '%s'\n", as)); 180 } 181 } 182 *s = as; 183 break; 184 185 186 case LIBNDR_FLAG_STR_SIZE2: 187 case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM: 188 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3)); 189 NDR_PULL_NEED_BYTES(ndr, (len3 + c_len_term)*byte_mul); 190 if (len3 == 0) { 191 as = talloc_strdup(ndr->current_mem_ctx, ""); 192 } else { 193 ret = convert_string_talloc(ndr->current_mem_ctx, 194 chset, CH_UNIX, 195 ndr->data+ndr->offset, 196 (len3 + c_len_term)*byte_mul, 197 &as, False); 198 if (ret == -1) { 199 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 200 "Bad character conversion"); 201 } 202 } 203 NDR_CHECK(ndr_pull_advance(ndr, (len3 + c_len_term)*byte_mul)); 204 205 /* this is a way of detecting if a string is sent with the wrong 206 termination */ 207 if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) { 208 if (strlen(as) < (len3 + c_len_term)) { 209 DEBUG(6,("short string '%s'\n", as)); 210 } 211 } else { 212 if (strlen(as) == (len3 + c_len_term)) { 213 DEBUG(6,("long string '%s'\n", as)); 214 } 215 } 216 *s = as; 217 break; 218 219 case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_BYTESIZE: 220 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3)); 221 NDR_PULL_NEED_BYTES(ndr, len3); 222 if (len3 == 0) { 223 as = talloc_strdup(ndr->current_mem_ctx, ""); 224 } else { 225 ret = convert_string_talloc(ndr->current_mem_ctx, 226 chset, CH_UNIX, 227 ndr->data+ndr->offset, 228 len3, &as, False); 229 if (ret == -1) { 230 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 231 "Bad character conversion"); 232 } 233 } 234 NDR_CHECK(ndr_pull_advance(ndr, len3)); 235 *s = as; 236 break; 237 238 case LIBNDR_FLAG_STR_NULLTERM: 239 if (byte_mul == 1) { 240 len1 = ascii_len_n((const char *)(ndr->data+ndr->offset), ndr->data_size - ndr->offset); 241 } else { 242 len1 = utf16_len_n(ndr->data+ndr->offset, ndr->data_size - ndr->offset); 243 } 244 ret = convert_string_talloc(ndr->current_mem_ctx, 245 chset, CH_UNIX, 246 ndr->data+ndr->offset, 247 len1, &as, False); 248 if (ret == -1) { 249 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 250 "Bad character conversion"); 251 } 252 NDR_CHECK(ndr_pull_advance(ndr, len1)); 253 *s = as; 254 break; 255 256 case LIBNDR_FLAG_STR_FIXLEN15: 257 case LIBNDR_FLAG_STR_FIXLEN32: 258 len1 = (flags & LIBNDR_FLAG_STR_FIXLEN32)?32:15; 259 NDR_PULL_NEED_BYTES(ndr, len1*byte_mul); 260 ret = convert_string_talloc(ndr->current_mem_ctx, 261 chset, CH_UNIX, 262 ndr->data+ndr->offset, 263 len1*byte_mul, &as, False); 264 if (ret == -1) { 265 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 266 "Bad character conversion"); 267 } 268 NDR_CHECK(ndr_pull_advance(ndr, len1*byte_mul)); 269 *s = as; 270 break; 271 272 default: 273 return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n", 274 ndr->flags & LIBNDR_STRING_FLAGS); 275 } 276 277 return NT_STATUS_OK; 278} 279 280 281/** 282 push a general string onto the wire 283*/ 284NTSTATUS ndr_push_string(struct ndr_push *ndr, int ndr_flags, const char *s) 285{ 286 ssize_t s_len, c_len, d_len; 287 charset_t chset = CH_UTF16LE; 288 unsigned flags = ndr->flags; 289 unsigned byte_mul = 2; 290 uint8_t *dest = NULL; 291 292 if (!(ndr_flags & NDR_SCALARS)) { 293 return NT_STATUS_OK; 294 } 295 296 if (NDR_BE(ndr)) { 297 chset = CH_UTF16BE; 298 } 299 300 s_len = s?strlen(s):0; 301 302 if (flags & LIBNDR_FLAG_STR_ASCII) { 303 chset = CH_DOS; 304 byte_mul = 1; 305 flags &= ~LIBNDR_FLAG_STR_ASCII; 306 } 307 308 if (flags & LIBNDR_FLAG_STR_UTF8) { 309 chset = CH_UTF8; 310 byte_mul = 1; 311 flags &= ~LIBNDR_FLAG_STR_UTF8; 312 } 313 314 flags &= ~LIBNDR_FLAG_STR_CONFORMANT; 315 316 if (!(flags & 317 (LIBNDR_FLAG_STR_NOTERM | 318 LIBNDR_FLAG_STR_FIXLEN15 | 319 LIBNDR_FLAG_STR_FIXLEN32))) { 320 s_len++; 321 } 322 d_len = convert_string_talloc(ndr, CH_UNIX, chset, s, s_len, &dest, 323 False); 324 if (d_len == -1) { 325 return ndr_push_error(ndr, NDR_ERR_CHARCNV, 326 "Bad character conversion"); 327 } 328 329 if (flags & LIBNDR_FLAG_STR_BYTESIZE) { 330 c_len = d_len; 331 flags &= ~LIBNDR_FLAG_STR_BYTESIZE; 332 } else if (flags & LIBNDR_FLAG_STR_CHARLEN) { 333 c_len = (d_len / byte_mul)-1; 334 flags &= ~LIBNDR_FLAG_STR_CHARLEN; 335 } else { 336 c_len = d_len / byte_mul; 337 } 338 339 switch ((flags & LIBNDR_STRING_FLAGS) & ~LIBNDR_FLAG_STR_NOTERM) { 340 case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4: 341 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len)); 342 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0)); 343 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len)); 344 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len)); 345 break; 346 347 case LIBNDR_FLAG_STR_LEN4: 348 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0)); 349 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len)); 350 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len)); 351 break; 352 353 case LIBNDR_FLAG_STR_SIZE4: 354 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, c_len)); 355 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len)); 356 break; 357 358 case LIBNDR_FLAG_STR_SIZE2: 359 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, c_len)); 360 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len)); 361 break; 362 363 case LIBNDR_FLAG_STR_NULLTERM: 364 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len)); 365 break; 366 367 case LIBNDR_FLAG_STR_FIXLEN15: 368 case LIBNDR_FLAG_STR_FIXLEN32: { 369 ssize_t fix_len = (flags & LIBNDR_FLAG_STR_FIXLEN32)?32:15; 370 uint32_t pad_len = fix_len - d_len; 371 if (d_len > fix_len) { 372 return ndr_push_error(ndr, NDR_ERR_CHARCNV, 373 "Bad character conversion"); 374 } 375 NDR_CHECK(ndr_push_bytes(ndr, dest, d_len)); 376 if (pad_len != 0) { 377 NDR_CHECK(ndr_push_zero(ndr, pad_len)); 378 } 379 break; 380 } 381 382 default: 383 return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n", 384 ndr->flags & LIBNDR_STRING_FLAGS); 385 } 386 387 talloc_free(dest); 388 389 return NT_STATUS_OK; 390} 391 392/** 393 push a general string onto the wire 394*/ 395size_t ndr_string_array_size(struct ndr_push *ndr, const char *s) 396{ 397 size_t c_len; 398 unsigned flags = ndr->flags; 399 unsigned byte_mul = 2; 400 unsigned c_len_term = 1; 401 402 if (flags & LIBNDR_FLAG_STR_FIXLEN32) { 403 return 32; 404 } 405 if (flags & LIBNDR_FLAG_STR_FIXLEN15) { 406 return 15; 407 } 408 409 c_len = s?strlen(s):0; 410 411 if (flags & (LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_UTF8)) { 412 byte_mul = 1; 413 } 414 415 if (flags & LIBNDR_FLAG_STR_NOTERM) { 416 c_len_term = 0; 417 } 418 419 c_len = c_len + c_len_term; 420 421 if (flags & LIBNDR_FLAG_STR_BYTESIZE) { 422 c_len = c_len * byte_mul; 423 } 424 425 return c_len; 426} 427 428void ndr_print_string(struct ndr_print *ndr, const char *name, const char *s) 429{ 430 if (s) { 431 ndr->print(ndr, "%-25s: '%s'", name, s); 432 } else { 433 ndr->print(ndr, "%-25s: NULL", name); 434 } 435} 436 437uint32_t ndr_size_string(int ret, const char * const* string, int flags) 438{ 439 /* FIXME: Is this correct for all strings ? */ 440 if(!(*string)) return ret; 441 return ret+strlen(*string)+1; 442} 443 444/** 445 pull a general string array from the wire 446*/ 447NTSTATUS ndr_pull_string_array(struct ndr_pull *ndr, int ndr_flags, const char ***_a) 448{ 449 const char **a = *_a; 450 uint32_t count; 451 452 if (!(ndr_flags & NDR_SCALARS)) { 453 return NT_STATUS_OK; 454 } 455 456 for (count = 0;; count++) { 457 TALLOC_CTX *tmp_ctx; 458 const char *s = NULL; 459 a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 2); 460 NT_STATUS_HAVE_NO_MEMORY(a); 461 a[count] = NULL; 462 a[count+1] = NULL; 463 464 tmp_ctx = ndr->current_mem_ctx; 465 ndr->current_mem_ctx = a; 466 NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s)); 467 ndr->current_mem_ctx = tmp_ctx; 468 if (strcmp("", s)==0) { 469 a[count] = NULL; 470 break; 471 } else { 472 a[count] = s; 473 } 474 } 475 476 *_a =a; 477 return NT_STATUS_OK; 478} 479 480/** 481 push a general string array onto the wire 482*/ 483NTSTATUS ndr_push_string_array(struct ndr_push *ndr, int ndr_flags, const char **a) 484{ 485 uint32_t count; 486 487 if (!(ndr_flags & NDR_SCALARS)) { 488 return NT_STATUS_OK; 489 } 490 491 for (count = 0; a && a[count]; count++) { 492 NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count])); 493 } 494 495 NDR_CHECK(ndr_push_string(ndr, ndr_flags, "")); 496 497 return NT_STATUS_OK; 498} 499 500void ndr_print_string_array(struct ndr_print *ndr, const char *name, const char **a) 501{ 502 uint32_t count; 503 uint32_t i; 504 505 for (count = 0; a && a[count]; count++) {} 506 507 ndr->print(ndr, "%s: ARRAY(%d)", name, count); 508 ndr->depth++; 509 for (i=0;i<count;i++) { 510 char *idx=NULL; 511 asprintf(&idx, "[%d]", i); 512 if (idx) { 513 ndr_print_string(ndr, idx, a[i]); 514 free(idx); 515 } 516 } 517 ndr->depth--; 518} 519 520/** 521 * Return number of elements in a string including the last (zeroed) element 522 */ 523uint32_t ndr_string_length(const void *_var, uint32_t element_size) 524{ 525 uint32_t i; 526 uint8_t zero[4] = {0,0,0,0}; 527 const char *var = (const char *)_var; 528 529 for (i = 0; memcmp(var+i*element_size,zero,element_size) != 0; i++); 530 531 return i+1; 532} 533 534NTSTATUS ndr_check_string_terminator(struct ndr_pull *ndr, uint32_t count, uint32_t element_size) 535{ 536 uint32_t i; 537 struct ndr_pull_save save_offset; 538 539 ndr_pull_save(ndr, &save_offset); 540 ndr_pull_advance(ndr, (count - 1) * element_size); 541 NDR_PULL_NEED_BYTES(ndr, element_size); 542 543 for (i = 0; i < element_size; i++) { 544 if (ndr->data[ndr->offset+i] != 0) { 545 ndr_pull_restore(ndr, &save_offset); 546 547 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "String terminator not present or outside string boundaries"); 548 } 549 } 550 551 ndr_pull_restore(ndr, &save_offset); 552 553 return NT_STATUS_OK; 554} 555 556NTSTATUS ndr_pull_charset(struct ndr_pull *ndr, int ndr_flags, const char **var, uint32_t length, uint8_t byte_mul, charset_t chset) 557{ 558 int ret; 559 if (length == 0) { 560 *var = talloc_strdup(ndr->current_mem_ctx, ""); 561 return NT_STATUS_OK; 562 } 563 564 if (NDR_BE(ndr) && chset == CH_UTF16) { 565 chset = CH_UTF16BE; 566 } 567 568 NDR_PULL_NEED_BYTES(ndr, length*byte_mul); 569 570 ret = convert_string_talloc(ndr->current_mem_ctx, 571 chset, CH_UNIX, 572 ndr->data+ndr->offset, 573 length*byte_mul, 574 var, False); 575 if (ret == -1) { 576 return ndr_pull_error(ndr, NDR_ERR_CHARCNV, 577 "Bad character conversion"); 578 } 579 NDR_CHECK(ndr_pull_advance(ndr, length*byte_mul)); 580 581 return NT_STATUS_OK; 582} 583 584NTSTATUS ndr_push_charset(struct ndr_push *ndr, int ndr_flags, const char *var, 585 uint32_t length, uint8_t byte_mul, charset_t chset) 586{ 587 ssize_t ret, required; 588 589 if (NDR_BE(ndr) && chset == CH_UTF16) { 590 chset = CH_UTF16BE; 591 } 592 593 required = byte_mul * length; 594 595 NDR_PUSH_NEED_BYTES(ndr, required); 596 ret = convert_string(CH_UNIX, chset, 597 var, strlen(var), 598 ndr->data+ndr->offset, required, False); 599 if (ret == -1) { 600 return ndr_push_error(ndr, NDR_ERR_CHARCNV, 601 "Bad character conversion"); 602 } 603 604 /* Make sure the remaining part of the string is filled with zeroes */ 605 if (ret < required) { 606 memset(ndr->data+ndr->offset+ret, 0, required-ret); 607 } 608 609 ndr->offset += required; 610 611 return NT_STATUS_OK; 612} 613 614/* Return number of elements in a string in the specified charset */ 615uint32_t ndr_charset_length(const void *var, int chset) 616{ 617 /* FIXME: Treat special chars special here, taking chset into account */ 618 /* Also include 0 byte */ 619 return strlen((const char *)var)+1; 620} 621