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 
30 #define TRUE 1
31 #define FALSE 0
32 
semanage_findval(const char * file,const char * var,const char * delim)33 char *semanage_findval(const char *file, const char *var, const char *delim)
34 {
35 	FILE *fd;
36 	char *buff = NULL;
37 	char *retval = NULL;
38 	size_t buff_len = 0;
39 
40 	assert(file);
41 	assert(var);
42 
43 	if ((fd = fopen(file, "r")) == NULL)
44 		return NULL;
45 
46 	while (getline(&buff, &buff_len, fd) > 0) {
47 		if (semanage_is_prefix(buff, var)) {
48 			retval = semanage_split(buff, delim);
49 			if (retval)
50 				semanage_rtrim(retval, '\n');
51 			break;
52 		}
53 	}
54 	free(buff);
55 	fclose(fd);
56 
57 	return retval;
58 }
59 
semanage_is_prefix(const char * str,const char * prefix)60 int semanage_is_prefix(const char *str, const char *prefix)
61 {
62 	if (!str) {
63 		return FALSE;
64 	}
65 	if (!prefix) {
66 		return TRUE;
67 	}
68 
69 	return strncmp(str, prefix, strlen(prefix)) == 0;
70 }
71 
semanage_split_on_space(const char * str)72 char *semanage_split_on_space(const char *str)
73 {
74 	/* as per the man page, these are the isspace() chars */
75 	const char *seps = "\f\n\r\t\v ";
76 	size_t off = 0;
77 
78 	if (!str)
79 		return NULL;
80 
81 	/* skip one token and the spaces before and after it */
82 	off = strspn(str, seps);
83 	off += strcspn(str + off, seps);
84 	off += strspn(str + off, seps);
85 	return strdup(str + off);
86 }
87 
semanage_split(const char * str,const char * delim)88 char *semanage_split(const char *str, const char *delim)
89 {
90 	char *retval;
91 
92 	if (!str)
93 		return NULL;
94 	if (!delim || !(*delim))
95 		return semanage_split_on_space(str);
96 
97 	retval = strstr(str, delim);
98 	if (retval == NULL)
99 		return NULL;
100 
101 	return strdup(retval + strlen(delim));
102 }
103 
semanage_list_push(semanage_list_t ** list,const char * data)104 int semanage_list_push(semanage_list_t ** list, const char *data)
105 {
106 	semanage_list_t *temp = NULL;
107 
108 	if (!data)
109 		return EINVAL;
110 
111 	if (semanage_list_find(*list, data) != NULL)
112 		return 0;
113 
114 	if (!(temp = malloc(sizeof(semanage_list_t))))
115 		return ENOMEM;
116 
117 	if (!(temp->data = strdup(data))) {
118 		free(temp);
119 		return ENOMEM;
120 	}
121 	temp->next = *list;
122 	*list = temp;
123 
124 	return 0;
125 }
126 
semanage_list_pop(semanage_list_t ** list)127 char *semanage_list_pop(semanage_list_t ** list)
128 {
129 	semanage_list_t *node = NULL;
130 	char *data = NULL;
131 
132 	if (!list || !(*list))
133 		return NULL;
134 
135 	node = (*list);
136 	data = node->data;
137 
138 	(*list) = node->next;
139 	free(node);
140 
141 	return data;
142 }
143 
semanage_list_destroy(semanage_list_t ** list)144 void semanage_list_destroy(semanage_list_t ** list)
145 {
146 	semanage_list_t *temp;
147 
148 	while ((temp = (*list))) {
149 		free(temp->data);
150 		(*list) = temp->next;
151 		free(temp);
152 	}
153 }
154 
semanage_list_find(semanage_list_t * l,const char * data)155 semanage_list_t *semanage_list_find(semanage_list_t * l, const char *data)
156 {
157 	if (!data)
158 		return NULL;
159 	while (l && strcmp(l->data, data))
160 		l = l->next;
161 
162 	return l;
163 }
164 
semanage_list_sort(semanage_list_t ** l)165 int semanage_list_sort(semanage_list_t ** l)
166 {
167 	semanage_list_t **array = NULL;
168 	semanage_list_t *temp = NULL;
169 	size_t count = 0;
170 	size_t i = 0;
171 
172 	if (!l)
173 		return 0;
174 
175 	for (temp = *l; temp; temp = temp->next)
176 		++count;
177 
178 	array = malloc(sizeof(semanage_list_t *) * count);
179 	if (!array)
180 		return ENOMEM;	/* couldn't allocate memory for sort */
181 	for (temp = *l; temp; temp = temp->next) {
182 		array[i++] = temp;
183 	}
184 
185 	qsort(array, count, sizeof(semanage_list_t *),
186 	      (int (*)(const void *, const void *))&semanage_cmp_plist_t);
187 	for (i = 0; i < (count - 1); ++i) {
188 		array[i]->next = array[i + 1];
189 	}
190 	array[i]->next = NULL;
191 	(*l) = array[0];
192 	free(array);
193 
194 	return 0;
195 }
196 
semanage_cmp_plist_t(const semanage_list_t ** x,const semanage_list_t ** y)197 int semanage_cmp_plist_t(const semanage_list_t ** x, const semanage_list_t ** y)
198 {
199 	return strcmp((*x)->data, (*y)->data);
200 }
201 
semanage_str_count(const char * data,char what)202 int semanage_str_count(const char *data, char what)
203 {
204 	int count = 0;
205 
206 	if (!data)
207 		return 0;
208 	while (*data) {
209 		if (*data == what)
210 			++count;
211 		++data;
212 	}
213 
214 	return count;
215 }
216 
semanage_rtrim(char * str,char trim_to)217 void semanage_rtrim(char *str, char trim_to)
218 {
219 	int len = 0;
220 
221 	if (!str)
222 		return;
223 	len = strlen(str);
224 
225 	while (len > 0) {
226 		if (str[--len] == trim_to) {
227 			str[len] = '\0';
228 			return;
229 		}
230 	}
231 }
232 
semanage_str_replace(const char * search,const char * replace,const char * src,size_t lim)233 char *semanage_str_replace(const char *search, const char *replace,
234 			   const char *src, size_t lim)
235 {
236 	size_t count = 0, slen, rlen, newsize;
237 	char *p, *pres, *result;
238 	const char *psrc;
239 
240 	slen = strlen(search);
241 	rlen = strlen(replace);
242 
243 	/* Do not support empty search strings */
244 	if (slen == 0)
245 		return NULL;
246 
247 	/* Count the occurences of search in src and compute the new size */
248 	for (p = strstr(src, search); p != NULL; p = strstr(p + slen, search)) {
249 		count++;
250 		if (lim && count >= lim)
251 			break;
252 	}
253 	if (!count)
254 		return strdup(src);
255 
256 	/* Allocate the result string */
257 	newsize = strlen(src) + 1 + count * (rlen - slen);
258 	result = malloc(newsize);
259 	if (!result)
260 		return NULL;
261 
262 	/* Fill the result */
263 	psrc = src;
264 	pres = result;
265 	for (p = strstr(src, search); p != NULL; p = strstr(psrc, search)) {
266 		/* Copy the part which has not been modified */
267 		if (p != psrc) {
268 			size_t length = (size_t)(p - psrc);
269 			memcpy(pres, psrc, length);
270 			pres += length;
271 		}
272 		/* Copy the replacement part */
273 		if (rlen != 0) {
274 			memcpy(pres, replace, rlen);
275 			pres += rlen;
276 		}
277 		psrc = p + slen;
278 		count--;
279 		if (!count)
280 			break;
281 	}
282 	/* Copy the last part, after doing a sanity check */
283 	assert(pres + strlen(psrc) + 1 == result + newsize);
284 	strcpy(pres, psrc);
285 	return result;
286 }
287 
288 /* list_addafter_controlmem does *NOT* duplicate the data argument
289  * use at your own risk, I am building a list out of malloc'd memory and
290  * it is only going to get stored into this list, thus when I destroy it
291  * later I won't free a ptr twice.
292  *
293  * returns the newly created node or NULL on error
294  */
list_addafter_controlmem(semanage_list_t * item,char * data)295 semanage_list_t *list_addafter_controlmem(semanage_list_t * item, char *data)
296 {
297 	semanage_list_t *temp = malloc(sizeof(semanage_list_t));
298 
299 	if (!temp)
300 		return NULL;
301 	temp->data = data;
302 	temp->next = item->next;
303 	item->next = temp;
304 
305 	return temp;
306 }
307 
semanage_slurp_file_filter(FILE * file,int (* pred)(const char *))308 semanage_list_t *semanage_slurp_file_filter(FILE * file,
309 					    int (*pred) (const char *))
310 {
311 	semanage_list_t head;
312 	semanage_list_t *current = &head;
313 	char *line = NULL;
314 	size_t buff_len = 0;
315 
316 	head.next = NULL;	/* initialize head, we aren't going to use the data */
317 	while (getline(&line, &buff_len, file) >= 0) {
318 		if (pred(line)) {
319 			semanage_rtrim(line, '\n');
320 			current = list_addafter_controlmem(current, line);
321 			if (!current)
322 				break;
323 			line = NULL;
324 			buff_len = 0;
325 		}
326 	}
327 	free(line);
328 
329 	return head.next;
330 }
331