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