Home | History | Annotate | Line # | Download | only in err
      1 /*
      2  * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License 2.0 (the "License").  You may not use
      5  * this file except in compliance with the License.  You can obtain a copy
      6  * in the file LICENSE in the source distribution or at
      7  * https://www.openssl.org/source/license.html
      8  */
      9 
     10 #define OSSL_FORCE_ERR_STATE
     11 
     12 #include <stdio.h>
     13 #include "internal/cryptlib.h"
     14 #include <openssl/crypto.h>
     15 #include <openssl/buffer.h>
     16 #include <openssl/err.h>
     17 #include "err_local.h"
     18 
     19 #define ERR_PRINT_BUF_SIZE 4096
     20 void ERR_print_errors_cb(int (*cb)(const char *str, size_t len, void *u),
     21     void *u)
     22 {
     23     CRYPTO_THREAD_ID tid = CRYPTO_THREAD_get_current_id();
     24     unsigned long l;
     25     const char *file, *data, *func;
     26     int line, flags;
     27 
     28     while ((l = ERR_get_error_all(&file, &line, &func, &data, &flags)) != 0) {
     29         char buf[ERR_PRINT_BUF_SIZE] = "";
     30         char *hex = NULL;
     31         int offset;
     32 
     33         if ((flags & ERR_TXT_STRING) == 0)
     34             data = "";
     35 
     36         hex = ossl_buf2hexstr_sep((const unsigned char *)&tid, sizeof(tid), '\0');
     37         BIO_snprintf(buf, sizeof(buf), "%s:", hex == NULL ? "<null>" : hex);
     38         offset = strlen(buf);
     39         ossl_err_string_int(l, func, buf + offset, sizeof(buf) - offset);
     40         offset += strlen(buf + offset);
     41         BIO_snprintf(buf + offset, sizeof(buf) - offset, ":%s:%d:%s\n",
     42             file, line, data);
     43         OPENSSL_free(hex);
     44         if (cb(buf, strlen(buf), u) <= 0)
     45             break; /* abort outputting the error report */
     46     }
     47 }
     48 
     49 /* auxiliary function for incrementally reporting texts via the error queue */
     50 static void put_error(int lib, const char *func, int reason,
     51     const char *file, int line)
     52 {
     53     ERR_new();
     54     ERR_set_debug(file, line, func);
     55     ERR_set_error(lib, reason, NULL /* no data here, so fmt is NULL */);
     56 }
     57 
     58 #define TYPICAL_MAX_OUTPUT_BEFORE_DATA 100
     59 #define MAX_DATA_LEN (ERR_PRINT_BUF_SIZE - TYPICAL_MAX_OUTPUT_BEFORE_DATA)
     60 void ERR_add_error_txt(const char *separator, const char *txt)
     61 {
     62     const char *file = NULL;
     63     int line;
     64     const char *func = NULL;
     65     const char *data = NULL;
     66     int flags;
     67     unsigned long err = ERR_peek_last_error();
     68 
     69     if (separator == NULL)
     70         separator = "";
     71     if (err == 0)
     72         put_error(ERR_LIB_NONE, NULL, 0, "", 0);
     73 
     74     do {
     75         size_t available_len, data_len;
     76         const char *curr = txt, *next = txt;
     77         const char *leading_separator = separator;
     78         int trailing_separator = 0;
     79         char *tmp;
     80 
     81         ERR_peek_last_error_all(&file, &line, &func, &data, &flags);
     82         if ((flags & ERR_TXT_STRING) == 0) {
     83             data = "";
     84             leading_separator = "";
     85         }
     86         data_len = strlen(data);
     87 
     88         /* workaround for limit of ERR_print_errors_cb() */
     89         if (data_len >= MAX_DATA_LEN
     90             || strlen(separator) >= (size_t)(MAX_DATA_LEN - data_len))
     91             available_len = 0;
     92         else
     93             available_len = MAX_DATA_LEN - data_len - strlen(separator) - 1;
     94         /* MAX_DATA_LEN > available_len >= 0 */
     95 
     96         if (*separator == '\0') {
     97             const size_t len_next = strlen(next);
     98 
     99             if (len_next <= available_len) {
    100                 next += len_next;
    101                 curr = NULL; /* no need to split */
    102             } else {
    103                 next += available_len;
    104                 curr = next; /* will split at this point */
    105             }
    106         } else {
    107             while (*next != '\0' && (size_t)(next - txt) <= available_len) {
    108                 curr = next;
    109                 next = strstr(curr, separator);
    110                 if (next != NULL) {
    111                     next += strlen(separator);
    112                     trailing_separator = *next == '\0';
    113                 } else {
    114                     next = curr + strlen(curr);
    115                 }
    116             }
    117             if ((size_t)(next - txt) <= available_len)
    118                 curr = NULL; /* the above loop implies *next == '\0' */
    119         }
    120         if (curr != NULL) {
    121             /* split error msg at curr since error data would get too long */
    122             if (curr != txt) {
    123                 tmp = OPENSSL_strndup(txt, curr - txt);
    124                 if (tmp == NULL)
    125                     return;
    126                 ERR_add_error_data(2, separator, tmp);
    127                 OPENSSL_free(tmp);
    128             }
    129             put_error(ERR_GET_LIB(err), func, err, file, line);
    130             txt = curr;
    131         } else {
    132             if (trailing_separator) {
    133                 tmp = OPENSSL_strndup(txt, next - strlen(separator) - txt);
    134                 if (tmp == NULL)
    135                     return;
    136                 /* output txt without the trailing separator */
    137                 ERR_add_error_data(2, leading_separator, tmp);
    138                 OPENSSL_free(tmp);
    139             } else {
    140                 ERR_add_error_data(2, leading_separator, txt);
    141             }
    142             txt = next; /* finished */
    143         }
    144     } while (*txt != '\0');
    145 }
    146 
    147 void ERR_add_error_mem_bio(const char *separator, BIO *bio)
    148 {
    149     if (bio != NULL) {
    150         char *str;
    151         long len = BIO_get_mem_data(bio, &str);
    152 
    153         if (len > 0) {
    154             if (str[len - 1] != '\0') {
    155                 if (BIO_write(bio, "", 1) <= 0)
    156                     return;
    157 
    158                 len = BIO_get_mem_data(bio, &str);
    159             }
    160             if (len > 1)
    161                 ERR_add_error_txt(separator, str);
    162         }
    163     }
    164 }
    165 
    166 static int print_bio(const char *str, size_t len, void *bp)
    167 {
    168     return BIO_write((BIO *)bp, str, len);
    169 }
    170 
    171 void ERR_print_errors(BIO *bp)
    172 {
    173     ERR_print_errors_cb(print_bio, bp);
    174 }
    175 
    176 #ifndef OPENSSL_NO_STDIO
    177 void ERR_print_errors_fp(FILE *fp)
    178 {
    179     BIO *bio = BIO_new_fp(fp, BIO_NOCLOSE);
    180     if (bio == NULL)
    181         return;
    182 
    183     ERR_print_errors_cb(print_bio, bio);
    184     BIO_free(bio);
    185 }
    186 #endif
    187