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