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 occurrences 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 static 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