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