1/*
2 * Copyright (c) 2008-2013 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 <stdlib.h>
25#include <unistd.h>
26#include <stdio.h>
27#include <string.h>
28#include <errno.h>
29#include <netdb.h>
30#include <asl.h>
31#include <printerdb.h>
32#include <sys/param.h>
33#include <sys/syscall.h>
34#include <pthread.h>
35#include <arpa/inet.h>
36#include <netinet/if_ether.h>
37#include "si_module.h"
38#include "libinfo.h"
39#include <thread_data.h>
40#include <sys/kauth.h>
41#include "netdb_async.h"
42#include <dispatch/dispatch.h>
43#include <mach-o/dyld_priv.h>
44
45#define SOCK_UNSPEC 0
46#define IPPROTO_UNSPEC 0
47#define IPV6_ADDR_LEN 16
48#define IPV4_ADDR_LEN 4
49
50/* kernel syscalls */
51extern int __initgroups(u_int gidsetsize, gid_t *gidset, int gmuid);
52
53/* SPI from long ago */
54int _proto_stayopen;
55
56extern struct addrinfo *si_list_to_addrinfo(si_list_t *list);
57extern int getnameinfo_link(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);
58__private_extern__ void search_set_flags(si_mod_t *si, const char *name, uint32_t flag);
59
60/*
61 * Impedence matching for async calls.
62 *
63 * This layer holds on to the caller's callback and context in this
64 * structure, which gets passed to the si_module async routines along
65 * with a callbac in this layer.  When this layer gets a callback,
66 * it can save the item or list in thread-specific memory and then
67 * invoke the caller's callback with the appropriate data type.
68 */
69
70typedef struct
71{
72	void *orig_callback;
73	void *orig_context;
74	uint32_t cat;
75	int32_t key_offset;
76} si_context_t;
77
78si_mod_t *
79si_search(void)
80{
81	static si_mod_t *search = NULL;
82
83	if (search == NULL) search = si_module_with_name("search");
84
85	return search;
86}
87
88void
89si_search_module_set_flags(const char *name, uint32_t flag)
90{
91	search_set_flags(si_search(), name, flag);
92}
93
94static void
95si_libinfo_general_callback(si_item_t *item, uint32_t status, void *ctx)
96{
97	si_context_t *sictx;
98	union
99	{
100		char *x;
101		struct passwd *u;
102		struct group *g;
103		struct grouplist_s *l;
104		struct hostent *h;
105		struct netent *n;
106		struct servent *s;
107		struct protoent *p;
108		struct rpcent *r;
109		struct fstab *f;
110	} res;
111
112	if (ctx == NULL) return;
113
114	sictx = (si_context_t *)ctx;
115
116	if ((sictx->orig_callback == NULL) || (status == SI_STATUS_CALL_CANCELLED))
117	{
118		free(sictx);
119		si_item_release(item);
120		return;
121	}
122
123	if (sictx->key_offset >= 0)
124	{
125		LI_set_thread_item(sictx->cat + sictx->key_offset, item);
126	}
127
128	res.x = NULL;
129	if (item != NULL) res.x = (char*)((uintptr_t)item + sizeof(si_item_t));
130
131	switch (sictx->cat)
132	{
133		case CATEGORY_USER:
134		{
135			((si_user_async_callback)(sictx->orig_callback))(res.u, sictx->orig_context);
136			break;
137		}
138		case CATEGORY_GROUP:
139		{
140			((si_group_async_callback)(sictx->orig_callback))(res.g, sictx->orig_context);
141			break;
142		}
143		case CATEGORY_GROUPLIST:
144		{
145			((si_grouplist_async_callback)(sictx->orig_callback))(res.l, sictx->orig_context);
146			break;
147		}
148		case CATEGORY_HOST_IPV4:
149		case CATEGORY_HOST_IPV6:
150		{
151			((si_host_async_callback)(sictx->orig_callback))(res.h, sictx->orig_context);
152			break;
153		}
154		case CATEGORY_NETWORK:
155		{
156			((si_network_async_callback)(sictx->orig_callback))(res.n, sictx->orig_context);
157			break;
158		}
159		case CATEGORY_SERVICE:
160		{
161			((si_service_async_callback)(sictx->orig_callback))(res.s, sictx->orig_context);
162			break;
163		}
164		case CATEGORY_PROTOCOL:
165		{
166			((si_protocol_async_callback)(sictx->orig_callback))(res.p, sictx->orig_context);
167			break;
168		}
169		case CATEGORY_RPC:
170		{
171			((si_rpc_async_callback)(sictx->orig_callback))(res.r, sictx->orig_context);
172			break;
173		}
174		case CATEGORY_FS:
175		{
176			((si_fs_async_callback)(sictx->orig_callback))(res.f, sictx->orig_context);
177			break;
178		}
179	}
180
181	free(sictx);
182}
183
184/* USER */
185
186struct passwd *
187getpwnam(const char *name)
188{
189	si_item_t *item;
190
191#ifdef CALL_TRACE
192	fprintf(stderr, "-> %s %s\n", __func__, name);
193#endif
194
195	item = si_user_byname(si_search(), name);
196	LI_set_thread_item(CATEGORY_USER + 100, item);
197
198	if (item == NULL) return NULL;
199	return (struct passwd *)((uintptr_t)item + sizeof(si_item_t));
200}
201
202mach_port_t
203getpwnam_async_call(const char *name, si_user_async_callback callback, void *context)
204{
205	si_context_t *sictx;
206
207#ifdef CALL_TRACE
208	fprintf(stderr, ">> %s %s\n", __func__, name);
209#endif
210
211	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
212	if (sictx == NULL) return MACH_PORT_NULL;
213
214	sictx->orig_callback = callback;
215	sictx->orig_context = context;
216	sictx->cat = CATEGORY_USER;
217	sictx->key_offset = 100;
218
219	return si_async_call(si_search(), SI_CALL_USER_BYNAME, name, NULL, NULL, 0, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
220}
221
222void
223getpwnam_async_handle_reply(mach_msg_header_t *msg)
224{
225#ifdef CALL_TRACE
226	fprintf(stderr, "<< %s\n", __func__);
227#endif
228
229	si_async_handle_reply(msg);
230}
231
232struct passwd *
233getpwuid(uid_t uid)
234{
235	si_item_t *item;
236
237#ifdef CALL_TRACE
238	fprintf(stderr, "-> %s %d\n", __func__, uid);
239#endif
240
241	item = si_user_byuid(si_search(), uid);
242	LI_set_thread_item(CATEGORY_USER + 200, item);
243
244	if (item == NULL) return NULL;
245	return (struct passwd *)((uintptr_t)item + sizeof(si_item_t));
246}
247
248mach_port_t
249getpwuid_async_call(uid_t uid, si_user_async_callback callback, void *context)
250{
251	si_context_t *sictx;
252
253#ifdef CALL_TRACE
254	fprintf(stderr, ">> %s %d\n", __func__, uid);
255#endif
256
257	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
258	if (sictx == NULL) return MACH_PORT_NULL;
259
260	sictx->orig_callback = callback;
261	sictx->orig_context = context;
262	sictx->cat = CATEGORY_USER;
263	sictx->key_offset = 200;
264
265	return si_async_call(si_search(), SI_CALL_USER_BYUID, NULL, NULL, NULL, (uint32_t)uid, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
266}
267
268void
269getpwuid_async_handle_reply(mach_msg_header_t *msg)
270{
271#ifdef CALL_TRACE
272	fprintf(stderr, "<< %s\n", __func__);
273#endif
274
275	si_async_handle_reply(msg);
276}
277
278struct passwd *
279getpwuuid(uuid_t uuid)
280{
281	si_item_t *item;
282
283#ifdef CALL_TRACE
284	uuid_string_t uuidstr;
285	uuid_unparse_upper(uuid, uuidstr);
286	fprintf(stderr, "-> %s %s\n", __func__, uuidstr);
287#endif
288
289	item = si_user_byuuid(si_search(), uuid);
290	LI_set_thread_item(CATEGORY_USER + 300, item);
291
292	if (item == NULL) return NULL;
293	return (struct passwd *)((uintptr_t)item + sizeof(si_item_t));
294}
295
296void
297setpwent(void)
298{
299#ifdef CALL_TRACE
300	fprintf(stderr, "-- %s\n", __func__);
301#endif
302
303	LI_set_thread_list(CATEGORY_USER, NULL);
304}
305
306struct passwd *
307getpwent(void)
308{
309	si_list_t *list;
310	si_item_t *item;
311
312#ifdef CALL_TRACE
313	fprintf(stderr, "-> %s\n", __func__);
314#endif
315
316	list = LI_get_thread_list(CATEGORY_USER);
317	if (list == NULL)
318	{
319		list = si_user_all(si_search());
320		LI_set_thread_list(CATEGORY_USER, list);
321	}
322
323	item = si_list_next(list);
324	if (item == NULL) return NULL;
325
326	return (struct passwd *)((uintptr_t)item + sizeof(si_item_t));
327}
328
329void
330endpwent(void)
331{
332#ifdef CALL_TRACE
333	fprintf(stderr, "-- %s\n", __func__);
334#endif
335
336	LI_set_thread_list(CATEGORY_USER, NULL);
337}
338
339int
340setpassent(int ignored)
341{
342	si_list_t *list;
343
344#ifdef CALL_TRACE
345	fprintf(stderr, "-> %s\n", __func__);
346#endif
347
348	list = LI_get_thread_list(CATEGORY_USER);
349	si_list_reset(list);
350
351	if (list == NULL) return 0;
352	return 1;
353}
354
355/* GROUP */
356
357struct group *
358getgrnam(const char *name)
359{
360	si_item_t *item;
361
362#ifdef CALL_TRACE
363	fprintf(stderr, "-> %s %s\n", __func__, name);
364#endif
365
366	item = si_group_byname(si_search(), name);
367	LI_set_thread_item(CATEGORY_GROUP + 100, item);
368
369	if (item == NULL) return NULL;
370	return (struct group *)((uintptr_t)item + sizeof(si_item_t));
371}
372
373mach_port_t
374getgrnam_async_call(const char *name, si_group_async_callback callback, void *context)
375{
376	si_context_t *sictx;
377
378#ifdef CALL_TRACE
379	fprintf(stderr, ">> %s %s\n", __func__, name);
380#endif
381
382	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
383	if (sictx == NULL) return MACH_PORT_NULL;
384
385	sictx->orig_callback = callback;
386	sictx->orig_context = context;
387	sictx->cat = CATEGORY_GROUP;
388	sictx->key_offset = 100;
389
390	return si_async_call(si_search(), SI_CALL_GROUP_BYNAME, name, NULL, NULL, 0, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
391}
392
393void
394getgrnam_async_handle_reply(mach_msg_header_t *msg)
395{
396#ifdef CALL_TRACE
397	fprintf(stderr, "<< %s\n", __func__);
398#endif
399
400	si_async_handle_reply(msg);
401}
402
403struct group *
404getgrgid(gid_t gid)
405{
406	si_item_t *item;
407
408#ifdef CALL_TRACE
409	fprintf(stderr, "-> %s %d\n", __func__, gid);
410#endif
411
412	item = si_group_bygid(si_search(), gid);
413	LI_set_thread_item(CATEGORY_GROUP + 200, item);
414
415	if (item == NULL) return NULL;
416	return (struct group *)((uintptr_t)item + sizeof(si_item_t));
417}
418
419mach_port_t
420getgrgid_async_call(gid_t gid, si_group_async_callback callback, void *context)
421{
422	si_context_t *sictx;
423
424#ifdef CALL_TRACE
425	fprintf(stderr, ">> %s %d\n", __func__, gid);
426#endif
427
428	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
429	if (sictx == NULL) return MACH_PORT_NULL;
430
431	sictx->orig_callback = callback;
432	sictx->orig_context = context;
433	sictx->cat = CATEGORY_GROUP;
434	sictx->key_offset = 200;
435
436	return si_async_call(si_search(), SI_CALL_GROUP_BYGID, NULL, NULL, NULL, (uint32_t)gid, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
437}
438
439void
440getgruid_async_handle_reply(mach_msg_header_t *msg)
441{
442#ifdef CALL_TRACE
443	fprintf(stderr, "<< %s\n", __func__);
444#endif
445
446	si_async_handle_reply(msg);
447}
448
449struct group *
450getgruuid(uuid_t uuid)
451{
452	si_item_t *item;
453
454#ifdef CALL_TRACE
455	uuid_string_t uuidstr;
456	uuid_unparse_upper(uuid, uuidstr);
457	fprintf(stderr, "-> %s %s\n", __func__, uuidstr);
458#endif
459
460	item = si_group_byuuid(si_search(), uuid);
461	LI_set_thread_item(CATEGORY_GROUP + 300, item);
462
463	if (item == NULL) return NULL;
464	return (struct group *)((uintptr_t)item + sizeof(si_item_t));
465}
466
467void
468setgrent(void)
469{
470#ifdef CALL_TRACE
471	fprintf(stderr, "-- %s\n", __func__);
472#endif
473
474	LI_set_thread_list(CATEGORY_GROUP, NULL);
475}
476
477struct group *
478getgrent(void)
479{
480	si_list_t *list;
481	si_item_t *item;
482
483#ifdef CALL_TRACE
484	fprintf(stderr, "-> %s\n", __func__);
485#endif
486
487	list = LI_get_thread_list(CATEGORY_GROUP);
488	if (list == NULL)
489	{
490		list = si_group_all(si_search());
491		LI_set_thread_list(CATEGORY_GROUP, list);
492	}
493
494	item = si_list_next(list);
495	if (item == NULL) return NULL;
496
497	return (struct group *)((uintptr_t)item + sizeof(si_item_t));
498}
499
500void
501endgrent(void)
502{
503#ifdef CALL_TRACE
504	fprintf(stderr, "-- %s\n", __func__);
505#endif
506
507	LI_set_thread_list(CATEGORY_GROUP, NULL);
508}
509
510int
511setgroupent(int ignored)
512{
513	si_list_t *list;
514
515#ifdef CALL_TRACE
516	fprintf(stderr, "-> %s\n", __func__);
517#endif
518
519	list = LI_get_thread_list(CATEGORY_GROUP);
520	si_list_reset(list);
521
522	if (list == NULL) return 0;
523	return 1;
524}
525
526/* NETGROUP */
527int
528innetgr(const char *group, const char *host, const char *user, const char *domain)
529{
530	int res;
531#ifdef CALL_TRACE
532	fprintf(stderr, "-> %s %s %s %s %s\n", __func__, group, host, user, domain);
533#endif
534
535	res = si_in_netgroup(si_search(), group, host, user, domain);
536
537#ifdef CALL_TRACE
538	fprintf(stderr, "<- %s %d\n", __func__, res);
539#endif
540
541	return res;
542}
543
544/* N.B. there is no async innetgr */
545
546/*
547 * setnetgrent is really more like a getXXXbyname routine than a
548 * setXXXent routine, since we are looking up a netgroup by name.
549 */
550void
551setnetgrent(const char *name)
552{
553	si_list_t *list;
554
555#ifdef CALL_TRACE
556	fprintf(stderr, "-> %s %s\n", __func__, name);
557#endif
558
559	list = si_netgroup_byname(si_search(), name);
560	LI_set_thread_list(CATEGORY_NETGROUP, list);
561}
562
563/* N.B. there is no async getnetgrent */
564
565int
566getnetgrent(char **host, char **user, char **domain)
567{
568	si_list_t *list;
569	si_item_t *item;
570	struct netgrent_s *ng;
571
572#ifdef CALL_TRACE
573	fprintf(stderr, "-> %s\n", __func__);
574#endif
575
576	list = LI_get_thread_list(CATEGORY_NETGROUP);
577	item = si_list_next(list);
578	if (item == NULL) return 0;
579
580	ng = (struct netgrent_s *)((uintptr_t)item + sizeof(si_item_t));
581
582	*host = ng->ng_host;
583	*user = ng->ng_user;
584	*domain = ng->ng_domain;
585
586	return 1;
587}
588
589void
590endnetgrent(void)
591{
592#ifdef CALL_TRACE
593	fprintf(stderr, "-- %s\n", __func__);
594#endif
595
596	LI_set_thread_list(CATEGORY_NETGROUP, NULL);
597}
598
599#if DS_AVAILABLE
600static void
601_check_groups(const char *function, int32_t ngroups)
602{
603	static dispatch_once_t once;
604
605	if (ngroups > 0 && ngroups < NGROUPS_MAX) {
606		return;
607	}
608
609	/* only log once per process */
610	dispatch_once(&once, ^(void) {
611		const char *proc_name = getprogname();
612		if (strcmp(proc_name, "id") != 0 && strcmp(proc_name, "smbd") != 0 && strcmp(proc_name, "rpcsvchost") != 0) {
613			aslmsg msg = asl_new(ASL_TYPE_MSG);
614			char buffer[256];
615
616			snprintf(buffer, sizeof(buffer), "%d", (ngroups == 0 ? INT_MAX : ngroups));
617			asl_set(msg, "com.apple.message.value", buffer);
618
619			asl_set(msg, "com.apple.message.domain", "com.apple.system.libinfo");
620			asl_set(msg, "com.apple.message.result", "noop");
621			asl_set(msg, "com.apple.message.signature", function);
622
623			asl_log(NULL, msg, ASL_LEVEL_NOTICE, "%s called triggering group enumeration", function);
624
625			asl_free(msg);
626		}
627	});
628}
629#endif
630
631/* GROUPLIST */
632
633static int
634getgrouplist_internal(const char *name, int basegid, gid_t *groups, uint32_t *ngroups)
635{
636	int i, j, x, g, add, max;
637	si_item_t *item;
638	si_grouplist_t *gl;
639
640	/*
641	 * On input, ngroups specifies the size of the groups array.
642	 * On output, it is set to the number of groups that are being returned.
643	 * Returns -1 if the size is too small to fit all the groups that were found.
644	 */
645
646#ifdef CALL_TRACE
647	fprintf(stderr, "-> %s %s %d\n", __func__, name, basegid);
648#endif
649
650	if (name == NULL) return 0;
651	if (groups == NULL) return 0;
652	if (ngroups == NULL) return 0;
653
654	max = (*ngroups);
655	*ngroups = 0;
656	if (max <= 0) return 0;
657
658	groups[0] = basegid;
659	*ngroups = 1;
660
661	item = si_grouplist(si_search(), name, max);
662	LI_set_thread_item(CATEGORY_GROUPLIST, item);
663	if (item == NULL) return 0;
664
665	gl = (si_grouplist_t *)((uintptr_t)item + sizeof(si_item_t));
666
667	x = 1;
668
669	for (i = 0; i < gl->gl_count; i++)
670	{
671		g = gl->gl_gid[i];
672		add = 1;
673		for (j = 0; j < x; j++) {
674			if (groups[j] == g) {
675				add = 0;
676				break;
677			}
678		}
679		if (add == 0) continue;
680
681		if (x >= max) return -1;
682		groups[x] = g;
683		x++;
684		*ngroups = x;
685	}
686
687	return 0;
688}
689
690int
691getgrouplist(const char *name, int basegid, int *groups, int *ngroups)
692{
693#if DS_AVAILABLE
694	_check_groups("getgrouplist", *ngroups);
695#endif
696
697	return getgrouplist_internal(name, basegid, (gid_t *)groups, (uint32_t *)ngroups);
698}
699
700static void
701merge_gid(gid_t *list, gid_t g, int32_t *count)
702{
703	int32_t cnt;
704	int i;
705
706	cnt = (*count);
707	for (i = 0; i < cnt; i++) {
708		if (list[i] == g) return;
709	}
710
711	list[cnt] = g;
712	(*count)++;
713}
714
715static int32_t
716_getgrouplist_2_internal(const char *name, gid_t basegid, gid_t **groups)
717{
718	int32_t i, count;
719	si_item_t *item;
720	gid_t *gids;
721	si_grouplist_t *gl;
722
723	item = si_grouplist(si_search(), name, INT_MAX);
724	LI_set_thread_item(CATEGORY_GROUPLIST, item);
725	if (item == NULL) return -1;
726
727	gl = (si_grouplist_t *) ((uintptr_t) item + sizeof(si_item_t));
728
729	/*
730	 * we can allocate enough up-front, we'll only use what we need
731	 * we add one to the count that was found in case the basegid is not there
732	 */
733	gids = calloc(gl->gl_count + 1, sizeof(gid_t));
734
735	count = 0;
736	merge_gid(gids, basegid, &count);
737	if (gl->gl_gid != NULL) {
738		for (i = 0; i < gl->gl_count; i++) {
739			merge_gid(gids, gl->gl_gid[i], &count);
740		}
741	}
742
743	(*groups) = gids;
744
745	return count;
746}
747
748int32_t
749getgrouplist_2(const char *name, gid_t basegid, gid_t **groups)
750{
751	/*
752	 * Passes back a gid_t list containing all the users groups (and basegid).
753	 * Caller must free the list.
754	 * Returns the number of gids in the list or -1 on failure.
755	 */
756
757#ifdef CALL_TRACE
758	fprintf(stderr, "-> %s %s %d\n", __func__, name, basegid);
759#endif
760
761	if (name == NULL) return 0;
762	if (groups == NULL) return 0;
763
764#if DS_AVAILABLE
765	_check_groups("getgrouplist_2", INT_MAX);
766#endif
767
768	return _getgrouplist_2_internal(name, basegid, groups);
769}
770
771int32_t
772getgroupcount(const char *name, gid_t basegid)
773{
774	int32_t count;
775	gid_t *groups;
776
777#ifdef CALL_TRACE
778	fprintf(stderr, "-> %s %s %d\n", __func__, name, basegid);
779#endif
780
781#if DS_AVAILABLE
782	_check_groups("getgroupcount", INT_MAX);
783#endif
784
785	groups = NULL;
786	count = _getgrouplist_2_internal(name, basegid, &groups);
787	if (groups != NULL) free(groups);
788
789	return count;
790}
791
792/* XXX to do: async getgrouplist_2 */
793
794int
795initgroups(const char *name, int basegid)
796{
797	int status;
798	uint32_t ngroups;
799	gid_t groups[NGROUPS];
800	uid_t uid;
801#ifdef DS_AVAILABLE
802	si_item_t *item;
803	struct passwd *p;
804#endif
805
806#ifdef CALL_TRACE
807	fprintf(stderr, "-> %s %s %d\n", __func__, name, basegid);
808#endif
809
810	/* KAUTH_UID_NONE tells the kernel not to fetch supplementary groups from DirectoryService */
811	uid = KAUTH_UID_NONE;
812
813#ifdef DS_AVAILABLE
814	/* get the UID for this user */
815	item = si_user_byname(si_search(), name);
816	if (item != NULL)
817	{
818		p = (struct passwd *)((uintptr_t)item + sizeof(si_item_t));
819		uid = p->pw_uid;
820		si_item_release(item);
821	}
822#endif
823
824	ngroups = NGROUPS;
825
826	/*
827	 * Ignore status.
828	 * A failure either means that user belongs to more than NGROUPS groups
829	 * or no groups at all.
830	 */
831
832	(void) getgrouplist_internal(name, basegid, groups, &ngroups);
833
834	status = __initgroups(ngroups, groups, uid);
835	if (status < 0) return -1;
836
837	return 0;
838}
839
840/* ALIAS */
841
842struct aliasent *
843alias_getbyname(const char *name)
844{
845	si_item_t *item;
846
847#ifdef CALL_TRACE
848	fprintf(stderr, "-> %s %s\n", __func__, name);
849#endif
850
851	item = si_alias_byname(si_search(), name);
852	LI_set_thread_item(CATEGORY_ALIAS + 100, item);
853	if (item == NULL) return NULL;
854
855	return (struct aliasent *)((uintptr_t)item + sizeof(si_item_t));
856}
857
858mach_port_t
859alias_getbyname_async_call(const char *name, si_alias_async_callback callback, void *context)
860{
861	si_context_t *sictx;
862
863#ifdef CALL_TRACE
864	fprintf(stderr, ">> %s %s\n", __func__, name);
865#endif
866
867	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
868	if (sictx == NULL) return MACH_PORT_NULL;
869
870	sictx->orig_callback = callback;
871	sictx->orig_context = context;
872	sictx->cat = CATEGORY_ALIAS;
873	sictx->key_offset = 100;
874
875	return si_async_call(si_search(), SI_CALL_ALIAS_BYNAME, name, NULL, NULL, 0, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
876}
877
878void
879alias_getbyname_async_handle_reply(mach_msg_header_t *msg)
880{
881#ifdef CALL_TRACE
882	fprintf(stderr, "<< %s\n", __func__);
883#endif
884
885	si_async_handle_reply(msg);
886}
887
888void
889alias_setent(void)
890{
891#ifdef CALL_TRACE
892	fprintf(stderr, "-> %s\n", __func__);
893#endif
894
895	LI_set_thread_list(CATEGORY_ALIAS, NULL);
896}
897
898struct aliasent *
899alias_getent(void)
900{
901	si_list_t *list;
902	si_item_t *item;
903
904#ifdef CALL_TRACE
905	fprintf(stderr, "-> %s\n", __func__);
906#endif
907
908	list = LI_get_thread_list(CATEGORY_ALIAS);
909	if (list == NULL)
910	{
911		list = si_alias_all(si_search());
912		LI_set_thread_list(CATEGORY_ALIAS, list);
913	}
914
915	item = si_list_next(list);
916	if (item == NULL) return NULL;
917
918	return (struct aliasent *)((uintptr_t)item + sizeof(si_item_t));
919}
920
921void
922alias_endent(void)
923{
924#ifdef CALL_TRACE
925	fprintf(stderr, "-- %s\n", __func__);
926#endif
927
928	LI_set_thread_list(CATEGORY_ALIAS, NULL);
929}
930
931/* HOST */
932
933void
934freehostent(struct hostent *h)
935{
936	if (h == NULL) return;
937
938	si_item_t *item = (si_item_t *)((uintptr_t)h - sizeof(si_item_t));
939	si_item_release(item);
940}
941
942struct hostent *
943gethostbynameerrno(const char *name, int *err)
944{
945	si_item_t *item;
946	uint32_t status;
947	struct in_addr addr4;
948
949#ifdef CALL_TRACE
950	fprintf(stderr, "-> %s %s\n", __func__, name);
951#endif
952
953	memset(&addr4, 0, sizeof(struct in_addr));
954	status = SI_STATUS_NO_ERROR;
955	item = NULL;
956
957	if (inet_aton(name, &addr4) == 1) item = si_ipnode_byname(si_search(), name, AF_INET, 0, NULL, &status);
958	else item = si_host_byname(si_search(), name, AF_INET, NULL, &status);
959
960	if (status >= SI_STATUS_INTERNAL) status = NO_RECOVERY;
961	if (err != NULL) *err = status;
962
963	LI_set_thread_item(CATEGORY_HOST + 100, item);
964	if (item == NULL) return NULL;
965
966	return (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
967}
968
969struct hostent *
970gethostbyname(const char *name)
971{
972	si_item_t *item;
973	uint32_t status;
974	struct in_addr addr4;
975
976#ifdef CALL_TRACE
977	fprintf(stderr, "-> %s %s\n", __func__, name);
978#endif
979
980	memset(&addr4, 0, sizeof(struct in_addr));
981	status = SI_STATUS_NO_ERROR;
982	item = NULL;
983
984	if (inet_aton(name, &addr4) == 1) item = si_ipnode_byname(si_search(), name, AF_INET, 0, NULL, &status);
985	else item = si_host_byname(si_search(), name, AF_INET, NULL, &status);
986
987	if (status >= SI_STATUS_INTERNAL) status = NO_RECOVERY;
988	h_errno = status;
989
990	LI_set_thread_item(CATEGORY_HOST + 100, item);
991	if (item == NULL) return NULL;
992
993	return (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
994}
995
996mach_port_t
997gethostbyname_async_call(const char *name, si_host_async_callback callback, void *context)
998{
999	si_context_t *sictx;
1000
1001#ifdef CALL_TRACE
1002	fprintf(stderr, ">> %s %s\n", __func__, name);
1003#endif
1004
1005	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
1006	if (sictx == NULL) return MACH_PORT_NULL;
1007
1008	sictx->orig_callback = callback;
1009	sictx->orig_context = context;
1010	sictx->cat = CATEGORY_HOST;
1011	sictx->key_offset = 100;
1012
1013	return si_async_call(si_search(), SI_CALL_HOST_BYNAME, name, NULL, NULL, AF_INET, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
1014}
1015
1016mach_port_t
1017gethostbyname_async_start(const char *name, si_host_async_callback callback, void *context)
1018{
1019	return gethostbyname_async_call(name, callback, context);
1020}
1021
1022void
1023gethostbyname_async_cancel(mach_port_t p)
1024{
1025#ifdef CALL_TRACE
1026	fprintf(stderr, "-- %s\n", __func__);
1027#endif
1028
1029	si_async_cancel(p);
1030}
1031
1032#if 0
1033void
1034gethostbyname_async_handle_reply(void *param)
1035{
1036	mach_msg_header_t *msg;
1037
1038#ifdef CALL_TRACE
1039	fprintf(stderr, "<< %s\n", __func__);
1040#endif
1041
1042	msg = (mach_msg_header_t *)param;
1043	si_async_handle_reply(msg);
1044}
1045#endif
1046
1047void
1048gethostbyname_async_handleReply(void *param)
1049{
1050	mach_msg_header_t *msg;
1051
1052#ifdef CALL_TRACE
1053	fprintf(stderr, "<< %s\n", __func__);
1054#endif
1055
1056	msg = (mach_msg_header_t *)param;
1057	si_async_handle_reply(msg);
1058}
1059
1060struct hostent *
1061gethostbyname2(const char *name, int af)
1062{
1063	si_item_t *item;
1064	uint32_t status;
1065	struct in_addr addr4;
1066	struct in6_addr addr6;
1067	si_mod_t *search = si_search();
1068
1069#ifdef CALL_TRACE
1070	fprintf(stderr, "-> %s %s %d\n", __func__, name, af);
1071#endif
1072
1073	memset(&addr4, 0, sizeof(struct in_addr));
1074	memset(&addr6, 0, sizeof(struct in6_addr));
1075	status = SI_STATUS_NO_ERROR;
1076	item = NULL;
1077
1078	if (((af == AF_INET) && (inet_aton(name, &addr4) == 1)) || ((af == AF_INET6) && (inet_pton(af, name, &addr6) == 1)))
1079	{
1080		item = si_ipnode_byname(search, name, (uint32_t)af, 0, NULL, &status);
1081	}
1082	else
1083	{
1084		item = si_host_byname(search, name, (uint32_t)af, NULL, &status);
1085	}
1086
1087	if (status >= SI_STATUS_INTERNAL) status = NO_RECOVERY;
1088	h_errno = status;
1089
1090	LI_set_thread_item(CATEGORY_HOST + 100, item);
1091	if (item == NULL) return NULL;
1092
1093	return (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
1094}
1095
1096mach_port_t
1097gethostbyname2_async_call(const char *name, int af, si_group_async_callback callback, void *context)
1098{
1099	si_context_t *sictx;
1100
1101#ifdef CALL_TRACE
1102	fprintf(stderr, ">> %s %s %d\n", __func__, name, af);
1103#endif
1104
1105	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
1106	if (sictx == NULL) return MACH_PORT_NULL;
1107
1108	sictx->orig_callback = callback;
1109	sictx->orig_context = context;
1110	sictx->cat = CATEGORY_HOST;
1111	sictx->key_offset = 100;
1112
1113	return si_async_call(si_search(), SI_CALL_HOST_BYNAME, name, NULL, NULL, (uint32_t)af, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
1114}
1115
1116void
1117gethostbyname2_async_cancel(mach_port_t p)
1118{
1119#ifdef CALL_TRACE
1120	fprintf(stderr, "-- %s\n", __func__);
1121#endif
1122
1123	si_async_cancel(p);
1124}
1125
1126void
1127gethostbyname2_async_handle_reply(mach_msg_header_t *msg)
1128{
1129#ifdef CALL_TRACE
1130	fprintf(stderr, "<< %s\n", __func__);
1131#endif
1132
1133	si_async_handle_reply(msg);
1134}
1135
1136struct hostent *
1137gethostbyaddr(const void *addr, socklen_t len, int type)
1138{
1139	si_item_t *item;
1140	uint32_t status;
1141
1142#ifdef CALL_TRACE
1143	fprintf(stderr, "-> %s %s\n", __func__, (type == AF_INET) ? inet_ntoa(*(struct in_addr *)addr) : "-IPv6-");
1144#endif
1145
1146	status = SI_STATUS_NO_ERROR;
1147
1148	item = si_host_byaddr(si_search(), addr, (uint32_t)type, NULL, &status);
1149	if (status >= SI_STATUS_INTERNAL) status = NO_RECOVERY;
1150	h_errno = status;
1151
1152	LI_set_thread_item(CATEGORY_HOST + 200, item);
1153	if (item == NULL) return NULL;
1154
1155	return (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
1156}
1157
1158mach_port_t
1159gethostbyaddr_async_call(const void *addr, socklen_t len, int type, si_host_async_callback callback, void *context)
1160{
1161	si_context_t *sictx;
1162	uint32_t addrlen;
1163
1164#ifdef CALL_TRACE
1165	fprintf(stderr, ">> %s %s\n", __func__, (type == AF_INET) ? inet_ntoa(*(struct in_addr *)addr) : "-IPv6-");
1166#endif
1167
1168	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
1169	if (sictx == NULL) return MACH_PORT_NULL;
1170
1171	sictx->orig_callback = callback;
1172	sictx->orig_context = context;
1173	sictx->cat = CATEGORY_HOST;
1174	sictx->key_offset = 200;
1175
1176	/* addr is not a C string - pass length in num3 */
1177	addrlen = len;
1178	return si_async_call(si_search(), SI_CALL_HOST_BYADDR, addr, NULL, NULL, (uint32_t)type, 0, addrlen, 0, (void *)si_libinfo_general_callback, sictx);
1179}
1180
1181mach_port_t
1182gethostbyaddr_async_start(const char *addr, int len, int family, si_host_async_callback callback, void *context)
1183{
1184	socklen_t slen = len;
1185
1186	return gethostbyaddr_async_call(addr, slen, family, callback, context);
1187}
1188
1189void
1190gethostbyaddr_async_cancel(mach_port_t p)
1191{
1192#ifdef CALL_TRACE
1193	fprintf(stderr, "-- %s\n", __func__);
1194#endif
1195
1196	si_async_cancel(p);
1197}
1198
1199#if 0
1200void
1201gethostbyaddr_async_handle_reply(void *param)
1202{
1203
1204	mach_msg_header_t *msg;
1205
1206#ifdef CALL_TRACE
1207	fprintf(stderr, "<< %s\n", __func__);
1208#endif
1209
1210	msg = (mach_msg_header_t *)param;
1211	si_async_handle_reply(msg);
1212}
1213#endif
1214
1215void
1216gethostbyaddr_async_handleReply(void *param)
1217{
1218	mach_msg_header_t *msg;
1219
1220#ifdef CALL_TRACE
1221	fprintf(stderr, "<< %s\n", __func__);
1222#endif
1223
1224	msg = (mach_msg_header_t *)param;
1225	si_async_handle_reply(msg);
1226}
1227
1228struct hostent *
1229getipnodebyname(const char *name, int family, int flags, int *err)
1230{
1231	si_item_t *item;
1232	uint32_t status;
1233
1234#ifdef CALL_TRACE
1235	fprintf(stderr, "-> %s %s %d 0x%08x\n", __func__, name, family, flags);
1236#endif
1237
1238	status = SI_STATUS_NO_ERROR;
1239
1240	item = si_ipnode_byname(si_search(), name, family, flags, NULL, &status);
1241	if (status >= SI_STATUS_INTERNAL) status = NO_RECOVERY;
1242	if (err != NULL) *err = status;
1243
1244	if (item == NULL) return NULL;
1245
1246	return (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
1247}
1248
1249#if 0
1250mach_port_t
1251getipnodebyname_async_call(const char *name, int family, int flags, int *err, si_host_async_callback callback, void *context)
1252{
1253	si_context_t *sictx;
1254
1255#ifdef CALL_TRACE
1256	fprintf(stderr, ">> %s %s %d 0x%08x\n", __func__, name, family, flags);
1257#endif
1258
1259	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
1260	if (sictx == NULL) return MACH_PORT_NULL;
1261
1262	sictx->orig_callback = callback;
1263	sictx->orig_context = context;
1264	sictx->cat = CATEGORY_HOST;
1265	sictx->key_offset = -1;
1266
1267	return si_async_call(si_search(), SI_CALL_IPNODE_BYNAME, name, NULL, NULL, (uint32_t)family, (uint32_t)flags, 0, 0, (void *)si_libinfo_general_callback, sictx);
1268}
1269
1270mach_port_t
1271getipnodebyname_async_start(const char *name, int family, int flags, int *err, si_host_async_callback callback, void *context)
1272{
1273	return getipnodebyname_async_call(name, family, flags, err, callback, context);
1274}
1275
1276void
1277getipnodebyname_async_cancel(mach_port_t p)
1278{
1279#ifdef CALL_TRACE
1280	fprintf(stderr, "-- %s\n", __func__);
1281#endif
1282
1283	si_async_cancel(p);
1284}
1285
1286void
1287getipnodebyname_async_handle_reply(mach_msg_header_t *msg)
1288{
1289#ifdef CALL_TRACE
1290	fprintf(stderr, "<< %s\n", __func__);
1291#endif
1292
1293	si_async_handle_reply(msg);
1294}
1295
1296void
1297getipnodebyname_async_handleReply(mach_msg_header_t *msg)
1298{
1299#ifdef CALL_TRACE
1300	fprintf(stderr, "<< %s\n", __func__);
1301#endif
1302
1303	si_async_handle_reply(msg);
1304}
1305#endif
1306
1307static int
1308is_a4_mapped(const char *s)
1309{
1310	int i;
1311	u_int8_t c;
1312
1313	if (s == NULL) return 0;
1314
1315	for (i = 0; i < 10; i++)
1316	{
1317		c = s[i];
1318		if (c != 0x0) return 0;
1319	}
1320
1321	for (i = 10; i < 12; i++)
1322	{
1323		c = s[i];
1324		if (c != 0xff) return 0;
1325	}
1326
1327	return 1;
1328}
1329
1330static int
1331is_a4_compat(const char *s)
1332{
1333	int i;
1334	u_int8_t c;
1335
1336	if (s == NULL) return 0;
1337
1338	for (i = 0; i < 12; i++)
1339	{
1340		c = s[i];
1341		if (c != 0x0) return 0;
1342	}
1343
1344	/* Check for :: and ::1 */
1345	for (i = 13; i < 15; i++)
1346	{
1347		/* anything non-zero in these 3 bytes means it's a V4 address */
1348		c = s[i];
1349		if (c != 0x0) return 1;
1350	}
1351
1352	/* Leading 15 bytes are all zero */
1353	c = s[15];
1354	if (c == 0x0) return 0;
1355	if (c == 0x1) return 0;
1356
1357	return 1;
1358}
1359
1360struct hostent *
1361getipnodebyaddr(const void *src, size_t len, int family, int *err)
1362{
1363	si_item_t *item;
1364
1365#ifdef CALL_TRACE
1366	fprintf(stderr, "-> %s %s\n", __func__, (family == AF_INET) ? inet_ntoa(*(struct in_addr *)src) : "-IPv6-");
1367#endif
1368
1369	if ((family == AF_INET6) && (len == IPV6_ADDR_LEN) && (is_a4_mapped((const char *)src) || is_a4_compat((const char *)src)))
1370	{
1371		src += 12;
1372		len = 4;
1373		family = AF_INET;
1374	}
1375
1376	item = si_host_byaddr(si_search(), src, family, NULL, (uint32_t *)err);
1377	if (item == NULL) return NULL;
1378
1379	return (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
1380}
1381
1382#if 0
1383static void
1384si_libinfo_ipnode_callback(si_item_t *item, uint32_t status, void *ctx)
1385{
1386	si_context_t *sictx;
1387	struct hostent *h;
1388
1389	if (ctx == NULL) return;
1390
1391	sictx = (si_context_t *)ctx;
1392
1393	if ((sictx->orig_callback == NULL) || (status == SI_STATUS_CALL_CANCELLED))
1394	{
1395		free(sictx);
1396		si_item_release(item);
1397		return;
1398	}
1399
1400	if (status >= SI_STATUS_INTERNAL) status = NO_RECOVERY;
1401
1402	if (item == NULL)
1403	{
1404		((si_ipnode_async_callback)(sictx->orig_callback))(NULL, status, sictx->orig_context);
1405		return;
1406	}
1407
1408	h = (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
1409	((si_ipnode_async_callback)(sictx->orig_callback))(h, status, sictx->orig_context);
1410
1411	free(sictx);
1412}
1413
1414mach_port_t
1415getipnodebyaddr_async_call(const void *src, socklen_t len, int family, int *err, si_ipnode_async_callback callback, void *context)
1416{
1417	si_context_t *sictx;
1418	uint32_t srclen;
1419
1420#ifdef CALL_TRACE
1421	fprintf(stderr, ">> %s %s\n", __func__, (family == AF_INET) ? inet_ntoa(*(struct in_addr *)src) : "-IPv6-");
1422#endif
1423
1424	if ((family == AF_INET6) && (len == IPV6_ADDR_LEN) && (is_a4_mapped((const char *)src) || is_a4_compat((const char *)src)))
1425	{
1426		src += 12;
1427		len = 4;
1428		family = AF_INET;
1429	}
1430
1431	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
1432	if (sictx == NULL) return MACH_PORT_NULL;
1433
1434	sictx->orig_callback = callback;
1435	sictx->orig_context = context;
1436	sictx->cat = CATEGORY_HOST;
1437	sictx->key_offset = -1;
1438
1439	/* src is not a C string - pass length in num3 */
1440	srclen = len;
1441	return si_async_call(si_search(), SI_CALL_HOST_BYADDR, src, NULL, NULL, (uint32_t)family, 0, srclen, 0, (void *)si_libinfo_ipnode_callback, sictx);
1442}
1443
1444mach_port_t
1445getipnodebyaddr_async_start(const void *addr, size_t len, int family, int *error, si_ipnode_async_callback callback, void *context)
1446{
1447	socklen_t slen = len;
1448
1449	return getipnodebyaddr_async_call(addr, slen, family, error, callback, context);
1450}
1451
1452void
1453getipnodebyaddr_async_cancel(mach_port_t p)
1454{
1455#ifdef CALL_TRACE
1456	fprintf(stderr, "-- %s\n", __func__);
1457#endif
1458
1459	si_async_cancel(p);
1460}
1461
1462void
1463getipnodebyaddr_async_handle_reply(mach_msg_header_t *msg)
1464{
1465#ifdef CALL_TRACE
1466	fprintf(stderr, "<< %s\n", __func__);
1467#endif
1468
1469	si_async_handle_reply(msg);
1470}
1471
1472void
1473getipnodebyaddr_async_handleReply(mach_msg_header_t *msg)
1474{
1475#ifdef CALL_TRACE
1476	fprintf(stderr, "<< %s\n", __func__);
1477#endif
1478
1479	si_async_handle_reply(msg);
1480}
1481#endif
1482
1483void
1484sethostent(int ignored)
1485{
1486#ifdef CALL_TRACE
1487	fprintf(stderr, "-- %s\n", __func__);
1488#endif
1489
1490	LI_set_thread_list(CATEGORY_HOST, NULL);
1491}
1492
1493struct hostent *
1494gethostent(void)
1495{
1496	si_list_t *list;
1497	si_item_t *item;
1498
1499#ifdef CALL_TRACE
1500	fprintf(stderr, "-> %s\n", __func__);
1501#endif
1502
1503	list = LI_get_thread_list(CATEGORY_HOST);
1504	if (list == NULL)
1505	{
1506		list = si_host_all(si_search());
1507		LI_set_thread_list(CATEGORY_HOST, list);
1508	}
1509
1510	item = si_list_next(list);
1511	if (item == NULL) return NULL;
1512
1513	return (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
1514}
1515
1516void
1517endhostent(void)
1518{
1519#ifdef CALL_TRACE
1520	fprintf(stderr, "-- %s\n", __func__);
1521#endif
1522
1523	LI_set_thread_list(CATEGORY_HOST, NULL);
1524}
1525
1526/* MAC ADDRESS */
1527
1528int
1529ether_hostton(const char *name, struct ether_addr *e)
1530{
1531	si_item_t *item;
1532	si_mac_t *mac;
1533	uint32_t t[6];
1534	int i;
1535
1536#ifdef CALL_TRACE
1537	fprintf(stderr, "-> %s %s\n", __func__, name);
1538#endif
1539
1540	if (name == NULL) return -1;
1541	if (e == NULL) return -1;
1542
1543	item = si_mac_byname(si_search(), name);
1544	LI_set_thread_item(CATEGORY_MAC + 100, item);
1545	if (item == NULL) return -1;
1546
1547	mac = (si_mac_t *)((uintptr_t)item + sizeof(si_item_t));
1548
1549	i = sscanf(mac->mac, " %x:%x:%x:%x:%x:%x", &t[0], &t[1], &t[2], &t[3], &t[4], &t[5]);
1550	if (i != 6) return -1;
1551
1552	for (i = 0; i < 6; i++) e->ether_addr_octet[i] = t[i];
1553	return 0;
1554}
1555
1556/* XXX to do? async ether_hostton */
1557
1558int
1559ether_ntohost(char *name, const struct ether_addr *e)
1560{
1561	si_item_t *item;
1562	si_mac_t *mac;
1563	uint32_t i, x[6];
1564	char str[256];
1565
1566	if (name == NULL) return -1;
1567	if (e == NULL) return -1;
1568
1569	for (i = 0; i < 6; i++) x[i] = e->ether_addr_octet[i];
1570	snprintf(str, sizeof(str), "%x:%x:%x:%x:%x:%x", x[0], x[1], x[2], x[3], x[4], x[5]);
1571
1572#ifdef CALL_TRACE
1573	fprintf(stderr, "-> %s %s\n", __func__, str);
1574#endif
1575
1576	item = si_mac_bymac(si_search(), str);
1577	LI_set_thread_item(CATEGORY_MAC + 200, item);
1578	if (item == NULL) return -1;
1579
1580	mac = (si_mac_t *)((uintptr_t)item + sizeof(si_item_t));
1581
1582	memcpy(name, mac->host, strlen(mac->host) + 1);
1583	return 0;
1584}
1585
1586/* XXX to do? async ether_ntohost */
1587
1588/* NETWORK */
1589
1590struct netent *
1591getnetbyname(const char *name)
1592{
1593	si_item_t *item;
1594
1595#ifdef CALL_TRACE
1596	fprintf(stderr, "-> %s %s\n", __func__, name);
1597#endif
1598
1599	item = si_network_byname(si_search(), name);
1600	LI_set_thread_item(CATEGORY_NETWORK + 100, item);
1601	if (item == NULL) return NULL;
1602
1603	return (struct netent *)((uintptr_t)item + sizeof(si_item_t));
1604}
1605
1606mach_port_t
1607getnetbyname_async_call(const char *name, si_network_async_callback callback, void *context)
1608{
1609	si_context_t *sictx;
1610
1611#ifdef CALL_TRACE
1612	fprintf(stderr, ">> %s %s\n", __func__, name);
1613#endif
1614
1615	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
1616	if (sictx == NULL) return MACH_PORT_NULL;
1617
1618	sictx->orig_callback = callback;
1619	sictx->orig_context = context;
1620	sictx->cat = CATEGORY_NETWORK;
1621	sictx->key_offset = 100;
1622
1623	return si_async_call(si_search(), SI_CALL_NETWORK_BYNAME, name, NULL, NULL, 0, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
1624}
1625
1626void
1627getnetbyname_async_handle_reply(mach_msg_header_t *msg)
1628{
1629#ifdef CALL_TRACE
1630	fprintf(stderr, "<< %s\n", __func__);
1631#endif
1632
1633	si_async_handle_reply(msg);
1634}
1635
1636struct netent *
1637getnetbyaddr(uint32_t net, int type)
1638{
1639	si_item_t *item;
1640
1641#ifdef CALL_TRACE
1642	fprintf(stderr, "-> %s 0x%08x\n", __func__, net);
1643#endif
1644
1645	if (type != AF_INET) return NULL;
1646
1647	item = si_network_byaddr(si_search(), net);
1648	LI_set_thread_item(CATEGORY_NETWORK + 200, item);
1649	if (item == NULL) return NULL;
1650
1651	return (struct netent *)((uintptr_t)item + sizeof(si_item_t));
1652}
1653
1654mach_port_t
1655getnetbyaddr_async_call(uint32_t net, int type, si_group_async_callback callback, void *context)
1656{
1657	si_context_t *sictx;
1658
1659#ifdef CALL_TRACE
1660	fprintf(stderr, ">> %s 0x%08x\n", __func__, net);
1661#endif
1662
1663	if (type != AF_INET) return MACH_PORT_NULL;
1664
1665	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
1666	if (sictx == NULL) return MACH_PORT_NULL;
1667
1668	sictx->orig_callback = callback;
1669	sictx->orig_context = context;
1670	sictx->cat = CATEGORY_NETWORK;
1671	sictx->key_offset = 200;
1672
1673	return si_async_call(si_search(), SI_CALL_NETWORK_BYADDR, NULL, NULL, NULL, net, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
1674}
1675
1676void
1677getnetbyaddr_async_handle_reply(mach_msg_header_t *msg)
1678{
1679#ifdef CALL_TRACE
1680	fprintf(stderr, "<< %s\n", __func__);
1681#endif
1682
1683	si_async_handle_reply(msg);
1684}
1685
1686void
1687setnetent(int ignored)
1688{
1689#ifdef CALL_TRACE
1690	fprintf(stderr, "-- %s\n", __func__);
1691#endif
1692
1693	LI_set_thread_list(CATEGORY_NETWORK, NULL);
1694}
1695
1696struct netent *
1697getnetent(void)
1698{
1699	si_list_t *list;
1700	si_item_t *item;
1701
1702#ifdef CALL_TRACE
1703	fprintf(stderr, "-> %s\n", __func__);
1704#endif
1705
1706	list = LI_get_thread_list(CATEGORY_NETWORK);
1707	if (list == NULL)
1708	{
1709		list = si_network_all(si_search());
1710		LI_set_thread_list(CATEGORY_NETWORK, list);
1711	}
1712
1713	item = si_list_next(list);
1714	if (item == NULL) return NULL;
1715
1716	return (struct netent *)((uintptr_t)item + sizeof(si_item_t));
1717}
1718
1719void
1720endnetent(void)
1721{
1722#ifdef CALL_TRACE
1723	fprintf(stderr, "-- %s\n", __func__);
1724#endif
1725
1726	LI_set_thread_list(CATEGORY_NETWORK, NULL);
1727}
1728
1729/* SERVICE */
1730
1731struct servent *
1732getservbyname(const char *name, const char *proto)
1733{
1734	si_item_t *item;
1735
1736#ifdef CALL_TRACE
1737	fprintf(stderr, "-> %s %s %s\n", __func__, name, proto);
1738#endif
1739
1740	item = si_service_byname(si_search(), name, proto);
1741	LI_set_thread_item(CATEGORY_SERVICE + 100, item);
1742	if (item == NULL) return NULL;
1743
1744	return (struct servent *)((uintptr_t)item + sizeof(si_item_t));
1745}
1746
1747mach_port_t
1748getservbyname_async_call(const char *name, const char *proto, si_service_async_callback callback, void *context)
1749{
1750	si_context_t *sictx;
1751
1752#ifdef CALL_TRACE
1753	fprintf(stderr, ">> %s %s %s\n", __func__, name, proto);
1754#endif
1755
1756	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
1757	if (sictx == NULL) return MACH_PORT_NULL;
1758
1759	sictx->orig_callback = callback;
1760	sictx->orig_context = context;
1761	sictx->cat = CATEGORY_SERVICE;
1762	sictx->key_offset = 100;
1763
1764	return si_async_call(si_search(), SI_CALL_SERVICE_BYNAME, name, proto, NULL, 0, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
1765}
1766
1767void
1768getservbyname_async_handle_reply(mach_msg_header_t *msg)
1769{
1770#ifdef CALL_TRACE
1771	fprintf(stderr, "<< %s\n", __func__);
1772#endif
1773
1774	si_async_handle_reply(msg);
1775}
1776
1777struct servent *
1778getservbyport(int port, const char *proto)
1779{
1780	si_item_t *item;
1781
1782#ifdef CALL_TRACE
1783	fprintf(stderr, "-> %s %d %s\n", __func__, ntohs((uint16_t)port), proto);
1784#endif
1785
1786	item = si_service_byport(si_search(), port, proto);
1787	LI_set_thread_item(CATEGORY_SERVICE + 200, item);
1788	if (item == NULL) return NULL;
1789
1790	return (struct servent *)((uintptr_t)item + sizeof(si_item_t));
1791}
1792
1793mach_port_t
1794getservbyport_async_call(int port, const char *proto, si_group_async_callback callback, void *context)
1795{
1796	si_context_t *sictx;
1797
1798#ifdef CALL_TRACE
1799	fprintf(stderr, ">> %s %d %s\n", __func__, port, proto);
1800#endif
1801
1802	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
1803	if (sictx == NULL) return MACH_PORT_NULL;
1804
1805	sictx->orig_callback = callback;
1806	sictx->orig_context = context;
1807	sictx->cat = CATEGORY_SERVICE;
1808	sictx->key_offset = 200;
1809
1810	return si_async_call(si_search(), SI_CALL_SERVICE_BYPORT, NULL, proto, NULL, port, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
1811}
1812
1813void
1814getservbyport_async_handle_reply(mach_msg_header_t *msg)
1815{
1816#ifdef CALL_TRACE
1817	fprintf(stderr, "<< %s\n", __func__);
1818#endif
1819
1820	si_async_handle_reply(msg);
1821}
1822
1823void
1824setservent(int ignored)
1825{
1826#ifdef CALL_TRACE
1827	fprintf(stderr, "-- %s\n", __func__);
1828#endif
1829
1830	LI_set_thread_list(CATEGORY_SERVICE, NULL);
1831}
1832
1833struct servent *
1834getservent(void)
1835{
1836	si_list_t *list;
1837	si_item_t *item;
1838
1839#ifdef CALL_TRACE
1840	fprintf(stderr, "-> %s\n", __func__);
1841#endif
1842
1843	list = LI_get_thread_list(CATEGORY_SERVICE);
1844	if (list == NULL)
1845	{
1846		list = si_service_all(si_search());
1847		LI_set_thread_list(CATEGORY_SERVICE, list);
1848	}
1849
1850	item = si_list_next(list);
1851	if (item == NULL) return NULL;
1852
1853	return (struct servent *)((uintptr_t)item + sizeof(si_item_t));
1854}
1855
1856void
1857endservent(void)
1858{
1859#ifdef CALL_TRACE
1860	fprintf(stderr, "-- %s\n", __func__);
1861#endif
1862
1863	LI_set_thread_list(CATEGORY_SERVICE, NULL);
1864}
1865
1866/* PROTOCOL */
1867
1868struct protoent *
1869getprotobyname(const char *name)
1870{
1871	si_item_t *item;
1872
1873#ifdef CALL_TRACE
1874	fprintf(stderr, "-> %s %s\n", __func__, name);
1875#endif
1876
1877	item = si_protocol_byname(si_search(), name);
1878	LI_set_thread_item(CATEGORY_PROTOCOL + 100, item);
1879	if (item == NULL) return NULL;
1880
1881	return (struct protoent *)((uintptr_t)item + sizeof(si_item_t));
1882}
1883
1884mach_port_t
1885getprotobyname_async_call(const char *name, si_protocol_async_callback callback, void *context)
1886{
1887	si_context_t *sictx;
1888
1889#ifdef CALL_TRACE
1890	fprintf(stderr, ">> %s %s\n", __func__, name);
1891#endif
1892
1893	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
1894	if (sictx == NULL) return MACH_PORT_NULL;
1895
1896	sictx->orig_callback = callback;
1897	sictx->orig_context = context;
1898	sictx->cat = CATEGORY_PROTOCOL;
1899	sictx->key_offset = 100;
1900
1901	return si_async_call(si_search(), SI_CALL_PROTOCOL_BYNAME, name, NULL, NULL, 0, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
1902}
1903
1904void
1905getprotobyname_async_handle_reply(mach_msg_header_t *msg)
1906{
1907#ifdef CALL_TRACE
1908	fprintf(stderr, "<< %s\n", __func__);
1909#endif
1910
1911	si_async_handle_reply(msg);
1912}
1913
1914struct protoent *
1915getprotobynumber(int number)
1916{
1917	si_item_t *item;
1918
1919#ifdef CALL_TRACE
1920	fprintf(stderr, "-> %s %d\n", __func__, number);
1921#endif
1922
1923	item = si_protocol_bynumber(si_search(), number);
1924	LI_set_thread_item(CATEGORY_PROTOCOL + 200, item);
1925	if (item == NULL) return NULL;
1926
1927	return (struct protoent *)((uintptr_t)item + sizeof(si_item_t));
1928}
1929
1930mach_port_t
1931getprotobynumber_async_call(int number, si_group_async_callback callback, void *context)
1932{
1933	si_context_t *sictx;
1934
1935#ifdef CALL_TRACE
1936	fprintf(stderr, ">> %s %d\n", __func__, number);
1937#endif
1938
1939	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
1940	if (sictx == NULL) return MACH_PORT_NULL;
1941
1942	sictx->orig_callback = callback;
1943	sictx->orig_context = context;
1944	sictx->cat = CATEGORY_PROTOCOL;
1945	sictx->key_offset = 200;
1946
1947	return si_async_call(si_search(), SI_CALL_PROTOCOL_BYNUMBER, NULL, NULL, NULL, number, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
1948}
1949
1950void
1951getprotobynumber_async_handle_reply(mach_msg_header_t *msg)
1952{
1953#ifdef CALL_TRACE
1954	fprintf(stderr, "<< %s\n", __func__);
1955#endif
1956
1957	si_async_handle_reply(msg);
1958}
1959
1960void
1961setprotoent(int ignored)
1962{
1963#ifdef CALL_TRACE
1964	fprintf(stderr, "-- %s\n", __func__);
1965#endif
1966
1967	LI_set_thread_list(CATEGORY_PROTOCOL, NULL);
1968}
1969
1970struct protoent *
1971getprotoent(void)
1972{
1973	si_list_t *list;
1974	si_item_t *item;
1975
1976#ifdef CALL_TRACE
1977	fprintf(stderr, "-> %s\n", __func__);
1978#endif
1979
1980	list = LI_get_thread_list(CATEGORY_PROTOCOL);
1981	if (list == NULL)
1982	{
1983		list = si_protocol_all(si_search());
1984		LI_set_thread_list(CATEGORY_PROTOCOL, list);
1985	}
1986
1987	item = si_list_next(list);
1988	if (item == NULL) return NULL;
1989
1990	return (struct protoent *)((uintptr_t)item + sizeof(si_item_t));
1991}
1992
1993void
1994endprotoent(void)
1995{
1996#ifdef CALL_TRACE
1997	fprintf(stderr, "-- %s\n", __func__);
1998#endif
1999
2000	LI_set_thread_list(CATEGORY_PROTOCOL, NULL);
2001}
2002
2003/* RPC */
2004
2005struct rpcent *
2006getrpcbyname(const char *name)
2007{
2008	si_item_t *item;
2009
2010#ifdef CALL_TRACE
2011	fprintf(stderr, "-> %s %s\n", __func__, name);
2012#endif
2013
2014	item = si_rpc_byname(si_search(), name);
2015	LI_set_thread_item(CATEGORY_RPC + 100, item);
2016	if (item == NULL) return NULL;
2017
2018	return (struct rpcent *)((uintptr_t)item + sizeof(si_item_t));
2019}
2020
2021mach_port_t
2022getrpcbyname_async_call(const char *name, si_rpc_async_callback callback, void *context)
2023{
2024	si_context_t *sictx;
2025
2026#ifdef CALL_TRACE
2027	fprintf(stderr, ">> %s %s\n", __func__, name);
2028#endif
2029
2030	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
2031	if (sictx == NULL) return MACH_PORT_NULL;
2032
2033	sictx->orig_callback = callback;
2034	sictx->orig_context = context;
2035	sictx->cat = CATEGORY_RPC;
2036	sictx->key_offset = 100;
2037
2038	return si_async_call(si_search(), SI_CALL_RPC_BYNAME, name, NULL, NULL, 0, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
2039}
2040
2041void
2042getrpcbyname_async_handle_reply(mach_msg_header_t *msg)
2043{
2044#ifdef CALL_TRACE
2045	fprintf(stderr, "<< %s\n", __func__);
2046#endif
2047
2048	si_async_handle_reply(msg);
2049}
2050
2051struct rpcent *
2052getrpcbynumber
2053(
2054#ifdef __LP64__
2055	int number
2056#else
2057	long number
2058#endif
2059)
2060{
2061	si_item_t *item;
2062
2063#ifdef CALL_TRACE
2064	fprintf(stderr, "-> %s %ld\n", __func__, (long int)number);
2065#endif
2066
2067	item = si_rpc_bynumber(si_search(), number);
2068	LI_set_thread_item(CATEGORY_RPC + 200, item);
2069	if (item == NULL) return NULL;
2070
2071	return (struct rpcent *)((uintptr_t)item + sizeof(si_item_t));
2072}
2073
2074mach_port_t
2075getrpcbynumber_async_call(int number, si_group_async_callback callback, void *context)
2076{
2077	si_context_t *sictx;
2078
2079#ifdef CALL_TRACE
2080	fprintf(stderr, ">> %s %d\n", __func__, number);
2081#endif
2082
2083	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
2084	if (sictx == NULL) return MACH_PORT_NULL;
2085
2086	sictx->orig_callback = callback;
2087	sictx->orig_context = context;
2088	sictx->cat = CATEGORY_RPC;
2089	sictx->key_offset = 200;
2090
2091	return si_async_call(si_search(), SI_CALL_RPC_BYNUMBER, NULL, NULL, NULL, number, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
2092}
2093
2094void
2095getrpcbynumber_async_handle_reply(mach_msg_header_t *msg)
2096{
2097#ifdef CALL_TRACE
2098	fprintf(stderr, "<< %s\n", __func__);
2099#endif
2100
2101	si_async_handle_reply(msg);
2102}
2103
2104void
2105setrpcent(int ignored)
2106{
2107#ifdef CALL_TRACE
2108	fprintf(stderr, "-- %s\n", __func__);
2109#endif
2110
2111	LI_set_thread_list(CATEGORY_RPC, NULL);
2112}
2113
2114struct rpcent *
2115getrpcent(void)
2116{
2117	si_list_t *list;
2118	si_item_t *item;
2119
2120#ifdef CALL_TRACE
2121	fprintf(stderr, "-> %s\n", __func__);
2122#endif
2123
2124	list = LI_get_thread_list(CATEGORY_RPC);
2125	if (list == NULL)
2126	{
2127		list = si_rpc_all(si_search());
2128		LI_set_thread_list(CATEGORY_RPC, list);
2129	}
2130
2131	item = si_list_next(list);
2132	if (item == NULL) return NULL;
2133
2134	return (struct rpcent *)((uintptr_t)item + sizeof(si_item_t));
2135}
2136
2137void
2138endrpcent(void)
2139{
2140#ifdef CALL_TRACE
2141	fprintf(stderr, "-- %s\n", __func__);
2142#endif
2143
2144	LI_set_thread_list(CATEGORY_RPC, NULL);
2145}
2146
2147/* FS */
2148
2149struct fstab *
2150getfsspec(const char *spec)
2151{
2152	si_item_t *item;
2153
2154#ifdef CALL_TRACE
2155	fprintf(stderr, "-> %s %s\n", __func__, spec);
2156#endif
2157
2158	item = si_fs_byspec(si_search(), spec);
2159	LI_set_thread_item(CATEGORY_FS + 100, item);
2160	if (item == NULL) return NULL;
2161
2162	return (struct fstab *)((uintptr_t)item + sizeof(si_item_t));
2163}
2164
2165struct fstab *
2166getfsbyname(const char *name)
2167{
2168#ifdef CALL_TRACE
2169	fprintf(stderr, "-> %s %s\n", __func__, name);
2170#endif
2171
2172	return getfsspec(name);
2173}
2174
2175mach_port_t
2176getfsspec_async_call(const char *spec, si_fs_async_callback callback, void *context)
2177{
2178	si_context_t *sictx;
2179
2180#ifdef CALL_TRACE
2181	fprintf(stderr, ">> %s %s\n", __func__, spec);
2182#endif
2183
2184	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
2185	if (sictx == NULL) return MACH_PORT_NULL;
2186
2187	sictx->orig_callback = callback;
2188	sictx->orig_context = context;
2189	sictx->cat = CATEGORY_FS;
2190	sictx->key_offset = 100;
2191
2192	return si_async_call(si_search(), SI_CALL_FS_BYSPEC, spec, NULL, NULL, 0, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
2193}
2194
2195void
2196getfsspec_async_handle_reply(mach_msg_header_t *msg)
2197{
2198#ifdef CALL_TRACE
2199	fprintf(stderr, "<< %s\n", __func__);
2200#endif
2201
2202	si_async_handle_reply(msg);
2203}
2204
2205struct fstab *
2206getfsfile(const char *file)
2207{
2208	si_item_t *item;
2209
2210#ifdef CALL_TRACE
2211	fprintf(stderr, "-> %s %s\n", __func__, file);
2212#endif
2213
2214	item = si_fs_byfile(si_search(), file);
2215	LI_set_thread_item(CATEGORY_FS + 200, item);
2216	if (item == NULL) return NULL;
2217
2218	return (struct fstab *)((uintptr_t)item + sizeof(si_item_t));
2219}
2220
2221mach_port_t
2222getfsfile_async_call(const char *file, si_fs_async_callback callback, void *context)
2223{
2224	si_context_t *sictx;
2225
2226#ifdef CALL_TRACE
2227	fprintf(stderr, ">> %s %s\n", __func__, file);
2228#endif
2229
2230	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
2231	if (sictx == NULL) return MACH_PORT_NULL;
2232
2233	sictx->orig_callback = callback;
2234	sictx->orig_context = context;
2235	sictx->cat = CATEGORY_FS;
2236	sictx->key_offset = 200;
2237
2238	return si_async_call(si_search(), SI_CALL_FS_BYFILE, file, NULL, NULL, 0, 0, 0, 0, (void *)si_libinfo_general_callback, sictx);
2239}
2240
2241void
2242getfsfile_async_handle_reply(mach_msg_header_t *msg)
2243{
2244#ifdef CALL_TRACE
2245	fprintf(stderr, "<< %s\n", __func__);
2246#endif
2247
2248	si_async_handle_reply(msg);
2249}
2250
2251int
2252setfsent(void)
2253{
2254#ifdef CALL_TRACE
2255	fprintf(stderr, "-> %s\n", __func__);
2256#endif
2257
2258	LI_set_thread_list(CATEGORY_FS, NULL);
2259	return 1;
2260}
2261
2262struct fstab *
2263getfsent(void)
2264{
2265	si_list_t *list;
2266	si_item_t *item;
2267
2268#ifdef CALL_TRACE
2269	fprintf(stderr, "-> %s\n", __func__);
2270#endif
2271
2272	list = LI_get_thread_list(CATEGORY_FS);
2273	if (list == NULL)
2274	{
2275		list = si_fs_all(si_search());
2276		LI_set_thread_list(CATEGORY_FS, list);
2277	}
2278
2279	item = si_list_next(list);
2280	if (item == NULL) return NULL;
2281
2282	return (struct fstab *)((uintptr_t)item + sizeof(si_item_t));
2283}
2284
2285void
2286endfsent(void)
2287{
2288#ifdef CALL_TRACE
2289	fprintf(stderr, "-- %s\n", __func__);
2290#endif
2291
2292	LI_set_thread_list(CATEGORY_FS, NULL);
2293}
2294
2295/* GETADDRINFO */
2296
2297static int
2298_getaddrinfo_internal(const char *nodename, const char *servname, const struct addrinfo *hints, const char *interface, struct addrinfo **res)
2299{
2300	si_list_t *list;
2301	uint32_t family, socktype, protocol, flags, status;
2302	struct addrinfo *ai;
2303
2304	family = AF_UNSPEC;
2305	socktype = SOCK_UNSPEC;
2306	protocol = IPPROTO_UNSPEC;
2307	flags = 0;
2308	status = SI_STATUS_NO_ERROR;
2309
2310	if (res == NULL) return 0;
2311	*res = NULL;
2312
2313	if (hints != NULL)
2314	{
2315		family = hints->ai_family;
2316		socktype = hints->ai_socktype;
2317		protocol = hints->ai_protocol;
2318		flags = hints->ai_flags;
2319	}
2320
2321#ifdef CALL_TRACE
2322	fprintf(stderr, "-> %s %s %s %u %u %u 0x%08x %s\n", __func__, nodename, servname, family, socktype, protocol, flags, (interface == NULL) ? "" : interface);
2323#endif
2324
2325	list = si_addrinfo(si_search(), nodename, servname, family, socktype, protocol, flags, interface, &status);
2326	if ((status != SI_STATUS_NO_ERROR) || (list == NULL) || (list->count == 0))
2327	{
2328		si_list_release(list);
2329
2330		if (status == SI_STATUS_NO_ERROR) return EAI_NONAME;
2331		else if (status <= SI_STATUS_EAI_PLUS_100) status = EAI_FAIL;
2332		else if (status >= SI_STATUS_ERRNO_PLUS_200) status = EAI_FAIL;
2333		else status = status - SI_STATUS_EAI_PLUS_100;
2334		return status;
2335	}
2336
2337	*res = si_list_to_addrinfo(list);
2338	si_list_release(list);
2339	if (*res == NULL) status = EAI_MEMORY;
2340
2341	/* don't return the canonical name unless asked */
2342	if ((flags & AI_CANONNAME) == 0)
2343	{
2344		for (ai = *res; ai != NULL; ai = ai->ai_next)
2345		{
2346			free(ai->ai_canonname);
2347			ai->ai_canonname = NULL;
2348		}
2349	}
2350
2351	return status;
2352}
2353
2354int
2355getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res)
2356{
2357	return _getaddrinfo_internal(nodename, servname, hints, NULL, res);
2358}
2359
2360#ifdef CALL_TRACE
2361
2362static char *
2363socket_name(int sock)
2364{
2365	static char str[16];
2366
2367	switch(sock)
2368	{
2369		case SOCK_UNSPEC: return "SOCK_UNSPEC";
2370		case SOCK_STREAM: return "SOCK_STREAM";
2371		case SOCK_DGRAM: return "SOCK_DGRAM";
2372	}
2373
2374	sprintf(str, "%d", sock);
2375	return str;
2376}
2377
2378static char *
2379family_name(int pf)
2380{
2381	static char str[16];
2382
2383	switch(pf)
2384	{
2385		case PF_UNSPEC: return "PF_UNSPEC";
2386		case PF_INET: return "PF_INET";
2387		case PF_INET6: return "PF_INET6";
2388	};
2389
2390	sprintf(str, "%d", pf);
2391	return str;
2392}
2393
2394static char *
2395protocol_name(int p)
2396{
2397	static char str[16];
2398
2399	switch(p)
2400	{
2401		case IPPROTO_UNSPEC: return "IPPROTO_UNSPEC";
2402		case IPPROTO_TCP: return "IPPROTO_TCP";
2403		case IPPROTO_UDP: return "IPPROTO_UDP";
2404	}
2405
2406	sprintf(str, "%d", p);
2407	return str;
2408}
2409
2410static char *
2411_gai_inet_ntop(struct in6_addr a)
2412{
2413	static char buf[128];
2414	char t[32];
2415	unsigned short x;
2416	char *p;
2417	int i;
2418
2419	memset(buf, 0, 128);
2420
2421	p = (char *)&a.__u6_addr.__u6_addr32;
2422	for (i = 0; i < 8; i++, x += 1)
2423	{
2424		memmove(&x, p, 2);
2425		p += 2;
2426		sprintf(t, "%hx", x);
2427		strcat(buf, t);
2428		if (i < 7) strcat(buf, ":");
2429	}
2430
2431	return buf;
2432}
2433
2434static void
2435fprint_addrinfo(FILE *f, struct addrinfo *a)
2436{
2437	int i;
2438	unsigned char v;
2439	struct sockaddr_in *s4;
2440	struct sockaddr_in6 *s6;
2441
2442	if (a == NULL) return;
2443
2444	if (a->ai_flags != 0)
2445	{
2446		fprintf(f, "flags =");
2447		if (a->ai_flags & AI_PASSIVE) fprintf(f, " AI_PASSIVE");
2448		if (a->ai_flags & AI_CANONNAME) fprintf(f, " AI_CANONNAME");
2449		if (a->ai_flags & AI_NUMERICHOST) fprintf(f, " AI_NUMERICHOST");
2450		if (a->ai_flags & AI_NUMERICSERV) fprintf(f, " AI_NUMERICSERV");
2451		fprintf(f, "\n");
2452	}
2453
2454	fprintf(f, "family = %s\n", family_name(a->ai_family));
2455	fprintf(f, "socktype = %s\n", socket_name(a->ai_socktype));
2456	fprintf(f, "protocol = %s\n", protocol_name(a->ai_protocol));
2457
2458	fprintf(f, "canonical name = ");
2459	if (a->ai_canonname == NULL) fprintf(f, "NULL\n");
2460	else fprintf(f, "\"%s\"\n", a->ai_canonname);
2461
2462	fprintf(f, "addrlen = %ld\n", (long int)a->ai_addrlen);
2463
2464	if (a->ai_addr == NULL) fprintf(f, "sockaddr = NULL\n");
2465	else
2466	{
2467		if (a->ai_family == PF_INET)
2468		{
2469			s4 = (struct sockaddr_in *)a->ai_addr;
2470
2471			fprintf(f, "sockaddr_in len = %d\n", s4->sin_len);
2472			fprintf(f, "sockaddr_in family = %s\n", family_name(s4->sin_family));
2473			fprintf(f, "sockaddr_in port = %hu\n", ntohs(s4->sin_port));
2474			fprintf(f, "sockaddr_in address = %s\n", inet_ntoa(s4->sin_addr));
2475		}
2476		else if (a->ai_family == PF_INET6)
2477		{
2478			s6 = (struct sockaddr_in6 *)a->ai_addr;
2479
2480			fprintf(f, "sockaddr_in6 len = %d\n", s6->sin6_len);
2481			fprintf(f, "sockaddr_in6 family = %s\n", family_name(s6->sin6_family));
2482			fprintf(f, "sockaddr_in6 port = %hu\n", ntohs(s6->sin6_port));
2483			fprintf(f, "sockaddr_in6 flowinfo = %d\n", s6->sin6_flowinfo);
2484			fprintf(f, "sockaddr_in6 address = %s\n", _gai_inet_ntop(s6->sin6_addr));
2485			fprintf(f, "sockaddr_in6 scope_id = %d\n", s6->sin6_scope_id);
2486		}
2487		else
2488		{
2489			fprintf(f, "sockaddr len = %d\n", a->ai_addr->sa_len);
2490			fprintf(f, "sockaddr family = %s\n", family_name(a->ai_addr->sa_family));
2491			fprintf(f, "sockaddr data = ");
2492			for (i = 0; i < a->ai_addr->sa_len - 2; i++)
2493			{
2494				v = a->ai_addr->sa_data[i];
2495				fprintf(f, "%02x", v);
2496			}
2497			fprintf(f, "\n");
2498		}
2499	}
2500
2501	if (a->ai_next != NULL)
2502	{
2503		fprintf(f, "NEXT --->\n");
2504		fprint_addrinfo(f, a->ai_next);
2505	}
2506}
2507
2508#endif
2509
2510static void
2511si_libinfo_addrinfo_callback(si_list_t *list, uint32_t status, void *ctx)
2512{
2513	si_context_t *sictx;
2514	struct addrinfo *out;
2515
2516	if (ctx == NULL)
2517	{
2518#ifdef CALL_TRACE
2519		fprintf(stderr, "   %s error no context\n", __func__);
2520#endif
2521		si_list_release(list);
2522		return;
2523	}
2524
2525	sictx = (si_context_t *)ctx;
2526
2527	if ((sictx->orig_callback == NULL) || (status == SI_STATUS_CALL_CANCELLED))
2528	{
2529#ifdef CALL_TRACE
2530		fprintf(stderr, "   %s error no callback\n", __func__);
2531#endif
2532		si_list_release(list);
2533		free(sictx);
2534		return;
2535	}
2536
2537	if (status != SI_STATUS_NO_ERROR)
2538	{
2539#ifdef CALL_TRACE
2540		fprintf(stderr, "   %s original status %d\n", __func__, status);
2541#endif
2542		if (status <= SI_STATUS_EAI_PLUS_100) status = EAI_FAIL;
2543		else if (status >= SI_STATUS_ERRNO_PLUS_200) status = EAI_FAIL;
2544		else status = status - SI_STATUS_EAI_PLUS_100;
2545	}
2546
2547	if (list == NULL)
2548	{
2549#ifdef CALL_TRACE
2550		fprintf(stderr, "   %s result NULL status %d (returning EAI_NONAME)\n", __func__, status);
2551#endif
2552		((si_addrinfo_async_callback)(sictx->orig_callback))(EAI_NONAME, NULL, sictx->orig_context);
2553		free(sictx);
2554		return;
2555	}
2556
2557	out = si_list_to_addrinfo(list);
2558	si_list_release(list);
2559	if (out == NULL)
2560	{
2561#ifdef CALL_TRACE
2562		fprintf(stderr, "   %s result conversion failed returning NULL status %d (returning EAI_MEMORY)\n", __func__, status);
2563#endif
2564		((si_addrinfo_async_callback)(sictx->orig_callback))(EAI_MEMORY, NULL, sictx->orig_context);
2565		free(sictx);
2566		return;
2567	}
2568
2569#ifdef CALL_TRACE
2570	fprintf(stderr, "   %s %d\n", __func__, status);
2571	fprint_addrinfo(stderr, out);
2572#endif
2573	((si_addrinfo_async_callback)(sictx->orig_callback))(status, out, sictx->orig_context);
2574
2575	free(sictx);
2576}
2577
2578/* SPI */
2579mach_port_t
2580_getaddrinfo_interface_async_call(const char *nodename, const char *servname, const struct addrinfo *hints, const char *interface, si_addrinfo_async_callback callback, void *context)
2581{
2582	si_context_t *sictx;
2583	uint32_t family, socktype, protocol, flags;
2584
2585	family = AF_UNSPEC;
2586	socktype = SOCK_UNSPEC;
2587	protocol = IPPROTO_UNSPEC;
2588	flags = 0;
2589
2590	if (hints != NULL)
2591	{
2592		family = hints->ai_family;
2593		socktype = hints->ai_socktype;
2594		protocol = hints->ai_protocol;
2595		flags = hints->ai_flags;
2596	}
2597
2598#ifdef CALL_TRACE
2599	fprintf(stderr, ">> %s %s %s %u %u %u 0x%08x\n", __func__, nodename, servname, family, socktype, protocol, flags);
2600#endif
2601
2602	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
2603	if (sictx == NULL) return MACH_PORT_NULL;
2604
2605	sictx->orig_callback = callback;
2606	sictx->orig_context = context;
2607	sictx->cat = CATEGORY_ADDRINFO;
2608	sictx->key_offset = 0;
2609
2610	return si_async_call(si_search(), SI_CALL_ADDRINFO, nodename, servname, interface, family, socktype, protocol, flags, (void *)si_libinfo_addrinfo_callback, sictx);
2611}
2612
2613mach_port_t
2614getaddrinfo_async_call(const char *nodename, const char *servname, const struct addrinfo *hints, si_addrinfo_async_callback callback, void *context)
2615{
2616	return _getaddrinfo_interface_async_call(nodename, servname, hints, NULL, callback, context);
2617}
2618
2619int32_t
2620getaddrinfo_async_start(mach_port_t *p, const char *nodename, const char *servname, const struct addrinfo *hints, si_addrinfo_async_callback callback, void *context)
2621{
2622	if (p == NULL) return EAI_SYSTEM;
2623
2624	*p = getaddrinfo_async_call(nodename, servname, hints, callback, context);
2625
2626	if (*p == MACH_PORT_NULL) return EAI_SYSTEM;
2627	return 0;
2628}
2629
2630int32_t
2631getaddrinfo_async_send(mach_port_t *p, const char *nodename, const char *servname, const struct addrinfo *hints)
2632{
2633	return getaddrinfo_async_start(p, nodename, servname, hints, NULL, NULL);
2634}
2635
2636int32_t
2637getaddrinfo_async_receive(mach_port_t p, struct addrinfo **res)
2638{
2639	/* unsupported Leopard SPI */
2640	return EAI_SYSTEM;
2641}
2642
2643void
2644getaddrinfo_async_cancel(mach_port_t p)
2645{
2646#ifdef CALL_TRACE
2647	fprintf(stderr, "-- %s\n", __func__);
2648#endif
2649
2650	si_async_cancel(p);
2651}
2652
2653int32_t
2654getaddrinfo_async_handle_reply(void *param)
2655{
2656	mach_msg_header_t *msg;
2657
2658#ifdef CALL_TRACE
2659	fprintf(stderr, "<< %s\n", __func__);
2660#endif
2661
2662	msg = (mach_msg_header_t *)param;
2663	si_async_handle_reply(msg);
2664
2665	return 0;
2666}
2667
2668/* GETNAMEINFO */
2669
2670static int
2671_getnameinfo_interface_internal(const struct sockaddr *sa, socklen_t salen, char *node, socklen_t nodelen, char *service, socklen_t servicelen, int flags, const char *interface)
2672{
2673	si_item_t *item;
2674	si_nameinfo_t *ni;
2675	uint32_t status, len, wantn, wants;
2676
2677#ifdef CALL_TRACE
2678	fprintf(stderr, "-> %s\n", __func__);
2679#endif
2680
2681	status = SI_STATUS_NO_ERROR;
2682
2683	wantn = 0;
2684	if ((node != NULL) && (nodelen > 0)) wantn = 1;
2685
2686	wants = 0;
2687	if ((service != NULL) && (servicelen > 0)) wants = 1;
2688
2689	if ((wantn == 0) && (wants == 0)) return status;
2690
2691	if (wantn == 0) flags |= NI_NUMERICHOST;
2692	if (wants == 0) flags |= NI_NUMERICSERV;
2693
2694	item = si_nameinfo(si_search(), sa, flags, interface, &status);
2695	if ((status != SI_STATUS_NO_ERROR) || (item == NULL))
2696	{
2697		si_item_release(item);
2698
2699		if (status == SI_STATUS_NO_ERROR) status = EAI_NONAME;
2700		else if (status <= SI_STATUS_EAI_PLUS_100) status = EAI_FAIL;
2701		else if (status >= SI_STATUS_ERRNO_PLUS_200) status = EAI_FAIL;
2702		else status = status - SI_STATUS_EAI_PLUS_100;
2703		return status;
2704	}
2705
2706	ni = (si_nameinfo_t *)((uintptr_t)item + sizeof(si_item_t));
2707
2708	len = 0;
2709	if (ni->ni_node != NULL) len = strlen(ni->ni_node) + 1;
2710	if ((wantn == 1) && (len > 0))
2711	{
2712		if (len > nodelen)
2713		{
2714			si_item_release(item);
2715			return EAI_OVERFLOW;
2716		}
2717
2718		memset(node, 0, nodelen);
2719		memcpy(node, ni->ni_node, len);
2720	}
2721
2722	len = 0;
2723	if (ni->ni_serv != NULL) len = strlen(ni->ni_serv) + 1;
2724	if ((wants == 1) && (len > 0))
2725	{
2726		if (len > servicelen)
2727		{
2728			si_item_release(item);
2729			return EAI_OVERFLOW;
2730		}
2731
2732		memset(service, 0, servicelen);
2733		memcpy(service, ni->ni_serv, len);
2734	}
2735
2736	si_item_release(item);
2737	return 0;
2738}
2739
2740int
2741getnameinfo(const struct sockaddr *sa, socklen_t salen, char *node, socklen_t nodelen, char *service, socklen_t servicelen, int flags)
2742{
2743	if (sa == NULL) return EAI_FAIL;
2744
2745	if (sa->sa_family == AF_LINK) return getnameinfo_link(sa, salen, node, nodelen, service, servicelen, flags);
2746	return _getnameinfo_interface_internal(sa, salen, node, nodelen, service, servicelen, flags, NULL);
2747}
2748
2749static void
2750si_libinfo_nameinfo_callback(si_item_t *item, uint32_t status, void *ctx)
2751{
2752	si_context_t *sictx;
2753	si_nameinfo_t *ni;
2754	char *node, *serv;
2755
2756	if (ctx == NULL) return;
2757
2758	sictx = (si_context_t *)ctx;
2759
2760	if ((sictx->orig_callback == NULL) || (status == SI_STATUS_CALL_CANCELLED))
2761	{
2762		si_item_release(item);
2763		free(sictx);
2764		return;
2765	}
2766
2767	if (status != SI_STATUS_NO_ERROR)
2768	{
2769		if (status <= SI_STATUS_EAI_PLUS_100) status = EAI_FAIL;
2770		else if (status >= SI_STATUS_ERRNO_PLUS_200) status = EAI_FAIL;
2771		else status = status - SI_STATUS_EAI_PLUS_100;
2772	}
2773
2774	if (item == NULL)
2775	{
2776		((si_nameinfo_async_callback)(sictx->orig_callback))(status, NULL, NULL, sictx->orig_context);
2777		free(sictx);
2778		return;
2779	}
2780
2781	LI_set_thread_item(CATEGORY_NAMEINFO, item);
2782
2783	node = NULL;
2784	serv = NULL;
2785
2786	ni = (si_nameinfo_t *)((uintptr_t)item + sizeof(si_item_t));
2787	if (ni->ni_node != NULL) node = strdup(ni->ni_node);
2788	if (ni->ni_serv != NULL) serv = strdup(ni->ni_serv);
2789
2790	((si_nameinfo_async_callback)(sictx->orig_callback))(status, node, serv, sictx->orig_context);
2791	free(sictx);
2792}
2793
2794/* SPI */
2795mach_port_t
2796_getnameinfo_interface_async_call(const struct sockaddr *sa, size_t len, int flags, const char *interface, si_nameinfo_async_callback callback, void *context)
2797{
2798	si_context_t *sictx;
2799	uint32_t salen;
2800
2801#ifdef CALL_TRACE
2802	fprintf(stderr, ">> %s\n", __func__);
2803#endif
2804
2805	sictx = (si_context_t *)calloc(1, sizeof(si_context_t));
2806	if (sictx == NULL) return MACH_PORT_NULL;
2807
2808	sictx->orig_callback = callback;
2809	sictx->orig_context = context;
2810	sictx->cat = CATEGORY_ADDRINFO;
2811	sictx->key_offset = 0;
2812
2813	/* sa is not a C string - pass length in num3 */
2814	salen = len;
2815	return si_async_call(si_search(), SI_CALL_NAMEINFO, (const char *)sa, NULL, interface, flags, 0, salen, 0, (void *)si_libinfo_nameinfo_callback, sictx);
2816}
2817
2818mach_port_t
2819getnameinfo_async_call(const struct sockaddr *sa, size_t len, int flags, si_nameinfo_async_callback callback, void *context)
2820{
2821	return _getnameinfo_interface_async_call(sa, len, flags, NULL, callback, context);
2822}
2823
2824int32_t
2825getnameinfo_async_start(mach_port_t *p, const struct sockaddr *sa, size_t salen, int flags, si_nameinfo_async_callback callback, void *context)
2826{
2827	if (p == NULL) return EAI_SYSTEM;
2828	*p = getnameinfo_async_call(sa, salen, flags, callback, context);
2829
2830	if (*p == MACH_PORT_NULL) return EAI_SYSTEM;
2831	return 0;
2832}
2833
2834int32_t
2835getnameinfo_async_send(mach_port_t *p, const struct sockaddr *sa, size_t salen, int flags)
2836{
2837	return getnameinfo_async_start(p, sa, salen, flags, NULL, NULL);
2838}
2839
2840void
2841getnameinfo_async_cancel(mach_port_t p)
2842{
2843#ifdef CALL_TRACE
2844	fprintf(stderr, "-- %s\n", __func__);
2845#endif
2846
2847	si_async_cancel(p);
2848}
2849
2850int32_t
2851getnameinfo_async_handle_reply(void *param)
2852{
2853	mach_msg_header_t *msg;
2854
2855#ifdef CALL_TRACE
2856	fprintf(stderr, "<< %s\n", __func__);
2857#endif
2858
2859	msg = (mach_msg_header_t *)param;
2860	si_async_handle_reply(msg);
2861
2862	return 0;
2863}
2864
2865/* getpwXXX_r and getgrXXX_r */
2866
2867static int
2868copy_user_r(struct passwd *in, struct passwd *out, char *buffer, int buflen)
2869{
2870	int hsize;
2871	char *bp;
2872
2873	if (in == NULL) return -1;
2874	if (out == NULL) return -1;
2875
2876	if (buffer == NULL) buflen = 0;
2877
2878	/* Calculate size of input */
2879	hsize = 0;
2880	if (in->pw_name != NULL) hsize += (strlen(in->pw_name) + 1);
2881	if (in->pw_passwd != NULL) hsize += (strlen(in->pw_passwd) + 1);
2882	if (in->pw_class != NULL) hsize += (strlen(in->pw_class) + 1);
2883	if (in->pw_gecos != NULL) hsize += (strlen(in->pw_gecos) + 1);
2884	if (in->pw_dir != NULL) hsize += (strlen(in->pw_dir) + 1);
2885	if (in->pw_shell != NULL) hsize += (strlen(in->pw_shell) + 1);
2886
2887	/* Check buffer space */
2888	if (hsize > buflen) return -1;
2889
2890	/* Copy result into caller's struct passwd, using buffer for memory */
2891	bp = buffer;
2892
2893	out->pw_name = NULL;
2894	if (in->pw_name != NULL)
2895	{
2896		out->pw_name = bp;
2897		hsize = strlen(in->pw_name) + 1;
2898		memmove(bp, in->pw_name, hsize);
2899		bp += hsize;
2900	}
2901
2902	out->pw_passwd = NULL;
2903	if (in->pw_passwd != NULL)
2904	{
2905		out->pw_passwd = bp;
2906		hsize = strlen(in->pw_passwd) + 1;
2907		memmove(bp, in->pw_passwd, hsize);
2908		bp += hsize;
2909	}
2910
2911	out->pw_uid = in->pw_uid;
2912
2913	out->pw_gid = in->pw_gid;
2914
2915	out->pw_change = in->pw_change;
2916
2917	out->pw_class = NULL;
2918	if (in->pw_class != NULL)
2919	{
2920		out->pw_class = bp;
2921		hsize = strlen(in->pw_class) + 1;
2922		memmove(bp, in->pw_class, hsize);
2923		bp += hsize;
2924	}
2925
2926	out->pw_gecos = NULL;
2927	if (in->pw_gecos != NULL)
2928	{
2929		out->pw_gecos = bp;
2930		hsize = strlen(in->pw_gecos) + 1;
2931		memmove(bp, in->pw_gecos, hsize);
2932		bp += hsize;
2933	}
2934
2935	out->pw_dir = NULL;
2936	if (in->pw_dir != NULL)
2937	{
2938		out->pw_dir = bp;
2939		hsize = strlen(in->pw_dir) + 1;
2940		memmove(bp, in->pw_dir, hsize);
2941		bp += hsize;
2942	}
2943
2944	out->pw_shell = NULL;
2945	if (in->pw_shell != NULL)
2946	{
2947		out->pw_shell = bp;
2948		hsize = strlen(in->pw_shell) + 1;
2949		memmove(bp, in->pw_shell, hsize);
2950		bp += hsize;
2951	}
2952
2953	out->pw_expire = in->pw_expire;
2954
2955	return 0;
2956}
2957
2958static int
2959copy_group_r(struct group *in, struct group *out, char *buffer, int buflen)
2960{
2961	int i, len, hsize;
2962	unsigned long addr;
2963	char *bp, *ap;
2964
2965	if (in == NULL) return -1;
2966	if (out == NULL) return -1;
2967
2968	if (buffer == NULL) buflen = 0;
2969
2970	/* Calculate size of input */
2971	hsize = 0;
2972	if (in->gr_name != NULL) hsize += (strlen(in->gr_name) + 1);
2973	if (in->gr_passwd != NULL) hsize += (strlen(in->gr_passwd) + 1);
2974
2975	/* NULL pointer at end of list */
2976	hsize += sizeof(char *);
2977
2978	len = 0;
2979	if (in->gr_mem != NULL)
2980	{
2981		for (len = 0; in->gr_mem[len] != NULL; len++)
2982		{
2983			hsize += sizeof(char *);
2984			hsize += (strlen(in->gr_mem[len]) + 1);
2985		}
2986	}
2987
2988	/* Check buffer space */
2989	if (hsize > buflen) return -1;
2990
2991	/* Copy result into caller's struct group, using buffer for memory */
2992	bp = buffer;
2993
2994	out->gr_name = NULL;
2995	if (in->gr_name != NULL)
2996	{
2997		out->gr_name = bp;
2998		hsize = strlen(in->gr_name) + 1;
2999		memmove(bp, in->gr_name, hsize);
3000		bp += hsize;
3001	}
3002
3003	out->gr_passwd = NULL;
3004	if (in->gr_passwd != NULL)
3005	{
3006		out->gr_passwd = bp;
3007		hsize = strlen(in->gr_passwd) + 1;
3008		memmove(bp, in->gr_passwd, hsize);
3009		bp += hsize;
3010	}
3011
3012	out->gr_gid = in->gr_gid;
3013
3014	out->gr_mem = NULL;
3015	ap = bp + ((len + 1) * sizeof(char *));
3016
3017	if (in->gr_mem != NULL)
3018	{
3019		out->gr_mem = (char **)bp;
3020		for (i = 0; i < len; i++)
3021		{
3022			addr = (unsigned long)ap;
3023			memmove(bp, &addr, sizeof(unsigned long));
3024			bp += sizeof(unsigned long);
3025
3026			hsize = strlen(in->gr_mem[i]) + 1;
3027			memmove(ap, in->gr_mem[i], hsize);
3028			ap += hsize;
3029		}
3030	}
3031
3032	memset(bp, 0, sizeof(unsigned long));
3033	bp = ap;
3034
3035	return 0;
3036}
3037
3038int
3039getgrnam_r(const char *name, struct group *grp, char *buffer, size_t bufsize, struct group **result)
3040{
3041	si_item_t *item;
3042	struct group *g;
3043	int status;
3044
3045#ifdef CALL_TRACE
3046	fprintf(stderr, "-> %s %s\n", __func__, name);
3047#endif
3048
3049	if (result != NULL) *result = NULL;
3050
3051	if ((grp == NULL) || (buffer == NULL) || (result == NULL) || (bufsize == 0)) return ERANGE;
3052
3053	item = si_group_byname(si_search(), name);
3054	if (item == NULL) return 0;
3055
3056	g = (struct group *)((uintptr_t)item + sizeof(si_item_t));
3057
3058	status = copy_group_r(g, grp, buffer, bufsize);
3059	si_item_release(item);
3060
3061	if (status != 0) return ERANGE;
3062
3063	*result = grp;
3064	return 0;
3065}
3066
3067int
3068getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize, struct group **result)
3069{
3070	si_item_t *item;
3071	struct group *g;
3072	int status;
3073
3074#ifdef CALL_TRACE
3075	fprintf(stderr, "-> %s %d\n", __func__, gid);
3076#endif
3077
3078	if (result != NULL) *result = NULL;
3079
3080	if ((grp == NULL) || (buffer == NULL) || (result == NULL) || (bufsize == 0)) return ERANGE;
3081
3082	item = si_group_bygid(si_search(), gid);
3083	if (item == NULL) return 0;
3084
3085	g = (struct group *)((uintptr_t)item + sizeof(si_item_t));
3086
3087	status = copy_group_r(g, grp, buffer, bufsize);
3088	si_item_release(item);
3089
3090	if (status != 0) return ERANGE;
3091
3092	*result = grp;
3093	return 0;
3094}
3095
3096int
3097getgruuid_r(uuid_t uuid, struct group *grp, char *buffer, size_t bufsize, struct group **result)
3098{
3099	si_item_t *item;
3100	struct group *g;
3101	int status;
3102
3103#ifdef CALL_TRACE
3104	uuid_string_t uuidstr;
3105	uuid_unparse_upper(uuid, uuidstr);
3106	fprintf(stderr, "-> %s %s\n", __func__, uuidstr);
3107#endif
3108
3109	if (result != NULL) *result = NULL;
3110
3111	if ((grp == NULL) || (buffer == NULL) || (result == NULL) || (bufsize == 0)) return ERANGE;
3112
3113	item = si_group_byuuid(si_search(), uuid);
3114	if (item == NULL) return 0;
3115
3116	g = (struct group *)((uintptr_t)item + sizeof(si_item_t));
3117
3118	status = copy_group_r(g, grp, buffer, bufsize);
3119	si_item_release(item);
3120
3121	if (status != 0) return ERANGE;
3122
3123	*result = grp;
3124	return 0;
3125}
3126
3127int
3128getpwnam_r(const char *name, struct passwd *pw, char *buffer, size_t bufsize, struct passwd **result)
3129{
3130	si_item_t *item;
3131	struct passwd *p;
3132	int status;
3133
3134#ifdef CALL_TRACE
3135	fprintf(stderr, "-> %s %s\n", __func__, name);
3136#endif
3137
3138	if (result != NULL) *result = NULL;
3139
3140	if ((pw == NULL) || (buffer == NULL) || (result == NULL) || (bufsize == 0)) return ERANGE;
3141
3142	item = si_user_byname(si_search(), name);
3143	if (item == NULL) return 0;
3144
3145	p = (struct passwd *)((uintptr_t)item + sizeof(si_item_t));
3146
3147	status = copy_user_r(p, pw, buffer, bufsize);
3148	si_item_release(item);
3149
3150	if (status != 0) return ERANGE;
3151
3152	*result = pw;
3153	return 0;
3154}
3155
3156int
3157getpwuid_r(uid_t uid, struct passwd *pw, char *buffer, size_t bufsize, struct passwd **result)
3158{
3159	si_item_t *item;
3160	struct passwd *p;
3161	int status;
3162
3163#ifdef CALL_TRACE
3164	fprintf(stderr, "-> %s %d\n", __func__, uid);
3165#endif
3166
3167	if (result != NULL) *result = NULL;
3168
3169	if ((pw == NULL) || (buffer == NULL) || (result == NULL) || (bufsize == 0)) return ERANGE;
3170
3171	item = si_user_byuid(si_search(), uid);
3172	if (item == NULL) return 0;
3173
3174	p = (struct passwd *)((uintptr_t)item + sizeof(si_item_t));
3175
3176	status = copy_user_r(p, pw, buffer, bufsize);
3177	si_item_release(item);
3178
3179	if (status != 0) return ERANGE;
3180
3181	*result = pw;
3182	return 0;
3183}
3184
3185int
3186getpwuuid_r(uuid_t uuid, struct passwd *pw, char *buffer, size_t bufsize, struct passwd **result)
3187{
3188	si_item_t *item;
3189	struct passwd *p;
3190	int status;
3191
3192#ifdef CALL_TRACE
3193	uuid_string_t uuidstr;
3194	uuid_unparse_upper(uuid, uuidstr);
3195	fprintf(stderr, "-> %s %s\n", __func__, uuidstr);
3196#endif
3197
3198	if (result != NULL) *result = NULL;
3199
3200	if ((pw == NULL) || (buffer == NULL) || (result == NULL) || (bufsize == 0)) return ERANGE;
3201
3202	item = si_user_byuuid(si_search(), uuid);
3203	if (item == NULL) return 0;
3204
3205	p = (struct passwd *)((uintptr_t)item + sizeof(si_item_t));
3206
3207	status = copy_user_r(p, pw, buffer, bufsize);
3208	si_item_release(item);
3209
3210	if (status != 0) return ERANGE;
3211
3212	*result = pw;
3213	return 0;
3214}
3215
3216/* misc */
3217
3218char *
3219user_from_uid(uid_t uid, int nouser)
3220{
3221	struct passwd *pw;
3222	static char buf[16];
3223
3224	pw = getpwuid(uid);
3225	if (pw != NULL) return pw->pw_name;
3226
3227	if (nouser) return NULL;
3228
3229	snprintf(buf, sizeof(buf), "%u", uid);
3230	return buf;
3231}
3232
3233char *
3234group_from_gid(gid_t gid, int nogroup)
3235{
3236	struct group *gr;
3237	static char buf[16];
3238
3239	gr = getgrgid(gid);
3240	if (gr != NULL) return gr->gr_name;
3241
3242	if (nogroup) return NULL;
3243
3244	snprintf(buf, sizeof(buf), "%u", gid);
3245	return buf;
3246}
3247
3248/* no longer supported */
3249
3250const prdb_ent *
3251prdb_getbyname(const char *name)
3252{
3253#ifdef CALL_TRACE
3254	fprintf(stderr, "~~ %s\n", __func__);
3255#endif
3256	return NULL;
3257}
3258
3259const prdb_ent *
3260prdb_get(void)
3261{
3262#ifdef CALL_TRACE
3263	fprintf(stderr, "~~ %s\n", __func__);
3264#endif
3265	return NULL;
3266}
3267
3268void
3269prdb_set(const char *name)
3270{
3271#ifdef CALL_TRACE
3272	fprintf(stderr, "~~ %s\n", __func__);
3273#endif
3274}
3275
3276void
3277prdb_end(void)
3278{
3279#ifdef CALL_TRACE
3280	fprintf(stderr, "~~ %s\n", __func__);
3281#endif
3282}
3283
3284struct bootparamsent *
3285bootparams_getbyname(const char *name)
3286{
3287#ifdef CALL_TRACE
3288	fprintf(stderr, "~~ %s\n", __func__);
3289#endif
3290	return NULL;
3291}
3292
3293struct bootparamsent *
3294bootparams_getent(void)
3295{
3296#ifdef CALL_TRACE
3297	fprintf(stderr, "~~ %s\n", __func__);
3298#endif
3299	return NULL;
3300}
3301
3302void
3303bootparams_setent(void)
3304{
3305#ifdef CALL_TRACE
3306	fprintf(stderr, "~~ %s\n", __func__);
3307#endif
3308}
3309
3310void
3311bootparams_endent(void)
3312{
3313#ifdef CALL_TRACE
3314	fprintf(stderr, "~~ %s\n", __func__);
3315#endif
3316}
3317
3318int
3319bootp_getbyether(struct ether_addr *enaddr, char **name,struct in_addr *ipaddr, char **bootfile)
3320{
3321#ifdef CALL_TRACE
3322	fprintf(stderr, "~~ %s\n", __func__);
3323#endif
3324	return 0;
3325}
3326
3327int
3328bootp_getbyip(struct ether_addr *enaddr, char **name, struct in_addr *ipaddr, char **bootfile)
3329{
3330#ifdef CALL_TRACE
3331	fprintf(stderr, "~~ %s\n", __func__);
3332#endif
3333	return 0;
3334}
3335