1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#include <stdio.h> 11e1051a39Sopenharmony_ci#include <string.h> 12e1051a39Sopenharmony_ci#include <errno.h> 13e1051a39Sopenharmony_ci#include "bio_local.h" 14e1051a39Sopenharmony_ci 15e1051a39Sopenharmony_cistatic int prefix_write(BIO *b, const char *out, size_t outl, 16e1051a39Sopenharmony_ci size_t *numwritten); 17e1051a39Sopenharmony_cistatic int prefix_read(BIO *b, char *buf, size_t size, size_t *numread); 18e1051a39Sopenharmony_cistatic int prefix_puts(BIO *b, const char *str); 19e1051a39Sopenharmony_cistatic int prefix_gets(BIO *b, char *str, int size); 20e1051a39Sopenharmony_cistatic long prefix_ctrl(BIO *b, int cmd, long arg1, void *arg2); 21e1051a39Sopenharmony_cistatic int prefix_create(BIO *b); 22e1051a39Sopenharmony_cistatic int prefix_destroy(BIO *b); 23e1051a39Sopenharmony_cistatic long prefix_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp); 24e1051a39Sopenharmony_ci 25e1051a39Sopenharmony_cistatic const BIO_METHOD prefix_meth = { 26e1051a39Sopenharmony_ci BIO_TYPE_BUFFER, 27e1051a39Sopenharmony_ci "prefix", 28e1051a39Sopenharmony_ci prefix_write, 29e1051a39Sopenharmony_ci NULL, 30e1051a39Sopenharmony_ci prefix_read, 31e1051a39Sopenharmony_ci NULL, 32e1051a39Sopenharmony_ci prefix_puts, 33e1051a39Sopenharmony_ci prefix_gets, 34e1051a39Sopenharmony_ci prefix_ctrl, 35e1051a39Sopenharmony_ci prefix_create, 36e1051a39Sopenharmony_ci prefix_destroy, 37e1051a39Sopenharmony_ci prefix_callback_ctrl, 38e1051a39Sopenharmony_ci}; 39e1051a39Sopenharmony_ci 40e1051a39Sopenharmony_ciconst BIO_METHOD *BIO_f_prefix(void) 41e1051a39Sopenharmony_ci{ 42e1051a39Sopenharmony_ci return &prefix_meth; 43e1051a39Sopenharmony_ci} 44e1051a39Sopenharmony_ci 45e1051a39Sopenharmony_citypedef struct prefix_ctx_st { 46e1051a39Sopenharmony_ci char *prefix; /* Text prefix, given by user */ 47e1051a39Sopenharmony_ci unsigned int indent; /* Indentation amount, given by user */ 48e1051a39Sopenharmony_ci 49e1051a39Sopenharmony_ci int linestart; /* flag to indicate we're at the line start */ 50e1051a39Sopenharmony_ci} PREFIX_CTX; 51e1051a39Sopenharmony_ci 52e1051a39Sopenharmony_cistatic int prefix_create(BIO *b) 53e1051a39Sopenharmony_ci{ 54e1051a39Sopenharmony_ci PREFIX_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); 55e1051a39Sopenharmony_ci 56e1051a39Sopenharmony_ci if (ctx == NULL) 57e1051a39Sopenharmony_ci return 0; 58e1051a39Sopenharmony_ci 59e1051a39Sopenharmony_ci ctx->prefix = NULL; 60e1051a39Sopenharmony_ci ctx->indent = 0; 61e1051a39Sopenharmony_ci ctx->linestart = 1; 62e1051a39Sopenharmony_ci BIO_set_data(b, ctx); 63e1051a39Sopenharmony_ci BIO_set_init(b, 1); 64e1051a39Sopenharmony_ci return 1; 65e1051a39Sopenharmony_ci} 66e1051a39Sopenharmony_ci 67e1051a39Sopenharmony_cistatic int prefix_destroy(BIO *b) 68e1051a39Sopenharmony_ci{ 69e1051a39Sopenharmony_ci PREFIX_CTX *ctx = BIO_get_data(b); 70e1051a39Sopenharmony_ci 71e1051a39Sopenharmony_ci OPENSSL_free(ctx->prefix); 72e1051a39Sopenharmony_ci OPENSSL_free(ctx); 73e1051a39Sopenharmony_ci return 1; 74e1051a39Sopenharmony_ci} 75e1051a39Sopenharmony_ci 76e1051a39Sopenharmony_cistatic int prefix_read(BIO *b, char *in, size_t size, size_t *numread) 77e1051a39Sopenharmony_ci{ 78e1051a39Sopenharmony_ci return BIO_read_ex(BIO_next(b), in, size, numread); 79e1051a39Sopenharmony_ci} 80e1051a39Sopenharmony_ci 81e1051a39Sopenharmony_cistatic int prefix_write(BIO *b, const char *out, size_t outl, 82e1051a39Sopenharmony_ci size_t *numwritten) 83e1051a39Sopenharmony_ci{ 84e1051a39Sopenharmony_ci PREFIX_CTX *ctx = BIO_get_data(b); 85e1051a39Sopenharmony_ci 86e1051a39Sopenharmony_ci if (ctx == NULL) 87e1051a39Sopenharmony_ci return 0; 88e1051a39Sopenharmony_ci 89e1051a39Sopenharmony_ci /* 90e1051a39Sopenharmony_ci * If no prefix is set or if it's empty, and no indentation amount is set, 91e1051a39Sopenharmony_ci * we've got nothing to do here 92e1051a39Sopenharmony_ci */ 93e1051a39Sopenharmony_ci if ((ctx->prefix == NULL || *ctx->prefix == '\0') 94e1051a39Sopenharmony_ci && ctx->indent == 0) { 95e1051a39Sopenharmony_ci /* 96e1051a39Sopenharmony_ci * We do note if what comes next will be a new line, though, so we're 97e1051a39Sopenharmony_ci * prepared to handle prefix and indentation the next time around. 98e1051a39Sopenharmony_ci */ 99e1051a39Sopenharmony_ci if (outl > 0) 100e1051a39Sopenharmony_ci ctx->linestart = (out[outl-1] == '\n'); 101e1051a39Sopenharmony_ci return BIO_write_ex(BIO_next(b), out, outl, numwritten); 102e1051a39Sopenharmony_ci } 103e1051a39Sopenharmony_ci 104e1051a39Sopenharmony_ci *numwritten = 0; 105e1051a39Sopenharmony_ci 106e1051a39Sopenharmony_ci while (outl > 0) { 107e1051a39Sopenharmony_ci size_t i; 108e1051a39Sopenharmony_ci char c; 109e1051a39Sopenharmony_ci 110e1051a39Sopenharmony_ci /* 111e1051a39Sopenharmony_ci * If we know that we're at the start of the line, output prefix and 112e1051a39Sopenharmony_ci * indentation. 113e1051a39Sopenharmony_ci */ 114e1051a39Sopenharmony_ci if (ctx->linestart) { 115e1051a39Sopenharmony_ci size_t dontcare; 116e1051a39Sopenharmony_ci 117e1051a39Sopenharmony_ci if (ctx->prefix != NULL 118e1051a39Sopenharmony_ci && !BIO_write_ex(BIO_next(b), ctx->prefix, strlen(ctx->prefix), 119e1051a39Sopenharmony_ci &dontcare)) 120e1051a39Sopenharmony_ci return 0; 121e1051a39Sopenharmony_ci BIO_printf(BIO_next(b), "%*s", ctx->indent, ""); 122e1051a39Sopenharmony_ci ctx->linestart = 0; 123e1051a39Sopenharmony_ci } 124e1051a39Sopenharmony_ci 125e1051a39Sopenharmony_ci /* Now, go look for the next LF, or the end of the string */ 126e1051a39Sopenharmony_ci for (i = 0, c = '\0'; i < outl && (c = out[i]) != '\n'; i++) 127e1051a39Sopenharmony_ci continue; 128e1051a39Sopenharmony_ci if (c == '\n') 129e1051a39Sopenharmony_ci i++; 130e1051a39Sopenharmony_ci 131e1051a39Sopenharmony_ci /* Output what we found so far */ 132e1051a39Sopenharmony_ci while (i > 0) { 133e1051a39Sopenharmony_ci size_t num = 0; 134e1051a39Sopenharmony_ci 135e1051a39Sopenharmony_ci if (!BIO_write_ex(BIO_next(b), out, i, &num)) 136e1051a39Sopenharmony_ci return 0; 137e1051a39Sopenharmony_ci out += num; 138e1051a39Sopenharmony_ci outl -= num; 139e1051a39Sopenharmony_ci *numwritten += num; 140e1051a39Sopenharmony_ci i -= num; 141e1051a39Sopenharmony_ci } 142e1051a39Sopenharmony_ci 143e1051a39Sopenharmony_ci /* If we found a LF, what follows is a new line, so take note */ 144e1051a39Sopenharmony_ci if (c == '\n') 145e1051a39Sopenharmony_ci ctx->linestart = 1; 146e1051a39Sopenharmony_ci } 147e1051a39Sopenharmony_ci 148e1051a39Sopenharmony_ci return 1; 149e1051a39Sopenharmony_ci} 150e1051a39Sopenharmony_ci 151e1051a39Sopenharmony_cistatic long prefix_ctrl(BIO *b, int cmd, long num, void *ptr) 152e1051a39Sopenharmony_ci{ 153e1051a39Sopenharmony_ci long ret = 0; 154e1051a39Sopenharmony_ci PREFIX_CTX *ctx; 155e1051a39Sopenharmony_ci 156e1051a39Sopenharmony_ci if (b == NULL || (ctx = BIO_get_data(b)) == NULL) 157e1051a39Sopenharmony_ci return -1; 158e1051a39Sopenharmony_ci 159e1051a39Sopenharmony_ci switch (cmd) { 160e1051a39Sopenharmony_ci case BIO_CTRL_SET_PREFIX: 161e1051a39Sopenharmony_ci OPENSSL_free(ctx->prefix); 162e1051a39Sopenharmony_ci if (ptr == NULL) { 163e1051a39Sopenharmony_ci ctx->prefix = NULL; 164e1051a39Sopenharmony_ci ret = 1; 165e1051a39Sopenharmony_ci } else { 166e1051a39Sopenharmony_ci ctx->prefix = OPENSSL_strdup((const char *)ptr); 167e1051a39Sopenharmony_ci ret = ctx->prefix != NULL; 168e1051a39Sopenharmony_ci } 169e1051a39Sopenharmony_ci break; 170e1051a39Sopenharmony_ci case BIO_CTRL_SET_INDENT: 171e1051a39Sopenharmony_ci if (num >= 0) { 172e1051a39Sopenharmony_ci ctx->indent = (unsigned int)num; 173e1051a39Sopenharmony_ci ret = 1; 174e1051a39Sopenharmony_ci } 175e1051a39Sopenharmony_ci break; 176e1051a39Sopenharmony_ci case BIO_CTRL_GET_INDENT: 177e1051a39Sopenharmony_ci ret = (long)ctx->indent; 178e1051a39Sopenharmony_ci break; 179e1051a39Sopenharmony_ci default: 180e1051a39Sopenharmony_ci /* Commands that we intercept before passing them along */ 181e1051a39Sopenharmony_ci switch (cmd) { 182e1051a39Sopenharmony_ci case BIO_C_FILE_SEEK: 183e1051a39Sopenharmony_ci case BIO_CTRL_RESET: 184e1051a39Sopenharmony_ci ctx->linestart = 1; 185e1051a39Sopenharmony_ci break; 186e1051a39Sopenharmony_ci } 187e1051a39Sopenharmony_ci if (BIO_next(b) != NULL) 188e1051a39Sopenharmony_ci ret = BIO_ctrl(BIO_next(b), cmd, num, ptr); 189e1051a39Sopenharmony_ci break; 190e1051a39Sopenharmony_ci } 191e1051a39Sopenharmony_ci return ret; 192e1051a39Sopenharmony_ci} 193e1051a39Sopenharmony_ci 194e1051a39Sopenharmony_cistatic long prefix_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) 195e1051a39Sopenharmony_ci{ 196e1051a39Sopenharmony_ci return BIO_callback_ctrl(BIO_next(b), cmd, fp); 197e1051a39Sopenharmony_ci} 198e1051a39Sopenharmony_ci 199e1051a39Sopenharmony_cistatic int prefix_gets(BIO *b, char *buf, int size) 200e1051a39Sopenharmony_ci{ 201e1051a39Sopenharmony_ci return BIO_gets(BIO_next(b), buf, size); 202e1051a39Sopenharmony_ci} 203e1051a39Sopenharmony_ci 204e1051a39Sopenharmony_cistatic int prefix_puts(BIO *b, const char *str) 205e1051a39Sopenharmony_ci{ 206e1051a39Sopenharmony_ci return BIO_write(b, str, strlen(str)); 207e1051a39Sopenharmony_ci} 208