Libinfo-391.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 <arpa/inet.h>
34 #include <sys/param.h>
35 #include <sys/mount.h>
36 #include <sys/stat.h>
37 #include <ils.h>
38 #include <dispatch/dispatch.h>
39
40 /* notify SPI */
41 uint32_t notify_peek(int token, uint32_t *val);
42
43 extern uint32_t gL1CacheEnabled;
44
45 /* These really should be in netdb.h & etc. */
46 #define _PATH_RPCS "/etc/rpc"
47 #define _PATH_ALIASES "/etc/aliases"
48 #define _PATH_ETHERS "/etc/ethers"
49 #define _PATH_NETGROUP "/etc/netgroup"
50
51 static dispatch_once_t rootfs_once;
52 static si_item_t *rootfs = NULL;
53
54 #define CHUNK 256
55 #define FNG_MEM 0x00000010
56 #define FNG_GRP 0x00000020
57
58 #define forever for(;;)
59
60 #define VALIDATION_PASSWD 0
61 #define VALIDATION_MASTER_PASSWD 1
62 #define VALIDATION_GROUP 2
63 #define VALIDATION_NETGROUP 3
64 #define VALIDATION_ALIASES 4
65 #define VALIDATION_HOSTS 5
66 #define VALIDATION_NETWORKS 6
67 #define VALIDATION_SERVICES 7
68 #define VALIDATION_PROTOCOLS 8
69 #define VALIDATION_RPC 9
70 #define VALIDATION_FSTAB 10
71 #define VALIDATION_ETHERS 11
72 #define VALIDATION_COUNT 12
73
74 #define VALIDATION_MASK_PASSWD 0x00000001
75 #define VALIDATION_MASK_MASTER_PASSWD 0x00000002
76 #define VALIDATION_MASK_MASK_GROUP 0x00000004
77 #define VALIDATION_MASK_NETGROUP 0x00000008
78 #define VALIDATION_MASK_ALIASES 0x00000010
79 #define VALIDATION_MASK_HOSTS 0x00000020
80 #define VALIDATION_MASK_NETWORKS 0x00000040
81 #define VALIDATION_MASK_SERVICES 0x00000080
82 #define VALIDATION_MASK_PROTOCOLS 0x00000100
83 #define VALIDATION_MASK_RPC 0x00000200
84 #define VALIDATION_MASK_FSTAB 0x00000400
85 #define VALIDATION_MASK_ETHERS 0x00000800
86
87 typedef struct file_netgroup_member_s
88 {
89 uint32_t flags;
90 char *host;
91 char *user;
92 char *domain;
93 struct file_netgroup_member_s *next;
94 } file_netgroup_member_t;
95
96 typedef struct file_netgroup_s
97 {
98 char *name;
99 uint32_t flags;
100 file_netgroup_member_t *members;
101 struct file_netgroup_s *next;
102 } file_netgroup_t;
103
104 typedef struct
105 {
106 uint32_t validation_notify_mask;
107 int notify_token[VALIDATION_COUNT];
108 file_netgroup_t *file_netgroup_cache;
109 uint64_t netgroup_validation_a;
110 uint64_t netgroup_validation_b;
111 } file_si_private_t;
112
113 static pthread_mutex_t file_mutex = PTHREAD_MUTEX_INITIALIZER;
114
115 static char *
116 _fsi_copy_string(char *s)
117 {
118 int len;
119 char *t;
120
121 if (s == NULL) return NULL;
122
123 len = strlen(s) + 1;
124 t = malloc(len);
125 bcopy(s, t, len);
126 return t;
127 }
128
129 static char **
130 _fsi_append_string(char *s, char **l)
131 {
132 int i, len;
133
134 if (s == NULL) return l;
135 if (l == NULL)
136 {
137 l = (char **)malloc(2 * sizeof(char *));
138 l[0] = s;
139 l[1] = NULL;
140 return l;
141 }
142
143 for (i = 0; l[i] != NULL; i++);
144 len = i + 1; /* count the NULL on the end of the list too! */
145
146 l = (char **)reallocf(l, (len + 1) * sizeof(char *));
147
148 l[len - 1] = s;
149 l[len] = 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) *a = 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 int32_t gid, basegid, *gidp;
988 char **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 free(item);
1004 }
1005
1006 f = fopen(_PATH_GROUP, "r");
1007 if (f == NULL) return NULL;
1008
1009 _fsi_get_validation(si, VALIDATION_GROUP, _PATH_GROUP, f, &va, &vb);
1010
1011 forever
1012 {
1013 line = _fsi_get_line(f);
1014 if (line == NULL) break;
1015
1016 if (line[0] == '#')
1017 {
1018 free(line);
1019 line = NULL;
1020 continue;
1021 }
1022
1023 ntokens = 0;
1024 tokens = _fsi_tokenize(line, ":", 1, &ntokens);
1025 if (ntokens != 4)
1026 {
1027 free(tokens);
1028 continue;
1029 }
1030
1031 ntokens = 0;
1032 members = _fsi_tokenize(tokens[3], ",", 1, &ntokens);
1033
1034 match = 0;
1035 gid = -2;
1036
1037 for (i = 0; (i < ntokens) && (match == 0); i++)
1038 {
1039 if (string_equal(user, members[i]))
1040 {
1041 gid = atoi(tokens[2]);
1042 match = 1;
1043 }
1044 }
1045
1046 free(tokens);
1047 free(members);
1048 free(line);
1049 line = NULL;
1050
1051 if (match == 1)
1052 {
1053 if (gidcount == 0) gidlist = (char **)calloc(1, sizeof(char *));
1054 else gidlist = (char **)reallocf(gidlist, (gidcount + 1) * sizeof(char *));
1055 gidp = (int32_t *)calloc(1, sizeof(int32_t));
1056
1057 if (gidlist == NULL)
1058 {
1059 gidcount = 0;
1060 break;
1061 }
1062
1063 if (gidp == NULL)
1064 {
1065 for (i = 0; i < gidcount; i++) free(gidlist[i]);
1066 free(gidlist);
1067 gidcount = 0;
1068 break;
1069 }
1070
1071 *gidp = gid;
1072 gidlist[gidcount++] = (char *)gidp;
1073 }
1074 }
1075
1076 fclose(f);
1077
1078 if (gidcount == 0) return NULL;
1079
1080 gidlist = (char **)reallocf(gidlist, (gidcount + 1) * sizeof(int32_t *));
1081 if (gidlist == NULL) return NULL;
1082 gidlist[gidcount] = NULL;
1083
1084 item = (si_item_t *)LI_ils_create("L4488s44a", (unsigned long)si, CATEGORY_GROUPLIST, 1, va, vb, user, basegid, gidcount, gidlist);
1085
1086 for (i = 0; i <= gidcount; i++) free(gidlist[i]);
1087 free(gidlist);
1088
1089 return item;
1090 }
1091
1092 /* ALIASES */
1093
1094 static si_item_t *
1095 _fsi_parse_alias(si_mod_t *si, const char *name, int which, char *data, uint64_t va, uint64_t vb)
1096 {
1097 char **tokens, **members;
1098 int ntokens, match;
1099 si_item_t *item;
1100
1101 if (data == NULL) return NULL;
1102
1103 ntokens = 0;
1104 tokens = _fsi_tokenize(data, ":", 1, &ntokens);
1105 if (ntokens < 2)
1106 {
1107 free(tokens);
1108 return NULL;
1109 }
1110
1111 match = 0;
1112
1113 if (which == SEL_ALL) match = 1;
1114 else if (string_equal(name, tokens[0])) match = 1;
1115
1116 if (match == 0)
1117 {
1118 free(tokens);
1119 return NULL;
1120 }
1121
1122 ntokens = 0;
1123 members = _fsi_tokenize(tokens[1], ",", 1, &ntokens);
1124
1125 item = (si_item_t *)LI_ils_create("L4488s4*4", (unsigned long)si, CATEGORY_ALIAS, 1, va, vb, tokens[0], ntokens, members, 1);
1126
1127 free(tokens);
1128 free(members);
1129
1130 return item;
1131 }
1132
1133 static void *
1134 _fsi_get_alias(si_mod_t *si, const char *name, int which)
1135 {
1136 char *line;
1137 si_item_t *item;
1138 FILE *f;
1139 si_list_t *all;
1140 uint64_t va, vb;
1141
1142 if ((which == SEL_NAME) && (name == NULL)) return NULL;
1143
1144 all = NULL;
1145 f = NULL;
1146
1147 f = fopen(_PATH_ALIASES, "r");
1148 if (f == NULL) return NULL;
1149
1150 _fsi_get_validation(si, VALIDATION_ALIASES, _PATH_ALIASES, f, &va, &vb);
1151
1152 forever
1153 {
1154 line = _fsi_get_line(f);
1155 if (line == NULL) break;
1156
1157 if (line[0] == '#')
1158 {
1159 free(line);
1160 line = NULL;
1161 continue;
1162 }
1163
1164 item = _fsi_parse_alias(si, name, which, line, va, vb);
1165 free(line);
1166 line = NULL;
1167
1168 if (item == NULL) continue;
1169
1170 if (which == SEL_ALL)
1171 {
1172 all = si_list_add(all, item);
1173 si_item_release(item);
1174 continue;
1175 }
1176
1177 fclose(f);
1178 return item;
1179 }
1180
1181 fclose(f);
1182 return all;
1183 }
1184
1185 /* ETHERS */
1186
1187 static si_item_t *
1188 _fsi_parse_ether(si_mod_t *si, const char *name, int which, char *data, uint64_t va, uint64_t vb)
1189 {
1190 char **tokens;
1191 char *cmac;
1192 int ntokens, match;
1193 si_item_t *item;
1194
1195 if (data == NULL) return NULL;
1196
1197 ntokens = 0;
1198 tokens = _fsi_tokenize(data, " \t", 1, &ntokens);
1199 if (ntokens != 2)
1200 {
1201 free(tokens);
1202 return NULL;
1203 }
1204
1205 cmac = si_standardize_mac_address(tokens[0]);
1206 if (cmac == NULL)
1207 {
1208 free(tokens);
1209 return NULL;
1210 }
1211
1212 match = 0;
1213 if (which == SEL_ALL) match = 1;
1214 else if ((which == SEL_NAME) && (string_equal(name, tokens[1]))) match = 1;
1215 else if ((which == SEL_NUMBER) && (string_equal(name, cmac))) match = 1;
1216
1217 if (match == 0)
1218 {
1219 free(tokens);
1220 free(cmac);
1221 return NULL;
1222 }
1223
1224 item = (si_item_t *)LI_ils_create("L4488ss", (unsigned long)si, CATEGORY_MAC, 1, va, vb, tokens[1], cmac);
1225
1226 free(tokens);
1227 free(cmac);
1228
1229 return item;
1230 }
1231
1232 static void *
1233 _fsi_get_ether(si_mod_t *si, const char *name, int which)
1234 {
1235 char *line, *cmac;
1236 si_item_t *item;
1237 FILE *f;
1238 si_list_t *all;
1239 uint64_t va, vb;
1240
1241 if ((which != SEL_ALL) && (name == NULL)) return NULL;
1242
1243 cmac = NULL;
1244 if (which == SEL_NUMBER)
1245 {
1246 cmac = si_standardize_mac_address(name);
1247 if (cmac == NULL) return NULL;
1248 }
1249
1250 all = NULL;
1251 f = NULL;
1252
1253 f = fopen(_PATH_ETHERS, "r");
1254 if (f == NULL) return NULL;
1255
1256 _fsi_get_validation(si, VALIDATION_ETHERS, _PATH_ETHERS, f, &va, &vb);
1257
1258 forever
1259 {
1260 line = _fsi_get_line(f);
1261 if (line == NULL) break;
1262
1263 if (line[0] == '#')
1264 {
1265 free(line);
1266 line = NULL;
1267 continue;
1268 }
1269
1270 item = NULL;
1271 if (which == SEL_NUMBER) item = _fsi_parse_ether(si, cmac, which, line, va, vb);
1272 else item = _fsi_parse_ether(si, name, which, line, va, vb);
1273
1274 free(line);
1275 line = NULL;
1276
1277 if (item == NULL) continue;
1278
1279 if (which == SEL_ALL)
1280 {
1281 all = si_list_add(all, item);
1282 si_item_release(item);
1283 continue;
1284 }
1285
1286 fclose(f);
1287 return item;
1288 }
1289
1290 fclose(f);
1291 return all;
1292 }
1293
1294 /* HOSTS */
1295
1296 static si_item_t *
1297 _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)
1298 {
1299 char **tokens, **h_aliases, *null_alias;
1300 int i, ntokens, match, h_addrtype, h_length;
1301 struct in_addr a4;
1302 struct in6_addr a6;
1303 si_item_t *item;
1304 char *h_addr_list[2];
1305 char h_addr_4[4], h_addr_6[16];
1306
1307 if (data == NULL) return NULL;
1308
1309 null_alias = NULL;
1310
1311 ntokens = 0;
1312 tokens = _fsi_tokenize(data, " ", 0, &ntokens);
1313 if (ntokens < 2)
1314 {
1315 free(tokens);
1316 return NULL;
1317 }
1318
1319 h_addr_list[1] = NULL;
1320
1321 h_addrtype = AF_UNSPEC;
1322 if (inet_pton(AF_INET, tokens[0], &a4) == 1)
1323 {
1324 h_addrtype = AF_INET;
1325 h_length = sizeof(struct in_addr);
1326 memcpy(h_addr_4, &a4, 4);
1327 h_addr_list[0] = h_addr_4;
1328 }
1329 else if (inet_pton(AF_INET6, tokens[0], &a6) == 1)
1330 {
1331 h_addrtype = AF_INET6;
1332 h_length = sizeof(struct in6_addr);
1333 memcpy(h_addr_6, &a6, 16);
1334 h_addr_list[0] = h_addr_6;
1335 }
1336
1337 if (h_addrtype == AF_UNSPEC)
1338 {
1339 free(tokens);
1340 return NULL;
1341 }
1342
1343 h_aliases = NULL;
1344 if (ntokens > 2) h_aliases = &(tokens[2]);
1345
1346 match = 0;
1347
1348 if (which == SEL_ALL) match = 1;
1349 else
1350 {
1351 if (h_addrtype == af)
1352 {
1353 if (which == SEL_NAME)
1354 {
1355 if (string_equal(name, tokens[1])) match = 1;
1356 else if (h_aliases != NULL)
1357 {
1358 for (i = 0; (h_aliases[i] != NULL) && (match == 0); i++)
1359 if (string_equal(name, h_aliases[i])) match = 1;
1360 }
1361 }
1362 else if (which == SEL_NUMBER)
1363 {
1364 if (memcmp(addr, h_addr_list[0], h_length) == 0) match = 1;
1365 }
1366 }
1367 }
1368
1369 if (match == 0)
1370 {
1371 free(tokens);
1372 return NULL;
1373 }
1374
1375 item = NULL;
1376
1377 if (h_aliases == NULL) h_aliases = &null_alias;
1378
1379 if (h_addrtype == AF_INET)
1380 {
1381 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);
1382 }
1383 else
1384 {
1385 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);
1386 }
1387
1388 free(tokens);
1389
1390 return item;
1391 }
1392
1393 static void *
1394 _fsi_get_host(si_mod_t *si, const char *name, const void *addr, int af, int which, uint32_t *err)
1395 {
1396 char *line;
1397 si_item_t *item;
1398 FILE *f;
1399 si_list_t *all;
1400 uint64_t va, vb;
1401
1402 if ((which == SEL_NAME) && (name == NULL))
1403 {
1404 if (err != NULL) *err = NO_RECOVERY;
1405 return NULL;
1406 }
1407
1408 if ((which == SEL_NUMBER) && (addr == NULL))
1409 {
1410 if (err != NULL) *err = NO_RECOVERY;
1411 return NULL;
1412 }
1413
1414 f = fopen(_PATH_HOSTS, "r");
1415 if (f == NULL)
1416 {
1417 if (err != NULL) *err = NO_RECOVERY;
1418 return NULL;
1419 }
1420
1421 _fsi_get_validation(si, VALIDATION_HOSTS, _PATH_HOSTS, f, &va, &vb);
1422
1423 all = NULL;
1424
1425 forever
1426 {
1427 line = _fsi_get_line(f);
1428 if (line == NULL) break;
1429
1430 if (line[0] == '#')
1431 {
1432 free(line);
1433 line = NULL;
1434 continue;
1435 }
1436
1437 item = _fsi_parse_host(si, name, addr, af, which, line, va, vb);
1438 free(line);
1439 line = NULL;
1440
1441 if (item == NULL) continue;
1442
1443 if (which == SEL_ALL)
1444 {
1445 all = si_list_add(all, item);
1446 si_item_release(item);
1447 continue;
1448 }
1449
1450 fclose(f);
1451 return item;
1452 }
1453
1454 fclose(f);
1455 return all;
1456 }
1457
1458 /* SERVICE */
1459
1460 static si_item_t *
1461 _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)
1462 {
1463 char **tokens, **s_aliases, *xproto;
1464 int i, ntokens, match;
1465 si_item_t *item;
1466 int xport;
1467
1468 if (data == NULL) return NULL;
1469
1470 port = ntohs(port);
1471
1472 ntokens = 0;
1473 tokens = _fsi_tokenize(data, " ", 0, &ntokens);
1474 if (ntokens < 2)
1475 {
1476 free(tokens);
1477 return NULL;
1478 }
1479
1480 s_aliases = NULL;
1481 if (ntokens > 2) s_aliases = &(tokens[2]);
1482
1483 xport = atoi(tokens[1]);
1484
1485 xproto = strchr(tokens[1], '/');
1486
1487 if (xproto == NULL)
1488 {
1489 free(tokens);
1490 return NULL;
1491 }
1492
1493 *xproto++ = '\0';
1494 if ((proto != NULL) && (string_not_equal(proto, xproto)))
1495 {
1496 free(tokens);
1497 return NULL;
1498 }
1499
1500 match = 0;
1501 if (which == SEL_ALL) match = 1;
1502 else if (which == SEL_NAME)
1503 {
1504 if (string_equal(name, tokens[0])) match = 1;
1505 else if (s_aliases != NULL)
1506 {
1507 for (i = 0; (s_aliases[i] != NULL) && (match == 0); i++)
1508 if (string_equal(name, s_aliases[i])) match = 1;
1509 }
1510 }
1511 else if ((which == SEL_NUMBER) && (port == xport)) match = 1;
1512
1513 if (match == 0)
1514 {
1515 free(tokens);
1516 return NULL;
1517 }
1518
1519 /* strange but correct */
1520 xport = htons(xport);
1521
1522 item = (si_item_t *)LI_ils_create("L4488s*4s", (unsigned long)si, CATEGORY_SERVICE, 1, va, vb, tokens[0], s_aliases, xport, xproto);
1523
1524 free(tokens);
1525
1526 return item;
1527 }
1528
1529 static void *
1530 _fsi_get_service(si_mod_t *si, const char *name, const char *proto, int port, int which)
1531 {
1532 char *p, *line;
1533 si_item_t *item;
1534 FILE *f;
1535 si_list_t *all;
1536 uint64_t va, vb;
1537
1538 if ((which == SEL_NAME) && (name == NULL)) return NULL;
1539 if ((which == SEL_NUMBER) && (port == 0)) return NULL;
1540
1541 f = fopen(_PATH_SERVICES, "r");
1542 if (f == NULL) return NULL;
1543
1544 _fsi_get_validation(si, VALIDATION_SERVICES, _PATH_SERVICES, f, &va, &vb);
1545
1546 all = NULL;
1547
1548 forever
1549 {
1550 line = _fsi_get_line(f);
1551 if (line == NULL) break;
1552
1553 if (line[0] == '#')
1554 {
1555 free(line);
1556 line = NULL;
1557 continue;
1558 }
1559
1560 p = strchr(line, '#');
1561 if (p != NULL) *p = '\0';
1562
1563 item = _fsi_parse_service(si, name, proto, port, which, line, va, vb);
1564 free(line);
1565 line = NULL;
1566
1567 if (item == NULL) continue;
1568
1569 if (which == SEL_ALL)
1570 {
1571 all = si_list_add(all, item);
1572 si_item_release(item);
1573 continue;
1574 }
1575
1576 fclose(f);
1577 return item;
1578 }
1579
1580 fclose(f);
1581 return all;
1582 }
1583
1584 /*
1585 * Generic name/number/aliases lookup
1586 * Works for protocols, networks, and rpcs
1587 */
1588
1589 static si_item_t *
1590 _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)
1591 {
1592 char **tokens, **aliases;
1593 int i, ntokens, match, xnum;
1594 si_item_t *item;
1595
1596 if (data == NULL) return NULL;
1597
1598 ntokens = 0;
1599 tokens = _fsi_tokenize(data, " ", 0, &ntokens);
1600 if (ntokens < 2)
1601 {
1602 free(tokens);
1603 return NULL;
1604 }
1605
1606 xnum = atoi(tokens[1]);
1607
1608 aliases = NULL;
1609 if (ntokens > 2) aliases = &(tokens[2]);
1610
1611 match = 0;
1612
1613 if (which == SEL_ALL) match = 1;
1614 else if (which == SEL_NAME)
1615 {
1616 if (string_equal(name, tokens[0])) match = 1;
1617 else if (aliases != NULL)
1618 {
1619 for (i = 0; (aliases[i] != NULL) && (match == 0); i++)
1620 if (string_equal(name, aliases[i])) match = 1;
1621 }
1622 }
1623 else if ((which == SEL_NUMBER) && (num == xnum)) match = 1;
1624
1625 if (match == 0)
1626 {
1627 free(tokens);
1628 return NULL;
1629 }
1630
1631 switch (cat) {
1632 case CATEGORY_NETWORK:
1633 // struct netent
1634 item = (si_item_t *)LI_ils_create("L4488s*44", (unsigned long)si, cat, 1, va, vb, tokens[0], aliases, AF_INET, xnum);
1635 break;
1636 case CATEGORY_PROTOCOL:
1637 case CATEGORY_RPC:
1638 // struct protoent
1639 // struct rpcent
1640 item = (si_item_t *)LI_ils_create("L4488s*4", (unsigned long)si, cat, 1, va, vb, tokens[0], aliases, xnum);
1641 break;
1642 default:
1643 abort();
1644 }
1645
1646 free(tokens);
1647
1648 return item;
1649 }
1650
1651 static void *
1652 _fsi_get_name_number_aliases(si_mod_t *si, const char *name, int num, int which, int cat)
1653 {
1654 char *p, *line;
1655 si_item_t *item;
1656 FILE *f;
1657 si_list_t *all;
1658 uint64_t va, vb;
1659 const char *path;
1660 int vtype;
1661
1662 switch (cat) {
1663 case CATEGORY_NETWORK:
1664 vtype = VALIDATION_NETWORKS;
1665 path = _PATH_NETWORKS;
1666 break;
1667 case CATEGORY_PROTOCOL:
1668 vtype = VALIDATION_PROTOCOLS;
1669 path = _PATH_PROTOCOLS;
1670 break;
1671 case CATEGORY_RPC:
1672 vtype = VALIDATION_RPC;
1673 path = _PATH_RPCS;
1674 break;
1675 default:
1676 abort();
1677 }
1678
1679 f = fopen(path, "r");
1680 if (f == NULL) return NULL;
1681
1682 _fsi_get_validation(si, vtype, path, f, &va, &vb);
1683
1684 all = NULL;
1685
1686 forever
1687 {
1688 line = _fsi_get_line(f);
1689 if (line == NULL) break;
1690
1691 if (line[0] == '#')
1692 {
1693 free(line);
1694 line = NULL;
1695 continue;
1696 }
1697
1698 p = strchr(line, '#');
1699 if (p != NULL) *p = '\0';
1700
1701 item = _fsi_parse_name_num_aliases(si, name, num, which, line, va, vb, cat);
1702 free(line);
1703 line = NULL;
1704
1705 if (item == NULL) continue;
1706
1707 if (which == SEL_ALL)
1708 {
1709 all = si_list_add(all, item);
1710 si_item_release(item);
1711 continue;
1712 }
1713
1714 fclose(f);
1715 return item;
1716 }
1717
1718 fclose(f);
1719 return all;
1720 }
1721
1722 /* MOUNT */
1723
1724 static si_item_t *
1725 _fsi_parse_fs(si_mod_t *si, const char *name, int which, char *data, uint64_t va, uint64_t vb)
1726 {
1727 char **tokens, *tmp, **opts, *fstype;
1728 int ntokens, match, i, freq, passno;
1729 si_item_t *item;
1730
1731 if (data == NULL) return NULL;
1732
1733 freq = 0;
1734 passno = 0;
1735 fstype = NULL;
1736
1737 ntokens = 0;
1738 tokens = _fsi_tokenize(data, " ", 0, &ntokens);
1739 if ((ntokens < 4) || (ntokens > 6))
1740 {
1741 free(tokens);
1742 return NULL;
1743 }
1744
1745 if (ntokens >= 5) freq = atoi(tokens[4]);
1746 if (ntokens == 6) passno = atoi(tokens[5]);
1747
1748 tmp = strdup(tokens[3]);
1749 if (tmp == NULL)
1750 {
1751 free(tokens);
1752 return NULL;
1753 }
1754
1755 ntokens = 0;
1756 opts = _fsi_tokenize(tmp, ",", 0, &ntokens);
1757
1758 if (opts == NULL)
1759 {
1760 free(tokens);
1761 free(tmp);
1762 return NULL;
1763 }
1764
1765 for (i = 0; i < ntokens; i++)
1766 {
1767 if ((string_equal(opts[i], "rw")) || (string_equal(opts[i], "ro")) || (string_equal(opts[i], "sw")) || (string_equal(opts[i], "xx")))
1768 {
1769 fstype = opts[i];
1770 break;
1771 }
1772 }
1773
1774 match = 0;
1775
1776 if (which == SEL_ALL) match = 1;
1777 else if ((which == SEL_NAME) && (string_equal(name, tokens[0]))) match = 1;
1778 else if ((which == SEL_NUMBER) && (string_equal(name, tokens[1]))) match = 1;
1779
1780 if (match == 0)
1781 {
1782 free(tokens);
1783 return NULL;
1784 }
1785
1786 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);
1787
1788 free(tokens);
1789 free(opts);
1790 free(tmp);
1791
1792 return item;
1793 }
1794
1795 static char *
1796 _fsi_get_device_path(dev_t target_dev)
1797 {
1798 char *result;
1799 char dev[PATH_MAX];
1800 char *name;
1801 char namebuf[PATH_MAX];
1802
1803 result = NULL;
1804
1805 strlcpy(dev, _PATH_DEV, sizeof(dev));
1806
1807 /* The root device in fstab should always be a block special device */
1808 name = devname_r(target_dev, S_IFBLK, namebuf, sizeof(namebuf));
1809 if (name == NULL)
1810 {
1811 DIR *dirp;
1812 struct stat devst;
1813 struct dirent *ent, entbuf;
1814
1815 /* No _PATH_DEVDB. We have to search for it the slow way */
1816 dirp = opendir(_PATH_DEV);
1817 if (dirp == NULL) return NULL;
1818
1819 while (readdir_r(dirp, &entbuf, &ent) == 0 && ent != NULL)
1820 {
1821 /* Look for a block special device */
1822 if (ent->d_type == DT_BLK)
1823 {
1824 strlcat(dev, ent->d_name, sizeof(dev));
1825 if (stat(dev, &devst) == 0)
1826 {
1827 if (devst.st_rdev == target_dev) {
1828 result = strdup(dev);
1829 break;
1830 }
1831 }
1832 }
1833
1834 /* reset dev to _PATH_DEV and try again */
1835 dev[sizeof(_PATH_DEV) - 1] = '\0';
1836 }
1837
1838 if (dirp) closedir(dirp);
1839 }
1840 else
1841 {
1842 /* We found the _PATH_DEVDB entry */
1843 strlcat(dev, name, sizeof(dev));
1844 result = strdup(dev);
1845 }
1846
1847 return result;
1848 }
1849
1850 static si_item_t *
1851 _fsi_fs_root(si_mod_t *si)
1852 {
1853 dispatch_once(&rootfs_once, ^{
1854 struct stat rootstat;
1855 struct statfs rootfsinfo;
1856 char *root_spec;
1857 const char *root_path = "/";
1858
1859 if (stat(root_path, &rootstat) < 0) return;
1860 if (statfs(root_path, &rootfsinfo) < 0) return;
1861
1862 // Check to make sure we're not looking at a synthetic root:
1863 if (string_equal(rootfsinfo.f_fstypename, "synthfs")) {
1864 root_path = "/root";
1865 if (stat(root_path, &rootstat) < 0) return;
1866 if (statfs(root_path, &rootfsinfo) < 0) return;
1867 }
1868
1869 root_spec = _fsi_get_device_path(rootstat.st_dev);
1870
1871 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);
1872 });
1873
1874 return si_item_retain(rootfs);
1875 }
1876
1877 static void *
1878 _fsi_get_fs(si_mod_t *si, const char *name, int which)
1879 {
1880 char *line;
1881 si_item_t *item;
1882 FILE *f;
1883 si_list_t *all;
1884 uint64_t va, vb;
1885 int synthesize_root;
1886 struct fstab *rfs;
1887
1888 if ((which != SEL_ALL) && (name == NULL)) return NULL;
1889
1890 all = NULL;
1891 f = NULL;
1892 #ifdef SYNTH_ROOTFS
1893 synthesize_root = 1;
1894 #else
1895 synthesize_root = 0;
1896 #endif
1897
1898 f = fopen(_PATH_FSTAB, "r");
1899 if ((f == NULL) || (synthesize_root == 1))
1900 {
1901 item = _fsi_fs_root(si);
1902
1903 rfs = NULL;
1904 if (item != NULL) rfs = (struct fstab *)((uintptr_t)item + sizeof(si_item_t));
1905
1906 switch (which)
1907 {
1908 case SEL_NAME:
1909 {
1910 if ((rfs != NULL) && (string_equal(name, rfs->fs_spec)))
1911 {
1912 if (f != NULL) fclose(f);
1913 return item;
1914 }
1915
1916 break;
1917 }
1918
1919 case SEL_NUMBER:
1920 {
1921 if ((rfs != NULL) && (string_equal(name, rfs->fs_file)))
1922 {
1923 if (f != NULL) fclose(f);
1924 return item;
1925 }
1926
1927 break;
1928 }
1929
1930 case SEL_ALL:
1931 {
1932 all = si_list_add(all, item);
1933 si_item_release(item);
1934 break;
1935 }
1936 }
1937 }
1938
1939 if (f == NULL) return all;
1940
1941 _fsi_get_validation(si, VALIDATION_FSTAB, _PATH_FSTAB, f, &va, &vb);
1942
1943 forever
1944 {
1945 line = _fsi_get_line(f);
1946 if (line == NULL) break;
1947
1948 if (line[0] == '#')
1949 {
1950 free(line);
1951 line = NULL;
1952 continue;
1953 }
1954
1955 item = _fsi_parse_fs(si, name, which, line, va, vb);
1956 free(line);
1957 line = NULL;
1958
1959 if (item == NULL) continue;
1960
1961 if (which == SEL_ALL)
1962 {
1963 all = si_list_add(all, item);
1964 si_item_release(item);
1965 continue;
1966 }
1967
1968 fclose(f);
1969 return item;
1970 }
1971
1972 fclose(f);
1973 return all;
1974 }
1975
1976 static int
1977 file_is_valid(si_mod_t *si, si_item_t *item)
1978 {
1979 si_mod_t *src;
1980
1981 if (si == NULL) return 0;
1982 if (item == NULL) return 0;
1983 if (si->name == NULL) return 0;
1984 if (item->src == NULL) return 0;
1985
1986 src = (si_mod_t *)item->src;
1987
1988 if (src->name == NULL) return 0;
1989 if (string_not_equal(si->name, src->name)) return 0;
1990
1991 if (item == rootfs) return 1;
1992
1993 return _fsi_validate(si, item->type, item->validation_a, item->validation_b);
1994 }
1995
1996 static si_item_t *
1997 file_user_byname(si_mod_t *si, const char *name)
1998 {
1999 return _fsi_get_user(si, name, 0, SEL_NAME);
2000 }
2001
2002 static si_item_t *
2003 file_user_byuid(si_mod_t *si, uid_t uid)
2004 {
2005 return _fsi_get_user(si, NULL, uid, SEL_NUMBER);
2006 }
2007
2008 static si_list_t *
2009 file_user_all(si_mod_t *si)
2010 {
2011 return _fsi_get_user(si, NULL, 0, SEL_ALL);
2012 }
2013
2014 static si_item_t *
2015 file_group_byname(si_mod_t *si, const char *name)
2016 {
2017 return _fsi_get_group(si, name, 0, SEL_NAME);
2018 }
2019
2020 static si_item_t *
2021 file_group_bygid(si_mod_t *si, gid_t gid)
2022 {
2023 return _fsi_get_group(si, NULL, gid, SEL_NUMBER);
2024 }
2025
2026 static si_list_t *
2027 file_group_all(si_mod_t *si)
2028 {
2029 return _fsi_get_group(si, NULL, 0, SEL_ALL);
2030 }
2031
2032 static si_item_t *
2033 file_grouplist(si_mod_t *si, const char *name)
2034 {
2035 return _fsi_get_grouplist(si, name);
2036 }
2037
2038 static si_list_t *
2039 file_netgroup_byname(si_mod_t *si, const char *name)
2040 {
2041 si_list_t *list = NULL;
2042 si_item_t *item;
2043 uint64_t va, vb;
2044 file_netgroup_t *n;
2045 file_si_private_t *pp;
2046
2047 if (name == NULL) return NULL;
2048
2049 pp = (file_si_private_t *)si->private;
2050 if (pp == NULL) return NULL;
2051
2052 _fsi_check_netgroup_cache(si);
2053
2054 pthread_mutex_lock(&file_mutex);
2055
2056 n = _fsi_find_netgroup(&(pp->file_netgroup_cache), name, 0);
2057 if (n != NULL)
2058 {
2059 file_netgroup_member_t *m = n->members;
2060 while (m != NULL)
2061 {
2062 item = (si_item_t *)LI_ils_create("L4488sss", (unsigned long)si, CATEGORY_NETGROUP, 1, va, vb, m->host, m->user, m->domain);
2063 list = si_list_add(list, item);
2064 m = m->next;
2065 }
2066 }
2067
2068 pthread_mutex_unlock(&file_mutex);
2069
2070 return list;
2071 }
2072
2073 static int
2074 file_in_netgroup(si_mod_t *si, const char *group, const char *host, const char *user, const char *domain)
2075 {
2076 file_netgroup_t *n;
2077 file_netgroup_member_t *m;
2078 file_si_private_t *pp;
2079
2080 if (group == NULL) return 0;
2081
2082 pp = (file_si_private_t *)si->private;
2083 if (pp == NULL) return 0;
2084
2085 _fsi_check_netgroup_cache(si);
2086
2087 pthread_mutex_lock(&file_mutex);
2088
2089 n = _fsi_find_netgroup(&(pp->file_netgroup_cache), group, 0);
2090 if (n == NULL)
2091 {
2092 pthread_mutex_unlock(&file_mutex);
2093 return 0;
2094 }
2095
2096 m = n->members;
2097 while (m != NULL)
2098 {
2099 file_netgroup_member_t *x = m;
2100 m = m->next;
2101
2102 if (host != NULL)
2103 {
2104 if (x->host == NULL) continue;
2105 if (strcmp(host, x->host)) continue;
2106 }
2107
2108 if (user != NULL)
2109 {
2110 if (x->user == NULL) continue;
2111 if (strcmp(user, x->user)) continue;
2112 }
2113
2114 if (domain != NULL)
2115 {
2116 if (x->domain == NULL) continue;
2117 if (strcmp(domain, x->domain)) continue;
2118 }
2119
2120 pthread_mutex_unlock(&file_mutex);
2121 return 1;
2122 }
2123
2124 pthread_mutex_unlock(&file_mutex);
2125 return 0;
2126 }
2127
2128 static si_item_t *
2129 file_host_byname(si_mod_t *si, const char *name, int af, const char *ignored, uint32_t *err)
2130 {
2131 si_item_t *item;
2132
2133 if (err != NULL) *err = SI_STATUS_NO_ERROR;
2134
2135 item = _fsi_get_host(si, name, NULL, af, SEL_NAME, err);
2136 if ((item == NULL) && (err != NULL) && (*err == 0)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
2137
2138 return item;
2139 }
2140
2141 static si_item_t *
2142 file_host_byaddr(si_mod_t *si, const void *addr, int af, const char *ignored, uint32_t *err)
2143 {
2144 si_item_t *item;
2145
2146 if (err != NULL) *err = SI_STATUS_NO_ERROR;
2147
2148 item = _fsi_get_host(si, NULL, addr, af, SEL_NUMBER, err);
2149 if ((item == NULL) && (err != NULL) && (*err == 0)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
2150
2151 return item;
2152 }
2153
2154 static si_list_t *
2155 file_host_all(si_mod_t *si)
2156 {
2157 return _fsi_get_host(si, NULL, NULL, 0, SEL_ALL, NULL);
2158 }
2159
2160 static si_item_t *
2161 file_network_byname(si_mod_t *si, const char *name)
2162 {
2163 if (name == NULL) return NULL;
2164 return _fsi_get_name_number_aliases(si, name, 0, SEL_NAME, CATEGORY_NETWORK);
2165 }
2166
2167 static si_item_t *
2168 file_network_byaddr(si_mod_t *si, uint32_t addr)
2169 {
2170 return _fsi_get_name_number_aliases(si, NULL, (int)addr, SEL_NUMBER, CATEGORY_NETWORK);
2171 }
2172
2173 static si_list_t *
2174 file_network_all(si_mod_t *si)
2175 {
2176 return _fsi_get_name_number_aliases(si, NULL, 0, SEL_ALL, CATEGORY_NETWORK);
2177 }
2178
2179 static si_item_t *
2180 file_service_byname(si_mod_t *si, const char *name, const char *proto)
2181 {
2182 return _fsi_get_service(si, name, proto, 0, SEL_NAME);
2183 }
2184
2185 static si_item_t *
2186 file_service_byport(si_mod_t *si, int port, const char *proto)
2187 {
2188 return _fsi_get_service(si, NULL, proto, port, SEL_NUMBER);
2189 }
2190
2191 static si_list_t *
2192 file_service_all(si_mod_t *si)
2193 {
2194 return _fsi_get_service(si, NULL, NULL, 0, SEL_ALL);
2195 }
2196
2197 static si_item_t *
2198 file_protocol_byname(si_mod_t *si, const char *name)
2199 {
2200 if (name == NULL) return NULL;
2201 return _fsi_get_name_number_aliases(si, name, 0, SEL_NAME, CATEGORY_PROTOCOL);
2202 }
2203
2204 static si_item_t *
2205 file_protocol_bynumber(si_mod_t *si, int number)
2206 {
2207 return _fsi_get_name_number_aliases(si, NULL, number, SEL_NUMBER, CATEGORY_PROTOCOL);
2208 }
2209
2210 static si_list_t *
2211 file_protocol_all(si_mod_t *si)
2212 {
2213 return _fsi_get_name_number_aliases(si, NULL, 0, SEL_ALL, CATEGORY_PROTOCOL);
2214 }
2215
2216 static si_item_t *
2217 file_rpc_byname(si_mod_t *si, const char *name)
2218 {
2219 if (name == NULL) return NULL;
2220 return _fsi_get_name_number_aliases(si, name, 0, SEL_NAME, CATEGORY_RPC);
2221 }
2222
2223 static si_item_t *
2224 file_rpc_bynumber(si_mod_t *si, int number)
2225 {
2226 return _fsi_get_name_number_aliases(si, NULL, number, SEL_NUMBER, CATEGORY_RPC);
2227 }
2228
2229 static si_list_t *
2230 file_rpc_all(si_mod_t *si)
2231 {
2232 return _fsi_get_name_number_aliases(si, NULL, 0, SEL_ALL, CATEGORY_RPC);
2233 }
2234
2235 static si_item_t *
2236 file_fs_byspec(si_mod_t *si, const char *spec)
2237 {
2238 return _fsi_get_fs(si, spec, SEL_NAME);
2239 }
2240
2241 static si_item_t *
2242 file_fs_byfile(si_mod_t *si, const char *file)
2243 {
2244 return _fsi_get_fs(si, file, SEL_NUMBER);
2245 }
2246
2247 static si_list_t *
2248 file_fs_all(si_mod_t *si)
2249 {
2250 return _fsi_get_fs(si, NULL, SEL_ALL);
2251 }
2252
2253 static si_item_t *
2254 file_alias_byname(si_mod_t *si, const char *name)
2255 {
2256 return _fsi_get_alias(si, name, SEL_NAME);
2257 }
2258
2259 static si_list_t *
2260 file_alias_all(si_mod_t *si)
2261 {
2262 return _fsi_get_alias(si, NULL, SEL_ALL);
2263 }
2264
2265 static si_item_t *
2266 file_mac_byname(si_mod_t *si, const char *name)
2267 {
2268 return _fsi_get_ether(si, name, SEL_NAME);
2269 }
2270
2271 static si_item_t *
2272 file_mac_bymac(si_mod_t *si, const char *mac)
2273 {
2274 return _fsi_get_ether(si, mac, SEL_NUMBER);
2275 }
2276
2277 static si_list_t *
2278 file_mac_all(si_mod_t *si)
2279 {
2280 return _fsi_get_ether(si, NULL, SEL_ALL);
2281 }
2282
2283 static si_list_t *
2284 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)
2285 {
2286 if (err != NULL) *err = SI_STATUS_NO_ERROR;
2287 return _gai_simple(si, node, serv, family, socktype, proto, flags, interface, err);
2288 }
2289
2290 si_mod_t *
2291 si_module_static_file(void)
2292 {
2293 static const struct si_mod_vtable_s file_vtable =
2294 {
2295 .sim_is_valid = &file_is_valid,
2296
2297 .sim_user_byname = &file_user_byname,
2298 .sim_user_byuid = &file_user_byuid,
2299 .sim_user_all = &file_user_all,
2300
2301 .sim_group_byname = &file_group_byname,
2302 .sim_group_bygid = &file_group_bygid,
2303 .sim_group_all = &file_group_all,
2304
2305 .sim_grouplist = &file_grouplist,
2306
2307 .sim_netgroup_byname = &file_netgroup_byname,
2308 .sim_in_netgroup = &file_in_netgroup,
2309
2310 .sim_alias_byname = &file_alias_byname,
2311 .sim_alias_all = &file_alias_all,
2312
2313 .sim_host_byname = &file_host_byname,
2314 .sim_host_byaddr = &file_host_byaddr,
2315 .sim_host_all = &file_host_all,
2316
2317 .sim_network_byname = &file_network_byname,
2318 .sim_network_byaddr = &file_network_byaddr,
2319 .sim_network_all = &file_network_all,
2320
2321 .sim_service_byname = &file_service_byname,
2322 .sim_service_byport = &file_service_byport,
2323 .sim_service_all = &file_service_all,
2324
2325 .sim_protocol_byname = &file_protocol_byname,
2326 .sim_protocol_bynumber = &file_protocol_bynumber,
2327 .sim_protocol_all = &file_protocol_all,
2328
2329 .sim_rpc_byname = &file_rpc_byname,
2330 .sim_rpc_bynumber = &file_rpc_bynumber,
2331 .sim_rpc_all = &file_rpc_all,
2332
2333 .sim_fs_byspec = &file_fs_byspec,
2334 .sim_fs_byfile = &file_fs_byfile,
2335 .sim_fs_all = &file_fs_all,
2336
2337 .sim_mac_byname = &file_mac_byname,
2338 .sim_mac_bymac = &file_mac_bymac,
2339 .sim_mac_all = &file_mac_all,
2340
2341 .sim_wants_addrinfo = NULL,
2342 .sim_addrinfo = &file_addrinfo,
2343
2344 /* no nameinfo support */
2345 .sim_nameinfo = NULL,
2346 };
2347
2348 static si_mod_t si =
2349 {
2350 .vers = 1,
2351 .refcount = 1,
2352 .flags = SI_MOD_FLAG_STATIC,
2353
2354 .private = NULL,
2355 .vtable = &file_vtable,
2356 };
2357
2358 static dispatch_once_t once;
2359
2360 dispatch_once(&once, ^{
2361 si.name = strdup("file");
2362 file_si_private_t *pp = calloc(1, sizeof(file_si_private_t));
2363 if (pp != NULL)
2364 {
2365 int i;
2366 for (i = 0; i < VALIDATION_COUNT; i++) pp->notify_token[i] = -1;
2367
2368 /* hardwired for now, but we may want to make this configurable someday */
2369 pp->validation_notify_mask = VALIDATION_MASK_HOSTS | VALIDATION_MASK_SERVICES;
2370 }
2371
2372 si.private = pp;
2373 });
2374
2375 return (si_mod_t *)&si;
2376 }