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