Libinfo-391.tar.gz
[apple/libinfo.git] / lookup.subproj / ds_module.c
1 /*
2 * Copyright (c) 2008-2010 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 #include <mach/mach.h>
25
26 kern_return_t
27 libinfoDSmig_do_Response_async(mach_port_t server, char *reply, mach_msg_type_number_t replyCnt, vm_offset_t ooreply, mach_msg_type_number_t ooreplyCnt, mach_vm_address_t callbackAddr, security_token_t servertoken)
28 {
29 return KERN_SUCCESS;
30 }
31
32 #ifdef DS_AVAILABLE
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <time.h>
39 #include <errno.h>
40 #include <arpa/inet.h>
41 #include <sys/stat.h>
42 #include <ils.h>
43 #include "kvbuf.h"
44 #include <pwd.h>
45 #include <grp.h>
46 #include <fstab.h>
47 #include <netdb.h>
48 #include <notify.h>
49 #include <notify_keys.h>
50 #include <si_data.h>
51 #include <si_module.h>
52 #include <netdb_async.h>
53 #include <net/if.h>
54 #include <servers/bootstrap.h>
55 #include <bootstrap_priv.h>
56 #include "DSlibinfoMIG.h"
57 #include "DSmemberdMIG.h"
58 #ifdef DEBUG
59 #include <asl.h>
60 #endif
61
62 #define SOCK_UNSPEC 0
63 #define IPPROTO_UNSPEC 0
64
65 #define IPV6_ADDR_LEN 16
66 #define IPV4_ADDR_LEN 4
67
68 #define WANT_NOTHING 0
69 #define WANT_A4_ONLY 1
70 #define WANT_A6_ONLY 2
71 #define WANT_A6_PLUS_MAPPED_A4 3
72 #define WANT_MAPPED_A4_ONLY 4
73
74 /* ONLY TO BE USED BY getipv6nodebyaddr */
75 #define WANT_A6_OR_MAPPED_A4_IF_NO_A6 5
76
77 #define MAX_LOOKUP_ATTEMPTS 10
78
79 #define INET_NTOP_AF_INET_OFFSET 4
80 #define INET_NTOP_AF_INET6_OFFSET 8
81
82 mach_port_t _ds_port;
83 mach_port_t _mbr_port;
84
85 extern uint32_t gL1CacheEnabled;
86
87 static pthread_key_t _ds_serv_cache_key = 0;
88
89 static void
90 _ds_child(void)
91 {
92 _ds_port = MACH_PORT_NULL;
93 _mbr_port = MACH_PORT_NULL;
94 }
95
96 static int _si_opendirectory_disabled;
97
98 void
99 _si_disable_opendirectory(void)
100 {
101 _si_opendirectory_disabled = 1;
102 _ds_port = MACH_PORT_NULL;
103 _mbr_port = MACH_PORT_NULL;
104 }
105
106 int
107 _ds_running(void)
108 {
109 kern_return_t status;
110 char *od_debug_mode = NULL;
111
112 if (_ds_port != MACH_PORT_NULL) return 1;
113
114 if (_si_opendirectory_disabled) return 0;
115 pthread_atfork(NULL, NULL, _ds_child);
116
117 if (!issetugid()) {
118 od_debug_mode = getenv("OD_DEBUG_MODE");
119 }
120
121 if (od_debug_mode) {
122 status = bootstrap_look_up(bootstrap_port, kDSStdMachDSLookupPortName "_debug", &_ds_port);
123 } else {
124 status = bootstrap_look_up2(bootstrap_port, kDSStdMachDSLookupPortName,
125 &_ds_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
126 }
127 if ((status != BOOTSTRAP_SUCCESS) && (status != BOOTSTRAP_UNKNOWN_SERVICE)) _ds_port = MACH_PORT_NULL;
128
129 if (od_debug_mode) {
130 status = bootstrap_look_up(bootstrap_port, kDSStdMachDSMembershipPortName "_debug", &_mbr_port);
131 } else {
132 status = bootstrap_look_up2(bootstrap_port, kDSStdMachDSMembershipPortName,
133 &_mbr_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
134 }
135 if ((status != BOOTSTRAP_SUCCESS) && (status != BOOTSTRAP_UNKNOWN_SERVICE)) _mbr_port = MACH_PORT_NULL;
136
137 return (_ds_port != MACH_PORT_NULL);
138 }
139
140 static void
141 _ds_serv_cache_free(void *x)
142 {
143 if (x != NULL) si_item_release(x);
144 }
145
146 static kern_return_t
147 LI_DSLookupGetProcedureNumber(const char *name, int32_t *procno)
148 {
149 kern_return_t status;
150 security_token_t token;
151 uint32_t n, len;
152
153 if (name == NULL) return KERN_FAILURE;
154
155 len = strlen(name) + 1;
156 if (len == 1) return KERN_FAILURE;
157
158 token.val[0] = -1;
159 token.val[1] = -1;
160
161 if (_ds_running() == 0) return KERN_FAILURE;
162 if (_ds_port == MACH_PORT_NULL) return KERN_FAILURE;
163
164 status = MIG_SERVER_DIED;
165 for (n = 0; (_ds_port != MACH_PORT_NULL) && (status == MIG_SERVER_DIED) && (n < MAX_LOOKUP_ATTEMPTS); n++)
166 {
167 status = libinfoDSmig_GetProcedureNumber(_ds_port, (char *)name, procno, &token);
168
169 if (status == MACH_SEND_INVALID_DEST)
170 {
171 mach_port_mod_refs(mach_task_self(), _ds_port, MACH_PORT_RIGHT_SEND, -1);
172 status = bootstrap_look_up2(bootstrap_port, kDSStdMachDSLookupPortName, &_ds_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
173 if ((status != BOOTSTRAP_SUCCESS) && (status != BOOTSTRAP_UNKNOWN_SERVICE)) _ds_port = MACH_PORT_NULL;
174 status = MIG_SERVER_DIED;
175 }
176 }
177
178 if (status != KERN_SUCCESS)
179 {
180 #ifdef DEBUG
181 asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupGetProcedureNumber %s status %u", name, status);
182 #endif
183 return status;
184 }
185
186 if (token.val[0] != 0)
187 {
188 #ifdef DEBUG
189 asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupGetProcedureNumber %s auth failure uid=%d", name, token.val[0]);
190 #endif
191 return KERN_FAILURE;
192 }
193
194 #ifdef DEBUG
195 asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupGetProcedureNumber %s = %d", name, *procno);
196 #endif
197 return status;
198 }
199
200 static kern_return_t
201 LI_DSLookupQuery(int32_t procno, kvbuf_t *request, kvarray_t **reply)
202 {
203 kern_return_t status;
204 security_token_t token;
205 uint32_t n;
206 mach_msg_type_number_t illen, oolen;
207 char ilbuf[MAX_MIG_INLINE_DATA];
208 vm_offset_t oobuf;
209 kvbuf_t *out;
210
211 if (reply == NULL) return KERN_FAILURE;
212 if ((request != NULL) && ((request->databuf == NULL) || (request->datalen == 0))) return KERN_FAILURE;
213
214 token.val[0] = -1;
215 token.val[1] = -1;
216 *reply = NULL;
217
218 if (_ds_running() == 0) return KERN_FAILURE;
219 if (_ds_port == MACH_PORT_NULL) return KERN_FAILURE;
220
221 status = MIG_SERVER_DIED;
222 for (n = 0; (_ds_port != MACH_PORT_NULL) && (status == MIG_SERVER_DIED) && (n < MAX_LOOKUP_ATTEMPTS); n++)
223 {
224 illen = 0;
225 oolen = 0;
226 oobuf = 0;
227
228 if (request != NULL)
229 {
230 status = libinfoDSmig_Query(_ds_port, procno, request->databuf, request->datalen, ilbuf, &illen, &oobuf, &oolen, &token);
231 }
232 else
233 {
234 status = libinfoDSmig_Query(_ds_port, procno, "", 0, ilbuf, &illen, &oobuf, &oolen, &token);
235 }
236
237 if (status == MACH_SEND_INVALID_DEST)
238 {
239 mach_port_mod_refs(mach_task_self(), _ds_port, MACH_PORT_RIGHT_SEND, -1);
240 status = bootstrap_look_up2(bootstrap_port, kDSStdMachDSLookupPortName, &_ds_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
241 if ((status != BOOTSTRAP_SUCCESS) && (status != BOOTSTRAP_UNKNOWN_SERVICE)) _ds_port = MACH_PORT_NULL;
242 status = MIG_SERVER_DIED;
243 }
244 }
245
246 if (status != KERN_SUCCESS)
247 {
248 #ifdef DEBUG
249 asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupQuery %d status %u", procno, status);
250 #endif
251 return status;
252 }
253
254 if (token.val[0] != 0)
255 {
256 #ifdef DEBUG
257 asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupQuery %d auth failure uid=%d", procno, token.val[0]);
258 #endif
259 if ((oolen > 0) && (oobuf != 0)) vm_deallocate(mach_task_self(), (vm_address_t)oobuf, oolen);
260 return KERN_FAILURE;
261 }
262
263 out = (kvbuf_t *)calloc(1, sizeof(kvbuf_t));
264 if (out == NULL)
265 {
266 if ((oolen > 0) && (oobuf != 0)) vm_deallocate(mach_task_self(), (vm_address_t)oobuf, oolen);
267 return KERN_FAILURE;
268 }
269
270 if ((oolen > 0) && (oobuf != 0))
271 {
272 out->datalen = oolen;
273 out->databuf = malloc(oolen);
274 if (out->databuf == NULL)
275 {
276 free(out);
277 *reply = NULL;
278 vm_deallocate(mach_task_self(), (vm_address_t)oobuf, oolen);
279 return KERN_FAILURE;
280 }
281
282 memcpy(out->databuf, (char *)oobuf, oolen);
283 vm_deallocate(mach_task_self(), (vm_address_t)oobuf, oolen);
284 }
285 else if (illen > 0)
286 {
287 out->datalen = illen;
288 out->databuf = malloc(illen);
289 if (out->databuf == NULL)
290 {
291 free(out);
292 *reply = NULL;
293 return KERN_FAILURE;
294 }
295
296 memcpy(out->databuf, ilbuf, illen);
297 }
298
299 *reply = kvbuf_decode(out);
300 if (*reply == NULL)
301 {
302 /* DS returned no data */
303 free(out->databuf);
304 free(out);
305 }
306
307 #ifdef DEBUG
308 asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "_DSLookupQuery %d status OK", procno);
309 #endif
310 return status;
311 }
312
313 /* notify SPI */
314 uint32_t notify_peek(int token, uint32_t *val);
315
316 typedef struct
317 {
318 int notify_token_global;
319 int notify_token_user;
320 int notify_token_group;
321 int notify_token_host;
322 int notify_token_service;
323 } ds_si_private_t;
324
325 static uid_t
326 audit_token_uid(audit_token_t a)
327 {
328 /*
329 * This should really call audit_token_to_au32,
330 * but that's in libbsm, not in a Libsystem library.
331 */
332 return (uid_t)a.val[1];
333 }
334
335 static void
336 ds_get_validation(si_mod_t *si, uint64_t *a, uint64_t *b, int cat)
337 {
338 ds_si_private_t *pp;
339 uint32_t peek;
340 int status;
341
342 if (si == NULL) return;
343
344 pp = (ds_si_private_t *)si->private;
345 if (pp == NULL) return;
346
347 if (a != NULL)
348 {
349 *a = 0;
350 status = notify_peek(pp->notify_token_global, &peek);
351 if (status == NOTIFY_STATUS_OK) *a = ntohl(peek);
352 }
353
354 if (b != NULL)
355 {
356 *b = 0;
357 peek = 0;
358 status = NOTIFY_STATUS_FAILED;
359
360 if (cat == CATEGORY_USER) status = notify_peek(pp->notify_token_user, &peek);
361 else if (cat == CATEGORY_GROUP) status = notify_peek(pp->notify_token_group, &peek);
362 else if (cat == CATEGORY_GROUPLIST) status = notify_peek(pp->notify_token_group, &peek);
363 else if (cat == CATEGORY_HOST_IPV4) status = notify_peek(pp->notify_token_host, &peek);
364 else if (cat == CATEGORY_HOST_IPV6) status = notify_peek(pp->notify_token_host, &peek);
365 else if (cat == CATEGORY_SERVICE) status = notify_peek(pp->notify_token_service, &peek);
366
367 if (status == NOTIFY_STATUS_OK) *b = ntohl(peek);
368 }
369 }
370
371 static si_list_t *
372 ds_list(si_mod_t *si, int cat, const char *procname, int *procnum, void *extra, si_item_t *(*extract)(si_mod_t *, kvarray_t *, void *, uint64_t, uint64_t), kvbuf_t *request)
373 {
374 si_item_t *item;
375 si_list_t *list;
376 kvarray_t *reply;
377 kern_return_t status;
378 uint64_t va, vb;
379
380 if (*procnum < 0)
381 {
382 status = LI_DSLookupGetProcedureNumber(procname, procnum);
383 if (status != KERN_SUCCESS) return NULL;
384 }
385
386 reply = NULL;
387 ds_get_validation(si, &va, &vb, cat);
388 status = LI_DSLookupQuery(*procnum, request, &reply);
389
390 if ((status != KERN_SUCCESS) || (reply == NULL)) return NULL;
391
392 list = NULL;
393 while (reply->curr < reply->count)
394 {
395 item = extract(si, reply, extra, va, vb);
396 list = si_list_add(list, item);
397 si_item_release(item);
398 }
399
400 kvarray_free(reply);
401
402 return list;
403 }
404
405 static si_item_t *
406 ds_item(si_mod_t *si, int cat, const char *procname, int *procnum, void *extra, si_item_t *(*extract)(si_mod_t *, kvarray_t *, void *, uint64_t, uint64_t), kvbuf_t *request)
407 {
408 si_item_t *item;
409 kvarray_t *reply;
410 kern_return_t status;
411 uint64_t va, vb;
412
413 if (*procnum < 0)
414 {
415 status = LI_DSLookupGetProcedureNumber(procname, procnum);
416 if (status != KERN_SUCCESS) return NULL;
417 }
418
419 reply = NULL;
420 ds_get_validation(si, &va, &vb, cat);
421 status = LI_DSLookupQuery(*procnum, request, &reply);
422
423 if ((status != KERN_SUCCESS) || (reply == NULL)) return NULL;
424
425 item = extract(si, reply, extra, va, vb);
426 kvarray_free(reply);
427
428 return item;
429 }
430
431 /*
432 * Extract the next user entry from a kvarray.
433 */
434 static si_item_t *
435 extract_user(si_mod_t *si, kvarray_t *in, void *ignored, uint64_t valid_global, uint64_t valid_cat)
436 {
437 struct passwd tmp;
438 uint32_t d, k, kcount;
439
440 if (si == NULL) return NULL;
441 if (in == NULL) return NULL;
442
443 d = in->curr;
444 in->curr++;
445
446 if (d >= in->count) return NULL;
447
448 memset(&tmp, 0, sizeof(struct passwd));
449
450 tmp.pw_uid = -2;
451 tmp.pw_gid = -2;
452
453 kcount = in->dict[d].kcount;
454
455 for (k = 0; k < kcount; k++)
456 {
457 if (string_equal(in->dict[d].key[k], "pw_name"))
458 {
459 if (tmp.pw_name != NULL) continue;
460 if (in->dict[d].vcount[k] == 0) continue;
461
462 tmp.pw_name = (char *)in->dict[d].val[k][0];
463 }
464 else if (string_equal(in->dict[d].key[k], "pw_passwd"))
465 {
466 if (tmp.pw_passwd != NULL) continue;
467 if (in->dict[d].vcount[k] == 0) continue;
468
469 tmp.pw_passwd = (char *)in->dict[d].val[k][0];
470 }
471 else if (string_equal(in->dict[d].key[k], "pw_uid"))
472 {
473 if (in->dict[d].vcount[k] == 0) continue;
474 tmp.pw_uid = atoi(in->dict[d].val[k][0]);
475 }
476 else if (string_equal(in->dict[d].key[k], "pw_gid"))
477 {
478 if (in->dict[d].vcount[k] == 0) continue;
479 tmp.pw_gid = atoi(in->dict[d].val[k][0]);
480 }
481 else if (string_equal(in->dict[d].key[k], "pw_change"))
482 {
483 if (in->dict[d].vcount[k] == 0) continue;
484 tmp.pw_change = atol(in->dict[d].val[k][0]);
485 }
486 else if (string_equal(in->dict[d].key[k], "pw_expire"))
487 {
488 if (in->dict[d].vcount[k] == 0) continue;
489 tmp.pw_expire = atol(in->dict[d].val[k][0]);
490 }
491 else if (string_equal(in->dict[d].key[k], "pw_class"))
492 {
493 if (tmp.pw_class != NULL) continue;
494 if (in->dict[d].vcount[k] == 0) continue;
495
496 tmp.pw_class = (char *)in->dict[d].val[k][0];
497 }
498 else if (string_equal(in->dict[d].key[k], "pw_gecos"))
499 {
500 if (tmp.pw_gecos != NULL) continue;
501 if (in->dict[d].vcount[k] == 0) continue;
502
503 tmp.pw_gecos = (char *)in->dict[d].val[k][0];
504 }
505 else if (string_equal(in->dict[d].key[k], "pw_dir"))
506 {
507 if (tmp.pw_dir != NULL) continue;
508 if (in->dict[d].vcount[k] == 0) continue;
509
510 tmp.pw_dir = (char *)in->dict[d].val[k][0];
511 }
512 else if (string_equal(in->dict[d].key[k], "pw_shell"))
513 {
514 if (tmp.pw_shell != NULL) continue;
515 if (in->dict[d].vcount[k] == 0) continue;
516
517 tmp.pw_shell = (char *)in->dict[d].val[k][0];
518 }
519 }
520
521 if (tmp.pw_name == NULL) tmp.pw_name = "";
522 if (tmp.pw_passwd == NULL) tmp.pw_passwd = "";
523 if (tmp.pw_class == NULL) tmp.pw_class = "";
524 if (tmp.pw_gecos == NULL) tmp.pw_gecos = "";
525 if (tmp.pw_dir == NULL) tmp.pw_dir = "";
526 if (tmp.pw_shell == NULL) tmp.pw_shell = "";
527
528 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);
529 }
530
531 static si_item_t *
532 extract_group(si_mod_t *si, kvarray_t *in, void *ignored, uint64_t valid_global, uint64_t valid_cat)
533 {
534 struct group tmp;
535 char *empty[1];
536 uint32_t d, k, kcount;
537
538 if (si == NULL) return NULL;
539 if (in == NULL) return NULL;
540
541 d = in->curr;
542 in->curr++;
543
544 if (d >= in->count) return NULL;
545
546 empty[0] = NULL;
547 memset(&tmp, 0, sizeof(struct group));
548
549 tmp.gr_gid = -2;
550
551 kcount = in->dict[d].kcount;
552
553 for (k = 0; k < kcount; k++)
554 {
555 if (string_equal(in->dict[d].key[k], "gr_name"))
556 {
557 if (tmp.gr_name != NULL) continue;
558 if (in->dict[d].vcount[k] == 0) continue;
559
560 tmp.gr_name = (char *)in->dict[d].val[k][0];
561 }
562 else if (string_equal(in->dict[d].key[k], "gr_passwd"))
563 {
564 if (tmp.gr_passwd != NULL) continue;
565 if (in->dict[d].vcount[k] == 0) continue;
566
567 tmp.gr_passwd = (char *)in->dict[d].val[k][0];
568 }
569 else if (string_equal(in->dict[d].key[k], "gr_gid"))
570 {
571 if (in->dict[d].vcount[k] == 0) continue;
572 tmp.gr_gid = atoi(in->dict[d].val[k][0]);
573 }
574 else if (string_equal(in->dict[d].key[k], "gr_mem"))
575 {
576 if (tmp.gr_mem != NULL) continue;
577 if (in->dict[d].vcount[k] == 0) continue;
578
579 tmp.gr_mem = (char **)in->dict[d].val[k];
580 }
581 }
582
583 if (tmp.gr_name == NULL) tmp.gr_name = "";
584 if (tmp.gr_passwd == NULL) tmp.gr_passwd = "";
585 if (tmp.gr_mem == NULL) tmp.gr_mem = empty;
586
587 return (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);
588 }
589
590 static void
591 _free_addr_list(char **l)
592 {
593 int i;
594
595 if (l == NULL) return;
596 for (i = 0; l[i] != NULL; i++) free(l[i]);
597 free(l);
598 }
599
600 /* map ipv4 addresses and append to v6 list */
601 static int
602 _map_v4(char ***v6, uint32_t n6, char **v4, uint32_t n4)
603 {
604 struct in6_addr a6;
605 uint32_t i;
606
607 a6.__u6_addr.__u6_addr32[0] = 0x00000000;
608 a6.__u6_addr.__u6_addr32[1] = 0x00000000;
609 a6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff);
610
611 if (*v6 == NULL)
612 {
613 *v6 = (char **)calloc(n4 + 1, sizeof(char *));
614 }
615 else
616 {
617 *v6 = (char **)reallocf(*v6, (n6 + n4 + 1) * sizeof(char *));
618 }
619
620 if (*v6 == NULL) return -1;
621
622 for (i = 0; i < n4; i++)
623 {
624 (*v6)[n6] = (char *)calloc(1, IPV6_ADDR_LEN);
625 if ((*v6)[n6] == NULL) return -1;
626
627 memcpy(&(a6.__u6_addr.__u6_addr32[3]), v4[i], IPV4_ADDR_LEN);
628 memcpy((*v6)[n6], &(a6.__u6_addr.__u6_addr32[0]), IPV6_ADDR_LEN);
629
630 n6++;
631 }
632
633 return 0;
634 }
635
636 static si_item_t *
637 extract_netgroup(si_mod_t *si, kvarray_t *in, void *ignored, uint64_t valid_global, uint64_t valid_cat)
638 {
639 const char *host, *user, *domain;
640 uint32_t d, k, kcount;
641
642 if (si == NULL) return NULL;
643 if (in == NULL) return NULL;
644
645 d = in->curr;
646 in->curr++;
647
648 if (d >= in->count) return NULL;
649
650 kcount = in->dict[d].kcount;
651
652 host = NULL;
653 user = NULL;
654 domain = NULL;
655
656 for (k = 0; k < kcount; k++)
657 {
658 if (string_equal(in->dict[d].key[k], "host"))
659 {
660 if (host != NULL) continue;
661 if (in->dict[d].vcount[k] == 0) continue;
662
663 host = (char *)in->dict[d].val[k][0];
664 }
665 else if (string_equal(in->dict[d].key[k], "user"))
666 {
667 if (user != NULL) continue;
668 if (in->dict[d].vcount[k] == 0) continue;
669
670 user = (char *)in->dict[d].val[k][0];
671 }
672 else if (string_equal(in->dict[d].key[k], "domain"))
673 {
674 if (domain != NULL) continue;
675 if (in->dict[d].vcount[k] == 0) continue;
676
677 domain = (char *)in->dict[d].val[k][0];
678 }
679 }
680
681 if (host == NULL) host = "";
682 if (user == NULL) user = "";
683 if (domain == NULL) domain = "";
684
685 return (si_item_t *)LI_ils_create("L4488sss", (unsigned long)si, CATEGORY_ALIAS, 1, valid_global, valid_cat, host, user, domain);
686 }
687
688 static si_item_t *
689 extract_alias(si_mod_t *si, kvarray_t *in, void *ignored, uint64_t valid_global, uint64_t valid_cat)
690 {
691 struct aliasent tmp;
692 char *empty[1];
693 uint32_t d, k, kcount;
694
695 if (si == NULL) return NULL;
696 if (in == NULL) return NULL;
697
698 d = in->curr;
699 in->curr++;
700
701 if (d >= in->count) return NULL;
702
703 empty[0] = NULL;
704 memset(&tmp, 0, sizeof(struct group));
705
706 kcount = in->dict[d].kcount;
707
708 for (k = 0; k < kcount; k++)
709 {
710 if (string_equal(in->dict[d].key[k], "alias_name"))
711 {
712 if (tmp.alias_name != NULL) continue;
713 if (in->dict[d].vcount[k] == 0) continue;
714
715 tmp.alias_name = (char *)in->dict[d].val[k][0];
716 }
717 else if (string_equal(in->dict[d].key[k], "alias_members"))
718 {
719 if (tmp.alias_members != NULL) continue;
720 if (in->dict[d].vcount[k] == 0) continue;
721
722 tmp.alias_members_len = in->dict[d].vcount[k];
723 tmp.alias_members = (char **)in->dict[d].val[k];
724 }
725 else if (string_equal(in->dict[d].key[k], "alias_local"))
726 {
727 if (in->dict[d].vcount[k] == 0) continue;
728 tmp.alias_local = atoi(in->dict[d].val[k][0]);
729 }
730 }
731
732 return (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);
733 }
734
735 static si_item_t *
736 extract_host(si_mod_t *si, kvarray_t *in, void *extra, uint64_t valid_global, uint64_t valid_cat)
737 {
738 struct hostent tmp;
739 si_item_t *out;
740 uint32_t i, d, k, kcount, vcount, v4count, v6count, want;
741 int status, addr_len;
742 int family, addr_count;
743 struct in_addr a4;
744 struct in6_addr a6;
745 char **v4addrs, **v6addrs;
746 char *empty[1];
747
748 v4addrs = NULL;
749 v6addrs = NULL;
750 v4count = 0;
751 v6count = 0;
752 addr_count = 0;
753 addr_len = sizeof(void *);
754
755 if (si == NULL) return NULL;
756 if (in == NULL) return NULL;
757
758 d = in->curr;
759 in->curr++;
760
761 if (d >= in->count) return NULL;
762
763 empty[0] = NULL;
764 memset(&tmp, 0, sizeof(struct hostent));
765
766 family = AF_INET;
767 tmp.h_length = IPV4_ADDR_LEN;
768
769 want = WANT_A4_ONLY;
770 if (extra != NULL) want = *(uint32_t *)extra;
771
772 if (want != WANT_A4_ONLY)
773 {
774 family = AF_INET6;
775 tmp.h_length = IPV6_ADDR_LEN;
776 }
777
778 tmp.h_addrtype = family;
779
780 kcount = in->dict[d].kcount;
781
782 for (k = 0; k < kcount; k++)
783 {
784 if (string_equal(in->dict[d].key[k], "h_name"))
785 {
786 if (tmp.h_name != NULL) continue;
787
788 vcount = in->dict[d].vcount[k];
789 if (vcount == 0) continue;
790
791 tmp.h_name = (char *)in->dict[d].val[k][0];
792 }
793 else if (string_equal(in->dict[d].key[k], "h_aliases"))
794 {
795 if (tmp.h_aliases != NULL) continue;
796
797 vcount = in->dict[d].vcount[k];
798 if (vcount == 0) continue;
799
800 tmp.h_aliases = (char **)in->dict[d].val[k];
801 }
802 else if (string_equal(in->dict[d].key[k], "h_ipv4_addr_list"))
803 {
804 if (v4addrs != NULL) continue;
805
806 v4count = in->dict[d].vcount[k];
807 if (v4count == 0) continue;
808
809 v4addrs = (char **)calloc(v4count + 1, sizeof(char *));
810 if (v4addrs == NULL)
811 {
812 _free_addr_list(v6addrs);
813 return NULL;
814 }
815
816 for (i = 0; i < v4count; i++)
817 {
818 v4addrs[i] = calloc(1, IPV4_ADDR_LEN);
819 if (v4addrs[i] == NULL)
820 {
821 _free_addr_list(v4addrs);
822 _free_addr_list(v6addrs);
823 return NULL;
824 }
825
826 memset(&a4, 0, sizeof(struct in_addr));
827 status = inet_pton(AF_INET, in->dict[d].val[k][i], &a4);
828 if (status != 1)
829 {
830 _free_addr_list(v4addrs);
831 _free_addr_list(v6addrs);
832 return NULL;
833 }
834
835 memcpy(v4addrs[i], &a4, IPV4_ADDR_LEN);
836 }
837 }
838 else if (string_equal(in->dict[d].key[k], "h_ipv6_addr_list"))
839 {
840 if (v6addrs != NULL) continue;
841
842 v6count = in->dict[d].vcount[k];
843 if (v6count == 0) continue;
844
845 v6addrs = (char **)calloc(v6count + 1, sizeof(char *));
846 if (v6addrs == NULL)
847 {
848 _free_addr_list(v4addrs);
849 return NULL;
850 }
851
852 for (i = 0; i < v6count; i++)
853 {
854 v6addrs[i] = calloc(1, IPV6_ADDR_LEN);
855 if (v6addrs[i] == NULL)
856 {
857 _free_addr_list(v4addrs);
858 _free_addr_list(v6addrs);
859 return NULL;
860 }
861
862 memset(&a6, 0, sizeof(struct in6_addr));
863 status = inet_pton(AF_INET6, in->dict[d].val[k][i], &a6);
864 if (status != 1)
865 {
866 _free_addr_list(v4addrs);
867 _free_addr_list(v6addrs);
868 return NULL;
869 }
870
871 memcpy(v6addrs[i], &(a6.__u6_addr.__u6_addr32[0]), IPV6_ADDR_LEN);
872 }
873 }
874 }
875
876 if (tmp.h_name == NULL) tmp.h_name = "";
877 if (tmp.h_aliases == NULL) tmp.h_aliases = empty;
878
879 if (want == WANT_A4_ONLY)
880 {
881 _free_addr_list(v6addrs);
882 if (v4addrs == NULL) return NULL;
883
884 tmp.h_addr_list = v4addrs;
885 out = (si_item_t *)LI_ils_create("L4488s*44a", (unsigned long)si, CATEGORY_HOST_IPV4, 1, valid_global, valid_cat, tmp.h_name, tmp.h_aliases, tmp.h_addrtype, tmp.h_length, tmp.h_addr_list);
886 _free_addr_list(v4addrs);
887 return out;
888 }
889 else if ((want == WANT_A6_ONLY) || ((want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) && (v6count > 0)))
890 {
891 _free_addr_list(v4addrs);
892 if (v6addrs == NULL) return NULL;
893
894 tmp.h_addr_list = v6addrs;
895 out = (si_item_t *)LI_ils_create("L4488s*44c", (unsigned long)si, CATEGORY_HOST_IPV6, 1, valid_global, valid_cat, tmp.h_name, tmp.h_aliases, tmp.h_addrtype, tmp.h_length, tmp.h_addr_list);
896 _free_addr_list(v6addrs);
897 return out;
898 }
899
900 /*
901 * At this point, want is WANT_A6_PLUS_MAPPED_A4, WANT_MAPPED_A4_ONLY,
902 * or WANT_A6_OR_MAPPED_A4_IF_NO_A6. In the last case, there are no ipv6
903 * addresses, so that case degenerates into WANT_MAPPED_A4_ONLY.
904 */
905 if (want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) want = WANT_MAPPED_A4_ONLY;
906
907 if (want == WANT_MAPPED_A4_ONLY)
908 {
909 _free_addr_list(v6addrs);
910 v6addrs = NULL;
911 v6count = 0;
912 }
913
914 status = _map_v4(&v6addrs, v6count, v4addrs, v4count);
915 _free_addr_list(v4addrs);
916 if (status != 0)
917 {
918 _free_addr_list(v6addrs);
919 return NULL;
920 }
921
922 if (v6addrs == NULL) return NULL;
923
924 tmp.h_addr_list = v6addrs;
925 out = (si_item_t *)LI_ils_create("L4488s*44c", (unsigned long)si, CATEGORY_HOST_IPV6, 1, valid_global, valid_cat, tmp.h_name, tmp.h_aliases, tmp.h_addrtype, tmp.h_length, tmp.h_addr_list);
926 _free_addr_list(v6addrs);
927 return out;
928 }
929
930 static si_item_t *
931 extract_network(si_mod_t *si, kvarray_t *in, void *ignored, uint64_t valid_global, uint64_t valid_cat)
932 {
933 struct netent tmp;
934 uint32_t d, k, kcount;
935 char *empty[1];
936
937 if (si == NULL) return NULL;
938 if (in == NULL) return NULL;
939
940 d = in->curr;
941 in->curr++;
942
943 if (d >= in->count) return NULL;
944
945 empty[0] = NULL;
946 memset(&tmp, 0, sizeof(struct netent));
947
948 tmp.n_addrtype = AF_INET;
949
950 kcount = in->dict[d].kcount;
951
952 for (k = 0; k < kcount; k++)
953 {
954 if (string_equal(in->dict[d].key[k], "n_name"))
955 {
956 if (tmp.n_name != NULL) continue;
957 if (in->dict[d].vcount[k] == 0) continue;
958
959 tmp.n_name = (char *)in->dict[d].val[k][0];
960 }
961 else if (string_equal(in->dict[d].key[k], "n_net"))
962 {
963 if (in->dict[d].vcount[k] == 0) continue;
964 tmp.n_net = inet_network(in->dict[d].val[k][0]);
965 }
966 else if (string_equal(in->dict[d].key[k], "n_addrtype"))
967 {
968 if (in->dict[d].vcount[k] == 0) continue;
969 tmp.n_addrtype = atoi(in->dict[d].val[k][0]);
970 }
971 else if (string_equal(in->dict[d].key[k], "n_aliases"))
972 {
973 if (tmp.n_aliases != NULL) continue;
974 if (in->dict[d].vcount[k] == 0) continue;
975
976 tmp.n_aliases = (char **)in->dict[d].val[k];
977 }
978 }
979
980 if (tmp.n_name == NULL) tmp.n_name = "";
981 if (tmp.n_aliases == NULL) tmp.n_aliases = empty;
982
983 return (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);
984 }
985
986 static si_item_t *
987 extract_service(si_mod_t *si, kvarray_t *in, void *ignored, uint64_t valid_global, uint64_t valid_cat)
988 {
989 struct servent tmp;
990 char *empty[1];
991 uint32_t d, k, kcount;
992
993 if (si == NULL) return NULL;
994 if (in == NULL) return NULL;
995
996 d = in->curr;
997 in->curr++;
998
999 if (d >= in->count) return NULL;
1000
1001 empty[0] = NULL;
1002 memset(&tmp, 0, sizeof(struct servent));
1003
1004 kcount = in->dict[d].kcount;
1005
1006 for (k = 0; k < kcount; k++)
1007 {
1008 if (string_equal(in->dict[d].key[k], "s_name"))
1009 {
1010 if (tmp.s_name != NULL) continue;
1011 if (in->dict[d].vcount[k] == 0) continue;
1012
1013 tmp.s_name = (char *)in->dict[d].val[k][0];
1014 }
1015 else if (string_equal(in->dict[d].key[k], "s_aliases"))
1016 {
1017 if (tmp.s_aliases != NULL) continue;
1018 if (in->dict[d].vcount[k] == 0) continue;
1019
1020 tmp.s_aliases = (char **)in->dict[d].val[k];
1021 }
1022 else if (string_equal(in->dict[d].key[k], "s_port"))
1023 {
1024 if (in->dict[d].vcount[k] == 0) continue;
1025 tmp.s_port = atoi(in->dict[d].val[k][0]);
1026 }
1027 else if (string_equal(in->dict[d].key[k], "s_proto"))
1028 {
1029 if (tmp.s_proto != NULL) continue;
1030 if (in->dict[d].vcount[k] == 0) continue;
1031
1032 tmp.s_proto = (char *)in->dict[d].val[k][0];
1033 }
1034 }
1035
1036 if (tmp.s_name == NULL) tmp.s_name = "";
1037 if (tmp.s_proto == NULL) tmp.s_proto = "";
1038 if (tmp.s_aliases == NULL) tmp.s_aliases = empty;
1039
1040 /* strange but correct */
1041 tmp.s_port = htons(tmp.s_port);
1042
1043 return (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);
1044 }
1045
1046 static si_item_t *
1047 extract_protocol(si_mod_t *si, kvarray_t *in, void *ignored, uint64_t valid_global, uint64_t valid_cat)
1048 {
1049 struct protoent tmp;
1050 uint32_t d, k, kcount;
1051 char *empty[1];
1052
1053 if (si == NULL) return NULL;
1054 if (in == NULL) return NULL;
1055
1056 d = in->curr;
1057 in->curr++;
1058
1059 if (d >= in->count) return NULL;
1060
1061 empty[0] = NULL;
1062 memset(&tmp, 0, sizeof(struct protoent));
1063
1064 kcount = in->dict[d].kcount;
1065
1066 for (k = 0; k < kcount; k++)
1067 {
1068 if (string_equal(in->dict[d].key[k], "p_name"))
1069 {
1070 if (tmp.p_name != NULL) continue;
1071 if (in->dict[d].vcount[k] == 0) continue;
1072
1073 tmp.p_name = (char *)in->dict[d].val[k][0];
1074 }
1075 else if (string_equal(in->dict[d].key[k], "p_proto"))
1076 {
1077 if (in->dict[d].vcount[k] == 0) continue;
1078 tmp.p_proto = atoi(in->dict[d].val[k][0]);
1079 }
1080 else if (string_equal(in->dict[d].key[k], "p_aliases"))
1081 {
1082 if (tmp.p_aliases != NULL) continue;
1083 if (in->dict[d].vcount[k] == 0) continue;
1084
1085 tmp.p_aliases = (char **)in->dict[d].val[k];
1086 }
1087 }
1088
1089 if (tmp.p_name == NULL) tmp.p_name = "";
1090 if (tmp.p_aliases == NULL) tmp.p_aliases = empty;
1091
1092 return (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);
1093 }
1094
1095 static si_item_t *
1096 extract_rpc(si_mod_t *si, kvarray_t *in, void *ignored, uint64_t valid_global, uint64_t valid_cat)
1097 {
1098 struct rpcent tmp;
1099 uint32_t d, k, kcount;
1100 char *empty[1];
1101
1102 if (si == NULL) return NULL;
1103 if (in == NULL) return NULL;
1104
1105 d = in->curr;
1106 in->curr++;
1107
1108 if (d >= in->count) return NULL;
1109
1110 empty[0] = NULL;
1111 memset(&tmp, 0, sizeof(struct rpcent));
1112
1113 kcount = in->dict[d].kcount;
1114
1115 for (k = 0; k < kcount; k++)
1116 {
1117 if (string_equal(in->dict[d].key[k], "r_name"))
1118 {
1119 if (tmp.r_name != NULL) continue;
1120 if (in->dict[d].vcount[k] == 0) continue;
1121
1122 tmp.r_name = (char *)in->dict[d].val[k][0];
1123 }
1124 else if (string_equal(in->dict[d].key[k], "r_number"))
1125 {
1126 if (in->dict[d].vcount[k] == 0) continue;
1127 tmp.r_number = atoi(in->dict[d].val[k][0]);
1128 }
1129 else if (string_equal(in->dict[d].key[k], "r_aliases"))
1130 {
1131 if (tmp.r_aliases != NULL) continue;
1132 if (in->dict[d].vcount[k] == 0) continue;
1133
1134 tmp.r_aliases = (char **)in->dict[d].val[k];
1135 }
1136 }
1137
1138 if (tmp.r_name == NULL) tmp.r_name = "";
1139 if (tmp.r_aliases == NULL) tmp.r_aliases = empty;
1140
1141 return (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);
1142 }
1143
1144 static si_item_t *
1145 extract_fstab(si_mod_t *si, kvarray_t *in, void *extra, uint64_t valid_global, uint64_t valid_cat)
1146 {
1147 struct fstab tmp;
1148 uint32_t d, k, kcount;
1149 char *file;
1150
1151 if (si == NULL) return NULL;
1152 if (in == NULL) return NULL;
1153
1154 file = NULL;
1155 if (extra != NULL) file = (char *)extra;
1156
1157 d = in->curr;
1158 in->curr++;
1159
1160 if (d >= in->count) return NULL;
1161
1162 memset(&tmp, 0, sizeof(struct fstab));
1163
1164 kcount = in->dict[d].kcount;
1165
1166 for (k = 0; k < kcount; k++)
1167 {
1168 if (string_equal(in->dict[d].key[k], "fs_spec"))
1169 {
1170 if (tmp.fs_spec != NULL) continue;
1171 if (in->dict[d].vcount[k] == 0) continue;
1172
1173 tmp.fs_spec = (char *)in->dict[d].val[k][0];
1174 }
1175 else if (string_equal(in->dict[d].key[k], "fs_file"))
1176 {
1177 if (tmp.fs_file != NULL) continue;
1178 if (in->dict[d].vcount[k] == 0) continue;
1179
1180 tmp.fs_file = (char *)in->dict[d].val[k][0];
1181 }
1182 else if (string_equal(in->dict[d].key[k], "fs_vfstype"))
1183 {
1184 if (tmp.fs_vfstype != NULL) continue;
1185 if (in->dict[d].vcount[k] == 0) continue;
1186
1187 tmp.fs_vfstype = (char *)in->dict[d].val[k][0];
1188 }
1189 else if (string_equal(in->dict[d].key[k], "fs_mntops"))
1190 {
1191 if (tmp.fs_mntops != NULL) continue;
1192 if (in->dict[d].vcount[k] == 0) continue;
1193
1194 tmp.fs_mntops = (char *)in->dict[d].val[k][0];
1195 }
1196 else if (string_equal(in->dict[d].key[k], "fs_type"))
1197 {
1198 if (tmp.fs_type != NULL) continue;
1199 if (in->dict[d].vcount[k] == 0) continue;
1200
1201 tmp.fs_type = (char *)in->dict[d].val[k][0];
1202 }
1203 else if (string_equal(in->dict[d].key[k], "fs_freq"))
1204 {
1205 if (in->dict[d].vcount[k] == 0) continue;
1206 tmp.fs_freq = atoi(in->dict[d].val[k][0]);
1207 }
1208 else if (string_equal(in->dict[d].key[k], "fs_passno"))
1209 {
1210 if (in->dict[d].vcount[k] == 0) continue;
1211 tmp.fs_passno = atoi(in->dict[d].val[k][0]);
1212 }
1213 }
1214
1215 if (tmp.fs_spec == NULL) tmp.fs_spec = "";
1216 if (tmp.fs_file == NULL) tmp.fs_file = "";
1217 if (tmp.fs_vfstype == NULL) tmp.fs_vfstype = "";
1218 if (tmp.fs_mntops == NULL) tmp.fs_mntops = "";
1219 if (tmp.fs_type == NULL) tmp.fs_type = "";
1220
1221 if ((file != NULL) && string_not_equal(file, tmp.fs_file)) return NULL;
1222
1223 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);
1224 }
1225
1226 static si_item_t *
1227 extract_mac_mac(si_mod_t *si, kvarray_t *in, void *extra, uint64_t valid_global, uint64_t valid_cat)
1228 {
1229 uint32_t d, k, kcount;
1230 char *cmac;
1231 si_item_t *out;
1232
1233 if (si == NULL) return NULL;
1234 if (in == NULL) return NULL;
1235 if (extra == NULL) return NULL;
1236
1237 d = in->curr;
1238 in->curr++;
1239
1240 if (d >= in->count) return NULL;
1241
1242 kcount = in->dict[d].kcount;
1243
1244 cmac = NULL;
1245 for (k = 0; k < kcount; k++)
1246 {
1247 if ((cmac == NULL) && (string_equal(in->dict[d].key[k], "mac")))
1248 {
1249 if (in->dict[d].vcount[k] == 0) continue;
1250 cmac = si_standardize_mac_address(in->dict[d].val[k][0]);
1251 if (cmac == NULL) return NULL;
1252 }
1253 }
1254
1255 if (cmac == NULL) return NULL;
1256
1257 out = (si_item_t *)LI_ils_create("L4488ss", (unsigned long)si, CATEGORY_MAC, 1, valid_global, valid_cat, extra, cmac);
1258 free(cmac);
1259 return out;
1260 }
1261
1262 static si_item_t *
1263 extract_mac_name(si_mod_t *si, kvarray_t *in, void *extra, uint64_t valid_global, uint64_t valid_cat)
1264 {
1265 uint32_t d, k, kcount;
1266 const char *name;
1267 si_item_t *out;
1268
1269 if (si == NULL) return NULL;
1270 if (in == NULL) return NULL;
1271 if (extra == NULL) return NULL;
1272
1273 d = in->curr;
1274 in->curr++;
1275
1276 if (d >= in->count) return NULL;
1277
1278 kcount = in->dict[d].kcount;
1279
1280 name = NULL;
1281 for (k = 0; k < kcount; k++)
1282 {
1283 if ((name == NULL) && (string_equal(in->dict[d].key[k], "name")))
1284 {
1285 if (in->dict[d].vcount[k] == 0) continue;
1286 name = in->dict[d].val[k][0];
1287 }
1288 }
1289
1290 if (name == NULL) return NULL;
1291
1292 out = (si_item_t *)LI_ils_create("L4488ss", (unsigned long)si, CATEGORY_MAC, 1, valid_global, valid_cat, name, extra);
1293 return out;
1294 }
1295
1296 static si_item_t *
1297 ds_user_byname(si_mod_t *si, const char *name)
1298 {
1299 static int proc = -1;
1300 kvbuf_t *request;
1301 si_item_t *item;
1302
1303 request = kvbuf_query_key_val("login", name);
1304 if (request == NULL) return NULL;
1305
1306 item = ds_item(si, CATEGORY_USER, "getpwnam", &proc, NULL, extract_user, request);
1307
1308 kvbuf_free(request);
1309 return item;
1310 }
1311
1312 static si_item_t *
1313 ds_user_byuid(si_mod_t *si, uid_t uid)
1314 {
1315 static int proc = -1;
1316 char val[16];
1317 kvbuf_t *request;
1318 si_item_t *item;
1319
1320 snprintf(val, sizeof(val), "%d", (int)uid);
1321 request = kvbuf_query_key_val("uid", val);
1322 if (request == NULL) return NULL;
1323
1324 item = ds_item(si, CATEGORY_USER, "getpwuid", &proc, NULL, extract_user, request);
1325
1326 kvbuf_free(request);
1327 return item;
1328 }
1329
1330 static si_list_t *
1331 ds_user_all(si_mod_t *si)
1332 {
1333 static int proc = -1;
1334
1335 return ds_list(si, CATEGORY_USER, "getpwent", &proc, NULL, extract_user, NULL);
1336 }
1337
1338 static si_item_t *
1339 ds_group_byname(si_mod_t *si, const char *name)
1340 {
1341 static int proc = -1;
1342 kvbuf_t *request;
1343 si_item_t *item;
1344
1345 request = kvbuf_query_key_val("name", name);
1346 if (request == NULL) return NULL;
1347
1348 item = ds_item(si, CATEGORY_GROUP, "getgrnam", &proc, NULL, extract_group, request);
1349
1350 kvbuf_free(request);
1351 return item;
1352 }
1353
1354 static si_item_t *
1355 ds_group_bygid(si_mod_t *si, gid_t gid)
1356 {
1357 static int proc = -1;
1358 char val[16];
1359 kvbuf_t *request;
1360 si_item_t *item;
1361
1362 snprintf(val, sizeof(val), "%d", (int)gid);
1363 request = kvbuf_query_key_val("gid", val);
1364 if (request == NULL) return NULL;
1365
1366 item = ds_item(si, CATEGORY_GROUP, "getgrgid", &proc, NULL, extract_group, request);
1367
1368 kvbuf_free(request);
1369 return item;
1370 }
1371
1372 static si_list_t *
1373 ds_group_all(si_mod_t *si)
1374 {
1375 static int proc = -1;
1376
1377 return ds_list(si, CATEGORY_GROUP, "getgrent", &proc, NULL, extract_group, NULL);
1378 }
1379
1380 static si_item_t *
1381 ds_grouplist(si_mod_t *si, const char *name)
1382 {
1383 struct passwd *pw;
1384 kern_return_t kstatus, ks2;
1385 uint32_t i, j, count, uid, basegid, gidptrCnt;
1386 int32_t *gidp;
1387 gid_t *gidptr;
1388 audit_token_t token;
1389 si_item_t *user, *item;
1390 char **gidlist;
1391 uint64_t va, vb;
1392 size_t gidptrsz;
1393 int n;
1394
1395 if (name == NULL) return NULL;
1396
1397 user = ds_user_byname(si, name);
1398 if (user == NULL) return NULL;
1399
1400 pw = (struct passwd *)((uintptr_t)user + sizeof(si_item_t));
1401 uid = pw->pw_uid;
1402 basegid = pw->pw_gid;
1403
1404 free(user);
1405
1406 count = 0;
1407 gidptr = NULL;
1408 gidptrCnt = 0;
1409 gidptrsz = 0;
1410 memset(&token, 0, sizeof(audit_token_t));
1411
1412 if (_mbr_port == MACH_PORT_NULL)
1413 {
1414 kstatus = bootstrap_look_up2(bootstrap_port, kDSStdMachDSMembershipPortName, &_mbr_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
1415 }
1416
1417 for (n = 0; n < MAX_LOOKUP_ATTEMPTS; n++)
1418 {
1419 kstatus = memberdDSmig_GetAllGroups(_mbr_port, uid, &count, &gidptr, &gidptrCnt, &token);
1420 if (kstatus != MACH_SEND_INVALID_DEST) break;
1421
1422 mach_port_mod_refs(mach_task_self(), _mbr_port, MACH_PORT_RIGHT_SEND, -1);
1423
1424 ks2 = bootstrap_look_up2(bootstrap_port, kDSStdMachDSMembershipPortName, &_mbr_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
1425 if ((ks2 != BOOTSTRAP_SUCCESS) && (ks2 != BOOTSTRAP_UNKNOWN_SERVICE))
1426 {
1427 _mbr_port = MACH_PORT_NULL;
1428 break;
1429 }
1430 }
1431
1432 if (kstatus != KERN_SUCCESS) return NULL;
1433 if (gidptr == NULL) return NULL;
1434
1435 /* gidptrCnt is the size, but it was set to number of groups (by DS) in 10.6 and earlier */
1436 gidptrsz = gidptrCnt;
1437 if (count == gidptrCnt) gidptrsz = gidptrCnt * sizeof(gid_t);
1438
1439 if ((audit_token_uid(token) != 0) || (count == 0))
1440 {
1441 if (gidptr != NULL) vm_deallocate(mach_task_self(), (vm_address_t)gidptr, gidptrsz);
1442 return NULL;
1443 }
1444
1445 gidlist = (char **)calloc(count + 1, sizeof(char *));
1446 if (gidlist == NULL)
1447 {
1448 if (gidptr != NULL) vm_deallocate(mach_task_self(), (vm_address_t)gidptr, gidptrsz);
1449 return NULL;
1450 }
1451
1452 for (i = 0; i < count; i++)
1453 {
1454 gidp = (int32_t *)calloc(1, sizeof(int32_t));
1455 if (gidp == NULL)
1456 {
1457 for (j = 0; j < i; j++) free(gidlist[j]);
1458 free(gidlist);
1459 count = 0;
1460 break;
1461 }
1462
1463 *gidp = gidptr[i];
1464 gidlist[i] = (char *)gidp;
1465 }
1466
1467 if (count == 0)
1468 {
1469 if (gidptr != NULL) vm_deallocate(mach_task_self(), (vm_address_t)gidptr, gidptrsz);
1470 return NULL;
1471 }
1472
1473 va = 0;
1474 vb = 0;
1475 ds_get_validation(si, &va, &vb, CATEGORY_GROUPLIST);
1476
1477 item = (si_item_t *)LI_ils_create("L4488s44a", (unsigned long)si, CATEGORY_GROUPLIST, 1, va, vb, name, basegid, count, gidlist);
1478
1479 if (gidptr != NULL) vm_deallocate(mach_task_self(), (vm_address_t)gidptr, gidptrsz);
1480
1481 for (i = 0; i <= count; i++) free(gidlist[i]);
1482 free(gidlist);
1483
1484 return item;
1485 }
1486
1487 static si_list_t *
1488 ds_netgroup_byname(si_mod_t *si, const char *name)
1489 {
1490 static int proc = -1;
1491 kvbuf_t *request;
1492 si_list_t *list;
1493
1494 request = kvbuf_query_key_val("netgroup", name);
1495 if (request == NULL) return NULL;
1496
1497 list = ds_list(si, CATEGORY_NETGROUP, "getnetgrent", &proc, NULL, extract_netgroup, request);
1498
1499 kvbuf_free(request);
1500
1501 return list;
1502 }
1503
1504 static int
1505 check_innetgr(kvarray_t *in)
1506 {
1507 uint32_t d, k, kcount;
1508
1509 if (in == NULL) return 0;
1510
1511 d = in->curr;
1512 if (d >= in->count) return 0;
1513
1514 kcount = in->dict[d].kcount;
1515
1516 for (k = 0; k < kcount; k++)
1517 {
1518 if (string_equal(in->dict[d].key[k], "result"))
1519 {
1520 if (in->dict[d].vcount[k] == 0) continue;
1521 return atoi(in->dict[d].val[k][0]);
1522 }
1523 }
1524
1525 return 0;
1526 }
1527
1528 static int
1529 ds_in_netgroup(si_mod_t *si, const char *group, const char *host, const char *user, const char *domain)
1530 {
1531 int is_innetgr;
1532 kvbuf_t *request;
1533 kvarray_t *reply;
1534 kern_return_t status;
1535 static int proc = -1;
1536
1537 if (proc < 0)
1538 {
1539 status = LI_DSLookupGetProcedureNumber("innetgr", &proc);
1540 if (status != KERN_SUCCESS) return 0;
1541 }
1542
1543 /* Encode NULL */
1544 if (group == NULL) group = "";
1545 if (host == NULL) host = "";
1546 if (user == NULL) user = "";
1547 if (domain == NULL) domain = "";
1548
1549 request = kvbuf_query("ksksksks", "netgroup", group, "host", host, "user", user, "domain", domain);
1550 if (request == NULL) return 0;
1551
1552 reply = NULL;
1553 status = LI_DSLookupQuery(proc, request, &reply);
1554 kvbuf_free(request);
1555
1556 if ((status != KERN_SUCCESS) || (reply == NULL)) return 0;
1557
1558 is_innetgr = check_innetgr(reply);
1559
1560 kvarray_free(reply);
1561
1562 return is_innetgr;
1563 }
1564
1565 static si_item_t *
1566 ds_alias_byname(si_mod_t *si, const char *name)
1567 {
1568 static int proc = -1;
1569 kvbuf_t *request;
1570 si_item_t *item;
1571
1572 request = kvbuf_query_key_val("name", name);
1573 if (request == NULL) return NULL;
1574
1575 item = ds_item(si, CATEGORY_ALIAS, "alias_getbyname", &proc, NULL, extract_alias, request);
1576
1577 kvbuf_free(request);
1578 return item;
1579 }
1580
1581 static si_list_t *
1582 ds_alias_all(si_mod_t *si)
1583 {
1584 static int proc = -1;
1585
1586 return ds_list(si, CATEGORY_ALIAS, "alias_getent", &proc, NULL, extract_alias, NULL);
1587 }
1588
1589 static si_item_t *
1590 ds_host_byname(si_mod_t *si, const char *name, int af, const char *ignored, uint32_t *err)
1591 {
1592 static int proc = -1;
1593 kvbuf_t *request;
1594 si_item_t *item;
1595 uint32_t want4, want6;
1596 int cat;
1597
1598 if (err != NULL) *err = SI_STATUS_NO_ERROR;
1599
1600 if (name == NULL)
1601 {
1602 *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1603 return NULL;
1604 }
1605
1606 want4 = 0;
1607 want6 = 0;
1608
1609 cat = CATEGORY_HOST_IPV4;
1610
1611 if (af == AF_INET)
1612 {
1613 want4 = 1;
1614 }
1615 else if (af == AF_INET6)
1616 {
1617 want6 = 1;
1618 cat = CATEGORY_HOST_IPV6;
1619 }
1620 else
1621 {
1622 *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1623 return NULL;
1624 }
1625
1626 request = kvbuf_query("kskuku", "name", name, "ipv4", want4, "ipv6", want6);
1627 if (request == NULL)
1628 {
1629 *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1630 return NULL;
1631 }
1632
1633 item = ds_item(si, cat, "gethostbyname", &proc, NULL, extract_host, request);
1634
1635 if ((item == NULL) && (err != NULL)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
1636
1637 kvbuf_free(request);
1638 return item;
1639 }
1640
1641 static si_item_t *
1642 ds_host_byaddr(si_mod_t *si, const void *addr, int af, const char *ignored, uint32_t *err)
1643 {
1644 static int proc = -1;
1645 kvbuf_t *request;
1646 si_item_t *item;
1647 struct in_addr addr4;
1648 struct in6_addr addr6;
1649 char val[64 + 1 + IF_NAMESIZE];
1650 int cat;
1651 uint32_t want;
1652
1653 if (err != NULL) *err = SI_STATUS_NO_ERROR;
1654
1655 cat = CATEGORY_HOST_IPV4;
1656
1657 memset(&addr4, 0, sizeof(struct in_addr));
1658 memset(&addr6, 0, sizeof(struct in6_addr));
1659 memset(val, 0, sizeof(val));
1660
1661 want = WANT_A4_ONLY;
1662
1663 if (af == AF_INET)
1664 {
1665 memcpy(&addr4.s_addr, addr, IPV4_ADDR_LEN);
1666 if (inet_ntop(af, &addr4, val, sizeof(val)) == NULL)
1667 {
1668 *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1669 return NULL;
1670 }
1671 }
1672 else if (af == AF_INET6)
1673 {
1674 want = WANT_A6_ONLY;
1675 cat = CATEGORY_HOST_IPV6;
1676 memcpy(&addr6, addr, IPV6_ADDR_LEN);
1677 if (inet_ntop(af, &addr6, val, sizeof(val)) == NULL)
1678 {
1679 *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1680 return NULL;
1681 }
1682 }
1683 else
1684 {
1685 *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1686 return NULL;
1687 }
1688
1689 request = kvbuf_query("ksku", "address", val, "family", af);
1690 if (request == NULL)
1691 {
1692 *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1693 return NULL;
1694 }
1695
1696 item = ds_item(si, cat, "gethostbyaddr", &proc, &want, extract_host, request);
1697
1698 if ((item == NULL) && (err != NULL)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
1699
1700 kvbuf_free(request);
1701 return item;
1702 }
1703
1704 static si_list_t *
1705 ds_host_all(si_mod_t *si)
1706 {
1707 static int proc = -1;
1708
1709 return ds_list(si, CATEGORY_HOST_IPV4, "gethostent", &proc, NULL, extract_host, NULL);
1710 }
1711
1712 static si_item_t *
1713 ds_network_byname(si_mod_t *si, const char *name)
1714 {
1715 static int proc = -1;
1716 kvbuf_t *request;
1717 si_item_t *item;
1718
1719 request = kvbuf_query_key_val("name", name);
1720 if (request == NULL) return NULL;
1721
1722 item = ds_item(si, CATEGORY_NETWORK, "getnetbyname", &proc, NULL, extract_network, request);
1723
1724 kvbuf_free(request);
1725 return item;
1726 }
1727
1728 static si_item_t *
1729 ds_network_byaddr(si_mod_t *si, uint32_t addr)
1730 {
1731 static int proc = -1;
1732 unsigned char f1, f2, f3;
1733 char val[64];
1734 kvbuf_t *request;
1735 si_item_t *item;
1736
1737 f1 = addr & 0xff;
1738 addr >>= 8;
1739 f2 = addr & 0xff;
1740 addr >>= 8;
1741 f3 = addr & 0xff;
1742
1743 if (f3 != 0) snprintf(val, sizeof(val), "%u.%u.%u", f3, f2, f1);
1744 else if (f2 != 0) snprintf(val, sizeof(val), "%u.%u", f2, f1);
1745 else snprintf(val, sizeof(val), "%u", f1);
1746
1747 request = kvbuf_query_key_val("net", val);
1748 if (request == NULL) return NULL;
1749
1750 item = ds_item(si, CATEGORY_NETWORK, "getnetbyaddr", &proc, NULL, extract_network, request);
1751
1752 kvbuf_free(request);
1753 return item;
1754 }
1755
1756 static si_list_t *
1757 ds_network_all(si_mod_t *si)
1758 {
1759 static int proc = -1;
1760
1761 return ds_list(si, CATEGORY_NETWORK, "getnetent", &proc, NULL, extract_network, NULL);
1762 }
1763
1764 static si_item_t *
1765 ds_service_byname(si_mod_t *si, const char *name, const char *proto)
1766 {
1767 static int proc = -1;
1768 kvbuf_t *request;
1769 si_item_t *item;
1770 struct servent *s;
1771
1772 if (name == NULL) name = "";
1773 if (proto == NULL) proto = "";
1774
1775 /* Check our local service cache (see ds_addrinfo). */
1776 item = pthread_getspecific(_ds_serv_cache_key);
1777 if (item != NULL)
1778 {
1779 s = (struct servent *)((uintptr_t)item + sizeof(si_item_t));
1780 if (string_equal(name, s->s_name)) return si_item_retain(item);
1781 }
1782
1783 request = kvbuf_query("ksks", "name", name, "proto", proto);
1784 if (request == NULL) return NULL;
1785
1786 item = ds_item(si, CATEGORY_SERVICE, "getservbyname", &proc, NULL, extract_service, request);
1787
1788 kvbuf_free(request);
1789 return item;
1790 }
1791
1792 static si_item_t *
1793 ds_service_byport(si_mod_t *si, int port, const char *proto)
1794 {
1795 static int proc = -1;
1796 uint16_t sport;
1797 char val[16];
1798 kvbuf_t *request;
1799 si_item_t *item;
1800
1801 if (proto == NULL) proto = "";
1802
1803 sport = port;
1804 snprintf(val, sizeof(val), "%d", ntohs(sport));
1805
1806 request = kvbuf_query("ksks", "port", val, "proto", proto);
1807 if (request == NULL) return NULL;
1808
1809 item = ds_item(si, CATEGORY_SERVICE, "getservbyport", &proc, NULL, extract_service, request);
1810
1811 kvbuf_free(request);
1812 return item;
1813 }
1814
1815 static si_list_t *
1816 ds_service_all(si_mod_t *si)
1817 {
1818 static int proc = -1;
1819
1820 return ds_list(si, CATEGORY_SERVICE, "getservent", &proc, NULL, extract_service, NULL);
1821 }
1822
1823 static si_item_t *
1824 ds_protocol_byname(si_mod_t *si, const char *name)
1825 {
1826 static int proc = -1;
1827 kvbuf_t *request;
1828 si_item_t *item;
1829
1830 request = kvbuf_query_key_val("name", name);
1831 if (request == NULL) return NULL;
1832
1833 item = ds_item(si, CATEGORY_PROTOCOL, "getprotobyname", &proc, NULL, extract_protocol, request);
1834
1835 kvbuf_free(request);
1836 return item;
1837 }
1838
1839 static si_item_t *
1840 ds_protocol_bynumber(si_mod_t *si, int number)
1841 {
1842 static int proc = -1;
1843 char val[16];
1844 kvbuf_t *request;
1845 si_item_t *item;
1846
1847 snprintf(val, sizeof(val), "%d", number);
1848 request = kvbuf_query_key_val("number", val);
1849 if (request == NULL) return NULL;
1850
1851 item = ds_item(si, CATEGORY_PROTOCOL, "getprotobynumber", &proc, NULL, extract_protocol, request);
1852
1853 kvbuf_free(request);
1854 return item;
1855 }
1856
1857 static si_list_t *
1858 ds_protocol_all(si_mod_t *si)
1859 {
1860 static int proc = -1;
1861
1862 return ds_list(si, CATEGORY_PROTOCOL, "getprotoent", &proc, NULL, extract_protocol, NULL);
1863 }
1864
1865 static si_item_t *
1866 ds_rpc_byname(si_mod_t *si, const char *name)
1867 {
1868 static int proc = -1;
1869 kvbuf_t *request;
1870 si_item_t *item;
1871
1872 request = kvbuf_query_key_val("name", name);
1873 if (request == NULL) return NULL;
1874
1875 item = ds_item(si, CATEGORY_RPC, "getrpcbyname", &proc, NULL, extract_rpc, request);
1876
1877 kvbuf_free(request);
1878 return item;
1879 }
1880
1881 static si_item_t *
1882 ds_rpc_bynumber(si_mod_t *si, int number)
1883 {
1884 static int proc = -1;
1885 char val[16];
1886 kvbuf_t *request;
1887 si_item_t *item;
1888
1889 snprintf(val, sizeof(val), "%u", (uint32_t)number);
1890 request = kvbuf_query_key_val("number", val);
1891 if (request == NULL) return NULL;
1892
1893 item = ds_item(si, CATEGORY_RPC, "getrpcbynumber", &proc, NULL, extract_rpc, request);
1894
1895 kvbuf_free(request);
1896 return item;
1897 }
1898
1899 static si_list_t *
1900 ds_rpc_all(si_mod_t *si)
1901 {
1902 static int proc = -1;
1903
1904 return ds_list(si, CATEGORY_RPC, "getrpcent", &proc, NULL, extract_rpc, NULL);
1905 }
1906
1907 static si_item_t *
1908 ds_fs_byspec(si_mod_t *si, const char *name)
1909 {
1910 static int proc = -1;
1911 kvbuf_t *request;
1912 si_item_t *item;
1913
1914 request = kvbuf_query_key_val("name", name);
1915 if (request == NULL) return NULL;
1916
1917 item = ds_item(si, CATEGORY_FS, "getfsbyname", &proc, NULL, extract_fstab, request);
1918
1919 kvbuf_free(request);
1920 return item;
1921 }
1922
1923 static si_list_t *
1924 ds_fs_all(si_mod_t *si)
1925 {
1926 static int proc = -1;
1927
1928 return ds_list(si, CATEGORY_FS, "getfsent", &proc, NULL, extract_fstab, NULL);
1929 }
1930
1931 static si_item_t *
1932 ds_fs_byfile(si_mod_t *si, const char *name)
1933 {
1934 si_item_t *item;
1935 si_list_t *list;
1936 uint32_t i;
1937 struct fstab *f;
1938
1939 if (name == NULL) return NULL;
1940
1941 list = ds_fs_all(si);
1942 if (list == NULL) return NULL;
1943
1944 item = NULL;
1945 for (i = 0; (i < list->count) && (item == NULL); i++)
1946 {
1947 f = (struct fstab *)((uintptr_t)(list->entry[i]) + sizeof(si_item_t));
1948 if (string_equal(name, f->fs_file)) item = si_item_retain(list->entry[i]);
1949 }
1950
1951 si_list_release(list);
1952 return item;
1953 }
1954
1955 static si_item_t *
1956 ds_mac_byname(si_mod_t *si, const char *name)
1957 {
1958 static int proc = -1;
1959 kvbuf_t *request;
1960 si_item_t *item;
1961
1962 request = kvbuf_query_key_val("name", name);
1963 if (request == NULL) return NULL;
1964
1965 item = ds_item(si, CATEGORY_MAC, "getmacbyname", &proc, (void *)name, extract_mac_mac, request);
1966
1967 kvbuf_free(request);
1968 return item;
1969 }
1970
1971 static si_item_t *
1972 ds_mac_bymac(si_mod_t *si, const char *mac)
1973 {
1974 static int proc = -1;
1975 kvbuf_t *request;
1976 si_item_t *item;
1977 char *cmac;
1978
1979 cmac = si_standardize_mac_address(mac);
1980 if (cmac == NULL) return NULL;
1981
1982 request = kvbuf_query_key_val("mac", cmac);
1983 if (request == NULL) return NULL;
1984
1985 item = ds_item(si, CATEGORY_MAC, "gethostbymac", &proc, cmac, extract_mac_name, request);
1986
1987 free(cmac);
1988 kvbuf_free(request);
1989 return item;
1990 }
1991
1992 static si_list_t *
1993 ds_addrinfo(si_mod_t *si, const void *node, const void *serv, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *ignored, uint32_t *err)
1994 {
1995 static int proc = -1;
1996 si_list_t *list, *out;
1997 si_item_t *item;
1998 kvbuf_t *request = NULL;
1999 kvdict_t *dict;
2000 kvarray_t *reply = NULL;
2001 kern_return_t status = 0;
2002 uint16_t scope = 0;
2003 int i, k, kcount, d;
2004 uint32_t port;
2005
2006 struct hostent *h;
2007 char *h_name = NULL;
2008 int h_aliases_cnt = 0;
2009 const char **h_aliases = NULL;
2010 struct in_addr *a4 = NULL;
2011 struct in6_addr *a6 = NULL;
2012 int a4_cnt = 0;
2013 int a6_cnt = 0;
2014 struct servent *s;
2015 const char *s_name = NULL;
2016 int s_aliases_cnt = 0;
2017 const char **s_aliases = NULL;
2018 uint16_t s_port = 0;
2019 const char *s_proto = NULL;
2020 const char *protoname;
2021 int wantv4, wantv6;
2022
2023 int numericserv = ((flags & AI_NUMERICSERV) != 0);
2024 int numerichost = ((flags & AI_NUMERICHOST) != 0);
2025
2026 wantv4 = 0;
2027 wantv6 = 0;
2028
2029 if (node != NULL)
2030 {
2031 wantv4 = ((family != AF_INET6) || (flags & AI_V4MAPPED));
2032 wantv6 = (family != AF_INET);
2033 }
2034
2035 if (err != NULL) *err = SI_STATUS_NO_ERROR;
2036
2037 if (proc < 0)
2038 {
2039 status = LI_DSLookupGetProcedureNumber("gethostbyname_service", &proc);
2040 if (status != KERN_SUCCESS)
2041 {
2042 if (err != NULL) *err = SI_STATUS_EAI_SYSTEM;
2043 return NULL;
2044 }
2045 }
2046
2047 /* look up canonical name of numeric host */
2048 if ((numerichost == 1) && (flags & AI_CANONNAME) && (node != NULL))
2049 {
2050 item = si_host_byaddr(si, node, family, NULL, NULL);
2051 if (item != NULL)
2052 {
2053 h = (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
2054 h_name = strdup(h->h_name);
2055 si_item_release(item);
2056 }
2057 }
2058
2059 if (numericserv == 1)
2060 {
2061 s_port = *(int16_t *)serv;
2062 }
2063
2064 if ((numericserv == 0) || (numerichost == 0))
2065 {
2066 request = kvbuf_new();
2067 if (request != NULL)
2068 {
2069 kvbuf_add_dict(request);
2070
2071 if (numerichost == 0)
2072 {
2073 kvbuf_add_key(request, "name");
2074 kvbuf_add_val(request, node);
2075 kvbuf_add_key(request, "ipv4");
2076 kvbuf_add_val(request, wantv4 ? "1" : "0");
2077 kvbuf_add_key(request, "ipv6");
2078 kvbuf_add_val(request, wantv6 ? "1" : "0");
2079 }
2080
2081 if (numericserv == 0)
2082 {
2083 protoname = NULL;
2084 if (proto == IPPROTO_UDP) protoname = "udp";
2085 if (proto == IPPROTO_TCP) protoname = "tcp";
2086
2087 kvbuf_add_key(request, "s_name");
2088 kvbuf_add_val(request, serv);
2089 if (protoname != NULL)
2090 {
2091 kvbuf_add_key(request, "s_proto");
2092 kvbuf_add_val(request, protoname);
2093 }
2094 }
2095
2096 status = LI_DSLookupQuery(proc, request, &reply);
2097 kvbuf_free(request);
2098 }
2099 else
2100 {
2101 if (err != NULL) *err = SI_STATUS_EAI_SYSTEM;
2102 }
2103 }
2104
2105 if ((status != KERN_SUCCESS) || (reply == NULL))
2106 {
2107 free(h_name);
2108 return NULL;
2109 }
2110
2111 for (d = 0; d < reply->count; d++)
2112 {
2113 dict = reply->dict + d;
2114 kcount = dict->kcount;
2115
2116 for (k = 0; k < kcount; k++)
2117 {
2118 if (string_equal(dict->key[k], "h_name"))
2119 {
2120 if (dict->vcount[k] == 0) continue;
2121 h_name = strdup(dict->val[k][0]);
2122 }
2123 else if (string_equal(dict->key[k], "h_aliases"))
2124 {
2125 h_aliases_cnt = dict->vcount[k];
2126 h_aliases = (const char **)calloc(h_aliases_cnt, sizeof(char *));
2127 if (h_aliases == NULL) h_aliases_cnt = 0;
2128
2129 for (i = 0; i < h_aliases_cnt; ++i)
2130 {
2131 h_aliases[i] = dict->val[k][i];
2132 }
2133 }
2134 else if (wantv4 && (string_equal(dict->key[k], "h_ipv4_addr_list")))
2135 {
2136 a4_cnt = dict->vcount[k];
2137 a4 = calloc(a4_cnt, sizeof(struct in_addr));
2138 if (a4 == NULL) a4_cnt = 0;
2139
2140 for (i = 0; i < a4_cnt; ++i)
2141 {
2142 memset(&a4[i], 0, sizeof(struct in_addr));
2143 inet_pton(AF_INET, dict->val[k][i], &a4[i]);
2144 }
2145 }
2146 else if (wantv6 && (string_equal(dict->key[k], "h_ipv6_addr_list")))
2147 {
2148 a6_cnt = dict->vcount[k];
2149 a6 = calloc(a6_cnt, sizeof(struct in6_addr));
2150 if (a6 == NULL) a6_cnt = 0;
2151
2152 for (i = 0; i < a6_cnt; ++i)
2153 {
2154 memset(&a6[i], 0, sizeof(struct in6_addr));
2155 inet_pton(AF_INET6, dict->val[k][i], &a6[i]);
2156 }
2157 }
2158 else if (string_equal(dict->key[k], "s_name"))
2159 {
2160 if (dict->vcount[k] == 0) continue;
2161 s_name = dict->val[k][0];
2162 }
2163 else if (string_equal(dict->key[k], "s_port"))
2164 {
2165 if (dict->vcount[k] == 0) continue;
2166 s_port = atoi(dict->val[k][0]);
2167 }
2168 else if (string_equal(dict->key[k], "s_aliases"))
2169 {
2170 s_aliases_cnt = dict->vcount[k];
2171 s_aliases = (const char **)calloc(s_aliases_cnt+1, sizeof(char *));
2172 if (s_aliases == NULL) s_aliases_cnt = 0;
2173
2174 for (i = 0; i < s_aliases_cnt; ++i)
2175 {
2176 s_aliases[i] = dict->val[k][i];
2177 }
2178 }
2179 else if (string_equal(dict->key[k], "s_proto"))
2180 {
2181 if (dict->vcount[k] == 0) continue;
2182 s_proto = dict->val[k][0];
2183 }
2184 }
2185 }
2186
2187 kvarray_free(reply);
2188
2189 /* check if we actually got back what we wanted */
2190 if (((wantv4 || wantv6) && (a4_cnt == 0) && (a6_cnt == 0)) || ((serv != NULL) && (s_port == 0)))
2191 {
2192 if (err != NULL) *err = SI_STATUS_EAI_NONAME;
2193
2194 free(h_name);
2195 free(h_aliases);
2196 free(s_aliases);
2197 free(a4);
2198 free(a6);
2199
2200 return NULL;
2201 }
2202
2203 /*
2204 * Cache the service entry regardless of whether there is a host match.
2205 * This allows later modules to get the service entry quickly.
2206 * This should really be part of the general cache mechanism, but that's
2207 * not currently visible outside of the search module.
2208 */
2209 if ((s_name != NULL) && (s_port != 0))
2210 {
2211 port = htons(s_port);
2212
2213 item = pthread_getspecific(_ds_serv_cache_key);
2214 if (item != NULL)
2215 {
2216 s = (struct servent *)((uintptr_t)item + sizeof(si_item_t));
2217 if ((port != s->s_port) || string_not_equal(s_name, s->s_name))
2218 {
2219 si_item_release(item);
2220 item = NULL;
2221 }
2222 }
2223
2224 if (item == NULL)
2225 {
2226 item = LI_ils_create("L4488s*4s", (unsigned long)si, CATEGORY_SERVICE, 1, (uint64_t)1, (uint64_t)1, s_name, s_aliases, port, s_proto);
2227 pthread_setspecific(_ds_serv_cache_key, item);
2228 }
2229 }
2230
2231 /* Construct the addrinfo list from the returned addresses (if found). */
2232 out = NULL;
2233 for (i = 0; i < a6_cnt; i++)
2234 {
2235 list = si_addrinfo_list(si, flags, socktype, proto, NULL, &a6[i], s_port, scope, NULL, h_name);
2236 out = si_list_concat(out, list);
2237 si_list_release(list);
2238 }
2239
2240 for (i = 0; i < a4_cnt; i++)
2241 {
2242 list = si_addrinfo_list(si, flags, socktype, proto, &a4[i], NULL, s_port, 0, h_name, NULL);
2243 out = si_list_concat(out, list);
2244 si_list_release(list);
2245 }
2246
2247 free(h_name);
2248 free(h_aliases);
2249 free(s_aliases);
2250 free(a4);
2251 free(a6);
2252
2253 return out;
2254 }
2255
2256 static int
2257 ds_is_valid(si_mod_t *si, si_item_t *item)
2258 {
2259 si_mod_t *src;
2260 ds_si_private_t *pp;
2261 int status;
2262 uint32_t oldval, newval;
2263
2264 if (si == NULL) return 0;
2265 if (item == NULL) return 0;
2266 if (si->name == NULL) return 0;
2267 if (item->src == NULL) return 0;
2268
2269 pp = (ds_si_private_t *)si->private;
2270 if (pp == NULL) return 0;
2271
2272 src = (si_mod_t *)item->src;
2273
2274 if (src->name == NULL) return 0;
2275 if (string_not_equal(si->name, src->name)) return 0;
2276
2277 /* check global invalidation */
2278 oldval = item->validation_a;
2279 newval = -1;
2280 status = notify_peek(pp->notify_token_global, &newval);
2281 if (status != NOTIFY_STATUS_OK) return 0;
2282
2283 newval = ntohl(newval);
2284 if (oldval != newval) return 0;
2285
2286 oldval = item->validation_b;
2287 newval = -1;
2288 if (item->type == CATEGORY_USER) status = notify_peek(pp->notify_token_user, &newval);
2289 else if (item->type == CATEGORY_GROUP) status = notify_peek(pp->notify_token_group, &newval);
2290 else if (item->type == CATEGORY_HOST_IPV4) status = notify_peek(pp->notify_token_host, &newval);
2291 else if (item->type == CATEGORY_HOST_IPV6) status = notify_peek(pp->notify_token_host, &newval);
2292 else if (item->type == CATEGORY_SERVICE) status = notify_peek(pp->notify_token_service, &newval);
2293 else return 0;
2294
2295 if (status != NOTIFY_STATUS_OK) return 0;
2296
2297 newval = ntohl(newval);
2298 if (oldval != newval) return 0;
2299
2300 return 1;
2301 }
2302
2303 si_mod_t *
2304 si_module_static_ds(void)
2305 {
2306 static const struct si_mod_vtable_s ds_vtable =
2307 {
2308 .sim_is_valid = &ds_is_valid,
2309
2310 .sim_user_byname = &ds_user_byname,
2311 .sim_user_byuid = &ds_user_byuid,
2312 .sim_user_all = &ds_user_all,
2313
2314 .sim_group_byname = &ds_group_byname,
2315 .sim_group_bygid = &ds_group_bygid,
2316 .sim_group_all = &ds_group_all,
2317
2318 .sim_grouplist = &ds_grouplist,
2319
2320 .sim_netgroup_byname = &ds_netgroup_byname,
2321 .sim_in_netgroup = &ds_in_netgroup,
2322
2323 .sim_alias_byname = &ds_alias_byname,
2324 .sim_alias_all = &ds_alias_all,
2325
2326 .sim_host_byname = &ds_host_byname,
2327 .sim_host_byaddr = &ds_host_byaddr,
2328 .sim_host_all = &ds_host_all,
2329
2330 .sim_network_byname = &ds_network_byname,
2331 .sim_network_byaddr = &ds_network_byaddr,
2332 .sim_network_all = &ds_network_all,
2333
2334 .sim_service_byname = &ds_service_byname,
2335 .sim_service_byport = &ds_service_byport,
2336 .sim_service_all = &ds_service_all,
2337
2338 .sim_protocol_byname = &ds_protocol_byname,
2339 .sim_protocol_bynumber = &ds_protocol_bynumber,
2340 .sim_protocol_all = &ds_protocol_all,
2341
2342 .sim_rpc_byname = &ds_rpc_byname,
2343 .sim_rpc_bynumber = &ds_rpc_bynumber,
2344 .sim_rpc_all = &ds_rpc_all,
2345
2346 .sim_fs_byspec = &ds_fs_byspec,
2347 .sim_fs_byfile = &ds_fs_byfile,
2348 .sim_fs_all = &ds_fs_all,
2349
2350 .sim_mac_byname = &ds_mac_byname,
2351 .sim_mac_bymac = &ds_mac_bymac,
2352
2353 /* si_mac_all not supported */
2354 .sim_mac_all = NULL,
2355
2356 .sim_addrinfo = &ds_addrinfo,
2357 };
2358
2359 static si_mod_t si =
2360 {
2361 .vers = 1,
2362 .refcount = 1,
2363 .flags = SI_MOD_FLAG_STATIC,
2364
2365 .private = NULL,
2366 .vtable = &ds_vtable,
2367 };
2368
2369 static dispatch_once_t once;
2370 dispatch_once(&once, ^{
2371 pthread_key_create(&_ds_serv_cache_key, _ds_serv_cache_free);
2372
2373 si.name = strdup("ds");
2374 ds_si_private_t *pp = calloc(1, sizeof(ds_si_private_t));
2375
2376 if (pp != NULL)
2377 {
2378 pp->notify_token_global = -1;
2379 pp->notify_token_user = -1;
2380 pp->notify_token_group = -1;
2381 pp->notify_token_host = -1;
2382 pp->notify_token_service = -1;
2383 }
2384
2385 /*
2386 * Don't register for notifications if the cache is disabled.
2387 * notifyd (notably) disables the cache to prevent deadlocks.
2388 */
2389 if (gL1CacheEnabled != 0)
2390 {
2391 /*
2392 * Errors in registering for cache invalidation notifications are ignored.
2393 * If there are failures, the tokens remain set to -1 which just causes
2394 * cached items to be invalidated.
2395 */
2396 notify_register_check(kNotifyDSCacheInvalidation, &(pp->notify_token_global));
2397 notify_register_check(kNotifyDSCacheInvalidationUser, &(pp->notify_token_user));
2398 notify_register_check(kNotifyDSCacheInvalidationGroup, &(pp->notify_token_group));
2399 notify_register_check(kNotifyDSCacheInvalidationHost, &(pp->notify_token_host));
2400 notify_register_check(kNotifyDSCacheInvalidationService, &(pp->notify_token_service));
2401 }
2402
2403 si.private = pp;
2404 });
2405
2406 return &si;
2407 }
2408
2409 #endif /* DS_AVAILABLE */