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
smb_netbios_cache_init(void)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
smb_netbios_cache_fini(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
smb_netbios_cache_clean(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
smb_netbios_cache_getfirst(nbcache_iter_t * iter)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
smb_netbios_cache_getnext(nbcache_iter_t * iter)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 *
smb_netbios_cache_lookup(struct name_entry * name)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
smb_netbios_cache_unlock_entry(struct name_entry * name)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 *
smb_netbios_cache_lookup_addr(struct name_entry * name)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
smb_netbios_cache_insert(struct name_entry * name)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
smb_netbios_cache_delete(struct name_entry * name)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
smb_netbios_cache_insert_list(struct name_entry * name)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
smb_netbios_cache_update_entry(struct name_entry * entry,struct name_entry * name)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 *
smb_netbios_cache_status(unsigned char * buf,int bufsize,unsigned char * scope)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
smb_netbios_cache_reset_ttl()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
smb_netbios_cache_insrefq(name_queue_t * refq,HT_ITEM * item)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
smb_netbios_cache_refresh(name_queue_t * refq)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
smb_netbios_cache_delete_locals(name_queue_t * delq)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
smb_netbios_name_freeaddrs(struct name_entry * entry)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
smb_netbios_cache_count()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
smb_netbios_cache_dump(FILE * fp)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
smb_netbios_name_dump(FILE * fp,struct name_entry * entry)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
smb_netbios_name_logf(struct name_entry * entry)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 *
smb_netbios_name_dup(struct name_entry * entry,int alladdr)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
smb_strname(struct name_entry * entry,char * buf,int bufsize)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
hash_callback(HT_ITEM * item)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
smb_netbios_match(const char * key1,const char * key2,size_t n)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
smb_netbios_cache_key(char * key,unsigned char * name,unsigned char * scope)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