2 * Copyright (c) 2008-2011 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This ds contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this ds except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
32 #include <arpa/inet.h>
41 #include <notify_keys.h>
43 #include <si_module.h>
44 #include <netdb_async.h>
47 #include <xpc/private.h>
48 #include <opendirectory/odipc.h>
49 #include <servers/bootstrap.h>
50 #include <bootstrap_priv.h>
51 #include <opendirectory/DSlibinfoMIG_types.h>
56 #define IPV6_ADDR_LEN 16
57 #define IPV4_ADDR_LEN 4
59 typedef si_item_t
*(*od_extract_t
)(si_mod_t
*si
, xpc_object_t reply
, const void *extra
, uint64_t valid_global
, uint64_t valid_cat
);
62 uint32_t notify_peek(int token
, uint32_t *val
);
66 int notify_token_global
;
67 int notify_token_user
;
68 int notify_token_group
;
69 int notify_token_service
;
72 extern uint32_t gL1CacheEnabled
;
73 extern int _si_opendirectory_disabled
;
75 static pthread_key_t _ds_serv_cache_key
= 0;
76 static xpc_pipe_t __od_pipe
; /* use accessor only */
77 static pthread_mutex_t mutex
= PTHREAD_MUTEX_INITIALIZER
;
84 // re-enable opendirectory interaction since we forked
85 _si_opendirectory_disabled
= 0;
87 if (__od_pipe
!= NULL
) {
88 xpc_pipe_invalidate(__od_pipe
);
89 /* disable release due to 10649340, it will cause a minor leak for each fork without exec */
90 // xpc_release(__od_pipe);
93 _ds_port
= MACH_PORT_NULL
;
94 pthread_mutex_unlock(&mutex
);
98 _od_fork_prepare(void)
100 pthread_mutex_lock(&mutex
);
104 _od_fork_parent(void)
106 pthread_mutex_unlock(&mutex
);
110 _ds_serv_cache_free(void *x
)
112 if (x
!= NULL
) si_item_release(x
);
116 _si_disable_opendirectory(void)
118 _si_opendirectory_disabled
= 1;
119 _ds_port
= MACH_PORT_NULL
;
124 _od_xpc_pipe(bool resetPipe
)
126 static dispatch_once_t once
;
127 xpc_pipe_t result
= NULL
;
129 dispatch_once(&once
, ^(void) {
132 /* if this is a build environment we ignore opendirectoryd */
133 xbs_disable
= getenv("XBS_DISABLE_LIBINFO");
134 if ((issetugid() == 0) && (xbs_disable
!= NULL
) && (strcmp(xbs_disable
, "YES") == 0)) {
135 _si_opendirectory_disabled
= 1;
139 pthread_atfork(_od_fork_prepare
, _od_fork_parent
, _od_fork_child
);
142 if (_si_opendirectory_disabled
== 1) {
146 pthread_mutex_lock(&mutex
);
148 xpc_release(__od_pipe
);
152 if (__od_pipe
== NULL
) {
153 if (!issetugid() && getenv("OD_DEBUG_MODE") != NULL
) {
154 __od_pipe
= xpc_pipe_create(kODMachLibinfoPortNameDebug
, 0);
156 __od_pipe
= xpc_pipe_create(kODMachLibinfoPortName
, XPC_PIPE_FLAG_PRIVILEGED
);
160 if (__od_pipe
!= NULL
) result
= xpc_retain(__od_pipe
);
161 pthread_mutex_unlock(&mutex
);
171 pipe
= _od_xpc_pipe(false);
176 if (_si_opendirectory_disabled
) {
180 return (pipe
!= NULL
);
186 _ds_port
= MACH_PORT_NULL
;
192 kern_return_t status
;
193 char *od_debug_mode
= NULL
;
195 if (_ds_port
!= MACH_PORT_NULL
) return 1;
197 if (_si_opendirectory_disabled
) return 0;
198 pthread_atfork(NULL
, NULL
, _ds_child
);
201 od_debug_mode
= getenv("OD_DEBUG_MODE");
205 status
= bootstrap_look_up(bootstrap_port
, kDSStdMachDSLookupPortName
"_debug", &_ds_port
);
207 status
= bootstrap_look_up2(bootstrap_port
, kDSStdMachDSLookupPortName
, &_ds_port
, 0, BOOTSTRAP_PRIVILEGED_SERVER
);
209 if ((status
!= BOOTSTRAP_SUCCESS
) && (status
!= BOOTSTRAP_UNKNOWN_SERVICE
)) _ds_port
= MACH_PORT_NULL
;
211 return (_ds_port
!= MACH_PORT_NULL
);
215 _valid_token(xpc_object_t reply
)
220 * This should really call audit_token_to_au32,
221 * but that's in libbsm, not in a Libsystem library.
223 xpc_dictionary_get_audit_token(reply
, &token
);
225 return ((uid_t
) token
.val
[1] == 0);
229 _ds_get_validation(si_mod_t
*si
, uint64_t *a
, uint64_t *b
, int cat
)
235 if (si
== NULL
) return;
237 pp
= (ds_si_private_t
*)si
->private;
238 if (pp
== NULL
) return;
243 status
= notify_peek(pp
->notify_token_global
, &peek
);
244 if (status
== NOTIFY_STATUS_OK
) *a
= ntohl(peek
);
251 status
= NOTIFY_STATUS_FAILED
;
253 if (cat
== CATEGORY_USER
) status
= notify_peek(pp
->notify_token_user
, &peek
);
254 else if (cat
== CATEGORY_GROUP
) status
= notify_peek(pp
->notify_token_group
, &peek
);
255 else if (cat
== CATEGORY_GROUPLIST
) status
= notify_peek(pp
->notify_token_group
, &peek
);
256 else if (cat
== CATEGORY_SERVICE
) status
= notify_peek(pp
->notify_token_service
, &peek
);
258 if (status
== NOTIFY_STATUS_OK
) *b
= ntohl(peek
);
263 __private_extern__ xpc_object_t
264 _od_rpc_call(const char *procname
, xpc_object_t payload
, xpc_pipe_t (*get_pipe
)(bool))
266 xpc_object_t result
= NULL
;
271 od_pipe
= get_pipe(false);
272 if (od_pipe
== NULL
) return NULL
;
274 if (payload
== NULL
) {
275 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
278 // we nest it for backward compatibility so we can do independent submissions
279 xpc_dictionary_set_string(payload
, OD_RPC_NAME
, procname
);
280 xpc_dictionary_set_int64(payload
, OD_RPC_VERSION
, 2);
282 for (retries
= 0; od_pipe
!= NULL
&& retries
< 2; retries
++) {
283 rc
= xpc_pipe_routine(od_pipe
, payload
, &reply
);
286 xpc_release(od_pipe
);
287 od_pipe
= get_pipe(true);
291 /* just loop and try to send again */
295 if (_valid_token(reply
) == true) {
298 /* fall through since we got a valid response */
301 /* release and NULL the pipe it'll break the loop */
302 xpc_release(od_pipe
);
308 if (od_pipe
!= NULL
) {
309 xpc_release(od_pipe
);
316 _ds_list(si_mod_t
*si
, int cat
, const char *procname
, const void *extra
, od_extract_t extract
)
318 __block si_list_t
*list
;
320 xpc_object_t reply
, result
;
322 if (procname
== NULL
) return NULL
;
324 _ds_get_validation(si
, &va
, &vb
, cat
);
327 reply
= _od_rpc_call(procname
, NULL
, _od_xpc_pipe
);
329 result
= xpc_dictionary_get_value(reply
, OD_RPC_RESULT
);
330 if (result
!= NULL
&& xpc_get_type(result
) == XPC_TYPE_ARRAY
) {
331 xpc_array_apply(result
, ^bool(size_t index
, xpc_object_t value
) {
332 si_item_t
*item
= extract(si
, value
, extra
, va
, vb
);
333 list
= si_list_add(list
, item
);
334 si_item_release(item
);
347 _ds_item(si_mod_t
*si
, int cat
, const char *procname
, const void *extra
, od_extract_t extract
, xpc_object_t payload
)
351 si_item_t
*item
= NULL
;
353 if (procname
== NULL
) return NULL
;
355 result
= _od_rpc_call(procname
, payload
, _od_xpc_pipe
);
356 if (result
!= NULL
) {
357 _ds_get_validation(si
, &va
, &vb
, cat
);
358 if (xpc_dictionary_get_int64(result
, OD_RPC_ERROR
) == 0) {
359 item
= extract(si
, result
, extra
, va
, vb
);
369 _ds_is_valid(si_mod_t
*si
, si_item_t
*item
)
374 uint32_t oldval
, newval
;
376 if (si
== NULL
) return 0;
377 if (item
== NULL
) return 0;
378 if (si
->name
== NULL
) return 0;
379 if (item
->src
== NULL
) return 0;
381 pp
= (ds_si_private_t
*)si
->private;
382 if (pp
== NULL
) return 0;
384 src
= (si_mod_t
*)item
->src
;
386 if (src
->name
== NULL
) return 0;
387 if (string_not_equal(si
->name
, src
->name
)) return 0;
389 /* check global invalidation */
390 oldval
= item
->validation_a
;
392 status
= notify_peek(pp
->notify_token_global
, &newval
);
393 if (status
!= NOTIFY_STATUS_OK
) return 0;
395 newval
= ntohl(newval
);
396 if (oldval
!= newval
) return 0;
398 oldval
= item
->validation_b
;
400 if (item
->type
== CATEGORY_USER
) status
= notify_peek(pp
->notify_token_user
, &newval
);
401 else if (item
->type
== CATEGORY_GROUP
) status
= notify_peek(pp
->notify_token_group
, &newval
);
402 else if (item
->type
== CATEGORY_SERVICE
) status
= notify_peek(pp
->notify_token_service
, &newval
);
405 if (status
!= NOTIFY_STATUS_OK
) return 0;
407 newval
= ntohl(newval
);
408 if (oldval
!= newval
) return 0;
414 _free_addr_list(char **l
)
418 if (l
== NULL
) return;
419 for (i
= 0; l
[i
] != NULL
; i
++) free(l
[i
]);
423 /* map ipv4 addresses and append to v6 list */
425 _map_v4(char ***v6
, uint32_t n6
, char **v4
, uint32_t n4
)
430 a6
.__u6_addr
.__u6_addr32
[0] = 0x00000000;
431 a6
.__u6_addr
.__u6_addr32
[1] = 0x00000000;
432 a6
.__u6_addr
.__u6_addr32
[2] = htonl(0x0000ffff);
436 *v6
= (char **)calloc(n4
+ 1, sizeof(char *));
440 *v6
= (char **)reallocf(*v6
, (n6
+ n4
+ 1) * sizeof(char *));
443 if (*v6
== NULL
) return -1;
445 for (i
= 0; i
< n4
; i
++)
447 (*v6
)[n6
] = (char *)calloc(1, IPV6_ADDR_LEN
);
448 if ((*v6
)[n6
] == NULL
) return -1;
450 memcpy(&(a6
.__u6_addr
.__u6_addr32
[3]), v4
[i
], IPV4_ADDR_LEN
);
451 memcpy((*v6
)[n6
], &(a6
.__u6_addr
.__u6_addr32
[0]), IPV6_ADDR_LEN
);
460 _xpc_query_key_string(const char *key
, const char *value
)
462 xpc_object_t payload
;
464 if (value
== NULL
) return NULL
;
466 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
467 if (payload
== NULL
) return NULL
;
469 xpc_dictionary_set_string(payload
, key
, value
);
475 _xpc_query_key_id(const char *key
, id_t idValue
)
477 xpc_object_t payload
;
479 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
480 if (payload
== NULL
) return NULL
;
482 xpc_dictionary_set_int64(payload
, key
, idValue
);
488 _xpc_query_key_uuid(const char *key
, uuid_t uu
)
490 xpc_object_t payload
;
492 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
493 if (payload
== NULL
) return NULL
;
495 xpc_dictionary_set_uuid(payload
, key
, uu
);
501 _xpc_query_key_int(const char *key
, int64_t intValue
)
503 xpc_object_t payload
;
505 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
506 if (payload
== NULL
) return NULL
;
508 xpc_dictionary_set_int64(payload
, key
, intValue
);
516 _extract_string_from_xpc_array_index(xpc_object_t reply
, int index
, const char **str
)
520 if (xpc_array_get_count(reply
) < index
) return -1;
522 value
= xpc_array_get_value(reply
, index
);
523 if (xpc_get_type(value
) != XPC_TYPE_STRING
) return -1;
525 *str
= xpc_string_get_string_ptr(value
);
530 _extract_string_from_xpc_object(xpc_object_t value
, const char **str
)
532 if (value
== NULL
) return -1;
533 else if (xpc_get_type(value
) == XPC_TYPE_STRING
)
535 *str
= xpc_string_get_string_ptr(value
);
538 else if (xpc_get_type(value
) == XPC_TYPE_ARRAY
)
540 return _extract_string_from_xpc_array_index(value
, 0, str
);
547 _extract_uint32_from_xpc_object(xpc_object_t value
, uint32_t *val32
)
551 if (value
== NULL
) return -1;
552 type
= xpc_get_type(value
);
554 if (type
== XPC_TYPE_STRING
)
556 *val32
= atoi(xpc_string_get_string_ptr(value
));
559 else if (type
== XPC_TYPE_INT64
)
561 *val32
= (uint32_t)xpc_int64_get_value(value
);
564 else if (type
== XPC_TYPE_BOOL
)
566 *val32
= (uint32_t)xpc_bool_get_value(value
);
569 else if (type
== XPC_TYPE_ARRAY
)
571 if (xpc_array_get_count(value
) == 0) return -1;
572 return _extract_uint32_from_xpc_object(xpc_array_get_value(value
, 0), val32
);
579 _extract_string_list_from_xpc_array_index(xpc_object_t reply
, int index
, unsigned int *len
, char ***list
)
582 xpc_object_t xpc_array
= xpc_array_get_value(reply
, index
);
584 if ((xpc_array
== NULL
) || (xpc_get_type(xpc_array
) != XPC_TYPE_ARRAY
)) return -1;
586 result
= calloc(xpc_array_get_count(xpc_array
) + 1, sizeof(*result
));
587 if (result
== NULL
) return -1;
589 /* include trailing NULL */
590 if (len
!= NULL
) (*len
) = xpc_array_get_count(xpc_array
) + 1;
592 xpc_array_apply(xpc_array
, ^bool(size_t idx
, xpc_object_t value
) {
593 result
[idx
] = (char *)xpc_string_get_string_ptr(value
);
602 _extract_uint32_from_xpc_array_index(xpc_object_t reply
, int index
, uint32_t *val32
)
604 xpc_object_t value
= xpc_array_get_value(reply
, index
);
605 return _extract_uint32_from_xpc_object(value
, val32
);
609 _extract_string_list_from_xpc_array(xpc_object_t xpc_array
, unsigned int *len
, char ***list
)
613 if ((xpc_array
== NULL
) || (xpc_get_type(xpc_array
) != XPC_TYPE_ARRAY
)) return -1;
615 result
= calloc(xpc_array_get_count(xpc_array
) + 1, sizeof(*result
));
616 if (result
== NULL
) return -1;
618 /* include trailing NULL */
619 if (len
!= NULL
) (*len
) = xpc_array_get_count(xpc_array
) + 1;
621 xpc_array_apply(xpc_array
, ^bool(size_t idx
, xpc_object_t value
) {
622 result
[idx
] = (char *)xpc_string_get_string_ptr(value
);
631 _extract_string_from_xpc_dict(xpc_object_t reply
, const char *key
, const char **str
)
633 xpc_object_t value
= xpc_dictionary_get_value(reply
, key
);
636 if (value
== NULL
) return -1;
638 if (xpc_get_type(value
) != XPC_TYPE_STRING
) return -1;
640 result
= xpc_string_get_string_ptr(value
);
641 if (result
== NULL
) return -1;
648 _extract_uint32_from_xpc_dict(xpc_object_t reply
, const char *key
, uint32_t *val32
)
650 xpc_object_t value
= xpc_dictionary_get_value(reply
, key
);
651 return _extract_uint32_from_xpc_object(value
, val32
);
669 _extract_user_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
674 if (xpc_array_get_count(reply
) < 7) return NULL
;
676 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.pw_name
)) return NULL
;
677 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.pw_passwd
)) return NULL
;
678 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.pw_uid
)) return NULL
;
679 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.pw_gid
)) return NULL
;
680 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.pw_gecos
)) return NULL
;
681 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.pw_dir
)) return NULL
;
682 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.pw_shell
)) return NULL
;
685 tmp
.pw_change
= (time_t)0;
686 tmp
.pw_expire
= (time_t)0;
687 tmp
.pw_class
= (char *)"";
689 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
);
693 _extract_user_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
695 __block
struct passwd tmp
;
696 __block
int status
= 0;
697 __block
int parts
= 3;
699 tmp
.pw_name
= (char *)"";
700 tmp
.pw_passwd
= (char *)"*";
701 tmp
.pw_uid
= (uid_t
)0;
702 tmp
.pw_gid
= (gid_t
)0;
703 tmp
.pw_change
= (time_t)0;
704 tmp
.pw_expire
= (time_t)0;
705 tmp
.pw_class
= (char *)"";
706 tmp
.pw_gecos
= (char *)"";
707 tmp
.pw_dir
= (char *)"/var/empty";
708 tmp
.pw_shell
= (char *)"/usr/bin/false";
710 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
711 if (key
== NULL
) return true;
712 else if (!strcmp(key
, "pw_name"))
714 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_name
);
715 if (status
== 0) parts
--;
717 else if (!strcmp(key
, "pw_passwd"))
719 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_passwd
);
720 /* no parts check - this value is optional */
722 else if (!strcmp(key
, "pw_uid"))
724 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.pw_uid
);
725 if (status
== 0) parts
--;
727 else if (!strcmp(key
, "pw_gid"))
729 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.pw_gid
);
730 if (status
== 0) parts
--;
732 else if (!strcmp(key
, "pw_change"))
734 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.pw_change
);
735 /* no parts check - this value is optional */
737 else if (!strcmp(key
, "pw_expire"))
739 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.pw_expire
);
740 /* no parts check - this value is optional */
742 else if (!strcmp(key
, "pw_class"))
744 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_class
);
745 /* no parts check - this value is optional */
747 else if (!strcmp(key
, "pw_gecos"))
749 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_gecos
);
750 /* no parts check - this value is optional */
752 else if (!strcmp(key
, "pw_dir"))
754 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_dir
);
755 /* no parts check - this value is optional */
757 else if (!strcmp(key
, "pw_shell"))
759 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.pw_shell
);
760 /* no parts check - this value is optional */
765 if ((status
!= 0) || (parts
!= 0)) return NULL
;
767 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
);
771 _extract_user(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
775 if (si
== NULL
) return NULL
;
776 if (reply
== NULL
) return NULL
;
778 type
= xpc_get_type(reply
);
780 if (type
== XPC_TYPE_ARRAY
) return _extract_user_array(si
, reply
, valid_global
, valid_cat
);
781 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_user_dict(si
, reply
, valid_global
, valid_cat
);
791 * optional members : array of string
796 _extract_group_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
801 int arraycount
= xpc_array_get_count(reply
);
803 if ((arraycount
< 2) || (arraycount
> 3)) return NULL
;
805 memset(&tmp
, 0, sizeof(tmp
));
807 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.gr_name
)) return NULL
;
808 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.gr_gid
)) return NULL
;
812 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.gr_mem
)) return NULL
;
816 tmp
.gr_passwd
= (char *)"*";
818 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
);
826 _extract_group_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
829 __block
struct group tmp
;
830 __block
int status
= 0;
831 __block
int parts
= 2;
833 tmp
.gr_name
= (char *)"";
834 tmp
.gr_passwd
= (char *)"*";
835 tmp
.gr_gid
= (gid_t
)0;
838 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
839 if (key
== NULL
) return true;
840 else if (!strcmp(key
, "gr_name"))
842 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.gr_name
);
843 if (status
== 0) parts
--;
845 else if (!strcmp(key
, "gr_passwd"))
847 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.gr_passwd
);
848 /* no parts check - this value is optional */
850 else if (!strcmp(key
, "gr_gid"))
852 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.gr_gid
);
853 if (status
== 0) parts
--;
855 else if (!strcmp(key
, "gr_mem"))
857 status
|= _extract_string_list_from_xpc_array(value
, NULL
, (char ***)&tmp
.gr_mem
);
858 /* no parts check - this value is optional */
863 if ((status
!= 0) || (parts
!= 0))
869 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
);
877 _extract_group(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
881 if (si
== NULL
) return NULL
;
882 if (reply
== NULL
) return NULL
;
884 type
= xpc_get_type(reply
);
885 if (type
== XPC_TYPE_ARRAY
) return _extract_group_array(si
, reply
, valid_global
, valid_cat
);
886 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_group_dict(si
, reply
, valid_global
, valid_cat
);
900 _extract_netgroup_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
902 const char *host
, *user
, *domain
;
905 if (xpc_array_get_count(reply
) != 3) return NULL
;
907 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&host
)) return NULL
;
908 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&user
)) return NULL
;
909 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&domain
)) return NULL
;
911 return (si_item_t
*)LI_ils_create("L4488sss", (unsigned long)si
, CATEGORY_NETGROUP
, 1, valid_global
, valid_cat
, host
, user
, domain
);
915 _extract_netgroup_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
917 __block
const char *host
= "";
918 __block
const char *user
= "";
919 __block
const char *domain
= "";
920 __block
int status
= 0;
921 __block
int parts
= 3;
923 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
924 if (key
== NULL
) return true;
925 else if (!strcmp(key
, "host"))
927 status
|= _extract_string_from_xpc_object(value
, (const char **)&host
);
928 if (status
== 0) parts
--;
930 else if (!strcmp(key
, "user"))
932 status
|= _extract_string_from_xpc_object(value
, (const char **)&user
);
933 if (status
== 0) parts
--;
935 else if (!strcmp(key
, "domain"))
937 status
|= _extract_string_from_xpc_object(value
, (const char **)&domain
);
938 if (status
== 0) parts
--;
943 if ((status
!= 0) || (parts
!= 0)) return NULL
;
945 return (si_item_t
*)LI_ils_create("L4488sss", (unsigned long)si
, CATEGORY_NETGROUP
, 1, valid_global
, valid_cat
, host
, user
, domain
);
949 _extract_netgroup(si_mod_t
*si
, xpc_object_t reply
, const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
953 if (si
== NULL
) return NULL
;
954 if (reply
== NULL
) return NULL
;
956 type
= xpc_get_type(reply
);
957 if (type
== XPC_TYPE_ARRAY
) return _extract_netgroup_array(si
, reply
, valid_global
, valid_cat
);
958 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_netgroup_dict(si
, reply
, valid_global
, valid_cat
);
968 * optional members : array of string
973 _extract_alias_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
978 int arraycount
= xpc_array_get_count(reply
);
980 if ((arraycount
< 2) || (arraycount
> 3)) return NULL
;
982 memset(&tmp
, 0, sizeof(tmp
));
984 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.alias_name
)) return NULL
;
985 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.alias_local
)) return NULL
;
989 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.alias_members
)) return NULL
;
992 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
);
994 free(tmp
.alias_members
);
1000 _extract_alias_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1003 __block
struct aliasent tmp
;
1004 __block
int status
= 0;
1005 __block
int parts
= 2;
1007 tmp
.alias_name
= (char *)"";
1008 tmp
.alias_local
= 0;
1009 tmp
.alias_members
= NULL
;
1010 tmp
.alias_members_len
= 0;
1012 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1013 if (key
== NULL
) return true;
1014 else if (!strcmp(key
, "alias_name"))
1016 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.alias_name
);
1017 if (status
== 0) parts
--;
1019 else if (!strcmp(key
, "alias_local"))
1021 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.alias_local
);
1022 if (status
== 0) parts
--;
1024 else if (!strcmp(key
, "alias_members"))
1026 status
|= _extract_string_list_from_xpc_array(value
, &tmp
.alias_members_len
, (char ***)&tmp
.alias_members
);
1027 /* no parts check - this value is optional */
1032 if ((status
!= 0) || (parts
!= 0))
1034 free(tmp
.alias_members
);
1038 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
);
1040 free(tmp
.alias_members
);
1046 _extract_alias(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1050 if (si
== NULL
) return NULL
;
1051 if (reply
== NULL
) return NULL
;
1053 type
= xpc_get_type(reply
);
1054 if (type
== XPC_TYPE_ARRAY
) return _extract_alias_array(si
, reply
, valid_global
, valid_cat
);
1055 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_alias_dict(si
, reply
, valid_global
, valid_cat
);
1065 * optional aliases : array of string
1070 _extract_network_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1075 int arraycount
= xpc_array_get_count(reply
);
1077 if ((arraycount
< 2) || (arraycount
> 3)) return NULL
;
1079 memset(&tmp
, 0, sizeof(tmp
));
1081 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.n_name
)) return NULL
;
1082 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.n_net
)) return NULL
;
1084 if (arraycount
== 3)
1086 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.n_aliases
)) return NULL
;
1090 tmp
.n_addrtype
= AF_INET
;
1092 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
);
1094 free(tmp
.n_aliases
);
1100 _extract_network_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1103 __block
struct netent tmp
;
1104 __block
int status
= 0;
1105 __block
int parts
= 2;
1107 if (si
== NULL
) return NULL
;
1108 if (reply
== NULL
) return NULL
;
1110 tmp
.n_name
= (char *)"";
1111 tmp
.n_aliases
= NULL
;
1115 tmp
.n_addrtype
= AF_INET
;
1117 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1118 if (key
== NULL
) return true;
1119 else if (!strcmp(key
, "n_name"))
1121 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.n_name
);
1122 if (status
== 0) parts
--;
1124 else if (!strcmp(key
, "n_aliases"))
1126 status
|= _extract_string_list_from_xpc_array(value
, NULL
, (char ***)&tmp
.n_aliases
);
1127 /* no parts check - this value is optional */
1129 else if (!strcmp(key
, "n_net"))
1131 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.n_net
);
1132 if (status
== 0) parts
--;
1137 if ((status
!= 0) || (parts
!= 0))
1139 free(tmp
.n_aliases
);
1143 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
);
1145 free(tmp
.n_aliases
);
1151 _extract_network(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1155 if (si
== NULL
) return NULL
;
1156 if (reply
== NULL
) return NULL
;
1158 type
= xpc_get_type(reply
);
1159 if (type
== XPC_TYPE_ARRAY
) return _extract_network_array(si
, reply
, valid_global
, valid_cat
);
1160 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_network_dict(si
, reply
, valid_global
, valid_cat
);
1171 * optional aliases : array of string
1176 _extract_service_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1181 int arraycount
= xpc_array_get_count(reply
);
1183 if ((arraycount
< 3) || (arraycount
> 4)) return NULL
;
1185 memset(&tmp
, 0, sizeof(tmp
));
1187 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.s_name
)) return NULL
;
1188 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.s_port
)) return NULL
;
1189 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.s_proto
)) return NULL
;
1191 if (arraycount
== 4)
1193 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.s_aliases
)) return NULL
;
1196 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
);
1198 free(tmp
.s_aliases
);
1204 _extract_service_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1207 __block
struct servent tmp
;
1208 __block
int status
= 0;
1209 __block
int parts
= 3;
1211 if (si
== NULL
) return NULL
;
1212 if (reply
== NULL
) return NULL
;
1214 tmp
.s_name
= (char *)"";
1215 tmp
.s_aliases
= NULL
;
1217 tmp
.s_proto
= (char *)"";
1219 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1220 if (key
== NULL
) return true;
1221 else if (!strcmp(key
, "s_name"))
1223 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.s_name
);
1224 if (status
== 0) parts
--;
1226 else if (!strcmp(key
, "s_aliases"))
1228 status
|= _extract_string_list_from_xpc_array(value
, NULL
, (char ***)&tmp
.s_aliases
);
1229 /* no parts check - this value is optional */
1231 else if (!strcmp(key
, "s_port"))
1234 status
|= _extract_uint32_from_xpc_object(value
, &v32
);
1237 tmp
.s_port
= (unsigned int)htons(v32
); // ugh
1241 else if (!strcmp(key
, "s_proto"))
1243 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.s_proto
);
1244 if (status
== 0) parts
--;
1249 if ((status
!= 0) || (parts
!= 0))
1251 free(tmp
.s_aliases
);
1255 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
);
1257 free(tmp
.s_aliases
);
1263 _extract_service(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1267 if (si
== NULL
) return NULL
;
1268 if (reply
== NULL
) return NULL
;
1270 type
= xpc_get_type(reply
);
1271 if (type
== XPC_TYPE_ARRAY
) return _extract_service_array(si
, reply
, valid_global
, valid_cat
);
1272 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_service_dict(si
, reply
, valid_global
, valid_cat
);
1282 * optional aliases : array of string
1286 _extract_protocol_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1289 struct protoent tmp
;
1291 int arraycount
= xpc_array_get_count(reply
);
1293 if ((arraycount
< 2) || (arraycount
> 3)) return NULL
;
1295 memset(&tmp
, 0, sizeof(tmp
));
1297 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.p_name
)) return NULL
;
1298 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.p_proto
)) return NULL
;
1300 if (arraycount
== 3)
1302 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.p_aliases
)) return NULL
;
1305 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
);
1307 free(tmp
.p_aliases
);
1313 _extract_protocol_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1316 __block
struct protoent tmp
;
1317 __block
int status
= 0;
1318 __block
int parts
= 2;
1320 tmp
.p_name
= (char *)"";
1322 tmp
.p_aliases
= NULL
;
1324 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1325 if (key
== NULL
) return true;
1326 else if (!strcmp(key
, "p_name"))
1328 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.p_name
);
1329 if (status
== 0) parts
--;
1331 else if (!strcmp(key
, "p_proto"))
1333 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.p_proto
);
1334 if (status
== 0) parts
--;
1336 else if (!strcmp(key
, "p_aliases"))
1338 status
|= _extract_string_list_from_xpc_array(value
, NULL
, (char ***)&tmp
.p_aliases
);
1339 /* no parts check - this value is optional */
1344 if ((status
!= 0) || (parts
!= 0))
1346 free(tmp
.p_aliases
);
1350 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
);
1352 free(tmp
.p_aliases
);
1358 _extract_protocol(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1362 if (si
== NULL
) return NULL
;
1363 if (reply
== NULL
) return NULL
;
1365 type
= xpc_get_type(reply
);
1366 if (type
== XPC_TYPE_ARRAY
) return _extract_protocol_array(si
, reply
, valid_global
, valid_cat
);
1367 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_protocol_dict(si
, reply
, valid_global
, valid_cat
);
1377 * optional aliases : array of string
1382 _extract_rpc_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1387 int arraycount
= xpc_array_get_count(reply
);
1389 if ((arraycount
< 2) || (arraycount
> 3)) return NULL
;
1391 memset(&tmp
, 0, sizeof(tmp
));
1393 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.r_name
)) return NULL
;
1394 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.r_number
)) return NULL
;
1396 if (arraycount
== 3)
1398 if (0 != _extract_string_list_from_xpc_array_index(reply
, i
++, NULL
, (char ***)&tmp
.r_aliases
)) return NULL
;
1401 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
);
1403 free(tmp
.r_aliases
);
1409 _extract_rpc_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1412 __block
struct rpcent tmp
;
1413 __block
int status
= 0;
1414 __block
int parts
= 2;
1416 tmp
.r_name
= (char *)"";
1418 tmp
.r_aliases
= NULL
;
1420 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1421 if (key
== NULL
) return true;
1422 else if (!strcmp(key
, "r_name"))
1424 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.r_name
);
1425 if (status
== 0) parts
--;
1427 else if (!strcmp(key
, "r_number"))
1429 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.r_number
);
1430 if (status
== 0) parts
--;
1432 else if (!strcmp(key
, "r_aliases"))
1434 status
|= _extract_string_list_from_xpc_array(value
, NULL
, (char ***)&tmp
.r_aliases
);
1435 /* no parts check - this value is optional */
1440 if ((status
!= 0) || (parts
!= 0))
1442 free(tmp
.r_aliases
);
1446 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
);
1448 free(tmp
.r_aliases
);
1454 _extract_rpc(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1458 if (si
== NULL
) return NULL
;
1459 if (reply
== NULL
) return NULL
;
1461 type
= xpc_get_type(reply
);
1462 if (type
== XPC_TYPE_ARRAY
) return _extract_rpc_array(si
, reply
, valid_global
, valid_cat
);
1463 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_rpc_dict(si
, reply
, valid_global
, valid_cat
);
1481 _extract_fstab_array(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1483 __block
struct fstab tmp
;
1486 if (xpc_array_get_count(reply
) != 7) return NULL
;
1488 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.fs_file
)) return NULL
;
1489 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.fs_spec
)) return NULL
;
1490 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.fs_freq
)) return NULL
;
1491 if (0 != _extract_uint32_from_xpc_array_index(reply
, i
++, (uint32_t *)&tmp
.fs_passno
)) return NULL
;
1492 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.fs_mntops
)) return NULL
;
1493 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.fs_type
)) return NULL
;
1494 if (0 != _extract_string_from_xpc_array_index(reply
, i
++, (const char **)&tmp
.fs_vfstype
)) return NULL
;
1496 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
);
1500 _extract_fstab_dict(si_mod_t
*si
, xpc_object_t reply
, uint64_t valid_global
, uint64_t valid_cat
)
1502 __block
struct fstab tmp
;
1503 __block
int status
= 0;
1504 __block
int parts
= 7;
1507 tmp
.fs_spec
= (char *)"";
1510 tmp
.fs_mntops
= (char *)"";
1511 tmp
.fs_type
= (char *)"";
1512 tmp
.fs_vfstype
= (char *)"";
1514 xpc_dictionary_apply(reply
, ^bool(const char *key
, xpc_object_t value
) {
1515 if (key
== NULL
) return true;
1516 else if (!strcmp(key
, "fs_file"))
1518 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.fs_file
);
1519 if (status
== 0) parts
--;
1521 else if (!strcmp(key
, "fs_spec"))
1523 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.fs_spec
);
1524 if (status
== 0) parts
--;
1526 else if (!strcmp(key
, "fs_freq"))
1528 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.fs_freq
);
1529 if (status
== 0) parts
--;
1531 else if (!strcmp(key
, "fs_passno"))
1533 status
|= _extract_uint32_from_xpc_object(value
, (uint32_t *)&tmp
.fs_passno
);
1534 if (status
== 0) parts
--;
1536 else if (!strcmp(key
, "fs_mntops"))
1538 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.fs_mntops
);
1539 if (status
== 0) parts
--;
1541 else if (!strcmp(key
, "fs_type"))
1543 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.fs_type
);
1544 if (status
== 0) parts
--;
1546 else if (!strcmp(key
, "fs_vfstype"))
1548 status
|= _extract_string_from_xpc_object(value
, (const char **)&tmp
.fs_vfstype
);
1549 if (status
== 0) parts
--;
1554 if ((status
!= 0) || (parts
!= 0)) return NULL
;
1556 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
);
1560 _extract_fstab(si_mod_t
*si
, xpc_object_t reply
, __unused
const void *ignored
, uint64_t valid_global
, uint64_t valid_cat
)
1564 if (si
== NULL
) return NULL
;
1565 if (reply
== NULL
) return NULL
;
1567 type
= xpc_get_type(reply
);
1568 if (type
== XPC_TYPE_ARRAY
) return _extract_fstab_array(si
, reply
, valid_global
, valid_cat
);
1569 else if (type
== XPC_TYPE_DICTIONARY
) return _extract_fstab_dict(si
, reply
, valid_global
, valid_cat
);
1575 _extract_mac_mac(si_mod_t
*si
, xpc_object_t reply
, const void *extra
, uint64_t valid_global
, uint64_t valid_cat
)
1579 const char *value
= NULL
;
1582 if (si
== NULL
) return NULL
;
1583 if (reply
== NULL
) return NULL
;
1584 if (extra
== NULL
) return NULL
;
1586 type
= xpc_get_type(reply
);
1587 if (type
== XPC_TYPE_ARRAY
)
1589 if (xpc_array_get_count(reply
) >= 1)
1591 if (0 != _extract_string_from_xpc_array_index(reply
, 0, (const char **)&value
)) return NULL
;
1594 else if (type
== XPC_TYPE_DICTIONARY
)
1596 if (0 != _extract_string_from_xpc_dict(reply
, "mac", &value
)) return NULL
;
1599 if (value
== NULL
|| value
[0] == '\0') return NULL
;
1601 cmac
= si_standardize_mac_address(value
);
1602 if (cmac
== NULL
) return NULL
;
1604 out
= (si_item_t
*)LI_ils_create("L4488ss", (unsigned long)si
, CATEGORY_MAC
, 1, valid_global
, valid_cat
, extra
, cmac
);
1612 _extract_mac_name(si_mod_t
*si
, xpc_object_t reply
, const void *extra
, uint64_t valid_global
, uint64_t valid_cat
)
1615 const char *name
= NULL
;
1618 if (si
== NULL
) return NULL
;
1619 if (reply
== NULL
) return NULL
;
1620 if (extra
== NULL
) return NULL
;
1622 type
= xpc_get_type(reply
);
1623 if (type
== XPC_TYPE_ARRAY
)
1625 if (xpc_array_get_count(reply
) >= 1)
1627 if (0 != _extract_string_from_xpc_array_index(reply
, 0, (const char **)&name
)) return NULL
;
1630 else if (type
== XPC_TYPE_DICTIONARY
)
1632 if (0 != _extract_string_from_xpc_dict(reply
, "name", &name
)) return NULL
;
1635 if (name
== NULL
) return NULL
;
1637 out
= (si_item_t
*)LI_ils_create("L4488ss", (unsigned long)si
, CATEGORY_MAC
, 1, valid_global
, valid_cat
, name
, extra
);
1645 ds_user_byname(si_mod_t
*si
, const char *name
)
1647 xpc_object_t payload
;
1650 if (!_od_running()) return NULL
;
1652 payload
= _xpc_query_key_string("name", name
);
1653 if (payload
== NULL
) return NULL
;
1655 item
= _ds_item(si
, CATEGORY_USER
, "getpwnam", NULL
, _extract_user
, payload
);
1657 xpc_release(payload
);
1662 ds_user_byuid(si_mod_t
*si
, uid_t uid
)
1664 xpc_object_t payload
;
1667 if (!_od_running()) return NULL
;
1669 payload
= _xpc_query_key_id("uid", uid
);
1670 if (payload
== NULL
) return NULL
;
1672 item
= _ds_item(si
, CATEGORY_USER
, "getpwuid", NULL
, _extract_user
, payload
);
1674 xpc_release(payload
);
1679 ds_user_byuuid(si_mod_t
*si
, uuid_t uuid
)
1681 xpc_object_t payload
;
1684 if (!_od_running()) return NULL
;
1686 payload
= _xpc_query_key_uuid("uuid", uuid
);
1687 if (payload
== NULL
) return NULL
;
1689 item
= _ds_item(si
, CATEGORY_USER
, "getpwuuid", NULL
, _extract_user
, payload
);
1691 xpc_release(payload
);
1696 ds_user_all(si_mod_t
*si
)
1698 return _ds_list(si
, CATEGORY_USER
, "getpwent", NULL
, _extract_user
);
1702 ds_group_byname(si_mod_t
*si
, const char *name
)
1704 xpc_object_t payload
;
1707 if (!_od_running()) return NULL
;
1709 payload
= _xpc_query_key_string("name", name
);
1710 if (payload
== NULL
) return NULL
;
1712 item
= _ds_item(si
, CATEGORY_GROUP
, "getgrnam", NULL
, _extract_group
, payload
);
1714 xpc_release(payload
);
1719 ds_group_bygid(si_mod_t
*si
, gid_t gid
)
1721 xpc_object_t payload
;
1724 if (!_od_running()) return NULL
;
1726 payload
= _xpc_query_key_id("gid", gid
);
1727 if (payload
== NULL
) return NULL
;
1729 item
= _ds_item(si
, CATEGORY_GROUP
, "getgrgid", NULL
, _extract_group
, payload
);
1731 xpc_release(payload
);
1736 ds_group_byuuid(si_mod_t
*si
, uuid_t uuid
)
1738 xpc_object_t payload
;
1741 if (!_od_running()) return NULL
;
1743 payload
= _xpc_query_key_uuid("uuid", uuid
);
1744 if (payload
== NULL
) return NULL
;
1746 item
= _ds_item(si
, CATEGORY_GROUP
, "getgruuid", NULL
, _extract_group
, payload
);
1748 xpc_release(payload
);
1753 ds_group_all(si_mod_t
*si
)
1755 if (!_od_running()) return NULL
;
1756 return _ds_list(si
, CATEGORY_GROUP
, "getgrent", NULL
, _extract_group
);
1760 ds_grouplist(si_mod_t
*si
, const char *name
, uint32_t ngroups
)
1762 xpc_object_t payload
, reply
;
1763 si_item_t
*item
= NULL
;
1765 if (!_od_running()) return NULL
;
1766 if (name
== NULL
) return NULL
;
1768 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
1769 if (payload
== NULL
) return NULL
;
1771 xpc_dictionary_set_string(payload
, "name", name
);
1772 xpc_dictionary_set_int64(payload
, "ngroups", ngroups
);
1774 reply
= _od_rpc_call("getgrouplist", payload
, _od_xpc_pipe
);
1775 if (reply
!= NULL
) {
1777 const gid_t
*gidptr
= xpc_dictionary_get_data(reply
, "groups", &gidptrsz
);
1781 _ds_get_validation(si
, &va
, &vb
, CATEGORY_GROUPLIST
);
1783 /* see what we were sent */
1784 if (0 == _extract_uint32_from_xpc_dict(reply
, "count", &count
))
1788 item
= (si_item_t
*)LI_ils_create("L4488s4@", (unsigned long)si
, CATEGORY_GROUPLIST
, 1, va
, vb
, name
, count
,
1796 xpc_release(payload
);
1802 ds_netgroup_byname(si_mod_t
*si
, const char *name
)
1804 xpc_object_t payload
;
1805 si_list_t
*list
= NULL
;
1808 if (!_od_running()) return NULL
;
1810 payload
= _xpc_query_key_string("netgroup", name
);
1811 if (payload
== NULL
) return NULL
;
1813 item
= _ds_item(si
, CATEGORY_NETGROUP
, "getnetgrent", NULL
, _extract_netgroup
, payload
);
1815 list
= si_list_add(list
, item
);
1816 si_item_release(item
);
1819 xpc_release(payload
);
1825 ds_in_netgroup(si_mod_t
*si
, const char *group
, const char *host
, const char *user
, const char *domain
)
1827 xpc_object_t payload
, reply
;
1830 if (!_od_running()) return 0;
1832 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
1833 if (payload
== NULL
) return 0;
1835 xpc_dictionary_set_string(payload
, "netgroup", (group
? group
: ""));
1836 xpc_dictionary_set_string(payload
, "host", (host
? host
: ""));
1837 xpc_dictionary_set_string(payload
, "user", (user
? user
: ""));
1838 xpc_dictionary_set_string(payload
, "domain", (domain
? domain
: ""));
1840 reply
= _od_rpc_call("innetgr", payload
, _od_xpc_pipe
);
1841 if (reply
!= NULL
) {
1842 is_innetgr
= xpc_dictionary_get_bool(reply
, OD_RPC_RESULT
);
1848 xpc_release(payload
);
1854 ds_alias_byname(si_mod_t
*si
, const char *name
)
1856 xpc_object_t payload
;
1859 if (!_od_running()) return NULL
;
1861 payload
= _xpc_query_key_string("name", name
);
1862 if (payload
== NULL
) return NULL
;
1864 item
= _ds_item(si
, CATEGORY_ALIAS
, "alias_getbyname", NULL
, _extract_alias
, payload
);
1866 xpc_release(payload
);
1871 ds_alias_all(si_mod_t
*si
)
1873 if (!_od_running()) return NULL
;
1874 return _ds_list(si
, CATEGORY_ALIAS
, "alias_getent", NULL
, _extract_alias
);
1878 ds_network_byname(si_mod_t
*si
, const char *name
)
1880 xpc_object_t payload
;
1883 if (!_od_running()) return NULL
;
1885 payload
= _xpc_query_key_string("name", name
);
1886 if (payload
== NULL
) return NULL
;
1888 item
= _ds_item(si
, CATEGORY_NETWORK
, "getnetbyname", NULL
, _extract_network
, payload
);
1890 xpc_release(payload
);
1895 ds_network_byaddr(si_mod_t
*si
, uint32_t addr
)
1897 unsigned char f1
, f2
, f3
;
1899 xpc_object_t payload
;
1902 if (!_od_running()) return NULL
;
1910 if (f3
!= 0) snprintf(val
, sizeof(val
), "%u.%u.%u", f3
, f2
, f1
);
1911 else if (f2
!= 0) snprintf(val
, sizeof(val
), "%u.%u", f2
, f1
);
1912 else snprintf(val
, sizeof(val
), "%u", f1
);
1914 payload
= _xpc_query_key_string("net", val
);
1915 if (payload
== NULL
) return NULL
;
1917 item
= _ds_item(si
, CATEGORY_NETWORK
, "getnetbyaddr", NULL
, _extract_network
, payload
);
1919 xpc_release(payload
);
1924 ds_network_all(si_mod_t
*si
)
1926 if (!_od_running()) return NULL
;
1927 return _ds_list(si
, CATEGORY_NETWORK
, "getnetent", NULL
, _extract_network
);
1931 ds_service_byname(si_mod_t
*si
, const char *name
, const char *proto
)
1933 xpc_object_t payload
;
1937 if (!_od_running()) return NULL
;
1938 if (name
== NULL
) name
= "";
1939 if (proto
== NULL
) proto
= "";
1941 /* Check our local service cache (see ds_addrinfo). */
1942 item
= pthread_getspecific(_ds_serv_cache_key
);
1945 s
= (struct servent
*)((uintptr_t)item
+ sizeof(si_item_t
));
1946 if (string_equal(name
, s
->s_name
)) return si_item_retain(item
);
1949 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
1950 if (payload
== NULL
) return NULL
;
1952 xpc_dictionary_set_string(payload
, "name", name
);
1953 xpc_dictionary_set_string(payload
, "proto", proto
);
1955 item
= _ds_item(si
, CATEGORY_SERVICE
, "getservbyname", NULL
, _extract_service
, payload
);
1957 xpc_release(payload
);
1963 ds_service_byport(si_mod_t
*si
, int port
, const char *proto
)
1965 xpc_object_t payload
;
1968 if (!_od_running()) return NULL
;
1970 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
1971 if (payload
== NULL
) return NULL
;
1973 /* swap to native order, API passes network order */
1974 xpc_dictionary_set_int64(payload
, "port", ntohs(port
));
1975 xpc_dictionary_set_string(payload
, "proto", (proto
? proto
: ""));
1977 item
= _ds_item(si
, CATEGORY_SERVICE
, "getservbyport", NULL
, _extract_service
, payload
);
1979 xpc_release(payload
);
1985 ds_service_all(si_mod_t
*si
)
1987 if (!_od_running()) return NULL
;
1988 return _ds_list(si
, CATEGORY_SERVICE
, "getservent", NULL
, _extract_service
);
1992 ds_protocol_byname(si_mod_t
*si
, const char *name
)
1994 xpc_object_t payload
;
1997 if (!_od_running()) return NULL
;
1999 payload
= _xpc_query_key_string("name", name
);
2000 if (payload
== NULL
) return NULL
;
2002 item
= _ds_item(si
, CATEGORY_PROTOCOL
, "getprotobyname", NULL
, _extract_protocol
, payload
);
2004 xpc_release(payload
);
2009 ds_protocol_bynumber(si_mod_t
*si
, int number
)
2011 xpc_object_t payload
;
2014 if (!_od_running()) return NULL
;
2016 payload
= _xpc_query_key_int("number", number
);
2017 if (payload
== NULL
) return NULL
;
2019 item
= _ds_item(si
, CATEGORY_PROTOCOL
, "getprotobynumber", NULL
, _extract_protocol
, payload
);
2021 xpc_release(payload
);
2026 ds_protocol_all(si_mod_t
*si
)
2028 return _ds_list(si
, CATEGORY_PROTOCOL
, "getprotoent", NULL
, _extract_protocol
);
2032 ds_rpc_byname(si_mod_t
*si
, const char *name
)
2034 xpc_object_t payload
;
2037 if (!_od_running()) return NULL
;
2039 payload
= _xpc_query_key_string("name", name
);
2040 if (payload
== NULL
) return NULL
;
2042 item
= _ds_item(si
, CATEGORY_RPC
, "getrpcbyname", NULL
, _extract_rpc
, payload
);
2044 xpc_release(payload
);
2049 ds_rpc_bynumber(si_mod_t
*si
, int number
)
2051 xpc_object_t payload
;
2054 if (!_od_running()) return NULL
;
2056 payload
= _xpc_query_key_int("number", number
);
2057 if (payload
== NULL
) return NULL
;
2059 item
= _ds_item(si
, CATEGORY_RPC
, "getrpcbynumber", NULL
, _extract_rpc
, payload
);
2061 xpc_release(payload
);
2066 ds_rpc_all(si_mod_t
*si
)
2068 return _ds_list(si
, CATEGORY_RPC
, "getrpcent", NULL
, _extract_rpc
);
2072 ds_fs_byspec(si_mod_t
*si
, const char *name
)
2074 xpc_object_t payload
;
2077 if (!_od_running()) return NULL
;
2079 payload
= _xpc_query_key_string("name", name
);
2080 if (payload
== NULL
) return NULL
;
2082 item
= _ds_item(si
, CATEGORY_FS
, "getfsbyname", NULL
, _extract_fstab
, payload
);
2084 xpc_release(payload
);
2089 ds_fs_all(si_mod_t
*si
)
2091 return _ds_list(si
, CATEGORY_FS
, "getfsent", NULL
, _extract_fstab
);
2095 ds_fs_byfile(si_mod_t
*si
, const char *name
)
2102 if (!_od_running()) return NULL
;
2103 if (name
== NULL
) return NULL
;
2105 list
= ds_fs_all(si
);
2106 if (list
== NULL
) return NULL
;
2109 for (i
= 0; (i
< list
->count
) && (item
== NULL
); i
++)
2111 f
= (struct fstab
*)((uintptr_t)(list
->entry
[i
]) + sizeof(si_item_t
));
2112 if (string_equal(name
, f
->fs_file
)) item
= si_item_retain(list
->entry
[i
]);
2115 si_list_release(list
);
2120 ds_mac_byname(si_mod_t
*si
, const char *name
)
2122 xpc_object_t payload
;
2125 if (!_od_running()) return NULL
;
2127 payload
= _xpc_query_key_string("name", name
);
2128 if (payload
== NULL
) return NULL
;
2130 item
= _ds_item(si
, CATEGORY_MAC
, "getmacbyname", name
, _extract_mac_mac
, payload
);
2132 xpc_release(payload
);
2137 ds_mac_bymac(si_mod_t
*si
, const char *mac
)
2139 xpc_object_t payload
;
2143 if (!_od_running()) return NULL
;
2145 cmac
= si_standardize_mac_address(mac
);
2146 if (cmac
== NULL
) return NULL
;
2148 payload
= xpc_dictionary_create(NULL
, NULL
, 0);
2149 if (payload
== NULL
) return NULL
;
2151 payload
= _xpc_query_key_string("mac", cmac
);
2152 item
= _ds_item(si
, CATEGORY_MAC
, "gethostbymac", cmac
, _extract_mac_name
, payload
);
2155 xpc_release(payload
);
2163 si_module_static_ds(void)
2165 static const struct si_mod_vtable_s ds_vtable
=
2167 .sim_is_valid
= &_ds_is_valid
,
2169 .sim_user_byname
= &ds_user_byname
,
2170 .sim_user_byuid
= &ds_user_byuid
,
2171 .sim_user_byuuid
= &ds_user_byuuid
,
2172 .sim_user_all
= &ds_user_all
,
2174 .sim_group_byname
= &ds_group_byname
,
2175 .sim_group_bygid
= &ds_group_bygid
,
2176 .sim_group_byuuid
= &ds_group_byuuid
,
2177 .sim_group_all
= &ds_group_all
,
2179 .sim_grouplist
= &ds_grouplist
,
2181 .sim_netgroup_byname
= &ds_netgroup_byname
,
2182 .sim_in_netgroup
= &ds_in_netgroup
,
2184 .sim_alias_byname
= &ds_alias_byname
,
2185 .sim_alias_all
= &ds_alias_all
,
2187 /* host lookups not supported */
2188 .sim_host_byname
= NULL
,
2189 .sim_host_byaddr
= NULL
,
2190 .sim_host_all
= NULL
,
2192 .sim_network_byname
= &ds_network_byname
,
2193 .sim_network_byaddr
= &ds_network_byaddr
,
2194 .sim_network_all
= &ds_network_all
,
2196 .sim_service_byname
= &ds_service_byname
,
2197 .sim_service_byport
= &ds_service_byport
,
2198 .sim_service_all
= &ds_service_all
,
2200 .sim_protocol_byname
= &ds_protocol_byname
,
2201 .sim_protocol_bynumber
= &ds_protocol_bynumber
,
2202 .sim_protocol_all
= &ds_protocol_all
,
2204 .sim_rpc_byname
= &ds_rpc_byname
,
2205 .sim_rpc_bynumber
= &ds_rpc_bynumber
,
2206 .sim_rpc_all
= &ds_rpc_all
,
2208 .sim_fs_byspec
= &ds_fs_byspec
,
2209 .sim_fs_byfile
= &ds_fs_byfile
,
2210 .sim_fs_all
= &ds_fs_all
,
2212 .sim_mac_byname
= &ds_mac_byname
,
2213 .sim_mac_bymac
= &ds_mac_bymac
,
2215 /* si_mac_all not supported */
2216 .sim_mac_all
= NULL
,
2218 /* si_addrinfo not supported */
2219 .sim_wants_addrinfo
= NULL
,
2220 .sim_addrinfo
= NULL
,
2223 static si_mod_t si
=
2227 .flags
= SI_MOD_FLAG_STATIC
,
2230 .vtable
= &ds_vtable
,
2233 static dispatch_once_t once
;
2234 dispatch_once(&once
, ^{
2235 pthread_key_create(&_ds_serv_cache_key
, _ds_serv_cache_free
);
2237 si
.name
= strdup("ds");
2238 ds_si_private_t
*pp
= calloc(1, sizeof(ds_si_private_t
));
2242 pp
->notify_token_global
= -1;
2243 pp
->notify_token_user
= -1;
2244 pp
->notify_token_group
= -1;
2245 pp
->notify_token_service
= -1;
2249 * Don't register for notifications if the cache is disabled.
2250 * notifyd (notably) disables the cache to prevent deadlocks.
2252 if (gL1CacheEnabled
!= 0)
2255 * Errors in registering for cache invalidation notifications are ignored.
2256 * If there are failures, the tokens remain set to -1 which just causes
2257 * cached items to be invalidated.
2259 notify_register_check(kNotifyDSCacheInvalidation
, &(pp
->notify_token_global
));
2260 notify_register_check(kNotifyDSCacheInvalidationUser
, &(pp
->notify_token_user
));
2261 notify_register_check(kNotifyDSCacheInvalidationGroup
, &(pp
->notify_token_group
));
2262 notify_register_check(kNotifyDSCacheInvalidationService
, &(pp
->notify_token_service
));
2271 #endif /* DS_AVAILABLE */