xref: /illumos-gate/usr/src/lib/libcryptoutil/common/config_parsing.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <stdio.h>
29 #include <errno.h>
30 #include <strings.h>
31 #include <locale.h>
32 #include <stdlib.h>
33 #include "cryptoutil.h"
34 
35 static int uef_interpret(char *, uentry_t **);
36 static int parse_policylist(char *, uentry_t *);
37 
38 /*
39  * Retrieve the user-level provider info from the pkcs11.conf file.
40  * If successful, the result is returned from the ppliblist argument.
41  * This function returns SUCCESS if successfully done; otherwise it returns
42  * FAILURE.
43  */
44 int
45 get_pkcs11conf_info(uentrylist_t **ppliblist)
46 {
47 	FILE *pfile;
48 	char buffer[BUFSIZ];
49 	size_t len;
50 	uentry_t *pent;
51 	uentrylist_t *pentlist;
52 	uentrylist_t *pcur;
53 	int rc = SUCCESS;
54 
55 	*ppliblist = NULL;
56 	if ((pfile = fopen(_PATH_PKCS11_CONF, "rF")) == NULL) {
57 		cryptoerror(LOG_ERR, "failed to open %s.\n", _PATH_PKCS11_CONF);
58 		return (FAILURE);
59 	}
60 
61 	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
62 		if (buffer[0] == '#' || buffer[0] == ' ' ||
63 		    buffer[0] == '\n'|| buffer[0] == '\t') {
64 			continue;   /* ignore comment lines */
65 		}
66 
67 		len = strlen(buffer);
68 		if (buffer[len-1] == '\n') { /* get rid of trailing '\n' */
69 			len--;
70 		}
71 		buffer[len] = '\0';
72 
73 		if ((rc = uef_interpret(buffer,  &pent)) != SUCCESS) {
74 			break;
75 		}
76 
77 		/* append pent into ppliblist */
78 		pentlist = malloc(sizeof (uentrylist_t));
79 		if (pentlist == NULL) {
80 			cryptoerror(LOG_ERR, "parsing %s, out of memory.\n",
81 			    _PATH_PKCS11_CONF);
82 			free_uentry(pent);
83 			rc = FAILURE;
84 			break;
85 		}
86 		pentlist->puent = pent;
87 		pentlist->next = NULL;
88 
89 		if (*ppliblist == NULL) {
90 			*ppliblist = pcur = pentlist;
91 		} else {
92 			pcur->next = pentlist;
93 			pcur = pcur->next;
94 		}
95 	}
96 
97 	(void) fclose(pfile);
98 
99 	if (rc != SUCCESS) {
100 		free_uentrylist(*ppliblist);
101 		*ppliblist = NULL;
102 	}
103 
104 	return (rc);
105 }
106 
107 
108 /*
109  * This routine converts a char string into a uentry_t structure
110  * The input string "buf" should be one of the following:
111  *	library_name
112  *	library_name:NO_RANDOM
113  *	library_name:disabledlist=m1,m2,...,mk
114  *	library_name:disabledlist=m1,m2,...,mk;NO_RANDOM
115  *	library_name:enabledlist=
116  *	library_name:enabledlist=;NO_RANDOM
117  *	library_name:enabledlist=m1,m2,...,mk
118  *	library_name:enabledlist=m1,m2,...,mk;NO_RANDOM
119  *	metaslot:status=enabled;enabledlist=m1,m2,....;slot=<slot-description>;\
120  *	token=<token-label>
121  *
122  * Note:
123  *	The mechanisms m1,..mk are in hex form. For example, "0x00000210"
124  *	for CKM_MD5.
125  *
126  *	For the metaslot entry, "enabledlist", "slot", "auto_key_migrate"
127  * 	or "token" is optional
128  */
129 static int
130 uef_interpret(char *buf, uentry_t **ppent)
131 {
132 	uentry_t *pent;
133 	char	*token1;
134 	char	*token2;
135 	char	*lasts;
136 	int	rc;
137 
138 	*ppent = NULL;
139 	if ((token1 = strtok_r(buf, SEP_COLON, &lasts)) == NULL) {
140 		/* buf is NULL */
141 		return (FAILURE);
142 	};
143 
144 	pent = calloc(sizeof (uentry_t), 1);
145 	if (pent == NULL) {
146 		cryptoerror(LOG_ERR, "parsing %s, out of memory.\n",
147 		    _PATH_PKCS11_CONF);
148 		return (FAILURE);
149 	}
150 	(void) strlcpy(pent->name, token1, sizeof (pent->name));
151 	/*
152 	 * in case metaslot_auto_key_migrate is not specified, it should
153 	 * be default to true
154 	 */
155 	pent->flag_metaslot_auto_key_migrate = B_TRUE;
156 
157 	while ((token2 = strtok_r(NULL, SEP_SEMICOLON, &lasts)) != NULL) {
158 		if ((rc = parse_policylist(token2, pent)) != SUCCESS) {
159 			free_uentry(pent);
160 			return (rc);
161 		}
162 	}
163 
164 	*ppent = pent;
165 	return (SUCCESS);
166 }
167 
168 
169 /*
170  * This routine parses the policy list and stored the result in the argument
171  * pent.
172  *
173  * 	Arg buf: input only, its format should be one of the following:
174  *     		enabledlist=
175  *		enabledlist=m1,m2,...,mk
176  *		disabledlist=m1,m2,...,mk
177  *		NO_RANDOM
178  *		metaslot_status=enabled|disabled
179  *		metaslot_token=<token-label>
180  *		metaslot_slot=<slot-description.
181  *
182  *	Arg pent: input/output
183  *
184  *      return: SUCCESS or FAILURE
185  */
186 static int
187 parse_policylist(char *buf, uentry_t *pent)
188 {
189 	umechlist_t *phead = NULL;
190 	umechlist_t *pcur = NULL;
191 	umechlist_t *pmech;
192 	char *next_token;
193 	char *value;
194 	char *lasts;
195 	int count = 0;
196 	int rc = SUCCESS;
197 
198 	if (pent == NULL) {
199 		return (FAILURE);
200 	}
201 
202 	if (strncmp(buf, EF_DISABLED, sizeof (EF_DISABLED) - 1) == 0) {
203 		pent->flag_enabledlist = B_FALSE;
204 	} else if (strncmp(buf, EF_ENABLED, sizeof (EF_ENABLED) - 1) == 0) {
205 		pent->flag_enabledlist = B_TRUE;
206 	} else if (strncmp(buf, EF_NORANDOM, sizeof (EF_NORANDOM) - 1) == 0) {
207 		pent->flag_norandom = B_TRUE;
208 		return (rc);
209 	} else if (strncmp(buf, METASLOT_TOKEN,
210 	    sizeof (METASLOT_TOKEN) - 1) == 0) {
211 		if (value = strpbrk(buf, SEP_EQUAL)) {
212 			value++; /* get rid of = */
213 			(void) strlcpy((char *)pent->metaslot_ks_token, value,
214 			    sizeof (pent->metaslot_ks_token));
215 			return (SUCCESS);
216 		} else {
217 			cryptoerror(LOG_ERR, "failed to parse %s.\n",
218 			    _PATH_PKCS11_CONF);
219 			return (FAILURE);
220 		}
221 	} else if (strncmp(buf, METASLOT_SLOT,
222 	    sizeof (METASLOT_SLOT) - 1) == 0) {
223 		if (value = strpbrk(buf, SEP_EQUAL)) {
224 			value++; /* get rid of = */
225 			(void) strlcpy((char *)pent->metaslot_ks_slot, value,
226 			    sizeof (pent->metaslot_ks_slot));
227 			return (SUCCESS);
228 		} else {
229 			cryptoerror(LOG_ERR, "failed to parse %s.\n",
230 			    _PATH_PKCS11_CONF);
231 			return (FAILURE);
232 		}
233 	} else if (strncmp(buf, METASLOT_STATUS,
234 	    sizeof (METASLOT_STATUS) - 1) == 0) {
235 		if (value = strpbrk(buf, SEP_EQUAL)) {
236 			value++; /* get rid of = */
237 			if (strcmp(value, METASLOT_DISABLED) == 0) {
238 				pent->flag_metaslot_enabled = B_FALSE;
239 			} else if (strcmp(value, METASLOT_ENABLED) == 0) {
240 				pent->flag_metaslot_enabled = B_TRUE;
241 			} else {
242 				cryptoerror(LOG_ERR, "failed to parse %s.\n",
243 				    _PATH_PKCS11_CONF);
244 				return (FAILURE);
245 			}
246 			return (SUCCESS);
247 		} else {
248 			cryptoerror(LOG_ERR, "failed to parse %s.\n",
249 			    _PATH_PKCS11_CONF);
250 			return (FAILURE);
251 		}
252 	} else if (strncmp(buf, METASLOT_AUTO_KEY_MIGRATE,
253 	    sizeof (METASLOT_AUTO_KEY_MIGRATE) - 1) == 0) {
254 		if (value = strpbrk(buf, SEP_EQUAL)) {
255 			value++; /* get rid of = */
256 			if (strcmp(value, METASLOT_DISABLED) == 0) {
257 				pent->flag_metaslot_auto_key_migrate = B_FALSE;
258 			} else if (strcmp(value, METASLOT_ENABLED) == 0) {
259 				pent->flag_metaslot_auto_key_migrate = B_TRUE;
260 			} else {
261 				cryptoerror(LOG_ERR, "failed to parse %s.\n",
262 				    _PATH_PKCS11_CONF);
263 				return (FAILURE);
264 			}
265 			return (SUCCESS);
266 		} else {
267 			cryptoerror(LOG_ERR, "failed to parse %s.\n",
268 			    _PATH_PKCS11_CONF);
269 			return (FAILURE);
270 		}
271 	} else {
272 		cryptoerror(LOG_ERR, "failed to parse %s.\n",
273 		    _PATH_PKCS11_CONF);
274 		return (FAILURE);
275 	}
276 
277 	if (value = strpbrk(buf, SEP_EQUAL)) {
278 		value++; /* get rid of = */
279 	}
280 
281 	if ((next_token = strtok_r(value, SEP_COMMA, &lasts)) == NULL) {
282 		if (pent->flag_enabledlist) {
283 			return (SUCCESS);
284 		} else {
285 			cryptoerror(LOG_ERR, "failed to parse %s.\n",
286 			    _PATH_PKCS11_CONF);
287 			return (FAILURE);
288 		}
289 	}
290 
291 	while (next_token) {
292 		if ((pmech = create_umech(next_token)) == NULL) {
293 			cryptoerror(LOG_ERR, "parsing %s, out of memory.\n",
294 			    _PATH_PKCS11_CONF);
295 			rc = FAILURE;
296 			break;
297 		}
298 
299 		if (phead == NULL) {
300 			phead = pcur = pmech;
301 		} else {
302 			pcur->next = pmech;
303 			pcur = pcur->next;
304 		}
305 		count++;
306 		next_token = strtok_r(NULL, SEP_COMMA, &lasts);
307 	}
308 
309 	if (rc == SUCCESS) {
310 		pent->policylist = phead;
311 		pent->count = count;
312 	} else {
313 		free_umechlist(phead);
314 	}
315 
316 	return (rc);
317 }
318 
319 
320 /*
321  * Create one item of type umechlist_t with the mechanism name.  A NULL is
322  * returned when the input name is NULL or the heap memory is insufficient.
323  */
324 umechlist_t *
325 create_umech(char *name)
326 {
327 	umechlist_t *pmech = NULL;
328 
329 	if (name == NULL) {
330 		return (NULL);
331 	}
332 
333 	if ((pmech = malloc(sizeof (umechlist_t))) != NULL) {
334 		(void) strlcpy(pmech->name, name, sizeof (pmech->name));
335 		pmech->next = NULL;
336 	}
337 
338 	return (pmech);
339 }
340 
341 
342 void
343 free_umechlist(umechlist_t *plist)
344 {
345 	umechlist_t *pnext;
346 
347 	while (plist != NULL) {
348 		pnext = plist->next;
349 		free(plist);
350 		plist = pnext;
351 	}
352 }
353 
354 
355 void
356 free_uentry(uentry_t  *pent)
357 {
358 	if (pent == NULL) {
359 		return;
360 	} else {
361 		free_umechlist(pent->policylist);
362 		free(pent);
363 	}
364 }
365 
366 
367 void
368 free_uentrylist(uentrylist_t *entrylist)
369 {
370 	uentrylist_t *pnext;
371 
372 	while (entrylist != NULL) {
373 		pnext = entrylist->next;
374 		free_uentry(entrylist->puent);
375 		free(entrylist);
376 		entrylist = pnext;
377 	}
378 }
379 
380 
381 
382 /*
383  * Duplicate an UEF mechanism list.  A NULL pointer is returned if out of
384  * memory or the input argument is NULL.
385  */
386 static umechlist_t *
387 dup_umechlist(umechlist_t *plist)
388 {
389 	umechlist_t *pres = NULL;
390 	umechlist_t *pcur;
391 	umechlist_t *ptmp;
392 	int rc = SUCCESS;
393 
394 	while (plist != NULL) {
395 		if (!(ptmp = create_umech(plist->name))) {
396 			rc = FAILURE;
397 			break;
398 		}
399 
400 		if (pres == NULL) {
401 			pres = pcur = ptmp;
402 		} else {
403 			pcur->next = ptmp;
404 			pcur = pcur->next;
405 		}
406 		plist = plist->next;
407 	}
408 
409 	if (rc != SUCCESS) {
410 		free_umechlist(pres);
411 		return (NULL);
412 	}
413 
414 	return (pres);
415 }
416 
417 
418 /*
419  * Duplicate an uentry.  A NULL pointer is returned if out of memory
420  * or the input argument is NULL.
421  */
422 static uentry_t *
423 dup_uentry(uentry_t *puent1)
424 {
425 	uentry_t *puent2 = NULL;
426 
427 	if (puent1 == NULL) {
428 		return (NULL);
429 	}
430 
431 	if ((puent2 = malloc(sizeof (uentry_t))) == NULL) {
432 		cryptoerror(LOG_STDERR, gettext("out of memory."));
433 		return (NULL);
434 	} else {
435 		(void) strlcpy(puent2->name, puent1->name,
436 		    sizeof (puent2->name));
437 		puent2->flag_norandom = puent1->flag_norandom;
438 		puent2->flag_enabledlist = puent1->flag_enabledlist;
439 		puent2->policylist = dup_umechlist(puent1->policylist);
440 		puent2->flag_metaslot_enabled = puent1->flag_metaslot_enabled;
441 		puent2->flag_metaslot_auto_key_migrate
442 		    = puent1->flag_metaslot_auto_key_migrate;
443 		(void) memcpy(puent2->metaslot_ks_slot,
444 		    puent1->metaslot_ks_slot, SLOT_DESCRIPTION_SIZE);
445 		(void) memcpy(puent2->metaslot_ks_token,
446 		    puent1->metaslot_ks_token, TOKEN_LABEL_SIZE);
447 		puent2->count = puent1->count;
448 		return (puent2);
449 	}
450 }
451 
452 /*
453  * Find the entry in the "pkcs11.conf" file with "libname" as the provider
454  * name. Return the entry if found, otherwise return NULL.
455  */
456 uentry_t *
457 getent_uef(char *libname)
458 {
459 	uentrylist_t	*pliblist = NULL;
460 	uentrylist_t	*plib = NULL;
461 	uentry_t	*puent = NULL;
462 	boolean_t	found = B_FALSE;
463 
464 	if (libname == NULL) {
465 		return (NULL);
466 	}
467 
468 	if ((get_pkcs11conf_info(&pliblist)) == FAILURE) {
469 		return (NULL);
470 	}
471 
472 	plib = pliblist;
473 	while (plib) {
474 		if (strcmp(plib->puent->name, libname) == 0) {
475 			found = B_TRUE;
476 			break;
477 		} else {
478 			plib = plib->next;
479 		}
480 	}
481 
482 	if (found) {
483 		puent = dup_uentry(plib->puent);
484 	}
485 
486 	free_uentrylist(pliblist);
487 	return (puent);
488 }
489 
490 
491 
492 /*
493  * Retrieve the metaslot information from the pkcs11.conf file.
494  * This function returns SUCCESS if successfully done; otherwise it returns
495  * FAILURE.   If successful, the caller is responsible to free the space
496  * allocated for objectstore_slot_info and objectstore_token_info.
497  */
498 int
499 get_metaslot_info(boolean_t  *status_enabled, boolean_t *migrate_enabled,
500     char **objectstore_slot_info, char **objectstore_token_info)
501 {
502 
503 	int rc = SUCCESS;
504 	uentry_t *puent;
505 	char *buf1 = NULL;
506 	char *buf2 = NULL;
507 
508 	if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) {
509 		/* metaslot entry doesn't exist */
510 		return (FAILURE);
511 	}
512 
513 	*status_enabled = puent->flag_metaslot_enabled;
514 	*migrate_enabled = puent->flag_metaslot_auto_key_migrate;
515 
516 	buf1 = malloc(SLOT_DESCRIPTION_SIZE);
517 	if (buf1 == NULL) {
518 		cryptoerror(LOG_ERR, "get_metaslot_info() - out of memory.\n");
519 		rc = FAILURE;
520 		goto out;
521 	}
522 	(void) strcpy(buf1, (const char *) puent->metaslot_ks_slot);
523 	*objectstore_slot_info = buf1;
524 
525 	buf2 = malloc(TOKEN_LABEL_SIZE);
526 	if (objectstore_slot_info == NULL) {
527 		cryptoerror(LOG_ERR, "get_metaslot_info() - out of memory.\n");
528 		rc = FAILURE;
529 		goto out;
530 	}
531 	(void) strcpy(buf2, (const char *) puent->metaslot_ks_token);
532 	*objectstore_token_info = buf2;
533 
534 out:
535 	if (puent != NULL) {
536 		free_uentry(puent);
537 	}
538 
539 	if (rc == FAILURE) {
540 		if (buf1 != NULL) {
541 			free(buf1);
542 		}
543 		if (buf2 != NULL) {
544 			free(buf2);
545 		}
546 	}
547 
548 	return (rc);
549 }
550