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