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 *
kva_match(kva_t * kva,char * key)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
_kva_free(kva_t * kva)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
_kva_free_value(kva_t * kva,char * key)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 *
_new_kva(int size)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 *
_str2kva(char * s,char * ass,char * del)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
_kva2str(kva_t * kva,char * buf,int buflen,char * ass,char * del)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
_insert2kva(kva_t * kva,char * key,char * value)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 *
_kva_dup(kva_t * old_kva)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
strip_spaces(char ** valuep)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 *
_do_unescape(char * src)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 *
_argv_to_csl(char ** strings)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 **
_csl_to_argv(char * csl)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
_free_argv(char ** p_argv)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
print_kva(kva_t * kva)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