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