diff options
Diffstat (limited to 'src/libstrongswan/utils')
33 files changed, 5503 insertions, 4168 deletions
diff --git a/src/libstrongswan/utils/backtrace.c b/src/libstrongswan/utils/backtrace.c index b6015fb35..0b6683233 100644 --- a/src/libstrongswan/utils/backtrace.c +++ b/src/libstrongswan/utils/backtrace.c @@ -54,7 +54,7 @@ struct private_backtrace_t { #ifdef HAVE_BFD_H #include <bfd.h> -#include <utils/hashtable.h> +#include <collections/hashtable.h> #include <threading/mutex.h> /** diff --git a/src/libstrongswan/utils/blocking_queue.c b/src/libstrongswan/utils/blocking_queue.c deleted file mode 100644 index c70184198..000000000 --- a/src/libstrongswan/utils/blocking_queue.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2012 Tobias Brunner - * Copyright (C) 2012 Giuliano Grassi - * Copyright (C) 2012 Ralf Sager - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program 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 General Public License - * for more details. - */ - -#include "blocking_queue.h" - -#include <threading/mutex.h> -#include <threading/thread.h> -#include <threading/condvar.h> -#include <utils/linked_list.h> - -typedef struct private_blocking_queue_t private_blocking_queue_t; - -/** - * Private data of a blocking_queue_t object. - */ -struct private_blocking_queue_t { - - /** - * Public part - */ - blocking_queue_t public; - - /** - * Linked list containing all items in the queue - */ - linked_list_t *list; - - /** - * Mutex used to synchronize access to the queue - */ - mutex_t *mutex; - - /** - * Condvar used to wait for items - */ - condvar_t *condvar; - -}; - -METHOD(blocking_queue_t, enqueue, void, - private_blocking_queue_t *this, void *item) -{ - this->mutex->lock(this->mutex); - this->list->insert_first(this->list, item); - this->condvar->signal(this->condvar); - this->mutex->unlock(this->mutex); -} - -METHOD(blocking_queue_t, dequeue, void*, - private_blocking_queue_t *this) -{ - bool oldstate; - void *item; - - - this->mutex->lock(this->mutex); - thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex); - /* ensure that a canceled thread does not dequeue any items */ - thread_cancellation_point(); - while (this->list->remove_last(this->list, &item) != SUCCESS) - { - oldstate = thread_cancelability(TRUE); - this->condvar->wait(this->condvar, this->mutex); - thread_cancelability(oldstate); - } - thread_cleanup_pop(TRUE); - return item; -} - -METHOD(blocking_queue_t, destroy, void, - private_blocking_queue_t *this) -{ - this->list->destroy(this->list); - this->condvar->destroy(this->condvar); - this->mutex->destroy(this->mutex); - free(this); -} - -METHOD(blocking_queue_t, destroy_offset, void, - private_blocking_queue_t *this, size_t offset) -{ - this->list->invoke_offset(this->list, offset); - destroy(this); -} - -METHOD(blocking_queue_t, destroy_function, void, - private_blocking_queue_t *this, void (*fn)(void*)) -{ - this->list->invoke_function(this->list, (linked_list_invoke_t)fn); - destroy(this); -} - -/* - * Described in header. - */ -blocking_queue_t *blocking_queue_create() -{ - private_blocking_queue_t *this; - - INIT(this, - .public = { - .enqueue = _enqueue, - .dequeue = _dequeue, - .destroy = _destroy, - .destroy_offset = _destroy_offset, - .destroy_function = _destroy_function, - }, - .list = linked_list_create(), - .mutex = mutex_create(MUTEX_TYPE_DEFAULT), - .condvar = condvar_create(CONDVAR_TYPE_DEFAULT), - ); - - return &this->public; -} - diff --git a/src/libstrongswan/utils/blocking_queue.h b/src/libstrongswan/utils/blocking_queue.h deleted file mode 100644 index cf2712cf4..000000000 --- a/src/libstrongswan/utils/blocking_queue.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2012 Tobias Brunner - * Copyright (C) 2012 Giuliano Grassi - * Copyright (C) 2012 Ralf Sager - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program 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 General Public License - * for more details. - */ - -/** - * @defgroup blocking_queue blocking_queue - * @{ @ingroup utils - */ - -#ifndef BLOCKING_QUEUE_H_ -#define BLOCKING_QUEUE_H_ - -typedef struct blocking_queue_t blocking_queue_t; - -#include <library.h> - -/** - * Class implementing a synchronized blocking queue based on linked_list_t - */ -struct blocking_queue_t { - - /** - * Inserts a new item at the tail of the queue - * - * @param item item to insert in queue - */ - void (*enqueue)(blocking_queue_t *this, void *item); - - /** - * Removes the first item in the queue and returns its value. - * If the queue is empty, this call blocks until a new item is inserted. - * - * @note This is a thread cancellation point - * - * @return removed item - */ - void *(*dequeue)(blocking_queue_t *this); - - /** - * Destroys a blocking_queue_t object. - * - * @note No thread must wait in dequeue() when this function is called - */ - void (*destroy)(blocking_queue_t *this); - - /** - * Destroys a queue and its objects using the given destructor. - * - * If a queue and the contained objects should be destroyed, use - * destroy_offset. The supplied offset specifies the destructor to - * call on each object. The offset may be calculated using the offsetof - * macro, e.g.: queue->destroy_offset(queue, offsetof(object_t, destroy)); - * - * @note No thread must wait in dequeue() when this function is called - * - * @param offset offset of the objects destructor - */ - void (*destroy_offset)(blocking_queue_t *this, size_t offset); - - /** - * Destroys a queue and its objects using a cleanup function. - * - * If a queue and its contents should get destroyed using a specific - * cleanup function, use destroy_function. This is useful when the - * list contains malloc()-ed blocks which should get freed, - * e.g.: queue->destroy_function(queue, free); - * - * @note No thread must wait in dequeue() when this function is called - * - * @param function function to call on each object - */ - void (*destroy_function)(blocking_queue_t *this, void (*)(void*)); - -}; - -/** - * Creates an empty queue object. - * - * @return blocking_queue_t object. - */ -blocking_queue_t *blocking_queue_create(); - -#endif /** BLOCKING_QUEUE_H_ @}*/ - diff --git a/src/libstrongswan/utils/capabilities.c b/src/libstrongswan/utils/capabilities.c index 34128d010..c36a76efe 100644 --- a/src/libstrongswan/utils/capabilities.c +++ b/src/libstrongswan/utils/capabilities.c @@ -27,7 +27,7 @@ # include <sys/prctl.h> #endif /* HAVE_PRCTL */ -#include <debug.h> +#include <utils/debug.h> #if !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETGRNAM_R) # include <threading/mutex.h> diff --git a/src/libstrongswan/utils/chunk.c b/src/libstrongswan/utils/chunk.c new file mode 100644 index 000000000..d7f1c31d9 --- /dev/null +++ b/src/libstrongswan/utils/chunk.c @@ -0,0 +1,690 @@ +/* + * Copyright (C) 2008-2009 Tobias Brunner + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program 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 General Public License + * for more details. + */ + +#include <stdio.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> +#include <ctype.h> + +#include "chunk.h" +#include "debug.h" + +/* required for chunk_hash */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) +#define get16bits(d) (*((const u_int16_t*)(d))) +#endif +#if !defined (get16bits) +#define get16bits(d) ((((u_int32_t)(((const u_int8_t*)(d))[1])) << 8)\ + + (u_int32_t)(((const u_int8_t*)(d))[0]) ) +#endif + +/** + * Empty chunk. + */ +chunk_t chunk_empty = { NULL, 0 }; + +/** + * Described in header. + */ +chunk_t chunk_create_clone(u_char *ptr, chunk_t chunk) +{ + chunk_t clone = chunk_empty; + + if (chunk.ptr && chunk.len > 0) + { + clone.ptr = ptr; + clone.len = chunk.len; + memcpy(clone.ptr, chunk.ptr, chunk.len); + } + + return clone; +} + +/** + * Described in header. + */ +size_t chunk_length(const char* mode, ...) +{ + va_list chunks; + size_t length = 0; + + va_start(chunks, mode); + while (TRUE) + { + switch (*mode++) + { + case 'm': + case 'c': + case 's': + { + chunk_t ch = va_arg(chunks, chunk_t); + length += ch.len; + continue; + } + default: + break; + } + break; + } + va_end(chunks); + return length; +} + +/** + * Described in header. + */ +chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...) +{ + va_list chunks; + chunk_t construct = chunk_create(ptr, 0); + + va_start(chunks, mode); + while (TRUE) + { + bool free_chunk = FALSE, clear_chunk = FALSE; + chunk_t ch; + + switch (*mode++) + { + case 's': + clear_chunk = TRUE; + /* FALL */ + case 'm': + free_chunk = TRUE; + /* FALL */ + case 'c': + ch = va_arg(chunks, chunk_t); + memcpy(ptr, ch.ptr, ch.len); + ptr += ch.len; + construct.len += ch.len; + if (clear_chunk) + { + chunk_clear(&ch); + } + else if (free_chunk) + { + free(ch.ptr); + } + continue; + default: + break; + } + break; + } + va_end(chunks); + + return construct; +} + +/** + * Described in header. + */ +void chunk_split(chunk_t chunk, const char *mode, ...) +{ + va_list chunks; + u_int len; + chunk_t *ch; + + va_start(chunks, mode); + while (TRUE) + { + if (*mode == '\0') + { + break; + } + len = va_arg(chunks, u_int); + ch = va_arg(chunks, chunk_t*); + /* a null chunk means skip len bytes */ + if (ch == NULL) + { + chunk = chunk_skip(chunk, len); + continue; + } + switch (*mode++) + { + case 'm': + { + ch->len = min(chunk.len, len); + if (ch->len) + { + ch->ptr = chunk.ptr; + } + else + { + ch->ptr = NULL; + } + chunk = chunk_skip(chunk, ch->len); + continue; + } + case 'a': + { + ch->len = min(chunk.len, len); + if (ch->len) + { + ch->ptr = malloc(ch->len); + memcpy(ch->ptr, chunk.ptr, ch->len); + } + else + { + ch->ptr = NULL; + } + chunk = chunk_skip(chunk, ch->len); + continue; + } + case 'c': + { + ch->len = min(ch->len, chunk.len); + ch->len = min(ch->len, len); + if (ch->len) + { + memcpy(ch->ptr, chunk.ptr, ch->len); + } + else + { + ch->ptr = NULL; + } + chunk = chunk_skip(chunk, ch->len); + continue; + } + default: + break; + } + break; + } + va_end(chunks); +} + +/** + * Described in header. + */ +bool chunk_write(chunk_t chunk, char *path, char *label, mode_t mask, bool force) +{ + mode_t oldmask; + FILE *fd; + bool good = FALSE; + + if (!force && access(path, F_OK) == 0) + { + DBG1(DBG_LIB, " %s file '%s' already exists", label, path); + return FALSE; + } + oldmask = umask(mask); + fd = fopen(path, "w"); + if (fd) + { + if (fwrite(chunk.ptr, sizeof(u_char), chunk.len, fd) == chunk.len) + { + DBG1(DBG_LIB, " written %s file '%s' (%d bytes)", + label, path, chunk.len); + good = TRUE; + } + else + { + DBG1(DBG_LIB, " writing %s file '%s' failed: %s", + label, path, strerror(errno)); + } + fclose(fd); + } + else + { + DBG1(DBG_LIB, " could not open %s file '%s': %s", label, path, + strerror(errno)); + } + umask(oldmask); + return good; +} + + +/** hex conversion digits */ +static char hexdig_upper[] = "0123456789ABCDEF"; +static char hexdig_lower[] = "0123456789abcdef"; + +/** + * Described in header. + */ +chunk_t chunk_to_hex(chunk_t chunk, char *buf, bool uppercase) +{ + int i, len; + char *hexdig = hexdig_lower; + + if (uppercase) + { + hexdig = hexdig_upper; + } + + len = chunk.len * 2; + if (!buf) + { + buf = malloc(len + 1); + } + buf[len] = '\0'; + + for (i = 0; i < chunk.len; i++) + { + buf[i*2] = hexdig[(chunk.ptr[i] >> 4) & 0xF]; + buf[i*2+1] = hexdig[(chunk.ptr[i] ) & 0xF]; + } + return chunk_create(buf, len); +} + +/** + * convert a signle hex character to its binary value + */ +static char hex2bin(char hex) +{ + switch (hex) + { + case '0' ... '9': + return hex - '0'; + case 'A' ... 'F': + return hex - 'A' + 10; + case 'a' ... 'f': + return hex - 'a' + 10; + default: + return 0; + } +} + +/** + * Described in header. + */ +chunk_t chunk_from_hex(chunk_t hex, char *buf) +{ + int i, len; + u_char *ptr; + bool odd = FALSE; + + /* subtract the number of optional ':' separation characters */ + len = hex.len; + ptr = hex.ptr; + for (i = 0; i < hex.len; i++) + { + if (*ptr++ == ':') + { + len--; + } + } + + /* compute the number of binary bytes */ + if (len % 2) + { + odd = TRUE; + len++; + } + len /= 2; + + /* allocate buffer memory unless provided by caller */ + if (!buf) + { + buf = malloc(len); + } + + /* buffer is filled from the right */ + memset(buf, 0, len); + hex.ptr += hex.len; + + for (i = len - 1; i >= 0; i--) + { + /* skip separation characters */ + if (*(--hex.ptr) == ':') + { + --hex.ptr; + } + buf[i] = hex2bin(*hex.ptr); + if (i > 0 || !odd) + { + buf[i] |= hex2bin(*(--hex.ptr)) << 4; + } + } + return chunk_create(buf, len); +} + +/** base 64 conversion digits */ +static char b64digits[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/** + * Described in header. + */ +chunk_t chunk_to_base64(chunk_t chunk, char *buf) +{ + int i, len; + char *pos; + + len = chunk.len + ((3 - chunk.len % 3) % 3); + if (!buf) + { + buf = malloc(len * 4 / 3 + 1); + } + pos = buf; + for (i = 0; i < len; i+=3) + { + *pos++ = b64digits[chunk.ptr[i] >> 2]; + if (i+1 >= chunk.len) + { + *pos++ = b64digits[(chunk.ptr[i] & 0x03) << 4]; + *pos++ = '='; + *pos++ = '='; + break; + } + *pos++ = b64digits[((chunk.ptr[i] & 0x03) << 4) | (chunk.ptr[i+1] >> 4)]; + if (i+2 >= chunk.len) + { + *pos++ = b64digits[(chunk.ptr[i+1] & 0x0F) << 2]; + *pos++ = '='; + break; + } + *pos++ = b64digits[((chunk.ptr[i+1] & 0x0F) << 2) | (chunk.ptr[i+2] >> 6)]; + *pos++ = b64digits[chunk.ptr[i+2] & 0x3F]; + } + *pos = '\0'; + return chunk_create(buf, len * 4 / 3); +} + +/** + * convert a base 64 digit to its binary form (inversion of b64digits array) + */ +static int b642bin(char b64) +{ + switch (b64) + { + case 'A' ... 'Z': + return b64 - 'A'; + case 'a' ... 'z': + return ('Z' - 'A' + 1) + b64 - 'a'; + case '0' ... '9': + return ('Z' - 'A' + 1) + ('z' - 'a' + 1) + b64 - '0'; + case '+': + case '-': + return 62; + case '/': + case '_': + return 63; + case '=': + return 0; + default: + return -1; + } +} + +/** + * Described in header. + */ +chunk_t chunk_from_base64(chunk_t base64, char *buf) +{ + u_char *pos, byte[4]; + int i, j, len, outlen; + + len = base64.len / 4 * 3; + if (!buf) + { + buf = malloc(len); + } + pos = base64.ptr; + outlen = 0; + for (i = 0; i < len; i+=3) + { + outlen += 3; + for (j = 0; j < 4; j++) + { + if (*pos == '=') + { + outlen--; + } + byte[j] = b642bin(*pos++); + } + buf[i] = (byte[0] << 2) | (byte[1] >> 4); + buf[i+1] = (byte[1] << 4) | (byte[2] >> 2); + buf[i+2] = (byte[2] << 6) | (byte[3]); + } + return chunk_create(buf, outlen); +} + +/** base 32 conversion digits */ +static char b32digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + +/** + * Described in header. + */ +chunk_t chunk_to_base32(chunk_t chunk, char *buf) +{ + int i, len; + char *pos; + + len = chunk.len + ((5 - chunk.len % 5) % 5); + if (!buf) + { + buf = malloc(len * 8 / 5 + 1); + } + pos = buf; + for (i = 0; i < len; i+=5) + { + *pos++ = b32digits[chunk.ptr[i] >> 3]; + if (i+1 >= chunk.len) + { + *pos++ = b32digits[(chunk.ptr[i] & 0x07) << 2]; + memset(pos, '=', 6); + pos += 6; + break; + } + *pos++ = b32digits[((chunk.ptr[i] & 0x07) << 2) | + (chunk.ptr[i+1] >> 6)]; + *pos++ = b32digits[(chunk.ptr[i+1] & 0x3E) >> 1]; + if (i+2 >= chunk.len) + { + *pos++ = b32digits[(chunk.ptr[i+1] & 0x01) << 4]; + memset(pos, '=', 4); + pos += 4; + break; + } + *pos++ = b32digits[((chunk.ptr[i+1] & 0x01) << 4) | + (chunk.ptr[i+2] >> 4)]; + if (i+3 >= chunk.len) + { + *pos++ = b32digits[(chunk.ptr[i+2] & 0x0F) << 1]; + memset(pos, '=', 3); + pos += 3; + break; + } + *pos++ = b32digits[((chunk.ptr[i+2] & 0x0F) << 1) | + (chunk.ptr[i+3] >> 7)]; + *pos++ = b32digits[(chunk.ptr[i+3] & 0x7F) >> 2]; + if (i+4 >= chunk.len) + { + *pos++ = b32digits[(chunk.ptr[i+3] & 0x03) << 3]; + *pos++ = '='; + break; + } + *pos++ = b32digits[((chunk.ptr[i+3] & 0x03) << 3) | + (chunk.ptr[i+4] >> 5)]; + *pos++ = b32digits[chunk.ptr[i+4] & 0x1F]; + } + *pos = '\0'; + return chunk_create(buf, len * 8 / 5); +} + +/** + * Described in header. + */ +int chunk_compare(chunk_t a, chunk_t b) +{ + int compare_len = a.len - b.len; + int len = (compare_len < 0)? a.len : b.len; + + if (compare_len != 0 || len == 0) + { + return compare_len; + } + return memcmp(a.ptr, b.ptr, len); +}; + + +/** + * Described in header. + */ +bool chunk_increment(chunk_t chunk) +{ + int i; + + for (i = chunk.len - 1; i >= 0; i--) + { + if (++chunk.ptr[i] != 0) + { + return FALSE; + } + } + return TRUE; +} + +/** + * Remove non-printable characters from a chunk. + */ +bool chunk_printable(chunk_t chunk, chunk_t *sane, char replace) +{ + bool printable = TRUE; + int i; + + if (sane) + { + *sane = chunk_clone(chunk); + } + for (i = 0; i < chunk.len; i++) + { + if (!isprint(chunk.ptr[i])) + { + if (sane) + { + sane->ptr[i] = replace; + } + printable = FALSE; + } + } + return printable; +} + +/** + * Described in header. + * + * The implementation is based on Paul Hsieh's SuperFastHash: + * http://www.azillionmonkeys.com/qed/hash.html + */ +u_int32_t chunk_hash_inc(chunk_t chunk, u_int32_t hash) +{ + u_char *data = chunk.ptr; + size_t len = chunk.len; + u_int32_t tmp; + int rem; + + if (!len || data == NULL) + { + return 0; + } + + rem = len & 3; + len >>= 2; + + /* Main loop */ + for (; len > 0; --len) + { + hash += get16bits(data); + tmp = (get16bits(data + 2) << 11) ^ hash; + hash = (hash << 16) ^ tmp; + data += 2 * sizeof(u_int16_t); + hash += hash >> 11; + } + + /* Handle end cases */ + switch (rem) + { + case 3: + { + hash += get16bits(data); + hash ^= hash << 16; + hash ^= data[sizeof(u_int16_t)] << 18; + hash += hash >> 11; + break; + } + case 2: + { + hash += get16bits(data); + hash ^= hash << 11; + hash += hash >> 17; + break; + } + case 1: + { + hash += *data; + hash ^= hash << 10; + hash += hash >> 1; + break; + } + } + + /* Force "avalanching" of final 127 bits */ + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + + return hash; +} + +/** + * Described in header. + */ +u_int32_t chunk_hash(chunk_t chunk) +{ + return chunk_hash_inc(chunk, chunk.len); +} + +/** + * Described in header. + */ +int chunk_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, + const void *const *args) +{ + chunk_t *chunk = *((chunk_t**)(args[0])); + bool first = TRUE; + chunk_t copy = *chunk; + int written = 0; + + if (!spec->hash) + { + u_int chunk_len = chunk->len; + const void *new_args[] = {&chunk->ptr, &chunk_len}; + return mem_printf_hook(data, spec, new_args); + } + + while (copy.len > 0) + { + if (first) + { + first = FALSE; + } + else + { + written += print_in_hook(data, ":"); + } + written += print_in_hook(data, "%02x", *copy.ptr++); + copy.len--; + } + return written; +} diff --git a/src/libstrongswan/utils/chunk.h b/src/libstrongswan/utils/chunk.h new file mode 100644 index 000000000..67848eec1 --- /dev/null +++ b/src/libstrongswan/utils/chunk.h @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2008-2009 Tobias Brunner + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program 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 General Public License + * for more details. + */ + +/** + * @defgroup chunk chunk + * @{ @ingroup utils + */ + +#ifndef CHUNK_H_ +#define CHUNK_H_ + +#include <string.h> +#include <stdarg.h> +#include <sys/types.h> +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#endif + +typedef struct chunk_t chunk_t; + +/** + * General purpose pointer/length abstraction. + */ +struct chunk_t { + /** Pointer to start of data */ + u_char *ptr; + /** Length of data in bytes */ + size_t len; +}; + +#include "utils.h" + +/** + * A { NULL, 0 }-chunk handy for initialization. + */ +extern chunk_t chunk_empty; + +/** + * Create a new chunk pointing to "ptr" with length "len" + */ +static inline chunk_t chunk_create(u_char *ptr, size_t len) +{ + chunk_t chunk = {ptr, len}; + return chunk; +} + +/** + * Create a clone of a chunk pointing to "ptr" + */ +chunk_t chunk_create_clone(u_char *ptr, chunk_t chunk); + +/** + * Calculate length of multiple chunks + */ +size_t chunk_length(const char *mode, ...); + +/** + * Concatenate chunks into a chunk pointing to "ptr". + * + * The mode string specifies the number of chunks, and how to handle each of + * them with a single character: 'c' for copy (allocate new chunk), 'm' for move + * (free given chunk) or 's' for sensitive-move (clear given chunk, then free). + */ +chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...); + +/** + * Split up a chunk into parts, "mode" is a string of "a" (alloc), + * "c" (copy) and "m" (move). Each letter say for the corresponding chunk if + * it should get allocated on heap, copied into existing chunk, or the chunk + * should point into "chunk". The length of each part is an argument before + * each target chunk. E.g.: + * chunk_split(chunk, "mcac", 3, &a, 7, &b, 5, &c, d.len, &d); + */ +void chunk_split(chunk_t chunk, const char *mode, ...); + +/** + * Write the binary contents of a chunk_t to a file + * + * @param chunk contents to write to file + * @param path path where file is written to + * @param label label specifying file type + * @param mask file mode creation mask + * @param force overwrite existing file by force + * @return TRUE if write operation was successful + */ +bool chunk_write(chunk_t chunk, char *path, char *label, mode_t mask, bool force); + +/** + * Convert a chunk of data to hex encoding. + * + * The resulting string is '\\0' terminated, but the chunk does not include + * the '\\0'. If buf is supplied, it must hold at least (chunk.len * 2 + 1). + * + * @param chunk data to convert to hex encoding + * @param buf buffer to write to, NULL to malloc + * @param uppercase TRUE to use uppercase letters + * @return chunk of encoded data + */ +chunk_t chunk_to_hex(chunk_t chunk, char *buf, bool uppercase); + +/** + * Convert a hex encoded in a binary chunk. + * + * If buf is supplied, it must hold at least (hex.len / 2) + (hex.len % 2) + * bytes. It is filled by the right to give correct values for short inputs. + * + * @param hex hex encoded input data + * @param buf buffer to write decoded data, NULL to malloc + * @return converted data + */ +chunk_t chunk_from_hex(chunk_t hex, char *buf); + +/** + * Convert a chunk of data to its base64 encoding. + * + * The resulting string is '\\0' terminated, but the chunk does not include + * the '\\0'. If buf is supplied, it must hold at least (chunk.len * 4 / 3 + 1). + * + * @param chunk data to convert + * @param buf buffer to write to, NULL to malloc + * @return chunk of encoded data + */ +chunk_t chunk_to_base64(chunk_t chunk, char *buf); + +/** + * Convert a base64 in a binary chunk. + * + * If buf is supplied, it must hold at least (base64.len / 4 * 3). + * + * @param base64 base64 encoded input data + * @param buf buffer to write decoded data, NULL to malloc + * @return converted data + */ +chunk_t chunk_from_base64(chunk_t base64, char *buf); + +/** + * Convert a chunk of data to its base32 encoding. + * + * The resulting string is '\\0' terminated, but the chunk does not include + * the '\\0'. If buf is supplied, it must hold (chunk.len * 8 / 5 + 1) bytes. + * + * @param chunk data to convert + * @param buf buffer to write to, NULL to malloc + * @return chunk of encoded data + */ +chunk_t chunk_to_base32(chunk_t chunk, char *buf); + +/** + * Free contents of a chunk + */ +static inline void chunk_free(chunk_t *chunk) +{ + free(chunk->ptr); + *chunk = chunk_empty; +} + +/** + * Overwrite the contents of a chunk and free it + */ +static inline void chunk_clear(chunk_t *chunk) +{ + if (chunk->ptr) + { + memwipe(chunk->ptr, chunk->len); + chunk_free(chunk); + } +} + +/** + * Initialize a chunk using a char array + */ +#define chunk_from_chars(...) ((chunk_t){(char[]){__VA_ARGS__}, sizeof((char[]){__VA_ARGS__})}) + +/** + * Initialize a chunk to point to a thing + */ +#define chunk_from_thing(thing) chunk_create((char*)&(thing), sizeof(thing)) + +/** + * Allocate a chunk on the heap + */ +#define chunk_alloc(bytes) ({size_t x = (bytes); chunk_create(x ? malloc(x) : NULL, x);}) + +/** + * Allocate a chunk on the stack + */ +#define chunk_alloca(bytes) ({size_t x = (bytes); chunk_create(x ? alloca(x) : NULL, x);}) + +/** + * Clone a chunk on heap + */ +#define chunk_clone(chunk) ({chunk_t x = (chunk); chunk_create_clone(x.len ? malloc(x.len) : NULL, x);}) + +/** + * Clone a chunk on stack + */ +#define chunk_clonea(chunk) ({chunk_t x = (chunk); chunk_create_clone(x.len ? alloca(x.len) : NULL, x);}) + +/** + * Concatenate chunks into a chunk on heap + */ +#define chunk_cat(mode, ...) chunk_create_cat(malloc(chunk_length(mode, __VA_ARGS__)), mode, __VA_ARGS__) + +/** + * Concatenate chunks into a chunk on stack + */ +#define chunk_cata(mode, ...) chunk_create_cat(alloca(chunk_length(mode, __VA_ARGS__)), mode, __VA_ARGS__) + +/** + * Skip n bytes in chunk (forward pointer, shorten length) + */ +static inline chunk_t chunk_skip(chunk_t chunk, size_t bytes) +{ + if (chunk.len > bytes) + { + chunk.ptr += bytes; + chunk.len -= bytes; + return chunk; + } + return chunk_empty; +} + +/** + * Skip a leading zero-valued byte + */ +static inline chunk_t chunk_skip_zero(chunk_t chunk) +{ + if (chunk.len > 1 && *chunk.ptr == 0x00) + { + chunk.ptr++; + chunk.len--; + } + return chunk; +} + + +/** + * Compare two chunks, returns zero if a equals b + * or negative/positive if a is small/greater than b + */ +int chunk_compare(chunk_t a, chunk_t b); + +/** + * Compare two chunks for equality, + * NULL chunks are never equal. + */ +static inline bool chunk_equals(chunk_t a, chunk_t b) +{ + return a.ptr != NULL && b.ptr != NULL && + a.len == b.len && memeq(a.ptr, b.ptr, a.len); +} + +/** + * Compare two chunks (given as pointers) for equality (useful as callback), + * NULL chunks are never equal. + */ +static inline bool chunk_equals_ptr(chunk_t *a, chunk_t *b) +{ + return a != NULL && b != NULL && chunk_equals(*a, *b); +} + +/** + * Increment a chunk, as it would reprensent a network order integer. + * + * @param chunk chunk to increment + * @return TRUE if an overflow occurred + */ +bool chunk_increment(chunk_t chunk); + +/** + * Check if a chunk has printable characters only. + * + * If sane is given, chunk is cloned into sane and all non printable characters + * get replaced by "replace". + * + * @param chunk chunk to check for printability + * @param sane pointer where sane version is allocated, or NULL + * @param replace character to use for replaceing unprintable characters + * @return TRUE if all characters in chunk are printable + */ +bool chunk_printable(chunk_t chunk, chunk_t *sane, char replace); + +/** + * Computes a 32 bit hash of the given chunk. + * Note: This hash is only intended for hash tables not for cryptographic purposes. + */ +u_int32_t chunk_hash(chunk_t chunk); + +/** + * Incremental version of chunk_hash. Use this to hash two or more chunks. + */ +u_int32_t chunk_hash_inc(chunk_t chunk, u_int32_t hash); + +/** + * printf hook function for chunk_t. + * + * Arguments are: + * chunk_t *chunk + * Use #-modifier to print a compact version + */ +int chunk_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, + const void *const *args); + +#endif /** CHUNK_H_ @}*/ diff --git a/src/libstrongswan/utils/debug.c b/src/libstrongswan/utils/debug.c new file mode 100644 index 000000000..e8c9e6b98 --- /dev/null +++ b/src/libstrongswan/utils/debug.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program 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 General Public License + * for more details. + */ + +#include <stdarg.h> + +#include "debug.h" + +ENUM(debug_names, DBG_DMN, DBG_LIB, + "DMN", + "MGR", + "IKE", + "CHD", + "JOB", + "CFG", + "KNL", + "NET", + "ASN", + "ENC", + "TNC", + "IMC", + "IMV", + "PTS", + "TLS", + "APP", + "ESP", + "LIB", +); + +ENUM(debug_lower_names, DBG_DMN, DBG_LIB, + "dmn", + "mgr", + "ike", + "chd", + "job", + "cfg", + "knl", + "net", + "asn", + "enc", + "tnc", + "imc", + "imv", + "pts", + "tls", + "app", + "esp", + "lib", +); + +/** + * level logged by the default logger + */ +static level_t default_level = 1; + +/** + * stream logged to by the default logger + */ +static FILE *default_stream = NULL; + +/** + * default dbg function which printf all to stderr + */ +void dbg_default(debug_t group, level_t level, char *fmt, ...) +{ + if (!default_stream) + { + default_stream = stderr; + } + if (level <= default_level) + { + va_list args; + + va_start(args, fmt); + vfprintf(default_stream, fmt, args); + fprintf(default_stream, "\n"); + va_end(args); + } +} + +/** + * set the level logged by the default stderr logger + */ +void dbg_default_set_level(level_t level) +{ + default_level = level; +} + +/** + * set the stream logged by dbg_default() to + */ +void dbg_default_set_stream(FILE *stream) +{ + default_stream = stream; +} + +/** + * The registered debug hook. + */ +void (*dbg) (debug_t group, level_t level, char *fmt, ...) = dbg_default; + diff --git a/src/libstrongswan/utils/debug.h b/src/libstrongswan/utils/debug.h new file mode 100644 index 000000000..c46d3fe55 --- /dev/null +++ b/src/libstrongswan/utils/debug.h @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program 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 General Public License + * for more details. + */ + +/** + * @defgroup debug debug + * @{ @ingroup utils + */ + +#ifndef DEBUG_H_ +#define DEBUG_H_ + +typedef enum debug_t debug_t; +typedef enum level_t level_t; + +#include <stdio.h> + +#include "utils/enum.h" + +/** + * Debug message group. + */ +enum debug_t { + /** daemon specific */ + DBG_DMN, + /** IKE_SA_MANAGER */ + DBG_MGR, + /** IKE_SA */ + DBG_IKE, + /** CHILD_SA */ + DBG_CHD, + /** job processing */ + DBG_JOB, + /** configuration backends */ + DBG_CFG, + /** kernel interface */ + DBG_KNL, + /** networking/sockets */ + DBG_NET, + /** low-level encoding/decoding (ASN.1, X.509 etc.) */ + DBG_ASN, + /** message encoding/decoding */ + DBG_ENC, + /** trusted network connect */ + DBG_TNC, + /** integrity measurement client */ + DBG_IMC, + /** integrity measurement verifier */ + DBG_IMV, + /** platform trust service */ + DBG_PTS, + /** libtls */ + DBG_TLS, + /** applications other than daemons */ + DBG_APP, + /** libipsec */ + DBG_ESP, + /** libstrongswan */ + DBG_LIB, + /** number of groups */ + DBG_MAX, + /** pseudo group with all groups */ + DBG_ANY = DBG_MAX, +}; + +/** + * short names of debug message group. + */ +extern enum_name_t *debug_names; + +/** + * short names of debug message group, lower case. + */ +extern enum_name_t *debug_lower_names; + +/** + * Debug levels used to control output verbosity. + */ +enum level_t { + /** absolutely silent */ + LEVEL_SILENT = -1, + /** most important auditing logs */ + LEVEL_AUDIT = 0, + /** control flow */ + LEVEL_CTRL = 1, + /** diagnose problems */ + LEVEL_DIAG = 2, + /** raw binary blobs */ + LEVEL_RAW = 3, + /** including sensitive data (private keys) */ + LEVEL_PRIVATE = 4, +}; + +#ifndef DEBUG_LEVEL +# define DEBUG_LEVEL 4 +#endif /* DEBUG_LEVEL */ + +/** debug macros, they call the dbg function hook */ +#if DEBUG_LEVEL >= 0 +# define DBG0(group, fmt, ...) dbg(group, 0, fmt, ##__VA_ARGS__) +#endif /* DEBUG_LEVEL */ +#if DEBUG_LEVEL >= 1 +# define DBG1(group, fmt, ...) dbg(group, 1, fmt, ##__VA_ARGS__) +#endif /* DEBUG_LEVEL */ +#if DEBUG_LEVEL >= 2 +# define DBG2(group, fmt, ...) dbg(group, 2, fmt, ##__VA_ARGS__) +#endif /* DEBUG_LEVEL */ +#if DEBUG_LEVEL >= 3 +# define DBG3(group, fmt, ...) dbg(group, 3, fmt, ##__VA_ARGS__) +#endif /* DEBUG_LEVEL */ +#if DEBUG_LEVEL >= 4 +# define DBG4(group, fmt, ...) dbg(group, 4, fmt, ##__VA_ARGS__) +#endif /* DEBUG_LEVEL */ + +#ifndef DBG0 +# define DBG0(...) {} +#endif +#ifndef DBG1 +# define DBG1(...) {} +#endif +#ifndef DBG2 +# define DBG2(...) {} +#endif +#ifndef DBG3 +# define DBG3(...) {} +#endif +#ifndef DBG4 +# define DBG4(...) {} +#endif + +/** dbg function hook, uses dbg_default() by default */ +extern void (*dbg) (debug_t group, level_t level, char *fmt, ...); + +/** default logging function */ +void dbg_default(debug_t group, level_t level, char *fmt, ...); + +/** set the level logged by dbg_default() */ +void dbg_default_set_level(level_t level); + +/** set the stream logged by dbg_default() to */ +void dbg_default_set_stream(FILE *stream); + +#endif /** DEBUG_H_ @}*/ diff --git a/src/libstrongswan/utils/enum.c b/src/libstrongswan/utils/enum.c new file mode 100644 index 000000000..9b3c4d566 --- /dev/null +++ b/src/libstrongswan/utils/enum.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program 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 General Public License + * for more details. + */ + +#include <stddef.h> +#include <stdio.h> + +#include <library.h> + +#include "enum.h" + +/** + * See header. + */ +char *enum_to_name(enum_name_t *e, int val) +{ + do + { + if (val >= e->first && val <= e->last) + { + return e->names[val - e->first]; + } + } + while ((e = e->next)); + return NULL; +} + +/** + * See header. + */ +int enum_from_name(enum_name_t *e, char *name) +{ + do + { + int i, count = e->last - e->first + 1; + + for (i = 0; i < count; i++) + { + if (strcaseeq(name, e->names[i])) + { + return e->first + i; + } + } + } + while ((e = e->next)); + return -1; +} + +/** + * Described in header. + */ +int enum_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, + const void *const *args) +{ + enum_name_t *ed = *((enum_name_t**)(args[0])); + int val = *((int*)(args[1])); + char *name, buf[32]; + + name = enum_to_name(ed, val); + if (name == NULL) + { + snprintf(buf, sizeof(buf), "(%d)", val); + name = buf; + } + if (spec->minus) + { + return print_in_hook(data, "%-*s", spec->width, name); + } + return print_in_hook(data, "%*s", spec->width, name); +} diff --git a/src/libstrongswan/utils/enum.h b/src/libstrongswan/utils/enum.h new file mode 100644 index 000000000..df8dbf8c1 --- /dev/null +++ b/src/libstrongswan/utils/enum.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2009 Tobias Brunner + * Copyright (C) 2006-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program 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 General Public License + * for more details. + */ + +/** + * @defgroup enum enum + * @{ @ingroup utils + */ + +#ifndef ENUM_H_ +#define ENUM_H_ + +#include "printf_hook.h" + +typedef struct enum_name_t enum_name_t; + +/** + * Struct to store names for enums. + * + * To print the string representation of enumeration values, the strings + * are stored in these structures. Every enum_name contains a range + * of strings, multiple ranges are linked together. + * Use the convenience macros to define these linked ranges. + * + * For a single range, use: + * @code + ENUM(name, first, last, string1, string2, ...) + @endcode + * For multiple linked ranges, use: + * @code + ENUM_BEGIN(name, first, last, string1, string2, ...) + ENUM_NEXT(name, first, last, last_from_previous, string3, ...) + ENUM_NEXT(name, first, last, last_from_previous, string4, ...) + ENUM_END(name, last_from_previous) + @endcode + * The ENUM and the ENUM_END define a enum_name_t pointer with the name supplied + * in "name". + * + * Resolving of enum names is done using a printf hook. A printf fromat + * character %N is replaced by the enum string. Printf needs two arguments to + * resolve a %N, the enum_name_t* (the defined name in ENUM_BEGIN) followed + * by the numerical enum value. + */ +struct enum_name_t { + /** value of the first enum string */ + int first; + /** value of the last enum string */ + int last; + /** next enum_name_t in list */ + enum_name_t *next; + /** array of strings containing names from first to last */ + char *names[]; +}; + +/** + * Begin a new enum_name list. + * + * @param name name of the enum_name list + * @param first enum value of the first enum string + * @param last enum value of the last enum string + * @param ... a list of strings + */ +#define ENUM_BEGIN(name, first, last, ...) static enum_name_t name##last = {first, last, NULL, { __VA_ARGS__ }} + +/** + * Continue a enum name list startetd with ENUM_BEGIN. + * + * @param name name of the enum_name list + * @param first enum value of the first enum string + * @param last enum value of the last enum string + * @param prev enum value of the "last" defined in ENUM_BEGIN/previous ENUM_NEXT + * @param ... a list of strings + */ +#define ENUM_NEXT(name, first, last, prev, ...) static enum_name_t name##last = {first, last, &name##prev, { __VA_ARGS__ }} + +/** + * Complete enum name list started with ENUM_BEGIN. + * + * @param name name of the enum_name list + * @param prev enum value of the "last" defined in ENUM_BEGIN/previous ENUM_NEXT + */ +#define ENUM_END(name, prev) enum_name_t *name = &name##prev; + +/** + * Define a enum name with only one range. + * + * This is a convenience macro to use when a enum_name list contains only + * one range, and is equal as defining ENUM_BEGIN followed by ENUM_END. + * + * @param name name of the enum_name list + * @param first enum value of the first enum string + * @param last enum value of the last enum string + * @param ... a list of strings + */ +#define ENUM(name, first, last, ...) ENUM_BEGIN(name, first, last, __VA_ARGS__); ENUM_END(name, last) + +/** + * Convert a enum value to its string representation. + * + * @param e enum names for this enum value + * @param val enum value to get string for + * @return string for enum, NULL if not found + */ +char *enum_to_name(enum_name_t *e, int val); + +/** + * Convert a enum string back to its enum value. + * + * @param e enum names for this enum value + * @param name name to get enum value for + * @return enum value, -1 if not found + */ +int enum_from_name(enum_name_t *e, char *name); + +/** + * printf hook function for enum_names_t. + * + * Arguments are: + * enum_names_t *names, int value + */ +int enum_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, + const void *const *args); + +#endif /** ENUM_H_ @}*/ diff --git a/src/libstrongswan/utils/enumerator.c b/src/libstrongswan/utils/enumerator.c deleted file mode 100644 index 53c94f9dd..000000000 --- a/src/libstrongswan/utils/enumerator.c +++ /dev/null @@ -1,560 +0,0 @@ -/* - * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program 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 General Public License - * for more details. - */ - -#include "enumerator.h" - -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <limits.h> -#include <stdio.h> -#include <dirent.h> -#include <errno.h> -#include <string.h> - -#include <debug.h> - -/** - * Implementation of enumerator_create_empty().enumerate - */ -static bool enumerate_empty(enumerator_t *enumerator, ...) -{ - return FALSE; -} - -/** - * See header - */ -enumerator_t* enumerator_create_empty() -{ - enumerator_t *this = malloc_thing(enumerator_t); - this->enumerate = enumerate_empty; - this->destroy = (void*)free; - return this; -} - -/** - * Enumerator implementation for directory enumerator - */ -typedef struct { - /** implements enumerator_t */ - enumerator_t public; - /** directory handle */ - DIR *dir; - /** absolute path of current file */ - char full[PATH_MAX]; - /** where directory part of full ends and relative file gets written */ - char *full_end; -} dir_enum_t; - -/** - * Implementation of enumerator_create_directory().destroy - */ -static void destroy_dir_enum(dir_enum_t *this) -{ - closedir(this->dir); - free(this); -} - -/** - * Implementation of enumerator_create_directory().enumerate - */ -static bool enumerate_dir_enum(dir_enum_t *this, char **relative, - char **absolute, struct stat *st) -{ - struct dirent *entry = readdir(this->dir); - size_t remaining; - int len; - - if (!entry) - { - return FALSE; - } - if (streq(entry->d_name, ".") || streq(entry->d_name, "..")) - { - return enumerate_dir_enum(this, relative, absolute, st); - } - if (relative) - { - *relative = entry->d_name; - } - if (absolute || st) - { - remaining = sizeof(this->full) - (this->full_end - this->full); - len = snprintf(this->full_end, remaining, "%s", entry->d_name); - if (len < 0 || len >= remaining) - { - DBG1(DBG_LIB, "buffer too small to enumerate file '%s'", - entry->d_name); - return FALSE; - } - if (absolute) - { - *absolute = this->full; - } - if (st) - { - if (stat(this->full, st)) - { - DBG1(DBG_LIB, "stat() on '%s' failed: %s", this->full, - strerror(errno)); - return FALSE; - } - } - } - return TRUE; -} - -/** - * See header - */ -enumerator_t* enumerator_create_directory(const char *path) -{ - int len; - dir_enum_t *this = malloc_thing(dir_enum_t); - this->public.enumerate = (void*)enumerate_dir_enum; - this->public.destroy = (void*)destroy_dir_enum; - - if (*path == '\0') - { - path = "./"; - } - len = snprintf(this->full, sizeof(this->full)-1, "%s", path); - if (len < 0 || len >= sizeof(this->full)-1) - { - DBG1(DBG_LIB, "path string '%s' too long", path); - free(this); - return NULL; - } - /* append a '/' if not already done */ - if (this->full[len-1] != '/') - { - this->full[len++] = '/'; - this->full[len] = '\0'; - } - this->full_end = &this->full[len]; - - this->dir = opendir(path); - if (this->dir == NULL) - { - DBG1(DBG_LIB, "opening directory '%s' failed: %s", path, strerror(errno)); - free(this); - return NULL; - } - return &this->public; -} - -/** - * Enumerator implementation for directory enumerator - */ -typedef struct { - /** implements enumerator_t */ - enumerator_t public; - /** string to parse */ - char *string; - /** current position */ - char *pos; - /** separater chars */ - const char *sep; - /** trim chars */ - const char *trim; -} token_enum_t; - -/** - * Implementation of enumerator_create_token().destroy - */ -static void destroy_token_enum(token_enum_t *this) -{ - free(this->string); - free(this); -} - -/** - * Implementation of enumerator_create_token().enumerate - */ -static bool enumerate_token_enum(token_enum_t *this, char **token) -{ - const char *sep, *trim; - char *pos = NULL, *tmp; - bool last = FALSE; - - /* trim leading characters/separators */ - while (*this->pos) - { - trim = this->trim; - while (*trim) - { - if (*trim == *this->pos) - { - this->pos++; - break; - } - trim++; - } - sep = this->sep; - while (*sep) - { - if (*sep == *this->pos) - { - this->pos++; - break; - } - sep++; - } - if (!*trim && !*sep) - { - break; - } - } - - switch (*this->pos) - { - case '"': - case '\'': - { - /* read quoted token */ - tmp = strchr(this->pos + 1, *this->pos); - if (tmp) - { - *token = this->pos + 1; - *tmp = '\0'; - this->pos = tmp + 1; - return TRUE; - } - /* unterminated string, FALL-THROUGH */ - } - default: - { - /* find nearest separator */ - sep = this->sep; - while (*sep) - { - tmp = strchr(this->pos, *sep); - if (tmp && (pos == NULL || tmp < pos)) - { - pos = tmp; - } - sep++; - } - *token = this->pos; - if (pos) - { - *pos = '\0'; - this->pos = pos + 1; - } - else - { - last = TRUE; - pos = this->pos = strchr(this->pos, '\0'); - } - break; - } - } - - /* trim trailing characters/separators */ - pos--; - while (pos >= *token) - { - trim = this->trim; - while (*trim) - { - if (*trim == *pos) - { - *(pos--) = '\0'; - break; - } - trim++; - } - sep = this->sep; - while (*sep) - { - if (*sep == *pos) - { - *(pos--) = '\0'; - break; - } - sep++; - } - if (!*trim && !*sep) - { - break; - } - } - - if (!last || pos >= *token) - { - return TRUE; - } - return FALSE; -} - -/** - * See header - */ -enumerator_t* enumerator_create_token(const char *string, const char *sep, - const char *trim) -{ - token_enum_t *enumerator = malloc_thing(token_enum_t); - - enumerator->public.enumerate = (void*)enumerate_token_enum; - enumerator->public.destroy = (void*)destroy_token_enum; - enumerator->string = strdup(string); - enumerator->pos = enumerator->string; - enumerator->sep = sep; - enumerator->trim = trim; - - return &enumerator->public; -} - -/** - * enumerator for nested enumerations - */ -typedef struct { - /* implements enumerator_t */ - enumerator_t public; - /* outer enumerator */ - enumerator_t *outer; - /* inner enumerator */ - enumerator_t *inner; - /* constructor for inner enumerator */ - enumerator_t *(*create_inner)(void *outer, void *data); - /* data to pass to constructor above */ - void *data; - /* destructor for data */ - void (*destroy_data)(void *data); -} nested_enumerator_t; - - -/** - * Implementation of enumerator_create_nested().enumerate() - */ -static bool enumerate_nested(nested_enumerator_t *this, void *v1, void *v2, - void *v3, void *v4, void *v5) -{ - while (TRUE) - { - while (this->inner == NULL) - { - void *outer; - - if (!this->outer->enumerate(this->outer, &outer)) - { - return FALSE; - } - this->inner = this->create_inner(outer, this->data); - } - if (this->inner->enumerate(this->inner, v1, v2, v3, v4, v5)) - { - return TRUE; - } - this->inner->destroy(this->inner); - this->inner = NULL; - } -} - -/** - * Implementation of enumerator_create_nested().destroy() - **/ -static void destroy_nested(nested_enumerator_t *this) -{ - if (this->destroy_data) - { - this->destroy_data(this->data); - } - DESTROY_IF(this->inner); - this->outer->destroy(this->outer); - free(this); -} - -/** - * See header - */ -enumerator_t *enumerator_create_nested(enumerator_t *outer, - enumerator_t *(inner_constructor)(void *outer, void *data), - void *data, void (*destroy_data)(void *data)) -{ - nested_enumerator_t *enumerator = malloc_thing(nested_enumerator_t); - - enumerator->public.enumerate = (void*)enumerate_nested; - enumerator->public.destroy = (void*)destroy_nested; - enumerator->outer = outer; - enumerator->inner = NULL; - enumerator->create_inner = (void*)inner_constructor; - enumerator->data = data; - enumerator->destroy_data = destroy_data; - - return &enumerator->public; -} - -/** - * enumerator for filtered enumerator - */ -typedef struct { - enumerator_t public; - enumerator_t *unfiltered; - void *data; - bool (*filter)(void *data, ...); - void (*destructor)(void *data); -} filter_enumerator_t; - -/** - * Implementation of enumerator_create_filter().destroy - */ -static void destroy_filter(filter_enumerator_t *this) -{ - if (this->destructor) - { - this->destructor(this->data); - } - this->unfiltered->destroy(this->unfiltered); - free(this); -} - -/** - * Implementation of enumerator_create_filter().enumerate - */ -static bool enumerate_filter(filter_enumerator_t *this, void *o1, void *o2, - void *o3, void *o4, void *o5) -{ - void *i1, *i2, *i3, *i4, *i5; - - while (this->unfiltered->enumerate(this->unfiltered, &i1, &i2, &i3, &i4, &i5)) - { - if (this->filter(this->data, &i1, o1, &i2, o2, &i3, o3, &i4, o4, &i5, o5)) - { - return TRUE; - } - } - return FALSE; -} - -/** - * see header - */ -enumerator_t *enumerator_create_filter(enumerator_t *unfiltered, - bool (*filter)(void *data, ...), - void *data, void (*destructor)(void *data)) -{ - filter_enumerator_t *this = malloc_thing(filter_enumerator_t); - - this->public.enumerate = (void*)enumerate_filter; - this->public.destroy = (void*)destroy_filter; - this->unfiltered = unfiltered; - this->filter = filter; - this->data = data; - this->destructor = destructor; - - return &this->public; -} - -/** - * enumerator for cleaner enumerator - */ -typedef struct { - enumerator_t public; - enumerator_t *wrapped; - void (*cleanup)(void *data); - void *data; -} cleaner_enumerator_t; - -/** - * Implementation of enumerator_create_cleanup().destroy - */ -static void destroy_cleaner(cleaner_enumerator_t *this) -{ - this->cleanup(this->data); - this->wrapped->destroy(this->wrapped); - free(this); -} - -/** - * Implementation of enumerator_create_cleaner().enumerate - */ -static bool enumerate_cleaner(cleaner_enumerator_t *this, void *v1, void *v2, - void *v3, void *v4, void *v5) -{ - return this->wrapped->enumerate(this->wrapped, v1, v2, v3, v4, v5); -} - -/** - * see header - */ -enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped, - void (*cleanup)(void *data), void *data) -{ - cleaner_enumerator_t *this = malloc_thing(cleaner_enumerator_t); - - this->public.enumerate = (void*)enumerate_cleaner; - this->public.destroy = (void*)destroy_cleaner; - this->wrapped = wrapped; - this->cleanup = cleanup; - this->data = data; - - return &this->public; -} - -/** - * enumerator for single enumerator - */ -typedef struct { - enumerator_t public; - void *item; - void (*cleanup)(void *item); - bool done; -} single_enumerator_t; - -/** - * Implementation of enumerator_create_single().destroy - */ -static void destroy_single(single_enumerator_t *this) -{ - if (this->cleanup) - { - this->cleanup(this->item); - } - free(this); -} - -/** - * Implementation of enumerator_create_single().enumerate - */ -static bool enumerate_single(single_enumerator_t *this, void **item) -{ - if (this->done) - { - return FALSE; - } - *item = this->item; - this->done = TRUE; - return TRUE; -} - -/** - * see header - */ -enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item)) -{ - single_enumerator_t *this = malloc_thing(single_enumerator_t); - - this->public.enumerate = (void*)enumerate_single; - this->public.destroy = (void*)destroy_single; - this->item = item; - this->cleanup = cleanup; - this->done = FALSE; - - return &this->public; -} - diff --git a/src/libstrongswan/utils/enumerator.h b/src/libstrongswan/utils/enumerator.h deleted file mode 100644 index 8c3d70173..000000000 --- a/src/libstrongswan/utils/enumerator.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program 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 General Public License - * for more details. - */ - -/** - * @defgroup enumerator enumerator - * @{ @ingroup utils - */ - -#ifndef ENUMERATOR_H_ -#define ENUMERATOR_H_ - -typedef struct enumerator_t enumerator_t; - -#include "../utils.h" - -/** - * Enumerator interface, allows enumeration over collections. - */ -struct enumerator_t { - - /** - * Enumerate collection. - * - * The enumerate function takes a variable argument list containing - * pointers where the enumerated values get written. - * - * @param ... variable list of enumerated items, implementation dependent - * @return TRUE if pointers returned - */ - bool (*enumerate)(enumerator_t *this, ...); - - /** - * Destroy a enumerator instance. - */ - void (*destroy)(enumerator_t *this); -}; - -/** - * Create an enumerator which enumerates over nothing - * - * @return an enumerator over no values - */ -enumerator_t* enumerator_create_empty(); - -/** - * Create an enumerator which enumerates over a single item - * - * @param item item to enumerate - * @param cleanup cleanup function called on destroy with the item - * @return an enumerator over a single value - */ -enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item)); - -/** - * Create an enumerator over files/subdirectories in a directory. - * - * This enumerator_t.enumerate() function returns a (to the directory) relative - * filename (as a char*), an absolute filename (as a char*) and a file status - * (to a struct stat), which all may be NULL. "." and ".." entries are - * skipped. Example: - * - * @code - char *rel, *abs; - struct stat st; - enumerator_t *e; - - e = enumerator_create_directory("/tmp"); - if (e) - { - while (e->enumerate(e, &rel, &abs, &st)) - { - if (S_ISDIR(st.st_mode) && *rel != '.') - { - printf("%s\n", abs); - } - } - e->destroy(e); - } - @endcode - * - * @param path path of the directory - * @return the directory enumerator, NULL on failure - */ -enumerator_t* enumerator_create_directory(const char *path); - -/** - * Create an enumerator over tokens of a string. - * - * Tokens are separated by one of the characters in sep and trimmed by the - * characters in trim. - * - * @param string string to parse - * @param sep separator characters - * @param trim characters to trim from tokens - * @return enumerator over char* tokens - */ -enumerator_t* enumerator_create_token(const char *string, const char *sep, - const char *trim); - -/** - * Creates an enumerator which enumerates over enumerated enumerators :-). - * - * The variable argument list of enumeration values is limit to 5. - * - * @param outer outer enumerator - * @param inner_constructor constructor to inner enumerator - * @param data data to pass to each inner_constructor call - * @param destroy_data destructor to pass to data - * @return the nested enumerator - */ -enumerator_t *enumerator_create_nested(enumerator_t *outer, - enumerator_t *(*inner_constructor)(void *outer, void *data), - void *data, void (*destroy_data)(void *data)); - -/** - * Creates an enumerator which filters output of another enumerator. - * - * The filter function receives the user supplied "data" followed by a - * unfiltered enumeration item, followed by an output pointer where to write - * the filtered data. Then the next input/output pair follows. - * It returns TRUE to deliver the - * values to the caller of enumerate(), FALSE to filter this enumeration. - * - * The variable argument list of enumeration values is limit to 5. - * - * @param unfiltered unfiltered enumerator to wrap, gets destroyed - * @param filter filter function - * @param data user data to supply to filter - * @param destructor destructor function to clean up data after use - * @return the filtered enumerator - */ -enumerator_t *enumerator_create_filter(enumerator_t *unfiltered, - bool (*filter)(void *data, ...), - void *data, void (*destructor)(void *data)); - -/** - * Create an enumerator wrapper which does a cleanup on destroy. - * - * @param wrapped wrapped enumerator - * @param cleanup cleanup function called on destroy - * @param data user data to supply to cleanup - * @return the enumerator with cleanup - */ -enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped, - void (*cleanup)(void *data), void *data); - -#endif /** ENUMERATOR_H_ @}*/ diff --git a/src/libstrongswan/utils/hashtable.c b/src/libstrongswan/utils/hashtable.c deleted file mode 100644 index d181d8ec8..000000000 --- a/src/libstrongswan/utils/hashtable.c +++ /dev/null @@ -1,444 +0,0 @@ -/* - * Copyright (C) 2008-2012 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program 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 General Public License - * for more details. - */ - - -#include "hashtable.h" - -/** The maximum capacity of the hash table (MUST be a power of 2) */ -#define MAX_CAPACITY (1 << 30) - -typedef struct pair_t pair_t; - -/** - * This pair holds a pointer to the key and value it represents. - */ -struct pair_t { - /** - * Key of a hash table item. - */ - void *key; - - /** - * Value of a hash table item. - */ - void *value; - - /** - * Cached hash (used in case of a resize). - */ - u_int hash; - - /** - * Next pair in an overflow list. - */ - pair_t *next; -}; - -/** - * Creates an empty pair object. - */ -static inline pair_t *pair_create(void *key, void *value, u_int hash) -{ - pair_t *this; - - INIT(this, - .key = key, - .value = value, - .hash = hash, - ); - - return this; -} - -typedef struct private_hashtable_t private_hashtable_t; - -/** - * Private data of a hashtable_t object. - * - */ -struct private_hashtable_t { - /** - * Public part of hash table. - */ - hashtable_t public; - - /** - * The number of items in the hash table. - */ - u_int count; - - /** - * The current capacity of the hash table (always a power of 2). - */ - u_int capacity; - - /** - * The current mask to calculate the row index (capacity - 1). - */ - u_int mask; - - /** - * The load factor. - */ - float load_factor; - - /** - * The actual table. - */ - pair_t **table; - - /** - * The hashing function. - */ - hashtable_hash_t hash; - - /** - * The equality function. - */ - hashtable_equals_t equals; -}; - -typedef struct private_enumerator_t private_enumerator_t; - -/** - * hash table enumerator implementation - */ -struct private_enumerator_t { - - /** - * implements enumerator interface - */ - enumerator_t enumerator; - - /** - * associated hash table - */ - private_hashtable_t *table; - - /** - * current row index - */ - u_int row; - - /** - * number of remaining items in hashtable - */ - u_int count; - - /** - * current pair - */ - pair_t *current; - - /** - * previous pair (used by remove_at) - */ - pair_t *prev; - -}; - -/** - * This function returns the next-highest power of two for the given number. - * The algorithm works by setting all bits on the right-hand side of the most - * significant 1 to 1 and then increments the whole number so it rolls over - * to the nearest power of two. Note: returns 0 for n == 0 - */ -static u_int get_nearest_powerof2(u_int n) -{ - u_int i; - - --n; - for (i = 1; i < sizeof(u_int) * 8; i <<= 1) - { - n |= n >> i; - } - return ++n; -} - -/** - * Init hash table parameters - */ -static void init_hashtable(private_hashtable_t *this, u_int capacity) -{ - capacity = max(1, min(capacity, MAX_CAPACITY)); - this->capacity = get_nearest_powerof2(capacity); - this->mask = this->capacity - 1; - this->load_factor = 0.75; - - this->table = calloc(this->capacity, sizeof(pair_t*)); -} - -/** - * Double the size of the hash table and rehash all the elements. - */ -static void rehash(private_hashtable_t *this) -{ - pair_t **old_table; - u_int row, old_capacity; - - if (this->capacity >= MAX_CAPACITY) - { - return; - } - - old_capacity = this->capacity; - old_table = this->table; - - init_hashtable(this, old_capacity << 1); - - for (row = 0; row < old_capacity; row++) - { - pair_t *pair, *next; - u_int new_row; - - pair = old_table[row]; - while (pair) - { /* insert pair at the front of new bucket*/ - next = pair->next; - new_row = pair->hash & this->mask; - pair->next = this->table[new_row]; - this->table[new_row] = pair; - pair = next; - } - } - free(old_table); -} - -METHOD(hashtable_t, put, void*, - private_hashtable_t *this, void *key, void *value) -{ - void *old_value = NULL; - pair_t *pair; - u_int hash, row; - - hash = this->hash(key); - row = hash & this->mask; - pair = this->table[row]; - while (pair) - { /* search existing bucket for key */ - if (this->equals(key, pair->key)) - { - old_value = pair->value; - pair->value = value; - pair->key = key; - break; - } - pair = pair->next; - } - if (!pair) - { /* insert at the front of bucket */ - pair = pair_create(key, value, hash); - pair->next = this->table[row]; - this->table[row] = pair; - this->count++; - } - if (this->count >= this->capacity * this->load_factor) - { - rehash(this); - } - return old_value; -} - -static void *get_internal(private_hashtable_t *this, void *key, - hashtable_equals_t equals) -{ - void *value = NULL; - pair_t *pair; - - if (!this->count) - { /* no need to calculate the hash */ - return NULL; - } - - pair = this->table[this->hash(key) & this->mask]; - while (pair) - { - if (equals(key, pair->key)) - { - value = pair->value; - break; - } - pair = pair->next; - } - return value; -} - -METHOD(hashtable_t, get, void*, - private_hashtable_t *this, void *key) -{ - return get_internal(this, key, this->equals); -} - -METHOD(hashtable_t, get_match, void*, - private_hashtable_t *this, void *key, hashtable_equals_t match) -{ - return get_internal(this, key, match); -} - -METHOD(hashtable_t, remove_, void*, - private_hashtable_t *this, void *key) -{ - void *value = NULL; - pair_t *pair, *prev = NULL; - u_int row; - - row = this->hash(key) & this->mask; - pair = this->table[row]; - while (pair) - { - if (this->equals(key, pair->key)) - { - if (prev) - { - prev->next = pair->next; - } - else - { - this->table[row] = pair->next; - } - value = pair->value; - this->count--; - free(pair); - break; - } - prev = pair; - pair = pair->next; - } - return value; -} - -METHOD(hashtable_t, remove_at, void, - private_hashtable_t *this, private_enumerator_t *enumerator) -{ - if (enumerator->table == this && enumerator->current) - { - pair_t *current = enumerator->current; - if (enumerator->prev) - { - enumerator->prev->next = current->next; - } - else - { - this->table[enumerator->row] = current->next; - } - enumerator->current = enumerator->prev; - free(current); - this->count--; - } -} - -METHOD(hashtable_t, get_count, u_int, - private_hashtable_t *this) -{ - return this->count; -} - -METHOD(enumerator_t, enumerate, bool, - private_enumerator_t *this, void **key, void **value) -{ - while (this->count && this->row < this->table->capacity) - { - this->prev = this->current; - if (this->current) - { - this->current = this->current->next; - } - else - { - this->current = this->table->table[this->row]; - } - if (this->current) - { - if (key) - { - *key = this->current->key; - } - if (value) - { - *value = this->current->value; - } - this->count--; - return TRUE; - } - this->row++; - } - return FALSE; -} - -METHOD(hashtable_t, create_enumerator, enumerator_t*, - private_hashtable_t *this) -{ - private_enumerator_t *enumerator; - - INIT(enumerator, - .enumerator = { - .enumerate = (void*)_enumerate, - .destroy = (void*)free, - }, - .table = this, - .count = this->count, - ); - - return &enumerator->enumerator; -} - -METHOD(hashtable_t, destroy, void, - private_hashtable_t *this) -{ - pair_t *pair, *next; - u_int row; - - for (row = 0; row < this->capacity; row++) - { - pair = this->table[row]; - while (pair) - { - next = pair->next; - free(pair); - pair = next; - } - } - free(this->table); - free(this); -} - -/* - * Described in header. - */ -hashtable_t *hashtable_create(hashtable_hash_t hash, hashtable_equals_t equals, - u_int capacity) -{ - private_hashtable_t *this; - - INIT(this, - .public = { - .put = _put, - .get = _get, - .get_match = _get_match, - .remove = _remove_, - .remove_at = (void*)_remove_at, - .get_count = _get_count, - .create_enumerator = _create_enumerator, - .destroy = _destroy, - }, - .hash = hash, - .equals = equals, - ); - - init_hashtable(this, capacity); - - return &this->public; -} - diff --git a/src/libstrongswan/utils/hashtable.h b/src/libstrongswan/utils/hashtable.h deleted file mode 100644 index 0a21ca373..000000000 --- a/src/libstrongswan/utils/hashtable.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2008-2012 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program 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 General Public License - * for more details. - */ - -/** - * @defgroup hashtable hashtable - * @{ @ingroup utils - */ - -#ifndef HASHTABLE_H_ -#define HASHTABLE_H_ - -#include <utils/enumerator.h> - -typedef struct hashtable_t hashtable_t; - -/** - * Prototype for a function that computes the hash code from the given key. - * - * @param key key to hash - * @return hash code - */ -typedef u_int (*hashtable_hash_t)(void *key); - -/** - * Prototype for a function that compares the two keys for equality. - * - * @param key first key (the one we are looking for) - * @param other_key second key - * @return TRUE if the keys are equal - */ -typedef bool (*hashtable_equals_t)(void *key, void *other_key); - -/** - * Class implementing a hash table. - * - * General purpose hash table. This hash table is not synchronized. - */ -struct hashtable_t { - - /** - * Create an enumerator over the hash table key/value pairs. - * - * @return enumerator over (void *key, void *value) - */ - enumerator_t *(*create_enumerator) (hashtable_t *this); - - /** - * Adds the given value with the given key to the hash table, if there - * exists no entry with that key. NULL is returned in this case. - * Otherwise the existing value is replaced and the function returns the - * old value. - * - * @param key the key to store - * @param value the value to store - * @return NULL if no item was replaced, the old value otherwise - */ - void *(*put) (hashtable_t *this, void *key, void *value); - - /** - * Returns the value with the given key, if the hash table contains such an - * entry, otherwise NULL is returned. - * - * @param key the key of the requested value - * @return the value, NULL if not found - */ - void *(*get) (hashtable_t *this, void *key); - - /** - * Returns the value with a matching key, if the hash table contains such an - * entry, otherwise NULL is returned. - * - * Compared to get() the given match function is used to compare the keys - * for equality. The hash function does have to be deviced properly in - * order to make this work if the match function compares keys differently - * than the equals function provided to the constructor. This basically - * allows to enumerate all entries with the same hash value. - * - * @param key the key to match against - * @param match match function to be used when comparing keys - * @return the value, NULL if not found - */ - void *(*get_match) (hashtable_t *this, void *key, hashtable_equals_t match); - - /** - * Removes the value with the given key from the hash table and returns the - * removed value (or NULL if no such value existed). - * - * @param key the key of the value to remove - * @return the removed value, NULL if not found - */ - void *(*remove) (hashtable_t *this, void *key); - - /** - * Removes the key and value pair from the hash table at which the given - * enumerator currently points. - * - * @param enumerator enumerator, from create_enumerator - */ - void (*remove_at) (hashtable_t *this, enumerator_t *enumerator); - - /** - * Gets the number of items in the hash table. - * - * @return number of items - */ - u_int (*get_count) (hashtable_t *this); - - /** - * Destroys a hash table object. - */ - void (*destroy) (hashtable_t *this); - -}; - -/** - * Creates an empty hash table object. - * - * @param hash hash function - * @param equals equals function - * @param capacity initial capacity - * @return hashtable_t object. - */ -hashtable_t *hashtable_create(hashtable_hash_t hash, hashtable_equals_t equals, - u_int capacity); - -#endif /** HASHTABLE_H_ @}*/ diff --git a/src/libstrongswan/utils/host.c b/src/libstrongswan/utils/host.c deleted file mode 100644 index e17b6ad02..000000000 --- a/src/libstrongswan/utils/host.c +++ /dev/null @@ -1,616 +0,0 @@ -/* - * Copyright (C) 2006-2009 Tobias Brunner - * Copyright (C) 2006 Daniel Roethlisberger - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program 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 General Public License - * for more details. - */ - -#define _GNU_SOURCE -#include <sys/socket.h> -#include <netdb.h> -#include <string.h> - -#include "host.h" - -#include <debug.h> - -#define IPV4_LEN 4 -#define IPV6_LEN 16 - -typedef struct private_host_t private_host_t; - -/** - * Private Data of a host object. - */ -struct private_host_t { - /** - * Public data - */ - host_t public; - - /** - * low-lewel structure, which stores the address - */ - union { - /** generic type */ - struct sockaddr address; - /** maximum sockaddr size */ - struct sockaddr_storage address_max; - /** IPv4 address */ - struct sockaddr_in address4; - /** IPv6 address */ - struct sockaddr_in6 address6; - }; - /** - * length of address structure - */ - socklen_t socklen; -}; - - -METHOD(host_t, get_sockaddr, sockaddr_t*, - private_host_t *this) -{ - return &(this->address); -} - -METHOD(host_t, get_sockaddr_len, socklen_t*, - private_host_t *this) -{ - return &(this->socklen); -} - -METHOD(host_t, is_anyaddr, bool, - private_host_t *this) -{ - static const u_int8_t zeroes[IPV6_LEN]; - - switch (this->address.sa_family) - { - case AF_INET: - { - return memeq(zeroes, &(this->address4.sin_addr.s_addr), IPV4_LEN); - } - case AF_INET6: - { - return memeq(zeroes, &(this->address6.sin6_addr.s6_addr), IPV6_LEN); - } - default: - { - return FALSE; - } - } -} - -/** - * Described in header. - */ -int host_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, - const void *const *args) -{ - private_host_t *this = *((private_host_t**)(args[0])); - char buffer[INET6_ADDRSTRLEN + 16]; - - if (this == NULL) - { - snprintf(buffer, sizeof(buffer), "(null)"); - } - else if (is_anyaddr(this) && !spec->plus) - { - snprintf(buffer, sizeof(buffer), "%%any%s", - this->address.sa_family == AF_INET6 ? "6" : ""); - } - else - { - void *address; - u_int16_t port; - int len; - - address = &this->address6.sin6_addr; - port = this->address6.sin6_port; - - switch (this->address.sa_family) - { - case AF_INET: - address = &this->address4.sin_addr; - port = this->address4.sin_port; - /* fall */ - case AF_INET6: - - if (inet_ntop(this->address.sa_family, address, - buffer, sizeof(buffer)) == NULL) - { - snprintf(buffer, sizeof(buffer), - "(address conversion failed)"); - } - else if (spec->hash) - { - len = strlen(buffer); - snprintf(buffer + len, sizeof(buffer) - len, - "[%d]", ntohs(port)); - } - break; - default: - snprintf(buffer, sizeof(buffer), "(family not supported)"); - break; - } - } - if (spec->minus) - { - return print_in_hook(data, "%-*s", spec->width, buffer); - } - return print_in_hook(data, "%*s", spec->width, buffer); -} - -METHOD(host_t, get_address, chunk_t, - private_host_t *this) -{ - chunk_t address = chunk_empty; - - switch (this->address.sa_family) - { - case AF_INET: - { - address.ptr = (char*)&(this->address4.sin_addr.s_addr); - address.len = IPV4_LEN; - return address; - } - case AF_INET6: - { - address.ptr = (char*)&(this->address6.sin6_addr.s6_addr); - address.len = IPV6_LEN; - return address; - } - default: - { - /* return empty chunk */ - return address; - } - } -} - -METHOD(host_t, get_family, int, - private_host_t *this) -{ - return this->address.sa_family; -} - -METHOD(host_t, get_port, u_int16_t, - private_host_t *this) -{ - switch (this->address.sa_family) - { - case AF_INET: - { - return ntohs(this->address4.sin_port); - } - case AF_INET6: - { - return ntohs(this->address6.sin6_port); - } - default: - { - return 0; - } - } -} - -METHOD(host_t, set_port, void, - private_host_t *this, u_int16_t port) -{ - switch (this->address.sa_family) - { - case AF_INET: - { - this->address4.sin_port = htons(port); - break; - } - case AF_INET6: - { - this->address6.sin6_port = htons(port); - break; - } - default: - { - break; - } - } -} - -METHOD(host_t, clone_, host_t*, - private_host_t *this) -{ - private_host_t *new; - - new = malloc_thing(private_host_t); - memcpy(new, this, sizeof(private_host_t)); - - return &new->public; -} - -/** - * Implements host_t.ip_equals - */ -static bool ip_equals(private_host_t *this, private_host_t *other) -{ - if (this->address.sa_family != other->address.sa_family) - { - /* 0.0.0.0 and 0::0 are equal */ - return (is_anyaddr(this) && is_anyaddr(other)); - } - - switch (this->address.sa_family) - { - case AF_INET: - { - return memeq(&this->address4.sin_addr, &other->address4.sin_addr, - sizeof(this->address4.sin_addr)); - } - case AF_INET6: - { - return memeq(&this->address6.sin6_addr, &other->address6.sin6_addr, - sizeof(this->address6.sin6_addr)); - } - default: - break; - } - return FALSE; -} - -/** - * Implements host_t.get_differences - */ -static host_diff_t get_differences(host_t *this, host_t *other) -{ - host_diff_t ret = HOST_DIFF_NONE; - - if (!this->ip_equals(this, other)) - { - ret |= HOST_DIFF_ADDR; - } - - if (this->get_port(this) != other->get_port(other)) - { - ret |= HOST_DIFF_PORT; - } - - return ret; -} - -/** - * Implements host_t.equals - */ -static bool equals(private_host_t *this, private_host_t *other) -{ - if (!ip_equals(this, other)) - { - return FALSE; - } - - switch (this->address.sa_family) - { - case AF_INET: - { - return (this->address4.sin_port == other->address4.sin_port); - } - case AF_INET6: - { - return (this->address6.sin6_port == other->address6.sin6_port); - } - default: - break; - } - return FALSE; -} - -METHOD(host_t, destroy, void, - private_host_t *this) -{ - free(this); -} - -/** - * Creates an empty host_t object - */ -static private_host_t *host_create_empty(void) -{ - private_host_t *this; - - INIT(this, - .public = { - .get_sockaddr = _get_sockaddr, - .get_sockaddr_len = _get_sockaddr_len, - .clone = _clone_, - .get_family = _get_family, - .get_address = _get_address, - .get_port = _get_port, - .set_port = _set_port, - .get_differences = get_differences, - .ip_equals = (bool (*)(host_t *,host_t *))ip_equals, - .equals = (bool (*)(host_t *,host_t *)) equals, - .is_anyaddr = _is_anyaddr, - .destroy = _destroy, - }, - ); - - return this; -} - -/* - * Create a %any host with port - */ -static host_t *host_create_any_port(int family, u_int16_t port) -{ - host_t *this; - - this = host_create_any(family); - this->set_port(this, port); - return this; -} - -/* - * Described in header. - */ -host_t *host_create_from_string(char *string, u_int16_t port) -{ - private_host_t *this; - - if (streq(string, "%any")) - { - return host_create_any_port(AF_INET, port); - } - if (streq(string, "%any6")) - { - return host_create_any_port(AF_INET6, port); - } - - this = host_create_empty(); - if (strchr(string, '.')) - { - this->address.sa_family = AF_INET; - } - else - { - this->address.sa_family = AF_INET6; - } - switch (this->address.sa_family) - { - case AF_INET: - { - if (inet_pton(AF_INET, string, &this->address4.sin_addr) <=0) - { - break; - } - this->address4.sin_port = htons(port); - this->socklen = sizeof(struct sockaddr_in); - return &this->public; - } - case AF_INET6: - { - if (inet_pton(AF_INET6, string, &this->address6.sin6_addr) <=0) - { - break; - } - this->address6.sin6_port = htons(port); - this->socklen = sizeof(struct sockaddr_in6); - return &this->public; - } - default: - { - break; - } - } - free(this); - return NULL; -} - -/* - * Described in header. - */ -host_t *host_create_from_sockaddr(sockaddr_t *sockaddr) -{ - private_host_t *this = host_create_empty(); - - switch (sockaddr->sa_family) - { - case AF_INET: - { - memcpy(&this->address4, (struct sockaddr_in*)sockaddr, - sizeof(struct sockaddr_in)); - this->socklen = sizeof(struct sockaddr_in); - return &this->public; - } - case AF_INET6: - { - memcpy(&this->address6, (struct sockaddr_in6*)sockaddr, - sizeof(struct sockaddr_in6)); - this->socklen = sizeof(struct sockaddr_in6); - return &this->public; - } - default: - break; - } - free(this); - return NULL; -} - -/* - * Described in header. - */ -host_t *host_create_from_dns(char *string, int af, u_int16_t port) -{ - private_host_t *this; - struct addrinfo hints, *result; - int error; - - if (streq(string, "%any")) - { - return host_create_any_port(af ? af : AF_INET, port); - } - if (streq(string, "%any6")) - { - return host_create_any_port(af ? af : AF_INET6, port); - } - if (af == AF_INET && strchr(string, ':')) - { /* do not try to convert v6 addresses for v4 family */ - return NULL; - } - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = af; - error = getaddrinfo(string, NULL, &hints, &result); - if (error != 0) - { - DBG1(DBG_LIB, "resolving '%s' failed: %s", string, gai_strerror(error)); - return NULL; - } - /* result is a linked list, but we use only the first address */ - this = (private_host_t*)host_create_from_sockaddr(result->ai_addr); - freeaddrinfo(result); - if (this) - { - switch (this->address.sa_family) - { - case AF_INET: - this->address4.sin_port = htons(port); - break; - case AF_INET6: - this->address6.sin6_port = htons(port); - break; - } - return &this->public; - } - return NULL; -} - -/* - * Described in header. - */ -host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port) -{ - private_host_t *this; - - switch (family) - { - case AF_INET: - if (address.len < IPV4_LEN) - { - return NULL; - } - address.len = IPV4_LEN; - break; - case AF_INET6: - if (address.len < IPV6_LEN) - { - return NULL; - } - address.len = IPV6_LEN; - break; - case AF_UNSPEC: - switch (address.len) - { - case IPV4_LEN: - family = AF_INET; - break; - case IPV6_LEN: - family = AF_INET6; - break; - default: - return NULL; - } - break; - default: - return NULL; - } - this = host_create_empty(); - this->address.sa_family = family; - switch (family) - { - case AF_INET: - memcpy(&this->address4.sin_addr.s_addr, address.ptr, address.len); - this->address4.sin_port = htons(port); - this->socklen = sizeof(struct sockaddr_in); - break; - case AF_INET6: - memcpy(&this->address6.sin6_addr.s6_addr, address.ptr, address.len); - this->address6.sin6_port = htons(port); - this->socklen = sizeof(struct sockaddr_in6); - break; - } - return &this->public; -} - -/* - * Described in header. - */ -host_t *host_create_from_subnet(char *string, int *bits) -{ - char *pos, buf[64]; - host_t *net; - - pos = strchr(string, '/'); - if (pos) - { - if (pos - string >= sizeof(buf)) - { - return NULL; - } - strncpy(buf, string, pos - string); - buf[pos - string] = '\0'; - *bits = atoi(pos + 1); - return host_create_from_string(buf, 0); - } - net = host_create_from_string(string, 0); - if (net) - { - if (net->get_family(net) == AF_INET) - { - *bits = 32; - } - else - { - *bits = 128; - } - } - return net; -} - -/* - * Described in header. - */ -host_t *host_create_any(int family) -{ - private_host_t *this = host_create_empty(); - - memset(&this->address_max, 0, sizeof(struct sockaddr_storage)); - this->address.sa_family = family; - - switch (family) - { - case AF_INET: - { - this->socklen = sizeof(struct sockaddr_in); - return &(this->public); - } - case AF_INET6: - { - this->socklen = sizeof(struct sockaddr_in6); - return &this->public; - } - default: - break; - } - free(this); - return NULL; -} diff --git a/src/libstrongswan/utils/host.h b/src/libstrongswan/utils/host.h deleted file mode 100644 index a8b010544..000000000 --- a/src/libstrongswan/utils/host.h +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (C) 2006-2009 Tobias Brunner - * Copyright (C) 2006 Daniel Roethlisberger - * Copyright (C) 2005-2008 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program 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 General Public License - * for more details. - */ - -/** - * @defgroup host host - * @{ @ingroup utils - */ - -#ifndef HOST_H_ -#define HOST_H_ - -typedef enum host_diff_t host_diff_t; -typedef struct host_t host_t; - -#include <stdlib.h> -#include <stdio.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> - -#include <chunk.h> - -/** - * Differences between two hosts. They differ in - * address, port, or both. - */ -enum host_diff_t { - HOST_DIFF_NONE = 0, - HOST_DIFF_ADDR = 1, - HOST_DIFF_PORT = 2, -}; - -/** - * Representates a Host - * - * Host object, identifies a address:port pair and defines some - * useful functions on it. - */ -struct host_t { - - /** - * Build a clone of this host object. - * - * @return cloned host - */ - host_t *(*clone) (host_t *this); - - /** - * Get a pointer to the internal sockaddr struct. - * - * This is used for sending and receiving via sockets. - * - * @return pointer to the internal sockaddr structure - */ - sockaddr_t *(*get_sockaddr) (host_t *this); - - /** - * Get the length of the sockaddr struct. - * - * Depending on the family, the length of the sockaddr struct - * is different. Use this function to get the length of the sockaddr - * struct returned by get_sock_addr. - * - * This is used for sending and receiving via sockets. - * - * @return length of the sockaddr struct - */ - socklen_t *(*get_sockaddr_len) (host_t *this); - - /** - * Gets the family of the address - * - * @return family - */ - int (*get_family) (host_t *this); - - /** - * Checks if the ip address of host is set to default route. - * - * @return TRUE if host is 0.0.0.0 or 0::0, FALSE otherwise - */ - bool (*is_anyaddr) (host_t *this); - - /** - * Get the address of this host as chunk_t - * - * Returned chunk points to internal data. - * - * @return address string, - */ - chunk_t (*get_address) (host_t *this); - - /** - * Get the port of this host - * - * @return port number - */ - u_int16_t (*get_port) (host_t *this); - - /** - * Set the port of this host - * - * @param port port numer - */ - void (*set_port) (host_t *this, u_int16_t port); - - /** - * Compare the ips of two hosts hosts. - * - * @param other the other to compare - * @return TRUE if addresses are equal. - */ - bool (*ip_equals) (host_t *this, host_t *other); - - /** - * Compare two hosts, with port. - * - * @param other the other to compare - * @return TRUE if addresses and ports are equal. - */ - bool (*equals) (host_t *this, host_t *other); - - /** - * Compare two hosts and return the differences. - * - * @param other the other to compare - * @return differences in a combination of host_diff_t's - */ - host_diff_t (*get_differences) (host_t *this, host_t *other); - - /** - * Destroy this host object. - */ - void (*destroy) (host_t *this); -}; - -/** - * Constructor to create a host_t object from an address string. - * - * @param string string of an address, such as "152.96.193.130" - * @param port port number - * @return host_t, NULL if string not an address. - */ -host_t *host_create_from_string(char *string, u_int16_t port); - -/** - * Constructor to create a host_t from a DNS name. - * - * @param string hostname to resolve - * @param family family to prefer, 0 for first match - * @param port port number - * @return host_t, NULL lookup failed - */ -host_t *host_create_from_dns(char *string, int family, u_int16_t port); - -/** - * Constructor to create a host_t object from an address chunk. - * - * If family is AF_UNSPEC, it is guessed using address.len. - * - * @param family Address family, such as AF_INET or AF_INET6 - * @param address address as chunk_t in network order - * @param port port number - * @return host_t, NULL if family not supported/chunk invalid - */ -host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port); - -/** - * Constructor to create a host_t object from a sockaddr struct - * - * @param sockaddr sockaddr struct which contains family, address and port - * @return host_t, NULL if family not supported - */ -host_t *host_create_from_sockaddr(sockaddr_t *sockaddr); - -/** - * Create a host from a CIDR subnet definition (1.2.3.0/24), return bits. - * - * @param string string to parse - * @param bits gets the number of network bits in CIDR notation - * @return network start address, NULL on error - */ -host_t *host_create_from_subnet(char *string, int *bits); - -/** - * Create a host without an address, a "any" host. - * - * @param family family of the any host - * @return host_t, NULL if family not supported - */ -host_t *host_create_any(int family); - -/** - * printf hook function for host_t. - * - * Arguments are: - * host_t *host - * Use #-modifier to include port number - * Use +-modifier to force numeric representation (instead of e.g. %any) - */ -int host_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, - const void *const *args); - -#endif /** HOST_H_ @}*/ diff --git a/src/libstrongswan/utils/identification.h b/src/libstrongswan/utils/identification.h index 024fcea4b..cdf229127 100644 --- a/src/libstrongswan/utils/identification.h +++ b/src/libstrongswan/utils/identification.h @@ -29,8 +29,8 @@ typedef struct identification_t identification_t; typedef enum id_match_t id_match_t; typedef enum id_part_t id_part_t; -#include <chunk.h> -#include <utils/enumerator.h> +#include <utils/chunk.h> +#include <collections/enumerator.h> /** * Matches returned from identification_t.match diff --git a/src/libstrongswan/utils/integrity_checker.c b/src/libstrongswan/utils/integrity_checker.c new file mode 100644 index 000000000..e962aba70 --- /dev/null +++ b/src/libstrongswan/utils/integrity_checker.c @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program 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 General Public License + * for more details. + */ + +#define _GNU_SOURCE + +#include "integrity_checker.h" + +#include <dlfcn.h> +#include <link.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "debug.h" +#include "library.h" + +typedef struct private_integrity_checker_t private_integrity_checker_t; + +/** + * Private data of an integrity_checker_t object. + */ +struct private_integrity_checker_t { + + /** + * Public integrity_checker_t interface. + */ + integrity_checker_t public; + + /** + * dlopen handle to checksum library + */ + void *handle; + + /** + * checksum array + */ + integrity_checksum_t *checksums; + + /** + * number of checksums in array + */ + int checksum_count; +}; + +METHOD(integrity_checker_t, build_file, u_int32_t, + private_integrity_checker_t *this, char *file, size_t *len) +{ + u_int32_t checksum; + chunk_t contents; + struct stat sb; + void *addr; + int fd; + + fd = open(file, O_RDONLY); + if (fd == -1) + { + DBG1(DBG_LIB, " opening '%s' failed: %s", file, strerror(errno)); + return 0; + } + + if (fstat(fd, &sb) == -1) + { + DBG1(DBG_LIB, " getting file size of '%s' failed: %s", file, + strerror(errno)); + close(fd); + return 0; + } + + addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (addr == MAP_FAILED) + { + DBG1(DBG_LIB, " mapping '%s' failed: %s", file, strerror(errno)); + close(fd); + return 0; + } + + *len = sb.st_size; + contents = chunk_create(addr, sb.st_size); + checksum = chunk_hash(contents); + + munmap(addr, sb.st_size); + close(fd); + + return checksum; +} + +/** + * dl_iterate_phdr callback function + */ +static int callback(struct dl_phdr_info *dlpi, size_t size, Dl_info *dli) +{ + /* We are looking for the dlpi_addr matching the address of our dladdr(). + * dl_iterate_phdr() returns such an address for other (unknown) objects + * in very rare cases (e.g. in a chrooted gentoo, but only if + * the checksum_builder is invoked by 'make'). As a workaround, we filter + * objects by dlpi_name; valid objects have a library name. + */ + if (dli->dli_fbase == (void*)dlpi->dlpi_addr && + dlpi->dlpi_name && *dlpi->dlpi_name) + { + int i; + + for (i = 0; i < dlpi->dlpi_phnum; i++) + { + const ElfW(Phdr) *sgmt = &dlpi->dlpi_phdr[i]; + + /* we are interested in the executable LOAD segment */ + if (sgmt->p_type == PT_LOAD && (sgmt->p_flags & PF_X)) + { + /* safe begin of segment in dli_fbase */ + dli->dli_fbase = (void*)sgmt->p_vaddr + dlpi->dlpi_addr; + /* safe end of segment in dli_saddr */ + dli->dli_saddr = dli->dli_fbase + sgmt->p_memsz; + return 1; + } + } + } + return 0; +} + +METHOD(integrity_checker_t, build_segment, u_int32_t, + private_integrity_checker_t *this, void *sym, size_t *len) +{ + chunk_t segment; + Dl_info dli; + + if (dladdr(sym, &dli) == 0) + { + DBG1(DBG_LIB, " unable to locate symbol: %s", dlerror()); + return 0; + } + /* we reuse the Dl_info struct as in/out parameter */ + if (!dl_iterate_phdr((void*)callback, &dli)) + { + DBG1(DBG_LIB, " executable section not found"); + return 0; + } + + segment = chunk_create(dli.dli_fbase, dli.dli_saddr - dli.dli_fbase); + *len = segment.len; + return chunk_hash(segment); +} + +/** + * Find a checksum by its name + */ +static integrity_checksum_t *find_checksum(private_integrity_checker_t *this, + char *name) +{ + int i; + + for (i = 0; i < this->checksum_count; i++) + { + if (streq(this->checksums[i].name, name)) + { + return &this->checksums[i]; + } + } + return NULL; +} + +METHOD(integrity_checker_t, check_file, bool, + private_integrity_checker_t *this, char *name, char *file) +{ + integrity_checksum_t *cs; + u_int32_t sum; + size_t len = 0; + + cs = find_checksum(this, name); + if (!cs) + { + DBG1(DBG_LIB, " '%s' file checksum not found", name); + return FALSE; + } + sum = build_file(this, file, &len); + if (!sum) + { + return FALSE; + } + if (cs->file_len != len) + { + DBG1(DBG_LIB, " invalid '%s' file size: %u bytes, expected %u bytes", + name, len, cs->file_len); + return FALSE; + } + if (cs->file != sum) + { + DBG1(DBG_LIB, " invalid '%s' file checksum: %08x, expected %08x", + name, sum, cs->file); + return FALSE; + } + DBG2(DBG_LIB, " valid '%s' file checksum: %08x", name, sum); + return TRUE; +} + +METHOD(integrity_checker_t, check_segment, bool, + private_integrity_checker_t *this, char *name, void *sym) +{ + integrity_checksum_t *cs; + u_int32_t sum; + size_t len = 0; + + cs = find_checksum(this, name); + if (!cs) + { + DBG1(DBG_LIB, " '%s' segment checksum not found", name); + return FALSE; + } + sum = build_segment(this, sym, &len); + if (!sum) + { + return FALSE; + } + if (cs->segment_len != len) + { + DBG1(DBG_LIB, " invalid '%s' segment size: %u bytes," + " expected %u bytes", name, len, cs->segment_len); + return FALSE; + } + if (cs->segment != sum) + { + DBG1(DBG_LIB, " invalid '%s' segment checksum: %08x, expected %08x", + name, sum, cs->segment); + return FALSE; + } + DBG2(DBG_LIB, " valid '%s' segment checksum: %08x", name, sum); + return TRUE; +} + +METHOD(integrity_checker_t, check, bool, + private_integrity_checker_t *this, char *name, void *sym) +{ + Dl_info dli; + + if (dladdr(sym, &dli) == 0) + { + DBG1(DBG_LIB, "unable to locate symbol: %s", dlerror()); + return FALSE; + } + if (!check_file(this, name, (char*)dli.dli_fname)) + { + return FALSE; + } + if (!check_segment(this, name, sym)) + { + return FALSE; + } + return TRUE; +} + +METHOD(integrity_checker_t, destroy, void, + private_integrity_checker_t *this) +{ + if (this->handle) + { + dlclose(this->handle); + } + free(this); +} + +/** + * See header + */ +integrity_checker_t *integrity_checker_create(char *checksum_library) +{ + private_integrity_checker_t *this; + + INIT(this, + .public = { + .check_file = _check_file, + .build_file = _build_file, + .check_segment = _check_segment, + .build_segment = _build_segment, + .check = _check, + .destroy = _destroy, + }, + ); + + if (checksum_library) + { + this->handle = dlopen(checksum_library, RTLD_LAZY); + if (this->handle) + { + int *checksum_count; + + this->checksums = dlsym(this->handle, "checksums"); + checksum_count = dlsym(this->handle, "checksum_count"); + if (this->checksums && checksum_count) + { + this->checksum_count = *checksum_count; + } + else + { + DBG1(DBG_LIB, "checksum library '%s' invalid", + checksum_library); + } + } + else + { + DBG1(DBG_LIB, "loading checksum library '%s' failed", + checksum_library); + } + } + return &this->public; +} + diff --git a/src/libstrongswan/utils/integrity_checker.h b/src/libstrongswan/utils/integrity_checker.h new file mode 100644 index 000000000..afaa114b3 --- /dev/null +++ b/src/libstrongswan/utils/integrity_checker.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program 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 General Public License + * for more details. + */ + +/** + * @defgroup integrity_checker integrity_checker + * @{ @ingroup utils + */ + +#ifndef INTEGRITY_CHECKER_H_ +#define INTEGRITY_CHECKER_H_ + +#include "utils.h" + +typedef struct integrity_checker_t integrity_checker_t; +typedef struct integrity_checksum_t integrity_checksum_t; + +/** + * Struct to hold a precalculated checksum, implemented in the checksum library. + */ +struct integrity_checksum_t { + /* name of the checksum */ + char *name; + /* size in bytes of the file on disk */ + size_t file_len; + /* checksum of the file on disk */ + u_int32_t file; + /* size in bytes of executable segment in memory */ + size_t segment_len; + /* checksum of the executable segment in memory */ + u_int32_t segment; +}; + +/** + * Code integrity checker to detect non-malicious file manipulation. + * + * The integrity checker reads the checksums from a separate library + * libchecksum.so to compare the checksums. + */ +struct integrity_checker_t { + + /** + * Check the integrity of a file on disk. + * + * @param name name to lookup checksum + * @param file path to file + * @return TRUE if integrity tested successfully + */ + bool (*check_file)(integrity_checker_t *this, char *name, char *file); + + /** + * Build the integrity checksum of a file on disk. + * + * @param file path to file + * @param len return length in bytes of file + * @return checksum, 0 on error + */ + u_int32_t (*build_file)(integrity_checker_t *this, char *file, size_t *len); + + /** + * Check the integrity of the code segment in memory. + * + * @param name name to lookup checksum + * @param sym a symbol in the segment to check + * @return TRUE if integrity tested successfully + */ + bool (*check_segment)(integrity_checker_t *this, char *name, void *sym); + /** + * Build the integrity checksum of a code segment in memory. + * + * @param sym a symbol in the segment to check + * @param len return length in bytes of code segment in memory + * @return checksum, 0 on error + */ + u_int32_t (*build_segment)(integrity_checker_t *this, void *sym, size_t *len); + + /** + * Check both, on disk file integrity and loaded segment. + * + * @param name name to lookup checksum + * @param sym a symbol to look up library and segment + * @return TRUE if integrity tested successfully + */ + bool (*check)(integrity_checker_t *this, char *name, void *sym); + + /** + * Destroy a integrity_checker_t. + */ + void (*destroy)(integrity_checker_t *this); +}; + +/** + * Create a integrity_checker instance. + * + * @param checksum_library library containing checksums + */ +integrity_checker_t *integrity_checker_create(char *checksum_library); + +#endif /** INTEGRITY_CHECKER_H_ @}*/ diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c index cface0538..2b0be1661 100644 --- a/src/libstrongswan/utils/leak_detective.c +++ b/src/libstrongswan/utils/leak_detective.c @@ -32,9 +32,9 @@ #include "leak_detective.h" #include <library.h> -#include <debug.h> +#include <utils/debug.h> #include <utils/backtrace.h> -#include <utils/hashtable.h> +#include <collections/hashtable.h> typedef struct private_leak_detective_t private_leak_detective_t; diff --git a/src/libstrongswan/utils/linked_list.c b/src/libstrongswan/utils/linked_list.c deleted file mode 100644 index 1ff80999b..000000000 --- a/src/libstrongswan/utils/linked_list.c +++ /dev/null @@ -1,615 +0,0 @@ -/* - * Copyright (C) 2007-2011 Tobias Brunner - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program 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 General Public License - * for more details. - */ - -#include <stdlib.h> -#include <stdarg.h> - -#include "linked_list.h" - -typedef struct element_t element_t; - -/** - * This element holds a pointer to the value it represents. - */ -struct element_t { - - /** - * Value of a list item. - */ - void *value; - - /** - * Previous list element. - * - * NULL if first element in list. - */ - element_t *previous; - - /** - * Next list element. - * - * NULL if last element in list. - */ - element_t *next; -}; - -/** - * Creates an empty linked list object. - */ -element_t *element_create(void *value) -{ - element_t *this; - INIT(this, - .value = value, - ); - return this; -} - - -typedef struct private_linked_list_t private_linked_list_t; - -/** - * Private data of a linked_list_t object. - * - */ -struct private_linked_list_t { - /** - * Public part of linked list. - */ - linked_list_t public; - - /** - * Number of items in the list. - */ - int count; - - /** - * First element in list. - * NULL if no elements in list. - */ - element_t *first; - - /** - * Last element in list. - * NULL if no elements in list. - */ - element_t *last; -}; - -typedef struct private_enumerator_t private_enumerator_t; - -/** - * linked lists enumerator implementation - */ -struct private_enumerator_t { - - /** - * implements enumerator interface - */ - enumerator_t enumerator; - - /** - * associated linked list - */ - private_linked_list_t *list; - - /** - * current item - */ - element_t *current; - - /** - * enumerator has enumerated all items - */ - bool finished; -}; - -METHOD(enumerator_t, enumerate, bool, - private_enumerator_t *this, void **item) -{ - if (this->finished) - { - return FALSE; - } - if (!this->current) - { - this->current = this->list->first; - } - else - { - this->current = this->current->next; - } - if (!this->current) - { - this->finished = TRUE; - return FALSE; - } - *item = this->current->value; - return TRUE; -} - -METHOD(linked_list_t, create_enumerator, enumerator_t*, - private_linked_list_t *this) -{ - private_enumerator_t *enumerator; - - INIT(enumerator, - .enumerator = { - .enumerate = (void*)_enumerate, - .destroy = (void*)free, - }, - .list = this, - ); - - return &enumerator->enumerator; -} - -METHOD(linked_list_t, reset_enumerator, void, - private_linked_list_t *this, private_enumerator_t *enumerator) -{ - enumerator->current = NULL; - enumerator->finished = FALSE; -} - -METHOD(linked_list_t, has_more, bool, - private_linked_list_t *this, private_enumerator_t *enumerator) -{ - if (enumerator->current) - { - return enumerator->current->next != NULL; - } - return !enumerator->finished && this->first != NULL; -} - -METHOD(linked_list_t, get_count, int, - private_linked_list_t *this) -{ - return this->count; -} - -METHOD(linked_list_t, insert_first, void, - private_linked_list_t *this, void *item) -{ - element_t *element; - - element = element_create(item); - if (this->count == 0) - { - /* first entry in list */ - this->first = element; - this->last = element; - } - else - { - element->next = this->first; - this->first->previous = element; - this->first = element; - } - this->count++; -} - -/** - * unlink an element form the list, returns following element - */ -static element_t* remove_element(private_linked_list_t *this, - element_t *element) -{ - element_t *next, *previous; - - next = element->next; - previous = element->previous; - free(element); - if (next) - { - next->previous = previous; - } - else - { - this->last = previous; - } - if (previous) - { - previous->next = next; - } - else - { - this->first = next; - } - if (--this->count == 0) - { - this->first = NULL; - this->last = NULL; - } - return next; -} - -METHOD(linked_list_t, get_first, status_t, - private_linked_list_t *this, void **item) -{ - if (this->count == 0) - { - return NOT_FOUND; - } - *item = this->first->value; - return SUCCESS; -} - -METHOD(linked_list_t, remove_first, status_t, - private_linked_list_t *this, void **item) -{ - if (get_first(this, item) == SUCCESS) - { - remove_element(this, this->first); - return SUCCESS; - } - return NOT_FOUND; -} - -METHOD(linked_list_t, insert_last, void, - private_linked_list_t *this, void *item) -{ - element_t *element; - - element = element_create(item); - if (this->count == 0) - { - /* first entry in list */ - this->first = element; - this->last = element; - } - else - { - element->previous = this->last; - this->last->next = element; - this->last = element; - } - this->count++; -} - -METHOD(linked_list_t, insert_before, void, - private_linked_list_t *this, private_enumerator_t *enumerator, - void *item) -{ - element_t *current, *element; - - current = enumerator->current; - if (!current) - { - if (enumerator->finished) - { - this->public.insert_last(&this->public, item); - } - else - { - this->public.insert_first(&this->public, item); - } - return; - } - element = element_create(item); - if (current->previous) - { - current->previous->next = element; - element->previous = current->previous; - current->previous = element; - element->next = current; - } - else - { - current->previous = element; - element->next = current; - this->first = element; - } - this->count++; -} - -METHOD(linked_list_t, replace, void*, - private_linked_list_t *this, private_enumerator_t *enumerator, - void *item) -{ - void *old = NULL; - - if (enumerator->current) - { - old = enumerator->current->value; - enumerator->current->value = item; - } - return old; -} - -METHOD(linked_list_t, get_last, status_t, - private_linked_list_t *this, void **item) -{ - if (this->count == 0) - { - return NOT_FOUND; - } - *item = this->last->value; - return SUCCESS; -} - -METHOD(linked_list_t, remove_last, status_t, - private_linked_list_t *this, void **item) -{ - if (get_last(this, item) == SUCCESS) - { - remove_element(this, this->last); - return SUCCESS; - } - return NOT_FOUND; -} - -METHOD(linked_list_t, remove_, int, - private_linked_list_t *this, void *item, bool (*compare)(void*,void*)) -{ - element_t *current = this->first; - int removed = 0; - - while (current) - { - if ((compare && compare(current->value, item)) || - (!compare && current->value == item)) - { - removed++; - current = remove_element(this, current); - } - else - { - current = current->next; - } - } - return removed; -} - -METHOD(linked_list_t, remove_at, void, - private_linked_list_t *this, private_enumerator_t *enumerator) -{ - element_t *current; - - if (enumerator->current) - { - current = enumerator->current; - enumerator->current = current->previous; - remove_element(this, current); - } -} - -METHOD(linked_list_t, find_first, status_t, - private_linked_list_t *this, linked_list_match_t match, - void **item, void *d1, void *d2, void *d3, void *d4, void *d5) -{ - element_t *current = this->first; - - while (current) - { - if ((match && match(current->value, d1, d2, d3, d4, d5)) || - (!match && item && current->value == *item)) - { - if (item != NULL) - { - *item = current->value; - } - return SUCCESS; - } - current = current->next; - } - return NOT_FOUND; -} - -METHOD(linked_list_t, find_last, status_t, - private_linked_list_t *this, linked_list_match_t match, - void **item, void *d1, void *d2, void *d3, void *d4, void *d5) -{ - element_t *current = this->last; - - while (current) - { - if ((match && match(current->value, d1, d2, d3, d4, d5)) || - (!match && item && current->value == *item)) - { - if (item != NULL) - { - *item = current->value; - } - return SUCCESS; - } - current = current->previous; - } - return NOT_FOUND; -} - -METHOD(linked_list_t, invoke_offset, void, - private_linked_list_t *this, size_t offset, - void *d1, void *d2, void *d3, void *d4, void *d5) -{ - element_t *current = this->first; - linked_list_invoke_t *method; - - while (current) - { - method = current->value + offset; - (*method)(current->value, d1, d2, d3, d4, d5); - current = current->next; - } -} - -METHOD(linked_list_t, invoke_function, void, - private_linked_list_t *this, linked_list_invoke_t fn, - void *d1, void *d2, void *d3, void *d4, void *d5) -{ - element_t *current = this->first; - - while (current) - { - fn(current->value, d1, d2, d3, d4, d5); - current = current->next; - } -} - -METHOD(linked_list_t, clone_offset, linked_list_t*, - private_linked_list_t *this, size_t offset) -{ - element_t *current = this->first; - linked_list_t *clone; - - clone = linked_list_create(); - while (current) - { - void* (**method)(void*) = current->value + offset; - clone->insert_last(clone, (*method)(current->value)); - current = current->next; - } - - return clone; -} - -METHOD(linked_list_t, clone_function, linked_list_t*, - private_linked_list_t *this, void* (*fn)(void*)) -{ - element_t *current = this->first; - linked_list_t *clone; - - clone = linked_list_create(); - while (current) - { - clone->insert_last(clone, fn(current->value)); - current = current->next; - } - return clone; -} - -METHOD(linked_list_t, destroy, void, - private_linked_list_t *this) -{ - void *value; - - /* Remove all list items before destroying list */ - while (remove_first(this, &value) == SUCCESS) - { - /* values are not destroyed so memory leaks are possible - * if list is not empty when deleting */ - } - free(this); -} - -METHOD(linked_list_t, destroy_offset, void, - private_linked_list_t *this, size_t offset) -{ - element_t *current = this->first, *next; - - while (current) - { - void (**method)(void*) = current->value + offset; - (*method)(current->value); - next = current->next; - free(current); - current = next; - } - free(this); -} - -METHOD(linked_list_t, destroy_function, void, - private_linked_list_t *this, void (*fn)(void*)) -{ - element_t *current = this->first, *next; - - while (current) - { - fn(current->value); - next = current->next; - free(current); - current = next; - } - free(this); -} - -/* - * Described in header. - */ -linked_list_t *linked_list_create() -{ - private_linked_list_t *this; - - INIT(this, - .public = { - .get_count = _get_count, - .create_enumerator = _create_enumerator, - .reset_enumerator = (void*)_reset_enumerator, - .has_more = (void*)_has_more, - .get_first = _get_first, - .get_last = _get_last, - .find_first = (void*)_find_first, - .find_last = (void*)_find_last, - .insert_first = _insert_first, - .insert_last = _insert_last, - .insert_before = (void*)_insert_before, - .replace = (void*)_replace, - .remove_first = _remove_first, - .remove_last = _remove_last, - .remove = _remove_, - .remove_at = (void*)_remove_at, - .invoke_offset = (void*)_invoke_offset, - .invoke_function = (void*)_invoke_function, - .clone_offset = _clone_offset, - .clone_function = _clone_function, - .destroy = _destroy, - .destroy_offset = _destroy_offset, - .destroy_function = _destroy_function, - }, - ); - - return &this->public; -} - -/* - * See header. - */ -linked_list_t *linked_list_create_from_enumerator(enumerator_t *enumerator) -{ - linked_list_t *list; - void *item; - - list = linked_list_create(); - - while (enumerator->enumerate(enumerator, &item)) - { - list->insert_last(list, item); - } - enumerator->destroy(enumerator); - - return list; -} - -/* - * See header. - */ -linked_list_t *linked_list_create_with_items(void *item, ...) -{ - linked_list_t *list; - va_list args; - - list = linked_list_create(); - - va_start(args, item); - while (item) - { - list->insert_last(list, item); - item = va_arg(args, void*); - } - va_end(args); - - return list; -} diff --git a/src/libstrongswan/utils/linked_list.h b/src/libstrongswan/utils/linked_list.h deleted file mode 100644 index 1b5518480..000000000 --- a/src/libstrongswan/utils/linked_list.h +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright (C) 2007-2011 Tobias Brunner - * Copyright (C) 2005-2008 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program 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 General Public License - * for more details. - */ - -/** - * @defgroup linked_list linked_list - * @{ @ingroup utils - */ - -#ifndef LINKED_LIST_H_ -#define LINKED_LIST_H_ - -typedef struct linked_list_t linked_list_t; - -#include <utils/enumerator.h> - -/** - * Method to match elements in a linked list (used in find_* functions) - * - * @param item current list item - * @param ... user supplied data (only pointers, at most 5) - * @return - * - TRUE, if the item matched - * - FALSE, otherwise - */ -typedef bool (*linked_list_match_t)(void *item, ...); - -/** - * Method to be invoked on elements in a linked list (used in invoke_* functions) - * - * @param item current list item - * @param ... user supplied data (only pointers, at most 5) - */ -typedef void (*linked_list_invoke_t)(void *item, ...); - -/** - * Class implementing a double linked list. - * - * General purpose linked list. This list is not synchronized. - */ -struct linked_list_t { - - /** - * Gets the count of items in the list. - * - * @return number of items in list - */ - int (*get_count) (linked_list_t *this); - - /** - * Create an enumerator over the list. - * - * @note The enumerator's position is invalid before the first call - * to enumerate(). - * - * @return enumerator over list items - */ - enumerator_t* (*create_enumerator)(linked_list_t *this); - - /** - * Resets the enumerator's current position to the beginning of the list. - * - * @param enumerator enumerator to reset - */ - void (*reset_enumerator)(linked_list_t *this, enumerator_t *enumerator); - - /** - * Checks if there are more elements following after the enumerator's - * current position. - * - * @param enumerator enumerator to check - */ - bool (*has_more)(linked_list_t *this, enumerator_t *enumerator); - - /** - * Inserts a new item at the beginning of the list. - * - * @param item item value to insert in list - */ - void (*insert_first) (linked_list_t *this, void *item); - - /** - * Removes the first item in the list and returns its value. - * - * @param item returned value of first item, or NULL - * @return SUCCESS, or NOT_FOUND if list is empty - */ - status_t (*remove_first) (linked_list_t *this, void **item); - - /** - * Inserts a new item before the item the enumerator currently points to. - * - * If this method is called before starting the enumeration the item is - * inserted first. If it is called after all items have been enumerated - * the item is inserted last. This is helpful when inserting items into - * a sorted list. - * - * @note The position of the enumerator is not changed. - * - * @param enumerator enumerator with position - * @param item item value to insert in list - */ - void (*insert_before)(linked_list_t *this, enumerator_t *enumerator, - void *item); - - /** - * Replaces the item the enumerator currently points to with the given item. - * - * @param enumerator enumerator with position - * @param item item value to replace current item with - * @return current item or NULL if the enumerator is at an - * invalid position - */ - void *(*replace)(linked_list_t *this, enumerator_t *enumerator, void *item); - - /** - * Remove an item from the list where the enumerator points to. - * - * @param enumerator enumerator with position - */ - void (*remove_at)(linked_list_t *this, enumerator_t *enumerator); - - /** - * Remove items from the list matching the given item. - * - * If a compare function is given, it is called for each item, with the - * first parameter being the current list item and the second parameter - * being the supplied item. Return TRUE from the compare function to remove - * the item, return FALSE to keep it in the list. - * - * If compare is NULL, comparison is done by pointers. - * - * @param item item to remove/pass to comparator - * @param compare compare function, or NULL - * @return number of removed items - */ - int (*remove)(linked_list_t *this, void *item, bool (*compare)(void*,void*)); - - /** - * Returns the value of the first list item without removing it. - * - * @param item returned value of first item - * @return SUCCESS, NOT_FOUND if list is empty - */ - status_t (*get_first) (linked_list_t *this, void **item); - - /** - * Inserts a new item at the end of the list. - * - * @param item value to insert into list - */ - void (*insert_last) (linked_list_t *this, void *item); - - /** - * Removes the last item in the list and returns its value. - * - * @param item returned value of last item, or NULL - * @return SUCCESS, NOT_FOUND if list is empty - */ - status_t (*remove_last) (linked_list_t *this, void **item); - - /** - * Returns the value of the last list item without removing it. - * - * @param item returned value of last item - * @return SUCCESS, NOT_FOUND if list is empty - */ - status_t (*get_last) (linked_list_t *this, void **item); - - /** Find the first matching element in the list. - * - * The first object passed to the match function is the current list item, - * followed by the user supplied data. - * If the supplied function returns TRUE this function returns SUCCESS, and - * the current object is returned in the third parameter, otherwise, - * the next item is checked. - * - * If match is NULL, *item and the current object are compared. - * - * @warning Only use pointers as user supplied data. - * - * @param match comparison function to call on each object, or NULL - * @param item the list item, if found - * @param ... user data to supply to match function (limited to 5 arguments) - * @return SUCCESS if found, NOT_FOUND otherwise - */ - status_t (*find_first) (linked_list_t *this, linked_list_match_t match, - void **item, ...); - - /** Find the last matching element in the list. - * - * The first object passed to the match function is the current list item, - * followed by the user supplied data. - * If the supplied function returns TRUE this function returns SUCCESS, and - * the current object is returned in the third parameter, otherwise, - * the next item is checked. - * - * If match is NULL, *item and the current object are compared. - * - * @warning Only use pointers as user supplied data. - * - * @param match comparison function to call on each object, or NULL - * @param item the list item, if found - * @param ... user data to supply to match function (limited to 5 arguments) - * @return SUCCESS if found, NOT_FOUND otherwise - */ - status_t (*find_last) (linked_list_t *this, linked_list_match_t match, - void **item, ...); - - /** - * Invoke a method on all of the contained objects. - * - * If a linked list contains objects with function pointers, - * invoke() can call a method on each of the objects. The - * method is specified by an offset of the function pointer, - * which can be evalutated at compile time using the offsetof - * macro, e.g.: list->invoke(list, offsetof(object_t, method)); - * - * @warning Only use pointers as user supplied data. - * - * @param offset offset of the method to invoke on objects - * @param ... user data to supply to called function (limited to 5 arguments) - */ - void (*invoke_offset) (linked_list_t *this, size_t offset, ...); - - /** - * Invoke a function on all of the contained objects. - * - * @warning Only use pointers as user supplied data. - * - * @param function offset of the method to invoke on objects - * @param ... user data to supply to called function (limited to 5 arguments) - */ - void (*invoke_function) (linked_list_t *this, linked_list_invoke_t function, ...); - - /** - * Clones a list and its objects using the objects' clone method. - * - * @param offset offset ot the objects clone function - * @return cloned list - */ - linked_list_t *(*clone_offset) (linked_list_t *this, size_t offset); - - /** - * Clones a list and its objects using a given function. - * - * @param function function that clones an object - * @return cloned list - */ - linked_list_t *(*clone_function) (linked_list_t *this, void*(*)(void*)); - - /** - * Destroys a linked_list object. - */ - void (*destroy) (linked_list_t *this); - - /** - * Destroys a list and its objects using the destructor. - * - * If a linked list and the contained objects should be destroyed, use - * destroy_offset. The supplied offset specifies the destructor to - * call on each object. The offset may be calculated using the offsetof - * macro, e.g.: list->destroy_offset(list, offsetof(object_t, destroy)); - * - * @param offset offset of the objects destructor - */ - void (*destroy_offset) (linked_list_t *this, size_t offset); - - /** - * Destroys a list and its contents using a a cleanup function. - * - * If a linked list and its contents should get destroyed using a specific - * cleanup function, use destroy_function. This is useful when the - * list contains malloc()-ed blocks which should get freed, - * e.g.: list->destroy_function(list, free); - * - * @param function function to call on each object - */ - void (*destroy_function) (linked_list_t *this, void (*)(void*)); -}; - -/** - * Creates an empty linked list object. - * - * @return linked_list_t object. - */ -linked_list_t *linked_list_create(void); - -/** - * Creates a linked list from an enumerator. - * - * @param enumerator enumerator over void*, gets destroyed - * @return linked_list_t object, containing enumerated values - */ -linked_list_t *linked_list_create_from_enumerator(enumerator_t *enumerator); - -/** - * Creates a linked list from a NULL terminated vararg list of items. - * - * @param first first item - * @param ... subsequent items, terminated by NULL - * @return linked_list_t object, containing passed items - */ -linked_list_t *linked_list_create_with_items(void *first, ...); - -#endif /** LINKED_LIST_H_ @}*/ diff --git a/src/libstrongswan/utils/optionsfrom.c b/src/libstrongswan/utils/optionsfrom.c index 5fd4cfd4d..117071351 100644 --- a/src/libstrongswan/utils/optionsfrom.c +++ b/src/libstrongswan/utils/optionsfrom.c @@ -2,22 +2,22 @@ * Copyright (C) 2007-2008 Andreas Steffen * Hochschule fuer Technik Rapperswil * - * This 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. See <http://www.fsf.org/copyleft/lgpl.txt>. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. * - * This library is distributed in the hope that it will be useful, but + * This program 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. + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. */ #include <stdio.h> #include <errno.h> #include <library.h> -#include <debug.h> +#include <utils/debug.h> #include <utils/lexparser.h> #include "optionsfrom.h" diff --git a/src/libstrongswan/utils/packet.c b/src/libstrongswan/utils/packet.c deleted file mode 100644 index a2c329d60..000000000 --- a/src/libstrongswan/utils/packet.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2012 Tobias Brunner - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program 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 General Public License - * for more details. - */ - -#include "packet.h" - -typedef struct private_packet_t private_packet_t; - -/** - * Private data of an packet_t object. - */ -struct private_packet_t { - - /** - * Public part of a packet_t object. - */ - packet_t public; - - /** - * source address - */ - host_t *source; - - /** - * destination address - */ - host_t *destination; - - /** - * message data - */ - chunk_t data; - - /** - * actual chunk returned from get_data, adjusted when skip_bytes is called - */ - chunk_t adjusted_data; -}; - -METHOD(packet_t, set_source, void, - private_packet_t *this, host_t *source) -{ - DESTROY_IF(this->source); - this->source = source; -} - -METHOD(packet_t, set_destination, void, - private_packet_t *this, host_t *destination) -{ - DESTROY_IF(this->destination); - this->destination = destination; -} - -METHOD(packet_t, get_source, host_t*, - private_packet_t *this) -{ - return this->source; -} - -METHOD(packet_t, get_destination, host_t*, - private_packet_t *this) -{ - return this->destination; -} - -METHOD(packet_t, get_data, chunk_t, - private_packet_t *this) -{ - return this->adjusted_data; -} - -METHOD(packet_t, set_data, void, - private_packet_t *this, chunk_t data) -{ - free(this->data.ptr); - this->adjusted_data = this->data = data; -} - -METHOD(packet_t, skip_bytes, void, - private_packet_t *this, size_t bytes) -{ - this->adjusted_data = chunk_skip(this->adjusted_data, bytes); -} - -METHOD(packet_t, destroy, void, - private_packet_t *this) -{ - DESTROY_IF(this->source); - DESTROY_IF(this->destination); - free(this->data.ptr); - free(this); -} - -METHOD(packet_t, clone_, packet_t*, - private_packet_t *this) -{ - packet_t *other; - - other = packet_create(); - if (this->destination) - { - other->set_destination(other, - this->destination->clone(this->destination)); - } - if (this->source) - { - other->set_source(other, this->source->clone(this->source)); - } - if (this->data.ptr) - { - other->set_data(other, chunk_clone(this->adjusted_data)); - } - return other; -} - -/** - * Described in header. - */ -packet_t *packet_create_from_data(host_t *src, host_t *dst, chunk_t data) -{ - private_packet_t *this; - - INIT(this, - .public = { - .set_data = _set_data, - .get_data = _get_data, - .set_source = _set_source, - .get_source = _get_source, - .set_destination = _set_destination, - .get_destination = _get_destination, - .skip_bytes = _skip_bytes, - .clone = _clone_, - .destroy = _destroy, - }, - .source = src, - .destination = dst, - .adjusted_data = data, - .data = data, - ); - - return &this->public; -} - -/* - * Described in header. - */ -packet_t *packet_create() -{ - return packet_create_from_data(NULL, NULL, chunk_empty); -} diff --git a/src/libstrongswan/utils/packet.h b/src/libstrongswan/utils/packet.h deleted file mode 100644 index 5c4440115..000000000 --- a/src/libstrongswan/utils/packet.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2012 Tobias Brunner - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program 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 General Public License - * for more details. - */ - -/** - * @defgroup packet packet - * @{ @ingroup utils - */ - -#ifndef PACKET_H_ -#define PACKET_H_ - -typedef struct packet_t packet_t; - -#include <library.h> -#include <utils/host.h> - -/** - * Abstraction of an IP/UDP-Packet, contains data, sender and receiver. - */ -struct packet_t { - - /** - * Set the source address. - * - * @param source address to set as source (gets owned) - */ - void (*set_source)(packet_t *packet, host_t *source); - - /** - * Set the destination address. - * - * @param source address to set as destination (gets owned) - */ - void (*set_destination)(packet_t *packet, host_t *destination); - - /** - * Get the source address. - * - * @return source address (internal data) - */ - host_t *(*get_source)(packet_t *packet); - - /** - * Get the destination address. - * - * @return destination address (internal data) - */ - host_t *(*get_destination)(packet_t *packet); - - /** - * Get the data from the packet. - * - * @return chunk containing the data (internal data) - */ - chunk_t (*get_data)(packet_t *packet); - - /** - * Set the data in the packet. - * - * @param data chunk with data to set (gets owned) - */ - void (*set_data)(packet_t *packet, chunk_t data); - - /** - * Increase the offset where the actual packet data starts. - * - * The total offset applies to future calls of get_data() and clone(). - * - * @note The offset is reset to 0 when set_data() is called. - * - * @param bytes the number of additional bytes to skip - */ - void (*skip_bytes)(packet_t *packet, size_t bytes); - - /** - * Clones a packet_t object. - * - * @note Data is cloned without skipped bytes. - * - * @param clone clone of the packet - */ - packet_t* (*clone)(packet_t *packet); - - /** - * Destroy the packet, freeing contained data. - */ - void (*destroy)(packet_t *packet); -}; - -/** - * Create an empty packet - * - * @return packet_t object - */ -packet_t *packet_create(); - -/** - * Create a packet from the supplied data - * - * @param src source address (gets owned) - * @param dst destination address (gets owned) - * @param data packet data (gets owned) - * @return packet_t object - */ -packet_t *packet_create_from_data(host_t *src, host_t *dst, chunk_t data); - -#endif /** PACKET_H_ @}*/ diff --git a/src/libstrongswan/utils/printf_hook.c b/src/libstrongswan/utils/printf_hook.c new file mode 100644 index 000000000..6e51aa4c3 --- /dev/null +++ b/src/libstrongswan/utils/printf_hook.c @@ -0,0 +1,511 @@ +/* + * Copyright (C) 2009 Tobias Brunner + * Copyright (C) 2006-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program 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 General Public License + * for more details. + */ + +#include "printf_hook.h" + +#include "utils.h" +#include "debug.h" + +#include <stdio.h> +#include <stdarg.h> +#include <string.h> + +typedef struct private_printf_hook_t private_printf_hook_t; +typedef struct printf_hook_handler_t printf_hook_handler_t; + +#define PRINTF_BUF_LEN 8192 +#define ARGS_MAX 3 + +/** + * private data of printf_hook + */ +struct private_printf_hook_t { + + /** + * public functions + */ + printf_hook_t public; +}; + +/** + * struct with information about a registered handler + */ +struct printf_hook_handler_t { + + /** + * callback function + */ + printf_hook_function_t hook; + + /** + * number of arguments + */ + int numargs; + + /** + * types of the arguments + */ + int argtypes[ARGS_MAX]; + +#ifdef USE_VSTR + /** + * name required for Vstr + */ + char *name; +#endif +}; + +/* A-Z | 6 other chars | a-z */ +#define NUM_HANDLERS 58 +static printf_hook_handler_t *printf_hooks[NUM_HANDLERS]; + +#define SPEC_TO_INDEX(spec) ((int)(spec) - (int)'A') +#define IS_VALID_SPEC(spec) (SPEC_TO_INDEX(spec) > -1 && SPEC_TO_INDEX(spec) < NUM_HANDLERS) + +#if !defined(USE_VSTR) && \ + (defined(HAVE_PRINTF_FUNCTION) || defined(HAVE_PRINTF_SPECIFIER)) + +/** + * Printf hook print function. This is actually of type "printf_function", + * however glibc does it typedef to function, but uclibc to a pointer. + * So we redefine it here. + */ +static int custom_print(FILE *stream, const struct printf_info *info, + const void *const *args) +{ + printf_hook_spec_t spec; + printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(info->spec)]; + printf_hook_data_t data = { + .stream = stream, + }; + + spec.hash = info->alt; + spec.plus = info->showsign; + spec.minus = info->left; + spec.width = info->width; + + return handler->hook(&data, &spec, args); +} + +/** + * Printf hook arginfo function, which is actually of type + * "printf_arginfo_[size_]function". + */ +static int custom_arginfo(const struct printf_info *info, size_t n, int *argtypes +#ifdef HAVE_PRINTF_SPECIFIER + , int *size +#endif + ) +{ + int i; + printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(info->spec)]; + + if (handler->numargs <= n) + { + for (i = 0; i < handler->numargs; ++i) + { + argtypes[i] = handler->argtypes[i]; + } + } + /* we never set "size", as we have no user defined types */ + return handler->numargs; +} + +#else + +#include <errno.h> +#include <unistd.h> /* for STDOUT_FILENO */ + +/** + * These are used below, whenever the public wrapper functions are called before + * initialization or after destruction. + */ +#undef vprintf +#undef vfprintf +#undef vsnprintf + +/** + * Vstr custom format specifier callback function. + */ +static int custom_fmt_cb(Vstr_base *base, size_t pos, Vstr_fmt_spec *fmt_spec) +{ + int i; + const void *args[ARGS_MAX]; + printf_hook_spec_t spec; + printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(fmt_spec->name[0])]; + printf_hook_data_t data = { + .base = base, + .pos = pos, + }; + + for (i = 0; i < handler->numargs; i++) + { + switch(handler->argtypes[i]) + { + case PRINTF_HOOK_ARGTYPE_INT: + args[i] = VSTR_FMT_CB_ARG_PTR(fmt_spec, i); + break; + case PRINTF_HOOK_ARGTYPE_POINTER: + args[i] = &VSTR_FMT_CB_ARG_PTR(fmt_spec, i); + break; + } + } + + spec.hash = fmt_spec->fmt_hash; + spec.plus = fmt_spec->fmt_plus; + spec.minus = fmt_spec->fmt_minus; + spec.width = fmt_spec->fmt_field_width; + + handler->hook(&data, &spec, args); + return 1; +} + +/** + * Add a custom format handler to the given Vstr_conf object + */ +static void vstr_fmt_add_handler(Vstr_conf *conf, printf_hook_handler_t *handler) +{ + int *at = handler->argtypes; + switch(handler->numargs) + { + case 1: + vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0], + VSTR_TYPE_FMT_END); + break; + case 2: + vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0], + at[1], VSTR_TYPE_FMT_END); + break; + case 3: + vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0], + at[1], at[2], VSTR_TYPE_FMT_END); + break; + } +} + +/** + * Management of thread-specific Vstr_conf objects + */ +#include <threading/thread_value.h> + +static thread_value_t *vstr_conf = NULL; + +static Vstr_conf *create_vstr_conf() +{ + int i; + Vstr_conf *conf = vstr_make_conf(); + vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_FMT_CHAR_ESC, '%'); + vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_TYPE_GRPALLOC_CACHE, + VSTR_TYPE_CNTL_CONF_GRPALLOC_CSTR); + vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_NUM_BUF_SZ, PRINTF_BUF_LEN); + for (i = 0; i < NUM_HANDLERS; ++i) + { + printf_hook_handler_t *handler = printf_hooks[i]; + if (handler) + { + vstr_fmt_add_handler(conf, handler); + } + } + return conf; +} + +static inline Vstr_conf *get_vstr_conf() +{ + Vstr_conf *conf = NULL; + if (vstr_conf) + { + conf = (Vstr_conf*)vstr_conf->get(vstr_conf); + if (!conf) + { + conf = create_vstr_conf(); + vstr_conf->set(vstr_conf, conf); + } + } + return conf; +} + +/** + * Described in header + */ +size_t vstr_print_in_hook(struct Vstr_base *base, size_t pos, const char *fmt, + ...) +{ + va_list args; + int written; + + va_start(args, fmt); + written = vstr_add_vfmt(base, pos, fmt, args); + va_end(args); + return written; +} + +/** + * Wrapper functions for printf and alike + */ +int vstr_wrapper_printf(const char *format, ...) +{ + int written; + va_list args; + va_start(args, format); + written = vstr_wrapper_vprintf(format, args); + va_end(args); + return written; +} +int vstr_wrapper_fprintf(FILE *stream, const char *format, ...) +{ + int written; + va_list args; + va_start(args, format); + written = vstr_wrapper_vfprintf(stream, format, args); + va_end(args); + return written; +} +int vstr_wrapper_sprintf(char *str, const char *format, ...) +{ + int written; + va_list args; + va_start(args, format); + written = vstr_wrapper_vsprintf(str, format, args); + va_end(args); + return written; +} +int vstr_wrapper_snprintf(char *str, size_t size, const char *format, ...) +{ + int written; + va_list args; + va_start(args, format); + written = vstr_wrapper_vsnprintf(str, size, format, args); + va_end(args); + return written; +} +int vstr_wrapper_asprintf(char **str, const char *format, ...) +{ + int written; + va_list args; + va_start(args, format); + written = vstr_wrapper_vasprintf(str, format, args); + va_end(args); + return written; +} +static inline int vstr_wrapper_vprintf_internal(Vstr_conf *conf, int fd, + const char *format, + va_list args) +{ + int written; + Vstr_base *s = vstr_make_base(conf); + vstr_add_vfmt(s, 0, format, args); + written = s->len; + while (s->len) + { + if (!vstr_sc_write_fd(s, 1, s->len, fd, NULL)) + { + if (errno != EAGAIN && errno != EINTR) + { + written -= s->len; + break; + } + } + } + vstr_free_base(s); + return written; +} +int vstr_wrapper_vprintf(const char *format, va_list args) +{ + Vstr_conf *conf = get_vstr_conf(); + if (conf) + { + return vstr_wrapper_vprintf_internal(conf, STDOUT_FILENO, format, args); + } + return vprintf(format, args); +} +int vstr_wrapper_vfprintf(FILE *stream, const char *format, va_list args) +{ + Vstr_conf *conf = get_vstr_conf(); + if (conf) + { + return vstr_wrapper_vprintf_internal(conf, fileno(stream), format, + args); + } + return vfprintf(stream, format, args); +} +static inline int vstr_wrapper_vsnprintf_internal(char *str, size_t size, + const char *format, + va_list args) +{ + Vstr_conf *conf = get_vstr_conf(); + if (conf) + { + int written; + Vstr_base *s = vstr_make_base(conf); + vstr_add_vfmt(s, 0, format, args); + written = s->len; + vstr_export_cstr_buf(s, 1, s->len, str, (size > 0) ? size : s->len + 1); + vstr_free_base(s); + return written; + } + return vsnprintf(str, size, format, args); +} +int vstr_wrapper_vsprintf(char *str, const char *format, va_list args) +{ + return vstr_wrapper_vsnprintf_internal(str, 0, format, args); +} +int vstr_wrapper_vsnprintf(char *str, size_t size, const char *format, + va_list args) +{ + return (size > 0) ? vstr_wrapper_vsnprintf_internal(str, size, format, args) : 0; +} +int vstr_wrapper_vasprintf(char **str, const char *format, va_list args) +{ + size_t len = 100; + int written; + *str = malloc(len); + while (TRUE) + { + va_list ac; + va_copy(ac, args); + written = vstr_wrapper_vsnprintf_internal(*str, len, format, ac); + va_end(ac); + if (written < len) + { + break; + } + len = written + 1; + *str = realloc(*str, len); + } + return written; +} +#endif + +METHOD(printf_hook_t, add_handler, void, + private_printf_hook_t *this, char spec, + printf_hook_function_t hook, ...) +{ + int i = -1; + printf_hook_handler_t *handler; + printf_hook_argtype_t argtype; + va_list args; + + if (!IS_VALID_SPEC(spec)) + { + DBG1(DBG_LIB, "'%c' is not a valid printf hook specifier, " + "not registered!", spec); + return; + } + + handler = malloc_thing(printf_hook_handler_t); + handler->hook = hook; + + va_start(args, hook); + while ((argtype = va_arg(args, printf_hook_argtype_t)) != PRINTF_HOOK_ARGTYPE_END) + { + if (++i >= ARGS_MAX) + { + DBG1(DBG_LIB, "Too many arguments for printf hook with " + "specifier '%c', not registered!", spec); + va_end(args); + free(handler); + return; + } + handler->argtypes[i] = argtype; + } + va_end(args); + + handler->numargs = i + 1; + + if (handler->numargs > 0) + { +#if !defined(USE_VSTR) && \ + (defined(HAVE_PRINTF_FUNCTION) || defined(HAVE_PRINTF_SPECIFIER)) +# ifdef HAVE_PRINTF_SPECIFIER + register_printf_specifier(spec, custom_print, custom_arginfo); +# else + register_printf_function(spec, custom_print, custom_arginfo); +# endif +#else + Vstr_conf *conf = get_vstr_conf(); + handler->name = malloc(2); + handler->name[0] = spec; + handler->name[1] = '\0'; + vstr_fmt_add_handler(conf, handler); +#endif + printf_hooks[SPEC_TO_INDEX(spec)] = handler; + } + else + { + free(handler); + } +} + +METHOD(printf_hook_t, destroy, void, + private_printf_hook_t *this) +{ + int i; +#ifdef USE_VSTR + Vstr_conf *conf = get_vstr_conf(); +#endif + + for (i = 0; i < NUM_HANDLERS; ++i) + { + printf_hook_handler_t *handler = printf_hooks[i]; + if (handler) + { +#ifdef USE_VSTR + vstr_fmt_del(conf, handler->name); + free(handler->name); +#endif + free(handler); + } + } + +#ifdef USE_VSTR + /* freeing the Vstr_conf of the main thread */ + vstr_conf->destroy(vstr_conf); + vstr_conf = NULL; + vstr_free_conf(conf); + vstr_exit(); +#endif + free(this); +} + +/* + * see header file + */ +printf_hook_t *printf_hook_create() +{ + private_printf_hook_t *this; + + INIT(this, + .public = { + .add_handler = _add_handler, + .destroy = _destroy, + }, + ); + + memset(printf_hooks, 0, sizeof(printf_hooks)); + +#ifdef USE_VSTR + if (!vstr_init()) + { + DBG1(DBG_LIB, "failed to initialize Vstr library!"); + free(this); + return NULL; + } + vstr_conf = thread_value_create((thread_cleanup_t)vstr_free_conf); +#endif + + return &this->public; +} + diff --git a/src/libstrongswan/utils/printf_hook.h b/src/libstrongswan/utils/printf_hook.h new file mode 100644 index 000000000..1425910be --- /dev/null +++ b/src/libstrongswan/utils/printf_hook.h @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2009 Tobias Brunner + * Copyright (C) 2006-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program 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 General Public License + * for more details. + */ + +/** + * @defgroup printf_hook printf_hook + * @{ @ingroup utils + */ + +#ifndef PRINTF_HOOK_H_ +#define PRINTF_HOOK_H_ + +typedef struct printf_hook_t printf_hook_t; +typedef struct printf_hook_spec_t printf_hook_spec_t; +typedef struct printf_hook_data_t printf_hook_data_t; +typedef enum printf_hook_argtype_t printf_hook_argtype_t; + +#if !defined(USE_VSTR) && \ + !defined(HAVE_PRINTF_FUNCTION) && \ + !defined(HAVE_PRINTF_SPECIFIER) +/* assume newer glibc register_printf_specifier if none given */ +#define HAVE_PRINTF_SPECIFIER +#endif + +#if !defined(USE_VSTR) && \ + (defined(HAVE_PRINTF_FUNCTION) || defined(HAVE_PRINTF_SPECIFIER)) + +#include <stdio.h> +#include <printf.h> + +enum printf_hook_argtype_t { + PRINTF_HOOK_ARGTYPE_END = -1, + PRINTF_HOOK_ARGTYPE_INT = PA_INT, + PRINTF_HOOK_ARGTYPE_POINTER = PA_POINTER, +}; + +/** + * Data to pass to a printf hook. + */ +struct printf_hook_data_t { + + /** + * Output FILE stream + */ + FILE *stream;; +}; + +/** + * Helper macro to be used in printf hook callbacks. + */ +#define print_in_hook(data, fmt, ...) ({\ + ssize_t _written = fprintf(data->stream, fmt, ##__VA_ARGS__);\ + if (_written < 0)\ + {\ + _written = 0;\ + }\ + _written;\ +}) + +#else + +#include <vstr.h> + +enum printf_hook_argtype_t { + PRINTF_HOOK_ARGTYPE_END = VSTR_TYPE_FMT_END, + PRINTF_HOOK_ARGTYPE_INT = VSTR_TYPE_FMT_INT, + PRINTF_HOOK_ARGTYPE_POINTER = VSTR_TYPE_FMT_PTR_VOID, +}; + +/** + * Redefining printf and alike + */ +#include <stdio.h> +#include <stdarg.h> + +int vstr_wrapper_printf(const char *format, ...); +int vstr_wrapper_fprintf(FILE *stream, const char *format, ...); +int vstr_wrapper_sprintf(char *str, const char *format, ...); +int vstr_wrapper_snprintf(char *str, size_t size, const char *format, ...); +int vstr_wrapper_asprintf(char **str, const char *format, ...); + +int vstr_wrapper_vprintf(const char *format, va_list ap); +int vstr_wrapper_vfprintf(FILE *stream, const char *format, va_list ap); +int vstr_wrapper_vsprintf(char *str, const char *format, va_list ap); +int vstr_wrapper_vsnprintf(char *str, size_t size, const char *format, va_list ap); +int vstr_wrapper_vasprintf(char **str, const char *format, va_list ap); + +#ifdef printf +#undef printf +#endif +#ifdef fprintf +#undef fprintf +#endif +#ifdef sprintf +#undef sprintf +#endif +#ifdef snprintf +#undef snprintf +#endif +#ifdef asprintf +#undef asprintf +#endif +#ifdef vprintf +#undef vprintf +#endif +#ifdef vfprintf +#undef vfprintf +#endif +#ifdef vsprintf +#undef vsprintf +#endif +#ifdef vsnprintf +#undef vsnprintf +#endif +#ifdef vasprintf +#undef vasprintf +#endif + +#define printf vstr_wrapper_printf +#define fprintf vstr_wrapper_fprintf +#define sprintf vstr_wrapper_sprintf +#define snprintf vstr_wrapper_snprintf +#define asprintf vstr_wrapper_asprintf + +#define vprintf vstr_wrapper_vprintf +#define vfprintf vstr_wrapper_vfprintf +#define vsprintf vstr_wrapper_vsprintf +#define vsnprintf vstr_wrapper_vsnprintf +#define vasprintf vstr_wrapper_vasprintf + +/** + * Data to pass to a printf hook. + */ +struct printf_hook_data_t { + + /** + * Base to append printf to + */ + Vstr_base *base; + + /** + * Position in base to write to + */ + size_t pos; +}; + +/** + * Wrapper around vstr_add_vfmt(), avoids having to link all users of + * print_in_hook() against libvstr. + * + * @param base Vstr_string to add string to + * @param pos position to write to + * @param fmt format string + * @param ... arguments + * @return number of characters written + */ +size_t vstr_print_in_hook(struct Vstr_base *base, size_t pos, const char *fmt, + ...); + +/** + * Helper macro to be used in printf hook callbacks. + */ +#define print_in_hook(data, fmt, ...) ({\ + size_t _written; \ + _written = vstr_print_in_hook(data->base, data->pos, fmt, ##__VA_ARGS__);\ + data->pos += _written;\ + _written;\ +}) + +#endif + +/** + * Callback function type for printf hooks. + * + * @param data hook data, to pass to print_in_hook() + * @param spec format specifier + * @param args arguments array + * @return number of characters written + */ +typedef int (*printf_hook_function_t)(printf_hook_data_t *data, + printf_hook_spec_t *spec, + const void *const *args); + +/** + * Properties of the format specifier + */ +struct printf_hook_spec_t { + /** + * TRUE if a '#' was used in the format specifier + */ + int hash; + + /** + * TRUE if a '-' was used in the format specifier + */ + int minus; + + /** + * TRUE if a '+' was used in the format specifier + */ + int plus; + + /** + * The width as given in the format specifier. + */ + int width; +}; + +/** + * Printf handler management. + */ +struct printf_hook_t { + + /** + * Register a printf handler. + * + * @param spec printf hook format character + * @param hook hook function + * @param ... list of PRINTF_HOOK_ARGTYPE_*, MUST end with PRINTF_HOOK_ARGTYPE_END + */ + void (*add_handler)(printf_hook_t *this, char spec, + printf_hook_function_t hook, ...); + + /** + * Destroy a printf_hook instance. + */ + void (*destroy)(printf_hook_t *this); +}; + +/** + * Create a printf_hook instance. + */ +printf_hook_t *printf_hook_create(); + +#endif /** PRINTF_HOOK_H_ @}*/ diff --git a/src/libstrongswan/utils/settings.c b/src/libstrongswan/utils/settings.c new file mode 100644 index 000000000..712ea6ee2 --- /dev/null +++ b/src/libstrongswan/utils/settings.c @@ -0,0 +1,1227 @@ +/* + * Copyright (C) 2010 Tobias Brunner + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program 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 General Public License + * for more details. + */ + +#define _GNU_SOURCE +#include <string.h> +#include <stdarg.h> +#include <stdio.h> +#include <errno.h> +#include <limits.h> +#include <libgen.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +#ifdef HAVE_GLOB_H +#include <glob.h> +#endif /* HAVE_GLOB_H */ + +#include "settings.h" + +#include "collections/linked_list.h" +#include "threading/rwlock.h" +#include "utils/debug.h" + +#define MAX_INCLUSION_LEVEL 10 + +typedef struct private_settings_t private_settings_t; +typedef struct section_t section_t; +typedef struct kv_t kv_t; + +/** + * private data of settings + */ +struct private_settings_t { + + /** + * public functions + */ + settings_t public; + + /** + * top level section + */ + section_t *top; + + /** + * contents of loaded files and in-memory settings (char*) + */ + linked_list_t *contents; + + /** + * lock to safely access the settings + */ + rwlock_t *lock; +}; + +/** + * section containing subsections and key value pairs + */ +struct section_t { + + /** + * name of the section + */ + char *name; + + /** + * subsections, as section_t + */ + linked_list_t *sections; + + /** + * key value pairs, as kv_t + */ + linked_list_t *kv; +}; + +/** + * Key value pair + */ +struct kv_t { + + /** + * key string, relative + */ + char *key; + + /** + * value as string + */ + char *value; +}; + +/** + * create a key/value pair + */ +static kv_t *kv_create(char *key, char *value) +{ + kv_t *this; + INIT(this, + .key = strdup(key), + .value = value, + ); + return this; +} + +/** + * destroy a key/value pair + */ +static void kv_destroy(kv_t *this) +{ + free(this->key); + free(this); +} + +/** + * create a section with the given name + */ +static section_t *section_create(char *name) +{ + section_t *this; + INIT(this, + .name = strdupnull(name), + .sections = linked_list_create(), + .kv = linked_list_create(), + ); + return this; +} + +/** + * destroy a section + */ +static void section_destroy(section_t *this) +{ + this->kv->destroy_function(this->kv, (void*)kv_destroy); + this->sections->destroy_function(this->sections, (void*)section_destroy); + free(this->name); + free(this); +} + +/** + * Purge contents of a section + */ +static void section_purge(section_t *this) +{ + this->kv->destroy_function(this->kv, (void*)kv_destroy); + this->kv = linked_list_create(); + this->sections->destroy_function(this->sections, (void*)section_destroy); + this->sections = linked_list_create(); +} + +/** + * callback to find a section by name + */ +static bool section_find(section_t *this, char *name) +{ + return streq(this->name, name); +} + +/** + * callback to find a kv pair by key + */ +static bool kv_find(kv_t *this, char *key) +{ + return streq(this->key, key); +} + +/** + * Print a format key, but consume already processed arguments + */ +static bool print_key(char *buf, int len, char *start, char *key, va_list args) +{ + va_list copy; + bool res; + char *pos; + + va_copy(copy, args); + while (start < key) + { + pos = strchr(start, '%'); + if (!pos) + { + start += strlen(start) + 1; + continue; + } + pos++; + switch (*pos) + { + case 'd': + va_arg(copy, int); + break; + case 's': + va_arg(copy, char*); + break; + case 'N': + va_arg(copy, enum_name_t*); + va_arg(copy, int); + break; + case '%': + break; + default: + DBG1(DBG_CFG, "settings with %%%c not supported!", *pos); + break; + } + start = pos; + if (*start) + { + start++; + } + } + res = vsnprintf(buf, len, key, copy) < len; + va_end(copy); + return res; +} + +/** + * Find a section by a given key, using buffered key, reusable buffer. + * If "ensure" is TRUE, the sections are created if they don't exist. + */ +static section_t *find_section_buffered(section_t *section, + char *start, char *key, va_list args, char *buf, int len, + bool ensure) +{ + char *pos; + section_t *found = NULL; + + if (section == NULL) + { + return NULL; + } + pos = strchr(key, '.'); + if (pos) + { + *pos = '\0'; + pos++; + } + if (!print_key(buf, len, start, key, args)) + { + return NULL; + } + if (section->sections->find_first(section->sections, + (linked_list_match_t)section_find, + (void**)&found, buf) != SUCCESS) + { + if (ensure) + { + found = section_create(buf); + section->sections->insert_last(section->sections, found); + } + } + if (found && pos) + { + return find_section_buffered(found, start, pos, args, buf, len, ensure); + } + return found; +} + +/** + * Find a section by a given key (thread-safe). + */ +static section_t *find_section(private_settings_t *this, section_t *section, + char *key, va_list args) +{ + char buf[128], keybuf[512]; + section_t *found; + + if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf)) + { + return NULL; + } + this->lock->read_lock(this->lock); + found = find_section_buffered(section, keybuf, keybuf, args, buf, + sizeof(buf), FALSE); + this->lock->unlock(this->lock); + return found; +} + +/** + * Ensure that the section with the given key exists (thread-safe). + */ +static section_t *ensure_section(private_settings_t *this, section_t *section, + char *key, va_list args) +{ + char buf[128], keybuf[512]; + section_t *found; + + if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf)) + { + return NULL; + } + /* we might have to change the tree */ + this->lock->write_lock(this->lock); + found = find_section_buffered(section, keybuf, keybuf, args, buf, + sizeof(buf), TRUE); + this->lock->unlock(this->lock); + return found; +} + +/** + * Find the key/value pair for a key, using buffered key, reusable buffer + * If "ensure" is TRUE, the sections (and key/value pair) are created if they + * don't exist. + */ +static kv_t *find_value_buffered(section_t *section, char *start, char *key, + va_list args, char *buf, int len, bool ensure) +{ + char *pos; + kv_t *kv = NULL; + section_t *found = NULL; + + if (section == NULL) + { + return NULL; + } + + pos = strchr(key, '.'); + if (pos) + { + *pos = '\0'; + pos++; + + if (!print_key(buf, len, start, key, args)) + { + return NULL; + } + if (section->sections->find_first(section->sections, + (linked_list_match_t)section_find, + (void**)&found, buf) != SUCCESS) + { + if (!ensure) + { + return NULL; + } + found = section_create(buf); + section->sections->insert_last(section->sections, found); + } + return find_value_buffered(found, start, pos, args, buf, len, + ensure); + } + else + { + if (!print_key(buf, len, start, key, args)) + { + return NULL; + } + if (section->kv->find_first(section->kv, (linked_list_match_t)kv_find, + (void**)&kv, buf) != SUCCESS) + { + if (ensure) + { + kv = kv_create(buf, NULL); + section->kv->insert_last(section->kv, kv); + } + } + } + return kv; +} + +/** + * Find the string value for a key (thread-safe). + */ +static char *find_value(private_settings_t *this, section_t *section, + char *key, va_list args) +{ + char buf[128], keybuf[512], *value = NULL; + kv_t *kv; + + if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf)) + { + return NULL; + } + this->lock->read_lock(this->lock); + kv = find_value_buffered(section, keybuf, keybuf, args, buf, sizeof(buf), + FALSE); + if (kv) + { + value = kv->value; + } + this->lock->unlock(this->lock); + return value; +} + +/** + * Set a value to a copy of the given string (thread-safe). + */ +static void set_value(private_settings_t *this, section_t *section, + char *key, va_list args, char *value) +{ + char buf[128], keybuf[512]; + kv_t *kv; + + if (snprintf(keybuf, sizeof(keybuf), "%s", key) >= sizeof(keybuf)) + { + return; + } + this->lock->write_lock(this->lock); + kv = find_value_buffered(section, keybuf, keybuf, args, buf, sizeof(buf), + TRUE); + if (kv) + { + if (!value) + { + kv->value = NULL; + } + else if (kv->value && (strlen(value) <= strlen(kv->value))) + { /* overwrite in-place, if possible */ + strcpy(kv->value, value); + } + else + { /* otherwise clone the string and store it in the cache */ + kv->value = strdup(value); + this->contents->insert_last(this->contents, kv->value); + } + } + this->lock->unlock(this->lock); +} + +METHOD(settings_t, get_str, char*, + private_settings_t *this, char *key, char *def, ...) +{ + char *value; + va_list args; + + va_start(args, def); + value = find_value(this, this->top, key, args); + va_end(args); + if (value) + { + return value; + } + return def; +} + +/** + * Described in header + */ +inline bool settings_value_as_bool(char *value, bool def) +{ + if (value) + { + if (strcaseeq(value, "1") || + strcaseeq(value, "yes") || + strcaseeq(value, "true") || + strcaseeq(value, "enabled")) + { + return TRUE; + } + else if (strcaseeq(value, "0") || + strcaseeq(value, "no") || + strcaseeq(value, "false") || + strcaseeq(value, "disabled")) + { + return FALSE; + } + } + return def; +} + +METHOD(settings_t, get_bool, bool, + private_settings_t *this, char *key, bool def, ...) +{ + char *value; + va_list args; + + va_start(args, def); + value = find_value(this, this->top, key, args); + va_end(args); + return settings_value_as_bool(value, def); +} + +/** + * Described in header + */ +inline int settings_value_as_int(char *value, int def) +{ + int intval; + if (value) + { + errno = 0; + intval = strtol(value, NULL, 10); + if (errno == 0) + { + return intval; + } + } + return def; +} + +METHOD(settings_t, get_int, int, + private_settings_t *this, char *key, int def, ...) +{ + char *value; + va_list args; + + va_start(args, def); + value = find_value(this, this->top, key, args); + va_end(args); + return settings_value_as_int(value, def); +} + +/** + * Described in header + */ +inline double settings_value_as_double(char *value, double def) +{ + double dval; + if (value) + { + errno = 0; + dval = strtod(value, NULL); + if (errno == 0) + { + return dval; + } + } + return def; +} + +METHOD(settings_t, get_double, double, + private_settings_t *this, char *key, double def, ...) +{ + char *value; + va_list args; + + va_start(args, def); + value = find_value(this, this->top, key, args); + va_end(args); + return settings_value_as_double(value, def); +} + +/** + * Described in header + */ +inline u_int32_t settings_value_as_time(char *value, u_int32_t def) +{ + char *endptr; + u_int32_t timeval; + if (value) + { + errno = 0; + timeval = strtoul(value, &endptr, 10); + if (errno == 0) + { + switch (*endptr) + { + case 'd': /* time in days */ + timeval *= 24 * 3600; + break; + case 'h': /* time in hours */ + timeval *= 3600; + break; + case 'm': /* time in minutes */ + timeval *= 60; + break; + case 's': /* time in seconds */ + default: + break; + } + return timeval; + } + } + return def; +} + +METHOD(settings_t, get_time, u_int32_t, + private_settings_t *this, char *key, u_int32_t def, ...) +{ + char *value; + va_list args; + + va_start(args, def); + value = find_value(this, this->top, key, args); + va_end(args); + return settings_value_as_time(value, def); +} + +METHOD(settings_t, set_str, void, + private_settings_t *this, char *key, char *value, ...) +{ + va_list args; + va_start(args, value); + set_value(this, this->top, key, args, value); + va_end(args); +} + +METHOD(settings_t, set_bool, void, + private_settings_t *this, char *key, bool value, ...) +{ + va_list args; + va_start(args, value); + set_value(this, this->top, key, args, value ? "1" : "0"); + va_end(args); +} + +METHOD(settings_t, set_int, void, + private_settings_t *this, char *key, int value, ...) +{ + char val[16]; + va_list args; + va_start(args, value); + if (snprintf(val, sizeof(val), "%d", value) < sizeof(val)) + { + set_value(this, this->top, key, args, val); + } + va_end(args); +} + +METHOD(settings_t, set_double, void, + private_settings_t *this, char *key, double value, ...) +{ + char val[64]; + va_list args; + va_start(args, value); + if (snprintf(val, sizeof(val), "%f", value) < sizeof(val)) + { + set_value(this, this->top, key, args, val); + } + va_end(args); +} + +METHOD(settings_t, set_time, void, + private_settings_t *this, char *key, u_int32_t value, ...) +{ + char val[16]; + va_list args; + va_start(args, value); + if (snprintf(val, sizeof(val), "%u", value) < sizeof(val)) + { + set_value(this, this->top, key, args, val); + } + va_end(args); +} + +/** + * Enumerate section names, not sections + */ +static bool section_filter(void *null, section_t **in, char **out) +{ + *out = (*in)->name; + return TRUE; +} + +METHOD(settings_t, create_section_enumerator, enumerator_t*, + private_settings_t *this, char *key, ...) +{ + section_t *section; + va_list args; + + va_start(args, key); + section = find_section(this, this->top, key, args); + va_end(args); + + if (!section) + { + return enumerator_create_empty(); + } + this->lock->read_lock(this->lock); + return enumerator_create_filter( + section->sections->create_enumerator(section->sections), + (void*)section_filter, this->lock, (void*)this->lock->unlock); +} + +/** + * Enumerate key and values, not kv_t entries + */ +static bool kv_filter(void *null, kv_t **in, char **key, + void *none, char **value) +{ + *key = (*in)->key; + *value = (*in)->value; + return TRUE; +} + +METHOD(settings_t, create_key_value_enumerator, enumerator_t*, + private_settings_t *this, char *key, ...) +{ + section_t *section; + va_list args; + + va_start(args, key); + section = find_section(this, this->top, key, args); + va_end(args); + + if (!section) + { + return enumerator_create_empty(); + } + this->lock->read_lock(this->lock); + return enumerator_create_filter( + section->kv->create_enumerator(section->kv), + (void*)kv_filter, this->lock, (void*)this->lock->unlock); +} + +/** + * parse text, truncate "skip" chars, delimited by term respecting brackets. + * + * Chars in "skip" are truncated at the beginning and the end of the resulting + * token. "term" contains a list of characters to read up to (first match), + * while "br" contains bracket counterparts found in "term" to skip. + */ +static char parse(char **text, char *skip, char *term, char *br, char **token) +{ + char *best = NULL; + char best_term = '\0'; + + /* skip leading chars */ + while (strchr(skip, **text)) + { + (*text)++; + if (!**text) + { + return 0; + } + } + /* mark begin of subtext */ + *token = *text; + while (*term) + { + char *pos = *text; + int level = 1; + + /* find terminator */ + while (*pos) + { + if (*pos == *term) + { + level--; + } + else if (br && *pos == *br) + { + level++; + } + if (level == 0) + { + if (best == NULL || best > pos) + { + best = pos; + best_term = *term; + } + break; + } + pos++; + } + /* try next terminator */ + term++; + if (br) + { + br++; + } + } + if (best) + { + /* update input */ + *text = best; + /* null trailing bytes */ + do + { + *best = '\0'; + best--; + } + while (best >= *token && strchr(skip, *best)); + /* return found terminator */ + return best_term; + } + return 0; +} + +/** + * Check if "text" starts with "pattern". + * Characters in "skip" are skipped first. If found, TRUE is returned and "text" + * is modified to point to the character right after "pattern". + */ +static bool starts_with(char **text, char *skip, char *pattern) +{ + char *pos = *text; + int len = strlen(pattern); + while (strchr(skip, *pos)) + { + pos++; + if (!*pos) + { + return FALSE; + } + } + if (strlen(pos) < len || !strneq(pos, pattern, len)) + { + return FALSE; + } + *text = pos + len; + return TRUE; +} + +/** + * Check if what follows in "text" is an include statement. + * If this function returns TRUE, "text" will point to the character right after + * the include pattern, which is returned in "pattern". + */ +static bool parse_include(char **text, char **pattern) +{ + char *pos = *text; + if (!starts_with(&pos, "\n\t ", "include")) + { + return FALSE; + } + if (starts_with(&pos, "\t ", "=")) + { /* ignore "include = value" */ + return FALSE; + } + *text = pos; + return parse(text, "\t ", "\n", NULL, pattern) != 0; +} + +/** + * Forward declaration. + */ +static bool parse_files(linked_list_t *contents, char *file, int level, + char *pattern, section_t *section); + +/** + * Parse a section + */ +static bool parse_section(linked_list_t *contents, char *file, int level, + char **text, section_t *section) +{ + bool finished = FALSE; + char *key, *value, *inner; + + while (!finished) + { + if (parse_include(text, &value)) + { + if (!parse_files(contents, file, level, value, section)) + { + DBG1(DBG_LIB, "failed to include '%s'", value); + return FALSE; + } + continue; + } + switch (parse(text, "\t\n ", "{=#", NULL, &key)) + { + case '{': + if (parse(text, "\t ", "}", "{", &inner)) + { + section_t *sub; + if (!strlen(key)) + { + DBG1(DBG_LIB, "skipping section without name in '%s'", + section->name); + continue; + } + if (section->sections->find_first(section->sections, + (linked_list_match_t)section_find, + (void**)&sub, key) != SUCCESS) + { + sub = section_create(key); + if (parse_section(contents, file, level, &inner, sub)) + { + section->sections->insert_last(section->sections, + sub); + continue; + } + section_destroy(sub); + } + else + { /* extend the existing section */ + if (parse_section(contents, file, level, &inner, sub)) + { + continue; + } + } + DBG1(DBG_LIB, "parsing subsection '%s' failed", key); + break; + } + DBG1(DBG_LIB, "matching '}' not found near %s", *text); + break; + case '=': + if (parse(text, "\t ", "\n", NULL, &value)) + { + kv_t *kv; + if (!strlen(key)) + { + DBG1(DBG_LIB, "skipping value without key in '%s'", + section->name); + continue; + } + if (section->kv->find_first(section->kv, + (linked_list_match_t)kv_find, + (void**)&kv, key) != SUCCESS) + { + kv = kv_create(key, value); + section->kv->insert_last(section->kv, kv); + } + else + { /* replace with the most recently read value */ + kv->value = value; + } + continue; + } + DBG1(DBG_LIB, "parsing value failed near %s", *text); + break; + case '#': + parse(text, "", "\n", NULL, &value); + continue; + default: + finished = TRUE; + continue; + } + return FALSE; + } + return TRUE; +} + +/** + * Parse a file and add the settings to the given section. + */ +static bool parse_file(linked_list_t *contents, char *file, int level, + section_t *section) +{ + bool success; + char *text, *pos; + struct stat st; + FILE *fd; + int len; + + DBG2(DBG_LIB, "loading config file '%s'", file); + if (stat(file, &st) == -1) + { + if (errno == ENOENT) + { + DBG2(DBG_LIB, "'%s' does not exist, ignored", file); + return TRUE; + } + DBG1(DBG_LIB, "failed to stat '%s': %s", file, strerror(errno)); + return FALSE; + } + else if (!S_ISREG(st.st_mode)) + { + DBG1(DBG_LIB, "'%s' is not a regular file", file); + return FALSE; + } + fd = fopen(file, "r"); + if (fd == NULL) + { + DBG1(DBG_LIB, "'%s' is not readable", file); + return FALSE; + } + fseek(fd, 0, SEEK_END); + len = ftell(fd); + rewind(fd); + text = malloc(len + 1); + text[len] = '\0'; + if (fread(text, 1, len, fd) != len) + { + free(text); + fclose(fd); + return FALSE; + } + fclose(fd); + + pos = text; + success = parse_section(contents, file, level, &pos, section); + if (!success) + { + free(text); + } + else + { + contents->insert_last(contents, text); + } + return success; +} + +/** + * Load the files matching "pattern", which is resolved with glob(3), if + * available. + * If the pattern is relative, the directory of "file" is used as base. + */ +static bool parse_files(linked_list_t *contents, char *file, int level, + char *pattern, section_t *section) +{ + bool success = TRUE; + char pat[PATH_MAX]; + + if (level > MAX_INCLUSION_LEVEL) + { + DBG1(DBG_LIB, "maximum level of %d includes reached, ignored", + MAX_INCLUSION_LEVEL); + return TRUE; + } + + if (!strlen(pattern)) + { + DBG2(DBG_LIB, "empty include pattern, ignored"); + return TRUE; + } + + if (!file || pattern[0] == '/') + { /* absolute path */ + if (snprintf(pat, sizeof(pat), "%s", pattern) >= sizeof(pat)) + { + DBG1(DBG_LIB, "include pattern too long, ignored"); + return TRUE; + } + } + else + { /* base relative paths to the directory of the current file */ + char *dir = strdup(file); + dir = dirname(dir); + if (snprintf(pat, sizeof(pat), "%s/%s", dir, pattern) >= sizeof(pat)) + { + DBG1(DBG_LIB, "include pattern too long, ignored"); + free(dir); + return TRUE; + } + free(dir); + } +#ifdef HAVE_GLOB_H + { + int status; + glob_t buf; + + status = glob(pat, GLOB_ERR, NULL, &buf); + if (status == GLOB_NOMATCH) + { + DBG2(DBG_LIB, "no files found matching '%s', ignored", pat); + } + else if (status != 0) + { + DBG1(DBG_LIB, "expanding file pattern '%s' failed", pat); + success = FALSE; + } + else + { + char **expanded; + for (expanded = buf.gl_pathv; *expanded != NULL; expanded++) + { + success &= parse_file(contents, *expanded, level + 1, section); + if (!success) + { + break; + } + } + } + globfree(&buf); + } +#else /* HAVE_GLOB_H */ + /* if glob(3) is not available, try to load pattern directly */ + success = parse_file(contents, pat, level + 1, section); +#endif /* HAVE_GLOB_H */ + return success; +} + +/** + * Recursivly extends "base" with "extension". + */ +static void section_extend(section_t *base, section_t *extension) +{ + enumerator_t *enumerator; + section_t *sec; + kv_t *kv; + + enumerator = extension->sections->create_enumerator(extension->sections); + while (enumerator->enumerate(enumerator, (void**)&sec)) + { + section_t *found; + if (base->sections->find_first(base->sections, + (linked_list_match_t)section_find, (void**)&found, + sec->name) == SUCCESS) + { + section_extend(found, sec); + } + else + { + extension->sections->remove_at(extension->sections, enumerator); + base->sections->insert_last(base->sections, sec); + } + } + enumerator->destroy(enumerator); + + enumerator = extension->kv->create_enumerator(extension->kv); + while (enumerator->enumerate(enumerator, (void**)&kv)) + { + kv_t *found; + if (base->kv->find_first(base->kv, (linked_list_match_t)kv_find, + (void**)&found, kv->key) == SUCCESS) + { + found->value = kv->value; + } + else + { + extension->kv->remove_at(extension->kv, enumerator); + base->kv->insert_last(base->kv, kv); + } + } + enumerator->destroy(enumerator); +} + +/** + * Load settings from files matching the given file pattern. + * All sections and values are added relative to "parent". + * All files (even included ones) have to be loaded successfully. + */ +static bool load_files_internal(private_settings_t *this, section_t *parent, + char *pattern, bool merge) +{ + char *text; + linked_list_t *contents; + section_t *section; + + if (pattern == NULL) + { +#ifdef STRONGSWAN_CONF + pattern = STRONGSWAN_CONF; +#else + return FALSE; +#endif + } + + contents = linked_list_create(); + section = section_create(NULL); + + if (!parse_files(contents, NULL, 0, pattern, section)) + { + contents->destroy_function(contents, (void*)free); + section_destroy(section); + return FALSE; + } + + this->lock->write_lock(this->lock); + if (!merge) + { + section_purge(parent); + } + /* extend parent section */ + section_extend(parent, section); + /* move contents of loaded files to main store */ + while (contents->remove_first(contents, (void**)&text) == SUCCESS) + { + this->contents->insert_last(this->contents, text); + } + this->lock->unlock(this->lock); + + section_destroy(section); + contents->destroy(contents); + return TRUE; +} + +METHOD(settings_t, load_files, bool, + private_settings_t *this, char *pattern, bool merge) +{ + return load_files_internal(this, this->top, pattern, merge); +} + +METHOD(settings_t, load_files_section, bool, + private_settings_t *this, char *pattern, bool merge, char *key, ...) +{ + section_t *section; + va_list args; + + va_start(args, key); + section = ensure_section(this, this->top, key, args); + va_end(args); + + if (!section) + { + return FALSE; + } + return load_files_internal(this, section, pattern, merge); +} + +METHOD(settings_t, destroy, void, + private_settings_t *this) +{ + section_destroy(this->top); + this->contents->destroy_function(this->contents, (void*)free); + this->lock->destroy(this->lock); + free(this); +} + +/* + * see header file + */ +settings_t *settings_create(char *file) +{ + private_settings_t *this; + + INIT(this, + .public = { + .get_str = _get_str, + .get_int = _get_int, + .get_double = _get_double, + .get_time = _get_time, + .get_bool = _get_bool, + .set_str = _set_str, + .set_int = _set_int, + .set_double = _set_double, + .set_time = _set_time, + .set_bool = _set_bool, + .create_section_enumerator = _create_section_enumerator, + .create_key_value_enumerator = _create_key_value_enumerator, + .load_files = _load_files, + .load_files_section = _load_files_section, + .destroy = _destroy, + }, + .top = section_create(NULL), + .contents = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); + + load_files(this, file, FALSE); + + return &this->public; +} + diff --git a/src/libstrongswan/utils/settings.h b/src/libstrongswan/utils/settings.h new file mode 100644 index 000000000..a861325f5 --- /dev/null +++ b/src/libstrongswan/utils/settings.h @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2010 Tobias Brunner + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program 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 General Public License + * for more details. + */ + +/** + * @defgroup settings settings + * @{ @ingroup utils + */ + +#ifndef SETTINGS_H_ +#define SETTINGS_H_ + +typedef struct settings_t settings_t; + +#include "utils.h" +#include "collections/enumerator.h" + +/** + * Convert a string value returned by a key/value enumerator to a boolean. + * + * @see settings_t.create_key_value_enumerator() + * @see settings_t.get_bool() + * @param value the string value + * @param def the default value, if value is NULL or invalid + */ +bool settings_value_as_bool(char *value, bool def); + +/** + * Convert a string value returned by a key/value enumerator to an integer. + * + * @see settings_t.create_key_value_enumerator() + * @see settings_t.get_int() + * @param value the string value + * @param def the default value, if value is NULL or invalid + */ +int settings_value_as_int(char *value, int def); + +/** + * Convert a string value returned by a key/value enumerator to a double. + * + * @see settings_t.create_key_value_enumerator() + * @see settings_t.get_double() + * @param value the string value + * @param def the default value, if value is NULL or invalid + */ +double settings_value_as_double(char *value, double def); + +/** + * Convert a string value returned by a key/value enumerator to a time value. + * + * @see settings_t.create_key_value_enumerator() + * @see settings_t.get_time() + * @param value the string value + * @param def the default value, if value is NULL or invalid + */ +u_int32_t settings_value_as_time(char *value, u_int32_t def); + +/** + * Generic configuration options read from a config file. + * + * The syntax is quite simple: + * @code + * settings := (section|keyvalue)* + * section := name { settings } + * keyvalue := key = value\n + * @endcode + * E.g.: + * @code + a = b + section-one { + somevalue = asdf + subsection { + othervalue = xxx + } + yetanother = zz + } + section-two { + } + @endcode + * + * The values are accessed using the get() functions using dotted keys, e.g. + * section-one.subsection.othervalue + * + * Currently only a limited set of printf format specifiers are supported + * (namely %s, %d and %N, see implementation for details). + * + * \section includes Including other files + * Other files can be included, using the include statement e.g. + * @code + * include /somepath/subconfig.conf + * @endcode + * Shell patterns like *.conf are possible. + * + * If the path is relative, the directory of the file containing the include + * statement is used as base. + * + * Sections loaded from included files extend previously loaded sections, + * already existing values are replaced. + * + * All settings included from files are added relative to the section the + * include statement is in. + * + * The following files result in the same final config as above: + * + * @code + a = b + section-one { + somevalue = before include + include include.conf + } + include two.conf + @endcode + * include.conf + * @code + somevalue = asdf + subsection { + othervalue = yyy + } + yetanother = zz + @endcode + * two.conf + * @code + section-one { + subsection { + othervalue = xxx + } + } + section-two { + } + @endcode + */ +struct settings_t { + + /** + * Get a settings value as a string. + * + * @param key key including sections, printf style format + * @param def value returned if key not found + * @param ... argument list for key + * @return value pointing to internal string + */ + char* (*get_str)(settings_t *this, char *key, char *def, ...); + + /** + * Get a boolean yes|no, true|false value. + * + * @param key key including sections, printf style format + * @param def value returned if key not found + * @param ... argument list for key + * @return value of the key + */ + bool (*get_bool)(settings_t *this, char *key, bool def, ...); + + /** + * Get an integer value. + * + * @param key key including sections, printf style format + * @param def value returned if key not found + * @param ... argument list for key + * @return value of the key + */ + int (*get_int)(settings_t *this, char *key, int def, ...); + + /** + * Get an double value. + * + * @param key key including sections, printf style format + * @param def value returned if key not found + * @param ... argument list for key + * @return value of the key + */ + double (*get_double)(settings_t *this, char *key, double def, ...); + + /** + * Get a time value. + * + * @param key key including sections, printf style format + * @param def value returned if key not found + * @param ... argument list for key + * @return value of the key (in seconds) + */ + u_int32_t (*get_time)(settings_t *this, char *key, u_int32_t def, ...); + + /** + * Set a string value. + * + * @param key key including sections, printf style format + * @param value value to set (gets cloned) + * @param ... argument list for key + */ + void (*set_str)(settings_t *this, char *key, char *value, ...); + + /** + * Set a boolean value. + * + * @param key key including sections, printf style format + * @param value value to set + * @param ... argument list for key + */ + void (*set_bool)(settings_t *this, char *key, bool value, ...); + + /** + * Set an integer value. + * + * @param key key including sections, printf style format + * @param value value to set + * @param ... argument list for key + */ + void (*set_int)(settings_t *this, char *key, int value, ...); + + /** + * Set an double value. + * + * @param key key including sections, printf style format + * @param value value to set + * @param ... argument list for key + */ + void (*set_double)(settings_t *this, char *key, double value, ...); + + /** + * Set a time value. + * + * @param key key including sections, printf style format + * @param def value to set + * @param ... argument list for key + */ + void (*set_time)(settings_t *this, char *key, u_int32_t value, ...); + + /** + * Create an enumerator over subsection names of a section. + * + * @param section section including parents, printf style format + * @param ... argument list for key + * @return enumerator over subsection names + */ + enumerator_t* (*create_section_enumerator)(settings_t *this, + char *section, ...); + + /** + * Create an enumerator over key/value pairs in a section. + * + * @param section section name to list key/value pairs of, printf style + * @param ... argument list for section + * @return enumerator over (char *key, char *value) + */ + enumerator_t* (*create_key_value_enumerator)(settings_t *this, + char *section, ...); + + /** + * Load settings from the files matching the given pattern. + * + * If merge is TRUE, existing sections are extended, existing values + * replaced, by those found in the loaded files. If it is FALSE, existing + * sections are purged before reading the new config. + * + * @note If any of the files matching the pattern fails to load, no settings + * are added at all. So, it's all or nothing. + * + * @param pattern file pattern + * @param merge TRUE to merge config with existing values + * @return TRUE, if settings were loaded successfully + */ + bool (*load_files)(settings_t *this, char *pattern, bool merge); + + /** + * Load settings from the files matching the given pattern. + * + * If merge is TRUE, existing sections are extended, existing values + * replaced, by those found in the loaded files. If it is FALSE, existing + * sections are purged before reading the new config. + * + * All settings are loaded relative to the given section. The section is + * created, if it does not yet exist. + * + * @note If any of the files matching the pattern fails to load, no settings + * are added at all. So, it's all or nothing. + * + * @param pattern file pattern + * @param merge TRUE to merge config with existing values + * @param section section name of parent section, printf style + * @param ... argument list for section + * @return TRUE, if settings were loaded successfully + */ + bool (*load_files_section)(settings_t *this, char *pattern, bool merge, + char *section, ...); + + /** + * Destroy a settings instance. + */ + void (*destroy)(settings_t *this); +}; + +/** + * Load settings from a file. + * + * @param file file to read settings from, NULL for default + * @return settings object + */ +settings_t *settings_create(char *file); + +#endif /** SETTINGS_H_ @}*/ diff --git a/src/libstrongswan/utils/tun_device.c b/src/libstrongswan/utils/tun_device.c deleted file mode 100644 index 36f3359c0..000000000 --- a/src/libstrongswan/utils/tun_device.c +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Copyright (C) 2012 Tobias Brunner - * Copyright (C) 2012 Giuliano Grassi - * Copyright (C) 2012 Ralf Sager - * Hochschule fuer Technik Rapperswil - * Copyright (C) 2012 Martin Willi - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program 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 General Public License - * for more details. - */ - -#include <errno.h> -#include <fcntl.h> -#include <netinet/in.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <unistd.h> -#include <net/if.h> - -#ifdef __APPLE__ -#include <net/if_utun.h> -#include <netinet/in_var.h> -#include <sys/kern_control.h> -#elif defined(__linux__) -#include <linux/if_tun.h> -#else -#include <net/if_tun.h> -#endif - -#include "tun_device.h" - -#include <library.h> -#include <debug.h> -#include <threading/thread.h> - -#define TUN_DEFAULT_MTU 1500 - -typedef struct private_tun_device_t private_tun_device_t; - -struct private_tun_device_t { - - /** - * Public interface - */ - tun_device_t public; - - /** - * The TUN device's file descriptor - */ - int tunfd; - - /** - * Name of the TUN device - */ - char if_name[IFNAMSIZ]; - - /** - * Socket used for ioctl() to set interface addr, ... - */ - int sock; - - /** - * The current MTU - */ - int mtu; -}; - -/** - * Set the sockaddr_t from the given netmask - */ -static void set_netmask(struct ifreq *ifr, int family, u_int8_t netmask) -{ - int len, bytes, bits; - char *target; - - switch (family) - { - case AF_INET: - { - struct sockaddr_in *addr = (struct sockaddr_in*)&ifr->ifr_addr; - addr->sin_family = AF_INET; - target = (char*)&addr->sin_addr; - len = 4; - break; - } - case AF_INET6: - { - struct sockaddr_in6 *addr = (struct sockaddr_in6*)&ifr->ifr_addr; - addr->sin6_family = AF_INET6; - target = (char*)&addr->sin6_addr; - len = 16; - break; - } - default: - return; - } - - bytes = (netmask + 7) / 8; - bits = (bytes * 8) - netmask; - - memset(target, 0xff, bytes); - memset(target + bytes, 0x00, len - bytes); - target[bytes - 1] = bits ? (u_int8_t)(0xff << bits) : 0xff; -} - -METHOD(tun_device_t, set_address, bool, - private_tun_device_t *this, host_t *addr, u_int8_t netmask) -{ - struct ifreq ifr; - int family; - - family = addr->get_family(addr); - if ((netmask > 32 && family == AF_INET) || netmask > 128) - { - DBG1(DBG_LIB, "failed to set address on %s: invalid netmask", - this->if_name); - return FALSE; - } - - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ); - memcpy(&ifr.ifr_addr, addr->get_sockaddr(addr), sizeof(sockaddr_t)); - - if (ioctl(this->sock, SIOCSIFADDR, &ifr) < 0) - { - DBG1(DBG_LIB, "failed to set address on %s: %s", - this->if_name, strerror(errno)); - return FALSE; - } -#ifdef __APPLE__ - if (ioctl(this->sock, SIOCSIFDSTADDR, &ifr) < 0) - { - DBG1(DBG_LIB, "failed to set dest address on %s: %s", - this->if_name, strerror(errno)); - return FALSE; - } -#endif /* __APPLE__ */ - - set_netmask(&ifr, family, netmask); - - if (ioctl(this->sock, SIOCSIFNETMASK, &ifr) < 0) - { - DBG1(DBG_LIB, "failed to set netmask on %s: %s", - this->if_name, strerror(errno)); - return FALSE; - } - return TRUE; -} - -METHOD(tun_device_t, up, bool, - private_tun_device_t *this) -{ - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ); - - if (ioctl(this->sock, SIOCGIFFLAGS, &ifr) < 0) - { - DBG1(DBG_LIB, "failed to get interface flags for %s: %s", this->if_name, - strerror(errno)); - return FALSE; - } - - ifr.ifr_flags |= IFF_RUNNING | IFF_UP; - - if (ioctl(this->sock, SIOCSIFFLAGS, &ifr) < 0) - { - DBG1(DBG_LIB, "failed to set interface flags on %s: %s", this->if_name, - strerror(errno)); - return FALSE; - } - return TRUE; -} - -METHOD(tun_device_t, set_mtu, bool, - private_tun_device_t *this, int mtu) -{ - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ); - ifr.ifr_mtu = mtu; - - if (ioctl(this->sock, SIOCSIFMTU, &ifr) < 0) - { - DBG1(DBG_LIB, "failed to set MTU on %s: %s", this->if_name, - strerror(errno)); - return FALSE; - } - this->mtu = mtu; - return TRUE; -} - -METHOD(tun_device_t, get_mtu, int, - private_tun_device_t *this) -{ - struct ifreq ifr; - - if (this->mtu > 0) - { - return this->mtu; - } - - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ); - this->mtu = TUN_DEFAULT_MTU; - - if (ioctl(this->sock, SIOCGIFMTU, &ifr) == 0) - { - this->mtu = ifr.ifr_mtu; - } - return this->mtu; -} - -METHOD(tun_device_t, get_name, char*, - private_tun_device_t *this) -{ - return this->if_name; -} - -METHOD(tun_device_t, write_packet, bool, - private_tun_device_t *this, chunk_t packet) -{ - ssize_t s; - - s = write(this->tunfd, packet.ptr, packet.len); - if (s < 0) - { - DBG1(DBG_LIB, "failed to write packet to TUN device %s: %s", - this->if_name, strerror(errno)); - return FALSE; - } - else if (s != packet.len) - { - return FALSE; - } - return TRUE; -} - -METHOD(tun_device_t, read_packet, bool, - private_tun_device_t *this, chunk_t *packet) -{ - ssize_t len; - fd_set set; - bool old; - - FD_ZERO(&set); - FD_SET(this->tunfd, &set); - - old = thread_cancelability(TRUE); - len = select(this->tunfd + 1, &set, NULL, NULL, NULL); - thread_cancelability(old); - - if (len < 0) - { - DBG1(DBG_LIB, "select on TUN device %s failed: %s", this->if_name, - strerror(errno)); - return FALSE; - } - /* FIXME: this is quite expensive for lots of small packets, copy from - * local buffer instead? */ - *packet = chunk_alloc(get_mtu(this)); - len = read(this->tunfd, packet->ptr, packet->len); - if (len < 0) - { - DBG1(DBG_LIB, "reading from TUN device %s failed: %s", this->if_name, - strerror(errno)); - chunk_free(packet); - return FALSE; - } - packet->len = len; - return TRUE; -} - -METHOD(tun_device_t, destroy, void, - private_tun_device_t *this) -{ - if (this->tunfd > 0) - { - close(this->tunfd); -#ifdef __FreeBSD__ - /* tun(4) says the following: "These network interfaces persist until - * the if_tun.ko module is unloaded, or until removed with the - * ifconfig(8) command." So simply closing the FD is not enough. */ - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ); - if (ioctl(this->sock, SIOCIFDESTROY, &ifr) < 0) - { - DBG1(DBG_LIB, "failed to destroy %s: %s", this->if_name, - strerror(errno)); - } -#endif /* __FreeBSD__ */ - } - if (this->sock > 0) - { - close(this->sock); - } - free(this); -} - -/** - * Initialize the tun device - */ -static bool init_tun(private_tun_device_t *this, const char *name_tmpl) -{ -#ifdef __APPLE__ - - struct ctl_info info; - struct sockaddr_ctl addr; - socklen_t size = IFNAMSIZ; - - memset(&info, 0, sizeof(info)); - memset(&addr, 0, sizeof(addr)); - - this->tunfd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); - if (this->tunfd < 0) - { - DBG1(DBG_LIB, "failed to open tundevice PF_SYSTEM socket: %s", - strerror(errno)); - return FALSE; - } - - /* get a control identifier for the utun kernel extension */ - strncpy(info.ctl_name, UTUN_CONTROL_NAME, strlen(UTUN_CONTROL_NAME)); - if (ioctl(this->tunfd, CTLIOCGINFO, &info) < 0) - { - DBG1(DBG_LIB, "failed to ioctl tundevice: %s", strerror(errno)); - close(this->tunfd); - return FALSE; - } - - addr.sc_id = info.ctl_id; - addr.sc_len = sizeof(addr); - addr.sc_family = AF_SYSTEM; - addr.ss_sysaddr = AF_SYS_CONTROL; - /* allocate identifier dynamically */ - addr.sc_unit = 0; - - if (connect(this->tunfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) - { - DBG1(DBG_LIB, "failed to connect tundevice: %s", strerror(errno)); - close(this->tunfd); - return FALSE; - } - if (getsockopt(this->tunfd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, - this->if_name, &size) < 0) - { - DBG1(DBG_LIB, "getting tundevice name failed: %s", strerror(errno)); - close(this->tunfd); - return FALSE; - } - return TRUE; - -#elif defined(IFF_TUN) - - struct ifreq ifr; - - strncpy(this->if_name, name_tmpl ?: "tun%d", IFNAMSIZ); - this->if_name[IFNAMSIZ-1] = '\0'; - - this->tunfd = open("/dev/net/tun", O_RDWR); - if (this->tunfd < 0) - { - DBG1(DBG_LIB, "failed to open /dev/net/tun: %s", strerror(errno)); - return FALSE; - } - - memset(&ifr, 0, sizeof(ifr)); - - /* TUN device, no packet info */ - ifr.ifr_flags = IFF_TUN | IFF_NO_PI; - - strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ); - if (ioctl(this->tunfd, TUNSETIFF, (void*)&ifr) < 0) - { - DBG1(DBG_LIB, "failed to configure TUN device: %s", strerror(errno)); - close(this->tunfd); - return FALSE; - } - strncpy(this->if_name, ifr.ifr_name, IFNAMSIZ); - return TRUE; - -#else /* !IFF_TUN */ - - /* this works on FreeBSD and might also work on Linux with older TUN - * driver versions (no IFF_TUN) */ - char devname[IFNAMSIZ]; - int i; - - if (name_tmpl) - { - DBG1(DBG_LIB, "arbitrary naming of TUN devices is not supported"); - } - - for (i = 0; i < 256; i++) - { - snprintf(devname, IFNAMSIZ, "/dev/tun%d", i); - this->tunfd = open(devname, O_RDWR); - if (this->tunfd > 0) - { /* for ioctl(2) calls only the interface name is used */ - snprintf(this->if_name, IFNAMSIZ, "tun%d", i); - break; - } - DBG1(DBG_LIB, "failed to open %s: %s", this->if_name, strerror(errno)); - } - return this->tunfd > 0; - -#endif /* !__APPLE__ */ -} - -/* - * Described in header - */ -tun_device_t *tun_device_create(const char *name_tmpl) -{ - private_tun_device_t *this; - - INIT(this, - .public = { - .read_packet = _read_packet, - .write_packet = _write_packet, - .get_mtu = _get_mtu, - .set_mtu = _set_mtu, - .get_name = _get_name, - .set_address = _set_address, - .up = _up, - .destroy = _destroy, - }, - .tunfd = -1, - .sock = -1, - ); - - if (!init_tun(this, name_tmpl)) - { - free(this); - return NULL; - } - DBG1(DBG_LIB, "created TUN device: %s", this->if_name); - - this->sock = socket(AF_INET, SOCK_DGRAM, 0); - if (this->sock < 0) - { - DBG1(DBG_LIB, "failed to open socket to configure TUN device"); - destroy(this); - return NULL; - } - return &this->public; -} diff --git a/src/libstrongswan/utils/tun_device.h b/src/libstrongswan/utils/tun_device.h deleted file mode 100644 index 71af0386b..000000000 --- a/src/libstrongswan/utils/tun_device.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2012 Tobias Brunner - * Copyright (C) 2012 Giuliano Grassi - * Copyright (C) 2012 Ralf Sager - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program 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 General Public License - * for more details. - */ - -/** - * @defgroup tun_device tun_device - * @{ @ingroup utils - */ - -#ifndef TUN_DEVICE_H_ -#define TUN_DEVICE_H_ - -#include <library.h> -#include <utils/host.h> - -typedef struct tun_device_t tun_device_t; - -/** - * Class to create TUN devices - * - * Creating such a device requires the CAP_NET_ADMIN capability. - * - * @note The implementation is currently very Linux specific - */ -struct tun_device_t { - - /** - * Read a packet from the TUN device - * - * @note This call blocks until a packet is available. It is a thread - * cancellation point. - * - * @param packet the packet read from the device - * @return TRUE if successful - */ - bool (*read_packet)(tun_device_t *this, chunk_t *packet); - - /** - * Write a packet to the TUN device - * - * @param packet the packet to write to the TUN device - * @return TRUE if successful - */ - bool (*write_packet)(tun_device_t *this, chunk_t packet); - - /** - * Set the IP address of the device - * - * @param addr the desired interface address - * @param netmask the netmask to use - * @return TRUE if operation successful - */ - bool (*set_address)(tun_device_t *this, host_t *addr, u_int8_t netmask); - - /** - * Bring the TUN device up - * - * @return TRUE if operation successful - */ - bool (*up)(tun_device_t *this); - - /** - * Set the MTU for this TUN device - * - * @param mtu new MTU - * @return TRUE if operation successful - */ - bool (*set_mtu)(tun_device_t *this, int mtu); - - /** - * Get the current MTU for this TUN device - * - * @return current MTU - */ - int (*get_mtu)(tun_device_t *this); - - /** - * Get the interface name of this device - * - * @return interface name - */ - char *(*get_name)(tun_device_t *this); - - /** - * Destroy a tun_device_t - */ - void (*destroy)(tun_device_t *this); - -}; - -/** - * Create a TUN device using the given name template. - * - * @param name_tmpl name template, defaults to "tun%d" if not given - * @return TUN device - */ -tun_device_t *tun_device_create(const char *name_tmpl); - -#endif /** TUN_DEVICE_H_ @}*/ diff --git a/src/libstrongswan/utils/utils.c b/src/libstrongswan/utils/utils.c new file mode 100644 index 000000000..bf0224c5f --- /dev/null +++ b/src/libstrongswan/utils/utils.c @@ -0,0 +1,570 @@ +/* + * Copyright (C) 2008-2012 Tobias Brunner + * Copyright (C) 2005-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program 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 General Public License + * for more details. + */ + +#include "utils.h" + +#include <sys/stat.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <inttypes.h> +#include <stdint.h> +#include <limits.h> +#include <dirent.h> +#include <time.h> +#include <pthread.h> + +#include "collections/enumerator.h" +#include "utils/debug.h" + +ENUM(status_names, SUCCESS, NEED_MORE, + "SUCCESS", + "FAILED", + "OUT_OF_RES", + "ALREADY_DONE", + "NOT_SUPPORTED", + "INVALID_ARG", + "NOT_FOUND", + "PARSE_ERROR", + "VERIFY_ERROR", + "INVALID_STATE", + "DESTROY_ME", + "NEED_MORE", +); + +/** + * Described in header. + */ +void *clalloc(void * pointer, size_t size) +{ + void *data; + data = malloc(size); + + memcpy(data, pointer, size); + + return (data); +} + +/** + * Described in header. + */ +void memxor(u_int8_t dst[], u_int8_t src[], size_t n) +{ + int m, i; + + /* byte wise XOR until dst aligned */ + for (i = 0; (uintptr_t)&dst[i] % sizeof(long) && i < n; i++) + { + dst[i] ^= src[i]; + } + /* try to use words if src shares an aligment with dst */ + switch (((uintptr_t)&src[i] % sizeof(long))) + { + case 0: + for (m = n - sizeof(long); i <= m; i += sizeof(long)) + { + *(long*)&dst[i] ^= *(long*)&src[i]; + } + break; + case sizeof(int): + for (m = n - sizeof(int); i <= m; i += sizeof(int)) + { + *(int*)&dst[i] ^= *(int*)&src[i]; + } + break; + case sizeof(short): + for (m = n - sizeof(short); i <= m; i += sizeof(short)) + { + *(short*)&dst[i] ^= *(short*)&src[i]; + } + break; + default: + break; + } + /* byte wise XOR of the rest */ + for (; i < n; i++) + { + dst[i] ^= src[i]; + } +} + +/** + * Described in header. + */ +void memwipe_noinline(void *ptr, size_t n) +{ + memwipe_inline(ptr, n); +} + +/** + * Described in header. + */ +void *memstr(const void *haystack, const char *needle, size_t n) +{ + unsigned const char *pos = haystack; + size_t l = strlen(needle); + for (; n >= l; ++pos, --n) + { + if (memeq(pos, needle, l)) + { + return (void*)pos; + } + } + return NULL; +} + +/** + * Described in header. + */ +char* translate(char *str, const char *from, const char *to) +{ + char *pos = str; + if (strlen(from) != strlen(to)) + { + return str; + } + while (pos && *pos) + { + char *match; + if ((match = strchr(from, *pos)) != NULL) + { + *pos = to[match - from]; + } + pos++; + } + return str; +} + +/** + * Described in header. + */ +bool mkdir_p(const char *path, mode_t mode) +{ + int len; + char *pos, full[PATH_MAX]; + pos = full; + if (!path || *path == '\0') + { + return TRUE; + } + len = snprintf(full, sizeof(full)-1, "%s", path); + if (len < 0 || len >= sizeof(full)-1) + { + DBG1(DBG_LIB, "path string %s too long", path); + return FALSE; + } + /* ensure that the path ends with a '/' */ + if (full[len-1] != '/') + { + full[len++] = '/'; + full[len] = '\0'; + } + /* skip '/' at the beginning */ + while (*pos == '/') + { + pos++; + } + while ((pos = strchr(pos, '/'))) + { + *pos = '\0'; + if (access(full, F_OK) < 0) + { + if (mkdir(full, mode) < 0) + { + DBG1(DBG_LIB, "failed to create directory %s", full); + return FALSE; + } + } + *pos = '/'; + pos++; + } + return TRUE; +} + + +/** + * The size of the thread-specific error buffer + */ +#define STRERROR_BUF_LEN 256 + +/** + * Key to store thread-specific error buffer + */ +static pthread_key_t strerror_buf_key; + +/** + * Only initialize the key above once + */ +static pthread_once_t strerror_buf_key_once = PTHREAD_ONCE_INIT; + +/** + * Create the key used for the thread-specific error buffer + */ +static void create_strerror_buf_key() +{ + pthread_key_create(&strerror_buf_key, free); +} + +/** + * Retrieve the error buffer assigned to the current thread (or create it) + */ +static inline char *get_strerror_buf() +{ + char *buf; + + pthread_once(&strerror_buf_key_once, create_strerror_buf_key); + buf = pthread_getspecific(strerror_buf_key); + if (!buf) + { + buf = malloc(STRERROR_BUF_LEN); + pthread_setspecific(strerror_buf_key, buf); + } + return buf; +} + +#ifdef HAVE_STRERROR_R +/* + * Described in header. + */ +const char *safe_strerror(int errnum) +{ + char *buf = get_strerror_buf(), *msg; + +#ifdef STRERROR_R_CHAR_P + /* char* version which may or may not return the original buffer */ + msg = strerror_r(errnum, buf, STRERROR_BUF_LEN); +#else + /* int version returns 0 on success */ + msg = strerror_r(errnum, buf, STRERROR_BUF_LEN) ? "Unknown error" : buf; +#endif + return msg; +} +#else /* HAVE_STRERROR_R */ +/* we actually wan't to call strerror(3) below */ +#undef strerror +/* + * Described in header. + */ +const char *safe_strerror(int errnum) +{ + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + char *buf = get_strerror_buf(); + + /* use a mutex to ensure calling strerror(3) is thread-safe */ + pthread_mutex_lock(&mutex); + strncpy(buf, strerror(errnum), STRERROR_BUF_LEN); + pthread_mutex_unlock(&mutex); + buf[STRERROR_BUF_LEN - 1] = '\0'; + return buf; +} +#endif /* HAVE_STRERROR_R */ + + +#ifndef HAVE_CLOSEFROM +/** + * Described in header. + */ +void closefrom(int lowfd) +{ + char fd_dir[PATH_MAX]; + int maxfd, fd, len; + + /* try to close only open file descriptors on Linux... */ + len = snprintf(fd_dir, sizeof(fd_dir), "/proc/%u/fd", getpid()); + if (len > 0 && len < sizeof(fd_dir) && access(fd_dir, F_OK) == 0) + { + enumerator_t *enumerator = enumerator_create_directory(fd_dir); + if (enumerator) + { + char *rel; + while (enumerator->enumerate(enumerator, &rel, NULL, NULL)) + { + fd = atoi(rel); + if (fd >= lowfd) + { + close(fd); + } + } + enumerator->destroy(enumerator); + return; + } + } + + /* ...fall back to closing all fds otherwise */ + maxfd = (int)sysconf(_SC_OPEN_MAX); + if (maxfd < 0) + { + maxfd = 256; + } + for (fd = lowfd; fd < maxfd; fd++) + { + close(fd); + } +} +#endif /* HAVE_CLOSEFROM */ + +/** + * Return monotonic time + */ +time_t time_monotonic(timeval_t *tv) +{ +#if defined(HAVE_CLOCK_GETTIME) && \ + (defined(HAVE_CONDATTR_CLOCK_MONOTONIC) || \ + defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)) + /* as we use time_monotonic() for condvar operations, we use the + * monotonic time source only if it is also supported by pthread. */ + timespec_t ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + { + if (tv) + { + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / 1000; + } + return ts.tv_sec; + } +#endif /* HAVE_CLOCK_GETTIME && (...) */ + /* Fallback to non-monotonic timestamps: + * On MAC OS X, creating monotonic timestamps is rather difficult. We + * could use mach_absolute_time() and catch sleep/wakeup notifications. + * We stick to the simpler (non-monotonic) gettimeofday() for now. + * But keep in mind: we need the same time source here as in condvar! */ + if (!tv) + { + return time(NULL); + } + if (gettimeofday(tv, NULL) != 0) + { /* should actually never fail if passed pointers are valid */ + return -1; + } + return tv->tv_sec; +} + +/** + * return null + */ +void *return_null() +{ + return NULL; +} + +/** + * returns TRUE + */ +bool return_true() +{ + return TRUE; +} + +/** + * returns FALSE + */ +bool return_false() +{ + return FALSE; +} + +/** + * returns FAILED + */ +status_t return_failed() +{ + return FAILED; +} + +/** + * nop operation + */ +void nop() +{ +} + +#ifndef HAVE_GCC_ATOMIC_OPERATIONS + +/** + * We use a single mutex for all refcount variables. + */ +static pthread_mutex_t ref_mutex = PTHREAD_MUTEX_INITIALIZER; + +/** + * Increase refcount + */ +void ref_get(refcount_t *ref) +{ + pthread_mutex_lock(&ref_mutex); + (*ref)++; + pthread_mutex_unlock(&ref_mutex); +} + +/** + * Decrease refcount + */ +bool ref_put(refcount_t *ref) +{ + bool more_refs; + + pthread_mutex_lock(&ref_mutex); + more_refs = --(*ref) > 0; + pthread_mutex_unlock(&ref_mutex); + return !more_refs; +} + +/** + * Single mutex for all compare and swap operations. + */ +static pthread_mutex_t cas_mutex = PTHREAD_MUTEX_INITIALIZER; + +/** + * Compare and swap if equal to old value + */ +#define _cas_impl(name, type) \ +bool cas_##name(type *ptr, type oldval, type newval) \ +{ \ + bool swapped; \ + pthread_mutex_lock(&cas_mutex); \ + if ((swapped = (*ptr == oldval))) { *ptr = newval; } \ + pthread_mutex_unlock(&cas_mutex); \ + return swapped; \ +} + +_cas_impl(bool, bool) +_cas_impl(ptr, void*) + +#endif /* HAVE_GCC_ATOMIC_OPERATIONS */ + +/** + * Described in header. + */ +int time_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, + const void *const *args) +{ + static const char* months[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + time_t *time = *((time_t**)(args[0])); + bool utc = *((bool*)(args[1]));; + struct tm t; + + if (time == UNDEFINED_TIME) + { + return print_in_hook(data, "--- -- --:--:--%s----", + utc ? " UTC " : " "); + } + if (utc) + { + gmtime_r(time, &t); + } + else + { + localtime_r(time, &t); + } + return print_in_hook(data, "%s %02d %02d:%02d:%02d%s%04d", + months[t.tm_mon], t.tm_mday, t.tm_hour, t.tm_min, + t.tm_sec, utc ? " UTC " : " ", t.tm_year + 1900); +} + +/** + * Described in header. + */ +int time_delta_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, + const void *const *args) +{ + char* unit = "second"; + time_t *arg1 = *((time_t**)(args[0])); + time_t *arg2 = *((time_t**)(args[1])); + u_int64_t delta = llabs(*arg1 - *arg2); + + if (delta > 2 * 60 * 60 * 24) + { + delta /= 60 * 60 * 24; + unit = "day"; + } + else if (delta > 2 * 60 * 60) + { + delta /= 60 * 60; + unit = "hour"; + } + else if (delta > 2 * 60) + { + delta /= 60; + unit = "minute"; + } + return print_in_hook(data, "%" PRIu64 " %s%s", delta, unit, + (delta == 1) ? "" : "s"); +} + +/** + * Number of bytes per line to dump raw data + */ +#define BYTES_PER_LINE 16 + +static char hexdig_upper[] = "0123456789ABCDEF"; + +/** + * Described in header. + */ +int mem_printf_hook(printf_hook_data_t *data, + printf_hook_spec_t *spec, const void *const *args) +{ + char *bytes = *((void**)(args[0])); + u_int len = *((int*)(args[1])); + + char buffer[BYTES_PER_LINE * 3]; + char ascii_buffer[BYTES_PER_LINE + 1]; + char *buffer_pos = buffer; + char *bytes_pos = bytes; + char *bytes_roof = bytes + len; + int line_start = 0; + int i = 0; + int written = 0; + + written += print_in_hook(data, "=> %u bytes @ %p", len, bytes); + + while (bytes_pos < bytes_roof) + { + *buffer_pos++ = hexdig_upper[(*bytes_pos >> 4) & 0xF]; + *buffer_pos++ = hexdig_upper[ *bytes_pos & 0xF]; + + ascii_buffer[i++] = + (*bytes_pos > 31 && *bytes_pos < 127) ? *bytes_pos : '.'; + + if (++bytes_pos == bytes_roof || i == BYTES_PER_LINE) + { + int padding = 3 * (BYTES_PER_LINE - i); + + while (padding--) + { + *buffer_pos++ = ' '; + } + *buffer_pos++ = '\0'; + ascii_buffer[i] = '\0'; + + written += print_in_hook(data, "\n%4d: %s %s", + line_start, buffer, ascii_buffer); + + buffer_pos = buffer; + line_start += BYTES_PER_LINE; + i = 0; + } + else + { + *buffer_pos++ = ' '; + } + } + return written; +} diff --git a/src/libstrongswan/utils/utils.h b/src/libstrongswan/utils/utils.h new file mode 100644 index 000000000..7b1beb93a --- /dev/null +++ b/src/libstrongswan/utils/utils.h @@ -0,0 +1,699 @@ +/* + * Copyright (C) 2008-2012 Tobias Brunner + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program 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 General Public License + * for more details. + */ + +/** + * @defgroup utils_i utils + * @{ @ingroup utils + */ + +#ifndef UTILS_H_ +#define UTILS_H_ + +#include <sys/types.h> +#include <stdlib.h> +#include <stddef.h> +#include <sys/time.h> +#include <arpa/inet.h> +#include <string.h> + +#include "enum.h" + +/** + * strongSwan program return codes + */ +#define SS_RC_LIBSTRONGSWAN_INTEGRITY 64 +#define SS_RC_DAEMON_INTEGRITY 65 +#define SS_RC_INITIALIZATION_FAILED 66 + +#define SS_RC_FIRST SS_RC_LIBSTRONGSWAN_INTEGRITY +#define SS_RC_LAST SS_RC_INITIALIZATION_FAILED + +/** + * Number of bits in a byte + */ +#define BITS_PER_BYTE 8 + +/** + * Default length for various auxiliary text buffers + */ +#define BUF_LEN 512 + +/** + * General purpose boolean type. + */ +#ifdef HAVE_STDBOOL_H +# include <stdbool.h> +#else +# ifndef HAVE__BOOL +# define _Bool signed char +# endif /* HAVE__BOOL */ +# define bool _Bool +# define false 0 +# define true 1 +# define __bool_true_false_are_defined 1 +#endif /* HAVE_STDBOOL_H */ +#ifndef FALSE +# define FALSE false +#endif /* FALSE */ +#ifndef TRUE +# define TRUE true +#endif /* TRUE */ + +/** + * Helper function that compares two strings for equality + */ +static inline bool streq(const char *x, const char *y) +{ + return strcmp(x, y) == 0; +} + +/** + * Macro compares two strings for equality, length limited + */ +#define strneq(x,y,len) (strncmp(x, y, len) == 0) + +/** + * Helper function that compares two strings for equality ignoring case + */ +static inline bool strcaseeq(const char *x, const char *y) +{ + return strcasecmp(x, y) == 0; +} + +/** + * Macro compares two strings for equality ignoring case, length limited + */ +#define strncaseeq(x,y,len) (strncasecmp(x, y, len) == 0) + +/** + * NULL-safe strdup variant + */ +static inline char *strdupnull(const char *s) +{ + return s ? strdup(s) : NULL; +} + +/** + * Macro compares two binary blobs for equality + */ +#define memeq(x,y,len) (memcmp(x, y, len) == 0) + +/** + * Macro gives back larger of two values. + */ +#define max(x,y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + _x > _y ? _x : _y; }) + + +/** + * Macro gives back smaller of two values. + */ +#define min(x,y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + _x < _y ? _x : _y; }) + +/** + * Call destructor of an object, if object != NULL + */ +#define DESTROY_IF(obj) if (obj) (obj)->destroy(obj) + +/** + * Call offset destructor of an object, if object != NULL + */ +#define DESTROY_OFFSET_IF(obj, offset) if (obj) obj->destroy_offset(obj, offset); + +/** + * Call function destructor of an object, if object != NULL + */ +#define DESTROY_FUNCTION_IF(obj, fn) if (obj) obj->destroy_function(obj, fn); + +/** + * Debug macro to follow control flow + */ +#define POS printf("%s, line %d\n", __FILE__, __LINE__) + +/** + * Object allocation/initialization macro, using designated initializer. + */ +#define INIT(this, ...) { (this) = malloc(sizeof(*(this))); \ + *(this) = (typeof(*(this))){ __VA_ARGS__ }; } + +/** + * Method declaration/definition macro, providing private and public interface. + * + * Defines a method name with this as first parameter and a return value ret, + * and an alias for this method with a _ prefix, having the this argument + * safely casted to the public interface iface. + * _name is provided a function pointer, but will get optimized out by GCC. + */ +#define METHOD(iface, name, ret, this, ...) \ + static ret name(union {iface *_public; this;} \ + __attribute__((transparent_union)), ##__VA_ARGS__); \ + static typeof(name) *_##name = (typeof(name)*)name; \ + static ret name(this, ##__VA_ARGS__) + +/** + * Same as METHOD(), but is defined for two public interfaces. + */ +#define METHOD2(iface1, iface2, name, ret, this, ...) \ + static ret name(union {iface1 *_public1; iface2 *_public2; this;} \ + __attribute__((transparent_union)), ##__VA_ARGS__); \ + static typeof(name) *_##name = (typeof(name)*)name; \ + static ret name(this, ##__VA_ARGS__) + +/** + * Architecture independent bitfield definition helpers (at least with GCC). + * + * Defines a bitfield with a type t and a fixed size of bitfield members, e.g.: + * BITFIELD2(u_int8_t, + * low: 4, + * high: 4, + * ) flags; + * The member defined first placed at bit 0. + */ +#if BYTE_ORDER == LITTLE_ENDIAN +#define BITFIELD2(t, a, b,...) struct { t a; t b; __VA_ARGS__} +#define BITFIELD3(t, a, b, c,...) struct { t a; t b; t c; __VA_ARGS__} +#define BITFIELD4(t, a, b, c, d,...) struct { t a; t b; t c; t d; __VA_ARGS__} +#define BITFIELD5(t, a, b, c, d, e,...) struct { t a; t b; t c; t d; t e; __VA_ARGS__} +#elif BYTE_ORDER == BIG_ENDIAN +#define BITFIELD2(t, a, b,...) struct { t b; t a; __VA_ARGS__} +#define BITFIELD3(t, a, b, c,...) struct { t c; t b; t a; __VA_ARGS__} +#define BITFIELD4(t, a, b, c, d,...) struct { t d; t c; t b; t a; __VA_ARGS__} +#define BITFIELD5(t, a, b, c, d, e,...) struct { t e; t d; t c; t b; t a; __VA_ARGS__} +#endif + +/** + * Macro to allocate a sized type. + */ +#define malloc_thing(thing) ((thing*)malloc(sizeof(thing))) + +/** + * Get the number of elements in an array + */ +#define countof(array) (sizeof(array)/sizeof(array[0])) + +/** + * Ignore result of functions tagged with warn_unused_result attributes + */ +#define ignore_result(call) { if(call){}; } + +/** + * Assign a function as a class method + */ +#define ASSIGN(method, function) (method = (typeof(method))function) + +/** + * time_t not defined + */ +#define UNDEFINED_TIME 0 + +/** + * Maximum time since epoch causing wrap-around on Jan 19 03:14:07 UTC 2038 + */ +#define TIME_32_BIT_SIGNED_MAX 0x7fffffff + +/** + * define some missing fixed width int types on OpenSolaris. + * TODO: since the uintXX_t types are defined by the C99 standard we should + * probably use those anyway + */ +#ifdef __sun + #include <stdint.h> + typedef uint8_t u_int8_t; + typedef uint16_t u_int16_t; + typedef uint32_t u_int32_t; + typedef uint64_t u_int64_t; +#endif + +typedef enum status_t status_t; + +/** + * Return values of function calls. + */ +enum status_t { + /** + * Call succeeded. + */ + SUCCESS, + + /** + * Call failed. + */ + FAILED, + + /** + * Out of resources. + */ + OUT_OF_RES, + + /** + * The suggested operation is already done + */ + ALREADY_DONE, + + /** + * Not supported. + */ + NOT_SUPPORTED, + + /** + * One of the arguments is invalid. + */ + INVALID_ARG, + + /** + * Something could not be found. + */ + NOT_FOUND, + + /** + * Error while parsing. + */ + PARSE_ERROR, + + /** + * Error while verifying. + */ + VERIFY_ERROR, + + /** + * Object in invalid state. + */ + INVALID_STATE, + + /** + * Destroy object which called method belongs to. + */ + DESTROY_ME, + + /** + * Another call to the method is required. + */ + NEED_MORE, +}; + +/** + * enum_names for type status_t. + */ +extern enum_name_t *status_names; + +/** + * deprecated pluto style return value: + * error message, NULL for success + */ +typedef const char *err_t; + +/** + * Handle struct timeval like an own type. + */ +typedef struct timeval timeval_t; + +/** + * Handle struct timespec like an own type. + */ +typedef struct timespec timespec_t; + +/** + * Handle struct chunk_t like an own type. + */ +typedef struct sockaddr sockaddr_t; + +/** + * Clone a data to a newly allocated buffer + */ +void *clalloc(void *pointer, size_t size); + +/** + * Same as memcpy, but XORs src into dst instead of copy + */ +void memxor(u_int8_t dest[], u_int8_t src[], size_t n); + +/** + * Safely overwrite n bytes of memory at ptr with zero, non-inlining variant. + */ +void memwipe_noinline(void *ptr, size_t n); + +/** + * Safely overwrite n bytes of memory at ptr with zero, inlining variant. + */ +static inline void memwipe_inline(void *ptr, size_t n) +{ + volatile char *c = (volatile char*)ptr; + size_t m, i; + + /* byte wise until long aligned */ + for (i = 0; (uintptr_t)&c[i] % sizeof(long) && i < n; i++) + { + c[i] = 0; + } + /* word wise */ + if (n >= sizeof(long)) + { + for (m = n - sizeof(long); i <= m; i += sizeof(long)) + { + *(volatile long*)&c[i] = 0; + } + } + /* byte wise of the rest */ + for (; i < n; i++) + { + c[i] = 0; + } +} + +/** + * Safely overwrite n bytes of memory at ptr with zero, auto-inlining variant. + */ +static inline void memwipe(void *ptr, size_t n) +{ + if (__builtin_constant_p(n)) + { + memwipe_inline(ptr, n); + } + else + { + memwipe_noinline(ptr, n); + } +} + +/** + * A variant of strstr with the characteristics of memchr, where haystack is not + * a null-terminated string but simply a memory area of length n. + */ +void *memstr(const void *haystack, const char *needle, size_t n); + +/** + * Translates the characters in the given string, searching for characters + * in 'from' and mapping them to characters in 'to'. + * The two characters sets 'from' and 'to' must contain the same number of + * characters. + */ +char *translate(char *str, const char *from, const char *to); + +/** + * Creates a directory and all required parent directories. + * + * @param path path to the new directory + * @param mode permissions of the new directory/directories + * @return TRUE on success + */ +bool mkdir_p(const char *path, mode_t mode); + +/** + * Thread-safe wrapper around strerror and strerror_r. + * + * This is required because the first is not thread-safe (on some platforms) + * and the second uses two different signatures (POSIX/GNU) and is impractical + * to use anyway. + * + * @param errnum error code (i.e. errno) + * @return error message + */ +const char *safe_strerror(int errnum); + +/** + * Replace usages of strerror(3) with thread-safe variant. + */ +#define strerror(errnum) safe_strerror(errnum) + +#ifndef HAVE_CLOSEFROM +/** + * Close open file descriptors greater than or equal to lowfd. + * + * @param lowfd start closing file descriptoros from here + */ +void closefrom(int lowfd); +#endif + +/** + * Get a timestamp from a monotonic time source. + * + * While the time()/gettimeofday() functions are affected by leap seconds + * and system time changes, this function returns ever increasing monotonic + * time stamps. + * + * @param tv timeval struct receiving monotonic timestamps, or NULL + * @return monotonic timestamp in seconds + */ +time_t time_monotonic(timeval_t *tv); + +/** + * Add the given number of milliseconds to the given timeval struct + * + * @param tv timeval struct to modify + * @param ms number of milliseconds + */ +static inline void timeval_add_ms(timeval_t *tv, u_int ms) +{ + tv->tv_usec += ms * 1000; + while (tv->tv_usec > 1000000 /* 1s */) + { + tv->tv_usec -= 1000000; + tv->tv_sec++; + } +} + +/** + * returns null + */ +void *return_null(); + +/** + * No-Operation function + */ +void nop(); + +/** + * returns TRUE + */ +bool return_true(); + +/** + * returns FALSE + */ +bool return_false(); + +/** + * returns FAILED + */ +status_t return_failed(); + +/** + * Write a 16-bit host order value in network order to an unaligned address. + * + * @param host host order 16-bit value + * @param network unaligned address to write network order value to + */ +static inline void htoun16(void *network, u_int16_t host) +{ + char *unaligned = (char*)network; + + host = htons(host); + memcpy(unaligned, &host, sizeof(host)); +} + +/** + * Write a 32-bit host order value in network order to an unaligned address. + * + * @param host host order 32-bit value + * @param network unaligned address to write network order value to + */ +static inline void htoun32(void *network, u_int32_t host) +{ + char *unaligned = (char*)network; + + host = htonl(host); + memcpy((char*)unaligned, &host, sizeof(host)); +} + +/** + * Write a 64-bit host order value in network order to an unaligned address. + * + * @param host host order 64-bit value + * @param network unaligned address to write network order value to + */ +static inline void htoun64(void *network, u_int64_t host) +{ + char *unaligned = (char*)network; + +#ifdef be64toh + host = htobe64(host); + memcpy((char*)unaligned, &host, sizeof(host)); +#else + u_int32_t high_part, low_part; + + high_part = host >> 32; + high_part = htonl(high_part); + low_part = host & 0xFFFFFFFFLL; + low_part = htonl(low_part); + + memcpy(unaligned, &high_part, sizeof(high_part)); + unaligned += sizeof(high_part); + memcpy(unaligned, &low_part, sizeof(low_part)); +#endif +} + +/** + * Read a 16-bit value in network order from an unaligned address to host order. + * + * @param network unaligned address to read network order value from + * @return host order value + */ +static inline u_int16_t untoh16(void *network) +{ + char *unaligned = (char*)network; + u_int16_t tmp; + + memcpy(&tmp, unaligned, sizeof(tmp)); + return ntohs(tmp); +} + +/** + * Read a 32-bit value in network order from an unaligned address to host order. + * + * @param network unaligned address to read network order value from + * @return host order value + */ +static inline u_int32_t untoh32(void *network) +{ + char *unaligned = (char*)network; + u_int32_t tmp; + + memcpy(&tmp, unaligned, sizeof(tmp)); + return ntohl(tmp); +} + +/** + * Read a 64-bit value in network order from an unaligned address to host order. + * + * @param network unaligned address to read network order value from + * @return host order value + */ +static inline u_int64_t untoh64(void *network) +{ + char *unaligned = (char*)network; + +#ifdef be64toh + u_int64_t tmp; + + memcpy(&tmp, unaligned, sizeof(tmp)); + return be64toh(tmp); +#else + u_int32_t high_part, low_part; + + memcpy(&high_part, unaligned, sizeof(high_part)); + unaligned += sizeof(high_part); + memcpy(&low_part, unaligned, sizeof(low_part)); + + high_part = ntohl(high_part); + low_part = ntohl(low_part); + + return (((u_int64_t)high_part) << 32) + low_part; +#endif +} + +/** + * Special type to count references + */ +typedef volatile u_int refcount_t; + + +#ifdef HAVE_GCC_ATOMIC_OPERATIONS + +#define ref_get(ref) {__sync_fetch_and_add(ref, 1); } +#define ref_put(ref) (!__sync_sub_and_fetch(ref, 1)) + +#define cas_bool(ptr, oldval, newval) \ + (__sync_bool_compare_and_swap(ptr, oldval, newval)) +#define cas_ptr(ptr, oldval, newval) \ + (__sync_bool_compare_and_swap(ptr, oldval, newval)) + +#else /* !HAVE_GCC_ATOMIC_OPERATIONS */ + +/** + * Get a new reference. + * + * Increments the reference counter atomic. + * + * @param ref pointer to ref counter + */ +void ref_get(refcount_t *ref); + +/** + * Put back a unused reference. + * + * Decrements the reference counter atomic and + * says if more references available. + * + * @param ref pointer to ref counter + * @return TRUE if no more references counted + */ +bool ref_put(refcount_t *ref); + +/** + * Atomically replace value of ptr with newval if it currently equals oldval. + * + * @param ptr pointer to variable + * @param oldval old value of the variable + * @param newval new value set if possible + * @return TRUE if value equaled oldval and newval was written + */ +bool cas_bool(bool *ptr, bool oldval, bool newval); + +/** + * Atomically replace value of ptr with newval if it currently equals oldval. + * + * @param ptr pointer to variable + * @param oldval old value of the variable + * @param newval new value set if possible + * @return TRUE if value equaled oldval and newval was written + */ +bool cas_ptr(void **ptr, void *oldval, void *newval); + +#endif /* HAVE_GCC_ATOMIC_OPERATIONS */ + +/** + * printf hook for time_t. + * + * Arguments are: + * time_t* time, bool utc + */ +int time_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, + const void *const *args); + +/** + * printf hook for time_t deltas. + * + * Arguments are: + * time_t* begin, time_t* end + */ +int time_delta_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, + const void *const *args); + +/** + * printf hook for memory areas. + * + * Arguments are: + * u_char *ptr, u_int len + */ +int mem_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, + const void *const *args); + +#endif /** UTILS_H_ @}*/ |