1/* 2 Unix SMB/CIFS implementation. 3 4 manipulate nbt name structures 5 6 Copyright (C) Andrew Tridgell 2005 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 3 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, see <http://www.gnu.org/licenses/>. 20*/ 21 22/* 23 see rfc1002 for the detailed format of compressed names 24*/ 25 26#include "includes.h" 27#include "librpc/gen_ndr/ndr_nbt.h" 28#include "librpc/gen_ndr/ndr_misc.h" 29#include "system/locale.h" 30 31/* don't allow an unlimited number of name components */ 32#define MAX_COMPONENTS 10 33 34/** 35 print a nbt string 36*/ 37_PUBLIC_ void ndr_print_nbt_string(struct ndr_print *ndr, const char *name, const char *s) 38{ 39 ndr_print_string(ndr, name, s); 40} 41 42/* 43 pull one component of a nbt_string 44*/ 45static enum ndr_err_code ndr_pull_component(struct ndr_pull *ndr, 46 uint8_t **component, 47 uint32_t *offset, 48 uint32_t *max_offset) 49{ 50 uint8_t len; 51 uint_t loops = 0; 52 while (loops < 5) { 53 if (*offset >= ndr->data_size) { 54 return ndr_pull_error(ndr, NDR_ERR_STRING, 55 "BAD NBT NAME component"); 56 } 57 len = ndr->data[*offset]; 58 if (len == 0) { 59 *offset += 1; 60 *max_offset = MAX(*max_offset, *offset); 61 *component = NULL; 62 return NDR_ERR_SUCCESS; 63 } 64 if ((len & 0xC0) == 0xC0) { 65 /* its a label pointer */ 66 if (1 + *offset >= ndr->data_size) { 67 return ndr_pull_error(ndr, NDR_ERR_STRING, 68 "BAD NBT NAME component"); 69 } 70 *max_offset = MAX(*max_offset, *offset + 2); 71 *offset = ((len&0x3F)<<8) | ndr->data[1 + *offset]; 72 *max_offset = MAX(*max_offset, *offset); 73 loops++; 74 continue; 75 } 76 if ((len & 0xC0) != 0) { 77 /* its a reserved length field */ 78 return ndr_pull_error(ndr, NDR_ERR_STRING, 79 "BAD NBT NAME component"); 80 } 81 if (*offset + len + 2 > ndr->data_size) { 82 return ndr_pull_error(ndr, NDR_ERR_STRING, 83 "BAD NBT NAME component"); 84 } 85 *component = (uint8_t*)talloc_strndup( 86 ndr->current_mem_ctx, 87 (const char *)&ndr->data[1 + *offset], len); 88 NDR_ERR_HAVE_NO_MEMORY(*component); 89 *offset += len + 1; 90 *max_offset = MAX(*max_offset, *offset); 91 return NDR_ERR_SUCCESS; 92 } 93 94 /* too many pointers */ 95 return ndr_pull_error(ndr, NDR_ERR_STRING, "BAD NBT NAME component"); 96} 97 98/** 99 pull a nbt_string from the wire 100*/ 101_PUBLIC_ enum ndr_err_code ndr_pull_nbt_string(struct ndr_pull *ndr, int ndr_flags, const char **s) 102{ 103 uint32_t offset = ndr->offset; 104 uint32_t max_offset = offset; 105 unsigned num_components; 106 char *name; 107 108 if (!(ndr_flags & NDR_SCALARS)) { 109 return NDR_ERR_SUCCESS; 110 } 111 112 name = NULL; 113 114 /* break up name into a list of components */ 115 for (num_components=0;num_components<MAX_COMPONENTS;num_components++) { 116 uint8_t *component = NULL; 117 NDR_CHECK(ndr_pull_component(ndr, &component, &offset, &max_offset)); 118 if (component == NULL) break; 119 if (name) { 120 name = talloc_asprintf_append_buffer(name, ".%s", component); 121 NDR_ERR_HAVE_NO_MEMORY(name); 122 } else { 123 name = (char *)component; 124 } 125 } 126 if (num_components == MAX_COMPONENTS) { 127 return ndr_pull_error(ndr, NDR_ERR_STRING, 128 "BAD NBT NAME too many components"); 129 } 130 if (num_components == 0) { 131 name = talloc_strdup(ndr->current_mem_ctx, ""); 132 NDR_ERR_HAVE_NO_MEMORY(name); 133 } 134 135 (*s) = name; 136 ndr->offset = max_offset; 137 138 return NDR_ERR_SUCCESS; 139} 140 141/** 142 push a nbt string to the wire 143*/ 144_PUBLIC_ enum ndr_err_code ndr_push_nbt_string(struct ndr_push *ndr, int ndr_flags, const char *s) 145{ 146 if (!(ndr_flags & NDR_SCALARS)) { 147 return NDR_ERR_SUCCESS; 148 } 149 150 while (s && *s) { 151 enum ndr_err_code ndr_err; 152 char *compname; 153 size_t complen; 154 uint32_t offset; 155 156 /* see if we have pushed the remaing string allready, 157 * if so we use a label pointer to this string 158 */ 159 ndr_err = ndr_token_retrieve_cmp_fn(&ndr->nbt_string_list, s, &offset, (comparison_fn_t)strcmp, false); 160 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 161 uint8_t b[2]; 162 163 if (offset > 0x3FFF) { 164 return ndr_push_error(ndr, NDR_ERR_STRING, 165 "offset for nbt string label pointer %u[%08X] > 0x00003FFF", 166 offset, offset); 167 } 168 169 b[0] = 0xC0 | (offset>>8); 170 b[1] = (offset & 0xFF); 171 172 return ndr_push_bytes(ndr, b, 2); 173 } 174 175 complen = strcspn(s, "."); 176 177 /* we need to make sure the length fits into 6 bytes */ 178 if (complen >= 0x3F) { 179 return ndr_push_error(ndr, NDR_ERR_STRING, 180 "component length %u[%08X] > 0x00003F", 181 (unsigned)complen, (unsigned)complen); 182 } 183 184 compname = talloc_asprintf(ndr, "%c%*.*s", 185 (unsigned char)complen, 186 (unsigned char)complen, 187 (unsigned char)complen, s); 188 NDR_ERR_HAVE_NO_MEMORY(compname); 189 190 /* remember the current componemt + the rest of the string 191 * so it can be reused later 192 */ 193 NDR_CHECK(ndr_token_store(ndr, &ndr->nbt_string_list, s, ndr->offset)); 194 195 /* push just this component into the blob */ 196 NDR_CHECK(ndr_push_bytes(ndr, (const uint8_t *)compname, complen+1)); 197 talloc_free(compname); 198 199 s += complen; 200 if (*s == '.') s++; 201 } 202 203 /* if we reach the end of the string and have pushed the last component 204 * without using a label pointer, we need to terminate the string 205 */ 206 return ndr_push_bytes(ndr, (const uint8_t *)"", 1); 207} 208 209 210/* 211 decompress a 'compressed' name component 212 */ 213static bool decompress_name(char *name, enum nbt_name_type *type) 214{ 215 int i; 216 for (i=0;name[2*i];i++) { 217 uint8_t c1 = name[2*i]; 218 uint8_t c2 = name[1+(2*i)]; 219 if (c1 < 'A' || c1 > 'P' || 220 c2 < 'A' || c2 > 'P') { 221 return false; 222 } 223 name[i] = ((c1-'A')<<4) | (c2-'A'); 224 } 225 name[i] = 0; 226 if (i == 16) { 227 *type = (enum nbt_name_type)(name[15]); 228 name[15] = 0; 229 i--; 230 } else { 231 *type = NBT_NAME_CLIENT; 232 } 233 234 /* trim trailing spaces */ 235 for (;i>0 && name[i-1]==' ';i--) { 236 name[i-1] = 0; 237 } 238 239 return true; 240} 241 242 243/* 244 compress a name component 245 */ 246static uint8_t *compress_name(TALLOC_CTX *mem_ctx, 247 const uint8_t *name, enum nbt_name_type type) 248{ 249 uint8_t *cname; 250 int i; 251 uint8_t pad_char; 252 253 if (strlen((const char *)name) > 15) { 254 return NULL; 255 } 256 257 cname = talloc_array(mem_ctx, uint8_t, 33); 258 if (cname == NULL) return NULL; 259 260 for (i=0;name[i];i++) { 261 cname[2*i] = 'A' + (name[i]>>4); 262 cname[1+2*i] = 'A' + (name[i]&0xF); 263 } 264 if (strcmp((const char *)name, "*") == 0) { 265 pad_char = 0; 266 } else { 267 pad_char = ' '; 268 } 269 for (;i<15;i++) { 270 cname[2*i] = 'A' + (pad_char>>4); 271 cname[1+2*i] = 'A' + (pad_char&0xF); 272 } 273 274 pad_char = type; 275 cname[2*i] = 'A' + (pad_char>>4); 276 cname[1+2*i] = 'A' + (pad_char&0xF); 277 278 cname[32] = 0; 279 return cname; 280} 281 282 283/** 284 pull a nbt name from the wire 285*/ 286_PUBLIC_ enum ndr_err_code ndr_pull_nbt_name(struct ndr_pull *ndr, int ndr_flags, struct nbt_name *r) 287{ 288 uint8_t *scope; 289 char *cname; 290 const char *s; 291 bool ok; 292 293 if (!(ndr_flags & NDR_SCALARS)) { 294 return NDR_ERR_SUCCESS; 295 } 296 297 NDR_CHECK(ndr_pull_nbt_string(ndr, ndr_flags, &s)); 298 299 scope = (uint8_t *)strchr(s, '.'); 300 if (scope) { 301 *scope = 0; 302 r->scope = talloc_strdup(ndr->current_mem_ctx, (const char *)&scope[1]); 303 NDR_ERR_HAVE_NO_MEMORY(r->scope); 304 } else { 305 r->scope = NULL; 306 } 307 308 cname = discard_const_p(char, s); 309 310 /* the first component is limited to 16 bytes in the DOS charset, 311 which is 32 in the 'compressed' form */ 312 if (strlen(cname) > 32) { 313 return ndr_pull_error(ndr, NDR_ERR_STRING, 314 "NBT NAME cname > 32"); 315 } 316 317 /* decompress the first component */ 318 ok = decompress_name(cname, &r->type); 319 if (!ok) { 320 return ndr_pull_error(ndr, NDR_ERR_STRING, 321 "NBT NAME failed to decompress"); 322 } 323 324 r->name = talloc_strdup(ndr->current_mem_ctx, cname); 325 NDR_ERR_HAVE_NO_MEMORY(r->name); 326 327 talloc_free(cname); 328 329 return NDR_ERR_SUCCESS; 330} 331 332/** 333 push a nbt name to the wire 334*/ 335_PUBLIC_ enum ndr_err_code ndr_push_nbt_name(struct ndr_push *ndr, int ndr_flags, const struct nbt_name *r) 336{ 337 uint8_t *cname, *fullname; 338 enum ndr_err_code ndr_err; 339 340 if (!(ndr_flags & NDR_SCALARS)) { 341 return NDR_ERR_SUCCESS; 342 } 343 344 if (strlen(r->name) > 15) { 345 return ndr_push_error(ndr, NDR_ERR_STRING, 346 "nbt_name longer as 15 chars: %s", 347 r->name); 348 } 349 350 cname = compress_name(ndr, (const uint8_t *)r->name, r->type); 351 NDR_ERR_HAVE_NO_MEMORY(cname); 352 353 if (r->scope) { 354 fullname = (uint8_t *)talloc_asprintf(ndr, "%s.%s", cname, r->scope); 355 NDR_ERR_HAVE_NO_MEMORY(fullname); 356 talloc_free(cname); 357 } else { 358 fullname = cname; 359 } 360 361 ndr_err = ndr_push_nbt_string(ndr, ndr_flags, (const char *)fullname); 362 363 return ndr_err; 364} 365 366 367/** 368 copy a nbt name structure 369*/ 370_PUBLIC_ NTSTATUS nbt_name_dup(TALLOC_CTX *mem_ctx, struct nbt_name *name, struct nbt_name *newname) 371{ 372 *newname = *name; 373 newname->name = talloc_strdup(mem_ctx, newname->name); 374 NT_STATUS_HAVE_NO_MEMORY(newname->name); 375 newname->scope = talloc_strdup(mem_ctx, newname->scope); 376 if (name->scope) { 377 NT_STATUS_HAVE_NO_MEMORY(newname->scope); 378 } 379 return NT_STATUS_OK; 380} 381 382/** 383 push a nbt name into a blob 384*/ 385_PUBLIC_ NTSTATUS nbt_name_to_blob(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, DATA_BLOB *blob, struct nbt_name *name) 386{ 387 enum ndr_err_code ndr_err; 388 389 ndr_err = ndr_push_struct_blob(blob, mem_ctx, iconv_convenience, name, (ndr_push_flags_fn_t)ndr_push_nbt_name); 390 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 391 return ndr_map_error2ntstatus(ndr_err); 392 } 393 394 return NT_STATUS_OK; 395} 396 397/** 398 pull a nbt name from a blob 399*/ 400_PUBLIC_ NTSTATUS nbt_name_from_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, struct nbt_name *name) 401{ 402 enum ndr_err_code ndr_err; 403 404 ndr_err = ndr_pull_struct_blob(blob, mem_ctx, NULL, name, 405 (ndr_pull_flags_fn_t)ndr_pull_nbt_name); 406 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 407 return ndr_map_error2ntstatus(ndr_err); 408 } 409 410 return NT_STATUS_OK; 411} 412 413 414/** 415 choose a name to use when calling a server in a NBT session request. 416 we use heuristics to see if the name we have been given is a IP 417 address, or a too-long name. If it is then use *SMBSERVER, or a 418 truncated name 419*/ 420_PUBLIC_ void nbt_choose_called_name(TALLOC_CTX *mem_ctx, 421 struct nbt_name *n, const char *name, int type) 422{ 423 n->scope = NULL; 424 n->type = type; 425 426 if ((name == NULL) || is_ipaddress(name)) { 427 n->name = "*SMBSERVER"; 428 return; 429 } 430 if (strlen(name) > 15) { 431 const char *p = strchr(name, '.'); 432 char *s; 433 if (p - name > 15) { 434 n->name = "*SMBSERVER"; 435 return; 436 } 437 s = talloc_strndup(mem_ctx, name, PTR_DIFF(p, name)); 438 n->name = talloc_strdup_upper(mem_ctx, s); 439 return; 440 } 441 442 n->name = talloc_strdup_upper(mem_ctx, name); 443} 444 445 446/* 447 escape a string into a form containing only a small set of characters, 448 the rest is hex encoded. This is similar to URL encoding 449*/ 450static const char *nbt_hex_encode(TALLOC_CTX *mem_ctx, const char *s) 451{ 452 int i, len; 453 char *ret; 454 const char *valid_chars = "_-.$@ "; 455#define NBT_CHAR_ALLOW(c) (isalnum((unsigned char)c) || strchr(valid_chars, c)) 456 457 for (len=i=0;s[i];i++,len++) { 458 if (!NBT_CHAR_ALLOW(s[i])) { 459 len += 2; 460 } 461 } 462 463 ret = talloc_array(mem_ctx, char, len+1); 464 if (ret == NULL) return NULL; 465 466 for (len=i=0;s[i];i++) { 467 if (NBT_CHAR_ALLOW(s[i])) { 468 ret[len++] = s[i]; 469 } else { 470 snprintf(&ret[len], 4, "%%%02x", (unsigned char)s[i]); 471 len += 3; 472 } 473 } 474 ret[len] = 0; 475 476 return ret; 477} 478 479 480/** 481 form a string for a NBT name 482*/ 483_PUBLIC_ char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name) 484{ 485 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); 486 char *ret; 487 if (name->scope) { 488 ret = talloc_asprintf(mem_ctx, "%s<%02x>-%s", 489 nbt_hex_encode(tmp_ctx, name->name), 490 name->type, 491 nbt_hex_encode(tmp_ctx, name->scope)); 492 } else { 493 ret = talloc_asprintf(mem_ctx, "%s<%02x>", 494 nbt_hex_encode(tmp_ctx, name->name), 495 name->type); 496 } 497 talloc_free(tmp_ctx); 498 return ret; 499} 500 501/** 502 pull a nbt name, WINS Replication uses another on wire format for nbt name 503*/ 504_PUBLIC_ enum ndr_err_code ndr_pull_wrepl_nbt_name(struct ndr_pull *ndr, int ndr_flags, const struct nbt_name **_r) 505{ 506 struct nbt_name *r; 507 uint8_t *namebuf; 508 uint32_t namebuf_len; 509 510 if (!(ndr_flags & NDR_SCALARS)) { 511 return NDR_ERR_SUCCESS; 512 } 513 514 NDR_CHECK(ndr_pull_align(ndr, 4)); 515 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &namebuf_len)); 516 if (namebuf_len < 1 || namebuf_len > 255) { 517 return ndr_pull_error(ndr, NDR_ERR_ALLOC, "value out of range"); 518 } 519 NDR_PULL_ALLOC_N(ndr, namebuf, namebuf_len); 520 NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, namebuf, namebuf_len)); 521 522 NDR_PULL_ALLOC(ndr, r); 523 524 /* oh wow, what a nasty bug in windows ... */ 525 if (namebuf[0] == 0x1b && namebuf_len >= 16) { 526 namebuf[0] = namebuf[15]; 527 namebuf[15] = 0x1b; 528 } 529 530 if (namebuf_len < 17) { 531 r->type = 0x00; 532 533 r->name = talloc_strndup(r, (char *)namebuf, namebuf_len); 534 if (!r->name) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory"); 535 536 r->scope= NULL; 537 538 talloc_free(namebuf); 539 *_r = r; 540 return NDR_ERR_SUCCESS; 541 } 542 543 r->type = namebuf[15]; 544 545 namebuf[15] = '\0'; 546 trim_string((char *)namebuf, NULL, " "); 547 r->name = talloc_strdup(r, (char *)namebuf); 548 if (!r->name) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory"); 549 550 if (namebuf_len > 18) { 551 r->scope = talloc_strndup(r, (char *)(namebuf+17), namebuf_len-17); 552 if (!r->scope) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory"); 553 } else { 554 r->scope = NULL; 555 } 556 557 talloc_free(namebuf); 558 *_r = r; 559 return NDR_ERR_SUCCESS; 560} 561 562/** 563 push a nbt name, WINS Replication uses another on wire format for nbt name 564*/ 565_PUBLIC_ enum ndr_err_code ndr_push_wrepl_nbt_name(struct ndr_push *ndr, int ndr_flags, const struct nbt_name *r) 566{ 567 uint8_t *namebuf; 568 uint32_t namebuf_len; 569 uint32_t _name_len; 570 uint32_t scope_len = 0; 571 572 if (r == NULL) { 573 return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, 574 "wrepl_nbt_name NULL pointer"); 575 } 576 577 if (!(ndr_flags & NDR_SCALARS)) { 578 return NDR_ERR_SUCCESS; 579 } 580 581 _name_len = strlen(r->name); 582 if (_name_len > 15) { 583 return ndr_push_error(ndr, NDR_ERR_STRING, 584 "wrepl_nbt_name longer as 15 chars: %s", 585 r->name); 586 } 587 588 if (r->scope) { 589 scope_len = strlen(r->scope); 590 } 591 if (scope_len > 238) { 592 return ndr_push_error(ndr, NDR_ERR_STRING, 593 "wrepl_nbt_name scope longer as 238 chars: %s", 594 r->scope); 595 } 596 597 namebuf = (uint8_t *)talloc_asprintf(ndr, "%-15s%c%s", 598 r->name, 'X', 599 (r->scope?r->scope:"")); 600 if (!namebuf) return ndr_push_error(ndr, NDR_ERR_ALLOC, "out of memory"); 601 602 namebuf_len = strlen((char *)namebuf) + 1; 603 604 /* 605 * we need to set the type here, and use a place-holder in the talloc_asprintf() 606 * as the type can be 0x00, and then the namebuf_len = strlen(namebuf); would give wrong results 607 */ 608 namebuf[15] = r->type; 609 610 /* oh wow, what a nasty bug in windows ... */ 611 if (r->type == 0x1b) { 612 namebuf[15] = namebuf[0]; 613 namebuf[0] = 0x1b; 614 } 615 616 NDR_CHECK(ndr_push_align(ndr, 4)); 617 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, namebuf_len)); 618 NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, namebuf, namebuf_len)); 619 620 talloc_free(namebuf); 621 return NDR_ERR_SUCCESS; 622} 623 624_PUBLIC_ void ndr_print_wrepl_nbt_name(struct ndr_print *ndr, const char *name, const struct nbt_name *r) 625{ 626 char *s = nbt_name_string(ndr, r); 627 ndr_print_string(ndr, name, s); 628 talloc_free(s); 629} 630 631_PUBLIC_ enum ndr_err_code ndr_push_nbt_res_rec(struct ndr_push *ndr, int ndr_flags, const struct nbt_res_rec *r) 632{ 633 { 634 uint32_t _flags_save_STRUCT = ndr->flags; 635 ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX); 636 if (ndr_flags & NDR_SCALARS) { 637 NDR_CHECK(ndr_push_align(ndr, 4)); 638 NDR_CHECK(ndr_push_nbt_name(ndr, NDR_SCALARS, &r->name)); 639 NDR_CHECK(ndr_push_nbt_qtype(ndr, NDR_SCALARS, r->rr_type)); 640 NDR_CHECK(ndr_push_nbt_qclass(ndr, NDR_SCALARS, r->rr_class)); 641 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->ttl)); 642 NDR_CHECK(ndr_push_set_switch_value(ndr, &r->rdata, ((((r->rr_type) == NBT_QTYPE_NETBIOS) && ((r->rdata).data.length == 2))?0:r->rr_type))); 643 NDR_CHECK(ndr_push_nbt_rdata(ndr, NDR_SCALARS, &r->rdata)); 644 } 645 if (ndr_flags & NDR_BUFFERS) { 646 } 647 ndr->flags = _flags_save_STRUCT; 648 } 649 return NDR_ERR_SUCCESS; 650} 651