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