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 29 log_on_stderr(const char *str) 30 { 31 fprintf(stderr, "%s", str); 32 } 33 34 static void 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 50 fido_log_init(void) 51 { 52 logging = 1; 53 log_handler = log_on_stderr; 54 } 55 56 void 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 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 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 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