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