Coverage Report

Created: 2026-05-30 06:29

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