2 * Copyright (c) 2008-2011 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This ds 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 ds 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
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.
21 * @APPLE_LICENSE_HEADER_END@
32 #include <arpa/inet.h>
41 #include <notify_keys.h>
43 #include <si_module.h>
44 #include <netdb_async.h>
47 #include <xpc/private.h>
48 #include <opendirectory/odipc.h>
49 #include <servers/bootstrap.h>
50 #include <bootstrap_priv.h>
51 #include <opendirectory/DSlibinfoMIG_types.h>
56 #define IPV6_ADDR_LEN 16
57 #define IPV4_ADDR_LEN 4
59 typedef si_item_t
*(*od_extract_t
)(si_mod_t
*si
, xpc_object_t reply
, const void *extra
, uint64_t valid_global
, uint64_t valid_cat
);
62 uint32_t notify_peek(int token
, uint32_t *val
);
66 int notify_token_global
;
67 int notify_token_user
;
68 int notify_token_group
;
69 int notify_token_service
;
72 extern uint32_t gL1CacheEnabled
;
73 extern int _si_opendirectory_disabled
;
75 static pthread_key_t _ds_serv_cache_key
= 0;
76 static xpc_pipe_t __od_pipe
; /* use accessor only */
77 static pthread_mutex_t mutex
= PTHREAD_MUTEX_INITIALIZER
;
84 // re-enable opendirectory interaction since we forked
85 _si_opendirectory_disabled
= 0;
87 if (__od_pipe
!= NULL
) {
88 xpc_pipe_invalidate(__od_pipe
);
89 /* disable release due to 10649340, it will cause a minor leak for each fork without exec */
90 // xpc_release(__od_pipe);
93 _ds_port
= MACH_PORT_NULL
;
94 pthread_mutex_unlock(&mutex
);
98 _od_fork_prepare(void)
100 pthread_mutex_lock(&mutex
);
104 _od_fork_parent(void)
106 pthread_mutex_unlock(&mutex
);
110 _ds_serv_cache_free(void *x
)
112 if (x
!= NULL
) si_item_release(x
);
116 _si_disable_opendirectory(void)
118 _si_opendirectory_disabled
= 1;
119 _ds_port
= MACH_PORT_NULL
;
124 _od_xpc_pipe(bool resetPipe
)
126 static dispatch_once_t once
;
127 xpc_pipe_t result
= NULL
;
129 dispatch_once(&once
, ^(void) {
132 /* if this is a build environment we ignore opendirectoryd */
133 xbs_disable
= getenv("XBS_DISABLE_LIBINFO");
134 if ((issetugid() == 0) && (xbs_disable
!= NULL
) && (strcmp(xbs_disable
, "YES") == 0)) {
135 _si_opendirectory_disabled
= 1;
139 pthread_atfork(_od_fork_prepare
, _od_fork_parent
, _od_fork_child
);
142 if (_si_opendirectory_disabled
== 1) {
146 pthread_mutex_lock(&mutex
);
148 xpc_release(__od_pipe
);
152 if (__od_pipe
== NULL
) {
153 if (!issetugid() && getenv("OD_DEBUG_MODE") != NULL
) {
154 __od_pipe
= xpc_pipe_create(kODMachLibinfoPortNameDebug
, 0);
156 __od_pipe
= xpc_pipe_create(kODMachLibinfoPortName
, XPC_PIPE_FLAG_PRIVILEGED
);
160 if (__od_pipe
!= NULL
) result
= xpc_retain(__od_pipe
);
161 pthread_mutex_unlock(&mutex
);
171 pipe
= _od_xpc_pipe(false);
176 if (_si_opendirectory_disabled
) {
180 return (pipe
!= NULL
);
186 _ds_port
= MACH_PORT_NULL
;
192 kern_return_t status
;
193 char *od_debug_mode
= NULL
;
195 if (_ds_port
!= MACH_PORT_NULL
) return 1;
197 if (_si_opendirectory_disabled
) return 0;
198 pthread_atfork(NULL
, NULL
, _ds_child
);
201 od_debug_mode
= getenv("OD_DEBUG_MODE");
205 status
= bootstrap_look_up(bootstrap_port
, kDSStdMachDSLookupPortName
"_debug", &_ds_port
);
207 status
= bootstrap_look_up2(bootstrap_port
, kDSStdMachDSLookupPortName
, &_ds_port
, 0, BOOTSTRAP_PRIVILEGED_SERVER
);
209 if ((status
!= BOOTSTRAP_SUCCESS
) && (status
!= BOOTSTRAP_UNKNOWN_SERVICE
)) _ds_port
= MACH_PORT_NULL
;
211 return (_ds_port
!= MACH_PORT_NULL
);
215 _valid_token(xpc_object_t reply
)
220 * This should really call audit_token_to_au32,
221 * but that's in libbsm, not in a Libsystem library.
223 xpc_dictionary_get_audit_token(reply
, &token
);
225 return ((uid_t
) token
.val
[1] == 0);
229 _ds_get_validation(si_mod_t
*si
, uint64_t *a
, uint64_t *b
, int cat
)
235 if (si
== NULL
) return;
237 pp
= (ds_si_private_t
*)si
->private;
238 if (pp
== NULL
) return;
243 status
= notify_peek(pp
->notify_token_global
, &peek
);
244 if (status
== NOTIFY_STATUS_OK
) *a
= ntohl(peek
);
251 status
= NOTIFY_STATUS_FAILED
;
253 if (cat
== CATEGORY_USER
) status
= notify_peek(pp
->notify_token_user
, &peek
);
254 else if (cat
== CATEGORY_GROUP
) status
= notify_peek(pp
->notify_token_group
, &peek
);
255 else if (cat
== CATEGORY_GROUPLIST
) status
= notify_peek(pp
->notify_token_group
, &peek
);
256 else if (cat
== CATEGORY_SERVICE
) status
= notify_peek(pp
->notify_token_service
, &peek
);
258 if (status
== NOTIFY_STATUS_OK
) *b
= ntohl(peek
);
263 __private_extern__ xpc_object_t
264 _od_rpc_call(const char *procname
, xpc_object_t payload
, xpc_pipe_t (*get_pipe
)(bool))
266 xpc_object_t result
= NULL
;
270 bool free_payload
= false;
272 od_pipe
= get_pipe(false);
273 if (od_pipe
== NULL
) return NULL
;
275 if (payload
== NULL
) {
276 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
280 // we nest it for backward compatibility so we can do independent submissions
281 xpc_dictionary_set_string(payload
, OD_RPC_NAME
, procname
);
282 xpc_dictionary_set_int64(payload
, OD_RPC_VERSION
, 2);
284 for (retries
= 0; od_pipe
!= NULL
&& retries
< 2; retries
++) {
285 rc
= xpc_pipe_routine(od_pipe
, payload
, &reply
);
288 xpc_release(od_pipe
);
289 od_pipe
= get_pipe(true);
293 /* just loop and try to send again */
297 if (_valid_token(reply
) == true) {
300 /* fall through since we got a valid response */
303 /* release and NULL the pipe it'll break the loop */
304 xpc_release(od_pipe
);
310 if (od_pipe
!= NULL
) {
311 xpc_release(od_pipe
);
315 xpc_release(payload
);
322 _ds_list(si_mod_t
*si
, int cat
, const char *procname
, const void *extra
, od_extract_t extract
)
324 __block si_list_t
*list
;
326 xpc_object_t reply
, result
;
328 if (procname
== NULL
) return NULL
;
330 _ds_get_validation(si
, &va
, &vb
, cat
);
333 reply
= _od_rpc_call(procname
, NULL
, _od_xpc_pipe
);
335 result
= xpc_dictionary_get_value(reply
, OD_RPC_RESULT
);
336 if (result
!= NULL
&& xpc_get_type(result
) == XPC_TYPE_ARRAY
) {
337 xpc_array_apply(result
, ^bool(size_t index
, xpc_object_t value
) {
338 si_item_t
*item
= extract(si
, value
, extra
, va
, vb
);
339 list
= si_list_add(list
, item
);
340 si_item_release(item
);
353 _ds_item(si_mod_t
*si
, int cat
, const char *procname
, const void *extra
, od_extract_t extract
, xpc_object_t payload
)
357 si_item_t
*item
= NULL
;
359 if (procname
== NULL
) return NULL
;
361 result
= _od_rpc_call(procname
, payload
, _od_xpc_pipe
);
362 if (result
!= NULL
) {
363 _ds_get_validation(si
, &va
, &vb
, cat
);
364 if (xpc_dictionary_get_int64(result
, OD_RPC_ERROR
) == 0) {
365 item
= extract(si
, result
, extra
, va
, vb
);
375 _ds_is_valid(si_mod_t
*si
, si_item_t
*item
)
380 uint32_t oldval
, newval
;
382 if (si
== NULL
) return 0;
383 if (item
== NULL
) return 0;
384 if (si
->name
== NULL
) return 0;
385 if (item
->src
== NULL
) return 0;
387 pp
= (ds_si_private_t
*)si
->private;
388 if (pp
== NULL
) return 0;
390 src
= (si_mod_t
*)item
->src
;
392 if (src
->name
== NULL
) return 0;
393 if (string_not_equal(si
->name
, src
->name
)) return 0;
395 /* check global invalidation */
396 oldval
= item
->validation_a
;
398 status
= notify_peek(pp
->notify_token_global
, &newval
);
399 if (status
!= NOTIFY_STATUS_OK
) return 0;
401 newval
= ntohl(newval
);
402 if (oldval
!= newval
) return 0;
404 oldval
= item
->validation_b
;
406 if (item
->type
== CATEGORY_USER
) status
= notify_peek(pp
->notify_token_user
, &newval
);
407 else if (item
->type
== CATEGORY_GROUP
) status
= notify_peek(pp
->notify_token_group
, &newval
);
408 else if (item
->type
== CATEGORY_SERVICE
) status
= notify_peek(pp
->notify_token_service
, &newval
);
411 if (status
!= NOTIFY_STATUS_OK
) return 0;
413 newval
= ntohl(newval
);
414 if (oldval
!= newval
) return 0;
420 _free_addr_list(char **l
)
424 if (l
== NULL
) return;
425 for (i
= 0; l
[i
] != NULL
; i
++) free(l
[i
]);
429 /* map ipv4 addresses and append to v6 list */
431 _map_v4(char ***v6
, uint32_t n6
, char **v4
, uint32_t n4
)
436 a6
.__u6_addr
.__u6_addr32
[0] = 0x00000000;
437 a6
.__u6_addr
.__u6_addr32
[1] = 0x00000000;
438 a6
.__u6_addr
.__u6_addr32
[2] = htonl(0x0000ffff);
442 *v6
= (char **)calloc(n4
+ 1, sizeof(char *));
446 *v6
= (char **)reallocf(*v6
, (n6
+ n4
+ 1) * sizeof(char *));
449 if (*v6
== NULL
) return -1;
451 for (i
= 0; i
< n4
; i
++)
453 (*v6
)[n6
] = (char *)calloc(1, IPV6_ADDR_LEN
);
454 if ((*v6
)[n6
] == NULL
) return -1;
456 memcpy(&(a6
.__u6_addr
.__u6_addr32
[3]), v4
[i
], IPV4_ADDR_LEN
);
457 memcpy((*v6
)[n6
], &(a6
.__u6_addr
.__u6_addr32
[0]), IPV6_ADDR_LEN
);
466 _xpc_query_key_string(const char *key
, const char *value
)
468 xpc_object_t payload
;
470 if (value
== NULL
) return NULL
;
472 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
473 if (payload
== NULL
) return NULL
;
475 xpc_dictionary_set_string(payload
, key
, value
);
481 _xpc_query_key_id(const char *key
, id_t idValue
)
483 xpc_object_t payload
;
485 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
486 if (payload
== NULL
) return NULL
;
488 xpc_dictionary_set_int64(payload
, key
, idValue
);
494 _xpc_query_key_uuid(const char *key
, uuid_t uu
)
496 xpc_object_t payload
;
498 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
499 if (payload
== NULL
) return NULL
;
501 xpc_dictionary_set_uuid(payload
, key
, uu
);
507 _xpc_query_key_int(const char *key
, int64_t intValue
)
509 xpc_object_t payload
;
511 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
512 if (payload
== NULL
) return NULL
;
514 xpc_dictionary_set_int64(payload
, key
, intValue
);
522 _extract_string_from_xpc_array_index(xpc_object_t reply
, int index
, const char **str
)
526 if (xpc_array_get_count(reply
) < index
) return -1;
528 value
= xpc_array_get_value(reply
, index
);
529 if (xpc_get_type(value
) != XPC_TYPE_STRING
) return -1;
531 *str
= xpc_string_get_string_ptr(value
);
536 _extract_string_from_xpc_object(xpc_object_t value
, const char **str
)
538 if (value
== NULL
) return -1;
539 else if (xpc_get_type(value
) == XPC_TYPE_STRING
)
541 *str
= xpc_string_get_string_ptr(value
);
544 else if (xpc_get_type(value
) == XPC_TYPE_ARRAY
)
546 return _extract_string_from_xpc_array_index(value
, 0, str
);
553 _extract_uint32_from_xpc_object(xpc_object_t value
, uint32_t *val32
)
557 if (value
== NULL
) return -1;
558 type
= xpc_get_type(value
);
560 if (type
== XPC_TYPE_STRING
)
562 *val32
= atoi(xpc_string_get_string_ptr(value
));
565 else if (type
== XPC_TYPE_INT64
)
567 *val32
= (uint32_t)xpc_int64_get_value(value
);
570 else if (type
== XPC_TYPE_BOOL
)
572 *val32
= (uint32_t)xpc_bool_get_value(value
);
575 else if (type
== XPC_TYPE_ARRAY
)
577 if (xpc_array_get_count(value
) == 0) return -1;
578 return _extract_uint32_from_xpc_object(xpc_array_get_value(value
, 0), val32
);
585 _extract_string_list_from_xpc_array_index(xpc_object_t reply
, int index
, unsigned int *len
, char ***list
)
588 xpc_object_t xpc_array
= xpc_array_get_value(reply
, index
);
590 if ((xpc_array
== NULL
) || (xpc_get_type(xpc_array
) != XPC_TYPE_ARRAY
)) return -1;
592 result
= calloc(xpc_array_get_count(xpc_array
) + 1, sizeof(*result
));
593 if (result
== NULL
) return -1;
595 /* include trailing NULL */
596 if (len
!= NULL
) (*len
) = xpc_array_get_count(xpc_array
) + 1;
598 xpc_array_apply(xpc_array
, ^bool(size_t idx
, xpc_object_t value
) {
599 result
[idx
] = (char *)xpc_string_get_string_ptr(value
);
608 _extract_uint32_from_xpc_array_index(xpc_object_t reply
, int index
, uint32_t *val32
)
610 xpc_object_t value
= xpc_array_get_value(reply
, index
);
611 return _extract_uint32_from_xpc_object(value
, val32
);
615 _extract_string_list_from_xpc_array(xpc_object_t xpc_array
, unsigned int *len
, char ***list
)
619 if ((xpc_array
== NULL
) || (xpc_get_type(xpc_array
) != XPC_TYPE_ARRAY
)) return -1;
621 result
= calloc(xpc_array_get_count(xpc_array
) + 1, sizeof(*result
));
622 if (result
== NULL
) return -1;
624 /* include trailing NULL */
625 if (len
!= NULL
) (*len
) = xpc_array_get_count(xpc_array
) + 1;
627 xpc_array_apply(xpc_array
, ^bool(size_t idx
, xpc_object_t value
) {
628 result
[idx
] = (char *)xpc_string_get_string_ptr(value
);
637 _extract_string_from_xpc_dict(xpc_object_t reply
, const char *key
, const char **str
)
639 xpc_object_t value
= xpc_dictionary_get_value(reply
, key
);
642 if (value
== NULL
) return -1;
644 if (xpc_get_type(value
) != XPC_TYPE_STRING
) return -1;
646 result
= xpc_string_get_string_ptr(value
);
647 if (result
== NULL
) return -1;
654 _extract_uint32_from_xpc_dict(xpc_object_t reply
, const char *key
, uint32_t *val32
)
656 xpc_object_t value
= xpc_dictionary_get_value(reply
, key
);
657 return _extract_uint32_from_xpc_object(value
, val32
);
675 _extract_user_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
680 if (xpc_array_get_count(reply
) < 7) return NULL
;
682 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.pw_name
)) return NULL
;
683 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.pw_passwd
)) return NULL
;
684 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.pw_uid
)) return NULL
;
685 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.pw_gid
)) return NULL
;
686 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.pw_gecos
)) return NULL
;
687 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.pw_dir
)) return NULL
;
688 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.pw_shell
)) return NULL
;
691 tmp
.pw_change
= (time_t)0;
692 tmp
.pw_expire
= (time_t)0;
693 tmp
.pw_class
= (char *)"";
695 return (si_item_t
*)LI_ils_create("L4488ss44LssssL", (unsigned long)si
, CATEGORY_USER
, 1, valid_global
, valid_cat
, tmp
.pw_name
, tmp
.pw_passwd
, tmp
.pw_uid
, tmp
.pw_gid
, tmp
.pw_change
, tmp
.pw_class
, tmp
.pw_gecos
, tmp
.pw_dir
, tmp
.pw_shell
, tmp
.pw_expire
);
699 _extract_user_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
701 __block
struct passwd tmp
;
702 __block
int status
= 0;
703 __block
int parts
= 3;
705 tmp
.pw_name
= (char *)"";
706 tmp
.pw_passwd
= (char *)"*";
707 tmp
.pw_uid
= (uid_t
)0;
708 tmp
.pw_gid
= (gid_t
)0;
709 tmp
.pw_change
= (time_t)0;
710 tmp
.pw_expire
= (time_t)0;
711 tmp
.pw_class
= (char *)"";
712 tmp
.pw_gecos
= (char *)"";
713 tmp
.pw_dir
= (char *)"/var/empty";
714 tmp
.pw_shell
= (char *)"/usr/bin/false";
716 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
717 if (key
== NULL
) return true;
718 else if (!strcmp(key
, "pw_name"))
720 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_name
);
721 if (status
== 0) parts
--;
723 else if (!strcmp(key
, "pw_passwd"))
725 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_passwd
);
726 /* no parts check - this value is optional */
728 else if (!strcmp(key
, "pw_uid"))
730 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.pw_uid
);
731 if (status
== 0) parts
--;
733 else if (!strcmp(key
, "pw_gid"))
735 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.pw_gid
);
736 if (status
== 0) parts
--;
738 else if (!strcmp(key
, "pw_change"))
740 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.pw_change
);
741 /* no parts check - this value is optional */
743 else if (!strcmp(key
, "pw_expire"))
745 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.pw_expire
);
746 /* no parts check - this value is optional */
748 else if (!strcmp(key
, "pw_class"))
750 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_class
);
751 /* no parts check - this value is optional */
753 else if (!strcmp(key
, "pw_gecos"))
755 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_gecos
);
756 /* no parts check - this value is optional */
758 else if (!strcmp(key
, "pw_dir"))
760 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_dir
);
761 /* no parts check - this value is optional */
763 else if (!strcmp(key
, "pw_shell"))
765 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_shell
);
766 /* no parts check - this value is optional */
771 if ((status
!= 0) || (parts
!= 0)) return NULL
;
773 return (si_item_t
*)LI_ils_create("L4488ss44LssssL", (unsigned long)si
, CATEGORY_USER
, 1, valid_global
, valid_cat
, tmp
.pw_name
, tmp
.pw_passwd
, tmp
.pw_uid
, tmp
.pw_gid
, tmp
.pw_change
, tmp
.pw_class
, tmp
.pw_gecos
, tmp
.pw_dir
, tmp
.pw_shell
, tmp
.pw_expire
);
777 _extract_user(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
781 if (si
== NULL
) return NULL
;
782 if (reply
== NULL
) return NULL
;
784 type
= xpc_get_type(reply
);
786 if (type
== XPC_TYPE_ARRAY
) return _extract_user_array(si
, reply
, valid_global
, valid_cat
);
787 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_user_dict(si
, reply
, valid_global
, valid_cat
);
797 * optional members : array of string
802 _extract_group_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
807 int arraycount
= xpc_array_get_count(reply
);
809 if ((arraycount
< 2) || (arraycount
> 3)) return NULL
;
811 memset(&tmp
, 0, sizeof(tmp
));
813 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.gr_name
)) return NULL
;
814 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.gr_gid
)) return NULL
;
818 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.gr_mem
)) return NULL
;
822 tmp
.gr_passwd
= (char *)"*";
824 item
= (si_item_t
*) LI_ils_create("L4488ss4*", (unsigned long)si
, CATEGORY_GROUP
, 1, valid_global
, valid_cat
, tmp
.gr_name
, tmp
.gr_passwd
, tmp
.gr_gid
, tmp
.gr_mem
);
832 _extract_group_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
835 __block
struct group tmp
;
836 __block
int status
= 0;
837 __block
int parts
= 2;
839 tmp
.gr_name
= (char *)"";
840 tmp
.gr_passwd
= (char *)"*";
841 tmp
.gr_gid
= (gid_t
)0;
844 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
845 if (key
== NULL
) return true;
846 else if (!strcmp(key
, "gr_name"))
848 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.gr_name
);
849 if (status
== 0) parts
--;
851 else if (!strcmp(key
, "gr_passwd"))
853 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.gr_passwd
);
854 /* no parts check - this value is optional */
856 else if (!strcmp(key
, "gr_gid"))
858 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.gr_gid
);
859 if (status
== 0) parts
--;
861 else if (!strcmp(key
, "gr_mem"))
863 status
|= _extract_string_list_from_xpc_array(value
, NULL
, (char ***)&tmp
.gr_mem
);
864 /* no parts check - this value is optional */
869 if ((status
!= 0) || (parts
!= 0))
875 item
= (si_item_t
*) LI_ils_create("L4488ss4*", (unsigned long)si
, CATEGORY_GROUP
, 1, valid_global
, valid_cat
, tmp
.gr_name
, tmp
.gr_passwd
, tmp
.gr_gid
, tmp
.gr_mem
);
883 _extract_group(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
887 if (si
== NULL
) return NULL
;
888 if (reply
== NULL
) return NULL
;
890 type
= xpc_get_type(reply
);
891 if (type
== XPC_TYPE_ARRAY
) return _extract_group_array(si
, reply
, valid_global
, valid_cat
);
892 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_group_dict(si
, reply
, valid_global
, valid_cat
);
906 _extract_netgroup_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
908 const char *host
, *user
, *domain
;
911 if (xpc_array_get_count(reply
) != 3) return NULL
;
913 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&host
)) return NULL
;
914 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&user
)) return NULL
;
915 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&domain
)) return NULL
;
917 return (si_item_t
*)LI_ils_create("L4488sss", (unsigned long)si
, CATEGORY_NETGROUP
, 1, valid_global
, valid_cat
, host
, user
, domain
);
921 _extract_netgroup_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
923 __block
const char *host
= "";
924 __block
const char *user
= "";
925 __block
const char *domain
= "";
926 __block
int status
= 0;
927 __block
int parts
= 3;
929 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
930 if (key
== NULL
) return true;
931 else if (!strcmp(key
, "host"))
933 status
|= _extract_string_from_xpc_object(value
, (const char **)&host
);
934 if (status
== 0) parts
--;
936 else if (!strcmp(key
, "user"))
938 status
|= _extract_string_from_xpc_object(value
, (const char **)&user
);
939 if (status
== 0) parts
--;
941 else if (!strcmp(key
, "domain"))
943 status
|= _extract_string_from_xpc_object(value
, (const char **)&domain
);
944 if (status
== 0) parts
--;
949 if ((status
!= 0) || (parts
!= 0)) return NULL
;
951 return (si_item_t
*)LI_ils_create("L4488sss", (unsigned long)si
, CATEGORY_NETGROUP
, 1, valid_global
, valid_cat
, host
, user
, domain
);
955 _extract_netgroup(si_mod_t
*si
, xpc_object_t reply
, const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
959 if (si
== NULL
) return NULL
;
960 if (reply
== NULL
) return NULL
;
962 type
= xpc_get_type(reply
);
963 if (type
== XPC_TYPE_ARRAY
) return _extract_netgroup_array(si
, reply
, valid_global
, valid_cat
);
964 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_netgroup_dict(si
, reply
, valid_global
, valid_cat
);
974 * optional members : array of string
979 _extract_alias_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
984 int arraycount
= xpc_array_get_count(reply
);
986 if ((arraycount
< 2) || (arraycount
> 3)) return NULL
;
988 memset(&tmp
, 0, sizeof(tmp
));
990 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.alias_name
)) return NULL
;
991 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.alias_local
)) return NULL
;
995 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.alias_members
)) return NULL
;
998 item
= (si_item_t
*)LI_ils_create("L4488s4*4", (unsigned long)si
, CATEGORY_ALIAS
, 1, valid_global
, valid_cat
, tmp
.alias_name
, tmp
.alias_members_len
, tmp
.alias_members
, tmp
.alias_local
);
1000 free(tmp
.alias_members
);
1006 _extract_alias_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1009 __block
struct aliasent tmp
;
1010 __block
int status
= 0;
1011 __block
int parts
= 2;
1013 tmp
.alias_name
= (char *)"";
1014 tmp
.alias_local
= 0;
1015 tmp
.alias_members
= NULL
;
1016 tmp
.alias_members_len
= 0;
1018 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1019 if (key
== NULL
) return true;
1020 else if (!strcmp(key
, "alias_name"))
1022 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.alias_name
);
1023 if (status
== 0) parts
--;
1025 else if (!strcmp(key
, "alias_local"))
1027 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.alias_local
);
1028 if (status
== 0) parts
--;
1030 else if (!strcmp(key
, "alias_members"))
1032 status
|= _extract_string_list_from_xpc_array(value
, &tmp
.alias_members_len
, (char ***)&tmp
.alias_members
);
1033 /* no parts check - this value is optional */
1038 if ((status
!= 0) || (parts
!= 0))
1040 free(tmp
.alias_members
);
1044 item
= (si_item_t
*)LI_ils_create("L4488s4*4", (unsigned long)si
, CATEGORY_ALIAS
, 1, valid_global
, valid_cat
, tmp
.alias_name
, tmp
.alias_members_len
, tmp
.alias_members
, tmp
.alias_local
);
1046 free(tmp
.alias_members
);
1052 _extract_alias(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1056 if (si
== NULL
) return NULL
;
1057 if (reply
== NULL
) return NULL
;
1059 type
= xpc_get_type(reply
);
1060 if (type
== XPC_TYPE_ARRAY
) return _extract_alias_array(si
, reply
, valid_global
, valid_cat
);
1061 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_alias_dict(si
, reply
, valid_global
, valid_cat
);
1071 * optional aliases : array of string
1076 _extract_network_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1081 int arraycount
= xpc_array_get_count(reply
);
1083 if ((arraycount
< 2) || (arraycount
> 3)) return NULL
;
1085 memset(&tmp
, 0, sizeof(tmp
));
1087 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.n_name
)) return NULL
;
1088 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.n_net
)) return NULL
;
1090 if (arraycount
== 3)
1092 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.n_aliases
)) return NULL
;
1096 tmp
.n_addrtype
= AF_INET
;
1098 item
= (si_item_t
*)LI_ils_create("L4488s*44", (unsigned long)si
, CATEGORY_NETWORK
, 1, valid_global
, valid_cat
, tmp
.n_name
, tmp
.n_aliases
, tmp
.n_addrtype
, tmp
.n_net
);
1100 free(tmp
.n_aliases
);
1106 _extract_network_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1109 __block
struct netent tmp
;
1110 __block
int status
= 0;
1111 __block
int parts
= 2;
1113 if (si
== NULL
) return NULL
;
1114 if (reply
== NULL
) return NULL
;
1116 tmp
.n_name
= (char *)"";
1117 tmp
.n_aliases
= NULL
;
1121 tmp
.n_addrtype
= AF_INET
;
1123 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1124 if (key
== NULL
) return true;
1125 else if (!strcmp(key
, "n_name"))
1127 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.n_name
);
1128 if (status
== 0) parts
--;
1130 else if (!strcmp(key
, "n_aliases"))
1132 status
|= _extract_string_list_from_xpc_array(value
, NULL
, (char ***)&tmp
.n_aliases
);
1133 /* no parts check - this value is optional */
1135 else if (!strcmp(key
, "n_net"))
1137 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.n_net
);
1138 if (status
== 0) parts
--;
1143 if ((status
!= 0) || (parts
!= 0))
1145 free(tmp
.n_aliases
);
1149 item
= (si_item_t
*)LI_ils_create("L4488s*44", (unsigned long)si
, CATEGORY_NETWORK
, 1, valid_global
, valid_cat
, tmp
.n_name
, tmp
.n_aliases
, tmp
.n_addrtype
, tmp
.n_net
);
1151 free(tmp
.n_aliases
);
1157 _extract_network(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1161 if (si
== NULL
) return NULL
;
1162 if (reply
== NULL
) return NULL
;
1164 type
= xpc_get_type(reply
);
1165 if (type
== XPC_TYPE_ARRAY
) return _extract_network_array(si
, reply
, valid_global
, valid_cat
);
1166 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_network_dict(si
, reply
, valid_global
, valid_cat
);
1177 * optional aliases : array of string
1182 _extract_service_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1187 int arraycount
= xpc_array_get_count(reply
);
1189 if ((arraycount
< 3) || (arraycount
> 4)) return NULL
;
1191 memset(&tmp
, 0, sizeof(tmp
));
1193 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.s_name
)) return NULL
;
1194 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.s_port
)) return NULL
;
1195 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.s_proto
)) return NULL
;
1197 if (arraycount
== 4)
1199 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.s_aliases
)) return NULL
;
1202 item
= (si_item_t
*)LI_ils_create("L4488s*4s", (unsigned long)si
, CATEGORY_SERVICE
, 1, valid_global
, valid_cat
, tmp
.s_name
, tmp
.s_aliases
, tmp
.s_port
, tmp
.s_proto
);
1204 free(tmp
.s_aliases
);
1210 _extract_service_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1213 __block
struct servent tmp
;
1214 __block
int status
= 0;
1215 __block
int parts
= 3;
1217 if (si
== NULL
) return NULL
;
1218 if (reply
== NULL
) return NULL
;
1220 tmp
.s_name
= (char *)"";
1221 tmp
.s_aliases
= NULL
;
1223 tmp
.s_proto
= (char *)"";
1225 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1226 if (key
== NULL
) return true;
1227 else if (!strcmp(key
, "s_name"))
1229 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.s_name
);
1230 if (status
== 0) parts
--;
1232 else if (!strcmp(key
, "s_aliases"))
1234 status
|= _extract_string_list_from_xpc_array(value
, NULL
, (char ***)&tmp
.s_aliases
);
1235 /* no parts check - this value is optional */
1237 else if (!strcmp(key
, "s_port"))
1240 status
|= _extract_uint32_from_xpc_object(value
, &v32
);
1243 tmp
.s_port
= (unsigned int)htons(v32
); // ugh
1247 else if (!strcmp(key
, "s_proto"))
1249 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.s_proto
);
1250 if (status
== 0) parts
--;
1255 if ((status
!= 0) || (parts
!= 0))
1257 free(tmp
.s_aliases
);
1261 item
= (si_item_t
*)LI_ils_create("L4488s*4s", (unsigned long)si
, CATEGORY_SERVICE
, 1, valid_global
, valid_cat
, tmp
.s_name
, tmp
.s_aliases
, tmp
.s_port
, tmp
.s_proto
);
1263 free(tmp
.s_aliases
);
1269 _extract_service(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1273 if (si
== NULL
) return NULL
;
1274 if (reply
== NULL
) return NULL
;
1276 type
= xpc_get_type(reply
);
1277 if (type
== XPC_TYPE_ARRAY
) return _extract_service_array(si
, reply
, valid_global
, valid_cat
);
1278 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_service_dict(si
, reply
, valid_global
, valid_cat
);
1288 * optional aliases : array of string
1292 _extract_protocol_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1295 struct protoent tmp
;
1297 int arraycount
= xpc_array_get_count(reply
);
1299 if ((arraycount
< 2) || (arraycount
> 3)) return NULL
;
1301 memset(&tmp
, 0, sizeof(tmp
));
1303 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.p_name
)) return NULL
;
1304 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.p_proto
)) return NULL
;
1306 if (arraycount
== 3)
1308 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.p_aliases
)) return NULL
;
1311 item
= (si_item_t
*)LI_ils_create("L4488s*4", (unsigned long)si
, CATEGORY_PROTOCOL
, 1, valid_global
, valid_cat
, tmp
.p_name
, tmp
.p_aliases
, tmp
.p_proto
);
1313 free(tmp
.p_aliases
);
1319 _extract_protocol_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1322 __block
struct protoent tmp
;
1323 __block
int status
= 0;
1324 __block
int parts
= 2;
1326 tmp
.p_name
= (char *)"";
1328 tmp
.p_aliases
= NULL
;
1330 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1331 if (key
== NULL
) return true;
1332 else if (!strcmp(key
, "p_name"))
1334 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.p_name
);
1335 if (status
== 0) parts
--;
1337 else if (!strcmp(key
, "p_proto"))
1339 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.p_proto
);
1340 if (status
== 0) parts
--;
1342 else if (!strcmp(key
, "p_aliases"))
1344 status
|= _extract_string_list_from_xpc_array(value
, NULL
, (char ***)&tmp
.p_aliases
);
1345 /* no parts check - this value is optional */
1350 if ((status
!= 0) || (parts
!= 0))
1352 free(tmp
.p_aliases
);
1356 item
= (si_item_t
*)LI_ils_create("L4488s*4", (unsigned long)si
, CATEGORY_PROTOCOL
, 1, valid_global
, valid_cat
, tmp
.p_name
, tmp
.p_aliases
, tmp
.p_proto
);
1358 free(tmp
.p_aliases
);
1364 _extract_protocol(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1368 if (si
== NULL
) return NULL
;
1369 if (reply
== NULL
) return NULL
;
1371 type
= xpc_get_type(reply
);
1372 if (type
== XPC_TYPE_ARRAY
) return _extract_protocol_array(si
, reply
, valid_global
, valid_cat
);
1373 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_protocol_dict(si
, reply
, valid_global
, valid_cat
);
1383 * optional aliases : array of string
1388 _extract_rpc_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1393 int arraycount
= xpc_array_get_count(reply
);
1395 if ((arraycount
< 2) || (arraycount
> 3)) return NULL
;
1397 memset(&tmp
, 0, sizeof(tmp
));
1399 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.r_name
)) return NULL
;
1400 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.r_number
)) return NULL
;
1402 if (arraycount
== 3)
1404 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.r_aliases
)) return NULL
;
1407 item
= (si_item_t
*)LI_ils_create("L4488s*4", (unsigned long)si
, CATEGORY_RPC
, 1, valid_global
, valid_cat
, tmp
.r_name
, tmp
.r_aliases
, tmp
.r_number
);
1409 free(tmp
.r_aliases
);
1415 _extract_rpc_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1418 __block
struct rpcent tmp
;
1419 __block
int status
= 0;
1420 __block
int parts
= 2;
1422 tmp
.r_name
= (char *)"";
1424 tmp
.r_aliases
= NULL
;
1426 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1427 if (key
== NULL
) return true;
1428 else if (!strcmp(key
, "r_name"))
1430 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.r_name
);
1431 if (status
== 0) parts
--;
1433 else if (!strcmp(key
, "r_number"))
1435 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.r_number
);
1436 if (status
== 0) parts
--;
1438 else if (!strcmp(key
, "r_aliases"))
1440 status
|= _extract_string_list_from_xpc_array(value
, NULL
, (char ***)&tmp
.r_aliases
);
1441 /* no parts check - this value is optional */
1446 if ((status
!= 0) || (parts
!= 0))
1448 free(tmp
.r_aliases
);
1452 item
= (si_item_t
*)LI_ils_create("L4488s*4", (unsigned long)si
, CATEGORY_RPC
, 1, valid_global
, valid_cat
, tmp
.r_name
, tmp
.r_aliases
, tmp
.r_number
);
1454 free(tmp
.r_aliases
);
1460 _extract_rpc(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1464 if (si
== NULL
) return NULL
;
1465 if (reply
== NULL
) return NULL
;
1467 type
= xpc_get_type(reply
);
1468 if (type
== XPC_TYPE_ARRAY
) return _extract_rpc_array(si
, reply
, valid_global
, valid_cat
);
1469 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_rpc_dict(si
, reply
, valid_global
, valid_cat
);
1487 _extract_fstab_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1489 __block
struct fstab tmp
;
1492 if (xpc_array_get_count(reply
) != 7) return NULL
;
1494 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.fs_file
)) return NULL
;
1495 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.fs_spec
)) return NULL
;
1496 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.fs_freq
)) return NULL
;
1497 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.fs_passno
)) return NULL
;
1498 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.fs_mntops
)) return NULL
;
1499 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.fs_type
)) return NULL
;
1500 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.fs_vfstype
)) return NULL
;
1502 return (si_item_t
*)LI_ils_create("L4488sssss44", (unsigned long)si
, CATEGORY_FS
, 1, valid_global
, valid_cat
, tmp
.fs_spec
, tmp
.fs_file
, tmp
.fs_vfstype
, tmp
.fs_mntops
, tmp
.fs_type
, tmp
.fs_freq
, tmp
.fs_passno
);
1506 _extract_fstab_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1508 __block
struct fstab tmp
;
1509 __block
int status
= 0;
1510 __block
int parts
= 7;
1513 tmp
.fs_spec
= (char *)"";
1516 tmp
.fs_mntops
= (char *)"";
1517 tmp
.fs_type
= (char *)"";
1518 tmp
.fs_vfstype
= (char *)"";
1520 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1521 if (key
== NULL
) return true;
1522 else if (!strcmp(key
, "fs_file"))
1524 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.fs_file
);
1525 if (status
== 0) parts
--;
1527 else if (!strcmp(key
, "fs_spec"))
1529 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.fs_spec
);
1530 if (status
== 0) parts
--;
1532 else if (!strcmp(key
, "fs_freq"))
1534 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.fs_freq
);
1535 if (status
== 0) parts
--;
1537 else if (!strcmp(key
, "fs_passno"))
1539 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.fs_passno
);
1540 if (status
== 0) parts
--;
1542 else if (!strcmp(key
, "fs_mntops"))
1544 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.fs_mntops
);
1545 if (status
== 0) parts
--;
1547 else if (!strcmp(key
, "fs_type"))
1549 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.fs_type
);
1550 if (status
== 0) parts
--;
1552 else if (!strcmp(key
, "fs_vfstype"))
1554 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.fs_vfstype
);
1555 if (status
== 0) parts
--;
1560 if ((status
!= 0) || (parts
!= 0)) return NULL
;
1562 return (si_item_t
*)LI_ils_create("L4488sssss44", (unsigned long)si
, CATEGORY_FS
, 1, valid_global
, valid_cat
, tmp
.fs_spec
, tmp
.fs_file
, tmp
.fs_vfstype
, tmp
.fs_mntops
, tmp
.fs_type
, tmp
.fs_freq
, tmp
.fs_passno
);
1566 _extract_fstab(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1570 if (si
== NULL
) return NULL
;
1571 if (reply
== NULL
) return NULL
;
1573 type
= xpc_get_type(reply
);
1574 if (type
== XPC_TYPE_ARRAY
) return _extract_fstab_array(si
, reply
, valid_global
, valid_cat
);
1575 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_fstab_dict(si
, reply
, valid_global
, valid_cat
);
1581 _extract_mac_mac(si_mod_t
*si
, xpc_object_t reply
, const void *extra
, uint64_t valid_global
, uint64_t valid_cat
)
1585 const char *value
= NULL
;
1588 if (si
== NULL
) return NULL
;
1589 if (reply
== NULL
) return NULL
;
1590 if (extra
== NULL
) return NULL
;
1592 type
= xpc_get_type(reply
);
1593 if (type
== XPC_TYPE_ARRAY
)
1595 if (xpc_array_get_count(reply
) >= 1)
1597 if (0 != _extract_string_from_xpc_array_index(reply
, 0, (const char **)&value
)) return NULL
;
1600 else if (type
== XPC_TYPE_DICTIONARY
)
1602 if (0 != _extract_string_from_xpc_dict(reply
, "mac", &value
)) return NULL
;
1605 if (value
== NULL
|| value
[0] == '\0') return NULL
;
1607 cmac
= si_standardize_mac_address(value
);
1608 if (cmac
== NULL
) return NULL
;
1610 out
= (si_item_t
*)LI_ils_create("L4488ss", (unsigned long)si
, CATEGORY_MAC
, 1, valid_global
, valid_cat
, extra
, cmac
);
1618 _extract_mac_name(si_mod_t
*si
, xpc_object_t reply
, const void *extra
, uint64_t valid_global
, uint64_t valid_cat
)
1621 const char *name
= NULL
;
1624 if (si
== NULL
) return NULL
;
1625 if (reply
== NULL
) return NULL
;
1626 if (extra
== NULL
) return NULL
;
1628 type
= xpc_get_type(reply
);
1629 if (type
== XPC_TYPE_ARRAY
)
1631 if (xpc_array_get_count(reply
) >= 1)
1633 if (0 != _extract_string_from_xpc_array_index(reply
, 0, (const char **)&name
)) return NULL
;
1636 else if (type
== XPC_TYPE_DICTIONARY
)
1638 if (0 != _extract_string_from_xpc_dict(reply
, "name", &name
)) return NULL
;
1641 if (name
== NULL
) return NULL
;
1643 out
= (si_item_t
*)LI_ils_create("L4488ss", (unsigned long)si
, CATEGORY_MAC
, 1, valid_global
, valid_cat
, name
, extra
);
1651 ds_user_byname(si_mod_t
*si
, const char *name
)
1653 xpc_object_t payload
;
1656 if (!_od_running()) return NULL
;
1658 payload
= _xpc_query_key_string("name", name
);
1659 if (payload
== NULL
) return NULL
;
1661 item
= _ds_item(si
, CATEGORY_USER
, "getpwnam", NULL
, _extract_user
, payload
);
1663 xpc_release(payload
);
1668 ds_user_byuid(si_mod_t
*si
, uid_t uid
)
1670 xpc_object_t payload
;
1673 if (!_od_running()) return NULL
;
1675 payload
= _xpc_query_key_id("uid", uid
);
1676 if (payload
== NULL
) return NULL
;
1678 item
= _ds_item(si
, CATEGORY_USER
, "getpwuid", NULL
, _extract_user
, payload
);
1680 xpc_release(payload
);
1685 ds_user_byuuid(si_mod_t
*si
, uuid_t uuid
)
1687 xpc_object_t payload
;
1690 if (!_od_running()) return NULL
;
1692 payload
= _xpc_query_key_uuid("uuid", uuid
);
1693 if (payload
== NULL
) return NULL
;
1695 item
= _ds_item(si
, CATEGORY_USER
, "getpwuuid", NULL
, _extract_user
, payload
);
1697 xpc_release(payload
);
1702 ds_user_all(si_mod_t
*si
)
1704 return _ds_list(si
, CATEGORY_USER
, "getpwent", NULL
, _extract_user
);
1708 ds_group_byname(si_mod_t
*si
, const char *name
)
1710 xpc_object_t payload
;
1713 if (!_od_running()) return NULL
;
1715 payload
= _xpc_query_key_string("name", name
);
1716 if (payload
== NULL
) return NULL
;
1718 item
= _ds_item(si
, CATEGORY_GROUP
, "getgrnam", NULL
, _extract_group
, payload
);
1720 xpc_release(payload
);
1725 ds_group_bygid(si_mod_t
*si
, gid_t gid
)
1727 xpc_object_t payload
;
1730 if (!_od_running()) return NULL
;
1732 payload
= _xpc_query_key_id("gid", gid
);
1733 if (payload
== NULL
) return NULL
;
1735 item
= _ds_item(si
, CATEGORY_GROUP
, "getgrgid", NULL
, _extract_group
, payload
);
1737 xpc_release(payload
);
1742 ds_group_byuuid(si_mod_t
*si
, uuid_t uuid
)
1744 xpc_object_t payload
;
1747 if (!_od_running()) return NULL
;
1749 payload
= _xpc_query_key_uuid("uuid", uuid
);
1750 if (payload
== NULL
) return NULL
;
1752 item
= _ds_item(si
, CATEGORY_GROUP
, "getgruuid", NULL
, _extract_group
, payload
);
1754 xpc_release(payload
);
1759 ds_group_all(si_mod_t
*si
)
1761 if (!_od_running()) return NULL
;
1762 return _ds_list(si
, CATEGORY_GROUP
, "getgrent", NULL
, _extract_group
);
1766 ds_grouplist(si_mod_t
*si
, const char *name
, uint32_t ngroups
)
1768 xpc_object_t payload
, reply
;
1769 si_item_t
*item
= NULL
;
1771 if (!_od_running()) return NULL
;
1772 if (name
== NULL
) return NULL
;
1774 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
1775 if (payload
== NULL
) return NULL
;
1777 xpc_dictionary_set_string(payload
, "name", name
);
1778 xpc_dictionary_set_int64(payload
, "ngroups", ngroups
);
1780 reply
= _od_rpc_call("getgrouplist", payload
, _od_xpc_pipe
);
1781 if (reply
!= NULL
) {
1783 const gid_t
*gidptr
= xpc_dictionary_get_data(reply
, "groups", &gidptrsz
);
1787 _ds_get_validation(si
, &va
, &vb
, CATEGORY_GROUPLIST
);
1789 /* see what we were sent */
1790 if (0 == _extract_uint32_from_xpc_dict(reply
, "count", &count
))
1794 item
= (si_item_t
*)LI_ils_create("L4488s4@", (unsigned long)si
, CATEGORY_GROUPLIST
, 1, va
, vb
, name
, count
,
1802 xpc_release(payload
);
1808 ds_netgroup_byname(si_mod_t
*si
, const char *name
)
1810 xpc_object_t payload
;
1811 si_list_t
*list
= NULL
;
1814 if (!_od_running()) return NULL
;
1816 payload
= _xpc_query_key_string("netgroup", name
);
1817 if (payload
== NULL
) return NULL
;
1819 item
= _ds_item(si
, CATEGORY_NETGROUP
, "getnetgrent", NULL
, _extract_netgroup
, payload
);
1821 list
= si_list_add(list
, item
);
1822 si_item_release(item
);
1825 xpc_release(payload
);
1831 ds_in_netgroup(si_mod_t
*si
, const char *group
, const char *host
, const char *user
, const char *domain
)
1833 xpc_object_t payload
, reply
;
1836 if (!_od_running()) return 0;
1838 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
1839 if (payload
== NULL
) return 0;
1841 xpc_dictionary_set_string(payload
, "netgroup", (group
? group
: ""));
1842 xpc_dictionary_set_string(payload
, "host", (host
? host
: ""));
1843 xpc_dictionary_set_string(payload
, "user", (user
? user
: ""));
1844 xpc_dictionary_set_string(payload
, "domain", (domain
? domain
: ""));
1846 reply
= _od_rpc_call("innetgr", payload
, _od_xpc_pipe
);
1847 if (reply
!= NULL
) {
1848 is_innetgr
= xpc_dictionary_get_bool(reply
, OD_RPC_RESULT
);
1854 xpc_release(payload
);
1860 ds_alias_byname(si_mod_t
*si
, const char *name
)
1862 xpc_object_t payload
;
1865 if (!_od_running()) return NULL
;
1867 payload
= _xpc_query_key_string("name", name
);
1868 if (payload
== NULL
) return NULL
;
1870 item
= _ds_item(si
, CATEGORY_ALIAS
, "alias_getbyname", NULL
, _extract_alias
, payload
);
1872 xpc_release(payload
);
1877 ds_alias_all(si_mod_t
*si
)
1879 if (!_od_running()) return NULL
;
1880 return _ds_list(si
, CATEGORY_ALIAS
, "alias_getent", NULL
, _extract_alias
);
1884 ds_network_byname(si_mod_t
*si
, const char *name
)
1886 xpc_object_t payload
;
1889 if (!_od_running()) return NULL
;
1891 payload
= _xpc_query_key_string("name", name
);
1892 if (payload
== NULL
) return NULL
;
1894 item
= _ds_item(si
, CATEGORY_NETWORK
, "getnetbyname", NULL
, _extract_network
, payload
);
1896 xpc_release(payload
);
1901 ds_network_byaddr(si_mod_t
*si
, uint32_t addr
)
1903 unsigned char f1
, f2
, f3
;
1905 xpc_object_t payload
;
1908 if (!_od_running()) return NULL
;
1916 if (f3
!= 0) snprintf(val
, sizeof(val
), "%u.%u.%u", f3
, f2
, f1
);
1917 else if (f2
!= 0) snprintf(val
, sizeof(val
), "%u.%u", f2
, f1
);
1918 else snprintf(val
, sizeof(val
), "%u", f1
);
1920 payload
= _xpc_query_key_string("net", val
);
1921 if (payload
== NULL
) return NULL
;
1923 item
= _ds_item(si
, CATEGORY_NETWORK
, "getnetbyaddr", NULL
, _extract_network
, payload
);
1925 xpc_release(payload
);
1930 ds_network_all(si_mod_t
*si
)
1932 if (!_od_running()) return NULL
;
1933 return _ds_list(si
, CATEGORY_NETWORK
, "getnetent", NULL
, _extract_network
);
1937 ds_service_byname(si_mod_t
*si
, const char *name
, const char *proto
)
1939 xpc_object_t payload
;
1943 if (!_od_running()) return NULL
;
1944 if (name
== NULL
) name
= "";
1945 if (proto
== NULL
) proto
= "";
1947 /* Check our local service cache (see ds_addrinfo). */
1948 item
= pthread_getspecific(_ds_serv_cache_key
);
1951 s
= (struct servent
*)((uintptr_t)item
+ sizeof(si_item_t
));
1952 if (string_equal(name
, s
->s_name
)) return si_item_retain(item
);
1955 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
1956 if (payload
== NULL
) return NULL
;
1958 xpc_dictionary_set_string(payload
, "name", name
);
1959 xpc_dictionary_set_string(payload
, "proto", proto
);
1961 item
= _ds_item(si
, CATEGORY_SERVICE
, "getservbyname", NULL
, _extract_service
, payload
);
1963 xpc_release(payload
);
1969 ds_service_byport(si_mod_t
*si
, int port
, const char *proto
)
1971 xpc_object_t payload
;
1974 if (!_od_running()) return NULL
;
1976 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
1977 if (payload
== NULL
) return NULL
;
1979 /* swap to native order, API passes network order */
1980 xpc_dictionary_set_int64(payload
, "port", ntohs(port
));
1981 xpc_dictionary_set_string(payload
, "proto", (proto
? proto
: ""));
1983 item
= _ds_item(si
, CATEGORY_SERVICE
, "getservbyport", NULL
, _extract_service
, payload
);
1985 xpc_release(payload
);
1991 ds_service_all(si_mod_t
*si
)
1993 if (!_od_running()) return NULL
;
1994 return _ds_list(si
, CATEGORY_SERVICE
, "getservent", NULL
, _extract_service
);
1998 ds_protocol_byname(si_mod_t
*si
, const char *name
)
2000 xpc_object_t payload
;
2003 if (!_od_running()) return NULL
;
2005 payload
= _xpc_query_key_string("name", name
);
2006 if (payload
== NULL
) return NULL
;
2008 item
= _ds_item(si
, CATEGORY_PROTOCOL
, "getprotobyname", NULL
, _extract_protocol
, payload
);
2010 xpc_release(payload
);
2015 ds_protocol_bynumber(si_mod_t
*si
, int number
)
2017 xpc_object_t payload
;
2020 if (!_od_running()) return NULL
;
2022 payload
= _xpc_query_key_int("number", number
);
2023 if (payload
== NULL
) return NULL
;
2025 item
= _ds_item(si
, CATEGORY_PROTOCOL
, "getprotobynumber", NULL
, _extract_protocol
, payload
);
2027 xpc_release(payload
);
2032 ds_protocol_all(si_mod_t
*si
)
2034 return _ds_list(si
, CATEGORY_PROTOCOL
, "getprotoent", NULL
, _extract_protocol
);
2038 ds_rpc_byname(si_mod_t
*si
, const char *name
)
2040 xpc_object_t payload
;
2043 if (!_od_running()) return NULL
;
2045 payload
= _xpc_query_key_string("name", name
);
2046 if (payload
== NULL
) return NULL
;
2048 item
= _ds_item(si
, CATEGORY_RPC
, "getrpcbyname", NULL
, _extract_rpc
, payload
);
2050 xpc_release(payload
);
2055 ds_rpc_bynumber(si_mod_t
*si
, int number
)
2057 xpc_object_t payload
;
2060 if (!_od_running()) return NULL
;
2062 payload
= _xpc_query_key_int("number", number
);
2063 if (payload
== NULL
) return NULL
;
2065 item
= _ds_item(si
, CATEGORY_RPC
, "getrpcbynumber", NULL
, _extract_rpc
, payload
);
2067 xpc_release(payload
);
2072 ds_rpc_all(si_mod_t
*si
)
2074 return _ds_list(si
, CATEGORY_RPC
, "getrpcent", NULL
, _extract_rpc
);
2078 ds_fs_byspec(si_mod_t
*si
, const char *name
)
2080 xpc_object_t payload
;
2083 if (!_od_running()) return NULL
;
2085 payload
= _xpc_query_key_string("name", name
);
2086 if (payload
== NULL
) return NULL
;
2088 item
= _ds_item(si
, CATEGORY_FS
, "getfsbyname", NULL
, _extract_fstab
, payload
);
2090 xpc_release(payload
);
2095 ds_fs_all(si_mod_t
*si
)
2097 return _ds_list(si
, CATEGORY_FS
, "getfsent", NULL
, _extract_fstab
);
2101 ds_fs_byfile(si_mod_t
*si
, const char *name
)
2108 if (!_od_running()) return NULL
;
2109 if (name
== NULL
) return NULL
;
2111 list
= ds_fs_all(si
);
2112 if (list
== NULL
) return NULL
;
2115 for (i
= 0; (i
< list
->count
) && (item
== NULL
); i
++)
2117 f
= (struct fstab
*)((uintptr_t)(list
->entry
[i
]) + sizeof(si_item_t
));
2118 if (string_equal(name
, f
->fs_file
)) item
= si_item_retain(list
->entry
[i
]);
2121 si_list_release(list
);
2126 ds_mac_byname(si_mod_t
*si
, const char *name
)
2128 xpc_object_t payload
;
2131 if (!_od_running()) return NULL
;
2133 payload
= _xpc_query_key_string("name", name
);
2134 if (payload
== NULL
) return NULL
;
2136 item
= _ds_item(si
, CATEGORY_MAC
, "getmacbyname", name
, _extract_mac_mac
, payload
);
2138 xpc_release(payload
);
2143 ds_mac_bymac(si_mod_t
*si
, const char *mac
)
2145 xpc_object_t payload
;
2149 if (!_od_running()) return NULL
;
2151 cmac
= si_standardize_mac_address(mac
);
2152 if (cmac
== NULL
) return NULL
;
2154 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
2155 if (payload
== NULL
) return NULL
;
2157 payload
= _xpc_query_key_string("mac", cmac
);
2158 item
= _ds_item(si
, CATEGORY_MAC
, "gethostbymac", cmac
, _extract_mac_name
, payload
);
2161 xpc_release(payload
);
2169 si_module_static_ds(void)
2171 static const struct si_mod_vtable_s ds_vtable
=
2173 .sim_is_valid
= &_ds_is_valid
,
2175 .sim_user_byname
= &ds_user_byname
,
2176 .sim_user_byuid
= &ds_user_byuid
,
2177 .sim_user_byuuid
= &ds_user_byuuid
,
2178 .sim_user_all
= &ds_user_all
,
2180 .sim_group_byname
= &ds_group_byname
,
2181 .sim_group_bygid
= &ds_group_bygid
,
2182 .sim_group_byuuid
= &ds_group_byuuid
,
2183 .sim_group_all
= &ds_group_all
,
2185 .sim_grouplist
= &ds_grouplist
,
2187 .sim_netgroup_byname
= &ds_netgroup_byname
,
2188 .sim_in_netgroup
= &ds_in_netgroup
,
2190 .sim_alias_byname
= &ds_alias_byname
,
2191 .sim_alias_all
= &ds_alias_all
,
2193 /* host lookups not supported */
2194 .sim_host_byname
= NULL
,
2195 .sim_host_byaddr
= NULL
,
2196 .sim_host_all
= NULL
,
2198 .sim_network_byname
= &ds_network_byname
,
2199 .sim_network_byaddr
= &ds_network_byaddr
,
2200 .sim_network_all
= &ds_network_all
,
2202 .sim_service_byname
= &ds_service_byname
,
2203 .sim_service_byport
= &ds_service_byport
,
2204 .sim_service_all
= &ds_service_all
,
2206 .sim_protocol_byname
= &ds_protocol_byname
,
2207 .sim_protocol_bynumber
= &ds_protocol_bynumber
,
2208 .sim_protocol_all
= &ds_protocol_all
,
2210 .sim_rpc_byname
= &ds_rpc_byname
,
2211 .sim_rpc_bynumber
= &ds_rpc_bynumber
,
2212 .sim_rpc_all
= &ds_rpc_all
,
2214 .sim_fs_byspec
= &ds_fs_byspec
,
2215 .sim_fs_byfile
= &ds_fs_byfile
,
2216 .sim_fs_all
= &ds_fs_all
,
2218 .sim_mac_byname
= &ds_mac_byname
,
2219 .sim_mac_bymac
= &ds_mac_bymac
,
2221 /* si_mac_all not supported */
2222 .sim_mac_all
= NULL
,
2224 /* si_addrinfo not supported */
2225 .sim_wants_addrinfo
= NULL
,
2226 .sim_addrinfo
= NULL
,
2229 static si_mod_t si
=
2233 .flags
= SI_MOD_FLAG_STATIC
,
2236 .vtable
= &ds_vtable
,
2239 static dispatch_once_t once
;
2240 dispatch_once(&once
, ^{
2241 pthread_key_create(&_ds_serv_cache_key
, _ds_serv_cache_free
);
2243 si
.name
= strdup("ds");
2244 ds_si_private_t
*pp
= calloc(1, sizeof(ds_si_private_t
));
2248 pp
->notify_token_global
= -1;
2249 pp
->notify_token_user
= -1;
2250 pp
->notify_token_group
= -1;
2251 pp
->notify_token_service
= -1;
2255 * Don't register for notifications if the cache is disabled.
2256 * notifyd (notably) disables the cache to prevent deadlocks.
2258 if (gL1CacheEnabled
!= 0)
2261 * Errors in registering for cache invalidation notifications are ignored.
2262 * If there are failures, the tokens remain set to -1 which just causes
2263 * cached items to be invalidated.
2265 notify_register_check(kNotifyDSCacheInvalidation
, &(pp
->notify_token_global
));
2266 notify_register_check(kNotifyDSCacheInvalidationUser
, &(pp
->notify_token_user
));
2267 notify_register_check(kNotifyDSCacheInvalidationGroup
, &(pp
->notify_token_group
));
2268 notify_register_check(kNotifyDSCacheInvalidationService
, &(pp
->notify_token_service
));
2277 #endif /* DS_AVAILABLE */