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