1 /* Author: Mark Goldman   <mgoldman@tresys.com>
2  *			Paul Rosenfeld	<prosenfeld@tresys.com>
3  *
4  * Copyright (C) 2007 Tresys Technology, LLC
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2.1 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20 #include "utilities.h"
21 
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <ctype.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <assert.h>
29 #include <ustr.h>
30 
31 #define TRUE 1
32 #define FALSE 0
33 
semanage_findval(const char * file,const char * var,const char * delim)34 char *semanage_findval(const char *file, const char *var, const char *delim)
35 {
36 	FILE *fd;
37 	char *buff = NULL;
38 	char *retval = NULL;
39 	size_t buff_len = 0;
40 
41 	assert(file);
42 	assert(var);
43 
44 	if ((fd = fopen(file, "r")) == NULL)
45 		return NULL;
46 
47 	while (getline(&buff, &buff_len, fd) > 0) {
48 		if (semanage_is_prefix(buff, var)) {
49 			retval = semanage_split(buff, delim);
50 			if (retval)
51 				semanage_rtrim(retval, '\n');
52 			break;
53 		}
54 	}
55 	free(buff);
56 	fclose(fd);
57 
58 	return retval;
59 }
60 
semanage_is_prefix(const char * str,const char * prefix)61 int semanage_is_prefix(const char *str, const char *prefix)
62 {
63 	if (!str) {
64 		return FALSE;
65 	}
66 	if (!prefix) {
67 		return TRUE;
68 	}
69 
70 	return strncmp(str, prefix, strlen(prefix)) == 0;
71 }
72 
semanage_split_on_space(const char * str)73 char *semanage_split_on_space(const char *str)
74 {
75 	/* as per the man page, these are the isspace() chars */
76 	const char *seps = "\f\n\r\t\v ";
77 	size_t slen = strlen(seps);
78 	size_t off = 0, rside_len = 0;
79 	char *retval = NULL;
80 	Ustr *ustr = USTR_NULL, *temp = USTR_NULL;
81 
82 	if (!str)
83 		goto done;
84 	if (!(ustr = ustr_dup_cstr(str)))
85 		goto done;
86 	temp =
87 	    ustr_split_spn_chrs(ustr, &off, seps, slen, USTR_NULL,
88 				USTR_FLAG_SPLIT_DEF);
89 	if (!temp)
90 		goto done;
91 	/* throw away the left hand side */
92 	ustr_sc_free(&temp);
93 
94 	rside_len = ustr_len(ustr) - off;
95 	temp = ustr_dup_subustr(ustr, off + 1, rside_len);
96 	if (!temp)
97 		goto done;
98 	retval = strdup(ustr_cstr(temp));
99 	ustr_sc_free(&temp);
100 
101       done:
102 	ustr_sc_free(&ustr);
103 	return retval;
104 }
105 
semanage_split(const char * str,const char * delim)106 char *semanage_split(const char *str, const char *delim)
107 {
108 	Ustr *ustr = USTR_NULL, *temp = USTR_NULL;
109 	size_t off = 0, rside_len = 0;
110 	char *retval = NULL;
111 
112 	if (!str)
113 		goto done;
114 	if (!delim || !(*delim))
115 		return semanage_split_on_space(str);
116 	ustr = ustr_dup_cstr(str);
117 	temp =
118 	    ustr_split_cstr(ustr, &off, delim, USTR_NULL, USTR_FLAG_SPLIT_DEF);
119 	if (!temp)
120 		goto done;
121 	/* throw away the left hand side */
122 	ustr_sc_free(&temp);
123 
124 	rside_len = ustr_len(ustr) - off;
125 
126 	temp = ustr_dup_subustr(ustr, off + 1, rside_len);
127 	if (!temp)
128 		goto done;
129 	retval = strdup(ustr_cstr(temp));
130 	ustr_sc_free(&temp);
131 
132       done:
133 	ustr_sc_free(&ustr);
134 	return retval;
135 }
136 
semanage_list_push(semanage_list_t ** list,const char * data)137 int semanage_list_push(semanage_list_t ** list, const char *data)
138 {
139 	semanage_list_t *temp = NULL;
140 
141 	if (!data)
142 		return EINVAL;
143 
144 	if (semanage_list_find(*list, data) != NULL)
145 		return 0;
146 
147 	if (!(temp = malloc(sizeof(semanage_list_t))))
148 		return ENOMEM;
149 
150 	if (!(temp->data = strdup(data))) {
151 		free(temp);
152 		return ENOMEM;
153 	}
154 	temp->next = *list;
155 	*list = temp;
156 
157 	return 0;
158 }
159 
semanage_list_pop(semanage_list_t ** list)160 char *semanage_list_pop(semanage_list_t ** list)
161 {
162 	semanage_list_t *node = NULL;
163 	char *data = NULL;
164 
165 	if (!list || !(*list))
166 		return NULL;
167 
168 	node = (*list);
169 	data = node->data;
170 
171 	(*list) = node->next;
172 	free(node);
173 
174 	return data;
175 }
176 
semanage_list_destroy(semanage_list_t ** list)177 void semanage_list_destroy(semanage_list_t ** list)
178 {
179 	semanage_list_t *temp;
180 
181 	while ((temp = (*list))) {
182 		free(temp->data);
183 		(*list) = temp->next;
184 		free(temp);
185 	}
186 }
187 
semanage_list_find(semanage_list_t * l,const char * data)188 semanage_list_t *semanage_list_find(semanage_list_t * l, const char *data)
189 {
190 	if (!data)
191 		return NULL;
192 	while (l && strcmp(l->data, data))
193 		l = l->next;
194 
195 	return l;
196 }
197 
semanage_list_sort(semanage_list_t ** l)198 int semanage_list_sort(semanage_list_t ** l)
199 {
200 	semanage_list_t **array = NULL;
201 	semanage_list_t *temp = NULL;
202 	size_t count = 0;
203 	size_t i = 0;
204 
205 	if (!l)
206 		return 0;
207 
208 	for (temp = *l; temp; temp = temp->next)
209 		++count;
210 
211 	array = malloc(sizeof(semanage_list_t *) * count);
212 	if (!array)
213 		return ENOMEM;	/* couldn't allocate memory for sort */
214 	for (temp = *l; temp; temp = temp->next) {
215 		array[i++] = temp;
216 	}
217 
218 	qsort(array, count, sizeof(semanage_list_t *),
219 	      (int (*)(const void *, const void *))&semanage_cmp_plist_t);
220 	for (i = 0; i < (count - 1); ++i) {
221 		array[i]->next = array[i + 1];
222 	}
223 	array[i]->next = NULL;
224 	(*l) = array[0];
225 	free(array);
226 
227 	return 0;
228 }
229 
semanage_cmp_plist_t(const semanage_list_t ** x,const semanage_list_t ** y)230 int semanage_cmp_plist_t(const semanage_list_t ** x, const semanage_list_t ** y)
231 {
232 	return strcmp((*x)->data, (*y)->data);
233 }
234 
semanage_str_count(char * data,char what)235 int semanage_str_count(char *data, char what)
236 {
237 	int count = 0;
238 
239 	if (!data)
240 		return 0;
241 	while (*data) {
242 		if (*data == what)
243 			++count;
244 		++data;
245 	}
246 
247 	return count;
248 }
249 
semanage_rtrim(char * str,char trim_to)250 void semanage_rtrim(char *str, char trim_to)
251 {
252 	int len = 0;
253 
254 	if (!str)
255 		return;
256 	len = strlen(str);
257 
258 	while (len > 0) {
259 		if (str[--len] == trim_to) {
260 			str[len] = '\0';
261 			return;
262 		}
263 	}
264 }
265 
266 /* list_addafter_controlmem does *NOT* duplicate the data argument
267  * use at your own risk, I am building a list out of malloc'd memory and
268  * it is only going to get stored into this list, thus when I destroy it
269  * later I won't free a ptr twice.
270  *
271  * returns the newly created node or NULL on error
272  */
list_addafter_controlmem(semanage_list_t * item,char * data)273 semanage_list_t *list_addafter_controlmem(semanage_list_t * item, char *data)
274 {
275 	semanage_list_t *temp = malloc(sizeof(semanage_list_t));
276 
277 	if (!temp)
278 		return NULL;
279 	temp->data = data;
280 	temp->next = item->next;
281 	item->next = temp;
282 
283 	return temp;
284 }
285 
semanage_slurp_file_filter(FILE * file,int (* pred)(const char *))286 semanage_list_t *semanage_slurp_file_filter(FILE * file,
287 					    int (*pred) (const char *))
288 {
289 	semanage_list_t head;
290 	semanage_list_t *current = &head;
291 	char *line = NULL;
292 	size_t buff_len = 0;
293 
294 	head.next = NULL;	/* initialize head, we aren't going to use the data */
295 	while (getline(&line, &buff_len, file) >= 0) {
296 		if (pred(line)) {
297 			semanage_rtrim(line, '\n');
298 			current = list_addafter_controlmem(current, line);
299 			if (!current)
300 				break;
301 			line = NULL;
302 			buff_len = 0;
303 		}
304 	}
305 	free(line);
306 
307 	return head.next;
308 }
309