]>
Commit | Line | Data |
---|---|---|
b1322259 | 1 | /* |
f5afac4b | 2 | * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. |
645749ef | 3 | * |
09abbca1 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
b1322259 RS |
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 | |
645749ef RL |
8 | */ |
9 | ||
10 | #include <stdio.h> | |
11 | #include <errno.h> | |
706457b7 | 12 | #include "bio_local.h" |
b39fc560 | 13 | #include "internal/cryptlib.h" |
645749ef RL |
14 | #include <openssl/evp.h> |
15 | ||
0f113f3e | 16 | static int linebuffer_write(BIO *h, const char *buf, int num); |
645749ef RL |
17 | static int linebuffer_read(BIO *h, char *buf, int size); |
18 | static int linebuffer_puts(BIO *h, const char *str); | |
19 | static int linebuffer_gets(BIO *h, char *str, int size); | |
20 | static long linebuffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); | |
21 | static int linebuffer_new(BIO *h); | |
22 | static int linebuffer_free(BIO *data); | |
fce78bd4 | 23 | static long linebuffer_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp); |
645749ef RL |
24 | |
25 | /* A 10k maximum should be enough for most purposes */ | |
0f113f3e | 26 | #define DEFAULT_LINEBUFFER_SIZE 1024*10 |
645749ef RL |
27 | |
28 | /* #define DEBUG */ | |
29 | ||
04f6b0fd | 30 | static const BIO_METHOD methods_linebuffer = { |
0f113f3e MC |
31 | BIO_TYPE_LINEBUFFER, |
32 | "linebuffer", | |
3befffa3 | 33 | bwrite_conv, |
0f113f3e | 34 | linebuffer_write, |
d07aee2c | 35 | bread_conv, |
0f113f3e MC |
36 | linebuffer_read, |
37 | linebuffer_puts, | |
38 | linebuffer_gets, | |
39 | linebuffer_ctrl, | |
40 | linebuffer_new, | |
41 | linebuffer_free, | |
42 | linebuffer_callback_ctrl, | |
43 | }; | |
645749ef | 44 | |
04f6b0fd | 45 | const BIO_METHOD *BIO_f_linebuffer(void) |
0f113f3e | 46 | { |
26a7d938 | 47 | return &methods_linebuffer; |
0f113f3e | 48 | } |
645749ef | 49 | |
0f113f3e MC |
50 | typedef struct bio_linebuffer_ctx_struct { |
51 | char *obuf; /* the output char array */ | |
52 | int obuf_size; /* how big is the output buffer */ | |
53 | int obuf_len; /* how many bytes are in it */ | |
54 | } BIO_LINEBUFFER_CTX; | |
645749ef RL |
55 | |
56 | static int linebuffer_new(BIO *bi) | |
0f113f3e MC |
57 | { |
58 | BIO_LINEBUFFER_CTX *ctx; | |
59 | ||
e077455e | 60 | if ((ctx = OPENSSL_malloc(sizeof(*ctx))) == NULL) |
26a7d938 | 61 | return 0; |
b196e7d9 | 62 | ctx->obuf = OPENSSL_malloc(DEFAULT_LINEBUFFER_SIZE); |
0f113f3e MC |
63 | if (ctx->obuf == NULL) { |
64 | OPENSSL_free(ctx); | |
26a7d938 | 65 | return 0; |
0f113f3e MC |
66 | } |
67 | ctx->obuf_size = DEFAULT_LINEBUFFER_SIZE; | |
68 | ctx->obuf_len = 0; | |
69 | ||
70 | bi->init = 1; | |
71 | bi->ptr = (char *)ctx; | |
72 | bi->flags = 0; | |
208fb891 | 73 | return 1; |
0f113f3e | 74 | } |
645749ef RL |
75 | |
76 | static int linebuffer_free(BIO *a) | |
0f113f3e MC |
77 | { |
78 | BIO_LINEBUFFER_CTX *b; | |
79 | ||
80 | if (a == NULL) | |
26a7d938 | 81 | return 0; |
0f113f3e | 82 | b = (BIO_LINEBUFFER_CTX *)a->ptr; |
b548a1f1 | 83 | OPENSSL_free(b->obuf); |
0f113f3e MC |
84 | OPENSSL_free(a->ptr); |
85 | a->ptr = NULL; | |
86 | a->init = 0; | |
87 | a->flags = 0; | |
208fb891 | 88 | return 1; |
0f113f3e MC |
89 | } |
90 | ||
645749ef | 91 | static int linebuffer_read(BIO *b, char *out, int outl) |
0f113f3e MC |
92 | { |
93 | int ret = 0; | |
94 | ||
95 | if (out == NULL) | |
26a7d938 | 96 | return 0; |
0f113f3e | 97 | if (b->next_bio == NULL) |
26a7d938 | 98 | return 0; |
0f113f3e MC |
99 | ret = BIO_read(b->next_bio, out, outl); |
100 | BIO_clear_retry_flags(b); | |
101 | BIO_copy_next_retry(b); | |
26a7d938 | 102 | return ret; |
0f113f3e | 103 | } |
645749ef RL |
104 | |
105 | static int linebuffer_write(BIO *b, const char *in, int inl) | |
0f113f3e MC |
106 | { |
107 | int i, num = 0, foundnl; | |
108 | BIO_LINEBUFFER_CTX *ctx; | |
109 | ||
110 | if ((in == NULL) || (inl <= 0)) | |
26a7d938 | 111 | return 0; |
0f113f3e MC |
112 | ctx = (BIO_LINEBUFFER_CTX *)b->ptr; |
113 | if ((ctx == NULL) || (b->next_bio == NULL)) | |
26a7d938 | 114 | return 0; |
645749ef | 115 | |
0f113f3e MC |
116 | BIO_clear_retry_flags(b); |
117 | ||
118 | do { | |
119 | const char *p; | |
f11a023a | 120 | char c; |
0f113f3e | 121 | |
f11a023a RL |
122 | for (p = in, c = '\0'; p < in + inl && (c = *p) != '\n'; p++) ; |
123 | if (c == '\n') { | |
0f113f3e MC |
124 | p++; |
125 | foundnl = 1; | |
126 | } else | |
127 | foundnl = 0; | |
128 | ||
129 | /* | |
130 | * If a NL was found and we already have text in the save buffer, | |
131 | * concatenate them and write | |
132 | */ | |
133 | while ((foundnl || p - in > ctx->obuf_size - ctx->obuf_len) | |
134 | && ctx->obuf_len > 0) { | |
135 | int orig_olen = ctx->obuf_len; | |
136 | ||
137 | i = ctx->obuf_size - ctx->obuf_len; | |
138 | if (p - in > 0) { | |
139 | if (i >= p - in) { | |
140 | memcpy(&(ctx->obuf[ctx->obuf_len]), in, p - in); | |
141 | ctx->obuf_len += p - in; | |
142 | inl -= p - in; | |
143 | num += p - in; | |
144 | in = p; | |
145 | } else { | |
146 | memcpy(&(ctx->obuf[ctx->obuf_len]), in, i); | |
147 | ctx->obuf_len += i; | |
148 | inl -= i; | |
149 | in += i; | |
150 | num += i; | |
151 | } | |
152 | } | |
0f113f3e MC |
153 | i = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); |
154 | if (i <= 0) { | |
155 | ctx->obuf_len = orig_olen; | |
156 | BIO_copy_next_retry(b); | |
645749ef | 157 | |
0f113f3e MC |
158 | if (i < 0) |
159 | return ((num > 0) ? num : i); | |
160 | if (i == 0) | |
26a7d938 | 161 | return num; |
0f113f3e | 162 | } |
0f113f3e MC |
163 | if (i < ctx->obuf_len) |
164 | memmove(ctx->obuf, ctx->obuf + i, ctx->obuf_len - i); | |
165 | ctx->obuf_len -= i; | |
166 | } | |
167 | ||
168 | /* | |
169 | * Now that the save buffer is emptied, let's write the input buffer | |
170 | * if a NL was found and there is anything to write. | |
171 | */ | |
172 | if ((foundnl || p - in > ctx->obuf_size) && p - in > 0) { | |
0f113f3e MC |
173 | i = BIO_write(b->next_bio, in, p - in); |
174 | if (i <= 0) { | |
175 | BIO_copy_next_retry(b); | |
0f113f3e MC |
176 | if (i < 0) |
177 | return ((num > 0) ? num : i); | |
178 | if (i == 0) | |
26a7d938 | 179 | return num; |
0f113f3e | 180 | } |
0f113f3e MC |
181 | num += i; |
182 | in += i; | |
183 | inl -= i; | |
184 | } | |
185 | } | |
186 | while (foundnl && inl > 0); | |
187 | /* | |
188 | * We've written as much as we can. The rest of the input buffer, if | |
189 | * any, is text that doesn't and with a NL and therefore needs to be | |
190 | * saved for the next trip. | |
191 | */ | |
192 | if (inl > 0) { | |
193 | memcpy(&(ctx->obuf[ctx->obuf_len]), in, inl); | |
194 | ctx->obuf_len += inl; | |
195 | num += inl; | |
196 | } | |
197 | return num; | |
198 | } | |
645749ef RL |
199 | |
200 | static long linebuffer_ctrl(BIO *b, int cmd, long num, void *ptr) | |
0f113f3e MC |
201 | { |
202 | BIO *dbio; | |
203 | BIO_LINEBUFFER_CTX *ctx; | |
204 | long ret = 1; | |
205 | char *p; | |
206 | int r; | |
207 | int obs; | |
208 | ||
209 | ctx = (BIO_LINEBUFFER_CTX *)b->ptr; | |
210 | ||
211 | switch (cmd) { | |
212 | case BIO_CTRL_RESET: | |
213 | ctx->obuf_len = 0; | |
214 | if (b->next_bio == NULL) | |
26a7d938 | 215 | return 0; |
0f113f3e MC |
216 | ret = BIO_ctrl(b->next_bio, cmd, num, ptr); |
217 | break; | |
218 | case BIO_CTRL_INFO: | |
219 | ret = (long)ctx->obuf_len; | |
220 | break; | |
221 | case BIO_CTRL_WPENDING: | |
222 | ret = (long)ctx->obuf_len; | |
223 | if (ret == 0) { | |
224 | if (b->next_bio == NULL) | |
26a7d938 | 225 | return 0; |
0f113f3e MC |
226 | ret = BIO_ctrl(b->next_bio, cmd, num, ptr); |
227 | } | |
228 | break; | |
229 | case BIO_C_SET_BUFF_SIZE: | |
59088414 TM |
230 | if (num > INT_MAX) |
231 | return 0; | |
0f113f3e MC |
232 | obs = (int)num; |
233 | p = ctx->obuf; | |
234 | if ((obs > DEFAULT_LINEBUFFER_SIZE) && (obs != ctx->obuf_size)) { | |
59088414 | 235 | p = OPENSSL_malloc((size_t)obs); |
0f113f3e | 236 | if (p == NULL) |
e077455e | 237 | return 0; |
0f113f3e MC |
238 | } |
239 | if (ctx->obuf != p) { | |
240 | if (ctx->obuf_len > obs) { | |
241 | ctx->obuf_len = obs; | |
242 | } | |
243 | memcpy(p, ctx->obuf, ctx->obuf_len); | |
244 | OPENSSL_free(ctx->obuf); | |
245 | ctx->obuf = p; | |
246 | ctx->obuf_size = obs; | |
247 | } | |
248 | break; | |
249 | case BIO_C_DO_STATE_MACHINE: | |
250 | if (b->next_bio == NULL) | |
26a7d938 | 251 | return 0; |
0f113f3e MC |
252 | BIO_clear_retry_flags(b); |
253 | ret = BIO_ctrl(b->next_bio, cmd, num, ptr); | |
254 | BIO_copy_next_retry(b); | |
255 | break; | |
256 | ||
257 | case BIO_CTRL_FLUSH: | |
258 | if (b->next_bio == NULL) | |
26a7d938 | 259 | return 0; |
0f113f3e MC |
260 | if (ctx->obuf_len <= 0) { |
261 | ret = BIO_ctrl(b->next_bio, cmd, num, ptr); | |
262 | break; | |
263 | } | |
264 | ||
265 | for (;;) { | |
266 | BIO_clear_retry_flags(b); | |
267 | if (ctx->obuf_len > 0) { | |
268 | r = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); | |
0f113f3e MC |
269 | BIO_copy_next_retry(b); |
270 | if (r <= 0) | |
26a7d938 | 271 | return (long)r; |
0f113f3e MC |
272 | if (r < ctx->obuf_len) |
273 | memmove(ctx->obuf, ctx->obuf + r, ctx->obuf_len - r); | |
274 | ctx->obuf_len -= r; | |
275 | } else { | |
276 | ctx->obuf_len = 0; | |
0f113f3e MC |
277 | break; |
278 | } | |
279 | } | |
280 | ret = BIO_ctrl(b->next_bio, cmd, num, ptr); | |
281 | break; | |
282 | case BIO_CTRL_DUP: | |
283 | dbio = (BIO *)ptr; | |
284 | if (!BIO_set_write_buffer_size(dbio, ctx->obuf_size)) | |
285 | ret = 0; | |
286 | break; | |
287 | default: | |
288 | if (b->next_bio == NULL) | |
26a7d938 | 289 | return 0; |
0f113f3e MC |
290 | ret = BIO_ctrl(b->next_bio, cmd, num, ptr); |
291 | break; | |
292 | } | |
26a7d938 | 293 | return ret; |
0f113f3e | 294 | } |
645749ef | 295 | |
fce78bd4 | 296 | static long linebuffer_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) |
0f113f3e | 297 | { |
0f113f3e | 298 | if (b->next_bio == NULL) |
26a7d938 | 299 | return 0; |
8f2fe32d | 300 | return BIO_callback_ctrl(b->next_bio, cmd, fp); |
0f113f3e | 301 | } |
645749ef RL |
302 | |
303 | static int linebuffer_gets(BIO *b, char *buf, int size) | |
0f113f3e MC |
304 | { |
305 | if (b->next_bio == NULL) | |
26a7d938 K |
306 | return 0; |
307 | return BIO_gets(b->next_bio, buf, size); | |
0f113f3e | 308 | } |
645749ef RL |
309 | |
310 | static int linebuffer_puts(BIO *b, const char *str) | |
0f113f3e | 311 | { |
26a7d938 | 312 | return linebuffer_write(b, str, strlen(str)); |
0f113f3e | 313 | } |