Libinfo-406.17.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 #ifdef __i386__
57 /* <rdar://problem/10675978> */
58 __attribute__((weak_import))
59 void xpc_dictionary_get_audit_token(xpc_object_t xdict, audit_token_t *token);
60
61 __attribute__((weak_import))
62 xpc_pipe_t xpc_pipe_create(const char *name, uint64_t flags);
63
64 __attribute__((weak_import))
65 void xpc_pipe_invalidate(xpc_pipe_t pipe);
66
67 __attribute__((weak_import))
68 int xpc_pipe_routine(xpc_pipe_t pipe, xpc_object_t message, xpc_object_t *reply);
69 #endif
70
71 #define IPV6_ADDR_LEN 16
72 #define IPV4_ADDR_LEN 4
73
74 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);
75
76 /* notify SPI */
77 uint32_t notify_peek(int token, uint32_t *val);
78
79 typedef struct
80 {
81 int notify_token_global;
82 int notify_token_user;
83 int notify_token_group;
84 int notify_token_service;
85 } ds_si_private_t;
86
87 extern uint32_t gL1CacheEnabled;
88 extern int _si_opendirectory_disabled;
89
90 static pthread_key_t _ds_serv_cache_key = 0;
91 static xpc_pipe_t __od_pipe; /* use accessor only */
92 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
93
94 mach_port_t _ds_port;
95
96 static void
97 _od_fork_child(void)
98 {
99 // re-enable opendirectory interaction since we forked
100 _si_opendirectory_disabled = 0;
101
102 if (__od_pipe != NULL) {
103 xpc_pipe_invalidate(__od_pipe);
104 /* disable release due to 10649340, it will cause a minor leak for each fork without exec */
105 // xpc_release(__od_pipe);
106 __od_pipe = NULL;
107 }
108 _ds_port = MACH_PORT_NULL;
109 pthread_mutex_unlock(&mutex);
110 }
111
112 static void
113 _od_fork_prepare(void)
114 {
115 pthread_mutex_lock(&mutex);
116 }
117
118 static void
119 _od_fork_parent(void)
120 {
121 pthread_mutex_unlock(&mutex);
122 }
123
124 static void
125 _ds_serv_cache_free(void *x)
126 {
127 if (x != NULL) si_item_release(x);
128 }
129
130 void
131 _si_disable_opendirectory(void)
132 {
133 _si_opendirectory_disabled = 1;
134 _ds_port = MACH_PORT_NULL;
135 }
136
137 XPC_RETURNS_RETAINED
138 static xpc_pipe_t
139 _od_xpc_pipe(bool resetPipe)
140 {
141 static dispatch_once_t once;
142 xpc_pipe_t result = NULL;
143
144 #ifdef __i386__
145 if (xpc_pipe_create == NULL) {
146 _si_disable_opendirectory();
147 return NULL;
148 }
149 #endif
150
151 dispatch_once(&once, ^(void) {
152 char *rc_xbs;
153
154 /* if this is a build environment we ignore opendirectoryd */
155 rc_xbs = getenv("RC_XBS");
156 if ((issetugid() == 0) && (rc_xbs != NULL) && (strcmp(rc_xbs, "YES") == 0)) {
157 _si_opendirectory_disabled = 1;
158 return;
159 }
160
161 pthread_atfork(_od_fork_prepare, _od_fork_parent, _od_fork_child);
162 });
163
164 if (_si_opendirectory_disabled == 1) {
165 return NULL;
166 }
167
168 pthread_mutex_lock(&mutex);
169 if (resetPipe) {
170 xpc_release(__od_pipe);
171 __od_pipe = NULL;
172 }
173
174 if (__od_pipe == NULL) {
175 if (!issetugid() && getenv("OD_DEBUG_MODE") != NULL) {
176 __od_pipe = xpc_pipe_create(kODMachLibinfoPortNameDebug, 0);
177 } else {
178 __od_pipe = xpc_pipe_create(kODMachLibinfoPortName, XPC_PIPE_FLAG_PRIVILEGED);
179 }
180 }
181
182 if (__od_pipe != NULL) result = xpc_retain(__od_pipe);
183 pthread_mutex_unlock(&mutex);
184
185 return result;
186 }
187
188 static bool
189 _od_running(void)
190 {
191 xpc_pipe_t pipe;
192
193 pipe = _od_xpc_pipe(false);
194 if (pipe != NULL) {
195 xpc_release(pipe);
196 }
197
198 if (_si_opendirectory_disabled) {
199 return 0;
200 }
201
202 return (pipe != NULL);
203 }
204
205 static void
206 _ds_child(void)
207 {
208 _ds_port = MACH_PORT_NULL;
209 }
210
211 int
212 _ds_running(void)
213 {
214 kern_return_t status;
215 char *od_debug_mode = NULL;
216
217 if (_ds_port != MACH_PORT_NULL) return 1;
218
219 if (_si_opendirectory_disabled) return 0;
220 pthread_atfork(NULL, NULL, _ds_child);
221
222 if (!issetugid()) {
223 od_debug_mode = getenv("OD_DEBUG_MODE");
224 }
225
226 if (od_debug_mode) {
227 status = bootstrap_look_up(bootstrap_port, kDSStdMachDSLookupPortName "_debug", &_ds_port);
228 } else {
229 status = bootstrap_look_up2(bootstrap_port, kDSStdMachDSLookupPortName, &_ds_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
230 }
231 if ((status != BOOTSTRAP_SUCCESS) && (status != BOOTSTRAP_UNKNOWN_SERVICE)) _ds_port = MACH_PORT_NULL;
232
233 return (_ds_port != MACH_PORT_NULL);
234 }
235
236 static bool
237 _valid_token(xpc_object_t reply)
238 {
239 audit_token_t token;
240
241 /*
242 * This should really call audit_token_to_au32,
243 * but that's in libbsm, not in a Libsystem library.
244 */
245 xpc_dictionary_get_audit_token(reply, &token);
246
247 return ((uid_t) token.val[1] == 0);
248 }
249
250 static void
251 _ds_get_validation(si_mod_t *si, uint64_t *a, uint64_t *b, int cat)
252 {
253 ds_si_private_t *pp;
254 uint32_t peek;
255 int status;
256
257 if (si == NULL) return;
258
259 pp = (ds_si_private_t *)si->private;
260 if (pp == NULL) return;
261
262 if (a != NULL)
263 {
264 *a = 0;
265 status = notify_peek(pp->notify_token_global, &peek);
266 if (status == NOTIFY_STATUS_OK) *a = ntohl(peek);
267 }
268
269 if (b != NULL)
270 {
271 *b = 0;
272 peek = 0;
273 status = NOTIFY_STATUS_FAILED;
274
275 if (cat == CATEGORY_USER) status = notify_peek(pp->notify_token_user, &peek);
276 else if (cat == CATEGORY_GROUP) status = notify_peek(pp->notify_token_group, &peek);
277 else if (cat == CATEGORY_GROUPLIST) status = notify_peek(pp->notify_token_group, &peek);
278 else if (cat == CATEGORY_SERVICE) status = notify_peek(pp->notify_token_service, &peek);
279
280 if (status == NOTIFY_STATUS_OK) *b = ntohl(peek);
281 }
282 }
283
284 XPC_RETURNS_RETAINED
285 __private_extern__ xpc_object_t
286 _od_rpc_call(const char *procname, xpc_object_t payload, xpc_pipe_t (*get_pipe)(bool))
287 {
288 xpc_object_t result = NULL;
289 xpc_object_t reply;
290 xpc_pipe_t od_pipe;
291 int retries, rc;
292
293 od_pipe = get_pipe(false);
294 if (od_pipe == NULL) return NULL;
295
296 if (payload == NULL) {
297 payload = xpc_dictionary_create(NULL, NULL, 0);
298 }
299
300 // we nest it for backward compatibility so we can do independent submissions
301 xpc_dictionary_set_string(payload, OD_RPC_NAME, procname);
302 xpc_dictionary_set_int64(payload, OD_RPC_VERSION, 2);
303
304 for (retries = 0; od_pipe != NULL && retries < 2; retries++) {
305 rc = xpc_pipe_routine(od_pipe, payload, &reply);
306 switch (rc) {
307 case EPIPE:
308 xpc_release(od_pipe);
309 od_pipe = get_pipe(true);
310 break;
311
312 case EAGAIN:
313 /* just loop and try to send again */
314 break;
315
316 case 0:
317 if (_valid_token(reply) == true) {
318 result = reply;
319 }
320 /* fall through since we got a valid response */
321
322 default:
323 /* release and NULL the pipe it'll break the loop */
324 xpc_release(od_pipe);
325 od_pipe = NULL;
326 break;
327 }
328 }
329
330 if (od_pipe != NULL) {
331 xpc_release(od_pipe);
332 }
333
334 return result;
335 }
336
337 static si_list_t *
338 _ds_list(si_mod_t *si, int cat, const char *procname, const void *extra, od_extract_t extract)
339 {
340 __block si_list_t *list;
341 uint64_t va, vb;
342 xpc_object_t reply, result;
343
344 if (procname == NULL) return NULL;
345
346 _ds_get_validation(si, &va, &vb, cat);
347
348 list = NULL;
349 reply = _od_rpc_call(procname, NULL, _od_xpc_pipe);
350 if (reply != NULL) {
351 result = xpc_dictionary_get_value(reply, OD_RPC_RESULT);
352 if (result != NULL && xpc_get_type(result) == XPC_TYPE_ARRAY) {
353 xpc_array_apply(result, ^bool(size_t index, xpc_object_t value) {
354 si_item_t *item = extract(si, value, extra, va, vb);
355 list = si_list_add(list, item);
356 si_item_release(item);
357
358 return true;
359 });
360 }
361
362 xpc_release(reply);
363 }
364
365 return list;
366 }
367
368 static si_item_t *
369 _ds_item(si_mod_t *si, int cat, const char *procname, const void *extra, od_extract_t extract, xpc_object_t payload)
370 {
371 xpc_object_t result;
372 uint64_t va, vb;
373 si_item_t *item = NULL;
374
375 if (procname == NULL) return NULL;
376
377 result = _od_rpc_call(procname, payload, _od_xpc_pipe);
378 if (result != NULL) {
379 _ds_get_validation(si, &va, &vb, cat);
380 if (xpc_dictionary_get_int64(result, OD_RPC_ERROR) == 0) {
381 item = extract(si, result, extra, va, vb);
382 }
383
384 xpc_release(result);
385 }
386
387 return item;
388 }
389
390 static int
391 _ds_is_valid(si_mod_t *si, si_item_t *item)
392 {
393 si_mod_t *src;
394 ds_si_private_t *pp;
395 int status;
396 uint32_t oldval, newval;
397
398 if (si == NULL) return 0;
399 if (item == NULL) return 0;
400 if (si->name == NULL) return 0;
401 if (item->src == NULL) return 0;
402
403 pp = (ds_si_private_t *)si->private;
404 if (pp == NULL) return 0;
405
406 src = (si_mod_t *)item->src;
407
408 if (src->name == NULL) return 0;
409 if (string_not_equal(si->name, src->name)) return 0;
410
411 /* check global invalidation */
412 oldval = item->validation_a;
413 newval = -1;
414 status = notify_peek(pp->notify_token_global, &newval);
415 if (status != NOTIFY_STATUS_OK) return 0;
416
417 newval = ntohl(newval);
418 if (oldval != newval) return 0;
419
420 oldval = item->validation_b;
421 newval = -1;
422 if (item->type == CATEGORY_USER) status = notify_peek(pp->notify_token_user, &newval);
423 else if (item->type == CATEGORY_GROUP) status = notify_peek(pp->notify_token_group, &newval);
424 else if (item->type == CATEGORY_SERVICE) status = notify_peek(pp->notify_token_service, &newval);
425 else return 0;
426
427 if (status != NOTIFY_STATUS_OK) return 0;
428
429 newval = ntohl(newval);
430 if (oldval != newval) return 0;
431
432 return 1;
433 }
434
435 static void
436 _free_addr_list(char **l)
437 {
438 int i;
439
440 if (l == NULL) return;
441 for (i = 0; l[i] != NULL; i++) free(l[i]);
442 free(l);
443 }
444
445 /* map ipv4 addresses and append to v6 list */
446 static int
447 _map_v4(char ***v6, uint32_t n6, char **v4, uint32_t n4)
448 {
449 struct in6_addr a6;
450 uint32_t i;
451
452 a6.__u6_addr.__u6_addr32[0] = 0x00000000;
453 a6.__u6_addr.__u6_addr32[1] = 0x00000000;
454 a6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff);
455
456 if (*v6 == NULL)
457 {
458 *v6 = (char **)calloc(n4 + 1, sizeof(char *));
459 }
460 else
461 {
462 *v6 = (char **)reallocf(*v6, (n6 + n4 + 1) * sizeof(char *));
463 }
464
465 if (*v6 == NULL) return -1;
466
467 for (i = 0; i < n4; i++)
468 {
469 (*v6)[n6] = (char *)calloc(1, IPV6_ADDR_LEN);
470 if ((*v6)[n6] == NULL) return -1;
471
472 memcpy(&(a6.__u6_addr.__u6_addr32[3]), v4[i], IPV4_ADDR_LEN);
473 memcpy((*v6)[n6], &(a6.__u6_addr.__u6_addr32[0]), IPV6_ADDR_LEN);
474
475 n6++;
476 }
477
478 return 0;
479 }
480
481 static xpc_object_t
482 _xpc_query_key_string(const char *key, const char *value)
483 {
484 xpc_object_t payload;
485
486 if (value == NULL) return NULL;
487
488 payload = xpc_dictionary_create(NULL, NULL, 0);
489 if (payload == NULL) return NULL;
490
491 xpc_dictionary_set_string(payload, key, value);
492
493 return payload;
494 }
495
496 static xpc_object_t
497 _xpc_query_key_id(const char *key, id_t idValue)
498 {
499 xpc_object_t payload;
500
501 payload = xpc_dictionary_create(NULL, NULL, 0);
502 if (payload == NULL) return NULL;
503
504 xpc_dictionary_set_int64(payload, key, idValue);
505
506 return payload;
507 }
508
509 static xpc_object_t
510 _xpc_query_key_uuid(const char *key, uuid_t uu)
511 {
512 xpc_object_t payload;
513
514 payload = xpc_dictionary_create(NULL, NULL, 0);
515 if (payload == NULL) return NULL;
516
517 xpc_dictionary_set_uuid(payload, key, uu);
518
519 return payload;
520 }
521
522 static xpc_object_t
523 _xpc_query_key_int(const char *key, int64_t intValue)
524 {
525 xpc_object_t payload;
526
527 payload = xpc_dictionary_create(NULL, NULL, 0);
528 if (payload == NULL) return NULL;
529
530 xpc_dictionary_set_int64(payload, key, intValue);
531
532 return payload;
533 }
534
535 #pragma mark -
536
537 static char **
538 _extract_array(xpc_object_t reply, const char *key, unsigned int *len)
539 {
540 xpc_object_t xpc_array;
541 char **result;
542
543 xpc_array = xpc_dictionary_get_value(reply, key);
544 if (xpc_array == NULL || xpc_get_type(xpc_array) != XPC_TYPE_ARRAY) {
545 return calloc(1, sizeof(*result));
546 }
547
548 result = calloc(xpc_array_get_count(xpc_array) + 1, sizeof(*result));
549 if (result == NULL) {
550 return NULL;
551 }
552
553 if (len != NULL) {
554 /* include trailing NULL */
555 (*len) = xpc_array_get_count(xpc_array) + 1;
556 }
557
558 xpc_array_apply(xpc_array, ^_Bool(size_t idx, xpc_object_t value) {
559 result[idx] = (char *) xpc_string_get_string_ptr(value);
560 return true;
561 });
562
563 return result;
564 }
565
566 static const char *
567 _extract_string(xpc_object_t reply, const char *key)
568 {
569 xpc_object_t value = xpc_dictionary_get_value(reply, key);
570 xpc_type_t type;
571 const char *result = NULL;
572
573 if (value == NULL) {
574 return "";
575 }
576
577 type = xpc_get_type(value);
578 if (type == XPC_TYPE_STRING) {
579 result = xpc_string_get_string_ptr(value);
580 } else if (type == XPC_TYPE_ARRAY && xpc_array_get_count(value) != 0) {
581 result = xpc_array_get_string(value, 0);
582 }
583
584 if (result == NULL) {
585 result = "";
586 }
587
588 return result;
589 }
590
591 static uint32_t
592 _extract_uint32(xpc_object_t reply, const char *key)
593 {
594 xpc_object_t value = xpc_dictionary_get_value(reply, key);
595 xpc_type_t type;
596 uint32_t result;
597
598 if (value == NULL) {
599 return 0;
600 }
601
602 type = xpc_get_type(value);
603 if (type == XPC_TYPE_ARRAY && xpc_array_get_count(value) != 0) {
604 value = xpc_array_get_value(value, 0);
605 type = xpc_get_type(value);
606 }
607
608 if (type == XPC_TYPE_STRING) {
609 result = (int) strtol(xpc_string_get_string_ptr(value), NULL, 10);
610 } else if (type == XPC_TYPE_INT64) {
611 result = (uint32_t) xpc_int64_get_value(value);
612 } else if (type == XPC_TYPE_BOOL) {
613 result = xpc_bool_get_value(value);
614 } else {
615 result = 0;
616 }
617
618 return result;
619 }
620
621 static si_item_t *
622 _extract_user(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
623 {
624 struct passwd tmp;
625
626 if (si == NULL) return NULL;
627 if (reply == NULL) return NULL;
628
629 tmp.pw_name = (char *) _extract_string(reply, "pw_name");
630 tmp.pw_passwd = (char *) _extract_string(reply, "pw_passwd");
631 tmp.pw_uid = (uid_t) _extract_uint32(reply, "pw_uid");
632 tmp.pw_gid = (gid_t) _extract_uint32(reply, "pw_gid");
633 tmp.pw_change = (time_t) _extract_uint32(reply, "pw_change");
634 tmp.pw_expire = (time_t) _extract_uint32(reply, "pw_expire");
635 tmp.pw_class = (char *) _extract_string(reply, "pw_class");
636 tmp.pw_gecos = (char *) _extract_string(reply, "pw_gecos");
637 tmp.pw_dir = (char *) _extract_string(reply, "pw_dir");
638 tmp.pw_shell = (char *) _extract_string(reply, "pw_shell");
639
640 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);
641 }
642
643 static si_item_t *
644 _extract_group(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
645 {
646 si_item_t *item;
647 struct group tmp;
648
649 if (si == NULL) return NULL;
650 if (reply == NULL) return NULL;
651
652 tmp.gr_name = (char *) _extract_string(reply, "gr_name");
653 tmp.gr_passwd = (char *) _extract_string(reply, "gr_passwd");
654 tmp.gr_gid = (gid_t) _extract_uint32(reply, "gr_gid");
655 tmp.gr_mem = _extract_array(reply, "gr_mem", NULL);
656
657 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);
658
659 if (tmp.gr_mem != NULL) {
660 free(tmp.gr_mem); /* have to free because it's allocated */
661 }
662
663 return item;
664 }
665
666 static si_item_t *
667 _extract_netgroup(si_mod_t *si, xpc_object_t reply, const void *ignored, uint64_t valid_global, uint64_t valid_cat)
668 {
669 const char *host, *user, *domain;
670
671 if (si == NULL) return NULL;
672 if (reply == NULL) return NULL;
673
674 host = _extract_string(reply, "host");
675 user = _extract_string(reply, "user");
676 domain = _extract_string(reply, "domain");
677
678 return (si_item_t *)LI_ils_create("L4488sss", (unsigned long)si, CATEGORY_NETGROUP, 1, valid_global, valid_cat, host, user, domain);
679 }
680
681 static si_item_t *
682 _extract_alias(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
683 {
684 struct aliasent tmp;
685 si_item_t *item;
686
687 if (si == NULL) return NULL;
688 if (reply == NULL) return NULL;
689
690 tmp.alias_name = (char *) _extract_string(reply, "alias_name");
691 tmp.alias_local = _extract_uint32(reply, "alias_local");
692 tmp.alias_members = _extract_array(reply, "alias_members", &tmp.alias_members_len);
693
694 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);
695
696 if (tmp.alias_members != NULL) {
697 free(tmp.alias_members);
698 }
699
700 return item;
701 }
702
703 static si_item_t *
704 _extract_network(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
705 {
706 struct netent tmp;
707 si_item_t *item;
708
709 if (si == NULL) return NULL;
710 if (reply == NULL) return NULL;
711
712 tmp.n_name = (char *) _extract_string(reply, "n_name");
713 tmp.n_aliases = _extract_array(reply, "n_aliases", NULL);
714 tmp.n_net = _extract_uint32(reply, "n_net");
715 tmp.n_addrtype = AF_INET; /* opendirectoryd doesn't return this value, only AF_INET is supported */
716
717 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);
718
719 if (tmp.n_aliases != NULL) {
720 free(tmp.n_aliases);
721 }
722
723 return item;
724 }
725
726 static si_item_t *
727 _extract_service(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
728 {
729 struct servent tmp;
730 si_item_t *item;
731
732 if (si == NULL) return NULL;
733 if (reply == NULL) return NULL;
734
735 tmp.s_name = (char *) _extract_string(reply, "s_name");
736 tmp.s_aliases = _extract_array(reply, "s_aliases", NULL);
737 tmp.s_port = (unsigned int) htons(_extract_uint32(reply, "s_port"));
738 tmp.s_proto = (char *) _extract_string(reply, "s_proto");
739
740 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);
741
742 if (tmp.s_aliases != NULL) {
743 free(tmp.s_aliases);
744 }
745
746 return item;
747 }
748
749 static si_item_t *
750 _extract_protocol(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
751 {
752 struct protoent tmp;
753 si_item_t *item;
754
755 if (si == NULL) return NULL;
756 if (reply == NULL) return NULL;
757
758 tmp.p_name = (char *) _extract_string(reply, "p_name");
759 tmp.p_proto = (int) _extract_uint32(reply, "p_proto");
760 tmp.p_aliases = _extract_array(reply, "p_aliases", NULL);
761
762 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);
763 if (tmp.p_aliases != NULL) {
764 free(tmp.p_aliases);
765 }
766
767 return item;
768 }
769
770 static si_item_t *
771 _extract_rpc(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
772 {
773 struct rpcent tmp;
774 si_item_t *item;
775
776 if (si == NULL) return NULL;
777 if (reply == NULL) return NULL;
778
779 tmp.r_name = (char *) _extract_string(reply, "r_name");
780 tmp.r_number = (int) _extract_uint32(reply, "r_number");
781 tmp.r_aliases = _extract_array(reply, "r_aliases", NULL);
782
783 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);
784 if (tmp.r_aliases != NULL) {
785 free(tmp.r_aliases);
786 }
787
788 return item;
789 }
790
791 static si_item_t *
792 _extract_fstab(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat)
793 {
794 struct fstab tmp;
795
796 if (si == NULL) return NULL;
797 if (reply == NULL) return NULL;
798
799 tmp.fs_file = (char *) _extract_string(reply, "fs_file");
800 if (tmp.fs_file == NULL) return NULL;
801
802 tmp.fs_spec = (char *) _extract_string(reply, "fs_spec");
803 tmp.fs_freq = _extract_uint32(reply, "fs_freq");
804 tmp.fs_passno = _extract_uint32(reply, "fs_passno");
805 tmp.fs_mntops = (char *) _extract_string(reply, "fs_mntops");
806 tmp.fs_type = (char *) _extract_string(reply, "fs_type");
807 tmp.fs_vfstype = (char *) _extract_string(reply, "fs_vfstype");
808
809 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);
810 }
811
812 static si_item_t *
813 _extract_mac_mac(si_mod_t *si, xpc_object_t reply, const void *extra, uint64_t valid_global, uint64_t valid_cat)
814 {
815 const char *value;
816 char *cmac;
817 si_item_t *out;
818
819 if (si == NULL) return NULL;
820 if (reply == NULL) return NULL;
821 if (extra == NULL) return NULL;
822
823 value = _extract_string(reply, "mac");
824 if (value == NULL || value[0] == '\0') return NULL;
825
826 cmac = si_standardize_mac_address(value);
827 if (cmac == NULL) return NULL;
828
829 out = (si_item_t *)LI_ils_create("L4488ss", (unsigned long)si, CATEGORY_MAC, 1, valid_global, valid_cat, extra, cmac);
830
831 free(cmac);
832
833 return out;
834 }
835
836 static si_item_t *
837 _extract_mac_name(si_mod_t *si, xpc_object_t reply, const void *extra, uint64_t valid_global, uint64_t valid_cat)
838 {
839 const char *name;
840 si_item_t *out;
841
842 if (si == NULL) return NULL;
843 if (reply == NULL) return NULL;
844 if (extra == NULL) return NULL;
845
846 name = _extract_string(reply, "name");
847
848 out = (si_item_t *)LI_ils_create("L4488ss", (unsigned long)si, CATEGORY_MAC, 1, valid_global, valid_cat, name, extra);
849 return out;
850 }
851
852 #pragma mark -
853
854 static si_item_t *
855 ds_user_byname(si_mod_t *si, const char *name)
856 {
857 xpc_object_t payload;
858 si_item_t *item;
859
860 if (!_od_running()) return NULL;
861
862 payload = _xpc_query_key_string("name", name);
863 if (payload == NULL) return NULL;
864
865 item = _ds_item(si, CATEGORY_USER, "getpwnam", NULL, _extract_user, payload);
866
867 xpc_release(payload);
868 return item;
869 }
870
871 static si_item_t *
872 ds_user_byuid(si_mod_t *si, uid_t uid)
873 {
874 xpc_object_t payload;
875 si_item_t *item;
876
877 if (!_od_running()) return NULL;
878
879 payload = _xpc_query_key_id("uid", uid);
880 if (payload == NULL) return NULL;
881
882 item = _ds_item(si, CATEGORY_USER, "getpwuid", NULL, _extract_user, payload);
883
884 xpc_release(payload);
885 return item;
886 }
887
888 static si_item_t *
889 ds_user_byuuid(si_mod_t *si, uuid_t uuid)
890 {
891 xpc_object_t payload;
892 si_item_t *item;
893
894 if (!_od_running()) return NULL;
895
896 payload = _xpc_query_key_uuid("uuid", uuid);
897 if (payload == NULL) return NULL;
898
899 item = _ds_item(si, CATEGORY_USER, "getpwuuid", NULL, _extract_user, payload);
900
901 xpc_release(payload);
902 return item;
903 }
904
905 static si_list_t *
906 ds_user_all(si_mod_t *si)
907 {
908 return _ds_list(si, CATEGORY_USER, "getpwent", NULL, _extract_user);
909 }
910
911 static si_item_t *
912 ds_group_byname(si_mod_t *si, const char *name)
913 {
914 xpc_object_t payload;
915 si_item_t *item;
916
917 if (!_od_running()) return NULL;
918
919 payload = _xpc_query_key_string("name", name);
920 if (payload == NULL) return NULL;
921
922 item = _ds_item(si, CATEGORY_GROUP, "getgrnam", NULL, _extract_group, payload);
923
924 xpc_release(payload);
925 return item;
926 }
927
928 static si_item_t *
929 ds_group_bygid(si_mod_t *si, gid_t gid)
930 {
931 xpc_object_t payload;
932 si_item_t *item;
933
934 if (!_od_running()) return NULL;
935
936 payload = _xpc_query_key_id("gid", gid);
937 if (payload == NULL) return NULL;
938
939 item = _ds_item(si, CATEGORY_GROUP, "getgrgid", NULL, _extract_group, payload);
940
941 xpc_release(payload);
942 return item;
943 }
944
945 static si_item_t *
946 ds_group_byuuid(si_mod_t *si, uuid_t uuid)
947 {
948 xpc_object_t payload;
949 si_item_t *item;
950
951 if (!_od_running()) return NULL;
952
953 payload = _xpc_query_key_uuid("uuid", uuid);
954 if (payload == NULL) return NULL;
955
956 item = _ds_item(si, CATEGORY_GROUP, "getgruuid", NULL, _extract_group, payload);
957
958 xpc_release(payload);
959 return item;
960 }
961
962 static si_list_t *
963 ds_group_all(si_mod_t *si)
964 {
965 if (!_od_running()) return NULL;
966 return _ds_list(si, CATEGORY_GROUP, "getgrent", NULL, _extract_group);
967 }
968
969 static si_item_t *
970 ds_grouplist(si_mod_t *si, const char *name, uint32_t ngroups)
971 {
972 xpc_object_t payload, reply;
973 si_item_t *item = NULL;
974
975 if (!_od_running()) return NULL;
976 if (name == NULL) return NULL;
977
978 payload = xpc_dictionary_create(NULL, NULL, 0);
979 if (payload == NULL) return NULL;
980
981 xpc_dictionary_set_string(payload, "name", name);
982 xpc_dictionary_set_int64(payload, "ngroups", ngroups);
983
984 reply = _od_rpc_call("getgrouplist", payload, _od_xpc_pipe);
985 if (reply != NULL) {
986 size_t gidptrsz;
987 const gid_t *gidptr = xpc_dictionary_get_data(reply, "groups", &gidptrsz);
988 int32_t count;
989 uint64_t va, vb;
990
991 _ds_get_validation(si, &va, &vb, CATEGORY_GROUPLIST);
992
993 /* see what we were sent */
994 count = _extract_uint32(reply, "count");
995 if (count != 0) {
996 item = (si_item_t *)LI_ils_create("L4488s4@", (unsigned long)si, CATEGORY_GROUPLIST, 1, va, vb, name, count,
997 gidptrsz, gidptr);
998 }
999
1000 xpc_release(reply);
1001 }
1002
1003 xpc_release(payload);
1004
1005 return item;
1006 }
1007
1008 static si_list_t *
1009 ds_netgroup_byname(si_mod_t *si, const char *name)
1010 {
1011 xpc_object_t payload;
1012 si_list_t *list = NULL;
1013 si_item_t *item;
1014
1015 if (!_od_running()) return NULL;
1016
1017 payload = _xpc_query_key_string("netgroup", name);
1018 if (payload == NULL) return NULL;
1019
1020 item = _ds_item(si, CATEGORY_NETGROUP, "getnetgrent", NULL, _extract_netgroup, payload);
1021 if (item != NULL) {
1022 list = si_list_add(list, item);
1023 si_item_release(item);
1024 }
1025
1026 xpc_release(payload);
1027
1028 return list;
1029 }
1030
1031 static int
1032 ds_in_netgroup(si_mod_t *si, const char *group, const char *host, const char *user, const char *domain)
1033 {
1034 xpc_object_t payload, reply;
1035 int is_innetgr;
1036
1037 if (!_od_running()) return 0;
1038
1039 payload = xpc_dictionary_create(NULL, NULL, 0);
1040 if (payload == NULL) return 0;
1041
1042 xpc_dictionary_set_string(payload, "netgroup", (group ? group : ""));
1043 xpc_dictionary_set_string(payload, "host", (host ? host : ""));
1044 xpc_dictionary_set_string(payload, "user", (user ? user : ""));
1045 xpc_dictionary_set_string(payload, "domain", (domain ? domain : ""));
1046
1047 reply = _od_rpc_call("innetgr", payload, _od_xpc_pipe);
1048 if (reply != NULL) {
1049 is_innetgr = xpc_dictionary_get_bool(reply, OD_RPC_RESULT);
1050 xpc_release(reply);
1051 } else {
1052 is_innetgr = 0;
1053 }
1054
1055 xpc_release(payload);
1056
1057 return is_innetgr;
1058 }
1059
1060 static si_item_t *
1061 ds_alias_byname(si_mod_t *si, const char *name)
1062 {
1063 xpc_object_t payload;
1064 si_item_t *item;
1065
1066 if (!_od_running()) return NULL;
1067
1068 payload = _xpc_query_key_string("name", name);
1069 if (payload == NULL) return NULL;
1070
1071 item = _ds_item(si, CATEGORY_ALIAS, "alias_getbyname", NULL, _extract_alias, payload);
1072
1073 xpc_release(payload);
1074 return item;
1075 }
1076
1077 static si_list_t *
1078 ds_alias_all(si_mod_t *si)
1079 {
1080 if (!_od_running()) return NULL;
1081 return _ds_list(si, CATEGORY_ALIAS, "alias_getent", NULL, _extract_alias);
1082 }
1083
1084 static si_item_t *
1085 ds_network_byname(si_mod_t *si, const char *name)
1086 {
1087 xpc_object_t payload;
1088 si_item_t *item;
1089
1090 if (!_od_running()) return NULL;
1091
1092 payload = _xpc_query_key_string("name", name);
1093 if (payload == NULL) return NULL;
1094
1095 item = _ds_item(si, CATEGORY_NETWORK, "getnetbyname", NULL, _extract_network, payload);
1096
1097 xpc_release(payload);
1098 return item;
1099 }
1100
1101 static si_item_t *
1102 ds_network_byaddr(si_mod_t *si, uint32_t addr)
1103 {
1104 unsigned char f1, f2, f3;
1105 char val[64];
1106 xpc_object_t payload;
1107 si_item_t *item;
1108
1109 if (!_od_running()) return NULL;
1110
1111 f1 = addr & 0xff;
1112 addr >>= 8;
1113 f2 = addr & 0xff;
1114 addr >>= 8;
1115 f3 = addr & 0xff;
1116
1117 if (f3 != 0) snprintf(val, sizeof(val), "%u.%u.%u", f3, f2, f1);
1118 else if (f2 != 0) snprintf(val, sizeof(val), "%u.%u", f2, f1);
1119 else snprintf(val, sizeof(val), "%u", f1);
1120
1121 payload = _xpc_query_key_string("net", val);
1122 if (payload == NULL) return NULL;
1123
1124 item = _ds_item(si, CATEGORY_NETWORK, "getnetbyaddr", NULL, _extract_network, payload);
1125
1126 xpc_release(payload);
1127 return item;
1128 }
1129
1130 static si_list_t *
1131 ds_network_all(si_mod_t *si)
1132 {
1133 if (!_od_running()) return NULL;
1134 return _ds_list(si, CATEGORY_NETWORK, "getnetent", NULL, _extract_network);
1135 }
1136
1137 static si_item_t *
1138 ds_service_byname(si_mod_t *si, const char *name, const char *proto)
1139 {
1140 xpc_object_t payload;
1141 si_item_t *item;
1142 struct servent *s;
1143
1144 if (!_od_running()) return NULL;
1145 if (name == NULL) name = "";
1146 if (proto == NULL) proto = "";
1147
1148 /* Check our local service cache (see ds_addrinfo). */
1149 item = pthread_getspecific(_ds_serv_cache_key);
1150 if (item != NULL)
1151 {
1152 s = (struct servent *)((uintptr_t)item + sizeof(si_item_t));
1153 if (string_equal(name, s->s_name)) return si_item_retain(item);
1154 }
1155
1156 payload = xpc_dictionary_create(NULL, NULL, 0);
1157 if (payload == NULL) return NULL;
1158
1159 xpc_dictionary_set_string(payload, "name", name);
1160 xpc_dictionary_set_string(payload, "proto", proto);
1161
1162 item = _ds_item(si, CATEGORY_SERVICE, "getservbyname", NULL, _extract_service, payload);
1163
1164 xpc_release(payload);
1165
1166 return item;
1167 }
1168
1169 static si_item_t *
1170 ds_service_byport(si_mod_t *si, int port, const char *proto)
1171 {
1172 xpc_object_t payload;
1173 si_item_t *item;
1174
1175 if (!_od_running()) return NULL;
1176
1177 payload = xpc_dictionary_create(NULL, NULL, 0);
1178 if (payload == NULL) return NULL;
1179
1180 /* swap to native order, API passes network order */
1181 xpc_dictionary_set_int64(payload, "port", ntohs(port));
1182 xpc_dictionary_set_string(payload, "proto", (proto ? proto : ""));
1183
1184 item = _ds_item(si, CATEGORY_SERVICE, "getservbyport", NULL, _extract_service, payload);
1185
1186 xpc_release(payload);
1187
1188 return item;
1189 }
1190
1191 static si_list_t *
1192 ds_service_all(si_mod_t *si)
1193 {
1194 if (!_od_running()) return NULL;
1195 return _ds_list(si, CATEGORY_SERVICE, "getservent", NULL, _extract_service);
1196 }
1197
1198 static si_item_t *
1199 ds_protocol_byname(si_mod_t *si, const char *name)
1200 {
1201 xpc_object_t payload;
1202 si_item_t *item;
1203
1204 if (!_od_running()) return NULL;
1205
1206 payload = _xpc_query_key_string("name", name);
1207 if (payload == NULL) return NULL;
1208
1209 item = _ds_item(si, CATEGORY_PROTOCOL, "getprotobyname", NULL, _extract_protocol, payload);
1210
1211 xpc_release(payload);
1212 return item;
1213 }
1214
1215 static si_item_t *
1216 ds_protocol_bynumber(si_mod_t *si, int number)
1217 {
1218 xpc_object_t payload;
1219 si_item_t *item;
1220
1221 if (!_od_running()) return NULL;
1222
1223 payload = _xpc_query_key_int("number", number);
1224 if (payload == NULL) return NULL;
1225
1226 item = _ds_item(si, CATEGORY_PROTOCOL, "getprotobynumber", NULL, _extract_protocol, payload);
1227
1228 xpc_release(payload);
1229 return item;
1230 }
1231
1232 static si_list_t *
1233 ds_protocol_all(si_mod_t *si)
1234 {
1235 return _ds_list(si, CATEGORY_PROTOCOL, "getprotoent", NULL, _extract_protocol);
1236 }
1237
1238 static si_item_t *
1239 ds_rpc_byname(si_mod_t *si, const char *name)
1240 {
1241 xpc_object_t payload;
1242 si_item_t *item;
1243
1244 if (!_od_running()) return NULL;
1245
1246 payload = _xpc_query_key_string("name", name);
1247 if (payload == NULL) return NULL;
1248
1249 item = _ds_item(si, CATEGORY_RPC, "getrpcbyname", NULL, _extract_rpc, payload);
1250
1251 xpc_release(payload);
1252 return item;
1253 }
1254
1255 static si_item_t *
1256 ds_rpc_bynumber(si_mod_t *si, int number)
1257 {
1258 xpc_object_t payload;
1259 si_item_t *item;
1260
1261 if (!_od_running()) return NULL;
1262
1263 payload = _xpc_query_key_int("number", number);
1264 if (payload == NULL) return NULL;
1265
1266 item = _ds_item(si, CATEGORY_RPC, "getrpcbynumber", NULL, _extract_rpc, payload);
1267
1268 xpc_release(payload);
1269 return item;
1270 }
1271
1272 static si_list_t *
1273 ds_rpc_all(si_mod_t *si)
1274 {
1275 return _ds_list(si, CATEGORY_RPC, "getrpcent", NULL, _extract_rpc);
1276 }
1277
1278 static si_item_t *
1279 ds_fs_byspec(si_mod_t *si, const char *name)
1280 {
1281 xpc_object_t payload;
1282 si_item_t *item;
1283
1284 if (!_od_running()) return NULL;
1285
1286 payload = _xpc_query_key_string("name", name);
1287 if (payload == NULL) return NULL;
1288
1289 item = _ds_item(si, CATEGORY_FS, "getfsbyname", NULL, _extract_fstab, payload);
1290
1291 xpc_release(payload);
1292 return item;
1293 }
1294
1295 static si_list_t *
1296 ds_fs_all(si_mod_t *si)
1297 {
1298 return _ds_list(si, CATEGORY_FS, "getfsent", NULL, _extract_fstab);
1299 }
1300
1301 static si_item_t *
1302 ds_fs_byfile(si_mod_t *si, const char *name)
1303 {
1304 si_item_t *item;
1305 si_list_t *list;
1306 uint32_t i;
1307 struct fstab *f;
1308
1309 if (!_od_running()) return NULL;
1310 if (name == NULL) return NULL;
1311
1312 list = ds_fs_all(si);
1313 if (list == NULL) return NULL;
1314
1315 item = NULL;
1316 for (i = 0; (i < list->count) && (item == NULL); i++)
1317 {
1318 f = (struct fstab *)((uintptr_t)(list->entry[i]) + sizeof(si_item_t));
1319 if (string_equal(name, f->fs_file)) item = si_item_retain(list->entry[i]);
1320 }
1321
1322 si_list_release(list);
1323 return item;
1324 }
1325
1326 static si_item_t *
1327 ds_mac_byname(si_mod_t *si, const char *name)
1328 {
1329 xpc_object_t payload;
1330 si_item_t *item;
1331
1332 if (!_od_running()) return NULL;
1333
1334 payload = _xpc_query_key_string("name", name);
1335 if (payload == NULL) return NULL;
1336
1337 item = _ds_item(si, CATEGORY_MAC, "getmacbyname", name, _extract_mac_mac, payload);
1338
1339 xpc_release(payload);
1340 return item;
1341 }
1342
1343 static si_item_t *
1344 ds_mac_bymac(si_mod_t *si, const char *mac)
1345 {
1346 xpc_object_t payload;
1347 si_item_t *item;
1348 char *cmac;
1349
1350 if (!_od_running()) return NULL;
1351
1352 cmac = si_standardize_mac_address(mac);
1353 if (cmac == NULL) return NULL;
1354
1355 payload = xpc_dictionary_create(NULL, NULL, 0);
1356 if (payload == NULL) return NULL;
1357
1358 payload = _xpc_query_key_string("mac", cmac);
1359 item = _ds_item(si, CATEGORY_MAC, "gethostbymac", cmac, _extract_mac_name, payload);
1360
1361 free(cmac);
1362 xpc_release(payload);
1363
1364 return item;
1365 }
1366
1367 #pragma mark -
1368
1369 si_mod_t *
1370 si_module_static_ds(void)
1371 {
1372 static const struct si_mod_vtable_s ds_vtable =
1373 {
1374 .sim_is_valid = &_ds_is_valid,
1375
1376 .sim_user_byname = &ds_user_byname,
1377 .sim_user_byuid = &ds_user_byuid,
1378 .sim_user_byuuid = &ds_user_byuuid,
1379 .sim_user_all = &ds_user_all,
1380
1381 .sim_group_byname = &ds_group_byname,
1382 .sim_group_bygid = &ds_group_bygid,
1383 .sim_group_byuuid = &ds_group_byuuid,
1384 .sim_group_all = &ds_group_all,
1385
1386 .sim_grouplist = &ds_grouplist,
1387
1388 .sim_netgroup_byname = &ds_netgroup_byname,
1389 .sim_in_netgroup = &ds_in_netgroup,
1390
1391 .sim_alias_byname = &ds_alias_byname,
1392 .sim_alias_all = &ds_alias_all,
1393
1394 /* host lookups not supported */
1395 .sim_host_byname = NULL,
1396 .sim_host_byaddr = NULL,
1397 .sim_host_all = NULL,
1398
1399 .sim_network_byname = &ds_network_byname,
1400 .sim_network_byaddr = &ds_network_byaddr,
1401 .sim_network_all = &ds_network_all,
1402
1403 .sim_service_byname = &ds_service_byname,
1404 .sim_service_byport = &ds_service_byport,
1405 .sim_service_all = &ds_service_all,
1406
1407 .sim_protocol_byname = &ds_protocol_byname,
1408 .sim_protocol_bynumber = &ds_protocol_bynumber,
1409 .sim_protocol_all = &ds_protocol_all,
1410
1411 .sim_rpc_byname = &ds_rpc_byname,
1412 .sim_rpc_bynumber = &ds_rpc_bynumber,
1413 .sim_rpc_all = &ds_rpc_all,
1414
1415 .sim_fs_byspec = &ds_fs_byspec,
1416 .sim_fs_byfile = &ds_fs_byfile,
1417 .sim_fs_all = &ds_fs_all,
1418
1419 .sim_mac_byname = &ds_mac_byname,
1420 .sim_mac_bymac = &ds_mac_bymac,
1421
1422 /* si_mac_all not supported */
1423 .sim_mac_all = NULL,
1424
1425 /* si_addrinfo not supported */
1426 .sim_wants_addrinfo = NULL,
1427 .sim_addrinfo = NULL,
1428 };
1429
1430 static si_mod_t si =
1431 {
1432 .vers = 1,
1433 .refcount = 1,
1434 .flags = SI_MOD_FLAG_STATIC,
1435
1436 .private = NULL,
1437 .vtable = &ds_vtable,
1438 };
1439
1440 static dispatch_once_t once;
1441 dispatch_once(&once, ^{
1442 pthread_key_create(&_ds_serv_cache_key, _ds_serv_cache_free);
1443
1444 si.name = strdup("ds");
1445 ds_si_private_t *pp = calloc(1, sizeof(ds_si_private_t));
1446
1447 if (pp != NULL)
1448 {
1449 pp->notify_token_global = -1;
1450 pp->notify_token_user = -1;
1451 pp->notify_token_group = -1;
1452 pp->notify_token_service = -1;
1453 }
1454
1455 /*
1456 * Don't register for notifications if the cache is disabled.
1457 * notifyd (notably) disables the cache to prevent deadlocks.
1458 */
1459 if (gL1CacheEnabled != 0)
1460 {
1461 /*
1462 * Errors in registering for cache invalidation notifications are ignored.
1463 * If there are failures, the tokens remain set to -1 which just causes
1464 * cached items to be invalidated.
1465 */
1466 notify_register_check(kNotifyDSCacheInvalidation, &(pp->notify_token_global));
1467 notify_register_check(kNotifyDSCacheInvalidationUser, &(pp->notify_token_user));
1468 notify_register_check(kNotifyDSCacheInvalidationGroup, &(pp->notify_token_group));
1469 notify_register_check(kNotifyDSCacheInvalidationService, &(pp->notify_token_service));
1470 }
1471
1472 si.private = pp;
1473 });
1474
1475 return &si;
1476 }
1477
1478 #endif /* DS_AVAILABLE */