1 /* Copyright (C) 2005 Red Hat, Inc. */
2 
3 #include <stdio.h>
4 #include <stdio_ext.h>
5 #include <errno.h>
6 #include <string.h>
7 #include <stdlib.h>
8 #include <ctype.h>
9 #include <semanage/handle.h>
10 #include "parse_utils.h"
11 #include "debug.h"
12 
parse_init(semanage_handle_t * handle,const char * filename,void * parse_arg,parse_info_t ** info)13 int parse_init(semanage_handle_t * handle,
14 	       const char *filename, void *parse_arg, parse_info_t ** info)
15 {
16 
17 	parse_info_t *tmp_info = (parse_info_t *) malloc(sizeof(parse_info_t));
18 
19 	if (!tmp_info) {
20 		ERR(handle,
21 		    "out of memory, could not allocate parse structure");
22 		return STATUS_ERR;
23 	}
24 
25 	tmp_info->filename = filename;
26 	tmp_info->file_stream = NULL;
27 	tmp_info->working_copy = NULL;
28 	tmp_info->orig_line = NULL;
29 	tmp_info->ptr = NULL;
30 	tmp_info->lineno = 0;
31 	tmp_info->parse_arg = parse_arg;
32 
33 	*info = tmp_info;
34 	return STATUS_SUCCESS;
35 }
36 
parse_release(parse_info_t * info)37 void parse_release(parse_info_t * info)
38 {
39 
40 	parse_close(info);
41 	parse_dispose_line(info);
42 	free(info);
43 }
44 
parse_open(semanage_handle_t * handle,parse_info_t * info)45 int parse_open(semanage_handle_t * handle, parse_info_t * info)
46 {
47 
48 	info->file_stream = fopen(info->filename, "r");
49 	if (!info->file_stream && (errno != ENOENT)) {
50 		ERR(handle, "could not open file %s: %s",
51 		    info->filename, strerror(errno));
52 		return STATUS_ERR;
53 	}
54 	if (info->file_stream)
55 		__fsetlocking(info->file_stream, FSETLOCKING_BYCALLER);
56 
57 	return STATUS_SUCCESS;
58 }
59 
parse_close(parse_info_t * info)60 void parse_close(parse_info_t * info)
61 {
62 
63 	if (info->file_stream)
64 		fclose(info->file_stream);
65 	info->file_stream = NULL;
66 }
67 
parse_dispose_line(parse_info_t * info)68 void parse_dispose_line(parse_info_t * info)
69 {
70 	if (info->orig_line) {
71 		free(info->orig_line);
72 		info->orig_line = NULL;
73 	}
74 
75 	if (info->working_copy) {
76 		free(info->working_copy);
77 		info->working_copy = NULL;
78 	}
79 
80 	info->ptr = NULL;
81 }
82 
parse_skip_space(semanage_handle_t * handle,parse_info_t * info)83 int parse_skip_space(semanage_handle_t * handle, parse_info_t * info)
84 {
85 
86 	size_t buf_len = 0;
87 	ssize_t len;
88 	int lineno = info->lineno;
89 	char *buffer = NULL;
90 	char *ptr;
91 
92 	if (info->ptr) {
93 		while (*(info->ptr) && isspace(*(info->ptr)))
94 			info->ptr++;
95 
96 		if (*(info->ptr))
97 			return STATUS_SUCCESS;
98 	}
99 
100 	parse_dispose_line(info);
101 
102 	while (info->file_stream &&
103 	       ((len = getline(&buffer, &buf_len, info->file_stream)) > 0)) {
104 
105 		lineno++;
106 
107 		/* Eat newline, preceding whitespace */
108 		if (buffer[len - 1] == '\n')
109 			buffer[len - 1] = '\0';
110 
111 		ptr = buffer;
112 		while (*ptr && isspace(*ptr))
113 			ptr++;
114 
115 		/* Skip comments and blank lines */
116 		if ((*ptr) && *ptr != '#') {
117 			char *tmp = strdup(buffer);
118 			if (!tmp)
119 				goto omem;
120 
121 			info->lineno = lineno;
122 			info->working_copy = buffer;
123 			info->orig_line = tmp;
124 			info->ptr = ptr;
125 
126 			return STATUS_SUCCESS;
127 		}
128 	}
129 
130 	free(buffer);
131 	buffer = NULL;
132 
133 	return STATUS_SUCCESS;
134 
135       omem:
136 	ERR(handle, "out of memory, could not allocate buffer");
137 	free(buffer);
138 	return STATUS_ERR;
139 }
140 
parse_assert_noeof(semanage_handle_t * handle,parse_info_t * info)141 int parse_assert_noeof(semanage_handle_t * handle, parse_info_t * info)
142 {
143 
144 	if (!info->ptr) {
145 		ERR(handle, "unexpected end of file (%s: %u)",
146 		    info->filename, info->lineno);
147 		return STATUS_ERR;
148 	}
149 
150 	return STATUS_SUCCESS;
151 }
152 
parse_assert_space(semanage_handle_t * handle,parse_info_t * info)153 int parse_assert_space(semanage_handle_t * handle, parse_info_t * info)
154 {
155 
156 	if (parse_assert_noeof(handle, info) < 0)
157 		return STATUS_ERR;
158 
159 	if (*(info->ptr) && !isspace(*(info->ptr))) {
160 		ERR(handle, "missing whitespace (%s: %u):\n%s",
161 		    info->filename, info->lineno, info->orig_line);
162 		return STATUS_ERR;
163 	}
164 
165 	if (parse_skip_space(handle, info) < 0)
166 		return STATUS_ERR;
167 
168 	return STATUS_SUCCESS;
169 }
170 
parse_assert_ch(semanage_handle_t * handle,parse_info_t * info,const char ch)171 int parse_assert_ch(semanage_handle_t * handle,
172 		    parse_info_t * info, const char ch)
173 {
174 
175 	if (parse_assert_noeof(handle, info) < 0)
176 		return STATUS_ERR;
177 
178 	if (*(info->ptr) != ch) {
179 		ERR(handle, "expected character \'%c\', but found \'%c\' "
180 		    "(%s: %u):\n%s", ch, *(info->ptr), info->filename,
181 		    info->lineno, info->orig_line);
182 		return STATUS_ERR;
183 	}
184 
185 	info->ptr++;
186 
187 	return STATUS_SUCCESS;
188 }
189 
parse_assert_str(semanage_handle_t * handle,parse_info_t * info,const char * assert_str)190 int parse_assert_str(semanage_handle_t * handle,
191 		     parse_info_t * info, const char *assert_str)
192 {
193 
194 	size_t len = strlen(assert_str);
195 
196 	if (parse_assert_noeof(handle, info) < 0)
197 		return STATUS_ERR;
198 
199 	if (strncmp(info->ptr, assert_str, len)) {
200 		ERR(handle, "experted string \"%s\", but found \"%s\" "
201 		    "(%s: %u):\n%s", assert_str, info->ptr,
202 		    info->filename, info->lineno, info->orig_line);
203 
204 		return STATUS_ERR;
205 	}
206 
207 	info->ptr += len;
208 	return STATUS_SUCCESS;
209 }
210 
parse_optional_ch(parse_info_t * info,const char ch)211 int parse_optional_ch(parse_info_t * info, const char ch)
212 {
213 
214 	if (!info->ptr)
215 		return STATUS_NODATA;
216 	if (*(info->ptr) != ch)
217 		return STATUS_NODATA;
218 
219 	info->ptr++;
220 	return STATUS_SUCCESS;
221 }
222 
parse_optional_str(parse_info_t * info,const char * str)223 int parse_optional_str(parse_info_t * info, const char *str)
224 {
225 	size_t len = strlen(str);
226 
227 	if (strncmp(info->ptr, str, len))
228 		return STATUS_NODATA;
229 
230 	info->ptr += len;
231 	return STATUS_SUCCESS;
232 }
233 
parse_fetch_int(semanage_handle_t * handle,parse_info_t * info,int * num,char delim)234 int parse_fetch_int(semanage_handle_t * handle,
235 		    parse_info_t * info, int *num, char delim)
236 {
237 
238 	char *str = NULL;
239 	char *test = NULL;
240 	int value = 0;
241 
242 	if (parse_fetch_string(handle, info, &str, delim) < 0)
243 		goto err;
244 
245 	if (!isdigit((int)*str)) {
246 		ERR(handle, "expected a numeric value: (%s: %u)\n%s",
247 		    info->filename, info->lineno, info->orig_line);
248 		goto err;
249 	}
250 
251 	value = strtol(str, &test, 10);
252 	if (*test != '\0') {
253 		ERR(handle, "could not parse numeric value \"%s\": "
254 		    "(%s: %u)\n%s", str, info->filename,
255 		    info->lineno, info->orig_line);
256 		goto err;
257 	}
258 
259 	*num = value;
260 	free(str);
261 	return STATUS_SUCCESS;
262 
263       err:
264 	ERR(handle, "could not fetch numeric value");
265 	free(str);
266 	return STATUS_ERR;
267 }
268 
parse_fetch_string(semanage_handle_t * handle,parse_info_t * info,char ** str,char delim)269 int parse_fetch_string(semanage_handle_t * handle,
270 		       parse_info_t * info, char **str, char delim)
271 {
272 
273 	char *start = info->ptr;
274 	int len = 0;
275 	char *tmp_str = NULL;
276 
277 	if (parse_assert_noeof(handle, info) < 0)
278 		goto err;
279 
280 	while (*(info->ptr) && !isspace(*(info->ptr)) &&
281 	       (*(info->ptr) != delim)) {
282 		info->ptr++;
283 		len++;
284 	}
285 
286 	if (len == 0) {
287 		ERR(handle, "expected non-empty string, but did not "
288 		    "find one (%s: %u):\n%s", info->filename, info->lineno,
289 		    info->orig_line);
290 		goto err;
291 	}
292 
293 	tmp_str = (char *)malloc(len + 1);
294 	if (!tmp_str) {
295 		ERR(handle, "out of memory");
296 		goto err;
297 	}
298 
299 	strncpy(tmp_str, start, len);
300 	*(tmp_str + len) = '\0';
301 	*str = tmp_str;
302 	return STATUS_SUCCESS;
303 
304       err:
305 	ERR(handle, "could not fetch string value");
306 	return STATUS_ERR;
307 }
308