1 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2  * All rights reserved.
3  *
4  * This package is an SSL implementation written
5  * by Eric Young (eay@cryptsoft.com).
6  * The implementation was written so as to conform with Netscapes SSL.
7  *
8  * This library is free for commercial and non-commercial use as long as
9  * the following conditions are aheared to.  The following conditions
10  * apply to all code found in this distribution, be it the RC4, RSA,
11  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
12  * included with this distribution is covered by the same copyright terms
13  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14  *
15  * Copyright remains Eric Young's, and as such any Copyright notices in
16  * the code are not to be removed.
17  * If this package is used in a product, Eric Young should be given attribution
18  * as the author of the parts of the library used.
19  * This can be in the form of a textual message at program startup or
20  * in documentation (online or textual) provided with the package.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  * 1. Redistributions of source code must retain the copyright
26  *    notice, this list of conditions and the following disclaimer.
27  * 2. Redistributions in binary form must reproduce the above copyright
28  *    notice, this list of conditions and the following disclaimer in the
29  *    documentation and/or other materials provided with the distribution.
30  * 3. All advertising materials mentioning features or use of this software
31  *    must display the following acknowledgement:
32  *    "This product includes cryptographic software written by
33  *     Eric Young (eay@cryptsoft.com)"
34  *    The word 'cryptographic' can be left out if the rouines from the library
35  *    being used are not cryptographic related :-).
36  * 4. If you include any Windows specific code (or a derivative thereof) from
37  *    the apps directory (application code) you must include an acknowledgement:
38  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39  *
40  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50  * SUCH DAMAGE.
51  *
52  * The licence and distribution terms for any publically available version or
53  * derivative of this code cannot be changed.  i.e. this code cannot simply be
54  * copied and put under another distribution licence
55  * [including the GNU Public Licence.] */
56 
57 #include <openssl/bio.h>
58 
59 #include <string.h>
60 
61 #include <openssl/buf.h>
62 #include <openssl/err.h>
63 #include <openssl/mem.h>
64 
65 
66 #define DEFAULT_BUFFER_SIZE 4096
67 
68 typedef struct bio_f_buffer_ctx_struct {
69   /* Buffers are setup like this:
70    *
71    * <---------------------- size ----------------------->
72    * +---------------------------------------------------+
73    * | consumed | remaining          | free space        |
74    * +---------------------------------------------------+
75    * <-- off --><------- len ------->
76    */
77 
78   int ibuf_size;  /* how big is the input buffer */
79   int obuf_size;  /* how big is the output buffer */
80 
81   char *ibuf;   /* the char array */
82   int ibuf_len; /* how many bytes are in it */
83   int ibuf_off; /* write/read offset */
84 
85   char *obuf;   /* the char array */
86   int obuf_len; /* how many bytes are in it */
87   int obuf_off; /* write/read offset */
88 } BIO_F_BUFFER_CTX;
89 
buffer_new(BIO * bio)90 static int buffer_new(BIO *bio) {
91   BIO_F_BUFFER_CTX *ctx;
92 
93   ctx = OPENSSL_malloc(sizeof(BIO_F_BUFFER_CTX));
94   if (ctx == NULL) {
95     return 0;
96   }
97   memset(ctx, 0, sizeof(BIO_F_BUFFER_CTX));
98 
99   ctx->ibuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
100   if (ctx->ibuf == NULL) {
101     goto err1;
102   }
103   ctx->obuf = (char *)OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
104   if (ctx->obuf == NULL) {
105     goto err2;
106   }
107   ctx->ibuf_size = DEFAULT_BUFFER_SIZE;
108   ctx->obuf_size = DEFAULT_BUFFER_SIZE;
109 
110   bio->init = 1;
111   bio->ptr = (char *)ctx;
112   return 1;
113 
114 err2:
115   OPENSSL_free(ctx->ibuf);
116 
117 err1:
118   OPENSSL_free(ctx);
119   return 0;
120 }
121 
buffer_free(BIO * bio)122 static int buffer_free(BIO *bio) {
123   BIO_F_BUFFER_CTX *ctx;
124 
125   if (bio == NULL || bio->ptr == NULL) {
126     return 0;
127   }
128 
129   ctx = (BIO_F_BUFFER_CTX *)bio->ptr;
130   OPENSSL_free(ctx->ibuf);
131   OPENSSL_free(ctx->obuf);
132   OPENSSL_free(bio->ptr);
133 
134   bio->ptr = NULL;
135   bio->init = 0;
136   bio->flags = 0;
137 
138   return 1;
139 }
140 
buffer_read(BIO * bio,char * out,int outl)141 static int buffer_read(BIO *bio, char *out, int outl) {
142   int i, num = 0;
143   BIO_F_BUFFER_CTX *ctx;
144 
145   ctx = (BIO_F_BUFFER_CTX *)bio->ptr;
146 
147   if (ctx == NULL || bio->next_bio == NULL) {
148     return 0;
149   }
150 
151   num = 0;
152   BIO_clear_retry_flags(bio);
153 
154   for (;;) {
155     i = ctx->ibuf_len;
156     /* If there is stuff left over, grab it */
157     if (i != 0) {
158       if (i > outl) {
159         i = outl;
160       }
161       memcpy(out, &ctx->ibuf[ctx->ibuf_off], i);
162       ctx->ibuf_off += i;
163       ctx->ibuf_len -= i;
164       num += i;
165       if (outl == i) {
166         return num;
167       }
168       outl -= i;
169       out += i;
170     }
171 
172     /* We may have done a partial read. Try to do more. We have nothing in the
173      * buffer. If we get an error and have read some data, just return it and
174      * let them retry to get the error again. Copy direct to parent address
175      * space */
176     if (outl > ctx->ibuf_size) {
177       for (;;) {
178         i = BIO_read(bio->next_bio, out, outl);
179         if (i <= 0) {
180           BIO_copy_next_retry(bio);
181           if (i < 0) {
182             return (num > 0) ? num : i;
183           }
184           return num;
185         }
186         num += i;
187         if (outl == i) {
188           return num;
189         }
190         out += i;
191         outl -= i;
192       }
193     }
194     /* else */
195 
196     /* we are going to be doing some buffering */
197     i = BIO_read(bio->next_bio, ctx->ibuf, ctx->ibuf_size);
198     if (i <= 0) {
199       BIO_copy_next_retry(bio);
200       if (i < 0) {
201         return (num > 0) ? num : i;
202       }
203       return num;
204     }
205     ctx->ibuf_off = 0;
206     ctx->ibuf_len = i;
207   }
208 }
209 
buffer_write(BIO * b,const char * in,int inl)210 static int buffer_write(BIO *b, const char *in, int inl) {
211   int i, num = 0;
212   BIO_F_BUFFER_CTX *ctx;
213 
214   ctx = (BIO_F_BUFFER_CTX *)b->ptr;
215   if (ctx == NULL || b->next_bio == NULL) {
216     return 0;
217   }
218 
219   BIO_clear_retry_flags(b);
220 
221   for (;;) {
222     i = ctx->obuf_size - (ctx->obuf_off + ctx->obuf_len);
223     /* add to buffer and return */
224     if (i >= inl) {
225       memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, inl);
226       ctx->obuf_len += inl;
227       return num + inl;
228     }
229     /* else */
230     /* stuff already in buffer, so add to it first, then flush */
231     if (ctx->obuf_len != 0) {
232       if (i > 0) {
233         memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, i);
234         in += i;
235         inl -= i;
236         num += i;
237         ctx->obuf_len += i;
238       }
239 
240       /* we now have a full buffer needing flushing */
241       for (;;) {
242         i = BIO_write(b->next_bio, &ctx->obuf[ctx->obuf_off], ctx->obuf_len);
243         if (i <= 0) {
244           BIO_copy_next_retry(b);
245 
246           if (i < 0) {
247             return (num > 0) ? num : i;
248           }
249           return num;
250         }
251         ctx->obuf_off += i;
252         ctx->obuf_len -= i;
253         if (ctx->obuf_len == 0) {
254           break;
255         }
256       }
257     }
258 
259     /* we only get here if the buffer has been flushed and we
260      * still have stuff to write */
261     ctx->obuf_off = 0;
262 
263     /* we now have inl bytes to write */
264     while (inl >= ctx->obuf_size) {
265       i = BIO_write(b->next_bio, in, inl);
266       if (i <= 0) {
267         BIO_copy_next_retry(b);
268         if (i < 0) {
269           return (num > 0) ? num : i;
270         }
271         return num;
272       }
273       num += i;
274       in += i;
275       inl -= i;
276       if (inl == 0) {
277         return num;
278       }
279     }
280 
281     /* copy the rest into the buffer since we have only a small
282      * amount left */
283   }
284 }
285 
buffer_ctrl(BIO * b,int cmd,long num,void * ptr)286 static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr) {
287   BIO_F_BUFFER_CTX *ctx;
288   long ret = 1;
289   char *p1, *p2;
290   int r, *ip;
291   int ibs, obs;
292 
293   ctx = (BIO_F_BUFFER_CTX *)b->ptr;
294 
295   switch (cmd) {
296     case BIO_CTRL_RESET:
297       ctx->ibuf_off = 0;
298       ctx->ibuf_len = 0;
299       ctx->obuf_off = 0;
300       ctx->obuf_len = 0;
301       if (b->next_bio == NULL) {
302         return 0;
303       }
304       ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
305       break;
306 
307     case BIO_CTRL_INFO:
308       ret = ctx->obuf_len;
309       break;
310 
311     case BIO_CTRL_WPENDING:
312       ret = (long)ctx->obuf_len;
313       if (ret == 0) {
314         if (b->next_bio == NULL) {
315           return 0;
316         }
317         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
318       }
319       break;
320 
321     case BIO_CTRL_PENDING:
322       ret = (long)ctx->ibuf_len;
323       if (ret == 0) {
324         if (b->next_bio == NULL) {
325           return 0;
326         }
327         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
328       }
329       break;
330 
331     case BIO_C_SET_BUFF_SIZE:
332       ip = (int *)ptr;
333       if (*ip == 0) {
334         ibs = (int)num;
335         obs = ctx->obuf_size;
336       } else /* if (*ip == 1) */ {
337         ibs = ctx->ibuf_size;
338         obs = (int)num;
339       }
340       p1 = ctx->ibuf;
341       p2 = ctx->obuf;
342       if (ibs > DEFAULT_BUFFER_SIZE && ibs != ctx->ibuf_size) {
343         p1 = (char *)OPENSSL_malloc(ibs);
344         if (p1 == NULL) {
345           goto malloc_error;
346         }
347       }
348       if (obs > DEFAULT_BUFFER_SIZE && obs != ctx->obuf_size) {
349         p2 = (char *)OPENSSL_malloc(obs);
350         if (p2 == NULL) {
351           if (p1 != ctx->ibuf) {
352             OPENSSL_free(p1);
353           }
354           goto malloc_error;
355         }
356       }
357 
358       if (ctx->ibuf != p1) {
359         OPENSSL_free(ctx->ibuf);
360         ctx->ibuf = p1;
361         ctx->ibuf_size = ibs;
362       }
363       ctx->ibuf_off = 0;
364       ctx->ibuf_len = 0;
365 
366       if (ctx->obuf != p2) {
367         OPENSSL_free(ctx->obuf);
368         ctx->obuf = p2;
369         ctx->obuf_size = obs;
370       }
371       ctx->obuf_off = 0;
372       ctx->obuf_len = 0;
373       break;
374 
375     case BIO_CTRL_FLUSH:
376       if (b->next_bio == NULL) {
377         return 0;
378       }
379 
380       while (ctx->obuf_len > 0) {
381         BIO_clear_retry_flags(b);
382         r = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]),
383                       ctx->obuf_len);
384         BIO_copy_next_retry(b);
385         if (r <= 0) {
386           return r;
387         }
388         ctx->obuf_off += r;
389         ctx->obuf_len -= r;
390       }
391 
392       ctx->obuf_len = 0;
393       ctx->obuf_off = 0;
394       ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
395       break;
396 
397     default:
398       if (b->next_bio == NULL) {
399         return 0;
400       }
401       BIO_clear_retry_flags(b);
402       ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
403       BIO_copy_next_retry(b);
404       break;
405   }
406   return ret;
407 
408 malloc_error:
409   OPENSSL_PUT_ERROR(BIO, buffer_ctrl, ERR_R_MALLOC_FAILURE);
410   return 0;
411 }
412 
buffer_callback_ctrl(BIO * b,int cmd,bio_info_cb fp)413 static long buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb fp) {
414   long ret = 1;
415 
416   if (b->next_bio == NULL) {
417     return 0;
418   }
419 
420   switch (cmd) {
421     default:
422       ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
423       break;
424   }
425   return ret;
426 }
427 
buffer_gets(BIO * b,char * buf,int size)428 static int buffer_gets(BIO *b, char *buf, int size) {
429   BIO_F_BUFFER_CTX *ctx;
430   int num = 0, i, flag;
431   char *p;
432 
433   ctx = (BIO_F_BUFFER_CTX *)b->ptr;
434   if (buf == NULL || size <= 0) {
435     return 0;
436   }
437 
438   size--; /* reserve space for a '\0' */
439   BIO_clear_retry_flags(b);
440 
441   for (;;) {
442     if (ctx->ibuf_len > 0) {
443       p = &ctx->ibuf[ctx->ibuf_off];
444       flag = 0;
445       for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) {
446         *(buf++) = p[i];
447         if (p[i] == '\n') {
448           flag = 1;
449           i++;
450           break;
451         }
452       }
453       num += i;
454       size -= i;
455       ctx->ibuf_len -= i;
456       ctx->ibuf_off += i;
457       if (flag || size == 0) {
458         *buf = '\0';
459         return num;
460       }
461     } else /* read another chunk */
462     {
463       i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size);
464       if (i <= 0) {
465         BIO_copy_next_retry(b);
466         *buf = '\0';
467         if (i < 0) {
468           return (num > 0) ? num : i;
469         }
470         return num;
471       }
472       ctx->ibuf_len = i;
473       ctx->ibuf_off = 0;
474     }
475   }
476 }
477 
buffer_puts(BIO * b,const char * str)478 static int buffer_puts(BIO *b, const char *str) {
479   return buffer_write(b, str, strlen(str));
480 }
481 
482 static const BIO_METHOD methods_buffer = {
483     BIO_TYPE_BUFFER, "buffer",             buffer_write, buffer_read,
484     buffer_puts,     buffer_gets,          buffer_ctrl,  buffer_new,
485     buffer_free,     buffer_callback_ctrl,
486 };
487 
BIO_f_buffer(void)488 const BIO_METHOD *BIO_f_buffer(void) { return &methods_buffer; }
489 
BIO_set_read_buffer_size(BIO * bio,int buffer_size)490 int BIO_set_read_buffer_size(BIO *bio, int buffer_size) {
491   return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 0);
492 }
493 
BIO_set_write_buffer_size(BIO * bio,int buffer_size)494 int BIO_set_write_buffer_size(BIO *bio, int buffer_size) {
495   return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 1);
496 }
497