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