xref: /illumos-gate/usr/src/lib/libsecdb/common/secdb.c (revision b3403853e80914bd0aade9b5b605da4878078173)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <strings.h>
29 #include <secdb.h>
30 #include <ctype.h>
31 
32 /* From libnsl */
33 extern char *_strdup_null(char *);
34 extern char *_strtok_escape(char *, char *, char **);
35 extern char *_strpbrk_escape(char *, char *);
36 extern char *_unescape(char *, char *);
37 
38 char *_do_unescape(char *);
39 
40 
41 /*
42  * kva_match(): Given a key-value array and a key, return a pointer to the
43  * value that matches the key.
44  */
45 char *
46 kva_match(kva_t *kva, char *key)
47 {
48 	int	i;
49 	kv_t	*data;
50 
51 	if (kva == NULL || key == NULL) {
52 		return (NULL);
53 	}
54 	data = kva->data;
55 	for (i = 0; i < kva->length; i++) {
56 		if (strcmp(data[i].key, key) == 0) {
57 			return (data[i].value);
58 		}
59 	}
60 
61 	return (NULL);
62 }
63 
64 /*
65  * _kva_free(): Free up memory.
66  */
67 void
68 _kva_free(kva_t *kva)
69 {
70 	int	i;
71 	kv_t	*data;
72 
73 	if (kva == NULL) {
74 		return;
75 	}
76 	data = kva->data;
77 	for (i = 0; i < kva->length; i++) {
78 		if (data[i].key != NULL) {
79 			free(data[i].key);
80 			data[i].key = NULL;
81 		}
82 		if (data[i].value != NULL) {
83 			free(data[i].value);
84 			data[i].value = NULL;
85 		}
86 	}
87 	free(kva->data);
88 	free(kva);
89 }
90 
91 /*
92  * _kva_free_value(): Free up memory (value) for all the occurrences of
93  * the given key.
94  */
95 void
96 _kva_free_value(kva_t *kva, char *key)
97 {
98 	int	ctr;
99 	kv_t	*data;
100 
101 	if (kva == NULL) {
102 		return;
103 	}
104 
105 	ctr = kva->length;
106 	data = kva->data;
107 
108 	while (ctr--) {
109 		if (strcmp(data->key, key) == 0 && data->value != NULL) {
110 			free(data->value);
111 			data->value = NULL;
112 		}
113 		data++;
114 	}
115 }
116 
117 /*
118  * new_kva(): Allocate a key-value array.
119  */
120 kva_t  *
121 _new_kva(int size)
122 {
123 	kva_t	*new_kva;
124 
125 	if ((new_kva = (kva_t *)calloc(1, sizeof (kva_t))) == NULL) {
126 		return (NULL);
127 	}
128 	if ((new_kva->data = (kv_t *)calloc(1, (size*sizeof (kv_t)))) == NULL) {
129 		free(new_kva);
130 		return (NULL);
131 	}
132 
133 	return (new_kva);
134 }
135 
136 /*
137  * _str2kva(): Given a string (s) of key-value pairs, separated by delimeter
138  * (del), place the values into the key value array (nkva).
139  */
140 kva_t  *
141 _str2kva(char *s, char *ass, char *del)
142 {
143 	int	n = 0;
144 	int	m;
145 	int	size = KV_ADD_KEYS;
146 	char	*buf;
147 	char	*p;
148 	char	*pair;
149 	char	*key;
150 	char	*last_pair;
151 	char	*last_key;
152 	kv_t	*data;
153 	kva_t	*nkva;
154 
155 	if (s == NULL ||
156 	    ass == NULL ||
157 	    del == NULL ||
158 	    *s == '\0' ||
159 	    *s == '\n' ||
160 	    (strlen(s) <= 1)) {
161 		return (NULL);
162 	}
163 	p = s;
164 	while ((p = _strpbrk_escape(p, ass)) != NULL) {
165 		n++;
166 		p++;
167 	}
168 	if (n > size) {
169 		m = n/size;
170 		if (n%size) {
171 			++m;
172 		}
173 		size = m * KV_ADD_KEYS;
174 	}
175 	if ((nkva = _new_kva(size)) == NULL) {
176 		return (NULL);
177 	}
178 	data = nkva->data;
179 	nkva->length = 0;
180 	if ((buf = strdup(s)) == NULL) {
181 		return (NULL);
182 	}
183 	pair = _strtok_escape(buf, del, &last_pair);
184 	do {
185 		key = _strtok_escape(pair, ass, &last_key);
186 		if (key != NULL) {
187 			data[nkva->length].key = _do_unescape(key);
188 			data[nkva->length].value = _do_unescape(last_key);
189 			nkva->length++;
190 		}
191 	} while ((pair = _strtok_escape(NULL, del, &last_pair)) != NULL);
192 	free(buf);
193 	return (nkva);
194 }
195 
196 /*
197  * _kva2str(): Given an array of key-value pairs, place them into a string
198  * (buf). Use delimeter (del) to separate pairs.  Use assignment character
199  * (ass) to separate keys and values.
200  *
201  * Return Values: 0  Success 1  Buffer too small
202  */
203 int
204 _kva2str(kva_t *kva, char *buf, int buflen, char *ass, char *del)
205 {
206 	int	i;
207 	int	len;
208 	int	off = 0;
209 	kv_t	*data;
210 
211 	if (kva == NULL) {
212 		return (0);
213 	}
214 
215 	buf[0] = '\0';
216 	data = kva->data;
217 
218 	for (i = 0; i < kva->length; i++) {
219 		if (data[i].value != NULL) {
220 			len = snprintf(buf + off, buflen - off, "%s%s%s%s",
221 			    data[i].key, ass, data[i].value, del);
222 			if (len < 0 || len + off >= buflen) {
223 				return (1);
224 			}
225 			off += len;
226 		}
227 	}
228 
229 	return (0);
230 }
231 
232 int
233 _insert2kva(kva_t *kva, char *key, char *value)
234 {
235 	int	i;
236 	kv_t	*data;
237 
238 	if (kva == NULL) {
239 		return (0);
240 	}
241 	data = kva->data;
242 	for (i = 0; i < kva->length; i++) {
243 		if (strcmp(data[i].key, key) == 0) {
244 			if (data[i].value != NULL)
245 				free(data[i].value);
246 			data[i].value = _strdup_null(value);
247 			return (0);
248 		}
249 	}
250 	return (1);
251 }
252 
253 kva_t  *
254 _kva_dup(kva_t *old_kva)
255 {
256 	int	i;
257 	int	size;
258 	kv_t	*old_data;
259 	kv_t	*new_data;
260 	kva_t	*nkva = NULL;
261 
262 	if (old_kva == NULL) {
263 		return (NULL);
264 	}
265 	old_data = old_kva->data;
266 	size = old_kva->length;
267 	if ((nkva = _new_kva(size)) == NULL) {
268 		return (NULL);
269 	}
270 	new_data = nkva->data;
271 	nkva->length = old_kva->length;
272 	for (i = 0; i < nkva->length; i++) {
273 		new_data[i].key = _strdup_null(old_data[i].key);
274 		new_data[i].value = _strdup_null(old_data[i].value);
275 	}
276 
277 	return (nkva);
278 }
279 
280 static void
281 strip_spaces(char **valuep)
282 {
283 	char *p, *start;
284 
285 	/* Find first non-white space character and return pointer to it */
286 	for (p = *valuep; *p != '\0' && isspace((unsigned char)*p); p++)
287 		;
288 
289 	*valuep = start = p;
290 
291 	if (*p == '\0')
292 		return;
293 
294 	p = p + strlen(p) - 1;
295 
296 	/* Remove trailing spaces */
297 	while (p > start && isspace((unsigned char)*p))
298 		p--;
299 
300 	p[1] = '\0';
301 }
302 
303 char *
304 _do_unescape(char *src)
305 {
306 	char *tmp = NULL;
307 	char *dst = NULL;
308 
309 	if (src == NULL) {
310 		dst = _strdup_null(src);
311 	} else {
312 		strip_spaces(&src);
313 		tmp = _unescape(src, "=;:,\\");
314 		dst = (tmp == NULL) ? _strdup_null(src) : tmp;
315 	}
316 
317 	return (dst);
318 }
319 
320 
321 /*
322  * Some utilities for handling comma-separated lists.
323  */
324 char *
325 _argv_to_csl(char **strings)
326 {
327 	int len = 0;
328 	int i = 0;
329 	char *newstr = NULL;
330 
331 	if (strings == NULL)
332 		return (NULL);
333 	for (i = 0; strings[i] != NULL; i++) {
334 		len += strlen(strings[i]) + 1;
335 	}
336 	if ((len > 0) && ((newstr = (char *)malloc(len + 1)) != NULL)) {
337 		(void) memset(newstr, 0, len);
338 		for (i = 0; strings[i] != NULL; i++) {
339 			(void) strcat(newstr, strings[i]);
340 			(void) strcat(newstr, ",");
341 		}
342 		newstr[len-1] = '\0';
343 		return (newstr);
344 	} else
345 		return (NULL);
346 }
347 
348 
349 char **
350 _csl_to_argv(char *csl)
351 {
352 	int len = 0;
353 	int ncommas = 0;
354 	int i = 0;
355 	char **spc = NULL;
356 	char *copy = NULL;
357 	char *pc;
358 	char *lasts = NULL;
359 
360 	len = strlen(csl);
361 	for (i = 0; i < len; i++) {
362 		if (csl[i] == ',')
363 			ncommas++;
364 	}
365 	if ((spc = (char **)malloc((ncommas + 2) * sizeof (char *))) == NULL) {
366 		return (NULL);
367 	}
368 	copy = strdup(csl);
369 	for (pc = strtok_r(copy, ",", &lasts), i = 0; pc != NULL;
370 	    pc = strtok_r(NULL, ",", &lasts), i++) {
371 		spc[i] = strdup(pc);
372 	}
373 	spc[i] = NULL;
374 	free(copy);
375 	return (spc);
376 }
377 
378 
379 void
380 _free_argv(char **p_argv)
381 {
382 	char **p_a;
383 
384 	for (p_a = p_argv; *p_a != NULL; p_a++)
385 		free(*p_a);
386 	free(p_argv);
387 }
388 
389 
390 #ifdef DEBUG
391 void
392 print_kva(kva_t *kva)
393 {
394 	int	i;
395 	kv_t	*data;
396 
397 	if (kva == NULL) {
398 		(void) printf("  (empty)\n");
399 		return;
400 	}
401 	data = kva->data;
402 	for (i = 0; i < kva->length; i++) {
403 		(void) printf("  %s = %s\n",
404 		    data[i].key != NULL ? data[i].key : "NULL",
405 		    data[i].value != NULL ? data[i].value : "NULL");
406 	}
407 }
408 #endif  /* DEBUG */
409