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