Branch data Line data Source code
1 : : /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 : : /* egg-buffer.c - Generic data buffer, used by openssh, gnome-keyring
3 : :
4 : : Copyright (C) 2007 Stefan Walter
5 : :
6 : : The Gnome Keyring Library is free software; you can redistribute it and/or
7 : : modify it under the terms of the GNU Library General Public License as
8 : : published by the Free Software Foundation; either version 2 of the
9 : : License, or (at your option) any later version.
10 : :
11 : : The Gnome Keyring Library is distributed in the hope that it will be useful,
12 : : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : Library General Public License for more details.
15 : :
16 : : You should have received a copy of the GNU Library General Public
17 : : License along with the Gnome Library; see the file COPYING.LIB. If not,
18 : : <http://www.gnu.org/licenses/>.
19 : :
20 : : Author: Stef Walter <stef@memberwebs.com>
21 : : */
22 : : #include "config.h"
23 : :
24 : : #include <string.h>
25 : : #include <stdarg.h>
26 : :
27 : : #include "egg-buffer.h"
28 : :
29 : : #define DEFAULT_ALLOCATOR ((EggBufferAllocator)realloc)
30 : :
31 : : int
32 : 0 : egg_buffer_init (EggBuffer *buffer, size_t reserve)
33 : : {
34 : 0 : return egg_buffer_init_full (buffer, reserve, NULL);
35 : : }
36 : :
37 : : int
38 : 0 : egg_buffer_init_full (EggBuffer *buffer, size_t reserve, EggBufferAllocator allocator)
39 : : {
40 : 0 : memset (buffer, 0, sizeof (*buffer));
41 : :
42 : 0 : if (!allocator)
43 : 0 : allocator = DEFAULT_ALLOCATOR;
44 : 0 : if (reserve == 0)
45 : 0 : reserve = 64;
46 : :
47 : 0 : buffer->buf = (allocator) (NULL, reserve);
48 : 0 : if (!buffer->buf) {
49 : 0 : buffer->failures++;
50 : 0 : return 0;
51 : : }
52 : :
53 : 0 : buffer->len = 0;
54 : 0 : buffer->allocated_len = reserve;
55 : 0 : buffer->failures = 0;
56 : 0 : buffer->allocator = allocator;
57 : :
58 : 0 : return 1;
59 : : }
60 : :
61 : : void
62 : 0 : egg_buffer_init_static (EggBuffer* buffer, const unsigned char *buf, size_t len)
63 : : {
64 : 0 : memset (buffer, 0, sizeof (*buffer));
65 : :
66 : 0 : buffer->buf = (unsigned char*)buf;
67 : 0 : buffer->len = len;
68 : 0 : buffer->allocated_len = len;
69 : 0 : buffer->failures = 0;
70 : :
71 : : /* A null allocator, and the buffer can't change in size */
72 : 0 : buffer->allocator = NULL;
73 : 0 : }
74 : :
75 : : void
76 : 0 : egg_buffer_init_allocated (EggBuffer *buffer, unsigned char *buf, size_t len,
77 : : EggBufferAllocator allocator)
78 : : {
79 : 0 : memset (buffer, 0, sizeof (*buffer));
80 : :
81 : 0 : if (!allocator)
82 : 0 : allocator = DEFAULT_ALLOCATOR;
83 : :
84 : 0 : buffer->buf = buf;
85 : 0 : buffer->len = len;
86 : 0 : buffer->allocated_len = len;
87 : 0 : buffer->failures = 0;
88 : 0 : buffer->allocator = allocator;
89 : 0 : }
90 : :
91 : : void
92 : 0 : egg_buffer_reset (EggBuffer *buffer)
93 : : {
94 : 0 : memset (buffer->buf, 0, buffer->allocated_len);
95 : 0 : buffer->len = 0;
96 : 0 : buffer->failures = 0;
97 : 0 : }
98 : :
99 : : void
100 : 0 : egg_buffer_uninit (EggBuffer *buffer)
101 : : {
102 : 0 : if (!buffer)
103 : 0 : return;
104 : :
105 : : /*
106 : : * Free the memory block using allocator. If no allocator,
107 : : * then this memory is ownerd elsewhere and not to be freed.
108 : : */
109 : 0 : if (buffer->buf && buffer->allocator)
110 : 0 : (buffer->allocator) (buffer->buf, 0);
111 : :
112 : 0 : memset (buffer, 0, sizeof (*buffer));
113 : : }
114 : :
115 : : unsigned char*
116 : 0 : egg_buffer_uninit_steal (EggBuffer *buffer, size_t *n_result)
117 : : {
118 : : unsigned char *result;
119 : :
120 : 0 : if (n_result)
121 : 0 : *n_result = buffer->len;
122 : 0 : result = buffer->buf;
123 : :
124 : 0 : memset (buffer, 0, sizeof (*buffer));
125 : :
126 : 0 : return result;
127 : : }
128 : :
129 : : int
130 : 0 : egg_buffer_set_allocator (EggBuffer *buffer, EggBufferAllocator allocator)
131 : : {
132 : 0 : unsigned char *buf = NULL;
133 : :
134 : 0 : if (!allocator)
135 : 0 : allocator = DEFAULT_ALLOCATOR;
136 : 0 : if (buffer->allocator == allocator)
137 : 0 : return 1;
138 : :
139 : 0 : if (buffer->allocated_len) {
140 : : /* Reallocate memory block using new allocator */
141 : 0 : buf = (allocator) (NULL, buffer->allocated_len);
142 : 0 : if (buf == NULL)
143 : 0 : return 0;
144 : :
145 : : /* Copy stuff into new memory */
146 : 0 : memcpy (buf, buffer->buf, buffer->allocated_len);
147 : : }
148 : :
149 : : /* If old wasn't static, then free it */
150 : 0 : if (buffer->allocator && buffer->buf)
151 : 0 : (buffer->allocator) (buffer->buf, 0);
152 : :
153 : 0 : buffer->buf = buf;
154 : 0 : buffer->allocator = allocator;
155 : :
156 : 0 : return 1;
157 : : }
158 : :
159 : : int
160 : 0 : egg_buffer_equal (EggBuffer *b1, EggBuffer *b2)
161 : : {
162 : 0 : if (b1->len != b2->len)
163 : 0 : return 0;
164 : 0 : return memcmp (b1->buf, b2->buf, b1->len) == 0;
165 : : }
166 : :
167 : : int
168 : 0 : egg_buffer_reserve (EggBuffer *buffer, size_t len)
169 : : {
170 : : unsigned char *newbuf;
171 : : size_t newlen;
172 : :
173 : 0 : if (len < buffer->allocated_len)
174 : 0 : return 1;
175 : :
176 : : /* Calculate a new length, minimize number of buffer allocations */
177 : 0 : newlen = buffer->allocated_len * 2;
178 : 0 : if (len > newlen)
179 : 0 : newlen += len;
180 : :
181 : : /* Memory owned elsewhere can't be reallocated */
182 : 0 : if (!buffer->allocator) {
183 : 0 : buffer->failures++;
184 : 0 : return 0;
185 : : }
186 : :
187 : : /* Reallocate built in buffer using allocator */
188 : 0 : newbuf = (buffer->allocator) (buffer->buf, newlen);
189 : 0 : if (!newbuf) {
190 : 0 : buffer->failures++;
191 : 0 : return 0;
192 : : }
193 : :
194 : 0 : buffer->buf = newbuf;
195 : 0 : buffer->allocated_len = newlen;
196 : :
197 : 0 : return 1;
198 : : }
199 : :
200 : : int
201 : 0 : egg_buffer_resize (EggBuffer *buffer, size_t len)
202 : : {
203 : 0 : if (!egg_buffer_reserve (buffer, len))
204 : 0 : return 0;
205 : :
206 : 0 : buffer->len = len;
207 : 0 : return 1;
208 : : }
209 : :
210 : : unsigned char*
211 : 0 : egg_buffer_add_empty (EggBuffer *buffer, size_t len)
212 : : {
213 : 0 : size_t pos = buffer->len;
214 : 0 : if (!egg_buffer_reserve (buffer, buffer->len + len))
215 : 0 : return NULL;
216 : 0 : buffer->len += len;
217 : 0 : return buffer->buf + pos;
218 : : }
219 : :
220 : : int
221 : 0 : egg_buffer_append (EggBuffer *buffer, const unsigned char *val,
222 : : size_t len)
223 : : {
224 : 0 : if (!egg_buffer_reserve (buffer, buffer->len + len))
225 : 0 : return 0; /* failures already incremented */
226 : 0 : memcpy (buffer->buf + buffer->len, val, len);
227 : 0 : buffer->len += len;
228 : 0 : return 1;
229 : : }
230 : :
231 : : int
232 : 0 : egg_buffer_add_byte (EggBuffer *buffer, unsigned char val)
233 : : {
234 : 0 : if (!egg_buffer_reserve (buffer, buffer->len + 1))
235 : 0 : return 0; /* failures already incremented */
236 : 0 : buffer->buf[buffer->len] = val;
237 : 0 : buffer->len++;
238 : 0 : return 1;
239 : : }
240 : :
241 : : int
242 : 0 : egg_buffer_get_byte (EggBuffer *buffer, size_t offset,
243 : : size_t *next_offset, unsigned char *val)
244 : : {
245 : : unsigned char *ptr;
246 : 0 : if (buffer->len < 1 || offset > buffer->len - 1) {
247 : 0 : buffer->failures++;
248 : 0 : return 0;
249 : : }
250 : 0 : ptr = (unsigned char*)buffer->buf + offset;
251 : 0 : if (val != NULL)
252 : 0 : *val = *ptr;
253 : 0 : if (next_offset != NULL)
254 : 0 : *next_offset = offset + 1;
255 : 0 : return 1;
256 : : }
257 : :
258 : : void
259 : 0 : egg_buffer_encode_uint16 (unsigned char* buf, uint16_t val)
260 : : {
261 : 0 : buf[0] = (val >> 8) & 0xff;
262 : 0 : buf[1] = (val >> 0) & 0xff;
263 : 0 : }
264 : :
265 : : uint16_t
266 : 0 : egg_buffer_decode_uint16 (unsigned char* buf)
267 : : {
268 : 0 : uint16_t val = buf[0] << 8 | buf[1];
269 : 0 : return val;
270 : : }
271 : :
272 : : int
273 : 0 : egg_buffer_add_uint16 (EggBuffer *buffer, uint16_t val)
274 : : {
275 : 0 : if (!egg_buffer_reserve (buffer, buffer->len + 2))
276 : 0 : return 0; /* failures already incremented */
277 : 0 : buffer->len += 2;
278 : 0 : egg_buffer_set_uint16 (buffer, buffer->len - 2, val);
279 : 0 : return 1;
280 : : }
281 : :
282 : : int
283 : 0 : egg_buffer_set_uint16 (EggBuffer *buffer, size_t offset, uint16_t val)
284 : : {
285 : : unsigned char *ptr;
286 : 0 : if (buffer->len < 2 || offset > buffer->len - 2) {
287 : 0 : buffer->failures++;
288 : 0 : return 0;
289 : : }
290 : 0 : ptr = (unsigned char*)buffer->buf + offset;
291 : 0 : egg_buffer_encode_uint16 (ptr, val);
292 : 0 : return 1;
293 : : }
294 : :
295 : : int
296 : 0 : egg_buffer_get_uint16 (EggBuffer *buffer, size_t offset,
297 : : size_t *next_offset, uint16_t *val)
298 : : {
299 : : unsigned char *ptr;
300 : 0 : if (buffer->len < 2 || offset > buffer->len - 2) {
301 : 0 : buffer->failures++;
302 : 0 : return 0;
303 : : }
304 : 0 : ptr = (unsigned char*)buffer->buf + offset;
305 : 0 : if (val != NULL)
306 : 0 : *val = egg_buffer_decode_uint16 (ptr);
307 : 0 : if (next_offset != NULL)
308 : 0 : *next_offset = offset + 2;
309 : 0 : return 1;
310 : : }
311 : :
312 : : void
313 : 0 : egg_buffer_encode_uint32 (unsigned char* buf, uint32_t val)
314 : : {
315 : 0 : buf[0] = (val >> 24) & 0xff;
316 : 0 : buf[1] = (val >> 16) & 0xff;
317 : 0 : buf[2] = (val >> 8) & 0xff;
318 : 0 : buf[3] = (val >> 0) & 0xff;
319 : 0 : }
320 : :
321 : : uint32_t
322 : 0 : egg_buffer_decode_uint32 (unsigned char* ptr)
323 : : {
324 : 0 : uint32_t val = (uint32_t) ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
325 : 0 : return val;
326 : : }
327 : :
328 : : int
329 : 0 : egg_buffer_add_uint32 (EggBuffer *buffer, uint32_t val)
330 : : {
331 : 0 : if (!egg_buffer_reserve (buffer, buffer->len + 4))
332 : 0 : return 0; /* failures already incremented */
333 : 0 : buffer->len += 4;
334 : 0 : egg_buffer_set_uint32 (buffer, buffer->len - 4, val);
335 : 0 : return 1;
336 : : }
337 : :
338 : : int
339 : 0 : egg_buffer_set_uint32 (EggBuffer *buffer, size_t offset, uint32_t val)
340 : : {
341 : : unsigned char *ptr;
342 : 0 : if (buffer->len < 4 || offset > buffer->len - 4) {
343 : 0 : buffer->failures++;
344 : 0 : return 0;
345 : : }
346 : 0 : ptr = (unsigned char*)buffer->buf + offset;
347 : 0 : egg_buffer_encode_uint32 (ptr, val);
348 : 0 : return 1;
349 : : }
350 : :
351 : : int
352 : 0 : egg_buffer_get_uint32 (EggBuffer *buffer, size_t offset, size_t *next_offset,
353 : : uint32_t *val)
354 : : {
355 : : unsigned char *ptr;
356 : 0 : if (buffer->len < 4 || offset > buffer->len - 4) {
357 : 0 : buffer->failures++;
358 : 0 : return 0;
359 : : }
360 : 0 : ptr = (unsigned char*)buffer->buf + offset;
361 : 0 : if (val != NULL)
362 : 0 : *val = egg_buffer_decode_uint32 (ptr);
363 : 0 : if (next_offset != NULL)
364 : 0 : *next_offset = offset + 4;
365 : 0 : return 1;
366 : : }
367 : :
368 : : int
369 : 0 : egg_buffer_add_uint64 (EggBuffer *buffer, uint64_t val)
370 : : {
371 : 0 : if (!egg_buffer_add_uint32 (buffer, ((val >> 32) & 0xffffffff)))
372 : 0 : return 0;
373 : 0 : return egg_buffer_add_uint32 (buffer, (val & 0xffffffff));
374 : : }
375 : :
376 : : int
377 : 0 : egg_buffer_get_uint64 (EggBuffer *buffer, size_t offset,
378 : : size_t *next_offset, uint64_t *val)
379 : : {
380 : : uint32_t a, b;
381 : 0 : if (!egg_buffer_get_uint32 (buffer, offset, &offset, &a))
382 : 0 : return 0;
383 : 0 : if (!egg_buffer_get_uint32 (buffer, offset, &offset, &b))
384 : 0 : return 0;
385 : 0 : if (val != NULL)
386 : 0 : *val = ((uint64_t)a) << 32 | b;
387 : 0 : if (next_offset != NULL)
388 : 0 : *next_offset = offset;
389 : 0 : return 1;
390 : : }
391 : :
392 : : int
393 : 0 : egg_buffer_add_byte_array (EggBuffer *buffer, const unsigned char *val,
394 : : size_t len)
395 : : {
396 : 0 : if (val == NULL)
397 : 0 : return egg_buffer_add_uint32 (buffer, 0xffffffff);
398 : 0 : if (len >= 0x7fffffff) {
399 : 0 : buffer->failures++;
400 : 0 : return 0;
401 : : }
402 : 0 : if (!egg_buffer_add_uint32 (buffer, len))
403 : 0 : return 0;
404 : 0 : return egg_buffer_append (buffer, val, len);
405 : : }
406 : :
407 : : unsigned char*
408 : 0 : egg_buffer_add_byte_array_empty (EggBuffer *buffer, size_t vlen)
409 : : {
410 : 0 : if (vlen >= 0x7fffffff) {
411 : 0 : buffer->failures++;
412 : 0 : return NULL;
413 : : }
414 : 0 : if (!egg_buffer_add_uint32 (buffer, vlen))
415 : 0 : return NULL;
416 : 0 : return egg_buffer_add_empty (buffer, vlen);
417 : : }
418 : :
419 : : int
420 : 0 : egg_buffer_get_byte_array (EggBuffer *buffer, size_t offset,
421 : : size_t *next_offset, const unsigned char **val,
422 : : size_t *vlen)
423 : : {
424 : : uint32_t len;
425 : 0 : if (!egg_buffer_get_uint32 (buffer, offset, &offset, &len))
426 : 0 : return 0;
427 : 0 : if (len == 0xffffffff) {
428 : 0 : if (next_offset)
429 : 0 : *next_offset = offset;
430 : 0 : if (val)
431 : 0 : *val = NULL;
432 : 0 : if (vlen)
433 : 0 : *vlen = 0;
434 : 0 : return 1;
435 : 0 : } else if (len >= 0x7fffffff) {
436 : 0 : buffer->failures++;
437 : 0 : return 0;
438 : : }
439 : :
440 : 0 : if (buffer->len < len || offset > buffer->len - len) {
441 : 0 : buffer->failures++;
442 : 0 : return 0;
443 : : }
444 : :
445 : 0 : if (val)
446 : 0 : *val = buffer->buf + offset;
447 : 0 : if (vlen)
448 : 0 : *vlen = len;
449 : 0 : if (next_offset)
450 : 0 : *next_offset = offset + len;
451 : :
452 : 0 : return 1;
453 : : }
454 : :
455 : : int
456 : 0 : egg_buffer_add_string (EggBuffer *buffer, const char *str)
457 : : {
458 : 0 : if (str == NULL) {
459 : 0 : return egg_buffer_add_uint32 (buffer, 0xffffffff);
460 : : } else {
461 : 0 : size_t len = strlen (str);
462 : 0 : if (len >= 0x7fffffff)
463 : 0 : return 0;
464 : 0 : if (!egg_buffer_add_uint32 (buffer, len))
465 : 0 : return 0;
466 : 0 : return egg_buffer_append (buffer, (unsigned char*)str, len);
467 : : }
468 : : }
469 : :
470 : : int
471 : 0 : egg_buffer_get_string (EggBuffer *buffer, size_t offset, size_t *next_offset,
472 : : char **str_ret, EggBufferAllocator allocator)
473 : : {
474 : : uint32_t len;
475 : :
476 : 0 : if (!allocator)
477 : 0 : allocator = buffer->allocator;
478 : 0 : if (!allocator)
479 : 0 : allocator = DEFAULT_ALLOCATOR;
480 : :
481 : 0 : if (!egg_buffer_get_uint32 (buffer, offset, &offset, &len)) {
482 : 0 : return 0;
483 : : }
484 : 0 : if (len == 0xffffffff) {
485 : 0 : *next_offset = offset;
486 : 0 : *str_ret = NULL;
487 : 0 : return 1;
488 : 0 : } else if (len >= 0x7fffffff) {
489 : 0 : return 0;
490 : : }
491 : :
492 : 0 : if (buffer->len < len ||
493 : 0 : offset > buffer->len - len) {
494 : 0 : return 0;
495 : : }
496 : :
497 : : /* Make sure no null characters in string */
498 : 0 : if (memchr (buffer->buf + offset, 0, len) != NULL)
499 : 0 : return 0;
500 : :
501 : : /* The passed allocator may be for non-pageable memory */
502 : 0 : *str_ret = (allocator) (NULL, len + 1);
503 : 0 : if (!*str_ret)
504 : 0 : return 0;
505 : 0 : memcpy (*str_ret, buffer->buf + offset, len);
506 : :
507 : : /* Always zero terminate */
508 : 0 : (*str_ret)[len] = 0;
509 : 0 : *next_offset = offset + len;
510 : :
511 : 0 : return 1;
512 : : }
513 : :
514 : : int
515 : 0 : egg_buffer_add_stringv (EggBuffer *buffer, const char** strv)
516 : : {
517 : : const char **v;
518 : 0 : uint32_t n = 0;
519 : :
520 : 0 : if (!strv)
521 : 0 : return 0;
522 : :
523 : : /* Add the number of strings coming */
524 : 0 : for (v = strv; *v; ++v)
525 : 0 : ++n;
526 : 0 : if (!egg_buffer_add_uint32 (buffer, n))
527 : 0 : return 0;
528 : :
529 : : /* Add the individual strings */
530 : 0 : for (v = strv; *v; ++v) {
531 : 0 : if (!egg_buffer_add_string (buffer, *v))
532 : 0 : return 0;
533 : : }
534 : :
535 : 0 : return 1;
536 : : }
537 : :
538 : : int
539 : 0 : egg_buffer_get_stringv (EggBuffer *buffer, size_t offset, size_t *next_offset,
540 : : char ***strv_ret, EggBufferAllocator allocator)
541 : : {
542 : : uint32_t n, i, j;
543 : : size_t len;
544 : :
545 : 0 : if (!allocator)
546 : 0 : allocator = buffer->allocator;
547 : 0 : if (!allocator)
548 : 0 : allocator = DEFAULT_ALLOCATOR;
549 : :
550 : : /* First the number of environment variable lines */
551 : 0 : if (!egg_buffer_get_uint32 (buffer, offset, &offset, &n))
552 : 0 : return 0;
553 : :
554 : : /* Then that number of strings */
555 : 0 : len = (n + 1) * sizeof (char*);
556 : 0 : *strv_ret = (char**)(allocator) (NULL, len);
557 : 0 : if (!*strv_ret)
558 : 0 : return 0;
559 : :
560 : : /* All null strings */
561 : 0 : memset (*strv_ret, 0, len);
562 : :
563 : 0 : for (i = 0; i < n; ++i) {
564 : 0 : if (!egg_buffer_get_string (buffer, offset, &offset,
565 : 0 : &((*strv_ret)[i]), allocator)) {
566 : :
567 : : /* Free all the strings on failure */
568 : 0 : for (j = 0; j < i; ++j) {
569 : 0 : if ((*strv_ret)[j])
570 : 0 : (allocator) ((*strv_ret)[j], 0);
571 : : }
572 : :
573 : 0 : return 0;
574 : : }
575 : : }
576 : :
577 : 0 : if (next_offset != NULL)
578 : 0 : *next_offset = offset;
579 : :
580 : 0 : return 1;
581 : : }
|