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