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