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