From 319cee9e2fc6fcf6ad865564eccdac4c55e92c0a Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Wed, 27 Nov 2019 16:02:33 +0100 Subject: [PATCH] BIO: Add BIO_f_prefix(), a text line prefixing filter Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/10531) --- crypto/bio/bf_prefix.c | 207 ++++++++++++++++++++++++++++++++++++++ crypto/bio/build.info | 2 +- doc/man3/BIO_f_prefix.pod | 70 +++++++++++++ include/openssl/bio.h | 11 ++ util/libcrypto.num | 1 + util/other.syms | 3 + 6 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 crypto/bio/bf_prefix.c create mode 100644 doc/man3/BIO_f_prefix.pod diff --git a/crypto/bio/bf_prefix.c b/crypto/bio/bf_prefix.c new file mode 100644 index 0000000000..5727c14950 --- /dev/null +++ b/crypto/bio/bf_prefix.c @@ -0,0 +1,207 @@ +/* + * Copyright 2018-2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include "bio_local.h" + +static int prefix_write(BIO *b, const char *out, size_t outl, + size_t *numwritten); +static int prefix_read(BIO *b, char *buf, size_t size, size_t *numread); +static int prefix_puts(BIO *b, const char *str); +static int prefix_gets(BIO *b, char *str, int size); +static long prefix_ctrl(BIO *b, int cmd, long arg1, void *arg2); +static int prefix_create(BIO *b); +static int prefix_destroy(BIO *b); +static long prefix_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp); + +static const BIO_METHOD prefix_meth = { + BIO_TYPE_BUFFER, + "prefix", + prefix_write, + NULL, + prefix_read, + NULL, + prefix_puts, + prefix_gets, + prefix_ctrl, + prefix_create, + prefix_destroy, + prefix_callback_ctrl, +}; + +const BIO_METHOD *BIO_f_prefix(void) +{ + return &prefix_meth; +} + +typedef struct prefix_ctx_st { + char *prefix; /* Text prefix, given by user */ + unsigned int indent; /* Indentation amount, given by user */ + + int linestart; /* flag to indicate we're at the line start */ +} PREFIX_CTX; + +static int prefix_create(BIO *b) +{ + PREFIX_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx == NULL) + return 0; + + ctx->prefix = NULL; + ctx->indent = 0; + ctx->linestart = 1; + BIO_set_data(b, ctx); + BIO_set_init(b, 1); + return 1; +} + +static int prefix_destroy(BIO *b) +{ + PREFIX_CTX *ctx = BIO_get_data(b); + + OPENSSL_free(ctx->prefix); + OPENSSL_free(ctx); + return 1; +} + +static int prefix_read(BIO *b, char *in, size_t size, size_t *numread) +{ + return BIO_read_ex(BIO_next(b), in, size, numread); +} + +static int prefix_write(BIO *b, const char *out, size_t outl, + size_t *numwritten) +{ + PREFIX_CTX *ctx = BIO_get_data(b); + + if (ctx == NULL) + return 0; + + /* + * If no prefix is set or if it's empty, and no indentation amount is set, + * we've got nothing to do here + */ + if ((ctx->prefix == NULL || *ctx->prefix == '\0') + && ctx->indent == 0) { + /* + * We do note if what comes next will be a new line, though, so we're + * prepared to handle prefix and indentation the next time around. + */ + if (outl > 0) + ctx->linestart = (out[outl-1] == '\n'); + return BIO_write_ex(BIO_next(b), out, outl, numwritten); + } + + *numwritten = 0; + + while (outl > 0) { + size_t i; + char c; + + /* + * If we know that we're at the start of the line, output prefix and + * indentation. + */ + if (ctx->linestart) { + size_t dontcare; + + if (ctx->prefix != NULL + && !BIO_write_ex(BIO_next(b), ctx->prefix, strlen(ctx->prefix), + &dontcare)) + return 0; + BIO_printf(BIO_next(b), "%*s", ctx->indent, ""); + ctx->linestart = 0; + } + + /* Now, go look for the next LF, or the end of the string */ + for (i = 0, c = '\0'; i < outl && (c = out[i]) != '\n'; i++) + continue; + if (c == '\n') + i++; + + /* Output what we found so far */ + while (i > 0) { + size_t num = 0; + + if (!BIO_write_ex(BIO_next(b), out, i, &num)) + return 0; + out += num; + outl -= num; + *numwritten += num; + i -= num; + } + + /* If we found a LF, what follows is a new line, so take note */ + if (c == '\n') + ctx->linestart = 1; + } + + return 1; +} + +static long prefix_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret = 0; + PREFIX_CTX *ctx = BIO_get_data(b); + + if (ctx == NULL) + return -1; + + switch (cmd) { + case BIO_CTRL_SET_PREFIX: + OPENSSL_free(ctx->prefix); + if (ptr == NULL) { + ctx->prefix = NULL; + ret = 1; + } else { + ctx->prefix = OPENSSL_strdup((const char *)ptr); + ret = ctx->prefix != NULL; + } + break; + case BIO_CTRL_SET_INDENT: + if (num >= 0) { + ctx->indent = (unsigned int)num; + ret = 1; + } + break; + case BIO_CTRL_GET_INDENT: + ret = (long)ctx->indent; + break; + default: + /* Commands that we intercept before passing them along */ + switch (cmd) { + case BIO_C_FILE_SEEK: + case BIO_CTRL_RESET: + ctx->linestart = 1; + break; + } + if (BIO_next(b) != NULL) + ret = BIO_ctrl(BIO_next(b), cmd, num, ptr); + break; + } + return ret; +} + +static long prefix_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) +{ + return BIO_callback_ctrl(BIO_next(b), cmd, fp); +} + +static int prefix_gets(BIO *b, char *buf, int size) +{ + return BIO_gets(BIO_next(b), buf, size); +} + +static int prefix_puts(BIO *b, const char *str) +{ + return BIO_write(b, str, strlen(str)); +} diff --git a/crypto/bio/build.info b/crypto/bio/build.info index 3f84bb824c..8e3f530f88 100644 --- a/crypto/bio/build.info +++ b/crypto/bio/build.info @@ -15,4 +15,4 @@ SOURCE[../../libcrypto]=\ # Filters SOURCE[../../libcrypto]=\ - bf_null.c bf_buff.c bf_lbuf.c bf_nbio.c + bf_null.c bf_buff.c bf_lbuf.c bf_nbio.c bf_prefix.c diff --git a/doc/man3/BIO_f_prefix.pod b/doc/man3/BIO_f_prefix.pod new file mode 100644 index 0000000000..b4d0298b2a --- /dev/null +++ b/doc/man3/BIO_f_prefix.pod @@ -0,0 +1,70 @@ +=pod + +=head1 NAME + +BIO_f_prefix, BIO_set_prefix, BIO_set_indent, BIO_get_indent +- prefix BIO filter + +=head1 SYNOPSIS + + #include + + const BIO_METHOD *BIO_f_prefix(void); + long BIO_set_prefix(BIO *b, const char *prefix); + long BIO_set_indent(BIO *b, long indent); + long BIO_get_indent(BIO *b); + +=head1 DESCRIPTION + +BIO_f_cipher() returns the prefix BIO method. This is a filter for +text output, where each line gets automatically prefixed and indented +according to user input. + +The prefix and the indentation are combined. For each line of output +going through this filter, the prefix is output first, then the amount +of additional spaces indicated by the indentation, and then the line +itself. + +By default, there is no prefix, and indentation is set to 0. + +BIO_set_prefix() sets the prefix to be used for future lines of +text, using I. I may be NULL, signifying that there +should be no prefix. If I isn't NULL, this function makes a +copy of it. + +BIO_set_indent() sets the indentation to be used for future lines of +text, using I. Negative values are not allowed. + +BIO_get_indent() gets the current indentation. + +=head1 NOTES + +BIO_set_prefix(), BIO_set_indent() and BIO_get_indent() are +implemented as macros. + +=head1 RETURN VALUES + +BIO_f_prefix() returns the prefix BIO method. + +BIO_set_prefix() returns 1 if the prefix was correctly set, or 0 on +failure. + +BIO_set_indent() returns 1 if the prefix was correctly set, or 0 on +failure. + +BIO_get_indent() returns the current indentation. + +=head1 SEE ALSO + +L + +=head1 COPYRIGHT + +Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + +Licensed under the Apache License 2.0 (the "License"). You may not use +this file except in compliance with the License. You can obtain a copy +in the file LICENSE in the source distribution or at +L. + +=cut diff --git a/include/openssl/bio.h b/include/openssl/bio.h index ed9ecc6cca..50ac82cc31 100644 --- a/include/openssl/bio.h +++ b/include/openssl/bio.h @@ -160,6 +160,11 @@ extern "C" { # define BIO_CTRL_DGRAM_SCTP_WAIT_FOR_DRY 77 # define BIO_CTRL_DGRAM_SCTP_MSG_WAITING 78 +/* BIO_f_prefix controls */ +# define BIO_CTRL_SET_PREFIX 79 +# define BIO_CTRL_SET_INDENT 80 +# define BIO_CTRL_GET_INDENT 81 + # ifndef OPENSSL_NO_KTLS # define BIO_get_ktls_send(b) \ BIO_ctrl(b, BIO_CTRL_GET_KTLS_SEND, 0, NULL) @@ -552,6 +557,11 @@ int BIO_ctrl_reset_read_request(BIO *b); # define BIO_dgram_get_mtu_overhead(b) \ (unsigned int)BIO_ctrl((b), BIO_CTRL_DGRAM_GET_MTU_OVERHEAD, 0, NULL) +/* ctrl macros for BIO_f_prefix */ +# define BIO_set_prefix(b,p) BIO_ctrl((b), BIO_CTRL_SET_PREFIX, 0, (void *)(p)) +# define BIO_set_indent(b,i) BIO_ctrl((b), BIO_CTRL_SET_INDENT, (i), NULL) +# define BIO_get_indent(b) BIO_ctrl((b), BIO_CTRL_GET_INDENT, 0, NULL) + #define BIO_get_ex_new_index(l, p, newf, dupf, freef) \ CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_BIO, l, p, newf, dupf, freef) int BIO_set_ex_data(BIO *bio, int idx, void *data); @@ -630,6 +640,7 @@ const BIO_METHOD *BIO_f_null(void); const BIO_METHOD *BIO_f_buffer(void); const BIO_METHOD *BIO_f_linebuffer(void); const BIO_METHOD *BIO_f_nbio_test(void); +const BIO_METHOD *BIO_f_prefix(void); # ifndef OPENSSL_NO_DGRAM const BIO_METHOD *BIO_s_datagram(void); int BIO_dgram_non_fatal_error(int error); diff --git a/util/libcrypto.num b/util/libcrypto.num index 9c17fc5e25..963181eb37 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4911,3 +4911,4 @@ i2d_X509_PUBKEY_bio ? 3_0_0 EXIST::FUNCTION: RSA_get0_pss_params ? 3_0_0 EXIST::FUNCTION:RSA X509_cmp_timeframe ? 3_0_0 EXIST::FUNCTION: OSSL_CMP_MSG_get0_header ? 3_0_0 EXIST::FUNCTION:CMP +BIO_f_prefix ? 3_0_0 EXIST::FUNCTION: diff --git a/util/other.syms b/util/other.syms index 51b4dfa255..3a8d284e97 100644 --- a/util/other.syms +++ b/util/other.syms @@ -127,6 +127,7 @@ BIO_get_conn_port define BIO_get_conn_ip_family define BIO_get_fd define BIO_get_fp define +BIO_get_indent define BIO_get_info_callback define BIO_get_md define BIO_get_md_ctx define @@ -158,12 +159,14 @@ BIO_set_conn_port define BIO_set_conn_ip_family define BIO_set_fd define BIO_set_fp define +BIO_set_indent define BIO_set_info_callback define BIO_set_md define BIO_set_mem_buf define BIO_set_mem_eof_return define BIO_set_nbio define BIO_set_nbio_accept define +BIO_set_prefix define BIO_set_read_buffer_size define BIO_set_ssl define BIO_set_ssl_mode define -- 2.34.1