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
13int 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
37void parse_release(parse_info_t * info)
38{
39
40	parse_close(info);
41	parse_dispose_line(info);
42	free(info);
43}
44
45int 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
60void 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
68void 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
83int 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
141int 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
153int 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
171int 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
190int 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
211int 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
223int 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
234int 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
269int 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