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