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