1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <synch.h> 27 #include <stdio.h> 28 #include <syslog.h> 29 #include <stdlib.h> 30 #include <arpa/inet.h> 31 #include <netdb.h> 32 33 #include <smbsrv/libsmbns.h> 34 #include <smbns_netbios.h> 35 36 #define NETBIOS_HTAB_SZ 128 37 #define NETBIOS_HKEY_SZ (NETBIOS_NAME_SZ + NETBIOS_DOMAIN_NAME_MAX) 38 39 #define NETBIOS_SAME_IP(addr1, addr2) \ 40 ((addr1)->sin.sin_addr.s_addr == (addr2)->sin.sin_addr.s_addr) 41 42 typedef char nb_key_t[NETBIOS_HKEY_SZ]; 43 static HT_HANDLE *smb_netbios_cache = 0; 44 static rwlock_t nb_cache_lock; 45 46 static void smb_strname(struct name_entry *name, char *buf, int bufsize); 47 static void hash_callback(HT_ITEM *item); 48 static int smb_netbios_match(const char *key1, const char *key2, size_t n); 49 static void smb_netbios_cache_key(char *key, unsigned char *name, 50 unsigned char *scope); 51 52 int 53 smb_netbios_cache_init(void) 54 { 55 (void) rw_wrlock(&nb_cache_lock); 56 if (smb_netbios_cache == NULL) { 57 smb_netbios_cache = ht_create_table(NETBIOS_HTAB_SZ, 58 NETBIOS_HKEY_SZ, HTHF_FIXED_KEY); 59 if (smb_netbios_cache == NULL) { 60 syslog(LOG_ERR, "nbns: cannot create name cache"); 61 (void) rw_unlock(&nb_cache_lock); 62 return (-1); 63 } 64 (void) ht_register_callback(smb_netbios_cache, hash_callback); 65 ht_set_cmpfn(smb_netbios_cache, smb_netbios_match); 66 } 67 (void) rw_unlock(&nb_cache_lock); 68 69 return (0); 70 } 71 72 void 73 smb_netbios_cache_fini(void) 74 { 75 (void) rw_wrlock(&nb_cache_lock); 76 ht_destroy_table(smb_netbios_cache); 77 smb_netbios_cache = NULL; 78 (void) rw_unlock(&nb_cache_lock); 79 } 80 81 void 82 smb_netbios_cache_clean(void) 83 { 84 (void) rw_wrlock(&nb_cache_lock); 85 (void) ht_clean_table(smb_netbios_cache); 86 (void) rw_unlock(&nb_cache_lock); 87 } 88 89 int 90 smb_netbios_cache_getfirst(nbcache_iter_t *iter) 91 { 92 HT_ITEM *item; 93 struct name_entry *entry; 94 95 (void) rw_rdlock(&nb_cache_lock); 96 item = ht_findfirst(smb_netbios_cache, &iter->nbc_hti); 97 if (item == NULL || item->hi_data == NULL) { 98 (void) rw_unlock(&nb_cache_lock); 99 return (-1); 100 } 101 102 entry = (struct name_entry *)item->hi_data; 103 (void) mutex_lock(&entry->mtx); 104 iter->nbc_entry = smb_netbios_name_dup(entry, 1); 105 (void) mutex_unlock(&entry->mtx); 106 107 (void) rw_unlock(&nb_cache_lock); 108 109 return ((iter->nbc_entry) ? 0 : -1); 110 } 111 112 int 113 smb_netbios_cache_getnext(nbcache_iter_t *iter) 114 { 115 HT_ITEM *item; 116 struct name_entry *entry; 117 118 (void) rw_rdlock(&nb_cache_lock); 119 item = ht_findnext(&iter->nbc_hti); 120 if (item == NULL || item->hi_data == NULL) { 121 (void) rw_unlock(&nb_cache_lock); 122 return (-1); 123 } 124 125 entry = (struct name_entry *)item->hi_data; 126 (void) mutex_lock(&entry->mtx); 127 iter->nbc_entry = smb_netbios_name_dup(entry, 1); 128 (void) mutex_unlock(&entry->mtx); 129 130 (void) rw_unlock(&nb_cache_lock); 131 132 return ((iter->nbc_entry) ? 0 : -1); 133 } 134 135 /* 136 * smb_netbios_cache_lookup 137 * 138 * Searches the name cache for the given entry, if found 139 * the entry will be locked before returning to caller 140 * so caller MUST unlock the entry after it's done with it. 141 */ 142 struct name_entry * 143 smb_netbios_cache_lookup(struct name_entry *name) 144 { 145 HT_ITEM *item; 146 nb_key_t key; 147 struct name_entry *entry = NULL; 148 unsigned char hostname[MAXHOSTNAMELEN]; 149 150 if (NETBIOS_NAME_IS_STAR(name->name)) { 151 /* Return our address */ 152 if (smb_getnetbiosname((char *)hostname, sizeof (hostname)) 153 != 0) 154 return (NULL); 155 156 smb_encode_netbios_name(hostname, 0x00, NULL, name); 157 } 158 159 (void) rw_rdlock(&nb_cache_lock); 160 161 smb_netbios_cache_key(key, name->name, name->scope); 162 item = ht_find_item(smb_netbios_cache, key); 163 if (item) { 164 entry = (struct name_entry *)item->hi_data; 165 (void) mutex_lock(&entry->mtx); 166 if ((entry->attributes & NAME_ATTR_CONFLICT) != 0) { 167 (void) mutex_unlock(&entry->mtx); 168 entry = NULL; 169 } 170 } 171 172 (void) rw_unlock(&nb_cache_lock); 173 return (entry); 174 } 175 176 void 177 smb_netbios_cache_unlock_entry(struct name_entry *name) 178 { 179 if (name) 180 (void) mutex_unlock(&name->mtx); 181 } 182 183 /* 184 * smb_netbios_cache_lookup_addr 185 * 186 * lookup the given 'name' in the cache and then checks 187 * if the address also matches with the found entry. 188 * 'name' is supposed to contain only one address. 189 * 190 * The found entry will be locked before returning to caller 191 * so caller MUST unlock the entry after it's done with it. 192 */ 193 struct name_entry * 194 smb_netbios_cache_lookup_addr(struct name_entry *name) 195 { 196 struct name_entry *entry = 0; 197 addr_entry_t *addr; 198 addr_entry_t *name_addr; 199 HT_ITEM *item; 200 nb_key_t key; 201 202 (void) rw_rdlock(&nb_cache_lock); 203 smb_netbios_cache_key(key, name->name, name->scope); 204 item = ht_find_item(smb_netbios_cache, key); 205 206 if (item && item->hi_data) { 207 name_addr = &name->addr_list; 208 entry = (struct name_entry *)item->hi_data; 209 (void) mutex_lock(&entry->mtx); 210 addr = &entry->addr_list; 211 do { 212 if (NETBIOS_SAME_IP(addr, name_addr)) { 213 /* note that entry lock isn't released here */ 214 (void) rw_unlock(&nb_cache_lock); 215 return (entry); 216 } 217 addr = addr->forw; 218 } while (addr != &entry->addr_list); 219 (void) mutex_unlock(&entry->mtx); 220 } 221 222 (void) rw_unlock(&nb_cache_lock); 223 return (0); 224 } 225 226 int 227 smb_netbios_cache_insert(struct name_entry *name) 228 { 229 struct name_entry *entry; 230 addr_entry_t *addr; 231 addr_entry_t *name_addr; 232 HT_ITEM *item; 233 nb_key_t key; 234 int rc; 235 236 /* No point in adding a name with IP address 255.255.255.255 */ 237 if (name->addr_list.sin.sin_addr.s_addr == 0xffffffff) 238 return (0); 239 240 (void) rw_wrlock(&nb_cache_lock); 241 smb_netbios_cache_key(key, name->name, name->scope); 242 item = ht_find_item(smb_netbios_cache, key); 243 244 if (item && item->hi_data) { 245 /* Name already exists */ 246 entry = (struct name_entry *)item->hi_data; 247 (void) mutex_lock(&entry->mtx); 248 249 name_addr = &name->addr_list; 250 addr = &entry->addr_list; 251 if (NETBIOS_SAME_IP(addr, name_addr) && 252 (addr->sin.sin_port == name_addr->sin.sin_port)) { 253 entry->attributes |= 254 name_addr->attributes & NAME_ATTR_LOCAL; 255 (void) mutex_unlock(&entry->mtx); 256 (void) rw_unlock(&nb_cache_lock); 257 return (0); 258 } 259 260 /* Was not primary: looks for others */ 261 for (addr = entry->addr_list.forw; 262 addr != &entry->addr_list; addr = addr->forw) { 263 if (NETBIOS_SAME_IP(addr, name_addr) && 264 (addr->sin.sin_port == name_addr->sin.sin_port)) { 265 (void) mutex_unlock(&entry->mtx); 266 (void) rw_unlock(&nb_cache_lock); 267 return (0); 268 } 269 } 270 271 if ((addr = malloc(sizeof (addr_entry_t))) != NULL) { 272 *addr = name->addr_list; 273 entry->attributes |= addr->attributes; 274 QUEUE_INSERT_TAIL(&entry->addr_list, addr); 275 rc = 0; 276 } else { 277 rc = -1; 278 } 279 280 (void) mutex_unlock(&entry->mtx); 281 (void) rw_unlock(&nb_cache_lock); 282 return (rc); 283 } 284 285 if ((entry = malloc(sizeof (struct name_entry))) == NULL) { 286 (void) rw_unlock(&nb_cache_lock); 287 return (-1); 288 } 289 290 *entry = *name; 291 entry->addr_list.forw = entry->addr_list.back = &entry->addr_list; 292 entry->attributes |= entry->addr_list.attributes; 293 (void) mutex_init(&entry->mtx, 0, 0); 294 if (ht_replace_item(smb_netbios_cache, key, entry) == 0) { 295 free(entry); 296 (void) rw_unlock(&nb_cache_lock); 297 return (-1); 298 } 299 300 (void) rw_unlock(&nb_cache_lock); 301 return (0); 302 } 303 304 305 void 306 smb_netbios_cache_delete(struct name_entry *name) 307 { 308 nb_key_t key; 309 HT_ITEM *item; 310 struct name_entry *entry; 311 312 (void) rw_wrlock(&nb_cache_lock); 313 smb_netbios_cache_key(key, name->name, name->scope); 314 item = ht_find_item(smb_netbios_cache, key); 315 if (item && item->hi_data) { 316 entry = (struct name_entry *)item->hi_data; 317 (void) mutex_lock(&entry->mtx); 318 ht_mark_delete(smb_netbios_cache, item); 319 (void) mutex_unlock(&entry->mtx); 320 } 321 (void) rw_unlock(&nb_cache_lock); 322 } 323 324 /* 325 * smb_netbios_cache_insert_list 326 * 327 * Insert a name with multiple addresses 328 */ 329 int 330 smb_netbios_cache_insert_list(struct name_entry *name) 331 { 332 struct name_entry entry; 333 addr_entry_t *addr; 334 335 addr = &name->addr_list; 336 do { 337 smb_init_name_struct(NETBIOS_EMPTY_NAME, 0, name->scope, 338 addr->sin.sin_addr.s_addr, 339 addr->sin.sin_port, 340 name->attributes, 341 addr->attributes, 342 &entry); 343 (void) memcpy(entry.name, name->name, NETBIOS_NAME_SZ); 344 entry.addr_list.refresh_ttl = entry.addr_list.ttl = 345 addr->refresh_ttl; 346 (void) smb_netbios_cache_insert(&entry); 347 addr = addr->forw; 348 } while (addr != &name->addr_list); 349 350 return (0); 351 } 352 353 void 354 smb_netbios_cache_update_entry(struct name_entry *entry, 355 struct name_entry *name) 356 { 357 addr_entry_t *addr; 358 addr_entry_t *name_addr; 359 360 addr = &entry->addr_list; 361 name_addr = &name->addr_list; 362 363 if (IS_UNIQUE(entry->attributes)) { 364 do { 365 addr->ttl = name_addr->ttl; 366 addr = addr->forw; 367 } while (addr != &entry->addr_list); 368 369 } else { 370 do { 371 if (NETBIOS_SAME_IP(addr, name_addr) && 372 (addr->sin.sin_port == name_addr->sin.sin_port)) { 373 addr->ttl = name_addr->ttl; 374 return; 375 } 376 addr = addr->forw; 377 } while (addr != &entry->addr_list); 378 } 379 } 380 381 /* 382 * smb_netbios_cache_status 383 * 384 * Scan the name cache and gather status for 385 * Node Status response for names in the given scope 386 */ 387 unsigned char * 388 smb_netbios_cache_status(unsigned char *buf, int bufsize, unsigned char *scope) 389 { 390 HT_ITERATOR hti; 391 HT_ITEM *item; 392 struct name_entry *name; 393 unsigned char *numnames; 394 unsigned char *scan; 395 unsigned char *scan_end; 396 397 scan = buf; 398 scan_end = scan + bufsize; 399 400 numnames = scan++; 401 *numnames = 0; 402 403 (void) rw_rdlock(&nb_cache_lock); 404 item = ht_findfirst(smb_netbios_cache, &hti); 405 do { 406 if (item == 0) 407 break; 408 409 if (item->hi_data == 0) 410 continue; 411 412 if ((scan + NETBIOS_NAME_SZ + 2) >= scan_end) 413 /* no room for adding next entry */ 414 break; 415 416 name = (struct name_entry *)item->hi_data; 417 (void) mutex_lock(&name->mtx); 418 419 if (IS_LOCAL(name->attributes) && 420 (strcasecmp((char *)scope, (char *)name->scope) == 0)) { 421 bcopy(name->name, scan, NETBIOS_NAME_SZ); 422 scan += NETBIOS_NAME_SZ; 423 *scan++ = (PUBLIC_BITS(name->attributes) >> 8) & 0xff; 424 *scan++ = PUBLIC_BITS(name->attributes) & 0xff; 425 (*numnames)++; 426 } 427 428 (void) mutex_unlock(&name->mtx); 429 } while ((item = ht_findnext(&hti)) != 0); 430 (void) rw_unlock(&nb_cache_lock); 431 432 return (scan); 433 } 434 435 void 436 smb_netbios_cache_reset_ttl() 437 { 438 addr_entry_t *addr; 439 struct name_entry *name; 440 HT_ITERATOR hti; 441 HT_ITEM *item; 442 443 (void) rw_rdlock(&nb_cache_lock); 444 item = ht_findfirst(smb_netbios_cache, &hti); 445 do { 446 if (item == 0) 447 break; 448 449 if (item->hi_data == 0) 450 continue; 451 452 name = (struct name_entry *)item->hi_data; 453 (void) mutex_lock(&name->mtx); 454 455 addr = &name->addr_list; 456 do { 457 if (addr->ttl < 1) { 458 if (addr->refresh_ttl) 459 addr->ttl = addr->refresh_ttl; 460 else 461 addr->refresh_ttl = addr->ttl = 462 TO_SECONDS(DEFAULT_TTL); 463 } 464 addr = addr->forw; 465 } while (addr != &name->addr_list); 466 467 (void) mutex_unlock(&name->mtx); 468 } while ((item = ht_findnext(&hti)) != 0); 469 (void) rw_unlock(&nb_cache_lock); 470 } 471 472 /* 473 * Returns TRUE when given name is added to the refresh queue 474 * FALSE if not. 475 */ 476 static boolean_t 477 smb_netbios_cache_insrefq(name_queue_t *refq, HT_ITEM *item) 478 { 479 struct name_entry *name; 480 struct name_entry *refent; 481 482 name = (struct name_entry *)item->hi_data; 483 484 if (IS_LOCAL(name->attributes)) { 485 if (IS_UNIQUE(name->attributes)) { 486 refent = smb_netbios_name_dup(name, 1); 487 if (refent) { 488 QUEUE_INSERT_TAIL(&refq->head, refent) 489 } 490 491 /* next name */ 492 return (B_TRUE); 493 } 494 } else { 495 ht_mark_delete(smb_netbios_cache, item); 496 refent = smb_netbios_name_dup(name, 0); 497 if (refent) { 498 QUEUE_INSERT_TAIL(&refq->head, refent) 499 } 500 501 /* next name */ 502 return (B_TRUE); 503 } 504 505 return (B_FALSE); 506 } 507 508 /* 509 * smb_netbios_cache_refresh 510 * 511 * Scans the name cache and add all local unique names 512 * and non-local names the passed refresh queue. Non- 513 * local names will also be marked as deleted. 514 * 515 * NOTE that the caller MUST protect the queue using 516 * its mutex 517 */ 518 void 519 smb_netbios_cache_refresh(name_queue_t *refq) 520 { 521 struct name_entry *name; 522 addr_entry_t *addr; 523 HT_ITERATOR hti; 524 HT_ITEM *item; 525 526 bzero(&refq->head, sizeof (refq->head)); 527 refq->head.forw = refq->head.back = &refq->head; 528 529 (void) rw_rdlock(&nb_cache_lock); 530 item = ht_findfirst(smb_netbios_cache, &hti); 531 do { /* name loop */ 532 if (item == 0) 533 break; 534 535 if (item->hi_data == 0) 536 continue; 537 538 name = (struct name_entry *)item->hi_data; 539 (void) mutex_lock(&name->mtx); 540 541 addr = &name->addr_list; 542 do { /* address loop */ 543 if (addr->ttl > 0) { 544 addr->ttl--; 545 if (addr->ttl == 0) { 546 if (smb_netbios_cache_insrefq(refq, 547 item)) 548 break; 549 } 550 } 551 addr = addr->forw; 552 } while (addr != &name->addr_list); 553 554 (void) mutex_unlock(&name->mtx); 555 } while ((item = ht_findnext(&hti)) != 0); 556 (void) rw_unlock(&nb_cache_lock); 557 } 558 559 /* 560 * smb_netbios_cache_delete_locals 561 * 562 * Scans the name cache and add all local names to 563 * the passed delete queue. 564 * 565 * NOTE that the caller MUST protect the queue using 566 * its mutex 567 */ 568 void 569 smb_netbios_cache_delete_locals(name_queue_t *delq) 570 { 571 struct name_entry *entry; 572 struct name_entry *delent; 573 HT_ITERATOR hti; 574 HT_ITEM *item; 575 576 bzero(&delq->head, sizeof (delq->head)); 577 delq->head.forw = delq->head.back = &delq->head; 578 579 (void) rw_wrlock(&nb_cache_lock); 580 item = ht_findfirst(smb_netbios_cache, &hti); 581 do { 582 if (item == 0) 583 break; 584 585 if (item->hi_data == 0) 586 continue; 587 588 entry = (struct name_entry *)item->hi_data; 589 (void) mutex_lock(&entry->mtx); 590 591 if (IS_LOCAL(entry->attributes)) { 592 ht_mark_delete(smb_netbios_cache, item); 593 delent = smb_netbios_name_dup(entry, 1); 594 if (delent) { 595 QUEUE_INSERT_TAIL(&delq->head, delent) 596 } 597 } 598 599 (void) mutex_unlock(&entry->mtx); 600 } while ((item = ht_findnext(&hti)) != 0); 601 (void) rw_unlock(&nb_cache_lock); 602 } 603 604 void 605 smb_netbios_name_freeaddrs(struct name_entry *entry) 606 { 607 addr_entry_t *addr; 608 609 if (entry == 0) 610 return; 611 612 while ((addr = entry->addr_list.forw) != &entry->addr_list) { 613 QUEUE_CLIP(addr); 614 free(addr); 615 } 616 } 617 618 /* 619 * smb_netbios_cache_count 620 * 621 * Returns the number of names in the cache 622 */ 623 int 624 smb_netbios_cache_count() 625 { 626 int cnt; 627 628 (void) rw_rdlock(&nb_cache_lock); 629 cnt = ht_get_total_items(smb_netbios_cache); 630 (void) rw_unlock(&nb_cache_lock); 631 632 return (cnt); 633 } 634 635 void 636 smb_netbios_cache_dump(FILE *fp) 637 { 638 struct name_entry *name; 639 HT_ITERATOR hti; 640 HT_ITEM *item; 641 642 (void) rw_rdlock(&nb_cache_lock); 643 644 if (ht_get_total_items(smb_netbios_cache) != 0) { 645 (void) fprintf(fp, "\n%-22s %-16s %-16s %s\n", 646 "Name", "Type", "Address", "TTL"); 647 (void) fprintf(fp, "%s%s\n", 648 "-------------------------------", 649 "------------------------------"); 650 } 651 652 item = ht_findfirst(smb_netbios_cache, &hti); 653 while (item) { 654 if (item->hi_data) { 655 name = (struct name_entry *)item->hi_data; 656 (void) mutex_lock(&name->mtx); 657 smb_netbios_name_dump(fp, name); 658 (void) mutex_unlock(&name->mtx); 659 } 660 item = ht_findnext(&hti); 661 } 662 (void) rw_unlock(&nb_cache_lock); 663 } 664 665 void 666 smb_netbios_name_dump(FILE *fp, struct name_entry *entry) 667 { 668 char buf[MAXHOSTNAMELEN]; 669 addr_entry_t *addr; 670 char *type; 671 int count = 0; 672 673 smb_strname(entry, buf, sizeof (buf)); 674 type = (IS_UNIQUE(entry->attributes)) ? "UNIQUE" : "GROUP"; 675 676 (void) fprintf(fp, "%s %-6s (0x%04x) ", buf, type, entry->attributes); 677 678 addr = &entry->addr_list; 679 do { 680 if (count == 0) 681 (void) fprintf(fp, "%-16s %d\n", 682 inet_ntoa(addr->sin.sin_addr), addr->ttl); 683 else 684 (void) fprintf(fp, "%-28s (0x%04x) %-16s %d\n", 685 " ", addr->attributes, 686 inet_ntoa(addr->sin.sin_addr), addr->ttl); 687 ++count; 688 addr = addr->forw; 689 } while (addr != &entry->addr_list); 690 } 691 692 void 693 smb_netbios_name_logf(struct name_entry *entry) 694 { 695 char namebuf[MAXHOSTNAMELEN]; 696 addr_entry_t *addr; 697 698 smb_strname(entry, namebuf, sizeof (namebuf)); 699 syslog(LOG_DEBUG, "%s flags=0x%x\n", namebuf, entry->attributes); 700 addr = &entry->addr_list; 701 do { 702 syslog(LOG_DEBUG, " %s ttl=%d flags=0x%x port=%d", 703 inet_ntoa(addr->sin.sin_addr), 704 addr->ttl, addr->attributes, 705 addr->sin.sin_port); 706 addr = addr->forw; 707 } while (addr && (addr != &entry->addr_list)); 708 } 709 710 /* 711 * smb_netbios_name_dup 712 * 713 * Duplicate the given name entry. If 'alladdr' is 0 only 714 * copy the primary address otherwise duplicate all the 715 * addresses. NOTE that the duplicate structure is not 716 * like a regular cache entry i.e. it's a contiguous block 717 * of memory and each addr structure doesn't have it's own 718 * allocated memory. So, the returned structure can be freed 719 * by one free call. 720 */ 721 struct name_entry * 722 smb_netbios_name_dup(struct name_entry *entry, int alladdr) 723 { 724 addr_entry_t *addr; 725 addr_entry_t *dup_addr; 726 struct name_entry *dup; 727 int addr_cnt = 0; 728 int size = 0; 729 730 if (alladdr) { 731 addr = entry->addr_list.forw; 732 while (addr && (addr != &entry->addr_list)) { 733 addr_cnt++; 734 addr = addr->forw; 735 } 736 } 737 738 size = sizeof (struct name_entry) + 739 (addr_cnt * sizeof (addr_entry_t)); 740 dup = (struct name_entry *)malloc(size); 741 if (dup == 0) 742 return (0); 743 744 bzero(dup, size); 745 746 dup->forw = dup->back = dup; 747 dup->attributes = entry->attributes; 748 (void) memcpy(dup->name, entry->name, NETBIOS_NAME_SZ); 749 (void) strlcpy((char *)dup->scope, (char *)entry->scope, 750 NETBIOS_DOMAIN_NAME_MAX); 751 dup->addr_list = entry->addr_list; 752 dup->addr_list.forw = dup->addr_list.back = &dup->addr_list; 753 754 if (alladdr == 0) 755 return (dup); 756 757 /* LINTED - E_BAD_PTR_CAST_ALIGN */ 758 dup_addr = (addr_entry_t *)((unsigned char *)dup + 759 sizeof (struct name_entry)); 760 761 addr = entry->addr_list.forw; 762 while (addr && (addr != &entry->addr_list)) { 763 *dup_addr = *addr; 764 QUEUE_INSERT_TAIL(&dup->addr_list, dup_addr); 765 addr = addr->forw; 766 dup_addr++; 767 } 768 769 return (dup); 770 } 771 772 static void 773 smb_strname(struct name_entry *entry, char *buf, int bufsize) 774 { 775 char tmp[MAXHOSTNAMELEN]; 776 char *p; 777 778 (void) snprintf(tmp, MAXHOSTNAMELEN, "%15.15s", entry->name); 779 if ((p = strchr(tmp, ' ')) != NULL) 780 *p = '\0'; 781 782 if (entry->scope[0] != '\0') { 783 (void) strlcat(tmp, ".", MAXHOSTNAMELEN); 784 (void) strlcat(tmp, (char *)entry->scope, MAXHOSTNAMELEN); 785 } 786 787 (void) snprintf(buf, bufsize, "%-16s <%02X>", tmp, entry->name[15]); 788 } 789 790 static void 791 hash_callback(HT_ITEM *item) 792 { 793 struct name_entry *entry; 794 795 if (item && item->hi_data) { 796 entry = (struct name_entry *)item->hi_data; 797 smb_netbios_name_freeaddrs(entry); 798 free(entry); 799 } 800 } 801 802 803 /*ARGSUSED*/ 804 static int 805 smb_netbios_match(const char *key1, const char *key2, size_t n) 806 { 807 int res; 808 809 res = bcmp(key1, key2, NETBIOS_NAME_SZ); 810 if (res == 0) { 811 /* Names are the same, compare scopes */ 812 res = strcmp(key1 + NETBIOS_NAME_SZ, key2 + NETBIOS_NAME_SZ); 813 } 814 815 return (res); 816 } 817 818 static void 819 smb_netbios_cache_key(char *key, unsigned char *name, unsigned char *scope) 820 { 821 bzero(key, NETBIOS_HKEY_SZ); 822 (void) memcpy(key, name, NETBIOS_NAME_SZ); 823 (void) memcpy(key + NETBIOS_NAME_SZ, scope, 824 strlen((const char *)scope)); 825 } 826