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