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