diff options
-rw-r--r-- | common/Makefile.am | 1 | ||||
-rw-r--r-- | common/buffer.c | 180 | ||||
-rw-r--r-- | common/buffer.h | 82 | ||||
-rw-r--r-- | common/tests/Makefile.am | 1 | ||||
-rw-r--r-- | common/tests/test-buffer.c | 214 | ||||
-rw-r--r-- | p11-kit/uri.c | 93 |
6 files changed, 515 insertions, 56 deletions
diff --git a/common/Makefile.am b/common/Makefile.am index 5d38c88..ce6dd2a 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -20,6 +20,7 @@ libp11_compat_la_SOURCES = \ libp11_library_la_SOURCES = \ attrs.c attrs.h \ array.c array.h \ + buffer.c buffer.h \ debug.c debug.h \ dict.c dict.h \ library.c library.h \ diff --git a/common/buffer.c b/common/buffer.c new file mode 100644 index 0000000..a91623e --- /dev/null +++ b/common/buffer.c @@ -0,0 +1,180 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* buffer.c - Generic data buffer, used by openssh, gnome-keyring + + Copyright (C) 2007, 2012 Stefan Walter + Copyright (C) 2013 Red Hat Inc. + + 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@thewalter.net> +*/ + +#include "config.h" + +#include "buffer.h" +#include "debug.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +static bool +buffer_realloc (p11_buffer *buffer, + size_t size) +{ + void *data; + + /* Memory owned elsewhere can't be reallocated */ + return_val_if_fail (buffer->frealloc != NULL, false); + + /* Reallocate built in buffer using allocator */ + data = (buffer->frealloc) (buffer->data, size); + if (!data && size > 0) { + p11_buffer_fail (buffer); + return_val_if_reached (false); + } + + buffer->data = data; + buffer->size = size; + return true; +} + +bool +p11_buffer_init (p11_buffer *buffer, + size_t reserve) +{ + p11_buffer_init_full (buffer, NULL, 0, 0, realloc, free); + return buffer_realloc (buffer, reserve); +} + +bool +p11_buffer_init_null (p11_buffer *buffer, + size_t reserve) +{ + p11_buffer_init_full (buffer, NULL, 0, P11_BUFFER_NULL, realloc, free); + return buffer_realloc (buffer, reserve); +} + +void +p11_buffer_init_full (p11_buffer *buffer, + void *data, + size_t len, + int flags, + void * (* frealloc) (void *, size_t), + void (* ffree) (void *)) +{ + memset (buffer, 0, sizeof (*buffer)); + + buffer->data = data; + buffer->len = len; + buffer->size = len; + buffer->flags = flags; + buffer->frealloc = frealloc; + buffer->ffree = ffree; + + return_if_fail (!(flags & P11_BUFFER_FAILED)); +} + +void +p11_buffer_uninit (p11_buffer *buffer) +{ + return_if_fail (buffer != NULL); + + if (buffer->ffree && buffer->data) + (buffer->ffree) (buffer->data); + memset (buffer, 0, sizeof (*buffer)); +} + +void * +p11_buffer_steal (p11_buffer *buffer, + size_t *length) +{ + void *data; + + return_val_if_fail (p11_buffer_ok (buffer), NULL); + + if (length) + *length = buffer->len; + data = buffer->data; + + buffer->data = NULL; + buffer->size = 0; + buffer->len = 0; + return data; +} + +bool +p11_buffer_reset (p11_buffer *buffer, + size_t reserve) +{ + buffer->flags &= ~P11_BUFFER_FAILED; + buffer->len = 0; + + if (reserve < buffer->size) + return true; + return buffer_realloc (buffer, reserve); +} + +void * +p11_buffer_append (p11_buffer *buffer, + size_t length) +{ + unsigned char *data; + size_t terminator; + size_t newlen; + size_t reserve; + + return_val_if_fail (p11_buffer_ok (buffer), NULL); + + terminator = (buffer->flags & P11_BUFFER_NULL) ? 1 : 0; + reserve = terminator + length + buffer->len; + + if (reserve > buffer->size) { + + /* Calculate a new length, minimize number of buffer allocations */ + newlen = buffer->size * 2; + if (!newlen) + newlen = 16; + if (reserve > newlen) + newlen = reserve; + + if (!buffer_realloc (buffer, newlen)) + return_val_if_reached (NULL); + } + + data = buffer->data; + data += buffer->len; + buffer->len += length; + if (terminator) + data[length] = '\0'; + return data; +} + +void +p11_buffer_add (p11_buffer *buffer, + const void *data, + ssize_t length) +{ + void *at; + + if (length < 0) + length = strlen (data); + + at = p11_buffer_append (buffer, length); + return_if_fail (at != NULL); + memcpy (at, data, length); +} diff --git a/common/buffer.h b/common/buffer.h new file mode 100644 index 0000000..d5335f8 --- /dev/null +++ b/common/buffer.h @@ -0,0 +1,82 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* buffer.h - Generic data buffer, used by openssh, gnome-keyring + + Copyright (C) 2007, 2012 Stefan Walter + Copyright (C) 2012 Red Hat Inc. + + 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@thewalter.net> +*/ + +#ifndef P11_BUFFER_H_ +#define P11_BUFFER_H_ + +#include "compat.h" + +enum { + P11_BUFFER_FAILED = 1 << 0, + P11_BUFFER_NULL = 1 << 1, +}; + +typedef struct { + void *data; + size_t len; + + int flags; + size_t size; + void * (* frealloc) (void *, size_t); + void (* ffree) (void *); +} p11_buffer; + +bool p11_buffer_init (p11_buffer *buffer, + size_t size); + +bool p11_buffer_init_null (p11_buffer *buffer, + size_t size); + +void p11_buffer_init_full (p11_buffer *buffer, + void *data, + size_t len, + int flags, + void * (* frealloc) (void *, size_t), + void (* ffree) (void *)); + +void p11_buffer_uninit (p11_buffer *buffer); + +void * p11_buffer_steal (p11_buffer *buffer, + size_t *length); + +bool p11_buffer_reset (p11_buffer *buffer, + size_t size); + +void * p11_buffer_append (p11_buffer *buffer, + size_t length); + +void p11_buffer_add (p11_buffer *buffer, + const void *data, + ssize_t length); + +#define p11_buffer_fail(buf) \ + ((buf)->flags |= P11_BUFFER_FAILED) + +#define p11_buffer_ok(buf) \ + (((buf)->flags & P11_BUFFER_FAILED) ? false : true) + +#define p11_buffer_failed(buf) \ + (((buf)->flags & P11_BUFFER_FAILED) ? true : false) + +#endif /* BUFFER_H */ diff --git a/common/tests/Makefile.am b/common/tests/Makefile.am index 4badbb5..3b6b986 100644 --- a/common/tests/Makefile.am +++ b/common/tests/Makefile.am @@ -21,6 +21,7 @@ CHECK_PROGS = \ test-dict \ test-array \ test-attrs \ + test-buffer \ $(NULL) noinst_PROGRAMS = \ diff --git a/common/tests/test-buffer.c b/common/tests/test-buffer.c new file mode 100644 index 0000000..9db5f83 --- /dev/null +++ b/common/tests/test-buffer.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2012 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stef@thewalter.net> + */ + +#include "config.h" +#include "CuTest.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "debug.h" +#include "buffer.h" + +static void +test_init_uninit (CuTest *tc) +{ + p11_buffer buffer; + + p11_buffer_init (&buffer, 10); + CuAssertPtrNotNull (tc, buffer.data); + CuAssertIntEquals (tc, 0, buffer.len); + CuAssertIntEquals (tc, 0, buffer.flags); + CuAssertTrue (tc, buffer.size >= 10); + CuAssertPtrNotNull (tc, buffer.ffree); + CuAssertPtrNotNull (tc, buffer.frealloc); + + p11_buffer_uninit (&buffer); +} + +static void +test_append (CuTest *tc) +{ + p11_buffer buffer; + + p11_buffer_init (&buffer, 10); + buffer.len = 5; + p11_buffer_append (&buffer, 35); + CuAssertIntEquals (tc, 5 + 35, buffer.len); + CuAssertTrue (tc, buffer.size >= 35 + 5); + + p11_buffer_append (&buffer, 15); + CuAssertIntEquals (tc, 5 + 35 + 15, buffer.len); + CuAssertTrue (tc, buffer.size >= 5 + 35 + 15); + + p11_buffer_uninit (&buffer); +} + +static void +test_null (CuTest *tc) +{ + p11_buffer buffer; + + p11_buffer_init_null (&buffer, 10); + p11_buffer_add (&buffer, "Blah", -1); + p11_buffer_add (&buffer, " blah", -1); + + CuAssertStrEquals (tc, "Blah blah", buffer.data); + + p11_buffer_uninit (&buffer); +} + +static int mock_realloced = 0; +static int mock_freed = 0; + +static void * +mock_realloc (void *data, + size_t size) +{ + mock_realloced++; + return realloc (data, size); +} + +static void +mock_free (void *data) +{ + mock_freed++; + free (data); +} + +static void +test_init_for_data (CuTest *tc) +{ + p11_buffer buffer; + unsigned char *ret; + size_t len; + + mock_realloced = 0; + mock_freed = 0; + + p11_buffer_init_full (&buffer, (unsigned char *)strdup ("blah"), 4, 0, + mock_realloc, mock_free); + + CuAssertPtrNotNull (tc, buffer.data); + CuAssertStrEquals (tc, "blah", (char *)buffer.data); + CuAssertIntEquals (tc, 4, buffer.len); + CuAssertIntEquals (tc, 0, buffer.flags); + CuAssertIntEquals (tc, 4, buffer.size); + CuAssertPtrEquals (tc, mock_free, buffer.ffree); + CuAssertPtrEquals (tc, mock_realloc, buffer.frealloc); + + CuAssertIntEquals (tc, 0, mock_realloced); + CuAssertIntEquals (tc, 0, mock_freed); + + len = buffer.len; + ret = p11_buffer_append (&buffer, 1024); + CuAssertPtrEquals (tc, (char *)buffer.data + len, ret); + CuAssertIntEquals (tc, 1, mock_realloced); + + p11_buffer_uninit (&buffer); + CuAssertIntEquals (tc, 1, mock_realloced); + CuAssertIntEquals (tc, 1, mock_freed); +} + +static void +test_steal (CuTest *tc) +{ + p11_buffer buffer; + char *string; + size_t length; + + mock_freed = 0; + + p11_buffer_init_full (&buffer, (unsigned char *)strdup ("blah"), 4, + P11_BUFFER_NULL, mock_realloc, mock_free); + + CuAssertPtrNotNull (tc, buffer.data); + CuAssertStrEquals (tc, "blah", buffer.data); + + p11_buffer_add (&buffer, " yada", -1); + CuAssertStrEquals (tc, "blah yada", buffer.data); + + string = p11_buffer_steal (&buffer, &length); + p11_buffer_uninit (&buffer); + + CuAssertStrEquals (tc, "blah yada", string); + CuAssertIntEquals (tc, 9, length); + CuAssertIntEquals (tc, 0, mock_freed); + + free (string); +} + +static void +test_add (CuTest *tc) +{ + p11_buffer buffer; + + p11_buffer_init (&buffer, 10); + + p11_buffer_add (&buffer, (unsigned char *)"Planet Express", 15); + CuAssertIntEquals (tc, 15, buffer.len); + CuAssertStrEquals (tc, "Planet Express", (char *)buffer.data); + CuAssertTrue (tc, p11_buffer_ok (&buffer)); + + p11_buffer_uninit (&buffer); +} + +int +main (void) +{ + CuString *output = CuStringNew (); + CuSuite* suite = CuSuiteNew (); + int ret; + + setenv ("P11_KIT_STRICT", "1", 1); + p11_debug_init (); + + SUITE_ADD_TEST (suite, test_init_uninit); + SUITE_ADD_TEST (suite, test_init_for_data); + SUITE_ADD_TEST (suite, test_append); + SUITE_ADD_TEST (suite, test_null); + SUITE_ADD_TEST (suite, test_add); + SUITE_ADD_TEST (suite, test_steal); + + CuSuiteRun (suite); + CuSuiteSummary (suite, output); + CuSuiteDetails (suite, output); + printf ("%s\n", output->buffer); + ret = suite->failCount; + CuSuiteDelete (suite); + CuStringDelete (output); + + return ret; +} diff --git a/p11-kit/uri.c b/p11-kit/uri.c index 9678358..8b16e46 100644 --- a/p11-kit/uri.c +++ b/p11-kit/uri.c @@ -35,6 +35,7 @@ #include "config.h" #include "attrs.h" +#include "buffer.h" #define P11_DEBUG_FLAG P11_DEBUG_URI #include "debug.h" #include "library.h" @@ -704,41 +705,27 @@ p11_kit_uri_new (void) } static bool -format_raw_string (char **string, - size_t *length, +format_raw_string (p11_buffer *buffer, bool *is_first, const char *name, const char *value) { - size_t namelen; - size_t vallen; - /* Not set */ if (!value) return true; - namelen = strlen (name); - vallen = strlen (value); - - *string = realloc (*string, *length + namelen + vallen + 3); - return_val_if_fail (*string != NULL, false); - if (!*is_first) - (*string)[(*length)++] = ';'; - memcpy ((*string) + *length, name, namelen); - *length += namelen; - (*string)[(*length)++] = '='; - memcpy ((*string) + *length, value, vallen); - *length += vallen; - (*string)[*length] = 0; + p11_buffer_add (buffer, ";", 1); + p11_buffer_add (buffer, name, -1); + p11_buffer_add (buffer, "=", 1); + p11_buffer_add (buffer, value, -1); *is_first = false; - return true; + return p11_buffer_ok (buffer); } static bool -format_encode_string (char **string, - size_t *length, +format_encode_string (p11_buffer *buffer, bool *is_first, const char *name, const unsigned char *value, @@ -751,15 +738,14 @@ format_encode_string (char **string, encoded = url_encode (value, value + n_value, NULL, force); return_val_if_fail (encoded != NULL, false); - ret = format_raw_string (string, length, is_first, name, encoded); + ret = format_raw_string (buffer, is_first, name, encoded); free (encoded); return ret; } static bool -format_struct_string (char **string, - size_t *length, +format_struct_string (p11_buffer *buffer, bool *is_first, const char *name, const unsigned char *value, @@ -772,12 +758,11 @@ format_struct_string (char **string, return true; len = p11_kit_space_strlen (value, value_max); - return format_encode_string (string, length, is_first, name, value, len, false); + return format_encode_string (buffer, is_first, name, value, len, false); } static bool -format_attribute_string (char **string, - size_t *length, +format_attribute_string (p11_buffer *buffer, bool *is_first, const char *name, CK_ATTRIBUTE_PTR attr, @@ -787,14 +772,13 @@ format_attribute_string (char **string, if (attr == NULL) return true; - return format_encode_string (string, length, is_first, name, + return format_encode_string (buffer, is_first, name, attr->pValue, attr->ulValueLen, force); } static bool -format_attribute_class (char **string, - size_t *length, +format_attribute_class (p11_buffer *buffer, bool *is_first, const char *name, CK_ATTRIBUTE_PTR attr) @@ -827,25 +811,24 @@ format_attribute_class (char **string, return true; } - return format_raw_string (string, length, is_first, name, value); + return format_raw_string (buffer, is_first, name, value); } static bool -format_struct_version (char **string, - size_t *length, +format_struct_version (p11_buffer *buffer, bool *is_first, const char *name, CK_VERSION_PTR version) { - char buffer[64]; + char buf[64]; /* Not set */ if (version->major == (CK_BYTE)-1 && version->minor == (CK_BYTE)-1) return true; - snprintf (buffer, sizeof (buffer), "%d.%d", + snprintf (buf, sizeof (buf), "%d.%d", (int)version->major, (int)version->minor); - return format_raw_string (string, length, is_first, name, buffer); + return format_raw_string (buffer, is_first, name, buf); } /** @@ -879,26 +862,23 @@ format_struct_version (char **string, int p11_kit_uri_format (P11KitUri *uri, P11KitUriType uri_type, char **string) { - char *result = NULL; - size_t length = 0; + p11_buffer buffer; bool is_first = true; return_val_if_fail (uri != NULL, P11_KIT_URI_UNEXPECTED); return_val_if_fail (string != NULL, P11_KIT_URI_UNEXPECTED); - result = malloc (128); - return_val_if_fail (result != NULL, P11_KIT_URI_UNEXPECTED); + if (!p11_buffer_init_null (&buffer, 64)) + return_val_if_reached (P11_KIT_URI_UNEXPECTED); - length = P11_KIT_URI_SCHEME_LEN; - memcpy (result, P11_KIT_URI_SCHEME, length); - result[length] = ':'; - result[++length] = 0; + p11_buffer_add (&buffer, P11_KIT_URI_SCHEME, P11_KIT_URI_SCHEME_LEN); + p11_buffer_add (&buffer, ":", 1); if ((uri_type & P11_KIT_URI_FOR_MODULE) == P11_KIT_URI_FOR_MODULE) { - if (!format_struct_string (&result, &length, &is_first, "library-description", + if (!format_struct_string (&buffer, &is_first, "library-description", uri->module.libraryDescription, sizeof (uri->module.libraryDescription)) || - !format_struct_string (&result, &length, &is_first, "library-manufacturer", + !format_struct_string (&buffer, &is_first, "library-manufacturer", uri->module.manufacturerID, sizeof (uri->module.manufacturerID))) { return_val_if_reached (P11_KIT_URI_UNEXPECTED); @@ -906,23 +886,23 @@ p11_kit_uri_format (P11KitUri *uri, P11KitUriType uri_type, char **string) } if ((uri_type & P11_KIT_URI_FOR_MODULE_WITH_VERSION) == P11_KIT_URI_FOR_MODULE_WITH_VERSION) { - if (!format_struct_version (&result, &length, &is_first, "library-version", + if (!format_struct_version (&buffer, &is_first, "library-version", &uri->module.libraryVersion)) { return_val_if_reached (P11_KIT_URI_UNEXPECTED); } } if ((uri_type & P11_KIT_URI_FOR_TOKEN) == P11_KIT_URI_FOR_TOKEN) { - if (!format_struct_string (&result, &length, &is_first, "model", + if (!format_struct_string (&buffer, &is_first, "model", uri->token.model, sizeof (uri->token.model)) || - !format_struct_string (&result, &length, &is_first, "manufacturer", + !format_struct_string (&buffer, &is_first, "manufacturer", uri->token.manufacturerID, sizeof (uri->token.manufacturerID)) || - !format_struct_string (&result, &length, &is_first, "serial", + !format_struct_string (&buffer, &is_first, "serial", uri->token.serialNumber, sizeof (uri->token.serialNumber)) || - !format_struct_string (&result, &length, &is_first, "token", + !format_struct_string (&buffer, &is_first, "token", uri->token.label, sizeof (uri->token.label))) { return_val_if_reached (P11_KIT_URI_UNEXPECTED); @@ -930,30 +910,31 @@ p11_kit_uri_format (P11KitUri *uri, P11KitUriType uri_type, char **string) } if ((uri_type & P11_KIT_URI_FOR_OBJECT) == P11_KIT_URI_FOR_OBJECT) { - if (!format_attribute_string (&result, &length, &is_first, "id", + if (!format_attribute_string (&buffer, &is_first, "id", p11_kit_uri_get_attribute (uri, CKA_ID), true) || - !format_attribute_string (&result, &length, &is_first, "object", + !format_attribute_string (&buffer, &is_first, "object", p11_kit_uri_get_attribute (uri, CKA_LABEL), false)) { return_val_if_reached (P11_KIT_URI_UNEXPECTED); } - if (!format_attribute_class (&result, &length, &is_first, "object-type", + if (!format_attribute_class (&buffer, &is_first, "object-type", p11_kit_uri_get_attribute (uri, CKA_CLASS))) { return_val_if_reached (P11_KIT_URI_UNEXPECTED); } } if (uri->pin_source) { - if (!format_encode_string (&result, &length, &is_first, "pin-source", + if (!format_encode_string (&buffer, &is_first, "pin-source", (const unsigned char*)uri->pin_source, strlen (uri->pin_source), 0)) { return_val_if_reached (P11_KIT_URI_UNEXPECTED); } } - *string = result; + return_val_if_fail (p11_buffer_ok (&buffer), P11_KIT_URI_UNEXPECTED); + *string = p11_buffer_steal (&buffer, NULL); return P11_KIT_URI_OK; } |