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