1 1.1 christos /* 2 1.1 christos * Copyright 2017-2025 The OpenSSL Project Authors. All Rights Reserved. 3 1.1 christos * 4 1.1 christos * Licensed under the Apache License 2.0 (the "License"). You may not use 5 1.1 christos * this file except in compliance with the License. You can obtain a copy 6 1.1 christos * in the file LICENSE in the source distribution or at 7 1.1 christos * https://www.openssl.org/source/license.html 8 1.1 christos */ 9 1.1 christos 10 1.1 christos #include <string.h> 11 1.1 christos #include <openssl/opensslconf.h> 12 1.1 christos #include <openssl/trace.h> 13 1.1 christos #include "apps.h" 14 1.1 christos #include "../testutil.h" 15 1.1 christos 16 1.1 christos #ifndef OPENSSL_NO_TRACE 17 1.1 christos typedef struct tracedata_st { 18 1.1 christos BIO *bio; 19 1.1.1.2 christos unsigned int ingroup : 1; 20 1.1 christos } tracedata; 21 1.1 christos 22 1.1 christos static size_t internal_trace_cb(const char *buf, size_t cnt, 23 1.1.1.2 christos int category, int cmd, void *vdata) 24 1.1 christos { 25 1.1 christos int ret = 0; 26 1.1 christos tracedata *trace_data = vdata; 27 1.1 christos char buffer[256], *hex; 28 1.1 christos CRYPTO_THREAD_ID tid; 29 1.1 christos 30 1.1 christos switch (cmd) { 31 1.1 christos case OSSL_TRACE_CTRL_BEGIN: 32 1.1 christos trace_data->ingroup = 1; 33 1.1 christos 34 1.1 christos tid = CRYPTO_THREAD_get_current_id(); 35 1.1 christos hex = OPENSSL_buf2hexstr((const unsigned char *)&tid, sizeof(tid)); 36 1.1 christos BIO_snprintf(buffer, sizeof(buffer), "TRACE[%s]:%s: ", 37 1.1.1.2 christos hex, OSSL_trace_get_category_name(category)); 38 1.1 christos OPENSSL_free(hex); 39 1.1 christos BIO_set_prefix(trace_data->bio, buffer); 40 1.1 christos break; 41 1.1 christos case OSSL_TRACE_CTRL_WRITE: 42 1.1 christos ret = BIO_write(trace_data->bio, buf, cnt); 43 1.1 christos break; 44 1.1 christos case OSSL_TRACE_CTRL_END: 45 1.1 christos trace_data->ingroup = 0; 46 1.1 christos 47 1.1 christos BIO_set_prefix(trace_data->bio, NULL); 48 1.1 christos break; 49 1.1 christos } 50 1.1 christos 51 1.1 christos return ret < 0 ? 0 : ret; 52 1.1 christos } 53 1.1 christos 54 1.1 christos DEFINE_STACK_OF(tracedata) 55 1.1 christos static STACK_OF(tracedata) *trace_data_stack; 56 1.1 christos 57 1.1 christos static void tracedata_free(tracedata *data) 58 1.1 christos { 59 1.1 christos BIO_free_all(data->bio); 60 1.1 christos OPENSSL_free(data); 61 1.1 christos } 62 1.1 christos 63 1.1 christos static STACK_OF(tracedata) *trace_data_stack; 64 1.1 christos 65 1.1 christos static void cleanup_trace(void) 66 1.1 christos { 67 1.1 christos sk_tracedata_pop_free(trace_data_stack, tracedata_free); 68 1.1 christos } 69 1.1 christos 70 1.1 christos static void setup_trace_category(int category) 71 1.1 christos { 72 1.1 christos BIO *channel; 73 1.1 christos tracedata *trace_data; 74 1.1 christos BIO *bio = NULL; 75 1.1 christos 76 1.1 christos if (OSSL_trace_enabled(category)) 77 1.1 christos return; 78 1.1 christos 79 1.1 christos bio = BIO_new(BIO_f_prefix()); 80 1.1 christos channel = BIO_push(bio, 81 1.1.1.2 christos BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT)); 82 1.1 christos trace_data = OPENSSL_zalloc(sizeof(*trace_data)); 83 1.1 christos 84 1.1 christos if (trace_data == NULL 85 1.1 christos || bio == NULL 86 1.1 christos || (trace_data->bio = channel) == NULL 87 1.1 christos || OSSL_trace_set_callback(category, internal_trace_cb, 88 1.1.1.2 christos trace_data) 89 1.1.1.2 christos == 0 90 1.1 christos || sk_tracedata_push(trace_data_stack, trace_data) == 0) { 91 1.1 christos 92 1.1 christos fprintf(stderr, 93 1.1.1.2 christos "warning: unable to setup trace callback for category '%s'.\n", 94 1.1.1.2 christos OSSL_trace_get_category_name(category)); 95 1.1 christos 96 1.1 christos OPENSSL_free(trace_data); 97 1.1 christos OSSL_trace_set_callback(category, NULL, NULL); 98 1.1 christos BIO_free_all(channel); 99 1.1 christos } 100 1.1 christos } 101 1.1 christos 102 1.1 christos static void setup_trace(const char *str) 103 1.1 christos { 104 1.1 christos char *val; 105 1.1 christos 106 1.1 christos /* 107 1.1 christos * We add this handler as early as possible to ensure it's executed 108 1.1 christos * as late as possible, i.e. after the TRACE code has done its cleanup 109 1.1 christos * (which happens last in OPENSSL_cleanup). 110 1.1 christos */ 111 1.1 christos atexit(cleanup_trace); 112 1.1 christos 113 1.1 christos trace_data_stack = sk_tracedata_new_null(); 114 1.1 christos val = OPENSSL_strdup(str); 115 1.1 christos 116 1.1 christos if (val != NULL) { 117 1.1 christos char *valp = val; 118 1.1 christos char *item; 119 1.1 christos 120 1.1 christos for (valp = val; (item = strtok(valp, ",")) != NULL; valp = NULL) { 121 1.1 christos int category = OSSL_trace_get_category_num(item); 122 1.1 christos 123 1.1 christos if (category == OSSL_TRACE_CATEGORY_ALL) { 124 1.1 christos while (++category < OSSL_TRACE_CATEGORY_NUM) 125 1.1 christos setup_trace_category(category); 126 1.1 christos break; 127 1.1 christos } else if (category > 0) { 128 1.1 christos setup_trace_category(category); 129 1.1 christos } else { 130 1.1 christos fprintf(stderr, 131 1.1.1.2 christos "warning: unknown trace category: '%s'.\n", item); 132 1.1 christos } 133 1.1 christos } 134 1.1 christos } 135 1.1 christos 136 1.1 christos OPENSSL_free(val); 137 1.1 christos } 138 1.1 christos #endif /* OPENSSL_NO_TRACE */ 139 1.1 christos 140 1.1 christos int global_init(void) 141 1.1 christos { 142 1.1 christos #ifndef OPENSSL_NO_TRACE 143 1.1 christos setup_trace(getenv("OPENSSL_TRACE")); 144 1.1 christos #endif 145 1.1 christos 146 1.1 christos return 1; 147 1.1 christos } 148