summaryrefslogtreecommitdiff
path: root/src/libstrongswan/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/utils')
-rw-r--r--src/libstrongswan/utils/chunk.c2
-rw-r--r--src/libstrongswan/utils/compat/apple.h119
-rw-r--r--src/libstrongswan/utils/compat/windows.c (renamed from src/libstrongswan/utils/windows.c)45
-rw-r--r--src/libstrongswan/utils/compat/windows.h (renamed from src/libstrongswan/utils/windows.h)45
-rw-r--r--src/libstrongswan/utils/enum.c93
-rw-r--r--src/libstrongswan/utils/enum.h35
-rw-r--r--src/libstrongswan/utils/identification.c87
-rw-r--r--src/libstrongswan/utils/identification.h9
-rw-r--r--src/libstrongswan/utils/utils.h6
9 files changed, 431 insertions, 10 deletions
diff --git a/src/libstrongswan/utils/chunk.c b/src/libstrongswan/utils/chunk.c
index 4b24b37c2..c4471be70 100644
--- a/src/libstrongswan/utils/chunk.c
+++ b/src/libstrongswan/utils/chunk.c
@@ -992,7 +992,7 @@ u_int32_t chunk_hash_static(chunk_t chunk)
*/
u_int16_t chunk_internet_checksum_inc(chunk_t data, u_int16_t checksum)
{
- u_int32_t sum = ntohs(~checksum);
+ u_int32_t sum = ntohs((u_int16_t)~checksum);
while (data.len > 1)
{
diff --git a/src/libstrongswan/utils/compat/apple.h b/src/libstrongswan/utils/compat/apple.h
new file mode 100644
index 000000000..61afb9d9e
--- /dev/null
+++ b/src/libstrongswan/utils/compat/apple.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * 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 apple apple
+ * @{ @ingroup compat
+ */
+
+#ifndef APPLE_H_
+#define APPLE_H_
+
+#include <poll.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+
+/* thread_create is a syscall used to create Mach kernel threads and although
+ * there are no errors or warnings during compilation or linkage the dynamic
+ * linker does not use our implementation, therefore we rename it here
+ */
+#define thread_create(main, arg) strongswan_thread_create(main, arg)
+
+/* Mach uses a semaphore_create() call, use a different name for ours */
+#define semaphore_create(x) strongswan_semaphore_create(x)
+
+/* Since OS X 10.10 XPC includes some additional conflicting Mach types */
+#define host_t strongswan_host_t
+#define processor_t strongswan_processor_t
+#define task_t strongswan_task_t
+#define thread_t strongswan_thread_t
+
+/* forward declaration, see below */
+static inline int precancellable_poll(struct pollfd fds[], nfds_t nfds,
+ int timeout);
+
+/* on Mac OS X 10.5 several system calls we use are no cancellation points.
+ * fortunately, select isn't one of them, so we wrap some of the others with
+ * calls to select(2).
+ */
+
+#define WRAP_WITH_POLL(func, socket, ...) \
+ struct pollfd pfd = { \
+ .fd = socket, \
+ .events = POLLIN, \
+ }; \
+ if (precancellable_poll(&pfd, 1, -1) <= 0) \
+ {\
+ return -1; \
+ }\
+ return func(socket, __VA_ARGS__)
+
+static inline int cancellable_accept(int socket, struct sockaddr *address,
+ socklen_t *address_len)
+{
+ WRAP_WITH_POLL(accept, socket, address, address_len);
+}
+#define accept cancellable_accept
+static inline int cancellable_recvfrom(int socket, void *buffer, size_t length,
+ int flags, struct sockaddr *address, socklen_t *address_len)
+{
+ WRAP_WITH_POLL(recvfrom, socket, buffer, length, flags, address, address_len);
+}
+#define recvfrom cancellable_recvfrom
+
+#include <threading/thread.h>
+
+/*
+ * While select() is a cancellation point, it seems that OS X does not honor
+ * pending cancellation points when entering the function. We manually test for
+ * and honor pending cancellation requests, but this obviously can't prevent
+ * some race conditions where the the cancellation happens after the check,
+ * but before the select.
+ */
+static inline int precancellable_select(int nfds, fd_set *restrict readfds,
+ fd_set *restrict writefds, fd_set *restrict errorfds,
+ struct timeval *restrict timeout)
+{
+ if (thread_cancelability(TRUE))
+ {
+ thread_cancellation_point();
+ }
+ else
+ {
+ thread_cancelability(FALSE);
+ }
+ return select(nfds, readfds, writefds, errorfds, timeout);
+}
+#define select precancellable_select
+
+/*
+ * The same as to select(2) applies to poll(2)
+ */
+static inline int precancellable_poll(struct pollfd fds[], nfds_t nfds,
+ int timeout)
+{
+ if (thread_cancelability(TRUE))
+ {
+ thread_cancellation_point();
+ }
+ else
+ {
+ thread_cancelability(FALSE);
+ }
+ return poll(fds, nfds, timeout);
+}
+#define poll precancellable_poll
+
+#endif /** APPLE_H_ @}*/
diff --git a/src/libstrongswan/utils/windows.c b/src/libstrongswan/utils/compat/windows.c
index 8820287b1..1f22ffa02 100644
--- a/src/libstrongswan/utils/windows.c
+++ b/src/libstrongswan/utils/compat/windows.c
@@ -13,7 +13,10 @@
* for more details.
*/
-#include "utils.h"
+/* WSAPoll() */
+#define _WIN32_WINNT 0x0600
+
+#include <utils/utils.h>
#include <errno.h>
@@ -639,3 +642,43 @@ ssize_t windows_sendto(int sockfd, const void *buf, size_t len, int flags,
}
return outlen;
}
+
+/**
+ * See header
+ */
+#undef read
+ssize_t windows_read(int fd, void *buf, size_t count)
+{
+ ssize_t ret;
+
+ ret = wserr(recv(fd, buf, count, 0));
+ if (ret == -1 && errno == ENOTSOCK)
+ {
+ ret = read(fd, buf, count);
+ }
+ return ret;
+}
+
+/**
+ * See header
+ */
+#undef write
+ssize_t windows_write(int fd, void *buf, size_t count)
+{
+ ssize_t ret;
+
+ ret = wserr(send(fd, buf, count, 0));
+ if (ret == -1 && errno == ENOTSOCK)
+ {
+ ret = write(fd, buf, count);
+ }
+ return ret;
+}
+
+/**
+ * See header
+ */
+int poll(struct pollfd *fds, int nfds, int timeout)
+{
+ return wserr(WSAPoll(fds, nfds, timeout));
+}
diff --git a/src/libstrongswan/utils/windows.h b/src/libstrongswan/utils/compat/windows.h
index 3761e10ab..fd4f1f196 100644
--- a/src/libstrongswan/utils/windows.h
+++ b/src/libstrongswan/utils/compat/windows.h
@@ -15,7 +15,7 @@
/**
* @defgroup windows windows
- * @{ @ingroup utils
+ * @{ @ingroup compat
*/
#ifndef WINDOWS_H_
@@ -363,6 +363,49 @@ ssize_t windows_sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
/**
+ * read(2) working on files and sockets, cancellable on sockets only
+ *
+ * On Windows, there does not seem to be a way how a cancellable read can
+ * be implemented on Low level I/O functions for files, _pipe()s or stdio.
+ */
+#define read windows_read
+ssize_t windows_read(int fd, void *buf, size_t count);
+
+/**
+ * write(2) working on files and sockets
+ */
+#define write windows_write
+ssize_t windows_write(int fd, void *buf, size_t count);
+
+#if _WIN32_WINNT < 0x0600
+/**
+ * Define pollfd and flags on our own if not specified
+ */
+struct pollfd {
+ SOCKET fd;
+ short events;
+ short revents;
+};
+enum {
+ POLLERR = 0x0001,
+ POLLHUP = 0x0002,
+ POLLNVAL = 0x0004,
+ POLLWRNORM = 0x0010,
+ POLLWRBAND = 0x0020,
+ POLLPRI = 0x0400,
+ POLLRDNORM = 0x0100,
+ POLLRDBAND = 0x0200,
+ POLLIN = POLLRDNORM | POLLRDBAND,
+ POLLOUT = POLLWRNORM,
+};
+#endif /* _WIN32_WINNT < 0x0600 */
+
+/**
+ * poll(2), implemented using Winsock2 WSAPoll()
+ */
+int poll(struct pollfd *fds, int nfds, int timeout);
+
+/**
* Declaration missing on older WinGW
*/
_CRTIMP errno_t strerror_s(char *buf, size_t size, int errnum);
diff --git a/src/libstrongswan/utils/enum.c b/src/libstrongswan/utils/enum.c
index f96fe2989..089bebb79 100644
--- a/src/libstrongswan/utils/enum.c
+++ b/src/libstrongswan/utils/enum.c
@@ -60,20 +60,103 @@ bool enum_from_name_as_int(enum_name_t *e, const char *name, int *val)
}
/**
+ * Get the position of a flag name using offset calculation
+ */
+static int find_flag_pos(u_int val, u_int first)
+{
+ int offset = 0;
+
+ while (val != 0x01)
+ {
+ val = val >> 1;
+ offset++;
+ }
+ return first - offset;
+}
+
+/**
* Described in header.
*/
+char *enum_flags_to_string(enum_name_t *e, u_int val, char *buf, size_t len)
+{
+ char *pos = buf, *delim = "";
+ int i, wr;
+
+ if (e->next != ENUM_FLAG_MAGIC)
+ {
+ if (snprintf(buf, len, "(%d)", (int)val) >= len)
+ {
+ return NULL;
+ }
+ return buf;
+ }
+
+ if (snprintf(buf, len, "(unset)") >= len)
+ {
+ return NULL;
+ }
+
+ for (i = 0; val; i++)
+ {
+ u_int flag = 1 << i;
+
+ if (val & flag)
+ {
+ char *name = NULL, hex[32];
+
+ if (flag >= (u_int)e->first && flag <= (u_int)e->last)
+ {
+ name = e->names[find_flag_pos(e->first, i)];
+ }
+ else
+ {
+ snprintf(hex, sizeof(hex), "(0x%X)", flag);
+ name = hex;
+ }
+ if (name)
+ {
+ wr = snprintf(pos, len, "%s%s", delim, name);
+ if (wr >= len)
+ {
+ return NULL;
+ }
+ len -= wr;
+ pos += wr;
+ delim = " | ";
+ }
+ val &= ~flag;
+ }
+ }
+ return buf;
+}
+
+/**
+ * See 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];
+ char *name, buf[512];
- name = enum_to_name(ed, val);
- if (name == NULL)
+ if (ed->next == ENUM_FLAG_MAGIC)
+ {
+ name = enum_flags_to_string(ed, val, buf, sizeof(buf));
+ if (name == NULL)
+ {
+ snprintf(buf, sizeof(buf), "(0x%X)", val);
+ name = buf;
+ }
+ }
+ else
{
- snprintf(buf, sizeof(buf), "(%d)", val);
- name = buf;
+ name = enum_to_name(ed, val);
+ if (name == NULL)
+ {
+ snprintf(buf, sizeof(buf), "(%d)", val);
+ name = buf;
+ }
}
if (spec->minus)
{
diff --git a/src/libstrongswan/utils/enum.h b/src/libstrongswan/utils/enum.h
index 3c03c2a7b..928f4079a 100644
--- a/src/libstrongswan/utils/enum.h
+++ b/src/libstrongswan/utils/enum.h
@@ -27,6 +27,11 @@
typedef struct enum_name_t enum_name_t;
/**
+ * Magic enum_name_t pointer indicating this is an enum name for flags
+ */
+#define ENUM_FLAG_MAGIC ((enum_name_t*)~(uintptr_t)0)
+
+/**
* Struct to store names for enums.
*
* To print the string representation of enumeration values, the strings
@@ -58,7 +63,7 @@ struct enum_name_t {
int first;
/** value of the last enum string */
int last;
- /** next enum_name_t in list */
+ /** next enum_name_t in list, or ENUM_FLAG_MAGIC */
enum_name_t *next;
/** array of strings containing names from first to last */
char *names[];
@@ -107,6 +112,23 @@ struct enum_name_t {
#define ENUM(name, first, last, ...) ENUM_BEGIN(name, first, last, __VA_ARGS__); ENUM_END(name, last)
/**
+ * Define a enum name with only one range for flags.
+ *
+ * Using an enum list for flags would be overkill. Hence we use a single
+ * range with all values in range. The next pointer is abused to mark
+ * that the enum name is for flags only. Use NULL if a particular flag
+ * is not meant to be printed.
+ *
+ * @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_FLAGS(name, first, last, ...) \
+ static enum_name_t name##last = {first, last, ENUM_FLAG_MAGIC, { __VA_ARGS__ }}; \
+ ENUM_END(name, last)
+
+/**
* Convert a enum value to its string representation.
*
* @param e enum names for this enum value
@@ -146,6 +168,17 @@ char *enum_to_name(enum_name_t *e, int val);
bool enum_from_name_as_int(enum_name_t *e, const char *name, int *val);
/**
+ * Convert a enum value containing flags to its string representation.
+ *
+ * @param e enum names for this enum value suitable for flags
+ * @param val enum value to get string for
+ * @param buf buffer to write flag string to
+ * @param len buffer size
+ * @return buf, NULL if buffer too small
+ */
+char *enum_flags_to_string(enum_name_t *e, u_int val, char *buf, size_t len);
+
+/**
* printf hook function for enum_names_t.
*
* Arguments are:
diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c
index 46ac7e890..b69adf399 100644
--- a/src/libstrongswan/utils/identification.c
+++ b/src/libstrongswan/utils/identification.c
@@ -17,6 +17,7 @@
#include <string.h>
#include <stdio.h>
+#include <errno.h>
#include "identification.h"
@@ -927,6 +928,82 @@ static private_identification_t *identification_create(id_type_t type)
return this;
}
+/**
+ * Create an identity for a specific type, determined by prefix
+ */
+static private_identification_t* create_from_string_with_prefix_type(char *str)
+{
+ struct {
+ const char *str;
+ id_type_t type;
+ } prefixes[] = {
+ { "ipv4:", ID_IPV4_ADDR },
+ { "ipv6:", ID_IPV6_ADDR },
+ { "rfc822:", ID_RFC822_ADDR },
+ { "email:", ID_RFC822_ADDR },
+ { "userfqdn:", ID_USER_FQDN },
+ { "fqdn:", ID_FQDN },
+ { "dns:", ID_FQDN },
+ { "asn1dn:", ID_DER_ASN1_DN },
+ { "asn1gn:", ID_DER_ASN1_GN },
+ { "keyid:", ID_KEY_ID },
+ };
+ private_identification_t *this;
+ int i;
+
+ for (i = 0; i < countof(prefixes); i++)
+ {
+ if (strcasepfx(str, prefixes[i].str))
+ {
+ this = identification_create(prefixes[i].type);
+ str += strlen(prefixes[i].str);
+ if (*str == '#')
+ {
+ this->encoded = chunk_from_hex(chunk_from_str(str + 1), NULL);
+ }
+ else
+ {
+ this->encoded = chunk_clone(chunk_from_str(str));
+ }
+ return this;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Create an identity for a specific type, determined by a numerical prefix
+ *
+ * The prefix is of the form "{x}:", where x denotes the numerical identity
+ * type.
+ */
+static private_identification_t* create_from_string_with_num_type(char *str)
+{
+ private_identification_t *this;
+ u_long type;
+
+ if (*str++ != '{')
+ {
+ return NULL;
+ }
+ errno = 0;
+ type = strtoul(str, &str, 0);
+ if (errno || *str++ != '}' || *str++ != ':')
+ {
+ return NULL;
+ }
+ this = identification_create(type);
+ if (*str == '#')
+ {
+ this->encoded = chunk_from_hex(chunk_from_str(str + 1), NULL);
+ }
+ else
+ {
+ this->encoded = chunk_clone(chunk_from_str(str));
+ }
+ return this;
+}
+
/*
* Described in header.
*/
@@ -939,6 +1016,16 @@ identification_t *identification_create_from_string(char *string)
{
string = "%any";
}
+ this = create_from_string_with_prefix_type(string);
+ if (this)
+ {
+ return &this->public;
+ }
+ this = create_from_string_with_num_type(string);
+ if (this)
+ {
+ return &this->public;
+ }
if (strchr(string, '=') != NULL)
{
/* we interpret this as an ASCII X.501 ID_DER_ASN1_DN.
diff --git a/src/libstrongswan/utils/identification.h b/src/libstrongswan/utils/identification.h
index e62446879..e6a9fe1c6 100644
--- a/src/libstrongswan/utils/identification.h
+++ b/src/libstrongswan/utils/identification.h
@@ -302,6 +302,15 @@ struct identification_t {
* N, G, I, dnQualifier, ID, EN, EmployeeNumber, E, Email, emailAddress, UN,
* unstructuredName, TCGID.
*
+ * To skip automatic type detection the following prefixes may be used to
+ * enforce a specific type: ipv4:, ipv6:, rfc822:, email:, userfqdn:, fqdn:,
+ * dns:, asn1dn:, asn1gn: and keyid:. If a # follows the :, the remaining data
+ * is interpreted as hex encoded binary data for that ID, otherwise the raw
+ * string following the prefix is used as identity data, without conversion.
+ * To specify a non-standard ID type, the numerical type may be prefixed
+ * between curly backets, building a prefix. For instance the "{1}:" prefix
+ * defines an ID_IPV4_ADDR type.
+ *
* This constructor never returns NULL. If it does not find a suitable
* conversion function, it will copy the string to an ID_KEY_ID.
*
diff --git a/src/libstrongswan/utils/utils.h b/src/libstrongswan/utils/utils.h
index da253cc35..7c48d949f 100644
--- a/src/libstrongswan/utils/utils.h
+++ b/src/libstrongswan/utils/utils.h
@@ -29,7 +29,7 @@
#include <string.h>
#ifdef WIN32
-# include "windows.h"
+# include "compat/windows.h"
#else
# define _GNU_SOURCE
# include <arpa/inet.h>
@@ -37,6 +37,7 @@
# include <netdb.h>
# include <netinet/in.h>
# include <sched.h>
+# include <poll.h>
#endif
/**
@@ -96,6 +97,9 @@
#include "enum.h"
#include "utils/strerror.h"
+#ifdef __APPLE__
+# include "compat/apple.h"
+#endif
/**
* Directory separator character in paths on this platform