/* Copyright (C) 2005 Red Hat, Inc. */ #include <stdio.h> #include <stdio_ext.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include <semanage/handle.h> #include "parse_utils.h" #include "debug.h" int parse_init(semanage_handle_t * handle, const char *filename, void *parse_arg, parse_info_t ** info) { parse_info_t *tmp_info = (parse_info_t *) malloc(sizeof(parse_info_t)); if (!tmp_info) { ERR(handle, "out of memory, could not allocate parse structure"); return STATUS_ERR; } tmp_info->filename = filename; tmp_info->file_stream = NULL; tmp_info->working_copy = NULL; tmp_info->orig_line = NULL; tmp_info->ptr = NULL; tmp_info->lineno = 0; tmp_info->parse_arg = parse_arg; *info = tmp_info; return STATUS_SUCCESS; } void parse_release(parse_info_t * info) { parse_close(info); parse_dispose_line(info); free(info); } int parse_open(semanage_handle_t * handle, parse_info_t * info) { info->file_stream = fopen(info->filename, "r"); if (!info->file_stream && (errno != ENOENT)) { ERR(handle, "could not open file %s: %s", info->filename, strerror(errno)); return STATUS_ERR; } if (info->file_stream) __fsetlocking(info->file_stream, FSETLOCKING_BYCALLER); return STATUS_SUCCESS; } void parse_close(parse_info_t * info) { if (info->file_stream) fclose(info->file_stream); info->file_stream = NULL; } void parse_dispose_line(parse_info_t * info) { if (info->orig_line) { free(info->orig_line); info->orig_line = NULL; } if (info->working_copy) { free(info->working_copy); info->working_copy = NULL; } info->ptr = NULL; } int parse_skip_space(semanage_handle_t * handle, parse_info_t * info) { size_t buf_len = 0; ssize_t len; int lineno = info->lineno; char *buffer = NULL; char *ptr; if (info->ptr) { while (*(info->ptr) && isspace(*(info->ptr))) info->ptr++; if (*(info->ptr)) return STATUS_SUCCESS; } parse_dispose_line(info); while (info->file_stream && ((len = getline(&buffer, &buf_len, info->file_stream)) > 0)) { lineno++; /* Eat newline, preceding whitespace */ if (buffer[len - 1] == '\n') buffer[len - 1] = '\0'; ptr = buffer; while (*ptr && isspace(*ptr)) ptr++; /* Skip comments and blank lines */ if ((*ptr) && *ptr != '#') { char *tmp = strdup(buffer); if (!tmp) goto omem; info->lineno = lineno; info->working_copy = buffer; info->orig_line = tmp; info->ptr = ptr; return STATUS_SUCCESS; } } free(buffer); buffer = NULL; return STATUS_SUCCESS; omem: ERR(handle, "out of memory, could not allocate buffer"); free(buffer); return STATUS_ERR; } int parse_assert_noeof(semanage_handle_t * handle, parse_info_t * info) { if (!info->ptr) { ERR(handle, "unexpected end of file (%s: %u)", info->filename, info->lineno); return STATUS_ERR; } return STATUS_SUCCESS; } int parse_assert_space(semanage_handle_t * handle, parse_info_t * info) { if (parse_assert_noeof(handle, info) < 0) return STATUS_ERR; if (*(info->ptr) && !isspace(*(info->ptr))) { ERR(handle, "missing whitespace (%s: %u):\n%s", info->filename, info->lineno, info->orig_line); return STATUS_ERR; } if (parse_skip_space(handle, info) < 0) return STATUS_ERR; return STATUS_SUCCESS; } int parse_assert_ch(semanage_handle_t * handle, parse_info_t * info, const char ch) { if (parse_assert_noeof(handle, info) < 0) return STATUS_ERR; if (*(info->ptr) != ch) { ERR(handle, "expected character \'%c\', but found \'%c\' " "(%s: %u):\n%s", ch, *(info->ptr), info->filename, info->lineno, info->orig_line); return STATUS_ERR; } info->ptr++; return STATUS_SUCCESS; } int parse_assert_str(semanage_handle_t * handle, parse_info_t * info, const char *assert_str) { size_t len = strlen(assert_str); if (parse_assert_noeof(handle, info) < 0) return STATUS_ERR; if (strncmp(info->ptr, assert_str, len)) { ERR(handle, "experted string \"%s\", but found \"%s\" " "(%s: %u):\n%s", assert_str, info->ptr, info->filename, info->lineno, info->orig_line); return STATUS_ERR; } info->ptr += len; return STATUS_SUCCESS; } int parse_optional_ch(parse_info_t * info, const char ch) { if (!info->ptr) return STATUS_NODATA; if (*(info->ptr) != ch) return STATUS_NODATA; info->ptr++; return STATUS_SUCCESS; } int parse_optional_str(parse_info_t * info, const char *str) { size_t len = strlen(str); if (strncmp(info->ptr, str, len)) return STATUS_NODATA; info->ptr += len; return STATUS_SUCCESS; } int parse_fetch_int(semanage_handle_t * handle, parse_info_t * info, int *num, char delim) { char *str = NULL; char *test = NULL; int value = 0; if (parse_fetch_string(handle, info, &str, delim) < 0) goto err; if (!isdigit((int)*str)) { ERR(handle, "expected a numeric value: (%s: %u)\n%s", info->filename, info->lineno, info->orig_line); goto err; } value = strtol(str, &test, 10); if (*test != '\0') { ERR(handle, "could not parse numeric value \"%s\": " "(%s: %u)\n%s", str, info->filename, info->lineno, info->orig_line); goto err; } *num = value; free(str); return STATUS_SUCCESS; err: ERR(handle, "could not fetch numeric value"); free(str); return STATUS_ERR; } int parse_fetch_string(semanage_handle_t * handle, parse_info_t * info, char **str, char delim) { char *start = info->ptr; int len = 0; char *tmp_str = NULL; if (parse_assert_noeof(handle, info) < 0) goto err; while (*(info->ptr) && !isspace(*(info->ptr)) && (*(info->ptr) != delim)) { info->ptr++; len++; } if (len == 0) { ERR(handle, "expected non-empty string, but did not " "find one (%s: %u):\n%s", info->filename, info->lineno, info->orig_line); goto err; } tmp_str = (char *)malloc(len + 1); if (!tmp_str) { ERR(handle, "out of memory"); goto err; } strncpy(tmp_str, start, len); *(tmp_str + len) = '\0'; *str = tmp_str; return STATUS_SUCCESS; err: ERR(handle, "could not fetch string value"); return STATUS_ERR; }