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