diff options
author | Stefan Walter <stefw@src.gnome.org> | 2009-01-17 23:27:10 +0000 |
---|---|---|
committer | Stefan Walter <stefw@src.gnome.org> | 2009-01-17 23:27:10 +0000 |
commit | a52d75ec21ac6fec61e2ea2216308f6742c2c975 (patch) | |
tree | 27942c5a376824f7848a549e2a3f1d8f9516245f /egg/egg-buffer.c | |
parent | be9d48c540c2b9141c40e3c1493a7dca4010eebc (diff) | |
download | gcr-a52d75ec21ac6fec61e2ea2216308f6742c2c975.tar.gz |
Consolidate truly common functionality into 'egg' library. Many more files
* egg/egg-asn1.c: (moved from pkcs11/gck/gck-data-asn1.c)
* egg/egg-asn1.h: (moved from pkcs11/gck/gck-data-asn1.h)
* egg/egg-buffer.c: (moved from common/gkr-buffer.c)
* egg/egg-buffer.h: (moved from common/gkr-buffer.h)
* egg/egg-secure-memory.c: (moved from common/gkr-secure-memory.c)
* egg/egg-secure-memory.h: (moved from common/gkr-secure-memory.h)
* egg/egg-unix-credentials.c: (moved from common/gkr-unix-credentials.c)
* egg/egg-unix-credentials.h: (moved from common/gkr-unix-credentials.h)
* egg/Makefile.am: (added)
* egg/pk.asn: (moved from pkcs11/gck/pk.asn)
* egg/pkix.asn: (moved from pkcs11/gck/pkix.asn)
* egg/tests/Makefile.am: (added)
* egg/tests/test.asn: (moved from pkcs11/gck/tests/test.asn)
* egg/tests/unit-test-asn1.c: (moved from pkcs11/gck/tests/unit-test-data-asn1.c)
* egg/tests/unit-test-secmem.c: (moved from common/tests/unit-test-secmem.c)
* egg/tests/test-data: (added) Consolidate truly common functionality into 'egg'
library. Many more files touched due to above changes.
svn path=/trunk/; revision=1461
Diffstat (limited to 'egg/egg-buffer.c')
-rw-r--r-- | egg/egg-buffer.c | 566 |
1 files changed, 566 insertions, 0 deletions
diff --git a/egg/egg-buffer.c b/egg/egg-buffer.c new file mode 100644 index 0000000..bbda991 --- /dev/null +++ b/egg/egg-buffer.c @@ -0,0 +1,566 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* egg-buffer.c - Generic data buffer, used by openssh, gnome-keyring + + Copyright (C) 2007 Stefan Walter + + The Gnome Keyring Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Keyring Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Stef Walter <stef@memberwebs.com> +*/ +#include "config.h" + +#include <string.h> +#include <stdarg.h> + +#include "egg-buffer.h" + +#define DEFAULT_ALLOCATOR ((EggBufferAllocator)realloc) + +int +egg_buffer_init (EggBuffer *buffer, size_t reserve) +{ + return egg_buffer_init_full (buffer, reserve, NULL); +} + +int +egg_buffer_init_full (EggBuffer *buffer, size_t reserve, EggBufferAllocator allocator) +{ + memset (buffer, 0, sizeof (*buffer)); + + if (!allocator) + allocator = DEFAULT_ALLOCATOR; + if (reserve == 0) + reserve = 64; + + buffer->buf = (allocator) (NULL, reserve); + if (!buffer->buf) { + buffer->failures++; + return 0; + } + + buffer->len = 0; + buffer->allocated_len = reserve; + buffer->failures = 0; + buffer->allocator = allocator; + + return 1; +} + +void +egg_buffer_init_static (EggBuffer* buffer, unsigned char *buf, size_t len) +{ + memset (buffer, 0, sizeof (*buffer)); + + buffer->buf = buf; + buffer->len = len; + buffer->allocated_len = len; + buffer->failures = 0; + + /* A null allocator, and the buffer can't change in size */ + buffer->allocator = NULL; +} + +void +egg_buffer_init_allocated (EggBuffer *buffer, unsigned char *buf, size_t len, + EggBufferAllocator allocator) +{ + memset (buffer, 0, sizeof (*buffer)); + + if (!allocator) + allocator = DEFAULT_ALLOCATOR; + + buffer->buf = buf; + buffer->len = len; + buffer->allocated_len = len; + buffer->failures = 0; + buffer->allocator = allocator; +} + +void +egg_buffer_reset (EggBuffer *buffer) +{ + memset (buffer->buf, 0, buffer->allocated_len); + buffer->len = 0; + buffer->failures = 0; +} + +void +egg_buffer_uninit (EggBuffer *buffer) +{ + if (!buffer) + return; + + /* + * Free the memory block using allocator. If no allocator, + * then this memory is ownerd elsewhere and not to be freed. + */ + if (buffer->buf && buffer->allocator) + (buffer->allocator) (buffer->buf, 0); + + memset (buffer, 0, sizeof (*buffer)); +} + +int +egg_buffer_set_allocator (EggBuffer *buffer, EggBufferAllocator allocator) +{ + unsigned char *buf; + + if (!allocator) + allocator = DEFAULT_ALLOCATOR; + if (buffer->allocator == allocator) + return 1; + + /* Reallocate memory block using new allocator */ + buf = (allocator) (NULL, buffer->allocated_len); + if (!buf) + return 0; + + /* Copy stuff and free old memory */ + memcpy (buf, buffer->buf, buffer->allocated_len); + + /* If old wasn't static, then free it */ + if (buffer->allocator) + (buffer->allocator) (buffer->buf, 0); + + buffer->buf = buf; + buffer->allocator = allocator; + + return 1; +} + +int +egg_buffer_equal (EggBuffer *b1, EggBuffer *b2) +{ + if (b1->len != b2->len) + return 0; + return memcmp (b1->buf, b2->buf, b1->len) == 0; +} + +int +egg_buffer_reserve (EggBuffer *buffer, size_t len) +{ + unsigned char *newbuf; + size_t newlen; + + if (len < buffer->allocated_len) + return 1; + + /* Calculate a new length, minimize number of buffer allocations */ + newlen = buffer->allocated_len * 2; + if (len > newlen) + newlen += len; + + /* Memory owned elsewhere can't be reallocated */ + if (!buffer->allocator) { + buffer->failures++; + return 0; + } + + /* Reallocate built in buffer using allocator */ + newbuf = (buffer->allocator) (buffer->buf, newlen); + if (!newbuf) { + buffer->failures++; + return 0; + } + + buffer->buf = newbuf; + buffer->allocated_len = newlen; + + return 1; +} + +int +egg_buffer_resize (EggBuffer *buffer, size_t len) +{ + if (!egg_buffer_reserve (buffer, len)) + return 0; + + buffer->len = len; + return 1; +} + +unsigned char* +egg_buffer_add_empty (EggBuffer *buffer, size_t len) +{ + size_t pos = buffer->len; + if (!egg_buffer_reserve (buffer, buffer->len + len)) + return NULL; + buffer->len += len; + return buffer->buf + pos; +} + +int +egg_buffer_append (EggBuffer *buffer, const unsigned char *val, + size_t len) +{ + if (!egg_buffer_reserve (buffer, buffer->len + len)) + return 0; /* failures already incremented */ + memcpy (buffer->buf + buffer->len, val, len); + buffer->len += len; + return 1; +} + +int +egg_buffer_add_byte (EggBuffer *buffer, unsigned char val) +{ + if (!egg_buffer_reserve (buffer, buffer->len + 1)) + return 0; /* failures already incremented */ + buffer->buf[buffer->len] = val; + buffer->len++; + return 1; +} + +int +egg_buffer_get_byte (EggBuffer *buffer, size_t offset, + size_t *next_offset, unsigned char *val) +{ + unsigned char *ptr; + if (buffer->len < 1 || offset > buffer->len - 1) { + buffer->failures++; + return 0; + } + ptr = (unsigned char*)buffer->buf + offset; + if (val != NULL) + *val = *ptr; + if (next_offset != NULL) + *next_offset = offset + 1; + return 1; +} + +void +egg_buffer_encode_uint16 (unsigned char* buf, uint16_t val) +{ + buf[0] = (val >> 8) & 0xff; + buf[1] = (val >> 0) & 0xff; +} + +uint16_t +egg_buffer_decode_uint16 (unsigned char* buf) +{ + uint16_t val = buf[0] << 8 | buf[1]; + return val; +} + +int +egg_buffer_add_uint16 (EggBuffer *buffer, uint16_t val) +{ + if (!egg_buffer_reserve (buffer, buffer->len + 2)) + return 0; /* failures already incremented */ + buffer->len += 2; + egg_buffer_set_uint16 (buffer, buffer->len - 2, val); + return 1; +} + +int +egg_buffer_set_uint16 (EggBuffer *buffer, size_t offset, uint16_t val) +{ + unsigned char *ptr; + if (buffer->len < 2 || offset > buffer->len - 2) { + buffer->failures++; + return 0; + } + ptr = (unsigned char*)buffer->buf + offset; + egg_buffer_encode_uint16 (ptr, val); + return 1; +} + +int +egg_buffer_get_uint16 (EggBuffer *buffer, size_t offset, + size_t *next_offset, uint16_t *val) +{ + unsigned char *ptr; + if (buffer->len < 2 || offset > buffer->len - 2) { + buffer->failures++; + return 0; + } + ptr = (unsigned char*)buffer->buf + offset; + if (val != NULL) + *val = egg_buffer_decode_uint16 (ptr); + if (next_offset != NULL) + *next_offset = offset + 2; + return 1; +} + +void +egg_buffer_encode_uint32 (unsigned char* buf, uint32_t val) +{ + buf[0] = (val >> 24) & 0xff; + buf[1] = (val >> 16) & 0xff; + buf[2] = (val >> 8) & 0xff; + buf[3] = (val >> 0) & 0xff; +} + +uint32_t +egg_buffer_decode_uint32 (unsigned char* ptr) +{ + uint32_t val = ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3]; + return val; +} + +int +egg_buffer_add_uint32 (EggBuffer *buffer, uint32_t val) +{ + if (!egg_buffer_reserve (buffer, buffer->len + 4)) + return 0; /* failures already incremented */ + buffer->len += 4; + egg_buffer_set_uint32 (buffer, buffer->len - 4, val); + return 1; +} + +int +egg_buffer_set_uint32 (EggBuffer *buffer, size_t offset, uint32_t val) +{ + unsigned char *ptr; + if (buffer->len < 4 || offset > buffer->len - 4) { + buffer->failures++; + return 0; + } + ptr = (unsigned char*)buffer->buf + offset; + egg_buffer_encode_uint32 (ptr, val); + return 1; +} + +int +egg_buffer_get_uint32 (EggBuffer *buffer, size_t offset, size_t *next_offset, + uint32_t *val) +{ + unsigned char *ptr; + if (buffer->len < 4 || offset > buffer->len - 4) { + buffer->failures++; + return 0; + } + ptr = (unsigned char*)buffer->buf + offset; + if (val != NULL) + *val = egg_buffer_decode_uint32 (ptr); + if (next_offset != NULL) + *next_offset = offset + 4; + return 1; +} + +int +egg_buffer_add_uint64 (EggBuffer *buffer, uint64_t val) +{ + if (!egg_buffer_add_uint32 (buffer, ((val >> 32) & 0xffffffff))) + return 0; + return egg_buffer_add_uint32 (buffer, (val & 0xffffffff)); +} + +int +egg_buffer_get_uint64 (EggBuffer *buffer, size_t offset, + size_t *next_offset, uint64_t *val) +{ + uint32_t a, b; + if (!egg_buffer_get_uint32 (buffer, offset, &offset, &a)) + return 0; + if (!egg_buffer_get_uint32 (buffer, offset, &offset, &b)) + return 0; + if (val != NULL) + *val = ((uint64_t)a) << 32 | b; + if (next_offset != NULL) + *next_offset = offset; + return 1; +} + +int +egg_buffer_add_byte_array (EggBuffer *buffer, const unsigned char *val, + size_t len) +{ + if (val == NULL) + return egg_buffer_add_uint32 (buffer, 0xffffffff); + if (len >= 0x7fffffff) { + buffer->failures++; + return 0; + } + if (!egg_buffer_add_uint32 (buffer, len)) + return 0; + return egg_buffer_append (buffer, val, len); +} + +unsigned char* +egg_buffer_add_byte_array_empty (EggBuffer *buffer, size_t vlen) +{ + if (vlen >= 0x7fffffff) { + buffer->failures++; + return NULL; + } + if (!egg_buffer_add_uint32 (buffer, vlen)) + return NULL; + return egg_buffer_add_empty (buffer, vlen); +} + +int +egg_buffer_get_byte_array (EggBuffer *buffer, size_t offset, + size_t *next_offset, const unsigned char **val, + size_t *vlen) +{ + uint32_t len; + if (!egg_buffer_get_uint32 (buffer, offset, &offset, &len)) + return 0; + if (len == 0xffffffff) { + if (next_offset) + *next_offset = offset; + if (val) + *val = NULL; + if (vlen) + *vlen = 0; + return 1; + } else if (len >= 0x7fffffff) { + buffer->failures++; + return 0; + } + + if (buffer->len < len || offset > buffer->len - len) { + buffer->failures++; + return 0; + } + + if (val) + *val = buffer->buf + offset; + if (vlen) + *vlen = len; + if (next_offset) + *next_offset = offset + len; + + return 1; +} + +int +egg_buffer_add_string (EggBuffer *buffer, const char *str) +{ + if (str == NULL) { + return egg_buffer_add_uint32 (buffer, 0xffffffff); + } else { + size_t len = strlen (str); + if (len >= 0x7fffffff) + return 0; + if (!egg_buffer_add_uint32 (buffer, len)) + return 0; + return egg_buffer_append (buffer, (unsigned char*)str, len); + } +} + +int +egg_buffer_get_string (EggBuffer *buffer, size_t offset, size_t *next_offset, + char **str_ret, EggBufferAllocator allocator) +{ + uint32_t len; + + if (!allocator) + allocator = buffer->allocator; + if (!allocator) + allocator = DEFAULT_ALLOCATOR; + + if (!egg_buffer_get_uint32 (buffer, offset, &offset, &len)) { + return 0; + } + if (len == 0xffffffff) { + *next_offset = offset; + *str_ret = NULL; + return 1; + } else if (len >= 0x7fffffff) { + return 0; + } + + if (buffer->len < len || + offset > buffer->len - len) { + return 0; + } + + /* Make sure no null characters in string */ + if (memchr (buffer->buf + offset, 0, len) != NULL) + return 0; + + /* The passed allocator may be for non-pageable memory */ + *str_ret = (allocator) (NULL, len + 1); + if (!*str_ret) + return 0; + memcpy (*str_ret, buffer->buf + offset, len); + + /* Always zero terminate */ + (*str_ret)[len] = 0; + *next_offset = offset + len; + + return 1; +} + +int +egg_buffer_add_stringv (EggBuffer *buffer, const char** strv) +{ + const char **v; + uint32_t n = 0; + + if (!strv) + return 0; + + /* Add the number of strings coming */ + for (v = strv; *v; ++v) + ++n; + if (!egg_buffer_add_uint32 (buffer, n)) + return 0; + + /* Add the individual strings */ + for (v = strv; *v; ++v) { + if (!egg_buffer_add_string (buffer, *v)) + return 0; + } + + return 1; +} + +int +egg_buffer_get_stringv (EggBuffer *buffer, size_t offset, size_t *next_offset, + char ***strv_ret, EggBufferAllocator allocator) +{ + uint32_t n, i, j; + size_t len; + + if (!allocator) + allocator = buffer->allocator; + if (!allocator) + allocator = DEFAULT_ALLOCATOR; + + /* First the number of environment variable lines */ + if (!egg_buffer_get_uint32 (buffer, offset, &offset, &n)) + return 0; + + /* Then that number of strings */ + len = (n + 1) * sizeof (char*); + *strv_ret = (char**)(allocator) (NULL, len); + if (!*strv_ret) + return 0; + + /* All null strings */ + memset (*strv_ret, 0, len); + + for (i = 0; i < n; ++i) { + if (!egg_buffer_get_string (buffer, offset, &offset, + &((*strv_ret)[i]), allocator)) { + + /* Free all the strings on failure */ + for (j = 0; j < i; ++j) { + if ((*strv_ret)[j]) + (allocator) ((*strv_ret)[j], 0); + } + + return 0; + } + } + + if (next_offset != NULL) + *next_offset = offset; + + return 1; +} |