void profile_read(const char *fname) { EUID_ASSERT(); // exit program if maximum include level was reached if (include_level > MAX_INCLUDE_LEVEL) { fprintf(stderr, "Error: maximum profile include level was reached\n"); exit(1); } // check file invalid_filename(fname); if (strlen(fname) == 0 || is_dir(fname)) { fprintf(stderr, "Error: invalid profile file\n"); exit(1); } if (access(fname, R_OK)) { // if the file ends in ".local", do not exit const char *base = gnu_basename(fname); char *ptr = strstr(base, ".local"); if (ptr && strlen(ptr) == 6) return; fprintf(stderr, "Error: cannot access profile file\n"); exit(1); } // allow debuggers if (arg_allow_debuggers) { char *tmp = strrchr(fname, '/'); if (tmp && *(tmp + 1) != '\0') { tmp++; if (strcmp(tmp, "disable-devel.inc") == 0) return; } } // open profile file: FILE *fp = fopen(fname, "r"); if (fp == NULL) { fprintf(stderr, "Error: cannot open profile file %s\n", fname); exit(1); } int msg_printed = 0; // read the file line by line char buf[MAX_READ + 1]; int lineno = 0; while (fgets(buf, MAX_READ, fp)) { ++lineno; // remove empty space - ptr in allocated memory char *ptr = line_remove_spaces(buf); if (ptr == NULL) continue; // comments if (*ptr == '#' || *ptr == '\0') { free(ptr); continue; } // process quiet if (strcmp(ptr, "quiet") == 0) { arg_quiet = 1; free(ptr); continue; } if (!msg_printed) { if (!arg_quiet) fprintf(stderr, "Reading profile %s\n", fname); msg_printed = 1; } // process include if (strncmp(ptr, "include ", 8) == 0) { include_level++; // extract profile filename and new skip params char *newprofile = ptr + 8; // profile name // expand ${HOME}/ in front of the new profile file char *newprofile2 = expand_home(newprofile, cfg.homedir); // recursivity profile_read((newprofile2)? newprofile2:newprofile); include_level--; if (newprofile2) free(newprofile2); free(ptr); continue; } // verify syntax, exit in case of error if (profile_check_line(ptr, lineno, fname)) profile_add(ptr); // we cannot free ptr here, data is extracted from ptr and linked as a pointer in cfg structure // else { // free(ptr); // } #ifdef HAVE_GCOV __gcov_flush(); #endif } fclose(fp); }
void profile_read(const char *fname) { EUID_ASSERT(); // exit program if maximum include level was reached if (include_level > MAX_INCLUDE_LEVEL) { fprintf(stderr, "Error: maximum profile include level was reached\n"); exit(1); } if (strlen(fname) == 0) { fprintf(stderr, "Error: invalid profile file\n"); exit(1); } // open profile file: FILE *fp = fopen(fname, "r"); if (fp == NULL) { fprintf(stderr, "Error: cannot open profile file %s\n", fname); exit(1); } if (!arg_quiet) fprintf(stderr, "Reading profile %s\n", fname); // read the file line by line char buf[MAX_READ + 1]; int lineno = 0; while (fgets(buf, MAX_READ, fp)) { ++lineno; // remove empty space - ptr in allocated memory char *ptr = line_remove_spaces(buf); if (ptr == NULL) continue; // comments if (*ptr == '#' || *ptr == '\0') { free(ptr); continue; } // process include if (strncmp(ptr, "include ", 8) == 0) { include_level++; // extract profile filename and new skip params char *newprofile = ptr + 8; // profile name // expand ${HOME}/ in front of the new profile file char *newprofile2 = expand_home(newprofile, cfg.homedir); // recursivity profile_read((newprofile2)? newprofile2:newprofile); include_level--; if (newprofile2) free(newprofile2); free(ptr); continue; } // verify syntax, exit in case of error if (profile_check_line(ptr, lineno, fname)) profile_add(ptr); // we cannot free ptr here, data is extracted from ptr and linked as a pointer in cfg structure // else { // free(ptr); // } } fclose(fp); }
int checkcfg(int val) { EUID_ASSERT(); assert(val < CFG_MAX); int line = 0; if (!initialized) { // initialize defaults int i; for (i = 0; i < CFG_MAX; i++) cfg_val[i] = 1; // most of them are enabled by default cfg_val[CFG_RESTRICTED_NETWORK] = 0; // disabled by default cfg_val[CFG_FORCE_NONEWPRIVS] = 0; // disabled by default // open configuration file char *fname; if (asprintf(&fname, "%s/firejail.config", SYSCONFDIR) == -1) errExit("asprintf"); FILE *fp = fopen(fname, "r"); if (!fp) { #ifdef HAVE_GLOBALCFG fprintf(stderr, "Warning: Firejail configuration file %s not found\n", fname); exit(1); #else initialized = 1; return cfg_val[val]; #endif } // if the file exists, it should be owned by root struct stat s; if (stat(fname, &s) == -1) errExit("stat"); if (s.st_uid != 0 || s.st_gid != 0) { fprintf(stderr, "Error: configuration file should be owned by root\n"); exit(1); } // read configuration file char buf[MAX_READ]; while (fgets(buf,MAX_READ, fp)) { line++; if (*buf == '#' || *buf == '\n') continue; // parse line char *ptr = line_remove_spaces(buf); if (!ptr) continue; // file transfer if (strncmp(ptr, "file-transfer ", 14) == 0) { if (strcmp(ptr + 14, "yes") == 0) cfg_val[CFG_FILE_TRANSFER] = 1; else if (strcmp(ptr + 14, "no") == 0) cfg_val[CFG_FILE_TRANSFER] = 0; else goto errout; } // x11 else if (strncmp(ptr, "x11 ", 4) == 0) { if (strcmp(ptr + 4, "yes") == 0) cfg_val[CFG_X11] = 1; else if (strcmp(ptr + 4, "no") == 0) cfg_val[CFG_X11] = 0; else goto errout; } // bind else if (strncmp(ptr, "bind ", 5) == 0) { if (strcmp(ptr + 5, "yes") == 0) cfg_val[CFG_BIND] = 1; else if (strcmp(ptr + 5, "no") == 0) cfg_val[CFG_BIND] = 0; else goto errout; } // user namespace else if (strncmp(ptr, "userns ", 7) == 0) { if (strcmp(ptr + 7, "yes") == 0) cfg_val[CFG_USERNS] = 1; else if (strcmp(ptr + 7, "no") == 0) cfg_val[CFG_USERNS] = 0; else goto errout; } // chroot else if (strncmp(ptr, "chroot ", 7) == 0) { if (strcmp(ptr + 7, "yes") == 0) cfg_val[CFG_CHROOT] = 1; else if (strcmp(ptr + 7, "no") == 0) cfg_val[CFG_CHROOT] = 0; else goto errout; } // nonewprivs else if (strncmp(ptr, "force-nonewprivs ", 17) == 0) { if (strcmp(ptr + 17, "yes") == 0) cfg_val[CFG_SECCOMP] = 1; else if (strcmp(ptr + 17, "no") == 0) cfg_val[CFG_SECCOMP] = 0; else goto errout; } // seccomp else if (strncmp(ptr, "seccomp ", 8) == 0) { if (strcmp(ptr + 8, "yes") == 0) cfg_val[CFG_SECCOMP] = 1; else if (strcmp(ptr + 8, "no") == 0) cfg_val[CFG_SECCOMP] = 0; else goto errout; } // whitelist else if (strncmp(ptr, "whitelist ", 10) == 0) { if (strcmp(ptr + 10, "yes") == 0) cfg_val[CFG_WHITELIST] = 1; else if (strcmp(ptr + 10, "no") == 0) cfg_val[CFG_WHITELIST] = 0; else goto errout; } // network else if (strncmp(ptr, "network ", 8) == 0) { if (strcmp(ptr + 8, "yes") == 0) cfg_val[CFG_NETWORK] = 1; else if (strcmp(ptr + 8, "no") == 0) cfg_val[CFG_NETWORK] = 0; else goto errout; } // network else if (strncmp(ptr, "restricted-network ", 19) == 0) { if (strcmp(ptr + 19, "yes") == 0) cfg_val[CFG_RESTRICTED_NETWORK] = 1; else if (strcmp(ptr + 19, "no") == 0) cfg_val[CFG_RESTRICTED_NETWORK] = 0; else goto errout; } // netfilter else if (strncmp(ptr, "netfilter-default ", 18) == 0) { char *fname = ptr + 18; while (*fname == ' ' || *fname == '\t') ptr++; char *end = strchr(fname, ' '); if (end) *end = '\0'; // is the file present? struct stat s; if (stat(fname, &s) == -1) { fprintf(stderr, "Error: netfilter-default file %s not available\n", fname); exit(1); } netfilter_default = strdup(fname); if (!netfilter_default) errExit("strdup"); if (arg_debug) printf("netfilter default file %s\n", fname); } // Xephyr screen size else if (strncmp(ptr, "xephyr-screen ", 14) == 0) { // expecting two numbers and an x between them int n1; int n2; int rv = sscanf(ptr + 14, "%dx%d", &n1, &n2); if (rv != 2) goto errout; if (asprintf(&xephyr_screen, "%dx%d", n1, n2) == -1) errExit("asprintf"); } // xephyr window title else if (strncmp(ptr, "xephyr-window-title ", 20) == 0) { if (strcmp(ptr + 20, "yes") == 0) cfg_val[CFG_XEPHYR_WINDOW_TITLE] = 1; else if (strcmp(ptr + 20, "no") == 0) cfg_val[CFG_XEPHYR_WINDOW_TITLE] = 0; else goto errout; } // Xephyr command extra parameters else if (strncmp(ptr, "xephyr-extra-params ", 19) == 0) { xephyr_extra_params = strdup(ptr + 19); if (!xephyr_extra_params) errExit("strdup"); } else goto errout; free(ptr); } fclose(fp); free(fname); initialized = 1; } return cfg_val[val]; errout: fprintf(stderr, "Error: invalid line %d in firejail configuration file\n", line ); exit(1); }
// skip1, skip2 - if the string is found in the line, the line is not interpreted void profile_read(const char *fname, const char *skip1, const char *skip2) { // exit program if maximum include level was reached if (include_level > MAX_INCLUDE_LEVEL) { fprintf(stderr, "Error: maximum profile include level was reached\n"); exit(1); } if (strlen(fname) == 0) { fprintf(stderr, "Error: invalid profile file\n"); exit(1); } // open profile file: FILE *fp = fopen(fname, "r"); if (fp == NULL) { fprintf(stderr, "Error: cannot open profile file\n"); exit(1); } if (!arg_quiet) fprintf(stderr, "Reading profile %s\n", fname); // read the file line by line char buf[MAX_READ + 1]; int lineno = 0; while (fgets(buf, MAX_READ, fp)) { ++lineno; // remove empty space - ptr in allocated memory char *ptr = line_remove_spaces(buf); if (ptr == NULL) continue; // comments if (*ptr == '#' || *ptr == '\0') { free(ptr); continue; } // process include if (strncmp(ptr, "include ", 8) == 0) { include_level++; // extract profile filename and new skip params char *newprofile = ptr + 8; // profile name char *newskip1 = NULL; // new skip1 char *newskip2 = NULL; // new skip2 char *p = newprofile; while (*p != '\0') { if (*p == ' ') { *p = '\0'; if (newskip1 == NULL) newskip1 = p + 1; else if (newskip2 == NULL) newskip2 = p + 1; } p++; } // expand ${HOME}/ in front of the new profile file char *newprofile2 = expand_home(newprofile, cfg.homedir); // recursivity profile_read((newprofile2)? newprofile2:newprofile, newskip1, newskip2); include_level--; if (newprofile2) free(newprofile2); free(ptr); continue; } // skip if (skip1) { if (strstr(ptr, skip1)) { free(ptr); continue; } } if (skip2) { if (strstr(ptr, skip2)) { free(ptr); continue; } } // verify syntax, exit in case of error if (profile_check_line(ptr, lineno)) profile_add(ptr); } fclose(fp); }
void profile_read(const char *fname) { // exit program if maximum include level was reached if (include_level > MAX_INCLUDE_LEVEL) { fprintf(stderr, "Error: maximum profile include level was reached\n"); exit(1); } if (strlen(fname) == 0) { fprintf(stderr, "Error: invalid profile file\n"); exit(1); } // open profile file: FILE *fp = fopen(fname, "r"); if (fp == NULL) { fprintf(stderr, "Error: cannot open profile file\n"); exit(1); } printf("Reading %s\n", fname); // linked list of lines struct mylist { char *line; struct mylist *next; } m = { NULL, NULL }; struct mylist *mptr = &m; int mylist_cnt = 1; // read the file line by line char buf[MAX_READ + 1]; int lineno = 0; while (fgets(buf, MAX_READ, fp)) { ++lineno; // remove empty space char *ptr = line_remove_spaces(buf); if (ptr == NULL || *ptr == '\0') continue; // comments if (*ptr == '#') continue; // process include if (strncmp(ptr, "include ", 8) == 0) { include_level++; // recursivity profile_read(ptr + 8); include_level--; continue; } // verify syntax, exit in case of error if (profile_check_line(ptr, lineno)) profile_add(ptr); } fclose(fp); }