summaryrefslogtreecommitdiff
path: root/keyexchange/isakmpd-20041012/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'keyexchange/isakmpd-20041012/util.c')
-rw-r--r--keyexchange/isakmpd-20041012/util.c485
1 files changed, 485 insertions, 0 deletions
diff --git a/keyexchange/isakmpd-20041012/util.c b/keyexchange/isakmpd-20041012/util.c
new file mode 100644
index 0000000..6504cb2
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/util.c
@@ -0,0 +1,485 @@
+/* $OpenBSD: util.c,v 1.48 2004/08/08 19:11:06 deraadt Exp $ */
+/* $EOM: util.c,v 1.23 2000/11/23 12:22:08 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2000, 2001, 2004 Håkan Olsson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "sysdep.h"
+
+#include "log.h"
+#include "message.h"
+#include "monitor.h"
+#include "sysdep.h"
+#include "transport.h"
+#include "util.h"
+
+/*
+ * Set if -N is given, allowing name lookups to be done, possibly stalling
+ * the daemon for quite a while.
+ */
+int allow_name_lookups = 0;
+
+/*
+ * This is set to true in case of regression-test mode, when it will
+ * cause predictable random numbers be generated.
+ */
+int regrand = 0;
+
+/*
+ * If in regression-test mode, this is the seed used.
+ */
+u_long seed;
+
+/*
+ * XXX These might be turned into inlines or macros, maybe even
+ * machine-dependent ones, for performance reasons.
+ */
+u_int16_t
+decode_16(u_int8_t *cp)
+{
+ return cp[0] << 8 | cp[1];
+}
+
+u_int32_t
+decode_32(u_int8_t *cp)
+{
+ return cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3];
+}
+
+u_int64_t
+decode_64(u_int8_t *cp)
+{
+ return (u_int64_t) cp[0] << 56 | (u_int64_t) cp[1] << 48 |
+ (u_int64_t) cp[2] << 40 | (u_int64_t) cp[3] << 32 |
+ cp[4] << 24 | cp[5] << 16 | cp[6] << 8 | cp[7];
+}
+
+#if 0
+/*
+ * XXX I severly doubt that we will need this. IPv6 does not have the legacy
+ * of representation in host byte order, AFAIK.
+ */
+
+void
+decode_128(u_int8_t *cp, u_int8_t *cpp)
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+ int i;
+
+ for (i = 0; i < 16; i++)
+ cpp[i] = cp[15 - i];
+#elif BYTE_ORDER == BIG_ENDIAN
+ bcopy(cp, cpp, 16);
+#else
+#error "Byte order unknown!"
+#endif
+}
+#endif
+
+void
+encode_16(u_int8_t *cp, u_int16_t x)
+{
+ *cp++ = x >> 8;
+ *cp = x & 0xff;
+}
+
+void
+encode_32(u_int8_t *cp, u_int32_t x)
+{
+ *cp++ = x >> 24;
+ *cp++ = (x >> 16) & 0xff;
+ *cp++ = (x >> 8) & 0xff;
+ *cp = x & 0xff;
+}
+
+void
+encode_64(u_int8_t *cp, u_int64_t x)
+{
+ *cp++ = x >> 56;
+ *cp++ = (x >> 48) & 0xff;
+ *cp++ = (x >> 40) & 0xff;
+ *cp++ = (x >> 32) & 0xff;
+ *cp++ = (x >> 24) & 0xff;
+ *cp++ = (x >> 16) & 0xff;
+ *cp++ = (x >> 8) & 0xff;
+ *cp = x & 0xff;
+}
+
+#if 0
+/*
+ * XXX I severly doubt that we will need this. IPv6 does not have the legacy
+ * of representation in host byte order, AFAIK.
+ */
+
+void
+encode_128(u_int8_t *cp, u_int8_t *cpp)
+{
+ decode_128(cpp, cp);
+}
+#endif
+
+/* Check a buffer for all zeroes. */
+int
+zero_test(const u_int8_t *p, size_t sz)
+{
+ while (sz-- > 0)
+ if (*p++ != 0)
+ return 0;
+ return 1;
+}
+
+/* Check a buffer for all ones. */
+int
+ones_test(const u_int8_t *p, size_t sz)
+{
+ while (sz-- > 0)
+ if (*p++ != 0xff)
+ return 0;
+ return 1;
+}
+
+/*
+ * Generate a random data, len bytes long.
+ */
+u_int8_t *
+getrandom(u_int8_t *buf, size_t len)
+{
+ u_int32_t tmp = 0;
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (i % sizeof tmp == 0)
+ tmp = sysdep_random();
+
+ buf[i] = tmp & 0xff;
+ tmp >>= 8;
+ }
+
+ return buf;
+}
+
+static __inline int
+hex2nibble(char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+}
+
+/*
+ * Convert hexadecimal string in S to raw binary buffer at BUF sized SZ
+ * bytes. Return 0 if everything is OK, -1 otherwise.
+ */
+int
+hex2raw(char *s, u_int8_t *buf, size_t sz)
+{
+ u_int8_t *bp;
+ char *p;
+ int tmp;
+
+ if (strlen(s) > sz * 2)
+ return -1;
+ for (p = s + strlen(s) - 1, bp = &buf[sz - 1]; bp >= buf; bp--) {
+ *bp = 0;
+ if (p >= s) {
+ tmp = hex2nibble(*p--);
+ if (tmp == -1)
+ return -1;
+ *bp = tmp;
+ }
+ if (p >= s) {
+ tmp = hex2nibble(*p--);
+ if (tmp == -1)
+ return -1;
+ *bp |= tmp << 4;
+ }
+ }
+ return 0;
+}
+
+int
+text2sockaddr(char *address, char *port, struct sockaddr **sa)
+{
+ struct addrinfo *ai, hints;
+
+ memset(&hints, 0, sizeof hints);
+ if (!allow_name_lookups)
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+
+ if (getaddrinfo(address, port, &hints, &ai))
+ return -1;
+
+ *sa = malloc(sysdep_sa_len(ai->ai_addr));
+ if (!*sa) {
+ freeaddrinfo(ai);
+ return -1;
+ }
+
+ memcpy(*sa, ai->ai_addr, sysdep_sa_len(ai->ai_addr));
+ freeaddrinfo(ai);
+ return 0;
+}
+
+/*
+ * Convert a sockaddr to text. With zflag non-zero fill out with zeroes,
+ * i.e 10.0.0.10 --> "010.000.000.010"
+ */
+int
+sockaddr2text(struct sockaddr *sa, char **address, int zflag)
+{
+ char buf[NI_MAXHOST], *token, *bstart, *ep;
+ int addrlen, i, j;
+ long val;
+
+ if (getnameinfo(sa, sysdep_sa_len(sa), buf, sizeof buf, 0, 0,
+ allow_name_lookups ? 0 : NI_NUMERICHOST))
+ return -1;
+
+ if (zflag == 0) {
+ *address = strdup(buf);
+ if (!*address)
+ return -1;
+ } else
+ switch (sa->sa_family) {
+ case AF_INET:
+ addrlen = sizeof "000.000.000.000";
+ *address = malloc(addrlen);
+ if (!*address)
+ return -1;
+ buf[addrlen] = '\0';
+ bstart = buf;
+ **address = '\0';
+ while ((token = strsep(&bstart, ".")) != NULL) {
+ if (strlen(*address) > 12) {
+ free(*address);
+ return -1;
+ }
+ val = strtol(token, &ep, 10);
+ if (ep == token || val < (long)0 ||
+ val > (long)UCHAR_MAX) {
+ free(*address);
+ return -1;
+ }
+ snprintf(*address + strlen(*address),
+ addrlen - strlen(*address), "%03ld", val);
+ if (bstart)
+ strlcat(*address, ".", addrlen);
+ }
+ break;
+
+ case AF_INET6:
+ /*
+ * XXX In the algorithm below there are some magic
+ * numbers we probably could give explaining names.
+ */
+ addrlen =
+ sizeof "0000:0000:0000:0000:0000:0000:0000:0000";
+ *address = malloc(addrlen);
+ if (!*address)
+ return -1;
+
+ for (i = 0, j = 0; i < 8; i++) {
+ snprintf((*address) + j, addrlen - j,
+ "%02x%02x",
+ ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[2*i],
+ ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[2*i + 1]);
+ j += 4;
+ (*address)[j] =
+ (j < (addrlen - 1)) ? ':' : '\0';
+ j++;
+ }
+ break;
+
+ default:
+ *address = strdup("<error>");
+ if (!*address)
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * sockaddr_addrlen and sockaddr_addrdata return the relevant sockaddr info
+ * depending on address family. Useful to keep other code shorter(/clearer?).
+ */
+int
+sockaddr_addrlen(struct sockaddr *sa)
+{
+ switch (sa->sa_family) {
+ case AF_INET6:
+ return sizeof((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr;
+ case AF_INET:
+ return sizeof((struct sockaddr_in *)sa)->sin_addr.s_addr;
+ default:
+ log_print("sockaddr_addrlen: unsupported protocol family %d",
+ sa->sa_family);
+ return 0;
+ }
+}
+
+u_int8_t *
+sockaddr_addrdata(struct sockaddr *sa)
+{
+ switch (sa->sa_family) {
+ case AF_INET6:
+ return (u_int8_t *)&((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr;
+ case AF_INET:
+ return (u_int8_t *)&((struct sockaddr_in *)sa)->sin_addr.s_addr;
+ default:
+ log_print("sockaddr_addrdata: unsupported protocol family %d",
+ sa->sa_family);
+ return 0;
+ }
+}
+
+in_port_t
+sockaddr_port(struct sockaddr *sa)
+{
+ switch (sa->sa_family) {
+ case AF_INET6:
+ return ((struct sockaddr_in6 *)sa)->sin6_port;
+ case AF_INET:
+ return ((struct sockaddr_in *)sa)->sin_port;
+ default:
+ log_print("sockaddr_port: unsupported protocol family %d",
+ sa->sa_family);
+ return 0;
+ }
+}
+
+/* Utility function used to set the port of a sockaddr. */
+void
+sockaddr_set_port(struct sockaddr *sa, in_port_t port)
+{
+ switch (sa->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)sa)->sin_port = htons (port);
+ break;
+
+ case AF_INET6:
+ ((struct sockaddr_in6 *)sa)->sin6_port = htons (port);
+ break;
+ }
+}
+
+/*
+ * Convert network address to text. The network address does not need
+ * to be properly aligned.
+ */
+void
+util_ntoa(char **buf, int af, u_int8_t *addr)
+{
+ struct sockaddr_storage from;
+ struct sockaddr *sfrom = (struct sockaddr *) & from;
+ socklen_t fromlen = sizeof from;
+
+ memset(&from, 0, fromlen);
+ sfrom->sa_family = af;
+#ifndef USE_OLD_SOCKADDR
+ switch (af) {
+ case AF_INET:
+ sfrom->sa_len = sizeof(struct sockaddr_in);
+ break;
+ case AF_INET6:
+ sfrom->sa_len = sizeof(struct sockaddr_in6);
+ break;
+ }
+#endif
+ memcpy(sockaddr_addrdata(sfrom), addr, sockaddr_addrlen(sfrom));
+
+ if (sockaddr2text(sfrom, buf, 0)) {
+ log_print("util_ntoa: could not make printable address out "
+ "of sockaddr %p", sfrom);
+ *buf = 0;
+ }
+}
+
+/*
+ * Perform sanity check on files containing secret information.
+ * Returns -1 on failure, 0 otherwise.
+ * Also, if FILE_SIZE is a not a null pointer, store file size here.
+ */
+
+int
+check_file_secrecy_fd(int fd, char *name, size_t *file_size)
+{
+ struct stat st;
+
+ if (fstat(fd, &st) == -1) {
+ log_error("check_file_secrecy: stat (\"%s\") failed", name);
+ return -1;
+ }
+ if (st.st_uid != 0 && st.st_uid != getuid()) {
+ log_print("check_file_secrecy_fd: "
+ "not loading %s - file owner is not process user", name);
+ errno = EPERM;
+ return -1;
+ }
+ if ((st.st_mode & (S_IRWXG | S_IRWXO)) != 0) {
+ log_print("check_file_secrecy_fd: not loading %s - too open "
+ "permissions", name);
+ errno = EPERM;
+ return -1;
+ }
+ if (file_size)
+ *file_size = (size_t)st.st_size;
+
+ return 0;
+}
+
+/* Special for compiling with Boehms GC. See Makefile and sysdep.h */
+#if defined (USE_BOEHM_GC)
+char *
+gc_strdup(const char *x)
+{
+ char *strcpy(char *,const char *);
+ char *y = malloc(strlen(x) + 1);
+ return strcpy(y,x);
+}
+#endif