2 * Copyright (c) 2008-2018 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@
26 #include "libinfo_common.h"
34 #include <arpa/inet.h>
43 #include <notify_keys.h>
45 #include <si_module.h>
46 #include <netdb_async.h>
49 #include <xpc/private.h>
50 #include <opendirectory/odipc.h>
51 #include <servers/bootstrap.h>
52 #include <bootstrap_priv.h>
53 #include <opendirectory/DSlibinfoMIG_types.h>
54 #include <os/activity.h>
57 #define IPV6_ADDR_LEN 16
58 #define IPV4_ADDR_LEN 4
60 /* The LI_OS_ACTIVITY macro contains os_activity_t functions
61 * that are not POSIX compliant. So calling them may
62 * inadvertantly change errno. To avoid this, the macro
63 * explicityly restores the errno to its state on entry
66 * Macro cannot contain any {} because it will end the scope
67 * of the activity prematurely
69 #define _LI_OS_ACTIVITY(_var, _desc) \
71 os_activity_t activity __attribute__((__cleanup__(_li_auto_os_release))) = os_activity_create(_desc, OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); \
72 os_activity_scope(activity); \
75 #define LI_OS_ACTIVITY(_desc) _LI_OS_ACTIVITY(OS_CONCAT(errnosav, __COUNTER__), _desc)
77 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
);
80 uint32_t notify_peek(int token
, uint32_t *val
);
84 int notify_token_global
;
85 int notify_token_user
;
86 int notify_token_group
;
87 int notify_token_service
;
90 extern uint32_t gL1CacheEnabled
;
91 extern int _si_opendirectory_disabled
;
93 static pthread_key_t _ds_serv_cache_key
= 0;
94 static xpc_pipe_t __od_pipe
; /* use accessor only */
95 static pthread_mutex_t mutex
= PTHREAD_MUTEX_INITIALIZER
;
102 // re-enable opendirectory interaction since we forked
103 _si_opendirectory_disabled
= 0;
105 if (__od_pipe
!= NULL
) {
106 xpc_pipe_invalidate(__od_pipe
);
107 /* disable release due to 10649340, it will cause a minor leak for each fork without exec */
108 // xpc_release(__od_pipe);
111 _ds_port
= MACH_PORT_NULL
;
112 pthread_mutex_unlock(&mutex
);
116 _od_fork_prepare(void)
118 pthread_mutex_lock(&mutex
);
122 _od_fork_parent(void)
124 pthread_mutex_unlock(&mutex
);
128 _ds_serv_cache_free(void *x
)
130 if (x
!= NULL
) si_item_release(x
);
135 _si_disable_opendirectory(void)
137 _si_opendirectory_disabled
= 1;
138 _ds_port
= MACH_PORT_NULL
;
142 _li_auto_os_release(os_activity_t
*activity
)
144 os_release(*activity
);
150 _od_xpc_pipe(bool resetPipe
)
152 static dispatch_once_t once
;
153 xpc_pipe_t result
= NULL
;
155 dispatch_once(&once
, ^(void) {
158 /* if this is a build environment we ignore opendirectoryd */
159 xbs_disable
= getenv("XBS_DISABLE_LIBINFO");
160 if ((issetugid() == 0) && (xbs_disable
!= NULL
) && (strcmp(xbs_disable
, "YES") == 0)) {
161 _si_opendirectory_disabled
= 1;
165 pthread_atfork(_od_fork_prepare
, _od_fork_parent
, _od_fork_child
);
168 if (_si_opendirectory_disabled
== 1) {
172 pthread_mutex_lock(&mutex
);
174 xpc_release(__od_pipe
);
178 if (__od_pipe
== NULL
) {
179 if (!issetugid() && getenv("OD_DEBUG_MODE") != NULL
) {
180 __od_pipe
= xpc_pipe_create(kODMachLibinfoPortNameDebug
, 0);
182 __od_pipe
= xpc_pipe_create(kODMachLibinfoPortName
, XPC_PIPE_FLAG_PRIVILEGED
);
186 if (__od_pipe
!= NULL
) result
= xpc_retain(__od_pipe
);
187 pthread_mutex_unlock(&mutex
);
197 pipe
= _od_xpc_pipe(false);
202 if (_si_opendirectory_disabled
) {
206 return (pipe
!= NULL
);
212 _ds_port
= MACH_PORT_NULL
;
219 kern_return_t status
;
220 char *od_debug_mode
= NULL
;
222 if (_ds_port
!= MACH_PORT_NULL
) return 1;
224 if (_si_opendirectory_disabled
) return 0;
225 pthread_atfork(NULL
, NULL
, _ds_child
);
228 od_debug_mode
= getenv("OD_DEBUG_MODE");
232 status
= bootstrap_look_up(bootstrap_port
, kDSStdMachDSLookupPortName
"_debug", &_ds_port
);
234 status
= bootstrap_look_up2(bootstrap_port
, kDSStdMachDSLookupPortName
, &_ds_port
, 0, BOOTSTRAP_PRIVILEGED_SERVER
);
236 if ((status
!= BOOTSTRAP_SUCCESS
) && (status
!= BOOTSTRAP_UNKNOWN_SERVICE
)) _ds_port
= MACH_PORT_NULL
;
238 return (_ds_port
!= MACH_PORT_NULL
);
242 _valid_token(xpc_object_t reply
)
247 * This should really call audit_token_to_au32,
248 * but that's in libbsm, not in a Libsystem library.
250 xpc_dictionary_get_audit_token(reply
, &token
);
252 return ((uid_t
) token
.val
[1] == 0);
256 _ds_get_validation(si_mod_t
*si
, uint64_t *a
, uint64_t *b
, int cat
)
262 if (si
== NULL
) return;
264 pp
= (ds_si_private_t
*)si
->private;
265 if (pp
== NULL
) return;
270 status
= notify_peek(pp
->notify_token_global
, &peek
);
271 if (status
== NOTIFY_STATUS_OK
) *a
= ntohl(peek
);
278 status
= NOTIFY_STATUS_FAILED
;
280 if (cat
== CATEGORY_USER
) status
= notify_peek(pp
->notify_token_user
, &peek
);
281 else if (cat
== CATEGORY_GROUP
) status
= notify_peek(pp
->notify_token_group
, &peek
);
282 else if (cat
== CATEGORY_GROUPLIST
) status
= notify_peek(pp
->notify_token_group
, &peek
);
283 else if (cat
== CATEGORY_SERVICE
) status
= notify_peek(pp
->notify_token_service
, &peek
);
285 if (status
== NOTIFY_STATUS_OK
) *b
= ntohl(peek
);
290 __private_extern__ xpc_object_t
291 _od_rpc_call(const char *procname
, xpc_object_t payload
, xpc_pipe_t (*get_pipe
)(bool))
293 xpc_object_t result
= NULL
;
297 bool free_payload
= false;
299 od_pipe
= get_pipe(false);
300 if (od_pipe
== NULL
) return NULL
;
302 if (payload
== NULL
) {
303 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
307 // we nest it for backward compatibility so we can do independent submissions
308 xpc_dictionary_set_string(payload
, OD_RPC_NAME
, procname
);
309 xpc_dictionary_set_int64(payload
, OD_RPC_VERSION
, 2);
311 for (retries
= 0; od_pipe
!= NULL
&& retries
< 2; retries
++) {
312 rc
= xpc_pipe_routine(od_pipe
, payload
, &reply
);
315 xpc_release(od_pipe
);
316 od_pipe
= get_pipe(true);
320 /* just loop and try to send again */
324 if (_valid_token(reply
) == true) {
327 /* fall through since we got a valid response */
330 /* release and NULL the pipe it'll break the loop */
331 xpc_release(od_pipe
);
337 if (od_pipe
!= NULL
) {
338 xpc_release(od_pipe
);
342 xpc_release(payload
);
349 _ds_list(si_mod_t
*si
, int cat
, const char *procname
, const void *extra
, od_extract_t extract
)
351 __block si_list_t
*list
;
352 uint64_t va
= 0, vb
= 0;
353 xpc_object_t reply
, result
;
355 if (procname
== NULL
) return NULL
;
357 _ds_get_validation(si
, &va
, &vb
, cat
);
360 reply
= _od_rpc_call(procname
, NULL
, _od_xpc_pipe
);
362 result
= xpc_dictionary_get_value(reply
, OD_RPC_RESULT
);
363 if (result
!= NULL
&& xpc_get_type(result
) == XPC_TYPE_ARRAY
) {
364 xpc_array_apply(result
, ^bool(size_t index
, xpc_object_t value
) {
365 si_item_t
*item
= extract(si
, value
, extra
, va
, vb
);
366 list
= si_list_add(list
, item
);
367 si_item_release(item
);
380 _ds_item(si_mod_t
*si
, int cat
, const char *procname
, const void *extra
, od_extract_t extract
, xpc_object_t payload
)
383 uint64_t va
= 0, vb
= 0;
384 si_item_t
*item
= NULL
;
386 if (procname
== NULL
) return NULL
;
388 result
= _od_rpc_call(procname
, payload
, _od_xpc_pipe
);
389 if (result
!= NULL
) {
390 _ds_get_validation(si
, &va
, &vb
, cat
);
391 if (xpc_dictionary_get_int64(result
, OD_RPC_ERROR
) == 0) {
392 item
= extract(si
, result
, extra
, va
, vb
);
402 _ds_is_valid(si_mod_t
*si
, si_item_t
*item
)
407 uint32_t oldval
, newval
;
409 if (si
== NULL
) return 0;
410 if (item
== NULL
) return 0;
411 if (si
->name
== NULL
) return 0;
412 if (item
->src
== NULL
) return 0;
414 pp
= (ds_si_private_t
*)si
->private;
415 if (pp
== NULL
) return 0;
417 src
= (si_mod_t
*)item
->src
;
419 if (src
->name
== NULL
) return 0;
420 if (string_not_equal(si
->name
, src
->name
)) return 0;
422 /* check global invalidation */
423 oldval
= item
->validation_a
;
425 status
= notify_peek(pp
->notify_token_global
, &newval
);
426 if (status
!= NOTIFY_STATUS_OK
) return 0;
428 newval
= ntohl(newval
);
429 if (oldval
!= newval
) return 0;
431 oldval
= item
->validation_b
;
433 if (item
->type
== CATEGORY_USER
) status
= notify_peek(pp
->notify_token_user
, &newval
);
434 else if (item
->type
== CATEGORY_GROUP
) status
= notify_peek(pp
->notify_token_group
, &newval
);
435 else if (item
->type
== CATEGORY_SERVICE
) status
= notify_peek(pp
->notify_token_service
, &newval
);
438 if (status
!= NOTIFY_STATUS_OK
) return 0;
440 newval
= ntohl(newval
);
441 if (oldval
!= newval
) return 0;
447 _xpc_query_key_string(const char *key
, const char *value
)
449 xpc_object_t payload
;
451 if (value
== NULL
) return NULL
;
453 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
454 if (payload
== NULL
) return NULL
;
456 xpc_dictionary_set_string(payload
, key
, value
);
462 _xpc_query_key_id(const char *key
, id_t idValue
)
464 xpc_object_t payload
;
466 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
467 if (payload
== NULL
) return NULL
;
469 xpc_dictionary_set_int64(payload
, key
, idValue
);
475 _xpc_query_key_uuid(const char *key
, uuid_t uu
)
477 xpc_object_t payload
;
479 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
480 if (payload
== NULL
) return NULL
;
482 xpc_dictionary_set_uuid(payload
, key
, uu
);
488 _xpc_query_key_int(const char *key
, int64_t intValue
)
490 xpc_object_t payload
;
492 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
493 if (payload
== NULL
) return NULL
;
495 xpc_dictionary_set_int64(payload
, key
, intValue
);
503 _extract_string_from_xpc_array_index(xpc_object_t reply
, int index
, const char **str
)
507 if (xpc_array_get_count(reply
) < index
) return -1;
509 value
= xpc_array_get_value(reply
, index
);
510 if (xpc_get_type(value
) != XPC_TYPE_STRING
) return -1;
512 *str
= xpc_string_get_string_ptr(value
);
517 _extract_string_from_xpc_object(xpc_object_t value
, const char **str
)
519 if (value
== NULL
) return -1;
520 else if (xpc_get_type(value
) == XPC_TYPE_STRING
)
522 *str
= xpc_string_get_string_ptr(value
);
525 else if (xpc_get_type(value
) == XPC_TYPE_ARRAY
)
527 return _extract_string_from_xpc_array_index(value
, 0, str
);
534 _extract_uint32_from_xpc_object(xpc_object_t value
, uint32_t *val32
)
538 if (value
== NULL
) return -1;
539 type
= xpc_get_type(value
);
541 if (type
== XPC_TYPE_STRING
)
543 *val32
= atoi(xpc_string_get_string_ptr(value
));
546 else if (type
== XPC_TYPE_INT64
)
548 *val32
= (uint32_t)xpc_int64_get_value(value
);
551 else if (type
== XPC_TYPE_BOOL
)
553 *val32
= (uint32_t)xpc_bool_get_value(value
);
556 else if (type
== XPC_TYPE_ARRAY
)
558 if (xpc_array_get_count(value
) == 0) return -1;
559 return _extract_uint32_from_xpc_object(xpc_array_get_value(value
, 0), val32
);
566 _extract_string_list_from_xpc_array_index(xpc_object_t reply
, int index
, unsigned int *len
, char ***list
)
569 xpc_object_t xpc_array
= xpc_array_get_value(reply
, index
);
571 if ((xpc_array
== NULL
) || (xpc_get_type(xpc_array
) != XPC_TYPE_ARRAY
)) return -1;
573 result
= calloc(xpc_array_get_count(xpc_array
) + 1, sizeof(*result
));
574 if (result
== NULL
) return -1;
576 /* include trailing NULL */
577 if (len
!= NULL
) (*len
) = xpc_array_get_count(xpc_array
) + 1;
579 xpc_array_apply(xpc_array
, ^bool(size_t idx
, xpc_object_t value
) {
580 result
[idx
] = (char *)xpc_string_get_string_ptr(value
);
589 _extract_uint32_from_xpc_array_index(xpc_object_t reply
, int index
, uint32_t *val32
)
591 xpc_object_t value
= xpc_array_get_value(reply
, index
);
592 return _extract_uint32_from_xpc_object(value
, val32
);
596 _extract_string_list_from_xpc_array(xpc_object_t xpc_array
, unsigned int *len
, char ***list
)
600 if ((xpc_array
== NULL
) || (xpc_get_type(xpc_array
) != XPC_TYPE_ARRAY
)) return -1;
602 result
= calloc(xpc_array_get_count(xpc_array
) + 1, sizeof(*result
));
603 if (result
== NULL
) return -1;
605 /* include trailing NULL */
606 if (len
!= NULL
) (*len
) = xpc_array_get_count(xpc_array
) + 1;
608 xpc_array_apply(xpc_array
, ^bool(size_t idx
, xpc_object_t value
) {
609 result
[idx
] = (char *)xpc_string_get_string_ptr(value
);
618 _extract_string_from_xpc_dict(xpc_object_t reply
, const char *key
, const char **str
)
620 xpc_object_t value
= xpc_dictionary_get_value(reply
, key
);
623 if (value
== NULL
) return -1;
625 if (xpc_get_type(value
) != XPC_TYPE_STRING
) return -1;
627 result
= xpc_string_get_string_ptr(value
);
628 if (result
== NULL
) return -1;
635 _extract_uint32_from_xpc_dict(xpc_object_t reply
, const char *key
, uint32_t *val32
)
637 xpc_object_t value
= xpc_dictionary_get_value(reply
, key
);
638 return _extract_uint32_from_xpc_object(value
, val32
);
656 _extract_user_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
661 if (xpc_array_get_count(reply
) < 7) return NULL
;
663 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.pw_name
)) return NULL
;
664 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.pw_passwd
)) return NULL
;
665 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.pw_uid
)) return NULL
;
666 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.pw_gid
)) return NULL
;
667 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.pw_gecos
)) return NULL
;
668 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.pw_dir
)) return NULL
;
669 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.pw_shell
)) return NULL
;
672 tmp
.pw_change
= (time_t)0;
673 tmp
.pw_expire
= (time_t)0;
674 tmp
.pw_class
= (char *)"";
676 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
);
680 _extract_user_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
682 __block
struct passwd tmp
;
683 __block
int status
= 0;
684 __block
int parts
= 3;
686 tmp
.pw_name
= (char *)"";
687 tmp
.pw_passwd
= (char *)"*";
688 tmp
.pw_uid
= (uid_t
)0;
689 tmp
.pw_gid
= (gid_t
)0;
690 tmp
.pw_change
= (time_t)0;
691 tmp
.pw_expire
= (time_t)0;
692 tmp
.pw_class
= (char *)"";
693 tmp
.pw_gecos
= (char *)"";
694 tmp
.pw_dir
= (char *)"/var/empty";
695 tmp
.pw_shell
= (char *)"/usr/bin/false";
697 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
698 if (key
== NULL
) return true;
699 else if (!strcmp(key
, "pw_name"))
701 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_name
);
702 if (status
== 0) parts
--;
704 else if (!strcmp(key
, "pw_passwd"))
706 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_passwd
);
707 /* no parts check - this value is optional */
709 else if (!strcmp(key
, "pw_uid"))
711 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.pw_uid
);
712 if (status
== 0) parts
--;
714 else if (!strcmp(key
, "pw_gid"))
716 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.pw_gid
);
717 if (status
== 0) parts
--;
719 else if (!strcmp(key
, "pw_change"))
721 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.pw_change
);
722 /* no parts check - this value is optional */
724 else if (!strcmp(key
, "pw_expire"))
726 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.pw_expire
);
727 /* no parts check - this value is optional */
729 else if (!strcmp(key
, "pw_class"))
731 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_class
);
732 /* no parts check - this value is optional */
734 else if (!strcmp(key
, "pw_gecos"))
736 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_gecos
);
737 /* no parts check - this value is optional */
739 else if (!strcmp(key
, "pw_dir"))
741 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_dir
);
742 /* no parts check - this value is optional */
744 else if (!strcmp(key
, "pw_shell"))
746 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_shell
);
747 /* no parts check - this value is optional */
752 if ((status
!= 0) || (parts
!= 0)) return NULL
;
754 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
);
758 _extract_user(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
762 if (si
== NULL
) return NULL
;
763 if (reply
== NULL
) return NULL
;
765 type
= xpc_get_type(reply
);
767 if (type
== XPC_TYPE_ARRAY
) return _extract_user_array(si
, reply
, valid_global
, valid_cat
);
768 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_user_dict(si
, reply
, valid_global
, valid_cat
);
778 * optional members : array of string
783 _extract_group_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
788 int arraycount
= xpc_array_get_count(reply
);
790 if ((arraycount
< 2) || (arraycount
> 3)) return NULL
;
792 memset(&tmp
, 0, sizeof(tmp
));
794 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.gr_name
)) return NULL
;
795 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.gr_gid
)) return NULL
;
799 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.gr_mem
)) return NULL
;
803 tmp
.gr_passwd
= (char *)"*";
805 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
);
813 _extract_group_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
816 __block
struct group tmp
;
817 __block
int status
= 0;
818 __block
int parts
= 2;
820 tmp
.gr_name
= (char *)"";
821 tmp
.gr_passwd
= (char *)"*";
822 tmp
.gr_gid
= (gid_t
)0;
825 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
826 if (key
== NULL
) return true;
827 else if (!strcmp(key
, "gr_name"))
829 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.gr_name
);
830 if (status
== 0) parts
--;
832 else if (!strcmp(key
, "gr_passwd"))
834 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.gr_passwd
);
835 /* no parts check - this value is optional */
837 else if (!strcmp(key
, "gr_gid"))
839 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.gr_gid
);
840 if (status
== 0) parts
--;
842 else if (!strcmp(key
, "gr_mem"))
844 status
|= _extract_string_list_from_xpc_array(value
, NULL
, (char ***)&tmp
.gr_mem
);
845 /* no parts check - this value is optional */
850 if ((status
!= 0) || (parts
!= 0))
856 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
);
864 _extract_group(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
868 if (si
== NULL
) return NULL
;
869 if (reply
== NULL
) return NULL
;
871 type
= xpc_get_type(reply
);
872 if (type
== XPC_TYPE_ARRAY
) return _extract_group_array(si
, reply
, valid_global
, valid_cat
);
873 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_group_dict(si
, reply
, valid_global
, valid_cat
);
887 _extract_netgroup_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
889 const char *host
, *user
, *domain
;
892 if (xpc_array_get_count(reply
) != 3) return NULL
;
894 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&host
)) return NULL
;
895 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&user
)) return NULL
;
896 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&domain
)) return NULL
;
898 return (si_item_t
*)LI_ils_create("L4488sss", (unsigned long)si
, CATEGORY_NETGROUP
, 1, valid_global
, valid_cat
, host
, user
, domain
);
902 _extract_netgroup_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
904 __block
const char *host
= "";
905 __block
const char *user
= "";
906 __block
const char *domain
= "";
907 __block
int status
= 0;
908 __block
int parts
= 3;
910 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
911 if (key
== NULL
) return true;
912 else if (!strcmp(key
, "host"))
914 status
|= _extract_string_from_xpc_object(value
, (const char **)&host
);
915 if (status
== 0) parts
--;
917 else if (!strcmp(key
, "user"))
919 status
|= _extract_string_from_xpc_object(value
, (const char **)&user
);
920 if (status
== 0) parts
--;
922 else if (!strcmp(key
, "domain"))
924 status
|= _extract_string_from_xpc_object(value
, (const char **)&domain
);
925 if (status
== 0) parts
--;
930 if ((status
!= 0) || (parts
!= 0)) return NULL
;
932 return (si_item_t
*)LI_ils_create("L4488sss", (unsigned long)si
, CATEGORY_NETGROUP
, 1, valid_global
, valid_cat
, host
, user
, domain
);
936 _extract_netgroup(si_mod_t
*si
, xpc_object_t reply
, const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
940 if (si
== NULL
) return NULL
;
941 if (reply
== NULL
) return NULL
;
943 type
= xpc_get_type(reply
);
944 if (type
== XPC_TYPE_ARRAY
) return _extract_netgroup_array(si
, reply
, valid_global
, valid_cat
);
945 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_netgroup_dict(si
, reply
, valid_global
, valid_cat
);
955 * optional members : array of string
960 _extract_alias_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
965 int arraycount
= xpc_array_get_count(reply
);
967 if ((arraycount
< 2) || (arraycount
> 3)) return NULL
;
969 memset(&tmp
, 0, sizeof(tmp
));
971 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.alias_name
)) return NULL
;
972 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.alias_local
)) return NULL
;
976 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.alias_members
)) return NULL
;
979 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
);
981 free(tmp
.alias_members
);
987 _extract_alias_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
990 __block
struct aliasent tmp
;
991 __block
int status
= 0;
992 __block
int parts
= 2;
994 tmp
.alias_name
= (char *)"";
996 tmp
.alias_members
= NULL
;
997 tmp
.alias_members_len
= 0;
999 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1000 if (key
== NULL
) return true;
1001 else if (!strcmp(key
, "alias_name"))
1003 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.alias_name
);
1004 if (status
== 0) parts
--;
1006 else if (!strcmp(key
, "alias_local"))
1008 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.alias_local
);
1009 if (status
== 0) parts
--;
1011 else if (!strcmp(key
, "alias_members"))
1013 status
|= _extract_string_list_from_xpc_array(value
, &tmp
.alias_members_len
, (char ***)&tmp
.alias_members
);
1014 /* no parts check - this value is optional */
1019 if ((status
!= 0) || (parts
!= 0))
1021 free(tmp
.alias_members
);
1025 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
);
1027 free(tmp
.alias_members
);
1033 _extract_alias(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1037 if (si
== NULL
) return NULL
;
1038 if (reply
== NULL
) return NULL
;
1040 type
= xpc_get_type(reply
);
1041 if (type
== XPC_TYPE_ARRAY
) return _extract_alias_array(si
, reply
, valid_global
, valid_cat
);
1042 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_alias_dict(si
, reply
, valid_global
, valid_cat
);
1052 * optional aliases : array of string
1057 _extract_network_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1062 int arraycount
= xpc_array_get_count(reply
);
1064 if ((arraycount
< 2) || (arraycount
> 3)) return NULL
;
1066 memset(&tmp
, 0, sizeof(tmp
));
1068 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.n_name
)) return NULL
;
1069 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.n_net
)) return NULL
;
1071 if (arraycount
== 3)
1073 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.n_aliases
)) return NULL
;
1077 tmp
.n_addrtype
= AF_INET
;
1079 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
);
1081 free(tmp
.n_aliases
);
1087 _extract_network_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1090 __block
struct netent tmp
;
1091 __block
int status
= 0;
1092 __block
int parts
= 2;
1094 if (si
== NULL
) return NULL
;
1095 if (reply
== NULL
) return NULL
;
1097 tmp
.n_name
= (char *)"";
1098 tmp
.n_aliases
= NULL
;
1102 tmp
.n_addrtype
= AF_INET
;
1104 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1105 if (key
== NULL
) return true;
1106 else if (!strcmp(key
, "n_name"))
1108 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.n_name
);
1109 if (status
== 0) parts
--;
1111 else if (!strcmp(key
, "n_aliases"))
1113 status
|= _extract_string_list_from_xpc_array(value
, NULL
, (char ***)&tmp
.n_aliases
);
1114 /* no parts check - this value is optional */
1116 else if (!strcmp(key
, "n_net"))
1118 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.n_net
);
1119 if (status
== 0) parts
--;
1124 if ((status
!= 0) || (parts
!= 0))
1126 free(tmp
.n_aliases
);
1130 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
);
1132 free(tmp
.n_aliases
);
1138 _extract_network(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1142 if (si
== NULL
) return NULL
;
1143 if (reply
== NULL
) return NULL
;
1145 type
= xpc_get_type(reply
);
1146 if (type
== XPC_TYPE_ARRAY
) return _extract_network_array(si
, reply
, valid_global
, valid_cat
);
1147 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_network_dict(si
, reply
, valid_global
, valid_cat
);
1158 * optional aliases : array of string
1163 _extract_service_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1168 int arraycount
= xpc_array_get_count(reply
);
1170 if ((arraycount
< 3) || (arraycount
> 4)) return NULL
;
1172 memset(&tmp
, 0, sizeof(tmp
));
1174 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.s_name
)) return NULL
;
1175 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.s_port
)) return NULL
;
1176 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.s_proto
)) return NULL
;
1178 if (arraycount
== 4)
1180 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.s_aliases
)) return NULL
;
1183 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
);
1185 free(tmp
.s_aliases
);
1191 _extract_service_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1194 __block
struct servent tmp
;
1195 __block
int status
= 0;
1196 __block
int parts
= 3;
1198 if (si
== NULL
) return NULL
;
1199 if (reply
== NULL
) return NULL
;
1201 tmp
.s_name
= (char *)"";
1202 tmp
.s_aliases
= NULL
;
1204 tmp
.s_proto
= (char *)"";
1206 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1207 if (key
== NULL
) return true;
1208 else if (!strcmp(key
, "s_name"))
1210 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.s_name
);
1211 if (status
== 0) parts
--;
1213 else if (!strcmp(key
, "s_aliases"))
1215 status
|= _extract_string_list_from_xpc_array(value
, NULL
, (char ***)&tmp
.s_aliases
);
1216 /* no parts check - this value is optional */
1218 else if (!strcmp(key
, "s_port"))
1221 status
|= _extract_uint32_from_xpc_object(value
, &v32
);
1224 tmp
.s_port
= (unsigned int)htons(v32
); // ugh
1228 else if (!strcmp(key
, "s_proto"))
1230 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.s_proto
);
1231 if (status
== 0) parts
--;
1236 if ((status
!= 0) || (parts
!= 0))
1238 free(tmp
.s_aliases
);
1242 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
);
1244 free(tmp
.s_aliases
);
1250 _extract_service(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1254 if (si
== NULL
) return NULL
;
1255 if (reply
== NULL
) return NULL
;
1257 type
= xpc_get_type(reply
);
1258 if (type
== XPC_TYPE_ARRAY
) return _extract_service_array(si
, reply
, valid_global
, valid_cat
);
1259 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_service_dict(si
, reply
, valid_global
, valid_cat
);
1269 * optional aliases : array of string
1273 _extract_protocol_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1276 struct protoent tmp
;
1278 int arraycount
= xpc_array_get_count(reply
);
1280 if ((arraycount
< 2) || (arraycount
> 3)) return NULL
;
1282 memset(&tmp
, 0, sizeof(tmp
));
1284 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.p_name
)) return NULL
;
1285 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.p_proto
)) return NULL
;
1287 if (arraycount
== 3)
1289 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.p_aliases
)) return NULL
;
1292 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
);
1294 free(tmp
.p_aliases
);
1300 _extract_protocol_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1303 __block
struct protoent tmp
;
1304 __block
int status
= 0;
1305 __block
int parts
= 2;
1307 tmp
.p_name
= (char *)"";
1309 tmp
.p_aliases
= NULL
;
1311 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1312 if (key
== NULL
) return true;
1313 else if (!strcmp(key
, "p_name"))
1315 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.p_name
);
1316 if (status
== 0) parts
--;
1318 else if (!strcmp(key
, "p_proto"))
1320 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.p_proto
);
1321 if (status
== 0) parts
--;
1323 else if (!strcmp(key
, "p_aliases"))
1325 status
|= _extract_string_list_from_xpc_array(value
, NULL
, (char ***)&tmp
.p_aliases
);
1326 /* no parts check - this value is optional */
1331 if ((status
!= 0) || (parts
!= 0))
1333 free(tmp
.p_aliases
);
1337 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
);
1339 free(tmp
.p_aliases
);
1345 _extract_protocol(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1349 if (si
== NULL
) return NULL
;
1350 if (reply
== NULL
) return NULL
;
1352 type
= xpc_get_type(reply
);
1353 if (type
== XPC_TYPE_ARRAY
) return _extract_protocol_array(si
, reply
, valid_global
, valid_cat
);
1354 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_protocol_dict(si
, reply
, valid_global
, valid_cat
);
1364 * optional aliases : array of string
1369 _extract_rpc_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1374 int arraycount
= xpc_array_get_count(reply
);
1376 if ((arraycount
< 2) || (arraycount
> 3)) return NULL
;
1378 memset(&tmp
, 0, sizeof(tmp
));
1380 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.r_name
)) return NULL
;
1381 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.r_number
)) return NULL
;
1383 if (arraycount
== 3)
1385 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.r_aliases
)) return NULL
;
1388 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
);
1390 free(tmp
.r_aliases
);
1396 _extract_rpc_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1399 __block
struct rpcent tmp
;
1400 __block
int status
= 0;
1401 __block
int parts
= 2;
1403 tmp
.r_name
= (char *)"";
1405 tmp
.r_aliases
= NULL
;
1407 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1408 if (key
== NULL
) return true;
1409 else if (!strcmp(key
, "r_name"))
1411 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.r_name
);
1412 if (status
== 0) parts
--;
1414 else if (!strcmp(key
, "r_number"))
1416 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.r_number
);
1417 if (status
== 0) parts
--;
1419 else if (!strcmp(key
, "r_aliases"))
1421 status
|= _extract_string_list_from_xpc_array(value
, NULL
, (char ***)&tmp
.r_aliases
);
1422 /* no parts check - this value is optional */
1427 if ((status
!= 0) || (parts
!= 0))
1429 free(tmp
.r_aliases
);
1433 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
);
1435 free(tmp
.r_aliases
);
1441 _extract_rpc(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1445 if (si
== NULL
) return NULL
;
1446 if (reply
== NULL
) return NULL
;
1448 type
= xpc_get_type(reply
);
1449 if (type
== XPC_TYPE_ARRAY
) return _extract_rpc_array(si
, reply
, valid_global
, valid_cat
);
1450 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_rpc_dict(si
, reply
, valid_global
, valid_cat
);
1468 _extract_fstab_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1470 __block
struct fstab tmp
;
1473 if (xpc_array_get_count(reply
) != 7) return NULL
;
1475 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.fs_file
)) return NULL
;
1476 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.fs_spec
)) return NULL
;
1477 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.fs_freq
)) return NULL
;
1478 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.fs_passno
)) return NULL
;
1479 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.fs_mntops
)) return NULL
;
1480 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.fs_type
)) return NULL
;
1481 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.fs_vfstype
)) return NULL
;
1483 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
);
1487 _extract_fstab_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1489 __block
struct fstab tmp
;
1490 __block
int status
= 0;
1491 __block
int parts
= 7;
1494 tmp
.fs_spec
= (char *)"";
1497 tmp
.fs_mntops
= (char *)"";
1498 tmp
.fs_type
= (char *)"";
1499 tmp
.fs_vfstype
= (char *)"";
1501 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1502 if (key
== NULL
) return true;
1503 else if (!strcmp(key
, "fs_file"))
1505 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.fs_file
);
1506 if (status
== 0) parts
--;
1508 else if (!strcmp(key
, "fs_spec"))
1510 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.fs_spec
);
1511 if (status
== 0) parts
--;
1513 else if (!strcmp(key
, "fs_freq"))
1515 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.fs_freq
);
1516 if (status
== 0) parts
--;
1518 else if (!strcmp(key
, "fs_passno"))
1520 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.fs_passno
);
1521 if (status
== 0) parts
--;
1523 else if (!strcmp(key
, "fs_mntops"))
1525 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.fs_mntops
);
1526 if (status
== 0) parts
--;
1528 else if (!strcmp(key
, "fs_type"))
1530 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.fs_type
);
1531 if (status
== 0) parts
--;
1533 else if (!strcmp(key
, "fs_vfstype"))
1535 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.fs_vfstype
);
1536 if (status
== 0) parts
--;
1541 if ((status
!= 0) || (parts
!= 0)) return NULL
;
1543 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
);
1547 _extract_fstab(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1551 if (si
== NULL
) return NULL
;
1552 if (reply
== NULL
) return NULL
;
1554 type
= xpc_get_type(reply
);
1555 if (type
== XPC_TYPE_ARRAY
) return _extract_fstab_array(si
, reply
, valid_global
, valid_cat
);
1556 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_fstab_dict(si
, reply
, valid_global
, valid_cat
);
1562 _extract_mac_mac(si_mod_t
*si
, xpc_object_t reply
, const void *extra
, uint64_t valid_global
, uint64_t valid_cat
)
1566 const char *value
= NULL
;
1569 if (si
== NULL
) return NULL
;
1570 if (reply
== NULL
) return NULL
;
1571 if (extra
== NULL
) return NULL
;
1573 type
= xpc_get_type(reply
);
1574 if (type
== XPC_TYPE_ARRAY
)
1576 if (xpc_array_get_count(reply
) >= 1)
1578 if (0 != _extract_string_from_xpc_array_index(reply
, 0, (const char **)&value
)) return NULL
;
1581 else if (type
== XPC_TYPE_DICTIONARY
)
1583 if (0 != _extract_string_from_xpc_dict(reply
, "mac", &value
)) return NULL
;
1586 if (value
== NULL
|| value
[0] == '\0') return NULL
;
1588 cmac
= si_standardize_mac_address(value
);
1589 if (cmac
== NULL
) return NULL
;
1591 out
= (si_item_t
*)LI_ils_create("L4488ss", (unsigned long)si
, CATEGORY_MAC
, 1, valid_global
, valid_cat
, extra
, cmac
);
1599 _extract_mac_name(si_mod_t
*si
, xpc_object_t reply
, const void *extra
, uint64_t valid_global
, uint64_t valid_cat
)
1602 const char *name
= NULL
;
1605 if (si
== NULL
) return NULL
;
1606 if (reply
== NULL
) return NULL
;
1607 if (extra
== NULL
) return NULL
;
1609 type
= xpc_get_type(reply
);
1610 if (type
== XPC_TYPE_ARRAY
)
1612 if (xpc_array_get_count(reply
) >= 1)
1614 if (0 != _extract_string_from_xpc_array_index(reply
, 0, (const char **)&name
)) return NULL
;
1617 else if (type
== XPC_TYPE_DICTIONARY
)
1619 if (0 != _extract_string_from_xpc_dict(reply
, "name", &name
)) return NULL
;
1622 if (name
== NULL
) return NULL
;
1624 out
= (si_item_t
*)LI_ils_create("L4488ss", (unsigned long)si
, CATEGORY_MAC
, 1, valid_global
, valid_cat
, name
, extra
);
1632 ds_user_byname(si_mod_t
*si
, const char *name
)
1634 xpc_object_t payload
;
1637 if (!_od_running()) return NULL
;
1639 LI_OS_ACTIVITY("Retrieve User by Name");
1641 payload
= _xpc_query_key_string("name", name
);
1642 if (payload
== NULL
) return NULL
;
1644 item
= _ds_item(si
, CATEGORY_USER
, "getpwnam", NULL
, _extract_user
, payload
);
1646 xpc_release(payload
);
1651 ds_user_byuid(si_mod_t
*si
, uid_t uid
)
1653 xpc_object_t payload
;
1656 if (!_od_running()) return NULL
;
1658 LI_OS_ACTIVITY("Retrieve User by ID");
1660 payload
= _xpc_query_key_id("uid", uid
);
1661 if (payload
== NULL
) return NULL
;
1663 item
= _ds_item(si
, CATEGORY_USER
, "getpwuid", NULL
, _extract_user
, payload
);
1665 xpc_release(payload
);
1670 ds_user_byuuid(si_mod_t
*si
, uuid_t uuid
)
1672 xpc_object_t payload
;
1675 if (!_od_running()) return NULL
;
1677 LI_OS_ACTIVITY("Retrieve User by UUID");
1679 payload
= _xpc_query_key_uuid("uuid", uuid
);
1680 if (payload
== NULL
) return NULL
;
1682 item
= _ds_item(si
, CATEGORY_USER
, "getpwuuid", NULL
, _extract_user
, payload
);
1684 xpc_release(payload
);
1689 ds_user_all(si_mod_t
*si
)
1691 LI_OS_ACTIVITY("Performance Impact - Enumerate all users");
1693 return _ds_list(si
, CATEGORY_USER
, "getpwent", NULL
, _extract_user
);
1697 ds_group_byname(si_mod_t
*si
, const char *name
)
1699 xpc_object_t payload
;
1702 if (!_od_running()) return NULL
;
1704 LI_OS_ACTIVITY("Retrieve Group by Name");
1706 payload
= _xpc_query_key_string("name", name
);
1707 if (payload
== NULL
) return NULL
;
1709 item
= _ds_item(si
, CATEGORY_GROUP
, "getgrnam", NULL
, _extract_group
, payload
);
1711 xpc_release(payload
);
1716 ds_group_bygid(si_mod_t
*si
, gid_t gid
)
1718 xpc_object_t payload
;
1721 if (!_od_running()) return NULL
;
1723 LI_OS_ACTIVITY("Retrieve Group by ID");
1725 payload
= _xpc_query_key_id("gid", gid
);
1726 if (payload
== NULL
) return NULL
;
1728 item
= _ds_item(si
, CATEGORY_GROUP
, "getgrgid", NULL
, _extract_group
, payload
);
1730 xpc_release(payload
);
1735 ds_group_byuuid(si_mod_t
*si
, uuid_t uuid
)
1737 xpc_object_t payload
;
1740 if (!_od_running()) return NULL
;
1742 LI_OS_ACTIVITY("Retrieve Group by UUID");
1744 payload
= _xpc_query_key_uuid("uuid", uuid
);
1745 if (payload
== NULL
) return NULL
;
1747 item
= _ds_item(si
, CATEGORY_GROUP
, "getgruuid", NULL
, _extract_group
, payload
);
1749 xpc_release(payload
);
1754 ds_group_all(si_mod_t
*si
)
1756 if (!_od_running()) return NULL
;
1757 LI_OS_ACTIVITY("Performance Impact - Enumerate all Groups");
1758 return _ds_list(si
, CATEGORY_GROUP
, "getgrent", NULL
, _extract_group
);
1762 ds_grouplist(si_mod_t
*si
, const char *name
, uint32_t ngroups
)
1764 xpc_object_t payload
, reply
;
1765 si_item_t
*item
= NULL
;
1766 os_activity_t activity
;
1768 if (!_od_running()) return NULL
;
1769 if (name
== NULL
) return NULL
;
1772 activity
= os_activity_create("Performance impact - Resolve user group list (>17 groups)", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1773 os_log(OS_LOG_DEFAULT
, "Too many groups requested (%u). Can cause performance issues when network directories are involved", ngroups
);
1775 activity
= os_activity_create("Resolve user group list", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1777 os_activity_scope(activity
);
1779 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
1780 if (payload
== NULL
) return NULL
;
1782 xpc_dictionary_set_string(payload
, "name", name
);
1783 xpc_dictionary_set_int64(payload
, "ngroups", ngroups
);
1785 reply
= _od_rpc_call("getgrouplist", payload
, _od_xpc_pipe
);
1786 if (reply
!= NULL
) {
1788 const gid_t
*gidptr
= xpc_dictionary_get_data(reply
, "groups", &gidptrsz
);
1792 _ds_get_validation(si
, &va
, &vb
, CATEGORY_GROUPLIST
);
1794 /* see what we were sent */
1795 if (0 == _extract_uint32_from_xpc_dict(reply
, "count", &count
))
1799 item
= (si_item_t
*)LI_ils_create("L4488s4@", (unsigned long)si
, CATEGORY_GROUPLIST
, 1, va
, vb
, name
, count
,
1807 xpc_release(payload
);
1808 os_release(activity
);
1814 ds_netgroup_byname(si_mod_t
*si
, const char *name
)
1816 xpc_object_t payload
;
1817 si_list_t
*list
= NULL
;
1820 if (!_od_running()) return NULL
;
1822 LI_OS_ACTIVITY("Retrieve netgroup by name");
1824 payload
= _xpc_query_key_string("netgroup", name
);
1825 if (payload
== NULL
) return NULL
;
1827 item
= _ds_item(si
, CATEGORY_NETGROUP
, "getnetgrent", NULL
, _extract_netgroup
, payload
);
1829 list
= si_list_add(list
, item
);
1830 si_item_release(item
);
1833 xpc_release(payload
);
1839 ds_in_netgroup(si_mod_t
*si
, const char *group
, const char *host
, const char *user
, const char *domain
)
1841 xpc_object_t payload
, reply
;
1844 if (!_od_running()) return 0;
1846 LI_OS_ACTIVITY("Match netgroup");
1848 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
1849 if (payload
== NULL
) return 0;
1851 xpc_dictionary_set_string(payload
, "netgroup", (group ? group
: ""));
1852 xpc_dictionary_set_string(payload
, "host", (host ? host
: ""));
1853 xpc_dictionary_set_string(payload
, "user", (user ? user
: ""));
1854 xpc_dictionary_set_string(payload
, "domain", (domain ? domain
: ""));
1856 reply
= _od_rpc_call("innetgr", payload
, _od_xpc_pipe
);
1857 if (reply
!= NULL
) {
1858 is_innetgr
= xpc_dictionary_get_bool(reply
, OD_RPC_RESULT
);
1864 xpc_release(payload
);
1870 ds_alias_byname(si_mod_t
*si
, const char *name
)
1872 xpc_object_t payload
;
1875 if (!_od_running()) return NULL
;
1877 LI_OS_ACTIVITY("Retrieve alias by name");
1878 payload
= _xpc_query_key_string("name", name
);
1879 if (payload
== NULL
) return NULL
;
1881 item
= _ds_item(si
, CATEGORY_ALIAS
, "alias_getbyname", NULL
, _extract_alias
, payload
);
1883 xpc_release(payload
);
1888 ds_alias_all(si_mod_t
*si
)
1890 if (!_od_running()) return NULL
;
1891 LI_OS_ACTIVITY("Enumerate all alias entries");
1892 return _ds_list(si
, CATEGORY_ALIAS
, "alias_getent", NULL
, _extract_alias
);
1896 ds_network_byname(si_mod_t
*si
, const char *name
)
1898 xpc_object_t payload
;
1901 if (!_od_running()) return NULL
;
1903 LI_OS_ACTIVITY("Retrieve network by name");
1904 payload
= _xpc_query_key_string("name", name
);
1905 if (payload
== NULL
) return NULL
;
1907 item
= _ds_item(si
, CATEGORY_NETWORK
, "getnetbyname", NULL
, _extract_network
, payload
);
1909 xpc_release(payload
);
1914 ds_network_byaddr(si_mod_t
*si
, uint32_t addr
)
1916 unsigned char f1
, f2
, f3
;
1918 xpc_object_t payload
;
1921 if (!_od_running()) return NULL
;
1923 LI_OS_ACTIVITY("Retrieve network by address");
1930 if (f3
!= 0) snprintf(val
, sizeof(val
), "%u.%u.%u", f3
, f2
, f1
);
1931 else if (f2
!= 0) snprintf(val
, sizeof(val
), "%u.%u", f2
, f1
);
1932 else snprintf(val
, sizeof(val
), "%u", f1
);
1934 payload
= _xpc_query_key_string("net", val
);
1935 if (payload
== NULL
) return NULL
;
1937 item
= _ds_item(si
, CATEGORY_NETWORK
, "getnetbyaddr", NULL
, _extract_network
, payload
);
1939 xpc_release(payload
);
1944 ds_network_all(si_mod_t
*si
)
1946 if (!_od_running()) return NULL
;
1947 LI_OS_ACTIVITY("Emumerate all network entries");
1948 return _ds_list(si
, CATEGORY_NETWORK
, "getnetent", NULL
, _extract_network
);
1952 ds_service_byname(si_mod_t
*si
, const char *name
, const char *proto
)
1954 xpc_object_t payload
;
1958 if (!_od_running()) return NULL
;
1959 if (name
== NULL
) name
= "";
1960 if (proto
== NULL
) proto
= "";
1962 LI_OS_ACTIVITY("Retrieve service by name");
1964 /* Check our local service cache (see ds_addrinfo). */
1965 item
= pthread_getspecific(_ds_serv_cache_key
);
1968 s
= (struct servent
*)((uintptr_t)item
+ sizeof(si_item_t
));
1969 if (string_equal(name
, s
->s_name
)) return si_item_retain(item
);
1972 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
1973 if (payload
== NULL
) return NULL
;
1975 xpc_dictionary_set_string(payload
, "name", name
);
1976 xpc_dictionary_set_string(payload
, "proto", proto
);
1978 item
= _ds_item(si
, CATEGORY_SERVICE
, "getservbyname", NULL
, _extract_service
, payload
);
1980 xpc_release(payload
);
1986 ds_service_byport(si_mod_t
*si
, int port
, const char *proto
)
1988 xpc_object_t payload
;
1991 if (!_od_running()) return NULL
;
1993 LI_OS_ACTIVITY("Retrieve service by port");
1995 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
1996 if (payload
== NULL
) return NULL
;
1998 /* swap to native order, API passes network order */
1999 xpc_dictionary_set_int64(payload
, "port", ntohs(port
));
2000 xpc_dictionary_set_string(payload
, "proto", (proto ? proto
: ""));
2002 item
= _ds_item(si
, CATEGORY_SERVICE
, "getservbyport", NULL
, _extract_service
, payload
);
2004 xpc_release(payload
);
2010 ds_service_all(si_mod_t
*si
)
2012 if (!_od_running()) return NULL
;
2013 LI_OS_ACTIVITY("Enumerate all services");
2014 return _ds_list(si
, CATEGORY_SERVICE
, "getservent", NULL
, _extract_service
);
2018 ds_protocol_byname(si_mod_t
*si
, const char *name
)
2020 xpc_object_t payload
;
2023 if (!_od_running()) return NULL
;
2025 LI_OS_ACTIVITY("Retrieve protocol by name");
2026 payload
= _xpc_query_key_string("name", name
);
2027 if (payload
== NULL
) return NULL
;
2029 item
= _ds_item(si
, CATEGORY_PROTOCOL
, "getprotobyname", NULL
, _extract_protocol
, payload
);
2031 xpc_release(payload
);
2036 ds_protocol_bynumber(si_mod_t
*si
, int number
)
2038 xpc_object_t payload
;
2041 if (!_od_running()) return NULL
;
2043 LI_OS_ACTIVITY("Retrieve protocol by number");
2044 payload
= _xpc_query_key_int("number", number
);
2045 if (payload
== NULL
) return NULL
;
2047 item
= _ds_item(si
, CATEGORY_PROTOCOL
, "getprotobynumber", NULL
, _extract_protocol
, payload
);
2049 xpc_release(payload
);
2054 ds_protocol_all(si_mod_t
*si
)
2056 LI_OS_ACTIVITY("Enumerate all protocols");
2057 return _ds_list(si
, CATEGORY_PROTOCOL
, "getprotoent", NULL
, _extract_protocol
);
2061 ds_rpc_byname(si_mod_t
*si
, const char *name
)
2063 xpc_object_t payload
;
2066 if (!_od_running()) return NULL
;
2068 LI_OS_ACTIVITY("Retrieve RPC by name");
2069 payload
= _xpc_query_key_string("name", name
);
2070 if (payload
== NULL
) return NULL
;
2072 item
= _ds_item(si
, CATEGORY_RPC
, "getrpcbyname", NULL
, _extract_rpc
, payload
);
2074 xpc_release(payload
);
2079 ds_rpc_bynumber(si_mod_t
*si
, int number
)
2081 xpc_object_t payload
;
2084 if (!_od_running()) return NULL
;
2086 LI_OS_ACTIVITY("Retrieve RPC by number");
2087 payload
= _xpc_query_key_int("number", number
);
2088 if (payload
== NULL
) return NULL
;
2090 item
= _ds_item(si
, CATEGORY_RPC
, "getrpcbynumber", NULL
, _extract_rpc
, payload
);
2092 xpc_release(payload
);
2097 ds_rpc_all(si_mod_t
*si
)
2099 LI_OS_ACTIVITY("Enumerate all RPC entries");
2100 return _ds_list(si
, CATEGORY_RPC
, "getrpcent", NULL
, _extract_rpc
);
2104 ds_fs_byspec(si_mod_t
*si
, const char *name
)
2106 xpc_object_t payload
;
2109 if (!_od_running()) return NULL
;
2111 LI_OS_ACTIVITY("Lookup FS entry by spec");
2112 payload
= _xpc_query_key_string("name", name
);
2113 if (payload
== NULL
) return NULL
;
2115 item
= _ds_item(si
, CATEGORY_FS
, "getfsbyname", NULL
, _extract_fstab
, payload
);
2117 xpc_release(payload
);
2122 ds_fs_all(si_mod_t
*si
)
2124 LI_OS_ACTIVITY("Performance impact - Enumerate all FS entries");
2125 return _ds_list(si
, CATEGORY_FS
, "getfsent", NULL
, _extract_fstab
);
2129 ds_fs_byfile(si_mod_t
*si
, const char *name
)
2136 if (!_od_running()) return NULL
;
2137 if (name
== NULL
) return NULL
;
2139 LI_OS_ACTIVITY("Retrieve FS by file location");
2140 list
= ds_fs_all(si
);
2141 if (list
== NULL
) return NULL
;
2144 for (i
= 0; (i
< list
->count
) && (item
== NULL
); i
++)
2146 f
= (struct fstab
*)((uintptr_t)(list
->entry
[i
]) + sizeof(si_item_t
));
2147 if (string_equal(name
, f
->fs_file
)) item
= si_item_retain(list
->entry
[i
]);
2150 si_list_release(list
);
2155 ds_mac_byname(si_mod_t
*si
, const char *name
)
2157 xpc_object_t payload
;
2160 if (!_od_running()) return NULL
;
2162 LI_OS_ACTIVITY("Retrieve FS by name");
2163 payload
= _xpc_query_key_string("name", name
);
2164 if (payload
== NULL
) return NULL
;
2166 item
= _ds_item(si
, CATEGORY_MAC
, "getmacbyname", name
, _extract_mac_mac
, payload
);
2168 xpc_release(payload
);
2173 ds_mac_bymac(si_mod_t
*si
, const char *mac
)
2175 xpc_object_t payload
;
2179 if (!_od_running()) return NULL
;
2181 LI_OS_ACTIVITY("Retrieve MAC entry by MAC");
2182 cmac
= si_standardize_mac_address(mac
);
2183 if (cmac
== NULL
) return NULL
;
2185 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
2186 if (payload
== NULL
) return NULL
;
2188 payload
= _xpc_query_key_string("mac", cmac
);
2189 item
= _ds_item(si
, CATEGORY_MAC
, "gethostbymac", cmac
, _extract_mac_name
, payload
);
2192 xpc_release(payload
);
2200 si_module_static_ds(void)
2202 static const struct si_mod_vtable_s ds_vtable
=
2204 .sim_is_valid
= &_ds_is_valid
,
2206 .sim_user_byname
= &ds_user_byname
,
2207 .sim_user_byuid
= &ds_user_byuid
,
2208 .sim_user_byuuid
= &ds_user_byuuid
,
2209 .sim_user_all
= &ds_user_all
,
2211 .sim_group_byname
= &ds_group_byname
,
2212 .sim_group_bygid
= &ds_group_bygid
,
2213 .sim_group_byuuid
= &ds_group_byuuid
,
2214 .sim_group_all
= &ds_group_all
,
2216 .sim_grouplist
= &ds_grouplist
,
2218 .sim_netgroup_byname
= &ds_netgroup_byname
,
2219 .sim_in_netgroup
= &ds_in_netgroup
,
2221 .sim_alias_byname
= &ds_alias_byname
,
2222 .sim_alias_all
= &ds_alias_all
,
2224 /* host lookups not supported */
2225 .sim_host_byname
= NULL
,
2226 .sim_host_byaddr
= NULL
,
2227 .sim_host_all
= NULL
,
2229 .sim_network_byname
= &ds_network_byname
,
2230 .sim_network_byaddr
= &ds_network_byaddr
,
2231 .sim_network_all
= &ds_network_all
,
2233 .sim_service_byname
= &ds_service_byname
,
2234 .sim_service_byport
= &ds_service_byport
,
2235 .sim_service_all
= &ds_service_all
,
2237 .sim_protocol_byname
= &ds_protocol_byname
,
2238 .sim_protocol_bynumber
= &ds_protocol_bynumber
,
2239 .sim_protocol_all
= &ds_protocol_all
,
2241 .sim_rpc_byname
= &ds_rpc_byname
,
2242 .sim_rpc_bynumber
= &ds_rpc_bynumber
,
2243 .sim_rpc_all
= &ds_rpc_all
,
2245 .sim_fs_byspec
= &ds_fs_byspec
,
2246 .sim_fs_byfile
= &ds_fs_byfile
,
2247 .sim_fs_all
= &ds_fs_all
,
2249 .sim_mac_byname
= &ds_mac_byname
,
2250 .sim_mac_bymac
= &ds_mac_bymac
,
2252 /* si_mac_all not supported */
2253 .sim_mac_all
= NULL
,
2255 /* si_addrinfo not supported */
2256 .sim_wants_addrinfo
= NULL
,
2257 .sim_addrinfo
= NULL
,
2260 static si_mod_t si
=
2264 .flags
= SI_MOD_FLAG_STATIC
,
2267 .vtable
= &ds_vtable
,
2270 static dispatch_once_t once
;
2271 dispatch_once(&once
, ^{
2272 pthread_key_create(&_ds_serv_cache_key
, _ds_serv_cache_free
);
2274 si
.name
= strdup("ds");
2275 ds_si_private_t
*pp
= calloc(1, sizeof(ds_si_private_t
));
2279 pp
->notify_token_global
= -1;
2280 pp
->notify_token_user
= -1;
2281 pp
->notify_token_group
= -1;
2282 pp
->notify_token_service
= -1;
2286 * Don't register for notifications if the cache is disabled.
2287 * notifyd (notably) disables the cache to prevent deadlocks.
2289 if (gL1CacheEnabled
!= 0)
2292 * Errors in registering for cache invalidation notifications are ignored.
2293 * If there are failures, the tokens remain set to -1 which just causes
2294 * cached items to be invalidated.
2296 notify_register_check(kNotifyDSCacheInvalidation
, &(pp
->notify_token_global
));
2297 notify_register_check(kNotifyDSCacheInvalidationUser
, &(pp
->notify_token_user
));
2298 notify_register_check(kNotifyDSCacheInvalidationGroup
, &(pp
->notify_token_group
));
2299 notify_register_check(kNotifyDSCacheInvalidationService
, &(pp
->notify_token_service
));
2308 #endif /* DS_AVAILABLE */