1 /*
2  * Copyright (c) 2011, Collabora Ltd.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *     * Redistributions of source code must retain the above
9  *       copyright notice, this list of conditions and the
10  *       following disclaimer.
11  *     * Redistributions in binary form must reproduce the
12  *       above copyright notice, this list of conditions and
13  *       the following disclaimer in the documentation and/or
14  *       other materials provided with the distribution.
15  *     * The names of contributors to this software may not be
16  *       used to endorse or promote products derived from this
17  *       software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
29  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
30  * DAMAGE.
31  *
32  * Author: Stef Walter <stefw@collabora.co.uk>
33  */
34 
35 #include "config.h"
36 
37 #include "compat.h"
38 #include "debug.h"
39 
40 #include <assert.h>
41 #include <ctype.h>
42 #include <limits.h>
43 #include <stdint.h>
44 #include <string.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <unistd.h>
48 
49 #include "message.h"
50 #include "p11-kit.h"
51 #include "tool.h"
52 #include "uri.h"
53 
54 #ifdef ENABLE_NLS
55 #include <libintl.h>
56 #define _(x) dgettext(PACKAGE_NAME, x)
57 #else
58 #define _(x) (x)
59 #endif
60 
61 int p11_kit_list_modules (int argc,
62                           char *argv[]);
63 
64 bool verbose = false;
65 
66 static const char HEXC_LOWER[] = "0123456789abcdef";
67 
68 static char *
hex_encode(const unsigned char * data,size_t n_data)69 hex_encode (const unsigned char *data,
70             size_t n_data)
71 {
72 	char *result;
73 	size_t i;
74 	size_t o;
75 
76 	if ((SIZE_MAX - 1) / 3 < n_data)
77 		return NULL;
78 	result = malloc (n_data * 3 + 1);
79 	if (result == NULL)
80 		return NULL;
81 
82 	for (i = 0, o = 0; i < n_data; i++) {
83 		if (i > 0)
84 			result[o++] = ':';
85 		result[o++] = HEXC_LOWER[data[i] >> 4 & 0xf];
86 		result[o++] = HEXC_LOWER[data[i] & 0xf];
87 	}
88 
89 	result[o] = 0;
90 	return result;
91 }
92 
93 static bool
is_ascii_string(const unsigned char * data,size_t n_data)94 is_ascii_string (const unsigned char *data,
95                  size_t n_data)
96 {
97 	size_t i;
98 
99 	for (i = 0; i < n_data; i++) {
100 		if (!isascii (data[i]) &&
101 		    (data[i] < 0x20 && !isspace (data[i])))
102 			return false;
103 	}
104 
105 	return true;
106 }
107 
108 static void
print_token_info(CK_FUNCTION_LIST_PTR module,CK_SLOT_ID slot_id)109 print_token_info (CK_FUNCTION_LIST_PTR module, CK_SLOT_ID slot_id)
110 {
111 	CK_TOKEN_INFO info;
112 	char *value;
113 	CK_RV rv;
114 
115 	rv = (module->C_GetTokenInfo) (slot_id, &info);
116 	if (rv != CKR_OK) {
117 		p11_message (_("couldn't load module info: %s"), p11_kit_strerror (rv));
118 		return;
119 	}
120 
121 	value = p11_kit_space_strdup (info.label, sizeof (info.label));
122 	printf ("    token: %s\n", value);
123 	free (value);
124 
125 	value = p11_kit_space_strdup (info.manufacturerID, sizeof (info.manufacturerID));
126 	printf ("        manufacturer: %s\n", value);
127 	free (value);
128 
129 	value = p11_kit_space_strdup (info.model, sizeof (info.model));
130 	printf ("        model: %s\n", value);
131 	free (value);
132 
133 	if (is_ascii_string (info.serialNumber, sizeof (info.serialNumber)))
134 		value = p11_kit_space_strdup (info.serialNumber, sizeof (info.serialNumber));
135 	else
136 		value = hex_encode (info.serialNumber, sizeof (info.serialNumber));
137 	printf ("        serial-number: %s\n", value);
138 	free (value);
139 
140 	if (info.hardwareVersion.major || info.hardwareVersion.minor)
141 		printf ("        hardware-version: %d.%d\n",
142 		        info.hardwareVersion.major,
143 		        info.hardwareVersion.minor);
144 
145 	if (info.firmwareVersion.major || info.firmwareVersion.minor)
146 		printf ("        firmware-version: %d.%d\n",
147 		        info.firmwareVersion.major,
148 		        info.firmwareVersion.minor);
149 
150 	printf ("        flags:\n");
151 	#define X(x, y)   if (info.flags & (x)) printf ("               %s\n", (y))
152 	X(CKF_RNG, "rng");
153 	X(CKF_WRITE_PROTECTED, "write-protected");
154 	X(CKF_LOGIN_REQUIRED, "login-required");
155 	X(CKF_USER_PIN_INITIALIZED, "user-pin-initialized");
156 	X(CKF_RESTORE_KEY_NOT_NEEDED, "restore-key-not-needed");
157 	X(CKF_CLOCK_ON_TOKEN, "clock-on-token");
158 	X(CKF_PROTECTED_AUTHENTICATION_PATH, "protected-authentication-path");
159 	X(CKF_DUAL_CRYPTO_OPERATIONS, "dual-crypto-operations");
160 	X(CKF_TOKEN_INITIALIZED, "token-initialized");
161 	X(CKF_SECONDARY_AUTHENTICATION, "secondary-authentication");
162 	X(CKF_USER_PIN_COUNT_LOW, "user-pin-count-low");
163 	X(CKF_USER_PIN_FINAL_TRY, "user-pin-final-try");
164 	X(CKF_USER_PIN_LOCKED, "user-pin-locked");
165 	X(CKF_USER_PIN_TO_BE_CHANGED, "user-pin-to-be-changed");
166 	X(CKF_SO_PIN_COUNT_LOW, "so-pin-count-low");
167 	X(CKF_SO_PIN_FINAL_TRY, "so-pin-final-try");
168 	X(CKF_SO_PIN_LOCKED, "so-pin-locked");
169 	X(CKF_SO_PIN_TO_BE_CHANGED, "so-pin-to-be-changed");
170 	#undef X
171 }
172 
173 static void
print_module_info(CK_FUNCTION_LIST_PTR module)174 print_module_info (CK_FUNCTION_LIST_PTR module)
175 {
176 	CK_SLOT_ID slot_list[256];
177 	CK_ULONG i, count;
178 	CK_INFO info;
179 	char *value;
180 	CK_RV rv;
181 
182 	rv = (module->C_GetInfo) (&info);
183 	if (rv != CKR_OK) {
184 		p11_message (_("couldn't load module info: %s"), p11_kit_strerror (rv));
185 		return;
186 	}
187 
188 	value = p11_kit_space_strdup (info.libraryDescription,
189 	                              sizeof (info.libraryDescription));
190 	printf ("    library-description: %s\n", value);
191 	free (value);
192 
193 	value = p11_kit_space_strdup (info.manufacturerID,
194 	                              sizeof (info.manufacturerID));
195 	printf ("    library-manufacturer: %s\n", value);
196 	free (value);
197 
198 	printf ("    library-version: %d.%d\n",
199 	        info.libraryVersion.major,
200 	        info.libraryVersion.minor);
201 
202 	count = sizeof (slot_list) / sizeof (slot_list[0]);
203 	rv = (module->C_GetSlotList) (CK_TRUE, slot_list, &count);
204 	if (rv != CKR_OK) {
205 		p11_message (_("couldn't load module info: %s"), p11_kit_strerror (rv));
206 		return;
207 	}
208 
209 	for (i = 0; i < count; i++)
210 		print_token_info (module, slot_list[i]);
211 }
212 
213 static int
print_modules(void)214 print_modules (void)
215 {
216 	CK_FUNCTION_LIST_PTR *module_list;
217 	char *name;
218 	char *path;
219 	int i;
220 
221 	module_list = p11_kit_modules_load_and_initialize (0);
222 	if (!module_list)
223 		return 1;
224 
225 	for (i = 0; module_list[i]; i++) {
226 		name = p11_kit_module_get_name (module_list[i]);
227 		path = p11_kit_config_option (module_list[i], "module");
228 
229 		printf ("%s: %s\n",
230 			name ? name : "(null)",
231 			path ? path : "(null)");
232 		print_module_info (module_list[i]);
233 
234 		free (name);
235 		free (path);
236 	}
237 
238 	p11_kit_modules_finalize_and_release (module_list);
239 	return 0;
240 }
241 
242 int
p11_kit_list_modules(int argc,char * argv[])243 p11_kit_list_modules (int argc,
244                       char *argv[])
245 {
246 	int opt;
247 
248 	enum {
249 		opt_verbose = 'v',
250 		opt_quiet = 'q',
251 		opt_list = 'l',
252 		opt_help = 'h',
253 	};
254 
255 	struct option options[] = {
256 		{ "verbose", no_argument, NULL, opt_verbose },
257 		{ "quiet", no_argument, NULL, opt_quiet },
258 		{ "list", no_argument, NULL, opt_list },
259 		{ "help", no_argument, NULL, opt_help },
260 		{ 0 },
261 	};
262 
263 	p11_tool_desc usages[] = {
264 		{ 0, "usage: p11-kit list" },
265 		{ opt_verbose, "show verbose debug output", },
266 		{ opt_quiet, "suppress command output", },
267 		{ 0 },
268 	};
269 
270 	while ((opt = p11_tool_getopt (argc, argv, options)) != -1) {
271 		switch (opt) {
272 
273 		case opt_verbose:
274 			p11_kit_be_loud ();
275 			break;
276 
277 		case opt_quiet:
278 			p11_kit_be_quiet ();
279 			break;
280 
281 		case opt_list:
282 			break;
283 
284 		case opt_help:
285 			p11_tool_usage (usages, options);
286 			return 0;
287 		case '?':
288 			return 2;
289 		default:
290 			assert_not_reached ();
291 			break;
292 		}
293 	}
294 
295 	if (argc - optind != 0) {
296 		p11_message (_("extra arguments specified"));
297 		return 2;
298 	}
299 
300 	return print_modules ();
301 }
302