1 /*
2 * Copyright (c) 2018-2021 Yubico AB. All rights reserved.
3 * Use of this source code is governed by a BSD-style
4 * license that can be found in the LICENSE file.
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8 #undef _GNU_SOURCE /* XSI strerror_r() */
9
10 #include <stdarg.h>
11 #include <stdio.h>
12
13 #include "fido.h"
14
15 #ifndef FIDO_NO_DIAGNOSTIC
16
17 #define XXDLEN 32
18 #define XXDROW 128
19 #define LINELEN 256
20
21 #ifndef TLS
22 #define TLS
23 #endif
24
25 static TLS int logging;
26 static TLS fido_log_handler_t *log_handler;
27
28 static void
log_on_stderr(const char * str)29 log_on_stderr(const char *str)
30 {
31 fprintf(stderr, "%s", str);
32 }
33
34 static void
do_log(const char * suffix,const char * fmt,va_list args)35 do_log(const char *suffix, const char *fmt, va_list args)
36 {
37 char line[LINELEN], body[LINELEN];
38
39 vsnprintf(body, sizeof(body), fmt, args);
40
41 if (suffix != NULL)
42 snprintf(line, sizeof(line), "%.180s: %.70s\n", body, suffix);
43 else
44 snprintf(line, sizeof(line), "%.180s\n", body);
45
46 log_handler(line);
47 }
48
49 void
fido_log_init(void)50 fido_log_init(void)
51 {
52 logging = 1;
53 log_handler = log_on_stderr;
54 }
55
56 void
fido_log_debug(const char * fmt,...)57 fido_log_debug(const char *fmt, ...)
58 {
59 va_list args;
60
61 if (!logging || log_handler == NULL)
62 return;
63
64 va_start(args, fmt);
65 do_log(NULL, fmt, args);
66 va_end(args);
67 }
68
69 void
fido_log_xxd(const void * buf,size_t count,const char * fmt,...)70 fido_log_xxd(const void *buf, size_t count, const char *fmt, ...)
71 {
72 const uint8_t *ptr = buf;
73 char row[XXDROW], xxd[XXDLEN];
74 va_list args;
75
76 if (!logging || log_handler == NULL)
77 return;
78
79 snprintf(row, sizeof(row), "buf=%p, len=%zu", buf, count);
80 va_start(args, fmt);
81 do_log(row, fmt, args);
82 va_end(args);
83 *row = '\0';
84
85 for (size_t i = 0; i < count; i++) {
86 *xxd = '\0';
87 if (i % 16 == 0)
88 snprintf(xxd, sizeof(xxd), "%04zu: %02x", i, *ptr++);
89 else
90 snprintf(xxd, sizeof(xxd), " %02x", *ptr++);
91 strlcat(row, xxd, sizeof(row));
92 if (i % 16 == 15 || i == count - 1) {
93 fido_log_debug("%s", row);
94 *row = '\0';
95 }
96 }
97 }
98
99 void
fido_log_error(int errnum,const char * fmt,...)100 fido_log_error(int errnum, const char *fmt, ...)
101 {
102 char errstr[LINELEN];
103 va_list args;
104
105 if (!logging || log_handler == NULL)
106 return;
107 if (strerror_r(errnum, errstr, sizeof(errstr)) != 0)
108 snprintf(errstr, sizeof(errstr), "error %d", errnum);
109
110 va_start(args, fmt);
111 do_log(errstr, fmt, args);
112 va_end(args);
113 }
114
115 void
fido_set_log_handler(fido_log_handler_t * handler)116 fido_set_log_handler(fido_log_handler_t *handler)
117 {
118 if (handler != NULL)
119 log_handler = handler;
120 }
121
122 #endif /* !FIDO_NO_DIAGNOSTIC */
123