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