adm_uef.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 <cryptoutil.h>
29#include <fcntl.h>
30#include <libintl.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <strings.h>
34#include <unistd.h>
35#include <errno.h>
36#include <dlfcn.h>
37#include <link.h>
38#include <sys/types.h>
39#include <sys/stat.h>
40#include <security/cryptoki.h>
41#include "cryptoadm.h"
42
43#define	HDR1 "                                     P\n"
44#define	HDR2 "                         S     V  K  a     U  D\n"
45#define	HDR3 "                         i     e  e  i     n  e\n"
46#define	HDR4 "                      S  g  V  r  y  r  W  w  r\n"
47#define	HDR5 "             E  D  D  i  n  e  i  G  G  r  r  i\n"
48#define	HDR6 "          H  n  e  i  g  +  r  +  e  e  a  a  v  E\n"
49#define	HDR7 "min  max  W  c  c  g  n  R  i  R  n  n  p  p  e  C\n"
50
51
52static int err; /* To store errno which may be overwritten by gettext() */
53static boolean_t is_in_policylist(midstr_t, umechlist_t *);
54static char *uent2str(uentry_t *);
55static boolean_t check_random(CK_SLOT_ID, CK_FUNCTION_LIST_PTR);
56
57static void display_slot_flags(CK_FLAGS flags)
58{
59	(void) printf(gettext("Slot Flags: "));
60	if (flags & CKF_TOKEN_PRESENT)
61		(void) printf("CKF_TOKEN_PRESENT ");
62	if (flags & CKF_REMOVABLE_DEVICE)
63		(void) printf("CKF_REMOVABLE_DEVICE ");
64	if (flags & CKF_HW_SLOT)
65		(void) printf("CKF_HW_SLOT ");
66	(void) printf("\n");
67}
68
69void
70display_token_flags(CK_FLAGS flags)
71{
72	(void) printf(gettext("Flags: "));
73	if (flags & CKF_RNG)
74		(void) printf("CKF_RNG ");
75	if (flags & CKF_WRITE_PROTECTED)
76		(void) printf("CKF_WRITE_PROTECTED ");
77	if (flags & CKF_LOGIN_REQUIRED)
78		(void) printf("CKF_LOGIN_REQUIRED ");
79	if (flags & CKF_USER_PIN_INITIALIZED)
80		(void) printf("CKF_USER_PIN_INITIALIZED ");
81	if (flags & CKF_RESTORE_KEY_NOT_NEEDED)
82		(void) printf("CKF_RESTORE_KEY_NOT_NEEDED ");
83	if (flags & CKF_CLOCK_ON_TOKEN)
84		(void) printf("CKF_CLOCK_ON_TOKEN ");
85	if (flags & CKF_PROTECTED_AUTHENTICATION_PATH)
86		(void) printf("CKF_PROTECTED_AUTHENTICATION_PATH ");
87	if (flags & CKF_DUAL_CRYPTO_OPERATIONS)
88		(void) printf("CKF_DUAL_CRYPTO_OPERATIONS ");
89	if (flags & CKF_TOKEN_INITIALIZED)
90		(void) printf("CKF_TOKEN_INITIALIZED ");
91	if (flags & CKF_SECONDARY_AUTHENTICATION)
92		(void) printf("CKF_SECONDARY_AUTHENTICATION ");
93	if (flags & CKF_USER_PIN_COUNT_LOW)
94		(void) printf("CKF_USER_PIN_COUNT_LOW ");
95	if (flags & CKF_USER_PIN_FINAL_TRY)
96		(void) printf("CKF_USER_PIN_FINAL_TRY ");
97	if (flags & CKF_USER_PIN_LOCKED)
98		(void) printf("CKF_USER_PIN_LOCKED ");
99	if (flags & CKF_USER_PIN_TO_BE_CHANGED)
100		(void) printf("CKF_USER_PIN_TO_BE_CHANGED ");
101	if (flags & CKF_SO_PIN_COUNT_LOW)
102		(void) printf("CKF_SO_PIN_COUNT_LOW ");
103	if (flags & CKF_SO_PIN_FINAL_TRY)
104		(void) printf("CKF_SO_PIN_FINAL_TRY ");
105	if (flags & CKF_SO_PIN_LOCKED)
106		(void) printf("CKF_SO_PIN_LOCKED ");
107	if (flags & CKF_SO_PIN_TO_BE_CHANGED)
108		(void) printf("CKF_SO_PIN_TO_BE_CHANGED ");
109	if (flags & CKF_SO_PIN_TO_BE_CHANGED)
110		(void) printf("CKF_SO_PIN_TO_BE_CHANGED ");
111	(void) printf("\n");
112}
113
114void
115display_mech_info(CK_MECHANISM_INFO *mechInfo)
116{
117	CK_FLAGS ec_flags = CKF_EC_F_P | CKF_EC_F_2M | CKF_EC_ECPARAMETERS |
118		CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS;
119
120	(void) printf("%-4ld %-4ld ", mechInfo->ulMinKeySize,
121		mechInfo->ulMaxKeySize);
122	(void) printf("%s  %s  %s  %s  %s  %s  %s  %s  %s  %s  %s  %s  "
123		"%s  %s",
124		(mechInfo->flags & CKF_HW) ? "X" : ".",
125		(mechInfo->flags & CKF_ENCRYPT) ? "X" : ".",
126		(mechInfo->flags & CKF_DECRYPT) ? "X" : ".",
127		(mechInfo->flags & CKF_DIGEST) ? "X" : ".",
128		(mechInfo->flags & CKF_SIGN) ? "X" : ".",
129		(mechInfo->flags & CKF_SIGN_RECOVER) ? "X" : ".",
130		(mechInfo->flags & CKF_VERIFY) ? "X" : ".",
131		(mechInfo->flags & CKF_VERIFY_RECOVER) ? "X" : ".",
132		(mechInfo->flags & CKF_GENERATE) ? "X" : ".",
133		(mechInfo->flags & CKF_GENERATE_KEY_PAIR) ? "X" : ".",
134		(mechInfo->flags & CKF_WRAP) ? "X" : ".",
135		(mechInfo->flags & CKF_UNWRAP) ? "X" : ".",
136		(mechInfo->flags & CKF_DERIVE) ? "X" : ".",
137		(mechInfo->flags & ec_flags) ? "X" : ".");
138}
139
140/*
141 * Converts the provided list of mechanism names in their string format to
142 * their corrsponding PKCS#11 mechanism IDs.
143 *
144 * The list of mechanism names to be converted is provided in the
145 * "mlist" argument.  The list of converted mechanism IDs is returned
146 * in the "pmech_list" argument.
147 *
148 * This function is called by list_metaslot_info() and
149 * list_mechlist_for_lib() functions.
150 */
151int
152convert_mechlist(CK_MECHANISM_TYPE **pmech_list, CK_ULONG *mech_count,
153    mechlist_t *mlist)
154{
155	int i, n = 0;
156	mechlist_t *p = mlist;
157
158	while (p != NULL) {
159		p = p->next;
160		n++;
161	}
162
163	*pmech_list = malloc(n * sizeof (CK_MECHANISM_TYPE));
164	if (pmech_list == NULL) {
165		cryptodebug("out of memory");
166		return (FAILURE);
167	}
168	p = mlist;
169	for (i = 0; i < n; i++) {
170		if (pkcs11_str2mech(p->name, &(*pmech_list[i])) != CKR_OK) {
171			free(*pmech_list);
172			return (FAILURE);
173		}
174		p = p->next;
175	}
176	*mech_count = n;
177	return (SUCCESS);
178}
179
180/*
181 * Display the mechanism list for a user-level library
182 */
183int
184list_mechlist_for_lib(char *libname, mechlist_t *mlist,
185		flag_val_t *rng_flag, boolean_t no_warn,
186		boolean_t verbose, boolean_t show_mechs)
187{
188	CK_RV	rv = CKR_OK;
189	CK_RV	(*Tmp_C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR);
190	CK_FUNCTION_LIST_PTR	prov_funcs; /* Provider's function list */
191	CK_SLOT_ID_PTR		prov_slots = NULL; /* Provider's slot list */
192	CK_MECHANISM_TYPE_PTR	pmech_list; /* mechanism list for a slot */
193	CK_SLOT_INFO	slotinfo;
194	CK_ULONG	slot_count;
195	CK_ULONG	mech_count;
196	uentry_t	*puent = NULL;
197	boolean_t lib_initialized = B_FALSE;
198	void	*dldesc = NULL;
199	char	*dl_error;
200	char 	*mech_name;
201	char	*isa;
202	char	libpath[MAXPATHLEN];
203	char	buf[MAXPATHLEN];
204	int	i, j;
205	int	rc = SUCCESS;
206
207	if (libname == NULL) {
208		/* should not happen */
209		cryptoerror(LOG_STDERR, gettext("internal error."));
210		cryptodebug("list_mechlist_for_lib() - libname is NULL.");
211		return (FAILURE);
212	}
213
214	/* Check if the library is in the pkcs11.conf file */
215	if ((puent = getent_uef(libname)) == NULL) {
216		cryptoerror(LOG_STDERR,
217		    gettext("%s does not exist."), libname);
218		return (FAILURE);
219	}
220	free_uentry(puent);
221
222	/* Remove $ISA from the library name */
223	if (strlcpy(buf, libname, sizeof (buf)) >= sizeof (buf)) {
224		(void) printf(gettext("%s: the provider name is too long."),
225		    libname);
226		return (FAILURE);
227	}
228
229	if ((isa = strstr(buf, PKCS11_ISA)) != NULL) {
230		*isa = '\000';
231		isa += strlen(PKCS11_ISA);
232		(void) snprintf(libpath, MAXPATHLEN, "%s%s%s", buf, "/", isa);
233	} else {
234		(void) strlcpy(libpath, libname, sizeof (libpath));
235	}
236
237	/* Open the provider */
238	dldesc = dlopen(libpath, RTLD_NOW);
239	if (dldesc == NULL) {
240		dl_error = dlerror();
241		cryptodebug("Cannot load PKCS#11 library %s.  dlerror: %s",
242		    libname, dl_error != NULL ? dl_error : "Unknown");
243		rc = FAILURE;
244		goto clean_exit;
245	}
246
247	/* Get the pointer to provider's C_GetFunctionList() */
248	Tmp_C_GetFunctionList = (CK_RV(*)())dlsym(dldesc, "C_GetFunctionList");
249	if (Tmp_C_GetFunctionList == NULL) {
250		cryptodebug("Cannot get the address of the C_GetFunctionList "
251		    "from %s", libname);
252		rc = FAILURE;
253		goto clean_exit;
254	}
255
256	/* Get the provider's function list */
257	rv = Tmp_C_GetFunctionList(&prov_funcs);
258	if (rv != CKR_OK) {
259		cryptodebug("failed to call C_GetFunctionList from %s",
260		    libname);
261		rc = FAILURE;
262		goto clean_exit;
263	}
264
265	/* Initialize this provider */
266	rv = prov_funcs->C_Initialize(NULL_PTR);
267	if (rv != CKR_OK) {
268		cryptodebug("failed to call C_Initialize from %s, "
269		    "return code = %d", libname, rv);
270		rc = FAILURE;
271		goto clean_exit;
272	} else {
273		lib_initialized = B_TRUE;
274	}
275
276	/*
277	 * Find out how many slots this provider has, call with tokenPresent
278	 * set to FALSE so all potential slots are returned.
279	 */
280	rv = prov_funcs->C_GetSlotList(FALSE, NULL_PTR, &slot_count);
281	if (rv != CKR_OK) {
282		cryptodebug("failed to get the slotlist from %s.", libname);
283		rc = FAILURE;
284		goto clean_exit;
285	} else if (slot_count == 0) {
286		if (!no_warn)
287			(void) printf(gettext("%s: no slots presented.\n"),
288				libname);
289		rc = SUCCESS;
290		goto clean_exit;
291	}
292
293	/* Allocate memory for the slot list */
294	prov_slots = malloc(slot_count * sizeof (CK_SLOT_ID));
295	if (prov_slots == NULL) {
296		cryptodebug("out of memory.");
297		rc = FAILURE;
298		goto clean_exit;
299	}
300
301	/* Get the slot list from provider */
302	rv = prov_funcs->C_GetSlotList(FALSE, prov_slots, &slot_count);
303	if (rv != CKR_OK) {
304		cryptodebug("failed to call C_GetSlotList() from %s.",
305		    libname);
306		rc = FAILURE;
307		goto clean_exit;
308	}
309
310	if (verbose) {
311		(void) printf(gettext("Number of slots: %d\n"), slot_count);
312	}
313
314	/* Get the mechanism list for each slot */
315	for (i = 0; i < slot_count; i++) {
316		if (verbose)
317			/*
318			 * TRANSLATION_NOTE:
319			 * In some languages, the # symbol should be
320			 * converted to "no", an "n" followed by a
321			 * superscript "o"..
322			 */
323			(void) printf(gettext("\nSlot #%d\n"), i+1);
324
325		if ((rng_flag != NULL) && (*rng_flag == NO_RNG)) {
326			if (check_random(prov_slots[i], prov_funcs)) {
327				*rng_flag = HAS_RNG;
328				rc = SUCCESS;
329				goto clean_exit;
330			} else
331				continue;
332		}
333
334		rv = prov_funcs->C_GetSlotInfo(prov_slots[i], &slotinfo);
335		if (rv != CKR_OK) {
336			cryptodebug("failed to get slotinfo from %s", libname);
337			rc = FAILURE;
338			break;
339		}
340		if (verbose) {
341			CK_TOKEN_INFO tokeninfo;
342
343			(void) printf(gettext("Description: %.64s\n"
344				"Manufacturer: %.32s\n"
345				"PKCS#11 Version: %d.%d\n"),
346				slotinfo.slotDescription,
347				slotinfo.manufacturerID,
348				prov_funcs->version.major,
349				prov_funcs->version.minor);
350
351			(void) printf(gettext("Hardware Version: %d.%d\n"
352				"Firmware Version: %d.%d\n"),
353				slotinfo.hardwareVersion.major,
354				slotinfo.hardwareVersion.minor,
355				slotinfo.firmwareVersion.major,
356				slotinfo.firmwareVersion.minor);
357
358			(void) printf(gettext("Token Present: %s\n"),
359				(slotinfo.flags & CKF_TOKEN_PRESENT ?
360				gettext("True") : gettext("False")));
361
362			display_slot_flags(slotinfo.flags);
363
364			rv = prov_funcs->C_GetTokenInfo(prov_slots[i],
365				&tokeninfo);
366			if (rv != CKR_OK) {
367				cryptodebug("Failed to get "
368					"token info from %s", libname);
369				rc = FAILURE;
370				break;
371			}
372
373			(void) printf(gettext("Token Label: %.32s\n"
374				"Manufacturer ID: %.32s\n"
375				"Model: %.16s\n"
376				"Serial Number: %.16s\n"
377				"Hardware Version: %d.%d\n"
378				"Firmware Version: %d.%d\n"
379				"UTC Time: %.16s\n"
380				"PIN Length: %d-%d\n"),
381				tokeninfo.label,
382				tokeninfo.manufacturerID,
383				tokeninfo.model,
384				tokeninfo.serialNumber,
385				tokeninfo.hardwareVersion.major,
386				tokeninfo.hardwareVersion.minor,
387				tokeninfo.firmwareVersion.major,
388				tokeninfo.firmwareVersion.minor,
389				tokeninfo.utcTime,
390				tokeninfo.ulMinPinLen,
391				tokeninfo.ulMaxPinLen);
392
393			display_token_flags(tokeninfo.flags);
394		}
395
396		if (mlist == NULL) {
397			rv = prov_funcs->C_GetMechanismList(prov_slots[i],
398				NULL_PTR, &mech_count);
399			if (rv != CKR_OK) {
400				cryptodebug(
401					"failed to call C_GetMechanismList() "
402					"from %s.", libname);
403				rc = FAILURE;
404				break;
405			}
406
407			if (mech_count == 0) {
408				/* no mechanisms in this slot */
409				continue;
410			}
411
412			pmech_list = malloc(mech_count *
413					sizeof (CK_MECHANISM_TYPE));
414			if (pmech_list == NULL) {
415				cryptodebug("out of memory");
416				rc = FAILURE;
417				break;
418			}
419
420			/* Get the actual mechanism list */
421			rv = prov_funcs->C_GetMechanismList(prov_slots[i],
422				pmech_list, &mech_count);
423			if (rv != CKR_OK) {
424				cryptodebug(
425					"failed to call C_GetMechanismList() "
426					"from %s.", libname);
427				(void) free(pmech_list);
428				rc = FAILURE;
429				break;
430			}
431		} else  {
432			/* use the mechanism list passed in */
433			rc = convert_mechlist(&pmech_list, &mech_count, mlist);
434			if (rc != SUCCESS) {
435				goto clean_exit;
436			}
437		}
438		if (show_mechs)
439			(void) printf(gettext("Mechanisms:\n"));
440
441		if (verbose && show_mechs) {
442			display_verbose_mech_header();
443		}
444		/*
445		 * Merge the current mechanism list into the returning
446		 * mechanism list.
447		 */
448		for (j = 0; show_mechs && j < mech_count; j++) {
449			mech_name = pkcs11_mech2str(pmech_list[j]);
450			(void) printf("%-29s", mech_name);
451			if (verbose) {
452				CK_MECHANISM_INFO mech_info;
453				rv = prov_funcs->C_GetMechanismInfo(
454				    prov_slots[i], pmech_list[j], &mech_info);
455				if (rv != CKR_OK) {
456					cryptodebug(
457					    "failed to call "
458					    "C_GetMechanismInfo() from %s.",
459					    libname);
460					(void) free(pmech_list);
461					rc = FAILURE;
462					break;
463				}
464				display_mech_info(&mech_info);
465			}
466			(void) printf("\n");
467		}
468		(void) free(pmech_list);
469		if (rc == FAILURE) {
470			break;
471		}
472	}
473
474	if (rng_flag != NULL || rc == FAILURE) {
475		goto clean_exit;
476	}
477
478clean_exit:
479
480	if (rc == FAILURE) {
481		(void) printf(gettext(
482		    "%s: failed to retrieve the mechanism list.\n"), libname);
483	}
484
485	if (lib_initialized) {
486		(void) prov_funcs->C_Finalize(NULL_PTR);
487	}
488
489	if (dldesc != NULL) {
490		(void) dlclose(dldesc);
491	}
492
493	if (prov_slots != NULL) {
494		(void) free(prov_slots);
495	}
496
497	return (rc);
498}
499
500
501/*
502 * Display the mechanism policy for a user-level library
503 */
504int
505list_policy_for_lib(char *libname)
506{
507	uentry_t *puent = NULL;
508	int rc;
509
510	if (libname == NULL) {
511		/* should not happen */
512		cryptoerror(LOG_STDERR, gettext("internal error."));
513		cryptodebug("list_policy_for_lib() - libname is NULL.");
514		return (FAILURE);
515	}
516
517	/* Get the library entry from the pkcs11.conf file */
518	if ((puent = getent_uef(libname)) == NULL) {
519		cryptoerror(LOG_STDERR,
520		    gettext("%s does not exist."), libname);
521		return (FAILURE);
522	}
523
524	/* Print the policy for this library */
525	rc = print_uef_policy(puent);
526	free_uentry(puent);
527
528	return (rc);
529}
530
531
532/*
533 * Disable mechanisms for a user-level library
534 */
535int
536disable_uef_lib(char *libname, boolean_t rndflag, boolean_t allflag,
537    mechlist_t *marglist)
538{
539	uentry_t	*puent;
540	int	rc;
541
542	if (libname == NULL) {
543		/* should not happen */
544		cryptoerror(LOG_STDERR, gettext("internal error."));
545		cryptodebug("disable_uef_lib() - libname is NULL.");
546		return (FAILURE);
547	}
548
549	/* Get the provider entry from the pkcs11.conf file */
550	if ((puent = getent_uef(libname)) == NULL) {
551		cryptoerror(LOG_STDERR,
552		    gettext("%s does not exist."), libname);
553		return (FAILURE);
554	}
555
556	/*
557	 * Update the mechanism policy of this library entry, based on
558	 * the current policy mode of the library and the mechanisms specified
559	 * in CLI.
560	 */
561	if (allflag) {
562		/*
563		 * If disabling all, just need to clean up the policylist and
564		 * set the flag_enabledlist flag to be B_TRUE.
565		 */
566		free_umechlist(puent->policylist);
567		puent->policylist = NULL;
568		puent->count = 0;
569		puent->flag_enabledlist = B_TRUE;
570		rc = SUCCESS;
571	} else if (marglist != NULL) {
572		if (puent->flag_enabledlist == B_TRUE) {
573			/*
574			 * The current default policy mode of this library
575			 * is "all are disabled, except ...", so if a
576			 * specified mechanism is in the exception list
577			 * (the policylist), delete it from the policylist.
578			 */
579			rc = update_policylist(puent, marglist, DELETE_MODE);
580		} else {
581			/*
582			 * The current default policy mode of this library
583			 * is "all are enabled", so if a specified mechanism
584			 * is not in the exception list (policylist), add
585			 * it into the policylist.
586			 */
587			rc = update_policylist(puent, marglist, ADD_MODE);
588		}
589	} else if (!rndflag) {
590		/* should not happen */
591		cryptoerror(LOG_STDERR, gettext("internal error."));
592		cryptodebug("disable_uef_lib() - wrong arguments.");
593		return (FAILURE);
594	}
595
596	if (rndflag)
597		puent->flag_norandom = B_TRUE;
598
599	if (rc == FAILURE) {
600		free_uentry(puent);
601		return (FAILURE);
602	}
603
604	/* Update the pkcs11.conf file with the updated entry */
605	rc = update_pkcs11conf(puent);
606	free_uentry(puent);
607	return (rc);
608}
609
610
611/*
612 * Enable disabled mechanisms for a user-level library.
613 */
614int
615enable_uef_lib(char *libname, boolean_t rndflag, boolean_t allflag,
616    mechlist_t *marglist)
617{
618	uentry_t	*puent;
619	int	rc = SUCCESS;
620
621	if (libname == NULL) {
622		/* should not happen */
623		cryptoerror(LOG_STDERR, gettext("internal error."));
624		cryptodebug("enable_uef_lib() - libname is NULL.");
625		return (FAILURE);
626	}
627
628	/* Get the provider entry from the pkcs11.conf file */
629	if ((puent = getent_uef(libname)) == NULL) {
630		cryptoerror(LOG_STDERR,
631		    gettext("%s does not exist."), libname);
632		return (FAILURE);
633	}
634
635	/*
636	 * Update the mechanism policy of this library entry, based on
637	 * the current policy mode of the library and the mechanisms
638	 * specified in CLI.
639	 */
640	if (allflag) {
641		/*
642		 * If enabling all, what needs to be done are cleaning up the
643		 * policylist and setting the "flag_enabledlist" flag to
644		 * B_FALSE.
645		 */
646		free_umechlist(puent->policylist);
647		puent->policylist = NULL;
648		puent->count = 0;
649		puent->flag_enabledlist = B_FALSE;
650		rc = SUCCESS;
651	} else if (marglist != NULL) {
652		if (puent->flag_enabledlist == B_TRUE) {
653			/*
654			 * The current default policy mode of this library
655			 * is "all are disabled, except ...", so if a
656			 * specified mechanism is not in the exception list
657			 * (policylist), add it.
658			 */
659			rc = update_policylist(puent, marglist, ADD_MODE);
660		} else {
661			/*
662			 * The current default policy mode of this library
663			 * is "all are enabled, except", so if a specified
664			 * mechanism is in the exception list (policylist),
665			 * delete it.
666			 */
667			rc = update_policylist(puent, marglist, DELETE_MODE);
668		}
669	} else if (!rndflag) {
670		/* should not come here */
671		cryptoerror(LOG_STDERR, gettext("internal error."));
672		cryptodebug("enable_uef_lib() - wrong arguments.");
673		return (FAILURE);
674	}
675
676	if (rndflag)
677		puent->flag_norandom = B_FALSE;
678
679	if (rc == FAILURE) {
680		free_uentry(puent);
681		return (FAILURE);
682	}
683
684	/* Update the pkcs11.conf file with the updated entry */
685	rc = update_pkcs11conf(puent);
686	free_uentry(puent);
687	return (rc);
688}
689
690
691/*
692 * Install a user-level library.
693 */
694int
695install_uef_lib(char *libname)
696{
697	uentry_t	*puent;
698	struct stat 	statbuf;
699	boolean_t	found;
700	FILE	*pfile;
701	FILE	*pfile_tmp;
702	char	tmpfile_name[MAXPATHLEN];
703	char	libpath[MAXPATHLEN];
704	char	libbuf[MAXPATHLEN];
705	char	*isa;
706	char 	buffer[BUFSIZ];
707	char 	*ptr;
708	int	found_count;
709	int	rc = SUCCESS;
710
711
712	if (libname == NULL) {
713		/* should not happen */
714		cryptoerror(LOG_STDERR, gettext("internal error."));
715		cryptodebug("install_uef_lib() - libname is NULL.");
716		return (FAILURE);
717	}
718
719	/* Check if the provider already exists in the framework */
720	if ((puent = getent_uef(libname)) != NULL) {
721		cryptoerror(LOG_STDERR, gettext("%s exists already."),
722		    libname);
723		free_uentry(puent);
724		return (FAILURE);
725	}
726
727	/*
728	 * Check if the library exists in the system. if $ISA is in the
729	 * path, only check the 32bit version.
730	 */
731	if (strlcpy(libbuf, libname, MAXPATHLEN) >= MAXPATHLEN) {
732		cryptoerror(LOG_STDERR,
733		    gettext("the provider name is too long - %s"), libname);
734		return (FAILURE);
735	}
736
737	if ((isa = strstr(libbuf, PKCS11_ISA)) != NULL) {
738		*isa = '\000';
739		isa += strlen(PKCS11_ISA);
740		(void) snprintf(libpath, sizeof (libpath), "%s%s%s", libbuf,
741		    "/", isa);
742	} else {
743		(void) strlcpy(libpath, libname, sizeof (libpath));
744	}
745
746	/* Check if it is same as the framework library */
747	if (strcmp(libpath, UEF_FRAME_LIB) == 0) {
748		cryptoerror(LOG_STDERR, gettext(
749		    "The framework library %s can not be installed."),
750		    libname);
751		return (FAILURE);
752	}
753
754	if (stat(libpath, &statbuf) != 0) {
755		cryptoerror(LOG_STDERR, gettext("%s not found"), libname);
756		return (FAILURE);
757	}
758
759	/* Need to add "\n" to libname for adding into the config file */
760	if (strlcat(libname, "\n", MAXPATHLEN) >= MAXPATHLEN) {
761		cryptoerror(LOG_STDERR, gettext(
762		    "can not install %s; the name is too long."), libname);
763		return (FAILURE);
764	}
765
766	if ((pfile = fopen(_PATH_PKCS11_CONF, "r+")) == NULL) {
767		err = errno;
768		cryptoerror(LOG_STDERR,
769		    gettext("failed to update the configuration - %s"),
770		    strerror(err));
771		cryptodebug("failed to open %s for write.", _PATH_PKCS11_CONF);
772		return (FAILURE);
773	}
774
775	if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
776		err = errno;
777		cryptoerror(LOG_STDERR,
778		    gettext("failed to lock the configuration - %s"),
779		    strerror(err));
780		(void) fclose(pfile);
781		return (FAILURE);
782	}
783
784	/*
785	 * Create a temporary file in the /etc/crypto directory.
786	 */
787	(void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
788	if (mkstemp(tmpfile_name) == -1) {
789		err = errno;
790		cryptoerror(LOG_STDERR,
791		    gettext("failed to create a temporary file - %s"),
792		    strerror(err));
793		(void) fclose(pfile);
794		return (FAILURE);
795	}
796
797	if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
798		err = errno;
799		cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
800		    tmpfile_name, strerror(err));
801		(void) fclose(pfile);
802		return (FAILURE);
803	}
804
805	/*
806	 * Loop thru the config file. If the file was reserved within a
807	 * package bracket, just uncomment it.  Other wise, append it at
808	 * the end.  The resulting file will be saved in the temp file first.
809	 */
810	found_count = 0;
811	rc = SUCCESS;
812	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
813		found = B_FALSE;
814		if (buffer[0] == '#') {
815			ptr = buffer;
816			ptr++;
817			if (strcmp(libname, ptr) == 0) {
818				found = B_TRUE;
819				found_count++;
820			}
821		}
822
823		if (found == B_FALSE) {
824			if (fputs(buffer, pfile_tmp) == EOF) {
825				rc = FAILURE;
826			}
827		} else {
828			if (found_count == 1) {
829				if (fputs(ptr, pfile_tmp) == EOF) {
830					rc = FAILURE;
831				}
832			} else {
833				/*
834				 * Found a second entry with #libname.
835				 * Should not happen. The pkcs11.conf file
836				 * is corrupted. Give a warning and skip
837				 * this entry.
838				 */
839				cryptoerror(LOG_STDERR, gettext(
840				    "(Warning) Found an additional reserved "
841				    "entry for %s."), libname);
842			}
843		}
844
845		if (rc == FAILURE) {
846			break;
847		}
848	}
849
850	if (rc == FAILURE) {
851		cryptoerror(LOG_STDERR, gettext("write error."));
852		(void) fclose(pfile);
853		(void) fclose(pfile_tmp);
854		if (unlink(tmpfile_name) != 0) {
855			err = errno;
856			cryptoerror(LOG_STDERR, gettext(
857			    "(Warning) failed to remove %s: %s"), tmpfile_name,
858			    strerror(err));
859		}
860		return (FAILURE);
861	}
862
863	if (found_count == 0) {
864		/*
865		 * This libname was not in package before, append it to the
866		 * end of the temp file.
867		 */
868		if (fputs(libname, pfile_tmp) == EOF) {
869			err = errno;
870			cryptoerror(LOG_STDERR, gettext(
871			    "failed to write to %s: %s"), tmpfile_name,
872			    strerror(err));
873			(void) fclose(pfile);
874			(void) fclose(pfile_tmp);
875			if (unlink(tmpfile_name) != 0) {
876				err = errno;
877				cryptoerror(LOG_STDERR, gettext(
878				    "(Warning) failed to remove %s: %s"),
879				    tmpfile_name, strerror(err));
880			}
881			return (FAILURE);
882		}
883	}
884
885	(void) fclose(pfile);
886	if (fclose(pfile_tmp) != 0) {
887		err = errno;
888		cryptoerror(LOG_STDERR,
889		    gettext("failed to close %s: %s"), tmpfile_name,
890		    strerror(err));
891		return (FAILURE);
892	}
893
894	if (rename(tmpfile_name, _PATH_PKCS11_CONF) == -1) {
895		err = errno;
896		cryptoerror(LOG_STDERR,
897		    gettext("failed to update the configuration - %s"),
898		    strerror(err));
899		cryptodebug("failed to rename %s to %s: %s", tmpfile_name,
900		    _PATH_PKCS11_CONF, strerror(err));
901		rc = FAILURE;
902	} else if (chmod(_PATH_PKCS11_CONF,
903	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
904		err = errno;
905		cryptoerror(LOG_STDERR,
906		    gettext("failed to update the configuration - %s"),
907		    strerror(err));
908		cryptodebug("failed to chmod to %s: %s", _PATH_PKCS11_CONF,
909		    strerror(err));
910		rc = FAILURE;
911	} else {
912		rc = SUCCESS;
913	}
914
915	if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
916		err = errno;
917		cryptoerror(LOG_STDERR, gettext(
918		    "(Warning) failed to remove %s: %s"), tmpfile_name,
919		    strerror(err));
920	}
921
922	return (rc);
923}
924
925
926/*
927 * Uninstall a user-level library.
928 */
929int
930uninstall_uef_lib(char *libname)
931{
932	uentry_t	*puent;
933	FILE	*pfile;
934	FILE	*pfile_tmp;
935	char 	buffer[BUFSIZ];
936	char 	buffer2[BUFSIZ];
937	char	tmpfile_name[MAXPATHLEN];
938	char 	*name;
939	boolean_t	found;
940	boolean_t	in_package;
941	int	len;
942	int	rc = SUCCESS;
943
944	if (libname == NULL) {
945		/* should not happen */
946		cryptoerror(LOG_STDERR, gettext("internal error."));
947		cryptodebug("uninstall_uef_lib() - libname is NULL.");
948		return (FAILURE);
949	}
950
951	/* Check if the provider exists */
952	if ((puent = getent_uef(libname)) == NULL) {
953		cryptoerror(LOG_STDERR,
954		    gettext("%s does not exist."), libname);
955		return (FAILURE);
956	}
957	free_uentry(puent);
958
959	/*  Open the pkcs11.conf file and lock it */
960	if ((pfile = fopen(_PATH_PKCS11_CONF, "r+")) == NULL) {
961		err = errno;
962		cryptoerror(LOG_STDERR,
963		    gettext("failed to update the configuration - %s"),
964		    strerror(err));
965		cryptodebug("failed to open %s for write.", _PATH_PKCS11_CONF);
966		return (FAILURE);
967	}
968
969	if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
970		err = errno;
971		cryptoerror(LOG_STDERR,
972		    gettext("failed to lock the configuration - %s"),
973		    strerror(err));
974		(void) fclose(pfile);
975		return (FAILURE);
976	}
977
978	/*
979	 * Create a temporary file in the /etc/crypto directory to save
980	 * the new configuration file first.
981	 */
982	(void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
983	if (mkstemp(tmpfile_name) == -1) {
984		err = errno;
985		cryptoerror(LOG_STDERR,
986		    gettext("failed to create a temporary file - %s"),
987		    strerror(err));
988		(void) fclose(pfile);
989		return (FAILURE);
990	}
991
992	if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
993		err = errno;
994		cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
995		    tmpfile_name, strerror(err));
996		if (unlink(tmpfile_name) != 0) {
997			err = errno;
998			cryptoerror(LOG_STDERR, gettext(
999			    "(Warning) failed to remove %s: %s"),
1000			    tmpfile_name, strerror(err));
1001		}
1002		(void) fclose(pfile);
1003		return (FAILURE);
1004	}
1005
1006
1007	/*
1008	 * Loop thru the config file.  If the library to be uninstalled
1009	 * is in a package, just comment it off.
1010	 */
1011	in_package = B_FALSE;
1012	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
1013		found = B_FALSE;
1014		if (!(buffer[0] == ' ' || buffer[0] == '\n' ||
1015		    buffer[0] == '\t')) {
1016			if (strstr(buffer, " Start ") != NULL) {
1017				in_package = B_TRUE;
1018			} else if (strstr(buffer, " End ") != NULL) {
1019				in_package = B_FALSE;
1020			} else if (buffer[0] != '#') {
1021				(void) strlcpy(buffer2, buffer, BUFSIZ);
1022
1023				/* get rid of trailing '\n' */
1024				len = strlen(buffer2);
1025				if (buffer2[len-1] == '\n') {
1026					len--;
1027				}
1028				buffer2[len] = '\0';
1029
1030				if ((name = strtok(buffer2, SEP_COLON))
1031				    == NULL) {
1032					rc = FAILURE;
1033					break;
1034				} else if (strcmp(libname, name) == 0) {
1035					found = B_TRUE;
1036				}
1037			}
1038		}
1039
1040		if (found) {
1041			if (in_package) {
1042				(void) snprintf(buffer2, sizeof (buffer2),
1043				    "%s%s%s", "#", libname, "\n");
1044				if (fputs(buffer2, pfile_tmp) == EOF) {
1045					rc = FAILURE;
1046				}
1047			}
1048		} else {
1049			if (fputs(buffer, pfile_tmp) == EOF) {
1050				rc = FAILURE;
1051			}
1052		}
1053
1054		if (rc == FAILURE) {
1055			break;
1056		}
1057	}
1058
1059	if (rc == FAILURE) {
1060		cryptoerror(LOG_STDERR, gettext("write error."));
1061		(void) fclose(pfile);
1062		(void) fclose(pfile_tmp);
1063		if (unlink(tmpfile_name) != 0) {
1064			err = errno;
1065			cryptoerror(LOG_STDERR, gettext(
1066			    "(Warning) failed to remove %s: %s"),
1067			    tmpfile_name, strerror(err));
1068		}
1069		return (FAILURE);
1070	}
1071
1072	(void) fclose(pfile);
1073	if (fclose(pfile_tmp) != 0) {
1074		err = errno;
1075		cryptoerror(LOG_STDERR,
1076		    gettext("failed to close a temporary file - %s"),
1077		    strerror(err));
1078		return (FAILURE);
1079	}
1080
1081	/* Now update the real config file */
1082	if (rename(tmpfile_name, _PATH_PKCS11_CONF) == -1) {
1083		err = errno;
1084		cryptoerror(LOG_STDERR,
1085		    gettext("failed to update the configuration - %s"),
1086		    strerror(err));
1087		cryptodebug("failed to rename %s to %s: %s", tmpfile,
1088		    _PATH_PKCS11_CONF, strerror(err));
1089		rc = FAILURE;
1090	} else if (chmod(_PATH_PKCS11_CONF,
1091	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
1092		err = errno;
1093		cryptoerror(LOG_STDERR,
1094		    gettext("failed to update the configuration - %s"),
1095		    strerror(err));
1096		cryptodebug("failed to chmod to %s: %s", _PATH_PKCS11_CONF,
1097		    strerror(err));
1098		rc = FAILURE;
1099	} else {
1100		rc = SUCCESS;
1101	}
1102
1103	if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
1104		err = errno;
1105		cryptoerror(LOG_STDERR, gettext(
1106		    "(Warning) failed to remove %s: %s"),
1107		    tmpfile_name, strerror(err));
1108	}
1109
1110	return (rc);
1111}
1112
1113
1114int
1115display_policy(uentry_t *puent)
1116{
1117	CK_MECHANISM_TYPE  mech_id;
1118	char *mech_name;
1119	umechlist_t *ptr;
1120
1121	if (puent == NULL) {
1122		return (SUCCESS);
1123	}
1124
1125	if (puent->flag_enabledlist == B_FALSE) {
1126		(void) printf(gettext("%s: all mechanisms are enabled"),
1127		    puent->name);
1128		ptr = puent->policylist;
1129		if (ptr == NULL) {
1130			(void) printf(".");
1131		} else {
1132			(void) printf(gettext(", except "));
1133			while (ptr != NULL) {
1134				mech_id = strtoul(ptr->name, NULL, 0);
1135				if (mech_id & CKO_VENDOR_DEFINED) {
1136					/* vendor defined mechanism */
1137					(void) printf("%s", ptr->name);
1138				} else {
1139					mech_name = pkcs11_mech2str(mech_id);
1140					if (mech_name == NULL) {
1141						return (FAILURE);
1142					}
1143					(void) printf("%s", mech_name);
1144					free(mech_name);
1145				}
1146
1147				ptr = ptr->next;
1148				if (ptr == NULL) {
1149					(void) printf(".");
1150				} else {
1151					(void) printf(",");
1152				}
1153			}
1154		}
1155	} else { /* puent->flag_enabledlist == B_TRUE */
1156		(void) printf(gettext("%s: all mechanisms are disabled"),
1157		    puent->name);
1158		ptr = puent->policylist;
1159		if (ptr == NULL) {
1160			(void) printf(".");
1161		} else {
1162			(void) printf(gettext(", except "));
1163			while (ptr != NULL) {
1164				mech_id = strtoul(ptr->name, NULL, 0);
1165				if (mech_id & CKO_VENDOR_DEFINED) {
1166					/* vendor defined mechanism */
1167					(void) printf("%s", ptr->name);
1168				} else {
1169					mech_name = pkcs11_mech2str(mech_id);
1170					if (mech_name == NULL) {
1171						return (FAILURE);
1172					}
1173					(void) printf("%s", mech_name);
1174					free(mech_name);
1175				}
1176				ptr = ptr->next;
1177				if (ptr == NULL) {
1178					(void) printf(".");
1179				} else {
1180					(void) printf(",");
1181				}
1182			}
1183		}
1184	}
1185	return (SUCCESS);
1186}
1187
1188
1189
1190/*
1191 * Print out the mechanism policy for a user-level provider pointed by puent.
1192 */
1193int
1194print_uef_policy(uentry_t *puent)
1195{
1196	flag_val_t rng_flag;
1197
1198	if (puent == NULL) {
1199		return (FAILURE);
1200	}
1201
1202	rng_flag = NO_RNG;
1203	if (list_mechlist_for_lib(puent->name, NULL, &rng_flag, B_TRUE,
1204		B_FALSE, B_FALSE) != SUCCESS) {
1205		cryptoerror(LOG_STDERR,
1206		    gettext("%s internal error."), puent->name);
1207		return (FAILURE);
1208	}
1209
1210	if (display_policy(puent) != SUCCESS) {
1211		goto failed_exit;
1212	}
1213
1214
1215	if (puent->flag_norandom == B_TRUE)
1216		/*
1217		 * TRANSLATION_NOTE:
1218		 * "random" is a keyword and not to be translated.
1219		 */
1220		(void) printf(gettext(" %s is disabled."), "random");
1221	else {
1222		if (rng_flag == HAS_RNG)
1223			/*
1224			 * TRANSLATION_NOTE:
1225			 * "random" is a keyword and not to be translated.
1226			 */
1227			(void) printf(gettext(" %s is enabled."), "random");
1228	}
1229	(void) printf("\n");
1230
1231	return (SUCCESS);
1232
1233failed_exit:
1234
1235	(void) printf(gettext("\nout of memory.\n"));
1236	return (FAILURE);
1237}
1238
1239
1240/*
1241 * Check if the mechanism is in the mechanism list.
1242 */
1243static boolean_t
1244is_in_policylist(midstr_t mechname, umechlist_t *plist)
1245{
1246	boolean_t found = B_FALSE;
1247
1248	if (mechname == NULL) {
1249		return (B_FALSE);
1250	}
1251
1252	while (plist != NULL) {
1253		if (strcmp(plist->name, mechname) == 0) {
1254			found = B_TRUE;
1255			break;
1256		}
1257		plist = plist->next;
1258	}
1259
1260	return (found);
1261}
1262
1263
1264/*
1265 * Update the pkcs11.conf file with the updated entry.
1266 */
1267int
1268update_pkcs11conf(uentry_t *puent)
1269{
1270	FILE	*pfile;
1271	FILE	*pfile_tmp;
1272	char buffer[BUFSIZ];
1273	char buffer2[BUFSIZ];
1274	char tmpfile_name[MAXPATHLEN];
1275	char *name;
1276	char *str;
1277	int len;
1278	int rc = SUCCESS;
1279	boolean_t found;
1280
1281	if (puent == NULL) {
1282		cryptoerror(LOG_STDERR, gettext("internal error."));
1283		return (FAILURE);
1284	}
1285
1286	/* Open the pkcs11.conf file */
1287	if ((pfile = fopen(_PATH_PKCS11_CONF, "r+")) == NULL) {
1288		err = errno;
1289		cryptoerror(LOG_STDERR,
1290		    gettext("failed to update the configuration - %s"),
1291		    strerror(err));
1292		cryptodebug("failed to open %s for write.", _PATH_PKCS11_CONF);
1293		return (FAILURE);
1294	}
1295
1296	/* Lock the pkcs11.conf file */
1297	if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
1298		err = errno;
1299		cryptoerror(LOG_STDERR,
1300		    gettext("failed to update the configuration - %s"),
1301			strerror(err));
1302		(void) fclose(pfile);
1303		return (FAILURE);
1304	}
1305
1306	/*
1307	 * Create a temporary file in the /etc/crypto directory to save
1308	 * updated configuration file first.
1309	 */
1310	(void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
1311	if (mkstemp(tmpfile_name) == -1) {
1312		err = errno;
1313		cryptoerror(LOG_STDERR,
1314		    gettext("failed to create a temporary file - %s"),
1315		    strerror(err));
1316		(void) fclose(pfile);
1317		return (FAILURE);
1318	}
1319
1320	if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
1321		err = errno;
1322		cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
1323		    tmpfile_name, strerror(err));
1324		if (unlink(tmpfile_name) != 0) {
1325			err = errno;
1326			cryptoerror(LOG_STDERR, gettext(
1327			    "(Warning) failed to remove %s: %s"),
1328			    tmpfile_name, strerror(err));
1329		}
1330		(void) fclose(pfile);
1331		return (FAILURE);
1332	}
1333
1334
1335	/*
1336	 * Loop thru entire pkcs11.conf file, update the entry to be
1337	 * updated and save the updated file to the temporary file first.
1338	 */
1339	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
1340		found = B_FALSE;
1341		if (!(buffer[0] == '#' || buffer[0] == ' ' ||
1342		    buffer[0] == '\n'|| buffer[0] == '\t')) {
1343			/*
1344			 * Get the provider name from this line and check if
1345			 * this is the entry to be updated. Note: can not use
1346			 * "buffer" directly because strtok will change its
1347			 * value.
1348			 */
1349			(void) strlcpy(buffer2, buffer, BUFSIZ);
1350
1351			/* get rid of trailing '\n' */
1352			len = strlen(buffer2);
1353			if (buffer2[len-1] == '\n') {
1354				len--;
1355			}
1356			buffer2[len] = '\0';
1357
1358			if ((name = strtok(buffer2, SEP_COLON)) == NULL) {
1359				rc = FAILURE;
1360				break;
1361			} else if (strcmp(puent->name, name) == 0) {
1362				found = B_TRUE;
1363			}
1364		}
1365
1366		if (found) {
1367			/*
1368			 * This is the entry to be modified, get the updated
1369			 * string.
1370			 */
1371			if ((str = uent2str(puent)) == NULL) {
1372				rc = FAILURE;
1373				break;
1374			} else {
1375				(void) strlcpy(buffer, str, BUFSIZ);
1376				free(str);
1377			}
1378		}
1379
1380		if (fputs(buffer, pfile_tmp) == EOF) {
1381			err = errno;
1382			cryptoerror(LOG_STDERR, gettext(
1383			    "failed to write to a temp file: %s."),
1384			    strerror(err));
1385			rc = FAILURE;
1386			break;
1387		}
1388	}
1389
1390	if (rc == FAILURE) {
1391		(void) fclose(pfile);
1392		(void) fclose(pfile_tmp);
1393		if (unlink(tmpfile_name) != 0) {
1394			err = errno;
1395			cryptoerror(LOG_STDERR, gettext(
1396			    "(Warning) failed to remove %s: %s"),
1397			    tmpfile_name, strerror(err));
1398		}
1399		return (FAILURE);
1400	}
1401
1402	(void) fclose(pfile);
1403	if (fclose(pfile_tmp) != 0) {
1404		err = errno;
1405		cryptoerror(LOG_STDERR,
1406		    gettext("failed to close %s: %s"), tmpfile_name,
1407		    strerror(err));
1408		return (FAILURE);
1409	}
1410
1411	/* Copy the temporary file to the pkcs11.conf file */
1412	if (rename(tmpfile_name, _PATH_PKCS11_CONF) == -1) {
1413		err = errno;
1414		cryptoerror(LOG_STDERR,
1415		    gettext("failed to update the configuration - %s"),
1416		    strerror(err));
1417		cryptodebug("failed to rename %s to %s: %s", tmpfile_name,
1418		    _PATH_PKCS11_CONF, strerror(err));
1419		rc = FAILURE;
1420	} else if (chmod(_PATH_PKCS11_CONF,
1421	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
1422		err = errno;
1423		cryptoerror(LOG_STDERR,
1424		    gettext("failed to update the configuration - %s"),
1425		    strerror(err));
1426		cryptodebug("failed to chmod to %s: %s", _PATH_PKCS11_CONF,
1427		    strerror(err));
1428		rc = FAILURE;
1429	} else {
1430		rc = SUCCESS;
1431	}
1432
1433	if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
1434		err = errno;
1435		cryptoerror(LOG_STDERR, gettext(
1436		    "(Warning) failed to remove %s: %s"),
1437		    tmpfile_name, strerror(err));
1438	}
1439
1440	return (rc);
1441}
1442
1443
1444/*
1445 * Convert an uentry to a character string
1446 */
1447static char *
1448uent2str(uentry_t *puent)
1449{
1450	umechlist_t	*phead;
1451	boolean_t tok1_present = B_FALSE;
1452	char *buf;
1453	char blank_buf[128];
1454
1455	if (puent == NULL) {
1456		cryptoerror(LOG_STDERR, gettext("internal error."));
1457		return (NULL);
1458	}
1459
1460	buf = malloc(BUFSIZ);
1461	if (buf == NULL) {
1462		cryptoerror(LOG_STDERR, gettext("out of memory."));
1463		return (NULL);
1464	}
1465
1466	/* convert the library name */
1467	if (strlcpy(buf, puent->name, BUFSIZ) >= BUFSIZ) {
1468		free(buf);
1469		return (NULL);
1470	}
1471
1472
1473	/* convert the enabledlist or the disabledlist */
1474	if (puent->flag_enabledlist == B_TRUE) {
1475		if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) {
1476			free(buf);
1477			return (NULL);
1478		}
1479
1480		if (strlcat(buf, EF_ENABLED, BUFSIZ) >= BUFSIZ) {
1481			free(buf);
1482			return (NULL);
1483		}
1484
1485		phead = puent->policylist;
1486		while (phead != NULL) {
1487			if (strlcat(buf, phead->name, BUFSIZ) >= BUFSIZ) {
1488				free(buf);
1489				return (NULL);
1490			}
1491
1492			phead = phead->next;
1493			if (phead != NULL) {
1494				if (strlcat(buf, SEP_COMMA, BUFSIZ)
1495				    >= BUFSIZ) {
1496					free(buf);
1497					return (NULL);
1498				}
1499			}
1500		}
1501		tok1_present = B_TRUE;
1502	} else if (puent->policylist != NULL) {
1503		if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) {
1504			free(buf);
1505			return (NULL);
1506		}
1507
1508		if (strlcat(buf, EF_DISABLED, BUFSIZ) >= BUFSIZ) {
1509			free(buf);
1510			return (NULL);
1511		}
1512		phead = puent->policylist;
1513		while (phead != NULL) {
1514			if (strlcat(buf, phead->name, BUFSIZ) >= BUFSIZ) {
1515				free(buf);
1516				return (NULL);
1517			}
1518
1519			phead = phead->next;
1520			if (phead != NULL) {
1521				if (strlcat(buf, SEP_COMMA, BUFSIZ)
1522				    >= BUFSIZ) {
1523					free(buf);
1524					return (NULL);
1525				}
1526			}
1527		}
1528		tok1_present = B_TRUE;
1529	}
1530
1531	if (puent->flag_norandom == B_TRUE) {
1532		if (strlcat(buf, (tok1_present ? SEP_SEMICOLON : SEP_COLON),
1533		    BUFSIZ) >= BUFSIZ) {
1534			free(buf);
1535			return (NULL);
1536		}
1537
1538		if (strlcat(buf, EF_NORANDOM, BUFSIZ) >= BUFSIZ) {
1539			free(buf);
1540			return (NULL);
1541		}
1542	}
1543
1544	if (strcmp(puent->name, METASLOT_KEYWORD) == 0) {
1545
1546		/* write the metaslot_status= value */
1547		if (strlcat(buf, (tok1_present ? SEP_SEMICOLON : SEP_COLON),
1548		    BUFSIZ) >= BUFSIZ) {
1549			free(buf);
1550			return (NULL);
1551		}
1552
1553		if (strlcat(buf, METASLOT_STATUS, BUFSIZ) >= BUFSIZ) {
1554			free(buf);
1555			return (NULL);
1556		}
1557
1558		if (puent->flag_metaslot_enabled) {
1559			if (strlcat(buf, METASLOT_ENABLED, BUFSIZ) >= BUFSIZ) {
1560				free(buf);
1561				return (NULL);
1562			}
1563		} else {
1564			if (strlcat(buf, METASLOT_DISABLED, BUFSIZ)
1565			    >= BUFSIZ) {
1566				free(buf);
1567				return (NULL);
1568			}
1569		}
1570
1571		if (!tok1_present) {
1572			tok1_present = B_TRUE;
1573		}
1574
1575		if (strlcat(buf, SEP_SEMICOLON, BUFSIZ) >= BUFSIZ) {
1576			free(buf);
1577			return (NULL);
1578		}
1579
1580		if (strlcat(buf, METASLOT_AUTO_KEY_MIGRATE, BUFSIZ) >= BUFSIZ) {
1581			free(buf);
1582			return (NULL);
1583		}
1584
1585		if (puent->flag_metaslot_auto_key_migrate) {
1586			if (strlcat(buf, METASLOT_ENABLED, BUFSIZ) >= BUFSIZ) {
1587				free(buf);
1588				return (NULL);
1589			}
1590		} else {
1591			if (strlcat(buf, METASLOT_DISABLED, BUFSIZ) >= BUFSIZ) {
1592				free(buf);
1593				return (NULL);
1594			}
1595		}
1596
1597		bzero(blank_buf, sizeof (blank_buf));
1598
1599		/* write metaslot_token= if specified */
1600		if (memcmp(puent->metaslot_ks_token, blank_buf,
1601		    TOKEN_LABEL_SIZE) != 0) {
1602			/* write the metaslot_status= value */
1603			if (strlcat(buf, (tok1_present ?
1604			    SEP_SEMICOLON : SEP_COLON), BUFSIZ) >= BUFSIZ) {
1605				free(buf);
1606				return (NULL);
1607			}
1608
1609			if (strlcat(buf, METASLOT_TOKEN, BUFSIZ) >= BUFSIZ) {
1610				free(buf);
1611				return (NULL);
1612			}
1613
1614			if (strlcat(buf,
1615			    (const char *)puent->metaslot_ks_token, BUFSIZ)
1616			    >= BUFSIZ) {
1617				free(buf);
1618				return (NULL);
1619			}
1620		}
1621
1622		/* write metaslot_slot= if specified */
1623		if (memcmp(puent->metaslot_ks_slot, blank_buf,
1624		    SLOT_DESCRIPTION_SIZE) != 0) {
1625			/* write the metaslot_status= value */
1626			if (strlcat(buf, (tok1_present ?
1627			    SEP_SEMICOLON : SEP_COLON), BUFSIZ) >= BUFSIZ) {
1628				free(buf);
1629				return (NULL);
1630			}
1631
1632			if (strlcat(buf, METASLOT_SLOT, BUFSIZ) >= BUFSIZ) {
1633				free(buf);
1634				return (NULL);
1635			}
1636
1637			if (strlcat(buf,
1638			    (const char *)puent->metaslot_ks_slot, BUFSIZ)
1639			    >= BUFSIZ) {
1640				free(buf);
1641				return (NULL);
1642			}
1643		}
1644	}
1645
1646	if (strlcat(buf, "\n", BUFSIZ) >= BUFSIZ) {
1647		free(buf);
1648		return (NULL);
1649	}
1650
1651	return (buf);
1652}
1653
1654
1655/*
1656 * This function updates the default policy mode and the policy exception list
1657 * for a user-level provider based on the mechanism specified in the disable
1658 * or enable subcommand and the update mode.   This function is called by the
1659 * enable_uef_lib() or disable_uef_lib().
1660 */
1661int
1662update_policylist(uentry_t *puent, mechlist_t *marglist, int update_mode)
1663{
1664	CK_MECHANISM_TYPE mech_type;
1665	midstr_t	midname;
1666	umechlist_t	*phead;
1667	umechlist_t	*pcur;
1668	umechlist_t	*pumech;
1669	boolean_t	found;
1670	int	rc = SUCCESS;
1671
1672	if ((puent == NULL) || (marglist == NULL)) {
1673		/* should not happen */
1674		cryptoerror(LOG_STDERR, gettext("internal error."));
1675		cryptodebug("update_policylist()- puent or marglist is NULL.");
1676		return (FAILURE);
1677	}
1678
1679	if ((update_mode != ADD_MODE) && (update_mode != DELETE_MODE)) {
1680		/* should not happen */
1681		cryptoerror(LOG_STDERR, gettext("internal error."));
1682		cryptodebug("update_policylist() - update_mode is incorrect.");
1683		return (FAILURE);
1684	}
1685
1686	/*
1687	 * For each mechanism operand, get its mechanism type first.
1688	 * If fails to get the mechanism type, the mechanism operand must be
1689	 * invalid, gives an warning and ignore it. Otherwise,
1690	 * - convert the mechanism type to the internal representation (hex)
1691	 *   in the pkcs11.conf file
1692	 * - If update_mode == DELETE_MODE,
1693	 *	If the mechanism is in the policy list, delete it.
1694	 *	If the mechanism is not in the policy list, do nothing.
1695	 * - If update_mode == ADD_MODE,
1696	 *	If the mechanism is not in the policy list, add it.
1697	 *	If the mechanism is in the policy list already, do nothing.
1698	 */
1699	while (marglist) {
1700		if (pkcs11_str2mech(marglist->name, &mech_type) != CKR_OK) {
1701			/*
1702			 * This mechanism is not a valid PKCS11 mechanism,
1703			 * give warning and ignore it.
1704			 */
1705			cryptoerror(LOG_STDERR, gettext(
1706			    "(Warning) %s is not a valid PKCS#11 mechanism."),
1707			    marglist->name);
1708			rc = FAILURE;
1709		} else {
1710			(void) snprintf(midname, sizeof (midname), "%#010x",
1711			    (int)mech_type);
1712			if (update_mode == DELETE_MODE) {
1713				found = B_FALSE;
1714				phead = pcur = puent->policylist;
1715				while (!found && pcur) {
1716					if (strcmp(pcur->name, midname) == 0) {
1717						found = B_TRUE;
1718					} else {
1719						phead = pcur;
1720						pcur = pcur->next;
1721					}
1722				}
1723
1724				if (found) {
1725					if (phead == pcur) {
1726						puent->policylist =
1727						    puent->policylist->next;
1728						free(pcur);
1729					} else {
1730						phead->next = pcur->next;
1731						free(pcur);
1732					}
1733					puent->count--;
1734					if (puent->count == 0) {
1735						puent->policylist = NULL;
1736					}
1737				}
1738			} else if (update_mode == ADD_MODE) {
1739				if (!is_in_policylist(midname,
1740				    puent->policylist)) {
1741					pumech = create_umech(midname);
1742					if (pumech == NULL) {
1743						rc = FAILURE;
1744						break;
1745					}
1746					phead = puent->policylist;
1747					puent->policylist = pumech;
1748					pumech->next = phead;
1749					puent->count++;
1750				}
1751			}
1752		}
1753		marglist = marglist->next;
1754	}
1755
1756	return (rc);
1757}
1758
1759/*
1760 * Open a session to the given slot and check if we can do
1761 * random numbers by asking for one byte.
1762 */
1763static boolean_t
1764check_random(CK_SLOT_ID slot_id, CK_FUNCTION_LIST_PTR prov_funcs)
1765{
1766	CK_RV rv;
1767	CK_SESSION_HANDLE hSession;
1768	CK_BYTE test_byte;
1769	CK_BYTE_PTR test_byte_ptr = &test_byte;
1770
1771	rv = prov_funcs->C_OpenSession(slot_id, CKF_SERIAL_SESSION,
1772	    NULL_PTR, NULL, &hSession);
1773	if (rv != CKR_OK)
1774		return (B_FALSE);
1775
1776	/* We care only about the return value */
1777	rv = prov_funcs->C_GenerateRandom(hSession, test_byte_ptr,
1778	    sizeof (test_byte));
1779	(void) prov_funcs->C_CloseSession(hSession);
1780
1781	/*
1782	 * These checks are purely to determine whether the slot can do
1783	 * random numbers. So, we don't check whether the routine
1784	 * succeeds. The reason we check for CKR_RANDOM_NO_RNG also is that
1785	 * this error effectively means CKR_FUNCTION_NOT_SUPPORTED.
1786	 */
1787	if (rv != CKR_FUNCTION_NOT_SUPPORTED && rv != CKR_RANDOM_NO_RNG)
1788		return (B_TRUE);
1789	else
1790		return (B_FALSE);
1791}
1792
1793void
1794display_verbose_mech_header()
1795{
1796	(void) printf("%28s %s", " ", HDR1);
1797	(void) printf("%28s %s", " ", HDR2);
1798	(void) printf("%28s %s", " ", HDR3);
1799	(void) printf("%28s %s", " ", HDR4);
1800	(void) printf("%28s %s", " ", HDR5);
1801	(void) printf("%28s %s", " ", HDR6);
1802	(void) printf("%-28.28s %s", gettext("mechanism name"), HDR7);
1803	/*
1804	 * TRANSLATION_NOTE:
1805	 * Strictly for appearance's sake, the first header line should be
1806	 * as long as the length of the translated text above.  The format
1807	 * lengths should all match too.
1808	 */
1809	(void) printf("%28s ---- ---- "
1810	    "-  -  -  -  -  -  -  -  -  -  -  -  -  -\n",
1811	    gettext("----------------------------"));
1812}
1813