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