xref: /illumos-gate/usr/src/cmd/cmd-crypto/cryptoadm/adm_uef.c (revision 24b9abbad58fdd63dad716fd35a99a7944c4e3eb)
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 2008 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 corresponding 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 	const 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 			CK_MECHANISM_TYPE	mech = pmech_list[j];
450 
451 			if (mech > CKM_VENDOR_DEFINED) {
452 				(void) printf("%#lx", mech);
453 			} else {
454 				mech_name = pkcs11_mech2str(mech);
455 				(void) printf("%-29s", mech_name);
456 			}
457 
458 			if (verbose) {
459 				CK_MECHANISM_INFO mech_info;
460 				rv = prov_funcs->C_GetMechanismInfo(
461 				    prov_slots[i], mech, &mech_info);
462 				if (rv != CKR_OK) {
463 					cryptodebug(
464 					    "failed to call "
465 					    "C_GetMechanismInfo() from %s.",
466 					    libname);
467 					(void) free(pmech_list);
468 					rc = FAILURE;
469 					break;
470 				}
471 				display_mech_info(&mech_info);
472 			}
473 			(void) printf("\n");
474 		}
475 		(void) free(pmech_list);
476 		if (rc == FAILURE) {
477 			break;
478 		}
479 	}
480 
481 	if (rng_flag != NULL || rc == FAILURE) {
482 		goto clean_exit;
483 	}
484 
485 clean_exit:
486 
487 	if (rc == FAILURE) {
488 		(void) printf(gettext(
489 		    "%s: failed to retrieve the mechanism list.\n"), libname);
490 	}
491 
492 	if (lib_initialized) {
493 		(void) prov_funcs->C_Finalize(NULL_PTR);
494 	}
495 
496 	if (dldesc != NULL) {
497 		(void) dlclose(dldesc);
498 	}
499 
500 	if (prov_slots != NULL) {
501 		(void) free(prov_slots);
502 	}
503 
504 	return (rc);
505 }
506 
507 
508 /*
509  * Display the mechanism policy for a user-level library
510  */
511 int
512 list_policy_for_lib(char *libname)
513 {
514 	uentry_t *puent = NULL;
515 	int rc;
516 
517 	if (libname == NULL) {
518 		/* should not happen */
519 		cryptoerror(LOG_STDERR, gettext("internal error."));
520 		cryptodebug("list_policy_for_lib() - libname is NULL.");
521 		return (FAILURE);
522 	}
523 
524 	/* Get the library entry from the pkcs11.conf file */
525 	if ((puent = getent_uef(libname)) == NULL) {
526 		cryptoerror(LOG_STDERR,
527 		    gettext("%s does not exist."), libname);
528 		return (FAILURE);
529 	}
530 
531 	/* Print the policy for this library */
532 	rc = print_uef_policy(puent);
533 	free_uentry(puent);
534 
535 	return (rc);
536 }
537 
538 
539 /*
540  * Disable mechanisms for a user-level library
541  */
542 int
543 disable_uef_lib(char *libname, boolean_t rndflag, boolean_t allflag,
544     mechlist_t *marglist)
545 {
546 	uentry_t	*puent;
547 	int	rc;
548 
549 	if (libname == NULL) {
550 		/* should not happen */
551 		cryptoerror(LOG_STDERR, gettext("internal error."));
552 		cryptodebug("disable_uef_lib() - libname is NULL.");
553 		return (FAILURE);
554 	}
555 
556 	/* Get the provider entry from the pkcs11.conf file */
557 	if ((puent = getent_uef(libname)) == NULL) {
558 		cryptoerror(LOG_STDERR,
559 		    gettext("%s does not exist."), libname);
560 		return (FAILURE);
561 	}
562 
563 	/*
564 	 * Update the mechanism policy of this library entry, based on
565 	 * the current policy mode of the library and the mechanisms specified
566 	 * in CLI.
567 	 */
568 	if (allflag) {
569 		/*
570 		 * If disabling all, just need to clean up the policylist and
571 		 * set the flag_enabledlist flag to be B_TRUE.
572 		 */
573 		free_umechlist(puent->policylist);
574 		puent->policylist = NULL;
575 		puent->count = 0;
576 		puent->flag_enabledlist = B_TRUE;
577 		rc = SUCCESS;
578 	} else if (marglist != NULL) {
579 		if (puent->flag_enabledlist == B_TRUE) {
580 			/*
581 			 * The current default policy mode of this library
582 			 * is "all are disabled, except ...", so if a
583 			 * specified mechanism is in the exception list
584 			 * (the policylist), delete it from the policylist.
585 			 */
586 			rc = update_policylist(puent, marglist, DELETE_MODE);
587 		} else {
588 			/*
589 			 * The current default policy mode of this library
590 			 * is "all are enabled", so if a specified mechanism
591 			 * is not in the exception list (policylist), add
592 			 * it into the policylist.
593 			 */
594 			rc = update_policylist(puent, marglist, ADD_MODE);
595 		}
596 	} else if (!rndflag) {
597 		/* should not happen */
598 		cryptoerror(LOG_STDERR, gettext("internal error."));
599 		cryptodebug("disable_uef_lib() - wrong arguments.");
600 		return (FAILURE);
601 	}
602 
603 	if (rndflag)
604 		puent->flag_norandom = B_TRUE;
605 
606 	if (rc == FAILURE) {
607 		free_uentry(puent);
608 		return (FAILURE);
609 	}
610 
611 	/* Update the pkcs11.conf file with the updated entry */
612 	rc = update_pkcs11conf(puent);
613 	free_uentry(puent);
614 	return (rc);
615 }
616 
617 
618 /*
619  * Enable disabled mechanisms for a user-level library.
620  */
621 int
622 enable_uef_lib(char *libname, boolean_t rndflag, boolean_t allflag,
623     mechlist_t *marglist)
624 {
625 	uentry_t	*puent;
626 	int	rc = SUCCESS;
627 
628 	if (libname == NULL) {
629 		/* should not happen */
630 		cryptoerror(LOG_STDERR, gettext("internal error."));
631 		cryptodebug("enable_uef_lib() - libname is NULL.");
632 		return (FAILURE);
633 	}
634 
635 	/* Get the provider entry from the pkcs11.conf file */
636 	if ((puent = getent_uef(libname)) == NULL) {
637 		cryptoerror(LOG_STDERR,
638 		    gettext("%s does not exist."), libname);
639 		return (FAILURE);
640 	}
641 
642 	/*
643 	 * Update the mechanism policy of this library entry, based on
644 	 * the current policy mode of the library and the mechanisms
645 	 * specified in CLI.
646 	 */
647 	if (allflag) {
648 		/*
649 		 * If enabling all, what needs to be done are cleaning up the
650 		 * policylist and setting the "flag_enabledlist" flag to
651 		 * B_FALSE.
652 		 */
653 		free_umechlist(puent->policylist);
654 		puent->policylist = NULL;
655 		puent->count = 0;
656 		puent->flag_enabledlist = B_FALSE;
657 		rc = SUCCESS;
658 	} else if (marglist != NULL) {
659 		if (puent->flag_enabledlist == B_TRUE) {
660 			/*
661 			 * The current default policy mode of this library
662 			 * is "all are disabled, except ...", so if a
663 			 * specified mechanism is not in the exception list
664 			 * (policylist), add it.
665 			 */
666 			rc = update_policylist(puent, marglist, ADD_MODE);
667 		} else {
668 			/*
669 			 * The current default policy mode of this library
670 			 * is "all are enabled, except", so if a specified
671 			 * mechanism is in the exception list (policylist),
672 			 * delete it.
673 			 */
674 			rc = update_policylist(puent, marglist, DELETE_MODE);
675 		}
676 	} else if (!rndflag) {
677 		/* should not come here */
678 		cryptoerror(LOG_STDERR, gettext("internal error."));
679 		cryptodebug("enable_uef_lib() - wrong arguments.");
680 		return (FAILURE);
681 	}
682 
683 	if (rndflag)
684 		puent->flag_norandom = B_FALSE;
685 
686 	if (rc == FAILURE) {
687 		free_uentry(puent);
688 		return (FAILURE);
689 	}
690 
691 	/* Update the pkcs11.conf file with the updated entry */
692 	rc = update_pkcs11conf(puent);
693 	free_uentry(puent);
694 	return (rc);
695 }
696 
697 
698 /*
699  * Install a user-level library.
700  */
701 int
702 install_uef_lib(char *libname)
703 {
704 	uentry_t	*puent;
705 	struct stat 	statbuf;
706 	boolean_t	found;
707 	FILE	*pfile;
708 	FILE	*pfile_tmp;
709 	char	tmpfile_name[MAXPATHLEN];
710 	char	libpath[MAXPATHLEN];
711 	char	libbuf[MAXPATHLEN];
712 	char	*isa;
713 	char 	buffer[BUFSIZ];
714 	char 	*ptr;
715 	int	found_count;
716 	int	rc = SUCCESS;
717 
718 
719 	if (libname == NULL) {
720 		/* should not happen */
721 		cryptoerror(LOG_STDERR, gettext("internal error."));
722 		cryptodebug("install_uef_lib() - libname is NULL.");
723 		return (FAILURE);
724 	}
725 
726 	/* Check if the provider already exists in the framework */
727 	if ((puent = getent_uef(libname)) != NULL) {
728 		cryptoerror(LOG_STDERR, gettext("%s exists already."),
729 		    libname);
730 		free_uentry(puent);
731 		return (FAILURE);
732 	}
733 
734 	/*
735 	 * Check if the library exists in the system. if $ISA is in the
736 	 * path, only check the 32bit version.
737 	 */
738 	if (strlcpy(libbuf, libname, MAXPATHLEN) >= MAXPATHLEN) {
739 		cryptoerror(LOG_STDERR,
740 		    gettext("the provider name is too long - %s"), libname);
741 		return (FAILURE);
742 	}
743 
744 	if ((isa = strstr(libbuf, PKCS11_ISA)) != NULL) {
745 		*isa = '\000';
746 		isa += strlen(PKCS11_ISA);
747 		(void) snprintf(libpath, sizeof (libpath), "%s%s%s", libbuf,
748 		    "/", isa);
749 	} else {
750 		(void) strlcpy(libpath, libname, sizeof (libpath));
751 	}
752 
753 	/* Check if it is same as the framework library */
754 	if (strcmp(libpath, UEF_FRAME_LIB) == 0) {
755 		cryptoerror(LOG_STDERR, gettext(
756 		    "The framework library %s can not be installed."),
757 		    libname);
758 		return (FAILURE);
759 	}
760 
761 	if (stat(libpath, &statbuf) != 0) {
762 		cryptoerror(LOG_STDERR, gettext("%s not found"), libname);
763 		return (FAILURE);
764 	}
765 
766 	/* Need to add "\n" to libname for adding into the config file */
767 	if (strlcat(libname, "\n", MAXPATHLEN) >= MAXPATHLEN) {
768 		cryptoerror(LOG_STDERR, gettext(
769 		    "can not install %s; the name is too long."), libname);
770 		return (FAILURE);
771 	}
772 
773 	if ((pfile = fopen(_PATH_PKCS11_CONF, "r+")) == NULL) {
774 		err = errno;
775 		cryptoerror(LOG_STDERR,
776 		    gettext("failed to update the configuration - %s"),
777 		    strerror(err));
778 		cryptodebug("failed to open %s for write.", _PATH_PKCS11_CONF);
779 		return (FAILURE);
780 	}
781 
782 	if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
783 		err = errno;
784 		cryptoerror(LOG_STDERR,
785 		    gettext("failed to lock the configuration - %s"),
786 		    strerror(err));
787 		(void) fclose(pfile);
788 		return (FAILURE);
789 	}
790 
791 	/*
792 	 * Create a temporary file in the /etc/crypto directory.
793 	 */
794 	(void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
795 	if (mkstemp(tmpfile_name) == -1) {
796 		err = errno;
797 		cryptoerror(LOG_STDERR,
798 		    gettext("failed to create a temporary file - %s"),
799 		    strerror(err));
800 		(void) fclose(pfile);
801 		return (FAILURE);
802 	}
803 
804 	if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
805 		err = errno;
806 		cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
807 		    tmpfile_name, strerror(err));
808 		(void) fclose(pfile);
809 		return (FAILURE);
810 	}
811 
812 	/*
813 	 * Loop thru the config file. If the file was reserved within a
814 	 * package bracket, just uncomment it.  Other wise, append it at
815 	 * the end.  The resulting file will be saved in the temp file first.
816 	 */
817 	found_count = 0;
818 	rc = SUCCESS;
819 	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
820 		found = B_FALSE;
821 		if (buffer[0] == '#') {
822 			ptr = buffer;
823 			ptr++;
824 			if (strcmp(libname, ptr) == 0) {
825 				found = B_TRUE;
826 				found_count++;
827 			}
828 		}
829 
830 		if (found == B_FALSE) {
831 			if (fputs(buffer, pfile_tmp) == EOF) {
832 				rc = FAILURE;
833 			}
834 		} else {
835 			if (found_count == 1) {
836 				if (fputs(ptr, pfile_tmp) == EOF) {
837 					rc = FAILURE;
838 				}
839 			} else {
840 				/*
841 				 * Found a second entry with #libname.
842 				 * Should not happen. The pkcs11.conf file
843 				 * is corrupted. Give a warning and skip
844 				 * this entry.
845 				 */
846 				cryptoerror(LOG_STDERR, gettext(
847 				    "(Warning) Found an additional reserved "
848 				    "entry for %s."), libname);
849 			}
850 		}
851 
852 		if (rc == FAILURE) {
853 			break;
854 		}
855 	}
856 
857 	if (rc == FAILURE) {
858 		cryptoerror(LOG_STDERR, gettext("write error."));
859 		(void) fclose(pfile);
860 		(void) fclose(pfile_tmp);
861 		if (unlink(tmpfile_name) != 0) {
862 			err = errno;
863 			cryptoerror(LOG_STDERR, gettext(
864 			    "(Warning) failed to remove %s: %s"), tmpfile_name,
865 			    strerror(err));
866 		}
867 		return (FAILURE);
868 	}
869 
870 	if (found_count == 0) {
871 		/*
872 		 * This libname was not in package before, append it to the
873 		 * end of the temp file.
874 		 */
875 		if (fputs(libname, pfile_tmp) == EOF) {
876 			err = errno;
877 			cryptoerror(LOG_STDERR, gettext(
878 			    "failed to write to %s: %s"), tmpfile_name,
879 			    strerror(err));
880 			(void) fclose(pfile);
881 			(void) fclose(pfile_tmp);
882 			if (unlink(tmpfile_name) != 0) {
883 				err = errno;
884 				cryptoerror(LOG_STDERR, gettext(
885 				    "(Warning) failed to remove %s: %s"),
886 				    tmpfile_name, strerror(err));
887 			}
888 			return (FAILURE);
889 		}
890 	}
891 
892 	(void) fclose(pfile);
893 	if (fclose(pfile_tmp) != 0) {
894 		err = errno;
895 		cryptoerror(LOG_STDERR,
896 		    gettext("failed to close %s: %s"), tmpfile_name,
897 		    strerror(err));
898 		return (FAILURE);
899 	}
900 
901 	if (rename(tmpfile_name, _PATH_PKCS11_CONF) == -1) {
902 		err = errno;
903 		cryptoerror(LOG_STDERR,
904 		    gettext("failed to update the configuration - %s"),
905 		    strerror(err));
906 		cryptodebug("failed to rename %s to %s: %s", tmpfile_name,
907 		    _PATH_PKCS11_CONF, strerror(err));
908 		rc = FAILURE;
909 	} else if (chmod(_PATH_PKCS11_CONF,
910 	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
911 		err = errno;
912 		cryptoerror(LOG_STDERR,
913 		    gettext("failed to update the configuration - %s"),
914 		    strerror(err));
915 		cryptodebug("failed to chmod to %s: %s", _PATH_PKCS11_CONF,
916 		    strerror(err));
917 		rc = FAILURE;
918 	} else {
919 		rc = SUCCESS;
920 	}
921 
922 	if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
923 		err = errno;
924 		cryptoerror(LOG_STDERR, gettext(
925 		    "(Warning) failed to remove %s: %s"), tmpfile_name,
926 		    strerror(err));
927 	}
928 
929 	return (rc);
930 }
931 
932 
933 /*
934  * Uninstall a user-level library.
935  */
936 int
937 uninstall_uef_lib(char *libname)
938 {
939 	uentry_t	*puent;
940 	FILE	*pfile;
941 	FILE	*pfile_tmp;
942 	char 	buffer[BUFSIZ];
943 	char 	buffer2[BUFSIZ];
944 	char	tmpfile_name[MAXPATHLEN];
945 	char 	*name;
946 	boolean_t	found;
947 	boolean_t	in_package;
948 	int	len;
949 	int	rc = SUCCESS;
950 
951 	if (libname == NULL) {
952 		/* should not happen */
953 		cryptoerror(LOG_STDERR, gettext("internal error."));
954 		cryptodebug("uninstall_uef_lib() - libname is NULL.");
955 		return (FAILURE);
956 	}
957 
958 	/* Check if the provider exists */
959 	if ((puent = getent_uef(libname)) == NULL) {
960 		cryptoerror(LOG_STDERR,
961 		    gettext("%s does not exist."), libname);
962 		return (FAILURE);
963 	}
964 	free_uentry(puent);
965 
966 	/*  Open the pkcs11.conf file and lock it */
967 	if ((pfile = fopen(_PATH_PKCS11_CONF, "r+")) == NULL) {
968 		err = errno;
969 		cryptoerror(LOG_STDERR,
970 		    gettext("failed to update the configuration - %s"),
971 		    strerror(err));
972 		cryptodebug("failed to open %s for write.", _PATH_PKCS11_CONF);
973 		return (FAILURE);
974 	}
975 
976 	if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
977 		err = errno;
978 		cryptoerror(LOG_STDERR,
979 		    gettext("failed to lock the configuration - %s"),
980 		    strerror(err));
981 		(void) fclose(pfile);
982 		return (FAILURE);
983 	}
984 
985 	/*
986 	 * Create a temporary file in the /etc/crypto directory to save
987 	 * the new configuration file first.
988 	 */
989 	(void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
990 	if (mkstemp(tmpfile_name) == -1) {
991 		err = errno;
992 		cryptoerror(LOG_STDERR,
993 		    gettext("failed to create a temporary file - %s"),
994 		    strerror(err));
995 		(void) fclose(pfile);
996 		return (FAILURE);
997 	}
998 
999 	if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
1000 		err = errno;
1001 		cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
1002 		    tmpfile_name, strerror(err));
1003 		if (unlink(tmpfile_name) != 0) {
1004 			err = errno;
1005 			cryptoerror(LOG_STDERR, gettext(
1006 			    "(Warning) failed to remove %s: %s"),
1007 			    tmpfile_name, strerror(err));
1008 		}
1009 		(void) fclose(pfile);
1010 		return (FAILURE);
1011 	}
1012 
1013 
1014 	/*
1015 	 * Loop thru the config file.  If the library to be uninstalled
1016 	 * is in a package, just comment it off.
1017 	 */
1018 	in_package = B_FALSE;
1019 	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
1020 		found = B_FALSE;
1021 		if (!(buffer[0] == ' ' || buffer[0] == '\n' ||
1022 		    buffer[0] == '\t')) {
1023 			if (strstr(buffer, " Start ") != NULL) {
1024 				in_package = B_TRUE;
1025 			} else if (strstr(buffer, " End ") != NULL) {
1026 				in_package = B_FALSE;
1027 			} else if (buffer[0] != '#') {
1028 				(void) strlcpy(buffer2, buffer, BUFSIZ);
1029 
1030 				/* get rid of trailing '\n' */
1031 				len = strlen(buffer2);
1032 				if (buffer2[len-1] == '\n') {
1033 					len--;
1034 				}
1035 				buffer2[len] = '\0';
1036 
1037 				if ((name = strtok(buffer2, SEP_COLON))
1038 				    == NULL) {
1039 					rc = FAILURE;
1040 					break;
1041 				} else if (strcmp(libname, name) == 0) {
1042 					found = B_TRUE;
1043 				}
1044 			}
1045 		}
1046 
1047 		if (found) {
1048 			if (in_package) {
1049 				(void) snprintf(buffer2, sizeof (buffer2),
1050 				    "%s%s%s", "#", libname, "\n");
1051 				if (fputs(buffer2, pfile_tmp) == EOF) {
1052 					rc = FAILURE;
1053 				}
1054 			}
1055 		} else {
1056 			if (fputs(buffer, pfile_tmp) == EOF) {
1057 				rc = FAILURE;
1058 			}
1059 		}
1060 
1061 		if (rc == FAILURE) {
1062 			break;
1063 		}
1064 	}
1065 
1066 	if (rc == FAILURE) {
1067 		cryptoerror(LOG_STDERR, gettext("write error."));
1068 		(void) fclose(pfile);
1069 		(void) fclose(pfile_tmp);
1070 		if (unlink(tmpfile_name) != 0) {
1071 			err = errno;
1072 			cryptoerror(LOG_STDERR, gettext(
1073 			    "(Warning) failed to remove %s: %s"),
1074 			    tmpfile_name, strerror(err));
1075 		}
1076 		return (FAILURE);
1077 	}
1078 
1079 	(void) fclose(pfile);
1080 	if (fclose(pfile_tmp) != 0) {
1081 		err = errno;
1082 		cryptoerror(LOG_STDERR,
1083 		    gettext("failed to close a temporary file - %s"),
1084 		    strerror(err));
1085 		return (FAILURE);
1086 	}
1087 
1088 	/* Now update the real config file */
1089 	if (rename(tmpfile_name, _PATH_PKCS11_CONF) == -1) {
1090 		err = errno;
1091 		cryptoerror(LOG_STDERR,
1092 		    gettext("failed to update the configuration - %s"),
1093 		    strerror(err));
1094 		cryptodebug("failed to rename %s to %s: %s", tmpfile,
1095 		    _PATH_PKCS11_CONF, strerror(err));
1096 		rc = FAILURE;
1097 	} else if (chmod(_PATH_PKCS11_CONF,
1098 	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
1099 		err = errno;
1100 		cryptoerror(LOG_STDERR,
1101 		    gettext("failed to update the configuration - %s"),
1102 		    strerror(err));
1103 		cryptodebug("failed to chmod to %s: %s", _PATH_PKCS11_CONF,
1104 		    strerror(err));
1105 		rc = FAILURE;
1106 	} else {
1107 		rc = SUCCESS;
1108 	}
1109 
1110 	if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
1111 		err = errno;
1112 		cryptoerror(LOG_STDERR, gettext(
1113 		    "(Warning) failed to remove %s: %s"),
1114 		    tmpfile_name, strerror(err));
1115 	}
1116 
1117 	return (rc);
1118 }
1119 
1120 
1121 int
1122 display_policy(uentry_t *puent)
1123 {
1124 	CK_MECHANISM_TYPE	mech_id;
1125 	const char		*mech_name;
1126 	umechlist_t		*ptr;
1127 
1128 	if (puent == NULL) {
1129 		return (SUCCESS);
1130 	}
1131 
1132 	if (puent->flag_enabledlist == B_FALSE) {
1133 		(void) printf(gettext("%s: all mechanisms are enabled"),
1134 		    puent->name);
1135 		ptr = puent->policylist;
1136 		if (ptr == NULL) {
1137 			(void) printf(".");
1138 		} else {
1139 			(void) printf(gettext(", except "));
1140 			while (ptr != NULL) {
1141 				mech_id = strtoul(ptr->name, NULL, 0);
1142 				if (mech_id & CKO_VENDOR_DEFINED) {
1143 					/* vendor defined mechanism */
1144 					(void) printf("%s", ptr->name);
1145 				} else {
1146 					if (mech_id > CKM_VENDOR_DEFINED) {
1147 						(void) printf("%#lx", mech_id);
1148 					} else {
1149 						mech_name = pkcs11_mech2str(
1150 						    mech_id);
1151 						if (mech_name == NULL) {
1152 							return (FAILURE);
1153 						}
1154 						(void) printf("%s", mech_name);
1155 					}
1156 				}
1157 
1158 				ptr = ptr->next;
1159 				if (ptr == NULL) {
1160 					(void) printf(".");
1161 				} else {
1162 					(void) printf(",");
1163 				}
1164 			}
1165 		}
1166 	} else { /* puent->flag_enabledlist == B_TRUE */
1167 		(void) printf(gettext("%s: all mechanisms are disabled"),
1168 		    puent->name);
1169 		ptr = puent->policylist;
1170 		if (ptr == NULL) {
1171 			(void) printf(".");
1172 		} else {
1173 			(void) printf(gettext(", except "));
1174 			while (ptr != NULL) {
1175 				mech_id = strtoul(ptr->name, NULL, 0);
1176 				if (mech_id & CKO_VENDOR_DEFINED) {
1177 					/* vendor defined mechanism */
1178 					(void) printf("%s", ptr->name);
1179 				} else {
1180 					mech_name = pkcs11_mech2str(mech_id);
1181 					if (mech_name == NULL) {
1182 						return (FAILURE);
1183 					}
1184 					(void) printf("%s", mech_name);
1185 				}
1186 				ptr = ptr->next;
1187 				if (ptr == NULL) {
1188 					(void) printf(".");
1189 				} else {
1190 					(void) printf(",");
1191 				}
1192 			}
1193 		}
1194 	}
1195 	return (SUCCESS);
1196 }
1197 
1198 
1199 
1200 /*
1201  * Print out the mechanism policy for a user-level provider pointed by puent.
1202  */
1203 int
1204 print_uef_policy(uentry_t *puent)
1205 {
1206 	flag_val_t rng_flag;
1207 
1208 	if (puent == NULL) {
1209 		return (FAILURE);
1210 	}
1211 
1212 	rng_flag = NO_RNG;
1213 	if (list_mechlist_for_lib(puent->name, NULL, &rng_flag, B_TRUE,
1214 	    B_FALSE, B_FALSE) != SUCCESS) {
1215 		cryptoerror(LOG_STDERR,
1216 		    gettext("%s internal error."), puent->name);
1217 		return (FAILURE);
1218 	}
1219 
1220 	if (display_policy(puent) != SUCCESS) {
1221 		goto failed_exit;
1222 	}
1223 
1224 
1225 	if (puent->flag_norandom == B_TRUE)
1226 		/*
1227 		 * TRANSLATION_NOTE:
1228 		 * "random" is a keyword and not to be translated.
1229 		 */
1230 		(void) printf(gettext(" %s is disabled."), "random");
1231 	else {
1232 		if (rng_flag == HAS_RNG)
1233 			/*
1234 			 * TRANSLATION_NOTE:
1235 			 * "random" is a keyword and not to be translated.
1236 			 */
1237 			(void) printf(gettext(" %s is enabled."), "random");
1238 	}
1239 	(void) printf("\n");
1240 
1241 	return (SUCCESS);
1242 
1243 failed_exit:
1244 
1245 	(void) printf(gettext("\nout of memory.\n"));
1246 	return (FAILURE);
1247 }
1248 
1249 
1250 /*
1251  * Check if the mechanism is in the mechanism list.
1252  */
1253 static boolean_t
1254 is_in_policylist(midstr_t mechname, umechlist_t *plist)
1255 {
1256 	boolean_t found = B_FALSE;
1257 
1258 	if (mechname == NULL) {
1259 		return (B_FALSE);
1260 	}
1261 
1262 	while (plist != NULL) {
1263 		if (strcmp(plist->name, mechname) == 0) {
1264 			found = B_TRUE;
1265 			break;
1266 		}
1267 		plist = plist->next;
1268 	}
1269 
1270 	return (found);
1271 }
1272 
1273 
1274 /*
1275  * Update the pkcs11.conf file with the updated entry.
1276  */
1277 int
1278 update_pkcs11conf(uentry_t *puent)
1279 {
1280 	FILE	*pfile;
1281 	FILE	*pfile_tmp;
1282 	char buffer[BUFSIZ];
1283 	char buffer2[BUFSIZ];
1284 	char tmpfile_name[MAXPATHLEN];
1285 	char *name;
1286 	char *str;
1287 	int len;
1288 	int rc = SUCCESS;
1289 	boolean_t found;
1290 
1291 	if (puent == NULL) {
1292 		cryptoerror(LOG_STDERR, gettext("internal error."));
1293 		return (FAILURE);
1294 	}
1295 
1296 	/* Open the pkcs11.conf file */
1297 	if ((pfile = fopen(_PATH_PKCS11_CONF, "r+")) == NULL) {
1298 		err = errno;
1299 		cryptoerror(LOG_STDERR,
1300 		    gettext("failed to update the configuration - %s"),
1301 		    strerror(err));
1302 		cryptodebug("failed to open %s for write.", _PATH_PKCS11_CONF);
1303 		return (FAILURE);
1304 	}
1305 
1306 	/* Lock the pkcs11.conf file */
1307 	if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
1308 		err = errno;
1309 		cryptoerror(LOG_STDERR,
1310 		    gettext("failed to update the configuration - %s"),
1311 		    strerror(err));
1312 		(void) fclose(pfile);
1313 		return (FAILURE);
1314 	}
1315 
1316 	/*
1317 	 * Create a temporary file in the /etc/crypto directory to save
1318 	 * updated configuration file first.
1319 	 */
1320 	(void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
1321 	if (mkstemp(tmpfile_name) == -1) {
1322 		err = errno;
1323 		cryptoerror(LOG_STDERR,
1324 		    gettext("failed to create a temporary file - %s"),
1325 		    strerror(err));
1326 		(void) fclose(pfile);
1327 		return (FAILURE);
1328 	}
1329 
1330 	if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
1331 		err = errno;
1332 		cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
1333 		    tmpfile_name, strerror(err));
1334 		if (unlink(tmpfile_name) != 0) {
1335 			err = errno;
1336 			cryptoerror(LOG_STDERR, gettext(
1337 			    "(Warning) failed to remove %s: %s"),
1338 			    tmpfile_name, strerror(err));
1339 		}
1340 		(void) fclose(pfile);
1341 		return (FAILURE);
1342 	}
1343 
1344 
1345 	/*
1346 	 * Loop thru entire pkcs11.conf file, update the entry to be
1347 	 * updated and save the updated file to the temporary file first.
1348 	 */
1349 	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
1350 		found = B_FALSE;
1351 		if (!(buffer[0] == '#' || buffer[0] == ' ' ||
1352 		    buffer[0] == '\n'|| buffer[0] == '\t')) {
1353 			/*
1354 			 * Get the provider name from this line and check if
1355 			 * this is the entry to be updated. Note: can not use
1356 			 * "buffer" directly because strtok will change its
1357 			 * value.
1358 			 */
1359 			(void) strlcpy(buffer2, buffer, BUFSIZ);
1360 
1361 			/* get rid of trailing '\n' */
1362 			len = strlen(buffer2);
1363 			if (buffer2[len-1] == '\n') {
1364 				len--;
1365 			}
1366 			buffer2[len] = '\0';
1367 
1368 			if ((name = strtok(buffer2, SEP_COLON)) == NULL) {
1369 				rc = FAILURE;
1370 				break;
1371 			} else if (strcmp(puent->name, name) == 0) {
1372 				found = B_TRUE;
1373 			}
1374 		}
1375 
1376 		if (found) {
1377 			/*
1378 			 * This is the entry to be modified, get the updated
1379 			 * string.
1380 			 */
1381 			if ((str = uent2str(puent)) == NULL) {
1382 				rc = FAILURE;
1383 				break;
1384 			} else {
1385 				(void) strlcpy(buffer, str, BUFSIZ);
1386 				free(str);
1387 			}
1388 		}
1389 
1390 		if (fputs(buffer, pfile_tmp) == EOF) {
1391 			err = errno;
1392 			cryptoerror(LOG_STDERR, gettext(
1393 			    "failed to write to a temp file: %s."),
1394 			    strerror(err));
1395 			rc = FAILURE;
1396 			break;
1397 		}
1398 	}
1399 
1400 	if (rc == FAILURE) {
1401 		(void) fclose(pfile);
1402 		(void) fclose(pfile_tmp);
1403 		if (unlink(tmpfile_name) != 0) {
1404 			err = errno;
1405 			cryptoerror(LOG_STDERR, gettext(
1406 			    "(Warning) failed to remove %s: %s"),
1407 			    tmpfile_name, strerror(err));
1408 		}
1409 		return (FAILURE);
1410 	}
1411 
1412 	(void) fclose(pfile);
1413 	if (fclose(pfile_tmp) != 0) {
1414 		err = errno;
1415 		cryptoerror(LOG_STDERR,
1416 		    gettext("failed to close %s: %s"), tmpfile_name,
1417 		    strerror(err));
1418 		return (FAILURE);
1419 	}
1420 
1421 	/* Copy the temporary file to the pkcs11.conf file */
1422 	if (rename(tmpfile_name, _PATH_PKCS11_CONF) == -1) {
1423 		err = errno;
1424 		cryptoerror(LOG_STDERR,
1425 		    gettext("failed to update the configuration - %s"),
1426 		    strerror(err));
1427 		cryptodebug("failed to rename %s to %s: %s", tmpfile_name,
1428 		    _PATH_PKCS11_CONF, strerror(err));
1429 		rc = FAILURE;
1430 	} else if (chmod(_PATH_PKCS11_CONF,
1431 	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
1432 		err = errno;
1433 		cryptoerror(LOG_STDERR,
1434 		    gettext("failed to update the configuration - %s"),
1435 		    strerror(err));
1436 		cryptodebug("failed to chmod to %s: %s", _PATH_PKCS11_CONF,
1437 		    strerror(err));
1438 		rc = FAILURE;
1439 	} else {
1440 		rc = SUCCESS;
1441 	}
1442 
1443 	if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
1444 		err = errno;
1445 		cryptoerror(LOG_STDERR, gettext(
1446 		    "(Warning) failed to remove %s: %s"),
1447 		    tmpfile_name, strerror(err));
1448 	}
1449 
1450 	return (rc);
1451 }
1452 
1453 
1454 /*
1455  * Convert an uentry to a character string
1456  */
1457 static char *
1458 uent2str(uentry_t *puent)
1459 {
1460 	umechlist_t	*phead;
1461 	boolean_t tok1_present = B_FALSE;
1462 	char *buf;
1463 	char blank_buf[128];
1464 
1465 	if (puent == NULL) {
1466 		cryptoerror(LOG_STDERR, gettext("internal error."));
1467 		return (NULL);
1468 	}
1469 
1470 	buf = malloc(BUFSIZ);
1471 	if (buf == NULL) {
1472 		cryptoerror(LOG_STDERR, gettext("out of memory."));
1473 		return (NULL);
1474 	}
1475 
1476 	/* convert the library name */
1477 	if (strlcpy(buf, puent->name, BUFSIZ) >= BUFSIZ) {
1478 		free(buf);
1479 		return (NULL);
1480 	}
1481 
1482 
1483 	/* convert the enabledlist or the disabledlist */
1484 	if (puent->flag_enabledlist == B_TRUE) {
1485 		if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) {
1486 			free(buf);
1487 			return (NULL);
1488 		}
1489 
1490 		if (strlcat(buf, EF_ENABLED, BUFSIZ) >= BUFSIZ) {
1491 			free(buf);
1492 			return (NULL);
1493 		}
1494 
1495 		phead = puent->policylist;
1496 		while (phead != NULL) {
1497 			if (strlcat(buf, phead->name, BUFSIZ) >= BUFSIZ) {
1498 				free(buf);
1499 				return (NULL);
1500 			}
1501 
1502 			phead = phead->next;
1503 			if (phead != NULL) {
1504 				if (strlcat(buf, SEP_COMMA, BUFSIZ)
1505 				    >= BUFSIZ) {
1506 					free(buf);
1507 					return (NULL);
1508 				}
1509 			}
1510 		}
1511 		tok1_present = B_TRUE;
1512 	} else if (puent->policylist != NULL) {
1513 		if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) {
1514 			free(buf);
1515 			return (NULL);
1516 		}
1517 
1518 		if (strlcat(buf, EF_DISABLED, BUFSIZ) >= BUFSIZ) {
1519 			free(buf);
1520 			return (NULL);
1521 		}
1522 		phead = puent->policylist;
1523 		while (phead != NULL) {
1524 			if (strlcat(buf, phead->name, BUFSIZ) >= BUFSIZ) {
1525 				free(buf);
1526 				return (NULL);
1527 			}
1528 
1529 			phead = phead->next;
1530 			if (phead != NULL) {
1531 				if (strlcat(buf, SEP_COMMA, BUFSIZ)
1532 				    >= BUFSIZ) {
1533 					free(buf);
1534 					return (NULL);
1535 				}
1536 			}
1537 		}
1538 		tok1_present = B_TRUE;
1539 	}
1540 
1541 	if (puent->flag_norandom == B_TRUE) {
1542 		if (strlcat(buf, (tok1_present ? SEP_SEMICOLON : SEP_COLON),
1543 		    BUFSIZ) >= BUFSIZ) {
1544 			free(buf);
1545 			return (NULL);
1546 		}
1547 
1548 		if (strlcat(buf, EF_NORANDOM, BUFSIZ) >= BUFSIZ) {
1549 			free(buf);
1550 			return (NULL);
1551 		}
1552 	}
1553 
1554 	if (strcmp(puent->name, METASLOT_KEYWORD) == 0) {
1555 
1556 		/* write the metaslot_status= value */
1557 		if (strlcat(buf, (tok1_present ? SEP_SEMICOLON : SEP_COLON),
1558 		    BUFSIZ) >= BUFSIZ) {
1559 			free(buf);
1560 			return (NULL);
1561 		}
1562 
1563 		if (strlcat(buf, METASLOT_STATUS, BUFSIZ) >= BUFSIZ) {
1564 			free(buf);
1565 			return (NULL);
1566 		}
1567 
1568 		if (puent->flag_metaslot_enabled) {
1569 			if (strlcat(buf, METASLOT_ENABLED, BUFSIZ) >= BUFSIZ) {
1570 				free(buf);
1571 				return (NULL);
1572 			}
1573 		} else {
1574 			if (strlcat(buf, METASLOT_DISABLED, BUFSIZ)
1575 			    >= BUFSIZ) {
1576 				free(buf);
1577 				return (NULL);
1578 			}
1579 		}
1580 
1581 		if (!tok1_present) {
1582 			tok1_present = B_TRUE;
1583 		}
1584 
1585 		if (strlcat(buf, SEP_SEMICOLON, BUFSIZ) >= BUFSIZ) {
1586 			free(buf);
1587 			return (NULL);
1588 		}
1589 
1590 		if (strlcat(buf, METASLOT_AUTO_KEY_MIGRATE, BUFSIZ) >= BUFSIZ) {
1591 			free(buf);
1592 			return (NULL);
1593 		}
1594 
1595 		if (puent->flag_metaslot_auto_key_migrate) {
1596 			if (strlcat(buf, METASLOT_ENABLED, BUFSIZ) >= BUFSIZ) {
1597 				free(buf);
1598 				return (NULL);
1599 			}
1600 		} else {
1601 			if (strlcat(buf, METASLOT_DISABLED, BUFSIZ) >= BUFSIZ) {
1602 				free(buf);
1603 				return (NULL);
1604 			}
1605 		}
1606 
1607 		bzero(blank_buf, sizeof (blank_buf));
1608 
1609 		/* write metaslot_token= if specified */
1610 		if (memcmp(puent->metaslot_ks_token, blank_buf,
1611 		    TOKEN_LABEL_SIZE) != 0) {
1612 			/* write the metaslot_status= value */
1613 			if (strlcat(buf, (tok1_present ?
1614 			    SEP_SEMICOLON : SEP_COLON), BUFSIZ) >= BUFSIZ) {
1615 				free(buf);
1616 				return (NULL);
1617 			}
1618 
1619 			if (strlcat(buf, METASLOT_TOKEN, BUFSIZ) >= BUFSIZ) {
1620 				free(buf);
1621 				return (NULL);
1622 			}
1623 
1624 			if (strlcat(buf,
1625 			    (const char *)puent->metaslot_ks_token, BUFSIZ)
1626 			    >= BUFSIZ) {
1627 				free(buf);
1628 				return (NULL);
1629 			}
1630 		}
1631 
1632 		/* write metaslot_slot= if specified */
1633 		if (memcmp(puent->metaslot_ks_slot, blank_buf,
1634 		    SLOT_DESCRIPTION_SIZE) != 0) {
1635 			/* write the metaslot_status= value */
1636 			if (strlcat(buf, (tok1_present ?
1637 			    SEP_SEMICOLON : SEP_COLON), BUFSIZ) >= BUFSIZ) {
1638 				free(buf);
1639 				return (NULL);
1640 			}
1641 
1642 			if (strlcat(buf, METASLOT_SLOT, BUFSIZ) >= BUFSIZ) {
1643 				free(buf);
1644 				return (NULL);
1645 			}
1646 
1647 			if (strlcat(buf,
1648 			    (const char *)puent->metaslot_ks_slot, BUFSIZ)
1649 			    >= BUFSIZ) {
1650 				free(buf);
1651 				return (NULL);
1652 			}
1653 		}
1654 	}
1655 
1656 	if (strlcat(buf, "\n", BUFSIZ) >= BUFSIZ) {
1657 		free(buf);
1658 		return (NULL);
1659 	}
1660 
1661 	return (buf);
1662 }
1663 
1664 
1665 /*
1666  * This function updates the default policy mode and the policy exception list
1667  * for a user-level provider based on the mechanism specified in the disable
1668  * or enable subcommand and the update mode.   This function is called by the
1669  * enable_uef_lib() or disable_uef_lib().
1670  */
1671 int
1672 update_policylist(uentry_t *puent, mechlist_t *marglist, int update_mode)
1673 {
1674 	CK_MECHANISM_TYPE mech_type;
1675 	midstr_t	midname;
1676 	umechlist_t	*phead;
1677 	umechlist_t	*pcur;
1678 	umechlist_t	*pumech;
1679 	boolean_t	found;
1680 	int	rc = SUCCESS;
1681 
1682 	if ((puent == NULL) || (marglist == NULL)) {
1683 		/* should not happen */
1684 		cryptoerror(LOG_STDERR, gettext("internal error."));
1685 		cryptodebug("update_policylist()- puent or marglist is NULL.");
1686 		return (FAILURE);
1687 	}
1688 
1689 	if ((update_mode != ADD_MODE) && (update_mode != DELETE_MODE)) {
1690 		/* should not happen */
1691 		cryptoerror(LOG_STDERR, gettext("internal error."));
1692 		cryptodebug("update_policylist() - update_mode is incorrect.");
1693 		return (FAILURE);
1694 	}
1695 
1696 	/*
1697 	 * For each mechanism operand, get its mechanism type first.
1698 	 * If fails to get the mechanism type, the mechanism operand must be
1699 	 * invalid, gives an warning and ignore it. Otherwise,
1700 	 * - convert the mechanism type to the internal representation (hex)
1701 	 *   in the pkcs11.conf file
1702 	 * - If update_mode == DELETE_MODE,
1703 	 *	If the mechanism is in the policy list, delete it.
1704 	 *	If the mechanism is not in the policy list, do nothing.
1705 	 * - If update_mode == ADD_MODE,
1706 	 *	If the mechanism is not in the policy list, add it.
1707 	 *	If the mechanism is in the policy list already, do nothing.
1708 	 */
1709 	while (marglist) {
1710 		if (pkcs11_str2mech(marglist->name, &mech_type) != CKR_OK) {
1711 			/*
1712 			 * This mechanism is not a valid PKCS11 mechanism,
1713 			 * give warning and ignore it.
1714 			 */
1715 			cryptoerror(LOG_STDERR, gettext(
1716 			    "(Warning) %s is not a valid PKCS#11 mechanism."),
1717 			    marglist->name);
1718 			rc = FAILURE;
1719 		} else {
1720 			(void) snprintf(midname, sizeof (midname), "%#010x",
1721 			    (int)mech_type);
1722 			if (update_mode == DELETE_MODE) {
1723 				found = B_FALSE;
1724 				phead = pcur = puent->policylist;
1725 				while (!found && pcur) {
1726 					if (strcmp(pcur->name, midname) == 0) {
1727 						found = B_TRUE;
1728 					} else {
1729 						phead = pcur;
1730 						pcur = pcur->next;
1731 					}
1732 				}
1733 
1734 				if (found) {
1735 					if (phead == pcur) {
1736 						puent->policylist =
1737 						    puent->policylist->next;
1738 						free(pcur);
1739 					} else {
1740 						phead->next = pcur->next;
1741 						free(pcur);
1742 					}
1743 					puent->count--;
1744 					if (puent->count == 0) {
1745 						puent->policylist = NULL;
1746 					}
1747 				}
1748 			} else if (update_mode == ADD_MODE) {
1749 				if (!is_in_policylist(midname,
1750 				    puent->policylist)) {
1751 					pumech = create_umech(midname);
1752 					if (pumech == NULL) {
1753 						rc = FAILURE;
1754 						break;
1755 					}
1756 					phead = puent->policylist;
1757 					puent->policylist = pumech;
1758 					pumech->next = phead;
1759 					puent->count++;
1760 				}
1761 			}
1762 		}
1763 		marglist = marglist->next;
1764 	}
1765 
1766 	return (rc);
1767 }
1768 
1769 /*
1770  * Open a session to the given slot and check if we can do
1771  * random numbers by asking for one byte.
1772  */
1773 static boolean_t
1774 check_random(CK_SLOT_ID slot_id, CK_FUNCTION_LIST_PTR prov_funcs)
1775 {
1776 	CK_RV rv;
1777 	CK_SESSION_HANDLE hSession;
1778 	CK_BYTE test_byte;
1779 	CK_BYTE_PTR test_byte_ptr = &test_byte;
1780 
1781 	rv = prov_funcs->C_OpenSession(slot_id, CKF_SERIAL_SESSION,
1782 	    NULL_PTR, NULL, &hSession);
1783 	if (rv != CKR_OK)
1784 		return (B_FALSE);
1785 
1786 	/* We care only about the return value */
1787 	rv = prov_funcs->C_GenerateRandom(hSession, test_byte_ptr,
1788 	    sizeof (test_byte));
1789 	(void) prov_funcs->C_CloseSession(hSession);
1790 
1791 	/*
1792 	 * These checks are purely to determine whether the slot can do
1793 	 * random numbers. So, we don't check whether the routine
1794 	 * succeeds. The reason we check for CKR_RANDOM_NO_RNG also is that
1795 	 * this error effectively means CKR_FUNCTION_NOT_SUPPORTED.
1796 	 */
1797 	if (rv != CKR_FUNCTION_NOT_SUPPORTED && rv != CKR_RANDOM_NO_RNG)
1798 		return (B_TRUE);
1799 	else
1800 		return (B_FALSE);
1801 }
1802 
1803 void
1804 display_verbose_mech_header()
1805 {
1806 	(void) printf("%28s %s", " ", HDR1);
1807 	(void) printf("%28s %s", " ", HDR2);
1808 	(void) printf("%28s %s", " ", HDR3);
1809 	(void) printf("%28s %s", " ", HDR4);
1810 	(void) printf("%28s %s", " ", HDR5);
1811 	(void) printf("%28s %s", " ", HDR6);
1812 	(void) printf("%-28.28s %s", gettext("mechanism name"), HDR7);
1813 	/*
1814 	 * TRANSLATION_NOTE:
1815 	 * Strictly for appearance's sake, the first header line should be
1816 	 * as long as the length of the translated text above.  The format
1817 	 * lengths should all match too.
1818 	 */
1819 	(void) printf("%28s ---- ---- "
1820 	    "-  -  -  -  -  -  -  -  -  -  -  -  -  -\n",
1821 	    gettext("----------------------------"));
1822 }
1823