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 155 : egg_buffer_init_full (EggBuffer *buffer, size_t reserve, EggBufferAllocator allocator)
39 : {
40 155 : memset (buffer, 0, sizeof (*buffer));
41 :
42 155 : if (!allocator)
43 0 : allocator = DEFAULT_ALLOCATOR;
44 155 : if (reserve == 0)
45 0 : reserve = 64;
46 :
47 155 : buffer->buf = (allocator) (NULL, reserve);
48 155 : if (!buffer->buf) {
49 0 : buffer->failures++;
50 0 : return 0;
51 : }
52 :
53 155 : buffer->len = 0;
54 155 : buffer->allocated_len = reserve;
55 155 : buffer->failures = 0;
56 155 : buffer->allocator = allocator;
57 :
58 155 : return 1;
59 : }
60 :
61 : void
62 121 : egg_buffer_init_static (EggBuffer* buffer, const unsigned char *buf, size_t len)
63 : {
64 121 : memset (buffer, 0, sizeof (*buffer));
65 :
66 121 : buffer->buf = (unsigned char*)buf;
67 121 : buffer->len = len;
68 121 : buffer->allocated_len = len;
69 121 : buffer->failures = 0;
70 :
71 : /* A null allocator, and the buffer can't change in size */
72 121 : buffer->allocator = NULL;
73 121 : }
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 211 : egg_buffer_reset (EggBuffer *buffer)
93 : {
94 211 : memset (buffer->buf, 0, buffer->allocated_len);
95 211 : buffer->len = 0;
96 211 : buffer->failures = 0;
97 211 : }
98 :
99 : void
100 246 : egg_buffer_uninit (EggBuffer *buffer)
101 : {
102 246 : 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 246 : if (buffer->buf && buffer->allocator)
110 225 : (buffer->allocator) (buffer->buf, 0);
111 :
112 246 : memset (buffer, 0, sizeof (*buffer));
113 : }
114 :
115 : unsigned char*
116 16 : egg_buffer_uninit_steal (EggBuffer *buffer, size_t *n_result)
117 : {
118 : unsigned char *result;
119 :
120 16 : if (n_result)
121 16 : *n_result = buffer->len;
122 16 : result = buffer->buf;
123 :
124 16 : memset (buffer, 0, sizeof (*buffer));
125 :
126 16 : return result;
127 : }
128 :
129 : int
130 102 : egg_buffer_set_allocator (EggBuffer *buffer, EggBufferAllocator allocator)
131 : {
132 102 : unsigned char *buf = NULL;
133 :
134 102 : if (!allocator)
135 0 : allocator = DEFAULT_ALLOCATOR;
136 102 : if (buffer->allocator == allocator)
137 16 : return 1;
138 :
139 86 : 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 86 : if (buffer->allocator && buffer->buf)
151 0 : (buffer->allocator) (buffer->buf, 0);
152 :
153 86 : buffer->buf = buf;
154 86 : buffer->allocator = allocator;
155 :
156 86 : 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 1794 : egg_buffer_reserve (EggBuffer *buffer, size_t len)
169 : {
170 : unsigned char *newbuf;
171 : size_t newlen;
172 :
173 1794 : if (len < buffer->allocated_len)
174 1660 : return 1;
175 :
176 : /* Calculate a new length, minimize number of buffer allocations */
177 134 : newlen = buffer->allocated_len * 2;
178 134 : if (len > newlen)
179 86 : newlen += len;
180 :
181 : /* Memory owned elsewhere can't be reallocated */
182 134 : if (!buffer->allocator) {
183 0 : buffer->failures++;
184 0 : return 0;
185 : }
186 :
187 : /* Reallocate built in buffer using allocator */
188 134 : newbuf = (buffer->allocator) (buffer->buf, newlen);
189 134 : if (!newbuf) {
190 0 : buffer->failures++;
191 0 : return 0;
192 : }
193 :
194 134 : buffer->buf = newbuf;
195 134 : buffer->allocated_len = newlen;
196 :
197 134 : return 1;
198 : }
199 :
200 : int
201 211 : egg_buffer_resize (EggBuffer *buffer, size_t len)
202 : {
203 211 : if (!egg_buffer_reserve (buffer, len))
204 0 : return 0;
205 :
206 211 : buffer->len = len;
207 211 : return 1;
208 : }
209 :
210 : unsigned char*
211 39 : egg_buffer_add_empty (EggBuffer *buffer, size_t len)
212 : {
213 39 : size_t pos = buffer->len;
214 39 : if (!egg_buffer_reserve (buffer, buffer->len + len))
215 0 : return NULL;
216 39 : buffer->len += len;
217 39 : return buffer->buf + pos;
218 : }
219 :
220 : int
221 277 : egg_buffer_append (EggBuffer *buffer, const unsigned char *val,
222 : size_t len)
223 : {
224 277 : if (!egg_buffer_reserve (buffer, buffer->len + len))
225 0 : return 0; /* failures already incremented */
226 277 : memcpy (buffer->buf + buffer->len, val, len);
227 277 : buffer->len += len;
228 277 : return 1;
229 : }
230 :
231 : int
232 178 : egg_buffer_add_byte (EggBuffer *buffer, unsigned char val)
233 : {
234 178 : if (!egg_buffer_reserve (buffer, buffer->len + 1))
235 0 : return 0; /* failures already incremented */
236 178 : buffer->buf[buffer->len] = val;
237 178 : buffer->len++;
238 178 : return 1;
239 : }
240 :
241 : int
242 10 : egg_buffer_get_byte (EggBuffer *buffer, size_t offset,
243 : size_t *next_offset, unsigned char *val)
244 : {
245 : unsigned char *ptr;
246 10 : if (buffer->len < 1 || offset > buffer->len - 1) {
247 0 : buffer->failures++;
248 0 : return 0;
249 : }
250 10 : ptr = (unsigned char*)buffer->buf + offset;
251 10 : if (val != NULL)
252 10 : *val = *ptr;
253 10 : if (next_offset != NULL)
254 10 : *next_offset = offset + 1;
255 10 : 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 1022 : egg_buffer_encode_uint32 (unsigned char* buf, uint32_t val)
314 : {
315 1022 : buf[0] = (val >> 24) & 0xff;
316 1022 : buf[1] = (val >> 16) & 0xff;
317 1022 : buf[2] = (val >> 8) & 0xff;
318 1022 : buf[3] = (val >> 0) & 0xff;
319 1022 : }
320 :
321 : uint32_t
322 3889 : egg_buffer_decode_uint32 (unsigned char* ptr)
323 : {
324 3889 : uint32_t val = (uint32_t) ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
325 3889 : return val;
326 : }
327 :
328 : int
329 981 : egg_buffer_add_uint32 (EggBuffer *buffer, uint32_t val)
330 : {
331 981 : if (!egg_buffer_reserve (buffer, buffer->len + 4))
332 0 : return 0; /* failures already incremented */
333 981 : buffer->len += 4;
334 981 : egg_buffer_set_uint32 (buffer, buffer->len - 4, val);
335 981 : return 1;
336 : }
337 :
338 : int
339 1010 : egg_buffer_set_uint32 (EggBuffer *buffer, size_t offset, uint32_t val)
340 : {
341 : unsigned char *ptr;
342 1010 : if (buffer->len < 4 || offset > buffer->len - 4) {
343 0 : buffer->failures++;
344 0 : return 0;
345 : }
346 1010 : ptr = (unsigned char*)buffer->buf + offset;
347 1010 : egg_buffer_encode_uint32 (ptr, val);
348 1010 : return 1;
349 : }
350 :
351 : int
352 3858 : egg_buffer_get_uint32 (EggBuffer *buffer, size_t offset, size_t *next_offset,
353 : uint32_t *val)
354 : {
355 : unsigned char *ptr;
356 3858 : if (buffer->len < 4 || offset > buffer->len - 4) {
357 0 : buffer->failures++;
358 0 : return 0;
359 : }
360 3858 : ptr = (unsigned char*)buffer->buf + offset;
361 3858 : if (val != NULL)
362 3858 : *val = egg_buffer_decode_uint32 (ptr);
363 3858 : if (next_offset != NULL)
364 3843 : *next_offset = offset + 4;
365 3858 : return 1;
366 : }
367 :
368 : int
369 24 : egg_buffer_add_uint64 (EggBuffer *buffer, uint64_t val)
370 : {
371 24 : if (!egg_buffer_add_uint32 (buffer, ((val >> 32) & 0xffffffff)))
372 0 : return 0;
373 24 : return egg_buffer_add_uint32 (buffer, (val & 0xffffffff));
374 : }
375 :
376 : int
377 55 : egg_buffer_get_uint64 (EggBuffer *buffer, size_t offset,
378 : size_t *next_offset, uint64_t *val)
379 : {
380 : uint32_t a, b;
381 55 : if (!egg_buffer_get_uint32 (buffer, offset, &offset, &a))
382 0 : return 0;
383 55 : if (!egg_buffer_get_uint32 (buffer, offset, &offset, &b))
384 0 : return 0;
385 55 : if (val != NULL)
386 55 : *val = ((uint64_t)a) << 32 | b;
387 55 : if (next_offset != NULL)
388 55 : *next_offset = offset;
389 55 : return 1;
390 : }
391 :
392 : int
393 67 : egg_buffer_add_byte_array (EggBuffer *buffer, const unsigned char *val,
394 : size_t len)
395 : {
396 67 : if (val == NULL)
397 2 : return egg_buffer_add_uint32 (buffer, 0xffffffff);
398 65 : if (len >= 0x7fffffff) {
399 0 : buffer->failures++;
400 0 : return 0;
401 : }
402 65 : if (!egg_buffer_add_uint32 (buffer, len))
403 0 : return 0;
404 65 : return egg_buffer_append (buffer, val, len);
405 : }
406 :
407 : unsigned char*
408 27 : egg_buffer_add_byte_array_empty (EggBuffer *buffer, size_t vlen)
409 : {
410 27 : if (vlen >= 0x7fffffff) {
411 0 : buffer->failures++;
412 0 : return NULL;
413 : }
414 27 : if (!egg_buffer_add_uint32 (buffer, vlen))
415 0 : return NULL;
416 27 : return egg_buffer_add_empty (buffer, vlen);
417 : }
418 :
419 : int
420 205 : 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 205 : if (!egg_buffer_get_uint32 (buffer, offset, &offset, &len))
426 0 : return 0;
427 205 : 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 205 : } else if (len >= 0x7fffffff) {
436 0 : buffer->failures++;
437 0 : return 0;
438 : }
439 :
440 205 : if (buffer->len < len || offset > buffer->len - len) {
441 0 : buffer->failures++;
442 0 : return 0;
443 : }
444 :
445 205 : if (val)
446 205 : *val = buffer->buf + offset;
447 205 : if (vlen)
448 205 : *vlen = len;
449 205 : if (next_offset)
450 205 : *next_offset = offset + len;
451 :
452 205 : return 1;
453 : }
454 :
455 : int
456 164 : egg_buffer_add_string (EggBuffer *buffer, const char *str)
457 : {
458 164 : if (str == NULL) {
459 19 : return egg_buffer_add_uint32 (buffer, 0xffffffff);
460 : } else {
461 145 : size_t len = strlen (str);
462 145 : if (len >= 0x7fffffff)
463 0 : return 0;
464 145 : if (!egg_buffer_add_uint32 (buffer, len))
465 0 : return 0;
466 145 : return egg_buffer_append (buffer, (unsigned char*)str, len);
467 : }
468 : }
469 :
470 : int
471 866 : 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 866 : if (!allocator)
477 20 : allocator = buffer->allocator;
478 866 : if (!allocator)
479 0 : allocator = DEFAULT_ALLOCATOR;
480 :
481 866 : if (!egg_buffer_get_uint32 (buffer, offset, &offset, &len)) {
482 0 : return 0;
483 : }
484 866 : if (len == 0xffffffff) {
485 55 : *next_offset = offset;
486 55 : *str_ret = NULL;
487 55 : return 1;
488 811 : } else if (len >= 0x7fffffff) {
489 0 : return 0;
490 : }
491 :
492 811 : if (buffer->len < len ||
493 811 : offset > buffer->len - len) {
494 0 : return 0;
495 : }
496 :
497 : /* Make sure no null characters in string */
498 811 : if (memchr (buffer->buf + offset, 0, len) != NULL)
499 0 : return 0;
500 :
501 : /* The passed allocator may be for non-pageable memory */
502 811 : *str_ret = (allocator) (NULL, len + 1);
503 811 : if (!*str_ret)
504 0 : return 0;
505 811 : memcpy (*str_ret, buffer->buf + offset, len);
506 :
507 : /* Always zero terminate */
508 811 : (*str_ret)[len] = 0;
509 811 : *next_offset = offset + len;
510 :
511 811 : 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 : }
|