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>
52 #include <os/activity.h>
55 #define IPV6_ADDR_LEN 16
56 #define IPV4_ADDR_LEN 4
58 /* The LI_OS_ACTIVITY macro contains os_activity_t functions
59 * that are not POSIX compliant. So calling them may
60 * inadvertantly change errno. To avoid this, the macro
61 * explicityly restores the errno to its state on entry
64 * Macro cannot contain any {} because it will end the scope
65 * of the activity prematurely
67 #define _LI_OS_ACTIVITY(_var, _desc) \
69 os_activity_t activity __attribute__((__cleanup__(_li_auto_os_release))) = os_activity_create(_desc, OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); \
70 os_activity_scope(activity); \
73 #define LI_OS_ACTIVITY(_desc) _LI_OS_ACTIVITY(OS_CONCAT(errnosav, __COUNTER__), _desc)
75 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
);
78 uint32_t notify_peek(int token
, uint32_t *val
);
82 int notify_token_global
;
83 int notify_token_user
;
84 int notify_token_group
;
85 int notify_token_service
;
88 extern uint32_t gL1CacheEnabled
;
89 extern int _si_opendirectory_disabled
;
91 static pthread_key_t _ds_serv_cache_key
= 0;
92 static xpc_pipe_t __od_pipe
; /* use accessor only */
93 static pthread_mutex_t mutex
= PTHREAD_MUTEX_INITIALIZER
;
100 // re-enable opendirectory interaction since we forked
101 _si_opendirectory_disabled
= 0;
103 if (__od_pipe
!= NULL
) {
104 xpc_pipe_invalidate(__od_pipe
);
105 /* disable release due to 10649340, it will cause a minor leak for each fork without exec */
106 // xpc_release(__od_pipe);
109 _ds_port
= MACH_PORT_NULL
;
110 pthread_mutex_unlock(&mutex
);
114 _od_fork_prepare(void)
116 pthread_mutex_lock(&mutex
);
120 _od_fork_parent(void)
122 pthread_mutex_unlock(&mutex
);
126 _ds_serv_cache_free(void *x
)
128 if (x
!= NULL
) si_item_release(x
);
132 _si_disable_opendirectory(void)
134 _si_opendirectory_disabled
= 1;
135 _ds_port
= MACH_PORT_NULL
;
139 _li_auto_os_release(os_activity_t
*activity
)
141 os_release(*activity
);
147 _od_xpc_pipe(bool resetPipe
)
149 static dispatch_once_t once
;
150 xpc_pipe_t result
= NULL
;
152 dispatch_once(&once
, ^(void) {
155 /* if this is a build environment we ignore opendirectoryd */
156 xbs_disable
= getenv("XBS_DISABLE_LIBINFO");
157 if ((issetugid() == 0) && (xbs_disable
!= NULL
) && (strcmp(xbs_disable
, "YES") == 0)) {
158 _si_opendirectory_disabled
= 1;
162 pthread_atfork(_od_fork_prepare
, _od_fork_parent
, _od_fork_child
);
165 if (_si_opendirectory_disabled
== 1) {
169 pthread_mutex_lock(&mutex
);
171 xpc_release(__od_pipe
);
175 if (__od_pipe
== NULL
) {
176 if (!issetugid() && getenv("OD_DEBUG_MODE") != NULL
) {
177 __od_pipe
= xpc_pipe_create(kODMachLibinfoPortNameDebug
, 0);
179 __od_pipe
= xpc_pipe_create(kODMachLibinfoPortName
, XPC_PIPE_FLAG_PRIVILEGED
);
183 if (__od_pipe
!= NULL
) result
= xpc_retain(__od_pipe
);
184 pthread_mutex_unlock(&mutex
);
194 pipe
= _od_xpc_pipe(false);
199 if (_si_opendirectory_disabled
) {
203 return (pipe
!= NULL
);
209 _ds_port
= MACH_PORT_NULL
;
215 kern_return_t status
;
216 char *od_debug_mode
= NULL
;
218 if (_ds_port
!= MACH_PORT_NULL
) return 1;
220 if (_si_opendirectory_disabled
) return 0;
221 pthread_atfork(NULL
, NULL
, _ds_child
);
224 od_debug_mode
= getenv("OD_DEBUG_MODE");
228 status
= bootstrap_look_up(bootstrap_port
, kDSStdMachDSLookupPortName
"_debug", &_ds_port
);
230 status
= bootstrap_look_up2(bootstrap_port
, kDSStdMachDSLookupPortName
, &_ds_port
, 0, BOOTSTRAP_PRIVILEGED_SERVER
);
232 if ((status
!= BOOTSTRAP_SUCCESS
) && (status
!= BOOTSTRAP_UNKNOWN_SERVICE
)) _ds_port
= MACH_PORT_NULL
;
234 return (_ds_port
!= MACH_PORT_NULL
);
238 _valid_token(xpc_object_t reply
)
243 * This should really call audit_token_to_au32,
244 * but that's in libbsm, not in a Libsystem library.
246 xpc_dictionary_get_audit_token(reply
, &token
);
248 return ((uid_t
) token
.val
[1] == 0);
252 _ds_get_validation(si_mod_t
*si
, uint64_t *a
, uint64_t *b
, int cat
)
258 if (si
== NULL
) return;
260 pp
= (ds_si_private_t
*)si
->private;
261 if (pp
== NULL
) return;
266 status
= notify_peek(pp
->notify_token_global
, &peek
);
267 if (status
== NOTIFY_STATUS_OK
) *a
= ntohl(peek
);
274 status
= NOTIFY_STATUS_FAILED
;
276 if (cat
== CATEGORY_USER
) status
= notify_peek(pp
->notify_token_user
, &peek
);
277 else if (cat
== CATEGORY_GROUP
) status
= notify_peek(pp
->notify_token_group
, &peek
);
278 else if (cat
== CATEGORY_GROUPLIST
) status
= notify_peek(pp
->notify_token_group
, &peek
);
279 else if (cat
== CATEGORY_SERVICE
) status
= notify_peek(pp
->notify_token_service
, &peek
);
281 if (status
== NOTIFY_STATUS_OK
) *b
= ntohl(peek
);
286 __private_extern__ xpc_object_t
287 _od_rpc_call(const char *procname
, xpc_object_t payload
, xpc_pipe_t (*get_pipe
)(bool))
289 xpc_object_t result
= NULL
;
293 bool free_payload
= false;
295 od_pipe
= get_pipe(false);
296 if (od_pipe
== NULL
) return NULL
;
298 if (payload
== NULL
) {
299 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
303 // we nest it for backward compatibility so we can do independent submissions
304 xpc_dictionary_set_string(payload
, OD_RPC_NAME
, procname
);
305 xpc_dictionary_set_int64(payload
, OD_RPC_VERSION
, 2);
307 for (retries
= 0; od_pipe
!= NULL
&& retries
< 2; retries
++) {
308 rc
= xpc_pipe_routine(od_pipe
, payload
, &reply
);
311 xpc_release(od_pipe
);
312 od_pipe
= get_pipe(true);
316 /* just loop and try to send again */
320 if (_valid_token(reply
) == true) {
323 /* fall through since we got a valid response */
326 /* release and NULL the pipe it'll break the loop */
327 xpc_release(od_pipe
);
333 if (od_pipe
!= NULL
) {
334 xpc_release(od_pipe
);
338 xpc_release(payload
);
345 _ds_list(si_mod_t
*si
, int cat
, const char *procname
, const void *extra
, od_extract_t extract
)
347 __block si_list_t
*list
;
348 uint64_t va
= 0, vb
= 0;
349 xpc_object_t reply
, result
;
351 if (procname
== NULL
) return NULL
;
353 _ds_get_validation(si
, &va
, &vb
, cat
);
356 reply
= _od_rpc_call(procname
, NULL
, _od_xpc_pipe
);
358 result
= xpc_dictionary_get_value(reply
, OD_RPC_RESULT
);
359 if (result
!= NULL
&& xpc_get_type(result
) == XPC_TYPE_ARRAY
) {
360 xpc_array_apply(result
, ^bool(size_t index
, xpc_object_t value
) {
361 si_item_t
*item
= extract(si
, value
, extra
, va
, vb
);
362 list
= si_list_add(list
, item
);
363 si_item_release(item
);
376 _ds_item(si_mod_t
*si
, int cat
, const char *procname
, const void *extra
, od_extract_t extract
, xpc_object_t payload
)
379 uint64_t va
= 0, vb
= 0;
380 si_item_t
*item
= NULL
;
382 if (procname
== NULL
) return NULL
;
384 result
= _od_rpc_call(procname
, payload
, _od_xpc_pipe
);
385 if (result
!= NULL
) {
386 _ds_get_validation(si
, &va
, &vb
, cat
);
387 if (xpc_dictionary_get_int64(result
, OD_RPC_ERROR
) == 0) {
388 item
= extract(si
, result
, extra
, va
, vb
);
398 _ds_is_valid(si_mod_t
*si
, si_item_t
*item
)
403 uint32_t oldval
, newval
;
405 if (si
== NULL
) return 0;
406 if (item
== NULL
) return 0;
407 if (si
->name
== NULL
) return 0;
408 if (item
->src
== NULL
) return 0;
410 pp
= (ds_si_private_t
*)si
->private;
411 if (pp
== NULL
) return 0;
413 src
= (si_mod_t
*)item
->src
;
415 if (src
->name
== NULL
) return 0;
416 if (string_not_equal(si
->name
, src
->name
)) return 0;
418 /* check global invalidation */
419 oldval
= item
->validation_a
;
421 status
= notify_peek(pp
->notify_token_global
, &newval
);
422 if (status
!= NOTIFY_STATUS_OK
) return 0;
424 newval
= ntohl(newval
);
425 if (oldval
!= newval
) return 0;
427 oldval
= item
->validation_b
;
429 if (item
->type
== CATEGORY_USER
) status
= notify_peek(pp
->notify_token_user
, &newval
);
430 else if (item
->type
== CATEGORY_GROUP
) status
= notify_peek(pp
->notify_token_group
, &newval
);
431 else if (item
->type
== CATEGORY_SERVICE
) status
= notify_peek(pp
->notify_token_service
, &newval
);
434 if (status
!= NOTIFY_STATUS_OK
) return 0;
436 newval
= ntohl(newval
);
437 if (oldval
!= newval
) return 0;
443 _xpc_query_key_string(const char *key
, const char *value
)
445 xpc_object_t payload
;
447 if (value
== NULL
) return NULL
;
449 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
450 if (payload
== NULL
) return NULL
;
452 xpc_dictionary_set_string(payload
, key
, value
);
458 _xpc_query_key_id(const char *key
, id_t idValue
)
460 xpc_object_t payload
;
462 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
463 if (payload
== NULL
) return NULL
;
465 xpc_dictionary_set_int64(payload
, key
, idValue
);
471 _xpc_query_key_uuid(const char *key
, uuid_t uu
)
473 xpc_object_t payload
;
475 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
476 if (payload
== NULL
) return NULL
;
478 xpc_dictionary_set_uuid(payload
, key
, uu
);
484 _xpc_query_key_int(const char *key
, int64_t intValue
)
486 xpc_object_t payload
;
488 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
489 if (payload
== NULL
) return NULL
;
491 xpc_dictionary_set_int64(payload
, key
, intValue
);
499 _extract_string_from_xpc_array_index(xpc_object_t reply
, int index
, const char **str
)
503 if (xpc_array_get_count(reply
) < index
) return -1;
505 value
= xpc_array_get_value(reply
, index
);
506 if (xpc_get_type(value
) != XPC_TYPE_STRING
) return -1;
508 *str
= xpc_string_get_string_ptr(value
);
513 _extract_string_from_xpc_object(xpc_object_t value
, const char **str
)
515 if (value
== NULL
) return -1;
516 else if (xpc_get_type(value
) == XPC_TYPE_STRING
)
518 *str
= xpc_string_get_string_ptr(value
);
521 else if (xpc_get_type(value
) == XPC_TYPE_ARRAY
)
523 return _extract_string_from_xpc_array_index(value
, 0, str
);
530 _extract_uint32_from_xpc_object(xpc_object_t value
, uint32_t *val32
)
534 if (value
== NULL
) return -1;
535 type
= xpc_get_type(value
);
537 if (type
== XPC_TYPE_STRING
)
539 *val32
= atoi(xpc_string_get_string_ptr(value
));
542 else if (type
== XPC_TYPE_INT64
)
544 *val32
= (uint32_t)xpc_int64_get_value(value
);
547 else if (type
== XPC_TYPE_BOOL
)
549 *val32
= (uint32_t)xpc_bool_get_value(value
);
552 else if (type
== XPC_TYPE_ARRAY
)
554 if (xpc_array_get_count(value
) == 0) return -1;
555 return _extract_uint32_from_xpc_object(xpc_array_get_value(value
, 0), val32
);
562 _extract_string_list_from_xpc_array_index(xpc_object_t reply
, int index
, unsigned int *len
, char ***list
)
565 xpc_object_t xpc_array
= xpc_array_get_value(reply
, index
);
567 if ((xpc_array
== NULL
) || (xpc_get_type(xpc_array
) != XPC_TYPE_ARRAY
)) return -1;
569 result
= calloc(xpc_array_get_count(xpc_array
) + 1, sizeof(*result
));
570 if (result
== NULL
) return -1;
572 /* include trailing NULL */
573 if (len
!= NULL
) (*len
) = xpc_array_get_count(xpc_array
) + 1;
575 xpc_array_apply(xpc_array
, ^bool(size_t idx
, xpc_object_t value
) {
576 result
[idx
] = (char *)xpc_string_get_string_ptr(value
);
585 _extract_uint32_from_xpc_array_index(xpc_object_t reply
, int index
, uint32_t *val32
)
587 xpc_object_t value
= xpc_array_get_value(reply
, index
);
588 return _extract_uint32_from_xpc_object(value
, val32
);
592 _extract_string_list_from_xpc_array(xpc_object_t xpc_array
, unsigned int *len
, char ***list
)
596 if ((xpc_array
== NULL
) || (xpc_get_type(xpc_array
) != XPC_TYPE_ARRAY
)) return -1;
598 result
= calloc(xpc_array_get_count(xpc_array
) + 1, sizeof(*result
));
599 if (result
== NULL
) return -1;
601 /* include trailing NULL */
602 if (len
!= NULL
) (*len
) = xpc_array_get_count(xpc_array
) + 1;
604 xpc_array_apply(xpc_array
, ^bool(size_t idx
, xpc_object_t value
) {
605 result
[idx
] = (char *)xpc_string_get_string_ptr(value
);
614 _extract_string_from_xpc_dict(xpc_object_t reply
, const char *key
, const char **str
)
616 xpc_object_t value
= xpc_dictionary_get_value(reply
, key
);
619 if (value
== NULL
) return -1;
621 if (xpc_get_type(value
) != XPC_TYPE_STRING
) return -1;
623 result
= xpc_string_get_string_ptr(value
);
624 if (result
== NULL
) return -1;
631 _extract_uint32_from_xpc_dict(xpc_object_t reply
, const char *key
, uint32_t *val32
)
633 xpc_object_t value
= xpc_dictionary_get_value(reply
, key
);
634 return _extract_uint32_from_xpc_object(value
, val32
);
652 _extract_user_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
657 if (xpc_array_get_count(reply
) < 7) return NULL
;
659 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.pw_name
)) return NULL
;
660 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.pw_passwd
)) return NULL
;
661 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.pw_uid
)) return NULL
;
662 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.pw_gid
)) return NULL
;
663 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.pw_gecos
)) return NULL
;
664 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.pw_dir
)) return NULL
;
665 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.pw_shell
)) return NULL
;
668 tmp
.pw_change
= (time_t)0;
669 tmp
.pw_expire
= (time_t)0;
670 tmp
.pw_class
= (char *)"";
672 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
);
676 _extract_user_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
678 __block
struct passwd tmp
;
679 __block
int status
= 0;
680 __block
int parts
= 3;
682 tmp
.pw_name
= (char *)"";
683 tmp
.pw_passwd
= (char *)"*";
684 tmp
.pw_uid
= (uid_t
)0;
685 tmp
.pw_gid
= (gid_t
)0;
686 tmp
.pw_change
= (time_t)0;
687 tmp
.pw_expire
= (time_t)0;
688 tmp
.pw_class
= (char *)"";
689 tmp
.pw_gecos
= (char *)"";
690 tmp
.pw_dir
= (char *)"/var/empty";
691 tmp
.pw_shell
= (char *)"/usr/bin/false";
693 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
694 if (key
== NULL
) return true;
695 else if (!strcmp(key
, "pw_name"))
697 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_name
);
698 if (status
== 0) parts
--;
700 else if (!strcmp(key
, "pw_passwd"))
702 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_passwd
);
703 /* no parts check - this value is optional */
705 else if (!strcmp(key
, "pw_uid"))
707 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.pw_uid
);
708 if (status
== 0) parts
--;
710 else if (!strcmp(key
, "pw_gid"))
712 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.pw_gid
);
713 if (status
== 0) parts
--;
715 else if (!strcmp(key
, "pw_change"))
717 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.pw_change
);
718 /* no parts check - this value is optional */
720 else if (!strcmp(key
, "pw_expire"))
722 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.pw_expire
);
723 /* no parts check - this value is optional */
725 else if (!strcmp(key
, "pw_class"))
727 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_class
);
728 /* no parts check - this value is optional */
730 else if (!strcmp(key
, "pw_gecos"))
732 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_gecos
);
733 /* no parts check - this value is optional */
735 else if (!strcmp(key
, "pw_dir"))
737 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_dir
);
738 /* no parts check - this value is optional */
740 else if (!strcmp(key
, "pw_shell"))
742 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_shell
);
743 /* no parts check - this value is optional */
748 if ((status
!= 0) || (parts
!= 0)) return NULL
;
750 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
);
754 _extract_user(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
758 if (si
== NULL
) return NULL
;
759 if (reply
== NULL
) return NULL
;
761 type
= xpc_get_type(reply
);
763 if (type
== XPC_TYPE_ARRAY
) return _extract_user_array(si
, reply
, valid_global
, valid_cat
);
764 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_user_dict(si
, reply
, valid_global
, valid_cat
);
774 * optional members : array of string
779 _extract_group_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
784 int arraycount
= xpc_array_get_count(reply
);
786 if ((arraycount
< 2) || (arraycount
> 3)) return NULL
;
788 memset(&tmp
, 0, sizeof(tmp
));
790 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.gr_name
)) return NULL
;
791 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.gr_gid
)) return NULL
;
795 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.gr_mem
)) return NULL
;
799 tmp
.gr_passwd
= (char *)"*";
801 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
);
809 _extract_group_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
812 __block
struct group tmp
;
813 __block
int status
= 0;
814 __block
int parts
= 2;
816 tmp
.gr_name
= (char *)"";
817 tmp
.gr_passwd
= (char *)"*";
818 tmp
.gr_gid
= (gid_t
)0;
821 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
822 if (key
== NULL
) return true;
823 else if (!strcmp(key
, "gr_name"))
825 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.gr_name
);
826 if (status
== 0) parts
--;
828 else if (!strcmp(key
, "gr_passwd"))
830 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.gr_passwd
);
831 /* no parts check - this value is optional */
833 else if (!strcmp(key
, "gr_gid"))
835 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.gr_gid
);
836 if (status
== 0) parts
--;
838 else if (!strcmp(key
, "gr_mem"))
840 status
|= _extract_string_list_from_xpc_array(value
, NULL
, (char ***)&tmp
.gr_mem
);
841 /* no parts check - this value is optional */
846 if ((status
!= 0) || (parts
!= 0))
852 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
);
860 _extract_group(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
864 if (si
== NULL
) return NULL
;
865 if (reply
== NULL
) return NULL
;
867 type
= xpc_get_type(reply
);
868 if (type
== XPC_TYPE_ARRAY
) return _extract_group_array(si
, reply
, valid_global
, valid_cat
);
869 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_group_dict(si
, reply
, valid_global
, valid_cat
);
883 _extract_netgroup_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
885 const char *host
, *user
, *domain
;
888 if (xpc_array_get_count(reply
) != 3) return NULL
;
890 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&host
)) return NULL
;
891 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&user
)) return NULL
;
892 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&domain
)) return NULL
;
894 return (si_item_t
*)LI_ils_create("L4488sss", (unsigned long)si
, CATEGORY_NETGROUP
, 1, valid_global
, valid_cat
, host
, user
, domain
);
898 _extract_netgroup_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
900 __block
const char *host
= "";
901 __block
const char *user
= "";
902 __block
const char *domain
= "";
903 __block
int status
= 0;
904 __block
int parts
= 3;
906 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
907 if (key
== NULL
) return true;
908 else if (!strcmp(key
, "host"))
910 status
|= _extract_string_from_xpc_object(value
, (const char **)&host
);
911 if (status
== 0) parts
--;
913 else if (!strcmp(key
, "user"))
915 status
|= _extract_string_from_xpc_object(value
, (const char **)&user
);
916 if (status
== 0) parts
--;
918 else if (!strcmp(key
, "domain"))
920 status
|= _extract_string_from_xpc_object(value
, (const char **)&domain
);
921 if (status
== 0) parts
--;
926 if ((status
!= 0) || (parts
!= 0)) return NULL
;
928 return (si_item_t
*)LI_ils_create("L4488sss", (unsigned long)si
, CATEGORY_NETGROUP
, 1, valid_global
, valid_cat
, host
, user
, domain
);
932 _extract_netgroup(si_mod_t
*si
, xpc_object_t reply
, const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
936 if (si
== NULL
) return NULL
;
937 if (reply
== NULL
) return NULL
;
939 type
= xpc_get_type(reply
);
940 if (type
== XPC_TYPE_ARRAY
) return _extract_netgroup_array(si
, reply
, valid_global
, valid_cat
);
941 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_netgroup_dict(si
, reply
, valid_global
, valid_cat
);
951 * optional members : array of string
956 _extract_alias_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
961 int arraycount
= xpc_array_get_count(reply
);
963 if ((arraycount
< 2) || (arraycount
> 3)) return NULL
;
965 memset(&tmp
, 0, sizeof(tmp
));
967 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.alias_name
)) return NULL
;
968 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.alias_local
)) return NULL
;
972 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.alias_members
)) return NULL
;
975 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
);
977 free(tmp
.alias_members
);
983 _extract_alias_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
986 __block
struct aliasent tmp
;
987 __block
int status
= 0;
988 __block
int parts
= 2;
990 tmp
.alias_name
= (char *)"";
992 tmp
.alias_members
= NULL
;
993 tmp
.alias_members_len
= 0;
995 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
996 if (key
== NULL
) return true;
997 else if (!strcmp(key
, "alias_name"))
999 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.alias_name
);
1000 if (status
== 0) parts
--;
1002 else if (!strcmp(key
, "alias_local"))
1004 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.alias_local
);
1005 if (status
== 0) parts
--;
1007 else if (!strcmp(key
, "alias_members"))
1009 status
|= _extract_string_list_from_xpc_array(value
, &tmp
.alias_members_len
, (char ***)&tmp
.alias_members
);
1010 /* no parts check - this value is optional */
1015 if ((status
!= 0) || (parts
!= 0))
1017 free(tmp
.alias_members
);
1021 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
);
1023 free(tmp
.alias_members
);
1029 _extract_alias(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1033 if (si
== NULL
) return NULL
;
1034 if (reply
== NULL
) return NULL
;
1036 type
= xpc_get_type(reply
);
1037 if (type
== XPC_TYPE_ARRAY
) return _extract_alias_array(si
, reply
, valid_global
, valid_cat
);
1038 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_alias_dict(si
, reply
, valid_global
, valid_cat
);
1048 * optional aliases : array of string
1053 _extract_network_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1058 int arraycount
= xpc_array_get_count(reply
);
1060 if ((arraycount
< 2) || (arraycount
> 3)) return NULL
;
1062 memset(&tmp
, 0, sizeof(tmp
));
1064 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.n_name
)) return NULL
;
1065 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.n_net
)) return NULL
;
1067 if (arraycount
== 3)
1069 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.n_aliases
)) return NULL
;
1073 tmp
.n_addrtype
= AF_INET
;
1075 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
);
1077 free(tmp
.n_aliases
);
1083 _extract_network_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1086 __block
struct netent tmp
;
1087 __block
int status
= 0;
1088 __block
int parts
= 2;
1090 if (si
== NULL
) return NULL
;
1091 if (reply
== NULL
) return NULL
;
1093 tmp
.n_name
= (char *)"";
1094 tmp
.n_aliases
= NULL
;
1098 tmp
.n_addrtype
= AF_INET
;
1100 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1101 if (key
== NULL
) return true;
1102 else if (!strcmp(key
, "n_name"))
1104 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.n_name
);
1105 if (status
== 0) parts
--;
1107 else if (!strcmp(key
, "n_aliases"))
1109 status
|= _extract_string_list_from_xpc_array(value
, NULL
, (char ***)&tmp
.n_aliases
);
1110 /* no parts check - this value is optional */
1112 else if (!strcmp(key
, "n_net"))
1114 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.n_net
);
1115 if (status
== 0) parts
--;
1120 if ((status
!= 0) || (parts
!= 0))
1122 free(tmp
.n_aliases
);
1126 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
);
1128 free(tmp
.n_aliases
);
1134 _extract_network(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1138 if (si
== NULL
) return NULL
;
1139 if (reply
== NULL
) return NULL
;
1141 type
= xpc_get_type(reply
);
1142 if (type
== XPC_TYPE_ARRAY
) return _extract_network_array(si
, reply
, valid_global
, valid_cat
);
1143 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_network_dict(si
, reply
, valid_global
, valid_cat
);
1154 * optional aliases : array of string
1159 _extract_service_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1164 int arraycount
= xpc_array_get_count(reply
);
1166 if ((arraycount
< 3) || (arraycount
> 4)) return NULL
;
1168 memset(&tmp
, 0, sizeof(tmp
));
1170 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.s_name
)) return NULL
;
1171 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.s_port
)) return NULL
;
1172 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.s_proto
)) return NULL
;
1174 if (arraycount
== 4)
1176 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.s_aliases
)) return NULL
;
1179 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
);
1181 free(tmp
.s_aliases
);
1187 _extract_service_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1190 __block
struct servent tmp
;
1191 __block
int status
= 0;
1192 __block
int parts
= 3;
1194 if (si
== NULL
) return NULL
;
1195 if (reply
== NULL
) return NULL
;
1197 tmp
.s_name
= (char *)"";
1198 tmp
.s_aliases
= NULL
;
1200 tmp
.s_proto
= (char *)"";
1202 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1203 if (key
== NULL
) return true;
1204 else if (!strcmp(key
, "s_name"))
1206 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.s_name
);
1207 if (status
== 0) parts
--;
1209 else if (!strcmp(key
, "s_aliases"))
1211 status
|= _extract_string_list_from_xpc_array(value
, NULL
, (char ***)&tmp
.s_aliases
);
1212 /* no parts check - this value is optional */
1214 else if (!strcmp(key
, "s_port"))
1217 status
|= _extract_uint32_from_xpc_object(value
, &v32
);
1220 tmp
.s_port
= (unsigned int)htons(v32
); // ugh
1224 else if (!strcmp(key
, "s_proto"))
1226 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.s_proto
);
1227 if (status
== 0) parts
--;
1232 if ((status
!= 0) || (parts
!= 0))
1234 free(tmp
.s_aliases
);
1238 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
);
1240 free(tmp
.s_aliases
);
1246 _extract_service(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1250 if (si
== NULL
) return NULL
;
1251 if (reply
== NULL
) return NULL
;
1253 type
= xpc_get_type(reply
);
1254 if (type
== XPC_TYPE_ARRAY
) return _extract_service_array(si
, reply
, valid_global
, valid_cat
);
1255 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_service_dict(si
, reply
, valid_global
, valid_cat
);
1265 * optional aliases : array of string
1269 _extract_protocol_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1272 struct protoent tmp
;
1274 int arraycount
= xpc_array_get_count(reply
);
1276 if ((arraycount
< 2) || (arraycount
> 3)) return NULL
;
1278 memset(&tmp
, 0, sizeof(tmp
));
1280 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.p_name
)) return NULL
;
1281 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.p_proto
)) return NULL
;
1283 if (arraycount
== 3)
1285 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.p_aliases
)) return NULL
;
1288 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
);
1290 free(tmp
.p_aliases
);
1296 _extract_protocol_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1299 __block
struct protoent tmp
;
1300 __block
int status
= 0;
1301 __block
int parts
= 2;
1303 tmp
.p_name
= (char *)"";
1305 tmp
.p_aliases
= NULL
;
1307 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1308 if (key
== NULL
) return true;
1309 else if (!strcmp(key
, "p_name"))
1311 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.p_name
);
1312 if (status
== 0) parts
--;
1314 else if (!strcmp(key
, "p_proto"))
1316 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.p_proto
);
1317 if (status
== 0) parts
--;
1319 else if (!strcmp(key
, "p_aliases"))
1321 status
|= _extract_string_list_from_xpc_array(value
, NULL
, (char ***)&tmp
.p_aliases
);
1322 /* no parts check - this value is optional */
1327 if ((status
!= 0) || (parts
!= 0))
1329 free(tmp
.p_aliases
);
1333 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
);
1335 free(tmp
.p_aliases
);
1341 _extract_protocol(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1345 if (si
== NULL
) return NULL
;
1346 if (reply
== NULL
) return NULL
;
1348 type
= xpc_get_type(reply
);
1349 if (type
== XPC_TYPE_ARRAY
) return _extract_protocol_array(si
, reply
, valid_global
, valid_cat
);
1350 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_protocol_dict(si
, reply
, valid_global
, valid_cat
);
1360 * optional aliases : array of string
1365 _extract_rpc_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1370 int arraycount
= xpc_array_get_count(reply
);
1372 if ((arraycount
< 2) || (arraycount
> 3)) return NULL
;
1374 memset(&tmp
, 0, sizeof(tmp
));
1376 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.r_name
)) return NULL
;
1377 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.r_number
)) return NULL
;
1379 if (arraycount
== 3)
1381 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.r_aliases
)) return NULL
;
1384 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
);
1386 free(tmp
.r_aliases
);
1392 _extract_rpc_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1395 __block
struct rpcent tmp
;
1396 __block
int status
= 0;
1397 __block
int parts
= 2;
1399 tmp
.r_name
= (char *)"";
1401 tmp
.r_aliases
= NULL
;
1403 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1404 if (key
== NULL
) return true;
1405 else if (!strcmp(key
, "r_name"))
1407 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.r_name
);
1408 if (status
== 0) parts
--;
1410 else if (!strcmp(key
, "r_number"))
1412 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.r_number
);
1413 if (status
== 0) parts
--;
1415 else if (!strcmp(key
, "r_aliases"))
1417 status
|= _extract_string_list_from_xpc_array(value
, NULL
, (char ***)&tmp
.r_aliases
);
1418 /* no parts check - this value is optional */
1423 if ((status
!= 0) || (parts
!= 0))
1425 free(tmp
.r_aliases
);
1429 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
);
1431 free(tmp
.r_aliases
);
1437 _extract_rpc(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1441 if (si
== NULL
) return NULL
;
1442 if (reply
== NULL
) return NULL
;
1444 type
= xpc_get_type(reply
);
1445 if (type
== XPC_TYPE_ARRAY
) return _extract_rpc_array(si
, reply
, valid_global
, valid_cat
);
1446 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_rpc_dict(si
, reply
, valid_global
, valid_cat
);
1464 _extract_fstab_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1466 __block
struct fstab tmp
;
1469 if (xpc_array_get_count(reply
) != 7) return NULL
;
1471 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.fs_file
)) return NULL
;
1472 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.fs_spec
)) return NULL
;
1473 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.fs_freq
)) return NULL
;
1474 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.fs_passno
)) return NULL
;
1475 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.fs_mntops
)) return NULL
;
1476 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.fs_type
)) return NULL
;
1477 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.fs_vfstype
)) return NULL
;
1479 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
);
1483 _extract_fstab_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1485 __block
struct fstab tmp
;
1486 __block
int status
= 0;
1487 __block
int parts
= 7;
1490 tmp
.fs_spec
= (char *)"";
1493 tmp
.fs_mntops
= (char *)"";
1494 tmp
.fs_type
= (char *)"";
1495 tmp
.fs_vfstype
= (char *)"";
1497 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1498 if (key
== NULL
) return true;
1499 else if (!strcmp(key
, "fs_file"))
1501 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.fs_file
);
1502 if (status
== 0) parts
--;
1504 else if (!strcmp(key
, "fs_spec"))
1506 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.fs_spec
);
1507 if (status
== 0) parts
--;
1509 else if (!strcmp(key
, "fs_freq"))
1511 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.fs_freq
);
1512 if (status
== 0) parts
--;
1514 else if (!strcmp(key
, "fs_passno"))
1516 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.fs_passno
);
1517 if (status
== 0) parts
--;
1519 else if (!strcmp(key
, "fs_mntops"))
1521 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.fs_mntops
);
1522 if (status
== 0) parts
--;
1524 else if (!strcmp(key
, "fs_type"))
1526 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.fs_type
);
1527 if (status
== 0) parts
--;
1529 else if (!strcmp(key
, "fs_vfstype"))
1531 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.fs_vfstype
);
1532 if (status
== 0) parts
--;
1537 if ((status
!= 0) || (parts
!= 0)) return NULL
;
1539 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
);
1543 _extract_fstab(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1547 if (si
== NULL
) return NULL
;
1548 if (reply
== NULL
) return NULL
;
1550 type
= xpc_get_type(reply
);
1551 if (type
== XPC_TYPE_ARRAY
) return _extract_fstab_array(si
, reply
, valid_global
, valid_cat
);
1552 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_fstab_dict(si
, reply
, valid_global
, valid_cat
);
1558 _extract_mac_mac(si_mod_t
*si
, xpc_object_t reply
, const void *extra
, uint64_t valid_global
, uint64_t valid_cat
)
1562 const char *value
= NULL
;
1565 if (si
== NULL
) return NULL
;
1566 if (reply
== NULL
) return NULL
;
1567 if (extra
== NULL
) return NULL
;
1569 type
= xpc_get_type(reply
);
1570 if (type
== XPC_TYPE_ARRAY
)
1572 if (xpc_array_get_count(reply
) >= 1)
1574 if (0 != _extract_string_from_xpc_array_index(reply
, 0, (const char **)&value
)) return NULL
;
1577 else if (type
== XPC_TYPE_DICTIONARY
)
1579 if (0 != _extract_string_from_xpc_dict(reply
, "mac", &value
)) return NULL
;
1582 if (value
== NULL
|| value
[0] == '\0') return NULL
;
1584 cmac
= si_standardize_mac_address(value
);
1585 if (cmac
== NULL
) return NULL
;
1587 out
= (si_item_t
*)LI_ils_create("L4488ss", (unsigned long)si
, CATEGORY_MAC
, 1, valid_global
, valid_cat
, extra
, cmac
);
1595 _extract_mac_name(si_mod_t
*si
, xpc_object_t reply
, const void *extra
, uint64_t valid_global
, uint64_t valid_cat
)
1598 const char *name
= NULL
;
1601 if (si
== NULL
) return NULL
;
1602 if (reply
== NULL
) return NULL
;
1603 if (extra
== NULL
) return NULL
;
1605 type
= xpc_get_type(reply
);
1606 if (type
== XPC_TYPE_ARRAY
)
1608 if (xpc_array_get_count(reply
) >= 1)
1610 if (0 != _extract_string_from_xpc_array_index(reply
, 0, (const char **)&name
)) return NULL
;
1613 else if (type
== XPC_TYPE_DICTIONARY
)
1615 if (0 != _extract_string_from_xpc_dict(reply
, "name", &name
)) return NULL
;
1618 if (name
== NULL
) return NULL
;
1620 out
= (si_item_t
*)LI_ils_create("L4488ss", (unsigned long)si
, CATEGORY_MAC
, 1, valid_global
, valid_cat
, name
, extra
);
1628 ds_user_byname(si_mod_t
*si
, const char *name
)
1630 xpc_object_t payload
;
1633 if (!_od_running()) return NULL
;
1635 LI_OS_ACTIVITY("Retrieve User by Name");
1637 payload
= _xpc_query_key_string("name", name
);
1638 if (payload
== NULL
) return NULL
;
1640 item
= _ds_item(si
, CATEGORY_USER
, "getpwnam", NULL
, _extract_user
, payload
);
1642 xpc_release(payload
);
1647 ds_user_byuid(si_mod_t
*si
, uid_t uid
)
1649 xpc_object_t payload
;
1652 if (!_od_running()) return NULL
;
1654 LI_OS_ACTIVITY("Retrieve User by ID");
1656 payload
= _xpc_query_key_id("uid", uid
);
1657 if (payload
== NULL
) return NULL
;
1659 item
= _ds_item(si
, CATEGORY_USER
, "getpwuid", NULL
, _extract_user
, payload
);
1661 xpc_release(payload
);
1666 ds_user_byuuid(si_mod_t
*si
, uuid_t uuid
)
1668 xpc_object_t payload
;
1671 if (!_od_running()) return NULL
;
1673 LI_OS_ACTIVITY("Retrieve User by UUID");
1675 payload
= _xpc_query_key_uuid("uuid", uuid
);
1676 if (payload
== NULL
) return NULL
;
1678 item
= _ds_item(si
, CATEGORY_USER
, "getpwuuid", NULL
, _extract_user
, payload
);
1680 xpc_release(payload
);
1685 ds_user_all(si_mod_t
*si
)
1687 LI_OS_ACTIVITY("Performance Impact - Enumerate all users");
1689 return _ds_list(si
, CATEGORY_USER
, "getpwent", NULL
, _extract_user
);
1693 ds_group_byname(si_mod_t
*si
, const char *name
)
1695 xpc_object_t payload
;
1698 if (!_od_running()) return NULL
;
1700 LI_OS_ACTIVITY("Retrieve Group by Name");
1702 payload
= _xpc_query_key_string("name", name
);
1703 if (payload
== NULL
) return NULL
;
1705 item
= _ds_item(si
, CATEGORY_GROUP
, "getgrnam", NULL
, _extract_group
, payload
);
1707 xpc_release(payload
);
1712 ds_group_bygid(si_mod_t
*si
, gid_t gid
)
1714 xpc_object_t payload
;
1717 if (!_od_running()) return NULL
;
1719 LI_OS_ACTIVITY("Retrieve Group by ID");
1721 payload
= _xpc_query_key_id("gid", gid
);
1722 if (payload
== NULL
) return NULL
;
1724 item
= _ds_item(si
, CATEGORY_GROUP
, "getgrgid", NULL
, _extract_group
, payload
);
1726 xpc_release(payload
);
1731 ds_group_byuuid(si_mod_t
*si
, uuid_t uuid
)
1733 xpc_object_t payload
;
1736 if (!_od_running()) return NULL
;
1738 LI_OS_ACTIVITY("Retrieve Group by UUID");
1740 payload
= _xpc_query_key_uuid("uuid", uuid
);
1741 if (payload
== NULL
) return NULL
;
1743 item
= _ds_item(si
, CATEGORY_GROUP
, "getgruuid", NULL
, _extract_group
, payload
);
1745 xpc_release(payload
);
1750 ds_group_all(si_mod_t
*si
)
1752 if (!_od_running()) return NULL
;
1753 LI_OS_ACTIVITY("Performance Impact - Enumerate all Groups");
1754 return _ds_list(si
, CATEGORY_GROUP
, "getgrent", NULL
, _extract_group
);
1758 ds_grouplist(si_mod_t
*si
, const char *name
, uint32_t ngroups
)
1760 xpc_object_t payload
, reply
;
1761 si_item_t
*item
= NULL
;
1762 os_activity_t activity
;
1764 if (!_od_running()) return NULL
;
1765 if (name
== NULL
) return NULL
;
1768 activity
= os_activity_create("Performance impact - Resolve user group list (>17 groups)", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1769 os_log(OS_LOG_DEFAULT
, "Too many groups requested (%u). Can cause performance issues when network directories are involved", ngroups
);
1771 activity
= os_activity_create("Resolve user group list", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
);
1773 os_activity_scope(activity
);
1775 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
1776 if (payload
== NULL
) return NULL
;
1778 xpc_dictionary_set_string(payload
, "name", name
);
1779 xpc_dictionary_set_int64(payload
, "ngroups", ngroups
);
1781 reply
= _od_rpc_call("getgrouplist", payload
, _od_xpc_pipe
);
1782 if (reply
!= NULL
) {
1784 const gid_t
*gidptr
= xpc_dictionary_get_data(reply
, "groups", &gidptrsz
);
1788 _ds_get_validation(si
, &va
, &vb
, CATEGORY_GROUPLIST
);
1790 /* see what we were sent */
1791 if (0 == _extract_uint32_from_xpc_dict(reply
, "count", &count
))
1795 item
= (si_item_t
*)LI_ils_create("L4488s4@", (unsigned long)si
, CATEGORY_GROUPLIST
, 1, va
, vb
, name
, count
,
1803 xpc_release(payload
);
1804 os_release(activity
);
1810 ds_netgroup_byname(si_mod_t
*si
, const char *name
)
1812 xpc_object_t payload
;
1813 si_list_t
*list
= NULL
;
1816 if (!_od_running()) return NULL
;
1818 LI_OS_ACTIVITY("Retrieve netgroup by name");
1820 payload
= _xpc_query_key_string("netgroup", name
);
1821 if (payload
== NULL
) return NULL
;
1823 item
= _ds_item(si
, CATEGORY_NETGROUP
, "getnetgrent", NULL
, _extract_netgroup
, payload
);
1825 list
= si_list_add(list
, item
);
1826 si_item_release(item
);
1829 xpc_release(payload
);
1835 ds_in_netgroup(si_mod_t
*si
, const char *group
, const char *host
, const char *user
, const char *domain
)
1837 xpc_object_t payload
, reply
;
1840 if (!_od_running()) return 0;
1842 LI_OS_ACTIVITY("Match netgroup");
1844 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
1845 if (payload
== NULL
) return 0;
1847 xpc_dictionary_set_string(payload
, "netgroup", (group ? group
: ""));
1848 xpc_dictionary_set_string(payload
, "host", (host ? host
: ""));
1849 xpc_dictionary_set_string(payload
, "user", (user ? user
: ""));
1850 xpc_dictionary_set_string(payload
, "domain", (domain ? domain
: ""));
1852 reply
= _od_rpc_call("innetgr", payload
, _od_xpc_pipe
);
1853 if (reply
!= NULL
) {
1854 is_innetgr
= xpc_dictionary_get_bool(reply
, OD_RPC_RESULT
);
1860 xpc_release(payload
);
1866 ds_alias_byname(si_mod_t
*si
, const char *name
)
1868 xpc_object_t payload
;
1871 if (!_od_running()) return NULL
;
1873 LI_OS_ACTIVITY("Retrieve alias by name");
1874 payload
= _xpc_query_key_string("name", name
);
1875 if (payload
== NULL
) return NULL
;
1877 item
= _ds_item(si
, CATEGORY_ALIAS
, "alias_getbyname", NULL
, _extract_alias
, payload
);
1879 xpc_release(payload
);
1884 ds_alias_all(si_mod_t
*si
)
1886 if (!_od_running()) return NULL
;
1887 LI_OS_ACTIVITY("Enumerate all alias entries");
1888 return _ds_list(si
, CATEGORY_ALIAS
, "alias_getent", NULL
, _extract_alias
);
1892 ds_network_byname(si_mod_t
*si
, const char *name
)
1894 xpc_object_t payload
;
1897 if (!_od_running()) return NULL
;
1899 LI_OS_ACTIVITY("Retrieve network by name");
1900 payload
= _xpc_query_key_string("name", name
);
1901 if (payload
== NULL
) return NULL
;
1903 item
= _ds_item(si
, CATEGORY_NETWORK
, "getnetbyname", NULL
, _extract_network
, payload
);
1905 xpc_release(payload
);
1910 ds_network_byaddr(si_mod_t
*si
, uint32_t addr
)
1912 unsigned char f1
, f2
, f3
;
1914 xpc_object_t payload
;
1917 if (!_od_running()) return NULL
;
1919 LI_OS_ACTIVITY("Retrieve network by address");
1926 if (f3
!= 0) snprintf(val
, sizeof(val
), "%u.%u.%u", f3
, f2
, f1
);
1927 else if (f2
!= 0) snprintf(val
, sizeof(val
), "%u.%u", f2
, f1
);
1928 else snprintf(val
, sizeof(val
), "%u", f1
);
1930 payload
= _xpc_query_key_string("net", val
);
1931 if (payload
== NULL
) return NULL
;
1933 item
= _ds_item(si
, CATEGORY_NETWORK
, "getnetbyaddr", NULL
, _extract_network
, payload
);
1935 xpc_release(payload
);
1940 ds_network_all(si_mod_t
*si
)
1942 if (!_od_running()) return NULL
;
1943 LI_OS_ACTIVITY("Emumerate all network entries");
1944 return _ds_list(si
, CATEGORY_NETWORK
, "getnetent", NULL
, _extract_network
);
1948 ds_service_byname(si_mod_t
*si
, const char *name
, const char *proto
)
1950 xpc_object_t payload
;
1954 if (!_od_running()) return NULL
;
1955 if (name
== NULL
) name
= "";
1956 if (proto
== NULL
) proto
= "";
1958 LI_OS_ACTIVITY("Retrieve service by name");
1960 /* Check our local service cache (see ds_addrinfo). */
1961 item
= pthread_getspecific(_ds_serv_cache_key
);
1964 s
= (struct servent
*)((uintptr_t)item
+ sizeof(si_item_t
));
1965 if (string_equal(name
, s
->s_name
)) return si_item_retain(item
);
1968 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
1969 if (payload
== NULL
) return NULL
;
1971 xpc_dictionary_set_string(payload
, "name", name
);
1972 xpc_dictionary_set_string(payload
, "proto", proto
);
1974 item
= _ds_item(si
, CATEGORY_SERVICE
, "getservbyname", NULL
, _extract_service
, payload
);
1976 xpc_release(payload
);
1982 ds_service_byport(si_mod_t
*si
, int port
, const char *proto
)
1984 xpc_object_t payload
;
1987 if (!_od_running()) return NULL
;
1989 LI_OS_ACTIVITY("Retrieve service by port");
1991 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
1992 if (payload
== NULL
) return NULL
;
1994 /* swap to native order, API passes network order */
1995 xpc_dictionary_set_int64(payload
, "port", ntohs(port
));
1996 xpc_dictionary_set_string(payload
, "proto", (proto ? proto
: ""));
1998 item
= _ds_item(si
, CATEGORY_SERVICE
, "getservbyport", NULL
, _extract_service
, payload
);
2000 xpc_release(payload
);
2006 ds_service_all(si_mod_t
*si
)
2008 if (!_od_running()) return NULL
;
2009 LI_OS_ACTIVITY("Enumerate all services");
2010 return _ds_list(si
, CATEGORY_SERVICE
, "getservent", NULL
, _extract_service
);
2014 ds_protocol_byname(si_mod_t
*si
, const char *name
)
2016 xpc_object_t payload
;
2019 if (!_od_running()) return NULL
;
2021 LI_OS_ACTIVITY("Retrieve protocol by name");
2022 payload
= _xpc_query_key_string("name", name
);
2023 if (payload
== NULL
) return NULL
;
2025 item
= _ds_item(si
, CATEGORY_PROTOCOL
, "getprotobyname", NULL
, _extract_protocol
, payload
);
2027 xpc_release(payload
);
2032 ds_protocol_bynumber(si_mod_t
*si
, int number
)
2034 xpc_object_t payload
;
2037 if (!_od_running()) return NULL
;
2039 LI_OS_ACTIVITY("Retrieve protocol by number");
2040 payload
= _xpc_query_key_int("number", number
);
2041 if (payload
== NULL
) return NULL
;
2043 item
= _ds_item(si
, CATEGORY_PROTOCOL
, "getprotobynumber", NULL
, _extract_protocol
, payload
);
2045 xpc_release(payload
);
2050 ds_protocol_all(si_mod_t
*si
)
2052 LI_OS_ACTIVITY("Enumerate all protocols");
2053 return _ds_list(si
, CATEGORY_PROTOCOL
, "getprotoent", NULL
, _extract_protocol
);
2057 ds_rpc_byname(si_mod_t
*si
, const char *name
)
2059 xpc_object_t payload
;
2062 if (!_od_running()) return NULL
;
2064 LI_OS_ACTIVITY("Retrieve RPC by name");
2065 payload
= _xpc_query_key_string("name", name
);
2066 if (payload
== NULL
) return NULL
;
2068 item
= _ds_item(si
, CATEGORY_RPC
, "getrpcbyname", NULL
, _extract_rpc
, payload
);
2070 xpc_release(payload
);
2075 ds_rpc_bynumber(si_mod_t
*si
, int number
)
2077 xpc_object_t payload
;
2080 if (!_od_running()) return NULL
;
2082 LI_OS_ACTIVITY("Retrieve RPC by number");
2083 payload
= _xpc_query_key_int("number", number
);
2084 if (payload
== NULL
) return NULL
;
2086 item
= _ds_item(si
, CATEGORY_RPC
, "getrpcbynumber", NULL
, _extract_rpc
, payload
);
2088 xpc_release(payload
);
2093 ds_rpc_all(si_mod_t
*si
)
2095 LI_OS_ACTIVITY("Enumerate all RPC entries");
2096 return _ds_list(si
, CATEGORY_RPC
, "getrpcent", NULL
, _extract_rpc
);
2100 ds_fs_byspec(si_mod_t
*si
, const char *name
)
2102 xpc_object_t payload
;
2105 if (!_od_running()) return NULL
;
2107 LI_OS_ACTIVITY("Lookup FS entry by spec");
2108 payload
= _xpc_query_key_string("name", name
);
2109 if (payload
== NULL
) return NULL
;
2111 item
= _ds_item(si
, CATEGORY_FS
, "getfsbyname", NULL
, _extract_fstab
, payload
);
2113 xpc_release(payload
);
2118 ds_fs_all(si_mod_t
*si
)
2120 LI_OS_ACTIVITY("Performance impact - Enumerate all FS entries");
2121 return _ds_list(si
, CATEGORY_FS
, "getfsent", NULL
, _extract_fstab
);
2125 ds_fs_byfile(si_mod_t
*si
, const char *name
)
2132 if (!_od_running()) return NULL
;
2133 if (name
== NULL
) return NULL
;
2135 LI_OS_ACTIVITY("Retrieve FS by file location");
2136 list
= ds_fs_all(si
);
2137 if (list
== NULL
) return NULL
;
2140 for (i
= 0; (i
< list
->count
) && (item
== NULL
); i
++)
2142 f
= (struct fstab
*)((uintptr_t)(list
->entry
[i
]) + sizeof(si_item_t
));
2143 if (string_equal(name
, f
->fs_file
)) item
= si_item_retain(list
->entry
[i
]);
2146 si_list_release(list
);
2151 ds_mac_byname(si_mod_t
*si
, const char *name
)
2153 xpc_object_t payload
;
2156 if (!_od_running()) return NULL
;
2158 LI_OS_ACTIVITY("Retrieve FS by name");
2159 payload
= _xpc_query_key_string("name", name
);
2160 if (payload
== NULL
) return NULL
;
2162 item
= _ds_item(si
, CATEGORY_MAC
, "getmacbyname", name
, _extract_mac_mac
, payload
);
2164 xpc_release(payload
);
2169 ds_mac_bymac(si_mod_t
*si
, const char *mac
)
2171 xpc_object_t payload
;
2175 if (!_od_running()) return NULL
;
2177 LI_OS_ACTIVITY("Retrieve MAC entry by MAC");
2178 cmac
= si_standardize_mac_address(mac
);
2179 if (cmac
== NULL
) return NULL
;
2181 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
2182 if (payload
== NULL
) return NULL
;
2184 payload
= _xpc_query_key_string("mac", cmac
);
2185 item
= _ds_item(si
, CATEGORY_MAC
, "gethostbymac", cmac
, _extract_mac_name
, payload
);
2188 xpc_release(payload
);
2196 si_module_static_ds(void)
2198 static const struct si_mod_vtable_s ds_vtable
=
2200 .sim_is_valid
= &_ds_is_valid
,
2202 .sim_user_byname
= &ds_user_byname
,
2203 .sim_user_byuid
= &ds_user_byuid
,
2204 .sim_user_byuuid
= &ds_user_byuuid
,
2205 .sim_user_all
= &ds_user_all
,
2207 .sim_group_byname
= &ds_group_byname
,
2208 .sim_group_bygid
= &ds_group_bygid
,
2209 .sim_group_byuuid
= &ds_group_byuuid
,
2210 .sim_group_all
= &ds_group_all
,
2212 .sim_grouplist
= &ds_grouplist
,
2214 .sim_netgroup_byname
= &ds_netgroup_byname
,
2215 .sim_in_netgroup
= &ds_in_netgroup
,
2217 .sim_alias_byname
= &ds_alias_byname
,
2218 .sim_alias_all
= &ds_alias_all
,
2220 /* host lookups not supported */
2221 .sim_host_byname
= NULL
,
2222 .sim_host_byaddr
= NULL
,
2223 .sim_host_all
= NULL
,
2225 .sim_network_byname
= &ds_network_byname
,
2226 .sim_network_byaddr
= &ds_network_byaddr
,
2227 .sim_network_all
= &ds_network_all
,
2229 .sim_service_byname
= &ds_service_byname
,
2230 .sim_service_byport
= &ds_service_byport
,
2231 .sim_service_all
= &ds_service_all
,
2233 .sim_protocol_byname
= &ds_protocol_byname
,
2234 .sim_protocol_bynumber
= &ds_protocol_bynumber
,
2235 .sim_protocol_all
= &ds_protocol_all
,
2237 .sim_rpc_byname
= &ds_rpc_byname
,
2238 .sim_rpc_bynumber
= &ds_rpc_bynumber
,
2239 .sim_rpc_all
= &ds_rpc_all
,
2241 .sim_fs_byspec
= &ds_fs_byspec
,
2242 .sim_fs_byfile
= &ds_fs_byfile
,
2243 .sim_fs_all
= &ds_fs_all
,
2245 .sim_mac_byname
= &ds_mac_byname
,
2246 .sim_mac_bymac
= &ds_mac_bymac
,
2248 /* si_mac_all not supported */
2249 .sim_mac_all
= NULL
,
2251 /* si_addrinfo not supported */
2252 .sim_wants_addrinfo
= NULL
,
2253 .sim_addrinfo
= NULL
,
2256 static si_mod_t si
=
2260 .flags
= SI_MOD_FLAG_STATIC
,
2263 .vtable
= &ds_vtable
,
2266 static dispatch_once_t once
;
2267 dispatch_once(&once
, ^{
2268 pthread_key_create(&_ds_serv_cache_key
, _ds_serv_cache_free
);
2270 si
.name
= strdup("ds");
2271 ds_si_private_t
*pp
= calloc(1, sizeof(ds_si_private_t
));
2275 pp
->notify_token_global
= -1;
2276 pp
->notify_token_user
= -1;
2277 pp
->notify_token_group
= -1;
2278 pp
->notify_token_service
= -1;
2282 * Don't register for notifications if the cache is disabled.
2283 * notifyd (notably) disables the cache to prevent deadlocks.
2285 if (gL1CacheEnabled
!= 0)
2288 * Errors in registering for cache invalidation notifications are ignored.
2289 * If there are failures, the tokens remain set to -1 which just causes
2290 * cached items to be invalidated.
2292 notify_register_check(kNotifyDSCacheInvalidation
, &(pp
->notify_token_global
));
2293 notify_register_check(kNotifyDSCacheInvalidationUser
, &(pp
->notify_token_user
));
2294 notify_register_check(kNotifyDSCacheInvalidationGroup
, &(pp
->notify_token_group
));
2295 notify_register_check(kNotifyDSCacheInvalidationService
, &(pp
->notify_token_service
));
2304 #endif /* DS_AVAILABLE */