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 25static TLS int logging; 26static TLS fido_log_handler_t *log_handler; 27 28static void 29log_on_stderr(const char *str) 30{ 31 fprintf(stderr, "%s", str); 32} 33 34static void 35do_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 49void 50fido_log_init(void) 51{ 52 logging = 1; 53 log_handler = log_on_stderr; 54} 55 56void 57fido_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 69void 70fido_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 99void 100fido_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 115void 116fido_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