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