Libinfo-517.200.9.tar.gz
[apple/libinfo.git] / lookup.subproj / si_module.c
1 /*
2 * Copyright (c) 2008-2018 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include "libinfo_common.h"
25
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <net/ethernet.h>
29 #include <libkern/OSAtomic.h>
30 #include <dlfcn.h>
31 #include <string.h>
32 #include <stdio.h>
33 #include <errno.h>
34 #include <pthread.h>
35 #include <mach/mach.h>
36 #include <dispatch/dispatch.h>
37 #include <dispatch/private.h>
38 #include "si_module.h"
39
40 #define PLUGIN_DIR_PATH "/usr/lib/info"
41 #define PLUGIN_BUNDLE_SUFFIX "so"
42
43 #define WORKUNIT_CANCELLED 0x00000001
44 #define WORKUNIT_RETURNS_LIST 0x00000002
45
46 #ifdef __BIG_ENDIAN__
47 #define WORKUNIT_CANCELLED_BIT_ADDRESS 31
48 #else
49 #define WORKUNIT_CANCELLED_BIT_ADDRESS 7
50 #endif
51
52 typedef struct si_async_workunit_s
53 {
54 si_mod_t *si;
55 uint32_t call;
56 char *str1;
57 char *str2;
58 char *str3;
59 uint32_t num1;
60 uint32_t num2;
61 uint32_t num3;
62 uint32_t num4;
63 uint32_t err;
64 /* async support below */
65 uint32_t flags;
66 int32_t refcount;
67 void *callback;
68 void *context;
69 mach_port_t port;
70 mach_port_t send;
71 si_item_t *resitem;
72 si_list_t *reslist;
73 struct si_async_workunit_s *next;
74 } si_async_workunit_t;
75
76 static si_mod_t **module_list = NULL;
77 static uint32_t module_count = 0;
78 static pthread_mutex_t module_mutex = PTHREAD_MUTEX_INITIALIZER;
79 static si_async_workunit_t *si_async_worklist = NULL;
80
81 si_mod_t *si_module_static_search(void);
82 si_mod_t *si_module_static_cache(void);
83 si_mod_t *si_module_static_file(void);
84 #ifdef MUSER_AVAILABLE
85 si_mod_t *si_module_static_muser(void);
86 #endif
87 #ifdef DS_AVAILABLE
88 si_mod_t *si_module_static_ds(void);
89 #endif
90 si_mod_t *si_module_static_mdns(void);
91
92 static void *
93 si_mod_dlsym(void *so, const char *name, const char *sym)
94 {
95 char *str;
96 void *out;
97
98 if ((so == NULL) || (name == NULL) || (sym == NULL)) return NULL;
99
100 str = NULL;
101 asprintf(&str, "%s_%s", name, sym);
102 if (str == NULL) return NULL;
103
104 out = dlsym(so, str);
105 free(str);
106 return out;
107 }
108
109 si_mod_t *
110 si_module_with_path(const char *path, const char *name)
111 {
112 void *so;
113 int (*si_sym_init)(si_mod_t *);
114 void (*si_sym_close)(si_mod_t *);
115 int status;
116 si_mod_t *out;
117 char *outname;
118
119 if ((path == NULL) || (name == NULL))
120 {
121 errno = EINVAL;
122 return NULL;
123 }
124
125 so = dlopen(path, RTLD_LOCAL);
126 if (so == NULL) return NULL;
127
128 si_sym_init = si_mod_dlsym(so, name, "init");
129 if (si_sym_init == NULL)
130 {
131 dlclose(so);
132 errno = ECONNREFUSED;
133 return NULL;
134 }
135
136 si_sym_close = si_mod_dlsym(so, name, "close");
137 if (si_sym_close == NULL)
138 {
139 dlclose(so);
140 errno = ECONNREFUSED;
141 return NULL;
142 }
143
144 out = (si_mod_t *)calloc(1, sizeof(si_mod_t));
145 outname = strdup(name);
146
147 if ((out == NULL) || (outname == NULL))
148 {
149 free(out);
150 free(outname);
151 dlclose(so);
152 errno = ENOMEM;
153 return NULL;
154 }
155
156 out->name = outname;
157 out->refcount = 1;
158 out->flags = 0;
159 out->bundle = so;
160
161 status = si_sym_init(out);
162 if (status != 0)
163 {
164 dlclose(so);
165 free(out);
166 free(outname);
167 errno = ECONNREFUSED;
168 return NULL;
169 }
170
171 return out;
172 }
173
174 LIBINFO_EXPORT
175 si_mod_t *
176 si_module_with_name(const char *name)
177 {
178 static struct
179 {
180 const char *name;
181 si_mod_t *(*init)(void);
182 si_mod_t *module;
183 } modules[] =
184 {
185 { "search", si_module_static_search, NULL },
186 { "cache", si_module_static_cache, NULL },
187 { "file", si_module_static_file, NULL },
188 #ifdef MUSER_AVAILABLE
189 { "muser", si_module_static_muser, NULL },
190 #endif
191 #ifdef DS_AVAILABLE
192 { "ds", si_module_static_ds, NULL },
193 #endif
194 { "mdns", si_module_static_mdns, NULL },
195 { NULL, NULL },
196 };
197
198 si_mod_t *si = NULL;
199 int i;
200
201 /*
202 * We don't need to worry about locking during initialization
203 * because all modules init routine returns static storage.
204 */
205
206 /* Find the module by name */
207 for (i = 0; modules[i].name != NULL; ++i)
208 {
209 if (string_equal(name, modules[i].name))
210 {
211 si = modules[i].module;
212 if (si == NULL)
213 {
214 si = modules[i].init();
215 modules[i].module = si;
216 }
217
218 break;
219 }
220 }
221
222 if (si != NULL) return si;
223
224 pthread_mutex_lock(&module_mutex);
225 char *path = NULL;
226
227 asprintf(&path, "%s/%s.%s", PLUGIN_DIR_PATH, name, PLUGIN_BUNDLE_SUFFIX);
228
229 if (path == NULL)
230 {
231 errno = ENOMEM;
232 pthread_mutex_unlock(&module_mutex);
233 return NULL;
234 }
235
236 si = si_module_with_path(path, name);
237 free(path);
238
239 if (si == NULL)
240 {
241 pthread_mutex_unlock(&module_mutex);
242 return NULL;
243 }
244
245 /* add out to module_list */
246 module_list = (si_mod_t **)reallocf(module_list, (module_count + 1) * sizeof(si_mod_t *));
247 if (module_list == NULL)
248 {
249 pthread_mutex_unlock(&module_mutex);
250 return si;
251 }
252
253 module_list[module_count] = si;
254 module_count++;
255
256 pthread_mutex_unlock(&module_mutex);
257
258 return si;
259 }
260
261 LIBINFO_EXPORT
262 si_mod_t *
263 si_module_retain(si_mod_t *si)
264 {
265 if (si == NULL) return NULL;
266 if (si->flags & SI_MOD_FLAG_STATIC) return si;
267
268 OSAtomicIncrement32Barrier(&si->refcount);
269
270 return si;
271 }
272
273 LIBINFO_EXPORT
274 void
275 si_module_release(si_mod_t *si)
276 {
277 int32_t i;
278
279 if (si == NULL) return;
280 if (si->flags & SI_MOD_FLAG_STATIC) return;
281
282 i = OSAtomicDecrement32Barrier(&si->refcount);
283 if (i > 0) return;
284
285 pthread_mutex_lock(&module_mutex);
286
287 for (i = 0; (i < module_count) && (module_list[i] != si); i++);
288 if (i >= module_count)
289 {
290 pthread_mutex_unlock(&module_mutex);
291 return;
292 }
293
294 if (module_count == 1)
295 {
296 free(module_list);
297 module_list = NULL;
298 module_count = 0;
299 pthread_mutex_unlock(&module_mutex);
300 return;
301 }
302
303 for (i++; i < module_count; i++) module_list[i - 1] = module_list[i];
304 module_count--;
305 module_list = (si_mod_t **)reallocf(module_list, module_count * sizeof(si_mod_t *));
306 if (module_list == NULL) module_count = 0;
307
308 pthread_mutex_unlock(&module_mutex);
309
310 if (si->vtable->sim_close != NULL) si->vtable->sim_close(si);
311 if (si->bundle != NULL) dlclose(si->bundle);
312 free(si->name);
313 free(si);
314 }
315
316 LIBINFO_EXPORT
317 const char *
318 si_module_name(si_mod_t *si)
319 {
320 if (si == NULL) return NULL;
321
322 return (const char *)si->name;
323 }
324
325 LIBINFO_EXPORT
326 int
327 si_module_vers(si_mod_t *si)
328 {
329 if (si == NULL) return 0;
330
331 return si->vers;
332 }
333
334 LIBINFO_EXPORT
335 int
336 si_item_match(si_item_t *item, int cat, const void *name, uint32_t num, int which)
337 {
338 int i;
339 union
340 {
341 char *x;
342 struct passwd *u;
343 struct group *g;
344 struct grouplist_s *l;
345 struct aliasent *a;
346 struct hostent *h;
347 struct netent *n;
348 struct servent *s;
349 struct protoent *p;
350 struct rpcent *r;
351 struct fstab *f;
352 struct mac_s *m;
353 } ent;
354
355 if (item == NULL) return 0;
356 if (which == SEL_ALL) return 1;
357 if ((which == SEL_NAME) && (name == NULL)) return 0;
358
359 ent.x = (char *)((uintptr_t)item + sizeof(si_item_t));
360
361 switch (cat)
362 {
363 case CATEGORY_USER:
364 {
365 if ((which == SEL_NAME) && (string_equal(name, ent.u->pw_name))) return 1;
366 else if ((which == SEL_NUMBER) && (num == (uint32_t)ent.u->pw_uid)) return 1;
367 return 0;
368 }
369 case CATEGORY_GROUP:
370 {
371 if ((which == SEL_NAME) && (string_equal(name, ent.g->gr_name))) return 1;
372 else if ((which == SEL_NUMBER) && (num == (uint32_t)ent.g->gr_gid)) return 1;
373 return 0;
374 }
375 case CATEGORY_GROUPLIST:
376 {
377 if ((which == SEL_NAME) && (string_equal(name, ent.l->gl_user))) return 1;
378 return 0;
379 }
380 case CATEGORY_ALIAS:
381 {
382 if ((which == SEL_NAME) && (string_equal(name, ent.a->alias_name))) return 1;
383 return 0;
384 }
385 case CATEGORY_HOST_IPV4:
386 case CATEGORY_HOST_IPV6:
387 {
388 /* N.B. address family is passed in num variable */
389 if (ent.h->h_addrtype != num) return 0;
390 if (which == SEL_NAME)
391 {
392 if (string_equal(name, ent.h->h_name)) return 1;
393 if (ent.h->h_aliases != NULL)
394 {
395 for (i = 0; ent.h->h_aliases[i] != NULL; i++)
396 {
397 if (string_equal(name, ent.h->h_aliases[i])) return 1;
398 }
399 }
400 }
401 else if (which == SEL_NUMBER)
402 {
403 if (memcmp(name, ent.h->h_addr_list[0], ent.h->h_length) == 0) return 1;
404 }
405 return 0;
406 }
407 case CATEGORY_NETWORK:
408 {
409 if (which == SEL_NAME)
410 {
411 if (string_equal(name, ent.n->n_name)) return 1;
412 if (ent.n->n_aliases != NULL)
413 {
414 for (i = 0; ent.n->n_aliases[i] != NULL; i++)
415 {
416 if (string_equal(name, ent.n->n_aliases[i])) return 1;
417 }
418 }
419 }
420 else if (which == SEL_NUMBER)
421 {
422 if (num == ent.n->n_net) return 1;
423 }
424 return 0;
425 }
426 case CATEGORY_SERVICE:
427 {
428 if (which == SEL_NAME)
429 {
430 /* N.B. for SEL_NAME, num is 0 (don't care), 1 (udp) or 2 (tcp) */
431 if ((num == 1) && (string_not_equal("udp", ent.s->s_proto))) return 0;
432 if ((num == 2) && (string_not_equal("tcp", ent.s->s_proto))) return 0;
433
434 if (string_equal(name, ent.s->s_name)) return 1;
435 if (ent.s->s_aliases != NULL)
436 {
437 for (i = 0; ent.s->s_aliases[i] != NULL; i++)
438 {
439 if (string_equal(name, ent.s->s_aliases[i])) return 1;
440 }
441 }
442 }
443 else if (which == SEL_NUMBER)
444 {
445 /* N.B. for SEL_NUMBER, protocol is sent in name variable */
446 if ((name != NULL) && (string_not_equal(name, ent.s->s_proto))) return 0;
447 if (num == ent.s->s_port) return 1;
448 }
449 return 0;
450 }
451 case CATEGORY_PROTOCOL:
452 {
453 if (which == SEL_NAME)
454 {
455 if (string_equal(name, ent.p->p_name)) return 1;
456 if (ent.p->p_aliases != NULL)
457 {
458 for (i = 0; ent.p->p_aliases[i] != NULL; i++)
459 {
460 if (string_equal(name, ent.p->p_aliases[i])) return 1;
461 }
462 }
463 }
464 else if (which == SEL_NUMBER)
465 {
466 if (num == ent.p->p_proto) return 1;
467 }
468 return 0;
469 }
470 case CATEGORY_RPC:
471 {
472 if (which == SEL_NAME)
473 {
474 if (string_equal(name, ent.r->r_name)) return 1;
475 if (ent.r->r_aliases != NULL)
476 {
477 for (i = 0; ent.r->r_aliases[i] != NULL; i++)
478 {
479 if (string_equal(name, ent.r->r_aliases[i])) return 1;
480 }
481 }
482 }
483 else if (which == SEL_NUMBER)
484 {
485 if (num == ent.r->r_number) return 1;
486 }
487 return 0;
488 }
489 case CATEGORY_FS:
490 {
491 if ((which == SEL_NAME) && (string_equal(name, ent.f->fs_spec))) return 1;
492 if ((which == SEL_NUMBER) && (string_equal(name, ent.f->fs_file))) return 1;
493 return 0;
494 }
495 case CATEGORY_MAC:
496 {
497 if ((which == SEL_NAME) && (string_equal(name, ent.m->host))) return 1;
498 if ((which == SEL_NUMBER) && (string_equal(name, ent.m->mac))) return 1;
499 return 0;
500 }
501 default: return 0;
502 }
503
504 return 0;
505 }
506
507 LIBINFO_EXPORT
508 int
509 si_item_is_valid(si_item_t *item)
510 {
511 si_mod_t *si;
512
513 if (item == NULL) return 0;
514
515 si = item->src;
516
517 if (si == NULL) return 0;
518 if (si->vtable->sim_is_valid == NULL) return 0;
519
520 return si->vtable->sim_is_valid(si, item);
521 }
522
523 LIBINFO_EXPORT
524 si_item_t *
525 si_user_byname(si_mod_t *si, const char *name)
526 {
527 if (si == NULL) return NULL;
528 if (si->vtable->sim_user_byname == NULL) return NULL;
529 return si->vtable->sim_user_byname(si, name);
530 }
531
532 LIBINFO_EXPORT
533 si_item_t *
534 si_user_byuid(si_mod_t *si, uid_t uid)
535 {
536 if (si == NULL) return NULL;
537 if (si->vtable->sim_user_byuid == NULL) return NULL;
538 return si->vtable->sim_user_byuid(si, uid);
539 }
540
541 LIBINFO_EXPORT
542 si_item_t *
543 si_user_byuuid(si_mod_t *si, uuid_t uuid)
544 {
545 if (si == NULL) return NULL;
546 if (si->vtable->sim_user_byuuid == NULL) return NULL;
547 return si->vtable->sim_user_byuuid(si, uuid);
548 }
549
550 LIBINFO_EXPORT
551 si_list_t *
552 si_user_all(si_mod_t *si)
553 {
554 if (si == NULL) return NULL;
555 if (si->vtable->sim_user_all == NULL) return NULL;
556 return si->vtable->sim_user_all(si);
557 }
558
559 LIBINFO_EXPORT
560 si_item_t *
561 si_group_byname(si_mod_t *si, const char *name)
562 {
563 if (si == NULL) return NULL;
564 if (si->vtable->sim_group_byname == NULL) return NULL;
565 return si->vtable->sim_group_byname(si, name);
566 }
567
568 LIBINFO_EXPORT
569 si_item_t *
570 si_group_bygid(si_mod_t *si, gid_t gid)
571 {
572 if (si == NULL) return NULL;
573 if (si->vtable->sim_group_bygid == NULL) return NULL;
574 return si->vtable->sim_group_bygid(si, gid);
575 }
576
577 LIBINFO_EXPORT
578 si_item_t *
579 si_group_byuuid(si_mod_t *si, uuid_t uuid)
580 {
581 if (si == NULL) return NULL;
582 if (si->vtable->sim_group_byuuid == NULL) return NULL;
583 return si->vtable->sim_group_byuuid(si, uuid);
584 }
585
586 LIBINFO_EXPORT
587 si_list_t *
588 si_group_all(si_mod_t *si)
589 {
590 if (si == NULL) return NULL;
591 if (si->vtable->sim_group_all == NULL) return NULL;
592 return si->vtable->sim_group_all(si);
593 }
594
595 LIBINFO_EXPORT
596 si_item_t *
597 si_grouplist(si_mod_t *si, const char *name, uint32_t count)
598 {
599 if (si == NULL) return NULL;
600 if (si->vtable->sim_grouplist == NULL) return NULL;
601 return si->vtable->sim_grouplist(si, name, count);
602 }
603
604 LIBINFO_EXPORT
605 si_list_t *
606 si_netgroup_byname(struct si_mod_s *si, const char *name)
607 {
608 if (si == NULL) return NULL;
609 if (si->vtable->sim_netgroup_byname == NULL) return NULL;
610 return si->vtable->sim_netgroup_byname(si, name);
611 }
612
613 LIBINFO_EXPORT
614 int
615 si_in_netgroup(struct si_mod_s *si, const char *name, const char *host, const char *user, const char *domain)
616 {
617 if (si == NULL) return 0;
618 if (si->vtable->sim_in_netgroup == NULL) return 0;
619 return si->vtable->sim_in_netgroup(si, name, host, user, domain);
620 }
621
622 LIBINFO_EXPORT
623 si_item_t *
624 si_alias_byname(si_mod_t *si, const char *name)
625 {
626 if (si == NULL) return NULL;
627 if (si->vtable->sim_alias_byname == NULL) return NULL;
628 return si->vtable->sim_alias_byname(si, name);
629 }
630
631 LIBINFO_EXPORT
632 si_list_t *
633 si_alias_all(si_mod_t *si)
634 {
635 if (si == NULL) return NULL;
636 if (si->vtable->sim_alias_all == NULL) return NULL;
637 return si->vtable->sim_alias_all(si);
638 }
639
640 LIBINFO_EXPORT
641 si_item_t *
642 si_host_byname(si_mod_t *si, const char *name, int af, const char *interface, uint32_t *err)
643 {
644 if (si == NULL) return NULL;
645 if (si->vtable->sim_host_byname == NULL) return NULL;
646 return si->vtable->sim_host_byname(si, name, af, interface, err);
647 }
648
649 LIBINFO_EXPORT
650 si_item_t *
651 si_host_byaddr(si_mod_t *si, const void *addr, int af, const char *interface, uint32_t *err)
652 {
653 if (si == NULL) return NULL;
654 if (si->vtable->sim_host_byaddr == NULL) return NULL;
655 return si->vtable->sim_host_byaddr(si, addr, af, interface, err);
656 }
657
658 LIBINFO_EXPORT
659 si_list_t *
660 si_host_all(si_mod_t *si)
661 {
662 if (si == NULL) return NULL;
663 if (si->vtable->sim_host_all == NULL) return NULL;
664 return si->vtable->sim_host_all(si);
665 }
666
667 LIBINFO_EXPORT
668 si_item_t *
669 si_mac_byname(struct si_mod_s *si, const char *name)
670 {
671 if (si == NULL) return NULL;
672 if (si->vtable->sim_mac_byname == NULL) return NULL;
673 return si->vtable->sim_mac_byname(si, name);
674 }
675
676 LIBINFO_EXPORT
677 si_item_t *
678 si_mac_bymac(struct si_mod_s *si, const char *mac)
679 {
680 if (si == NULL) return NULL;
681 if (si->vtable->sim_mac_bymac == NULL) return NULL;
682 return si->vtable->sim_mac_bymac(si, mac);
683 }
684
685 LIBINFO_EXPORT
686 si_list_t *
687 si_mac_all(si_mod_t *si)
688 {
689 if (si == NULL) return NULL;
690 if (si->vtable->sim_mac_all == NULL) return NULL;
691 return si->vtable->sim_mac_all(si);
692 }
693
694 LIBINFO_EXPORT
695 si_item_t *
696 si_network_byname(si_mod_t *si, const char *name)
697 {
698 if (si == NULL) return NULL;
699 if (si->vtable->sim_network_byname == NULL) return NULL;
700 return si->vtable->sim_network_byname(si, name);
701 }
702
703 LIBINFO_EXPORT
704 si_item_t *
705 si_network_byaddr(si_mod_t *si, uint32_t addr)
706 {
707 if (si == NULL) return NULL;
708 if (si->vtable->sim_network_byaddr == NULL) return NULL;
709 return si->vtable->sim_network_byaddr(si, addr);
710 }
711
712 LIBINFO_EXPORT
713 si_list_t *
714 si_network_all(si_mod_t *si)
715 {
716 if (si == NULL) return NULL;
717 if (si->vtable->sim_network_all == NULL) return NULL;
718 return si->vtable->sim_network_all(si);
719 }
720
721 LIBINFO_EXPORT
722 si_item_t *
723 si_service_byname(si_mod_t *si, const char *name, const char *proto)
724 {
725 if (si == NULL) return NULL;
726 if (si->vtable->sim_service_byname == NULL) return NULL;
727 return si->vtable->sim_service_byname(si, name, proto);
728 }
729
730 LIBINFO_EXPORT
731 si_item_t *
732 si_service_byport(si_mod_t *si, int port, const char *proto)
733 {
734 if (si == NULL) return NULL;
735 if (si->vtable->sim_service_byport == NULL) return NULL;
736 return si->vtable->sim_service_byport(si, port, proto);
737 }
738
739 LIBINFO_EXPORT
740 si_list_t *
741 si_service_all(si_mod_t *si)
742 {
743 if (si == NULL) return NULL;
744 if (si->vtable->sim_service_all == NULL) return NULL;
745 return si->vtable->sim_service_all(si);
746 }
747
748 LIBINFO_EXPORT
749 si_item_t *
750 si_protocol_byname(si_mod_t *si, const char *name)
751 {
752 if (si == NULL) return NULL;
753 if (si->vtable->sim_protocol_byname == NULL) return NULL;
754 return si->vtable->sim_protocol_byname(si, name);
755 }
756
757 LIBINFO_EXPORT
758 si_item_t *
759 si_protocol_bynumber(si_mod_t *si, uint32_t number)
760 {
761 if (si == NULL) return NULL;
762 if (si->vtable->sim_protocol_bynumber == NULL) return NULL;
763 return si->vtable->sim_protocol_bynumber(si, number);
764 }
765
766 LIBINFO_EXPORT
767 si_list_t *
768 si_protocol_all(si_mod_t *si)
769 {
770 if (si == NULL) return NULL;
771 if (si->vtable->sim_protocol_all == NULL) return NULL;
772 return si->vtable->sim_protocol_all(si);
773 }
774
775 LIBINFO_EXPORT
776 si_item_t *
777 si_rpc_byname(si_mod_t *si, const char *name)
778 {
779 if (si == NULL) return NULL;
780 if (si->vtable->sim_rpc_byname == NULL) return NULL;
781 return si->vtable->sim_rpc_byname(si, name);
782 }
783
784 LIBINFO_EXPORT
785 si_item_t *
786 si_rpc_bynumber(si_mod_t *si, int number)
787 {
788 if (si == NULL) return NULL;
789 if (si->vtable->sim_rpc_bynumber == NULL) return NULL;
790 return si->vtable->sim_rpc_bynumber(si, number);
791 }
792
793 LIBINFO_EXPORT
794 si_list_t *
795 si_rpc_all(si_mod_t *si)
796 {
797 if (si == NULL) return NULL;
798 if (si->vtable->sim_rpc_all == NULL) return NULL;
799 return si->vtable->sim_rpc_all(si);
800 }
801
802 LIBINFO_EXPORT
803 si_item_t *
804 si_fs_byspec(si_mod_t *si, const char *spec)
805 {
806 if (si == NULL) return NULL;
807 if (si->vtable->sim_fs_byspec == NULL) return NULL;
808 return si->vtable->sim_fs_byspec(si, spec);
809 }
810
811 LIBINFO_EXPORT
812 si_item_t *
813 si_fs_byfile(si_mod_t *si, const char *file)
814 {
815 if (si == NULL) return NULL;
816 if (si->vtable->sim_fs_byfile == NULL) return NULL;
817 return si->vtable->sim_fs_byfile(si, file);
818 }
819
820 LIBINFO_EXPORT
821 si_list_t *
822 si_fs_all(si_mod_t *si)
823 {
824 if (si == NULL) return NULL;
825 if (si->vtable->sim_fs_all == NULL) return NULL;
826 return si->vtable->sim_fs_all(si);
827 }
828
829 LIBINFO_EXPORT
830 si_item_t *
831 si_item_call(struct si_mod_s *si, int call, const char *str1, const char *str2, const char *str3, uint32_t num1, uint32_t num2, uint32_t *err)
832 {
833 if (si == NULL) return NULL;
834
835 switch (call)
836 {
837 case SI_CALL_USER_BYNAME: return si_user_byname(si, str1);
838 case SI_CALL_USER_BYUID: return si_user_byuid(si, (uid_t)num1);
839 case SI_CALL_GROUP_BYNAME: return si_group_byname(si, str1);
840 case SI_CALL_GROUP_BYGID: return si_group_bygid(si, (gid_t)num1);
841 case SI_CALL_GROUPLIST: return si_grouplist(si, str1, (int) num1);
842 case SI_CALL_ALIAS_BYNAME: return si_alias_byname(si, str1);
843 case SI_CALL_HOST_BYNAME: return si_host_byname(si, str1, num1, str3, err);
844 case SI_CALL_HOST_BYADDR: return si_host_byaddr(si, (void *)str1, num1, str3, err);
845 case SI_CALL_NETWORK_BYNAME: return si_network_byname(si, str1);
846 case SI_CALL_NETWORK_BYADDR: return si_network_byaddr(si, num1);
847 case SI_CALL_SERVICE_BYNAME: return si_service_byname(si, str1, str2);
848 case SI_CALL_SERVICE_BYPORT: return si_service_byport(si, num1, str2);
849 case SI_CALL_PROTOCOL_BYNAME: return si_protocol_byname(si, str1);
850 case SI_CALL_PROTOCOL_BYNUMBER: return si_protocol_bynumber(si, num1);
851 case SI_CALL_RPC_BYNAME: return si_network_byname(si, str1);
852 case SI_CALL_RPC_BYNUMBER: return si_rpc_bynumber(si, num1);
853 case SI_CALL_FS_BYSPEC: return si_fs_byspec(si, str1);
854 case SI_CALL_FS_BYFILE: return si_fs_byfile(si, str1);
855 case SI_CALL_NAMEINFO: return si_nameinfo(si, (const struct sockaddr *)str1, num1, str3, err);
856 case SI_CALL_IPNODE_BYNAME: return si_ipnode_byname(si, (const char *)str1, num1, num2, str3, err);
857 case SI_CALL_MAC_BYNAME: return si_mac_byname(si, (const char *)str1);
858 case SI_CALL_MAC_BYMAC: return si_mac_bymac(si, (const char *)str1);
859
860 /* Support for DNS async calls */
861 case SI_CALL_DNS_QUERY:
862 case SI_CALL_DNS_SEARCH:
863 {
864 if (si->vtable->sim_item_call == NULL) return NULL;
865 return si->vtable->sim_item_call(si, call, str1, str2, str3, num1, num2, err);
866 }
867
868 default: return NULL;
869 }
870
871 return NULL;
872 }
873
874 LIBINFO_EXPORT
875 si_list_t *
876 si_list_call(struct si_mod_s *si, int call, const char *str1, const char *str2, const char *str3, uint32_t num1, uint32_t num2, uint32_t num3, uint32_t num4, uint32_t *err)
877 {
878 if (si == NULL) return NULL;
879
880 switch (call)
881 {
882 case SI_CALL_USER_ALL: return si_user_all(si);
883 case SI_CALL_GROUP_ALL: return si_group_all(si);
884 case SI_CALL_ALIAS_ALL: return si_alias_all(si);
885 case SI_CALL_HOST_ALL: return si_host_all(si);
886 case SI_CALL_NETWORK_ALL: return si_network_all(si);
887 case SI_CALL_SERVICE_ALL: return si_service_all(si);
888 case SI_CALL_PROTOCOL_ALL: return si_protocol_all(si);
889 case SI_CALL_RPC_ALL: return si_rpc_all(si);
890 case SI_CALL_FS_ALL: return si_fs_all(si);
891 case SI_CALL_MAC_ALL: return si_mac_all(si);
892 case SI_CALL_ADDRINFO: return si_addrinfo(si, str1, str2, num1, num2, num3, num4, str3, err);
893 default: return NULL;
894 }
895
896 return NULL;
897 }
898
899 static void
900 si_async_worklist_add_unit(si_async_workunit_t *r)
901 {
902 pthread_mutex_lock(&module_mutex);
903 r->next = si_async_worklist;
904 si_async_worklist = r;
905 pthread_mutex_unlock(&module_mutex);
906 }
907
908 static void
909 si_async_worklist_remove_unit(si_async_workunit_t *r)
910 {
911 si_async_workunit_t *x;
912
913 pthread_mutex_lock(&module_mutex);
914 if (si_async_worklist == r)
915 {
916 si_async_worklist = r->next;
917 }
918 else
919 {
920 for (x = si_async_worklist; (x != NULL) && (x->next != r); x = x->next) {;}
921 if (x != NULL) x->next = r->next;
922 }
923 pthread_mutex_unlock(&module_mutex);
924 }
925
926 static si_async_workunit_t*
927 si_async_worklist_find_unit(mach_port_t p)
928 {
929 si_async_workunit_t *r;
930
931 pthread_mutex_lock(&module_mutex);
932 for (r = si_async_worklist; (r != NULL) && (r->port != p); r = r->next) {;}
933 pthread_mutex_unlock(&module_mutex);
934
935 return r;
936 }
937
938 static si_async_workunit_t *
939 si_async_workunit_create(si_mod_t *si, int call, const char *str1, const char *str2, const char *str3, uint32_t num1, uint32_t num2, uint32_t num3, uint32_t num4, void *callback, void *context)
940 {
941 si_async_workunit_t *r;
942 kern_return_t status;
943 mach_port_t reply, send;
944 mach_msg_type_name_t type;
945 char *s1, *s2, *s3;
946
947 s1 = NULL;
948 s2 = NULL;
949 s3 = NULL;
950
951 if (si_call_str1_is_buffer(call))
952 {
953 if (num3 > 0)
954 {
955 s1 = calloc(1, num3);
956 if (s1 == NULL) return NULL;
957 memcpy(s1, str1, num3);
958 }
959 }
960 else if (str1 != NULL)
961 {
962 s1 = strdup(str1);
963 if (s1 == NULL) return NULL;
964 }
965
966 if (str2 != NULL)
967 {
968 s2 = strdup(str2);
969 if (s2 == NULL)
970 {
971 if (s1 != NULL) free(s1);
972 return NULL;
973 }
974 }
975
976 if (str3 != NULL)
977 {
978 s3 = strdup(str3);
979 if (s3 == NULL)
980 {
981 if (s1 != NULL) free(s1);
982 if (s2 != NULL) free(s2);
983 return NULL;
984 }
985 }
986
987 r = (si_async_workunit_t *)calloc(1, sizeof(si_async_workunit_t));
988 if (r == NULL)
989 {
990 if (s1 != NULL) free(s1);
991 if (s2 != NULL) free(s2);
992 if (s3 != NULL) free(s3);
993 return NULL;
994 }
995
996 reply = MACH_PORT_NULL;
997 send = MACH_PORT_NULL;
998 type = 0;
999
1000 status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &reply);
1001 if (status == KERN_SUCCESS) status = mach_port_extract_right(mach_task_self(), reply, MACH_MSG_TYPE_MAKE_SEND_ONCE, &send, &type);
1002 if (status != KERN_SUCCESS)
1003 {
1004 if (reply != MACH_PORT_NULL) mach_port_mod_refs(mach_task_self(), reply, MACH_PORT_RIGHT_RECEIVE, -1);
1005 if (s1 != NULL) free(s1);
1006 if (s2 != NULL) free(s2);
1007 if (s3 != NULL) free(s3);
1008 free(r);
1009 return NULL;
1010 }
1011
1012 r->si = si;
1013 r->call = call;
1014 r->str1 = s1;
1015 r->str2 = s2;
1016 r->str3 = s3;
1017 r->num1 = num1;
1018 r->num2 = num2;
1019 r->num3 = num3;
1020 r->num4 = num4;
1021
1022 r->refcount = 2;
1023 r->flags = 0;
1024 if (si_call_returns_list(call)) r->flags |= WORKUNIT_RETURNS_LIST;
1025
1026 r->callback = callback;
1027 r->context = context;
1028 r->port = reply;
1029 r->send = send;
1030
1031 si_async_worklist_add_unit(r);
1032
1033 return r;
1034 }
1035
1036 static void
1037 si_async_workunit_release(si_async_workunit_t *r)
1038 {
1039 if (r == NULL) return;
1040
1041 if (OSAtomicDecrement32Barrier(&(r->refcount)) != 0) return;
1042
1043 #ifdef CALL_TRACE
1044 fprintf(stderr, "** %s freeing worklist item %p\n", __func__, r);
1045 #endif
1046
1047 si_async_worklist_remove_unit(r);
1048
1049 if (r->resitem != NULL) si_item_release(r->resitem);
1050 if (r->reslist != NULL) si_list_release(r->reslist);
1051
1052 if (r->str1 != NULL) free(r->str1);
1053 if (r->str2 != NULL) free(r->str2);
1054 if (r->str3 != NULL) free(r->str3);
1055
1056 /* release send-once right if it has not been used */
1057 if (r->send != MACH_PORT_NULL) mach_port_deallocate(mach_task_self(), r->send);
1058
1059 /* release receive right */
1060 mach_port_mod_refs(mach_task_self(), r->port, MACH_PORT_RIGHT_RECEIVE, -1);
1061
1062 free(r);
1063 }
1064
1065 static void
1066 si_async_launchpad(si_async_workunit_t *r)
1067 {
1068 kern_return_t status;
1069 mach_msg_empty_send_t msg;
1070
1071 #ifdef CALL_TRACE
1072 fprintf(stderr, "** %s starting worklist item %p\n", __func__, r);
1073 #endif
1074
1075 if (r->flags & WORKUNIT_CANCELLED)
1076 {
1077 si_async_workunit_release(r);
1078 #ifdef CALL_TRACE
1079 fprintf(stderr, "** %s worklist item %p was cancelled early\n", __func__, r);
1080 #endif
1081 return;
1082 }
1083
1084 if (r->flags & WORKUNIT_RETURNS_LIST) r->reslist = si_list_call(r->si, r->call, r->str1, r->str2, r->str3, r->num1, r->num2, r->num3, r->num4, &(r->err));
1085 else r->resitem = si_item_call(r->si, r->call, r->str1, r->str2, r->str3, r->num1, r->num2, &(r->err));
1086
1087 /*
1088 * Test and set the cancelled flag.
1089 * If it was set, then this work item was cancelled.
1090 * Otherwise, setting it here prevents si_async_cancel from cancelling:
1091 * too late to cancel now!
1092 */
1093 if (OSAtomicTestAndSetBarrier(WORKUNIT_CANCELLED_BIT_ADDRESS, &(r->flags)) == 1)
1094 {
1095 si_async_workunit_release(r);
1096 #ifdef CALL_TRACE
1097 fprintf(stderr, "** %s worklist item %p was cancelled in flight\n", __func__, r);
1098 #endif
1099 return;
1100 }
1101 #ifdef CALL_TRACE
1102 else fprintf(stderr, "** %s worklist item %p flags are now 0x%08x\n", __func__, r, r->flags);
1103 #endif
1104
1105 memset(&msg, 0, sizeof(mach_msg_empty_send_t));
1106
1107 msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, MACH_MSGH_BITS_ZERO);
1108 msg.header.msgh_remote_port = r->send;
1109 r->send = MACH_PORT_NULL;
1110 msg.header.msgh_local_port = MACH_PORT_NULL;
1111 msg.header.msgh_size = sizeof(mach_msg_empty_send_t);
1112 msg.header.msgh_id = r->call;
1113
1114 status = mach_msg(&(msg.header), MACH_SEND_MSG, msg.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
1115 if ((status == MACH_SEND_INVALID_DEST) || (status == MACH_SEND_TIMED_OUT))
1116 {
1117 /* receiver failed - clean up to avoid a port leak */
1118 mach_msg_destroy(&(msg.header));
1119 #ifdef CALL_TRACE
1120 fprintf(stderr, "** %s mach message send failed for worklist item %p\n", __func__, r);
1121 #endif
1122 }
1123
1124 si_async_workunit_release(r);
1125
1126 /*
1127 * The client is now responsible for calling si_async_handle_reply,
1128 * which will invoke the client's callback and then release the workunit.
1129 */
1130
1131 #ifdef CALL_TRACE
1132 fprintf(stderr, "** %s completed async worklist item %p\n", __func__, r);
1133 #endif
1134 }
1135
1136 LIBINFO_EXPORT
1137 mach_port_t
1138 si_async_call(struct si_mod_s *si, int call, const char *str1, const char *str2, const char *str3, uint32_t num1, uint32_t num2, uint32_t num3, uint32_t num4, void *callback, void *context)
1139 {
1140 si_async_workunit_t *req;
1141
1142 if (si == NULL) return MACH_PORT_NULL;
1143 if (callback == NULL) return MACH_PORT_NULL;
1144
1145 /* if module does async on it's own, hand off the call */
1146 if (si->vtable->sim_async_call != NULL)
1147 {
1148 return si->vtable->sim_async_call(si, call, str1, str2, str3, num1, num2, num3, num4, callback, context);
1149 }
1150
1151 req = si_async_workunit_create(si, call, str1, str2, str3, num1, num2, num3, num4, callback, context);
1152 if (req == NULL) return MACH_PORT_NULL;
1153
1154 /* queue the work on the global low-priority dispatch queue */
1155 #ifdef CALL_TRACE
1156 fprintf(stderr, "** %s dispatching worklist item %p\n", __func__, req);
1157 #endif
1158 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, DISPATCH_QUEUE_OVERCOMMIT), ^{ si_async_launchpad(req); });
1159
1160 return req->port;
1161 }
1162
1163 LIBINFO_EXPORT
1164 void
1165 si_async_cancel(mach_port_t p)
1166 {
1167 si_async_workunit_t *r;
1168
1169 r = si_async_worklist_find_unit(p);
1170 if (r == NULL)
1171 {
1172 #ifdef CALL_TRACE
1173 fprintf(stderr, "** %s can't find worklist item\n", __func__);
1174 #endif
1175 return;
1176 }
1177
1178 /*
1179 * Test and set the WORKUNIT_CANCELLED flag.
1180 * If it was already set, this work item has been executed - too late to really cancel.
1181 */
1182 if (OSAtomicTestAndSetBarrier(WORKUNIT_CANCELLED_BIT_ADDRESS, &(r->flags)) == 1)
1183 {
1184 /* already executed */
1185 #ifdef CALL_TRACE
1186 fprintf(stderr, "** %s worklist item %p has executed\n", __func__, r);
1187 #endif
1188 }
1189
1190 #ifdef CALL_TRACE
1191 fprintf(stderr, "** %s calling worklist item %p callback SI_STATUS_CALL_CANCELLED\n", __func__, r);
1192 #endif
1193
1194 if (r->callback != NULL)
1195 {
1196 if (r->flags & WORKUNIT_RETURNS_LIST) ((list_async_callback)(r->callback))(NULL, SI_STATUS_CALL_CANCELLED, r->context);
1197 else ((item_async_callback)(r->callback))(NULL, SI_STATUS_CALL_CANCELLED, r->context);
1198 }
1199
1200 si_async_workunit_release(r);
1201 }
1202
1203 LIBINFO_EXPORT
1204 void
1205 si_async_handle_reply(mach_msg_header_t *msg)
1206 {
1207 si_async_workunit_t *r;
1208 mach_port_t reply = msg->msgh_local_port;
1209
1210 r = si_async_worklist_find_unit(reply);
1211 if (r == NULL)
1212 {
1213 #ifdef CALL_TRACE
1214 fprintf(stderr, "** %s can't find worklist item\n", __func__);
1215 #endif
1216 return;
1217 }
1218
1219 #ifdef CALL_TRACE
1220 fprintf(stderr, "** %s worklist item %p flags are 0x%08x\n", __func__, r, r->flags);
1221 #endif
1222 if ((r->flags & WORKUNIT_CANCELLED) == 0)
1223 {
1224 #ifdef CALL_TRACE
1225 fprintf(stderr, "** %s workunit thread is still active\n", __func__);
1226 #endif
1227 return;
1228 }
1229
1230 if (r->callback != NULL)
1231 {
1232 if (r->flags & WORKUNIT_RETURNS_LIST) ((list_async_callback)(r->callback))(r->reslist, r->err, r->context);
1233 else ((item_async_callback)(r->callback))(r->resitem, r->err, r->context);
1234
1235 r->reslist = NULL;
1236 r->resitem = NULL;
1237 }
1238 else
1239 {
1240 #ifdef CALL_TRACE
1241 fprintf(stderr, "** %s workunit has no callback\n", __func__);
1242 #endif
1243 }
1244
1245 si_async_workunit_release(r);
1246 }
1247
1248 LIBINFO_EXPORT
1249 char *
1250 si_standardize_mac_address(const char *addr)
1251 {
1252 char e[6][3];
1253 char *out;
1254 struct ether_addr *ether;
1255 int i;
1256
1257 if (addr == NULL) return NULL;
1258
1259 /* ether_aton isn't thread-safe */
1260 pthread_mutex_lock(&module_mutex);
1261
1262 ether = ether_aton(addr);
1263 if (ether == NULL)
1264 {
1265 pthread_mutex_unlock(&module_mutex);
1266 return NULL;
1267 }
1268
1269 for (i = 0; i < 6; i++)
1270 {
1271 if (ether->ether_addr_octet[i] <= 15)
1272 {
1273 sprintf(e[i], "0%x", ether->ether_addr_octet[i]);
1274 }
1275 else
1276 {
1277 sprintf(e[i], "%x", ether->ether_addr_octet[i]);
1278 }
1279 }
1280
1281 pthread_mutex_unlock(&module_mutex);
1282
1283 out = NULL;
1284 asprintf(&out, "%s:%s:%s:%s:%s:%s", e[0], e[1], e[2], e[3], e[4], e[5]);
1285 return out;
1286 }