Libinfo-449.1.3.tar.gz
[apple/libinfo.git] / lookup.subproj / ds_module.c
1 /*
2 * Copyright (c) 2008-2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * ds.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #ifdef DS_AVAILABLE
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <time.h>
31 #include <errno.h>
32 #include <arpa/inet.h>
33 #include <sys/stat.h>
34 #include <pthread.h>
35 #include <ils.h>
36 #include <pwd.h>
37 #include <grp.h>
38 #include <fstab.h>
39 #include <netdb.h>
40 #include <notify.h>
41 #include <notify_keys.h>
42 #include <si_data.h>
43 #include <si_module.h>
44 #include <netdb_async.h>
45 #include <net/if.h>
46 #include <xpc/xpc.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 #ifdef DEBUG
53 #include <asl.h>
54 #endif
55
56 #define IPV6_ADDR_LEN 16
57 #define IPV4_ADDR_LEN 4
58
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);
60
61 /* notify SPI */
62 uint32_t notify_peek(int token, uint32_t *val);
63
64 typedef struct
65 {
66 int notify_token_global;
67 int notify_token_user;
68 int notify_token_group;
69 int notify_token_service;
70 } ds_si_private_t;
71
72 extern uint32_t gL1CacheEnabled;
73 extern int _si_opendirectory_disabled;
74
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;
78
79 mach_port_t _ds_port;
80
81 static void
82 _od_fork_child(void)
83 {
84 // re-enable opendirectory interaction since we forked
85 _si_opendirectory_disabled = 0;
86
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);
91 __od_pipe = NULL;
92 }
93 _ds_port = MACH_PORT_NULL;
94 pthread_mutex_unlock(&mutex);
95 }
96
97 static void
98 _od_fork_prepare(void)
99 {
100 pthread_mutex_lock(&mutex);
101 }
102
103 static void
104 _od_fork_parent(void)
105 {
106 pthread_mutex_unlock(&mutex);
107 }
108
109 static void
110 _ds_serv_cache_free(void *x)
111 {
112 if (x != NULL) si_item_release(x);
113 }
114
115 void
116 _si_disable_opendirectory(void)
117 {
118 _si_opendirectory_disabled = 1;
119 _ds_port = MACH_PORT_NULL;
120 }
121
122 XPC_RETURNS_RETAINED
123 static xpc_pipe_t
124 _od_xpc_pipe(bool resetPipe)
125 {
126 static dispatch_once_t once;
127 xpc_pipe_t result = NULL;
128
129 dispatch_once(&once, ^(void) {
130 char *xbs_disable;
131
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;
136 return;
137 }
138
139 pthread_atfork(_od_fork_prepare, _od_fork_parent, _od_fork_child);
140 });
141
142 if (_si_opendirectory_disabled == 1) {
143 return NULL;
144 }
145
146 pthread_mutex_lock(&mutex);
147 if (resetPipe) {
148 xpc_release(__od_pipe);
149 __od_pipe = NULL;
150 }
151
152 if (__od_pipe == NULL) {
153 if (!issetugid() && getenv("OD_DEBUG_MODE") != NULL) {
154 __od_pipe = xpc_pipe_create(kODMachLibinfoPortNameDebug, 0);
155 } else {
156 __od_pipe = xpc_pipe_create(kODMachLibinfoPortName, XPC_PIPE_FLAG_PRIVILEGED);
157 }
158 }
159
160 if (__od_pipe != NULL) result = xpc_retain(__od_pipe);
161 pthread_mutex_unlock(&mutex);
162
163 return result;
164 }
165
166 static bool
167 _od_running(void)
168 {
169 xpc_pipe_t pipe;
170
171 pipe = _od_xpc_pipe(false);
172 if (pipe != NULL) {
173 xpc_release(pipe);
174 }
175
176 if (_si_opendirectory_disabled) {
177 return 0;
178 }
179
180 return (pipe != NULL);
181 }
182
183 static void
184 _ds_child(void)
185 {
186 _ds_port = MACH_PORT_NULL;
187 }
188
189 int
190 _ds_running(void)
191 {
192 kern_return_t status;
193 char *od_debug_mode = NULL;
194
195 if (_ds_port != MACH_PORT_NULL) return 1;
196
197 if (_si_opendirectory_disabled) return 0;
198 pthread_atfork(NULL, NULL, _ds_child);
199
200 if (!issetugid()) {
201 od_debug_mode = getenv("OD_DEBUG_MODE");
202 }
203
204 if (od_debug_mode) {
205 status = bootstrap_look_up(bootstrap_port, kDSStdMachDSLookupPortName "_debug", &_ds_port);
206 } else {
207 status = bootstrap_look_up2(bootstrap_port, kDSStdMachDSLookupPortName, &_ds_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
208 }
209 if ((status != BOOTSTRAP_SUCCESS) && (status != BOOTSTRAP_UNKNOWN_SERVICE)) _ds_port = MACH_PORT_NULL;
210
211 return (_ds_port != MACH_PORT_NULL);
212 }
213
214 static bool
215 _valid_token(xpc_object_t reply)
216 {
217 audit_token_t token;
218
219 /*
220 * This should really call audit_token_to_au32,
221 * but that's in libbsm, not in a Libsystem library.
222 */
223 xpc_dictionary_get_audit_token(reply, &token);
224
225 return ((uid_t) token.val[1] == 0);
226 }
227
228 static void
229 _ds_get_validation(si_mod_t *si, uint64_t *a, uint64_t *b, int cat)
230 {
231 ds_si_private_t *pp;
232 uint32_t peek;
233 int status;
234
235 if (si == NULL) return;
236
237 pp = (ds_si_private_t *)si->private;
238 if (pp == NULL) return;
239
240 if (a != NULL)
241 {
242 *a = 0;
243 status = notify_peek(pp->notify_token_global, &peek);
244 if (status == NOTIFY_STATUS_OK) *a = ntohl(peek);
245 }
246
247 if (b != NULL)
248 {
249 *b = 0;
250 peek = 0;
251 status = NOTIFY_STATUS_FAILED;
252
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);
257
258 if (status == NOTIFY_STATUS_OK) *b = ntohl(peek);
259 }
260 }
261
262 XPC_RETURNS_RETAINED
263 __private_extern__ xpc_object_t
264 _od_rpc_call(const char *procname, xpc_object_t payload, xpc_pipe_t (*get_pipe)(bool))
265 {
266 xpc_object_t result = NULL;
267 xpc_object_t reply;
268 xpc_pipe_t od_pipe;
269 int retries, rc;
270
271 od_pipe = get_pipe(false);
272 if (od_pipe == NULL) return NULL;
273
274 if (payload == NULL) {
275 payload = xpc_dictionary_create(NULL, NULL, 0);
276 }
277
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);
281
282 for (retries = 0; od_pipe != NULL && retries < 2; retries++) {
283 rc = xpc_pipe_routine(od_pipe, payload, &reply);
284 switch (rc) {
285 case EPIPE:
286 xpc_release(od_pipe);
287 od_pipe = get_pipe(true);
288 break;
289
290 case EAGAIN:
291 /* just loop and try to send again */
292 break;
293
294 case 0:
295 if (_valid_token(reply) == true) {
296 result = reply;
297 }
298 /* fall through since we got a valid response */
299
300 default:
301 /* release and NULL the pipe it'll break the loop */
302 xpc_release(od_pipe);
303 od_pipe = NULL;
304 break;
305 }
306 }
307
308 if (od_pipe != NULL) {
309 xpc_release(od_pipe);
310 }
311
312 return result;
313 }
314
315 static si_list_t *
316 _ds_list(si_mod_t *si, int cat, const char *procname, const void *extra, od_extract_t extract)
317 {
318 __block si_list_t *list;
319 uint64_t va, vb;
320 xpc_object_t reply, result;
321
322 if (procname == NULL) return NULL;
323
324 _ds_get_validation(si, &va, &vb, cat);
325
326 list = NULL;
327 reply = _od_rpc_call(procname, NULL, _od_xpc_pipe);
328 if (reply != NULL) {
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);
335
336 return true;
337 });
338 }
339
340 xpc_release(reply);
341 }
342
343 return list;
344 }
345
346 static si_item_t *
347 _ds_item(si_mod_t *si, int cat, const char *procname, const void *extra, od_extract_t extract, xpc_object_t payload)
348 {
349 xpc_object_t result;
350 uint64_t va, vb;
351 si_item_t *item = NULL;
352
353 if (procname == NULL) return NULL;
354
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);
360 }
361
362 xpc_release(result);
363 }
364
365 return item;
366 }
367
368 static int
369 _ds_is_valid(si_mod_t *si, si_item_t *item)
370 {
371 si_mod_t *src;
372 ds_si_private_t *pp;
373 int status;
374 uint32_t oldval, newval;
375
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;
380
381 pp = (ds_si_private_t *)si->private;
382 if (pp == NULL) return 0;
383
384 src = (si_mod_t *)item->src;
385
386 if (src->name == NULL) return 0;
387 if (string_not_equal(si->name, src->name)) return 0;
388
389 /* check global invalidation */
390 oldval = item->validation_a;
391 newval = -1;
392 status = notify_peek(pp->notify_token_global, &newval);
393 if (status != NOTIFY_STATUS_OK) return 0;
394
395 newval = ntohl(newval);
396 if (oldval != newval) return 0;
397
398 oldval = item->validation_b;
399 newval = -1;
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);
403 else return 0;
404
405 if (status != NOTIFY_STATUS_OK) return 0;
406
407 newval = ntohl(newval);
408 if (oldval != newval) return 0;
409
410 return 1;
411 }
412
413 static void
414 _free_addr_list(char **l)
415 {
416 int i;
417
418 if (l == NULL) return;
419 for (i = 0; l[i] != NULL; i++) free(l[i]);
420 free(l);
421 }
422
423 /* map ipv4 addresses and append to v6 list */
424 static int
425 _map_v4(char ***v6, uint32_t n6, char **v4, uint32_t n4)
426 {
427 struct in6_addr a6;
428 uint32_t i;
429
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);
433
434 if (*v6 == NULL)
435 {
436 *v6 = (char **)calloc(n4 + 1, sizeof(char *));
437 }
438 else
439 {
440 *v6 = (char **)reallocf(*v6, (n6 + n4 + 1) * sizeof(char *));
441 }
442
443 if (*v6 == NULL) return -1;
444
445 for (i = 0; i < n4; i++)
446 {
447 (*v6)[n6] = (char *)calloc(1, IPV6_ADDR_LEN);
448 if ((*v6)[n6] == NULL) return -1;
449
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);
452
453 n6++;
454 }
455
456 return 0;
457 }
458
459 static xpc_object_t
460 _xpc_query_key_string(const char *key, const char *value)
461 {
462 xpc_object_t payload;
463
464 if (value == NULL) return NULL;
465
466 payload = xpc_dictionary_create(NULL, NULL, 0);
467 if (payload == NULL) return NULL;
468
469 xpc_dictionary_set_string(payload, key, value);
470
471 return payload;
472 }
473
474 static xpc_object_t
475 _xpc_query_key_id(const char *key, id_t idValue)
476 {
477 xpc_object_t payload;
478
479 payload = xpc_dictionary_create(NULL, NULL, 0);
480 if (payload == NULL) return NULL;
481
482 xpc_dictionary_set_int64(payload, key, idValue);
483
484 return payload;
485 }
486
487 static xpc_object_t
488 _xpc_query_key_uuid(const char *key, uuid_t uu)
489 {
490 xpc_object_t payload;
491
492 payload = xpc_dictionary_create(NULL, NULL, 0);
493 if (payload == NULL) return NULL;
494
495 xpc_dictionary_set_uuid(payload, key, uu);
496
497 return payload;
498 }
499
500 static xpc_object_t
501 _xpc_query_key_int(const char *key, int64_t intValue)
502 {
503 xpc_object_t payload;
504
505 payload = xpc_dictionary_create(NULL, NULL, 0);
506 if (payload == NULL) return NULL;
507
508 xpc_dictionary_set_int64(payload, key, intValue);
509
510 return payload;
511 }
512
513 #pragma mark -
514
515 static int
516 _extract_string_from_xpc_array_index(xpc_object_t reply, int index, const char **str)
517 {
518 xpc_object_t value;
519
520 if (xpc_array_get_count(reply) < index) return -1;
521
522 value = xpc_array_get_value(reply, index);
523 if (xpc_get_type(value) != XPC_TYPE_STRING) return -1;
524
525 *str = xpc_string_get_string_ptr(value);
526 return 0;
527 }
528
529 static int
530 _extract_string_from_xpc_object(xpc_object_t value, const char **str)
531 {
532 if (value == NULL) return -1;
533 else if (xpc_get_type(value) == XPC_TYPE_STRING)
534 {
535 *str = xpc_string_get_string_ptr(value);
536 return 0;
537 }
538 else if (xpc_get_type(value) == XPC_TYPE_ARRAY)
539 {
540 return _extract_string_from_xpc_array_index(value, 0, str);
541 }
542
543 return -1;
544 }
545
546 static int
547 _extract_uint32_from_xpc_object(xpc_object_t value, uint32_t *val32)
548 {
549 xpc_type_t type;
550
551 if (value == NULL) return -1;
552 type = xpc_get_type(value);
553
554 if (type == XPC_TYPE_STRING)
555 {
556 *val32 = atoi(xpc_string_get_string_ptr(value));
557 return 0;
558 }
559 else if (type == XPC_TYPE_INT64)
560 {
561 *val32 = (uint32_t)xpc_int64_get_value(value);
562 return 0;
563 }
564 else if (type == XPC_TYPE_BOOL)
565 {
566 *val32 = (uint32_t)xpc_bool_get_value(value);
567 return 0;
568 }
569 else if (type == XPC_TYPE_ARRAY)
570 {
571 if (xpc_array_get_count(value) == 0) return -1;
572 return _extract_uint32_from_xpc_object(xpc_array_get_value(value, 0), val32);
573 }
574
575 return -1;
576 }
577
578 static int
579 _extract_string_list_from_xpc_array_index(xpc_object_t reply, int index, unsigned int *len, char ***list)
580 {
581 char **result;
582 xpc_object_t xpc_array = xpc_array_get_value(reply, index);
583
584 if ((xpc_array == NULL) || (xpc_get_type(xpc_array) != XPC_TYPE_ARRAY)) return -1;
585
586 result = calloc(xpc_array_get_count(xpc_array) + 1, sizeof(*result));
587 if (result == NULL) return -1;
588
589 /* include trailing NULL */
590 if (len != NULL) (*len) = xpc_array_get_count(xpc_array) + 1;
591
592 xpc_array_apply(xpc_array, ^bool(size_t idx, xpc_object_t value) {
593 result[idx] = (char *)xpc_string_get_string_ptr(value);
594 return true;
595 });
596
597 *list = result;
598 return 0;
599 }
600
601 static int
602 _extract_uint32_from_xpc_array_index(xpc_object_t reply, int index, uint32_t *val32)
603 {
604 xpc_object_t value = xpc_array_get_value(reply, index);
605 return _extract_uint32_from_xpc_object(value, val32);
606 }
607
608 static int
609 _extract_string_list_from_xpc_array(xpc_object_t xpc_array, unsigned int *len, char ***list)
610 {
611 char **result;
612
613 if ((xpc_array == NULL) || (xpc_get_type(xpc_array) != XPC_TYPE_ARRAY)) return -1;
614
615 result = calloc(xpc_array_get_count(xpc_array) + 1, sizeof(*result));
616 if (result == NULL) return -1;
617
618 /* include trailing NULL */
619 if (len != NULL) (*len) = xpc_array_get_count(xpc_array) + 1;
620
621 xpc_array_apply(xpc_array, ^bool(size_t idx, xpc_object_t value) {
622 result[idx] = (char *)xpc_string_get_string_ptr(value);
623 return true;
624 });
625
626 *list = result;
627 return 0;
628 }
629
630 static int
631 _extract_string_from_xpc_dict(xpc_object_t reply, const char *key, const char **str)
632 {
633 xpc_object_t value = xpc_dictionary_get_value(reply, key);
634 const char *result;
635
636 if (value == NULL) return -1;
637
638 if (xpc_get_type(value) != XPC_TYPE_STRING) return -1;
639
640 result = xpc_string_get_string_ptr(value);
641 if (result == NULL) return -1;
642
643 *str = result;
644 return 0;
645 }
646
647 static int
648 _extract_uint32_from_xpc_dict(xpc_object_t reply, const char *key, uint32_t *val32)
649 {
650 xpc_object_t value = xpc_dictionary_get_value(reply, key);
651 return _extract_uint32_from_xpc_object(value, val32);
652 }
653
654 #pragma mark -
655
656 /*
657 * user schema
658 *
659 * name : string
660 * passwd : string
661 * uid : uint32
662 * gid : uint32
663 * gecos : string
664 * dir : string
665 * shell : string
666 */
667
668 static si_item_t *
669 _extract_user_array(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat)
670 {
671 struct passwd tmp;
672 int i = 0;
673
674 if (xpc_array_get_count(reply) < 7) return NULL;
675
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;
683
684 /* default values */
685 tmp.pw_change = (time_t)0;
686 tmp.pw_expire = (time_t)0;
687 tmp.pw_class = (char *)"";
688
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);
690 }
691
692 static si_item_t *
693 _extract_user_dict(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat)
694 {
695 __block struct passwd tmp;
696 __block int status = 0;
697 __block int parts = 3;
698
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";
709
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"))
713 {
714 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.pw_name);
715 if (status == 0) parts--;
716 }
717 else if (!strcmp(key, "pw_passwd"))
718 {
719 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.pw_passwd);
720 /* no parts check - this value is optional */
721 }
722 else if (!strcmp(key, "pw_uid"))
723 {
724 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.pw_uid);
725 if (status == 0) parts--;
726 }
727 else if (!strcmp(key, "pw_gid"))
728 {
729 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.pw_gid);
730 if (status == 0) parts--;
731 }
732 else if (!strcmp(key, "pw_change"))
733 {
734 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.pw_change);
735 /* no parts check - this value is optional */
736 }
737 else if (!strcmp(key, "pw_expire"))
738 {
739 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.pw_expire);
740 /* no parts check - this value is optional */
741 }
742 else if (!strcmp(key, "pw_class"))
743 {
744 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.pw_class);
745 /* no parts check - this value is optional */
746 }
747 else if (!strcmp(key, "pw_gecos"))
748 {
749 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.pw_gecos);
750 /* no parts check - this value is optional */
751 }
752 else if (!strcmp(key, "pw_dir"))
753 {
754 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.pw_dir);
755 /* no parts check - this value is optional */
756 }
757 else if (!strcmp(key, "pw_shell"))
758 {
759 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.pw_shell);
760 /* no parts check - this value is optional */
761 }
762 return true;
763 });
764
765 if ((status != 0) || (parts != 0)) return NULL;
766
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);
768 }
769
770 static si_item_t *
771 _extract_user(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
772 {
773 xpc_type_t type;
774
775 if (si == NULL) return NULL;
776 if (reply == NULL) return NULL;
777
778 type = xpc_get_type(reply);
779
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);
782
783 return NULL;
784 }
785
786 /*
787 * group schema
788 *
789 * name : string
790 * gid : uint32
791 * optional members : array of string
792 *
793 */
794
795 static si_item_t *
796 _extract_group_array(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat)
797 {
798 si_item_t *item;
799 struct group tmp;
800 int i = 0;
801 int arraycount = xpc_array_get_count(reply);
802
803 if ((arraycount < 2) || (arraycount > 3)) return NULL;
804
805 memset(&tmp, 0, sizeof(tmp));
806
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;
809
810 if (arraycount == 3)
811 {
812 if (0 != _extract_string_list_from_xpc_array_index(reply, i++, NULL, (char ***)&tmp.gr_mem)) return NULL;
813 }
814
815 /* default value */
816 tmp.gr_passwd = (char *)"*";
817
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);
819
820 free(tmp.gr_mem);
821
822 return item;
823 }
824
825 static si_item_t *
826 _extract_group_dict(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat)
827 {
828 si_item_t *item;
829 __block struct group tmp;
830 __block int status = 0;
831 __block int parts = 2;
832
833 tmp.gr_name = (char *)"";
834 tmp.gr_passwd = (char *)"*";
835 tmp.gr_gid = (gid_t)0;
836 tmp.gr_mem = NULL;
837
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"))
841 {
842 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.gr_name);
843 if (status == 0) parts--;
844 }
845 else if (!strcmp(key, "gr_passwd"))
846 {
847 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.gr_passwd);
848 /* no parts check - this value is optional */
849 }
850 else if (!strcmp(key, "gr_gid"))
851 {
852 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.gr_gid);
853 if (status == 0) parts--;
854 }
855 else if (!strcmp(key, "gr_mem"))
856 {
857 status |= _extract_string_list_from_xpc_array(value, NULL, (char ***)&tmp.gr_mem);
858 /* no parts check - this value is optional */
859 }
860 return true;
861 });
862
863 if ((status != 0) || (parts != 0))
864 {
865 free(tmp.gr_mem);
866 return NULL;
867 }
868
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);
870
871 free(tmp.gr_mem);
872
873 return item;
874 }
875
876 static si_item_t *
877 _extract_group(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
878 {
879 xpc_type_t type;
880
881 if (si == NULL) return NULL;
882 if (reply == NULL) return NULL;
883
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);
887
888 return NULL;
889 }
890
891 /*
892 * netgroup schema
893 *
894 * host : string
895 * user : string
896 * domain : string
897 *
898 */
899 static si_item_t *
900 _extract_netgroup_array(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat)
901 {
902 const char *host, *user, *domain;
903 int i = 0;
904
905 if (xpc_array_get_count(reply) != 3) return NULL;
906
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;
910
911 return (si_item_t *)LI_ils_create("L4488sss", (unsigned long)si, CATEGORY_NETGROUP, 1, valid_global, valid_cat, host, user, domain);
912 }
913
914 static si_item_t *
915 _extract_netgroup_dict(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat)
916 {
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;
922
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"))
926 {
927 status |= _extract_string_from_xpc_object(value, (const char **)&host);
928 if (status == 0) parts--;
929 }
930 else if (!strcmp(key, "user"))
931 {
932 status |= _extract_string_from_xpc_object(value, (const char **)&user);
933 if (status == 0) parts--;
934 }
935 else if (!strcmp(key, "domain"))
936 {
937 status |= _extract_string_from_xpc_object(value, (const char **)&domain);
938 if (status == 0) parts--;
939 }
940 return true;
941 });
942
943 if ((status != 0) || (parts != 0)) return NULL;
944
945 return (si_item_t *)LI_ils_create("L4488sss", (unsigned long)si, CATEGORY_NETGROUP, 1, valid_global, valid_cat, host, user, domain);
946 }
947
948 static si_item_t *
949 _extract_netgroup(si_mod_t *si, xpc_object_t reply, const void *ignored, uint64_t valid_global, uint64_t valid_cat)
950 {
951 xpc_type_t type;
952
953 if (si == NULL) return NULL;
954 if (reply == NULL) return NULL;
955
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);
959
960 return NULL;
961 }
962
963 /*
964 * alias schema
965 *
966 * name : string
967 * local : uint32
968 * optional members : array of string
969 *
970 */
971
972 static si_item_t *
973 _extract_alias_array(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat)
974 {
975 si_item_t *item;
976 struct aliasent tmp;
977 int i = 0;
978 int arraycount = xpc_array_get_count(reply);
979
980 if ((arraycount < 2) || (arraycount > 3)) return NULL;
981
982 memset(&tmp, 0, sizeof(tmp));
983
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;
986
987 if (arraycount == 3)
988 {
989 if (0 != _extract_string_list_from_xpc_array_index(reply, i++, NULL, (char ***)&tmp.alias_members)) return NULL;
990 }
991
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);
993
994 free(tmp.alias_members);
995
996 return item;
997 }
998
999 static si_item_t *
1000 _extract_alias_dict(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat)
1001 {
1002 si_item_t *item;
1003 __block struct aliasent tmp;
1004 __block int status = 0;
1005 __block int parts = 2;
1006
1007 tmp.alias_name = (char *)"";
1008 tmp.alias_local = 0;
1009 tmp.alias_members = NULL;
1010 tmp.alias_members_len = 0;
1011
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"))
1015 {
1016 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.alias_name);
1017 if (status == 0) parts--;
1018 }
1019 else if (!strcmp(key, "alias_local"))
1020 {
1021 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.alias_local);
1022 if (status == 0) parts--;
1023 }
1024 else if (!strcmp(key, "alias_members"))
1025 {
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 */
1028 }
1029 return true;
1030 });
1031
1032 if ((status != 0) || (parts != 0))
1033 {
1034 free(tmp.alias_members);
1035 return NULL;
1036 }
1037
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);
1039
1040 free(tmp.alias_members);
1041
1042 return item;
1043 }
1044
1045 static si_item_t *
1046 _extract_alias(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
1047 {
1048 xpc_type_t type;
1049
1050 if (si == NULL) return NULL;
1051 if (reply == NULL) return NULL;
1052
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);
1056
1057 return NULL;
1058 }
1059
1060 /*
1061 * network schema
1062 *
1063 * name : string
1064 * net : uint32
1065 * optional aliases : array of string
1066 *
1067 */
1068
1069 static si_item_t *
1070 _extract_network_array(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat)
1071 {
1072 si_item_t *item;
1073 struct netent tmp;
1074 int i = 0;
1075 int arraycount = xpc_array_get_count(reply);
1076
1077 if ((arraycount < 2) || (arraycount > 3)) return NULL;
1078
1079 memset(&tmp, 0, sizeof(tmp));
1080
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;
1083
1084 if (arraycount == 3)
1085 {
1086 if (0 != _extract_string_list_from_xpc_array_index(reply, i++, NULL, (char ***)&tmp.n_aliases)) return NULL;
1087 }
1088
1089 /* default value */
1090 tmp.n_addrtype = AF_INET;
1091
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);
1093
1094 free(tmp.n_aliases);
1095
1096 return item;
1097 }
1098
1099 static si_item_t *
1100 _extract_network_dict(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat)
1101 {
1102 si_item_t *item;
1103 __block struct netent tmp;
1104 __block int status = 0;
1105 __block int parts = 2;
1106
1107 if (si == NULL) return NULL;
1108 if (reply == NULL) return NULL;
1109
1110 tmp.n_name = (char *)"";
1111 tmp.n_aliases = NULL;
1112 tmp.n_net = 0;
1113
1114 /* default value */
1115 tmp.n_addrtype = AF_INET;
1116
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"))
1120 {
1121 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.n_name);
1122 if (status == 0) parts--;
1123 }
1124 else if (!strcmp(key, "n_aliases"))
1125 {
1126 status |= _extract_string_list_from_xpc_array(value, NULL, (char ***)&tmp.n_aliases);
1127 /* no parts check - this value is optional */
1128 }
1129 else if (!strcmp(key, "n_net"))
1130 {
1131 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.n_net);
1132 if (status == 0) parts--;
1133 }
1134 return true;
1135 });
1136
1137 if ((status != 0) || (parts != 0))
1138 {
1139 free(tmp.n_aliases);
1140 return NULL;
1141 }
1142
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);
1144
1145 free(tmp.n_aliases);
1146
1147 return item;
1148 }
1149
1150 static si_item_t *
1151 _extract_network(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
1152 {
1153 xpc_type_t type;
1154
1155 if (si == NULL) return NULL;
1156 if (reply == NULL) return NULL;
1157
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);
1161
1162 return NULL;
1163 }
1164
1165 /*
1166 * service schema
1167 *
1168 * name : string
1169 * port : uint32
1170 * proto : string
1171 * optional aliases : array of string
1172 *
1173 */
1174
1175 static si_item_t *
1176 _extract_service_array(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat)
1177 {
1178 si_item_t *item;
1179 struct servent tmp;
1180 int i = 0;
1181 int arraycount = xpc_array_get_count(reply);
1182
1183 if ((arraycount < 3) || (arraycount > 4)) return NULL;
1184
1185 memset(&tmp, 0, sizeof(tmp));
1186
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;
1190
1191 if (arraycount == 4)
1192 {
1193 if (0 != _extract_string_list_from_xpc_array_index(reply, i++, NULL, (char ***)&tmp.s_aliases)) return NULL;
1194 }
1195
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);
1197
1198 free(tmp.s_aliases);
1199
1200 return item;
1201 }
1202
1203 static si_item_t *
1204 _extract_service_dict(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat)
1205 {
1206 si_item_t *item;
1207 __block struct servent tmp;
1208 __block int status = 0;
1209 __block int parts = 3;
1210
1211 if (si == NULL) return NULL;
1212 if (reply == NULL) return NULL;
1213
1214 tmp.s_name = (char *)"";
1215 tmp.s_aliases = NULL;
1216 tmp.s_port = 0;
1217 tmp.s_proto = (char *)"";
1218
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"))
1222 {
1223 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.s_name);
1224 if (status == 0) parts--;
1225 }
1226 else if (!strcmp(key, "s_aliases"))
1227 {
1228 status |= _extract_string_list_from_xpc_array(value, NULL, (char ***)&tmp.s_aliases);
1229 /* no parts check - this value is optional */
1230 }
1231 else if (!strcmp(key, "s_port"))
1232 {
1233 uint32_t v32;
1234 status |= _extract_uint32_from_xpc_object(value, &v32);
1235 if (status == 0)
1236 {
1237 tmp.s_port = (unsigned int)htons(v32); // ugh
1238 parts--;
1239 }
1240 }
1241 else if (!strcmp(key, "s_proto"))
1242 {
1243 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.s_proto);
1244 if (status == 0) parts--;
1245 }
1246 return true;
1247 });
1248
1249 if ((status != 0) || (parts != 0))
1250 {
1251 free(tmp.s_aliases);
1252 return NULL;
1253 }
1254
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);
1256
1257 free(tmp.s_aliases);
1258
1259 return item;
1260 }
1261
1262 static si_item_t *
1263 _extract_service(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
1264 {
1265 xpc_type_t type;
1266
1267 if (si == NULL) return NULL;
1268 if (reply == NULL) return NULL;
1269
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);
1273
1274 return NULL;
1275 }
1276
1277 /*
1278 * protocol schema
1279 *
1280 * name : string
1281 * proto : uint32
1282 * optional aliases : array of string
1283 *
1284 */
1285 static si_item_t *
1286 _extract_protocol_array(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat)
1287 {
1288 si_item_t *item;
1289 struct protoent tmp;
1290 int i = 0;
1291 int arraycount = xpc_array_get_count(reply);
1292
1293 if ((arraycount < 2) || (arraycount > 3)) return NULL;
1294
1295 memset(&tmp, 0, sizeof(tmp));
1296
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;
1299
1300 if (arraycount == 3)
1301 {
1302 if (0 != _extract_string_list_from_xpc_array_index(reply, i++, NULL, (char ***)&tmp.p_aliases)) return NULL;
1303 }
1304
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);
1306
1307 free(tmp.p_aliases);
1308
1309 return item;
1310 }
1311
1312 static si_item_t *
1313 _extract_protocol_dict(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat)
1314 {
1315 si_item_t *item;
1316 __block struct protoent tmp;
1317 __block int status = 0;
1318 __block int parts = 2;
1319
1320 tmp.p_name = (char *)"";
1321 tmp.p_proto = 0;
1322 tmp.p_aliases = NULL;
1323
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"))
1327 {
1328 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.p_name);
1329 if (status == 0) parts--;
1330 }
1331 else if (!strcmp(key, "p_proto"))
1332 {
1333 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.p_proto);
1334 if (status == 0) parts--;
1335 }
1336 else if (!strcmp(key, "p_aliases"))
1337 {
1338 status |= _extract_string_list_from_xpc_array(value, NULL, (char ***)&tmp.p_aliases);
1339 /* no parts check - this value is optional */
1340 }
1341 return true;
1342 });
1343
1344 if ((status != 0) || (parts != 0))
1345 {
1346 free(tmp.p_aliases);
1347 return NULL;
1348 }
1349
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);
1351
1352 free(tmp.p_aliases);
1353
1354 return item;
1355 }
1356
1357 static si_item_t *
1358 _extract_protocol(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
1359 {
1360 xpc_type_t type;
1361
1362 if (si == NULL) return NULL;
1363 if (reply == NULL) return NULL;
1364
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);
1368
1369 return NULL;
1370 }
1371
1372 /*
1373 * rpc schema
1374 *
1375 * name : string
1376 * number : uint32
1377 * optional aliases : array of string
1378 *
1379 */
1380
1381 static si_item_t *
1382 _extract_rpc_array(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat)
1383 {
1384 si_item_t *item;
1385 struct rpcent tmp;
1386 int i = 0;
1387 int arraycount = xpc_array_get_count(reply);
1388
1389 if ((arraycount < 2) || (arraycount > 3)) return NULL;
1390
1391 memset(&tmp, 0, sizeof(tmp));
1392
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;
1395
1396 if (arraycount == 3)
1397 {
1398 if (0 != _extract_string_list_from_xpc_array_index(reply, i++, NULL, (char ***)&tmp.r_aliases)) return NULL;
1399 }
1400
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);
1402
1403 free(tmp.r_aliases);
1404
1405 return item;
1406 }
1407
1408 static si_item_t *
1409 _extract_rpc_dict(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat)
1410 {
1411 si_item_t *item;
1412 __block struct rpcent tmp;
1413 __block int status = 0;
1414 __block int parts = 2;
1415
1416 tmp.r_name = (char *)"";
1417 tmp.r_number = 0;
1418 tmp.r_aliases = NULL;
1419
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"))
1423 {
1424 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.r_name);
1425 if (status == 0) parts--;
1426 }
1427 else if (!strcmp(key, "r_number"))
1428 {
1429 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.r_number);
1430 if (status == 0) parts--;
1431 }
1432 else if (!strcmp(key, "r_aliases"))
1433 {
1434 status |= _extract_string_list_from_xpc_array(value, NULL, (char ***)&tmp.r_aliases);
1435 /* no parts check - this value is optional */
1436 }
1437 return true;
1438 });
1439
1440 if ((status != 0) || (parts != 0))
1441 {
1442 free(tmp.r_aliases);
1443 return NULL;
1444 }
1445
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);
1447
1448 free(tmp.r_aliases);
1449
1450 return item;
1451 }
1452
1453 static si_item_t *
1454 _extract_rpc(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
1455 {
1456 xpc_type_t type;
1457
1458 if (si == NULL) return NULL;
1459 if (reply == NULL) return NULL;
1460
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);
1464
1465 return NULL;
1466 }
1467
1468 /*
1469 * fstab schema
1470 *
1471 * file : string
1472 * spec : string
1473 * freq : uint32
1474 * passno : uint32
1475 * mntopts : string
1476 * type : string
1477 * vfstype : string
1478 */
1479
1480 static si_item_t *
1481 _extract_fstab_array(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat)
1482 {
1483 __block struct fstab tmp;
1484 int i = 0;
1485
1486 if (xpc_array_get_count(reply) != 7) return NULL;
1487
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;
1495
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);
1497 }
1498
1499 static si_item_t *
1500 _extract_fstab_dict(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat)
1501 {
1502 __block struct fstab tmp;
1503 __block int status = 0;
1504 __block int parts = 7;
1505
1506 tmp.fs_file = NULL;
1507 tmp.fs_spec = (char *)"";
1508 tmp.fs_freq = 0;
1509 tmp.fs_passno = 0;
1510 tmp.fs_mntops = (char *)"";
1511 tmp.fs_type = (char *)"";
1512 tmp.fs_vfstype = (char *)"";
1513
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"))
1517 {
1518 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.fs_file);
1519 if (status == 0) parts--;
1520 }
1521 else if (!strcmp(key, "fs_spec"))
1522 {
1523 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.fs_spec);
1524 if (status == 0) parts--;
1525 }
1526 else if (!strcmp(key, "fs_freq"))
1527 {
1528 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.fs_freq);
1529 if (status == 0) parts--;
1530 }
1531 else if (!strcmp(key, "fs_passno"))
1532 {
1533 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.fs_passno);
1534 if (status == 0) parts--;
1535 }
1536 else if (!strcmp(key, "fs_mntops"))
1537 {
1538 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.fs_mntops);
1539 if (status == 0) parts--;
1540 }
1541 else if (!strcmp(key, "fs_type"))
1542 {
1543 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.fs_type);
1544 if (status == 0) parts--;
1545 }
1546 else if (!strcmp(key, "fs_vfstype"))
1547 {
1548 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.fs_vfstype);
1549 if (status == 0) parts--;
1550 }
1551 return true;
1552 });
1553
1554 if ((status != 0) || (parts != 0)) return NULL;
1555
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);
1557 }
1558
1559 static si_item_t *
1560 _extract_fstab(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
1561 {
1562 xpc_type_t type;
1563
1564 if (si == NULL) return NULL;
1565 if (reply == NULL) return NULL;
1566
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);
1570
1571 return NULL;
1572 }
1573
1574 static si_item_t *
1575 _extract_mac_mac(si_mod_t *si, xpc_object_t reply, const void *extra, uint64_t valid_global, uint64_t valid_cat)
1576 {
1577 xpc_type_t type;
1578 char *cmac;
1579 const char *value = NULL;
1580 si_item_t *out;
1581
1582 if (si == NULL) return NULL;
1583 if (reply == NULL) return NULL;
1584 if (extra == NULL) return NULL;
1585
1586 type = xpc_get_type(reply);
1587 if (type == XPC_TYPE_ARRAY)
1588 {
1589 if (xpc_array_get_count(reply) >= 1)
1590 {
1591 if (0 != _extract_string_from_xpc_array_index(reply, 0, (const char **)&value)) return NULL;
1592 }
1593 }
1594 else if (type == XPC_TYPE_DICTIONARY)
1595 {
1596 if (0 != _extract_string_from_xpc_dict(reply, "mac", &value)) return NULL;
1597 }
1598
1599 if (value == NULL || value[0] == '\0') return NULL;
1600
1601 cmac = si_standardize_mac_address(value);
1602 if (cmac == NULL) return NULL;
1603
1604 out = (si_item_t *)LI_ils_create("L4488ss", (unsigned long)si, CATEGORY_MAC, 1, valid_global, valid_cat, extra, cmac);
1605
1606 free(cmac);
1607
1608 return out;
1609 }
1610
1611 static si_item_t *
1612 _extract_mac_name(si_mod_t *si, xpc_object_t reply, const void *extra, uint64_t valid_global, uint64_t valid_cat)
1613 {
1614 xpc_type_t type;
1615 const char *name = NULL;
1616 si_item_t *out;
1617
1618 if (si == NULL) return NULL;
1619 if (reply == NULL) return NULL;
1620 if (extra == NULL) return NULL;
1621
1622 type = xpc_get_type(reply);
1623 if (type == XPC_TYPE_ARRAY)
1624 {
1625 if (xpc_array_get_count(reply) >= 1)
1626 {
1627 if (0 != _extract_string_from_xpc_array_index(reply, 0, (const char **)&name )) return NULL;
1628 }
1629 }
1630 else if (type == XPC_TYPE_DICTIONARY)
1631 {
1632 if (0 != _extract_string_from_xpc_dict(reply, "name", &name)) return NULL;
1633 }
1634
1635 if (name == NULL) return NULL;
1636
1637 out = (si_item_t *)LI_ils_create("L4488ss", (unsigned long)si, CATEGORY_MAC, 1, valid_global, valid_cat, name, extra);
1638
1639 return out;
1640 }
1641
1642 #pragma mark -
1643
1644 static si_item_t *
1645 ds_user_byname(si_mod_t *si, const char *name)
1646 {
1647 xpc_object_t payload;
1648 si_item_t *item;
1649
1650 if (!_od_running()) return NULL;
1651
1652 payload = _xpc_query_key_string("name", name);
1653 if (payload == NULL) return NULL;
1654
1655 item = _ds_item(si, CATEGORY_USER, "getpwnam", NULL, _extract_user, payload);
1656
1657 xpc_release(payload);
1658 return item;
1659 }
1660
1661 static si_item_t *
1662 ds_user_byuid(si_mod_t *si, uid_t uid)
1663 {
1664 xpc_object_t payload;
1665 si_item_t *item;
1666
1667 if (!_od_running()) return NULL;
1668
1669 payload = _xpc_query_key_id("uid", uid);
1670 if (payload == NULL) return NULL;
1671
1672 item = _ds_item(si, CATEGORY_USER, "getpwuid", NULL, _extract_user, payload);
1673
1674 xpc_release(payload);
1675 return item;
1676 }
1677
1678 static si_item_t *
1679 ds_user_byuuid(si_mod_t *si, uuid_t uuid)
1680 {
1681 xpc_object_t payload;
1682 si_item_t *item;
1683
1684 if (!_od_running()) return NULL;
1685
1686 payload = _xpc_query_key_uuid("uuid", uuid);
1687 if (payload == NULL) return NULL;
1688
1689 item = _ds_item(si, CATEGORY_USER, "getpwuuid", NULL, _extract_user, payload);
1690
1691 xpc_release(payload);
1692 return item;
1693 }
1694
1695 static si_list_t *
1696 ds_user_all(si_mod_t *si)
1697 {
1698 return _ds_list(si, CATEGORY_USER, "getpwent", NULL, _extract_user);
1699 }
1700
1701 static si_item_t *
1702 ds_group_byname(si_mod_t *si, const char *name)
1703 {
1704 xpc_object_t payload;
1705 si_item_t *item;
1706
1707 if (!_od_running()) return NULL;
1708
1709 payload = _xpc_query_key_string("name", name);
1710 if (payload == NULL) return NULL;
1711
1712 item = _ds_item(si, CATEGORY_GROUP, "getgrnam", NULL, _extract_group, payload);
1713
1714 xpc_release(payload);
1715 return item;
1716 }
1717
1718 static si_item_t *
1719 ds_group_bygid(si_mod_t *si, gid_t gid)
1720 {
1721 xpc_object_t payload;
1722 si_item_t *item;
1723
1724 if (!_od_running()) return NULL;
1725
1726 payload = _xpc_query_key_id("gid", gid);
1727 if (payload == NULL) return NULL;
1728
1729 item = _ds_item(si, CATEGORY_GROUP, "getgrgid", NULL, _extract_group, payload);
1730
1731 xpc_release(payload);
1732 return item;
1733 }
1734
1735 static si_item_t *
1736 ds_group_byuuid(si_mod_t *si, uuid_t uuid)
1737 {
1738 xpc_object_t payload;
1739 si_item_t *item;
1740
1741 if (!_od_running()) return NULL;
1742
1743 payload = _xpc_query_key_uuid("uuid", uuid);
1744 if (payload == NULL) return NULL;
1745
1746 item = _ds_item(si, CATEGORY_GROUP, "getgruuid", NULL, _extract_group, payload);
1747
1748 xpc_release(payload);
1749 return item;
1750 }
1751
1752 static si_list_t *
1753 ds_group_all(si_mod_t *si)
1754 {
1755 if (!_od_running()) return NULL;
1756 return _ds_list(si, CATEGORY_GROUP, "getgrent", NULL, _extract_group);
1757 }
1758
1759 static si_item_t *
1760 ds_grouplist(si_mod_t *si, const char *name, uint32_t ngroups)
1761 {
1762 xpc_object_t payload, reply;
1763 si_item_t *item = NULL;
1764
1765 if (!_od_running()) return NULL;
1766 if (name == NULL) return NULL;
1767
1768 payload = xpc_dictionary_create(NULL, NULL, 0);
1769 if (payload == NULL) return NULL;
1770
1771 xpc_dictionary_set_string(payload, "name", name);
1772 xpc_dictionary_set_int64(payload, "ngroups", ngroups);
1773
1774 reply = _od_rpc_call("getgrouplist", payload, _od_xpc_pipe);
1775 if (reply != NULL) {
1776 size_t gidptrsz;
1777 const gid_t *gidptr = xpc_dictionary_get_data(reply, "groups", &gidptrsz);
1778 uint32_t count = 0;
1779 uint64_t va, vb;
1780
1781 _ds_get_validation(si, &va, &vb, CATEGORY_GROUPLIST);
1782
1783 /* see what we were sent */
1784 if (0 == _extract_uint32_from_xpc_dict(reply, "count", &count))
1785 {
1786 if (count != 0)
1787 {
1788 item = (si_item_t *)LI_ils_create("L4488s4@", (unsigned long)si, CATEGORY_GROUPLIST, 1, va, vb, name, count,
1789 gidptrsz, gidptr);
1790 }
1791 }
1792
1793 xpc_release(reply);
1794 }
1795
1796 xpc_release(payload);
1797
1798 return item;
1799 }
1800
1801 static si_list_t *
1802 ds_netgroup_byname(si_mod_t *si, const char *name)
1803 {
1804 xpc_object_t payload;
1805 si_list_t *list = NULL;
1806 si_item_t *item;
1807
1808 if (!_od_running()) return NULL;
1809
1810 payload = _xpc_query_key_string("netgroup", name);
1811 if (payload == NULL) return NULL;
1812
1813 item = _ds_item(si, CATEGORY_NETGROUP, "getnetgrent", NULL, _extract_netgroup, payload);
1814 if (item != NULL) {
1815 list = si_list_add(list, item);
1816 si_item_release(item);
1817 }
1818
1819 xpc_release(payload);
1820
1821 return list;
1822 }
1823
1824 static int
1825 ds_in_netgroup(si_mod_t *si, const char *group, const char *host, const char *user, const char *domain)
1826 {
1827 xpc_object_t payload, reply;
1828 int is_innetgr;
1829
1830 if (!_od_running()) return 0;
1831
1832 payload = xpc_dictionary_create(NULL, NULL, 0);
1833 if (payload == NULL) return 0;
1834
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 : ""));
1839
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);
1843 xpc_release(reply);
1844 } else {
1845 is_innetgr = 0;
1846 }
1847
1848 xpc_release(payload);
1849
1850 return is_innetgr;
1851 }
1852
1853 static si_item_t *
1854 ds_alias_byname(si_mod_t *si, const char *name)
1855 {
1856 xpc_object_t payload;
1857 si_item_t *item;
1858
1859 if (!_od_running()) return NULL;
1860
1861 payload = _xpc_query_key_string("name", name);
1862 if (payload == NULL) return NULL;
1863
1864 item = _ds_item(si, CATEGORY_ALIAS, "alias_getbyname", NULL, _extract_alias, payload);
1865
1866 xpc_release(payload);
1867 return item;
1868 }
1869
1870 static si_list_t *
1871 ds_alias_all(si_mod_t *si)
1872 {
1873 if (!_od_running()) return NULL;
1874 return _ds_list(si, CATEGORY_ALIAS, "alias_getent", NULL, _extract_alias);
1875 }
1876
1877 static si_item_t *
1878 ds_network_byname(si_mod_t *si, const char *name)
1879 {
1880 xpc_object_t payload;
1881 si_item_t *item;
1882
1883 if (!_od_running()) return NULL;
1884
1885 payload = _xpc_query_key_string("name", name);
1886 if (payload == NULL) return NULL;
1887
1888 item = _ds_item(si, CATEGORY_NETWORK, "getnetbyname", NULL, _extract_network, payload);
1889
1890 xpc_release(payload);
1891 return item;
1892 }
1893
1894 static si_item_t *
1895 ds_network_byaddr(si_mod_t *si, uint32_t addr)
1896 {
1897 unsigned char f1, f2, f3;
1898 char val[64];
1899 xpc_object_t payload;
1900 si_item_t *item;
1901
1902 if (!_od_running()) return NULL;
1903
1904 f1 = addr & 0xff;
1905 addr >>= 8;
1906 f2 = addr & 0xff;
1907 addr >>= 8;
1908 f3 = addr & 0xff;
1909
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);
1913
1914 payload = _xpc_query_key_string("net", val);
1915 if (payload == NULL) return NULL;
1916
1917 item = _ds_item(si, CATEGORY_NETWORK, "getnetbyaddr", NULL, _extract_network, payload);
1918
1919 xpc_release(payload);
1920 return item;
1921 }
1922
1923 static si_list_t *
1924 ds_network_all(si_mod_t *si)
1925 {
1926 if (!_od_running()) return NULL;
1927 return _ds_list(si, CATEGORY_NETWORK, "getnetent", NULL, _extract_network);
1928 }
1929
1930 static si_item_t *
1931 ds_service_byname(si_mod_t *si, const char *name, const char *proto)
1932 {
1933 xpc_object_t payload;
1934 si_item_t *item;
1935 struct servent *s;
1936
1937 if (!_od_running()) return NULL;
1938 if (name == NULL) name = "";
1939 if (proto == NULL) proto = "";
1940
1941 /* Check our local service cache (see ds_addrinfo). */
1942 item = pthread_getspecific(_ds_serv_cache_key);
1943 if (item != NULL)
1944 {
1945 s = (struct servent *)((uintptr_t)item + sizeof(si_item_t));
1946 if (string_equal(name, s->s_name)) return si_item_retain(item);
1947 }
1948
1949 payload = xpc_dictionary_create(NULL, NULL, 0);
1950 if (payload == NULL) return NULL;
1951
1952 xpc_dictionary_set_string(payload, "name", name);
1953 xpc_dictionary_set_string(payload, "proto", proto);
1954
1955 item = _ds_item(si, CATEGORY_SERVICE, "getservbyname", NULL, _extract_service, payload);
1956
1957 xpc_release(payload);
1958
1959 return item;
1960 }
1961
1962 static si_item_t *
1963 ds_service_byport(si_mod_t *si, int port, const char *proto)
1964 {
1965 xpc_object_t payload;
1966 si_item_t *item;
1967
1968 if (!_od_running()) return NULL;
1969
1970 payload = xpc_dictionary_create(NULL, NULL, 0);
1971 if (payload == NULL) return NULL;
1972
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 : ""));
1976
1977 item = _ds_item(si, CATEGORY_SERVICE, "getservbyport", NULL, _extract_service, payload);
1978
1979 xpc_release(payload);
1980
1981 return item;
1982 }
1983
1984 static si_list_t *
1985 ds_service_all(si_mod_t *si)
1986 {
1987 if (!_od_running()) return NULL;
1988 return _ds_list(si, CATEGORY_SERVICE, "getservent", NULL, _extract_service);
1989 }
1990
1991 static si_item_t *
1992 ds_protocol_byname(si_mod_t *si, const char *name)
1993 {
1994 xpc_object_t payload;
1995 si_item_t *item;
1996
1997 if (!_od_running()) return NULL;
1998
1999 payload = _xpc_query_key_string("name", name);
2000 if (payload == NULL) return NULL;
2001
2002 item = _ds_item(si, CATEGORY_PROTOCOL, "getprotobyname", NULL, _extract_protocol, payload);
2003
2004 xpc_release(payload);
2005 return item;
2006 }
2007
2008 static si_item_t *
2009 ds_protocol_bynumber(si_mod_t *si, int number)
2010 {
2011 xpc_object_t payload;
2012 si_item_t *item;
2013
2014 if (!_od_running()) return NULL;
2015
2016 payload = _xpc_query_key_int("number", number);
2017 if (payload == NULL) return NULL;
2018
2019 item = _ds_item(si, CATEGORY_PROTOCOL, "getprotobynumber", NULL, _extract_protocol, payload);
2020
2021 xpc_release(payload);
2022 return item;
2023 }
2024
2025 static si_list_t *
2026 ds_protocol_all(si_mod_t *si)
2027 {
2028 return _ds_list(si, CATEGORY_PROTOCOL, "getprotoent", NULL, _extract_protocol);
2029 }
2030
2031 static si_item_t *
2032 ds_rpc_byname(si_mod_t *si, const char *name)
2033 {
2034 xpc_object_t payload;
2035 si_item_t *item;
2036
2037 if (!_od_running()) return NULL;
2038
2039 payload = _xpc_query_key_string("name", name);
2040 if (payload == NULL) return NULL;
2041
2042 item = _ds_item(si, CATEGORY_RPC, "getrpcbyname", NULL, _extract_rpc, payload);
2043
2044 xpc_release(payload);
2045 return item;
2046 }
2047
2048 static si_item_t *
2049 ds_rpc_bynumber(si_mod_t *si, int number)
2050 {
2051 xpc_object_t payload;
2052 si_item_t *item;
2053
2054 if (!_od_running()) return NULL;
2055
2056 payload = _xpc_query_key_int("number", number);
2057 if (payload == NULL) return NULL;
2058
2059 item = _ds_item(si, CATEGORY_RPC, "getrpcbynumber", NULL, _extract_rpc, payload);
2060
2061 xpc_release(payload);
2062 return item;
2063 }
2064
2065 static si_list_t *
2066 ds_rpc_all(si_mod_t *si)
2067 {
2068 return _ds_list(si, CATEGORY_RPC, "getrpcent", NULL, _extract_rpc);
2069 }
2070
2071 static si_item_t *
2072 ds_fs_byspec(si_mod_t *si, const char *name)
2073 {
2074 xpc_object_t payload;
2075 si_item_t *item;
2076
2077 if (!_od_running()) return NULL;
2078
2079 payload = _xpc_query_key_string("name", name);
2080 if (payload == NULL) return NULL;
2081
2082 item = _ds_item(si, CATEGORY_FS, "getfsbyname", NULL, _extract_fstab, payload);
2083
2084 xpc_release(payload);
2085 return item;
2086 }
2087
2088 static si_list_t *
2089 ds_fs_all(si_mod_t *si)
2090 {
2091 return _ds_list(si, CATEGORY_FS, "getfsent", NULL, _extract_fstab);
2092 }
2093
2094 static si_item_t *
2095 ds_fs_byfile(si_mod_t *si, const char *name)
2096 {
2097 si_item_t *item;
2098 si_list_t *list;
2099 uint32_t i;
2100 struct fstab *f;
2101
2102 if (!_od_running()) return NULL;
2103 if (name == NULL) return NULL;
2104
2105 list = ds_fs_all(si);
2106 if (list == NULL) return NULL;
2107
2108 item = NULL;
2109 for (i = 0; (i < list->count) && (item == NULL); i++)
2110 {
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]);
2113 }
2114
2115 si_list_release(list);
2116 return item;
2117 }
2118
2119 static si_item_t *
2120 ds_mac_byname(si_mod_t *si, const char *name)
2121 {
2122 xpc_object_t payload;
2123 si_item_t *item;
2124
2125 if (!_od_running()) return NULL;
2126
2127 payload = _xpc_query_key_string("name", name);
2128 if (payload == NULL) return NULL;
2129
2130 item = _ds_item(si, CATEGORY_MAC, "getmacbyname", name, _extract_mac_mac, payload);
2131
2132 xpc_release(payload);
2133 return item;
2134 }
2135
2136 static si_item_t *
2137 ds_mac_bymac(si_mod_t *si, const char *mac)
2138 {
2139 xpc_object_t payload;
2140 si_item_t *item;
2141 char *cmac;
2142
2143 if (!_od_running()) return NULL;
2144
2145 cmac = si_standardize_mac_address(mac);
2146 if (cmac == NULL) return NULL;
2147
2148 payload = xpc_dictionary_create(NULL, NULL, 0);
2149 if (payload == NULL) return NULL;
2150
2151 payload = _xpc_query_key_string("mac", cmac);
2152 item = _ds_item(si, CATEGORY_MAC, "gethostbymac", cmac, _extract_mac_name, payload);
2153
2154 free(cmac);
2155 xpc_release(payload);
2156
2157 return item;
2158 }
2159
2160 #pragma mark -
2161
2162 si_mod_t *
2163 si_module_static_ds(void)
2164 {
2165 static const struct si_mod_vtable_s ds_vtable =
2166 {
2167 .sim_is_valid = &_ds_is_valid,
2168
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,
2173
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,
2178
2179 .sim_grouplist = &ds_grouplist,
2180
2181 .sim_netgroup_byname = &ds_netgroup_byname,
2182 .sim_in_netgroup = &ds_in_netgroup,
2183
2184 .sim_alias_byname = &ds_alias_byname,
2185 .sim_alias_all = &ds_alias_all,
2186
2187 /* host lookups not supported */
2188 .sim_host_byname = NULL,
2189 .sim_host_byaddr = NULL,
2190 .sim_host_all = NULL,
2191
2192 .sim_network_byname = &ds_network_byname,
2193 .sim_network_byaddr = &ds_network_byaddr,
2194 .sim_network_all = &ds_network_all,
2195
2196 .sim_service_byname = &ds_service_byname,
2197 .sim_service_byport = &ds_service_byport,
2198 .sim_service_all = &ds_service_all,
2199
2200 .sim_protocol_byname = &ds_protocol_byname,
2201 .sim_protocol_bynumber = &ds_protocol_bynumber,
2202 .sim_protocol_all = &ds_protocol_all,
2203
2204 .sim_rpc_byname = &ds_rpc_byname,
2205 .sim_rpc_bynumber = &ds_rpc_bynumber,
2206 .sim_rpc_all = &ds_rpc_all,
2207
2208 .sim_fs_byspec = &ds_fs_byspec,
2209 .sim_fs_byfile = &ds_fs_byfile,
2210 .sim_fs_all = &ds_fs_all,
2211
2212 .sim_mac_byname = &ds_mac_byname,
2213 .sim_mac_bymac = &ds_mac_bymac,
2214
2215 /* si_mac_all not supported */
2216 .sim_mac_all = NULL,
2217
2218 /* si_addrinfo not supported */
2219 .sim_wants_addrinfo = NULL,
2220 .sim_addrinfo = NULL,
2221 };
2222
2223 static si_mod_t si =
2224 {
2225 .vers = 1,
2226 .refcount = 1,
2227 .flags = SI_MOD_FLAG_STATIC,
2228
2229 .private = NULL,
2230 .vtable = &ds_vtable,
2231 };
2232
2233 static dispatch_once_t once;
2234 dispatch_once(&once, ^{
2235 pthread_key_create(&_ds_serv_cache_key, _ds_serv_cache_free);
2236
2237 si.name = strdup("ds");
2238 ds_si_private_t *pp = calloc(1, sizeof(ds_si_private_t));
2239
2240 if (pp != NULL)
2241 {
2242 pp->notify_token_global = -1;
2243 pp->notify_token_user = -1;
2244 pp->notify_token_group = -1;
2245 pp->notify_token_service = -1;
2246 }
2247
2248 /*
2249 * Don't register for notifications if the cache is disabled.
2250 * notifyd (notably) disables the cache to prevent deadlocks.
2251 */
2252 if (gL1CacheEnabled != 0)
2253 {
2254 /*
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.
2258 */
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));
2263 }
2264
2265 si.private = pp;
2266 });
2267
2268 return &si;
2269 }
2270
2271 #endif /* DS_AVAILABLE */