Home | History | Annotate | Line # | Download | only in bio
      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_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             p1 = OPENSSL_malloc((int)num);
    293             if (p1 == NULL)
    294                 goto malloc_error;
    295             OPENSSL_free(ctx->ibuf);
    296             ctx->ibuf = p1;
    297         }
    298         ctx->ibuf_off = 0;
    299         ctx->ibuf_len = (int)num;
    300         memcpy(ctx->ibuf, ptr, (int)num);
    301         ret = 1;
    302         break;
    303     case BIO_C_SET_BUFF_SIZE:
    304         if (ptr != NULL) {
    305             ip = (int *)ptr;
    306             if (*ip == 0) {
    307                 ibs = (int)num;
    308                 obs = ctx->obuf_size;
    309             } else {            /* if (*ip == 1) */
    310 
    311                 ibs = ctx->ibuf_size;
    312                 obs = (int)num;
    313             }
    314         } else {
    315             ibs = (int)num;
    316             obs = (int)num;
    317         }
    318         p1 = ctx->ibuf;
    319         p2 = ctx->obuf;
    320         if ((ibs > DEFAULT_BUFFER_SIZE) && (ibs != ctx->ibuf_size)) {
    321             p1 = OPENSSL_malloc((int)num);
    322             if (p1 == NULL)
    323                 goto malloc_error;
    324         }
    325         if ((obs > DEFAULT_BUFFER_SIZE) && (obs != ctx->obuf_size)) {
    326             p2 = OPENSSL_malloc((int)num);
    327             if (p2 == NULL) {
    328                 if (p1 != ctx->ibuf)
    329                     OPENSSL_free(p1);
    330                 goto malloc_error;
    331             }
    332         }
    333         if (ctx->ibuf != p1) {
    334             OPENSSL_free(ctx->ibuf);
    335             ctx->ibuf = p1;
    336             ctx->ibuf_off = 0;
    337             ctx->ibuf_len = 0;
    338             ctx->ibuf_size = ibs;
    339         }
    340         if (ctx->obuf != p2) {
    341             OPENSSL_free(ctx->obuf);
    342             ctx->obuf = p2;
    343             ctx->obuf_off = 0;
    344             ctx->obuf_len = 0;
    345             ctx->obuf_size = obs;
    346         }
    347         break;
    348     case BIO_C_DO_STATE_MACHINE:
    349         if (b->next_bio == NULL)
    350             return 0;
    351         BIO_clear_retry_flags(b);
    352         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
    353         BIO_copy_next_retry(b);
    354         break;
    355 
    356     case BIO_CTRL_FLUSH:
    357         if (b->next_bio == NULL)
    358             return 0;
    359         if (ctx->obuf_len <= 0) {
    360             ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
    361             break;
    362         }
    363 
    364         for (;;) {
    365             BIO_clear_retry_flags(b);
    366             if (ctx->obuf_len > 0) {
    367                 r = BIO_write(b->next_bio,
    368                               &(ctx->obuf[ctx->obuf_off]), ctx->obuf_len);
    369                 BIO_copy_next_retry(b);
    370                 if (r <= 0)
    371                     return (long)r;
    372                 ctx->obuf_off += r;
    373                 ctx->obuf_len -= r;
    374             } else {
    375                 ctx->obuf_len = 0;
    376                 ctx->obuf_off = 0;
    377                 break;
    378             }
    379         }
    380         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
    381         break;
    382     case BIO_CTRL_DUP:
    383         dbio = (BIO *)ptr;
    384         if (!BIO_set_read_buffer_size(dbio, ctx->ibuf_size) ||
    385             !BIO_set_write_buffer_size(dbio, ctx->obuf_size))
    386             ret = 0;
    387         break;
    388     case BIO_CTRL_PEEK:
    389         /* Ensure there's stuff in the input buffer */
    390         {
    391             char fake_buf[1];
    392             (void)buffer_read(b, fake_buf, 0);
    393         }
    394         if (num > ctx->ibuf_len)
    395             num = ctx->ibuf_len;
    396         memcpy(ptr, &(ctx->ibuf[ctx->ibuf_off]), num);
    397         ret = num;
    398         break;
    399     default:
    400         if (b->next_bio == NULL)
    401             return 0;
    402         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
    403         break;
    404     }
    405     return ret;
    406  malloc_error:
    407     BIOerr(BIO_F_BUFFER_CTRL, ERR_R_MALLOC_FAILURE);
    408     return 0;
    409 }
    410 
    411 static long buffer_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
    412 {
    413     long ret = 1;
    414 
    415     if (b->next_bio == NULL)
    416         return 0;
    417     switch (cmd) {
    418     default:
    419         ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
    420         break;
    421     }
    422     return ret;
    423 }
    424 
    425 static int buffer_gets(BIO *b, char *buf, int size)
    426 {
    427     BIO_F_BUFFER_CTX *ctx;
    428     int num = 0, i, flag;
    429     char *p;
    430 
    431     ctx = (BIO_F_BUFFER_CTX *)b->ptr;
    432     size--;                     /* reserve space for a '\0' */
    433     BIO_clear_retry_flags(b);
    434 
    435     for (;;) {
    436         if (ctx->ibuf_len > 0) {
    437             p = &(ctx->ibuf[ctx->ibuf_off]);
    438             flag = 0;
    439             for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) {
    440                 *(buf++) = p[i];
    441                 if (p[i] == '\n') {
    442                     flag = 1;
    443                     i++;
    444                     break;
    445                 }
    446             }
    447             num += i;
    448             size -= i;
    449             ctx->ibuf_len -= i;
    450             ctx->ibuf_off += i;
    451             if (flag || size == 0) {
    452                 *buf = '\0';
    453                 return num;
    454             }
    455         } else {                /* read another chunk */
    456 
    457             i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size);
    458             if (i <= 0) {
    459                 BIO_copy_next_retry(b);
    460                 *buf = '\0';
    461                 if (i < 0)
    462                     return ((num > 0) ? num : i);
    463                 if (i == 0)
    464                     return num;
    465             }
    466             ctx->ibuf_len = i;
    467             ctx->ibuf_off = 0;
    468         }
    469     }
    470 }
    471 
    472 static int buffer_puts(BIO *b, const char *str)
    473 {
    474     return buffer_write(b, str, strlen(str));
    475 }
    476