Libinfo-542.40.3.tar.gz
[apple/libinfo.git] / lookup.subproj / file_module.c
1 /*
2 * Copyright (c) 2008-2015 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file 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 file 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 * file.
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 <si_module.h>
25 #include <paths.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <time.h>
30 #include <dirent.h>
31 #include <errno.h>
32 #include <notify.h>
33 #include <pthread.h>
34 #include <arpa/inet.h>
35 #include <sys/param.h>
36 #include <sys/mount.h>
37 #include <sys/stat.h>
38 #include <ils.h>
39 #include <dispatch/dispatch.h>
40 #include <TargetConditionals.h>
41 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
42 #include <sys/sysctl.h>
43 #include <apfs/apfs_sysctl.h>
44 #endif
45
46 /* notify SPI */
47 uint32_t notify_peek(int token, uint32_t *val);
48
49 extern uint32_t gL1CacheEnabled;
50
51 /* These really should be in netdb.h & etc. */
52 #define _PATH_RPCS "/etc/rpc"
53 #define _PATH_ALIASES "/etc/aliases"
54 #define _PATH_ETHERS "/etc/ethers"
55 #define _PATH_NETGROUP "/etc/netgroup"
56
57 static dispatch_once_t rootfs_once;
58 static si_item_t *rootfs = NULL;
59
60 #define CHUNK 256
61 #define FNG_MEM 0x00000010
62 #define FNG_GRP 0x00000020
63
64 #define forever for(;;)
65
66 #define VALIDATION_PASSWD 0
67 #define VALIDATION_MASTER_PASSWD 1
68 #define VALIDATION_GROUP 2
69 #define VALIDATION_NETGROUP 3
70 #define VALIDATION_ALIASES 4
71 #define VALIDATION_HOSTS 5
72 #define VALIDATION_NETWORKS 6
73 #define VALIDATION_SERVICES 7
74 #define VALIDATION_PROTOCOLS 8
75 #define VALIDATION_RPC 9
76 #define VALIDATION_FSTAB 10
77 #define VALIDATION_ETHERS 11
78 #define VALIDATION_COUNT 12
79
80 #define VALIDATION_MASK_PASSWD 0x00000001
81 #define VALIDATION_MASK_MASTER_PASSWD 0x00000002
82 #define VALIDATION_MASK_MASK_GROUP 0x00000004
83 #define VALIDATION_MASK_NETGROUP 0x00000008
84 #define VALIDATION_MASK_ALIASES 0x00000010
85 #define VALIDATION_MASK_HOSTS 0x00000020
86 #define VALIDATION_MASK_NETWORKS 0x00000040
87 #define VALIDATION_MASK_SERVICES 0x00000080
88 #define VALIDATION_MASK_PROTOCOLS 0x00000100
89 #define VALIDATION_MASK_RPC 0x00000200
90 #define VALIDATION_MASK_FSTAB 0x00000400
91 #define VALIDATION_MASK_ETHERS 0x00000800
92
93 typedef struct file_netgroup_member_s
94 {
95 uint32_t flags;
96 char *host;
97 char *user;
98 char *domain;
99 struct file_netgroup_member_s *next;
100 } file_netgroup_member_t;
101
102 typedef struct file_netgroup_s
103 {
104 char *name;
105 uint32_t flags;
106 file_netgroup_member_t *members;
107 struct file_netgroup_s *next;
108 } file_netgroup_t;
109
110 typedef struct
111 {
112 uint32_t validation_notify_mask;
113 int notify_token[VALIDATION_COUNT];
114 file_netgroup_t *file_netgroup_cache;
115 uint64_t netgroup_validation_a;
116 uint64_t netgroup_validation_b;
117 } file_si_private_t;
118
119 static pthread_mutex_t file_mutex = PTHREAD_MUTEX_INITIALIZER;
120
121 static char *
122 _fsi_copy_string(char *s)
123 {
124 int len;
125 char *t;
126
127 if (s == NULL) return NULL;
128
129 len = strlen(s) + 1;
130 t = malloc(len);
131 if (t == NULL) return NULL;
132
133 bcopy(s, t, len);
134 return t;
135 }
136
137 static char **
138 _fsi_append_string(char *s, char **l)
139 {
140 int i, len;
141
142 if (s == NULL) return l;
143 if (l != NULL) {
144 for (i = 0; l[i] != NULL; i++);
145 len = i;
146 } else {
147 len = 0;
148 }
149
150 l = (char **) reallocf(l, (len + 2) * sizeof(char *));
151 if (l == NULL) return NULL;
152
153 l[len] = s;
154 l[len + 1] = NULL;
155 return l;
156 }
157
158 char **
159 _fsi_tokenize(char *data, const char *sep, int trailing_empty, int *ntokens)
160 {
161 char **tokens;
162 int p, i, start, end, more, len, end_on_sep;
163 int scanning;
164
165 tokens = NULL;
166 end_on_sep = 0;
167
168 if (data == NULL) return NULL;
169
170 if (ntokens != NULL) *ntokens = 0;
171 if (sep == NULL)
172 {
173 tokens = _fsi_append_string(data, tokens);
174 if (ntokens != NULL) *ntokens = *ntokens + 1;
175 return tokens;
176 }
177
178 len = strlen(sep);
179 p = 0;
180
181 while (data[p] != '\0')
182 {
183 end_on_sep = 1;
184 /* skip leading white space */
185 while ((data[p] == ' ') || (data[p] == '\t') || (data[p] == '\n')) p++;
186
187 /* check for end of line */
188 if (data[p] == '\0') break;
189
190 /* scan for separator */
191 start = p;
192 end = p;
193 scanning = 1;
194 end_on_sep = 0;
195
196 while (scanning == 1)
197 {
198 if (data[p] == '\0') break;
199
200 for (i = 0; i < len; i++)
201 {
202 if (data[p] == sep[i])
203 {
204 scanning = 0;
205 end_on_sep = 1;
206 break;
207 }
208 }
209
210 /* end is last non-whitespace character */
211 if ((scanning == 1) && (data[p] != ' ') && (data[p] != '\t') && (data[p] != '\n')) end = p;
212
213 p += scanning;
214 }
215
216 /* see if there's data left after p */
217 more = 0;
218 if (data[p] != '\0') more = 1;
219
220 /* set the character following the token to nul */
221 if (start == p) data[p] = '\0';
222 else data[end + 1] = '\0';
223
224 tokens = _fsi_append_string(data + start, tokens);
225 if (ntokens != NULL) *ntokens = *ntokens + 1;
226 p += more;
227 }
228
229 if ((end_on_sep == 1) && (trailing_empty != 0))
230 {
231 /* if the scan ended on an empty token, add a null string */
232 tokens = _fsi_append_string(data + p, tokens);
233 if (ntokens != NULL) *ntokens = *ntokens + 1;
234 }
235
236 return tokens;
237 }
238
239 char *
240 _fsi_get_line(FILE *fp)
241 {
242 char s[4096];
243 char *x, *out;
244
245 s[0] = '\0';
246
247 x = fgets(s, sizeof(s), fp);
248 if ((x == NULL) || (s[0] == '\0')) return NULL;
249
250 if (s[0] != '#') s[strlen(s) - 1] = '\0';
251
252 out = _fsi_copy_string(s);
253 return out;
254 }
255
256 static const char *
257 _fsi_validation_path(int vtype)
258 {
259 if (vtype == VALIDATION_PASSWD) return _PATH_PASSWD;
260 else if (vtype == VALIDATION_MASTER_PASSWD) return _PATH_MASTERPASSWD;
261 else if (vtype == VALIDATION_GROUP) return _PATH_GROUP;
262 else if (vtype == VALIDATION_NETGROUP) return _PATH_NETGROUP;
263 else if (vtype == VALIDATION_ALIASES) return _PATH_ALIASES;
264 else if (vtype == VALIDATION_HOSTS) return _PATH_HOSTS;
265 else if (vtype == VALIDATION_NETWORKS) return _PATH_NETWORKS;
266 else if (vtype == VALIDATION_SERVICES) return _PATH_SERVICES;
267 else if (vtype == VALIDATION_PROTOCOLS) return _PATH_PROTOCOLS;
268 else if (vtype == VALIDATION_RPC) return _PATH_RPCS;
269 else if (vtype == VALIDATION_FSTAB) return _PATH_FSTAB;
270 else if (vtype == VALIDATION_ETHERS) return _PATH_ETHERS;
271
272 return NULL;
273 }
274
275 static void
276 _fsi_get_validation(si_mod_t *si, int vtype, const char *path, FILE *f, uint64_t *a, uint64_t *b)
277 {
278 struct stat sb;
279 file_si_private_t *pp;
280 uint32_t peek, bit;
281 int status;
282
283 if (a != NULL) *a = 0;
284 if (b != NULL) *b = 0;
285
286 if (si == NULL) return;
287 if (path == NULL) return;
288 if (gL1CacheEnabled == 0) return;
289
290 pp = (file_si_private_t *)si->private;
291 if (pp == NULL) return;
292
293 if (vtype >= VALIDATION_COUNT) return;
294
295 bit = 1 << vtype;
296 if (bit & pp->validation_notify_mask)
297 {
298 /* use notify validation for this type */
299 if (pp->notify_token[vtype] < 0)
300 {
301 char *str = NULL;
302 asprintf(&str, "com.apple.system.info:%s", path);
303 if (str == NULL) return;
304
305 status = notify_register_check(str, &(pp->notify_token[vtype]));
306 free(str);
307 }
308
309 if (a != NULL)
310 {
311 status = notify_peek(pp->notify_token[vtype], &peek);
312 if (status == NOTIFY_STATUS_OK) *a = ntohl(peek);
313 }
314
315 if (b != NULL) *b = vtype;
316 }
317 else
318 {
319 /* use stat() and last mod time for this type */
320 memset(&sb, 0, sizeof(struct stat));
321 if (f != NULL)
322 {
323 if (fstat(fileno(f), &sb) == 0)
324 {
325 if (a != NULL) *a = sb.st_mtimespec.tv_sec;
326 if (b != NULL) *b = sb.st_mtimespec.tv_nsec;
327 }
328 }
329 else
330 {
331 path = _fsi_validation_path(vtype);
332 if (path != NULL)
333 {
334 memset(&sb, 0, sizeof(struct stat));
335 if (stat(path, &sb) == 0)
336 {
337 if (a != NULL) *a = sb.st_mtimespec.tv_sec;
338 if (b != NULL) *b = sb.st_mtimespec.tv_nsec;
339 }
340 }
341 }
342 }
343 }
344
345 static int
346 _fsi_validate(si_mod_t *si, int cat, uint64_t va, uint64_t vb)
347 {
348 #if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
349 struct stat sb;
350 const char *path;
351 uint32_t item_val, curr_val, vtype;
352 file_si_private_t *pp;
353 int status;
354 #endif
355
356 if (si == NULL) return 0;
357
358 #if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
359 /* /etc is on a read-only filesystem, so no validation is required */
360
361 pp = (file_si_private_t *)si->private;
362 if (pp == NULL) return 0;
363
364 vtype = UINT32_MAX;
365 switch (cat)
366 {
367 case CATEGORY_USER:
368 {
369 if (geteuid() == 0) vtype = VALIDATION_MASTER_PASSWD;
370 else vtype = VALIDATION_PASSWD;
371 break;
372 }
373 case CATEGORY_GROUP:
374 {
375 vtype = VALIDATION_GROUP;
376 break;
377 }
378 case CATEGORY_GROUPLIST:
379 {
380 vtype = VALIDATION_GROUP;
381 break;
382 }
383 case CATEGORY_NETGROUP:
384 {
385 vtype = VALIDATION_NETGROUP;
386 break;
387 }
388 case CATEGORY_ALIAS:
389 {
390 vtype = VALIDATION_ALIASES;
391 break;
392 }
393 case CATEGORY_HOST_IPV4:
394 {
395 vtype = VALIDATION_HOSTS;
396 break;
397 }
398 case CATEGORY_HOST_IPV6:
399 {
400 vtype = VALIDATION_HOSTS;
401 break;
402 }
403 case CATEGORY_NETWORK:
404 {
405 vtype = VALIDATION_NETWORKS;
406 break;
407 }
408 case CATEGORY_SERVICE:
409 {
410 vtype = VALIDATION_SERVICES;
411 break;
412 }
413 case CATEGORY_PROTOCOL:
414 {
415 vtype = VALIDATION_PROTOCOLS;
416 break;
417 }
418 case CATEGORY_RPC:
419 {
420 vtype = VALIDATION_RPC;
421 break;
422 }
423 case CATEGORY_FS:
424 {
425 vtype = VALIDATION_FSTAB;
426 break;
427 }
428 case CATEGORY_MAC:
429 {
430 vtype = VALIDATION_ETHERS;
431 break;
432 }
433 default: return 0;
434 }
435
436 if (pp->notify_token[vtype] < 0)
437 {
438 path = _fsi_validation_path(vtype);
439 if (path == NULL) return 0;
440
441 memset(&sb, 0, sizeof(struct stat));
442 if (stat(path, &sb) != 0) return 0;
443 if (va != sb.st_mtimespec.tv_sec) return 0;
444 if (vb != sb.st_mtimespec.tv_nsec) return 0;
445 }
446 else
447 {
448 item_val = va;
449 curr_val = -1;
450 status = notify_peek(pp->notify_token[vtype], &curr_val);
451 if (status != NOTIFY_STATUS_OK) return 0;
452
453 curr_val = ntohl(curr_val);
454 if (item_val != curr_val) return 0;
455 }
456 #endif
457
458 return 1;
459 }
460
461 /* netgroup support */
462 static char *
463 _fsi_append_char_to_line(char c, char *buf, size_t *x)
464 {
465 if (x == NULL) return NULL;
466
467 if (buf == NULL) *x = 0;
468
469 if ((*x % CHUNK) == 0)
470 {
471 buf = reallocf(buf, *x + CHUNK);
472 if (buf == NULL) return NULL;
473
474 memset(buf + *x, 0, CHUNK);
475 }
476
477 buf[*x] = c;
478 *x = *x + 1;
479
480 return buf;
481 }
482
483 static char *
484 _fsi_read_netgroup_line(FILE *f)
485 {
486 char *out = NULL;
487 size_t x = 0;
488 int white = 0;
489 int paren = 0;
490
491 if (f == NULL) return NULL;
492 forever
493 {
494 int c = getc(f);
495
496 if (c == EOF)
497 {
498 if (out == NULL) return NULL;
499 return _fsi_append_char_to_line('\0', out, &x);
500 }
501
502 if (c == '\n') return _fsi_append_char_to_line('\0', out, &x);
503 if (c == '(') paren = 1;
504 else if (c == ')') paren = 0;
505
506 if ((c == ' ') || (c == '\t'))
507 {
508 if ((white == 0) && (paren == 0)) out = _fsi_append_char_to_line(' ', out, &x);
509 white = 1;
510 }
511 else if (c == '\\')
512 {
513 forever
514 {
515 c = getc(f);
516 if (c == EOF) return _fsi_append_char_to_line('\0', out, &x);
517 if (c == '\n') break;
518 }
519 }
520 else
521 {
522 out = _fsi_append_char_to_line(c, out, &x);
523 white = 0;
524 }
525 }
526 }
527
528 static file_netgroup_t *
529 _fsi_find_netgroup(file_netgroup_t **list, const char *name, int create)
530 {
531 file_netgroup_t *n;
532
533 if (list == NULL) return NULL;
534
535 for (n = *list; n != NULL; n = n->next)
536 {
537 if (!strcmp(name, n->name)) return n;
538 }
539
540 if (create == 0) return NULL;
541
542 n = (file_netgroup_t *)calloc(1, sizeof(file_netgroup_t));
543 if (n == NULL) return NULL;
544
545 n->name = strdup(name);
546
547 n->next = *list;
548 *list = n;
549 return n;
550 }
551
552 void
553 _fsi_free_file_netgroup(file_netgroup_t *n)
554 {
555 file_netgroup_member_t *m;
556
557 if (n == NULL) return;
558 free(n->name);
559
560 m = n->members;
561 while (m != NULL)
562 {
563 file_netgroup_member_t *x = m;
564 m = m->next;
565 free(x->host);
566 free(x->user);
567 free(x->domain);
568 free(x);
569 }
570
571 free(n);
572 }
573
574 static void
575 _fsi_add_netgroup_group(file_netgroup_t *n, char *grp)
576 {
577 file_netgroup_member_t *g;
578
579 if (n == NULL) return;
580
581 g = (file_netgroup_member_t *)calloc(1, sizeof(file_netgroup_member_t));
582 if (g == NULL) return;
583
584 g->flags = FNG_GRP;
585 g->host = strdup(grp);
586
587 g->next = n->members;
588 n->members = g;
589
590 return;
591 }
592
593 static void
594 _fsi_add_netgroup_member(file_netgroup_t *n, char *mem)
595 {
596 char **tokens;
597 file_netgroup_member_t *m;
598 int ntokens;
599
600 if (n == NULL) return;
601
602 m = (file_netgroup_member_t *)calloc(1, sizeof(file_netgroup_member_t));
603 if (m == NULL) return;
604
605 tokens = _fsi_tokenize(mem + 1, ",)", 0, &ntokens);
606
607 if (tokens == NULL)
608 {
609 free(m);
610 return;
611 }
612
613 if ((ntokens > 0) && (tokens[0][0] != '\0')) m->host = strdup(tokens[0]);
614 if ((ntokens > 1) && (tokens[1][0] != '\0')) m->user = strdup(tokens[1]);
615 if ((ntokens > 2) && (tokens[2][0] != '\0')) m->domain = strdup(tokens[2]);
616
617 free(tokens);
618
619 m->flags = FNG_MEM;
620 m->next = n->members;
621 n->members = m;
622 }
623
624 static file_netgroup_t *
625 _fsi_process_netgroup_line(file_netgroup_t **pass1, char *line)
626 {
627 file_netgroup_t *n;
628 char **tokens;
629 int i, ntokens = 0;
630
631 tokens = _fsi_tokenize(line, " ", 0, &ntokens);
632 if (tokens == NULL) return NULL;
633 if (tokens[0] == NULL)
634 {
635 free(tokens);
636 return NULL;
637 }
638
639 n = _fsi_find_netgroup(pass1, tokens[0], 1);
640
641 for (i = 1; tokens[i] != NULL; i++)
642 {
643 if (tokens[i][0] == '(') _fsi_add_netgroup_member(n, tokens[i]);
644 else if (tokens[i][0] != '\0') _fsi_add_netgroup_group(n, tokens[i]);
645 }
646
647 free(tokens);
648 return n;
649 }
650
651 static void
652 _fsi_flatten_netgroup(file_netgroup_t *pass1, file_netgroup_t **top, file_netgroup_t *n, file_netgroup_member_t *m)
653 {
654 if (n == NULL) return;
655
656 if (n->flags == 1) return;
657 n->flags = 1;
658
659 if (*top == NULL)
660 {
661 *top = (file_netgroup_t *)calloc(1, sizeof(file_netgroup_t));
662 if (*top == NULL) return;
663 (*top)->name = strdup(n->name);
664 if ((*top)->name == NULL)
665 {
666 free(*top);
667 *top = NULL;
668 return;
669 }
670 }
671
672 while (m!= NULL)
673 {
674 if (m->flags & FNG_MEM)
675 {
676 file_netgroup_member_t *x = (file_netgroup_member_t *)calloc(1, sizeof(file_netgroup_member_t));
677 if (x == NULL) return;
678
679 x->flags = FNG_MEM;
680 if (m->host != NULL) x->host = strdup(m->host);
681 if (m->user != NULL) x->user = strdup(m->user);
682 if (m->domain != NULL) x->domain = strdup(m->domain);
683
684 x->next = (*top)->members;
685 (*top)->members = x;
686 }
687 else
688 {
689 file_netgroup_t *g = _fsi_find_netgroup(&pass1, m->host, 0);
690 if (g == NULL) continue;
691
692 _fsi_flatten_netgroup(pass1, top, g, g->members);
693 }
694
695 m = m->next;
696 }
697 }
698
699 static void
700 _fsi_check_netgroup_cache(si_mod_t *si)
701 {
702 file_netgroup_t *p1, *n, *x, *a;
703 char *line;
704 FILE *f;
705 file_si_private_t *pp;
706
707 if (si == NULL) return;
708
709 pp = (file_si_private_t *)si->private;
710 if (pp == NULL) return;
711
712 pthread_mutex_lock(&file_mutex);
713
714 if (_fsi_validate(si, CATEGORY_NETGROUP, pp->netgroup_validation_a, pp->netgroup_validation_b))
715 {
716 pthread_mutex_unlock(&file_mutex);
717 return;
718 }
719
720 n = pp->file_netgroup_cache;
721 while (n != NULL)
722 {
723 x = n;
724 n = n->next;
725 _fsi_free_file_netgroup(x);
726 }
727
728 pp->file_netgroup_cache = NULL;
729
730 f = fopen(_PATH_NETGROUP, "r");
731 if (f == NULL)
732 {
733 pthread_mutex_unlock(&file_mutex);
734 return;
735 }
736
737 _fsi_get_validation(si, VALIDATION_NETGROUP, _PATH_NETGROUP, f, &(pp->netgroup_validation_a), &(pp->netgroup_validation_b));
738
739 p1 = NULL;
740
741 line = _fsi_read_netgroup_line(f);
742 while (line != NULL)
743 {
744 n = _fsi_process_netgroup_line(&p1, line);
745
746 free(line);
747 line = _fsi_read_netgroup_line(f);
748 }
749
750 fclose(f);
751
752 for (n = p1; n != NULL; n = n->next)
753 {
754 a = NULL;
755 _fsi_flatten_netgroup(p1, &a, n, n->members);
756 for (x = p1; x != NULL; x = x->next) x->flags = 0;
757
758 if (a != NULL)
759 {
760 a->next = pp->file_netgroup_cache;
761 pp->file_netgroup_cache = a;
762 }
763 }
764
765 n = p1;
766 while (n != NULL)
767 {
768 x = n;
769 n = n->next;
770 _fsi_free_file_netgroup(x);
771 }
772
773 pthread_mutex_unlock(&file_mutex);
774 }
775
776 /* USERS */
777
778 static si_item_t *
779 _fsi_parse_user(si_mod_t *si, const char *name, uid_t uid, int which, char *data, int format, uint64_t va, uint64_t vb)
780 {
781 char **tokens;
782 int ntokens, match;
783 time_t change, expire;
784 si_item_t *item;
785 uid_t xuid;
786
787 if (data == NULL) return NULL;
788
789 ntokens = 0;
790 tokens = _fsi_tokenize(data, ":", 1, &ntokens);
791 if (((format == 0) && (ntokens != 10)) || ((format == 1) && (ntokens != 7)))
792 {
793 free(tokens);
794 return NULL;
795 }
796
797 xuid = atoi(tokens[2]);
798 match = 0;
799
800 /* XXX MATCH GECOS? XXX*/
801 if (which == SEL_ALL) match = 1;
802 else if ((which == SEL_NAME) && (string_equal(name, tokens[0]))) match = 1;
803 else if ((which == SEL_NUMBER) && (uid == xuid)) match = 1;
804
805 if (match == 0)
806 {
807 free(tokens);
808 return NULL;
809 }
810
811 if (format == 0)
812 {
813 /* master.passwd: name[0] passwd[1] uid[2] gid[3] class[4] change[5] expire[6] gecos[7] dir[8] shell[9] */
814 /* struct pwd: name[0] passwd[1] uid[2] gid[3] change[5] class[4] gecos[7] dir[8] shell[9] expire[6] */
815 change = atoi(tokens[5]);
816 expire = atoi(tokens[6]);
817 item = (si_item_t *)LI_ils_create("L4488ss44LssssL", (unsigned long)si, CATEGORY_USER, 1, va, vb, tokens[0], tokens[1], xuid, atoi(tokens[3]), change, tokens[4], tokens[7], tokens[8], tokens[9], expire);
818 }
819 else
820 {
821 /* passwd: name[0] passwd[1] uid[2] gid[3] gecos[4] dir[5] shell[6] */
822 /* struct pwd: name[0] passwd[1] uid[2] gid[3] change[-] class[-] gecos[4] dir[5] shell[6] expire[-] */
823 item = (si_item_t *)LI_ils_create("L4488ss44LssssL", (unsigned long)si, CATEGORY_USER, 1, va, vb, tokens[0], tokens[1], xuid, atoi(tokens[3]), 0, "", tokens[4], tokens[5], tokens[6], 0);
824 }
825
826 free(tokens);
827 return item;
828 }
829
830 static void *
831 _fsi_get_user(si_mod_t *si, const char *name, uid_t uid, int which)
832 {
833 char *line;
834 si_item_t *item;
835 int fmt;
836 FILE *f;
837 si_list_t *all;
838 uint64_t va, vb;
839
840 if ((which == SEL_NAME) && (name == NULL)) return NULL;
841
842 all = NULL;
843 f = NULL;
844 fmt = 0;
845 va = 0;
846 vb = 0;
847
848 if (geteuid() == 0)
849 {
850 f = fopen(_PATH_MASTERPASSWD, "r");
851 _fsi_get_validation(si, VALIDATION_MASTER_PASSWD, _PATH_MASTERPASSWD, f, &va, &vb);
852 }
853 else
854 {
855 f = fopen(_PATH_PASSWD, "r");
856 _fsi_get_validation(si, VALIDATION_PASSWD, _PATH_PASSWD, f, &va, &vb);
857 fmt = 1;
858 }
859
860 if (f == NULL) return NULL;
861
862
863 forever
864 {
865 line = _fsi_get_line(f);
866 if (line == NULL) break;
867
868 if (line[0] == '#')
869 {
870 free(line);
871 line = NULL;
872 continue;
873 }
874
875 item = _fsi_parse_user(si, name, uid, which, line, fmt, va, vb);
876 free(line);
877 line = NULL;
878
879 if (item == NULL) continue;
880
881 if (which == SEL_ALL)
882 {
883 all = si_list_add(all, item);
884 si_item_release(item);
885 continue;
886 }
887
888 fclose(f);
889 return item;
890 }
891 fclose(f);
892 return all;
893 }
894
895 /* GROUPS */
896
897 static si_item_t *
898 _fsi_parse_group(si_mod_t *si, const char *name, gid_t gid, int which, char *data, uint64_t va, uint64_t vb)
899 {
900 char **tokens, **members;
901 int ntokens, match;
902 si_item_t *item;
903 gid_t xgid;
904
905 if (data == NULL) return NULL;
906
907 ntokens = 0;
908 tokens = _fsi_tokenize(data, ":", 1, &ntokens);
909 if (ntokens != 4)
910 {
911 free(tokens);
912 return NULL;
913 }
914
915 xgid = atoi(tokens[2]);
916 match = 0;
917
918 if (which == SEL_ALL) match = 1;
919 else if ((which == SEL_NAME) && (string_equal(name, tokens[0]))) match = 1;
920 else if ((which == SEL_NUMBER) && (gid == xgid)) match = 1;
921
922 if (match == 0)
923 {
924 free(tokens);
925 return NULL;
926 }
927
928 ntokens = 0;
929 members = _fsi_tokenize(tokens[3], ",", 1, &ntokens);
930
931 item = (si_item_t *)LI_ils_create("L4488ss4*", (unsigned long)si, CATEGORY_GROUP, 1, va, vb, tokens[0], tokens[1], xgid, members);
932
933 free(tokens);
934 free(members);
935
936 return item;
937 }
938
939 static void *
940 _fsi_get_group(si_mod_t *si, const char *name, gid_t gid, int which)
941 {
942 char *line;
943 si_item_t *item;
944 FILE *f;
945 si_list_t *all;
946 uint64_t va, vb;
947
948 if ((which == SEL_NAME) && (name == NULL)) return NULL;
949
950 all = NULL;
951 f = NULL;
952
953 f = fopen(_PATH_GROUP, "r");
954 if (f == NULL) return NULL;
955
956 _fsi_get_validation(si, VALIDATION_GROUP, _PATH_GROUP, f, &va, &vb);
957
958 forever
959 {
960 line = _fsi_get_line(f);
961 if (line == NULL) break;
962
963 if (line[0] == '#')
964 {
965 free(line);
966 line = NULL;
967 continue;
968 }
969
970 item = _fsi_parse_group(si, name, gid, which, line, va, vb);
971 free(line);
972 line = NULL;
973
974 if (item == NULL) continue;
975
976 if (which == SEL_ALL)
977 {
978 all = si_list_add(all, item);
979 si_item_release(item);
980 continue;
981 }
982
983 fclose(f);
984 return item;
985 }
986
987 fclose(f);
988 return all;
989 }
990
991 static void *
992 _fsi_get_grouplist(si_mod_t *si, const char *user)
993 {
994 char **tokens, **members;
995 int ntokens, i, match, gidcount;
996 char *line;
997 si_item_t *item;
998 FILE *f;
999 uint64_t va, vb;
1000 gid_t gid, basegid;
1001 gid_t *gidlist;
1002 struct passwd *pw;
1003
1004 if (user == NULL) return NULL;
1005
1006 gidlist = NULL;
1007 gidcount = 0;
1008 f = NULL;
1009 basegid = -1;
1010
1011 item = si->vtable->sim_user_byname(si, user);
1012 if (item != NULL)
1013 {
1014 pw = (struct passwd *)((uintptr_t)item + sizeof(si_item_t));
1015 basegid = pw->pw_gid;
1016 si_item_release(item);
1017 item = NULL;
1018 }
1019
1020 f = fopen(_PATH_GROUP, "r");
1021 if (f == NULL) return NULL;
1022
1023 _fsi_get_validation(si, VALIDATION_GROUP, _PATH_GROUP, f, &va, &vb);
1024
1025 forever
1026 {
1027 line = _fsi_get_line(f);
1028 if (line == NULL) break;
1029
1030 if (line[0] == '#')
1031 {
1032 free(line);
1033 line = NULL;
1034 continue;
1035 }
1036
1037 ntokens = 0;
1038 tokens = _fsi_tokenize(line, ":", 1, &ntokens);
1039 if (ntokens != 4)
1040 {
1041 free(tokens);
1042 continue;
1043 }
1044
1045 ntokens = 0;
1046 members = _fsi_tokenize(tokens[3], ",", 1, &ntokens);
1047
1048 match = 0;
1049 gid = -2;
1050
1051 for (i = 0; i < ntokens; i++)
1052 {
1053 if (string_equal(user, members[i]))
1054 {
1055 gid = atoi(tokens[2]);
1056 match = 1;
1057 break;
1058 }
1059 }
1060
1061 free(tokens);
1062 free(members);
1063 free(line);
1064 line = NULL;
1065
1066 if (match == 1)
1067 {
1068 gidlist = (gid_t *) reallocf(gidlist, (gidcount + 1) * sizeof(gid_t));
1069 if (gidlist == NULL)
1070 {
1071 gidcount = 0;
1072 break;
1073 }
1074
1075 gidlist[gidcount++] = gid;
1076 }
1077 }
1078
1079 fclose(f);
1080
1081 if (gidcount != 0) {
1082 item = (si_item_t *)LI_ils_create("L4488s4@", (unsigned long)si, CATEGORY_GROUPLIST, 1, va, vb, user, gidcount,
1083 gidcount * sizeof(gid_t), gidlist);
1084 }
1085
1086 free(gidlist);
1087
1088 return item;
1089 }
1090
1091 /* ALIASES */
1092
1093 static si_item_t *
1094 _fsi_parse_alias(si_mod_t *si, const char *name, int which, char *data, uint64_t va, uint64_t vb)
1095 {
1096 char **tokens, **members;
1097 int ntokens, match;
1098 si_item_t *item;
1099
1100 if (data == NULL) return NULL;
1101
1102 ntokens = 0;
1103 tokens = _fsi_tokenize(data, ":", 1, &ntokens);
1104 if (ntokens < 2)
1105 {
1106 free(tokens);
1107 return NULL;
1108 }
1109
1110 match = 0;
1111
1112 if (which == SEL_ALL) match = 1;
1113 else if (string_equal(name, tokens[0])) match = 1;
1114
1115 if (match == 0)
1116 {
1117 free(tokens);
1118 return NULL;
1119 }
1120
1121 ntokens = 0;
1122 members = _fsi_tokenize(tokens[1], ",", 1, &ntokens);
1123
1124 item = (si_item_t *)LI_ils_create("L4488s4*4", (unsigned long)si, CATEGORY_ALIAS, 1, va, vb, tokens[0], ntokens, members, 1);
1125
1126 free(tokens);
1127 free(members);
1128
1129 return item;
1130 }
1131
1132 static void *
1133 _fsi_get_alias(si_mod_t *si, const char *name, int which)
1134 {
1135 char *line;
1136 si_item_t *item;
1137 FILE *f;
1138 si_list_t *all;
1139 uint64_t va, vb;
1140
1141 if ((which == SEL_NAME) && (name == NULL)) return NULL;
1142
1143 all = NULL;
1144 f = NULL;
1145
1146 f = fopen(_PATH_ALIASES, "r");
1147 if (f == NULL) return NULL;
1148
1149 _fsi_get_validation(si, VALIDATION_ALIASES, _PATH_ALIASES, f, &va, &vb);
1150
1151 forever
1152 {
1153 line = _fsi_get_line(f);
1154 if (line == NULL) break;
1155
1156 if (line[0] == '#')
1157 {
1158 free(line);
1159 line = NULL;
1160 continue;
1161 }
1162
1163 item = _fsi_parse_alias(si, name, which, line, va, vb);
1164 free(line);
1165 line = NULL;
1166
1167 if (item == NULL) continue;
1168
1169 if (which == SEL_ALL)
1170 {
1171 all = si_list_add(all, item);
1172 si_item_release(item);
1173 continue;
1174 }
1175
1176 fclose(f);
1177 return item;
1178 }
1179
1180 fclose(f);
1181 return all;
1182 }
1183
1184 /* ETHERS */
1185
1186 static si_item_t *
1187 _fsi_parse_ether(si_mod_t *si, const char *name, int which, char *data, uint64_t va, uint64_t vb)
1188 {
1189 char **tokens;
1190 char *cmac;
1191 int ntokens, match;
1192 si_item_t *item;
1193
1194 if (data == NULL) return NULL;
1195
1196 ntokens = 0;
1197 tokens = _fsi_tokenize(data, " \t", 1, &ntokens);
1198 if (ntokens != 2)
1199 {
1200 free(tokens);
1201 return NULL;
1202 }
1203
1204 cmac = si_standardize_mac_address(tokens[0]);
1205 if (cmac == NULL)
1206 {
1207 free(tokens);
1208 return NULL;
1209 }
1210
1211 match = 0;
1212 if (which == SEL_ALL) match = 1;
1213 else if ((which == SEL_NAME) && (string_equal(name, tokens[1]))) match = 1;
1214 else if ((which == SEL_NUMBER) && (string_equal(name, cmac))) match = 1;
1215
1216 if (match == 0)
1217 {
1218 free(tokens);
1219 free(cmac);
1220 return NULL;
1221 }
1222
1223 item = (si_item_t *)LI_ils_create("L4488ss", (unsigned long)si, CATEGORY_MAC, 1, va, vb, tokens[1], cmac);
1224
1225 free(tokens);
1226 free(cmac);
1227
1228 return item;
1229 }
1230
1231 static void *
1232 _fsi_get_ether(si_mod_t *si, const char *name, int which)
1233 {
1234 char *line, *cmac;
1235 si_item_t *item;
1236 FILE *f;
1237 si_list_t *all;
1238 uint64_t va, vb;
1239
1240 if ((which != SEL_ALL) && (name == NULL)) return NULL;
1241
1242 cmac = NULL;
1243 if (which == SEL_NUMBER)
1244 {
1245 cmac = si_standardize_mac_address(name);
1246 if (cmac == NULL) return NULL;
1247 }
1248
1249 all = NULL;
1250 f = NULL;
1251
1252 f = fopen(_PATH_ETHERS, "r");
1253 if (f == NULL) return NULL;
1254
1255 _fsi_get_validation(si, VALIDATION_ETHERS, _PATH_ETHERS, f, &va, &vb);
1256
1257 forever
1258 {
1259 line = _fsi_get_line(f);
1260 if (line == NULL) break;
1261
1262 if (line[0] == '#')
1263 {
1264 free(line);
1265 line = NULL;
1266 continue;
1267 }
1268
1269 item = NULL;
1270 if (which == SEL_NUMBER) item = _fsi_parse_ether(si, cmac, which, line, va, vb);
1271 else item = _fsi_parse_ether(si, name, which, line, va, vb);
1272
1273 free(line);
1274 line = NULL;
1275
1276 if (item == NULL) continue;
1277
1278 if (which == SEL_ALL)
1279 {
1280 all = si_list_add(all, item);
1281 si_item_release(item);
1282 continue;
1283 }
1284
1285 fclose(f);
1286 return item;
1287 }
1288
1289 fclose(f);
1290 return all;
1291 }
1292
1293 /* HOSTS */
1294
1295 static si_item_t *
1296 _fsi_parse_host(si_mod_t *si, const char *name, const void *addr, int af, int which, char *data, uint64_t va, uint64_t vb)
1297 {
1298 char **tokens, **h_aliases, *null_alias;
1299 int i, ntokens, match, h_addrtype, h_length;
1300 struct in_addr a4;
1301 struct in6_addr a6;
1302 si_item_t *item;
1303 char *h_addr_list[2];
1304 char h_addr_4[4], h_addr_6[16];
1305
1306 if (data == NULL) return NULL;
1307
1308 null_alias = NULL;
1309
1310 ntokens = 0;
1311 tokens = _fsi_tokenize(data, " ", 0, &ntokens);
1312 if (ntokens < 2)
1313 {
1314 free(tokens);
1315 return NULL;
1316 }
1317
1318 h_addr_list[1] = NULL;
1319
1320 h_addrtype = AF_UNSPEC;
1321 if (inet_pton(AF_INET, tokens[0], &a4) == 1)
1322 {
1323 h_addrtype = AF_INET;
1324 h_length = sizeof(struct in_addr);
1325 memcpy(h_addr_4, &a4, 4);
1326 h_addr_list[0] = h_addr_4;
1327 }
1328 else if (inet_pton(AF_INET6, tokens[0], &a6) == 1)
1329 {
1330 h_addrtype = AF_INET6;
1331 h_length = sizeof(struct in6_addr);
1332 memcpy(h_addr_6, &a6, 16);
1333 h_addr_list[0] = h_addr_6;
1334 }
1335
1336 if (h_addrtype == AF_UNSPEC)
1337 {
1338 free(tokens);
1339 return NULL;
1340 }
1341
1342 h_aliases = NULL;
1343 if (ntokens > 2) h_aliases = &(tokens[2]);
1344
1345 match = 0;
1346
1347 if (which == SEL_ALL) match = 1;
1348 else
1349 {
1350 if (h_addrtype == af)
1351 {
1352 if (which == SEL_NAME)
1353 {
1354 if (string_equal(name, tokens[1])) match = 1;
1355 else if (h_aliases != NULL)
1356 {
1357 for (i = 0; (h_aliases[i] != NULL) && (match == 0); i++)
1358 if (string_equal(name, h_aliases[i])) match = 1;
1359 }
1360 }
1361 else if (which == SEL_NUMBER)
1362 {
1363 if (memcmp(addr, h_addr_list[0], h_length) == 0) match = 1;
1364 }
1365 }
1366 }
1367
1368 if (match == 0)
1369 {
1370 free(tokens);
1371 return NULL;
1372 }
1373
1374 item = NULL;
1375
1376 if (h_aliases == NULL) h_aliases = &null_alias;
1377
1378 if (h_addrtype == AF_INET)
1379 {
1380 item = (si_item_t *)LI_ils_create("L4488s*44a", (unsigned long)si, CATEGORY_HOST_IPV4, 1, va, vb, tokens[1], h_aliases, h_addrtype, h_length, h_addr_list);
1381 }
1382 else
1383 {
1384 item = (si_item_t *)LI_ils_create("L4488s*44c", (unsigned long)si, CATEGORY_HOST_IPV6, 1, va, vb, tokens[1], h_aliases, h_addrtype, h_length, h_addr_list);
1385 }
1386
1387 free(tokens);
1388
1389 return item;
1390 }
1391
1392 static void *
1393 _fsi_get_host(si_mod_t *si, const char *name, const void *addr, int af, int which, uint32_t *err)
1394 {
1395 char *line;
1396 si_item_t *item;
1397 FILE *f;
1398 si_list_t *all;
1399 uint64_t va, vb;
1400
1401 if ((which == SEL_NAME) && (name == NULL))
1402 {
1403 if (err != NULL) *err = NO_RECOVERY;
1404 return NULL;
1405 }
1406
1407 if ((which == SEL_NUMBER) && (addr == NULL))
1408 {
1409 if (err != NULL) *err = NO_RECOVERY;
1410 return NULL;
1411 }
1412
1413 f = fopen(_PATH_HOSTS, "r");
1414 if (f == NULL)
1415 {
1416 if (err != NULL) *err = NO_RECOVERY;
1417 return NULL;
1418 }
1419
1420 _fsi_get_validation(si, VALIDATION_HOSTS, _PATH_HOSTS, f, &va, &vb);
1421
1422 all = NULL;
1423
1424 forever
1425 {
1426 line = _fsi_get_line(f);
1427 if (line == NULL) break;
1428
1429 if (line[0] == '#')
1430 {
1431 free(line);
1432 line = NULL;
1433 continue;
1434 }
1435
1436 item = _fsi_parse_host(si, name, addr, af, which, line, va, vb);
1437 free(line);
1438 line = NULL;
1439
1440 if (item == NULL) continue;
1441
1442 if (which == SEL_ALL)
1443 {
1444 all = si_list_add(all, item);
1445 si_item_release(item);
1446 continue;
1447 }
1448
1449 fclose(f);
1450 return item;
1451 }
1452
1453 fclose(f);
1454 return all;
1455 }
1456
1457 /* SERVICE */
1458
1459 static si_item_t *
1460 _fsi_parse_service(si_mod_t *si, const char *name, const char *proto, int port, int which, char *data, uint64_t va, uint64_t vb)
1461 {
1462 char **tokens, **s_aliases, *xproto;
1463 int i, ntokens, match;
1464 si_item_t *item;
1465 int xport;
1466
1467 if (data == NULL) return NULL;
1468
1469 port = ntohs(port);
1470
1471 ntokens = 0;
1472 tokens = _fsi_tokenize(data, " ", 0, &ntokens);
1473 if (ntokens < 2)
1474 {
1475 free(tokens);
1476 return NULL;
1477 }
1478
1479 s_aliases = NULL;
1480 if (ntokens > 2) s_aliases = &(tokens[2]);
1481
1482 xport = atoi(tokens[1]);
1483
1484 xproto = strchr(tokens[1], '/');
1485
1486 if (xproto == NULL)
1487 {
1488 free(tokens);
1489 return NULL;
1490 }
1491
1492 *xproto++ = '\0';
1493 if ((proto != NULL) && (string_not_equal(proto, xproto)))
1494 {
1495 free(tokens);
1496 return NULL;
1497 }
1498
1499 match = 0;
1500 if (which == SEL_ALL) match = 1;
1501 else if (which == SEL_NAME)
1502 {
1503 if (string_equal(name, tokens[0])) match = 1;
1504 else if (s_aliases != NULL)
1505 {
1506 for (i = 0; (s_aliases[i] != NULL) && (match == 0); i++)
1507 if (string_equal(name, s_aliases[i])) match = 1;
1508 }
1509 }
1510 else if ((which == SEL_NUMBER) && (port == xport)) match = 1;
1511
1512 if (match == 0)
1513 {
1514 free(tokens);
1515 return NULL;
1516 }
1517
1518 /* strange but correct */
1519 xport = htons(xport);
1520
1521 item = (si_item_t *)LI_ils_create("L4488s*4s", (unsigned long)si, CATEGORY_SERVICE, 1, va, vb, tokens[0], s_aliases, xport, xproto);
1522
1523 free(tokens);
1524
1525 return item;
1526 }
1527
1528 static void *
1529 _fsi_get_service(si_mod_t *si, const char *name, const char *proto, int port, int which)
1530 {
1531 char *p, *line;
1532 si_item_t *item;
1533 FILE *f;
1534 si_list_t *all;
1535 uint64_t va, vb;
1536
1537 if ((which == SEL_NAME) && (name == NULL)) return NULL;
1538 if ((which == SEL_NUMBER) && (port == 0)) return NULL;
1539
1540 f = fopen(_PATH_SERVICES, "r");
1541 if (f == NULL) return NULL;
1542
1543 _fsi_get_validation(si, VALIDATION_SERVICES, _PATH_SERVICES, f, &va, &vb);
1544
1545 all = NULL;
1546
1547 forever
1548 {
1549 line = _fsi_get_line(f);
1550 if (line == NULL) break;
1551
1552 if (line[0] == '#')
1553 {
1554 free(line);
1555 line = NULL;
1556 continue;
1557 }
1558
1559 p = strchr(line, '#');
1560 if (p != NULL) *p = '\0';
1561
1562 item = _fsi_parse_service(si, name, proto, port, which, line, va, vb);
1563 free(line);
1564 line = NULL;
1565
1566 if (item == NULL) continue;
1567
1568 if (which == SEL_ALL)
1569 {
1570 all = si_list_add(all, item);
1571 si_item_release(item);
1572 continue;
1573 }
1574
1575 fclose(f);
1576 return item;
1577 }
1578
1579 fclose(f);
1580 return all;
1581 }
1582
1583 /*
1584 * Generic name/number/aliases lookup
1585 * Works for protocols, networks, and rpcs
1586 */
1587
1588 static si_item_t *
1589 _fsi_parse_name_num_aliases(si_mod_t *si, const char *name, int num, int which, char *data, uint64_t va, uint64_t vb, int cat)
1590 {
1591 char **tokens, **aliases;
1592 int i, ntokens, match, xnum;
1593 si_item_t *item;
1594
1595 if (data == NULL) return NULL;
1596
1597 ntokens = 0;
1598 tokens = _fsi_tokenize(data, " ", 0, &ntokens);
1599 if (ntokens < 2)
1600 {
1601 free(tokens);
1602 return NULL;
1603 }
1604
1605 xnum = atoi(tokens[1]);
1606
1607 aliases = NULL;
1608 if (ntokens > 2) aliases = &(tokens[2]);
1609
1610 match = 0;
1611
1612 if (which == SEL_ALL) match = 1;
1613 else if (which == SEL_NAME)
1614 {
1615 if (string_equal(name, tokens[0])) match = 1;
1616 else if (aliases != NULL)
1617 {
1618 for (i = 0; (aliases[i] != NULL) && (match == 0); i++)
1619 if (string_equal(name, aliases[i])) match = 1;
1620 }
1621 }
1622 else if ((which == SEL_NUMBER) && (num == xnum)) match = 1;
1623
1624 if (match == 0)
1625 {
1626 free(tokens);
1627 return NULL;
1628 }
1629
1630 switch (cat) {
1631 case CATEGORY_NETWORK:
1632 // struct netent
1633 item = (si_item_t *)LI_ils_create("L4488s*44", (unsigned long)si, cat, 1, va, vb, tokens[0], aliases, AF_INET, xnum);
1634 break;
1635 case CATEGORY_PROTOCOL:
1636 case CATEGORY_RPC:
1637 // struct protoent
1638 // struct rpcent
1639 item = (si_item_t *)LI_ils_create("L4488s*4", (unsigned long)si, cat, 1, va, vb, tokens[0], aliases, xnum);
1640 break;
1641 default:
1642 abort();
1643 }
1644
1645 free(tokens);
1646
1647 return item;
1648 }
1649
1650 static void *
1651 _fsi_get_name_number_aliases(si_mod_t *si, const char *name, int num, int which, int cat)
1652 {
1653 char *p, *line;
1654 si_item_t *item;
1655 FILE *f;
1656 si_list_t *all;
1657 uint64_t va, vb;
1658 const char *path;
1659 int vtype;
1660
1661 switch (cat) {
1662 case CATEGORY_NETWORK:
1663 vtype = VALIDATION_NETWORKS;
1664 path = _PATH_NETWORKS;
1665 break;
1666 case CATEGORY_PROTOCOL:
1667 vtype = VALIDATION_PROTOCOLS;
1668 path = _PATH_PROTOCOLS;
1669 break;
1670 case CATEGORY_RPC:
1671 vtype = VALIDATION_RPC;
1672 path = _PATH_RPCS;
1673 break;
1674 default:
1675 abort();
1676 }
1677
1678 f = fopen(path, "r");
1679 if (f == NULL) return NULL;
1680
1681 _fsi_get_validation(si, vtype, path, f, &va, &vb);
1682
1683 all = NULL;
1684
1685 forever
1686 {
1687 line = _fsi_get_line(f);
1688 if (line == NULL) break;
1689
1690 if (line[0] == '#')
1691 {
1692 free(line);
1693 line = NULL;
1694 continue;
1695 }
1696
1697 p = strchr(line, '#');
1698 if (p != NULL) *p = '\0';
1699
1700 item = _fsi_parse_name_num_aliases(si, name, num, which, line, va, vb, cat);
1701 free(line);
1702 line = NULL;
1703
1704 if (item == NULL) continue;
1705
1706 if (which == SEL_ALL)
1707 {
1708 all = si_list_add(all, item);
1709 si_item_release(item);
1710 continue;
1711 }
1712
1713 fclose(f);
1714 return item;
1715 }
1716
1717 fclose(f);
1718 return all;
1719 }
1720
1721 /* MOUNT */
1722
1723 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
1724 static si_item_t *
1725 _fsi_parse_edt_fs(si_mod_t *si, const char *name, int which, struct edt_fstab *fs, uint64_t va, uint64_t vb)
1726 {
1727 int match;
1728 si_item_t *item;
1729
1730 if (fs == NULL) return NULL;
1731
1732 match = 0;
1733
1734 if (which == SEL_ALL) match = 1;
1735 else if ((which == SEL_NAME) && (string_equal(name, fs->fs_spec))) match = 1;
1736 else if ((which == SEL_NUMBER) && (string_equal(name, fs->fs_file))) match = 1;
1737
1738 if (match == 0)
1739 {
1740 return NULL;
1741 }
1742
1743 item = (si_item_t *)LI_ils_create("L4488sssss44", (unsigned long)si, CATEGORY_FS, 1, va, vb, fs->fs_spec, fs->fs_file, fs->fs_vfstype, fs->fs_mntops, fs->fs_type, fs->fs_freq, fs->fs_passno);
1744
1745 return item;
1746 }
1747 #endif
1748
1749 static si_item_t *
1750 _fsi_parse_fs(si_mod_t *si, const char *name, int which, char *data, uint64_t va, uint64_t vb)
1751 {
1752 char **tokens, *tmp, **opts, *fstype;
1753 int ntokens, match, i, freq, passno;
1754 si_item_t *item;
1755
1756 if (data == NULL) return NULL;
1757
1758 freq = 0;
1759 passno = 0;
1760 fstype = NULL;
1761
1762 ntokens = 0;
1763 tokens = _fsi_tokenize(data, " ", 0, &ntokens);
1764 if ((ntokens < 4) || (ntokens > 6))
1765 {
1766 free(tokens);
1767 return NULL;
1768 }
1769
1770 if (ntokens >= 5) freq = atoi(tokens[4]);
1771 if (ntokens == 6) passno = atoi(tokens[5]);
1772
1773 tmp = strdup(tokens[3]);
1774 if (tmp == NULL)
1775 {
1776 free(tokens);
1777 return NULL;
1778 }
1779
1780 ntokens = 0;
1781 opts = _fsi_tokenize(tmp, ",", 0, &ntokens);
1782
1783 if (opts == NULL)
1784 {
1785 free(tokens);
1786 free(tmp);
1787 return NULL;
1788 }
1789
1790 for (i = 0; i < ntokens; i++)
1791 {
1792 if ((string_equal(opts[i], "rw")) || (string_equal(opts[i], "ro")) || (string_equal(opts[i], "sw")) || (string_equal(opts[i], "xx")))
1793 {
1794 fstype = opts[i];
1795 break;
1796 }
1797 }
1798
1799 match = 0;
1800
1801 if (which == SEL_ALL) match = 1;
1802 else if ((which == SEL_NAME) && (string_equal(name, tokens[0]))) match = 1;
1803 else if ((which == SEL_NUMBER) && (string_equal(name, tokens[1]))) match = 1;
1804
1805 if (match == 0)
1806 {
1807 free(tokens);
1808 return NULL;
1809 }
1810
1811 item = (si_item_t *)LI_ils_create("L4488sssss44", (unsigned long)si, CATEGORY_FS, 1, va, vb, tokens[0], tokens[1], tokens[2], tokens[3], (fstype == NULL) ? "rw" : fstype, freq, passno);
1812
1813 free(tokens);
1814 free(opts);
1815 free(tmp);
1816
1817 return item;
1818 }
1819
1820 static char *
1821 _fsi_get_device_path(dev_t target_dev)
1822 {
1823 char *result;
1824 char dev[PATH_MAX];
1825 char *name;
1826 char namebuf[PATH_MAX];
1827
1828 result = NULL;
1829
1830 strlcpy(dev, _PATH_DEV, sizeof(dev));
1831
1832 /* The root device in fstab should always be a block special device */
1833 name = devname_r(target_dev, S_IFBLK, namebuf, sizeof(namebuf));
1834 if (name == NULL)
1835 {
1836 DIR *dirp;
1837 struct stat devst;
1838 struct dirent *ent, entbuf;
1839
1840 /* No _PATH_DEVDB. We have to search for it the slow way */
1841 dirp = opendir(_PATH_DEV);
1842 if (dirp == NULL) return NULL;
1843
1844 while (readdir_r(dirp, &entbuf, &ent) == 0 && ent != NULL)
1845 {
1846 /* Look for a block special device */
1847 if (ent->d_type == DT_BLK)
1848 {
1849 strlcat(dev, ent->d_name, sizeof(dev));
1850 if (stat(dev, &devst) == 0)
1851 {
1852 if (devst.st_rdev == target_dev) {
1853 result = strdup(dev);
1854 break;
1855 }
1856 }
1857 }
1858
1859 /* reset dev to _PATH_DEV and try again */
1860 dev[sizeof(_PATH_DEV) - 1] = '\0';
1861 }
1862
1863 if (dirp) closedir(dirp);
1864 }
1865 else
1866 {
1867 /* We found the _PATH_DEVDB entry */
1868 strlcat(dev, name, sizeof(dev));
1869 result = strdup(dev);
1870 }
1871
1872 return result;
1873 }
1874
1875 static si_item_t *
1876 _fsi_fs_root(si_mod_t *si)
1877 {
1878 dispatch_once(&rootfs_once, ^{
1879 struct stat rootstat;
1880 struct statfs rootfsinfo;
1881 char *root_spec;
1882 const char *root_path = "/";
1883
1884 if (stat(root_path, &rootstat) < 0) return;
1885 if (statfs(root_path, &rootfsinfo) < 0) return;
1886
1887 // Check to make sure we're not looking at a synthetic root:
1888 if (string_equal(rootfsinfo.f_fstypename, "synthfs")) {
1889 root_path = "/root";
1890 if (stat(root_path, &rootstat) < 0) return;
1891 if (statfs(root_path, &rootfsinfo) < 0) return;
1892 }
1893
1894 root_spec = _fsi_get_device_path(rootstat.st_dev);
1895
1896 // In case root is mounted from snapshot, _fsi_get_device_path will return NULL as the device name does not comply to
1897 // /dev/diskAAsBB, but in the format of snap@/dev/diskAAsBB, in that case f_mntfromname has the correct device name, so return it
1898 if (root_spec == NULL) {
1899 const char *mntfromname = rootfsinfo.f_mntfromname;
1900 size_t len = sizeof(rootfsinfo.f_mntfromname);
1901 const char *p;
1902 while ((p = strnstr(mntfromname, "@", len))) {
1903 len -= p + 1 - mntfromname;
1904 mntfromname = p + 1;
1905 }
1906 root_spec = strndup(mntfromname, len);
1907 }
1908
1909 rootfs = (si_item_t *)LI_ils_create("L4488sssss44", (unsigned long)si, CATEGORY_FS, 1, 0LL, 0LL, root_spec, root_path, rootfsinfo.f_fstypename, FSTAB_RW, FSTAB_RW, 0, 1);
1910 free(root_spec);
1911 });
1912
1913 return si_item_retain(rootfs);
1914 }
1915
1916 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
1917 static void *
1918 _fsi_get_edt_fs(si_mod_t *si, const char *name, int which)
1919 {
1920 void *data;
1921 struct edt_fstab *fstab;
1922 size_t i, size;
1923 si_item_t *item;
1924 si_list_t *all;
1925 uint64_t va, vb;
1926
1927 if ((which != SEL_ALL) && (name == NULL)) return NULL;
1928
1929 all = NULL;
1930 item = NULL;
1931 fstab = NULL;
1932 i = 0;
1933 size = 0;
1934
1935 // obtain fstab information from the EDT provided through this sysctl
1936 if (sysctlbyname(APFS_FSTAB_SYSCTL, NULL, &size, NULL, 0) || !size)
1937 {
1938 return all;
1939 }
1940
1941 fstab = malloc(size);
1942 if (!fstab)
1943 {
1944 return all;
1945 }
1946
1947 if (sysctlbyname(APFS_FSTAB_SYSCTL, fstab, &size, NULL, 0))
1948 {
1949 free(fstab);
1950 return all;
1951 }
1952 size = size / sizeof(struct edt_fstab);
1953
1954 _fsi_get_validation(si, VALIDATION_FSTAB, _PATH_FSTAB, NULL, &va, &vb);
1955
1956 forever
1957 {
1958 if (i >= size)
1959 {
1960 free(fstab);
1961 break;
1962 }
1963
1964 data = fstab + i;
1965 i++;
1966
1967 item = _fsi_parse_edt_fs(si, name, which, data, va, vb);
1968
1969 if (item == NULL) continue;
1970
1971 if (which == SEL_ALL)
1972 {
1973 all = si_list_add(all, item);
1974 si_item_release(item);
1975 continue;
1976 }
1977
1978 return item;
1979 }
1980
1981 return all;
1982 }
1983 #endif
1984
1985 static void *
1986 _fsi_get_fs(si_mod_t *si, const char *name, int which)
1987 {
1988 char *line;
1989 si_item_t *item;
1990 FILE *f;
1991 si_list_t *all;
1992 uint64_t va, vb;
1993 int synthesize_root;
1994 struct fstab *rfs;
1995
1996 if ((which != SEL_ALL) && (name == NULL)) return NULL;
1997
1998 all = NULL;
1999 f = NULL;
2000 #ifdef SYNTH_ROOTFS
2001 synthesize_root = 1;
2002 #else
2003 synthesize_root = 0;
2004 #endif
2005
2006 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
2007 // We still boot using HFS sometimes (e.g. ramdisks) and therefore
2008 // need to conditionalize using the EDT over the fstab file.
2009 // Certain HFS ramdisks rely on the EDT entries. Prefer the EDT
2010 // over the fstab file, but fall back to use the file upon failure
2011 // to obtain the EDT entries.
2012 struct statfs rootfs;
2013 const char *root_path = "/";
2014
2015 if (statfs(root_path, &rootfs)) return NULL;
2016
2017 all = _fsi_get_edt_fs(si, name, which);
2018 if (all || string_equal(rootfs.f_fstypename, "apfs"))
2019 {
2020 return all;
2021 }
2022 #endif
2023
2024 f = fopen(_PATH_FSTAB, "r");
2025 if ((f == NULL) || (synthesize_root == 1))
2026 {
2027 item = _fsi_fs_root(si);
2028
2029 rfs = NULL;
2030 if (item != NULL) rfs = (struct fstab *)((uintptr_t)item + sizeof(si_item_t));
2031
2032 switch (which)
2033 {
2034 case SEL_NAME:
2035 {
2036 if ((rfs != NULL) && (string_equal(name, rfs->fs_spec)))
2037 {
2038 if (f != NULL) fclose(f);
2039 return item;
2040 }
2041
2042 break;
2043 }
2044
2045 case SEL_NUMBER:
2046 {
2047 if ((rfs != NULL) && (string_equal(name, rfs->fs_file)))
2048 {
2049 if (f != NULL) fclose(f);
2050 return item;
2051 }
2052
2053 break;
2054 }
2055
2056 case SEL_ALL:
2057 {
2058 all = si_list_add(all, item);
2059 si_item_release(item);
2060 break;
2061 }
2062 }
2063 }
2064
2065 if (f == NULL) return all;
2066
2067 _fsi_get_validation(si, VALIDATION_FSTAB, _PATH_FSTAB, f, &va, &vb);
2068
2069 forever
2070 {
2071 line = _fsi_get_line(f);
2072 if (line == NULL) break;
2073
2074 if (line[0] == '#')
2075 {
2076 free(line);
2077 line = NULL;
2078 continue;
2079 }
2080
2081 item = _fsi_parse_fs(si, name, which, line, va, vb);
2082 free(line);
2083 line = NULL;
2084
2085 if (item == NULL) continue;
2086
2087 if (which == SEL_ALL)
2088 {
2089 all = si_list_add(all, item);
2090 si_item_release(item);
2091 continue;
2092 }
2093
2094 fclose(f);
2095 return item;
2096 }
2097
2098 fclose(f);
2099 return all;
2100 }
2101
2102 static int
2103 file_is_valid(si_mod_t *si, si_item_t *item)
2104 {
2105 si_mod_t *src;
2106
2107 if (si == NULL) return 0;
2108 if (item == NULL) return 0;
2109 if (si->name == NULL) return 0;
2110 if (item->src == NULL) return 0;
2111
2112 src = (si_mod_t *)item->src;
2113
2114 if (src->name == NULL) return 0;
2115 if (string_not_equal(si->name, src->name)) return 0;
2116
2117 if (item == rootfs) return 1;
2118
2119 return _fsi_validate(si, item->type, item->validation_a, item->validation_b);
2120 }
2121
2122 static si_item_t *
2123 file_user_byname(si_mod_t *si, const char *name)
2124 {
2125 return _fsi_get_user(si, name, 0, SEL_NAME);
2126 }
2127
2128 static si_item_t *
2129 file_user_byuid(si_mod_t *si, uid_t uid)
2130 {
2131 return _fsi_get_user(si, NULL, uid, SEL_NUMBER);
2132 }
2133
2134 static si_list_t *
2135 file_user_all(si_mod_t *si)
2136 {
2137 return _fsi_get_user(si, NULL, 0, SEL_ALL);
2138 }
2139
2140 static si_item_t *
2141 file_group_byname(si_mod_t *si, const char *name)
2142 {
2143 return _fsi_get_group(si, name, 0, SEL_NAME);
2144 }
2145
2146 static si_item_t *
2147 file_group_bygid(si_mod_t *si, gid_t gid)
2148 {
2149 return _fsi_get_group(si, NULL, gid, SEL_NUMBER);
2150 }
2151
2152 static si_list_t *
2153 file_group_all(si_mod_t *si)
2154 {
2155 return _fsi_get_group(si, NULL, 0, SEL_ALL);
2156 }
2157
2158 static si_item_t *
2159 file_grouplist(si_mod_t *si, const char *name, __unused uint32_t ignored)
2160 {
2161 return _fsi_get_grouplist(si, name);
2162 }
2163
2164 static si_list_t *
2165 file_netgroup_byname(si_mod_t *si, const char *name)
2166 {
2167 si_list_t *list = NULL;
2168 si_item_t *item;
2169 uint64_t va=0, vb=0;
2170 file_netgroup_t *n;
2171 file_si_private_t *pp;
2172
2173 if (name == NULL) return NULL;
2174
2175 pp = (file_si_private_t *)si->private;
2176 if (pp == NULL) return NULL;
2177
2178 _fsi_check_netgroup_cache(si);
2179
2180 pthread_mutex_lock(&file_mutex);
2181
2182 n = _fsi_find_netgroup(&(pp->file_netgroup_cache), name, 0);
2183 if (n != NULL)
2184 {
2185 file_netgroup_member_t *m = n->members;
2186 while (m != NULL)
2187 {
2188 item = (si_item_t *)LI_ils_create("L4488sss", (unsigned long)si, CATEGORY_NETGROUP, 1, va, vb, m->host, m->user, m->domain);
2189 list = si_list_add(list, item);
2190 m = m->next;
2191 }
2192 }
2193
2194 pthread_mutex_unlock(&file_mutex);
2195
2196 return list;
2197 }
2198
2199 static int
2200 file_in_netgroup(si_mod_t *si, const char *group, const char *host, const char *user, const char *domain)
2201 {
2202 file_netgroup_t *n;
2203 file_netgroup_member_t *m;
2204 file_si_private_t *pp;
2205
2206 if (group == NULL) return 0;
2207
2208 pp = (file_si_private_t *)si->private;
2209 if (pp == NULL) return 0;
2210
2211 _fsi_check_netgroup_cache(si);
2212
2213 pthread_mutex_lock(&file_mutex);
2214
2215 n = _fsi_find_netgroup(&(pp->file_netgroup_cache), group, 0);
2216 if (n == NULL)
2217 {
2218 pthread_mutex_unlock(&file_mutex);
2219 return 0;
2220 }
2221
2222 m = n->members;
2223 while (m != NULL)
2224 {
2225 file_netgroup_member_t *x = m;
2226 m = m->next;
2227
2228 if (host != NULL)
2229 {
2230 if (x->host == NULL) continue;
2231 if (strcmp(host, x->host)) continue;
2232 }
2233
2234 if (user != NULL)
2235 {
2236 if (x->user == NULL) continue;
2237 if (strcmp(user, x->user)) continue;
2238 }
2239
2240 if (domain != NULL)
2241 {
2242 if (x->domain == NULL) continue;
2243 if (strcmp(domain, x->domain)) continue;
2244 }
2245
2246 pthread_mutex_unlock(&file_mutex);
2247 return 1;
2248 }
2249
2250 pthread_mutex_unlock(&file_mutex);
2251 return 0;
2252 }
2253
2254 static si_item_t *
2255 file_host_byname(si_mod_t *si, const char *name, int af, const char *ignored, uint32_t *err)
2256 {
2257 si_item_t *item;
2258
2259 if (err != NULL) *err = SI_STATUS_NO_ERROR;
2260
2261 item = _fsi_get_host(si, name, NULL, af, SEL_NAME, err);
2262 if ((item == NULL) && (err != NULL) && (*err == 0)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
2263
2264 return item;
2265 }
2266
2267 static si_item_t *
2268 file_host_byaddr(si_mod_t *si, const void *addr, int af, const char *ignored, uint32_t *err)
2269 {
2270 si_item_t *item;
2271
2272 if (err != NULL) *err = SI_STATUS_NO_ERROR;
2273
2274 item = _fsi_get_host(si, NULL, addr, af, SEL_NUMBER, err);
2275 if ((item == NULL) && (err != NULL) && (*err == 0)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
2276
2277 return item;
2278 }
2279
2280 static si_list_t *
2281 file_host_all(si_mod_t *si)
2282 {
2283 return _fsi_get_host(si, NULL, NULL, 0, SEL_ALL, NULL);
2284 }
2285
2286 static si_item_t *
2287 file_network_byname(si_mod_t *si, const char *name)
2288 {
2289 if (name == NULL) return NULL;
2290 return _fsi_get_name_number_aliases(si, name, 0, SEL_NAME, CATEGORY_NETWORK);
2291 }
2292
2293 static si_item_t *
2294 file_network_byaddr(si_mod_t *si, uint32_t addr)
2295 {
2296 return _fsi_get_name_number_aliases(si, NULL, (int)addr, SEL_NUMBER, CATEGORY_NETWORK);
2297 }
2298
2299 static si_list_t *
2300 file_network_all(si_mod_t *si)
2301 {
2302 return _fsi_get_name_number_aliases(si, NULL, 0, SEL_ALL, CATEGORY_NETWORK);
2303 }
2304
2305 static si_item_t *
2306 file_service_byname(si_mod_t *si, const char *name, const char *proto)
2307 {
2308 return _fsi_get_service(si, name, proto, 0, SEL_NAME);
2309 }
2310
2311 static si_item_t *
2312 file_service_byport(si_mod_t *si, int port, const char *proto)
2313 {
2314 return _fsi_get_service(si, NULL, proto, port, SEL_NUMBER);
2315 }
2316
2317 static si_list_t *
2318 file_service_all(si_mod_t *si)
2319 {
2320 return _fsi_get_service(si, NULL, NULL, 0, SEL_ALL);
2321 }
2322
2323 static si_item_t *
2324 file_protocol_byname(si_mod_t *si, const char *name)
2325 {
2326 if (name == NULL) return NULL;
2327 return _fsi_get_name_number_aliases(si, name, 0, SEL_NAME, CATEGORY_PROTOCOL);
2328 }
2329
2330 static si_item_t *
2331 file_protocol_bynumber(si_mod_t *si, int number)
2332 {
2333 return _fsi_get_name_number_aliases(si, NULL, number, SEL_NUMBER, CATEGORY_PROTOCOL);
2334 }
2335
2336 static si_list_t *
2337 file_protocol_all(si_mod_t *si)
2338 {
2339 return _fsi_get_name_number_aliases(si, NULL, 0, SEL_ALL, CATEGORY_PROTOCOL);
2340 }
2341
2342 static si_item_t *
2343 file_rpc_byname(si_mod_t *si, const char *name)
2344 {
2345 if (name == NULL) return NULL;
2346 return _fsi_get_name_number_aliases(si, name, 0, SEL_NAME, CATEGORY_RPC);
2347 }
2348
2349 static si_item_t *
2350 file_rpc_bynumber(si_mod_t *si, int number)
2351 {
2352 return _fsi_get_name_number_aliases(si, NULL, number, SEL_NUMBER, CATEGORY_RPC);
2353 }
2354
2355 static si_list_t *
2356 file_rpc_all(si_mod_t *si)
2357 {
2358 return _fsi_get_name_number_aliases(si, NULL, 0, SEL_ALL, CATEGORY_RPC);
2359 }
2360
2361 static si_item_t *
2362 file_fs_byspec(si_mod_t *si, const char *spec)
2363 {
2364 return _fsi_get_fs(si, spec, SEL_NAME);
2365 }
2366
2367 static si_item_t *
2368 file_fs_byfile(si_mod_t *si, const char *file)
2369 {
2370 return _fsi_get_fs(si, file, SEL_NUMBER);
2371 }
2372
2373 static si_list_t *
2374 file_fs_all(si_mod_t *si)
2375 {
2376 return _fsi_get_fs(si, NULL, SEL_ALL);
2377 }
2378
2379 static si_item_t *
2380 file_alias_byname(si_mod_t *si, const char *name)
2381 {
2382 return _fsi_get_alias(si, name, SEL_NAME);
2383 }
2384
2385 static si_list_t *
2386 file_alias_all(si_mod_t *si)
2387 {
2388 return _fsi_get_alias(si, NULL, SEL_ALL);
2389 }
2390
2391 static si_item_t *
2392 file_mac_byname(si_mod_t *si, const char *name)
2393 {
2394 return _fsi_get_ether(si, name, SEL_NAME);
2395 }
2396
2397 static si_item_t *
2398 file_mac_bymac(si_mod_t *si, const char *mac)
2399 {
2400 return _fsi_get_ether(si, mac, SEL_NUMBER);
2401 }
2402
2403 static si_list_t *
2404 file_mac_all(si_mod_t *si)
2405 {
2406 return _fsi_get_ether(si, NULL, SEL_ALL);
2407 }
2408
2409 static si_list_t *
2410 file_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 *interface, uint32_t *err)
2411 {
2412 if (err != NULL) *err = SI_STATUS_NO_ERROR;
2413 return _gai_simple(si, node, serv, family, socktype, proto, flags, interface, err);
2414 }
2415
2416 si_mod_t *
2417 si_module_static_file(void)
2418 {
2419 static const struct si_mod_vtable_s file_vtable =
2420 {
2421 .sim_is_valid = &file_is_valid,
2422
2423 .sim_user_byname = &file_user_byname,
2424 .sim_user_byuid = &file_user_byuid,
2425 .sim_user_byuuid = NULL,
2426 .sim_user_all = &file_user_all,
2427
2428 .sim_group_byname = &file_group_byname,
2429 .sim_group_bygid = &file_group_bygid,
2430 .sim_group_byuuid = NULL,
2431 .sim_group_all = &file_group_all,
2432
2433 .sim_grouplist = &file_grouplist,
2434
2435 .sim_netgroup_byname = &file_netgroup_byname,
2436 .sim_in_netgroup = &file_in_netgroup,
2437
2438 .sim_alias_byname = &file_alias_byname,
2439 .sim_alias_all = &file_alias_all,
2440
2441 .sim_host_byname = &file_host_byname,
2442 .sim_host_byaddr = &file_host_byaddr,
2443 .sim_host_all = &file_host_all,
2444
2445 .sim_network_byname = &file_network_byname,
2446 .sim_network_byaddr = &file_network_byaddr,
2447 .sim_network_all = &file_network_all,
2448
2449 .sim_service_byname = &file_service_byname,
2450 .sim_service_byport = &file_service_byport,
2451 .sim_service_all = &file_service_all,
2452
2453 .sim_protocol_byname = &file_protocol_byname,
2454 .sim_protocol_bynumber = &file_protocol_bynumber,
2455 .sim_protocol_all = &file_protocol_all,
2456
2457 .sim_rpc_byname = &file_rpc_byname,
2458 .sim_rpc_bynumber = &file_rpc_bynumber,
2459 .sim_rpc_all = &file_rpc_all,
2460
2461 .sim_fs_byspec = &file_fs_byspec,
2462 .sim_fs_byfile = &file_fs_byfile,
2463 .sim_fs_all = &file_fs_all,
2464
2465 .sim_mac_byname = &file_mac_byname,
2466 .sim_mac_bymac = &file_mac_bymac,
2467 .sim_mac_all = &file_mac_all,
2468
2469 .sim_wants_addrinfo = NULL,
2470 .sim_addrinfo = &file_addrinfo,
2471
2472 /* no nameinfo support */
2473 .sim_nameinfo = NULL,
2474 };
2475
2476 static si_mod_t si =
2477 {
2478 .vers = 1,
2479 .refcount = 1,
2480 .flags = SI_MOD_FLAG_STATIC,
2481
2482 .private = NULL,
2483 .vtable = &file_vtable,
2484 };
2485
2486 static dispatch_once_t once;
2487
2488 dispatch_once(&once, ^{
2489 si.name = strdup("file");
2490 file_si_private_t *pp = calloc(1, sizeof(file_si_private_t));
2491 if (pp != NULL)
2492 {
2493 int i;
2494 for (i = 0; i < VALIDATION_COUNT; i++) pp->notify_token[i] = -1;
2495
2496 /* hardwired for now, but we may want to make this configurable someday */
2497 pp->validation_notify_mask = VALIDATION_MASK_HOSTS | VALIDATION_MASK_SERVICES | VALIDATION_MASK_PROTOCOLS;
2498 }
2499
2500 si.private = pp;
2501 });
2502
2503 return (si_mod_t *)&si;
2504 }