config_parsing.c revision 3089:8ddeb2ace8aa
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
35static int uef_interpret(char *, uentry_t **);
36static 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 */
44int
45get_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 */
129static int
130uef_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 */
186static int
187parse_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 */
324umechlist_t *
325create_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
342void
343free_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
355void
356free_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
367void
368free_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 */
386static umechlist_t *
387dup_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 */
422static uentry_t *
423dup_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 */
456uentry_t *
457getent_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 */
498int
499get_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
534out:
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