Update copyright year
[openssl.git] / crypto / bio / bf_buff.c
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 #include <stdio.h>
11 #include <errno.h>
12 #include "bio_local.h"
13 #include "internal/cryptlib.h"
14
15 static int buffer_write(BIO *h, const char *buf, int num);
16 static int buffer_read(BIO *h, char *buf, int size);
17 static int buffer_puts(BIO *h, const char *str);
18 static int buffer_gets(BIO *h, char *str, int size);
19 static long buffer_ctrl(BIO *h, int cmd, long arg1, void *arg2);
20 static int buffer_new(BIO *h);
21 static int buffer_free(BIO *data);
22 static long buffer_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp);
23 #define DEFAULT_BUFFER_SIZE     4096
24
25 static const BIO_METHOD methods_buffer = {
26     BIO_TYPE_BUFFER,
27     "buffer",
28     /* TODO: Convert to new style write function */
29     bwrite_conv,
30     buffer_write,
31     /* TODO: Convert to new style read function */
32     bread_conv,
33     buffer_read,
34     buffer_puts,
35     buffer_gets,
36     buffer_ctrl,
37     buffer_new,
38     buffer_free,
39     buffer_callback_ctrl,
40 };
41
42 const BIO_METHOD *BIO_f_buffer(void)
43 {
44     return &methods_buffer;
45 }
46
47 static int buffer_new(BIO *bi)
48 {
49     BIO_F_BUFFER_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
50
51     if (ctx == NULL)
52         return 0;
53     ctx->ibuf_size = DEFAULT_BUFFER_SIZE;
54     ctx->ibuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
55     if (ctx->ibuf == NULL) {
56         OPENSSL_free(ctx);
57         return 0;
58     }
59     ctx->obuf_size = DEFAULT_BUFFER_SIZE;
60     ctx->obuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
61     if (ctx->obuf == NULL) {
62         OPENSSL_free(ctx->ibuf);
63         OPENSSL_free(ctx);
64         return 0;
65     }
66
67     bi->init = 1;
68     bi->ptr = (char *)ctx;
69     bi->flags = 0;
70     return 1;
71 }
72
73 static int buffer_free(BIO *a)
74 {
75     BIO_F_BUFFER_CTX *b;
76
77     if (a == NULL)
78         return 0;
79     b = (BIO_F_BUFFER_CTX *)a->ptr;
80     OPENSSL_free(b->ibuf);
81     OPENSSL_free(b->obuf);
82     OPENSSL_free(a->ptr);
83     a->ptr = NULL;
84     a->init = 0;
85     a->flags = 0;
86     return 1;
87 }
88
89 static int buffer_read(BIO *b, char *out, int outl)
90 {
91     int i, num = 0;
92     BIO_F_BUFFER_CTX *ctx;
93
94     if (out == NULL)
95         return 0;
96     ctx = (BIO_F_BUFFER_CTX *)b->ptr;
97
98     if ((ctx == NULL) || (b->next_bio == NULL))
99         return 0;
100     num = 0;
101     BIO_clear_retry_flags(b);
102
103  start:
104     i = ctx->ibuf_len;
105     /* If there is stuff left over, grab it */
106     if (i != 0) {
107         if (i > outl)
108             i = outl;
109         memcpy(out, &(ctx->ibuf[ctx->ibuf_off]), i);
110         ctx->ibuf_off += i;
111         ctx->ibuf_len -= i;
112         num += i;
113         if (outl == i)
114             return num;
115         outl -= i;
116         out += i;
117     }
118
119     /*
120      * We may have done a partial read. try to do more. We have nothing in
121      * the buffer. If we get an error and have read some data, just return it
122      * and let them retry to get the error again. copy direct to parent
123      * address space
124      */
125     if (outl > ctx->ibuf_size) {
126         for (;;) {
127             i = BIO_read(b->next_bio, out, outl);
128             if (i <= 0) {
129                 BIO_copy_next_retry(b);
130                 if (i < 0)
131                     return ((num > 0) ? num : i);
132                 if (i == 0)
133                     return num;
134             }
135             num += i;
136             if (outl == i)
137                 return num;
138             out += i;
139             outl -= i;
140         }
141     }
142     /* else */
143
144     /* we are going to be doing some buffering */
145     i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size);
146     if (i <= 0) {
147         BIO_copy_next_retry(b);
148         if (i < 0)
149             return ((num > 0) ? num : i);
150         if (i == 0)
151             return num;
152     }
153     ctx->ibuf_off = 0;
154     ctx->ibuf_len = i;
155
156     /* Lets re-read using ourselves :-) */
157     goto start;
158 }
159
160 static int buffer_write(BIO *b, const char *in, int inl)
161 {
162     int i, num = 0;
163     BIO_F_BUFFER_CTX *ctx;
164
165     if ((in == NULL) || (inl <= 0))
166         return 0;
167     ctx = (BIO_F_BUFFER_CTX *)b->ptr;
168     if ((ctx == NULL) || (b->next_bio == NULL))
169         return 0;
170
171     BIO_clear_retry_flags(b);
172  start:
173     i = ctx->obuf_size - (ctx->obuf_len + ctx->obuf_off);
174     /* add to buffer and return */
175     if (i >= inl) {
176         memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, inl);
177         ctx->obuf_len += inl;
178         return (num + inl);
179     }
180     /* else */
181     /* stuff already in buffer, so add to it first, then flush */
182     if (ctx->obuf_len != 0) {
183         if (i > 0) {            /* lets fill it up if we can */
184             memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, i);
185             in += i;
186             inl -= i;
187             num += i;
188             ctx->obuf_len += i;
189         }
190         /* we now have a full buffer needing flushing */
191         for (;;) {
192             i = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]),
193                           ctx->obuf_len);
194             if (i <= 0) {
195                 BIO_copy_next_retry(b);
196
197                 if (i < 0)
198                     return ((num > 0) ? num : i);
199                 if (i == 0)
200                     return num;
201             }
202             ctx->obuf_off += i;
203             ctx->obuf_len -= i;
204             if (ctx->obuf_len == 0)
205                 break;
206         }
207     }
208     /*
209      * we only get here if the buffer has been flushed and we still have
210      * stuff to write
211      */
212     ctx->obuf_off = 0;
213
214     /* we now have inl bytes to write */
215     while (inl >= ctx->obuf_size) {
216         i = BIO_write(b->next_bio, in, inl);
217         if (i <= 0) {
218             BIO_copy_next_retry(b);
219             if (i < 0)
220                 return ((num > 0) ? num : i);
221             if (i == 0)
222                 return num;
223         }
224         num += i;
225         in += i;
226         inl -= i;
227         if (inl == 0)
228             return num;
229     }
230
231     /*
232      * copy the rest into the buffer since we have only a small amount left
233      */
234     goto start;
235 }
236
237 static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr)
238 {
239     BIO *dbio;
240     BIO_F_BUFFER_CTX *ctx;
241     long ret = 1;
242     char *p1, *p2;
243     int r, i, *ip;
244     int ibs, obs;
245
246     ctx = (BIO_F_BUFFER_CTX *)b->ptr;
247
248     switch (cmd) {
249     case BIO_CTRL_RESET:
250         ctx->ibuf_off = 0;
251         ctx->ibuf_len = 0;
252         ctx->obuf_off = 0;
253         ctx->obuf_len = 0;
254         if (b->next_bio == NULL)
255             return 0;
256         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
257         break;
258     case BIO_CTRL_EOF:
259         if (ctx->ibuf_len > 0)
260             return 0;
261         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
262         break;
263     case BIO_CTRL_INFO:
264         ret = (long)ctx->obuf_len;
265         break;
266     case BIO_C_GET_BUFF_NUM_LINES:
267         ret = 0;
268         p1 = ctx->ibuf;
269         for (i = 0; i < ctx->ibuf_len; i++) {
270             if (p1[ctx->ibuf_off + i] == '\n')
271                 ret++;
272         }
273         break;
274     case BIO_CTRL_WPENDING:
275         ret = (long)ctx->obuf_len;
276         if (ret == 0) {
277             if (b->next_bio == NULL)
278                 return 0;
279             ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
280         }
281         break;
282     case BIO_CTRL_PENDING:
283         ret = (long)ctx->ibuf_len;
284         if (ret == 0) {
285             if (b->next_bio == NULL)
286                 return 0;
287             ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
288         }
289         break;
290     case BIO_C_SET_BUFF_READ_DATA:
291         if (num > ctx->ibuf_size) {
292             if (num <= 0)
293                 return 0;
294             p1 = OPENSSL_malloc((size_t)num);
295             if (p1 == NULL)
296                 goto malloc_error;
297             OPENSSL_free(ctx->ibuf);
298             ctx->ibuf = p1;
299         }
300         ctx->ibuf_off = 0;
301         ctx->ibuf_len = (int)num;
302         memcpy(ctx->ibuf, ptr, (int)num);
303         ret = 1;
304         break;
305     case BIO_C_SET_BUFF_SIZE:
306         if (ptr != NULL) {
307             ip = (int *)ptr;
308             if (*ip == 0) {
309                 ibs = (int)num;
310                 obs = ctx->obuf_size;
311             } else {            /* if (*ip == 1) */
312
313                 ibs = ctx->ibuf_size;
314                 obs = (int)num;
315             }
316         } else {
317             ibs = (int)num;
318             obs = (int)num;
319         }
320         p1 = ctx->ibuf;
321         p2 = ctx->obuf;
322         if ((ibs > DEFAULT_BUFFER_SIZE) && (ibs != ctx->ibuf_size)) {
323             if (num <= 0)
324                 return 0;
325             p1 = OPENSSL_malloc((size_t)num);
326             if (p1 == NULL)
327                 goto malloc_error;
328         }
329         if ((obs > DEFAULT_BUFFER_SIZE) && (obs != ctx->obuf_size)) {
330             p2 = OPENSSL_malloc((size_t)num);
331             if (p2 == NULL) {
332                 if (p1 != ctx->ibuf)
333                     OPENSSL_free(p1);
334                 goto malloc_error;
335             }
336         }
337         if (ctx->ibuf != p1) {
338             OPENSSL_free(ctx->ibuf);
339             ctx->ibuf = p1;
340             ctx->ibuf_off = 0;
341             ctx->ibuf_len = 0;
342             ctx->ibuf_size = ibs;
343         }
344         if (ctx->obuf != p2) {
345             OPENSSL_free(ctx->obuf);
346             ctx->obuf = p2;
347             ctx->obuf_off = 0;
348             ctx->obuf_len = 0;
349             ctx->obuf_size = obs;
350         }
351         break;
352     case BIO_C_DO_STATE_MACHINE:
353         if (b->next_bio == NULL)
354             return 0;
355         BIO_clear_retry_flags(b);
356         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
357         BIO_copy_next_retry(b);
358         break;
359
360     case BIO_CTRL_FLUSH:
361         if (b->next_bio == NULL)
362             return 0;
363         if (ctx->obuf_len <= 0) {
364             ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
365             break;
366         }
367
368         for (;;) {
369             BIO_clear_retry_flags(b);
370             if (ctx->obuf_len > 0) {
371                 r = BIO_write(b->next_bio,
372                               &(ctx->obuf[ctx->obuf_off]), ctx->obuf_len);
373                 BIO_copy_next_retry(b);
374                 if (r <= 0)
375                     return (long)r;
376                 ctx->obuf_off += r;
377                 ctx->obuf_len -= r;
378             } else {
379                 ctx->obuf_len = 0;
380                 ctx->obuf_off = 0;
381                 break;
382             }
383         }
384         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
385         break;
386     case BIO_CTRL_DUP:
387         dbio = (BIO *)ptr;
388         if (!BIO_set_read_buffer_size(dbio, ctx->ibuf_size) ||
389             !BIO_set_write_buffer_size(dbio, ctx->obuf_size))
390             ret = 0;
391         break;
392     case BIO_CTRL_PEEK:
393         /* Ensure there's stuff in the input buffer */
394         {
395             char fake_buf[1];
396             (void)buffer_read(b, fake_buf, 0);
397         }
398         if (num > ctx->ibuf_len)
399             num = ctx->ibuf_len;
400         memcpy(ptr, &(ctx->ibuf[ctx->ibuf_off]), num);
401         ret = num;
402         break;
403     default:
404         if (b->next_bio == NULL)
405             return 0;
406         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
407         break;
408     }
409     return ret;
410  malloc_error:
411     ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE);
412     return 0;
413 }
414
415 static long buffer_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
416 {
417     if (b->next_bio == NULL)
418         return 0;
419     return BIO_callback_ctrl(b->next_bio, cmd, fp);
420 }
421
422 static int buffer_gets(BIO *b, char *buf, int size)
423 {
424     BIO_F_BUFFER_CTX *ctx;
425     int num = 0, i, flag;
426     char *p;
427
428     ctx = (BIO_F_BUFFER_CTX *)b->ptr;
429     size--;                     /* reserve space for a '\0' */
430     BIO_clear_retry_flags(b);
431
432     for (;;) {
433         if (ctx->ibuf_len > 0) {
434             p = &(ctx->ibuf[ctx->ibuf_off]);
435             flag = 0;
436             for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) {
437                 *(buf++) = p[i];
438                 if (p[i] == '\n') {
439                     flag = 1;
440                     i++;
441                     break;
442                 }
443             }
444             num += i;
445             size -= i;
446             ctx->ibuf_len -= i;
447             ctx->ibuf_off += i;
448             if (flag || size == 0) {
449                 *buf = '\0';
450                 return num;
451             }
452         } else {                /* read another chunk */
453
454             i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size);
455             if (i <= 0) {
456                 BIO_copy_next_retry(b);
457                 *buf = '\0';
458                 if (i < 0)
459                     return ((num > 0) ? num : i);
460                 if (i == 0)
461                     return num;
462             }
463             ctx->ibuf_len = i;
464             ctx->ibuf_off = 0;
465         }
466     }
467 }
468
469 static int buffer_puts(BIO *b, const char *str)
470 {
471     return buffer_write(b, str, strlen(str));
472 }