1 /*
2  * util.c: utility functions used by OpenSC command line tools.
3  *
4  * Copyright (C) 2011 OpenSC Project developers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 
21 #include "config.h"
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #ifndef _WIN32
27 #include <termios.h>
28 #else
29 #include <conio.h>
30 #endif
31 #include <ctype.h>
32 #include "util.h"
33 #include "ui/notify.h"
34 #include "common/compat_strlcat.h"
35 
36 int
is_string_valid_atr(const char * atr_str)37 is_string_valid_atr(const char *atr_str)
38 {
39 	unsigned char atr[SC_MAX_ATR_SIZE];
40 	size_t atr_len = sizeof(atr);
41 
42 	if (sc_hex_to_bin(atr_str, atr, &atr_len))
43 		return 0;
44 	if (atr_len < 2)
45 		return 0;
46 	if (atr[0] != 0x3B && atr[0] != 0x3F)
47 		return 0;
48 	return 1;
49 }
50 
util_connect_reader(sc_context_t * ctx,sc_reader_t ** reader,const char * reader_id,int do_wait,int verbose)51 int util_connect_reader (sc_context_t *ctx, sc_reader_t **reader,
52 	const char *reader_id, int do_wait, int verbose)
53 {
54 	struct sc_reader *found = NULL;
55 	int r;
56 
57 	setbuf(stderr, NULL);
58 	setbuf(stdout, NULL);
59 
60 	sc_notify_init();
61 
62 	if (verbose) {
63 		ctx->debug = verbose;
64 		sc_ctx_log_to_file(ctx, "stderr");
65 	}
66 
67 	if (do_wait) {
68 		unsigned int event;
69 
70 		if (sc_ctx_get_reader_count(ctx) == 0) {
71 			fprintf(stderr, "Waiting for a reader to be attached...\n");
72 			r = sc_wait_for_event(ctx, SC_EVENT_READER_ATTACHED, &found, &event, -1, NULL);
73 			if (r < 0) {
74 				fprintf(stderr, "Error while waiting for a reader: %s\n", sc_strerror(r));
75 				return r;
76 			}
77 			r = sc_ctx_detect_readers(ctx);
78 			if (r < 0) {
79 				fprintf(stderr, "Error while refreshing readers: %s\n", sc_strerror(r));
80 				return r;
81 			}
82 		}
83 		fprintf(stderr, "Waiting for a card to be inserted...\n");
84 		r = sc_wait_for_event(ctx, SC_EVENT_CARD_INSERTED, &found, &event, -1, NULL);
85 		if (r < 0) {
86 			fprintf(stderr, "Error while waiting for a card: %s\n", sc_strerror(r));
87 			return r;
88 		}
89 		*reader = found;
90 	}
91 	else if (sc_ctx_get_reader_count(ctx) == 0) {
92 		fprintf(stderr, "No smart card readers found.\n");
93 		return SC_ERROR_NO_READERS_FOUND;
94 	}
95 	else   {
96 		if (!reader_id) {
97 			unsigned int i;
98 			/* Automatically try to skip to a reader with a card if reader not specified */
99 			for (i = 0; i < sc_ctx_get_reader_count(ctx); i++) {
100 				*reader = sc_ctx_get_reader(ctx, i);
101 				if (sc_detect_card_presence(*reader) & SC_READER_CARD_PRESENT) {
102 					fprintf(stderr, "Using reader with a card: %s\n", (*reader)->name);
103 					goto autofound;
104 				}
105 			}
106 			/* If no reader had a card, default to the first reader */
107 			*reader = sc_ctx_get_reader(ctx, 0);
108 		}
109 		else {
110 			/* If the reader identifier looks like an ATR, try to find the reader with that card */
111 			if (is_string_valid_atr(reader_id))   {
112 				unsigned char atr_buf[SC_MAX_ATR_SIZE];
113 				size_t atr_buf_len = sizeof(atr_buf);
114 				unsigned int i;
115 
116 				sc_hex_to_bin(reader_id, atr_buf, &atr_buf_len);
117 				/* Loop readers, looking for a card with ATR */
118 				for (i = 0; i < sc_ctx_get_reader_count(ctx); i++) {
119 					struct sc_reader *rdr = sc_ctx_get_reader(ctx, i);
120 
121 					if (!(sc_detect_card_presence(rdr) & SC_READER_CARD_PRESENT))
122 						continue;
123 					else if (rdr->atr.len != atr_buf_len)
124 						continue;
125 					else if (memcmp(rdr->atr.value, atr_buf, rdr->atr.len))
126 						continue;
127 
128 					fprintf(stderr, "Matched ATR in reader: %s\n", rdr->name);
129 					*reader = rdr;
130 					goto autofound;
131 				}
132 			}
133 			else   {
134 				char *endptr = NULL;
135 				unsigned int num;
136 
137 				errno = 0;
138 				num = strtol(reader_id, &endptr, 0);
139 				if (!errno && endptr && *endptr == '\0')
140 					*reader = sc_ctx_get_reader(ctx, num);
141 				else
142 					*reader = sc_ctx_get_reader_by_name(ctx, reader_id);
143 			}
144 		}
145 autofound:
146 		if (!(*reader)) {
147 			fprintf(stderr, "Reader \"%s\" not found (%d reader(s) detected)\n",
148 					reader_id, sc_ctx_get_reader_count(ctx));
149 			return SC_ERROR_READER;
150 		}
151 
152 		if (sc_detect_card_presence(*reader) <= 0) {
153 			fprintf(stderr, "Card not present.\n");
154 			return SC_ERROR_CARD_NOT_PRESENT;
155 		}
156 	}
157 	return SC_SUCCESS;
158 }
159 int
util_connect_card_ex(sc_context_t * ctx,sc_card_t ** cardp,const char * reader_id,int do_wait,int do_lock,int verbose)160 util_connect_card_ex(sc_context_t *ctx, sc_card_t **cardp,
161 		 const char *reader_id, int do_wait, int do_lock, int verbose)
162 {
163 	struct sc_reader *reader = NULL;
164 	struct sc_card *card = NULL;
165 	int r;
166 
167 	r = util_connect_reader(ctx, &reader, reader_id, do_wait, verbose);
168 	if(r)
169 		return r;
170 	if (verbose)
171 		printf("Connecting to card in reader %s...\n", reader->name);
172 	r = sc_connect_card(reader, &card);
173 	if (r < 0) {
174 		fprintf(stderr, "Failed to connect to card: %s\n", sc_strerror(r));
175 		return r;
176 	}
177 
178 	if (verbose)
179 		printf("Using card driver %s.\n", card->driver->name);
180 
181 	if (do_lock) {
182 		r = sc_lock(card);
183 		if (r < 0) {
184 			fprintf(stderr, "Failed to lock card: %s\n", sc_strerror(r));
185 			sc_disconnect_card(card);
186 			return r;
187 		}
188 	}
189 
190 	*cardp = card;
191 	return SC_SUCCESS;
192 }
193 
194 int
util_connect_card(sc_context_t * ctx,sc_card_t ** cardp,const char * reader_id,int do_wait,int verbose)195 util_connect_card(sc_context_t *ctx, sc_card_t **cardp,
196 		 const char *reader_id, int do_wait, int verbose)
197 {
198 	return util_connect_card_ex(ctx, cardp, reader_id, do_wait, 1, verbose);
199 }
200 
util_print_binary(FILE * f,const u8 * buf,int count)201 void util_print_binary(FILE *f, const u8 *buf, int count)
202 {
203 	int i;
204 
205 	for (i = 0; i < count; i++) {
206 		unsigned char c = buf[i];
207 		const char *format;
208 		if (!isprint(c))
209 			format = "\\x%02X";
210 		else
211 			format = "%c";
212 		fprintf(f, format, c);
213 	}
214 	(void) fflush(f);
215 }
216 
util_hex_dump(FILE * f,const u8 * in,int len,const char * sep)217 void util_hex_dump(FILE *f, const u8 *in, int len, const char *sep)
218 {
219 	int i;
220 
221 	for (i = 0; i < len; i++) {
222 		if (sep != NULL && i)
223 			fprintf(f, "%s", sep);
224 		fprintf(f, "%02X", in[i]);
225 	}
226 }
227 
util_hex_dump_asc(FILE * f,const u8 * in,size_t count,int addr)228 void util_hex_dump_asc(FILE *f, const u8 *in, size_t count, int addr)
229 {
230 	int lines = 0;
231 
232  	while (count) {
233 		char ascbuf[17];
234 		size_t i;
235 
236 		if (addr >= 0) {
237 			fprintf(f, "%08X: ", addr);
238 			addr += 16;
239 		}
240 		for (i = 0; i < count && i < 16; i++) {
241 			fprintf(f, "%02X ", *in);
242 			if (isprint(*in))
243 				ascbuf[i] = *in;
244 			else
245 				ascbuf[i] = '.';
246 			in++;
247 		}
248 		count -= i;
249 		ascbuf[i] = 0;
250 		for (; i < 16 && lines; i++)
251 			fprintf(f, "   ");
252 		fprintf(f, "%s\n", ascbuf);
253 		lines++;
254 	}
255 }
256 
257 NORETURN void
util_print_usage_and_die(const char * app_name,const struct option options[],const char * option_help[],const char * args)258 util_print_usage_and_die(const char *app_name, const struct option options[],
259 	const char *option_help[], const char *args)
260 {
261 	int i;
262 	int header_shown = 0;
263 
264 	if (args)
265 		printf("Usage: %s [OPTIONS] %s\n", app_name, args);
266 	else
267 		printf("Usage: %s [OPTIONS]\n", app_name);
268 
269 	for (i = 0; options[i].name; i++) {
270 		char buf[40];
271 		const char *arg_str;
272 
273 		/* Skip "hidden" options */
274 		if (option_help[i] == NULL)
275 			continue;
276 
277 		if (!header_shown++)
278 			printf("Options:\n");
279 
280 		switch (options[i].has_arg) {
281 		case 1:
282 			arg_str = " <arg>";
283 			break;
284 		case 2:
285 			arg_str = " [arg]";
286 			break;
287 		default:
288 			arg_str = "";
289 			break;
290 		}
291 		if (isascii(options[i].val) &&
292 		    isprint(options[i].val) && !isspace(options[i].val))
293 			sprintf(buf, "-%c, --%s%s", options[i].val, options[i].name, arg_str);
294 		else
295 			sprintf(buf, "    --%s%s", options[i].name, arg_str);
296 
297 		/* print the line - wrap if necessary */
298 		if (strlen(buf) > 28) {
299 			printf("  %s\n", buf);
300 			buf[0] = '\0';
301 		}
302 		printf("  %-28s  %s\n", buf, option_help[i]);
303 	}
304 
305 	exit(2);
306 }
307 
util_list_card_drivers(const sc_context_t * ctx)308 int util_list_card_drivers(const sc_context_t *ctx)
309 {
310 	int i;
311 
312 	if (ctx == NULL) {
313 		fprintf(stderr, "Unable to get card drivers!\n");
314 		return 1;
315 	}
316 	if (ctx->card_drivers[0] == NULL) {
317 		fprintf(stderr, "No card drivers installed!\n");
318 		return 1;
319 	}
320 	printf("Available card drivers:\n");
321 	for (i = 0; ctx->card_drivers[i] != NULL; i++) {
322 		printf("  %-16s %s\n", ctx->card_drivers[i]->short_name,
323 		      ctx->card_drivers[i]->name);
324 	}
325 	return 0;
326 }
327 
util_acl_to_str(const sc_acl_entry_t * e)328 const char * util_acl_to_str(const sc_acl_entry_t *e)
329 {
330 	static char line[80], buf[20];
331 	unsigned int acl;
332 
333 	if (e == NULL)
334 		return "N/A";
335 	line[0] = 0;
336 	while (e != NULL) {
337 		acl = e->method;
338 
339 		switch (acl) {
340 		case SC_AC_UNKNOWN:
341 			return "N/A";
342 		case SC_AC_NEVER:
343 			return "NEVR";
344 		case SC_AC_NONE:
345 			return "NONE";
346 		case SC_AC_CHV:
347 			strcpy(buf, "CHV");
348 			if (e->key_ref != SC_AC_KEY_REF_NONE)
349 				sprintf(buf + 3, "%d", e->key_ref);
350 			break;
351 		case SC_AC_TERM:
352 			strcpy(buf, "TERM");
353 			break;
354 		case SC_AC_PRO:
355 			strcpy(buf, "PROT");
356 			break;
357 		case SC_AC_AUT:
358 			strcpy(buf, "AUTH");
359 			if (e->key_ref != SC_AC_KEY_REF_NONE)
360 				sprintf(buf + 4, "%d", e->key_ref);
361 			break;
362 		case SC_AC_SEN:
363 			strcpy(buf, "Sec.Env. ");
364 			if (e->key_ref != SC_AC_KEY_REF_NONE)
365 				sprintf(buf + 3, "#%d", e->key_ref);
366 			break;
367 		case SC_AC_SCB:
368 			strcpy(buf, "Sec.ControlByte ");
369 			if (e->key_ref != SC_AC_KEY_REF_NONE)
370 				sprintf(buf + 3, "Ox%X", e->key_ref);
371 			break;
372 		case SC_AC_IDA:
373 			strcpy(buf, "PKCS#15 AuthID ");
374 			if (e->key_ref != SC_AC_KEY_REF_NONE)
375 				sprintf(buf + 3, "#%d", e->key_ref);
376 			break;
377 		default:
378 			strcpy(buf, "????");
379 			break;
380 		}
381 		strlcat(line, buf, sizeof line);
382 		strlcat(line, " ", sizeof line);
383 		e = e->next;
384 	}
385 	line[(sizeof line)-1] = '\0'; /* make sure it's NUL terminated */
386 	line[strlen(line)-1] = 0; /* get rid of trailing space */
387 	return line;
388 }
389 
390 NORETURN void
util_fatal(const char * fmt,...)391 util_fatal(const char *fmt, ...)
392 {
393 	va_list	ap;
394 
395 	va_start(ap, fmt);
396 	fprintf(stderr, "error: ");
397 	vfprintf(stderr, fmt, ap);
398 	fprintf(stderr, "\nAborting.\n");
399 	va_end(ap);
400 
401 	sc_notify_close();
402 
403 	exit(1);
404 }
405 
406 void
util_error(const char * fmt,...)407 util_error(const char *fmt, ...)
408 {
409 	va_list	ap;
410 
411 	va_start(ap, fmt);
412 	fprintf(stderr, "error: ");
413 	vfprintf(stderr, fmt, ap);
414 	fprintf(stderr, "\n");
415 	va_end(ap);
416 }
417 
418 void
util_warn(const char * fmt,...)419 util_warn(const char *fmt, ...)
420 {
421 	va_list	ap;
422 
423 	va_start(ap, fmt);
424 	fprintf(stderr, "warning: ");
425 	vfprintf(stderr, fmt, ap);
426 	fprintf(stderr, "\n");
427 	va_end(ap);
428 }
429 
430 int
util_getpass(char ** lineptr,size_t * len,FILE * stream)431 util_getpass (char **lineptr, size_t *len, FILE *stream)
432 {
433 #define MAX_PASS_SIZE	128
434 	char *buf;
435 	size_t i;
436 	int ch = 0;
437 #ifndef _WIN32
438 	struct termios old, new;
439 
440 	fflush(stdout);
441 	if (tcgetattr (fileno (stdout), &old) != 0)
442 		return -1;
443 	new = old;
444 	new.c_lflag &= ~ECHO;
445 	if (tcsetattr (fileno (stdout), TCSAFLUSH, &new) != 0)
446 		return -1;
447 #endif
448 
449 	buf = calloc(1, MAX_PASS_SIZE);
450 	if (!buf)
451 		return -1;
452 
453 	for (i = 0; i < MAX_PASS_SIZE - 1; i++) {
454 #ifndef _WIN32
455 		ch = getchar();
456 #else
457 		ch = _getch();
458 #endif
459 		if (ch == 0 || ch == 3)
460 			break;
461 		if (ch == '\n' || ch == '\r')
462 			break;
463 
464 		buf[i] = (char) ch;
465 	}
466 #ifndef _WIN32
467 	tcsetattr (fileno (stdout), TCSAFLUSH, &old);
468 	fputs("\n", stdout);
469 #endif
470 	if (ch == 0 || ch == 3) {
471 		free(buf);
472 		return -1;
473 	}
474 
475 	if (*lineptr && (!len || *len < i+1)) {
476 		free(*lineptr);
477 		*lineptr = NULL;
478 	}
479 
480 	if (*lineptr) {
481 		memcpy(*lineptr,buf,i+1);
482 		memset(buf, 0, MAX_PASS_SIZE);
483 		free(buf);
484 	} else {
485 		*lineptr = buf;
486 		if (len)
487 			*len = MAX_PASS_SIZE;
488 	}
489 	return i;
490 }
491 
492 size_t
util_get_pin(const char * input,const char ** pin)493 util_get_pin(const char *input, const char **pin)
494 {
495 	size_t inputlen = strlen(input);
496 	size_t pinlen = 0;
497 
498 	if(inputlen > 4 && strncasecmp(input, "env:", 4) == 0) {
499 		// Get a PIN from a environment variable
500 		*pin = getenv(input + 4);
501 		pinlen = *pin ? strlen(*pin) : 0;
502 	} else {
503 		//Just use the input
504 		*pin = input;
505 		pinlen = inputlen;
506 	}
507 	return pinlen;
508 }
509