static int init(struct selabel_handle *rec, struct selinux_opt *opts, unsigned n) { struct saved_data *data = (struct saved_data *)rec->data; const char *path = NULL; FILE *fp; char line_buf[BUFSIZ]; unsigned int lineno = 0, maxnspec, pass; int status = -1; struct stat sb; /* Process arguments */ while (n--) switch (opts[n].type) { case SELABEL_OPT_PATH: path = opts[n].value; break; } if (!path) return -1; /* Open the specification file. */ if ((fp = fopen(path, "r")) == NULL) return -1; if (fstat(fileno(fp), &sb) < 0) goto finish; errno = EINVAL; if (!S_ISREG(sb.st_mode)) goto finish; /* * Two passes of the specification file. First is to get the size. * After the first pass, the spec array is malloced to the appropriate * size. Second pass is to populate the spec array and check for * dups. */ maxnspec = UINT_MAX / sizeof(spec_t); for (pass = 0; pass < 2; pass++) { data->nspec = 0; while (fgets(line_buf, sizeof line_buf - 1, fp) && data->nspec < maxnspec) { if (process_line(rec, path, line_buf, pass, ++lineno) != 0) goto finish; } if (pass == 1) { status = nodups_specs(data, path); if (status) goto finish; } if (pass == 0) { if (data->nspec == 0) { status = 0; goto finish; } if (NULL == (data->spec_arr = malloc(sizeof(spec_t) * data->nspec))) goto finish; memset(data->spec_arr, 0, sizeof(spec_t) * data->nspec); maxnspec = data->nspec; rewind(fp); } } qsort(data->spec_arr, data->nspec, sizeof(struct spec), cmp); status = 0; finish: fclose(fp); return status; }
static int init(struct selabel_handle *rec, struct selinux_opt *opts, unsigned n) { struct saved_data *data = (struct saved_data *)rec->data; const char *path = NULL; const char *prefix = NULL; FILE *fp; FILE *localfp = NULL; FILE *homedirfp = NULL; char local_path[PATH_MAX + 1]; char homedir_path[PATH_MAX + 1]; char *line_buf = NULL; size_t line_len = 0; unsigned int lineno, pass, i, j, maxnspec; spec_t *spec_copy = NULL; int status = -1, baseonly = 0; struct stat sb; /* Process arguments */ while (n--) switch(opts[n].type) { case SELABEL_OPT_PATH: path = opts[n].value; break; case SELABEL_OPT_SUBSET: prefix = opts[n].value; break; case SELABEL_OPT_BASEONLY: baseonly = !!opts[n].value; break; } /* Open the specification file. */ if (!path) path = selinux_file_context_path(); if ((fp = fopen(path, "r")) == NULL) return -1; __fsetlocking(fp, FSETLOCKING_BYCALLER); if (fstat(fileno(fp), &sb) < 0) return -1; if (!S_ISREG(sb.st_mode)) { errno = EINVAL; return -1; } if (!baseonly) { snprintf(homedir_path, sizeof(homedir_path), "%s.homedirs", path); homedirfp = fopen(homedir_path, "r"); if (homedirfp != NULL) __fsetlocking(homedirfp, FSETLOCKING_BYCALLER); snprintf(local_path, sizeof(local_path), "%s.local", path); localfp = fopen(local_path, "r"); if (localfp != NULL) __fsetlocking(localfp, FSETLOCKING_BYCALLER); } /* * Perform two passes over the specification file. * The first pass counts the number of specifications and * performs simple validation of the input. At the end * of the first pass, the spec array is allocated. * The second pass performs detailed validation of the input * and fills in the spec array. */ maxnspec = UINT_MAX / sizeof(spec_t); for (pass = 0; pass < 2; pass++) { lineno = 0; data->nspec = 0; data->ncomp = 0; while (getline(&line_buf, &line_len, fp) > 0 && data->nspec < maxnspec) { if (process_line(rec, path, prefix, line_buf, pass, ++lineno) != 0) goto finish; } if (pass == 1) { status = nodups_specs(data, path); if (status) goto finish; } lineno = 0; if (homedirfp) while (getline(&line_buf, &line_len, homedirfp) > 0 && data->nspec < maxnspec) { if (process_line (rec, homedir_path, prefix, line_buf, pass, ++lineno) != 0) goto finish; } lineno = 0; if (localfp) while (getline(&line_buf, &line_len, localfp) > 0 && data->nspec < maxnspec) { if (process_line (rec, local_path, prefix, line_buf, pass, ++lineno) != 0) goto finish; } if (pass == 0) { if (data->nspec == 0) { status = 0; goto finish; } if (NULL == (data->spec_arr = malloc(sizeof(spec_t) * data->nspec))) goto finish; memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec); maxnspec = data->nspec; rewind(fp); if (homedirfp) rewind(homedirfp); if (localfp) rewind(localfp); } } free(line_buf); /* Move exact pathname specifications to the end. */ spec_copy = malloc(sizeof(spec_t) * data->nspec); if (!spec_copy) goto finish; j = 0; for (i = 0; i < data->nspec; i++) if (data->spec_arr[i].hasMetaChars) memcpy(&spec_copy[j++], &data->spec_arr[i], sizeof(spec_t)); for (i = 0; i < data->nspec; i++) if (!data->spec_arr[i].hasMetaChars) memcpy(&spec_copy[j++], &data->spec_arr[i], sizeof(spec_t)); free(data->spec_arr); data->spec_arr = spec_copy; status = 0; finish: fclose(fp); if (data->spec_arr != spec_copy) free(data->spec_arr); if (homedirfp) fclose(homedirfp); if (localfp) fclose(localfp); return status; }
static int init(struct selabel_handle *rec, const struct selinux_opt *opts, unsigned n) { struct saved_data *data = (struct saved_data *)rec->data; const char *path = NULL; const char *prefix = NULL; char subs_file[PATH_MAX + 1]; int status = -1, baseonly = 0; /* Process arguments */ while (n--) switch(opts[n].type) { case SELABEL_OPT_PATH: path = opts[n].value; break; case SELABEL_OPT_SUBSET: prefix = opts[n].value; break; case SELABEL_OPT_BASEONLY: baseonly = !!opts[n].value; break; } /* Process local and distribution substitution files */ if (!path) { rec->dist_subs = selabel_subs_init(selinux_file_context_subs_dist_path(), rec->dist_subs); rec->subs = selabel_subs_init(selinux_file_context_subs_path(), rec->subs); path = selinux_file_context_path(); } else { snprintf(subs_file, sizeof(subs_file), "%s.subs_dist", path); rec->dist_subs = selabel_subs_init(subs_file, rec->dist_subs); snprintf(subs_file, sizeof(subs_file), "%s.subs", path); rec->subs = selabel_subs_init(subs_file, rec->subs); } rec->spec_file = strdup(path); /* * The do detailed validation of the input and fill the spec array */ status = process_file(path, NULL, rec, prefix); if (status) goto finish; if (rec->validating) { status = nodups_specs(data, path); if (status) goto finish; } if (!baseonly) { status = process_file(path, "homedirs", rec, prefix); if (status && errno != ENOENT) goto finish; status = process_file(path, "local", rec, prefix); if (status && errno != ENOENT) goto finish; } status = sort_specs(data); finish: if (status) free(data->spec_arr); return status; }