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