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