7a730954889dadf456bc7968928149a8d8c2bc93
[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     /* 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_INFO:
259         ret = (long)ctx->obuf_len;
260         break;
261     case BIO_C_GET_BUFF_NUM_LINES:
262         ret = 0;
263         p1 = ctx->ibuf;
264         for (i = 0; i < ctx->ibuf_len; i++) {
265             if (p1[ctx->ibuf_off + i] == '\n')
266                 ret++;
267         }
268         break;
269     case BIO_CTRL_WPENDING:
270         ret = (long)ctx->obuf_len;
271         if (ret == 0) {
272             if (b->next_bio == NULL)
273                 return (0);
274             ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
275         }
276         break;
277     case BIO_CTRL_PENDING:
278         ret = (long)ctx->ibuf_len;
279         if (ret == 0) {
280             if (b->next_bio == NULL)
281                 return (0);
282             ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
283         }
284         break;
285     case BIO_C_SET_BUFF_READ_DATA:
286         if (num > ctx->ibuf_size) {
287             p1 = OPENSSL_malloc((int)num);
288             if (p1 == NULL)
289                 goto malloc_error;
290             OPENSSL_free(ctx->ibuf);
291             ctx->ibuf = p1;
292         }
293         ctx->ibuf_off = 0;
294         ctx->ibuf_len = (int)num;
295         memcpy(ctx->ibuf, ptr, (int)num);
296         ret = 1;
297         break;
298     case BIO_C_SET_BUFF_SIZE:
299         if (ptr != NULL) {
300             ip = (int *)ptr;
301             if (*ip == 0) {
302                 ibs = (int)num;
303                 obs = ctx->obuf_size;
304             } else {            /* if (*ip == 1) */
305
306                 ibs = ctx->ibuf_size;
307                 obs = (int)num;
308             }
309         } else {
310             ibs = (int)num;
311             obs = (int)num;
312         }
313         p1 = ctx->ibuf;
314         p2 = ctx->obuf;
315         if ((ibs > DEFAULT_BUFFER_SIZE) && (ibs != ctx->ibuf_size)) {
316             p1 = OPENSSL_malloc((int)num);
317             if (p1 == NULL)
318                 goto malloc_error;
319         }
320         if ((obs > DEFAULT_BUFFER_SIZE) && (obs != ctx->obuf_size)) {
321             p2 = OPENSSL_malloc((int)num);
322             if (p2 == NULL) {
323                 if (p1 != ctx->ibuf)
324                     OPENSSL_free(p1);
325                 goto malloc_error;
326             }
327         }
328         if (ctx->ibuf != p1) {
329             OPENSSL_free(ctx->ibuf);
330             ctx->ibuf = p1;
331             ctx->ibuf_off = 0;
332             ctx->ibuf_len = 0;
333             ctx->ibuf_size = ibs;
334         }
335         if (ctx->obuf != p2) {
336             OPENSSL_free(ctx->obuf);
337             ctx->obuf = p2;
338             ctx->obuf_off = 0;
339             ctx->obuf_len = 0;
340             ctx->obuf_size = obs;
341         }
342         break;
343     case BIO_C_DO_STATE_MACHINE:
344         if (b->next_bio == NULL)
345             return (0);
346         BIO_clear_retry_flags(b);
347         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
348         BIO_copy_next_retry(b);
349         break;
350
351     case BIO_CTRL_FLUSH:
352         if (b->next_bio == NULL)
353             return (0);
354         if (ctx->obuf_len <= 0) {
355             ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
356             break;
357         }
358
359         for (;;) {
360             BIO_clear_retry_flags(b);
361             if (ctx->obuf_len > 0) {
362                 r = BIO_write(b->next_bio,
363                               &(ctx->obuf[ctx->obuf_off]), ctx->obuf_len);
364                 BIO_copy_next_retry(b);
365                 if (r <= 0)
366                     return ((long)r);
367                 ctx->obuf_off += r;
368                 ctx->obuf_len -= r;
369             } else {
370                 ctx->obuf_len = 0;
371                 ctx->obuf_off = 0;
372                 break;
373             }
374         }
375         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
376         break;
377     case BIO_CTRL_DUP:
378         dbio = (BIO *)ptr;
379         if (!BIO_set_read_buffer_size(dbio, ctx->ibuf_size) ||
380             !BIO_set_write_buffer_size(dbio, ctx->obuf_size))
381             ret = 0;
382         break;
383     default:
384         if (b->next_bio == NULL)
385             return (0);
386         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
387         break;
388     }
389     return (ret);
390  malloc_error:
391     BIOerr(BIO_F_BUFFER_CTRL, ERR_R_MALLOC_FAILURE);
392     return (0);
393 }
394
395 static long buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
396 {
397     long ret = 1;
398
399     if (b->next_bio == NULL)
400         return (0);
401     switch (cmd) {
402     default:
403         ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
404         break;
405     }
406     return (ret);
407 }
408
409 static int buffer_gets(BIO *b, char *buf, int size)
410 {
411     BIO_F_BUFFER_CTX *ctx;
412     int num = 0, i, flag;
413     char *p;
414
415     ctx = (BIO_F_BUFFER_CTX *)b->ptr;
416     size--;                     /* reserve space for a '\0' */
417     BIO_clear_retry_flags(b);
418
419     for (;;) {
420         if (ctx->ibuf_len > 0) {
421             p = &(ctx->ibuf[ctx->ibuf_off]);
422             flag = 0;
423             for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) {
424                 *(buf++) = p[i];
425                 if (p[i] == '\n') {
426                     flag = 1;
427                     i++;
428                     break;
429                 }
430             }
431             num += i;
432             size -= i;
433             ctx->ibuf_len -= i;
434             ctx->ibuf_off += i;
435             if (flag || size == 0) {
436                 *buf = '\0';
437                 return (num);
438             }
439         } else {                /* read another chunk */
440
441             i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size);
442             if (i <= 0) {
443                 BIO_copy_next_retry(b);
444                 *buf = '\0';
445                 if (i < 0)
446                     return ((num > 0) ? num : i);
447                 if (i == 0)
448                     return (num);
449             }
450             ctx->ibuf_len = i;
451             ctx->ibuf_off = 0;
452         }
453     }
454 }
455
456 static int buffer_puts(BIO *b, const char *str)
457 {
458     return (buffer_write(b, str, strlen(str)));
459 }