xref: /illumos-gate/usr/src/cmd/cmd-crypto/cryptoadm/cryptoadm.c (revision 069e6b7e31ba5dcbc5441b98af272714d9a5455c)
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 /*
26  * Copyright (c) 2018, Joyent, Inc.
27  */
28 
29 #include <fcntl.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <strings.h>
33 #include <unistd.h>
34 #include <locale.h>
35 #include <libgen.h>
36 #include <sys/types.h>
37 #include <zone.h>
38 #include <sys/crypto/ioctladmin.h>
39 #include <cryptoutil.h>
40 #include "cryptoadm.h"
41 
42 #define	REQ_ARG_CNT	2
43 
44 /* subcommand index */
45 enum subcommand_index {
46 	CRYPTO_LIST,
47 	CRYPTO_DISABLE,
48 	CRYPTO_ENABLE,
49 	CRYPTO_INSTALL,
50 	CRYPTO_UNINSTALL,
51 	CRYPTO_UNLOAD,
52 	CRYPTO_REFRESH,
53 	CRYPTO_START,
54 	CRYPTO_STOP,
55 	CRYPTO_HELP };
56 
57 /*
58  * TRANSLATION_NOTE
59  * Command keywords are not to be translated.
60  */
61 static char *cmd_table[] = {
62 	"list",
63 	"disable",
64 	"enable",
65 	"install",
66 	"uninstall",
67 	"unload",
68 	"refresh",
69 	"start",
70 	"stop",
71 	"--help" };
72 
73 /* provider type */
74 enum provider_type_index {
75 	PROV_UEF_LIB,
76 	PROV_KEF_SOFT,
77 	PROV_KEF_HARD,
78 	METASLOT,
79 	PROV_BADNAME };
80 
81 typedef struct {
82 	char cp_name[MAXPATHLEN];
83 	enum provider_type_index cp_type;
84 } cryptoadm_provider_t;
85 
86 /*
87  * TRANSLATION_NOTE
88  * Operand keywords are not to be translated.
89  */
90 static const char *KN_PROVIDER = "provider=";
91 static const char *KN_MECH = "mechanism=";
92 static const char *KN_ALL = "all";
93 static const char *KN_TOKEN = "token=";
94 static const char *KN_SLOT = "slot=";
95 static const char *KN_DEFAULT_KS = "default-keystore";
96 static const char *KN_AUTO_KEY_MIGRATE = "auto-key-migrate";
97 
98 /* static variables */
99 static boolean_t	allflag = B_FALSE;
100 static boolean_t	rndflag = B_FALSE;
101 static mechlist_t	*mecharglist = NULL;
102 
103 /* static functions */
104 static void usage(void);
105 static int get_provider_type(char *);
106 static int process_mech_operands(int, char **, boolean_t);
107 static int do_list(int, char **);
108 static int do_disable(int, char **);
109 static int do_enable(int, char **);
110 static int do_install(int, char **);
111 static int do_uninstall(int, char **);
112 static int do_unload(int, char **);
113 static int do_refresh(int);
114 static int do_start(int);
115 static int do_stop(int);
116 static int list_simple_for_all(boolean_t);
117 static int list_mechlist_for_all(boolean_t);
118 static int list_policy_for_all(void);
119 
120 int
121 main(int argc, char *argv[])
122 {
123 	char	*subcmd;
124 	int	cmdnum;
125 	int	cmd_index = 0;
126 	int	rc = SUCCESS;
127 
128 	(void) setlocale(LC_ALL, "");
129 
130 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
131 #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
132 #endif
133 	(void) textdomain(TEXT_DOMAIN);
134 
135 	cryptodebug_init(basename(argv[0]));
136 
137 	if (argc < REQ_ARG_CNT) {
138 		usage();
139 		return (ERROR_USAGE);
140 	}
141 
142 	/* get the subcommand index */
143 	cmd_index = 0;
144 	subcmd = argv[1];
145 	cmdnum = sizeof (cmd_table)/sizeof (cmd_table[0]);
146 
147 	while ((cmd_index < cmdnum) &&
148 	    (strcmp(subcmd, cmd_table[cmd_index]) != 0)) {
149 		cmd_index++;
150 	}
151 	if (cmd_index >= cmdnum) {
152 		usage();
153 		return (ERROR_USAGE);
154 	}
155 
156 	/* do the subcommand */
157 	switch (cmd_index) {
158 	case CRYPTO_LIST:
159 		rc = do_list(argc, argv);
160 		break;
161 	case CRYPTO_DISABLE:
162 		rc = do_disable(argc, argv);
163 		break;
164 	case CRYPTO_ENABLE:
165 		rc = do_enable(argc, argv);
166 		break;
167 	case CRYPTO_INSTALL:
168 		rc = do_install(argc, argv);
169 		break;
170 	case CRYPTO_UNINSTALL:
171 		rc = do_uninstall(argc, argv);
172 		break;
173 	case CRYPTO_UNLOAD:
174 		rc = do_unload(argc, argv);
175 		break;
176 	case CRYPTO_REFRESH:
177 		rc = do_refresh(argc);
178 		break;
179 	case CRYPTO_START:
180 		rc = do_start(argc);
181 		break;
182 	case CRYPTO_STOP:
183 		rc = do_stop(argc);
184 		break;
185 	case CRYPTO_HELP:
186 		usage();
187 		rc = SUCCESS;
188 		break;
189 	default: /* should not come here */
190 		usage();
191 		rc = ERROR_USAGE;
192 		break;
193 	}
194 	return (rc);
195 }
196 
197 
198 static void
199 usage(void)
200 {
201 	/*
202 	 * TRANSLATION_NOTE
203 	 * Command usage is not to be translated.  Only the word "Usage:"
204 	 * along with localized expressions indicating what kind of value
205 	 * is expected for arguments.
206 	 */
207 	(void) fprintf(stderr, gettext("Usage:\n"));
208 	(void) fprintf(stderr,
209 	    "  cryptoadm list [-mpv] [provider=<%s> | metaslot]"
210 	    " [mechanism=<%s>]\n",
211 	    gettext("provider-name"), gettext("mechanism-list"));
212 	(void) fprintf(stderr,
213 	    "  cryptoadm disable provider=<%s>"
214 	    " mechanism=<%s> | random | all\n",
215 	    gettext("provider-name"), gettext("mechanism-list"));
216 	(void) fprintf(stderr,
217 	    "  cryptoadm disable metaslot"
218 	    " [auto-key-migrate] [mechanism=<%s>]\n",
219 	    gettext("mechanism-list"));
220 	(void) fprintf(stderr,
221 	    "  cryptoadm enable provider=<%s>"
222 	    " mechanism=<%s> | random | all\n",
223 	    gettext("provider-name"), gettext("mechanism-list"));
224 	(void) fprintf(stderr,
225 	    "  cryptoadm enable metaslot [mechanism=<%s>]"
226 	    " [[token=<%s>] [slot=<%s>]"
227 	    " | [default-keystore]] | [auto-key-migrate]\n",
228 	    gettext("mechanism-list"), gettext("token-label"),
229 	    gettext("slot-description"));
230 	(void) fprintf(stderr,
231 	    "  cryptoadm install provider=<%s>\n",
232 	    gettext("provider-name"));
233 	(void) fprintf(stderr,
234 	    "  cryptoadm install provider=<%s> [mechanism=<%s>]\n",
235 	    gettext("provider-name"), gettext("mechanism-list"));
236 	(void) fprintf(stderr,
237 	    "  cryptoadm uninstall provider=<%s>\n",
238 	    gettext("provider-name"));
239 	(void) fprintf(stderr,
240 	    "  cryptoadm unload provider=<%s>\n",
241 	    gettext("provider-name"));
242 	(void) fprintf(stderr,
243 	    "  cryptoadm refresh\n"
244 	    "  cryptoadm start\n"
245 	    "  cryptoadm stop\n"
246 	    "  cryptoadm --help\n");
247 }
248 
249 
250 /*
251  * Get the provider type.  This function returns
252  * - PROV_UEF_LIB if provname contains an absolute path name
253  * - PROV_KEF_SOFT if provname is a base name only (e.g., "aes").
254  * - PROV_KEF_HARD if provname contains one slash only and the slash is not
255  *	the 1st character (e.g., "mca/0").
256  * - PROV_BADNAME otherwise.
257  */
258 static int
259 get_provider_type(char *provname)
260 {
261 	char *pslash1;
262 	char *pslash2;
263 
264 	if (provname == NULL) {
265 		return (FAILURE);
266 	}
267 
268 	if (provname[0] == '/') {
269 		return (PROV_UEF_LIB);
270 	} else if ((pslash1 = strchr(provname, SEP_SLASH)) == NULL) {
271 		/* no slash */
272 		return (PROV_KEF_SOFT);
273 	} else {
274 		pslash2 = strrchr(provname, SEP_SLASH);
275 		if (pslash1 == pslash2) {
276 			return (PROV_KEF_HARD);
277 		} else {
278 			return (PROV_BADNAME);
279 		}
280 	}
281 }
282 
283 /*
284  * Get the provider structure.  This function returns NULL if no valid
285  * provider= is found in argv[], otherwise a cryptoadm_provider_t is returned.
286  * If provider= is found but has no argument, then a cryptoadm_provider_t
287  * with cp_type = PROV_BADNAME is returned.
288  */
289 static cryptoadm_provider_t *
290 get_provider(int argc, char **argv)
291 {
292 	int			c = 0;
293 	boolean_t		found = B_FALSE;
294 	cryptoadm_provider_t	*provider = NULL;
295 	char			*provstr = NULL, *savstr;
296 	boolean_t		is_metaslot = B_FALSE;
297 
298 	while (!found && ++c < argc) {
299 		if (strncmp(argv[c], METASLOT_KEYWORD,
300 		    strlen(METASLOT_KEYWORD)) == 0) {
301 			is_metaslot = B_TRUE;
302 			found = B_TRUE;
303 		} else if (strncmp(argv[c], KN_PROVIDER,
304 		    strlen(KN_PROVIDER)) == 0 &&
305 		    strlen(argv[c]) > strlen(KN_PROVIDER)) {
306 			if ((provstr = strdup(argv[c])) == NULL) {
307 				int err = errno;
308 				/*
309 				 * TRANSLATION_NOTE
310 				 * "get_provider" is a function name and should
311 				 * not be translated.
312 				 */
313 				cryptoerror(LOG_STDERR, "get_provider: %s.",
314 				    strerror(err));
315 				return (NULL);
316 			}
317 			found = B_TRUE;
318 		}
319 	}
320 	if (!found)
321 		return (NULL);
322 
323 	provider = malloc(sizeof (cryptoadm_provider_t));
324 	if (provider == NULL) {
325 		cryptoerror(LOG_STDERR, gettext("out of memory."));
326 		if (provstr) {
327 			free(provstr);
328 		}
329 		return (NULL);
330 	}
331 
332 	if (is_metaslot) {
333 		(void) strlcpy(provider->cp_name, METASLOT_KEYWORD,
334 		    strlen(METASLOT_KEYWORD));
335 		provider->cp_type = METASLOT;
336 	} else {
337 
338 		savstr = provstr;
339 		(void) strtok(provstr, "=");
340 		provstr = strtok(NULL, "=");
341 		if (provstr == NULL) {
342 			cryptoerror(LOG_STDERR, gettext("bad provider name."));
343 			provider->cp_type = PROV_BADNAME;
344 			free(savstr);
345 			return (provider);
346 		}
347 
348 		(void) strlcpy(provider->cp_name, provstr,
349 		    sizeof (provider->cp_name));
350 		provider->cp_type = get_provider_type(provider->cp_name);
351 
352 		free(savstr);
353 	}
354 	return (provider);
355 }
356 
357 /*
358  * Process the "feature" operands.
359  *
360  * "argc" and "argv" contain values specified on the command line.
361  * All other arguments are used for returning parsing results.
362  * If any of these arguments are NULL, that keyword is not expected,
363  * and FAILURE will be returned.
364  */
365 static int
366 process_metaslot_operands(int argc, char **argv, char **meta_ks_token,
367     char **meta_ks_slot, boolean_t *use_default,
368     boolean_t *auto_key_migrate_flag)
369 {
370 	int c = 2;
371 	int rc = SUCCESS;
372 
373 	while (++c < argc) {
374 		if ((strncmp(argv[c], KN_MECH, strlen(KN_MECH)) == 0) &&
375 		    strlen(argv[c]) > strlen(KN_MECH)) {
376 
377 			/* process mechanism operands */
378 			if ((rc = process_mech_operands(argc, argv, B_TRUE))
379 			    != SUCCESS) {
380 				goto finish;
381 			}
382 
383 		} else if ((strncmp(argv[c], KN_TOKEN,
384 		    strlen(KN_TOKEN)) == 0) &&
385 		    strlen(argv[c]) > strlen(KN_TOKEN)) {
386 			if ((meta_ks_token) && (strtok(argv[c], "=") != NULL)) {
387 				char *tmp;
388 				if ((tmp = strtok(NULL, "=")) != NULL) {
389 					*meta_ks_token = strdup(tmp);
390 				} else {
391 					return (FAILURE);
392 				}
393 			} else {
394 				return (FAILURE);
395 			}
396 
397 		} else if ((strncmp(argv[c], KN_SLOT,
398 		    strlen(KN_SLOT)) == 0) &&
399 		    strlen(argv[c]) > strlen(KN_SLOT)) {
400 
401 			if ((meta_ks_slot) && (strtok(argv[c], "=") != NULL)) {
402 				char *tmp;
403 				if ((tmp = strtok(NULL, "=")) != NULL) {
404 					*meta_ks_slot = strdup(tmp);
405 				} else {
406 					return (FAILURE);
407 				}
408 			} else {
409 				return (FAILURE);
410 			}
411 
412 		} else if (strncmp(argv[c], KN_DEFAULT_KS,
413 		    strlen(KN_DEFAULT_KS)) == 0) {
414 
415 			if (use_default) {
416 				*use_default = B_TRUE;
417 			} else {
418 				return (FAILURE);
419 			}
420 		} else if (strncmp(argv[c], KN_AUTO_KEY_MIGRATE,
421 		    strlen(KN_AUTO_KEY_MIGRATE)) == 0) {
422 
423 			if (auto_key_migrate_flag) {
424 				*auto_key_migrate_flag = B_TRUE;
425 			} else {
426 				return (FAILURE);
427 			}
428 		} else {
429 			return (FAILURE);
430 		}
431 	}
432 finish:
433 	return (rc);
434 }
435 
436 /*
437  * Process the "feature" operands.
438  */
439 static int
440 process_feature_operands(int argc, char **argv)
441 {
442 	int c = 2;
443 
444 	while (++c < argc) {
445 		if (strcmp(argv[c], KN_ALL) == 0) {
446 			allflag = B_TRUE;
447 			rndflag = B_TRUE; /* all includes random also. */
448 		} else if (strcmp(argv[c], RANDOM) == 0) {
449 			rndflag = B_TRUE;
450 		}
451 	}
452 	return (SUCCESS);
453 }
454 
455 /*
456  * Process the mechanism operands for the disable, enable and install
457  * subcommands.  This function sets the static variable allflag to be B_TRUE
458  * if the keyword "all" is specified, otherwise builds a link list of the
459  * mechanism operands and save it in the static variable mecharglist.
460  *
461  * This function returns
462  *	ERROR_USAGE: mechanism operand is missing.
463  *	FAILURE: out of memory.
464  *	SUCCESS: otherwise.
465  */
466 static int
467 process_mech_operands(int argc, char **argv, boolean_t quiet)
468 {
469 	mechlist_t	*pmech;
470 	mechlist_t	*pcur = NULL;
471 	mechlist_t	*phead = NULL;
472 	boolean_t	found = B_FALSE;
473 	char		*mechliststr = NULL;
474 	char		*curmech = NULL;
475 	int		c = -1;
476 	int		rc = SUCCESS;
477 
478 	while (!found && ++c < argc) {
479 		if ((strncmp(argv[c], KN_MECH, strlen(KN_MECH)) == 0) &&
480 		    strlen(argv[c]) > strlen(KN_MECH)) {
481 			found = B_TRUE;
482 		}
483 	}
484 	if (!found) {
485 		if (!quiet)
486 			/*
487 			 * TRANSLATION_NOTE
488 			 * "mechanism" could be either a literal keyword
489 			 * and hence not to be translated, or a descriptive
490 			 * word and translatable.  A choice was made to
491 			 * view it as a literal keyword.
492 			 */
493 			cryptoerror(LOG_STDERR,
494 			    gettext("the %s operand is missing.\n"),
495 			    "mechanism");
496 		return (ERROR_USAGE);
497 	}
498 	(void) strtok(argv[c], "=");
499 	mechliststr = strtok(NULL, "=");
500 
501 	if (strcmp(mechliststr, "all") == 0) {
502 		allflag = B_TRUE;
503 		mecharglist = NULL;
504 		return (SUCCESS);
505 	}
506 
507 	curmech = strtok(mechliststr, ",");
508 	do {
509 		if ((pmech = create_mech(curmech)) == NULL) {
510 			rc = FAILURE;
511 			break;
512 		} else {
513 			if (phead == NULL) {
514 				phead = pcur = pmech;
515 			} else {
516 				pcur->next = pmech;
517 				pcur = pmech;
518 			}
519 		}
520 	} while ((curmech = strtok(NULL, ",")) != NULL);
521 
522 	if (rc == FAILURE) {
523 		cryptoerror(LOG_STDERR, gettext("out of memory."));
524 		free_mechlist(phead);
525 	} else {
526 		mecharglist = phead;
527 		rc = SUCCESS;
528 	}
529 	return (rc);
530 }
531 
532 
533 
534 /*
535  * The top level function for the "cryptoadm list" subcommand and options.
536  */
537 static int
538 do_list(int argc, char **argv)
539 {
540 	boolean_t		mflag = B_FALSE;
541 	boolean_t		pflag = B_FALSE;
542 	boolean_t		vflag = B_FALSE;
543 	char			ch;
544 	cryptoadm_provider_t	*prov = NULL;
545 	int			rc = SUCCESS;
546 
547 	argc -= 1;
548 	argv += 1;
549 
550 	if (argc == 1) {
551 		rc = list_simple_for_all(B_FALSE);
552 		goto out;
553 	}
554 
555 	/*
556 	 * cryptoadm list [-v] [-m] [-p] [provider=<>] [mechanism=<>]
557 	 */
558 	if (argc > 5) {
559 		usage();
560 		return (rc);
561 	}
562 
563 	while ((ch = getopt(argc, argv, "mpv")) != EOF) {
564 		switch (ch) {
565 		case 'm':
566 			mflag = B_TRUE;
567 			if (pflag) {
568 				rc = ERROR_USAGE;
569 			}
570 			break;
571 		case 'p':
572 			pflag = B_TRUE;
573 			if (mflag || vflag) {
574 				rc = ERROR_USAGE;
575 			}
576 			break;
577 		case 'v':
578 			vflag = B_TRUE;
579 			if (pflag)
580 				rc = ERROR_USAGE;
581 			break;
582 		default:
583 			rc = ERROR_USAGE;
584 			break;
585 		}
586 	}
587 
588 	if (rc == ERROR_USAGE) {
589 		usage();
590 		return (rc);
591 	}
592 
593 	if ((rc = process_feature_operands(argc, argv)) != SUCCESS) {
594 		goto out;
595 	}
596 
597 	prov = get_provider(argc, argv);
598 
599 	if (mflag || vflag) {
600 		if (argc > 0) {
601 			rc = process_mech_operands(argc, argv, B_TRUE);
602 			if (rc == FAILURE)
603 				goto out;
604 			/* "-m" is implied when a mechanism list is given */
605 			if (mecharglist != NULL || allflag)
606 				mflag = B_TRUE;
607 		}
608 	}
609 
610 	if (prov == NULL) {
611 		if (mflag) {
612 			rc = list_mechlist_for_all(vflag);
613 		} else if (pflag) {
614 			rc = list_policy_for_all();
615 		} else if (vflag) {
616 			rc = list_simple_for_all(vflag);
617 		}
618 	} else if (prov->cp_type == METASLOT) {
619 		if ((!mflag) && (!vflag) && (!pflag)) {
620 			/* no flag is specified, just list metaslot status */
621 			rc = list_metaslot_info(mflag, vflag, mecharglist);
622 		} else if (mflag || vflag) {
623 			rc = list_metaslot_info(mflag, vflag, mecharglist);
624 		} else if (pflag) {
625 			rc = list_metaslot_policy();
626 		} else {
627 			/* error message */
628 			usage();
629 			rc = ERROR_USAGE;
630 		}
631 	} else if (prov->cp_type == PROV_BADNAME) {
632 		usage();
633 		rc = ERROR_USAGE;
634 		goto out;
635 	} else { /* do the listing for a provider only */
636 		char	*provname = prov->cp_name;
637 
638 		if (mflag || vflag) {
639 			if (vflag)
640 				(void) printf(gettext("Provider: %s\n"),
641 				    provname);
642 			switch (prov->cp_type) {
643 			case PROV_UEF_LIB:
644 				rc = list_mechlist_for_lib(provname,
645 				    mecharglist, NULL, B_FALSE, vflag, mflag);
646 				break;
647 			case PROV_KEF_SOFT:
648 				rc = list_mechlist_for_soft(provname,
649 				    NULL, NULL);
650 				break;
651 			case PROV_KEF_HARD:
652 				rc = list_mechlist_for_hard(provname);
653 				break;
654 			default: /* should not come here */
655 				rc = FAILURE;
656 				break;
657 			}
658 		} else if (pflag) {
659 			switch (prov->cp_type) {
660 			case PROV_UEF_LIB:
661 				rc = list_policy_for_lib(provname);
662 				break;
663 			case PROV_KEF_SOFT:
664 				if (getzoneid() == GLOBAL_ZONEID) {
665 					rc = list_policy_for_soft(provname,
666 					    NULL, NULL);
667 				} else {
668 					/*
669 					 * TRANSLATION_NOTE
670 					 * "global" is keyword and not to
671 					 * be translated.
672 					 */
673 					cryptoerror(LOG_STDERR, gettext(
674 					    "policy information for kernel "
675 					    "providers is available "
676 					    "in the %s zone only"), "global");
677 					rc = FAILURE;
678 				}
679 				break;
680 			case PROV_KEF_HARD:
681 				if (getzoneid() == GLOBAL_ZONEID) {
682 					rc = list_policy_for_hard(
683 					    provname, NULL, NULL, NULL);
684 				} else {
685 					/*
686 					 * TRANSLATION_NOTE
687 					 * "global" is keyword and not to
688 					 * be translated.
689 					 */
690 					cryptoerror(LOG_STDERR, gettext(
691 					    "policy information for kernel "
692 					    "providers is available "
693 					    "in the %s zone only"), "global");
694 					rc = FAILURE;
695 				}
696 
697 				break;
698 			default: /* should not come here */
699 				rc = FAILURE;
700 				break;
701 			}
702 		} else {
703 			/* error message */
704 			usage();
705 			rc = ERROR_USAGE;
706 		}
707 	}
708 
709 out:
710 	if (prov != NULL)
711 		free(prov);
712 
713 	if (mecharglist != NULL)
714 		free_mechlist(mecharglist);
715 	return (rc);
716 }
717 
718 
719 /*
720  * The top level function for the "cryptoadm disable" subcommand.
721  */
722 static int
723 do_disable(int argc, char **argv)
724 {
725 	cryptoadm_provider_t	*prov = NULL;
726 	int			rc = SUCCESS;
727 	boolean_t		auto_key_migrate_flag = B_FALSE;
728 
729 	if ((argc < 3) || (argc > 5)) {
730 		usage();
731 		return (ERROR_USAGE);
732 	}
733 
734 	prov = get_provider(argc, argv);
735 	if (prov == NULL) {
736 		usage();
737 		return (ERROR_USAGE);
738 	}
739 	if (prov->cp_type == PROV_BADNAME) {
740 		return (FAILURE);
741 	}
742 
743 	if ((rc = process_feature_operands(argc, argv)) != SUCCESS) {
744 		goto out;
745 	}
746 
747 	/*
748 	 * If allflag or rndflag has already been set there is no reason to
749 	 * process mech=
750 	 */
751 	if (prov->cp_type == METASLOT) {
752 		if ((argc > 3) &&
753 		    (rc = process_metaslot_operands(argc, argv,
754 		    NULL, NULL, NULL, &auto_key_migrate_flag)) != SUCCESS) {
755 			usage();
756 			return (rc);
757 		}
758 	} else if (!allflag && !rndflag &&
759 	    (rc = process_mech_operands(argc, argv, B_FALSE)) != SUCCESS) {
760 			return (rc);
761 	}
762 
763 	switch (prov->cp_type) {
764 	case METASLOT:
765 		rc = disable_metaslot(mecharglist, allflag,
766 		    auto_key_migrate_flag);
767 		break;
768 	case PROV_UEF_LIB:
769 		rc = disable_uef_lib(prov->cp_name, rndflag, allflag,
770 		    mecharglist);
771 		break;
772 	case PROV_KEF_SOFT:
773 		if (rndflag && !allflag) {
774 			if ((mecharglist = create_mech(RANDOM)) == NULL) {
775 				rc = FAILURE;
776 				break;
777 			}
778 		}
779 		if (getzoneid() == GLOBAL_ZONEID) {
780 			rc = disable_kef_software(prov->cp_name, rndflag,
781 			    allflag, mecharglist);
782 		} else {
783 			/*
784 			 * TRANSLATION_NOTE
785 			 * "disable" could be either a literal keyword
786 			 * and hence not to be translated, or a verb and
787 			 * translatable.  A choice was made to view it as
788 			 * a literal keyword.  "global" is keyword and not
789 			 * to be translated.
790 			 */
791 			cryptoerror(LOG_STDERR, gettext("%1$s for kernel "
792 			    "providers is supported in the %2$s zone only"),
793 			    "disable", "global");
794 			rc = FAILURE;
795 		}
796 		break;
797 	case PROV_KEF_HARD:
798 		if (rndflag && !allflag) {
799 			if ((mecharglist = create_mech(RANDOM)) == NULL) {
800 				rc = FAILURE;
801 				break;
802 			}
803 		}
804 		if (getzoneid() == GLOBAL_ZONEID) {
805 			rc = disable_kef_hardware(prov->cp_name, rndflag,
806 			    allflag, mecharglist);
807 		} else {
808 			/*
809 			 * TRANSLATION_NOTE
810 			 * "disable" could be either a literal keyword
811 			 * and hence not to be translated, or a verb and
812 			 * translatable.  A choice was made to view it as
813 			 * a literal keyword.  "global" is keyword and not
814 			 * to be translated.
815 			 */
816 			cryptoerror(LOG_STDERR, gettext("%1$s for kernel "
817 			    "providers is supported in the %2$s zone only"),
818 			    "disable", "global");
819 			rc = FAILURE;
820 		}
821 		break;
822 	default: /* should not come here */
823 		rc = FAILURE;
824 		break;
825 	}
826 
827 out:
828 	free(prov);
829 	if (mecharglist != NULL) {
830 		free_mechlist(mecharglist);
831 	}
832 	return (rc);
833 }
834 
835 
836 /*
837  * The top level function for the "cryptoadm enable" subcommand.
838  */
839 static int
840 do_enable(int argc, char **argv)
841 {
842 	cryptoadm_provider_t	*prov = NULL;
843 	int			rc = SUCCESS;
844 	char 			*alt_token = NULL, *alt_slot = NULL;
845 	boolean_t		use_default = B_FALSE;
846 	boolean_t		auto_key_migrate_flag = B_FALSE;
847 
848 	if ((argc < 3) || (argc > 6)) {
849 		usage();
850 		return (ERROR_USAGE);
851 	}
852 
853 	prov = get_provider(argc, argv);
854 	if (prov == NULL) {
855 		usage();
856 		return (ERROR_USAGE);
857 	}
858 	if ((prov->cp_type != METASLOT) && (argc != 4)) {
859 		usage();
860 		return (ERROR_USAGE);
861 	}
862 	if (prov->cp_type == PROV_BADNAME) {
863 		rc = FAILURE;
864 		goto out;
865 	}
866 
867 
868 	if (prov->cp_type == METASLOT) {
869 		if ((rc = process_metaslot_operands(argc, argv, &alt_token,
870 		    &alt_slot, &use_default, &auto_key_migrate_flag))
871 		    != SUCCESS) {
872 			usage();
873 			goto out;
874 		}
875 		if ((alt_slot || alt_token) && use_default) {
876 			usage();
877 			rc = FAILURE;
878 			goto out;
879 		}
880 	} else {
881 		if ((rc = process_feature_operands(argc, argv)) != SUCCESS) {
882 			goto out;
883 		}
884 
885 		/*
886 		 * If allflag or rndflag has already been set there is
887 		 * no reason to process mech=
888 		 */
889 		if (!allflag && !rndflag &&
890 		    (rc = process_mech_operands(argc, argv, B_FALSE))
891 		    != SUCCESS) {
892 			goto out;
893 		}
894 	}
895 
896 	switch (prov->cp_type) {
897 	case METASLOT:
898 		rc = enable_metaslot(alt_token, alt_slot, use_default,
899 		    mecharglist, allflag, auto_key_migrate_flag);
900 		break;
901 	case PROV_UEF_LIB:
902 		rc = enable_uef_lib(prov->cp_name, rndflag, allflag,
903 		    mecharglist);
904 		break;
905 	case PROV_KEF_SOFT:
906 	case PROV_KEF_HARD:
907 		if (rndflag && !allflag) {
908 			if ((mecharglist = create_mech(RANDOM)) == NULL) {
909 				rc = FAILURE;
910 				break;
911 			}
912 		}
913 		if (getzoneid() == GLOBAL_ZONEID) {
914 			rc = enable_kef(prov->cp_name, rndflag, allflag,
915 			    mecharglist);
916 		} else {
917 			/*
918 			 * TRANSLATION_NOTE
919 			 * "enable" could be either a literal keyword
920 			 * and hence not to be translated, or a verb and
921 			 * translatable.  A choice was made to view it as
922 			 * a literal keyword.  "global" is keyword and not
923 			 * to be translated.
924 			 */
925 			cryptoerror(LOG_STDERR, gettext("%1$s for kernel "
926 			    "providers is supported in the %2$s zone only"),
927 			    "enable", "global");
928 			rc = FAILURE;
929 		}
930 		break;
931 	default: /* should not come here */
932 		rc = FAILURE;
933 		break;
934 	}
935 out:
936 	free(prov);
937 	if (mecharglist != NULL) {
938 		free_mechlist(mecharglist);
939 	}
940 	if (alt_token != NULL) {
941 		free(alt_token);
942 	}
943 	if (alt_slot != NULL) {
944 		free(alt_slot);
945 	}
946 	return (rc);
947 }
948 
949 
950 
951 /*
952  * The top level function for the "cryptoadm install" subcommand.
953  */
954 static int
955 do_install(int argc, char **argv)
956 {
957 	cryptoadm_provider_t	*prov = NULL;
958 	int	rc;
959 
960 	if (argc < 3) {
961 		usage();
962 		return (ERROR_USAGE);
963 	}
964 
965 	prov = get_provider(argc, argv);
966 	if (prov == NULL ||
967 	    prov->cp_type == PROV_BADNAME || prov->cp_type == PROV_KEF_HARD) {
968 		/*
969 		 * TRANSLATION_NOTE
970 		 * "install" could be either a literal keyword and hence
971 		 * not to be translated, or a verb and translatable.  A
972 		 * choice was made to view it as a literal keyword.
973 		 */
974 		cryptoerror(LOG_STDERR,
975 		    gettext("bad provider name for %s."), "install");
976 		rc = FAILURE;
977 		goto out;
978 	}
979 
980 	if (prov->cp_type == PROV_UEF_LIB) {
981 		rc = install_uef_lib(prov->cp_name);
982 		goto out;
983 	}
984 
985 	/* It is the PROV_KEF_SOFT type now  */
986 
987 	/* check if there are mechanism operands */
988 	if (argc < 4) {
989 		/*
990 		 * TRANSLATION_NOTE
991 		 * "mechanism" could be either a literal keyword and hence
992 		 * not to be translated, or a descriptive word and
993 		 * translatable.  A choice was made to view it as a literal
994 		 * keyword.
995 		 */
996 		cryptoerror(LOG_STDERR,
997 		    gettext("need %s operands for installing a"
998 		    " kernel software provider."), "mechanism");
999 		rc = ERROR_USAGE;
1000 		goto out;
1001 	}
1002 
1003 	if ((rc = process_mech_operands(argc, argv, B_FALSE)) != SUCCESS) {
1004 		goto out;
1005 	}
1006 
1007 	if (allflag == B_TRUE) {
1008 		/*
1009 		 * TRANSLATION_NOTE
1010 		 * "all", "mechanism", and "install" are all keywords and
1011 		 * not to be translated.
1012 		 */
1013 		cryptoerror(LOG_STDERR,
1014 		    gettext("can not use the %1$s keyword for %2$s "
1015 		    "in the %3$s subcommand."), "all", "mechanism", "install");
1016 		rc = ERROR_USAGE;
1017 		goto out;
1018 	}
1019 
1020 	if (getzoneid() == GLOBAL_ZONEID) {
1021 		rc = install_kef(prov->cp_name, mecharglist);
1022 	} else {
1023 		/*
1024 		 * TRANSLATION_NOTE
1025 		 * "install" could be either a literal keyword and hence
1026 		 * not to be translated, or a verb and translatable.  A
1027 		 * choice was made to view it as a literal keyword.
1028 		 * "global" is keyword and not to be translated.
1029 		 */
1030 		cryptoerror(LOG_STDERR, gettext("%1$s for kernel providers "
1031 		    "is supported in the %2$s zone only"), "install", "global");
1032 		rc = FAILURE;
1033 	}
1034 out:
1035 	free(prov);
1036 	return (rc);
1037 }
1038 
1039 
1040 
1041 /*
1042  * The top level function for the "cryptoadm uninstall" subcommand.
1043  */
1044 static int
1045 do_uninstall(int argc, char **argv)
1046 {
1047 	cryptoadm_provider_t	*prov = NULL;
1048 	int	rc = SUCCESS;
1049 
1050 	if (argc != 3) {
1051 		usage();
1052 		return (ERROR_USAGE);
1053 	}
1054 
1055 	prov = get_provider(argc, argv);
1056 	if (prov == NULL ||
1057 	    prov->cp_type == PROV_BADNAME || prov->cp_type == PROV_KEF_HARD) {
1058 		/*
1059 		 * TRANSLATION_NOTE
1060 		 * "uninstall" could be either a literal keyword and hence
1061 		 * not to be translated, or a verb and translatable.  A
1062 		 * choice was made to view it as a literal keyword.
1063 		 */
1064 		cryptoerror(LOG_STDERR,
1065 		    gettext("bad provider name for %s."), "uninstall");
1066 		free(prov);
1067 		return (FAILURE);
1068 	}
1069 
1070 	if (prov->cp_type == PROV_UEF_LIB) {
1071 		rc = uninstall_uef_lib(prov->cp_name);
1072 
1073 	} else if (prov->cp_type == PROV_KEF_SOFT) {
1074 		if (getzoneid() == GLOBAL_ZONEID) {
1075 			/* unload and remove from kcf.conf */
1076 			rc = uninstall_kef(prov->cp_name);
1077 		} else {
1078 			/*
1079 			 * TRANSLATION_NOTE
1080 			 * "uninstall" could be either a literal keyword and
1081 			 * hence not to be translated, or a verb and
1082 			 * translatable.  A choice was made to view it as a
1083 			 * literal keyword.  "global" is keyword and not to
1084 			 * be translated.
1085 			 */
1086 			cryptoerror(LOG_STDERR, gettext("%1$s for kernel "
1087 			    "providers is supported in the %2$s zone only"),
1088 			    "uninstall", "global");
1089 			rc = FAILURE;
1090 		}
1091 	}
1092 
1093 	free(prov);
1094 	return (rc);
1095 }
1096 
1097 
1098 /*
1099  * The top level function for the "cryptoadm unload" subcommand.
1100  */
1101 static int
1102 do_unload(int argc, char **argv)
1103 {
1104 	cryptoadm_provider_t	*prov = NULL;
1105 	entry_t			*pent = NULL;
1106 	boolean_t		in_kernel = B_FALSE;
1107 	int			rc = SUCCESS;
1108 	char			*provname = NULL;
1109 
1110 	if (argc != 3) {
1111 		usage();
1112 		return (ERROR_USAGE);
1113 	}
1114 
1115 	/* check if it is a kernel software provider */
1116 	prov = get_provider(argc, argv);
1117 	if (prov == NULL) {
1118 		cryptoerror(LOG_STDERR,
1119 		    gettext("unable to determine provider name."));
1120 		goto out;
1121 	}
1122 	provname = prov->cp_name;
1123 	if (prov->cp_type != PROV_KEF_SOFT) {
1124 		cryptoerror(LOG_STDERR,
1125 		    gettext("%s is not a valid kernel software provider."),
1126 		    provname);
1127 		rc = FAILURE;
1128 		goto out;
1129 	}
1130 
1131 	if (getzoneid() != GLOBAL_ZONEID) {
1132 		/*
1133 		 * TRANSLATION_NOTE
1134 		 * "unload" could be either a literal keyword and hence
1135 		 * not to be translated, or a verb and translatable.
1136 		 * A choice was made to view it as a literal keyword.
1137 		 * "global" is keyword and not to be translated.
1138 		 */
1139 		cryptoerror(LOG_STDERR, gettext("%1$s for kernel providers "
1140 		    "is supported in the %2$s zone only"), "unload", "global");
1141 		rc = FAILURE;
1142 		goto out;
1143 	}
1144 
1145 	if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) {
1146 		cryptodebug("internal error");
1147 		rc = FAILURE;
1148 		goto out;
1149 	} else if (in_kernel == B_FALSE) {
1150 		cryptoerror(LOG_STDERR,
1151 		    gettext("provider %s is not loaded or does not exist."),
1152 		    provname);
1153 		rc = FAILURE;
1154 		goto out;
1155 	}
1156 
1157 	/* Get kcf.conf entry.  If none, build a new entry */
1158 	if ((pent = getent_kef(provname, NULL, NULL)) == NULL) {
1159 		if ((pent = create_entry(provname)) == NULL) {
1160 			cryptoerror(LOG_STDERR, gettext("out of memory."));
1161 			rc = FAILURE;
1162 			goto out;
1163 		}
1164 	}
1165 
1166 	/* If it is unloaded already, return  */
1167 	if (!pent->load) { /* unloaded already */
1168 		cryptoerror(LOG_STDERR,
1169 		    gettext("failed to unload %s."), provname);
1170 		rc = FAILURE;
1171 		goto out;
1172 	} else if (unload_kef_soft(provname) != FAILURE) {
1173 		/* Mark as unloaded in kcf.conf */
1174 		pent->load = B_FALSE;
1175 		rc = update_kcfconf(pent, MODIFY_MODE);
1176 	} else {
1177 		cryptoerror(LOG_STDERR,
1178 		    gettext("failed to unload %s."), provname);
1179 		rc = FAILURE;
1180 	}
1181 out:
1182 	free(prov);
1183 	free_entry(pent);
1184 	return (rc);
1185 }
1186 
1187 
1188 
1189 /*
1190  * The top level function for the "cryptoadm refresh" subcommand.
1191  */
1192 static int
1193 do_refresh(int argc)
1194 {
1195 	if (argc != 2) {
1196 		usage();
1197 		return (ERROR_USAGE);
1198 	}
1199 
1200 	if (getzoneid() == GLOBAL_ZONEID) {
1201 		return (refresh());
1202 	} else { /* non-global zone */
1203 		/*
1204 		 * Note:  in non-global zone, this must silently return SUCCESS
1205 		 * due to integration with SMF, for "svcadm refresh cryptosvc"
1206 		 */
1207 		return (SUCCESS);
1208 	}
1209 }
1210 
1211 
1212 /*
1213  * The top level function for the "cryptoadm start" subcommand.
1214  * This used to start up kcfd, but now all it does is load up the
1215  * initial providers.
1216  */
1217 static int
1218 do_start(int argc)
1219 {
1220 	if (argc != 2) {
1221 		usage();
1222 		return (ERROR_USAGE);
1223 	}
1224 
1225 	return (do_refresh(argc));
1226 }
1227 
1228 /*
1229  * The top level function for the "cryptoadm stop" subcommand.
1230  * This no longer does anything useful, but we leave it here
1231  * for compatibility.
1232  */
1233 static int
1234 do_stop(int argc)
1235 {
1236 	if (argc != 2) {
1237 		usage();
1238 		return (ERROR_USAGE);
1239 	}
1240 
1241 	return (SUCCESS);
1242 }
1243 
1244 
1245 
1246 /*
1247  * Print a list all the the providers.
1248  * Called for "cryptoadm list" or "cryptoadm list -v" (no -m or -p).
1249  */
1250 static int
1251 list_simple_for_all(boolean_t verbose)
1252 {
1253 	uentrylist_t		*pliblist = NULL;
1254 	uentrylist_t		*plibptr = NULL;
1255 	entry_t			*pent = NULL;
1256 	crypto_get_dev_list_t	*pdevlist_kernel = NULL;
1257 	int			rc = SUCCESS;
1258 	int			i;
1259 
1260 	/* get user-level providers */
1261 	(void) printf(gettext("\nUser-level providers:\n"));
1262 	if (get_pkcs11conf_info(&pliblist) != SUCCESS) {
1263 		cryptoerror(LOG_STDERR, gettext(
1264 		    "failed to retrieve the list of user-level providers."));
1265 		rc = FAILURE;
1266 	}
1267 
1268 	for (plibptr = pliblist; plibptr != NULL; plibptr = plibptr->next) {
1269 		/* skip metaslot and fips-140 entry */
1270 		if ((strcmp(plibptr->puent->name, METASLOT_KEYWORD) != 0) &&
1271 		    (strcmp(plibptr->puent->name, FIPS_KEYWORD) != 0)) {
1272 			(void) printf(gettext("Provider: %s\n"),
1273 			    plibptr->puent->name);
1274 			if (verbose) {
1275 				(void) list_mechlist_for_lib(
1276 				    plibptr->puent->name, mecharglist, NULL,
1277 				    B_FALSE, verbose, B_FALSE);
1278 				(void) printf("\n");
1279 			}
1280 		}
1281 	}
1282 	free_uentrylist(pliblist);
1283 
1284 	/* get kernel software providers */
1285 	(void) printf(gettext("\nKernel software providers:\n"));
1286 
1287 	if (getzoneid() == GLOBAL_ZONEID) {
1288 		/* get kernel software providers from kernel ioctl */
1289 		crypto_get_soft_list_t		*psoftlist_kernel = NULL;
1290 		uint_t				sl_soft_count;
1291 		char				*psoftname;
1292 		entrylist_t			*pdevlist_conf = NULL;
1293 		entrylist_t			*psoftlist_conf = NULL;
1294 
1295 		if (get_soft_list(&psoftlist_kernel) == FAILURE) {
1296 			cryptoerror(LOG_ERR, gettext("Failed to retrieve the "
1297 			    "software provider list from kernel."));
1298 			rc = FAILURE;
1299 		} else {
1300 			sl_soft_count = psoftlist_kernel->sl_soft_count;
1301 
1302 			if (get_kcfconf_info(&pdevlist_conf, &psoftlist_conf)
1303 			    == FAILURE) {
1304 				cryptoerror(LOG_ERR,
1305 				    "failed to retrieve the providers' "
1306 				    "information from file kcf.conf - %s.",
1307 				    _PATH_KCF_CONF);
1308 				rc = FAILURE;
1309 			} else {
1310 
1311 				for (i = 0,
1312 				    psoftname = psoftlist_kernel->sl_soft_names;
1313 				    i < sl_soft_count;
1314 				    ++i, psoftname += strlen(psoftname) + 1) {
1315 					pent = getent_kef(psoftname,
1316 					    pdevlist_conf, psoftlist_conf);
1317 					(void) printf("\t%s%s\n", psoftname,
1318 					    (pent == NULL) || (pent->load) ?
1319 					    "" : gettext(" (inactive)"));
1320 				}
1321 				free_entrylist(pdevlist_conf);
1322 				free_entrylist(psoftlist_conf);
1323 			}
1324 			free(psoftlist_kernel);
1325 		}
1326 
1327 	} else {
1328 		/* kcf.conf not there in non-global zone, use /dev/cryptoadm */
1329 		entrylist_t	*pdevlist_zone = NULL;
1330 		entrylist_t	*psoftlist_zone = NULL;
1331 		entrylist_t	*ptr;
1332 
1333 		if (get_admindev_info(&pdevlist_zone, &psoftlist_zone) !=
1334 		    SUCCESS) {
1335 			cryptoerror(LOG_STDERR,
1336 			    gettext("failed to retrieve the "
1337 			    "list of kernel software providers.\n"));
1338 			rc = FAILURE;
1339 		}
1340 
1341 		ptr = psoftlist_zone;
1342 		while (ptr != NULL) {
1343 			(void) printf("\t%s\n", ptr->pent->name);
1344 			ptr = ptr->next;
1345 		}
1346 
1347 		free_entrylist(pdevlist_zone);
1348 		free_entrylist(psoftlist_zone);
1349 	}
1350 
1351 	/* get kernel hardware providers */
1352 	(void) printf(gettext("\nKernel hardware providers:\n"));
1353 	if (get_dev_list(&pdevlist_kernel) == FAILURE) {
1354 		cryptoerror(LOG_STDERR, gettext("failed to retrieve "
1355 		    "the list of kernel hardware providers.\n"));
1356 		rc = FAILURE;
1357 	} else {
1358 		for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) {
1359 			(void) printf("\t%s/%d\n",
1360 			    pdevlist_kernel->dl_devs[i].le_dev_name,
1361 			    pdevlist_kernel->dl_devs[i].le_dev_instance);
1362 		}
1363 	}
1364 	free(pdevlist_kernel);
1365 
1366 	return (rc);
1367 }
1368 
1369 
1370 
1371 /*
1372  * List all the providers. And for each provider, list the mechanism list.
1373  * Called for "cryptoadm list -m" or "cryptoadm list -mv" .
1374  */
1375 static int
1376 list_mechlist_for_all(boolean_t verbose)
1377 {
1378 	crypto_get_dev_list_t	*pdevlist_kernel = NULL;
1379 	uentrylist_t		*pliblist = NULL;
1380 	uentrylist_t		*plibptr = NULL;
1381 	entry_t			*pent = NULL;
1382 	mechlist_t		*pmechlist = NULL;
1383 	char			provname[MAXNAMELEN];
1384 	char			devname[MAXNAMELEN];
1385 	int			inst_num;
1386 	int			count;
1387 	int			i;
1388 	int			rv;
1389 	int			rc = SUCCESS;
1390 
1391 	/* get user-level providers */
1392 	(void) printf(gettext("\nUser-level providers:\n"));
1393 	/*
1394 	 * TRANSLATION_NOTE
1395 	 * Strictly for appearance's sake, this line should be as long as
1396 	 * the length of the translated text above.
1397 	 */
1398 	(void) printf(gettext("=====================\n"));
1399 	if (get_pkcs11conf_info(&pliblist) != SUCCESS) {
1400 		cryptoerror(LOG_STDERR, gettext("failed to retrieve "
1401 		    "the list of user-level providers.\n"));
1402 		rc = FAILURE;
1403 	}
1404 
1405 	plibptr = pliblist;
1406 	while (plibptr != NULL) {
1407 		/* skip metaslot and fips-140 entry */
1408 		if ((strcmp(plibptr->puent->name, METASLOT_KEYWORD) != 0) &&
1409 		    (strcmp(plibptr->puent->name, FIPS_KEYWORD) != 0)) {
1410 			(void) printf(gettext("\nProvider: %s\n"),
1411 			    plibptr->puent->name);
1412 			rv = list_mechlist_for_lib(plibptr->puent->name,
1413 			    mecharglist, NULL, B_FALSE, verbose, B_TRUE);
1414 			if (rv == FAILURE) {
1415 				rc = FAILURE;
1416 			}
1417 		}
1418 		plibptr = plibptr->next;
1419 	}
1420 	free_uentrylist(pliblist);
1421 
1422 	/* get kernel software providers */
1423 	(void) printf(gettext("\nKernel software providers:\n"));
1424 
1425 	/*
1426 	 * TRANSLATION_NOTE
1427 	 * Strictly for appearance's sake, this line should be as long as
1428 	 * the length of the translated text above.
1429 	 */
1430 	(void) printf(gettext("==========================\n"));
1431 	if (getzoneid() == GLOBAL_ZONEID) {
1432 		/* get kernel software providers from kernel ioctl */
1433 		crypto_get_soft_list_t		*psoftlist_kernel = NULL;
1434 		uint_t				sl_soft_count;
1435 		char				*psoftname;
1436 		int				i;
1437 		entrylist_t			*pdevlist_conf = NULL;
1438 		entrylist_t			*psoftlist_conf = NULL;
1439 
1440 		if (get_soft_list(&psoftlist_kernel) == FAILURE) {
1441 			cryptoerror(LOG_ERR, gettext("Failed to retrieve the "
1442 			    "software provider list from kernel."));
1443 			return (FAILURE);
1444 		}
1445 		sl_soft_count = psoftlist_kernel->sl_soft_count;
1446 
1447 		if (get_kcfconf_info(&pdevlist_conf, &psoftlist_conf)
1448 		    == FAILURE) {
1449 			cryptoerror(LOG_ERR,
1450 			    "failed to retrieve the providers' "
1451 			    "information from file kcf.conf - %s.",
1452 			    _PATH_KCF_CONF);
1453 			free(psoftlist_kernel);
1454 			return (FAILURE);
1455 		}
1456 
1457 		for (i = 0, psoftname = psoftlist_kernel->sl_soft_names;
1458 		    i < sl_soft_count;
1459 		    ++i, psoftname += strlen(psoftname) + 1) {
1460 			pent = getent_kef(psoftname, pdevlist_conf,
1461 			    psoftlist_conf);
1462 			if ((pent == NULL) || (pent->load)) {
1463 				rv = list_mechlist_for_soft(psoftname,
1464 				    NULL, NULL);
1465 				if (rv == FAILURE) {
1466 					rc = FAILURE;
1467 				}
1468 			} else {
1469 				(void) printf(gettext("%s: (inactive)\n"),
1470 				    psoftname);
1471 			}
1472 		}
1473 
1474 		free(psoftlist_kernel);
1475 		free_entrylist(pdevlist_conf);
1476 		free_entrylist(psoftlist_conf);
1477 
1478 	} else {
1479 		/* kcf.conf not there in non-global zone, use /dev/cryptoadm */
1480 		entrylist_t	*pdevlist_zone = NULL;
1481 		entrylist_t	*psoftlist_zone = NULL;
1482 		entrylist_t	*ptr;
1483 
1484 		if (get_admindev_info(&pdevlist_zone, &psoftlist_zone) !=
1485 		    SUCCESS) {
1486 			cryptoerror(LOG_STDERR, gettext("failed to retrieve "
1487 			    "the list of kernel software providers.\n"));
1488 			rc = FAILURE;
1489 		}
1490 
1491 		for (ptr = psoftlist_zone; ptr != NULL; ptr = ptr->next) {
1492 			rv = list_mechlist_for_soft(ptr->pent->name,
1493 			    pdevlist_zone, psoftlist_zone);
1494 			if (rv == FAILURE) {
1495 				(void) printf(gettext(
1496 				    "%s: failed to get the mechanism list.\n"),
1497 				    ptr->pent->name);
1498 				rc = FAILURE;
1499 			}
1500 		}
1501 
1502 		free_entrylist(pdevlist_zone);
1503 		free_entrylist(psoftlist_zone);
1504 	}
1505 
1506 	/* Get kernel hardware providers and their mechanism lists */
1507 	(void) printf(gettext("\nKernel hardware providers:\n"));
1508 	/*
1509 	 * TRANSLATION_NOTE
1510 	 * Strictly for appearance's sake, this line should be as long as
1511 	 * the length of the translated text above.
1512 	 */
1513 	(void) printf(gettext("==========================\n"));
1514 	if (get_dev_list(&pdevlist_kernel) != SUCCESS) {
1515 		cryptoerror(LOG_STDERR, gettext("failed to retrieve "
1516 		    "the list of hardware providers.\n"));
1517 		return (FAILURE);
1518 	}
1519 
1520 	for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) {
1521 		(void) strlcpy(devname,
1522 		    pdevlist_kernel->dl_devs[i].le_dev_name, MAXNAMELEN);
1523 		inst_num = pdevlist_kernel->dl_devs[i].le_dev_instance;
1524 		count = pdevlist_kernel->dl_devs[i].le_mechanism_count;
1525 		(void) snprintf(provname, sizeof (provname), "%s/%d", devname,
1526 		    inst_num);
1527 		if (get_dev_info(devname, inst_num, count, &pmechlist) ==
1528 		    SUCCESS) {
1529 			(void) filter_mechlist(&pmechlist, RANDOM);
1530 			print_mechlist(provname, pmechlist);
1531 			free_mechlist(pmechlist);
1532 		} else {
1533 			(void) printf(gettext("%s: failed to get the mechanism"
1534 			    " list.\n"), provname);
1535 			rc = FAILURE;
1536 		}
1537 	}
1538 	free(pdevlist_kernel);
1539 	return (rc);
1540 }
1541 
1542 
1543 /*
1544  * List all the providers. And for each provider, list the policy information.
1545  * Called for "cryptoadm list -p".
1546  */
1547 static int
1548 list_policy_for_all(void)
1549 {
1550 	crypto_get_dev_list_t	*pdevlist_kernel = NULL;
1551 	uentrylist_t		*pliblist = NULL;
1552 	entrylist_t		*pdevlist_conf = NULL;
1553 	entrylist_t		*psoftlist_conf = NULL;
1554 	entrylist_t		*ptr = NULL;
1555 	entrylist_t		*phead = NULL;
1556 	boolean_t		found = B_FALSE;
1557 	char			provname[MAXNAMELEN];
1558 	int			i;
1559 	int			rc = SUCCESS;
1560 
1561 	/* Get user-level providers */
1562 	(void) printf(gettext("\nUser-level providers:\n"));
1563 	/*
1564 	 * TRANSLATION_NOTE
1565 	 * Strictly for appearance's sake, this line should be as long as
1566 	 * the length of the translated text above.
1567 	 */
1568 	(void) printf(gettext("=====================\n"));
1569 	if (get_pkcs11conf_info(&pliblist) == FAILURE) {
1570 		cryptoerror(LOG_STDERR, gettext("failed to retrieve "
1571 		    "the list of user-level providers.\n"));
1572 		rc = FAILURE;
1573 	} else {
1574 		uentrylist_t	*plibptr = pliblist;
1575 
1576 		while (plibptr != NULL) {
1577 			/* skip metaslot and fips-140 entry */
1578 			if ((strcmp(plibptr->puent->name,
1579 			    METASLOT_KEYWORD) != 0) &&
1580 			    (strcmp(plibptr->puent->name,
1581 			    FIPS_KEYWORD) != 0)) {
1582 				if (print_uef_policy(plibptr->puent)
1583 				    == FAILURE) {
1584 					rc = FAILURE;
1585 				}
1586 			}
1587 			plibptr = plibptr->next;
1588 		}
1589 		free_uentrylist(pliblist);
1590 	}
1591 
1592 	/* kernel software providers */
1593 	(void) printf(gettext("\nKernel software providers:\n"));
1594 	/*
1595 	 * TRANSLATION_NOTE
1596 	 * Strictly for appearance's sake, this line should be as long as
1597 	 * the length of the translated text above.
1598 	 */
1599 	(void) printf(gettext("==========================\n"));
1600 
1601 	/* Get all entries from the kernel */
1602 	if (getzoneid() == GLOBAL_ZONEID) {
1603 		/* get kernel software providers from kernel ioctl */
1604 		crypto_get_soft_list_t		*psoftlist_kernel = NULL;
1605 		uint_t				sl_soft_count;
1606 		char				*psoftname;
1607 		int				i;
1608 
1609 		if (get_soft_list(&psoftlist_kernel) == FAILURE) {
1610 			cryptoerror(LOG_ERR, gettext("Failed to retrieve the "
1611 			    "software provider list from kernel."));
1612 			rc = FAILURE;
1613 		} else {
1614 			sl_soft_count = psoftlist_kernel->sl_soft_count;
1615 
1616 			for (i = 0, psoftname = psoftlist_kernel->sl_soft_names;
1617 			    i < sl_soft_count;
1618 			    ++i, psoftname += strlen(psoftname) + 1) {
1619 				(void) list_policy_for_soft(psoftname,
1620 				    pdevlist_conf, psoftlist_conf);
1621 			}
1622 			free(psoftlist_kernel);
1623 		}
1624 
1625 	} else {
1626 		/* kcf.conf not there in non-global zone, no policy info */
1627 
1628 		/*
1629 		 * TRANSLATION_NOTE
1630 		 * "global" is keyword and not to be translated.
1631 		 */
1632 		cryptoerror(LOG_STDERR, gettext(
1633 		    "policy information for kernel software providers is "
1634 		    "available in the %s zone only"), "global");
1635 	}
1636 
1637 	/* Kernel hardware providers */
1638 	(void) printf(gettext("\nKernel hardware providers:\n"));
1639 	/*
1640 	 * TRANSLATION_NOTE
1641 	 * Strictly for appearance's sake, this line should be as long as
1642 	 * the length of the translated text above.
1643 	 */
1644 	(void) printf(gettext("==========================\n"));
1645 
1646 	if (getzoneid() != GLOBAL_ZONEID) {
1647 		/*
1648 		 * TRANSLATION_NOTE
1649 		 * "global" is keyword and not to be translated.
1650 		 */
1651 		cryptoerror(LOG_STDERR, gettext(
1652 		    "policy information for kernel hardware providers is "
1653 		    "available in the %s zone only"), "global");
1654 		return (FAILURE);
1655 	}
1656 
1657 	/* Get the hardware provider list from kernel */
1658 	if (get_dev_list(&pdevlist_kernel) != SUCCESS) {
1659 		cryptoerror(LOG_STDERR, gettext(
1660 		    "failed to retrieve the list of hardware providers.\n"));
1661 		return (FAILURE);
1662 	}
1663 
1664 	if (get_kcfconf_info(&pdevlist_conf, &psoftlist_conf) == FAILURE) {
1665 		cryptoerror(LOG_ERR, "failed to retrieve the providers' "
1666 		    "information from file kcf.conf - %s.",
1667 		    _PATH_KCF_CONF);
1668 		return (FAILURE);
1669 	}
1670 
1671 
1672 	/*
1673 	 * For each hardware provider from kernel, check if it has an entry
1674 	 * in the config file.  If it has an entry, print out the policy from
1675 	 * config file and remove the entry from the hardware provider list
1676 	 * of the config file.  If it does not have an entry in the config
1677 	 * file, no mechanisms of it have been disabled. But, we still call
1678 	 * list_policy_for_hard() to account for the "random" feature.
1679 	 */
1680 	for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) {
1681 		(void) snprintf(provname, sizeof (provname), "%s/%d",
1682 		    pdevlist_kernel->dl_devs[i].le_dev_name,
1683 		    pdevlist_kernel->dl_devs[i].le_dev_instance);
1684 
1685 		found = B_FALSE;
1686 		phead = ptr = pdevlist_conf;
1687 		while (!found && ptr) {
1688 			if (strcmp(ptr->pent->name, provname) == 0) {
1689 				found = B_TRUE;
1690 			} else {
1691 				phead = ptr;
1692 				ptr = ptr->next;
1693 			}
1694 		}
1695 
1696 		if (found) {
1697 			(void) list_policy_for_hard(ptr->pent->name,
1698 			    pdevlist_conf, psoftlist_conf, pdevlist_kernel);
1699 			if (phead == ptr) {
1700 				pdevlist_conf = pdevlist_conf->next;
1701 			} else {
1702 				phead->next = ptr->next;
1703 			}
1704 			free_entry(ptr->pent);
1705 			free(ptr);
1706 		} else {
1707 			(void) list_policy_for_hard(provname, pdevlist_conf,
1708 			    psoftlist_conf, pdevlist_kernel);
1709 		}
1710 	}
1711 
1712 	/*
1713 	 * If there are still entries left in the pdevlist_conf list from
1714 	 * the config file, these providers must have been detached.
1715 	 * Should print out their policy information also.
1716 	 */
1717 	for (ptr = pdevlist_conf; ptr != NULL; ptr = ptr->next) {
1718 		print_kef_policy(ptr->pent->name, ptr->pent, B_FALSE, B_TRUE);
1719 	}
1720 
1721 	free_entrylist(pdevlist_conf);
1722 	free_entrylist(psoftlist_conf);
1723 	free(pdevlist_kernel);
1724 
1725 	return (rc);
1726 }
1727