xref: /illumos-gate/usr/src/lib/libsecdb/common/secdb.c (revision ceeba6f9)
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 ((char *)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 ((char *)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  * new_kva(): Allocate a key-value array.
93  */
94 kva_t  *
95 _new_kva(int size)
96 {
97 	kva_t	*new_kva;
98 
99 	if ((new_kva = (kva_t *)calloc(1, sizeof (kva_t))) == NULL) {
100 		return ((kva_t *)NULL);
101 	}
102 	if ((new_kva->data = (kv_t *)calloc(1, (size*sizeof (kv_t)))) == NULL) {
103 		free(new_kva);
104 		return ((kva_t *)NULL);
105 	}
106 
107 	return (new_kva);
108 }
109 
110 /*
111  * _str2kva(): Given a string (s) of key-value pairs, separated by delimeter
112  * (del), place the values into the key value array (nkva).
113  */
114 kva_t  *
115 _str2kva(char *s, char *ass, char *del)
116 {
117 	int	n = 0;
118 	int	m;
119 	int	size = KV_ADD_KEYS;
120 	char	*buf;
121 	char	*p;
122 	char	*pair;
123 	char	*key;
124 	char	*last_pair;
125 	char	*last_key;
126 	kv_t	*data;
127 	kva_t	*nkva;
128 
129 	if (s == NULL ||
130 	    ass == NULL ||
131 	    del == NULL ||
132 	    *s == '\0' ||
133 	    *s == '\n' ||
134 	    (strlen(s) <= 1)) {
135 		return ((kva_t *)NULL);
136 	}
137 	p = s;
138 	while ((p = _strpbrk_escape(p, ass)) != NULL) {
139 		n++;
140 		p++;
141 	}
142 	if (n > size) {
143 		m = n/size;
144 		if (n%size) {
145 			++m;
146 		}
147 		size = m * KV_ADD_KEYS;
148 	}
149 	if ((nkva = _new_kva(size)) == NULL) {
150 		return ((kva_t *)NULL);
151 	}
152 	data = nkva->data;
153 	nkva->length = 0;
154 	if ((buf = strdup(s)) == NULL) {
155 		return ((kva_t *)NULL);
156 	}
157 	pair = _strtok_escape(buf, del, &last_pair);
158 	do {
159 		key = _strtok_escape(pair, ass, &last_key);
160 		if (key != NULL) {
161 			data[nkva->length].key = _do_unescape(key);
162 			data[nkva->length].value = _do_unescape(last_key);
163 			nkva->length++;
164 		}
165 	} while ((pair = _strtok_escape(NULL, del, &last_pair)) != NULL);
166 	free(buf);
167 	return (nkva);
168 }
169 
170 /*
171  * _kva2str(): Given an array of key-value pairs, place them into a string
172  * (buf). Use delimeter (del) to separate pairs.  Use assignment character
173  * (ass) to separate keys and values.
174  *
175  * Return Values: 0  Success 1  Buffer too small 2  Out of memory
176  */
177 int
178 _kva2str(kva_t *kva, char *buf, int buflen, char *ass, char *del)
179 {
180 	int	i;
181 	int	length = 0;
182 	char	*tmp;
183 	kv_t	*data;
184 
185 	if (kva == NULL) {
186 		return (0);
187 	}
188 	data = kva->data;
189 	for (i = 0; i < kva->length; i++) {
190 		if (data[i].value != NULL) {
191 			length += 2 + strlen(data[i].value);
192 		}
193 	}
194 	if (length > buflen) {
195 		return (1);
196 	}
197 	(void) memset(buf, 0, buflen);
198 	if ((tmp = (char *)malloc(buflen)) == NULL) {
199 		return (2);
200 	}
201 	for (i = 0; i < kva->length; i++) {
202 		if (data[i].value != NULL) {
203 			if (snprintf(tmp, buflen, "%s%s%s%s",
204 			    data[i].key, ass, data[i].value, del) >= buflen) {
205 				free((void *)tmp);
206 				return (0);
207 			}
208 			(void) strcat(buf, tmp);
209 		}
210 	}
211 	free((void *)tmp);
212 	return (0);
213 }
214 
215 int
216 _insert2kva(kva_t *kva, char *key, char *value)
217 {
218 	int	i;
219 	kv_t	*data;
220 
221 	if (kva == NULL) {
222 		return (0);
223 	}
224 	data = kva->data;
225 	for (i = 0; i < kva->length; i++) {
226 		if (strcmp(data[i].key, key) == 0) {
227 			if (data[i].value != NULL)
228 				free(data[i].value);
229 			data[i].value = _strdup_null(value);
230 			return (0);
231 		}
232 	}
233 	return (1);
234 }
235 
236 kva_t  *
237 _kva_dup(kva_t *old_kva)
238 {
239 	int	i;
240 	int	size;
241 	kv_t	*old_data;
242 	kv_t	*new_data;
243 	kva_t 	*nkva = (kva_t *)NULL;
244 
245 	if (old_kva == NULL) {
246 		return ((kva_t *)NULL);
247 	}
248 	old_data = old_kva->data;
249 	size = old_kva->length;
250 	if ((nkva = _new_kva(size)) == NULL) {
251 		return ((kva_t *)NULL);
252 	}
253 	new_data = nkva->data;
254 	nkva->length = old_kva->length;
255 	for (i = 0; i < nkva->length; i++) {
256 		new_data[i].key = _strdup_null(old_data[i].key);
257 		new_data[i].value = _strdup_null(old_data[i].value);
258 	}
259 
260 	return (nkva);
261 }
262 
263 static void
264 strip_spaces(char **valuep)
265 {
266 	char *p, *start;
267 
268 	/* Find first non-white space character and return pointer to it */
269 	for (p = *valuep; *p != '\0' && isspace((unsigned char)*p); p++)
270 		;
271 
272 	*valuep = start = p;
273 
274 	if (*p == '\0')
275 		return;
276 
277 	p = p + strlen(p) - 1;
278 
279 	/* Remove trailing spaces */
280 	while (p > start && isspace((unsigned char)*p))
281 		p--;
282 
283 	p[1] = '\0';
284 }
285 
286 char *
287 _do_unescape(char *src)
288 {
289 	char *tmp = NULL;
290 	char *dst = NULL;
291 
292 	if (src == NULL) {
293 		dst = _strdup_null(src);
294 	} else {
295 		strip_spaces(&src);
296 		tmp = _unescape(src, "=;:,\\");
297 		dst = (tmp == NULL) ? _strdup_null(src) : tmp;
298 	}
299 
300 	return (dst);
301 }
302 
303 
304 /*
305  * Some utilities for handling comma-separated lists.
306  */
307 char *
308 _argv_to_csl(char **strings)
309 {
310 	int len = 0;
311 	int i = 0;
312 	char *newstr = (char *)NULL;
313 
314 	if (strings == NULL)
315 		return ((char *)NULL);
316 	for (i = 0; strings[i] != NULL; i++) {
317 		len += strlen(strings[i]) + 1;
318 	}
319 	if ((len > 0) && ((newstr = (char *)malloc(len + 1)) != NULL)) {
320 		(void) memset(newstr, 0, len);
321 		for (i = 0; strings[i] != NULL; i++) {
322 			(void) strcat(newstr, strings[i]);
323 			(void) strcat(newstr, ",");
324 		}
325 		newstr[len-1] = NULL;
326 		return (newstr);
327 	} else
328 		return ((char *)NULL);
329 }
330 
331 
332 char **
333 _csl_to_argv(char *csl)
334 {
335 	int len = 0;
336 	int ncommas = 0;
337 	int i = 0;
338 	char **spc = (char **)NULL;
339 	char *copy = (char *)NULL;
340 	char *pc;
341 	char *lasts = (char *)NULL;
342 
343 	len = strlen(csl);
344 	for (i = 0; i < len; i++) {
345 		if (csl[i] == ',')
346 			ncommas++;
347 	}
348 	if ((spc = (char **)malloc((ncommas + 2) * sizeof (char *))) == NULL) {
349 		return ((char **)NULL);
350 	}
351 	copy = strdup(csl);
352 	for (pc = strtok_r(copy, ",", &lasts), i = 0; pc != NULL;
353 	    pc = strtok_r(NULL, ",", &lasts), i++) {
354 		spc[i] = strdup(pc);
355 	}
356 	spc[i] = NULL;
357 	free(copy);
358 	return (spc);
359 }
360 
361 
362 void
363 _free_argv(char **p_argv)
364 {
365 	char **p_a;
366 
367 	for (p_a = p_argv; *p_a != NULL; p_a++)
368 		free(*p_a);
369 	free(p_argv);
370 }
371 
372 
373 #ifdef DEBUG
374 void
375 print_kva(kva_t *kva)
376 {
377 	int	i;
378 	kv_t	*data;
379 
380 	if (kva == NULL) {
381 		printf("  (empty)\n");
382 		return;
383 	}
384 	data = kva->data;
385 	for (i = 0; i < kva->length; i++) {
386 		printf("  %s = %s\n", data[i].key, data[i].value);
387 	}
388 }
389 #endif  /* DEBUG */
390