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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * This file comprises the main driver for this tool.
31  * Upon parsing the command verbs from user input, it
32  * branches to the appropriate modules to perform the
33  * requested task.
34  */
35 
36 #include <stdio.h>
37 #include <string.h>
38 #include <ctype.h>
39 #include <malloc.h>
40 #include <libgen.h>
41 #include <errno.h>
42 #include <cryptoutil.h>
43 #include <security/cryptoki.h>
44 #include "common.h"
45 
46 /*
47  * The verbcmd construct allows genericizing information about a verb so
48  * that it is easier to manipulate.  Makes parsing code easier to read,
49  * fix, and extend with new verbs.
50  */
51 typedef struct verbcmd_s {
52 	char	*verb;
53 	int	(*action)(int, char *[]);
54 	int	mode;
55 	char	*synopsis;
56 } verbcmd;
57 
58 /* External declarations for supported verb actions. */
59 extern int	pk_setpin(int argc, char *argv[]);
60 extern int	pk_list(int argc, char *argv[]);
61 extern int	pk_delete(int argc, char *argv[]);
62 extern int	pk_import(int argc, char *argv[]);
63 extern int	pk_export(int argc, char *argv[]);
64 extern int	pk_tokens(int argc, char *argv[]);
65 
66 /* Forward declarations for "built-in" verb actions. */
67 static int	pk_help(int argc, char *argv[]);
68 
69 /* Command structure for verbs and their actions.  Do NOT i18n/l10n. */
70 static verbcmd	cmds[] = {
71 	{ "tokens",	pk_tokens,	0,	"tokens" },
72 	{ "setpin",	pk_setpin,	0,
73 	    "setpin [token=<token>[:<manuf>[:<serial>]]]" },
74 	{ "list",	pk_list,	0,
75 	    "list [token=<token>[:<manuf>[:<serial>]]] "
76 	    "[objtype=private|public|both] [label=<label>]" },
77 	{ "delete",	pk_delete,	0,
78 	    "delete [token=<token>[:<manuf>[:<serial>]]] "
79 	    "{ [objtype=private|public|both] [label=<label>] }" },
80 	{ "import",	pk_import,	0,
81 	    "import [token=<token>[:<manuf>[:<serial>]]] infile=<file>" },
82 	{ "export",	pk_export,	0,
83 	    "export [token=<token>[:<manuf>[:<serial>]]] outfile=<file>" },
84 	{ "-?",		pk_help,	0,	"help\t(help and usage)" },
85 };
86 static int	num_cmds = sizeof (cmds) / sizeof (verbcmd);
87 
88 static char	*prog;
89 static void	usage(void);
90 
91 /*
92  * Usage information.  This function must be updated when new verbs or
93  * options are added.
94  */
95 static void
96 usage(void)
97 {
98 	int	i;
99 
100 	cryptodebug("inside usage");
101 
102 	/* Display this block only in command-line mode. */
103 	(void) fprintf(stdout, gettext("Usage:\n"));
104 	(void) fprintf(stdout, gettext("\t%s -?\t(help and usage)\n"), prog);
105 	(void) fprintf(stdout, gettext("\t%s subcommand [options...]\n"), prog);
106 	(void) fprintf(stdout, gettext("where subcommands may be:\n"));
107 
108 	/* Display only those verbs that match the current tool mode. */
109 	for (i = 0; i < num_cmds; i++) {
110 		/* Do NOT i18n/l10n. */
111 		(void) fprintf(stdout, "\t%s\n", cmds[i].synopsis);
112 	}
113 }
114 
115 /*
116  * Provide help, in the form of displaying the usage.
117  */
118 static int
119 pk_help(int argc, char *argv[])
120 /* ARGSUSED */
121 {
122 	cryptodebug("inside pk_help");
123 
124 	usage();
125 	return (0);
126 }
127 
128 /*
129  * MAIN() -- where all the action is
130  */
131 int
132 main(int argc, char *argv[], char *envp[])
133 /* ARGSUSED2 */
134 {
135 	int	i, found = -1;
136 	int	rv;
137 	int	pk_argc = 0;
138 	char	**pk_argv = NULL;
139 	int	save_errno = 0;
140 
141 	/* Set up for i18n/l10n. */
142 	(void) setlocale(LC_ALL, "");
143 #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D. */
144 #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it isn't. */
145 #endif
146 	(void) textdomain(TEXT_DOMAIN);
147 
148 	/* Get program base name and move pointer over 0th arg. */
149 	prog = basename(argv[0]);
150 	argv++, argc--;
151 
152 	/* Set up for debug and error output. */
153 	cryptodebug_init(prog);
154 
155 	if (argc == 0) {
156 		usage();
157 		return (1);
158 	}
159 
160 	/* Check for help options.  For CLIP-compliance. */
161 	if (argc == 1 && argv[0][0] == '-') {
162 		switch (argv[0][1]) {
163 		case '?':
164 			return (pk_help(argc, argv));
165 		default:
166 			usage();
167 			return (1);
168 		}
169 	}
170 
171 	/* Always turns off Metaslot so that we can see softtoken. */
172 	cryptodebug("disabling Metaslot");
173 	if (setenv("METASLOT_ENABLED", "false", 1) < 0) {
174 		save_errno = errno;
175 		cryptoerror(LOG_STDERR,
176 		    gettext("Disabling Metaslot failed (%s)."),
177 		    strerror(save_errno));
178 		return (1);
179 	}
180 
181 	/* Begin parsing command line. */
182 	cryptodebug("begin parsing command line");
183 	pk_argc = argc;
184 	pk_argv = argv;
185 
186 	/* Check for valid verb (or an abbreviation of it). */
187 	found = -1;
188 	for (i = 0; i < num_cmds; i++) {
189 		if (strcmp(cmds[i].verb, pk_argv[0]) == 0) {
190 			if (found < 0) {
191 				cryptodebug("found cmd %s", cmds[i].verb);
192 				found = i;
193 				break;
194 			} else {
195 				cryptodebug("also found cmd %s, skipping",
196 				    cmds[i].verb);
197 			}
198 		}
199 	}
200 	/* Stop here if no valid verb found. */
201 	if (found < 0) {
202 		cryptoerror(LOG_STDERR, gettext("Invalid verb: %s"),
203 		    pk_argv[0]);
204 		return (1);
205 	}
206 
207 	/* Get to work! */
208 	cryptodebug("begin executing cmd action");
209 	rv = (*cmds[found].action)(pk_argc, pk_argv);
210 	cryptodebug("end executing cmd action");
211 	switch (rv) {
212 	case PK_ERR_NONE:
213 		cryptodebug("subcommand succeeded");
214 		break;		/* Command succeeded, do nothing. */
215 	case PK_ERR_USAGE:
216 		cryptodebug("usage error detected");
217 		usage();
218 		break;
219 	case PK_ERR_QUIT:
220 		cryptodebug("quit command received");
221 		exit(0);
222 		/* NOTREACHED */
223 	case PK_ERR_PK11:
224 		cryptoerror(LOG_STDERR, "%s",
225 		    gettext("Command failed due to PKCS#11 error."));
226 		break;
227 	case PK_ERR_SYSTEM:
228 		cryptoerror(LOG_STDERR, "%s",
229 		    gettext("Command failed due to system error."));
230 		break;
231 	case PK_ERR_OPENSSL:
232 		cryptoerror(LOG_STDERR, "%s",
233 		    gettext("Command failed due to OpenSSL error."));
234 		break;
235 	default:
236 		cryptoerror(LOG_STDERR, "%s (%d).",
237 		    gettext("Unknown error value"), rv);
238 		break;
239 	}
240 	return (rv);
241 }
242