From a3c6d0af68a4cec015ec1e9397d170799d6731ac Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Thu, 8 Oct 2015 10:44:24 +0200 Subject: [PATCH 01/39] Remove portable code; it has been suspended until we find a new -portable maintainer. Sync iked/ikectl code with -current. --- .gitignore | 3 - LICENSE.md | 3 +- Makefile | 4 + Makefile.am | 19 - README.md | 145 +- bootstrap | 151 -- configure.ac | 2555 ------------------------------- ikectl/.cvsignore | 5 - ikectl/CVS/Entries | 14 +- ikectl/Makefile | 22 + ikectl/Makefile.am | 45 - ikectl/ikeca.c | 257 +++- ikectl/ikeca.cnf | 4 +- ikectl/ikectl.8 | 22 +- ikectl/ikectl.c | 15 +- ikectl/parser.c | 9 +- ikectl/parser.h | 8 +- iked/.cvsignore | 1 - iked/CVS/Entries | 62 +- iked/Makefile | 33 + iked/Makefile.am | 76 - iked/ca.c | 513 +++++-- iked/chap_ms.c | 170 +- iked/chap_ms.h | 36 +- iked/config.c | 172 ++- iked/control.c | 28 +- iked/crypto.c | 190 ++- iked/dh.c | 153 +- iked/dh.h | 32 +- iked/eap.c | 37 +- iked/eap.h | 64 +- iked/genmap.sh | 3 +- iked/iked.8 | 100 +- iked/iked.c | 97 +- iked/iked.conf | 12 - iked/iked.conf.5 | 101 +- iked/iked.h | 473 +++--- iked/ikev1.c | 18 +- iked/ikev2.c | 2072 +++++++++++++++++++------ iked/ikev2.h | 123 +- iked/ikev2_msg.c | 148 +- iked/ikev2_pld.c | 1078 ++++++++++--- iked/imsg_util.c | 19 +- iked/log.c | 7 +- iked/ocsp.c | 514 +++++++ iked/parse.y | 343 +++-- iked/pfkey.c | 962 +++++------- iked/policy.c | 208 +-- iked/proc.c | 447 ++++-- iked/smult_curve25519_ref.c | 265 ++++ iked/timer.c | 24 +- iked/types.h | 47 +- iked/util.c | 198 +-- mdoc2man.awk | 370 ----- openbsd-compat/Makefile.am | 14 - openbsd-compat/bsd-arc4random.c | 233 --- openbsd-compat/bsd-closefrom.c | 89 -- openbsd-compat/chacha_private.h | 222 --- openbsd-compat/daemon.c | 82 - openbsd-compat/defines.h | 881 ----------- openbsd-compat/entropy.c | 203 --- openbsd-compat/fgetln.c | 63 - openbsd-compat/getopt.c | 123 -- openbsd-compat/imsg-buffer.c | 305 ---- openbsd-compat/imsg.c | 323 ---- openbsd-compat/imsg.h | 112 -- openbsd-compat/includes.h | 131 -- openbsd-compat/openbsd-compat.h | 182 --- openbsd-compat/setproctitle.c | 163 -- openbsd-compat/setresguid.c | 65 - openbsd-compat/strlcat.c | 62 - openbsd-compat/strlcpy.c | 58 - openbsd-compat/strtonum.c | 74 - openbsd-compat/sys-queue.h | 660 -------- openbsd-compat/sys-tree.h | 750 --------- openbsd-compat/vis.c | 225 --- openbsd-compat/vis.h | 98 -- 77 files changed, 6254 insertions(+), 11341 deletions(-) create mode 100644 Makefile delete mode 100644 Makefile.am delete mode 100755 bootstrap delete mode 100644 configure.ac delete mode 100644 ikectl/.cvsignore create mode 100644 ikectl/Makefile delete mode 100644 ikectl/Makefile.am create mode 100644 iked/Makefile delete mode 100644 iked/Makefile.am delete mode 100644 iked/iked.conf create mode 100644 iked/ocsp.c create mode 100644 iked/smult_curve25519_ref.c delete mode 100644 mdoc2man.awk delete mode 100644 openbsd-compat/Makefile.am delete mode 100644 openbsd-compat/bsd-arc4random.c delete mode 100644 openbsd-compat/bsd-closefrom.c delete mode 100644 openbsd-compat/chacha_private.h delete mode 100644 openbsd-compat/daemon.c delete mode 100644 openbsd-compat/defines.h delete mode 100644 openbsd-compat/entropy.c delete mode 100644 openbsd-compat/fgetln.c delete mode 100644 openbsd-compat/getopt.c delete mode 100644 openbsd-compat/imsg-buffer.c delete mode 100644 openbsd-compat/imsg.c delete mode 100644 openbsd-compat/imsg.h delete mode 100644 openbsd-compat/includes.h delete mode 100644 openbsd-compat/openbsd-compat.h delete mode 100644 openbsd-compat/setproctitle.c delete mode 100644 openbsd-compat/setresguid.c delete mode 100644 openbsd-compat/strlcat.c delete mode 100644 openbsd-compat/strlcpy.c delete mode 100644 openbsd-compat/strtonum.c delete mode 100644 openbsd-compat/sys-queue.h delete mode 100644 openbsd-compat/sys-tree.h delete mode 100644 openbsd-compat/vis.c delete mode 100644 openbsd-compat/vis.h diff --git a/.gitignore b/.gitignore index 999d144..f4dbad9 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ .DS_Store m4 aclocal.m4 -Makefile autom4te.cache compile config.guess @@ -27,8 +26,6 @@ missing parse.c stamp-h1 ylwrap -iked -ikectl *_map.c clang_* *-scan-build diff --git a/LICENSE.md b/LICENSE.md index 4ba7f6f..021608f 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -5,8 +5,7 @@ OpenIKED is free software under OpenBSD's ISC-style license. * Most of the code has been written by Reyk Floeter * The ikectl CA code has been written by Jonathan Gray -* The `openbsd-compat` and autoconf parts of the portable version are - based on work by Damien Miller for OpenSSH. +* Much work by Markus Friedl and Hans-Joerg Hoexer. * Please refer to the individual source files for other copyright holders! > Copyright (c) 2010-2013 Reyk Floeter diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..49ae017 --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +SUBDIR= iked ikectl +MAKE_FLAGS= BINDIR=/sbin + +.include diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index dd5faa3..0000000 --- a/Makefile.am +++ /dev/null @@ -1,19 +0,0 @@ -SUBDIRS= openbsd-compat iked ikectl -ACLOCAL_AMFLAGS= -I m4 - -PRIVKEY=$(DESTDIR)$(sysconfdir)/iked/private/local.key -PUBKEY=$(DESTDIR)$(sysconfdir)/iked/local.pub - -install-exec-hook: host-key - -host-key: - @if [ -z "$(DESTDIR)" ] ; then \ - if [ -f $(PRIVKEY) ]; then \ - echo "$(PRIVKEY) already exists, skipping." ; \ - elif $(OPENSSL) genrsa -out $(PRIVKEY) 2048 ; then \ - $(CHMOD) 600 $(PRIVKEY) ; \ - $(OPENSSL) rsa -out $(PUBKEY) -in $(PRIVKEY) -pubout ; \ - else \ - echo "$(PRIVKEY) failed" ; \ - fi ; \ - fi diff --git a/README.md b/README.md index 81e2b14..da009c5 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,7 @@ OpenIKED ======== -This is the port of OpenBSD's iked to Darwin/OS X and other -operating systems (see "Supported Platforms"). +This is a development mirror of OpenBSD's iked. iked is a lean Internet Key Exchange (IKEv2) daemon which performs mutual authentication and which establishes and maintains IPsec VPN @@ -20,13 +19,10 @@ with other IKEv2 implementations like the native IKEv2 implementation of Windows 7 or newer (aka Agile VPN) or strongSwan. The main development of iked is being done for OpenBSD and the source -tree is found in OpenBSD's CVS repository. This port adds -replacements for OpenBSD-specific library functions and portability -code for other platforms. Like most of the projects from the OpenBSD -repository, the original source code does not include any portability -glue (#ifdefs) and is specifically developed for OpenBSD. This -external repository adds all the portable extensions to run it on -other supported platforms. +tree is found in OpenBSD's CVS repository. Like most of the projects +from the OpenBSD repository, the original source code does not include +any portability glue (#ifdefs) and is specifically developed for +OpenBSD. The main development tree is found in the src/sbin/iked and src/usr.sbin/ikectl directories of the OpenBSD CVS repository: @@ -35,55 +31,6 @@ src/usr.sbin/ikectl directories of the OpenBSD CVS repository: * http://www.openbsd.org/cgi-bin/cvsweb/src/usr.sbin/ikectl/ * See also: http://www.openiked.org/ -Installation ------------- - -The portable version of OpenIKED uses the GNU autoconf environment to -build and install from the sources. As usual, follow these basic -steps to install OpenIKED: - -1. Requirements: - - Make sure that the external libraries OpenSSL (version 1.0 or newer) -and libevent (version 1.4 or newer) with their header files are -installed. - - If you're checking out the sources from the Git repository, you will -also need GNU automake, autoconf (version 2.69 or newer) and libtool. -2. Enter the top directory of the extracted sources. -3. If you checked out the sources from the Git repository, run -`sh bootstrap` to generate the required build files. -4. Run `./configure` in this directory to generate the Makefiles. - - `./configure --help` will show you some available build options. - - For example, you can run the following when building on Apple OSX -with MacPorts: -``` - ./configure --with-ssl-dir=/opt/local/ - --with-libevent-dir=/opt/local/lib/libevent1/ - --prefix=/opt/local/ -``` -5. Type `make` to build all parts of OpenIKED including iked and ikectl. -6. Type `make install` to install OpenIKED, or `sudo make install` if -you didn't compile OpenIKED as root. - -7. Run something like the following to create iked's unprivileged -system user and environment. Note that the command syntax and user -name might vary on different platforms - use "iked" instead of "_iked" -on Linux. -``` - # mkdir /var/empty - # chown root:sys /var/empty - # chmod 755 /var/empty - # groupadd _iked - # useradd -g _iked -c 'iked privsep' -d /var/empty -s /sbin/nologin _iked -``` - -8. On FreeBSD, NetBSD and maybe other BSD-variants IPsec is not -enabled in the default GENERIC kernel. You have to compile a custom -kernel and enable options like `IPSEC`. Please refer to the -individual documentation for details, for example: - -* http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/ipsec.html -* http://www.netbsd.org/docs/network/ipsec/#config_kernel - Supported Platforms ------------------- @@ -91,52 +38,13 @@ Original version: * OpenBSD 4.8 or newer -Portable version: - -* Darwin (Apple OS X Mountain Lion 10.8) -* Linux (Ubuntu 12.10 GNU/Linux 3.5.0-19-generic) -* FreeBSD (FreeBSD 9.0-RELEASE with IPSEC kernel) -* NetBSD (NetBSD 6.0 with IPSEC kernel) -* TODO: other BSDs and PFKEYv2/KAME-based platforms. - -Development ------------ - -The source tree of OpenIKED contains the following directories: - -* `openiked/`: - Build scripts for automake/autoconf and README files. -* `openiked/ikectl/`: - The control and status utility for iked. -* `openiked/iked/`: - The IKEv2 daemon itself and some files that are shared with ikectl. -* `openiked/openbsd-compat/`: - Portability glue and API functions for non-OpenBSD platforms. - -You can checkout the portable code from GitHub: - -``` -$ git clone git://github.com/reyk/openiked.git -``` - -And compare the contents of the `iked` and `ikectl` directories in -the git repository with the original sources in OpenBSD's -(Anon)CVS repository by running the `cvs diff` command in these -subdirectories. This will show you the differences between the portable -version and the unpatched OpenBSD version: - -``` -$ cd openiked/iked/ -$ cvs diff -Nup | tee ../iked.diff -$ cd ../ikectl/ -$ cvs diff -Nup | tee ../ikectl.diff -``` - -Before you continue with looking at the code or writing any diffs, you -should study OpenBSD's source style guide; or the "KNF". You can -find it in OpenBSD's style(9) manpage or online at: -http://www.openbsd.org/cgi-bin/man.cgi?query=style&sektion=9. -Please also note that each line should be at most 80 characters long. +The portable version has been suspended and is not available at +present. It previously supported the following platforms: + +* Darwin (Apple OS X Mountain Lion 10.8) - DEPRECATED +* Linux (Ubuntu 12.10 GNU/Linux 3.5.0-19-generic) - DEPRECATED +* FreeBSD (FreeBSD 9.0-RELEASE with IPSEC kernel) - DEPRECATED +* NetBSD (NetBSD 6.0 with IPSEC kernel) - DEPRECATED Authors ------- @@ -147,35 +55,6 @@ Authors See [`LICENSE.md`](https://github.com/reyk/openiked/blob/master/LICENSE.md) for information about copyright and licensing. -Caveats, bugs and limitations ------------------------------ - -This is work in progress! OpenIKED is not yet finished and is missing -some important security features. It should not yet be used in -production networks. - -OpenIKED might have a few limitations on operating systems other than -the most recent versions of OpenBSD. A major difference between -OpenBSD and other systems is the API and availability of the IPsec -PFKEYv2 flow implementation (SADB) and message passing between kernel -and iked. Current known limitations are: - -* VPN traffic leakage prevention: -Automatic blocking of IPv6 traffic is not working on KAME-bases stacks. - -* NAT-T: -NAT-T is only supported on OpenBSD and Darwin (OS X). The NAT-T API -is not standardized in PFKEYv2, not even on a semi-level, and differs -in most operating systems, if supported at all. - -* Crypto algorithms: -Some of the crypto algorithms are either not supported on other systems -or not implemented correctly. For example, Linux still uses the broken -pre-standard version of hmac-sha2-256 by default that was specified with -96 bit truncation instead of the standard 128 bit truncation. The common -workaround that allows to specify the truncation length would be to use -Linux' non-standard XFRM kernel API instead of PFKEYv2. - Reyk [![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/thing/1038961/reykopeniked-on-GitHub) diff --git a/bootstrap b/bootstrap deleted file mode 100755 index 6cfcf9d..0000000 --- a/bootstrap +++ /dev/null @@ -1,151 +0,0 @@ -#! /bin/sh - -# bootstrap: generic bootstrap/autogen.sh script for autotools projects -# -# Copyright (c) 2002-2011 Sam Hocevar -# -# This program is free software. It comes without any warranty, to -# the extent permitted by applicable law. You can redistribute it -# and/or modify it under the terms of the Do What The Fuck You Want -# To Public License, Version 2, as published by Sam Hocevar. See -# http://sam.zoy.org/wtfpl/COPYING for more details. -# -# The latest version of this script can be found at the following place: -# http://caca.zoy.org/wiki/build - -# Die if an error occurs -set -e - -# Guess whether we are using configure.ac or configure.in -if test -f configure.ac; then - conffile="configure.ac" -elif test -f configure.in; then - conffile="configure.in" -else - echo "$0: could not find configure.ac or configure.in" - exit 1 -fi - -# Check for needed features -auxdir="`sed -ne 's/^[ \t]*A._CONFIG_AUX_DIR *([[ ]*\([^] )]*\).*/\1/p' $conffile`" -pkgconfig="`grep '^[ \t]*PKG_PROG_PKG_CONFIG' $conffile >/dev/null 2>&1 && echo yes || echo no`" -libtool="`grep '^[ \t]*A._PROG_LIBTOOL' $conffile >/dev/null 2>&1 && echo yes || echo no`" -header="`grep '^[ \t]*A._CONFIG_HEADER' $conffile >/dev/null 2>&1 && echo yes || echo no`" -makefile="`[ -f Makefile.am ] && echo yes || echo no`" -aclocalflags="`sed -ne 's/^[ \t]*ACLOCAL_AMFLAGS[ \t]*=//p' Makefile.am 2>/dev/null || :`" - -# Check for automake -amvers="no" -for v in 12 11 10 9 8 7 6 5; do - if automake-1.${v} --version >/dev/null 2>&1; then - amvers="-1.${v}" - break - elif automake1.${v} --version >/dev/null 2>&1; then - amvers="1.${v}" - break - fi -done - -if test "${amvers}" = "no" && automake --version > /dev/null 2>&1; then - amvers="`automake --version | sed -e '1s/[^0-9]*//' -e q`" - if expr "$amvers" "<" "1.5" > /dev/null 2>&1; then - amvers="no" - else - amvers="" - fi -fi - -if test "$amvers" = "no"; then - echo "$0: you need automake version 1.5 or later" - exit 1 -fi - -# Check for autoconf -acvers="no" -for v in "" "269" "-2.69" "259" "-2.59" "253" "-2.53"; do - if autoconf${v} --version >/dev/null 2>&1; then - acvers="${v}" - break - fi -done - -if test "$acvers" = "no"; then - echo "$0: you need autoconf" - exit 1 -fi - -# Check for libtool -if test "$libtool" = "yes"; then - libtoolize="no" - if glibtoolize --version >/dev/null 2>&1; then - libtoolize="glibtoolize" - else - for v in "16" "15" "" "14"; do - if libtoolize${v} --version >/dev/null 2>&1; then - libtoolize="libtoolize${v}" - break - fi - done - fi - - if test "$libtoolize" = "no"; then - echo "$0: you need libtool" - exit 1 - fi -fi - -# Check for pkg-config -if test "$pkgconfig" = "yes"; then - if ! pkg-config --version >/dev/null 2>&1; then - echo "$0: you need pkg-config" - exit 1 - fi -fi - -# Remove old cruft -for x in aclocal.m4 configure config.guess config.log config.sub config.cache config.h.in config.h compile libtool.m4 ltoptions.m4 ltsugar.m4 ltversion.m4 ltmain.sh libtool ltconfig missing mkinstalldirs depcomp install-sh; do rm -f $x autotools/$x; if test -n "$auxdir"; then rm -f "$auxdir/$x"; fi; done -rm -Rf autom4te.cache -if test -n "$auxdir"; then - if test ! -d "$auxdir"; then - mkdir "$auxdir" - fi - aclocalflags="${aclocalflags} -I $auxdir -I ." -fi - -# Honour M4PATH because sometimes M4 doesn't -save_IFS=$IFS -IFS=: -tmp="$M4PATH" -for x in $tmp; do - if test -n "$x"; then - aclocalflags="${aclocalflags} -I $x" - fi -done -IFS=$save_IFS - -# Explain what we are doing from now -set -x - -# Bootstrap package -if test "$libtool" = "yes"; then - ${libtoolize} --copy --force - if test -n "$auxdir" -a ! "$auxdir" = "." -a -f "ltmain.sh"; then - echo "$0: working around a minor libtool issue" - mv ltmain.sh "$auxdir/" - fi -fi - -aclocal${amvers} ${aclocalflags} -autoconf${acvers} -if test "$header" = "yes"; then - autoheader${acvers} -fi -if test "$makefile" = "yes"; then - #add --include-deps if you want to bootstrap with any other compiler than gcc - #automake${amvers} --add-missing --copy --include-deps - automake${amvers} --foreign --add-missing --copy -fi - -# Remove cruft that we no longer want -rm -Rf autom4te.cache - diff --git a/configure.ac b/configure.ac deleted file mode 100644 index 1705862..0000000 --- a/configure.ac +++ /dev/null @@ -1,2555 +0,0 @@ -# Copyright (c) 2012 Reyk Floeter -# Copyright (c) 1999-2004 Damien Miller -# -# Permission to use, copy, modify, and distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -dnl AC_INIT([OpenIKED-portable],[5.2.0p0],[Reyk Floeter ]) -AC_INIT([OpenIKED-portable], m4_esyscmd(date +%Y%m%d%H%M%S | sed -e 's/^\(.*\)$/5.2-\1/' | tr -d '\n'),[Reyk Floeter ]) -AC_LANG([C]) -AC_CONFIG_MACRO_DIR([m4]) - -AC_CONFIG_HEADER([config.h]) -AC_CANONICAL_HOST -AC_C_BIGENDIAN - -AM_INIT_AUTOMAKE - -# Checks for programs. -AC_PROG_CC -AM_PROG_CC_C_O -AC_PROG_CPP -AC_PROG_INSTALL -AC_PROG_LIBTOOL -AC_PATH_PROG([AR], [ar]) -AC_PATH_PROG([CAT], [cat]) -AC_PATH_PROG([CHMOD], [chmod]) -AC_PATH_PROG([CHOWN], [chown]) -AC_PATH_PROG([SED], [sed]) -AC_PATH_PROG([TEST_MINUS_S_SH], [bash]) -AC_PATH_PROG([TEST_MINUS_S_SH], [ksh]) -AC_PATH_PROG([TEST_MINUS_S_SH], [sh]) -AC_PATH_PROG([SH], [sh]) -AC_PATH_PROG([GROFF], [groff]) -AC_PATH_PROG([NROFF], [nroff]) -AC_PATH_PROG([MANDOC], [mandoc]) -AC_PROG_YACC -AC_PATH_PROG(OPENSSL, openssl) -AC_PATH_PROG(ZIP, zip) -AC_PATH_PROG(TAR, tar) - -LT_INIT - -dnl select manpage formatter -if test "x$MANDOC" != "x" ; then - MANFMT="$MANDOC" -elif test "x$NROFF" != "x" ; then - MANFMT="$NROFF -mandoc" -elif test "x$GROFF" != "x" ; then - MANFMT="$GROFF -mandoc -Tascii" -else - AC_MSG_WARN([no manpage formatted found]) - MANFMT="false" -fi -AC_SUBST([MANFMT]) - -if test -z "$LD" ; then - LD=$CC -fi -AC_SUBST([LD]) - -AC_C_INLINE - -AC_CHECK_DECL([LLONG_MAX], [have_llong_max=1], , [#include ]) - -if test "$GCC" = "yes" || test "$GCC" = "egcs"; then - CFLAGS="$CFLAGS -Wall -Wpointer-arith -Wuninitialized" - GCC_VER=`$CC -v 2>&1 | $AWK '/gcc version /{print $3}'` - case $GCC_VER in - 1.*) no_attrib_nonnull=1 ;; - 2.8* | 2.9*) - CFLAGS="$CFLAGS -Wsign-compare" - no_attrib_nonnull=1 - ;; - 2.*) no_attrib_nonnull=1 ;; - 3.*) CFLAGS="$CFLAGS -Wsign-compare" ;; - 4.*) CFLAGS="$CFLAGS -Wsign-compare -Wno-pointer-sign" ;; - *) ;; - esac - - if test -z "$have_llong_max"; then - # retry LLONG_MAX with -std=gnu99, needed on some Linuxes - unset ac_cv_have_decl_LLONG_MAX - saved_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -std=gnu99" - AC_CHECK_DECL(LLONG_MAX, - [have_llong_max=1], - [CFLAGS="$saved_CFLAGS"], - [#include ] - ) - fi -fi - -if test "x$no_attrib_nonnull" != "x1" ; then - AC_DEFINE(HAVE_ATTRIBUTE__NONNULL__, 1, [Have attribute nonnull]) -fi - -AC_ARG_WITH(Werror, - [ --with-Werror Build main code with -Werror], - [ - if test -n "$withval" && test "x$withval" != "xno"; then - werror_flags="-Werror" - if test "x${withval}" != "xyes"; then - werror_flags="$withval" - fi - fi - ] -) - -AC_ARG_WITH(debug, - [ --with-debug Build main code with debugging symbols and disable privsep], - [ - if test -n "$withval" && test "x$withval" != "xno"; then - debug_flags="-g -DDEBUG=1" - if test "x${withval}" != "xyes"; then - debug_flags="$withval" - fi - fi - ] -) - -AC_CHECK_HEADERS([\ - arpa/inet.h \ - asm/byteorder.h \ - ctype.h \ - dirent.h \ - endian.h \ - err.h \ - errno.h \ - fcntl.h \ - getopt.h \ - libkern/OSByteOrder.h \ - ndir.h \ - net/pfkeyv2.h \ - linux/pfkeyv2.h \ - linux/in.h \ - linux/ipsec.h \ - limits.h \ - netdb.h \ - netinet/in.h \ - netinet/in_systm.h \ - netinet/ip_ipsp.h \ - netinet/tcp.h \ - netinet6/ipsec.h \ - netipsec/ipsec.h \ - mach/mach_time.h \ - pwd.h \ - signal.h \ - stdarg.h \ - stdio.h \ - stdlib.h \ - string.h \ - sys/cdefs.h \ - sys/endian.h \ - sys/ndir.h \ - sys/param.h \ - sys/pstat.h \ - sys/socket.h \ - sys/stat.h \ - sys/sysctl.h \ - sys/types.h \ - sys/uio.h \ - sys/un.h \ - sys/wait.h \ - syslog.h \ - ucred.h \ - unistd.h \ - vis.h \ -]) - -# login_cap.h requires sys/types.h on NetBSD -AC_CHECK_HEADERS([login_cap.h], [], [], [ -#include -]) - -pfkeyv2_h="net/pfkeyv2.h" -IKED_USER=_iked - -# Check for some target-specific stuff -case "$host" in -*-*-aix*) - check_for_aix_broken_getaddrinfo=1 - AC_DEFINE([BROKEN_REALPATH], [1], [Define if you have a broken realpath.]) - AC_DEFINE([SETEUID_BREAKS_SETUID], [1], - [Define if your platform breaks doing a seteuid before a setuid]) - AC_DEFINE([BROKEN_SETREUID], [1], [Define if your setreuid() is broken]) - AC_DEFINE([BROKEN_SETREGID], [1], [Define if your setregid() is broken]) - AC_DEFINE([SPT_TYPE], [SPT_REUSEARGV], - [Define to a Set Process Title type if your system is - supported by bsd-setproctitle.c]) - ;; -*-*-darwin*) - AC_MSG_CHECKING([if we have working getaddrinfo]) - AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include -main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) - exit(0); - else - exit(1); -} - ]])], - [AC_MSG_RESULT([working])], - [AC_MSG_RESULT([buggy]) - AC_DEFINE([BROKEN_GETADDRINFO], [1], - [getaddrinfo is broken (if present)]) - ], - [AC_MSG_RESULT([assume it is working])]) - AC_DEFINE([SETEUID_BREAKS_SETUID]) - AC_DEFINE([BROKEN_SETREUID]) - AC_DEFINE([BROKEN_SETREGID]) - AC_DEFINE([BROKEN_GLOB], [1], [OS X glob does not do what we expect]) - AC_DEFINE_UNQUOTED([BIND_8_COMPAT], [1], - [Define if your resolver libs need this for getrrsetbyname]) - AC_DEFINE([SPT_TYPE], [SPT_REUSEARGV], - [Define to a Set Process Title type if your system is - supported by setproctitle.c]) - # IPv6 compatibility - AC_DEFINE([__APPLE_USE_RFC_3542], [1], [Use RFC3542 IPv6 API]) - - # We cannot check if NAT-T is really supported by the kernel because - # it is not exposed in the public version of the pfkeyv2.h header. - AC_DEFINE([HAVE_APPLE_NATT], [1], [Use Apple's NAT-T support]) - - ac_deprecated_daemon=yes - ;; -*-*-dragonfly*) - IKEDLIBS="$IKEDLIBS -lcrypt" - ;; -*-*-hpux*) - # first we define all of the options common to all HP-UX releases - CPPFLAGS="$CPPFLAGS -D_HPUX_SOURCE -D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED=1" - AC_DEFINE([SPT_TYPE], [SPT_PSTAT]) - ;; -*-*-linux*) - check_for_libcrypt_later=1 - AC_DEFINE([SPT_TYPE], [SPT_REUSEARGV]) - case `uname -r` in - 1.*|2.0.*) - AC_DEFINE(BROKEN_CMSG_TYPE, 1, - [Define if cmsg_type is not passed correctly]) - ;; - esac - AC_DEFINE([BROKEN_HMAC_SHA2_256], 1, - [Uses pre-standard HMAC-SHA2-256 truncation]) - pfkeyv2_h="linux/pfkeyv2.h" - IKED_USER=iked - ;; -*-*-netbsd*) - check_for_libcrypt_before=1 - if test "x$withval" != "xno" ; then - need_dash_r=1 - fi - ;; -*-*-freebsd*) - check_for_libcrypt_later=1 - ;; -*-*-openbsd*) - echo "Please use -current" - ;; -*-*-solaris*) - if test "x$withval" != "xno" ; then - need_dash_r=1 - fi - ;; -*-*-sunos4*) - CPPFLAGS="$CPPFLAGS -DSUNOS4" - ;; -esac - -dnl IRIX and Solaris 2.5.1 have dirname() in libgen -AC_CHECK_FUNCS([dirname], [AC_CHECK_HEADERS([libgen.h])] , [ - AC_CHECK_LIB([gen], [dirname], [ - AC_CACHE_CHECK([for broken dirname], - ac_cv_have_broken_dirname, [ - save_LIBS="$LIBS" - LIBS="$LIBS -lgen" - AC_RUN_IFELSE( - [AC_LANG_SOURCE([[ -#include -#include - -int main(int argc, char **argv) { - char *s, buf[32]; - - strncpy(buf,"/etc", 32); - s = dirname(buf); - if (!s || strncmp(s, "/", 32) != 0) { - exit(1); - } else { - exit(0); - } -} - ]])], - [ ac_cv_have_broken_dirname="no" ], - [ ac_cv_have_broken_dirname="yes" ], - [ ac_cv_have_broken_dirname="no" ], - ) - LIBS="$save_LIBS" - ]) - if test "x$ac_cv_have_broken_dirname" = "xno" ; then - LIBS="$LIBS -lgen" - AC_DEFINE([HAVE_DIRNAME]) - AC_CHECK_HEADERS([libgen.h]) - fi - ]) -]) - -AC_SEARCH_LIBS([basename], [gen], [AC_DEFINE([HAVE_BASENAME], [1], - [Define if you have the basename function.])]) - -dnl zlib is required -AC_ARG_WITH([zlib], - [ --with-zlib=PATH Use zlib in PATH], - [ if test "x$withval" = "xno" ; then - AC_MSG_ERROR([*** zlib is required ***]) - elif test "x$withval" != "xyes"; then - if test -d "$withval/lib"; then - if test -n "${need_dash_r}"; then - LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}" - else - LDFLAGS="-L${withval}/lib ${LDFLAGS}" - fi - else - if test -n "${need_dash_r}"; then - LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}" - else - LDFLAGS="-L${withval} ${LDFLAGS}" - fi - fi - if test -d "$withval/include"; then - CPPFLAGS="-I${withval}/include ${CPPFLAGS}" - else - CPPFLAGS="-I${withval} ${CPPFLAGS}" - fi - fi ] -) - -AC_CHECK_HEADER([zlib.h], ,[AC_MSG_ERROR([*** zlib.h missing - please install first or check config.log ***])]) -AC_CHECK_LIB([z], [deflate], , - [ - saved_CPPFLAGS="$CPPFLAGS" - saved_LDFLAGS="$LDFLAGS" - save_LIBS="$LIBS" - dnl Check default zlib install dir - if test -n "${need_dash_r}"; then - LDFLAGS="-L/usr/local/lib -R/usr/local/lib ${saved_LDFLAGS}" - else - LDFLAGS="-L/usr/local/lib ${saved_LDFLAGS}" - fi - CPPFLAGS="-I/usr/local/include ${saved_CPPFLAGS}" - LIBS="$LIBS -lz" - AC_TRY_LINK_FUNC([deflate], [AC_DEFINE([HAVE_LIBZ])], - [ - AC_MSG_ERROR([*** zlib missing - please install first or check config.log ***]) - ] - ) - ] -) - -AC_ARG_WITH([zlib-version-check], - [ --without-zlib-version-check Disable zlib version check], - [ if test "x$withval" = "xno" ; then - zlib_check_nonfatal=1 - fi - ] -) - -AC_MSG_CHECKING([for possibly buggy zlib]) -AC_RUN_IFELSE([AC_LANG_PROGRAM([[ -#include -#include - ]], - [[ - int a=0, b=0, c=0, d=0, n, v; - n = sscanf(ZLIB_VERSION, "%d.%d.%d.%d", &a, &b, &c, &d); - if (n != 3 && n != 4) - exit(1); - v = a*1000000 + b*10000 + c*100 + d; - fprintf(stderr, "found zlib version %s (%d)\n", ZLIB_VERSION, v); - - /* 1.1.4 is OK */ - if (a == 1 && b == 1 && c >= 4) - exit(0); - - /* 1.2.3 and up are OK */ - if (v >= 1020300) - exit(0); - - exit(2); - ]])], - AC_MSG_RESULT([no]), - [ AC_MSG_RESULT([yes]) - if test -z "$zlib_check_nonfatal" ; then - AC_MSG_ERROR([*** zlib too old - check config.log *** -Your reported zlib version has known security problems. It's possible your -vendor has fixed these problems without changing the version number. If you -are sure this is the case, you can disable the check by running -"./configure --without-zlib-version-check". -If you are in doubt, upgrade zlib to version 1.2.3 or greater. -See http://www.gzip.org/zlib/ for details.]) - else - AC_MSG_WARN([zlib version may have security problems]) - fi - ], - [ AC_MSG_WARN([cross compiling: not checking zlib version]) ] -) - -dnl Checks for libutil functions -AC_CHECK_HEADERS([libutil.h]) -AC_SEARCH_LIBS([fmt_scaled], [util bsd]) -AC_CHECK_FUNCS([fmt_scaled]) -AC_CHECK_HEADERS([libutil.h]) -AC_SEARCH_LIBS([fmt_scaled], [util bsd]) - -AC_MSG_CHECKING([for /proc/pid/fd directory]) -if test -d "/proc/$$/fd" ; then - AC_DEFINE(HAVE_PROC_PID, 1, [Define if you have /proc/$pid/fd]) - AC_MSG_RESULT(yes) -else - AC_MSG_RESULT(no) -fi - -AC_CHECK_FUNCS([ \ - arc4random \ - arc4random_buf \ - arc4random_uniform \ - asprintf \ - bcopy \ - chflags \ - closefrom \ - dirfd \ - dirname \ - fgetln \ - freeaddrinfo \ - getaddrinfo \ - getnameinfo \ - getopt \ - getpeereid \ - memmove \ - setproctitle \ - setregid \ - setreuid \ - strlcat \ - strlcpy \ - strnvis \ - strtonum \ - strmode \ - sysconf \ - waitpid \ -]) - -# IRIX has a const char return value for gai_strerror() -AC_CHECK_FUNCS([gai_strerror], [ - AC_DEFINE([HAVE_GAI_STRERROR]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include -#include -#include - -const char *gai_strerror(int); - ]], [[ - char *str; - str = gai_strerror(0); - ]])], [ - AC_DEFINE([HAVE_CONST_GAI_STRERROR_PROTO], [1], - [Define if gai_strerror() returns const char *])], [])]) - -AC_CHECK_DECL([strsep], - [AC_CHECK_FUNCS([strsep])], - [], - [ -#ifdef HAVE_STRING_H -# include -#endif - ]) - -AC_CHECK_DECLS([O_NONBLOCK], , , - [ -#include -#ifdef HAVE_SYS_STAT_H -# include -#endif -#ifdef HAVE_FCNTL_H -# include -#endif - ]) - -AC_CHECK_DECLS([writev], , , [ -#include -#include -#include - ]) - -AC_CHECK_FUNCS([setresuid], [ - dnl Some platorms have setresuid that isn't implemented, test for this - AC_MSG_CHECKING([if setresuid seems to work]) - AC_RUN_IFELSE( - [AC_LANG_PROGRAM([[ -#include -#include - ]], [[ - errno=0; - setresuid(0,0,0); - if (errno==ENOSYS) - exit(1); - else - exit(0); - ]])], - [AC_MSG_RESULT([yes])], - [AC_DEFINE([BROKEN_SETRESUID], [1], - [Define if your setresuid() is broken]) - AC_MSG_RESULT([not implemented])], - [AC_MSG_WARN([cross compiling: not checking setresuid])] - ) -]) - -AC_CHECK_FUNCS([setresgid], [ - dnl Some platorms have setresgid that isn't implemented, test for this - AC_MSG_CHECKING([if setresgid seems to work]) - AC_RUN_IFELSE( - [AC_LANG_PROGRAM([[ -#include -#include - ]], [[ - errno=0; - setresgid(0,0,0); - if (errno==ENOSYS) - exit(1); - else - exit(0); - ]])], - [AC_MSG_RESULT([yes])], - [AC_DEFINE([BROKEN_SETRESGID], [1], - [Define if your setresgid() is broken]) - AC_MSG_RESULT([not implemented])], - [AC_MSG_WARN([cross compiling: not checking setresuid])] - ) -]) - -dnl Checks for time functions -AC_CHECK_FUNCS([gettimeofday time]) - -AC_CHECK_FUNC([daemon], - [AC_DEFINE([HAVE_DAEMON], [1], [Define if your libraries define daemon()])], - [AC_CHECK_LIB([bsd], [daemon], - [LIBS="$LIBS -lbsd"; AC_DEFINE([HAVE_DAEMON])])] -) -if test "x$ac_deprecated_daemon" = "xyes"; then - AC_DEFINE([HAVE_DEPRECATED_DAEMON], [1], - [System declares daemon as deprecated]) -fi - -##chl -AC_CHECK_FUNC([fparseln], - [AC_DEFINE([HAVE_FPARSELN], [1], [Define if your libraries define fparseln()])], - [AC_CHECK_LIB([util], [fparseln], - [LIBS="$LIBS -lutil"; AC_DEFINE([HAVE_FPARSELN])])] -) - -AC_CHECK_FUNC([clock_gettime], - [AC_DEFINE([HAVE_CLOCK_GETTIME], [1], [Define if your libraries define clock_gettime()])], - [AC_CHECK_LIB([rt], [clock_gettime], - [LIBS="$LIBS -lrt"; AC_DEFINE([HAVE_CLOCK_GETTIME])])] -) - -AC_SEARCH_LIBS(res_9_b64_ntop, resolv) -##chl - -# Check for broken snprintf -if test "x$ac_cv_func_snprintf" = "xyes" ; then - AC_MSG_CHECKING([whether snprintf correctly terminates long strings]) - AC_RUN_IFELSE( - [AC_LANG_PROGRAM([[ #include ]], - [[ - char b[5]; - snprintf(b,5,"123456789"); - exit(b[4]!='\0'); - ]])], - [AC_MSG_RESULT([yes])], - [ - AC_MSG_RESULT([no]) - AC_DEFINE([BROKEN_SNPRINTF], [1], - [Define if your snprintf is busted]) - AC_MSG_WARN([****** Your snprintf() function is broken, complain to your vendor]) - ], - [ AC_MSG_WARN([cross compiling: Assuming working snprintf()]) ] - ) -fi - -# If we don't have a working asprintf, then we strongly depend on vsnprintf -# returning the right thing on overflow: the number of characters it tried to -# create (as per SUSv3) -if test "x$ac_cv_func_asprintf" != "xyes" && \ - test "x$ac_cv_func_vsnprintf" = "xyes" ; then - AC_MSG_CHECKING([whether vsnprintf returns correct values on overflow]) - AC_RUN_IFELSE( - [AC_LANG_PROGRAM([[ -#include -#include -#include - -int x_snprintf(char *str,size_t count,const char *fmt,...) -{ - size_t ret; va_list ap; - va_start(ap, fmt); ret = vsnprintf(str, count, fmt, ap); va_end(ap); - return ret; -} - ]], [[ - char x[1]; - exit(x_snprintf(x, 1, "%s %d", "hello", 12345) == 11 ? 0 : 1); - ]])], - [AC_MSG_RESULT([yes])], - [ - AC_MSG_RESULT([no]) - AC_DEFINE([BROKEN_SNPRINTF], [1], - [Define if your snprintf is busted]) - AC_MSG_WARN([****** Your vsnprintf() function is broken, complain to your vendor]) - ], - [ AC_MSG_WARN([cross compiling: Assuming working vsnprintf()]) ] - ) -fi - -# On systems where [v]snprintf is broken, but is declared in stdio, -# check that the fmt argument is const char * or just char *. -# This is only useful for when BROKEN_SNPRINTF -AC_MSG_CHECKING([whether snprintf can declare const char *fmt]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include -int snprintf(char *a, size_t b, const char *c, ...) { return 0; } - ]], [[ - snprintf(0, 0, 0); - ]])], - [AC_MSG_RESULT([yes]) - AC_DEFINE([SNPRINTF_CONST], [const], - [Define as const if snprintf() can declare const char *fmt])], - [AC_MSG_RESULT([no]) - AC_DEFINE([SNPRINTF_CONST], [/* not const */])]) - -# Check for missing getpeereid (or equiv) support -NO_PEERCHECK="" -if test "x$ac_cv_func_getpeereid" != "xyes" -a "x$ac_cv_func_getpeerucred" != "xyes"; then - AC_MSG_CHECKING([whether system supports SO_PEERCRED getsockopt]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include -#include ]], [[int i = SO_PEERCRED;]])], - [ AC_MSG_RESULT([yes]) - AC_DEFINE([HAVE_SO_PEERCRED], [1], [Have PEERCRED socket option]) - ], [AC_MSG_RESULT([no]) - NO_PEERCHECK=1 - ]) -fi - -dnl see whether mkstemp() requires XXXXXX -if test "x$ac_cv_func_mkdtemp" = "xyes" ; then -AC_MSG_CHECKING([for (overly) strict mkstemp]) -AC_RUN_IFELSE( - [AC_LANG_PROGRAM([[ -#include - ]], [[ - char template[]="conftest.mkstemp-test"; - if (mkstemp(template) == -1) - exit(1); - unlink(template); - exit(0); - ]])], - [ - AC_MSG_RESULT([no]) - ], - [ - AC_MSG_RESULT([yes]) - AC_DEFINE([HAVE_STRICT_MKSTEMP], [1], [Silly mkstemp()]) - ], - [ - AC_MSG_RESULT([yes]) - AC_DEFINE([HAVE_STRICT_MKSTEMP]) - ] -) -fi - -if test "x$ac_cv_func_getaddrinfo" = "xyes" && \ - test "x$check_for_hpux_broken_getaddrinfo" = "x1"; then - AC_MSG_CHECKING([if getaddrinfo seems to work]) - AC_RUN_IFELSE( - [AC_LANG_PROGRAM([[ -#include -#include -#include -#include -#include - -#define TEST_PORT "2222" - ]], [[ - int err, sock; - struct addrinfo *gai_ai, *ai, hints; - char ntop[NI_MAXHOST], strport[NI_MAXSERV], *name = NULL; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_PASSIVE; - - err = getaddrinfo(name, TEST_PORT, &hints, &gai_ai); - if (err != 0) { - fprintf(stderr, "getaddrinfo failed (%s)", gai_strerror(err)); - exit(1); - } - - for (ai = gai_ai; ai != NULL; ai = ai->ai_next) { - if (ai->ai_family != AF_INET6) - continue; - - err = getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, - sizeof(ntop), strport, sizeof(strport), - NI_NUMERICHOST|NI_NUMERICSERV); - - if (err != 0) { - if (err == EAI_SYSTEM) - perror("getnameinfo EAI_SYSTEM"); - else - fprintf(stderr, "getnameinfo failed: %s\n", - gai_strerror(err)); - exit(2); - } - - sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); - if (sock < 0) - perror("socket"); - if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { - if (errno == EBADF) - exit(3); - } - } - exit(0); - ]])], - [ - AC_MSG_RESULT([yes]) - ], - [ - AC_MSG_RESULT([no]) - AC_DEFINE([BROKEN_GETADDRINFO]) - ], - [ - AC_MSG_RESULT([cross-compiling, assuming yes]) - ] - ) -fi - -if test "x$ac_cv_func_getaddrinfo" = "xyes" && \ - test "x$check_for_aix_broken_getaddrinfo" = "x1"; then - AC_MSG_CHECKING([if getaddrinfo seems to work]) - AC_RUN_IFELSE( - [AC_LANG_PROGRAM([[ -#include -#include -#include -#include -#include - -#define TEST_PORT "2222" - ]], [[ - int err, sock; - struct addrinfo *gai_ai, *ai, hints; - char ntop[NI_MAXHOST], strport[NI_MAXSERV], *name = NULL; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_PASSIVE; - - err = getaddrinfo(name, TEST_PORT, &hints, &gai_ai); - if (err != 0) { - fprintf(stderr, "getaddrinfo failed (%s)", gai_strerror(err)); - exit(1); - } - - for (ai = gai_ai; ai != NULL; ai = ai->ai_next) { - if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) - continue; - - err = getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, - sizeof(ntop), strport, sizeof(strport), - NI_NUMERICHOST|NI_NUMERICSERV); - - if (ai->ai_family == AF_INET && err != 0) { - perror("getnameinfo"); - exit(2); - } - } - exit(0); - ]])], - [ - AC_MSG_RESULT([yes]) - AC_DEFINE([AIX_GETNAMEINFO_HACK], [1], - [Define if you have a getaddrinfo that fails - for the all-zeros IPv6 address]) - ], - [ - AC_MSG_RESULT([no]) - AC_DEFINE([BROKEN_GETADDRINFO]) - ], - [ - AC_MSG_RESULT([cross-compiling, assuming no]) - ] - ) -fi - -# Check for PAM libs -PAM_MSG="no" -AC_ARG_WITH([pam], - [ --with-pam Enable PAM support ], - [ - if test "x$withval" != "xno" ; then - if test "x$ac_cv_header_security_pam_appl_h" != "xyes" && \ - test "x$ac_cv_header_pam_pam_appl_h" != "xyes" ; then - AC_MSG_ERROR([PAM headers not found]) - fi - - saved_LIBS="$LIBS" - AC_CHECK_LIB([dl], [dlopen], , ) - AC_CHECK_LIB([pam], [pam_set_item], , [AC_MSG_ERROR([*** libpam missing])]) - AC_CHECK_FUNCS([pam_getenvlist]) - AC_CHECK_FUNCS([pam_putenv]) - LIBS="$saved_LIBS" - - PAM_MSG="yes" - - IKEDLIBS="$IKEDLIBS -lpam" - AC_DEFINE([USE_PAM], [1], - [Define if you want to enable PAM support]) - - if test $ac_cv_lib_dl_dlopen = yes; then - case "$LIBS" in - *-ldl*) - # libdl already in LIBS - ;; - *) - IKEDLIBS="$IKEDLIBS -ldl" - ;; - esac - fi - fi - ] -) - -# Check for older PAM -if test "x$PAM_MSG" = "xyes" ; then - # Check PAM strerror arguments (old PAM) - AC_MSG_CHECKING([whether pam_strerror takes only one argument]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include -#if defined(HAVE_SECURITY_PAM_APPL_H) -#include -#elif defined (HAVE_PAM_PAM_APPL_H) -#include -#endif - ]], [[ -(void)pam_strerror((pam_handle_t *)NULL, -1); - ]])], [AC_MSG_RESULT([no])], [ - AC_DEFINE([HAVE_OLD_PAM], [1], - [Define if you have an old version of PAM - which takes only one argument to pam_strerror]) - AC_MSG_RESULT([yes]) - PAM_MSG="yes (old library)" - - ]) -fi - -# Check for long long datatypes -AC_CHECK_TYPES([long long, unsigned long long, long double]) - -# Check datatype sizes -AC_CHECK_SIZEOF([short int], [2]) -AC_CHECK_SIZEOF([int], [4]) -AC_CHECK_SIZEOF([long int], [4]) -AC_CHECK_SIZEOF([long long int], [8]) - -AC_CHECK_TYPES([float_t], [], [], [[#include ]]) - -# Sanity check long long for some platforms (AIX) -if test "x$ac_cv_sizeof_long_long_int" = "x4" ; then - ac_cv_sizeof_long_long_int=0 -fi - -# compute LLONG_MIN and LLONG_MAX if we don't know them. -if test -z "$have_llong_max"; then - AC_MSG_CHECKING([for max value of long long]) - AC_RUN_IFELSE( - [AC_LANG_PROGRAM([[ -#include -/* Why is this so damn hard? */ -#ifdef __GNUC__ -# undef __GNUC__ -#endif -#define __USE_ISOC99 -#include -#define DATA "conftest.llminmax" -#define my_abs(a) ((a) < 0 ? ((a) * -1) : (a)) - -/* - * printf in libc on some platforms (eg old Tru64) does not understand %lld so - * we do this the hard way. - */ -static int -fprint_ll(FILE *f, long long n) -{ - unsigned int i; - int l[sizeof(long long) * 8]; - - if (n < 0) - if (fprintf(f, "-") < 0) - return -1; - for (i = 0; n != 0; i++) { - l[i] = my_abs(n % 10); - n /= 10; - } - do { - if (fprintf(f, "%d", l[--i]) < 0) - return -1; - } while (i != 0); - if (fprintf(f, " ") < 0) - return -1; - return 0; -} - ]], [[ - FILE *f; - long long i, llmin, llmax = 0; - - if((f = fopen(DATA,"w")) == NULL) - exit(1); - -#if defined(LLONG_MIN) && defined(LLONG_MAX) - fprintf(stderr, "Using system header for LLONG_MIN and LLONG_MAX\n"); - llmin = LLONG_MIN; - llmax = LLONG_MAX; -#else - fprintf(stderr, "Calculating LLONG_MIN and LLONG_MAX\n"); - /* This will work on one's complement and two's complement */ - for (i = 1; i > llmax; i <<= 1, i++) - llmax = i; - llmin = llmax + 1LL; /* wrap */ -#endif - - /* Sanity check */ - if (llmin + 1 < llmin || llmin - 1 < llmin || llmax + 1 > llmax - || llmax - 1 > llmax || llmin == llmax || llmin == 0 - || llmax == 0 || llmax < LONG_MAX || llmin > LONG_MIN) { - fprintf(f, "unknown unknown\n"); - exit(2); - } - - if (fprint_ll(f, llmin) < 0) - exit(3); - if (fprint_ll(f, llmax) < 0) - exit(4); - if (fclose(f) < 0) - exit(5); - exit(0); - ]])], - [ - llong_min=`$AWK '{print $1}' conftest.llminmax` - llong_max=`$AWK '{print $2}' conftest.llminmax` - - AC_MSG_RESULT([$llong_max]) - AC_DEFINE_UNQUOTED([LLONG_MAX], [${llong_max}LL], - [max value of long long calculated by configure]) - AC_MSG_CHECKING([for min value of long long]) - AC_MSG_RESULT([$llong_min]) - AC_DEFINE_UNQUOTED([LLONG_MIN], [${llong_min}LL], - [min value of long long calculated by configure]) - ], - [ - AC_MSG_RESULT([not found]) - ], - [ - AC_MSG_WARN([cross compiling: not checking]) - ] - ) -fi - - -# More checks for data types -AC_CACHE_CHECK([for u_int type], ac_cv_have_u_int, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ u_int a; a = 1;]])], - [ ac_cv_have_u_int="yes" ], [ ac_cv_have_u_int="no" - ]) -]) -if test "x$ac_cv_have_u_int" = "xyes" ; then - AC_DEFINE([HAVE_U_INT], [1], [define if you have u_int data type]) - have_u_int=1 -fi - -AC_CACHE_CHECK([for intXX_t types], ac_cv_have_intxx_t, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ int8_t a; int16_t b; int32_t c; a = b = c = 1;]])], - [ ac_cv_have_intxx_t="yes" ], [ ac_cv_have_intxx_t="no" - ]) -]) -if test "x$ac_cv_have_intxx_t" = "xyes" ; then - AC_DEFINE([HAVE_INTXX_T], [1], [define if you have intxx_t data type]) - have_intxx_t=1 -fi - -if (test -z "$have_intxx_t" && \ - test "x$ac_cv_header_stdint_h" = "xyes") -then - AC_MSG_CHECKING([for intXX_t types in stdint.h]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ int8_t a; int16_t b; int32_t c; a = b = c = 1;]])], - [ - AC_DEFINE([HAVE_INTXX_T]) - AC_MSG_RESULT([yes]) - ], [ AC_MSG_RESULT([no]) - ]) -fi - -AC_CACHE_CHECK([for int64_t type], ac_cv_have_int64_t, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include -#ifdef HAVE_STDINT_H -# include -#endif -#include -#ifdef HAVE_SYS_BITYPES_H -# include -#endif - ]], [[ -int64_t a; a = 1; - ]])], - [ ac_cv_have_int64_t="yes" ], [ ac_cv_have_int64_t="no" - ]) -]) -if test "x$ac_cv_have_int64_t" = "xyes" ; then - AC_DEFINE([HAVE_INT64_T], [1], [define if you have int64_t data type]) -fi - -AC_CACHE_CHECK([for u_intXX_t types], ac_cv_have_u_intxx_t, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ u_int8_t a; u_int16_t b; u_int32_t c; a = b = c = 1;]])], - [ ac_cv_have_u_intxx_t="yes" ], [ ac_cv_have_u_intxx_t="no" - ]) -]) -if test "x$ac_cv_have_u_intxx_t" = "xyes" ; then - AC_DEFINE([HAVE_U_INTXX_T], [1], [define if you have u_intxx_t data type]) - have_u_intxx_t=1 -fi - -if test -z "$have_u_intxx_t" ; then - AC_MSG_CHECKING([for u_intXX_t types in sys/socket.h]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ u_int8_t a; u_int16_t b; u_int32_t c; a = b = c = 1;]])], - [ - AC_DEFINE([HAVE_U_INTXX_T]) - AC_MSG_RESULT([yes]) - ], [ AC_MSG_RESULT([no]) - ]) -fi - -AC_CACHE_CHECK([for u_int64_t types], ac_cv_have_u_int64_t, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ u_int64_t a; a = 1;]])], - [ ac_cv_have_u_int64_t="yes" ], [ ac_cv_have_u_int64_t="no" - ]) -]) -if test "x$ac_cv_have_u_int64_t" = "xyes" ; then - AC_DEFINE([HAVE_U_INT64_T], [1], [define if you have u_int64_t data type]) - have_u_int64_t=1 -fi - -if test -z "$have_u_int64_t" ; then - AC_MSG_CHECKING([for u_int64_t type in sys/bitypes.h]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ u_int64_t a; a = 1]])], - [ - AC_DEFINE([HAVE_U_INT64_T]) - AC_MSG_RESULT([yes]) - ], [ AC_MSG_RESULT([no]) - ]) -fi - -if test -z "$have_u_intxx_t" ; then - AC_CACHE_CHECK([for uintXX_t types], ac_cv_have_uintxx_t, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include - ]], [[ - uint8_t a; - uint16_t b; - uint32_t c; - a = b = c = 1; - ]])], - [ ac_cv_have_uintxx_t="yes" ], [ ac_cv_have_uintxx_t="no" - ]) - ]) - if test "x$ac_cv_have_uintxx_t" = "xyes" ; then - AC_DEFINE([HAVE_UINTXX_T], [1], - [define if you have uintxx_t data type]) - fi -fi - -if test -z "$have_uintxx_t" ; then - AC_MSG_CHECKING([for uintXX_t types in stdint.h]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ uint8_t a; uint16_t b; uint32_t c; a = b = c = 1;]])], - [ - AC_DEFINE([HAVE_UINTXX_T]) - AC_MSG_RESULT([yes]) - ], [ AC_MSG_RESULT([no]) - ]) -fi - -if (test -z "$have_u_intxx_t" || test -z "$have_intxx_t" && \ - test "x$ac_cv_header_sys_bitypes_h" = "xyes") -then - AC_MSG_CHECKING([for intXX_t and u_intXX_t types in sys/bitypes.h]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include - ]], [[ - int8_t a; int16_t b; int32_t c; - u_int8_t e; u_int16_t f; u_int32_t g; - a = b = c = e = f = g = 1; - ]])], - [ - AC_DEFINE([HAVE_U_INTXX_T]) - AC_DEFINE([HAVE_INTXX_T]) - AC_MSG_RESULT([yes]) - ], [AC_MSG_RESULT([no]) - ]) -fi - - -AC_CACHE_CHECK([for u_char], ac_cv_have_u_char, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ u_char foo; foo = 125; ]])], - [ ac_cv_have_u_char="yes" ], [ ac_cv_have_u_char="no" - ]) -]) -if test "x$ac_cv_have_u_char" = "xyes" ; then - AC_DEFINE([HAVE_U_CHAR], [1], [define if you have u_char data type]) -fi -## - -#TYPE_SOCKLEN_T - -## -AC_CHECK_TYPES([sig_atomic_t], , , [#include ]) -AC_CHECK_TYPES([fsblkcnt_t, fsfilcnt_t], , , [ -#include -#ifdef HAVE_SYS_BITYPES_H -#include -#endif -#ifdef HAVE_SYS_STATFS_H -#include -#endif -#ifdef HAVE_SYS_STATVFS_H -#include -#endif -]) - -AC_CHECK_TYPES([in_addr_t, in_port_t], , , -[#include -#include ]) - -AC_CACHE_CHECK([for size_t], ac_cv_have_size_t, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ size_t foo; foo = 1235; ]])], - [ ac_cv_have_size_t="yes" ], [ ac_cv_have_size_t="no" - ]) -]) -if test "x$ac_cv_have_size_t" = "xyes" ; then - AC_DEFINE([HAVE_SIZE_T], [1], [define if you have size_t data type]) -fi - -AC_CACHE_CHECK([for ssize_t], ac_cv_have_ssize_t, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ ssize_t foo; foo = 1235; ]])], - [ ac_cv_have_ssize_t="yes" ], [ ac_cv_have_ssize_t="no" - ]) -]) -if test "x$ac_cv_have_ssize_t" = "xyes" ; then - AC_DEFINE([HAVE_SSIZE_T], [1], [define if you have ssize_t data type]) -fi - -AC_CACHE_CHECK([for clock_t], ac_cv_have_clock_t, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ clock_t foo; foo = 1235; ]])], - [ ac_cv_have_clock_t="yes" ], [ ac_cv_have_clock_t="no" - ]) -]) -if test "x$ac_cv_have_clock_t" = "xyes" ; then - AC_DEFINE([HAVE_CLOCK_T], [1], [define if you have clock_t data type]) -fi - -AC_CACHE_CHECK([for sa_family_t], ac_cv_have_sa_family_t, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include -#include - ]], [[ sa_family_t foo; foo = 1235; ]])], - [ ac_cv_have_sa_family_t="yes" ], - [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include -#include -#include - ]], [[ sa_family_t foo; foo = 1235; ]])], - [ ac_cv_have_sa_family_t="yes" ], - [ ac_cv_have_sa_family_t="no" ] - ) - ]) -]) -if test "x$ac_cv_have_sa_family_t" = "xyes" ; then - AC_DEFINE([HAVE_SA_FAMILY_T], [1], - [define if you have sa_family_t data type]) -fi - -AC_CACHE_CHECK([for pid_t], ac_cv_have_pid_t, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ pid_t foo; foo = 1235; ]])], - [ ac_cv_have_pid_t="yes" ], [ ac_cv_have_pid_t="no" - ]) -]) -if test "x$ac_cv_have_pid_t" = "xyes" ; then - AC_DEFINE([HAVE_PID_T], [1], [define if you have pid_t data type]) -fi - -AC_CACHE_CHECK([for mode_t], ac_cv_have_mode_t, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ mode_t foo; foo = 1235; ]])], - [ ac_cv_have_mode_t="yes" ], [ ac_cv_have_mode_t="no" - ]) -]) -if test "x$ac_cv_have_mode_t" = "xyes" ; then - AC_DEFINE([HAVE_MODE_T], [1], [define if you have mode_t data type]) -fi - - -AC_CACHE_CHECK([for struct sockaddr_storage], ac_cv_have_struct_sockaddr_storage, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include -#include - ]], [[ struct sockaddr_storage s; ]])], - [ ac_cv_have_struct_sockaddr_storage="yes" ], - [ ac_cv_have_struct_sockaddr_storage="no" - ]) -]) -if test "x$ac_cv_have_struct_sockaddr_storage" = "xyes" ; then - AC_DEFINE([HAVE_STRUCT_SOCKADDR_STORAGE], [1], - [define if you have struct sockaddr_storage data type]) -fi - -AC_CACHE_CHECK([for struct sockaddr_in6], ac_cv_have_struct_sockaddr_in6, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include -#include - ]], [[ struct sockaddr_in6 s; s.sin6_family = 0; ]])], - [ ac_cv_have_struct_sockaddr_in6="yes" ], - [ ac_cv_have_struct_sockaddr_in6="no" - ]) -]) -if test "x$ac_cv_have_struct_sockaddr_in6" = "xyes" ; then - AC_DEFINE([HAVE_STRUCT_SOCKADDR_IN6], [1], - [define if you have struct sockaddr_in6 data type]) -fi - -AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include -#include - ]], [[ struct in6_addr s; s.s6_addr[0] = 0; ]])], - [ ac_cv_have_struct_in6_addr="yes" ], - [ ac_cv_have_struct_in6_addr="no" - ]) -]) -if test "x$ac_cv_have_struct_in6_addr" = "xyes" ; then - AC_DEFINE([HAVE_STRUCT_IN6_ADDR], [1], - [define if you have struct in6_addr data type]) - -dnl Now check for sin6_scope_id - AC_CHECK_MEMBERS([struct sockaddr_in6.sin6_scope_id], , , - [ -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#include - ]) -fi - -AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include -#include -#include - ]], [[ struct addrinfo s; s.ai_flags = AI_PASSIVE; ]])], - [ ac_cv_have_struct_addrinfo="yes" ], - [ ac_cv_have_struct_addrinfo="no" - ]) -]) -if test "x$ac_cv_have_struct_addrinfo" = "xyes" ; then - AC_DEFINE([HAVE_STRUCT_ADDRINFO], [1], - [define if you have struct addrinfo data type]) -fi - -AC_CACHE_CHECK([for struct timeval], ac_cv_have_struct_timeval, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ struct timeval tv; tv.tv_sec = 1;]])], - [ ac_cv_have_struct_timeval="yes" ], - [ ac_cv_have_struct_timeval="no" - ]) -]) -if test "x$ac_cv_have_struct_timeval" = "xyes" ; then - AC_DEFINE([HAVE_STRUCT_TIMEVAL], [1], [define if you have struct timeval]) - have_struct_timeval=1 -fi - -AC_CHECK_TYPES([struct timespec]) - -# We need int64_t or else certian parts of the compile will fail. -if test "x$ac_cv_have_int64_t" = "xno" && \ - test "x$ac_cv_sizeof_long_int" != "x8" && \ - test "x$ac_cv_sizeof_long_long_int" = "x0" ; then - echo "OpenSSH requires int64_t support. Contact your vendor or install" - echo "an alternative compiler (I.E., GCC) before continuing." - echo "" - exit 1; -else -dnl test snprintf (broken on SCO w/gcc) - AC_RUN_IFELSE( - [AC_LANG_SOURCE([[ -#include -#include -#ifdef HAVE_SNPRINTF -main() -{ - char buf[50]; - char expected_out[50]; - int mazsize = 50 ; -#if (SIZEOF_LONG_INT == 8) - long int num = 0x7fffffffffffffff; -#else - long long num = 0x7fffffffffffffffll; -#endif - strcpy(expected_out, "9223372036854775807"); - snprintf(buf, mazsize, "%lld", num); - if(strcmp(buf, expected_out) != 0) - exit(1); - exit(0); -} -#else -main() { exit(0); } -#endif - ]])], [ true ], [ AC_DEFINE([BROKEN_SNPRINTF]) ], - AC_MSG_WARN([cross compiling: Assuming working snprintf()]) - ) -fi - -AC_CACHE_CHECK([for ss_family field in struct sockaddr_storage], - ac_cv_have_ss_family_in_struct_ss, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include -#include - ]], [[ struct sockaddr_storage s; s.ss_family = 1; ]])], - [ ac_cv_have_ss_family_in_struct_ss="yes" ], - [ ac_cv_have_ss_family_in_struct_ss="no" ]) -]) -if test "x$ac_cv_have_ss_family_in_struct_ss" = "xyes" ; then - AC_DEFINE([HAVE_SS_FAMILY_IN_SS], [1], [Fields in struct sockaddr_storage]) -fi - -AC_CACHE_CHECK([for __ss_family field in struct sockaddr_storage], - ac_cv_have___ss_family_in_struct_ss, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include -#include - ]], [[ struct sockaddr_storage s; s.__ss_family = 1; ]])], - [ ac_cv_have___ss_family_in_struct_ss="yes" ], - [ ac_cv_have___ss_family_in_struct_ss="no" - ]) -]) -if test "x$ac_cv_have___ss_family_in_struct_ss" = "xyes" ; then - AC_DEFINE([HAVE___SS_FAMILY_IN_SS], [1], - [Fields in struct sockaddr_storage]) -fi - -AC_CACHE_CHECK([for pw_class field in struct passwd], - ac_cv_have_pw_class_in_struct_passwd, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ struct passwd p; p.pw_class = 0; ]])], - [ ac_cv_have_pw_class_in_struct_passwd="yes" ], - [ ac_cv_have_pw_class_in_struct_passwd="no" - ]) -]) -if test "x$ac_cv_have_pw_class_in_struct_passwd" = "xyes" ; then - AC_DEFINE([HAVE_PW_CLASS_IN_PASSWD], [1], - [Define if your password has a pw_class field]) -fi - -AC_CACHE_CHECK([for pw_expire field in struct passwd], - ac_cv_have_pw_expire_in_struct_passwd, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ struct passwd p; p.pw_expire = 0; ]])], - [ ac_cv_have_pw_expire_in_struct_passwd="yes" ], - [ ac_cv_have_pw_expire_in_struct_passwd="no" - ]) -]) -if test "x$ac_cv_have_pw_expire_in_struct_passwd" = "xyes" ; then - AC_DEFINE([HAVE_PW_EXPIRE_IN_PASSWD], [1], - [Define if your password has a pw_expire field]) -fi - -AC_CACHE_CHECK([for pw_change field in struct passwd], - ac_cv_have_pw_change_in_struct_passwd, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ struct passwd p; p.pw_change = 0; ]])], - [ ac_cv_have_pw_change_in_struct_passwd="yes" ], - [ ac_cv_have_pw_change_in_struct_passwd="no" - ]) -]) -if test "x$ac_cv_have_pw_change_in_struct_passwd" = "xyes" ; then - AC_DEFINE([HAVE_PW_CHANGE_IN_PASSWD], [1], - [Define if your password has a pw_change field]) -fi - -dnl make sure we're using the real structure members and not defines -AC_CACHE_CHECK([for msg_accrights field in struct msghdr], - ac_cv_have_accrights_in_msghdr, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include -#include -#include - ]], [[ -#ifdef msg_accrights -#error "msg_accrights is a macro" -exit(1); -#endif -struct msghdr m; -m.msg_accrights = 0; -exit(0); - ]])], - [ ac_cv_have_accrights_in_msghdr="yes" ], - [ ac_cv_have_accrights_in_msghdr="no" ] - ) -]) -if test "x$ac_cv_have_accrights_in_msghdr" = "xyes" ; then - AC_DEFINE([HAVE_ACCRIGHTS_IN_MSGHDR], [1], - [Define if your system uses access rights style - file descriptor passing]) -fi - -AC_MSG_CHECKING([if struct statvfs.f_fsid is integral type]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include -#include -#ifdef HAVE_SYS_TIME_H -# include -#endif -#ifdef HAVE_SYS_MOUNT_H -#include -#endif -#ifdef HAVE_SYS_STATVFS_H -#include -#endif - ]], [[ struct statvfs s; s.f_fsid = 0; ]])], - [ AC_MSG_RESULT([yes]) ], - [ AC_MSG_RESULT([no]) - - AC_MSG_CHECKING([if fsid_t has member val]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include -#include - ]], [[ fsid_t t; t.val[0] = 0; ]])], - [ AC_MSG_RESULT([yes]) - AC_DEFINE([FSID_HAS_VAL], [1], [fsid_t has member val]) ], - [ AC_MSG_RESULT([no]) ]) - - AC_MSG_CHECKING([if f_fsid has member __val]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include -#include - ]], [[ fsid_t t; t.__val[0] = 0; ]])], - [ AC_MSG_RESULT([yes]) - AC_DEFINE([FSID_HAS___VAL], [1], [fsid_t has member __val]) ], - [ AC_MSG_RESULT([no]) ]) -]) - -AC_CACHE_CHECK([for msg_control field in struct msghdr], - ac_cv_have_control_in_msghdr, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include -#include -#include - ]], [[ -#ifdef msg_control -#error "msg_control is a macro" -exit(1); -#endif -struct msghdr m; -m.msg_control = 0; -exit(0); - ]])], - [ ac_cv_have_control_in_msghdr="yes" ], - [ ac_cv_have_control_in_msghdr="no" ] - ) -]) -if test "x$ac_cv_have_control_in_msghdr" = "xyes" ; then - AC_DEFINE([HAVE_CONTROL_IN_MSGHDR], [1], - [Define if your system uses ancillary data style - file descriptor passing]) -fi - -AC_CACHE_CHECK([if libc defines __progname], ac_cv_libc_defines___progname, [ - AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], - [[ extern char *__progname; printf("%s", __progname); ]])], - [ ac_cv_libc_defines___progname="yes" ], - [ ac_cv_libc_defines___progname="no" - ]) -]) -if test "x$ac_cv_libc_defines___progname" = "xyes" ; then - AC_DEFINE([HAVE___PROGNAME], [1], [Define if libc defines __progname]) -fi - -AC_CACHE_CHECK([whether $CC implements __FUNCTION__], ac_cv_cc_implements___FUNCTION__, [ - AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ printf("%s", __FUNCTION__); ]])], - [ ac_cv_cc_implements___FUNCTION__="yes" ], - [ ac_cv_cc_implements___FUNCTION__="no" - ]) -]) -if test "x$ac_cv_cc_implements___FUNCTION__" = "xyes" ; then - AC_DEFINE([HAVE___FUNCTION__], [1], - [Define if compiler implements __FUNCTION__]) -fi - -AC_CACHE_CHECK([whether $CC implements __func__], ac_cv_cc_implements___func__, [ - AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ printf("%s", __func__); ]])], - [ ac_cv_cc_implements___func__="yes" ], - [ ac_cv_cc_implements___func__="no" - ]) -]) -if test "x$ac_cv_cc_implements___func__" = "xyes" ; then - AC_DEFINE([HAVE___func__], [1], [Define if compiler implements __func__]) -fi - -AC_CACHE_CHECK([whether va_copy exists], ac_cv_have_va_copy, [ - AC_LINK_IFELSE([AC_LANG_PROGRAM([[ -#include -va_list x,y; - ]], [[ va_copy(x,y); ]])], - [ ac_cv_have_va_copy="yes" ], - [ ac_cv_have_va_copy="no" - ]) -]) -if test "x$ac_cv_have_va_copy" = "xyes" ; then - AC_DEFINE([HAVE_VA_COPY], [1], [Define if va_copy exists]) -fi - -AC_CACHE_CHECK([whether __va_copy exists], ac_cv_have___va_copy, [ - AC_LINK_IFELSE([AC_LANG_PROGRAM([[ -#include -va_list x,y; - ]], [[ __va_copy(x,y); ]])], - [ ac_cv_have___va_copy="yes" ], [ ac_cv_have___va_copy="no" - ]) -]) -if test "x$ac_cv_have___va_copy" = "xyes" ; then - AC_DEFINE([HAVE___VA_COPY], [1], [Define if __va_copy exists]) -fi - -AC_CACHE_CHECK([whether getopt has optreset support], - ac_cv_have_getopt_optreset, [ - AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include ]], - [[ extern int optreset; optreset = 0; ]])], - [ ac_cv_have_getopt_optreset="yes" ], - [ ac_cv_have_getopt_optreset="no" - ]) -]) -if test "x$ac_cv_have_getopt_optreset" = "xyes" ; then - AC_DEFINE([HAVE_GETOPT_OPTRESET], [1], - [Define if your getopt(3) defines and uses optreset]) -fi - -##chl part -AC_CHECK_MEMBERS([struct stat.st_flags], , , - [ #include - #include ] -) - -AC_CHECK_MEMBERS([struct stat.st_mtim], , , - [ #include - #include ] -) - -AC_CHECK_MEMBERS([struct stat.st_mtimespec], , , - [ #include - #include ] -) - -AC_CHECK_MEMBERS([struct sockaddr.sa_len], , , - [ #include - #include - #include ] -) - -AC_CHECK_MEMBERS([struct sockaddr_storage.ss_len], , , - [ #include - #include - #include ] -) - -AC_CHECK_MEMBERS([struct sockaddr_in.sin_len], , , - [ #include - #include - #include ] -) - -AC_CHECK_MEMBERS([struct sockaddr_in6.sin6_len], , , - [ #include - #include - #include ] -) -##chl part - - -# Looking for programs, paths and files - -PRIVSEP_PATH=/var/empty -AC_ARG_WITH([privsep-path], - [ --with-privsep-path=xxx Path for privilege separation chroot (default=/var/empty)], - [ - if test -n "$withval" && test "x$withval" != "xno" && \ - test "x${withval}" != "xyes"; then - PRIVSEP_PATH=$withval - fi - ] -) -AC_SUBST([PRIVSEP_PATH]) - -# Options from here on. Some of these are preset by platform above -AC_ARG_WITH([mantype], - [ --with-mantype=man|cat|doc Set man page type], - [ - case "$withval" in - man|cat|doc) - MANTYPE=$withval - ;; - *) - AC_MSG_ERROR([invalid man type: $withval]) - ;; - esac - ] -) -if test -z "$MANTYPE"; then - TestPath="/usr/bin${PATH_SEPARATOR}/usr/ucb" - AC_PATH_PROGS([NROFF], [nroff awf], [/bin/false], [$TestPath]) - if ${NROFF} -mdoc ${srcdir}/iked/iked.8 >/dev/null 2>&1; then - MANTYPE=doc - elif ${NROFF} -man ${srcdir}/iked/iked.8 >/dev/null 2>&1; then - MANTYPE=man - else - MANTYPE=cat - fi -fi -AC_SUBST([MANTYPE]) -if test "$MANTYPE" = "doc"; then - mansubdir=man; -else - mansubdir=$MANTYPE; -fi -AC_SUBST([mansubdir]) - -# Whether to enable BSD auth support -BSD_AUTH_MSG=no -AC_ARG_WITH([bsd-auth], - [ --with-bsd-auth Enable BSD auth support], - [ - if test "x$withval" != "xno" ; then - AC_DEFINE([BSD_AUTH], [1], - [Define if you have BSD auth support]) - BSD_AUTH_MSG=yes - fi - ] -) - -AC_ARG_WITH([privsep-user], - [ --with-privsep-user=user Specify non-privileged user for privilege separation], - [ - if test -n "$withval" && test "x$withval" != "xno" && \ - test "x${withval}" != "xyes"; then - IKED_USER=$withval - fi - ] -) -AC_DEFINE_UNQUOTED([IKED_USER], ["$IKED_USER"], - [non-privileged user for privilege separation]) -AC_SUBST([IKED_USER]) - -_sysconfdir=`eval echo ${sysconfdir}` -case $_sysconfdir in -NONE/*) - _sysconfdir=`echo $_sysconfdir | sed "s~NONE~$ac_default_prefix~"` ;; -esac - -ikedconf=`eval echo ${_sysconfdir}/iked.conf` -AC_DEFINE_UNQUOTED([IKED_CONFIG], ["$ikedconf"], - [configuration file path]) -AC_SUBST([IKED_CONFIG]) - -ikedca=`eval echo ${_sysconfdir}/iked/` -AC_DEFINE_UNQUOTED([IKED_CA], ["$ikedca"], - [certificate path]) -AC_SUBST([IKED_CA]) - -# Where to place iked.sock -sockdir=/var/run -# make sure the directory exists -if test ! -d $sockdir ; then - sockdir=`eval echo ${_sysconfdir}` -fi - -AC_ARG_WITH([sock-dir], - [ --with-sock-dir=PATH Specify location of iked.sock file], - [ - if test -n "$withval" && test "x$withval" != "xno" && \ - test "x${withval}" != "xyes"; then - sockdir=$withval - if test ! -d $sockdir ; then - AC_MSG_WARN([** no $sockdir directory on this system **]) - fi - fi - ] -) - -AC_DEFINE_UNQUOTED([IKED_SOCKDIR], ["$sockdir"], - [Specify location of iked.sock]) -AC_SUBST([sockdir]) - -if test "x$ac_cv_func_getaddrinfo" != "xyes" ; then - TEST_SSH_IPV6=no -else - TEST_SSH_IPV6=yes -fi -AC_CHECK_DECL([BROKEN_GETADDRINFO], [TEST_SSH_IPV6=no]) -AC_SUBST([TEST_SSH_IPV6], [$TEST_SSH_IPV6]) - -AC_EXEEXT - -AC_MSG_CHECKING([if inet_net_pton will link]) -AC_LINK_IFELSE([AC_LANG_PROGRAM([[ -#include -#include -#include -#include -#include - ]], [[ - inet_net_pton (0, 0, 0, 0, 0); - ]])], - AC_MSG_RESULT([yes]), - [AC_MSG_RESULT([no]) - saved_LIBS="$LIBS" - LIBS="$LIBS -lresolv" - AC_MSG_CHECKING([for inet_net_pton in -lresolv]) - AC_LINK_IFELSE([AC_LANG_PROGRAM([[ -#include -#include -#include -#include -#include - ]], [[ - inet_net_pton (0, 0, 0, 0, 0); - ]])], - [AC_MSG_RESULT([yes])], - [LIBS="$saved_LIBS" - AC_MSG_RESULT([no])]) - ]) - - -# Search for OpenSSL -saved_CPPFLAGS="$CPPFLAGS" -saved_LDFLAGS="$LDFLAGS" -AC_ARG_WITH([ssl-dir], - [ --with-ssl-dir=PATH Specify path to OpenSSL installation ], - [ - if test "x$withval" != "xno" ; then - case "$withval" in - # Relative paths - ./*|../*) withval="`pwd`/$withval" - esac - if test -d "$withval/lib"; then - if test -n "${need_dash_r}"; then - LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}" - else - LDFLAGS="-L${withval}/lib ${LDFLAGS}" - fi - elif test -d "$withval/lib64"; then - if test -n "${need_dash_r}"; then - LDFLAGS="-L${withval}/lib64 -R${withval}/lib64 ${LDFLAGS}" - else - LDFLAGS="-L${withval}/lib64 ${LDFLAGS}" - fi - else - if test -n "${need_dash_r}"; then - LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}" - else - LDFLAGS="-L${withval} ${LDFLAGS}" - fi - fi - if test -d "$withval/include"; then - CPPFLAGS="-I${withval}/include ${CPPFLAGS}" - else - CPPFLAGS="-I${withval} ${CPPFLAGS}" - fi - fi - ] -) -LIBS="-lcrypto -lssl $LIBS" -AC_TRY_LINK_FUNC([RAND_add], [AC_DEFINE([HAVE_OPENSSL], [1], - [Define if your ssl headers are included - with #include ])], - [ - dnl Check default openssl install dir - if test -n "${need_dash_r}"; then - LDFLAGS="-L/usr/local/ssl/lib -R/usr/local/ssl/lib ${saved_LDFLAGS}" - else - LDFLAGS="-L/usr/local/ssl/lib ${saved_LDFLAGS}" - fi - CPPFLAGS="-I/usr/local/ssl/include ${saved_CPPFLAGS}" - AC_CHECK_HEADER([openssl/opensslv.h], , - [AC_MSG_ERROR([*** OpenSSL headers missing - please install first or check config.log ***])]) - AC_TRY_LINK_FUNC([RAND_add], [AC_DEFINE([HAVE_OPENSSL])], - [ - AC_MSG_ERROR([*** Can't find recent OpenSSL libcrypto (see config.log for details) ***]) - ] - ) - ] -) - -# Determine OpenSSL header version -AC_MSG_CHECKING([OpenSSL header version]) -AC_RUN_IFELSE( - [AC_LANG_PROGRAM([[ -#include -#include -#include -#define DATA "conftest.sslincver" - ]], [[ - FILE *fd; - int rc; - - fd = fopen(DATA,"w"); - if(fd == NULL) - exit(1); - - if ((rc = fprintf(fd ,"%x (%s)\n", OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT)) <0) - exit(1); - - exit(0); - ]])], - [ - ssl_header_ver=`cat conftest.sslincver` - AC_MSG_RESULT([$ssl_header_ver]) - ], - [ - AC_MSG_RESULT([not found]) - AC_MSG_ERROR([OpenSSL version header not found.]) - ], - [ - AC_MSG_WARN([cross compiling: not checking]) - ] -) - -# Determine OpenSSL library version -AC_MSG_CHECKING([OpenSSL library version]) -AC_RUN_IFELSE( - [AC_LANG_PROGRAM([[ -#include -#include -#include -#include -#define DATA "conftest.ssllibver" - ]], [[ - FILE *fd; - int rc; - - fd = fopen(DATA,"w"); - if(fd == NULL) - exit(1); - - if ((rc = fprintf(fd ,"%x (%s)\n", SSLeay(), SSLeay_version(SSLEAY_VERSION))) <0) - exit(1); - - exit(0); - ]])], - [ - ssl_library_ver=`cat conftest.ssllibver` - AC_MSG_RESULT([$ssl_library_ver]) - ], - [ - AC_MSG_RESULT([not found]) - AC_MSG_ERROR([OpenSSL library not found.]) - ], - [ - AC_MSG_WARN([cross compiling: not checking]) - ] -) - -AC_ARG_WITH([openssl-header-check], - [ --without-openssl-header-check Disable OpenSSL version consistency check], - [ if test "x$withval" = "xno" ; then - openssl_check_nonfatal=1 - fi - ] -) - -# Sanity check OpenSSL headers -AC_MSG_CHECKING([whether OpenSSL's headers match the library]) -AC_RUN_IFELSE( - [AC_LANG_PROGRAM([[ -#include -#include - ]], [[ - exit(SSLeay() == OPENSSL_VERSION_NUMBER ? 0 : 1); - ]])], - [ - AC_MSG_RESULT([yes]) - ], - [ - AC_MSG_RESULT([no]) - if test "x$openssl_check_nonfatal" = "x"; then - AC_MSG_ERROR([Your OpenSSL headers do not match your -library. Check config.log for details. -If you are sure your installation is consistent, you can disable the check -by running "./configure --without-openssl-header-check". -Also see contrib/findssl.sh for help identifying header/library mismatches. -]) - else - AC_MSG_WARN([Your OpenSSL headers do not match your -library. Check config.log for details. -Also see contrib/findssl.sh for help identifying header/library mismatches.]) - fi - ], - [ - AC_MSG_WARN([cross compiling: not checking]) - ] -) - -AC_MSG_CHECKING([if programs using OpenSSL functions will link]) -AC_LINK_IFELSE( - [AC_LANG_PROGRAM([[ #include ]], - [[ SSLeay_add_all_algorithms(); ]])], - [ - AC_MSG_RESULT([yes]) - ], - [ - AC_MSG_RESULT([no]) - saved_LIBS="$LIBS" - LIBS="$LIBS -ldl" - AC_MSG_CHECKING([if programs using OpenSSL need -ldl]) - AC_LINK_IFELSE( - [AC_LANG_PROGRAM([[ #include ]], - [[ SSLeay_add_all_algorithms(); ]])], - [ - AC_MSG_RESULT([yes]) - ], - [ - AC_MSG_RESULT([no]) - LIBS="$saved_LIBS" - ] - ) - ] -) - -# Some systems want crypt() from libcrypt, *not* the version in OpenSSL, -# because the system crypt() is more featureful. -if test "x$check_for_libcrypt_before" = "x1"; then - AC_CHECK_LIB([crypt], [crypt]) -fi - -# Some Linux systems (Slackware) need crypt() from libcrypt, *not* the -# version in OpenSSL. -if test "x$check_for_libcrypt_later" = "x1"; then - AC_CHECK_LIB([crypt], [crypt], [LIBS="$LIBS -lcrypt"]) -fi - -# Determine OpenSSL configuration directory -SSLDIR=${_sysconfdir}/ssl -AC_MSG_CHECKING([OpenSSL configuration directory]) -AC_RUN_IFELSE( - [AC_LANG_PROGRAM([[ -#include -#include -#define HEADER_CRYPTLIB_H -#include -#include -#define DATA "conftest.sslincdir" - ]], [[ - FILE *fp; - int rc; - - if ((fp = fopen(DATA,"w")) == NULL) - return(1); - - if ((rc = fprintf(fp, "%s\n", OPENSSLDIR)) <0) - return(1); - fclose(fp); - ]])], - [ - SSLDIR=`cat conftest.sslincdir` - ], - [], []) -AC_MSG_RESULT([$SSLDIR]) -AC_DEFINE_UNQUOTED([SSLDIR], ["$SSLDIR"], [OpenSSL Configuration Directory]) -AC_SUBST([SSLDIR]) - -### Configure cryptographic random number support - -# Check wheter OpenSSL seeds itself -AC_MSG_CHECKING([whether OpenSSL's PRNG is internally seeded]) -AC_RUN_IFELSE( - [AC_LANG_PROGRAM([[ -#include -#include - ]], [[ - exit(RAND_status() == 1 ? 0 : 1); - ]])], - [ - OPENSSL_SEEDS_ITSELF=yes - AC_MSG_RESULT([yes]) - ], - [ - AC_MSG_RESULT([no]) - ], - [ - AC_MSG_WARN([cross compiling: assuming yes]) - # This is safe, since we will fatal() at runtime if - # OpenSSL is not seeded correctly. - OPENSSL_SEEDS_ITSELF=yes - ] -) - -# PRNGD TCP socket -AC_ARG_WITH([prngd-port], - [ --with-prngd-port=PORT read entropy from PRNGD/EGD TCP localhost:PORT], - [ - case "$withval" in - no) - withval="" - ;; - [[0-9]]*) - ;; - *) - AC_MSG_ERROR([You must specify a numeric port number for --with-prngd-port]) - ;; - esac - if test ! -z "$withval" ; then - PRNGD_PORT="$withval" - AC_DEFINE_UNQUOTED([PRNGD_PORT], [$PRNGD_PORT], - [Port number of PRNGD/EGD random number socket]) - fi - ] -) - -# PRNGD Unix domain socket -AC_ARG_WITH([prngd-socket], - [ --with-prngd-socket=FILE read entropy from PRNGD/EGD socket FILE (default=/var/run/egd-pool)], - [ - case "$withval" in - yes) - withval="/var/run/egd-pool" - ;; - no) - withval="" - ;; - /*) - ;; - *) - AC_MSG_ERROR([You must specify an absolute path to the entropy socket]) - ;; - esac - - if test ! -z "$withval" ; then - if test ! -z "$PRNGD_PORT" ; then - AC_MSG_ERROR([You may not specify both a PRNGD/EGD port and socket]) - fi - if test ! -r "$withval" ; then - AC_MSG_WARN([Entropy socket is not readable]) - fi - PRNGD_SOCKET="$withval" - AC_DEFINE_UNQUOTED([PRNGD_SOCKET], ["$PRNGD_SOCKET"], - [Location of PRNGD/EGD random number socket]) - fi - ], - [ - # Check for existing socket only if we don't have a random device already - if test "x$OPENSSL_SEEDS_ITSELF" != "xyes" ; then - AC_MSG_CHECKING([for PRNGD/EGD socket]) - # Insert other locations here - for sock in /var/run/egd-pool /dev/egd-pool /etc/entropy; do - if test -r $sock && $TEST_MINUS_S_SH -c "test -S $sock -o -p $sock" ; then - PRNGD_SOCKET="$sock" - AC_DEFINE_UNQUOTED([PRNGD_SOCKET], ["$PRNGD_SOCKET"]) - break; - fi - done - if test ! -z "$PRNGD_SOCKET" ; then - AC_MSG_RESULT([$PRNGD_SOCKET]) - else - AC_MSG_RESULT([not found]) - fi - fi - ] -) - -# Which randomness source do we use? -if test ! -z "$PRNGD_PORT" ; then - RAND_MSG="PRNGd port $PRNGD_PORT" -elif test ! -z "$PRNGD_SOCKET" ; then - RAND_MSG="PRNGd socket $PRNGD_SOCKET" -elif test ! -z "$OPENSSL_SEEDS_ITSELF" ; then - AC_DEFINE([OPENSSL_PRNG_ONLY], [1], - [Define if you want OpenSSL's internally seeded PRNG only]) - RAND_MSG="OpenSSL internal ONLY" -else - AC_MSG_ERROR([OpenSSH has no source of random numbers. Please configure OpenSSL with an entropy source or re-run configure using one of the --with-prngd-port or --with-prngd-socket options]) -fi - -# Search for libevent -saved_CPPFLAGS="$CPPFLAGS" -saved_LDFLAGS="$LDFLAGS" -AC_ARG_WITH([libevent-dir], - [ --with-libevent-dir=PATH Specify path to libevent installation ], - [ - if test "x$withval" != "xno" ; then - case "$withval" in - ./*|../*) - # Relative paths - withval="`pwd`/$withval" - ;; - */libevent1|*/libevent1/|*/libevent|*/libevent/) - AC_MSG_CHECKING([libevent header path]) - evincludes=`echo $withval | sed s/lib/include/` - if test -d "$evincludes"; then - CPPFLAGS="-I${evincludes} ${CPPFLAGS}" - AC_MSG_RESULT([${evincludes}]) - else - AC_MSG_RESULT([not found]) - fi - ;; - esac - if test -d "$withval/lib"; then - if test -n "${need_dash_r}"; then - LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}" - else - LDFLAGS="-L${withval}/lib ${LDFLAGS}" - fi - elif test -d "$withval/lib64"; then - if test -n "${need_dash_r}"; then - LDFLAGS="-L${withval}/lib64 -R${withval}/lib64 ${LDFLAGS}" - else - LDFLAGS="-L${withval}/lib64 ${LDFLAGS}" - fi - else - if test -n "${need_dash_r}"; then - LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}" - else - LDFLAGS="-L${withval} ${LDFLAGS}" - fi - fi - if test -d "$withval/include"; then - CPPFLAGS="-I${withval}/include ${CPPFLAGS}" - else - CPPFLAGS="-I${withval} ${CPPFLAGS}" - fi - fi - ] -) - -LIBS="-levent $LIBS" - -# Determine libevent header version -AC_MSG_CHECKING([libevent header version]) -AC_RUN_IFELSE( - [AC_LANG_PROGRAM([[ -#include -#include -#include -#include -#define DATA "conftest.libeventincver" - ]], [[ - FILE *fd; - int rc; - - fd = fopen(DATA,"w"); - if(fd == NULL) - return(1); - - if ((rc = fprintf(fd ,"%s\n", _EVENT_VERSION)) <0) - return(1); - - return(0); - ]])], - [ - libevent_header_ver=`cat conftest.libeventincver` - AC_MSG_RESULT([$libevent_header_ver]) - ], - [ - AC_MSG_RESULT([not found]) - AC_MSG_ERROR([libevent version header not found. ${CPPFLAGS}]) - ], - [ - AC_MSG_WARN([cross compiling: not checking]) - ] -) - -# Determine libevent library version -AC_MSG_CHECKING([libevent library version]) -AC_RUN_IFELSE( - [AC_LANG_PROGRAM([[ -#include -#include -#include -#define DATA "conftest.libeventlibver" - ]], [[ - FILE *fd; - int rc; - - fd = fopen(DATA,"w"); - if(fd == NULL) - return(1); - - if ((rc = fprintf(fd ,"%s\n", event_get_version())) <0) - return(1); - - return(0); - ]])], - [ - libevent_library_ver=`cat conftest.libeventlibver` - AC_MSG_RESULT([$libevent_library_ver]) - ], - [ - AC_MSG_RESULT([not found]) - AC_MSG_ERROR([libevent library not found.]) - ], - [ - AC_MSG_WARN([cross compiling: not checking]) - ] -) - -libevent_major_version=`cat conftest.libeventlibver|head -c1 || echo 1` - -AC_DEFINE_UNQUOTED([LIBEVENT_MAJOR_VERSION], [$libevent_major_version], [Define libevent major version]) - -AC_ARG_WITH([libevent-header-check], - [ --without-libevent-header-check Disable libevent version consistency check], - [ if test "x$withval" = "xno" ; then - libevent_check_nonfatal=1 - fi - ] -) - -# Sanity check libevent headers -AC_MSG_CHECKING([whether libevent's headers match the library]) -AC_RUN_IFELSE( - [AC_LANG_PROGRAM([[ -#if LIBEVENT_MAJOR_VERSION < 2 -#include -#else -#include -#endif -#include -#include - ]], [[ - exit(strcmp(event_get_version(), _EVENT_VERSION) == 0 ? 0 : 1); - ]])], - [ - AC_MSG_RESULT([yes]) - ], - [ - AC_MSG_RESULT([no]) - if test "x$libevent_check_nonfatal" = "x"; then - AC_MSG_ERROR([Your libevent headers do not match your -library. Check config.log for details. -If you are sure your installation is consistent, you can disable the check -by running "./configure --without-libevent-header-check".]) - else - AC_MSG_WARN([Your libevent headers do not match your -library. Check config.log for details.]) - fi - ], - [ - AC_MSG_WARN([cross compiling: not checking]) - ] -) - -AC_MSG_CHECKING([if programs using libevent functions will link]) -AC_LINK_IFELSE( - [AC_LANG_PROGRAM([[ -#if LIBEVENT_MAJOR_VERSION < 2 -#include -#else -#include -#endif - ]], [[ - event_base_new(); - ]])], - [ - AC_MSG_RESULT([yes]) - ], - [ - AC_MSG_RESULT([no]) - ] -) - -#AC_SEARCH_LIBS([bufferevent_openssl_socket_new], [event event_openssl], []) - -AC_CHECK_HEADER([$pfkeyv2_h], [ - AC_MSG_CHECKING([for extended PFKEv2 crypto algorithms]) - AC_RUN_IFELSE([AC_LANG_PROGRAM([[ - #include - #include - #include <$pfkeyv2_h> - #include - #define DATA "conftest.pfkeyv2alg" - ]], [[ - FILE *fp; - int i; - struct pfkeyalgs { - const char *name; - const char *openbsd; - const char *target; - } algs[] = { - { "blowfish", "SADB_X_EALG_BLF", -#if defined(SADB_X_EALG_BLF) - "SADB_X_EALG_BLF" -#elif defined(SADB_X_EALG_BLOWFISHCBC) - "SADB_X_EALG_BLOWFISHCBC" -#else - NULL -#endif - }, - { "aes", "SADB_X_EALG_AES", -#if defined(SADB_X_EALG_AES) - "SADB_X_EALG_AES" -#elif defined(SADB_X_EALG_AESCBC) - "SADB_X_EALG_AESCBC" -#elif defined(SADB_X_EALG_RIJNDAEL) - "SADB_X_EALG_RIJNDAELCBC" -#else - NULL -#endif - }, - { "cast", "SADB_X_EALG_CAST", -#if defined(SADB_X_EALG_CAST) - "SADB_X_EALG_CAST" -#elif defined(SADB_X_EALG_CAST128CBC) - "SADB_X_EALG_CAST128CBC" -#else - NULL -#endif - }, - { "aes-gcm16", "SADB_X_EALG_AESGCM16", -#if defined(SADB_X_EALG_AESGCM16) - "SADB_X_EALG_AESGCM16" -#elif defined(SADB_X_EALG_AES_GCM_ICV16) - "SADB_X_EALG_AES_GCM_ICV16" -#else - NULL -#endif - }, - { "sha2-256", "SADB_X_AALG_SHA2_256", -#if defined(SADB_X_AALG_SHA2_256) - "SADB_X_AALG_SHA2_256", -#elif defined(SADB_X_AALG_SHA2_256HMAC) - "SADB_X_AALG_SHA2_256HMAC" -#else - NULL -#endif - }, - { "sha2-384", "SADB_X_AALG_SHA2_384", -#if defined(SADB_X_AALG_SHA2_384) - "SADB_X_AALG_SHA2_384", -#elif defined(SADB_X_AALG_SHA2_384HMAC) - "SADB_X_AALG_SHA2_384HMAC" -#else - NULL -#endif - }, - { "sha2-512", "SADB_X_AALG_SHA2_512", -#if defined(SADB_X_AALG_SHA2_512) - "SADB_X_AALG_SHA2_512", -#elif defined(SADB_X_AALG_SHA2_512HMAC) - "SADB_X_AALG_SHA2_512HMAC" -#else - NULL -#endif - }, - { NULL } - }; - - if ((fp = fopen(DATA, "w")) == NULL) - return(1); - - for (i = 0; algs[i].name != NULL; i++) { - if (algs[i].target == NULL) - continue; - (void)fprintf(fp, "%s\t%s\t%s\n", - algs[i].name, - algs[i].openbsd, - algs[i].target); - } - - fclose(fp); - ]])], - [ - pfkeyv2_algs=`$AWK '{ print $1 }' conftest.pfkeyv2alg` - p_values="" - p_flags="" - - for i in $pfkeyv2_algs; do - p_alg=`$GREP $i conftest.pfkeyv2alg` - p_name=`echo $p_alg | $AWK '{print $1}'` - p_openbsd=`echo $p_alg | $AWK '{print $2}'` - p_target=`echo $p_alg | $AWK '{print $3}'` - p_values="$p_values $p_name" - if test "x$p_openbsd" != "x$p_target"; then - # XXX AC_DEFINE_UNQUOTED will not work here - p_flags="$p_flags -D$p_openbsd=$p_target" - fi - done - - PFKEY_CPPFLAGS=`eval echo $p_flags` - AC_SUBST([PFKEY_CPPFLAGS]) - - AC_MSG_RESULT([$p_values]) - ], - [ - AC_MSG_RESULT([failed]) - AC_MSG_ERROR([PFKEv2 compilation failed.]) - ], []) -], [], [ -#include -#include -]) - -if test "x$OPENSSL" != "x"; then - AC_DEFINE_UNQUOTED([PATH_OPENSSL], ["$OPENSSL"], - [Path to OpenSSL binary]) -fi - -if test "x$TAR" != "x"; then - AC_DEFINE_UNQUOTED([PATH_TAR], ["$TAR"], [Path to TAR binary]) -fi -if test "x$ZIP" != "x"; then - AC_DEFINE_UNQUOTED([PATH_ZIP], ["$ZIP"], [Path to ZIP binary]) -fi - -AC_DEFINE_UNQUOTED([PREFIX], ["$prefix"], [Root directory prefix]) - -AC_DEFINE([_GNU_SOURCE], [1], [Enable GNU Extensions]) - -dnl Adding -Werror to CFLAGS early prevents configure tests from running. -dnl Add now. -CFLAGS="$CFLAGS $werror_flags $debug_flags" - -LIBS="$LIBS ${IKEDLIBS}" - -AC_CONFIG_FILES([Makefile - openbsd-compat/Makefile - iked/Makefile - ikectl/Makefile - ]) - -AC_OUTPUT - -# Print summary of options - -# Someone please show me a better way :) -A=`eval echo ${prefix}` ; A=`eval echo ${A}` -B=`eval echo ${bindir}` ; B=`eval echo ${B}` -C=`eval echo ${sbindir}` ; C=`eval echo ${C}` -D=`eval echo ${sysconfdir}` ; D=`eval echo ${D}` -F=`eval echo ${mandir}/${mansubdir}X` ; F=`eval echo ${F}` -G=`eval echo ${sockdir}` ; G=`eval echo ${G}` -H=`eval echo ${PRIVSEP_PATH}` ; H=`eval echo ${H}` -I=`eval echo ${ikedconf}` ; I=`eval echo ${I}` -J=`eval echo ${ikedca}` ; J=`eval echo ${J}` - -echo "" -echo "OpenIKED has been configured with the following options:" -echo " User binaries: $B" -echo " System binaries: $C" -echo " Configuration files: $D" -echo " Configuration files: $D" -echo " Manual pages: $F" -echo " iked.sock dir: $G" -echo " Privilege separation chroot path: $H" -echo " OpenIKED configuration file: $I" -echo " OpenIKED CA and keys directory: $J" -echo " Manpage format: $MANTYPE" -#echo " PAM support: $PAM_MSG" -#echo " OSF SIA support: $SIA_MSG" -#echo " KerberosV support: $KRB5_MSG" -#echo " SELinux support: $SELINUX_MSG" -#echo " Smartcard support: $SCARD_MSG" -#echo " S/KEY support: $SKEY_MSG" -#echo " TCP Wrappers support: $TCPW_MSG" -#echo " MD5 password support: $MD5_MSG" -#echo " libedit support: $LIBEDIT_MSG" -#echo " Solaris process contract support: $SPC_MSG" -#echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG" -#echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" -echo " BSD Auth support: $BSD_AUTH_MSG" -echo " Random number source: $RAND_MSG" - -echo "" - -echo " Host: ${host}" -echo " Compiler: ${CC}" -echo " Compiler flags: ${CFLAGS}" -echo "Preprocessor flags: ${CPPFLAGS}" -echo " Linker flags: ${LDFLAGS}" -echo " Libraries: ${LIBS}" -echo "" - -if test "x$MAKE_PACKAGE_SUPPORTED" = "xyes" ; then - echo "SVR4 style packages are supported with \"make package\"" - echo "" -fi - -if test "x$PAM_MSG" = "xyes" ; then - echo "PAM is enabled. You may need to install a PAM control file " - echo "for sshd, otherwise password authentication may fail. " - echo "Example PAM control files can be found in the contrib/ " - echo "subdirectory" - echo "" -fi - -if test ! -z "$NO_PEERCHECK" ; then - echo "WARNING: the operating system that you are using does not" - echo "appear to support getpeereid(), getpeerucred() or the" - echo "SO_PEERCRED getsockopt() option. These facilities are used to" - echo "enforce security checks to prevent unauthorised connections to" - echo "ssh-agent. Their absence increases the risk that a malicious" - echo "user can connect to your agent." - echo "" -fi - -if test "$AUDIT_MODULE" = "bsm" ; then - echo "WARNING: BSM audit support is currently considered EXPERIMENTAL." - echo "See the Solaris section in README.platform for details." -fi diff --git a/ikectl/.cvsignore b/ikectl/.cvsignore deleted file mode 100644 index 536efe1..0000000 --- a/ikectl/.cvsignore +++ /dev/null @@ -1,5 +0,0 @@ -.cvsignore -.deps -Makefile -Makefile.am -Makefile.in diff --git a/ikectl/CVS/Entries b/ikectl/CVS/Entries index 76336d8..20653f9 100644 --- a/ikectl/CVS/Entries +++ b/ikectl/CVS/Entries @@ -1,8 +1,8 @@ -/Makefile/1.2/Result of merge+Fri Jan 11 08:23:23 2013// -/ikeca.c/1.25/Result of merge// -/ikectl.c/1.16/Result of merge// -/parser.c/1.12/Result of merge// -/ikeca.cnf/1.5/Sat Dec 15 14:53:03 2012// -/ikectl.8/1.20/Mon Jan 14 14:11:49 2013// -/parser.h/1.12/Mon Jan 14 14:11:49 2013// +/Makefile/1.4/Thu Oct 8 08:38:35 2015// +/ikeca.c/1.37/Thu Oct 8 08:38:35 2015// +/ikeca.cnf/1.6/Thu Oct 8 08:38:35 2015// +/ikectl.8/1.24/Thu Oct 8 08:38:35 2015// +/ikectl.c/1.20/Thu Oct 8 08:38:35 2015// +/parser.c/1.14/Thu Oct 8 08:38:35 2015// +/parser.h/1.13/Thu Oct 8 08:38:35 2015// D diff --git a/ikectl/Makefile b/ikectl/Makefile new file mode 100644 index 0000000..eab9819 --- /dev/null +++ b/ikectl/Makefile @@ -0,0 +1,22 @@ +# $OpenBSD: Makefile,v 1.4 2015/08/19 12:25:59 reyk Exp $ + +.PATH: ${.CURDIR}/../iked + +PROG= ikectl +SRCS= log.c ikeca.c ikectl.c parser.c util.c + +MAN= ikectl.8 + +LDADD= -lutil -lcrypto +DPADD= ${LIBUTIL} +CFLAGS+= -Wall -I${.CURDIR} -I${.CURDIR}/../iked +CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes +CFLAGS+= -Wmissing-declarations +CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual +CFLAGS+= -Wsign-compare + +#distribution: +# ${INSTALL} -C -g wheel -m 0644 ${.CURDIR}/ikeca.cnf \ +# ${DESTDIR}/etc/ssl/ikeca.cnf + +.include diff --git a/ikectl/Makefile.am b/ikectl/Makefile.am deleted file mode 100644 index 4f44e8b..0000000 --- a/ikectl/Makefile.am +++ /dev/null @@ -1,45 +0,0 @@ -sbin_PROGRAMS= ikectl - -ikectl_SOURCES= ikeca.c ikectl.c parser.c $(top_srcdir)/iked/log.c -ikectl_CFLAGS= - -LIBCOMPAT= $(top_builddir)/openbsd-compat/libopenbsd-compat.a -LDADD= $(LIBCOMPAT) -CPPFLAGS= -include $(top_srcdir)/openbsd-compat/includes.h \ - -I$(top_srcdir)/openbsd-compat \ - -I$(top_srcdir)/iked \ - -I$(srcdir) @CPPFLAGS@ @DEFS@ -MANPAGES= ikectl.8.out -MANPAGES_IN= ikectl.8 -EXTRA_DIST= $(MANPAGES_IN) ikeca.cnf -CLEANFILES= $(CONFIGFILES) $(MANPAGES) -PATHSUBS= -e 's|/etc/iked/|$(sysconfdir)/iked/|g' \ - -e 's|/usr/libexec|$(libexecdir)|g' \ - -e 's|/var/run/iked.sock|$(sockdir)/iked.sock|g' -FIXPATHSCMD= $(SED) $(PATHSUBS) - -$(MANPAGES): $(MANPAGES_IN) - if test "$(MANTYPE)" = "cat"; then \ - manpage=$(srcdir)/`echo $@ | sed 's/\.[1-9]\.out$$/\.0/'`; \ - else \ - manpage=$(srcdir)/`echo $@ | sed 's/\.out$$//'`; \ - fi; \ - if test "$(MANTYPE)" = "man"; then \ - $(FIXPATHSCMD) $${manpage} | $(AWK) -f $(top_srcdir)/mdoc2man.awk > $@; \ - else \ - $(FIXPATHSCMD) $${manpage} > $@; \ - fi - -install-exec-hook: $(MANPAGES) - $(MKDIR_P) $(DESTDIR)$(sysconfdir)/iked/ - $(MKDIR_P) $(DESTDIR)$(SSLDIR) - $(MKDIR_P) $(DESTDIR)$(sbindir) - $(MKDIR_P) $(DESTDIR)$(mandir)/$(mansubdir)8 - - @if [ ! -f $(DESTDIR)$(SSLDIR)/ikeca.cnf ]; then \ - $(INSTALL) -m 644 ikeca.cnf $(DESTDIR)$(SSLDIR)/ikeca.cnf; \ - else \ - echo "$(DESTDIR)$(SSLDIR)/ikeca.cnf already exists, install will not overwrite"; \ - fi - - $(INSTALL) -m 644 ikectl.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ikectl.8 diff --git a/ikectl/ikeca.c b/ikectl/ikeca.c index 4b84090..8ecfd3e 100644 --- a/ikectl/ikeca.c +++ b/ikectl/ikeca.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikeca.c,v 1.25 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: ikeca.c,v 1.37 2015/08/19 21:07:23 reyk Exp $ */ /* * Copyright (c) 2010 Jonathan Gray @@ -16,7 +16,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include #include #include @@ -29,6 +28,7 @@ #include #include #include +#include #include #include @@ -52,7 +52,7 @@ #endif #ifndef PATH_OPENSSL -#define PATH_OPENSSL "/usr/sbin/openssl" +#define PATH_OPENSSL "/usr/bin/openssl" #endif #ifndef PATH_ZIP #define PATH_ZIP "/usr/local/bin/zip" @@ -82,13 +82,39 @@ struct { { "/private", 0700 } }; -int ca_sign(struct ca *, char *, int, char *); +/* explicitly list allowed variables */ +const char *ca_env[][2] = { + { "$ENV::CADB", NULL }, + { "$ENV::CERTFQDN", NULL }, + { "$ENV::CERTIP", NULL }, + { "$ENV::CERTPATHLEN", NULL }, + { "$ENV::CERTUSAGE", NULL }, + { "$ENV::CERT_C", NULL }, + { "$ENV::CERT_CN", NULL }, + { "$ENV::CERT_EMAIL", NULL }, + { "$ENV::CERT_L", NULL }, + { "$ENV::CERT_O", NULL }, + { "$ENV::CERT_OU", NULL }, + { "$ENV::CERT_ST", NULL }, + { "$ENV::EXTCERTUSAGE", NULL }, + { "$ENV::NSCERTTYPE", NULL }, + { NULL } +}; + +int ca_sign(struct ca *, char *, int); int ca_request(struct ca *, char *); -int ca_newpass(char *, char *); -char * ca_readpass(char *, size_t *); +void ca_newpass(char *, char *); +char *ca_readpass(char *, size_t *); int fcopy(char *, char *, mode_t); +void fcopy_env(const char *, const char *, mode_t); int rm_dir(char *); -int ca_hier(char *); +void ca_hier(char *); +void ca_setenv(const char *, const char *); +void ca_clrenv(void); +void ca_setcnf(struct ca *, const char *); + +/* util.c */ +int expand_string(char *, size_t, const char *, const char *); int ca_delete(struct ca *ca) @@ -173,10 +199,13 @@ ca_request(struct ca *ca, char *keyname) char cmd[PATH_MAX * 2]; char path[PATH_MAX]; + ca_setenv("$ENV::CERT_CN", keyname); + ca_setcnf(ca, keyname); + snprintf(path, sizeof(path), "%s/private/%s.csr", ca->sslpath, keyname); - snprintf(cmd, sizeof(cmd), "env CERT_CN=%s %s req %s-new" + snprintf(cmd, sizeof(cmd), "%s req %s-new" " -key %s/private/%s.key -out %s -config %s", - keyname, PATH_OPENSSL, ca->batch, ca->sslpath, keyname, + PATH_OPENSSL, ca->batch, ca->sslpath, keyname, path, ca->sslcnf); system(cmd); @@ -186,40 +215,40 @@ ca_request(struct ca *ca, char *keyname) } int -ca_sign(struct ca *ca, char *keyname, int type, char *envargs) +ca_sign(struct ca *ca, char *keyname, int type) { char cmd[PATH_MAX * 2]; - char hostname[MAXHOSTNAMELEN]; + char hostname[HOST_NAME_MAX+1]; char name[128]; + const char *extensions = NULL; strlcpy(name, keyname, sizeof(name)); - if (envargs == NULL) - envargs = ""; - if (type == HOST_IPADDR) { - snprintf(cmd, sizeof(cmd), "env CERTIP=%s%s %s x509 -req" - " -days 365 -in %s/private/%s.csr" - " -CA %s/ca.crt -CAkey %s/private/ca.key -CAcreateserial" - " -extfile %s -extensions x509v3_IPAddr -out %s/%s.crt" - " -passin file:%s", name, envargs, PATH_OPENSSL, - ca->sslpath, keyname, ca->sslpath, ca->sslpath, - ca->extcnf, ca->sslpath, keyname, ca->passfile); + ca_setenv("$ENV::CERTIP", name); + extensions = "x509v3_IPAddr"; } else if (type == HOST_FQDN) { if (!strcmp(keyname, "local")) { if (gethostname(hostname, sizeof(hostname))) err(1, "gethostname"); strlcpy(name, hostname, sizeof(name)); } - snprintf(cmd, sizeof(cmd), "env CERTFQDN=%s%s %s x509 -req" - " -days 365 -in %s/private/%s.csr" - " -CA %s/ca.crt -CAkey %s/private/ca.key -CAcreateserial" - " -extfile %s -extensions x509v3_FQDN -out %s/%s.crt" - " -passin file:%s", name, envargs, PATH_OPENSSL, - ca->sslpath, keyname, ca->sslpath, ca->sslpath, - ca->extcnf, ca->sslpath, keyname, ca->passfile); - } else - err(1, "unknown host type %d", type); + ca_setenv("$ENV::CERTFQDN", name); + extensions = "x509v3_FQDN"; + } else { + errx(1, "unknown host type %d", type); + } + + ca_setcnf(ca, keyname); + + snprintf(cmd, sizeof(cmd), "%s x509 -req" + " -days 365 -in %s/private/%s.csr" + " -CA %s/ca.crt -CAkey %s/private/ca.key -CAcreateserial" + " -extfile %s -extensions %s -out %s/%s.crt" + " -passin file:%s", + PATH_OPENSSL, + ca->sslpath, keyname, ca->sslpath, ca->sslpath, + ca->extcnf, extensions, ca->sslpath, keyname, ca->passfile); system(cmd); @@ -229,16 +258,20 @@ ca_sign(struct ca *ca, char *keyname, int type, char *envargs) int ca_certificate(struct ca *ca, char *keyname, int type, int action) { - char *envargs = ""; + ca_clrenv(); switch (action) { case CA_SERVER: - envargs = " EXTCERTUSAGE=serverAuth NSCERTTYPE=server" - " CERTUSAGE=digitalSignature,keyEncipherment"; + ca_setenv("$ENV::EXTCERTUSAGE", "serverAuth"); + ca_setenv("$ENV::NSCERTTYPE", "server"); + ca_setenv("$ENV::CERTUSAGE", + "digitalSignature,keyEncipherment"); break; case CA_CLIENT: - envargs = " EXTCERTUSAGE=clientAuth NSCERTTYPE=client" - " CERTUSAGE=digitalSignature,keyAgreement"; + ca_setenv("$ENV::EXTCERTUSAGE", "clientAuth"); + ca_setenv("$ENV::NSCERTTYPE", "client"); + ca_setenv("$ENV::CERTUSAGE", + "digitalSignature,keyAgreement"); break; default: break; @@ -246,7 +279,7 @@ ca_certificate(struct ca *ca, char *keyname, int type, int action) ca_key_create(ca, keyname); ca_request(ca, keyname); - ca_sign(ca, keyname, type, envargs); + ca_sign(ca, keyname, type); return (0); } @@ -313,7 +346,7 @@ ca_cert_install(struct ca *ca, char *keyname, char *dir) return (0); } -int +void ca_newpass(char *passfile, char *password) { FILE *f; @@ -342,8 +375,6 @@ ca_newpass(char *passfile, char *password) fprintf(f, "%s\n%s\n", pass, pass); fclose(f); - - return (0); } int @@ -352,6 +383,8 @@ ca_create(struct ca *ca) char cmd[PATH_MAX * 2]; char path[PATH_MAX]; + ca_clrenv(); + snprintf(path, sizeof(path), "%s/private/ca.key", ca->sslpath); snprintf(cmd, sizeof(cmd), "%s genrsa -aes256 -out" " %s -passout file:%s 2048", PATH_OPENSSL, @@ -359,8 +392,11 @@ ca_create(struct ca *ca) system(cmd); chmod(path, 0600); + ca_setenv("$ENV::CERT_CN", "VPN CA"); + ca_setcnf(ca, "ca"); + snprintf(path, sizeof(path), "%s/private/ca.csr", ca->sslpath); - snprintf(cmd, sizeof(cmd), "env CERT_CN='VPN CA' %s req %s-new" + snprintf(cmd, sizeof(cmd), "%s req %s-new" " -key %s/private/ca.key" " -config %s -out %s -passin file:%s", PATH_OPENSSL, ca->batch, ca->sslpath, ca->sslcnf, path, ca->passfile); @@ -443,8 +479,8 @@ ca_show_certs(struct ca *ca, char *name) err(1, "could not open directory %s", ca->sslpath); while ((de = readdir(dir)) != NULL) { - if (NAMLEN(de) > 4) { - p = de->d_name + NAMLEN(de) - 4; + if (de->d_namlen > 4) { + p = de->d_name + de->d_namlen - 4; if (strcmp(".crt", p) != 0) continue; snprintf(path, sizeof(path), "%s/%s", ca->sslpath, @@ -466,15 +502,16 @@ int fcopy(char *src, char *dst, mode_t mode) { int ifd, ofd; - u_int8_t buf[BUFSIZ]; + uint8_t buf[BUFSIZ]; ssize_t r; if ((ifd = open(src, O_RDONLY)) == -1) err(1, "open %s", src); if ((ofd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) { + int saved_errno = errno; close(ifd); - err(1, "open %s", dst); + errc(1, saved_errno, "open %s", dst); } while ((r = read(ifd, buf, sizeof(buf))) > 0) { @@ -487,6 +524,45 @@ fcopy(char *src, char *dst, mode_t mode) return (r == -1); } +void +fcopy_env(const char *src, const char *dst, mode_t mode) +{ + int ofd = -1, i; + uint8_t buf[BUFSIZ]; + ssize_t r = -1, len; + FILE *ifp = NULL; + int saved_errno; + + if ((ifp = fopen(src, "r")) == NULL) + err(1, "fopen %s", src); + + if ((ofd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) + goto done; + + while (fgets(buf, sizeof(buf), ifp) != NULL) { + for (i = 0; ca_env[i][0] != NULL; i++) { + if (ca_env[i][1] == NULL) + continue; + if (expand_string(buf, sizeof(buf), + ca_env[i][0], ca_env[i][1]) == -1) + errx(1, "env %s value too long", ca_env[i][0]); + } + len = strlen(buf); + if (write(ofd, buf, len) != len) + goto done; + } + + r = 0; + + done: + saved_errno = errno; + close(ofd); + if (ifp != NULL) + fclose(ifp); + if (r == -1) + errc(1, saved_errno, "open %s", dst); +} + int rm_dir(char *path) { @@ -522,13 +598,12 @@ rm_dir(char *path) return (0); } - -int +void ca_hier(char *path) { struct stat st; char dst[PATH_MAX]; - u_int i; + unsigned int i; for (i = 0; i < nitems(hier); i++) { strlcpy(dst, path, sizeof(dst)); @@ -537,8 +612,6 @@ ca_hier(char *path) mkdir(dst, hier[i].mode) != 0) err(1, "failed to create dir %s", dst); } - - return (0); } int @@ -555,12 +628,12 @@ ca_export(struct ca *ca, char *keyname, char *myname, char *password) char dst[PATH_MAX]; char *p; char tpl[] = "/tmp/ikectl.XXXXXXXXXX"; - u_int i; + unsigned int i; int fd; if (keyname != NULL) { if (strlcpy(oname, keyname, sizeof(oname)) >= sizeof(oname)) - err(1, "name too long"); + errx(1, "name too long"); } else { strlcpy(oname, "ca", sizeof(oname)); } @@ -682,7 +755,7 @@ ca_export(struct ca *ca, char *keyname, char *myname, char *password) de->d_name); snprintf(dst, sizeof(dst), "%s/export/%s", p, de->d_name); - fcopy(src, dst, 644); + fcopy(src, dst, 0644); } closedir(dexp); } @@ -741,6 +814,7 @@ ca_revoke(struct ca *ca, char *keyname) struct stat st; char cmd[PATH_MAX * 2]; char path[PATH_MAX]; + char cadb[PATH_MAX]; int fd; char *pass; size_t len; @@ -757,7 +831,7 @@ ca_revoke(struct ca *ca, char *keyname) snprintf(path, sizeof(path), "%s/ikeca.passwd", ca->sslpath); pass = ca_readpass(path, &len); if (pass == NULL) - err(1, "could not open passphrase file"); + errx(1, "could not open passphrase file"); /* create index if it doesn't already exist */ snprintf(path, sizeof(path), "%s/index.txt", ca->sslpath); @@ -770,43 +844,93 @@ ca_revoke(struct ca *ca, char *keyname) err(1, "could not access %s", path); } + snprintf(cadb, sizeof(cadb), "%s/index.txt", ca->sslpath); + ca_setenv("$ENV::CADB", cadb); + ca_setcnf(ca, "ca-revoke"); + if (keyname) { - snprintf(cmd, sizeof(cmd), "env CADB='%s/index.txt' " - " %s ca %s-config %s -keyfile %s/private/ca.key" + snprintf(cmd, sizeof(cmd), + "%s ca %s-config %s -keyfile %s/private/ca.key" " -key %s" " -cert %s/ca.crt" " -md sha1" " -revoke %s/%s.crt", - ca->sslpath, PATH_OPENSSL, ca->batch, ca->sslcnf, + PATH_OPENSSL, ca->batch, ca->sslcnf, ca->sslpath, pass, ca->sslpath, ca->sslpath, keyname); system(cmd); } - snprintf(cmd, sizeof(cmd), "env CADB='%s/index.txt' " - " %s ca %s-config %s -keyfile %s/private/ca.key" + snprintf(cmd, sizeof(cmd), + "%s ca %s-config %s -keyfile %s/private/ca.key" " -key %s" " -gencrl" " -cert %s/ca.crt" " -md sha1" " -crldays 365" " -out %s/ca.crl", - ca->sslpath, PATH_OPENSSL, ca->batch, ca->sslcnf, ca->sslpath, + PATH_OPENSSL, ca->batch, ca->sslcnf, ca->sslpath, pass, ca->sslpath, ca->sslpath); system(cmd); - bzero(pass, len); + explicit_bzero(pass, len); free(pass); return (0); } +void +ca_clrenv(void) +{ + int i; + for (i = 0; ca_env[i][0] != NULL; i++) + ca_env[i][1] = NULL; +} + +void +ca_setenv(const char *key, const char *value) +{ + int i; + + for (i = 0; ca_env[i][0] != NULL; i++) { + if (strcmp(ca_env[i][0], key) == 0) { + if (ca_env[i][1] != NULL) + errx(1, "env %s already set: %s", key, value); + ca_env[i][1] = value; + return; + } + } + errx(1, "env %s invalid", key); +} + +void +ca_setcnf(struct ca *ca, const char *keyname) +{ + struct stat st; + const char *extcnf, *sslcnf; + + if (stat(IKECA_CNF, &st) == 0) { + extcnf = IKECA_CNF; + sslcnf = IKECA_CNF; + } else { + extcnf = X509_CNF; + sslcnf = SSL_CNF; + } + + snprintf(ca->extcnf, sizeof(ca->extcnf), "%s/%s-ext.cnf", + ca->sslpath, keyname); + snprintf(ca->sslcnf, sizeof(ca->sslcnf), "%s/%s-ssl.cnf", + ca->sslpath, keyname); + + fcopy_env(extcnf, ca->extcnf, 0400); + fcopy_env(sslcnf, ca->sslcnf, 0400); +} + struct ca * ca_setup(char *caname, int create, int quiet, char *pass) { struct stat st; struct ca *ca; char path[PATH_MAX]; - u_int32_t rnd[256]; if (stat(PATH_OPENSSL, &st) == -1) err(1, "openssl binary not available"); @@ -822,14 +946,6 @@ ca_setup(char *caname, int create, int quiet, char *pass) if (quiet) strlcpy(ca->batch, "-batch ", sizeof(ca->batch)); - if (stat(IKECA_CNF, &st) == 0) { - strlcpy(ca->extcnf, IKECA_CNF, sizeof(ca->extcnf)); - strlcpy(ca->sslcnf, IKECA_CNF, sizeof(ca->sslcnf)); - } else { - strlcpy(ca->extcnf, X509_CNF, sizeof(ca->extcnf)); - strlcpy(ca->sslcnf, SSL_CNF, sizeof(ca->sslcnf)); - } - if (create == 0 && stat(ca->sslpath, &st) == -1) { free(ca->caname); free(ca); @@ -846,8 +962,5 @@ ca_setup(char *caname, int create, int quiet, char *pass) if (create && stat(ca->passfile, &st) == -1 && errno == ENOENT) ca_newpass(ca->passfile, pass); - arc4random_buf(rnd, sizeof(rnd)); - RAND_seed(rnd, sizeof(rnd)); - return (ca); } diff --git a/ikectl/ikeca.cnf b/ikectl/ikeca.cnf index d71662c..cba9bd1 100644 --- a/ikectl/ikeca.cnf +++ b/ikectl/ikeca.cnf @@ -1,6 +1,6 @@ -# $OpenBSD: ikeca.cnf,v 1.5 2012/10/25 12:35:55 reyk Exp $ +# $OpenBSD: ikeca.cnf,v 1.6 2014/11/22 18:15:41 deraadt Exp $ -RANDFILE = /dev/arandom +RANDFILE = /dev/random CERT_C = DE CERT_ST = Lower Saxony diff --git a/ikectl/ikectl.8 b/ikectl/ikectl.8 index 19caee9..0ea9711 100644 --- a/ikectl/ikectl.8 +++ b/ikectl/ikectl.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ikectl.8,v 1.20 2013/01/08 10:38:19 reyk Exp $ +.\" $OpenBSD: ikectl.8,v 1.24 2015/09/07 15:24:53 sobrado Exp $ .\" .\" Copyright (c) 2007-2013 Reyk Floeter .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: January 8 2013 $ +.Dd $Mdocdate: September 7 2015 $ .Dt IKECTL 8 .Os .Sh NAME @@ -149,7 +149,7 @@ as the currently active CA or into the specified .It Xo .Cm ca Ar name Cm certificate Ar host .Cm create -.Op Ic server \*(Ba client +.Op Ic server | client .Xc Create a private key and certificate for .Ar host @@ -250,21 +250,21 @@ from the named .El .Sh FILES .Bl -tag -width "/var/run/iked.sockXX" -compact -.It /etc/iked/ +.It Pa /etc/iked/ Active configuration. -.It /etc/ssl/ +.It Pa /etc/ssl/ Directory to store the CA files. -.It /usr/share/iked +.It Pa /usr/share/iked/ If this optional directory exists, .Nm will include the contents with the .Cm ca export commands. -.It /var/run/iked.sock -default +.It Pa /var/run/iked.sock +Default .Ux Ns -domain socket used for communication with -.Xr iked 8 +.Xr iked 8 . .El .Sh EXAMPLES First create a new certificate authority: @@ -346,9 +346,9 @@ program first appeared in The .Nm program was written by -.An Reyk Floeter Aq reyk@openbsd.org +.An Reyk Floeter Aq Mt reyk@openbsd.org and -.An Jonathan Gray Aq jsg@openbsd.org . +.An Jonathan Gray Aq Mt jsg@openbsd.org . .Sh CAVEATS For ease of use, the .Ic ca diff --git a/ikectl/ikectl.c b/ikectl/ikectl.c index 5c591fc..d9fd301 100644 --- a/ikectl/ikectl.c +++ b/ikectl/ikectl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikectl.c,v 1.16 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: ikectl.c,v 1.20 2015/08/19 13:30:54 reyk Exp $ */ /* * Copyright (c) 2007-2013 Reyk Floeter @@ -19,12 +19,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include #include -#include "openbsd-compat/sys-queue.h" +#include #include -#include "openbsd-compat/sys-tree.h" +#include #include #include @@ -45,7 +44,7 @@ struct imsgname { void (*func)(struct imsg *); }; -struct imsgname *monitor_lookup(u_int8_t); +struct imsgname *monitor_lookup(uint8_t); void monitor_id(struct imsg *); int monitor(struct imsg *); @@ -313,7 +312,7 @@ main(int argc, char *argv[]) } while (ibuf->w.queued) - if (msgbuf_write(&ibuf->w) < 0) + if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) err(1, "write error"); while (!done) { @@ -344,7 +343,7 @@ main(int argc, char *argv[]) } struct imsgname * -monitor_lookup(u_int8_t type) +monitor_lookup(uint8_t type) { int i; @@ -366,7 +365,7 @@ monitor(struct imsg *imsg) imn = monitor_lookup(imsg->hdr.type); printf("%s: imsg type %u len %u peerid %u pid %d\n", imn->name, imsg->hdr.type, imsg->hdr.len, imsg->hdr.peerid, imsg->hdr.pid); - printf("\ttimestamp: %u, %s", now, ctime(&now)); + printf("\ttimestamp: %lld, %s", (long long)now, ctime(&now)); if (imn->type == -1) done = 1; if (imn->func != NULL) diff --git a/ikectl/parser.c b/ikectl/parser.c index c4a7cb4..5d1e406 100644 --- a/ikectl/parser.c +++ b/ikectl/parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.c,v 1.12 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: parser.c,v 1.14 2015/08/19 13:30:54 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -18,11 +18,10 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include #include -#include "openbsd-compat/sys-queue.h" -#include "openbsd-compat/sys-tree.h" +#include +#include #include #include @@ -284,7 +283,7 @@ parse_addr(const char *word) const struct token * match_token(char *word, const struct token table[]) { - u_int i, match = 0; + unsigned int i, match = 0; const struct token *t = NULL; for (i = 0; table[i].type != ENDTOKEN; i++) { diff --git a/ikectl/parser.h b/ikectl/parser.h index 4281400..250bae0 100644 --- a/ikectl/parser.h +++ b/ikectl/parser.h @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.h,v 1.12 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: parser.h,v 1.13 2015/06/11 18:49:09 reyk Exp $ */ /* * Copyright (c) 2007-2013 Reyk Floeter @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _IKECTL_PARSER_H -#define _IKECTL_PARSER_H +#ifndef IKECTL_PARSER_H +#define IKECTL_PARSER_H enum actions { NONE, @@ -88,4 +88,4 @@ int ca_key_delete(struct ca *, char *); int ca_key_install(struct ca *, char *, char *); int ca_key_import(struct ca *, char *, char *); -#endif /* _IKECTL_PARSER_H */ +#endif /* IKECTL_PARSER_H */ diff --git a/iked/.cvsignore b/iked/.cvsignore index d822aec..3d1e8c4 100644 --- a/iked/.cvsignore +++ b/iked/.cvsignore @@ -1,6 +1,5 @@ .cvsignore .deps -Makefile Makefile.am Makefile.in iked.conf diff --git a/iked/CVS/Entries b/iked/CVS/Entries index ac67746..da5cfbb 100644 --- a/iked/CVS/Entries +++ b/iked/CVS/Entries @@ -1,31 +1,33 @@ -/Makefile/1.8/Result of merge+Fri Jan 11 08:22:53 2013// -/chap_ms.c/1.6/Result of merge// -/crypto.c/1.9/Result of merge// -/iked.8/1.13/Result of merge// -/iked.h/1.56/Result of merge// -/log.c/1.3/Result of merge// -/policy.c/1.23/Result of merge+Fri Jan 11 08:23:08 2013// -/timer.c/1.10/Result of merge// -/util.c/1.18/Result of merge// -/ca.c/1.22/Result of merge+Tue Apr 2 09:13:18 2013// -/chap_ms.h/1.3/Mon Jan 14 14:11:49 2013// -/config.c/1.20/Result of merge+Tue Apr 2 09:13:19 2013// -/control.c/1.12/Result of merge// -/dh.c/1.10/Mon Jan 14 14:11:49 2013// -/dh.h/1.5/Mon Jan 14 14:11:49 2013// -/eap.c/1.9/Result of merge+Tue Apr 2 09:13:20 2013// -/eap.h/1.3/Mon Jan 14 14:11:49 2013// -/genmap.sh/1.6/Mon Jan 14 14:11:49 2013// -/iked.c/1.17/Result of merge+Tue Apr 2 09:13:21 2013// -/iked.conf.5/1.23/Tue Apr 2 09:13:22 2013// -/ikev1.c/1.13/Result of merge+Tue Apr 2 09:13:23 2013// -/ikev2.c/1.82/Result of merge+Tue Apr 2 09:13:24 2013// -/ikev2.h/1.12/Tue Apr 2 09:13:26 2013// -/ikev2_msg.c/1.25/Result of merge+Tue Apr 2 09:13:26 2013// -/ikev2_pld.c/1.31/Result of merge+Tue Apr 2 09:13:27 2013// -/imsg_util.c/1.7/Result of merge+Tue Apr 2 09:13:28 2013// -/parse.y/1.30/Result of merge// -/pfkey.c/1.23/Result of merge// -/proc.c/1.9/Result of merge+Tue Apr 2 09:13:31 2013// -/types.h/1.17/Mon Jan 14 14:11:49 2013// +/Makefile/1.12/Thu Oct 8 08:37:37 2015// +/ca.c/1.37/Thu Oct 8 08:37:38 2015// +/chap_ms.c/1.9/Thu Oct 8 08:37:38 2015// +/chap_ms.h/1.6/Thu Oct 8 08:37:38 2015// +/config.c/1.37/Thu Oct 8 08:37:38 2015// +/control.c/1.16/Thu Oct 8 08:37:38 2015// +/crypto.c/1.18/Thu Oct 8 08:37:38 2015// +/dh.c/1.17/Thu Oct 8 08:37:38 2015// +/dh.h/1.9/Thu Oct 8 08:37:38 2015// +/eap.c/1.14/Thu Oct 8 08:37:38 2015// +/eap.h/1.5/Thu Oct 8 08:37:38 2015// +/genmap.sh/1.7/Thu Oct 8 08:37:38 2015// +/iked.8/1.19/Thu Oct 8 08:37:38 2015// +/iked.c/1.25/Thu Oct 8 08:37:38 2015// +/iked.conf.5/1.39/Thu Oct 8 08:37:39 2015// +/iked.h/1.89/Thu Oct 8 08:37:39 2015// +/ikev1.c/1.18/Thu Oct 8 08:37:39 2015// +/ikev2.c/1.125/Thu Oct 8 08:37:39 2015// +/ikev2.h/1.22/Thu Oct 8 08:37:39 2015// +/ikev2_msg.c/1.43/Thu Oct 8 08:37:39 2015// +/ikev2_pld.c/1.54/Thu Oct 8 08:37:39 2015// +/imsg_util.c/1.10/Thu Oct 8 08:37:39 2015// +/log.c/1.4/Thu Oct 8 08:37:39 2015// +/ocsp.c/1.6/Fri Aug 21 11:59:27 2015// +/parse.y/1.51/Thu Oct 8 08:37:40 2015// +/pfkey.c/1.45/Thu Oct 8 08:37:40 2015// +/policy.c/1.40/Thu Oct 8 08:37:40 2015// +/proc.c/1.23/Thu Oct 8 08:37:40 2015// +/smult_curve25519_ref.c/1.1/Wed Aug 27 10:28:57 2014// +/timer.c/1.12/Thu Oct 8 08:37:40 2015// +/types.h/1.21/Thu Oct 8 08:37:40 2015// +/util.c/1.27/Thu Oct 8 08:37:40 2015// D diff --git a/iked/Makefile b/iked/Makefile new file mode 100644 index 0000000..85d4c39 --- /dev/null +++ b/iked/Makefile @@ -0,0 +1,33 @@ +# $OpenBSD: Makefile,v 1.12 2014/08/27 10:28:57 reyk Exp $ + +PROG= iked +SRCS= ca.c chap_ms.c config.c control.c crypto.c dh.c \ + eap.c iked.c ikev1.c ikev2.c ikev2_msg.c ikev2_pld.c \ + log.c ocsp.c pfkey.c policy.c proc.c timer.c util.c \ + imsg_util.c smult_curve25519_ref.c +SRCS+= eap_map.c ikev2_map.c +SRCS+= parse.y +MAN= iked.conf.5 iked.8 +#NOMAN= yes + +LDADD= -lutil -levent -lcrypto +DPADD= ${LIBUTIL} ${LIBEVENT} ${LIBCRYPTO} +CFLAGS+= -Wall -I${.CURDIR} +CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes +CFLAGS+= -Wmissing-declarations +CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual +CFLAGS+= -Wsign-compare +CLEANFILES+= y.tab.h ikev2_map.c eap_map.c +GENERATED= ikev2_map.c eap_map.c + +ikev2_map.c: genmap.sh ikev2.h + /bin/sh ${.CURDIR}/genmap.sh ${.CURDIR}/ikev2.h ikev2 > $@ + @touch $@ + +eap_map.c: genmap.sh eap.h + /bin/sh ${.CURDIR}/genmap.sh ${.CURDIR}/eap.h eap > $@ + @touch $@ + +${PROG} beforedepend: ${GENERATED} + +.include diff --git a/iked/Makefile.am b/iked/Makefile.am deleted file mode 100644 index a1dc4a7..0000000 --- a/iked/Makefile.am +++ /dev/null @@ -1,76 +0,0 @@ -sbin_PROGRAMS= iked - -iked_MAPS= eap_map.c ikev2_map.c -iked_MAPS_IN= eap.h ikev2.h -iked_SOURCES= ca.c chap_ms.c config.c control.c crypto.c dh.c \ - eap.c iked.c ikev1.c ikev2.c ikev2_msg.c ikev2_pld.c \ - log.c policy.c proc.c timer.c util.c imsg_util.c \ - parse.y $(iked_MAPS) -iked_CFLAGS= - -libpfkey_a_SOURCES= pfkey.c -libpfkey_a_CPPFLAGS= @PFKEY_CPPFLAGS@ - -noinst_LIBRARIES= libpfkey.a - -LIBCOMPAT= $(top_builddir)/openbsd-compat/libopenbsd-compat.a -LDADD= $(LIBCOMPAT) libpfkey.a -CPPFLAGS= -include $(top_srcdir)/openbsd-compat/includes.h \ - -I$(top_srcdir)/openbsd-compat \ - -I$(srcdir) @CPPFLAGS@ @DEFS@ -MANPAGES= iked.8.out iked.conf.5.out -MANPAGES_IN= iked.8 iked.conf.5 -CONFIGFILES= iked.conf.out -CONFIGFILES_IN= iked.conf -EXTRA_DIST= $(CONFIGFILES_IN) $(MANPAGES_IN) -CLEANFILES= $(iked_MAPS) $(CONFIGFILES) $(MANPAGES) -PATHSUBS= -e 's|/etc/iked/|$(sysconfdir)/iked/|g' \ - -e 's|/usr/libexec|$(libexecdir)|g' \ - -e 's|/var/run/iked.sock|$(sockdir)/iked.sock|g' -FIXPATHSCMD= $(SED) $(PATHSUBS) - -$(iked_MAPS): genmap.sh $(iked_MAPS_IN) - mapname=`echo $@ | sed 's/_map\.c$$//'`; \ - hdrname=$${mapname}.h; \ - $(SH) genmap.sh $${hdrname} $${mapname} > $@ - @touch $@ - -$(MANPAGES): $(MANPAGES_IN) - if test "$(MANTYPE)" = "cat"; then \ - manpage=$(srcdir)/`echo $@ | sed 's/\.[1-9]\.out$$/\.0/'`; \ - else \ - manpage=$(srcdir)/`echo $@ | sed 's/\.out$$//'`; \ - fi; \ - if test "$(MANTYPE)" = "man"; then \ - $(FIXPATHSCMD) $${manpage} | $(AWK) -f $(top_srcdir)/mdoc2man.awk > $@; \ - else \ - $(FIXPATHSCMD) $${manpage} > $@; \ - fi - -$(CONFIGFILES): $(CONFIGFILES_IN) - conffile=`echo $@ | sed 's/.out$$//'`; \ - $(FIXPATHSCMD) $(srcdir)/$${conffile} > $@ - -install-exec-hook: $(CONFIGFILES) $(MANPAGES) - $(INSTALL) -d $(DESTDIR)$(sysconfdir)/iked/ - $(INSTALL) -d $(DESTDIR)$(sysconfdir)/iked/ca - $(INSTALL) -d $(DESTDIR)$(sysconfdir)/iked/certs - $(INSTALL) -d $(DESTDIR)$(sysconfdir)/iked/crls - $(INSTALL) -d $(DESTDIR)$(sysconfdir)/iked/pubkeys/fqdn - $(INSTALL) -d $(DESTDIR)$(sysconfdir)/iked/pubkeys/ufqdn - $(INSTALL) -d $(DESTDIR)$(sysconfdir)/iked/pubkeys/ipv4 - $(INSTALL) -d $(DESTDIR)$(sysconfdir)/iked/pubkeys/ipv6 - $(INSTALL) -d -m 700 $(DESTDIR)$(sysconfdir)/iked/private - $(INSTALL) -d $(DESTDIR)$(sysconfdir)/iked/ - $(INSTALL) -d $(DESTDIR)$(sbindir) - $(INSTALL) -d $(DESTDIR)$(mandir)/$(mansubdir)8 - $(INSTALL) -d $(DESTDIR)$(mandir)/$(mansubdir)5 - - @if [ ! -f $(DESTDIR)$(sysconfdir)/iked.conf ]; then \ - $(INSTALL) -m 600 iked.conf.out $(DESTDIR)$(sysconfdir)/iked.conf; \ - else \ - echo "$(DESTDIR)$(sysconfdir)/iked.conf already exists, install will not overwrite"; \ - fi - - $(INSTALL) -m 644 iked.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/iked.8 - $(INSTALL) -m 644 iked.conf.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/iked.conf.5 diff --git a/iked/ca.c b/iked/ca.c index 5f55b1f..dd0ef9e 100644 --- a/iked/ca.c +++ b/iked/ca.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ca.c,v 1.22 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: ca.c,v 1.37 2015/10/01 10:59:23 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,8 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include #include #include #include @@ -27,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -43,19 +41,21 @@ #include #include #include +#include #include "iked.h" #include "ikev2.h" -void ca_reset(struct privsep *, void *); +void ca_reset(struct privsep *, struct privsep_proc *, void *); int ca_reload(struct iked *); int ca_getreq(struct iked *, struct imsg *); int ca_getcert(struct iked *, struct imsg *); int ca_getauth(struct iked *, struct imsg *); -X509 *ca_by_subjectpubkey(X509_STORE *, u_int8_t *, size_t); +X509 *ca_by_subjectpubkey(X509_STORE *, uint8_t *, size_t); X509 *ca_by_issuer(X509_STORE *, X509_NAME *, struct iked_static_id *); -int ca_subjectpubkey_digest(X509 *, u_int8_t *, u_int *); +int ca_subjectpubkey_digest(X509 *, uint8_t *, unsigned int *); +int ca_x509_subject_cmp(X509 *, struct iked_static_id *); int ca_validate_pubkey(struct iked *, struct iked_static_id *, void *, size_t); int ca_validate_cert(struct iked *, struct iked_static_id *, @@ -64,7 +64,8 @@ struct ibuf * ca_x509_serialize(X509 *); int ca_x509_subjectaltname_cmp(X509 *, struct iked_static_id *); int ca_x509_subjectaltname(X509 *cert, struct iked_id *); -int ca_key_serialize(EVP_PKEY *, struct iked_id *); +int ca_privkey_serialize(EVP_PKEY *, struct iked_id *); +int ca_pubkey_serialize(EVP_PKEY *, struct iked_id *); int ca_dispatch_parent(int, struct privsep_proc *, struct imsg *); int ca_dispatch_ikev1(int, struct privsep_proc *, struct imsg *); int ca_dispatch_ikev2(int, struct privsep_proc *, struct imsg *); @@ -83,6 +84,7 @@ struct ca_store { X509_LOOKUP *ca_certlookup; struct iked_id ca_privkey; + struct iked_id ca_pubkey; }; pid_t @@ -98,6 +100,7 @@ caproc(struct privsep *ps, struct privsep_proc *p) if ((store = calloc(1, sizeof(*store))) == NULL) fatal("ca: failed to allocate cert store"); + /* Read private key */ if ((fp = fopen(IKED_PRIVKEY, "r")) == NULL) fatal("ca: failed to open private key"); @@ -105,14 +108,18 @@ caproc(struct privsep *ps, struct privsep_proc *p) fatalx("ca: failed to read private key"); fclose(fp); - if (ca_key_serialize(key, &store->ca_privkey) != 0) + if (ca_privkey_serialize(key, &store->ca_privkey) != 0) fatalx("ca: failed to serialize private key"); + if (ca_pubkey_serialize(key, &store->ca_pubkey) != 0) + fatalx("ca: failed to serialize public key"); + + EVP_PKEY_free(key); return (proc_run(ps, p, procs, nitems(procs), ca_reset, store)); } void -ca_reset(struct privsep *ps, void *arg) +ca_reset(struct privsep *ps, struct privsep_proc *p, void *arg) { struct iked *env = ps->ps_env; struct ca_store *store = arg; @@ -144,8 +151,8 @@ int ca_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) { struct iked *env = p->p_env; - struct ca_store *store = env->sc_priv; - u_int mode; + struct ca_store *store = env->sc_priv; + unsigned int mode; switch (imsg->hdr.type) { case IMSG_CTL_RESET: @@ -153,9 +160,15 @@ ca_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) memcpy(&mode, imsg->data, sizeof(mode)); if (mode == RESET_ALL || mode == RESET_CA) { log_debug("%s: config reload", __func__); - ca_reset(&env->sc_ps, store); + ca_reset(&env->sc_ps, p, store); } break; + case IMSG_OCSP_FD: + ocsp_receive_fd(env, imsg); + break; + case IMSG_OCSP_URL: + config_getocsp(env, imsg); + break; default: return (-1); } @@ -193,7 +206,7 @@ ca_dispatch_ikev2(int fd, struct privsep_proc *p, struct imsg *imsg) int ca_setcert(struct iked *env, struct iked_sahdr *sh, struct iked_id *id, - u_int8_t type, u_int8_t *data, size_t len, enum privsep_procid procid) + uint8_t type, uint8_t *data, size_t len, enum privsep_procid procid) { struct iovec iov[4]; int iovcnt = 0; @@ -228,14 +241,15 @@ ca_setcert(struct iked *env, struct iked_sahdr *sh, struct iked_id *id, iov[iovcnt].iov_len = len; iovcnt++; - if (proc_composev_imsg(env, procid, IMSG_CERT, -1, iov, iovcnt) == -1) + if (proc_composev_imsg(&env->sc_ps, procid, -1, + IMSG_CERT, -1, iov, iovcnt) == -1) return (-1); return (0); } int -ca_setreq(struct iked *env, struct iked_sahdr *sh, - struct iked_static_id *localid, u_int8_t type, u_int8_t *data, +ca_setreq(struct iked *env, struct iked_sa *sa, + struct iked_static_id *localid, uint8_t type, uint8_t *data, size_t len, enum privsep_procid procid) { struct iovec iov[4]; @@ -259,8 +273,8 @@ ca_setreq(struct iked *env, struct iked_sahdr *sh, iov[iovcnt].iov_len = sizeof(idb); iovcnt++; - iov[iovcnt].iov_base = sh; - iov[iovcnt].iov_len = sizeof(*sh); + iov[iovcnt].iov_base = &sa->sa_hdr; + iov[iovcnt].iov_len = sizeof(sa->sa_hdr); iovcnt++; iov[iovcnt].iov_base = &type; iov[iovcnt].iov_len = sizeof(type); @@ -269,10 +283,12 @@ ca_setreq(struct iked *env, struct iked_sahdr *sh, iov[iovcnt].iov_len = len; iovcnt++; - if (proc_composev_imsg(env, procid, + if (proc_composev_imsg(&env->sc_ps, procid, -1, IMSG_CERTREQ, -1, iov, iovcnt) == -1) goto done; + sa_stateflags(sa, IKED_REQ_CERTREQ); + ret = 0; done: ibuf_release(id.id_buf); @@ -286,7 +302,13 @@ ca_setauth(struct iked *env, struct iked_sa *sa, struct iovec iov[3]; int iovcnt = 3; struct iked_policy *policy = sa->sa_policy; - u_int8_t type = policy->pol_auth.auth_method; + uint8_t type = policy->pol_auth.auth_method; + + /* switch encoding to IKEV2_AUTH_SIG if SHA2 is supported */ + if (sa->sa_sigsha2 && type == IKEV2_AUTH_RSA_SIG) { + log_debug("%s: switching from RSA_SIG to SIG", __func__); + type = IKEV2_AUTH_SIG; + } if (type == IKEV2_AUTH_SHARED_KEY_MIC) { sa->sa_stateflags |= IKED_REQ_AUTH; @@ -303,10 +325,11 @@ ca_setauth(struct iked *env, struct iked_sa *sa, else { iov[2].iov_base = ibuf_data(authmsg); iov[2].iov_len = ibuf_size(authmsg); - log_debug("%s: auth length %d", __func__, ibuf_size(authmsg)); + log_debug("%s: auth length %zu", __func__, ibuf_size(authmsg)); } - if (proc_composev_imsg(env, id, IMSG_AUTH, -1, iov, iovcnt) == -1) + if (proc_composev_imsg(&env->sc_ps, id, -1, + IMSG_AUTH, -1, iov, iovcnt) == -1) return (-1); return (0); } @@ -315,15 +338,15 @@ int ca_getcert(struct iked *env, struct imsg *imsg) { struct iked_sahdr sh; - u_int8_t type; - u_int8_t *ptr; + uint8_t type; + uint8_t *ptr; size_t len; struct iked_static_id id; - u_int i; + unsigned int i; struct iovec iov[2]; int iovcnt = 2, cmd, ret = 0; - ptr = (u_int8_t *)imsg->data; + ptr = (uint8_t *)imsg->data; len = IMSG_DATA_SIZE(imsg); i = sizeof(id) + sizeof(sh) + sizeof(type); if (len <= i) @@ -333,7 +356,7 @@ ca_getcert(struct iked *env, struct imsg *imsg) if (id.id_type == IKEV2_ID_NONE) return (-1); memcpy(&sh, ptr + sizeof(id), sizeof(sh)); - memcpy(&type, ptr + sizeof(id) + sizeof(sh), sizeof(u_int8_t)); + memcpy(&type, ptr + sizeof(id) + sizeof(sh), sizeof(uint8_t)); ptr += i; len -= i; @@ -341,6 +364,11 @@ ca_getcert(struct iked *env, struct imsg *imsg) switch (type) { case IKEV2_CERT_X509_CERT: ret = ca_validate_cert(env, &id, ptr, len); + if (ret == 0 && env->sc_ocsp_url) { + ret = ocsp_validate_cert(env, &id, ptr, len, sh, type); + if (ret == 0) + return (0); + } break; case IKEV2_CERT_RSA_KEY: ret = ca_validate_pubkey(env, &id, ptr, len); @@ -361,7 +389,8 @@ ca_getcert(struct iked *env, struct imsg *imsg) iov[1].iov_base = &type; iov[1].iov_len = sizeof(type); - if (proc_composev_imsg(env, PROC_IKEV2, cmd, -1, iov, iovcnt) == -1) + if (proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, + cmd, -1, iov, iovcnt) == -1) return (-1); return (0); } @@ -369,19 +398,19 @@ ca_getcert(struct iked *env, struct imsg *imsg) int ca_getreq(struct iked *env, struct imsg *imsg) { - struct ca_store *store = env->sc_priv; + struct ca_store *store = env->sc_priv; struct iked_sahdr sh; - u_int8_t type; - u_int8_t *ptr; + uint8_t type; + uint8_t *ptr; size_t len; - u_int i, n; + unsigned int i, n; X509 *ca = NULL, *cert = NULL; struct ibuf *buf; struct iked_static_id id; - ptr = (u_int8_t *)imsg->data; + ptr = (uint8_t *)imsg->data; len = IMSG_DATA_SIZE(imsg); - i = sizeof(id) + sizeof(u_int8_t) + sizeof(sh); + i = sizeof(id) + sizeof(uint8_t) + sizeof(sh); if (len < i || ((len - i) % SHA_DIGEST_LENGTH) != 0) return (-1); @@ -389,41 +418,51 @@ ca_getreq(struct iked *env, struct imsg *imsg) if (id.id_type == IKEV2_ID_NONE) return (-1); memcpy(&sh, ptr + sizeof(id), sizeof(sh)); - memcpy(&type, ptr + sizeof(id) + sizeof(sh), sizeof(u_int8_t)); - if (type != IKEV2_CERT_X509_CERT) - return (-1); - - for (n = 1; i < len; n++, i += SHA_DIGEST_LENGTH) { - if ((ca = ca_by_subjectpubkey(store->ca_cas, - ptr + i, SHA_DIGEST_LENGTH)) == NULL) { - log_debug("%s: CA %d not found", __func__, n); - print_hex(ptr, i, SHA_DIGEST_LENGTH); - continue; - } + memcpy(&type, ptr + sizeof(id) + sizeof(sh), sizeof(uint8_t)); - log_debug("%s: found CA %s", __func__, ca->name); + switch (type) { + case IKEV2_CERT_RSA_KEY: + if (store->ca_pubkey.id_type != type || + (buf = store->ca_pubkey.id_buf) == NULL) + return (-1); - if ((cert = ca_by_issuer(store->ca_certs, - X509_get_subject_name(ca), &id)) != NULL) { - /* XXX should we re-validate our own cert here? */ - break; - } + log_debug("%s: using local public key of type %s", __func__, + print_map(type, ikev2_cert_map)); + break; + case IKEV2_CERT_X509_CERT: + for (n = 1; i < len; n++, i += SHA_DIGEST_LENGTH) { + if ((ca = ca_by_subjectpubkey(store->ca_cas, ptr + i, + SHA_DIGEST_LENGTH)) == NULL) + continue; - log_debug("%s: no valid certificate for this CA", __func__); - } - if (ca == NULL || cert == NULL) { - log_warnx("%s: no valid local certificate found", __func__); - type = IKEV2_CERT_NONE; - ca_setcert(env, &sh, NULL, type, NULL, 0, PROC_IKEV2); - return (0); - } + log_debug("%s: found CA %s", __func__, ca->name); - log_debug("%s: found local certificate %s", __func__, cert->name); + if ((cert = ca_by_issuer(store->ca_certs, + X509_get_subject_name(ca), &id)) != NULL) { + /* XXX + * should we re-validate our own cert here? + */ + break; + } + } + if (ca == NULL || cert == NULL) { + log_warnx("%s: no valid local certificate found", + __func__); + type = IKEV2_CERT_NONE; + ca_setcert(env, &sh, NULL, type, NULL, 0, PROC_IKEV2); + return (0); + } + log_debug("%s: found local certificate %s", __func__, + cert->name); - if ((buf = ca_x509_serialize(cert)) == NULL) + if ((buf = ca_x509_serialize(cert)) == NULL) + return (-1); + break; + default: + log_warnx("%s: unknown cert type requested", __func__); return (-1); + } - type = IKEV2_CERT_X509_CERT; ca_setcert(env, &sh, NULL, type, ibuf_data(buf), ibuf_size(buf), PROC_IKEV2); @@ -433,26 +472,26 @@ ca_getreq(struct iked *env, struct imsg *imsg) int ca_getauth(struct iked *env, struct imsg *imsg) { - struct ca_store *store = env->sc_priv; + struct ca_store *store = env->sc_priv; struct iked_sahdr sh; - u_int8_t method; - u_int8_t *ptr; + uint8_t method; + uint8_t *ptr; size_t len; - u_int i; + unsigned int i; int ret = -1; struct iked_sa sa; struct iked_policy policy; struct iked_id *id; struct ibuf *authmsg; - ptr = (u_int8_t *)imsg->data; + ptr = (uint8_t *)imsg->data; len = IMSG_DATA_SIZE(imsg); i = sizeof(method) + sizeof(sh); if (len <= i) return (-1); memcpy(&sh, ptr, sizeof(sh)); - memcpy(&method, ptr + sizeof(sh), sizeof(u_int8_t)); + memcpy(&method, ptr + sizeof(sh), sizeof(uint8_t)); if (method == IKEV2_AUTH_SHARED_KEY_MIC) return (-1); @@ -492,17 +531,16 @@ ca_getauth(struct iked *env, struct imsg *imsg) int ca_reload(struct iked *env) { - struct ca_store *store = env->sc_priv; - DIR *dir; - struct dirent *entry; + struct ca_store *store = env->sc_priv; + uint8_t md[EVP_MAX_MD_SIZE]; char file[PATH_MAX]; + struct iovec iov[2]; + struct dirent *entry; STACK_OF(X509_OBJECT) *h; X509_OBJECT *xo; X509 *x509; - int i, len; - u_int8_t md[EVP_MAX_MD_SIZE]; - struct iovec iov[2]; - int iovcnt = 2; + DIR *dir; + int i, len, iovcnt = 0; /* * Load CAs @@ -523,7 +561,7 @@ ca_reload(struct iked *env) X509_FILETYPE_PEM)) { log_warn("%s: failed to load ca file %s", __func__, entry->d_name); - ca_sslerror(); + ca_sslerror(__func__); continue; } log_debug("%s: loaded ca file %s", __func__, entry->d_name); @@ -549,7 +587,7 @@ ca_reload(struct iked *env) X509_FILETYPE_PEM)) { log_warn("%s: failed to load crl file %s", __func__, entry->d_name); - ca_sslerror(); + ca_sslerror(__func__); continue; } @@ -588,16 +626,18 @@ ca_reload(struct iked *env) env->sc_certreqtype = IKEV2_CERT_X509_CERT; iov[0].iov_base = &env->sc_certreqtype; iov[0].iov_len = sizeof(env->sc_certreqtype); + iovcnt++; iov[1].iov_base = ibuf_data(env->sc_certreq); iov[1].iov_len = ibuf_length(env->sc_certreq); + iovcnt++; - log_debug("%s: loaded %d ca certificate%s", __func__, + log_debug("%s: loaded %zu ca certificate%s", __func__, ibuf_length(env->sc_certreq) / SHA_DIGEST_LENGTH, ibuf_length(env->sc_certreq) == SHA_DIGEST_LENGTH ? "" : "s"); - (void)proc_composev_imsg(env, PROC_IKEV2, IMSG_CERTREQ, -1, - iov, iovcnt); + (void)proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, + IMSG_CERTREQ, -1, iov, iovcnt); } /* @@ -619,7 +659,7 @@ ca_reload(struct iked *env) X509_FILETYPE_PEM)) { log_warn("%s: failed to load cert file %s", __func__, entry->d_name); - ca_sslerror(); + ca_sslerror(__func__); continue; } log_debug("%s: loaded cert file %s", __func__, entry->d_name); @@ -637,18 +677,31 @@ ca_reload(struct iked *env) (void)ca_validate_cert(env, NULL, x509, 0); } + if (!env->sc_certreqtype) + env->sc_certreqtype = store->ca_pubkey.id_type; + + log_debug("%s: local cert type %s", __func__, + print_map(env->sc_certreqtype, ikev2_cert_map)); + + iov[0].iov_base = &env->sc_certreqtype; + iov[0].iov_len = sizeof(env->sc_certreqtype); + if (iovcnt == 0) + iovcnt++; + (void)proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, + IMSG_CERTREQ, -1, iov, iovcnt); + return (0); } X509 * -ca_by_subjectpubkey(X509_STORE *ctx, u_int8_t *sig, size_t siglen) +ca_by_subjectpubkey(X509_STORE *ctx, uint8_t *sig, size_t siglen) { STACK_OF(X509_OBJECT) *h; X509_OBJECT *xo; X509 *ca; int i; - u_int len; - u_int8_t md[EVP_MAX_MD_SIZE]; + unsigned int len; + uint8_t md[EVP_MAX_MD_SIZE]; h = ctx->objs; @@ -690,9 +743,16 @@ ca_by_issuer(X509_STORE *ctx, X509_NAME *subject, struct iked_static_id *id) if ((issuer = X509_get_issuer_name(cert)) == NULL) continue; else if (X509_NAME_cmp(subject, issuer) == 0) { - if (ca_x509_subjectaltname_cmp(cert, id) != 0) - continue; - return (cert); + switch (id->id_type) { + case IKEV2_ID_ASN1_DN: + if (ca_x509_subject_cmp(cert, id) == 0) + return (cert); + break; + default: + if (ca_x509_subjectaltname_cmp(cert, id) == 0) + return (cert); + break; + } } } @@ -700,9 +760,9 @@ ca_by_issuer(X509_STORE *ctx, X509_NAME *subject, struct iked_static_id *id) } int -ca_subjectpubkey_digest(X509 *x509, u_int8_t *md, u_int *size) +ca_subjectpubkey_digest(X509 *x509, uint8_t *md, unsigned int *size) { - u_int8_t *buf = NULL; + uint8_t *buf = NULL; int buflen; if (*size < SHA_DIGEST_LENGTH) @@ -731,7 +791,7 @@ ca_x509_serialize(X509 *x509) { long len; struct ibuf *buf; - u_int8_t *d = NULL; + uint8_t *d = NULL; BIO *out; if ((out = BIO_new(BIO_s_mem())) == NULL) @@ -743,16 +803,18 @@ ca_x509_serialize(X509 *x509) len = BIO_get_mem_data(out, &d); buf = ibuf_new(d, len); + BIO_free(out); return (buf); } int -ca_key_serialize(EVP_PKEY *key, struct iked_id *id) +ca_pubkey_serialize(EVP_PKEY *key, struct iked_id *id) { - int len; - u_int8_t *d; - RSA *rsa; + RSA *rsa = NULL; + uint8_t *d; + int len = 0; + int ret = -1; switch (key->type) { case EVP_PKEY_RSA: @@ -761,16 +823,60 @@ ca_key_serialize(EVP_PKEY *key, struct iked_id *id) ibuf_release(id->id_buf); if ((rsa = EVP_PKEY_get1_RSA(key)) == NULL) - return (-1); + goto done; + if ((len = i2d_RSAPublicKey(rsa, NULL)) <= 0) + goto done; + if ((id->id_buf = ibuf_new(NULL, len)) == NULL) + goto done; + + d = ibuf_data(id->id_buf); + if (i2d_RSAPublicKey(rsa, &d) != len) { + ibuf_release(id->id_buf); + goto done; + } + + id->id_type = IKEV2_CERT_RSA_KEY; + break; + default: + log_debug("%s: unsupported key type %d", __func__, key->type); + return (-1); + } + + log_debug("%s: type %s length %d", __func__, + print_map(id->id_type, ikev2_cert_map), len); + + ret = 0; + done: + if (rsa != NULL) + RSA_free(rsa); + return (ret); +} + +int +ca_privkey_serialize(EVP_PKEY *key, struct iked_id *id) +{ + RSA *rsa = NULL; + uint8_t *d; + int len = 0; + int ret = -1; + + switch (key->type) { + case EVP_PKEY_RSA: + id->id_type = 0; + id->id_offset = 0; + ibuf_release(id->id_buf); + + if ((rsa = EVP_PKEY_get1_RSA(key)) == NULL) + goto done; if ((len = i2d_RSAPrivateKey(rsa, NULL)) <= 0) - return (-1); + goto done; if ((id->id_buf = ibuf_new(NULL, len)) == NULL) - return (-1); + goto done; d = ibuf_data(id->id_buf); if (i2d_RSAPrivateKey(rsa, &d) != len) { ibuf_release(id->id_buf); - return (-1); + goto done; } id->id_type = IKEV2_CERT_RSA_KEY; @@ -780,15 +886,22 @@ ca_key_serialize(EVP_PKEY *key, struct iked_id *id) return (-1); } - return (0); + log_debug("%s: type %s length %d", __func__, + print_map(id->id_type, ikev2_cert_map), len); + + ret = 0; + done: + if (rsa != NULL) + RSA_free(rsa); + return (ret); } char * -ca_asn1_name(u_int8_t *asn1, size_t len) +ca_asn1_name(uint8_t *asn1, size_t len) { X509_NAME *name = NULL; char *str = NULL; - const u_int8_t *p; + const uint8_t *p; p = asn1; if ((name = d2i_X509_NAME(NULL, &p, len)) == NULL) @@ -812,17 +925,112 @@ ca_x509_name(void *ptr) return (strdup(buf)); } +/* + * Copy 'src' to 'dst' until 'marker' is found while unescaping '\' + * characters. The return value tells the caller where to continue + * parsing (might be the end of the string) or NULL on error. + */ +static char * +ca_x509_name_unescape(char *src, char *dst, char marker) +{ + while (*src) { + if (*src == marker) { + src++; + break; + } + if (*src == '\\') { + src++; + if (!*src) { + log_warnx("%s: '\\' at end of string", + __func__); + *dst = '\0'; + return (NULL); + } + } + *dst++ = *src++; + } + *dst = '\0'; + return (src); +} +/* + * Parse an X509 subject name where 'subject' is in the format + * /type0=value0/type1=value1/type2=... + * where characters may be escaped by '\'. + * See lib/libssl/src/apps/apps.c:parse_name() + */ +void * +ca_x509_name_parse(char *subject) +{ + char *cp, *value = NULL, *type = NULL; + size_t maxlen; + X509_NAME *name = NULL; + + if (*subject != '/') { + log_warnx("%s: leading '/' missing in '%s'", __func__, subject); + goto err; + } + + /* length of subject is upper bound for unescaped type/value */ + maxlen = strlen(subject) + 1; + + if ((type = calloc(1, maxlen)) == NULL || + (value = calloc(1, maxlen)) == NULL || + (name = X509_NAME_new()) == NULL) + goto err; + + cp = subject + 1; + while (*cp) { + /* unescape type, terminated by '=' */ + cp = ca_x509_name_unescape(cp, type, '='); + if (cp == NULL) { + log_warnx("%s: could not parse type", __func__); + goto err; + } + if (!*cp) { + log_warnx("%s: missing value", __func__); + goto err; + } + /* unescape value, terminated by '/' */ + cp = ca_x509_name_unescape(cp, value, '/'); + if (cp == NULL) { + log_warnx("%s: could not parse value", __func__); + goto err; + } + if (!*type || !*value) { + log_warnx("%s: empty type or value", __func__); + goto err; + } + log_debug("%s: setting '%s' to '%s'", __func__, type, value); + if (!X509_NAME_add_entry_by_txt(name, type, MBSTRING_ASC, + value, -1, -1, 0)) { + log_warnx("%s: setting '%s' to '%s' failed", __func__, + type, value); + ca_sslerror(__func__); + goto err; + } + } + free(type); + free(value); + return (name); + +err: + X509_NAME_free(name); + free(type); + free(value); + return (NULL); +} + int ca_validate_pubkey(struct iked *env, struct iked_static_id *id, void *data, size_t len) { BIO *rawcert = NULL; - RSA *rsa = NULL; + RSA *peerrsa = NULL, *localrsa = NULL; EVP_PKEY *peerkey = NULL, *localkey = NULL; int ret = -1; FILE *fp = NULL; char idstr[IKED_ID_SIZE]; - char file[MAXPATHLEN]; + char file[PATH_MAX]; struct iked_id idp; if (len == 0 && data == NULL) @@ -855,42 +1063,58 @@ ca_validate_pubkey(struct iked *env, struct iked_static_id *id, if ((rawcert = BIO_new_mem_buf(data, len)) == NULL) goto done; - if ((rsa = d2i_RSAPublicKey_bio(rawcert, NULL)) == NULL) + if ((peerrsa = d2i_RSAPublicKey_bio(rawcert, NULL)) == NULL) goto sslerr; if ((peerkey = EVP_PKEY_new()) == NULL) goto sslerr; - if (!EVP_PKEY_set1_RSA(peerkey, rsa)) + if (!EVP_PKEY_set1_RSA(peerkey, peerrsa)) goto sslerr; } lc_string(idstr); if (strlcpy(file, IKED_PUBKEY_DIR, sizeof(file)) >= sizeof(file) || - strlcpy(file, idstr, sizeof(file)) >= sizeof(file)) + strlcat(file, idstr, sizeof(file)) >= sizeof(file)) goto done; - log_debug("%s: looking up %s", __func__, file); - if ((fp = fopen(file, "r")) == NULL) goto done; - localkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL); - fclose(fp); + if (localkey == NULL) { + /* reading PKCS #8 failed, try PEM */ + rewind(fp); + localrsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL); + fclose(fp); + if (localrsa == NULL) + goto sslerr; + if ((localkey = EVP_PKEY_new()) == NULL) + goto sslerr; + if (!EVP_PKEY_set1_RSA(localkey, localrsa)) + goto sslerr; + } else { + fclose(fp); + } if (localkey == NULL) goto sslerr; if (!EVP_PKEY_cmp(peerkey, localkey)) goto done; + log_debug("%s: valid public key in file %s", __func__, file); + ret = 0; sslerr: if (ret != 0) - ca_sslerror(); + ca_sslerror(__func__); done: ibuf_release(idp.id_buf); if (peerkey != NULL) EVP_PKEY_free(peerkey); - if (rsa != NULL) - RSA_free(rsa); + if (localkey != NULL) + EVP_PKEY_free(localkey); + if (peerrsa != NULL) + RSA_free(peerrsa); + if (localrsa != NULL) + RSA_free(localrsa); if (rawcert != NULL) BIO_free(rawcert); @@ -906,9 +1130,7 @@ ca_validate_cert(struct iked *env, struct iked_static_id *id, BIO *rawcert = NULL; X509 *cert = NULL; int ret = -1, result, error; - size_t idlen, idoff; - const u_int8_t *idptr; - X509_NAME *idname = NULL, *subject; + X509_NAME *subject; const char *errstr = "failed"; if (len == 0) { @@ -931,23 +1153,13 @@ ca_validate_cert(struct iked *env, struct iked_static_id *id, if (id != NULL) { if ((ret = ca_validate_pubkey(env, id, X509_get_pubkey(cert), 0)) == 0) { - errstr = "public key found, ok"; + errstr = "in public key file, ok"; goto done; } switch (id->id_type) { case IKEV2_ID_ASN1_DN: - idoff = id->id_offset; - if (id->id_length <= idoff) { - errstr = "invalid ASN1_DN id length"; - goto done; - } - idlen = id->id_length - idoff; - idptr = id->id_data + idoff; - - if ((idname = d2i_X509_NAME(NULL, - &idptr, idlen)) == NULL || - X509_NAME_cmp(subject, idname) != 0) { + if (ca_x509_subject_cmp(cert, id) < 0) { errstr = "ASN1_DN identifier mismatch"; goto done; } @@ -984,14 +1196,12 @@ ca_validate_cert(struct iked *env, struct iked_static_id *id, /* Success */ ret = 0; + errstr = "ok"; done: if (cert != NULL) - log_debug("%s: %s %.100s", __func__, cert->name, - ret == 0 ? "ok" : errstr); + log_debug("%s: %s %.100s", __func__, cert->name, errstr); - if (idname != NULL) - X509_NAME_free(idname); if (rawcert != NULL) { BIO_free(rawcert); if (cert != NULL) @@ -1001,6 +1211,31 @@ ca_validate_cert(struct iked *env, struct iked_static_id *id, return (ret); } +/* check if subject from cert matches the id */ +int +ca_x509_subject_cmp(X509 *cert, struct iked_static_id *id) +{ + X509_NAME *subject, *idname = NULL; + const uint8_t *idptr; + size_t idlen; + int ret = -1; + + if (id->id_type != IKEV2_ID_ASN1_DN) + return (-1); + if ((subject = X509_get_subject_name(cert)) == NULL) + return (-1); + if (id->id_length <= id->id_offset) + return (-1); + idlen = id->id_length - id->id_offset; + idptr = id->id_data + id->id_offset; + if ((idname = d2i_X509_NAME(NULL, &idptr, idlen)) == NULL) + return (-1); + if (X509_NAME_cmp(subject, idname) == 0) + ret = 0; + X509_NAME_free(idname); + return (ret); +} + int ca_x509_subjectaltname_cmp(X509 *cert, struct iked_static_id *id) { @@ -1036,7 +1271,7 @@ int ca_x509_subjectaltname(X509 *cert, struct iked_id *id) { X509_EXTENSION *san; - u_int8_t sanhdr[4], *data; + uint8_t sanhdr[4], *data; int ext, santype, sanlen; char idstr[IKED_ID_SIZE]; @@ -1056,7 +1291,7 @@ ca_x509_subjectaltname(X509 *cert, struct iked_id *id) } /* This is partially based on isakmpd's x509 subjectaltname code */ - data = (u_int8_t *)san->value->data; + data = (uint8_t *)san->value->data; memcpy(&sanhdr, data, sizeof(sanhdr)); santype = sanhdr[2] & 0x3f; sanlen = sanhdr[3]; @@ -1112,16 +1347,14 @@ ca_sslinit(void) /* Init hardware crypto engines. */ ENGINE_load_builtin_engines(); ENGINE_register_all_complete(); - - seed_rng(); } void -ca_sslerror(void) +ca_sslerror(const char *caller) { - u_long error; + unsigned long error; while ((error = ERR_get_error()) != 0) - log_warn("%s: %.100s", __func__, + log_warn("%s: %s: %.100s", __func__, caller, ERR_error_string(error, NULL)); } diff --git a/iked/chap_ms.c b/iked/chap_ms.c index dfaff2f..1e03f1d 100644 --- a/iked/chap_ms.c +++ b/iked/chap_ms.c @@ -1,4 +1,4 @@ -/* $OpenBSD: chap_ms.c,v 1.6 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: chap_ms.c,v 1.9 2015/08/21 11:59:27 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -56,32 +56,32 @@ * "It is unclear to us why this protocol is so complicated." */ -static u_int8_t sha1_pad1[40] = { +static uint8_t sha1_pad1[40] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static u_int8_t sha1_pad2[40] = { +static uint8_t sha1_pad2[40] = { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 }; -u_int8_t get7bits(u_int8_t *, int); -void mschap_des_addparity(u_int8_t *, u_int8_t *); -void mschap_des_encrypt(u_int8_t *, u_int8_t *, u_int8_t *); -void mschap_challenge_response(u_int8_t *, u_int8_t *, u_int8_t *); +uint8_t get7bits(uint8_t *, int); +void mschap_des_addparity(uint8_t *, uint8_t *); +void mschap_des_encrypt(uint8_t *, uint8_t *, uint8_t *); +void mschap_challenge_response(uint8_t *, uint8_t *, uint8_t *); -u_int8_t -get7bits(u_int8_t *in, int start) +uint8_t +get7bits(uint8_t *in, int start) { - u_int word; + unsigned int word; - word = (u_int)in[start / 8] << 8; - word |= (u_int)in[start / 8 + 1]; + word = (unsigned int)in[start / 8] << 8; + word |= (unsigned int)in[start / 8 + 1]; word >>= 15 - (start % 8 + 7); return (word & 0xfe); @@ -90,7 +90,7 @@ get7bits(u_int8_t *in, int start) /* IN 56 bit DES key missing parity bits OUT 64 bit DES key with parity bits added */ void -mschap_des_addparity(u_int8_t *key, u_int8_t *des_key) +mschap_des_addparity(uint8_t *key, uint8_t *des_key) { des_key[0] = get7bits(key, 0); des_key[1] = get7bits(key, 7); @@ -105,7 +105,7 @@ mschap_des_addparity(u_int8_t *key, u_int8_t *des_key) } void -mschap_des_encrypt(u_int8_t *clear, u_int8_t *key, u_int8_t *cipher) +mschap_des_encrypt(uint8_t *clear, uint8_t *key, uint8_t *cipher) { DES_cblock des_key; DES_key_schedule key_schedule; @@ -118,10 +118,10 @@ mschap_des_encrypt(u_int8_t *clear, u_int8_t *key, u_int8_t *cipher) } void -mschap_challenge_response(u_int8_t *challenge, u_int8_t *pwhash, - u_int8_t *response) +mschap_challenge_response(uint8_t *challenge, uint8_t *pwhash, + uint8_t *response) { - u_int8_t padpwhash[21 + 1]; + uint8_t padpwhash[21 + 1]; bzero(&padpwhash, sizeof(padpwhash)); memcpy(padpwhash, pwhash, MSCHAP_HASH_SZ); @@ -132,10 +132,10 @@ mschap_challenge_response(u_int8_t *challenge, u_int8_t *pwhash, } void -mschap_ntpassword_hash(u_int8_t *in, int inlen, u_int8_t *hash) +mschap_ntpassword_hash(uint8_t *in, int inlen, uint8_t *hash) { EVP_MD_CTX ctx; - u_int mdlen; + unsigned int mdlen; EVP_DigestInit(&ctx, EVP_md4()); EVP_DigestUpdate(&ctx, in, inlen); @@ -143,13 +143,13 @@ mschap_ntpassword_hash(u_int8_t *in, int inlen, u_int8_t *hash) } void -mschap_challenge_hash(u_int8_t *peer_challenge, u_int8_t *auth_challenge, - u_int8_t *username, int usernamelen, u_int8_t *challenge) +mschap_challenge_hash(uint8_t *peer_challenge, uint8_t *auth_challenge, + uint8_t *username, int usernamelen, uint8_t *challenge) { EVP_MD_CTX ctx; - u_int8_t md[SHA_DIGEST_LENGTH]; - u_int mdlen; - u_int8_t *name; + uint8_t md[SHA_DIGEST_LENGTH]; + unsigned int mdlen; + uint8_t *name; if ((name = strrchr(username, '\\')) == NULL) name = username; @@ -166,12 +166,12 @@ mschap_challenge_hash(u_int8_t *peer_challenge, u_int8_t *auth_challenge, } void -mschap_nt_response(u_int8_t *auth_challenge, u_int8_t *peer_challenge, - u_int8_t *username, int usernamelen, u_int8_t *password, int passwordlen, - u_int8_t *response) +mschap_nt_response(uint8_t *auth_challenge, uint8_t *peer_challenge, + uint8_t *username, int usernamelen, uint8_t *password, int passwordlen, + uint8_t *response) { - u_int8_t challenge[MSCHAP_CHALLENGE_SZ]; - u_int8_t password_hash[MSCHAP_HASH_SZ]; + uint8_t challenge[MSCHAP_CHALLENGE_SZ]; + uint8_t password_hash[MSCHAP_HASH_SZ]; mschap_challenge_hash(peer_challenge, auth_challenge, username, usernamelen, challenge); @@ -181,25 +181,25 @@ mschap_nt_response(u_int8_t *auth_challenge, u_int8_t *peer_challenge, } void -mschap_auth_response(u_int8_t *password, int passwordlen, - u_int8_t *ntresponse, u_int8_t *auth_challenge, u_int8_t *peer_challenge, - u_int8_t *username, int usernamelen, u_int8_t *auth_response) +mschap_auth_response(uint8_t *password, int passwordlen, + uint8_t *ntresponse, uint8_t *auth_challenge, uint8_t *peer_challenge, + uint8_t *username, int usernamelen, uint8_t *auth_response) { EVP_MD_CTX ctx; - u_int8_t password_hash[MSCHAP_HASH_SZ]; - u_int8_t password_hash2[MSCHAP_HASH_SZ]; - u_int8_t challenge[MSCHAP_CHALLENGE_SZ]; - u_int8_t md[SHA_DIGEST_LENGTH], *ptr; - u_int mdlen; + uint8_t password_hash[MSCHAP_HASH_SZ]; + uint8_t password_hash2[MSCHAP_HASH_SZ]; + uint8_t challenge[MSCHAP_CHALLENGE_SZ]; + uint8_t md[SHA_DIGEST_LENGTH], *ptr; + unsigned int mdlen; int i; - const u_int8_t hex[] = "0123456789ABCDEF"; - static u_int8_t magic1[39] = { + const uint8_t hex[] = "0123456789ABCDEF"; + static uint8_t magic1[39] = { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 }; - static u_int8_t magic2[41] = { + static uint8_t magic2[41] = { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, @@ -242,13 +242,13 @@ mschap_auth_response(u_int8_t *password, int passwordlen, } void -mschap_masterkey(u_int8_t *password_hash2, u_int8_t *ntresponse, - u_int8_t *masterkey) +mschap_masterkey(uint8_t *password_hash2, uint8_t *ntresponse, + uint8_t *masterkey) { - u_int8_t md[SHA_DIGEST_LENGTH]; - u_int mdlen; + uint8_t md[SHA_DIGEST_LENGTH]; + unsigned int mdlen; EVP_MD_CTX ctx; - static u_int8_t magic1[27] = { + static uint8_t magic1[27] = { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 @@ -264,14 +264,14 @@ mschap_masterkey(u_int8_t *password_hash2, u_int8_t *ntresponse, } void -mschap_asymetric_startkey(u_int8_t *masterkey, u_int8_t *sessionkey, +mschap_asymetric_startkey(uint8_t *masterkey, uint8_t *sessionkey, int sessionkeylen, int issend, int isserver) { EVP_MD_CTX ctx; - u_int8_t md[SHA_DIGEST_LENGTH]; - u_int mdlen; - u_int8_t *s; - static u_int8_t magic2[84] = { + uint8_t md[SHA_DIGEST_LENGTH]; + unsigned int mdlen; + uint8_t *s; + static uint8_t magic2[84] = { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, @@ -282,7 +282,7 @@ mschap_asymetric_startkey(u_int8_t *masterkey, u_int8_t *sessionkey, 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x2e }; - static u_int8_t magic3[84] = { + static uint8_t magic3[84] = { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, @@ -310,14 +310,14 @@ mschap_asymetric_startkey(u_int8_t *masterkey, u_int8_t *sessionkey, } void -mschap_msk(u_int8_t *password, int passwordlen, - u_int8_t *ntresponse, u_int8_t *msk) +mschap_msk(uint8_t *password, int passwordlen, + uint8_t *ntresponse, uint8_t *msk) { - u_int8_t password_hash[MSCHAP_HASH_SZ]; - u_int8_t password_hash2[MSCHAP_HASH_SZ]; - u_int8_t masterkey[MSCHAP_MASTERKEY_SZ]; - u_int8_t sendkey[MSCHAP_MASTERKEY_SZ]; - u_int8_t recvkey[MSCHAP_MASTERKEY_SZ]; + uint8_t password_hash[MSCHAP_HASH_SZ]; + uint8_t password_hash2[MSCHAP_HASH_SZ]; + uint8_t masterkey[MSCHAP_MASTERKEY_SZ]; + uint8_t sendkey[MSCHAP_MASTERKEY_SZ]; + uint8_t recvkey[MSCHAP_MASTERKEY_SZ]; mschap_ntpassword_hash(password, passwordlen, password_hash); mschap_ntpassword_hash(password_hash, MSCHAP_HASH_SZ, password_hash2); @@ -333,58 +333,12 @@ mschap_msk(u_int8_t *password, int passwordlen, } void -mschap_newkey(u_int8_t *startkey, u_int8_t *sessionkey, - long sessionkeylen, u_int8_t *key) +mschap_radiuskey(uint8_t *plain, const uint8_t *crypted, + const uint8_t *authenticator, const uint8_t *secret) { EVP_MD_CTX ctx; - u_int8_t md[SHA_DIGEST_LENGTH]; - u_int mdlen; - - EVP_DigestInit(&ctx, EVP_sha1()); - EVP_DigestUpdate(&ctx, startkey, sessionkeylen); - EVP_DigestUpdate(&ctx, sha1_pad1, sizeof(sha1_pad1)); - EVP_DigestUpdate(&ctx, sessionkey, sessionkeylen); - EVP_DigestUpdate(&ctx, sha1_pad2, sizeof(sha1_pad2)); - EVP_DigestFinal(&ctx, md, &mdlen); - - memcpy(key, md, sessionkeylen); -} - -void -mschap_nt(u_int8_t *password_hash, u_int8_t *challenge) -{ - u_int8_t response[24]; - - mschap_challenge_response(challenge, password_hash, response); - memcpy(password_hash, response, sizeof(response)); - password_hash[24] = 1; /* NT-style response */ -} - -void -mschap_lanman(u_int8_t *digest, u_int8_t *challenge, u_int8_t *secret) -{ - static u_int8_t salt[] = "KGS!@#$%"; /* RASAPI32.dll */ - u_int8_t SECRET[14 + 1], *ptr, *end; - u_int8_t hash[MSCHAP_HASH_SZ]; - - bzero(&SECRET, sizeof(SECRET)); - end = SECRET + (sizeof(SECRET) - 1); - for (ptr = SECRET; *secret && ptr < end; ptr++, secret++) - *ptr = toupper(*secret); - - mschap_des_encrypt(salt, SECRET, hash); - mschap_des_encrypt(salt, SECRET + 7, hash + 8); - - mschap_challenge_response(challenge, hash, digest); -} - -void -mschap_radiuskey(u_int8_t *plain, const u_int8_t *crypted, - const u_int8_t *authenticator, const u_int8_t *secret) -{ - EVP_MD_CTX ctx; - u_int8_t b[MD5_DIGEST_LENGTH], p[32]; - u_int i, mdlen; + uint8_t b[MD5_DIGEST_LENGTH], p[32]; + unsigned int i, mdlen; EVP_DigestInit(&ctx, EVP_md5()); EVP_DigestUpdate(&ctx, secret, strlen(secret)); diff --git a/iked/chap_ms.h b/iked/chap_ms.h index f06940c..53b3adb 100644 --- a/iked/chap_ms.h +++ b/iked/chap_ms.h @@ -1,4 +1,4 @@ -/* $OpenBSD: chap_ms.h,v 1.3 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: chap_ms.h,v 1.6 2015/08/21 11:59:27 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _CHAP_MS_H -#define _CHAP_MS_H +#ifndef CHAP_MS_H +#define CHAP_MS_H #define MSCHAP_CHALLENGE_SZ 8 #define MSCHAPV2_CHALLENGE_SZ 16 @@ -29,23 +29,19 @@ #define MSCHAP_MAXNTPASSWORD_SZ 255 /* unicode chars */ -void mschap_nt_response(u_int8_t *, u_int8_t *, u_int8_t *, int, - u_int8_t *, int , u_int8_t *); -void mschap_auth_response(u_int8_t *, int, u_int8_t *, u_int8_t *, - u_int8_t *, u_int8_t *, int, u_int8_t *); +void mschap_nt_response(uint8_t *, uint8_t *, uint8_t *, int, + uint8_t *, int , uint8_t *); +void mschap_auth_response(uint8_t *, int, uint8_t *, uint8_t *, + uint8_t *, uint8_t *, int, uint8_t *); -void mschap_nt(u_int8_t *, u_int8_t *); -void mschap_lanman(u_int8_t *, u_int8_t *, u_int8_t *); +void mschap_ntpassword_hash(uint8_t *, int, uint8_t *); +void mschap_challenge_hash(uint8_t *, uint8_t *, uint8_t *, + int, uint8_t *); -void mschap_ntpassword_hash(u_int8_t *, int, u_int8_t *); -void mschap_challenge_hash(u_int8_t *, u_int8_t *, u_int8_t *, - int, u_int8_t *); +void mschap_asymetric_startkey(uint8_t *, uint8_t *, int, int, int); +void mschap_masterkey(uint8_t *, uint8_t *, uint8_t *); +void mschap_radiuskey(uint8_t *, const uint8_t *, const uint8_t *, + const uint8_t *); +void mschap_msk(uint8_t *, int, uint8_t *, uint8_t *); -void mschap_asymetric_startkey(u_int8_t *, u_int8_t *, int, int, int); -void mschap_masterkey(u_int8_t *, u_int8_t *, u_int8_t *); -void mschap_newkey(u_int8_t *, u_int8_t *, long, u_int8_t *); -void mschap_radiuskey(u_int8_t *, const u_int8_t *, const u_int8_t *, - const u_int8_t *); -void mschap_msk(u_int8_t *, int, u_int8_t *, u_int8_t *); - -#endif /* _CHAP_MS_H */ +#endif /* CHAP_MS_H */ diff --git a/iked/config.c b/iked/config.c index 397191d..b0d395c 100644 --- a/iked/config.c +++ b/iked/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.20 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: config.c,v 1.37 2015/08/21 11:59:27 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,24 +16,15 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include #include #include #include -#include -#include -#include -#include -#include -#include - #include #include #include #include -#include #include #include #include @@ -70,31 +61,52 @@ config_new_sa(struct iked *env, int initiator) return (sa); } -u_int64_t +uint64_t config_getspi(void) { - u_int64_t spi; + uint64_t spi; - spi = ((u_int64_t)arc4random() << 32) | arc4random(); - if (spi == 0) - return (config_getspi()); + do { + arc4random_buf(&spi, sizeof spi); + } while (spi == 0); return (spi); } void -config_free_sa(struct iked *env, struct iked_sa *sa) +config_free_kex(struct iked_kex *kex) { - (void)RB_REMOVE(iked_sas, &env->sc_sas, sa); + if (kex == NULL) + return; + + ibuf_release(kex->kex_inonce); + ibuf_release(kex->kex_rnonce); - timer_deregister(env, &sa->sa_timer); + if (kex->kex_dhgroup != NULL) + group_free(kex->kex_dhgroup); + ibuf_release(kex->kex_dhiexchange); + ibuf_release(kex->kex_dhrexchange); + + free(kex); +} + +void +config_free_sa(struct iked *env, struct iked_sa *sa) +{ + timer_del(env, &sa->sa_timer); + timer_del(env, &sa->sa_rekey); config_free_proposals(&sa->sa_proposals, 0); config_free_childsas(env, &sa->sa_childsas, NULL, NULL); sa_free_flows(env, &sa->sa_flows); + if (sa->sa_addrpool) { + (void)RB_REMOVE(iked_addrpool, &env->sc_addrpool, sa); + free(sa->sa_addrpool); + } + if (sa->sa_policy) { - (void)RB_REMOVE(iked_sapeers, &sa->sa_policy->pol_sapeers, sa); + TAILQ_REMOVE(&sa->sa_policy->pol_sapeers, sa, sa_peer_entry); policy_unref(env, sa->sa_policy); } @@ -145,8 +157,10 @@ config_new_policy(struct iked *env) if ((pol = calloc(1, sizeof(*pol))) == NULL) return (NULL); + /* XXX caller does this again */ TAILQ_INIT(&pol->pol_proposals); - RB_INIT(&pol->pol_sapeers); + TAILQ_INIT(&pol->pol_sapeers); + RB_INIT(&pol->pol_flows); return (pol); } @@ -161,10 +175,13 @@ config_free_policy(struct iked *env, struct iked_policy *pol) TAILQ_REMOVE(&env->sc_policies, pol, pol_entry); - RB_FOREACH(sa, iked_sapeers, &pol->pol_sapeers) { - /* Remove from the policy tree, but keep for existing SAs */ + TAILQ_FOREACH(sa, &pol->pol_sapeers, sa_peer_entry) { + /* Remove from the policy list, but keep for existing SAs */ if (sa->sa_policy == pol) policy_ref(env, pol); + else + log_warnx("%s: ERROR: sa_policy %p != pol %p", + __func__, sa->sa_policy, pol); } if (pol->pol_refcnt) @@ -177,7 +194,8 @@ config_free_policy(struct iked *env, struct iked_policy *pol) } struct iked_proposal * -config_add_proposal(struct iked_proposals *head, u_int id, u_int proto) +config_add_proposal(struct iked_proposals *head, unsigned int id, + unsigned int proto) { struct iked_proposal *pp; @@ -199,7 +217,7 @@ config_add_proposal(struct iked_proposals *head, u_int id, u_int proto) } void -config_free_proposals(struct iked_proposals *head, u_int proto) +config_free_proposals(struct iked_proposals *head, unsigned int proto) { struct iked_proposal *prop, *next; @@ -266,13 +284,13 @@ config_free_childsas(struct iked *env, struct iked_childsas *head, } struct iked_transform * -config_add_transform(struct iked_proposal *prop, u_int type, - u_int id, u_int length, u_int keylength) +config_add_transform(struct iked_proposal *prop, unsigned int type, + unsigned int id, unsigned int length, unsigned int keylength) { struct iked_transform *xform; struct iked_constmap *map = NULL; int score = 1; - u_int i; + unsigned int i; switch (type) { case IKEV2_XFORMTYPE_ENCR: @@ -321,8 +339,8 @@ config_add_transform(struct iked_proposal *prop, u_int type, } } - if ((xform = realloc(prop->prop_xforms, - (prop->prop_nxforms + 1) * sizeof(*xform))) == NULL) { + if ((xform = reallocarray(prop->prop_xforms, + prop->prop_nxforms + 1, sizeof(*xform))) == NULL) { return (NULL); } @@ -341,14 +359,18 @@ config_add_transform(struct iked_proposal *prop, u_int type, } struct iked_transform * -config_findtransform(struct iked_proposals *props, u_int8_t type) +config_findtransform(struct iked_proposals *props, uint8_t type, + unsigned int proto) { struct iked_proposal *prop; struct iked_transform *xform; - u_int i; + unsigned int i; /* Search of the first transform with the desired type */ TAILQ_FOREACH(prop, props, prop_entry) { + /* Find any proposal or only selected SA proto */ + if (proto != 0 && prop->prop_protoid != proto) + continue; for (i = 0; i < prop->prop_nxforms; i++) { xform = prop->prop_xforms + i; if (xform->xform_type == type) @@ -388,41 +410,41 @@ config_new_user(struct iked *env, struct iked_user *new) */ int -config_setcoupled(struct iked *env, u_int couple) +config_setcoupled(struct iked *env, unsigned int couple) { - u_int type; + unsigned int type; type = couple ? IMSG_CTL_COUPLE : IMSG_CTL_DECOUPLE; - proc_compose_imsg(env, PROC_IKEV1, type, -1, NULL, 0); - proc_compose_imsg(env, PROC_IKEV2, type, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, PROC_IKEV1, -1, type, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, PROC_IKEV2, -1, type, -1, NULL, 0); return (0); } int -config_getcoupled(struct iked *env, u_int type) +config_getcoupled(struct iked *env, unsigned int type) { return (pfkey_couple(env->sc_pfkey, &env->sc_sas, type == IMSG_CTL_COUPLE ? 1 : 0)); } int -config_setmode(struct iked *env, u_int passive) +config_setmode(struct iked *env, unsigned int passive) { - u_int type; + unsigned int type; type = passive ? IMSG_CTL_PASSIVE : IMSG_CTL_ACTIVE; - proc_compose_imsg(env, PROC_IKEV1, type, -1, NULL, 0); - proc_compose_imsg(env, PROC_IKEV2, type, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, PROC_IKEV1, -1, type, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, PROC_IKEV2, -1, type, -1, NULL, 0); return (0); } int -config_getmode(struct iked *env, u_int type) +config_getmode(struct iked *env, unsigned int type) { - u_int8_t old; - u_char *mode[] = { "active", "passive" }; + uint8_t old; + unsigned char *mode[] = { "active", "passive" }; old = env->sc_passive ? 1 : 0; env->sc_passive = type == IMSG_CTL_PASSIVE ? 1 : 0; @@ -437,9 +459,10 @@ config_getmode(struct iked *env, u_int type) } int -config_setreset(struct iked *env, u_int mode, enum privsep_procid id) +config_setreset(struct iked *env, unsigned int mode, enum privsep_procid id) { - proc_compose_imsg(env, id, IMSG_CTL_RESET, -1, &mode, sizeof(mode)); + proc_compose_imsg(&env->sc_ps, id, -1, + IMSG_CTL_RESET, -1, &mode, sizeof(mode)); return (0); } @@ -449,7 +472,7 @@ config_getreset(struct iked *env, struct imsg *imsg) struct iked_policy *pol, *nextpol; struct iked_sa *sa, *nextsa; struct iked_user *usr, *nextusr; - u_int mode; + unsigned int mode; IMSG_SIZE_CHECK(imsg, &mode); memcpy(&mode, imsg->data, sizeof(mode)); @@ -468,6 +491,7 @@ config_getreset(struct iked *env, struct imsg *imsg) for (sa = RB_MIN(iked_sas, &env->sc_sas); sa != NULL; sa = nextsa) { nextsa = RB_NEXT(iked_sas, &env->sc_sas, sa); + RB_REMOVE(iked_sas, &env->sc_sas, sa); config_free_sa(env, sa); } } @@ -493,8 +517,8 @@ config_setsocket(struct iked *env, struct sockaddr_storage *ss, if ((s = udp_bind((struct sockaddr *)ss, port)) == -1) return (-1); - proc_compose_imsg(env, id, IMSG_UDP_SOCKET, s, - ss, sizeof(*ss)); + proc_compose_imsg(&env->sc_ps, id, -1, + IMSG_UDP_SOCKET, s, ss, sizeof(*ss)); return (0); } @@ -531,7 +555,8 @@ config_getsocket(struct iked *env, struct imsg *imsg, if (*sptr == NULL) *sptr = sock; if (*nptr == NULL && - socket_getport(&sock->sock_addr) == IKED_NATT_PORT) + socket_getport((struct sockaddr *)&sock->sock_addr) == + IKED_NATT_PORT) *nptr = sock; event_set(&sock->sock_ev, sock->sock_fd, @@ -548,7 +573,8 @@ config_setpfkey(struct iked *env, enum privsep_procid id) if ((s = pfkey_socket()) == -1) return (-1); - proc_compose_imsg(env, id, IMSG_PFKEY_SOCKET, s, NULL, 0); + proc_compose_imsg(&env->sc_ps, id, -1, + IMSG_PFKEY_SOCKET, s, NULL, 0); return (0); } @@ -568,7 +594,8 @@ config_setuser(struct iked *env, struct iked_user *usr, enum privsep_procid id) return (0); } - proc_compose_imsg(env, id, IMSG_CFG_USER, -1, usr, sizeof(*usr)); + proc_compose_imsg(&env->sc_ps, id, -1, + IMSG_CFG_USER, -1, usr, sizeof(*usr)); return (0); } @@ -638,8 +665,8 @@ config_setpolicy(struct iked *env, struct iked_policy *pol, return (0); } - if (proc_composev_imsg(env, id, IMSG_CFG_POLICY, -1, - iov, iovcnt) == -1) + if (proc_composev_imsg(&env->sc_ps, id, -1, + IMSG_CFG_POLICY, -1, iov, iovcnt) == -1) return (-1); return (0); @@ -653,8 +680,8 @@ config_getpolicy(struct iked *env, struct imsg *imsg) struct iked_transform xf, *xform; struct iked_flow *flow; off_t offset = 0; - u_int i, j; - u_int8_t *buf = (u_int8_t *)imsg->data; + unsigned int i, j; + uint8_t *buf = (uint8_t *)imsg->data; IMSG_SIZE_CHECK(imsg, pol); log_debug("%s: received policy", __func__); @@ -666,6 +693,7 @@ config_getpolicy(struct iked *env, struct imsg *imsg) offset += sizeof(*pol); TAILQ_INIT(&pol->pol_proposals); + TAILQ_INIT(&pol->pol_sapeers); RB_INIT(&pol->pol_flows); for (i = 0; i < pol->pol_nproposals; i++) { @@ -694,7 +722,8 @@ config_getpolicy(struct iked *env, struct imsg *imsg) memcpy(flow, buf + offset, sizeof(*flow)); offset += sizeof(*flow); - RB_INSERT(iked_flows, &pol->pol_flows, flow); + if (RB_INSERT(iked_flows, &pol->pol_flows, flow)) + free(flow); } TAILQ_INSERT_TAIL(&env->sc_policies, pol, pol_entry); @@ -717,7 +746,8 @@ config_setcompile(struct iked *env, enum privsep_procid id) if (env->sc_opts & IKED_OPT_NOACTION) return (0); - proc_compose_imsg(env, id, IMSG_COMPILE, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, id, -1, + IMSG_COMPILE, -1, NULL, 0); return (0); } @@ -733,3 +763,29 @@ config_getcompile(struct iked *env, struct imsg *imsg) log_debug("%s: compilation done", __func__); return (0); } + +int +config_setocsp(struct iked *env) +{ + if (env->sc_opts & IKED_OPT_NOACTION) + return (0); + proc_compose_imsg(&env->sc_ps, PROC_CERT, -1, + IMSG_OCSP_URL, -1, env->sc_ocsp_url, + env->sc_ocsp_url ? strlen(env->sc_ocsp_url) : 0); + + return (0); +} + +int +config_getocsp(struct iked *env, struct imsg *imsg) +{ + if (env->sc_ocsp_url) + free(env->sc_ocsp_url); + if (IMSG_DATA_SIZE(imsg) > 0) + env->sc_ocsp_url = get_string(imsg->data, IMSG_DATA_SIZE(imsg)); + else + env->sc_ocsp_url = NULL; + log_debug("%s: ocsp_url %s", __func__, + env->sc_ocsp_url ? env->sc_ocsp_url : "none"); + return (0); +} diff --git a/iked/control.c b/iked/control.c index dfa48b3..3932008 100644 --- a/iked/control.c +++ b/iked/control.c @@ -1,4 +1,4 @@ -/* $OpenBSD: control.c,v 1.12 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: control.c,v 1.16 2015/01/16 06:39:58 deraadt Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -17,12 +17,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "openbsd-compat/sys-queue.h" -#include +#include #include #include #include -#include "openbsd-compat/sys-tree.h" +#include #include @@ -241,22 +240,17 @@ control_dispatch_imsg(int fd, short event, void *arg) return; } - switch (event) { - case EV_READ: + if (event & EV_READ) { if ((n = imsg_read(&c->iev.ibuf)) == -1 || n == 0) { control_close(fd, cs); return; } - break; - case EV_WRITE: - if (msgbuf_write(&c->iev.ibuf.w) < 0) { + } + if (event & EV_WRITE) { + if (msgbuf_write(&c->iev.ibuf.w) <= 0 && errno != EAGAIN) { control_close(fd, cs); return; } - imsg_event_add(&c->iev); - return; - default: - fatalx("unknown event"); } for (;;) { @@ -288,9 +282,9 @@ control_dispatch_imsg(int fd, short event, void *arg) memcpy(&v, imsg.data, sizeof(v)); log_verbose(v); - proc_forward_imsg(env, &imsg, PROC_PARENT); - proc_forward_imsg(env, &imsg, PROC_IKEV2); - proc_forward_imsg(env, &imsg, PROC_IKEV1); + proc_forward_imsg(&env->sc_ps, &imsg, PROC_PARENT, -1); + proc_forward_imsg(&env->sc_ps, &imsg, PROC_IKEV2, -1); + proc_forward_imsg(&env->sc_ps, &imsg, PROC_IKEV1, -1); break; case IMSG_CTL_RELOAD: case IMSG_CTL_RESET: @@ -298,7 +292,7 @@ control_dispatch_imsg(int fd, short event, void *arg) case IMSG_CTL_DECOUPLE: case IMSG_CTL_ACTIVE: case IMSG_CTL_PASSIVE: - proc_forward_imsg(env, &imsg, PROC_PARENT); + proc_forward_imsg(&env->sc_ps, &imsg, PROC_PARENT, -1); break; default: log_debug("%s: error handling imsg %d", diff --git a/iked/crypto.c b/iked/crypto.c index 6959c37..c956e79 100644 --- a/iked/crypto.c +++ b/iked/crypto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: crypto.c,v 1.9 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: crypto.c,v 1.18 2015/08/21 11:59:27 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include /* roundup */ +#include #include #include @@ -34,12 +34,44 @@ #include #include #include +#include #include "iked.h" #include "ikev2.h" +/* RFC 7427, A.1 */ +static const uint8_t sha256WithRSAEncryption[] = { + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00 +}; +static const uint8_t sha384WithRSAEncryption[] = { + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00 +}; +static const uint8_t sha512WithRSAEncryption[] = { + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00 +}; + +struct { + uint8_t sc_len; + const uint8_t *sc_oid; + const EVP_MD *(*sc_md)(void); +} schemes[] = { + { sizeof(sha256WithRSAEncryption), + sha256WithRSAEncryption, EVP_sha256 }, + { sizeof(sha384WithRSAEncryption), + sha384WithRSAEncryption, EVP_sha384 }, + { sizeof(sha512WithRSAEncryption), + sha512WithRSAEncryption, EVP_sha512 }, +}; + +int _dsa_verify_init(struct iked_dsa *, const uint8_t *, size_t); +size_t _dsa_verify_offset(struct iked_dsa *, uint8_t *); +int _dsa_sign_encode(struct iked_dsa *, uint8_t *, size_t *); + struct iked_hash * -hash_new(u_int8_t type, u_int16_t id) +hash_new(uint8_t type, uint16_t id) { struct iked_hash *hash; const EVP_MD *md = NULL; @@ -197,7 +229,7 @@ hash_update(struct iked_hash *hash, void *buf, size_t len) void hash_final(struct iked_hash *hash, void *buf, size_t *len) { - u_int length = 0; + unsigned int length = 0; HMAC_Final(hash->hash_ctx, buf, &length); *len = (size_t)length; @@ -222,7 +254,7 @@ hash_keylength(struct iked_hash *hash) } struct iked_cipher * -cipher_new(u_int8_t type, u_int16_t id, u_int16_t id_length) +cipher_new(uint8_t type, uint16_t id, uint16_t id_length) { struct iked_cipher *encr; const EVP_CIPHER *cipher = NULL; @@ -328,7 +360,7 @@ cipher_setiv(struct iked_cipher *encr, void *iv, size_t len) ibuf_release(encr->encr_iv); if (iv != NULL) { if (len < encr->encr_ivlength) { - log_debug("%s: invalid IV length %d", __func__, len); + log_debug("%s: invalid IV length %zu", __func__, len); return (NULL); } encr->encr_iv = ibuf_new(iv, encr->encr_ivlength); @@ -384,7 +416,7 @@ cipher_update(struct iked_cipher *encr, void *in, size_t inlen, olen = 0; if (!EVP_CipherUpdate(encr->encr_ctx, out, &olen, in, inlen)) { - ca_sslerror(); + ca_sslerror(__func__); *outlen = 0; return; } @@ -398,7 +430,7 @@ cipher_final(struct iked_cipher *encr, void *out, size_t *outlen) olen = 0; if (!EVP_CipherFinal_ex(encr->encr_ctx, out, &olen)) { - ca_sslerror(); + ca_sslerror(__func__); *outlen = 0; return; } @@ -434,23 +466,22 @@ cipher_outlength(struct iked_cipher *encr, size_t inlen) } struct iked_dsa * -dsa_new(u_int16_t id, struct iked_hash *prf, int sign) +dsa_new(uint16_t id, struct iked_hash *prf, int sign) { struct iked_dsa *dsap = NULL, dsa; bzero(&dsa, sizeof(dsa)); switch (id) { + case IKEV2_AUTH_SIG: + if (sign) + dsa.dsa_priv = EVP_sha256(); /* XXX should be passed */ + else + dsa.dsa_priv = NULL; /* set later by dsa_init() */ + break; case IKEV2_AUTH_RSA_SIG: - /* - * XXX RFC4306 is not very clear about this and the - * XXX informational RFC4718 says that we should use - * XXX SHA1 here, but shouldn't we use the negotiated PRF - * XXX alg instead? - */ - if ((dsa.dsa_priv = - EVP_get_digestbyname("sha1WithRSAEncryption")) == NULL) - fatalx("dsa_new: cipher not available"); + /* RFC5996 says we SHOULD use SHA1 here */ + dsa.dsa_priv = EVP_sha1(); break; case IKEV2_AUTH_SHARED_KEY_MIC: if (prf == NULL || prf->hash_priv == NULL) @@ -505,13 +536,13 @@ dsa_new(u_int16_t id, struct iked_hash *prf, int sign) } struct iked_dsa * -dsa_sign_new(u_int16_t id, struct iked_hash *prf) +dsa_sign_new(uint16_t id, struct iked_hash *prf) { return (dsa_new(id, prf, 1)); } struct iked_dsa * -dsa_verify_new(u_int16_t id, struct iked_hash *prf) +dsa_verify_new(uint16_t id, struct iked_hash *prf) { return (dsa_new(id, prf, 0)); } @@ -537,7 +568,7 @@ dsa_free(struct iked_dsa *dsa) } struct ibuf * -dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, u_int8_t type) +dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, uint8_t type) { BIO *rawcert = NULL; X509 *cert = NULL; @@ -578,6 +609,7 @@ dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, u_int8_t type) if (!EVP_PKEY_set1_RSA(pkey, rsa)) goto sslerr; + RSA_free(rsa); /* pkey now has the reference */ dsa->dsa_cert = NULL; dsa->dsa_key = pkey; break; @@ -591,7 +623,7 @@ dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, u_int8_t type) return (dsa->dsa_keydata); sslerr: - ca_sslerror(); + ca_sslerror(__func__); err: log_debug("%s: error", __func__); @@ -608,7 +640,53 @@ dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, u_int8_t type) } int -dsa_init(struct iked_dsa *dsa) +_dsa_verify_init(struct iked_dsa *dsa, const uint8_t *sig, size_t len) +{ + uint8_t oidlen; + size_t i; + + if (dsa->dsa_priv != NULL) + return (0); + /* + * For IKEV2_AUTH_SIG the oid of the authentication signature + * is encoded in the first bytes of the auth message. + */ + if (dsa->dsa_method != IKEV2_AUTH_SIG) { + log_debug("%s: dsa_priv not set for %s", __func__, + print_map(dsa->dsa_method, ikev2_auth_map)); + return (-1); + } + if (sig == NULL) { + log_debug("%s: signature missing", __func__); + return (-1); + } + if (len < 1) { + log_debug("%s: signature (%zu) too small for oid length", + __func__, len); + return (-1); + } + memcpy(&oidlen, sig, sizeof(oidlen)); + if (len < (size_t)oidlen + 1) { + log_debug("%s: signature (%zu) too small for oid (%u)", + __func__, len, oidlen); + return (-1); + } + for (i = 0; i < nitems(schemes); i++) { + if (oidlen == schemes[i].sc_len && + memcmp(sig + 1, schemes[i].sc_oid, + schemes[i].sc_len) == 0) { + dsa->dsa_priv = (*schemes[i].sc_md)(); + log_debug("%s: signature scheme %zd selected", + __func__, i); + return (0); + } + } + log_debug("%s: unsupported signature (%d)", __func__, oidlen); + return (-1); +} + +int +dsa_init(struct iked_dsa *dsa, const void *buf, size_t len) { int ret; @@ -621,8 +699,11 @@ dsa_init(struct iked_dsa *dsa) if (dsa->dsa_sign) ret = EVP_SignInit_ex(dsa->dsa_ctx, dsa->dsa_priv, NULL); - else + else { + if ((ret = _dsa_verify_init(dsa, buf, len)) != 0) + return (ret); ret = EVP_VerifyInit_ex(dsa->dsa_ctx, dsa->dsa_priv, NULL); + } return (ret ? 0 : -1); } @@ -642,18 +723,44 @@ dsa_update(struct iked_dsa *dsa, const void *buf, size_t len) return (ret ? 0 : -1); } +/* Prefix signature hash with encoded type */ +int +_dsa_sign_encode(struct iked_dsa *dsa, uint8_t *ptr, size_t *offp) +{ + if (offp) + *offp = 0; + if (dsa->dsa_method != IKEV2_AUTH_SIG) + return (0); + if (dsa->dsa_priv != EVP_sha256()) + return (-1); + if (ptr) { + ptr[0] = sizeof(sha256WithRSAEncryption); + memcpy(ptr + 1, sha256WithRSAEncryption, + sizeof(sha256WithRSAEncryption)); + } + if (offp) + *offp = 1 + sizeof(sha256WithRSAEncryption); + return (0); +} + size_t dsa_length(struct iked_dsa *dsa) { + size_t off = 0; + if (dsa->dsa_hmac) return (EVP_MD_size(dsa->dsa_priv)); - return (EVP_PKEY_size(dsa->dsa_key)); + if (_dsa_sign_encode(dsa, NULL, &off) < 0) + fatal("dsa_length: internal error"); + return (EVP_PKEY_size(dsa->dsa_key) + off); } ssize_t dsa_sign_final(struct iked_dsa *dsa, void *buf, size_t len) { - u_int siglen; + unsigned int siglen; + size_t off = 0; + uint8_t *ptr = buf; if (len < dsa_length(dsa)) return (-1); @@ -662,19 +769,36 @@ dsa_sign_final(struct iked_dsa *dsa, void *buf, size_t len) if (!HMAC_Final(dsa->dsa_ctx, buf, &siglen)) return (-1); } else { - if (!EVP_SignFinal(dsa->dsa_ctx, buf, &siglen, + if (_dsa_sign_encode(dsa, ptr, &off) < 0) + return (-1); + if (!EVP_SignFinal(dsa->dsa_ctx, ptr + off, &siglen, dsa->dsa_key)) return (-1); + siglen += off; } return (siglen); } +size_t +_dsa_verify_offset(struct iked_dsa *dsa, uint8_t *ptr) +{ + /* + * XXX assumes that _dsa_verify_init() has already checked + * the encoded method. + */ + if (dsa->dsa_method == IKEV2_AUTH_SIG) + return (ptr[0] + 1); + return (0); +} + ssize_t dsa_verify_final(struct iked_dsa *dsa, void *buf, size_t len) { - u_int8_t sig[EVP_MAX_MD_SIZE]; - u_int siglen = sizeof(sig); + uint8_t sig[EVP_MAX_MD_SIZE]; + unsigned int siglen = sizeof(sig); + uint8_t *ptr = buf; + size_t off = 0; if (dsa->dsa_hmac) { if (!HMAC_Final(dsa->dsa_ctx, sig, &siglen)) @@ -682,9 +806,11 @@ dsa_verify_final(struct iked_dsa *dsa, void *buf, size_t len) if (siglen != len || memcmp(buf, sig, siglen) != 0) return (-1); } else { - if (EVP_VerifyFinal(dsa->dsa_ctx, buf, len, + if ((off = _dsa_verify_offset(dsa, ptr)) >= len) + return (-1); + if (EVP_VerifyFinal(dsa->dsa_ctx, ptr + off, len - off, dsa->dsa_key) != 1) { - ca_sslerror(); + ca_sslerror(__func__); return (-1); } } diff --git a/iked/dh.c b/iked/dh.c index de33d96..a3c462f 100644 --- a/iked/dh.c +++ b/iked/dh.c @@ -1,7 +1,7 @@ -/* $OpenBSD: dh.c,v 1.10 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: dh.c,v 1.17 2015/08/21 11:59:27 reyk Exp $ */ /* - * Copyright (c) 2010-2013 Reyk Floeter + * Copyright (c) 2010-2014 Reyk Floeter * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,31 +16,52 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +#include /* roundup */ #include #include #include #include #include +#include #include "dh.h" int dh_init(struct group *); +/* MODP */ int modp_init(struct group *); int modp_getlen(struct group *); -int modp_create_exchange(struct group *, u_int8_t *); -int modp_create_shared(struct group *, u_int8_t *, u_int8_t *); +int modp_create_exchange(struct group *, uint8_t *); +int modp_create_shared(struct group *, uint8_t *, uint8_t *); +/* EC2N/ECP */ int ec_init(struct group *); int ec_getlen(struct group *); -int ec_create_exchange(struct group *, u_int8_t *); -int ec_create_shared(struct group *, u_int8_t *, u_int8_t *); +int ec_create_exchange(struct group *, uint8_t *); +int ec_create_shared(struct group *, uint8_t *, uint8_t *); -int ec_point2raw(struct group *, const EC_POINT *, u_int8_t *, size_t); +int ec_point2raw(struct group *, const EC_POINT *, uint8_t *, size_t); EC_POINT * - ec_raw2point(struct group *, u_int8_t *, size_t); + ec_raw2point(struct group *, uint8_t *, size_t); + +/* curve25519 */ +int ec25519_init(struct group *); +int ec25519_getlen(struct group *); +int ec25519_create_exchange(struct group *, uint8_t *); +int ec25519_create_shared(struct group *, uint8_t *, uint8_t *); + +#define CURVE25519_SIZE 32 /* 256 bits */ +struct curve25519_key { + uint8_t secret[CURVE25519_SIZE]; + uint8_t public[CURVE25519_SIZE]; +}; +extern int crypto_scalarmult_curve25519(unsigned char a[CURVE25519_SIZE], + const unsigned char b[CURVE25519_SIZE], + const unsigned char c[CURVE25519_SIZE]) + __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) + __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))) + __attribute__((__bounded__(__minbytes__, 3, CURVE25519_SIZE))); struct group_id ike_groups[] = { { GROUP_MODP, 1, 768, @@ -277,7 +298,14 @@ struct group_id ike_groups[] = { "5E2327CFEF98C582664B4C0F6CC41659" }, { GROUP_ECP, 25, 192, NULL, NULL, NID_X9_62_prime192v1 }, - { GROUP_ECP, 26, 224, NULL, NULL, NID_secp224r1 } + { GROUP_ECP, 26, 224, NULL, NULL, NID_secp224r1 }, + { GROUP_ECP, 27, 224, NULL, NULL, NID_brainpoolP224r1 }, + { GROUP_ECP, 28, 256, NULL, NULL, NID_brainpoolP256r1 }, + { GROUP_ECP, 29, 384, NULL, NULL, NID_brainpoolP384r1 }, + { GROUP_ECP, 30, 512, NULL, NULL, NID_brainpoolP512r1 }, + + /* "Private use" extensions */ + { GROUP_CURVE25519, 1034, CURVE25519_SIZE * 8 } }; void @@ -296,16 +324,21 @@ group_free(struct group *group) DH_free(group->dh); if (group->ec != NULL) EC_KEY_free(group->ec); + if (group->curve25519 != NULL) { + explicit_bzero(group->curve25519, + sizeof(struct curve25519_key)); + free(group->curve25519); + } group->spec = NULL; free(group); } struct group * -group_get(u_int32_t id) +group_get(uint32_t id) { struct group_id *p = NULL; struct group *group; - u_int i, items; + unsigned int i, items; items = sizeof(ike_groups) / sizeof(ike_groups[0]); for (i = 0; i < items; i++) { @@ -337,6 +370,12 @@ group_get(u_int32_t id) group->exchange = ec_create_exchange; group->shared = ec_create_shared; break; + case GROUP_CURVE25519: + group->init = ec25519_init; + group->getlen = ec25519_getlen; + group->exchange = ec25519_create_exchange; + group->shared = ec25519_create_shared; + break; default: group_free(group); return (NULL); @@ -363,13 +402,13 @@ dh_getlen(struct group *group) } int -dh_create_exchange(struct group *group, u_int8_t *buf) +dh_create_exchange(struct group *group, uint8_t *buf) { return (group->exchange(group, buf)); } int -dh_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange) +dh_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) { return (group->shared(group, secret, exchange)); } @@ -399,7 +438,7 @@ modp_getlen(struct group *group) } int -modp_create_exchange(struct group *group, u_int8_t *buf) +modp_create_exchange(struct group *group, uint8_t *buf) { DH *dh = group->dh; int len, ret; @@ -422,7 +461,7 @@ modp_create_exchange(struct group *group, u_int8_t *buf) } int -modp_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange) +modp_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) { BIGNUM *ex; int len, ret; @@ -434,7 +473,7 @@ modp_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange) ret = DH_compute_key(secret, ex, group->dh); BN_clear_free(ex); - if (!ret) + if (ret <= 0) return (-1); /* add zero padding */ @@ -453,6 +492,10 @@ ec_init(struct group *group) return (-1); if (!EC_KEY_generate_key(group->ec)) return (-1); + if (!EC_KEY_check_key(group->ec)) { + EC_KEY_free(group->ec); + return (-1); + } return (0); } @@ -466,7 +509,7 @@ ec_getlen(struct group *group) } int -ec_create_exchange(struct group *group, u_int8_t *buf) +ec_create_exchange(struct group *group, uint8_t *buf) { size_t len; @@ -478,10 +521,11 @@ ec_create_exchange(struct group *group, u_int8_t *buf) } int -ec_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange) +ec_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) { const EC_GROUP *ecgroup = NULL; const BIGNUM *privkey; + EC_KEY *exkey = NULL; EC_POINT *exchangep = NULL, *secretp = NULL; int ret = -1; @@ -493,6 +537,17 @@ ec_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange) ec_raw2point(group, exchange, ec_getlen(group))) == NULL) goto done; + if ((exkey = EC_KEY_new()) == NULL) + goto done; + if (!EC_KEY_set_group(exkey, ecgroup)) + goto done; + if (!EC_KEY_set_public_key(exkey, exchangep)) + goto done; + + /* validate exchangep */ + if (!EC_KEY_check_key(exkey)) + goto done; + if ((secretp = EC_POINT_new(ecgroup)) == NULL) goto done; @@ -502,6 +557,8 @@ ec_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange) ret = ec_point2raw(group, secretp, secret, ec_getlen(group)); done: + if (exkey != NULL) + EC_KEY_free(exkey); if (exchangep != NULL) EC_POINT_clear_free(exchangep); if (secretp != NULL) @@ -512,7 +569,7 @@ ec_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange) int ec_point2raw(struct group *group, const EC_POINT *point, - u_int8_t *buf, size_t len) + uint8_t *buf, size_t len) { const EC_GROUP *ecgroup = NULL; BN_CTX *bnctx = NULL; @@ -559,6 +616,11 @@ ec_point2raw(struct group *group, const EC_POINT *point, ret = 0; done: + /* Make sure to erase sensitive data */ + if (x != NULL) + BN_clear(x); + if (y != NULL) + BN_clear(y); BN_CTX_end(bnctx); BN_CTX_free(bnctx); @@ -566,7 +628,7 @@ ec_point2raw(struct group *group, const EC_POINT *point, } EC_POINT * -ec_raw2point(struct group *group, u_int8_t *buf, size_t len) +ec_raw2point(struct group *group, uint8_t *buf, size_t len) { const EC_GROUP *ecgroup = NULL; EC_POINT *point = NULL; @@ -612,8 +674,57 @@ ec_raw2point(struct group *group, u_int8_t *buf, size_t len) done: if (ret != 0 && point != NULL) EC_POINT_clear_free(point); + /* Make sure to erase sensitive data */ + if (x != NULL) + BN_clear(x); + if (y != NULL) + BN_clear(y); BN_CTX_end(bnctx); BN_CTX_free(bnctx); return (point); } + +int +ec25519_init(struct group *group) +{ + static const uint8_t basepoint[CURVE25519_SIZE] = { 9 }; + struct curve25519_key *curve25519; + + if ((curve25519 = calloc(1, sizeof(*curve25519))) == NULL) + return (-1); + + group->curve25519 = curve25519; + + arc4random_buf(curve25519->secret, CURVE25519_SIZE); + crypto_scalarmult_curve25519(curve25519->public, + curve25519->secret, basepoint); + + return (0); +} + +int +ec25519_getlen(struct group *group) +{ + if (group->spec == NULL) + return (0); + return (CURVE25519_SIZE); +} + +int +ec25519_create_exchange(struct group *group, uint8_t *buf) +{ + struct curve25519_key *curve25519 = group->curve25519; + + memcpy(buf, curve25519->public, ec25519_getlen(group)); + return (0); +} + +int +ec25519_create_shared(struct group *group, uint8_t *shared, uint8_t *public) +{ + struct curve25519_key *curve25519 = group->curve25519; + + crypto_scalarmult_curve25519(shared, curve25519->secret, public); + return (0); +} diff --git a/iked/dh.h b/iked/dh.h index d7b8ea8..e5b825c 100644 --- a/iked/dh.h +++ b/iked/dh.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dh.h,v 1.5 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: dh.h,v 1.9 2015/08/21 11:59:27 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,18 +16,19 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _DH_H_ -#define _DH_H_ +#ifndef DH_GROUP_H +#define DH_GROUP_H enum group_type { - GROUP_MODP = 0, - GROUP_EC2N = 1, - GROUP_ECP = 2 + GROUP_MODP = 0, + GROUP_EC2N = 1, + GROUP_ECP = 2, + GROUP_CURVE25519 = 3 }; struct group_id { enum group_type type; - u_int id; + unsigned int id; int bits; char *prime; char *generator; @@ -40,21 +41,22 @@ struct group { void *dh; void *ec; + void *curve25519; int (*init)(struct group *); int (*getlen)(struct group *); - int (*exchange)(struct group *, u_int8_t *); - int (*shared)(struct group *, u_int8_t *, u_int8_t *); + int (*exchange)(struct group *, uint8_t *); + int (*shared)(struct group *, uint8_t *, uint8_t *); }; #define DH_MAXSZ 1024 /* 8192 bits */ -void group_init(void); -void group_free(struct group *); -struct group *group_get(u_int32_t); +void group_init(void); +void group_free(struct group *); +struct group *group_get(uint32_t); int dh_getlen(struct group *); -int dh_create_exchange(struct group *, u_int8_t *); -int dh_create_shared(struct group *, u_int8_t *, u_int8_t *); +int dh_create_exchange(struct group *, uint8_t *); +int dh_create_shared(struct group *, uint8_t *, uint8_t *); -#endif /* _DH_H_ */ +#endif /* DH_GROUP_H */ diff --git a/iked/eap.c b/iked/eap.c index bbb5a7c..a7764b1 100644 --- a/iked/eap.c +++ b/iked/eap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: eap.c,v 1.9 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: eap.c,v 1.14 2015/08/21 11:59:27 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,23 +16,18 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include #include #include #include #include -#if defined(__OpenBSD__) -#include -#endif #include #include #include #include #include -#include #include #include #include @@ -71,19 +66,19 @@ eap_identity_request(struct ibuf *e) char * eap_identity_response(struct eap_message *eap) { - size_t len; - char *str; - u_int8_t *ptr = (u_int8_t *)eap; + size_t len; + char *str; + uint8_t *ptr = (uint8_t *)eap; len = betoh16(eap->eap_length) - sizeof(*eap); ptr += sizeof(*eap); if (len == 0 || (str = get_string(ptr, len)) == NULL) { - log_info("%s: invalid identity response, length %d", + log_info("%s: invalid identity response, length %zu", __func__, len); return (NULL); } - log_debug("%s: identity '%s' length %d", __func__, str, len); + log_debug("%s: identity '%s' length %zd", __func__, str, len); return (str); } @@ -177,11 +172,11 @@ eap_mschap(struct iked *env, struct iked_sa *sa, struct eap_message *eap) struct eap_mschap_peer *msp; struct eap_mschap *ms; struct eap_mschap_success *mss; - u_int8_t *ptr, *pass; + uint8_t *ptr, *pass; size_t len, passlen; char *name, *msg; - u_int8_t ntresponse[EAP_MSCHAP_NTRESPONSE_SZ]; - u_int8_t successmsg[EAP_MSCHAP_SUCCESS_SZ]; + uint8_t ntresponse[EAP_MSCHAP_NTRESPONSE_SZ]; + uint8_t successmsg[EAP_MSCHAP_SUCCESS_SZ]; struct ibuf *eapmsg = NULL; int ret = -1; @@ -208,7 +203,7 @@ eap_mschap(struct iked *env, struct iked_sa *sa, struct eap_message *eap) } ms = (struct eap_mschap *)(eap + 1); - ptr = (u_int8_t *)(eap + 1); + ptr = (uint8_t *)(eap + 1); switch (ms->ms_opcode) { case EAP_MSOPCODE_RESPONSE: @@ -336,7 +331,7 @@ eap_parse(struct iked *env, struct iked_sa *sa, void *data, int response) struct eap_header *hdr = data; struct eap_message *eap = data; size_t len; - u_int8_t *ptr; + uint8_t *ptr; struct eap_mschap *ms; struct eap_mschap_challenge *msc; struct eap_mschap_response *msr; @@ -346,7 +341,7 @@ eap_parse(struct iked *env, struct iked_sa *sa, void *data, int response) /* length is already verified by the caller */ len = betoh16(hdr->eap_length); - ptr = (u_int8_t *)(eap + 1); + ptr = (uint8_t *)(eap + 1); switch (hdr->eap_code) { case EAP_CODE_REQUEST: @@ -399,7 +394,7 @@ eap_parse(struct iked *env, struct iked_sa *sa, void *data, int response) return (-1); } log_info("%s: %s %s id %d " - "length %d valuesize %d name '%s' length %d", + "length %d valuesize %d name '%s' length %zu", __func__, print_map(eap->eap_type, eap_type_map), print_map(ms->ms_opcode, eap_msopcode_map), @@ -420,7 +415,7 @@ eap_parse(struct iked *env, struct iked_sa *sa, void *data, int response) return (-1); } log_info("%s: %s %s id %d " - "length %d valuesize %d name '%s' name-length %d", + "length %d valuesize %d name '%s' name-length %zu", __func__, print_map(eap->eap_type, eap_type_map), print_map(ms->ms_opcode, eap_msopcode_map), @@ -442,7 +437,7 @@ eap_parse(struct iked *env, struct iked_sa *sa, void *data, int response) return (-1); } log_info("%s: %s %s request id %d " - "length %d message '%s' message-len %d", + "length %d message '%s' message-len %zu", __func__, print_map(eap->eap_type, eap_type_map), print_map(ms->ms_opcode, eap_msopcode_map), diff --git a/iked/eap.h b/iked/eap.h index a8d158e..cc567ea 100644 --- a/iked/eap.h +++ b/iked/eap.h @@ -1,4 +1,4 @@ -/* $OpenBSD: eap.h,v 1.3 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: eap.h,v 1.5 2015/08/21 11:59:27 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,20 +16,20 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _IKEV2_EAP_H -#define _IKEV2_EAP_H +#ifndef IKED_EAP_H +#define IKED_EAP_H struct eap_header { - u_int8_t eap_code; - u_int8_t eap_id; - u_int16_t eap_length; + uint8_t eap_code; + uint8_t eap_id; + uint16_t eap_length; } __packed; struct eap_message { - u_int8_t eap_code; - u_int8_t eap_id; - u_int16_t eap_length; - u_int8_t eap_type; + uint8_t eap_code; + uint8_t eap_id; + uint16_t eap_length; + uint8_t eap_type; /* Followed by type-specific data */ } __packed; @@ -114,48 +114,48 @@ extern struct iked_constmap eap_type_map[]; extern struct iked_constmap eap_msopcode_map[]; struct eap_mschap { - u_int8_t ms_opcode; + uint8_t ms_opcode; } __packed; struct eap_mschap_challenge { - u_int8_t msc_opcode; - u_int8_t msc_id; - u_int16_t msc_length; - u_int8_t msc_valuesize; - u_int8_t msc_challenge[EAP_MSCHAP_CHALLENGE_SZ]; + uint8_t msc_opcode; + uint8_t msc_id; + uint16_t msc_length; + uint8_t msc_valuesize; + uint8_t msc_challenge[EAP_MSCHAP_CHALLENGE_SZ]; /* Followed by variable-size name field */ } __packed; struct eap_mschap_peer { - u_int8_t msp_challenge[EAP_MSCHAP_CHALLENGE_SZ]; - u_int8_t msp_reserved[8]; - u_int8_t msp_ntresponse[EAP_MSCHAP_NTRESPONSE_SZ]; - u_int8_t msp_flags; + uint8_t msp_challenge[EAP_MSCHAP_CHALLENGE_SZ]; + uint8_t msp_reserved[8]; + uint8_t msp_ntresponse[EAP_MSCHAP_NTRESPONSE_SZ]; + uint8_t msp_flags; }; struct eap_mschap_response { - u_int8_t msr_opcode; - u_int8_t msr_id; - u_int16_t msr_length; - u_int8_t msr_valuesize; + uint8_t msr_opcode; + uint8_t msr_id; + uint16_t msr_length; + uint8_t msr_valuesize; union { - u_int8_t resp_data[EAP_MSCHAP_RESPONSE_SZ]; + uint8_t resp_data[EAP_MSCHAP_RESPONSE_SZ]; struct eap_mschap_peer resp_peer; } msr_response; /* Followed by variable-size name field */ } __packed; struct eap_mschap_success { - u_int8_t mss_opcode; - u_int8_t mss_id; - u_int16_t mss_length; + uint8_t mss_opcode; + uint8_t mss_id; + uint16_t mss_length; /* Followed by variable-size success message */ } __packed; struct eap_mschap_failure { - u_int8_t msf_opcode; - u_int8_t msf_id; - u_int16_t msf_length; + uint8_t msf_opcode; + uint8_t msf_id; + uint16_t msf_length; /* Followed by variable-size message field */ } __packed; @@ -168,4 +168,4 @@ struct eap_mschap_failure { extern struct iked_constmap eap_mserror_map[]; -#endif /* _IKEV2_EAP_H */ +#endif /* IKED_EAP_H */ diff --git a/iked/genmap.sh b/iked/genmap.sh index 685f42e..9cd4ba0 100644 --- a/iked/genmap.sh +++ b/iked/genmap.sh @@ -1,5 +1,5 @@ #!/bin/sh -# $OpenBSD: genmap.sh,v 1.6 2013/01/08 10:38:19 reyk Exp $ +# $OpenBSD: genmap.sh,v 1.7 2015/01/16 06:39:58 deraadt Exp $ # Copyright (c) 2010-2013 Reyk Floeter # @@ -28,7 +28,6 @@ EOF sed -n '1,/^ \*\//p' $1 cat < #include #include "types.h" diff --git a/iked/iked.8 b/iked/iked.8 index 7f2dc16..c03ec11 100644 --- a/iked/iked.8 +++ b/iked/iked.8 @@ -1,6 +1,6 @@ -.\" $OpenBSD: iked.8,v 1.13 2013/01/08 10:38:19 reyk Exp $ +.\" $OpenBSD: iked.8,v 1.19 2014/11/10 13:57:32 jmc Exp $ .\" -.\" Copyright (c) 2010-2013 Reyk Floeter +.\" Copyright (c) 2010 - 2014 Reyk Floeter .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: January 8 2013 $ +.Dd $Mdocdate: November 10 2014 $ .Dt IKED 8 .Os .Sh NAME @@ -23,9 +23,7 @@ .Sh SYNOPSIS .Nm iked .Op Fl 6dnSTtv -.Oo -.Fl D Ar macro Ns = Ns Ar value -.Oc +.Op Fl D Ar macro Ns = Ns Ar value .Op Fl f Ar file .Sh DESCRIPTION .Nm @@ -48,10 +46,8 @@ is provided by .Nm supports mutual authentication using RSA public keys and X.509 certificates. See the -.Sx FILES -section below and -.Sx PKI AND CERTIFICATE AUTHORITY COMMANDS -in +.Sx PUBLIC KEY AUTHENTICATION +section below and PKI AND CERTIFICATE AUTHORITY COMMANDS in .Xr ikectl 8 for more information about creating and maintaining the public key infrastructure. @@ -103,6 +99,54 @@ negotiate NAT-Traversal with the peers. .It Fl v Produce more verbose output. .El +.Sh PUBLIC KEY AUTHENTICATION +It is possible to store trusted public keys to make them directly +usable by +.Nm , +bypassing the need to use certificates. +The keys should be saved in PEM format (see +.Xr openssl 1 ) +and named and stored as follows: +.Pp +.Bl -tag -width "for_ufqdn_identitiesXX" -offset 3n -compact +.It For IPv4 identities: +/etc/iked/pubkeys/ipv4/A.B.C.D +.It For IPv6 identities: +/etc/iked/pubkeys/ipv6/abcd:abcd::ab:bc +.It For FQDN identities: +/etc/iked/pubkeys/fqdn/foo.bar.org +.It For UFQDN identities: +/etc/iked/pubkeys/ufqdn/user@foo.bar.org +.El +.Pp +Depending on the +.Ic srcid +and +.Ic dstid +specifications in +.Xr iked.conf 5 , +keys may be named after their IPv4 address, IPv6 address, +fully qualified domain name (FQDN) or user fully qualified domain name (UFQDN). +.Pp +For example, +.Nm +can authenticate using the pre-generated keys if the local public key, +by default +.Pa /etc/iked/local.pub , +is copied to the remote gateway as +.Pa /etc/iked/pubkeys/ipv4/local.gateway.ip.address +and the remote gateway's public key +is copied to the local gateway as +.Pa /etc/iked/pubkeys/ipv4/remote.gateway.ip.address . +Of course, new keys may also be generated +(the user is not required to use the pre-generated keys). +In this example, +.Ic srcid +and +.Ic dstid +would also have to be set to the specified addresses +in +.Xr iked.conf 5 . .Sh FILES .Bl -tag -width "/etc/iked/private/XXX" -compact .It Pa /etc/iked.conf @@ -154,38 +198,4 @@ program first appeared in The .Nm program was written by -.An Reyk Floeter Aq reyk@openbsd.org . -.Sh CAVEATS -.Nm -is not yet finished and is missing some important security features. -It should not yet be used in production networks. -.Sh BUGS -The portable version of -.Nm , -.Ic OpenIKED , -might have a few limitations on operating systems other than the most -recent versions of -.Ox . -A major difference between -.Ox -and other systems is the API and availability of the IPsec PFKEYv2 -flow implementation (SADB) and message passing between kernel and -.Nm . -Current known limitations are: -.Bl -tag -width Ds -.It Ic VPN traffic leakage prevention -Automatic blocking of IPv6 traffic is not working on KAME-bases stacks. -.It Ic NAT-T -NAT-T is only supported on OpenBSD and Darwin (OS X). -The NAT-T API is not standardized in PFKEYv2, not even on a semi-level, -and differs in most operating systems, if supported at all. -.It Ic Crypto algorithms -Some of the crypto algorithms are either not supported on other -systems or not implemented correctly. -For example, Linux still uses the broken pre-standard version of -hmac-sha2-256 by default that was specified with 96 bit truncation -instead of the standard 128 bit truncation. -The common workaround that allows to specify the truncation length -would be to use Linux' non-standard XFRM kernel API instead of -PFKEYv2. -.El +.An Reyk Floeter Aq Mt reyk@openbsd.org . diff --git a/iked/iked.c b/iked/iked.c index 7419f13..b74251a 100644 --- a/iked/iked.c +++ b/iked/iked.c @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.c,v 1.17 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: iked.c,v 1.25 2015/08/21 11:59:27 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,24 +16,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include #include #include #include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_DEPRECATED_DAEMON -/* Apple deprected daemon() and prints an warning that breaks -Werror */ -#define daemon XXX_daemon -#endif - #include #include #include @@ -48,11 +35,6 @@ #include "iked.h" #include "ikev2.h" -#ifdef HAVE_DEPRECATED_DAEMON -#undef daemon -extern int daemon(int, int); -#endif - __dead void usage(void); void parent_shutdown(struct iked *); @@ -68,12 +50,6 @@ static struct privsep_proc procs[] = { { "ca", PROC_CERT, parent_dispatch_ca, caproc, IKED_CA } }; -#ifndef HAVE_SETPROCTITLE -/* Saved arguments to main(). */ -char **saved_argv; -int saved_argc; -#endif - __dead void usage(void) { @@ -96,24 +72,6 @@ main(int argc, char *argv[]) log_init(1); -#ifndef HAVE_SETPROCTITLE - /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ - saved_argc = argc; - saved_argv = calloc(argc + 1, sizeof(*saved_argv)); - if (saved_argv == NULL) - fatal("calloc: argv"); - for (c = 0; c < argc; c++) { - saved_argv[c] = strdup(argv[c]); - if (saved_argv[c] == NULL) - fatal("strdup: saved_argv[c]"); - } - saved_argv[c] = NULL; - - /* Prepare for later setproctitle emulation */ - compat_init_setproctitle(argc, argv); - argv = saved_argv; -#endif - while ((c = getopt(argc, argv, "6dD:nf:vSTt")) != -1) { switch (c) { case '6': @@ -159,13 +117,14 @@ main(int argc, char *argv[]) ps = &env->sc_ps; ps->ps_env = env; + TAILQ_INIT(&ps->ps_rcsocks); if ((opts & (IKED_OPT_NONATT|IKED_OPT_NATT)) == (IKED_OPT_NONATT|IKED_OPT_NATT)) errx(1, "conflicting NAT-T options"); - if (strlcpy(env->sc_conffile, conffile, MAXPATHLEN) >= MAXPATHLEN) - errx(1, "config file exceeds MAXPATHLEN"); + if (strlcpy(env->sc_conffile, conffile, PATH_MAX) >= PATH_MAX) + errx(1, "config file exceeds PATH_MAX"); ca_sslinit(); policy_init(env); @@ -187,6 +146,8 @@ main(int argc, char *argv[]) err(1, "failed to daemonize"); group_init(); + + ps->ps_ninstances = 1; proc_init(ps, procs, nitems(procs)); setproctitle("parent"); @@ -198,14 +159,16 @@ main(int argc, char *argv[]) signal_set(&ps->ps_evsigchld, SIGCHLD, parent_sig_handler, ps); signal_set(&ps->ps_evsighup, SIGHUP, parent_sig_handler, ps); signal_set(&ps->ps_evsigpipe, SIGPIPE, parent_sig_handler, ps); + signal_set(&ps->ps_evsigusr1, SIGUSR1, parent_sig_handler, ps); signal_add(&ps->ps_evsigint, NULL); signal_add(&ps->ps_evsigterm, NULL); signal_add(&ps->ps_evsigchld, NULL); signal_add(&ps->ps_evsighup, NULL); signal_add(&ps->ps_evsigpipe, NULL); + signal_add(&ps->ps_evsigusr1, NULL); - proc_config(ps, procs, nitems(procs)); + proc_listen(ps, procs, nitems(procs)); if (parent_configure(env) == -1) fatalx("configuration failed"); @@ -221,9 +184,6 @@ int parent_configure(struct iked *env) { struct sockaddr_storage ss; -#if defined(HAVE_APPLE_NATT) - int udpencap; -#endif if (parse_config(env->sc_conffile, env) == -1) { proc_kill(&env->sc_ps); @@ -246,15 +206,6 @@ parent_configure(struct iked *env) bzero(&ss, sizeof(ss)); ss.ss_family = AF_INET; -#if defined(HAVE_APPLE_NATT) - if ((env->sc_opts & IKED_OPT_NONATT) == 0) { - udpencap = IKED_NATT_PORT; - if (sysctlbyname("net.inet.ipsec.esp_port", NULL, NULL, - &udpencap, sizeof(udpencap)) != 0) - fatalx("failed to set NAT-T port"); - } -#endif - if ((env->sc_opts & IKED_OPT_NATT) == 0) config_setsocket(env, &ss, ntohs(IKED_IKE_PORT), PROC_IKEV2); if ((env->sc_opts & IKED_OPT_NONATT) == 0) @@ -270,6 +221,7 @@ parent_configure(struct iked *env) config_setcoupled(env, env->sc_decoupled ? 0 : 1); config_setmode(env, env->sc_passive ? 1 : 0); + config_setocsp(env); return (0); } @@ -299,6 +251,7 @@ parent_reload(struct iked *env, int reset, const char *filename) config_setcoupled(env, env->sc_decoupled ? 0 : 1); config_setmode(env, env->sc_passive ? 1 : 0); + config_setocsp(env); } else { config_setreset(env, reset, PROC_IKEV1); config_setreset(env, reset, PROC_IKEV2); @@ -327,12 +280,17 @@ parent_sig_handler(int sig, short event, void *arg) case SIGPIPE: log_info("%s: ignoring SIGPIPE", __func__); break; + case SIGUSR1: + log_info("%s: ignoring SIGUSR1", __func__); + break; case SIGTERM: case SIGINT: die = 1; /* FALLTHROUGH */ case SIGCHLD: do { + int len; + pid = waitpid(-1, &status, WNOHANG); if (pid <= 0) continue; @@ -340,17 +298,21 @@ parent_sig_handler(int sig, short event, void *arg) fail = 0; if (WIFSIGNALED(status)) { fail = 1; - asprintf(&cause, "terminated; signal %d", + len = asprintf(&cause, "terminated; signal %d", WTERMSIG(status)); } else if (WIFEXITED(status)) { if (WEXITSTATUS(status) != 0) { fail = 1; - asprintf(&cause, "exited abnormally"); + len = asprintf(&cause, + "exited abnormally"); } else - asprintf(&cause, "exited okay"); + len = asprintf(&cause, "exited okay"); } else fatalx("unexpected cause of SIGCHLD"); + if (len == -1) + fatal("asprintf"); + die = 1; for (id = 0; id < PROC_MAX; id++) @@ -400,7 +362,7 @@ parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg) struct iked *env = p->p_ps->ps_env; int v; char *str = NULL; - u_int type = imsg->hdr.type; + unsigned int type = imsg->hdr.type; switch (type) { case IMSG_CTL_RESET: @@ -412,8 +374,10 @@ parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg) case IMSG_CTL_DECOUPLE: case IMSG_CTL_ACTIVE: case IMSG_CTL_PASSIVE: - proc_compose_imsg(env, PROC_IKEV1, type, -1, NULL, 0); - proc_compose_imsg(env, PROC_IKEV2, type, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, PROC_IKEV1, -1, + type, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, PROC_IKEV2, -1, + type, -1, NULL, 0); break; case IMSG_CTL_RELOAD: if (IMSG_DATA_SIZE(imsg) > 0) @@ -422,6 +386,9 @@ parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg) if (str != NULL) free(str); break; + case IMSG_OCSP_FD: + ocsp_connect(env); + break; default: return (-1); } diff --git a/iked/iked.conf b/iked/iked.conf deleted file mode 100644 index 71ef75c..0000000 --- a/iked/iked.conf +++ /dev/null @@ -1,12 +0,0 @@ -# OpenIKED client configuration file -# -# See iked.conf(5) for syntax and examples. - -# Connect to a remote IKEv2 gateway using certificates. Please note -# that the srcid has to match the subjectAltName value in the local host -# certificate. The default srcid value is the local hostname. -ikev2 active esp \ - from 10.2.1.0/30 to 10.1.0.0/24 \ - local any peer openbsd-iked.vpn.example.com \ - srcid roadwarrior.vpn.example.com -# psk "you-should-not-use-psk-authentication" diff --git a/iked/iked.conf.5 b/iked/iked.conf.5 index c915ee0..d02e08e 100644 --- a/iked/iked.conf.5 +++ b/iked/iked.conf.5 @@ -1,6 +1,6 @@ -.\" $OpenBSD: iked.conf.5,v 1.23 2013/03/05 19:16:01 sobrado Exp $ +.\" $OpenBSD: iked.conf.5,v 1.39 2015/07/14 13:06:37 jmc Exp $ .\" -.\" Copyright (c) 2010-2013 Reyk Floeter +.\" Copyright (c) 2010 - 2014 Reyk Floeter .\" Copyright (c) 2004 Mathieu Sauve-Frankel All rights reserved. .\" .\" Permission to use, copy, modify, and distribute this software for any @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: March 5 2013 $ +.Dd $Mdocdate: July 14 2015 $ .Dt IKED.CONF 5 .Os .Sh NAME @@ -136,6 +136,13 @@ This is the default. .It Ic set decouple Don't load the negotiated SAs and flows from the kernel. This mode is only useful for testing and debugging. +.It Ic set ocsp Ar URL +Enable OCSP and set the URL of the OCSP responder. +Please note that the matching responder and issuer certificates +have to be placed in +.Pa /etc/iked/ocsp/responder.crt +and +.Pa /etc/iked/ocsp/issuer.crt . .It Ic user Ar name Ar password .Xr iked 8 supports user-based authentication by tunneling the Extensible @@ -239,6 +246,10 @@ is specified, negotiation will be started at once. If omitted, .Ar passive mode will be used. +.It Ic ipcomp +Enable optional support for +.Xr ipcomp 4 , +the IP Payload Compression protocol. .It Op Ar encap .Ar encap specifies the encapsulation protocol to be used. @@ -386,7 +397,7 @@ If omitted, will use the default proposals for the ESP or AH protocol. The .Ic group -option will only be used to enable Perfect Forwarding Security (PFS) +option will only be used to enable Perfect Forward Secrecy (PFS) for additional Child SAs exchanges that are not part of the initial key exchange. .It Ic srcid Ar string Ic dstid Ar string @@ -424,6 +435,14 @@ is similar to .Ic srcid , but instead specifies the ID to be used by the remote peer. +.It Ic ikelifetime Ar time +The optional +.Ic ikelifetime +parameter defines the IKE SA expiration timeout by the +.Ar time +SA was created. +A zero value disables active IKE SA rekeying. +This is the default. .It Ic lifetime Ar time Op Ic bytes Ar bytes The optional .Ic lifetime @@ -473,6 +492,33 @@ or hex value (starting with 0x) for authentication. Use RSA public key authentication. This is the default mode if no option is specified. .El +.It Ic config Ar option address +Send one or more optional configuration payloads (CP) to the peer. +The configuration +.Ar option +can be one of the following with the expected address format: +.Pp +.Bl -tag -width Ds -compact -offset indent +.It Ic address Ar address +Assign a static address on the internal network. +.It Ic address Ar address/prefix +Assign a dynamic address on the internal network. +The address will be assigned from an address pool with the size specified by +.Ar prefix . +.It Ic netmask Ar netmask +The IPv4 netmask of the internal network. +.It Ic name-server Ar address +The DNS server address within the internal network. +.It Ic netbios-server Ar address +The NetBIOS name server (WINS) within the internal network. +This option is provided for compatibility with legacy clients. +.It Ic dhcp-server Ar address +The address of an internal DHCP server for further configuration. +.It Ic protected-subnet Ar address/prefix +The address of the protected subnet within the internal network. +.It Ic access-server Ar address +The address of an internal remote access server. +.El .It Ic tag Ar string Add a .Xr pf 4 @@ -553,7 +599,7 @@ Interface for IKE traffic and encapsulated IPsec traffic. IKE traffic on the external interface. .It proto udp port 4500 IKE NAT-Traversal traffic on the external interface. -.It proto ah \*(Ba esp +.It proto ah | esp Encapsulated IPsec traffic on the external interface. .It enc0 @@ -624,17 +670,16 @@ The following fragment uses queues for all IPsec traffic with special handling for developers and employees: .Bd -literal -offset indent -altq on ix0 cbq bandwidth 1000Mb \e - queue { deflt, developers, employees, ipsec } - queue deflt bandwidth 10% priority 0 cbq(default ecn) - queue developers bandwidth 75% priority 7 cbq(borrow red) - queue employees bandwidth 5% cbq(red) - queue ipsec bandwidth 10% cbq(red) +queue std on ix0 bandwidth 100M +queue deflt parent std bandwidth 10M default +queue developers parent std bandwidth 75M +queue employees parent std bandwidth 5M +queue ipsec parent std bandwidth 10M -pass out on ix0 proto esp queue ipsec +pass out on ix0 proto esp set queue ipsec -pass out on ix0 tagged ipsec-developers.example.com queue developers -pass out on ix0 tagged ipsec-employees.example.com queue employees +pass out on ix0 tagged ipsec-developers.example.com set queue developers +pass out on ix0 tagged ipsec-employees.example.com set queue employees .Ed .Pp The following example assigns the tags in the @@ -673,7 +718,7 @@ a relevant NAT rule is required in For the example above, this would be: .Bd -literal -offset indent -match on enc0 from 192.168.1.0/24 to 192.168.2.0/24 nat-to 10.10.10.1 +match out on enc0 from 192.168.1.0/24 to 192.168.2.0/24 nat-to 10.10.10.1 .Ed .Pp From the peer's point of view, @@ -720,16 +765,21 @@ keyword: .It Li aes-128-gcm Ta "160 bits" Ta "[ESP only]" .It Li aes-192-gcm Ta "224 bits" Ta "[ESP only]" .It Li aes-256-gcm Ta "288 bits" Ta "[ESP only]" +.It Li blowfish Ta "160 bits" Ta "[ESP only]" +.It Li cast Ta "128 bits" Ta "[ESP only]" +.El +.Pp +The following cipher types provide only authentication, +not encryption: +.Bl -column "aes-128-gmac" "Key Length" "[ESP only]" -offset indent .It Li aes-128-gmac Ta "160 bits" Ta "[ESP only]" .It Li aes-192-gmac Ta "224 bits" Ta "[ESP only]" .It Li aes-256-gmac Ta "288 bits" Ta "[ESP only]" -.It Li blowfish Ta "160 bits" Ta "[ESP only]" -.It Li cast Ta "128 bits" Ta "[ESP only]" .It Li null Ta "" Ta "[ESP only]" .El .Pp -Use of DES as an encryption algorithm is not recommended (except for -backwards compatibility) due to the short key length. +Use of DES as an encryption algorithm is considered to be insecure +since brute force attacks are practical due its short key length. .Pp DES requires 8 bytes to form a 56-bit key and 3DES requires 24 bytes to form its 168-bit key. @@ -766,17 +816,22 @@ keyword: .It Li modp2048-256 Ta grp24 Ta 2048 Ta "MODP, 256 bit Prime Order Subgroup" .It Li ecp192 Ta grp25 Ta 192 Ta "ECP" .It Li ecp224 Ta grp26 Ta 224 Ta "ECP" +.It Li brainpool224 Ta grp27 Ta 224 Ta "ECP, brainpoolP224r1" +.It Li brainpool256 Ta grp28 Ta 256 Ta "ECP, brainpoolP256r1" +.It Li brainpool384 Ta grp29 Ta 384 Ta "ECP, brainpoolP384r1" +.It Li brainpool512 Ta grp30 Ta 512 Ta "ECP, brainpoolP512r1" +.It Li curve25519 Ta - Ta 256 Ta "Curve25519" .El .Pp The currently supported group types are either MODP (exponentiation groups modulo a prime), EC2N (elliptic curve groups over GF[2^N]), -or -ECP (elliptic curve groups modulo a prime). +ECP (elliptic curve groups modulo a prime), +or the non-standard Curve25519. Please note that the EC2N groups are considered as insecure and only provided for backwards compatibility. .Sh EXAMPLES -The first example is intended for clients connecting to +The first example is intended for a server with clients connecting to .Xr iked 8 as an IPsec gateway, or IKEv2 responder, using mutual public key authentication and additional challenge-based EAP-MSCHAPv2 password @@ -846,4 +901,4 @@ file format first appeared in The .Xr iked 8 program was written by -.An Reyk Floeter Aq reyk@openbsd.org . +.An Reyk Floeter Aq Mt reyk@openbsd.org . diff --git a/iked/iked.h b/iked/iked.h index 0430274..12cb10c 100644 --- a/iked/iked.h +++ b/iked/iked.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.h,v 1.56 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: iked.h,v 1.89 2015/10/01 10:59:23 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -17,29 +17,30 @@ */ #include -#include "openbsd-compat/sys-tree.h" -#include "openbsd-compat/sys-queue.h" +#include +#include +#include #include #include "types.h" #include "dh.h" -#ifndef _IKED_H -#define _IKED_H +#ifndef IKED_H +#define IKED_H /* * Common IKEv1/IKEv2 header */ struct ike_header { - u_int64_t ike_ispi; /* Initiator cookie */ - u_int64_t ike_rspi; /* Responder cookie */ - u_int8_t ike_nextpayload; /* Next payload type */ - u_int8_t ike_version; /* Major/Minor version number */ - u_int8_t ike_exchange; /* Exchange type */ - u_int8_t ike_flags; /* Message options */ - u_int32_t ike_msgid; /* Message identifier */ - u_int32_t ike_length; /* Total message length */ + uint64_t ike_ispi; /* Initiator cookie */ + uint64_t ike_rspi; /* Responder cookie */ + uint8_t ike_nextpayload; /* Next payload type */ + uint8_t ike_version; /* Major/Minor version number */ + uint8_t ike_exchange; /* Exchange type */ + uint8_t ike_flags; /* Message options */ + uint32_t ike_msgid; /* Message identifier */ + uint32_t ike_length; /* Total message length */ } __packed; /* @@ -50,6 +51,7 @@ struct imsgev { struct imsgbuf ibuf; void (*handler)(int, short, void *); struct event ev; + struct privsep_proc *proc; void *data; short events; const char *name; @@ -79,11 +81,14 @@ struct control_sock { int cs_fd; int cs_restricted; void *cs_env; + + TAILQ_ENTRY(control_sock) cs_entry; }; +TAILQ_HEAD(control_socks, control_sock); struct ctl_conn { TAILQ_ENTRY(ctl_conn) entry; - u_int8_t flags; + uint8_t flags; #define CTL_CONN_NOTIFY 0x01 struct imsgev iev; }; @@ -104,20 +109,20 @@ struct iked_timer { }; struct iked_spi { - u_int64_t spi; - u_int8_t spi_size; - u_int8_t spi_protoid; + uint64_t spi; + uint8_t spi_size; + uint8_t spi_protoid; }; struct iked_proposal { - u_int8_t prop_id; - u_int8_t prop_protoid; + uint8_t prop_id; + uint8_t prop_protoid; struct iked_spi prop_localspi; struct iked_spi prop_peerspi; struct iked_transform *prop_xforms; - u_int prop_nxforms; + unsigned int prop_nxforms; TAILQ_ENTRY(iked_proposal) prop_entry; }; @@ -126,7 +131,7 @@ TAILQ_HEAD(iked_proposals, iked_proposal); struct iked_addr { int addr_af; struct sockaddr_storage addr; - u_int8_t addr_mask; + uint8_t addr_mask; int addr_net; in_port_t addr_port; }; @@ -134,17 +139,13 @@ struct iked_addr { struct iked_flow { struct iked_addr flow_src; struct iked_addr flow_dst; - u_int flow_dir; /* in/out */ - - u_int flow_loaded; /* pfkey done */ + unsigned int flow_dir; /* in/out */ - u_int8_t flow_saproto; - u_int8_t flow_ipproto; - u_int8_t flow_type; - u_int32_t flow_id; + unsigned int flow_loaded; /* pfkey done */ - struct iked_id *flow_srcid; - struct iked_id *flow_dstid; + uint8_t flow_saproto; + uint8_t flow_ipproto; + uint8_t flow_type; struct iked_addr *flow_local; /* outer source */ struct iked_addr *flow_peer; /* outer dest */ @@ -157,26 +158,24 @@ RB_HEAD(iked_flows, iked_flow); TAILQ_HEAD(iked_saflows, iked_flow); struct iked_childsa { - u_int8_t csa_saproto; /* IPSec protocol */ - u_int csa_dir; /* in/out */ + uint8_t csa_saproto; /* IPSec protocol */ + unsigned int csa_dir; /* in/out */ - u_int64_t csa_peerspi; /* peer relation */ - u_int8_t csa_loaded; /* pfkey done */ - u_int8_t csa_rekey; /* will be deleted */ - u_int8_t csa_allocated; /* from the kernel */ - u_int8_t csa_persistent;/* do not rekey */ - u_int8_t csa_esn; /* use ESN */ + uint64_t csa_peerspi; /* peer relation */ + uint8_t csa_loaded; /* pfkey done */ + uint8_t csa_rekey; /* will be deleted */ + uint8_t csa_allocated; /* from the kernel */ + uint8_t csa_persistent;/* do not rekey */ + uint8_t csa_esn; /* use ESN */ + uint8_t csa_transport; /* transport mode */ struct iked_spi csa_spi; struct ibuf *csa_encrkey; /* encryption key */ - struct iked_transform *csa_encrxf; /* encryption xform */ + uint16_t csa_encrid; /* encryption xform id */ struct ibuf *csa_integrkey; /* auth key */ - struct iked_transform *csa_integrxf; /* auth xform */ - - struct iked_id *csa_srcid; - struct iked_id *csa_dstid; + uint16_t csa_integrid; /* auth xform id */ struct iked_addr *csa_local; /* outer source */ struct iked_addr *csa_peer; /* outer dest */ @@ -184,6 +183,9 @@ struct iked_childsa { struct iked_childsa *csa_peersa; /* peer */ + struct iked_childsa *csa_parent; /* IPCOMP parent */ + unsigned int csa_children; /* IPCOMP children */ + RB_ENTRY(iked_childsa) csa_node; TAILQ_ENTRY(iked_childsa) csa_entry; }; @@ -192,36 +194,36 @@ TAILQ_HEAD(iked_childsas, iked_childsa); struct iked_static_id { - u_int8_t id_type; - u_int8_t id_length; - u_int8_t id_offset; - u_int8_t id_data[IKED_ID_SIZE]; + uint8_t id_type; + uint8_t id_length; + uint8_t id_offset; + uint8_t id_data[IKED_ID_SIZE]; }; struct iked_auth { - u_int8_t auth_method; - u_int8_t auth_eap; /* optional EAP */ - u_int8_t auth_length; /* zero if EAP */ - u_int8_t auth_data[IKED_PSK_SIZE]; + uint8_t auth_method; + uint8_t auth_eap; /* optional EAP */ + uint8_t auth_length; /* zero if EAP */ + uint8_t auth_data[IKED_PSK_SIZE]; }; struct iked_cfg { - u_int8_t cfg_action; - u_int16_t cfg_type; + uint8_t cfg_action; + uint16_t cfg_type; union { struct iked_addr address; } cfg; }; -RB_HEAD(iked_sapeers, iked_sa); +TAILQ_HEAD(iked_sapeers, iked_sa); struct iked_lifetime { - u_int64_t lt_bytes; - u_int64_t lt_seconds; + uint64_t lt_bytes; + uint64_t lt_seconds; }; struct iked_policy { - u_int pol_id; + unsigned int pol_id; char pol_name[IKED_ID_SIZE]; #define IKED_SKIP_FLAGS 0 @@ -232,19 +234,22 @@ struct iked_policy { #define IKED_SKIP_COUNT 5 struct iked_policy *pol_skip[IKED_SKIP_COUNT]; - u_int8_t pol_flags; + uint8_t pol_flags; #define IKED_POLICY_PASSIVE 0x00 #define IKED_POLICY_DEFAULT 0x01 #define IKED_POLICY_ACTIVE 0x02 #define IKED_POLICY_REFCNT 0x04 #define IKED_POLICY_QUICK 0x08 #define IKED_POLICY_SKIP 0x10 +#define IKED_POLICY_IPCOMP 0x20 int pol_refcnt; + uint8_t pol_certreqtype; + int pol_af; - u_int8_t pol_saproto; - u_int pol_ipproto; + uint8_t pol_saproto; + unsigned int pol_ipproto; struct iked_addr pol_peer; struct group *pol_peerdh; @@ -256,7 +261,7 @@ struct iked_policy { struct iked_auth pol_auth; char pol_tag[IKED_TAG_SIZE]; - u_int pol_tap; + unsigned int pol_tap; struct iked_proposals pol_proposals; size_t pol_nproposals; @@ -265,9 +270,10 @@ struct iked_policy { size_t pol_nflows; struct iked_cfg pol_cfg[IKED_CFG_MAX]; - u_int pol_ncfg; + unsigned int pol_ncfg; - struct iked_lifetime pol_lifetime; + uint32_t pol_rekey; /* ike SA lifetime */ + struct iked_lifetime pol_lifetime; /* child SA lifetime */ struct iked_sapeers pol_sapeers; @@ -276,8 +282,8 @@ struct iked_policy { TAILQ_HEAD(iked_policies, iked_policy); struct iked_hash { - u_int8_t hash_type; /* PRF or INTEGR */ - u_int16_t hash_id; /* IKE PRF/INTEGR hash id */ + uint8_t hash_type; /* PRF or INTEGR */ + uint16_t hash_id; /* IKE PRF/INTEGR hash id */ const void *hash_priv; /* Identifying the hash alg */ void *hash_ctx; /* Context of the current invocation */ int hash_fixedkey; /* Requires fixed key length */ @@ -288,8 +294,8 @@ struct iked_hash { }; struct iked_cipher { - u_int8_t encr_type; /* ENCR */ - u_int16_t encr_id; /* IKE ENCR hash id */ + uint8_t encr_type; /* ENCR */ + uint16_t encr_id; /* IKE ENCR hash id */ const void *encr_priv; /* Identifying the hash alg */ void *encr_ctx; /* Context of the current invocation */ int encr_fixedkey; /* Requires fixed key length */ @@ -300,7 +306,7 @@ struct iked_cipher { }; struct iked_dsa { - u_int8_t dsa_method; /* AUTH method */ + uint8_t dsa_method; /* AUTH method */ const void *dsa_priv; /* PRF or signature hash function */ void *dsa_ctx; /* PRF or signature hash ctx */ struct ibuf *dsa_keydata; /* public, private or shared key */ @@ -311,41 +317,54 @@ struct iked_dsa { }; struct iked_id { - u_int8_t id_type; - u_int8_t id_offset; + uint8_t id_type; + uint8_t id_offset; struct ibuf *id_buf; }; -#define IKED_REQ_CERT 0x01 /* get local certificate (if required) */ -#define IKED_REQ_VALID 0x02 /* validate the peer cert */ -#define IKED_REQ_AUTH 0x04 /* AUTH payload */ -#define IKED_REQ_SA 0x08 /* SA available */ -#define IKED_REQ_CHILDSA 0x10 /* Child SA initiated */ -#define IKED_REQ_INF 0x20 /* Informational exchange initiated */ -#define IKED_REQ_DELETE 0x40 /* Rekeying continuation */ +#define IKED_REQ_CERT 0x0001 /* get local certificate (if required) */ +#define IKED_REQ_CERTVALID 0x0002 /* validated the peer cert */ +#define IKED_REQ_CERTREQ 0x0004 /* CERTREQ has been received */ +#define IKED_REQ_AUTH 0x0008 /* AUTH payload */ +#define IKED_REQ_AUTHVALID 0x0010 /* AUTH payload has been verified */ +#define IKED_REQ_SA 0x0020 /* SA available */ +#define IKED_REQ_EAPVALID 0x0040 /* EAP payload has been verified */ +#define IKED_REQ_CHILDSA 0x0080 /* Child SA initiated */ +#define IKED_REQ_INF 0x0100 /* Informational exchange initiated */ #define IKED_REQ_BITS \ - "\10\01CERT\02VALID\03AUTH\04SA" + "\20\01CERT\02CERTVALID\03CERTREQ\04AUTH\05AUTHVALID\06SA\07EAPVALID" \ + "\10CHILDSA\11INF" TAILQ_HEAD(iked_msgqueue, iked_message); struct iked_sahdr { - u_int64_t sh_ispi; /* Initiator SPI */ - u_int64_t sh_rspi; /* Responder SPI */ - u_int sh_initiator; /* Is initiator? */ + uint64_t sh_ispi; /* Initiator SPI */ + uint64_t sh_rspi; /* Responder SPI */ + unsigned int sh_initiator; /* Is initiator? */ } __packed; +struct iked_kex { + struct ibuf *kex_inonce; /* Ni */ + struct ibuf *kex_rnonce; /* Nr */ + + struct group *kex_dhgroup; /* DH group */ + struct ibuf *kex_dhiexchange; + struct ibuf *kex_dhrexchange; + struct ibuf *kex_dhpeer; /* pointer to i or r */ +}; + struct iked_sa { struct iked_sahdr sa_hdr; - u_int32_t sa_msgid; - u_int32_t sa_reqid; + uint32_t sa_msgid; /* Last request rcvd */ + int sa_msgid_set; /* msgid initialized */ + uint32_t sa_reqid; /* Next request sent */ int sa_type; #define IKED_SATYPE_LOOKUP 0 /* Used for lookup */ #define IKED_SATYPE_LOCAL 1 /* Local SA */ struct iked_addr sa_peer; - struct iked_addr sa_polpeer; struct iked_addr sa_local; int sa_fd; @@ -353,9 +372,9 @@ struct iked_sa { int sa_udpencap; /* for pfkey */ int sa_state; - u_int sa_stateflags; - u_int sa_stateinit; /* SA_INIT */ - u_int sa_statevalid; /* IKE_AUTH */ + unsigned int sa_stateflags; + unsigned int sa_stateinit; /* SA_INIT */ + unsigned int sa_statevalid; /* IKE_AUTH */ int sa_cp; /* XXX */ @@ -365,13 +384,14 @@ struct iked_sa { char *sa_tag; - struct ibuf *sa_inonce; /* Ni */ - struct ibuf *sa_rnonce; /* Nr */ - - struct group *sa_dhgroup; /* DH group */ - struct ibuf *sa_dhiexchange; - struct ibuf *sa_dhrexchange; - struct ibuf *sa_dhpeer; /* pointer to i or r */ + struct iked_kex sa_kex; +/* XXX compat defines until everything is converted */ +#define sa_inonce sa_kex.kex_inonce +#define sa_rnonce sa_kex.kex_rnonce +#define sa_dhgroup sa_kex.kex_dhgroup +#define sa_dhiexchange sa_kex.kex_dhiexchange +#define sa_dhrexchange sa_kex.kex_dhrexchange +#define sa_dhpeer sa_kex.kex_dhpeer struct iked_hash *sa_prf; /* PRF alg */ struct iked_hash *sa_integr; /* integrity alg */ @@ -388,11 +408,14 @@ struct iked_sa { struct ibuf *sa_1stmsg; /* for initiator AUTH */ struct ibuf *sa_2ndmsg; /* for responder AUTH */ struct iked_id sa_localauth; /* local AUTH message */ + int sa_sigsha2; /* use SHA2 for signatures */ struct iked_id sa_iid; /* initiator id */ struct iked_id sa_rid; /* responder id */ struct iked_id sa_icert; /* initiator cert */ struct iked_id sa_rcert; /* responder cert */ +#define IKESA_SRCID(x) ((x)->sa_hdr.sh_initiator ? &(x)->sa_iid : &(x)->sa_rid) +#define IKESA_DSTID(x) ((x)->sa_hdr.sh_initiator ? &(x)->sa_rid : &(x)->sa_iid) char *sa_eapid; /* EAP identity */ struct iked_id sa_eap; /* EAP challenge */ @@ -402,8 +425,18 @@ struct iked_sa { struct iked_childsas sa_childsas; /* IPSec Child SAs */ struct iked_saflows sa_flows; /* IPSec flows */ + struct iked_sa *sa_next; /* IKE SA rekeying */ + uint64_t sa_rekeyspi; /* peerspi for rekey*/ + + uint8_t sa_ipcomp; /* IPcomp transform */ + uint16_t sa_cpi_out; /* IPcomp outgoing */ + uint16_t sa_cpi_in; /* IPcomp incoming*/ + struct iked_timer sa_timer; /* SA timeouts */ -#define IKED_IKE_SA_REKEY_TIMEOUT 300 /* 5 minutes */ +#define IKED_IKE_SA_DELETE_TIMEOUT 300 /* 5 minutes */ +#define IKED_IKE_SA_ALIVE_TIMEOUT 60 /* 1 minute */ + + struct iked_timer sa_rekey; /* rekey timeout */ struct iked_msgqueue sa_requests; /* request queue */ #define IKED_RETRANSMIT_TIMEOUT 2 /* 2 seconds */ @@ -411,14 +444,18 @@ struct iked_sa { struct iked_msgqueue sa_responses; /* response queue */ #define IKED_RESPONSE_TIMEOUT 120 /* 2 minutes */ - RB_ENTRY(iked_sa) sa_peer_entry; + TAILQ_ENTRY(iked_sa) sa_peer_entry; RB_ENTRY(iked_sa) sa_entry; + + struct iked_addr *sa_addrpool; /* address from pool */ + RB_ENTRY(iked_sa) sa_addrpool_entry; /* pool entries */ }; RB_HEAD(iked_sas, iked_sa); +RB_HEAD(iked_addrpool, iked_sa); struct iked_message { struct ibuf *msg_data; - off_t msg_offset; + size_t msg_offset; struct sockaddr_storage msg_local; socklen_t msg_locallen; @@ -430,6 +467,7 @@ struct iked_message { int msg_fd; int msg_response; + int msg_responded; int msg_natt; int msg_error; int msg_e; @@ -439,8 +477,8 @@ struct iked_message { struct iked_policy *msg_policy; struct iked_sa *msg_sa; - u_int32_t msg_msgid; - u_int8_t msg_exchange; + uint32_t msg_msgid; + uint8_t msg_exchange; /* Parsed information */ struct iked_proposals msg_proposals; @@ -453,7 +491,7 @@ struct iked_message { /* Parse stack */ struct iked_proposal *msg_prop; - u_int16_t msg_attrlength; + uint16_t msg_attrlength; /* Retransmit queue */ struct iked_timer msg_timer; @@ -464,20 +502,32 @@ struct iked_message { }; struct iked_user { - char usr_name[MAXLOGNAME]; + char usr_name[LOGIN_NAME_MAX]; char usr_pass[IKED_PASSWORD_SIZE]; RB_ENTRY(iked_user) usr_entry; }; RB_HEAD(iked_users, iked_user); +struct privsep_pipes { + int *pp_pipes[PROC_MAX]; +}; + struct privsep { - int ps_pipes[PROC_MAX][PROC_MAX]; - struct imsgev ps_ievs[PROC_MAX]; + struct privsep_pipes *ps_pipes[PROC_MAX]; + struct privsep_pipes *ps_pp; + + struct imsgev *ps_ievs[PROC_MAX]; const char *ps_title[PROC_MAX]; pid_t ps_pid[PROC_MAX]; struct passwd *ps_pw; + int ps_noaction; struct control_sock ps_csock; + struct control_socks ps_rcsocks; + + unsigned int ps_instances[PROC_MAX]; + unsigned int ps_ninstances; + unsigned int ps_instance; /* Event and signal handlers */ struct event ps_evsigint; @@ -485,6 +535,7 @@ struct privsep { struct event ps_evsigchld; struct event ps_evsighup; struct event ps_evsigpipe; + struct event ps_evsigusr1; struct iked *ps_env; }; @@ -499,18 +550,26 @@ struct privsep_proc { const char *p_chroot; struct privsep *p_ps; struct iked *p_env; + void (*p_shutdown)(void); + unsigned int p_instance; +}; + +struct iked_ocsp_entry { + TAILQ_ENTRY(iked_ocsp_entry) ioe_entry; /* next request */ + void *ioe_ocsp; /* private ocsp request data */ }; +TAILQ_HEAD(iked_ocsp_requests, iked_ocsp_entry); /* * Daemon configuration */ struct iked { - char sc_conffile[MAXPATHLEN]; + char sc_conffile[PATH_MAX]; - u_int32_t sc_opts; - u_int8_t sc_passive; - u_int8_t sc_decoupled; + uint32_t sc_opts; + uint8_t sc_passive; + uint8_t sc_decoupled; struct iked_policies sc_policies; struct iked_policy *sc_defaultcon; @@ -524,7 +583,7 @@ struct iked { int sc_pfkey; /* ike process */ struct event sc_pfkeyev; - u_int8_t sc_certreqtype; + uint8_t sc_certreqtype; struct ibuf *sc_certreq; struct iked_socket *sc_sock4[2]; @@ -535,6 +594,11 @@ struct iked { #define IKED_INITIATOR_INTERVAL 60 struct privsep sc_ps; + + struct iked_ocsp_requests sc_ocsp; + char *sc_ocsp_url; + + struct iked_addrpool sc_addrpool; }; struct iked_socket { @@ -555,30 +619,32 @@ void control_cleanup(struct control_sock *); /* config.c */ struct iked_policy * config_new_policy(struct iked *); +void config_free_kex(struct iked_kex *); void config_free_sa(struct iked *, struct iked_sa *); struct iked_sa * config_new_sa(struct iked *, int); struct iked_user * config_new_user(struct iked *, struct iked_user *); -u_int64_t +uint64_t config_getspi(void); struct iked_transform * - config_findtransform(struct iked_proposals *, u_int8_t); + config_findtransform(struct iked_proposals *, uint8_t, unsigned int); void config_free_policy(struct iked *, struct iked_policy *); struct iked_proposal * - config_add_proposal(struct iked_proposals *, u_int, u_int); -void config_free_proposals(struct iked_proposals *, u_int); + config_add_proposal(struct iked_proposals *, unsigned int, + unsigned int); +void config_free_proposals(struct iked_proposals *, unsigned int); void config_free_flows(struct iked *, struct iked_flows *); void config_free_childsas(struct iked *, struct iked_childsas *, struct iked_spi *, struct iked_spi *); struct iked_transform * config_add_transform(struct iked_proposal *, - u_int, u_int, u_int, u_int); -int config_setcoupled(struct iked *, u_int); -int config_getcoupled(struct iked *, u_int); -int config_setmode(struct iked *, u_int); -int config_getmode(struct iked *, u_int); -int config_setreset(struct iked *, u_int, enum privsep_procid); + unsigned int, unsigned int, unsigned int, unsigned int); +int config_setcoupled(struct iked *, unsigned int); +int config_getcoupled(struct iked *, unsigned int); +int config_setmode(struct iked *, unsigned int); +int config_getmode(struct iked *, unsigned int); +int config_setreset(struct iked *, unsigned int, enum privsep_procid); int config_getreset(struct iked *, struct imsg *); int config_setpolicy(struct iked *, struct iked_policy *, enum privsep_procid); @@ -593,6 +659,8 @@ int config_setuser(struct iked *, struct iked_user *, enum privsep_procid); int config_getuser(struct iked *, struct imsg *); int config_setcompile(struct iked *, enum privsep_procid); int config_getcompile(struct iked *, struct imsg *); +int config_setocsp(struct iked *); +int config_getocsp(struct iked *, struct imsg *); /* policy.c */ void policy_init(struct iked *); @@ -603,34 +671,32 @@ void policy_calc_skip_steps(struct iked_policies *); void policy_ref(struct iked *, struct iked_policy *); void policy_unref(struct iked *, struct iked_policy *); void sa_state(struct iked *, struct iked_sa *, int); -void sa_stateflags(struct iked_sa *, u_int); +void sa_stateflags(struct iked_sa *, unsigned int); int sa_stateok(struct iked_sa *, int); struct iked_sa * - sa_new(struct iked *, u_int64_t, u_int64_t, u_int, + sa_new(struct iked *, uint64_t, uint64_t, unsigned int, struct iked_policy *); void sa_free(struct iked *, struct iked_sa *); void sa_free_flows(struct iked *, struct iked_saflows *); int sa_address(struct iked_sa *, struct iked_addr *, - struct sockaddr_storage *, int); + struct sockaddr_storage *); void childsa_free(struct iked_childsa *); struct iked_childsa * - childsa_lookup(struct iked_sa *, u_int64_t, u_int8_t); + childsa_lookup(struct iked_sa *, uint64_t, uint8_t); void flow_free(struct iked_flow *); struct iked_sa * - sa_lookup(struct iked *, u_int64_t, u_int64_t, u_int); -struct iked_sa * - sa_peer_lookup(struct iked_policy *, struct sockaddr_storage *); + sa_lookup(struct iked *, uint64_t, uint64_t, unsigned int); struct iked_user * user_lookup(struct iked *, const char *); RB_PROTOTYPE(iked_sas, iked_sa, sa_entry, sa_cmp); -RB_PROTOTYPE(iked_sapeers, iked_sa, sa_peer_entry, sa_peer_cmp); +RB_PROTOTYPE(iked_addrpool, iked_sa, sa_addrpool_entry, sa_addrpool_cmp); RB_PROTOTYPE(iked_users, iked_user, user_entry, user_cmp); RB_PROTOTYPE(iked_activesas, iked_childsa, csa_node, childsa_cmp); RB_PROTOTYPE(iked_flows, iked_flow, flow_node, flow_cmp); /* crypto.c */ struct iked_hash * - hash_new(u_int8_t, u_int16_t); + hash_new(uint8_t, uint16_t); struct ibuf * hash_setkey(struct iked_hash *, void *, size_t); void hash_free(struct iked_hash *); @@ -641,7 +707,7 @@ size_t hash_keylength(struct iked_hash *); size_t hash_length(struct iked_hash *); struct iked_cipher * - cipher_new(u_int8_t, u_int16_t, u_int16_t); + cipher_new(uint8_t, uint16_t, uint16_t); struct ibuf * cipher_setkey(struct iked_cipher *, void *, size_t); struct ibuf * @@ -658,15 +724,15 @@ size_t cipher_ivlength(struct iked_cipher *); size_t cipher_outlength(struct iked_cipher *, size_t); struct iked_dsa * - dsa_new(u_int16_t, struct iked_hash *, int); + dsa_new(uint16_t, struct iked_hash *, int); struct iked_dsa * - dsa_sign_new(u_int16_t, struct iked_hash *); + dsa_sign_new(uint16_t, struct iked_hash *); struct iked_dsa * - dsa_verify_new(u_int16_t, struct iked_hash *); + dsa_verify_new(uint16_t, struct iked_hash *); struct ibuf * - dsa_setkey(struct iked_dsa *, void *, size_t, u_int8_t); + dsa_setkey(struct iked_dsa *, void *, size_t, uint8_t); void dsa_free(struct iked_dsa *); -int dsa_init(struct iked_dsa *); +int dsa_init(struct iked_dsa *, const void *, size_t); size_t dsa_length(struct iked_dsa *); int dsa_update(struct iked_dsa *, const void *, size_t); ssize_t dsa_sign_final(struct iked_dsa *, void *, size_t); @@ -679,34 +745,34 @@ pid_t ikev1(struct privsep *, struct privsep_proc *); pid_t ikev2(struct privsep *, struct privsep_proc *); void ikev2_recv(struct iked *, struct iked_message *); void ikev2_init_ike_sa(struct iked *, void *); -int ikev2_sa_negotiate(struct iked_sa *, struct iked_proposals *, +int ikev2_sa_negotiate(struct iked_proposals *, struct iked_proposals *, struct iked_proposals *); int ikev2_policy2id(struct iked_static_id *, struct iked_id *, int); int ikev2_childsa_enable(struct iked *, struct iked_sa *); int ikev2_childsa_delete(struct iked *, struct iked_sa *, - u_int8_t, u_int64_t, u_int64_t *, int); + uint8_t, uint64_t, uint64_t *, int); struct ibuf * ikev2_prfplus(struct iked_hash *, struct ibuf *, struct ibuf *, size_t); -ssize_t ikev2_psk(struct iked_sa *, u_int8_t *, size_t, u_int8_t **); +ssize_t ikev2_psk(struct iked_sa *, uint8_t *, size_t, uint8_t **); ssize_t ikev2_nat_detection(struct iked *, struct iked_message *, - void *, size_t, u_int); + void *, size_t, unsigned int); int ikev2_send_informational(struct iked *, struct iked_message *); int ikev2_send_ike_e(struct iked *, struct iked_sa *, struct ibuf *, - u_int8_t, u_int8_t, int); + uint8_t, uint8_t, int); struct ike_header * ikev2_add_header(struct ibuf *, struct iked_sa *, - u_int32_t, u_int8_t, u_int8_t, u_int8_t); + uint32_t, uint8_t, uint8_t, uint8_t); int ikev2_set_header(struct ike_header *, size_t); struct ikev2_payload * ikev2_add_payload(struct ibuf *); int ikev2_next_payload(struct ikev2_payload *, size_t, - u_int8_t); -void ikev2_acquire_sa(struct iked *, struct iked_flow *); + uint8_t); +int ikev2_acquire_sa(struct iked *, struct iked_flow *); void ikev2_disable_rekeying(struct iked *, struct iked_sa *); -void ikev2_rekey_sa(struct iked *, struct iked_spi *); -void ikev2_drop_sa(struct iked *, struct iked_spi *); +int ikev2_rekey_sa(struct iked *, struct iked_spi *); +int ikev2_drop_sa(struct iked *, struct iked_spi *); int ikev2_print_id(struct iked_id *, char *, size_t); /* ikev2_msg.c */ @@ -718,19 +784,19 @@ struct ibuf * struct iked_message * ikev2_msg_copy(struct iked *, struct iked_message *); void ikev2_msg_cleanup(struct iked *, struct iked_message *); -u_int32_t +uint32_t ikev2_msg_id(struct iked *, struct iked_sa *); struct ibuf *ikev2_msg_auth(struct iked *, struct iked_sa *, int); int ikev2_msg_authsign(struct iked *, struct iked_sa *, struct iked_auth *, struct ibuf *); int ikev2_msg_authverify(struct iked *, struct iked_sa *, - struct iked_auth *, u_int8_t *, size_t, struct ibuf *); + struct iked_auth *, uint8_t *, size_t, struct ibuf *); int ikev2_msg_valid_ike_sa(struct iked *, struct ike_header *, struct iked_message *); int ikev2_msg_send(struct iked *, struct iked_message *); int ikev2_msg_send_encrypt(struct iked *, struct iked_sa *, - struct ibuf **, u_int8_t, u_int8_t, int); + struct ibuf **, uint8_t, uint8_t, int); struct ibuf *ikev2_msg_encrypt(struct iked *, struct iked_sa *, struct ibuf *); struct ibuf * @@ -753,7 +819,7 @@ struct iked_message * /* ikev2_pld.c */ int ikev2_pld_parse(struct iked *, struct ike_header *, - struct iked_message *, off_t); + struct iked_message *, size_t); /* eap.c */ ssize_t eap_identity_request(struct ibuf *); @@ -763,88 +829,93 @@ int eap_parse(struct iked *, struct iked_sa *, void *, int); int pfkey_couple(int, struct iked_sas *, int); int pfkey_flow_add(int fd, struct iked_flow *); int pfkey_flow_delete(int fd, struct iked_flow *); -int pfkey_block(int, int, u_int); -int pfkey_sa_init(int, struct iked_childsa *, u_int32_t *); +int pfkey_block(int, int, unsigned int); +int pfkey_sa_init(int, struct iked_childsa *, uint32_t *); int pfkey_sa_add(int, struct iked_childsa *, struct iked_childsa *); int pfkey_sa_delete(int, struct iked_childsa *); -int pfkey_flush(int, u_int); +int pfkey_sa_last_used(int, struct iked_childsa *, uint64_t *); +int pfkey_flush(int); int pfkey_socket(void); void pfkey_init(struct iked *, int fd); /* ca.c */ pid_t caproc(struct privsep *, struct privsep_proc *); -int ca_setreq(struct iked *, struct iked_sahdr *, struct iked_static_id *, - u_int8_t, u_int8_t *, size_t, enum privsep_procid); +int ca_setreq(struct iked *, struct iked_sa *, struct iked_static_id *, + uint8_t, uint8_t *, size_t, enum privsep_procid); int ca_setcert(struct iked *, struct iked_sahdr *, struct iked_id *, - u_int8_t, u_int8_t *, size_t, enum privsep_procid); + uint8_t, uint8_t *, size_t, enum privsep_procid); int ca_setauth(struct iked *, struct iked_sa *, struct ibuf *, enum privsep_procid); void ca_sslinit(void); -void ca_sslerror(void); -char *ca_asn1_name(u_int8_t *, size_t); +void ca_sslerror(const char *); +char *ca_asn1_name(uint8_t *, size_t); char *ca_x509_name(void *); +void *ca_x509_name_parse(char *); /* timer.c */ -void timer_initialize(struct iked *, struct iked_timer *, +void timer_set(struct iked *, struct iked_timer *, void (*)(struct iked *, void *), void *); -int timer_initialized(struct iked *, struct iked_timer *); -void timer_register(struct iked *, struct iked_timer *, int); -void timer_deregister(struct iked *, struct iked_timer *); +void timer_add(struct iked *, struct iked_timer *, int); +void timer_del(struct iked *, struct iked_timer *); /* proc.c */ -void proc_init(struct privsep *, struct privsep_proc *, u_int); +void proc_init(struct privsep *, struct privsep_proc *, unsigned int); void proc_kill(struct privsep *); -void proc_config(struct privsep *, struct privsep_proc *, u_int); +void proc_listen(struct privsep *, struct privsep_proc *, size_t); void proc_dispatch(int, short event, void *); pid_t proc_run(struct privsep *, struct privsep_proc *, - struct privsep_proc *, u_int, - void (*)(struct privsep *, void *), void *); + struct privsep_proc *, unsigned int, + void (*)(struct privsep *, struct privsep_proc *, void *), void *); void imsg_event_add(struct imsgev *); -int imsg_compose_event(struct imsgev *, u_int16_t, u_int32_t, - pid_t, int, void *, u_int16_t); -int imsg_composev_event(struct imsgev *, u_int16_t, u_int32_t, +int imsg_compose_event(struct imsgev *, uint16_t, uint32_t, + pid_t, int, void *, uint16_t); +int imsg_composev_event(struct imsgev *, uint16_t, uint32_t, pid_t, int, const struct iovec *, int); -int proc_compose_imsg(struct iked *, enum privsep_procid, - u_int16_t, int, void *, u_int16_t); -int proc_composev_imsg(struct iked *, enum privsep_procid, - u_int16_t, int, const struct iovec *, int); -int proc_forward_imsg(struct iked *, struct imsg *, - enum privsep_procid); -void proc_flush_imsg(struct iked *, enum privsep_procid); +int proc_compose_imsg(struct privsep *, enum privsep_procid, int, + uint16_t, int, void *, uint16_t); +int proc_composev_imsg(struct privsep *, enum privsep_procid, int, + uint16_t, int, const struct iovec *, int); +int proc_forward_imsg(struct privsep *, struct imsg *, + enum privsep_procid, int); +struct imsgbuf * + proc_ibuf(struct privsep *, enum privsep_procid, int); +struct imsgev * + proc_iev(struct privsep *, enum privsep_procid, int); /* util.c */ void socket_set_blockmode(int, enum blockmodes); int socket_af(struct sockaddr *, in_port_t); in_port_t - socket_getport(struct sockaddr_storage *); + socket_getport(struct sockaddr *); +int socket_setport(struct sockaddr *, in_port_t); int socket_getaddr(int, struct sockaddr_storage *); int socket_bypass(int, struct sockaddr *); int udp_bind(struct sockaddr *, in_port_t); ssize_t recvfromto(int, void *, size_t, int, struct sockaddr *, socklen_t *, struct sockaddr *, socklen_t *); const char * - print_spi(u_int64_t, int); + print_spi(uint64_t, int); const char * - print_map(u_int, struct iked_constmap *); + print_map(unsigned int, struct iked_constmap *); void lc_string(char *); -void print_hex(u_int8_t *, off_t, size_t); -void print_hexval(u_int8_t *, off_t, size_t); +void print_hex(uint8_t *, off_t, size_t); +void print_hexval(uint8_t *, off_t, size_t); const char * - print_bits(u_short, char *); + print_bits(unsigned short, unsigned char *); int sockaddr_cmp(struct sockaddr *, struct sockaddr *, int); -u_int8_t mask2prefixlen(struct sockaddr *); -u_int8_t mask2prefixlen6(struct sockaddr *); +uint8_t mask2prefixlen(struct sockaddr *); +uint8_t mask2prefixlen6(struct sockaddr *); struct in6_addr * - prefixlen2mask6(u_int8_t, u_int32_t *); -u_int32_t - prefixlen2mask(u_int8_t); + prefixlen2mask6(uint8_t, uint32_t *); +uint32_t + prefixlen2mask(uint8_t); const char * - print_host(struct sockaddr_storage *, char *, size_t); -char *get_string(u_int8_t *, size_t); + print_host(struct sockaddr *, char *, size_t); +char *get_string(uint8_t *, size_t); const char * - print_proto(u_int8_t); + print_proto(uint8_t); int expand_string(char *, size_t, const char *, const char *); -u_int8_t *string2unicode(const char *, size_t *); +uint8_t *string2unicode(const char *, size_t *); /* imsg_util.c */ struct ibuf * @@ -855,7 +926,7 @@ int ibuf_cat(struct ibuf *, struct ibuf *); void ibuf_release(struct ibuf *); size_t ibuf_length(struct ibuf *); int ibuf_setsize(struct ibuf *, size_t); -u_int8_t * +uint8_t * ibuf_data(struct ibuf *); void *ibuf_getdata(struct ibuf *, size_t); struct ibuf * @@ -871,21 +942,27 @@ void ibuf_zero(struct ibuf *); /* log.c */ void log_init(int); void log_verbose(int); -void log_warn(const char *, ...); -void log_warnx(const char *, ...); -void log_info(const char *, ...); -void log_debug(const char *, ...); -void print_debug(const char *, ...); -void print_verbose(const char *, ...); +void log_warn(const char *, ...) __attribute__((format(printf, 1, 2))); +void log_warnx(const char *, ...) __attribute__((format(printf, 1, 2))); +void log_info(const char *, ...) __attribute__((format(printf, 1, 2))); +void log_debug(const char *, ...) __attribute__((format(printf, 1, 2))); +void print_debug(const char *, ...) __attribute__((format(printf, 1, 2))); +void print_verbose(const char *, ...) __attribute__((format(printf, 1, 2))); __dead void fatal(const char *); __dead void fatalx(const char *); +/* ocsp.c */ +int ocsp_connect(struct iked *env); +int ocsp_receive_fd(struct iked *, struct imsg *); +int ocsp_validate_cert(struct iked *, struct iked_static_id *, + void *, size_t, struct iked_sahdr, uint8_t); + /* parse.y */ int parse_config(const char *, struct iked *); void print_user(struct iked_user *); void print_policy(struct iked_policy *); -size_t keylength_xf(u_int, u_int, u_int); -size_t noncelength_xf(u_int, u_int); +size_t keylength_xf(unsigned int, unsigned int, unsigned int); +size_t noncelength_xf(unsigned int, unsigned int); int cmdline_symset(char *); -#endif /* _IKED_H */ +#endif /* IKED_H */ diff --git a/iked/ikev1.c b/iked/ikev1.c index fc4f6b2..dd2f3ec 100644 --- a/iked/ikev1.c +++ b/iked/ikev1.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev1.c,v 1.13 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: ikev1.c,v 1.18 2015/08/21 11:59:27 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -22,8 +22,7 @@ * XXX or remove this file and ikev1 from the iked tree. */ -#include -#include "openbsd-compat/sys-queue.h" +#include #include #include #include @@ -32,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -92,7 +90,7 @@ ikev1_dispatch_ikev2(int fd, struct privsep_proc *p, struct imsg *imsg) { struct iked *env = p->p_env; struct iked_message msg; - u_int8_t *buf; + uint8_t *buf; ssize_t len; switch (imsg->hdr.type) { @@ -102,13 +100,13 @@ ikev1_dispatch_ikev2(int fd, struct privsep_proc *p, struct imsg *imsg) memcpy(&msg, imsg->data, sizeof(msg)); len = IMSG_DATA_SIZE(imsg) - sizeof(msg); - buf = (u_int8_t *)imsg->data + sizeof(msg); + buf = (uint8_t *)imsg->data + sizeof(msg); if (len <= 0 || (msg.msg_data = ibuf_new(buf, len)) == NULL) { log_debug("%s: short message", __func__); return (0); } - log_debug("%s: message length %d", __func__, len); + log_debug("%s: message length %zd", __func__, len); ikev1_recv(env, &msg); ikev2_msg_cleanup(env, &msg); @@ -133,7 +131,7 @@ ikev1_msg_cb(int fd, short event, void *arg) struct iked *env = sock->sock_env; struct iked_message msg; struct ike_header hdr; - u_int8_t buf[IKED_MSGBUF_MAX]; + uint8_t buf[IKED_MSGBUF_MAX]; size_t len; struct iovec iov[2]; @@ -158,8 +156,8 @@ ikev1_msg_cb(int fd, short event, void *arg) iov[1].iov_base = buf; iov[1].iov_len = len; - proc_composev_imsg(env, PROC_IKEV2, IMSG_IKE_MESSAGE, -1, - iov, 2); + proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, + IMSG_IKE_MESSAGE, -1, iov, 2); goto done; } diff --git a/iked/ikev2.c b/iked/ikev2.c index a24af78..9b1ee9b 100644 --- a/iked/ikev2.c +++ b/iked/ikev2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.c,v 1.82 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: ikev2.c,v 1.125 2015/10/02 16:13:43 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,24 +16,20 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include /* roundup */ +#include #include #include #include -#include #include -#if defined(__OpenBSD__) #include -#endif #include #include #include #include #include -#include #include #include #include @@ -42,6 +38,7 @@ #include #include +#include #include "iked.h" #include "ikev2.h" @@ -54,11 +51,13 @@ int ikev2_dispatch_cert(int, struct privsep_proc *, struct imsg *); struct iked_sa * ikev2_getimsgdata(struct iked *, struct imsg *, struct iked_sahdr *, - u_int8_t *, u_int8_t **, size_t *); + uint8_t *, uint8_t **, size_t *); void ikev2_recv(struct iked *, struct iked_message *); -int ikev2_ike_auth(struct iked *, struct iked_sa *, +int ikev2_ike_auth_compatible(struct iked_sa *, uint8_t, uint8_t); +int ikev2_ike_auth_recv(struct iked *, struct iked_sa *, struct iked_message *); +int ikev2_ike_auth(struct iked *, struct iked_sa *); void ikev2_init_recv(struct iked *, struct iked_message *, struct ike_header *); @@ -75,35 +74,61 @@ int ikev2_resp_ike_auth(struct iked *, struct iked_sa *); int ikev2_resp_ike_eap(struct iked *, struct iked_sa *, struct ibuf *); int ikev2_send_create_child_sa(struct iked *, struct iked_sa *, - struct iked_spi *, u_int8_t); + struct iked_spi *, uint8_t); +int ikev2_ikesa_enable(struct iked *, struct iked_sa *, struct iked_sa *); +void ikev2_ikesa_delete(struct iked *, struct iked_sa *, int); int ikev2_init_create_child_sa(struct iked *, struct iked_message *); int ikev2_resp_create_child_sa(struct iked *, struct iked_message *); +void ikev2_ike_sa_rekey(struct iked *, void *); void ikev2_ike_sa_timeout(struct iked *env, void *); +void ikev2_ike_sa_alive(struct iked *, void *); int ikev2_sa_initiator(struct iked *, struct iked_sa *, - struct iked_message *); + struct iked_sa *, struct iked_message *); int ikev2_sa_responder(struct iked *, struct iked_sa *, struct iked_sa *, struct iked_message *); +int ikev2_sa_initiator_dh(struct iked_sa *, struct iked_message *, + unsigned int); +int ikev2_sa_responder_dh(struct iked_kex *, struct iked_proposals *, + struct iked_message *, unsigned int); +void ikev2_sa_cleanup_dh(struct iked_sa *); int ikev2_sa_keys(struct iked *, struct iked_sa *, struct ibuf *); int ikev2_sa_tag(struct iked_sa *, struct iked_id *); +int ikev2_set_sa_proposal(struct iked_sa *, struct iked_policy *, + unsigned int); -int ikev2_childsa_negotiate(struct iked *, struct iked_sa *, int); +int ikev2_childsa_negotiate(struct iked *, struct iked_sa *, + struct iked_kex *, struct iked_proposals *, int, int); int ikev2_match_proposals(struct iked_proposal *, struct iked_proposal *, struct iked_transform **); int ikev2_valid_proposal(struct iked_proposal *, struct iked_transform **, struct iked_transform **, int *); ssize_t ikev2_add_proposals(struct iked *, struct iked_sa *, struct ibuf *, - struct iked_proposals *, u_int8_t, int, int); + struct iked_proposals *, uint8_t, int, int); ssize_t ikev2_add_cp(struct iked *, struct iked_sa *, struct ibuf *); ssize_t ikev2_add_transform(struct ibuf *, - u_int8_t, u_int8_t, u_int16_t, u_int16_t); + uint8_t, uint8_t, uint16_t, uint16_t); ssize_t ikev2_add_ts(struct ibuf *, struct ikev2_payload **, ssize_t, struct iked_sa *, int); -ssize_t ikev2_add_ts_payload(struct ibuf *, u_int, struct iked_sa *); +ssize_t ikev2_add_certreq(struct ibuf *, struct ikev2_payload **, ssize_t, + struct ibuf *, uint8_t); +ssize_t ikev2_add_ipcompnotify(struct iked *, struct ibuf *, + struct ikev2_payload **, ssize_t, struct iked_sa *); +ssize_t ikev2_add_ts_payload(struct ibuf *, unsigned int, struct iked_sa *); int ikev2_add_data(struct ibuf *, void *, size_t); int ikev2_add_buf(struct ibuf *buf, struct ibuf *); +int ikev2_ipcomp_enable(struct iked *, struct iked_sa *); +void ikev2_ipcomp_csa_free(struct iked *, struct iked_childsa *); + +int ikev2_cp_setaddr(struct iked *, struct iked_sa *); +int ikev2_cp_fixaddr(struct iked_sa *, struct iked_addr *, + struct iked_addr *); + +ssize_t ikev2_add_sighashnotify(struct ibuf *, struct ikev2_payload **, + ssize_t); + static struct privsep_proc procs[] = { { "parent", PROC_PARENT, ikev2_dispatch_parent }, { "ikev1", PROC_IKEV1, ikev2_dispatch_ikev1 }, @@ -131,9 +156,9 @@ ikev2_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) case IMSG_CTL_PASSIVE: if (config_getmode(env, imsg->hdr.type) == -1) return (0); /* ignore error */ - timer_initialize(env, &env->sc_inittmr, ikev2_init_ike_sa, + timer_set(env, &env->sc_inittmr, ikev2_init_ike_sa, NULL); - timer_register(env, &env->sc_inittmr, IKED_INITIATOR_INITIAL); + timer_add(env, &env->sc_inittmr, IKED_INITIATOR_INITIAL); return (0); case IMSG_UDP_SOCKET: return (config_getsocket(env, imsg, ikev2_msg_cb)); @@ -157,7 +182,7 @@ ikev2_dispatch_ikev1(int fd, struct privsep_proc *p, struct imsg *imsg) { struct iked *env = p->p_env; struct iked_message msg; - u_int8_t *buf; + uint8_t *buf; ssize_t len; switch (imsg->hdr.type) { @@ -167,13 +192,13 @@ ikev2_dispatch_ikev1(int fd, struct privsep_proc *p, struct imsg *imsg) memcpy(&msg, imsg->data, sizeof(msg)); len = IMSG_DATA_SIZE(imsg) - sizeof(msg); - buf = (u_int8_t *)imsg->data + sizeof(msg); + buf = (uint8_t *)imsg->data + sizeof(msg); if (len <= 0 || (msg.msg_data = ibuf_new(buf, len)) == NULL) { log_debug("%s: short message", __func__); return (0); } - log_debug("%s: message length %d", __func__, len); + log_debug("%s: message length %zd", __func__, len); ikev2_recv(env, &msg); ikev2_msg_cleanup(env, &msg); @@ -191,10 +216,11 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) struct iked *env = p->p_env; struct iked_sahdr sh; struct iked_sa *sa; - u_int8_t type; - u_int8_t *ptr; + uint8_t type; + uint8_t *ptr; size_t len; struct iked_id *id = NULL; + int ignore = 0; switch (imsg->hdr.type) { case IMSG_CERTREQ: @@ -209,14 +235,15 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) env->sc_certreq = ibuf_new(ptr, IMSG_DATA_SIZE(imsg) - sizeof(type)); - log_debug("%s: updated local CERTREQ signatures length %d", - __func__, ibuf_length(env->sc_certreq)); + log_debug("%s: updated local CERTREQ type %s length %zu", + __func__, print_map(type, ikev2_cert_map), + ibuf_length(env->sc_certreq)); break; case IMSG_CERTVALID: case IMSG_CERTINVALID: memcpy(&sh, imsg->data, sizeof(sh)); - memcpy(&type, (u_int8_t *)imsg->data + sizeof(sh), + memcpy(&type, (uint8_t *)imsg->data + sizeof(sh), sizeof(type)); /* Ignore invalid or unauthenticated SAs */ @@ -227,13 +254,12 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) if (imsg->hdr.type == IMSG_CERTVALID) { log_debug("%s: peer certificate is valid", __func__); - sa_stateflags(sa, IKED_REQ_VALID); - sa_state(env, sa, IKEV2_STATE_VALID); + sa_stateflags(sa, IKED_REQ_CERTVALID); } else { log_warnx("%s: peer certificate is invalid", __func__); } - if (ikev2_ike_auth(env, sa, NULL) != 0) + if (ikev2_ike_auth(env, sa) != 0) log_debug("%s: failed to send ike auth", __func__); break; case IMSG_CERT: @@ -243,6 +269,21 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) break; } + /* + * Ignore the message if we already got a valid certificate. + * This might happen if the peer sent multiple CERTREQs. + */ + if (sa->sa_stateflags & IKED_REQ_CERT || + type == IKEV2_CERT_NONE) + ignore = 1; + + log_debug("%s: cert type %s length %zu, %s", __func__, + print_map(type, ikev2_cert_map), len, + ignore ? "ignored" : "ok"); + + if (ignore) + break; + if (sh.sh_initiator) id = &sa->sa_icert; else @@ -253,21 +294,15 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) ibuf_release(id->id_buf); id->id_buf = NULL; - if (type != IKEV2_CERT_NONE) { - if (len <= 0 || - (id->id_buf = ibuf_new(ptr, len)) == NULL) { - log_debug("%s: failed to get cert payload", - __func__); - break; - } + if (len <= 0 || (id->id_buf = ibuf_new(ptr, len)) == NULL) { + log_debug("%s: failed to get cert payload", + __func__); + break; } - log_debug("%s: cert type %d length %d", __func__, - id->id_type, ibuf_length(id->id_buf)); - sa_stateflags(sa, IKED_REQ_CERT); - if (ikev2_ike_auth(env, sa, NULL) != 0) + if (ikev2_ike_auth(env, sa) != 0) log_debug("%s: failed to send ike auth", __func__); break; case IMSG_AUTH: @@ -276,8 +311,13 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) log_debug("%s: invalid auth reply", __func__); break; } + if (sa_stateok(sa, IKEV2_STATE_VALID)) { + log_warnx("%s: ignoring AUTH in state %s", __func__, + print_map(sa->sa_state, ikev2_state_map)); + break; + } - log_debug("%s: AUTH type %d len %d", __func__, type, len); + log_debug("%s: AUTH type %d len %zu", __func__, type, len); id = &sa->sa_localauth; id->id_type = type; @@ -295,7 +335,7 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) sa_stateflags(sa, IKED_REQ_AUTH); - if (ikev2_ike_auth(env, sa, NULL) != 0) + if (ikev2_ike_auth(env, sa) != 0) log_debug("%s: failed to send ike auth", __func__); break; default: @@ -307,9 +347,9 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) struct iked_sa * ikev2_getimsgdata(struct iked *env, struct imsg *imsg, struct iked_sahdr *sh, - u_int8_t *type, u_int8_t **buf, size_t *size) + uint8_t *type, uint8_t **buf, size_t *size) { - u_int8_t *ptr; + uint8_t *ptr; size_t len; struct iked_sa *sa; @@ -323,7 +363,7 @@ ikev2_getimsgdata(struct iked *env, struct imsg *imsg, struct iked_sahdr *sh, sa = sa_lookup(env, sh->sh_ispi, sh->sh_rspi, sh->sh_initiator); log_debug("%s: imsg %d rspi %s ispi %s initiator %d sa %s" - " type %d data length %d", + " type %d data length %zd", __func__, imsg->hdr.type, print_spi(sh->sh_rspi, 8), print_spi(sh->sh_ispi, 8), @@ -345,17 +385,16 @@ ikev2_recv(struct iked *env, struct iked_message *msg) struct ike_header *hdr; struct iked_message *m; struct iked_sa *sa; - u_int initiator, flag = 0; - int response; + unsigned int initiator, flag = 0; hdr = ibuf_seek(msg->msg_data, msg->msg_offset, sizeof(*hdr)); - if (hdr == NULL || (ssize_t)ibuf_size(msg->msg_data) < + if (hdr == NULL || ibuf_size(msg->msg_data) < (betoh32(hdr->ike_length) - msg->msg_offset)) return; initiator = (hdr->ike_flags & IKEV2_FLAG_INITIATOR) ? 0 : 1; - response = (hdr->ike_flags & IKEV2_FLAG_RESPONSE) ? 1 : 0; + msg->msg_response = (hdr->ike_flags & IKEV2_FLAG_RESPONSE) ? 1 : 0; msg->msg_sa = sa_lookup(env, betoh64(hdr->ike_ispi), betoh64(hdr->ike_rspi), initiator); @@ -363,11 +402,12 @@ ikev2_recv(struct iked *env, struct iked_message *msg) if (policy_lookup(env, msg) != 0) return; - log_info("%s: %s from %s %s to %s policy '%s' id %u, %ld bytes", + log_info("%s: %s %s from %s %s to %s policy '%s' id %u, %ld bytes", __func__, print_map(hdr->ike_exchange, ikev2_exchange_map), + msg->msg_response ? "response" : "request", initiator ? "responder" : "initiator", - print_host(&msg->msg_peer, NULL, 0), - print_host(&msg->msg_local, NULL, 0), + print_host((struct sockaddr *)&msg->msg_peer, NULL, 0), + print_host((struct sockaddr *)&msg->msg_local, NULL, 0), msg->msg_policy->pol_name, msg->msg_msgid, ibuf_length(msg->msg_data)); log_debug("%s: ispi %s rspi %s", __func__, @@ -382,7 +422,7 @@ ikev2_recv(struct iked *env, struct iked_message *msg) if (hdr->ike_exchange == IKEV2_EXCHANGE_INFORMATIONAL) flag = IKED_REQ_INF; - if (response) { + if (msg->msg_response) { if (msg->msg_msgid > sa->sa_reqid) return; if (hdr->ike_exchange != IKEV2_EXCHANGE_INFORMATIONAL && @@ -391,6 +431,10 @@ ikev2_recv(struct iked *env, struct iked_message *msg) if (flag) { if ((sa->sa_stateflags & flag) == 0) return; + /* + * We have initiated this exchange, even if + * we are not the initiator of the IKE SA. + */ initiator = 1; } /* @@ -413,24 +457,33 @@ ikev2_recv(struct iked *env, struct iked_message *msg) sa_free(env, sa); } return; + } else if (sa->sa_msgid_set && msg->msg_msgid == sa->sa_msgid) { + /* + * Response is being worked on, most likely we're + * waiting for the CA process to get back to us + */ + return; } /* * If it's a new request, make sure to update the peer's - * message ID and dispose of all previous responses + * message ID and dispose of all previous responses. + * We need to set sa_msgid_set in order to distinguish between + * "last msgid was 0" and "msgid not set yet". */ sa->sa_msgid = msg->msg_msgid; + sa->sa_msgid_set = 1; ikev2_msg_prevail(env, &sa->sa_responses, msg); } - if (sa_address(sa, &sa->sa_peer, &msg->msg_peer, initiator) == -1 || - sa_address(sa, &sa->sa_local, &msg->msg_local, initiator) == -1) + if (sa_address(sa, &sa->sa_peer, &msg->msg_peer) == -1 || + sa_address(sa, &sa->sa_local, &msg->msg_local) == -1) return; sa->sa_fd = msg->msg_fd; log_debug("%s: updated SA to peer %s local %s", __func__, - print_host(&sa->sa_peer.addr, NULL, 0), - print_host(&sa->sa_local.addr, NULL, 0)); + print_host((struct sockaddr *)&sa->sa_peer.addr, NULL, 0), + print_host((struct sockaddr *)&sa->sa_local.addr, NULL, 0)); done: if (initiator) @@ -445,7 +498,18 @@ ikev2_recv(struct iked *env, struct iked_message *msg) } int -ikev2_ike_auth(struct iked *env, struct iked_sa *sa, +ikev2_ike_auth_compatible(struct iked_sa *sa, uint8_t want, uint8_t have) +{ + if (want == have) + return (0); + if (sa->sa_sigsha2 && + have == IKEV2_AUTH_SIG && want == IKEV2_AUTH_RSA_SIG) + return (0); + return (-1); +} + +int +ikev2_ike_auth_recv(struct iked *env, struct iked_sa *sa, struct iked_message *msg) { struct iked_id *id, *certid; @@ -454,9 +518,6 @@ ikev2_ike_auth(struct iked *env, struct iked_sa *sa, struct iked_policy *policy = sa->sa_policy; int ret = -1; - if (msg == NULL) - goto done; - if (sa->sa_hdr.sh_initiator) { id = &sa->sa_rid; certid = &sa->sa_rcert; @@ -464,20 +525,39 @@ ikev2_ike_auth(struct iked *env, struct iked_sa *sa, id = &sa->sa_iid; certid = &sa->sa_icert; } + /* try to relookup the policy based on the peerid */ + if (msg->msg_id.id_type && !sa->sa_hdr.sh_initiator) { + struct iked_policy *old = sa->sa_policy; + + sa->sa_policy = NULL; + if (policy_lookup(env, msg) == 0 && msg->msg_policy && + msg->msg_policy != old) { + /* move sa to new policy */ + policy = sa->sa_policy = msg->msg_policy; + TAILQ_REMOVE(&old->pol_sapeers, sa, sa_peer_entry); + TAILQ_INSERT_TAIL(&policy->pol_sapeers, + sa, sa_peer_entry); + } else { + /* restore */ + msg->msg_policy = sa->sa_policy = old; + } + } if (msg->msg_id.id_type) { memcpy(id, &msg->msg_id, sizeof(*id)); bzero(&msg->msg_id, sizeof(msg->msg_id)); - if ((authmsg = ikev2_msg_auth(env, sa, - !sa->sa_hdr.sh_initiator)) == NULL) { - log_debug("%s: failed to get response " - "auth data", __func__); - return (-1); - } + if (!sa->sa_hdr.sh_initiator) { + if ((authmsg = ikev2_msg_auth(env, sa, + !sa->sa_hdr.sh_initiator)) == NULL) { + log_debug("%s: failed to get response " + "auth data", __func__); + return (-1); + } - ca_setauth(env, sa, authmsg, PROC_CERT); - ibuf_release(authmsg); + ca_setauth(env, sa, authmsg, PROC_CERT); + ibuf_release(authmsg); + } } if (msg->msg_cert.id_type) { @@ -506,11 +586,13 @@ ikev2_ike_auth(struct iked *env, struct iked_sa *sa, ikeauth.auth_length = ibuf_size(sa->sa_eapmsk); } - if (msg->msg_auth.id_type != ikeauth.auth_method) { + if (ikev2_ike_auth_compatible(sa, + ikeauth.auth_method, msg->msg_auth.id_type) < 0) { log_warnx("%s: unexpected auth method %s", __func__, - print_map(ikeauth.auth_method, ikev2_auth_map)); + print_map(msg->msg_auth.id_type, ikev2_auth_map)); return (-1); } + ikeauth.auth_method = msg->msg_auth.id_type; if ((authmsg = ikev2_msg_auth(env, sa, sa->sa_hdr.sh_initiator)) == NULL) { @@ -524,8 +606,10 @@ ikev2_ike_auth(struct iked *env, struct iked_sa *sa, authmsg); ibuf_release(authmsg); - if (ret != 0) - goto done; + if (ret != 0) { + log_debug("%s: ikev2_msg_authverify failed", __func__); + return (-1); + } if (sa->sa_eapmsk != NULL) { if ((authmsg = ikev2_msg_auth(env, sa, @@ -544,13 +628,17 @@ ikev2_ike_auth(struct iked *env, struct iked_sa *sa, return (-1); } - sa_state(env, sa, IKEV2_STATE_EAP_VALID); + /* ikev2_msg_authverify verified AUTH */ + sa_stateflags(sa, IKED_REQ_AUTHVALID); + sa_stateflags(sa, IKED_REQ_EAPVALID); + + sa_state(env, sa, IKEV2_STATE_EAP_SUCCESS); } } if (!TAILQ_EMPTY(&msg->msg_proposals)) { - if (ikev2_sa_negotiate(sa, &sa->sa_policy->pol_proposals, - &msg->msg_proposals) != 0) { + if (ikev2_sa_negotiate(&sa->sa_proposals, + &sa->sa_policy->pol_proposals, &msg->msg_proposals) != 0) { log_debug("%s: no proposal chosen", __func__); msg->msg_error = IKEV2_N_NO_PROPOSAL_CHOSEN; return (-1); @@ -558,13 +646,49 @@ ikev2_ike_auth(struct iked *env, struct iked_sa *sa, sa_stateflags(sa, IKED_REQ_SA); } - done: + return ikev2_ike_auth(env, sa); +} + +int +ikev2_ike_auth(struct iked *env, struct iked_sa *sa) +{ + struct iked_policy *pol = sa->sa_policy; + uint8_t certreqtype; + + /* Attempt state transition */ + if (sa->sa_state == IKEV2_STATE_EAP_SUCCESS) + sa_state(env, sa, IKEV2_STATE_EAP_VALID); + else if (sa->sa_state == IKEV2_STATE_AUTH_SUCCESS) + sa_state(env, sa, IKEV2_STATE_VALID); + if (sa->sa_hdr.sh_initiator) { if (sa_stateok(sa, IKEV2_STATE_AUTH_SUCCESS)) return (ikev2_init_done(env, sa)); else return (ikev2_init_ike_auth(env, sa)); } + + /* + * If we have to send a local certificate but did not receive an + * optional CERTREQ, use our own certreq to find a local certificate. + * We could alternatively extract the CA from the peer certificate + * to find a matching local one. + */ + if (sa->sa_statevalid & IKED_REQ_CERT) { + if ((sa->sa_stateflags & IKED_REQ_CERTREQ) == 0) { + log_debug("%s: no CERTREQ, using default", __func__); + if (pol->pol_certreqtype) + certreqtype = pol->pol_certreqtype; + else + certreqtype = env->sc_certreqtype; + return (ca_setreq(env, sa, + &pol->pol_localid, certreqtype, + ibuf_data(env->sc_certreq), + ibuf_size(env->sc_certreq), PROC_CERT)); + } else if ((sa->sa_stateflags & IKED_REQ_CERT) == 0) + return (0); /* ignored, wait for cert */ + } + return (ikev2_resp_ike_auth(env, sa)); } @@ -589,7 +713,8 @@ ikev2_init_recv(struct iked *env, struct iked_message *msg, betoh64(hdr->ike_ispi), betoh64(hdr->ike_rspi), 1, NULL)) == NULL || sa != msg->msg_sa) { log_debug("%s: invalid new SA", __func__); - sa_free(env, sa); + if (sa) + sa_free(env, sa); } break; case IKEV2_EXCHANGE_IKE_AUTH: @@ -620,7 +745,8 @@ ikev2_init_recv(struct iked *env, struct iked_message *msg, * Update address information and use the NAT-T * port and socket, if available. */ - port = htons(socket_getport(&sock->sock_addr)); + port = htons(socket_getport( + (struct sockaddr *)&sock->sock_addr)); sa->sa_local.addr_port = port; sa->sa_peer.addr_port = port; (void)socket_af((struct sockaddr *)&sa->sa_local.addr, port); @@ -632,8 +758,8 @@ ikev2_init_recv(struct iked *env, struct iked_message *msg, log_debug("%s: NAT detected, updated SA to " "peer %s local %s", __func__, - print_host(&sa->sa_peer.addr, NULL, 0), - print_host(&sa->sa_local.addr, NULL, 0)); + print_host((struct sockaddr *)&sa->sa_peer.addr, NULL, 0), + print_host((struct sockaddr *)&sa->sa_local.addr, NULL, 0)); } switch (hdr->ike_exchange) { @@ -641,12 +767,13 @@ ikev2_init_recv(struct iked *env, struct iked_message *msg, (void)ikev2_init_auth(env, msg); break; case IKEV2_EXCHANGE_IKE_AUTH: - (void)ikev2_ike_auth(env, sa, msg); + (void)ikev2_ike_auth_recv(env, sa, msg); break; case IKEV2_EXCHANGE_CREATE_CHILD_SA: (void)ikev2_init_create_child_sa(env, msg); break; case IKEV2_EXCHANGE_INFORMATIONAL: + sa->sa_stateflags &= ~IKED_REQ_INF; break; default: log_debug("%s: exchange %s not implemented", __func__, @@ -659,24 +786,11 @@ void ikev2_init_ike_sa(struct iked *env, void *arg) { struct iked_policy *pol; -#ifdef __APPLE__ - static struct timeval waketime = { 0, 0 }; - struct timeval tv; - size_t size = sizeof(tv); - - if (sysctlbyname("kern.waketime", &tv, &size, NULL, 0) == 0) { - if (waketime.tv_sec != 0 && - memcmp(&waketime, &tv, sizeof(waketime)) != 0) { - log_debug("%s: after power resume", __func__); - } - memcpy(&waketime, &tv, sizeof(waketime)); - } -#endif TAILQ_FOREACH(pol, &env->sc_policies, pol_entry) { if ((pol->pol_flags & IKED_POLICY_ACTIVE) == 0) continue; - if (sa_peer_lookup(pol, &pol->pol_peer.addr) != NULL) { + if (!TAILQ_EMPTY(&pol->pol_sapeers)) { log_debug("%s: \"%s\" is already active", __func__, pol->pol_name); continue; @@ -686,11 +800,13 @@ ikev2_init_ike_sa(struct iked *env, void *arg) if (ikev2_init_ike_sa_peer(env, pol, &pol->pol_peer)) log_debug("%s: failed to initiate with peer %s", - __func__, print_host(&pol->pol_peer.addr, NULL, 0)); + __func__, + print_host((struct sockaddr *)&pol->pol_peer.addr, + NULL, 0)); } - timer_initialize(env, &env->sc_inittmr, ikev2_init_ike_sa, NULL); - timer_register(env, &env->sc_inittmr, IKED_INITIATOR_INTERVAL); + timer_set(env, &env->sc_inittmr, ikev2_init_ike_sa, NULL); + timer_add(env, &env->sc_inittmr, IKED_INITIATOR_INTERVAL); } int @@ -706,7 +822,7 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, struct iked_sa *sa; struct ibuf *buf; struct group *group; - u_int8_t *ptr; + uint8_t *ptr; ssize_t len; int ret = -1; struct iked_socket *sock; @@ -720,23 +836,24 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, return (-1); /* Pick peer's DH group if asked */ + /* XXX free old sa_dhgroup ? */ sa->sa_dhgroup = pol->pol_peerdh; - if (ikev2_sa_initiator(env, sa, NULL) == -1) + if (ikev2_sa_initiator(env, sa, NULL, NULL) == -1) goto done; if (pol->pol_local.addr.ss_family == AF_UNSPEC) { if (socket_getaddr(sock->sock_fd, &ss) == -1) goto done; } else - memcpy(&ss, &pol->pol_local.addr, SS_LEN(&pol->pol_local.addr)); + memcpy(&ss, &pol->pol_local.addr, pol->pol_local.addr.ss_len); - if ((buf = ikev2_msg_init(env, &req, &peer->addr, SS_LEN(&peer->addr), - &ss, SS_LEN(&ss), 0)) == NULL) + if ((buf = ikev2_msg_init(env, &req, &peer->addr, peer->addr.ss_len, + &ss, ss.ss_len, 0)) == NULL) goto done; /* Inherit the port from the 1st send socket */ - port = htons(socket_getport(&sock->sock_addr)); + port = htons(socket_getport((struct sockaddr *)&sock->sock_addr)); (void)socket_af((struct sockaddr *)&req.msg_local, port); (void)socket_af((struct sockaddr *)&req.msg_peer, port); @@ -825,6 +942,9 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, len += sizeof(*n); } + if ((len = ikev2_add_sighashnotify(buf, &pld, len)) == -1) + goto done; + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONE) == -1) goto done; @@ -839,12 +959,6 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, goto done; } - memcpy(&sa->sa_polpeer, &pol->pol_peer, sizeof(sa->sa_polpeer)); - if (RB_INSERT(iked_sapeers, &pol->pol_sapeers, sa)) { - log_debug("%s: conflicting sa", __func__); - goto done; - } - if ((ret = ikev2_msg_send(env, &req)) == 0) sa_state(env, sa, IKEV2_STATE_SA_INIT); @@ -867,7 +981,7 @@ ikev2_init_auth(struct iked *env, struct iked_message *msg) if (sa == NULL) return (-1); - if (ikev2_sa_initiator(env, sa, msg) == -1) { + if (ikev2_sa_initiator(env, sa, NULL, msg) == -1) { log_debug("%s: failed to get IKE keys", __func__); return (-1); } @@ -895,7 +1009,7 @@ ikev2_init_ike_auth(struct iked *env, struct iked_sa *sa) struct ikev2_auth *auth; struct iked_id *id, *certid; struct ibuf *e = NULL; - u_int8_t firstpayload; + uint8_t firstpayload; int ret = -1; ssize_t len; @@ -937,21 +1051,15 @@ ikev2_init_ike_auth(struct iked *env, struct iked_sa *sa) goto done; len = ibuf_size(certid->id_buf) + sizeof(*cert); - if (env->sc_certreqtype) { - if (ikev2_next_payload(pld, len, - IKEV2_PAYLOAD_CERTREQ) == -1) - goto done; + /* CERTREQ payload(s) */ + if ((len = ikev2_add_certreq(e, &pld, + len, env->sc_certreq, env->sc_certreqtype)) == -1) + goto done; - /* CERTREQ payload */ - if ((pld = ikev2_add_payload(e)) == NULL) - goto done; - if ((cert = ibuf_advance(e, sizeof(*cert))) == NULL) - goto done; - cert->cert_type = env->sc_certreqtype; - if (ikev2_add_buf(e, env->sc_certreq) == -1) - goto done; - len = ibuf_size(env->sc_certreq) + sizeof(*cert); - } + if (env->sc_certreqtype != pol->pol_certreqtype && + (len = ikev2_add_certreq(e, &pld, + len, NULL, pol->pol_certreqtype)) == -1) + goto done; } if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_AUTH) == -1) @@ -978,6 +1086,11 @@ ikev2_init_ike_auth(struct iked *env, struct iked_sa *sa) goto done; } + /* compression */ + if ((pol->pol_flags & IKED_POLICY_IPCOMP) && + (len = ikev2_add_ipcompnotify(env, e, &pld, len, sa)) == -1) + goto done; + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1) goto done; @@ -1011,11 +1124,18 @@ ikev2_init_done(struct iked *env, struct iked_sa *sa) if (!sa_stateok(sa, IKEV2_STATE_VALID)) return (0); /* ignored */ - ret = ikev2_childsa_negotiate(env, sa, sa->sa_hdr.sh_initiator); + ret = ikev2_childsa_negotiate(env, sa, &sa->sa_kex, &sa->sa_proposals, + sa->sa_hdr.sh_initiator, 0); if (ret == 0) ret = ikev2_childsa_enable(env, sa); - if (ret == 0) + if (ret == 0) { sa_state(env, sa, IKEV2_STATE_ESTABLISHED); + timer_set(env, &sa->sa_timer, ikev2_ike_sa_alive, sa); + timer_add(env, &sa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT); + timer_set(env, &sa->sa_rekey, ikev2_ike_sa_rekey, sa); + if (sa->sa_policy->pol_rekey) + timer_add(env, &sa->sa_rekey, sa->sa_policy->pol_rekey); + } if (ret) ikev2_childsa_delete(env, sa, 0, 0, NULL, 1); @@ -1030,6 +1150,9 @@ ikev2_policy2id(struct iked_static_id *polid, struct iked_id *id, int srcid) char idstr[IKED_ID_SIZE]; struct in_addr in4; struct in6_addr in6; + X509_NAME *name = NULL; + uint8_t *p; + int len; /* Fixup the local Id if not specified */ if (srcid && polid->id_type == 0) { @@ -1072,6 +1195,19 @@ ikev2_policy2id(struct iked_static_id *polid, struct iked_id *id, int srcid) return (-1); } break; + case IKEV2_ID_ASN1_DN: + /* policy has ID in string-format, convert to ASN1 */ + if ((name = ca_x509_name_parse(polid->id_data)) == NULL || + (len = i2d_X509_NAME(name, NULL)) < 0 || + (p = ibuf_reserve(id->id_buf, len)) == NULL || + (i2d_X509_NAME(name, &p)) < 0) { + if (name) + X509_NAME_free(name); + ibuf_release(id->id_buf); + return (-1); + } + X509_NAME_free(name); + break; default: if (ibuf_add(id->id_buf, polid->id_data, polid->id_length) != 0) { @@ -1084,7 +1220,7 @@ ikev2_policy2id(struct iked_static_id *polid, struct iked_id *id, int srcid) if (ikev2_print_id(id, idstr, sizeof(idstr)) == -1) return (-1); - log_debug("%s: %s %s length %d", __func__, + log_debug("%s: %s %s length %zu", __func__, srcid ? "srcid" : "dstid", idstr, ibuf_size(id->id_buf)); @@ -1093,8 +1229,8 @@ ikev2_policy2id(struct iked_static_id *polid, struct iked_id *id, int srcid) struct ike_header * ikev2_add_header(struct ibuf *buf, struct iked_sa *sa, - u_int32_t msgid, u_int8_t nextpayload, - u_int8_t exchange, u_int8_t flags) + uint32_t msgid, uint8_t nextpayload, + uint8_t exchange, uint8_t flags) { struct ike_header *hdr; @@ -1121,7 +1257,7 @@ ikev2_add_header(struct ibuf *buf, struct iked_sa *sa, int ikev2_set_header(struct ike_header *hdr, size_t length) { - u_int32_t hdrlength = sizeof(*hdr) + length; + uint32_t hdrlength = sizeof(*hdr) + length; if (hdrlength > UINT32_MAX) { log_debug("%s: message too long", __func__); @@ -1150,16 +1286,17 @@ ikev2_add_payload(struct ibuf *buf) } ssize_t -ikev2_add_ts_payload(struct ibuf *buf, u_int type, struct iked_sa *sa) +ikev2_add_ts_payload(struct ibuf *buf, unsigned int type, struct iked_sa *sa) { struct iked_policy *pol = sa->sa_policy; struct ikev2_tsp *tsp; struct ikev2_ts *ts; struct iked_flow *flow; struct iked_addr *addr; - u_int8_t *ptr; + struct iked_addr pooladdr; + uint8_t *ptr; size_t len = 0; - u_int32_t av[4], bv[4], mv[4]; + uint32_t av[4], bv[4], mv[4]; struct sockaddr_in *in4; struct sockaddr_in6 *in6; @@ -1185,6 +1322,13 @@ ikev2_add_ts_payload(struct ibuf *buf, u_int type, struct iked_sa *sa) } else return (-1); + /* patch remote address (if configured to 0.0.0.0) */ + if ((type == IKEV2_PAYLOAD_TSi && !sa->sa_hdr.sh_initiator) || + (type == IKEV2_PAYLOAD_TSr && sa->sa_hdr.sh_initiator)) { + if (ikev2_cp_fixaddr(sa, addr, &pooladdr) != -1) + addr = &pooladdr; + } + ts->ts_protoid = flow->flow_ipproto; if (addr->addr_port) { @@ -1277,9 +1421,136 @@ ikev2_add_ts(struct ibuf *e, struct ikev2_payload **pld, ssize_t len, return (len); } + +ssize_t +ikev2_add_certreq(struct ibuf *e, struct ikev2_payload **pld, ssize_t len, + struct ibuf *certreq, uint8_t type) +{ + struct ikev2_cert *cert; + + if (type == IKEV2_CERT_NONE) + return (len); + + if (ikev2_next_payload(*pld, len, IKEV2_PAYLOAD_CERTREQ) == -1) + return (-1); + + /* CERTREQ payload */ + if ((*pld = ikev2_add_payload(e)) == NULL) + return (-1); + + if ((cert = ibuf_advance(e, sizeof(*cert))) == NULL) + return (-1); + + cert->cert_type = type; + len = sizeof(*cert); + + if (certreq != NULL && cert->cert_type == IKEV2_CERT_X509_CERT) { + if (ikev2_add_buf(e, certreq) == -1) + return (-1); + len += ibuf_size(certreq); + } + + log_debug("%s: type %s length %zd", __func__, + print_map(type, ikev2_cert_map), len); + + return (len); +} + +ssize_t +ikev2_add_ipcompnotify(struct iked *env, struct ibuf *e, + struct ikev2_payload **pld, ssize_t len, struct iked_sa *sa) +{ + struct iked_childsa csa; + struct ikev2_notify *n; + uint8_t *ptr; + uint16_t cpi; + uint32_t spi; + uint8_t transform; + + /* we only support deflate */ + transform = IKEV2_IPCOMP_DEFLATE; + + bzero(&csa, sizeof(csa)); + csa.csa_saproto = IKEV2_SAPROTO_IPCOMP; + csa.csa_ikesa = sa; + csa.csa_local = &sa->sa_peer; + csa.csa_peer = &sa->sa_local; + + if (pfkey_sa_init(env->sc_pfkey, &csa, &spi) == -1) + return (-1); + /* + * We get spi == 0 if the kernel does not support IPcomp, + * so just return the length of the current payload. + */ + if (spi == 0) + return (len); + cpi = htobe16((uint16_t)spi); + if (*pld) + if (ikev2_next_payload(*pld, len, IKEV2_PAYLOAD_NOTIFY) == -1) + return (-1); + if ((*pld = ikev2_add_payload(e)) == NULL) + return (-1); + len = sizeof(*n) + sizeof(cpi) + sizeof(transform); + if ((ptr = ibuf_advance(e, len)) == NULL) + return (-1); + n = (struct ikev2_notify *)ptr; + n->n_protoid = 0; + n->n_spisize = 0; + n->n_type = htobe16(IKEV2_N_IPCOMP_SUPPORTED); + ptr += sizeof(*n); + memcpy(ptr, &cpi, sizeof(cpi)); + ptr += sizeof(cpi); + memcpy(ptr, &transform, sizeof(transform)); + + sa->sa_cpi_in = spi; /* already on host byte order */ + log_debug("%s: sa_cpi_in 0x%04x", __func__, sa->sa_cpi_in); + + return (len); +} + +ssize_t +ikev2_add_sighashnotify(struct ibuf *e, struct ikev2_payload **pld, + ssize_t len) +{ + struct ikev2_notify *n; + uint8_t *ptr; + size_t i; + uint16_t hash, signature_hashes[] = { + IKEV2_SIGHASH_SHA2_256, + IKEV2_SIGHASH_SHA2_384, + IKEV2_SIGHASH_SHA2_512 + }; + + if (ikev2_next_payload(*pld, len, IKEV2_PAYLOAD_NOTIFY) == -1) + return (-1); + + /* XXX signature_hashes are hardcoded for now */ + len = sizeof(*n) + nitems(signature_hashes) * sizeof(hash); + + /* NOTIFY payload */ + if ((*pld = ikev2_add_payload(e)) == NULL) + return (-1); + if ((ptr = ibuf_advance(e, len)) == NULL) + return (-1); + + n = (struct ikev2_notify *)ptr; + n->n_protoid = 0; + n->n_spisize = 0; + n->n_type = htobe16(IKEV2_N_SIGNATURE_HASH_ALGORITHMS); + ptr += sizeof(*n); + + for (i = 0; i < nitems(signature_hashes); i++) { + hash = htobe16(signature_hashes[i]); + memcpy(ptr, &hash, sizeof(hash)); + ptr += sizeof(hash); + } + + return (len); +} + int ikev2_next_payload(struct ikev2_payload *pld, size_t length, - u_int8_t nextpayload) + uint8_t nextpayload) { size_t pldlength = sizeof(*pld) + length; @@ -1288,7 +1559,7 @@ ikev2_next_payload(struct ikev2_payload *pld, size_t length, return (-1); } - log_debug("%s: length %d nextpayload %s", + log_debug("%s: length %zu nextpayload %s", __func__, pldlength, print_map(nextpayload, ikev2_payload_map)); pld->pld_length = htobe16(pldlength); @@ -1299,21 +1570,21 @@ ikev2_next_payload(struct ikev2_payload *pld, size_t length, ssize_t ikev2_nat_detection(struct iked *env, struct iked_message *msg, - void *ptr, size_t len, u_int type) + void *ptr, size_t len, unsigned int type) { EVP_MD_CTX ctx; struct ike_header *hdr; - u_int8_t md[SHA_DIGEST_LENGTH]; - u_int mdlen = sizeof(md); + uint8_t md[SHA_DIGEST_LENGTH]; + unsigned int mdlen = sizeof(md); struct iked_sa *sa = msg->msg_sa; struct sockaddr_in *in4; struct sockaddr_in6 *in6; ssize_t ret = -1; - struct sockaddr_storage *src, *dst, *ss; - u_int64_t rspi, ispi; + struct sockaddr *src, *dst, *ss; + uint64_t rspi, ispi; struct ibuf *buf; int frompeer = 0; - u_int32_t rnd; + uint32_t rnd; if (ptr == NULL) return (mdlen); @@ -1325,14 +1596,14 @@ ikev2_nat_detection(struct iked *env, struct iked_message *msg, ispi = hdr->ike_ispi; rspi = hdr->ike_rspi; frompeer = 1; - src = &msg->msg_peer; - dst = &msg->msg_local; + src = (struct sockaddr *)&msg->msg_peer; + dst = (struct sockaddr *)&msg->msg_local; } else { ispi = htobe64(sa->sa_hdr.sh_ispi); rspi = htobe64(sa->sa_hdr.sh_rspi); frompeer = 0; - src = &msg->msg_local; - dst = &msg->msg_peer; + src = (struct sockaddr *)&msg->msg_local; + dst = (struct sockaddr *)&msg->msg_peer; } EVP_MD_CTX_init(&ctx); @@ -1362,7 +1633,7 @@ ikev2_nat_detection(struct iked *env, struct iked_message *msg, EVP_DigestUpdate(&ctx, &ispi, sizeof(ispi)); EVP_DigestUpdate(&ctx, &rspi, sizeof(rspi)); - switch (ss->ss_family) { + switch (ss->sa_family) { case AF_INET: in4 = (struct sockaddr_in *)ss; EVP_DigestUpdate(&ctx, &in4->sin_addr.s_addr, @@ -1407,11 +1678,12 @@ ikev2_add_cp(struct iked *env, struct iked_sa *sa, struct ibuf *buf) struct ikev2_cp *cp; struct ikev2_cfg *cfg; struct iked_cfg *ikecfg; - u_int i; + unsigned int i; + uint32_t mask4; size_t len; struct sockaddr_in *in4; struct sockaddr_in6 *in6; - u_int8_t prefixlen; + uint8_t prefixlen; if ((cp = ibuf_advance(buf, sizeof(*cp))) == NULL) return (-1); @@ -1447,12 +1719,29 @@ ikev2_add_cp(struct iked *env, struct iked_sa *sa, struct ibuf *buf) case IKEV2_CFG_INTERNAL_IP4_DHCP: case IKEV2_CFG_INTERNAL_IP4_SERVER: /* 4 bytes IPv4 address */ - in4 = (struct sockaddr_in *)&ikecfg->cfg.address.addr; + in4 = (ikecfg->cfg.address.addr_mask != 32 && + (ikecfg->cfg_type == + IKEV2_CFG_INTERNAL_IP4_ADDRESS) && + sa->sa_addrpool && + sa->sa_addrpool->addr_af == AF_INET) ? + (struct sockaddr_in *)&sa->sa_addrpool->addr : + (struct sockaddr_in *)&ikecfg->cfg.address.addr; cfg->cfg_length = htobe16(4); if (ibuf_add(buf, &in4->sin_addr.s_addr, 4) == -1) return (-1); len += 4; break; + case IKEV2_CFG_INTERNAL_IP4_SUBNET: + /* 4 bytes IPv4 address + 4 bytes IPv4 mask + */ + in4 = (struct sockaddr_in *)&ikecfg->cfg.address.addr; + mask4 = prefixlen2mask(ikecfg->cfg.address.addr_mask); + cfg->cfg_length = htobe16(8); + if (ibuf_add(buf, &in4->sin_addr.s_addr, 4) == -1) + return (-1); + if (ibuf_add(buf, &mask4, 4) == -1) + return (-1); + len += 8; + break; case IKEV2_CFG_INTERNAL_IP6_DNS: case IKEV2_CFG_INTERNAL_IP6_NBNS: case IKEV2_CFG_INTERNAL_IP6_DHCP: @@ -1465,8 +1754,15 @@ ikev2_add_cp(struct iked *env, struct iked_sa *sa, struct ibuf *buf) len += 16; break; case IKEV2_CFG_INTERNAL_IP6_ADDRESS: + case IKEV2_CFG_INTERNAL_IP6_SUBNET: /* 16 bytes IPv6 address + 1 byte prefix length */ - in6 = (struct sockaddr_in6 *)&ikecfg->cfg.address.addr; + in6 = (ikecfg->cfg.address.addr_mask != 128 && + (ikecfg->cfg_type == + IKEV2_CFG_INTERNAL_IP6_ADDRESS) && + sa->sa_addrpool && + sa->sa_addrpool->addr_af == AF_INET6) ? + (struct sockaddr_in6 *)&sa->sa_addrpool->addr : + (struct sockaddr_in6 *)&ikecfg->cfg.address.addr; cfg->cfg_length = htobe16(17); if (ibuf_add(buf, &in6->sin6_addr.s6_addr, 16) == -1) return (-1); @@ -1490,7 +1786,7 @@ ikev2_add_cp(struct iked *env, struct iked_sa *sa, struct ibuf *buf) ssize_t ikev2_add_proposals(struct iked *env, struct iked_sa *sa, struct ibuf *buf, - struct iked_proposals *proposals, u_int8_t protoid, int initiator, + struct iked_proposals *proposals, uint8_t protoid, int initiator, int sendikespi) { struct ikev2_sa_proposal *sap; @@ -1498,9 +1794,9 @@ ikev2_add_proposals(struct iked *env, struct iked_sa *sa, struct ibuf *buf, struct iked_proposal *prop; struct iked_childsa csa; ssize_t length = 0, saplength, xflen; - u_int64_t spi64; - u_int32_t spi32, spi; - u_int i; + uint64_t spi64; + uint32_t spi32, spi; + unsigned int i; TAILQ_FOREACH(prop, proposals, prop_entry) { if ((protoid && prop->prop_protoid != protoid) || @@ -1575,14 +1871,14 @@ ikev2_add_proposals(struct iked *env, struct iked_sa *sa, struct ibuf *buf, length += saplength; } - log_debug("%s: length %d", __func__, length); + log_debug("%s: length %zd", __func__, length); return (length); } ssize_t ikev2_add_transform(struct ibuf *buf, - u_int8_t more, u_int8_t type, u_int16_t id, u_int16_t length) + uint8_t more, uint8_t type, uint16_t id, uint16_t length) { struct ikev2_transform *xfrm; struct ikev2_attribute *attr; @@ -1720,7 +2016,7 @@ ikev2_resp_recv(struct iked *env, struct iked_message *msg, sa->sa_policy->pol_auth.auth_eap) sa_state(env, sa, IKEV2_STATE_EAP); - if (ikev2_ike_auth(env, sa, msg) != 0) { + if (ikev2_ike_auth_recv(env, sa, msg) != 0) { log_debug("%s: failed to send auth response", __func__); sa_state(env, sa, IKEV2_STATE_CLOSED); return; @@ -1729,6 +2025,14 @@ ikev2_resp_recv(struct iked *env, struct iked_message *msg, case IKEV2_EXCHANGE_CREATE_CHILD_SA: (void)ikev2_resp_create_child_sa(env, msg); break; + case IKEV2_EXCHANGE_INFORMATIONAL: + if (!msg->msg_responded && !msg->msg_error) { + (void)ikev2_send_ike_e(env, sa, NULL, + IKEV2_PAYLOAD_NONE, IKEV2_EXCHANGE_INFORMATIONAL, + 1); + msg->msg_responded = 1; + } + break; default: break; } @@ -1740,13 +2044,12 @@ ikev2_resp_ike_sa_init(struct iked *env, struct iked_message *msg) struct iked_message resp; struct ike_header *hdr; struct ikev2_payload *pld; - struct ikev2_cert *cert; struct ikev2_keyexchange *ke; struct ikev2_notify *n; struct iked_sa *sa = msg->msg_sa; struct ibuf *buf; struct group *group; - u_int8_t *ptr; + uint8_t *ptr; ssize_t len; int ret = -1; @@ -1841,21 +2144,22 @@ ikev2_resp_ike_sa_init(struct iked *env, struct iked_message *msg) len += sizeof(*n); } - if (env->sc_certreqtype && (sa->sa_statevalid & IKED_REQ_CERT)) { - if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_CERTREQ) == -1) + if (sa->sa_statevalid & IKED_REQ_CERT) { + /* CERTREQ payload(s) */ + if ((len = ikev2_add_certreq(buf, &pld, + len, env->sc_certreq, env->sc_certreqtype)) == -1) goto done; - /* CERTREQ payload */ - if ((pld = ikev2_add_payload(buf)) == NULL) - goto done; - if ((cert = ibuf_advance(buf, sizeof(*cert))) == NULL) - goto done; - cert->cert_type = env->sc_certreqtype; - if (ikev2_add_buf(buf, env->sc_certreq) == -1) + if (env->sc_certreqtype != sa->sa_policy->pol_certreqtype && + (len = ikev2_add_certreq(buf, &pld, + len, NULL, sa->sa_policy->pol_certreqtype)) == -1) goto done; - len = ibuf_size(env->sc_certreq) + sizeof(*cert); } + if (sa->sa_sigsha2 && + (len = ikev2_add_sighashnotify(buf, &pld, len)) == -1) + goto done; + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONE) == -1) goto done; @@ -1888,7 +2192,7 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) struct ikev2_auth *auth; struct iked_id *id, *certid; struct ibuf *e = NULL; - u_int8_t firstpayload; + uint8_t firstpayload; int ret = -1; ssize_t len; @@ -1900,7 +2204,11 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) else if (!sa_stateok(sa, IKEV2_STATE_VALID)) return (0); /* ignore */ - if (ikev2_childsa_negotiate(env, sa, sa->sa_hdr.sh_initiator) == -1) + if (ikev2_cp_setaddr(env, sa) < 0) + return (-1); + + if (ikev2_childsa_negotiate(env, sa, &sa->sa_kex, &sa->sa_proposals, + sa->sa_hdr.sh_initiator, 0) < 0) return (-1); /* New encrypted message buffer */ @@ -1988,6 +2296,11 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) goto done; } + /* compression */ + if (sa->sa_ipcomp && + (len = ikev2_add_ipcompnotify(env, e, &pld, len, sa)) == -1) + goto done; + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1) goto done; @@ -2009,8 +2322,14 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) IKEV2_EXCHANGE_IKE_AUTH, firstpayload, 1); if (ret == 0) ret = ikev2_childsa_enable(env, sa); - if (ret == 0) + if (ret == 0) { sa_state(env, sa, IKEV2_STATE_ESTABLISHED); + timer_set(env, &sa->sa_timer, ikev2_ike_sa_alive, sa); + timer_add(env, &sa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT); + timer_set(env, &sa->sa_rekey, ikev2_ike_sa_rekey, sa); + if (sa->sa_policy->pol_rekey) + timer_add(env, &sa->sa_rekey, sa->sa_policy->pol_rekey); + } done: if (ret) @@ -2027,17 +2346,18 @@ ikev2_resp_ike_eap(struct iked *env, struct iked_sa *sa, struct ibuf *eapmsg) struct ikev2_auth *auth; struct iked_id *id, *certid; struct ibuf *e = NULL; - u_int8_t firstpayload; + uint8_t firstpayload; int ret = -1; ssize_t len = 0; - if (!sa_stateok(sa, IKEV2_STATE_EAP)) - return (0); - /* Responder only */ if (sa->sa_hdr.sh_initiator) return (-1); + /* Check if "ca" has done it's job yet */ + if (!sa->sa_localauth.id_type) + return (0); + /* New encrypted message buffer */ if ((e = ibuf_static()) == NULL) goto done; @@ -2105,7 +2425,7 @@ ikev2_resp_ike_eap(struct iked *env, struct iked_sa *sa, struct ibuf *eapmsg) int ikev2_send_ike_e(struct iked *env, struct iked_sa *sa, struct ibuf *buf, - u_int8_t firstpayload, u_int8_t exchange, int response) + uint8_t firstpayload, uint8_t exchange, int response) { struct ikev2_payload *pld; struct ibuf *e = NULL; @@ -2117,11 +2437,15 @@ ikev2_send_ike_e(struct iked *env, struct iked_sa *sa, struct ibuf *buf, if ((pld = ikev2_add_payload(e)) == NULL) goto done; - if (ibuf_cat(e, buf) != 0) - goto done; - if (ikev2_next_payload(pld, ibuf_size(buf), IKEV2_PAYLOAD_NONE) == -1) - goto done; + if (buf) { + if (ibuf_cat(e, buf) != 0) + goto done; + + if (ikev2_next_payload(pld, ibuf_size(buf), + IKEV2_PAYLOAD_NONE) == -1) + goto done; + } ret = ikev2_msg_send_encrypt(env, sa, &e, exchange, firstpayload, response); @@ -2132,16 +2456,47 @@ ikev2_send_ike_e(struct iked *env, struct iked_sa *sa, struct ibuf *buf, return (ret); } +int +ikev2_set_sa_proposal(struct iked_sa *sa, struct iked_policy *pol, + unsigned int proto) +{ + struct iked_proposal *prop, *copy; + struct iked_transform *xform; + unsigned int i; + + /* create copy of the policy proposals */ + config_free_proposals(&sa->sa_proposals, proto); + TAILQ_FOREACH(prop, &pol->pol_proposals, prop_entry) { + if (proto != 0 && prop->prop_protoid != proto) + continue; + if ((copy = config_add_proposal(&sa->sa_proposals, + prop->prop_id, prop->prop_protoid)) == NULL) + return (-1); + for (i = 0; i < prop->prop_nxforms; i++) { + xform = &prop->prop_xforms[i]; + if (config_add_transform(copy, xform->xform_type, + xform->xform_id, xform->xform_length, + xform->xform_keylength) == NULL) + return (-1); + } + } + return (0); +} + int ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, - struct iked_spi *rekey, u_int8_t protoid) + struct iked_spi *rekey, uint8_t protoid) { + struct iked_policy *pol = sa->sa_policy; struct iked_childsa *csa = NULL, *csb = NULL; struct ikev2_notify *n; - struct ikev2_payload *pld; + struct ikev2_payload *pld = NULL; + struct ikev2_keyexchange *ke; + struct group *group; struct ibuf *e = NULL, *nonce = NULL; - u_int8_t *ptr; - u_int32_t spi; + uint8_t *ptr; + uint8_t firstpayload; + uint32_t spi; ssize_t len = 0; int initiator, ret = -1; @@ -2152,6 +2507,14 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, else log_debug("%s: creating new CHILD SAs", __func__); + /* XXX cannot initiate multiple concurrent CREATE_CHILD_SA exchanges */ + if (sa->sa_stateflags & IKED_REQ_CHILDSA) { + log_debug("%s: another CREATE_CHILD_SA exchange already active", + __func__); + return (-1); + } + + sa->sa_rekeyspi = 0; /* clear rekey spi */ initiator = sa->sa_hdr.sh_initiator ? 1 : 0; if (rekey && @@ -2160,6 +2523,7 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, (csb = csa->csa_peersa) == NULL)) { log_debug("%s: CHILD SA %s wasn't found", __func__, print_spi(rekey->spi, rekey->spi_size)); + goto done; } /* Generate new nonce */ @@ -2173,9 +2537,32 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, if ((e = ibuf_static()) == NULL) goto done; + /* compression */ + if ((pol->pol_flags & IKED_POLICY_IPCOMP) && + (len = ikev2_add_ipcompnotify(env, e, &pld, 0, sa)) == -1) + goto done; + + if (pld) { + firstpayload = IKEV2_PAYLOAD_NOTIFY; + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1) + goto done; + } else + firstpayload = IKEV2_PAYLOAD_SA; + /* SA payload */ if ((pld = ikev2_add_payload(e)) == NULL) goto done; + + /* + * We need to reset the sa_proposal. Otherwise it would be + * left over from the IKE_AUTH exchange and would not contain + * any DH groups (e.g. for ESP child SAs). + */ + if (ikev2_set_sa_proposal(sa, pol, protoid) < 0) { + log_debug("%s: ikev2_set_sa_proposal failed", __func__); + goto done; + } + if ((len = ikev2_add_proposals(env, sa, e, &sa->sa_proposals, protoid, 1, 0)) == -1) goto done; @@ -2190,6 +2577,32 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, goto done; len = ibuf_size(nonce); + if (config_findtransform(&pol->pol_proposals, IKEV2_XFORMTYPE_DH, + protoid)) { + log_debug("%s: enable PFS", __func__); + ikev2_sa_cleanup_dh(sa); + if (ikev2_sa_initiator_dh(sa, NULL, protoid) < 0) { + log_debug("%s: failed to setup DH", __func__); + goto done; + } + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_KE) == -1) + goto done; + + /* KE payload */ + if ((pld = ikev2_add_payload(e)) == NULL) + goto done; + if ((ke = ibuf_advance(e, sizeof(*ke))) == NULL) + goto done; + if ((group = sa->sa_dhgroup) == NULL) { + log_debug("%s: invalid dh", __func__); + goto done; + } + ke->kex_dhgroup = htobe16(group->id); + if (ikev2_add_buf(e, sa->sa_dhiexchange) == -1) + goto done; + len = sizeof(*ke) + dh_getlen(group); + } + if ((len = ikev2_add_ts(e, &pld, len, sa, !initiator)) == -1) goto done; @@ -2208,7 +2621,7 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, if ((ptr = ibuf_advance(e, rekey->spi_size)) == NULL) goto done; len = rekey->spi_size; - spi = htobe32((u_int32_t)csa->csa_peerspi); + spi = htobe32((uint32_t)csa->csa_peerspi); memcpy(ptr, &spi, rekey->spi_size); len += sizeof(*n); } @@ -2217,11 +2630,16 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, goto done; ret = ikev2_msg_send_encrypt(env, sa, &e, - IKEV2_EXCHANGE_CREATE_CHILD_SA, IKEV2_PAYLOAD_SA, 0); + IKEV2_EXCHANGE_CREATE_CHILD_SA, firstpayload, 0); if (ret == 0) { if (rekey) { csa->csa_rekey = 1; csb->csa_rekey = 1; + /* + * Remember the peer spi of the rekeyed + * SA for ikev2_init_create_child_sa(). + */ + sa->sa_rekeyspi = csa->csa_peerspi; } sa->sa_stateflags |= IKED_REQ_CHILDSA; } @@ -2231,28 +2649,131 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, return (ret); } -int -ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) +void +ikev2_ike_sa_rekey(struct iked *env, void *arg) { - struct iked_childsa *csa; - struct iked_proposal *prop; - struct iked_sa *sa = msg->msg_sa; - struct ikev2_delete *del; - struct ibuf *buf = NULL; - u_int64_t peerspi; - u_int32_t spi32; - int rekeying = 0, ret = -1; + struct iked_sa *sa = arg; + struct iked_sa *nsa = NULL; + struct ikev2_payload *pld = NULL; + struct ikev2_keyexchange *ke; + struct group *group; + struct ibuf *e = NULL, *nonce = NULL; + ssize_t len = 0; + int ret = -1; + + log_debug("%s: called for IKE SA %p", __func__, sa); + + if (sa->sa_stateflags & IKED_REQ_CHILDSA) { + /* + * We cannot initiate multiple concurrent CREATE_CHILD_SA + * exchanges, so retry in one minute. + */ + timer_add(env, &sa->sa_rekey, 60); + return; + } + + if ((nsa = sa_new(env, 0, 0, 1, sa->sa_policy)) == NULL) { + log_debug("%s: failed to get new SA", __func__); + goto done; + } + + if (ikev2_sa_initiator(env, nsa, sa, NULL)) { + log_debug("%s: failed to setup DH", __func__); + goto done; + } + sa_state(env, nsa, IKEV2_STATE_AUTH_SUCCESS); + nonce = nsa->sa_inonce; + + if ((e = ibuf_static()) == NULL) + goto done; + + /* SA payload */ + if ((pld = ikev2_add_payload(e)) == NULL) + goto done; + + /* just reuse the old IKE SA proposals */ + if ((len = ikev2_add_proposals(env, nsa, e, &sa->sa_proposals, + IKEV2_SAPROTO_IKE, 1, 1)) == -1) + goto done; + + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONCE) == -1) + goto done; + + /* NONCE payload */ + if ((pld = ikev2_add_payload(e)) == NULL) + goto done; + if (ikev2_add_buf(e, nonce) == -1) + goto done; + len = ibuf_size(nonce); + + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_KE) == -1) + goto done; + + /* KE payload */ + if ((pld = ikev2_add_payload(e)) == NULL) + goto done; + if ((ke = ibuf_advance(e, sizeof(*ke))) == NULL) + goto done; + if ((group = nsa->sa_dhgroup) == NULL) { + log_debug("%s: invalid dh", __func__); + goto done; + } + ke->kex_dhgroup = htobe16(group->id); + if (ikev2_add_buf(e, nsa->sa_dhiexchange) == -1) + goto done; + len = sizeof(*ke) + dh_getlen(group); + + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONE) == -1) + goto done; + + ret = ikev2_msg_send_encrypt(env, sa, &e, + IKEV2_EXCHANGE_CREATE_CHILD_SA, IKEV2_PAYLOAD_SA, 0); + if (ret == 0) { + sa->sa_stateflags |= IKED_REQ_CHILDSA; + sa->sa_next = nsa; + nsa = NULL; + } +done: + if (nsa) + sa_free(env, nsa); + ibuf_release(e); + + if (ret == 0) + log_debug("%s: create child SA sent", __func__); + else + log_debug("%s: could not send create child SA", __func__); + /* XXX should we try again in case of ret != 0 ? */ +} + +int +ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) +{ + struct iked_childsa *csa = NULL; + struct iked_proposal *prop; + struct iked_sa *sa = msg->msg_sa; + struct iked_sa *nsa; + struct iked_spi *spi; + struct ikev2_delete *del; + struct ibuf *buf = NULL; + uint32_t spi32; + int pfs = 0, ret = -1; if (!ikev2_msg_frompeer(msg) || (sa->sa_stateflags & IKED_REQ_CHILDSA) == 0) return (0); - if (msg->msg_prop == NULL) { + if (msg->msg_prop == NULL || + TAILQ_EMPTY(&msg->msg_proposals)) { log_debug("%s: no proposal specified", __func__); return (-1); } - /* Update peer SPI */ + if (ikev2_sa_negotiate(&sa->sa_proposals, &sa->sa_proposals, + &msg->msg_proposals) != 0) { + log_debug("%s: no proposal chosen", __func__); + return (-1); + } + TAILQ_FOREACH(prop, &sa->sa_proposals, prop_entry) { if (prop->prop_protoid == msg->msg_prop->prop_protoid) break; @@ -2263,13 +2784,56 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) return (-1); } - peerspi = prop->prop_peerspi.spi; - prop->prop_peerspi.spi = msg->msg_prop->prop_peerspi.spi; - - if ((csa = childsa_lookup(sa, peerspi, prop->prop_protoid)) != NULL) { - rekeying = 1; - log_debug("%s: rekeying CHILD SA %s", __func__, - print_spi(peerspi, prop->prop_peerspi.spi_size)); + /* IKE SA rekeying */ + if (prop->prop_protoid == IKEV2_SAPROTO_IKE) { + if (sa->sa_next == NULL) { + log_debug("%s: missing IKE SA for rekeying", __func__); + return (-1); + } + /* Update the responder SPI */ + spi = &msg->msg_prop->prop_peerspi; + if ((nsa = sa_new(env, sa->sa_next->sa_hdr.sh_ispi, + spi->spi, 1, NULL)) == NULL || nsa != sa->sa_next) { + log_debug("%s: invalid rekey SA", __func__); + if (nsa) + sa_free(env, nsa); + sa_free(env, sa->sa_next); + sa->sa_next = NULL; + return (-1); + } + if (ikev2_sa_initiator(env, nsa, sa, msg) == -1) { + log_debug("%s: failed to get IKE keys", __func__); + return (-1); + } + sa->sa_stateflags &= ~IKED_REQ_CHILDSA; + sa->sa_next = NULL; + return (ikev2_ikesa_enable(env, sa, nsa)); + } + + /* Child SA rekeying */ + if (sa->sa_rekeyspi && + (csa = childsa_lookup(sa, sa->sa_rekeyspi, prop->prop_protoid)) + != NULL) { + log_debug("%s: rekeying CHILD SA old %s spi %s", __func__, + print_spi(csa->csa_spi.spi, csa->csa_spi.spi_size), + print_spi(prop->prop_peerspi.spi, + prop->prop_peerspi.spi_size)); + } + + /* check KE payload for PFS */ + if (ibuf_length(msg->msg_ke)) { + log_debug("%s: using PFS", __func__); + if (ikev2_sa_initiator_dh(sa, msg, prop->prop_protoid) < 0) { + log_debug("%s: failed to setup DH", __func__); + return (ret); + } + if (sa->sa_dhpeer == NULL) { + log_debug("%s: no peer DH", __func__); + return (ret); + } + pfs = 1; + /* XXX check group against policy ? */ + /* XXX should ikev2_sa_negotiate do this? */ } /* Update responder's nonce */ @@ -2280,12 +2844,13 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) ibuf_release(sa->sa_rnonce); sa->sa_rnonce = ibuf_dup(msg->msg_nonce); - if (ikev2_childsa_negotiate(env, sa, 1)) { + if (ikev2_childsa_negotiate(env, sa, &sa->sa_kex, &sa->sa_proposals, 1, + pfs)) { log_debug("%s: failed to get CHILD SAs", __func__); return (-1); } - if (rekeying) { + if (csa) { /* Child SA rekeying */ if ((buf = ibuf_static()) == NULL) @@ -2298,7 +2863,7 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) del->del_spisize = sizeof(spi32); del->del_nspi = htobe16(1); - spi32 = htobe32(csa->csa_peerspi); + spi32 = htobe32(csa->csa_spi.spi); if (ibuf_add(buf, &spi32, sizeof(spi32))) goto done; @@ -2306,7 +2871,7 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) IKEV2_EXCHANGE_INFORMATIONAL, 0)) goto done; - sa->sa_stateflags |= IKED_REQ_INF | IKED_REQ_DELETE; + sa->sa_stateflags |= IKED_REQ_INF; } ret = ikev2_childsa_enable(env, sa); @@ -2321,29 +2886,159 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) } int -ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) +ikev2_ikesa_enable(struct iked *env, struct iked_sa *sa, struct iked_sa *nsa) { struct iked_childsa *csa, *nextcsa; struct iked_flow *flow, *nextflow; struct iked_proposal *prop, *nextprop; + + log_debug("%s: IKE SA %p ispi %s rspi %s replaced" + " by SA %p ispi %s rspi %s ", + __func__, sa, + print_spi(sa->sa_hdr.sh_ispi, 8), + print_spi(sa->sa_hdr.sh_rspi, 8), + nsa, + print_spi(nsa->sa_hdr.sh_ispi, 8), + print_spi(nsa->sa_hdr.sh_rspi, 8)); + + /* Transfer socket and NAT information */ + nsa->sa_fd = sa->sa_fd; + nsa->sa_natt = sa->sa_natt; + nsa->sa_udpencap = sa->sa_udpencap; + + /* Transfer all Child SAs and flows from the old IKE SA */ + for (flow = TAILQ_FIRST(&sa->sa_flows); flow != NULL; + flow = nextflow) { + nextflow = TAILQ_NEXT(flow, flow_entry); + TAILQ_REMOVE(&sa->sa_flows, flow, flow_entry); + TAILQ_INSERT_TAIL(&nsa->sa_flows, flow, + flow_entry); + flow->flow_ikesa = nsa; + flow->flow_local = &nsa->sa_local; + flow->flow_peer = &nsa->sa_peer; + } + for (csa = TAILQ_FIRST(&sa->sa_childsas); csa != NULL; + csa = nextcsa) { + nextcsa = TAILQ_NEXT(csa, csa_entry); + TAILQ_REMOVE(&sa->sa_childsas, csa, csa_entry); + TAILQ_INSERT_TAIL(&nsa->sa_childsas, csa, + csa_entry); + csa->csa_ikesa = nsa; + if (csa->csa_dir == IPSP_DIRECTION_IN) { + csa->csa_local = &nsa->sa_peer; + csa->csa_peer = &nsa->sa_local; + } else { + csa->csa_local = &nsa->sa_local; + csa->csa_peer = &nsa->sa_peer; + } + } + /* Transfer all non-IKE proposals */ + for (prop = TAILQ_FIRST(&sa->sa_proposals); prop != NULL; + prop = nextprop) { + nextprop = TAILQ_NEXT(prop, prop_entry); + if (prop->prop_protoid == IKEV2_SAPROTO_IKE) + continue; + TAILQ_REMOVE(&sa->sa_proposals, prop, prop_entry); + TAILQ_INSERT_TAIL(&nsa->sa_proposals, prop, + prop_entry); + } + + /* Preserve ID information */ + if (sa->sa_hdr.sh_initiator == nsa->sa_hdr.sh_initiator) { + nsa->sa_iid = sa->sa_iid; + nsa->sa_rid = sa->sa_rid; + } else { + /* initiator and responder role swapped */ + nsa->sa_iid = sa->sa_rid; + nsa->sa_rid = sa->sa_iid; + } + /* duplicate the actual buffer */ + nsa->sa_iid.id_buf = ibuf_dup(nsa->sa_iid.id_buf); + nsa->sa_rid.id_buf = ibuf_dup(nsa->sa_rid.id_buf); + + /* Transfer sa_addrpool address */ + if (sa->sa_addrpool) { + RB_REMOVE(iked_addrpool, &env->sc_addrpool, sa); + nsa->sa_addrpool = sa->sa_addrpool; + sa->sa_addrpool = NULL; + RB_INSERT(iked_addrpool, &env->sc_addrpool, nsa); + } + + log_debug("%s: activating new IKE SA", __func__); + sa_state(env, nsa, IKEV2_STATE_ESTABLISHED); + timer_set(env, &nsa->sa_timer, ikev2_ike_sa_alive, nsa); + timer_add(env, &nsa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT); + timer_set(env, &nsa->sa_rekey, ikev2_ike_sa_rekey, nsa); + if (nsa->sa_policy->pol_rekey) + timer_add(env, &nsa->sa_rekey, nsa->sa_policy->pol_rekey); + nsa->sa_stateflags = nsa->sa_statevalid; /* XXX */ + + /* unregister DPD keep alive timer & rekey first */ + if (sa->sa_state == IKEV2_STATE_ESTABLISHED) { + timer_del(env, &sa->sa_rekey); + timer_del(env, &sa->sa_timer); + } + + ikev2_ikesa_delete(env, sa, nsa->sa_hdr.sh_initiator); + return (0); +} + +void +ikev2_ikesa_delete(struct iked *env, struct iked_sa *sa, int initiator) +{ + struct ibuf *buf = NULL; + struct ikev2_delete *del; + + if (initiator) { + /* Send PAYLOAD_DELETE */ + if ((buf = ibuf_static()) == NULL) + goto done; + if ((del = ibuf_advance(buf, sizeof(*del))) == NULL) + goto done; + del->del_protoid = IKEV2_SAPROTO_IKE; + del->del_spisize = 0; + del->del_nspi = 0; + if (ikev2_send_ike_e(env, sa, buf, IKEV2_PAYLOAD_DELETE, + IKEV2_EXCHANGE_INFORMATIONAL, 0) == -1) + goto done; + log_debug("%s: sent delete, closing SA", __func__); +done: + ibuf_release(buf); + sa_state(env, sa, IKEV2_STATE_CLOSED); + } else { + sa_state(env, sa, IKEV2_STATE_CLOSING); + } + + /* Remove IKE-SA after timeout, e.g. if we don't get a delete */ + timer_set(env, &sa->sa_timer, ikev2_ike_sa_timeout, sa); + timer_add(env, &sa->sa_timer, IKED_IKE_SA_DELETE_TIMEOUT); +} + +int +ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) +{ + struct iked_childsa *csa; + struct iked_proposal *prop; + struct iked_proposals proposals; + struct iked_kex *kex, *kextmp = NULL; struct iked_sa *nsa = NULL, *sa = msg->msg_sa; struct iked_spi *spi, *rekey = &msg->msg_rekey; struct ikev2_keyexchange *ke; - struct ikev2_notify *n; - struct ikev2_payload *pld; - struct ibuf *buf = NULL, *e = NULL, *nonce = NULL; - struct group *group; - u_int64_t spi64; - u_int32_t spi32; + struct ikev2_payload *pld = NULL; + struct ibuf *e = NULL, *nonce = NULL; + uint8_t firstpayload; ssize_t len = 0; int initiator, protoid, rekeying = 1; int ret = -1; + int pfs = 0; initiator = sa->sa_hdr.sh_initiator ? 1 : 0; if (!ikev2_msg_frompeer(msg) || msg->msg_prop == NULL) return (0); + TAILQ_INIT(&proposals); + if ((protoid = rekey->spi_protoid) == 0) { /* * If REKEY_SA notification is not present, then it's either @@ -2389,45 +3084,42 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) sa_state(env, nsa, IKEV2_STATE_AUTH_SUCCESS); nonce = nsa->sa_rnonce; + kex = &nsa->sa_kex; } else { /* Child SA creating/rekeying */ + if ((kex = kextmp = calloc(1, sizeof(*kextmp))) == NULL) { + log_debug("%s: calloc kex", __func__); + goto fail; + } + + if (ikev2_sa_negotiate(&proposals, + &sa->sa_policy->pol_proposals, &msg->msg_proposals) != 0) { + log_debug("%s: no proposal chosen", __func__); + goto fail; + } + + /* check KE payload for PFS */ if (ibuf_length(msg->msg_parent->msg_ke)) { - /* We do not support KE payload yet */ - if ((buf = ibuf_static()) == NULL) - return (-1); - if ((n = ibuf_advance(buf, sizeof(*n))) == NULL) { - ibuf_release(buf); - return (-1); - } - n->n_protoid = protoid; - n->n_spisize = rekey->spi_size; - n->n_type = htobe16(IKEV2_N_NO_ADDITIONAL_SAS); - switch (rekey->spi_size) { - case 4: - spi32 = htobe32(rekey->spi); - ibuf_add(buf, &spi32, rekey->spi_size); - break; - case 8: - spi64 = htobe64(rekey->spi); - ibuf_add(buf, &spi64, rekey->spi_size); - break; + log_debug("%s: using PFS", __func__); + if (ikev2_sa_responder_dh(kex, &proposals, + msg->msg_parent, protoid) < 0) { + log_debug("%s: failed to setup DH", __func__); + goto fail; } - ikev2_send_ike_e(env, sa, buf, IKEV2_PAYLOAD_NOTIFY, - IKEV2_EXCHANGE_CREATE_CHILD_SA, 1); - ibuf_release(buf); - return (0); + pfs = 1; + /* XXX check group against policy ? */ } /* Update peer SPI */ - TAILQ_FOREACH(prop, &sa->sa_proposals, prop_entry) { + TAILQ_FOREACH(prop, &proposals, prop_entry) { if (prop->prop_protoid == protoid) break; } if (prop == NULL) { log_debug("%s: failed to find %s proposals", __func__, print_map(protoid, ikev2_saproto_map)); - return (-1); + goto fail; } else prop->prop_peerspi = msg->msg_prop->prop_peerspi; @@ -2438,13 +3130,13 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) log_debug("%s: CHILD SA %s wasn't found", __func__, print_spi(rekey->spi, rekey->spi_size)); - return (-1); + goto fail; } if (!csa->csa_loaded || !csa->csa_peersa || !csa->csa_peersa->csa_loaded) { log_debug("%s: SA is not loaded or no peer SA", __func__); - return (-1); + goto fail; } csa->csa_rekey = 1; csa->csa_peersa->csa_rekey = 1; @@ -2453,34 +3145,46 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) /* Update initiator's nonce */ if (!ibuf_length(msg->msg_nonce)) { log_debug("%s: initiator didn't send nonce", __func__); - return (-1); + goto fail; } - ibuf_release(sa->sa_inonce); - sa->sa_inonce = ibuf_dup(msg->msg_nonce); + ibuf_release(kex->kex_inonce); + kex->kex_inonce = ibuf_dup(msg->msg_nonce); /* Generate new responder's nonce */ if ((nonce = ibuf_random(IKED_NONCE_SIZE)) == NULL) - return (-1); + goto fail; /* Update responder's nonce */ - ibuf_release(sa->sa_rnonce); - sa->sa_rnonce = nonce; + ibuf_release(kex->kex_rnonce); + kex->kex_rnonce = nonce; - if (ikev2_childsa_negotiate(env, sa, 0)) { + if (ikev2_childsa_negotiate(env, sa, kex, &proposals, 0, pfs)) { log_debug("%s: failed to get CHILD SAs", __func__); - return (-1); + goto fail; } } if ((e = ibuf_static()) == NULL) goto done; + /* compression (unless IKE rekeying) */ + if (!nsa && sa->sa_ipcomp && + (len = ikev2_add_ipcompnotify(env, e, &pld, 0, sa)) == -1) + goto done; + + if (pld) { + firstpayload = IKEV2_PAYLOAD_NOTIFY; + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1) + goto done; + } else + firstpayload = IKEV2_PAYLOAD_SA; + /* SA payload */ if ((pld = ikev2_add_payload(e)) == NULL) goto done; if ((len = ikev2_add_proposals(env, nsa ? nsa : sa, e, - nsa ? &nsa->sa_proposals : &sa->sa_proposals, + nsa ? &nsa->sa_proposals : &proposals, protoid, 0, nsa ? 1 : 0)) == -1) goto done; @@ -2494,7 +3198,8 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) goto done; len = ibuf_size(nonce); - if (protoid == IKEV2_SAPROTO_IKE) { + if (protoid == IKEV2_SAPROTO_IKE || pfs) { + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_KE) == -1) goto done; @@ -2503,74 +3208,44 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) goto done; if ((ke = ibuf_advance(e, sizeof(*ke))) == NULL) goto done; - if ((group = nsa->sa_dhgroup) == NULL) { + if (kex->kex_dhgroup == NULL) { log_debug("%s: invalid dh", __func__); goto done; } - ke->kex_dhgroup = htobe16(group->id); - if (ikev2_add_buf(e, nsa->sa_dhrexchange) == -1) + ke->kex_dhgroup = htobe16(kex->kex_dhgroup->id); + if (ikev2_add_buf(e, kex->kex_dhrexchange) == -1) goto done; - len = sizeof(*ke) + dh_getlen(group); - } else { + len = sizeof(*ke) + dh_getlen(kex->kex_dhgroup); + } + + if (protoid != IKEV2_SAPROTO_IKE) if ((len = ikev2_add_ts(e, &pld, len, sa, initiator)) == -1) goto done; - } if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONE) == -1) goto done; if ((ret = ikev2_msg_send_encrypt(env, sa, &e, - IKEV2_EXCHANGE_CREATE_CHILD_SA, IKEV2_PAYLOAD_SA, 1)) == -1) + IKEV2_EXCHANGE_CREATE_CHILD_SA, firstpayload, 1)) == -1) goto done; - if (protoid == IKEV2_SAPROTO_IKE) { - /* Transfer all Child SAs and flows from the old IKE SA */ - for (flow = TAILQ_FIRST(&sa->sa_flows); flow != NULL; - flow = nextflow) { - nextflow = TAILQ_NEXT(flow, flow_entry); - TAILQ_REMOVE(&sa->sa_flows, flow, flow_entry); - TAILQ_INSERT_TAIL(&nsa->sa_flows, flow, - flow_entry); - flow->flow_ikesa = nsa; - } - for (csa = TAILQ_FIRST(&sa->sa_childsas); csa != NULL; - csa = nextcsa) { - nextcsa = TAILQ_NEXT(csa, csa_entry); - TAILQ_REMOVE(&sa->sa_childsas, csa, csa_entry); - TAILQ_INSERT_TAIL(&nsa->sa_childsas, csa, - csa_entry); - csa->csa_ikesa = nsa; - } - /* Transfer all non-IKE proposals */ - for (prop = TAILQ_FIRST(&sa->sa_proposals); prop != NULL; - prop = nextprop) { - nextprop = TAILQ_NEXT(prop, prop_entry); - if (prop->prop_protoid == IKEV2_SAPROTO_IKE) - continue; - TAILQ_REMOVE(&sa->sa_proposals, prop, prop_entry); - TAILQ_INSERT_TAIL(&nsa->sa_proposals, prop, - prop_entry); - } - /* Preserve ID information */ - nsa->sa_iid = sa->sa_iid; - nsa->sa_iid.id_buf = ibuf_dup(sa->sa_iid.id_buf); - nsa->sa_rid = sa->sa_rid; - nsa->sa_rid.id_buf = ibuf_dup(sa->sa_rid.id_buf); - - log_debug("%s: activating new IKE SA", __func__); - sa_state(env, nsa, IKEV2_STATE_ESTABLISHED); - nsa->sa_stateflags = sa->sa_statevalid; /* XXX */ - - timer_initialize(env, &sa->sa_timer, ikev2_ike_sa_timeout, sa); - timer_register(env, &sa->sa_timer, IKED_IKE_SA_REKEY_TIMEOUT); - } else + if (protoid == IKEV2_SAPROTO_IKE) + ret = ikev2_ikesa_enable(env, sa, nsa); + else ret = ikev2_childsa_enable(env, sa); done: if (ret && protoid != IKEV2_SAPROTO_IKE) ikev2_childsa_delete(env, sa, 0, 0, NULL, 1); ibuf_release(e); + config_free_proposals(&proposals, 0); + config_free_kex(kextmp); return (ret); + + fail: + config_free_proposals(&proposals, 0); + config_free_kex(kextmp); + return (-1); } void @@ -2582,6 +3257,50 @@ ikev2_ike_sa_timeout(struct iked *env, void *arg) sa_free(env, sa); } +void +ikev2_ike_sa_alive(struct iked *env, void *arg) +{ + struct iked_sa *sa = arg; + struct iked_childsa *csa = NULL; + struct timeval tv; + uint64_t last_used, diff; + int foundin = 0, foundout = 0; + + /* check for incoming traffic on any child SA */ + TAILQ_FOREACH(csa, &sa->sa_childsas, csa_entry) { + if (!csa->csa_loaded || + csa->csa_saproto == IKEV2_SAPROTO_IPCOMP) + continue; + if (pfkey_sa_last_used(env->sc_pfkey, csa, &last_used) != 0) + continue; + gettimeofday(&tv, NULL); + diff = (uint32_t)(tv.tv_sec - last_used); + log_debug("%s: %s CHILD SA spi %s last used %llu second(s) ago", + __func__, + csa->csa_dir == IPSP_DIRECTION_IN ? "incoming" : "outgoing", + print_spi(csa->csa_spi.spi, csa->csa_spi.spi_size), diff); + if (diff < IKED_IKE_SA_ALIVE_TIMEOUT) { + if (csa->csa_dir == IPSP_DIRECTION_IN) { + foundin = 1; + break; + } else { + foundout = 1; + } + } + } + + /* send probe if any outging SA has been used, but no incoming SA */ + if (!foundin && foundout) { + log_debug("%s: sending alive check", __func__); + ikev2_send_ike_e(env, sa, NULL, IKEV2_PAYLOAD_NONE, + IKEV2_EXCHANGE_INFORMATIONAL, 0); + sa->sa_stateflags |= IKED_REQ_INF; + } + + /* re-register */ + timer_add(env, &sa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT); +} + int ikev2_send_informational(struct iked *env, struct iked_message *msg) { @@ -2696,10 +3415,10 @@ ikev2_send_informational(struct iked *env, struct iked_message *msg) } ssize_t -ikev2_psk(struct iked_sa *sa, u_int8_t *data, size_t length, - u_int8_t **pskptr) +ikev2_psk(struct iked_sa *sa, uint8_t *data, size_t length, + uint8_t **pskptr) { - u_int8_t *psk; + uint8_t *psk; size_t psklen = -1; if (hash_setkey(sa->sa_prf, data, length) == NULL) @@ -2721,8 +3440,8 @@ ikev2_match_proposals(struct iked_proposal *local, struct iked_proposal *peer, struct iked_transform **xforms) { struct iked_transform *tpeer, *tlocal; - u_int i, j, type, score; - u_int8_t protoid = peer->prop_protoid; + unsigned int i, j, type, score; + uint8_t protoid = peer->prop_protoid; for (i = 0; i < peer->prop_nxforms; i++) { tpeer = peer->prop_xforms + i; @@ -2778,16 +3497,17 @@ ikev2_match_proposals(struct iked_proposal *local, struct iked_proposal *peer, } int -ikev2_sa_negotiate(struct iked_sa *sa, struct iked_proposals *local, +ikev2_sa_negotiate(struct iked_proposals *result, struct iked_proposals *local, struct iked_proposals *peer) { struct iked_proposal *ppeer = NULL, *plocal, *prop, vpeer, vlocal; - struct iked_transform *chosen[IKEV2_XFORMTYPE_MAX]; + struct iked_transform chosen[IKEV2_XFORMTYPE_MAX]; + struct iked_transform *valid[IKEV2_XFORMTYPE_MAX]; struct iked_transform *match[IKEV2_XFORMTYPE_MAX]; - u_int i, score, chosen_score = 0; - u_int8_t protoid = 0; + unsigned int i, score, chosen_score = 0; + uint8_t protoid = 0; - bzero(chosen, sizeof(chosen)); + bzero(valid, sizeof(valid)); bzero(&vlocal, sizeof(vlocal)); bzero(&vpeer, sizeof(vpeer)); @@ -2806,8 +3526,11 @@ ikev2_sa_negotiate(struct iked_sa *sa, struct iked_proposals *local, log_debug("%s: score %d", __func__, score); if (score && (!chosen_score || score < chosen_score)) { chosen_score = score; - for (i = 0; i < IKEV2_XFORMTYPE_MAX; i++) - chosen[i] = match[i]; + for (i = 0; i < IKEV2_XFORMTYPE_MAX; i++) { + if ((valid[i] = match[i])) + memcpy(&chosen[i], match[i], + sizeof(chosen[0])); + } memcpy(&vpeer, ppeer, sizeof(vpeer)); memcpy(&vlocal, plocal, sizeof(vlocal)); } @@ -2818,12 +3541,11 @@ ikev2_sa_negotiate(struct iked_sa *sa, struct iked_proposals *local, if (chosen_score == 0) return (-1); - else if (sa == NULL) + else if (result == NULL) return (0); - (void)config_free_proposals(&sa->sa_proposals, vpeer.prop_protoid); - prop = config_add_proposal(&sa->sa_proposals, vpeer.prop_id, - vpeer.prop_protoid); + (void)config_free_proposals(result, vpeer.prop_protoid); + prop = config_add_proposal(result, vpeer.prop_id, vpeer.prop_protoid); if (vpeer.prop_localspi.spi_size) { prop->prop_localspi.spi_size = vpeer.prop_localspi.spi_size; @@ -2835,18 +3557,18 @@ ikev2_sa_negotiate(struct iked_sa *sa, struct iked_proposals *local, } for (i = 0; i < IKEV2_XFORMTYPE_MAX; i++) { - if (chosen[i] == NULL) + if (valid[i] == NULL) continue; print_debug("%s: score %d: %s %s", __func__, - chosen[i]->xform_score, print_map(i, ikev2_xformtype_map), - print_map(chosen[i]->xform_id, chosen[i]->xform_map)); - if (chosen[i]->xform_length) - print_debug(" %d", chosen[i]->xform_length); + chosen[i].xform_score, print_map(i, ikev2_xformtype_map), + print_map(chosen[i].xform_id, chosen[i].xform_map)); + if (chosen[i].xform_length) + print_debug(" %d", chosen[i].xform_length); print_debug("\n"); - if (config_add_transform(prop, chosen[i]->xform_type, - chosen[i]->xform_id, chosen[i]->xform_length, - chosen[i]->xform_keylength) == NULL) + if (config_add_transform(prop, chosen[i].xform_type, + chosen[i].xform_id, chosen[i].xform_length, + chosen[i].xform_keylength) == NULL) break; } @@ -2854,15 +3576,15 @@ ikev2_sa_negotiate(struct iked_sa *sa, struct iked_proposals *local, } int -ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, - struct iked_message *msg) +ikev2_sa_initiator_dh(struct iked_sa *sa, struct iked_message *msg, + unsigned int proto) { struct iked_policy *pol = sa->sa_policy; struct iked_transform *xform; if (sa->sa_dhgroup == NULL) { if ((xform = config_findtransform(&pol->pol_proposals, - IKEV2_XFORMTYPE_DH)) == NULL) { + IKEV2_XFORMTYPE_DH, proto)) == NULL) { log_debug("%s: did not find dh transform", __func__); return (-1); } @@ -2887,28 +3609,10 @@ ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, } } - if (!ibuf_length(sa->sa_inonce)) { - if ((sa->sa_inonce = ibuf_random(IKED_NONCE_SIZE)) == NULL) { - log_debug("%s: failed to get local nonce", __func__); - return (-1); - } - } - /* Initial message */ if (msg == NULL) return (0); - if (!ibuf_length(sa->sa_rnonce)) { - if (!ibuf_length(msg->msg_nonce)) { - log_debug("%s: invalid peer nonce", __func__); - return (-1); - } - if ((sa->sa_rnonce = ibuf_dup(msg->msg_nonce)) == NULL) { - log_debug("%s: failed to get peer nonce", __func__); - return (-1); - } - } - if (!ibuf_length(sa->sa_dhrexchange)) { if (!ibuf_length(msg->msg_ke)) { log_debug("%s: invalid peer dh exchange", __func__); @@ -2928,10 +3632,43 @@ ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, /* Set a pointer to the peer exchange */ sa->sa_dhpeer = sa->sa_dhrexchange; + return (0); +} + +int +ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, + struct iked_sa *osa, struct iked_message *msg) +{ + struct iked_transform *xform; + + if (ikev2_sa_initiator_dh(sa, msg, 0) < 0) + return (-1); + + if (!ibuf_length(sa->sa_inonce)) { + if ((sa->sa_inonce = ibuf_random(IKED_NONCE_SIZE)) == NULL) { + log_debug("%s: failed to get local nonce", __func__); + return (-1); + } + } + + /* Initial message */ + if (msg == NULL) + return (0); + + if (!ibuf_length(sa->sa_rnonce)) { + if (!ibuf_length(msg->msg_nonce)) { + log_debug("%s: invalid peer nonce", __func__); + return (-1); + } + if ((sa->sa_rnonce = ibuf_dup(msg->msg_nonce)) == NULL) { + log_debug("%s: failed to get peer nonce", __func__); + return (-1); + } + } /* XXX we need a better way to get this */ - if (ikev2_sa_negotiate(sa, &msg->msg_policy->pol_proposals, - &msg->msg_proposals) != 0) { + if (ikev2_sa_negotiate(&sa->sa_proposals, + &msg->msg_policy->pol_proposals, &msg->msg_proposals) != 0) { log_debug("%s: no proposal chosen", __func__); msg->msg_error = IKEV2_N_NO_PROPOSAL_CHOSEN; return (-1); @@ -2940,7 +3677,7 @@ ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, if (sa->sa_encr == NULL) { if ((xform = config_findtransform(&sa->sa_proposals, - IKEV2_XFORMTYPE_ENCR)) == NULL) { + IKEV2_XFORMTYPE_ENCR, 0)) == NULL) { log_debug("%s: did not find encr transform", __func__); return (-1); } @@ -2953,7 +3690,7 @@ ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, if (sa->sa_prf == NULL) { if ((xform = config_findtransform(&sa->sa_proposals, - IKEV2_XFORMTYPE_PRF)) == NULL) { + IKEV2_XFORMTYPE_PRF, 0)) == NULL) { log_debug("%s: did not find prf transform", __func__); return (-1); } @@ -2966,7 +3703,7 @@ ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, if (sa->sa_integr == NULL) { if ((xform = config_findtransform(&sa->sa_proposals, - IKEV2_XFORMTYPE_INTEGR)) == NULL) { + IKEV2_XFORMTYPE_INTEGR, 0)) == NULL) { log_debug("%s: did not find integr transform", __func__); return (-1); @@ -2984,9 +3721,57 @@ ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, return (-1); } - return (ikev2_sa_keys(env, sa, NULL)); + return (ikev2_sa_keys(env, sa, osa ? osa->sa_key_d : NULL)); } +int +ikev2_sa_responder_dh(struct iked_kex *kex, struct iked_proposals *proposals, + struct iked_message *msg, unsigned int proto) +{ + struct iked_transform *xform; + + if (kex->kex_dhgroup == NULL) { + if ((xform = config_findtransform(proposals, + IKEV2_XFORMTYPE_DH, proto)) == NULL) { + log_debug("%s: did not find dh transform", __func__); + return (-1); + } + if ((kex->kex_dhgroup = + group_get(xform->xform_id)) == NULL) { + log_debug("%s: invalid dh %d", __func__, + xform->xform_id); + return (-1); + } + } + + if (!ibuf_length(kex->kex_dhrexchange)) { + if ((kex->kex_dhrexchange = ibuf_new(NULL, + dh_getlen(kex->kex_dhgroup))) == NULL) { + log_debug("%s: failed to alloc dh exchange", __func__); + return (-1); + } + if (dh_create_exchange(kex->kex_dhgroup, + kex->kex_dhrexchange->buf) == -1) { + log_debug("%s: failed to get dh exchange", __func__); + return (-1); + } + } + + if (!ibuf_length(kex->kex_dhiexchange)) { + if ((kex->kex_dhiexchange = ibuf_dup(msg->msg_ke)) == NULL || + ((ssize_t)ibuf_length(kex->kex_dhiexchange) != + dh_getlen(kex->kex_dhgroup))) { + /* XXX send notification to peer */ + log_debug("%s: invalid dh, size %d", __func__, + dh_getlen(kex->kex_dhgroup) * 8); + return (-1); + } + } + + /* Set a pointer to the peer exchange */ + kex->kex_dhpeer = kex->kex_dhiexchange; + return (0); +} int ikev2_sa_responder(struct iked *env, struct iked_sa *sa, struct iked_sa *osa, struct iked_message *msg) @@ -3015,8 +3800,8 @@ ikev2_sa_responder(struct iked *env, struct iked_sa *sa, struct iked_sa *osa, } /* XXX we need a better way to get this */ - if (ikev2_sa_negotiate(sa, &msg->msg_policy->pol_proposals, - &msg->msg_proposals) != 0) { + if (ikev2_sa_negotiate(&sa->sa_proposals, + &msg->msg_policy->pol_proposals, &msg->msg_proposals) != 0) { log_debug("%s: no proposal chosen", __func__); msg->msg_error = IKEV2_N_NO_PROPOSAL_CHOSEN; return (-1); @@ -3025,7 +3810,7 @@ ikev2_sa_responder(struct iked *env, struct iked_sa *sa, struct iked_sa *osa, if (sa->sa_encr == NULL) { if ((xform = config_findtransform(&sa->sa_proposals, - IKEV2_XFORMTYPE_ENCR)) == NULL) { + IKEV2_XFORMTYPE_ENCR, 0)) == NULL) { log_debug("%s: did not find encr transform", __func__); return (-1); } @@ -3038,7 +3823,7 @@ ikev2_sa_responder(struct iked *env, struct iked_sa *sa, struct iked_sa *osa, if (sa->sa_prf == NULL) { if ((xform = config_findtransform(&sa->sa_proposals, - IKEV2_XFORMTYPE_PRF)) == NULL) { + IKEV2_XFORMTYPE_PRF, 0)) == NULL) { log_debug("%s: did not find prf transform", __func__); return (-1); } @@ -3051,7 +3836,7 @@ ikev2_sa_responder(struct iked *env, struct iked_sa *sa, struct iked_sa *osa, if (sa->sa_integr == NULL) { if ((xform = config_findtransform(&sa->sa_proposals, - IKEV2_XFORMTYPE_INTEGR)) == NULL) { + IKEV2_XFORMTYPE_INTEGR, 0)) == NULL) { log_debug("%s: did not find integr transform", __func__); return (-1); @@ -3063,45 +3848,8 @@ ikev2_sa_responder(struct iked *env, struct iked_sa *sa, struct iked_sa *osa, } } - if (sa->sa_dhgroup == NULL) { - if ((xform = config_findtransform(&sa->sa_proposals, - IKEV2_XFORMTYPE_DH)) == NULL) { - log_debug("%s: did not find dh transform", __func__); - return (-1); - } - if ((sa->sa_dhgroup = - group_get(xform->xform_id)) == NULL) { - log_debug("%s: invalid dh", __func__); - return (-1); - } - } - - if (!ibuf_length(sa->sa_dhrexchange)) { - if ((sa->sa_dhrexchange = ibuf_new(NULL, - dh_getlen(sa->sa_dhgroup))) == NULL) { - log_debug("%s: failed to alloc dh exchange", __func__); - return (-1); - } - if (dh_create_exchange(sa->sa_dhgroup, - sa->sa_dhrexchange->buf) == -1) { - log_debug("%s: failed to get dh exchange", __func__); - return (-1); - } - } - - if (!ibuf_length(sa->sa_dhiexchange)) { - if ((sa->sa_dhiexchange = ibuf_dup(msg->msg_ke)) == NULL || - ((ssize_t)ibuf_length(sa->sa_dhiexchange) != - dh_getlen(sa->sa_dhgroup))) { - /* XXX send notification to peer */ - log_debug("%s: invalid dh, size %d", __func__, - dh_getlen(sa->sa_dhgroup) * 8); - return (-1); - } - } - - /* Set a pointer to the peer exchange */ - sa->sa_dhpeer = sa->sa_dhiexchange; + if (ikev2_sa_responder_dh(&sa->sa_kex, &sa->sa_proposals, msg, 0) < 0) + return (-1); return (ikev2_sa_keys(env, sa, osa ? osa->sa_key_d : NULL)); } @@ -3114,7 +3862,7 @@ ikev2_sa_keys(struct iked *env, struct iked_sa *sa, struct ibuf *key) struct group *group; struct ibuf *ninr, *dhsecret, *skeyseed, *s, *t; size_t nonceminlen, ilen, rlen, tmplen; - u_int64_t ispi, rspi; + uint64_t ispi, rspi; int ret = -1; ninr = dhsecret = skeyseed = s = t = NULL; @@ -3171,7 +3919,7 @@ ikev2_sa_keys(struct iked *env, struct iked_sa *sa, struct ibuf *key) if (dh_create_shared(group, dhsecret->buf, sa->sa_dhpeer->buf) == -1) { log_debug("%s: failed to get dh secret" - " group %d len %d secret %d exchange %d", __func__, + " group %d len %d secret %zu exchange %zu", __func__, group->id, dh_getlen(group), ibuf_length(dhsecret), ibuf_length(sa->sa_dhpeer)); goto done; @@ -3215,7 +3963,7 @@ ikev2_sa_keys(struct iked *env, struct iked_sa *sa, struct ibuf *key) hash_update(prf, dhsecret->buf, ibuf_length(dhsecret)); hash_final(prf, skeyseed->buf, &tmplen); - log_debug("%s: SKEYSEED with %d bytes", __func__, tmplen); + log_debug("%s: SKEYSEED with %zu bytes", __func__, tmplen); print_hex(skeyseed->buf, 0, tmplen); if (ibuf_setsize(skeyseed, tmplen) == -1) { @@ -3243,7 +3991,7 @@ ikev2_sa_keys(struct iked *env, struct iked_sa *sa, struct ibuf *key) goto done; } - log_debug("%s: S with %d bytes", __func__, ibuf_length(s)); + log_debug("%s: S with %zu bytes", __func__, ibuf_length(s)); print_hex(s->buf, 0, ibuf_length(s)); /* @@ -3275,25 +4023,25 @@ ikev2_sa_keys(struct iked *env, struct iked_sa *sa, struct ibuf *key) goto done; } - log_debug("%s: SK_d with %d bytes", __func__, + log_debug("%s: SK_d with %zu bytes", __func__, ibuf_length(sa->sa_key_d)); print_hex(sa->sa_key_d->buf, 0, ibuf_length(sa->sa_key_d)); - log_debug("%s: SK_ai with %d bytes", __func__, + log_debug("%s: SK_ai with %zu bytes", __func__, ibuf_length(sa->sa_key_iauth)); print_hex(sa->sa_key_iauth->buf, 0, ibuf_length(sa->sa_key_iauth)); - log_debug("%s: SK_ar with %d bytes", __func__, + log_debug("%s: SK_ar with %zu bytes", __func__, ibuf_length(sa->sa_key_rauth)); print_hex(sa->sa_key_rauth->buf, 0, ibuf_length(sa->sa_key_rauth)); - log_debug("%s: SK_ei with %d bytes", __func__, + log_debug("%s: SK_ei with %zu bytes", __func__, ibuf_length(sa->sa_key_iencr)); print_hex(sa->sa_key_iencr->buf, 0, ibuf_length(sa->sa_key_iencr)); - log_debug("%s: SK_er with %d bytes", __func__, + log_debug("%s: SK_er with %zu bytes", __func__, ibuf_length(sa->sa_key_rencr)); print_hex(sa->sa_key_rencr->buf, 0, ibuf_length(sa->sa_key_rencr)); - log_debug("%s: SK_pi with %d bytes", __func__, + log_debug("%s: SK_pi with %zu bytes", __func__, ibuf_length(sa->sa_key_iprf)); print_hex(sa->sa_key_iprf->buf, 0, ibuf_length(sa->sa_key_iprf)); - log_debug("%s: SK_pr with %d bytes", __func__, + log_debug("%s: SK_pr with %zu bytes", __func__, ibuf_length(sa->sa_key_rprf)); print_hex(sa->sa_key_rprf->buf, 0, ibuf_length(sa->sa_key_rprf)); @@ -3309,13 +4057,24 @@ ikev2_sa_keys(struct iked *env, struct iked_sa *sa, struct ibuf *key) return (ret); } +void +ikev2_sa_cleanup_dh(struct iked_sa *sa) +{ + ibuf_release(sa->sa_dhiexchange); + ibuf_release(sa->sa_dhrexchange); + group_free(sa->sa_dhgroup); + sa->sa_dhiexchange = NULL; + sa->sa_dhrexchange = NULL; + sa->sa_dhgroup = NULL; +} + struct ibuf * ikev2_prfplus(struct iked_hash *prf, struct ibuf *key, struct ibuf *seed, size_t keymatlen) { struct ibuf *t = NULL, *t1 = NULL, *t2 = NULL; size_t rlen, i, hashlen = 0; - u_int8_t pad = 0; + uint8_t pad = 0; /* * prf+ (K, S) = T1 | T2 | T3 | T4 | ... @@ -3362,12 +4121,12 @@ ikev2_prfplus(struct iked_hash *prf, struct ibuf *key, struct ibuf *seed, ibuf_release(t2); ibuf_add(t, t1->buf, ibuf_length(t1)); - log_debug("%s: T%d with %d bytes", __func__, + log_debug("%s: T%d with %zu bytes", __func__, pad, ibuf_length(t1)); print_hex(t1->buf, 0, ibuf_length(t1)); } - log_debug("%s: Tn with %d bytes", __func__, ibuf_length(t)); + log_debug("%s: Tn with %zu bytes", __func__, ibuf_length(t)); print_hex(t->buf, 0, ibuf_length(t)); ibuf_release(t1); @@ -3453,7 +4212,7 @@ ikev2_sa_tag(struct iked_sa *sa, struct iked_id *id) } } - log_debug("%s: %s (%d)", __func__, sa->sa_tag, strlen(sa->sa_tag)); + log_debug("%s: %s (%zu)", __func__, sa->sa_tag, strlen(sa->sa_tag)); ret = 0; fail: @@ -3466,35 +4225,29 @@ ikev2_sa_tag(struct iked_sa *sa, struct iked_id *id) } int -ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) +ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, + struct iked_kex *kex, struct iked_proposals *proposals, int initiator, + int pfs) { struct iked_proposal *prop; struct iked_transform *xform, *encrxf = NULL, *integrxf = NULL; struct iked_childsa *csa, *csb; struct iked_flow *flow, *saflow, *flowa, *flowb; - struct iked_id *peerid, *localid; - struct ibuf *keymat = NULL, *seed = NULL; - u_int32_t spi = 0; - u_int i; + struct ibuf *keymat = NULL, *seed = NULL, *dhsecret = NULL; + struct group *group; + uint32_t spi = 0; + unsigned int i; size_t ilen = 0; int esn, skip, ret = -1; if (!sa_stateok(sa, IKEV2_STATE_VALID)) return (-1); - if (sa->sa_hdr.sh_initiator) { - peerid = &sa->sa_rid; - localid = &sa->sa_iid; - } else { - peerid = &sa->sa_iid; - localid = &sa->sa_rid; - } - - if (ikev2_sa_tag(sa, peerid) == -1) + if (ikev2_sa_tag(sa, IKESA_DSTID(sa)) == -1) return (-1); /* We need to determine the key material length first */ - TAILQ_FOREACH(prop, &sa->sa_proposals, prop_entry) { + TAILQ_FOREACH(prop, proposals, prop_entry) { if (prop->prop_protoid == IKEV2_SAPROTO_IKE) continue; log_debug("%s: proposal %d", __func__, prop->prop_id); @@ -3522,10 +4275,40 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) /* double key material length for inbound/outbound */ ilen *= 2; - log_debug("%s: key material length %d", __func__, ilen); + log_debug("%s: key material length %zu", __func__, ilen); - if ((seed = ibuf_dup(sa->sa_inonce)) == NULL || - ibuf_cat(seed, sa->sa_rnonce) != 0 || + if ((seed = ibuf_new(NULL, 0)) == NULL) { + log_debug("%s: failed to setup IKE SA key material", __func__); + goto done; + } + if (pfs) { + log_debug("%s: using PFS", __func__); + if (kex->kex_dhpeer == NULL || + ibuf_length(kex->kex_dhpeer) == 0 || + (group = kex->kex_dhgroup) == NULL) { + log_debug("%s: no dh group for pfs", __func__); + goto done; + } + if ((dhsecret = ibuf_new(NULL, dh_getlen(group))) == NULL) { + log_debug("%s: failed to alloc dh secret", __func__); + goto done; + } + if (dh_create_shared(group, dhsecret->buf, + kex->kex_dhpeer->buf) == -1) { + log_debug("%s: failed to get dh secret" + " group %d len %d secret %zu exchange %zu", + __func__, group->id, dh_getlen(group), + ibuf_length(dhsecret), + ibuf_length(kex->kex_dhpeer)); + goto done; + } + if (ibuf_cat(seed, dhsecret) != 0) { + log_debug("%s: failed to set dh secret", __func__); + goto done; + } + } + if (ibuf_cat(seed, kex->kex_inonce) != 0 || + ibuf_cat(seed, kex->kex_rnonce) != 0 || (keymat = ikev2_prfplus(sa->sa_prf, sa->sa_key_d, seed, ilen)) == NULL) { log_debug("%s: failed to get IKE SA key material", __func__); @@ -3533,7 +4316,7 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) } /* Create the new flows */ - TAILQ_FOREACH(prop, &sa->sa_proposals, prop_entry) { + TAILQ_FOREACH(prop, proposals, prop_entry) { if (ikev2_valid_proposal(prop, NULL, NULL, NULL) != 0) continue; @@ -3544,8 +4327,11 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) &flow->flow_src) && IKED_ADDR_EQ(&saflow->flow_dst, &flow->flow_dst) && - saflow->flow_saproto == prop->prop_protoid) + saflow->flow_saproto == + prop->prop_protoid) { skip = 1; + break; + } } if (skip) continue; @@ -3558,11 +4344,10 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) memcpy(flowa, flow, sizeof(*flow)); flowa->flow_dir = IPSP_DIRECTION_OUT; flowa->flow_saproto = prop->prop_protoid; - flowa->flow_srcid = localid; - flowa->flow_dstid = peerid; flowa->flow_local = &sa->sa_local; flowa->flow_peer = &sa->sa_peer; flowa->flow_ikesa = sa; + ikev2_cp_fixaddr(sa, &flow->flow_dst, &flowa->flow_dst); if ((flowb = calloc(1, sizeof(*flowb))) == NULL) { log_debug("%s: failed to get flow", __func__); @@ -3577,6 +4362,7 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) sizeof(flow->flow_dst)); memcpy(&flowb->flow_dst, &flow->flow_src, sizeof(flow->flow_src)); + ikev2_cp_fixaddr(sa, &flow->flow_dst, &flowb->flow_src); TAILQ_INSERT_TAIL(&sa->sa_flows, flowa, flow_entry); TAILQ_INSERT_TAIL(&sa->sa_flows, flowb, flow_entry); @@ -3584,7 +4370,7 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) } /* create the CHILD SAs using the key material */ - TAILQ_FOREACH(prop, &sa->sa_proposals, prop_entry) { + TAILQ_FOREACH(prop, proposals, prop_entry) { if (ikev2_valid_proposal(prop, &encrxf, &integrxf, &esn) != 0) continue; @@ -3597,8 +4383,6 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) csa->csa_saproto = prop->prop_protoid; csa->csa_ikesa = sa; - csa->csa_srcid = localid; - csa->csa_dstid = peerid; csa->csa_spi.spi_protoid = prop->prop_protoid; csa->csa_esn = esn; @@ -3639,8 +4423,10 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) childsa_free(csa); goto done; } - csa->csa_encrxf = encrxf; - csa->csa_integrxf = integrxf; + if (encrxf) + csa->csa_encrid = encrxf->xform_id; + if (integrxf) + csa->csa_integrid = integrxf->xform_id; if ((csb = calloc(1, sizeof(*csb))) == NULL) { log_debug("%s: failed to get CHILD SA", __func__); @@ -3685,17 +4471,183 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) ret = 0; done: + ibuf_release(dhsecret); ibuf_release(keymat); ibuf_release(seed); return (ret); } +/* free a replaced IPCOMP SA */ +void +ikev2_ipcomp_csa_free(struct iked *env, struct iked_childsa *csa) +{ + if (csa->csa_children) + fatalx("ikev2_ipcomp_csa_free: has children"); + if (csa->csa_ikesa) + TAILQ_REMOVE(&csa->csa_ikesa->sa_childsas, csa, + csa_entry); + if (csa->csa_loaded) { + log_debug("%s: csa %p loaded: calling pfkey_sa_delete", + __func__, csa); + pfkey_sa_delete(env->sc_pfkey, csa); + RB_REMOVE(iked_activesas, &env->sc_activesas, csa); + } + childsa_free(csa); +} + +int +ikev2_ipcomp_enable(struct iked *env, struct iked_sa *sa) +{ + struct iked_childsa *other, *nother, *csa = NULL, *csb = NULL; + struct iked_flow *flow, *flowa = NULL, *flowb = NULL; + struct iked_flow *nflow, *oflow; + + if ((csa = calloc(1, sizeof(*csa))) == NULL || + (csb = calloc(1, sizeof(*csb))) == NULL || + (flowa = calloc(1, sizeof(*flowa))) == NULL || + (flowb = calloc(1, sizeof(*flowb))) == NULL) { + free(csa); + free(csb); + free(flowa); + free(flowb); + return (-1); + } + + /* switch ESP SAs to transport mode */ + TAILQ_FOREACH(other, &sa->sa_childsas, csa_entry) { + if (!other->csa_rekey && !other->csa_loaded && + other->csa_saproto == IKEV2_SAPROTO_ESP) { + other->csa_transport = 1; + if (other->csa_dir == IPSP_DIRECTION_OUT) { + other->csa_parent = csa; + csa->csa_children++; + } else { + other->csa_parent = csb; + csb->csa_children++; + } + } + } + + /* install IPCOMP SAs */ + csa->csa_ikesa = sa; + csa->csa_saproto = IKEV2_SAPROTO_IPCOMP; + csa->csa_spi.spi_size = 2; + csa->csa_spi.spi = sa->sa_cpi_out; + csa->csa_peerspi = sa->sa_cpi_in; + csa->csa_dir = IPSP_DIRECTION_OUT; + csa->csa_local = &sa->sa_local; + csa->csa_peer = &sa->sa_peer; + + memcpy(csb, csa, sizeof(*csb)); + csb->csa_spi.spi = csa->csa_peerspi; + csb->csa_peerspi = csa->csa_spi.spi; + csb->csa_dir = IPSP_DIRECTION_IN; + csb->csa_local = csa->csa_peer; + csb->csa_peer = csa->csa_local; + csb->csa_allocated = 1; + + /* remove old replaced IPCOMP SAs */ + TAILQ_FOREACH_SAFE(other, &sa->sa_childsas, csa_entry, nother) { + if (other->csa_saproto != IKEV2_SAPROTO_IPCOMP || + other->csa_children != 0) + continue; + if (other->csa_dir == csa->csa_dir && + IKED_ADDR_EQ(other->csa_local, csa->csa_local) && + IKED_ADDR_EQ(other->csa_peer, csa->csa_peer)) { + log_debug("%s: csa %p replaces %p", + __func__, csa, other); + ikev2_ipcomp_csa_free(env, other); + } else if (other->csa_dir == csb->csa_dir && + IKED_ADDR_EQ(other->csa_local, csb->csa_local) && + IKED_ADDR_EQ(other->csa_peer, csb->csa_peer)) { + log_debug("%s: csa %p replaces %p", + __func__, csb, other); + ikev2_ipcomp_csa_free(env, other); + } + } + + TAILQ_INSERT_TAIL(&sa->sa_childsas, csa, csa_entry); + TAILQ_INSERT_TAIL(&sa->sa_childsas, csb, csa_entry); + + csa->csa_peersa = csb; + csb->csa_peersa = csa; + + /* redirect flows to IPCOMP */ + /* XXX expensive? should be merged into ikev2_childsa_negotiate() */ + TAILQ_FOREACH_SAFE(flow, &sa->sa_flows, flow_entry, nflow) { + if (flow->flow_loaded || + flow->flow_saproto != IKEV2_SAPROTO_ESP) + continue; + TAILQ_FOREACH(oflow, &sa->sa_flows, flow_entry) + if (IKED_ADDR_EQ(&oflow->flow_src, &flow->flow_src) && + IKED_ADDR_EQ(&oflow->flow_dst, &flow->flow_dst) && + oflow->flow_dir == flow->flow_dir && + oflow->flow_saproto == IKEV2_SAPROTO_IPCOMP) + break; + if (oflow != NULL) { + log_debug("%s: keeping oflow %p, indentical to flow %p", + __func__, oflow, flow); + TAILQ_REMOVE(&sa->sa_flows, flow, flow_entry); + flow_free(flow); + } else { + log_debug("%s: flow %p saproto %d -> %d", __func__, + flow, flow->flow_saproto, IKEV2_SAPROTO_IPCOMP); + flow->flow_saproto = IKEV2_SAPROTO_IPCOMP; + } + } + + /* setup ESP flows for gateways */ + flowa->flow_dir = IPSP_DIRECTION_OUT; + flowa->flow_saproto = IKEV2_SAPROTO_ESP; + flowa->flow_local = &sa->sa_local; + flowa->flow_peer = &sa->sa_peer; + memcpy(&flowa->flow_src, &sa->sa_local, sizeof(sa->sa_local)); + memcpy(&flowa->flow_dst, &sa->sa_peer, sizeof(sa->sa_peer)); + socket_setport((struct sockaddr *)&flowa->flow_src.addr, 0); + socket_setport((struct sockaddr *)&flowa->flow_dst.addr, 0); + flowa->flow_src.addr_port = flowa->flow_dst.addr_port = 0; + flowa->flow_src.addr_mask = flowa->flow_dst.addr_mask = + (sa->sa_local.addr_af == AF_INET) ? 32 : 128; + flowa->flow_ikesa = sa; + + /* skip if flow already exists */ + TAILQ_FOREACH(flow, &sa->sa_flows, flow_entry) { + if (IKED_ADDR_EQ(&flow->flow_src, &flowa->flow_src) && + IKED_ADDR_EQ(&flow->flow_dst, &flowa->flow_dst) && + flow->flow_dir == flowa->flow_dir && + flow->flow_saproto == flowa->flow_saproto) { + free(flowa); + free(flowb); + goto done; + } + } + + memcpy(flowb, flowa, sizeof(*flowb)); + flowb->flow_dir = IPSP_DIRECTION_IN; + memcpy(&flowb->flow_dst, &flowa->flow_src, sizeof(flowa->flow_src)); + memcpy(&flowb->flow_src, &flowa->flow_dst, sizeof(flowa->flow_dst)); + + TAILQ_INSERT_TAIL(&sa->sa_flows, flowa, flow_entry); + TAILQ_INSERT_TAIL(&sa->sa_flows, flowb, flow_entry); + + done: + /* make sure IPCOMP CPIs are not reused */ + sa->sa_ipcomp = 0; + sa->sa_cpi_in = sa->sa_cpi_out = 0; + + return (0); +} + int ikev2_childsa_enable(struct iked *env, struct iked_sa *sa) { struct iked_childsa *csa; - struct iked_flow *flow; + struct iked_flow *flow, *oflow; + + if (sa->sa_ipcomp && sa->sa_cpi_in && sa->sa_cpi_out && + ikev2_ipcomp_enable(env, sa) == -1) + return (-1); TAILQ_FOREACH(csa, &sa->sa_childsas, csa_entry) { if (csa->csa_rekey || csa->csa_loaded) @@ -3723,6 +4675,14 @@ ikev2_childsa_enable(struct iked *env, struct iked_sa *sa) return (-1); } + if ((oflow = RB_FIND(iked_flows, &env->sc_activeflows, flow)) + != NULL) { + log_debug("%s: replaced old flow %p with %p", + __func__, oflow, flow); + oflow->flow_loaded = 0; + RB_REMOVE(iked_flows, &env->sc_activeflows, oflow); + } + RB_INSERT(iked_flows, &env->sc_activeflows, flow); log_debug("%s: loaded flow %p", __func__, flow); @@ -3732,11 +4692,11 @@ ikev2_childsa_enable(struct iked *env, struct iked_sa *sa) } int -ikev2_childsa_delete(struct iked *env, struct iked_sa *sa, u_int8_t saproto, - u_int64_t spi, u_int64_t *spiptr, int cleanup) +ikev2_childsa_delete(struct iked *env, struct iked_sa *sa, uint8_t saproto, + uint64_t spi, uint64_t *spiptr, int cleanup) { struct iked_childsa *csa, *nextcsa = NULL; - u_int64_t peerspi = 0; + uint64_t peerspi = 0; int found = 0; for (csa = TAILQ_FIRST(&sa->sa_childsas); csa != NULL; csa = nextcsa) { @@ -3779,7 +4739,7 @@ ikev2_valid_proposal(struct iked_proposal *prop, struct iked_transform **exf, struct iked_transform **ixf, int *esn) { struct iked_transform *xform, *encrxf, *integrxf; - u_int i, doesn = 0; + unsigned int i, doesn = 0; switch (prop->prop_protoid) { case IKEV2_SAPROTO_ESP: @@ -3822,19 +4782,17 @@ ikev2_valid_proposal(struct iked_proposal *prop, return (0); } -void +/* return 0 if processed, -1 if busy */ +int ikev2_acquire_sa(struct iked *env, struct iked_flow *acquire) { struct iked_flow *flow; struct iked_sa *sa; -#if defined(_OPENBSD_IPSEC_API_VERSION) struct iked_policy pol, *p = NULL; -#endif if (env->sc_passive) - return; + return (0); -#if defined(_OPENBSD_IPSEC_API_VERSION) /* First try to find an active flow with IKE SA */ flow = RB_FIND(iked_flows, &env->sc_activeflows, acquire); if (!flow) { @@ -3850,7 +4808,7 @@ ikev2_acquire_sa(struct iked *env, struct iked_flow *acquire) if ((p = policy_test(env, &pol)) == NULL) { log_warnx("%s: flow wasn't found", __func__); - return; + return (0); } log_debug("%s: found matching policy '%s'", __func__, @@ -3860,21 +4818,20 @@ ikev2_acquire_sa(struct iked *env, struct iked_flow *acquire) log_warnx("%s: failed to initiate a " "IKE_SA_INIT exchange", __func__); } else { -#else - if ((flow = acquire) != NULL) { -#endif log_debug("%s: found active flow", __func__); if ((sa = flow->flow_ikesa) == NULL) { log_warnx("%s: flow without SA", __func__); - return; + return (0); } - + if (sa->sa_stateflags & IKED_REQ_CHILDSA) + return (-1); /* busy, retry later */ if (ikev2_send_create_child_sa(env, sa, NULL, flow->flow_saproto) != 0) log_warnx("%s: failed to initiate a " "CREATE_CHILD_SA exchange", __func__); } + return (0); } void @@ -3890,7 +4847,8 @@ ikev2_disable_rekeying(struct iked *env, struct iked_sa *sa) (void)ikev2_childsa_delete(env, sa, 0, 0, NULL, 1); } -void +/* return 0 if processed, -1 if busy */ +int ikev2_rekey_sa(struct iked *env, struct iked_spi *rekey) { struct iked_childsa *csa, key; @@ -3899,51 +4857,64 @@ ikev2_rekey_sa(struct iked *env, struct iked_spi *rekey) key.csa_spi = *rekey; csa = RB_FIND(iked_activesas, &env->sc_activesas, &key); if (!csa) - return; + return (0); if (csa->csa_rekey) /* See if it's already taken care of */ - return; + return (0); + if (csa->csa_saproto == IKEV2_SAPROTO_IPCOMP) /* no rekey */ + return (0); if ((sa = csa->csa_ikesa) == NULL) { log_warnx("%s: SA %s doesn't have a parent SA", __func__, print_spi(rekey->spi, rekey->spi_size)); - return; + return (0); } if (!sa_stateok(sa, IKEV2_STATE_ESTABLISHED)) { log_warnx("%s: SA %s is not established", __func__, print_spi(rekey->spi, rekey->spi_size)); - return; + return (0); } + if (sa->sa_stateflags & IKED_REQ_CHILDSA) + return (-1); /* busy, retry later */ if (csa->csa_allocated) /* Peer SPI died first, get the local one */ rekey->spi = csa->csa_peerspi; if (ikev2_send_create_child_sa(env, sa, rekey, rekey->spi_protoid)) log_warnx("%s: failed to initiate a CREATE_CHILD_SA exchange", __func__); + return (0); } -void +/* return 0 if processed, -1 if busy */ +int ikev2_drop_sa(struct iked *env, struct iked_spi *drop) { struct ibuf *buf = NULL; struct iked_childsa *csa, key; struct iked_sa *sa; struct ikev2_delete *del; - u_int32_t spi32; + uint32_t spi32; key.csa_spi = *drop; csa = RB_FIND(iked_activesas, &env->sc_activesas, &key); if (!csa || csa->csa_rekey) - return; + return (0); + + sa = csa->csa_ikesa; + if (sa && (sa->sa_stateflags & IKED_REQ_CHILDSA)) + return (-1); /* busy, retry later */ + RB_REMOVE(iked_activesas, &env->sc_activesas, csa); csa->csa_loaded = 0; - if ((sa = csa->csa_ikesa) == NULL) { + csa->csa_rekey = 1; /* prevent re-loading */ + if (sa == NULL) { log_debug("%s: failed to find a parent SA", __func__); - return; + return (0); + } + if (csa->csa_saproto == IKEV2_SAPROTO_IPCOMP) { + /* matching Child SAs (e.g. ESP) should have expired by now */ + if (csa->csa_children == 0) + ikev2_ipcomp_csa_free(env, csa); + return (0); } - - if ((buf = ibuf_static()) == NULL) - goto done; - if ((del = ibuf_advance(buf, sizeof(*del))) == NULL) - goto done; if (csa->csa_allocated) spi32 = htobe32(csa->csa_spi.spi); @@ -3958,7 +4929,7 @@ ikev2_drop_sa(struct iked *env, struct iked_spi *drop) /* Send PAYLOAD_DELETE */ if ((buf = ibuf_static()) == NULL) - return; + return (0); if ((del = ibuf_advance(buf, sizeof(*del))) == NULL) goto done; del->del_protoid = drop->spi_protoid; @@ -3980,13 +4951,13 @@ ikev2_drop_sa(struct iked *env, struct iked_spi *drop) done: ibuf_release(buf); - return; + return (0); } int ikev2_print_id(struct iked_id *id, char *idstr, size_t idstrlen) { - u_int8_t buf[BUFSIZ], *ptr; + uint8_t buf[BUFSIZ], *ptr; struct sockaddr_in *s4; struct sockaddr_in6 *s6; char *str; @@ -4022,12 +4993,10 @@ ikev2_print_id(struct iked_id *id, char *idstr, size_t idstrlen) case IKEV2_ID_IPV4: s4 = (struct sockaddr_in *)buf; s4->sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN s4->sin_len = sizeof(*s4); -#endif memcpy(&s4->sin_addr.s_addr, ptr, len); - if (print_host((struct sockaddr_storage *)s4, + if (print_host((struct sockaddr *)s4, idstr, idstrlen) == NULL) return (-1); break; @@ -4048,12 +5017,10 @@ ikev2_print_id(struct iked_id *id, char *idstr, size_t idstrlen) case IKEV2_ID_IPV6: s6 = (struct sockaddr_in6 *)buf; s6->sin6_family = AF_INET6; -#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN s6->sin6_len = sizeof(*s6); -#endif memcpy(&s6->sin6_addr, ptr, len); - if (print_host((struct sockaddr_storage *)s6, + if (print_host((struct sockaddr *)s6, idstr, idstrlen) == NULL) return (-1); break; @@ -4076,3 +5043,144 @@ ikev2_print_id(struct iked_id *id, char *idstr, size_t idstrlen) return (0); } + +/* + * If we have an IKEV2_CP_REQUEST for IKEV2_CFG_INTERNAL_IP4_ADDRESS and + * if a network(pool) is configured, then select an address from that pool + * and remember it in the sa_addrpool attribute. + */ +int +ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa) +{ + struct iked_cfg *ikecfg = NULL; + struct iked_policy *pol = sa->sa_policy; + struct sockaddr_in *in4 = NULL, *cfg4 = NULL; + struct sockaddr_in6 *in6 = NULL, *cfg6 = NULL; + struct iked_sa key; + struct iked_addr addr; + uint32_t mask, host, lower, upper, start; + size_t i; + + if (sa->sa_addrpool || pol->pol_ncfg == 0) + return (0); + /* check for an address pool config (address w/ prefixlen != 32) */ + bzero(&addr, sizeof(addr)); + for (i = 0; i < pol->pol_ncfg; i++) { + ikecfg = &pol->pol_cfg[i]; + if (ikecfg->cfg_type == IKEV2_CFG_INTERNAL_IP4_ADDRESS && + ikecfg->cfg.address.addr_mask != 32) { + addr.addr_af = AF_INET; + break; + } + if (ikecfg->cfg_type == IKEV2_CFG_INTERNAL_IP6_ADDRESS && + ikecfg->cfg.address.addr_mask != 128) { + addr.addr_af = AF_INET6; + break; + } + } + if (i == pol->pol_ncfg) + return (0); + + /* + * failure: pool configured, but not requested. + * If we continue, we might end up with flows where 0.0.0.0 is NOT + * replaced with an address from the pool with ikev2_cp_fixaddr(). + */ + if (sa->sa_cp != IKEV2_CP_REQUEST) { + log_debug("%s: pool configured, but IKEV2_CP_REQUEST missing", + __func__); + return (-1); + } + + /* truncate prefixlen in the v6 case */ + mask = prefixlen2mask(ikecfg->cfg.address.addr_mask); + + switch (addr.addr_af) { + case AF_INET: + cfg4 = (struct sockaddr_in *)&ikecfg->cfg.address.addr; + in4 = (struct sockaddr_in *)&addr.addr; + in4->sin_family = AF_INET; + in4->sin_len = sizeof(*in4); + lower = ntohl(cfg4->sin_addr.s_addr & ~mask); + break; + case AF_INET6: + cfg6 = (struct sockaddr_in6 *)&ikecfg->cfg.address.addr; + in6 = (struct sockaddr_in6 *)&addr.addr; + in6->sin6_family = AF_INET6; + in6->sin6_len = sizeof(*in6); + lower = cfg6->sin6_addr.s6_addr[3]; + break; + default: + return (-1); + } + + if (lower == 0) + lower = 1; + /* Note that start, upper and host are in HOST byte order */ + upper = ntohl(~mask); + /* Randomly select start from [lower, upper-1] */ + start = arc4random_uniform(upper - lower) + lower; + + key.sa_addrpool = &addr; + + for (host = start;;) { + log_debug("%s: mask %x start %x lower %x host %x upper %x", + __func__, mask, start, lower, host, upper); + switch (addr.addr_af) { + case AF_INET: + in4->sin_addr.s_addr = + (cfg4->sin_addr.s_addr & mask) | htonl(host); + break; + case AF_INET6: + memcpy(in6, cfg6, sizeof(*in6)); + in6->sin6_addr.s6_addr[3] = htonl(host); + break; + } + if (!RB_FIND(iked_addrpool, &env->sc_addrpool, &key)) + break; + /* try next address */ + host++; + /* but skip broadcast and network address */ + if (host >= upper || host < lower) + host = lower; + if (host == start) + return (-1); /* exhausted */ + } + if (!key.sa_addrpool) + return (-1); /* cannot happen? */ + if ((sa->sa_addrpool = calloc(1, sizeof(addr))) == NULL) + return (-1); + memcpy(sa->sa_addrpool, &addr, sizeof(addr)); + RB_INSERT(iked_addrpool, &env->sc_addrpool, sa); + return (0); +} + +/* + * if 'addr' is 'UNSPECIFIED' replace it with sa_addrpool from + * the ip-pool and store the result in 'patched'. + */ +int +ikev2_cp_fixaddr(struct iked_sa *sa, struct iked_addr *addr, + struct iked_addr *patched) +{ + struct sockaddr_in *in4; + struct sockaddr_in6 *in6; + + if (sa->sa_addrpool == NULL || + sa->sa_addrpool->addr_af != addr->addr_af) + return (-1); + switch (addr->addr_af) { + case AF_INET: + in4 = (struct sockaddr_in *)&addr->addr; + if (in4->sin_addr.s_addr) + return (-1); + break; + case AF_INET6: + in6 = (struct sockaddr_in6 *)&addr->addr; + if (IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) + return (-1); + break; + } + memcpy(patched, sa->sa_addrpool, sizeof(*patched)); + return (0); +} diff --git a/iked/ikev2.h b/iked/ikev2.h index 439e8ab..05df987 100644 --- a/iked/ikev2.h +++ b/iked/ikev2.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.h,v 1.12 2013/03/30 16:31:37 reyk Exp $ */ +/* $OpenBSD: ikev2.h,v 1.22 2015/10/02 22:14:39 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _IKEV2_H -#define _IKEV2_H +#ifndef IKED_IKEV2_H +#define IKED_IKEV2_H #define IKEV2_VERSION 0x20 /* IKE version 2.0 */ #define IKEV1_VERSION 0x10 /* IKE version 1.0 */ @@ -32,12 +32,14 @@ #define IKEV2_STATE_COOKIE 1 /* cookie requested */ #define IKEV2_STATE_SA_INIT 2 /* init IKE SA */ #define IKEV2_STATE_EAP 3 /* EAP requested */ -#define IKEV2_STATE_AUTH_REQUEST 4 /* auth received */ -#define IKEV2_STATE_AUTH_SUCCESS 5 /* authenticated */ -#define IKEV2_STATE_VALID 6 /* validated peer certs */ -#define IKEV2_STATE_EAP_VALID 7 /* EAP validated */ -#define IKEV2_STATE_ESTABLISHED 8 /* active IKE SA */ -#define IKEV2_STATE_CLOSED 9 /* delete this SA */ +#define IKEV2_STATE_EAP_SUCCESS 4 /* EAP succeeded */ +#define IKEV2_STATE_AUTH_REQUEST 5 /* auth received */ +#define IKEV2_STATE_AUTH_SUCCESS 6 /* authenticated */ +#define IKEV2_STATE_VALID 7 /* authenticated AND validated certs */ +#define IKEV2_STATE_EAP_VALID 8 /* EAP validated */ +#define IKEV2_STATE_ESTABLISHED 9 /* active IKE SA */ +#define IKEV2_STATE_CLOSING 10 /* expect delete for this SA */ +#define IKEV2_STATE_CLOSED 11 /* delete this SA */ extern struct iked_constmap ikev2_state_map[]; @@ -71,9 +73,9 @@ extern struct iked_constmap ikev2_flag_map[]; */ struct ikev2_payload { - u_int8_t pld_nextpayload; /* Next payload type */ - u_int8_t pld_reserved; /* Contains the critical bit */ - u_int16_t pld_length; /* Payload length with header */ + uint8_t pld_nextpayload; /* Next payload type */ + uint8_t pld_reserved; /* Contains the critical bit */ + uint16_t pld_length; /* Payload length with header */ } __packed; #define IKEV2_CRITICAL_PAYLOAD 0x01 /* First bit in the reserved field */ @@ -105,13 +107,13 @@ extern struct iked_constmap ikev2_payload_map[]; */ struct ikev2_sa_proposal { - u_int8_t sap_more; /* Last proposal or more */ - u_int8_t sap_reserved; /* Must be set to zero */ - u_int16_t sap_length; /* Proposal length */ - u_int8_t sap_proposalnr; /* Proposal number */ - u_int8_t sap_protoid; /* Protocol Id */ - u_int8_t sap_spisize; /* SPI size */ - u_int8_t sap_transforms; /* Number of transforms */ + uint8_t sap_more; /* Last proposal or more */ + uint8_t sap_reserved; /* Must be set to zero */ + uint16_t sap_length; /* Proposal length */ + uint8_t sap_proposalnr; /* Proposal number */ + uint8_t sap_protoid; /* Protocol Id */ + uint8_t sap_spisize; /* SPI size */ + uint8_t sap_transforms; /* Number of transforms */ /* Followed by variable-length SPI */ /* Followed by variable-length transforms */ } __packed; @@ -125,16 +127,17 @@ struct ikev2_sa_proposal { #define IKEV2_SAPROTO_ESP 3 /* ESP */ #define IKEV2_SAPROTO_FC_ESP_HEADER 4 /* RFC4595 */ #define IKEV2_SAPROTO_FC_CT_AUTH 5 /* RFC4595 */ +#define IKEV2_SAPROTO_IPCOMP 204 /* private, should be 4 */ extern struct iked_constmap ikev2_saproto_map[]; struct ikev2_transform { - u_int8_t xfrm_more; /* Last transform or more */ - u_int8_t xfrm_reserved; /* Must be set to zero */ - u_int16_t xfrm_length; /* Transform length */ - u_int8_t xfrm_type; /* Transform type */ - u_int8_t xfrm_reserved1; /* Must be set to zero */ - u_int16_t xfrm_id; /* Transform Id */ + uint8_t xfrm_more; /* Last transform or more */ + uint8_t xfrm_reserved; /* Must be set to zero */ + uint16_t xfrm_length; /* Transform length */ + uint8_t xfrm_type; /* Transform type */ + uint8_t xfrm_reserved1; /* Must be set to zero */ + uint16_t xfrm_id; /* Transform Id */ /* Followed by variable-length transform attributes */ } __packed; @@ -177,6 +180,7 @@ extern struct iked_constmap ikev2_xformtype_map[]; #define IKEV2_XFORMENCR_CAMELLIA_CCM_8 25 /* RFC5529 */ #define IKEV2_XFORMENCR_CAMELLIA_CCM_12 26 /* RFC5529 */ #define IKEV2_XFORMENCR_CAMELLIA_CCM_16 27 /* RFC5529 */ +#define IKEV2_XFORMENCR_CHACHA20_POLY1305 28 /* RFC7634 */ extern struct iked_constmap ikev2_xformencr_map[]; @@ -239,7 +243,7 @@ extern struct iked_constmap ikev2_xformauth_map[]; #define IKEV2_XFORMDH_BRAINPOOL_P256R1 28 /* DH Group 28 */ #define IKEV2_XFORMDH_BRAINPOOL_P384R1 29 /* DH Group 29 */ #define IKEV2_XFORMDH_BRAINPOOL_P512R1 30 /* DH Group 30 */ -#define IKEV2_XFORMDH_MAX 31 +#define IKEV2_XFORMDH_X_CURVE25519 1034 /* draft-ietf-ipsecme-safecurves-00 */ extern struct iked_constmap ikev2_xformdh_map[]; @@ -249,8 +253,8 @@ extern struct iked_constmap ikev2_xformdh_map[]; extern struct iked_constmap ikev2_xformesn_map[]; struct ikev2_attribute { - u_int16_t attr_type; /* Attribute type */ - u_int16_t attr_length; /* Attribute length or value */ + uint16_t attr_type; /* Attribute type */ + uint16_t attr_length; /* Attribute length or value */ /* Followed by variable length (TLV) */ } __packed; @@ -266,8 +270,8 @@ extern struct iked_constmap ikev2_attrtype_map[]; */ struct ikev2_keyexchange { - u_int16_t kex_dhgroup; /* DH Group # */ - u_int16_t kex_reserved; /* Reserved */ + uint16_t kex_dhgroup; /* DH Group # */ + uint16_t kex_reserved; /* Reserved */ } __packed; /* @@ -275,9 +279,9 @@ struct ikev2_keyexchange { */ struct ikev2_notify { - u_int8_t n_protoid; /* Protocol Id */ - u_int8_t n_spisize; /* SPI size */ - u_int16_t n_type; /* Notify message type */ + uint8_t n_protoid; /* Protocol Id */ + uint8_t n_spisize; /* SPI size */ + uint16_t n_type; /* Notify message type */ /* Followed by variable length SPI */ /* Followed by variable length notification data */ } __packed; @@ -347,6 +351,7 @@ struct ikev2_notify { #define IKEV2_N_PSK_CONFIRM 16426 /* RFC6631 */ #define IKEV2_N_ERX_SUPPORTED 16427 /* RFC6867 */ #define IKEV2_N_IFOM_CAPABILITY 16428 /* OA3GPP */ +#define IKEV2_N_SIGNATURE_HASH_ALGORITHMS 16431 /* RFC7427 */ extern struct iked_constmap ikev2_n_map[]; @@ -355,9 +360,9 @@ extern struct iked_constmap ikev2_n_map[]; */ struct ikev2_delete { - u_int8_t del_protoid; /* Protocol Id */ - u_int8_t del_spisize; /* SPI size */ - u_int16_t del_nspi; /* Number of SPIs */ + uint8_t del_protoid; /* Protocol Id */ + uint8_t del_spisize; /* SPI size */ + uint16_t del_nspi; /* Number of SPIs */ /* Followed by variable length SPIs */ } __packed; @@ -366,8 +371,8 @@ struct ikev2_delete { */ struct ikev2_id { - u_int8_t id_type; /* Id type */ - u_int8_t id_reserved[3]; /* Reserved */ + uint8_t id_type; /* Id type */ + uint8_t id_reserved[3]; /* Reserved */ /* Followed by the identification data */ } __packed; @@ -388,7 +393,7 @@ extern struct iked_constmap ikev2_id_map[]; */ struct ikev2_cert { - u_int8_t cert_type; /* Encoding */ + uint8_t cert_type; /* Encoding */ /* Followed by the certificate data */ } __packed; @@ -414,17 +419,17 @@ extern struct iked_constmap ikev2_cert_map[]; */ struct ikev2_tsp { - u_int8_t tsp_count; /* Number of TSs */ - u_int8_t tsp_reserved[3]; /* Reserved */ + uint8_t tsp_count; /* Number of TSs */ + uint8_t tsp_reserved[3]; /* Reserved */ /* Followed by the traffic selectors */ } __packed; struct ikev2_ts { - u_int8_t ts_type; /* TS type */ - u_int8_t ts_protoid; /* Protocol Id */ - u_int16_t ts_length; /* Length */ - u_int16_t ts_startport; /* Start port */ - u_int16_t ts_endport; /* End port */ + uint8_t ts_type; /* TS type */ + uint8_t ts_protoid; /* Protocol Id */ + uint16_t ts_length; /* Length */ + uint16_t ts_startport; /* Start port */ + uint16_t ts_endport; /* End port */ } __packed; #define IKEV2_TS_IPV4_ADDR_RANGE 7 /* RFC4306 */ @@ -438,8 +443,8 @@ extern struct iked_constmap ikev2_ts_map[]; */ struct ikev2_auth { - u_int8_t auth_method; /* Signature type */ - u_int8_t auth_reserved[3]; /* Reserved */ + uint8_t auth_method; /* Signature type */ + uint8_t auth_reserved[3]; /* Reserved */ /* Followed by the signature */ } __packed; @@ -451,16 +456,28 @@ struct ikev2_auth { #define IKEV2_AUTH_ECDSA_384 10 /* RFC4754 */ #define IKEV2_AUTH_ECDSA_512 11 /* RFC4754 */ #define IKEV2_AUTH_GSPM 12 /* RFC6467 */ +#define IKEV2_AUTH_NULL 13 /* RFC7619 */ +#define IKEV2_AUTH_SIG 14 /* RFC7427 */ extern struct iked_constmap ikev2_auth_map[]; +/* Notifications used together with IKEV2_AUTH_SIG */ + +#define IKEV2_SIGHASH_RESERVED 0 /* RFC7427 */ +#define IKEV2_SIGHASH_SHA1 1 /* RFC7427 */ +#define IKEV2_SIGHASH_SHA2_256 2 /* RFC7427 */ +#define IKEV2_SIGHASH_SHA2_384 3 /* RFC7427 */ +#define IKEV2_SIGHASH_SHA2_512 4 /* RFC7427 */ + +extern struct iked_constmap ikev2_sighash_map[]; + /* * CP payload */ struct ikev2_cp { - u_int8_t cp_type; - u_int8_t cp_reserved[3]; + uint8_t cp_type; + uint8_t cp_reserved[3]; /* Followed by the attributes */ } __packed; @@ -472,8 +489,8 @@ struct ikev2_cp { extern struct iked_constmap ikev2_cp_map[]; struct ikev2_cfg { - u_int16_t cfg_type; /* first bit must be set to zero */ - u_int16_t cfg_length; + uint16_t cfg_type; /* first bit must be set to zero */ + uint16_t cfg_length; /* Followed by variable-length data */ } __packed; @@ -500,4 +517,4 @@ struct ikev2_cfg { extern struct iked_constmap ikev2_cfg_map[]; -#endif /* _IKEV2_H */ +#endif /* IKED_IKEV2_H */ diff --git a/iked/ikev2_msg.c b/iked/ikev2_msg.c index 12016c8..b03db56 100644 --- a/iked/ikev2_msg.c +++ b/iked/ikev2_msg.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2_msg.c,v 1.25 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: ikev2_msg.c,v 1.43 2015/08/21 11:59:27 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,23 +16,19 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include /* roundup */ +#include #include #include #include #include -#if defined(__OpenBSD__) -#include -#endif #include #include #include #include #include -#include #include #include #include @@ -57,8 +53,8 @@ ikev2_msg_cb(int fd, short event, void *arg) struct iked *env = sock->sock_env; struct iked_message msg; struct ike_header hdr; - u_int32_t natt = 0x00000000; - u_int8_t buf[IKED_MSGBUF_MAX]; + uint32_t natt = 0x00000000; + uint8_t buf[IKED_MSGBUF_MAX]; ssize_t len; off_t off; struct iovec iov[2]; @@ -77,8 +73,9 @@ ikev2_msg_cb(int fd, short event, void *arg) (ssize_t)sizeof(natt)) return; - if (socket_getport(&msg.msg_local) == IKED_NATT_PORT) { - if (bcmp(&natt, buf, sizeof(natt)) != 0) + if (socket_getport((struct sockaddr *)&msg.msg_local) == + IKED_NATT_PORT) { + if (memcmp(&natt, buf, sizeof(natt)) != 0) return; msg.msg_natt = 1; off = sizeof(natt); @@ -98,8 +95,8 @@ ikev2_msg_cb(int fd, short event, void *arg) iov[1].iov_base = buf; iov[1].iov_len = len; - proc_composev_imsg(env, PROC_IKEV1, IMSG_IKE_MESSAGE, -1, - iov, 2); + proc_composev_imsg(&env->sc_ps, PROC_IKEV1, -1, + IMSG_IKE_MESSAGE, -1, iov, 2); goto done; } TAILQ_INIT(&msg.msg_proposals); @@ -136,11 +133,14 @@ ikev2_msg_copy(struct iked *env, struct iked_message *msg) { struct iked_message *m = NULL; struct ibuf *buf; - ssize_t len; + size_t len; void *ptr; - if ((len = ibuf_size(msg->msg_data) - msg->msg_offset) <= 0 || - (ptr = ibuf_seek(msg->msg_data, msg->msg_offset, len)) == NULL || + if (ibuf_size(msg->msg_data) < msg->msg_offset) + return (NULL); + len = ibuf_size(msg->msg_data) - msg->msg_offset; + + if ((ptr = ibuf_seek(msg->msg_data, msg->msg_offset, len)) == NULL || (m = malloc(sizeof(*m))) == NULL || (buf = ikev2_msg_init(env, m, &msg->msg_peer, msg->msg_peerlen, &msg->msg_local, msg->msg_locallen, msg->msg_response)) == NULL || @@ -188,8 +188,22 @@ ikev2_msg_valid_ike_sa(struct iked *env, struct ike_header *oldhdr, struct iked_sa sa; #endif - if (msg->msg_sa != NULL && msg->msg_policy != NULL) + if (msg->msg_sa != NULL && msg->msg_policy != NULL) { + /* + * Only permit informational requests from initiator + * on closing SAs (for DELETE). + */ + if (msg->msg_sa->sa_state == IKEV2_STATE_CLOSING) { + if (((oldhdr->ike_flags & + (IKEV2_FLAG_INITIATOR|IKEV2_FLAG_RESPONSE)) == + IKEV2_FLAG_INITIATOR) && + (oldhdr->ike_exchange == + IKEV2_EXCHANGE_INFORMATIONAL)) + return (0); + return (-1); + } return (0); + } #if 0 /* @@ -256,8 +270,9 @@ ikev2_msg_send(struct iked *env, struct iked_message *msg) { struct iked_sa *sa = msg->msg_sa; struct ibuf *buf = msg->msg_data; - u_int32_t natt = 0x00000000; + uint32_t natt = 0x00000000; int isnatt = 0; + uint8_t exchange, flags; struct ike_header *hdr; struct iked_message *m; @@ -267,10 +282,14 @@ ikev2_msg_send(struct iked *env, struct iked_message *msg) isnatt = (msg->msg_natt || (msg->msg_sa && msg->msg_sa->sa_natt)); - log_info("%s: %s from %s to %s, %ld bytes%s", __func__, - print_map(hdr->ike_exchange, ikev2_exchange_map), - print_host(&msg->msg_local, NULL, 0), - print_host(&msg->msg_peer, NULL, 0), + exchange = hdr->ike_exchange; + flags = hdr->ike_flags; + log_info("%s: %s %s from %s to %s msgid %u, %ld bytes%s", __func__, + print_map(exchange, ikev2_exchange_map), + (flags & IKEV2_FLAG_RESPONSE) ? "response" : "request", + print_host((struct sockaddr *)&msg->msg_local, NULL, 0), + print_host((struct sockaddr *)&msg->msg_peer, NULL, 0), + betoh32(hdr->ike_msgid), ibuf_length(buf), isnatt ? ", NAT-T" : ""); if (isnatt) { @@ -294,27 +313,25 @@ ikev2_msg_send(struct iked *env, struct iked_message *msg) log_debug("%s: failed to copy a message", __func__); return (-1); } - m->msg_exchange = hdr->ike_exchange; + m->msg_exchange = exchange; - if (hdr->ike_flags & IKEV2_FLAG_RESPONSE) { + if (flags & IKEV2_FLAG_RESPONSE) { TAILQ_INSERT_TAIL(&sa->sa_responses, m, msg_entry); - timer_initialize(env, &m->msg_timer, - ikev2_msg_response_timeout, m); - timer_register(env, &m->msg_timer, IKED_RESPONSE_TIMEOUT); + timer_set(env, &m->msg_timer, ikev2_msg_response_timeout, m); + timer_add(env, &m->msg_timer, IKED_RESPONSE_TIMEOUT); } else { TAILQ_INSERT_TAIL(&sa->sa_requests, m, msg_entry); - timer_initialize(env, &m->msg_timer, - ikev2_msg_retransmit_timeout, m); - timer_register(env, &m->msg_timer, IKED_RETRANSMIT_TIMEOUT); + timer_set(env, &m->msg_timer, ikev2_msg_retransmit_timeout, m); + timer_add(env, &m->msg_timer, IKED_RETRANSMIT_TIMEOUT); } return (0); } -u_int32_t +uint32_t ikev2_msg_id(struct iked *env, struct iked_sa *sa) { - u_int32_t id = sa->sa_reqid; + uint32_t id = sa->sa_reqid; if (++sa->sa_reqid == UINT32_MAX) { /* XXX we should close and renegotiate the connection now */ @@ -328,13 +345,13 @@ ikev2_msg_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf *src) { size_t len, ivlen, encrlen, integrlen, blocklen, outlen; - u_int8_t *buf, pad = 0, *ptr; + uint8_t *buf, pad = 0, *ptr; struct ibuf *encr, *dst = NULL, *out = NULL; buf = ibuf_data(src); len = ibuf_size(src); - log_debug("%s: decrypted length %d", __func__, len); + log_debug("%s: decrypted length %zu", __func__, len); print_hex(buf, 0, len); if (sa == NULL || @@ -366,7 +383,7 @@ ikev2_msg_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf *src) if (ibuf_add(src, &pad, sizeof(pad)) != 0) goto done; - log_debug("%s: padded length %d", __func__, ibuf_size(src)); + log_debug("%s: padded length %zu", __func__, ibuf_size(src)); print_hex(ibuf_data(src), 0, ibuf_size(src)); cipher_setkey(sa->sa_encr, encr->buf, ibuf_length(encr)); @@ -389,9 +406,9 @@ ikev2_msg_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf *src) if ((ptr = ibuf_advance(dst, integrlen)) == NULL) goto done; - bzero(ptr, integrlen); + explicit_bzero(ptr, integrlen); - log_debug("%s: length %d, padding %d, output length %d", + log_debug("%s: length %zu, padding %d, output length %zu", __func__, len + sizeof(pad), pad, ibuf_size(dst)); print_hex(ibuf_data(dst), 0, ibuf_size(dst)); @@ -411,9 +428,9 @@ ikev2_msg_integr(struct iked *env, struct iked_sa *sa, struct ibuf *src) int ret = -1; size_t integrlen, tmplen; struct ibuf *integr, *tmp = NULL; - u_int8_t *ptr; + uint8_t *ptr; - log_debug("%s: message length %d", __func__, ibuf_size(src)); + log_debug("%s: message length %zu", __func__, ibuf_size(src)); print_hex(ibuf_data(src), 0, ibuf_size(src)); if (sa == NULL || @@ -429,7 +446,7 @@ ikev2_msg_integr(struct iked *env, struct iked_sa *sa, struct ibuf *src) integrlen = hash_length(sa->sa_integr); - log_debug("%s: integrity checksum length %d", __func__, + log_debug("%s: integrity checksum length %zu", __func__, integrlen); /* @@ -469,7 +486,7 @@ ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, { ssize_t ivlen, encrlen, integrlen, blocklen, outlen, tmplen; - u_int8_t pad = 0, *ptr; + uint8_t pad = 0, *ptr; struct ibuf *integr, *encr, *tmp = NULL, *out = NULL; off_t ivoff, encroff, integroff; @@ -502,11 +519,11 @@ ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, goto done; } - log_debug("%s: IV length %d", __func__, ivlen); + log_debug("%s: IV length %zd", __func__, ivlen); print_hex(ibuf_data(src), 0, ivlen); - log_debug("%s: encrypted payload length %d", __func__, encrlen); + log_debug("%s: encrypted payload length %zd", __func__, encrlen); print_hex(ibuf_data(src), encroff, encrlen); - log_debug("%s: integrity checksum length %d", __func__, integrlen); + log_debug("%s: integrity checksum length %zd", __func__, integrlen); print_hex(ibuf_data(src), integroff, integrlen); /* @@ -556,7 +573,7 @@ ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, pad = *ptr; } - log_debug("%s: decrypted payload length %d/%d padding %d", + log_debug("%s: decrypted payload length %zd/%zd padding %d", __func__, outlen, encrlen, pad); print_hex(ibuf_data(out), 0, ibuf_size(out)); @@ -574,7 +591,7 @@ ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, int ikev2_msg_send_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf **ep, - u_int8_t exchange, u_int8_t firstpayload, int response) + uint8_t exchange, uint8_t firstpayload, int response) { struct iked_message resp; struct ike_header *hdr; @@ -583,8 +600,8 @@ ikev2_msg_send_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf **ep, int ret = -1; if ((buf = ikev2_msg_init(env, &resp, &sa->sa_peer.addr, - SS_LEN(&sa->sa_peer.addr), &sa->sa_local.addr, - SS_LEN(&sa->sa_local.addr), response)) == NULL) + sa->sa_peer.addr.ss_len, &sa->sa_local.addr, + sa->sa_local.addr.ss_len, response)) == NULL) goto done; resp.msg_msgid = response ? sa->sa_msgid : ikev2_msg_id(env, sa); @@ -637,7 +654,7 @@ struct ibuf * ikev2_msg_auth(struct iked *env, struct iked_sa *sa, int response) { struct ibuf *authmsg = NULL, *nonce, *prfkey, *buf; - u_int8_t *ptr; + uint8_t *ptr; struct iked_id *id; size_t tmplen; @@ -681,7 +698,7 @@ ikev2_msg_auth(struct iked *env, struct iked_sa *sa, int response) if (tmplen != hash_length(sa->sa_prf)) goto fail; - log_debug("%s: %s auth data length %d", + log_debug("%s: %s auth data length %zu", __func__, response ? "responder" : "initiator", ibuf_size(authmsg)); print_hex(ibuf_data(authmsg), 0, ibuf_size(authmsg)); @@ -695,14 +712,14 @@ ikev2_msg_auth(struct iked *env, struct iked_sa *sa, int response) int ikev2_msg_authverify(struct iked *env, struct iked_sa *sa, - struct iked_auth *auth, u_int8_t *buf, size_t len, struct ibuf *authmsg) + struct iked_auth *auth, uint8_t *buf, size_t len, struct ibuf *authmsg) { - u_int8_t *key, *psk = NULL; + uint8_t *key, *psk = NULL; ssize_t keylen; struct iked_id *id; struct iked_dsa *dsa = NULL; int ret = -1; - u_int8_t keytype; + uint8_t keytype; if (sa->sa_hdr.sh_initiator) id = &sa->sa_rcert; @@ -739,12 +756,12 @@ ikev2_msg_authverify(struct iked *env, struct iked_sa *sa, break; } - log_debug("%s: method %s keylen %d type %s", __func__, + log_debug("%s: method %s keylen %zd type %s", __func__, print_map(auth->auth_method, ikev2_auth_map), keylen, print_map(id->id_type, ikev2_cert_map)); if (dsa_setkey(dsa, key, keylen, keytype) == NULL || - dsa_init(dsa) != 0 || + dsa_init(dsa, buf, len) != 0 || dsa_update(dsa, ibuf_data(authmsg), ibuf_size(authmsg))) { log_debug("%s: failed to compute digital signature", __func__); goto done; @@ -753,10 +770,7 @@ ikev2_msg_authverify(struct iked *env, struct iked_sa *sa, if ((ret = dsa_verify_final(dsa, buf, len)) == 0) { log_debug("%s: authentication successful", __func__); sa_state(env, sa, IKEV2_STATE_AUTH_SUCCESS); - - if (!sa->sa_policy->pol_auth.auth_eap && - auth->auth_method == IKEV2_AUTH_SHARED_KEY_MIC) - sa_state(env, sa, IKEV2_STATE_VALID); + sa_stateflags(sa, IKED_REQ_AUTHVALID); } else { log_debug("%s: authentication failed", __func__); sa_state(env, sa, IKEV2_STATE_AUTH_REQUEST); @@ -774,14 +788,14 @@ int ikev2_msg_authsign(struct iked *env, struct iked_sa *sa, struct iked_auth *auth, struct ibuf *authmsg) { - u_int8_t *key, *psk = NULL; + uint8_t *key, *psk = NULL; ssize_t keylen; struct iked_hash *prf = sa->sa_prf; struct iked_id *id; struct iked_dsa *dsa = NULL; struct ibuf *buf; int ret = -1; - u_int8_t keytype; + uint8_t keytype; if (sa->sa_hdr.sh_initiator) id = &sa->sa_icert; @@ -819,7 +833,7 @@ ikev2_msg_authsign(struct iked *env, struct iked_sa *sa, } if (dsa_setkey(dsa, key, keylen, keytype) == NULL || - dsa_init(dsa) != 0 || + dsa_init(dsa, NULL, 0) != 0 || dsa_update(dsa, ibuf_data(authmsg), ibuf_size(authmsg))) { log_debug("%s: failed to compute digital signature", __func__); goto done; @@ -905,7 +919,7 @@ ikev2_msg_dispose(struct iked *env, struct iked_msgqueue *queue, struct iked_message *msg) { TAILQ_REMOVE(queue, msg, msg_entry); - timer_deregister(env, &msg->msg_timer); + timer_del(env, &msg->msg_timer); ikev2_msg_cleanup(env, msg); free(msg); } @@ -942,11 +956,10 @@ ikev2_msg_retransmit_response(struct iked *env, struct iked_sa *sa, ibuf_size(msg->msg_data), 0, (struct sockaddr *)&msg->msg_peer, msg->msg_peerlen)) == -1) { log_warn("%s: sendto", __func__); - sa_free(env, sa); return (-1); } - timer_register(env, &msg->msg_timer, IKED_RESPONSE_TIMEOUT); + timer_add(env, &msg->msg_timer, IKED_RESPONSE_TIMEOUT); return (0); } @@ -975,10 +988,11 @@ ikev2_msg_retransmit_timeout(struct iked *env, void *arg) return; } /* Exponential timeout */ - timer_register(env, &msg->msg_timer, + timer_add(env, &msg->msg_timer, IKED_RETRANSMIT_TIMEOUT * (2 << (msg->msg_tries++))); } else { - log_debug("%s: retransmit limit reached", __func__); + log_debug("%s: retransmit limit reached for msgid %u", + __func__, msg->msg_msgid); sa_free(env, sa); } } diff --git a/iked/ikev2_pld.c b/iked/ikev2_pld.c index 9e4ed78..dff525f 100644 --- a/iked/ikev2_pld.c +++ b/iked/ikev2_pld.c @@ -1,7 +1,8 @@ -/* $OpenBSD: ikev2_pld.c,v 1.31 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: ikev2_pld.c,v 1.54 2015/10/01 13:57:29 sthen Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter + * Copyright (c) 2014 Hans-Joerg Hoexer * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,23 +17,18 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include #include #include #include #include -#if defined(__OpenBSD__) -#include -#endif #include #include #include #include #include -#include #include #include #include @@ -47,42 +43,72 @@ #include "eap.h" #include "dh.h" +int ikev2_validate_pld(struct iked_message *, size_t, size_t, + struct ikev2_payload *); int ikev2_pld_payloads(struct iked *, struct iked_message *, - off_t, size_t, u_int, int); + size_t, size_t, unsigned int); +int ikev2_validate_sa(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct ikev2_sa_proposal *); int ikev2_pld_sa(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); +int ikev2_validate_xform(struct iked_message *, size_t, size_t, + struct ikev2_transform *); int ikev2_pld_xform(struct iked *, struct ikev2_sa_proposal *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); +int ikev2_validate_attr(struct iked_message *, size_t, size_t, + struct ikev2_attribute *); int ikev2_pld_attr(struct iked *, struct ikev2_transform *, - struct iked_message *, off_t, int); + struct iked_message *, size_t, size_t); +int ikev2_validate_ke(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct ikev2_keyexchange *); int ikev2_pld_ke(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); +int ikev2_validate_id(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct ikev2_id *); int ikev2_pld_id(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t, u_int); + struct iked_message *, size_t, size_t, unsigned int); +int ikev2_validate_cert(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct ikev2_cert *); int ikev2_pld_cert(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); +int ikev2_validate_certreq(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct ikev2_cert *); int ikev2_pld_certreq(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); +int ikev2_validate_nonce(struct iked_message *, size_t, size_t, + struct ikev2_payload *); int ikev2_pld_nonce(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); +int ikev2_validate_notify(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct ikev2_notify *); int ikev2_pld_notify(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); +int ikev2_validate_delete(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct ikev2_delete *); int ikev2_pld_delete(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); +int ikev2_validate_ts(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct ikev2_tsp *); int ikev2_pld_ts(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t, u_int); + struct iked_message *, size_t, size_t, unsigned int); +int ikev2_validate_auth(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct ikev2_auth *); int ikev2_pld_auth(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); int ikev2_pld_e(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t); +int ikev2_validate_cp(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct ikev2_cp *); int ikev2_pld_cp(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); +int ikev2_validate_eap(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct eap_header *); int ikev2_pld_eap(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); int ikev2_pld_parse(struct iked *env, struct ike_header *hdr, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset) { log_debug("%s: header ispi %s rspi %s" " nextpayload %s version 0x%02x exchange %s flags 0x%02x" @@ -105,94 +131,130 @@ ikev2_pld_parse(struct iked *env, struct ike_header *hdr, offset += sizeof(*hdr); return (ikev2_pld_payloads(env, msg, offset, - betoh32(hdr->ike_length), hdr->ike_nextpayload, 0)); + betoh32(hdr->ike_length), hdr->ike_nextpayload)); +} + +int +ikev2_validate_pld(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld) +{ + uint8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + /* We need at least the generic header. */ + if (left < sizeof(*pld)) { + log_debug("%s: malformed payload: too short for generic " + "header (%zu < %zu)", __func__, left, sizeof(*pld)); + return (-1); + } + memcpy(pld, msgbuf + offset, sizeof(*pld)); + + /* + * We need at least the specified number of bytes. + * pld_length is the full size of the payload including + * the generic payload header. + */ + pld_length = betoh16(pld->pld_length); + if (left < pld_length) { + log_debug("%s: malformed payload: shorter than specified " + "(%zu < %zu)", __func__, left, pld_length); + return (-1); + } + /* + * Sanity check the specified payload size, it must + * be at last the size of the generic payload header. + */ + if (pld_length < sizeof(*pld)) { + log_debug("%s: malformed payload: shorter than minimum " + "header size (%zu < %zu)", __func__, pld_length, + sizeof(*pld)); + return (-1); + } + + return (0); } int ikev2_pld_payloads(struct iked *env, struct iked_message *msg, - off_t offset, size_t length, u_int payload, int quick) + size_t offset, size_t length, unsigned int payload) { struct ikev2_payload pld; - u_int e; + unsigned int e; int ret; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); + size_t left; /* Check if message was decrypted in an E payload */ e = msg->msg_e ? IKED_E : 0; - if (quick) - print_debug("%s: %spayloads", __func__, - e ? "decrypted " : ""); - else - ikev2_pld_payloads(env, msg, offset, length, payload, 1); + while (payload != 0 && offset < length) { + /* Bytes left in datagram. */ + left = length - offset; - while (payload != 0 && offset < (off_t)length) { - memcpy(&pld, msgbuf + offset, sizeof(pld)); + if (ikev2_validate_pld(msg, offset, left, &pld)) + return (-1); - if (quick) - print_debug(" %s", - print_map(payload, ikev2_payload_map)); - else - log_debug("%s: %spayload %s" - " nextpayload %s critical 0x%02x length %d", - __func__, e ? "decrypted " : "", - print_map(payload, ikev2_payload_map), - print_map(pld.pld_nextpayload, ikev2_payload_map), - pld.pld_reserved & IKEV2_CRITICAL_PAYLOAD, - betoh16(pld.pld_length)); + log_debug("%s: %spayload %s" + " nextpayload %s critical 0x%02x length %d", + __func__, e ? "decrypted " : "", + print_map(payload, ikev2_payload_map), + print_map(pld.pld_nextpayload, ikev2_payload_map), + pld.pld_reserved & IKEV2_CRITICAL_PAYLOAD, + betoh16(pld.pld_length)); + /* Skip over generic payload header. */ offset += sizeof(pld); + left -= sizeof(pld); ret = 0; - if (quick) - goto next; - switch (payload | e) { case IKEV2_PAYLOAD_SA: case IKEV2_PAYLOAD_SA | IKED_E: - ret = ikev2_pld_sa(env, &pld, msg, offset); + ret = ikev2_pld_sa(env, &pld, msg, offset, left); break; case IKEV2_PAYLOAD_KE: case IKEV2_PAYLOAD_KE | IKED_E: - ret = ikev2_pld_ke(env, &pld, msg, offset); + ret = ikev2_pld_ke(env, &pld, msg, offset, left); break; case IKEV2_PAYLOAD_IDi | IKED_E: case IKEV2_PAYLOAD_IDr | IKED_E: - ret = ikev2_pld_id(env, &pld, msg, offset, payload); + ret = ikev2_pld_id(env, &pld, msg, offset, left, + payload); break; case IKEV2_PAYLOAD_CERT | IKED_E: - ret = ikev2_pld_cert(env, &pld, msg, offset); + ret = ikev2_pld_cert(env, &pld, msg, offset, left); break; case IKEV2_PAYLOAD_CERTREQ: case IKEV2_PAYLOAD_CERTREQ | IKED_E: - ret = ikev2_pld_certreq(env, &pld, msg, offset); + ret = ikev2_pld_certreq(env, &pld, msg, offset, left); break; case IKEV2_PAYLOAD_AUTH | IKED_E: - ret = ikev2_pld_auth(env, &pld, msg, offset); + ret = ikev2_pld_auth(env, &pld, msg, offset, left); break; case IKEV2_PAYLOAD_NONCE: case IKEV2_PAYLOAD_NONCE | IKED_E: - ret = ikev2_pld_nonce(env, &pld, msg, offset); + ret = ikev2_pld_nonce(env, &pld, msg, offset, left); break; case IKEV2_PAYLOAD_NOTIFY: case IKEV2_PAYLOAD_NOTIFY | IKED_E: - ret = ikev2_pld_notify(env, &pld, msg, offset); + ret = ikev2_pld_notify(env, &pld, msg, offset, left); break; case IKEV2_PAYLOAD_DELETE | IKED_E: - ret = ikev2_pld_delete(env, &pld, msg, offset); + ret = ikev2_pld_delete(env, &pld, msg, offset, left); break; case IKEV2_PAYLOAD_TSi | IKED_E: case IKEV2_PAYLOAD_TSr | IKED_E: - ret = ikev2_pld_ts(env, &pld, msg, offset, payload); + ret = ikev2_pld_ts(env, &pld, msg, offset, left, + payload); break; case IKEV2_PAYLOAD_SK: ret = ikev2_pld_e(env, &pld, msg, offset); break; case IKEV2_PAYLOAD_CP | IKED_E: - ret = ikev2_pld_cp(env, &pld, msg, offset); + ret = ikev2_pld_cp(env, &pld, msg, offset, left); break; case IKEV2_PAYLOAD_EAP | IKED_E: - ret = ikev2_pld_eap(env, &pld, msg, offset); + ret = ikev2_pld_eap(env, &pld, msg, offset, left); break; default: print_hex(msgbuf, offset, @@ -209,34 +271,128 @@ ikev2_pld_payloads(struct iked *env, struct iked_message *msg, if (payload == IKEV2_PAYLOAD_SK) return (0); - next: payload = pld.pld_nextpayload; offset += betoh16(pld.pld_length) - sizeof(pld); } - if (quick) - print_debug("\n"); + return (0); +} + +int +ikev2_validate_sa(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct ikev2_sa_proposal *sap) +{ + uint8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length, sap_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*sap)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*sap)); + return (-1); + } + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*sap)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*sap)); + return (-1); + } + memcpy(sap, msgbuf + offset, sizeof(*sap)); + + sap_length = betoh16(sap->sap_length); + if (sap_length < sizeof(*sap)) { + log_debug("%s: malformed payload: shorter than minimum header " + "size (%zu < %zu)", __func__, sap_length, sizeof(*sap)); + return (-1); + } + if (left < sap_length) { + log_debug("%s: malformed payload: too long for actual payload " + "size (%zu < %zu)", __func__, left, sap_length); + return (-1); + } + /* + * NB: There might be more proposals, we parse only the first one. + * This condition must never be true. + */ + if (pld_length - sizeof(*pld) < sap_length) { + log_debug("%s: payload malformed: SA payload length mismatches " + "proposal substructure length (%lu < %zu)", __func__, + pld_length - sizeof(*pld), sap_length); + return (-1); + } + /* + * If there is only one proposal, sap_length must be the + * total payload size. + */ + if (!sap->sap_more && ((pld_length - sizeof(*pld)) != sap_length)) { + log_debug("%s: payload malformed: SA payload length mismatches " + "single proposal substructure length (%lu != %zu)", + __func__, pld_length - sizeof(*pld), sap_length); + return (-1); + } + /* + * If there are more than one proposal, there must be bytes + * left in the payload. + */ + if (sap->sap_more && ((pld_length - sizeof(*pld)) <= sap_length)) { + log_debug("%s: payload malformed: SA payload too small for " + "further proposals (%zu <= %zu)", __func__, + pld_length - sizeof(*pld), sap_length); + return (-1); + } return (0); } +/* + * NB: This function parses both the SA header and the first proposal. + * Additional proposals are ignored. + */ int ikev2_pld_sa(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t left) { struct ikev2_sa_proposal sap; struct iked_proposal *prop = NULL; - u_int32_t spi32; - u_int64_t spi = 0, spi64; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint32_t spi32; + uint64_t spi = 0, spi64; + uint8_t *msgbuf = ibuf_data(msg->msg_data); struct iked_proposals *props; + size_t total; + + if (ikev2_validate_sa(msg, offset, left, pld, &sap)) + return (-1); + + if (sap.sap_more) + log_debug("%s: more than one proposal specified", __func__); + + /* Assumed size of the first proposals, including SPI if present. */ + total = (betoh16(sap.sap_length) - sizeof(sap)); props = &msg->msg_parent->msg_proposals; - memcpy(&sap, msgbuf + offset, sizeof(sap)); offset += sizeof(sap); + left -= sizeof(sap); if (sap.sap_spisize) { + if (left < sap.sap_spisize) { + log_debug("%s: malformed payload: SPI larger than " + "actual payload (%zu < %d)", __func__, left, + sap.sap_spisize); + return (-1); + } + if (total < sap.sap_spisize) { + log_debug("%s: malformed payload: SPI larger than " + "proposal (%zu < %d)", __func__, total, + sap.sap_spisize); + return (-1); + } + if (total < sap.sap_spisize) { + log_debug("%s: malformed payload: SPI too large " + "(%zu < %d)", __func__, total, sap.sap_spisize); + return (-1); + } switch (sap.sap_spisize) { case 4: memcpy(&spi32, msgbuf + offset, 4); @@ -253,6 +409,20 @@ ikev2_pld_sa(struct iked *env, struct ikev2_payload *pld, } offset += sap.sap_spisize; + left -= sap.sap_spisize; + + /* Assumed size of the proposal, now without SPI. */ + total -= sap.sap_spisize; + } + + /* + * As we verified sanity of packet headers, this check will + * be always false, but just to be sure we keep it. + */ + if (left < total) { + log_debug("%s: payload malformed: too long for payload " + "(%zu < %zu)", __func__, left, total); + return (-1); } log_debug("%s: more %d reserved %d length %d" @@ -281,7 +451,7 @@ ikev2_pld_sa(struct iked *env, struct ikev2_payload *pld, * Parse the attached transforms */ if (sap.sap_transforms && - ikev2_pld_xform(env, &sap, msg, offset) != 0) { + ikev2_pld_xform(env, &sap, msg, offset, total) != 0) { log_debug("%s: invalid proposal transforms", __func__); return (-1); } @@ -289,15 +459,48 @@ ikev2_pld_sa(struct iked *env, struct ikev2_payload *pld, return (0); } +int +ikev2_validate_xform(struct iked_message *msg, size_t offset, size_t total, + struct ikev2_transform *xfrm) +{ + uint8_t *msgbuf = ibuf_data(msg->msg_data); + size_t xfrm_length; + + if (total < sizeof(*xfrm)) { + log_debug("%s: payload malformed: too short for header " + "(%zu < %zu)", __func__, total, sizeof(*xfrm)); + return (-1); + } + memcpy(xfrm, msgbuf + offset, sizeof(*xfrm)); + + xfrm_length = betoh16(xfrm->xfrm_length); + if (xfrm_length < sizeof(*xfrm)) { + log_debug("%s: payload malformed: shorter than minimal header " + "(%zu < %zu)", __func__, xfrm_length, sizeof(*xfrm)); + return (-1); + } + if (total < xfrm_length) { + log_debug("%s: malformed payload: too long for payload size " + "(%zu < %zu)", __func__, total, xfrm_length); + return (-1); + } + + return (0); +} + int ikev2_pld_xform(struct iked *env, struct ikev2_sa_proposal *sap, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t total) { struct ikev2_transform xfrm; char id[BUFSIZ]; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + int ret = 0; + size_t xfrm_length; - memcpy(&xfrm, msgbuf + offset, sizeof(xfrm)); + if (ikev2_validate_xform(msg, offset, total, &xfrm)) + return (-1); + + xfrm_length = betoh16(xfrm.xfrm_length); switch (xfrm.xfrm_type) { case IKEV2_XFORMTYPE_ENCR: @@ -325,19 +528,21 @@ ikev2_pld_xform(struct iked *env, struct ikev2_sa_proposal *sap, break; } - log_debug("%s: more %d reserved %d length %d" + log_debug("%s: more %d reserved %d length %zu" " type %s id %s", - __func__, xfrm.xfrm_more, xfrm.xfrm_reserved, - betoh16(xfrm.xfrm_length), + __func__, xfrm.xfrm_more, xfrm.xfrm_reserved, xfrm_length, print_map(xfrm.xfrm_type, ikev2_xformtype_map), id); /* * Parse transform attributes, if available */ msg->msg_attrlength = 0; - if ((u_int)betoh16(xfrm.xfrm_length) > sizeof(xfrm)) - ikev2_pld_attr(env, &xfrm, msg, offset + sizeof(xfrm), - betoh16(xfrm.xfrm_length) - sizeof(xfrm)); + if (xfrm_length > sizeof(xfrm)) { + if (ikev2_pld_attr(env, &xfrm, msg, offset + sizeof(xfrm), + xfrm_length - sizeof(xfrm)) != 0) { + return (-1); + } + } if (ikev2_msg_frompeer(msg)) { if (config_add_transform(msg->msg_parent->msg_prop, @@ -349,26 +554,52 @@ ikev2_pld_xform(struct iked *env, struct ikev2_sa_proposal *sap, } /* Next transform */ - offset += betoh16(xfrm.xfrm_length); + offset += xfrm_length; + total -= xfrm_length; if (xfrm.xfrm_more == IKEV2_XFORM_MORE) - ikev2_pld_xform(env, sap, msg, offset); + ret = ikev2_pld_xform(env, sap, msg, offset, total); + else if (total != 0) { + /* No more transforms but still some data left. */ + log_debug("%s: less data than specified, %zu bytes left", + __func__, total); + ret = -1; + } + + return (ret); +} + +int +ikev2_validate_attr(struct iked_message *msg, size_t offset, size_t total, + struct ikev2_attribute *attr) +{ + uint8_t *msgbuf = ibuf_data(msg->msg_data); + + if (total < sizeof(*attr)) { + log_debug("%s: payload malformed: too short for header " + "(%zu < %zu)", __func__, total, sizeof(*attr)); + return (-1); + } + memcpy(attr, msgbuf + offset, sizeof(*attr)); return (0); } int ikev2_pld_attr(struct iked *env, struct ikev2_transform *xfrm, - struct iked_message *msg, off_t offset, int total) + struct iked_message *msg, size_t offset, size_t total) { struct ikev2_attribute attr; - u_int type; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + unsigned int type; + uint8_t *msgbuf = ibuf_data(msg->msg_data); + int ret = 0; + size_t attr_length; - memcpy(&attr, msgbuf + offset, sizeof(attr)); + if (ikev2_validate_attr(msg, offset, total, &attr)) + return (-1); type = betoh16(attr.attr_type) & ~IKEV2_ATTRAF_TV; - log_debug("%s: attribute type %s length %d total %d", + log_debug("%s: attribute type %s length %d total %zu", __func__, print_map(type, ikev2_attrtype_map), betoh16(attr.attr_length), total); @@ -381,30 +612,70 @@ ikev2_pld_attr(struct iked *env, struct ikev2_transform *xfrm, msg->msg_attrlength = betoh16(attr.attr_length); } else { /* Type-Length-Value attribute */ + attr_length = betoh16(attr.attr_length); + if (attr_length < sizeof(attr)) { + log_debug("%s: payload malformed: shorter than " + "minimal header (%zu < %zu)", __func__, + attr_length, sizeof(attr)); + return (-1); + } + if (total < attr_length) { + log_debug("%s: payload malformed: attribute larger " + "than actual payload (%zu < %zu)", __func__, + total, attr_length); + return (-1); + } print_hex(msgbuf, offset + sizeof(attr), - betoh16(attr.attr_length) - sizeof(attr)); - offset += betoh16(attr.attr_length); - total -= betoh16(attr.attr_length); + attr_length - sizeof(attr)); + offset += attr_length; + total -= attr_length; } if (total > 0) { /* Next attribute */ - ikev2_pld_attr(env, xfrm, msg, offset, total); + ret = ikev2_pld_attr(env, xfrm, msg, offset, total); + } + + return (ret); +} + +int +ikev2_validate_ke(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct ikev2_keyexchange *kex) +{ + uint8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*kex)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*kex)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*kex)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*kex)); + return (-1); } + memcpy(kex, msgbuf + offset, sizeof(*kex)); return (0); } int ikev2_pld_ke(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t left) { struct ikev2_keyexchange kex; - u_int8_t *buf; + uint8_t *buf; size_t len; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); - memcpy(&kex, msgbuf + offset, sizeof(kex)); + if (ikev2_validate_ke(msg, offset, left, pld, &kex)) + return (-1); log_debug("%s: dh group %s reserved %d", __func__, print_map(betoh16(kex.kex_dhgroup), ikev2_xformdh_map), @@ -413,6 +684,17 @@ ikev2_pld_ke(struct iked *env, struct ikev2_payload *pld, buf = msgbuf + offset + sizeof(kex); len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(kex); + if (len == 0) { + log_debug("%s: malformed payload: no KE data given", __func__); + return (-1); + } + /* This will actually be caught by earlier checks. */ + if (left < len) { + log_debug("%s: malformed payload: smaller than specified " + "(%zu < %zu)", __func__, left, len); + return (-1); + } + print_hex(buf, 0, len); if (ikev2_msg_frompeer(msg)) { @@ -426,19 +708,47 @@ ikev2_pld_ke(struct iked *env, struct ikev2_payload *pld, return (0); } +int +ikev2_validate_id(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct ikev2_id *id) +{ + uint8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*id)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*id)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*id)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*id)); + return (-1); + } + memcpy(id, msgbuf + offset, sizeof(*id)); + + return (0); +} + int ikev2_pld_id(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset, u_int payload) + struct iked_message *msg, size_t offset, size_t left, unsigned int payload) { - u_int8_t *ptr; + uint8_t *ptr; struct ikev2_id id; size_t len; struct iked_id *idp, idb; struct iked_sa *sa = msg->msg_sa; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); char idstr[IKED_ID_SIZE]; - memcpy(&id, msgbuf + offset, sizeof(id)); + if (ikev2_validate_id(msg, offset, left, pld, &id)) + return (-1); + bzero(&idb, sizeof(idb)); /* Don't strip the Id payload header */ @@ -455,7 +765,7 @@ ikev2_pld_id(struct iked *env, struct ikev2_payload *pld, return (-1); } - log_debug("%s: id %s length %d", __func__, idstr, len); + log_debug("%s: id %s length %zu", __func__, idstr, len); if (!ikev2_msg_frompeer(msg)) { ibuf_release(idb.id_buf); @@ -481,23 +791,50 @@ ikev2_pld_id(struct iked *env, struct ikev2_payload *pld, return (0); } +int +ikev2_validate_cert(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct ikev2_cert *cert) +{ + uint8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*cert)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*cert)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*cert)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*cert)); + return (-1); + } + memcpy(cert, msgbuf + offset, sizeof(*cert)); + + return (0); +} + int ikev2_pld_cert(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t left) { struct ikev2_cert cert; - u_int8_t *buf; + uint8_t *buf; size_t len; struct iked_id *certid; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); - memcpy(&cert, msgbuf + offset, sizeof(cert)); + if (ikev2_validate_cert(msg, offset, left, pld, &cert)) + return (-1); offset += sizeof(cert); buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(cert); - log_debug("%s: type %s length %d", + log_debug("%s: type %s length %zu", __func__, print_map(cert.cert_type, ikev2_cert_map), len); print_hex(buf, 0, len); @@ -521,32 +858,70 @@ ikev2_pld_cert(struct iked *env, struct ikev2_payload *pld, return (0); } +int +ikev2_validate_certreq(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct ikev2_cert *cert) +{ + uint8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*cert)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*cert)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*cert)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*cert)); + return (-1); + } + memcpy(cert, msgbuf + offset, sizeof(*cert)); + + return (0); +} + int ikev2_pld_certreq(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t left) { struct iked_sa *sa = msg->msg_sa; struct ikev2_cert cert; - u_int8_t *buf; - size_t len; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *buf; + ssize_t len; + uint8_t *msgbuf = ibuf_data(msg->msg_data); - memcpy(&cert, msgbuf + offset, sizeof(cert)); + if (ikev2_validate_certreq(msg, offset, left, pld, &cert)) + return (-1); offset += sizeof(cert); buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(cert); - log_debug("%s: type %s signatures length %d", + log_debug("%s: type %s length %zd", __func__, print_map(cert.cert_type, ikev2_cert_map), len); + + /* This will actually be caught by earlier checks. */ + if (len < 0) { + log_debug("%s: invalid certificate request length", __func__); + return (-1); + } + print_hex(buf, 0, len); if (!ikev2_msg_frompeer(msg)) return (0); - if (!len || (len % SHA_DIGEST_LENGTH) != 0) { - log_debug("%s: invalid certificate request", __func__); - return (-1); + if (cert.cert_type == IKEV2_CERT_X509_CERT) { + if (!len) + return (0); + if ((len % SHA_DIGEST_LENGTH) != 0) { + log_debug("%s: invalid certificate request", __func__); + return (-1); + } } if (msg->msg_sa == NULL) @@ -558,30 +933,57 @@ ikev2_pld_certreq(struct iked *env, struct ikev2_payload *pld, else sa->sa_statevalid |= IKED_REQ_CERT; - ca_setreq(env, &sa->sa_hdr, &sa->sa_policy->pol_localid, + ca_setreq(env, sa, &sa->sa_policy->pol_localid, cert.cert_type, buf, len, PROC_CERT); return (0); } +int +ikev2_validate_auth(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct ikev2_auth *auth) +{ + uint8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*auth)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*auth)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*auth)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*auth)); + return (-1); + } + memcpy(auth, msgbuf + offset, sizeof(*auth)); + + return (0); +} + int ikev2_pld_auth(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t left) { struct ikev2_auth auth; struct iked_id *idp; - u_int8_t *buf; + uint8_t *buf; size_t len; struct iked_sa *sa = msg->msg_sa; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); - memcpy(&auth, msgbuf + offset, sizeof(auth)); + if (ikev2_validate_auth(msg, offset, left, pld, &auth)) + return (-1); offset += sizeof(auth); buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(auth); - log_debug("%s: method %s length %d", + log_debug("%s: method %s length %zu", __func__, print_map(auth.auth_method, ikev2_auth_map), len); print_hex(buf, 0, len); @@ -608,16 +1010,49 @@ ikev2_pld_auth(struct iked *env, struct ikev2_payload *pld, return (0); } +int +ikev2_validate_nonce(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld) +{ + size_t pld_length; + + /* This will actually be caught by earlier checks. */ + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld)); + return (-1); + } + + return (0); +} + int ikev2_pld_nonce(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t left) { size_t len; - u_int8_t *buf; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *buf; + uint8_t *msgbuf = ibuf_data(msg->msg_data); + + if (ikev2_validate_nonce(msg, offset, left, pld)) + return (-1); buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld); + + if (len == 0) { + log_debug("%s: malformed payload: no NONCE given", __func__); + return (-1); + } + /* This will actually be caught by earlier checks. */ + if (left < len) { + log_debug("%s: malformed payload: smaller than specified " + "(%zu < %zu)", __func__, left, len); + return (-1); + } + print_hex(buf, 0, len); if (ikev2_msg_frompeer(msg)) { @@ -632,30 +1067,59 @@ ikev2_pld_nonce(struct iked *env, struct ikev2_payload *pld, return (0); } +int +ikev2_validate_notify(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct ikev2_notify *n) +{ + uint8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*n)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*n)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*n)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*n)); + return (-1); + } + memcpy(n, msgbuf + offset, sizeof(*n)); + + return (0); +} + int ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t left) { - struct ikev2_notify *n; - u_int8_t *buf, md[SHA_DIGEST_LENGTH]; + struct ikev2_notify n; + uint8_t *buf, md[SHA_DIGEST_LENGTH]; size_t len; - u_int32_t spi32; - u_int64_t spi64; + uint32_t spi32; + uint64_t spi64; struct iked_spi *rekey; - u_int16_t type; - u_int16_t group; + uint16_t type; + uint16_t group; + uint16_t cpi; + uint16_t signature_hash; + uint8_t transform; - if ((n = ibuf_seek(msg->msg_data, offset, sizeof(*n))) == NULL) + if (ikev2_validate_notify(msg, offset, left, pld, &n)) return (-1); - type = betoh16(n->n_type); + type = betoh16(n.n_type); log_debug("%s: protoid %s spisize %d type %s", __func__, - print_map(n->n_protoid, ikev2_saproto_map), n->n_spisize, + print_map(n.n_protoid, ikev2_saproto_map), n.n_spisize, print_map(type, ikev2_n_map)); - len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(*n); - if ((buf = ibuf_seek(msg->msg_data, offset + sizeof(*n), len)) == NULL) + len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(n); + if ((buf = ibuf_seek(msg->msg_data, offset + sizeof(n), len)) == NULL) return (-1); print_hex(buf, 0, len); @@ -666,9 +1130,14 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, switch (type) { case IKEV2_N_NAT_DETECTION_SOURCE_IP: case IKEV2_N_NAT_DETECTION_DESTINATION_IP: + if (len != sizeof(md)) { + log_debug("%s: malformed payload: hash size mismatch" + " (%zu != %zu)", __func__, len, sizeof(md)); + return (-1); + } if (ikev2_nat_detection(env, msg, md, sizeof(md), type) == -1) return (-1); - if (len != sizeof(md) || memcmp(buf, md, len) != 0) { + if (memcmp(buf, md, len) != 0) { log_debug("%s: %s detected NAT, enabling " "UDP encapsulation", __func__, print_map(type, ikev2_n_map)); @@ -683,13 +1152,21 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, print_hex(md, 0, sizeof(md)); break; case IKEV2_N_INVALID_KE_PAYLOAD: + if (sa_stateok(msg->msg_sa, IKEV2_STATE_VALID) && + !msg->msg_e) { + log_debug("%s: INVALID_KE_PAYLOAD not encrypted", + __func__); + return (-1); + } if (len != sizeof(group)) { - log_debug("%s: malformed notification", __func__); + log_debug("%s: malformed payload: group size mismatch" + " (%zu != %zu)", __func__, len, sizeof(group)); return (-1); } + /* XXX chould also happen for PFS */ if (!msg->msg_sa->sa_hdr.sh_initiator) { log_debug("%s: not an initiator", __func__); - sa_free(env, msg->msg_sa); + sa_state(env, msg->msg_sa, IKEV2_STATE_CLOSED); msg->msg_sa = NULL; return (-1); } @@ -703,13 +1180,21 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, } log_debug("%s: responder selected DH group %d", __func__, group); - sa_free(env, msg->msg_sa); + sa_state(env, msg->msg_sa, IKEV2_STATE_CLOSED); msg->msg_sa = NULL; - timer_initialize(env, &env->sc_inittmr, ikev2_init_ike_sa, - NULL); - timer_register(env, &env->sc_inittmr, IKED_INITIATOR_INITIAL); + + /* + * XXX should also happen for PFS so we have to check state. + */ + timer_set(env, &env->sc_inittmr, ikev2_init_ike_sa, NULL); + timer_add(env, &env->sc_inittmr, IKED_INITIATOR_INITIAL); break; case IKEV2_N_NO_ADDITIONAL_SAS: + if (!msg->msg_e) { + log_debug("%s: NO_ADDITIONAL_SAS not encrypted", + __func__); + return (-1); + } /* This makes sense for Child SAs only atm */ if (msg->msg_sa->sa_stateflags & IKED_REQ_CHILDSA) { ikev2_disable_rekeying(env, msg->msg_sa); @@ -717,7 +1202,11 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, } break; case IKEV2_N_REKEY_SA: - if (len != n->n_spisize) { + if (!msg->msg_e) { + log_debug("%s: N_REKEY_SA not encrypted", __func__); + return (-1); + } + if (len != n.n_spisize) { log_debug("%s: malformed notification", __func__); return (-1); } @@ -727,7 +1216,7 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, __func__); return (-1); } - switch (n->n_spisize) { + switch (n.n_spisize) { case 4: memcpy(&spi32, buf, len); rekey->spi = betoh32(spi32); @@ -738,55 +1227,130 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, break; default: log_debug("%s: invalid spi size %d", __func__, - n->n_spisize); + n.n_spisize); return (-1); } - rekey->spi_size = n->n_spisize; - rekey->spi_protoid = n->n_protoid; + rekey->spi_size = n.n_spisize; + rekey->spi_protoid = n.n_protoid; log_debug("%s: rekey %s spi %s", __func__, - print_map(n->n_protoid, ikev2_saproto_map), - print_spi(rekey->spi, n->n_spisize)); + print_map(n.n_protoid, ikev2_saproto_map), + print_spi(rekey->spi, n.n_spisize)); + break; + case IKEV2_N_IPCOMP_SUPPORTED: + if (!msg->msg_e) { + log_debug("%s: N_IPCOMP_SUPPORTED not encrypted", + __func__); + return (-1); + } + if (len < sizeof(cpi) + sizeof(transform)) { + log_debug("%s: ignoring malformed ipcomp notification", + __func__); + return (0); + } + memcpy(&cpi, buf, sizeof(cpi)); + memcpy(&transform, buf + sizeof(cpi), sizeof(transform)); + log_debug("%s: cpi 0x%x, transform %s, len %zu", __func__, + betoh16(cpi), print_map(transform, ikev2_ipcomp_map), len); + /* we only support deflate */ + if ((msg->msg_policy->pol_flags & IKED_POLICY_IPCOMP) && + (transform == IKEV2_IPCOMP_DEFLATE)) { + msg->msg_sa->sa_ipcomp = transform; + msg->msg_sa->sa_cpi_out = betoh16(cpi); + } + break; + case IKEV2_N_SIGNATURE_HASH_ALGORITHMS: + if (msg->msg_e) { + log_debug("%s: SIGNATURE_HASH_ALGORITHMS: encrypted", + __func__); + return (-1); + } + if (msg->msg_sa == NULL || + msg->msg_sa->sa_sigsha2) { + log_debug("%s: SIGNATURE_HASH_ALGORITHMS: no SA or " + "duplicate notify", __func__); + return (-1); + } + if (len < sizeof(signature_hash) || + len % sizeof(signature_hash)) { + log_debug("%s: malformed signature hash notification" + "(%zu bytes)", __func__, len); + return (0); + } + while (len >= sizeof(signature_hash)) { + memcpy(&signature_hash, buf, sizeof(signature_hash)); + signature_hash = betoh16(signature_hash); + log_debug("%s: signature hash %s (%x)", __func__, + print_map(signature_hash, ikev2_sighash_map), + signature_hash); + len -= sizeof(signature_hash); + buf += sizeof(signature_hash); + if (signature_hash == IKEV2_SIGHASH_SHA2_256) + msg->msg_sa->sa_sigsha2 = 1; + } break; } return (0); } +int +ikev2_validate_delete(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct ikev2_delete *del) +{ + uint8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*del)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*del)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*del)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*del)); + return (-1); + } + memcpy(del, msgbuf + offset, sizeof(*del)); + + return (0); +} + int ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t left) { struct iked_childsa **peersas = NULL; struct iked_sa *sa = msg->msg_sa; - struct ikev2_delete *del, *localdel; + struct ikev2_delete del, *localdel; struct ibuf *resp = NULL; - u_int64_t *localspi = NULL; - u_int64_t spi64, spi = 0; - u_int32_t spi32; - u_int8_t *buf, *msgbuf = ibuf_data(msg->msg_data); + uint64_t *localspi = NULL; + uint64_t spi64, spi = 0; + uint32_t spi32; + uint8_t *buf, *msgbuf = ibuf_data(msg->msg_data); size_t found = 0, failed = 0; int cnt, i, len, sz, ret = -1; - /* Skip if it's a reply and we don't have to deal with it */ - if (ikev2_msg_frompeer(msg) && sa && - (sa->sa_stateflags & IKED_REQ_INF)) { - sa->sa_stateflags &= ~IKED_REQ_INF; - if ((sa->sa_stateflags & IKED_REQ_DELETE) == 0) - return (0); - } + /* Skip if it's a response, then we don't have to deal with it */ + if (ikev2_msg_frompeer(msg) && + msg->msg_parent->msg_response) + return (0); - if ((del = ibuf_seek(msg->msg_data, offset, sizeof(*del))) == NULL) + if (ikev2_validate_delete(msg, offset, left, pld, &del)) return (-1); - cnt = betoh16(del->del_nspi); - sz = del->del_spisize; + cnt = betoh16(del.del_nspi); + sz = del.del_spisize; log_debug("%s: proto %s spisize %d nspi %d", - __func__, print_map(del->del_protoid, ikev2_saproto_map), + __func__, print_map(del.del_protoid, ikev2_saproto_map), sz, cnt); - buf = msgbuf + offset + sizeof(*del); - len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(*del); + buf = msgbuf + offset + sizeof(del); + len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(del); print_hex(buf, 0, len); @@ -795,20 +1359,28 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, case 8: break; default: - if (ikev2_msg_frompeer(msg) && - del->del_protoid == IKEV2_SAPROTO_IKE) { + if (del.del_protoid != IKEV2_SAPROTO_IKE) { + log_debug("%s: invalid SPI size", __func__); + return (-1); + } + if (ikev2_msg_frompeer(msg)) { /* Send an empty informational response */ if ((resp = ibuf_static()) == NULL) goto done; ret = ikev2_send_ike_e(env, sa, resp, IKEV2_PAYLOAD_NONE, IKEV2_EXCHANGE_INFORMATIONAL, 1); + msg->msg_parent->msg_responded = 1; ibuf_release(resp); sa_state(env, sa, IKEV2_STATE_CLOSED); - return (ret); + } else { + /* + * We're sending a delete message. Upper layer + * must deal with deletion of the IKE SA. + */ + ret = 0; } - log_debug("%s: invalid SPI size", __func__); - return (-1); + return (ret); } if ((len / sz) != cnt) { @@ -819,7 +1391,7 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, if (ikev2_msg_frompeer(msg) && ((peersas = calloc(cnt, sizeof(struct iked_childsa *))) == NULL || - (localspi = calloc(cnt, sizeof(u_int64_t))) == NULL)) { + (localspi = calloc(cnt, sizeof(uint64_t))) == NULL)) { log_warn("%s", __func__); goto done; } @@ -842,13 +1414,13 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, continue; if ((peersas[i] = childsa_lookup(sa, spi, - del->del_protoid)) == NULL) { + del.del_protoid)) == NULL) { log_warnx("%s: CHILD SA doesn't exist for spi %s", - __func__, print_spi(spi, del->del_spisize)); - goto done; + __func__, print_spi(spi, del.del_spisize)); + continue; } - if (ikev2_childsa_delete(env, sa, del->del_protoid, spi, + if (ikev2_childsa_delete(env, sa, del.del_protoid, spi, &localspi[i], 0) == -1) failed++; else @@ -864,9 +1436,7 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, if (!ikev2_msg_frompeer(msg)) goto done; - if (sa && (sa->sa_stateflags & IKED_REQ_DELETE)) { - /* Finish rekeying */ - sa->sa_stateflags &= ~IKED_REQ_DELETE; + if (msg->msg_parent->msg_response) { ret = 0; goto done; } @@ -880,8 +1450,8 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, if ((localdel = ibuf_advance(resp, sizeof(*localdel))) == NULL) goto done; - localdel->del_protoid = del->del_protoid; - localdel->del_spisize = del->del_spisize; + localdel->del_protoid = del.del_protoid; + localdel->del_spisize = del.del_spisize; localdel->del_nspi = htobe16(found); for (i = 0; i < cnt; i++) { @@ -899,12 +1469,13 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, } } - log_warnx("%s: deleted %d spis", __func__, found); + log_warnx("%s: deleted %zu spis", __func__, found); } if (found) { ret = ikev2_send_ike_e(env, sa, resp, IKEV2_PAYLOAD_DELETE, IKEV2_EXCHANGE_INFORMATIONAL, 1); + msg->msg_parent->msg_responded = 1; } else { /* XXX should we send an INVALID_SPI notification? */ ret = 0; @@ -919,24 +1490,51 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, return (ret); } +int +ikev2_validate_ts(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct ikev2_tsp *tsp) +{ + uint8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*tsp)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*tsp)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*tsp)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*tsp)); + return (-1); + } + memcpy(tsp, msgbuf + offset, sizeof(*tsp)); + + return (0); +} + int ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset, u_int payload) + struct iked_message *msg, size_t offset, size_t left, unsigned int payload) { struct ikev2_tsp tsp; struct ikev2_ts ts; size_t len, i; struct sockaddr_in s4; struct sockaddr_in6 s6; - u_int8_t buf[2][128]; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t buf[2][128]; + uint8_t *msgbuf = ibuf_data(msg->msg_data); - memcpy(&tsp, msgbuf + offset, sizeof(tsp)); + if (ikev2_validate_ts(msg, offset, left, pld, &tsp)) + return (-1); offset += sizeof(tsp); len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(tsp); - log_debug("%s: count %d length %d", __func__, + log_debug("%s: count %d length %zu", __func__, tsp.tsp_count, len); for (i = 0; i < tsp.tsp_count; i++) { @@ -953,16 +1551,14 @@ ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld, case IKEV2_TS_IPV4_ADDR_RANGE: bzero(&s4, sizeof(s4)); s4.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN s4.sin_len = sizeof(s4); -#endif memcpy(&s4.sin_addr.s_addr, msgbuf + offset + sizeof(ts), 4); - print_host((struct sockaddr_storage *)&s4, + print_host((struct sockaddr *)&s4, (char *)buf[0], sizeof(buf[0])); memcpy(&s4.sin_addr.s_addr, msgbuf + offset + sizeof(ts) + 4, 4); - print_host((struct sockaddr_storage *)&s4, + print_host((struct sockaddr *)&s4, (char *)buf[1], sizeof(buf[1])); log_debug("%s: start %s end %s", __func__, buf[0], buf[1]); @@ -970,16 +1566,14 @@ ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld, case IKEV2_TS_IPV6_ADDR_RANGE: bzero(&s6, sizeof(s6)); s6.sin6_family = AF_INET6; -#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN s6.sin6_len = sizeof(s6); -#endif memcpy(&s6.sin6_addr, msgbuf + offset + sizeof(ts), 16); - print_host((struct sockaddr_storage *)&s6, + print_host((struct sockaddr *)&s6, (char *)buf[0], sizeof(buf[0])); memcpy(&s6.sin6_addr, msgbuf + offset + sizeof(ts) + 16, 16); - print_host((struct sockaddr_storage *)&s6, + print_host((struct sockaddr *)&s6, (char *)buf[1], sizeof(buf[1])); log_debug("%s: start %s end %s", __func__, buf[0], buf[1]); @@ -996,13 +1590,13 @@ ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld, int ikev2_pld_e(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset) { struct iked_sa *sa = msg->msg_sa; struct ibuf *e = NULL; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); struct iked_message emsg; - u_int8_t *buf; + uint8_t *buf; size_t len; int ret = -1; @@ -1034,7 +1628,7 @@ ikev2_pld_e(struct iked *env, struct ikev2_payload *pld, TAILQ_INIT(&emsg.msg_proposals); ret = ikev2_pld_payloads(env, &emsg, 0, ibuf_size(e), - pld->pld_nextpayload, 0); + pld->pld_nextpayload); done: ibuf_release(e); @@ -1042,24 +1636,51 @@ ikev2_pld_e(struct iked *env, struct ikev2_payload *pld, return (ret); } +int +ikev2_validate_cp(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct ikev2_cp *cp) +{ + uint8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*cp)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*cp)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*cp)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*cp)); + return (-1); + } + memcpy(cp, msgbuf + offset, sizeof(*cp)); + + return (0); +} + int ikev2_pld_cp(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t left) { struct ikev2_cp cp; struct ikev2_cfg *cfg; - u_int8_t *buf; + uint8_t *buf; size_t len, i; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); struct iked_sa *sa = msg->msg_sa; - memcpy(&cp, msgbuf + offset, sizeof(cp)); + if (ikev2_validate_cp(msg, offset, left, pld, &cp)) + return (-1); offset += sizeof(cp); buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(cp); - log_debug("%s: type %s length %d", + log_debug("%s: type %s length %zu", __func__, print_map(cp.cp_type, ikev2_cp_map), len); print_hex(buf, 0, len); @@ -1083,26 +1704,49 @@ ikev2_pld_cp(struct iked *env, struct ikev2_payload *pld, return (0); } +int +ikev2_validate_eap(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct eap_header *hdr) +{ + uint8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*hdr)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*hdr)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*hdr)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*hdr)); + return (-1); + } + memcpy(hdr, msgbuf + offset, sizeof(*hdr)); + + return (0); +} + int ikev2_pld_eap(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t left) { - struct eap_header *hdr; + struct eap_header hdr; struct eap_message *eap = NULL; struct iked_sa *sa = msg->msg_sa; size_t len; - if ((hdr = ibuf_seek(msg->msg_data, offset, sizeof(*hdr))) == NULL) { - log_debug("%s: failed to get EAP header", __func__); + if (ikev2_validate_eap(msg, offset, left, pld, &hdr)) return (-1); - } - - len = betoh16(hdr->eap_length); + len = betoh16(hdr.eap_length); if (len < sizeof(*eap)) { log_info("%s: %s id %d length %d", __func__, - print_map(hdr->eap_code, eap_code_map), - hdr->eap_id, betoh16(hdr->eap_length)); + print_map(hdr.eap_code, eap_code_map), + hdr.eap_id, betoh16(hdr.eap_length)); } else { /* Now try to get the indicated length */ if ((eap = ibuf_seek(msg->msg_data, offset, len)) == NULL) { @@ -1114,10 +1758,10 @@ ikev2_pld_eap(struct iked *env, struct ikev2_payload *pld, print_map(eap->eap_code, eap_code_map), eap->eap_id, betoh16(eap->eap_length), print_map(eap->eap_type, eap_type_map)); - } - if (eap_parse(env, sa, hdr, msg->msg_response) == -1) - return (-1); + if (eap_parse(env, sa, eap, msg->msg_response) == -1) + return (-1); + } return (0); } diff --git a/iked/imsg_util.c b/iked/imsg_util.c index 8dcfab2..9bd2003 100644 --- a/iked/imsg_util.c +++ b/iked/imsg_util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: imsg_util.c,v 1.7 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: imsg_util.c,v 1.10 2015/08/21 11:59:27 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,18 +16,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "openbsd-compat/sys-queue.h" +#include #include #include -#include -#include -#include -#include -#include -#include #include - #include #include #include @@ -52,7 +45,7 @@ ibuf_cat(struct ibuf *dst, struct ibuf *src) void ibuf_zero(struct ibuf *buf) { - memset(buf->buf, 0, buf->wpos); + explicit_bzero(buf->buf, buf->wpos); } struct ibuf * @@ -110,8 +103,10 @@ ibuf_release(struct ibuf *buf) { if (buf == NULL) return; - if (buf->buf != NULL) + if (buf->buf != NULL) { + ibuf_zero(buf); free(buf->buf); + } free(buf); } @@ -123,7 +118,7 @@ ibuf_length(struct ibuf *buf) return (ibuf_size(buf)); } -u_int8_t * +uint8_t * ibuf_data(struct ibuf *buf) { return (ibuf_seek(buf, 0, 0)); diff --git a/iked/log.c b/iked/log.c index e283024..61256f3 100644 --- a/iked/log.c +++ b/iked/log.c @@ -1,4 +1,4 @@ -/* $OpenBSD: log.c,v 1.3 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: log.c,v 1.4 2015/01/16 06:39:58 deraadt Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -16,10 +16,9 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include #include -#include "openbsd-compat/sys-tree.h" +#include #include #include diff --git a/iked/ocsp.c b/iked/ocsp.c new file mode 100644 index 0000000..37356d8 --- /dev/null +++ b/iked/ocsp.c @@ -0,0 +1,514 @@ +/* $OpenBSD: ocsp.c,v 1.6 2015/08/21 11:59:27 reyk Exp $ */ + +/* + * Copyright (c) 2014 Markus Friedl + * Copyright (c) 2005 Marco Pfatschbacher + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "iked.h" + +struct iked_ocsp { + struct iked *ocsp_env; /* back pointer to env */ + struct iked_sahdr ocsp_sh; /* ike sa */ + uint8_t ocsp_type; /* auth type */ + struct iked_socket *ocsp_sock; /* socket to ocsp responder */ + BIO *ocsp_cbio; /* matching OpenSSL obj */ + OCSP_CERTID *ocsp_id; /* ocsp-id for cert */ + OCSP_REQUEST *ocsp_req; /* ocsp-request */ + OCSP_REQ_CTX *ocsp_req_ctx; /* async ocsp-request */ +}; + +struct ocsp_connect { + struct iked_socket oc_sock; + char *oc_path; +}; + +/* priv */ +void ocsp_connect_cb(int, short, void *); +int ocsp_connect_finish(struct iked *, int, struct ocsp_connect *); + +/* unpriv */ +void ocsp_free(struct iked_ocsp *); +void ocsp_callback(int, short, void *); +void ocsp_parse_response(struct iked_ocsp *, OCSP_RESPONSE *); +STACK_OF(X509) *ocsp_load_certs(const char *); +int ocsp_validate_finish(struct iked_ocsp *, int); + + +/* priv */ + +/* async connect to configure ocsp-responder */ +int +ocsp_connect(struct iked *env) +{ + struct ocsp_connect *oc = NULL; + struct addrinfo hints, *res0 = NULL, *res; + char *host = NULL, *port = NULL, *path = NULL; + int use_ssl, fd = -1, ret = -1, error; + + if (env->sc_ocsp_url == 0) { + log_warnx("%s: no ocsp url", __func__); + goto done; + } + if (!OCSP_parse_url(env->sc_ocsp_url, &host, &port, &path, &use_ssl)) { + log_warnx("%s: error parsing OCSP-request-URL: %s", __func__, + env->sc_ocsp_url); + goto done; + } + + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + log_debug("%s: socket failed", __func__); + goto done; + } + if ((oc = calloc(1, sizeof(*oc))) == NULL) { + log_debug("%s: calloc failed", __func__); + goto done; + } + + bzero(&hints, sizeof(struct addrinfo)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(host, port, &hints, &res0); + if (error) { + log_debug("%s: getaddrinfo(%s, %s) failed", + __func__, host, port); + goto done; + } + /* XXX just pick the first answer. we could loop instead */ + for (res = res0; res; res = res->ai_next) + if (res->ai_family == AF_INET) + break; + if (res == NULL) { + log_debug("%s: no addr to connect to for %s:%s", + __func__, host, port); + goto done; + } + + oc->oc_sock.sock_fd = fd; + oc->oc_sock.sock_env = env; + oc->oc_path = path; + path = NULL; + + log_debug("%s: connect(%s, %s)", __func__, host, port); + socket_set_blockmode(fd, BM_NONBLOCK); + if (connect(fd, res->ai_addr, res->ai_addrlen) == -1) { + /* register callback for ansync connect */ + if (errno == EINPROGRESS) { + event_set(&oc->oc_sock.sock_ev, fd, EV_WRITE, + ocsp_connect_cb, oc); + event_add(&oc->oc_sock.sock_ev, NULL); + ret = 0; + } else + log_debug("%s: error while connecting: %s", __func__, + strerror(errno)); + } else { + ocsp_connect_finish(env, fd, oc); + ret = 0; + } + done: + if (res0) + freeaddrinfo(res0); + free(host); + free(port); + free(path); + if (ret == -1) { + ocsp_connect_finish(env, -1, oc); + if (fd >= 0) + close(fd); + } + return (ret); +} + +/* callback triggered if connection to ocsp-responder completes/fails */ +void +ocsp_connect_cb(int fd, short event, void *arg) +{ + struct ocsp_connect *oc = arg; + int error, send_fd = -1; + socklen_t len; + + len = sizeof(error); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + log_warn("%s: getsockopt SOL_SOCKET SO_ERROR", __func__); + } else if (error) { + log_debug("%s: error while connecting: %s", __func__, + strerror(error)); + } else { + send_fd = fd; + } + ocsp_connect_finish(oc->oc_sock.sock_env, send_fd, oc); + + /* if we did not send the fd, we need to close it ourself */ + if (send_fd == -1) + close(fd); +} + +/* send FD+path or error back to CA process */ +int +ocsp_connect_finish(struct iked *env, int fd, struct ocsp_connect *oc) +{ + struct iovec iov[1]; + int iovcnt = 1, ret; + + if (oc && fd >= 0) { + /* the imsg framework will close the FD after send */ + iov[0].iov_base = oc->oc_path; + iov[0].iov_len = strlen(oc->oc_path); + ret = proc_composev_imsg(&env->sc_ps, PROC_CERT, -1, + IMSG_OCSP_FD, fd, iov, iovcnt); + } else { + ret = proc_compose_imsg(&env->sc_ps, PROC_CERT, -1, + IMSG_OCSP_FD, -1, NULL, 0); + if (fd >= 0) + close(fd); + } + if (oc) { + free(oc->oc_path); + free(oc); + } + return (ret); +} + + +/* unpriv */ + +/* validate the certifcate stored in 'data' by querying the ocsp-responder */ +int +ocsp_validate_cert(struct iked *env, struct iked_static_id *id, + void *data, size_t len, struct iked_sahdr sh, uint8_t type) +{ + struct iked_ocsp_entry *ioe; + struct iked_ocsp *ocsp; + BIO *rawcert = NULL, *bissuer = NULL; + X509 *cert = NULL, *issuer = NULL; + + if ((ioe = calloc(1, sizeof(*ioe))) == NULL) + return (-1); + if ((ocsp = calloc(1, sizeof(*ocsp))) == NULL) { + free(ioe); + return (-1); + } + + ocsp->ocsp_env = env; + ocsp->ocsp_sh = sh; + ocsp->ocsp_type = type; + + if ((rawcert = BIO_new_mem_buf(data, len)) == NULL || + (cert = d2i_X509_bio(rawcert, NULL)) == NULL || + (bissuer = BIO_new_file(IKED_OCSP_ISSUER, "r")) == NULL || + (issuer = PEM_read_bio_X509(bissuer, NULL, NULL, NULL)) == NULL || + (ocsp->ocsp_cbio = BIO_new(BIO_s_socket())) == NULL || + (ocsp->ocsp_req = OCSP_REQUEST_new()) == NULL || + !(ocsp->ocsp_id = OCSP_cert_to_id(NULL, cert, issuer)) || + !OCSP_request_add0_id(ocsp->ocsp_req, ocsp->ocsp_id)) + goto err; + + BIO_free(rawcert); + BIO_free(bissuer); + X509_free(cert); + X509_free(issuer); + + ioe->ioe_ocsp = ocsp; + TAILQ_INSERT_TAIL(&env->sc_ocsp, ioe, ioe_entry); + + /* request connection to ocsp-responder */ + proc_compose_imsg(&env->sc_ps, PROC_PARENT, -1, + IMSG_OCSP_FD, -1, NULL, 0); + return (0); + + err: + ca_sslerror(__func__); + free(ioe); + if (rawcert != NULL) + BIO_free(rawcert); + if (cert != NULL) + X509_free(cert); + if (bissuer != NULL) + BIO_free(bissuer); + if (issuer != NULL) + X509_free(issuer); + ocsp_validate_finish(ocsp, 0); /* failed */ + return (-1); +} + +/* free ocsp query context */ +void +ocsp_free(struct iked_ocsp *ocsp) +{ + if (ocsp != NULL) { + if (ocsp->ocsp_sock != NULL) { + close(ocsp->ocsp_sock->sock_fd); + free(ocsp->ocsp_sock); + } + if (ocsp->ocsp_cbio != NULL) + BIO_free_all(ocsp->ocsp_cbio); + if (ocsp->ocsp_id != NULL) + OCSP_CERTID_free(ocsp->ocsp_id); + + /* XXX not sure about ownership XXX */ + if (ocsp->ocsp_req_ctx != NULL) + OCSP_REQ_CTX_free(ocsp->ocsp_req_ctx); + else if (ocsp->ocsp_req != NULL) + OCSP_REQUEST_free(ocsp->ocsp_req); + + free(ocsp); + } +} + +/* we got a connection to the ocsp responder */ +int +ocsp_receive_fd(struct iked *env, struct imsg *imsg) +{ + struct iked_ocsp_entry *ioe = NULL; + struct iked_ocsp *ocsp = NULL; + struct iked_socket *sock; + char *path = NULL; + int ret = -1; + + log_debug("%s: received socket fd %d", __func__, imsg->fd); + if ((ioe = TAILQ_FIRST(&env->sc_ocsp)) == NULL) { + log_debug("%s: oops, no request for", __func__); + close(imsg->fd); + return (-1); + } + TAILQ_REMOVE(&env->sc_ocsp, ioe, ioe_entry); + ocsp = ioe->ioe_ocsp; + free(ioe); + + if ((sock = calloc(1, sizeof(*sock))) == NULL) + fatal("ocsp_receive_fd: calloc sock"); + + /* note that sock_addr is not set */ + sock->sock_fd = imsg->fd; + sock->sock_env = env; + ocsp->ocsp_sock = sock; + + /* fetch 'path' and 'fd' from imsg */ + if ((path = get_string(imsg->data, IMSG_DATA_SIZE(imsg))) == NULL) + goto done; + + BIO_set_fd(ocsp->ocsp_cbio, imsg->fd, BIO_NOCLOSE); + + if ((ocsp->ocsp_req_ctx = OCSP_sendreq_new(ocsp->ocsp_cbio, + path, NULL, -1)) == NULL) + goto done; + if (!OCSP_REQ_CTX_set1_req(ocsp->ocsp_req_ctx, ocsp->ocsp_req)) + goto done; + + event_set(&sock->sock_ev, sock->sock_fd, EV_WRITE, ocsp_callback, ocsp); + event_add(&sock->sock_ev, NULL); + ret = 0; + done: + if (ret == -1) + ocsp_validate_finish(ocsp, 0); /* failed */ + free(path); + return (ret); +} + +/* load a stack of x509 certificates */ +STACK_OF(X509)* +ocsp_load_certs(const char *file) +{ + BIO *bio = NULL; + STACK_OF(X509) *certs = NULL; + STACK_OF(X509_INFO) *xis = NULL; + X509_INFO *xi; + int i; + + if ((bio = BIO_new_file(file, "r")) == NULL) { + log_warn("%s: BIO_new_file failed for %s", + __func__, file); + return (NULL); + } + if ((xis = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL)) == NULL) { + ca_sslerror(__func__); + goto done; + } + if ((certs = sk_X509_new_null()) == NULL) { + log_debug("%s: sk_X509_new_null failed for %s", __func__, file); + goto done; + } + for (i = 0; i < sk_X509_INFO_num(xis); i++) { + xi = sk_X509_INFO_value(xis, i); + if (xi->x509) { + if (!sk_X509_push(certs, xi->x509)) + goto done; + xi->x509 = NULL; + } + } + + done: + if (bio) + BIO_free(bio); + if (xis) + sk_X509_INFO_pop_free(xis, X509_INFO_free); + if (certs && sk_X509_num(certs) <= 0) { + sk_X509_pop_free(certs, X509_free); + certs = NULL; + } + return (certs); +} + +/* read/write callback that sends the requests and reads the ocsp response */ +void +ocsp_callback(int fd, short event, void *arg) +{ + struct iked_ocsp *ocsp = arg; + struct iked_socket *sock = ocsp->ocsp_sock; + OCSP_RESPONSE *resp = NULL; + + /* + * Only call OCSP_sendreq_nbio() if should_read/write is + * either not requested or read/write can be called. + */ + if ((!BIO_should_read(ocsp->ocsp_cbio) || (event & EV_READ)) && + (!BIO_should_write(ocsp->ocsp_cbio) || (event & EV_WRITE)) && + OCSP_sendreq_nbio(&resp, ocsp->ocsp_req_ctx) != -1 ) { + ocsp_parse_response(ocsp, resp); + return; + } + if (BIO_should_read(ocsp->ocsp_cbio)) + event_set(&sock->sock_ev, sock->sock_fd, EV_READ, + ocsp_callback, ocsp); + else if (BIO_should_write(ocsp->ocsp_cbio)) + event_set(&sock->sock_ev, sock->sock_fd, EV_WRITE, + ocsp_callback, ocsp); + event_add(&sock->sock_ev, NULL); +} + +/* parse the actual OCSP response */ +void +ocsp_parse_response(struct iked_ocsp *ocsp, OCSP_RESPONSE *resp) +{ + int status; + X509_STORE *store = NULL; + STACK_OF(X509) *verify_other = NULL; + OCSP_BASICRESP *bs = NULL; + int verify_flags = 0; + ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; + int reason = 0; + int error = 1; + + if (!resp) { + log_warnx("%s: error querying OCSP responder", __func__); + goto done; + } + + status = OCSP_response_status(resp); + if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + log_warnx("%s: responder error: %s (%i)\n", __func__, + OCSP_response_status_str(status), status); + goto done; + } + + verify_other = ocsp_load_certs(IKED_OCSP_RESPCERT); + verify_flags |= OCSP_TRUSTOTHER; + if (!verify_other) + goto done; + + bs = OCSP_response_get1_basic(resp); + if (!bs) { + log_warnx("%s: error parsing response", __func__); + goto done; + } + + status = OCSP_check_nonce(ocsp->ocsp_req, bs); + if (status <= 0) { + if (status == -1) + log_warnx("%s: no nonce in response", __func__); + else { + log_warnx("%s: nonce verify error", __func__); + goto done; + } + } + + store = X509_STORE_new(); + status = OCSP_basic_verify(bs, verify_other, store, verify_flags); + if (status < 0) + status = OCSP_basic_verify(bs, NULL, store, 0); + + if (status <= 0) { + ca_sslerror(__func__); + log_warnx("%s: response verify failure", __func__); + goto done; + } else + log_debug("%s: response verify ok", __func__); + + if (!OCSP_resp_find_status(bs, ocsp->ocsp_id, &status, &reason, + &rev, &thisupd, &nextupd)) { + log_warnx("%s: no status found", __func__); + goto done; + } + log_debug("%s: status: %s", __func__, OCSP_cert_status_str(status)); + + if (status == V_OCSP_CERTSTATUS_GOOD) + error = 0; + + done: + if (store) + X509_STORE_free(store); + if (verify_other) + sk_X509_pop_free(verify_other, X509_free); + if (resp) + OCSP_RESPONSE_free(resp); + if (bs) + OCSP_BASICRESP_free(bs); + + ocsp_validate_finish(ocsp, error == 0); +} + +/* + * finish the ocsp_validate_cert() RPC by sending the appropriate + * message back to the IKEv2 process + */ +int +ocsp_validate_finish(struct iked_ocsp *ocsp, int valid) +{ + struct iked *env = ocsp->ocsp_env; + struct iovec iov[2]; + int iovcnt = 2, ret, cmd; + + iov[0].iov_base = &ocsp->ocsp_sh; + iov[0].iov_len = sizeof(ocsp->ocsp_sh); + iov[1].iov_base = &ocsp->ocsp_type; + iov[1].iov_len = sizeof(ocsp->ocsp_type); + + cmd = valid ? IMSG_CERTVALID : IMSG_CERTINVALID; + ret = proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, + cmd, -1, iov, iovcnt); + + ocsp_free(ocsp); + return (ret); +} diff --git a/iked/parse.y b/iked/parse.y index 7c1bda2..14ff9ef 100644 --- a/iked/parse.y +++ b/iked/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.30 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: parse.y,v 1.51 2015/10/02 16:56:34 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -24,14 +24,11 @@ %{ #include #include -#include "openbsd-compat/sys-queue.h" +#include #include #include #include #include -#if defined(__OpenBSD__) -#include -#endif #include #include @@ -65,10 +62,12 @@ static struct file { struct file *pushfile(const char *, int); int popfile(void); int check_file_secrecy(int, const char *); +int check_pubkey(char *, int ); int yyparse(void); int yylex(void); -int yyerror(const char *, ...); -int yywarn(const char *, ...); +int yyerror(const char *, ...) + __attribute__((__format__ (printf, 1, 2))) + __attribute__((__nonnull__ (1))); int kw_cmp(const void *, const void *); int lookup(char *); int lgetc(int); @@ -93,14 +92,15 @@ static int debug = 0; static int rules = 0; static int passive = 0; static int decouple = 0; +static char *ocsp_url = NULL; struct ipsec_xf { const char *name; - u_int id; - u_int length; - u_int keylength; - u_int nonce; - u_int noauth; + unsigned int id; + unsigned int length; + unsigned int keylength; + unsigned int nonce; + unsigned int noauth; }; struct ipsec_transforms { @@ -113,7 +113,7 @@ struct ipsec_transforms { struct ipsec_mode { struct ipsec_transforms *xfs; - u_int8_t ike_exch; + uint8_t ike_exch; }; struct iked_transform ikev2_default_ike_transforms[] = { @@ -123,10 +123,8 @@ struct iked_transform ikev2_default_ike_transforms[] = { { IKEV2_XFORMTYPE_ENCR, IKEV2_XFORMENCR_3DES }, { IKEV2_XFORMTYPE_PRF, IKEV2_XFORMPRF_HMAC_SHA2_256 }, { IKEV2_XFORMTYPE_PRF, IKEV2_XFORMPRF_HMAC_SHA1 }, - { IKEV2_XFORMTYPE_PRF, IKEV2_XFORMPRF_HMAC_MD5 }, { IKEV2_XFORMTYPE_INTEGR, IKEV2_XFORMAUTH_HMAC_SHA2_256_128 }, { IKEV2_XFORMTYPE_INTEGR, IKEV2_XFORMAUTH_HMAC_SHA1_96 }, - { IKEV2_XFORMTYPE_INTEGR, IKEV2_XFORMAUTH_HMAC_MD5_96 }, { IKEV2_XFORMTYPE_DH, IKEV2_XFORMDH_MODP_2048_256 }, { IKEV2_XFORMTYPE_DH, IKEV2_XFORMDH_MODP_2048 }, { IKEV2_XFORMTYPE_DH, IKEV2_XFORMDH_MODP_1536 }, @@ -140,13 +138,9 @@ struct iked_transform ikev2_default_esp_transforms[] = { { IKEV2_XFORMTYPE_ENCR, IKEV2_XFORMENCR_AES_CBC, 256 }, { IKEV2_XFORMTYPE_ENCR, IKEV2_XFORMENCR_AES_CBC, 192 }, { IKEV2_XFORMTYPE_ENCR, IKEV2_XFORMENCR_AES_CBC, 128 }, -#ifndef BROKEN_HMAC_SHA2_256 { IKEV2_XFORMTYPE_INTEGR, IKEV2_XFORMAUTH_HMAC_SHA2_256_128 }, -#endif { IKEV2_XFORMTYPE_INTEGR, IKEV2_XFORMAUTH_HMAC_SHA1_96 }, -#ifdef HAVE_ESN { IKEV2_XFORMTYPE_ESN, IKEV2_XFORMESN_ESN }, -#endif { IKEV2_XFORMTYPE_ESN, IKEV2_XFORMESN_NONE }, { 0 } }; @@ -241,6 +235,15 @@ const struct ipsec_xf groupxfs[] = { { "grp25", IKEV2_XFORMDH_ECP_192 }, { "ecp224", IKEV2_XFORMDH_ECP_224 }, { "grp26", IKEV2_XFORMDH_ECP_224 }, + { "brainpool224", IKEV2_XFORMDH_BRAINPOOL_P224R1 }, + { "grp27", IKEV2_XFORMDH_BRAINPOOL_P224R1 }, + { "brainpool256", IKEV2_XFORMDH_BRAINPOOL_P256R1 }, + { "grp28", IKEV2_XFORMDH_BRAINPOOL_P256R1 }, + { "brainpool384", IKEV2_XFORMDH_BRAINPOOL_P384R1 }, + { "grp29", IKEV2_XFORMDH_BRAINPOOL_P384R1 }, + { "brainpool512", IKEV2_XFORMDH_BRAINPOOL_P512R1 }, + { "grp30", IKEV2_XFORMDH_BRAINPOOL_P512R1 }, + { "curve25519", IKEV2_XFORMDH_X_CURVE25519 }, { NULL } }; @@ -272,7 +275,8 @@ const struct ipsec_xf cpxfs[] = { { "protected-subnet", IKEV2_CFG_INTERNAL_IP4_SUBNET, AF_INET }, { "protected-subnet", IKEV2_CFG_INTERNAL_IP6_SUBNET, AF_INET6 }, { "access-server", IKEV2_CFG_INTERNAL_IP4_SERVER, AF_INET }, - { "access-server", IKEV2_CFG_INTERNAL_IP6_SERVER, AF_INET6 } + { "access-server", IKEV2_CFG_INTERNAL_IP6_SERVER, AF_INET6 }, + { NULL } }; const struct iked_lifetime deflifetime = { @@ -282,11 +286,11 @@ const struct iked_lifetime deflifetime = { struct ipsec_addr_wrap { struct sockaddr_storage address; - u_int8_t mask; + uint8_t mask; int netaddress; sa_family_t af; - u_int type; - u_int action; + unsigned int type; + unsigned int action; char *name; struct ipsec_addr_wrap *next; struct ipsec_addr_wrap *tail; @@ -296,13 +300,13 @@ struct ipsec_addr_wrap { struct ipsec_hosts { struct ipsec_addr_wrap *src; struct ipsec_addr_wrap *dst; - u_int16_t sport; - u_int16_t dport; + uint16_t sport; + uint16_t dport; }; struct ipsec_filters { - char *tag; - u_int tap; + char *tag; + unsigned int tap; }; struct ipsec_addr_wrap *host(const char *); @@ -315,22 +319,25 @@ void ifa_load(void); int ifa_exists(const char *); struct ipsec_addr_wrap *ifa_lookup(const char *ifa_name); struct ipsec_addr_wrap *ifa_grouplookup(const char *); -void set_ipmask(struct ipsec_addr_wrap *, u_int8_t); -const struct ipsec_xf *parse_xf(const char *, u_int, const struct ipsec_xf *); -const char *print_xf(u_int, u_int, const struct ipsec_xf *); -void copy_transforms(u_int, const struct ipsec_xf *, +void set_ipmask(struct ipsec_addr_wrap *, uint8_t); +const struct ipsec_xf *parse_xf(const char *, unsigned int, + const struct ipsec_xf *); +const char *print_xf(unsigned int, unsigned int, + const struct ipsec_xf *); +void copy_transforms(unsigned int, const struct ipsec_xf *, const struct ipsec_xf *, struct iked_transform *, size_t, - u_int *, struct iked_transform *, size_t); -int create_ike(char *, int, u_int8_t, struct ipsec_hosts *, - struct ipsec_hosts *, struct ipsec_mode *, - struct ipsec_mode *, u_int8_t, - u_int8_t, char *, char *, struct iked_lifetime *, - struct iked_auth *, struct ipsec_filters *, - struct ipsec_addr_wrap *); + unsigned int *, struct iked_transform *, size_t); +int create_ike(char *, int, uint8_t, struct ipsec_hosts *, + struct ipsec_hosts *, struct ipsec_mode *, + struct ipsec_mode *, uint8_t, + uint8_t, char *, char *, + uint32_t, struct iked_lifetime *, + struct iked_auth *, struct ipsec_filters *, + struct ipsec_addr_wrap *); int create_user(const char *, const char *); int get_id_type(char *); -u_int8_t x2i(unsigned char *); +uint8_t x2i(unsigned char *); int parsekey(unsigned char *, size_t, struct iked_auth *); int parsekeyfile(char *, struct iked_auth *); @@ -340,12 +347,12 @@ struct ipsec_filters *ipsec_filters; typedef struct { union { int64_t number; - u_int8_t ikemode; - u_int8_t dir; - u_int8_t satype; - u_int8_t proto; + uint8_t ikemode; + uint8_t dir; + uint8_t satype; + uint8_t proto; char *string; - u_int16_t port; + uint16_t port; struct ipsec_hosts *hosts; struct ipsec_hosts peers; struct ipsec_addr_wrap *anyhost; @@ -356,7 +363,7 @@ typedef struct { char *dstid; } ids; char *id; - u_int8_t type; + uint8_t type; struct iked_lifetime lifetime; struct iked_auth ikeauth; struct iked_auth ikekey; @@ -374,6 +381,7 @@ typedef struct { %token PASSIVE ACTIVE ANY TAG TAP PROTO LOCAL GROUP NAME CONFIG EAP USER %token IKEV1 FLOW SA TCPMD5 TUNNEL TRANSPORT COUPLE DECOUPLE SET %token INCLUDE LIFETIME BYTES INET INET6 QUICK SKIP DEFAULT +%token IPCOMP OCSP IKELIFETIME %token STRING %token NUMBER %type string @@ -390,12 +398,12 @@ typedef struct { %type id %type transforms %type filters -%type ikeflags ikematch ikemode +%type ikeflags ikematch ikemode ipcomp %type ikeauth %type keyspec %type ike_sa child_sa %type lifetime -%type byte_spec time_spec +%type byte_spec time_spec ikelifetime %type name %type cfg ikecfg ikecfgvals %% @@ -434,6 +442,12 @@ set : SET ACTIVE { passive = 0; } | SET PASSIVE { passive = 1; } | SET COUPLE { decouple = 0; } | SET DECOUPLE { decouple = 1; } + | SET OCSP STRING { + if ((ocsp_url = strdup($3)) == NULL) { + yyerror("cannot set ocsp_url"); + YYERROR; + } + } ; user : USER STRING STRING { @@ -443,9 +457,11 @@ user : USER STRING STRING { ; ikev2rule : IKEV2 name ikeflags satype af proto hosts_list peers - ike_sa child_sa ids lifetime ikeauth ikecfg filters { + ike_sa child_sa ids ikelifetime lifetime ikeauth ikecfg + filters { if (create_ike($2, $5, $6, $7, &$8, $9, $10, $4, $3, - $11.srcid, $11.dstid, &$12, &$13, $15, $14) == -1) + $11.srcid, $11.dstid, $12, &$13, &$14, + $16, $15) == -1) YYERROR; } ; @@ -757,7 +773,7 @@ ike_sa : /* empty */ { encxfs = ikeencxfs; } transforms { if (($$ = calloc(1, sizeof(*$$))) == NULL) - err(1, "child_sa: calloc"); + err(1, "ike_sa: calloc"); $$->xfs = $3; } ; @@ -774,7 +790,7 @@ child_sa : /* empty */ { } ; -ikeflags : ikematch ikemode { $$ = $1 | $2; } +ikeflags : ikematch ikemode ipcomp { $$ = $1 | $2 | $3; } ; ikematch : /* empty */ { $$ = 0; } @@ -788,6 +804,10 @@ ikemode : /* empty */ { $$ = IKED_POLICY_PASSIVE; } | ACTIVE { $$ = IKED_POLICY_ACTIVE; } ; +ipcomp : /* empty */ { $$ = 0; } + | IPCOMP { $$ = IKED_POLICY_IPCOMP; } + ; + ikeauth : /* empty */ { $$.auth_method = IKEV2_AUTH_RSA_SIG; $$.auth_length = 0; @@ -801,7 +821,7 @@ ikeauth : /* empty */ { $$.auth_method = IKEV2_AUTH_SHARED_KEY_MIC; } | EAP STRING { - u_int i; + unsigned int i; for (i = 0; i < strlen($2); i++) if ($2[i] == '-') @@ -824,14 +844,14 @@ byte_spec : NUMBER { $$ = $1; } | STRING { - u_int64_t bytes = 0; + uint64_t bytes = 0; char unit = 0; if (sscanf($1, "%llu%c", &bytes, &unit) != 2) { yyerror("invalid byte specification: %s", $1); YYERROR; } - switch (toupper(unit)) { + switch (toupper((unsigned char)unit)) { case 'K': bytes *= 1024; break; @@ -853,14 +873,14 @@ time_spec : NUMBER { $$ = $1; } | STRING { - u_int64_t seconds = 0; + uint64_t seconds = 0; char unit = 0; if (sscanf($1, "%llu%c", &seconds, &unit) != 2) { yyerror("invalid time specification: %s", $1); YYERROR; } - switch (tolower(unit)) { + switch (tolower((unsigned char)unit)) { case 'm': seconds *= 60; break; @@ -888,8 +908,15 @@ lifetime : /* empty */ { } ; +ikelifetime : /* empty */ { + $$ = 0; + } + | IKELIFETIME time_spec { + $$ = $2; + } + keyspec : STRING { - u_int8_t *hex; + uint8_t *hex; bzero(&$$, sizeof($$)); @@ -1034,19 +1061,6 @@ yyerror(const char *fmt, ...) return (0); } -int -yywarn(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - fprintf(stderr, "%s: %d: ", file->name, yylval.lineno); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - return (0); -} - int kw_cmp(const void *k, const void *e) { @@ -1077,14 +1091,17 @@ lookup(char *s) { "from", FROM }, { "group", GROUP }, { "ike", IKEV1 }, + { "ikelifetime", IKELIFETIME }, { "ikesa", IKESA }, { "ikev2", IKEV2 }, { "include", INCLUDE }, { "inet", INET }, { "inet6", INET6 }, + { "ipcomp", IPCOMP }, { "lifetime", LIFETIME }, { "local", LOCAL }, { "name", NAME }, + { "ocsp", OCSP }, { "passive", PASSIVE }, { "peer", PEER }, { "port", PORT }, @@ -1123,10 +1140,10 @@ lookup(char *s) #define MAXPUSHBACK 128 -char *parsebuf; -int parseindex; -char pushback_buffer[MAXPUSHBACK]; -int pushback_index = 0; +unsigned char *parsebuf; +int parseindex; +unsigned char pushback_buffer[MAXPUSHBACK]; +int pushback_index = 0; int lgetc(int quotec) @@ -1149,7 +1166,8 @@ lgetc(int quotec) if (quotec) { if ((c = getc(file->stream)) == EOF) { - yyerror("reached end of file while parsing quoted string"); + yyerror("reached end of file while parsing " + "quoted string"); if (popfile() == EOF) return (EOF); return (quotec); @@ -1217,10 +1235,10 @@ findeol(void) int yylex(void) { - char buf[8096]; - char *p, *val; - int quotec, next, c; - int token; + unsigned char buf[8096]; + unsigned char *p, *val; + int quotec, next, c; + int token; top: p = buf; @@ -1241,7 +1259,7 @@ top: return (findeol()); } if (isalnum(c) || c == '_') { - *p++ = (char)c; + *p++ = c; continue; } *p = '\0'; @@ -1281,12 +1299,15 @@ top: } else if (c == quotec) { *p = '\0'; break; + } else if (c == '\0') { + yyerror("syntax error"); + return (findeol()); } if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } - *p++ = (char)c; + *p++ = c; } yylval.v.string = strdup(buf); if (yylval.v.string == NULL) @@ -1373,8 +1394,8 @@ check_file_secrecy(int fd, const char *fname) warnx("%s: owner not root or current user", fname); return (-1); } - if (st.st_mode & (S_IRWXG | S_IRWXO)) { - warnx("%s: group/world readable/writeable", fname); + if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { + warnx("%s: group writable or world read/writable", fname); return (-1); } return (0); @@ -1459,6 +1480,7 @@ parse_config(const char *filename, struct iked *x_env) env->sc_passive = passive ? 1 : 0; env->sc_decoupled = decouple ? 1 : 0; + env->sc_ocsp_url = ocsp_url; if (!rules) log_warnx("%s: no valid configuration rules found", @@ -1555,7 +1577,7 @@ symget(const char *nam) return (NULL); } -u_int8_t +uint8_t x2i(unsigned char *s) { char ss[3]; @@ -1568,13 +1590,13 @@ x2i(unsigned char *s) yyerror("keys need to be specified in hex digits"); return (-1); } - return ((u_int8_t)strtoul(ss, NULL, 16)); + return ((uint8_t)strtoul(ss, NULL, 16)); } int parsekey(unsigned char *hexkey, size_t len, struct iked_auth *auth) { - u_int i; + unsigned int i; bzero(auth, sizeof(*auth)); if ((len / 2) > sizeof(auth->auth_data)) @@ -1631,6 +1653,48 @@ get_id_type(char *string) return (IKEV2_ID_FQDN); } +int +check_pubkey(char *idstr, int type) +{ + char keyfile[PATH_MAX]; + FILE *fp = NULL; + const char *suffix = NULL; + + switch (type) { + case IKEV2_ID_IPV4: + suffix = "ipv4"; + break; + case IKEV2_ID_IPV6: + suffix = "ipv6"; + break; + case IKEV2_ID_FQDN: + suffix = "fqdn"; + break; + case IKEV2_ID_UFQDN: + suffix = "ufqdn"; + break; + default: + /* Unspecified ID or public key not supported for this type */ + return (-1); + } + + lc_string(idstr); + if ((size_t)snprintf(keyfile, sizeof(keyfile), + IKED_CA IKED_PUBKEY_DIR "%s/%s", suffix, + idstr) >= sizeof(keyfile)) { + log_warnx("%s: public key path is too long", __func__); + return (-1); + } + + if ((fp = fopen(keyfile, "r")) == NULL) + return (-1); + fclose(fp); + + log_debug("%s: found public key file %s", __func__, keyfile); + + return (0); +} + struct ipsec_addr_wrap * host(const char *s) { @@ -1710,11 +1774,12 @@ host_v6(const char *s, int prefixlen) if (prefixlen != 128) { ipa->netaddress = 1; - asprintf(&ipa->name, "%s/%d", hbuf, prefixlen); - } else - ipa->name = strdup(hbuf); - if (ipa->name == NULL) - err(1, "host_v6: strdup"); + if (asprintf(&ipa->name, "%s/%d", hbuf, prefixlen) == -1) + err(1, "host_v6: asprintf"); + } else { + if ((ipa->name = strdup(hbuf)) == NULL) + err(1, "host_v6: strdup"); + } freeaddrinfo(res); @@ -1743,9 +1808,7 @@ host_v4(const char *s, int mask) err(1, "host_v4: calloc"); ina.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN ina.sin_len = sizeof(ina); -#endif memcpy(&ipa->address, &ina, sizeof(ina)); ipa->name = strdup(s); @@ -1773,6 +1836,7 @@ host_dns(const char *s, int mask) bzero(&hints, sizeof(struct addrinfo)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG; error = getaddrinfo(s, NULL, &hints, &res0); if (error) return (NULL); @@ -1909,15 +1973,12 @@ int ifa_exists(const char *ifa_name) { struct ipsec_addr_wrap *n; -#if defined(SIOCGIFGMEMB) struct ifgroupreq ifgr; int s; -#endif if (iftab == NULL) ifa_load(); -#if defined(SIOCGIFGMEMB) /* check wether this is a group */ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) err(1, "ifa_exists: socket"); @@ -1928,7 +1989,6 @@ ifa_exists(const char *ifa_name) return (1); } close(s); -#endif for (n = iftab; n; n = n->next) { if (n->af == AF_LINK && !strncmp(n->name, ifa_name, @@ -1942,7 +2002,6 @@ ifa_exists(const char *ifa_name) struct ipsec_addr_wrap * ifa_grouplookup(const char *ifa_name) { -#if defined(SIOCGIFGMEMB) struct ifg_req *ifg; struct ifgroupreq ifgr; int s; @@ -1982,9 +2041,6 @@ ifa_grouplookup(const char *ifa_name) close(s); return (h); -#else - return (NULL); -#endif } struct ipsec_addr_wrap * @@ -1992,7 +2048,7 @@ ifa_lookup(const char *ifa_name) { struct ipsec_addr_wrap *p = NULL, *h = NULL, *n = NULL; struct sockaddr_in6 *in6; - u_int8_t *s6; + uint8_t *s6; if (iftab == NULL) ifa_load(); @@ -2017,11 +2073,11 @@ ifa_lookup(const char *ifa_name) break; case AF_INET6: in6 = (struct sockaddr_in6 *)&n->address; - s6 = (u_int8_t *)&in6->sin6_addr.s6_addr; + s6 = (uint8_t *)&in6->sin6_addr.s6_addr; /* route/show.c and bgpd/util.c give KAME credit */ if (IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) { - u_int16_t tmp16; + uint16_t tmp16; /* for now we can not handle link local, * therefore bail for now @@ -2054,13 +2110,13 @@ ifa_lookup(const char *ifa_name) } void -set_ipmask(struct ipsec_addr_wrap *address, u_int8_t b) +set_ipmask(struct ipsec_addr_wrap *address, uint8_t b) { address->mask = b; } const struct ipsec_xf * -parse_xf(const char *name, u_int length, const struct ipsec_xf xfs[]) +parse_xf(const char *name, unsigned int length, const struct ipsec_xf xfs[]) { int i; @@ -2074,7 +2130,7 @@ parse_xf(const char *name, u_int length, const struct ipsec_xf xfs[]) } const char * -print_xf(u_int id, u_int length, const struct ipsec_xf xfs[]) +print_xf(unsigned int id, unsigned int length, const struct ipsec_xf xfs[]) { int i; @@ -2088,7 +2144,7 @@ print_xf(u_int id, u_int length, const struct ipsec_xf xfs[]) } size_t -keylength_xf(u_int saproto, u_int type, u_int id) +keylength_xf(unsigned int saproto, unsigned int type, unsigned int id) { int i; const struct ipsec_xf *xfs; @@ -2115,7 +2171,7 @@ keylength_xf(u_int saproto, u_int type, u_int id) } size_t -noncelength_xf(u_int type, u_int id) +noncelength_xf(unsigned int type, unsigned int id) { const struct ipsec_xf *xfs = ipsecencxfs; int i; @@ -2142,7 +2198,7 @@ print_policy(struct iked_policy *pol) struct iked_transform *xform; struct iked_flow *flow; struct iked_cfg *cfg; - u_int i, j; + unsigned int i, j; const struct ipsec_xf *xfs = NULL; print_verbose("ikev2"); @@ -2176,7 +2232,8 @@ print_policy(struct iked_policy *pol) RB_FOREACH(flow, iked_flows, &pol->pol_flows) { print_verbose(" from %s", - print_host(&flow->flow_src.addr, NULL, 0)); + print_host((struct sockaddr *)&flow->flow_src.addr, NULL, + 0)); if (flow->flow_src.addr_af != AF_UNSPEC && flow->flow_src.addr_net) print_verbose("/%d", flow->flow_src.addr_mask); @@ -2185,7 +2242,8 @@ print_policy(struct iked_policy *pol) ntohs(flow->flow_src.addr_port)); print_verbose(" to %s", - print_host(&flow->flow_dst.addr, NULL, 0)); + print_host((struct sockaddr *)&flow->flow_dst.addr, NULL, + 0)); if (flow->flow_dst.addr_af != AF_UNSPEC && flow->flow_dst.addr_net) print_verbose("/%d", flow->flow_dst.addr_mask); @@ -2196,13 +2254,15 @@ print_policy(struct iked_policy *pol) if ((pol->pol_flags & IKED_POLICY_DEFAULT) == 0) { print_verbose(" local %s", - print_host(&pol->pol_local.addr, NULL, 0)); + print_host((struct sockaddr *)&pol->pol_local.addr, NULL, + 0)); if (pol->pol_local.addr.ss_family != AF_UNSPEC && pol->pol_local.addr_net) print_verbose("/%d", pol->pol_local.addr_mask); print_verbose(" peer %s", - print_host(&pol->pol_peer.addr, NULL, 0)); + print_host((struct sockaddr *)&pol->pol_peer.addr, NULL, + 0)); if (pol->pol_peer.addr.ss_family != AF_UNSPEC && pol->pol_peer.addr_net) print_verbose("/%d", pol->pol_peer.addr_mask); @@ -2266,6 +2326,9 @@ print_policy(struct iked_policy *pol) if (pol->pol_peerid.id_length != 0) print_verbose(" dstid %s", pol->pol_peerid.id_data); + if (pol->pol_rekey) + print_verbose(" ikelifetime %u", pol->pol_rekey); + print_verbose(" lifetime %llu bytes %llu", pol->pol_lifetime.lt_seconds, pol->pol_lifetime.lt_bytes); @@ -2287,7 +2350,8 @@ print_policy(struct iked_policy *pol) cfg = &pol->pol_cfg[i]; print_verbose(" config %s %s", print_xf(cfg->cfg_type, cfg->cfg.address.addr_af, cpxfs), - print_host(&cfg->cfg.address.addr, NULL, 0)); + print_host((struct sockaddr *)&cfg->cfg.address.addr, NULL, + 0)); } if (pol->pol_tag[0] != '\0') @@ -2300,12 +2364,12 @@ print_policy(struct iked_policy *pol) } void -copy_transforms(u_int type, const struct ipsec_xf *xf, +copy_transforms(unsigned int type, const struct ipsec_xf *xf, const struct ipsec_xf *xfs, struct iked_transform *dst, size_t ndst, - u_int *n, struct iked_transform *src, size_t nsrc) + unsigned int *n, struct iked_transform *src, size_t nsrc) { - u_int i; + unsigned int i; struct iked_transform *a, *b; if (xf != NULL) { @@ -2332,26 +2396,31 @@ copy_transforms(u_int type, const struct ipsec_xf *xf, } int -create_ike(char *name, int af, u_int8_t ipproto, struct ipsec_hosts *hosts, +create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, struct ipsec_hosts *peers, struct ipsec_mode *ike_sa, - struct ipsec_mode *ipsec_sa, u_int8_t saproto, - u_int8_t flags, char *srcid, char *dstid, struct iked_lifetime *lt, + struct ipsec_mode *ipsec_sa, uint8_t saproto, + uint8_t flags, char *srcid, char *dstid, + uint32_t ikelifetime, struct iked_lifetime *lt, struct iked_auth *authtype, struct ipsec_filters *filter, struct ipsec_addr_wrap *ikecfg) { + char idstr[IKED_ID_SIZE]; + unsigned int idtype = IKEV2_ID_NONE; struct ipsec_addr_wrap *ipa, *ipb; struct iked_policy pol; struct iked_proposal prop[2]; - u_int j; + unsigned int j; struct iked_transform ikexforms[64], ipsecxforms[64]; struct iked_flow flows[64]; - static u_int policy_id = 0; + static unsigned int policy_id = 0; struct iked_cfg *cfg; bzero(&pol, sizeof(pol)); bzero(&prop, sizeof(prop)); + bzero(idstr, sizeof(idstr)); pol.pol_id = ++policy_id; + pol.pol_certreqtype = env->sc_certreqtype; pol.pol_af = af; pol.pol_saproto = saproto; pol.pol_ipproto = ipproto; @@ -2457,6 +2526,9 @@ create_ike(char *name, int af, u_int8_t ipproto, struct ipsec_hosts *hosts, pol.pol_af = ipb->af; } + if (ikelifetime) + pol.pol_rekey = ikelifetime; + if (lt) pol.pol_lifetime = *lt; else @@ -2556,6 +2628,8 @@ create_ike(char *name, int af, u_int8_t ipproto, struct ipsec_hosts *hosts, flows[j].flow_dst.addr_net = ipb->netaddress; flows[j].flow_dst.addr_port = hosts->dport; + flows[j].flow_ipproto = ipproto; + pol.pol_nflows++; RB_INSERT(iked_flows, &pol.pol_flows, &flows[j]); } @@ -2575,6 +2649,29 @@ create_ike(char *name, int af, u_int8_t ipproto, struct ipsec_hosts *hosts, cfg->cfg.address.addr_af = ipa->af; } + if (dstid) { + strlcpy(idstr, dstid, sizeof(idstr)); + idtype = pol.pol_peerid.id_type; + } else if (!pol.pol_peer.addr_net) { + print_host((struct sockaddr *)&pol.pol_peer.addr, idstr, + sizeof(idstr)); + switch (pol.pol_peer.addr.ss_family) { + case AF_INET: + idtype = IKEV2_ID_IPV4; + break; + case AF_INET6: + idtype = IKEV2_ID_IPV6; + break; + default: + log_warnx("%s: unknown address family", __func__); + break; + } + } + + /* Check if we have a raw public key for this peer */ + if (check_pubkey(idstr, idtype) != -1) + pol.pol_certreqtype = IKEV2_CERT_RSA_KEY; + config_setpolicy(env, &pol, PROC_IKEV2); rules++; diff --git a/iked/pfkey.c b/iked/pfkey.c index 343e372..413cdd3 100644 --- a/iked/pfkey.c +++ b/iked/pfkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfkey.c,v 1.23 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: pfkey.c,v 1.45 2015/08/26 02:09:29 jsg Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -19,20 +19,18 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include #include #include #include -#if defined(__OpenBSD__) #include #include -#endif #include #include #include +#include #include #include #include @@ -44,115 +42,85 @@ #define ROUNDUP(x) (((x) + (PFKEYV2_CHUNK - 1)) & ~(PFKEYV2_CHUNK - 1)) #define IOV_CNT 20 -#define PFKEYV2_CHUNK sizeof(u_int64_t) +#define PFKEYV2_CHUNK sizeof(uint64_t) +#define PFKEY_REPLY_TIMEOUT 1000 -static u_int32_t sadb_msg_seq = 0; -static u_int sadb_decoupled = 0; -static u_int sadb_ipv6refcnt = 0; +static uint32_t sadb_msg_seq = 0; +static unsigned int sadb_decoupled = 0; +static unsigned int sadb_ipv6refcnt = 0; static int pfkey_blockipv6 = 0; -static struct iked_timer pfkey_timer; -static struct iked_timer pfkey_pwrtimer; +static struct event pfkey_timer_ev; +static struct timeval pfkey_timer_tv; struct pfkey_message { SIMPLEQ_ENTRY(pfkey_message) pm_entry; - u_int8_t *pm_data; - ssize_t pm_lenght; + uint8_t *pm_data; + ssize_t pm_length; }; -SIMPLEQ_HEAD(, pfkey_message) pfkey_postponed = +SIMPLEQ_HEAD(, pfkey_message) pfkey_retry, pfkey_postponed = SIMPLEQ_HEAD_INITIALIZER(pfkey_postponed); struct pfkey_constmap { - u_int8_t pfkey_id; - u_int pfkey_ikeid; - u_int pfkey_fixedkey; + uint8_t pfkey_id; + unsigned int pfkey_ikeid; + unsigned int pfkey_fixedkey; }; static const struct pfkey_constmap pfkey_encr[] = { -#ifdef SADB_X_EALG_DES_IV64 { SADB_X_EALG_DES_IV64, IKEV2_XFORMENCR_DES_IV64 }, -#endif { SADB_EALG_DESCBC, IKEV2_XFORMENCR_DES }, { SADB_EALG_3DESCBC, IKEV2_XFORMENCR_3DES }, -#ifdef SADB_X_EALG_RC5 { SADB_X_EALG_RC5, IKEV2_XFORMENCR_RC5 }, -#endif -#ifdef SADB_X_EALG_IDEA { SADB_X_EALG_IDEA, IKEV2_XFORMENCR_IDEA }, -#endif -#ifdef SADB_X_EALG_RC5 { SADB_X_EALG_CAST, IKEV2_XFORMENCR_CAST }, -#endif -#ifdef SADB_X_EALG_BLF { SADB_X_EALG_BLF, IKEV2_XFORMENCR_BLOWFISH }, -#endif -#ifdef SADB_X_EALG_3IDEA { SADB_X_EALG_3IDEA, IKEV2_XFORMENCR_3IDEA }, -#endif -#ifdef SADB_X_EALG_DES_IV32 { SADB_X_EALG_DES_IV32, IKEV2_XFORMENCR_DES_IV32 }, -#endif -#ifdef SADB_X_EALG_RC4 { SADB_X_EALG_RC4, IKEV2_XFORMENCR_RC4 }, -#endif { SADB_EALG_NULL, IKEV2_XFORMENCR_NULL }, { SADB_X_EALG_AES, IKEV2_XFORMENCR_AES_CBC }, -#ifdef SADB_X_EALG_AESCTR { SADB_X_EALG_AESCTR, IKEV2_XFORMENCR_AES_CTR }, -#endif -#ifdef SADB_X_EALG_AESGCM16 { SADB_X_EALG_AESGCM16, IKEV2_XFORMENCR_AES_GCM_16 }, -#endif -#ifdef SADB_X_EALG_AESGMAC { SADB_X_EALG_AESGMAC, IKEV2_XFORMENCR_NULL_AES_GMAC }, -#endif { 0 } }; static const struct pfkey_constmap pfkey_integr[] = { { SADB_AALG_MD5HMAC, IKEV2_XFORMAUTH_HMAC_MD5_96 }, { SADB_AALG_SHA1HMAC, IKEV2_XFORMAUTH_HMAC_SHA1_96 }, -#ifdef SADB_X_AALG_DES { SADB_X_AALG_DES, IKEV2_XFORMAUTH_DES_MAC }, -#endif -#if defined(SADB_X_AALG_SHA2_256) && !defined(BROKEN_HMAC_SHA2_256) { SADB_X_AALG_SHA2_256, IKEV2_XFORMAUTH_HMAC_SHA2_256_128 }, -#endif -#ifdef SADB_X_AALG_SHA2_384 { SADB_X_AALG_SHA2_384, IKEV2_XFORMAUTH_HMAC_SHA2_384_192 }, -#endif -#ifdef SADB_X_AALG_SHA2_512 { SADB_X_AALG_SHA2_512, IKEV2_XFORMAUTH_HMAC_SHA2_512_256 }, -#endif { 0 } }; static const struct pfkey_constmap pfkey_satype[] = { { SADB_SATYPE_AH, IKEV2_SAPROTO_AH }, { SADB_SATYPE_ESP, IKEV2_SAPROTO_ESP }, + { SADB_X_SATYPE_IPCOMP, IKEV2_SAPROTO_IPCOMP }, { 0 } }; -int pfkey_map(const struct pfkey_constmap *, u_int16_t, u_int8_t *); -int pfkey_flow(int, u_int8_t, u_int8_t, struct iked_flow *); -int pfkey_sa(int, u_int8_t, u_int8_t, struct iked_childsa *); -int pfkey_sa_getspi(int, u_int8_t, struct iked_childsa *, u_int32_t *); -#if defined(_OPENBSD_IPSEC_API_VERSION) -int pfkey_sagroup(int, u_int8_t, u_int8_t, +int pfkey_map(const struct pfkey_constmap *, uint16_t, uint8_t *); +int pfkey_flow(int, uint8_t, uint8_t, struct iked_flow *); +int pfkey_sa(int, uint8_t, uint8_t, struct iked_childsa *); +int pfkey_sa_getspi(int, uint8_t, struct iked_childsa *, uint32_t *); +int pfkey_sagroup(int, uint8_t, uint8_t, struct iked_childsa *, struct iked_childsa *); -#endif int pfkey_write(int, struct sadb_msg *, struct iovec *, int, - u_int8_t **, ssize_t *); -int pfkey_reply(int, u_int8_t **, ssize_t *); + uint8_t **, ssize_t *); +int pfkey_reply(int, uint8_t **, ssize_t *); void pfkey_dispatch(int, short, void *); struct sadb_ident * - pfkey_id2ident(struct iked_id *, u_int); -void *pfkey_find_ext(u_int8_t *, ssize_t, int); + pfkey_id2ident(struct iked_id *, unsigned int); +void *pfkey_find_ext(uint8_t *, ssize_t, int); -void pfkey_timer_cb(struct iked *, void *); -void pfkey_process(struct iked *, struct pfkey_message *); +void pfkey_timer_cb(int, short, void *); +int pfkey_process(struct iked *, struct pfkey_message *); int pfkey_couple(int sd, struct iked_sas *sas, int couple) @@ -160,42 +128,43 @@ pfkey_couple(int sd, struct iked_sas *sas, int couple) struct iked_sa *sa; struct iked_flow *flow; struct iked_childsa *csa; - u_int old; const char *mode[] = { "coupled", "decoupled" }; /* Socket is not ready */ if (sd == -1) return (-1); - old = sadb_decoupled ? 1 : 0; - sadb_decoupled = couple ? 0 : 1; - - if (old == sadb_decoupled) + if (sadb_decoupled == !couple) return (0); log_debug("%s: kernel %s -> %s", __func__, - mode[old], mode[sadb_decoupled]); + mode[sadb_decoupled], mode[!sadb_decoupled]); + + /* Allow writes to the PF_KEY socket */ + sadb_decoupled = 0; RB_FOREACH(sa, iked_sas, sas) { TAILQ_FOREACH(csa, &sa->sa_childsas, csa_entry) { - if (!csa->csa_loaded && !sadb_decoupled) + if (!csa->csa_loaded && couple) (void)pfkey_sa_add(sd, csa, NULL); - else if (csa->csa_loaded && sadb_decoupled) + else if (csa->csa_loaded && !couple) (void)pfkey_sa_delete(sd, csa); } TAILQ_FOREACH(flow, &sa->sa_flows, flow_entry) { - if (!flow->flow_loaded && !sadb_decoupled) + if (!flow->flow_loaded && couple) (void)pfkey_flow_add(sd, flow); - else if (flow->flow_loaded && sadb_decoupled) + else if (flow->flow_loaded && !couple) (void)pfkey_flow_delete(sd, flow); } } + sadb_decoupled = !couple; + return (0); } int -pfkey_map(const struct pfkey_constmap *map, u_int16_t alg, u_int8_t *pfkalg) +pfkey_map(const struct pfkey_constmap *map, uint16_t alg, uint8_t *pfkalg) { int i; @@ -208,9 +177,8 @@ pfkey_map(const struct pfkey_constmap *map, u_int16_t alg, u_int8_t *pfkalg) } int -pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) +pfkey_flow(int sd, uint8_t satype, uint8_t action, struct iked_flow *flow) { -#if defined(_OPENBSD_IPSEC_API_VERSION) struct sadb_msg smsg; struct sadb_address sa_src, sa_dst, sa_local, sa_peer, sa_smask, sa_dmask; @@ -219,19 +187,16 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) struct sockaddr_storage ssrc, sdst, slocal, speer, smask, dmask; struct iovec iov[IOV_CNT]; int iov_cnt, ret = -1; - in_port_t sport, dport; - sport = dport = 0; sa_srcid = sa_dstid = NULL; bzero(&ssrc, sizeof(ssrc)); bzero(&smask, sizeof(smask)); memcpy(&ssrc, &flow->flow_src.addr, sizeof(ssrc)); memcpy(&smask, &flow->flow_src.addr, sizeof(smask)); - if ((sport = flow->flow_src.addr_port) != 0) - dport = 0xffff; - socket_af((struct sockaddr *)&ssrc, sport); - socket_af((struct sockaddr *)&smask, dport); + socket_af((struct sockaddr *)&ssrc, flow->flow_src.addr_port); + socket_af((struct sockaddr *)&smask, flow->flow_src.addr_port ? + 0xffff : 0); switch (flow->flow_src.addr_af) { case AF_INET: @@ -242,7 +207,7 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) case AF_INET6: prefixlen2mask6(flow->flow_src.addr_net ? flow->flow_src.addr_mask : 128, - (u_int32_t *)((struct sockaddr_in6 *) + (uint32_t *)((struct sockaddr_in6 *) &smask)->sin6_addr.s6_addr); break; default: @@ -256,10 +221,9 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) bzero(&dmask, sizeof(dmask)); memcpy(&sdst, &flow->flow_dst.addr, sizeof(sdst)); memcpy(&dmask, &flow->flow_dst.addr, sizeof(dmask)); - if ((sport = flow->flow_dst.addr_port) != 0) - dport = 0xffff; - socket_af((struct sockaddr *)&sdst, sport); - socket_af((struct sockaddr *)&dmask, dport); + socket_af((struct sockaddr *)&sdst, flow->flow_dst.addr_port); + socket_af((struct sockaddr *)&dmask, flow->flow_dst.addr_port ? + 0xffff : 0); switch (flow->flow_dst.addr_af) { case AF_INET: @@ -270,7 +234,7 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) case AF_INET6: prefixlen2mask6(flow->flow_dst.addr_net ? flow->flow_dst.addr_mask : 128, - (u_int32_t *)((struct sockaddr_in6 *) + (uint32_t *)((struct sockaddr_in6 *) &dmask)->sin6_addr.s6_addr); break; default: @@ -345,11 +309,11 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) (sizeof(sa_peer) + ROUNDUP(speer.ss_len)) / 8; /* local id */ - sa_srcid = pfkey_id2ident(flow->flow_srcid, + sa_srcid = pfkey_id2ident(IKESA_SRCID(flow->flow_ikesa), SADB_EXT_IDENTITY_SRC); /* peer id */ - sa_dstid = pfkey_id2ident(flow->flow_dstid, + sa_dstid = pfkey_id2ident(IKESA_DSTID(flow->flow_ikesa), SADB_EXT_IDENTITY_DST); } @@ -452,234 +416,27 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) if (sa_dstid) free(sa_dstid); -#else /* !_OPENBSD_IPSEC_API_VERSION */ - - struct sadb_msg smsg; - struct sadb_address sa_src, sa_dst; - struct sadb_x_ipsecrequest sa_ipsec; - struct sadb_x_policy sa_policy, *sa_polid; - struct sadb_x_sa2 sa_2; - struct sockaddr_storage ssrc, sdst, slocal, speer; - struct iovec iov[IOV_CNT]; - int iov_cnt, ret = -1; - in_port_t sport, dport; - u_int8_t smask, dmask; - u_int8_t zeropad[8]; - size_t padlen; - u_int8_t *reply = NULL; - ssize_t rlen; - - bzero(&ssrc, sizeof(ssrc)); - memcpy(&ssrc, &flow->flow_src.addr, sizeof(ssrc)); - sport = flow->flow_src.addr_port; - socket_af((struct sockaddr *)&ssrc, sport); - - switch (flow->flow_src.addr_af) { - case AF_INET: - smask = flow->flow_src.addr_net ? - flow->flow_src.addr_mask : 32; - break; - case AF_INET6: - smask = flow->flow_src.addr_net ? - flow->flow_src.addr_mask : 128; - break; - default: - log_warnx("%s: unsupported address family %d", - __func__, flow->flow_src.addr_af); - return (-1); - } - - bzero(&sdst, sizeof(sdst)); - memcpy(&sdst, &flow->flow_dst.addr, sizeof(sdst)); - dport = flow->flow_dst.addr_port; - socket_af((struct sockaddr *)&sdst, dport); - - switch (flow->flow_dst.addr_af) { - case AF_INET: - dmask = flow->flow_dst.addr_net ? - flow->flow_dst.addr_mask : 32; - break; - case AF_INET6: - dmask = flow->flow_dst.addr_net ? - flow->flow_dst.addr_mask : 128; - break; - default: - log_warnx("%s: unsupported address family %d", - __func__, flow->flow_dst.addr_af); - return (-1); - } - - bzero(&slocal, sizeof(slocal)); - bzero(&speer, sizeof(speer)); - bzero(&zeropad, sizeof(zeropad)); - if (flow->flow_local == NULL) { - slocal.ss_family = flow->flow_src.addr_af; - speer.ss_family = flow->flow_dst.addr_af; - } else if (flow->flow_dir == IPSEC_DIR_INBOUND) { - memcpy(&speer, &flow->flow_local->addr, sizeof(slocal)); - memcpy(&slocal, &flow->flow_peer->addr, sizeof(speer)); - } else { - memcpy(&slocal, &flow->flow_local->addr, sizeof(slocal)); - memcpy(&speer, &flow->flow_peer->addr, sizeof(speer)); - } - socket_af((struct sockaddr *)&slocal, 0); - socket_af((struct sockaddr *)&speer, 0); - - bzero(&smsg, sizeof(smsg)); - smsg.sadb_msg_version = PF_KEY_V2; - smsg.sadb_msg_seq = ++sadb_msg_seq; - smsg.sadb_msg_pid = getpid(); - smsg.sadb_msg_len = sizeof(smsg) / 8; - smsg.sadb_msg_type = action; - smsg.sadb_msg_satype = SADB_SATYPE_UNSPEC; - - bzero(&sa_2, sizeof(sa_2)); - sa_2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - sa_2.sadb_x_sa2_len = sizeof(sa_2) / 8; - sa_2.sadb_x_sa2_mode = IPSEC_MODE_TUNNEL; - - bzero(&sa_src, sizeof(sa_src)); - sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; - sa_src.sadb_address_proto = IPSEC_ULPROTO_ANY; //flow->flow_ipproto - sa_src.sadb_address_prefixlen = smask; - sa_src.sadb_address_len = ROUNDUP(sizeof(sa_src) + SS_LEN(&ssrc)) / 8; - - bzero(&sa_dst, sizeof(sa_dst)); - sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; - sa_dst.sadb_address_proto = IPSEC_ULPROTO_ANY; //flow->flow_ipproto; - sa_dst.sadb_address_prefixlen = dmask; - sa_dst.sadb_address_len = ROUNDUP(sizeof(sa_dst) + SS_LEN(&sdst)) / 8; - - bzero(&sa_policy, sizeof(sa_policy)); - sa_policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY; - sa_policy.sadb_x_policy_dir = flow->flow_dir; - - switch (flow->flow_type) { - case SADB_X_FLOW_TYPE_DENY: - sa_policy.sadb_x_policy_type = IPSEC_POLICY_DISCARD; - sa_policy.sadb_x_policy_len = sizeof(sa_policy) / 8; - break; - default: - sa_policy.sadb_x_policy_type = IPSEC_POLICY_IPSEC; - bzero(&sa_ipsec, sizeof(sa_ipsec)); - sa_ipsec.sadb_x_ipsecrequest_proto = - satype == SADB_SATYPE_AH ? IPPROTO_AH : IPPROTO_ESP; - sa_ipsec.sadb_x_ipsecrequest_mode = IPSEC_MODE_TUNNEL; /* XXX */ - sa_ipsec.sadb_x_ipsecrequest_level = - flow->flow_dir == IPSEC_DIR_INBOUND ? - IPSEC_LEVEL_USE : IPSEC_LEVEL_REQUIRE; - sa_ipsec.sadb_x_ipsecrequest_len = sizeof(sa_ipsec) + - SS_LEN(&slocal) + SS_LEN(&speer); - padlen = ROUNDUP(sa_ipsec.sadb_x_ipsecrequest_len) - - sa_ipsec.sadb_x_ipsecrequest_len; - sa_ipsec.sadb_x_ipsecrequest_len += padlen; - sa_policy.sadb_x_policy_len = - (sizeof(sa_policy) + - sa_ipsec.sadb_x_ipsecrequest_len) / 8; - break; - } - - iov_cnt = 0; - - /* header */ - iov[iov_cnt].iov_base = &smsg; - iov[iov_cnt].iov_len = sizeof(smsg); - iov_cnt++; - - /* add flow SA2 */ - iov[iov_cnt].iov_base = &sa_2; - iov[iov_cnt].iov_len = sizeof(sa_2); - smsg.sadb_msg_len += sa_2.sadb_x_sa2_len; - iov_cnt++; - - /* add source address */ - iov[iov_cnt].iov_base = &sa_src; - iov[iov_cnt].iov_len = sizeof(sa_src); - iov_cnt++; - iov[iov_cnt].iov_base = &ssrc; - iov[iov_cnt].iov_len = SS_LEN(&ssrc); - smsg.sadb_msg_len += sa_src.sadb_address_len; - iov_cnt++; - - /* add destination address */ - iov[iov_cnt].iov_base = &sa_dst; - iov[iov_cnt].iov_len = sizeof(sa_dst); - iov_cnt++; - iov[iov_cnt].iov_base = &sdst; - iov[iov_cnt].iov_len = SS_LEN(&sdst); - smsg.sadb_msg_len += sa_dst.sadb_address_len; - iov_cnt++; - - /* add policy extension */ - iov[iov_cnt].iov_base = &sa_policy; - iov[iov_cnt].iov_len = sizeof(sa_policy); - smsg.sadb_msg_len += sa_policy.sadb_x_policy_len; - iov_cnt++; - - if (sa_policy.sadb_x_policy_type == IPSEC_POLICY_IPSEC) { - iov[iov_cnt].iov_base = &sa_ipsec; - iov[iov_cnt].iov_len = sizeof(sa_ipsec); - iov_cnt++; - iov[iov_cnt].iov_base = &slocal; - iov[iov_cnt].iov_len = SS_LEN(&slocal); - iov_cnt++; - iov[iov_cnt].iov_base = &speer; - iov[iov_cnt].iov_len = SS_LEN(&speer); - if (padlen) { - iov_cnt++; - iov[iov_cnt].iov_base = zeropad; - iov[iov_cnt].iov_len = padlen; - } - iov_cnt++; - } - - ret = -1; - if (pfkey_write(sd, &smsg, iov, iov_cnt, &reply, &rlen) != 0) - goto done; - - if ((sa_polid = pfkey_find_ext(reply, rlen, - SADB_X_EXT_POLICY)) == NULL) { - log_debug("%s: erronous reply", __func__); - goto done; - } - flow->flow_id = sa_polid->sadb_x_policy_id; - - log_debug("%s: flow with policy id 0x%x", __func__, flow->flow_id); - ret = 0; - - done: - free(reply); - -#endif /* !_OPENBSD_IPSEC_API_VERSION */ - return (ret); } int -pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) +pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) { struct sadb_msg smsg; struct sadb_sa sadb; struct sadb_address sa_src, sa_dst; struct sadb_key sa_authkey, sa_enckey; struct sadb_lifetime sa_ltime_hard, sa_ltime_soft; -#if defined(_OPENBSD_IPSEC_API_VERSION) struct sadb_x_udpencap udpencap; struct sadb_x_tag sa_tag; char *tag = NULL; struct sadb_x_tap sa_tap; -#else - struct sadb_x_sa2 sa_2; -#if defined(HAVE_APPLE_NATT) - struct sadb_sa_natt natt; -#endif -#endif struct sockaddr_storage ssrc, sdst; struct sadb_ident *sa_srcid, *sa_dstid; struct iked_lifetime *lt; struct iked_policy *pol; struct iovec iov[IOV_CNT]; - u_int32_t jitter; + uint32_t jitter; int iov_cnt; sa_srcid = sa_dstid = NULL; @@ -720,34 +477,23 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) sadb.sadb_sa_state = SADB_SASTATE_MATURE; sadb.sadb_sa_replay = 64; -#if defined(_OPENBSD_IPSEC_API_VERSION) - /* XXX we don't support transport mode, yet */ - sadb.sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL; + if (!sa->csa_transport) + sadb.sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL; if (sa->csa_esn) sadb.sadb_sa_flags |= SADB_X_SAFLAGS_ESN; -#else - bzero(&sa_2, sizeof(sa_2)); - sa_2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - sa_2.sadb_x_sa2_len = sizeof(sa_2) / 8; - sa_2.sadb_x_sa2_mode = IPSEC_MODE_TUNNEL; /* XXX */ -#endif bzero(&sa_src, sizeof(sa_src)); - sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(SS_LEN(&ssrc))) / 8; + sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; bzero(&sa_dst, sizeof(sa_dst)); - sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(SS_LEN(&sdst))) / 8; + sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; bzero(&sa_authkey, sizeof(sa_authkey)); bzero(&sa_enckey, sizeof(sa_enckey)); -#if defined(_OPENBSD_IPSEC_API_VERSION) bzero(&udpencap, sizeof udpencap); -#elif defined(HAVE_APPLE_NATT) - bzero(&natt, sizeof(natt)); -#endif bzero(&sa_ltime_hard, sizeof(sa_ltime_hard)); bzero(&sa_ltime_soft, sizeof(sa_ltime_soft)); @@ -761,66 +507,54 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) sa_ltime_hard.sadb_lifetime_bytes = lt->lt_bytes; sa_ltime_hard.sadb_lifetime_addtime = lt->lt_seconds; + /* double the lifetime for IP compression */ + if (satype == SADB_X_SATYPE_IPCOMP) + sa_ltime_hard.sadb_lifetime_addtime *= 2; + sa_ltime_soft.sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; sa_ltime_soft.sadb_lifetime_len = sizeof(sa_ltime_soft) / 8; /* set randomly to 85-95% */ jitter = 850 + arc4random_uniform(100); sa_ltime_soft.sadb_lifetime_bytes = - (lt->lt_bytes * jitter) / 1000; + (sa_ltime_hard.sadb_lifetime_bytes * jitter) / 1000; sa_ltime_soft.sadb_lifetime_addtime = - (lt->lt_seconds * jitter) / 1000; + (sa_ltime_hard.sadb_lifetime_addtime * jitter) / 1000; } /* XXX handle NULL encryption or NULL auth or combined encr/auth */ if (action == SADB_ADD && !ibuf_length(sa->csa_integrkey) && !ibuf_length(sa->csa_encrkey) && - satype != SADB_X_SATYPE_IPCOMP -#if defined(_OPENBSD_IPSEC_API_VERSION) - && satype != SADB_X_SATYPE_IPIP -#endif - ) { - + satype != SADB_X_SATYPE_IPCOMP && satype != SADB_X_SATYPE_IPIP) { log_warnx("%s: no key specified", __func__); return (-1); } - if (sa->csa_ikesa->sa_udpencap && sa->csa_ikesa->sa_natt) { -#if defined(_OPENBSD_IPSEC_API_VERSION) + if (satype == SADB_SATYPE_ESP && + sa->csa_ikesa->sa_udpencap && sa->csa_ikesa->sa_natt) { sadb.sadb_sa_flags |= SADB_X_SAFLAGS_UDPENCAP; udpencap.sadb_x_udpencap_exttype = SADB_X_EXT_UDPENCAP; udpencap.sadb_x_udpencap_len = sizeof(udpencap) / 8; udpencap.sadb_x_udpencap_port = sa->csa_ikesa->sa_peer.addr_port; -#elif defined(HAVE_APPLE_NATT) - sadb.sadb_sa_flags |= SADB_X_EXT_NATT; - /* XXX check NAT detection for local/peer hash instead */ - if (sa->csa_dir == IPSP_DIRECTION_OUT) - sadb.sadb_sa_flags |= SADB_X_EXT_NATT_KEEPALIVE; - else - sadb.sadb_sa_flags |= SADB_X_EXT_NATT_DETECTED_PEER; - natt.sadb_sa_natt_port = - ntohs(sa->csa_ikesa->sa_peer.addr_port); -#else -#warning PFKEYv2 NAT-T not supported -#endif - log_debug("%s: udpencap port %u", __func__, - ntohs(sa->csa_ikesa->sa_peer.addr_port)); + + log_debug("%s: udpencap port %d", __func__, + ntohs(udpencap.sadb_x_udpencap_port)); } - if (sa->csa_integrxf) + if (sa->csa_integrid) if (pfkey_map(pfkey_integr, - sa->csa_integrxf->xform_id, &sadb.sadb_sa_auth) == -1) { + sa->csa_integrid, &sadb.sadb_sa_auth) == -1) { log_warnx("%s: unsupported integrity algorithm %s", - __func__, print_map(sa->csa_integrxf->xform_id, + __func__, print_map(sa->csa_integrid, ikev2_xformauth_map)); return (-1); } - if (sa->csa_encrxf) + if (sa->csa_encrid) if (pfkey_map(pfkey_encr, - sa->csa_encrxf->xform_id, &sadb.sadb_sa_encrypt) == -1) { + sa->csa_encrid, &sadb.sadb_sa_encrypt) == -1) { log_warnx("%s: unsupported encryption algorithm %s", - __func__, print_map(sa->csa_encrxf->xform_id, + __func__, print_map(sa->csa_encrid, ikev2_xformencr_map)); return (-1); } @@ -841,13 +575,23 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) 8 * ibuf_size(sa->csa_encrkey); } - /* local id */ - sa_srcid = pfkey_id2ident(sa->csa_srcid, SADB_EXT_IDENTITY_SRC); + /* we only support deflate */ + if (satype == SADB_X_SATYPE_IPCOMP) + sadb.sadb_sa_encrypt = SADB_X_CALG_DEFLATE; - /* peer id */ - sa_dstid = pfkey_id2ident(sa->csa_dstid, SADB_EXT_IDENTITY_DST); + /* Note that we need to swap the IDs for incoming SAs (SADB_UPDATE) */ + if (action != SADB_UPDATE) { + sa_srcid = pfkey_id2ident( + IKESA_SRCID(sa->csa_ikesa), SADB_EXT_IDENTITY_SRC); + sa_dstid = pfkey_id2ident( + IKESA_DSTID(sa->csa_ikesa), SADB_EXT_IDENTITY_DST); + } else { + sa_srcid = pfkey_id2ident( + IKESA_DSTID(sa->csa_ikesa), SADB_EXT_IDENTITY_SRC); + sa_dstid = pfkey_id2ident( + IKESA_SRCID(sa->csa_ikesa), SADB_EXT_IDENTITY_DST); + } -#if defined(_OPENBSD_IPSEC_API_VERSION) tag = sa->csa_ikesa->sa_tag; if (tag != NULL && *tag != '\0') { bzero(&sa_tag, sizeof(sa_tag)); @@ -864,7 +608,6 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) sa_tap.sadb_x_tap_len = sizeof(sa_tap) / 8; sa_tap.sadb_x_tap_unit = pol->pol_tap; } -#endif send: iov_cnt = 0; @@ -877,31 +620,15 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) /* sa */ iov[iov_cnt].iov_base = &sadb; iov[iov_cnt].iov_len = sizeof(sadb); -#if defined(HAVE_APPLE_NATT) - if (natt.sadb_sa_natt_port) { - iov_cnt++; - iov[iov_cnt].iov_base = &natt; - iov[iov_cnt].iov_len = sizeof(natt); - sadb.sadb_sa_len += sizeof(natt) / 8; - } -#endif smsg.sadb_msg_len += sadb.sadb_sa_len; iov_cnt++; -#if !defined(_OPENBSD_IPSEC_API_VERSION) - /* sa2 */ - iov[iov_cnt].iov_base = &sa_2; - iov[iov_cnt].iov_len = sizeof(sa_2); - smsg.sadb_msg_len += sa_2.sadb_x_sa2_len; - iov_cnt++; -#endif - /* src addr */ iov[iov_cnt].iov_base = &sa_src; iov[iov_cnt].iov_len = sizeof(sa_src); iov_cnt++; iov[iov_cnt].iov_base = &ssrc; - iov[iov_cnt].iov_len = ROUNDUP(SS_LEN(&ssrc)); + iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); smsg.sadb_msg_len += sa_src.sadb_address_len; iov_cnt++; @@ -910,7 +637,7 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) iov[iov_cnt].iov_len = sizeof(sa_dst); iov_cnt++; iov[iov_cnt].iov_base = &sdst; - iov[iov_cnt].iov_len = ROUNDUP(SS_LEN(&sdst)); + iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); smsg.sadb_msg_len += sa_dst.sadb_address_len; iov_cnt++; @@ -930,14 +657,12 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) iov_cnt++; } -#if defined(_OPENBSD_IPSEC_API_VERSION) if (udpencap.sadb_x_udpencap_len) { iov[iov_cnt].iov_base = &udpencap; iov[iov_cnt].iov_len = sizeof(udpencap); smsg.sadb_msg_len += udpencap.sadb_x_udpencap_len; iov_cnt++; } -#endif if (sa_enckey.sadb_key_len) { /* encryption key */ @@ -977,7 +702,6 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) iov_cnt++; } -#if defined(_OPENBSD_IPSEC_API_VERSION) if (tag != NULL) { /* tag identity */ iov[iov_cnt].iov_base = &sa_tag; @@ -996,14 +720,125 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) smsg.sadb_msg_len += sa_tap.sadb_x_tap_len; iov_cnt++; } -#endif return (pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL)); } int -pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, - u_int32_t *spip) +pfkey_sa_last_used(int sd, struct iked_childsa *sa, uint64_t *last_used) +{ + struct sadb_msg *msg, smsg; + struct sadb_address sa_src, sa_dst; + struct sadb_sa sadb; + struct sadb_lifetime *sa_life; + struct sockaddr_storage ssrc, sdst; + struct iovec iov[IOV_CNT]; + uint8_t *data; + ssize_t n; + int iov_cnt, ret = -1; + uint8_t satype; + + *last_used = 0; + + if (pfkey_map(pfkey_satype, sa->csa_saproto, &satype) == -1) + return (-1); + + bzero(&ssrc, sizeof(ssrc)); + memcpy(&ssrc, &sa->csa_local->addr, sizeof(ssrc)); + if (socket_af((struct sockaddr *)&ssrc, 0) == -1) { + log_warn("%s: invalid address", __func__); + return (-1); + } + + bzero(&sdst, sizeof(sdst)); + memcpy(&sdst, &sa->csa_peer->addr, sizeof(sdst)); + if (socket_af((struct sockaddr *)&sdst, 0) == -1) { + log_warn("%s: invalid address", __func__); + return (-1); + } + + bzero(&smsg, sizeof(smsg)); + smsg.sadb_msg_version = PF_KEY_V2; + smsg.sadb_msg_seq = ++sadb_msg_seq; + smsg.sadb_msg_pid = getpid(); + smsg.sadb_msg_len = sizeof(smsg) / 8; + smsg.sadb_msg_type = SADB_GET; + smsg.sadb_msg_satype = satype; + + bzero(&sadb, sizeof(sadb)); + sadb.sadb_sa_len = sizeof(sadb) / 8; + sadb.sadb_sa_exttype = SADB_EXT_SA; + sadb.sadb_sa_spi = htonl(sa->csa_spi.spi); + sadb.sadb_sa_state = SADB_SASTATE_MATURE; + sadb.sadb_sa_replay = 64; + + bzero(&sa_src, sizeof(sa_src)); + sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; + sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + + bzero(&sa_dst, sizeof(sa_dst)); + sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; + sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + + iov_cnt = 0; + + /* header */ + iov[iov_cnt].iov_base = &smsg; + iov[iov_cnt].iov_len = sizeof(smsg); + iov_cnt++; + + /* sa */ + iov[iov_cnt].iov_base = &sadb; + iov[iov_cnt].iov_len = sizeof(sadb); + smsg.sadb_msg_len += sadb.sadb_sa_len; + iov_cnt++; + + /* src addr */ + iov[iov_cnt].iov_base = &sa_src; + iov[iov_cnt].iov_len = sizeof(sa_src); + iov_cnt++; + iov[iov_cnt].iov_base = &ssrc; + iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); + smsg.sadb_msg_len += sa_src.sadb_address_len; + iov_cnt++; + + /* dst addr */ + iov[iov_cnt].iov_base = &sa_dst; + iov[iov_cnt].iov_len = sizeof(sa_dst); + iov_cnt++; + iov[iov_cnt].iov_base = &sdst; + iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); + smsg.sadb_msg_len += sa_dst.sadb_address_len; + iov_cnt++; + + if ((ret = pfkey_write(sd, &smsg, iov, iov_cnt, &data, &n)) != 0) + return (-1); + + msg = (struct sadb_msg *)data; + if (msg->sadb_msg_errno != 0) { + errno = msg->sadb_msg_errno; + ret = -1; + log_warn("%s: message", __func__); + goto done; + } + if ((sa_life = pfkey_find_ext(data, n, SADB_X_EXT_LIFETIME_LASTUSE)) + == NULL) { + /* has never been used */ + ret = -1; + goto done; + } + *last_used = sa_life->sadb_lifetime_usetime; + log_debug("%s: last_used %llu", __func__, *last_used); + +done: + bzero(data, n); + free(data); + return (ret); +} + +int +pfkey_sa_getspi(int sd, uint8_t satype, struct iked_childsa *sa, + uint32_t *spip) { struct sadb_msg *msg, smsg; struct sadb_address sa_src, sa_dst; @@ -1011,12 +846,9 @@ pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, struct sadb_spirange sa_spirange; struct sockaddr_storage ssrc, sdst; struct iovec iov[IOV_CNT]; - u_int8_t *data; + uint8_t *data; ssize_t n; int iov_cnt, ret = -1; -#if !defined(_OPENBSD_IPSEC_API_VERSION) - struct sadb_x_sa2 sa_2; -#endif bzero(&ssrc, sizeof(ssrc)); memcpy(&ssrc, &sa->csa_local->addr, sizeof(ssrc)); @@ -1040,32 +872,21 @@ pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, smsg.sadb_msg_type = SADB_GETSPI; smsg.sadb_msg_satype = satype; -#if !defined(_OPENBSD_IPSEC_API_VERSION) - bzero(&sa_2, sizeof(sa_2)); - sa_2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - sa_2.sadb_x_sa2_len = sizeof(sa_2) / 8; - sa_2.sadb_x_sa2_mode = IPSEC_MODE_TUNNEL; -#endif - bzero(&sa_spirange, sizeof(sa_spirange)); sa_spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE; sa_spirange.sadb_spirange_len = sizeof(sa_spirange) / 8; sa_spirange.sadb_spirange_min = 0x100; - sa_spirange.sadb_spirange_max = 0xffffffff; + sa_spirange.sadb_spirange_max = (satype == SADB_X_SATYPE_IPCOMP) ? + (CPI_PRIVATE_MIN - 1) : 0xffffffff; + sa_spirange.sadb_spirange_reserved = 0; bzero(&sa_src, sizeof(sa_src)); - sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(SS_LEN(&ssrc))) / 8; + sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; - sa_src.sadb_address_proto = IPSEC_ULPROTO_ANY; - sa_src.sadb_address_prefixlen = (ssrc.ss_family == AF_INET ? - sizeof(struct in_addr) : sizeof(struct in6_addr)) << 3; bzero(&sa_dst, sizeof(sa_dst)); - sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(SS_LEN(&sdst))) / 8; + sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; - sa_dst.sadb_address_proto = IPSEC_ULPROTO_ANY; - sa_dst.sadb_address_prefixlen = (sdst.ss_family == AF_INET ? - sizeof(struct in_addr) : sizeof(struct in6_addr)) << 3; iov_cnt = 0; @@ -1074,20 +895,18 @@ pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, iov[iov_cnt].iov_len = sizeof(smsg); iov_cnt++; -#if !defined(_OPENBSD_IPSEC_API_VERSION) - /* extended SA header */ - iov[iov_cnt].iov_base = &sa_2; - iov[iov_cnt].iov_len = sizeof(sa_2); - smsg.sadb_msg_len += sa_2.sadb_x_sa2_len; + /* SPI range */ + iov[iov_cnt].iov_base = &sa_spirange; + iov[iov_cnt].iov_len = sizeof(sa_spirange); + smsg.sadb_msg_len += sa_spirange.sadb_spirange_len; iov_cnt++; -#endif /* src addr */ iov[iov_cnt].iov_base = &sa_src; iov[iov_cnt].iov_len = sizeof(sa_src); iov_cnt++; iov[iov_cnt].iov_base = &ssrc; - iov[iov_cnt].iov_len = ROUNDUP(SS_LEN(&ssrc)); + iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); smsg.sadb_msg_len += sa_src.sadb_address_len; iov_cnt++; @@ -1096,16 +915,10 @@ pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, iov[iov_cnt].iov_len = sizeof(sa_dst); iov_cnt++; iov[iov_cnt].iov_base = &sdst; - iov[iov_cnt].iov_len = ROUNDUP(SS_LEN(&sdst)); + iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); smsg.sadb_msg_len += sa_dst.sadb_address_len; iov_cnt++; - /* SPI range */ - iov[iov_cnt].iov_base = &sa_spirange; - iov[iov_cnt].iov_len = sizeof(sa_spirange); - smsg.sadb_msg_len += sa_spirange.sadb_spirange_len; - iov_cnt++; - *spip = 0; if ((ret = pfkey_write(sd, &smsg, iov, iov_cnt, &data, &n)) != 0) @@ -1131,9 +944,8 @@ pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, return (ret); } -#if defined(_OPENBSD_IPSEC_API_VERSION) int -pfkey_sagroup(int sd, u_int8_t satype1, u_int8_t action, +pfkey_sagroup(int sd, uint8_t satype1, uint8_t action, struct iked_childsa *sa1, struct iked_childsa *sa2) { struct sadb_msg smsg; @@ -1143,7 +955,7 @@ pfkey_sagroup(int sd, u_int8_t satype1, u_int8_t action, struct sadb_protocol sa_proto; struct iovec iov[IOV_CNT]; int iov_cnt; - u_int8_t satype2; + uint8_t satype2; if (pfkey_map(pfkey_satype, sa2->csa_saproto, &satype2) == -1) return (-1); @@ -1244,11 +1056,10 @@ pfkey_sagroup(int sd, u_int8_t satype1, u_int8_t action, return (pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL)); } -#endif int pfkey_write(int sd, struct sadb_msg *smsg, struct iovec *iov, int iov_cnt, - u_int8_t **datap, ssize_t *lenp) + uint8_t **datap, ssize_t *lenp) { ssize_t n, len = smsg->sadb_msg_len * 8; @@ -1279,14 +1090,36 @@ pfkey_write(int sd, struct sadb_msg *smsg, struct iovec *iov, int iov_cnt, } int -pfkey_reply(int sd, u_int8_t **datap, ssize_t *lenp) +pfkey_reply(int sd, uint8_t **datap, ssize_t *lenp) { struct pfkey_message *pm; struct sadb_msg hdr; ssize_t len; - u_int8_t *data; + uint8_t *data; + struct pollfd pfd[1]; + int n; + + pfd[0].fd = sd; + pfd[0].events = POLLIN; for (;;) { + /* + * We should actually expect the reply to get lost + * as PF_KEY is an unreliable service per the specs. + * Currently we do this by setting a short timeout, + * and if it is not readable in that time, we fail + * the read. + */ + n = poll(pfd, 1, PFKEY_REPLY_TIMEOUT / 1000); + if (n == -1) { + log_warn("%s: poll() failed", __func__); + return (-1); + } + if (n == 0) { + log_warnx("%s: no reply from PF_KEY", __func__); + return (-1); + } + if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) { log_warn("%s: short recv", __func__); return (-1); @@ -1297,11 +1130,13 @@ pfkey_reply(int sd, u_int8_t **datap, ssize_t *lenp) return (-1); } - len = hdr.sadb_msg_len * PFKEYV2_CHUNK; - if ((data = malloc(len)) == NULL) { + if ((data = reallocarray(NULL, hdr.sadb_msg_len, + PFKEYV2_CHUNK)) == NULL) { log_warn("%s: malloc", __func__); return (-1); } + len = hdr.sadb_msg_len * PFKEYV2_CHUNK; + if (read(sd, data, len) != len) { log_warnx("%s: short read", __func__); free(data); @@ -1310,19 +1145,26 @@ pfkey_reply(int sd, u_int8_t **datap, ssize_t *lenp) /* XXX: Only one message can be outstanding. */ if (hdr.sadb_msg_seq == sadb_msg_seq && - hdr.sadb_msg_pid == (u_int32_t)getpid()) + hdr.sadb_msg_pid == (uint32_t)getpid()) break; + /* ignore messages for other processes */ + if (hdr.sadb_msg_pid != 0 && + hdr.sadb_msg_pid != (uint32_t)getpid()) { + free(data); + continue; + } + /* not the reply, enqueue */ if ((pm = malloc(sizeof(*pm))) == NULL) { - log_warn("%s", __func__); + log_warn("%s: malloc", __func__); free(data); return (-1); } pm->pm_data = data; - pm->pm_lenght = len; + pm->pm_length = len; SIMPLEQ_INSERT_TAIL(&pfkey_postponed, pm, pm_entry); - timer_register(NULL, &pfkey_timer, 1); + evtimer_add(&pfkey_timer_ev, &pfkey_timer_tv); } if (datap) { @@ -1345,7 +1187,7 @@ pfkey_reply(int sd, u_int8_t **datap, ssize_t *lenp) int pfkey_flow_add(int fd, struct iked_flow *flow) { - u_int8_t satype; + uint8_t satype; if (flow->flow_loaded) return (0); @@ -1370,7 +1212,7 @@ pfkey_flow_add(int fd, struct iked_flow *flow) int pfkey_flow_delete(int fd, struct iked_flow *flow) { - u_int8_t satype; + uint8_t satype; if (!flow->flow_loaded) return (0); @@ -1393,20 +1235,10 @@ pfkey_flow_delete(int fd, struct iked_flow *flow) } int -pfkey_block(int fd, int af, u_int action) +pfkey_block(int fd, int af, unsigned int action) { struct iked_flow flow; -#if !defined(_OPENBSD_IPSEC_API_VERSION) && !defined(XXX_BLOCK_IPV6) - /* - * XXX This is work in progress, I didn't have time to make - * XXX this work with PFKEYv2 on KAME-based platforms yet. - */ -#warning PFKEYv2 IPv6 blocking not supported - log_debug("%s: not yet supported on this platform, ignored", __func__); - return (0); -#endif - if (!pfkey_blockipv6) return (0); @@ -1433,9 +1265,9 @@ pfkey_block(int fd, int af, u_int action) } int -pfkey_sa_init(int fd, struct iked_childsa *sa, u_int32_t *spi) +pfkey_sa_init(int fd, struct iked_childsa *sa, uint32_t *spi) { - u_int8_t satype; + uint8_t satype; if (pfkey_map(pfkey_satype, sa->csa_saproto, &satype) == -1) return (-1); @@ -1451,8 +1283,8 @@ pfkey_sa_init(int fd, struct iked_childsa *sa, u_int32_t *spi) int pfkey_sa_add(int fd, struct iked_childsa *sa, struct iked_childsa *last) { - u_int8_t satype; - u_int cmd; + uint8_t satype; + unsigned int cmd; if (pfkey_map(pfkey_satype, sa->csa_saproto, &satype) == -1) return (-1); @@ -1466,19 +1298,27 @@ pfkey_sa_add(int fd, struct iked_childsa *sa, struct iked_childsa *last) print_spi(sa->csa_spi.spi, 4)); if (pfkey_sa(fd, satype, cmd, sa) == -1) { - if (cmd == SADB_ADD) + if (cmd == SADB_ADD) { (void)pfkey_sa_delete(fd, sa); - return (-1); + return (-1); + } + if (sa->csa_allocated && !sa->csa_loaded && errno == ESRCH) { + /* Needed for recoupling local SAs */ + log_debug("%s: SADB_UPDATE on local SA returned ESRCH," + " trying SADB_ADD", __func__); + if (pfkey_sa(fd, satype, SADB_ADD, sa) == -1) + return (-1); + } else { + return (-1); + } } if (last && cmd == SADB_ADD) { -#if defined(_OPENBSD_IPSEC_API_VERSION) if (pfkey_sagroup(fd, satype, SADB_X_GRPSPIS, sa, last) == -1) { (void)pfkey_sa_delete(fd, sa); return (-1); } -#endif } sa->csa_loaded = 1; @@ -1488,7 +1328,7 @@ pfkey_sa_add(int fd, struct iked_childsa *sa, struct iked_childsa *last) int pfkey_sa_delete(int fd, struct iked_childsa *sa) { - u_int8_t satype; + uint8_t satype; if (!sa->csa_loaded || sa->csa_spi.spi == 0) return (0); @@ -1504,7 +1344,7 @@ pfkey_sa_delete(int fd, struct iked_childsa *sa) } int -pfkey_flush(int sd, u_int what) +pfkey_flush(int sd) { struct sadb_msg smsg; struct iovec iov[IOV_CNT]; @@ -1515,7 +1355,7 @@ pfkey_flush(int sd, u_int what) smsg.sadb_msg_seq = ++sadb_msg_seq; smsg.sadb_msg_pid = getpid(); smsg.sadb_msg_len = sizeof(smsg) / 8; - smsg.sadb_msg_type = what; + smsg.sadb_msg_type = SADB_FLUSH; smsg.sadb_msg_satype = SADB_SATYPE_UNSPEC; iov_cnt = 0; @@ -1528,10 +1368,10 @@ pfkey_flush(int sd, u_int what) } struct sadb_ident * -pfkey_id2ident(struct iked_id *id, u_int exttype) +pfkey_id2ident(struct iked_id *id, unsigned int exttype) { char idstr[IKED_ID_SIZE]; - u_int type; + unsigned int type; size_t len; struct sadb_ident *sa_id; @@ -1572,27 +1412,6 @@ pfkey_id2ident(struct iked_id *id, u_int exttype) return (sa_id); } -void -pfkey_pwrtimer_cb(struct iked *env, void *arg) -{ -#ifdef __APPLE__ - static struct timeval waketime = { 0, 0 }; - struct timeval tv; - size_t size = sizeof(tv); - - if (sysctlbyname("kern.waketime", &tv, &size, NULL, 0) == 0) { - if (waketime.tv_sec != 0 && - memcmp(&waketime, &tv, sizeof(waketime)) != 0) { - log_info("%s: after power resume", __func__); - pfkey_flush(env->sc_pfkey, SADB_FLUSH); - } - memcpy(&waketime, &tv, sizeof(waketime)); - } -#endif - - timer_register(env, &pfkey_pwrtimer, 3); -} - int pfkey_socket(void) { @@ -1604,8 +1423,7 @@ pfkey_socket(void) if ((fd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) == -1) fatal("pfkey_socket: failed to open PF_KEY socket"); - pfkey_flush(fd, SADB_FLUSH); - pfkey_flush(fd, SADB_X_SPDFLUSH); + pfkey_flush(fd); return (fd); } @@ -1616,6 +1434,11 @@ pfkey_init(struct iked *env, int fd) struct sadb_msg smsg; struct iovec iov; + /* Set up a timer to process messages deferred by the pfkey_reply */ + pfkey_timer_tv.tv_sec = 1; + pfkey_timer_tv.tv_usec = 0; + evtimer_set(&pfkey_timer_ev, pfkey_timer_cb, env); + /* Register the pfkey socket event handler */ env->sc_pfkey = fd; event_set(&env->sc_pfkeyev, env->sc_pfkey, @@ -1651,13 +1474,6 @@ pfkey_init(struct iked *env, int fd) if (pfkey_write(fd, &smsg, &iov, 1, NULL, NULL)) fatal("pfkey_init: failed to set up AH acquires"); - /* Set up a timer to process messages deferred by the pfkey_reply */ - timer_initialize(env, &pfkey_timer, pfkey_timer_cb, NULL); - - /* Run a timer to flush the SADB after power resume */ - timer_initialize(env, &pfkey_pwrtimer, pfkey_pwrtimer_cb, NULL); - timer_register(env, &pfkey_pwrtimer, 3); - if (env->sc_opts & IKED_OPT_NOIPV6BLOCKING) return; @@ -1668,15 +1484,15 @@ pfkey_init(struct iked *env, int fd) } void * -pfkey_find_ext(u_int8_t *data, ssize_t len, int type) +pfkey_find_ext(uint8_t *data, ssize_t len, int type) { struct sadb_ext *ext = (struct sadb_ext *)(data + sizeof(struct sadb_msg)); - while (ext && ((u_int8_t *)ext - data < len)) { + while (ext && ((uint8_t *)ext - data < len)) { if (ext->sadb_ext_type == type) return (ext); - ext = (struct sadb_ext *)((u_int8_t *)ext + + ext = (struct sadb_ext *)((uint8_t *)ext + ext->sadb_ext_len * PFKEYV2_CHUNK); } @@ -1687,10 +1503,10 @@ void pfkey_dispatch(int sd, short event, void *arg) { struct iked *env = (struct iked *)arg; - struct pfkey_message pm; + struct pfkey_message pm, *pmp; struct sadb_msg hdr; ssize_t len; - u_int8_t *data; + uint8_t *data; if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) { log_warn("%s: short recv", __func__); @@ -1702,100 +1518,128 @@ pfkey_dispatch(int sd, short event, void *arg) return; } - len = hdr.sadb_msg_len * PFKEYV2_CHUNK; - if ((data = malloc(len)) == NULL) { + if ((data = reallocarray(NULL, hdr.sadb_msg_len, PFKEYV2_CHUNK)) + == NULL) { log_warn("%s: malloc", __func__); return; } + len = hdr.sadb_msg_len * PFKEYV2_CHUNK; + if (read(sd, data, len) != len) { log_warn("%s: short read", __func__); free(data); return; } - pm.pm_data = data; - pm.pm_lenght = len; - pfkey_process(env, &pm); + /* Try postponed requests first, so we do in-order processing */ + if (!SIMPLEQ_EMPTY(&pfkey_postponed)) + pfkey_timer_cb(0, 0, env); - free(data); + pm.pm_data = data; + pm.pm_length = len; + + if (pfkey_process(env, &pm) == -1 && + (pmp = calloc(1, sizeof(*pmp))) != NULL) { + pmp->pm_data = data; + pmp->pm_length = len; + log_debug("%s: pfkey_process is busy, retry later", __func__); + SIMPLEQ_INSERT_TAIL(&pfkey_postponed, pmp, pm_entry); + evtimer_add(&pfkey_timer_ev, &pfkey_timer_tv); + } else { + free(data); + } } void -pfkey_timer_cb(struct iked *env, void *arg) +pfkey_timer_cb(int unused, short event, void *arg) { + struct iked *env = arg; struct pfkey_message *pm; + SIMPLEQ_INIT(&pfkey_retry); while (!SIMPLEQ_EMPTY(&pfkey_postponed)) { pm = SIMPLEQ_FIRST(&pfkey_postponed); SIMPLEQ_REMOVE_HEAD(&pfkey_postponed, pm_entry); - pfkey_process(env, pm); - free(pm->pm_data); - free(pm); + if (pfkey_process(env, pm) == -1) { + log_debug("%s: pfkey_process is busy, retry later", + __func__); + SIMPLEQ_INSERT_TAIL(&pfkey_retry, pm, pm_entry); + } else { + free(pm->pm_data); + free(pm); + } } + /* move from retry to postponed */ + while ((pm = SIMPLEQ_FIRST(&pfkey_retry)) != NULL) { + SIMPLEQ_REMOVE_HEAD(&pfkey_retry, pm_entry); + SIMPLEQ_INSERT_TAIL(&pfkey_postponed, pm, pm_entry); + } + if (!SIMPLEQ_EMPTY(&pfkey_postponed)) + evtimer_add(&pfkey_timer_ev, &pfkey_timer_tv); } -void +/* + * pfkey_process returns 0 if the message has been processed and -1 if + * the system is busy and the the message should be passed again, later. + */ +int pfkey_process(struct iked *env, struct pfkey_message *pm) { struct iked_spi spi; struct sadb_sa *sa; struct sadb_lifetime *sa_ltime; struct sadb_msg *hdr; -#if defined(_OPENBSD_IPSEC_API_VERSION) struct sadb_msg smsg; struct iked_addr peer; struct iked_flow flow; struct sadb_address *sa_addr; struct sadb_protocol *sa_proto; struct sadb_x_policy sa_pol; - struct sadb_x_sa2 sa_2; - struct sockaddr_storage *ssrc, *sdst, *smask, *dmask, *speer; + struct sockaddr *ssrc, *sdst, *smask, *dmask, *speer; struct iovec iov[IOV_CNT]; - int iov_cnt, sd = env->sc_pfkey; - u_int8_t *reply; + int ret = 0, iov_cnt, sd; + uint8_t *reply; ssize_t rlen; const char *errmsg = NULL; -#else - struct iked_addr peer; - struct sadb_address *sa_addr; - struct sockaddr_storage *speer; - struct sadb_x_policy *sa_pol; - struct iked_flow *flow; -#endif - u_int8_t *data = pm->pm_data; - ssize_t len = pm->pm_lenght; + uint8_t *data = pm->pm_data; + ssize_t len = pm->pm_length; + size_t slen; if (!env || !data || !len) - return; + return (0); + sd = env->sc_pfkey; hdr = (struct sadb_msg *)data; switch (hdr->sadb_msg_type) { case SADB_ACQUIRE: - /* Get peer from the acquire message */ + bzero(&flow, sizeof(flow)); + bzero(&peer, sizeof(peer)); + if ((sa_addr = pfkey_find_ext(data, len, SADB_EXT_ADDRESS_DST)) == NULL) { log_debug("%s: no peer address", __func__); - return; + return (0); } - speer = (struct sockaddr_storage *)(sa_addr + 1); - bzero(&peer, sizeof(peer)); - peer.addr_af = speer->ss_family; + speer = (struct sockaddr *)(sa_addr + 1); + peer.addr_af = speer->sa_family; peer.addr_port = htons(socket_getport(speer)); - memcpy(&peer.addr, speer, sizeof(*speer)); + if ((slen = speer->sa_len) > sizeof(peer.addr)) { + log_debug("%s: invalid peer address len", __func__); + return (0); + } + memcpy(&peer.addr, speer, slen); if (socket_af((struct sockaddr *)&peer.addr, peer.addr_port) == -1) { log_debug("%s: invalid address", __func__); - return; + return (0); } + flow.flow_peer = &peer; + log_debug("%s: acquire request (peer %s)", __func__, print_host(speer, NULL, 0)); -#if defined(_OPENBSD_IPSEC_API_VERSION) - /* Get the matching flow */ - bzero(&flow, sizeof(flow)); - flow.flow_peer = &peer; - + /* get the matching flow */ bzero(&smsg, sizeof(smsg)); smsg.sadb_msg_version = PF_KEY_V2; smsg.sadb_msg_seq = ++sadb_msg_seq; @@ -1821,7 +1665,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) if (pfkey_write(sd, &smsg, iov, iov_cnt, &reply, &rlen)) { log_warnx("%s: failed to get a policy", __func__); - return; + return (0); } if ((sa_addr = pfkey_find_ext(reply, rlen, @@ -1829,14 +1673,18 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) errmsg = "flow source address"; goto out; } - ssrc = (struct sockaddr_storage *)(sa_addr + 1); - flow.flow_src.addr_af = ssrc->ss_family; + ssrc = (struct sockaddr *)(sa_addr + 1); + flow.flow_src.addr_af = ssrc->sa_family; flow.flow_src.addr_port = htons(socket_getport(ssrc)); - memcpy(&flow.flow_src.addr, ssrc, sizeof(*ssrc)); + if ((slen = ssrc->sa_len) > sizeof(flow.flow_src.addr)) { + log_debug("%s: invalid src address len", __func__); + return (0); + } + memcpy(&flow.flow_src.addr, ssrc, slen); if (socket_af((struct sockaddr *)&flow.flow_src.addr, flow.flow_src.addr_port) == -1) { log_debug("%s: invalid address", __func__); - return; + return (0); } if ((sa_addr = pfkey_find_ext(reply, rlen, @@ -1844,14 +1692,18 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) errmsg = "flow destination address"; goto out; } - sdst = (struct sockaddr_storage *)(sa_addr + 1); - flow.flow_dst.addr_af = sdst->ss_family; + sdst = (struct sockaddr *)(sa_addr + 1); + flow.flow_dst.addr_af = sdst->sa_family; flow.flow_dst.addr_port = htons(socket_getport(sdst)); - memcpy(&flow.flow_dst.addr, sdst, sizeof(*sdst)); + if ((slen = sdst->sa_len) > sizeof(flow.flow_dst.addr)) { + log_debug("%s: invalid dst address len", __func__); + return (0); + } + memcpy(&flow.flow_dst.addr, sdst, slen); if (socket_af((struct sockaddr *)&flow.flow_dst.addr, flow.flow_dst.addr_port) == -1) { log_debug("%s: invalid address", __func__); - return; + return (0); } if ((sa_addr = pfkey_find_ext(reply, rlen, @@ -1859,8 +1711,8 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) errmsg = "flow source mask"; goto out; } - smask = (struct sockaddr_storage *)(sa_addr + 1); - switch (smask->ss_family) { + smask = (struct sockaddr *)(sa_addr + 1); + switch (smask->sa_family) { case AF_INET: flow.flow_src.addr_mask = mask2prefixlen((struct sockaddr *)smask); @@ -1876,7 +1728,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) default: log_debug("%s: bad address family", __func__); free(reply); - return; + return (0); } if ((sa_addr = pfkey_find_ext(reply, rlen, @@ -1884,8 +1736,8 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) errmsg = "flow destination mask"; goto out; } - dmask = (struct sockaddr_storage *)(sa_addr + 1); - switch (dmask->ss_family) { + dmask = (struct sockaddr *)(sa_addr + 1); + switch (dmask->sa_family) { case AF_INET: flow.flow_dst.addr_mask = mask2prefixlen((struct sockaddr *)dmask); @@ -1901,7 +1753,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) default: log_debug("%s: bad address family", __func__); free(reply); - return; + return (0); } if ((sa_proto = pfkey_find_ext(reply, rlen, @@ -1917,45 +1769,18 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) print_host(sdst, NULL, 0), print_host(dmask, NULL, 0), print_host(speer, NULL, 0)); - ikev2_acquire_sa(env, &flow); + ret = ikev2_acquire_sa(env, &flow); out: if (errmsg) log_warnx("%s: %s wasn't found", __func__, errmsg); free(reply); -#elif defined(SADB_X_EXT_POLICY) - if ((sa_pol = pfkey_find_ext(data, len, - SADB_X_EXT_POLICY)) == NULL) { - log_debug("%s: no policy extension", __func__); - return; - } - - RB_FOREACH(flow, iked_flows, &env->sc_activeflows) { - /* - * Find existing active policy by policy Id. - * XXX This should use another tree that uses - * XXX the x_policy_id as lookup key. - */ - if (flow->flow_id == sa_pol->sadb_x_policy_id) { - log_debug("%s: flow %s policy id 0x%x ", - __func__, - flow->flow_dir == IPSP_DIRECTION_IN ? - "in" : "out", flow->flow_id); - ikev2_acquire_sa(env, flow); - break; - } - } -#else -#warning PFKEYv2 SADB_ACQUIRE not implemented - log_debug("%s: SADB_ACQUIRE not yet supported here, ignored", - __func__); -#endif break; case SADB_EXPIRE: if ((sa = pfkey_find_ext(data, len, SADB_EXT_SA)) == NULL) { log_warnx("%s: SA extension wasn't found", __func__); - return; + return (0); } if ((sa_ltime = pfkey_find_ext(data, len, SADB_EXT_LIFETIME_SOFT)) == NULL && @@ -1963,7 +1788,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) SADB_EXT_LIFETIME_HARD)) == NULL) { log_warnx("%s: lifetime extension wasn't found", __func__); - return; + return (0); } spi.spi = ntohl(sa->sadb_sa_spi); spi.spi_size = 4; @@ -1974,11 +1799,15 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) case SADB_SATYPE_ESP: spi.spi_protoid = IKEV2_SAPROTO_ESP; break; + case SADB_X_SATYPE_IPCOMP: + spi.spi_size = 2; + spi.spi_protoid = IKEV2_SAPROTO_IPCOMP; + break; default: - log_warnx("%s: usupported SA type %d spi %s", + log_warnx("%s: unsupported SA type %d spi %s", __func__, hdr->sadb_msg_satype, print_spi(spi.spi, spi.spi_size)); - return; + return (0); } log_debug("%s: SA %s is expired, pending %s", __func__, @@ -1987,9 +1816,10 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) "rekeying" : "deletion"); if (sa_ltime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT) - ikev2_rekey_sa(env, &spi); + ret = ikev2_rekey_sa(env, &spi); else - ikev2_drop_sa(env, &spi); + ret = ikev2_drop_sa(env, &spi); break; } + return (ret); } diff --git a/iked/policy.c b/iked/policy.c index 7cff708..1c85e98 100644 --- a/iked/policy.c +++ b/iked/policy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: policy.c,v 1.23 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: policy.c,v 1.40 2015/10/01 10:59:23 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -17,18 +17,10 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include #include #include -#include "openbsd-compat/sys-tree.h" - -#include -#include -#include -#include -#include -#include +#include #include #include @@ -65,6 +57,8 @@ int policy_lookup(struct iked *env, struct iked_message *msg) { struct iked_policy pol; + char *s, idstr[IKED_ID_SIZE]; + if (msg->msg_sa != NULL && msg->msg_sa->sa_policy != NULL) { /* Existing SA with policy */ @@ -76,6 +70,15 @@ policy_lookup(struct iked *env, struct iked_message *msg) pol.pol_af = msg->msg_peer.ss_family; memcpy(&pol.pol_peer.addr, &msg->msg_peer, sizeof(msg->msg_peer)); memcpy(&pol.pol_local.addr, &msg->msg_local, sizeof(msg->msg_local)); + if (msg->msg_id.id_type && + ikev2_print_id(&msg->msg_id, idstr, IKED_ID_SIZE) == 0 && + (s = strchr(idstr, '/')) != NULL) { + pol.pol_peerid.id_type = msg->msg_id.id_type; + pol.pol_peerid.id_length = strlen(s+1); + strlcpy(pol.pol_peerid.id_data, s+1, + sizeof(pol.pol_peerid.id_data)); + log_debug("%s: peerid '%s'", __func__, s+1); + } /* Try to find a matching policy for this message */ if ((msg->msg_policy = policy_test(env, &pol)) != NULL) @@ -97,7 +100,7 @@ policy_test(struct iked *env, struct iked_policy *key) { struct iked_policy *p = NULL, *pol = NULL; struct iked_flow *flow = NULL, *flowkey; - u_int cnt = 0; + unsigned int cnt = 0; p = TAILQ_FIRST(&env->sc_policies); while (p != NULL) { @@ -132,6 +135,15 @@ policy_test(struct iked *env, struct iked_policy *key) p = TAILQ_NEXT(p, pol_entry); continue; } + /* make sure the peer ID matches */ + if (key->pol_peerid.id_type && + (key->pol_peerid.id_type != p->pol_peerid.id_type || + memcmp(key->pol_peerid.id_data, + p->pol_peerid.id_data, + sizeof(key->pol_peerid.id_data)) != 0)) { + p = TAILQ_NEXT(p, pol_entry); + continue; + } /* Policy matched */ pol = p; @@ -202,6 +214,16 @@ policy_unref(struct iked *env, struct iked_policy *pol) return; if (--(pol->pol_refcnt) <= 0) config_free_policy(env, pol); + else { + struct iked_sa *tmp; + int count = 0; + + TAILQ_FOREACH(tmp, &pol->pol_sapeers, sa_peer_entry) + count++; + if (count != pol->pol_refcnt) + log_warnx("%s: ERROR pol %p pol_refcnt %d != count %d", + __func__, pol, pol->pol_refcnt, count); + } } void @@ -209,19 +231,28 @@ sa_state(struct iked *env, struct iked_sa *sa, int state) { const char *a; const char *b; + int ostate = sa->sa_state; - a = print_map(sa->sa_state, ikev2_state_map); + a = print_map(ostate, ikev2_state_map); b = print_map(state, ikev2_state_map); - if (state > sa->sa_state) { + sa->sa_state = state; + if (ostate != IKEV2_STATE_INIT && + !sa_stateok(sa, state)) { + log_debug("%s: cannot switch: %s -> %s", __func__, a, b); + sa->sa_state = ostate; + } else if (ostate != sa->sa_state) { switch (state) { case IKEV2_STATE_ESTABLISHED: case IKEV2_STATE_CLOSED: log_info("%s: %s -> %s from %s to %s policy '%s'", __func__, a, b, - print_host(&sa->sa_peer.addr, NULL, 0), - print_host(&sa->sa_local.addr, NULL, 0), - sa->sa_policy->pol_name); + print_host((struct sockaddr *)&sa->sa_peer.addr, + NULL, 0), + print_host((struct sockaddr *)&sa->sa_local.addr, + NULL, 0), + sa->sa_policy ? sa->sa_policy->pol_name : + ""); break; default: log_debug("%s: %s -> %s", __func__, a, b); @@ -229,20 +260,19 @@ sa_state(struct iked *env, struct iked_sa *sa, int state) } } - sa->sa_state = state; } void -sa_stateflags(struct iked_sa *sa, u_int flags) +sa_stateflags(struct iked_sa *sa, unsigned int flags) { - u_int require; + unsigned int require; if (sa->sa_state > IKEV2_STATE_SA_INIT) require = sa->sa_statevalid; else require = sa->sa_stateinit; - log_debug("%s: 0x%02x -> 0x%02x %s (required 0x%02x %s)", __func__, + log_debug("%s: 0x%04x -> 0x%04x %s (required 0x%04x %s)", __func__, sa->sa_stateflags, sa->sa_stateflags | flags, print_bits(sa->sa_stateflags | flags, IKED_REQ_BITS), require, print_bits(require, IKED_REQ_BITS)); @@ -253,7 +283,7 @@ sa_stateflags(struct iked_sa *sa, u_int flags) int sa_stateok(struct iked_sa *sa, int state) { - u_int require; + unsigned int require; if (sa->sa_state < state) return (0); @@ -265,8 +295,8 @@ sa_stateok(struct iked_sa *sa, int state) if (state == IKEV2_STATE_SA_INIT || state == IKEV2_STATE_VALID || - state == IKEV2_STATE_EAP) { - log_debug("%s: %s flags 0x%02x, require 0x%02x %s", __func__, + state == IKEV2_STATE_EAP_VALID) { + log_debug("%s: %s flags 0x%04x, require 0x%04x %s", __func__, print_map(state, ikev2_state_map), (sa->sa_stateflags & require), require, print_bits(require, IKED_REQ_BITS)); @@ -278,38 +308,58 @@ sa_stateok(struct iked_sa *sa, int state) } struct iked_sa * -sa_new(struct iked *env, u_int64_t ispi, u_int64_t rspi, - u_int initiator, struct iked_policy *pol) +sa_new(struct iked *env, uint64_t ispi, uint64_t rspi, + unsigned int initiator, struct iked_policy *pol) { struct iked_sa *sa; + struct iked_sa *old; struct iked_id *localid; - u_int diff; + unsigned int diff; if ((ispi == 0 && rspi == 0) || (sa = sa_lookup(env, ispi, rspi, initiator)) == NULL) { /* Create new SA */ + if (!initiator && ispi == 0) { + log_debug("%s: cannot create responder IKE SA w/o ispi", + __func__); + return (NULL); + } sa = config_new_sa(env, initiator); + if (sa == NULL) { + log_debug("%s: failed to allocate IKE SA", __func__); + return (NULL); + } + if (!initiator) + sa->sa_hdr.sh_ispi = ispi; + old = RB_INSERT(iked_sas, &env->sc_sas, sa); + if (old && old != sa) { + log_warnx("%s: duplicate IKE SA", __func__); + config_free_sa(env, sa); + return (NULL); + } } - if (sa == NULL) { - log_debug("%s: failed to get sa", __func__); - return (NULL); - } - if (sa->sa_policy == NULL) + /* Update rspi in the initator case */ + if (initiator && sa->sa_hdr.sh_rspi == 0 && rspi) + sa->sa_hdr.sh_rspi = rspi; + + if (sa->sa_policy == NULL) { sa->sa_policy = pol; - else + TAILQ_INSERT_TAIL(&pol->pol_sapeers, sa, sa_peer_entry); + } else pol = sa->sa_policy; - sa->sa_statevalid = IKED_REQ_AUTH|IKED_REQ_SA; + sa->sa_statevalid = IKED_REQ_AUTH|IKED_REQ_AUTHVALID|IKED_REQ_SA; if (pol != NULL && pol->pol_auth.auth_eap) { - sa->sa_statevalid |= IKED_REQ_CERT; + sa->sa_statevalid |= IKED_REQ_CERT|IKED_REQ_EAPVALID; } else if (pol != NULL && pol->pol_auth.auth_method != IKEV2_AUTH_SHARED_KEY_MIC) { - sa->sa_statevalid |= IKED_REQ_VALID|IKED_REQ_CERT; + sa->sa_statevalid |= IKED_REQ_CERTVALID|IKED_REQ_CERT; } if (initiator) { localid = &sa->sa_iid; - diff = IKED_REQ_VALID|IKED_REQ_SA; + diff = IKED_REQ_CERTVALID|IKED_REQ_AUTHVALID|IKED_REQ_SA| + IKED_REQ_EAPVALID; sa->sa_stateinit = sa->sa_statevalid & ~diff; sa->sa_statevalid = sa->sa_statevalid & diff; } else @@ -322,14 +372,6 @@ sa_new(struct iked *env, u_int64_t ispi, u_int64_t rspi, return (NULL); } - if (sa->sa_hdr.sh_ispi == 0) - sa->sa_hdr.sh_ispi = ispi; - if (sa->sa_hdr.sh_rspi == 0) - sa->sa_hdr.sh_rspi = rspi; - - /* Re-insert node into the tree */ - RB_INSERT(iked_sas, &env->sc_sas, sa); - return (sa); } @@ -340,6 +382,12 @@ sa_free(struct iked *env, struct iked_sa *sa) print_spi(sa->sa_hdr.sh_ispi, 8), print_spi(sa->sa_hdr.sh_rspi, 8)); + /* IKE rekeying running? */ + if (sa->sa_next) { + RB_REMOVE(iked_sas, &env->sc_sas, sa->sa_next); + config_free_sa(env, sa->sa_next); + } + RB_REMOVE(iked_sas, &env->sc_sas, sa); config_free_sa(env, sa); } @@ -364,45 +412,37 @@ sa_free_flows(struct iked *env, struct iked_saflows *head) int sa_address(struct iked_sa *sa, struct iked_addr *addr, - struct sockaddr_storage *peer, int initiator) + struct sockaddr_storage *peer) { - struct iked_policy *pol = sa->sa_policy; - - if (pol == NULL) { - log_debug("%s: invalid policy", __func__); - return (-1); - } - bzero(addr, sizeof(*addr)); addr->addr_af = peer->ss_family; - addr->addr_port = htons(socket_getport(peer)); + addr->addr_port = htons(socket_getport((struct sockaddr *)peer)); memcpy(&addr->addr, peer, sizeof(*peer)); if (socket_af((struct sockaddr *)&addr->addr, addr->addr_port) == -1) { log_debug("%s: invalid address", __func__); return (-1); } - - if (addr == &sa->sa_peer) { - /* XXX Re-insert node into the tree */ - RB_REMOVE(iked_sapeers, &pol->pol_sapeers, sa); - memcpy(&sa->sa_polpeer, initiator ? &pol->pol_peer : - &sa->sa_peer, sizeof(sa->sa_polpeer)); - RB_INSERT(iked_sapeers, &pol->pol_sapeers, sa); - } - return (0); } void -childsa_free(struct iked_childsa *sa) +childsa_free(struct iked_childsa *csa) { - ibuf_release(sa->csa_encrkey); - ibuf_release(sa->csa_integrkey); - free(sa); + if (csa->csa_children) { + /* XXX should not happen */ + log_warnx("%s: trying to remove CSA %p children %u", + __func__, csa, csa->csa_children); + return; + } + if (csa->csa_parent) + csa->csa_parent->csa_children--; + ibuf_release(csa->csa_encrkey); + ibuf_release(csa->csa_integrkey); + free(csa); } struct iked_childsa * -childsa_lookup(struct iked_sa *sa, u_int64_t spi, u_int8_t protoid) +childsa_lookup(struct iked_sa *sa, uint64_t spi, uint8_t protoid) { struct iked_childsa *csa; @@ -424,13 +464,13 @@ flow_free(struct iked_flow *flow) } struct iked_sa * -sa_lookup(struct iked *env, u_int64_t ispi, u_int64_t rspi, - u_int initiator) +sa_lookup(struct iked *env, uint64_t ispi, uint64_t rspi, + unsigned int initiator) { struct iked_sa *sa, key; key.sa_hdr.sh_ispi = ispi; - key.sa_hdr.sh_rspi = rspi; + /* key.sa_hdr.sh_rspi = rspi; */ key.sa_hdr.sh_initiator = initiator; if ((sa = RB_FIND(iked_sas, &env->sc_sas, &key)) != NULL) { @@ -438,6 +478,7 @@ sa_lookup(struct iked *env, u_int64_t ispi, u_int64_t rspi, /* Validate if SPIr matches */ if ((sa->sa_hdr.sh_rspi != 0) && + (rspi != 0) && (sa->sa_hdr.sh_rspi != rspi)) return (NULL); } @@ -448,8 +489,10 @@ sa_lookup(struct iked *env, u_int64_t ispi, u_int64_t rspi, static __inline int sa_cmp(struct iked_sa *a, struct iked_sa *b) { - if (a->sa_hdr.sh_initiator != b->sa_hdr.sh_initiator) - return (-2); + if (a->sa_hdr.sh_initiator > b->sa_hdr.sh_initiator) + return (-1); + if (a->sa_hdr.sh_initiator < b->sa_hdr.sh_initiator) + return (1); if (a->sa_hdr.sh_ispi > b->sa_hdr.sh_ispi) return (-1); @@ -471,20 +514,11 @@ sa_cmp(struct iked_sa *a, struct iked_sa *b) return (0); } -struct iked_sa * -sa_peer_lookup(struct iked_policy *pol, struct sockaddr_storage *peer) -{ - struct iked_sa key; - - memcpy(&key.sa_polpeer.addr, peer, sizeof(*peer)); - return (RB_FIND(iked_sapeers, &pol->pol_sapeers, &key)); -} - static __inline int -sa_peer_cmp(struct iked_sa *a, struct iked_sa *b) +sa_addrpool_cmp(struct iked_sa *a, struct iked_sa *b) { - return (sockaddr_cmp((struct sockaddr *)&a->sa_polpeer.addr, - (struct sockaddr *)&b->sa_polpeer.addr, -1)); + return (sockaddr_cmp((struct sockaddr *)&a->sa_addrpool->addr, + (struct sockaddr *)&b->sa_addrpool->addr, -1)); } struct iked_user * @@ -547,10 +581,8 @@ flow_cmp(struct iked_flow *a, struct iked_flow *b) return (diff); } -#ifndef __clang_analyzer__ RB_GENERATE(iked_sas, iked_sa, sa_entry, sa_cmp); -RB_GENERATE(iked_sapeers, iked_sa, sa_peer_entry, sa_peer_cmp); +RB_GENERATE(iked_addrpool, iked_sa, sa_addrpool_entry, sa_addrpool_cmp); RB_GENERATE(iked_users, iked_user, usr_entry, user_cmp); RB_GENERATE(iked_activesas, iked_childsa, csa_node, childsa_cmp); RB_GENERATE(iked_flows, iked_flow, flow_node, flow_cmp); -#endif diff --git a/iked/proc.c b/iked/proc.c index 331d84b..18b219b 100644 --- a/iked/proc.c +++ b/iked/proc.c @@ -1,7 +1,7 @@ -/* $OpenBSD: proc.c,v 1.9 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: proc.c,v 1.23 2015/08/21 11:59:28 reyk Exp $ */ /* - * Copyright (c) 2010-2013 Reyk Floeter + * Copyright (c) 2010 - 2014 Reyk Floeter * Copyright (c) 2008 Pierre-Yves Ritschard * * Permission to use, copy, modify, and distribute this software for any @@ -17,11 +17,15 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" -#include "openbsd-compat/sys-tree.h" -#include +#include #include +#include +#include + +#include +#include +#include +#include #include #include @@ -32,40 +36,98 @@ #include #include -#include - #include "iked.h" -void proc_setup(struct privsep *); +void proc_open(struct privsep *, struct privsep_proc *, + struct privsep_proc *, size_t); +void proc_close(struct privsep *); +int proc_ispeer(struct privsep_proc *, unsigned int, enum privsep_procid); void proc_shutdown(struct privsep_proc *); void proc_sig_handler(int, short, void *); +void proc_range(struct privsep *, enum privsep_procid, int *, int *); + +int +proc_ispeer(struct privsep_proc *procs, unsigned int nproc, + enum privsep_procid type) +{ + unsigned int i; + + for (i = 0; i < nproc; i++) + if (procs[i].p_id == type) + return (1); + return (0); +} void -proc_init(struct privsep *ps, struct privsep_proc *p, u_int nproc) +proc_init(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc) { - u_int i; + unsigned int i, j, src, dst; + struct privsep_pipes *pp; /* - * Called from parent + * Allocate pipes for all process instances (incl. parent) + * + * - ps->ps_pipes: N:M mapping + * N source processes connected to M destination processes: + * [src][instances][dst][instances], for example + * [PROC_RELAY][3][PROC_CA][3] + * + * - ps->ps_pp: per-process 1:M part of ps->ps_pipes + * Each process instance has a destination array of socketpair fds: + * [dst][instances], for example + * [PROC_PARENT][0] + */ + for (src = 0; src < PROC_MAX; src++) { + /* Allocate destination array for each process */ + if ((ps->ps_pipes[src] = calloc(ps->ps_ninstances, + sizeof(struct privsep_pipes))) == NULL) + fatal("proc_init: calloc"); + + for (i = 0; i < ps->ps_ninstances; i++) { + pp = &ps->ps_pipes[src][i]; + + for (dst = 0; dst < PROC_MAX; dst++) { + /* Allocate maximum fd integers */ + if ((pp->pp_pipes[dst] = + calloc(ps->ps_ninstances, + sizeof(int))) == NULL) + fatal("proc_init: calloc"); + + /* Mark fd as unused */ + for (j = 0; j < ps->ps_ninstances; j++) + pp->pp_pipes[dst][j] = -1; + } + } + } + + /* + * Setup and run the parent and its children */ privsep_process = PROC_PARENT; + ps->ps_instances[PROC_PARENT] = 1; ps->ps_title[PROC_PARENT] = "parent"; ps->ps_pid[PROC_PARENT] = getpid(); + ps->ps_pp = &ps->ps_pipes[privsep_process][0]; + + for (i = 0; i < nproc; i++) { + /* Default to 1 process instance */ + if (ps->ps_instances[procs[i].p_id] < 1) + ps->ps_instances[procs[i].p_id] = 1; + ps->ps_title[procs[i].p_id] = procs[i].p_title; + } - proc_setup(ps); + proc_open(ps, NULL, procs, nproc); /* Engage! */ - for (i = 0; i < nproc; i++, p++) { - ps->ps_title[p->p_id] = p->p_title; - ps->ps_pid[p->p_id] = (*p->p_init)(ps, p); - } + for (i = 0; i < nproc; i++) + ps->ps_pid[procs[i].p_id] = (*procs[i].p_init)(ps, &procs[i]); } void proc_kill(struct privsep *ps) { pid_t pid; - u_int i; + unsigned int i; if (privsep_process != PROC_PARENT) return; @@ -73,83 +135,157 @@ proc_kill(struct privsep *ps) for (i = 0; i < PROC_MAX; i++) { if (ps->ps_pid[i] == 0) continue; - kill(ps->ps_pid[i], SIGTERM); + killpg(ps->ps_pid[i], SIGTERM); } do { pid = waitpid(WAIT_ANY, NULL, 0); } while (pid != -1 || (pid == -1 && errno == EINTR)); + + proc_close(ps); } void -proc_setup(struct privsep *ps) +proc_open(struct privsep *ps, struct privsep_proc *p, + struct privsep_proc *procs, size_t nproc) { - int i, j, sockpair[2]; - - for (i = 0; i < PROC_MAX; i++) - for (j = 0; j < PROC_MAX; j++) { - if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, - sockpair) == -1) - fatal("sockpair"); - ps->ps_pipes[i][j] = sockpair[0]; - ps->ps_pipes[j][i] = sockpair[1]; - socket_set_blockmode(ps->ps_pipes[i][j], - BM_NONBLOCK); - socket_set_blockmode(ps->ps_pipes[j][i], - BM_NONBLOCK); + struct privsep_pipes *pa, *pb; + int fds[2]; + unsigned int i, j, src, proc; + + if (p == NULL) + src = privsep_process; /* parent */ + else + src = p->p_id; + + /* + * Open socket pairs for our peers + */ + for (proc = 0; proc < nproc; proc++) { + procs[proc].p_ps = ps; + procs[proc].p_env = ps->ps_env; + + for (i = 0; i < ps->ps_instances[src]; i++) { + for (j = 0; j < ps->ps_instances[procs[proc].p_id]; + j++) { + pa = &ps->ps_pipes[src][i]; + pb = &ps->ps_pipes[procs[proc].p_id][j]; + + /* Check if fds are already set by peer */ + if (pa->pp_pipes[procs[proc].p_id][j] != -1) + continue; + + if (socketpair(AF_UNIX, SOCK_STREAM, + PF_UNSPEC, fds) == -1) + fatal("socketpair"); + + socket_set_blockmode(fds[0], BM_NONBLOCK); + socket_set_blockmode(fds[1], BM_NONBLOCK); + + pa->pp_pipes[procs[proc].p_id][j] = fds[0]; + pb->pp_pipes[src][i] = fds[1]; + } } + } } void -proc_config(struct privsep *ps, struct privsep_proc *p, u_int nproc) +proc_listen(struct privsep *ps, struct privsep_proc *procs, size_t nproc) { - u_int src, dst, i, j, k, found; - - src = privsep_process; + unsigned int i, dst, src, n, m; + struct privsep_pipes *pp; /* - * close unused pipes + * Close unused pipes */ - for (i = 0; i < PROC_MAX; i++) { - if (i != privsep_process) { - for (j = 0; j < PROC_MAX; j++) { - close(ps->ps_pipes[i][j]); - ps->ps_pipes[i][j] = -1; - } - } else { - for (j = found = 0; j < PROC_MAX; j++, found = 0) { - for (k = 0; k < nproc; k++) { - if (p[k].p_id == j) - found++; - } - if (!found) { - close(ps->ps_pipes[i][j]); - ps->ps_pipes[i][j] = -1; + for (src = 0; src < PROC_MAX; src++) { + for (n = 0; n < ps->ps_instances[src]; n++) { + /* Ingore current process */ + if (src == (unsigned int)privsep_process && + n == ps->ps_instance) + continue; + + pp = &ps->ps_pipes[src][n]; + + for (dst = 0; dst < PROC_MAX; dst++) { + if (src == dst) + continue; + for (m = 0; m < ps->ps_instances[dst]; m++) { + if (pp->pp_pipes[dst][m] == -1) + continue; + + /* Close and invalidate fd */ + close(pp->pp_pipes[dst][m]); + pp->pp_pipes[dst][m] = -1; } } } } + src = privsep_process; + ps->ps_pp = pp = &ps->ps_pipes[src][ps->ps_instance]; + /* - * listen on appropriate pipes + * Listen on appropriate pipes */ - for (i = 0; i < nproc; i++, p++) { - dst = p->p_id; - p->p_ps = ps; - p->p_env = ps->ps_env; - - imsg_init(&ps->ps_ievs[dst].ibuf, - ps->ps_pipes[src][dst]); - ps->ps_ievs[dst].handler = proc_dispatch; - ps->ps_ievs[dst].events = EV_READ; - ps->ps_ievs[dst].data = p; - ps->ps_ievs[dst].name = p->p_title; - event_set(&ps->ps_ievs[dst].ev, - ps->ps_ievs[dst].ibuf.fd, - ps->ps_ievs[dst].events, - ps->ps_ievs[dst].handler, - ps->ps_ievs[dst].data); - event_add(&ps->ps_ievs[dst].ev, NULL); + for (i = 0; i < nproc; i++) { + dst = procs[i].p_id; + + if (src == dst) + fatal("proc_listen: cannot peer with oneself"); + + if ((ps->ps_ievs[dst] = calloc(ps->ps_instances[dst], + sizeof(struct imsgev))) == NULL) + fatal("proc_open"); + + for (n = 0; n < ps->ps_instances[dst]; n++) { + if (pp->pp_pipes[dst][n] == -1) + continue; + + imsg_init(&(ps->ps_ievs[dst][n].ibuf), + pp->pp_pipes[dst][n]); + ps->ps_ievs[dst][n].handler = proc_dispatch; + ps->ps_ievs[dst][n].events = EV_READ; + ps->ps_ievs[dst][n].proc = &procs[i]; + ps->ps_ievs[dst][n].data = &ps->ps_ievs[dst][n]; + procs[i].p_instance = n; + + event_set(&(ps->ps_ievs[dst][n].ev), + ps->ps_ievs[dst][n].ibuf.fd, + ps->ps_ievs[dst][n].events, + ps->ps_ievs[dst][n].handler, + ps->ps_ievs[dst][n].data); + event_add(&(ps->ps_ievs[dst][n].ev), NULL); + } + } +} + +void +proc_close(struct privsep *ps) +{ + unsigned int dst, n; + struct privsep_pipes *pp; + + if (ps == NULL) + return; + + pp = ps->ps_pp; + + for (dst = 0; dst < PROC_MAX; dst++) { + if (ps->ps_ievs[dst] == NULL) + continue; + + for (n = 0; n < ps->ps_instances[dst]; n++) { + if (pp->pp_pipes[dst][n] == -1) + continue; + + /* Cancel the fd, close and invalidate the fd */ + event_del(&(ps->ps_ievs[dst][n].ev)); + imsg_clear(&(ps->ps_ievs[dst][n].ibuf)); + close(pp->pp_pipes[dst][n]); + pp->pp_pipes[dst][n] = -1; + } + free(ps->ps_ievs[dst]); } } @@ -161,7 +297,13 @@ proc_shutdown(struct privsep_proc *p) if (p->p_id == PROC_CONTROL && ps) control_cleanup(&ps->ps_csock); - log_info("%s exiting", p->p_title); + if (p->p_shutdown != NULL) + (*p->p_shutdown)(); + + proc_close(ps); + + log_info("%s exiting, pid %d", p->p_title, getpid()); + _exit(0); } @@ -178,6 +320,7 @@ proc_sig_handler(int sig, short event, void *arg) case SIGCHLD: case SIGHUP: case SIGPIPE: + case SIGUSR1: /* ignore */ break; default: @@ -188,18 +331,27 @@ proc_sig_handler(int sig, short event, void *arg) pid_t proc_run(struct privsep *ps, struct privsep_proc *p, - struct privsep_proc *procs, u_int nproc, - void (*init)(struct privsep *, void *), void *arg) + struct privsep_proc *procs, unsigned int nproc, + void (*init)(struct privsep *, struct privsep_proc *, void *), void *arg) { - pid_t pid; - struct passwd *pw; - const char *root; - u_int32_t seed[256]; + pid_t pid; + struct passwd *pw; + const char *root; + struct control_sock *rcs; + unsigned int n; + + if (ps->ps_noaction) + return (0); + proc_open(ps, p, procs, nproc); + + /* Fork child handlers */ switch (pid = fork()) { case -1: fatal("proc_run: cannot fork"); case 0: + /* Set the process group of the current process */ + setpgid(0, 0); break; default: return (pid); @@ -207,9 +359,12 @@ proc_run(struct privsep *ps, struct privsep_proc *p, pw = ps->ps_pw; - if (p->p_id == PROC_CONTROL) { + if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { if (control_init(ps, &ps->ps_csock) == -1) fatalx(p->p_title); + TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry) + if (control_init(ps, rcs) == -1) + fatalx(p->p_title); } /* Change root directory */ @@ -218,30 +373,31 @@ proc_run(struct privsep *ps, struct privsep_proc *p, else root = pw->pw_dir; -#ifndef DEBUG if (chroot(root) == -1) fatal("proc_run: chroot"); if (chdir("/") == -1) fatal("proc_run: chdir(\"/\")"); -#else -#warning disabling privilege revocation and chroot in DEBUG MODE - if (p->p_chroot != NULL) { - if (chroot(root) == -1) - fatal("proc_run: chroot"); - if (chdir("/") == -1) - fatal("proc_run: chdir(\"/\")"); - } -#endif privsep_process = p->p_id; setproctitle("%s", p->p_title); -#ifndef DEBUG if (setgroups(1, &pw->pw_gid) || setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) fatal("proc_run: cannot drop privileges"); + + /* Fork child handlers */ + for (n = 1; n < ps->ps_instances[p->p_id]; n++) { + if (fork() == 0) { + ps->ps_instance = p->p_instance = n; + break; + } + } + +#ifdef DEBUG + log_debug("%s: %s %d/%d, pid %d", __func__, p->p_title, + ps->ps_instance + 1, ps->ps_instances[p->p_id], getpid()); #endif event_init(); @@ -251,26 +407,28 @@ proc_run(struct privsep *ps, struct privsep_proc *p, signal_set(&ps->ps_evsigchld, SIGCHLD, proc_sig_handler, p); signal_set(&ps->ps_evsighup, SIGHUP, proc_sig_handler, p); signal_set(&ps->ps_evsigpipe, SIGPIPE, proc_sig_handler, p); + signal_set(&ps->ps_evsigusr1, SIGUSR1, proc_sig_handler, p); signal_add(&ps->ps_evsigint, NULL); signal_add(&ps->ps_evsigterm, NULL); signal_add(&ps->ps_evsigchld, NULL); signal_add(&ps->ps_evsighup, NULL); signal_add(&ps->ps_evsigpipe, NULL); + signal_add(&ps->ps_evsigusr1, NULL); - proc_config(ps, procs, nproc); - - arc4random_buf(seed, sizeof(seed)); - RAND_seed(seed, sizeof(seed)); + proc_listen(ps, procs, nproc); - if (p->p_id == PROC_CONTROL) { + if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { TAILQ_INIT(&ctl_conns); if (control_listen(&ps->ps_csock) == -1) fatalx(p->p_title); + TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry) + if (control_listen(rcs) == -1) + fatalx(p->p_title); } if (init != NULL) - init(ps, arg); + init(ps, p, arg); event_dispatch(); @@ -282,9 +440,9 @@ proc_run(struct privsep *ps, struct privsep_proc *p, void proc_dispatch(int fd, short event, void *arg) { - struct privsep_proc *p = (struct privsep_proc *)arg; + struct imsgev *iev = arg; + struct privsep_proc *p = iev->proc; struct privsep *ps = p->p_ps; - struct imsgev *iev; struct imsgbuf *ibuf; struct imsg imsg; ssize_t n; @@ -292,7 +450,6 @@ proc_dispatch(int fd, short event, void *arg) const char *title; title = ps->ps_title[privsep_process]; - iev = &ps->ps_ievs[p->p_id]; ibuf = &iev->ibuf; if (event & EV_READ) { @@ -307,7 +464,7 @@ proc_dispatch(int fd, short event, void *arg) } if (event & EV_WRITE) { - if (msgbuf_write(&ibuf->w) == -1) + if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) fatal(title); } @@ -317,6 +474,12 @@ proc_dispatch(int fd, short event, void *arg) if (n == 0) break; +#if DEBUG > 1 + log_debug("%s: %s %d got imsg %d from %s %d", + __func__, title, ps->ps_instance + 1, + imsg.hdr.type, p->p_title, p->p_instance); +#endif + /* * Check the message with the program callback */ @@ -332,13 +495,13 @@ proc_dispatch(int fd, short event, void *arg) switch (imsg.hdr.type) { case IMSG_CTL_VERBOSE: IMSG_SIZE_CHECK(&imsg, &verbose); - memcpy(&verbose, imsg.data, sizeof(verbose)); log_verbose(verbose); break; default: - log_warnx("%s: %s got imsg %d", __func__, p->p_title, - imsg.hdr.type); + log_warnx("%s: %s %d got invalid imsg %d from %s %d", + __func__, title, ps->ps_instance + 1, + imsg.hdr.type, p->p_title, p->p_instance); fatalx(title); } imsg_free(&imsg); @@ -346,6 +509,10 @@ proc_dispatch(int fd, short event, void *arg) imsg_event_add(iev); } +/* + * imsg helper functions + */ + void imsg_event_add(struct imsgev *iev) { @@ -364,8 +531,8 @@ imsg_event_add(struct imsgev *iev) } int -imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, - pid_t pid, int fd, void *data, u_int16_t datalen) +imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, + pid_t pid, int fd, void *data, uint16_t datalen) { int ret; @@ -377,7 +544,7 @@ imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, } int -imsg_composev_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, +imsg_composev_event(struct imsgev *iev, uint16_t type, uint32_t peerid, pid_t pid, int fd, const struct iovec *iov, int iovcnt) { int ret; @@ -389,32 +556,72 @@ imsg_composev_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, return (ret); } +void +proc_range(struct privsep *ps, enum privsep_procid id, int *n, int *m) +{ + if (*n == -1) { + /* Use a range of all target instances */ + *n = 0; + *m = ps->ps_instances[id]; + } else { + /* Use only a single slot of the specified peer process */ + *m = *n + 1; + } +} + int -proc_compose_imsg(struct iked *env, enum privsep_procid id, - u_int16_t type, int fd, void *data, u_int16_t datalen) +proc_compose_imsg(struct privsep *ps, enum privsep_procid id, int n, + uint16_t type, int fd, void *data, uint16_t datalen) { - return (imsg_compose_event(&env->sc_ps.ps_ievs[id], - type, -1, 0, fd, data, datalen)); + int m; + + proc_range(ps, id, &n, &m); + for (; n < m; n++) { + if (imsg_compose_event(&ps->ps_ievs[id][n], + type, -1, 0, fd, data, datalen) == -1) + return (-1); + } + + return (0); } int -proc_composev_imsg(struct iked *env, enum privsep_procid id, - u_int16_t type, int fd, const struct iovec *iov, int iovcnt) +proc_composev_imsg(struct privsep *ps, enum privsep_procid id, int n, + uint16_t type, int fd, const struct iovec *iov, int iovcnt) { - return (imsg_composev_event(&env->sc_ps.ps_ievs[id], - type, -1, 0, fd, iov, iovcnt)); + int m; + + proc_range(ps, id, &n, &m); + for (; n < m; n++) + if (imsg_composev_event(&ps->ps_ievs[id][n], + type, -1, 0, fd, iov, iovcnt) == -1) + return (-1); + + return (0); } int -proc_forward_imsg(struct iked *env, struct imsg *imsg, - enum privsep_procid id) +proc_forward_imsg(struct privsep *ps, struct imsg *imsg, + enum privsep_procid id, int n) { - return (proc_compose_imsg(env, id, imsg->hdr.type, + return (proc_compose_imsg(ps, id, n, imsg->hdr.type, imsg->fd, imsg->data, IMSG_DATA_SIZE(imsg))); } -void -proc_flush_imsg(struct iked *env, enum privsep_procid id) +struct imsgbuf * +proc_ibuf(struct privsep *ps, enum privsep_procid id, int n) { - imsg_flush(&env->sc_ps.ps_ievs[id].ibuf); + int m; + + proc_range(ps, id, &n, &m); + return (&ps->ps_ievs[id][n].ibuf); +} + +struct imsgev * +proc_iev(struct privsep *ps, enum privsep_procid id, int n) +{ + int m; + + proc_range(ps, id, &n, &m); + return (&ps->ps_ievs[id][n]); } diff --git a/iked/smult_curve25519_ref.c b/iked/smult_curve25519_ref.c new file mode 100644 index 0000000..71c106a --- /dev/null +++ b/iked/smult_curve25519_ref.c @@ -0,0 +1,265 @@ +/* $OpenBSD: smult_curve25519_ref.c,v 1.1 2014/08/27 10:28:57 reyk Exp $ */ +/* +version 20081011 +Matthew Dempsky +Public domain. +Derived from public domain code by D. J. Bernstein. +*/ + +int crypto_scalarmult_curve25519(unsigned char *, const unsigned char *, const unsigned char *); + +static void add(unsigned int out[32],const unsigned int a[32],const unsigned int b[32]) +{ + unsigned int j; + unsigned int u; + u = 0; + for (j = 0;j < 31;++j) { u += a[j] + b[j]; out[j] = u & 255; u >>= 8; } + u += a[31] + b[31]; out[31] = u; +} + +static void sub(unsigned int out[32],const unsigned int a[32],const unsigned int b[32]) +{ + unsigned int j; + unsigned int u; + u = 218; + for (j = 0;j < 31;++j) { + u += a[j] + 65280 - b[j]; + out[j] = u & 255; + u >>= 8; + } + u += a[31] - b[31]; + out[31] = u; +} + +static void squeeze(unsigned int a[32]) +{ + unsigned int j; + unsigned int u; + u = 0; + for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; } + u += a[31]; a[31] = u & 127; + u = 19 * (u >> 7); + for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; } + u += a[31]; a[31] = u; +} + +static const unsigned int minusp[32] = { + 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128 +} ; + +static void freeze(unsigned int a[32]) +{ + unsigned int aorig[32]; + unsigned int j; + unsigned int negative; + + for (j = 0;j < 32;++j) aorig[j] = a[j]; + add(a,a,minusp); + negative = -((a[31] >> 7) & 1); + for (j = 0;j < 32;++j) a[j] ^= negative & (aorig[j] ^ a[j]); +} + +static void mult(unsigned int out[32],const unsigned int a[32],const unsigned int b[32]) +{ + unsigned int i; + unsigned int j; + unsigned int u; + + for (i = 0;i < 32;++i) { + u = 0; + for (j = 0;j <= i;++j) u += a[j] * b[i - j]; + for (j = i + 1;j < 32;++j) u += 38 * a[j] * b[i + 32 - j]; + out[i] = u; + } + squeeze(out); +} + +static void mult121665(unsigned int out[32],const unsigned int a[32]) +{ + unsigned int j; + unsigned int u; + + u = 0; + for (j = 0;j < 31;++j) { u += 121665 * a[j]; out[j] = u & 255; u >>= 8; } + u += 121665 * a[31]; out[31] = u & 127; + u = 19 * (u >> 7); + for (j = 0;j < 31;++j) { u += out[j]; out[j] = u & 255; u >>= 8; } + u += out[j]; out[j] = u; +} + +static void square(unsigned int out[32],const unsigned int a[32]) +{ + unsigned int i; + unsigned int j; + unsigned int u; + + for (i = 0;i < 32;++i) { + u = 0; + for (j = 0;j < i - j;++j) u += a[j] * a[i - j]; + for (j = i + 1;j < i + 32 - j;++j) u += 38 * a[j] * a[i + 32 - j]; + u *= 2; + if ((i & 1) == 0) { + u += a[i / 2] * a[i / 2]; + u += 38 * a[i / 2 + 16] * a[i / 2 + 16]; + } + out[i] = u; + } + squeeze(out); +} + +static void select(unsigned int p[64],unsigned int q[64],const unsigned int r[64],const unsigned int s[64],unsigned int b) +{ + unsigned int j; + unsigned int t; + unsigned int bminus1; + + bminus1 = b - 1; + for (j = 0;j < 64;++j) { + t = bminus1 & (r[j] ^ s[j]); + p[j] = s[j] ^ t; + q[j] = r[j] ^ t; + } +} + +static void mainloop(unsigned int work[64],const unsigned char e[32]) +{ + unsigned int xzm1[64]; + unsigned int xzm[64]; + unsigned int xzmb[64]; + unsigned int xzm1b[64]; + unsigned int xznb[64]; + unsigned int xzn1b[64]; + unsigned int a0[64]; + unsigned int a1[64]; + unsigned int b0[64]; + unsigned int b1[64]; + unsigned int c1[64]; + unsigned int r[32]; + unsigned int s[32]; + unsigned int t[32]; + unsigned int u[32]; + unsigned int j; + unsigned int b; + int pos; + + for (j = 0;j < 32;++j) xzm1[j] = work[j]; + xzm1[32] = 1; + for (j = 33;j < 64;++j) xzm1[j] = 0; + + xzm[0] = 1; + for (j = 1;j < 64;++j) xzm[j] = 0; + + for (pos = 254;pos >= 0;--pos) { + b = e[pos / 8] >> (pos & 7); + b &= 1; + select(xzmb,xzm1b,xzm,xzm1,b); + add(a0,xzmb,xzmb + 32); + sub(a0 + 32,xzmb,xzmb + 32); + add(a1,xzm1b,xzm1b + 32); + sub(a1 + 32,xzm1b,xzm1b + 32); + square(b0,a0); + square(b0 + 32,a0 + 32); + mult(b1,a1,a0 + 32); + mult(b1 + 32,a1 + 32,a0); + add(c1,b1,b1 + 32); + sub(c1 + 32,b1,b1 + 32); + square(r,c1 + 32); + sub(s,b0,b0 + 32); + mult121665(t,s); + add(u,t,b0); + mult(xznb,b0,b0 + 32); + mult(xznb + 32,s,u); + square(xzn1b,c1); + mult(xzn1b + 32,r,work); + select(xzm,xzm1,xznb,xzn1b,b); + } + + for (j = 0;j < 64;++j) work[j] = xzm[j]; +} + +static void recip(unsigned int out[32],const unsigned int z[32]) +{ + unsigned int z2[32]; + unsigned int z9[32]; + unsigned int z11[32]; + unsigned int z2_5_0[32]; + unsigned int z2_10_0[32]; + unsigned int z2_20_0[32]; + unsigned int z2_50_0[32]; + unsigned int z2_100_0[32]; + unsigned int t0[32]; + unsigned int t1[32]; + int i; + + /* 2 */ square(z2,z); + /* 4 */ square(t1,z2); + /* 8 */ square(t0,t1); + /* 9 */ mult(z9,t0,z); + /* 11 */ mult(z11,z9,z2); + /* 22 */ square(t0,z11); + /* 2^5 - 2^0 = 31 */ mult(z2_5_0,t0,z9); + + /* 2^6 - 2^1 */ square(t0,z2_5_0); + /* 2^7 - 2^2 */ square(t1,t0); + /* 2^8 - 2^3 */ square(t0,t1); + /* 2^9 - 2^4 */ square(t1,t0); + /* 2^10 - 2^5 */ square(t0,t1); + /* 2^10 - 2^0 */ mult(z2_10_0,t0,z2_5_0); + + /* 2^11 - 2^1 */ square(t0,z2_10_0); + /* 2^12 - 2^2 */ square(t1,t0); + /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { square(t0,t1); square(t1,t0); } + /* 2^20 - 2^0 */ mult(z2_20_0,t1,z2_10_0); + + /* 2^21 - 2^1 */ square(t0,z2_20_0); + /* 2^22 - 2^2 */ square(t1,t0); + /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { square(t0,t1); square(t1,t0); } + /* 2^40 - 2^0 */ mult(t0,t1,z2_20_0); + + /* 2^41 - 2^1 */ square(t1,t0); + /* 2^42 - 2^2 */ square(t0,t1); + /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { square(t1,t0); square(t0,t1); } + /* 2^50 - 2^0 */ mult(z2_50_0,t0,z2_10_0); + + /* 2^51 - 2^1 */ square(t0,z2_50_0); + /* 2^52 - 2^2 */ square(t1,t0); + /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { square(t0,t1); square(t1,t0); } + /* 2^100 - 2^0 */ mult(z2_100_0,t1,z2_50_0); + + /* 2^101 - 2^1 */ square(t1,z2_100_0); + /* 2^102 - 2^2 */ square(t0,t1); + /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { square(t1,t0); square(t0,t1); } + /* 2^200 - 2^0 */ mult(t1,t0,z2_100_0); + + /* 2^201 - 2^1 */ square(t0,t1); + /* 2^202 - 2^2 */ square(t1,t0); + /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { square(t0,t1); square(t1,t0); } + /* 2^250 - 2^0 */ mult(t0,t1,z2_50_0); + + /* 2^251 - 2^1 */ square(t1,t0); + /* 2^252 - 2^2 */ square(t0,t1); + /* 2^253 - 2^3 */ square(t1,t0); + /* 2^254 - 2^4 */ square(t0,t1); + /* 2^255 - 2^5 */ square(t1,t0); + /* 2^255 - 21 */ mult(out,t1,z11); +} + +int crypto_scalarmult_curve25519(unsigned char *q, + const unsigned char *n, + const unsigned char *p) +{ + unsigned int work[96]; + unsigned char e[32]; + unsigned int i; + for (i = 0;i < 32;++i) e[i] = n[i]; + e[0] &= 248; + e[31] &= 127; + e[31] |= 64; + for (i = 0;i < 32;++i) work[i] = p[i]; + mainloop(work,e); + recip(work + 32,work + 32); + mult(work + 64,work,work + 32); + freeze(work + 64); + for (i = 0;i < 32;++i) q[i] = work[64 + i]; + return 0; +} diff --git a/iked/timer.c b/iked/timer.c index 150673b..01341cb 100644 --- a/iked/timer.c +++ b/iked/timer.c @@ -1,4 +1,4 @@ -/* $OpenBSD: timer.c,v 1.10 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: timer.c,v 1.12 2015/01/16 06:39:58 deraadt Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,8 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include #include #include @@ -35,7 +34,7 @@ void timer_callback(int, short, void *); void -timer_initialize(struct iked *env, struct iked_timer *tmr, +timer_set(struct iked *env, struct iked_timer *tmr, void (*cb)(struct iked *, void *), void *arg) { tmr->tmr_env = env; @@ -44,17 +43,8 @@ timer_initialize(struct iked *env, struct iked_timer *tmr, evtimer_set(&tmr->tmr_ev, timer_callback, tmr); } -int -timer_initialized(struct iked *env, struct iked_timer *tmr) -{ - if (tmr && tmr->tmr_env == env && tmr->tmr_cb && - evtimer_initialized(&tmr->tmr_ev)) - return (1); - return (0); -} - void -timer_register(struct iked *env, struct iked_timer *tmr, int timeout) +timer_add(struct iked *env, struct iked_timer *tmr, int timeout) { struct timeval tv = { timeout }; @@ -66,9 +56,11 @@ timer_register(struct iked *env, struct iked_timer *tmr, int timeout) } void -timer_deregister(struct iked *env, struct iked_timer *tmr) +timer_del(struct iked *env, struct iked_timer *tmr) { - evtimer_del(&tmr->tmr_ev); + if (tmr->tmr_env == env && tmr->tmr_cb && + evtimer_initialized(&tmr->tmr_ev)) + evtimer_del(&tmr->tmr_ev); } void diff --git a/iked/types.h b/iked/types.h index d0de6e5..476e845 100644 --- a/iked/types.h +++ b/iked/types.h @@ -1,4 +1,4 @@ -/* $OpenBSD: types.h,v 1.17 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: types.h,v 1.21 2015/08/21 11:59:28 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,27 +16,32 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _IKED_TYPES_H -#define _IKED_TYPES_H +#ifndef IKED_TYPES_H +#define IKED_TYPES_H #ifndef IKED_USER -#define IKED_USER "_iked" +#define IKED_USER "_iked" #endif #ifndef IKED_CONFIG -#define IKED_CONFIG "/etc/iked.conf" +#define IKED_CONFIG "/etc/iked.conf" #endif -#define IKED_SOCKET "/var/run/iked.sock" + +#define IKED_SOCKET "/var/run/iked.sock" #ifndef IKED_CA -#define IKED_CA "/etc/iked/" +#define IKED_CA "/etc/iked/" #endif -#define IKED_CA_DIR "ca/" -#define IKED_CRL_DIR "crls/" -#define IKED_CERT_DIR "certs/" -#define IKED_PUBKEY_DIR "pubkeys/" -#define IKED_PRIVKEY IKED_CA "private/local.key" -#define IKED_PUBKEY "local.pub" + +#define IKED_CA_DIR "ca/" +#define IKED_CRL_DIR "crls/" +#define IKED_CERT_DIR "certs/" +#define IKED_PUBKEY_DIR "pubkeys/" +#define IKED_PRIVKEY IKED_CA "private/local.key" +#define IKED_PUBKEY "local.pub" + +#define IKED_OCSP_RESPCERT "ocsp/responder.crt" +#define IKED_OCSP_ISSUER "ocsp/issuer.crt" #define IKED_OPT_VERBOSE 0x00000001 #define IKED_OPT_NOACTION 0x00000002 @@ -65,17 +70,17 @@ #define IKED_E 0x1000 /* Decrypted flag */ struct iked_constmap { - u_int cm_type; + unsigned int cm_type; const char *cm_name; const char *cm_descr; }; struct iked_transform { - u_int8_t xform_type; - u_int16_t xform_id; - u_int16_t xform_length; - u_int16_t xform_keylength; - u_int xform_score; + uint8_t xform_type; + uint16_t xform_id; + uint16_t xform_length; + uint16_t xform_keylength; + unsigned int xform_score; struct iked_constmap *xform_map; }; @@ -101,6 +106,8 @@ enum imsg_type { IMSG_CERT, IMSG_CERTVALID, IMSG_CERTINVALID, + IMSG_OCSP_FD, + IMSG_OCSP_URL, IMSG_AUTH }; @@ -133,4 +140,4 @@ enum flushmode { #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif -#endif /* _IKED_TYPES_H */ +#endif /* IKED_TYPES_H */ diff --git a/iked/util.c b/iked/util.c index 5b0f013..7b108de 100644 --- a/iked/util.c +++ b/iked/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.18 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: util.c,v 1.27 2015/08/21 11:59:28 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -17,23 +17,17 @@ */ #include -#include "openbsd-compat/sys-queue.h" +#include #include #include -#include -#include -#include -#include -#include -#include #include - #include #include #include #include #include +#include #include #include #include @@ -65,17 +59,13 @@ socket_af(struct sockaddr *sa, in_port_t port) switch (sa->sa_family) { case AF_INET: ((struct sockaddr_in *)sa)->sin_port = port; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN ((struct sockaddr_in *)sa)->sin_len = sizeof(struct sockaddr_in); -#endif break; case AF_INET6: ((struct sockaddr_in6 *)sa)->sin6_port = port; -#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN ((struct sockaddr_in6 *)sa)->sin6_len = sizeof(struct sockaddr_in6); -#endif break; default: errno = EPFNOSUPPORT; @@ -86,13 +76,13 @@ socket_af(struct sockaddr *sa, in_port_t port) } in_port_t -socket_getport(struct sockaddr_storage *ss) +socket_getport(struct sockaddr *sa) { - switch (ss->ss_family) { + switch (sa->sa_family) { case AF_INET: - return (ntohs(((struct sockaddr_in *)ss)->sin_port)); + return (ntohs(((struct sockaddr_in *)sa)->sin_port)); case AF_INET6: - return (ntohs(((struct sockaddr_in6 *)ss)->sin6_port)); + return (ntohs(((struct sockaddr_in6 *)sa)->sin6_port)); default: return (0); } @@ -101,6 +91,22 @@ socket_getport(struct sockaddr_storage *ss) return (0); } +int +socket_setport(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; + default: + return (-1); + } + return (0); +} + int socket_getaddr(int s, struct sockaddr_storage *ss) { @@ -112,7 +118,6 @@ socket_getaddr(int s, struct sockaddr_storage *ss) int socket_bypass(int s, struct sockaddr *sa) { -#if defined(__OpenBSD__) int v, *a; int a4[] = { IPPROTO_IP, @@ -164,47 +169,6 @@ socket_bypass(int s, struct sockaddr *sa) return (-1); } #endif -#else /* __OpenBSD__ */ - int *a; - int a4[] = { - IPPROTO_IP, - IP_IPSEC_POLICY - }; - int a6[] = { - IPPROTO_IPV6, - IPV6_IPSEC_POLICY, - - }; - struct sadb_x_policy pol = { - SADB_UPDATE, - SADB_EXT_SENSITIVITY, - IPSEC_POLICY_BYPASS, - 0, 0, 0, 0 - }; - - switch (sa->sa_family) { - case AF_INET: - a = a4; - break; - case AF_INET6: - a = a6; - break; - default: - log_warn("%s: invalid address family", __func__); - return (-1); - } - - pol.sadb_x_policy_dir = IPSEC_DIR_INBOUND; - if (setsockopt(s, a[0], a[1], &pol, sizeof(pol)) == -1) { - log_warn("%s: IPSEC_DIR_INBOUND", __func__); - return (-1); - } - pol.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND; - if (setsockopt(s, a[0], a[1], &pol, sizeof(pol)) == -1) { - log_warn("%s: IPSEC_DIR_OUTBOUND", __func__); - return (-1); - } -#endif /* !__OpenBSD__ */ return (0); } @@ -231,46 +195,26 @@ udp_bind(struct sockaddr *sa, in_port_t port) goto bad; } -#ifdef SO_REUSEPORT val = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(int)) == -1) { log_warn("%s: failed to set reuseport", __func__); goto bad; } -#endif -#ifdef SO_REUSEADDR val = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int)) == -1) { log_warn("%s: failed to set reuseaddr", __func__); goto bad; } -#endif if (sa->sa_family == AF_INET) { val = 1; - if (setsockopt(s, IPPROTO_IP, -#if defined(IP_RECVDSTADDR) - IP_RECVDSTADDR, -#elif defined(IP_PKTINFO) - IP_PKTINFO, -#else -#error IPv4 packet info not supported -#endif + if (setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &val, sizeof(int)) == -1) { log_warn("%s: failed to set IPv4 packet info", __func__); goto bad; } } else { -#ifdef IPV6_V6ONLY - val = 1; - if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, - &val, sizeof(int)) == -1) { - log_warn("%s: failed to set IPv6-only mode", - __func__); - goto bad; - } -#endif val = 1; if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(int)) == -1) { @@ -280,7 +224,7 @@ udp_bind(struct sockaddr *sa, in_port_t port) } } - if (bind(s, sa, SA_LEN(sa)) == -1) { + if (bind(s, sa, sa->sa_len) == -1) { log_warn("%s: failed to bind UDP socket", __func__); goto bad; } @@ -296,7 +240,7 @@ sockaddr_cmp(struct sockaddr *a, struct sockaddr *b, int prefixlen) { struct sockaddr_in *a4, *b4; struct sockaddr_in6 *a6, *b6; - u_int32_t av[4], bv[4], mv[4]; + uint32_t av[4], bv[4], mv[4]; if (a->sa_family == AF_UNSPEC || b->sa_family == AF_UNSPEC) return (0); @@ -369,9 +313,6 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, struct cmsghdr hdr; char buf[CMSG_SPACE(sizeof(struct sockaddr_storage))]; } cmsgbuf; -#if !defined(IP_RECVDSTADDR) && defined(IP_PKTINFO) - struct in_pktinfo *pkt; -#endif bzero(&msg, sizeof(msg)); bzero(&cmsgbuf.buf, sizeof(cmsgbuf.buf)); @@ -388,7 +329,7 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, if ((ret = recvmsg(s, &msg, 0)) == -1) return (-1); - *fromlen = SA_LEN(from); + *fromlen = from->sa_len; *tolen = 0; if (getsockname(s, to, tolen) != 0) @@ -398,7 +339,6 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, cmsg = CMSG_NXTHDR(&msg, cmsg)) { switch (from->sa_family) { case AF_INET: -#if defined(IP_RECVDSTADDR) if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) { in = (struct sockaddr_in *)to; @@ -407,32 +347,13 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, memcpy(&in->sin_addr, CMSG_DATA(cmsg), sizeof(struct in_addr)); } -#elif defined(IP_PKTINFO) - if (cmsg->cmsg_level == IPPROTO_IP && - cmsg->cmsg_type == IP_PKTINFO) { - in = (struct sockaddr_in *)to; - in->sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - in->sin_len = *tolen = sizeof(*in); -#else - *tolen = sizeof(*in); -#endif - pkt = (struct in_pktinfo *)CMSG_DATA(cmsg); - memcpy(&in->sin_addr, &pkt->ipi_addr, - sizeof(struct in_addr)); - } -#endif break; case AF_INET6: if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) { in6 = (struct sockaddr_in6 *)to; in6->sin6_family = AF_INET6; -#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN in6->sin6_len = *tolen = sizeof(*in6); -#else - *tolen = sizeof(*in6); -#endif pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg); memcpy(&in6->sin6_addr, &pkt6->ipi6_addr, sizeof(struct in6_addr)); @@ -448,7 +369,7 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, } const char * -print_spi(u_int64_t spi, int size) +print_spi(uint64_t spi, int size) { static char buf[IKED_CYCLE_BUFFERS][32]; static int i = 0; @@ -457,8 +378,11 @@ print_spi(u_int64_t spi, int size) ptr = buf[i]; switch (size) { + case 2: + snprintf(ptr, 32, "0x%04x", (uint16_t)spi); + break; case 4: - snprintf(ptr, 32, "0x%08x", (u_int32_t)spi); + snprintf(ptr, 32, "0x%08x", (uint32_t)spi); break; case 8: snprintf(ptr, 32, "0x%016llx", spi); @@ -475,9 +399,9 @@ print_spi(u_int64_t spi, int size) } const char * -print_map(u_int type, struct iked_constmap *map) +print_map(unsigned int type, struct iked_constmap *map) { - u_int i; + unsigned int i; static char buf[IKED_CYCLE_BUFFERS][32]; static int idx = 0; const char *name = NULL; @@ -503,16 +427,16 @@ void lc_string(char *str) { for (; *str != '\0'; str++) - *str = tolower(*str); + *str = tolower((unsigned char)*str); } void -print_hex(u_int8_t *buf, off_t offset, size_t length) +print_hex(uint8_t *buf, off_t offset, size_t length) { - u_int i; + unsigned int i; extern int verbose; - if (verbose < 2 || !length) + if (verbose < 3 || !length) return; for (i = 0; i < length; i++) { @@ -528,9 +452,9 @@ print_hex(u_int8_t *buf, off_t offset, size_t length) } void -print_hexval(u_int8_t *buf, off_t offset, size_t length) +print_hexval(uint8_t *buf, off_t offset, size_t length) { - u_int i; + unsigned int i; extern int verbose; if (verbose < 2 || !length) @@ -543,12 +467,12 @@ print_hexval(u_int8_t *buf, off_t offset, size_t length) } const char * -print_bits(u_short v, char *bits) +print_bits(unsigned short v, unsigned char *bits) { static char buf[IKED_CYCLE_BUFFERS][BUFSIZ]; static int idx = 0; - u_int i, any = 0, j = 0; - char c; + unsigned int i, any = 0, j = 0; + unsigned char c; if (!bits) return (""); @@ -568,7 +492,7 @@ print_bits(u_short v, char *bits) } any = 1; for (; (c = *bits) > 32; bits++) { - buf[idx][j++] = tolower(c); + buf[idx][j++] = tolower((unsigned char)c); if (j >= sizeof(buf[idx])) return (buf[idx]); } @@ -580,7 +504,7 @@ print_bits(u_short v, char *bits) return (buf[idx]); } -u_int8_t +uint8_t mask2prefixlen(struct sockaddr *sa) { struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; @@ -592,18 +516,18 @@ mask2prefixlen(struct sockaddr *sa) return (33 - ffs(ntohl(ina))); } -u_int8_t +uint8_t mask2prefixlen6(struct sockaddr *sa) { struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; - u_int8_t l = 0, *ap, *ep; + uint8_t l = 0, *ap, *ep; /* * sin6_len is the size of the sockaddr so substract the offset of * the possibly truncated sin6_addr struct. */ - ap = (u_int8_t *)&sa_in6->sin6_addr; - ep = (u_int8_t *)sa_in6 + SA_LEN(sa); + ap = (uint8_t *)&sa_in6->sin6_addr; + ep = (uint8_t *)sa_in6 + sa_in6->sin6_len; for (; ap < ep; ap++) { /* this "beauty" is adopted from sbin/route/show.c ... */ switch (*ap) { @@ -641,8 +565,8 @@ mask2prefixlen6(struct sockaddr *sa) return (l); } -u_int32_t -prefixlen2mask(u_int8_t prefixlen) +uint32_t +prefixlen2mask(uint8_t prefixlen) { if (prefixlen == 0) return (0); @@ -654,7 +578,7 @@ prefixlen2mask(u_int8_t prefixlen) } struct in6_addr * -prefixlen2mask6(u_int8_t prefixlen, u_int32_t *mask) +prefixlen2mask6(uint8_t prefixlen, uint32_t *mask) { static struct in6_addr s6; int i; @@ -675,7 +599,7 @@ prefixlen2mask6(u_int8_t prefixlen, u_int32_t *mask) } const char * -print_host(struct sockaddr_storage *ss, char *buf, size_t len) +print_host(struct sockaddr *sa, char *buf, size_t len) { static char sbuf[IKED_CYCLE_BUFFERS][NI_MAXHOST + 7]; static int idx = 0; @@ -689,18 +613,18 @@ print_host(struct sockaddr_storage *ss, char *buf, size_t len) idx = 0; } - if (ss->ss_family == AF_UNSPEC) { + if (sa->sa_family == AF_UNSPEC) { strlcpy(buf, "any", len); return (buf); } - if (getnameinfo((struct sockaddr *)ss, SS_LEN(ss), + if (getnameinfo(sa, sa->sa_len, buf, len, NULL, 0, NI_NUMERICHOST) != 0) { buf[0] = '\0'; return (NULL); } - if ((port = socket_getport(ss)) != 0) { + if ((port = socket_getport(sa)) != 0) { snprintf(pbuf, sizeof(pbuf), ":%d", port); (void)strlcat(buf, pbuf, len); } @@ -709,13 +633,13 @@ print_host(struct sockaddr_storage *ss, char *buf, size_t len) } char * -get_string(u_int8_t *ptr, size_t len) +get_string(uint8_t *ptr, size_t len) { size_t i; char *str; for (i = 0; i < len; i++) - if (!isprint((char)ptr[i])) + if (!isprint(ptr[i])) break; if ((str = calloc(1, i + 1)) == NULL) @@ -726,7 +650,7 @@ get_string(u_int8_t *ptr, size_t len) } const char * -print_proto(u_int8_t proto) +print_proto(uint8_t proto) { struct protoent *p; static char buf[IKED_CYCLE_BUFFERS][BUFSIZ]; @@ -777,10 +701,10 @@ expand_string(char *label, size_t len, const char *srch, const char *repl) return (0); } -u_int8_t * +uint8_t * string2unicode(const char *ascii, size_t *outlen) { - u_int8_t *uc = NULL; + uint8_t *uc = NULL; size_t i, len = strlen(ascii); if ((uc = calloc(1, (len * 2) + 2)) == NULL) diff --git a/mdoc2man.awk b/mdoc2man.awk deleted file mode 100644 index 80e8d5f..0000000 --- a/mdoc2man.awk +++ /dev/null @@ -1,370 +0,0 @@ -#!/usr/bin/awk -# -# $Id: mdoc2man.awk,v 1.9 2009/10/24 00:52:42 dtucker Exp $ -# -# Version history: -# v4+ Adapted for OpenSSH Portable (see cvs Id and history) -# v3, I put the program under a proper license -# Dan Nelson added .An, .Aq and fixed a typo -# v2, fixed to work on GNU awk --posix and MacOS X -# v1, first attempt, didn't work on MacOS X -# -# Copyright (c) 2003 Peter Stuge -# -# Permission to use, copy, modify, and distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - -BEGIN { - optlist=0 - oldoptlist=0 - nospace=0 - synopsis=0 - reference=0 - block=0 - ext=0 - extopt=0 - literal=0 - prenl=0 - breakw=0 - line="" -} - -function wtail() { - retval="" - while(w0;i--) { - add(refauthors[i]) - if(i>1) - add(", ") - } - if(nrefauthors>1) - add(" and ") - if(nrefauthors>0) - add(refauthors[0] ", ") - add("\\fI" reftitle "\\fP") - if(length(refissue)) - add(", " refissue) - if(length(refreport)) { - add(", " refreport) - } - if(length(refdate)) - add(", " refdate) - if(length(refopt)) - add(", " refopt) - add(".") - reference=0 - } else if(reference) { - if(match(words[w],"^%A$")) { refauthors[nrefauthors++]=wtail() } - if(match(words[w],"^%T$")) { - reftitle=wtail() - sub("^\"","",reftitle) - sub("\"$","",reftitle) - } - if(match(words[w],"^%N$")) { refissue=wtail() } - if(match(words[w],"^%D$")) { refdate=wtail() } - if(match(words[w],"^%O$")) { refopt=wtail() } - if(match(words[w],"^%R$")) { refreport=wtail() } - } else if(match(words[w],"^Nm$")) { - if(synopsis) { - add(".br") - prenl++ - } - n=words[++w] - if(!length(name)) - name=n - if(!length(n)) - n=name - add("\\fB" n "\\fP") - if(!nospace&&match(words[w+1],"^[\\.,]")) - nospace=1 - } else if(match(words[w],"^Nd$")) { - add("\\- " wtail()) - } else if(match(words[w],"^Fl$")) { - add("\\fB\\-" words[++w] "\\fP") - if(!nospace&&match(words[w+1],"^[\\.,]")) - nospace=1 - } else if(match(words[w],"^Ar$")) { - add("\\fI") - if(w==nwords) - add("file ...\\fP") - else { - add(words[++w] "\\fP") - while(match(words[w+1],"^\\|$")) - add(OFS words[++w] " \\fI" words[++w] "\\fP") - } - if(!nospace&&match(words[w+1],"^[\\.,]")) - nospace=1 - } else if(match(words[w],"^Cm$")) { - add("\\fB" words[++w] "\\fP") - while(w") - if(option) - add("]") - if(ext&&!extopt&&!match(line," $")) - add(OFS) - if(!ext&&!extopt&&length(line)) { - print line - prenl=0 - line="" - } -} diff --git a/openbsd-compat/Makefile.am b/openbsd-compat/Makefile.am deleted file mode 100644 index 80b5eba..0000000 --- a/openbsd-compat/Makefile.am +++ /dev/null @@ -1,14 +0,0 @@ -noinst_LIBRARIES= libopenbsd-compat.a - -libopenbsd_compat_a_SOURCES= \ - bsd-arc4random.c bsd-closefrom.c \ - daemon.c entropy.c fgetln.c getopt.c imsg.c imsg-buffer.c \ - setresguid.c setproctitle.c \ - strlcat.c strlcpy.c strtonum.c vis.c - -EXTRA_DIST= defines.h imsg.h includes.h \ - openbsd-compat.h sys-queue.h sys-tree.h vis.h - -CPPFLAGS= -include $(top_srcdir)/openbsd-compat/includes.h \ - -I$(top_srcdir) -I$(top_srcdir)/openbsd-compat \ - @CPPFLAGS@ @DEFS@ diff --git a/openbsd-compat/bsd-arc4random.c b/openbsd-compat/bsd-arc4random.c deleted file mode 100644 index a7e562b..0000000 --- a/openbsd-compat/bsd-arc4random.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (c) 1996, David Mazieres - * Copyright (c) 2008, Damien Miller - * Copyright (c) 2013, Markus Friedl - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* - * ChaCha based random number generator for OpenBSD. - */ - -#include "includes.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define KEYSTREAM_ONLY -#include "chacha_private.h" - -#ifdef __GNUC__ -#define inline __inline -#else /* !__GNUC__ */ -#define inline -#endif /* !__GNUC__ */ - -#define KEYSZ 32 -#define IVSZ 8 -#define BLOCKSZ 64 -#define RSBUFSZ (16*BLOCKSZ) -static int rs_initialized; -static pid_t rs_stir_pid; -static chacha_ctx rs; /* chacha context for random keystream */ -static u_char rs_buf[RSBUFSZ]; /* keystream blocks */ -static size_t rs_have; /* valid bytes at end of rs_buf */ -static size_t rs_count; /* bytes till reseed */ - -static inline void _rs_rekey(u_char *dat, size_t datlen); -static inline void _rs_random_buf(void *_buf, size_t n); - -static inline void -_rs_init(u_char *buf, size_t n) -{ - if (n < KEYSZ + IVSZ) - return; - chacha_keysetup(&rs, buf, KEYSZ * 8, 0); - chacha_ivsetup(&rs, buf + KEYSZ); -} - -static void -_rs_stir(void) -{ - size_t len; - u_char rnd[KEYSZ + IVSZ]; - - len = sizeof(rnd); - - _rs_random_buf(rnd, len); - if (!rs_initialized) { - rs_initialized = 1; - _rs_init(rnd, sizeof(rnd)); - } else - _rs_rekey(rnd, sizeof(rnd)); - memset(rnd, 0, sizeof(rnd)); - - /* invalidate rs_buf */ - rs_have = 0; - memset(rs_buf, 0, RSBUFSZ); - - rs_count = 1600000; -} - -static inline void -_rs_stir_if_needed(size_t len) -{ - pid_t pid = getpid(); - - if (rs_count <= len || !rs_initialized || rs_stir_pid != pid) { - rs_stir_pid = pid; - _rs_stir(); - } else - rs_count -= len; -} - -static inline void -_rs_rekey(u_char *dat, size_t datlen) -{ -#ifndef KEYSTREAM_ONLY - memset(rs_buf, 0,RSBUFSZ); -#endif - /* fill rs_buf with the keystream */ - chacha_encrypt_bytes(&rs, rs_buf, rs_buf, RSBUFSZ); - /* mix in optional user provided data */ - if (dat) { - size_t i, m; - - m = MIN(datlen, KEYSZ + IVSZ); - for (i = 0; i < m; i++) - rs_buf[i] ^= dat[i]; - } - /* immediately reinit for backtracking resistance */ - _rs_init(rs_buf, KEYSZ + IVSZ); - memset(rs_buf, 0, KEYSZ + IVSZ); - rs_have = RSBUFSZ - KEYSZ - IVSZ; -} - -static inline void -_rs_random_buf(void *_buf, size_t n) -{ - u_char *buf = (u_char *)_buf; - size_t m; - - while (n > 0) { - if (rs_have > 0) { - m = MIN(n, rs_have); - memcpy(buf, rs_buf + RSBUFSZ - rs_have, m); - memset(rs_buf + RSBUFSZ - rs_have, 0, m); - buf += m; - n -= m; - rs_have -= m; - } - if (rs_have == 0) - _rs_rekey(NULL, 0); - } -} - -static inline void -_rs_random_u32(u_int32_t *val) -{ - _rs_stir_if_needed(sizeof(*val)); - if (rs_have < sizeof(*val)) - _rs_rekey(NULL, 0); - memcpy(val, rs_buf + RSBUFSZ - rs_have, sizeof(*val)); - memset(rs_buf + RSBUFSZ - rs_have, 0, sizeof(*val)); - rs_have -= sizeof(*val); - return; -} - -#ifndef HAVE_ARC4RANDOM -void -arc4random_stir(void) -{ - _rs_stir(); -} - -void -arc4random_addrandom(u_char *dat, int datlen) -{ - int m; - - if (!rs_initialized) - _rs_stir(); - while (datlen > 0) { - m = MIN(datlen, KEYSZ + IVSZ); - _rs_rekey(dat, m); - dat += m; - datlen -= m; - } -} - -u_int32_t -arc4random(void) -{ - u_int32_t val; - - _rs_random_u32(&val); - return val; -} -#endif /* !HAVE_ARC4RANDOM */ - -#ifndef HAVE_ARC4RANDOM_BUF -void -arc4random_buf(void *buf, size_t n) -{ - _rs_stir_if_needed(n); - _rs_random_buf(buf, n); -} -#endif /* !HAVE_ARC4RANDOM_BUF */ - -#ifndef HAVE_ARC4RANDOM_UNIFORM -/* - * Calculate a uniformly distributed random number less than upper_bound - * avoiding "modulo bias". - * - * Uniformity is achieved by generating new random numbers until the one - * returned is outside the range [0, 2**32 % upper_bound). This - * guarantees the selected random number will be inside - * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) - * after reduction modulo upper_bound. - */ -u_int32_t -arc4random_uniform(u_int32_t upper_bound) -{ - u_int32_t r, min; - - if (upper_bound < 2) - return 0; - - /* 2**32 % x == (2**32 - x) % x */ - min = -upper_bound % upper_bound; - - /* - * This could theoretically loop forever but each retry has - * p > 0.5 (worst case, usually far better) of selecting a - * number inside the range we need, so it should rarely need - * to re-roll. - */ - for (;;) { - r = arc4random(); - if (r >= min) - break; - } - - return r % upper_bound; -} -#endif /* !HAVE_ARC4RANDOM_UNIFORM */ diff --git a/openbsd-compat/bsd-closefrom.c b/openbsd-compat/bsd-closefrom.c deleted file mode 100644 index 8598970..0000000 --- a/openbsd-compat/bsd-closefrom.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2004-2005 Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "includes.h" - -#ifndef HAVE_CLOSEFROM - -#include -#include -#include -#include -#ifdef HAVE_FCNTL_H -# include -#endif -#include -#include -#include -#include -#include - -#if 0 -__unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $"; -#endif /* lint */ - -/* - * Close all file descriptors greater than or equal to lowfd. - */ -#ifdef HAVE_FCNTL_CLOSEM -void -closefrom(int lowfd) -{ - (void) fcntl(lowfd, F_CLOSEM, 0); -} -#else -void -closefrom(int lowfd) -{ - long fd, maxfd; -#if defined(HAVE_DIRFD) && defined(HAVE_PROC_PID) - char fdpath[PATH_MAX], *endp; - struct dirent *dent; - DIR *dirp; - int len; - - /* Check for a /proc/$$/fd directory. */ - len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid()); - if (len > 0 && (size_t)len <= sizeof(fdpath) && (dirp = opendir(fdpath))) { - while ((dent = readdir(dirp)) != NULL) { - fd = strtol(dent->d_name, &endp, 10); - if (dent->d_name != endp && *endp == '\0' && - fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp)) - (void) close((int) fd); - } - (void) closedir(dirp); - } else -#endif - { - /* - * Fall back on sysconf() or getdtablesize(). We avoid checking - * resource limits since it is possible to open a file descriptor - * and then drop the rlimit such that it is below the open fd. - */ -#ifdef HAVE_SYSCONF - maxfd = sysconf(_SC_OPEN_MAX); -#else - maxfd = getdtablesize(); -#endif /* HAVE_SYSCONF */ - if (maxfd < 0) - maxfd = OPEN_MAX; - - for (fd = lowfd; fd < maxfd; fd++) - (void) close((int) fd); - } -} -#endif /* !HAVE_FCNTL_CLOSEM */ -#endif /* HAVE_CLOSEFROM */ diff --git a/openbsd-compat/chacha_private.h b/openbsd-compat/chacha_private.h deleted file mode 100644 index 7c3680f..0000000 --- a/openbsd-compat/chacha_private.h +++ /dev/null @@ -1,222 +0,0 @@ -/* -chacha-merged.c version 20080118 -D. J. Bernstein -Public domain. -*/ - -/* $OpenBSD: chacha_private.h,v 1.2 2013/10/04 07:02:27 djm Exp $ */ - -typedef unsigned char u8; -typedef unsigned int u32; - -typedef struct -{ - u32 input[16]; /* could be compressed */ -} chacha_ctx; - -#define U8C(v) (v##U) -#define U32C(v) (v##U) - -#define U8V(v) ((u8)(v) & U8C(0xFF)) -#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) - -#define ROTL32(v, n) \ - (U32V((v) << (n)) | ((v) >> (32 - (n)))) - -#define U8TO32_LITTLE(p) \ - (((u32)((p)[0]) ) | \ - ((u32)((p)[1]) << 8) | \ - ((u32)((p)[2]) << 16) | \ - ((u32)((p)[3]) << 24)) - -#define U32TO8_LITTLE(p, v) \ - do { \ - (p)[0] = U8V((v) ); \ - (p)[1] = U8V((v) >> 8); \ - (p)[2] = U8V((v) >> 16); \ - (p)[3] = U8V((v) >> 24); \ - } while (0) - -#define ROTATE(v,c) (ROTL32(v,c)) -#define XOR(v,w) ((v) ^ (w)) -#define PLUS(v,w) (U32V((v) + (w))) -#define PLUSONE(v) (PLUS((v),1)) - -#define QUARTERROUND(a,b,c,d) \ - a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ - c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ - a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ - c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); - -static const char sigma[16] = "expand 32-byte k"; -static const char tau[16] = "expand 16-byte k"; - -static void -chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ivbits) -{ - const char *constants; - - x->input[4] = U8TO32_LITTLE(k + 0); - x->input[5] = U8TO32_LITTLE(k + 4); - x->input[6] = U8TO32_LITTLE(k + 8); - x->input[7] = U8TO32_LITTLE(k + 12); - if (kbits == 256) { /* recommended */ - k += 16; - constants = sigma; - } else { /* kbits == 128 */ - constants = tau; - } - x->input[8] = U8TO32_LITTLE(k + 0); - x->input[9] = U8TO32_LITTLE(k + 4); - x->input[10] = U8TO32_LITTLE(k + 8); - x->input[11] = U8TO32_LITTLE(k + 12); - x->input[0] = U8TO32_LITTLE(constants + 0); - x->input[1] = U8TO32_LITTLE(constants + 4); - x->input[2] = U8TO32_LITTLE(constants + 8); - x->input[3] = U8TO32_LITTLE(constants + 12); -} - -static void -chacha_ivsetup(chacha_ctx *x,const u8 *iv) -{ - x->input[12] = 0; - x->input[13] = 0; - x->input[14] = U8TO32_LITTLE(iv + 0); - x->input[15] = U8TO32_LITTLE(iv + 4); -} - -static void -chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) -{ - u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; - u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; - u8 *ctarget = NULL; - u8 tmp[64]; - u_int i; - - if (!bytes) return; - - j0 = x->input[0]; - j1 = x->input[1]; - j2 = x->input[2]; - j3 = x->input[3]; - j4 = x->input[4]; - j5 = x->input[5]; - j6 = x->input[6]; - j7 = x->input[7]; - j8 = x->input[8]; - j9 = x->input[9]; - j10 = x->input[10]; - j11 = x->input[11]; - j12 = x->input[12]; - j13 = x->input[13]; - j14 = x->input[14]; - j15 = x->input[15]; - - for (;;) { - if (bytes < 64) { - for (i = 0;i < bytes;++i) tmp[i] = m[i]; - m = tmp; - ctarget = c; - c = tmp; - } - x0 = j0; - x1 = j1; - x2 = j2; - x3 = j3; - x4 = j4; - x5 = j5; - x6 = j6; - x7 = j7; - x8 = j8; - x9 = j9; - x10 = j10; - x11 = j11; - x12 = j12; - x13 = j13; - x14 = j14; - x15 = j15; - for (i = 20;i > 0;i -= 2) { - QUARTERROUND( x0, x4, x8,x12) - QUARTERROUND( x1, x5, x9,x13) - QUARTERROUND( x2, x6,x10,x14) - QUARTERROUND( x3, x7,x11,x15) - QUARTERROUND( x0, x5,x10,x15) - QUARTERROUND( x1, x6,x11,x12) - QUARTERROUND( x2, x7, x8,x13) - QUARTERROUND( x3, x4, x9,x14) - } - x0 = PLUS(x0,j0); - x1 = PLUS(x1,j1); - x2 = PLUS(x2,j2); - x3 = PLUS(x3,j3); - x4 = PLUS(x4,j4); - x5 = PLUS(x5,j5); - x6 = PLUS(x6,j6); - x7 = PLUS(x7,j7); - x8 = PLUS(x8,j8); - x9 = PLUS(x9,j9); - x10 = PLUS(x10,j10); - x11 = PLUS(x11,j11); - x12 = PLUS(x12,j12); - x13 = PLUS(x13,j13); - x14 = PLUS(x14,j14); - x15 = PLUS(x15,j15); - -#ifndef KEYSTREAM_ONLY - x0 = XOR(x0,U8TO32_LITTLE(m + 0)); - x1 = XOR(x1,U8TO32_LITTLE(m + 4)); - x2 = XOR(x2,U8TO32_LITTLE(m + 8)); - x3 = XOR(x3,U8TO32_LITTLE(m + 12)); - x4 = XOR(x4,U8TO32_LITTLE(m + 16)); - x5 = XOR(x5,U8TO32_LITTLE(m + 20)); - x6 = XOR(x6,U8TO32_LITTLE(m + 24)); - x7 = XOR(x7,U8TO32_LITTLE(m + 28)); - x8 = XOR(x8,U8TO32_LITTLE(m + 32)); - x9 = XOR(x9,U8TO32_LITTLE(m + 36)); - x10 = XOR(x10,U8TO32_LITTLE(m + 40)); - x11 = XOR(x11,U8TO32_LITTLE(m + 44)); - x12 = XOR(x12,U8TO32_LITTLE(m + 48)); - x13 = XOR(x13,U8TO32_LITTLE(m + 52)); - x14 = XOR(x14,U8TO32_LITTLE(m + 56)); - x15 = XOR(x15,U8TO32_LITTLE(m + 60)); -#endif - - j12 = PLUSONE(j12); - if (!j12) { - j13 = PLUSONE(j13); - /* stopping at 2^70 bytes per nonce is user's responsibility */ - } - - U32TO8_LITTLE(c + 0,x0); - U32TO8_LITTLE(c + 4,x1); - U32TO8_LITTLE(c + 8,x2); - U32TO8_LITTLE(c + 12,x3); - U32TO8_LITTLE(c + 16,x4); - U32TO8_LITTLE(c + 20,x5); - U32TO8_LITTLE(c + 24,x6); - U32TO8_LITTLE(c + 28,x7); - U32TO8_LITTLE(c + 32,x8); - U32TO8_LITTLE(c + 36,x9); - U32TO8_LITTLE(c + 40,x10); - U32TO8_LITTLE(c + 44,x11); - U32TO8_LITTLE(c + 48,x12); - U32TO8_LITTLE(c + 52,x13); - U32TO8_LITTLE(c + 56,x14); - U32TO8_LITTLE(c + 60,x15); - - if (bytes <= 64) { - if (bytes < 64) { - for (i = 0;i < bytes;++i) ctarget[i] = c[i]; - } - x->input[12] = j12; - x->input[13] = j13; - return; - } - bytes -= 64; - c += 64; -#ifndef KEYSTREAM_ONLY - m += 64; -#endif - } -} diff --git a/openbsd-compat/daemon.c b/openbsd-compat/daemon.c deleted file mode 100644 index 3efe14c..0000000 --- a/openbsd-compat/daemon.c +++ /dev/null @@ -1,82 +0,0 @@ -/* $OpenBSD: daemon.c,v 1.6 2005/08/08 08:05:33 espie Exp $ */ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. 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. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* OPENBSD ORIGINAL: lib/libc/gen/daemon.c */ - -#include "includes.h" - -#ifndef HAVE_DAEMON - -#include - -#ifdef HAVE_SYS_STAT_H -# include -#endif - -#ifdef HAVE_FCNTL_H -# include -#endif - -#ifdef HAVE_UNISTD_H -# include -#endif - -int -daemon(int nochdir, int noclose) -{ - int fd; - - switch (fork()) { - case -1: - return (-1); - case 0: - break; - default: - _exit(0); - } - - if (setsid() == -1) - return (-1); - - if (!nochdir) - (void)chdir("/"); - - if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { - (void)dup2(fd, STDIN_FILENO); - (void)dup2(fd, STDOUT_FILENO); - (void)dup2(fd, STDERR_FILENO); - if (fd > 2) - (void)close (fd); - } - return (0); -} - -#endif /* !HAVE_DAEMON */ - diff --git a/openbsd-compat/defines.h b/openbsd-compat/defines.h deleted file mode 100644 index fa9dbdf..0000000 --- a/openbsd-compat/defines.h +++ /dev/null @@ -1,881 +0,0 @@ -/* - * Copyright (c) 2012 Reyk Floeter - * Copyright (c) 1999-2003 Damien Miller. 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. - */ - -#ifndef _DEFINES_H -#define _DEFINES_H - -/* $Id: defines.h,v 1.145 2007/09/26 21:03:20 dtucker Exp $ */ - - -/* Constants */ - -#define YYSTYPE_IS_DECLARED 1 - -#if defined(HAVE_DECL_SHUT_RD) && HAVE_DECL_SHUT_RD == 0 -enum -{ - SHUT_RD = 0, /* No more receptions. */ - SHUT_WR, /* No more transmissions. */ - SHUT_RDWR /* No more receptions or transmissions. */ -}; -# define SHUT_RD SHUT_RD -# define SHUT_WR SHUT_WR -# define SHUT_RDWR SHUT_RDWR -#endif - -#ifndef IPTOS_LOWDELAY -# define IPTOS_LOWDELAY 0x10 -# define IPTOS_THROUGHPUT 0x08 -# define IPTOS_RELIABILITY 0x04 -# define IPTOS_LOWCOST 0x02 -# define IPTOS_MINCOST IPTOS_LOWCOST -#endif /* IPTOS_LOWDELAY */ - -#if !defined(HAVE_NETINET_IP_IPSP_H) && (defined(HAVE_NETINET6_IPSEC_H) || \ - defined(HAVE_NETIPSEC_IPSEC_H) || defined(HAVE_LINUX_IPSEC_H)) -#define IPSP_DIRECTION_IN IPSEC_DIR_INBOUND -#define IPSP_DIRECTION_OUT IPSEC_DIR_OUTBOUND /* XXX Linux: _FWD? */ -#endif - -#if defined(HAVE_NET_PFKEYV2_H) || defined(HAVE_LINUX_PFKEYV2_H) -#if !defined(SADB_X_ADDFLOW) && defined(SADB_X_SPDADD) -#define SADB_X_ADDFLOW SADB_X_SPDADD -#endif -#if !defined(SADB_X_DELFLOW) && defined(SADB_X_SPDDELETE) -#define SADB_X_DELFLOW SADB_X_SPDDELETE -#endif -#if !defined(SADB_X_FLOW_TYPE_DENY) -#define SADB_X_FLOW_TYPE_DENY 1 -#endif -#endif /* HAVE_NET_PFKEYV2_H || HAVE_LINUX_PFKEYV2_H */ - -#ifndef MAXHOSTNAMELEN -# define MAXHOSTNAMELEN 64 -#endif - -#ifndef LOGIN_NAME_MAX -# define LOGIN_NAME_MAX 9 -#endif - -#ifndef PATH_MAX -# ifdef _POSIX_PATH_MAX -# define PATH_MAX _POSIX_PATH_MAX -# else -# define PATH_MAX 64 -# endif -#endif - -/* - * Looks like ugly, but MAX_IMSGSIZE equals 16384, - * and if we don't care it will overflow for some struct - */ -#if PATH_MAX > 1024 -# undef PATH_MAX -# define PATH_MAX 1024 -#endif - -#ifndef MAXPATHLEN -# define MAXPATHLEN PATH_MAX -#endif - -#if MAXPATHLEN > 1024 -# undef MAXPATHLEN -# define MAXPATHLEN 1024 -#endif - -#if defined(HAVE_DECL_MAXSYMLINKS) && HAVE_DECL_MAXSYMLINKS == 0 -# define MAXSYMLINKS 5 -#endif - -#ifndef MAXLOGNAME -#define MAXLOGNAME LOGIN_NAME_MAX -#endif - -#ifndef STDIN_FILENO -# define STDIN_FILENO 0 -#endif -#ifndef STDOUT_FILENO -# define STDOUT_FILENO 1 -#endif -#ifndef STDERR_FILENO -# define STDERR_FILENO 2 -#endif - -#ifndef NGROUPS_MAX /* Disable groupaccess if NGROUP_MAX is not set */ -#ifdef NGROUPS -#define NGROUPS_MAX NGROUPS -#else -#define NGROUPS_MAX 0 -#endif -#endif - -#if defined(HAVE_DECL_O_NONBLOCK) && HAVE_DECL_O_NONBLOCK == 0 -# define O_NONBLOCK 00004 /* Non Blocking Open */ -#endif - -#ifndef S_ISDIR -# define S_ISDIR(mode) (((mode) & (_S_IFMT)) == (_S_IFDIR)) -#endif /* S_ISDIR */ - -#ifndef S_ISREG -# define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG)) -#endif /* S_ISREG */ - -#ifndef S_ISLNK -# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) -#endif /* S_ISLNK */ - -#ifndef S_IXUSR -# define S_IXUSR 0000100 /* execute/search permission, */ -# define S_IXGRP 0000010 /* execute/search permission, */ -# define S_IXOTH 0000001 /* execute/search permission, */ -# define _S_IWUSR 0000200 /* write permission, */ -# define S_IWUSR _S_IWUSR /* write permission, owner */ -# define S_IWGRP 0000020 /* write permission, group */ -# define S_IWOTH 0000002 /* write permission, other */ -# define S_IRUSR 0000400 /* read permission, owner */ -# define S_IRGRP 0000040 /* read permission, group */ -# define S_IROTH 0000004 /* read permission, other */ -# define S_IRWXU 0000700 /* read, write, execute */ -# define S_IRWXG 0000070 /* read, write, execute */ -# define S_IRWXO 0000007 /* read, write, execute */ -#endif /* S_IXUSR */ - -#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) -#define MAP_ANON MAP_ANONYMOUS -#endif - -#ifndef MAP_FAILED -# define MAP_FAILED ((void *)-1) -#endif - -/* *-*-nto-qnx doesn't define this constant in the system headers */ -#ifdef MISSING_NFDBITS -# define NFDBITS (8 * sizeof(unsigned long)) -#endif - -/* -SCO Open Server 3 has INADDR_LOOPBACK defined in rpc/rpc.h but -including rpc/rpc.h breaks Solaris 6 -*/ -#ifndef INADDR_LOOPBACK -#define INADDR_LOOPBACK ((u_long)0x7f000001) -#endif - -/* Types */ - -/* If sys/types.h does not supply intXX_t, supply them ourselves */ -/* (or die trying) */ - -#ifndef HAVE_U_INT -typedef unsigned int u_int; -#endif - -#ifndef HAVE_INTXX_T -# if (SIZEOF_CHAR == 1) -typedef char int8_t; -# else -# error "8 bit int type not found." -# endif -# if (SIZEOF_SHORT_INT == 2) -typedef short int int16_t; -# else -# ifdef _UNICOS -# if (SIZEOF_SHORT_INT == 4) -typedef short int16_t; -# else -typedef long int16_t; -# endif -# else -# error "16 bit int type not found." -# endif /* _UNICOS */ -# endif -# if (SIZEOF_INT == 4) -typedef int int32_t; -# else -# ifdef _UNICOS -typedef long int32_t; -# else -# error "32 bit int type not found." -# endif /* _UNICOS */ -# endif -#endif - -/* If sys/types.h does not supply u_intXX_t, supply them ourselves */ -#ifndef HAVE_U_INTXX_T -# ifdef HAVE_UINTXX_T -typedef uint8_t u_int8_t; -typedef uint16_t u_int16_t; -typedef uint32_t u_int32_t; -# define HAVE_U_INTXX_T 1 -# else -# if (SIZEOF_CHAR == 1) -typedef unsigned char u_int8_t; -# else -# error "8 bit int type not found." -# endif -# if (SIZEOF_SHORT_INT == 2) -typedef unsigned short int u_int16_t; -# else -# ifdef _UNICOS -# if (SIZEOF_SHORT_INT == 4) -typedef unsigned short u_int16_t; -# else -typedef unsigned long u_int16_t; -# endif -# else -# error "16 bit int type not found." -# endif -# endif -# if (SIZEOF_INT == 4) -typedef unsigned int u_int32_t; -# else -# ifdef _UNICOS -typedef unsigned long u_int32_t; -# else -# error "32 bit int type not found." -# endif -# endif -# endif -#define __BIT_TYPES_DEFINED__ -#endif - -/* 64-bit types */ -#ifndef HAVE_INT64_T -# if (SIZEOF_LONG_INT == 8) -typedef long int int64_t; -# else -# if (SIZEOF_LONG_LONG_INT == 8) -typedef long long int int64_t; -# endif -# endif -#endif -#ifndef HAVE_U_INT64_T -# if (SIZEOF_LONG_INT == 8) -typedef unsigned long int u_int64_t; -# else -# if (SIZEOF_LONG_LONG_INT == 8) -typedef unsigned long long int u_int64_t; -# endif -# endif -#endif - -#ifndef HAVE_U_CHAR -typedef unsigned char u_char; -# define HAVE_U_CHAR -#endif /* HAVE_U_CHAR */ - -#ifndef SIZE_T_MAX -#define SIZE_T_MAX ULONG_MAX -#endif /* SIZE_T_MAX */ - -#ifndef HAVE_SIZE_T -typedef unsigned int size_t; -# define HAVE_SIZE_T -# define SIZE_T_MAX UINT_MAX -#endif /* HAVE_SIZE_T */ - -#ifndef HAVE_SSIZE_T -typedef int ssize_t; -# define HAVE_SSIZE_T -#endif /* HAVE_SSIZE_T */ - -#ifndef HAVE_CLOCK_T -typedef long clock_t; -# define HAVE_CLOCK_T -#endif /* HAVE_CLOCK_T */ - -#ifndef HAVE_SA_FAMILY_T -typedef int sa_family_t; -# define HAVE_SA_FAMILY_T -#endif /* HAVE_SA_FAMILY_T */ - -#ifndef HAVE_PID_T -typedef int pid_t; -# define HAVE_PID_T -#endif /* HAVE_PID_T */ - -#ifndef HAVE_SIG_ATOMIC_T -typedef int sig_atomic_t; -# define HAVE_SIG_ATOMIC_T -#endif /* HAVE_SIG_ATOMIC_T */ - -#ifndef HAVE_MODE_T -typedef int mode_t; -# define HAVE_MODE_T -#endif /* HAVE_MODE_T */ - -#if !defined(HAVE_SS_FAMILY_IN_SS) && defined(HAVE___SS_FAMILY_IN_SS) -# define ss_family __ss_family -#endif /* !defined(HAVE_SS_FAMILY_IN_SS) && defined(HAVE_SA_FAMILY_IN_SS) */ - -#ifndef HAVE_SYS_UN_H -struct sockaddr_un { - short sun_family; /* AF_UNIX */ - char sun_path[108]; /* path name (gag) */ -}; -#endif /* HAVE_SYS_UN_H */ - -#if !defined(AF_LINK) && defined(AF_PACKET) -#define AF_LINK AF_PACKET /* XXX workaround on Linux */ -#endif - -#ifndef HAVE_IN_ADDR_T -typedef u_int32_t in_addr_t; -#endif - -#ifndef HAVE_IN_PORT_T -typedef u_int16_t in_port_t; -#endif - -#if defined(BROKEN_SYS_TERMIO_H) && !defined(_STRUCT_WINSIZE) -#define _STRUCT_WINSIZE -struct winsize { - unsigned short ws_row; /* rows, in characters */ - unsigned short ws_col; /* columns, in character */ - unsigned short ws_xpixel; /* horizontal size, pixels */ - unsigned short ws_ypixel; /* vertical size, pixels */ -}; -#endif - -/* *-*-nto-qnx does not define this type in the system headers */ -#ifdef MISSING_FD_MASK - typedef unsigned long int fd_mask; -#endif - -#if defined(HAVE_LIBKERN_OSBYTEORDER_H) -/* Byte conversion on OS X */ -#define betoh16 OSSwapBigToHostInt16 -#define betoh32 OSSwapBigToHostInt32 -#define betoh64 OSSwapBigToHostInt64 -#define htobe16 OSSwapHostToBigInt16 -#define htobe32 OSSwapHostToBigInt32 -#define htobe64 OSSwapHostToBigInt64 -#else -#if !defined(betoh16) -#define betoh16 be16toh -#endif -#if !defined(betoh32) -#define betoh32 be32toh -#endif -#if !defined(betoh64) -#define betoh64 be64toh -#endif -#endif - -#if defined(HAVE_APPLE_NATT) && !defined(SADB_X_EXT_NATT) -/* - * These are hidden in Apple XNU's private pfkeyv2.h header - */ -#define SADB_X_EXT_NATT 0x0002 /* Enable UDP encapsulation */ -#define SADB_X_EXT_NATT_KEEPALIVE 0x0004 /* Send NAT-T keepalives */ -#define SADB_X_EXT_NATT_MULTIPLEUSERS 0x0008 /* Use for VPN gateways */ -#define SADB_X_EXT_NATT_DETECTED_PEER 0x1000 /* Opposite of KEEPALIVE */ - -struct sadb_sa_natt { - u_int16_t sadb_sa_natt_port; - u_int16_t sadb_reserved; - u_int32_t sadb_reserved1; -}; -#endif - -/* Paths */ - -#ifndef _PATH_BSHELL -# define _PATH_BSHELL "/bin/sh" -#endif - -#ifdef USER_PATH -# ifdef _PATH_STDPATH -# undef _PATH_STDPATH -# endif -# define _PATH_STDPATH USER_PATH -#endif - -#ifndef _PATH_STDPATH -# define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin" -#endif - -#ifndef SUPERUSER_PATH -# define SUPERUSER_PATH _PATH_STDPATH -#endif - -#ifndef _PATH_DEVNULL -# define _PATH_DEVNULL "/dev/null" -#endif - -#ifndef MAIL_DIRECTORY -# define MAIL_DIRECTORY "/var/spool/mail" -#endif - -/* remove it -#ifndef MAILDIR -# define MAILDIR MAIL_DIRECTORY -#endif */ - -#if !defined(_PATH_MAILDIR) && defined(MAILDIR) -# define _PATH_MAILDIR MAILDIR -#endif /* !defined(_PATH_MAILDIR) && defined(MAILDIR) */ - -#ifndef _PATH_NOLOGIN -# define _PATH_NOLOGIN "/etc/nologin" -#endif - -/* Define this to be the path of the xauth program. */ -#ifdef XAUTH_PATH -#define _PATH_XAUTH XAUTH_PATH -#endif /* XAUTH_PATH */ - -/* derived from XF4/xc/lib/dps/Xlibnet.h */ -#ifndef X_UNIX_PATH -# ifdef __hpux -# define X_UNIX_PATH "/var/spool/sockets/X11/%u" -# else -# define X_UNIX_PATH "/tmp/.X11-unix/X%u" -# endif -#endif /* X_UNIX_PATH */ -#define _PATH_UNIX_X X_UNIX_PATH - -#ifndef _PATH_TTY -# define _PATH_TTY "/dev/tty" -#endif - -/* Macros */ - -#if defined(HAVE_LOGIN_GETCAPBOOL) && defined(HAVE_LOGIN_CAP_H) -# define HAVE_LOGIN_CAP -#endif - -#ifndef MAX -# define MAX(a,b) (((a)>(b))?(a):(b)) -# define MIN(a,b) (((a)<(b))?(a):(b)) -#endif - -#ifndef roundup -# define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) -#endif - -#ifndef timersub -#define timersub(a, b, result) \ - do { \ - (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ - (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ - if ((result)->tv_usec < 0) { \ - --(result)->tv_sec; \ - (result)->tv_usec += 1000000; \ - } \ - } while (0) -#endif - -#ifndef timespeccmp -#define timespeccmp(a, b, cmp) \ - (((a)->tv_sec == (b)->tv_sec) ? \ - ((a)->tv_nsec cmp (b)->tv_nsec) : \ - ((a)->tv_sec cmp (b)->tv_sec)) -#endif - -#ifndef timespecsub -#define timespecsub(a, b, result) \ - do { \ - (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ - (result)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec; \ - if ((result)->tv_nsec < 0) { \ - --(result)->tv_sec; \ - (result)->tv_nsec += 1000000000L; \ - } \ - } while (0) -#endif - -#ifndef TIMEVAL_TO_TIMESPEC -#define TIMEVAL_TO_TIMESPEC(tv, ts) { \ - (ts)->tv_sec = (tv)->tv_sec; \ - (ts)->tv_nsec = (tv)->tv_usec * 1000; \ -} -#endif - -#ifndef TIMESPEC_TO_TIMEVAL -#define TIMESPEC_TO_TIMEVAL(tv, ts) { \ - (tv)->tv_sec = (ts)->tv_sec; \ - (tv)->tv_usec = (ts)->tv_nsec / 1000; \ -} -#endif - -#ifndef __P -# define __P(x) x -#endif - -#if !defined(IN6_IS_ADDR_V4MAPPED) -# define IN6_IS_ADDR_V4MAPPED(a) \ - ((((u_int32_t *) (a))[0] == 0) && (((u_int32_t *) (a))[1] == 0) && \ - (((u_int32_t *) (a))[2] == htonl (0xffff))) -#endif /* !defined(IN6_IS_ADDR_V4MAPPED) */ - -#if !defined(__GNUC__) || (__GNUC__ < 2) -# define __attribute__(x) -#endif /* !defined(__GNUC__) || (__GNUC__ < 2) */ - -#ifndef __packed -# define __packed __attribute__((packed)) -#endif - -#if defined(__clang__) -# if defined(__dead) -# undef __dead -# endif -# define __dead __attribute__((noreturn)) __attribute__((analyzer_noreturn)) -#elif !defined(__dead) -# define __dead __attribute__((noreturn)) -#endif - -#if !defined(HAVE_ATTRIBUTE__SENTINEL__) && !defined(__sentinel__) -# define __sentinel__ -#endif - -#if !defined(HAVE_ATTRIBUTE__BOUNDED__) && !defined(__bounded__) -# define __bounded__(x, y, z...) -#endif - -#if !defined(HAVE_ATTRIBUTE__NONNULL__) && !defined(__nonnull__) -# define __nonnull__(x) -#endif - -/* *-*-nto-qnx doesn't define this macro in the system headers */ -#ifdef MISSING_HOWMANY -# define howmany(x,y) (((x)+((y)-1))/(y)) -#endif - -#ifndef OSSH_ALIGNBYTES -#define OSSH_ALIGNBYTES (sizeof(int) - 1) -#endif -#ifndef __CMSG_ALIGN -#define __CMSG_ALIGN(p) (((u_int)(p) + OSSH_ALIGNBYTES) &~ OSSH_ALIGNBYTES) -#endif - -/* Length of the contents of a control message of length len */ -#ifndef CMSG_LEN -#define CMSG_LEN(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + (len)) -#endif - -/* Length of the space taken up by a padded control message of length len */ -#ifndef CMSG_SPACE -#define CMSG_SPACE(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(len)) -#endif - -/* given pointer to struct cmsghdr, return pointer to data */ -#ifndef CMSG_DATA -#define CMSG_DATA(cmsg) ((u_char *)(cmsg) + __CMSG_ALIGN(sizeof(struct cmsghdr))) -#endif /* CMSG_DATA */ - -/* - * RFC 2292 requires to check msg_controllen, in case that the kernel returns - * an empty list for some reasons. - */ -#ifndef CMSG_FIRSTHDR -#define CMSG_FIRSTHDR(mhdr) \ - ((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \ - (struct cmsghdr *)(mhdr)->msg_control : \ - (struct cmsghdr *)NULL) -#endif /* CMSG_FIRSTHDR */ - -#if defined(HAVE_DECL_OFFSETOF) && HAVE_DECL_OFFSETOF == 0 -# define offsetof(type, member) ((size_t) &((type *)0)->member) -#endif - -/* Set up BSD-style BYTE_ORDER definition if it isn't there already */ -/* XXX: doesn't try to cope with strange byte orders (PDP_ENDIAN) */ -#ifndef BYTE_ORDER -# ifndef LITTLE_ENDIAN -# define LITTLE_ENDIAN 1234 -# endif /* LITTLE_ENDIAN */ -# ifndef BIG_ENDIAN -# define BIG_ENDIAN 4321 -# endif /* BIG_ENDIAN */ -# ifdef WORDS_BIGENDIAN -# define BYTE_ORDER BIG_ENDIAN -# else /* WORDS_BIGENDIAN */ -# define BYTE_ORDER LITTLE_ENDIAN -# endif /* WORDS_BIGENDIAN */ -#endif /* BYTE_ORDER */ - -/* Function replacement / compatibility hacks */ - -#if !defined(HAVE_GETADDRINFO) && (defined(HAVE_OGETADDRINFO) || defined(HAVE_NGETADDRINFO)) -# define HAVE_GETADDRINFO -#endif - -#ifndef HAVE_GETOPT_OPTRESET -# undef getopt -# undef opterr -# undef optind -# undef optopt -# undef optreset -# undef optarg -# define getopt(ac, av, o) BSDgetopt(ac, av, o) -# define opterr BSDopterr -# define optind BSDoptind -# define optopt BSDoptopt -# define optreset BSDoptreset -# define optarg BSDoptarg -#endif - -#if defined(BROKEN_GETADDRINFO) && defined(HAVE_GETADDRINFO) -# undef HAVE_GETADDRINFO -#endif -#if defined(BROKEN_GETADDRINFO) && defined(HAVE_FREEADDRINFO) -# undef HAVE_FREEADDRINFO -#endif -#if defined(BROKEN_GETADDRINFO) && defined(HAVE_GAI_STRERROR) -# undef HAVE_GAI_STRERROR -#endif - -#if defined(BROKEN_UPDWTMPX) && defined(HAVE_UPDWTMPX) -# undef HAVE_UPDWTMPX -#endif - -#if defined(BROKEN_SHADOW_EXPIRE) && defined(HAS_SHADOW_EXPIRE) -# undef HAS_SHADOW_EXPIRE -#endif - -#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) && \ - defined(SYSLOG_R_SAFE_IN_SIGHAND) -# define DO_LOG_SAFE_IN_SIGHAND -#endif - -#if !defined(HAVE_MEMMOVE) && defined(HAVE_BCOPY) -# define memmove(s1, s2, n) bcopy((s2), (s1), (n)) -#endif /* !defined(HAVE_MEMMOVE) && defined(HAVE_BCOPY) */ - -#if defined(HAVE_VHANGUP) && !defined(HAVE_DEV_PTMX) -# define USE_VHANGUP -#endif /* defined(HAVE_VHANGUP) && !defined(HAVE_DEV_PTMX) */ - -#ifdef USE_BSM_AUDIT -# define SSH_AUDIT_EVENTS -# define CUSTOM_SSH_AUDIT_EVENTS -#endif - -/* OPENSSL_free() is Free() in versions before OpenSSL 0.9.6 */ -#if !defined(OPENSSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x0090600f) -# define OPENSSL_free(x) Free(x) -#endif - -#if !defined(HAVE___func__) && defined(HAVE___FUNCTION__) -# define __func__ __FUNCTION__ -#elif !defined(HAVE___func__) -# define __func__ "" -#endif - -#if defined(KRB5) && !defined(HEIMDAL) -# define krb5_get_err_text(context,code) error_message(code) -#endif - -#if defined(SKEYCHALLENGE_4ARG) -# define _compat_skeychallenge(a,b,c,d) skeychallenge(a,b,c,d) -#else -# define _compat_skeychallenge(a,b,c,d) skeychallenge(a,b,c) -#endif - -/* Maximum number of file descriptors available */ -#ifndef OPEN_MAX -# ifdef HAVE_SYSCONF -# define OPEN_MAX sysconf(_SC_OPEN_MAX) -# else -# define OPEN_MAX 256 -# endif -#endif - -#if defined(__Lynx__) - /* - * LynxOS defines these in param.h which we do not want to include since - * it will also pull in a bunch of kernel definitions. - */ -# define ALIGNBYTES (sizeof(int) - 1) -# define ALIGN(p) (((unsigned)p + ALIGNBYTES) & ~ALIGNBYTES) - /* Missing prototypes on LynxOS */ - int snprintf (char *, size_t, const char *, ...); - int mkstemp (char *); - char *crypt (const char *, const char *); - int seteuid (uid_t); - int setegid (gid_t); - char *mkdtemp (char *); - int rresvport_af (int *, sa_family_t); - int innetgr (const char *, const char *, const char *, const char *); -#endif - -/* - * Define this to use pipes instead of socketpairs for communicating with the - * client program. Socketpairs do not seem to work on all systems. - * - * configure.ac sets this for a few OS's which are known to have problems - * but you may need to set it yourself - */ -/* #define USE_PIPES 1 */ - -/** - ** login recorder definitions - **/ - -/* FIXME: put default paths back in */ -#ifndef UTMP_FILE -# ifdef _PATH_UTMP -# define UTMP_FILE _PATH_UTMP -# else -# ifdef CONF_UTMP_FILE -# define UTMP_FILE CONF_UTMP_FILE -# endif -# endif -#endif -#ifndef WTMP_FILE -# ifdef _PATH_WTMP -# define WTMP_FILE _PATH_WTMP -# else -# ifdef CONF_WTMP_FILE -# define WTMP_FILE CONF_WTMP_FILE -# endif -# endif -#endif -/* pick up the user's location for lastlog if given */ -#ifndef LASTLOG_FILE -# ifdef _PATH_LASTLOG -# define LASTLOG_FILE _PATH_LASTLOG -# else -# ifdef CONF_LASTLOG_FILE -# define LASTLOG_FILE CONF_LASTLOG_FILE -# endif -# endif -#endif - -#if defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW) -# define USE_SHADOW -#endif - -/* The login() library function in libutil is first choice */ -#if defined(HAVE_LOGIN) && !defined(DISABLE_LOGIN) -# define USE_LOGIN - -#else -/* Simply select your favourite login types. */ -/* Can't do if-else because some systems use several... */ -# if defined(UTMPX_FILE) && !defined(DISABLE_UTMPX) -# define USE_UTMPX -# endif -# if defined(UTMP_FILE) && !defined(DISABLE_UTMP) -# define USE_UTMP -# endif -# if defined(WTMPX_FILE) && !defined(DISABLE_WTMPX) -# define USE_WTMPX -# endif -# if defined(WTMP_FILE) && !defined(DISABLE_WTMP) -# define USE_WTMP -# endif - -#endif - -#ifndef UT_LINESIZE -# define UT_LINESIZE 8 -#endif - -/* I hope that the presence of LASTLOG_FILE is enough to detect this */ -#if defined(LASTLOG_FILE) && !defined(DISABLE_LASTLOG) -# define USE_LASTLOG -#endif - -#ifdef HAVE_OSF_SIA -# ifdef USE_SHADOW -# undef USE_SHADOW -# endif -# define CUSTOM_SYS_AUTH_PASSWD 1 -#endif - -#if defined(HAVE_LIBIAF) && defined(HAVE_SET_ID) -# define CUSTOM_SYS_AUTH_PASSWD 1 -#endif -#if defined(HAVE_LIBIAF) && defined(HAVE_SET_ID) && !defined(BROKEN_LIBIAF) -# define USE_LIBIAF -#endif - -/* HP-UX 11.11 */ -#ifdef BTMP_FILE -# define _PATH_BTMP BTMP_FILE -#endif - -#if defined(USE_BTMP) && defined(_PATH_BTMP) -# define CUSTOM_FAILED_LOGIN -#endif - -/** end of login recorder definitions */ - -#ifdef BROKEN_GETGROUPS -# define getgroups(a,b) ((a)==0 && (b)==NULL ? NGROUPS_MAX : getgroups((a),(b))) -#endif - -#if defined(HAVE_MMAP) && defined(BROKEN_MMAP) -# undef HAVE_MMAP -#endif - -#ifndef IOV_MAX -# if defined(_XOPEN_IOV_MAX) -# define IOV_MAX _XOPEN_IOV_MAX -# elif defined(DEF_IOV_MAX) -# define IOV_MAX DEF_IOV_MAX -# else -# define IOV_MAX 16 -# endif -#endif - -#ifndef EAI_NODATA -# ifdef EAI_NONAME -# define EAI_NODATA EAI_NONAME -# else -# error "Neither EAI_NODATA and EAI_NONAME are defined! :(" -# endif -#endif - -#ifndef CLOCK_MONOTONIC -#define CLOCK_MONOTONIC -1 -#endif - -#ifdef HAVE_DIRENT_H -# include -# define NAMLEN(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen -# ifdef HAVE_SYS_NDIR_H -# include -# endif -# ifdef HAVE_SYS_DIR_H -# include -# endif -# ifdef HAVE_NDIR_H -# include -# endif -#endif - -#ifndef _PASSWORD_LEN -#define _PASSWORD_LEN 128 -#endif - -#endif /* _DEFINES_H */ diff --git a/openbsd-compat/entropy.c b/openbsd-compat/entropy.c deleted file mode 100644 index ea798a7..0000000 --- a/openbsd-compat/entropy.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2001 Damien Miller. 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. - */ - -#include "includes.h" - -#include -#include -#ifdef HAVE_SYS_UN_H -# include -#endif - -#include -#include - -#include -#include -#include -#include -#include /* for offsetof */ - -#include -#include -#include - -/* - * Portable OpenSSH PRNG seeding: - * If OpenSSL has not "internally seeded" itself (e.g. pulled data from - * /dev/random), then collect RANDOM_SEED_SIZE bytes of randomness from - * PRNGd. - */ -#ifndef OPENSSL_PRNG_ONLY - -#define RANDOM_SEED_SIZE 48 - -/* - * Collect 'len' bytes of entropy into 'buf' from PRNGD/EGD daemon - * listening either on 'tcp_port', or via Unix domain socket at * - * 'socket_path'. - * Either a non-zero tcp_port or a non-null socket_path must be - * supplied. - * Returns 0 on success, -1 on error - */ -int -get_random_bytes_prngd(unsigned char *buf, int len, - unsigned short tcp_port, char *socket_path) -{ - int fd, addr_len, rval, errors; - u_char msg[2]; - struct sockaddr_storage addr; - struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr; - struct sockaddr_un *addr_un = (struct sockaddr_un *)&addr; - mysig_t old_sigpipe; - - /* Sanity checks */ - if (socket_path == NULL && tcp_port == 0) - errx(1, "You must specify a port or a socket"); - if (socket_path != NULL && - strlen(socket_path) >= sizeof(addr_un->sun_path)) - errx(1, "Random pool path is too long"); - if (len <= 0 || len > 255) - errx(1, "Too many bytes (%d) to read from PRNGD", len); - - memset(&addr, '\0', sizeof(addr)); - - if (tcp_port != 0) { - addr_in->sin_family = AF_INET; - addr_in->sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr_in->sin_port = htons(tcp_port); - addr_len = sizeof(*addr_in); - } else { - addr_un->sun_family = AF_UNIX; - strlcpy(addr_un->sun_path, socket_path, - sizeof(addr_un->sun_path)); - addr_len = offsetof(struct sockaddr_un, sun_path) + - strlen(socket_path) + 1; - } - - old_sigpipe = mysignal(SIGPIPE, SIG_IGN); - - errors = 0; - rval = -1; -reopen: - fd = socket(addr.ss_family, SOCK_STREAM, 0); - if (fd == -1) { - warn("Couldn't create socket"); - goto done; - } - - if (connect(fd, (struct sockaddr*)&addr, addr_len) == -1) { - if (tcp_port != 0) { - warn("Couldn't connect to PRNGD port %d", - tcp_port); - } else { - warn("Couldn't connect to PRNGD socket \"%s\"", - addr_un->sun_path); - } - goto done; - } - - /* Send blocking read request to PRNGD */ - msg[0] = 0x02; - msg[1] = len; - - if (atomicio(vwrite, fd, msg, sizeof(msg)) != sizeof(msg)) { - if (errno == EPIPE && errors < 10) { - close(fd); - errors++; - goto reopen; - } - warn("Couldn't write to PRNGD socket"); - goto done; - } - - if (atomicio(read, fd, buf, len) != (size_t)len) { - if (errno == EPIPE && errors < 10) { - close(fd); - errors++; - goto reopen; - } - warn("Couldn't read from PRNGD socket"); - goto done; - } - - rval = 0; -done: - mysignal(SIGPIPE, old_sigpipe); - if (fd != -1) - close(fd); - return rval; -} - -static int -seed_from_prngd(unsigned char *buf, size_t bytes) -{ -#ifdef PRNGD_PORT - debug("trying egd/prngd port %d", PRNGD_PORT); - if (get_random_bytes_prngd(buf, bytes, PRNGD_PORT, NULL) == 0) - return 0; -#endif -#ifdef PRNGD_SOCKET - debug("trying egd/prngd socket %s", PRNGD_SOCKET); - if (get_random_bytes_prngd(buf, bytes, 0, PRNGD_SOCKET) == 0) - return 0; -#endif - return -1; -} -#endif /* OPENSSL_PRNG_ONLY */ - -void -seed_rng(void) -{ -#ifndef OPENSSL_PRNG_ONLY - unsigned char buf[RANDOM_SEED_SIZE]; -#endif - /* - * OpenSSL version numbers: MNNFFPPS: major minor fix patch status - * We match major, minor, fix and status (not patch) for <1.0.0. - * After that, we acceptable compatible fix versions (so we - * allow 1.0.1 to work with 1.0.0). Going backwards is only allowed - * within a patch series. - */ - u_long version_mask = SSLeay() >= 0x1000000f ? ~0xffff0L : ~0xff0L; - if (((SSLeay() ^ OPENSSL_VERSION_NUMBER) & version_mask) || - (SSLeay() >> 12) < (OPENSSL_VERSION_NUMBER >> 12)) - errx(1, "OpenSSL version mismatch. Built against %lx, you " - "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay()); - -#ifndef OPENSSL_PRNG_ONLY - if (RAND_status() == 1) { - warnx("RNG is ready, skipping seeding"); - return; - } - - if (seed_from_prngd(buf, sizeof(buf)) == -1) - errx(1, "Could not obtain seed from PRNGd"); - RAND_add(buf, sizeof(buf), sizeof(buf)); - memset(buf, '\0', sizeof(buf)); - -#endif /* OPENSSL_PRNG_ONLY */ - if (RAND_status() != 1) - errx(1, "PRNG is not seeded"); -} diff --git a/openbsd-compat/fgetln.c b/openbsd-compat/fgetln.c deleted file mode 100644 index c7fef41..0000000 --- a/openbsd-compat/fgetln.c +++ /dev/null @@ -1,63 +0,0 @@ -/* $OpenBSD: util.c,v 1.23 2007/09/17 09:28:36 espie Exp $ */ -/* $NetBSD: util.c,v 1.10 1996/12/31 17:56:04 christos Exp $ */ - -/* - * Copyright (c) 2001 Marc Espie. - * - * 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 OPENBSD PROJECT AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD - * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* OPENBSD ORIGINAL: usr.bin/make/util.c */ - -#include "includes.h" - -#ifndef HAVE_FGETLN - -#include - -char * -fgetln(stream, len) - FILE *stream; - size_t *len; -{ - static char *buffer = NULL; - static size_t buflen = 0; - - if (buflen == 0) { - buflen = 512; - if ((buffer = malloc(buflen+1)) == NULL) - err(255, "fatal: malloc: out of memory"); - } - if (fgets(buffer, buflen+1, stream) == NULL) - return NULL; - *len = strlen(buffer); - while (*len == buflen && buffer[*len-1] != '\n') { - if ((buffer = realloc(buffer, 2*buflen + 1)) == NULL) - err(255, "fatal: realloc: out of memory"); - if (fgets(buffer + buflen, buflen + 1, stream) == NULL) - return NULL; - *len += strlen(buffer + buflen); - buflen *= 2; - } - return buffer; -} -#endif diff --git a/openbsd-compat/getopt.c b/openbsd-compat/getopt.c deleted file mode 100644 index 5450e43..0000000 --- a/openbsd-compat/getopt.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 1987, 1993, 1994 - * The Regents of the University of California. 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. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* OPENBSD ORIGINAL: lib/libc/stdlib/getopt.c */ - -#include "includes.h" -#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET) - -#if defined(LIBC_SCCS) && !defined(lint) -static char *rcsid = "$OpenBSD: getopt.c,v 1.5 2003/06/02 20:18:37 millert Exp $"; -#endif /* LIBC_SCCS and not lint */ - -#include -#include -#include - -int BSDopterr = 1, /* if error message should be printed */ - BSDoptind = 1, /* index into parent argv vector */ - BSDoptopt, /* character checked for validity */ - BSDoptreset; /* reset getopt */ -char *BSDoptarg; /* argument associated with option */ - -#define BADCH (int)'?' -#define BADARG (int)':' -#define EMSG "" - -/* - * getopt -- - * Parse argc/argv argument vector. - */ -int -BSDgetopt(nargc, nargv, ostr) - int nargc; - char * const *nargv; - const char *ostr; -{ - extern char *__progname; - static char *place = EMSG; /* option letter processing */ - char *oli; /* option letter list index */ - - if (ostr == NULL) - return (-1); - - if (BSDoptreset || !*place) { /* update scanning pointer */ - BSDoptreset = 0; - if (BSDoptind >= nargc || *(place = nargv[BSDoptind]) != '-') { - place = EMSG; - return (-1); - } - if (place[1] && *++place == '-') { /* found "--" */ - ++BSDoptind; - place = EMSG; - return (-1); - } - } /* option letter okay? */ - if ((BSDoptopt = (int)*place++) == (int)':' || - !(oli = strchr(ostr, BSDoptopt))) { - /* - * if the user didn't specify '-' as an option, - * assume it means -1. - */ - if (BSDoptopt == (int)'-') - return (-1); - if (!*place) - ++BSDoptind; - if (BSDopterr && *ostr != ':') - (void)fprintf(stderr, - "%s: illegal option -- %c\n", __progname, BSDoptopt); - return (BADCH); - } - if (*++oli != ':') { /* don't need argument */ - BSDoptarg = NULL; - if (!*place) - ++BSDoptind; - } - else { /* need an argument */ - if (*place) /* no white space */ - BSDoptarg = place; - else if (nargc <= ++BSDoptind) { /* no arg */ - place = EMSG; - if (*ostr == ':') - return (BADARG); - if (BSDopterr) - (void)fprintf(stderr, - "%s: option requires an argument -- %c\n", - __progname, BSDoptopt); - return (BADCH); - } - else /* white space */ - BSDoptarg = nargv[BSDoptind]; - place = EMSG; - ++BSDoptind; - } - return (BSDoptopt); /* dump back option letter */ -} - -#endif /* !defined(HAVE_GETOPT) || !defined(HAVE_OPTRESET) */ diff --git a/openbsd-compat/imsg-buffer.c b/openbsd-compat/imsg-buffer.c deleted file mode 100644 index 2e7aef8..0000000 --- a/openbsd-compat/imsg-buffer.c +++ /dev/null @@ -1,305 +0,0 @@ -/* $OpenBSD: imsg-buffer.c,v 1.2 2012/06/02 21:46:53 gilles Exp $ */ - -/* - * Copyright (c) 2003, 2004 Henning Brauer - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "imsg.h" - -int ibuf_realloc(struct ibuf *, size_t); -void ibuf_enqueue(struct msgbuf *, struct ibuf *); -void ibuf_dequeue(struct msgbuf *, struct ibuf *); - -struct ibuf * -ibuf_open(size_t len) -{ - struct ibuf *buf; - - if ((buf = calloc(1, sizeof(struct ibuf))) == NULL) - return (NULL); - if ((buf->buf = malloc(len)) == NULL) { - free(buf); - return (NULL); - } - buf->size = buf->max = len; - buf->fd = -1; - - return (buf); -} - -struct ibuf * -ibuf_dynamic(size_t len, size_t max) -{ - struct ibuf *buf; - - if (max < len) - return (NULL); - - if ((buf = ibuf_open(len)) == NULL) - return (NULL); - - if (max > 0) - buf->max = max; - - return (buf); -} - -int -ibuf_realloc(struct ibuf *buf, size_t len) -{ - u_char *b; - - /* on static buffers max is eq size and so the following fails */ - if (buf->wpos + len > buf->max) { - errno = ENOMEM; - return (-1); - } - - b = realloc(buf->buf, buf->wpos + len); - if (b == NULL) - return (-1); - buf->buf = b; - buf->size = buf->wpos + len; - - return (0); -} - -int -ibuf_add(struct ibuf *buf, const void *data, size_t len) -{ - if (buf->wpos + len > buf->size) - if (ibuf_realloc(buf, len) == -1) - return (-1); - - memcpy(buf->buf + buf->wpos, data, len); - buf->wpos += len; - return (0); -} - -void * -ibuf_reserve(struct ibuf *buf, size_t len) -{ - void *b; - - if (buf->wpos + len > buf->size) - if (ibuf_realloc(buf, len) == -1) - return (NULL); - - b = buf->buf + buf->wpos; - buf->wpos += len; - return (b); -} - -void * -ibuf_seek(struct ibuf *buf, size_t pos, size_t len) -{ - /* only allowed to seek in already written parts */ - if (pos + len > buf->wpos) - return (NULL); - - return (buf->buf + pos); -} - -size_t -ibuf_size(struct ibuf *buf) -{ - return (buf->wpos); -} - -size_t -ibuf_left(struct ibuf *buf) -{ - return (buf->max - buf->wpos); -} - -void -ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf) -{ - ibuf_enqueue(msgbuf, buf); -} - -int -ibuf_write(struct msgbuf *msgbuf) -{ - struct iovec iov[IOV_MAX]; - struct ibuf *buf; - unsigned int i = 0; - ssize_t n; - - bzero(&iov, sizeof(iov)); - TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { - if (i >= IOV_MAX) - break; - iov[i].iov_base = buf->buf + buf->rpos; - iov[i].iov_len = buf->wpos - buf->rpos; - i++; - } - -again: - if ((n = writev(msgbuf->fd, iov, i)) == -1) { - if (errno == EAGAIN || errno == EINTR) - goto again; - if (errno == ENOBUFS) - errno = EAGAIN; - return (-1); - } - - if (n == 0) { /* connection closed */ - errno = 0; - return (0); - } - - msgbuf_drain(msgbuf, n); - - return (1); -} - -void -ibuf_free(struct ibuf *buf) -{ - free(buf->buf); - free(buf); -} - -void -msgbuf_init(struct msgbuf *msgbuf) -{ - msgbuf->queued = 0; - msgbuf->fd = -1; - TAILQ_INIT(&msgbuf->bufs); -} - -void -msgbuf_drain(struct msgbuf *msgbuf, size_t n) -{ - struct ibuf *buf, *next; - - for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; - buf = next) { - next = TAILQ_NEXT(buf, entry); - if (buf->rpos + n >= buf->wpos) { - n -= buf->wpos - buf->rpos; - ibuf_dequeue(msgbuf, buf); - } else { - buf->rpos += n; - n = 0; - } - } -} - -void -msgbuf_clear(struct msgbuf *msgbuf) -{ - struct ibuf *buf; - - while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL) - ibuf_dequeue(msgbuf, buf); -} - -int -msgbuf_write(struct msgbuf *msgbuf) -{ - struct iovec iov[IOV_MAX]; - struct ibuf *buf; - unsigned int i = 0; - ssize_t n; - struct msghdr msg; - struct cmsghdr *cmsg; - union { - struct cmsghdr hdr; - char buf[CMSG_SPACE(sizeof(int))]; - } cmsgbuf; - - bzero(&iov, sizeof(iov)); - bzero(&msg, sizeof(msg)); - TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { - if (i >= IOV_MAX) - break; - iov[i].iov_base = buf->buf + buf->rpos; - iov[i].iov_len = buf->wpos - buf->rpos; - i++; - if (buf->fd != -1) - break; - } - - msg.msg_iov = iov; - msg.msg_iovlen = i; - - if (buf != NULL && buf->fd != -1) { - msg.msg_control = (caddr_t)&cmsgbuf.buf; - msg.msg_controllen = sizeof(cmsgbuf.buf); - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - *(int *)CMSG_DATA(cmsg) = buf->fd; - } - -again: - if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) { - if (errno == EAGAIN || errno == EINTR) - goto again; - if (errno == ENOBUFS) - errno = EAGAIN; - return (-1); - } - - if (n == 0) { /* connection closed */ - errno = 0; - return (0); - } - - /* - * assumption: fd got sent if sendmsg sent anything - * this works because fds are passed one at a time - */ - if (buf != NULL && buf->fd != -1) { - close(buf->fd); - buf->fd = -1; - } - - msgbuf_drain(msgbuf, n); - - return (1); -} - -void -ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf) -{ - TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry); - msgbuf->queued++; -} - -void -ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf) -{ - TAILQ_REMOVE(&msgbuf->bufs, buf, entry); - - if (buf->fd != -1) - close(buf->fd); - - msgbuf->queued--; - ibuf_free(buf); -} diff --git a/openbsd-compat/imsg.c b/openbsd-compat/imsg.c deleted file mode 100644 index a4536a2..0000000 --- a/openbsd-compat/imsg.c +++ /dev/null @@ -1,323 +0,0 @@ -/* $OpenBSD: imsg.c,v 1.2 2012/06/02 21:46:53 gilles Exp $ */ - -/* - * Copyright (c) 2003, 2004 Henning Brauer - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "imsg.h" - -int imsg_fd_overhead = 0; - -int imsg_get_fd(struct imsgbuf *); - -void -imsg_init(struct imsgbuf *ibuf, int fd) -{ - msgbuf_init(&ibuf->w); - bzero(&ibuf->r, sizeof(ibuf->r)); - ibuf->fd = fd; - ibuf->w.fd = fd; - ibuf->pid = getpid(); - TAILQ_INIT(&ibuf->fds); -} - -int -available_fds(int n) -{ - int i, ret, fds[256]; - - if (n > (int)(sizeof(fds)/sizeof(fds[0]))) - return (1); - - ret = 0; - for (i = 0; i < n; i++) { - fds[i] = -1; - if ((fds[i] = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - ret = 1; - break; - } - } - - for (i = 0; i < n && fds[i] >= 0; i++) - close(fds[i]); - - return (ret); -} - -ssize_t -imsg_read(struct imsgbuf *ibuf) -{ - struct msghdr msg; - struct cmsghdr *cmsg; - union { - struct cmsghdr hdr; - char buf[CMSG_SPACE(sizeof(int) * 1)]; - } cmsgbuf; - struct iovec iov; - ssize_t n = -1; - int fd; - struct imsg_fd *ifd; - - bzero(&msg, sizeof(msg)); - - iov.iov_base = ibuf->r.buf + ibuf->r.wpos; - iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = &cmsgbuf.buf; - msg.msg_controllen = sizeof(cmsgbuf.buf); - - if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) - return (-1); - -again: - if (available_fds(imsg_fd_overhead + - (CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))) { - errno = EAGAIN; - return (-1); - } - - if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) { - if (errno == EMSGSIZE) - goto fail; - if (errno != EINTR && errno != EAGAIN) - goto fail; - goto again; - } - - ibuf->r.wpos += n; - - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; - cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_RIGHTS) { - int i; - int j; - - /* - * We only accept one file descriptor. Due to C - * padding rules, our control buffer might contain - * more than one fd, and we must close them. - */ - j = ((char *)cmsg + cmsg->cmsg_len - - (char *)CMSG_DATA(cmsg)) / sizeof(int); - for (i = 0; i < j; i++) { - fd = ((int *)CMSG_DATA(cmsg))[i]; - if (ifd != NULL) { - ifd->fd = fd; - TAILQ_INSERT_TAIL(&ibuf->fds, ifd, - entry); - ifd = NULL; - } else - close(fd); - } - } - /* we do not handle other ctl data level */ - } - -fail: - if (ifd) - free(ifd); - return (n); -} - -ssize_t -imsg_get(struct imsgbuf *ibuf, struct imsg *imsg) -{ - size_t av, left, datalen; - - av = ibuf->r.wpos; - - if (IMSG_HEADER_SIZE > av) - return (0); - - memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr)); - if (imsg->hdr.len < IMSG_HEADER_SIZE || - imsg->hdr.len > MAX_IMSGSIZE) { - errno = ERANGE; - return (-1); - } - if (imsg->hdr.len > av) - return (0); - datalen = imsg->hdr.len - IMSG_HEADER_SIZE; - ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE; - if ((imsg->data = malloc(datalen)) == NULL) - return (-1); - - if (imsg->hdr.flags & IMSGF_HASFD) - imsg->fd = imsg_get_fd(ibuf); - else - imsg->fd = -1; - - memcpy(imsg->data, ibuf->r.rptr, datalen); - - if (imsg->hdr.len < av) { - left = av - imsg->hdr.len; - memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left); - ibuf->r.wpos = left; - } else - ibuf->r.wpos = 0; - - return (datalen + IMSG_HEADER_SIZE); -} - -int -imsg_compose(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, - pid_t pid, int fd, void *data, u_int16_t datalen) -{ - struct ibuf *wbuf; - - if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) - return (-1); - - if (imsg_add(wbuf, data, datalen) == -1) - return (-1); - - wbuf->fd = fd; - - imsg_close(ibuf, wbuf); - - return (1); -} - -int -imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, - pid_t pid, int fd, const struct iovec *iov, int iovcnt) -{ - struct ibuf *wbuf; - int i, datalen = 0; - - for (i = 0; i < iovcnt; i++) - datalen += iov[i].iov_len; - - if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) - return (-1); - - for (i = 0; i < iovcnt; i++) - if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1) - return (-1); - - wbuf->fd = fd; - - imsg_close(ibuf, wbuf); - - return (1); -} - -/* ARGSUSED */ -struct ibuf * -imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, - pid_t pid, u_int16_t datalen) -{ - struct ibuf *wbuf; - struct imsg_hdr hdr; - - datalen += IMSG_HEADER_SIZE; - if (datalen > MAX_IMSGSIZE) { - errno = ERANGE; - return (NULL); - } - - hdr.type = type; - hdr.flags = 0; - hdr.peerid = peerid; - if ((hdr.pid = pid) == 0) - hdr.pid = ibuf->pid; - if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) { - return (NULL); - } - if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1) - return (NULL); - - return (wbuf); -} - -int -imsg_add(struct ibuf *msg, void *data, u_int16_t datalen) -{ - if (datalen) - if (ibuf_add(msg, data, datalen) == -1) { - ibuf_free(msg); - return (-1); - } - return (datalen); -} - -void -imsg_close(struct imsgbuf *ibuf, struct ibuf *msg) -{ - struct imsg_hdr *hdr; - - hdr = (struct imsg_hdr *)msg->buf; - - hdr->flags &= ~IMSGF_HASFD; - if (msg->fd != -1) - hdr->flags |= IMSGF_HASFD; - - hdr->len = (u_int16_t)msg->wpos; - - ibuf_close(&ibuf->w, msg); -} - -void -imsg_free(struct imsg *imsg) -{ - free(imsg->data); -} - -int -imsg_get_fd(struct imsgbuf *ibuf) -{ - int fd; - struct imsg_fd *ifd; - - if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL) - return (-1); - - fd = ifd->fd; - TAILQ_REMOVE(&ibuf->fds, ifd, entry); - free(ifd); - - return (fd); -} - -int -imsg_flush(struct imsgbuf *ibuf) -{ - while (ibuf->w.queued) - if (msgbuf_write(&ibuf->w) < 0) - return (-1); - return (0); -} - -void -imsg_clear(struct imsgbuf *ibuf) -{ - int fd; - - msgbuf_clear(&ibuf->w); - while ((fd = imsg_get_fd(ibuf)) != -1) - close(fd); -} diff --git a/openbsd-compat/imsg.h b/openbsd-compat/imsg.h deleted file mode 100644 index d691f7d..0000000 --- a/openbsd-compat/imsg.h +++ /dev/null @@ -1,112 +0,0 @@ -/* $OpenBSD: imsg.h,v 1.2 2010/06/23 07:53:55 nicm Exp $ */ - -/* - * Copyright (c) 2006, 2007 Pierre-Yves Ritschard - * Copyright (c) 2006, 2007, 2008 Reyk Floeter - * Copyright (c) 2003, 2004 Henning Brauer - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _IMSG_H_ -#define _IMSG_H_ - -#define IBUF_READ_SIZE 65535 -#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) -#define MAX_IMSGSIZE 16384 - -struct ibuf { - TAILQ_ENTRY(ibuf) entry; - u_char *buf; - size_t size; - size_t max; - size_t wpos; - size_t rpos; - int fd; -}; - -struct msgbuf { - TAILQ_HEAD(, ibuf) bufs; - u_int32_t queued; - int fd; -}; - -struct ibuf_read { - u_char buf[IBUF_READ_SIZE]; - u_char *rptr; - size_t wpos; -}; - -struct imsg_fd { - TAILQ_ENTRY(imsg_fd) entry; - int fd; -}; - -struct imsgbuf { - TAILQ_HEAD(, imsg_fd) fds; - struct ibuf_read r; - struct msgbuf w; - int fd; - pid_t pid; -}; - -#define IMSGF_HASFD 1 - -struct imsg_hdr { - u_int32_t type; - u_int16_t len; - u_int16_t flags; - u_int32_t peerid; - u_int32_t pid; -}; - -struct imsg { - struct imsg_hdr hdr; - int fd; - void *data; -}; - - -/* buffer.c */ -struct ibuf *ibuf_open(size_t); -struct ibuf *ibuf_dynamic(size_t, size_t); -int ibuf_add(struct ibuf *, const void *, size_t); -void *ibuf_reserve(struct ibuf *, size_t); -void *ibuf_seek(struct ibuf *, size_t, size_t); -size_t ibuf_size(struct ibuf *); -size_t ibuf_left(struct ibuf *); -void ibuf_close(struct msgbuf *, struct ibuf *); -int ibuf_write(struct msgbuf *); -void ibuf_free(struct ibuf *); -void msgbuf_init(struct msgbuf *); -void msgbuf_clear(struct msgbuf *); -int msgbuf_write(struct msgbuf *); -void msgbuf_drain(struct msgbuf *, size_t); - -/* imsg.c */ -void imsg_init(struct imsgbuf *, int); -ssize_t imsg_read(struct imsgbuf *); -ssize_t imsg_get(struct imsgbuf *, struct imsg *); -int imsg_compose(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, - int, void *, u_int16_t); -int imsg_composev(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, - int, const struct iovec *, int); -struct ibuf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, - u_int16_t); -int imsg_add(struct ibuf *, void *, u_int16_t); -void imsg_close(struct imsgbuf *, struct ibuf *); -void imsg_free(struct imsg *); -int imsg_flush(struct imsgbuf *); -void imsg_clear(struct imsgbuf *); - -#endif diff --git a/openbsd-compat/includes.h b/openbsd-compat/includes.h deleted file mode 100644 index 073845d..0000000 --- a/openbsd-compat/includes.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2012 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* based on includes.h from OpenSSH: - * - * $OpenBSD: includes.h,v 1.54 2006/07/22 20:48:23 stevesk Exp $ - * - * Author: Tatu Ylonen - * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - * All rights reserved - * This file includes most of the needed system headers. - * - * As far as I am concerned, the code I have written for this software - * can be used freely for any purpose. Any derived versions of this - * software must be clearly marked as such, and if the derived work is - * incompatible with the protocol description in the RFC file, it must be - * called by a name other than "ssh" or "Secure Shell". - */ - -#ifndef INCLUDES_H -#define INCLUDES_H - -#include "config.h" - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE /* activate extra prototypes for glibc */ -#endif - -#include -#include /* For CMSG_* */ - -#ifdef HAVE_LIMITS_H -# include /* For PATH_MAX */ -#endif - -#ifdef HAVE_BSTRING_H -# include -#endif - -#ifdef HAVE_ASM_BYTEORDER_H -# include -#endif - -#if defined(HAVE_ENDIAN_H) -# include -#elif defined(HAVE_SYS_ENDIAN_H) -# include -#endif - -#ifdef HAVE_PATHS_H -# include -#endif - -/* - *-*-nto-qnx needs these headers for strcasecmp and LASTLOG_FILE respectively - */ -#ifdef HAVE_STRINGS_H -# include -#endif -#ifdef HAVE_LOGIN_H -# include -#endif - -#ifdef HAVE_RPC_TYPES_H -# include /* For INADDR_LOOPBACK */ -#endif -#ifdef USE_PAM -#if defined(HAVE_SECURITY_PAM_APPL_H) -# include -#elif defined (HAVE_PAM_PAM_APPL_H) -# include -#endif -#endif -#include - -#ifdef HAVE_ERR_H -#include -#endif - -#if defined (HAVE_NETINET_IN_H) -#include -#endif - -#ifdef HAVE_NETDB_H -# include -#endif - -#if defined (HAVE_NETINET6_IPSEC_H) -#include -#elif defined(HAVE_NETIPSEC_IPSEC_H) -#include -#elif defined (HAVE_LINUX_IPSEC_H) -#include -#endif - -#if defined(HAVE_LIBKERN_OSBYTEORDER_H) -#include -#endif - -#ifdef HAVE_NET_PFKEYV2_H -#include -#endif - -#ifdef HAVE_LINUX_PFKEYV2_H -#include -#endif - -#ifdef HAVE_SYS_SYSCTL_H -#include -#endif - -#include /* For OPENSSL_VERSION_NUMBER */ - -#include "defines.h" - -#include "openbsd-compat.h" - -#endif /* INCLUDES_H */ diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h deleted file mode 100644 index 26bf649..0000000 --- a/openbsd-compat/openbsd-compat.h +++ /dev/null @@ -1,182 +0,0 @@ -/* $Id: openbsd-compat.h,v 1.51 2010/10/07 10:25:29 djm Exp $ */ - -/* - * Copyright (c) 1999-2003 Damien Miller. All rights reserved. - * Copyright (c) 2003 Ben Lindstrom. All rights reserved. - * Copyright (c) 2002 Tim Rice. 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. - */ - -#ifndef _OPENBSD_COMPAT_H -#define _OPENBSD_COMPAT_H - -#include "includes.h" - -#include - -#include -#include - -#ifndef AI_MASK -/* valid flags for addrinfo */ -#define AI_MASK \ - (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_NUMERICSERV) -#ifdef AI_FQDN -#define AI_MASK (AI_MASK | AI_FQDN) -#endif -#endif - -#ifndef AI_FQDN -#define AI_FQDN AI_CANONNAME -#endif - -#include "sys-queue.h" -#include "sys-tree.h" -#include "vis.h" - -#ifdef HAVE_SYS_TIME_H -#include -#endif - -#ifndef SIZE_MAX -#include -#endif - -/* From OpenNTPD portable */ -#if !defined(SA_LEN) -# if defined(HAVE_STRUCT_SOCKADDR_SA_LEN) -# define SA_LEN(x) ((x)->sa_len) -# else -# define SA_LEN(x) ((x)->sa_family == AF_INET6 ? \ - sizeof(struct sockaddr_in6) : \ - sizeof(struct sockaddr_in)) -# endif -#endif - -/* From OpenBGPD portable */ -#if !defined(SS_LEN) -# if defined(HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN) -# define SS_LEN(x) ((x)->ss_len) -# else -# define SS_LEN(x) SA_LEN((struct sockaddr *)(x)) -# endif -#endif - -#ifdef HAVE_SS_LEN -# define STORAGE_LEN(X) ((X).ss_len) -# define SET_STORAGE_LEN(X, Y) do { STORAGE_LEN(X) = (Y); } while(0) -#elif defined(HAVE___SS_LEN) -# define STORAGE_LEN(X) ((X).__ss_len) -# define SET_STORAGE_LEN(X, Y) do { STORAGE_LEN(X) = (Y); } while(0) -#else -# define STORAGE_LEN(X) (STORAGE_FAMILY(X) == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)) -# define SET_STORAGE_LEN(X, Y) (void) 0 -#endif - - -#ifndef HAVE_CLOSEFROM -void closefrom(int); -#endif - -#ifndef HAVE_STRLCPY -size_t strlcpy(char *dst, const char *src, size_t size); -#endif - -#ifndef HAVE_STRLCAT -size_t strlcat(char *dst, const char *src, size_t size); -#endif - -#ifndef HAVE_STRMODE -void strmode(int mode, char *p); -#endif - -#ifndef HAVE_DIRNAME -char *dirname(const char *path); -#endif - -#ifndef HAVE_STRSEP -char *strsep(char **stringp, const char *delim); -#endif - -#ifndef HAVE_SETPROCTITLE -void setproctitle(const char *fmt, ...); -void compat_init_setproctitle(int argc, char *argv[]); -#endif - -#ifndef HAVE_SETRESGID -int setresgid(uid_t rgid, uid_t egid, uid_t sgid); -#endif - -#ifndef HAVE_SETRESUID -int setresuid(uid_t ruid, uid_t euid, uid_t suid); -#endif - -#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET) -int BSDgetopt(int argc, char * const *argv, const char *opts); -char *BSDoptarg; /* argument associated with option */ -int BSDoptind; /* index into parent argv vector */ -#endif - -#ifndef HAVE_GETPEEREID -int getpeereid(int , uid_t *, gid_t *); -#endif - -#ifndef HAVE_ARC4RANDOM -unsigned int arc4random(void); -void arc4random_stir(void); -#endif /* !HAVE_ARC4RANDOM */ - -#ifndef HAVE_ARC4RANDOM_BUF -void arc4random_buf(void *, size_t); -#endif - -#ifndef HAVE_ARC4RANDOM_UNIFORM -u_int32_t arc4random_uniform(u_int32_t); -#endif - -#ifndef HAVE_FGETLN -#include -#include -char * fgetln(FILE *stream, size_t *len); -#endif - -#ifndef HAVE_FPARSELN -char * fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags); -#endif - -#ifndef HAVE_STRTONUM -long long strtonum(const char *nptr, long long minval, long long maxval, const char **errstr); -#endif - -#ifndef HAVE_STRMODE -void strmode(int mode, char *p); -#endif - -#ifndef HAVE_FMT_SCALED -#define FMT_SCALED_STRSIZE 7 -int scan_scaled(char *scaled, long long *result); -int fmt_scaled(long long number, char *result); -#endif - -void seed_rng(void); - -#endif /* _OPENBSD_COMPAT_H */ diff --git a/openbsd-compat/setproctitle.c b/openbsd-compat/setproctitle.c deleted file mode 100644 index 40a6737..0000000 --- a/openbsd-compat/setproctitle.c +++ /dev/null @@ -1,163 +0,0 @@ -/* Based on conf.c from UCB sendmail 8.8.8 */ - -/* - * Copyright 2003 Damien Miller - * Copyright (c) 1983, 1995-1997 Eric P. Allman - * Copyright (c) 1988, 1993 - * The Regents of the University of California. 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. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef HAVE_SETPROCTITLE - -#include -#include -#include -#include -#ifdef HAVE_SYS_PSTAT_H -#include -#endif -#include - -#include - -#define SPT_NONE 0 /* don't use it at all */ -#define SPT_PSTAT 1 /* use pstat(PSTAT_SETCMD, ...) */ -#define SPT_REUSEARGV 2 /* cover argv with title information */ - -#ifndef SPT_TYPE -# define SPT_TYPE SPT_NONE -#endif - -#ifndef SPT_PADCHAR -# define SPT_PADCHAR '\0' -#endif - -#if SPT_TYPE == SPT_REUSEARGV -static char *argv_start = NULL; -static size_t argv_env_len = 0; -#endif - -#endif /* HAVE_SETPROCTITLE */ - -void -compat_init_setproctitle(int argc, char *argv[]) -{ -#if defined(SPT_TYPE) && SPT_TYPE == SPT_REUSEARGV - extern char **environ; - char *lastargv = NULL; - char **envp = environ; - int i; - - /* - * NB: This assumes that argv has already been copied out of the - * way. This is true for sshd, but may not be true for other - * programs. Beware. - */ - - if (argc == 0 || argv[0] == NULL) - return; - - /* Fail if we can't allocate room for the new environment */ - for (i = 0; envp[i] != NULL; i++) - ; - if ((environ = calloc(i + 1, sizeof(*environ))) == NULL) { - environ = envp; /* put it back */ - return; - } - - /* - * Find the last argv string or environment variable within - * our process memory area. - */ - for (i = 0; i < argc; i++) { - if (lastargv == NULL || lastargv + 1 == argv[i]) - lastargv = argv[i] + strlen(argv[i]); - } - for (i = 0; envp[i] != NULL; i++) { - if (lastargv + 1 == envp[i]) - lastargv = envp[i] + strlen(envp[i]); - } - - argv[1] = NULL; - argv_start = argv[0]; - argv_env_len = lastargv - argv[0] - 1; - - /* - * Copy environment - * XXX - will truncate env on strdup fail - */ - for (i = 0; envp[i] != NULL; i++) - environ[i] = strdup(envp[i]); - environ[i] = NULL; -#endif /* SPT_REUSEARGV */ -} - -#ifndef HAVE_SETPROCTITLE -void -setproctitle(const char *fmt, ...) -{ -#if SPT_TYPE != SPT_NONE - va_list ap; - char buf[1024], ptitle[1024]; - size_t len; - extern char *__progname; -#if SPT_TYPE == SPT_PSTAT - union pstun pst; -#endif - -#if SPT_TYPE == SPT_REUSEARGV - if (argv_env_len <= 0) - return; -#endif - - strlcpy(buf, __progname, sizeof(buf)); - - va_start(ap, fmt); - if (fmt != NULL) { - len = strlcat(buf, ": ", sizeof(buf)); - if (len < sizeof(buf)) - vsnprintf(buf + len, sizeof(buf) - len , fmt, ap); - } - va_end(ap); - strnvis(ptitle, buf, sizeof(ptitle), - VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL); - -#if SPT_TYPE == SPT_PSTAT - pst.pst_command = ptitle; - pstat(PSTAT_SETCMD, pst, strlen(ptitle), 0, 0); -#elif SPT_TYPE == SPT_REUSEARGV -/* debug("setproctitle: copy \"%s\" into len %d", - buf, argv_env_len); */ - len = strlcpy(argv_start, ptitle, argv_env_len); - for(; len < argv_env_len; len++) - argv_start[len] = SPT_PADCHAR; -#endif - -#endif /* SPT_NONE */ -} - -#endif /* HAVE_SETPROCTITLE */ diff --git a/openbsd-compat/setresguid.c b/openbsd-compat/setresguid.c deleted file mode 100644 index f332d50..0000000 --- a/openbsd-compat/setresguid.c +++ /dev/null @@ -1,65 +0,0 @@ -/* Subset of uidswap.c from portable OpenSSH */ - -/* $OpenBSD: uidswap.c,v 1.35 2006/08/03 03:34:42 deraadt Exp $ */ -/* - * Author: Tatu Ylonen - * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - * All rights reserved - * Code for uid-swapping. - * - * As far as I am concerned, the code I have written for this software - * can be used freely for any purpose. Any derived versions of this - * software must be clearly marked as such, and if the derived work is - * incompatible with the protocol description in the RFC file, it must be - * called by a name other than "ssh" or "Secure Shell". - */ - -#include "includes.h" - -#ifdef HAVE_UNISTD_H -# include -#endif - -#ifndef HAVE_SETRESGID -int setresgid(uid_t rgid, uid_t egid, uid_t sgid) -{ - -#if defined(HAVE_SETRESGID) && !defined(BROKEN_SETRESGID) - if (setresgid(rgid, egid, sgid) < 0) - err(1, "setresgid %u", (u_int)rgid); -#elif defined(HAVE_SETREGID) && !defined(BROKEN_SETREGID) - if (setregid(rgid, egid) < 0) - err(1, "setregid %u", (u_int)rgid); -#else - if (setegid(egid) < 0) - err(1, "setegid %u", (u_int)egid); - if (setgid(rgid) < 0) - err(1, "setgid %u", (u_int)rgid); -#endif - return (0); -} -#endif /* HAVE_SETRESGID */ - - - -#ifndef HAVE_SETRESUID -int setresuid(uid_t ruid, uid_t euid, uid_t suid) -{ - -#if defined(HAVE_SETRESUID) && !defined(BROKEN_SETRESUID) - if (setresuid(ruid, euid, suid) < 0) - err(1, "setresuid %u", (u_int)ruid); -#elif defined(HAVE_SETREUID) && !defined(BROKEN_SETREUID) - if (setreuid(ruid, euid) < 0) - err(1, "setreuid %u", (u_int)ruid); -#else -# ifndef SETEUID_BREAKS_SETUID - if (seteuid(euid) < 0) - err(1, "seteuid %u", (u_int)euid); -# endif - if (setuid(ruid) < 0) - err(1, "setuid %u", (u_int)ruid); -#endif - return (0); -} -#endif /* HAVE_SETRESUID */ diff --git a/openbsd-compat/strlcat.c b/openbsd-compat/strlcat.c deleted file mode 100644 index bcc1b61..0000000 --- a/openbsd-compat/strlcat.c +++ /dev/null @@ -1,62 +0,0 @@ -/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ - -/* - * Copyright (c) 1998 Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* OPENBSD ORIGINAL: lib/libc/string/strlcat.c */ - -#include "includes.h" -#ifndef HAVE_STRLCAT - -#include -#include - -/* - * Appends src to string dst of size siz (unlike strncat, siz is the - * full size of dst, not space left). At most siz-1 characters - * will be copied. Always NUL terminates (unless siz <= strlen(dst)). - * Returns strlen(src) + MIN(siz, strlen(initial dst)). - * If retval >= siz, truncation occurred. - */ -size_t -strlcat(char *dst, const char *src, size_t siz) -{ - char *d = dst; - const char *s = src; - size_t n = siz; - size_t dlen; - - /* Find the end of dst and adjust bytes left but don't go past end */ - while (n-- != 0 && *d != '\0') - d++; - dlen = d - dst; - n = siz - dlen; - - if (n == 0) - return(dlen + strlen(s)); - while (*s != '\0') { - if (n != 1) { - *d++ = *s; - n--; - } - s++; - } - *d = '\0'; - - return(dlen + (s - src)); /* count does not include NUL */ -} - -#endif /* !HAVE_STRLCAT */ diff --git a/openbsd-compat/strlcpy.c b/openbsd-compat/strlcpy.c deleted file mode 100644 index b4b1b60..0000000 --- a/openbsd-compat/strlcpy.c +++ /dev/null @@ -1,58 +0,0 @@ -/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ - -/* - * Copyright (c) 1998 Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* OPENBSD ORIGINAL: lib/libc/string/strlcpy.c */ - -#include "includes.h" -#ifndef HAVE_STRLCPY - -#include -#include - -/* - * Copy src to string dst of size siz. At most siz-1 characters - * will be copied. Always NUL terminates (unless siz == 0). - * Returns strlen(src); if retval >= siz, truncation occurred. - */ -size_t -strlcpy(char *dst, const char *src, size_t siz) -{ - char *d = dst; - const char *s = src; - size_t n = siz; - - /* Copy as many bytes as will fit */ - if (n != 0) { - while (--n != 0) { - if ((*d++ = *s++) == '\0') - break; - } - } - - /* Not enough room in dst, add NUL and traverse rest of src */ - if (n == 0) { - if (siz != 0) - *d = '\0'; /* NUL-terminate dst */ - while (*s++) - ; - } - - return(s - src - 1); /* count does not include NUL */ -} - -#endif /* !HAVE_STRLCPY */ diff --git a/openbsd-compat/strtonum.c b/openbsd-compat/strtonum.c deleted file mode 100644 index 88c74e2..0000000 --- a/openbsd-compat/strtonum.c +++ /dev/null @@ -1,74 +0,0 @@ -/* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */ - -/* - * Copyright (c) 2004 Ted Unangst and Todd Miller - * All rights reserved. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* OPENBSD ORIGINAL: lib/libc/stdlib/strtonum.c */ - -#ifdef HAVE_CONFIG_H -#include "includes.h" -#endif - -#ifndef HAVE_STRTONUM -#include -#include -#include - -#define INVALID 1 -#define TOOSMALL 2 -#define TOOLARGE 3 - -long long -strtonum(const char *numstr, long long minval, long long maxval, - const char **errstrp) -{ - long long ll = 0; - char *ep; - int error = 0; - struct errval { - const char *errstr; - int err; - } ev[4] = { - { NULL, 0 }, - { "invalid", EINVAL }, - { "too small", ERANGE }, - { "too large", ERANGE }, - }; - - ev[0].err = errno; - errno = 0; - if (minval > maxval) - error = INVALID; - else { - ll = strtoll(numstr, &ep, 10); - if (numstr == ep || *ep != '\0') - error = INVALID; - else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) - error = TOOSMALL; - else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) - error = TOOLARGE; - } - if (errstrp != NULL) - *errstrp = ev[error].errstr; - errno = ev[error].err; - if (error) - ll = 0; - - return (ll); -} - -#endif /* HAVE_STRTONUM */ diff --git a/openbsd-compat/sys-queue.h b/openbsd-compat/sys-queue.h deleted file mode 100644 index a75c754..0000000 --- a/openbsd-compat/sys-queue.h +++ /dev/null @@ -1,660 +0,0 @@ -/* $OpenBSD: queue.h,v 1.36 2012/04/11 13:29:14 naddy Exp $ */ -/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ - -/* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. 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. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)queue.h 8.5 (Berkeley) 8/20/94 - */ - -/* OPENBSD ORIGINAL: sys/openbsd-compat/sys-queue.h */ - -#ifndef _FAKE_QUEUE_H_ -#define _FAKE_QUEUE_H_ - -/* - * Require for OS/X and other platforms that have old/broken/incomplete - * . - */ -#undef SLIST_HEAD -#undef SLIST_HEAD_INITIALIZER -#undef SLIST_ENTRY -#undef SLIST_FIRST -#undef SLIST_END -#undef SLIST_EMPTY -#undef SLIST_NEXT -#undef SLIST_FOREACH -#undef SLIST_FOREACH_SAFE -#undef SLIST_INIT -#undef SLIST_INSERT_AFTER -#undef SLIST_INSERT_HEAD -#undef SLIST_REMOVE_AFTER -#undef SLIST_REMOVE_HEAD -#undef SLIST_REMOVE -#undef LIST_HEAD -#undef LIST_HEAD_INITIALIZER -#undef LIST_ENTRY -#undef LIST_FIRST -#undef LIST_END -#undef LIST_EMPTY -#undef LIST_NEXT -#undef LIST_FOREACH -#undef LIST_FOREACH_SAFE -#undef LIST_INIT -#undef LIST_INSERT_AFTER -#undef LIST_INSERT_BEFORE -#undef LIST_INSERT_HEAD -#undef LIST_REMOVE -#undef LIST_REPLACE -#undef SIMPLEQ_HEAD -#undef SIMPLEQ_HEAD_INITIALIZER -#undef SIMPLEQ_ENTRY -#undef SIMPLEQ_FIRST -#undef SIMPLEQ_END -#undef SIMPLEQ_EMPTY -#undef SIMPLEQ_NEXT -#undef SIMPLEQ_FOREACH -#undef SIMPLEQ_FOREACH_SAFE -#undef SIMPLEQ_INIT -#undef SIMPLEQ_INSERT_HEAD -#undef SIMPLEQ_INSERT_TAIL -#undef SIMPLEQ_INSERT_AFTER -#undef SIMPLEQ_REMOVE_HEAD -#undef SIMPLEQ_REMOVE_AFTER -#undef TAILQ_HEAD -#undef TAILQ_HEAD_INITIALIZER -#undef TAILQ_ENTRY -#undef TAILQ_FIRST -#undef TAILQ_END -#undef TAILQ_NEXT -#undef TAILQ_LAST -#undef TAILQ_PREV -#undef TAILQ_EMPTY -#undef TAILQ_FOREACH -#undef TAILQ_FOREACH_SAFE -#undef TAILQ_FOREACH_REVERSE -#undef TAILQ_FOREACH_REVERSE_SAFE -#undef TAILQ_INIT -#undef TAILQ_INSERT_HEAD -#undef TAILQ_INSERT_TAIL -#undef TAILQ_INSERT_AFTER -#undef TAILQ_INSERT_BEFORE -#undef TAILQ_REMOVE -#undef TAILQ_REPLACE -#undef CIRCLEQ_HEAD -#undef CIRCLEQ_HEAD_INITIALIZER -#undef CIRCLEQ_ENTRY -#undef CIRCLEQ_FIRST -#undef CIRCLEQ_LAST -#undef CIRCLEQ_END -#undef CIRCLEQ_NEXT -#undef CIRCLEQ_PREV -#undef CIRCLEQ_EMPTY -#undef CIRCLEQ_FOREACH -#undef CIRCLEQ_FOREACH_SAFE -#undef CIRCLEQ_FOREACH_REVERSE -#undef CIRCLEQ_FOREACH_REVERSE_SAFE -#undef CIRCLEQ_INIT -#undef CIRCLEQ_INSERT_AFTER -#undef CIRCLEQ_INSERT_BEFORE -#undef CIRCLEQ_INSERT_HEAD -#undef CIRCLEQ_INSERT_TAIL -#undef CIRCLEQ_REMOVE -#undef CIRCLEQ_REPLACE - -/* - * This file defines five types of data structures: singly-linked lists, - * lists, simple queues, tail queues, and circular queues. - * - * - * A singly-linked list is headed by a single forward pointer. The elements - * are singly linked for minimum space and pointer manipulation overhead at - * the expense of O(n) removal for arbitrary elements. New elements can be - * added to the list after an existing element or at the head of the list. - * Elements being removed from the head of the list should use the explicit - * macro for this purpose for optimum efficiency. A singly-linked list may - * only be traversed in the forward direction. Singly-linked lists are ideal - * for applications with large datasets and few or no removals or for - * implementing a LIFO queue. - * - * A list is headed by a single forward pointer (or an array of forward - * pointers for a hash table header). The elements are doubly linked - * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before - * or after an existing element or at the head of the list. A list - * may only be traversed in the forward direction. - * - * A simple queue is headed by a pair of pointers, one the head of the - * list and the other to the tail of the list. The elements are singly - * linked to save space, so elements can only be removed from the - * head of the list. New elements can be added to the list before or after - * an existing element, at the head of the list, or at the end of the - * list. A simple queue may only be traversed in the forward direction. - * - * A tail queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or - * after an existing element, at the head of the list, or at the end of - * the list. A tail queue may be traversed in either direction. - * - * A circle queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or after - * an existing element, at the head of the list, or at the end of the list. - * A circle queue may be traversed in either direction, but has a more - * complex end of list detection. - * - * For details on the use of these macros, see the queue(3) manual page. - */ - -#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) -#define _Q_INVALIDATE(a) (a) = ((void *)-1) -#else -#define _Q_INVALIDATE(a) -#endif - -/* - * Singly-linked List definitions. - */ -#define SLIST_HEAD(name, type) \ -struct name { \ - struct type *slh_first; /* first element */ \ -} - -#define SLIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define SLIST_ENTRY(type) \ -struct { \ - struct type *sle_next; /* next element */ \ -} - -/* - * Singly-linked List access methods. - */ -#define SLIST_FIRST(head) ((head)->slh_first) -#define SLIST_END(head) NULL -#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) -#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) - -#define SLIST_FOREACH(var, head, field) \ - for((var) = SLIST_FIRST(head); \ - (var) != SLIST_END(head); \ - (var) = SLIST_NEXT(var, field)) - -#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = SLIST_FIRST(head); \ - (var) && ((tvar) = SLIST_NEXT(var, field), 1); \ - (var) = (tvar)) - -/* - * Singly-linked List functions. - */ -#define SLIST_INIT(head) { \ - SLIST_FIRST(head) = SLIST_END(head); \ -} - -#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ - (elm)->field.sle_next = (slistelm)->field.sle_next; \ - (slistelm)->field.sle_next = (elm); \ -} while (0) - -#define SLIST_INSERT_HEAD(head, elm, field) do { \ - (elm)->field.sle_next = (head)->slh_first; \ - (head)->slh_first = (elm); \ -} while (0) - -#define SLIST_REMOVE_AFTER(elm, field) do { \ - (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ -} while (0) - -#define SLIST_REMOVE_HEAD(head, field) do { \ - (head)->slh_first = (head)->slh_first->field.sle_next; \ -} while (0) - -#define SLIST_REMOVE(head, elm, type, field) do { \ - if ((head)->slh_first == (elm)) { \ - SLIST_REMOVE_HEAD((head), field); \ - } else { \ - struct type *curelm = (head)->slh_first; \ - \ - while (curelm->field.sle_next != (elm)) \ - curelm = curelm->field.sle_next; \ - curelm->field.sle_next = \ - curelm->field.sle_next->field.sle_next; \ - _Q_INVALIDATE((elm)->field.sle_next); \ - } \ -} while (0) - -/* - * List definitions. - */ -#define LIST_HEAD(name, type) \ -struct name { \ - struct type *lh_first; /* first element */ \ -} - -#define LIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define LIST_ENTRY(type) \ -struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ -} - -/* - * List access methods - */ -#define LIST_FIRST(head) ((head)->lh_first) -#define LIST_END(head) NULL -#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) -#define LIST_NEXT(elm, field) ((elm)->field.le_next) - -#define LIST_FOREACH(var, head, field) \ - for((var) = LIST_FIRST(head); \ - (var)!= LIST_END(head); \ - (var) = LIST_NEXT(var, field)) - -#define LIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = LIST_FIRST(head); \ - (var) && ((tvar) = LIST_NEXT(var, field), 1); \ - (var) = (tvar)) - -/* - * List functions. - */ -#define LIST_INIT(head) do { \ - LIST_FIRST(head) = LIST_END(head); \ -} while (0) - -#define LIST_INSERT_AFTER(listelm, elm, field) do { \ - if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ - (listelm)->field.le_next->field.le_prev = \ - &(elm)->field.le_next; \ - (listelm)->field.le_next = (elm); \ - (elm)->field.le_prev = &(listelm)->field.le_next; \ -} while (0) - -#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ - (elm)->field.le_prev = (listelm)->field.le_prev; \ - (elm)->field.le_next = (listelm); \ - *(listelm)->field.le_prev = (elm); \ - (listelm)->field.le_prev = &(elm)->field.le_next; \ -} while (0) - -#define LIST_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.le_next = (head)->lh_first) != NULL) \ - (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ - (head)->lh_first = (elm); \ - (elm)->field.le_prev = &(head)->lh_first; \ -} while (0) - -#define LIST_REMOVE(elm, field) do { \ - if ((elm)->field.le_next != NULL) \ - (elm)->field.le_next->field.le_prev = \ - (elm)->field.le_prev; \ - *(elm)->field.le_prev = (elm)->field.le_next; \ - _Q_INVALIDATE((elm)->field.le_prev); \ - _Q_INVALIDATE((elm)->field.le_next); \ -} while (0) - -#define LIST_REPLACE(elm, elm2, field) do { \ - if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ - (elm2)->field.le_next->field.le_prev = \ - &(elm2)->field.le_next; \ - (elm2)->field.le_prev = (elm)->field.le_prev; \ - *(elm2)->field.le_prev = (elm2); \ - _Q_INVALIDATE((elm)->field.le_prev); \ - _Q_INVALIDATE((elm)->field.le_next); \ -} while (0) - -/* - * Simple queue definitions. - */ -#define SIMPLEQ_HEAD(name, type) \ -struct name { \ - struct type *sqh_first; /* first element */ \ - struct type **sqh_last; /* addr of last next element */ \ -} - -#define SIMPLEQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).sqh_first } - -#define SIMPLEQ_ENTRY(type) \ -struct { \ - struct type *sqe_next; /* next element */ \ -} - -/* - * Simple queue access methods. - */ -#define SIMPLEQ_FIRST(head) ((head)->sqh_first) -#define SIMPLEQ_END(head) NULL -#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) -#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) - -#define SIMPLEQ_FOREACH(var, head, field) \ - for((var) = SIMPLEQ_FIRST(head); \ - (var) != SIMPLEQ_END(head); \ - (var) = SIMPLEQ_NEXT(var, field)) - -#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = SIMPLEQ_FIRST(head); \ - (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \ - (var) = (tvar)) - -/* - * Simple queue functions. - */ -#define SIMPLEQ_INIT(head) do { \ - (head)->sqh_first = NULL; \ - (head)->sqh_last = &(head)->sqh_first; \ -} while (0) - -#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ - (head)->sqh_last = &(elm)->field.sqe_next; \ - (head)->sqh_first = (elm); \ -} while (0) - -#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.sqe_next = NULL; \ - *(head)->sqh_last = (elm); \ - (head)->sqh_last = &(elm)->field.sqe_next; \ -} while (0) - -#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ - if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ - (head)->sqh_last = &(elm)->field.sqe_next; \ - (listelm)->field.sqe_next = (elm); \ -} while (0) - -#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ - if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ - (head)->sqh_last = &(head)->sqh_first; \ -} while (0) - -#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \ - if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \ - == NULL) \ - (head)->sqh_last = &(elm)->field.sqe_next; \ -} while (0) - -/* - * Tail queue definitions. - */ -#define TAILQ_HEAD(name, type) \ -struct name { \ - struct type *tqh_first; /* first element */ \ - struct type **tqh_last; /* addr of last next element */ \ -} - -#define TAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).tqh_first } - -#define TAILQ_ENTRY(type) \ -struct { \ - struct type *tqe_next; /* next element */ \ - struct type **tqe_prev; /* address of previous next element */ \ -} - -/* - * tail queue access methods - */ -#define TAILQ_FIRST(head) ((head)->tqh_first) -#define TAILQ_END(head) NULL -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) -#define TAILQ_LAST(head, headname) \ - (*(((struct headname *)((head)->tqh_last))->tqh_last)) -/* XXX */ -#define TAILQ_PREV(elm, headname, field) \ - (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) -#define TAILQ_EMPTY(head) \ - (TAILQ_FIRST(head) == TAILQ_END(head)) - -#define TAILQ_FOREACH(var, head, field) \ - for((var) = TAILQ_FIRST(head); \ - (var) != TAILQ_END(head); \ - (var) = TAILQ_NEXT(var, field)) - -#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = TAILQ_FIRST(head); \ - (var) != TAILQ_END(head) && \ - ((tvar) = TAILQ_NEXT(var, field), 1); \ - (var) = (tvar)) - - -#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ - for((var) = TAILQ_LAST(head, headname); \ - (var) != TAILQ_END(head); \ - (var) = TAILQ_PREV(var, headname, field)) - -#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ - for ((var) = TAILQ_LAST(head, headname); \ - (var) != TAILQ_END(head) && \ - ((tvar) = TAILQ_PREV(var, headname, field), 1); \ - (var) = (tvar)) - -/* - * Tail queue functions. - */ -#define TAILQ_INIT(head) do { \ - (head)->tqh_first = NULL; \ - (head)->tqh_last = &(head)->tqh_first; \ -} while (0) - -#define TAILQ_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ - (head)->tqh_first->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (head)->tqh_first = (elm); \ - (elm)->field.tqe_prev = &(head)->tqh_first; \ -} while (0) - -#define TAILQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.tqe_next = NULL; \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &(elm)->field.tqe_next; \ -} while (0) - -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ - if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ - (elm)->field.tqe_next->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (listelm)->field.tqe_next = (elm); \ - (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ -} while (0) - -#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ - (elm)->field.tqe_next = (listelm); \ - *(listelm)->field.tqe_prev = (elm); \ - (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ -} while (0) - -#define TAILQ_REMOVE(head, elm, field) do { \ - if (((elm)->field.tqe_next) != NULL) \ - (elm)->field.tqe_next->field.tqe_prev = \ - (elm)->field.tqe_prev; \ - else \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ - _Q_INVALIDATE((elm)->field.tqe_prev); \ - _Q_INVALIDATE((elm)->field.tqe_next); \ -} while (0) - -#define TAILQ_REPLACE(head, elm, elm2, field) do { \ - if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ - (elm2)->field.tqe_next->field.tqe_prev = \ - &(elm2)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm2)->field.tqe_next; \ - (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ - *(elm2)->field.tqe_prev = (elm2); \ - _Q_INVALIDATE((elm)->field.tqe_prev); \ - _Q_INVALIDATE((elm)->field.tqe_next); \ -} while (0) - -/* - * Circular queue definitions. - */ -#define CIRCLEQ_HEAD(name, type) \ -struct name { \ - struct type *cqh_first; /* first element */ \ - struct type *cqh_last; /* last element */ \ -} - -#define CIRCLEQ_HEAD_INITIALIZER(head) \ - { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } - -#define CIRCLEQ_ENTRY(type) \ -struct { \ - struct type *cqe_next; /* next element */ \ - struct type *cqe_prev; /* previous element */ \ -} - -/* - * Circular queue access methods - */ -#define CIRCLEQ_FIRST(head) ((head)->cqh_first) -#define CIRCLEQ_LAST(head) ((head)->cqh_last) -#define CIRCLEQ_END(head) ((void *)(head)) -#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) -#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) -#define CIRCLEQ_EMPTY(head) \ - (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) - -#define CIRCLEQ_FOREACH(var, head, field) \ - for((var) = CIRCLEQ_FIRST(head); \ - (var) != CIRCLEQ_END(head); \ - (var) = CIRCLEQ_NEXT(var, field)) - -#define CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = CIRCLEQ_FIRST(head); \ - (var) != CIRCLEQ_END(head) && \ - ((tvar) = CIRCLEQ_NEXT(var, field), 1); \ - (var) = (tvar)) - -#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ - for((var) = CIRCLEQ_LAST(head); \ - (var) != CIRCLEQ_END(head); \ - (var) = CIRCLEQ_PREV(var, field)) - -#define CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ - for ((var) = CIRCLEQ_LAST(head, headname); \ - (var) != CIRCLEQ_END(head) && \ - ((tvar) = CIRCLEQ_PREV(var, headname, field), 1); \ - (var) = (tvar)) - -/* - * Circular queue functions. - */ -#define CIRCLEQ_INIT(head) do { \ - (head)->cqh_first = CIRCLEQ_END(head); \ - (head)->cqh_last = CIRCLEQ_END(head); \ -} while (0) - -#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ - (elm)->field.cqe_next = (listelm)->field.cqe_next; \ - (elm)->field.cqe_prev = (listelm); \ - if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ - (head)->cqh_last = (elm); \ - else \ - (listelm)->field.cqe_next->field.cqe_prev = (elm); \ - (listelm)->field.cqe_next = (elm); \ -} while (0) - -#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ - (elm)->field.cqe_next = (listelm); \ - (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ - if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ - (head)->cqh_first = (elm); \ - else \ - (listelm)->field.cqe_prev->field.cqe_next = (elm); \ - (listelm)->field.cqe_prev = (elm); \ -} while (0) - -#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ - (elm)->field.cqe_next = (head)->cqh_first; \ - (elm)->field.cqe_prev = CIRCLEQ_END(head); \ - if ((head)->cqh_last == CIRCLEQ_END(head)) \ - (head)->cqh_last = (elm); \ - else \ - (head)->cqh_first->field.cqe_prev = (elm); \ - (head)->cqh_first = (elm); \ -} while (0) - -#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.cqe_next = CIRCLEQ_END(head); \ - (elm)->field.cqe_prev = (head)->cqh_last; \ - if ((head)->cqh_first == CIRCLEQ_END(head)) \ - (head)->cqh_first = (elm); \ - else \ - (head)->cqh_last->field.cqe_next = (elm); \ - (head)->cqh_last = (elm); \ -} while (0) - -#define CIRCLEQ_REMOVE(head, elm, field) do { \ - if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ - (head)->cqh_last = (elm)->field.cqe_prev; \ - else \ - (elm)->field.cqe_next->field.cqe_prev = \ - (elm)->field.cqe_prev; \ - if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ - (head)->cqh_first = (elm)->field.cqe_next; \ - else \ - (elm)->field.cqe_prev->field.cqe_next = \ - (elm)->field.cqe_next; \ - _Q_INVALIDATE((elm)->field.cqe_prev); \ - _Q_INVALIDATE((elm)->field.cqe_next); \ -} while (0) - -#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ - if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ - CIRCLEQ_END(head)) \ - (head).cqh_last = (elm2); \ - else \ - (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ - if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ - CIRCLEQ_END(head)) \ - (head).cqh_first = (elm2); \ - else \ - (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ - _Q_INVALIDATE((elm)->field.cqe_prev); \ - _Q_INVALIDATE((elm)->field.cqe_next); \ -} while (0) - -#endif /* !_SYS_QUEUE_H_ */ diff --git a/openbsd-compat/sys-tree.h b/openbsd-compat/sys-tree.h deleted file mode 100644 index cadfb55..0000000 --- a/openbsd-compat/sys-tree.h +++ /dev/null @@ -1,750 +0,0 @@ -/* $OpenBSD: tree.h,v 1.13 2011/07/09 00:19:45 pirofti Exp $ */ -/* - * Copyright 2002 Niels Provos - * 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. - */ - -/* OPENBSD ORIGINAL: sys/openbsd-compat/sys-tree.h */ - -#ifndef _SYS_TREE_H_ -#define _SYS_TREE_H_ - -/* - * This file defines data structures for different types of trees: - * splay trees and red-black trees. - * - * A splay tree is a self-organizing data structure. Every operation - * on the tree causes a splay to happen. The splay moves the requested - * node to the root of the tree and partly rebalances it. - * - * This has the benefit that request locality causes faster lookups as - * the requested nodes move to the top of the tree. On the other hand, - * every lookup causes memory writes. - * - * The Balance Theorem bounds the total access time for m operations - * and n inserts on an initially empty tree as O((m + n)lg n). The - * amortized cost for a sequence of m accesses to a splay tree is O(lg n); - * - * A red-black tree is a binary search tree with the node color as an - * extra attribute. It fulfills a set of conditions: - * - every search path from the root to a leaf consists of the - * same number of black nodes, - * - each red node (except for the root) has a black parent, - * - each leaf node is black. - * - * Every operation on a red-black tree is bounded as O(lg n). - * The maximum height of a red-black tree is 2lg (n+1). - */ - -#define SPLAY_HEAD(name, type) \ -struct name { \ - struct type *sph_root; /* root of the tree */ \ -} - -#define SPLAY_INITIALIZER(root) \ - { NULL } - -#define SPLAY_INIT(root) do { \ - (root)->sph_root = NULL; \ -} while (0) - -#define SPLAY_ENTRY(type) \ -struct { \ - struct type *spe_left; /* left element */ \ - struct type *spe_right; /* right element */ \ -} - -#define SPLAY_LEFT(elm, field) (elm)->field.spe_left -#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right -#define SPLAY_ROOT(head) (head)->sph_root -#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) - -/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ -#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ - SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ - SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ - (head)->sph_root = tmp; \ -} while (0) - -#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ - SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ - SPLAY_LEFT(tmp, field) = (head)->sph_root; \ - (head)->sph_root = tmp; \ -} while (0) - -#define SPLAY_LINKLEFT(head, tmp, field) do { \ - SPLAY_LEFT(tmp, field) = (head)->sph_root; \ - tmp = (head)->sph_root; \ - (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ -} while (0) - -#define SPLAY_LINKRIGHT(head, tmp, field) do { \ - SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ - tmp = (head)->sph_root; \ - (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ -} while (0) - -#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ - SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ - SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ - SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ - SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ -} while (0) - -/* Generates prototypes and inline functions */ - -#define SPLAY_PROTOTYPE(name, type, field, cmp) \ -void name##_SPLAY(struct name *, struct type *); \ -void name##_SPLAY_MINMAX(struct name *, int); \ -struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ -struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ - \ -/* Finds the node with the same key as elm */ \ -static __inline struct type * \ -name##_SPLAY_FIND(struct name *head, struct type *elm) \ -{ \ - if (SPLAY_EMPTY(head)) \ - return(NULL); \ - name##_SPLAY(head, elm); \ - if ((cmp)(elm, (head)->sph_root) == 0) \ - return (head->sph_root); \ - return (NULL); \ -} \ - \ -static __inline struct type * \ -name##_SPLAY_NEXT(struct name *head, struct type *elm) \ -{ \ - name##_SPLAY(head, elm); \ - if (SPLAY_RIGHT(elm, field) != NULL) { \ - elm = SPLAY_RIGHT(elm, field); \ - while (SPLAY_LEFT(elm, field) != NULL) { \ - elm = SPLAY_LEFT(elm, field); \ - } \ - } else \ - elm = NULL; \ - return (elm); \ -} \ - \ -static __inline struct type * \ -name##_SPLAY_MIN_MAX(struct name *head, int val) \ -{ \ - name##_SPLAY_MINMAX(head, val); \ - return (SPLAY_ROOT(head)); \ -} - -/* Main splay operation. - * Moves node close to the key of elm to top - */ -#define SPLAY_GENERATE(name, type, field, cmp) \ -struct type * \ -name##_SPLAY_INSERT(struct name *head, struct type *elm) \ -{ \ - if (SPLAY_EMPTY(head)) { \ - SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ - } else { \ - int __comp; \ - name##_SPLAY(head, elm); \ - __comp = (cmp)(elm, (head)->sph_root); \ - if(__comp < 0) { \ - SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ - SPLAY_RIGHT(elm, field) = (head)->sph_root; \ - SPLAY_LEFT((head)->sph_root, field) = NULL; \ - } else if (__comp > 0) { \ - SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ - SPLAY_LEFT(elm, field) = (head)->sph_root; \ - SPLAY_RIGHT((head)->sph_root, field) = NULL; \ - } else \ - return ((head)->sph_root); \ - } \ - (head)->sph_root = (elm); \ - return (NULL); \ -} \ - \ -struct type * \ -name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ -{ \ - struct type *__tmp; \ - if (SPLAY_EMPTY(head)) \ - return (NULL); \ - name##_SPLAY(head, elm); \ - if ((cmp)(elm, (head)->sph_root) == 0) { \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ - (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ - } else { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ - name##_SPLAY(head, elm); \ - SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ - } \ - return (elm); \ - } \ - return (NULL); \ -} \ - \ -void \ -name##_SPLAY(struct name *head, struct type *elm) \ -{ \ - struct type __node, *__left, *__right, *__tmp; \ - int __comp; \ -\ - SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ - __left = __right = &__node; \ -\ - while ((__comp = (cmp)(elm, (head)->sph_root))) { \ - if (__comp < 0) { \ - __tmp = SPLAY_LEFT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if ((cmp)(elm, __tmp) < 0){ \ - SPLAY_ROTATE_RIGHT(head, __tmp, field); \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKLEFT(head, __right, field); \ - } else if (__comp > 0) { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if ((cmp)(elm, __tmp) > 0){ \ - SPLAY_ROTATE_LEFT(head, __tmp, field); \ - if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKRIGHT(head, __left, field); \ - } \ - } \ - SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ -} \ - \ -/* Splay with either the minimum or the maximum element \ - * Used to find minimum or maximum element in tree. \ - */ \ -void name##_SPLAY_MINMAX(struct name *head, int __comp) \ -{ \ - struct type __node, *__left, *__right, *__tmp; \ -\ - SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ - __left = __right = &__node; \ -\ - while (1) { \ - if (__comp < 0) { \ - __tmp = SPLAY_LEFT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if (__comp < 0){ \ - SPLAY_ROTATE_RIGHT(head, __tmp, field); \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKLEFT(head, __right, field); \ - } else if (__comp > 0) { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if (__comp > 0) { \ - SPLAY_ROTATE_LEFT(head, __tmp, field); \ - if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKRIGHT(head, __left, field); \ - } \ - } \ - SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ -} - -#define SPLAY_NEGINF -1 -#define SPLAY_INF 1 - -#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) -#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) -#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) -#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) -#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ - : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) -#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ - : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) - -#define SPLAY_FOREACH(x, name, head) \ - for ((x) = SPLAY_MIN(name, head); \ - (x) != NULL; \ - (x) = SPLAY_NEXT(name, head, x)) - -/* Macros that define a red-black tree */ -#define RB_HEAD(name, type) \ -struct name { \ - struct type *rbh_root; /* root of the tree */ \ -} - -#define RB_INITIALIZER(root) \ - { NULL } - -#define RB_INIT(root) do { \ - (root)->rbh_root = NULL; \ -} while (0) - -#define RB_BLACK 0 -#define RB_RED 1 -#define RB_ENTRY(type) \ -struct { \ - struct type *rbe_left; /* left element */ \ - struct type *rbe_right; /* right element */ \ - struct type *rbe_parent; /* parent element */ \ - int rbe_color; /* node color */ \ -} - -#define RB_LEFT(elm, field) (elm)->field.rbe_left -#define RB_RIGHT(elm, field) (elm)->field.rbe_right -#define RB_PARENT(elm, field) (elm)->field.rbe_parent -#define RB_COLOR(elm, field) (elm)->field.rbe_color -#define RB_ROOT(head) (head)->rbh_root -#define RB_EMPTY(head) (RB_ROOT(head) == NULL) - -#define RB_SET(elm, parent, field) do { \ - RB_PARENT(elm, field) = parent; \ - RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ - RB_COLOR(elm, field) = RB_RED; \ -} while (0) - -#define RB_SET_BLACKRED(black, red, field) do { \ - RB_COLOR(black, field) = RB_BLACK; \ - RB_COLOR(red, field) = RB_RED; \ -} while (0) - -#ifndef RB_AUGMENT -#define RB_AUGMENT(x) do {} while (0) -#endif - -#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ - (tmp) = RB_RIGHT(elm, field); \ - if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ - RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ - } \ - RB_AUGMENT(elm); \ - if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ - if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ - RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ - else \ - RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ - } else \ - (head)->rbh_root = (tmp); \ - RB_LEFT(tmp, field) = (elm); \ - RB_PARENT(elm, field) = (tmp); \ - RB_AUGMENT(tmp); \ - if ((RB_PARENT(tmp, field))) \ - RB_AUGMENT(RB_PARENT(tmp, field)); \ -} while (0) - -#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ - (tmp) = RB_LEFT(elm, field); \ - if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ - RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ - } \ - RB_AUGMENT(elm); \ - if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ - if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ - RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ - else \ - RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ - } else \ - (head)->rbh_root = (tmp); \ - RB_RIGHT(tmp, field) = (elm); \ - RB_PARENT(elm, field) = (tmp); \ - RB_AUGMENT(tmp); \ - if ((RB_PARENT(tmp, field))) \ - RB_AUGMENT(RB_PARENT(tmp, field)); \ -} while (0) - -/* Generates prototypes and inline functions */ -#define RB_PROTOTYPE(name, type, field, cmp) \ - RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) -#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ - RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static) -#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ -attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \ -attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ -attr struct type *name##_RB_REMOVE(struct name *, struct type *); \ -attr struct type *name##_RB_INSERT(struct name *, struct type *); \ -attr struct type *name##_RB_FIND(struct name *, struct type *); \ -attr struct type *name##_RB_NFIND(struct name *, struct type *); \ -attr struct type *name##_RB_NEXT(struct type *); \ -attr struct type *name##_RB_PREV(struct type *); \ -attr struct type *name##_RB_MINMAX(struct name *, int); \ - \ - -/* Main rb operation. - * Moves node close to the key of elm to top - */ -#define RB_GENERATE(name, type, field, cmp) \ - RB_GENERATE_INTERNAL(name, type, field, cmp,) -#define RB_GENERATE_STATIC(name, type, field, cmp) \ - RB_GENERATE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static) -#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ -attr void \ -name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ -{ \ - struct type *parent, *gparent, *tmp; \ - while ((parent = RB_PARENT(elm, field)) && \ - RB_COLOR(parent, field) == RB_RED) { \ - gparent = RB_PARENT(parent, field); \ - if (parent == RB_LEFT(gparent, field)) { \ - tmp = RB_RIGHT(gparent, field); \ - if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ - RB_COLOR(tmp, field) = RB_BLACK; \ - RB_SET_BLACKRED(parent, gparent, field);\ - elm = gparent; \ - continue; \ - } \ - if (RB_RIGHT(parent, field) == elm) { \ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - tmp = parent; \ - parent = elm; \ - elm = tmp; \ - } \ - RB_SET_BLACKRED(parent, gparent, field); \ - RB_ROTATE_RIGHT(head, gparent, tmp, field); \ - } else { \ - tmp = RB_LEFT(gparent, field); \ - if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ - RB_COLOR(tmp, field) = RB_BLACK; \ - RB_SET_BLACKRED(parent, gparent, field);\ - elm = gparent; \ - continue; \ - } \ - if (RB_LEFT(parent, field) == elm) { \ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - tmp = parent; \ - parent = elm; \ - elm = tmp; \ - } \ - RB_SET_BLACKRED(parent, gparent, field); \ - RB_ROTATE_LEFT(head, gparent, tmp, field); \ - } \ - } \ - RB_COLOR(head->rbh_root, field) = RB_BLACK; \ -} \ - \ -attr void \ -name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ -{ \ - struct type *tmp; \ - while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ - elm != RB_ROOT(head)) { \ - if (RB_LEFT(parent, field) == elm) { \ - tmp = RB_RIGHT(parent, field); \ - if (RB_COLOR(tmp, field) == RB_RED) { \ - RB_SET_BLACKRED(tmp, parent, field); \ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - tmp = RB_RIGHT(parent, field); \ - } \ - if ((RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ - (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ - RB_COLOR(tmp, field) = RB_RED; \ - elm = parent; \ - parent = RB_PARENT(elm, field); \ - } else { \ - if (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ - struct type *oleft; \ - if ((oleft = RB_LEFT(tmp, field)))\ - RB_COLOR(oleft, field) = RB_BLACK;\ - RB_COLOR(tmp, field) = RB_RED; \ - RB_ROTATE_RIGHT(head, tmp, oleft, field);\ - tmp = RB_RIGHT(parent, field); \ - } \ - RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ - RB_COLOR(parent, field) = RB_BLACK; \ - if (RB_RIGHT(tmp, field)) \ - RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - elm = RB_ROOT(head); \ - break; \ - } \ - } else { \ - tmp = RB_LEFT(parent, field); \ - if (RB_COLOR(tmp, field) == RB_RED) { \ - RB_SET_BLACKRED(tmp, parent, field); \ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - tmp = RB_LEFT(parent, field); \ - } \ - if ((RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ - (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ - RB_COLOR(tmp, field) = RB_RED; \ - elm = parent; \ - parent = RB_PARENT(elm, field); \ - } else { \ - if (RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ - struct type *oright; \ - if ((oright = RB_RIGHT(tmp, field)))\ - RB_COLOR(oright, field) = RB_BLACK;\ - RB_COLOR(tmp, field) = RB_RED; \ - RB_ROTATE_LEFT(head, tmp, oright, field);\ - tmp = RB_LEFT(parent, field); \ - } \ - RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ - RB_COLOR(parent, field) = RB_BLACK; \ - if (RB_LEFT(tmp, field)) \ - RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - elm = RB_ROOT(head); \ - break; \ - } \ - } \ - } \ - if (elm) \ - RB_COLOR(elm, field) = RB_BLACK; \ -} \ - \ -attr struct type * \ -name##_RB_REMOVE(struct name *head, struct type *elm) \ -{ \ - struct type *child, *parent, *old = elm; \ - int color; \ - if (RB_LEFT(elm, field) == NULL) \ - child = RB_RIGHT(elm, field); \ - else if (RB_RIGHT(elm, field) == NULL) \ - child = RB_LEFT(elm, field); \ - else { \ - struct type *left; \ - elm = RB_RIGHT(elm, field); \ - while ((left = RB_LEFT(elm, field))) \ - elm = left; \ - child = RB_RIGHT(elm, field); \ - parent = RB_PARENT(elm, field); \ - color = RB_COLOR(elm, field); \ - if (child) \ - RB_PARENT(child, field) = parent; \ - if (parent) { \ - if (RB_LEFT(parent, field) == elm) \ - RB_LEFT(parent, field) = child; \ - else \ - RB_RIGHT(parent, field) = child; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = child; \ - if (RB_PARENT(elm, field) == old) \ - parent = elm; \ - (elm)->field = (old)->field; \ - if (RB_PARENT(old, field)) { \ - if (RB_LEFT(RB_PARENT(old, field), field) == old)\ - RB_LEFT(RB_PARENT(old, field), field) = elm;\ - else \ - RB_RIGHT(RB_PARENT(old, field), field) = elm;\ - RB_AUGMENT(RB_PARENT(old, field)); \ - } else \ - RB_ROOT(head) = elm; \ - RB_PARENT(RB_LEFT(old, field), field) = elm; \ - if (RB_RIGHT(old, field)) \ - RB_PARENT(RB_RIGHT(old, field), field) = elm; \ - if (parent) { \ - left = parent; \ - do { \ - RB_AUGMENT(left); \ - } while ((left = RB_PARENT(left, field))); \ - } \ - goto color; \ - } \ - parent = RB_PARENT(elm, field); \ - color = RB_COLOR(elm, field); \ - if (child) \ - RB_PARENT(child, field) = parent; \ - if (parent) { \ - if (RB_LEFT(parent, field) == elm) \ - RB_LEFT(parent, field) = child; \ - else \ - RB_RIGHT(parent, field) = child; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = child; \ -color: \ - if (color == RB_BLACK) \ - name##_RB_REMOVE_COLOR(head, parent, child); \ - return (old); \ -} \ - \ -/* Inserts a node into the RB tree */ \ -attr struct type * \ -name##_RB_INSERT(struct name *head, struct type *elm) \ -{ \ - struct type *tmp; \ - struct type *parent = NULL; \ - int comp = 0; \ - tmp = RB_ROOT(head); \ - while (tmp) { \ - parent = tmp; \ - comp = (cmp)(elm, parent); \ - if (comp < 0) \ - tmp = RB_LEFT(tmp, field); \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - RB_SET(elm, parent, field); \ - if (parent != NULL) { \ - if (comp < 0) \ - RB_LEFT(parent, field) = elm; \ - else \ - RB_RIGHT(parent, field) = elm; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = elm; \ - name##_RB_INSERT_COLOR(head, elm); \ - return (NULL); \ -} \ - \ -/* Finds the node with the same key as elm */ \ -attr struct type * \ -name##_RB_FIND(struct name *head, struct type *elm) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - int comp; \ - while (tmp) { \ - comp = cmp(elm, tmp); \ - if (comp < 0) \ - tmp = RB_LEFT(tmp, field); \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - return (NULL); \ -} \ - \ -/* Finds the first node greater than or equal to the search key */ \ -attr struct type * \ -name##_RB_NFIND(struct name *head, struct type *elm) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - struct type *res = NULL; \ - int comp; \ - while (tmp) { \ - comp = cmp(elm, tmp); \ - if (comp < 0) { \ - res = tmp; \ - tmp = RB_LEFT(tmp, field); \ - } \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - return (res); \ -} \ - \ -/* ARGSUSED */ \ -attr struct type * \ -name##_RB_NEXT(struct type *elm) \ -{ \ - if (RB_RIGHT(elm, field)) { \ - elm = RB_RIGHT(elm, field); \ - while (RB_LEFT(elm, field)) \ - elm = RB_LEFT(elm, field); \ - } else { \ - if (RB_PARENT(elm, field) && \ - (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ - elm = RB_PARENT(elm, field); \ - else { \ - while (RB_PARENT(elm, field) && \ - (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ - elm = RB_PARENT(elm, field); \ - elm = RB_PARENT(elm, field); \ - } \ - } \ - return (elm); \ -} \ - \ -/* ARGSUSED */ \ -attr struct type * \ -name##_RB_PREV(struct type *elm) \ -{ \ - if (RB_LEFT(elm, field)) { \ - elm = RB_LEFT(elm, field); \ - while (RB_RIGHT(elm, field)) \ - elm = RB_RIGHT(elm, field); \ - } else { \ - if (RB_PARENT(elm, field) && \ - (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ - elm = RB_PARENT(elm, field); \ - else { \ - while (RB_PARENT(elm, field) && \ - (elm == RB_LEFT(RB_PARENT(elm, field), field)))\ - elm = RB_PARENT(elm, field); \ - elm = RB_PARENT(elm, field); \ - } \ - } \ - return (elm); \ -} \ - \ -attr struct type * \ -name##_RB_MINMAX(struct name *head, int val) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - struct type *parent = NULL; \ - while (tmp) { \ - parent = tmp; \ - if (val < 0) \ - tmp = RB_LEFT(tmp, field); \ - else \ - tmp = RB_RIGHT(tmp, field); \ - } \ - return (parent); \ -} - -#define RB_NEGINF -1 -#define RB_INF 1 - -#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) -#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) -#define RB_FIND(name, x, y) name##_RB_FIND(x, y) -#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) -#define RB_NEXT(name, x, y) name##_RB_NEXT(y) -#define RB_PREV(name, x, y) name##_RB_PREV(y) -#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) -#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) - -#define RB_FOREACH(x, name, head) \ - for ((x) = RB_MIN(name, head); \ - (x) != NULL; \ - (x) = name##_RB_NEXT(x)) - -#define RB_FOREACH_SAFE(x, name, head, y) \ - for ((x) = RB_MIN(name, head); \ - ((x) != NULL) && ((y) = name##_RB_NEXT(x), 1); \ - (x) = (y)) - -#define RB_FOREACH_REVERSE(x, name, head) \ - for ((x) = RB_MAX(name, head); \ - (x) != NULL; \ - (x) = name##_RB_PREV(x)) - -#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ - for ((x) = RB_MAX(name, head); \ - ((x) != NULL) && ((y) = name##_RB_PREV(x), 1); \ - (x) = (y)) - -#endif /* _SYS_TREE_H_ */ diff --git a/openbsd-compat/vis.c b/openbsd-compat/vis.c deleted file mode 100644 index 3a087b3..0000000 --- a/openbsd-compat/vis.c +++ /dev/null @@ -1,225 +0,0 @@ -/* $OpenBSD: vis.c,v 1.19 2005/09/01 17:15:49 millert Exp $ */ -/*- - * Copyright (c) 1989, 1993 - * The Regents of the University of California. 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. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* OPENBSD ORIGINAL: lib/libc/gen/vis.c */ - -#include "includes.h" -#if !defined(HAVE_STRNVIS) - -#include -#include - -#include "vis.h" - -#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') -#define isvisible(c) \ - (((u_int)(c) <= UCHAR_MAX && isascii((u_char)(c)) && \ - (((c) != '*' && (c) != '?' && (c) != '[' && (c) != '#') || \ - (flag & VIS_GLOB) == 0) && isgraph((u_char)(c))) || \ - ((flag & VIS_SP) == 0 && (c) == ' ') || \ - ((flag & VIS_TAB) == 0 && (c) == '\t') || \ - ((flag & VIS_NL) == 0 && (c) == '\n') || \ - ((flag & VIS_SAFE) && ((c) == '\b' || \ - (c) == '\007' || (c) == '\r' || \ - isgraph((u_char)(c))))) - -/* - * vis - visually encode characters - */ -char * -vis(char *dst, int c, int flag, int nextc) -{ - if (isvisible(c)) { - *dst++ = c; - if (c == '\\' && (flag & VIS_NOSLASH) == 0) - *dst++ = '\\'; - *dst = '\0'; - return (dst); - } - - if (flag & VIS_CSTYLE) { - switch(c) { - case '\n': - *dst++ = '\\'; - *dst++ = 'n'; - goto done; - case '\r': - *dst++ = '\\'; - *dst++ = 'r'; - goto done; - case '\b': - *dst++ = '\\'; - *dst++ = 'b'; - goto done; - case '\a': - *dst++ = '\\'; - *dst++ = 'a'; - goto done; - case '\v': - *dst++ = '\\'; - *dst++ = 'v'; - goto done; - case '\t': - *dst++ = '\\'; - *dst++ = 't'; - goto done; - case '\f': - *dst++ = '\\'; - *dst++ = 'f'; - goto done; - case ' ': - *dst++ = '\\'; - *dst++ = 's'; - goto done; - case '\0': - *dst++ = '\\'; - *dst++ = '0'; - if (isoctal(nextc)) { - *dst++ = '0'; - *dst++ = '0'; - } - goto done; - } - } - if (((c & 0177) == ' ') || (flag & VIS_OCTAL) || - ((flag & VIS_GLOB) && (c == '*' || c == '?' || c == '[' || c == '#'))) { - *dst++ = '\\'; - *dst++ = ((u_char)c >> 6 & 07) + '0'; - *dst++ = ((u_char)c >> 3 & 07) + '0'; - *dst++ = ((u_char)c & 07) + '0'; - goto done; - } - if ((flag & VIS_NOSLASH) == 0) - *dst++ = '\\'; - if (c & 0200) { - c &= 0177; - *dst++ = 'M'; - } - if (iscntrl((u_char)c)) { - *dst++ = '^'; - if (c == 0177) - *dst++ = '?'; - else - *dst++ = c + '@'; - } else { - *dst++ = '-'; - *dst++ = c; - } -done: - *dst = '\0'; - return (dst); -} - -/* - * strvis, strnvis, strvisx - visually encode characters from src into dst - * - * Dst must be 4 times the size of src to account for possible - * expansion. The length of dst, not including the trailing NULL, - * is returned. - * - * Strnvis will write no more than siz-1 bytes (and will NULL terminate). - * The number of bytes needed to fully encode the string is returned. - * - * Strvisx encodes exactly len bytes from src into dst. - * This is useful for encoding a block of data. - */ -int -strvis(char *dst, const char *src, int flag) -{ - char c; - char *start; - - for (start = dst; (c = *src);) - dst = vis(dst, c, flag, *++src); - *dst = '\0'; - return (dst - start); -} - -int -strnvis(char *dst, const char *src, size_t siz, int flag) -{ - char *start, *end; - char tbuf[5]; - int c, i; - - i = 0; - for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) { - if (isvisible(c)) { - i = 1; - *dst++ = c; - if (c == '\\' && (flag & VIS_NOSLASH) == 0) { - /* need space for the extra '\\' */ - if (dst < end) - *dst++ = '\\'; - else { - dst--; - i = 2; - break; - } - } - src++; - } else { - i = vis(tbuf, c, flag, *++src) - tbuf; - if (dst + i <= end) { - memcpy(dst, tbuf, i); - dst += i; - } else { - src--; - break; - } - } - } - if (siz > 0) - *dst = '\0'; - if (dst + i > end) { - /* adjust return value for truncation */ - while ((c = *src)) - dst += vis(tbuf, c, flag, *++src) - tbuf; - } - return (dst - start); -} - -int -strvisx(char *dst, const char *src, size_t len, int flag) -{ - char c; - char *start; - - for (start = dst; len > 1; len--) { - c = *src; - dst = vis(dst, c, flag, *++src); - } - if (len) - dst = vis(dst, *src, flag, '\0'); - *dst = '\0'; - return (dst - start); -} - -#endif diff --git a/openbsd-compat/vis.h b/openbsd-compat/vis.h deleted file mode 100644 index 66c0951..0000000 --- a/openbsd-compat/vis.h +++ /dev/null @@ -1,98 +0,0 @@ -/* $OpenBSD: vis.h,v 1.11 2005/08/09 19:38:31 millert Exp $ */ -/* $NetBSD: vis.h,v 1.4 1994/10/26 00:56:41 cgd Exp $ */ - -/*- - * Copyright (c) 1990 The Regents of the University of California. - * 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. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)vis.h 5.9 (Berkeley) 4/3/91 - */ - -/* OPENBSD ORIGINAL: include/vis.h */ - -#ifdef HAVE_CONFIG_H -#include "includes.h" -#endif - -// #if !defined(HAVE_STRNVIS) - -#ifndef _VIS_H_ -#define _VIS_H_ - -#include -#include - -/* - * to select alternate encoding format - */ -#define VIS_OCTAL 0x01 /* use octal \ddd format */ -#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropriate */ - -/* - * to alter set of characters encoded (default is to encode all - * non-graphic except space, tab, and newline). - */ -#define VIS_SP 0x04 /* also encode space */ -#define VIS_TAB 0x08 /* also encode tab */ -#define VIS_NL 0x10 /* also encode newline */ -#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL) -#define VIS_SAFE 0x20 /* only encode "unsafe" characters */ - -/* - * other - */ -#define VIS_NOSLASH 0x40 /* inhibit printing '\' */ -#define VIS_GLOB 0x100 /* encode glob(3) magics and '#' */ - -/* - * unvis return codes - */ -#define UNVIS_VALID 1 /* character valid */ -#define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */ -#define UNVIS_NOCHAR 3 /* valid sequence, no character produced */ -#define UNVIS_SYNBAD -1 /* unrecognized escape sequence */ -#define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */ - -/* - * unvis flags - */ -#define UNVIS_END 1 /* no more characters */ - -char *vis(char *, int, int, int); -int strvis(char *, const char *, int); -int strnvis(char *, const char *, size_t, int) - __attribute__ ((__bounded__(__string__,1,3))); -int strvisx(char *, const char *, size_t, int) - __attribute__ ((__bounded__(__string__,1,3))); -int strunvis(char *, const char *); -int unvis(char *, char, int *, int); -ssize_t strnunvis(char *, const char *, size_t) - __attribute__ ((__bounded__(__string__,1,3))); - -#endif /* !_VIS_H_ */ - -//#endif /* !HAVE_STRNVIS */ From 9e9acd731673a572d72726b66ad51fdbae64b50c Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Thu, 8 Oct 2015 10:47:01 +0200 Subject: [PATCH 02/39] Add regress tests from CVS --- regress/CVS/Entries | 2 + regress/CVS/Repository | 1 + regress/CVS/Root | 1 + regress/Makefile | 5 +++ regress/dh/CVS/Entries | 3 ++ regress/dh/CVS/Repository | 1 + regress/dh/CVS/Root | 1 + regress/dh/Makefile | 17 ++++++++ regress/dh/dhtest.c | 82 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 113 insertions(+) create mode 100644 regress/CVS/Entries create mode 100644 regress/CVS/Repository create mode 100644 regress/CVS/Root create mode 100644 regress/Makefile create mode 100644 regress/dh/CVS/Entries create mode 100644 regress/dh/CVS/Repository create mode 100644 regress/dh/CVS/Root create mode 100644 regress/dh/Makefile create mode 100644 regress/dh/dhtest.c diff --git a/regress/CVS/Entries b/regress/CVS/Entries new file mode 100644 index 0000000..112daed --- /dev/null +++ b/regress/CVS/Entries @@ -0,0 +1,2 @@ +/Makefile/1.1/Mon Aug 25 19:22:20 2014// +D/dh//// diff --git a/regress/CVS/Repository b/regress/CVS/Repository new file mode 100644 index 0000000..512f007 --- /dev/null +++ b/regress/CVS/Repository @@ -0,0 +1 @@ +src/regress/sbin/iked diff --git a/regress/CVS/Root b/regress/CVS/Root new file mode 100644 index 0000000..f9802fd --- /dev/null +++ b/regress/CVS/Root @@ -0,0 +1 @@ +anoncvs@ftp.hostserver.de:/cvs diff --git a/regress/Makefile b/regress/Makefile new file mode 100644 index 0000000..556e851 --- /dev/null +++ b/regress/Makefile @@ -0,0 +1,5 @@ +# $OpenBSD: Makefile,v 1.1 2014/08/25 19:22:20 reyk Exp $ + +SUBDIR= dh + +.include diff --git a/regress/dh/CVS/Entries b/regress/dh/CVS/Entries new file mode 100644 index 0000000..4c4738a --- /dev/null +++ b/regress/dh/CVS/Entries @@ -0,0 +1,3 @@ +/Makefile/1.2/Wed Aug 27 10:28:57 2014// +/dhtest.c/1.2/Wed Aug 27 10:28:57 2014// +D diff --git a/regress/dh/CVS/Repository b/regress/dh/CVS/Repository new file mode 100644 index 0000000..3a5edbe --- /dev/null +++ b/regress/dh/CVS/Repository @@ -0,0 +1 @@ +src/regress/sbin/iked/dh diff --git a/regress/dh/CVS/Root b/regress/dh/CVS/Root new file mode 100644 index 0000000..f9802fd --- /dev/null +++ b/regress/dh/CVS/Root @@ -0,0 +1 @@ +anoncvs@ftp.hostserver.de:/cvs diff --git a/regress/dh/Makefile b/regress/dh/Makefile new file mode 100644 index 0000000..9afb73d --- /dev/null +++ b/regress/dh/Makefile @@ -0,0 +1,17 @@ +# $OpenBSD: Makefile,v 1.2 2014/08/27 10:28:57 reyk Exp $ + +# Test DH: + +PROG= dhtest +SRCS= dh.c dhtest.c smult_curve25519_ref.c +TOPSRC= ${.CURDIR}/../../iked +TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- +.PATH: ${TOPSRC} ${TOPOBJ} +CFLAGS+= -I${TOPSRC} -I${TOPOBJ} -Wall + +NOMAN= +LDADD+= -lcrypto +DPADD+= ${LIBCRYPTO} +DEBUG= -g + +.include diff --git a/regress/dh/dhtest.c b/regress/dh/dhtest.c new file mode 100644 index 0000000..575109e --- /dev/null +++ b/regress/dh/dhtest.c @@ -0,0 +1,82 @@ +/* $OpenBSD: dhtest.c,v 1.2 2014/08/27 10:28:57 reyk Exp $ */ +/* $EOM: dhtest.c,v 1.1 1998/07/18 21:14:20 provos Exp $ */ + +/* + * Copyright (c) 2010 Reyk Floeter + * Copyright (c) 1998 Niels Provos. 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. + */ + +/* + * This module does a Diffie-Hellman Exchange + */ + +#include +#include +#include + +#include "dh.h" + +int +main(void) +{ + int len, id; + char buf[DH_MAXSZ], buf2[DH_MAXSZ]; + char sec[DH_MAXSZ], sec2[DH_MAXSZ]; + struct group *group, *group2; + const char *name[] = { "MODP", "EC2N", "ECP", "CURVE25519" }; + + group_init(); + + for (id = 0; id < 0xffff; id++) { + if ((group = group_get(id)) == NULL || + (group2 = group_get(id)) == NULL) + continue; + + len = dh_getlen(group); + + printf ("Testing group %d (%s-%d, length %d): ", id, + name[group->spec->type], + group->spec->bits, len * 8); + + dh_create_exchange(group, buf); + dh_create_exchange(group2, buf2); + + dh_create_shared(group, sec, buf2); + dh_create_shared(group2, sec2, buf); + + if (memcmp (sec, sec2, len)) { + printf("FAILED\n"); + return (1); + } else + printf("OKAY\n"); + + group_free(group); + group_free(group2); + } + + return (0); +} From e22720d9c9304841eac92c08380d0fc1ebb7b0b1 Mon Sep 17 00:00:00 2001 From: Charlie Root Date: Fri, 12 Feb 2016 18:51:35 +0000 Subject: [PATCH 03/39] automake 1.15 is up to 1.15 --- bootstrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap b/bootstrap index 6cfcf9d..b8d8fe5 100755 --- a/bootstrap +++ b/bootstrap @@ -36,7 +36,7 @@ aclocalflags="`sed -ne 's/^[ \t]*ACLOCAL_AMFLAGS[ \t]*=//p' Makefile.am 2>/dev/n # Check for automake amvers="no" -for v in 12 11 10 9 8 7 6 5; do +for v in 15 14 13 12 11 10 9 8 7 6 5; do if automake-1.${v} --version >/dev/null 2>&1; then amvers="-1.${v}" break From 066f64edc58e32b7c18779aec2a13c0316dec182 Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Fri, 12 Feb 2016 11:41:37 -0800 Subject: [PATCH 04/39] automake is up to 1.15 --- bootstrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap b/bootstrap index 6cfcf9d..b8d8fe5 100755 --- a/bootstrap +++ b/bootstrap @@ -36,7 +36,7 @@ aclocalflags="`sed -ne 's/^[ \t]*ACLOCAL_AMFLAGS[ \t]*=//p' Makefile.am 2>/dev/n # Check for automake amvers="no" -for v in 12 11 10 9 8 7 6 5; do +for v in 15 14 13 12 11 10 9 8 7 6 5; do if automake-1.${v} --version >/dev/null 2>&1; then amvers="-1.${v}" break From 4a20022a11281116f72fe1f548aaaf5eba4171f3 Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Wed, 4 May 2016 14:21:32 +0000 Subject: [PATCH 05/39] WIP: Sync the portable openiked to OpenBSD 5.8's version --- ikectl/ikeca.c | 21 +- ikectl/ikeca.cnf | 4 +- ikectl/ikectl.8 | 18 +- ikectl/ikectl.c | 11 +- ikectl/parser.c | 7 +- ikectl/parser.h | 8 +- iked/ca.c | 428 +++++++--- iked/chap_ms.c | 48 +- iked/chap_ms.h | 12 +- iked/config.c | 131 +++- iked/control.c | 28 +- iked/crypto.c | 168 +++- iked/dh.c | 120 ++- iked/dh.h | 16 +- iked/eap.c | 19 +- iked/eap.h | 8 +- iked/genmap.sh | 3 +- iked/iked.8 | 100 +-- iked/iked.c | 95 +-- iked/iked.conf.5 | 101 ++- iked/iked.h | 216 ++++-- iked/ikev1.c | 12 +- iked/ikev2.c | 1933 ++++++++++++++++++++++++++++++++++++---------- iked/ikev2.h | 37 +- iked/ikev2_msg.c | 118 +-- iked/ikev2_pld.c | 1001 +++++++++++++++++++----- iked/imsg_util.c | 17 +- iked/log.c | 7 +- iked/parse.y | 220 ++++-- iked/pfkey.c | 628 ++++++++------- iked/policy.c | 184 +++-- iked/proc.c | 432 ++++++++--- iked/timer.c | 24 +- iked/types.h | 13 +- iked/util.c | 156 +--- 35 files changed, 4488 insertions(+), 1856 deletions(-) diff --git a/ikectl/ikeca.c b/ikectl/ikeca.c index 4b84090..7e25f7f 100644 --- a/ikectl/ikeca.c +++ b/ikectl/ikeca.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikeca.c,v 1.25 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: ikeca.c,v 1.30 2015/01/16 06:40:17 deraadt Exp $ */ /* * Copyright (c) 2010 Jonathan Gray @@ -16,7 +16,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include #include #include @@ -29,6 +28,7 @@ #include #include #include +#include #include #include @@ -52,7 +52,7 @@ #endif #ifndef PATH_OPENSSL -#define PATH_OPENSSL "/usr/sbin/openssl" +#define PATH_OPENSSL "/usr/bin/openssl" #endif #ifndef PATH_ZIP #define PATH_ZIP "/usr/local/bin/zip" @@ -189,7 +189,7 @@ int ca_sign(struct ca *ca, char *keyname, int type, char *envargs) { char cmd[PATH_MAX * 2]; - char hostname[MAXHOSTNAMELEN]; + char hostname[HOST_NAME_MAX+1]; char name[128]; strlcpy(name, keyname, sizeof(name)); @@ -443,8 +443,8 @@ ca_show_certs(struct ca *ca, char *name) err(1, "could not open directory %s", ca->sslpath); while ((de = readdir(dir)) != NULL) { - if (NAMLEN(de) > 4) { - p = de->d_name + NAMLEN(de) - 4; + if (de->d_namlen > 4) { + p = de->d_name + de->d_namlen - 4; if (strcmp(".crt", p) != 0) continue; snprintf(path, sizeof(path), "%s/%s", ca->sslpath, @@ -473,8 +473,9 @@ fcopy(char *src, char *dst, mode_t mode) err(1, "open %s", src); if ((ofd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) { + int saved_errno = errno; close(ifd); - err(1, "open %s", dst); + errc(1, saved_errno, "open %s", dst); } while ((r = read(ifd, buf, sizeof(buf))) > 0) { @@ -794,7 +795,7 @@ ca_revoke(struct ca *ca, char *keyname) pass, ca->sslpath, ca->sslpath); system(cmd); - bzero(pass, len); + explicit_bzero(pass, len); free(pass); return (0); @@ -806,7 +807,6 @@ ca_setup(char *caname, int create, int quiet, char *pass) struct stat st; struct ca *ca; char path[PATH_MAX]; - u_int32_t rnd[256]; if (stat(PATH_OPENSSL, &st) == -1) err(1, "openssl binary not available"); @@ -846,8 +846,5 @@ ca_setup(char *caname, int create, int quiet, char *pass) if (create && stat(ca->passfile, &st) == -1 && errno == ENOENT) ca_newpass(ca->passfile, pass); - arc4random_buf(rnd, sizeof(rnd)); - RAND_seed(rnd, sizeof(rnd)); - return (ca); } diff --git a/ikectl/ikeca.cnf b/ikectl/ikeca.cnf index d71662c..cba9bd1 100644 --- a/ikectl/ikeca.cnf +++ b/ikectl/ikeca.cnf @@ -1,6 +1,6 @@ -# $OpenBSD: ikeca.cnf,v 1.5 2012/10/25 12:35:55 reyk Exp $ +# $OpenBSD: ikeca.cnf,v 1.6 2014/11/22 18:15:41 deraadt Exp $ -RANDFILE = /dev/arandom +RANDFILE = /dev/random CERT_C = DE CERT_ST = Lower Saxony diff --git a/ikectl/ikectl.8 b/ikectl/ikectl.8 index 19caee9..e03d9f7 100644 --- a/ikectl/ikectl.8 +++ b/ikectl/ikectl.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ikectl.8,v 1.20 2013/01/08 10:38:19 reyk Exp $ +.\" $OpenBSD: ikectl.8,v 1.23 2015/07/27 17:28:39 sobrado Exp $ .\" .\" Copyright (c) 2007-2013 Reyk Floeter .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: January 8 2013 $ +.Dd $Mdocdate: July 27 2015 $ .Dt IKECTL 8 .Os .Sh NAME @@ -149,7 +149,7 @@ as the currently active CA or into the specified .It Xo .Cm ca Ar name Cm certificate Ar host .Cm create -.Op Ic server \*(Ba client +.Op Ic server | client .Xc Create a private key and certificate for .Ar host @@ -250,17 +250,17 @@ from the named .El .Sh FILES .Bl -tag -width "/var/run/iked.sockXX" -compact -.It /etc/iked/ +.It Pa /etc/iked/ Active configuration. -.It /etc/ssl/ +.It Pa /etc/ssl/ Directory to store the CA files. -.It /usr/share/iked +.It Pa /usr/share/iked If this optional directory exists, .Nm will include the contents with the .Cm ca export commands. -.It /var/run/iked.sock +.It Pa /var/run/iked.sock default .Ux Ns -domain socket used for communication with @@ -346,9 +346,9 @@ program first appeared in The .Nm program was written by -.An Reyk Floeter Aq reyk@openbsd.org +.An Reyk Floeter Aq Mt reyk@openbsd.org and -.An Jonathan Gray Aq jsg@openbsd.org . +.An Jonathan Gray Aq Mt jsg@openbsd.org . .Sh CAVEATS For ease of use, the .Ic ca diff --git a/ikectl/ikectl.c b/ikectl/ikectl.c index 5c591fc..5e85ab8 100644 --- a/ikectl/ikectl.c +++ b/ikectl/ikectl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikectl.c,v 1.16 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: ikectl.c,v 1.19 2015/01/16 06:40:17 deraadt Exp $ */ /* * Copyright (c) 2007-2013 Reyk Floeter @@ -19,12 +19,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include #include -#include "openbsd-compat/sys-queue.h" +#include #include -#include "openbsd-compat/sys-tree.h" +#include #include #include @@ -313,7 +312,7 @@ main(int argc, char *argv[]) } while (ibuf->w.queued) - if (msgbuf_write(&ibuf->w) < 0) + if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) err(1, "write error"); while (!done) { @@ -366,7 +365,7 @@ monitor(struct imsg *imsg) imn = monitor_lookup(imsg->hdr.type); printf("%s: imsg type %u len %u peerid %u pid %d\n", imn->name, imsg->hdr.type, imsg->hdr.len, imsg->hdr.peerid, imsg->hdr.pid); - printf("\ttimestamp: %u, %s", now, ctime(&now)); + printf("\ttimestamp: %lld, %s", (long long)now, ctime(&now)); if (imn->type == -1) done = 1; if (imn->func != NULL) diff --git a/ikectl/parser.c b/ikectl/parser.c index c4a7cb4..6c21436 100644 --- a/ikectl/parser.c +++ b/ikectl/parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.c,v 1.12 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: parser.c,v 1.13 2015/01/16 06:40:17 deraadt Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -18,11 +18,10 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include #include -#include "openbsd-compat/sys-queue.h" -#include "openbsd-compat/sys-tree.h" +#include +#include #include #include diff --git a/ikectl/parser.h b/ikectl/parser.h index 4281400..250bae0 100644 --- a/ikectl/parser.h +++ b/ikectl/parser.h @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.h,v 1.12 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: parser.h,v 1.13 2015/06/11 18:49:09 reyk Exp $ */ /* * Copyright (c) 2007-2013 Reyk Floeter @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _IKECTL_PARSER_H -#define _IKECTL_PARSER_H +#ifndef IKECTL_PARSER_H +#define IKECTL_PARSER_H enum actions { NONE, @@ -88,4 +88,4 @@ int ca_key_delete(struct ca *, char *); int ca_key_install(struct ca *, char *, char *); int ca_key_import(struct ca *, char *, char *); -#endif /* _IKECTL_PARSER_H */ +#endif /* IKECTL_PARSER_H */ diff --git a/iked/ca.c b/iked/ca.c index 5f55b1f..3840cae 100644 --- a/iked/ca.c +++ b/iked/ca.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ca.c,v 1.22 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: ca.c,v 1.35 2015/03/26 19:52:35 markus Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -43,11 +42,12 @@ #include #include #include +#include #include "iked.h" #include "ikev2.h" -void ca_reset(struct privsep *, void *); +void ca_reset(struct privsep *, struct privsep_proc *, void *); int ca_reload(struct iked *); int ca_getreq(struct iked *, struct imsg *); @@ -56,6 +56,7 @@ int ca_getauth(struct iked *, struct imsg *); X509 *ca_by_subjectpubkey(X509_STORE *, u_int8_t *, size_t); X509 *ca_by_issuer(X509_STORE *, X509_NAME *, struct iked_static_id *); int ca_subjectpubkey_digest(X509 *, u_int8_t *, u_int *); +int ca_x509_subject_cmp(X509 *, struct iked_static_id *); int ca_validate_pubkey(struct iked *, struct iked_static_id *, void *, size_t); int ca_validate_cert(struct iked *, struct iked_static_id *, @@ -64,7 +65,8 @@ struct ibuf * ca_x509_serialize(X509 *); int ca_x509_subjectaltname_cmp(X509 *, struct iked_static_id *); int ca_x509_subjectaltname(X509 *cert, struct iked_id *); -int ca_key_serialize(EVP_PKEY *, struct iked_id *); +int ca_privkey_serialize(EVP_PKEY *, struct iked_id *); +int ca_pubkey_serialize(EVP_PKEY *, struct iked_id *); int ca_dispatch_parent(int, struct privsep_proc *, struct imsg *); int ca_dispatch_ikev1(int, struct privsep_proc *, struct imsg *); int ca_dispatch_ikev2(int, struct privsep_proc *, struct imsg *); @@ -83,6 +85,7 @@ struct ca_store { X509_LOOKUP *ca_certlookup; struct iked_id ca_privkey; + struct iked_id ca_pubkey; }; pid_t @@ -98,6 +101,7 @@ caproc(struct privsep *ps, struct privsep_proc *p) if ((store = calloc(1, sizeof(*store))) == NULL) fatal("ca: failed to allocate cert store"); + /* Read private key */ if ((fp = fopen(IKED_PRIVKEY, "r")) == NULL) fatal("ca: failed to open private key"); @@ -105,14 +109,18 @@ caproc(struct privsep *ps, struct privsep_proc *p) fatalx("ca: failed to read private key"); fclose(fp); - if (ca_key_serialize(key, &store->ca_privkey) != 0) + if (ca_privkey_serialize(key, &store->ca_privkey) != 0) fatalx("ca: failed to serialize private key"); + if (ca_pubkey_serialize(key, &store->ca_pubkey) != 0) + fatalx("ca: failed to serialize public key"); + + EVP_PKEY_free(key); return (proc_run(ps, p, procs, nitems(procs), ca_reset, store)); } void -ca_reset(struct privsep *ps, void *arg) +ca_reset(struct privsep *ps, struct privsep_proc *p, void *arg) { struct iked *env = ps->ps_env; struct ca_store *store = arg; @@ -153,9 +161,15 @@ ca_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) memcpy(&mode, imsg->data, sizeof(mode)); if (mode == RESET_ALL || mode == RESET_CA) { log_debug("%s: config reload", __func__); - ca_reset(&env->sc_ps, store); + ca_reset(&env->sc_ps, p, store); } break; + case IMSG_OCSP_FD: + ocsp_receive_fd(env, imsg); + break; + case IMSG_OCSP_URL: + config_getocsp(env, imsg); + break; default: return (-1); } @@ -228,7 +242,8 @@ ca_setcert(struct iked *env, struct iked_sahdr *sh, struct iked_id *id, iov[iovcnt].iov_len = len; iovcnt++; - if (proc_composev_imsg(env, procid, IMSG_CERT, -1, iov, iovcnt) == -1) + if (proc_composev_imsg(&env->sc_ps, procid, -1, + IMSG_CERT, -1, iov, iovcnt) == -1) return (-1); return (0); } @@ -269,7 +284,7 @@ ca_setreq(struct iked *env, struct iked_sahdr *sh, iov[iovcnt].iov_len = len; iovcnt++; - if (proc_composev_imsg(env, procid, + if (proc_composev_imsg(&env->sc_ps, procid, -1, IMSG_CERTREQ, -1, iov, iovcnt) == -1) goto done; @@ -288,6 +303,12 @@ ca_setauth(struct iked *env, struct iked_sa *sa, struct iked_policy *policy = sa->sa_policy; u_int8_t type = policy->pol_auth.auth_method; + /* switch encoding to IKEV2_AUTH_SIG if SHA2 is supported */ + if (sa->sa_sigsha2 && type == IKEV2_AUTH_RSA_SIG) { + log_debug("%s: switching from RSA_SIG to SIG", __func__); + type = IKEV2_AUTH_SIG; + } + if (type == IKEV2_AUTH_SHARED_KEY_MIC) { sa->sa_stateflags |= IKED_REQ_AUTH; return (ikev2_msg_authsign(env, sa, @@ -303,10 +324,11 @@ ca_setauth(struct iked *env, struct iked_sa *sa, else { iov[2].iov_base = ibuf_data(authmsg); iov[2].iov_len = ibuf_size(authmsg); - log_debug("%s: auth length %d", __func__, ibuf_size(authmsg)); + log_debug("%s: auth length %zu", __func__, ibuf_size(authmsg)); } - if (proc_composev_imsg(env, id, IMSG_AUTH, -1, iov, iovcnt) == -1) + if (proc_composev_imsg(&env->sc_ps, id, -1, + IMSG_AUTH, -1, iov, iovcnt) == -1) return (-1); return (0); } @@ -341,6 +363,11 @@ ca_getcert(struct iked *env, struct imsg *imsg) switch (type) { case IKEV2_CERT_X509_CERT: ret = ca_validate_cert(env, &id, ptr, len); + if (ret == 0 && env->sc_ocsp_url) { + ret = ocsp_validate_cert(env, &id, ptr, len, sh, type); + if (ret == 0) + return (0); + } break; case IKEV2_CERT_RSA_KEY: ret = ca_validate_pubkey(env, &id, ptr, len); @@ -361,7 +388,8 @@ ca_getcert(struct iked *env, struct imsg *imsg) iov[1].iov_base = &type; iov[1].iov_len = sizeof(type); - if (proc_composev_imsg(env, PROC_IKEV2, cmd, -1, iov, iovcnt) == -1) + if (proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, + cmd, -1, iov, iovcnt) == -1) return (-1); return (0); } @@ -390,40 +418,50 @@ ca_getreq(struct iked *env, struct imsg *imsg) return (-1); memcpy(&sh, ptr + sizeof(id), sizeof(sh)); memcpy(&type, ptr + sizeof(id) + sizeof(sh), sizeof(u_int8_t)); - if (type != IKEV2_CERT_X509_CERT) - return (-1); - - for (n = 1; i < len; n++, i += SHA_DIGEST_LENGTH) { - if ((ca = ca_by_subjectpubkey(store->ca_cas, - ptr + i, SHA_DIGEST_LENGTH)) == NULL) { - log_debug("%s: CA %d not found", __func__, n); - print_hex(ptr, i, SHA_DIGEST_LENGTH); - continue; - } - log_debug("%s: found CA %s", __func__, ca->name); + switch (type) { + case IKEV2_CERT_RSA_KEY: + if (store->ca_pubkey.id_type != type || + (buf = store->ca_pubkey.id_buf) == NULL) + return (-1); - if ((cert = ca_by_issuer(store->ca_certs, - X509_get_subject_name(ca), &id)) != NULL) { - /* XXX should we re-validate our own cert here? */ - break; - } + log_debug("%s: using local public key of type %s", __func__, + print_map(type, ikev2_cert_map)); + break; + case IKEV2_CERT_X509_CERT: + for (n = 1; i < len; n++, i += SHA_DIGEST_LENGTH) { + if ((ca = ca_by_subjectpubkey(store->ca_cas, ptr + i, + SHA_DIGEST_LENGTH)) == NULL) + continue; - log_debug("%s: no valid certificate for this CA", __func__); - } - if (ca == NULL || cert == NULL) { - log_warnx("%s: no valid local certificate found", __func__); - type = IKEV2_CERT_NONE; - ca_setcert(env, &sh, NULL, type, NULL, 0, PROC_IKEV2); - return (0); - } + log_debug("%s: found CA %s", __func__, ca->name); - log_debug("%s: found local certificate %s", __func__, cert->name); + if ((cert = ca_by_issuer(store->ca_certs, + X509_get_subject_name(ca), &id)) != NULL) { + /* XXX + * should we re-validate our own cert here? + */ + break; + } + } + if (ca == NULL || cert == NULL) { + log_warnx("%s: no valid local certificate found", + __func__); + type = IKEV2_CERT_NONE; + ca_setcert(env, &sh, NULL, type, NULL, 0, PROC_IKEV2); + return (0); + } + log_debug("%s: found local certificate %s", __func__, + cert->name); - if ((buf = ca_x509_serialize(cert)) == NULL) + if ((buf = ca_x509_serialize(cert)) == NULL) + return (-1); + break; + default: + log_warnx("%s: unknown cert type requested", __func__); return (-1); + } - type = IKEV2_CERT_X509_CERT; ca_setcert(env, &sh, NULL, type, ibuf_data(buf), ibuf_size(buf), PROC_IKEV2); @@ -492,17 +530,16 @@ ca_getauth(struct iked *env, struct imsg *imsg) int ca_reload(struct iked *env) { - struct ca_store *store = env->sc_priv; - DIR *dir; - struct dirent *entry; + struct ca_store *store = env->sc_priv; + u_int8_t md[EVP_MAX_MD_SIZE]; char file[PATH_MAX]; + struct iovec iov[2]; + struct dirent *entry; STACK_OF(X509_OBJECT) *h; X509_OBJECT *xo; X509 *x509; - int i, len; - u_int8_t md[EVP_MAX_MD_SIZE]; - struct iovec iov[2]; - int iovcnt = 2; + DIR *dir; + int i, len, iovcnt = 0; /* * Load CAs @@ -523,7 +560,7 @@ ca_reload(struct iked *env) X509_FILETYPE_PEM)) { log_warn("%s: failed to load ca file %s", __func__, entry->d_name); - ca_sslerror(); + ca_sslerror(__func__); continue; } log_debug("%s: loaded ca file %s", __func__, entry->d_name); @@ -549,7 +586,7 @@ ca_reload(struct iked *env) X509_FILETYPE_PEM)) { log_warn("%s: failed to load crl file %s", __func__, entry->d_name); - ca_sslerror(); + ca_sslerror(__func__); continue; } @@ -588,16 +625,18 @@ ca_reload(struct iked *env) env->sc_certreqtype = IKEV2_CERT_X509_CERT; iov[0].iov_base = &env->sc_certreqtype; iov[0].iov_len = sizeof(env->sc_certreqtype); + iovcnt++; iov[1].iov_base = ibuf_data(env->sc_certreq); iov[1].iov_len = ibuf_length(env->sc_certreq); + iovcnt++; - log_debug("%s: loaded %d ca certificate%s", __func__, + log_debug("%s: loaded %zu ca certificate%s", __func__, ibuf_length(env->sc_certreq) / SHA_DIGEST_LENGTH, ibuf_length(env->sc_certreq) == SHA_DIGEST_LENGTH ? "" : "s"); - (void)proc_composev_imsg(env, PROC_IKEV2, IMSG_CERTREQ, -1, - iov, iovcnt); + (void)proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, + IMSG_CERTREQ, -1, iov, iovcnt); } /* @@ -619,7 +658,7 @@ ca_reload(struct iked *env) X509_FILETYPE_PEM)) { log_warn("%s: failed to load cert file %s", __func__, entry->d_name); - ca_sslerror(); + ca_sslerror(__func__); continue; } log_debug("%s: loaded cert file %s", __func__, entry->d_name); @@ -637,6 +676,19 @@ ca_reload(struct iked *env) (void)ca_validate_cert(env, NULL, x509, 0); } + if (!env->sc_certreqtype) + env->sc_certreqtype = store->ca_pubkey.id_type; + + log_debug("%s: local cert type %s", __func__, + print_map(env->sc_certreqtype, ikev2_cert_map)); + + iov[0].iov_base = &env->sc_certreqtype; + iov[0].iov_len = sizeof(env->sc_certreqtype); + if (iovcnt == 0) + iovcnt++; + (void)proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, + IMSG_CERTREQ, -1, iov, iovcnt); + return (0); } @@ -690,9 +742,16 @@ ca_by_issuer(X509_STORE *ctx, X509_NAME *subject, struct iked_static_id *id) if ((issuer = X509_get_issuer_name(cert)) == NULL) continue; else if (X509_NAME_cmp(subject, issuer) == 0) { - if (ca_x509_subjectaltname_cmp(cert, id) != 0) - continue; - return (cert); + switch (id->id_type) { + case IKEV2_ID_ASN1_DN: + if (ca_x509_subject_cmp(cert, id) == 0) + return (cert); + break; + default: + if (ca_x509_subjectaltname_cmp(cert, id) == 0) + return (cert); + break; + } } } @@ -743,16 +802,18 @@ ca_x509_serialize(X509 *x509) len = BIO_get_mem_data(out, &d); buf = ibuf_new(d, len); + BIO_free(out); return (buf); } int -ca_key_serialize(EVP_PKEY *key, struct iked_id *id) +ca_pubkey_serialize(EVP_PKEY *key, struct iked_id *id) { - int len; + RSA *rsa = NULL; u_int8_t *d; - RSA *rsa; + int len = 0; + int ret = -1; switch (key->type) { case EVP_PKEY_RSA: @@ -761,16 +822,60 @@ ca_key_serialize(EVP_PKEY *key, struct iked_id *id) ibuf_release(id->id_buf); if ((rsa = EVP_PKEY_get1_RSA(key)) == NULL) - return (-1); + goto done; + if ((len = i2d_RSAPublicKey(rsa, NULL)) <= 0) + goto done; + if ((id->id_buf = ibuf_new(NULL, len)) == NULL) + goto done; + + d = ibuf_data(id->id_buf); + if (i2d_RSAPublicKey(rsa, &d) != len) { + ibuf_release(id->id_buf); + goto done; + } + + id->id_type = IKEV2_CERT_RSA_KEY; + break; + default: + log_debug("%s: unsupported key type %d", __func__, key->type); + return (-1); + } + + log_debug("%s: type %s length %d", __func__, + print_map(id->id_type, ikev2_cert_map), len); + + ret = 0; + done: + if (rsa != NULL) + RSA_free(rsa); + return (ret); +} + +int +ca_privkey_serialize(EVP_PKEY *key, struct iked_id *id) +{ + RSA *rsa = NULL; + u_int8_t *d; + int len = 0; + int ret = -1; + + switch (key->type) { + case EVP_PKEY_RSA: + id->id_type = 0; + id->id_offset = 0; + ibuf_release(id->id_buf); + + if ((rsa = EVP_PKEY_get1_RSA(key)) == NULL) + goto done; if ((len = i2d_RSAPrivateKey(rsa, NULL)) <= 0) - return (-1); + goto done; if ((id->id_buf = ibuf_new(NULL, len)) == NULL) - return (-1); + goto done; d = ibuf_data(id->id_buf); if (i2d_RSAPrivateKey(rsa, &d) != len) { ibuf_release(id->id_buf); - return (-1); + goto done; } id->id_type = IKEV2_CERT_RSA_KEY; @@ -780,7 +885,14 @@ ca_key_serialize(EVP_PKEY *key, struct iked_id *id) return (-1); } - return (0); + log_debug("%s: type %s length %d", __func__, + print_map(id->id_type, ikev2_cert_map), len); + + ret = 0; + done: + if (rsa != NULL) + RSA_free(rsa); + return (ret); } char * @@ -812,17 +924,112 @@ ca_x509_name(void *ptr) return (strdup(buf)); } +/* + * Copy 'src' to 'dst' until 'marker' is found while unescaping '\' + * characters. The return value tells the caller where to continue + * parsing (might be the end of the string) or NULL on error. + */ +static char * +ca_x509_name_unescape(char *src, char *dst, char marker) +{ + while (*src) { + if (*src == marker) { + src++; + break; + } + if (*src == '\\') { + src++; + if (!*src) { + log_warnx("%s: '\\' at end of string", + __func__); + *dst = '\0'; + return (NULL); + } + } + *dst++ = *src++; + } + *dst = '\0'; + return (src); +} +/* + * Parse an X509 subject name where 'subject' is in the format + * /type0=value0/type1=value1/type2=... + * where characters may be escaped by '\'. + * See lib/libssl/src/apps/apps.c:parse_name() + */ +void * +ca_x509_name_parse(char *subject) +{ + char *cp, *value = NULL, *type = NULL; + size_t maxlen; + X509_NAME *name = NULL; + + if (*subject != '/') { + log_warnx("%s: leading '/' missing in '%s'", __func__, subject); + goto err; + } + + /* length of subject is upper bound for unescaped type/value */ + maxlen = strlen(subject) + 1; + + if ((type = calloc(1, maxlen)) == NULL || + (value = calloc(1, maxlen)) == NULL || + (name = X509_NAME_new()) == NULL) + goto err; + + cp = subject + 1; + while (*cp) { + /* unescape type, terminated by '=' */ + cp = ca_x509_name_unescape(cp, type, '='); + if (cp == NULL) { + log_warnx("%s: could not parse type", __func__); + goto err; + } + if (!*cp) { + log_warnx("%s: missing value", __func__); + goto err; + } + /* unescape value, terminated by '/' */ + cp = ca_x509_name_unescape(cp, value, '/'); + if (cp == NULL) { + log_warnx("%s: could not parse value", __func__); + goto err; + } + if (!*type || !*value) { + log_warnx("%s: empty type or value", __func__); + goto err; + } + log_debug("%s: setting '%s' to '%s'", __func__, type, value); + if (!X509_NAME_add_entry_by_txt(name, type, MBSTRING_ASC, + value, -1, -1, 0)) { + log_warnx("%s: setting '%s' to '%s' failed", __func__, + type, value); + ca_sslerror(__func__); + goto err; + } + } + free(type); + free(value); + return (name); + +err: + X509_NAME_free(name); + free(type); + free(value); + return (NULL); +} + int ca_validate_pubkey(struct iked *env, struct iked_static_id *id, void *data, size_t len) { BIO *rawcert = NULL; - RSA *rsa = NULL; + RSA *peerrsa = NULL, *localrsa = NULL; EVP_PKEY *peerkey = NULL, *localkey = NULL; int ret = -1; FILE *fp = NULL; char idstr[IKED_ID_SIZE]; - char file[MAXPATHLEN]; + char file[PATH_MAX]; struct iked_id idp; if (len == 0 && data == NULL) @@ -855,42 +1062,58 @@ ca_validate_pubkey(struct iked *env, struct iked_static_id *id, if ((rawcert = BIO_new_mem_buf(data, len)) == NULL) goto done; - if ((rsa = d2i_RSAPublicKey_bio(rawcert, NULL)) == NULL) + if ((peerrsa = d2i_RSAPublicKey_bio(rawcert, NULL)) == NULL) goto sslerr; if ((peerkey = EVP_PKEY_new()) == NULL) goto sslerr; - if (!EVP_PKEY_set1_RSA(peerkey, rsa)) + if (!EVP_PKEY_set1_RSA(peerkey, peerrsa)) goto sslerr; } lc_string(idstr); if (strlcpy(file, IKED_PUBKEY_DIR, sizeof(file)) >= sizeof(file) || - strlcpy(file, idstr, sizeof(file)) >= sizeof(file)) + strlcat(file, idstr, sizeof(file)) >= sizeof(file)) goto done; - log_debug("%s: looking up %s", __func__, file); - if ((fp = fopen(file, "r")) == NULL) goto done; - localkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL); - fclose(fp); + if (localkey == NULL) { + /* reading PKCS #8 failed, try PEM */ + rewind(fp); + localrsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL); + fclose(fp); + if (localrsa == NULL) + goto sslerr; + if ((localkey = EVP_PKEY_new()) == NULL) + goto sslerr; + if (!EVP_PKEY_set1_RSA(localkey, localrsa)) + goto sslerr; + } else { + fclose(fp); + } if (localkey == NULL) goto sslerr; if (!EVP_PKEY_cmp(peerkey, localkey)) goto done; + log_debug("%s: valid public key in file %s", __func__, file); + ret = 0; sslerr: if (ret != 0) - ca_sslerror(); + ca_sslerror(__func__); done: ibuf_release(idp.id_buf); if (peerkey != NULL) EVP_PKEY_free(peerkey); - if (rsa != NULL) - RSA_free(rsa); + if (localkey != NULL) + EVP_PKEY_free(localkey); + if (peerrsa != NULL) + RSA_free(peerrsa); + if (localrsa != NULL) + RSA_free(localrsa); if (rawcert != NULL) BIO_free(rawcert); @@ -906,9 +1129,7 @@ ca_validate_cert(struct iked *env, struct iked_static_id *id, BIO *rawcert = NULL; X509 *cert = NULL; int ret = -1, result, error; - size_t idlen, idoff; - const u_int8_t *idptr; - X509_NAME *idname = NULL, *subject; + X509_NAME *subject; const char *errstr = "failed"; if (len == 0) { @@ -931,23 +1152,13 @@ ca_validate_cert(struct iked *env, struct iked_static_id *id, if (id != NULL) { if ((ret = ca_validate_pubkey(env, id, X509_get_pubkey(cert), 0)) == 0) { - errstr = "public key found, ok"; + errstr = "in public key file, ok"; goto done; } switch (id->id_type) { case IKEV2_ID_ASN1_DN: - idoff = id->id_offset; - if (id->id_length <= idoff) { - errstr = "invalid ASN1_DN id length"; - goto done; - } - idlen = id->id_length - idoff; - idptr = id->id_data + idoff; - - if ((idname = d2i_X509_NAME(NULL, - &idptr, idlen)) == NULL || - X509_NAME_cmp(subject, idname) != 0) { + if (ca_x509_subject_cmp(cert, id) < 0) { errstr = "ASN1_DN identifier mismatch"; goto done; } @@ -984,14 +1195,12 @@ ca_validate_cert(struct iked *env, struct iked_static_id *id, /* Success */ ret = 0; + errstr = "ok"; done: if (cert != NULL) - log_debug("%s: %s %.100s", __func__, cert->name, - ret == 0 ? "ok" : errstr); + log_debug("%s: %s %.100s", __func__, cert->name, errstr); - if (idname != NULL) - X509_NAME_free(idname); if (rawcert != NULL) { BIO_free(rawcert); if (cert != NULL) @@ -1001,6 +1210,31 @@ ca_validate_cert(struct iked *env, struct iked_static_id *id, return (ret); } +/* check if subject from cert matches the id */ +int +ca_x509_subject_cmp(X509 *cert, struct iked_static_id *id) +{ + X509_NAME *subject, *idname = NULL; + const u_int8_t *idptr; + size_t idlen; + int ret = -1; + + if (id->id_type != IKEV2_ID_ASN1_DN) + return (-1); + if ((subject = X509_get_subject_name(cert)) == NULL) + return (-1); + if (id->id_length <= id->id_offset) + return (-1); + idlen = id->id_length - id->id_offset; + idptr = id->id_data + id->id_offset; + if ((idname = d2i_X509_NAME(NULL, &idptr, idlen)) == NULL) + return (-1); + if (X509_NAME_cmp(subject, idname) == 0) + ret = 0; + X509_NAME_free(idname); + return (ret); +} + int ca_x509_subjectaltname_cmp(X509 *cert, struct iked_static_id *id) { @@ -1112,16 +1346,14 @@ ca_sslinit(void) /* Init hardware crypto engines. */ ENGINE_load_builtin_engines(); ENGINE_register_all_complete(); - - seed_rng(); } void -ca_sslerror(void) +ca_sslerror(const char *caller) { u_long error; while ((error = ERR_get_error()) != 0) - log_warn("%s: %.100s", __func__, + log_warn("%s: %s: %.100s", __func__, caller, ERR_error_string(error, NULL)); } diff --git a/iked/chap_ms.c b/iked/chap_ms.c index dfaff2f..eea7907 100644 --- a/iked/chap_ms.c +++ b/iked/chap_ms.c @@ -1,4 +1,4 @@ -/* $OpenBSD: chap_ms.c,v 1.6 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: chap_ms.c,v 1.8 2014/11/20 03:48:12 tedu Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -332,52 +332,6 @@ mschap_msk(u_int8_t *password, int passwordlen, memcpy(msk + sizeof(recvkey), &sendkey, sizeof(sendkey)); } -void -mschap_newkey(u_int8_t *startkey, u_int8_t *sessionkey, - long sessionkeylen, u_int8_t *key) -{ - EVP_MD_CTX ctx; - u_int8_t md[SHA_DIGEST_LENGTH]; - u_int mdlen; - - EVP_DigestInit(&ctx, EVP_sha1()); - EVP_DigestUpdate(&ctx, startkey, sessionkeylen); - EVP_DigestUpdate(&ctx, sha1_pad1, sizeof(sha1_pad1)); - EVP_DigestUpdate(&ctx, sessionkey, sessionkeylen); - EVP_DigestUpdate(&ctx, sha1_pad2, sizeof(sha1_pad2)); - EVP_DigestFinal(&ctx, md, &mdlen); - - memcpy(key, md, sessionkeylen); -} - -void -mschap_nt(u_int8_t *password_hash, u_int8_t *challenge) -{ - u_int8_t response[24]; - - mschap_challenge_response(challenge, password_hash, response); - memcpy(password_hash, response, sizeof(response)); - password_hash[24] = 1; /* NT-style response */ -} - -void -mschap_lanman(u_int8_t *digest, u_int8_t *challenge, u_int8_t *secret) -{ - static u_int8_t salt[] = "KGS!@#$%"; /* RASAPI32.dll */ - u_int8_t SECRET[14 + 1], *ptr, *end; - u_int8_t hash[MSCHAP_HASH_SZ]; - - bzero(&SECRET, sizeof(SECRET)); - end = SECRET + (sizeof(SECRET) - 1); - for (ptr = SECRET; *secret && ptr < end; ptr++, secret++) - *ptr = toupper(*secret); - - mschap_des_encrypt(salt, SECRET, hash); - mschap_des_encrypt(salt, SECRET + 7, hash + 8); - - mschap_challenge_response(challenge, hash, digest); -} - void mschap_radiuskey(u_int8_t *plain, const u_int8_t *crypted, const u_int8_t *authenticator, const u_int8_t *secret) diff --git a/iked/chap_ms.h b/iked/chap_ms.h index f06940c..d78d335 100644 --- a/iked/chap_ms.h +++ b/iked/chap_ms.h @@ -1,4 +1,4 @@ -/* $OpenBSD: chap_ms.h,v 1.3 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: chap_ms.h,v 1.5 2015/06/11 18:49:09 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _CHAP_MS_H -#define _CHAP_MS_H +#ifndef CHAP_MS_H +#define CHAP_MS_H #define MSCHAP_CHALLENGE_SZ 8 #define MSCHAPV2_CHALLENGE_SZ 16 @@ -34,18 +34,14 @@ void mschap_nt_response(u_int8_t *, u_int8_t *, u_int8_t *, int, void mschap_auth_response(u_int8_t *, int, u_int8_t *, u_int8_t *, u_int8_t *, u_int8_t *, int, u_int8_t *); -void mschap_nt(u_int8_t *, u_int8_t *); -void mschap_lanman(u_int8_t *, u_int8_t *, u_int8_t *); - void mschap_ntpassword_hash(u_int8_t *, int, u_int8_t *); void mschap_challenge_hash(u_int8_t *, u_int8_t *, u_int8_t *, int, u_int8_t *); void mschap_asymetric_startkey(u_int8_t *, u_int8_t *, int, int, int); void mschap_masterkey(u_int8_t *, u_int8_t *, u_int8_t *); -void mschap_newkey(u_int8_t *, u_int8_t *, long, u_int8_t *); void mschap_radiuskey(u_int8_t *, const u_int8_t *, const u_int8_t *, const u_int8_t *); void mschap_msk(u_int8_t *, int, u_int8_t *, u_int8_t *); -#endif /* _CHAP_MS_H */ +#endif /* CHAP_MS_H */ diff --git a/iked/config.c b/iked/config.c index 397191d..0e05d8f 100644 --- a/iked/config.c +++ b/iked/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.20 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: config.c,v 1.36 2015/07/07 19:13:31 markus Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,24 +16,15 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include #include #include #include -#include -#include -#include -#include -#include -#include - #include #include #include #include -#include #include #include #include @@ -75,26 +66,47 @@ config_getspi(void) { u_int64_t spi; - spi = ((u_int64_t)arc4random() << 32) | arc4random(); - if (spi == 0) - return (config_getspi()); + do { + arc4random_buf(&spi, sizeof spi); + } while (spi == 0); return (spi); } void -config_free_sa(struct iked *env, struct iked_sa *sa) +config_free_kex(struct iked_kex *kex) { - (void)RB_REMOVE(iked_sas, &env->sc_sas, sa); + if (kex == NULL) + return; + + ibuf_release(kex->kex_inonce); + ibuf_release(kex->kex_rnonce); - timer_deregister(env, &sa->sa_timer); + if (kex->kex_dhgroup != NULL) + group_free(kex->kex_dhgroup); + ibuf_release(kex->kex_dhiexchange); + ibuf_release(kex->kex_dhrexchange); + + free(kex); +} + +void +config_free_sa(struct iked *env, struct iked_sa *sa) +{ + timer_del(env, &sa->sa_timer); + timer_del(env, &sa->sa_rekey); config_free_proposals(&sa->sa_proposals, 0); config_free_childsas(env, &sa->sa_childsas, NULL, NULL); sa_free_flows(env, &sa->sa_flows); + if (sa->sa_addrpool) { + (void)RB_REMOVE(iked_addrpool, &env->sc_addrpool, sa); + free(sa->sa_addrpool); + } + if (sa->sa_policy) { - (void)RB_REMOVE(iked_sapeers, &sa->sa_policy->pol_sapeers, sa); + TAILQ_REMOVE(&sa->sa_policy->pol_sapeers, sa, sa_peer_entry); policy_unref(env, sa->sa_policy); } @@ -145,8 +157,10 @@ config_new_policy(struct iked *env) if ((pol = calloc(1, sizeof(*pol))) == NULL) return (NULL); + /* XXX caller does this again */ TAILQ_INIT(&pol->pol_proposals); - RB_INIT(&pol->pol_sapeers); + TAILQ_INIT(&pol->pol_sapeers); + RB_INIT(&pol->pol_flows); return (pol); } @@ -161,10 +175,13 @@ config_free_policy(struct iked *env, struct iked_policy *pol) TAILQ_REMOVE(&env->sc_policies, pol, pol_entry); - RB_FOREACH(sa, iked_sapeers, &pol->pol_sapeers) { - /* Remove from the policy tree, but keep for existing SAs */ + TAILQ_FOREACH(sa, &pol->pol_sapeers, sa_peer_entry) { + /* Remove from the policy list, but keep for existing SAs */ if (sa->sa_policy == pol) policy_ref(env, pol); + else + log_warnx("%s: ERROR: sa_policy %p != pol %p", + __func__, sa->sa_policy, pol); } if (pol->pol_refcnt) @@ -321,8 +338,8 @@ config_add_transform(struct iked_proposal *prop, u_int type, } } - if ((xform = realloc(prop->prop_xforms, - (prop->prop_nxforms + 1) * sizeof(*xform))) == NULL) { + if ((xform = reallocarray(prop->prop_xforms, + prop->prop_nxforms + 1, sizeof(*xform))) == NULL) { return (NULL); } @@ -341,7 +358,8 @@ config_add_transform(struct iked_proposal *prop, u_int type, } struct iked_transform * -config_findtransform(struct iked_proposals *props, u_int8_t type) +config_findtransform(struct iked_proposals *props, u_int8_t type, + u_int proto) { struct iked_proposal *prop; struct iked_transform *xform; @@ -349,6 +367,9 @@ config_findtransform(struct iked_proposals *props, u_int8_t type) /* Search of the first transform with the desired type */ TAILQ_FOREACH(prop, props, prop_entry) { + /* Find any proposal or only selected SA proto */ + if (proto != 0 && prop->prop_protoid != proto) + continue; for (i = 0; i < prop->prop_nxforms; i++) { xform = prop->prop_xforms + i; if (xform->xform_type == type) @@ -393,8 +414,8 @@ config_setcoupled(struct iked *env, u_int couple) u_int type; type = couple ? IMSG_CTL_COUPLE : IMSG_CTL_DECOUPLE; - proc_compose_imsg(env, PROC_IKEV1, type, -1, NULL, 0); - proc_compose_imsg(env, PROC_IKEV2, type, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, PROC_IKEV1, -1, type, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, PROC_IKEV2, -1, type, -1, NULL, 0); return (0); } @@ -412,8 +433,8 @@ config_setmode(struct iked *env, u_int passive) u_int type; type = passive ? IMSG_CTL_PASSIVE : IMSG_CTL_ACTIVE; - proc_compose_imsg(env, PROC_IKEV1, type, -1, NULL, 0); - proc_compose_imsg(env, PROC_IKEV2, type, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, PROC_IKEV1, -1, type, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, PROC_IKEV2, -1, type, -1, NULL, 0); return (0); } @@ -439,7 +460,8 @@ config_getmode(struct iked *env, u_int type) int config_setreset(struct iked *env, u_int mode, enum privsep_procid id) { - proc_compose_imsg(env, id, IMSG_CTL_RESET, -1, &mode, sizeof(mode)); + proc_compose_imsg(&env->sc_ps, id, -1, + IMSG_CTL_RESET, -1, &mode, sizeof(mode)); return (0); } @@ -468,6 +490,7 @@ config_getreset(struct iked *env, struct imsg *imsg) for (sa = RB_MIN(iked_sas, &env->sc_sas); sa != NULL; sa = nextsa) { nextsa = RB_NEXT(iked_sas, &env->sc_sas, sa); + RB_REMOVE(iked_sas, &env->sc_sas, sa); config_free_sa(env, sa); } } @@ -493,8 +516,8 @@ config_setsocket(struct iked *env, struct sockaddr_storage *ss, if ((s = udp_bind((struct sockaddr *)ss, port)) == -1) return (-1); - proc_compose_imsg(env, id, IMSG_UDP_SOCKET, s, - ss, sizeof(*ss)); + proc_compose_imsg(&env->sc_ps, id, -1, + IMSG_UDP_SOCKET, s, ss, sizeof(*ss)); return (0); } @@ -531,7 +554,8 @@ config_getsocket(struct iked *env, struct imsg *imsg, if (*sptr == NULL) *sptr = sock; if (*nptr == NULL && - socket_getport(&sock->sock_addr) == IKED_NATT_PORT) + socket_getport((struct sockaddr *)&sock->sock_addr) == + IKED_NATT_PORT) *nptr = sock; event_set(&sock->sock_ev, sock->sock_fd, @@ -548,7 +572,8 @@ config_setpfkey(struct iked *env, enum privsep_procid id) if ((s = pfkey_socket()) == -1) return (-1); - proc_compose_imsg(env, id, IMSG_PFKEY_SOCKET, s, NULL, 0); + proc_compose_imsg(&env->sc_ps, id, -1, + IMSG_PFKEY_SOCKET, s, NULL, 0); return (0); } @@ -568,7 +593,8 @@ config_setuser(struct iked *env, struct iked_user *usr, enum privsep_procid id) return (0); } - proc_compose_imsg(env, id, IMSG_CFG_USER, -1, usr, sizeof(*usr)); + proc_compose_imsg(&env->sc_ps, id, -1, + IMSG_CFG_USER, -1, usr, sizeof(*usr)); return (0); } @@ -638,8 +664,8 @@ config_setpolicy(struct iked *env, struct iked_policy *pol, return (0); } - if (proc_composev_imsg(env, id, IMSG_CFG_POLICY, -1, - iov, iovcnt) == -1) + if (proc_composev_imsg(&env->sc_ps, id, -1, + IMSG_CFG_POLICY, -1, iov, iovcnt) == -1) return (-1); return (0); @@ -666,6 +692,7 @@ config_getpolicy(struct iked *env, struct imsg *imsg) offset += sizeof(*pol); TAILQ_INIT(&pol->pol_proposals); + TAILQ_INIT(&pol->pol_sapeers); RB_INIT(&pol->pol_flows); for (i = 0; i < pol->pol_nproposals; i++) { @@ -694,7 +721,8 @@ config_getpolicy(struct iked *env, struct imsg *imsg) memcpy(flow, buf + offset, sizeof(*flow)); offset += sizeof(*flow); - RB_INSERT(iked_flows, &pol->pol_flows, flow); + if (RB_INSERT(iked_flows, &pol->pol_flows, flow)) + free(flow); } TAILQ_INSERT_TAIL(&env->sc_policies, pol, pol_entry); @@ -717,7 +745,8 @@ config_setcompile(struct iked *env, enum privsep_procid id) if (env->sc_opts & IKED_OPT_NOACTION) return (0); - proc_compose_imsg(env, id, IMSG_COMPILE, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, id, -1, + IMSG_COMPILE, -1, NULL, 0); return (0); } @@ -733,3 +762,29 @@ config_getcompile(struct iked *env, struct imsg *imsg) log_debug("%s: compilation done", __func__); return (0); } + +int +config_setocsp(struct iked *env) +{ + if (env->sc_opts & IKED_OPT_NOACTION) + return (0); + proc_compose_imsg(&env->sc_ps, PROC_CERT, -1, + IMSG_OCSP_URL, -1, env->sc_ocsp_url, + env->sc_ocsp_url ? strlen(env->sc_ocsp_url) : 0); + + return (0); +} + +int +config_getocsp(struct iked *env, struct imsg *imsg) +{ + if (env->sc_ocsp_url) + free(env->sc_ocsp_url); + if (IMSG_DATA_SIZE(imsg) > 0) + env->sc_ocsp_url = get_string(imsg->data, IMSG_DATA_SIZE(imsg)); + else + env->sc_ocsp_url = NULL; + log_debug("%s: ocsp_url %s", __func__, + env->sc_ocsp_url ? env->sc_ocsp_url : "none"); + return (0); +} diff --git a/iked/control.c b/iked/control.c index dfa48b3..3932008 100644 --- a/iked/control.c +++ b/iked/control.c @@ -1,4 +1,4 @@ -/* $OpenBSD: control.c,v 1.12 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: control.c,v 1.16 2015/01/16 06:39:58 deraadt Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -17,12 +17,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "openbsd-compat/sys-queue.h" -#include +#include #include #include #include -#include "openbsd-compat/sys-tree.h" +#include #include @@ -241,22 +240,17 @@ control_dispatch_imsg(int fd, short event, void *arg) return; } - switch (event) { - case EV_READ: + if (event & EV_READ) { if ((n = imsg_read(&c->iev.ibuf)) == -1 || n == 0) { control_close(fd, cs); return; } - break; - case EV_WRITE: - if (msgbuf_write(&c->iev.ibuf.w) < 0) { + } + if (event & EV_WRITE) { + if (msgbuf_write(&c->iev.ibuf.w) <= 0 && errno != EAGAIN) { control_close(fd, cs); return; } - imsg_event_add(&c->iev); - return; - default: - fatalx("unknown event"); } for (;;) { @@ -288,9 +282,9 @@ control_dispatch_imsg(int fd, short event, void *arg) memcpy(&v, imsg.data, sizeof(v)); log_verbose(v); - proc_forward_imsg(env, &imsg, PROC_PARENT); - proc_forward_imsg(env, &imsg, PROC_IKEV2); - proc_forward_imsg(env, &imsg, PROC_IKEV1); + proc_forward_imsg(&env->sc_ps, &imsg, PROC_PARENT, -1); + proc_forward_imsg(&env->sc_ps, &imsg, PROC_IKEV2, -1); + proc_forward_imsg(&env->sc_ps, &imsg, PROC_IKEV1, -1); break; case IMSG_CTL_RELOAD: case IMSG_CTL_RESET: @@ -298,7 +292,7 @@ control_dispatch_imsg(int fd, short event, void *arg) case IMSG_CTL_DECOUPLE: case IMSG_CTL_ACTIVE: case IMSG_CTL_PASSIVE: - proc_forward_imsg(env, &imsg, PROC_PARENT); + proc_forward_imsg(&env->sc_ps, &imsg, PROC_PARENT, -1); break; default: log_debug("%s: error handling imsg %d", diff --git a/iked/crypto.c b/iked/crypto.c index 6959c37..2fd6f35 100644 --- a/iked/crypto.c +++ b/iked/crypto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: crypto.c,v 1.9 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: crypto.c,v 1.16 2015/03/26 19:52:35 markus Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include /* roundup */ +#include #include #include @@ -34,10 +34,39 @@ #include #include #include +#include #include "iked.h" #include "ikev2.h" +/* RFC 7427, A.1 */ +static const u_int8_t sha256WithRSAEncryption[] = { + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00 +}; +static const u_int8_t sha384WithRSAEncryption[] = { + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00 +}; +static const u_int8_t sha512WithRSAEncryption[] = { + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00 +}; + +struct { + u_int8_t sc_len; + const u_int8_t *sc_oid; + const EVP_MD *(*sc_md)(void); +} schemes[] = { + { sizeof(sha256WithRSAEncryption), sha256WithRSAEncryption, EVP_sha256 }, + { sizeof(sha384WithRSAEncryption), sha384WithRSAEncryption, EVP_sha384 }, + { sizeof(sha512WithRSAEncryption), sha512WithRSAEncryption, EVP_sha512 }, +}; + +int _dsa_verify_init(struct iked_dsa *, const u_int8_t *, size_t); +size_t _dsa_verify_offset(struct iked_dsa *, u_int8_t *); +int _dsa_sign_encode(struct iked_dsa *, u_int8_t *, size_t *); + struct iked_hash * hash_new(u_int8_t type, u_int16_t id) { @@ -328,7 +357,7 @@ cipher_setiv(struct iked_cipher *encr, void *iv, size_t len) ibuf_release(encr->encr_iv); if (iv != NULL) { if (len < encr->encr_ivlength) { - log_debug("%s: invalid IV length %d", __func__, len); + log_debug("%s: invalid IV length %zu", __func__, len); return (NULL); } encr->encr_iv = ibuf_new(iv, encr->encr_ivlength); @@ -384,7 +413,7 @@ cipher_update(struct iked_cipher *encr, void *in, size_t inlen, olen = 0; if (!EVP_CipherUpdate(encr->encr_ctx, out, &olen, in, inlen)) { - ca_sslerror(); + ca_sslerror(__func__); *outlen = 0; return; } @@ -398,7 +427,7 @@ cipher_final(struct iked_cipher *encr, void *out, size_t *outlen) olen = 0; if (!EVP_CipherFinal_ex(encr->encr_ctx, out, &olen)) { - ca_sslerror(); + ca_sslerror(__func__); *outlen = 0; return; } @@ -441,16 +470,15 @@ dsa_new(u_int16_t id, struct iked_hash *prf, int sign) bzero(&dsa, sizeof(dsa)); switch (id) { + case IKEV2_AUTH_SIG: + if (sign) + dsa.dsa_priv = EVP_sha256(); /* XXX should be passed */ + else + dsa.dsa_priv = NULL; /* set later by dsa_init() */ + break; case IKEV2_AUTH_RSA_SIG: - /* - * XXX RFC4306 is not very clear about this and the - * XXX informational RFC4718 says that we should use - * XXX SHA1 here, but shouldn't we use the negotiated PRF - * XXX alg instead? - */ - if ((dsa.dsa_priv = - EVP_get_digestbyname("sha1WithRSAEncryption")) == NULL) - fatalx("dsa_new: cipher not available"); + /* RFC5996 says we SHOULD use SHA1 here */ + dsa.dsa_priv = EVP_sha1(); break; case IKEV2_AUTH_SHARED_KEY_MIC: if (prf == NULL || prf->hash_priv == NULL) @@ -578,6 +606,7 @@ dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, u_int8_t type) if (!EVP_PKEY_set1_RSA(pkey, rsa)) goto sslerr; + RSA_free(rsa); /* pkey now has the reference */ dsa->dsa_cert = NULL; dsa->dsa_key = pkey; break; @@ -591,7 +620,7 @@ dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, u_int8_t type) return (dsa->dsa_keydata); sslerr: - ca_sslerror(); + ca_sslerror(__func__); err: log_debug("%s: error", __func__); @@ -608,9 +637,54 @@ dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, u_int8_t type) } int -dsa_init(struct iked_dsa *dsa) +_dsa_verify_init(struct iked_dsa *dsa, const u_int8_t *sig, size_t len) +{ + u_int8_t oidlen; + size_t i; + + if (dsa->dsa_priv != NULL) + return (0); + /* + * For IKEV2_AUTH_SIG the oid of the authentication signature + * is encoded in the first bytes of the auth message. + */ + if (dsa->dsa_method != IKEV2_AUTH_SIG) { + log_debug("%s: dsa_priv not set for %s", __func__, + print_map(dsa->dsa_method, ikev2_auth_map)); + return (-1); + } + if (sig == NULL) { + log_debug("%s: signature missing", __func__); + return (-1); + } + if (len < 1) { + log_debug("%s: signature (%zu) too small for oid length", + __func__, len); + return (-1); + } + memcpy(&oidlen, sig, sizeof(oidlen)); + if (len < (size_t)oidlen + 1) { + log_debug("%s: signature (%zu) too small for oid (%u)", + __func__, len, oidlen); + return (-1); + } + for (i = 0; i < nitems(schemes); i++) { + if (oidlen == schemes[i].sc_len && + memcmp(sig + 1, schemes[i].sc_oid, schemes[i].sc_len) == 0) { + dsa->dsa_priv = (*schemes[i].sc_md)(); + log_debug("%s: signature scheme %zd selected", + __func__, i); + return (0); + } + } + log_debug("%s: unsupported signature (%d)", __func__, oidlen); + return (-1); +} + +int +dsa_init(struct iked_dsa *dsa, const void *buf, size_t len) { - int ret; + int ret; if (dsa->dsa_hmac) { if (!HMAC_Init_ex(dsa->dsa_ctx, ibuf_data(dsa->dsa_keydata), @@ -621,8 +695,11 @@ dsa_init(struct iked_dsa *dsa) if (dsa->dsa_sign) ret = EVP_SignInit_ex(dsa->dsa_ctx, dsa->dsa_priv, NULL); - else + else { + if ((ret = _dsa_verify_init(dsa, buf, len)) != 0) + return (ret); ret = EVP_VerifyInit_ex(dsa->dsa_ctx, dsa->dsa_priv, NULL); + } return (ret ? 0 : -1); } @@ -642,18 +719,44 @@ dsa_update(struct iked_dsa *dsa, const void *buf, size_t len) return (ret ? 0 : -1); } +/* Prefix signature hash with encoded type */ +int +_dsa_sign_encode(struct iked_dsa *dsa, u_int8_t *ptr, size_t *offp) +{ + if (offp) + *offp = 0; + if (dsa->dsa_method != IKEV2_AUTH_SIG) + return (0); + if (dsa->dsa_priv != EVP_sha256()) + return (-1); + if (ptr) { + ptr[0] = sizeof(sha256WithRSAEncryption); + memcpy(ptr + 1, sha256WithRSAEncryption, + sizeof(sha256WithRSAEncryption)); + } + if (offp) + *offp = 1 + sizeof(sha256WithRSAEncryption); + return (0); +} + size_t dsa_length(struct iked_dsa *dsa) { + size_t off = 0; + if (dsa->dsa_hmac) return (EVP_MD_size(dsa->dsa_priv)); - return (EVP_PKEY_size(dsa->dsa_key)); + if (_dsa_sign_encode(dsa, NULL, &off) < 0) + fatal("dsa_length: internal error"); + return (EVP_PKEY_size(dsa->dsa_key) + off); } ssize_t dsa_sign_final(struct iked_dsa *dsa, void *buf, size_t len) { u_int siglen; + size_t off = 0; + u_int8_t *ptr = buf; if (len < dsa_length(dsa)) return (-1); @@ -662,19 +765,36 @@ dsa_sign_final(struct iked_dsa *dsa, void *buf, size_t len) if (!HMAC_Final(dsa->dsa_ctx, buf, &siglen)) return (-1); } else { - if (!EVP_SignFinal(dsa->dsa_ctx, buf, &siglen, + if (_dsa_sign_encode(dsa, ptr, &off) < 0) + return (-1); + if (!EVP_SignFinal(dsa->dsa_ctx, ptr + off, &siglen, dsa->dsa_key)) return (-1); + siglen += off; } return (siglen); } +size_t +_dsa_verify_offset(struct iked_dsa *dsa, u_int8_t *ptr) +{ + /* + * XXX assumes that _dsa_verify_init() has already checked + * the encoded method. + */ + if (dsa->dsa_method == IKEV2_AUTH_SIG) + return (ptr[0] + 1); + return (0); +} + ssize_t dsa_verify_final(struct iked_dsa *dsa, void *buf, size_t len) { u_int8_t sig[EVP_MAX_MD_SIZE]; u_int siglen = sizeof(sig); + u_int8_t *ptr = buf; + size_t off = 0; if (dsa->dsa_hmac) { if (!HMAC_Final(dsa->dsa_ctx, sig, &siglen)) @@ -682,9 +802,11 @@ dsa_verify_final(struct iked_dsa *dsa, void *buf, size_t len) if (siglen != len || memcmp(buf, sig, siglen) != 0) return (-1); } else { - if (EVP_VerifyFinal(dsa->dsa_ctx, buf, len, + if ((off = _dsa_verify_offset(dsa, ptr)) >= len) + return (-1); + if (EVP_VerifyFinal(dsa->dsa_ctx, ptr + off, len - off, dsa->dsa_key) != 1) { - ca_sslerror(); + ca_sslerror(__func__); return (-1); } } diff --git a/iked/dh.c b/iked/dh.c index de33d96..5c5ae38 100644 --- a/iked/dh.c +++ b/iked/dh.c @@ -1,7 +1,7 @@ -/* $OpenBSD: dh.c,v 1.10 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: dh.c,v 1.16 2015/01/16 06:39:58 deraadt Exp $ */ /* - * Copyright (c) 2010-2013 Reyk Floeter + * Copyright (c) 2010-2014 Reyk Floeter * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,23 +16,26 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +#include /* roundup */ #include #include #include #include #include +#include #include "dh.h" int dh_init(struct group *); +/* MODP */ int modp_init(struct group *); int modp_getlen(struct group *); int modp_create_exchange(struct group *, u_int8_t *); int modp_create_shared(struct group *, u_int8_t *, u_int8_t *); +/* EC2N/ECP */ int ec_init(struct group *); int ec_getlen(struct group *); int ec_create_exchange(struct group *, u_int8_t *); @@ -42,6 +45,23 @@ int ec_point2raw(struct group *, const EC_POINT *, u_int8_t *, size_t); EC_POINT * ec_raw2point(struct group *, u_int8_t *, size_t); +/* curve25519 */ +int ec25519_init(struct group *); +int ec25519_getlen(struct group *); +int ec25519_create_exchange(struct group *, u_int8_t *); +int ec25519_create_shared(struct group *, u_int8_t *, u_int8_t *); + +#define CURVE25519_SIZE 32 /* 256 bits */ +struct curve25519_key { + u_int8_t secret[CURVE25519_SIZE]; + u_int8_t public[CURVE25519_SIZE]; +}; +extern int crypto_scalarmult_curve25519(u_char a[CURVE25519_SIZE], + const u_char b[CURVE25519_SIZE], const u_char c[CURVE25519_SIZE]) + __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) + __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))) + __attribute__((__bounded__(__minbytes__, 3, CURVE25519_SIZE))); + struct group_id ike_groups[] = { { GROUP_MODP, 1, 768, "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" @@ -277,7 +297,14 @@ struct group_id ike_groups[] = { "5E2327CFEF98C582664B4C0F6CC41659" }, { GROUP_ECP, 25, 192, NULL, NULL, NID_X9_62_prime192v1 }, - { GROUP_ECP, 26, 224, NULL, NULL, NID_secp224r1 } + { GROUP_ECP, 26, 224, NULL, NULL, NID_secp224r1 }, + { GROUP_ECP, 27, 224, NULL, NULL, NID_brainpoolP224r1 }, + { GROUP_ECP, 28, 256, NULL, NULL, NID_brainpoolP256r1 }, + { GROUP_ECP, 29, 384, NULL, NULL, NID_brainpoolP384r1 }, + { GROUP_ECP, 30, 512, NULL, NULL, NID_brainpoolP512r1 }, + + /* "Private use" extensions */ + { GROUP_CURVE25519, 1034, CURVE25519_SIZE * 8 } }; void @@ -296,6 +323,11 @@ group_free(struct group *group) DH_free(group->dh); if (group->ec != NULL) EC_KEY_free(group->ec); + if (group->curve25519 != NULL) { + explicit_bzero(group->curve25519, + sizeof(struct curve25519_key)); + free(group->curve25519); + } group->spec = NULL; free(group); } @@ -337,6 +369,12 @@ group_get(u_int32_t id) group->exchange = ec_create_exchange; group->shared = ec_create_shared; break; + case GROUP_CURVE25519: + group->init = ec25519_init; + group->getlen = ec25519_getlen; + group->exchange = ec25519_create_exchange; + group->shared = ec25519_create_shared; + break; default: group_free(group); return (NULL); @@ -434,7 +472,7 @@ modp_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange) ret = DH_compute_key(secret, ex, group->dh); BN_clear_free(ex); - if (!ret) + if (ret <= 0) return (-1); /* add zero padding */ @@ -453,6 +491,10 @@ ec_init(struct group *group) return (-1); if (!EC_KEY_generate_key(group->ec)) return (-1); + if (!EC_KEY_check_key(group->ec)) { + EC_KEY_free(group->ec); + return (-1); + } return (0); } @@ -482,6 +524,7 @@ ec_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange) { const EC_GROUP *ecgroup = NULL; const BIGNUM *privkey; + EC_KEY *exkey = NULL; EC_POINT *exchangep = NULL, *secretp = NULL; int ret = -1; @@ -493,6 +536,17 @@ ec_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange) ec_raw2point(group, exchange, ec_getlen(group))) == NULL) goto done; + if ((exkey = EC_KEY_new()) == NULL) + goto done; + if (!EC_KEY_set_group(exkey, ecgroup)) + goto done; + if (!EC_KEY_set_public_key(exkey, exchangep)) + goto done; + + /* validate exchangep */ + if (!EC_KEY_check_key(exkey)) + goto done; + if ((secretp = EC_POINT_new(ecgroup)) == NULL) goto done; @@ -502,6 +556,8 @@ ec_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange) ret = ec_point2raw(group, secretp, secret, ec_getlen(group)); done: + if (exkey != NULL) + EC_KEY_free(exkey); if (exchangep != NULL) EC_POINT_clear_free(exchangep); if (secretp != NULL) @@ -559,6 +615,11 @@ ec_point2raw(struct group *group, const EC_POINT *point, ret = 0; done: + /* Make sure to erase sensitive data */ + if (x != NULL) + BN_clear(x); + if (y != NULL) + BN_clear(y); BN_CTX_end(bnctx); BN_CTX_free(bnctx); @@ -612,8 +673,57 @@ ec_raw2point(struct group *group, u_int8_t *buf, size_t len) done: if (ret != 0 && point != NULL) EC_POINT_clear_free(point); + /* Make sure to erase sensitive data */ + if (x != NULL) + BN_clear(x); + if (y != NULL) + BN_clear(y); BN_CTX_end(bnctx); BN_CTX_free(bnctx); return (point); } + +int +ec25519_init(struct group *group) +{ + static const u_int8_t basepoint[CURVE25519_SIZE] = { 9 }; + struct curve25519_key *curve25519; + + if ((curve25519 = calloc(1, sizeof(*curve25519))) == NULL) + return (-1); + + group->curve25519 = curve25519; + + arc4random_buf(curve25519->secret, CURVE25519_SIZE); + crypto_scalarmult_curve25519(curve25519->public, + curve25519->secret, basepoint); + + return (0); +} + +int +ec25519_getlen(struct group *group) +{ + if (group->spec == NULL) + return (0); + return (CURVE25519_SIZE); +} + +int +ec25519_create_exchange(struct group *group, u_int8_t *buf) +{ + struct curve25519_key *curve25519 = group->curve25519; + + memcpy(buf, curve25519->public, ec25519_getlen(group)); + return (0); +} + +int +ec25519_create_shared(struct group *group, u_int8_t *shared, u_int8_t *public) +{ + struct curve25519_key *curve25519 = group->curve25519; + + crypto_scalarmult_curve25519(shared, curve25519->secret, public); + return (0); +} diff --git a/iked/dh.h b/iked/dh.h index d7b8ea8..1b058d3 100644 --- a/iked/dh.h +++ b/iked/dh.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dh.h,v 1.5 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: dh.h,v 1.7 2015/06/11 18:49:09 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,13 +16,14 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _DH_H_ -#define _DH_H_ +#ifndef DH_GROUP_H +#define DH_GROUP_H enum group_type { - GROUP_MODP = 0, - GROUP_EC2N = 1, - GROUP_ECP = 2 + GROUP_MODP = 0, + GROUP_EC2N = 1, + GROUP_ECP = 2, + GROUP_CURVE25519 = 3 }; struct group_id { @@ -40,6 +41,7 @@ struct group { void *dh; void *ec; + void *curve25519; int (*init)(struct group *); int (*getlen)(struct group *); @@ -57,4 +59,4 @@ int dh_getlen(struct group *); int dh_create_exchange(struct group *, u_int8_t *); int dh_create_shared(struct group *, u_int8_t *, u_int8_t *); -#endif /* _DH_H_ */ +#endif /* DH_GROUP_H */ diff --git a/iked/eap.c b/iked/eap.c index bbb5a7c..a947a5d 100644 --- a/iked/eap.c +++ b/iked/eap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: eap.c,v 1.9 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: eap.c,v 1.13 2015/02/06 10:39:01 deraadt Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,23 +16,18 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include #include #include #include #include -#if defined(__OpenBSD__) -#include -#endif #include #include #include #include #include -#include #include #include #include @@ -79,11 +74,11 @@ eap_identity_response(struct eap_message *eap) ptr += sizeof(*eap); if (len == 0 || (str = get_string(ptr, len)) == NULL) { - log_info("%s: invalid identity response, length %d", + log_info("%s: invalid identity response, length %zu", __func__, len); return (NULL); } - log_debug("%s: identity '%s' length %d", __func__, str, len); + log_debug("%s: identity '%s' length %zd", __func__, str, len); return (str); } @@ -399,7 +394,7 @@ eap_parse(struct iked *env, struct iked_sa *sa, void *data, int response) return (-1); } log_info("%s: %s %s id %d " - "length %d valuesize %d name '%s' length %d", + "length %d valuesize %d name '%s' length %zu", __func__, print_map(eap->eap_type, eap_type_map), print_map(ms->ms_opcode, eap_msopcode_map), @@ -420,7 +415,7 @@ eap_parse(struct iked *env, struct iked_sa *sa, void *data, int response) return (-1); } log_info("%s: %s %s id %d " - "length %d valuesize %d name '%s' name-length %d", + "length %d valuesize %d name '%s' name-length %zu", __func__, print_map(eap->eap_type, eap_type_map), print_map(ms->ms_opcode, eap_msopcode_map), @@ -442,7 +437,7 @@ eap_parse(struct iked *env, struct iked_sa *sa, void *data, int response) return (-1); } log_info("%s: %s %s request id %d " - "length %d message '%s' message-len %d", + "length %d message '%s' message-len %zu", __func__, print_map(eap->eap_type, eap_type_map), print_map(ms->ms_opcode, eap_msopcode_map), diff --git a/iked/eap.h b/iked/eap.h index a8d158e..799750c 100644 --- a/iked/eap.h +++ b/iked/eap.h @@ -1,4 +1,4 @@ -/* $OpenBSD: eap.h,v 1.3 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: eap.h,v 1.4 2015/06/11 18:49:09 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _IKEV2_EAP_H -#define _IKEV2_EAP_H +#ifndef IKED_EAP_H +#define IKED_EAP_H struct eap_header { u_int8_t eap_code; @@ -168,4 +168,4 @@ struct eap_mschap_failure { extern struct iked_constmap eap_mserror_map[]; -#endif /* _IKEV2_EAP_H */ +#endif /* IKED_EAP_H */ diff --git a/iked/genmap.sh b/iked/genmap.sh index 685f42e..9cd4ba0 100644 --- a/iked/genmap.sh +++ b/iked/genmap.sh @@ -1,5 +1,5 @@ #!/bin/sh -# $OpenBSD: genmap.sh,v 1.6 2013/01/08 10:38:19 reyk Exp $ +# $OpenBSD: genmap.sh,v 1.7 2015/01/16 06:39:58 deraadt Exp $ # Copyright (c) 2010-2013 Reyk Floeter # @@ -28,7 +28,6 @@ EOF sed -n '1,/^ \*\//p' $1 cat < #include #include "types.h" diff --git a/iked/iked.8 b/iked/iked.8 index 7f2dc16..c03ec11 100644 --- a/iked/iked.8 +++ b/iked/iked.8 @@ -1,6 +1,6 @@ -.\" $OpenBSD: iked.8,v 1.13 2013/01/08 10:38:19 reyk Exp $ +.\" $OpenBSD: iked.8,v 1.19 2014/11/10 13:57:32 jmc Exp $ .\" -.\" Copyright (c) 2010-2013 Reyk Floeter +.\" Copyright (c) 2010 - 2014 Reyk Floeter .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: January 8 2013 $ +.Dd $Mdocdate: November 10 2014 $ .Dt IKED 8 .Os .Sh NAME @@ -23,9 +23,7 @@ .Sh SYNOPSIS .Nm iked .Op Fl 6dnSTtv -.Oo -.Fl D Ar macro Ns = Ns Ar value -.Oc +.Op Fl D Ar macro Ns = Ns Ar value .Op Fl f Ar file .Sh DESCRIPTION .Nm @@ -48,10 +46,8 @@ is provided by .Nm supports mutual authentication using RSA public keys and X.509 certificates. See the -.Sx FILES -section below and -.Sx PKI AND CERTIFICATE AUTHORITY COMMANDS -in +.Sx PUBLIC KEY AUTHENTICATION +section below and PKI AND CERTIFICATE AUTHORITY COMMANDS in .Xr ikectl 8 for more information about creating and maintaining the public key infrastructure. @@ -103,6 +99,54 @@ negotiate NAT-Traversal with the peers. .It Fl v Produce more verbose output. .El +.Sh PUBLIC KEY AUTHENTICATION +It is possible to store trusted public keys to make them directly +usable by +.Nm , +bypassing the need to use certificates. +The keys should be saved in PEM format (see +.Xr openssl 1 ) +and named and stored as follows: +.Pp +.Bl -tag -width "for_ufqdn_identitiesXX" -offset 3n -compact +.It For IPv4 identities: +/etc/iked/pubkeys/ipv4/A.B.C.D +.It For IPv6 identities: +/etc/iked/pubkeys/ipv6/abcd:abcd::ab:bc +.It For FQDN identities: +/etc/iked/pubkeys/fqdn/foo.bar.org +.It For UFQDN identities: +/etc/iked/pubkeys/ufqdn/user@foo.bar.org +.El +.Pp +Depending on the +.Ic srcid +and +.Ic dstid +specifications in +.Xr iked.conf 5 , +keys may be named after their IPv4 address, IPv6 address, +fully qualified domain name (FQDN) or user fully qualified domain name (UFQDN). +.Pp +For example, +.Nm +can authenticate using the pre-generated keys if the local public key, +by default +.Pa /etc/iked/local.pub , +is copied to the remote gateway as +.Pa /etc/iked/pubkeys/ipv4/local.gateway.ip.address +and the remote gateway's public key +is copied to the local gateway as +.Pa /etc/iked/pubkeys/ipv4/remote.gateway.ip.address . +Of course, new keys may also be generated +(the user is not required to use the pre-generated keys). +In this example, +.Ic srcid +and +.Ic dstid +would also have to be set to the specified addresses +in +.Xr iked.conf 5 . .Sh FILES .Bl -tag -width "/etc/iked/private/XXX" -compact .It Pa /etc/iked.conf @@ -154,38 +198,4 @@ program first appeared in The .Nm program was written by -.An Reyk Floeter Aq reyk@openbsd.org . -.Sh CAVEATS -.Nm -is not yet finished and is missing some important security features. -It should not yet be used in production networks. -.Sh BUGS -The portable version of -.Nm , -.Ic OpenIKED , -might have a few limitations on operating systems other than the most -recent versions of -.Ox . -A major difference between -.Ox -and other systems is the API and availability of the IPsec PFKEYv2 -flow implementation (SADB) and message passing between kernel and -.Nm . -Current known limitations are: -.Bl -tag -width Ds -.It Ic VPN traffic leakage prevention -Automatic blocking of IPv6 traffic is not working on KAME-bases stacks. -.It Ic NAT-T -NAT-T is only supported on OpenBSD and Darwin (OS X). -The NAT-T API is not standardized in PFKEYv2, not even on a semi-level, -and differs in most operating systems, if supported at all. -.It Ic Crypto algorithms -Some of the crypto algorithms are either not supported on other -systems or not implemented correctly. -For example, Linux still uses the broken pre-standard version of -hmac-sha2-256 by default that was specified with 96 bit truncation -instead of the standard 128 bit truncation. -The common workaround that allows to specify the truncation length -would be to use Linux' non-standard XFRM kernel API instead of -PFKEYv2. -.El +.An Reyk Floeter Aq Mt reyk@openbsd.org . diff --git a/iked/iked.c b/iked/iked.c index 7419f13..9a9c7cd 100644 --- a/iked/iked.c +++ b/iked/iked.c @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.c,v 1.17 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: iked.c,v 1.24 2015/06/03 02:24:36 millert Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,24 +16,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include #include #include #include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_DEPRECATED_DAEMON -/* Apple deprected daemon() and prints an warning that breaks -Werror */ -#define daemon XXX_daemon -#endif - #include #include #include @@ -48,11 +35,6 @@ #include "iked.h" #include "ikev2.h" -#ifdef HAVE_DEPRECATED_DAEMON -#undef daemon -extern int daemon(int, int); -#endif - __dead void usage(void); void parent_shutdown(struct iked *); @@ -68,12 +50,6 @@ static struct privsep_proc procs[] = { { "ca", PROC_CERT, parent_dispatch_ca, caproc, IKED_CA } }; -#ifndef HAVE_SETPROCTITLE -/* Saved arguments to main(). */ -char **saved_argv; -int saved_argc; -#endif - __dead void usage(void) { @@ -96,24 +72,6 @@ main(int argc, char *argv[]) log_init(1); -#ifndef HAVE_SETPROCTITLE - /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ - saved_argc = argc; - saved_argv = calloc(argc + 1, sizeof(*saved_argv)); - if (saved_argv == NULL) - fatal("calloc: argv"); - for (c = 0; c < argc; c++) { - saved_argv[c] = strdup(argv[c]); - if (saved_argv[c] == NULL) - fatal("strdup: saved_argv[c]"); - } - saved_argv[c] = NULL; - - /* Prepare for later setproctitle emulation */ - compat_init_setproctitle(argc, argv); - argv = saved_argv; -#endif - while ((c = getopt(argc, argv, "6dD:nf:vSTt")) != -1) { switch (c) { case '6': @@ -159,13 +117,14 @@ main(int argc, char *argv[]) ps = &env->sc_ps; ps->ps_env = env; + TAILQ_INIT(&ps->ps_rcsocks); if ((opts & (IKED_OPT_NONATT|IKED_OPT_NATT)) == (IKED_OPT_NONATT|IKED_OPT_NATT)) errx(1, "conflicting NAT-T options"); - if (strlcpy(env->sc_conffile, conffile, MAXPATHLEN) >= MAXPATHLEN) - errx(1, "config file exceeds MAXPATHLEN"); + if (strlcpy(env->sc_conffile, conffile, PATH_MAX) >= PATH_MAX) + errx(1, "config file exceeds PATH_MAX"); ca_sslinit(); policy_init(env); @@ -187,6 +146,8 @@ main(int argc, char *argv[]) err(1, "failed to daemonize"); group_init(); + + ps->ps_ninstances = 1; proc_init(ps, procs, nitems(procs)); setproctitle("parent"); @@ -198,14 +159,16 @@ main(int argc, char *argv[]) signal_set(&ps->ps_evsigchld, SIGCHLD, parent_sig_handler, ps); signal_set(&ps->ps_evsighup, SIGHUP, parent_sig_handler, ps); signal_set(&ps->ps_evsigpipe, SIGPIPE, parent_sig_handler, ps); + signal_set(&ps->ps_evsigusr1, SIGUSR1, parent_sig_handler, ps); signal_add(&ps->ps_evsigint, NULL); signal_add(&ps->ps_evsigterm, NULL); signal_add(&ps->ps_evsigchld, NULL); signal_add(&ps->ps_evsighup, NULL); signal_add(&ps->ps_evsigpipe, NULL); + signal_add(&ps->ps_evsigusr1, NULL); - proc_config(ps, procs, nitems(procs)); + proc_listen(ps, procs, nitems(procs)); if (parent_configure(env) == -1) fatalx("configuration failed"); @@ -221,9 +184,6 @@ int parent_configure(struct iked *env) { struct sockaddr_storage ss; -#if defined(HAVE_APPLE_NATT) - int udpencap; -#endif if (parse_config(env->sc_conffile, env) == -1) { proc_kill(&env->sc_ps); @@ -246,15 +206,6 @@ parent_configure(struct iked *env) bzero(&ss, sizeof(ss)); ss.ss_family = AF_INET; -#if defined(HAVE_APPLE_NATT) - if ((env->sc_opts & IKED_OPT_NONATT) == 0) { - udpencap = IKED_NATT_PORT; - if (sysctlbyname("net.inet.ipsec.esp_port", NULL, NULL, - &udpencap, sizeof(udpencap)) != 0) - fatalx("failed to set NAT-T port"); - } -#endif - if ((env->sc_opts & IKED_OPT_NATT) == 0) config_setsocket(env, &ss, ntohs(IKED_IKE_PORT), PROC_IKEV2); if ((env->sc_opts & IKED_OPT_NONATT) == 0) @@ -270,6 +221,7 @@ parent_configure(struct iked *env) config_setcoupled(env, env->sc_decoupled ? 0 : 1); config_setmode(env, env->sc_passive ? 1 : 0); + config_setocsp(env); return (0); } @@ -299,6 +251,7 @@ parent_reload(struct iked *env, int reset, const char *filename) config_setcoupled(env, env->sc_decoupled ? 0 : 1); config_setmode(env, env->sc_passive ? 1 : 0); + config_setocsp(env); } else { config_setreset(env, reset, PROC_IKEV1); config_setreset(env, reset, PROC_IKEV2); @@ -327,12 +280,17 @@ parent_sig_handler(int sig, short event, void *arg) case SIGPIPE: log_info("%s: ignoring SIGPIPE", __func__); break; + case SIGUSR1: + log_info("%s: ignoring SIGUSR1", __func__); + break; case SIGTERM: case SIGINT: die = 1; /* FALLTHROUGH */ case SIGCHLD: do { + int len; + pid = waitpid(-1, &status, WNOHANG); if (pid <= 0) continue; @@ -340,17 +298,21 @@ parent_sig_handler(int sig, short event, void *arg) fail = 0; if (WIFSIGNALED(status)) { fail = 1; - asprintf(&cause, "terminated; signal %d", + len = asprintf(&cause, "terminated; signal %d", WTERMSIG(status)); } else if (WIFEXITED(status)) { if (WEXITSTATUS(status) != 0) { fail = 1; - asprintf(&cause, "exited abnormally"); + len = asprintf(&cause, + "exited abnormally"); } else - asprintf(&cause, "exited okay"); + len = asprintf(&cause, "exited okay"); } else fatalx("unexpected cause of SIGCHLD"); + if (len == -1) + fatal("asprintf"); + die = 1; for (id = 0; id < PROC_MAX; id++) @@ -412,8 +374,10 @@ parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg) case IMSG_CTL_DECOUPLE: case IMSG_CTL_ACTIVE: case IMSG_CTL_PASSIVE: - proc_compose_imsg(env, PROC_IKEV1, type, -1, NULL, 0); - proc_compose_imsg(env, PROC_IKEV2, type, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, PROC_IKEV1, -1, + type, -1, NULL, 0); + proc_compose_imsg(&env->sc_ps, PROC_IKEV2, -1, + type, -1, NULL, 0); break; case IMSG_CTL_RELOAD: if (IMSG_DATA_SIZE(imsg) > 0) @@ -422,6 +386,9 @@ parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg) if (str != NULL) free(str); break; + case IMSG_OCSP_FD: + ocsp_connect(env); + break; default: return (-1); } diff --git a/iked/iked.conf.5 b/iked/iked.conf.5 index c915ee0..d02e08e 100644 --- a/iked/iked.conf.5 +++ b/iked/iked.conf.5 @@ -1,6 +1,6 @@ -.\" $OpenBSD: iked.conf.5,v 1.23 2013/03/05 19:16:01 sobrado Exp $ +.\" $OpenBSD: iked.conf.5,v 1.39 2015/07/14 13:06:37 jmc Exp $ .\" -.\" Copyright (c) 2010-2013 Reyk Floeter +.\" Copyright (c) 2010 - 2014 Reyk Floeter .\" Copyright (c) 2004 Mathieu Sauve-Frankel All rights reserved. .\" .\" Permission to use, copy, modify, and distribute this software for any @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: March 5 2013 $ +.Dd $Mdocdate: July 14 2015 $ .Dt IKED.CONF 5 .Os .Sh NAME @@ -136,6 +136,13 @@ This is the default. .It Ic set decouple Don't load the negotiated SAs and flows from the kernel. This mode is only useful for testing and debugging. +.It Ic set ocsp Ar URL +Enable OCSP and set the URL of the OCSP responder. +Please note that the matching responder and issuer certificates +have to be placed in +.Pa /etc/iked/ocsp/responder.crt +and +.Pa /etc/iked/ocsp/issuer.crt . .It Ic user Ar name Ar password .Xr iked 8 supports user-based authentication by tunneling the Extensible @@ -239,6 +246,10 @@ is specified, negotiation will be started at once. If omitted, .Ar passive mode will be used. +.It Ic ipcomp +Enable optional support for +.Xr ipcomp 4 , +the IP Payload Compression protocol. .It Op Ar encap .Ar encap specifies the encapsulation protocol to be used. @@ -386,7 +397,7 @@ If omitted, will use the default proposals for the ESP or AH protocol. The .Ic group -option will only be used to enable Perfect Forwarding Security (PFS) +option will only be used to enable Perfect Forward Secrecy (PFS) for additional Child SAs exchanges that are not part of the initial key exchange. .It Ic srcid Ar string Ic dstid Ar string @@ -424,6 +435,14 @@ is similar to .Ic srcid , but instead specifies the ID to be used by the remote peer. +.It Ic ikelifetime Ar time +The optional +.Ic ikelifetime +parameter defines the IKE SA expiration timeout by the +.Ar time +SA was created. +A zero value disables active IKE SA rekeying. +This is the default. .It Ic lifetime Ar time Op Ic bytes Ar bytes The optional .Ic lifetime @@ -473,6 +492,33 @@ or hex value (starting with 0x) for authentication. Use RSA public key authentication. This is the default mode if no option is specified. .El +.It Ic config Ar option address +Send one or more optional configuration payloads (CP) to the peer. +The configuration +.Ar option +can be one of the following with the expected address format: +.Pp +.Bl -tag -width Ds -compact -offset indent +.It Ic address Ar address +Assign a static address on the internal network. +.It Ic address Ar address/prefix +Assign a dynamic address on the internal network. +The address will be assigned from an address pool with the size specified by +.Ar prefix . +.It Ic netmask Ar netmask +The IPv4 netmask of the internal network. +.It Ic name-server Ar address +The DNS server address within the internal network. +.It Ic netbios-server Ar address +The NetBIOS name server (WINS) within the internal network. +This option is provided for compatibility with legacy clients. +.It Ic dhcp-server Ar address +The address of an internal DHCP server for further configuration. +.It Ic protected-subnet Ar address/prefix +The address of the protected subnet within the internal network. +.It Ic access-server Ar address +The address of an internal remote access server. +.El .It Ic tag Ar string Add a .Xr pf 4 @@ -553,7 +599,7 @@ Interface for IKE traffic and encapsulated IPsec traffic. IKE traffic on the external interface. .It proto udp port 4500 IKE NAT-Traversal traffic on the external interface. -.It proto ah \*(Ba esp +.It proto ah | esp Encapsulated IPsec traffic on the external interface. .It enc0 @@ -624,17 +670,16 @@ The following fragment uses queues for all IPsec traffic with special handling for developers and employees: .Bd -literal -offset indent -altq on ix0 cbq bandwidth 1000Mb \e - queue { deflt, developers, employees, ipsec } - queue deflt bandwidth 10% priority 0 cbq(default ecn) - queue developers bandwidth 75% priority 7 cbq(borrow red) - queue employees bandwidth 5% cbq(red) - queue ipsec bandwidth 10% cbq(red) +queue std on ix0 bandwidth 100M +queue deflt parent std bandwidth 10M default +queue developers parent std bandwidth 75M +queue employees parent std bandwidth 5M +queue ipsec parent std bandwidth 10M -pass out on ix0 proto esp queue ipsec +pass out on ix0 proto esp set queue ipsec -pass out on ix0 tagged ipsec-developers.example.com queue developers -pass out on ix0 tagged ipsec-employees.example.com queue employees +pass out on ix0 tagged ipsec-developers.example.com set queue developers +pass out on ix0 tagged ipsec-employees.example.com set queue employees .Ed .Pp The following example assigns the tags in the @@ -673,7 +718,7 @@ a relevant NAT rule is required in For the example above, this would be: .Bd -literal -offset indent -match on enc0 from 192.168.1.0/24 to 192.168.2.0/24 nat-to 10.10.10.1 +match out on enc0 from 192.168.1.0/24 to 192.168.2.0/24 nat-to 10.10.10.1 .Ed .Pp From the peer's point of view, @@ -720,16 +765,21 @@ keyword: .It Li aes-128-gcm Ta "160 bits" Ta "[ESP only]" .It Li aes-192-gcm Ta "224 bits" Ta "[ESP only]" .It Li aes-256-gcm Ta "288 bits" Ta "[ESP only]" +.It Li blowfish Ta "160 bits" Ta "[ESP only]" +.It Li cast Ta "128 bits" Ta "[ESP only]" +.El +.Pp +The following cipher types provide only authentication, +not encryption: +.Bl -column "aes-128-gmac" "Key Length" "[ESP only]" -offset indent .It Li aes-128-gmac Ta "160 bits" Ta "[ESP only]" .It Li aes-192-gmac Ta "224 bits" Ta "[ESP only]" .It Li aes-256-gmac Ta "288 bits" Ta "[ESP only]" -.It Li blowfish Ta "160 bits" Ta "[ESP only]" -.It Li cast Ta "128 bits" Ta "[ESP only]" .It Li null Ta "" Ta "[ESP only]" .El .Pp -Use of DES as an encryption algorithm is not recommended (except for -backwards compatibility) due to the short key length. +Use of DES as an encryption algorithm is considered to be insecure +since brute force attacks are practical due its short key length. .Pp DES requires 8 bytes to form a 56-bit key and 3DES requires 24 bytes to form its 168-bit key. @@ -766,17 +816,22 @@ keyword: .It Li modp2048-256 Ta grp24 Ta 2048 Ta "MODP, 256 bit Prime Order Subgroup" .It Li ecp192 Ta grp25 Ta 192 Ta "ECP" .It Li ecp224 Ta grp26 Ta 224 Ta "ECP" +.It Li brainpool224 Ta grp27 Ta 224 Ta "ECP, brainpoolP224r1" +.It Li brainpool256 Ta grp28 Ta 256 Ta "ECP, brainpoolP256r1" +.It Li brainpool384 Ta grp29 Ta 384 Ta "ECP, brainpoolP384r1" +.It Li brainpool512 Ta grp30 Ta 512 Ta "ECP, brainpoolP512r1" +.It Li curve25519 Ta - Ta 256 Ta "Curve25519" .El .Pp The currently supported group types are either MODP (exponentiation groups modulo a prime), EC2N (elliptic curve groups over GF[2^N]), -or -ECP (elliptic curve groups modulo a prime). +ECP (elliptic curve groups modulo a prime), +or the non-standard Curve25519. Please note that the EC2N groups are considered as insecure and only provided for backwards compatibility. .Sh EXAMPLES -The first example is intended for clients connecting to +The first example is intended for a server with clients connecting to .Xr iked 8 as an IPsec gateway, or IKEv2 responder, using mutual public key authentication and additional challenge-based EAP-MSCHAPv2 password @@ -846,4 +901,4 @@ file format first appeared in The .Xr iked 8 program was written by -.An Reyk Floeter Aq reyk@openbsd.org . +.An Reyk Floeter Aq Mt reyk@openbsd.org . diff --git a/iked/iked.h b/iked/iked.h index 0430274..5df3d35 100644 --- a/iked/iked.h +++ b/iked/iked.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.h,v 1.56 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: iked.h,v 1.86 2015/07/07 19:13:31 markus Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -19,13 +19,14 @@ #include #include "openbsd-compat/sys-tree.h" #include "openbsd-compat/sys-queue.h" +#include #include #include "types.h" #include "dh.h" -#ifndef _IKED_H -#define _IKED_H +#ifndef IKED_H +#define IKED_H /* * Common IKEv1/IKEv2 header @@ -50,6 +51,7 @@ struct imsgev { struct imsgbuf ibuf; void (*handler)(int, short, void *); struct event ev; + struct privsep_proc *proc; void *data; short events; const char *name; @@ -79,7 +81,10 @@ struct control_sock { int cs_fd; int cs_restricted; void *cs_env; + + TAILQ_ENTRY(control_sock) cs_entry; }; +TAILQ_HEAD(control_socks, control_sock); struct ctl_conn { TAILQ_ENTRY(ctl_conn) entry; @@ -141,10 +146,6 @@ struct iked_flow { u_int8_t flow_saproto; u_int8_t flow_ipproto; u_int8_t flow_type; - u_int32_t flow_id; - - struct iked_id *flow_srcid; - struct iked_id *flow_dstid; struct iked_addr *flow_local; /* outer source */ struct iked_addr *flow_peer; /* outer dest */ @@ -166,17 +167,15 @@ struct iked_childsa { u_int8_t csa_allocated; /* from the kernel */ u_int8_t csa_persistent;/* do not rekey */ u_int8_t csa_esn; /* use ESN */ + u_int8_t csa_transport; /* transport mode */ struct iked_spi csa_spi; struct ibuf *csa_encrkey; /* encryption key */ - struct iked_transform *csa_encrxf; /* encryption xform */ + u_int16_t csa_encrid; /* encryption xform id */ struct ibuf *csa_integrkey; /* auth key */ - struct iked_transform *csa_integrxf; /* auth xform */ - - struct iked_id *csa_srcid; - struct iked_id *csa_dstid; + u_int16_t csa_integrid; /* auth xform id */ struct iked_addr *csa_local; /* outer source */ struct iked_addr *csa_peer; /* outer dest */ @@ -184,6 +183,9 @@ struct iked_childsa { struct iked_childsa *csa_peersa; /* peer */ + struct iked_childsa *csa_parent; /* IPCOMP parent */ + u_int csa_children; /* IPCOMP children */ + RB_ENTRY(iked_childsa) csa_node; TAILQ_ENTRY(iked_childsa) csa_entry; }; @@ -213,7 +215,7 @@ struct iked_cfg { } cfg; }; -RB_HEAD(iked_sapeers, iked_sa); +TAILQ_HEAD(iked_sapeers, iked_sa); struct iked_lifetime { u_int64_t lt_bytes; @@ -239,9 +241,12 @@ struct iked_policy { #define IKED_POLICY_REFCNT 0x04 #define IKED_POLICY_QUICK 0x08 #define IKED_POLICY_SKIP 0x10 +#define IKED_POLICY_IPCOMP 0x20 int pol_refcnt; + u_int8_t pol_certreqtype; + int pol_af; u_int8_t pol_saproto; u_int pol_ipproto; @@ -267,7 +272,8 @@ struct iked_policy { struct iked_cfg pol_cfg[IKED_CFG_MAX]; u_int pol_ncfg; - struct iked_lifetime pol_lifetime; + u_int32_t pol_rekey; /* ike SA lifetime */ + struct iked_lifetime pol_lifetime; /* child SA lifetime */ struct iked_sapeers pol_sapeers; @@ -317,15 +323,16 @@ struct iked_id { }; #define IKED_REQ_CERT 0x01 /* get local certificate (if required) */ -#define IKED_REQ_VALID 0x02 /* validate the peer cert */ +#define IKED_REQ_CERTVALID 0x02 /* validated the peer cert */ #define IKED_REQ_AUTH 0x04 /* AUTH payload */ -#define IKED_REQ_SA 0x08 /* SA available */ -#define IKED_REQ_CHILDSA 0x10 /* Child SA initiated */ -#define IKED_REQ_INF 0x20 /* Informational exchange initiated */ -#define IKED_REQ_DELETE 0x40 /* Rekeying continuation */ +#define IKED_REQ_AUTHVALID 0x08 /* AUTH payload has been verified */ +#define IKED_REQ_SA 0x10 /* SA available */ +#define IKED_REQ_EAPVALID 0x20 /* EAP payload has been verified */ +#define IKED_REQ_CHILDSA 0x40 /* Child SA initiated */ +#define IKED_REQ_INF 0x80 /* Informational exchange initiated */ #define IKED_REQ_BITS \ - "\10\01CERT\02VALID\03AUTH\04SA" + "\20\01CERT\02CERTVALID\03AUTH\04AUTHVALID\05SA\06EAP" TAILQ_HEAD(iked_msgqueue, iked_message); @@ -335,17 +342,27 @@ struct iked_sahdr { u_int sh_initiator; /* Is initiator? */ } __packed; +struct iked_kex { + struct ibuf *kex_inonce; /* Ni */ + struct ibuf *kex_rnonce; /* Nr */ + + struct group *kex_dhgroup; /* DH group */ + struct ibuf *kex_dhiexchange; + struct ibuf *kex_dhrexchange; + struct ibuf *kex_dhpeer; /* pointer to i or r */ +}; + struct iked_sa { struct iked_sahdr sa_hdr; - u_int32_t sa_msgid; - u_int32_t sa_reqid; + u_int32_t sa_msgid; /* Last request rcvd */ + int sa_msgid_set; /* msgid initialized */ + u_int32_t sa_reqid; /* Next request sent */ int sa_type; #define IKED_SATYPE_LOOKUP 0 /* Used for lookup */ #define IKED_SATYPE_LOCAL 1 /* Local SA */ struct iked_addr sa_peer; - struct iked_addr sa_polpeer; struct iked_addr sa_local; int sa_fd; @@ -365,13 +382,14 @@ struct iked_sa { char *sa_tag; - struct ibuf *sa_inonce; /* Ni */ - struct ibuf *sa_rnonce; /* Nr */ - - struct group *sa_dhgroup; /* DH group */ - struct ibuf *sa_dhiexchange; - struct ibuf *sa_dhrexchange; - struct ibuf *sa_dhpeer; /* pointer to i or r */ + struct iked_kex sa_kex; +/* XXX compat defines until everything is converted */ +#define sa_inonce sa_kex.kex_inonce +#define sa_rnonce sa_kex.kex_rnonce +#define sa_dhgroup sa_kex.kex_dhgroup +#define sa_dhiexchange sa_kex.kex_dhiexchange +#define sa_dhrexchange sa_kex.kex_dhrexchange +#define sa_dhpeer sa_kex.kex_dhpeer struct iked_hash *sa_prf; /* PRF alg */ struct iked_hash *sa_integr; /* integrity alg */ @@ -388,11 +406,14 @@ struct iked_sa { struct ibuf *sa_1stmsg; /* for initiator AUTH */ struct ibuf *sa_2ndmsg; /* for responder AUTH */ struct iked_id sa_localauth; /* local AUTH message */ + int sa_sigsha2; /* use SHA2 for signatures */ struct iked_id sa_iid; /* initiator id */ struct iked_id sa_rid; /* responder id */ struct iked_id sa_icert; /* initiator cert */ struct iked_id sa_rcert; /* responder cert */ +#define IKESA_SRCID(x) ((x)->sa_hdr.sh_initiator ? &(x)->sa_iid : &(x)->sa_rid) +#define IKESA_DSTID(x) ((x)->sa_hdr.sh_initiator ? &(x)->sa_rid : &(x)->sa_iid) char *sa_eapid; /* EAP identity */ struct iked_id sa_eap; /* EAP challenge */ @@ -402,8 +423,18 @@ struct iked_sa { struct iked_childsas sa_childsas; /* IPSec Child SAs */ struct iked_saflows sa_flows; /* IPSec flows */ + struct iked_sa *sa_next; /* IKE SA rekeying */ + u_int64_t sa_rekeyspi; /* peerspi for rekey*/ + + u_int8_t sa_ipcomp; /* IPcomp transform */ + u_int16_t sa_cpi_out; /* IPcomp outgoing */ + u_int16_t sa_cpi_in; /* IPcomp incoming*/ + struct iked_timer sa_timer; /* SA timeouts */ -#define IKED_IKE_SA_REKEY_TIMEOUT 300 /* 5 minutes */ +#define IKED_IKE_SA_DELETE_TIMEOUT 300 /* 5 minutes */ +#define IKED_IKE_SA_ALIVE_TIMEOUT 60 /* 1 minute */ + + struct iked_timer sa_rekey; /* rekey timeout */ struct iked_msgqueue sa_requests; /* request queue */ #define IKED_RETRANSMIT_TIMEOUT 2 /* 2 seconds */ @@ -411,14 +442,18 @@ struct iked_sa { struct iked_msgqueue sa_responses; /* response queue */ #define IKED_RESPONSE_TIMEOUT 120 /* 2 minutes */ - RB_ENTRY(iked_sa) sa_peer_entry; + TAILQ_ENTRY(iked_sa) sa_peer_entry; RB_ENTRY(iked_sa) sa_entry; + + struct iked_addr *sa_addrpool; /* address from pool */ + RB_ENTRY(iked_sa) sa_addrpool_entry; /* pool entries */ }; RB_HEAD(iked_sas, iked_sa); +RB_HEAD(iked_addrpool, iked_sa); struct iked_message { struct ibuf *msg_data; - off_t msg_offset; + size_t msg_offset; struct sockaddr_storage msg_local; socklen_t msg_locallen; @@ -430,6 +465,7 @@ struct iked_message { int msg_fd; int msg_response; + int msg_responded; int msg_natt; int msg_error; int msg_e; @@ -464,20 +500,32 @@ struct iked_message { }; struct iked_user { - char usr_name[MAXLOGNAME]; + char usr_name[LOGIN_NAME_MAX]; char usr_pass[IKED_PASSWORD_SIZE]; RB_ENTRY(iked_user) usr_entry; }; RB_HEAD(iked_users, iked_user); +struct privsep_pipes { + int *pp_pipes[PROC_MAX]; +}; + struct privsep { - int ps_pipes[PROC_MAX][PROC_MAX]; - struct imsgev ps_ievs[PROC_MAX]; + struct privsep_pipes *ps_pipes[PROC_MAX]; + struct privsep_pipes *ps_pp; + + struct imsgev *ps_ievs[PROC_MAX]; const char *ps_title[PROC_MAX]; pid_t ps_pid[PROC_MAX]; struct passwd *ps_pw; + int ps_noaction; struct control_sock ps_csock; + struct control_socks ps_rcsocks; + + u_int ps_instances[PROC_MAX]; + u_int ps_ninstances; + u_int ps_instance; /* Event and signal handlers */ struct event ps_evsigint; @@ -485,6 +533,7 @@ struct privsep { struct event ps_evsigchld; struct event ps_evsighup; struct event ps_evsigpipe; + struct event ps_evsigusr1; struct iked *ps_env; }; @@ -499,14 +548,22 @@ struct privsep_proc { const char *p_chroot; struct privsep *p_ps; struct iked *p_env; + void (*p_shutdown)(void); + u_int p_instance; +}; + +struct iked_ocsp_entry { + TAILQ_ENTRY(iked_ocsp_entry) ioe_entry; /* next request */ + void *ioe_ocsp; /* private ocsp request data */ }; +TAILQ_HEAD(iked_ocsp_requests, iked_ocsp_entry); /* * Daemon configuration */ struct iked { - char sc_conffile[MAXPATHLEN]; + char sc_conffile[PATH_MAX]; u_int32_t sc_opts; u_int8_t sc_passive; @@ -535,6 +592,11 @@ struct iked { #define IKED_INITIATOR_INTERVAL 60 struct privsep sc_ps; + + struct iked_ocsp_requests sc_ocsp; + char *sc_ocsp_url; + + struct iked_addrpool sc_addrpool; }; struct iked_socket { @@ -555,6 +617,7 @@ void control_cleanup(struct control_sock *); /* config.c */ struct iked_policy * config_new_policy(struct iked *); +void config_free_kex(struct iked_kex *); void config_free_sa(struct iked *, struct iked_sa *); struct iked_sa * config_new_sa(struct iked *, int); @@ -563,7 +626,7 @@ struct iked_user * u_int64_t config_getspi(void); struct iked_transform * - config_findtransform(struct iked_proposals *, u_int8_t); + config_findtransform(struct iked_proposals *, u_int8_t, u_int); void config_free_policy(struct iked *, struct iked_policy *); struct iked_proposal * config_add_proposal(struct iked_proposals *, u_int, u_int); @@ -593,6 +656,8 @@ int config_setuser(struct iked *, struct iked_user *, enum privsep_procid); int config_getuser(struct iked *, struct imsg *); int config_setcompile(struct iked *, enum privsep_procid); int config_getcompile(struct iked *, struct imsg *); +int config_setocsp(struct iked *); +int config_getocsp(struct iked *, struct imsg *); /* policy.c */ void policy_init(struct iked *); @@ -611,19 +676,17 @@ struct iked_sa * void sa_free(struct iked *, struct iked_sa *); void sa_free_flows(struct iked *, struct iked_saflows *); int sa_address(struct iked_sa *, struct iked_addr *, - struct sockaddr_storage *, int); + struct sockaddr_storage *); void childsa_free(struct iked_childsa *); struct iked_childsa * childsa_lookup(struct iked_sa *, u_int64_t, u_int8_t); void flow_free(struct iked_flow *); struct iked_sa * sa_lookup(struct iked *, u_int64_t, u_int64_t, u_int); -struct iked_sa * - sa_peer_lookup(struct iked_policy *, struct sockaddr_storage *); struct iked_user * user_lookup(struct iked *, const char *); RB_PROTOTYPE(iked_sas, iked_sa, sa_entry, sa_cmp); -RB_PROTOTYPE(iked_sapeers, iked_sa, sa_peer_entry, sa_peer_cmp); +RB_PROTOTYPE(iked_addrpool, iked_sa, sa_addrpool_entry, sa_addrpool_cmp); RB_PROTOTYPE(iked_users, iked_user, user_entry, user_cmp); RB_PROTOTYPE(iked_activesas, iked_childsa, csa_node, childsa_cmp); RB_PROTOTYPE(iked_flows, iked_flow, flow_node, flow_cmp); @@ -666,7 +729,7 @@ struct iked_dsa * struct ibuf * dsa_setkey(struct iked_dsa *, void *, size_t, u_int8_t); void dsa_free(struct iked_dsa *); -int dsa_init(struct iked_dsa *); +int dsa_init(struct iked_dsa *, const void *, size_t); size_t dsa_length(struct iked_dsa *); int dsa_update(struct iked_dsa *, const void *, size_t); ssize_t dsa_sign_final(struct iked_dsa *, void *, size_t); @@ -679,7 +742,7 @@ pid_t ikev1(struct privsep *, struct privsep_proc *); pid_t ikev2(struct privsep *, struct privsep_proc *); void ikev2_recv(struct iked *, struct iked_message *); void ikev2_init_ike_sa(struct iked *, void *); -int ikev2_sa_negotiate(struct iked_sa *, struct iked_proposals *, +int ikev2_sa_negotiate(struct iked_proposals *, struct iked_proposals *, struct iked_proposals *); int ikev2_policy2id(struct iked_static_id *, struct iked_id *, int); int ikev2_childsa_enable(struct iked *, struct iked_sa *); @@ -703,10 +766,10 @@ struct ikev2_payload * ikev2_add_payload(struct ibuf *); int ikev2_next_payload(struct ikev2_payload *, size_t, u_int8_t); -void ikev2_acquire_sa(struct iked *, struct iked_flow *); +int ikev2_acquire_sa(struct iked *, struct iked_flow *); void ikev2_disable_rekeying(struct iked *, struct iked_sa *); -void ikev2_rekey_sa(struct iked *, struct iked_spi *); -void ikev2_drop_sa(struct iked *, struct iked_spi *); +int ikev2_rekey_sa(struct iked *, struct iked_spi *); +int ikev2_drop_sa(struct iked *, struct iked_spi *); int ikev2_print_id(struct iked_id *, char *, size_t); /* ikev2_msg.c */ @@ -753,7 +816,7 @@ struct iked_message * /* ikev2_pld.c */ int ikev2_pld_parse(struct iked *, struct ike_header *, - struct iked_message *, off_t); + struct iked_message *, size_t); /* eap.c */ ssize_t eap_identity_request(struct ibuf *); @@ -767,7 +830,8 @@ int pfkey_block(int, int, u_int); int pfkey_sa_init(int, struct iked_childsa *, u_int32_t *); int pfkey_sa_add(int, struct iked_childsa *, struct iked_childsa *); int pfkey_sa_delete(int, struct iked_childsa *); -int pfkey_flush(int, u_int); +int pfkey_sa_last_used(int, struct iked_childsa *, u_int64_t *); +int pfkey_flush(int); int pfkey_socket(void); void pfkey_init(struct iked *, int fd); @@ -780,43 +844,47 @@ int ca_setcert(struct iked *, struct iked_sahdr *, struct iked_id *, int ca_setauth(struct iked *, struct iked_sa *, struct ibuf *, enum privsep_procid); void ca_sslinit(void); -void ca_sslerror(void); +void ca_sslerror(const char *); char *ca_asn1_name(u_int8_t *, size_t); char *ca_x509_name(void *); +void *ca_x509_name_parse(char *); /* timer.c */ -void timer_initialize(struct iked *, struct iked_timer *, +void timer_set(struct iked *, struct iked_timer *, void (*)(struct iked *, void *), void *); -int timer_initialized(struct iked *, struct iked_timer *); -void timer_register(struct iked *, struct iked_timer *, int); -void timer_deregister(struct iked *, struct iked_timer *); +void timer_add(struct iked *, struct iked_timer *, int); +void timer_del(struct iked *, struct iked_timer *); /* proc.c */ void proc_init(struct privsep *, struct privsep_proc *, u_int); void proc_kill(struct privsep *); -void proc_config(struct privsep *, struct privsep_proc *, u_int); +void proc_listen(struct privsep *, struct privsep_proc *, size_t); void proc_dispatch(int, short event, void *); pid_t proc_run(struct privsep *, struct privsep_proc *, struct privsep_proc *, u_int, - void (*)(struct privsep *, void *), void *); + void (*)(struct privsep *, struct privsep_proc *, void *), void *); void imsg_event_add(struct imsgev *); int imsg_compose_event(struct imsgev *, u_int16_t, u_int32_t, pid_t, int, void *, u_int16_t); int imsg_composev_event(struct imsgev *, u_int16_t, u_int32_t, pid_t, int, const struct iovec *, int); -int proc_compose_imsg(struct iked *, enum privsep_procid, +int proc_compose_imsg(struct privsep *, enum privsep_procid, int, u_int16_t, int, void *, u_int16_t); -int proc_composev_imsg(struct iked *, enum privsep_procid, +int proc_composev_imsg(struct privsep *, enum privsep_procid, int, u_int16_t, int, const struct iovec *, int); -int proc_forward_imsg(struct iked *, struct imsg *, - enum privsep_procid); -void proc_flush_imsg(struct iked *, enum privsep_procid); +int proc_forward_imsg(struct privsep *, struct imsg *, + enum privsep_procid, int); +struct imsgbuf * + proc_ibuf(struct privsep *, enum privsep_procid, int); +struct imsgev * + proc_iev(struct privsep *, enum privsep_procid, int); /* util.c */ void socket_set_blockmode(int, enum blockmodes); int socket_af(struct sockaddr *, in_port_t); in_port_t - socket_getport(struct sockaddr_storage *); + socket_getport(struct sockaddr *); +int socket_setport(struct sockaddr *, in_port_t); int socket_getaddr(int, struct sockaddr_storage *); int socket_bypass(int, struct sockaddr *); int udp_bind(struct sockaddr *, in_port_t); @@ -830,7 +898,7 @@ void lc_string(char *); void print_hex(u_int8_t *, off_t, size_t); void print_hexval(u_int8_t *, off_t, size_t); const char * - print_bits(u_short, char *); + print_bits(u_short, u_char *); int sockaddr_cmp(struct sockaddr *, struct sockaddr *, int); u_int8_t mask2prefixlen(struct sockaddr *); u_int8_t mask2prefixlen6(struct sockaddr *); @@ -839,7 +907,7 @@ struct in6_addr * u_int32_t prefixlen2mask(u_int8_t); const char * - print_host(struct sockaddr_storage *, char *, size_t); + print_host(struct sockaddr *, char *, size_t); char *get_string(u_int8_t *, size_t); const char * print_proto(u_int8_t); @@ -871,15 +939,21 @@ void ibuf_zero(struct ibuf *); /* log.c */ void log_init(int); void log_verbose(int); -void log_warn(const char *, ...); -void log_warnx(const char *, ...); -void log_info(const char *, ...); -void log_debug(const char *, ...); -void print_debug(const char *, ...); -void print_verbose(const char *, ...); +void log_warn(const char *, ...) __attribute__((format(printf, 1, 2))); +void log_warnx(const char *, ...) __attribute__((format(printf, 1, 2))); +void log_info(const char *, ...) __attribute__((format(printf, 1, 2))); +void log_debug(const char *, ...) __attribute__((format(printf, 1, 2))); +void print_debug(const char *, ...) __attribute__((format(printf, 1, 2))); +void print_verbose(const char *, ...) __attribute__((format(printf, 1, 2))); __dead void fatal(const char *); __dead void fatalx(const char *); +/* ocsp.c */ +int ocsp_connect(struct iked *env); +int ocsp_receive_fd(struct iked *, struct imsg *); +int ocsp_validate_cert(struct iked *, struct iked_static_id *, + void *, size_t, struct iked_sahdr, u_int8_t); + /* parse.y */ int parse_config(const char *, struct iked *); void print_user(struct iked_user *); @@ -888,4 +962,4 @@ size_t keylength_xf(u_int, u_int, u_int); size_t noncelength_xf(u_int, u_int); int cmdline_symset(char *); -#endif /* _IKED_H */ +#endif /* IKED_H */ diff --git a/iked/ikev1.c b/iked/ikev1.c index fc4f6b2..7d10e86 100644 --- a/iked/ikev1.c +++ b/iked/ikev1.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev1.c,v 1.13 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: ikev1.c,v 1.17 2015/02/06 10:39:01 deraadt Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -22,8 +22,7 @@ * XXX or remove this file and ikev1 from the iked tree. */ -#include -#include "openbsd-compat/sys-queue.h" +#include #include #include #include @@ -32,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -108,7 +106,7 @@ ikev1_dispatch_ikev2(int fd, struct privsep_proc *p, struct imsg *imsg) return (0); } - log_debug("%s: message length %d", __func__, len); + log_debug("%s: message length %zd", __func__, len); ikev1_recv(env, &msg); ikev2_msg_cleanup(env, &msg); @@ -158,8 +156,8 @@ ikev1_msg_cb(int fd, short event, void *arg) iov[1].iov_base = buf; iov[1].iov_len = len; - proc_composev_imsg(env, PROC_IKEV2, IMSG_IKE_MESSAGE, -1, - iov, 2); + proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, + IMSG_IKE_MESSAGE, -1, iov, 2); goto done; } diff --git a/iked/ikev2.c b/iked/ikev2.c index a24af78..7b676e6 100644 --- a/iked/ikev2.c +++ b/iked/ikev2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.c,v 1.82 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: ikev2.c,v 1.121 2015/07/07 19:13:31 markus Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,24 +16,20 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include /* roundup */ +#include #include #include #include -#include #include -#if defined(__OpenBSD__) #include -#endif #include #include #include #include #include -#include #include #include #include @@ -42,6 +38,7 @@ #include #include +#include #include "iked.h" #include "ikev2.h" @@ -57,8 +54,10 @@ struct iked_sa * u_int8_t *, u_int8_t **, size_t *); void ikev2_recv(struct iked *, struct iked_message *); -int ikev2_ike_auth(struct iked *, struct iked_sa *, +int ikev2_ike_auth_compatible(struct iked_sa *, u_int8_t, u_int8_t); +int ikev2_ike_auth_recv(struct iked *, struct iked_sa *, struct iked_message *); +int ikev2_ike_auth(struct iked *, struct iked_sa *); void ikev2_init_recv(struct iked *, struct iked_message *, struct ike_header *); @@ -76,18 +75,28 @@ int ikev2_resp_ike_eap(struct iked *, struct iked_sa *, struct ibuf *); int ikev2_send_create_child_sa(struct iked *, struct iked_sa *, struct iked_spi *, u_int8_t); +int ikev2_ikesa_enable(struct iked *, struct iked_sa *, struct iked_sa *); +void ikev2_ikesa_delete(struct iked *, struct iked_sa *, int); int ikev2_init_create_child_sa(struct iked *, struct iked_message *); int ikev2_resp_create_child_sa(struct iked *, struct iked_message *); +void ikev2_ike_sa_rekey(struct iked *, void *); void ikev2_ike_sa_timeout(struct iked *env, void *); +void ikev2_ike_sa_alive(struct iked *, void *); int ikev2_sa_initiator(struct iked *, struct iked_sa *, - struct iked_message *); + struct iked_sa *, struct iked_message *); int ikev2_sa_responder(struct iked *, struct iked_sa *, struct iked_sa *, struct iked_message *); +int ikev2_sa_initiator_dh(struct iked_sa *, struct iked_message *, u_int); +int ikev2_sa_responder_dh(struct iked_kex *, struct iked_proposals *, + struct iked_message *, u_int); +void ikev2_sa_cleanup_dh(struct iked_sa *); int ikev2_sa_keys(struct iked *, struct iked_sa *, struct ibuf *); int ikev2_sa_tag(struct iked_sa *, struct iked_id *); +int ikev2_set_sa_proposal(struct iked_sa *, struct iked_policy *, u_int); -int ikev2_childsa_negotiate(struct iked *, struct iked_sa *, int); +int ikev2_childsa_negotiate(struct iked *, struct iked_sa *, + struct iked_kex *, struct iked_proposals *, int, int); int ikev2_match_proposals(struct iked_proposal *, struct iked_proposal *, struct iked_transform **); int ikev2_valid_proposal(struct iked_proposal *, @@ -100,10 +109,24 @@ ssize_t ikev2_add_transform(struct ibuf *, u_int8_t, u_int8_t, u_int16_t, u_int16_t); ssize_t ikev2_add_ts(struct ibuf *, struct ikev2_payload **, ssize_t, struct iked_sa *, int); +ssize_t ikev2_add_certreq(struct ibuf *, struct ikev2_payload **, ssize_t, + struct ibuf *, u_int8_t); +ssize_t ikev2_add_ipcompnotify(struct iked *, struct ibuf *, + struct ikev2_payload **, ssize_t, struct iked_sa *); ssize_t ikev2_add_ts_payload(struct ibuf *, u_int, struct iked_sa *); int ikev2_add_data(struct ibuf *, void *, size_t); int ikev2_add_buf(struct ibuf *buf, struct ibuf *); +int ikev2_ipcomp_enable(struct iked *, struct iked_sa *); +void ikev2_ipcomp_csa_free(struct iked *, struct iked_childsa *); + +int ikev2_cp_setaddr(struct iked *, struct iked_sa *); +int ikev2_cp_fixaddr(struct iked_sa *, struct iked_addr *, + struct iked_addr *); + +ssize_t ikev2_add_sighashnotify(struct ibuf *, struct ikev2_payload **, + ssize_t); + static struct privsep_proc procs[] = { { "parent", PROC_PARENT, ikev2_dispatch_parent }, { "ikev1", PROC_IKEV1, ikev2_dispatch_ikev1 }, @@ -131,9 +154,9 @@ ikev2_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) case IMSG_CTL_PASSIVE: if (config_getmode(env, imsg->hdr.type) == -1) return (0); /* ignore error */ - timer_initialize(env, &env->sc_inittmr, ikev2_init_ike_sa, + timer_set(env, &env->sc_inittmr, ikev2_init_ike_sa, NULL); - timer_register(env, &env->sc_inittmr, IKED_INITIATOR_INITIAL); + timer_add(env, &env->sc_inittmr, IKED_INITIATOR_INITIAL); return (0); case IMSG_UDP_SOCKET: return (config_getsocket(env, imsg, ikev2_msg_cb)); @@ -173,7 +196,7 @@ ikev2_dispatch_ikev1(int fd, struct privsep_proc *p, struct imsg *imsg) return (0); } - log_debug("%s: message length %d", __func__, len); + log_debug("%s: message length %zd", __func__, len); ikev2_recv(env, &msg); ikev2_msg_cleanup(env, &msg); @@ -195,6 +218,7 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) u_int8_t *ptr; size_t len; struct iked_id *id = NULL; + int ignore = 0; switch (imsg->hdr.type) { case IMSG_CERTREQ: @@ -209,8 +233,9 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) env->sc_certreq = ibuf_new(ptr, IMSG_DATA_SIZE(imsg) - sizeof(type)); - log_debug("%s: updated local CERTREQ signatures length %d", - __func__, ibuf_length(env->sc_certreq)); + log_debug("%s: updated local CERTREQ type %s length %zu", + __func__, print_map(type, ikev2_cert_map), + ibuf_length(env->sc_certreq)); break; case IMSG_CERTVALID: @@ -227,13 +252,12 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) if (imsg->hdr.type == IMSG_CERTVALID) { log_debug("%s: peer certificate is valid", __func__); - sa_stateflags(sa, IKED_REQ_VALID); - sa_state(env, sa, IKEV2_STATE_VALID); + sa_stateflags(sa, IKED_REQ_CERTVALID); } else { log_warnx("%s: peer certificate is invalid", __func__); } - if (ikev2_ike_auth(env, sa, NULL) != 0) + if (ikev2_ike_auth(env, sa) != 0) log_debug("%s: failed to send ike auth", __func__); break; case IMSG_CERT: @@ -243,6 +267,21 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) break; } + /* + * Ignore the message if we already got a valid certificate. + * This might happen if the peer sent multiple CERTREQs. + */ + if (sa->sa_stateflags & IKED_REQ_CERT || + type == IKEV2_CERT_NONE) + ignore = 1; + + log_debug("%s: cert type %s length %zu, %s", __func__, + print_map(type, ikev2_cert_map), len, + ignore ? "ignored" : "ok"); + + if (ignore) + break; + if (sh.sh_initiator) id = &sa->sa_icert; else @@ -253,21 +292,15 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) ibuf_release(id->id_buf); id->id_buf = NULL; - if (type != IKEV2_CERT_NONE) { - if (len <= 0 || - (id->id_buf = ibuf_new(ptr, len)) == NULL) { - log_debug("%s: failed to get cert payload", - __func__); - break; - } + if (len <= 0 || (id->id_buf = ibuf_new(ptr, len)) == NULL) { + log_debug("%s: failed to get cert payload", + __func__); + break; } - log_debug("%s: cert type %d length %d", __func__, - id->id_type, ibuf_length(id->id_buf)); - sa_stateflags(sa, IKED_REQ_CERT); - if (ikev2_ike_auth(env, sa, NULL) != 0) + if (ikev2_ike_auth(env, sa) != 0) log_debug("%s: failed to send ike auth", __func__); break; case IMSG_AUTH: @@ -276,8 +309,13 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) log_debug("%s: invalid auth reply", __func__); break; } + if (sa_stateok(sa, IKEV2_STATE_VALID)) { + log_warnx("%s: ignoring AUTH in state %s", __func__, + print_map(sa->sa_state, ikev2_state_map)); + break; + } - log_debug("%s: AUTH type %d len %d", __func__, type, len); + log_debug("%s: AUTH type %d len %zu", __func__, type, len); id = &sa->sa_localauth; id->id_type = type; @@ -295,7 +333,7 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) sa_stateflags(sa, IKED_REQ_AUTH); - if (ikev2_ike_auth(env, sa, NULL) != 0) + if (ikev2_ike_auth(env, sa) != 0) log_debug("%s: failed to send ike auth", __func__); break; default: @@ -323,7 +361,7 @@ ikev2_getimsgdata(struct iked *env, struct imsg *imsg, struct iked_sahdr *sh, sa = sa_lookup(env, sh->sh_ispi, sh->sh_rspi, sh->sh_initiator); log_debug("%s: imsg %d rspi %s ispi %s initiator %d sa %s" - " type %d data length %d", + " type %d data length %zd", __func__, imsg->hdr.type, print_spi(sh->sh_rspi, 8), print_spi(sh->sh_ispi, 8), @@ -346,16 +384,15 @@ ikev2_recv(struct iked *env, struct iked_message *msg) struct iked_message *m; struct iked_sa *sa; u_int initiator, flag = 0; - int response; hdr = ibuf_seek(msg->msg_data, msg->msg_offset, sizeof(*hdr)); - if (hdr == NULL || (ssize_t)ibuf_size(msg->msg_data) < + if (hdr == NULL || ibuf_size(msg->msg_data) < (betoh32(hdr->ike_length) - msg->msg_offset)) return; initiator = (hdr->ike_flags & IKEV2_FLAG_INITIATOR) ? 0 : 1; - response = (hdr->ike_flags & IKEV2_FLAG_RESPONSE) ? 1 : 0; + msg->msg_response = (hdr->ike_flags & IKEV2_FLAG_RESPONSE) ? 1 : 0; msg->msg_sa = sa_lookup(env, betoh64(hdr->ike_ispi), betoh64(hdr->ike_rspi), initiator); @@ -363,11 +400,12 @@ ikev2_recv(struct iked *env, struct iked_message *msg) if (policy_lookup(env, msg) != 0) return; - log_info("%s: %s from %s %s to %s policy '%s' id %u, %ld bytes", + log_info("%s: %s %s from %s %s to %s policy '%s' id %u, %ld bytes", __func__, print_map(hdr->ike_exchange, ikev2_exchange_map), + msg->msg_response ? "response" : "request", initiator ? "responder" : "initiator", - print_host(&msg->msg_peer, NULL, 0), - print_host(&msg->msg_local, NULL, 0), + print_host((struct sockaddr *)&msg->msg_peer, NULL, 0), + print_host((struct sockaddr *)&msg->msg_local, NULL, 0), msg->msg_policy->pol_name, msg->msg_msgid, ibuf_length(msg->msg_data)); log_debug("%s: ispi %s rspi %s", __func__, @@ -382,7 +420,7 @@ ikev2_recv(struct iked *env, struct iked_message *msg) if (hdr->ike_exchange == IKEV2_EXCHANGE_INFORMATIONAL) flag = IKED_REQ_INF; - if (response) { + if (msg->msg_response) { if (msg->msg_msgid > sa->sa_reqid) return; if (hdr->ike_exchange != IKEV2_EXCHANGE_INFORMATIONAL && @@ -391,6 +429,10 @@ ikev2_recv(struct iked *env, struct iked_message *msg) if (flag) { if ((sa->sa_stateflags & flag) == 0) return; + /* + * We have initiated this exchange, even if + * we are not the initiator of the IKE SA. + */ initiator = 1; } /* @@ -413,24 +455,33 @@ ikev2_recv(struct iked *env, struct iked_message *msg) sa_free(env, sa); } return; + } else if (sa->sa_msgid_set && msg->msg_msgid == sa->sa_msgid) { + /* + * Response is being worked on, most likely we're + * waiting for the CA process to get back to us + */ + return; } /* * If it's a new request, make sure to update the peer's - * message ID and dispose of all previous responses + * message ID and dispose of all previous responses. + * We need to set sa_msgid_set in order to distinguish between + * "last msgid was 0" and "msgid not set yet". */ sa->sa_msgid = msg->msg_msgid; + sa->sa_msgid_set = 1; ikev2_msg_prevail(env, &sa->sa_responses, msg); } - if (sa_address(sa, &sa->sa_peer, &msg->msg_peer, initiator) == -1 || - sa_address(sa, &sa->sa_local, &msg->msg_local, initiator) == -1) + if (sa_address(sa, &sa->sa_peer, &msg->msg_peer) == -1 || + sa_address(sa, &sa->sa_local, &msg->msg_local) == -1) return; sa->sa_fd = msg->msg_fd; log_debug("%s: updated SA to peer %s local %s", __func__, - print_host(&sa->sa_peer.addr, NULL, 0), - print_host(&sa->sa_local.addr, NULL, 0)); + print_host((struct sockaddr *)&sa->sa_peer.addr, NULL, 0), + print_host((struct sockaddr *)&sa->sa_local.addr, NULL, 0)); done: if (initiator) @@ -445,7 +496,18 @@ ikev2_recv(struct iked *env, struct iked_message *msg) } int -ikev2_ike_auth(struct iked *env, struct iked_sa *sa, +ikev2_ike_auth_compatible(struct iked_sa *sa, u_int8_t want, u_int8_t have) +{ + if (want == have) + return (0); + if (sa->sa_sigsha2 && + have == IKEV2_AUTH_SIG && want == IKEV2_AUTH_RSA_SIG) + return (0); + return (-1); +} + +int +ikev2_ike_auth_recv(struct iked *env, struct iked_sa *sa, struct iked_message *msg) { struct iked_id *id, *certid; @@ -454,9 +516,6 @@ ikev2_ike_auth(struct iked *env, struct iked_sa *sa, struct iked_policy *policy = sa->sa_policy; int ret = -1; - if (msg == NULL) - goto done; - if (sa->sa_hdr.sh_initiator) { id = &sa->sa_rid; certid = &sa->sa_rcert; @@ -464,20 +523,38 @@ ikev2_ike_auth(struct iked *env, struct iked_sa *sa, id = &sa->sa_iid; certid = &sa->sa_icert; } + /* try to relookup the policy based on the peerid */ + if (msg->msg_id.id_type && !sa->sa_hdr.sh_initiator) { + struct iked_policy *old = sa->sa_policy; + + sa->sa_policy = NULL; + if (policy_lookup(env, msg) == 0 && msg->msg_policy && + msg->msg_policy != old) { + /* move sa to new policy */ + policy = sa->sa_policy = msg->msg_policy; + TAILQ_REMOVE(&old->pol_sapeers, sa, sa_peer_entry); + TAILQ_INSERT_TAIL(&policy->pol_sapeers, sa, sa_peer_entry); + } else { + /* restore */ + msg->msg_policy = sa->sa_policy = old; + } + } if (msg->msg_id.id_type) { memcpy(id, &msg->msg_id, sizeof(*id)); bzero(&msg->msg_id, sizeof(msg->msg_id)); - if ((authmsg = ikev2_msg_auth(env, sa, - !sa->sa_hdr.sh_initiator)) == NULL) { - log_debug("%s: failed to get response " - "auth data", __func__); - return (-1); - } + if (!sa->sa_hdr.sh_initiator) { + if ((authmsg = ikev2_msg_auth(env, sa, + !sa->sa_hdr.sh_initiator)) == NULL) { + log_debug("%s: failed to get response " + "auth data", __func__); + return (-1); + } - ca_setauth(env, sa, authmsg, PROC_CERT); - ibuf_release(authmsg); + ca_setauth(env, sa, authmsg, PROC_CERT); + ibuf_release(authmsg); + } } if (msg->msg_cert.id_type) { @@ -506,11 +583,13 @@ ikev2_ike_auth(struct iked *env, struct iked_sa *sa, ikeauth.auth_length = ibuf_size(sa->sa_eapmsk); } - if (msg->msg_auth.id_type != ikeauth.auth_method) { + if (ikev2_ike_auth_compatible(sa, + ikeauth.auth_method, msg->msg_auth.id_type) < 0) { log_warnx("%s: unexpected auth method %s", __func__, - print_map(ikeauth.auth_method, ikev2_auth_map)); + print_map(msg->msg_auth.id_type, ikev2_auth_map)); return (-1); } + ikeauth.auth_method = msg->msg_auth.id_type; if ((authmsg = ikev2_msg_auth(env, sa, sa->sa_hdr.sh_initiator)) == NULL) { @@ -524,8 +603,10 @@ ikev2_ike_auth(struct iked *env, struct iked_sa *sa, authmsg); ibuf_release(authmsg); - if (ret != 0) - goto done; + if (ret != 0) { + log_debug("%s: ikev2_msg_authverify failed", __func__); + return (-1); + } if (sa->sa_eapmsk != NULL) { if ((authmsg = ikev2_msg_auth(env, sa, @@ -544,13 +625,17 @@ ikev2_ike_auth(struct iked *env, struct iked_sa *sa, return (-1); } - sa_state(env, sa, IKEV2_STATE_EAP_VALID); + /* ikev2_msg_authverify verified AUTH */ + sa_stateflags(sa, IKED_REQ_AUTHVALID); + sa_stateflags(sa, IKED_REQ_EAPVALID); + + sa_state(env, sa, IKEV2_STATE_EAP_SUCCESS); } } if (!TAILQ_EMPTY(&msg->msg_proposals)) { - if (ikev2_sa_negotiate(sa, &sa->sa_policy->pol_proposals, - &msg->msg_proposals) != 0) { + if (ikev2_sa_negotiate(&sa->sa_proposals, + &sa->sa_policy->pol_proposals, &msg->msg_proposals) != 0) { log_debug("%s: no proposal chosen", __func__); msg->msg_error = IKEV2_N_NO_PROPOSAL_CHOSEN; return (-1); @@ -558,7 +643,18 @@ ikev2_ike_auth(struct iked *env, struct iked_sa *sa, sa_stateflags(sa, IKED_REQ_SA); } - done: + return ikev2_ike_auth(env, sa); +} + +int +ikev2_ike_auth(struct iked *env, struct iked_sa *sa) +{ + /* Attempt state transition */ + if (sa->sa_state == IKEV2_STATE_EAP_SUCCESS) + sa_state(env, sa, IKEV2_STATE_EAP_VALID); + else if (sa->sa_state == IKEV2_STATE_AUTH_SUCCESS) + sa_state(env, sa, IKEV2_STATE_VALID); + if (sa->sa_hdr.sh_initiator) { if (sa_stateok(sa, IKEV2_STATE_AUTH_SUCCESS)) return (ikev2_init_done(env, sa)); @@ -589,7 +685,8 @@ ikev2_init_recv(struct iked *env, struct iked_message *msg, betoh64(hdr->ike_ispi), betoh64(hdr->ike_rspi), 1, NULL)) == NULL || sa != msg->msg_sa) { log_debug("%s: invalid new SA", __func__); - sa_free(env, sa); + if (sa) + sa_free(env, sa); } break; case IKEV2_EXCHANGE_IKE_AUTH: @@ -620,7 +717,8 @@ ikev2_init_recv(struct iked *env, struct iked_message *msg, * Update address information and use the NAT-T * port and socket, if available. */ - port = htons(socket_getport(&sock->sock_addr)); + port = htons(socket_getport( + (struct sockaddr *)&sock->sock_addr)); sa->sa_local.addr_port = port; sa->sa_peer.addr_port = port; (void)socket_af((struct sockaddr *)&sa->sa_local.addr, port); @@ -632,8 +730,8 @@ ikev2_init_recv(struct iked *env, struct iked_message *msg, log_debug("%s: NAT detected, updated SA to " "peer %s local %s", __func__, - print_host(&sa->sa_peer.addr, NULL, 0), - print_host(&sa->sa_local.addr, NULL, 0)); + print_host((struct sockaddr *)&sa->sa_peer.addr, NULL, 0), + print_host((struct sockaddr *)&sa->sa_local.addr, NULL, 0)); } switch (hdr->ike_exchange) { @@ -641,12 +739,13 @@ ikev2_init_recv(struct iked *env, struct iked_message *msg, (void)ikev2_init_auth(env, msg); break; case IKEV2_EXCHANGE_IKE_AUTH: - (void)ikev2_ike_auth(env, sa, msg); + (void)ikev2_ike_auth_recv(env, sa, msg); break; case IKEV2_EXCHANGE_CREATE_CHILD_SA: (void)ikev2_init_create_child_sa(env, msg); break; case IKEV2_EXCHANGE_INFORMATIONAL: + sa->sa_stateflags &= ~IKED_REQ_INF; break; default: log_debug("%s: exchange %s not implemented", __func__, @@ -659,24 +758,11 @@ void ikev2_init_ike_sa(struct iked *env, void *arg) { struct iked_policy *pol; -#ifdef __APPLE__ - static struct timeval waketime = { 0, 0 }; - struct timeval tv; - size_t size = sizeof(tv); - - if (sysctlbyname("kern.waketime", &tv, &size, NULL, 0) == 0) { - if (waketime.tv_sec != 0 && - memcmp(&waketime, &tv, sizeof(waketime)) != 0) { - log_debug("%s: after power resume", __func__); - } - memcpy(&waketime, &tv, sizeof(waketime)); - } -#endif TAILQ_FOREACH(pol, &env->sc_policies, pol_entry) { if ((pol->pol_flags & IKED_POLICY_ACTIVE) == 0) continue; - if (sa_peer_lookup(pol, &pol->pol_peer.addr) != NULL) { + if (!TAILQ_EMPTY(&pol->pol_sapeers)) { log_debug("%s: \"%s\" is already active", __func__, pol->pol_name); continue; @@ -686,11 +772,13 @@ ikev2_init_ike_sa(struct iked *env, void *arg) if (ikev2_init_ike_sa_peer(env, pol, &pol->pol_peer)) log_debug("%s: failed to initiate with peer %s", - __func__, print_host(&pol->pol_peer.addr, NULL, 0)); + __func__, + print_host((struct sockaddr *)&pol->pol_peer.addr, + NULL, 0)); } - timer_initialize(env, &env->sc_inittmr, ikev2_init_ike_sa, NULL); - timer_register(env, &env->sc_inittmr, IKED_INITIATOR_INTERVAL); + timer_set(env, &env->sc_inittmr, ikev2_init_ike_sa, NULL); + timer_add(env, &env->sc_inittmr, IKED_INITIATOR_INTERVAL); } int @@ -720,23 +808,24 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, return (-1); /* Pick peer's DH group if asked */ + /* XXX free old sa_dhgroup ? */ sa->sa_dhgroup = pol->pol_peerdh; - if (ikev2_sa_initiator(env, sa, NULL) == -1) + if (ikev2_sa_initiator(env, sa, NULL, NULL) == -1) goto done; if (pol->pol_local.addr.ss_family == AF_UNSPEC) { if (socket_getaddr(sock->sock_fd, &ss) == -1) goto done; } else - memcpy(&ss, &pol->pol_local.addr, SS_LEN(&pol->pol_local.addr)); + memcpy(&ss, &pol->pol_local.addr, pol->pol_local.addr.ss_len); - if ((buf = ikev2_msg_init(env, &req, &peer->addr, SS_LEN(&peer->addr), - &ss, SS_LEN(&ss), 0)) == NULL) + if ((buf = ikev2_msg_init(env, &req, &peer->addr, peer->addr.ss_len, + &ss, ss.ss_len, 0)) == NULL) goto done; /* Inherit the port from the 1st send socket */ - port = htons(socket_getport(&sock->sock_addr)); + port = htons(socket_getport((struct sockaddr *)&sock->sock_addr)); (void)socket_af((struct sockaddr *)&req.msg_local, port); (void)socket_af((struct sockaddr *)&req.msg_peer, port); @@ -825,6 +914,9 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, len += sizeof(*n); } + if ((len = ikev2_add_sighashnotify(buf, &pld, len)) == -1) + goto done; + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONE) == -1) goto done; @@ -839,12 +931,6 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, goto done; } - memcpy(&sa->sa_polpeer, &pol->pol_peer, sizeof(sa->sa_polpeer)); - if (RB_INSERT(iked_sapeers, &pol->pol_sapeers, sa)) { - log_debug("%s: conflicting sa", __func__); - goto done; - } - if ((ret = ikev2_msg_send(env, &req)) == 0) sa_state(env, sa, IKEV2_STATE_SA_INIT); @@ -867,7 +953,7 @@ ikev2_init_auth(struct iked *env, struct iked_message *msg) if (sa == NULL) return (-1); - if (ikev2_sa_initiator(env, sa, msg) == -1) { + if (ikev2_sa_initiator(env, sa, NULL, msg) == -1) { log_debug("%s: failed to get IKE keys", __func__); return (-1); } @@ -937,21 +1023,15 @@ ikev2_init_ike_auth(struct iked *env, struct iked_sa *sa) goto done; len = ibuf_size(certid->id_buf) + sizeof(*cert); - if (env->sc_certreqtype) { - if (ikev2_next_payload(pld, len, - IKEV2_PAYLOAD_CERTREQ) == -1) - goto done; + /* CERTREQ payload(s) */ + if ((len = ikev2_add_certreq(e, &pld, + len, env->sc_certreq, env->sc_certreqtype)) == -1) + goto done; - /* CERTREQ payload */ - if ((pld = ikev2_add_payload(e)) == NULL) - goto done; - if ((cert = ibuf_advance(e, sizeof(*cert))) == NULL) - goto done; - cert->cert_type = env->sc_certreqtype; - if (ikev2_add_buf(e, env->sc_certreq) == -1) - goto done; - len = ibuf_size(env->sc_certreq) + sizeof(*cert); - } + if (env->sc_certreqtype != pol->pol_certreqtype && + (len = ikev2_add_certreq(e, &pld, + len, NULL, pol->pol_certreqtype)) == -1) + goto done; } if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_AUTH) == -1) @@ -978,6 +1058,11 @@ ikev2_init_ike_auth(struct iked *env, struct iked_sa *sa) goto done; } + /* compression */ + if ((pol->pol_flags & IKED_POLICY_IPCOMP) && + (len = ikev2_add_ipcompnotify(env, e, &pld, len, sa)) == -1) + goto done; + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1) goto done; @@ -1011,11 +1096,18 @@ ikev2_init_done(struct iked *env, struct iked_sa *sa) if (!sa_stateok(sa, IKEV2_STATE_VALID)) return (0); /* ignored */ - ret = ikev2_childsa_negotiate(env, sa, sa->sa_hdr.sh_initiator); + ret = ikev2_childsa_negotiate(env, sa, &sa->sa_kex, &sa->sa_proposals, + sa->sa_hdr.sh_initiator, 0); if (ret == 0) ret = ikev2_childsa_enable(env, sa); - if (ret == 0) + if (ret == 0) { sa_state(env, sa, IKEV2_STATE_ESTABLISHED); + timer_set(env, &sa->sa_timer, ikev2_ike_sa_alive, sa); + timer_add(env, &sa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT); + timer_set(env, &sa->sa_rekey, ikev2_ike_sa_rekey, sa); + if (sa->sa_policy->pol_rekey) + timer_add(env, &sa->sa_rekey, sa->sa_policy->pol_rekey); + } if (ret) ikev2_childsa_delete(env, sa, 0, 0, NULL, 1); @@ -1030,6 +1122,9 @@ ikev2_policy2id(struct iked_static_id *polid, struct iked_id *id, int srcid) char idstr[IKED_ID_SIZE]; struct in_addr in4; struct in6_addr in6; + X509_NAME *name = NULL; + u_int8_t *p; + int len; /* Fixup the local Id if not specified */ if (srcid && polid->id_type == 0) { @@ -1072,6 +1167,19 @@ ikev2_policy2id(struct iked_static_id *polid, struct iked_id *id, int srcid) return (-1); } break; + case IKEV2_ID_ASN1_DN: + /* policy has ID in string-format, convert to ASN1 */ + if ((name = ca_x509_name_parse(polid->id_data)) == NULL || + (len = i2d_X509_NAME(name, NULL)) < 0 || + (p = ibuf_reserve(id->id_buf, len)) == NULL || + (i2d_X509_NAME(name, &p)) < 0) { + if (name) + X509_NAME_free(name); + ibuf_release(id->id_buf); + return (-1); + } + X509_NAME_free(name); + break; default: if (ibuf_add(id->id_buf, polid->id_data, polid->id_length) != 0) { @@ -1084,7 +1192,7 @@ ikev2_policy2id(struct iked_static_id *polid, struct iked_id *id, int srcid) if (ikev2_print_id(id, idstr, sizeof(idstr)) == -1) return (-1); - log_debug("%s: %s %s length %d", __func__, + log_debug("%s: %s %s length %zu", __func__, srcid ? "srcid" : "dstid", idstr, ibuf_size(id->id_buf)); @@ -1157,6 +1265,7 @@ ikev2_add_ts_payload(struct ibuf *buf, u_int type, struct iked_sa *sa) struct ikev2_ts *ts; struct iked_flow *flow; struct iked_addr *addr; + struct iked_addr pooladdr; u_int8_t *ptr; size_t len = 0; u_int32_t av[4], bv[4], mv[4]; @@ -1185,6 +1294,13 @@ ikev2_add_ts_payload(struct ibuf *buf, u_int type, struct iked_sa *sa) } else return (-1); + /* patch remote address (if configured to 0.0.0.0) */ + if ((type == IKEV2_PAYLOAD_TSi && !sa->sa_hdr.sh_initiator) || + (type == IKEV2_PAYLOAD_TSr && sa->sa_hdr.sh_initiator)) { + if (ikev2_cp_fixaddr(sa, addr, &pooladdr) != -1) + addr = &pooladdr; + } + ts->ts_protoid = flow->flow_ipproto; if (addr->addr_port) { @@ -1277,6 +1393,133 @@ ikev2_add_ts(struct ibuf *e, struct ikev2_payload **pld, ssize_t len, return (len); } + +ssize_t +ikev2_add_certreq(struct ibuf *e, struct ikev2_payload **pld, ssize_t len, + struct ibuf *certreq, u_int8_t type) +{ + struct ikev2_cert *cert; + + if (type == IKEV2_CERT_NONE) + return (len); + + if (ikev2_next_payload(*pld, len, IKEV2_PAYLOAD_CERTREQ) == -1) + return (-1); + + /* CERTREQ payload */ + if ((*pld = ikev2_add_payload(e)) == NULL) + return (-1); + + if ((cert = ibuf_advance(e, sizeof(*cert))) == NULL) + return (-1); + + cert->cert_type = type; + len = sizeof(*cert); + + if (certreq != NULL && cert->cert_type == IKEV2_CERT_X509_CERT) { + if (ikev2_add_buf(e, certreq) == -1) + return (-1); + len += ibuf_size(certreq); + } + + log_debug("%s: type %s length %zd", __func__, + print_map(type, ikev2_cert_map), len); + + return (len); +} + +ssize_t +ikev2_add_ipcompnotify(struct iked *env, struct ibuf *e, + struct ikev2_payload **pld, ssize_t len, struct iked_sa *sa) +{ + struct iked_childsa csa; + struct ikev2_notify *n; + u_int8_t *ptr; + u_int16_t cpi; + u_int32_t spi; + u_int8_t transform; + + /* we only support deflate */ + transform = IKEV2_IPCOMP_DEFLATE; + + bzero(&csa, sizeof(csa)); + csa.csa_saproto = IKEV2_SAPROTO_IPCOMP; + csa.csa_ikesa = sa; + csa.csa_local = &sa->sa_peer; + csa.csa_peer = &sa->sa_local; + + if (pfkey_sa_init(env->sc_pfkey, &csa, &spi) == -1) + return (-1); + /* + * We get spi == 0 if the kernel does not support IPcomp, + * so just return the length of the current payload. + */ + if (spi == 0) + return (len); + cpi = htobe16((u_int16_t)spi); + if (*pld) + if (ikev2_next_payload(*pld, len, IKEV2_PAYLOAD_NOTIFY) == -1) + return (-1); + if ((*pld = ikev2_add_payload(e)) == NULL) + return (-1); + len = sizeof(*n) + sizeof(cpi) + sizeof(transform); + if ((ptr = ibuf_advance(e, len)) == NULL) + return (-1); + n = (struct ikev2_notify *)ptr; + n->n_protoid = 0; + n->n_spisize = 0; + n->n_type = htobe16(IKEV2_N_IPCOMP_SUPPORTED); + ptr += sizeof(*n); + memcpy(ptr, &cpi, sizeof(cpi)); + ptr += sizeof(cpi); + memcpy(ptr, &transform, sizeof(transform)); + + sa->sa_cpi_in = spi; /* already on host byte order */ + log_debug("%s: sa_cpi_in 0x%04x", __func__, sa->sa_cpi_in); + + return (len); +} + +ssize_t +ikev2_add_sighashnotify(struct ibuf *e, struct ikev2_payload **pld, + ssize_t len) +{ + struct ikev2_notify *n; + u_int8_t *ptr; + size_t i; + u_int16_t hash, signature_hashes[] = { + IKEV2_SIGHASH_SHA2_256, + IKEV2_SIGHASH_SHA2_384, + IKEV2_SIGHASH_SHA2_512 + }; + + if (ikev2_next_payload(*pld, len, IKEV2_PAYLOAD_NOTIFY) == -1) + return (-1); + + /* XXX signature_hashes are hardcoded for now */ + len = sizeof(*n) + nitems(signature_hashes) * sizeof(hash); + + /* NOTIFY payload */ + if ((*pld = ikev2_add_payload(e)) == NULL) + return (-1); + if ((ptr = ibuf_advance(e, len)) == NULL) + return (-1); + + n = (struct ikev2_notify *)ptr; + n->n_protoid = 0; + n->n_spisize = 0; + n->n_type = htobe16(IKEV2_N_SIGNATURE_HASH_ALGORITHMS); + ptr += sizeof(*n); + + for (i = 0; i < nitems(signature_hashes); i++) { + hash = htobe16(signature_hashes[i]); + memcpy(ptr, &hash, sizeof(hash)); + ptr += sizeof(hash); + } + + return (len); +} + int ikev2_next_payload(struct ikev2_payload *pld, size_t length, u_int8_t nextpayload) @@ -1288,7 +1531,7 @@ ikev2_next_payload(struct ikev2_payload *pld, size_t length, return (-1); } - log_debug("%s: length %d nextpayload %s", + log_debug("%s: length %zu nextpayload %s", __func__, pldlength, print_map(nextpayload, ikev2_payload_map)); pld->pld_length = htobe16(pldlength); @@ -1309,7 +1552,7 @@ ikev2_nat_detection(struct iked *env, struct iked_message *msg, struct sockaddr_in *in4; struct sockaddr_in6 *in6; ssize_t ret = -1; - struct sockaddr_storage *src, *dst, *ss; + struct sockaddr *src, *dst, *ss; u_int64_t rspi, ispi; struct ibuf *buf; int frompeer = 0; @@ -1325,14 +1568,14 @@ ikev2_nat_detection(struct iked *env, struct iked_message *msg, ispi = hdr->ike_ispi; rspi = hdr->ike_rspi; frompeer = 1; - src = &msg->msg_peer; - dst = &msg->msg_local; + src = (struct sockaddr *)&msg->msg_peer; + dst = (struct sockaddr *)&msg->msg_local; } else { ispi = htobe64(sa->sa_hdr.sh_ispi); rspi = htobe64(sa->sa_hdr.sh_rspi); frompeer = 0; - src = &msg->msg_local; - dst = &msg->msg_peer; + src = (struct sockaddr *)&msg->msg_local; + dst = (struct sockaddr *)&msg->msg_peer; } EVP_MD_CTX_init(&ctx); @@ -1362,7 +1605,7 @@ ikev2_nat_detection(struct iked *env, struct iked_message *msg, EVP_DigestUpdate(&ctx, &ispi, sizeof(ispi)); EVP_DigestUpdate(&ctx, &rspi, sizeof(rspi)); - switch (ss->ss_family) { + switch (ss->sa_family) { case AF_INET: in4 = (struct sockaddr_in *)ss; EVP_DigestUpdate(&ctx, &in4->sin_addr.s_addr, @@ -1408,6 +1651,7 @@ ikev2_add_cp(struct iked *env, struct iked_sa *sa, struct ibuf *buf) struct ikev2_cfg *cfg; struct iked_cfg *ikecfg; u_int i; + u_int32_t mask4; size_t len; struct sockaddr_in *in4; struct sockaddr_in6 *in6; @@ -1447,12 +1691,29 @@ ikev2_add_cp(struct iked *env, struct iked_sa *sa, struct ibuf *buf) case IKEV2_CFG_INTERNAL_IP4_DHCP: case IKEV2_CFG_INTERNAL_IP4_SERVER: /* 4 bytes IPv4 address */ - in4 = (struct sockaddr_in *)&ikecfg->cfg.address.addr; + in4 = (ikecfg->cfg.address.addr_mask != 32 && + (ikecfg->cfg_type == + IKEV2_CFG_INTERNAL_IP4_ADDRESS) && + sa->sa_addrpool && + sa->sa_addrpool->addr_af == AF_INET) ? + (struct sockaddr_in *)&sa->sa_addrpool->addr : + (struct sockaddr_in *)&ikecfg->cfg.address.addr; cfg->cfg_length = htobe16(4); if (ibuf_add(buf, &in4->sin_addr.s_addr, 4) == -1) return (-1); len += 4; break; + case IKEV2_CFG_INTERNAL_IP4_SUBNET: + /* 4 bytes IPv4 address + 4 bytes IPv4 mask + */ + in4 = (struct sockaddr_in *)&ikecfg->cfg.address.addr; + mask4 = prefixlen2mask(ikecfg->cfg.address.addr_mask); + cfg->cfg_length = htobe16(8); + if (ibuf_add(buf, &in4->sin_addr.s_addr, 4) == -1) + return (-1); + if (ibuf_add(buf, &mask4, 4) == -1) + return (-1); + len += 8; + break; case IKEV2_CFG_INTERNAL_IP6_DNS: case IKEV2_CFG_INTERNAL_IP6_NBNS: case IKEV2_CFG_INTERNAL_IP6_DHCP: @@ -1465,8 +1726,15 @@ ikev2_add_cp(struct iked *env, struct iked_sa *sa, struct ibuf *buf) len += 16; break; case IKEV2_CFG_INTERNAL_IP6_ADDRESS: + case IKEV2_CFG_INTERNAL_IP6_SUBNET: /* 16 bytes IPv6 address + 1 byte prefix length */ - in6 = (struct sockaddr_in6 *)&ikecfg->cfg.address.addr; + in6 = (ikecfg->cfg.address.addr_mask != 128 && + (ikecfg->cfg_type == + IKEV2_CFG_INTERNAL_IP6_ADDRESS) && + sa->sa_addrpool && + sa->sa_addrpool->addr_af == AF_INET6) ? + (struct sockaddr_in6 *)&sa->sa_addrpool->addr : + (struct sockaddr_in6 *)&ikecfg->cfg.address.addr; cfg->cfg_length = htobe16(17); if (ibuf_add(buf, &in6->sin6_addr.s6_addr, 16) == -1) return (-1); @@ -1575,7 +1843,7 @@ ikev2_add_proposals(struct iked *env, struct iked_sa *sa, struct ibuf *buf, length += saplength; } - log_debug("%s: length %d", __func__, length); + log_debug("%s: length %zd", __func__, length); return (length); } @@ -1720,7 +1988,7 @@ ikev2_resp_recv(struct iked *env, struct iked_message *msg, sa->sa_policy->pol_auth.auth_eap) sa_state(env, sa, IKEV2_STATE_EAP); - if (ikev2_ike_auth(env, sa, msg) != 0) { + if (ikev2_ike_auth_recv(env, sa, msg) != 0) { log_debug("%s: failed to send auth response", __func__); sa_state(env, sa, IKEV2_STATE_CLOSED); return; @@ -1729,6 +1997,14 @@ ikev2_resp_recv(struct iked *env, struct iked_message *msg, case IKEV2_EXCHANGE_CREATE_CHILD_SA: (void)ikev2_resp_create_child_sa(env, msg); break; + case IKEV2_EXCHANGE_INFORMATIONAL: + if (!msg->msg_responded && !msg->msg_error) { + (void)ikev2_send_ike_e(env, sa, NULL, + IKEV2_PAYLOAD_NONE, IKEV2_EXCHANGE_INFORMATIONAL, + 1); + msg->msg_responded = 1; + } + break; default: break; } @@ -1740,7 +2016,6 @@ ikev2_resp_ike_sa_init(struct iked *env, struct iked_message *msg) struct iked_message resp; struct ike_header *hdr; struct ikev2_payload *pld; - struct ikev2_cert *cert; struct ikev2_keyexchange *ke; struct ikev2_notify *n; struct iked_sa *sa = msg->msg_sa; @@ -1841,21 +2116,22 @@ ikev2_resp_ike_sa_init(struct iked *env, struct iked_message *msg) len += sizeof(*n); } - if (env->sc_certreqtype && (sa->sa_statevalid & IKED_REQ_CERT)) { - if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_CERTREQ) == -1) + if (sa->sa_statevalid & IKED_REQ_CERT) { + /* CERTREQ payload(s) */ + if ((len = ikev2_add_certreq(buf, &pld, + len, env->sc_certreq, env->sc_certreqtype)) == -1) goto done; - /* CERTREQ payload */ - if ((pld = ikev2_add_payload(buf)) == NULL) - goto done; - if ((cert = ibuf_advance(buf, sizeof(*cert))) == NULL) + if (env->sc_certreqtype != sa->sa_policy->pol_certreqtype && + (len = ikev2_add_certreq(buf, &pld, + len, NULL, sa->sa_policy->pol_certreqtype)) == -1) goto done; - cert->cert_type = env->sc_certreqtype; - if (ikev2_add_buf(buf, env->sc_certreq) == -1) - goto done; - len = ibuf_size(env->sc_certreq) + sizeof(*cert); } + if (sa->sa_sigsha2 && + (len = ikev2_add_sighashnotify(buf, &pld, len)) == -1) + goto done; + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONE) == -1) goto done; @@ -1900,7 +2176,11 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) else if (!sa_stateok(sa, IKEV2_STATE_VALID)) return (0); /* ignore */ - if (ikev2_childsa_negotiate(env, sa, sa->sa_hdr.sh_initiator) == -1) + if (ikev2_cp_setaddr(env, sa) < 0) + return (-1); + + if (ikev2_childsa_negotiate(env, sa, &sa->sa_kex, &sa->sa_proposals, + sa->sa_hdr.sh_initiator, 0) < 0) return (-1); /* New encrypted message buffer */ @@ -1988,6 +2268,11 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) goto done; } + /* compression */ + if (sa->sa_ipcomp && + (len = ikev2_add_ipcompnotify(env, e, &pld, len, sa)) == -1) + goto done; + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1) goto done; @@ -2009,8 +2294,14 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) IKEV2_EXCHANGE_IKE_AUTH, firstpayload, 1); if (ret == 0) ret = ikev2_childsa_enable(env, sa); - if (ret == 0) + if (ret == 0) { sa_state(env, sa, IKEV2_STATE_ESTABLISHED); + timer_set(env, &sa->sa_timer, ikev2_ike_sa_alive, sa); + timer_add(env, &sa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT); + timer_set(env, &sa->sa_rekey, ikev2_ike_sa_rekey, sa); + if (sa->sa_policy->pol_rekey) + timer_add(env, &sa->sa_rekey, sa->sa_policy->pol_rekey); + } done: if (ret) @@ -2031,13 +2322,14 @@ ikev2_resp_ike_eap(struct iked *env, struct iked_sa *sa, struct ibuf *eapmsg) int ret = -1; ssize_t len = 0; - if (!sa_stateok(sa, IKEV2_STATE_EAP)) - return (0); - /* Responder only */ if (sa->sa_hdr.sh_initiator) return (-1); + /* Check if "ca" has done it's job yet */ + if (!sa->sa_localauth.id_type) + return (0); + /* New encrypted message buffer */ if ((e = ibuf_static()) == NULL) goto done; @@ -2117,11 +2409,15 @@ ikev2_send_ike_e(struct iked *env, struct iked_sa *sa, struct ibuf *buf, if ((pld = ikev2_add_payload(e)) == NULL) goto done; - if (ibuf_cat(e, buf) != 0) - goto done; - if (ikev2_next_payload(pld, ibuf_size(buf), IKEV2_PAYLOAD_NONE) == -1) - goto done; + if (buf) { + if (ibuf_cat(e, buf) != 0) + goto done; + + if (ikev2_next_payload(pld, ibuf_size(buf), + IKEV2_PAYLOAD_NONE) == -1) + goto done; + } ret = ikev2_msg_send_encrypt(env, sa, &e, exchange, firstpayload, response); @@ -2132,15 +2428,46 @@ ikev2_send_ike_e(struct iked *env, struct iked_sa *sa, struct ibuf *buf, return (ret); } +int +ikev2_set_sa_proposal(struct iked_sa *sa, struct iked_policy *pol, + u_int proto) +{ + struct iked_proposal *prop, *copy; + struct iked_transform *xform; + u_int i; + + /* create copy of the policy proposals */ + config_free_proposals(&sa->sa_proposals, proto); + TAILQ_FOREACH(prop, &pol->pol_proposals, prop_entry) { + if (proto != 0 && prop->prop_protoid != proto) + continue; + if ((copy = config_add_proposal(&sa->sa_proposals, + prop->prop_id, prop->prop_protoid)) == NULL) + return (-1); + for (i = 0; i < prop->prop_nxforms; i++) { + xform = &prop->prop_xforms[i]; + if (config_add_transform(copy, xform->xform_type, + xform->xform_id, xform->xform_length, + xform->xform_keylength) == NULL) + return (-1); + } + } + return (0); +} + int ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, struct iked_spi *rekey, u_int8_t protoid) { + struct iked_policy *pol = sa->sa_policy; struct iked_childsa *csa = NULL, *csb = NULL; struct ikev2_notify *n; - struct ikev2_payload *pld; + struct ikev2_payload *pld = NULL; + struct ikev2_keyexchange *ke; + struct group *group; struct ibuf *e = NULL, *nonce = NULL; u_int8_t *ptr; + u_int8_t firstpayload; u_int32_t spi; ssize_t len = 0; int initiator, ret = -1; @@ -2152,6 +2479,14 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, else log_debug("%s: creating new CHILD SAs", __func__); + /* XXX cannot initiate multiple concurrent CREATE_CHILD_SA exchanges */ + if (sa->sa_stateflags & IKED_REQ_CHILDSA) { + log_debug("%s: another CREATE_CHILD_SA exchange already active", + __func__); + return (-1); + } + + sa->sa_rekeyspi = 0; /* clear rekey spi */ initiator = sa->sa_hdr.sh_initiator ? 1 : 0; if (rekey && @@ -2160,6 +2495,7 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, (csb = csa->csa_peersa) == NULL)) { log_debug("%s: CHILD SA %s wasn't found", __func__, print_spi(rekey->spi, rekey->spi_size)); + goto done; } /* Generate new nonce */ @@ -2173,9 +2509,32 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, if ((e = ibuf_static()) == NULL) goto done; + /* compression */ + if ((pol->pol_flags & IKED_POLICY_IPCOMP) && + (len = ikev2_add_ipcompnotify(env, e, &pld, 0, sa)) == -1) + goto done; + + if (pld) { + firstpayload = IKEV2_PAYLOAD_NOTIFY; + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1) + goto done; + } else + firstpayload = IKEV2_PAYLOAD_SA; + /* SA payload */ if ((pld = ikev2_add_payload(e)) == NULL) goto done; + + /* + * We need to reset the sa_proposal. Otherwise it would be + * left over from the IKE_AUTH exchange and would not contain + * any DH groups (e.g. for ESP child SAs). + */ + if (ikev2_set_sa_proposal(sa, pol, protoid) < 0) { + log_debug("%s: ikev2_set_sa_proposal failed", __func__); + goto done; + } + if ((len = ikev2_add_proposals(env, sa, e, &sa->sa_proposals, protoid, 1, 0)) == -1) goto done; @@ -2190,6 +2549,32 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, goto done; len = ibuf_size(nonce); + if (config_findtransform(&pol->pol_proposals, IKEV2_XFORMTYPE_DH, + protoid)) { + log_debug("%s: enable PFS", __func__); + ikev2_sa_cleanup_dh(sa); + if (ikev2_sa_initiator_dh(sa, NULL, protoid) < 0) { + log_debug("%s: failed to setup DH", __func__); + goto done; + } + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_KE) == -1) + goto done; + + /* KE payload */ + if ((pld = ikev2_add_payload(e)) == NULL) + goto done; + if ((ke = ibuf_advance(e, sizeof(*ke))) == NULL) + goto done; + if ((group = sa->sa_dhgroup) == NULL) { + log_debug("%s: invalid dh", __func__); + goto done; + } + ke->kex_dhgroup = htobe16(group->id); + if (ikev2_add_buf(e, sa->sa_dhiexchange) == -1) + goto done; + len = sizeof(*ke) + dh_getlen(group); + } + if ((len = ikev2_add_ts(e, &pld, len, sa, !initiator)) == -1) goto done; @@ -2217,11 +2602,16 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, goto done; ret = ikev2_msg_send_encrypt(env, sa, &e, - IKEV2_EXCHANGE_CREATE_CHILD_SA, IKEV2_PAYLOAD_SA, 0); + IKEV2_EXCHANGE_CREATE_CHILD_SA, firstpayload, 0); if (ret == 0) { if (rekey) { csa->csa_rekey = 1; csb->csa_rekey = 1; + /* + * Remember the peer spi of the rekeyed + * SA for ikev2_init_create_child_sa(). + */ + sa->sa_rekeyspi = csa->csa_peerspi; } sa->sa_stateflags |= IKED_REQ_CHILDSA; } @@ -2231,28 +2621,131 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, return (ret); } -int -ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) +void +ikev2_ike_sa_rekey(struct iked *env, void *arg) { - struct iked_childsa *csa; - struct iked_proposal *prop; - struct iked_sa *sa = msg->msg_sa; - struct ikev2_delete *del; - struct ibuf *buf = NULL; - u_int64_t peerspi; - u_int32_t spi32; - int rekeying = 0, ret = -1; + struct iked_sa *sa = arg; + struct iked_sa *nsa = NULL; + struct ikev2_payload *pld = NULL; + struct ikev2_keyexchange *ke; + struct group *group; + struct ibuf *e = NULL, *nonce = NULL; + ssize_t len = 0; + int ret = -1; - if (!ikev2_msg_frompeer(msg) || - (sa->sa_stateflags & IKED_REQ_CHILDSA) == 0) - return (0); + log_debug("%s: called for IKE SA %p", __func__, sa); - if (msg->msg_prop == NULL) { - log_debug("%s: no proposal specified", __func__); - return (-1); + if (sa->sa_stateflags & IKED_REQ_CHILDSA) { + /* + * We cannot initiate multiple concurrent CREATE_CHILD_SA + * exchanges, so retry in one minute. + */ + timer_add(env, &sa->sa_rekey, 60); + return; + } + + if ((nsa = sa_new(env, 0, 0, 1, sa->sa_policy)) == NULL) { + log_debug("%s: failed to get new SA", __func__); + goto done; + } + + if (ikev2_sa_initiator(env, nsa, sa, NULL)) { + log_debug("%s: failed to setup DH", __func__); + goto done; + } + sa_state(env, nsa, IKEV2_STATE_AUTH_SUCCESS); + nonce = nsa->sa_inonce; + + if ((e = ibuf_static()) == NULL) + goto done; + + /* SA payload */ + if ((pld = ikev2_add_payload(e)) == NULL) + goto done; + + /* just reuse the old IKE SA proposals */ + if ((len = ikev2_add_proposals(env, nsa, e, &sa->sa_proposals, + IKEV2_SAPROTO_IKE, 1, 1)) == -1) + goto done; + + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONCE) == -1) + goto done; + + /* NONCE payload */ + if ((pld = ikev2_add_payload(e)) == NULL) + goto done; + if (ikev2_add_buf(e, nonce) == -1) + goto done; + len = ibuf_size(nonce); + + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_KE) == -1) + goto done; + + /* KE payload */ + if ((pld = ikev2_add_payload(e)) == NULL) + goto done; + if ((ke = ibuf_advance(e, sizeof(*ke))) == NULL) + goto done; + if ((group = nsa->sa_dhgroup) == NULL) { + log_debug("%s: invalid dh", __func__); + goto done; + } + ke->kex_dhgroup = htobe16(group->id); + if (ikev2_add_buf(e, nsa->sa_dhiexchange) == -1) + goto done; + len = sizeof(*ke) + dh_getlen(group); + + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONE) == -1) + goto done; + + ret = ikev2_msg_send_encrypt(env, sa, &e, + IKEV2_EXCHANGE_CREATE_CHILD_SA, IKEV2_PAYLOAD_SA, 0); + if (ret == 0) { + sa->sa_stateflags |= IKED_REQ_CHILDSA; + sa->sa_next = nsa; + nsa = NULL; + } +done: + if (nsa) + sa_free(env, nsa); + ibuf_release(e); + + if (ret == 0) + log_debug("%s: create child SA sent", __func__); + else + log_debug("%s: could not send create child SA", __func__); + /* XXX should we try again in case of ret != 0 ? */ +} + +int +ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) +{ + struct iked_childsa *csa = NULL; + struct iked_proposal *prop; + struct iked_sa *sa = msg->msg_sa; + struct iked_sa *nsa; + struct iked_spi *spi; + struct ikev2_delete *del; + struct ibuf *buf = NULL; + u_int32_t spi32; + int pfs = 0, ret = -1; + + if (!ikev2_msg_frompeer(msg) || + (sa->sa_stateflags & IKED_REQ_CHILDSA) == 0) + return (0); + + if (msg->msg_prop == NULL || + TAILQ_EMPTY(&msg->msg_proposals)) { + log_debug("%s: no proposal specified", __func__); + return (-1); + } + + if (ikev2_sa_negotiate(&sa->sa_proposals, &sa->sa_proposals, + &msg->msg_proposals) != 0) { + log_debug("%s: no proposal chosen", __func__); + return (-1); } - /* Update peer SPI */ TAILQ_FOREACH(prop, &sa->sa_proposals, prop_entry) { if (prop->prop_protoid == msg->msg_prop->prop_protoid) break; @@ -2263,13 +2756,56 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) return (-1); } - peerspi = prop->prop_peerspi.spi; - prop->prop_peerspi.spi = msg->msg_prop->prop_peerspi.spi; - - if ((csa = childsa_lookup(sa, peerspi, prop->prop_protoid)) != NULL) { - rekeying = 1; - log_debug("%s: rekeying CHILD SA %s", __func__, - print_spi(peerspi, prop->prop_peerspi.spi_size)); + /* IKE SA rekeying */ + if (prop->prop_protoid == IKEV2_SAPROTO_IKE) { + if (sa->sa_next == NULL) { + log_debug("%s: missing IKE SA for rekeying", __func__); + return (-1); + } + /* Update the responder SPI */ + spi = &msg->msg_prop->prop_peerspi; + if ((nsa = sa_new(env, sa->sa_next->sa_hdr.sh_ispi, + spi->spi, 1, NULL)) == NULL || nsa != sa->sa_next) { + log_debug("%s: invalid rekey SA", __func__); + if (nsa) + sa_free(env, nsa); + sa_free(env, sa->sa_next); + sa->sa_next = NULL; + return (-1); + } + if (ikev2_sa_initiator(env, nsa, sa, msg) == -1) { + log_debug("%s: failed to get IKE keys", __func__); + return (-1); + } + sa->sa_stateflags &= ~IKED_REQ_CHILDSA; + sa->sa_next = NULL; + return (ikev2_ikesa_enable(env, sa, nsa)); + } + + /* Child SA rekeying */ + if (sa->sa_rekeyspi && + (csa = childsa_lookup(sa, sa->sa_rekeyspi, prop->prop_protoid)) + != NULL) { + log_debug("%s: rekeying CHILD SA old %s spi %s", __func__, + print_spi(csa->csa_spi.spi, csa->csa_spi.spi_size), + print_spi(prop->prop_peerspi.spi, + prop->prop_peerspi.spi_size)); + } + + /* check KE payload for PFS */ + if (ibuf_length(msg->msg_ke)) { + log_debug("%s: using PFS", __func__); + if (ikev2_sa_initiator_dh(sa, msg, prop->prop_protoid) < 0) { + log_debug("%s: failed to setup DH", __func__); + return (ret); + } + if (sa->sa_dhpeer == NULL) { + log_debug("%s: no peer DH", __func__); + return (ret); + } + pfs = 1; + /* XXX check group against policy ? */ + /* XXX should ikev2_sa_negotiate do this? */ } /* Update responder's nonce */ @@ -2280,12 +2816,13 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) ibuf_release(sa->sa_rnonce); sa->sa_rnonce = ibuf_dup(msg->msg_nonce); - if (ikev2_childsa_negotiate(env, sa, 1)) { + if (ikev2_childsa_negotiate(env, sa, &sa->sa_kex, &sa->sa_proposals, 1, + pfs)) { log_debug("%s: failed to get CHILD SAs", __func__); return (-1); } - if (rekeying) { + if (csa) { /* Child SA rekeying */ if ((buf = ibuf_static()) == NULL) @@ -2298,7 +2835,7 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) del->del_spisize = sizeof(spi32); del->del_nspi = htobe16(1); - spi32 = htobe32(csa->csa_peerspi); + spi32 = htobe32(csa->csa_spi.spi); if (ibuf_add(buf, &spi32, sizeof(spi32))) goto done; @@ -2306,7 +2843,7 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) IKEV2_EXCHANGE_INFORMATIONAL, 0)) goto done; - sa->sa_stateflags |= IKED_REQ_INF | IKED_REQ_DELETE; + sa->sa_stateflags |= IKED_REQ_INF; } ret = ikev2_childsa_enable(env, sa); @@ -2321,29 +2858,159 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) } int -ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) +ikev2_ikesa_enable(struct iked *env, struct iked_sa *sa, struct iked_sa *nsa) { struct iked_childsa *csa, *nextcsa; struct iked_flow *flow, *nextflow; struct iked_proposal *prop, *nextprop; + + log_debug("%s: IKE SA %p ispi %s rspi %s replaced" + " by SA %p ispi %s rspi %s ", + __func__, sa, + print_spi(sa->sa_hdr.sh_ispi, 8), + print_spi(sa->sa_hdr.sh_rspi, 8), + nsa, + print_spi(nsa->sa_hdr.sh_ispi, 8), + print_spi(nsa->sa_hdr.sh_rspi, 8)); + + /* Transfer socket and NAT information */ + nsa->sa_fd = sa->sa_fd; + nsa->sa_natt = sa->sa_natt; + nsa->sa_udpencap = sa->sa_udpencap; + + /* Transfer all Child SAs and flows from the old IKE SA */ + for (flow = TAILQ_FIRST(&sa->sa_flows); flow != NULL; + flow = nextflow) { + nextflow = TAILQ_NEXT(flow, flow_entry); + TAILQ_REMOVE(&sa->sa_flows, flow, flow_entry); + TAILQ_INSERT_TAIL(&nsa->sa_flows, flow, + flow_entry); + flow->flow_ikesa = nsa; + flow->flow_local = &nsa->sa_local; + flow->flow_peer = &nsa->sa_peer; + } + for (csa = TAILQ_FIRST(&sa->sa_childsas); csa != NULL; + csa = nextcsa) { + nextcsa = TAILQ_NEXT(csa, csa_entry); + TAILQ_REMOVE(&sa->sa_childsas, csa, csa_entry); + TAILQ_INSERT_TAIL(&nsa->sa_childsas, csa, + csa_entry); + csa->csa_ikesa = nsa; + if (csa->csa_dir == IPSP_DIRECTION_IN) { + csa->csa_local = &nsa->sa_peer; + csa->csa_peer = &nsa->sa_local; + } else { + csa->csa_local = &nsa->sa_local; + csa->csa_peer = &nsa->sa_peer; + } + } + /* Transfer all non-IKE proposals */ + for (prop = TAILQ_FIRST(&sa->sa_proposals); prop != NULL; + prop = nextprop) { + nextprop = TAILQ_NEXT(prop, prop_entry); + if (prop->prop_protoid == IKEV2_SAPROTO_IKE) + continue; + TAILQ_REMOVE(&sa->sa_proposals, prop, prop_entry); + TAILQ_INSERT_TAIL(&nsa->sa_proposals, prop, + prop_entry); + } + + /* Preserve ID information */ + if (sa->sa_hdr.sh_initiator == nsa->sa_hdr.sh_initiator) { + nsa->sa_iid = sa->sa_iid; + nsa->sa_rid = sa->sa_rid; + } else { + /* initiator and responder role swapped */ + nsa->sa_iid = sa->sa_rid; + nsa->sa_rid = sa->sa_iid; + } + /* duplicate the actual buffer */ + nsa->sa_iid.id_buf = ibuf_dup(nsa->sa_iid.id_buf); + nsa->sa_rid.id_buf = ibuf_dup(nsa->sa_rid.id_buf); + + /* Transfer sa_addrpool address */ + if (sa->sa_addrpool) { + RB_REMOVE(iked_addrpool, &env->sc_addrpool, sa); + nsa->sa_addrpool = sa->sa_addrpool; + sa->sa_addrpool = NULL; + RB_INSERT(iked_addrpool, &env->sc_addrpool, nsa); + } + + log_debug("%s: activating new IKE SA", __func__); + sa_state(env, nsa, IKEV2_STATE_ESTABLISHED); + timer_set(env, &nsa->sa_timer, ikev2_ike_sa_alive, nsa); + timer_add(env, &nsa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT); + timer_set(env, &nsa->sa_rekey, ikev2_ike_sa_rekey, nsa); + if (nsa->sa_policy->pol_rekey) + timer_add(env, &nsa->sa_rekey, nsa->sa_policy->pol_rekey); + nsa->sa_stateflags = nsa->sa_statevalid; /* XXX */ + + /* unregister DPD keep alive timer & rekey first */ + if (sa->sa_state == IKEV2_STATE_ESTABLISHED) { + timer_del(env, &sa->sa_rekey); + timer_del(env, &sa->sa_timer); + } + + ikev2_ikesa_delete(env, sa, nsa->sa_hdr.sh_initiator); + return (0); +} + +void +ikev2_ikesa_delete(struct iked *env, struct iked_sa *sa, int initiator) +{ + struct ibuf *buf = NULL; + struct ikev2_delete *del; + + if (initiator) { + /* Send PAYLOAD_DELETE */ + if ((buf = ibuf_static()) == NULL) + goto done; + if ((del = ibuf_advance(buf, sizeof(*del))) == NULL) + goto done; + del->del_protoid = IKEV2_SAPROTO_IKE; + del->del_spisize = 0; + del->del_nspi = 0; + if (ikev2_send_ike_e(env, sa, buf, IKEV2_PAYLOAD_DELETE, + IKEV2_EXCHANGE_INFORMATIONAL, 0) == -1) + goto done; + log_debug("%s: sent delete, closing SA", __func__); +done: + ibuf_release(buf); + sa_state(env, sa, IKEV2_STATE_CLOSED); + } else { + sa_state(env, sa, IKEV2_STATE_CLOSING); + } + + /* Remove IKE-SA after timeout, e.g. if we don't get a delete */ + timer_set(env, &sa->sa_timer, ikev2_ike_sa_timeout, sa); + timer_add(env, &sa->sa_timer, IKED_IKE_SA_DELETE_TIMEOUT); +} + +int +ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) +{ + struct iked_childsa *csa; + struct iked_proposal *prop; + struct iked_proposals proposals; + struct iked_kex *kex, *kextmp = NULL; struct iked_sa *nsa = NULL, *sa = msg->msg_sa; struct iked_spi *spi, *rekey = &msg->msg_rekey; struct ikev2_keyexchange *ke; - struct ikev2_notify *n; - struct ikev2_payload *pld; - struct ibuf *buf = NULL, *e = NULL, *nonce = NULL; - struct group *group; - u_int64_t spi64; - u_int32_t spi32; + struct ikev2_payload *pld = NULL; + struct ibuf *e = NULL, *nonce = NULL; + u_int8_t firstpayload; ssize_t len = 0; int initiator, protoid, rekeying = 1; int ret = -1; + int pfs = 0; initiator = sa->sa_hdr.sh_initiator ? 1 : 0; if (!ikev2_msg_frompeer(msg) || msg->msg_prop == NULL) return (0); + TAILQ_INIT(&proposals); + if ((protoid = rekey->spi_protoid) == 0) { /* * If REKEY_SA notification is not present, then it's either @@ -2389,45 +3056,42 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) sa_state(env, nsa, IKEV2_STATE_AUTH_SUCCESS); nonce = nsa->sa_rnonce; + kex = &nsa->sa_kex; } else { /* Child SA creating/rekeying */ + if ((kex = kextmp = calloc(1, sizeof(*kextmp))) == NULL) { + log_debug("%s: calloc kex", __func__); + goto fail; + } + + if (ikev2_sa_negotiate(&proposals, + &sa->sa_policy->pol_proposals, &msg->msg_proposals) != 0) { + log_debug("%s: no proposal chosen", __func__); + goto fail; + } + + /* check KE payload for PFS */ if (ibuf_length(msg->msg_parent->msg_ke)) { - /* We do not support KE payload yet */ - if ((buf = ibuf_static()) == NULL) - return (-1); - if ((n = ibuf_advance(buf, sizeof(*n))) == NULL) { - ibuf_release(buf); - return (-1); + log_debug("%s: using PFS", __func__); + if (ikev2_sa_responder_dh(kex, &proposals, + msg->msg_parent, protoid) < 0) { + log_debug("%s: failed to setup DH", __func__); + goto fail; } - n->n_protoid = protoid; - n->n_spisize = rekey->spi_size; - n->n_type = htobe16(IKEV2_N_NO_ADDITIONAL_SAS); - switch (rekey->spi_size) { - case 4: - spi32 = htobe32(rekey->spi); - ibuf_add(buf, &spi32, rekey->spi_size); - break; - case 8: - spi64 = htobe64(rekey->spi); - ibuf_add(buf, &spi64, rekey->spi_size); - break; - } - ikev2_send_ike_e(env, sa, buf, IKEV2_PAYLOAD_NOTIFY, - IKEV2_EXCHANGE_CREATE_CHILD_SA, 1); - ibuf_release(buf); - return (0); + pfs = 1; + /* XXX check group against policy ? */ } /* Update peer SPI */ - TAILQ_FOREACH(prop, &sa->sa_proposals, prop_entry) { + TAILQ_FOREACH(prop, &proposals, prop_entry) { if (prop->prop_protoid == protoid) break; } if (prop == NULL) { log_debug("%s: failed to find %s proposals", __func__, print_map(protoid, ikev2_saproto_map)); - return (-1); + goto fail; } else prop->prop_peerspi = msg->msg_prop->prop_peerspi; @@ -2438,13 +3102,13 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) log_debug("%s: CHILD SA %s wasn't found", __func__, print_spi(rekey->spi, rekey->spi_size)); - return (-1); + goto fail; } if (!csa->csa_loaded || !csa->csa_peersa || !csa->csa_peersa->csa_loaded) { log_debug("%s: SA is not loaded or no peer SA", __func__); - return (-1); + goto fail; } csa->csa_rekey = 1; csa->csa_peersa->csa_rekey = 1; @@ -2453,34 +3117,46 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) /* Update initiator's nonce */ if (!ibuf_length(msg->msg_nonce)) { log_debug("%s: initiator didn't send nonce", __func__); - return (-1); + goto fail; } - ibuf_release(sa->sa_inonce); - sa->sa_inonce = ibuf_dup(msg->msg_nonce); + ibuf_release(kex->kex_inonce); + kex->kex_inonce = ibuf_dup(msg->msg_nonce); /* Generate new responder's nonce */ if ((nonce = ibuf_random(IKED_NONCE_SIZE)) == NULL) - return (-1); + goto fail; /* Update responder's nonce */ - ibuf_release(sa->sa_rnonce); - sa->sa_rnonce = nonce; + ibuf_release(kex->kex_rnonce); + kex->kex_rnonce = nonce; - if (ikev2_childsa_negotiate(env, sa, 0)) { + if (ikev2_childsa_negotiate(env, sa, kex, &proposals, 0, pfs)) { log_debug("%s: failed to get CHILD SAs", __func__); - return (-1); + goto fail; } } if ((e = ibuf_static()) == NULL) goto done; + /* compression (unless IKE rekeying) */ + if (!nsa && sa->sa_ipcomp && + (len = ikev2_add_ipcompnotify(env, e, &pld, 0, sa)) == -1) + goto done; + + if (pld) { + firstpayload = IKEV2_PAYLOAD_NOTIFY; + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1) + goto done; + } else + firstpayload = IKEV2_PAYLOAD_SA; + /* SA payload */ if ((pld = ikev2_add_payload(e)) == NULL) goto done; if ((len = ikev2_add_proposals(env, nsa ? nsa : sa, e, - nsa ? &nsa->sa_proposals : &sa->sa_proposals, + nsa ? &nsa->sa_proposals : &proposals, protoid, 0, nsa ? 1 : 0)) == -1) goto done; @@ -2494,7 +3170,8 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) goto done; len = ibuf_size(nonce); - if (protoid == IKEV2_SAPROTO_IKE) { + if (protoid == IKEV2_SAPROTO_IKE || pfs) { + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_KE) == -1) goto done; @@ -2503,74 +3180,44 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) goto done; if ((ke = ibuf_advance(e, sizeof(*ke))) == NULL) goto done; - if ((group = nsa->sa_dhgroup) == NULL) { + if (kex->kex_dhgroup == NULL) { log_debug("%s: invalid dh", __func__); goto done; } - ke->kex_dhgroup = htobe16(group->id); - if (ikev2_add_buf(e, nsa->sa_dhrexchange) == -1) + ke->kex_dhgroup = htobe16(kex->kex_dhgroup->id); + if (ikev2_add_buf(e, kex->kex_dhrexchange) == -1) goto done; - len = sizeof(*ke) + dh_getlen(group); - } else { + len = sizeof(*ke) + dh_getlen(kex->kex_dhgroup); + } + + if (protoid != IKEV2_SAPROTO_IKE) if ((len = ikev2_add_ts(e, &pld, len, sa, initiator)) == -1) goto done; - } if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONE) == -1) goto done; if ((ret = ikev2_msg_send_encrypt(env, sa, &e, - IKEV2_EXCHANGE_CREATE_CHILD_SA, IKEV2_PAYLOAD_SA, 1)) == -1) + IKEV2_EXCHANGE_CREATE_CHILD_SA, firstpayload, 1)) == -1) goto done; - if (protoid == IKEV2_SAPROTO_IKE) { - /* Transfer all Child SAs and flows from the old IKE SA */ - for (flow = TAILQ_FIRST(&sa->sa_flows); flow != NULL; - flow = nextflow) { - nextflow = TAILQ_NEXT(flow, flow_entry); - TAILQ_REMOVE(&sa->sa_flows, flow, flow_entry); - TAILQ_INSERT_TAIL(&nsa->sa_flows, flow, - flow_entry); - flow->flow_ikesa = nsa; - } - for (csa = TAILQ_FIRST(&sa->sa_childsas); csa != NULL; - csa = nextcsa) { - nextcsa = TAILQ_NEXT(csa, csa_entry); - TAILQ_REMOVE(&sa->sa_childsas, csa, csa_entry); - TAILQ_INSERT_TAIL(&nsa->sa_childsas, csa, - csa_entry); - csa->csa_ikesa = nsa; - } - /* Transfer all non-IKE proposals */ - for (prop = TAILQ_FIRST(&sa->sa_proposals); prop != NULL; - prop = nextprop) { - nextprop = TAILQ_NEXT(prop, prop_entry); - if (prop->prop_protoid == IKEV2_SAPROTO_IKE) - continue; - TAILQ_REMOVE(&sa->sa_proposals, prop, prop_entry); - TAILQ_INSERT_TAIL(&nsa->sa_proposals, prop, - prop_entry); - } - /* Preserve ID information */ - nsa->sa_iid = sa->sa_iid; - nsa->sa_iid.id_buf = ibuf_dup(sa->sa_iid.id_buf); - nsa->sa_rid = sa->sa_rid; - nsa->sa_rid.id_buf = ibuf_dup(sa->sa_rid.id_buf); - - log_debug("%s: activating new IKE SA", __func__); - sa_state(env, nsa, IKEV2_STATE_ESTABLISHED); - nsa->sa_stateflags = sa->sa_statevalid; /* XXX */ - - timer_initialize(env, &sa->sa_timer, ikev2_ike_sa_timeout, sa); - timer_register(env, &sa->sa_timer, IKED_IKE_SA_REKEY_TIMEOUT); - } else + if (protoid == IKEV2_SAPROTO_IKE) + ret = ikev2_ikesa_enable(env, sa, nsa); + else ret = ikev2_childsa_enable(env, sa); done: if (ret && protoid != IKEV2_SAPROTO_IKE) ikev2_childsa_delete(env, sa, 0, 0, NULL, 1); ibuf_release(e); + config_free_proposals(&proposals, 0); + config_free_kex(kextmp); return (ret); + + fail: + config_free_proposals(&proposals, 0); + config_free_kex(kextmp); + return (-1); } void @@ -2582,6 +3229,50 @@ ikev2_ike_sa_timeout(struct iked *env, void *arg) sa_free(env, sa); } +void +ikev2_ike_sa_alive(struct iked *env, void *arg) +{ + struct iked_sa *sa = arg; + struct iked_childsa *csa = NULL; + struct timeval tv; + u_int64_t last_used, diff; + int foundin = 0, foundout = 0; + + /* check for incoming traffic on any child SA */ + TAILQ_FOREACH(csa, &sa->sa_childsas, csa_entry) { + if (!csa->csa_loaded || + csa->csa_saproto == IKEV2_SAPROTO_IPCOMP) + continue; + if (pfkey_sa_last_used(env->sc_pfkey, csa, &last_used) != 0) + continue; + gettimeofday(&tv, NULL); + diff = (u_int32_t)(tv.tv_sec - last_used); + log_debug("%s: %s CHILD SA spi %s last used %llu second(s) ago", + __func__, + csa->csa_dir == IPSP_DIRECTION_IN ? "incoming" : "outgoing", + print_spi(csa->csa_spi.spi, csa->csa_spi.spi_size), diff); + if (diff < IKED_IKE_SA_ALIVE_TIMEOUT) { + if (csa->csa_dir == IPSP_DIRECTION_IN) { + foundin = 1; + break; + } else { + foundout = 1; + } + } + } + + /* send probe if any outging SA has been used, but no incoming SA */ + if (!foundin && foundout) { + log_debug("%s: sending alive check", __func__); + ikev2_send_ike_e(env, sa, NULL, IKEV2_PAYLOAD_NONE, + IKEV2_EXCHANGE_INFORMATIONAL, 0); + sa->sa_stateflags |= IKED_REQ_INF; + } + + /* re-register */ + timer_add(env, &sa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT); +} + int ikev2_send_informational(struct iked *env, struct iked_message *msg) { @@ -2778,16 +3469,17 @@ ikev2_match_proposals(struct iked_proposal *local, struct iked_proposal *peer, } int -ikev2_sa_negotiate(struct iked_sa *sa, struct iked_proposals *local, +ikev2_sa_negotiate(struct iked_proposals *result, struct iked_proposals *local, struct iked_proposals *peer) { struct iked_proposal *ppeer = NULL, *plocal, *prop, vpeer, vlocal; - struct iked_transform *chosen[IKEV2_XFORMTYPE_MAX]; + struct iked_transform chosen[IKEV2_XFORMTYPE_MAX]; + struct iked_transform *valid[IKEV2_XFORMTYPE_MAX]; struct iked_transform *match[IKEV2_XFORMTYPE_MAX]; u_int i, score, chosen_score = 0; u_int8_t protoid = 0; - bzero(chosen, sizeof(chosen)); + bzero(valid, sizeof(valid)); bzero(&vlocal, sizeof(vlocal)); bzero(&vpeer, sizeof(vpeer)); @@ -2806,8 +3498,11 @@ ikev2_sa_negotiate(struct iked_sa *sa, struct iked_proposals *local, log_debug("%s: score %d", __func__, score); if (score && (!chosen_score || score < chosen_score)) { chosen_score = score; - for (i = 0; i < IKEV2_XFORMTYPE_MAX; i++) - chosen[i] = match[i]; + for (i = 0; i < IKEV2_XFORMTYPE_MAX; i++) { + if ((valid[i] = match[i])) + memcpy(&chosen[i], match[i], + sizeof(chosen[0])); + } memcpy(&vpeer, ppeer, sizeof(vpeer)); memcpy(&vlocal, plocal, sizeof(vlocal)); } @@ -2818,12 +3513,11 @@ ikev2_sa_negotiate(struct iked_sa *sa, struct iked_proposals *local, if (chosen_score == 0) return (-1); - else if (sa == NULL) + else if (result == NULL) return (0); - (void)config_free_proposals(&sa->sa_proposals, vpeer.prop_protoid); - prop = config_add_proposal(&sa->sa_proposals, vpeer.prop_id, - vpeer.prop_protoid); + (void)config_free_proposals(result, vpeer.prop_protoid); + prop = config_add_proposal(result, vpeer.prop_id, vpeer.prop_protoid); if (vpeer.prop_localspi.spi_size) { prop->prop_localspi.spi_size = vpeer.prop_localspi.spi_size; @@ -2835,18 +3529,18 @@ ikev2_sa_negotiate(struct iked_sa *sa, struct iked_proposals *local, } for (i = 0; i < IKEV2_XFORMTYPE_MAX; i++) { - if (chosen[i] == NULL) + if (valid[i] == NULL) continue; print_debug("%s: score %d: %s %s", __func__, - chosen[i]->xform_score, print_map(i, ikev2_xformtype_map), - print_map(chosen[i]->xform_id, chosen[i]->xform_map)); - if (chosen[i]->xform_length) - print_debug(" %d", chosen[i]->xform_length); + chosen[i].xform_score, print_map(i, ikev2_xformtype_map), + print_map(chosen[i].xform_id, chosen[i].xform_map)); + if (chosen[i].xform_length) + print_debug(" %d", chosen[i].xform_length); print_debug("\n"); - if (config_add_transform(prop, chosen[i]->xform_type, - chosen[i]->xform_id, chosen[i]->xform_length, - chosen[i]->xform_keylength) == NULL) + if (config_add_transform(prop, chosen[i].xform_type, + chosen[i].xform_id, chosen[i].xform_length, + chosen[i].xform_keylength) == NULL) break; } @@ -2854,15 +3548,14 @@ ikev2_sa_negotiate(struct iked_sa *sa, struct iked_proposals *local, } int -ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, - struct iked_message *msg) +ikev2_sa_initiator_dh(struct iked_sa *sa, struct iked_message *msg, u_int proto) { struct iked_policy *pol = sa->sa_policy; struct iked_transform *xform; if (sa->sa_dhgroup == NULL) { if ((xform = config_findtransform(&pol->pol_proposals, - IKEV2_XFORMTYPE_DH)) == NULL) { + IKEV2_XFORMTYPE_DH, proto)) == NULL) { log_debug("%s: did not find dh transform", __func__); return (-1); } @@ -2887,28 +3580,10 @@ ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, } } - if (!ibuf_length(sa->sa_inonce)) { - if ((sa->sa_inonce = ibuf_random(IKED_NONCE_SIZE)) == NULL) { - log_debug("%s: failed to get local nonce", __func__); - return (-1); - } - } - /* Initial message */ if (msg == NULL) return (0); - if (!ibuf_length(sa->sa_rnonce)) { - if (!ibuf_length(msg->msg_nonce)) { - log_debug("%s: invalid peer nonce", __func__); - return (-1); - } - if ((sa->sa_rnonce = ibuf_dup(msg->msg_nonce)) == NULL) { - log_debug("%s: failed to get peer nonce", __func__); - return (-1); - } - } - if (!ibuf_length(sa->sa_dhrexchange)) { if (!ibuf_length(msg->msg_ke)) { log_debug("%s: invalid peer dh exchange", __func__); @@ -2928,10 +3603,43 @@ ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, /* Set a pointer to the peer exchange */ sa->sa_dhpeer = sa->sa_dhrexchange; + return (0); +} + +int +ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, + struct iked_sa *osa, struct iked_message *msg) +{ + struct iked_transform *xform; + + if (ikev2_sa_initiator_dh(sa, msg, 0) < 0) + return (-1); + + if (!ibuf_length(sa->sa_inonce)) { + if ((sa->sa_inonce = ibuf_random(IKED_NONCE_SIZE)) == NULL) { + log_debug("%s: failed to get local nonce", __func__); + return (-1); + } + } + + /* Initial message */ + if (msg == NULL) + return (0); + + if (!ibuf_length(sa->sa_rnonce)) { + if (!ibuf_length(msg->msg_nonce)) { + log_debug("%s: invalid peer nonce", __func__); + return (-1); + } + if ((sa->sa_rnonce = ibuf_dup(msg->msg_nonce)) == NULL) { + log_debug("%s: failed to get peer nonce", __func__); + return (-1); + } + } /* XXX we need a better way to get this */ - if (ikev2_sa_negotiate(sa, &msg->msg_policy->pol_proposals, - &msg->msg_proposals) != 0) { + if (ikev2_sa_negotiate(&sa->sa_proposals, + &msg->msg_policy->pol_proposals, &msg->msg_proposals) != 0) { log_debug("%s: no proposal chosen", __func__); msg->msg_error = IKEV2_N_NO_PROPOSAL_CHOSEN; return (-1); @@ -2940,7 +3648,7 @@ ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, if (sa->sa_encr == NULL) { if ((xform = config_findtransform(&sa->sa_proposals, - IKEV2_XFORMTYPE_ENCR)) == NULL) { + IKEV2_XFORMTYPE_ENCR, 0)) == NULL) { log_debug("%s: did not find encr transform", __func__); return (-1); } @@ -2953,7 +3661,7 @@ ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, if (sa->sa_prf == NULL) { if ((xform = config_findtransform(&sa->sa_proposals, - IKEV2_XFORMTYPE_PRF)) == NULL) { + IKEV2_XFORMTYPE_PRF, 0)) == NULL) { log_debug("%s: did not find prf transform", __func__); return (-1); } @@ -2966,7 +3674,7 @@ ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, if (sa->sa_integr == NULL) { if ((xform = config_findtransform(&sa->sa_proposals, - IKEV2_XFORMTYPE_INTEGR)) == NULL) { + IKEV2_XFORMTYPE_INTEGR, 0)) == NULL) { log_debug("%s: did not find integr transform", __func__); return (-1); @@ -2984,9 +3692,57 @@ ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, return (-1); } - return (ikev2_sa_keys(env, sa, NULL)); + return (ikev2_sa_keys(env, sa, osa ? osa->sa_key_d : NULL)); } +int +ikev2_sa_responder_dh(struct iked_kex *kex, struct iked_proposals *proposals, + struct iked_message *msg, u_int proto) +{ + struct iked_transform *xform; + + if (kex->kex_dhgroup == NULL) { + if ((xform = config_findtransform(proposals, + IKEV2_XFORMTYPE_DH, proto)) == NULL) { + log_debug("%s: did not find dh transform", __func__); + return (-1); + } + if ((kex->kex_dhgroup = + group_get(xform->xform_id)) == NULL) { + log_debug("%s: invalid dh %d", __func__, + xform->xform_id); + return (-1); + } + } + + if (!ibuf_length(kex->kex_dhrexchange)) { + if ((kex->kex_dhrexchange = ibuf_new(NULL, + dh_getlen(kex->kex_dhgroup))) == NULL) { + log_debug("%s: failed to alloc dh exchange", __func__); + return (-1); + } + if (dh_create_exchange(kex->kex_dhgroup, + kex->kex_dhrexchange->buf) == -1) { + log_debug("%s: failed to get dh exchange", __func__); + return (-1); + } + } + + if (!ibuf_length(kex->kex_dhiexchange)) { + if ((kex->kex_dhiexchange = ibuf_dup(msg->msg_ke)) == NULL || + ((ssize_t)ibuf_length(kex->kex_dhiexchange) != + dh_getlen(kex->kex_dhgroup))) { + /* XXX send notification to peer */ + log_debug("%s: invalid dh, size %d", __func__, + dh_getlen(kex->kex_dhgroup) * 8); + return (-1); + } + } + + /* Set a pointer to the peer exchange */ + kex->kex_dhpeer = kex->kex_dhiexchange; + return (0); +} int ikev2_sa_responder(struct iked *env, struct iked_sa *sa, struct iked_sa *osa, struct iked_message *msg) @@ -3015,8 +3771,8 @@ ikev2_sa_responder(struct iked *env, struct iked_sa *sa, struct iked_sa *osa, } /* XXX we need a better way to get this */ - if (ikev2_sa_negotiate(sa, &msg->msg_policy->pol_proposals, - &msg->msg_proposals) != 0) { + if (ikev2_sa_negotiate(&sa->sa_proposals, + &msg->msg_policy->pol_proposals, &msg->msg_proposals) != 0) { log_debug("%s: no proposal chosen", __func__); msg->msg_error = IKEV2_N_NO_PROPOSAL_CHOSEN; return (-1); @@ -3025,7 +3781,7 @@ ikev2_sa_responder(struct iked *env, struct iked_sa *sa, struct iked_sa *osa, if (sa->sa_encr == NULL) { if ((xform = config_findtransform(&sa->sa_proposals, - IKEV2_XFORMTYPE_ENCR)) == NULL) { + IKEV2_XFORMTYPE_ENCR, 0)) == NULL) { log_debug("%s: did not find encr transform", __func__); return (-1); } @@ -3038,7 +3794,7 @@ ikev2_sa_responder(struct iked *env, struct iked_sa *sa, struct iked_sa *osa, if (sa->sa_prf == NULL) { if ((xform = config_findtransform(&sa->sa_proposals, - IKEV2_XFORMTYPE_PRF)) == NULL) { + IKEV2_XFORMTYPE_PRF, 0)) == NULL) { log_debug("%s: did not find prf transform", __func__); return (-1); } @@ -3051,7 +3807,7 @@ ikev2_sa_responder(struct iked *env, struct iked_sa *sa, struct iked_sa *osa, if (sa->sa_integr == NULL) { if ((xform = config_findtransform(&sa->sa_proposals, - IKEV2_XFORMTYPE_INTEGR)) == NULL) { + IKEV2_XFORMTYPE_INTEGR, 0)) == NULL) { log_debug("%s: did not find integr transform", __func__); return (-1); @@ -3063,45 +3819,8 @@ ikev2_sa_responder(struct iked *env, struct iked_sa *sa, struct iked_sa *osa, } } - if (sa->sa_dhgroup == NULL) { - if ((xform = config_findtransform(&sa->sa_proposals, - IKEV2_XFORMTYPE_DH)) == NULL) { - log_debug("%s: did not find dh transform", __func__); - return (-1); - } - if ((sa->sa_dhgroup = - group_get(xform->xform_id)) == NULL) { - log_debug("%s: invalid dh", __func__); - return (-1); - } - } - - if (!ibuf_length(sa->sa_dhrexchange)) { - if ((sa->sa_dhrexchange = ibuf_new(NULL, - dh_getlen(sa->sa_dhgroup))) == NULL) { - log_debug("%s: failed to alloc dh exchange", __func__); - return (-1); - } - if (dh_create_exchange(sa->sa_dhgroup, - sa->sa_dhrexchange->buf) == -1) { - log_debug("%s: failed to get dh exchange", __func__); - return (-1); - } - } - - if (!ibuf_length(sa->sa_dhiexchange)) { - if ((sa->sa_dhiexchange = ibuf_dup(msg->msg_ke)) == NULL || - ((ssize_t)ibuf_length(sa->sa_dhiexchange) != - dh_getlen(sa->sa_dhgroup))) { - /* XXX send notification to peer */ - log_debug("%s: invalid dh, size %d", __func__, - dh_getlen(sa->sa_dhgroup) * 8); - return (-1); - } - } - - /* Set a pointer to the peer exchange */ - sa->sa_dhpeer = sa->sa_dhiexchange; + if (ikev2_sa_responder_dh(&sa->sa_kex, &sa->sa_proposals, msg, 0) < 0) + return (-1); return (ikev2_sa_keys(env, sa, osa ? osa->sa_key_d : NULL)); } @@ -3171,7 +3890,7 @@ ikev2_sa_keys(struct iked *env, struct iked_sa *sa, struct ibuf *key) if (dh_create_shared(group, dhsecret->buf, sa->sa_dhpeer->buf) == -1) { log_debug("%s: failed to get dh secret" - " group %d len %d secret %d exchange %d", __func__, + " group %d len %d secret %zu exchange %zu", __func__, group->id, dh_getlen(group), ibuf_length(dhsecret), ibuf_length(sa->sa_dhpeer)); goto done; @@ -3215,7 +3934,7 @@ ikev2_sa_keys(struct iked *env, struct iked_sa *sa, struct ibuf *key) hash_update(prf, dhsecret->buf, ibuf_length(dhsecret)); hash_final(prf, skeyseed->buf, &tmplen); - log_debug("%s: SKEYSEED with %d bytes", __func__, tmplen); + log_debug("%s: SKEYSEED with %zu bytes", __func__, tmplen); print_hex(skeyseed->buf, 0, tmplen); if (ibuf_setsize(skeyseed, tmplen) == -1) { @@ -3243,7 +3962,7 @@ ikev2_sa_keys(struct iked *env, struct iked_sa *sa, struct ibuf *key) goto done; } - log_debug("%s: S with %d bytes", __func__, ibuf_length(s)); + log_debug("%s: S with %zu bytes", __func__, ibuf_length(s)); print_hex(s->buf, 0, ibuf_length(s)); /* @@ -3275,25 +3994,25 @@ ikev2_sa_keys(struct iked *env, struct iked_sa *sa, struct ibuf *key) goto done; } - log_debug("%s: SK_d with %d bytes", __func__, + log_debug("%s: SK_d with %zu bytes", __func__, ibuf_length(sa->sa_key_d)); print_hex(sa->sa_key_d->buf, 0, ibuf_length(sa->sa_key_d)); - log_debug("%s: SK_ai with %d bytes", __func__, + log_debug("%s: SK_ai with %zu bytes", __func__, ibuf_length(sa->sa_key_iauth)); print_hex(sa->sa_key_iauth->buf, 0, ibuf_length(sa->sa_key_iauth)); - log_debug("%s: SK_ar with %d bytes", __func__, + log_debug("%s: SK_ar with %zu bytes", __func__, ibuf_length(sa->sa_key_rauth)); print_hex(sa->sa_key_rauth->buf, 0, ibuf_length(sa->sa_key_rauth)); - log_debug("%s: SK_ei with %d bytes", __func__, + log_debug("%s: SK_ei with %zu bytes", __func__, ibuf_length(sa->sa_key_iencr)); print_hex(sa->sa_key_iencr->buf, 0, ibuf_length(sa->sa_key_iencr)); - log_debug("%s: SK_er with %d bytes", __func__, + log_debug("%s: SK_er with %zu bytes", __func__, ibuf_length(sa->sa_key_rencr)); print_hex(sa->sa_key_rencr->buf, 0, ibuf_length(sa->sa_key_rencr)); - log_debug("%s: SK_pi with %d bytes", __func__, + log_debug("%s: SK_pi with %zu bytes", __func__, ibuf_length(sa->sa_key_iprf)); print_hex(sa->sa_key_iprf->buf, 0, ibuf_length(sa->sa_key_iprf)); - log_debug("%s: SK_pr with %d bytes", __func__, + log_debug("%s: SK_pr with %zu bytes", __func__, ibuf_length(sa->sa_key_rprf)); print_hex(sa->sa_key_rprf->buf, 0, ibuf_length(sa->sa_key_rprf)); @@ -3309,6 +4028,17 @@ ikev2_sa_keys(struct iked *env, struct iked_sa *sa, struct ibuf *key) return (ret); } +void +ikev2_sa_cleanup_dh(struct iked_sa *sa) +{ + ibuf_release(sa->sa_dhiexchange); + ibuf_release(sa->sa_dhrexchange); + group_free(sa->sa_dhgroup); + sa->sa_dhiexchange = NULL; + sa->sa_dhrexchange = NULL; + sa->sa_dhgroup = NULL; +} + struct ibuf * ikev2_prfplus(struct iked_hash *prf, struct ibuf *key, struct ibuf *seed, size_t keymatlen) @@ -3362,12 +4092,12 @@ ikev2_prfplus(struct iked_hash *prf, struct ibuf *key, struct ibuf *seed, ibuf_release(t2); ibuf_add(t, t1->buf, ibuf_length(t1)); - log_debug("%s: T%d with %d bytes", __func__, + log_debug("%s: T%d with %zu bytes", __func__, pad, ibuf_length(t1)); print_hex(t1->buf, 0, ibuf_length(t1)); } - log_debug("%s: Tn with %d bytes", __func__, ibuf_length(t)); + log_debug("%s: Tn with %zu bytes", __func__, ibuf_length(t)); print_hex(t->buf, 0, ibuf_length(t)); ibuf_release(t1); @@ -3453,7 +4183,7 @@ ikev2_sa_tag(struct iked_sa *sa, struct iked_id *id) } } - log_debug("%s: %s (%d)", __func__, sa->sa_tag, strlen(sa->sa_tag)); + log_debug("%s: %s (%zu)", __func__, sa->sa_tag, strlen(sa->sa_tag)); ret = 0; fail: @@ -3466,14 +4196,16 @@ ikev2_sa_tag(struct iked_sa *sa, struct iked_id *id) } int -ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) +ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, + struct iked_kex *kex, struct iked_proposals *proposals, int initiator, + int pfs) { struct iked_proposal *prop; struct iked_transform *xform, *encrxf = NULL, *integrxf = NULL; struct iked_childsa *csa, *csb; struct iked_flow *flow, *saflow, *flowa, *flowb; - struct iked_id *peerid, *localid; - struct ibuf *keymat = NULL, *seed = NULL; + struct ibuf *keymat = NULL, *seed = NULL, *dhsecret = NULL; + struct group *group; u_int32_t spi = 0; u_int i; size_t ilen = 0; @@ -3482,19 +4214,11 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) if (!sa_stateok(sa, IKEV2_STATE_VALID)) return (-1); - if (sa->sa_hdr.sh_initiator) { - peerid = &sa->sa_rid; - localid = &sa->sa_iid; - } else { - peerid = &sa->sa_iid; - localid = &sa->sa_rid; - } - - if (ikev2_sa_tag(sa, peerid) == -1) + if (ikev2_sa_tag(sa, IKESA_DSTID(sa)) == -1) return (-1); /* We need to determine the key material length first */ - TAILQ_FOREACH(prop, &sa->sa_proposals, prop_entry) { + TAILQ_FOREACH(prop, proposals, prop_entry) { if (prop->prop_protoid == IKEV2_SAPROTO_IKE) continue; log_debug("%s: proposal %d", __func__, prop->prop_id); @@ -3522,10 +4246,38 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) /* double key material length for inbound/outbound */ ilen *= 2; - log_debug("%s: key material length %d", __func__, ilen); + log_debug("%s: key material length %zu", __func__, ilen); - if ((seed = ibuf_dup(sa->sa_inonce)) == NULL || - ibuf_cat(seed, sa->sa_rnonce) != 0 || + if ((seed = ibuf_new(NULL, 0)) == NULL) { + log_debug("%s: failed to setup IKE SA key material", __func__); + goto done; + } + if (pfs) { + log_debug("%s: using PFS", __func__); + if (kex->kex_dhpeer == NULL || ibuf_length(kex->kex_dhpeer) == 0 || + (group = kex->kex_dhgroup) == NULL) { + log_debug("%s: no dh group for pfs", __func__); + goto done; + } + if ((dhsecret = ibuf_new(NULL, dh_getlen(group))) == NULL) { + log_debug("%s: failed to alloc dh secret", __func__); + goto done; + } + if (dh_create_shared(group, dhsecret->buf, + kex->kex_dhpeer->buf) == -1) { + log_debug("%s: failed to get dh secret" + " group %d len %d secret %zu exchange %zu", __func__, + group->id, dh_getlen(group), ibuf_length(dhsecret), + ibuf_length(kex->kex_dhpeer)); + goto done; + } + if (ibuf_cat(seed, dhsecret) != 0) { + log_debug("%s: failed to set dh secret", __func__); + goto done; + } + } + if (ibuf_cat(seed, kex->kex_inonce) != 0 || + ibuf_cat(seed, kex->kex_rnonce) != 0 || (keymat = ikev2_prfplus(sa->sa_prf, sa->sa_key_d, seed, ilen)) == NULL) { log_debug("%s: failed to get IKE SA key material", __func__); @@ -3533,7 +4285,7 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) } /* Create the new flows */ - TAILQ_FOREACH(prop, &sa->sa_proposals, prop_entry) { + TAILQ_FOREACH(prop, proposals, prop_entry) { if (ikev2_valid_proposal(prop, NULL, NULL, NULL) != 0) continue; @@ -3544,8 +4296,11 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) &flow->flow_src) && IKED_ADDR_EQ(&saflow->flow_dst, &flow->flow_dst) && - saflow->flow_saproto == prop->prop_protoid) + saflow->flow_saproto == + prop->prop_protoid) { skip = 1; + break; + } } if (skip) continue; @@ -3558,11 +4313,10 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) memcpy(flowa, flow, sizeof(*flow)); flowa->flow_dir = IPSP_DIRECTION_OUT; flowa->flow_saproto = prop->prop_protoid; - flowa->flow_srcid = localid; - flowa->flow_dstid = peerid; flowa->flow_local = &sa->sa_local; flowa->flow_peer = &sa->sa_peer; flowa->flow_ikesa = sa; + ikev2_cp_fixaddr(sa, &flow->flow_dst, &flowa->flow_dst); if ((flowb = calloc(1, sizeof(*flowb))) == NULL) { log_debug("%s: failed to get flow", __func__); @@ -3577,6 +4331,7 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) sizeof(flow->flow_dst)); memcpy(&flowb->flow_dst, &flow->flow_src, sizeof(flow->flow_src)); + ikev2_cp_fixaddr(sa, &flow->flow_dst, &flowb->flow_src); TAILQ_INSERT_TAIL(&sa->sa_flows, flowa, flow_entry); TAILQ_INSERT_TAIL(&sa->sa_flows, flowb, flow_entry); @@ -3584,7 +4339,7 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) } /* create the CHILD SAs using the key material */ - TAILQ_FOREACH(prop, &sa->sa_proposals, prop_entry) { + TAILQ_FOREACH(prop, proposals, prop_entry) { if (ikev2_valid_proposal(prop, &encrxf, &integrxf, &esn) != 0) continue; @@ -3597,8 +4352,6 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) csa->csa_saproto = prop->prop_protoid; csa->csa_ikesa = sa; - csa->csa_srcid = localid; - csa->csa_dstid = peerid; csa->csa_spi.spi_protoid = prop->prop_protoid; csa->csa_esn = esn; @@ -3639,8 +4392,10 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) childsa_free(csa); goto done; } - csa->csa_encrxf = encrxf; - csa->csa_integrxf = integrxf; + if (encrxf) + csa->csa_encrid = encrxf->xform_id; + if (integrxf) + csa->csa_integrid = integrxf->xform_id; if ((csb = calloc(1, sizeof(*csb))) == NULL) { log_debug("%s: failed to get CHILD SA", __func__); @@ -3685,17 +4440,183 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) ret = 0; done: + ibuf_release(dhsecret); ibuf_release(keymat); ibuf_release(seed); return (ret); } +/* free a replaced IPCOMP SA */ +void +ikev2_ipcomp_csa_free(struct iked *env, struct iked_childsa *csa) +{ + if (csa->csa_children) + fatalx("ikev2_ipcomp_csa_free: has children"); + if (csa->csa_ikesa) + TAILQ_REMOVE(&csa->csa_ikesa->sa_childsas, csa, + csa_entry); + if (csa->csa_loaded) { + log_debug("%s: csa %p loaded: calling pfkey_sa_delete", + __func__, csa); + pfkey_sa_delete(env->sc_pfkey, csa); + RB_REMOVE(iked_activesas, &env->sc_activesas, csa); + } + childsa_free(csa); +} + +int +ikev2_ipcomp_enable(struct iked *env, struct iked_sa *sa) +{ + struct iked_childsa *other, *nother, *csa = NULL, *csb = NULL; + struct iked_flow *flow, *flowa = NULL, *flowb = NULL; + struct iked_flow *nflow, *oflow; + + if ((csa = calloc(1, sizeof(*csa))) == NULL || + (csb = calloc(1, sizeof(*csb))) == NULL || + (flowa = calloc(1, sizeof(*flowa))) == NULL || + (flowb = calloc(1, sizeof(*flowb))) == NULL) { + free(csa); + free(csb); + free(flowa); + free(flowb); + return (-1); + } + + /* switch ESP SAs to transport mode */ + TAILQ_FOREACH(other, &sa->sa_childsas, csa_entry) { + if (!other->csa_rekey && !other->csa_loaded && + other->csa_saproto == IKEV2_SAPROTO_ESP) { + other->csa_transport = 1; + if (other->csa_dir == IPSP_DIRECTION_OUT) { + other->csa_parent = csa; + csa->csa_children++; + } else { + other->csa_parent = csb; + csb->csa_children++; + } + } + } + + /* install IPCOMP SAs */ + csa->csa_ikesa = sa; + csa->csa_saproto = IKEV2_SAPROTO_IPCOMP; + csa->csa_spi.spi_size = 2; + csa->csa_spi.spi = sa->sa_cpi_out; + csa->csa_peerspi = sa->sa_cpi_in; + csa->csa_dir = IPSP_DIRECTION_OUT; + csa->csa_local = &sa->sa_local; + csa->csa_peer = &sa->sa_peer; + + memcpy(csb, csa, sizeof(*csb)); + csb->csa_spi.spi = csa->csa_peerspi; + csb->csa_peerspi = csa->csa_spi.spi; + csb->csa_dir = IPSP_DIRECTION_IN; + csb->csa_local = csa->csa_peer; + csb->csa_peer = csa->csa_local; + csb->csa_allocated = 1; + + /* remove old replaced IPCOMP SAs */ + TAILQ_FOREACH_SAFE(other, &sa->sa_childsas, csa_entry, nother) { + if (other->csa_saproto != IKEV2_SAPROTO_IPCOMP || + other->csa_children != 0) + continue; + if (other->csa_dir == csa->csa_dir && + IKED_ADDR_EQ(other->csa_local, csa->csa_local) && + IKED_ADDR_EQ(other->csa_peer, csa->csa_peer)) { + log_debug("%s: csa %p replaces %p", + __func__, csa, other); + ikev2_ipcomp_csa_free(env, other); + } else if (other->csa_dir == csb->csa_dir && + IKED_ADDR_EQ(other->csa_local, csb->csa_local) && + IKED_ADDR_EQ(other->csa_peer, csb->csa_peer)) { + log_debug("%s: csa %p replaces %p", + __func__, csb, other); + ikev2_ipcomp_csa_free(env, other); + } + } + + TAILQ_INSERT_TAIL(&sa->sa_childsas, csa, csa_entry); + TAILQ_INSERT_TAIL(&sa->sa_childsas, csb, csa_entry); + + csa->csa_peersa = csb; + csb->csa_peersa = csa; + + /* redirect flows to IPCOMP */ + /* XXX expensive? should be merged into ikev2_childsa_negotiate() */ + TAILQ_FOREACH_SAFE(flow, &sa->sa_flows, flow_entry, nflow) { + if (flow->flow_loaded || + flow->flow_saproto != IKEV2_SAPROTO_ESP) + continue; + TAILQ_FOREACH(oflow, &sa->sa_flows, flow_entry) + if (IKED_ADDR_EQ(&oflow->flow_src, &flow->flow_src) && + IKED_ADDR_EQ(&oflow->flow_dst, &flow->flow_dst) && + oflow->flow_dir == flow->flow_dir && + oflow->flow_saproto == IKEV2_SAPROTO_IPCOMP) + break; + if (oflow != NULL) { + log_debug("%s: keeping oflow %p, indentical to flow %p", + __func__, oflow, flow); + TAILQ_REMOVE(&sa->sa_flows, flow, flow_entry); + flow_free(flow); + } else { + log_debug("%s: flow %p saproto %d -> %d", __func__, + flow, flow->flow_saproto, IKEV2_SAPROTO_IPCOMP); + flow->flow_saproto = IKEV2_SAPROTO_IPCOMP; + } + } + + /* setup ESP flows for gateways */ + flowa->flow_dir = IPSP_DIRECTION_OUT; + flowa->flow_saproto = IKEV2_SAPROTO_ESP; + flowa->flow_local = &sa->sa_local; + flowa->flow_peer = &sa->sa_peer; + memcpy(&flowa->flow_src, &sa->sa_local, sizeof(sa->sa_local)); + memcpy(&flowa->flow_dst, &sa->sa_peer, sizeof(sa->sa_peer)); + socket_setport((struct sockaddr *)&flowa->flow_src.addr, 0); + socket_setport((struct sockaddr *)&flowa->flow_dst.addr, 0); + flowa->flow_src.addr_port = flowa->flow_dst.addr_port = 0; + flowa->flow_src.addr_mask = flowa->flow_dst.addr_mask = + (sa->sa_local.addr_af == AF_INET) ? 32 : 128; + flowa->flow_ikesa = sa; + + /* skip if flow already exists */ + TAILQ_FOREACH(flow, &sa->sa_flows, flow_entry) { + if (IKED_ADDR_EQ(&flow->flow_src, &flowa->flow_src) && + IKED_ADDR_EQ(&flow->flow_dst, &flowa->flow_dst) && + flow->flow_dir == flowa->flow_dir && + flow->flow_saproto == flowa->flow_saproto) { + free(flowa); + free(flowb); + goto done; + } + } + + memcpy(flowb, flowa, sizeof(*flowb)); + flowb->flow_dir = IPSP_DIRECTION_IN; + memcpy(&flowb->flow_dst, &flowa->flow_src, sizeof(flowa->flow_src)); + memcpy(&flowb->flow_src, &flowa->flow_dst, sizeof(flowa->flow_dst)); + + TAILQ_INSERT_TAIL(&sa->sa_flows, flowa, flow_entry); + TAILQ_INSERT_TAIL(&sa->sa_flows, flowb, flow_entry); + + done: + /* make sure IPCOMP CPIs are not reused */ + sa->sa_ipcomp = 0; + sa->sa_cpi_in = sa->sa_cpi_out = 0; + + return (0); +} + int ikev2_childsa_enable(struct iked *env, struct iked_sa *sa) { struct iked_childsa *csa; - struct iked_flow *flow; + struct iked_flow *flow, *oflow; + + if (sa->sa_ipcomp && sa->sa_cpi_in && sa->sa_cpi_out && + ikev2_ipcomp_enable(env, sa) == -1) + return (-1); TAILQ_FOREACH(csa, &sa->sa_childsas, csa_entry) { if (csa->csa_rekey || csa->csa_loaded) @@ -3723,6 +4644,14 @@ ikev2_childsa_enable(struct iked *env, struct iked_sa *sa) return (-1); } + if ((oflow = RB_FIND(iked_flows, &env->sc_activeflows, flow)) + != NULL) { + log_debug("%s: replaced old flow %p with %p", + __func__, oflow, flow); + oflow->flow_loaded = 0; + RB_REMOVE(iked_flows, &env->sc_activeflows, oflow); + } + RB_INSERT(iked_flows, &env->sc_activeflows, flow); log_debug("%s: loaded flow %p", __func__, flow); @@ -3822,19 +4751,17 @@ ikev2_valid_proposal(struct iked_proposal *prop, return (0); } -void +/* return 0 if processed, -1 if busy */ +int ikev2_acquire_sa(struct iked *env, struct iked_flow *acquire) { struct iked_flow *flow; struct iked_sa *sa; -#if defined(_OPENBSD_IPSEC_API_VERSION) struct iked_policy pol, *p = NULL; -#endif if (env->sc_passive) - return; + return (0); -#if defined(_OPENBSD_IPSEC_API_VERSION) /* First try to find an active flow with IKE SA */ flow = RB_FIND(iked_flows, &env->sc_activeflows, acquire); if (!flow) { @@ -3850,7 +4777,7 @@ ikev2_acquire_sa(struct iked *env, struct iked_flow *acquire) if ((p = policy_test(env, &pol)) == NULL) { log_warnx("%s: flow wasn't found", __func__); - return; + return (0); } log_debug("%s: found matching policy '%s'", __func__, @@ -3860,21 +4787,20 @@ ikev2_acquire_sa(struct iked *env, struct iked_flow *acquire) log_warnx("%s: failed to initiate a " "IKE_SA_INIT exchange", __func__); } else { -#else - if ((flow = acquire) != NULL) { -#endif log_debug("%s: found active flow", __func__); if ((sa = flow->flow_ikesa) == NULL) { log_warnx("%s: flow without SA", __func__); - return; + return (0); } - + if (sa->sa_stateflags & IKED_REQ_CHILDSA) + return (-1); /* busy, retry later */ if (ikev2_send_create_child_sa(env, sa, NULL, flow->flow_saproto) != 0) log_warnx("%s: failed to initiate a " "CREATE_CHILD_SA exchange", __func__); } + return (0); } void @@ -3890,7 +4816,8 @@ ikev2_disable_rekeying(struct iked *env, struct iked_sa *sa) (void)ikev2_childsa_delete(env, sa, 0, 0, NULL, 1); } -void +/* return 0 if processed, -1 if busy */ +int ikev2_rekey_sa(struct iked *env, struct iked_spi *rekey) { struct iked_childsa *csa, key; @@ -3899,28 +4826,34 @@ ikev2_rekey_sa(struct iked *env, struct iked_spi *rekey) key.csa_spi = *rekey; csa = RB_FIND(iked_activesas, &env->sc_activesas, &key); if (!csa) - return; + return (0); if (csa->csa_rekey) /* See if it's already taken care of */ - return; + return (0); + if (csa->csa_saproto == IKEV2_SAPROTO_IPCOMP) /* no rekey */ + return (0); if ((sa = csa->csa_ikesa) == NULL) { log_warnx("%s: SA %s doesn't have a parent SA", __func__, print_spi(rekey->spi, rekey->spi_size)); - return; + return (0); } if (!sa_stateok(sa, IKEV2_STATE_ESTABLISHED)) { log_warnx("%s: SA %s is not established", __func__, print_spi(rekey->spi, rekey->spi_size)); - return; + return (0); } + if (sa->sa_stateflags & IKED_REQ_CHILDSA) + return (-1); /* busy, retry later */ if (csa->csa_allocated) /* Peer SPI died first, get the local one */ rekey->spi = csa->csa_peerspi; if (ikev2_send_create_child_sa(env, sa, rekey, rekey->spi_protoid)) log_warnx("%s: failed to initiate a CREATE_CHILD_SA exchange", __func__); + return (0); } -void +/* return 0 if processed, -1 if busy */ +int ikev2_drop_sa(struct iked *env, struct iked_spi *drop) { struct ibuf *buf = NULL; @@ -3932,18 +4865,25 @@ ikev2_drop_sa(struct iked *env, struct iked_spi *drop) key.csa_spi = *drop; csa = RB_FIND(iked_activesas, &env->sc_activesas, &key); if (!csa || csa->csa_rekey) - return; + return (0); + + sa = csa->csa_ikesa; + if (sa && (sa->sa_stateflags & IKED_REQ_CHILDSA)) + return (-1); /* busy, retry later */ + RB_REMOVE(iked_activesas, &env->sc_activesas, csa); csa->csa_loaded = 0; - if ((sa = csa->csa_ikesa) == NULL) { + csa->csa_rekey = 1; /* prevent re-loading */ + if (sa == NULL) { log_debug("%s: failed to find a parent SA", __func__); - return; + return (0); + } + if (csa->csa_saproto == IKEV2_SAPROTO_IPCOMP) { + /* matching Child SAs (e.g. ESP) should have expired by now */ + if (csa->csa_children == 0) + ikev2_ipcomp_csa_free(env, csa); + return (0); } - - if ((buf = ibuf_static()) == NULL) - goto done; - if ((del = ibuf_advance(buf, sizeof(*del))) == NULL) - goto done; if (csa->csa_allocated) spi32 = htobe32(csa->csa_spi.spi); @@ -3958,7 +4898,7 @@ ikev2_drop_sa(struct iked *env, struct iked_spi *drop) /* Send PAYLOAD_DELETE */ if ((buf = ibuf_static()) == NULL) - return; + return (0); if ((del = ibuf_advance(buf, sizeof(*del))) == NULL) goto done; del->del_protoid = drop->spi_protoid; @@ -3980,7 +4920,7 @@ ikev2_drop_sa(struct iked *env, struct iked_spi *drop) done: ibuf_release(buf); - return; + return (0); } int @@ -4022,12 +4962,10 @@ ikev2_print_id(struct iked_id *id, char *idstr, size_t idstrlen) case IKEV2_ID_IPV4: s4 = (struct sockaddr_in *)buf; s4->sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN s4->sin_len = sizeof(*s4); -#endif memcpy(&s4->sin_addr.s_addr, ptr, len); - if (print_host((struct sockaddr_storage *)s4, + if (print_host((struct sockaddr *)s4, idstr, idstrlen) == NULL) return (-1); break; @@ -4048,12 +4986,10 @@ ikev2_print_id(struct iked_id *id, char *idstr, size_t idstrlen) case IKEV2_ID_IPV6: s6 = (struct sockaddr_in6 *)buf; s6->sin6_family = AF_INET6; -#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN s6->sin6_len = sizeof(*s6); -#endif memcpy(&s6->sin6_addr, ptr, len); - if (print_host((struct sockaddr_storage *)s6, + if (print_host((struct sockaddr *)s6, idstr, idstrlen) == NULL) return (-1); break; @@ -4076,3 +5012,144 @@ ikev2_print_id(struct iked_id *id, char *idstr, size_t idstrlen) return (0); } + +/* + * If we have an IKEV2_CP_REQUEST for IKEV2_CFG_INTERNAL_IP4_ADDRESS and + * if a network(pool) is configured, then select an address from that pool + * and remember it in the sa_addrpool attribute. + */ +int +ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa) +{ + struct iked_cfg *ikecfg = NULL; + struct iked_policy *pol = sa->sa_policy; + struct sockaddr_in *in4 = NULL, *cfg4 = NULL; + struct sockaddr_in6 *in6 = NULL, *cfg6 = NULL; + struct iked_sa key; + struct iked_addr addr; + u_int32_t mask, host, lower, upper, start; + size_t i; + + if (sa->sa_addrpool || pol->pol_ncfg == 0) + return (0); + /* check for an address pool config (address w/ prefixlen != 32) */ + bzero(&addr, sizeof(addr)); + for (i = 0; i < pol->pol_ncfg; i++) { + ikecfg = &pol->pol_cfg[i]; + if (ikecfg->cfg_type == IKEV2_CFG_INTERNAL_IP4_ADDRESS && + ikecfg->cfg.address.addr_mask != 32) { + addr.addr_af = AF_INET; + break; + } + if (ikecfg->cfg_type == IKEV2_CFG_INTERNAL_IP6_ADDRESS && + ikecfg->cfg.address.addr_mask != 128) { + addr.addr_af = AF_INET6; + break; + } + } + if (i == pol->pol_ncfg) + return (0); + + /* + * failure: pool configured, but not requested. + * If we continue, we might end up with flows where 0.0.0.0 is NOT + * replaced with an address from the pool with ikev2_cp_fixaddr(). + */ + if (sa->sa_cp != IKEV2_CP_REQUEST) { + log_debug("%s: pool configured, but IKEV2_CP_REQUEST missing", + __func__); + return (-1); + } + + /* truncate prefixlen in the v6 case */ + mask = prefixlen2mask(ikecfg->cfg.address.addr_mask); + + switch (addr.addr_af) { + case AF_INET: + cfg4 = (struct sockaddr_in *)&ikecfg->cfg.address.addr; + in4 = (struct sockaddr_in *)&addr.addr; + in4->sin_family = AF_INET; + in4->sin_len = sizeof(*in4); + lower = ntohl(cfg4->sin_addr.s_addr & ~mask); + break; + case AF_INET6: + cfg6 = (struct sockaddr_in6 *)&ikecfg->cfg.address.addr; + in6 = (struct sockaddr_in6 *)&addr.addr; + in6->sin6_family = AF_INET6; + in6->sin6_len = sizeof(*in6); + lower = cfg6->sin6_addr.s6_addr[3]; + break; + default: + return (-1); + } + + if (lower == 0) + lower = 1; + /* Note that start, upper and host are in HOST byte order */ + upper = ntohl(~mask); + /* Randomly select start from [lower, upper-1] */ + start = arc4random_uniform(upper - lower) + lower; + + key.sa_addrpool = &addr; + + for (host = start;;) { + log_debug("%s: mask %x start %x lower %x host %x upper %x", + __func__, mask, start, lower, host, upper); + switch (addr.addr_af) { + case AF_INET: + in4->sin_addr.s_addr = + (cfg4->sin_addr.s_addr & mask) | htonl(host); + break; + case AF_INET6: + memcpy(in6, cfg6, sizeof(*in6)); + in6->sin6_addr.s6_addr[3] = htonl(host); + break; + } + if (!RB_FIND(iked_addrpool, &env->sc_addrpool, &key)) + break; + /* try next address */ + host++; + /* but skip broadcast and network address */ + if (host >= upper || host < lower) + host = lower; + if (host == start) + return (-1); /* exhausted */ + } + if (!key.sa_addrpool) + return (-1); /* cannot happen? */ + if ((sa->sa_addrpool = calloc(1, sizeof(addr))) == NULL) + return (-1); + memcpy(sa->sa_addrpool, &addr, sizeof(addr)); + RB_INSERT(iked_addrpool, &env->sc_addrpool, sa); + return (0); +} + +/* + * if 'addr' is 'UNSPECIFIED' replace it with sa_addrpool from + * the ip-pool and store the result in 'patched'. + */ +int +ikev2_cp_fixaddr(struct iked_sa *sa, struct iked_addr *addr, + struct iked_addr *patched) +{ + struct sockaddr_in *in4; + struct sockaddr_in6 *in6; + + if (sa->sa_addrpool == NULL || + sa->sa_addrpool->addr_af != addr->addr_af) + return (-1); + switch (addr->addr_af) { + case AF_INET: + in4 = (struct sockaddr_in *)&addr->addr; + if (in4->sin_addr.s_addr) + return (-1); + break; + case AF_INET6: + in6 = (struct sockaddr_in6 *)&addr->addr; + if (IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) + return (-1); + break; + } + memcpy(patched, sa->sa_addrpool, sizeof(*patched)); + return (0); +} diff --git a/iked/ikev2.h b/iked/ikev2.h index 439e8ab..b794665 100644 --- a/iked/ikev2.h +++ b/iked/ikev2.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.h,v 1.12 2013/03/30 16:31:37 reyk Exp $ */ +/* $OpenBSD: ikev2.h,v 1.19 2015/06/11 18:49:09 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _IKEV2_H -#define _IKEV2_H +#ifndef IKED_IKEV2_H +#define IKED_IKEV2_H #define IKEV2_VERSION 0x20 /* IKE version 2.0 */ #define IKEV1_VERSION 0x10 /* IKE version 1.0 */ @@ -32,12 +32,14 @@ #define IKEV2_STATE_COOKIE 1 /* cookie requested */ #define IKEV2_STATE_SA_INIT 2 /* init IKE SA */ #define IKEV2_STATE_EAP 3 /* EAP requested */ -#define IKEV2_STATE_AUTH_REQUEST 4 /* auth received */ -#define IKEV2_STATE_AUTH_SUCCESS 5 /* authenticated */ -#define IKEV2_STATE_VALID 6 /* validated peer certs */ -#define IKEV2_STATE_EAP_VALID 7 /* EAP validated */ -#define IKEV2_STATE_ESTABLISHED 8 /* active IKE SA */ -#define IKEV2_STATE_CLOSED 9 /* delete this SA */ +#define IKEV2_STATE_EAP_SUCCESS 4 /* EAP succeeded */ +#define IKEV2_STATE_AUTH_REQUEST 5 /* auth received */ +#define IKEV2_STATE_AUTH_SUCCESS 6 /* authenticated */ +#define IKEV2_STATE_VALID 7 /* authenticated AND validated certs */ +#define IKEV2_STATE_EAP_VALID 8 /* EAP validated */ +#define IKEV2_STATE_ESTABLISHED 9 /* active IKE SA */ +#define IKEV2_STATE_CLOSING 10 /* expect delete for this SA */ +#define IKEV2_STATE_CLOSED 11 /* delete this SA */ extern struct iked_constmap ikev2_state_map[]; @@ -125,6 +127,7 @@ struct ikev2_sa_proposal { #define IKEV2_SAPROTO_ESP 3 /* ESP */ #define IKEV2_SAPROTO_FC_ESP_HEADER 4 /* RFC4595 */ #define IKEV2_SAPROTO_FC_CT_AUTH 5 /* RFC4595 */ +#define IKEV2_SAPROTO_IPCOMP 204 /* private, should be 4 */ extern struct iked_constmap ikev2_saproto_map[]; @@ -239,7 +242,7 @@ extern struct iked_constmap ikev2_xformauth_map[]; #define IKEV2_XFORMDH_BRAINPOOL_P256R1 28 /* DH Group 28 */ #define IKEV2_XFORMDH_BRAINPOOL_P384R1 29 /* DH Group 29 */ #define IKEV2_XFORMDH_BRAINPOOL_P512R1 30 /* DH Group 30 */ -#define IKEV2_XFORMDH_MAX 31 +#define IKEV2_XFORMDH_X_CURVE25519 1034 /* curve25519 */ extern struct iked_constmap ikev2_xformdh_map[]; @@ -347,6 +350,7 @@ struct ikev2_notify { #define IKEV2_N_PSK_CONFIRM 16426 /* RFC6631 */ #define IKEV2_N_ERX_SUPPORTED 16427 /* RFC6867 */ #define IKEV2_N_IFOM_CAPABILITY 16428 /* OA3GPP */ +#define IKEV2_N_SIGNATURE_HASH_ALGORITHMS 16431 /* RFC7427 */ extern struct iked_constmap ikev2_n_map[]; @@ -451,9 +455,20 @@ struct ikev2_auth { #define IKEV2_AUTH_ECDSA_384 10 /* RFC4754 */ #define IKEV2_AUTH_ECDSA_512 11 /* RFC4754 */ #define IKEV2_AUTH_GSPM 12 /* RFC6467 */ +#define IKEV2_AUTH_SIG 14 /* RFC7427 */ extern struct iked_constmap ikev2_auth_map[]; +/* Notifications used together with IKEV2_AUTH_SIG */ + +#define IKEV2_SIGHASH_RESERVED 0 /* RFC7427 */ +#define IKEV2_SIGHASH_SHA1 1 /* RFC7427 */ +#define IKEV2_SIGHASH_SHA2_256 2 /* RFC7427 */ +#define IKEV2_SIGHASH_SHA2_384 3 /* RFC7427 */ +#define IKEV2_SIGHASH_SHA2_512 4 /* RFC7427 */ + +extern struct iked_constmap ikev2_sighash_map[]; + /* * CP payload */ @@ -500,4 +515,4 @@ struct ikev2_cfg { extern struct iked_constmap ikev2_cfg_map[]; -#endif /* _IKEV2_H */ +#endif /* IKED_IKEV2_H */ diff --git a/iked/ikev2_msg.c b/iked/ikev2_msg.c index 12016c8..88ffefc 100644 --- a/iked/ikev2_msg.c +++ b/iked/ikev2_msg.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2_msg.c,v 1.25 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: ikev2_msg.c,v 1.42 2015/03/26 19:52:35 markus Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,23 +16,19 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include /* roundup */ +#include #include #include #include #include -#if defined(__OpenBSD__) -#include -#endif #include #include #include #include #include -#include #include #include #include @@ -77,8 +73,9 @@ ikev2_msg_cb(int fd, short event, void *arg) (ssize_t)sizeof(natt)) return; - if (socket_getport(&msg.msg_local) == IKED_NATT_PORT) { - if (bcmp(&natt, buf, sizeof(natt)) != 0) + if (socket_getport((struct sockaddr *)&msg.msg_local) == + IKED_NATT_PORT) { + if (memcmp(&natt, buf, sizeof(natt)) != 0) return; msg.msg_natt = 1; off = sizeof(natt); @@ -98,8 +95,8 @@ ikev2_msg_cb(int fd, short event, void *arg) iov[1].iov_base = buf; iov[1].iov_len = len; - proc_composev_imsg(env, PROC_IKEV1, IMSG_IKE_MESSAGE, -1, - iov, 2); + proc_composev_imsg(&env->sc_ps, PROC_IKEV1, -1, + IMSG_IKE_MESSAGE, -1, iov, 2); goto done; } TAILQ_INIT(&msg.msg_proposals); @@ -136,11 +133,14 @@ ikev2_msg_copy(struct iked *env, struct iked_message *msg) { struct iked_message *m = NULL; struct ibuf *buf; - ssize_t len; + size_t len; void *ptr; - if ((len = ibuf_size(msg->msg_data) - msg->msg_offset) <= 0 || - (ptr = ibuf_seek(msg->msg_data, msg->msg_offset, len)) == NULL || + if (ibuf_size(msg->msg_data) < msg->msg_offset) + return (NULL); + len = ibuf_size(msg->msg_data) - msg->msg_offset; + + if ((ptr = ibuf_seek(msg->msg_data, msg->msg_offset, len)) == NULL || (m = malloc(sizeof(*m))) == NULL || (buf = ikev2_msg_init(env, m, &msg->msg_peer, msg->msg_peerlen, &msg->msg_local, msg->msg_locallen, msg->msg_response)) == NULL || @@ -188,8 +188,22 @@ ikev2_msg_valid_ike_sa(struct iked *env, struct ike_header *oldhdr, struct iked_sa sa; #endif - if (msg->msg_sa != NULL && msg->msg_policy != NULL) + if (msg->msg_sa != NULL && msg->msg_policy != NULL) { + /* + * Only permit informational requests from initiator + * on closing SAs (for DELETE). + */ + if (msg->msg_sa->sa_state == IKEV2_STATE_CLOSING) { + if (((oldhdr->ike_flags & + (IKEV2_FLAG_INITIATOR|IKEV2_FLAG_RESPONSE)) == + IKEV2_FLAG_INITIATOR) && + (oldhdr->ike_exchange == + IKEV2_EXCHANGE_INFORMATIONAL)) + return (0); + return (-1); + } return (0); + } #if 0 /* @@ -258,6 +272,7 @@ ikev2_msg_send(struct iked *env, struct iked_message *msg) struct ibuf *buf = msg->msg_data; u_int32_t natt = 0x00000000; int isnatt = 0; + u_int8_t exchange, flags; struct ike_header *hdr; struct iked_message *m; @@ -267,10 +282,14 @@ ikev2_msg_send(struct iked *env, struct iked_message *msg) isnatt = (msg->msg_natt || (msg->msg_sa && msg->msg_sa->sa_natt)); - log_info("%s: %s from %s to %s, %ld bytes%s", __func__, - print_map(hdr->ike_exchange, ikev2_exchange_map), - print_host(&msg->msg_local, NULL, 0), - print_host(&msg->msg_peer, NULL, 0), + exchange = hdr->ike_exchange; + flags = hdr->ike_flags; + log_info("%s: %s %s from %s to %s msgid %u, %ld bytes%s", __func__, + print_map(exchange, ikev2_exchange_map), + (flags & IKEV2_FLAG_RESPONSE) ? "response" : "request", + print_host((struct sockaddr *)&msg->msg_local, NULL, 0), + print_host((struct sockaddr *)&msg->msg_peer, NULL, 0), + betoh32(hdr->ike_msgid), ibuf_length(buf), isnatt ? ", NAT-T" : ""); if (isnatt) { @@ -294,18 +313,16 @@ ikev2_msg_send(struct iked *env, struct iked_message *msg) log_debug("%s: failed to copy a message", __func__); return (-1); } - m->msg_exchange = hdr->ike_exchange; + m->msg_exchange = exchange; - if (hdr->ike_flags & IKEV2_FLAG_RESPONSE) { + if (flags & IKEV2_FLAG_RESPONSE) { TAILQ_INSERT_TAIL(&sa->sa_responses, m, msg_entry); - timer_initialize(env, &m->msg_timer, - ikev2_msg_response_timeout, m); - timer_register(env, &m->msg_timer, IKED_RESPONSE_TIMEOUT); + timer_set(env, &m->msg_timer, ikev2_msg_response_timeout, m); + timer_add(env, &m->msg_timer, IKED_RESPONSE_TIMEOUT); } else { TAILQ_INSERT_TAIL(&sa->sa_requests, m, msg_entry); - timer_initialize(env, &m->msg_timer, - ikev2_msg_retransmit_timeout, m); - timer_register(env, &m->msg_timer, IKED_RETRANSMIT_TIMEOUT); + timer_set(env, &m->msg_timer, ikev2_msg_retransmit_timeout, m); + timer_add(env, &m->msg_timer, IKED_RETRANSMIT_TIMEOUT); } return (0); @@ -334,7 +351,7 @@ ikev2_msg_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf *src) buf = ibuf_data(src); len = ibuf_size(src); - log_debug("%s: decrypted length %d", __func__, len); + log_debug("%s: decrypted length %zu", __func__, len); print_hex(buf, 0, len); if (sa == NULL || @@ -366,7 +383,7 @@ ikev2_msg_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf *src) if (ibuf_add(src, &pad, sizeof(pad)) != 0) goto done; - log_debug("%s: padded length %d", __func__, ibuf_size(src)); + log_debug("%s: padded length %zu", __func__, ibuf_size(src)); print_hex(ibuf_data(src), 0, ibuf_size(src)); cipher_setkey(sa->sa_encr, encr->buf, ibuf_length(encr)); @@ -389,9 +406,9 @@ ikev2_msg_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf *src) if ((ptr = ibuf_advance(dst, integrlen)) == NULL) goto done; - bzero(ptr, integrlen); + explicit_bzero(ptr, integrlen); - log_debug("%s: length %d, padding %d, output length %d", + log_debug("%s: length %zu, padding %d, output length %zu", __func__, len + sizeof(pad), pad, ibuf_size(dst)); print_hex(ibuf_data(dst), 0, ibuf_size(dst)); @@ -413,7 +430,7 @@ ikev2_msg_integr(struct iked *env, struct iked_sa *sa, struct ibuf *src) struct ibuf *integr, *tmp = NULL; u_int8_t *ptr; - log_debug("%s: message length %d", __func__, ibuf_size(src)); + log_debug("%s: message length %zu", __func__, ibuf_size(src)); print_hex(ibuf_data(src), 0, ibuf_size(src)); if (sa == NULL || @@ -429,7 +446,7 @@ ikev2_msg_integr(struct iked *env, struct iked_sa *sa, struct ibuf *src) integrlen = hash_length(sa->sa_integr); - log_debug("%s: integrity checksum length %d", __func__, + log_debug("%s: integrity checksum length %zu", __func__, integrlen); /* @@ -502,11 +519,11 @@ ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, goto done; } - log_debug("%s: IV length %d", __func__, ivlen); + log_debug("%s: IV length %zd", __func__, ivlen); print_hex(ibuf_data(src), 0, ivlen); - log_debug("%s: encrypted payload length %d", __func__, encrlen); + log_debug("%s: encrypted payload length %zd", __func__, encrlen); print_hex(ibuf_data(src), encroff, encrlen); - log_debug("%s: integrity checksum length %d", __func__, integrlen); + log_debug("%s: integrity checksum length %zd", __func__, integrlen); print_hex(ibuf_data(src), integroff, integrlen); /* @@ -556,7 +573,7 @@ ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, pad = *ptr; } - log_debug("%s: decrypted payload length %d/%d padding %d", + log_debug("%s: decrypted payload length %zd/%zd padding %d", __func__, outlen, encrlen, pad); print_hex(ibuf_data(out), 0, ibuf_size(out)); @@ -583,8 +600,8 @@ ikev2_msg_send_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf **ep, int ret = -1; if ((buf = ikev2_msg_init(env, &resp, &sa->sa_peer.addr, - SS_LEN(&sa->sa_peer.addr), &sa->sa_local.addr, - SS_LEN(&sa->sa_local.addr), response)) == NULL) + sa->sa_peer.addr.ss_len, &sa->sa_local.addr, + sa->sa_local.addr.ss_len, response)) == NULL) goto done; resp.msg_msgid = response ? sa->sa_msgid : ikev2_msg_id(env, sa); @@ -681,7 +698,7 @@ ikev2_msg_auth(struct iked *env, struct iked_sa *sa, int response) if (tmplen != hash_length(sa->sa_prf)) goto fail; - log_debug("%s: %s auth data length %d", + log_debug("%s: %s auth data length %zu", __func__, response ? "responder" : "initiator", ibuf_size(authmsg)); print_hex(ibuf_data(authmsg), 0, ibuf_size(authmsg)); @@ -739,12 +756,12 @@ ikev2_msg_authverify(struct iked *env, struct iked_sa *sa, break; } - log_debug("%s: method %s keylen %d type %s", __func__, + log_debug("%s: method %s keylen %zd type %s", __func__, print_map(auth->auth_method, ikev2_auth_map), keylen, print_map(id->id_type, ikev2_cert_map)); if (dsa_setkey(dsa, key, keylen, keytype) == NULL || - dsa_init(dsa) != 0 || + dsa_init(dsa, buf, len) != 0 || dsa_update(dsa, ibuf_data(authmsg), ibuf_size(authmsg))) { log_debug("%s: failed to compute digital signature", __func__); goto done; @@ -753,10 +770,7 @@ ikev2_msg_authverify(struct iked *env, struct iked_sa *sa, if ((ret = dsa_verify_final(dsa, buf, len)) == 0) { log_debug("%s: authentication successful", __func__); sa_state(env, sa, IKEV2_STATE_AUTH_SUCCESS); - - if (!sa->sa_policy->pol_auth.auth_eap && - auth->auth_method == IKEV2_AUTH_SHARED_KEY_MIC) - sa_state(env, sa, IKEV2_STATE_VALID); + sa_stateflags(sa, IKED_REQ_AUTHVALID); } else { log_debug("%s: authentication failed", __func__); sa_state(env, sa, IKEV2_STATE_AUTH_REQUEST); @@ -819,7 +833,7 @@ ikev2_msg_authsign(struct iked *env, struct iked_sa *sa, } if (dsa_setkey(dsa, key, keylen, keytype) == NULL || - dsa_init(dsa) != 0 || + dsa_init(dsa, NULL, 0) != 0 || dsa_update(dsa, ibuf_data(authmsg), ibuf_size(authmsg))) { log_debug("%s: failed to compute digital signature", __func__); goto done; @@ -905,7 +919,7 @@ ikev2_msg_dispose(struct iked *env, struct iked_msgqueue *queue, struct iked_message *msg) { TAILQ_REMOVE(queue, msg, msg_entry); - timer_deregister(env, &msg->msg_timer); + timer_del(env, &msg->msg_timer); ikev2_msg_cleanup(env, msg); free(msg); } @@ -942,11 +956,10 @@ ikev2_msg_retransmit_response(struct iked *env, struct iked_sa *sa, ibuf_size(msg->msg_data), 0, (struct sockaddr *)&msg->msg_peer, msg->msg_peerlen)) == -1) { log_warn("%s: sendto", __func__); - sa_free(env, sa); return (-1); } - timer_register(env, &msg->msg_timer, IKED_RESPONSE_TIMEOUT); + timer_add(env, &msg->msg_timer, IKED_RESPONSE_TIMEOUT); return (0); } @@ -975,10 +988,11 @@ ikev2_msg_retransmit_timeout(struct iked *env, void *arg) return; } /* Exponential timeout */ - timer_register(env, &msg->msg_timer, + timer_add(env, &msg->msg_timer, IKED_RETRANSMIT_TIMEOUT * (2 << (msg->msg_tries++))); } else { - log_debug("%s: retransmit limit reached", __func__); + log_debug("%s: retransmit limit reached for msgid %u", + __func__, msg->msg_msgid); sa_free(env, sa); } } diff --git a/iked/ikev2_pld.c b/iked/ikev2_pld.c index 9e4ed78..766aefc 100644 --- a/iked/ikev2_pld.c +++ b/iked/ikev2_pld.c @@ -1,7 +1,8 @@ -/* $OpenBSD: ikev2_pld.c,v 1.31 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: ikev2_pld.c,v 1.50 2015/03/26 19:52:35 markus Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter + * Copyright (c) 2014 Hans-Joerg Hoexer * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,23 +17,18 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include #include #include #include #include -#if defined(__OpenBSD__) -#include -#endif #include #include #include #include #include -#include #include #include #include @@ -47,42 +43,72 @@ #include "eap.h" #include "dh.h" +int ikev2_validate_pld(struct iked_message *, size_t, size_t, + struct ikev2_payload *); int ikev2_pld_payloads(struct iked *, struct iked_message *, - off_t, size_t, u_int, int); + size_t, size_t, u_int); +int ikev2_validate_sa(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct ikev2_sa_proposal *); int ikev2_pld_sa(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); +int ikev2_validate_xform(struct iked_message *, size_t, size_t, + struct ikev2_transform *); int ikev2_pld_xform(struct iked *, struct ikev2_sa_proposal *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); +int ikev2_validate_attr(struct iked_message *, size_t, size_t, + struct ikev2_attribute *); int ikev2_pld_attr(struct iked *, struct ikev2_transform *, - struct iked_message *, off_t, int); + struct iked_message *, size_t, size_t); +int ikev2_validate_ke(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct ikev2_keyexchange *); int ikev2_pld_ke(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); +int ikev2_validate_id(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct ikev2_id *); int ikev2_pld_id(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t, u_int); + struct iked_message *, size_t, size_t, u_int); +int ikev2_validate_cert(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct ikev2_cert *); int ikev2_pld_cert(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); +int ikev2_validate_certreq(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct ikev2_cert *); int ikev2_pld_certreq(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); +int ikev2_validate_nonce(struct iked_message *, size_t, size_t, + struct ikev2_payload *); int ikev2_pld_nonce(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); +int ikev2_validate_notify(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct ikev2_notify *); int ikev2_pld_notify(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); +int ikev2_validate_delete(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct ikev2_delete *); int ikev2_pld_delete(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); +int ikev2_validate_ts(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct ikev2_tsp *); int ikev2_pld_ts(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t, u_int); + struct iked_message *, size_t, size_t, u_int); +int ikev2_validate_auth(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct ikev2_auth *); int ikev2_pld_auth(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); int ikev2_pld_e(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t); +int ikev2_validate_cp(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct ikev2_cp *); int ikev2_pld_cp(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); +int ikev2_validate_eap(struct iked_message *, size_t, size_t, + struct ikev2_payload *, struct eap_header *); int ikev2_pld_eap(struct iked *, struct ikev2_payload *, - struct iked_message *, off_t); + struct iked_message *, size_t, size_t); int ikev2_pld_parse(struct iked *env, struct ike_header *hdr, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset) { log_debug("%s: header ispi %s rspi %s" " nextpayload %s version 0x%02x exchange %s flags 0x%02x" @@ -105,94 +131,130 @@ ikev2_pld_parse(struct iked *env, struct ike_header *hdr, offset += sizeof(*hdr); return (ikev2_pld_payloads(env, msg, offset, - betoh32(hdr->ike_length), hdr->ike_nextpayload, 0)); + betoh32(hdr->ike_length), hdr->ike_nextpayload)); +} + +int +ikev2_validate_pld(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld) +{ + u_int8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + /* We need at least the generic header. */ + if (left < sizeof(*pld)) { + log_debug("%s: malformed payload: too short for generic " + "header (%zu < %zu)", __func__, left, sizeof(*pld)); + return (-1); + } + memcpy(pld, msgbuf + offset, sizeof(*pld)); + + /* + * We need at least the specified number of bytes. + * pld_length is the full size of the payload including + * the generic payload header. + */ + pld_length = betoh16(pld->pld_length); + if (left < pld_length) { + log_debug("%s: malformed payload: shorter than specified " + "(%zu < %zu)", __func__, left, pld_length); + return (-1); + } + /* + * Sanity check the specified payload size, it must + * be at last the size of the generic payload header. + */ + if (pld_length < sizeof(*pld)) { + log_debug("%s: malformed payload: shorter than minimum " + "header size (%zu < %zu)", __func__, pld_length, + sizeof(*pld)); + return (-1); + } + + return (0); } int ikev2_pld_payloads(struct iked *env, struct iked_message *msg, - off_t offset, size_t length, u_int payload, int quick) + size_t offset, size_t length, u_int payload) { struct ikev2_payload pld; u_int e; int ret; u_int8_t *msgbuf = ibuf_data(msg->msg_data); + size_t left; /* Check if message was decrypted in an E payload */ e = msg->msg_e ? IKED_E : 0; - if (quick) - print_debug("%s: %spayloads", __func__, - e ? "decrypted " : ""); - else - ikev2_pld_payloads(env, msg, offset, length, payload, 1); + while (payload != 0 && offset < length) { + /* Bytes left in datagram. */ + left = length - offset; - while (payload != 0 && offset < (off_t)length) { - memcpy(&pld, msgbuf + offset, sizeof(pld)); + if (ikev2_validate_pld(msg, offset, left, &pld)) + return (-1); - if (quick) - print_debug(" %s", - print_map(payload, ikev2_payload_map)); - else - log_debug("%s: %spayload %s" - " nextpayload %s critical 0x%02x length %d", - __func__, e ? "decrypted " : "", - print_map(payload, ikev2_payload_map), - print_map(pld.pld_nextpayload, ikev2_payload_map), - pld.pld_reserved & IKEV2_CRITICAL_PAYLOAD, - betoh16(pld.pld_length)); + log_debug("%s: %spayload %s" + " nextpayload %s critical 0x%02x length %d", + __func__, e ? "decrypted " : "", + print_map(payload, ikev2_payload_map), + print_map(pld.pld_nextpayload, ikev2_payload_map), + pld.pld_reserved & IKEV2_CRITICAL_PAYLOAD, + betoh16(pld.pld_length)); + /* Skip over generic payload header. */ offset += sizeof(pld); + left -= sizeof(pld); ret = 0; - if (quick) - goto next; - switch (payload | e) { case IKEV2_PAYLOAD_SA: case IKEV2_PAYLOAD_SA | IKED_E: - ret = ikev2_pld_sa(env, &pld, msg, offset); + ret = ikev2_pld_sa(env, &pld, msg, offset, left); break; case IKEV2_PAYLOAD_KE: case IKEV2_PAYLOAD_KE | IKED_E: - ret = ikev2_pld_ke(env, &pld, msg, offset); + ret = ikev2_pld_ke(env, &pld, msg, offset, left); break; case IKEV2_PAYLOAD_IDi | IKED_E: case IKEV2_PAYLOAD_IDr | IKED_E: - ret = ikev2_pld_id(env, &pld, msg, offset, payload); + ret = ikev2_pld_id(env, &pld, msg, offset, left, + payload); break; case IKEV2_PAYLOAD_CERT | IKED_E: - ret = ikev2_pld_cert(env, &pld, msg, offset); + ret = ikev2_pld_cert(env, &pld, msg, offset, left); break; case IKEV2_PAYLOAD_CERTREQ: case IKEV2_PAYLOAD_CERTREQ | IKED_E: - ret = ikev2_pld_certreq(env, &pld, msg, offset); + ret = ikev2_pld_certreq(env, &pld, msg, offset, left); break; case IKEV2_PAYLOAD_AUTH | IKED_E: - ret = ikev2_pld_auth(env, &pld, msg, offset); + ret = ikev2_pld_auth(env, &pld, msg, offset, left); break; case IKEV2_PAYLOAD_NONCE: case IKEV2_PAYLOAD_NONCE | IKED_E: - ret = ikev2_pld_nonce(env, &pld, msg, offset); + ret = ikev2_pld_nonce(env, &pld, msg, offset, left); break; case IKEV2_PAYLOAD_NOTIFY: case IKEV2_PAYLOAD_NOTIFY | IKED_E: - ret = ikev2_pld_notify(env, &pld, msg, offset); + ret = ikev2_pld_notify(env, &pld, msg, offset, left); break; case IKEV2_PAYLOAD_DELETE | IKED_E: - ret = ikev2_pld_delete(env, &pld, msg, offset); + ret = ikev2_pld_delete(env, &pld, msg, offset, left); break; case IKEV2_PAYLOAD_TSi | IKED_E: case IKEV2_PAYLOAD_TSr | IKED_E: - ret = ikev2_pld_ts(env, &pld, msg, offset, payload); + ret = ikev2_pld_ts(env, &pld, msg, offset, left, + payload); break; case IKEV2_PAYLOAD_SK: ret = ikev2_pld_e(env, &pld, msg, offset); break; case IKEV2_PAYLOAD_CP | IKED_E: - ret = ikev2_pld_cp(env, &pld, msg, offset); + ret = ikev2_pld_cp(env, &pld, msg, offset, left); break; case IKEV2_PAYLOAD_EAP | IKED_E: - ret = ikev2_pld_eap(env, &pld, msg, offset); + ret = ikev2_pld_eap(env, &pld, msg, offset, left); break; default: print_hex(msgbuf, offset, @@ -209,20 +271,87 @@ ikev2_pld_payloads(struct iked *env, struct iked_message *msg, if (payload == IKEV2_PAYLOAD_SK) return (0); - next: payload = pld.pld_nextpayload; offset += betoh16(pld.pld_length) - sizeof(pld); } - if (quick) - print_debug("\n"); + return (0); +} + +int +ikev2_validate_sa(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct ikev2_sa_proposal *sap) +{ + u_int8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length, sap_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*sap)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*sap)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*sap)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*sap)); + return (-1); + } + memcpy(sap, msgbuf + offset, sizeof(*sap)); + sap_length = betoh16(sap->sap_length); + if (sap_length < sizeof(*sap)) { + log_debug("%s: malformed payload: shorter than minimum header " + "size (%zu < %zu)", __func__, sap_length, sizeof(*sap)); + return (-1); + } + if (left < sap_length) { + log_debug("%s: malformed payload: too long for actual payload " + "size (%zu < %zu)", __func__, left, sap_length); + return (-1); + } + /* + * NB: There might be more proposals, we parse only the first one. + * This condition must never be true. + */ + if (pld_length - sizeof(*pld) < sap_length) { + log_debug("%s: payload malformed: SA payload length mismatches " + "proposal substructure length (%lu < %zu)", __func__, + pld_length - sizeof(*pld), sap_length); + return (-1); + } + /* + * If there is only one proposal, sap_length must be the + * total payload size. + */ + if (!sap->sap_more && ((pld_length - sizeof(*pld)) != sap_length)) { + log_debug("%s: payload malformed: SA payload length mismatches " + "single proposal substructure length (%lu != %zu)", + __func__, pld_length - sizeof(*pld), sap_length); + return (-1); + } + /* + * If there are more than one proposal, there must be bytes + * left in the payload. + */ + if (sap->sap_more && ((pld_length - sizeof(*pld)) <= sap_length)) { + log_debug("%s: payload malformed: SA payload too small for " + "further proposals (%zu <= %zu)", __func__, + pld_length - sizeof(*pld), sap_length); + return (-1); + } return (0); } +/* + * NB: This function parses both the SA header and the first proposal. + * Additional proposals are ignored. + */ int ikev2_pld_sa(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t left) { struct ikev2_sa_proposal sap; struct iked_proposal *prop = NULL; @@ -230,13 +359,40 @@ ikev2_pld_sa(struct iked *env, struct ikev2_payload *pld, u_int64_t spi = 0, spi64; u_int8_t *msgbuf = ibuf_data(msg->msg_data); struct iked_proposals *props; + size_t total; + + if (ikev2_validate_sa(msg, offset, left, pld, &sap)) + return (-1); + + if (sap.sap_more) + log_debug("%s: more than one proposal specified", __func__); + + /* Assumed size of the first proposals, including SPI if present. */ + total = (betoh16(sap.sap_length) - sizeof(sap)); props = &msg->msg_parent->msg_proposals; - memcpy(&sap, msgbuf + offset, sizeof(sap)); offset += sizeof(sap); + left -= sizeof(sap); if (sap.sap_spisize) { + if (left < sap.sap_spisize) { + log_debug("%s: malformed payload: SPI larger than " + "actual payload (%zu < %d)", __func__, left, + sap.sap_spisize); + return (-1); + } + if (total < sap.sap_spisize) { + log_debug("%s: malformed payload: SPI larger than " + "proposal (%zu < %d)", __func__, total, + sap.sap_spisize); + return (-1); + } + if (total < sap.sap_spisize) { + log_debug("%s: malformed payload: SPI too large " + "(%zu < %d)", __func__, total, sap.sap_spisize); + return (-1); + } switch (sap.sap_spisize) { case 4: memcpy(&spi32, msgbuf + offset, 4); @@ -253,6 +409,20 @@ ikev2_pld_sa(struct iked *env, struct ikev2_payload *pld, } offset += sap.sap_spisize; + left -= sap.sap_spisize; + + /* Assumed size of the proposal, now without SPI. */ + total -= sap.sap_spisize; + } + + /* + * As we verified sanity of packet headers, this check will + * be always false, but just to be sure we keep it. + */ + if (left < total) { + log_debug("%s: payload malformed: too long for payload " + "(%zu < %zu)", __func__, left, total); + return (-1); } log_debug("%s: more %d reserved %d length %d" @@ -281,7 +451,7 @@ ikev2_pld_sa(struct iked *env, struct ikev2_payload *pld, * Parse the attached transforms */ if (sap.sap_transforms && - ikev2_pld_xform(env, &sap, msg, offset) != 0) { + ikev2_pld_xform(env, &sap, msg, offset, total) != 0) { log_debug("%s: invalid proposal transforms", __func__); return (-1); } @@ -289,15 +459,48 @@ ikev2_pld_sa(struct iked *env, struct ikev2_payload *pld, return (0); } +int +ikev2_validate_xform(struct iked_message *msg, size_t offset, size_t total, + struct ikev2_transform *xfrm) +{ + u_int8_t *msgbuf = ibuf_data(msg->msg_data); + size_t xfrm_length; + + if (total < sizeof(*xfrm)) { + log_debug("%s: payload malformed: too short for header " + "(%zu < %zu)", __func__, total, sizeof(*xfrm)); + return (-1); + } + memcpy(xfrm, msgbuf + offset, sizeof(*xfrm)); + + xfrm_length = betoh16(xfrm->xfrm_length); + if (xfrm_length < sizeof(*xfrm)) { + log_debug("%s: payload malformed: shorter than minimal header " + "(%zu < %zu)", __func__, xfrm_length, sizeof(*xfrm)); + return (-1); + } + if (total < xfrm_length) { + log_debug("%s: malformed payload: too long for payload size " + "(%zu < %zu)", __func__, total, xfrm_length); + return (-1); + } + + return (0); +} + int ikev2_pld_xform(struct iked *env, struct ikev2_sa_proposal *sap, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t total) { struct ikev2_transform xfrm; char id[BUFSIZ]; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + int ret = 0; + size_t xfrm_length; - memcpy(&xfrm, msgbuf + offset, sizeof(xfrm)); + if (ikev2_validate_xform(msg, offset, total, &xfrm)) + return (-1); + + xfrm_length = betoh16(xfrm.xfrm_length); switch (xfrm.xfrm_type) { case IKEV2_XFORMTYPE_ENCR: @@ -325,19 +528,21 @@ ikev2_pld_xform(struct iked *env, struct ikev2_sa_proposal *sap, break; } - log_debug("%s: more %d reserved %d length %d" + log_debug("%s: more %d reserved %d length %zu" " type %s id %s", - __func__, xfrm.xfrm_more, xfrm.xfrm_reserved, - betoh16(xfrm.xfrm_length), + __func__, xfrm.xfrm_more, xfrm.xfrm_reserved, xfrm_length, print_map(xfrm.xfrm_type, ikev2_xformtype_map), id); /* * Parse transform attributes, if available */ msg->msg_attrlength = 0; - if ((u_int)betoh16(xfrm.xfrm_length) > sizeof(xfrm)) - ikev2_pld_attr(env, &xfrm, msg, offset + sizeof(xfrm), - betoh16(xfrm.xfrm_length) - sizeof(xfrm)); + if (xfrm_length > sizeof(xfrm)) { + if (ikev2_pld_attr(env, &xfrm, msg, offset + sizeof(xfrm), + xfrm_length - sizeof(xfrm)) != 0) { + return (-1); + } + } if (ikev2_msg_frompeer(msg)) { if (config_add_transform(msg->msg_parent->msg_prop, @@ -349,26 +554,52 @@ ikev2_pld_xform(struct iked *env, struct ikev2_sa_proposal *sap, } /* Next transform */ - offset += betoh16(xfrm.xfrm_length); + offset += xfrm_length; + total -= xfrm_length; if (xfrm.xfrm_more == IKEV2_XFORM_MORE) - ikev2_pld_xform(env, sap, msg, offset); + ret = ikev2_pld_xform(env, sap, msg, offset, total); + else if (total != 0) { + /* No more transforms but still some data left. */ + log_debug("%s: less data than specified, %zu bytes left", + __func__, total); + ret = -1; + } + + return (ret); +} + +int +ikev2_validate_attr(struct iked_message *msg, size_t offset, size_t total, + struct ikev2_attribute *attr) +{ + u_int8_t *msgbuf = ibuf_data(msg->msg_data); + + if (total < sizeof(*attr)) { + log_debug("%s: payload malformed: too short for header " + "(%zu < %zu)", __func__, total, sizeof(*attr)); + return (-1); + } + memcpy(attr, msgbuf + offset, sizeof(*attr)); return (0); } int ikev2_pld_attr(struct iked *env, struct ikev2_transform *xfrm, - struct iked_message *msg, off_t offset, int total) + struct iked_message *msg, size_t offset, size_t total) { struct ikev2_attribute attr; u_int type; u_int8_t *msgbuf = ibuf_data(msg->msg_data); + int ret = 0; + size_t attr_length; - memcpy(&attr, msgbuf + offset, sizeof(attr)); + if (ikev2_validate_attr(msg, offset, total, &attr)) + return (-1); type = betoh16(attr.attr_type) & ~IKEV2_ATTRAF_TV; - log_debug("%s: attribute type %s length %d total %d", + log_debug("%s: attribute type %s length %d total %zu", __func__, print_map(type, ikev2_attrtype_map), betoh16(attr.attr_length), total); @@ -381,30 +612,70 @@ ikev2_pld_attr(struct iked *env, struct ikev2_transform *xfrm, msg->msg_attrlength = betoh16(attr.attr_length); } else { /* Type-Length-Value attribute */ + attr_length = betoh16(attr.attr_length); + if (attr_length < sizeof(attr)) { + log_debug("%s: payload malformed: shorter than " + "minimal header (%zu < %zu)", __func__, + attr_length, sizeof(attr)); + return (-1); + } + if (total < attr_length) { + log_debug("%s: payload malformed: attribute larger " + "than actual payload (%zu < %zu)", __func__, + total, attr_length); + return (-1); + } print_hex(msgbuf, offset + sizeof(attr), - betoh16(attr.attr_length) - sizeof(attr)); - offset += betoh16(attr.attr_length); - total -= betoh16(attr.attr_length); + attr_length - sizeof(attr)); + offset += attr_length; + total -= attr_length; } if (total > 0) { /* Next attribute */ - ikev2_pld_attr(env, xfrm, msg, offset, total); + ret = ikev2_pld_attr(env, xfrm, msg, offset, total); + } + + return (ret); +} + +int +ikev2_validate_ke(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct ikev2_keyexchange *kex) +{ + u_int8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*kex)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*kex)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*kex)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*kex)); + return (-1); } + memcpy(kex, msgbuf + offset, sizeof(*kex)); return (0); } int ikev2_pld_ke(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t left) { struct ikev2_keyexchange kex; u_int8_t *buf; size_t len; u_int8_t *msgbuf = ibuf_data(msg->msg_data); - memcpy(&kex, msgbuf + offset, sizeof(kex)); + if (ikev2_validate_ke(msg, offset, left, pld, &kex)) + return (-1); log_debug("%s: dh group %s reserved %d", __func__, print_map(betoh16(kex.kex_dhgroup), ikev2_xformdh_map), @@ -413,6 +684,17 @@ ikev2_pld_ke(struct iked *env, struct ikev2_payload *pld, buf = msgbuf + offset + sizeof(kex); len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(kex); + if (len == 0) { + log_debug("%s: malformed payload: no KE data given", __func__); + return (-1); + } + /* This will actually be caught by earlier checks. */ + if (left < len) { + log_debug("%s: malformed payload: smaller than specified " + "(%zu < %zu)", __func__, left, len); + return (-1); + } + print_hex(buf, 0, len); if (ikev2_msg_frompeer(msg)) { @@ -426,9 +708,35 @@ ikev2_pld_ke(struct iked *env, struct ikev2_payload *pld, return (0); } +int +ikev2_validate_id(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct ikev2_id *id) +{ + u_int8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*id)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*id)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*id)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*id)); + return (-1); + } + memcpy(id, msgbuf + offset, sizeof(*id)); + + return (0); +} + int ikev2_pld_id(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset, u_int payload) + struct iked_message *msg, size_t offset, size_t left, u_int payload) { u_int8_t *ptr; struct ikev2_id id; @@ -438,7 +746,9 @@ ikev2_pld_id(struct iked *env, struct ikev2_payload *pld, u_int8_t *msgbuf = ibuf_data(msg->msg_data); char idstr[IKED_ID_SIZE]; - memcpy(&id, msgbuf + offset, sizeof(id)); + if (ikev2_validate_id(msg, offset, left, pld, &id)) + return (-1); + bzero(&idb, sizeof(idb)); /* Don't strip the Id payload header */ @@ -455,7 +765,7 @@ ikev2_pld_id(struct iked *env, struct ikev2_payload *pld, return (-1); } - log_debug("%s: id %s length %d", __func__, idstr, len); + log_debug("%s: id %s length %zu", __func__, idstr, len); if (!ikev2_msg_frompeer(msg)) { ibuf_release(idb.id_buf); @@ -481,9 +791,35 @@ ikev2_pld_id(struct iked *env, struct ikev2_payload *pld, return (0); } +int +ikev2_validate_cert(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct ikev2_cert *cert) +{ + u_int8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*cert)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*cert)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*cert)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*cert)); + return (-1); + } + memcpy(cert, msgbuf + offset, sizeof(*cert)); + + return (0); +} + int ikev2_pld_cert(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t left) { struct ikev2_cert cert; u_int8_t *buf; @@ -491,13 +827,14 @@ ikev2_pld_cert(struct iked *env, struct ikev2_payload *pld, struct iked_id *certid; u_int8_t *msgbuf = ibuf_data(msg->msg_data); - memcpy(&cert, msgbuf + offset, sizeof(cert)); + if (ikev2_validate_cert(msg, offset, left, pld, &cert)) + return (-1); offset += sizeof(cert); buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(cert); - log_debug("%s: type %s length %d", + log_debug("%s: type %s length %zu", __func__, print_map(cert.cert_type, ikev2_cert_map), len); print_hex(buf, 0, len); @@ -521,32 +858,68 @@ ikev2_pld_cert(struct iked *env, struct ikev2_payload *pld, return (0); } +int +ikev2_validate_certreq(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct ikev2_cert *cert) +{ + u_int8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*cert)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*cert)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*cert)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*cert)); + return (-1); + } + memcpy(cert, msgbuf + offset, sizeof(*cert)); + + return (0); +} + int ikev2_pld_certreq(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t left) { struct iked_sa *sa = msg->msg_sa; struct ikev2_cert cert; u_int8_t *buf; - size_t len; + ssize_t len; u_int8_t *msgbuf = ibuf_data(msg->msg_data); - memcpy(&cert, msgbuf + offset, sizeof(cert)); + if (ikev2_validate_certreq(msg, offset, left, pld, &cert)) + return (-1); offset += sizeof(cert); buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(cert); - log_debug("%s: type %s signatures length %d", + log_debug("%s: type %s length %zd", __func__, print_map(cert.cert_type, ikev2_cert_map), len); + + /* This will actually be caught by earlier checks. */ + if (len < 0) { + log_debug("%s: invalid certificate request length", __func__); + return (-1); + } + print_hex(buf, 0, len); if (!ikev2_msg_frompeer(msg)) return (0); - if (!len || (len % SHA_DIGEST_LENGTH) != 0) { - log_debug("%s: invalid certificate request", __func__); - return (-1); + if (cert.cert_type == IKEV2_CERT_X509_CERT) { + if (!len || (len % SHA_DIGEST_LENGTH) != 0) { + log_debug("%s: invalid certificate request", __func__); + return (-1); + } } if (msg->msg_sa == NULL) @@ -564,9 +937,35 @@ ikev2_pld_certreq(struct iked *env, struct ikev2_payload *pld, return (0); } +int +ikev2_validate_auth(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct ikev2_auth *auth) +{ + u_int8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*auth)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*auth)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*auth)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*auth)); + return (-1); + } + memcpy(auth, msgbuf + offset, sizeof(*auth)); + + return (0); +} + int ikev2_pld_auth(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t left) { struct ikev2_auth auth; struct iked_id *idp; @@ -575,13 +974,14 @@ ikev2_pld_auth(struct iked *env, struct ikev2_payload *pld, struct iked_sa *sa = msg->msg_sa; u_int8_t *msgbuf = ibuf_data(msg->msg_data); - memcpy(&auth, msgbuf + offset, sizeof(auth)); + if (ikev2_validate_auth(msg, offset, left, pld, &auth)) + return (-1); offset += sizeof(auth); buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(auth); - log_debug("%s: method %s length %d", + log_debug("%s: method %s length %zu", __func__, print_map(auth.auth_method, ikev2_auth_map), len); print_hex(buf, 0, len); @@ -608,16 +1008,49 @@ ikev2_pld_auth(struct iked *env, struct ikev2_payload *pld, return (0); } +int +ikev2_validate_nonce(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld) +{ + size_t pld_length; + + /* This will actually be caught by earlier checks. */ + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld)); + return (-1); + } + + return (0); +} + int ikev2_pld_nonce(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t left) { size_t len; u_int8_t *buf; u_int8_t *msgbuf = ibuf_data(msg->msg_data); + if (ikev2_validate_nonce(msg, offset, left, pld)) + return (-1); + buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld); + + if (len == 0) { + log_debug("%s: malformed payload: no NONCE given", __func__); + return (-1); + } + /* This will actually be caught by earlier checks. */ + if (left < len) { + log_debug("%s: malformed payload: smaller than specified " + "(%zu < %zu)", __func__, left, len); + return (-1); + } + print_hex(buf, 0, len); if (ikev2_msg_frompeer(msg)) { @@ -632,11 +1065,37 @@ ikev2_pld_nonce(struct iked *env, struct ikev2_payload *pld, return (0); } +int +ikev2_validate_notify(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct ikev2_notify *n) +{ + u_int8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*n)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*n)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*n)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*n)); + return (-1); + } + memcpy(n, msgbuf + offset, sizeof(*n)); + + return (0); +} + int ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t left) { - struct ikev2_notify *n; + struct ikev2_notify n; u_int8_t *buf, md[SHA_DIGEST_LENGTH]; size_t len; u_int32_t spi32; @@ -644,18 +1103,21 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, struct iked_spi *rekey; u_int16_t type; u_int16_t group; + u_int16_t cpi; + u_int16_t signature_hash; + u_int8_t transform; - if ((n = ibuf_seek(msg->msg_data, offset, sizeof(*n))) == NULL) + if (ikev2_validate_notify(msg, offset, left, pld, &n)) return (-1); - type = betoh16(n->n_type); + type = betoh16(n.n_type); log_debug("%s: protoid %s spisize %d type %s", __func__, - print_map(n->n_protoid, ikev2_saproto_map), n->n_spisize, + print_map(n.n_protoid, ikev2_saproto_map), n.n_spisize, print_map(type, ikev2_n_map)); - len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(*n); - if ((buf = ibuf_seek(msg->msg_data, offset + sizeof(*n), len)) == NULL) + len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(n); + if ((buf = ibuf_seek(msg->msg_data, offset + sizeof(n), len)) == NULL) return (-1); print_hex(buf, 0, len); @@ -666,9 +1128,14 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, switch (type) { case IKEV2_N_NAT_DETECTION_SOURCE_IP: case IKEV2_N_NAT_DETECTION_DESTINATION_IP: + if (len != sizeof(md)) { + log_debug("%s: malformed payload: hash size mismatch" + " (%zu != %zu)", __func__, len, sizeof(md)); + return (-1); + } if (ikev2_nat_detection(env, msg, md, sizeof(md), type) == -1) return (-1); - if (len != sizeof(md) || memcmp(buf, md, len) != 0) { + if (memcmp(buf, md, len) != 0) { log_debug("%s: %s detected NAT, enabling " "UDP encapsulation", __func__, print_map(type, ikev2_n_map)); @@ -683,13 +1150,21 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, print_hex(md, 0, sizeof(md)); break; case IKEV2_N_INVALID_KE_PAYLOAD: + if (sa_stateok(msg->msg_sa, IKEV2_STATE_VALID) && + !msg->msg_e) { + log_debug("%s: INVALID_KE_PAYLOAD not encrypted", + __func__); + return (-1); + } if (len != sizeof(group)) { - log_debug("%s: malformed notification", __func__); + log_debug("%s: malformed payload: group size mismatch" + " (%zu != %zu)", __func__, len, sizeof(group)); return (-1); } + /* XXX chould also happen for PFS */ if (!msg->msg_sa->sa_hdr.sh_initiator) { log_debug("%s: not an initiator", __func__); - sa_free(env, msg->msg_sa); + sa_state(env, msg->msg_sa, IKEV2_STATE_CLOSED); msg->msg_sa = NULL; return (-1); } @@ -703,13 +1178,18 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, } log_debug("%s: responder selected DH group %d", __func__, group); - sa_free(env, msg->msg_sa); + sa_state(env, msg->msg_sa, IKEV2_STATE_CLOSED); msg->msg_sa = NULL; - timer_initialize(env, &env->sc_inittmr, ikev2_init_ike_sa, - NULL); - timer_register(env, &env->sc_inittmr, IKED_INITIATOR_INITIAL); + /* XXX chould also happen for PFS so we have to check state XXX*/ + timer_set(env, &env->sc_inittmr, ikev2_init_ike_sa, NULL); + timer_add(env, &env->sc_inittmr, IKED_INITIATOR_INITIAL); break; case IKEV2_N_NO_ADDITIONAL_SAS: + if (!msg->msg_e) { + log_debug("%s: NO_ADDITIONAL_SAS not encrypted", + __func__); + return (-1); + } /* This makes sense for Child SAs only atm */ if (msg->msg_sa->sa_stateflags & IKED_REQ_CHILDSA) { ikev2_disable_rekeying(env, msg->msg_sa); @@ -717,7 +1197,11 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, } break; case IKEV2_N_REKEY_SA: - if (len != n->n_spisize) { + if (!msg->msg_e) { + log_debug("%s: N_REKEY_SA not encrypted", __func__); + return (-1); + } + if (len != n.n_spisize) { log_debug("%s: malformed notification", __func__); return (-1); } @@ -727,7 +1211,7 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, __func__); return (-1); } - switch (n->n_spisize) { + switch (n.n_spisize) { case 4: memcpy(&spi32, buf, len); rekey->spi = betoh32(spi32); @@ -738,28 +1222,106 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, break; default: log_debug("%s: invalid spi size %d", __func__, - n->n_spisize); + n.n_spisize); return (-1); } - rekey->spi_size = n->n_spisize; - rekey->spi_protoid = n->n_protoid; + rekey->spi_size = n.n_spisize; + rekey->spi_protoid = n.n_protoid; log_debug("%s: rekey %s spi %s", __func__, - print_map(n->n_protoid, ikev2_saproto_map), - print_spi(rekey->spi, n->n_spisize)); + print_map(n.n_protoid, ikev2_saproto_map), + print_spi(rekey->spi, n.n_spisize)); + break; + case IKEV2_N_IPCOMP_SUPPORTED: + if (!msg->msg_e) { + log_debug("%s: N_IPCOMP_SUPPORTED not encrypted", + __func__); + return (-1); + } + if (len < sizeof(cpi) + sizeof(transform)) { + log_debug("%s: ignoring malformed ipcomp notification", + __func__); + return (0); + } + memcpy(&cpi, buf, sizeof(cpi)); + memcpy(&transform, buf + sizeof(cpi), sizeof(transform)); + log_debug("%s: cpi 0x%x, transform %s, len %zu", __func__, + betoh16(cpi), print_map(transform, ikev2_ipcomp_map), len); + /* we only support deflate */ + if ((msg->msg_policy->pol_flags & IKED_POLICY_IPCOMP) && + (transform == IKEV2_IPCOMP_DEFLATE)) { + msg->msg_sa->sa_ipcomp = transform; + msg->msg_sa->sa_cpi_out = betoh16(cpi); + } break; + case IKEV2_N_SIGNATURE_HASH_ALGORITHMS: + if (msg->msg_e) { + log_debug("%s: SIGNATURE_HASH_ALGORITHMS: encrypted", + __func__); + return (-1); + } + if (msg->msg_sa == NULL || + msg->msg_sa->sa_sigsha2) { + log_debug("%s: SIGNATURE_HASH_ALGORITHMS: no SA or " + "duplicate notify", __func__); + return (-1); + } + if (len < sizeof(signature_hash) || + len % sizeof(signature_hash)) { + log_debug("%s: malformed signature hash notification" + "(%zu bytes)", __func__, len); + return (0); + } + while (len >= sizeof(signature_hash)) { + memcpy(&signature_hash, buf, sizeof(signature_hash)); + signature_hash = betoh16(signature_hash); + log_debug("%s: signature hash %s (%x)", __func__, + print_map(signature_hash, ikev2_sighash_map), + signature_hash); + len -= sizeof(signature_hash); + buf += sizeof(signature_hash); + if (signature_hash == IKEV2_SIGHASH_SHA2_256) + msg->msg_sa->sa_sigsha2 = 1; + } + break; + } + + return (0); +} + +int +ikev2_validate_delete(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct ikev2_delete *del) +{ + u_int8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*del)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*del)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*del)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*del)); + return (-1); } + memcpy(del, msgbuf + offset, sizeof(*del)); return (0); } int ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t left) { struct iked_childsa **peersas = NULL; struct iked_sa *sa = msg->msg_sa; - struct ikev2_delete *del, *localdel; + struct ikev2_delete del, *localdel; struct ibuf *resp = NULL; u_int64_t *localspi = NULL; u_int64_t spi64, spi = 0; @@ -768,25 +1330,22 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, size_t found = 0, failed = 0; int cnt, i, len, sz, ret = -1; - /* Skip if it's a reply and we don't have to deal with it */ - if (ikev2_msg_frompeer(msg) && sa && - (sa->sa_stateflags & IKED_REQ_INF)) { - sa->sa_stateflags &= ~IKED_REQ_INF; - if ((sa->sa_stateflags & IKED_REQ_DELETE) == 0) - return (0); - } + /* Skip if it's a response, then we don't have to deal with it */ + if (ikev2_msg_frompeer(msg) && + msg->msg_parent->msg_response) + return (0); - if ((del = ibuf_seek(msg->msg_data, offset, sizeof(*del))) == NULL) + if (ikev2_validate_delete(msg, offset, left, pld, &del)) return (-1); - cnt = betoh16(del->del_nspi); - sz = del->del_spisize; + cnt = betoh16(del.del_nspi); + sz = del.del_spisize; log_debug("%s: proto %s spisize %d nspi %d", - __func__, print_map(del->del_protoid, ikev2_saproto_map), + __func__, print_map(del.del_protoid, ikev2_saproto_map), sz, cnt); - buf = msgbuf + offset + sizeof(*del); - len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(*del); + buf = msgbuf + offset + sizeof(del); + len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(del); print_hex(buf, 0, len); @@ -795,20 +1354,28 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, case 8: break; default: - if (ikev2_msg_frompeer(msg) && - del->del_protoid == IKEV2_SAPROTO_IKE) { + if (del.del_protoid != IKEV2_SAPROTO_IKE) { + log_debug("%s: invalid SPI size", __func__); + return (-1); + } + if (ikev2_msg_frompeer(msg)) { /* Send an empty informational response */ if ((resp = ibuf_static()) == NULL) goto done; ret = ikev2_send_ike_e(env, sa, resp, IKEV2_PAYLOAD_NONE, IKEV2_EXCHANGE_INFORMATIONAL, 1); + msg->msg_parent->msg_responded = 1; ibuf_release(resp); sa_state(env, sa, IKEV2_STATE_CLOSED); - return (ret); + } else { + /* + * We're sending a delete message. Upper layer + * must deal with deletion of the IKE SA. + */ + ret = 0; } - log_debug("%s: invalid SPI size", __func__); - return (-1); + return (ret); } if ((len / sz) != cnt) { @@ -842,13 +1409,13 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, continue; if ((peersas[i] = childsa_lookup(sa, spi, - del->del_protoid)) == NULL) { + del.del_protoid)) == NULL) { log_warnx("%s: CHILD SA doesn't exist for spi %s", - __func__, print_spi(spi, del->del_spisize)); - goto done; + __func__, print_spi(spi, del.del_spisize)); + continue; } - if (ikev2_childsa_delete(env, sa, del->del_protoid, spi, + if (ikev2_childsa_delete(env, sa, del.del_protoid, spi, &localspi[i], 0) == -1) failed++; else @@ -864,9 +1431,7 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, if (!ikev2_msg_frompeer(msg)) goto done; - if (sa && (sa->sa_stateflags & IKED_REQ_DELETE)) { - /* Finish rekeying */ - sa->sa_stateflags &= ~IKED_REQ_DELETE; + if (msg->msg_parent->msg_response) { ret = 0; goto done; } @@ -880,8 +1445,8 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, if ((localdel = ibuf_advance(resp, sizeof(*localdel))) == NULL) goto done; - localdel->del_protoid = del->del_protoid; - localdel->del_spisize = del->del_spisize; + localdel->del_protoid = del.del_protoid; + localdel->del_spisize = del.del_spisize; localdel->del_nspi = htobe16(found); for (i = 0; i < cnt; i++) { @@ -899,12 +1464,13 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, } } - log_warnx("%s: deleted %d spis", __func__, found); + log_warnx("%s: deleted %zu spis", __func__, found); } if (found) { ret = ikev2_send_ike_e(env, sa, resp, IKEV2_PAYLOAD_DELETE, IKEV2_EXCHANGE_INFORMATIONAL, 1); + msg->msg_parent->msg_responded = 1; } else { /* XXX should we send an INVALID_SPI notification? */ ret = 0; @@ -919,9 +1485,35 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, return (ret); } +int +ikev2_validate_ts(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct ikev2_tsp *tsp) +{ + u_int8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*tsp)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*tsp)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*tsp)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*tsp)); + return (-1); + } + memcpy(tsp, msgbuf + offset, sizeof(*tsp)); + + return (0); +} + int ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset, u_int payload) + struct iked_message *msg, size_t offset, size_t left, u_int payload) { struct ikev2_tsp tsp; struct ikev2_ts ts; @@ -931,12 +1523,13 @@ ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld, u_int8_t buf[2][128]; u_int8_t *msgbuf = ibuf_data(msg->msg_data); - memcpy(&tsp, msgbuf + offset, sizeof(tsp)); + if (ikev2_validate_ts(msg, offset, left, pld, &tsp)) + return (-1); offset += sizeof(tsp); len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(tsp); - log_debug("%s: count %d length %d", __func__, + log_debug("%s: count %d length %zu", __func__, tsp.tsp_count, len); for (i = 0; i < tsp.tsp_count; i++) { @@ -953,16 +1546,14 @@ ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld, case IKEV2_TS_IPV4_ADDR_RANGE: bzero(&s4, sizeof(s4)); s4.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN s4.sin_len = sizeof(s4); -#endif memcpy(&s4.sin_addr.s_addr, msgbuf + offset + sizeof(ts), 4); - print_host((struct sockaddr_storage *)&s4, + print_host((struct sockaddr *)&s4, (char *)buf[0], sizeof(buf[0])); memcpy(&s4.sin_addr.s_addr, msgbuf + offset + sizeof(ts) + 4, 4); - print_host((struct sockaddr_storage *)&s4, + print_host((struct sockaddr *)&s4, (char *)buf[1], sizeof(buf[1])); log_debug("%s: start %s end %s", __func__, buf[0], buf[1]); @@ -970,16 +1561,14 @@ ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld, case IKEV2_TS_IPV6_ADDR_RANGE: bzero(&s6, sizeof(s6)); s6.sin6_family = AF_INET6; -#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN s6.sin6_len = sizeof(s6); -#endif memcpy(&s6.sin6_addr, msgbuf + offset + sizeof(ts), 16); - print_host((struct sockaddr_storage *)&s6, + print_host((struct sockaddr *)&s6, (char *)buf[0], sizeof(buf[0])); memcpy(&s6.sin6_addr, msgbuf + offset + sizeof(ts) + 16, 16); - print_host((struct sockaddr_storage *)&s6, + print_host((struct sockaddr *)&s6, (char *)buf[1], sizeof(buf[1])); log_debug("%s: start %s end %s", __func__, buf[0], buf[1]); @@ -996,7 +1585,7 @@ ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld, int ikev2_pld_e(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset) { struct iked_sa *sa = msg->msg_sa; struct ibuf *e = NULL; @@ -1034,7 +1623,7 @@ ikev2_pld_e(struct iked *env, struct ikev2_payload *pld, TAILQ_INIT(&emsg.msg_proposals); ret = ikev2_pld_payloads(env, &emsg, 0, ibuf_size(e), - pld->pld_nextpayload, 0); + pld->pld_nextpayload); done: ibuf_release(e); @@ -1042,9 +1631,35 @@ ikev2_pld_e(struct iked *env, struct ikev2_payload *pld, return (ret); } +int +ikev2_validate_cp(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct ikev2_cp *cp) +{ + u_int8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*cp)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*cp)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*cp)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*cp)); + return (-1); + } + memcpy(cp, msgbuf + offset, sizeof(*cp)); + + return (0); +} + int ikev2_pld_cp(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t left) { struct ikev2_cp cp; struct ikev2_cfg *cfg; @@ -1053,13 +1668,14 @@ ikev2_pld_cp(struct iked *env, struct ikev2_payload *pld, u_int8_t *msgbuf = ibuf_data(msg->msg_data); struct iked_sa *sa = msg->msg_sa; - memcpy(&cp, msgbuf + offset, sizeof(cp)); + if (ikev2_validate_cp(msg, offset, left, pld, &cp)) + return (-1); offset += sizeof(cp); buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(cp); - log_debug("%s: type %s length %d", + log_debug("%s: type %s length %zu", __func__, print_map(cp.cp_type, ikev2_cp_map), len); print_hex(buf, 0, len); @@ -1083,26 +1699,49 @@ ikev2_pld_cp(struct iked *env, struct ikev2_payload *pld, return (0); } +int +ikev2_validate_eap(struct iked_message *msg, size_t offset, size_t left, + struct ikev2_payload *pld, struct eap_header *hdr) +{ + u_int8_t *msgbuf = ibuf_data(msg->msg_data); + size_t pld_length; + + pld_length = betoh16(pld->pld_length); + if (pld_length < sizeof(*pld) + sizeof(*hdr)) { + log_debug("%s: malformed payload: specified length smaller " + "than minimum size (%zu < %zu)", __func__, pld_length, + sizeof(*pld) + sizeof(*hdr)); + return (-1); + } + + /* This will actually be caught by earlier checks. */ + if (left < sizeof(*hdr)) { + log_debug("%s: malformed payload: too short for header " + "(%zu < %zu)", __func__, left, sizeof(*hdr)); + return (-1); + } + memcpy(hdr, msgbuf + offset, sizeof(*hdr)); + + return (0); +} + int ikev2_pld_eap(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, off_t offset) + struct iked_message *msg, size_t offset, size_t left) { - struct eap_header *hdr; + struct eap_header hdr; struct eap_message *eap = NULL; struct iked_sa *sa = msg->msg_sa; size_t len; - if ((hdr = ibuf_seek(msg->msg_data, offset, sizeof(*hdr))) == NULL) { - log_debug("%s: failed to get EAP header", __func__); + if (ikev2_validate_eap(msg, offset, left, pld, &hdr)) return (-1); - } - - len = betoh16(hdr->eap_length); + len = betoh16(hdr.eap_length); if (len < sizeof(*eap)) { log_info("%s: %s id %d length %d", __func__, - print_map(hdr->eap_code, eap_code_map), - hdr->eap_id, betoh16(hdr->eap_length)); + print_map(hdr.eap_code, eap_code_map), + hdr.eap_id, betoh16(hdr.eap_length)); } else { /* Now try to get the indicated length */ if ((eap = ibuf_seek(msg->msg_data, offset, len)) == NULL) { @@ -1114,10 +1753,10 @@ ikev2_pld_eap(struct iked *env, struct ikev2_payload *pld, print_map(eap->eap_code, eap_code_map), eap->eap_id, betoh16(eap->eap_length), print_map(eap->eap_type, eap_type_map)); - } - if (eap_parse(env, sa, hdr, msg->msg_response) == -1) - return (-1); + if (eap_parse(env, sa, eap, msg->msg_response) == -1) + return (-1); + } return (0); } diff --git a/iked/imsg_util.c b/iked/imsg_util.c index 8dcfab2..f883217 100644 --- a/iked/imsg_util.c +++ b/iked/imsg_util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: imsg_util.c,v 1.7 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: imsg_util.c,v 1.9 2014/05/06 11:11:14 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,18 +16,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "openbsd-compat/sys-queue.h" +#include #include #include -#include -#include -#include -#include -#include -#include #include - #include #include #include @@ -52,7 +45,7 @@ ibuf_cat(struct ibuf *dst, struct ibuf *src) void ibuf_zero(struct ibuf *buf) { - memset(buf->buf, 0, buf->wpos); + explicit_bzero(buf->buf, buf->wpos); } struct ibuf * @@ -110,8 +103,10 @@ ibuf_release(struct ibuf *buf) { if (buf == NULL) return; - if (buf->buf != NULL) + if (buf->buf != NULL) { + ibuf_zero(buf); free(buf->buf); + } free(buf); } diff --git a/iked/log.c b/iked/log.c index e283024..61256f3 100644 --- a/iked/log.c +++ b/iked/log.c @@ -1,4 +1,4 @@ -/* $OpenBSD: log.c,v 1.3 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: log.c,v 1.4 2015/01/16 06:39:58 deraadt Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -16,10 +16,9 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include #include -#include "openbsd-compat/sys-tree.h" +#include #include #include diff --git a/iked/parse.y b/iked/parse.y index 7c1bda2..861295c 100644 --- a/iked/parse.y +++ b/iked/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.30 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: parse.y,v 1.48 2015/07/03 17:46:52 mikeb Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -24,14 +24,11 @@ %{ #include #include -#include "openbsd-compat/sys-queue.h" +#include #include #include #include #include -#if defined(__OpenBSD__) -#include -#endif #include #include @@ -65,10 +62,12 @@ static struct file { struct file *pushfile(const char *, int); int popfile(void); int check_file_secrecy(int, const char *); +int check_pubkey(char *, int ); int yyparse(void); int yylex(void); -int yyerror(const char *, ...); -int yywarn(const char *, ...); +int yyerror(const char *, ...) + __attribute__((__format__ (printf, 1, 2))) + __attribute__((__nonnull__ (1))); int kw_cmp(const void *, const void *); int lookup(char *); int lgetc(int); @@ -93,6 +92,7 @@ static int debug = 0; static int rules = 0; static int passive = 0; static int decouple = 0; +static char *ocsp_url = NULL; struct ipsec_xf { const char *name; @@ -140,13 +140,9 @@ struct iked_transform ikev2_default_esp_transforms[] = { { IKEV2_XFORMTYPE_ENCR, IKEV2_XFORMENCR_AES_CBC, 256 }, { IKEV2_XFORMTYPE_ENCR, IKEV2_XFORMENCR_AES_CBC, 192 }, { IKEV2_XFORMTYPE_ENCR, IKEV2_XFORMENCR_AES_CBC, 128 }, -#ifndef BROKEN_HMAC_SHA2_256 { IKEV2_XFORMTYPE_INTEGR, IKEV2_XFORMAUTH_HMAC_SHA2_256_128 }, -#endif { IKEV2_XFORMTYPE_INTEGR, IKEV2_XFORMAUTH_HMAC_SHA1_96 }, -#ifdef HAVE_ESN { IKEV2_XFORMTYPE_ESN, IKEV2_XFORMESN_ESN }, -#endif { IKEV2_XFORMTYPE_ESN, IKEV2_XFORMESN_NONE }, { 0 } }; @@ -241,6 +237,15 @@ const struct ipsec_xf groupxfs[] = { { "grp25", IKEV2_XFORMDH_ECP_192 }, { "ecp224", IKEV2_XFORMDH_ECP_224 }, { "grp26", IKEV2_XFORMDH_ECP_224 }, + { "brainpool224", IKEV2_XFORMDH_BRAINPOOL_P224R1 }, + { "grp27", IKEV2_XFORMDH_BRAINPOOL_P224R1 }, + { "brainpool256", IKEV2_XFORMDH_BRAINPOOL_P256R1 }, + { "grp28", IKEV2_XFORMDH_BRAINPOOL_P256R1 }, + { "brainpool384", IKEV2_XFORMDH_BRAINPOOL_P384R1 }, + { "grp29", IKEV2_XFORMDH_BRAINPOOL_P384R1 }, + { "brainpool512", IKEV2_XFORMDH_BRAINPOOL_P512R1 }, + { "grp30", IKEV2_XFORMDH_BRAINPOOL_P512R1 }, + { "curve25519", IKEV2_XFORMDH_X_CURVE25519 }, { NULL } }; @@ -272,7 +277,8 @@ const struct ipsec_xf cpxfs[] = { { "protected-subnet", IKEV2_CFG_INTERNAL_IP4_SUBNET, AF_INET }, { "protected-subnet", IKEV2_CFG_INTERNAL_IP6_SUBNET, AF_INET6 }, { "access-server", IKEV2_CFG_INTERNAL_IP4_SERVER, AF_INET }, - { "access-server", IKEV2_CFG_INTERNAL_IP6_SERVER, AF_INET6 } + { "access-server", IKEV2_CFG_INTERNAL_IP6_SERVER, AF_INET6 }, + { NULL } }; const struct iked_lifetime deflifetime = { @@ -325,7 +331,8 @@ void copy_transforms(u_int, const struct ipsec_xf *, int create_ike(char *, int, u_int8_t, struct ipsec_hosts *, struct ipsec_hosts *, struct ipsec_mode *, struct ipsec_mode *, u_int8_t, - u_int8_t, char *, char *, struct iked_lifetime *, + u_int8_t, char *, char *, + u_int32_t, struct iked_lifetime *, struct iked_auth *, struct ipsec_filters *, struct ipsec_addr_wrap *); int create_user(const char *, const char *); @@ -374,6 +381,7 @@ typedef struct { %token PASSIVE ACTIVE ANY TAG TAP PROTO LOCAL GROUP NAME CONFIG EAP USER %token IKEV1 FLOW SA TCPMD5 TUNNEL TRANSPORT COUPLE DECOUPLE SET %token INCLUDE LIFETIME BYTES INET INET6 QUICK SKIP DEFAULT +%token IPCOMP OCSP IKELIFETIME %token STRING %token NUMBER %type string @@ -390,12 +398,12 @@ typedef struct { %type id %type transforms %type filters -%type ikeflags ikematch ikemode +%type ikeflags ikematch ikemode ipcomp %type ikeauth %type keyspec %type ike_sa child_sa %type lifetime -%type byte_spec time_spec +%type byte_spec time_spec ikelifetime %type name %type cfg ikecfg ikecfgvals %% @@ -434,6 +442,12 @@ set : SET ACTIVE { passive = 0; } | SET PASSIVE { passive = 1; } | SET COUPLE { decouple = 0; } | SET DECOUPLE { decouple = 1; } + | SET OCSP STRING { + if ((ocsp_url = strdup($3)) == NULL) { + yyerror("cannot set ocsp_url"); + YYERROR; + } + } ; user : USER STRING STRING { @@ -443,9 +457,9 @@ user : USER STRING STRING { ; ikev2rule : IKEV2 name ikeflags satype af proto hosts_list peers - ike_sa child_sa ids lifetime ikeauth ikecfg filters { + ike_sa child_sa ids ikelifetime lifetime ikeauth ikecfg filters { if (create_ike($2, $5, $6, $7, &$8, $9, $10, $4, $3, - $11.srcid, $11.dstid, &$12, &$13, $15, $14) == -1) + $11.srcid, $11.dstid, $12, &$13, &$14, $16, $15) == -1) YYERROR; } ; @@ -757,7 +771,7 @@ ike_sa : /* empty */ { encxfs = ikeencxfs; } transforms { if (($$ = calloc(1, sizeof(*$$))) == NULL) - err(1, "child_sa: calloc"); + err(1, "ike_sa: calloc"); $$->xfs = $3; } ; @@ -774,7 +788,7 @@ child_sa : /* empty */ { } ; -ikeflags : ikematch ikemode { $$ = $1 | $2; } +ikeflags : ikematch ikemode ipcomp { $$ = $1 | $2 | $3; } ; ikematch : /* empty */ { $$ = 0; } @@ -788,6 +802,10 @@ ikemode : /* empty */ { $$ = IKED_POLICY_PASSIVE; } | ACTIVE { $$ = IKED_POLICY_ACTIVE; } ; +ipcomp : /* empty */ { $$ = 0; } + | IPCOMP { $$ = IKED_POLICY_IPCOMP; } + ; + ikeauth : /* empty */ { $$.auth_method = IKEV2_AUTH_RSA_SIG; $$.auth_length = 0; @@ -831,7 +849,7 @@ byte_spec : NUMBER { yyerror("invalid byte specification: %s", $1); YYERROR; } - switch (toupper(unit)) { + switch (toupper((unsigned char)unit)) { case 'K': bytes *= 1024; break; @@ -860,7 +878,7 @@ time_spec : NUMBER { yyerror("invalid time specification: %s", $1); YYERROR; } - switch (tolower(unit)) { + switch (tolower((unsigned char)unit)) { case 'm': seconds *= 60; break; @@ -888,6 +906,13 @@ lifetime : /* empty */ { } ; +ikelifetime : /* empty */ { + $$ = 0; + } + | IKELIFETIME time_spec { + $$ = $2; + } + keyspec : STRING { u_int8_t *hex; @@ -1034,19 +1059,6 @@ yyerror(const char *fmt, ...) return (0); } -int -yywarn(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - fprintf(stderr, "%s: %d: ", file->name, yylval.lineno); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - return (0); -} - int kw_cmp(const void *k, const void *e) { @@ -1077,14 +1089,17 @@ lookup(char *s) { "from", FROM }, { "group", GROUP }, { "ike", IKEV1 }, + { "ikelifetime", IKELIFETIME }, { "ikesa", IKESA }, { "ikev2", IKEV2 }, { "include", INCLUDE }, { "inet", INET }, { "inet6", INET6 }, + { "ipcomp", IPCOMP }, { "lifetime", LIFETIME }, { "local", LOCAL }, { "name", NAME }, + { "ocsp", OCSP }, { "passive", PASSIVE }, { "peer", PEER }, { "port", PORT }, @@ -1123,9 +1138,9 @@ lookup(char *s) #define MAXPUSHBACK 128 -char *parsebuf; +u_char *parsebuf; int parseindex; -char pushback_buffer[MAXPUSHBACK]; +u_char pushback_buffer[MAXPUSHBACK]; int pushback_index = 0; int @@ -1217,8 +1232,8 @@ findeol(void) int yylex(void) { - char buf[8096]; - char *p, *val; + u_char buf[8096]; + u_char *p, *val; int quotec, next, c; int token; @@ -1241,7 +1256,7 @@ top: return (findeol()); } if (isalnum(c) || c == '_') { - *p++ = (char)c; + *p++ = c; continue; } *p = '\0'; @@ -1281,12 +1296,15 @@ top: } else if (c == quotec) { *p = '\0'; break; + } else if (c == '\0') { + yyerror("syntax error"); + return (findeol()); } if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } - *p++ = (char)c; + *p++ = c; } yylval.v.string = strdup(buf); if (yylval.v.string == NULL) @@ -1373,8 +1391,8 @@ check_file_secrecy(int fd, const char *fname) warnx("%s: owner not root or current user", fname); return (-1); } - if (st.st_mode & (S_IRWXG | S_IRWXO)) { - warnx("%s: group/world readable/writeable", fname); + if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { + warnx("%s: group writable or world read/writable", fname); return (-1); } return (0); @@ -1459,6 +1477,7 @@ parse_config(const char *filename, struct iked *x_env) env->sc_passive = passive ? 1 : 0; env->sc_decoupled = decouple ? 1 : 0; + env->sc_ocsp_url = ocsp_url; if (!rules) log_warnx("%s: no valid configuration rules found", @@ -1631,6 +1650,48 @@ get_id_type(char *string) return (IKEV2_ID_FQDN); } +int +check_pubkey(char *idstr, int type) +{ + char keyfile[PATH_MAX]; + FILE *fp = NULL; + const char *suffix = NULL; + + switch (type) { + case IKEV2_ID_IPV4: + suffix = "ipv4"; + break; + case IKEV2_ID_IPV6: + suffix = "ipv6"; + break; + case IKEV2_ID_FQDN: + suffix = "fqdn"; + break; + case IKEV2_ID_UFQDN: + suffix = "ufqdn"; + break; + default: + /* Unspecified ID or public key not supported for this type */ + return (-1); + } + + lc_string(idstr); + if ((size_t)snprintf(keyfile, sizeof(keyfile), + IKED_CA IKED_PUBKEY_DIR "%s/%s", suffix, + idstr) >= sizeof(keyfile)) { + log_warnx("%s: public key path is too long", __func__); + return (-1); + } + + if ((fp = fopen(keyfile, "r")) == NULL) + return (-1); + fclose(fp); + + log_debug("%s: found public key file %s", __func__, keyfile); + + return (0); +} + struct ipsec_addr_wrap * host(const char *s) { @@ -1710,11 +1771,12 @@ host_v6(const char *s, int prefixlen) if (prefixlen != 128) { ipa->netaddress = 1; - asprintf(&ipa->name, "%s/%d", hbuf, prefixlen); - } else - ipa->name = strdup(hbuf); - if (ipa->name == NULL) - err(1, "host_v6: strdup"); + if (asprintf(&ipa->name, "%s/%d", hbuf, prefixlen) == -1) + err(1, "host_v6: asprintf"); + } else { + if ((ipa->name = strdup(hbuf)) == NULL) + err(1, "host_v6: strdup"); + } freeaddrinfo(res); @@ -1743,9 +1805,7 @@ host_v4(const char *s, int mask) err(1, "host_v4: calloc"); ina.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN ina.sin_len = sizeof(ina); -#endif memcpy(&ipa->address, &ina, sizeof(ina)); ipa->name = strdup(s); @@ -1773,6 +1833,7 @@ host_dns(const char *s, int mask) bzero(&hints, sizeof(struct addrinfo)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG; error = getaddrinfo(s, NULL, &hints, &res0); if (error) return (NULL); @@ -1909,15 +1970,12 @@ int ifa_exists(const char *ifa_name) { struct ipsec_addr_wrap *n; -#if defined(SIOCGIFGMEMB) struct ifgroupreq ifgr; int s; -#endif if (iftab == NULL) ifa_load(); -#if defined(SIOCGIFGMEMB) /* check wether this is a group */ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) err(1, "ifa_exists: socket"); @@ -1928,7 +1986,6 @@ ifa_exists(const char *ifa_name) return (1); } close(s); -#endif for (n = iftab; n; n = n->next) { if (n->af == AF_LINK && !strncmp(n->name, ifa_name, @@ -1942,7 +1999,6 @@ ifa_exists(const char *ifa_name) struct ipsec_addr_wrap * ifa_grouplookup(const char *ifa_name) { -#if defined(SIOCGIFGMEMB) struct ifg_req *ifg; struct ifgroupreq ifgr; int s; @@ -1982,9 +2038,6 @@ ifa_grouplookup(const char *ifa_name) close(s); return (h); -#else - return (NULL); -#endif } struct ipsec_addr_wrap * @@ -2176,7 +2229,8 @@ print_policy(struct iked_policy *pol) RB_FOREACH(flow, iked_flows, &pol->pol_flows) { print_verbose(" from %s", - print_host(&flow->flow_src.addr, NULL, 0)); + print_host((struct sockaddr *)&flow->flow_src.addr, NULL, + 0)); if (flow->flow_src.addr_af != AF_UNSPEC && flow->flow_src.addr_net) print_verbose("/%d", flow->flow_src.addr_mask); @@ -2185,7 +2239,8 @@ print_policy(struct iked_policy *pol) ntohs(flow->flow_src.addr_port)); print_verbose(" to %s", - print_host(&flow->flow_dst.addr, NULL, 0)); + print_host((struct sockaddr *)&flow->flow_dst.addr, NULL, + 0)); if (flow->flow_dst.addr_af != AF_UNSPEC && flow->flow_dst.addr_net) print_verbose("/%d", flow->flow_dst.addr_mask); @@ -2196,13 +2251,15 @@ print_policy(struct iked_policy *pol) if ((pol->pol_flags & IKED_POLICY_DEFAULT) == 0) { print_verbose(" local %s", - print_host(&pol->pol_local.addr, NULL, 0)); + print_host((struct sockaddr *)&pol->pol_local.addr, NULL, + 0)); if (pol->pol_local.addr.ss_family != AF_UNSPEC && pol->pol_local.addr_net) print_verbose("/%d", pol->pol_local.addr_mask); print_verbose(" peer %s", - print_host(&pol->pol_peer.addr, NULL, 0)); + print_host((struct sockaddr *)&pol->pol_peer.addr, NULL, + 0)); if (pol->pol_peer.addr.ss_family != AF_UNSPEC && pol->pol_peer.addr_net) print_verbose("/%d", pol->pol_peer.addr_mask); @@ -2266,6 +2323,9 @@ print_policy(struct iked_policy *pol) if (pol->pol_peerid.id_length != 0) print_verbose(" dstid %s", pol->pol_peerid.id_data); + if (pol->pol_rekey) + print_verbose(" ikelifetime %u", pol->pol_rekey); + print_verbose(" lifetime %llu bytes %llu", pol->pol_lifetime.lt_seconds, pol->pol_lifetime.lt_bytes); @@ -2287,7 +2347,8 @@ print_policy(struct iked_policy *pol) cfg = &pol->pol_cfg[i]; print_verbose(" config %s %s", print_xf(cfg->cfg_type, cfg->cfg.address.addr_af, cpxfs), - print_host(&cfg->cfg.address.addr, NULL, 0)); + print_host((struct sockaddr *)&cfg->cfg.address.addr, NULL, + 0)); } if (pol->pol_tag[0] != '\0') @@ -2335,10 +2396,13 @@ int create_ike(char *name, int af, u_int8_t ipproto, struct ipsec_hosts *hosts, struct ipsec_hosts *peers, struct ipsec_mode *ike_sa, struct ipsec_mode *ipsec_sa, u_int8_t saproto, - u_int8_t flags, char *srcid, char *dstid, struct iked_lifetime *lt, + u_int8_t flags, char *srcid, char *dstid, + u_int32_t ikelifetime, struct iked_lifetime *lt, struct iked_auth *authtype, struct ipsec_filters *filter, struct ipsec_addr_wrap *ikecfg) { + char idstr[IKED_ID_SIZE]; + u_int idtype = IKEV2_ID_NONE; struct ipsec_addr_wrap *ipa, *ipb; struct iked_policy pol; struct iked_proposal prop[2]; @@ -2350,8 +2414,10 @@ create_ike(char *name, int af, u_int8_t ipproto, struct ipsec_hosts *hosts, bzero(&pol, sizeof(pol)); bzero(&prop, sizeof(prop)); + bzero(idstr, sizeof(idstr)); pol.pol_id = ++policy_id; + pol.pol_certreqtype = env->sc_certreqtype; pol.pol_af = af; pol.pol_saproto = saproto; pol.pol_ipproto = ipproto; @@ -2457,6 +2523,9 @@ create_ike(char *name, int af, u_int8_t ipproto, struct ipsec_hosts *hosts, pol.pol_af = ipb->af; } + if (ikelifetime) + pol.pol_rekey = ikelifetime; + if (lt) pol.pol_lifetime = *lt; else @@ -2556,6 +2625,8 @@ create_ike(char *name, int af, u_int8_t ipproto, struct ipsec_hosts *hosts, flows[j].flow_dst.addr_net = ipb->netaddress; flows[j].flow_dst.addr_port = hosts->dport; + flows[j].flow_ipproto = ipproto; + pol.pol_nflows++; RB_INSERT(iked_flows, &pol.pol_flows, &flows[j]); } @@ -2575,6 +2646,29 @@ create_ike(char *name, int af, u_int8_t ipproto, struct ipsec_hosts *hosts, cfg->cfg.address.addr_af = ipa->af; } + if (dstid) { + strlcpy(idstr, dstid, sizeof(idstr)); + idtype = pol.pol_peerid.id_type; + } else if (!pol.pol_peer.addr_net) { + print_host((struct sockaddr *)&pol.pol_peer.addr, idstr, + sizeof(idstr)); + switch (pol.pol_peer.addr.ss_family) { + case AF_INET: + idtype = IKEV2_ID_IPV4; + break; + case AF_INET6: + idtype = IKEV2_ID_IPV6; + break; + default: + log_warnx("%s: unknown address family", __func__); + break; + } + } + + /* Check if we have a raw public key for this peer */ + if (check_pubkey(idstr, idtype) != -1) + pol.pol_certreqtype = IKEV2_CERT_RSA_KEY; + config_setpolicy(env, &pol, PROC_IKEV2); rules++; diff --git a/iked/pfkey.c b/iked/pfkey.c index 343e372..558722d 100644 --- a/iked/pfkey.c +++ b/iked/pfkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfkey.c,v 1.23 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: pfkey.c,v 1.43 2015/07/17 14:48:17 mikeb Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -45,22 +46,23 @@ #define IOV_CNT 20 #define PFKEYV2_CHUNK sizeof(u_int64_t) +#define PFKEY_REPLY_TIMEOUT 1000 static u_int32_t sadb_msg_seq = 0; static u_int sadb_decoupled = 0; static u_int sadb_ipv6refcnt = 0; static int pfkey_blockipv6 = 0; -static struct iked_timer pfkey_timer; -static struct iked_timer pfkey_pwrtimer; +static struct event pfkey_timer_ev; +static struct timeval pfkey_timer_tv; struct pfkey_message { SIMPLEQ_ENTRY(pfkey_message) pm_entry; u_int8_t *pm_data; - ssize_t pm_lenght; + ssize_t pm_length; }; -SIMPLEQ_HEAD(, pfkey_message) pfkey_postponed = +SIMPLEQ_HEAD(, pfkey_message) pfkey_retry, pfkey_postponed = SIMPLEQ_HEAD_INITIALIZER(pfkey_postponed); struct pfkey_constmap { @@ -81,12 +83,8 @@ static const struct pfkey_constmap pfkey_encr[] = { #ifdef SADB_X_EALG_IDEA { SADB_X_EALG_IDEA, IKEV2_XFORMENCR_IDEA }, #endif -#ifdef SADB_X_EALG_RC5 { SADB_X_EALG_CAST, IKEV2_XFORMENCR_CAST }, -#endif -#ifdef SADB_X_EALG_BLF { SADB_X_EALG_BLF, IKEV2_XFORMENCR_BLOWFISH }, -#endif #ifdef SADB_X_EALG_3IDEA { SADB_X_EALG_3IDEA, IKEV2_XFORMENCR_3IDEA }, #endif @@ -98,15 +96,9 @@ static const struct pfkey_constmap pfkey_encr[] = { #endif { SADB_EALG_NULL, IKEV2_XFORMENCR_NULL }, { SADB_X_EALG_AES, IKEV2_XFORMENCR_AES_CBC }, -#ifdef SADB_X_EALG_AESCTR { SADB_X_EALG_AESCTR, IKEV2_XFORMENCR_AES_CTR }, -#endif -#ifdef SADB_X_EALG_AESGCM16 { SADB_X_EALG_AESGCM16, IKEV2_XFORMENCR_AES_GCM_16 }, -#endif -#ifdef SADB_X_EALG_AESGMAC { SADB_X_EALG_AESGMAC, IKEV2_XFORMENCR_NULL_AES_GMAC }, -#endif { 0 } }; @@ -116,21 +108,16 @@ static const struct pfkey_constmap pfkey_integr[] = { #ifdef SADB_X_AALG_DES { SADB_X_AALG_DES, IKEV2_XFORMAUTH_DES_MAC }, #endif -#if defined(SADB_X_AALG_SHA2_256) && !defined(BROKEN_HMAC_SHA2_256) { SADB_X_AALG_SHA2_256, IKEV2_XFORMAUTH_HMAC_SHA2_256_128 }, -#endif -#ifdef SADB_X_AALG_SHA2_384 { SADB_X_AALG_SHA2_384, IKEV2_XFORMAUTH_HMAC_SHA2_384_192 }, -#endif -#ifdef SADB_X_AALG_SHA2_512 { SADB_X_AALG_SHA2_512, IKEV2_XFORMAUTH_HMAC_SHA2_512_256 }, -#endif { 0 } }; static const struct pfkey_constmap pfkey_satype[] = { { SADB_SATYPE_AH, IKEV2_SAPROTO_AH }, { SADB_SATYPE_ESP, IKEV2_SAPROTO_ESP }, + { SADB_X_SATYPE_IPCOMP, IKEV2_SAPROTO_IPCOMP }, { 0 } }; @@ -138,10 +125,8 @@ int pfkey_map(const struct pfkey_constmap *, u_int16_t, u_int8_t *); int pfkey_flow(int, u_int8_t, u_int8_t, struct iked_flow *); int pfkey_sa(int, u_int8_t, u_int8_t, struct iked_childsa *); int pfkey_sa_getspi(int, u_int8_t, struct iked_childsa *, u_int32_t *); -#if defined(_OPENBSD_IPSEC_API_VERSION) int pfkey_sagroup(int, u_int8_t, u_int8_t, struct iked_childsa *, struct iked_childsa *); -#endif int pfkey_write(int, struct sadb_msg *, struct iovec *, int, u_int8_t **, ssize_t *); int pfkey_reply(int, u_int8_t **, ssize_t *); @@ -151,8 +136,8 @@ struct sadb_ident * pfkey_id2ident(struct iked_id *, u_int); void *pfkey_find_ext(u_int8_t *, ssize_t, int); -void pfkey_timer_cb(struct iked *, void *); -void pfkey_process(struct iked *, struct pfkey_message *); +void pfkey_timer_cb(int, short, void *); +int pfkey_process(struct iked *, struct pfkey_message *); int pfkey_couple(int sd, struct iked_sas *sas, int couple) @@ -160,37 +145,38 @@ pfkey_couple(int sd, struct iked_sas *sas, int couple) struct iked_sa *sa; struct iked_flow *flow; struct iked_childsa *csa; - u_int old; const char *mode[] = { "coupled", "decoupled" }; /* Socket is not ready */ if (sd == -1) return (-1); - old = sadb_decoupled ? 1 : 0; - sadb_decoupled = couple ? 0 : 1; - - if (old == sadb_decoupled) + if (sadb_decoupled == !couple) return (0); log_debug("%s: kernel %s -> %s", __func__, - mode[old], mode[sadb_decoupled]); + mode[sadb_decoupled], mode[!sadb_decoupled]); + + /* Allow writes to the PF_KEY socket */ + sadb_decoupled = 0; RB_FOREACH(sa, iked_sas, sas) { TAILQ_FOREACH(csa, &sa->sa_childsas, csa_entry) { - if (!csa->csa_loaded && !sadb_decoupled) + if (!csa->csa_loaded && couple) (void)pfkey_sa_add(sd, csa, NULL); - else if (csa->csa_loaded && sadb_decoupled) + else if (csa->csa_loaded && !couple) (void)pfkey_sa_delete(sd, csa); } TAILQ_FOREACH(flow, &sa->sa_flows, flow_entry) { - if (!flow->flow_loaded && !sadb_decoupled) + if (!flow->flow_loaded && couple) (void)pfkey_flow_add(sd, flow); - else if (flow->flow_loaded && sadb_decoupled) + else if (flow->flow_loaded && !couple) (void)pfkey_flow_delete(sd, flow); } } + sadb_decoupled = !couple; + return (0); } @@ -219,19 +205,16 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) struct sockaddr_storage ssrc, sdst, slocal, speer, smask, dmask; struct iovec iov[IOV_CNT]; int iov_cnt, ret = -1; - in_port_t sport, dport; - sport = dport = 0; sa_srcid = sa_dstid = NULL; bzero(&ssrc, sizeof(ssrc)); bzero(&smask, sizeof(smask)); memcpy(&ssrc, &flow->flow_src.addr, sizeof(ssrc)); memcpy(&smask, &flow->flow_src.addr, sizeof(smask)); - if ((sport = flow->flow_src.addr_port) != 0) - dport = 0xffff; - socket_af((struct sockaddr *)&ssrc, sport); - socket_af((struct sockaddr *)&smask, dport); + socket_af((struct sockaddr *)&ssrc, flow->flow_src.addr_port); + socket_af((struct sockaddr *)&smask, flow->flow_src.addr_port ? + 0xfffff : 0); switch (flow->flow_src.addr_af) { case AF_INET: @@ -256,10 +239,9 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) bzero(&dmask, sizeof(dmask)); memcpy(&sdst, &flow->flow_dst.addr, sizeof(sdst)); memcpy(&dmask, &flow->flow_dst.addr, sizeof(dmask)); - if ((sport = flow->flow_dst.addr_port) != 0) - dport = 0xffff; - socket_af((struct sockaddr *)&sdst, sport); - socket_af((struct sockaddr *)&dmask, dport); + socket_af((struct sockaddr *)&sdst, flow->flow_dst.addr_port); + socket_af((struct sockaddr *)&dmask, flow->flow_dst.addr_port ? + 0xffff : 0); switch (flow->flow_dst.addr_af) { case AF_INET: @@ -345,11 +327,11 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) (sizeof(sa_peer) + ROUNDUP(speer.ss_len)) / 8; /* local id */ - sa_srcid = pfkey_id2ident(flow->flow_srcid, + sa_srcid = pfkey_id2ident(IKESA_SRCID(flow->flow_ikesa), SADB_EXT_IDENTITY_SRC); /* peer id */ - sa_dstid = pfkey_id2ident(flow->flow_dstid, + sa_dstid = pfkey_id2ident(IKESA_DSTID(flow->flow_ikesa), SADB_EXT_IDENTITY_DST); } @@ -642,9 +624,7 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) log_debug("%s: erronous reply", __func__); goto done; } - flow->flow_id = sa_polid->sadb_x_policy_id; - log_debug("%s: flow with policy id 0x%x", __func__, flow->flow_id); ret = 0; done: @@ -670,9 +650,6 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) struct sadb_x_tap sa_tap; #else struct sadb_x_sa2 sa_2; -#if defined(HAVE_APPLE_NATT) - struct sadb_sa_natt natt; -#endif #endif struct sockaddr_storage ssrc, sdst; struct sadb_ident *sa_srcid, *sa_dstid; @@ -721,8 +698,8 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) sadb.sadb_sa_replay = 64; #if defined(_OPENBSD_IPSEC_API_VERSION) - /* XXX we don't support transport mode, yet */ - sadb.sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL; + if (!sa->csa_transport) + sadb.sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL; if (sa->csa_esn) sadb.sadb_sa_flags |= SADB_X_SAFLAGS_ESN; @@ -730,15 +707,18 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) bzero(&sa_2, sizeof(sa_2)); sa_2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; sa_2.sadb_x_sa2_len = sizeof(sa_2) / 8; - sa_2.sadb_x_sa2_mode = IPSEC_MODE_TUNNEL; /* XXX */ + if (!sa->csa_transport) + sa_2.sadb_x_sa2_mode = IPSEC_MODE_TUNNEL; + else + sa_2.sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT; #endif bzero(&sa_src, sizeof(sa_src)); - sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(SS_LEN(&ssrc))) / 8; + sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; bzero(&sa_dst, sizeof(sa_dst)); - sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(SS_LEN(&sdst))) / 8; + sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; bzero(&sa_authkey, sizeof(sa_authkey)); @@ -761,14 +741,18 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) sa_ltime_hard.sadb_lifetime_bytes = lt->lt_bytes; sa_ltime_hard.sadb_lifetime_addtime = lt->lt_seconds; + /* double the lifetime for IP compression */ + if (satype == SADB_X_SATYPE_IPCOMP) + sa_ltime_hard.sadb_lifetime_addtime *= 2; + sa_ltime_soft.sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; sa_ltime_soft.sadb_lifetime_len = sizeof(sa_ltime_soft) / 8; /* set randomly to 85-95% */ jitter = 850 + arc4random_uniform(100); sa_ltime_soft.sadb_lifetime_bytes = - (lt->lt_bytes * jitter) / 1000; + (sa_ltime_hard.sadb_lifetime_bytes * jitter) / 1000; sa_ltime_soft.sadb_lifetime_addtime = - (lt->lt_seconds * jitter) / 1000; + (sa_ltime_hard.sadb_lifetime_addtime * jitter) / 1000; } /* XXX handle NULL encryption or NULL auth or combined encr/auth */ @@ -779,48 +763,40 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) && satype != SADB_X_SATYPE_IPIP #endif ) { - log_warnx("%s: no key specified", __func__); return (-1); } - if (sa->csa_ikesa->sa_udpencap && sa->csa_ikesa->sa_natt) { + if (satype == SADB_SATYPE_ESP && + sa->csa_ikesa->sa_udpencap && sa->csa_ikesa->sa_natt) { #if defined(_OPENBSD_IPSEC_API_VERSION) sadb.sadb_sa_flags |= SADB_X_SAFLAGS_UDPENCAP; udpencap.sadb_x_udpencap_exttype = SADB_X_EXT_UDPENCAP; udpencap.sadb_x_udpencap_len = sizeof(udpencap) / 8; udpencap.sadb_x_udpencap_port = sa->csa_ikesa->sa_peer.addr_port; -#elif defined(HAVE_APPLE_NATT) - sadb.sadb_sa_flags |= SADB_X_EXT_NATT; - /* XXX check NAT detection for local/peer hash instead */ - if (sa->csa_dir == IPSP_DIRECTION_OUT) - sadb.sadb_sa_flags |= SADB_X_EXT_NATT_KEEPALIVE; - else - sadb.sadb_sa_flags |= SADB_X_EXT_NATT_DETECTED_PEER; - natt.sadb_sa_natt_port = - ntohs(sa->csa_ikesa->sa_peer.addr_port); + + log_debug("%s: udpencap port %d", __func__, + ntohs(udpencap.sadb_x_udpencap_port)); #else #warning PFKEYv2 NAT-T not supported #endif - log_debug("%s: udpencap port %u", __func__, - ntohs(sa->csa_ikesa->sa_peer.addr_port)); } - if (sa->csa_integrxf) + if (sa->csa_integrid) if (pfkey_map(pfkey_integr, - sa->csa_integrxf->xform_id, &sadb.sadb_sa_auth) == -1) { + sa->csa_integrid, &sadb.sadb_sa_auth) == -1) { log_warnx("%s: unsupported integrity algorithm %s", - __func__, print_map(sa->csa_integrxf->xform_id, + __func__, print_map(sa->csa_integrid, ikev2_xformauth_map)); return (-1); } - if (sa->csa_encrxf) + if (sa->csa_encrid) if (pfkey_map(pfkey_encr, - sa->csa_encrxf->xform_id, &sadb.sadb_sa_encrypt) == -1) { + sa->csa_encrid, &sadb.sadb_sa_encrypt) == -1) { log_warnx("%s: unsupported encryption algorithm %s", - __func__, print_map(sa->csa_encrxf->xform_id, + __func__, print_map(sa->csa_encrid, ikev2_xformencr_map)); return (-1); } @@ -841,11 +817,22 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) 8 * ibuf_size(sa->csa_encrkey); } - /* local id */ - sa_srcid = pfkey_id2ident(sa->csa_srcid, SADB_EXT_IDENTITY_SRC); + /* we only support deflate */ + if (satype == SADB_X_SATYPE_IPCOMP) + sadb.sadb_sa_encrypt = SADB_X_CALG_DEFLATE; - /* peer id */ - sa_dstid = pfkey_id2ident(sa->csa_dstid, SADB_EXT_IDENTITY_DST); + /* Note that we need to swap the IDs for incoming SAs (SADB_UPDATE) */ + if (action != SADB_UPDATE) { + sa_srcid = pfkey_id2ident( + IKESA_SRCID(sa->csa_ikesa), SADB_EXT_IDENTITY_SRC); + sa_dstid = pfkey_id2ident( + IKESA_DSTID(sa->csa_ikesa), SADB_EXT_IDENTITY_DST); + } else { + sa_srcid = pfkey_id2ident( + IKESA_DSTID(sa->csa_ikesa), SADB_EXT_IDENTITY_SRC); + sa_dstid = pfkey_id2ident( + IKESA_SRCID(sa->csa_ikesa), SADB_EXT_IDENTITY_DST); + } #if defined(_OPENBSD_IPSEC_API_VERSION) tag = sa->csa_ikesa->sa_tag; @@ -877,31 +864,15 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) /* sa */ iov[iov_cnt].iov_base = &sadb; iov[iov_cnt].iov_len = sizeof(sadb); -#if defined(HAVE_APPLE_NATT) - if (natt.sadb_sa_natt_port) { - iov_cnt++; - iov[iov_cnt].iov_base = &natt; - iov[iov_cnt].iov_len = sizeof(natt); - sadb.sadb_sa_len += sizeof(natt) / 8; - } -#endif smsg.sadb_msg_len += sadb.sadb_sa_len; iov_cnt++; -#if !defined(_OPENBSD_IPSEC_API_VERSION) - /* sa2 */ - iov[iov_cnt].iov_base = &sa_2; - iov[iov_cnt].iov_len = sizeof(sa_2); - smsg.sadb_msg_len += sa_2.sadb_x_sa2_len; - iov_cnt++; -#endif - /* src addr */ iov[iov_cnt].iov_base = &sa_src; iov[iov_cnt].iov_len = sizeof(sa_src); iov_cnt++; iov[iov_cnt].iov_base = &ssrc; - iov[iov_cnt].iov_len = ROUNDUP(SS_LEN(&ssrc)); + iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); smsg.sadb_msg_len += sa_src.sadb_address_len; iov_cnt++; @@ -910,7 +881,7 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) iov[iov_cnt].iov_len = sizeof(sa_dst); iov_cnt++; iov[iov_cnt].iov_base = &sdst; - iov[iov_cnt].iov_len = ROUNDUP(SS_LEN(&sdst)); + iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); smsg.sadb_msg_len += sa_dst.sadb_address_len; iov_cnt++; @@ -930,14 +901,12 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) iov_cnt++; } -#if defined(_OPENBSD_IPSEC_API_VERSION) if (udpencap.sadb_x_udpencap_len) { iov[iov_cnt].iov_base = &udpencap; iov[iov_cnt].iov_len = sizeof(udpencap); smsg.sadb_msg_len += udpencap.sadb_x_udpencap_len; iov_cnt++; } -#endif if (sa_enckey.sadb_key_len) { /* encryption key */ @@ -977,7 +946,6 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) iov_cnt++; } -#if defined(_OPENBSD_IPSEC_API_VERSION) if (tag != NULL) { /* tag identity */ iov[iov_cnt].iov_base = &sa_tag; @@ -996,11 +964,122 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) smsg.sadb_msg_len += sa_tap.sadb_x_tap_len; iov_cnt++; } -#endif return (pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL)); } +int +pfkey_sa_last_used(int sd, struct iked_childsa *sa, u_int64_t *last_used) +{ + struct sadb_msg *msg, smsg; + struct sadb_address sa_src, sa_dst; + struct sadb_sa sadb; + struct sadb_lifetime *sa_life; + struct sockaddr_storage ssrc, sdst; + struct iovec iov[IOV_CNT]; + u_int8_t *data; + ssize_t n; + int iov_cnt, ret = -1; + u_int8_t satype; + + *last_used = 0; + + if (pfkey_map(pfkey_satype, sa->csa_saproto, &satype) == -1) + return (-1); + + bzero(&ssrc, sizeof(ssrc)); + memcpy(&ssrc, &sa->csa_local->addr, sizeof(ssrc)); + if (socket_af((struct sockaddr *)&ssrc, 0) == -1) { + log_warn("%s: invalid address", __func__); + return (-1); + } + + bzero(&sdst, sizeof(sdst)); + memcpy(&sdst, &sa->csa_peer->addr, sizeof(sdst)); + if (socket_af((struct sockaddr *)&sdst, 0) == -1) { + log_warn("%s: invalid address", __func__); + return (-1); + } + + bzero(&smsg, sizeof(smsg)); + smsg.sadb_msg_version = PF_KEY_V2; + smsg.sadb_msg_seq = ++sadb_msg_seq; + smsg.sadb_msg_pid = getpid(); + smsg.sadb_msg_len = sizeof(smsg) / 8; + smsg.sadb_msg_type = SADB_GET; + smsg.sadb_msg_satype = satype; + + bzero(&sadb, sizeof(sadb)); + sadb.sadb_sa_len = sizeof(sadb) / 8; + sadb.sadb_sa_exttype = SADB_EXT_SA; + sadb.sadb_sa_spi = htonl(sa->csa_spi.spi); + sadb.sadb_sa_state = SADB_SASTATE_MATURE; + sadb.sadb_sa_replay = 64; + + bzero(&sa_src, sizeof(sa_src)); + sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; + sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + + bzero(&sa_dst, sizeof(sa_dst)); + sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; + sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + + iov_cnt = 0; + + /* header */ + iov[iov_cnt].iov_base = &smsg; + iov[iov_cnt].iov_len = sizeof(smsg); + iov_cnt++; + + /* sa */ + iov[iov_cnt].iov_base = &sadb; + iov[iov_cnt].iov_len = sizeof(sadb); + smsg.sadb_msg_len += sadb.sadb_sa_len; + iov_cnt++; + + /* src addr */ + iov[iov_cnt].iov_base = &sa_src; + iov[iov_cnt].iov_len = sizeof(sa_src); + iov_cnt++; + iov[iov_cnt].iov_base = &ssrc; + iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); + smsg.sadb_msg_len += sa_src.sadb_address_len; + iov_cnt++; + + /* dst addr */ + iov[iov_cnt].iov_base = &sa_dst; + iov[iov_cnt].iov_len = sizeof(sa_dst); + iov_cnt++; + iov[iov_cnt].iov_base = &sdst; + iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); + smsg.sadb_msg_len += sa_dst.sadb_address_len; + iov_cnt++; + + if ((ret = pfkey_write(sd, &smsg, iov, iov_cnt, &data, &n)) != 0) + return (-1); + + msg = (struct sadb_msg *)data; + if (msg->sadb_msg_errno != 0) { + errno = msg->sadb_msg_errno; + ret = -1; + log_warn("%s: message", __func__); + goto done; + } + if ((sa_life = pfkey_find_ext(data, n, SADB_X_EXT_LIFETIME_LASTUSE)) + == NULL) { + /* has never been used */ + ret = -1; + goto done; + } + *last_used = sa_life->sadb_lifetime_usetime; + log_debug("%s: last_used %llu", __func__, *last_used); + +done: + bzero(data, n); + free(data); + return (ret); +} + int pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, u_int32_t *spip) @@ -1014,9 +1093,6 @@ pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, u_int8_t *data; ssize_t n; int iov_cnt, ret = -1; -#if !defined(_OPENBSD_IPSEC_API_VERSION) - struct sadb_x_sa2 sa_2; -#endif bzero(&ssrc, sizeof(ssrc)); memcpy(&ssrc, &sa->csa_local->addr, sizeof(ssrc)); @@ -1040,32 +1116,21 @@ pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, smsg.sadb_msg_type = SADB_GETSPI; smsg.sadb_msg_satype = satype; -#if !defined(_OPENBSD_IPSEC_API_VERSION) - bzero(&sa_2, sizeof(sa_2)); - sa_2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - sa_2.sadb_x_sa2_len = sizeof(sa_2) / 8; - sa_2.sadb_x_sa2_mode = IPSEC_MODE_TUNNEL; -#endif - bzero(&sa_spirange, sizeof(sa_spirange)); sa_spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE; sa_spirange.sadb_spirange_len = sizeof(sa_spirange) / 8; sa_spirange.sadb_spirange_min = 0x100; - sa_spirange.sadb_spirange_max = 0xffffffff; + sa_spirange.sadb_spirange_max = (satype == SADB_X_SATYPE_IPCOMP) ? + (CPI_PRIVATE_MIN - 1) : 0xffffffff; + sa_spirange.sadb_spirange_reserved = 0; bzero(&sa_src, sizeof(sa_src)); - sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(SS_LEN(&ssrc))) / 8; + sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; - sa_src.sadb_address_proto = IPSEC_ULPROTO_ANY; - sa_src.sadb_address_prefixlen = (ssrc.ss_family == AF_INET ? - sizeof(struct in_addr) : sizeof(struct in6_addr)) << 3; bzero(&sa_dst, sizeof(sa_dst)); - sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(SS_LEN(&sdst))) / 8; + sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; - sa_dst.sadb_address_proto = IPSEC_ULPROTO_ANY; - sa_dst.sadb_address_prefixlen = (sdst.ss_family == AF_INET ? - sizeof(struct in_addr) : sizeof(struct in6_addr)) << 3; iov_cnt = 0; @@ -1074,20 +1139,18 @@ pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, iov[iov_cnt].iov_len = sizeof(smsg); iov_cnt++; -#if !defined(_OPENBSD_IPSEC_API_VERSION) - /* extended SA header */ - iov[iov_cnt].iov_base = &sa_2; - iov[iov_cnt].iov_len = sizeof(sa_2); - smsg.sadb_msg_len += sa_2.sadb_x_sa2_len; + /* SPI range */ + iov[iov_cnt].iov_base = &sa_spirange; + iov[iov_cnt].iov_len = sizeof(sa_spirange); + smsg.sadb_msg_len += sa_spirange.sadb_spirange_len; iov_cnt++; -#endif /* src addr */ iov[iov_cnt].iov_base = &sa_src; iov[iov_cnt].iov_len = sizeof(sa_src); iov_cnt++; iov[iov_cnt].iov_base = &ssrc; - iov[iov_cnt].iov_len = ROUNDUP(SS_LEN(&ssrc)); + iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); smsg.sadb_msg_len += sa_src.sadb_address_len; iov_cnt++; @@ -1096,16 +1159,10 @@ pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, iov[iov_cnt].iov_len = sizeof(sa_dst); iov_cnt++; iov[iov_cnt].iov_base = &sdst; - iov[iov_cnt].iov_len = ROUNDUP(SS_LEN(&sdst)); + iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); smsg.sadb_msg_len += sa_dst.sadb_address_len; iov_cnt++; - /* SPI range */ - iov[iov_cnt].iov_base = &sa_spirange; - iov[iov_cnt].iov_len = sizeof(sa_spirange); - smsg.sadb_msg_len += sa_spirange.sadb_spirange_len; - iov_cnt++; - *spip = 0; if ((ret = pfkey_write(sd, &smsg, iov, iov_cnt, &data, &n)) != 0) @@ -1131,7 +1188,6 @@ pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, return (ret); } -#if defined(_OPENBSD_IPSEC_API_VERSION) int pfkey_sagroup(int sd, u_int8_t satype1, u_int8_t action, struct iked_childsa *sa1, struct iked_childsa *sa2) @@ -1244,7 +1300,6 @@ pfkey_sagroup(int sd, u_int8_t satype1, u_int8_t action, return (pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL)); } -#endif int pfkey_write(int sd, struct sadb_msg *smsg, struct iovec *iov, int iov_cnt, @@ -1285,8 +1340,30 @@ pfkey_reply(int sd, u_int8_t **datap, ssize_t *lenp) struct sadb_msg hdr; ssize_t len; u_int8_t *data; + struct pollfd pfd[1]; + int n; + + pfd[0].fd = sd; + pfd[0].events = POLLIN; for (;;) { + /* + * We should actually expect the reply to get lost + * as PF_KEY is an unreliable service per the specs. + * Currently we do this by setting a short timeout, + * and if it is not readable in that time, we fail + * the read. + */ + n = poll(pfd, 1, PFKEY_REPLY_TIMEOUT / 1000); + if (n == -1) { + log_warn("%s: poll() failed", __func__); + return (-1); + } + if (n == 0) { + log_warnx("%s: no reply from PF_KEY", __func__); + return (-1); + } + if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) { log_warn("%s: short recv", __func__); return (-1); @@ -1297,11 +1374,13 @@ pfkey_reply(int sd, u_int8_t **datap, ssize_t *lenp) return (-1); } - len = hdr.sadb_msg_len * PFKEYV2_CHUNK; - if ((data = malloc(len)) == NULL) { + if ((data = reallocarray(NULL, hdr.sadb_msg_len, + PFKEYV2_CHUNK)) == NULL) { log_warn("%s: malloc", __func__); return (-1); } + len = hdr.sadb_msg_len * PFKEYV2_CHUNK; + if (read(sd, data, len) != len) { log_warnx("%s: short read", __func__); free(data); @@ -1313,16 +1392,23 @@ pfkey_reply(int sd, u_int8_t **datap, ssize_t *lenp) hdr.sadb_msg_pid == (u_int32_t)getpid()) break; + /* ignore messages for other processes */ + if (hdr.sadb_msg_pid != 0 && + hdr.sadb_msg_pid != (u_int32_t)getpid()) { + free(data); + continue; + } + /* not the reply, enqueue */ if ((pm = malloc(sizeof(*pm))) == NULL) { - log_warn("%s", __func__); + log_warn("%s: malloc", __func__); free(data); return (-1); } pm->pm_data = data; - pm->pm_lenght = len; + pm->pm_length = len; SIMPLEQ_INSERT_TAIL(&pfkey_postponed, pm, pm_entry); - timer_register(NULL, &pfkey_timer, 1); + evtimer_add(&pfkey_timer_ev, &pfkey_timer_tv); } if (datap) { @@ -1397,16 +1483,6 @@ pfkey_block(int fd, int af, u_int action) { struct iked_flow flow; -#if !defined(_OPENBSD_IPSEC_API_VERSION) && !defined(XXX_BLOCK_IPV6) - /* - * XXX This is work in progress, I didn't have time to make - * XXX this work with PFKEYv2 on KAME-based platforms yet. - */ -#warning PFKEYv2 IPv6 blocking not supported - log_debug("%s: not yet supported on this platform, ignored", __func__); - return (0); -#endif - if (!pfkey_blockipv6) return (0); @@ -1466,19 +1542,27 @@ pfkey_sa_add(int fd, struct iked_childsa *sa, struct iked_childsa *last) print_spi(sa->csa_spi.spi, 4)); if (pfkey_sa(fd, satype, cmd, sa) == -1) { - if (cmd == SADB_ADD) + if (cmd == SADB_ADD) { (void)pfkey_sa_delete(fd, sa); - return (-1); + return (-1); + } + if (sa->csa_allocated && !sa->csa_loaded && errno == ESRCH) { + /* Needed for recoupling local SAs */ + log_debug("%s: SADB_UPDATE on local SA returned ESRCH," + " trying SADB_ADD", __func__); + if (pfkey_sa(fd, satype, SADB_ADD, sa) == -1) + return (-1); + } else { + return (-1); + } } if (last && cmd == SADB_ADD) { -#if defined(_OPENBSD_IPSEC_API_VERSION) if (pfkey_sagroup(fd, satype, SADB_X_GRPSPIS, sa, last) == -1) { (void)pfkey_sa_delete(fd, sa); return (-1); } -#endif } sa->csa_loaded = 1; @@ -1504,7 +1588,7 @@ pfkey_sa_delete(int fd, struct iked_childsa *sa) } int -pfkey_flush(int sd, u_int what) +pfkey_flush(int sd) { struct sadb_msg smsg; struct iovec iov[IOV_CNT]; @@ -1515,7 +1599,7 @@ pfkey_flush(int sd, u_int what) smsg.sadb_msg_seq = ++sadb_msg_seq; smsg.sadb_msg_pid = getpid(); smsg.sadb_msg_len = sizeof(smsg) / 8; - smsg.sadb_msg_type = what; + smsg.sadb_msg_type = SADB_FLUSH; smsg.sadb_msg_satype = SADB_SATYPE_UNSPEC; iov_cnt = 0; @@ -1572,27 +1656,6 @@ pfkey_id2ident(struct iked_id *id, u_int exttype) return (sa_id); } -void -pfkey_pwrtimer_cb(struct iked *env, void *arg) -{ -#ifdef __APPLE__ - static struct timeval waketime = { 0, 0 }; - struct timeval tv; - size_t size = sizeof(tv); - - if (sysctlbyname("kern.waketime", &tv, &size, NULL, 0) == 0) { - if (waketime.tv_sec != 0 && - memcmp(&waketime, &tv, sizeof(waketime)) != 0) { - log_info("%s: after power resume", __func__); - pfkey_flush(env->sc_pfkey, SADB_FLUSH); - } - memcpy(&waketime, &tv, sizeof(waketime)); - } -#endif - - timer_register(env, &pfkey_pwrtimer, 3); -} - int pfkey_socket(void) { @@ -1604,8 +1667,7 @@ pfkey_socket(void) if ((fd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) == -1) fatal("pfkey_socket: failed to open PF_KEY socket"); - pfkey_flush(fd, SADB_FLUSH); - pfkey_flush(fd, SADB_X_SPDFLUSH); + pfkey_flush(fd); return (fd); } @@ -1616,6 +1678,11 @@ pfkey_init(struct iked *env, int fd) struct sadb_msg smsg; struct iovec iov; + /* Set up a timer to process messages deferred by the pfkey_reply */ + pfkey_timer_tv.tv_sec = 1; + pfkey_timer_tv.tv_usec = 0; + evtimer_set(&pfkey_timer_ev, pfkey_timer_cb, env); + /* Register the pfkey socket event handler */ env->sc_pfkey = fd; event_set(&env->sc_pfkeyev, env->sc_pfkey, @@ -1651,13 +1718,6 @@ pfkey_init(struct iked *env, int fd) if (pfkey_write(fd, &smsg, &iov, 1, NULL, NULL)) fatal("pfkey_init: failed to set up AH acquires"); - /* Set up a timer to process messages deferred by the pfkey_reply */ - timer_initialize(env, &pfkey_timer, pfkey_timer_cb, NULL); - - /* Run a timer to flush the SADB after power resume */ - timer_initialize(env, &pfkey_pwrtimer, pfkey_pwrtimer_cb, NULL); - timer_register(env, &pfkey_pwrtimer, 3); - if (env->sc_opts & IKED_OPT_NOIPV6BLOCKING) return; @@ -1687,7 +1747,7 @@ void pfkey_dispatch(int sd, short event, void *arg) { struct iked *env = (struct iked *)arg; - struct pfkey_message pm; + struct pfkey_message pm, *pmp; struct sadb_msg hdr; ssize_t len; u_int8_t *data; @@ -1702,39 +1762,71 @@ pfkey_dispatch(int sd, short event, void *arg) return; } - len = hdr.sadb_msg_len * PFKEYV2_CHUNK; - if ((data = malloc(len)) == NULL) { + if ((data = reallocarray(NULL, hdr.sadb_msg_len, PFKEYV2_CHUNK)) + == NULL) { log_warn("%s: malloc", __func__); return; } + len = hdr.sadb_msg_len * PFKEYV2_CHUNK; + if (read(sd, data, len) != len) { log_warn("%s: short read", __func__); free(data); return; } - pm.pm_data = data; - pm.pm_lenght = len; - pfkey_process(env, &pm); + /* Try postponed requests first, so we do in-order processing */ + if (!SIMPLEQ_EMPTY(&pfkey_postponed)) + pfkey_timer_cb(0, 0, env); - free(data); + pm.pm_data = data; + pm.pm_length = len; + + if (pfkey_process(env, &pm) == -1 && + (pmp = calloc(1, sizeof(*pmp))) != NULL) { + pmp->pm_data = data; + pmp->pm_length = len; + log_debug("%s: pfkey_process is busy, retry later", __func__); + SIMPLEQ_INSERT_TAIL(&pfkey_postponed, pmp, pm_entry); + evtimer_add(&pfkey_timer_ev, &pfkey_timer_tv); + } else { + free(data); + } } void -pfkey_timer_cb(struct iked *env, void *arg) +pfkey_timer_cb(int unused, short event, void *arg) { + struct iked *env = arg; struct pfkey_message *pm; + SIMPLEQ_INIT(&pfkey_retry); while (!SIMPLEQ_EMPTY(&pfkey_postponed)) { pm = SIMPLEQ_FIRST(&pfkey_postponed); SIMPLEQ_REMOVE_HEAD(&pfkey_postponed, pm_entry); - pfkey_process(env, pm); - free(pm->pm_data); - free(pm); + if (pfkey_process(env, pm) == -1) { + log_debug("%s: pfkey_process is busy, retry later", + __func__); + SIMPLEQ_INSERT_TAIL(&pfkey_retry, pm, pm_entry); + } else { + free(pm->pm_data); + free(pm); + } + } + /* move from retry to postponed */ + while ((pm = SIMPLEQ_FIRST(&pfkey_retry)) != NULL) { + SIMPLEQ_REMOVE_HEAD(&pfkey_retry, pm_entry); + SIMPLEQ_INSERT_TAIL(&pfkey_postponed, pm, pm_entry); } + if (!SIMPLEQ_EMPTY(&pfkey_postponed)) + evtimer_add(&pfkey_timer_ev, &pfkey_timer_tv); } -void +/* + * pfkey_process returns 0 if the message has been processed and -1 if + * the system is busy and the the message should be passed again, later. + */ +int pfkey_process(struct iked *env, struct pfkey_message *pm) { struct iked_spi spi; @@ -1748,54 +1840,58 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) struct sadb_address *sa_addr; struct sadb_protocol *sa_proto; struct sadb_x_policy sa_pol; - struct sadb_x_sa2 sa_2; - struct sockaddr_storage *ssrc, *sdst, *smask, *dmask, *speer; + struct sockaddr *ssrc, *sdst, *smask, *dmask, *speer; struct iovec iov[IOV_CNT]; - int iov_cnt, sd = env->sc_pfkey; + int ret = 0, iov_cnt, sd; u_int8_t *reply; ssize_t rlen; const char *errmsg = NULL; #else - struct iked_addr peer; - struct sadb_address *sa_addr; - struct sockaddr_storage *speer; - struct sadb_x_policy *sa_pol; - struct iked_flow *flow; + struct iked_addr peer; + struct sadb_address *sa_addr; + struct sockaddr_storage *speer; + struct sadb_x_policy *sa_pol; + struct iked_flow *flow; #endif u_int8_t *data = pm->pm_data; - ssize_t len = pm->pm_lenght; + ssize_t len = pm->pm_length; + size_t slen; if (!env || !data || !len) - return; + return (0); + sd = env->sc_pfkey; hdr = (struct sadb_msg *)data; switch (hdr->sadb_msg_type) { case SADB_ACQUIRE: - /* Get peer from the acquire message */ + bzero(&flow, sizeof(flow)); + bzero(&peer, sizeof(peer)); + if ((sa_addr = pfkey_find_ext(data, len, SADB_EXT_ADDRESS_DST)) == NULL) { log_debug("%s: no peer address", __func__); - return; + return (0); } - speer = (struct sockaddr_storage *)(sa_addr + 1); - bzero(&peer, sizeof(peer)); - peer.addr_af = speer->ss_family; + speer = (struct sockaddr *)(sa_addr + 1); + peer.addr_af = speer->sa_family; peer.addr_port = htons(socket_getport(speer)); - memcpy(&peer.addr, speer, sizeof(*speer)); + if ((slen = speer->sa_len) > sizeof(peer.addr)) { + log_debug("%s: invalid peer address len", __func__); + return (0); + } + memcpy(&peer.addr, speer, slen); if (socket_af((struct sockaddr *)&peer.addr, peer.addr_port) == -1) { log_debug("%s: invalid address", __func__); - return; + return (0); } + flow.flow_peer = &peer; + log_debug("%s: acquire request (peer %s)", __func__, print_host(speer, NULL, 0)); -#if defined(_OPENBSD_IPSEC_API_VERSION) - /* Get the matching flow */ - bzero(&flow, sizeof(flow)); - flow.flow_peer = &peer; - + /* get the matching flow */ bzero(&smsg, sizeof(smsg)); smsg.sadb_msg_version = PF_KEY_V2; smsg.sadb_msg_seq = ++sadb_msg_seq; @@ -1821,7 +1917,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) if (pfkey_write(sd, &smsg, iov, iov_cnt, &reply, &rlen)) { log_warnx("%s: failed to get a policy", __func__); - return; + return (0); } if ((sa_addr = pfkey_find_ext(reply, rlen, @@ -1829,14 +1925,18 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) errmsg = "flow source address"; goto out; } - ssrc = (struct sockaddr_storage *)(sa_addr + 1); - flow.flow_src.addr_af = ssrc->ss_family; + ssrc = (struct sockaddr *)(sa_addr + 1); + flow.flow_src.addr_af = ssrc->sa_family; flow.flow_src.addr_port = htons(socket_getport(ssrc)); - memcpy(&flow.flow_src.addr, ssrc, sizeof(*ssrc)); + if ((slen = ssrc->sa_len) > sizeof(flow.flow_src.addr)) { + log_debug("%s: invalid src address len", __func__); + return (0); + } + memcpy(&flow.flow_src.addr, ssrc, slen); if (socket_af((struct sockaddr *)&flow.flow_src.addr, flow.flow_src.addr_port) == -1) { log_debug("%s: invalid address", __func__); - return; + return (0); } if ((sa_addr = pfkey_find_ext(reply, rlen, @@ -1844,14 +1944,18 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) errmsg = "flow destination address"; goto out; } - sdst = (struct sockaddr_storage *)(sa_addr + 1); - flow.flow_dst.addr_af = sdst->ss_family; + sdst = (struct sockaddr *)(sa_addr + 1); + flow.flow_dst.addr_af = sdst->sa_family; flow.flow_dst.addr_port = htons(socket_getport(sdst)); - memcpy(&flow.flow_dst.addr, sdst, sizeof(*sdst)); + if ((slen = sdst->sa_len) > sizeof(flow.flow_dst.addr)) { + log_debug("%s: invalid dst address len", __func__); + return (0); + } + memcpy(&flow.flow_dst.addr, sdst, slen); if (socket_af((struct sockaddr *)&flow.flow_dst.addr, flow.flow_dst.addr_port) == -1) { log_debug("%s: invalid address", __func__); - return; + return (0); } if ((sa_addr = pfkey_find_ext(reply, rlen, @@ -1859,8 +1963,8 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) errmsg = "flow source mask"; goto out; } - smask = (struct sockaddr_storage *)(sa_addr + 1); - switch (smask->ss_family) { + smask = (struct sockaddr *)(sa_addr + 1); + switch (smask->sa_family) { case AF_INET: flow.flow_src.addr_mask = mask2prefixlen((struct sockaddr *)smask); @@ -1876,7 +1980,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) default: log_debug("%s: bad address family", __func__); free(reply); - return; + return (0); } if ((sa_addr = pfkey_find_ext(reply, rlen, @@ -1884,8 +1988,8 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) errmsg = "flow destination mask"; goto out; } - dmask = (struct sockaddr_storage *)(sa_addr + 1); - switch (dmask->ss_family) { + dmask = (struct sockaddr *)(sa_addr + 1); + switch (dmask->sa_family) { case AF_INET: flow.flow_dst.addr_mask = mask2prefixlen((struct sockaddr *)dmask); @@ -1901,7 +2005,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) default: log_debug("%s: bad address family", __func__); free(reply); - return; + return (0); } if ((sa_proto = pfkey_find_ext(reply, rlen, @@ -1917,45 +2021,18 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) print_host(sdst, NULL, 0), print_host(dmask, NULL, 0), print_host(speer, NULL, 0)); - ikev2_acquire_sa(env, &flow); + ret = ikev2_acquire_sa(env, &flow); out: if (errmsg) log_warnx("%s: %s wasn't found", __func__, errmsg); free(reply); -#elif defined(SADB_X_EXT_POLICY) - if ((sa_pol = pfkey_find_ext(data, len, - SADB_X_EXT_POLICY)) == NULL) { - log_debug("%s: no policy extension", __func__); - return; - } - - RB_FOREACH(flow, iked_flows, &env->sc_activeflows) { - /* - * Find existing active policy by policy Id. - * XXX This should use another tree that uses - * XXX the x_policy_id as lookup key. - */ - if (flow->flow_id == sa_pol->sadb_x_policy_id) { - log_debug("%s: flow %s policy id 0x%x ", - __func__, - flow->flow_dir == IPSP_DIRECTION_IN ? - "in" : "out", flow->flow_id); - ikev2_acquire_sa(env, flow); - break; - } - } -#else -#warning PFKEYv2 SADB_ACQUIRE not implemented - log_debug("%s: SADB_ACQUIRE not yet supported here, ignored", - __func__); -#endif break; case SADB_EXPIRE: if ((sa = pfkey_find_ext(data, len, SADB_EXT_SA)) == NULL) { log_warnx("%s: SA extension wasn't found", __func__); - return; + return (0); } if ((sa_ltime = pfkey_find_ext(data, len, SADB_EXT_LIFETIME_SOFT)) == NULL && @@ -1963,7 +2040,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) SADB_EXT_LIFETIME_HARD)) == NULL) { log_warnx("%s: lifetime extension wasn't found", __func__); - return; + return (0); } spi.spi = ntohl(sa->sadb_sa_spi); spi.spi_size = 4; @@ -1974,11 +2051,15 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) case SADB_SATYPE_ESP: spi.spi_protoid = IKEV2_SAPROTO_ESP; break; + case SADB_X_SATYPE_IPCOMP: + spi.spi_size = 2; + spi.spi_protoid = IKEV2_SAPROTO_IPCOMP; + break; default: - log_warnx("%s: usupported SA type %d spi %s", + log_warnx("%s: unsupported SA type %d spi %s", __func__, hdr->sadb_msg_satype, print_spi(spi.spi, spi.spi_size)); - return; + return (0); } log_debug("%s: SA %s is expired, pending %s", __func__, @@ -1987,9 +2068,10 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) "rekeying" : "deletion"); if (sa_ltime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT) - ikev2_rekey_sa(env, &spi); + ret = ikev2_rekey_sa(env, &spi); else - ikev2_drop_sa(env, &spi); + ret = ikev2_drop_sa(env, &spi); break; } + return (ret); } diff --git a/iked/policy.c b/iked/policy.c index 7cff708..86087ef 100644 --- a/iked/policy.c +++ b/iked/policy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: policy.c,v 1.23 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: policy.c,v 1.37 2015/07/07 19:13:31 markus Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -17,18 +17,10 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include #include #include -#include "openbsd-compat/sys-tree.h" - -#include -#include -#include -#include -#include -#include +#include #include #include @@ -65,6 +57,8 @@ int policy_lookup(struct iked *env, struct iked_message *msg) { struct iked_policy pol; + char *s, idstr[IKED_ID_SIZE]; + if (msg->msg_sa != NULL && msg->msg_sa->sa_policy != NULL) { /* Existing SA with policy */ @@ -76,6 +70,15 @@ policy_lookup(struct iked *env, struct iked_message *msg) pol.pol_af = msg->msg_peer.ss_family; memcpy(&pol.pol_peer.addr, &msg->msg_peer, sizeof(msg->msg_peer)); memcpy(&pol.pol_local.addr, &msg->msg_local, sizeof(msg->msg_local)); + if (msg->msg_id.id_type && + ikev2_print_id(&msg->msg_id, idstr, IKED_ID_SIZE) == 0 && + (s = strchr(idstr, '/')) != NULL) { + pol.pol_peerid.id_type = msg->msg_id.id_type; + pol.pol_peerid.id_length = strlen(s+1); + strlcpy(pol.pol_peerid.id_data, s+1, + sizeof(pol.pol_peerid.id_data)); + log_debug("%s: peerid '%s'", __func__, s+1); + } /* Try to find a matching policy for this message */ if ((msg->msg_policy = policy_test(env, &pol)) != NULL) @@ -132,6 +135,15 @@ policy_test(struct iked *env, struct iked_policy *key) p = TAILQ_NEXT(p, pol_entry); continue; } + /* make sure the peer ID matches */ + if (key->pol_peerid.id_type && + (key->pol_peerid.id_type != p->pol_peerid.id_type || + memcmp(key->pol_peerid.id_data, + p->pol_peerid.id_data, + sizeof(key->pol_peerid.id_data)) != 0)) { + p = TAILQ_NEXT(p, pol_entry); + continue; + } /* Policy matched */ pol = p; @@ -202,6 +214,16 @@ policy_unref(struct iked *env, struct iked_policy *pol) return; if (--(pol->pol_refcnt) <= 0) config_free_policy(env, pol); + else { + struct iked_sa *tmp; + int count = 0; + + TAILQ_FOREACH(tmp, &pol->pol_sapeers, sa_peer_entry) + count++; + if (count != pol->pol_refcnt) + log_warnx("%s: ERROR pol %p pol_refcnt %d != count %d", + __func__, pol, pol->pol_refcnt, count); + } } void @@ -209,19 +231,28 @@ sa_state(struct iked *env, struct iked_sa *sa, int state) { const char *a; const char *b; + int ostate = sa->sa_state; - a = print_map(sa->sa_state, ikev2_state_map); + a = print_map(ostate, ikev2_state_map); b = print_map(state, ikev2_state_map); - if (state > sa->sa_state) { + sa->sa_state = state; + if (ostate != IKEV2_STATE_INIT && + !sa_stateok(sa, state)) { + log_debug("%s: cannot switch: %s -> %s", __func__, a, b); + sa->sa_state = ostate; + } else if (ostate != sa->sa_state) { switch (state) { case IKEV2_STATE_ESTABLISHED: case IKEV2_STATE_CLOSED: log_info("%s: %s -> %s from %s to %s policy '%s'", __func__, a, b, - print_host(&sa->sa_peer.addr, NULL, 0), - print_host(&sa->sa_local.addr, NULL, 0), - sa->sa_policy->pol_name); + print_host((struct sockaddr *)&sa->sa_peer.addr, + NULL, 0), + print_host((struct sockaddr *)&sa->sa_local.addr, + NULL, 0), + sa->sa_policy ? sa->sa_policy->pol_name : + ""); break; default: log_debug("%s: %s -> %s", __func__, a, b); @@ -229,7 +260,6 @@ sa_state(struct iked *env, struct iked_sa *sa, int state) } } - sa->sa_state = state; } void @@ -265,7 +295,7 @@ sa_stateok(struct iked_sa *sa, int state) if (state == IKEV2_STATE_SA_INIT || state == IKEV2_STATE_VALID || - state == IKEV2_STATE_EAP) { + state == IKEV2_STATE_EAP_VALID) { log_debug("%s: %s flags 0x%02x, require 0x%02x %s", __func__, print_map(state, ikev2_state_map), (sa->sa_stateflags & require), require, @@ -282,34 +312,54 @@ sa_new(struct iked *env, u_int64_t ispi, u_int64_t rspi, u_int initiator, struct iked_policy *pol) { struct iked_sa *sa; + struct iked_sa *old; struct iked_id *localid; u_int diff; if ((ispi == 0 && rspi == 0) || (sa = sa_lookup(env, ispi, rspi, initiator)) == NULL) { /* Create new SA */ + if (!initiator && ispi == 0) { + log_debug("%s: cannot create responder IKE SA w/o ispi", + __func__); + return (NULL); + } sa = config_new_sa(env, initiator); + if (sa == NULL) { + log_debug("%s: failed to allocate IKE SA", __func__); + return (NULL); + } + if (!initiator) + sa->sa_hdr.sh_ispi = ispi; + old = RB_INSERT(iked_sas, &env->sc_sas, sa); + if (old && old != sa) { + log_warnx("%s: duplicate IKE SA", __func__); + config_free_sa(env, sa); + return (NULL); + } } - if (sa == NULL) { - log_debug("%s: failed to get sa", __func__); - return (NULL); - } - if (sa->sa_policy == NULL) + /* Update rspi in the initator case */ + if (initiator && sa->sa_hdr.sh_rspi == 0 && rspi) + sa->sa_hdr.sh_rspi = rspi; + + if (sa->sa_policy == NULL) { sa->sa_policy = pol; - else + TAILQ_INSERT_TAIL(&pol->pol_sapeers, sa, sa_peer_entry); + } else pol = sa->sa_policy; - sa->sa_statevalid = IKED_REQ_AUTH|IKED_REQ_SA; + sa->sa_statevalid = IKED_REQ_AUTH|IKED_REQ_AUTHVALID|IKED_REQ_SA; if (pol != NULL && pol->pol_auth.auth_eap) { - sa->sa_statevalid |= IKED_REQ_CERT; + sa->sa_statevalid |= IKED_REQ_CERT|IKED_REQ_EAPVALID; } else if (pol != NULL && pol->pol_auth.auth_method != IKEV2_AUTH_SHARED_KEY_MIC) { - sa->sa_statevalid |= IKED_REQ_VALID|IKED_REQ_CERT; + sa->sa_statevalid |= IKED_REQ_CERTVALID|IKED_REQ_CERT; } if (initiator) { localid = &sa->sa_iid; - diff = IKED_REQ_VALID|IKED_REQ_SA; + diff = IKED_REQ_CERTVALID|IKED_REQ_AUTHVALID|IKED_REQ_SA| + IKED_REQ_EAPVALID; sa->sa_stateinit = sa->sa_statevalid & ~diff; sa->sa_statevalid = sa->sa_statevalid & diff; } else @@ -322,14 +372,6 @@ sa_new(struct iked *env, u_int64_t ispi, u_int64_t rspi, return (NULL); } - if (sa->sa_hdr.sh_ispi == 0) - sa->sa_hdr.sh_ispi = ispi; - if (sa->sa_hdr.sh_rspi == 0) - sa->sa_hdr.sh_rspi = rspi; - - /* Re-insert node into the tree */ - RB_INSERT(iked_sas, &env->sc_sas, sa); - return (sa); } @@ -340,6 +382,12 @@ sa_free(struct iked *env, struct iked_sa *sa) print_spi(sa->sa_hdr.sh_ispi, 8), print_spi(sa->sa_hdr.sh_rspi, 8)); + /* IKE rekeying running? */ + if (sa->sa_next) { + RB_REMOVE(iked_sas, &env->sc_sas, sa->sa_next); + config_free_sa(env, sa->sa_next); + } + RB_REMOVE(iked_sas, &env->sc_sas, sa); config_free_sa(env, sa); } @@ -364,41 +412,33 @@ sa_free_flows(struct iked *env, struct iked_saflows *head) int sa_address(struct iked_sa *sa, struct iked_addr *addr, - struct sockaddr_storage *peer, int initiator) + struct sockaddr_storage *peer) { - struct iked_policy *pol = sa->sa_policy; - - if (pol == NULL) { - log_debug("%s: invalid policy", __func__); - return (-1); - } - bzero(addr, sizeof(*addr)); addr->addr_af = peer->ss_family; - addr->addr_port = htons(socket_getport(peer)); + addr->addr_port = htons(socket_getport((struct sockaddr *)peer)); memcpy(&addr->addr, peer, sizeof(*peer)); if (socket_af((struct sockaddr *)&addr->addr, addr->addr_port) == -1) { log_debug("%s: invalid address", __func__); return (-1); } - - if (addr == &sa->sa_peer) { - /* XXX Re-insert node into the tree */ - RB_REMOVE(iked_sapeers, &pol->pol_sapeers, sa); - memcpy(&sa->sa_polpeer, initiator ? &pol->pol_peer : - &sa->sa_peer, sizeof(sa->sa_polpeer)); - RB_INSERT(iked_sapeers, &pol->pol_sapeers, sa); - } - return (0); } void -childsa_free(struct iked_childsa *sa) +childsa_free(struct iked_childsa *csa) { - ibuf_release(sa->csa_encrkey); - ibuf_release(sa->csa_integrkey); - free(sa); + if (csa->csa_children) { + /* XXX should not happen */ + log_warnx("%s: trying to remove CSA %p children %u", + __func__, csa, csa->csa_children); + return; + } + if (csa->csa_parent) + csa->csa_parent->csa_children--; + ibuf_release(csa->csa_encrkey); + ibuf_release(csa->csa_integrkey); + free(csa); } struct iked_childsa * @@ -430,7 +470,7 @@ sa_lookup(struct iked *env, u_int64_t ispi, u_int64_t rspi, struct iked_sa *sa, key; key.sa_hdr.sh_ispi = ispi; - key.sa_hdr.sh_rspi = rspi; + /* key.sa_hdr.sh_rspi = rspi; */ key.sa_hdr.sh_initiator = initiator; if ((sa = RB_FIND(iked_sas, &env->sc_sas, &key)) != NULL) { @@ -438,6 +478,7 @@ sa_lookup(struct iked *env, u_int64_t ispi, u_int64_t rspi, /* Validate if SPIr matches */ if ((sa->sa_hdr.sh_rspi != 0) && + (rspi != 0) && (sa->sa_hdr.sh_rspi != rspi)) return (NULL); } @@ -448,8 +489,10 @@ sa_lookup(struct iked *env, u_int64_t ispi, u_int64_t rspi, static __inline int sa_cmp(struct iked_sa *a, struct iked_sa *b) { - if (a->sa_hdr.sh_initiator != b->sa_hdr.sh_initiator) - return (-2); + if (a->sa_hdr.sh_initiator > b->sa_hdr.sh_initiator) + return (-1); + if (a->sa_hdr.sh_initiator < b->sa_hdr.sh_initiator) + return (1); if (a->sa_hdr.sh_ispi > b->sa_hdr.sh_ispi) return (-1); @@ -471,20 +514,11 @@ sa_cmp(struct iked_sa *a, struct iked_sa *b) return (0); } -struct iked_sa * -sa_peer_lookup(struct iked_policy *pol, struct sockaddr_storage *peer) -{ - struct iked_sa key; - - memcpy(&key.sa_polpeer.addr, peer, sizeof(*peer)); - return (RB_FIND(iked_sapeers, &pol->pol_sapeers, &key)); -} - static __inline int -sa_peer_cmp(struct iked_sa *a, struct iked_sa *b) +sa_addrpool_cmp(struct iked_sa *a, struct iked_sa *b) { - return (sockaddr_cmp((struct sockaddr *)&a->sa_polpeer.addr, - (struct sockaddr *)&b->sa_polpeer.addr, -1)); + return (sockaddr_cmp((struct sockaddr *)&a->sa_addrpool->addr, + (struct sockaddr *)&b->sa_addrpool->addr, -1)); } struct iked_user * @@ -547,10 +581,8 @@ flow_cmp(struct iked_flow *a, struct iked_flow *b) return (diff); } -#ifndef __clang_analyzer__ RB_GENERATE(iked_sas, iked_sa, sa_entry, sa_cmp); -RB_GENERATE(iked_sapeers, iked_sa, sa_peer_entry, sa_peer_cmp); +RB_GENERATE(iked_addrpool, iked_sa, sa_addrpool_entry, sa_addrpool_cmp); RB_GENERATE(iked_users, iked_user, usr_entry, user_cmp); RB_GENERATE(iked_activesas, iked_childsa, csa_node, childsa_cmp); RB_GENERATE(iked_flows, iked_flow, flow_node, flow_cmp); -#endif diff --git a/iked/proc.c b/iked/proc.c index 331d84b..2e1fdf6 100644 --- a/iked/proc.c +++ b/iked/proc.c @@ -1,7 +1,7 @@ -/* $OpenBSD: proc.c,v 1.9 2013/03/21 04:30:14 deraadt Exp $ */ +/* $OpenBSD: proc.c,v 1.22 2015/01/16 06:39:58 deraadt Exp $ */ /* - * Copyright (c) 2010-2013 Reyk Floeter + * Copyright (c) 2010 - 2014 Reyk Floeter * Copyright (c) 2008 Pierre-Yves Ritschard * * Permission to use, copy, modify, and distribute this software for any @@ -17,11 +17,15 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" -#include "openbsd-compat/sys-tree.h" -#include +#include #include +#include +#include + +#include +#include +#include +#include #include #include @@ -32,33 +36,90 @@ #include #include -#include - #include "iked.h" -void proc_setup(struct privsep *); +void proc_open(struct privsep *, struct privsep_proc *, + struct privsep_proc *, size_t); +void proc_close(struct privsep *); +int proc_ispeer(struct privsep_proc *, u_int, enum privsep_procid); void proc_shutdown(struct privsep_proc *); void proc_sig_handler(int, short, void *); +void proc_range(struct privsep *, enum privsep_procid, int *, int *); + +int +proc_ispeer(struct privsep_proc *procs, u_int nproc, enum privsep_procid type) +{ + u_int i; + + for (i = 0; i < nproc; i++) + if (procs[i].p_id == type) + return (1); + return (0); +} void -proc_init(struct privsep *ps, struct privsep_proc *p, u_int nproc) +proc_init(struct privsep *ps, struct privsep_proc *procs, u_int nproc) { - u_int i; + u_int i, j, src, dst; + struct privsep_pipes *pp; /* - * Called from parent + * Allocate pipes for all process instances (incl. parent) + * + * - ps->ps_pipes: N:M mapping + * N source processes connected to M destination processes: + * [src][instances][dst][instances], for example + * [PROC_RELAY][3][PROC_CA][3] + * + * - ps->ps_pp: per-process 1:M part of ps->ps_pipes + * Each process instance has a destination array of socketpair fds: + * [dst][instances], for example + * [PROC_PARENT][0] + */ + for (src = 0; src < PROC_MAX; src++) { + /* Allocate destination array for each process */ + if ((ps->ps_pipes[src] = calloc(ps->ps_ninstances, + sizeof(struct privsep_pipes))) == NULL) + fatal("proc_init: calloc"); + + for (i = 0; i < ps->ps_ninstances; i++) { + pp = &ps->ps_pipes[src][i]; + + for (dst = 0; dst < PROC_MAX; dst++) { + /* Allocate maximum fd integers */ + if ((pp->pp_pipes[dst] = + calloc(ps->ps_ninstances, + sizeof(int))) == NULL) + fatal("proc_init: calloc"); + + /* Mark fd as unused */ + for (j = 0; j < ps->ps_ninstances; j++) + pp->pp_pipes[dst][j] = -1; + } + } + } + + /* + * Setup and run the parent and its children */ privsep_process = PROC_PARENT; + ps->ps_instances[PROC_PARENT] = 1; ps->ps_title[PROC_PARENT] = "parent"; ps->ps_pid[PROC_PARENT] = getpid(); + ps->ps_pp = &ps->ps_pipes[privsep_process][0]; + + for (i = 0; i < nproc; i++) { + /* Default to 1 process instance */ + if (ps->ps_instances[procs[i].p_id] < 1) + ps->ps_instances[procs[i].p_id] = 1; + ps->ps_title[procs[i].p_id] = procs[i].p_title; + } - proc_setup(ps); + proc_open(ps, NULL, procs, nproc); /* Engage! */ - for (i = 0; i < nproc; i++, p++) { - ps->ps_title[p->p_id] = p->p_title; - ps->ps_pid[p->p_id] = (*p->p_init)(ps, p); - } + for (i = 0; i < nproc; i++) + ps->ps_pid[procs[i].p_id] = (*procs[i].p_init)(ps, &procs[i]); } void @@ -73,83 +134,157 @@ proc_kill(struct privsep *ps) for (i = 0; i < PROC_MAX; i++) { if (ps->ps_pid[i] == 0) continue; - kill(ps->ps_pid[i], SIGTERM); + killpg(ps->ps_pid[i], SIGTERM); } do { pid = waitpid(WAIT_ANY, NULL, 0); } while (pid != -1 || (pid == -1 && errno == EINTR)); + + proc_close(ps); } void -proc_setup(struct privsep *ps) +proc_open(struct privsep *ps, struct privsep_proc *p, + struct privsep_proc *procs, size_t nproc) { - int i, j, sockpair[2]; - - for (i = 0; i < PROC_MAX; i++) - for (j = 0; j < PROC_MAX; j++) { - if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, - sockpair) == -1) - fatal("sockpair"); - ps->ps_pipes[i][j] = sockpair[0]; - ps->ps_pipes[j][i] = sockpair[1]; - socket_set_blockmode(ps->ps_pipes[i][j], - BM_NONBLOCK); - socket_set_blockmode(ps->ps_pipes[j][i], - BM_NONBLOCK); + struct privsep_pipes *pa, *pb; + int fds[2]; + u_int i, j, src, proc; + + if (p == NULL) + src = privsep_process; /* parent */ + else + src = p->p_id; + + /* + * Open socket pairs for our peers + */ + for (proc = 0; proc < nproc; proc++) { + procs[proc].p_ps = ps; + procs[proc].p_env = ps->ps_env; + + for (i = 0; i < ps->ps_instances[src]; i++) { + for (j = 0; j < ps->ps_instances[procs[proc].p_id]; + j++) { + pa = &ps->ps_pipes[src][i]; + pb = &ps->ps_pipes[procs[proc].p_id][j]; + + /* Check if fds are already set by peer */ + if (pa->pp_pipes[procs[proc].p_id][j] != -1) + continue; + + if (socketpair(AF_UNIX, SOCK_STREAM, + PF_UNSPEC, fds) == -1) + fatal("socketpair"); + + socket_set_blockmode(fds[0], BM_NONBLOCK); + socket_set_blockmode(fds[1], BM_NONBLOCK); + + pa->pp_pipes[procs[proc].p_id][j] = fds[0]; + pb->pp_pipes[src][i] = fds[1]; + } } + } } void -proc_config(struct privsep *ps, struct privsep_proc *p, u_int nproc) +proc_listen(struct privsep *ps, struct privsep_proc *procs, size_t nproc) { - u_int src, dst, i, j, k, found; - - src = privsep_process; + u_int i, dst, src, n, m; + struct privsep_pipes *pp; /* - * close unused pipes + * Close unused pipes */ - for (i = 0; i < PROC_MAX; i++) { - if (i != privsep_process) { - for (j = 0; j < PROC_MAX; j++) { - close(ps->ps_pipes[i][j]); - ps->ps_pipes[i][j] = -1; - } - } else { - for (j = found = 0; j < PROC_MAX; j++, found = 0) { - for (k = 0; k < nproc; k++) { - if (p[k].p_id == j) - found++; - } - if (!found) { - close(ps->ps_pipes[i][j]); - ps->ps_pipes[i][j] = -1; + for (src = 0; src < PROC_MAX; src++) { + for (n = 0; n < ps->ps_instances[src]; n++) { + /* Ingore current process */ + if (src == (u_int)privsep_process && + n == ps->ps_instance) + continue; + + pp = &ps->ps_pipes[src][n]; + + for (dst = 0; dst < PROC_MAX; dst++) { + if (src == dst) + continue; + for (m = 0; m < ps->ps_instances[dst]; m++) { + if (pp->pp_pipes[dst][m] == -1) + continue; + + /* Close and invalidate fd */ + close(pp->pp_pipes[dst][m]); + pp->pp_pipes[dst][m] = -1; } } } } + src = privsep_process; + ps->ps_pp = pp = &ps->ps_pipes[src][ps->ps_instance]; + /* - * listen on appropriate pipes + * Listen on appropriate pipes */ - for (i = 0; i < nproc; i++, p++) { - dst = p->p_id; - p->p_ps = ps; - p->p_env = ps->ps_env; - - imsg_init(&ps->ps_ievs[dst].ibuf, - ps->ps_pipes[src][dst]); - ps->ps_ievs[dst].handler = proc_dispatch; - ps->ps_ievs[dst].events = EV_READ; - ps->ps_ievs[dst].data = p; - ps->ps_ievs[dst].name = p->p_title; - event_set(&ps->ps_ievs[dst].ev, - ps->ps_ievs[dst].ibuf.fd, - ps->ps_ievs[dst].events, - ps->ps_ievs[dst].handler, - ps->ps_ievs[dst].data); - event_add(&ps->ps_ievs[dst].ev, NULL); + for (i = 0; i < nproc; i++) { + dst = procs[i].p_id; + + if (src == dst) + fatal("proc_listen: cannot peer with oneself"); + + if ((ps->ps_ievs[dst] = calloc(ps->ps_instances[dst], + sizeof(struct imsgev))) == NULL) + fatal("proc_open"); + + for (n = 0; n < ps->ps_instances[dst]; n++) { + if (pp->pp_pipes[dst][n] == -1) + continue; + + imsg_init(&(ps->ps_ievs[dst][n].ibuf), + pp->pp_pipes[dst][n]); + ps->ps_ievs[dst][n].handler = proc_dispatch; + ps->ps_ievs[dst][n].events = EV_READ; + ps->ps_ievs[dst][n].proc = &procs[i]; + ps->ps_ievs[dst][n].data = &ps->ps_ievs[dst][n]; + procs[i].p_instance = n; + + event_set(&(ps->ps_ievs[dst][n].ev), + ps->ps_ievs[dst][n].ibuf.fd, + ps->ps_ievs[dst][n].events, + ps->ps_ievs[dst][n].handler, + ps->ps_ievs[dst][n].data); + event_add(&(ps->ps_ievs[dst][n].ev), NULL); + } + } +} + +void +proc_close(struct privsep *ps) +{ + u_int dst, n; + struct privsep_pipes *pp; + + if (ps == NULL) + return; + + pp = ps->ps_pp; + + for (dst = 0; dst < PROC_MAX; dst++) { + if (ps->ps_ievs[dst] == NULL) + continue; + + for (n = 0; n < ps->ps_instances[dst]; n++) { + if (pp->pp_pipes[dst][n] == -1) + continue; + + /* Cancel the fd, close and invalidate the fd */ + event_del(&(ps->ps_ievs[dst][n].ev)); + imsg_clear(&(ps->ps_ievs[dst][n].ibuf)); + close(pp->pp_pipes[dst][n]); + pp->pp_pipes[dst][n] = -1; + } + free(ps->ps_ievs[dst]); } } @@ -161,7 +296,13 @@ proc_shutdown(struct privsep_proc *p) if (p->p_id == PROC_CONTROL && ps) control_cleanup(&ps->ps_csock); - log_info("%s exiting", p->p_title); + if (p->p_shutdown != NULL) + (*p->p_shutdown)(); + + proc_close(ps); + + log_info("%s exiting, pid %d", p->p_title, getpid()); + _exit(0); } @@ -178,6 +319,7 @@ proc_sig_handler(int sig, short event, void *arg) case SIGCHLD: case SIGHUP: case SIGPIPE: + case SIGUSR1: /* ignore */ break; default: @@ -189,17 +331,26 @@ proc_sig_handler(int sig, short event, void *arg) pid_t proc_run(struct privsep *ps, struct privsep_proc *p, struct privsep_proc *procs, u_int nproc, - void (*init)(struct privsep *, void *), void *arg) + void (*init)(struct privsep *, struct privsep_proc *, void *), void *arg) { - pid_t pid; - struct passwd *pw; - const char *root; - u_int32_t seed[256]; + pid_t pid; + struct passwd *pw; + const char *root; + struct control_sock *rcs; + u_int n; + + if (ps->ps_noaction) + return (0); + proc_open(ps, p, procs, nproc); + + /* Fork child handlers */ switch (pid = fork()) { case -1: fatal("proc_run: cannot fork"); case 0: + /* Set the process group of the current process */ + setpgid(0, 0); break; default: return (pid); @@ -207,9 +358,12 @@ proc_run(struct privsep *ps, struct privsep_proc *p, pw = ps->ps_pw; - if (p->p_id == PROC_CONTROL) { + if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { if (control_init(ps, &ps->ps_csock) == -1) fatalx(p->p_title); + TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry) + if (control_init(ps, rcs) == -1) + fatalx(p->p_title); } /* Change root directory */ @@ -218,30 +372,31 @@ proc_run(struct privsep *ps, struct privsep_proc *p, else root = pw->pw_dir; -#ifndef DEBUG if (chroot(root) == -1) fatal("proc_run: chroot"); if (chdir("/") == -1) fatal("proc_run: chdir(\"/\")"); -#else -#warning disabling privilege revocation and chroot in DEBUG MODE - if (p->p_chroot != NULL) { - if (chroot(root) == -1) - fatal("proc_run: chroot"); - if (chdir("/") == -1) - fatal("proc_run: chdir(\"/\")"); - } -#endif privsep_process = p->p_id; setproctitle("%s", p->p_title); -#ifndef DEBUG if (setgroups(1, &pw->pw_gid) || setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) fatal("proc_run: cannot drop privileges"); + + /* Fork child handlers */ + for (n = 1; n < ps->ps_instances[p->p_id]; n++) { + if (fork() == 0) { + ps->ps_instance = p->p_instance = n; + break; + } + } + +#ifdef DEBUG + log_debug("%s: %s %d/%d, pid %d", __func__, p->p_title, + ps->ps_instance + 1, ps->ps_instances[p->p_id], getpid()); #endif event_init(); @@ -251,26 +406,28 @@ proc_run(struct privsep *ps, struct privsep_proc *p, signal_set(&ps->ps_evsigchld, SIGCHLD, proc_sig_handler, p); signal_set(&ps->ps_evsighup, SIGHUP, proc_sig_handler, p); signal_set(&ps->ps_evsigpipe, SIGPIPE, proc_sig_handler, p); + signal_set(&ps->ps_evsigusr1, SIGUSR1, proc_sig_handler, p); signal_add(&ps->ps_evsigint, NULL); signal_add(&ps->ps_evsigterm, NULL); signal_add(&ps->ps_evsigchld, NULL); signal_add(&ps->ps_evsighup, NULL); signal_add(&ps->ps_evsigpipe, NULL); + signal_add(&ps->ps_evsigusr1, NULL); - proc_config(ps, procs, nproc); - - arc4random_buf(seed, sizeof(seed)); - RAND_seed(seed, sizeof(seed)); + proc_listen(ps, procs, nproc); - if (p->p_id == PROC_CONTROL) { + if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { TAILQ_INIT(&ctl_conns); if (control_listen(&ps->ps_csock) == -1) fatalx(p->p_title); + TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry) + if (control_listen(rcs) == -1) + fatalx(p->p_title); } if (init != NULL) - init(ps, arg); + init(ps, p, arg); event_dispatch(); @@ -282,9 +439,9 @@ proc_run(struct privsep *ps, struct privsep_proc *p, void proc_dispatch(int fd, short event, void *arg) { - struct privsep_proc *p = (struct privsep_proc *)arg; + struct imsgev *iev = arg; + struct privsep_proc *p = iev->proc; struct privsep *ps = p->p_ps; - struct imsgev *iev; struct imsgbuf *ibuf; struct imsg imsg; ssize_t n; @@ -292,7 +449,6 @@ proc_dispatch(int fd, short event, void *arg) const char *title; title = ps->ps_title[privsep_process]; - iev = &ps->ps_ievs[p->p_id]; ibuf = &iev->ibuf; if (event & EV_READ) { @@ -307,7 +463,7 @@ proc_dispatch(int fd, short event, void *arg) } if (event & EV_WRITE) { - if (msgbuf_write(&ibuf->w) == -1) + if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) fatal(title); } @@ -317,6 +473,12 @@ proc_dispatch(int fd, short event, void *arg) if (n == 0) break; +#if DEBUG > 1 + log_debug("%s: %s %d got imsg %d from %s %d", + __func__, title, ps->ps_instance + 1, + imsg.hdr.type, p->p_title, p->p_instance); +#endif + /* * Check the message with the program callback */ @@ -332,13 +494,13 @@ proc_dispatch(int fd, short event, void *arg) switch (imsg.hdr.type) { case IMSG_CTL_VERBOSE: IMSG_SIZE_CHECK(&imsg, &verbose); - memcpy(&verbose, imsg.data, sizeof(verbose)); log_verbose(verbose); break; default: - log_warnx("%s: %s got imsg %d", __func__, p->p_title, - imsg.hdr.type); + log_warnx("%s: %s %d got invalid imsg %d from %s %d", + __func__, title, ps->ps_instance + 1, + imsg.hdr.type, p->p_title, p->p_instance); fatalx(title); } imsg_free(&imsg); @@ -346,6 +508,10 @@ proc_dispatch(int fd, short event, void *arg) imsg_event_add(iev); } +/* + * imsg helper functions + */ + void imsg_event_add(struct imsgev *iev) { @@ -389,32 +555,72 @@ imsg_composev_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, return (ret); } +void +proc_range(struct privsep *ps, enum privsep_procid id, int *n, int *m) +{ + if (*n == -1) { + /* Use a range of all target instances */ + *n = 0; + *m = ps->ps_instances[id]; + } else { + /* Use only a single slot of the specified peer process */ + *m = *n + 1; + } +} + int -proc_compose_imsg(struct iked *env, enum privsep_procid id, +proc_compose_imsg(struct privsep *ps, enum privsep_procid id, int n, u_int16_t type, int fd, void *data, u_int16_t datalen) { - return (imsg_compose_event(&env->sc_ps.ps_ievs[id], - type, -1, 0, fd, data, datalen)); + int m; + + proc_range(ps, id, &n, &m); + for (; n < m; n++) { + if (imsg_compose_event(&ps->ps_ievs[id][n], + type, -1, 0, fd, data, datalen) == -1) + return (-1); + } + + return (0); } int -proc_composev_imsg(struct iked *env, enum privsep_procid id, +proc_composev_imsg(struct privsep *ps, enum privsep_procid id, int n, u_int16_t type, int fd, const struct iovec *iov, int iovcnt) { - return (imsg_composev_event(&env->sc_ps.ps_ievs[id], - type, -1, 0, fd, iov, iovcnt)); + int m; + + proc_range(ps, id, &n, &m); + for (; n < m; n++) + if (imsg_composev_event(&ps->ps_ievs[id][n], + type, -1, 0, fd, iov, iovcnt) == -1) + return (-1); + + return (0); } int -proc_forward_imsg(struct iked *env, struct imsg *imsg, - enum privsep_procid id) +proc_forward_imsg(struct privsep *ps, struct imsg *imsg, + enum privsep_procid id, int n) { - return (proc_compose_imsg(env, id, imsg->hdr.type, + return (proc_compose_imsg(ps, id, n, imsg->hdr.type, imsg->fd, imsg->data, IMSG_DATA_SIZE(imsg))); } -void -proc_flush_imsg(struct iked *env, enum privsep_procid id) +struct imsgbuf * +proc_ibuf(struct privsep *ps, enum privsep_procid id, int n) { - imsg_flush(&env->sc_ps.ps_ievs[id].ibuf); + int m; + + proc_range(ps, id, &n, &m); + return (&ps->ps_ievs[id][n].ibuf); +} + +struct imsgev * +proc_iev(struct privsep *ps, enum privsep_procid id, int n) +{ + int m; + + proc_range(ps, id, &n, &m); + return (&ps->ps_ievs[id][n]); } diff --git a/iked/timer.c b/iked/timer.c index 150673b..01341cb 100644 --- a/iked/timer.c +++ b/iked/timer.c @@ -1,4 +1,4 @@ -/* $OpenBSD: timer.c,v 1.10 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: timer.c,v 1.12 2015/01/16 06:39:58 deraadt Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,8 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include #include #include @@ -35,7 +34,7 @@ void timer_callback(int, short, void *); void -timer_initialize(struct iked *env, struct iked_timer *tmr, +timer_set(struct iked *env, struct iked_timer *tmr, void (*cb)(struct iked *, void *), void *arg) { tmr->tmr_env = env; @@ -44,17 +43,8 @@ timer_initialize(struct iked *env, struct iked_timer *tmr, evtimer_set(&tmr->tmr_ev, timer_callback, tmr); } -int -timer_initialized(struct iked *env, struct iked_timer *tmr) -{ - if (tmr && tmr->tmr_env == env && tmr->tmr_cb && - evtimer_initialized(&tmr->tmr_ev)) - return (1); - return (0); -} - void -timer_register(struct iked *env, struct iked_timer *tmr, int timeout) +timer_add(struct iked *env, struct iked_timer *tmr, int timeout) { struct timeval tv = { timeout }; @@ -66,9 +56,11 @@ timer_register(struct iked *env, struct iked_timer *tmr, int timeout) } void -timer_deregister(struct iked *env, struct iked_timer *tmr) +timer_del(struct iked *env, struct iked_timer *tmr) { - evtimer_del(&tmr->tmr_ev); + if (tmr->tmr_env == env && tmr->tmr_cb && + evtimer_initialized(&tmr->tmr_ev)) + evtimer_del(&tmr->tmr_ev); } void diff --git a/iked/types.h b/iked/types.h index d0de6e5..3c30efb 100644 --- a/iked/types.h +++ b/iked/types.h @@ -1,4 +1,4 @@ -/* $OpenBSD: types.h,v 1.17 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: types.h,v 1.19 2015/06/11 18:49:09 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _IKED_TYPES_H -#define _IKED_TYPES_H +#ifndef IKED_TYPES_H +#define IKED_TYPES_H #ifndef IKED_USER #define IKED_USER "_iked" @@ -38,6 +38,9 @@ #define IKED_PRIVKEY IKED_CA "private/local.key" #define IKED_PUBKEY "local.pub" +#define IKED_OCSP_RESPCERT "ocsp/responder.crt" +#define IKED_OCSP_ISSUER "ocsp/issuer.crt" + #define IKED_OPT_VERBOSE 0x00000001 #define IKED_OPT_NOACTION 0x00000002 #define IKED_OPT_NONATT 0x00000004 @@ -101,6 +104,8 @@ enum imsg_type { IMSG_CERT, IMSG_CERTVALID, IMSG_CERTINVALID, + IMSG_OCSP_FD, + IMSG_OCSP_URL, IMSG_AUTH }; @@ -133,4 +138,4 @@ enum flushmode { #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif -#endif /* _IKED_TYPES_H */ +#endif /* IKED_TYPES_H */ diff --git a/iked/util.c b/iked/util.c index 5b0f013..b7044c0 100644 --- a/iked/util.c +++ b/iked/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.18 2013/01/08 10:38:19 reyk Exp $ */ +/* $OpenBSD: util.c,v 1.26 2015/01/16 06:39:58 deraadt Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -17,23 +17,17 @@ */ #include -#include "openbsd-compat/sys-queue.h" +#include #include #include -#include -#include -#include -#include -#include -#include #include - #include #include #include #include #include +#include #include #include #include @@ -65,17 +59,13 @@ socket_af(struct sockaddr *sa, in_port_t port) switch (sa->sa_family) { case AF_INET: ((struct sockaddr_in *)sa)->sin_port = port; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN ((struct sockaddr_in *)sa)->sin_len = sizeof(struct sockaddr_in); -#endif break; case AF_INET6: ((struct sockaddr_in6 *)sa)->sin6_port = port; -#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN ((struct sockaddr_in6 *)sa)->sin6_len = sizeof(struct sockaddr_in6); -#endif break; default: errno = EPFNOSUPPORT; @@ -86,13 +76,13 @@ socket_af(struct sockaddr *sa, in_port_t port) } in_port_t -socket_getport(struct sockaddr_storage *ss) +socket_getport(struct sockaddr *sa) { - switch (ss->ss_family) { + switch (sa->sa_family) { case AF_INET: - return (ntohs(((struct sockaddr_in *)ss)->sin_port)); + return (ntohs(((struct sockaddr_in *)sa)->sin_port)); case AF_INET6: - return (ntohs(((struct sockaddr_in6 *)ss)->sin6_port)); + return (ntohs(((struct sockaddr_in6 *)sa)->sin6_port)); default: return (0); } @@ -101,6 +91,22 @@ socket_getport(struct sockaddr_storage *ss) return (0); } +int +socket_setport(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; + default: + return (-1); + } + return (0); +} + int socket_getaddr(int s, struct sockaddr_storage *ss) { @@ -112,7 +118,6 @@ socket_getaddr(int s, struct sockaddr_storage *ss) int socket_bypass(int s, struct sockaddr *sa) { -#if defined(__OpenBSD__) int v, *a; int a4[] = { IPPROTO_IP, @@ -164,47 +169,6 @@ socket_bypass(int s, struct sockaddr *sa) return (-1); } #endif -#else /* __OpenBSD__ */ - int *a; - int a4[] = { - IPPROTO_IP, - IP_IPSEC_POLICY - }; - int a6[] = { - IPPROTO_IPV6, - IPV6_IPSEC_POLICY, - - }; - struct sadb_x_policy pol = { - SADB_UPDATE, - SADB_EXT_SENSITIVITY, - IPSEC_POLICY_BYPASS, - 0, 0, 0, 0 - }; - - switch (sa->sa_family) { - case AF_INET: - a = a4; - break; - case AF_INET6: - a = a6; - break; - default: - log_warn("%s: invalid address family", __func__); - return (-1); - } - - pol.sadb_x_policy_dir = IPSEC_DIR_INBOUND; - if (setsockopt(s, a[0], a[1], &pol, sizeof(pol)) == -1) { - log_warn("%s: IPSEC_DIR_INBOUND", __func__); - return (-1); - } - pol.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND; - if (setsockopt(s, a[0], a[1], &pol, sizeof(pol)) == -1) { - log_warn("%s: IPSEC_DIR_OUTBOUND", __func__); - return (-1); - } -#endif /* !__OpenBSD__ */ return (0); } @@ -231,46 +195,26 @@ udp_bind(struct sockaddr *sa, in_port_t port) goto bad; } -#ifdef SO_REUSEPORT val = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(int)) == -1) { log_warn("%s: failed to set reuseport", __func__); goto bad; } -#endif -#ifdef SO_REUSEADDR val = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int)) == -1) { log_warn("%s: failed to set reuseaddr", __func__); goto bad; } -#endif if (sa->sa_family == AF_INET) { val = 1; - if (setsockopt(s, IPPROTO_IP, -#if defined(IP_RECVDSTADDR) - IP_RECVDSTADDR, -#elif defined(IP_PKTINFO) - IP_PKTINFO, -#else -#error IPv4 packet info not supported -#endif + if (setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &val, sizeof(int)) == -1) { log_warn("%s: failed to set IPv4 packet info", __func__); goto bad; } } else { -#ifdef IPV6_V6ONLY - val = 1; - if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, - &val, sizeof(int)) == -1) { - log_warn("%s: failed to set IPv6-only mode", - __func__); - goto bad; - } -#endif val = 1; if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(int)) == -1) { @@ -280,7 +224,7 @@ udp_bind(struct sockaddr *sa, in_port_t port) } } - if (bind(s, sa, SA_LEN(sa)) == -1) { + if (bind(s, sa, sa->sa_len) == -1) { log_warn("%s: failed to bind UDP socket", __func__); goto bad; } @@ -369,9 +313,6 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, struct cmsghdr hdr; char buf[CMSG_SPACE(sizeof(struct sockaddr_storage))]; } cmsgbuf; -#if !defined(IP_RECVDSTADDR) && defined(IP_PKTINFO) - struct in_pktinfo *pkt; -#endif bzero(&msg, sizeof(msg)); bzero(&cmsgbuf.buf, sizeof(cmsgbuf.buf)); @@ -388,7 +329,7 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, if ((ret = recvmsg(s, &msg, 0)) == -1) return (-1); - *fromlen = SA_LEN(from); + *fromlen = from->sa_len; *tolen = 0; if (getsockname(s, to, tolen) != 0) @@ -398,7 +339,6 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, cmsg = CMSG_NXTHDR(&msg, cmsg)) { switch (from->sa_family) { case AF_INET: -#if defined(IP_RECVDSTADDR) if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) { in = (struct sockaddr_in *)to; @@ -407,32 +347,13 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, memcpy(&in->sin_addr, CMSG_DATA(cmsg), sizeof(struct in_addr)); } -#elif defined(IP_PKTINFO) - if (cmsg->cmsg_level == IPPROTO_IP && - cmsg->cmsg_type == IP_PKTINFO) { - in = (struct sockaddr_in *)to; - in->sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - in->sin_len = *tolen = sizeof(*in); -#else - *tolen = sizeof(*in); -#endif - pkt = (struct in_pktinfo *)CMSG_DATA(cmsg); - memcpy(&in->sin_addr, &pkt->ipi_addr, - sizeof(struct in_addr)); - } -#endif break; case AF_INET6: if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) { in6 = (struct sockaddr_in6 *)to; in6->sin6_family = AF_INET6; -#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN in6->sin6_len = *tolen = sizeof(*in6); -#else - *tolen = sizeof(*in6); -#endif pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg); memcpy(&in6->sin6_addr, &pkt6->ipi6_addr, sizeof(struct in6_addr)); @@ -457,6 +378,9 @@ print_spi(u_int64_t spi, int size) ptr = buf[i]; switch (size) { + case 2: + snprintf(ptr, 32, "0x%04x", (u_int16_t)spi); + break; case 4: snprintf(ptr, 32, "0x%08x", (u_int32_t)spi); break; @@ -503,7 +427,7 @@ void lc_string(char *str) { for (; *str != '\0'; str++) - *str = tolower(*str); + *str = tolower((unsigned char)*str); } void @@ -512,7 +436,7 @@ print_hex(u_int8_t *buf, off_t offset, size_t length) u_int i; extern int verbose; - if (verbose < 2 || !length) + if (verbose < 3 || !length) return; for (i = 0; i < length; i++) { @@ -543,12 +467,12 @@ print_hexval(u_int8_t *buf, off_t offset, size_t length) } const char * -print_bits(u_short v, char *bits) +print_bits(u_short v, u_char *bits) { static char buf[IKED_CYCLE_BUFFERS][BUFSIZ]; static int idx = 0; u_int i, any = 0, j = 0; - char c; + u_char c; if (!bits) return (""); @@ -568,7 +492,7 @@ print_bits(u_short v, char *bits) } any = 1; for (; (c = *bits) > 32; bits++) { - buf[idx][j++] = tolower(c); + buf[idx][j++] = tolower((unsigned char)c); if (j >= sizeof(buf[idx])) return (buf[idx]); } @@ -603,7 +527,7 @@ mask2prefixlen6(struct sockaddr *sa) * the possibly truncated sin6_addr struct. */ ap = (u_int8_t *)&sa_in6->sin6_addr; - ep = (u_int8_t *)sa_in6 + SA_LEN(sa); + ep = (u_int8_t *)sa_in6 + sa_in6->sin6_len; for (; ap < ep; ap++) { /* this "beauty" is adopted from sbin/route/show.c ... */ switch (*ap) { @@ -675,7 +599,7 @@ prefixlen2mask6(u_int8_t prefixlen, u_int32_t *mask) } const char * -print_host(struct sockaddr_storage *ss, char *buf, size_t len) +print_host(struct sockaddr *sa, char *buf, size_t len) { static char sbuf[IKED_CYCLE_BUFFERS][NI_MAXHOST + 7]; static int idx = 0; @@ -689,18 +613,18 @@ print_host(struct sockaddr_storage *ss, char *buf, size_t len) idx = 0; } - if (ss->ss_family == AF_UNSPEC) { + if (sa->sa_family == AF_UNSPEC) { strlcpy(buf, "any", len); return (buf); } - if (getnameinfo((struct sockaddr *)ss, SS_LEN(ss), + if (getnameinfo(sa, sa->sa_len, buf, len, NULL, 0, NI_NUMERICHOST) != 0) { buf[0] = '\0'; return (NULL); } - if ((port = socket_getport(ss)) != 0) { + if ((port = socket_getport(sa)) != 0) { snprintf(pbuf, sizeof(pbuf), ":%d", port); (void)strlcat(buf, pbuf, len); } @@ -715,7 +639,7 @@ get_string(u_int8_t *ptr, size_t len) char *str; for (i = 0; i < len; i++) - if (!isprint((char)ptr[i])) + if (!isprint(ptr[i])) break; if ((str = calloc(1, i + 1)) == NULL) From 4fb6f9a4d3bf4aa68d0d1f9b703ebaab3619999e Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Tue, 7 Jun 2016 09:02:20 -0700 Subject: [PATCH 06/39] Sync up with Bracket Computing's internal version. This needs build testing and cleanups. --- .gitignore | 34 - ikectl/.cvsignore | 5 - ikectl/CVS/Entries | 8 - ikectl/CVS/Repository | 1 - ikectl/CVS/Root | 1 - ikectl/ikeca.c | 6 +- iked/.cvsignore | 7 - iked/CVS/Entries | 31 - iked/CVS/Repository | 1 - iked/CVS/Root | 1 - iked/Makefile.am | 3 +- iked/ca.c | 4 +- iked/config.c | 1 + iked/dh.c | 9 + iked/genmap.sh | 0 iked/iked.c | 1 - iked/iked.h | 8 +- iked/ikev2.c | 30 +- iked/log.c | 21 +- iked/ocsp.c | 512 ++++++++ iked/parse.y | 15 +- iked/pfkey.c | 2055 ++++++++++++++++--------------- iked/policy.c | 68 +- iked/smult_curve25519_ref.c | 265 ++++ iked/timer.c | 5 + iked/util.c | 135 +- openbsd-compat/Makefile.am | 9 +- openbsd-compat/bsd-arc4random.c | 233 ---- openbsd-compat/bsd-closefrom.c | 89 -- openbsd-compat/chacha_private.h | 222 ---- openbsd-compat/daemon.c | 82 -- openbsd-compat/defines.h | 15 - openbsd-compat/entropy.c | 203 --- openbsd-compat/explicit-bzero.c | 19 + openbsd-compat/fgetln.c | 63 - openbsd-compat/getopt.c | 123 -- openbsd-compat/openbsd-compat.h | 47 +- openbsd-compat/reallocarray.c | 38 + openbsd-compat/setproctitle.c | 163 --- openbsd-compat/strlcat.c | 62 - openbsd-compat/strlcpy.c | 58 - openbsd-compat/vis.c | 225 ---- openbsd-compat/vis.h | 98 -- 43 files changed, 2115 insertions(+), 2861 deletions(-) delete mode 100644 .gitignore delete mode 100644 ikectl/.cvsignore delete mode 100644 ikectl/CVS/Entries delete mode 100644 ikectl/CVS/Repository delete mode 100644 ikectl/CVS/Root delete mode 100644 iked/.cvsignore delete mode 100644 iked/CVS/Entries delete mode 100644 iked/CVS/Repository delete mode 100644 iked/CVS/Root mode change 100644 => 100755 iked/genmap.sh create mode 100644 iked/ocsp.c create mode 100644 iked/smult_curve25519_ref.c delete mode 100644 openbsd-compat/bsd-arc4random.c delete mode 100644 openbsd-compat/bsd-closefrom.c delete mode 100644 openbsd-compat/chacha_private.h delete mode 100644 openbsd-compat/daemon.c delete mode 100644 openbsd-compat/entropy.c create mode 100644 openbsd-compat/explicit-bzero.c delete mode 100644 openbsd-compat/fgetln.c delete mode 100644 openbsd-compat/getopt.c create mode 100644 openbsd-compat/reallocarray.c delete mode 100644 openbsd-compat/setproctitle.c delete mode 100644 openbsd-compat/strlcat.c delete mode 100644 openbsd-compat/strlcpy.c delete mode 100644 openbsd-compat/vis.c delete mode 100644 openbsd-compat/vis.h diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 999d144..0000000 --- a/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -*.o -*.a -*.d -*.in -*.out -*.log -*~ -*.cat? -.#* -.deps -.DS_Store -m4 -aclocal.m4 -Makefile -autom4te.cache -compile -config.guess -config.h -config.status -config.sub -configure -depcomp -install-sh -libtool -ltmain.sh -missing -parse.c -stamp-h1 -ylwrap -iked -ikectl -*_map.c -clang_* -*-scan-build diff --git a/ikectl/.cvsignore b/ikectl/.cvsignore deleted file mode 100644 index 536efe1..0000000 --- a/ikectl/.cvsignore +++ /dev/null @@ -1,5 +0,0 @@ -.cvsignore -.deps -Makefile -Makefile.am -Makefile.in diff --git a/ikectl/CVS/Entries b/ikectl/CVS/Entries deleted file mode 100644 index 76336d8..0000000 --- a/ikectl/CVS/Entries +++ /dev/null @@ -1,8 +0,0 @@ -/Makefile/1.2/Result of merge+Fri Jan 11 08:23:23 2013// -/ikeca.c/1.25/Result of merge// -/ikectl.c/1.16/Result of merge// -/parser.c/1.12/Result of merge// -/ikeca.cnf/1.5/Sat Dec 15 14:53:03 2012// -/ikectl.8/1.20/Mon Jan 14 14:11:49 2013// -/parser.h/1.12/Mon Jan 14 14:11:49 2013// -D diff --git a/ikectl/CVS/Repository b/ikectl/CVS/Repository deleted file mode 100644 index 2a96acb..0000000 --- a/ikectl/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -src/usr.sbin/ikectl diff --git a/ikectl/CVS/Root b/ikectl/CVS/Root deleted file mode 100644 index 13631a1..0000000 --- a/ikectl/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -anoncvs@anoncvs.openbsd.org:/cvs diff --git a/ikectl/ikeca.c b/ikectl/ikeca.c index 7e25f7f..d8f7e1d 100644 --- a/ikectl/ikeca.c +++ b/ikectl/ikeca.c @@ -189,7 +189,7 @@ int ca_sign(struct ca *ca, char *keyname, int type, char *envargs) { char cmd[PATH_MAX * 2]; - char hostname[HOST_NAME_MAX+1]; + char hostname[MAXHOSTNAMELEN]; char name[128]; strlcpy(name, keyname, sizeof(name)); @@ -473,9 +473,7 @@ fcopy(char *src, char *dst, mode_t mode) err(1, "open %s", src); if ((ofd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) { - int saved_errno = errno; - close(ifd); - errc(1, saved_errno, "open %s", dst); + err(1, "open %s", dst); } while ((r = read(ifd, buf, sizeof(buf))) > 0) { diff --git a/iked/.cvsignore b/iked/.cvsignore deleted file mode 100644 index d822aec..0000000 --- a/iked/.cvsignore +++ /dev/null @@ -1,7 +0,0 @@ -.cvsignore -.deps -Makefile -Makefile.am -Makefile.in -iked.conf -parse.c diff --git a/iked/CVS/Entries b/iked/CVS/Entries deleted file mode 100644 index ac67746..0000000 --- a/iked/CVS/Entries +++ /dev/null @@ -1,31 +0,0 @@ -/Makefile/1.8/Result of merge+Fri Jan 11 08:22:53 2013// -/chap_ms.c/1.6/Result of merge// -/crypto.c/1.9/Result of merge// -/iked.8/1.13/Result of merge// -/iked.h/1.56/Result of merge// -/log.c/1.3/Result of merge// -/policy.c/1.23/Result of merge+Fri Jan 11 08:23:08 2013// -/timer.c/1.10/Result of merge// -/util.c/1.18/Result of merge// -/ca.c/1.22/Result of merge+Tue Apr 2 09:13:18 2013// -/chap_ms.h/1.3/Mon Jan 14 14:11:49 2013// -/config.c/1.20/Result of merge+Tue Apr 2 09:13:19 2013// -/control.c/1.12/Result of merge// -/dh.c/1.10/Mon Jan 14 14:11:49 2013// -/dh.h/1.5/Mon Jan 14 14:11:49 2013// -/eap.c/1.9/Result of merge+Tue Apr 2 09:13:20 2013// -/eap.h/1.3/Mon Jan 14 14:11:49 2013// -/genmap.sh/1.6/Mon Jan 14 14:11:49 2013// -/iked.c/1.17/Result of merge+Tue Apr 2 09:13:21 2013// -/iked.conf.5/1.23/Tue Apr 2 09:13:22 2013// -/ikev1.c/1.13/Result of merge+Tue Apr 2 09:13:23 2013// -/ikev2.c/1.82/Result of merge+Tue Apr 2 09:13:24 2013// -/ikev2.h/1.12/Tue Apr 2 09:13:26 2013// -/ikev2_msg.c/1.25/Result of merge+Tue Apr 2 09:13:26 2013// -/ikev2_pld.c/1.31/Result of merge+Tue Apr 2 09:13:27 2013// -/imsg_util.c/1.7/Result of merge+Tue Apr 2 09:13:28 2013// -/parse.y/1.30/Result of merge// -/pfkey.c/1.23/Result of merge// -/proc.c/1.9/Result of merge+Tue Apr 2 09:13:31 2013// -/types.h/1.17/Mon Jan 14 14:11:49 2013// -D diff --git a/iked/CVS/Repository b/iked/CVS/Repository deleted file mode 100644 index 6a68f45..0000000 --- a/iked/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -src/sbin/iked diff --git a/iked/CVS/Root b/iked/CVS/Root deleted file mode 100644 index 13631a1..0000000 --- a/iked/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -anoncvs@anoncvs.openbsd.org:/cvs diff --git a/iked/Makefile.am b/iked/Makefile.am index a1dc4a7..564e097 100644 --- a/iked/Makefile.am +++ b/iked/Makefile.am @@ -4,7 +4,8 @@ iked_MAPS= eap_map.c ikev2_map.c iked_MAPS_IN= eap.h ikev2.h iked_SOURCES= ca.c chap_ms.c config.c control.c crypto.c dh.c \ eap.c iked.c ikev1.c ikev2.c ikev2_msg.c ikev2_pld.c \ - log.c policy.c proc.c timer.c util.c imsg_util.c \ + log.c ocsp.c policy.c proc.c \ + smult_curve25519_ref.c timer.c util.c imsg_util.c \ parse.y $(iked_MAPS) iked_CFLAGS= diff --git a/iked/ca.c b/iked/ca.c index 3840cae..59d8755 100644 --- a/iked/ca.c +++ b/iked/ca.c @@ -16,8 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include #include #include #include @@ -73,7 +72,6 @@ int ca_dispatch_ikev2(int, struct privsep_proc *, struct imsg *); static struct privsep_proc procs[] = { { "parent", PROC_PARENT, ca_dispatch_parent }, - { "ikev1", PROC_IKEV1, ca_dispatch_ikev1 }, { "ikev2", PROC_IKEV2, ca_dispatch_ikev2 } }; diff --git a/iked/config.c b/iked/config.c index 0e05d8f..c0382da 100644 --- a/iked/config.c +++ b/iked/config.c @@ -31,6 +31,7 @@ #include #include +#include "defines.h" #include "iked.h" #include "ikev2.h" diff --git a/iked/dh.c b/iked/dh.c index 5c5ae38..602ded4 100644 --- a/iked/dh.c +++ b/iked/dh.c @@ -25,6 +25,7 @@ #include #include +#include "defines.h" #include "dh.h" int dh_init(struct group *); @@ -298,10 +299,18 @@ struct group_id ike_groups[] = { }, { GROUP_ECP, 25, 192, NULL, NULL, NID_X9_62_prime192v1 }, { GROUP_ECP, 26, 224, NULL, NULL, NID_secp224r1 }, +#ifdef NID_brainpoolP224r1 { GROUP_ECP, 27, 224, NULL, NULL, NID_brainpoolP224r1 }, +#endif +#ifdef NID_brainpoolP256r1 { GROUP_ECP, 28, 256, NULL, NULL, NID_brainpoolP256r1 }, +#endif +#ifdef NID_brainpoolP384r1 { GROUP_ECP, 29, 384, NULL, NULL, NID_brainpoolP384r1 }, +#endif +#ifdef NID_brainpoolP512r1 { GROUP_ECP, 30, 512, NULL, NULL, NID_brainpoolP512r1 }, +#endif /* "Private use" extensions */ { GROUP_CURVE25519, 1034, CURVE25519_SIZE * 8 } diff --git a/iked/genmap.sh b/iked/genmap.sh old mode 100644 new mode 100755 diff --git a/iked/iked.c b/iked/iked.c index 9a9c7cd..4f9f997 100644 --- a/iked/iked.c +++ b/iked/iked.c @@ -45,7 +45,6 @@ int parent_dispatch_ca(int, struct privsep_proc *, struct imsg *); int parent_configure(struct iked *); static struct privsep_proc procs[] = { - { "ikev1", PROC_IKEV1, parent_dispatch_ikev1, ikev1 }, { "ikev2", PROC_IKEV2, parent_dispatch_ikev2, ikev2 }, { "ca", PROC_CERT, parent_dispatch_ca, caproc, IKED_CA } }; diff --git a/iked/iked.h b/iked/iked.h index 5df3d35..f050fa1 100644 --- a/iked/iked.h +++ b/iked/iked.h @@ -17,10 +17,10 @@ */ #include -#include "openbsd-compat/sys-tree.h" -#include "openbsd-compat/sys-queue.h" +#include +#include #include -#include +#include "imsg.h" #include "types.h" #include "dh.h" @@ -146,7 +146,7 @@ struct iked_flow { u_int8_t flow_saproto; u_int8_t flow_ipproto; u_int8_t flow_type; - + u_int32_t flow_id; struct iked_addr *flow_local; /* outer source */ struct iked_addr *flow_peer; /* outer dest */ struct iked_sa *flow_ikesa; /* parent SA */ diff --git a/iked/ikev2.c b/iked/ikev2.c index 7b676e6..6e1a052 100644 --- a/iked/ikev2.c +++ b/iked/ikev2.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include @@ -2296,6 +2296,14 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) ret = ikev2_childsa_enable(env, sa); if (ret == 0) { sa_state(env, sa, IKEV2_STATE_ESTABLISHED); + /** + * Logs about the secure session are tagged with LOG_SESSION + * so that it can be extracted for customer visiblity purposes + */ + log_info("LOG_SESSION: Secure session established to peer %s \ + local %s", print_host((struct sockaddr *)&sa->sa_peer.addr, + NULL, 0), print_host((struct sockaddr *)&sa->sa_local.addr, + NULL, 0)); timer_set(env, &sa->sa_timer, ikev2_ike_sa_alive, sa); timer_add(env, &sa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT); timer_set(env, &sa->sa_rekey, ikev2_ike_sa_rekey, sa); @@ -2306,6 +2314,12 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) done: if (ret) ikev2_childsa_delete(env, sa, 0, 0, NULL, 1); + if (ret != 0) { + log_info("LOG_SESSION: Authentication failure in establishing \ + secure session from %s to peer %s", + print_host((struct sockaddr *)&sa->sa_local.addr, NULL, 0), + print_host((struct sockaddr *)&sa->sa_peer.addr, NULL, 0)); + } ibuf_release(e); return (ret); } @@ -2847,6 +2861,12 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) } ret = ikev2_childsa_enable(env, sa); + if ((ret == 0) && (csa)) { + log_info("LOG_SESSION: Rekeying secure session key peer %s \ + local %s", print_host((struct sockaddr *)&sa->sa_peer.addr, + NULL, 0), print_host((struct sockaddr *)&sa->sa_local.addr, + NULL, 0)); + } done: sa->sa_stateflags &= ~IKED_REQ_CHILDSA; @@ -3243,8 +3263,10 @@ ikev2_ike_sa_alive(struct iked *env, void *arg) if (!csa->csa_loaded || csa->csa_saproto == IKEV2_SAPROTO_IPCOMP) continue; +#if defined(_OPENBSD_IPSEC_API_VERSION) if (pfkey_sa_last_used(env->sc_pfkey, csa, &last_used) != 0) continue; +#endif gettimeofday(&tv, NULL); diff = (u_int32_t)(tv.tv_sec - last_used); log_debug("%s: %s CHILD SA spi %s last used %llu second(s) ago", @@ -4635,6 +4657,7 @@ ikev2_childsa_enable(struct iked *env, struct iked_sa *sa) print_spi(csa->csa_spi.spi, csa->csa_spi.spi_size)); } +#if defined (_INSTALL_IPSEC_POLICY) TAILQ_FOREACH(flow, &sa->sa_flows, flow_entry) { if (flow->flow_loaded) continue; @@ -4656,6 +4679,7 @@ ikev2_childsa_enable(struct iked *env, struct iked_sa *sa) log_debug("%s: loaded flow %p", __func__, flow); } +#endif return (0); } @@ -4776,7 +4800,9 @@ ikev2_acquire_sa(struct iked *env, struct iked_flow *acquire) pol.pol_nflows = 1; if ((p = policy_test(env, &pol)) == NULL) { - log_warnx("%s: flow wasn't found", __func__); + log_warnx("%s: config for peer %s wasn't found", + __func__, print_host((struct sockaddr *) + &((acquire->flow_dst).addr), NULL, 0)); return (0); } diff --git a/iked/log.c b/iked/log.c index 61256f3..7b31b71 100644 --- a/iked/log.c +++ b/iked/log.c @@ -44,8 +44,7 @@ log_init(int n_debug) debug = n_debug; verbose = n_debug; - if (!debug) - openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON); + openlog(__progname, LOG_PID | LOG_NDELAY, LOG_LOCAL2); tzset(); } @@ -70,19 +69,7 @@ void vlog(int pri, const char *fmt, va_list ap) { char *nfmt; - - if (debug) { - /* best effort in out of mem situations */ - if (asprintf(&nfmt, "%s\n", fmt) == -1) { - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - } else { - vfprintf(stderr, nfmt, ap); - free(nfmt); - } - fflush(stderr); - } else - vsyslog(pri, fmt, ap); + vsyslog(pri, fmt, ap); } @@ -149,7 +136,7 @@ print_debug(const char *emsg, ...) if (debug && verbose > 2) { va_start(ap, emsg); - vfprintf(stderr, emsg, ap); + vlog(LOG_DEBUG, emsg, ap); va_end(ap); } } @@ -161,7 +148,7 @@ print_verbose(const char *emsg, ...) if (verbose) { va_start(ap, emsg); - vfprintf(stderr, emsg, ap); + vlog(LOG_DEBUG, emsg, ap); va_end(ap); } } diff --git a/iked/ocsp.c b/iked/ocsp.c new file mode 100644 index 0000000..76827ab --- /dev/null +++ b/iked/ocsp.c @@ -0,0 +1,512 @@ +/* + * Copyright (c) 2014 Markus Friedl + * Copyright (c) 2005 Marco Pfatschbacher + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "iked.h" + +struct iked_ocsp { + struct iked *ocsp_env; /* back pointer to env */ + struct iked_sahdr ocsp_sh; /* ike sa */ + u_int8_t ocsp_type; /* auth type */ + struct iked_socket *ocsp_sock; /* socket to ocsp responder */ + BIO *ocsp_cbio; /* matching OpenSSL obj */ + OCSP_CERTID *ocsp_id; /* ocsp-id for cert */ + OCSP_REQUEST *ocsp_req; /* ocsp-request */ + OCSP_REQ_CTX *ocsp_req_ctx; /* async ocsp-request */ +}; + +struct ocsp_connect { + struct iked_socket oc_sock; + char *oc_path; +}; + +/* priv */ +void ocsp_connect_cb(int, short, void *); +int ocsp_connect_finish(struct iked *, int, struct ocsp_connect *); + +/* unpriv */ +void ocsp_free(struct iked_ocsp *); +void ocsp_callback(int, short, void *); +void ocsp_parse_response(struct iked_ocsp *, OCSP_RESPONSE *); +STACK_OF(X509) *ocsp_load_certs(const char *); +int ocsp_validate_finish(struct iked_ocsp *, int); + + +/* priv */ + +/* async connect to configure ocsp-responder */ +int +ocsp_connect(struct iked *env) +{ + struct ocsp_connect *oc = NULL; + struct addrinfo hints, *res0 = NULL, *res; + char *host = NULL, *port = NULL, *path = NULL; + int use_ssl, fd = -1, ret = -1, error; + + if (env->sc_ocsp_url == 0) { + log_warnx("%s: no ocsp url", __func__); + goto done; + } + if (!OCSP_parse_url(env->sc_ocsp_url, &host, &port, &path, &use_ssl)) { + log_warnx("%s: error parsing OCSP-request-URL: %s", __func__, + env->sc_ocsp_url); + goto done; + } + + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + log_debug("%s: socket failed", __func__); + goto done; + } + if ((oc = calloc(1, sizeof(*oc))) == NULL) { + log_debug("%s: calloc failed", __func__); + goto done; + } + + bzero(&hints, sizeof(struct addrinfo)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(host, port, &hints, &res0); + if (error) { + log_debug("%s: getaddrinfo(%s, %s) failed", + __func__, host, port); + goto done; + } + /* XXX just pick the first answer. we could loop instead */ + for (res = res0; res; res = res->ai_next) + if (res->ai_family == AF_INET) + break; + if (res == NULL) { + log_debug("%s: no addr to connect to for %s:%s", + __func__, host, port); + goto done; + } + + oc->oc_sock.sock_fd = fd; + oc->oc_sock.sock_env = env; + oc->oc_path = path; + path = NULL; + + log_debug("%s: connect(%s, %s)", __func__, host, port); + socket_set_blockmode(fd, BM_NONBLOCK); + if (connect(fd, res->ai_addr, res->ai_addrlen) == -1) { + /* register callback for ansync connect */ + if (errno == EINPROGRESS) { + event_set(&oc->oc_sock.sock_ev, fd, EV_WRITE, + ocsp_connect_cb, oc); + event_add(&oc->oc_sock.sock_ev, NULL); + ret = 0; + } else + log_debug("%s: error while connecting: %s", __func__, + strerror(errno)); + } else { + ocsp_connect_finish(env, fd, oc); + ret = 0; + } + done: + if (res0) + freeaddrinfo(res0); + free(host); + free(port); + free(path); + if (ret == -1) { + ocsp_connect_finish(env, -1, oc); + if (fd >= 0) + close(fd); + } + return (ret); +} + +/* callback triggered if connection to ocsp-responder completes/fails */ +void +ocsp_connect_cb(int fd, short event, void *arg) +{ + struct ocsp_connect *oc = arg; + int error, send_fd = -1; + socklen_t len; + + len = sizeof(error); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + log_warn("%s: getsockopt SOL_SOCKET SO_ERROR", __func__); + } else if (error) { + log_debug("%s: error while connecting: %s", __func__, + strerror(error)); + } else { + send_fd = fd; + } + ocsp_connect_finish(oc->oc_sock.sock_env, send_fd, oc); + + /* if we did not send the fd, we need to close it ourself */ + if (send_fd == -1) + close(fd); +} + +/* send FD+path or error back to CA process */ +int +ocsp_connect_finish(struct iked *env, int fd, struct ocsp_connect *oc) +{ + struct iovec iov[1]; + int iovcnt = 1, ret; + + if (oc && fd >= 0) { + /* the imsg framework will close the FD after send */ + iov[0].iov_base = oc->oc_path; + iov[0].iov_len = strlen(oc->oc_path); + ret = proc_composev_imsg(&env->sc_ps, PROC_CERT, -1, + IMSG_OCSP_FD, fd, iov, iovcnt); + } else { + ret = proc_compose_imsg(&env->sc_ps, PROC_CERT, -1, + IMSG_OCSP_FD, -1, NULL, 0); + if (fd >= 0) + close(fd); + } + if (oc) { + free(oc->oc_path); + free(oc); + } + return (ret); +} + + +/* unpriv */ + +/* validate the certifcate stored in 'data' by querying the ocsp-responder */ +int +ocsp_validate_cert(struct iked *env, struct iked_static_id *id, + void *data, size_t len, struct iked_sahdr sh, u_int8_t type) +{ + struct iked_ocsp_entry *ioe; + struct iked_ocsp *ocsp; + BIO *rawcert = NULL, *bissuer = NULL; + X509 *cert = NULL, *issuer = NULL; + + if ((ioe = calloc(1, sizeof(*ioe))) == NULL) + return (-1); + if ((ocsp = calloc(1, sizeof(*ocsp))) == NULL) { + free(ioe); + return (-1); + } + + ocsp->ocsp_env = env; + ocsp->ocsp_sh = sh; + ocsp->ocsp_type = type; + + if ((rawcert = BIO_new_mem_buf(data, len)) == NULL || + (cert = d2i_X509_bio(rawcert, NULL)) == NULL || + (bissuer = BIO_new_file(IKED_OCSP_ISSUER, "r")) == NULL || + (issuer = PEM_read_bio_X509(bissuer, NULL, NULL, NULL)) == NULL || + (ocsp->ocsp_cbio = BIO_new(BIO_s_socket())) == NULL || + (ocsp->ocsp_req = OCSP_REQUEST_new()) == NULL || + !(ocsp->ocsp_id = OCSP_cert_to_id(NULL, cert, issuer)) || + !OCSP_request_add0_id(ocsp->ocsp_req, ocsp->ocsp_id)) + goto err; + + BIO_free(rawcert); + BIO_free(bissuer); + X509_free(cert); + X509_free(issuer); + + ioe->ioe_ocsp = ocsp; + TAILQ_INSERT_TAIL(&env->sc_ocsp, ioe, ioe_entry); + + /* request connection to ocsp-responder */ + proc_compose_imsg(&env->sc_ps, PROC_PARENT, -1, + IMSG_OCSP_FD, -1, NULL, 0); + return (0); + + err: + ca_sslerror(__func__); + free(ioe); + if (rawcert != NULL) + BIO_free(rawcert); + if (cert != NULL) + X509_free(cert); + if (bissuer != NULL) + BIO_free(bissuer); + if (issuer != NULL) + X509_free(issuer); + ocsp_validate_finish(ocsp, 0); /* failed */ + return (-1); +} + +/* free ocsp query context */ +void +ocsp_free(struct iked_ocsp *ocsp) +{ + if (ocsp != NULL) { + if (ocsp->ocsp_sock != NULL) { + close(ocsp->ocsp_sock->sock_fd); + free(ocsp->ocsp_sock); + } + if (ocsp->ocsp_cbio != NULL) + BIO_free_all(ocsp->ocsp_cbio); + if (ocsp->ocsp_id != NULL) + OCSP_CERTID_free(ocsp->ocsp_id); + + /* XXX not sure about ownership XXX */ + if (ocsp->ocsp_req_ctx != NULL) + OCSP_REQ_CTX_free(ocsp->ocsp_req_ctx); + else if (ocsp->ocsp_req != NULL) + OCSP_REQUEST_free(ocsp->ocsp_req); + + free(ocsp); + } +} + +/* we got a connection to the ocsp responder */ +int +ocsp_receive_fd(struct iked *env, struct imsg *imsg) +{ + struct iked_ocsp_entry *ioe = NULL; + struct iked_ocsp *ocsp = NULL; + struct iked_socket *sock; + char *path = NULL; + int ret = -1; + + log_debug("%s: received socket fd %d", __func__, imsg->fd); + if ((ioe = TAILQ_FIRST(&env->sc_ocsp)) == NULL) { + log_debug("%s: oops, no request for", __func__); + close(imsg->fd); + return (-1); + } + TAILQ_REMOVE(&env->sc_ocsp, ioe, ioe_entry); + ocsp = ioe->ioe_ocsp; + free(ioe); + + if ((sock = calloc(1, sizeof(*sock))) == NULL) + fatal("ocsp_receive_fd: calloc sock"); + + /* note that sock_addr is not set */ + sock->sock_fd = imsg->fd; + sock->sock_env = env; + ocsp->ocsp_sock = sock; + + /* fetch 'path' and 'fd' from imsg */ + if ((path = get_string(imsg->data, IMSG_DATA_SIZE(imsg))) == NULL) + goto done; + + BIO_set_fd(ocsp->ocsp_cbio, imsg->fd, BIO_NOCLOSE); + + if ((ocsp->ocsp_req_ctx = OCSP_sendreq_new(ocsp->ocsp_cbio, + path, NULL, -1)) == NULL) + goto done; + if (!OCSP_REQ_CTX_set1_req(ocsp->ocsp_req_ctx, ocsp->ocsp_req)) + goto done; + + event_set(&sock->sock_ev, sock->sock_fd, EV_WRITE, ocsp_callback, ocsp); + event_add(&sock->sock_ev, NULL); + ret = 0; + done: + if (ret == -1) + ocsp_validate_finish(ocsp, 0); /* failed */ + free(path); + return (ret); +} + +/* load a stack of x509 certificates */ +STACK_OF(X509)* +ocsp_load_certs(const char *file) +{ + BIO *bio = NULL; + STACK_OF(X509) *certs = NULL; + STACK_OF(X509_INFO) *xis = NULL; + X509_INFO *xi; + int i; + + if ((bio = BIO_new_file(file, "r")) == NULL) { + log_warn("%s: BIO_new_file failed for %s", + __func__, file); + return (NULL); + } + if ((xis = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL)) == NULL) { + ca_sslerror(__func__); + goto done; + } + if ((certs = sk_X509_new_null()) == NULL) { + log_debug("%s: sk_X509_new_null failed for %s", __func__, file); + goto done; + } + for (i = 0; i < sk_X509_INFO_num(xis); i++) { + xi = sk_X509_INFO_value(xis, i); + if (xi->x509) { + if (!sk_X509_push(certs, xi->x509)) + goto done; + xi->x509 = NULL; + } + } + + done: + if (bio) + BIO_free(bio); + if (xis) + sk_X509_INFO_pop_free(xis, X509_INFO_free); + if (certs && sk_X509_num(certs) <= 0) { + sk_X509_pop_free(certs, X509_free); + certs = NULL; + } + return (certs); +} + +/* read/write callback that sends the requests and reads the ocsp response */ +void +ocsp_callback(int fd, short event, void *arg) +{ + struct iked_ocsp *ocsp = arg; + struct iked_socket *sock = ocsp->ocsp_sock; + OCSP_RESPONSE *resp = NULL; + + /* + * Only call OCSP_sendreq_nbio() if should_read/write is + * either not requested or read/write can be called. + */ + if ((!BIO_should_read(ocsp->ocsp_cbio) || (event & EV_READ)) && + (!BIO_should_write(ocsp->ocsp_cbio) || (event & EV_WRITE)) && + OCSP_sendreq_nbio(&resp, ocsp->ocsp_req_ctx) != -1 ) { + ocsp_parse_response(ocsp, resp); + return; + } + if (BIO_should_read(ocsp->ocsp_cbio)) + event_set(&sock->sock_ev, sock->sock_fd, EV_READ, + ocsp_callback, ocsp); + else if (BIO_should_write(ocsp->ocsp_cbio)) + event_set(&sock->sock_ev, sock->sock_fd, EV_WRITE, + ocsp_callback, ocsp); + event_add(&sock->sock_ev, NULL); +} + +/* parse the actual OCSP response */ +void +ocsp_parse_response(struct iked_ocsp *ocsp, OCSP_RESPONSE *resp) +{ + int status; + X509_STORE *store = NULL; + STACK_OF(X509) *verify_other = NULL; + OCSP_BASICRESP *bs = NULL; + int verify_flags = 0; + ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; + int reason = 0; + int error = 1; + + if (!resp) { + log_warnx("%s: error querying OCSP responder", __func__); + goto done; + } + + status = OCSP_response_status(resp); + if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + log_warnx("%s: responder error: %s (%i)\n", __func__, + OCSP_response_status_str(status), status); + goto done; + } + + verify_other = ocsp_load_certs(IKED_OCSP_RESPCERT); + verify_flags |= OCSP_TRUSTOTHER; + if (!verify_other) + goto done; + + bs = OCSP_response_get1_basic(resp); + if (!bs) { + log_warnx("%s: error parsing response", __func__); + goto done; + } + + status = OCSP_check_nonce(ocsp->ocsp_req, bs); + if (status <= 0) { + if (status == -1) + log_warnx("%s: no nonce in response", __func__); + else { + log_warnx("%s: nonce verify error", __func__); + goto done; + } + } + + store = X509_STORE_new(); + status = OCSP_basic_verify(bs, verify_other, store, verify_flags); + if (status < 0) + status = OCSP_basic_verify(bs, NULL, store, 0); + + if (status <= 0) { + ca_sslerror(__func__); + log_warnx("%s: response verify failure", __func__); + goto done; + } else + log_debug("%s: response verify ok", __func__); + + if (!OCSP_resp_find_status(bs, ocsp->ocsp_id, &status, &reason, + &rev, &thisupd, &nextupd)) { + log_warnx("%s: no status found", __func__); + goto done; + } + log_debug("%s: status: %s", __func__, OCSP_cert_status_str(status)); + + if (status == V_OCSP_CERTSTATUS_GOOD) + error = 0; + + done: + if (store) + X509_STORE_free(store); + if (verify_other) + sk_X509_pop_free(verify_other, X509_free); + if (resp) + OCSP_RESPONSE_free(resp); + if (bs) + OCSP_BASICRESP_free(bs); + + ocsp_validate_finish(ocsp, error == 0); +} + +/* + * finish the ocsp_validate_cert() RPC by sending the appropriate + * message back to the IKEv2 process + */ +int +ocsp_validate_finish(struct iked_ocsp *ocsp, int valid) +{ + struct iked *env = ocsp->ocsp_env; + struct iovec iov[2]; + int iovcnt = 2, ret, cmd; + + iov[0].iov_base = &ocsp->ocsp_sh; + iov[0].iov_len = sizeof(ocsp->ocsp_sh); + iov[1].iov_base = &ocsp->ocsp_type; + iov[1].iov_len = sizeof(ocsp->ocsp_type); + + cmd = valid ? IMSG_CERTVALID : IMSG_CERTINVALID; + ret = proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, + cmd, -1, iov, iovcnt); + + ocsp_free(ocsp); + return (ret); +} diff --git a/iked/parse.y b/iked/parse.y index 861295c..85bdc73 100644 --- a/iked/parse.y +++ b/iked/parse.y @@ -809,10 +809,12 @@ ipcomp : /* empty */ { $$ = 0; } ikeauth : /* empty */ { $$.auth_method = IKEV2_AUTH_RSA_SIG; $$.auth_length = 0; + $$.auth_eap = 0; } | RSA { $$.auth_method = IKEV2_AUTH_RSA_SIG; $$.auth_length = 0; + $$.auth_eap = 0; } | PSK keyspec { memcpy(&$$, &$2, sizeof($$)); @@ -1970,12 +1972,15 @@ int ifa_exists(const char *ifa_name) { struct ipsec_addr_wrap *n; - struct ifgroupreq ifgr; - int s; +#if defined(SIOCGIFGMEMB) + struct ifgroupreq ifgr; + int s; +#endif if (iftab == NULL) ifa_load(); +#if defined(SIOCGIFGMEMB) /* check wether this is a group */ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) err(1, "ifa_exists: socket"); @@ -1986,6 +1991,7 @@ ifa_exists(const char *ifa_name) return (1); } close(s); +#endif for (n = iftab; n; n = n->next) { if (n->af == AF_LINK && !strncmp(n->name, ifa_name, @@ -1999,6 +2005,7 @@ ifa_exists(const char *ifa_name) struct ipsec_addr_wrap * ifa_grouplookup(const char *ifa_name) { +#if defined(SIOCGIFGMEMB) struct ifg_req *ifg; struct ifgroupreq ifgr; int s; @@ -2037,7 +2044,9 @@ ifa_grouplookup(const char *ifa_name) free(ifgr.ifgr_groups); close(s); - return (h); +#else + return (NULL); +#endif } struct ipsec_addr_wrap * diff --git a/iked/pfkey.c b/iked/pfkey.c index 558722d..6a3c63a 100644 --- a/iked/pfkey.c +++ b/iked/pfkey.c @@ -19,16 +19,13 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include "openbsd-compat/sys-queue.h" +#include #include #include #include -#if defined(__OpenBSD__) -#include +#include #include -#endif #include #include @@ -73,45 +70,61 @@ struct pfkey_constmap { static const struct pfkey_constmap pfkey_encr[] = { #ifdef SADB_X_EALG_DES_IV64 - { SADB_X_EALG_DES_IV64, IKEV2_XFORMENCR_DES_IV64 }, + { SADB_X_EALG_DES_IV64, IKEV2_XFORMENCR_DES_IV64 }, #endif - { SADB_EALG_DESCBC, IKEV2_XFORMENCR_DES }, - { SADB_EALG_3DESCBC, IKEV2_XFORMENCR_3DES }, + { SADB_EALG_DESCBC, IKEV2_XFORMENCR_DES }, + { SADB_EALG_3DESCBC, IKEV2_XFORMENCR_3DES }, #ifdef SADB_X_EALG_RC5 - { SADB_X_EALG_RC5, IKEV2_XFORMENCR_RC5 }, + { SADB_X_EALG_RC5, IKEV2_XFORMENCR_RC5 }, #endif #ifdef SADB_X_EALG_IDEA - { SADB_X_EALG_IDEA, IKEV2_XFORMENCR_IDEA }, + { SADB_X_EALG_IDEA, IKEV2_XFORMENCR_IDEA }, +#endif +#ifdef SADB_X_EALG_RC5 + { SADB_X_EALG_CAST, IKEV2_XFORMENCR_CAST }, +#endif +#ifdef SADB_X_EALG_BLF + { SADB_X_EALG_BLF, IKEV2_XFORMENCR_BLOWFISH }, #endif - { SADB_X_EALG_CAST, IKEV2_XFORMENCR_CAST }, - { SADB_X_EALG_BLF, IKEV2_XFORMENCR_BLOWFISH }, #ifdef SADB_X_EALG_3IDEA - { SADB_X_EALG_3IDEA, IKEV2_XFORMENCR_3IDEA }, + { SADB_X_EALG_3IDEA, IKEV2_XFORMENCR_3IDEA }, #endif #ifdef SADB_X_EALG_DES_IV32 - { SADB_X_EALG_DES_IV32, IKEV2_XFORMENCR_DES_IV32 }, + { SADB_X_EALG_DES_IV32, IKEV2_XFORMENCR_DES_IV32 }, #endif #ifdef SADB_X_EALG_RC4 - { SADB_X_EALG_RC4, IKEV2_XFORMENCR_RC4 }, + { SADB_X_EALG_RC4, IKEV2_XFORMENCR_RC4 }, #endif - { SADB_EALG_NULL, IKEV2_XFORMENCR_NULL }, - { SADB_X_EALG_AES, IKEV2_XFORMENCR_AES_CBC }, - { SADB_X_EALG_AESCTR, IKEV2_XFORMENCR_AES_CTR }, - { SADB_X_EALG_AESGCM16, IKEV2_XFORMENCR_AES_GCM_16 }, - { SADB_X_EALG_AESGMAC, IKEV2_XFORMENCR_NULL_AES_GMAC }, - { 0 } + { SADB_EALG_NULL, IKEV2_XFORMENCR_NULL }, + { SADB_X_EALG_AES, IKEV2_XFORMENCR_AES_CBC }, +#ifdef SADB_X_EALG_AESCTR + { SADB_X_EALG_AESCTR, IKEV2_XFORMENCR_AES_CTR }, +#endif +#ifdef SADB_X_EALG_AESGCM16 + { SADB_X_EALG_AESGCM16, IKEV2_XFORMENCR_AES_GCM_16 }, +#endif +#ifdef SADB_X_EALG_AESGMAC + { SADB_X_EALG_AESGMAC, IKEV2_XFORMENCR_NULL_AES_GMAC }, +#endif + { 0 } }; static const struct pfkey_constmap pfkey_integr[] = { - { SADB_AALG_MD5HMAC, IKEV2_XFORMAUTH_HMAC_MD5_96 }, - { SADB_AALG_SHA1HMAC, IKEV2_XFORMAUTH_HMAC_SHA1_96 }, + { SADB_AALG_MD5HMAC, IKEV2_XFORMAUTH_HMAC_MD5_96 }, + { SADB_AALG_SHA1HMAC, IKEV2_XFORMAUTH_HMAC_SHA1_96 }, #ifdef SADB_X_AALG_DES - { SADB_X_AALG_DES, IKEV2_XFORMAUTH_DES_MAC }, + { SADB_X_AALG_DES, IKEV2_XFORMAUTH_DES_MAC }, #endif - { SADB_X_AALG_SHA2_256, IKEV2_XFORMAUTH_HMAC_SHA2_256_128 }, - { SADB_X_AALG_SHA2_384, IKEV2_XFORMAUTH_HMAC_SHA2_384_192 }, - { SADB_X_AALG_SHA2_512, IKEV2_XFORMAUTH_HMAC_SHA2_512_256 }, - { 0 } +#if defined(SADB_X_AALG_SHA2_256) && !defined(BROKEN_HMAC_SHA2_256) + { SADB_X_AALG_SHA2_256, IKEV2_XFORMAUTH_HMAC_SHA2_256_128 }, +#endif +#ifdef SADB_X_AALG_SHA2_384 + { SADB_X_AALG_SHA2_384, IKEV2_XFORMAUTH_HMAC_SHA2_384_192 }, +#endif +#ifdef SADB_X_AALG_SHA2_512 + { SADB_X_AALG_SHA2_512, IKEV2_XFORMAUTH_HMAC_SHA2_512_256 }, +#endif + { 0 } }; static const struct pfkey_constmap pfkey_satype[] = { @@ -197,777 +210,795 @@ int pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) { #if defined(_OPENBSD_IPSEC_API_VERSION) - struct sadb_msg smsg; - struct sadb_address sa_src, sa_dst, sa_local, sa_peer, sa_smask, - sa_dmask; - struct sadb_protocol sa_flowtype, sa_protocol; - struct sadb_ident *sa_srcid, *sa_dstid; - struct sockaddr_storage ssrc, sdst, slocal, speer, smask, dmask; - struct iovec iov[IOV_CNT]; - int iov_cnt, ret = -1; - - sa_srcid = sa_dstid = NULL; - - bzero(&ssrc, sizeof(ssrc)); - bzero(&smask, sizeof(smask)); - memcpy(&ssrc, &flow->flow_src.addr, sizeof(ssrc)); - memcpy(&smask, &flow->flow_src.addr, sizeof(smask)); - socket_af((struct sockaddr *)&ssrc, flow->flow_src.addr_port); - socket_af((struct sockaddr *)&smask, flow->flow_src.addr_port ? - 0xfffff : 0); - - switch (flow->flow_src.addr_af) { - case AF_INET: - ((struct sockaddr_in *)&smask)->sin_addr.s_addr = - prefixlen2mask(flow->flow_src.addr_net ? - flow->flow_src.addr_mask : 32); - break; - case AF_INET6: - prefixlen2mask6(flow->flow_src.addr_net ? - flow->flow_src.addr_mask : 128, - (u_int32_t *)((struct sockaddr_in6 *) - &smask)->sin6_addr.s6_addr); - break; - default: - log_warnx("%s: unsupported address family %d", - __func__, flow->flow_src.addr_af); - return (-1); - } - smask.ss_len = ssrc.ss_len; - - bzero(&sdst, sizeof(sdst)); - bzero(&dmask, sizeof(dmask)); - memcpy(&sdst, &flow->flow_dst.addr, sizeof(sdst)); - memcpy(&dmask, &flow->flow_dst.addr, sizeof(dmask)); - socket_af((struct sockaddr *)&sdst, flow->flow_dst.addr_port); - socket_af((struct sockaddr *)&dmask, flow->flow_dst.addr_port ? - 0xffff : 0); - - switch (flow->flow_dst.addr_af) { - case AF_INET: - ((struct sockaddr_in *)&dmask)->sin_addr.s_addr = - prefixlen2mask(flow->flow_dst.addr_net ? - flow->flow_dst.addr_mask : 32); - break; - case AF_INET6: - prefixlen2mask6(flow->flow_dst.addr_net ? - flow->flow_dst.addr_mask : 128, - (u_int32_t *)((struct sockaddr_in6 *) - &dmask)->sin6_addr.s6_addr); - break; - default: - log_warnx("%s: unsupported address family %d", - __func__, flow->flow_dst.addr_af); - return (-1); - } - dmask.ss_len = sdst.ss_len; - - bzero(&slocal, sizeof(slocal)); - bzero(&speer, sizeof(speer)); - if (action != SADB_X_DELFLOW && flow->flow_local != NULL) { - memcpy(&slocal, &flow->flow_local->addr, sizeof(slocal)); - socket_af((struct sockaddr *)&slocal, 0); - - memcpy(&speer, &flow->flow_peer->addr, sizeof(speer)); - socket_af((struct sockaddr *)&speer, 0); - } - - bzero(&smsg, sizeof(smsg)); - smsg.sadb_msg_version = PF_KEY_V2; - smsg.sadb_msg_seq = ++sadb_msg_seq; - smsg.sadb_msg_pid = getpid(); - smsg.sadb_msg_len = sizeof(smsg) / 8; - smsg.sadb_msg_type = action; - smsg.sadb_msg_satype = satype; - - bzero(&sa_flowtype, sizeof(sa_flowtype)); - sa_flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE; - sa_flowtype.sadb_protocol_len = sizeof(sa_flowtype) / 8; - sa_flowtype.sadb_protocol_direction = flow->flow_dir; - sa_flowtype.sadb_protocol_proto = - flow->flow_type ? flow->flow_type : - (flow->flow_dir == IPSP_DIRECTION_IN ? - SADB_X_FLOW_TYPE_USE : SADB_X_FLOW_TYPE_REQUIRE); - - bzero(&sa_protocol, sizeof(sa_protocol)); - sa_protocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; - sa_protocol.sadb_protocol_len = sizeof(sa_protocol) / 8; - sa_protocol.sadb_protocol_direction = 0; - sa_protocol.sadb_protocol_proto = flow->flow_ipproto; - - bzero(&sa_src, sizeof(sa_src)); - sa_src.sadb_address_exttype = SADB_X_EXT_SRC_FLOW; - sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; - - bzero(&sa_smask, sizeof(sa_smask)); - sa_smask.sadb_address_exttype = SADB_X_EXT_SRC_MASK; - sa_smask.sadb_address_len = - (sizeof(sa_smask) + ROUNDUP(smask.ss_len)) / 8; - - bzero(&sa_dst, sizeof(sa_dst)); - sa_dst.sadb_address_exttype = SADB_X_EXT_DST_FLOW; - sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; - - bzero(&sa_dmask, sizeof(sa_dmask)); - sa_dmask.sadb_address_exttype = SADB_X_EXT_DST_MASK; - sa_dmask.sadb_address_len = - (sizeof(sa_dmask) + ROUNDUP(dmask.ss_len)) / 8; - - if (action != SADB_X_DELFLOW && flow->flow_local != NULL) { - /* local address */ - bzero(&sa_local, sizeof(sa_local)); - sa_local.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; - sa_local.sadb_address_len = - (sizeof(sa_local) + ROUNDUP(slocal.ss_len)) / 8; - - /* peer address */ - bzero(&sa_peer, sizeof(sa_peer)); - sa_peer.sadb_address_exttype = SADB_EXT_ADDRESS_DST; - sa_peer.sadb_address_len = - (sizeof(sa_peer) + ROUNDUP(speer.ss_len)) / 8; - - /* local id */ - sa_srcid = pfkey_id2ident(IKESA_SRCID(flow->flow_ikesa), - SADB_EXT_IDENTITY_SRC); - - /* peer id */ - sa_dstid = pfkey_id2ident(IKESA_DSTID(flow->flow_ikesa), - SADB_EXT_IDENTITY_DST); - } - - iov_cnt = 0; - - /* header */ - iov[iov_cnt].iov_base = &smsg; - iov[iov_cnt].iov_len = sizeof(smsg); - iov_cnt++; - - /* add flow type */ - iov[iov_cnt].iov_base = &sa_flowtype; - iov[iov_cnt].iov_len = sizeof(sa_flowtype); - smsg.sadb_msg_len += sa_flowtype.sadb_protocol_len; - iov_cnt++; - - if (action != SADB_X_DELFLOW && flow->flow_local != NULL) { + struct sadb_msg smsg; + struct sadb_address sa_src, sa_dst, sa_local, sa_peer, sa_smask, + sa_dmask; + struct sadb_protocol sa_flowtype, sa_protocol; + struct sadb_ident *sa_srcid, *sa_dstid; + struct sockaddr_storage ssrc, sdst, slocal, speer, smask, dmask; + struct iovec iov[IOV_CNT]; + int iov_cnt, ret = -1; + in_port_t sport, dport; + + sport = dport = 0; + sa_srcid = sa_dstid = NULL; + + bzero(&ssrc, sizeof(ssrc)); + bzero(&smask, sizeof(smask)); + memcpy(&ssrc, &flow->flow_src.addr, sizeof(ssrc)); + memcpy(&smask, &flow->flow_src.addr, sizeof(smask)); + if ((sport = flow->flow_src.addr_port) != 0) + dport = 0xffff; + socket_af((struct sockaddr *)&ssrc, sport); + socket_af((struct sockaddr *)&smask, dport); + + switch (flow->flow_src.addr_af) { + case AF_INET: + ((struct sockaddr_in *)&smask)->sin_addr.s_addr = + prefixlen2mask(flow->flow_src.addr_net ? + flow->flow_src.addr_mask : 32); + break; + case AF_INET6: + prefixlen2mask6(flow->flow_src.addr_net ? + flow->flow_src.addr_mask : 128, + (u_int32_t *)((struct sockaddr_in6 *) + &smask)->sin6_addr.s6_addrek; + default: + log_warnx("%s: unsupported address family %d", + __func__, flow->flow_src.addr_af); + return (-1); + } + smask.ss_len = ssrc.ss_len; + + bzero(&sdst, sizeof(sdst)); + bzero(&dmask, sizeof(dmask)); + memcpy(&sdst, &flow->flow_dst.addr, sizeof(sdst)); + memcpy(&dmask, &flow->flow_dst.addr, sizeof(dmask)); + if ((sport = flow->flow_dst.addr_port) != 0) + dport = 0xffff; + socket_af((struct sockaddr *)&sdst, sport); + socket_af((struct sockaddr *)&dmask, dport); + + switch (flow->flow_dst.addr_af) { + case AF_INET: + ((struct sockaddr_in *)&dmask)->sin_addr.s_addr = + prefixlen2mask(flow->flow_dst.addr_net ? + flow->flow_dst.addr_mask : 32); + break; + case AF_INET6: + prefixlen2mask6(flow->flow_dst.addr_net ? + flow->flow_dst.addr_mask : 128, + (u_int32_t *)((struct sockaddr_in6 *) + &dmask)->sin6_addr.s6_addr); + break; + default: + log_warnx("%s: unsupported address family %d", + __func__, flow->flow_dst.addr_af); + return (-1); + } + dmask.ss_len = sdst.ss_len; + + bzero(&slocal, sizeof(slocal)); + bzero(&speer, sizeof(speer)); + if (action != SADB_X_DELFLOW && flow->flow_local != NULL) { + memcpy(&slocal, &flow->flow_local->addr, sizeof(slocal)); + socket_af((struct sockaddr *)&slocal, 0); + + memcpy(&speer, &flow->flow_peer->addr, sizeof(speer)); + socket_af((struct sockaddr *)&speer, 0); + } + + bzero(&smsg, sizeof(smsg)); + smsg.sadb_msg_version = PF_KEY_V2; + smsg.sadb_msg_seq = ++sadb_msg_seq; + smsg.sadb_msg_pid = getpid(); + smsg.sadb_msg_len = sizeof(smsg) / 8; + smsg.sadb_msg_type = action; + smsg.sadb_msg_satype = satype; + + bzero(&sa_flowtype, sizeof(sa_flowtype)); + sa_flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE; + sa_flowtype.sadb_protocol_len = sizeof(sa_flowtype) / 8; + sa_flowtype.sadb_protocol_direction = flow->flow_dir; + sa_flowtype.sadb_protocol_proto = + flow->flow_type ? flow->flow_type : + (flow->flow_dir == IPSP_DIRECTION_IN ? + SADB_X_FLOW_TYPE_USE : SADB_X_FLOW_TYPE_REQUIRE); + + bzero(&sa_protocol, sizeof(sa_protocol)); + sa_protocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; + sa_protocol.sadb_protocol_len = sizeof(sa_protocol) / 8; + sa_protocol.sadb_protocol_direction = 0; + sa_protocol.sadb_protocol_proto = flow->flow_ipproto; + + bzero(&sa_src, sizeof(sa_src)); + sa_src.sadb_address_exttype = SADB_X_EXT_SRC_FLOW; + sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; + + bzero(&sa_smask, sizeof(sa_smask)); + sa_smask.sadb_address_exttype = SADB_X_EXT_SRC_MASK; + sa_smask.sadb_address_len = + sa_smask.sadb_address_len = + (sizeof(sa_smask) + ROUNDUP(smask.ss_len)) / 8; + + bzero(&sa_dst, sizeof(sa_dst)); + sa_dst.sadb_address_exttype = SADB_X_EXT_DST_FLOW; + sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; + + bzero(&sa_dmask, sizeof(sa_dmask)); + sa_dmask.sadb_address_exttype = SADB_X_EXT_DST_MASK; + sa_dmask.sadb_address_len = + (sizeof(sa_dmask) + ROUNDUP(dmask.ss_len)) / 8; + + if (action != SADB_X_DELFLOW && flow->flow_local != NULL) { + /* local address */ + bzero(&sa_local, sizeof(sa_local)); + sa_local.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + sa_local.sadb_address_len = + (sizeof(sa_local) + ROUNDUP(slocal.ss_len)) / 8; + + /* peer address */ + bzero(&sa_peer, sizeof(sa_peer)); + sa_peer.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + sa_peer.sadb_address_len = + (sizeof(sa_peer) + ROUNDUP(speer.ss_len)) / 8; + + /* local id */ + sa_srcid = pfkey_id2ident(flow->flow_srcid, + SADB_EXT_IDENTITY_SRC); + + /* peer id */ + sa_dstid = pfkey_id2ident(flow->flow_dstid, + SADB_EXT_IDENTITY_DST); + } + + iov_cnt = 0; + + /* header */ + iov[iov_cnt].iov_base = &smsg; + iov[iov_cnt].iov_len = sizeof(smsg); + iov_cnt++; + + /* add flow type */ + iov[iov_cnt].iov_base = &sa_flowtype; + iov[iov_cnt].iov_len = sizeof(sa_flowtype); + smsg.sadb_msg_len += sa_flowtype.sadb_protocol_len; + iov_cnt++; + + if (action != SADB_X_DELFLOW && flow->flow_local != NULL) { #if 0 - /* local ip */ - iov[iov_cnt].iov_base = &sa_local; - iov[iov_cnt].iov_len = sizeof(sa_local); - iov_cnt++; - iov[iov_cnt].iov_base = &slocal; - iov[iov_cnt].iov_len = ROUNDUP(slocal.ss_len); - smsg.sadb_msg_len += sa_local.sadb_address_len; - iov_cnt++; + /* local ip */ + iov[iov_cnt].iov_base = &sa_local; + iov[iov_cnt].iov_len = sizeof(sa_local); + iov_cnt++; + iov[iov_cnt].iov_base = &slocal; + iov[iov_cnt].iov_len = ROUNDUP(slocal.ss_len); + smsg.sadb_msg_len += sa_local.sadb_address_len; + iov_cnt++; #endif - /* remote peer */ - iov[iov_cnt].iov_base = &sa_peer; - iov[iov_cnt].iov_len = sizeof(sa_peer); - iov_cnt++; - iov[iov_cnt].iov_base = &speer; - iov[iov_cnt].iov_len = ROUNDUP(speer.ss_len); - smsg.sadb_msg_len += sa_peer.sadb_address_len; - iov_cnt++; - } - - /* src addr */ - iov[iov_cnt].iov_base = &sa_src; - iov[iov_cnt].iov_len = sizeof(sa_src); - iov_cnt++; - iov[iov_cnt].iov_base = &ssrc; - iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); - smsg.sadb_msg_len += sa_src.sadb_address_len; - iov_cnt++; - - /* src mask */ - iov[iov_cnt].iov_base = &sa_smask; - iov[iov_cnt].iov_len = sizeof(sa_smask); - iov_cnt++; - iov[iov_cnt].iov_base = &smask; - iov[iov_cnt].iov_len = ROUNDUP(smask.ss_len); - smsg.sadb_msg_len += sa_smask.sadb_address_len; - iov_cnt++; - - /* dest addr */ - iov[iov_cnt].iov_base = &sa_dst; - iov[iov_cnt].iov_len = sizeof(sa_dst); - iov_cnt++; - iov[iov_cnt].iov_base = &sdst; - iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); - smsg.sadb_msg_len += sa_dst.sadb_address_len; - iov_cnt++; - - /* dst mask */ - iov[iov_cnt].iov_base = &sa_dmask; - iov[iov_cnt].iov_len = sizeof(sa_dmask); - iov_cnt++; - iov[iov_cnt].iov_base = &dmask; - iov[iov_cnt].iov_len = ROUNDUP(dmask.ss_len); - smsg.sadb_msg_len += sa_dmask.sadb_address_len; - iov_cnt++; - - /* add protocol */ - iov[iov_cnt].iov_base = &sa_protocol; - iov[iov_cnt].iov_len = sizeof(sa_protocol); - smsg.sadb_msg_len += sa_protocol.sadb_protocol_len; - iov_cnt++; - - if (sa_srcid) { - /* src identity */ - iov[iov_cnt].iov_base = sa_srcid; - iov[iov_cnt].iov_len = sa_srcid->sadb_ident_len * 8; - smsg.sadb_msg_len += sa_srcid->sadb_ident_len; - iov_cnt++; - } - if (sa_dstid) { - /* dst identity */ - iov[iov_cnt].iov_base = sa_dstid; - iov[iov_cnt].iov_len = sa_dstid->sadb_ident_len * 8; - smsg.sadb_msg_len += sa_dstid->sadb_ident_len; - iov_cnt++; - } - - ret = pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL); - - if (sa_srcid) - free(sa_srcid); - if (sa_dstid) - free(sa_dstid); + /* remote peer */ + iov[iov_cnt].iov_base = &sa_peer; + iov[iov_cnt].iov_len = sizeof(sa_peer); + iov_cnt++; + iov[iov_cnt].iov_base = &speer; + iov[iov_cnt].iov_len = ROUNDUP(speer.ss_len); + smsg.sadb_msg_len += sa_peer.sadb_address_len; + iov_cnt++; + } + + /* src addr */ + iov[iov_cnt].iov_base = &sa_src; + iov[iov_cnt].iov_len = sizeof(sa_src); + iov_cnt++; + iov[iov_cnt].iov_base = &ssrc; + iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); + smsg.sadb_msg_len += sa_src.sadb_address_len; + iov_cnt++; + + /* src mask */ + iov[iov_cnt].iov_base = &sa_smask; + iov[iov_cnt].iov_len = sizeof(sa_smask); + iov_cnt++; + iov[iov_cnt].iov_base = &smask; + iov[iov_cnt].iov_len = ROUNDUP(smask.ss_len); + smsg.sadb_msg_len += sa_smask.sadb_address_len; + iov_cnt++; + + /* dest addr */ + iov[iov_cnt].iov_base = &sa_dst; + iov[iov_cnt].iov_len = sizeof(sa_dst); + iov_cnt++; + iov[iov_cnt].iov_base = &sdst; + iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); + smsg.sadb_msg_len += sa_dst.sadb_address_len; + iov_cnt++; + + /* dst mask */ + iov[iov_cnt].iov_base = &sa_dmask; + iov[iov_cnt].iov_len = sizeof(sa_dmask); + iov_cnt++; + iov[iov_cnt].iov_base = &dmask; + iov[iov_cnt].iov_len = ROUNDUP(dmask.ss_len); + smsg.sadb_msg_len += sa_dmask.sadb_address_len; + iov_cnt++; + + /* add protocol */ + iov[iov_cnt].iov_base = &sa_protocol; + iov[iov_cnt].iov_len = sizeof(sa_protocol); + smsg.sadb_msg_len += sa_protocol.sadb_protocol_len; + iov_cnt++; + + if (sa_srcid) { + /* src identity */ + iov[iov_cnt].iov_base = sa_srcid; + iov[iov_cnt].iov_len = sa_srcid->sadb_ident_len * 8; + smsg.sadb_msg_len += sa_srcid->sadb_ident_len; + iov_cnt++; + } + if (sa_dstid) { + /* dst identity */ + iov[iov_cnt].iov_base = sa_dstid; + iov[iov_cnt].iov_len = sa_dstid->sadb_ident_len * 8; + smsg.sadb_msg_len += sa_dstid->sadb_ident_len; + iov_cnt++; + } + + ret = pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL); + + if (sa_srcid) + free(sa_srcid); + if (sa_dstid) + free(sa_dstid); #else /* !_OPENBSD_IPSEC_API_VERSION */ - struct sadb_msg smsg; - struct sadb_address sa_src, sa_dst; - struct sadb_x_ipsecrequest sa_ipsec; - struct sadb_x_policy sa_policy, *sa_polid; - struct sadb_x_sa2 sa_2; - struct sockaddr_storage ssrc, sdst, slocal, speer; - struct iovec iov[IOV_CNT]; - int iov_cnt, ret = -1; - in_port_t sport, dport; - u_int8_t smask, dmask; - u_int8_t zeropad[8]; - size_t padlen; - u_int8_t *reply = NULL; - ssize_t rlen; - - bzero(&ssrc, sizeof(ssrc)); - memcpy(&ssrc, &flow->flow_src.addr, sizeof(ssrc)); - sport = flow->flow_src.addr_port; - socket_af((struct sockaddr *)&ssrc, sport); - - switch (flow->flow_src.addr_af) { - case AF_INET: - smask = flow->flow_src.addr_net ? - flow->flow_src.addr_mask : 32; - break; - case AF_INET6: - smask = flow->flow_src.addr_net ? - flow->flow_src.addr_mask : 128; - break; - default: - log_warnx("%s: unsupported address family %d", - __func__, flow->flow_src.addr_af); - return (-1); - } - - bzero(&sdst, sizeof(sdst)); - memcpy(&sdst, &flow->flow_dst.addr, sizeof(sdst)); - dport = flow->flow_dst.addr_port; - socket_af((struct sockaddr *)&sdst, dport); - - switch (flow->flow_dst.addr_af) { - case AF_INET: - dmask = flow->flow_dst.addr_net ? - flow->flow_dst.addr_mask : 32; - break; - case AF_INET6: - dmask = flow->flow_dst.addr_net ? - flow->flow_dst.addr_mask : 128; - break; - default: - log_warnx("%s: unsupported address family %d", - __func__, flow->flow_dst.addr_af); - return (-1); - } - - bzero(&slocal, sizeof(slocal)); - bzero(&speer, sizeof(speer)); - bzero(&zeropad, sizeof(zeropad)); - if (flow->flow_local == NULL) { - slocal.ss_family = flow->flow_src.addr_af; - speer.ss_family = flow->flow_dst.addr_af; - } else if (flow->flow_dir == IPSEC_DIR_INBOUND) { - memcpy(&speer, &flow->flow_local->addr, sizeof(slocal)); - memcpy(&slocal, &flow->flow_peer->addr, sizeof(speer)); - } else { - memcpy(&slocal, &flow->flow_local->addr, sizeof(slocal)); - memcpy(&speer, &flow->flow_peer->addr, sizeof(speer)); - } - socket_af((struct sockaddr *)&slocal, 0); - socket_af((struct sockaddr *)&speer, 0); - - bzero(&smsg, sizeof(smsg)); - smsg.sadb_msg_version = PF_KEY_V2; - smsg.sadb_msg_seq = ++sadb_msg_seq; - smsg.sadb_msg_pid = getpid(); - smsg.sadb_msg_len = sizeof(smsg) / 8; - smsg.sadb_msg_type = action; - smsg.sadb_msg_satype = SADB_SATYPE_UNSPEC; - - bzero(&sa_2, sizeof(sa_2)); - sa_2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - sa_2.sadb_x_sa2_len = sizeof(sa_2) / 8; - sa_2.sadb_x_sa2_mode = IPSEC_MODE_TUNNEL; - - bzero(&sa_src, sizeof(sa_src)); - sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; - sa_src.sadb_address_proto = IPSEC_ULPROTO_ANY; //flow->flow_ipproto - sa_src.sadb_address_prefixlen = smask; - sa_src.sadb_address_len = ROUNDUP(sizeof(sa_src) + SS_LEN(&ssrc)) / 8; - - bzero(&sa_dst, sizeof(sa_dst)); - sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; - sa_dst.sadb_address_proto = IPSEC_ULPROTO_ANY; //flow->flow_ipproto; - sa_dst.sadb_address_prefixlen = dmask; - sa_dst.sadb_address_len = ROUNDUP(sizeof(sa_dst) + SS_LEN(&sdst)) / 8; - - bzero(&sa_policy, sizeof(sa_policy)); - sa_policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY; - sa_policy.sadb_x_policy_dir = flow->flow_dir; - - switch (flow->flow_type) { - case SADB_X_FLOW_TYPE_DENY: - sa_policy.sadb_x_policy_type = IPSEC_POLICY_DISCARD; - sa_policy.sadb_x_policy_len = sizeof(sa_policy) / 8; - break; - default: - sa_policy.sadb_x_policy_type = IPSEC_POLICY_IPSEC; - bzero(&sa_ipsec, sizeof(sa_ipsec)); - sa_ipsec.sadb_x_ipsecrequest_proto = - satype == SADB_SATYPE_AH ? IPPROTO_AH : IPPROTO_ESP; - sa_ipsec.sadb_x_ipsecrequest_mode = IPSEC_MODE_TUNNEL; /* XXX */ - sa_ipsec.sadb_x_ipsecrequest_level = - flow->flow_dir == IPSEC_DIR_INBOUND ? - IPSEC_LEVEL_USE : IPSEC_LEVEL_REQUIRE; - sa_ipsec.sadb_x_ipsecrequest_len = sizeof(sa_ipsec) + - SS_LEN(&slocal) + SS_LEN(&speer); - padlen = ROUNDUP(sa_ipsec.sadb_x_ipsecrequest_len) - - sa_ipsec.sadb_x_ipsecrequest_len; - sa_ipsec.sadb_x_ipsecrequest_len += padlen; - sa_policy.sadb_x_policy_len = - (sizeof(sa_policy) + - sa_ipsec.sadb_x_ipsecrequest_len) / 8; - break; - } - - iov_cnt = 0; - - /* header */ - iov[iov_cnt].iov_base = &smsg; - iov[iov_cnt].iov_len = sizeof(smsg); - iov_cnt++; - - /* add flow SA2 */ - iov[iov_cnt].iov_base = &sa_2; - iov[iov_cnt].iov_len = sizeof(sa_2); - smsg.sadb_msg_len += sa_2.sadb_x_sa2_len; - iov_cnt++; - - /* add source address */ - iov[iov_cnt].iov_base = &sa_src; - iov[iov_cnt].iov_len = sizeof(sa_src); - iov_cnt++; - iov[iov_cnt].iov_base = &ssrc; - iov[iov_cnt].iov_len = SS_LEN(&ssrc); - smsg.sadb_msg_len += sa_src.sadb_address_len; - iov_cnt++; - - /* add destination address */ - iov[iov_cnt].iov_base = &sa_dst; - iov[iov_cnt].iov_len = sizeof(sa_dst); - iov_cnt++; - iov[iov_cnt].iov_base = &sdst; - iov[iov_cnt].iov_len = SS_LEN(&sdst); - smsg.sadb_msg_len += sa_dst.sadb_address_len; - iov_cnt++; - - /* add policy extension */ - iov[iov_cnt].iov_base = &sa_policy; - iov[iov_cnt].iov_len = sizeof(sa_policy); - smsg.sadb_msg_len += sa_policy.sadb_x_policy_len; - iov_cnt++; - - if (sa_policy.sadb_x_policy_type == IPSEC_POLICY_IPSEC) { - iov[iov_cnt].iov_base = &sa_ipsec; - iov[iov_cnt].iov_len = sizeof(sa_ipsec); - iov_cnt++; - iov[iov_cnt].iov_base = &slocal; - iov[iov_cnt].iov_len = SS_LEN(&slocal); - iov_cnt++; - iov[iov_cnt].iov_base = &speer; - iov[iov_cnt].iov_len = SS_LEN(&speer); - if (padlen) { - iov_cnt++; - iov[iov_cnt].iov_base = zeropad; - iov[iov_cnt].iov_len = padlen; - } - iov_cnt++; - } - - ret = -1; - if (pfkey_write(sd, &smsg, iov, iov_cnt, &reply, &rlen) != 0) - goto done; - - if ((sa_polid = pfkey_find_ext(reply, rlen, - SADB_X_EXT_POLICY)) == NULL) { - log_debug("%s: erronous reply", __func__); - goto done; - } - - ret = 0; + struct sadb_msg smsg; + struct sadb_address sa_src, sa_dst; + struct sadb_x_ipsecrequest sa_ipsec; + struct sadb_x_policy sa_policy, *sa_polid; + struct sadb_x_sa2 sa_2; + struct sockaddr_storage ssrc, sdst, slocal, speer; + struct iovec iov[10]; + int iov_cnt, ret = -1; + in_port_t sport, dport; + u_int8_t smask, dmask; + u_int8_t zeropad[8]; + size_t padlen; + u_int8_t *reply = NULL; + ssize_t rlen; + + bzero(&ssrc, sizeof(ssrc)); + memcpy(&ssrc, &flow->flow_src.addr, sizeof(ssrc)); + sport = flow->flow_src.addr_port; + socket_af((struct sockaddr *)&ssrc, sport); + + switch (flow->flow_src.addr_af) { + case AF_INET: + smask = flow->flow_src.addr_net ? + flow->flow_src.addr_mask : 32; + break; + case AF_INET6: + smask = flow->flow_src.addr_net ? + flow->flow_src.addr_mask : 128; + break; + default: + log_warnx("%s: unsupported address family %d", + __func__, flow->flow_src.addr_af); + return (-1); + } + + bzero(&sdst, sizeof(sdst)); + memcpy(&sdst, &flow->flow_dst.addr, sizeof(sdst)); + dport = flow->flow_dst.addr_port; + socket_af((struct sockaddr *)&sdst, dport); + + switch (flow->flow_dst.addr_af) { + case AF_INET: + dmask = flow->flow_dst.addr_net ? + flow->flow_dst.addr_mask : 32; + break; + case AF_INET6: + dmask = flow->flow_dst.addr_net ? + flow->flow_dst.addr_mask : 128; + break; + default: + log_warnx("%s: unsupported address family %d", + __func__, flow->flow_dst.addr_af); + return (-1); + } + + bzero(&slocal, sizeof(slocal)); + bzero(&speer, sizeof(speer)); + bzero(&zeropad, sizeof(zeropad)); + if (flow->flow_local == NULL) { + slocal.ss_family = flow->flow_src.addr_af; + speer.ss_family = flow->flow_dst.addr_af; + } else if (flow->flow_dir == IPSEC_DIR_INBOUND) { + memcpy(&speer, &flow->flow_local->addr, sizeof(slocal)); + memcpy(&slocal, &flow->flow_peer->addr, sizeof(speer)); + } else { + memcpy(&slocal, &flow->flow_local->addr, sizeof(slocal)); + memcpy(&speer, &flow->flow_peer->addr, sizeof(speer)); + } + socket_af((struct sockaddr *)&slocal, 0); + socket_af((struct sockaddr *)&speer, 0); + + bzero(&smsg, sizeof(smsg)); + smsg.sadb_msg_version = PF_KEY_V2; + smsg.sadb_msg_seq = ++sadb_msg_seq; + smsg.sadb_msg_pid = getpid(); + smsg.sadb_msg_len = sizeof(smsg) / 8; + smsg.sadb_msg_type = action; + smsg.sadb_msg_satype = SADB_SATYPE_UNSPEC; + + bzero(&sa_2, sizeof(sa_2)); + sa_2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; + sa_2.sadb_x_sa2_len = sizeof(sa_2) / 8; + sa_2.sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT; + + bzero(&sa_src, sizeof(sa_src)); + sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + sa_src.sadb_address_proto = IPSEC_ULPROTO_ANY; //flow->flow_ipproto + sa_src.sadb_address_prefixlen = smask; + sa_src.sadb_address_len = ROUNDUP(sizeof(sa_src) + SS_LEN(&ssrc)) / 8; + + bzero(&sa_dst, sizeof(sa_dst)); + sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + sa_dst.sadb_address_proto = IPSEC_ULPROTO_ANY; //flow->flow_ipproto; + sa_dst.sadb_address_prefixlen = dmask; + sa_dst.sadb_address_len = ROUNDUP(sizeof(sa_dst) + SS_LEN(&sdst)) / 8; + + bzero(&sa_policy, sizeof(sa_policy)); + sa_policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY; + sa_policy.sadb_x_policy_dir = flow->flow_dir; + + switch (flow->flow_type) { + case SADB_X_FLOW_TYPE_DENY: + sa_policy.sadb_x_policy_type = IPSEC_POLICY_DISCARD; + sa_policy.sadb_x_policy_len = sizeof(sa_policy) / 8; + break; + default: + sa_policy.sadb_x_policy_type = IPSEC_POLICY_IPSEC; + bzero(&sa_ipsec, sizeof(sa_ipsec)); + sa_ipsec.sadb_x_ipsecrequest_proto = + satype == SADB_SATYPE_AH ? IPPROTO_AH : IPPROTO_ESP; + sa_ipsec.sadb_x_ipsecrequest_mode = IPSEC_MODE_TRANSPORT; /* XXX */ + sa_ipsec.sadb_x_ipsecrequest_level = + flow->flow_dir == IPSEC_DIR_INBOUND ? + IPSEC_LEVEL_USE : IPSEC_LEVEL_REQUIRE; + sa_ipsec.sadb_x_ipsecrequest_len = sizeof(sa_ipsec) + + SS_LEN(&slocal) + SS_LEN(&speer); + padlen = ROUNDUP(sa_ipsec.sadb_x_ipsecrequest_len) - + sa_ipsec.sadb_x_ipsecrequest_len; + sa_ipsec.sadb_x_ipsecrequest_len += padlen; + sa_policy.sadb_x_policy_len = + (sizeof(sa_policy) + + sa_ipsec.sadb_x_ipsecrequest_len) / 8; + break; + } + + iov_cnt = 0; + + /* header */ + iov[iov_cnt].iov_base = &smsg; + iov[iov_cnt].iov_len = sizeof(smsg); + iov_cnt++; + + /* add flow SA2 */ + iov[iov_cnt].iov_base = &sa_2; + iov[iov_cnt].iov_len = sizeof(sa_2); + smsg.sadb_msg_len += sa_2.sadb_x_sa2_len; + iov_cnt++; + + /* add source address */ + iov[iov_cnt].iov_base = &sa_src; + iov[iov_cnt].iov_len = sizeof(sa_src); + iov_cnt++; + iov[iov_cnt].iov_base = &ssrc; + iov[iov_cnt].iov_len = SS_LEN(&ssrc); + smsg.sadb_msg_len += sa_src.sadb_address_len; + iov_cnt++; + + /* add destination address */ + iov[iov_cnt].iov_base = &sa_dst; + iov[iov_cnt].iov_len = sizeof(sa_dst); + iov_cnt++; + iov[iov_cnt].iov_base = &sdst; + iov[iov_cnt].iov_len = SS_LEN(&sdst); + smsg.sadb_msg_len += sa_dst.sadb_address_len; + iov_cnt++; + + /* add policy extension */ + iov[iov_cnt].iov_base = &sa_policy; + iov[iov_cnt].iov_len = sizeof(sa_policy); + smsg.sadb_msg_len += sa_policy.sadb_x_policy_len; + iov_cnt++; + + if (sa_policy.sadb_x_policy_type == IPSEC_POLICY_IPSEC) { + iov[iov_cnt].iov_base = &sa_ipsec; + iov[iov_cnt].iov_len = sizeof(sa_ipsec); + iov_cnt++; + iov[iov_cnt].iov_base = &slocal; + iov[iov_cnt].iov_len = SS_LEN(&slocal); + iov_cnt++; + iov[iov_cnt].iov_base = &speer; + iov[iov_cnt].iov_len = SS_LEN(&speer); + if (padlen) { + iov_cnt++; + iov[iov_cnt].iov_base = zeropad; + iov[iov_cnt].iov_len = padlen; + } + iov_cnt++; + } + + ret = -1; + if (pfkey_write(sd, &smsg, iov, iov_cnt, &reply, &rlen) != 0) + goto done; + + if ((sa_polid = pfkey_find_ext(reply, rlen, + SADB_X_EXT_POLICY)) == NULL) { + log_debug("%s: erronous reply", __func__); + goto done; + } + flow->flow_id = sa_polid->sadb_x_policy_id; + + log_debug("%s: flow with policy id 0x%x", __func__, flow->flow_id); + ret = 0; done: - free(reply); + free(reply); #endif /* !_OPENBSD_IPSEC_API_VERSION */ - return (ret); + return (ret); } int -pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) +pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) { - struct sadb_msg smsg; - struct sadb_sa sadb; - struct sadb_address sa_src, sa_dst; - struct sadb_key sa_authkey, sa_enckey; - struct sadb_lifetime sa_ltime_hard, sa_ltime_soft; + struct sadb_msg smsg; + struct sadb_sa sadb; + struct sadb_address sa_src, sa_dst; + struct sadb_key sa_authkey, sa_enckey; + struct sadb_lifetime sa_ltime_hard, sa_ltime_soft; #if defined(_OPENBSD_IPSEC_API_VERSION) - struct sadb_x_udpencap udpencap; - struct sadb_x_tag sa_tag; - char *tag = NULL; - struct sadb_x_tap sa_tap; + struct sadb_x_udpencap udpencap; + struct sadb_x_tag sa_tag; + char *tag = NULL; + struct sadb_x_tap sa_tap; #else - struct sadb_x_sa2 sa_2; + struct sadb_x_sa2 sa_2; +#if defined(HAVE_APPLE_NATT) + struct sadb_sa_natt natt; #endif - struct sockaddr_storage ssrc, sdst; - struct sadb_ident *sa_srcid, *sa_dstid; - struct iked_lifetime *lt; - struct iked_policy *pol; - struct iovec iov[IOV_CNT]; - u_int32_t jitter; - int iov_cnt; - - sa_srcid = sa_dstid = NULL; - - if (sa->csa_ikesa == NULL || sa->csa_ikesa->sa_policy == NULL) { - log_warn("%s: invalid SA and policy", __func__); - return (-1); - } - pol = sa->csa_ikesa->sa_policy; - lt = &pol->pol_lifetime; - - bzero(&ssrc, sizeof(ssrc)); - memcpy(&ssrc, &sa->csa_local->addr, sizeof(ssrc)); - if (socket_af((struct sockaddr *)&ssrc, 0) == -1) { - log_warn("%s: invalid address", __func__); - return (-1); - } - - bzero(&sdst, sizeof(sdst)); - memcpy(&sdst, &sa->csa_peer->addr, sizeof(sdst)); - if (socket_af((struct sockaddr *)&sdst, 0) == -1) { - log_warn("%s: invalid address", __func__); - return (-1); - } - - bzero(&smsg, sizeof(smsg)); - smsg.sadb_msg_version = PF_KEY_V2; - smsg.sadb_msg_seq = ++sadb_msg_seq; - smsg.sadb_msg_pid = getpid(); - smsg.sadb_msg_len = sizeof(smsg) / 8; - smsg.sadb_msg_type = action; - smsg.sadb_msg_satype = satype; - - bzero(&sadb, sizeof(sadb)); - sadb.sadb_sa_len = sizeof(sadb) / 8; - sadb.sadb_sa_exttype = SADB_EXT_SA; - sadb.sadb_sa_spi = htonl(sa->csa_spi.spi); - sadb.sadb_sa_state = SADB_SASTATE_MATURE; - sadb.sadb_sa_replay = 64; +#endif + struct sockaddr_storage ssrc, sdst; + struct sadb_ident *sa_srcid, *sa_dstid; + struct iked_lifetime *lt; + struct iked_policy *pol; + struct iovec iov[IOV_CNT]; + u_int32_t jitter; + int iov_cnt; + + sa_srcid = sa_dstid = NULL; + + if (sa->csa_ikesa == NULL || sa->csa_ikesa->sa_policy == NULL) { + log_warn("%s: invalid SA and policy", __func__); + return (-1); + } + pol = sa->csa_ikesa->sa_policy; + lt = &pol->pol_lifetime; + + bzero(&ssrc, sizeof(ssrc)); + memcpy(&ssrc, &sa->csa_local->addr, sizeof(ssrc)); + if (socket_af((struct sockaddr *)&ssrc, 0) == -1) { + log_warn("%s: invalid address", __func__); + return (-1); + } + + bzero(&sdst, sizeof(sdst)); + memcpy(&sdst, &sa->csa_peer->addr, sizeof(sdst)); + if (socket_af((struct sockaddr *)&sdst, 0) == -1) { + log_warn("%s: invalid address", __func__); + return (-1); + } + + bzero(&smsg, sizeof(smsg)); + smsg.sadb_msg_version = PF_KEY_V2; + smsg.sadb_msg_seq = ++sadb_msg_seq; + smsg.sadb_msg_pid = getpid(); + smsg.sadb_msg_len = sizeof(smsg) / 8; + smsg.sadb_msg_type = action; + smsg.sadb_msg_satype = satype; + + bzero(&sadb, sizeof(sadb)); + sadb.sadb_sa_len = sizeof(sadb) / 8; + sadb.sadb_sa_exttype = SADB_EXT_SA; + sadb.sadb_sa_spi = htonl(sa->csa_spi.spi); + sadb.sadb_sa_state = SADB_SASTATE_MATURE; + sadb.sadb_sa_replay = 64; #if defined(_OPENBSD_IPSEC_API_VERSION) - if (!sa->csa_transport) - sadb.sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL; + /* XXX we don't support transport mode, yet */ + sadb.sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL; - if (sa->csa_esn) - sadb.sadb_sa_flags |= SADB_X_SAFLAGS_ESN; + if (sa->csa_esn) + sadb.sadb_sa_flags |= SADB_X_SAFLAGS_ESN; #else - bzero(&sa_2, sizeof(sa_2)); - sa_2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - sa_2.sadb_x_sa2_len = sizeof(sa_2) / 8; - if (!sa->csa_transport) - sa_2.sadb_x_sa2_mode = IPSEC_MODE_TUNNEL; - else - sa_2.sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT; + bzero(&sa_2, sizeof(sa_2)); + sa_2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; + sa_2.sadb_x_sa2_len = sizeof(sa_2) / 8; + sa_2.sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT; /* XXX */ #endif - bzero(&sa_src, sizeof(sa_src)); - sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; - sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + bzero(&sa_src, sizeof(sa_src)); + sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(SS_LEN(&ssrc))) / 8; + sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; - bzero(&sa_dst, sizeof(sa_dst)); - sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; - sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + bzero(&sa_dst, sizeof(sa_dst)); + sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(SS_LEN(&sdst))) / 8; + sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; - bzero(&sa_authkey, sizeof(sa_authkey)); - bzero(&sa_enckey, sizeof(sa_enckey)); + bzero(&sa_authkey, sizeof(sa_authkey)); + bzero(&sa_enckey, sizeof(sa_enckey)); #if defined(_OPENBSD_IPSEC_API_VERSION) - bzero(&udpencap, sizeof udpencap); + bzero(&udpencap, sizeof udpencap); #elif defined(HAVE_APPLE_NATT) - bzero(&natt, sizeof(natt)); + bzero(&natt, sizeof(natt)); #endif - bzero(&sa_ltime_hard, sizeof(sa_ltime_hard)); - bzero(&sa_ltime_soft, sizeof(sa_ltime_soft)); - - if (action == SADB_DELETE) - goto send; - - if ((action == SADB_ADD || action == SADB_UPDATE) && - !sa->csa_persistent && (lt->lt_bytes || lt->lt_seconds)) { - sa_ltime_hard.sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; - sa_ltime_hard.sadb_lifetime_len = sizeof(sa_ltime_hard) / 8; - sa_ltime_hard.sadb_lifetime_bytes = lt->lt_bytes; - sa_ltime_hard.sadb_lifetime_addtime = lt->lt_seconds; - - /* double the lifetime for IP compression */ - if (satype == SADB_X_SATYPE_IPCOMP) - sa_ltime_hard.sadb_lifetime_addtime *= 2; - - sa_ltime_soft.sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; - sa_ltime_soft.sadb_lifetime_len = sizeof(sa_ltime_soft) / 8; - /* set randomly to 85-95% */ - jitter = 850 + arc4random_uniform(100); - sa_ltime_soft.sadb_lifetime_bytes = - (sa_ltime_hard.sadb_lifetime_bytes * jitter) / 1000; - sa_ltime_soft.sadb_lifetime_addtime = - (sa_ltime_hard.sadb_lifetime_addtime * jitter) / 1000; - } - - /* XXX handle NULL encryption or NULL auth or combined encr/auth */ - if (action == SADB_ADD && - !ibuf_length(sa->csa_integrkey) && !ibuf_length(sa->csa_encrkey) && - satype != SADB_X_SATYPE_IPCOMP + bzero(&sa_ltime_hard, sizeof(sa_ltime_hard)); + bzero(&sa_ltime_soft, sizeof(sa_ltime_soft)); + + if (action == SADB_DELETE) + goto send; + + if ((action == SADB_ADD || action == SADB_UPDATE) && + !sa->csa_persistent && (lt->lt_bytes || lt->lt_seconds)) { + sa_ltime_hard.sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; + sa_ltime_hard.sadb_lifetime_len = sizeof(sa_ltime_hard) / 8; + sa_ltime_hard.sadb_lifetime_bytes = lt->lt_bytes; + sa_ltime_hard.sadb_lifetime_addtime = lt->lt_seconds; + + sa_ltime_soft.sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; + sa_ltime_soft.sadb_lifetime_len = sizeof(sa_ltime_soft) / 8; + /* set randomly to 85-95% */ + jitter = 850 + arc4random_uniform(100); + sa_ltime_soft.sadb_lifetime_bytes = + (lt->lt_bytes * jitter) / 1000; + sa_ltime_soft.sadb_lifetime_addtime = + (lt->lt_seconds * jitter) / 1000; + } + + /* XXX handle NULL encryption or NULL auth or combined encr/auth */ + if (action == SADB_ADD && + !ibuf_length(sa->csa_integrkey) && !ibuf_length(sa->csa_encrkey) && + satype != SADB_X_SATYPE_IPCOMP #if defined(_OPENBSD_IPSEC_API_VERSION) - && satype != SADB_X_SATYPE_IPIP + && satype != SADB_X_SATYPE_IPIP #endif - ) { - log_warnx("%s: no key specified", __func__); - return (-1); - } + ) { + + log_warnx("%s: no key specified", __func__); + return (-1); + } - if (satype == SADB_SATYPE_ESP && - sa->csa_ikesa->sa_udpencap && sa->csa_ikesa->sa_natt) { + if (sa->csa_ikesa->sa_udpencap && sa->csa_ikesa->sa_natt) { #if defined(_OPENBSD_IPSEC_API_VERSION) - sadb.sadb_sa_flags |= SADB_X_SAFLAGS_UDPENCAP; - udpencap.sadb_x_udpencap_exttype = SADB_X_EXT_UDPENCAP; - udpencap.sadb_x_udpencap_len = sizeof(udpencap) / 8; - udpencap.sadb_x_udpencap_port = - sa->csa_ikesa->sa_peer.addr_port; - - log_debug("%s: udpencap port %d", __func__, - ntohs(udpencap.sadb_x_udpencap_port)); + sadb.sadb_sa_flags |= SADB_X_SAFLAGS_UDPENCAP; + udpencap.sadb_x_udpencap_exttype = SADB_X_EXT_UDPENCAP; + udpencap.sadb_x_udpencap_len = sizeof(udpencap) / 8; + udpencap.sadb_x_udpencap_port = + sa->csa_ikesa->sa_peer.addr_port; +#elif defined(HAVE_APPLE_NATT) + sadb.sadb_sa_flags |= SADB_X_EXT_NATT; + /* XXX check NAT detection for local/peer hash instead */ + if (sa->csa_dir == IPSP_DIRECTION_OUT) + sadb.sadb_sa_flags |= SADB_X_EXT_NATT_KEEPALIVE; + else + sadb.sadb_sa_flags |= SADB_X_EXT_NATT_DETECTED_PEER; + natt.sadb_sa_natt_port = + ntohs(sa->csa_ikesa->sa_peer.addr_port); #else -#warning PFKEYv2 NAT-T not supported +//#warning PFKEYv2 NAT-T not supported #endif - } - - if (sa->csa_integrid) - if (pfkey_map(pfkey_integr, - sa->csa_integrid, &sadb.sadb_sa_auth) == -1) { - log_warnx("%s: unsupported integrity algorithm %s", - __func__, print_map(sa->csa_integrid, - ikev2_xformauth_map)); - return (-1); - } - - if (sa->csa_encrid) - if (pfkey_map(pfkey_encr, - sa->csa_encrid, &sadb.sadb_sa_encrypt) == -1) { - log_warnx("%s: unsupported encryption algorithm %s", - __func__, print_map(sa->csa_encrid, - ikev2_xformencr_map)); - return (-1); - } - - if (ibuf_length(sa->csa_integrkey)) { - sa_authkey.sadb_key_len = (sizeof(sa_authkey) + - ((ibuf_size(sa->csa_integrkey) + 7) / 8) * 8) / 8; - sa_authkey.sadb_key_exttype = SADB_EXT_KEY_AUTH; - sa_authkey.sadb_key_bits = - 8 * ibuf_size(sa->csa_integrkey); - } - - if (ibuf_length(sa->csa_encrkey)) { - sa_enckey.sadb_key_len = (sizeof(sa_enckey) + - ((ibuf_size(sa->csa_encrkey) + 7) / 8) * 8) / 8; - sa_enckey.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; - sa_enckey.sadb_key_bits = - 8 * ibuf_size(sa->csa_encrkey); - } - - /* we only support deflate */ - if (satype == SADB_X_SATYPE_IPCOMP) - sadb.sadb_sa_encrypt = SADB_X_CALG_DEFLATE; - - /* Note that we need to swap the IDs for incoming SAs (SADB_UPDATE) */ - if (action != SADB_UPDATE) { - sa_srcid = pfkey_id2ident( - IKESA_SRCID(sa->csa_ikesa), SADB_EXT_IDENTITY_SRC); - sa_dstid = pfkey_id2ident( - IKESA_DSTID(sa->csa_ikesa), SADB_EXT_IDENTITY_DST); - } else { - sa_srcid = pfkey_id2ident( - IKESA_DSTID(sa->csa_ikesa), SADB_EXT_IDENTITY_SRC); - sa_dstid = pfkey_id2ident( - IKESA_SRCID(sa->csa_ikesa), SADB_EXT_IDENTITY_DST); - } + log_debug("%s: udpencap port %u", __func__, + ntohs(sa->csa_ikesa->sa_peer.addr_port)); + } + + + if (sa->csa_integrid != 0) + if (pfkey_map(pfkey_integr, + sa->csa_integrid, &sadb.sadb_sa_auth) == -1) { + log_warnx("%s: unsupported integrity algorithm %s", + __func__, print_map(sa->csa_integrid, + ikev2_xformauth_map)); + return (-1); + } + + if (sa->csa_encrid != 0) + if (pfkey_map(pfkey_encr, + sa->csa_encrid, &sadb.sadb_sa_encrypt) == -1) { + log_warnx("%s: unsupported encryption algorithm %s", + __func__, print_map(sa->csa_encrid, + ikev2_xformencr_map)); + return (-1); + } + + if (ibuf_length(sa->csa_integrkey)) { + sa_authkey.sadb_key_len = (sizeof(sa_authkey) + + ((ibuf_size(sa->csa_integrkey) + 7) / 8) * 8) / 8; + sa_authkey.sadb_key_exttype = SADB_EXT_KEY_AUTH; + sa_authkey.sadb_key_bits = + 8 * ibuf_size(sa->csa_integrkey); + } + + if (ibuf_length(sa->csa_encrkey)) { + sa_enckey.sadb_key_len = (sizeof(sa_enckey) + + ((ibuf_size(sa->csa_encrkey) + 7) / 8) * 8) / 8; + sa_enckey.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; + sa_enckey.sadb_key_bits = + 8 * ibuf_size(sa->csa_encrkey); + } + + /* local id */ + sa_srcid = pfkey_id2ident(IKESA_SRCID(sa->csa_ikesa), SADB_EXT_IDENTITY_SRC); + /* peer id */ + sa_dstid = pfkey_id2ident(IKESA_DSTID(sa->csa_ikesa), SADB_EXT_IDENTITY_DST); #if defined(_OPENBSD_IPSEC_API_VERSION) - tag = sa->csa_ikesa->sa_tag; - if (tag != NULL && *tag != '\0') { - bzero(&sa_tag, sizeof(sa_tag)); - sa_tag.sadb_x_tag_exttype = SADB_X_EXT_TAG; - sa_tag.sadb_x_tag_len = - (ROUNDUP(strlen(tag) + 1) + sizeof(sa_tag)) / 8; - sa_tag.sadb_x_tag_taglen = strlen(tag) + 1; - } else - tag = NULL; - - if (pol->pol_tap != 0) { - bzero(&sa_tap, sizeof(sa_tap)); - sa_tap.sadb_x_tap_exttype = SADB_X_EXT_TAP; - sa_tap.sadb_x_tap_len = sizeof(sa_tap) / 8; - sa_tap.sadb_x_tap_unit = pol->pol_tap; - } + tag = sa->csa_ikesa->sa_tag; + if (tag != NULL && *tag != '\0') { + bzero(&sa_tag, sizeof(sa_tag)); + sa_tag.sadb_x_tag_exttype = SADB_X_EXT_TAG; + sa_tag.sadb_x_tag_len = + (ROUNDUP(strlen(tag) + 1) + sizeof(sa_tag)) / 8; + sa_tag.sadb_x_tag_taglen = strlen(tag) + 1; + } else + tag = NULL; + + if (pol->pol_tap != 0) { + bzero(&sa_tap, sizeof(sa_tap)); + sa_tap.sadb_x_tap_exttype = SADB_X_EXT_TAP; + sa_tap.sadb_x_tap_len = sizeof(sa_tap) / 8; + sa_tap.sadb_x_tap_unit = pol->pol_tap; + } #endif send: - iov_cnt = 0; - - /* header */ - iov[iov_cnt].iov_base = &smsg; - iov[iov_cnt].iov_len = sizeof(smsg); - iov_cnt++; - - /* sa */ - iov[iov_cnt].iov_base = &sadb; - iov[iov_cnt].iov_len = sizeof(sadb); - smsg.sadb_msg_len += sadb.sadb_sa_len; - iov_cnt++; - - /* src addr */ - iov[iov_cnt].iov_base = &sa_src; - iov[iov_cnt].iov_len = sizeof(sa_src); - iov_cnt++; - iov[iov_cnt].iov_base = &ssrc; - iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); - smsg.sadb_msg_len += sa_src.sadb_address_len; - iov_cnt++; - - /* dst addr */ - iov[iov_cnt].iov_base = &sa_dst; - iov[iov_cnt].iov_len = sizeof(sa_dst); - iov_cnt++; - iov[iov_cnt].iov_base = &sdst; - iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); - smsg.sadb_msg_len += sa_dst.sadb_address_len; - iov_cnt++; - - if (sa_ltime_soft.sadb_lifetime_len) { - /* soft lifetime */ - iov[iov_cnt].iov_base = &sa_ltime_soft; - iov[iov_cnt].iov_len = sizeof(sa_ltime_soft); - smsg.sadb_msg_len += sa_ltime_soft.sadb_lifetime_len; - iov_cnt++; - } - - if (sa_ltime_hard.sadb_lifetime_len) { - /* hard lifetime */ - iov[iov_cnt].iov_base = &sa_ltime_hard; - iov[iov_cnt].iov_len = sizeof(sa_ltime_hard); - smsg.sadb_msg_len += sa_ltime_hard.sadb_lifetime_len; - iov_cnt++; - } + iov_cnt = 0; + + /* header */ + iov[iov_cnt].iov_base = &smsg; + iov[iov_cnt].iov_len = sizeof(smsg); + iov_cnt++; + + /* sa */ + iov[iov_cnt].iov_base = &sadb; + iov[iov_cnt].iov_len = sizeof(sadb); +#if defined(HAVE_APPLE_NATT) + if (natt.sadb_sa_natt_port) { + iov_cnt++; + iov[iov_cnt].iov_base = &natt; + iov[iov_cnt].iov_len = sizeof(natt); + sadb.sadb_sa_len += sizeof(natt) / 8; + } +#endif + smsg.sadb_msg_len += sadb.sadb_sa_len; + iov_cnt++; + +#if !defined(_OPENBSD_IPSEC_API_VERSION) + /* sa2 */ + iov[iov_cnt].iov_base = &sa_2; + iov[iov_cnt].iov_len = sizeof(sa_2); + smsg.sadb_msg_len += sa_2.sadb_x_sa2_len; + iov_cnt++; +#endif - if (udpencap.sadb_x_udpencap_len) { - iov[iov_cnt].iov_base = &udpencap; - iov[iov_cnt].iov_len = sizeof(udpencap); - smsg.sadb_msg_len += udpencap.sadb_x_udpencap_len; - iov_cnt++; - } + /* src addr */ + iov[iov_cnt].iov_base = &sa_src; + iov[iov_cnt].iov_len = sizeof(sa_src); + iov_cnt++; + iov[iov_cnt].iov_base = &ssrc; + iov[iov_cnt].iov_len = ROUNDUP(SS_LEN(&ssrc)); + smsg.sadb_msg_len += sa_src.sadb_address_len; + iov_cnt++; + + /* dst addr */ + iov[iov_cnt].iov_base = &sa_dst; + iov[iov_cnt].iov_len = sizeof(sa_dst); + iov_cnt++; + iov[iov_cnt].iov_base = &sdst; + iov[iov_cnt].iov_len = ROUNDUP(SS_LEN(&sdst)); + smsg.sadb_msg_len += sa_dst.sadb_address_len; + iov_cnt++; + + if (sa_ltime_soft.sadb_lifetime_len) { + /* soft lifetime */ + iov[iov_cnt].iov_base = &sa_ltime_soft; + iov[iov_cnt].iov_len = sizeof(sa_ltime_soft); smsg.sadb_msg_len += sa_ltime_soft.sadb_lifetime_len; + iov_cnt++; + } + + if (sa_ltime_hard.sadb_lifetime_len) { + /* hard lifetime */ + iov[iov_cnt].iov_base = &sa_ltime_hard; + iov[iov_cnt].iov_len = sizeof(sa_ltime_hard); + smsg.sadb_msg_len += sa_ltime_hard.sadb_lifetime_len; + iov_cnt++; + } - if (sa_enckey.sadb_key_len) { - /* encryption key */ - iov[iov_cnt].iov_base = &sa_enckey; - iov[iov_cnt].iov_len = sizeof(sa_enckey); - iov_cnt++; - iov[iov_cnt].iov_base = ibuf_data(sa->csa_encrkey); - iov[iov_cnt].iov_len = - ((ibuf_size(sa->csa_encrkey) + 7) / 8) * 8; - smsg.sadb_msg_len += sa_enckey.sadb_key_len; - iov_cnt++; - } - if (sa_authkey.sadb_key_len) { - /* authentication key */ - iov[iov_cnt].iov_base = &sa_authkey; - iov[iov_cnt].iov_len = sizeof(sa_authkey); - iov_cnt++; - iov[iov_cnt].iov_base = ibuf_data(sa->csa_integrkey); - iov[iov_cnt].iov_len = - ((ibuf_size(sa->csa_integrkey) + 7) / 8) * 8; - smsg.sadb_msg_len += sa_authkey.sadb_key_len; - iov_cnt++; - } - - if (sa_srcid) { - /* src identity */ - iov[iov_cnt].iov_base = sa_srcid; - iov[iov_cnt].iov_len = sa_srcid->sadb_ident_len * 8; - smsg.sadb_msg_len += sa_srcid->sadb_ident_len; - iov_cnt++; - } - if (sa_dstid) { - /* dst identity */ - iov[iov_cnt].iov_base = sa_dstid; - iov[iov_cnt].iov_len = sa_dstid->sadb_ident_len * 8; - smsg.sadb_msg_len += sa_dstid->sadb_ident_len; - iov_cnt++; - } +#if defined(_OPENBSD_IPSEC_API_VERSION) + if (udpencap.sadb_x_udpencap_len) { + iov[iov_cnt].iov_base = &udpencap; + iov[iov_cnt].iov_len = sizeof(udpencap); + smsg.sadb_msg_len += udpencap.sadb_x_udpencap_len; + iov_cnt++; + } +#endif - if (tag != NULL) { - /* tag identity */ - iov[iov_cnt].iov_base = &sa_tag; - iov[iov_cnt].iov_len = sizeof(sa_tag); - iov_cnt++; - iov[iov_cnt].iov_base = tag; - iov[iov_cnt].iov_len = ROUNDUP(strlen(tag) + 1); - smsg.sadb_msg_len += sa_tag.sadb_x_tag_len; - iov_cnt++; - } + if (sa_enckey.sadb_key_len) { + /* encryption key */ + iov[iov_cnt].iov_base = &sa_enckey; + iov[iov_cnt].iov_len = sizeof(sa_enckey); + iov_cnt++; + iov[iov_cnt].iov_base = ibuf_data(sa->csa_encrkey); + iov[iov_cnt].iov_len = + ((ibuf_size(sa->csa_encrkey) + 7) / 8) * 8; + smsg.sadb_msg_len += sa_enckey.sadb_key_len; + iov_cnt++; + } + if (sa_authkey.sadb_key_len) { + /* authentication key */ + iov[iov_cnt].iov_base = &sa_authkey; + iov[iov_cnt].iov_len = sizeof(sa_authkey); + iov_cnt++; + iov[iov_cnt].iov_base = ibuf_data(sa->csa_integrkey); iov[iov_cnt].iov_len = + ((ibuf_size(sa->csa_integrkey) + 7) / 8) * 8; + smsg.sadb_msg_len += sa_authkey.sadb_key_len; + iov_cnt++; + } + + if (sa_srcid) { + /* src identity */ + iov[iov_cnt].iov_base = sa_srcid; + iov[iov_cnt].iov_len = sa_srcid->sadb_ident_len * 8; + smsg.sadb_msg_len += sa_srcid->sadb_ident_len; + iov_cnt++; + } + if (sa_dstid) { + /* dst identity */ + iov[iov_cnt].iov_base = sa_dstid; + iov[iov_cnt].iov_len = sa_dstid->sadb_ident_len * 8; + smsg.sadb_msg_len += sa_dstid->sadb_ident_len; + iov_cnt++; + } - if (pol->pol_tap != 0) { - /* enc(4) device tap unit */ - iov[iov_cnt].iov_base = &sa_tap; - iov[iov_cnt].iov_len = sizeof(sa_tap); - smsg.sadb_msg_len += sa_tap.sadb_x_tap_len; - iov_cnt++; - } +#if defined(_OPENBSD_IPSEC_API_VERSION) + if (tag != NULL) { + /* tag identity */ + iov[iov_cnt].iov_base = &sa_tag; + iov[iov_cnt].iov_len = sizeof(sa_tag); + iov_cnt++; + iov[iov_cnt].iov_base = tag; + iov[iov_cnt].iov_len = ROUNDUP(strlen(tag) + 1); + smsg.sadb_msg_len += sa_tag.sadb_x_tag_len; + iov_cnt++; + } + + if (pol->pol_tap != 0) { + /* enc(4) device tap unit */ + iov[iov_cnt].iov_base = &sa_tap; + iov[iov_cnt].iov_len = sizeof(sa_tap); + smsg.sadb_msg_len += sa_tap.sadb_x_tap_len; + iov_cnt++; + } +#endif - return (pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL)); + return (pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL)); } +#if defined(_OPENBSD_IPSEC_API_VERSION) int pfkey_sa_last_used(int sd, struct iked_childsa *sa, u_int64_t *last_used) { @@ -1079,6 +1110,7 @@ pfkey_sa_last_used(int sd, struct iked_childsa *sa, u_int64_t *last_used) free(data); return (ret); } +#endif int pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, @@ -1120,8 +1152,7 @@ pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, sa_spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE; sa_spirange.sadb_spirange_len = sizeof(sa_spirange) / 8; sa_spirange.sadb_spirange_min = 0x100; - sa_spirange.sadb_spirange_max = (satype == SADB_X_SATYPE_IPCOMP) ? - (CPI_PRIVATE_MIN - 1) : 0xffffffff; + sa_spirange.sadb_spirange_max = 0xffffffff; sa_spirange.sadb_spirange_reserved = 0; bzero(&sa_src, sizeof(sa_src)); @@ -1188,6 +1219,7 @@ pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, return (ret); } +#if defined(_OPENBSD_IPSEC_API_VERSION) int pfkey_sagroup(int sd, u_int8_t satype1, u_int8_t action, struct iked_childsa *sa1, struct iked_childsa *sa2) @@ -1300,6 +1332,7 @@ pfkey_sagroup(int sd, u_int8_t satype1, u_int8_t action, return (pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL)); } +#endif int pfkey_write(int sd, struct sadb_msg *smsg, struct iovec *iov, int iov_cnt, @@ -1558,11 +1591,13 @@ pfkey_sa_add(int fd, struct iked_childsa *sa, struct iked_childsa *last) } if (last && cmd == SADB_ADD) { +#if defined(_OPENBSD_IPSEC_API_VERSION) if (pfkey_sagroup(fd, satype, SADB_X_GRPSPIS, sa, last) == -1) { (void)pfkey_sa_delete(fd, sa); return (-1); } +#endif } sa->csa_loaded = 1; @@ -1822,256 +1857,282 @@ pfkey_timer_cb(int unused, short event, void *arg) evtimer_add(&pfkey_timer_ev, &pfkey_timer_tv); } -/* - * pfkey_process returns 0 if the message has been processed and -1 if - * the system is busy and the the message should be passed again, later. - */ int pfkey_process(struct iked *env, struct pfkey_message *pm) { - struct iked_spi spi; - struct sadb_sa *sa; - struct sadb_lifetime *sa_ltime; - struct sadb_msg *hdr; + struct iked_spi spi; + struct sadb_sa *sa; + struct sadb_lifetime *sa_ltime; + struct sadb_msg *hdr; #if defined(_OPENBSD_IPSEC_API_VERSION) - struct sadb_msg smsg; - struct iked_addr peer; - struct iked_flow flow; - struct sadb_address *sa_addr; - struct sadb_protocol *sa_proto; - struct sadb_x_policy sa_pol; - struct sockaddr *ssrc, *sdst, *smask, *dmask, *speer; - struct iovec iov[IOV_CNT]; - int ret = 0, iov_cnt, sd; - u_int8_t *reply; - ssize_t rlen; - const char *errmsg = NULL; + struct sadb_msg smsg; + struct iked_addr peer; + struct iked_flow flow; + struct sadb_address *sa_addr; + struct sadb_protocol *sa_proto; + struct sadb_x_policy sa_pol; + struct sadb_x_sa2 sa_2; + struct sockaddr *ssrc, *sdst, *smask, *dmask, *speer; + struct iovec iov[IOV_CNT]; + int iov_cnt, sd = env->sc_pfkey; + u_int8_t *reply; + ssize_t rlen; + const char *errmsg = NULL; #else - struct iked_addr peer; - struct sadb_address *sa_addr; - struct sockaddr_storage *speer; - struct sadb_x_policy *sa_pol; - struct iked_flow *flow; + struct iked_addr peer; + struct sadb_address *sa_addr; + struct sockaddr *speer; + struct sadb_x_policy *sa_pol; + struct iked_flow flow; + struct sockaddr *ssrc, *sdst; #endif - u_int8_t *data = pm->pm_data; - ssize_t len = pm->pm_length; - size_t slen; - - if (!env || !data || !len) - return (0); + u_int8_t *data = pm->pm_data; + ssize_t len = pm->pm_length; + + if (!env || !data || !len) + return 0; + + hdr = (struct sadb_msg *)data; + + switch (hdr->sadb_msg_type) { + case SADB_ACQUIRE: + /* Get peer from the acquire message */ + if ((sa_addr = pfkey_find_ext(data, len, + SADB_EXT_ADDRESS_DST)) == NULL) { + log_debug("%s: no peer address", __func__); + return 0; + } + speer = (struct sockaddr *)(sa_addr + 1); + //speer = (struct sockaddr_storage *)(sa_addr + 1); + bzero(&peer, sizeof(peer)); + peer.addr_af = speer->sa_family; + peer.addr_port = htons(socket_getport(speer)); + memcpy(&peer.addr, speer, sizeof(*speer)); + if (socket_af((struct sockaddr *)&peer.addr, + peer.addr_port) == -1) { + log_debug("%s: invalid address", __func__); + return 0; + } + log_debug("%s: acquire request (peer %s)", __func__, + print_host(speer, NULL, 0)); - sd = env->sc_pfkey; - hdr = (struct sadb_msg *)data; - - switch (hdr->sadb_msg_type) { - case SADB_ACQUIRE: - bzero(&flow, sizeof(flow)); - bzero(&peer, sizeof(peer)); - - if ((sa_addr = pfkey_find_ext(data, len, - SADB_EXT_ADDRESS_DST)) == NULL) { - log_debug("%s: no peer address", __func__); - return (0); - } - speer = (struct sockaddr *)(sa_addr + 1); - peer.addr_af = speer->sa_family; - peer.addr_port = htons(socket_getport(speer)); - if ((slen = speer->sa_len) > sizeof(peer.addr)) { - log_debug("%s: invalid peer address len", __func__); - return (0); - } - memcpy(&peer.addr, speer, slen); - if (socket_af((struct sockaddr *)&peer.addr, - peer.addr_port) == -1) { - log_debug("%s: invalid address", __func__); - return (0); - } - flow.flow_peer = &peer; - - log_debug("%s: acquire request (peer %s)", __func__, - print_host(speer, NULL, 0)); - - /* get the matching flow */ - bzero(&smsg, sizeof(smsg)); - smsg.sadb_msg_version = PF_KEY_V2; - smsg.sadb_msg_seq = ++sadb_msg_seq; - smsg.sadb_msg_pid = getpid(); - smsg.sadb_msg_len = sizeof(smsg) / 8; - smsg.sadb_msg_type = SADB_X_ASKPOLICY; - - iov_cnt = 0; - - iov[iov_cnt].iov_base = &smsg; - iov[iov_cnt].iov_len = sizeof(smsg); - iov_cnt++; - - bzero(&sa_pol, sizeof(sa_pol)); - sa_pol.sadb_x_policy_exttype = SADB_X_EXT_POLICY; - sa_pol.sadb_x_policy_len = sizeof(sa_pol) / 8; - sa_pol.sadb_x_policy_seq = hdr->sadb_msg_seq; - - iov[iov_cnt].iov_base = &sa_pol; - iov[iov_cnt].iov_len = sizeof(sa_pol); - smsg.sadb_msg_len += sizeof(sa_pol) / 8; - iov_cnt++; - - if (pfkey_write(sd, &smsg, iov, iov_cnt, &reply, &rlen)) { - log_warnx("%s: failed to get a policy", __func__); - return (0); - } - - if ((sa_addr = pfkey_find_ext(reply, rlen, - SADB_X_EXT_SRC_FLOW)) == NULL) { - errmsg = "flow source address"; - goto out; - } - ssrc = (struct sockaddr *)(sa_addr + 1); - flow.flow_src.addr_af = ssrc->sa_family; - flow.flow_src.addr_port = htons(socket_getport(ssrc)); - if ((slen = ssrc->sa_len) > sizeof(flow.flow_src.addr)) { - log_debug("%s: invalid src address len", __func__); - return (0); - } - memcpy(&flow.flow_src.addr, ssrc, slen); - if (socket_af((struct sockaddr *)&flow.flow_src.addr, - flow.flow_src.addr_port) == -1) { - log_debug("%s: invalid address", __func__); - return (0); - } - - if ((sa_addr = pfkey_find_ext(reply, rlen, - SADB_X_EXT_DST_FLOW)) == NULL) { - errmsg = "flow destination address"; - goto out; - } - sdst = (struct sockaddr *)(sa_addr + 1); - flow.flow_dst.addr_af = sdst->sa_family; - flow.flow_dst.addr_port = htons(socket_getport(sdst)); - if ((slen = sdst->sa_len) > sizeof(flow.flow_dst.addr)) { - log_debug("%s: invalid dst address len", __func__); - return (0); - } - memcpy(&flow.flow_dst.addr, sdst, slen); - if (socket_af((struct sockaddr *)&flow.flow_dst.addr, - flow.flow_dst.addr_port) == -1) { - log_debug("%s: invalid address", __func__); - return (0); - } - - if ((sa_addr = pfkey_find_ext(reply, rlen, - SADB_X_EXT_SRC_MASK)) == NULL) { - errmsg = "flow source mask"; - goto out; - } - smask = (struct sockaddr *)(sa_addr + 1); - switch (smask->sa_family) { - case AF_INET: - flow.flow_src.addr_mask = - mask2prefixlen((struct sockaddr *)smask); - if (flow.flow_src.addr_mask != 32) - flow.flow_src.addr_net = 1; - break; - case AF_INET6: - flow.flow_src.addr_mask = - mask2prefixlen6((struct sockaddr *)smask); - if (flow.flow_src.addr_mask != 128) - flow.flow_src.addr_net = 1; - break; - default: - log_debug("%s: bad address family", __func__); - free(reply); - return (0); - } - - if ((sa_addr = pfkey_find_ext(reply, rlen, - SADB_X_EXT_DST_MASK)) == NULL) { - errmsg = "flow destination mask"; - goto out; - } - dmask = (struct sockaddr *)(sa_addr + 1); - switch (dmask->sa_family) { - case AF_INET: - flow.flow_dst.addr_mask = - mask2prefixlen((struct sockaddr *)dmask); - if (flow.flow_src.addr_mask != 32) - flow.flow_src.addr_net = 1; - break; - case AF_INET6: - flow.flow_dst.addr_mask = - mask2prefixlen6((struct sockaddr *)dmask); - if (flow.flow_src.addr_mask != 128) - flow.flow_src.addr_net = 1; - break; - default: - log_debug("%s: bad address family", __func__); - free(reply); - return (0); - } - - if ((sa_proto = pfkey_find_ext(reply, rlen, - SADB_X_EXT_FLOW_TYPE)) == NULL) { - errmsg = "flow protocol"; - goto out; - } - flow.flow_dir = sa_proto->sadb_protocol_direction; - - log_debug("%s: flow %s from %s/%s to %s/%s via %s", __func__, - flow.flow_dir == IPSP_DIRECTION_IN ? "in" : "out", - print_host(ssrc, NULL, 0), print_host(smask, NULL, 0), - print_host(sdst, NULL, 0), print_host(dmask, NULL, 0), - print_host(speer, NULL, 0)); - - ret = ikev2_acquire_sa(env, &flow); +#if defined(_OPENBSD_IPSEC_API_VERSION) + /* Get the matching flow */ + bzero(&flow, sizeof(flow)); + flow.flow_peer = &peer; + + bzero(&smsg, sizeof(smsg)); + smsg.sadb_msg_version = PF_KEY_V2; + smsg.sadb_msg_seq = ++sadb_msg_seq; + smsg.sadb_msg_pid = getpid(); + smsg.sadb_msg_len = sizeof(smsg) / 8; + smsg.sadb_msg_type = SADB_X_ASKPOLICY; + + iov_cnt = 0; + + iov[iov_cnt].iov_base = &smsg; + iov[iov_cnt].iov_len = sizeof(smsg); + iov_cnt++; + + bzero(&sa_pol, sizeof(sa_pol)); + sa_pol.sadb_x_policy_exttype = SADB_X_EXT_POLICY; + sa_pol.sadb_x_policy_len = sizeof(sa_pol) / 8; + sa_pol.sadb_x_policy_seq = hdr->sadb_msg_seq; + + iov[iov_cnt].iov_base = &sa_pol; + iov[iov_cnt].iov_len = sizeof(sa_pol); + smsg.sadb_msg_len += sizeof(sa_pol) / 8; + iov_cnt++; + + if (pfkey_write(sd, &smsg, iov, iov_cnt, &reply, &rlen)) { + log_warnx("%s: failed to get a policy", __func__); + return 0; + } + + if ((sa_addr = pfkey_find_ext(reply, rlen, + SADB_X_EXT_SRC_FLOW)) == NULL) { + errmsg = "flow source address"; + goto out; + } + ssrc = (struct sockaddr_storage *)(sa_addr + 1); + flow.flow_src.addr_af = ssrc->ss_family; + flow.flow_src.addr_port = htons(socket_getport(ssrc)); + memcpy(&flow.flow_src.addr, ssrc, sizeof(*ssrc)); + if (socket_af((struct sockaddr *)&flow.flow_src.addr, + flow.flow_src.addr_port) == -1) { + log_debug("%s: invalid address", __func__); + return 0; + } + + if ((sa_addr = pfkey_find_ext(reply, rlen, + SADB_X_EXT_DST_FLOW)) == NULL) { + errmsg = "flow destination address"; + goto out; + } + sdst = (struct sockaddr_storage *)(sa_addr + 1); + flow.flow_dst.addr_af = sdst->ss_family; + flow.flow_dst.addr_port = htons(socket_getport(sdst)); + memcpy(&flow.flow_dst.addr, sdst, sizeof(*sdst)); + if (socket_af((struct sockaddr *)&flow.flow_dst.addr, + flow.flow_dst.addr_port) == -1) { + log_debug("%s: invalid address", __func__); + return 0; + } + + if ((sa_addr = pfkey_find_ext(reply, rlen, + SADB_X_EXT_SRC_MASK)) == NULL) { + errmsg = "flow source mask"; + goto out; + } + smask = (struct sockaddr_storage *)(sa_addr + 1); + switch (smask->ss_family) { + case AF_INET: + flow.flow_src.addr_mask = + mask2prefixlen((struct sockaddr *)smask); + if (flow.flow_src.addr_mask != 32) + flow.flow_src.addr_net = 1; + break; + case AF_INET6: + flow.flow_src.addr_mask = + mask2prefixlen6((struct sockaddr *)smask); + if (flow.flow_src.addr_mask != 128) + flow.flow_src.addr_net = 1; + break; + default: + log_debug("%s: bad address family", __func__); + free(reply); + return 0; + } + + if ((sa_addr = pfkey_find_ext(reply, rlen, + SADB_X_EXT_DST_MASK)) == NULL) { + errmsg = "flow destination mask"; + goto out; + } + dmask = (struct sockaddr_storage *)(sa_addr + 1); + switch (dmask->ss_family) { + case AF_INET: + flow.flow_dst.addr_mask = + mask2prefixlen((struct sockaddr *)dmask); + if (flow.flow_src.addr_mask != 32) + flow.flow_src.addr_net = 1; + break; + case AF_INET6: + flow.flow_dst.addr_mask = + mask2prefixlen6((struct sockaddr *)dmask); + if (flow.flow_src.addr_mask != 128) + flow.flow_src.addr_net = 1; + break; + default: + log_debug("%s: bad address family", __func__); + free(reply); + return 0; + } + + if ((sa_proto = pfkey_find_ext(reply, rlen, + SADB_X_EXT_FLOW_TYPE)) == NULL) { + errmsg = "flow protocol"; + goto out; + } + flow.flow_dir = sa_proto->sadb_protocol_direction; + + log_debug("%s: flow %s from %s/%s to %s/%s via %s", __func__, + flow.flow_dir == IPSP_DIRECTION_IN ? "in" : "out", + print_host(ssrc, NULL, 0), print_host(smask, NULL, 0), + print_host(sdst, NULL, 0), print_host(dmask, NULL, 0), + print_host(speer, NULL, 0)); + + ret = ikev2_acquire_sa(env, &flow); out: - if (errmsg) - log_warnx("%s: %s wasn't found", __func__, errmsg); - free(reply); - break; - - case SADB_EXPIRE: - if ((sa = pfkey_find_ext(data, len, SADB_EXT_SA)) == NULL) { - log_warnx("%s: SA extension wasn't found", __func__); - return (0); - } - if ((sa_ltime = pfkey_find_ext(data, len, - SADB_EXT_LIFETIME_SOFT)) == NULL && - (sa_ltime = pfkey_find_ext(data, len, - SADB_EXT_LIFETIME_HARD)) == NULL) { - log_warnx("%s: lifetime extension wasn't found", - __func__); - return (0); - } - spi.spi = ntohl(sa->sadb_sa_spi); - spi.spi_size = 4; - switch (hdr->sadb_msg_satype) { - case SADB_SATYPE_AH: - spi.spi_protoid = IKEV2_SAPROTO_AH; - break; - case SADB_SATYPE_ESP: - spi.spi_protoid = IKEV2_SAPROTO_ESP; - break; - case SADB_X_SATYPE_IPCOMP: - spi.spi_size = 2; - spi.spi_protoid = IKEV2_SAPROTO_IPCOMP; - break; - default: - log_warnx("%s: unsupported SA type %d spi %s", - __func__, hdr->sadb_msg_satype, - print_spi(spi.spi, spi.spi_size)); - return (0); - } - - log_debug("%s: SA %s is expired, pending %s", __func__, - print_spi(spi.spi, spi.spi_size), - sa_ltime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT ? - "rekeying" : "deletion"); - - if (sa_ltime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT) - ret = ikev2_rekey_sa(env, &spi); - else - ret = ikev2_drop_sa(env, &spi); - break; - } - return (ret); + if (errmsg) + log_warnx("%s: %s wasn't found", __func__, errmsg); + free(reply); +#elif defined(SADB_X_EXT_POLICY) + /* + * On an upcall from the kernel, reconstruct iked_flow with src + * and dest in upcall message. Then proceed onto establish SA + */ + bzero(&flow, sizeof(flow)); + flow.flow_peer = &peer; + flow.flow_dst = peer; + if (flow.flow_dst.addr_af == AF_INET) { + flow.flow_dst.addr_mask = 32; + } + if ((sa_pol = pfkey_find_ext(data, len, + SADB_X_EXT_POLICY)) == NULL) { + log_debug("%s: no policy extension", __func__); + return 0; + } + + if ((sa_addr = pfkey_find_ext(data, len, + SADB_EXT_ADDRESS_SRC)) == NULL) { + log_debug("%s: no src in ext_policy upcall", __func__); + return 0; + } + ssrc = (struct sockaddr*)(sa_addr + 1); + flow.flow_src.addr_af = ssrc->sa_family; + flow.flow_src.addr_port = htons(socket_getport(ssrc)); + if (flow.flow_src.addr_af == AF_INET) { + flow.flow_src.addr_mask = 32; + } + memcpy(&flow.flow_src.addr, ssrc, sizeof(*ssrc)); + if (socket_af((struct sockaddr *)&flow.flow_src.addr, + flow.flow_src.addr_port) == -1) { + log_debug("%s: invalid address", __func__); + return 0; + } + + log_debug("%s: flow %s from to %s ", __func__, + print_host((struct sockaddr*)&(flow.flow_src.addr), NULL, 0), + print_host((struct sockaddr*)&(flow.flow_dst.addr), NULL, 0)); + ikev2_acquire_sa(env, &flow); +#else +#warning PFKEYv2 SADB_ACQUIRE not implemented + log_debug("%s: SADB_ACQUIRE not yet supported here, ignored", + __func__); +#endif + break; + + case SADB_EXPIRE: + if ((sa = pfkey_find_ext(data, len, SADB_EXT_SA)) == NULL) { + log_warnx("%s: SA extension wasn't found", __func__); + return 0; + } + if ((sa_ltime = pfkey_find_ext(data, len, + SADB_EXT_LIFETIME_SOFT)) == NULL && + (sa_ltime = pfkey_find_ext(data, len, + SADB_EXT_LIFETIME_HARD)) == NULL) { + log_warnx("%s: lifetime extension wasn't found", + __func__); + return 0; + } + spi.spi = ntohl(sa->sadb_sa_spi); + spi.spi_size = 4; + switch (hdr->sadb_msg_satype) { + case SADB_SATYPE_AH: + spi.spi_protoid = IKEV2_SAPROTO_AH; + break; + case SADB_SATYPE_ESP: + spi.spi_protoid = IKEV2_SAPROTO_ESP; + break; + default: + log_warnx("%s: usupported SA type %d spi %s", + __func__, hdr->sadb_msg_satype, + print_spi(spi.spi, spi.spi_size)); + return 0; + } + + log_debug("%s: SA %s is expired, pending %s", __func__, + print_spi(spi.spi, spi.spi_size), + sa_ltime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT ? + "rekeying" : "deletion"); + + if (sa_ltime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT) + ikev2_rekey_sa(env, &spi); + else + ikev2_drop_sa(env, &spi); + break; + } + return 0; } diff --git a/iked/policy.c b/iked/policy.c index 86087ef..eb3c707 100644 --- a/iked/policy.c +++ b/iked/policy.c @@ -95,6 +95,42 @@ policy_lookup(struct iked *env, struct iked_message *msg) return (0); } +/* + * Check if host is in a subnet + */ +bool is_in_subnet(struct sockaddr_in* host, struct sockaddr_in* subnet, + u_int8_t subnet_mask) { + uint32_t host_addr = ntohl(host->sin_addr.s_addr); + uint32_t subnet_addr = ntohl(subnet->sin_addr.s_addr); + + unsigned int mask = 0xFFFFFFFF << (32 - subnet_mask); + return ((host_addr & mask) == (subnet_addr & mask)); +} + +bool isipv4_flow_and_policy(struct iked_addr fsrc, struct iked_addr fdst, + struct iked_addr psrc, struct iked_addr pdst) { + return (fsrc.addr_af == AF_INET) && (fdst.addr_af == AF_INET) && + (psrc.addr_af == AF_INET) && (pdst.addr_af == AF_INET); +} + +/* + * Rules/Configuration Policies in iked.conf are subnet based. + * This routinue checks if an incoming flow matches a preconfigured + * policy in the config + */ +bool flow_matches_policy(struct iked_addr fsrc, struct iked_addr fdst, + struct iked_addr psrc, struct iked_addr pdst) { + + struct sockaddr_in *fsrc_addr, *psrc_addr, *fdst_addr, *pdst_addr; + fsrc_addr = (struct sockaddr_in*)&(fsrc.addr); + psrc_addr = (struct sockaddr_in*)&(psrc.addr); + fdst_addr = (struct sockaddr_in*)&(fdst.addr); + pdst_addr = (struct sockaddr_in*)&(pdst.addr); + return (isipv4_flow_and_policy(fsrc, fdst, psrc, pdst) && + is_in_subnet(fsrc_addr, psrc_addr, psrc.addr_mask) && + is_in_subnet(fdst_addr, pdst_addr, pdst.addr_mask)); +} + struct iked_policy * policy_test(struct iked *env, struct iked_policy *key) { @@ -128,13 +164,31 @@ policy_test(struct iked *env, struct iked_policy *key) * and find a matching flow. */ if (key->pol_nflows && - (flowkey = RB_MIN(iked_flows, - &key->pol_flows)) != NULL && - (flow = RB_FIND(iked_flows, &p->pol_flows, - flowkey)) == NULL) { - p = TAILQ_NEXT(p, pol_entry); - continue; - } + (flowkey = RB_MIN(iked_flows, + &key->pol_flows)) != NULL) { + bool match = false; + struct iked_addr psrc, pdst, fsrc, fdst; + /* + * Check if incoming flow from kernel upcall + * matches any of the configuration policies + * or rules specified in iked.conf + */ + RB_FOREACH(flow, iked_flows, &p->pol_flows) { + psrc = flow->flow_src; + pdst = flow->flow_dst; + fsrc = flowkey->flow_src; + fdst = flowkey->flow_dst; + if (flow_matches_policy(fsrc, fdst, + psrc, pdst)) { + match = true; + break; + } + } + if (!match) { + p = TAILQ_NEXT(p, pol_entry); + continue; + } + } /* make sure the peer ID matches */ if (key->pol_peerid.id_type && (key->pol_peerid.id_type != p->pol_peerid.id_type || diff --git a/iked/smult_curve25519_ref.c b/iked/smult_curve25519_ref.c new file mode 100644 index 0000000..4c65eb5 --- /dev/null +++ b/iked/smult_curve25519_ref.c @@ -0,0 +1,265 @@ +/* $OpenBSD: smult_curve25519_ref.c,v 1.1 2014/08/27 10:28:57 reyk Exp $ */ +/* +version 20081011 +Matthew Dempsky +Public domain. +Derived from public domain code by D. J. Bernstein. +*/ + +int crypto_scalarmult_curve25519(unsigned char *, const unsigned char *, const unsigned char *); + +static void add(unsigned int out[32],const unsigned int a[32],const unsigned int b[32]) +{ + unsigned int j; + unsigned int u; + u = 0; + for (j = 0;j < 31;++j) { u += a[j] + b[j]; out[j] = u & 255; u >>= 8; } + u += a[31] + b[31]; out[31] = u; +} + +static void sub(unsigned int out[32],const unsigned int a[32],const unsigned int b[32]) +{ + unsigned int j; + unsigned int u; + u = 218; + for (j = 0;j < 31;++j) { + u += a[j] + 65280 - b[j]; + out[j] = u & 255; + u >>= 8; + } + u += a[31] - b[31]; + out[31] = u; +} + +static void squeeze(unsigned int a[32]) +{ + unsigned int j; + unsigned int u; + u = 0; + for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; } + u += a[31]; a[31] = u & 127; + u = 19 * (u >> 7); + for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; } + u += a[31]; a[31] = u; +} + +static const unsigned int minusp[32] = { + 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128 +} ; + +static void freeze(unsigned int a[32]) +{ + unsigned int aorig[32]; + unsigned int j; + unsigned int negative; + + for (j = 0;j < 32;++j) aorig[j] = a[j]; + add(a,a,minusp); + negative = -((a[31] >> 7) & 1); + for (j = 0;j < 32;++j) a[j] ^= negative & (aorig[j] ^ a[j]); +} + +static void mult(unsigned int out[32],const unsigned int a[32],const unsigned int b[32]) +{ + unsigned int i; + unsigned int j; + unsigned int u; + + for (i = 0;i < 32;++i) { + u = 0; + for (j = 0;j <= i;++j) u += a[j] * b[i - j]; + for (j = i + 1;j < 32;++j) u += 38 * a[j] * b[i + 32 - j]; + out[i] = u; + } + squeeze(out); +} + +static void mult121665(unsigned int out[32],const unsigned int a[32]) +{ + unsigned int j; + unsigned int u; + + u = 0; + for (j = 0;j < 31;++j) { u += 121665 * a[j]; out[j] = u & 255; u >>= 8; } + u += 121665 * a[31]; out[31] = u & 127; + u = 19 * (u >> 7); + for (j = 0;j < 31;++j) { u += out[j]; out[j] = u & 255; u >>= 8; } + u += out[j]; out[j] = u; +} + +static void square(unsigned int out[32],const unsigned int a[32]) +{ + unsigned int i; + unsigned int j; + unsigned int u; + + for (i = 0;i < 32;++i) { + u = 0; + for (j = 0;j < i - j;++j) u += a[j] * a[i - j]; + for (j = i + 1;j < i + 32 - j;++j) u += 38 * a[j] * a[i + 32 - j]; + u *= 2; + if ((i & 1) == 0) { + u += a[i / 2] * a[i / 2]; + u += 38 * a[i / 2 + 16] * a[i / 2 + 16]; + } + out[i] = u; + } + squeeze(out); +} + +static void smult_select(unsigned int p[64],unsigned int q[64],const unsigned int r[64],const unsigned int s[64],unsigned int b) +{ + unsigned int j; + unsigned int t; + unsigned int bminus1; + + bminus1 = b - 1; + for (j = 0;j < 64;++j) { + t = bminus1 & (r[j] ^ s[j]); + p[j] = s[j] ^ t; + q[j] = r[j] ^ t; + } +} + +static void mainloop(unsigned int work[64],const unsigned char e[32]) +{ + unsigned int xzm1[64]; + unsigned int xzm[64]; + unsigned int xzmb[64]; + unsigned int xzm1b[64]; + unsigned int xznb[64]; + unsigned int xzn1b[64]; + unsigned int a0[64]; + unsigned int a1[64]; + unsigned int b0[64]; + unsigned int b1[64]; + unsigned int c1[64]; + unsigned int r[32]; + unsigned int s[32]; + unsigned int t[32]; + unsigned int u[32]; + unsigned int j; + unsigned int b; + int pos; + + for (j = 0;j < 32;++j) xzm1[j] = work[j]; + xzm1[32] = 1; + for (j = 33;j < 64;++j) xzm1[j] = 0; + + xzm[0] = 1; + for (j = 1;j < 64;++j) xzm[j] = 0; + + for (pos = 254;pos >= 0;--pos) { + b = e[pos / 8] >> (pos & 7); + b &= 1; + smult_select(xzmb,xzm1b,xzm,xzm1,b); + add(a0,xzmb,xzmb + 32); + sub(a0 + 32,xzmb,xzmb + 32); + add(a1,xzm1b,xzm1b + 32); + sub(a1 + 32,xzm1b,xzm1b + 32); + square(b0,a0); + square(b0 + 32,a0 + 32); + mult(b1,a1,a0 + 32); + mult(b1 + 32,a1 + 32,a0); + add(c1,b1,b1 + 32); + sub(c1 + 32,b1,b1 + 32); + square(r,c1 + 32); + sub(s,b0,b0 + 32); + mult121665(t,s); + add(u,t,b0); + mult(xznb,b0,b0 + 32); + mult(xznb + 32,s,u); + square(xzn1b,c1); + mult(xzn1b + 32,r,work); + smult_select(xzm,xzm1,xznb,xzn1b,b); + } + + for (j = 0;j < 64;++j) work[j] = xzm[j]; +} + +static void recip(unsigned int out[32],const unsigned int z[32]) +{ + unsigned int z2[32]; + unsigned int z9[32]; + unsigned int z11[32]; + unsigned int z2_5_0[32]; + unsigned int z2_10_0[32]; + unsigned int z2_20_0[32]; + unsigned int z2_50_0[32]; + unsigned int z2_100_0[32]; + unsigned int t0[32]; + unsigned int t1[32]; + int i; + + /* 2 */ square(z2,z); + /* 4 */ square(t1,z2); + /* 8 */ square(t0,t1); + /* 9 */ mult(z9,t0,z); + /* 11 */ mult(z11,z9,z2); + /* 22 */ square(t0,z11); + /* 2^5 - 2^0 = 31 */ mult(z2_5_0,t0,z9); + + /* 2^6 - 2^1 */ square(t0,z2_5_0); + /* 2^7 - 2^2 */ square(t1,t0); + /* 2^8 - 2^3 */ square(t0,t1); + /* 2^9 - 2^4 */ square(t1,t0); + /* 2^10 - 2^5 */ square(t0,t1); + /* 2^10 - 2^0 */ mult(z2_10_0,t0,z2_5_0); + + /* 2^11 - 2^1 */ square(t0,z2_10_0); + /* 2^12 - 2^2 */ square(t1,t0); + /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { square(t0,t1); square(t1,t0); } + /* 2^20 - 2^0 */ mult(z2_20_0,t1,z2_10_0); + + /* 2^21 - 2^1 */ square(t0,z2_20_0); + /* 2^22 - 2^2 */ square(t1,t0); + /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { square(t0,t1); square(t1,t0); } + /* 2^40 - 2^0 */ mult(t0,t1,z2_20_0); + + /* 2^41 - 2^1 */ square(t1,t0); + /* 2^42 - 2^2 */ square(t0,t1); + /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { square(t1,t0); square(t0,t1); } + /* 2^50 - 2^0 */ mult(z2_50_0,t0,z2_10_0); + + /* 2^51 - 2^1 */ square(t0,z2_50_0); + /* 2^52 - 2^2 */ square(t1,t0); + /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { square(t0,t1); square(t1,t0); } + /* 2^100 - 2^0 */ mult(z2_100_0,t1,z2_50_0); + + /* 2^101 - 2^1 */ square(t1,z2_100_0); + /* 2^102 - 2^2 */ square(t0,t1); + /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { square(t1,t0); square(t0,t1); } + /* 2^200 - 2^0 */ mult(t1,t0,z2_100_0); + + /* 2^201 - 2^1 */ square(t0,t1); + /* 2^202 - 2^2 */ square(t1,t0); + /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { square(t0,t1); square(t1,t0); } + /* 2^250 - 2^0 */ mult(t0,t1,z2_50_0); + + /* 2^251 - 2^1 */ square(t1,t0); + /* 2^252 - 2^2 */ square(t0,t1); + /* 2^253 - 2^3 */ square(t1,t0); + /* 2^254 - 2^4 */ square(t0,t1); + /* 2^255 - 2^5 */ square(t1,t0); + /* 2^255 - 21 */ mult(out,t1,z11); +} + +int crypto_scalarmult_curve25519(unsigned char *q, + const unsigned char *n, + const unsigned char *p) +{ + unsigned int work[96]; + unsigned char e[32]; + unsigned int i; + for (i = 0;i < 32;++i) e[i] = n[i]; + e[0] &= 248; + e[31] &= 127; + e[31] |= 64; + for (i = 0;i < 32;++i) work[i] = p[i]; + mainloop(work,e); + recip(work + 32,work + 32); + mult(work + 64,work,work + 32); + freeze(work + 64); + for (i = 0;i < 32;++i) q[i] = work[64 + i]; + return 0; +} diff --git a/iked/timer.c b/iked/timer.c index 01341cb..ca8a631 100644 --- a/iked/timer.c +++ b/iked/timer.c @@ -40,6 +40,11 @@ timer_set(struct iked *env, struct iked_timer *tmr, tmr->tmr_env = env; tmr->tmr_cb = cb; tmr->tmr_cbarg = arg; + + if (evtimer_initialized(&tmr->tmr_ev) && + evtimer_pending(&tmr->tmr_ev, NULL)) { + evtimer_del(&tmr->tmr_ev); + } evtimer_set(&tmr->tmr_ev, timer_callback, tmr); } diff --git a/iked/util.c b/iked/util.c index b7044c0..cdabda5 100644 --- a/iked/util.c +++ b/iked/util.c @@ -118,59 +118,100 @@ socket_getaddr(int s, struct sockaddr_storage *ss) int socket_bypass(int s, struct sockaddr *sa) { - int v, *a; - int a4[] = { - IPPROTO_IP, - IP_AUTH_LEVEL, - IP_ESP_TRANS_LEVEL, - IP_ESP_NETWORK_LEVEL, +#if defined(__OpenBSD__) + int v, *a; + int a4[] = { + IPPROTO_IP, + IP_AUTH_LEVEL, + IP_ESP_TRANS_LEVEL, + IP_ESP_NETWORK_LEVEL, #ifdef IPV6_IPCOMP_LEVEL - IP_IPCOMP_LEVEL + IP_IPCOMP_LEVEL #endif - }; - int a6[] = { - IPPROTO_IPV6, - IPV6_AUTH_LEVEL, - IPV6_ESP_TRANS_LEVEL, - IPV6_ESP_NETWORK_LEVEL, + }; + int a6[] = { + IPPROTO_IPV6, + IPV6_AUTH_LEVEL, + IPV6_ESP_TRANS_LEVEL, + IPV6_ESP_NETWORK_LEVEL, #ifdef IPV6_IPCOMP_LEVEL - IPV6_IPCOMP_LEVEL + IPV6_IPCOMP_LEVEL #endif - }; - - switch (sa->sa_family) { - case AF_INET: - a = a4; - break; - case AF_INET6: - a = a6; - break; - default: - log_warn("%s: invalid address family", __func__); - return (-1); - } - - v = IPSEC_LEVEL_BYPASS; - if (setsockopt(s, a[0], a[1], &v, sizeof(v)) == -1) { - log_warn("%s: AUTH_LEVEL", __func__); - return (-1); - } - if (setsockopt(s, a[0], a[2], &v, sizeof(v)) == -1) { - log_warn("%s: ESP_TRANS_LEVEL", __func__); - return (-1); - } - if (setsockopt(s, a[0], a[3], &v, sizeof(v)) == -1) { - log_warn("%s: ESP_NETWORK_LEVEL", __func__); - return (-1); - } + }; + + switch (sa->sa_family) { + case AF_INET: + a = a4; + break; + case AF_INET6: + a = a6; + break; + default: + log_warn("%s: invalid address family", __func__); + return (-1); + } + v = IPSEC_LEVEL_BYPASS; + if (setsockopt(s, a[0], a[1], &v, sizeof(v)) == -1) { + log_warn("%s: AUTH_LEVEL", __func__); + return (-1); + } + if (setsockopt(s, a[0], a[2], &v, sizeof(v)) == -1) { + log_warn("%s: ESP_TRANS_LEVEL", __func__); + return (-1); + } + if (setsockopt(s, a[0], a[3], &v, sizeof(v)) == -1) { + log_warn("%s: ESP_NETWORK_LEVEL", __func__); + return (-1); + } #ifdef IP_IPCOMP_LEVEL - if (setsockopt(s, a[0], a[4], &v, sizeof(v)) == -1) { - log_warn("%s: IPCOMP_LEVEL", __func__); - return (-1); - } + if (setsockopt(s, a[0], a[4], &v, sizeof(v)) == -1) { + log_warn("%s: IPCOMP_LEVEL", __func__); + return (-1); + } #endif - - return (0); +#else /* __OpenBSD__ */ + int *a; + int a4[] = { + IPPROTO_IP, + IP_IPSEC_POLICY + }; + int a6[] = { + IPPROTO_IPV6, + IPV6_IPSEC_POLICY, + + }; + struct sadb_x_policy pol = { + SADB_UPDATE, + SADB_EXT_SENSITIVITY, + IPSEC_POLICY_BYPASS, + 0, 0, 0, 0 + }; + + switch (sa->sa_family) { + case AF_INET: + a = a4; + break; + case AF_INET6: + a = a6; + break; + default: + log_warn("%s: invalid address family", __func__); + return (-1); + } + + pol.sadb_x_policy_dir = IPSEC_DIR_INBOUND; + if (setsockopt(s, a[0], a[1], &pol, sizeof(pol)) == -1) { + log_warn("%s: IPSEC_DIR_INBOUND", __func__); + return (-1); + } + pol.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND; + if (setsockopt(s, a[0], a[1], &pol, sizeof(pol)) == -1) { + log_warn("%s: IPSEC_DIR_OUTBOUND", __func__); + return (-1); + } +#endif /* !__OpenBSD__ */ + + return (0); } int diff --git a/openbsd-compat/Makefile.am b/openbsd-compat/Makefile.am index 80b5eba..6817048 100644 --- a/openbsd-compat/Makefile.am +++ b/openbsd-compat/Makefile.am @@ -1,13 +1,12 @@ noinst_LIBRARIES= libopenbsd-compat.a libopenbsd_compat_a_SOURCES= \ - bsd-arc4random.c bsd-closefrom.c \ - daemon.c entropy.c fgetln.c getopt.c imsg.c imsg-buffer.c \ - setresguid.c setproctitle.c \ - strlcat.c strlcpy.c strtonum.c vis.c + explicit-bzero.c \ + imsg.c imsg-buffer.c \ + reallocarray.c setresguid.c strtonum.c EXTRA_DIST= defines.h imsg.h includes.h \ - openbsd-compat.h sys-queue.h sys-tree.h vis.h + openbsd-compat.h sys-queue.h sys-tree.h CPPFLAGS= -include $(top_srcdir)/openbsd-compat/includes.h \ -I$(top_srcdir) -I$(top_srcdir)/openbsd-compat \ diff --git a/openbsd-compat/bsd-arc4random.c b/openbsd-compat/bsd-arc4random.c deleted file mode 100644 index a7e562b..0000000 --- a/openbsd-compat/bsd-arc4random.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (c) 1996, David Mazieres - * Copyright (c) 2008, Damien Miller - * Copyright (c) 2013, Markus Friedl - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* - * ChaCha based random number generator for OpenBSD. - */ - -#include "includes.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define KEYSTREAM_ONLY -#include "chacha_private.h" - -#ifdef __GNUC__ -#define inline __inline -#else /* !__GNUC__ */ -#define inline -#endif /* !__GNUC__ */ - -#define KEYSZ 32 -#define IVSZ 8 -#define BLOCKSZ 64 -#define RSBUFSZ (16*BLOCKSZ) -static int rs_initialized; -static pid_t rs_stir_pid; -static chacha_ctx rs; /* chacha context for random keystream */ -static u_char rs_buf[RSBUFSZ]; /* keystream blocks */ -static size_t rs_have; /* valid bytes at end of rs_buf */ -static size_t rs_count; /* bytes till reseed */ - -static inline void _rs_rekey(u_char *dat, size_t datlen); -static inline void _rs_random_buf(void *_buf, size_t n); - -static inline void -_rs_init(u_char *buf, size_t n) -{ - if (n < KEYSZ + IVSZ) - return; - chacha_keysetup(&rs, buf, KEYSZ * 8, 0); - chacha_ivsetup(&rs, buf + KEYSZ); -} - -static void -_rs_stir(void) -{ - size_t len; - u_char rnd[KEYSZ + IVSZ]; - - len = sizeof(rnd); - - _rs_random_buf(rnd, len); - if (!rs_initialized) { - rs_initialized = 1; - _rs_init(rnd, sizeof(rnd)); - } else - _rs_rekey(rnd, sizeof(rnd)); - memset(rnd, 0, sizeof(rnd)); - - /* invalidate rs_buf */ - rs_have = 0; - memset(rs_buf, 0, RSBUFSZ); - - rs_count = 1600000; -} - -static inline void -_rs_stir_if_needed(size_t len) -{ - pid_t pid = getpid(); - - if (rs_count <= len || !rs_initialized || rs_stir_pid != pid) { - rs_stir_pid = pid; - _rs_stir(); - } else - rs_count -= len; -} - -static inline void -_rs_rekey(u_char *dat, size_t datlen) -{ -#ifndef KEYSTREAM_ONLY - memset(rs_buf, 0,RSBUFSZ); -#endif - /* fill rs_buf with the keystream */ - chacha_encrypt_bytes(&rs, rs_buf, rs_buf, RSBUFSZ); - /* mix in optional user provided data */ - if (dat) { - size_t i, m; - - m = MIN(datlen, KEYSZ + IVSZ); - for (i = 0; i < m; i++) - rs_buf[i] ^= dat[i]; - } - /* immediately reinit for backtracking resistance */ - _rs_init(rs_buf, KEYSZ + IVSZ); - memset(rs_buf, 0, KEYSZ + IVSZ); - rs_have = RSBUFSZ - KEYSZ - IVSZ; -} - -static inline void -_rs_random_buf(void *_buf, size_t n) -{ - u_char *buf = (u_char *)_buf; - size_t m; - - while (n > 0) { - if (rs_have > 0) { - m = MIN(n, rs_have); - memcpy(buf, rs_buf + RSBUFSZ - rs_have, m); - memset(rs_buf + RSBUFSZ - rs_have, 0, m); - buf += m; - n -= m; - rs_have -= m; - } - if (rs_have == 0) - _rs_rekey(NULL, 0); - } -} - -static inline void -_rs_random_u32(u_int32_t *val) -{ - _rs_stir_if_needed(sizeof(*val)); - if (rs_have < sizeof(*val)) - _rs_rekey(NULL, 0); - memcpy(val, rs_buf + RSBUFSZ - rs_have, sizeof(*val)); - memset(rs_buf + RSBUFSZ - rs_have, 0, sizeof(*val)); - rs_have -= sizeof(*val); - return; -} - -#ifndef HAVE_ARC4RANDOM -void -arc4random_stir(void) -{ - _rs_stir(); -} - -void -arc4random_addrandom(u_char *dat, int datlen) -{ - int m; - - if (!rs_initialized) - _rs_stir(); - while (datlen > 0) { - m = MIN(datlen, KEYSZ + IVSZ); - _rs_rekey(dat, m); - dat += m; - datlen -= m; - } -} - -u_int32_t -arc4random(void) -{ - u_int32_t val; - - _rs_random_u32(&val); - return val; -} -#endif /* !HAVE_ARC4RANDOM */ - -#ifndef HAVE_ARC4RANDOM_BUF -void -arc4random_buf(void *buf, size_t n) -{ - _rs_stir_if_needed(n); - _rs_random_buf(buf, n); -} -#endif /* !HAVE_ARC4RANDOM_BUF */ - -#ifndef HAVE_ARC4RANDOM_UNIFORM -/* - * Calculate a uniformly distributed random number less than upper_bound - * avoiding "modulo bias". - * - * Uniformity is achieved by generating new random numbers until the one - * returned is outside the range [0, 2**32 % upper_bound). This - * guarantees the selected random number will be inside - * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) - * after reduction modulo upper_bound. - */ -u_int32_t -arc4random_uniform(u_int32_t upper_bound) -{ - u_int32_t r, min; - - if (upper_bound < 2) - return 0; - - /* 2**32 % x == (2**32 - x) % x */ - min = -upper_bound % upper_bound; - - /* - * This could theoretically loop forever but each retry has - * p > 0.5 (worst case, usually far better) of selecting a - * number inside the range we need, so it should rarely need - * to re-roll. - */ - for (;;) { - r = arc4random(); - if (r >= min) - break; - } - - return r % upper_bound; -} -#endif /* !HAVE_ARC4RANDOM_UNIFORM */ diff --git a/openbsd-compat/bsd-closefrom.c b/openbsd-compat/bsd-closefrom.c deleted file mode 100644 index 8598970..0000000 --- a/openbsd-compat/bsd-closefrom.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2004-2005 Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "includes.h" - -#ifndef HAVE_CLOSEFROM - -#include -#include -#include -#include -#ifdef HAVE_FCNTL_H -# include -#endif -#include -#include -#include -#include -#include - -#if 0 -__unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $"; -#endif /* lint */ - -/* - * Close all file descriptors greater than or equal to lowfd. - */ -#ifdef HAVE_FCNTL_CLOSEM -void -closefrom(int lowfd) -{ - (void) fcntl(lowfd, F_CLOSEM, 0); -} -#else -void -closefrom(int lowfd) -{ - long fd, maxfd; -#if defined(HAVE_DIRFD) && defined(HAVE_PROC_PID) - char fdpath[PATH_MAX], *endp; - struct dirent *dent; - DIR *dirp; - int len; - - /* Check for a /proc/$$/fd directory. */ - len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid()); - if (len > 0 && (size_t)len <= sizeof(fdpath) && (dirp = opendir(fdpath))) { - while ((dent = readdir(dirp)) != NULL) { - fd = strtol(dent->d_name, &endp, 10); - if (dent->d_name != endp && *endp == '\0' && - fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp)) - (void) close((int) fd); - } - (void) closedir(dirp); - } else -#endif - { - /* - * Fall back on sysconf() or getdtablesize(). We avoid checking - * resource limits since it is possible to open a file descriptor - * and then drop the rlimit such that it is below the open fd. - */ -#ifdef HAVE_SYSCONF - maxfd = sysconf(_SC_OPEN_MAX); -#else - maxfd = getdtablesize(); -#endif /* HAVE_SYSCONF */ - if (maxfd < 0) - maxfd = OPEN_MAX; - - for (fd = lowfd; fd < maxfd; fd++) - (void) close((int) fd); - } -} -#endif /* !HAVE_FCNTL_CLOSEM */ -#endif /* HAVE_CLOSEFROM */ diff --git a/openbsd-compat/chacha_private.h b/openbsd-compat/chacha_private.h deleted file mode 100644 index 7c3680f..0000000 --- a/openbsd-compat/chacha_private.h +++ /dev/null @@ -1,222 +0,0 @@ -/* -chacha-merged.c version 20080118 -D. J. Bernstein -Public domain. -*/ - -/* $OpenBSD: chacha_private.h,v 1.2 2013/10/04 07:02:27 djm Exp $ */ - -typedef unsigned char u8; -typedef unsigned int u32; - -typedef struct -{ - u32 input[16]; /* could be compressed */ -} chacha_ctx; - -#define U8C(v) (v##U) -#define U32C(v) (v##U) - -#define U8V(v) ((u8)(v) & U8C(0xFF)) -#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) - -#define ROTL32(v, n) \ - (U32V((v) << (n)) | ((v) >> (32 - (n)))) - -#define U8TO32_LITTLE(p) \ - (((u32)((p)[0]) ) | \ - ((u32)((p)[1]) << 8) | \ - ((u32)((p)[2]) << 16) | \ - ((u32)((p)[3]) << 24)) - -#define U32TO8_LITTLE(p, v) \ - do { \ - (p)[0] = U8V((v) ); \ - (p)[1] = U8V((v) >> 8); \ - (p)[2] = U8V((v) >> 16); \ - (p)[3] = U8V((v) >> 24); \ - } while (0) - -#define ROTATE(v,c) (ROTL32(v,c)) -#define XOR(v,w) ((v) ^ (w)) -#define PLUS(v,w) (U32V((v) + (w))) -#define PLUSONE(v) (PLUS((v),1)) - -#define QUARTERROUND(a,b,c,d) \ - a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ - c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ - a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ - c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); - -static const char sigma[16] = "expand 32-byte k"; -static const char tau[16] = "expand 16-byte k"; - -static void -chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ivbits) -{ - const char *constants; - - x->input[4] = U8TO32_LITTLE(k + 0); - x->input[5] = U8TO32_LITTLE(k + 4); - x->input[6] = U8TO32_LITTLE(k + 8); - x->input[7] = U8TO32_LITTLE(k + 12); - if (kbits == 256) { /* recommended */ - k += 16; - constants = sigma; - } else { /* kbits == 128 */ - constants = tau; - } - x->input[8] = U8TO32_LITTLE(k + 0); - x->input[9] = U8TO32_LITTLE(k + 4); - x->input[10] = U8TO32_LITTLE(k + 8); - x->input[11] = U8TO32_LITTLE(k + 12); - x->input[0] = U8TO32_LITTLE(constants + 0); - x->input[1] = U8TO32_LITTLE(constants + 4); - x->input[2] = U8TO32_LITTLE(constants + 8); - x->input[3] = U8TO32_LITTLE(constants + 12); -} - -static void -chacha_ivsetup(chacha_ctx *x,const u8 *iv) -{ - x->input[12] = 0; - x->input[13] = 0; - x->input[14] = U8TO32_LITTLE(iv + 0); - x->input[15] = U8TO32_LITTLE(iv + 4); -} - -static void -chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) -{ - u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; - u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; - u8 *ctarget = NULL; - u8 tmp[64]; - u_int i; - - if (!bytes) return; - - j0 = x->input[0]; - j1 = x->input[1]; - j2 = x->input[2]; - j3 = x->input[3]; - j4 = x->input[4]; - j5 = x->input[5]; - j6 = x->input[6]; - j7 = x->input[7]; - j8 = x->input[8]; - j9 = x->input[9]; - j10 = x->input[10]; - j11 = x->input[11]; - j12 = x->input[12]; - j13 = x->input[13]; - j14 = x->input[14]; - j15 = x->input[15]; - - for (;;) { - if (bytes < 64) { - for (i = 0;i < bytes;++i) tmp[i] = m[i]; - m = tmp; - ctarget = c; - c = tmp; - } - x0 = j0; - x1 = j1; - x2 = j2; - x3 = j3; - x4 = j4; - x5 = j5; - x6 = j6; - x7 = j7; - x8 = j8; - x9 = j9; - x10 = j10; - x11 = j11; - x12 = j12; - x13 = j13; - x14 = j14; - x15 = j15; - for (i = 20;i > 0;i -= 2) { - QUARTERROUND( x0, x4, x8,x12) - QUARTERROUND( x1, x5, x9,x13) - QUARTERROUND( x2, x6,x10,x14) - QUARTERROUND( x3, x7,x11,x15) - QUARTERROUND( x0, x5,x10,x15) - QUARTERROUND( x1, x6,x11,x12) - QUARTERROUND( x2, x7, x8,x13) - QUARTERROUND( x3, x4, x9,x14) - } - x0 = PLUS(x0,j0); - x1 = PLUS(x1,j1); - x2 = PLUS(x2,j2); - x3 = PLUS(x3,j3); - x4 = PLUS(x4,j4); - x5 = PLUS(x5,j5); - x6 = PLUS(x6,j6); - x7 = PLUS(x7,j7); - x8 = PLUS(x8,j8); - x9 = PLUS(x9,j9); - x10 = PLUS(x10,j10); - x11 = PLUS(x11,j11); - x12 = PLUS(x12,j12); - x13 = PLUS(x13,j13); - x14 = PLUS(x14,j14); - x15 = PLUS(x15,j15); - -#ifndef KEYSTREAM_ONLY - x0 = XOR(x0,U8TO32_LITTLE(m + 0)); - x1 = XOR(x1,U8TO32_LITTLE(m + 4)); - x2 = XOR(x2,U8TO32_LITTLE(m + 8)); - x3 = XOR(x3,U8TO32_LITTLE(m + 12)); - x4 = XOR(x4,U8TO32_LITTLE(m + 16)); - x5 = XOR(x5,U8TO32_LITTLE(m + 20)); - x6 = XOR(x6,U8TO32_LITTLE(m + 24)); - x7 = XOR(x7,U8TO32_LITTLE(m + 28)); - x8 = XOR(x8,U8TO32_LITTLE(m + 32)); - x9 = XOR(x9,U8TO32_LITTLE(m + 36)); - x10 = XOR(x10,U8TO32_LITTLE(m + 40)); - x11 = XOR(x11,U8TO32_LITTLE(m + 44)); - x12 = XOR(x12,U8TO32_LITTLE(m + 48)); - x13 = XOR(x13,U8TO32_LITTLE(m + 52)); - x14 = XOR(x14,U8TO32_LITTLE(m + 56)); - x15 = XOR(x15,U8TO32_LITTLE(m + 60)); -#endif - - j12 = PLUSONE(j12); - if (!j12) { - j13 = PLUSONE(j13); - /* stopping at 2^70 bytes per nonce is user's responsibility */ - } - - U32TO8_LITTLE(c + 0,x0); - U32TO8_LITTLE(c + 4,x1); - U32TO8_LITTLE(c + 8,x2); - U32TO8_LITTLE(c + 12,x3); - U32TO8_LITTLE(c + 16,x4); - U32TO8_LITTLE(c + 20,x5); - U32TO8_LITTLE(c + 24,x6); - U32TO8_LITTLE(c + 28,x7); - U32TO8_LITTLE(c + 32,x8); - U32TO8_LITTLE(c + 36,x9); - U32TO8_LITTLE(c + 40,x10); - U32TO8_LITTLE(c + 44,x11); - U32TO8_LITTLE(c + 48,x12); - U32TO8_LITTLE(c + 52,x13); - U32TO8_LITTLE(c + 56,x14); - U32TO8_LITTLE(c + 60,x15); - - if (bytes <= 64) { - if (bytes < 64) { - for (i = 0;i < bytes;++i) ctarget[i] = c[i]; - } - x->input[12] = j12; - x->input[13] = j13; - return; - } - bytes -= 64; - c += 64; -#ifndef KEYSTREAM_ONLY - m += 64; -#endif - } -} diff --git a/openbsd-compat/daemon.c b/openbsd-compat/daemon.c deleted file mode 100644 index 3efe14c..0000000 --- a/openbsd-compat/daemon.c +++ /dev/null @@ -1,82 +0,0 @@ -/* $OpenBSD: daemon.c,v 1.6 2005/08/08 08:05:33 espie Exp $ */ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. 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. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* OPENBSD ORIGINAL: lib/libc/gen/daemon.c */ - -#include "includes.h" - -#ifndef HAVE_DAEMON - -#include - -#ifdef HAVE_SYS_STAT_H -# include -#endif - -#ifdef HAVE_FCNTL_H -# include -#endif - -#ifdef HAVE_UNISTD_H -# include -#endif - -int -daemon(int nochdir, int noclose) -{ - int fd; - - switch (fork()) { - case -1: - return (-1); - case 0: - break; - default: - _exit(0); - } - - if (setsid() == -1) - return (-1); - - if (!nochdir) - (void)chdir("/"); - - if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { - (void)dup2(fd, STDIN_FILENO); - (void)dup2(fd, STDOUT_FILENO); - (void)dup2(fd, STDERR_FILENO); - if (fd > 2) - (void)close (fd); - } - return (0); -} - -#endif /* !HAVE_DAEMON */ - diff --git a/openbsd-compat/defines.h b/openbsd-compat/defines.h index fa9dbdf..cd08596 100644 --- a/openbsd-compat/defines.h +++ b/openbsd-compat/defines.h @@ -625,21 +625,6 @@ struct sadb_sa_natt { # define HAVE_GETADDRINFO #endif -#ifndef HAVE_GETOPT_OPTRESET -# undef getopt -# undef opterr -# undef optind -# undef optopt -# undef optreset -# undef optarg -# define getopt(ac, av, o) BSDgetopt(ac, av, o) -# define opterr BSDopterr -# define optind BSDoptind -# define optopt BSDoptopt -# define optreset BSDoptreset -# define optarg BSDoptarg -#endif - #if defined(BROKEN_GETADDRINFO) && defined(HAVE_GETADDRINFO) # undef HAVE_GETADDRINFO #endif diff --git a/openbsd-compat/entropy.c b/openbsd-compat/entropy.c deleted file mode 100644 index ea798a7..0000000 --- a/openbsd-compat/entropy.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2001 Damien Miller. 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. - */ - -#include "includes.h" - -#include -#include -#ifdef HAVE_SYS_UN_H -# include -#endif - -#include -#include - -#include -#include -#include -#include -#include /* for offsetof */ - -#include -#include -#include - -/* - * Portable OpenSSH PRNG seeding: - * If OpenSSL has not "internally seeded" itself (e.g. pulled data from - * /dev/random), then collect RANDOM_SEED_SIZE bytes of randomness from - * PRNGd. - */ -#ifndef OPENSSL_PRNG_ONLY - -#define RANDOM_SEED_SIZE 48 - -/* - * Collect 'len' bytes of entropy into 'buf' from PRNGD/EGD daemon - * listening either on 'tcp_port', or via Unix domain socket at * - * 'socket_path'. - * Either a non-zero tcp_port or a non-null socket_path must be - * supplied. - * Returns 0 on success, -1 on error - */ -int -get_random_bytes_prngd(unsigned char *buf, int len, - unsigned short tcp_port, char *socket_path) -{ - int fd, addr_len, rval, errors; - u_char msg[2]; - struct sockaddr_storage addr; - struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr; - struct sockaddr_un *addr_un = (struct sockaddr_un *)&addr; - mysig_t old_sigpipe; - - /* Sanity checks */ - if (socket_path == NULL && tcp_port == 0) - errx(1, "You must specify a port or a socket"); - if (socket_path != NULL && - strlen(socket_path) >= sizeof(addr_un->sun_path)) - errx(1, "Random pool path is too long"); - if (len <= 0 || len > 255) - errx(1, "Too many bytes (%d) to read from PRNGD", len); - - memset(&addr, '\0', sizeof(addr)); - - if (tcp_port != 0) { - addr_in->sin_family = AF_INET; - addr_in->sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr_in->sin_port = htons(tcp_port); - addr_len = sizeof(*addr_in); - } else { - addr_un->sun_family = AF_UNIX; - strlcpy(addr_un->sun_path, socket_path, - sizeof(addr_un->sun_path)); - addr_len = offsetof(struct sockaddr_un, sun_path) + - strlen(socket_path) + 1; - } - - old_sigpipe = mysignal(SIGPIPE, SIG_IGN); - - errors = 0; - rval = -1; -reopen: - fd = socket(addr.ss_family, SOCK_STREAM, 0); - if (fd == -1) { - warn("Couldn't create socket"); - goto done; - } - - if (connect(fd, (struct sockaddr*)&addr, addr_len) == -1) { - if (tcp_port != 0) { - warn("Couldn't connect to PRNGD port %d", - tcp_port); - } else { - warn("Couldn't connect to PRNGD socket \"%s\"", - addr_un->sun_path); - } - goto done; - } - - /* Send blocking read request to PRNGD */ - msg[0] = 0x02; - msg[1] = len; - - if (atomicio(vwrite, fd, msg, sizeof(msg)) != sizeof(msg)) { - if (errno == EPIPE && errors < 10) { - close(fd); - errors++; - goto reopen; - } - warn("Couldn't write to PRNGD socket"); - goto done; - } - - if (atomicio(read, fd, buf, len) != (size_t)len) { - if (errno == EPIPE && errors < 10) { - close(fd); - errors++; - goto reopen; - } - warn("Couldn't read from PRNGD socket"); - goto done; - } - - rval = 0; -done: - mysignal(SIGPIPE, old_sigpipe); - if (fd != -1) - close(fd); - return rval; -} - -static int -seed_from_prngd(unsigned char *buf, size_t bytes) -{ -#ifdef PRNGD_PORT - debug("trying egd/prngd port %d", PRNGD_PORT); - if (get_random_bytes_prngd(buf, bytes, PRNGD_PORT, NULL) == 0) - return 0; -#endif -#ifdef PRNGD_SOCKET - debug("trying egd/prngd socket %s", PRNGD_SOCKET); - if (get_random_bytes_prngd(buf, bytes, 0, PRNGD_SOCKET) == 0) - return 0; -#endif - return -1; -} -#endif /* OPENSSL_PRNG_ONLY */ - -void -seed_rng(void) -{ -#ifndef OPENSSL_PRNG_ONLY - unsigned char buf[RANDOM_SEED_SIZE]; -#endif - /* - * OpenSSL version numbers: MNNFFPPS: major minor fix patch status - * We match major, minor, fix and status (not patch) for <1.0.0. - * After that, we acceptable compatible fix versions (so we - * allow 1.0.1 to work with 1.0.0). Going backwards is only allowed - * within a patch series. - */ - u_long version_mask = SSLeay() >= 0x1000000f ? ~0xffff0L : ~0xff0L; - if (((SSLeay() ^ OPENSSL_VERSION_NUMBER) & version_mask) || - (SSLeay() >> 12) < (OPENSSL_VERSION_NUMBER >> 12)) - errx(1, "OpenSSL version mismatch. Built against %lx, you " - "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay()); - -#ifndef OPENSSL_PRNG_ONLY - if (RAND_status() == 1) { - warnx("RNG is ready, skipping seeding"); - return; - } - - if (seed_from_prngd(buf, sizeof(buf)) == -1) - errx(1, "Could not obtain seed from PRNGd"); - RAND_add(buf, sizeof(buf), sizeof(buf)); - memset(buf, '\0', sizeof(buf)); - -#endif /* OPENSSL_PRNG_ONLY */ - if (RAND_status() != 1) - errx(1, "PRNG is not seeded"); -} diff --git a/openbsd-compat/explicit-bzero.c b/openbsd-compat/explicit-bzero.c new file mode 100644 index 0000000..3e33ca8 --- /dev/null +++ b/openbsd-compat/explicit-bzero.c @@ -0,0 +1,19 @@ +/* $OpenBSD: explicit_bzero.c,v 1.3 2014/06/21 02:34:26 matthew Exp $ */ +/* + * Public domain. + * Written by Matthew Dempsky. + */ + +#include + +__attribute__((weak)) void +__explicit_bzero_hook(void *buf, size_t len) +{ +} + +void +explicit_bzero(void *buf, size_t len) +{ + memset(buf, 0, len); + __explicit_bzero_hook(buf, len); +} diff --git a/openbsd-compat/fgetln.c b/openbsd-compat/fgetln.c deleted file mode 100644 index c7fef41..0000000 --- a/openbsd-compat/fgetln.c +++ /dev/null @@ -1,63 +0,0 @@ -/* $OpenBSD: util.c,v 1.23 2007/09/17 09:28:36 espie Exp $ */ -/* $NetBSD: util.c,v 1.10 1996/12/31 17:56:04 christos Exp $ */ - -/* - * Copyright (c) 2001 Marc Espie. - * - * 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 OPENBSD PROJECT AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD - * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* OPENBSD ORIGINAL: usr.bin/make/util.c */ - -#include "includes.h" - -#ifndef HAVE_FGETLN - -#include - -char * -fgetln(stream, len) - FILE *stream; - size_t *len; -{ - static char *buffer = NULL; - static size_t buflen = 0; - - if (buflen == 0) { - buflen = 512; - if ((buffer = malloc(buflen+1)) == NULL) - err(255, "fatal: malloc: out of memory"); - } - if (fgets(buffer, buflen+1, stream) == NULL) - return NULL; - *len = strlen(buffer); - while (*len == buflen && buffer[*len-1] != '\n') { - if ((buffer = realloc(buffer, 2*buflen + 1)) == NULL) - err(255, "fatal: realloc: out of memory"); - if (fgets(buffer + buflen, buflen + 1, stream) == NULL) - return NULL; - *len += strlen(buffer + buflen); - buflen *= 2; - } - return buffer; -} -#endif diff --git a/openbsd-compat/getopt.c b/openbsd-compat/getopt.c deleted file mode 100644 index 5450e43..0000000 --- a/openbsd-compat/getopt.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 1987, 1993, 1994 - * The Regents of the University of California. 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. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* OPENBSD ORIGINAL: lib/libc/stdlib/getopt.c */ - -#include "includes.h" -#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET) - -#if defined(LIBC_SCCS) && !defined(lint) -static char *rcsid = "$OpenBSD: getopt.c,v 1.5 2003/06/02 20:18:37 millert Exp $"; -#endif /* LIBC_SCCS and not lint */ - -#include -#include -#include - -int BSDopterr = 1, /* if error message should be printed */ - BSDoptind = 1, /* index into parent argv vector */ - BSDoptopt, /* character checked for validity */ - BSDoptreset; /* reset getopt */ -char *BSDoptarg; /* argument associated with option */ - -#define BADCH (int)'?' -#define BADARG (int)':' -#define EMSG "" - -/* - * getopt -- - * Parse argc/argv argument vector. - */ -int -BSDgetopt(nargc, nargv, ostr) - int nargc; - char * const *nargv; - const char *ostr; -{ - extern char *__progname; - static char *place = EMSG; /* option letter processing */ - char *oli; /* option letter list index */ - - if (ostr == NULL) - return (-1); - - if (BSDoptreset || !*place) { /* update scanning pointer */ - BSDoptreset = 0; - if (BSDoptind >= nargc || *(place = nargv[BSDoptind]) != '-') { - place = EMSG; - return (-1); - } - if (place[1] && *++place == '-') { /* found "--" */ - ++BSDoptind; - place = EMSG; - return (-1); - } - } /* option letter okay? */ - if ((BSDoptopt = (int)*place++) == (int)':' || - !(oli = strchr(ostr, BSDoptopt))) { - /* - * if the user didn't specify '-' as an option, - * assume it means -1. - */ - if (BSDoptopt == (int)'-') - return (-1); - if (!*place) - ++BSDoptind; - if (BSDopterr && *ostr != ':') - (void)fprintf(stderr, - "%s: illegal option -- %c\n", __progname, BSDoptopt); - return (BADCH); - } - if (*++oli != ':') { /* don't need argument */ - BSDoptarg = NULL; - if (!*place) - ++BSDoptind; - } - else { /* need an argument */ - if (*place) /* no white space */ - BSDoptarg = place; - else if (nargc <= ++BSDoptind) { /* no arg */ - place = EMSG; - if (*ostr == ':') - return (BADARG); - if (BSDopterr) - (void)fprintf(stderr, - "%s: option requires an argument -- %c\n", - __progname, BSDoptopt); - return (BADCH); - } - else /* white space */ - BSDoptarg = nargv[BSDoptind]; - place = EMSG; - ++BSDoptind; - } - return (BSDoptopt); /* dump back option letter */ -} - -#endif /* !defined(HAVE_GETOPT) || !defined(HAVE_OPTRESET) */ diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h index 26bf649..9dc43b0 100644 --- a/openbsd-compat/openbsd-compat.h +++ b/openbsd-compat/openbsd-compat.h @@ -51,7 +51,6 @@ #include "sys-queue.h" #include "sys-tree.h" -#include "vis.h" #ifdef HAVE_SYS_TIME_H #include @@ -92,19 +91,6 @@ # define SET_STORAGE_LEN(X, Y) (void) 0 #endif - -#ifndef HAVE_CLOSEFROM -void closefrom(int); -#endif - -#ifndef HAVE_STRLCPY -size_t strlcpy(char *dst, const char *src, size_t size); -#endif - -#ifndef HAVE_STRLCAT -size_t strlcat(char *dst, const char *src, size_t size); -#endif - #ifndef HAVE_STRMODE void strmode(int mode, char *p); #endif @@ -117,11 +103,6 @@ char *dirname(const char *path); char *strsep(char **stringp, const char *delim); #endif -#ifndef HAVE_SETPROCTITLE -void setproctitle(const char *fmt, ...); -void compat_init_setproctitle(int argc, char *argv[]); -#endif - #ifndef HAVE_SETRESGID int setresgid(uid_t rgid, uid_t egid, uid_t sgid); #endif @@ -130,35 +111,10 @@ int setresgid(uid_t rgid, uid_t egid, uid_t sgid); int setresuid(uid_t ruid, uid_t euid, uid_t suid); #endif -#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET) -int BSDgetopt(int argc, char * const *argv, const char *opts); -char *BSDoptarg; /* argument associated with option */ -int BSDoptind; /* index into parent argv vector */ -#endif - #ifndef HAVE_GETPEEREID int getpeereid(int , uid_t *, gid_t *); #endif -#ifndef HAVE_ARC4RANDOM -unsigned int arc4random(void); -void arc4random_stir(void); -#endif /* !HAVE_ARC4RANDOM */ - -#ifndef HAVE_ARC4RANDOM_BUF -void arc4random_buf(void *, size_t); -#endif - -#ifndef HAVE_ARC4RANDOM_UNIFORM -u_int32_t arc4random_uniform(u_int32_t); -#endif - -#ifndef HAVE_FGETLN -#include -#include -char * fgetln(FILE *stream, size_t *len); -#endif - #ifndef HAVE_FPARSELN char * fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags); #endif @@ -177,6 +133,7 @@ int scan_scaled(char *scaled, long long *result); int fmt_scaled(long long number, char *result); #endif -void seed_rng(void); +void *reallocarray(void *, size_t , size_t); +void explicit_bzero(void *buf, size_t len); #endif /* _OPENBSD_COMPAT_H */ diff --git a/openbsd-compat/reallocarray.c b/openbsd-compat/reallocarray.c new file mode 100644 index 0000000..ed3244e --- /dev/null +++ b/openbsd-compat/reallocarray.c @@ -0,0 +1,38 @@ +/* $OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $ */ +/* + * Copyright (c) 2008 Otto Moerbeek + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +/* + * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX + * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW + */ +#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) + +void * +reallocarray(void *optr, size_t nmemb, size_t size) +{ + if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + nmemb > 0 && SIZE_MAX / nmemb < size) { + errno = ENOMEM; + return NULL; + } + return realloc(optr, size * nmemb); +} diff --git a/openbsd-compat/setproctitle.c b/openbsd-compat/setproctitle.c deleted file mode 100644 index 40a6737..0000000 --- a/openbsd-compat/setproctitle.c +++ /dev/null @@ -1,163 +0,0 @@ -/* Based on conf.c from UCB sendmail 8.8.8 */ - -/* - * Copyright 2003 Damien Miller - * Copyright (c) 1983, 1995-1997 Eric P. Allman - * Copyright (c) 1988, 1993 - * The Regents of the University of California. 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. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef HAVE_SETPROCTITLE - -#include -#include -#include -#include -#ifdef HAVE_SYS_PSTAT_H -#include -#endif -#include - -#include - -#define SPT_NONE 0 /* don't use it at all */ -#define SPT_PSTAT 1 /* use pstat(PSTAT_SETCMD, ...) */ -#define SPT_REUSEARGV 2 /* cover argv with title information */ - -#ifndef SPT_TYPE -# define SPT_TYPE SPT_NONE -#endif - -#ifndef SPT_PADCHAR -# define SPT_PADCHAR '\0' -#endif - -#if SPT_TYPE == SPT_REUSEARGV -static char *argv_start = NULL; -static size_t argv_env_len = 0; -#endif - -#endif /* HAVE_SETPROCTITLE */ - -void -compat_init_setproctitle(int argc, char *argv[]) -{ -#if defined(SPT_TYPE) && SPT_TYPE == SPT_REUSEARGV - extern char **environ; - char *lastargv = NULL; - char **envp = environ; - int i; - - /* - * NB: This assumes that argv has already been copied out of the - * way. This is true for sshd, but may not be true for other - * programs. Beware. - */ - - if (argc == 0 || argv[0] == NULL) - return; - - /* Fail if we can't allocate room for the new environment */ - for (i = 0; envp[i] != NULL; i++) - ; - if ((environ = calloc(i + 1, sizeof(*environ))) == NULL) { - environ = envp; /* put it back */ - return; - } - - /* - * Find the last argv string or environment variable within - * our process memory area. - */ - for (i = 0; i < argc; i++) { - if (lastargv == NULL || lastargv + 1 == argv[i]) - lastargv = argv[i] + strlen(argv[i]); - } - for (i = 0; envp[i] != NULL; i++) { - if (lastargv + 1 == envp[i]) - lastargv = envp[i] + strlen(envp[i]); - } - - argv[1] = NULL; - argv_start = argv[0]; - argv_env_len = lastargv - argv[0] - 1; - - /* - * Copy environment - * XXX - will truncate env on strdup fail - */ - for (i = 0; envp[i] != NULL; i++) - environ[i] = strdup(envp[i]); - environ[i] = NULL; -#endif /* SPT_REUSEARGV */ -} - -#ifndef HAVE_SETPROCTITLE -void -setproctitle(const char *fmt, ...) -{ -#if SPT_TYPE != SPT_NONE - va_list ap; - char buf[1024], ptitle[1024]; - size_t len; - extern char *__progname; -#if SPT_TYPE == SPT_PSTAT - union pstun pst; -#endif - -#if SPT_TYPE == SPT_REUSEARGV - if (argv_env_len <= 0) - return; -#endif - - strlcpy(buf, __progname, sizeof(buf)); - - va_start(ap, fmt); - if (fmt != NULL) { - len = strlcat(buf, ": ", sizeof(buf)); - if (len < sizeof(buf)) - vsnprintf(buf + len, sizeof(buf) - len , fmt, ap); - } - va_end(ap); - strnvis(ptitle, buf, sizeof(ptitle), - VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL); - -#if SPT_TYPE == SPT_PSTAT - pst.pst_command = ptitle; - pstat(PSTAT_SETCMD, pst, strlen(ptitle), 0, 0); -#elif SPT_TYPE == SPT_REUSEARGV -/* debug("setproctitle: copy \"%s\" into len %d", - buf, argv_env_len); */ - len = strlcpy(argv_start, ptitle, argv_env_len); - for(; len < argv_env_len; len++) - argv_start[len] = SPT_PADCHAR; -#endif - -#endif /* SPT_NONE */ -} - -#endif /* HAVE_SETPROCTITLE */ diff --git a/openbsd-compat/strlcat.c b/openbsd-compat/strlcat.c deleted file mode 100644 index bcc1b61..0000000 --- a/openbsd-compat/strlcat.c +++ /dev/null @@ -1,62 +0,0 @@ -/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ - -/* - * Copyright (c) 1998 Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* OPENBSD ORIGINAL: lib/libc/string/strlcat.c */ - -#include "includes.h" -#ifndef HAVE_STRLCAT - -#include -#include - -/* - * Appends src to string dst of size siz (unlike strncat, siz is the - * full size of dst, not space left). At most siz-1 characters - * will be copied. Always NUL terminates (unless siz <= strlen(dst)). - * Returns strlen(src) + MIN(siz, strlen(initial dst)). - * If retval >= siz, truncation occurred. - */ -size_t -strlcat(char *dst, const char *src, size_t siz) -{ - char *d = dst; - const char *s = src; - size_t n = siz; - size_t dlen; - - /* Find the end of dst and adjust bytes left but don't go past end */ - while (n-- != 0 && *d != '\0') - d++; - dlen = d - dst; - n = siz - dlen; - - if (n == 0) - return(dlen + strlen(s)); - while (*s != '\0') { - if (n != 1) { - *d++ = *s; - n--; - } - s++; - } - *d = '\0'; - - return(dlen + (s - src)); /* count does not include NUL */ -} - -#endif /* !HAVE_STRLCAT */ diff --git a/openbsd-compat/strlcpy.c b/openbsd-compat/strlcpy.c deleted file mode 100644 index b4b1b60..0000000 --- a/openbsd-compat/strlcpy.c +++ /dev/null @@ -1,58 +0,0 @@ -/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ - -/* - * Copyright (c) 1998 Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* OPENBSD ORIGINAL: lib/libc/string/strlcpy.c */ - -#include "includes.h" -#ifndef HAVE_STRLCPY - -#include -#include - -/* - * Copy src to string dst of size siz. At most siz-1 characters - * will be copied. Always NUL terminates (unless siz == 0). - * Returns strlen(src); if retval >= siz, truncation occurred. - */ -size_t -strlcpy(char *dst, const char *src, size_t siz) -{ - char *d = dst; - const char *s = src; - size_t n = siz; - - /* Copy as many bytes as will fit */ - if (n != 0) { - while (--n != 0) { - if ((*d++ = *s++) == '\0') - break; - } - } - - /* Not enough room in dst, add NUL and traverse rest of src */ - if (n == 0) { - if (siz != 0) - *d = '\0'; /* NUL-terminate dst */ - while (*s++) - ; - } - - return(s - src - 1); /* count does not include NUL */ -} - -#endif /* !HAVE_STRLCPY */ diff --git a/openbsd-compat/vis.c b/openbsd-compat/vis.c deleted file mode 100644 index 3a087b3..0000000 --- a/openbsd-compat/vis.c +++ /dev/null @@ -1,225 +0,0 @@ -/* $OpenBSD: vis.c,v 1.19 2005/09/01 17:15:49 millert Exp $ */ -/*- - * Copyright (c) 1989, 1993 - * The Regents of the University of California. 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. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* OPENBSD ORIGINAL: lib/libc/gen/vis.c */ - -#include "includes.h" -#if !defined(HAVE_STRNVIS) - -#include -#include - -#include "vis.h" - -#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') -#define isvisible(c) \ - (((u_int)(c) <= UCHAR_MAX && isascii((u_char)(c)) && \ - (((c) != '*' && (c) != '?' && (c) != '[' && (c) != '#') || \ - (flag & VIS_GLOB) == 0) && isgraph((u_char)(c))) || \ - ((flag & VIS_SP) == 0 && (c) == ' ') || \ - ((flag & VIS_TAB) == 0 && (c) == '\t') || \ - ((flag & VIS_NL) == 0 && (c) == '\n') || \ - ((flag & VIS_SAFE) && ((c) == '\b' || \ - (c) == '\007' || (c) == '\r' || \ - isgraph((u_char)(c))))) - -/* - * vis - visually encode characters - */ -char * -vis(char *dst, int c, int flag, int nextc) -{ - if (isvisible(c)) { - *dst++ = c; - if (c == '\\' && (flag & VIS_NOSLASH) == 0) - *dst++ = '\\'; - *dst = '\0'; - return (dst); - } - - if (flag & VIS_CSTYLE) { - switch(c) { - case '\n': - *dst++ = '\\'; - *dst++ = 'n'; - goto done; - case '\r': - *dst++ = '\\'; - *dst++ = 'r'; - goto done; - case '\b': - *dst++ = '\\'; - *dst++ = 'b'; - goto done; - case '\a': - *dst++ = '\\'; - *dst++ = 'a'; - goto done; - case '\v': - *dst++ = '\\'; - *dst++ = 'v'; - goto done; - case '\t': - *dst++ = '\\'; - *dst++ = 't'; - goto done; - case '\f': - *dst++ = '\\'; - *dst++ = 'f'; - goto done; - case ' ': - *dst++ = '\\'; - *dst++ = 's'; - goto done; - case '\0': - *dst++ = '\\'; - *dst++ = '0'; - if (isoctal(nextc)) { - *dst++ = '0'; - *dst++ = '0'; - } - goto done; - } - } - if (((c & 0177) == ' ') || (flag & VIS_OCTAL) || - ((flag & VIS_GLOB) && (c == '*' || c == '?' || c == '[' || c == '#'))) { - *dst++ = '\\'; - *dst++ = ((u_char)c >> 6 & 07) + '0'; - *dst++ = ((u_char)c >> 3 & 07) + '0'; - *dst++ = ((u_char)c & 07) + '0'; - goto done; - } - if ((flag & VIS_NOSLASH) == 0) - *dst++ = '\\'; - if (c & 0200) { - c &= 0177; - *dst++ = 'M'; - } - if (iscntrl((u_char)c)) { - *dst++ = '^'; - if (c == 0177) - *dst++ = '?'; - else - *dst++ = c + '@'; - } else { - *dst++ = '-'; - *dst++ = c; - } -done: - *dst = '\0'; - return (dst); -} - -/* - * strvis, strnvis, strvisx - visually encode characters from src into dst - * - * Dst must be 4 times the size of src to account for possible - * expansion. The length of dst, not including the trailing NULL, - * is returned. - * - * Strnvis will write no more than siz-1 bytes (and will NULL terminate). - * The number of bytes needed to fully encode the string is returned. - * - * Strvisx encodes exactly len bytes from src into dst. - * This is useful for encoding a block of data. - */ -int -strvis(char *dst, const char *src, int flag) -{ - char c; - char *start; - - for (start = dst; (c = *src);) - dst = vis(dst, c, flag, *++src); - *dst = '\0'; - return (dst - start); -} - -int -strnvis(char *dst, const char *src, size_t siz, int flag) -{ - char *start, *end; - char tbuf[5]; - int c, i; - - i = 0; - for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) { - if (isvisible(c)) { - i = 1; - *dst++ = c; - if (c == '\\' && (flag & VIS_NOSLASH) == 0) { - /* need space for the extra '\\' */ - if (dst < end) - *dst++ = '\\'; - else { - dst--; - i = 2; - break; - } - } - src++; - } else { - i = vis(tbuf, c, flag, *++src) - tbuf; - if (dst + i <= end) { - memcpy(dst, tbuf, i); - dst += i; - } else { - src--; - break; - } - } - } - if (siz > 0) - *dst = '\0'; - if (dst + i > end) { - /* adjust return value for truncation */ - while ((c = *src)) - dst += vis(tbuf, c, flag, *++src) - tbuf; - } - return (dst - start); -} - -int -strvisx(char *dst, const char *src, size_t len, int flag) -{ - char c; - char *start; - - for (start = dst; len > 1; len--) { - c = *src; - dst = vis(dst, c, flag, *++src); - } - if (len) - dst = vis(dst, *src, flag, '\0'); - *dst = '\0'; - return (dst - start); -} - -#endif diff --git a/openbsd-compat/vis.h b/openbsd-compat/vis.h deleted file mode 100644 index 66c0951..0000000 --- a/openbsd-compat/vis.h +++ /dev/null @@ -1,98 +0,0 @@ -/* $OpenBSD: vis.h,v 1.11 2005/08/09 19:38:31 millert Exp $ */ -/* $NetBSD: vis.h,v 1.4 1994/10/26 00:56:41 cgd Exp $ */ - -/*- - * Copyright (c) 1990 The Regents of the University of California. - * 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. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)vis.h 5.9 (Berkeley) 4/3/91 - */ - -/* OPENBSD ORIGINAL: include/vis.h */ - -#ifdef HAVE_CONFIG_H -#include "includes.h" -#endif - -// #if !defined(HAVE_STRNVIS) - -#ifndef _VIS_H_ -#define _VIS_H_ - -#include -#include - -/* - * to select alternate encoding format - */ -#define VIS_OCTAL 0x01 /* use octal \ddd format */ -#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropriate */ - -/* - * to alter set of characters encoded (default is to encode all - * non-graphic except space, tab, and newline). - */ -#define VIS_SP 0x04 /* also encode space */ -#define VIS_TAB 0x08 /* also encode tab */ -#define VIS_NL 0x10 /* also encode newline */ -#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL) -#define VIS_SAFE 0x20 /* only encode "unsafe" characters */ - -/* - * other - */ -#define VIS_NOSLASH 0x40 /* inhibit printing '\' */ -#define VIS_GLOB 0x100 /* encode glob(3) magics and '#' */ - -/* - * unvis return codes - */ -#define UNVIS_VALID 1 /* character valid */ -#define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */ -#define UNVIS_NOCHAR 3 /* valid sequence, no character produced */ -#define UNVIS_SYNBAD -1 /* unrecognized escape sequence */ -#define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */ - -/* - * unvis flags - */ -#define UNVIS_END 1 /* no more characters */ - -char *vis(char *, int, int, int); -int strvis(char *, const char *, int); -int strnvis(char *, const char *, size_t, int) - __attribute__ ((__bounded__(__string__,1,3))); -int strvisx(char *, const char *, size_t, int) - __attribute__ ((__bounded__(__string__,1,3))); -int strunvis(char *, const char *); -int unvis(char *, char, int *, int); -ssize_t strnunvis(char *, const char *, size_t) - __attribute__ ((__bounded__(__string__,1,3))); - -#endif /* !_VIS_H_ */ - -//#endif /* !HAVE_STRNVIS */ From 00f316b42cd5ba6ac5235e561395cade67d19c83 Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Tue, 7 Jun 2016 09:56:12 -0700 Subject: [PATCH 07/39] Invoke AM_INIT_AUTOMAKE with [subdir-objects] --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 1705862..43dec5c 100644 --- a/configure.ac +++ b/configure.ac @@ -22,7 +22,7 @@ AC_CONFIG_HEADER([config.h]) AC_CANONICAL_HOST AC_C_BIGENDIAN -AM_INIT_AUTOMAKE +AM_INIT_AUTOMAKE([subdir-objects]) # Checks for programs. AC_PROG_CC From 91bd356f5aaed5d0a0f34339e251bbe6c4cd8892 Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Tue, 7 Jun 2016 10:06:24 -0700 Subject: [PATCH 08/39] Fix build errors on FreeBSD-current. --- iked/pfkey.c | 2 +- iked/policy.c | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/iked/pfkey.c b/iked/pfkey.c index 6a3c63a..8f989b6 100644 --- a/iked/pfkey.c +++ b/iked/pfkey.c @@ -1884,7 +1884,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) struct sockaddr *speer; struct sadb_x_policy *sa_pol; struct iked_flow flow; - struct sockaddr *ssrc, *sdst; + struct sockaddr *ssrc; #endif u_int8_t *data = pm->pm_data; ssize_t len = pm->pm_length; diff --git a/iked/policy.c b/iked/policy.c index eb3c707..df866bd 100644 --- a/iked/policy.c +++ b/iked/policy.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -75,7 +76,7 @@ policy_lookup(struct iked *env, struct iked_message *msg) (s = strchr(idstr, '/')) != NULL) { pol.pol_peerid.id_type = msg->msg_id.id_type; pol.pol_peerid.id_length = strlen(s+1); - strlcpy(pol.pol_peerid.id_data, s+1, + strlcpy((char *)pol.pol_peerid.id_data, s+1, sizeof(pol.pol_peerid.id_data)); log_debug("%s: peerid '%s'", __func__, s+1); } @@ -328,8 +329,8 @@ sa_stateflags(struct iked_sa *sa, u_int flags) log_debug("%s: 0x%02x -> 0x%02x %s (required 0x%02x %s)", __func__, sa->sa_stateflags, sa->sa_stateflags | flags, - print_bits(sa->sa_stateflags | flags, IKED_REQ_BITS), require, - print_bits(require, IKED_REQ_BITS)); + print_bits(sa->sa_stateflags | flags, (u_char *)IKED_REQ_BITS), + require, print_bits(require, (u_char *)IKED_REQ_BITS)); sa->sa_stateflags |= flags; } @@ -353,7 +354,7 @@ sa_stateok(struct iked_sa *sa, int state) log_debug("%s: %s flags 0x%02x, require 0x%02x %s", __func__, print_map(state, ikev2_state_map), (sa->sa_stateflags & require), require, - print_bits(require, IKED_REQ_BITS)); + print_bits(require, (u_char *)IKED_REQ_BITS)); if ((sa->sa_stateflags & require) != require) return (0); /* not ready, ignore */ From 79508e5193beef02fa224101a31d3c6fdea5c3f7 Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Tue, 7 Jun 2016 10:23:37 -0700 Subject: [PATCH 09/39] Revert adding subdir-objects until I understand why it causes a build failure (ikectl-log.Po) --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 43dec5c..8648bf1 100644 --- a/configure.ac +++ b/configure.ac @@ -22,7 +22,7 @@ AC_CONFIG_HEADER([config.h]) AC_CANONICAL_HOST AC_C_BIGENDIAN -AM_INIT_AUTOMAKE([subdir-objects]) +AM_INIT_AUTOMAKE() # Checks for programs. AC_PROG_CC From ee6b58bf0993c703701a3e72c4d6f5d47cf17c25 Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Tue, 7 Jun 2016 11:24:29 -0700 Subject: [PATCH 10/39] Fix more build warnings. --- ikectl/parser.c | 1 - iked/ca.c | 8 +++++--- iked/chap_ms.c | 8 ++++---- iked/config.c | 2 +- iked/eap.c | 8 ++++---- iked/ikev2.c | 12 +++++++----- iked/ikev2_msg.c | 4 ++-- iked/log.c | 2 +- iked/parse.y | 27 ++++++++++++++------------- iked/util.c | 4 ++-- 10 files changed, 40 insertions(+), 36 deletions(-) diff --git a/ikectl/parser.c b/ikectl/parser.c index 6c21436..af88b1d 100644 --- a/ikectl/parser.c +++ b/ikectl/parser.c @@ -67,7 +67,6 @@ static const struct token t_ca_ex_pass[]; static const struct token t_ca_modifiers[]; static const struct token t_ca_cert[]; static const struct token t_ca_cert_extusage[]; -static const struct token t_ca_cert_ex_peer[]; static const struct token t_ca_cert_modifiers[]; static const struct token t_ca_key[]; static const struct token t_ca_key_modifiers[]; diff --git a/iked/ca.c b/iked/ca.c index 59d8755..43a5e1b 100644 --- a/iked/ca.c +++ b/iked/ca.c @@ -537,7 +537,8 @@ ca_reload(struct iked *env) X509_OBJECT *xo; X509 *x509; DIR *dir; - int i, len, iovcnt = 0; + u_int len; + int i, iovcnt = 0; /* * Load CAs @@ -958,7 +959,8 @@ ca_x509_name_unescape(char *src, char *dst, char marker) void * ca_x509_name_parse(char *subject) { - char *cp, *value = NULL, *type = NULL; + u_char *value = NULL; + char *cp, *type = NULL; size_t maxlen; X509_NAME *name = NULL; @@ -988,7 +990,7 @@ ca_x509_name_parse(char *subject) goto err; } /* unescape value, terminated by '/' */ - cp = ca_x509_name_unescape(cp, value, '/'); + cp = ca_x509_name_unescape(cp, (char *)value, '/'); if (cp == NULL) { log_warnx("%s: could not parse value", __func__); goto err; diff --git a/iked/chap_ms.c b/iked/chap_ms.c index eea7907..23ca735 100644 --- a/iked/chap_ms.c +++ b/iked/chap_ms.c @@ -151,7 +151,7 @@ mschap_challenge_hash(u_int8_t *peer_challenge, u_int8_t *auth_challenge, u_int mdlen; u_int8_t *name; - if ((name = strrchr(username, '\\')) == NULL) + if ((name = (u_char *)strrchr((char *)username, '\\')) == NULL) name = username; else name++; @@ -159,7 +159,7 @@ mschap_challenge_hash(u_int8_t *peer_challenge, u_int8_t *auth_challenge, EVP_DigestInit(&ctx, EVP_sha1()); EVP_DigestUpdate(&ctx, peer_challenge, MSCHAPV2_CHALLENGE_SZ); EVP_DigestUpdate(&ctx, auth_challenge, MSCHAPV2_CHALLENGE_SZ); - EVP_DigestUpdate(&ctx, name, strlen(name)); + EVP_DigestUpdate(&ctx, name, strlen((char *)name)); EVP_DigestFinal(&ctx, md, &mdlen); memcpy(challenge, md, MSCHAP_CHALLENGE_SZ); @@ -341,7 +341,7 @@ mschap_radiuskey(u_int8_t *plain, const u_int8_t *crypted, u_int i, mdlen; EVP_DigestInit(&ctx, EVP_md5()); - EVP_DigestUpdate(&ctx, secret, strlen(secret)); + EVP_DigestUpdate(&ctx, (char *)secret, strlen((char *)secret)); EVP_DigestUpdate(&ctx, authenticator, 16); EVP_DigestUpdate(&ctx, crypted, 2); EVP_DigestFinal(&ctx, b, &mdlen); @@ -351,7 +351,7 @@ mschap_radiuskey(u_int8_t *plain, const u_int8_t *crypted, } EVP_DigestInit(&ctx, EVP_md5()); - EVP_DigestUpdate(&ctx, secret, strlen(secret)); + EVP_DigestUpdate(&ctx, secret, strlen((char *)secret)); EVP_DigestUpdate(&ctx, crypted + 2, mdlen); EVP_DigestFinal(&ctx, b, &mdlen); diff --git a/iked/config.c b/iked/config.c index c0382da..9ff9a3f 100644 --- a/iked/config.c +++ b/iked/config.c @@ -444,7 +444,7 @@ int config_getmode(struct iked *env, u_int type) { u_int8_t old; - u_char *mode[] = { "active", "passive" }; + char *mode[] = { "active", "passive" }; old = env->sc_passive ? 1 : 0; env->sc_passive = type == IMSG_CTL_PASSIVE ? 1 : 0; diff --git a/iked/eap.c b/iked/eap.c index a947a5d..5617641 100644 --- a/iked/eap.c +++ b/iked/eap.c @@ -235,8 +235,8 @@ eap_mschap(struct iked *env, struct iked_sa *sa, struct eap_message *eap) msp = &msr->msr_response.resp_peer; mschap_nt_response(ibuf_data(sa->sa_eap.id_buf), - msp->msp_challenge, usr->usr_name, strlen(usr->usr_name), - pass, passlen, ntresponse); + msp->msp_challenge, (u_char *)usr->usr_name, + strlen(usr->usr_name), pass, passlen, ntresponse); if (memcmp(ntresponse, msp->msp_ntresponse, sizeof(ntresponse)) != 0) { @@ -251,8 +251,8 @@ eap_mschap(struct iked *env, struct iked_sa *sa, struct eap_message *eap) bzero(&successmsg, sizeof(successmsg)); mschap_auth_response(pass, passlen, ntresponse, ibuf_data(sa->sa_eap.id_buf), - msp->msp_challenge, usr->usr_name, strlen(usr->usr_name), - successmsg); + msp->msp_challenge, (u_char *)usr->usr_name, + strlen(usr->usr_name), successmsg); if ((sa->sa_eapmsk = ibuf_new(NULL, MSCHAP_MSK_SZ)) == NULL) { log_debug("%s: failed to get MSK", __func__); free(pass); diff --git a/iked/ikev2.c b/iked/ikev2.c index 6e1a052..7d4663b 100644 --- a/iked/ikev2.c +++ b/iked/ikev2.c @@ -1169,8 +1169,8 @@ ikev2_policy2id(struct iked_static_id *polid, struct iked_id *id, int srcid) break; case IKEV2_ID_ASN1_DN: /* policy has ID in string-format, convert to ASN1 */ - if ((name = ca_x509_name_parse(polid->id_data)) == NULL || - (len = i2d_X509_NAME(name, NULL)) < 0 || + name = ca_x509_name_parse((char *)polid->id_data); + if (name == NULL || (len = i2d_X509_NAME(name, NULL)) < 0 || (p = ibuf_reserve(id->id_buf, len)) == NULL || (i2d_X509_NAME(name, &p)) < 0) { if (name) @@ -3263,16 +3263,19 @@ ikev2_ike_sa_alive(struct iked *env, void *arg) if (!csa->csa_loaded || csa->csa_saproto == IKEV2_SAPROTO_IPCOMP) continue; + gettimeofday(&tv, NULL); #if defined(_OPENBSD_IPSEC_API_VERSION) if (pfkey_sa_last_used(env->sc_pfkey, csa, &last_used) != 0) continue; +#else + last_used = tv.tv_sec; /* XXX */ #endif - gettimeofday(&tv, NULL); diff = (u_int32_t)(tv.tv_sec - last_used); log_debug("%s: %s CHILD SA spi %s last used %llu second(s) ago", __func__, csa->csa_dir == IPSP_DIRECTION_IN ? "incoming" : "outgoing", - print_spi(csa->csa_spi.spi, csa->csa_spi.spi_size), diff); + print_spi(csa->csa_spi.spi, csa->csa_spi.spi_size), + (unsigned long long)diff); if (diff < IKED_IKE_SA_ALIVE_TIMEOUT) { if (csa->csa_dir == IPSP_DIRECTION_IN) { foundin = 1; @@ -4634,7 +4637,6 @@ int ikev2_childsa_enable(struct iked *env, struct iked_sa *sa) { struct iked_childsa *csa; - struct iked_flow *flow, *oflow; if (sa->sa_ipcomp && sa->sa_cpi_in && sa->sa_cpi_out && ikev2_ipcomp_enable(env, sa) == -1) diff --git a/iked/ikev2_msg.c b/iked/ikev2_msg.c index 88ffefc..399273d 100644 --- a/iked/ikev2_msg.c +++ b/iked/ikev2_msg.c @@ -536,7 +536,7 @@ ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, hash_init(sa->sa_integr); hash_update(sa->sa_integr, ibuf_data(msg), ibuf_size(msg) - integrlen); - hash_final(sa->sa_integr, tmp->buf, &tmplen); + hash_final(sa->sa_integr, tmp->buf, (size_t *)&tmplen); if (memcmp(tmp->buf, ibuf_data(src) + integroff, integrlen) != 0) { log_debug("%s: integrity check failed", __func__); @@ -567,7 +567,7 @@ ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, if ((outlen = ibuf_length(out)) != 0) { cipher_update(sa->sa_encr, ibuf_data(src) + encroff, encrlen, - ibuf_data(out), &outlen); + ibuf_data(out), (size_t *)&outlen); ptr = ibuf_seek(out, outlen - 1, 1); pad = *ptr; diff --git a/iked/log.c b/iked/log.c index 7b31b71..a514efd 100644 --- a/iked/log.c +++ b/iked/log.c @@ -68,7 +68,7 @@ logit(int pri, const char *fmt, ...) void vlog(int pri, const char *fmt, va_list ap) { - char *nfmt; + vsyslog(pri, fmt, ap); } diff --git a/iked/parse.y b/iked/parse.y index 85bdc73..506b507 100644 --- a/iked/parse.y +++ b/iked/parse.y @@ -654,7 +654,7 @@ host_spec : STRING { | STRING '/' NUMBER { char *buf; - if (asprintf(&buf, "%s/%lld", $1, $3) == -1) + if (asprintf(&buf, "%s/%lld", $1, (long long)$3) == -1) err(1, "host: asprintf"); free($1); if (($$ = host(buf)) == NULL) { @@ -844,10 +844,10 @@ byte_spec : NUMBER { $$ = $1; } | STRING { - u_int64_t bytes = 0; + uintmax_t bytes = 0; char unit = 0; - if (sscanf($1, "%llu%c", &bytes, &unit) != 2) { + if (sscanf($1, "%ju%c", &bytes, &unit) != 2) { yyerror("invalid byte specification: %s", $1); YYERROR; } @@ -873,10 +873,10 @@ time_spec : NUMBER { $$ = $1; } | STRING { - u_int64_t seconds = 0; + uintmax_t seconds = 0; char unit = 0; - if (sscanf($1, "%llu%c", &seconds, &unit) != 2) { + if (sscanf($1, "%ju%c", &seconds, &unit) != 2) { yyerror("invalid time specification: %s", $1); YYERROR; } @@ -916,14 +916,14 @@ ikelifetime : /* empty */ { } keyspec : STRING { - u_int8_t *hex; + char *hex; bzero(&$$, sizeof($$)); hex = $1; if (strncmp(hex, "0x", 2) == 0) { hex += 2; - if (parsekey(hex, strlen(hex), &$$) != 0) { + if (parsekey((u_char *)hex, strlen(hex), &$$)) { free($1); YYERROR; } @@ -933,7 +933,7 @@ keyspec : STRING { free($1); YYERROR; } - strlcpy($$.auth_data, $1, + strlcpy((char *)$$.auth_data, $1, sizeof($$.auth_data)); $$.auth_length = strlen($1); } @@ -1234,8 +1234,8 @@ findeol(void) int yylex(void) { - u_char buf[8096]; - u_char *p, *val; + char buf[8096]; + char *p, *val; int quotec, next, c; int token; @@ -1270,7 +1270,7 @@ top: yyerror("macro '%s' not defined", buf); return (findeol()); } - parsebuf = val; + parsebuf = (u_char *)val; parseindex = 0; goto top; } @@ -2043,7 +2043,7 @@ ifa_grouplookup(const char *ifa_name) } free(ifgr.ifgr_groups); close(s); - + return (h); #else return (NULL); #endif @@ -2336,7 +2336,8 @@ print_policy(struct iked_policy *pol) print_verbose(" ikelifetime %u", pol->pol_rekey); print_verbose(" lifetime %llu bytes %llu", - pol->pol_lifetime.lt_seconds, pol->pol_lifetime.lt_bytes); + (unsigned long long)pol->pol_lifetime.lt_seconds, + (unsigned long long)pol->pol_lifetime.lt_bytes); if (pol->pol_auth.auth_method == IKEV2_AUTH_SHARED_KEY_MIC) { print_verbose(" psk 0x"); diff --git a/iked/util.c b/iked/util.c index cdabda5..96fa9df 100644 --- a/iked/util.c +++ b/iked/util.c @@ -426,10 +426,10 @@ print_spi(u_int64_t spi, int size) snprintf(ptr, 32, "0x%08x", (u_int32_t)spi); break; case 8: - snprintf(ptr, 32, "0x%016llx", spi); + snprintf(ptr, 32, "0x%016llx", (unsigned long long)spi); break; default: - snprintf(ptr, 32, "%llu", spi); + snprintf(ptr, 32, "%llu", (unsigned long long)spi); break; } From 6caf20b966a305c8ac8489b3f2a278b2a9d0f9c6 Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Tue, 7 Jun 2016 12:25:45 -0700 Subject: [PATCH 11/39] Indent using tabs. Whitespace change only --- iked/dh.h | 4 +- iked/iked.h | 6 +- iked/ikev2.c | 28 +- iked/parse.y | 10 +- iked/pfkey.c | 1980 ++++++++++++++++++------------------- iked/policy.c | 62 +- iked/timer.c | 2 +- iked/types.h | 4 +- iked/util.c | 170 ++-- openbsd-compat/defines.h | 36 +- openbsd-compat/sys-tree.h | 2 +- 11 files changed, 1152 insertions(+), 1152 deletions(-) diff --git a/iked/dh.h b/iked/dh.h index 1b058d3..f39d6e9 100644 --- a/iked/dh.h +++ b/iked/dh.h @@ -51,8 +51,8 @@ struct group { #define DH_MAXSZ 1024 /* 8192 bits */ -void group_init(void); -void group_free(struct group *); +void group_init(void); +void group_free(struct group *); struct group *group_get(u_int32_t); int dh_getlen(struct group *); diff --git a/iked/iked.h b/iked/iked.h index f050fa1..4b3db78 100644 --- a/iked/iked.h +++ b/iked/iked.h @@ -93,7 +93,7 @@ struct ctl_conn { struct imsgev iev; }; TAILQ_HEAD(ctl_connlist, ctl_conn); -extern struct ctl_connlist ctl_conns; +extern struct ctl_connlist ctl_conns; enum privsep_procid privsep_process; @@ -146,7 +146,7 @@ struct iked_flow { u_int8_t flow_saproto; u_int8_t flow_ipproto; u_int8_t flow_type; - u_int32_t flow_id; + u_int32_t flow_id; struct iked_addr *flow_local; /* outer source */ struct iked_addr *flow_peer; /* outer dest */ struct iked_sa *flow_ikesa; /* parent SA */ @@ -175,7 +175,7 @@ struct iked_childsa { u_int16_t csa_encrid; /* encryption xform id */ struct ibuf *csa_integrkey; /* auth key */ - u_int16_t csa_integrid; /* auth xform id */ + u_int16_t csa_integrid; /* auth xform id */ struct iked_addr *csa_local; /* outer source */ struct iked_addr *csa_peer; /* outer dest */ diff --git a/iked/ikev2.c b/iked/ikev2.c index 7d4663b..927ea48 100644 --- a/iked/ikev2.c +++ b/iked/ikev2.c @@ -2297,11 +2297,11 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) if (ret == 0) { sa_state(env, sa, IKEV2_STATE_ESTABLISHED); /** - * Logs about the secure session are tagged with LOG_SESSION - * so that it can be extracted for customer visiblity purposes - */ + * Logs about the secure session are tagged with LOG_SESSION + * so that it can be extracted for customer visiblity purposes + */ log_info("LOG_SESSION: Secure session established to peer %s \ - local %s", print_host((struct sockaddr *)&sa->sa_peer.addr, + local %s", print_host((struct sockaddr *)&sa->sa_peer.addr, NULL, 0), print_host((struct sockaddr *)&sa->sa_local.addr, NULL, 0)); timer_set(env, &sa->sa_timer, ikev2_ike_sa_alive, sa); @@ -2316,9 +2316,9 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) ikev2_childsa_delete(env, sa, 0, 0, NULL, 1); if (ret != 0) { log_info("LOG_SESSION: Authentication failure in establishing \ - secure session from %s to peer %s", - print_host((struct sockaddr *)&sa->sa_local.addr, NULL, 0), - print_host((struct sockaddr *)&sa->sa_peer.addr, NULL, 0)); + secure session from %s to peer %s", + print_host((struct sockaddr *)&sa->sa_local.addr, NULL, 0), + print_host((struct sockaddr *)&sa->sa_peer.addr, NULL, 0)); } ibuf_release(e); return (ret); @@ -2446,9 +2446,9 @@ int ikev2_set_sa_proposal(struct iked_sa *sa, struct iked_policy *pol, u_int proto) { - struct iked_proposal *prop, *copy; - struct iked_transform *xform; - u_int i; + struct iked_proposal *prop, *copy; + struct iked_transform *xform; + u_int i; /* create copy of the policy proposals */ config_free_proposals(&sa->sa_proposals, proto); @@ -2863,7 +2863,7 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) ret = ikev2_childsa_enable(env, sa); if ((ret == 0) && (csa)) { log_info("LOG_SESSION: Rekeying secure session key peer %s \ - local %s", print_host((struct sockaddr *)&sa->sa_peer.addr, + local %s", print_host((struct sockaddr *)&sa->sa_peer.addr, NULL, 0), print_host((struct sockaddr *)&sa->sa_local.addr, NULL, 0)); } @@ -2978,8 +2978,8 @@ ikev2_ikesa_enable(struct iked *env, struct iked_sa *sa, struct iked_sa *nsa) void ikev2_ikesa_delete(struct iked *env, struct iked_sa *sa, int initiator) { - struct ibuf *buf = NULL; - struct ikev2_delete *del; + struct ibuf *buf = NULL; + struct ikev2_delete *del; if (initiator) { /* Send PAYLOAD_DELETE */ @@ -3012,7 +3012,7 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) struct iked_childsa *csa; struct iked_proposal *prop; struct iked_proposals proposals; - struct iked_kex *kex, *kextmp = NULL; + struct iked_kex *kex, *kextmp = NULL; struct iked_sa *nsa = NULL, *sa = msg->msg_sa; struct iked_spi *spi, *rekey = &msg->msg_rekey; struct ikev2_keyexchange *ke; diff --git a/iked/parse.y b/iked/parse.y index 506b507..64dea70 100644 --- a/iked/parse.y +++ b/iked/parse.y @@ -667,7 +667,7 @@ host_spec : STRING { ; host : host_spec { $$ = $1; } - | host_spec '(' host_spec ')' { + | host_spec '(' host_spec ')' { if (($1->af != AF_UNSPEC) && ($3->af != AF_UNSPEC) && ($3->af != $1->af)) { yyerror("Flow NAT address family mismatch"); @@ -1973,8 +1973,8 @@ ifa_exists(const char *ifa_name) { struct ipsec_addr_wrap *n; #if defined(SIOCGIFGMEMB) - struct ifgroupreq ifgr; - int s; + struct ifgroupreq ifgr; + int s; #endif if (iftab == NULL) @@ -2045,7 +2045,7 @@ ifa_grouplookup(const char *ifa_name) close(s); return (h); #else - return (NULL); + return (NULL); #endif } @@ -2412,7 +2412,7 @@ create_ike(char *name, int af, u_int8_t ipproto, struct ipsec_hosts *hosts, struct ipsec_addr_wrap *ikecfg) { char idstr[IKED_ID_SIZE]; - u_int idtype = IKEV2_ID_NONE; + u_int idtype = IKEV2_ID_NONE; struct ipsec_addr_wrap *ipa, *ipb; struct iked_policy pol; struct iked_proposal prop[2]; diff --git a/iked/pfkey.c b/iked/pfkey.c index 8f989b6..c9f6193 100644 --- a/iked/pfkey.c +++ b/iked/pfkey.c @@ -70,61 +70,61 @@ struct pfkey_constmap { static const struct pfkey_constmap pfkey_encr[] = { #ifdef SADB_X_EALG_DES_IV64 - { SADB_X_EALG_DES_IV64, IKEV2_XFORMENCR_DES_IV64 }, + { SADB_X_EALG_DES_IV64, IKEV2_XFORMENCR_DES_IV64 }, #endif - { SADB_EALG_DESCBC, IKEV2_XFORMENCR_DES }, - { SADB_EALG_3DESCBC, IKEV2_XFORMENCR_3DES }, + { SADB_EALG_DESCBC, IKEV2_XFORMENCR_DES }, + { SADB_EALG_3DESCBC, IKEV2_XFORMENCR_3DES }, #ifdef SADB_X_EALG_RC5 - { SADB_X_EALG_RC5, IKEV2_XFORMENCR_RC5 }, + { SADB_X_EALG_RC5, IKEV2_XFORMENCR_RC5 }, #endif #ifdef SADB_X_EALG_IDEA - { SADB_X_EALG_IDEA, IKEV2_XFORMENCR_IDEA }, + { SADB_X_EALG_IDEA, IKEV2_XFORMENCR_IDEA }, #endif #ifdef SADB_X_EALG_RC5 - { SADB_X_EALG_CAST, IKEV2_XFORMENCR_CAST }, + { SADB_X_EALG_CAST, IKEV2_XFORMENCR_CAST }, #endif #ifdef SADB_X_EALG_BLF - { SADB_X_EALG_BLF, IKEV2_XFORMENCR_BLOWFISH }, + { SADB_X_EALG_BLF, IKEV2_XFORMENCR_BLOWFISH }, #endif #ifdef SADB_X_EALG_3IDEA - { SADB_X_EALG_3IDEA, IKEV2_XFORMENCR_3IDEA }, + { SADB_X_EALG_3IDEA, IKEV2_XFORMENCR_3IDEA }, #endif #ifdef SADB_X_EALG_DES_IV32 - { SADB_X_EALG_DES_IV32, IKEV2_XFORMENCR_DES_IV32 }, + { SADB_X_EALG_DES_IV32, IKEV2_XFORMENCR_DES_IV32 }, #endif #ifdef SADB_X_EALG_RC4 - { SADB_X_EALG_RC4, IKEV2_XFORMENCR_RC4 }, + { SADB_X_EALG_RC4, IKEV2_XFORMENCR_RC4 }, #endif - { SADB_EALG_NULL, IKEV2_XFORMENCR_NULL }, - { SADB_X_EALG_AES, IKEV2_XFORMENCR_AES_CBC }, + { SADB_EALG_NULL, IKEV2_XFORMENCR_NULL }, + { SADB_X_EALG_AES, IKEV2_XFORMENCR_AES_CBC }, #ifdef SADB_X_EALG_AESCTR - { SADB_X_EALG_AESCTR, IKEV2_XFORMENCR_AES_CTR }, + { SADB_X_EALG_AESCTR, IKEV2_XFORMENCR_AES_CTR }, #endif #ifdef SADB_X_EALG_AESGCM16 - { SADB_X_EALG_AESGCM16, IKEV2_XFORMENCR_AES_GCM_16 }, + { SADB_X_EALG_AESGCM16, IKEV2_XFORMENCR_AES_GCM_16 }, #endif #ifdef SADB_X_EALG_AESGMAC - { SADB_X_EALG_AESGMAC, IKEV2_XFORMENCR_NULL_AES_GMAC }, + { SADB_X_EALG_AESGMAC, IKEV2_XFORMENCR_NULL_AES_GMAC }, #endif - { 0 } + { 0 } }; static const struct pfkey_constmap pfkey_integr[] = { - { SADB_AALG_MD5HMAC, IKEV2_XFORMAUTH_HMAC_MD5_96 }, - { SADB_AALG_SHA1HMAC, IKEV2_XFORMAUTH_HMAC_SHA1_96 }, + { SADB_AALG_MD5HMAC, IKEV2_XFORMAUTH_HMAC_MD5_96 }, + { SADB_AALG_SHA1HMAC, IKEV2_XFORMAUTH_HMAC_SHA1_96 }, #ifdef SADB_X_AALG_DES - { SADB_X_AALG_DES, IKEV2_XFORMAUTH_DES_MAC }, + { SADB_X_AALG_DES, IKEV2_XFORMAUTH_DES_MAC }, #endif #if defined(SADB_X_AALG_SHA2_256) && !defined(BROKEN_HMAC_SHA2_256) - { SADB_X_AALG_SHA2_256, IKEV2_XFORMAUTH_HMAC_SHA2_256_128 }, + { SADB_X_AALG_SHA2_256, IKEV2_XFORMAUTH_HMAC_SHA2_256_128 }, #endif #ifdef SADB_X_AALG_SHA2_384 - { SADB_X_AALG_SHA2_384, IKEV2_XFORMAUTH_HMAC_SHA2_384_192 }, + { SADB_X_AALG_SHA2_384, IKEV2_XFORMAUTH_HMAC_SHA2_384_192 }, #endif #ifdef SADB_X_AALG_SHA2_512 - { SADB_X_AALG_SHA2_512, IKEV2_XFORMAUTH_HMAC_SHA2_512_256 }, + { SADB_X_AALG_SHA2_512, IKEV2_XFORMAUTH_HMAC_SHA2_512_256 }, #endif - { 0 } + { 0 } }; static const struct pfkey_constmap pfkey_satype[] = { @@ -210,792 +210,792 @@ int pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) { #if defined(_OPENBSD_IPSEC_API_VERSION) - struct sadb_msg smsg; - struct sadb_address sa_src, sa_dst, sa_local, sa_peer, sa_smask, - sa_dmask; - struct sadb_protocol sa_flowtype, sa_protocol; - struct sadb_ident *sa_srcid, *sa_dstid; - struct sockaddr_storage ssrc, sdst, slocal, speer, smask, dmask; - struct iovec iov[IOV_CNT]; - int iov_cnt, ret = -1; - in_port_t sport, dport; - - sport = dport = 0; - sa_srcid = sa_dstid = NULL; - - bzero(&ssrc, sizeof(ssrc)); - bzero(&smask, sizeof(smask)); - memcpy(&ssrc, &flow->flow_src.addr, sizeof(ssrc)); - memcpy(&smask, &flow->flow_src.addr, sizeof(smask)); - if ((sport = flow->flow_src.addr_port) != 0) - dport = 0xffff; - socket_af((struct sockaddr *)&ssrc, sport); - socket_af((struct sockaddr *)&smask, dport); - - switch (flow->flow_src.addr_af) { - case AF_INET: - ((struct sockaddr_in *)&smask)->sin_addr.s_addr = - prefixlen2mask(flow->flow_src.addr_net ? - flow->flow_src.addr_mask : 32); - break; - case AF_INET6: - prefixlen2mask6(flow->flow_src.addr_net ? - flow->flow_src.addr_mask : 128, - (u_int32_t *)((struct sockaddr_in6 *) - &smask)->sin6_addr.s6_addrek; - default: - log_warnx("%s: unsupported address family %d", - __func__, flow->flow_src.addr_af); - return (-1); - } - smask.ss_len = ssrc.ss_len; - - bzero(&sdst, sizeof(sdst)); - bzero(&dmask, sizeof(dmask)); - memcpy(&sdst, &flow->flow_dst.addr, sizeof(sdst)); - memcpy(&dmask, &flow->flow_dst.addr, sizeof(dmask)); - if ((sport = flow->flow_dst.addr_port) != 0) - dport = 0xffff; - socket_af((struct sockaddr *)&sdst, sport); - socket_af((struct sockaddr *)&dmask, dport); - - switch (flow->flow_dst.addr_af) { - case AF_INET: - ((struct sockaddr_in *)&dmask)->sin_addr.s_addr = - prefixlen2mask(flow->flow_dst.addr_net ? - flow->flow_dst.addr_mask : 32); - break; - case AF_INET6: - prefixlen2mask6(flow->flow_dst.addr_net ? - flow->flow_dst.addr_mask : 128, - (u_int32_t *)((struct sockaddr_in6 *) - &dmask)->sin6_addr.s6_addr); - break; - default: - log_warnx("%s: unsupported address family %d", - __func__, flow->flow_dst.addr_af); - return (-1); - } - dmask.ss_len = sdst.ss_len; - - bzero(&slocal, sizeof(slocal)); - bzero(&speer, sizeof(speer)); - if (action != SADB_X_DELFLOW && flow->flow_local != NULL) { - memcpy(&slocal, &flow->flow_local->addr, sizeof(slocal)); - socket_af((struct sockaddr *)&slocal, 0); - - memcpy(&speer, &flow->flow_peer->addr, sizeof(speer)); - socket_af((struct sockaddr *)&speer, 0); - } - - bzero(&smsg, sizeof(smsg)); - smsg.sadb_msg_version = PF_KEY_V2; - smsg.sadb_msg_seq = ++sadb_msg_seq; - smsg.sadb_msg_pid = getpid(); - smsg.sadb_msg_len = sizeof(smsg) / 8; - smsg.sadb_msg_type = action; - smsg.sadb_msg_satype = satype; - - bzero(&sa_flowtype, sizeof(sa_flowtype)); - sa_flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE; - sa_flowtype.sadb_protocol_len = sizeof(sa_flowtype) / 8; - sa_flowtype.sadb_protocol_direction = flow->flow_dir; - sa_flowtype.sadb_protocol_proto = - flow->flow_type ? flow->flow_type : - (flow->flow_dir == IPSP_DIRECTION_IN ? - SADB_X_FLOW_TYPE_USE : SADB_X_FLOW_TYPE_REQUIRE); - - bzero(&sa_protocol, sizeof(sa_protocol)); - sa_protocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; - sa_protocol.sadb_protocol_len = sizeof(sa_protocol) / 8; - sa_protocol.sadb_protocol_direction = 0; - sa_protocol.sadb_protocol_proto = flow->flow_ipproto; - - bzero(&sa_src, sizeof(sa_src)); - sa_src.sadb_address_exttype = SADB_X_EXT_SRC_FLOW; - sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; - - bzero(&sa_smask, sizeof(sa_smask)); - sa_smask.sadb_address_exttype = SADB_X_EXT_SRC_MASK; - sa_smask.sadb_address_len = - sa_smask.sadb_address_len = - (sizeof(sa_smask) + ROUNDUP(smask.ss_len)) / 8; - - bzero(&sa_dst, sizeof(sa_dst)); - sa_dst.sadb_address_exttype = SADB_X_EXT_DST_FLOW; - sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; - - bzero(&sa_dmask, sizeof(sa_dmask)); - sa_dmask.sadb_address_exttype = SADB_X_EXT_DST_MASK; - sa_dmask.sadb_address_len = - (sizeof(sa_dmask) + ROUNDUP(dmask.ss_len)) / 8; - - if (action != SADB_X_DELFLOW && flow->flow_local != NULL) { - /* local address */ - bzero(&sa_local, sizeof(sa_local)); - sa_local.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; - sa_local.sadb_address_len = - (sizeof(sa_local) + ROUNDUP(slocal.ss_len)) / 8; - - /* peer address */ - bzero(&sa_peer, sizeof(sa_peer)); - sa_peer.sadb_address_exttype = SADB_EXT_ADDRESS_DST; - sa_peer.sadb_address_len = - (sizeof(sa_peer) + ROUNDUP(speer.ss_len)) / 8; - - /* local id */ - sa_srcid = pfkey_id2ident(flow->flow_srcid, - SADB_EXT_IDENTITY_SRC); - - /* peer id */ - sa_dstid = pfkey_id2ident(flow->flow_dstid, - SADB_EXT_IDENTITY_DST); - } - - iov_cnt = 0; - - /* header */ - iov[iov_cnt].iov_base = &smsg; - iov[iov_cnt].iov_len = sizeof(smsg); - iov_cnt++; - - /* add flow type */ - iov[iov_cnt].iov_base = &sa_flowtype; - iov[iov_cnt].iov_len = sizeof(sa_flowtype); - smsg.sadb_msg_len += sa_flowtype.sadb_protocol_len; - iov_cnt++; - - if (action != SADB_X_DELFLOW && flow->flow_local != NULL) { + struct sadb_msg smsg; + struct sadb_address sa_src, sa_dst, sa_local, sa_peer, sa_smask, + sa_dmask; + struct sadb_protocol sa_flowtype, sa_protocol; + struct sadb_ident *sa_srcid, *sa_dstid; + struct sockaddr_storage ssrc, sdst, slocal, speer, smask, dmask; + struct iovec iov[IOV_CNT]; + int iov_cnt, ret = -1; + in_port_t sport, dport; + + sport = dport = 0; + sa_srcid = sa_dstid = NULL; + + bzero(&ssrc, sizeof(ssrc)); + bzero(&smask, sizeof(smask)); + memcpy(&ssrc, &flow->flow_src.addr, sizeof(ssrc)); + memcpy(&smask, &flow->flow_src.addr, sizeof(smask)); + if ((sport = flow->flow_src.addr_port) != 0) + dport = 0xffff; + socket_af((struct sockaddr *)&ssrc, sport); + socket_af((struct sockaddr *)&smask, dport); + + switch (flow->flow_src.addr_af) { + case AF_INET: + ((struct sockaddr_in *)&smask)->sin_addr.s_addr = + prefixlen2mask(flow->flow_src.addr_net ? + flow->flow_src.addr_mask : 32); + break; + case AF_INET6: + prefixlen2mask6(flow->flow_src.addr_net ? + flow->flow_src.addr_mask : 128, + (u_int32_t *)((struct sockaddr_in6 *) + &smask)->sin6_addr.s6_addrek; + default: + log_warnx("%s: unsupported address family %d", + __func__, flow->flow_src.addr_af); + return (-1); + } + smask.ss_len = ssrc.ss_len; + + bzero(&sdst, sizeof(sdst)); + bzero(&dmask, sizeof(dmask)); + memcpy(&sdst, &flow->flow_dst.addr, sizeof(sdst)); + memcpy(&dmask, &flow->flow_dst.addr, sizeof(dmask)); + if ((sport = flow->flow_dst.addr_port) != 0) + dport = 0xffff; + socket_af((struct sockaddr *)&sdst, sport); + socket_af((struct sockaddr *)&dmask, dport); + + switch (flow->flow_dst.addr_af) { + case AF_INET: + ((struct sockaddr_in *)&dmask)->sin_addr.s_addr = + prefixlen2mask(flow->flow_dst.addr_net ? + flow->flow_dst.addr_mask : 32); + break; + case AF_INET6: + prefixlen2mask6(flow->flow_dst.addr_net ? + flow->flow_dst.addr_mask : 128, + (u_int32_t *)((struct sockaddr_in6 *) + &dmask)->sin6_addr.s6_addr); + break; + default: + log_warnx("%s: unsupported address family %d", + __func__, flow->flow_dst.addr_af); + return (-1); + } + dmask.ss_len = sdst.ss_len; + + bzero(&slocal, sizeof(slocal)); + bzero(&speer, sizeof(speer)); + if (action != SADB_X_DELFLOW && flow->flow_local != NULL) { + memcpy(&slocal, &flow->flow_local->addr, sizeof(slocal)); + socket_af((struct sockaddr *)&slocal, 0); + + memcpy(&speer, &flow->flow_peer->addr, sizeof(speer)); + socket_af((struct sockaddr *)&speer, 0); + } + + bzero(&smsg, sizeof(smsg)); + smsg.sadb_msg_version = PF_KEY_V2; + smsg.sadb_msg_seq = ++sadb_msg_seq; + smsg.sadb_msg_pid = getpid(); + smsg.sadb_msg_len = sizeof(smsg) / 8; + smsg.sadb_msg_type = action; + smsg.sadb_msg_satype = satype; + + bzero(&sa_flowtype, sizeof(sa_flowtype)); + sa_flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE; + sa_flowtype.sadb_protocol_len = sizeof(sa_flowtype) / 8; + sa_flowtype.sadb_protocol_direction = flow->flow_dir; + sa_flowtype.sadb_protocol_proto = + flow->flow_type ? flow->flow_type : + (flow->flow_dir == IPSP_DIRECTION_IN ? + SADB_X_FLOW_TYPE_USE : SADB_X_FLOW_TYPE_REQUIRE); + + bzero(&sa_protocol, sizeof(sa_protocol)); + sa_protocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; + sa_protocol.sadb_protocol_len = sizeof(sa_protocol) / 8; + sa_protocol.sadb_protocol_direction = 0; + sa_protocol.sadb_protocol_proto = flow->flow_ipproto; + + bzero(&sa_src, sizeof(sa_src)); + sa_src.sadb_address_exttype = SADB_X_EXT_SRC_FLOW; + sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; + + bzero(&sa_smask, sizeof(sa_smask)); + sa_smask.sadb_address_exttype = SADB_X_EXT_SRC_MASK; + sa_smask.sadb_address_len = + sa_smask.sadb_address_len = + (sizeof(sa_smask) + ROUNDUP(smask.ss_len)) / 8; + + bzero(&sa_dst, sizeof(sa_dst)); + sa_dst.sadb_address_exttype = SADB_X_EXT_DST_FLOW; + sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; + + bzero(&sa_dmask, sizeof(sa_dmask)); + sa_dmask.sadb_address_exttype = SADB_X_EXT_DST_MASK; + sa_dmask.sadb_address_len = + (sizeof(sa_dmask) + ROUNDUP(dmask.ss_len)) / 8; + + if (action != SADB_X_DELFLOW && flow->flow_local != NULL) { + /* local address */ + bzero(&sa_local, sizeof(sa_local)); + sa_local.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + sa_local.sadb_address_len = + (sizeof(sa_local) + ROUNDUP(slocal.ss_len)) / 8; + + /* peer address */ + bzero(&sa_peer, sizeof(sa_peer)); + sa_peer.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + sa_peer.sadb_address_len = + (sizeof(sa_peer) + ROUNDUP(speer.ss_len)) / 8; + + /* local id */ + sa_srcid = pfkey_id2ident(flow->flow_srcid, + SADB_EXT_IDENTITY_SRC); + + /* peer id */ + sa_dstid = pfkey_id2ident(flow->flow_dstid, + SADB_EXT_IDENTITY_DST); + } + + iov_cnt = 0; + + /* header */ + iov[iov_cnt].iov_base = &smsg; + iov[iov_cnt].iov_len = sizeof(smsg); + iov_cnt++; + + /* add flow type */ + iov[iov_cnt].iov_base = &sa_flowtype; + iov[iov_cnt].iov_len = sizeof(sa_flowtype); + smsg.sadb_msg_len += sa_flowtype.sadb_protocol_len; + iov_cnt++; + + if (action != SADB_X_DELFLOW && flow->flow_local != NULL) { #if 0 - /* local ip */ - iov[iov_cnt].iov_base = &sa_local; - iov[iov_cnt].iov_len = sizeof(sa_local); - iov_cnt++; - iov[iov_cnt].iov_base = &slocal; - iov[iov_cnt].iov_len = ROUNDUP(slocal.ss_len); - smsg.sadb_msg_len += sa_local.sadb_address_len; - iov_cnt++; + /* local ip */ + iov[iov_cnt].iov_base = &sa_local; + iov[iov_cnt].iov_len = sizeof(sa_local); + iov_cnt++; + iov[iov_cnt].iov_base = &slocal; + iov[iov_cnt].iov_len = ROUNDUP(slocal.ss_len); + smsg.sadb_msg_len += sa_local.sadb_address_len; + iov_cnt++; #endif - /* remote peer */ - iov[iov_cnt].iov_base = &sa_peer; - iov[iov_cnt].iov_len = sizeof(sa_peer); - iov_cnt++; - iov[iov_cnt].iov_base = &speer; - iov[iov_cnt].iov_len = ROUNDUP(speer.ss_len); - smsg.sadb_msg_len += sa_peer.sadb_address_len; - iov_cnt++; - } - - /* src addr */ - iov[iov_cnt].iov_base = &sa_src; - iov[iov_cnt].iov_len = sizeof(sa_src); - iov_cnt++; - iov[iov_cnt].iov_base = &ssrc; - iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); - smsg.sadb_msg_len += sa_src.sadb_address_len; - iov_cnt++; - - /* src mask */ - iov[iov_cnt].iov_base = &sa_smask; - iov[iov_cnt].iov_len = sizeof(sa_smask); - iov_cnt++; - iov[iov_cnt].iov_base = &smask; - iov[iov_cnt].iov_len = ROUNDUP(smask.ss_len); - smsg.sadb_msg_len += sa_smask.sadb_address_len; - iov_cnt++; - - /* dest addr */ - iov[iov_cnt].iov_base = &sa_dst; - iov[iov_cnt].iov_len = sizeof(sa_dst); - iov_cnt++; - iov[iov_cnt].iov_base = &sdst; - iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); - smsg.sadb_msg_len += sa_dst.sadb_address_len; - iov_cnt++; - - /* dst mask */ - iov[iov_cnt].iov_base = &sa_dmask; - iov[iov_cnt].iov_len = sizeof(sa_dmask); - iov_cnt++; - iov[iov_cnt].iov_base = &dmask; - iov[iov_cnt].iov_len = ROUNDUP(dmask.ss_len); - smsg.sadb_msg_len += sa_dmask.sadb_address_len; - iov_cnt++; - - /* add protocol */ - iov[iov_cnt].iov_base = &sa_protocol; - iov[iov_cnt].iov_len = sizeof(sa_protocol); - smsg.sadb_msg_len += sa_protocol.sadb_protocol_len; - iov_cnt++; - - if (sa_srcid) { - /* src identity */ - iov[iov_cnt].iov_base = sa_srcid; - iov[iov_cnt].iov_len = sa_srcid->sadb_ident_len * 8; - smsg.sadb_msg_len += sa_srcid->sadb_ident_len; - iov_cnt++; - } - if (sa_dstid) { - /* dst identity */ - iov[iov_cnt].iov_base = sa_dstid; - iov[iov_cnt].iov_len = sa_dstid->sadb_ident_len * 8; - smsg.sadb_msg_len += sa_dstid->sadb_ident_len; - iov_cnt++; - } - - ret = pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL); - - if (sa_srcid) - free(sa_srcid); - if (sa_dstid) - free(sa_dstid); + /* remote peer */ + iov[iov_cnt].iov_base = &sa_peer; + iov[iov_cnt].iov_len = sizeof(sa_peer); + iov_cnt++; + iov[iov_cnt].iov_base = &speer; + iov[iov_cnt].iov_len = ROUNDUP(speer.ss_len); + smsg.sadb_msg_len += sa_peer.sadb_address_len; + iov_cnt++; + } + + /* src addr */ + iov[iov_cnt].iov_base = &sa_src; + iov[iov_cnt].iov_len = sizeof(sa_src); + iov_cnt++; + iov[iov_cnt].iov_base = &ssrc; + iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); + smsg.sadb_msg_len += sa_src.sadb_address_len; + iov_cnt++; + + /* src mask */ + iov[iov_cnt].iov_base = &sa_smask; + iov[iov_cnt].iov_len = sizeof(sa_smask); + iov_cnt++; + iov[iov_cnt].iov_base = &smask; + iov[iov_cnt].iov_len = ROUNDUP(smask.ss_len); + smsg.sadb_msg_len += sa_smask.sadb_address_len; + iov_cnt++; + + /* dest addr */ + iov[iov_cnt].iov_base = &sa_dst; + iov[iov_cnt].iov_len = sizeof(sa_dst); + iov_cnt++; + iov[iov_cnt].iov_base = &sdst; + iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); + smsg.sadb_msg_len += sa_dst.sadb_address_len; + iov_cnt++; + + /* dst mask */ + iov[iov_cnt].iov_base = &sa_dmask; + iov[iov_cnt].iov_len = sizeof(sa_dmask); + iov_cnt++; + iov[iov_cnt].iov_base = &dmask; + iov[iov_cnt].iov_len = ROUNDUP(dmask.ss_len); + smsg.sadb_msg_len += sa_dmask.sadb_address_len; + iov_cnt++; + + /* add protocol */ + iov[iov_cnt].iov_base = &sa_protocol; + iov[iov_cnt].iov_len = sizeof(sa_protocol); + smsg.sadb_msg_len += sa_protocol.sadb_protocol_len; + iov_cnt++; + + if (sa_srcid) { + /* src identity */ + iov[iov_cnt].iov_base = sa_srcid; + iov[iov_cnt].iov_len = sa_srcid->sadb_ident_len * 8; + smsg.sadb_msg_len += sa_srcid->sadb_ident_len; + iov_cnt++; + } + if (sa_dstid) { + /* dst identity */ + iov[iov_cnt].iov_base = sa_dstid; + iov[iov_cnt].iov_len = sa_dstid->sadb_ident_len * 8; + smsg.sadb_msg_len += sa_dstid->sadb_ident_len; + iov_cnt++; + } + + ret = pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL); + + if (sa_srcid) + free(sa_srcid); + if (sa_dstid) + free(sa_dstid); #else /* !_OPENBSD_IPSEC_API_VERSION */ - struct sadb_msg smsg; - struct sadb_address sa_src, sa_dst; - struct sadb_x_ipsecrequest sa_ipsec; - struct sadb_x_policy sa_policy, *sa_polid; - struct sadb_x_sa2 sa_2; - struct sockaddr_storage ssrc, sdst, slocal, speer; - struct iovec iov[10]; - int iov_cnt, ret = -1; - in_port_t sport, dport; - u_int8_t smask, dmask; - u_int8_t zeropad[8]; - size_t padlen; - u_int8_t *reply = NULL; - ssize_t rlen; - - bzero(&ssrc, sizeof(ssrc)); - memcpy(&ssrc, &flow->flow_src.addr, sizeof(ssrc)); - sport = flow->flow_src.addr_port; - socket_af((struct sockaddr *)&ssrc, sport); - - switch (flow->flow_src.addr_af) { - case AF_INET: - smask = flow->flow_src.addr_net ? - flow->flow_src.addr_mask : 32; - break; - case AF_INET6: - smask = flow->flow_src.addr_net ? - flow->flow_src.addr_mask : 128; - break; - default: - log_warnx("%s: unsupported address family %d", - __func__, flow->flow_src.addr_af); - return (-1); - } - - bzero(&sdst, sizeof(sdst)); - memcpy(&sdst, &flow->flow_dst.addr, sizeof(sdst)); - dport = flow->flow_dst.addr_port; - socket_af((struct sockaddr *)&sdst, dport); - - switch (flow->flow_dst.addr_af) { - case AF_INET: - dmask = flow->flow_dst.addr_net ? - flow->flow_dst.addr_mask : 32; - break; - case AF_INET6: - dmask = flow->flow_dst.addr_net ? - flow->flow_dst.addr_mask : 128; - break; - default: - log_warnx("%s: unsupported address family %d", - __func__, flow->flow_dst.addr_af); - return (-1); - } - - bzero(&slocal, sizeof(slocal)); - bzero(&speer, sizeof(speer)); - bzero(&zeropad, sizeof(zeropad)); - if (flow->flow_local == NULL) { - slocal.ss_family = flow->flow_src.addr_af; - speer.ss_family = flow->flow_dst.addr_af; - } else if (flow->flow_dir == IPSEC_DIR_INBOUND) { - memcpy(&speer, &flow->flow_local->addr, sizeof(slocal)); - memcpy(&slocal, &flow->flow_peer->addr, sizeof(speer)); - } else { - memcpy(&slocal, &flow->flow_local->addr, sizeof(slocal)); - memcpy(&speer, &flow->flow_peer->addr, sizeof(speer)); - } - socket_af((struct sockaddr *)&slocal, 0); - socket_af((struct sockaddr *)&speer, 0); - - bzero(&smsg, sizeof(smsg)); - smsg.sadb_msg_version = PF_KEY_V2; - smsg.sadb_msg_seq = ++sadb_msg_seq; - smsg.sadb_msg_pid = getpid(); - smsg.sadb_msg_len = sizeof(smsg) / 8; - smsg.sadb_msg_type = action; - smsg.sadb_msg_satype = SADB_SATYPE_UNSPEC; - - bzero(&sa_2, sizeof(sa_2)); - sa_2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - sa_2.sadb_x_sa2_len = sizeof(sa_2) / 8; - sa_2.sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT; - - bzero(&sa_src, sizeof(sa_src)); - sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; - sa_src.sadb_address_proto = IPSEC_ULPROTO_ANY; //flow->flow_ipproto - sa_src.sadb_address_prefixlen = smask; - sa_src.sadb_address_len = ROUNDUP(sizeof(sa_src) + SS_LEN(&ssrc)) / 8; - - bzero(&sa_dst, sizeof(sa_dst)); - sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; - sa_dst.sadb_address_proto = IPSEC_ULPROTO_ANY; //flow->flow_ipproto; - sa_dst.sadb_address_prefixlen = dmask; - sa_dst.sadb_address_len = ROUNDUP(sizeof(sa_dst) + SS_LEN(&sdst)) / 8; - - bzero(&sa_policy, sizeof(sa_policy)); - sa_policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY; - sa_policy.sadb_x_policy_dir = flow->flow_dir; - - switch (flow->flow_type) { - case SADB_X_FLOW_TYPE_DENY: - sa_policy.sadb_x_policy_type = IPSEC_POLICY_DISCARD; - sa_policy.sadb_x_policy_len = sizeof(sa_policy) / 8; - break; - default: - sa_policy.sadb_x_policy_type = IPSEC_POLICY_IPSEC; - bzero(&sa_ipsec, sizeof(sa_ipsec)); - sa_ipsec.sadb_x_ipsecrequest_proto = - satype == SADB_SATYPE_AH ? IPPROTO_AH : IPPROTO_ESP; - sa_ipsec.sadb_x_ipsecrequest_mode = IPSEC_MODE_TRANSPORT; /* XXX */ - sa_ipsec.sadb_x_ipsecrequest_level = - flow->flow_dir == IPSEC_DIR_INBOUND ? - IPSEC_LEVEL_USE : IPSEC_LEVEL_REQUIRE; - sa_ipsec.sadb_x_ipsecrequest_len = sizeof(sa_ipsec) + - SS_LEN(&slocal) + SS_LEN(&speer); - padlen = ROUNDUP(sa_ipsec.sadb_x_ipsecrequest_len) - - sa_ipsec.sadb_x_ipsecrequest_len; - sa_ipsec.sadb_x_ipsecrequest_len += padlen; - sa_policy.sadb_x_policy_len = - (sizeof(sa_policy) + - sa_ipsec.sadb_x_ipsecrequest_len) / 8; - break; - } - - iov_cnt = 0; - - /* header */ - iov[iov_cnt].iov_base = &smsg; - iov[iov_cnt].iov_len = sizeof(smsg); - iov_cnt++; - - /* add flow SA2 */ - iov[iov_cnt].iov_base = &sa_2; - iov[iov_cnt].iov_len = sizeof(sa_2); - smsg.sadb_msg_len += sa_2.sadb_x_sa2_len; - iov_cnt++; - - /* add source address */ - iov[iov_cnt].iov_base = &sa_src; - iov[iov_cnt].iov_len = sizeof(sa_src); - iov_cnt++; - iov[iov_cnt].iov_base = &ssrc; - iov[iov_cnt].iov_len = SS_LEN(&ssrc); - smsg.sadb_msg_len += sa_src.sadb_address_len; - iov_cnt++; - - /* add destination address */ - iov[iov_cnt].iov_base = &sa_dst; - iov[iov_cnt].iov_len = sizeof(sa_dst); - iov_cnt++; - iov[iov_cnt].iov_base = &sdst; - iov[iov_cnt].iov_len = SS_LEN(&sdst); - smsg.sadb_msg_len += sa_dst.sadb_address_len; - iov_cnt++; - - /* add policy extension */ - iov[iov_cnt].iov_base = &sa_policy; - iov[iov_cnt].iov_len = sizeof(sa_policy); - smsg.sadb_msg_len += sa_policy.sadb_x_policy_len; - iov_cnt++; - - if (sa_policy.sadb_x_policy_type == IPSEC_POLICY_IPSEC) { - iov[iov_cnt].iov_base = &sa_ipsec; - iov[iov_cnt].iov_len = sizeof(sa_ipsec); - iov_cnt++; - iov[iov_cnt].iov_base = &slocal; - iov[iov_cnt].iov_len = SS_LEN(&slocal); - iov_cnt++; - iov[iov_cnt].iov_base = &speer; - iov[iov_cnt].iov_len = SS_LEN(&speer); - if (padlen) { - iov_cnt++; - iov[iov_cnt].iov_base = zeropad; - iov[iov_cnt].iov_len = padlen; - } - iov_cnt++; - } - - ret = -1; - if (pfkey_write(sd, &smsg, iov, iov_cnt, &reply, &rlen) != 0) - goto done; - - if ((sa_polid = pfkey_find_ext(reply, rlen, - SADB_X_EXT_POLICY)) == NULL) { - log_debug("%s: erronous reply", __func__); - goto done; - } - flow->flow_id = sa_polid->sadb_x_policy_id; - - log_debug("%s: flow with policy id 0x%x", __func__, flow->flow_id); - ret = 0; + struct sadb_msg smsg; + struct sadb_address sa_src, sa_dst; + struct sadb_x_ipsecrequest sa_ipsec; + struct sadb_x_policy sa_policy, *sa_polid; + struct sadb_x_sa2 sa_2; + struct sockaddr_storage ssrc, sdst, slocal, speer; + struct iovec iov[10]; + int iov_cnt, ret = -1; + in_port_t sport, dport; + u_int8_t smask, dmask; + u_int8_t zeropad[8]; + size_t padlen; + u_int8_t *reply = NULL; + ssize_t rlen; + + bzero(&ssrc, sizeof(ssrc)); + memcpy(&ssrc, &flow->flow_src.addr, sizeof(ssrc)); + sport = flow->flow_src.addr_port; + socket_af((struct sockaddr *)&ssrc, sport); + + switch (flow->flow_src.addr_af) { + case AF_INET: + smask = flow->flow_src.addr_net ? + flow->flow_src.addr_mask : 32; + break; + case AF_INET6: + smask = flow->flow_src.addr_net ? + flow->flow_src.addr_mask : 128; + break; + default: + log_warnx("%s: unsupported address family %d", + __func__, flow->flow_src.addr_af); + return (-1); + } + + bzero(&sdst, sizeof(sdst)); + memcpy(&sdst, &flow->flow_dst.addr, sizeof(sdst)); + dport = flow->flow_dst.addr_port; + socket_af((struct sockaddr *)&sdst, dport); + + switch (flow->flow_dst.addr_af) { + case AF_INET: + dmask = flow->flow_dst.addr_net ? + flow->flow_dst.addr_mask : 32; + break; + case AF_INET6: + dmask = flow->flow_dst.addr_net ? + flow->flow_dst.addr_mask : 128; + break; + default: + log_warnx("%s: unsupported address family %d", + __func__, flow->flow_dst.addr_af); + return (-1); + } + + bzero(&slocal, sizeof(slocal)); + bzero(&speer, sizeof(speer)); + bzero(&zeropad, sizeof(zeropad)); + if (flow->flow_local == NULL) { + slocal.ss_family = flow->flow_src.addr_af; + speer.ss_family = flow->flow_dst.addr_af; + } else if (flow->flow_dir == IPSEC_DIR_INBOUND) { + memcpy(&speer, &flow->flow_local->addr, sizeof(slocal)); + memcpy(&slocal, &flow->flow_peer->addr, sizeof(speer)); + } else { + memcpy(&slocal, &flow->flow_local->addr, sizeof(slocal)); + memcpy(&speer, &flow->flow_peer->addr, sizeof(speer)); + } + socket_af((struct sockaddr *)&slocal, 0); + socket_af((struct sockaddr *)&speer, 0); + + bzero(&smsg, sizeof(smsg)); + smsg.sadb_msg_version = PF_KEY_V2; + smsg.sadb_msg_seq = ++sadb_msg_seq; + smsg.sadb_msg_pid = getpid(); + smsg.sadb_msg_len = sizeof(smsg) / 8; + smsg.sadb_msg_type = action; + smsg.sadb_msg_satype = SADB_SATYPE_UNSPEC; + + bzero(&sa_2, sizeof(sa_2)); + sa_2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; + sa_2.sadb_x_sa2_len = sizeof(sa_2) / 8; + sa_2.sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT; + + bzero(&sa_src, sizeof(sa_src)); + sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + sa_src.sadb_address_proto = IPSEC_ULPROTO_ANY; //flow->flow_ipproto + sa_src.sadb_address_prefixlen = smask; + sa_src.sadb_address_len = ROUNDUP(sizeof(sa_src) + SS_LEN(&ssrc)) / 8; + + bzero(&sa_dst, sizeof(sa_dst)); + sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + sa_dst.sadb_address_proto = IPSEC_ULPROTO_ANY; //flow->flow_ipproto; + sa_dst.sadb_address_prefixlen = dmask; + sa_dst.sadb_address_len = ROUNDUP(sizeof(sa_dst) + SS_LEN(&sdst)) / 8; + + bzero(&sa_policy, sizeof(sa_policy)); + sa_policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY; + sa_policy.sadb_x_policy_dir = flow->flow_dir; + + switch (flow->flow_type) { + case SADB_X_FLOW_TYPE_DENY: + sa_policy.sadb_x_policy_type = IPSEC_POLICY_DISCARD; + sa_policy.sadb_x_policy_len = sizeof(sa_policy) / 8; + break; + default: + sa_policy.sadb_x_policy_type = IPSEC_POLICY_IPSEC; + bzero(&sa_ipsec, sizeof(sa_ipsec)); + sa_ipsec.sadb_x_ipsecrequest_proto = + satype == SADB_SATYPE_AH ? IPPROTO_AH : IPPROTO_ESP; + sa_ipsec.sadb_x_ipsecrequest_mode = IPSEC_MODE_TRANSPORT; /* XXX */ + sa_ipsec.sadb_x_ipsecrequest_level = + flow->flow_dir == IPSEC_DIR_INBOUND ? + IPSEC_LEVEL_USE : IPSEC_LEVEL_REQUIRE; + sa_ipsec.sadb_x_ipsecrequest_len = sizeof(sa_ipsec) + + SS_LEN(&slocal) + SS_LEN(&speer); + padlen = ROUNDUP(sa_ipsec.sadb_x_ipsecrequest_len) - + sa_ipsec.sadb_x_ipsecrequest_len; + sa_ipsec.sadb_x_ipsecrequest_len += padlen; + sa_policy.sadb_x_policy_len = + (sizeof(sa_policy) + + sa_ipsec.sadb_x_ipsecrequest_len) / 8; + break; + } + + iov_cnt = 0; + + /* header */ + iov[iov_cnt].iov_base = &smsg; + iov[iov_cnt].iov_len = sizeof(smsg); + iov_cnt++; + + /* add flow SA2 */ + iov[iov_cnt].iov_base = &sa_2; + iov[iov_cnt].iov_len = sizeof(sa_2); + smsg.sadb_msg_len += sa_2.sadb_x_sa2_len; + iov_cnt++; + + /* add source address */ + iov[iov_cnt].iov_base = &sa_src; + iov[iov_cnt].iov_len = sizeof(sa_src); + iov_cnt++; + iov[iov_cnt].iov_base = &ssrc; + iov[iov_cnt].iov_len = SS_LEN(&ssrc); + smsg.sadb_msg_len += sa_src.sadb_address_len; + iov_cnt++; + + /* add destination address */ + iov[iov_cnt].iov_base = &sa_dst; + iov[iov_cnt].iov_len = sizeof(sa_dst); + iov_cnt++; + iov[iov_cnt].iov_base = &sdst; + iov[iov_cnt].iov_len = SS_LEN(&sdst); + smsg.sadb_msg_len += sa_dst.sadb_address_len; + iov_cnt++; + + /* add policy extension */ + iov[iov_cnt].iov_base = &sa_policy; + iov[iov_cnt].iov_len = sizeof(sa_policy); + smsg.sadb_msg_len += sa_policy.sadb_x_policy_len; + iov_cnt++; + + if (sa_policy.sadb_x_policy_type == IPSEC_POLICY_IPSEC) { + iov[iov_cnt].iov_base = &sa_ipsec; + iov[iov_cnt].iov_len = sizeof(sa_ipsec); + iov_cnt++; + iov[iov_cnt].iov_base = &slocal; + iov[iov_cnt].iov_len = SS_LEN(&slocal); + iov_cnt++; + iov[iov_cnt].iov_base = &speer; + iov[iov_cnt].iov_len = SS_LEN(&speer); + if (padlen) { + iov_cnt++; + iov[iov_cnt].iov_base = zeropad; + iov[iov_cnt].iov_len = padlen; + } + iov_cnt++; + } + + ret = -1; + if (pfkey_write(sd, &smsg, iov, iov_cnt, &reply, &rlen) != 0) + goto done; + + if ((sa_polid = pfkey_find_ext(reply, rlen, + SADB_X_EXT_POLICY)) == NULL) { + log_debug("%s: erronous reply", __func__); + goto done; + } + flow->flow_id = sa_polid->sadb_x_policy_id; + + log_debug("%s: flow with policy id 0x%x", __func__, flow->flow_id); + ret = 0; done: - free(reply); + free(reply); #endif /* !_OPENBSD_IPSEC_API_VERSION */ - return (ret); + return (ret); } int pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) { - struct sadb_msg smsg; - struct sadb_sa sadb; - struct sadb_address sa_src, sa_dst; - struct sadb_key sa_authkey, sa_enckey; - struct sadb_lifetime sa_ltime_hard, sa_ltime_soft; + struct sadb_msg smsg; + struct sadb_sa sadb; + struct sadb_address sa_src, sa_dst; + struct sadb_key sa_authkey, sa_enckey; + struct sadb_lifetime sa_ltime_hard, sa_ltime_soft; #if defined(_OPENBSD_IPSEC_API_VERSION) - struct sadb_x_udpencap udpencap; - struct sadb_x_tag sa_tag; - char *tag = NULL; - struct sadb_x_tap sa_tap; + struct sadb_x_udpencap udpencap; + struct sadb_x_tag sa_tag; + char *tag = NULL; + struct sadb_x_tap sa_tap; #else - struct sadb_x_sa2 sa_2; + struct sadb_x_sa2 sa_2; #if defined(HAVE_APPLE_NATT) - struct sadb_sa_natt natt; + struct sadb_sa_natt natt; #endif #endif - struct sockaddr_storage ssrc, sdst; - struct sadb_ident *sa_srcid, *sa_dstid; - struct iked_lifetime *lt; - struct iked_policy *pol; - struct iovec iov[IOV_CNT]; - u_int32_t jitter; - int iov_cnt; - - sa_srcid = sa_dstid = NULL; - - if (sa->csa_ikesa == NULL || sa->csa_ikesa->sa_policy == NULL) { - log_warn("%s: invalid SA and policy", __func__); - return (-1); - } - pol = sa->csa_ikesa->sa_policy; - lt = &pol->pol_lifetime; - - bzero(&ssrc, sizeof(ssrc)); - memcpy(&ssrc, &sa->csa_local->addr, sizeof(ssrc)); - if (socket_af((struct sockaddr *)&ssrc, 0) == -1) { - log_warn("%s: invalid address", __func__); - return (-1); - } - - bzero(&sdst, sizeof(sdst)); - memcpy(&sdst, &sa->csa_peer->addr, sizeof(sdst)); - if (socket_af((struct sockaddr *)&sdst, 0) == -1) { - log_warn("%s: invalid address", __func__); - return (-1); - } - - bzero(&smsg, sizeof(smsg)); - smsg.sadb_msg_version = PF_KEY_V2; - smsg.sadb_msg_seq = ++sadb_msg_seq; - smsg.sadb_msg_pid = getpid(); - smsg.sadb_msg_len = sizeof(smsg) / 8; - smsg.sadb_msg_type = action; - smsg.sadb_msg_satype = satype; - - bzero(&sadb, sizeof(sadb)); - sadb.sadb_sa_len = sizeof(sadb) / 8; - sadb.sadb_sa_exttype = SADB_EXT_SA; - sadb.sadb_sa_spi = htonl(sa->csa_spi.spi); - sadb.sadb_sa_state = SADB_SASTATE_MATURE; - sadb.sadb_sa_replay = 64; + struct sockaddr_storage ssrc, sdst; + struct sadb_ident *sa_srcid, *sa_dstid; + struct iked_lifetime *lt; + struct iked_policy *pol; + struct iovec iov[IOV_CNT]; + u_int32_t jitter; + int iov_cnt; + + sa_srcid = sa_dstid = NULL; + + if (sa->csa_ikesa == NULL || sa->csa_ikesa->sa_policy == NULL) { + log_warn("%s: invalid SA and policy", __func__); + return (-1); + } + pol = sa->csa_ikesa->sa_policy; + lt = &pol->pol_lifetime; + + bzero(&ssrc, sizeof(ssrc)); + memcpy(&ssrc, &sa->csa_local->addr, sizeof(ssrc)); + if (socket_af((struct sockaddr *)&ssrc, 0) == -1) { + log_warn("%s: invalid address", __func__); + return (-1); + } + + bzero(&sdst, sizeof(sdst)); + memcpy(&sdst, &sa->csa_peer->addr, sizeof(sdst)); + if (socket_af((struct sockaddr *)&sdst, 0) == -1) { + log_warn("%s: invalid address", __func__); + return (-1); + } + + bzero(&smsg, sizeof(smsg)); + smsg.sadb_msg_version = PF_KEY_V2; + smsg.sadb_msg_seq = ++sadb_msg_seq; + smsg.sadb_msg_pid = getpid(); + smsg.sadb_msg_len = sizeof(smsg) / 8; + smsg.sadb_msg_type = action; + smsg.sadb_msg_satype = satype; + + bzero(&sadb, sizeof(sadb)); + sadb.sadb_sa_len = sizeof(sadb) / 8; + sadb.sadb_sa_exttype = SADB_EXT_SA; + sadb.sadb_sa_spi = htonl(sa->csa_spi.spi); + sadb.sadb_sa_state = SADB_SASTATE_MATURE; + sadb.sadb_sa_replay = 64; #if defined(_OPENBSD_IPSEC_API_VERSION) - /* XXX we don't support transport mode, yet */ - sadb.sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL; + /* XXX we don't support transport mode, yet */ + sadb.sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL; - if (sa->csa_esn) - sadb.sadb_sa_flags |= SADB_X_SAFLAGS_ESN; + if (sa->csa_esn) + sadb.sadb_sa_flags |= SADB_X_SAFLAGS_ESN; #else - bzero(&sa_2, sizeof(sa_2)); - sa_2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - sa_2.sadb_x_sa2_len = sizeof(sa_2) / 8; - sa_2.sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT; /* XXX */ + bzero(&sa_2, sizeof(sa_2)); + sa_2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; + sa_2.sadb_x_sa2_len = sizeof(sa_2) / 8; + sa_2.sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT; /* XXX */ #endif - bzero(&sa_src, sizeof(sa_src)); - sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(SS_LEN(&ssrc))) / 8; - sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + bzero(&sa_src, sizeof(sa_src)); + sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(SS_LEN(&ssrc))) / 8; + sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; - bzero(&sa_dst, sizeof(sa_dst)); - sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(SS_LEN(&sdst))) / 8; - sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + bzero(&sa_dst, sizeof(sa_dst)); + sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(SS_LEN(&sdst))) / 8; + sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; - bzero(&sa_authkey, sizeof(sa_authkey)); - bzero(&sa_enckey, sizeof(sa_enckey)); + bzero(&sa_authkey, sizeof(sa_authkey)); + bzero(&sa_enckey, sizeof(sa_enckey)); #if defined(_OPENBSD_IPSEC_API_VERSION) - bzero(&udpencap, sizeof udpencap); + bzero(&udpencap, sizeof udpencap); #elif defined(HAVE_APPLE_NATT) - bzero(&natt, sizeof(natt)); + bzero(&natt, sizeof(natt)); #endif - bzero(&sa_ltime_hard, sizeof(sa_ltime_hard)); - bzero(&sa_ltime_soft, sizeof(sa_ltime_soft)); - - if (action == SADB_DELETE) - goto send; - - if ((action == SADB_ADD || action == SADB_UPDATE) && - !sa->csa_persistent && (lt->lt_bytes || lt->lt_seconds)) { - sa_ltime_hard.sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; - sa_ltime_hard.sadb_lifetime_len = sizeof(sa_ltime_hard) / 8; - sa_ltime_hard.sadb_lifetime_bytes = lt->lt_bytes; - sa_ltime_hard.sadb_lifetime_addtime = lt->lt_seconds; - - sa_ltime_soft.sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; - sa_ltime_soft.sadb_lifetime_len = sizeof(sa_ltime_soft) / 8; - /* set randomly to 85-95% */ - jitter = 850 + arc4random_uniform(100); - sa_ltime_soft.sadb_lifetime_bytes = - (lt->lt_bytes * jitter) / 1000; - sa_ltime_soft.sadb_lifetime_addtime = - (lt->lt_seconds * jitter) / 1000; - } - - /* XXX handle NULL encryption or NULL auth or combined encr/auth */ - if (action == SADB_ADD && - !ibuf_length(sa->csa_integrkey) && !ibuf_length(sa->csa_encrkey) && - satype != SADB_X_SATYPE_IPCOMP + bzero(&sa_ltime_hard, sizeof(sa_ltime_hard)); + bzero(&sa_ltime_soft, sizeof(sa_ltime_soft)); + + if (action == SADB_DELETE) + goto send; + + if ((action == SADB_ADD || action == SADB_UPDATE) && + !sa->csa_persistent && (lt->lt_bytes || lt->lt_seconds)) { + sa_ltime_hard.sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; + sa_ltime_hard.sadb_lifetime_len = sizeof(sa_ltime_hard) / 8; + sa_ltime_hard.sadb_lifetime_bytes = lt->lt_bytes; + sa_ltime_hard.sadb_lifetime_addtime = lt->lt_seconds; + + sa_ltime_soft.sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; + sa_ltime_soft.sadb_lifetime_len = sizeof(sa_ltime_soft) / 8; + /* set randomly to 85-95% */ + jitter = 850 + arc4random_uniform(100); + sa_ltime_soft.sadb_lifetime_bytes = + (lt->lt_bytes * jitter) / 1000; + sa_ltime_soft.sadb_lifetime_addtime = + (lt->lt_seconds * jitter) / 1000; + } + + /* XXX handle NULL encryption or NULL auth or combined encr/auth */ + if (action == SADB_ADD && + !ibuf_length(sa->csa_integrkey) && !ibuf_length(sa->csa_encrkey) && + satype != SADB_X_SATYPE_IPCOMP #if defined(_OPENBSD_IPSEC_API_VERSION) - && satype != SADB_X_SATYPE_IPIP + && satype != SADB_X_SATYPE_IPIP #endif - ) { + ) { - log_warnx("%s: no key specified", __func__); - return (-1); - } + log_warnx("%s: no key specified", __func__); + return (-1); + } - if (sa->csa_ikesa->sa_udpencap && sa->csa_ikesa->sa_natt) { + if (sa->csa_ikesa->sa_udpencap && sa->csa_ikesa->sa_natt) { #if defined(_OPENBSD_IPSEC_API_VERSION) - sadb.sadb_sa_flags |= SADB_X_SAFLAGS_UDPENCAP; - udpencap.sadb_x_udpencap_exttype = SADB_X_EXT_UDPENCAP; - udpencap.sadb_x_udpencap_len = sizeof(udpencap) / 8; - udpencap.sadb_x_udpencap_port = - sa->csa_ikesa->sa_peer.addr_port; + sadb.sadb_sa_flags |= SADB_X_SAFLAGS_UDPENCAP; + udpencap.sadb_x_udpencap_exttype = SADB_X_EXT_UDPENCAP; + udpencap.sadb_x_udpencap_len = sizeof(udpencap) / 8; + udpencap.sadb_x_udpencap_port = + sa->csa_ikesa->sa_peer.addr_port; #elif defined(HAVE_APPLE_NATT) - sadb.sadb_sa_flags |= SADB_X_EXT_NATT; - /* XXX check NAT detection for local/peer hash instead */ - if (sa->csa_dir == IPSP_DIRECTION_OUT) - sadb.sadb_sa_flags |= SADB_X_EXT_NATT_KEEPALIVE; - else - sadb.sadb_sa_flags |= SADB_X_EXT_NATT_DETECTED_PEER; - natt.sadb_sa_natt_port = - ntohs(sa->csa_ikesa->sa_peer.addr_port); + sadb.sadb_sa_flags |= SADB_X_EXT_NATT; + /* XXX check NAT detection for local/peer hash instead */ + if (sa->csa_dir == IPSP_DIRECTION_OUT) + sadb.sadb_sa_flags |= SADB_X_EXT_NATT_KEEPALIVE; + else + sadb.sadb_sa_flags |= SADB_X_EXT_NATT_DETECTED_PEER; + natt.sadb_sa_natt_port = + ntohs(sa->csa_ikesa->sa_peer.addr_port); #else //#warning PFKEYv2 NAT-T not supported #endif - log_debug("%s: udpencap port %u", __func__, - ntohs(sa->csa_ikesa->sa_peer.addr_port)); - } - - - if (sa->csa_integrid != 0) - if (pfkey_map(pfkey_integr, - sa->csa_integrid, &sadb.sadb_sa_auth) == -1) { - log_warnx("%s: unsupported integrity algorithm %s", - __func__, print_map(sa->csa_integrid, - ikev2_xformauth_map)); - return (-1); - } - - if (sa->csa_encrid != 0) - if (pfkey_map(pfkey_encr, - sa->csa_encrid, &sadb.sadb_sa_encrypt) == -1) { - log_warnx("%s: unsupported encryption algorithm %s", - __func__, print_map(sa->csa_encrid, - ikev2_xformencr_map)); - return (-1); - } - - if (ibuf_length(sa->csa_integrkey)) { - sa_authkey.sadb_key_len = (sizeof(sa_authkey) + - ((ibuf_size(sa->csa_integrkey) + 7) / 8) * 8) / 8; - sa_authkey.sadb_key_exttype = SADB_EXT_KEY_AUTH; - sa_authkey.sadb_key_bits = - 8 * ibuf_size(sa->csa_integrkey); - } - - if (ibuf_length(sa->csa_encrkey)) { - sa_enckey.sadb_key_len = (sizeof(sa_enckey) + - ((ibuf_size(sa->csa_encrkey) + 7) / 8) * 8) / 8; - sa_enckey.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; - sa_enckey.sadb_key_bits = - 8 * ibuf_size(sa->csa_encrkey); - } - - /* local id */ - sa_srcid = pfkey_id2ident(IKESA_SRCID(sa->csa_ikesa), SADB_EXT_IDENTITY_SRC); - /* peer id */ - sa_dstid = pfkey_id2ident(IKESA_DSTID(sa->csa_ikesa), SADB_EXT_IDENTITY_DST); + log_debug("%s: udpencap port %u", __func__, + ntohs(sa->csa_ikesa->sa_peer.addr_port)); + } + + + if (sa->csa_integrid != 0) + if (pfkey_map(pfkey_integr, + sa->csa_integrid, &sadb.sadb_sa_auth) == -1) { + log_warnx("%s: unsupported integrity algorithm %s", + __func__, print_map(sa->csa_integrid, + ikev2_xformauth_map)); + return (-1); + } + + if (sa->csa_encrid != 0) + if (pfkey_map(pfkey_encr, + sa->csa_encrid, &sadb.sadb_sa_encrypt) == -1) { + log_warnx("%s: unsupported encryption algorithm %s", + __func__, print_map(sa->csa_encrid, + ikev2_xformencr_map)); + return (-1); + } + + if (ibuf_length(sa->csa_integrkey)) { + sa_authkey.sadb_key_len = (sizeof(sa_authkey) + + ((ibuf_size(sa->csa_integrkey) + 7) / 8) * 8) / 8; + sa_authkey.sadb_key_exttype = SADB_EXT_KEY_AUTH; + sa_authkey.sadb_key_bits = + 8 * ibuf_size(sa->csa_integrkey); + } + + if (ibuf_length(sa->csa_encrkey)) { + sa_enckey.sadb_key_len = (sizeof(sa_enckey) + + ((ibuf_size(sa->csa_encrkey) + 7) / 8) * 8) / 8; + sa_enckey.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; + sa_enckey.sadb_key_bits = + 8 * ibuf_size(sa->csa_encrkey); + } + + /* local id */ + sa_srcid = pfkey_id2ident(IKESA_SRCID(sa->csa_ikesa), SADB_EXT_IDENTITY_SRC); + /* peer id */ + sa_dstid = pfkey_id2ident(IKESA_DSTID(sa->csa_ikesa), SADB_EXT_IDENTITY_DST); #if defined(_OPENBSD_IPSEC_API_VERSION) - tag = sa->csa_ikesa->sa_tag; - if (tag != NULL && *tag != '\0') { - bzero(&sa_tag, sizeof(sa_tag)); - sa_tag.sadb_x_tag_exttype = SADB_X_EXT_TAG; - sa_tag.sadb_x_tag_len = - (ROUNDUP(strlen(tag) + 1) + sizeof(sa_tag)) / 8; - sa_tag.sadb_x_tag_taglen = strlen(tag) + 1; - } else - tag = NULL; - - if (pol->pol_tap != 0) { - bzero(&sa_tap, sizeof(sa_tap)); - sa_tap.sadb_x_tap_exttype = SADB_X_EXT_TAP; - sa_tap.sadb_x_tap_len = sizeof(sa_tap) / 8; - sa_tap.sadb_x_tap_unit = pol->pol_tap; - } + tag = sa->csa_ikesa->sa_tag; + if (tag != NULL && *tag != '\0') { + bzero(&sa_tag, sizeof(sa_tag)); + sa_tag.sadb_x_tag_exttype = SADB_X_EXT_TAG; + sa_tag.sadb_x_tag_len = + (ROUNDUP(strlen(tag) + 1) + sizeof(sa_tag)) / 8; + sa_tag.sadb_x_tag_taglen = strlen(tag) + 1; + } else + tag = NULL; + + if (pol->pol_tap != 0) { + bzero(&sa_tap, sizeof(sa_tap)); + sa_tap.sadb_x_tap_exttype = SADB_X_EXT_TAP; + sa_tap.sadb_x_tap_len = sizeof(sa_tap) / 8; + sa_tap.sadb_x_tap_unit = pol->pol_tap; + } #endif send: - iov_cnt = 0; + iov_cnt = 0; - /* header */ - iov[iov_cnt].iov_base = &smsg; - iov[iov_cnt].iov_len = sizeof(smsg); - iov_cnt++; + /* header */ + iov[iov_cnt].iov_base = &smsg; + iov[iov_cnt].iov_len = sizeof(smsg); + iov_cnt++; - /* sa */ - iov[iov_cnt].iov_base = &sadb; - iov[iov_cnt].iov_len = sizeof(sadb); + /* sa */ + iov[iov_cnt].iov_base = &sadb; + iov[iov_cnt].iov_len = sizeof(sadb); #if defined(HAVE_APPLE_NATT) - if (natt.sadb_sa_natt_port) { - iov_cnt++; - iov[iov_cnt].iov_base = &natt; - iov[iov_cnt].iov_len = sizeof(natt); - sadb.sadb_sa_len += sizeof(natt) / 8; - } + if (natt.sadb_sa_natt_port) { + iov_cnt++; + iov[iov_cnt].iov_base = &natt; + iov[iov_cnt].iov_len = sizeof(natt); + sadb.sadb_sa_len += sizeof(natt) / 8; + } #endif - smsg.sadb_msg_len += sadb.sadb_sa_len; - iov_cnt++; + smsg.sadb_msg_len += sadb.sadb_sa_len; + iov_cnt++; #if !defined(_OPENBSD_IPSEC_API_VERSION) - /* sa2 */ - iov[iov_cnt].iov_base = &sa_2; - iov[iov_cnt].iov_len = sizeof(sa_2); - smsg.sadb_msg_len += sa_2.sadb_x_sa2_len; - iov_cnt++; + /* sa2 */ + iov[iov_cnt].iov_base = &sa_2; + iov[iov_cnt].iov_len = sizeof(sa_2); + smsg.sadb_msg_len += sa_2.sadb_x_sa2_len; + iov_cnt++; #endif - /* src addr */ - iov[iov_cnt].iov_base = &sa_src; - iov[iov_cnt].iov_len = sizeof(sa_src); - iov_cnt++; - iov[iov_cnt].iov_base = &ssrc; - iov[iov_cnt].iov_len = ROUNDUP(SS_LEN(&ssrc)); - smsg.sadb_msg_len += sa_src.sadb_address_len; - iov_cnt++; - - /* dst addr */ - iov[iov_cnt].iov_base = &sa_dst; - iov[iov_cnt].iov_len = sizeof(sa_dst); - iov_cnt++; - iov[iov_cnt].iov_base = &sdst; - iov[iov_cnt].iov_len = ROUNDUP(SS_LEN(&sdst)); - smsg.sadb_msg_len += sa_dst.sadb_address_len; - iov_cnt++; - - if (sa_ltime_soft.sadb_lifetime_len) { - /* soft lifetime */ - iov[iov_cnt].iov_base = &sa_ltime_soft; - iov[iov_cnt].iov_len = sizeof(sa_ltime_soft); smsg.sadb_msg_len += sa_ltime_soft.sadb_lifetime_len; - iov_cnt++; - } - - if (sa_ltime_hard.sadb_lifetime_len) { - /* hard lifetime */ - iov[iov_cnt].iov_base = &sa_ltime_hard; - iov[iov_cnt].iov_len = sizeof(sa_ltime_hard); - smsg.sadb_msg_len += sa_ltime_hard.sadb_lifetime_len; - iov_cnt++; - } + /* src addr */ + iov[iov_cnt].iov_base = &sa_src; + iov[iov_cnt].iov_len = sizeof(sa_src); + iov_cnt++; + iov[iov_cnt].iov_base = &ssrc; + iov[iov_cnt].iov_len = ROUNDUP(SS_LEN(&ssrc)); + smsg.sadb_msg_len += sa_src.sadb_address_len; + iov_cnt++; + + /* dst addr */ + iov[iov_cnt].iov_base = &sa_dst; + iov[iov_cnt].iov_len = sizeof(sa_dst); + iov_cnt++; + iov[iov_cnt].iov_base = &sdst; + iov[iov_cnt].iov_len = ROUNDUP(SS_LEN(&sdst)); + smsg.sadb_msg_len += sa_dst.sadb_address_len; + iov_cnt++; + + if (sa_ltime_soft.sadb_lifetime_len) { + /* soft lifetime */ + iov[iov_cnt].iov_base = &sa_ltime_soft; + iov[iov_cnt].iov_len = sizeof(sa_ltime_soft); smsg.sadb_msg_len += sa_ltime_soft.sadb_lifetime_len; + iov_cnt++; + } + + if (sa_ltime_hard.sadb_lifetime_len) { + /* hard lifetime */ + iov[iov_cnt].iov_base = &sa_ltime_hard; + iov[iov_cnt].iov_len = sizeof(sa_ltime_hard); + smsg.sadb_msg_len += sa_ltime_hard.sadb_lifetime_len; + iov_cnt++; + } #if defined(_OPENBSD_IPSEC_API_VERSION) - if (udpencap.sadb_x_udpencap_len) { - iov[iov_cnt].iov_base = &udpencap; - iov[iov_cnt].iov_len = sizeof(udpencap); - smsg.sadb_msg_len += udpencap.sadb_x_udpencap_len; - iov_cnt++; - } + if (udpencap.sadb_x_udpencap_len) { + iov[iov_cnt].iov_base = &udpencap; + iov[iov_cnt].iov_len = sizeof(udpencap); + smsg.sadb_msg_len += udpencap.sadb_x_udpencap_len; + iov_cnt++; + } #endif - if (sa_enckey.sadb_key_len) { - /* encryption key */ - iov[iov_cnt].iov_base = &sa_enckey; - iov[iov_cnt].iov_len = sizeof(sa_enckey); - iov_cnt++; - iov[iov_cnt].iov_base = ibuf_data(sa->csa_encrkey); - iov[iov_cnt].iov_len = - ((ibuf_size(sa->csa_encrkey) + 7) / 8) * 8; - smsg.sadb_msg_len += sa_enckey.sadb_key_len; - iov_cnt++; - } - if (sa_authkey.sadb_key_len) { - /* authentication key */ - iov[iov_cnt].iov_base = &sa_authkey; - iov[iov_cnt].iov_len = sizeof(sa_authkey); - iov_cnt++; - iov[iov_cnt].iov_base = ibuf_data(sa->csa_integrkey); iov[iov_cnt].iov_len = - ((ibuf_size(sa->csa_integrkey) + 7) / 8) * 8; - smsg.sadb_msg_len += sa_authkey.sadb_key_len; - iov_cnt++; - } - - if (sa_srcid) { - /* src identity */ - iov[iov_cnt].iov_base = sa_srcid; - iov[iov_cnt].iov_len = sa_srcid->sadb_ident_len * 8; - smsg.sadb_msg_len += sa_srcid->sadb_ident_len; - iov_cnt++; - } - if (sa_dstid) { - /* dst identity */ - iov[iov_cnt].iov_base = sa_dstid; - iov[iov_cnt].iov_len = sa_dstid->sadb_ident_len * 8; - smsg.sadb_msg_len += sa_dstid->sadb_ident_len; - iov_cnt++; - } + if (sa_enckey.sadb_key_len) { + /* encryption key */ + iov[iov_cnt].iov_base = &sa_enckey; + iov[iov_cnt].iov_len = sizeof(sa_enckey); + iov_cnt++; + iov[iov_cnt].iov_base = ibuf_data(sa->csa_encrkey); + iov[iov_cnt].iov_len = + ((ibuf_size(sa->csa_encrkey) + 7) / 8) * 8; + smsg.sadb_msg_len += sa_enckey.sadb_key_len; + iov_cnt++; + } + if (sa_authkey.sadb_key_len) { + /* authentication key */ + iov[iov_cnt].iov_base = &sa_authkey; + iov[iov_cnt].iov_len = sizeof(sa_authkey); + iov_cnt++; + iov[iov_cnt].iov_base = ibuf_data(sa->csa_integrkey); iov[iov_cnt].iov_len = + ((ibuf_size(sa->csa_integrkey) + 7) / 8) * 8; + smsg.sadb_msg_len += sa_authkey.sadb_key_len; + iov_cnt++; + } + + if (sa_srcid) { + /* src identity */ + iov[iov_cnt].iov_base = sa_srcid; + iov[iov_cnt].iov_len = sa_srcid->sadb_ident_len * 8; + smsg.sadb_msg_len += sa_srcid->sadb_ident_len; + iov_cnt++; + } + if (sa_dstid) { + /* dst identity */ + iov[iov_cnt].iov_base = sa_dstid; + iov[iov_cnt].iov_len = sa_dstid->sadb_ident_len * 8; + smsg.sadb_msg_len += sa_dstid->sadb_ident_len; + iov_cnt++; + } #if defined(_OPENBSD_IPSEC_API_VERSION) - if (tag != NULL) { - /* tag identity */ - iov[iov_cnt].iov_base = &sa_tag; - iov[iov_cnt].iov_len = sizeof(sa_tag); - iov_cnt++; - iov[iov_cnt].iov_base = tag; - iov[iov_cnt].iov_len = ROUNDUP(strlen(tag) + 1); - smsg.sadb_msg_len += sa_tag.sadb_x_tag_len; - iov_cnt++; - } - - if (pol->pol_tap != 0) { - /* enc(4) device tap unit */ - iov[iov_cnt].iov_base = &sa_tap; - iov[iov_cnt].iov_len = sizeof(sa_tap); - smsg.sadb_msg_len += sa_tap.sadb_x_tap_len; - iov_cnt++; - } + if (tag != NULL) { + /* tag identity */ + iov[iov_cnt].iov_base = &sa_tag; + iov[iov_cnt].iov_len = sizeof(sa_tag); + iov_cnt++; + iov[iov_cnt].iov_base = tag; + iov[iov_cnt].iov_len = ROUNDUP(strlen(tag) + 1); + smsg.sadb_msg_len += sa_tag.sadb_x_tag_len; + iov_cnt++; + } + + if (pol->pol_tap != 0) { + /* enc(4) device tap unit */ + iov[iov_cnt].iov_base = &sa_tap; + iov[iov_cnt].iov_len = sizeof(sa_tap); + smsg.sadb_msg_len += sa_tap.sadb_x_tap_len; + iov_cnt++; + } #endif - return (pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL)); + return (pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL)); } #if defined(_OPENBSD_IPSEC_API_VERSION) @@ -1860,279 +1860,279 @@ pfkey_timer_cb(int unused, short event, void *arg) int pfkey_process(struct iked *env, struct pfkey_message *pm) { - struct iked_spi spi; - struct sadb_sa *sa; + struct iked_spi spi; + struct sadb_sa *sa; struct sadb_lifetime *sa_ltime; - struct sadb_msg *hdr; + struct sadb_msg *hdr; #if defined(_OPENBSD_IPSEC_API_VERSION) - struct sadb_msg smsg; - struct iked_addr peer; - struct iked_flow flow; + struct sadb_msg smsg; + struct iked_addr peer; + struct iked_flow flow; struct sadb_address *sa_addr; struct sadb_protocol *sa_proto; struct sadb_x_policy sa_pol; - struct sadb_x_sa2 sa_2; + struct sadb_x_sa2 sa_2; struct sockaddr *ssrc, *sdst, *smask, *dmask, *speer; - struct iovec iov[IOV_CNT]; - int iov_cnt, sd = env->sc_pfkey; - u_int8_t *reply; - ssize_t rlen; - const char *errmsg = NULL; + struct iovec iov[IOV_CNT]; + int iov_cnt, sd = env->sc_pfkey; + u_int8_t *reply; + ssize_t rlen; + const char *errmsg = NULL; #else - struct iked_addr peer; + struct iked_addr peer; struct sadb_address *sa_addr; struct sockaddr *speer; struct sadb_x_policy *sa_pol; struct iked_flow flow; struct sockaddr *ssrc; #endif - u_int8_t *data = pm->pm_data; - ssize_t len = pm->pm_length; + u_int8_t *data = pm->pm_data; + ssize_t len = pm->pm_length; if (!env || !data || !len) - return 0; + return 0; hdr = (struct sadb_msg *)data; switch (hdr->sadb_msg_type) { case SADB_ACQUIRE: - /* Get peer from the acquire message */ - if ((sa_addr = pfkey_find_ext(data, len, - SADB_EXT_ADDRESS_DST)) == NULL) { - log_debug("%s: no peer address", __func__); - return 0; - } - speer = (struct sockaddr *)(sa_addr + 1); - //speer = (struct sockaddr_storage *)(sa_addr + 1); - bzero(&peer, sizeof(peer)); - peer.addr_af = speer->sa_family; - peer.addr_port = htons(socket_getport(speer)); - memcpy(&peer.addr, speer, sizeof(*speer)); - if (socket_af((struct sockaddr *)&peer.addr, - peer.addr_port) == -1) { - log_debug("%s: invalid address", __func__); - return 0; - } - log_debug("%s: acquire request (peer %s)", __func__, - print_host(speer, NULL, 0)); + /* Get peer from the acquire message */ + if ((sa_addr = pfkey_find_ext(data, len, + SADB_EXT_ADDRESS_DST)) == NULL) { + log_debug("%s: no peer address", __func__); + return 0; + } + speer = (struct sockaddr *)(sa_addr + 1); + //speer = (struct sockaddr_storage *)(sa_addr + 1); + bzero(&peer, sizeof(peer)); + peer.addr_af = speer->sa_family; + peer.addr_port = htons(socket_getport(speer)); + memcpy(&peer.addr, speer, sizeof(*speer)); + if (socket_af((struct sockaddr *)&peer.addr, + peer.addr_port) == -1) { + log_debug("%s: invalid address", __func__); + return 0; + } + log_debug("%s: acquire request (peer %s)", __func__, + print_host(speer, NULL, 0)); #if defined(_OPENBSD_IPSEC_API_VERSION) - /* Get the matching flow */ - bzero(&flow, sizeof(flow)); - flow.flow_peer = &peer; - - bzero(&smsg, sizeof(smsg)); - smsg.sadb_msg_version = PF_KEY_V2; - smsg.sadb_msg_seq = ++sadb_msg_seq; - smsg.sadb_msg_pid = getpid(); - smsg.sadb_msg_len = sizeof(smsg) / 8; - smsg.sadb_msg_type = SADB_X_ASKPOLICY; - - iov_cnt = 0; - - iov[iov_cnt].iov_base = &smsg; - iov[iov_cnt].iov_len = sizeof(smsg); - iov_cnt++; - - bzero(&sa_pol, sizeof(sa_pol)); - sa_pol.sadb_x_policy_exttype = SADB_X_EXT_POLICY; - sa_pol.sadb_x_policy_len = sizeof(sa_pol) / 8; - sa_pol.sadb_x_policy_seq = hdr->sadb_msg_seq; - - iov[iov_cnt].iov_base = &sa_pol; - iov[iov_cnt].iov_len = sizeof(sa_pol); - smsg.sadb_msg_len += sizeof(sa_pol) / 8; - iov_cnt++; - - if (pfkey_write(sd, &smsg, iov, iov_cnt, &reply, &rlen)) { - log_warnx("%s: failed to get a policy", __func__); - return 0; - } - - if ((sa_addr = pfkey_find_ext(reply, rlen, - SADB_X_EXT_SRC_FLOW)) == NULL) { - errmsg = "flow source address"; - goto out; - } - ssrc = (struct sockaddr_storage *)(sa_addr + 1); - flow.flow_src.addr_af = ssrc->ss_family; - flow.flow_src.addr_port = htons(socket_getport(ssrc)); - memcpy(&flow.flow_src.addr, ssrc, sizeof(*ssrc)); - if (socket_af((struct sockaddr *)&flow.flow_src.addr, - flow.flow_src.addr_port) == -1) { - log_debug("%s: invalid address", __func__); - return 0; - } - - if ((sa_addr = pfkey_find_ext(reply, rlen, - SADB_X_EXT_DST_FLOW)) == NULL) { - errmsg = "flow destination address"; - goto out; - } - sdst = (struct sockaddr_storage *)(sa_addr + 1); - flow.flow_dst.addr_af = sdst->ss_family; - flow.flow_dst.addr_port = htons(socket_getport(sdst)); - memcpy(&flow.flow_dst.addr, sdst, sizeof(*sdst)); - if (socket_af((struct sockaddr *)&flow.flow_dst.addr, - flow.flow_dst.addr_port) == -1) { - log_debug("%s: invalid address", __func__); - return 0; - } - - if ((sa_addr = pfkey_find_ext(reply, rlen, - SADB_X_EXT_SRC_MASK)) == NULL) { - errmsg = "flow source mask"; - goto out; - } - smask = (struct sockaddr_storage *)(sa_addr + 1); - switch (smask->ss_family) { - case AF_INET: - flow.flow_src.addr_mask = - mask2prefixlen((struct sockaddr *)smask); - if (flow.flow_src.addr_mask != 32) - flow.flow_src.addr_net = 1; - break; - case AF_INET6: - flow.flow_src.addr_mask = - mask2prefixlen6((struct sockaddr *)smask); - if (flow.flow_src.addr_mask != 128) - flow.flow_src.addr_net = 1; - break; - default: - log_debug("%s: bad address family", __func__); - free(reply); - return 0; - } - - if ((sa_addr = pfkey_find_ext(reply, rlen, - SADB_X_EXT_DST_MASK)) == NULL) { - errmsg = "flow destination mask"; - goto out; - } - dmask = (struct sockaddr_storage *)(sa_addr + 1); - switch (dmask->ss_family) { - case AF_INET: - flow.flow_dst.addr_mask = - mask2prefixlen((struct sockaddr *)dmask); - if (flow.flow_src.addr_mask != 32) - flow.flow_src.addr_net = 1; - break; - case AF_INET6: - flow.flow_dst.addr_mask = - mask2prefixlen6((struct sockaddr *)dmask); - if (flow.flow_src.addr_mask != 128) - flow.flow_src.addr_net = 1; - break; - default: - log_debug("%s: bad address family", __func__); - free(reply); - return 0; - } - - if ((sa_proto = pfkey_find_ext(reply, rlen, - SADB_X_EXT_FLOW_TYPE)) == NULL) { - errmsg = "flow protocol"; - goto out; - } - flow.flow_dir = sa_proto->sadb_protocol_direction; - - log_debug("%s: flow %s from %s/%s to %s/%s via %s", __func__, - flow.flow_dir == IPSP_DIRECTION_IN ? "in" : "out", - print_host(ssrc, NULL, 0), print_host(smask, NULL, 0), - print_host(sdst, NULL, 0), print_host(dmask, NULL, 0), - print_host(speer, NULL, 0)); - - ret = ikev2_acquire_sa(env, &flow); + /* Get the matching flow */ + bzero(&flow, sizeof(flow)); + flow.flow_peer = &peer; + + bzero(&smsg, sizeof(smsg)); + smsg.sadb_msg_version = PF_KEY_V2; + smsg.sadb_msg_seq = ++sadb_msg_seq; + smsg.sadb_msg_pid = getpid(); + smsg.sadb_msg_len = sizeof(smsg) / 8; + smsg.sadb_msg_type = SADB_X_ASKPOLICY; + + iov_cnt = 0; + + iov[iov_cnt].iov_base = &smsg; + iov[iov_cnt].iov_len = sizeof(smsg); + iov_cnt++; + + bzero(&sa_pol, sizeof(sa_pol)); + sa_pol.sadb_x_policy_exttype = SADB_X_EXT_POLICY; + sa_pol.sadb_x_policy_len = sizeof(sa_pol) / 8; + sa_pol.sadb_x_policy_seq = hdr->sadb_msg_seq; + + iov[iov_cnt].iov_base = &sa_pol; + iov[iov_cnt].iov_len = sizeof(sa_pol); + smsg.sadb_msg_len += sizeof(sa_pol) / 8; + iov_cnt++; + + if (pfkey_write(sd, &smsg, iov, iov_cnt, &reply, &rlen)) { + log_warnx("%s: failed to get a policy", __func__); + return 0; + } + + if ((sa_addr = pfkey_find_ext(reply, rlen, + SADB_X_EXT_SRC_FLOW)) == NULL) { + errmsg = "flow source address"; + goto out; + } + ssrc = (struct sockaddr_storage *)(sa_addr + 1); + flow.flow_src.addr_af = ssrc->ss_family; + flow.flow_src.addr_port = htons(socket_getport(ssrc)); + memcpy(&flow.flow_src.addr, ssrc, sizeof(*ssrc)); + if (socket_af((struct sockaddr *)&flow.flow_src.addr, + flow.flow_src.addr_port) == -1) { + log_debug("%s: invalid address", __func__); + return 0; + } + + if ((sa_addr = pfkey_find_ext(reply, rlen, + SADB_X_EXT_DST_FLOW)) == NULL) { + errmsg = "flow destination address"; + goto out; + } + sdst = (struct sockaddr_storage *)(sa_addr + 1); + flow.flow_dst.addr_af = sdst->ss_family; + flow.flow_dst.addr_port = htons(socket_getport(sdst)); + memcpy(&flow.flow_dst.addr, sdst, sizeof(*sdst)); + if (socket_af((struct sockaddr *)&flow.flow_dst.addr, + flow.flow_dst.addr_port) == -1) { + log_debug("%s: invalid address", __func__); + return 0; + } + + if ((sa_addr = pfkey_find_ext(reply, rlen, + SADB_X_EXT_SRC_MASK)) == NULL) { + errmsg = "flow source mask"; + goto out; + } + smask = (struct sockaddr_storage *)(sa_addr + 1); + switch (smask->ss_family) { + case AF_INET: + flow.flow_src.addr_mask = + mask2prefixlen((struct sockaddr *)smask); + if (flow.flow_src.addr_mask != 32) + flow.flow_src.addr_net = 1; + break; + case AF_INET6: + flow.flow_src.addr_mask = + mask2prefixlen6((struct sockaddr *)smask); + if (flow.flow_src.addr_mask != 128) + flow.flow_src.addr_net = 1; + break; + default: + log_debug("%s: bad address family", __func__); + free(reply); + return 0; + } + + if ((sa_addr = pfkey_find_ext(reply, rlen, + SADB_X_EXT_DST_MASK)) == NULL) { + errmsg = "flow destination mask"; + goto out; + } + dmask = (struct sockaddr_storage *)(sa_addr + 1); + switch (dmask->ss_family) { + case AF_INET: + flow.flow_dst.addr_mask = + mask2prefixlen((struct sockaddr *)dmask); + if (flow.flow_src.addr_mask != 32) + flow.flow_src.addr_net = 1; + break; + case AF_INET6: + flow.flow_dst.addr_mask = + mask2prefixlen6((struct sockaddr *)dmask); + if (flow.flow_src.addr_mask != 128) + flow.flow_src.addr_net = 1; + break; + default: + log_debug("%s: bad address family", __func__); + free(reply); + return 0; + } + + if ((sa_proto = pfkey_find_ext(reply, rlen, + SADB_X_EXT_FLOW_TYPE)) == NULL) { + errmsg = "flow protocol"; + goto out; + } + flow.flow_dir = sa_proto->sadb_protocol_direction; + + log_debug("%s: flow %s from %s/%s to %s/%s via %s", __func__, + flow.flow_dir == IPSP_DIRECTION_IN ? "in" : "out", + print_host(ssrc, NULL, 0), print_host(smask, NULL, 0), + print_host(sdst, NULL, 0), print_host(dmask, NULL, 0), + print_host(speer, NULL, 0)); + + ret = ikev2_acquire_sa(env, &flow); out: - if (errmsg) - log_warnx("%s: %s wasn't found", __func__, errmsg); - free(reply); + if (errmsg) + log_warnx("%s: %s wasn't found", __func__, errmsg); + free(reply); #elif defined(SADB_X_EXT_POLICY) - /* - * On an upcall from the kernel, reconstruct iked_flow with src - * and dest in upcall message. Then proceed onto establish SA - */ - bzero(&flow, sizeof(flow)); - flow.flow_peer = &peer; - flow.flow_dst = peer; - if (flow.flow_dst.addr_af == AF_INET) { - flow.flow_dst.addr_mask = 32; - } - if ((sa_pol = pfkey_find_ext(data, len, - SADB_X_EXT_POLICY)) == NULL) { - log_debug("%s: no policy extension", __func__); - return 0; - } - - if ((sa_addr = pfkey_find_ext(data, len, - SADB_EXT_ADDRESS_SRC)) == NULL) { - log_debug("%s: no src in ext_policy upcall", __func__); - return 0; - } - ssrc = (struct sockaddr*)(sa_addr + 1); - flow.flow_src.addr_af = ssrc->sa_family; - flow.flow_src.addr_port = htons(socket_getport(ssrc)); - if (flow.flow_src.addr_af == AF_INET) { - flow.flow_src.addr_mask = 32; - } - memcpy(&flow.flow_src.addr, ssrc, sizeof(*ssrc)); - if (socket_af((struct sockaddr *)&flow.flow_src.addr, - flow.flow_src.addr_port) == -1) { - log_debug("%s: invalid address", __func__); - return 0; - } - - log_debug("%s: flow %s from to %s ", __func__, - print_host((struct sockaddr*)&(flow.flow_src.addr), NULL, 0), - print_host((struct sockaddr*)&(flow.flow_dst.addr), NULL, 0)); - ikev2_acquire_sa(env, &flow); + /* + * On an upcall from the kernel, reconstruct iked_flow with src + * and dest in upcall message. Then proceed onto establish SA + */ + bzero(&flow, sizeof(flow)); + flow.flow_peer = &peer; + flow.flow_dst = peer; + if (flow.flow_dst.addr_af == AF_INET) { + flow.flow_dst.addr_mask = 32; + } + if ((sa_pol = pfkey_find_ext(data, len, + SADB_X_EXT_POLICY)) == NULL) { + log_debug("%s: no policy extension", __func__); + return 0; + } + + if ((sa_addr = pfkey_find_ext(data, len, + SADB_EXT_ADDRESS_SRC)) == NULL) { + log_debug("%s: no src in ext_policy upcall", __func__); + return 0; + } + ssrc = (struct sockaddr*)(sa_addr + 1); + flow.flow_src.addr_af = ssrc->sa_family; + flow.flow_src.addr_port = htons(socket_getport(ssrc)); + if (flow.flow_src.addr_af == AF_INET) { + flow.flow_src.addr_mask = 32; + } + memcpy(&flow.flow_src.addr, ssrc, sizeof(*ssrc)); + if (socket_af((struct sockaddr *)&flow.flow_src.addr, + flow.flow_src.addr_port) == -1) { + log_debug("%s: invalid address", __func__); + return 0; + } + + log_debug("%s: flow %s from to %s ", __func__, + print_host((struct sockaddr*)&(flow.flow_src.addr), NULL, 0), + print_host((struct sockaddr*)&(flow.flow_dst.addr), NULL, 0)); + ikev2_acquire_sa(env, &flow); #else #warning PFKEYv2 SADB_ACQUIRE not implemented - log_debug("%s: SADB_ACQUIRE not yet supported here, ignored", - __func__); + log_debug("%s: SADB_ACQUIRE not yet supported here, ignored", + __func__); #endif - break; + break; case SADB_EXPIRE: - if ((sa = pfkey_find_ext(data, len, SADB_EXT_SA)) == NULL) { - log_warnx("%s: SA extension wasn't found", __func__); - return 0; - } - if ((sa_ltime = pfkey_find_ext(data, len, - SADB_EXT_LIFETIME_SOFT)) == NULL && - (sa_ltime = pfkey_find_ext(data, len, - SADB_EXT_LIFETIME_HARD)) == NULL) { - log_warnx("%s: lifetime extension wasn't found", - __func__); - return 0; - } - spi.spi = ntohl(sa->sadb_sa_spi); - spi.spi_size = 4; - switch (hdr->sadb_msg_satype) { - case SADB_SATYPE_AH: - spi.spi_protoid = IKEV2_SAPROTO_AH; - break; - case SADB_SATYPE_ESP: - spi.spi_protoid = IKEV2_SAPROTO_ESP; - break; - default: - log_warnx("%s: usupported SA type %d spi %s", - __func__, hdr->sadb_msg_satype, - print_spi(spi.spi, spi.spi_size)); - return 0; - } - - log_debug("%s: SA %s is expired, pending %s", __func__, - print_spi(spi.spi, spi.spi_size), - sa_ltime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT ? - "rekeying" : "deletion"); - - if (sa_ltime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT) - ikev2_rekey_sa(env, &spi); - else - ikev2_drop_sa(env, &spi); - break; + if ((sa = pfkey_find_ext(data, len, SADB_EXT_SA)) == NULL) { + log_warnx("%s: SA extension wasn't found", __func__); + return 0; + } + if ((sa_ltime = pfkey_find_ext(data, len, + SADB_EXT_LIFETIME_SOFT)) == NULL && + (sa_ltime = pfkey_find_ext(data, len, + SADB_EXT_LIFETIME_HARD)) == NULL) { + log_warnx("%s: lifetime extension wasn't found", + __func__); + return 0; + } + spi.spi = ntohl(sa->sadb_sa_spi); + spi.spi_size = 4; + switch (hdr->sadb_msg_satype) { + case SADB_SATYPE_AH: + spi.spi_protoid = IKEV2_SAPROTO_AH; + break; + case SADB_SATYPE_ESP: + spi.spi_protoid = IKEV2_SAPROTO_ESP; + break; + default: + log_warnx("%s: usupported SA type %d spi %s", + __func__, hdr->sadb_msg_satype, + print_spi(spi.spi, spi.spi_size)); + return 0; + } + + log_debug("%s: SA %s is expired, pending %s", __func__, + print_spi(spi.spi, spi.spi_size), + sa_ltime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT ? + "rekeying" : "deletion"); + + if (sa_ltime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT) + ikev2_rekey_sa(env, &spi); + else + ikev2_drop_sa(env, &spi); + break; } return 0; } diff --git a/iked/policy.c b/iked/policy.c index df866bd..fcfd6c0 100644 --- a/iked/policy.c +++ b/iked/policy.c @@ -100,12 +100,12 @@ policy_lookup(struct iked *env, struct iked_message *msg) * Check if host is in a subnet */ bool is_in_subnet(struct sockaddr_in* host, struct sockaddr_in* subnet, - u_int8_t subnet_mask) { - uint32_t host_addr = ntohl(host->sin_addr.s_addr); - uint32_t subnet_addr = ntohl(subnet->sin_addr.s_addr); + u_int8_t subnet_mask) { + uint32_t host_addr = ntohl(host->sin_addr.s_addr); + uint32_t subnet_addr = ntohl(subnet->sin_addr.s_addr); - unsigned int mask = 0xFFFFFFFF << (32 - subnet_mask); - return ((host_addr & mask) == (subnet_addr & mask)); + unsigned int mask = 0xFFFFFFFF << (32 - subnet_mask); + return ((host_addr & mask) == (subnet_addr & mask)); } bool isipv4_flow_and_policy(struct iked_addr fsrc, struct iked_addr fdst, @@ -128,8 +128,8 @@ bool flow_matches_policy(struct iked_addr fsrc, struct iked_addr fdst, fdst_addr = (struct sockaddr_in*)&(fdst.addr); pdst_addr = (struct sockaddr_in*)&(pdst.addr); return (isipv4_flow_and_policy(fsrc, fdst, psrc, pdst) && - is_in_subnet(fsrc_addr, psrc_addr, psrc.addr_mask) && - is_in_subnet(fdst_addr, pdst_addr, pdst.addr_mask)); + is_in_subnet(fsrc_addr, psrc_addr, psrc.addr_mask) && + is_in_subnet(fdst_addr, pdst_addr, pdst.addr_mask)); } struct iked_policy * @@ -165,31 +165,31 @@ policy_test(struct iked *env, struct iked_policy *key) * and find a matching flow. */ if (key->pol_nflows && - (flowkey = RB_MIN(iked_flows, - &key->pol_flows)) != NULL) { - bool match = false; - struct iked_addr psrc, pdst, fsrc, fdst; - /* - * Check if incoming flow from kernel upcall - * matches any of the configuration policies - * or rules specified in iked.conf - */ - RB_FOREACH(flow, iked_flows, &p->pol_flows) { - psrc = flow->flow_src; - pdst = flow->flow_dst; - fsrc = flowkey->flow_src; - fdst = flowkey->flow_dst; + (flowkey = RB_MIN(iked_flows, + &key->pol_flows)) != NULL) { + bool match = false; + struct iked_addr psrc, pdst, fsrc, fdst; + /* + * Check if incoming flow from kernel upcall + * matches any of the configuration policies + * or rules specified in iked.conf + */ + RB_FOREACH(flow, iked_flows, &p->pol_flows) { + psrc = flow->flow_src; + pdst = flow->flow_dst; + fsrc = flowkey->flow_src; + fdst = flowkey->flow_dst; if (flow_matches_policy(fsrc, fdst, psrc, pdst)) { - match = true; - break; - } - } - if (!match) { - p = TAILQ_NEXT(p, pol_entry); - continue; - } - } + match = true; + break; + } + } + if (!match) { + p = TAILQ_NEXT(p, pol_entry); + continue; + } + } /* make sure the peer ID matches */ if (key->pol_peerid.id_type && (key->pol_peerid.id_type != p->pol_peerid.id_type || @@ -286,7 +286,7 @@ sa_state(struct iked *env, struct iked_sa *sa, int state) { const char *a; const char *b; - int ostate = sa->sa_state; + int ostate = sa->sa_state; a = print_map(ostate, ikev2_state_map); b = print_map(state, ikev2_state_map); diff --git a/iked/timer.c b/iked/timer.c index ca8a631..bf1514f 100644 --- a/iked/timer.c +++ b/iked/timer.c @@ -44,7 +44,7 @@ timer_set(struct iked *env, struct iked_timer *tmr, if (evtimer_initialized(&tmr->tmr_ev) && evtimer_pending(&tmr->tmr_ev, NULL)) { evtimer_del(&tmr->tmr_ev); - } + } evtimer_set(&tmr->tmr_ev, timer_callback, tmr); } diff --git a/iked/types.h b/iked/types.h index 3c30efb..fd5383c 100644 --- a/iked/types.h +++ b/iked/types.h @@ -38,8 +38,8 @@ #define IKED_PRIVKEY IKED_CA "private/local.key" #define IKED_PUBKEY "local.pub" -#define IKED_OCSP_RESPCERT "ocsp/responder.crt" -#define IKED_OCSP_ISSUER "ocsp/issuer.crt" +#define IKED_OCSP_RESPCERT "ocsp/responder.crt" +#define IKED_OCSP_ISSUER "ocsp/issuer.crt" #define IKED_OPT_VERBOSE 0x00000001 #define IKED_OPT_NOACTION 0x00000002 diff --git a/iked/util.c b/iked/util.c index 96fa9df..5ed8b6e 100644 --- a/iked/util.c +++ b/iked/util.c @@ -119,99 +119,99 @@ int socket_bypass(int s, struct sockaddr *sa) { #if defined(__OpenBSD__) - int v, *a; - int a4[] = { - IPPROTO_IP, - IP_AUTH_LEVEL, - IP_ESP_TRANS_LEVEL, - IP_ESP_NETWORK_LEVEL, + int v, *a; + int a4[] = { + IPPROTO_IP, + IP_AUTH_LEVEL, + IP_ESP_TRANS_LEVEL, + IP_ESP_NETWORK_LEVEL, #ifdef IPV6_IPCOMP_LEVEL - IP_IPCOMP_LEVEL + IP_IPCOMP_LEVEL #endif - }; - int a6[] = { - IPPROTO_IPV6, - IPV6_AUTH_LEVEL, - IPV6_ESP_TRANS_LEVEL, - IPV6_ESP_NETWORK_LEVEL, + }; + int a6[] = { + IPPROTO_IPV6, + IPV6_AUTH_LEVEL, + IPV6_ESP_TRANS_LEVEL, + IPV6_ESP_NETWORK_LEVEL, #ifdef IPV6_IPCOMP_LEVEL - IPV6_IPCOMP_LEVEL + IPV6_IPCOMP_LEVEL #endif - }; - - switch (sa->sa_family) { - case AF_INET: - a = a4; - break; - case AF_INET6: - a = a6; - break; - default: - log_warn("%s: invalid address family", __func__); - return (-1); - } - v = IPSEC_LEVEL_BYPASS; - if (setsockopt(s, a[0], a[1], &v, sizeof(v)) == -1) { - log_warn("%s: AUTH_LEVEL", __func__); - return (-1); - } - if (setsockopt(s, a[0], a[2], &v, sizeof(v)) == -1) { - log_warn("%s: ESP_TRANS_LEVEL", __func__); - return (-1); - } - if (setsockopt(s, a[0], a[3], &v, sizeof(v)) == -1) { - log_warn("%s: ESP_NETWORK_LEVEL", __func__); - return (-1); - } + }; + + switch (sa->sa_family) { + case AF_INET: + a = a4; + break; + case AF_INET6: + a = a6; + break; + default: + log_warn("%s: invalid address family", __func__); + return (-1); + } + v = IPSEC_LEVEL_BYPASS; + if (setsockopt(s, a[0], a[1], &v, sizeof(v)) == -1) { + log_warn("%s: AUTH_LEVEL", __func__); + return (-1); + } + if (setsockopt(s, a[0], a[2], &v, sizeof(v)) == -1) { + log_warn("%s: ESP_TRANS_LEVEL", __func__); + return (-1); + } + if (setsockopt(s, a[0], a[3], &v, sizeof(v)) == -1) { + log_warn("%s: ESP_NETWORK_LEVEL", __func__); + return (-1); + } #ifdef IP_IPCOMP_LEVEL - if (setsockopt(s, a[0], a[4], &v, sizeof(v)) == -1) { - log_warn("%s: IPCOMP_LEVEL", __func__); - return (-1); - } + if (setsockopt(s, a[0], a[4], &v, sizeof(v)) == -1) { + log_warn("%s: IPCOMP_LEVEL", __func__); + return (-1); + } #endif #else /* __OpenBSD__ */ - int *a; - int a4[] = { - IPPROTO_IP, - IP_IPSEC_POLICY - }; - int a6[] = { - IPPROTO_IPV6, - IPV6_IPSEC_POLICY, - - }; - struct sadb_x_policy pol = { - SADB_UPDATE, - SADB_EXT_SENSITIVITY, - IPSEC_POLICY_BYPASS, - 0, 0, 0, 0 - }; - - switch (sa->sa_family) { - case AF_INET: - a = a4; - break; - case AF_INET6: - a = a6; - break; - default: - log_warn("%s: invalid address family", __func__); - return (-1); - } - - pol.sadb_x_policy_dir = IPSEC_DIR_INBOUND; - if (setsockopt(s, a[0], a[1], &pol, sizeof(pol)) == -1) { - log_warn("%s: IPSEC_DIR_INBOUND", __func__); - return (-1); - } - pol.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND; - if (setsockopt(s, a[0], a[1], &pol, sizeof(pol)) == -1) { - log_warn("%s: IPSEC_DIR_OUTBOUND", __func__); - return (-1); - } + int *a; + int a4[] = { + IPPROTO_IP, + IP_IPSEC_POLICY + }; + int a6[] = { + IPPROTO_IPV6, + IPV6_IPSEC_POLICY, + + }; + struct sadb_x_policy pol = { + SADB_UPDATE, + SADB_EXT_SENSITIVITY, + IPSEC_POLICY_BYPASS, + 0, 0, 0, 0 + }; + + switch (sa->sa_family) { + case AF_INET: + a = a4; + break; + case AF_INET6: + a = a6; + break; + default: + log_warn("%s: invalid address family", __func__); + return (-1); + } + + pol.sadb_x_policy_dir = IPSEC_DIR_INBOUND; + if (setsockopt(s, a[0], a[1], &pol, sizeof(pol)) == -1) { + log_warn("%s: IPSEC_DIR_INBOUND", __func__); + return (-1); + } + pol.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND; + if (setsockopt(s, a[0], a[1], &pol, sizeof(pol)) == -1) { + log_warn("%s: IPSEC_DIR_OUTBOUND", __func__); + return (-1); + } #endif /* !__OpenBSD__ */ - return (0); + return (0); } int @@ -621,7 +621,7 @@ prefixlen2mask(u_int8_t prefixlen) struct in6_addr * prefixlen2mask6(u_int8_t prefixlen, u_int32_t *mask) { - static struct in6_addr s6; + static struct in6_addr s6; int i; if (prefixlen > 128) diff --git a/openbsd-compat/defines.h b/openbsd-compat/defines.h index cd08596..3eb830a 100644 --- a/openbsd-compat/defines.h +++ b/openbsd-compat/defines.h @@ -36,7 +36,7 @@ #if defined(HAVE_DECL_SHUT_RD) && HAVE_DECL_SHUT_RD == 0 enum { - SHUT_RD = 0, /* No more receptions. */ + SHUT_RD = 0, /* No more receptions. */ SHUT_WR, /* No more transmissions. */ SHUT_RDWR /* No more receptions or transmissions. */ }; @@ -46,11 +46,11 @@ enum #endif #ifndef IPTOS_LOWDELAY -# define IPTOS_LOWDELAY 0x10 -# define IPTOS_THROUGHPUT 0x08 -# define IPTOS_RELIABILITY 0x04 -# define IPTOS_LOWCOST 0x02 -# define IPTOS_MINCOST IPTOS_LOWCOST +# define IPTOS_LOWDELAY 0x10 +# define IPTOS_THROUGHPUT 0x08 +# define IPTOS_RELIABILITY 0x04 +# define IPTOS_LOWCOST 0x02 +# define IPTOS_MINCOST IPTOS_LOWCOST #endif /* IPTOS_LOWDELAY */ #if !defined(HAVE_NETINET_IP_IPSP_H) && (defined(HAVE_NETINET6_IPSEC_H) || \ @@ -110,17 +110,17 @@ enum #endif #ifndef MAXLOGNAME -#define MAXLOGNAME LOGIN_NAME_MAX +#define MAXLOGNAME LOGIN_NAME_MAX #endif #ifndef STDIN_FILENO -# define STDIN_FILENO 0 +# define STDIN_FILENO 0 #endif #ifndef STDOUT_FILENO -# define STDOUT_FILENO 1 +# define STDOUT_FILENO 1 #endif #ifndef STDERR_FILENO -# define STDERR_FILENO 2 +# define STDERR_FILENO 2 #endif #ifndef NGROUPS_MAX /* Disable groupaccess if NGROUP_MAX is not set */ @@ -132,7 +132,7 @@ enum #endif #if defined(HAVE_DECL_O_NONBLOCK) && HAVE_DECL_O_NONBLOCK == 0 -# define O_NONBLOCK 00004 /* Non Blocking Open */ +# define O_NONBLOCK 00004 /* Non Blocking Open */ #endif #ifndef S_ISDIR @@ -353,8 +353,8 @@ typedef u_int16_t in_port_t; #if defined(BROKEN_SYS_TERMIO_H) && !defined(_STRUCT_WINSIZE) #define _STRUCT_WINSIZE struct winsize { - unsigned short ws_row; /* rows, in characters */ - unsigned short ws_col; /* columns, in character */ + unsigned short ws_row; /* rows, in characters */ + unsigned short ws_col; /* columns, in character */ unsigned short ws_xpixel; /* horizontal size, pixels */ unsigned short ws_ypixel; /* vertical size, pixels */ }; @@ -474,7 +474,7 @@ struct sadb_sa_natt { #endif #ifndef roundup -# define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) +# define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) #endif #ifndef timersub @@ -490,9 +490,9 @@ struct sadb_sa_natt { #endif #ifndef timespeccmp -#define timespeccmp(a, b, cmp) \ - (((a)->tv_sec == (b)->tv_sec) ? \ - ((a)->tv_nsec cmp (b)->tv_nsec) : \ +#define timespeccmp(a, b, cmp) \ + (((a)->tv_sec == (b)->tv_sec) ? \ + ((a)->tv_nsec cmp (b)->tv_nsec) : \ ((a)->tv_sec cmp (b)->tv_sec)) #endif @@ -610,7 +610,7 @@ struct sadb_sa_natt { # define LITTLE_ENDIAN 1234 # endif /* LITTLE_ENDIAN */ # ifndef BIG_ENDIAN -# define BIG_ENDIAN 4321 +# define BIG_ENDIAN 4321 # endif /* BIG_ENDIAN */ # ifdef WORDS_BIGENDIAN # define BYTE_ORDER BIG_ENDIAN diff --git a/openbsd-compat/sys-tree.h b/openbsd-compat/sys-tree.h index cadfb55..4959548 100644 --- a/openbsd-compat/sys-tree.h +++ b/openbsd-compat/sys-tree.h @@ -149,7 +149,7 @@ static __inline struct type * \ name##_SPLAY_MIN_MAX(struct name *head, int val) \ { \ name##_SPLAY_MINMAX(head, val); \ - return (SPLAY_ROOT(head)); \ + return (SPLAY_ROOT(head)); \ } /* Main splay operation. From d77efb36b8b57cd12fd22ac2d5d40ccf7e52396e Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Wed, 8 Jun 2016 09:28:34 -0700 Subject: [PATCH 12/39] Revert "Remove portable code; it has been suspended until we find a new" This reverts commit a3c6d0af68a4cec015ec1e9397d170799d6731ac. --- .gitignore | 3 + LICENSE.md | 3 +- Makefile | 4 - Makefile.am | 19 + README.md | 145 +- bootstrap | 151 ++ configure.ac | 2555 +++++++++++++++++++++++++++++++ ikectl/.cvsignore | 5 + ikectl/CVS/Entries | 14 +- ikectl/Makefile | 22 - ikectl/Makefile.am | 45 + ikectl/ikeca.c | 257 +--- ikectl/ikeca.cnf | 4 +- ikectl/ikectl.8 | 22 +- ikectl/ikectl.c | 15 +- ikectl/parser.c | 9 +- ikectl/parser.h | 8 +- iked/.cvsignore | 1 + iked/CVS/Entries | 62 +- iked/Makefile | 33 - iked/Makefile.am | 76 + iked/ca.c | 513 ++----- iked/chap_ms.c | 170 +- iked/chap_ms.h | 36 +- iked/config.c | 172 +-- iked/control.c | 28 +- iked/crypto.c | 190 +-- iked/dh.c | 153 +- iked/dh.h | 32 +- iked/eap.c | 37 +- iked/eap.h | 64 +- iked/genmap.sh | 3 +- iked/iked.8 | 100 +- iked/iked.c | 97 +- iked/iked.conf | 12 + iked/iked.conf.5 | 101 +- iked/iked.h | 473 +++--- iked/ikev1.c | 18 +- iked/ikev2.c | 2072 ++++++------------------- iked/ikev2.h | 123 +- iked/ikev2_msg.c | 148 +- iked/ikev2_pld.c | 1078 +++---------- iked/imsg_util.c | 19 +- iked/log.c | 7 +- iked/ocsp.c | 514 ------- iked/parse.y | 343 ++--- iked/pfkey.c | 962 +++++++----- iked/policy.c | 208 ++- iked/proc.c | 447 ++---- iked/smult_curve25519_ref.c | 265 ---- iked/timer.c | 24 +- iked/types.h | 47 +- iked/util.c | 198 ++- mdoc2man.awk | 370 +++++ openbsd-compat/Makefile.am | 14 + openbsd-compat/bsd-arc4random.c | 233 +++ openbsd-compat/bsd-closefrom.c | 89 ++ openbsd-compat/chacha_private.h | 222 +++ openbsd-compat/daemon.c | 82 + openbsd-compat/defines.h | 881 +++++++++++ openbsd-compat/entropy.c | 203 +++ openbsd-compat/fgetln.c | 63 + openbsd-compat/getopt.c | 123 ++ openbsd-compat/imsg-buffer.c | 305 ++++ openbsd-compat/imsg.c | 323 ++++ openbsd-compat/imsg.h | 112 ++ openbsd-compat/includes.h | 131 ++ openbsd-compat/openbsd-compat.h | 182 +++ openbsd-compat/setproctitle.c | 163 ++ openbsd-compat/setresguid.c | 65 + openbsd-compat/strlcat.c | 62 + openbsd-compat/strlcpy.c | 58 + openbsd-compat/strtonum.c | 74 + openbsd-compat/sys-queue.h | 660 ++++++++ openbsd-compat/sys-tree.h | 750 +++++++++ openbsd-compat/vis.c | 225 +++ openbsd-compat/vis.h | 98 ++ 77 files changed, 11341 insertions(+), 6254 deletions(-) delete mode 100644 Makefile create mode 100644 Makefile.am create mode 100755 bootstrap create mode 100644 configure.ac create mode 100644 ikectl/.cvsignore delete mode 100644 ikectl/Makefile create mode 100644 ikectl/Makefile.am delete mode 100644 iked/Makefile create mode 100644 iked/Makefile.am create mode 100644 iked/iked.conf delete mode 100644 iked/ocsp.c delete mode 100644 iked/smult_curve25519_ref.c create mode 100644 mdoc2man.awk create mode 100644 openbsd-compat/Makefile.am create mode 100644 openbsd-compat/bsd-arc4random.c create mode 100644 openbsd-compat/bsd-closefrom.c create mode 100644 openbsd-compat/chacha_private.h create mode 100644 openbsd-compat/daemon.c create mode 100644 openbsd-compat/defines.h create mode 100644 openbsd-compat/entropy.c create mode 100644 openbsd-compat/fgetln.c create mode 100644 openbsd-compat/getopt.c create mode 100644 openbsd-compat/imsg-buffer.c create mode 100644 openbsd-compat/imsg.c create mode 100644 openbsd-compat/imsg.h create mode 100644 openbsd-compat/includes.h create mode 100644 openbsd-compat/openbsd-compat.h create mode 100644 openbsd-compat/setproctitle.c create mode 100644 openbsd-compat/setresguid.c create mode 100644 openbsd-compat/strlcat.c create mode 100644 openbsd-compat/strlcpy.c create mode 100644 openbsd-compat/strtonum.c create mode 100644 openbsd-compat/sys-queue.h create mode 100644 openbsd-compat/sys-tree.h create mode 100644 openbsd-compat/vis.c create mode 100644 openbsd-compat/vis.h diff --git a/.gitignore b/.gitignore index f4dbad9..999d144 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ .DS_Store m4 aclocal.m4 +Makefile autom4te.cache compile config.guess @@ -26,6 +27,8 @@ missing parse.c stamp-h1 ylwrap +iked +ikectl *_map.c clang_* *-scan-build diff --git a/LICENSE.md b/LICENSE.md index 021608f..4ba7f6f 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -5,7 +5,8 @@ OpenIKED is free software under OpenBSD's ISC-style license. * Most of the code has been written by Reyk Floeter * The ikectl CA code has been written by Jonathan Gray -* Much work by Markus Friedl and Hans-Joerg Hoexer. +* The `openbsd-compat` and autoconf parts of the portable version are + based on work by Damien Miller for OpenSSH. * Please refer to the individual source files for other copyright holders! > Copyright (c) 2010-2013 Reyk Floeter diff --git a/Makefile b/Makefile deleted file mode 100644 index 49ae017..0000000 --- a/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -SUBDIR= iked ikectl -MAKE_FLAGS= BINDIR=/sbin - -.include diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..dd5faa3 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,19 @@ +SUBDIRS= openbsd-compat iked ikectl +ACLOCAL_AMFLAGS= -I m4 + +PRIVKEY=$(DESTDIR)$(sysconfdir)/iked/private/local.key +PUBKEY=$(DESTDIR)$(sysconfdir)/iked/local.pub + +install-exec-hook: host-key + +host-key: + @if [ -z "$(DESTDIR)" ] ; then \ + if [ -f $(PRIVKEY) ]; then \ + echo "$(PRIVKEY) already exists, skipping." ; \ + elif $(OPENSSL) genrsa -out $(PRIVKEY) 2048 ; then \ + $(CHMOD) 600 $(PRIVKEY) ; \ + $(OPENSSL) rsa -out $(PUBKEY) -in $(PRIVKEY) -pubout ; \ + else \ + echo "$(PRIVKEY) failed" ; \ + fi ; \ + fi diff --git a/README.md b/README.md index da009c5..81e2b14 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ OpenIKED ======== -This is a development mirror of OpenBSD's iked. +This is the port of OpenBSD's iked to Darwin/OS X and other +operating systems (see "Supported Platforms"). iked is a lean Internet Key Exchange (IKEv2) daemon which performs mutual authentication and which establishes and maintains IPsec VPN @@ -19,10 +20,13 @@ with other IKEv2 implementations like the native IKEv2 implementation of Windows 7 or newer (aka Agile VPN) or strongSwan. The main development of iked is being done for OpenBSD and the source -tree is found in OpenBSD's CVS repository. Like most of the projects -from the OpenBSD repository, the original source code does not include -any portability glue (#ifdefs) and is specifically developed for -OpenBSD. +tree is found in OpenBSD's CVS repository. This port adds +replacements for OpenBSD-specific library functions and portability +code for other platforms. Like most of the projects from the OpenBSD +repository, the original source code does not include any portability +glue (#ifdefs) and is specifically developed for OpenBSD. This +external repository adds all the portable extensions to run it on +other supported platforms. The main development tree is found in the src/sbin/iked and src/usr.sbin/ikectl directories of the OpenBSD CVS repository: @@ -31,6 +35,55 @@ src/usr.sbin/ikectl directories of the OpenBSD CVS repository: * http://www.openbsd.org/cgi-bin/cvsweb/src/usr.sbin/ikectl/ * See also: http://www.openiked.org/ +Installation +------------ + +The portable version of OpenIKED uses the GNU autoconf environment to +build and install from the sources. As usual, follow these basic +steps to install OpenIKED: + +1. Requirements: + - Make sure that the external libraries OpenSSL (version 1.0 or newer) +and libevent (version 1.4 or newer) with their header files are +installed. + - If you're checking out the sources from the Git repository, you will +also need GNU automake, autoconf (version 2.69 or newer) and libtool. +2. Enter the top directory of the extracted sources. +3. If you checked out the sources from the Git repository, run +`sh bootstrap` to generate the required build files. +4. Run `./configure` in this directory to generate the Makefiles. + - `./configure --help` will show you some available build options. + - For example, you can run the following when building on Apple OSX +with MacPorts: +``` + ./configure --with-ssl-dir=/opt/local/ + --with-libevent-dir=/opt/local/lib/libevent1/ + --prefix=/opt/local/ +``` +5. Type `make` to build all parts of OpenIKED including iked and ikectl. +6. Type `make install` to install OpenIKED, or `sudo make install` if +you didn't compile OpenIKED as root. + +7. Run something like the following to create iked's unprivileged +system user and environment. Note that the command syntax and user +name might vary on different platforms - use "iked" instead of "_iked" +on Linux. +``` + # mkdir /var/empty + # chown root:sys /var/empty + # chmod 755 /var/empty + # groupadd _iked + # useradd -g _iked -c 'iked privsep' -d /var/empty -s /sbin/nologin _iked +``` + +8. On FreeBSD, NetBSD and maybe other BSD-variants IPsec is not +enabled in the default GENERIC kernel. You have to compile a custom +kernel and enable options like `IPSEC`. Please refer to the +individual documentation for details, for example: + +* http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/ipsec.html +* http://www.netbsd.org/docs/network/ipsec/#config_kernel + Supported Platforms ------------------- @@ -38,13 +91,52 @@ Original version: * OpenBSD 4.8 or newer -The portable version has been suspended and is not available at -present. It previously supported the following platforms: - -* Darwin (Apple OS X Mountain Lion 10.8) - DEPRECATED -* Linux (Ubuntu 12.10 GNU/Linux 3.5.0-19-generic) - DEPRECATED -* FreeBSD (FreeBSD 9.0-RELEASE with IPSEC kernel) - DEPRECATED -* NetBSD (NetBSD 6.0 with IPSEC kernel) - DEPRECATED +Portable version: + +* Darwin (Apple OS X Mountain Lion 10.8) +* Linux (Ubuntu 12.10 GNU/Linux 3.5.0-19-generic) +* FreeBSD (FreeBSD 9.0-RELEASE with IPSEC kernel) +* NetBSD (NetBSD 6.0 with IPSEC kernel) +* TODO: other BSDs and PFKEYv2/KAME-based platforms. + +Development +----------- + +The source tree of OpenIKED contains the following directories: + +* `openiked/`: + Build scripts for automake/autoconf and README files. +* `openiked/ikectl/`: + The control and status utility for iked. +* `openiked/iked/`: + The IKEv2 daemon itself and some files that are shared with ikectl. +* `openiked/openbsd-compat/`: + Portability glue and API functions for non-OpenBSD platforms. + +You can checkout the portable code from GitHub: + +``` +$ git clone git://github.com/reyk/openiked.git +``` + +And compare the contents of the `iked` and `ikectl` directories in +the git repository with the original sources in OpenBSD's +(Anon)CVS repository by running the `cvs diff` command in these +subdirectories. This will show you the differences between the portable +version and the unpatched OpenBSD version: + +``` +$ cd openiked/iked/ +$ cvs diff -Nup | tee ../iked.diff +$ cd ../ikectl/ +$ cvs diff -Nup | tee ../ikectl.diff +``` + +Before you continue with looking at the code or writing any diffs, you +should study OpenBSD's source style guide; or the "KNF". You can +find it in OpenBSD's style(9) manpage or online at: +http://www.openbsd.org/cgi-bin/man.cgi?query=style&sektion=9. +Please also note that each line should be at most 80 characters long. Authors ------- @@ -55,6 +147,35 @@ Authors See [`LICENSE.md`](https://github.com/reyk/openiked/blob/master/LICENSE.md) for information about copyright and licensing. +Caveats, bugs and limitations +----------------------------- + +This is work in progress! OpenIKED is not yet finished and is missing +some important security features. It should not yet be used in +production networks. + +OpenIKED might have a few limitations on operating systems other than +the most recent versions of OpenBSD. A major difference between +OpenBSD and other systems is the API and availability of the IPsec +PFKEYv2 flow implementation (SADB) and message passing between kernel +and iked. Current known limitations are: + +* VPN traffic leakage prevention: +Automatic blocking of IPv6 traffic is not working on KAME-bases stacks. + +* NAT-T: +NAT-T is only supported on OpenBSD and Darwin (OS X). The NAT-T API +is not standardized in PFKEYv2, not even on a semi-level, and differs +in most operating systems, if supported at all. + +* Crypto algorithms: +Some of the crypto algorithms are either not supported on other systems +or not implemented correctly. For example, Linux still uses the broken +pre-standard version of hmac-sha2-256 by default that was specified with +96 bit truncation instead of the standard 128 bit truncation. The common +workaround that allows to specify the truncation length would be to use +Linux' non-standard XFRM kernel API instead of PFKEYv2. + Reyk [![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/thing/1038961/reykopeniked-on-GitHub) diff --git a/bootstrap b/bootstrap new file mode 100755 index 0000000..6cfcf9d --- /dev/null +++ b/bootstrap @@ -0,0 +1,151 @@ +#! /bin/sh + +# bootstrap: generic bootstrap/autogen.sh script for autotools projects +# +# Copyright (c) 2002-2011 Sam Hocevar +# +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. +# +# The latest version of this script can be found at the following place: +# http://caca.zoy.org/wiki/build + +# Die if an error occurs +set -e + +# Guess whether we are using configure.ac or configure.in +if test -f configure.ac; then + conffile="configure.ac" +elif test -f configure.in; then + conffile="configure.in" +else + echo "$0: could not find configure.ac or configure.in" + exit 1 +fi + +# Check for needed features +auxdir="`sed -ne 's/^[ \t]*A._CONFIG_AUX_DIR *([[ ]*\([^] )]*\).*/\1/p' $conffile`" +pkgconfig="`grep '^[ \t]*PKG_PROG_PKG_CONFIG' $conffile >/dev/null 2>&1 && echo yes || echo no`" +libtool="`grep '^[ \t]*A._PROG_LIBTOOL' $conffile >/dev/null 2>&1 && echo yes || echo no`" +header="`grep '^[ \t]*A._CONFIG_HEADER' $conffile >/dev/null 2>&1 && echo yes || echo no`" +makefile="`[ -f Makefile.am ] && echo yes || echo no`" +aclocalflags="`sed -ne 's/^[ \t]*ACLOCAL_AMFLAGS[ \t]*=//p' Makefile.am 2>/dev/null || :`" + +# Check for automake +amvers="no" +for v in 12 11 10 9 8 7 6 5; do + if automake-1.${v} --version >/dev/null 2>&1; then + amvers="-1.${v}" + break + elif automake1.${v} --version >/dev/null 2>&1; then + amvers="1.${v}" + break + fi +done + +if test "${amvers}" = "no" && automake --version > /dev/null 2>&1; then + amvers="`automake --version | sed -e '1s/[^0-9]*//' -e q`" + if expr "$amvers" "<" "1.5" > /dev/null 2>&1; then + amvers="no" + else + amvers="" + fi +fi + +if test "$amvers" = "no"; then + echo "$0: you need automake version 1.5 or later" + exit 1 +fi + +# Check for autoconf +acvers="no" +for v in "" "269" "-2.69" "259" "-2.59" "253" "-2.53"; do + if autoconf${v} --version >/dev/null 2>&1; then + acvers="${v}" + break + fi +done + +if test "$acvers" = "no"; then + echo "$0: you need autoconf" + exit 1 +fi + +# Check for libtool +if test "$libtool" = "yes"; then + libtoolize="no" + if glibtoolize --version >/dev/null 2>&1; then + libtoolize="glibtoolize" + else + for v in "16" "15" "" "14"; do + if libtoolize${v} --version >/dev/null 2>&1; then + libtoolize="libtoolize${v}" + break + fi + done + fi + + if test "$libtoolize" = "no"; then + echo "$0: you need libtool" + exit 1 + fi +fi + +# Check for pkg-config +if test "$pkgconfig" = "yes"; then + if ! pkg-config --version >/dev/null 2>&1; then + echo "$0: you need pkg-config" + exit 1 + fi +fi + +# Remove old cruft +for x in aclocal.m4 configure config.guess config.log config.sub config.cache config.h.in config.h compile libtool.m4 ltoptions.m4 ltsugar.m4 ltversion.m4 ltmain.sh libtool ltconfig missing mkinstalldirs depcomp install-sh; do rm -f $x autotools/$x; if test -n "$auxdir"; then rm -f "$auxdir/$x"; fi; done +rm -Rf autom4te.cache +if test -n "$auxdir"; then + if test ! -d "$auxdir"; then + mkdir "$auxdir" + fi + aclocalflags="${aclocalflags} -I $auxdir -I ." +fi + +# Honour M4PATH because sometimes M4 doesn't +save_IFS=$IFS +IFS=: +tmp="$M4PATH" +for x in $tmp; do + if test -n "$x"; then + aclocalflags="${aclocalflags} -I $x" + fi +done +IFS=$save_IFS + +# Explain what we are doing from now +set -x + +# Bootstrap package +if test "$libtool" = "yes"; then + ${libtoolize} --copy --force + if test -n "$auxdir" -a ! "$auxdir" = "." -a -f "ltmain.sh"; then + echo "$0: working around a minor libtool issue" + mv ltmain.sh "$auxdir/" + fi +fi + +aclocal${amvers} ${aclocalflags} +autoconf${acvers} +if test "$header" = "yes"; then + autoheader${acvers} +fi +if test "$makefile" = "yes"; then + #add --include-deps if you want to bootstrap with any other compiler than gcc + #automake${amvers} --add-missing --copy --include-deps + automake${amvers} --foreign --add-missing --copy +fi + +# Remove cruft that we no longer want +rm -Rf autom4te.cache + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..1705862 --- /dev/null +++ b/configure.ac @@ -0,0 +1,2555 @@ +# Copyright (c) 2012 Reyk Floeter +# Copyright (c) 1999-2004 Damien Miller +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +dnl AC_INIT([OpenIKED-portable],[5.2.0p0],[Reyk Floeter ]) +AC_INIT([OpenIKED-portable], m4_esyscmd(date +%Y%m%d%H%M%S | sed -e 's/^\(.*\)$/5.2-\1/' | tr -d '\n'),[Reyk Floeter ]) +AC_LANG([C]) +AC_CONFIG_MACRO_DIR([m4]) + +AC_CONFIG_HEADER([config.h]) +AC_CANONICAL_HOST +AC_C_BIGENDIAN + +AM_INIT_AUTOMAKE + +# Checks for programs. +AC_PROG_CC +AM_PROG_CC_C_O +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_LIBTOOL +AC_PATH_PROG([AR], [ar]) +AC_PATH_PROG([CAT], [cat]) +AC_PATH_PROG([CHMOD], [chmod]) +AC_PATH_PROG([CHOWN], [chown]) +AC_PATH_PROG([SED], [sed]) +AC_PATH_PROG([TEST_MINUS_S_SH], [bash]) +AC_PATH_PROG([TEST_MINUS_S_SH], [ksh]) +AC_PATH_PROG([TEST_MINUS_S_SH], [sh]) +AC_PATH_PROG([SH], [sh]) +AC_PATH_PROG([GROFF], [groff]) +AC_PATH_PROG([NROFF], [nroff]) +AC_PATH_PROG([MANDOC], [mandoc]) +AC_PROG_YACC +AC_PATH_PROG(OPENSSL, openssl) +AC_PATH_PROG(ZIP, zip) +AC_PATH_PROG(TAR, tar) + +LT_INIT + +dnl select manpage formatter +if test "x$MANDOC" != "x" ; then + MANFMT="$MANDOC" +elif test "x$NROFF" != "x" ; then + MANFMT="$NROFF -mandoc" +elif test "x$GROFF" != "x" ; then + MANFMT="$GROFF -mandoc -Tascii" +else + AC_MSG_WARN([no manpage formatted found]) + MANFMT="false" +fi +AC_SUBST([MANFMT]) + +if test -z "$LD" ; then + LD=$CC +fi +AC_SUBST([LD]) + +AC_C_INLINE + +AC_CHECK_DECL([LLONG_MAX], [have_llong_max=1], , [#include ]) + +if test "$GCC" = "yes" || test "$GCC" = "egcs"; then + CFLAGS="$CFLAGS -Wall -Wpointer-arith -Wuninitialized" + GCC_VER=`$CC -v 2>&1 | $AWK '/gcc version /{print $3}'` + case $GCC_VER in + 1.*) no_attrib_nonnull=1 ;; + 2.8* | 2.9*) + CFLAGS="$CFLAGS -Wsign-compare" + no_attrib_nonnull=1 + ;; + 2.*) no_attrib_nonnull=1 ;; + 3.*) CFLAGS="$CFLAGS -Wsign-compare" ;; + 4.*) CFLAGS="$CFLAGS -Wsign-compare -Wno-pointer-sign" ;; + *) ;; + esac + + if test -z "$have_llong_max"; then + # retry LLONG_MAX with -std=gnu99, needed on some Linuxes + unset ac_cv_have_decl_LLONG_MAX + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -std=gnu99" + AC_CHECK_DECL(LLONG_MAX, + [have_llong_max=1], + [CFLAGS="$saved_CFLAGS"], + [#include ] + ) + fi +fi + +if test "x$no_attrib_nonnull" != "x1" ; then + AC_DEFINE(HAVE_ATTRIBUTE__NONNULL__, 1, [Have attribute nonnull]) +fi + +AC_ARG_WITH(Werror, + [ --with-Werror Build main code with -Werror], + [ + if test -n "$withval" && test "x$withval" != "xno"; then + werror_flags="-Werror" + if test "x${withval}" != "xyes"; then + werror_flags="$withval" + fi + fi + ] +) + +AC_ARG_WITH(debug, + [ --with-debug Build main code with debugging symbols and disable privsep], + [ + if test -n "$withval" && test "x$withval" != "xno"; then + debug_flags="-g -DDEBUG=1" + if test "x${withval}" != "xyes"; then + debug_flags="$withval" + fi + fi + ] +) + +AC_CHECK_HEADERS([\ + arpa/inet.h \ + asm/byteorder.h \ + ctype.h \ + dirent.h \ + endian.h \ + err.h \ + errno.h \ + fcntl.h \ + getopt.h \ + libkern/OSByteOrder.h \ + ndir.h \ + net/pfkeyv2.h \ + linux/pfkeyv2.h \ + linux/in.h \ + linux/ipsec.h \ + limits.h \ + netdb.h \ + netinet/in.h \ + netinet/in_systm.h \ + netinet/ip_ipsp.h \ + netinet/tcp.h \ + netinet6/ipsec.h \ + netipsec/ipsec.h \ + mach/mach_time.h \ + pwd.h \ + signal.h \ + stdarg.h \ + stdio.h \ + stdlib.h \ + string.h \ + sys/cdefs.h \ + sys/endian.h \ + sys/ndir.h \ + sys/param.h \ + sys/pstat.h \ + sys/socket.h \ + sys/stat.h \ + sys/sysctl.h \ + sys/types.h \ + sys/uio.h \ + sys/un.h \ + sys/wait.h \ + syslog.h \ + ucred.h \ + unistd.h \ + vis.h \ +]) + +# login_cap.h requires sys/types.h on NetBSD +AC_CHECK_HEADERS([login_cap.h], [], [], [ +#include +]) + +pfkeyv2_h="net/pfkeyv2.h" +IKED_USER=_iked + +# Check for some target-specific stuff +case "$host" in +*-*-aix*) + check_for_aix_broken_getaddrinfo=1 + AC_DEFINE([BROKEN_REALPATH], [1], [Define if you have a broken realpath.]) + AC_DEFINE([SETEUID_BREAKS_SETUID], [1], + [Define if your platform breaks doing a seteuid before a setuid]) + AC_DEFINE([BROKEN_SETREUID], [1], [Define if your setreuid() is broken]) + AC_DEFINE([BROKEN_SETREGID], [1], [Define if your setregid() is broken]) + AC_DEFINE([SPT_TYPE], [SPT_REUSEARGV], + [Define to a Set Process Title type if your system is + supported by bsd-setproctitle.c]) + ;; +*-*-darwin*) + AC_MSG_CHECKING([if we have working getaddrinfo]) + AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include +main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) + exit(0); + else + exit(1); +} + ]])], + [AC_MSG_RESULT([working])], + [AC_MSG_RESULT([buggy]) + AC_DEFINE([BROKEN_GETADDRINFO], [1], + [getaddrinfo is broken (if present)]) + ], + [AC_MSG_RESULT([assume it is working])]) + AC_DEFINE([SETEUID_BREAKS_SETUID]) + AC_DEFINE([BROKEN_SETREUID]) + AC_DEFINE([BROKEN_SETREGID]) + AC_DEFINE([BROKEN_GLOB], [1], [OS X glob does not do what we expect]) + AC_DEFINE_UNQUOTED([BIND_8_COMPAT], [1], + [Define if your resolver libs need this for getrrsetbyname]) + AC_DEFINE([SPT_TYPE], [SPT_REUSEARGV], + [Define to a Set Process Title type if your system is + supported by setproctitle.c]) + # IPv6 compatibility + AC_DEFINE([__APPLE_USE_RFC_3542], [1], [Use RFC3542 IPv6 API]) + + # We cannot check if NAT-T is really supported by the kernel because + # it is not exposed in the public version of the pfkeyv2.h header. + AC_DEFINE([HAVE_APPLE_NATT], [1], [Use Apple's NAT-T support]) + + ac_deprecated_daemon=yes + ;; +*-*-dragonfly*) + IKEDLIBS="$IKEDLIBS -lcrypt" + ;; +*-*-hpux*) + # first we define all of the options common to all HP-UX releases + CPPFLAGS="$CPPFLAGS -D_HPUX_SOURCE -D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED=1" + AC_DEFINE([SPT_TYPE], [SPT_PSTAT]) + ;; +*-*-linux*) + check_for_libcrypt_later=1 + AC_DEFINE([SPT_TYPE], [SPT_REUSEARGV]) + case `uname -r` in + 1.*|2.0.*) + AC_DEFINE(BROKEN_CMSG_TYPE, 1, + [Define if cmsg_type is not passed correctly]) + ;; + esac + AC_DEFINE([BROKEN_HMAC_SHA2_256], 1, + [Uses pre-standard HMAC-SHA2-256 truncation]) + pfkeyv2_h="linux/pfkeyv2.h" + IKED_USER=iked + ;; +*-*-netbsd*) + check_for_libcrypt_before=1 + if test "x$withval" != "xno" ; then + need_dash_r=1 + fi + ;; +*-*-freebsd*) + check_for_libcrypt_later=1 + ;; +*-*-openbsd*) + echo "Please use -current" + ;; +*-*-solaris*) + if test "x$withval" != "xno" ; then + need_dash_r=1 + fi + ;; +*-*-sunos4*) + CPPFLAGS="$CPPFLAGS -DSUNOS4" + ;; +esac + +dnl IRIX and Solaris 2.5.1 have dirname() in libgen +AC_CHECK_FUNCS([dirname], [AC_CHECK_HEADERS([libgen.h])] , [ + AC_CHECK_LIB([gen], [dirname], [ + AC_CACHE_CHECK([for broken dirname], + ac_cv_have_broken_dirname, [ + save_LIBS="$LIBS" + LIBS="$LIBS -lgen" + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include +#include + +int main(int argc, char **argv) { + char *s, buf[32]; + + strncpy(buf,"/etc", 32); + s = dirname(buf); + if (!s || strncmp(s, "/", 32) != 0) { + exit(1); + } else { + exit(0); + } +} + ]])], + [ ac_cv_have_broken_dirname="no" ], + [ ac_cv_have_broken_dirname="yes" ], + [ ac_cv_have_broken_dirname="no" ], + ) + LIBS="$save_LIBS" + ]) + if test "x$ac_cv_have_broken_dirname" = "xno" ; then + LIBS="$LIBS -lgen" + AC_DEFINE([HAVE_DIRNAME]) + AC_CHECK_HEADERS([libgen.h]) + fi + ]) +]) + +AC_SEARCH_LIBS([basename], [gen], [AC_DEFINE([HAVE_BASENAME], [1], + [Define if you have the basename function.])]) + +dnl zlib is required +AC_ARG_WITH([zlib], + [ --with-zlib=PATH Use zlib in PATH], + [ if test "x$withval" = "xno" ; then + AC_MSG_ERROR([*** zlib is required ***]) + elif test "x$withval" != "xyes"; then + if test -d "$withval/lib"; then + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}" + else + LDFLAGS="-L${withval}/lib ${LDFLAGS}" + fi + else + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}" + else + LDFLAGS="-L${withval} ${LDFLAGS}" + fi + fi + if test -d "$withval/include"; then + CPPFLAGS="-I${withval}/include ${CPPFLAGS}" + else + CPPFLAGS="-I${withval} ${CPPFLAGS}" + fi + fi ] +) + +AC_CHECK_HEADER([zlib.h], ,[AC_MSG_ERROR([*** zlib.h missing - please install first or check config.log ***])]) +AC_CHECK_LIB([z], [deflate], , + [ + saved_CPPFLAGS="$CPPFLAGS" + saved_LDFLAGS="$LDFLAGS" + save_LIBS="$LIBS" + dnl Check default zlib install dir + if test -n "${need_dash_r}"; then + LDFLAGS="-L/usr/local/lib -R/usr/local/lib ${saved_LDFLAGS}" + else + LDFLAGS="-L/usr/local/lib ${saved_LDFLAGS}" + fi + CPPFLAGS="-I/usr/local/include ${saved_CPPFLAGS}" + LIBS="$LIBS -lz" + AC_TRY_LINK_FUNC([deflate], [AC_DEFINE([HAVE_LIBZ])], + [ + AC_MSG_ERROR([*** zlib missing - please install first or check config.log ***]) + ] + ) + ] +) + +AC_ARG_WITH([zlib-version-check], + [ --without-zlib-version-check Disable zlib version check], + [ if test "x$withval" = "xno" ; then + zlib_check_nonfatal=1 + fi + ] +) + +AC_MSG_CHECKING([for possibly buggy zlib]) +AC_RUN_IFELSE([AC_LANG_PROGRAM([[ +#include +#include + ]], + [[ + int a=0, b=0, c=0, d=0, n, v; + n = sscanf(ZLIB_VERSION, "%d.%d.%d.%d", &a, &b, &c, &d); + if (n != 3 && n != 4) + exit(1); + v = a*1000000 + b*10000 + c*100 + d; + fprintf(stderr, "found zlib version %s (%d)\n", ZLIB_VERSION, v); + + /* 1.1.4 is OK */ + if (a == 1 && b == 1 && c >= 4) + exit(0); + + /* 1.2.3 and up are OK */ + if (v >= 1020300) + exit(0); + + exit(2); + ]])], + AC_MSG_RESULT([no]), + [ AC_MSG_RESULT([yes]) + if test -z "$zlib_check_nonfatal" ; then + AC_MSG_ERROR([*** zlib too old - check config.log *** +Your reported zlib version has known security problems. It's possible your +vendor has fixed these problems without changing the version number. If you +are sure this is the case, you can disable the check by running +"./configure --without-zlib-version-check". +If you are in doubt, upgrade zlib to version 1.2.3 or greater. +See http://www.gzip.org/zlib/ for details.]) + else + AC_MSG_WARN([zlib version may have security problems]) + fi + ], + [ AC_MSG_WARN([cross compiling: not checking zlib version]) ] +) + +dnl Checks for libutil functions +AC_CHECK_HEADERS([libutil.h]) +AC_SEARCH_LIBS([fmt_scaled], [util bsd]) +AC_CHECK_FUNCS([fmt_scaled]) +AC_CHECK_HEADERS([libutil.h]) +AC_SEARCH_LIBS([fmt_scaled], [util bsd]) + +AC_MSG_CHECKING([for /proc/pid/fd directory]) +if test -d "/proc/$$/fd" ; then + AC_DEFINE(HAVE_PROC_PID, 1, [Define if you have /proc/$pid/fd]) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +AC_CHECK_FUNCS([ \ + arc4random \ + arc4random_buf \ + arc4random_uniform \ + asprintf \ + bcopy \ + chflags \ + closefrom \ + dirfd \ + dirname \ + fgetln \ + freeaddrinfo \ + getaddrinfo \ + getnameinfo \ + getopt \ + getpeereid \ + memmove \ + setproctitle \ + setregid \ + setreuid \ + strlcat \ + strlcpy \ + strnvis \ + strtonum \ + strmode \ + sysconf \ + waitpid \ +]) + +# IRIX has a const char return value for gai_strerror() +AC_CHECK_FUNCS([gai_strerror], [ + AC_DEFINE([HAVE_GAI_STRERROR]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#include + +const char *gai_strerror(int); + ]], [[ + char *str; + str = gai_strerror(0); + ]])], [ + AC_DEFINE([HAVE_CONST_GAI_STRERROR_PROTO], [1], + [Define if gai_strerror() returns const char *])], [])]) + +AC_CHECK_DECL([strsep], + [AC_CHECK_FUNCS([strsep])], + [], + [ +#ifdef HAVE_STRING_H +# include +#endif + ]) + +AC_CHECK_DECLS([O_NONBLOCK], , , + [ +#include +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef HAVE_FCNTL_H +# include +#endif + ]) + +AC_CHECK_DECLS([writev], , , [ +#include +#include +#include + ]) + +AC_CHECK_FUNCS([setresuid], [ + dnl Some platorms have setresuid that isn't implemented, test for this + AC_MSG_CHECKING([if setresuid seems to work]) + AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ +#include +#include + ]], [[ + errno=0; + setresuid(0,0,0); + if (errno==ENOSYS) + exit(1); + else + exit(0); + ]])], + [AC_MSG_RESULT([yes])], + [AC_DEFINE([BROKEN_SETRESUID], [1], + [Define if your setresuid() is broken]) + AC_MSG_RESULT([not implemented])], + [AC_MSG_WARN([cross compiling: not checking setresuid])] + ) +]) + +AC_CHECK_FUNCS([setresgid], [ + dnl Some platorms have setresgid that isn't implemented, test for this + AC_MSG_CHECKING([if setresgid seems to work]) + AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ +#include +#include + ]], [[ + errno=0; + setresgid(0,0,0); + if (errno==ENOSYS) + exit(1); + else + exit(0); + ]])], + [AC_MSG_RESULT([yes])], + [AC_DEFINE([BROKEN_SETRESGID], [1], + [Define if your setresgid() is broken]) + AC_MSG_RESULT([not implemented])], + [AC_MSG_WARN([cross compiling: not checking setresuid])] + ) +]) + +dnl Checks for time functions +AC_CHECK_FUNCS([gettimeofday time]) + +AC_CHECK_FUNC([daemon], + [AC_DEFINE([HAVE_DAEMON], [1], [Define if your libraries define daemon()])], + [AC_CHECK_LIB([bsd], [daemon], + [LIBS="$LIBS -lbsd"; AC_DEFINE([HAVE_DAEMON])])] +) +if test "x$ac_deprecated_daemon" = "xyes"; then + AC_DEFINE([HAVE_DEPRECATED_DAEMON], [1], + [System declares daemon as deprecated]) +fi + +##chl +AC_CHECK_FUNC([fparseln], + [AC_DEFINE([HAVE_FPARSELN], [1], [Define if your libraries define fparseln()])], + [AC_CHECK_LIB([util], [fparseln], + [LIBS="$LIBS -lutil"; AC_DEFINE([HAVE_FPARSELN])])] +) + +AC_CHECK_FUNC([clock_gettime], + [AC_DEFINE([HAVE_CLOCK_GETTIME], [1], [Define if your libraries define clock_gettime()])], + [AC_CHECK_LIB([rt], [clock_gettime], + [LIBS="$LIBS -lrt"; AC_DEFINE([HAVE_CLOCK_GETTIME])])] +) + +AC_SEARCH_LIBS(res_9_b64_ntop, resolv) +##chl + +# Check for broken snprintf +if test "x$ac_cv_func_snprintf" = "xyes" ; then + AC_MSG_CHECKING([whether snprintf correctly terminates long strings]) + AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ #include ]], + [[ + char b[5]; + snprintf(b,5,"123456789"); + exit(b[4]!='\0'); + ]])], + [AC_MSG_RESULT([yes])], + [ + AC_MSG_RESULT([no]) + AC_DEFINE([BROKEN_SNPRINTF], [1], + [Define if your snprintf is busted]) + AC_MSG_WARN([****** Your snprintf() function is broken, complain to your vendor]) + ], + [ AC_MSG_WARN([cross compiling: Assuming working snprintf()]) ] + ) +fi + +# If we don't have a working asprintf, then we strongly depend on vsnprintf +# returning the right thing on overflow: the number of characters it tried to +# create (as per SUSv3) +if test "x$ac_cv_func_asprintf" != "xyes" && \ + test "x$ac_cv_func_vsnprintf" = "xyes" ; then + AC_MSG_CHECKING([whether vsnprintf returns correct values on overflow]) + AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ +#include +#include +#include + +int x_snprintf(char *str,size_t count,const char *fmt,...) +{ + size_t ret; va_list ap; + va_start(ap, fmt); ret = vsnprintf(str, count, fmt, ap); va_end(ap); + return ret; +} + ]], [[ + char x[1]; + exit(x_snprintf(x, 1, "%s %d", "hello", 12345) == 11 ? 0 : 1); + ]])], + [AC_MSG_RESULT([yes])], + [ + AC_MSG_RESULT([no]) + AC_DEFINE([BROKEN_SNPRINTF], [1], + [Define if your snprintf is busted]) + AC_MSG_WARN([****** Your vsnprintf() function is broken, complain to your vendor]) + ], + [ AC_MSG_WARN([cross compiling: Assuming working vsnprintf()]) ] + ) +fi + +# On systems where [v]snprintf is broken, but is declared in stdio, +# check that the fmt argument is const char * or just char *. +# This is only useful for when BROKEN_SNPRINTF +AC_MSG_CHECKING([whether snprintf can declare const char *fmt]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +int snprintf(char *a, size_t b, const char *c, ...) { return 0; } + ]], [[ + snprintf(0, 0, 0); + ]])], + [AC_MSG_RESULT([yes]) + AC_DEFINE([SNPRINTF_CONST], [const], + [Define as const if snprintf() can declare const char *fmt])], + [AC_MSG_RESULT([no]) + AC_DEFINE([SNPRINTF_CONST], [/* not const */])]) + +# Check for missing getpeereid (or equiv) support +NO_PEERCHECK="" +if test "x$ac_cv_func_getpeereid" != "xyes" -a "x$ac_cv_func_getpeerucred" != "xyes"; then + AC_MSG_CHECKING([whether system supports SO_PEERCRED getsockopt]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#include ]], [[int i = SO_PEERCRED;]])], + [ AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_SO_PEERCRED], [1], [Have PEERCRED socket option]) + ], [AC_MSG_RESULT([no]) + NO_PEERCHECK=1 + ]) +fi + +dnl see whether mkstemp() requires XXXXXX +if test "x$ac_cv_func_mkdtemp" = "xyes" ; then +AC_MSG_CHECKING([for (overly) strict mkstemp]) +AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ +#include + ]], [[ + char template[]="conftest.mkstemp-test"; + if (mkstemp(template) == -1) + exit(1); + unlink(template); + exit(0); + ]])], + [ + AC_MSG_RESULT([no]) + ], + [ + AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_STRICT_MKSTEMP], [1], [Silly mkstemp()]) + ], + [ + AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_STRICT_MKSTEMP]) + ] +) +fi + +if test "x$ac_cv_func_getaddrinfo" = "xyes" && \ + test "x$check_for_hpux_broken_getaddrinfo" = "x1"; then + AC_MSG_CHECKING([if getaddrinfo seems to work]) + AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ +#include +#include +#include +#include +#include + +#define TEST_PORT "2222" + ]], [[ + int err, sock; + struct addrinfo *gai_ai, *ai, hints; + char ntop[NI_MAXHOST], strport[NI_MAXSERV], *name = NULL; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + err = getaddrinfo(name, TEST_PORT, &hints, &gai_ai); + if (err != 0) { + fprintf(stderr, "getaddrinfo failed (%s)", gai_strerror(err)); + exit(1); + } + + for (ai = gai_ai; ai != NULL; ai = ai->ai_next) { + if (ai->ai_family != AF_INET6) + continue; + + err = getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, + sizeof(ntop), strport, sizeof(strport), + NI_NUMERICHOST|NI_NUMERICSERV); + + if (err != 0) { + if (err == EAI_SYSTEM) + perror("getnameinfo EAI_SYSTEM"); + else + fprintf(stderr, "getnameinfo failed: %s\n", + gai_strerror(err)); + exit(2); + } + + sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (sock < 0) + perror("socket"); + if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { + if (errno == EBADF) + exit(3); + } + } + exit(0); + ]])], + [ + AC_MSG_RESULT([yes]) + ], + [ + AC_MSG_RESULT([no]) + AC_DEFINE([BROKEN_GETADDRINFO]) + ], + [ + AC_MSG_RESULT([cross-compiling, assuming yes]) + ] + ) +fi + +if test "x$ac_cv_func_getaddrinfo" = "xyes" && \ + test "x$check_for_aix_broken_getaddrinfo" = "x1"; then + AC_MSG_CHECKING([if getaddrinfo seems to work]) + AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ +#include +#include +#include +#include +#include + +#define TEST_PORT "2222" + ]], [[ + int err, sock; + struct addrinfo *gai_ai, *ai, hints; + char ntop[NI_MAXHOST], strport[NI_MAXSERV], *name = NULL; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + err = getaddrinfo(name, TEST_PORT, &hints, &gai_ai); + if (err != 0) { + fprintf(stderr, "getaddrinfo failed (%s)", gai_strerror(err)); + exit(1); + } + + for (ai = gai_ai; ai != NULL; ai = ai->ai_next) { + if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) + continue; + + err = getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, + sizeof(ntop), strport, sizeof(strport), + NI_NUMERICHOST|NI_NUMERICSERV); + + if (ai->ai_family == AF_INET && err != 0) { + perror("getnameinfo"); + exit(2); + } + } + exit(0); + ]])], + [ + AC_MSG_RESULT([yes]) + AC_DEFINE([AIX_GETNAMEINFO_HACK], [1], + [Define if you have a getaddrinfo that fails + for the all-zeros IPv6 address]) + ], + [ + AC_MSG_RESULT([no]) + AC_DEFINE([BROKEN_GETADDRINFO]) + ], + [ + AC_MSG_RESULT([cross-compiling, assuming no]) + ] + ) +fi + +# Check for PAM libs +PAM_MSG="no" +AC_ARG_WITH([pam], + [ --with-pam Enable PAM support ], + [ + if test "x$withval" != "xno" ; then + if test "x$ac_cv_header_security_pam_appl_h" != "xyes" && \ + test "x$ac_cv_header_pam_pam_appl_h" != "xyes" ; then + AC_MSG_ERROR([PAM headers not found]) + fi + + saved_LIBS="$LIBS" + AC_CHECK_LIB([dl], [dlopen], , ) + AC_CHECK_LIB([pam], [pam_set_item], , [AC_MSG_ERROR([*** libpam missing])]) + AC_CHECK_FUNCS([pam_getenvlist]) + AC_CHECK_FUNCS([pam_putenv]) + LIBS="$saved_LIBS" + + PAM_MSG="yes" + + IKEDLIBS="$IKEDLIBS -lpam" + AC_DEFINE([USE_PAM], [1], + [Define if you want to enable PAM support]) + + if test $ac_cv_lib_dl_dlopen = yes; then + case "$LIBS" in + *-ldl*) + # libdl already in LIBS + ;; + *) + IKEDLIBS="$IKEDLIBS -ldl" + ;; + esac + fi + fi + ] +) + +# Check for older PAM +if test "x$PAM_MSG" = "xyes" ; then + # Check PAM strerror arguments (old PAM) + AC_MSG_CHECKING([whether pam_strerror takes only one argument]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#if defined(HAVE_SECURITY_PAM_APPL_H) +#include +#elif defined (HAVE_PAM_PAM_APPL_H) +#include +#endif + ]], [[ +(void)pam_strerror((pam_handle_t *)NULL, -1); + ]])], [AC_MSG_RESULT([no])], [ + AC_DEFINE([HAVE_OLD_PAM], [1], + [Define if you have an old version of PAM + which takes only one argument to pam_strerror]) + AC_MSG_RESULT([yes]) + PAM_MSG="yes (old library)" + + ]) +fi + +# Check for long long datatypes +AC_CHECK_TYPES([long long, unsigned long long, long double]) + +# Check datatype sizes +AC_CHECK_SIZEOF([short int], [2]) +AC_CHECK_SIZEOF([int], [4]) +AC_CHECK_SIZEOF([long int], [4]) +AC_CHECK_SIZEOF([long long int], [8]) + +AC_CHECK_TYPES([float_t], [], [], [[#include ]]) + +# Sanity check long long for some platforms (AIX) +if test "x$ac_cv_sizeof_long_long_int" = "x4" ; then + ac_cv_sizeof_long_long_int=0 +fi + +# compute LLONG_MIN and LLONG_MAX if we don't know them. +if test -z "$have_llong_max"; then + AC_MSG_CHECKING([for max value of long long]) + AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ +#include +/* Why is this so damn hard? */ +#ifdef __GNUC__ +# undef __GNUC__ +#endif +#define __USE_ISOC99 +#include +#define DATA "conftest.llminmax" +#define my_abs(a) ((a) < 0 ? ((a) * -1) : (a)) + +/* + * printf in libc on some platforms (eg old Tru64) does not understand %lld so + * we do this the hard way. + */ +static int +fprint_ll(FILE *f, long long n) +{ + unsigned int i; + int l[sizeof(long long) * 8]; + + if (n < 0) + if (fprintf(f, "-") < 0) + return -1; + for (i = 0; n != 0; i++) { + l[i] = my_abs(n % 10); + n /= 10; + } + do { + if (fprintf(f, "%d", l[--i]) < 0) + return -1; + } while (i != 0); + if (fprintf(f, " ") < 0) + return -1; + return 0; +} + ]], [[ + FILE *f; + long long i, llmin, llmax = 0; + + if((f = fopen(DATA,"w")) == NULL) + exit(1); + +#if defined(LLONG_MIN) && defined(LLONG_MAX) + fprintf(stderr, "Using system header for LLONG_MIN and LLONG_MAX\n"); + llmin = LLONG_MIN; + llmax = LLONG_MAX; +#else + fprintf(stderr, "Calculating LLONG_MIN and LLONG_MAX\n"); + /* This will work on one's complement and two's complement */ + for (i = 1; i > llmax; i <<= 1, i++) + llmax = i; + llmin = llmax + 1LL; /* wrap */ +#endif + + /* Sanity check */ + if (llmin + 1 < llmin || llmin - 1 < llmin || llmax + 1 > llmax + || llmax - 1 > llmax || llmin == llmax || llmin == 0 + || llmax == 0 || llmax < LONG_MAX || llmin > LONG_MIN) { + fprintf(f, "unknown unknown\n"); + exit(2); + } + + if (fprint_ll(f, llmin) < 0) + exit(3); + if (fprint_ll(f, llmax) < 0) + exit(4); + if (fclose(f) < 0) + exit(5); + exit(0); + ]])], + [ + llong_min=`$AWK '{print $1}' conftest.llminmax` + llong_max=`$AWK '{print $2}' conftest.llminmax` + + AC_MSG_RESULT([$llong_max]) + AC_DEFINE_UNQUOTED([LLONG_MAX], [${llong_max}LL], + [max value of long long calculated by configure]) + AC_MSG_CHECKING([for min value of long long]) + AC_MSG_RESULT([$llong_min]) + AC_DEFINE_UNQUOTED([LLONG_MIN], [${llong_min}LL], + [min value of long long calculated by configure]) + ], + [ + AC_MSG_RESULT([not found]) + ], + [ + AC_MSG_WARN([cross compiling: not checking]) + ] + ) +fi + + +# More checks for data types +AC_CACHE_CHECK([for u_int type], ac_cv_have_u_int, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ u_int a; a = 1;]])], + [ ac_cv_have_u_int="yes" ], [ ac_cv_have_u_int="no" + ]) +]) +if test "x$ac_cv_have_u_int" = "xyes" ; then + AC_DEFINE([HAVE_U_INT], [1], [define if you have u_int data type]) + have_u_int=1 +fi + +AC_CACHE_CHECK([for intXX_t types], ac_cv_have_intxx_t, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ int8_t a; int16_t b; int32_t c; a = b = c = 1;]])], + [ ac_cv_have_intxx_t="yes" ], [ ac_cv_have_intxx_t="no" + ]) +]) +if test "x$ac_cv_have_intxx_t" = "xyes" ; then + AC_DEFINE([HAVE_INTXX_T], [1], [define if you have intxx_t data type]) + have_intxx_t=1 +fi + +if (test -z "$have_intxx_t" && \ + test "x$ac_cv_header_stdint_h" = "xyes") +then + AC_MSG_CHECKING([for intXX_t types in stdint.h]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ int8_t a; int16_t b; int32_t c; a = b = c = 1;]])], + [ + AC_DEFINE([HAVE_INTXX_T]) + AC_MSG_RESULT([yes]) + ], [ AC_MSG_RESULT([no]) + ]) +fi + +AC_CACHE_CHECK([for int64_t type], ac_cv_have_int64_t, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#ifdef HAVE_STDINT_H +# include +#endif +#include +#ifdef HAVE_SYS_BITYPES_H +# include +#endif + ]], [[ +int64_t a; a = 1; + ]])], + [ ac_cv_have_int64_t="yes" ], [ ac_cv_have_int64_t="no" + ]) +]) +if test "x$ac_cv_have_int64_t" = "xyes" ; then + AC_DEFINE([HAVE_INT64_T], [1], [define if you have int64_t data type]) +fi + +AC_CACHE_CHECK([for u_intXX_t types], ac_cv_have_u_intxx_t, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ u_int8_t a; u_int16_t b; u_int32_t c; a = b = c = 1;]])], + [ ac_cv_have_u_intxx_t="yes" ], [ ac_cv_have_u_intxx_t="no" + ]) +]) +if test "x$ac_cv_have_u_intxx_t" = "xyes" ; then + AC_DEFINE([HAVE_U_INTXX_T], [1], [define if you have u_intxx_t data type]) + have_u_intxx_t=1 +fi + +if test -z "$have_u_intxx_t" ; then + AC_MSG_CHECKING([for u_intXX_t types in sys/socket.h]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ u_int8_t a; u_int16_t b; u_int32_t c; a = b = c = 1;]])], + [ + AC_DEFINE([HAVE_U_INTXX_T]) + AC_MSG_RESULT([yes]) + ], [ AC_MSG_RESULT([no]) + ]) +fi + +AC_CACHE_CHECK([for u_int64_t types], ac_cv_have_u_int64_t, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ u_int64_t a; a = 1;]])], + [ ac_cv_have_u_int64_t="yes" ], [ ac_cv_have_u_int64_t="no" + ]) +]) +if test "x$ac_cv_have_u_int64_t" = "xyes" ; then + AC_DEFINE([HAVE_U_INT64_T], [1], [define if you have u_int64_t data type]) + have_u_int64_t=1 +fi + +if test -z "$have_u_int64_t" ; then + AC_MSG_CHECKING([for u_int64_t type in sys/bitypes.h]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ u_int64_t a; a = 1]])], + [ + AC_DEFINE([HAVE_U_INT64_T]) + AC_MSG_RESULT([yes]) + ], [ AC_MSG_RESULT([no]) + ]) +fi + +if test -z "$have_u_intxx_t" ; then + AC_CACHE_CHECK([for uintXX_t types], ac_cv_have_uintxx_t, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include + ]], [[ + uint8_t a; + uint16_t b; + uint32_t c; + a = b = c = 1; + ]])], + [ ac_cv_have_uintxx_t="yes" ], [ ac_cv_have_uintxx_t="no" + ]) + ]) + if test "x$ac_cv_have_uintxx_t" = "xyes" ; then + AC_DEFINE([HAVE_UINTXX_T], [1], + [define if you have uintxx_t data type]) + fi +fi + +if test -z "$have_uintxx_t" ; then + AC_MSG_CHECKING([for uintXX_t types in stdint.h]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ uint8_t a; uint16_t b; uint32_t c; a = b = c = 1;]])], + [ + AC_DEFINE([HAVE_UINTXX_T]) + AC_MSG_RESULT([yes]) + ], [ AC_MSG_RESULT([no]) + ]) +fi + +if (test -z "$have_u_intxx_t" || test -z "$have_intxx_t" && \ + test "x$ac_cv_header_sys_bitypes_h" = "xyes") +then + AC_MSG_CHECKING([for intXX_t and u_intXX_t types in sys/bitypes.h]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include + ]], [[ + int8_t a; int16_t b; int32_t c; + u_int8_t e; u_int16_t f; u_int32_t g; + a = b = c = e = f = g = 1; + ]])], + [ + AC_DEFINE([HAVE_U_INTXX_T]) + AC_DEFINE([HAVE_INTXX_T]) + AC_MSG_RESULT([yes]) + ], [AC_MSG_RESULT([no]) + ]) +fi + + +AC_CACHE_CHECK([for u_char], ac_cv_have_u_char, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ u_char foo; foo = 125; ]])], + [ ac_cv_have_u_char="yes" ], [ ac_cv_have_u_char="no" + ]) +]) +if test "x$ac_cv_have_u_char" = "xyes" ; then + AC_DEFINE([HAVE_U_CHAR], [1], [define if you have u_char data type]) +fi +## + +#TYPE_SOCKLEN_T + +## +AC_CHECK_TYPES([sig_atomic_t], , , [#include ]) +AC_CHECK_TYPES([fsblkcnt_t, fsfilcnt_t], , , [ +#include +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +#ifdef HAVE_SYS_STATFS_H +#include +#endif +#ifdef HAVE_SYS_STATVFS_H +#include +#endif +]) + +AC_CHECK_TYPES([in_addr_t, in_port_t], , , +[#include +#include ]) + +AC_CACHE_CHECK([for size_t], ac_cv_have_size_t, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ size_t foo; foo = 1235; ]])], + [ ac_cv_have_size_t="yes" ], [ ac_cv_have_size_t="no" + ]) +]) +if test "x$ac_cv_have_size_t" = "xyes" ; then + AC_DEFINE([HAVE_SIZE_T], [1], [define if you have size_t data type]) +fi + +AC_CACHE_CHECK([for ssize_t], ac_cv_have_ssize_t, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ ssize_t foo; foo = 1235; ]])], + [ ac_cv_have_ssize_t="yes" ], [ ac_cv_have_ssize_t="no" + ]) +]) +if test "x$ac_cv_have_ssize_t" = "xyes" ; then + AC_DEFINE([HAVE_SSIZE_T], [1], [define if you have ssize_t data type]) +fi + +AC_CACHE_CHECK([for clock_t], ac_cv_have_clock_t, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ clock_t foo; foo = 1235; ]])], + [ ac_cv_have_clock_t="yes" ], [ ac_cv_have_clock_t="no" + ]) +]) +if test "x$ac_cv_have_clock_t" = "xyes" ; then + AC_DEFINE([HAVE_CLOCK_T], [1], [define if you have clock_t data type]) +fi + +AC_CACHE_CHECK([for sa_family_t], ac_cv_have_sa_family_t, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#include + ]], [[ sa_family_t foo; foo = 1235; ]])], + [ ac_cv_have_sa_family_t="yes" ], + [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#include + ]], [[ sa_family_t foo; foo = 1235; ]])], + [ ac_cv_have_sa_family_t="yes" ], + [ ac_cv_have_sa_family_t="no" ] + ) + ]) +]) +if test "x$ac_cv_have_sa_family_t" = "xyes" ; then + AC_DEFINE([HAVE_SA_FAMILY_T], [1], + [define if you have sa_family_t data type]) +fi + +AC_CACHE_CHECK([for pid_t], ac_cv_have_pid_t, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ pid_t foo; foo = 1235; ]])], + [ ac_cv_have_pid_t="yes" ], [ ac_cv_have_pid_t="no" + ]) +]) +if test "x$ac_cv_have_pid_t" = "xyes" ; then + AC_DEFINE([HAVE_PID_T], [1], [define if you have pid_t data type]) +fi + +AC_CACHE_CHECK([for mode_t], ac_cv_have_mode_t, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ mode_t foo; foo = 1235; ]])], + [ ac_cv_have_mode_t="yes" ], [ ac_cv_have_mode_t="no" + ]) +]) +if test "x$ac_cv_have_mode_t" = "xyes" ; then + AC_DEFINE([HAVE_MODE_T], [1], [define if you have mode_t data type]) +fi + + +AC_CACHE_CHECK([for struct sockaddr_storage], ac_cv_have_struct_sockaddr_storage, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#include + ]], [[ struct sockaddr_storage s; ]])], + [ ac_cv_have_struct_sockaddr_storage="yes" ], + [ ac_cv_have_struct_sockaddr_storage="no" + ]) +]) +if test "x$ac_cv_have_struct_sockaddr_storage" = "xyes" ; then + AC_DEFINE([HAVE_STRUCT_SOCKADDR_STORAGE], [1], + [define if you have struct sockaddr_storage data type]) +fi + +AC_CACHE_CHECK([for struct sockaddr_in6], ac_cv_have_struct_sockaddr_in6, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#include + ]], [[ struct sockaddr_in6 s; s.sin6_family = 0; ]])], + [ ac_cv_have_struct_sockaddr_in6="yes" ], + [ ac_cv_have_struct_sockaddr_in6="no" + ]) +]) +if test "x$ac_cv_have_struct_sockaddr_in6" = "xyes" ; then + AC_DEFINE([HAVE_STRUCT_SOCKADDR_IN6], [1], + [define if you have struct sockaddr_in6 data type]) +fi + +AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#include + ]], [[ struct in6_addr s; s.s6_addr[0] = 0; ]])], + [ ac_cv_have_struct_in6_addr="yes" ], + [ ac_cv_have_struct_in6_addr="no" + ]) +]) +if test "x$ac_cv_have_struct_in6_addr" = "xyes" ; then + AC_DEFINE([HAVE_STRUCT_IN6_ADDR], [1], + [define if you have struct in6_addr data type]) + +dnl Now check for sin6_scope_id + AC_CHECK_MEMBERS([struct sockaddr_in6.sin6_scope_id], , , + [ +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#include + ]) +fi + +AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#include + ]], [[ struct addrinfo s; s.ai_flags = AI_PASSIVE; ]])], + [ ac_cv_have_struct_addrinfo="yes" ], + [ ac_cv_have_struct_addrinfo="no" + ]) +]) +if test "x$ac_cv_have_struct_addrinfo" = "xyes" ; then + AC_DEFINE([HAVE_STRUCT_ADDRINFO], [1], + [define if you have struct addrinfo data type]) +fi + +AC_CACHE_CHECK([for struct timeval], ac_cv_have_struct_timeval, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ struct timeval tv; tv.tv_sec = 1;]])], + [ ac_cv_have_struct_timeval="yes" ], + [ ac_cv_have_struct_timeval="no" + ]) +]) +if test "x$ac_cv_have_struct_timeval" = "xyes" ; then + AC_DEFINE([HAVE_STRUCT_TIMEVAL], [1], [define if you have struct timeval]) + have_struct_timeval=1 +fi + +AC_CHECK_TYPES([struct timespec]) + +# We need int64_t or else certian parts of the compile will fail. +if test "x$ac_cv_have_int64_t" = "xno" && \ + test "x$ac_cv_sizeof_long_int" != "x8" && \ + test "x$ac_cv_sizeof_long_long_int" = "x0" ; then + echo "OpenSSH requires int64_t support. Contact your vendor or install" + echo "an alternative compiler (I.E., GCC) before continuing." + echo "" + exit 1; +else +dnl test snprintf (broken on SCO w/gcc) + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include +#include +#ifdef HAVE_SNPRINTF +main() +{ + char buf[50]; + char expected_out[50]; + int mazsize = 50 ; +#if (SIZEOF_LONG_INT == 8) + long int num = 0x7fffffffffffffff; +#else + long long num = 0x7fffffffffffffffll; +#endif + strcpy(expected_out, "9223372036854775807"); + snprintf(buf, mazsize, "%lld", num); + if(strcmp(buf, expected_out) != 0) + exit(1); + exit(0); +} +#else +main() { exit(0); } +#endif + ]])], [ true ], [ AC_DEFINE([BROKEN_SNPRINTF]) ], + AC_MSG_WARN([cross compiling: Assuming working snprintf()]) + ) +fi + +AC_CACHE_CHECK([for ss_family field in struct sockaddr_storage], + ac_cv_have_ss_family_in_struct_ss, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#include + ]], [[ struct sockaddr_storage s; s.ss_family = 1; ]])], + [ ac_cv_have_ss_family_in_struct_ss="yes" ], + [ ac_cv_have_ss_family_in_struct_ss="no" ]) +]) +if test "x$ac_cv_have_ss_family_in_struct_ss" = "xyes" ; then + AC_DEFINE([HAVE_SS_FAMILY_IN_SS], [1], [Fields in struct sockaddr_storage]) +fi + +AC_CACHE_CHECK([for __ss_family field in struct sockaddr_storage], + ac_cv_have___ss_family_in_struct_ss, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#include + ]], [[ struct sockaddr_storage s; s.__ss_family = 1; ]])], + [ ac_cv_have___ss_family_in_struct_ss="yes" ], + [ ac_cv_have___ss_family_in_struct_ss="no" + ]) +]) +if test "x$ac_cv_have___ss_family_in_struct_ss" = "xyes" ; then + AC_DEFINE([HAVE___SS_FAMILY_IN_SS], [1], + [Fields in struct sockaddr_storage]) +fi + +AC_CACHE_CHECK([for pw_class field in struct passwd], + ac_cv_have_pw_class_in_struct_passwd, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ struct passwd p; p.pw_class = 0; ]])], + [ ac_cv_have_pw_class_in_struct_passwd="yes" ], + [ ac_cv_have_pw_class_in_struct_passwd="no" + ]) +]) +if test "x$ac_cv_have_pw_class_in_struct_passwd" = "xyes" ; then + AC_DEFINE([HAVE_PW_CLASS_IN_PASSWD], [1], + [Define if your password has a pw_class field]) +fi + +AC_CACHE_CHECK([for pw_expire field in struct passwd], + ac_cv_have_pw_expire_in_struct_passwd, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ struct passwd p; p.pw_expire = 0; ]])], + [ ac_cv_have_pw_expire_in_struct_passwd="yes" ], + [ ac_cv_have_pw_expire_in_struct_passwd="no" + ]) +]) +if test "x$ac_cv_have_pw_expire_in_struct_passwd" = "xyes" ; then + AC_DEFINE([HAVE_PW_EXPIRE_IN_PASSWD], [1], + [Define if your password has a pw_expire field]) +fi + +AC_CACHE_CHECK([for pw_change field in struct passwd], + ac_cv_have_pw_change_in_struct_passwd, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ struct passwd p; p.pw_change = 0; ]])], + [ ac_cv_have_pw_change_in_struct_passwd="yes" ], + [ ac_cv_have_pw_change_in_struct_passwd="no" + ]) +]) +if test "x$ac_cv_have_pw_change_in_struct_passwd" = "xyes" ; then + AC_DEFINE([HAVE_PW_CHANGE_IN_PASSWD], [1], + [Define if your password has a pw_change field]) +fi + +dnl make sure we're using the real structure members and not defines +AC_CACHE_CHECK([for msg_accrights field in struct msghdr], + ac_cv_have_accrights_in_msghdr, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#include + ]], [[ +#ifdef msg_accrights +#error "msg_accrights is a macro" +exit(1); +#endif +struct msghdr m; +m.msg_accrights = 0; +exit(0); + ]])], + [ ac_cv_have_accrights_in_msghdr="yes" ], + [ ac_cv_have_accrights_in_msghdr="no" ] + ) +]) +if test "x$ac_cv_have_accrights_in_msghdr" = "xyes" ; then + AC_DEFINE([HAVE_ACCRIGHTS_IN_MSGHDR], [1], + [Define if your system uses access rights style + file descriptor passing]) +fi + +AC_MSG_CHECKING([if struct statvfs.f_fsid is integral type]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#ifdef HAVE_SYS_TIME_H +# include +#endif +#ifdef HAVE_SYS_MOUNT_H +#include +#endif +#ifdef HAVE_SYS_STATVFS_H +#include +#endif + ]], [[ struct statvfs s; s.f_fsid = 0; ]])], + [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_RESULT([no]) + + AC_MSG_CHECKING([if fsid_t has member val]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#include + ]], [[ fsid_t t; t.val[0] = 0; ]])], + [ AC_MSG_RESULT([yes]) + AC_DEFINE([FSID_HAS_VAL], [1], [fsid_t has member val]) ], + [ AC_MSG_RESULT([no]) ]) + + AC_MSG_CHECKING([if f_fsid has member __val]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#include + ]], [[ fsid_t t; t.__val[0] = 0; ]])], + [ AC_MSG_RESULT([yes]) + AC_DEFINE([FSID_HAS___VAL], [1], [fsid_t has member __val]) ], + [ AC_MSG_RESULT([no]) ]) +]) + +AC_CACHE_CHECK([for msg_control field in struct msghdr], + ac_cv_have_control_in_msghdr, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#include + ]], [[ +#ifdef msg_control +#error "msg_control is a macro" +exit(1); +#endif +struct msghdr m; +m.msg_control = 0; +exit(0); + ]])], + [ ac_cv_have_control_in_msghdr="yes" ], + [ ac_cv_have_control_in_msghdr="no" ] + ) +]) +if test "x$ac_cv_have_control_in_msghdr" = "xyes" ; then + AC_DEFINE([HAVE_CONTROL_IN_MSGHDR], [1], + [Define if your system uses ancillary data style + file descriptor passing]) +fi + +AC_CACHE_CHECK([if libc defines __progname], ac_cv_libc_defines___progname, [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], + [[ extern char *__progname; printf("%s", __progname); ]])], + [ ac_cv_libc_defines___progname="yes" ], + [ ac_cv_libc_defines___progname="no" + ]) +]) +if test "x$ac_cv_libc_defines___progname" = "xyes" ; then + AC_DEFINE([HAVE___PROGNAME], [1], [Define if libc defines __progname]) +fi + +AC_CACHE_CHECK([whether $CC implements __FUNCTION__], ac_cv_cc_implements___FUNCTION__, [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ printf("%s", __FUNCTION__); ]])], + [ ac_cv_cc_implements___FUNCTION__="yes" ], + [ ac_cv_cc_implements___FUNCTION__="no" + ]) +]) +if test "x$ac_cv_cc_implements___FUNCTION__" = "xyes" ; then + AC_DEFINE([HAVE___FUNCTION__], [1], + [Define if compiler implements __FUNCTION__]) +fi + +AC_CACHE_CHECK([whether $CC implements __func__], ac_cv_cc_implements___func__, [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ printf("%s", __func__); ]])], + [ ac_cv_cc_implements___func__="yes" ], + [ ac_cv_cc_implements___func__="no" + ]) +]) +if test "x$ac_cv_cc_implements___func__" = "xyes" ; then + AC_DEFINE([HAVE___func__], [1], [Define if compiler implements __func__]) +fi + +AC_CACHE_CHECK([whether va_copy exists], ac_cv_have_va_copy, [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +va_list x,y; + ]], [[ va_copy(x,y); ]])], + [ ac_cv_have_va_copy="yes" ], + [ ac_cv_have_va_copy="no" + ]) +]) +if test "x$ac_cv_have_va_copy" = "xyes" ; then + AC_DEFINE([HAVE_VA_COPY], [1], [Define if va_copy exists]) +fi + +AC_CACHE_CHECK([whether __va_copy exists], ac_cv_have___va_copy, [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +va_list x,y; + ]], [[ __va_copy(x,y); ]])], + [ ac_cv_have___va_copy="yes" ], [ ac_cv_have___va_copy="no" + ]) +]) +if test "x$ac_cv_have___va_copy" = "xyes" ; then + AC_DEFINE([HAVE___VA_COPY], [1], [Define if __va_copy exists]) +fi + +AC_CACHE_CHECK([whether getopt has optreset support], + ac_cv_have_getopt_optreset, [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include ]], + [[ extern int optreset; optreset = 0; ]])], + [ ac_cv_have_getopt_optreset="yes" ], + [ ac_cv_have_getopt_optreset="no" + ]) +]) +if test "x$ac_cv_have_getopt_optreset" = "xyes" ; then + AC_DEFINE([HAVE_GETOPT_OPTRESET], [1], + [Define if your getopt(3) defines and uses optreset]) +fi + +##chl part +AC_CHECK_MEMBERS([struct stat.st_flags], , , + [ #include + #include ] +) + +AC_CHECK_MEMBERS([struct stat.st_mtim], , , + [ #include + #include ] +) + +AC_CHECK_MEMBERS([struct stat.st_mtimespec], , , + [ #include + #include ] +) + +AC_CHECK_MEMBERS([struct sockaddr.sa_len], , , + [ #include + #include + #include ] +) + +AC_CHECK_MEMBERS([struct sockaddr_storage.ss_len], , , + [ #include + #include + #include ] +) + +AC_CHECK_MEMBERS([struct sockaddr_in.sin_len], , , + [ #include + #include + #include ] +) + +AC_CHECK_MEMBERS([struct sockaddr_in6.sin6_len], , , + [ #include + #include + #include ] +) +##chl part + + +# Looking for programs, paths and files + +PRIVSEP_PATH=/var/empty +AC_ARG_WITH([privsep-path], + [ --with-privsep-path=xxx Path for privilege separation chroot (default=/var/empty)], + [ + if test -n "$withval" && test "x$withval" != "xno" && \ + test "x${withval}" != "xyes"; then + PRIVSEP_PATH=$withval + fi + ] +) +AC_SUBST([PRIVSEP_PATH]) + +# Options from here on. Some of these are preset by platform above +AC_ARG_WITH([mantype], + [ --with-mantype=man|cat|doc Set man page type], + [ + case "$withval" in + man|cat|doc) + MANTYPE=$withval + ;; + *) + AC_MSG_ERROR([invalid man type: $withval]) + ;; + esac + ] +) +if test -z "$MANTYPE"; then + TestPath="/usr/bin${PATH_SEPARATOR}/usr/ucb" + AC_PATH_PROGS([NROFF], [nroff awf], [/bin/false], [$TestPath]) + if ${NROFF} -mdoc ${srcdir}/iked/iked.8 >/dev/null 2>&1; then + MANTYPE=doc + elif ${NROFF} -man ${srcdir}/iked/iked.8 >/dev/null 2>&1; then + MANTYPE=man + else + MANTYPE=cat + fi +fi +AC_SUBST([MANTYPE]) +if test "$MANTYPE" = "doc"; then + mansubdir=man; +else + mansubdir=$MANTYPE; +fi +AC_SUBST([mansubdir]) + +# Whether to enable BSD auth support +BSD_AUTH_MSG=no +AC_ARG_WITH([bsd-auth], + [ --with-bsd-auth Enable BSD auth support], + [ + if test "x$withval" != "xno" ; then + AC_DEFINE([BSD_AUTH], [1], + [Define if you have BSD auth support]) + BSD_AUTH_MSG=yes + fi + ] +) + +AC_ARG_WITH([privsep-user], + [ --with-privsep-user=user Specify non-privileged user for privilege separation], + [ + if test -n "$withval" && test "x$withval" != "xno" && \ + test "x${withval}" != "xyes"; then + IKED_USER=$withval + fi + ] +) +AC_DEFINE_UNQUOTED([IKED_USER], ["$IKED_USER"], + [non-privileged user for privilege separation]) +AC_SUBST([IKED_USER]) + +_sysconfdir=`eval echo ${sysconfdir}` +case $_sysconfdir in +NONE/*) + _sysconfdir=`echo $_sysconfdir | sed "s~NONE~$ac_default_prefix~"` ;; +esac + +ikedconf=`eval echo ${_sysconfdir}/iked.conf` +AC_DEFINE_UNQUOTED([IKED_CONFIG], ["$ikedconf"], + [configuration file path]) +AC_SUBST([IKED_CONFIG]) + +ikedca=`eval echo ${_sysconfdir}/iked/` +AC_DEFINE_UNQUOTED([IKED_CA], ["$ikedca"], + [certificate path]) +AC_SUBST([IKED_CA]) + +# Where to place iked.sock +sockdir=/var/run +# make sure the directory exists +if test ! -d $sockdir ; then + sockdir=`eval echo ${_sysconfdir}` +fi + +AC_ARG_WITH([sock-dir], + [ --with-sock-dir=PATH Specify location of iked.sock file], + [ + if test -n "$withval" && test "x$withval" != "xno" && \ + test "x${withval}" != "xyes"; then + sockdir=$withval + if test ! -d $sockdir ; then + AC_MSG_WARN([** no $sockdir directory on this system **]) + fi + fi + ] +) + +AC_DEFINE_UNQUOTED([IKED_SOCKDIR], ["$sockdir"], + [Specify location of iked.sock]) +AC_SUBST([sockdir]) + +if test "x$ac_cv_func_getaddrinfo" != "xyes" ; then + TEST_SSH_IPV6=no +else + TEST_SSH_IPV6=yes +fi +AC_CHECK_DECL([BROKEN_GETADDRINFO], [TEST_SSH_IPV6=no]) +AC_SUBST([TEST_SSH_IPV6], [$TEST_SSH_IPV6]) + +AC_EXEEXT + +AC_MSG_CHECKING([if inet_net_pton will link]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#include +#include +#include + ]], [[ + inet_net_pton (0, 0, 0, 0, 0); + ]])], + AC_MSG_RESULT([yes]), + [AC_MSG_RESULT([no]) + saved_LIBS="$LIBS" + LIBS="$LIBS -lresolv" + AC_MSG_CHECKING([for inet_net_pton in -lresolv]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#include +#include +#include + ]], [[ + inet_net_pton (0, 0, 0, 0, 0); + ]])], + [AC_MSG_RESULT([yes])], + [LIBS="$saved_LIBS" + AC_MSG_RESULT([no])]) + ]) + + +# Search for OpenSSL +saved_CPPFLAGS="$CPPFLAGS" +saved_LDFLAGS="$LDFLAGS" +AC_ARG_WITH([ssl-dir], + [ --with-ssl-dir=PATH Specify path to OpenSSL installation ], + [ + if test "x$withval" != "xno" ; then + case "$withval" in + # Relative paths + ./*|../*) withval="`pwd`/$withval" + esac + if test -d "$withval/lib"; then + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}" + else + LDFLAGS="-L${withval}/lib ${LDFLAGS}" + fi + elif test -d "$withval/lib64"; then + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval}/lib64 -R${withval}/lib64 ${LDFLAGS}" + else + LDFLAGS="-L${withval}/lib64 ${LDFLAGS}" + fi + else + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}" + else + LDFLAGS="-L${withval} ${LDFLAGS}" + fi + fi + if test -d "$withval/include"; then + CPPFLAGS="-I${withval}/include ${CPPFLAGS}" + else + CPPFLAGS="-I${withval} ${CPPFLAGS}" + fi + fi + ] +) +LIBS="-lcrypto -lssl $LIBS" +AC_TRY_LINK_FUNC([RAND_add], [AC_DEFINE([HAVE_OPENSSL], [1], + [Define if your ssl headers are included + with #include ])], + [ + dnl Check default openssl install dir + if test -n "${need_dash_r}"; then + LDFLAGS="-L/usr/local/ssl/lib -R/usr/local/ssl/lib ${saved_LDFLAGS}" + else + LDFLAGS="-L/usr/local/ssl/lib ${saved_LDFLAGS}" + fi + CPPFLAGS="-I/usr/local/ssl/include ${saved_CPPFLAGS}" + AC_CHECK_HEADER([openssl/opensslv.h], , + [AC_MSG_ERROR([*** OpenSSL headers missing - please install first or check config.log ***])]) + AC_TRY_LINK_FUNC([RAND_add], [AC_DEFINE([HAVE_OPENSSL])], + [ + AC_MSG_ERROR([*** Can't find recent OpenSSL libcrypto (see config.log for details) ***]) + ] + ) + ] +) + +# Determine OpenSSL header version +AC_MSG_CHECKING([OpenSSL header version]) +AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ +#include +#include +#include +#define DATA "conftest.sslincver" + ]], [[ + FILE *fd; + int rc; + + fd = fopen(DATA,"w"); + if(fd == NULL) + exit(1); + + if ((rc = fprintf(fd ,"%x (%s)\n", OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT)) <0) + exit(1); + + exit(0); + ]])], + [ + ssl_header_ver=`cat conftest.sslincver` + AC_MSG_RESULT([$ssl_header_ver]) + ], + [ + AC_MSG_RESULT([not found]) + AC_MSG_ERROR([OpenSSL version header not found.]) + ], + [ + AC_MSG_WARN([cross compiling: not checking]) + ] +) + +# Determine OpenSSL library version +AC_MSG_CHECKING([OpenSSL library version]) +AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ +#include +#include +#include +#include +#define DATA "conftest.ssllibver" + ]], [[ + FILE *fd; + int rc; + + fd = fopen(DATA,"w"); + if(fd == NULL) + exit(1); + + if ((rc = fprintf(fd ,"%x (%s)\n", SSLeay(), SSLeay_version(SSLEAY_VERSION))) <0) + exit(1); + + exit(0); + ]])], + [ + ssl_library_ver=`cat conftest.ssllibver` + AC_MSG_RESULT([$ssl_library_ver]) + ], + [ + AC_MSG_RESULT([not found]) + AC_MSG_ERROR([OpenSSL library not found.]) + ], + [ + AC_MSG_WARN([cross compiling: not checking]) + ] +) + +AC_ARG_WITH([openssl-header-check], + [ --without-openssl-header-check Disable OpenSSL version consistency check], + [ if test "x$withval" = "xno" ; then + openssl_check_nonfatal=1 + fi + ] +) + +# Sanity check OpenSSL headers +AC_MSG_CHECKING([whether OpenSSL's headers match the library]) +AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ +#include +#include + ]], [[ + exit(SSLeay() == OPENSSL_VERSION_NUMBER ? 0 : 1); + ]])], + [ + AC_MSG_RESULT([yes]) + ], + [ + AC_MSG_RESULT([no]) + if test "x$openssl_check_nonfatal" = "x"; then + AC_MSG_ERROR([Your OpenSSL headers do not match your +library. Check config.log for details. +If you are sure your installation is consistent, you can disable the check +by running "./configure --without-openssl-header-check". +Also see contrib/findssl.sh for help identifying header/library mismatches. +]) + else + AC_MSG_WARN([Your OpenSSL headers do not match your +library. Check config.log for details. +Also see contrib/findssl.sh for help identifying header/library mismatches.]) + fi + ], + [ + AC_MSG_WARN([cross compiling: not checking]) + ] +) + +AC_MSG_CHECKING([if programs using OpenSSL functions will link]) +AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ #include ]], + [[ SSLeay_add_all_algorithms(); ]])], + [ + AC_MSG_RESULT([yes]) + ], + [ + AC_MSG_RESULT([no]) + saved_LIBS="$LIBS" + LIBS="$LIBS -ldl" + AC_MSG_CHECKING([if programs using OpenSSL need -ldl]) + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ #include ]], + [[ SSLeay_add_all_algorithms(); ]])], + [ + AC_MSG_RESULT([yes]) + ], + [ + AC_MSG_RESULT([no]) + LIBS="$saved_LIBS" + ] + ) + ] +) + +# Some systems want crypt() from libcrypt, *not* the version in OpenSSL, +# because the system crypt() is more featureful. +if test "x$check_for_libcrypt_before" = "x1"; then + AC_CHECK_LIB([crypt], [crypt]) +fi + +# Some Linux systems (Slackware) need crypt() from libcrypt, *not* the +# version in OpenSSL. +if test "x$check_for_libcrypt_later" = "x1"; then + AC_CHECK_LIB([crypt], [crypt], [LIBS="$LIBS -lcrypt"]) +fi + +# Determine OpenSSL configuration directory +SSLDIR=${_sysconfdir}/ssl +AC_MSG_CHECKING([OpenSSL configuration directory]) +AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ +#include +#include +#define HEADER_CRYPTLIB_H +#include +#include +#define DATA "conftest.sslincdir" + ]], [[ + FILE *fp; + int rc; + + if ((fp = fopen(DATA,"w")) == NULL) + return(1); + + if ((rc = fprintf(fp, "%s\n", OPENSSLDIR)) <0) + return(1); + fclose(fp); + ]])], + [ + SSLDIR=`cat conftest.sslincdir` + ], + [], []) +AC_MSG_RESULT([$SSLDIR]) +AC_DEFINE_UNQUOTED([SSLDIR], ["$SSLDIR"], [OpenSSL Configuration Directory]) +AC_SUBST([SSLDIR]) + +### Configure cryptographic random number support + +# Check wheter OpenSSL seeds itself +AC_MSG_CHECKING([whether OpenSSL's PRNG is internally seeded]) +AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ +#include +#include + ]], [[ + exit(RAND_status() == 1 ? 0 : 1); + ]])], + [ + OPENSSL_SEEDS_ITSELF=yes + AC_MSG_RESULT([yes]) + ], + [ + AC_MSG_RESULT([no]) + ], + [ + AC_MSG_WARN([cross compiling: assuming yes]) + # This is safe, since we will fatal() at runtime if + # OpenSSL is not seeded correctly. + OPENSSL_SEEDS_ITSELF=yes + ] +) + +# PRNGD TCP socket +AC_ARG_WITH([prngd-port], + [ --with-prngd-port=PORT read entropy from PRNGD/EGD TCP localhost:PORT], + [ + case "$withval" in + no) + withval="" + ;; + [[0-9]]*) + ;; + *) + AC_MSG_ERROR([You must specify a numeric port number for --with-prngd-port]) + ;; + esac + if test ! -z "$withval" ; then + PRNGD_PORT="$withval" + AC_DEFINE_UNQUOTED([PRNGD_PORT], [$PRNGD_PORT], + [Port number of PRNGD/EGD random number socket]) + fi + ] +) + +# PRNGD Unix domain socket +AC_ARG_WITH([prngd-socket], + [ --with-prngd-socket=FILE read entropy from PRNGD/EGD socket FILE (default=/var/run/egd-pool)], + [ + case "$withval" in + yes) + withval="/var/run/egd-pool" + ;; + no) + withval="" + ;; + /*) + ;; + *) + AC_MSG_ERROR([You must specify an absolute path to the entropy socket]) + ;; + esac + + if test ! -z "$withval" ; then + if test ! -z "$PRNGD_PORT" ; then + AC_MSG_ERROR([You may not specify both a PRNGD/EGD port and socket]) + fi + if test ! -r "$withval" ; then + AC_MSG_WARN([Entropy socket is not readable]) + fi + PRNGD_SOCKET="$withval" + AC_DEFINE_UNQUOTED([PRNGD_SOCKET], ["$PRNGD_SOCKET"], + [Location of PRNGD/EGD random number socket]) + fi + ], + [ + # Check for existing socket only if we don't have a random device already + if test "x$OPENSSL_SEEDS_ITSELF" != "xyes" ; then + AC_MSG_CHECKING([for PRNGD/EGD socket]) + # Insert other locations here + for sock in /var/run/egd-pool /dev/egd-pool /etc/entropy; do + if test -r $sock && $TEST_MINUS_S_SH -c "test -S $sock -o -p $sock" ; then + PRNGD_SOCKET="$sock" + AC_DEFINE_UNQUOTED([PRNGD_SOCKET], ["$PRNGD_SOCKET"]) + break; + fi + done + if test ! -z "$PRNGD_SOCKET" ; then + AC_MSG_RESULT([$PRNGD_SOCKET]) + else + AC_MSG_RESULT([not found]) + fi + fi + ] +) + +# Which randomness source do we use? +if test ! -z "$PRNGD_PORT" ; then + RAND_MSG="PRNGd port $PRNGD_PORT" +elif test ! -z "$PRNGD_SOCKET" ; then + RAND_MSG="PRNGd socket $PRNGD_SOCKET" +elif test ! -z "$OPENSSL_SEEDS_ITSELF" ; then + AC_DEFINE([OPENSSL_PRNG_ONLY], [1], + [Define if you want OpenSSL's internally seeded PRNG only]) + RAND_MSG="OpenSSL internal ONLY" +else + AC_MSG_ERROR([OpenSSH has no source of random numbers. Please configure OpenSSL with an entropy source or re-run configure using one of the --with-prngd-port or --with-prngd-socket options]) +fi + +# Search for libevent +saved_CPPFLAGS="$CPPFLAGS" +saved_LDFLAGS="$LDFLAGS" +AC_ARG_WITH([libevent-dir], + [ --with-libevent-dir=PATH Specify path to libevent installation ], + [ + if test "x$withval" != "xno" ; then + case "$withval" in + ./*|../*) + # Relative paths + withval="`pwd`/$withval" + ;; + */libevent1|*/libevent1/|*/libevent|*/libevent/) + AC_MSG_CHECKING([libevent header path]) + evincludes=`echo $withval | sed s/lib/include/` + if test -d "$evincludes"; then + CPPFLAGS="-I${evincludes} ${CPPFLAGS}" + AC_MSG_RESULT([${evincludes}]) + else + AC_MSG_RESULT([not found]) + fi + ;; + esac + if test -d "$withval/lib"; then + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}" + else + LDFLAGS="-L${withval}/lib ${LDFLAGS}" + fi + elif test -d "$withval/lib64"; then + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval}/lib64 -R${withval}/lib64 ${LDFLAGS}" + else + LDFLAGS="-L${withval}/lib64 ${LDFLAGS}" + fi + else + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}" + else + LDFLAGS="-L${withval} ${LDFLAGS}" + fi + fi + if test -d "$withval/include"; then + CPPFLAGS="-I${withval}/include ${CPPFLAGS}" + else + CPPFLAGS="-I${withval} ${CPPFLAGS}" + fi + fi + ] +) + +LIBS="-levent $LIBS" + +# Determine libevent header version +AC_MSG_CHECKING([libevent header version]) +AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ +#include +#include +#include +#include +#define DATA "conftest.libeventincver" + ]], [[ + FILE *fd; + int rc; + + fd = fopen(DATA,"w"); + if(fd == NULL) + return(1); + + if ((rc = fprintf(fd ,"%s\n", _EVENT_VERSION)) <0) + return(1); + + return(0); + ]])], + [ + libevent_header_ver=`cat conftest.libeventincver` + AC_MSG_RESULT([$libevent_header_ver]) + ], + [ + AC_MSG_RESULT([not found]) + AC_MSG_ERROR([libevent version header not found. ${CPPFLAGS}]) + ], + [ + AC_MSG_WARN([cross compiling: not checking]) + ] +) + +# Determine libevent library version +AC_MSG_CHECKING([libevent library version]) +AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ +#include +#include +#include +#define DATA "conftest.libeventlibver" + ]], [[ + FILE *fd; + int rc; + + fd = fopen(DATA,"w"); + if(fd == NULL) + return(1); + + if ((rc = fprintf(fd ,"%s\n", event_get_version())) <0) + return(1); + + return(0); + ]])], + [ + libevent_library_ver=`cat conftest.libeventlibver` + AC_MSG_RESULT([$libevent_library_ver]) + ], + [ + AC_MSG_RESULT([not found]) + AC_MSG_ERROR([libevent library not found.]) + ], + [ + AC_MSG_WARN([cross compiling: not checking]) + ] +) + +libevent_major_version=`cat conftest.libeventlibver|head -c1 || echo 1` + +AC_DEFINE_UNQUOTED([LIBEVENT_MAJOR_VERSION], [$libevent_major_version], [Define libevent major version]) + +AC_ARG_WITH([libevent-header-check], + [ --without-libevent-header-check Disable libevent version consistency check], + [ if test "x$withval" = "xno" ; then + libevent_check_nonfatal=1 + fi + ] +) + +# Sanity check libevent headers +AC_MSG_CHECKING([whether libevent's headers match the library]) +AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ +#if LIBEVENT_MAJOR_VERSION < 2 +#include +#else +#include +#endif +#include +#include + ]], [[ + exit(strcmp(event_get_version(), _EVENT_VERSION) == 0 ? 0 : 1); + ]])], + [ + AC_MSG_RESULT([yes]) + ], + [ + AC_MSG_RESULT([no]) + if test "x$libevent_check_nonfatal" = "x"; then + AC_MSG_ERROR([Your libevent headers do not match your +library. Check config.log for details. +If you are sure your installation is consistent, you can disable the check +by running "./configure --without-libevent-header-check".]) + else + AC_MSG_WARN([Your libevent headers do not match your +library. Check config.log for details.]) + fi + ], + [ + AC_MSG_WARN([cross compiling: not checking]) + ] +) + +AC_MSG_CHECKING([if programs using libevent functions will link]) +AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ +#if LIBEVENT_MAJOR_VERSION < 2 +#include +#else +#include +#endif + ]], [[ + event_base_new(); + ]])], + [ + AC_MSG_RESULT([yes]) + ], + [ + AC_MSG_RESULT([no]) + ] +) + +#AC_SEARCH_LIBS([bufferevent_openssl_socket_new], [event event_openssl], []) + +AC_CHECK_HEADER([$pfkeyv2_h], [ + AC_MSG_CHECKING([for extended PFKEv2 crypto algorithms]) + AC_RUN_IFELSE([AC_LANG_PROGRAM([[ + #include + #include + #include <$pfkeyv2_h> + #include + #define DATA "conftest.pfkeyv2alg" + ]], [[ + FILE *fp; + int i; + struct pfkeyalgs { + const char *name; + const char *openbsd; + const char *target; + } algs[] = { + { "blowfish", "SADB_X_EALG_BLF", +#if defined(SADB_X_EALG_BLF) + "SADB_X_EALG_BLF" +#elif defined(SADB_X_EALG_BLOWFISHCBC) + "SADB_X_EALG_BLOWFISHCBC" +#else + NULL +#endif + }, + { "aes", "SADB_X_EALG_AES", +#if defined(SADB_X_EALG_AES) + "SADB_X_EALG_AES" +#elif defined(SADB_X_EALG_AESCBC) + "SADB_X_EALG_AESCBC" +#elif defined(SADB_X_EALG_RIJNDAEL) + "SADB_X_EALG_RIJNDAELCBC" +#else + NULL +#endif + }, + { "cast", "SADB_X_EALG_CAST", +#if defined(SADB_X_EALG_CAST) + "SADB_X_EALG_CAST" +#elif defined(SADB_X_EALG_CAST128CBC) + "SADB_X_EALG_CAST128CBC" +#else + NULL +#endif + }, + { "aes-gcm16", "SADB_X_EALG_AESGCM16", +#if defined(SADB_X_EALG_AESGCM16) + "SADB_X_EALG_AESGCM16" +#elif defined(SADB_X_EALG_AES_GCM_ICV16) + "SADB_X_EALG_AES_GCM_ICV16" +#else + NULL +#endif + }, + { "sha2-256", "SADB_X_AALG_SHA2_256", +#if defined(SADB_X_AALG_SHA2_256) + "SADB_X_AALG_SHA2_256", +#elif defined(SADB_X_AALG_SHA2_256HMAC) + "SADB_X_AALG_SHA2_256HMAC" +#else + NULL +#endif + }, + { "sha2-384", "SADB_X_AALG_SHA2_384", +#if defined(SADB_X_AALG_SHA2_384) + "SADB_X_AALG_SHA2_384", +#elif defined(SADB_X_AALG_SHA2_384HMAC) + "SADB_X_AALG_SHA2_384HMAC" +#else + NULL +#endif + }, + { "sha2-512", "SADB_X_AALG_SHA2_512", +#if defined(SADB_X_AALG_SHA2_512) + "SADB_X_AALG_SHA2_512", +#elif defined(SADB_X_AALG_SHA2_512HMAC) + "SADB_X_AALG_SHA2_512HMAC" +#else + NULL +#endif + }, + { NULL } + }; + + if ((fp = fopen(DATA, "w")) == NULL) + return(1); + + for (i = 0; algs[i].name != NULL; i++) { + if (algs[i].target == NULL) + continue; + (void)fprintf(fp, "%s\t%s\t%s\n", + algs[i].name, + algs[i].openbsd, + algs[i].target); + } + + fclose(fp); + ]])], + [ + pfkeyv2_algs=`$AWK '{ print $1 }' conftest.pfkeyv2alg` + p_values="" + p_flags="" + + for i in $pfkeyv2_algs; do + p_alg=`$GREP $i conftest.pfkeyv2alg` + p_name=`echo $p_alg | $AWK '{print $1}'` + p_openbsd=`echo $p_alg | $AWK '{print $2}'` + p_target=`echo $p_alg | $AWK '{print $3}'` + p_values="$p_values $p_name" + if test "x$p_openbsd" != "x$p_target"; then + # XXX AC_DEFINE_UNQUOTED will not work here + p_flags="$p_flags -D$p_openbsd=$p_target" + fi + done + + PFKEY_CPPFLAGS=`eval echo $p_flags` + AC_SUBST([PFKEY_CPPFLAGS]) + + AC_MSG_RESULT([$p_values]) + ], + [ + AC_MSG_RESULT([failed]) + AC_MSG_ERROR([PFKEv2 compilation failed.]) + ], []) +], [], [ +#include +#include +]) + +if test "x$OPENSSL" != "x"; then + AC_DEFINE_UNQUOTED([PATH_OPENSSL], ["$OPENSSL"], + [Path to OpenSSL binary]) +fi + +if test "x$TAR" != "x"; then + AC_DEFINE_UNQUOTED([PATH_TAR], ["$TAR"], [Path to TAR binary]) +fi +if test "x$ZIP" != "x"; then + AC_DEFINE_UNQUOTED([PATH_ZIP], ["$ZIP"], [Path to ZIP binary]) +fi + +AC_DEFINE_UNQUOTED([PREFIX], ["$prefix"], [Root directory prefix]) + +AC_DEFINE([_GNU_SOURCE], [1], [Enable GNU Extensions]) + +dnl Adding -Werror to CFLAGS early prevents configure tests from running. +dnl Add now. +CFLAGS="$CFLAGS $werror_flags $debug_flags" + +LIBS="$LIBS ${IKEDLIBS}" + +AC_CONFIG_FILES([Makefile + openbsd-compat/Makefile + iked/Makefile + ikectl/Makefile + ]) + +AC_OUTPUT + +# Print summary of options + +# Someone please show me a better way :) +A=`eval echo ${prefix}` ; A=`eval echo ${A}` +B=`eval echo ${bindir}` ; B=`eval echo ${B}` +C=`eval echo ${sbindir}` ; C=`eval echo ${C}` +D=`eval echo ${sysconfdir}` ; D=`eval echo ${D}` +F=`eval echo ${mandir}/${mansubdir}X` ; F=`eval echo ${F}` +G=`eval echo ${sockdir}` ; G=`eval echo ${G}` +H=`eval echo ${PRIVSEP_PATH}` ; H=`eval echo ${H}` +I=`eval echo ${ikedconf}` ; I=`eval echo ${I}` +J=`eval echo ${ikedca}` ; J=`eval echo ${J}` + +echo "" +echo "OpenIKED has been configured with the following options:" +echo " User binaries: $B" +echo " System binaries: $C" +echo " Configuration files: $D" +echo " Configuration files: $D" +echo " Manual pages: $F" +echo " iked.sock dir: $G" +echo " Privilege separation chroot path: $H" +echo " OpenIKED configuration file: $I" +echo " OpenIKED CA and keys directory: $J" +echo " Manpage format: $MANTYPE" +#echo " PAM support: $PAM_MSG" +#echo " OSF SIA support: $SIA_MSG" +#echo " KerberosV support: $KRB5_MSG" +#echo " SELinux support: $SELINUX_MSG" +#echo " Smartcard support: $SCARD_MSG" +#echo " S/KEY support: $SKEY_MSG" +#echo " TCP Wrappers support: $TCPW_MSG" +#echo " MD5 password support: $MD5_MSG" +#echo " libedit support: $LIBEDIT_MSG" +#echo " Solaris process contract support: $SPC_MSG" +#echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG" +#echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" +echo " BSD Auth support: $BSD_AUTH_MSG" +echo " Random number source: $RAND_MSG" + +echo "" + +echo " Host: ${host}" +echo " Compiler: ${CC}" +echo " Compiler flags: ${CFLAGS}" +echo "Preprocessor flags: ${CPPFLAGS}" +echo " Linker flags: ${LDFLAGS}" +echo " Libraries: ${LIBS}" +echo "" + +if test "x$MAKE_PACKAGE_SUPPORTED" = "xyes" ; then + echo "SVR4 style packages are supported with \"make package\"" + echo "" +fi + +if test "x$PAM_MSG" = "xyes" ; then + echo "PAM is enabled. You may need to install a PAM control file " + echo "for sshd, otherwise password authentication may fail. " + echo "Example PAM control files can be found in the contrib/ " + echo "subdirectory" + echo "" +fi + +if test ! -z "$NO_PEERCHECK" ; then + echo "WARNING: the operating system that you are using does not" + echo "appear to support getpeereid(), getpeerucred() or the" + echo "SO_PEERCRED getsockopt() option. These facilities are used to" + echo "enforce security checks to prevent unauthorised connections to" + echo "ssh-agent. Their absence increases the risk that a malicious" + echo "user can connect to your agent." + echo "" +fi + +if test "$AUDIT_MODULE" = "bsm" ; then + echo "WARNING: BSM audit support is currently considered EXPERIMENTAL." + echo "See the Solaris section in README.platform for details." +fi diff --git a/ikectl/.cvsignore b/ikectl/.cvsignore new file mode 100644 index 0000000..536efe1 --- /dev/null +++ b/ikectl/.cvsignore @@ -0,0 +1,5 @@ +.cvsignore +.deps +Makefile +Makefile.am +Makefile.in diff --git a/ikectl/CVS/Entries b/ikectl/CVS/Entries index 20653f9..76336d8 100644 --- a/ikectl/CVS/Entries +++ b/ikectl/CVS/Entries @@ -1,8 +1,8 @@ -/Makefile/1.4/Thu Oct 8 08:38:35 2015// -/ikeca.c/1.37/Thu Oct 8 08:38:35 2015// -/ikeca.cnf/1.6/Thu Oct 8 08:38:35 2015// -/ikectl.8/1.24/Thu Oct 8 08:38:35 2015// -/ikectl.c/1.20/Thu Oct 8 08:38:35 2015// -/parser.c/1.14/Thu Oct 8 08:38:35 2015// -/parser.h/1.13/Thu Oct 8 08:38:35 2015// +/Makefile/1.2/Result of merge+Fri Jan 11 08:23:23 2013// +/ikeca.c/1.25/Result of merge// +/ikectl.c/1.16/Result of merge// +/parser.c/1.12/Result of merge// +/ikeca.cnf/1.5/Sat Dec 15 14:53:03 2012// +/ikectl.8/1.20/Mon Jan 14 14:11:49 2013// +/parser.h/1.12/Mon Jan 14 14:11:49 2013// D diff --git a/ikectl/Makefile b/ikectl/Makefile deleted file mode 100644 index eab9819..0000000 --- a/ikectl/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -# $OpenBSD: Makefile,v 1.4 2015/08/19 12:25:59 reyk Exp $ - -.PATH: ${.CURDIR}/../iked - -PROG= ikectl -SRCS= log.c ikeca.c ikectl.c parser.c util.c - -MAN= ikectl.8 - -LDADD= -lutil -lcrypto -DPADD= ${LIBUTIL} -CFLAGS+= -Wall -I${.CURDIR} -I${.CURDIR}/../iked -CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes -CFLAGS+= -Wmissing-declarations -CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual -CFLAGS+= -Wsign-compare - -#distribution: -# ${INSTALL} -C -g wheel -m 0644 ${.CURDIR}/ikeca.cnf \ -# ${DESTDIR}/etc/ssl/ikeca.cnf - -.include diff --git a/ikectl/Makefile.am b/ikectl/Makefile.am new file mode 100644 index 0000000..4f44e8b --- /dev/null +++ b/ikectl/Makefile.am @@ -0,0 +1,45 @@ +sbin_PROGRAMS= ikectl + +ikectl_SOURCES= ikeca.c ikectl.c parser.c $(top_srcdir)/iked/log.c +ikectl_CFLAGS= + +LIBCOMPAT= $(top_builddir)/openbsd-compat/libopenbsd-compat.a +LDADD= $(LIBCOMPAT) +CPPFLAGS= -include $(top_srcdir)/openbsd-compat/includes.h \ + -I$(top_srcdir)/openbsd-compat \ + -I$(top_srcdir)/iked \ + -I$(srcdir) @CPPFLAGS@ @DEFS@ +MANPAGES= ikectl.8.out +MANPAGES_IN= ikectl.8 +EXTRA_DIST= $(MANPAGES_IN) ikeca.cnf +CLEANFILES= $(CONFIGFILES) $(MANPAGES) +PATHSUBS= -e 's|/etc/iked/|$(sysconfdir)/iked/|g' \ + -e 's|/usr/libexec|$(libexecdir)|g' \ + -e 's|/var/run/iked.sock|$(sockdir)/iked.sock|g' +FIXPATHSCMD= $(SED) $(PATHSUBS) + +$(MANPAGES): $(MANPAGES_IN) + if test "$(MANTYPE)" = "cat"; then \ + manpage=$(srcdir)/`echo $@ | sed 's/\.[1-9]\.out$$/\.0/'`; \ + else \ + manpage=$(srcdir)/`echo $@ | sed 's/\.out$$//'`; \ + fi; \ + if test "$(MANTYPE)" = "man"; then \ + $(FIXPATHSCMD) $${manpage} | $(AWK) -f $(top_srcdir)/mdoc2man.awk > $@; \ + else \ + $(FIXPATHSCMD) $${manpage} > $@; \ + fi + +install-exec-hook: $(MANPAGES) + $(MKDIR_P) $(DESTDIR)$(sysconfdir)/iked/ + $(MKDIR_P) $(DESTDIR)$(SSLDIR) + $(MKDIR_P) $(DESTDIR)$(sbindir) + $(MKDIR_P) $(DESTDIR)$(mandir)/$(mansubdir)8 + + @if [ ! -f $(DESTDIR)$(SSLDIR)/ikeca.cnf ]; then \ + $(INSTALL) -m 644 ikeca.cnf $(DESTDIR)$(SSLDIR)/ikeca.cnf; \ + else \ + echo "$(DESTDIR)$(SSLDIR)/ikeca.cnf already exists, install will not overwrite"; \ + fi + + $(INSTALL) -m 644 ikectl.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ikectl.8 diff --git a/ikectl/ikeca.c b/ikectl/ikeca.c index 8ecfd3e..4b84090 100644 --- a/ikectl/ikeca.c +++ b/ikectl/ikeca.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikeca.c,v 1.37 2015/08/19 21:07:23 reyk Exp $ */ +/* $OpenBSD: ikeca.c,v 1.25 2013/01/08 10:38:19 reyk Exp $ */ /* * Copyright (c) 2010 Jonathan Gray @@ -16,6 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include #include @@ -28,7 +29,6 @@ #include #include #include -#include #include #include @@ -52,7 +52,7 @@ #endif #ifndef PATH_OPENSSL -#define PATH_OPENSSL "/usr/bin/openssl" +#define PATH_OPENSSL "/usr/sbin/openssl" #endif #ifndef PATH_ZIP #define PATH_ZIP "/usr/local/bin/zip" @@ -82,39 +82,13 @@ struct { { "/private", 0700 } }; -/* explicitly list allowed variables */ -const char *ca_env[][2] = { - { "$ENV::CADB", NULL }, - { "$ENV::CERTFQDN", NULL }, - { "$ENV::CERTIP", NULL }, - { "$ENV::CERTPATHLEN", NULL }, - { "$ENV::CERTUSAGE", NULL }, - { "$ENV::CERT_C", NULL }, - { "$ENV::CERT_CN", NULL }, - { "$ENV::CERT_EMAIL", NULL }, - { "$ENV::CERT_L", NULL }, - { "$ENV::CERT_O", NULL }, - { "$ENV::CERT_OU", NULL }, - { "$ENV::CERT_ST", NULL }, - { "$ENV::EXTCERTUSAGE", NULL }, - { "$ENV::NSCERTTYPE", NULL }, - { NULL } -}; - -int ca_sign(struct ca *, char *, int); +int ca_sign(struct ca *, char *, int, char *); int ca_request(struct ca *, char *); -void ca_newpass(char *, char *); -char *ca_readpass(char *, size_t *); +int ca_newpass(char *, char *); +char * ca_readpass(char *, size_t *); int fcopy(char *, char *, mode_t); -void fcopy_env(const char *, const char *, mode_t); int rm_dir(char *); -void ca_hier(char *); -void ca_setenv(const char *, const char *); -void ca_clrenv(void); -void ca_setcnf(struct ca *, const char *); - -/* util.c */ -int expand_string(char *, size_t, const char *, const char *); +int ca_hier(char *); int ca_delete(struct ca *ca) @@ -199,13 +173,10 @@ ca_request(struct ca *ca, char *keyname) char cmd[PATH_MAX * 2]; char path[PATH_MAX]; - ca_setenv("$ENV::CERT_CN", keyname); - ca_setcnf(ca, keyname); - snprintf(path, sizeof(path), "%s/private/%s.csr", ca->sslpath, keyname); - snprintf(cmd, sizeof(cmd), "%s req %s-new" + snprintf(cmd, sizeof(cmd), "env CERT_CN=%s %s req %s-new" " -key %s/private/%s.key -out %s -config %s", - PATH_OPENSSL, ca->batch, ca->sslpath, keyname, + keyname, PATH_OPENSSL, ca->batch, ca->sslpath, keyname, path, ca->sslcnf); system(cmd); @@ -215,40 +186,40 @@ ca_request(struct ca *ca, char *keyname) } int -ca_sign(struct ca *ca, char *keyname, int type) +ca_sign(struct ca *ca, char *keyname, int type, char *envargs) { char cmd[PATH_MAX * 2]; - char hostname[HOST_NAME_MAX+1]; + char hostname[MAXHOSTNAMELEN]; char name[128]; - const char *extensions = NULL; strlcpy(name, keyname, sizeof(name)); + if (envargs == NULL) + envargs = ""; + if (type == HOST_IPADDR) { - ca_setenv("$ENV::CERTIP", name); - extensions = "x509v3_IPAddr"; + snprintf(cmd, sizeof(cmd), "env CERTIP=%s%s %s x509 -req" + " -days 365 -in %s/private/%s.csr" + " -CA %s/ca.crt -CAkey %s/private/ca.key -CAcreateserial" + " -extfile %s -extensions x509v3_IPAddr -out %s/%s.crt" + " -passin file:%s", name, envargs, PATH_OPENSSL, + ca->sslpath, keyname, ca->sslpath, ca->sslpath, + ca->extcnf, ca->sslpath, keyname, ca->passfile); } else if (type == HOST_FQDN) { if (!strcmp(keyname, "local")) { if (gethostname(hostname, sizeof(hostname))) err(1, "gethostname"); strlcpy(name, hostname, sizeof(name)); } - ca_setenv("$ENV::CERTFQDN", name); - extensions = "x509v3_FQDN"; - } else { - errx(1, "unknown host type %d", type); - } - - ca_setcnf(ca, keyname); - - snprintf(cmd, sizeof(cmd), "%s x509 -req" - " -days 365 -in %s/private/%s.csr" - " -CA %s/ca.crt -CAkey %s/private/ca.key -CAcreateserial" - " -extfile %s -extensions %s -out %s/%s.crt" - " -passin file:%s", - PATH_OPENSSL, - ca->sslpath, keyname, ca->sslpath, ca->sslpath, - ca->extcnf, extensions, ca->sslpath, keyname, ca->passfile); + snprintf(cmd, sizeof(cmd), "env CERTFQDN=%s%s %s x509 -req" + " -days 365 -in %s/private/%s.csr" + " -CA %s/ca.crt -CAkey %s/private/ca.key -CAcreateserial" + " -extfile %s -extensions x509v3_FQDN -out %s/%s.crt" + " -passin file:%s", name, envargs, PATH_OPENSSL, + ca->sslpath, keyname, ca->sslpath, ca->sslpath, + ca->extcnf, ca->sslpath, keyname, ca->passfile); + } else + err(1, "unknown host type %d", type); system(cmd); @@ -258,20 +229,16 @@ ca_sign(struct ca *ca, char *keyname, int type) int ca_certificate(struct ca *ca, char *keyname, int type, int action) { - ca_clrenv(); + char *envargs = ""; switch (action) { case CA_SERVER: - ca_setenv("$ENV::EXTCERTUSAGE", "serverAuth"); - ca_setenv("$ENV::NSCERTTYPE", "server"); - ca_setenv("$ENV::CERTUSAGE", - "digitalSignature,keyEncipherment"); + envargs = " EXTCERTUSAGE=serverAuth NSCERTTYPE=server" + " CERTUSAGE=digitalSignature,keyEncipherment"; break; case CA_CLIENT: - ca_setenv("$ENV::EXTCERTUSAGE", "clientAuth"); - ca_setenv("$ENV::NSCERTTYPE", "client"); - ca_setenv("$ENV::CERTUSAGE", - "digitalSignature,keyAgreement"); + envargs = " EXTCERTUSAGE=clientAuth NSCERTTYPE=client" + " CERTUSAGE=digitalSignature,keyAgreement"; break; default: break; @@ -279,7 +246,7 @@ ca_certificate(struct ca *ca, char *keyname, int type, int action) ca_key_create(ca, keyname); ca_request(ca, keyname); - ca_sign(ca, keyname, type); + ca_sign(ca, keyname, type, envargs); return (0); } @@ -346,7 +313,7 @@ ca_cert_install(struct ca *ca, char *keyname, char *dir) return (0); } -void +int ca_newpass(char *passfile, char *password) { FILE *f; @@ -375,6 +342,8 @@ ca_newpass(char *passfile, char *password) fprintf(f, "%s\n%s\n", pass, pass); fclose(f); + + return (0); } int @@ -383,8 +352,6 @@ ca_create(struct ca *ca) char cmd[PATH_MAX * 2]; char path[PATH_MAX]; - ca_clrenv(); - snprintf(path, sizeof(path), "%s/private/ca.key", ca->sslpath); snprintf(cmd, sizeof(cmd), "%s genrsa -aes256 -out" " %s -passout file:%s 2048", PATH_OPENSSL, @@ -392,11 +359,8 @@ ca_create(struct ca *ca) system(cmd); chmod(path, 0600); - ca_setenv("$ENV::CERT_CN", "VPN CA"); - ca_setcnf(ca, "ca"); - snprintf(path, sizeof(path), "%s/private/ca.csr", ca->sslpath); - snprintf(cmd, sizeof(cmd), "%s req %s-new" + snprintf(cmd, sizeof(cmd), "env CERT_CN='VPN CA' %s req %s-new" " -key %s/private/ca.key" " -config %s -out %s -passin file:%s", PATH_OPENSSL, ca->batch, ca->sslpath, ca->sslcnf, path, ca->passfile); @@ -479,8 +443,8 @@ ca_show_certs(struct ca *ca, char *name) err(1, "could not open directory %s", ca->sslpath); while ((de = readdir(dir)) != NULL) { - if (de->d_namlen > 4) { - p = de->d_name + de->d_namlen - 4; + if (NAMLEN(de) > 4) { + p = de->d_name + NAMLEN(de) - 4; if (strcmp(".crt", p) != 0) continue; snprintf(path, sizeof(path), "%s/%s", ca->sslpath, @@ -502,16 +466,15 @@ int fcopy(char *src, char *dst, mode_t mode) { int ifd, ofd; - uint8_t buf[BUFSIZ]; + u_int8_t buf[BUFSIZ]; ssize_t r; if ((ifd = open(src, O_RDONLY)) == -1) err(1, "open %s", src); if ((ofd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) { - int saved_errno = errno; close(ifd); - errc(1, saved_errno, "open %s", dst); + err(1, "open %s", dst); } while ((r = read(ifd, buf, sizeof(buf))) > 0) { @@ -524,45 +487,6 @@ fcopy(char *src, char *dst, mode_t mode) return (r == -1); } -void -fcopy_env(const char *src, const char *dst, mode_t mode) -{ - int ofd = -1, i; - uint8_t buf[BUFSIZ]; - ssize_t r = -1, len; - FILE *ifp = NULL; - int saved_errno; - - if ((ifp = fopen(src, "r")) == NULL) - err(1, "fopen %s", src); - - if ((ofd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) - goto done; - - while (fgets(buf, sizeof(buf), ifp) != NULL) { - for (i = 0; ca_env[i][0] != NULL; i++) { - if (ca_env[i][1] == NULL) - continue; - if (expand_string(buf, sizeof(buf), - ca_env[i][0], ca_env[i][1]) == -1) - errx(1, "env %s value too long", ca_env[i][0]); - } - len = strlen(buf); - if (write(ofd, buf, len) != len) - goto done; - } - - r = 0; - - done: - saved_errno = errno; - close(ofd); - if (ifp != NULL) - fclose(ifp); - if (r == -1) - errc(1, saved_errno, "open %s", dst); -} - int rm_dir(char *path) { @@ -598,12 +522,13 @@ rm_dir(char *path) return (0); } -void + +int ca_hier(char *path) { struct stat st; char dst[PATH_MAX]; - unsigned int i; + u_int i; for (i = 0; i < nitems(hier); i++) { strlcpy(dst, path, sizeof(dst)); @@ -612,6 +537,8 @@ ca_hier(char *path) mkdir(dst, hier[i].mode) != 0) err(1, "failed to create dir %s", dst); } + + return (0); } int @@ -628,12 +555,12 @@ ca_export(struct ca *ca, char *keyname, char *myname, char *password) char dst[PATH_MAX]; char *p; char tpl[] = "/tmp/ikectl.XXXXXXXXXX"; - unsigned int i; + u_int i; int fd; if (keyname != NULL) { if (strlcpy(oname, keyname, sizeof(oname)) >= sizeof(oname)) - errx(1, "name too long"); + err(1, "name too long"); } else { strlcpy(oname, "ca", sizeof(oname)); } @@ -755,7 +682,7 @@ ca_export(struct ca *ca, char *keyname, char *myname, char *password) de->d_name); snprintf(dst, sizeof(dst), "%s/export/%s", p, de->d_name); - fcopy(src, dst, 0644); + fcopy(src, dst, 644); } closedir(dexp); } @@ -814,7 +741,6 @@ ca_revoke(struct ca *ca, char *keyname) struct stat st; char cmd[PATH_MAX * 2]; char path[PATH_MAX]; - char cadb[PATH_MAX]; int fd; char *pass; size_t len; @@ -831,7 +757,7 @@ ca_revoke(struct ca *ca, char *keyname) snprintf(path, sizeof(path), "%s/ikeca.passwd", ca->sslpath); pass = ca_readpass(path, &len); if (pass == NULL) - errx(1, "could not open passphrase file"); + err(1, "could not open passphrase file"); /* create index if it doesn't already exist */ snprintf(path, sizeof(path), "%s/index.txt", ca->sslpath); @@ -844,93 +770,43 @@ ca_revoke(struct ca *ca, char *keyname) err(1, "could not access %s", path); } - snprintf(cadb, sizeof(cadb), "%s/index.txt", ca->sslpath); - ca_setenv("$ENV::CADB", cadb); - ca_setcnf(ca, "ca-revoke"); - if (keyname) { - snprintf(cmd, sizeof(cmd), - "%s ca %s-config %s -keyfile %s/private/ca.key" + snprintf(cmd, sizeof(cmd), "env CADB='%s/index.txt' " + " %s ca %s-config %s -keyfile %s/private/ca.key" " -key %s" " -cert %s/ca.crt" " -md sha1" " -revoke %s/%s.crt", - PATH_OPENSSL, ca->batch, ca->sslcnf, + ca->sslpath, PATH_OPENSSL, ca->batch, ca->sslcnf, ca->sslpath, pass, ca->sslpath, ca->sslpath, keyname); system(cmd); } - snprintf(cmd, sizeof(cmd), - "%s ca %s-config %s -keyfile %s/private/ca.key" + snprintf(cmd, sizeof(cmd), "env CADB='%s/index.txt' " + " %s ca %s-config %s -keyfile %s/private/ca.key" " -key %s" " -gencrl" " -cert %s/ca.crt" " -md sha1" " -crldays 365" " -out %s/ca.crl", - PATH_OPENSSL, ca->batch, ca->sslcnf, ca->sslpath, + ca->sslpath, PATH_OPENSSL, ca->batch, ca->sslcnf, ca->sslpath, pass, ca->sslpath, ca->sslpath); system(cmd); - explicit_bzero(pass, len); + bzero(pass, len); free(pass); return (0); } -void -ca_clrenv(void) -{ - int i; - for (i = 0; ca_env[i][0] != NULL; i++) - ca_env[i][1] = NULL; -} - -void -ca_setenv(const char *key, const char *value) -{ - int i; - - for (i = 0; ca_env[i][0] != NULL; i++) { - if (strcmp(ca_env[i][0], key) == 0) { - if (ca_env[i][1] != NULL) - errx(1, "env %s already set: %s", key, value); - ca_env[i][1] = value; - return; - } - } - errx(1, "env %s invalid", key); -} - -void -ca_setcnf(struct ca *ca, const char *keyname) -{ - struct stat st; - const char *extcnf, *sslcnf; - - if (stat(IKECA_CNF, &st) == 0) { - extcnf = IKECA_CNF; - sslcnf = IKECA_CNF; - } else { - extcnf = X509_CNF; - sslcnf = SSL_CNF; - } - - snprintf(ca->extcnf, sizeof(ca->extcnf), "%s/%s-ext.cnf", - ca->sslpath, keyname); - snprintf(ca->sslcnf, sizeof(ca->sslcnf), "%s/%s-ssl.cnf", - ca->sslpath, keyname); - - fcopy_env(extcnf, ca->extcnf, 0400); - fcopy_env(sslcnf, ca->sslcnf, 0400); -} - struct ca * ca_setup(char *caname, int create, int quiet, char *pass) { struct stat st; struct ca *ca; char path[PATH_MAX]; + u_int32_t rnd[256]; if (stat(PATH_OPENSSL, &st) == -1) err(1, "openssl binary not available"); @@ -946,6 +822,14 @@ ca_setup(char *caname, int create, int quiet, char *pass) if (quiet) strlcpy(ca->batch, "-batch ", sizeof(ca->batch)); + if (stat(IKECA_CNF, &st) == 0) { + strlcpy(ca->extcnf, IKECA_CNF, sizeof(ca->extcnf)); + strlcpy(ca->sslcnf, IKECA_CNF, sizeof(ca->sslcnf)); + } else { + strlcpy(ca->extcnf, X509_CNF, sizeof(ca->extcnf)); + strlcpy(ca->sslcnf, SSL_CNF, sizeof(ca->sslcnf)); + } + if (create == 0 && stat(ca->sslpath, &st) == -1) { free(ca->caname); free(ca); @@ -962,5 +846,8 @@ ca_setup(char *caname, int create, int quiet, char *pass) if (create && stat(ca->passfile, &st) == -1 && errno == ENOENT) ca_newpass(ca->passfile, pass); + arc4random_buf(rnd, sizeof(rnd)); + RAND_seed(rnd, sizeof(rnd)); + return (ca); } diff --git a/ikectl/ikeca.cnf b/ikectl/ikeca.cnf index cba9bd1..d71662c 100644 --- a/ikectl/ikeca.cnf +++ b/ikectl/ikeca.cnf @@ -1,6 +1,6 @@ -# $OpenBSD: ikeca.cnf,v 1.6 2014/11/22 18:15:41 deraadt Exp $ +# $OpenBSD: ikeca.cnf,v 1.5 2012/10/25 12:35:55 reyk Exp $ -RANDFILE = /dev/random +RANDFILE = /dev/arandom CERT_C = DE CERT_ST = Lower Saxony diff --git a/ikectl/ikectl.8 b/ikectl/ikectl.8 index 0ea9711..19caee9 100644 --- a/ikectl/ikectl.8 +++ b/ikectl/ikectl.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ikectl.8,v 1.24 2015/09/07 15:24:53 sobrado Exp $ +.\" $OpenBSD: ikectl.8,v 1.20 2013/01/08 10:38:19 reyk Exp $ .\" .\" Copyright (c) 2007-2013 Reyk Floeter .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: September 7 2015 $ +.Dd $Mdocdate: January 8 2013 $ .Dt IKECTL 8 .Os .Sh NAME @@ -149,7 +149,7 @@ as the currently active CA or into the specified .It Xo .Cm ca Ar name Cm certificate Ar host .Cm create -.Op Ic server | client +.Op Ic server \*(Ba client .Xc Create a private key and certificate for .Ar host @@ -250,21 +250,21 @@ from the named .El .Sh FILES .Bl -tag -width "/var/run/iked.sockXX" -compact -.It Pa /etc/iked/ +.It /etc/iked/ Active configuration. -.It Pa /etc/ssl/ +.It /etc/ssl/ Directory to store the CA files. -.It Pa /usr/share/iked/ +.It /usr/share/iked If this optional directory exists, .Nm will include the contents with the .Cm ca export commands. -.It Pa /var/run/iked.sock -Default +.It /var/run/iked.sock +default .Ux Ns -domain socket used for communication with -.Xr iked 8 . +.Xr iked 8 .El .Sh EXAMPLES First create a new certificate authority: @@ -346,9 +346,9 @@ program first appeared in The .Nm program was written by -.An Reyk Floeter Aq Mt reyk@openbsd.org +.An Reyk Floeter Aq reyk@openbsd.org and -.An Jonathan Gray Aq Mt jsg@openbsd.org . +.An Jonathan Gray Aq jsg@openbsd.org . .Sh CAVEATS For ease of use, the .Ic ca diff --git a/ikectl/ikectl.c b/ikectl/ikectl.c index d9fd301..5c591fc 100644 --- a/ikectl/ikectl.c +++ b/ikectl/ikectl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikectl.c,v 1.20 2015/08/19 13:30:54 reyk Exp $ */ +/* $OpenBSD: ikectl.c,v 1.16 2013/01/08 10:38:19 reyk Exp $ */ /* * Copyright (c) 2007-2013 Reyk Floeter @@ -19,11 +19,12 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include -#include +#include "openbsd-compat/sys-queue.h" #include -#include +#include "openbsd-compat/sys-tree.h" #include #include @@ -44,7 +45,7 @@ struct imsgname { void (*func)(struct imsg *); }; -struct imsgname *monitor_lookup(uint8_t); +struct imsgname *monitor_lookup(u_int8_t); void monitor_id(struct imsg *); int monitor(struct imsg *); @@ -312,7 +313,7 @@ main(int argc, char *argv[]) } while (ibuf->w.queued) - if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) + if (msgbuf_write(&ibuf->w) < 0) err(1, "write error"); while (!done) { @@ -343,7 +344,7 @@ main(int argc, char *argv[]) } struct imsgname * -monitor_lookup(uint8_t type) +monitor_lookup(u_int8_t type) { int i; @@ -365,7 +366,7 @@ monitor(struct imsg *imsg) imn = monitor_lookup(imsg->hdr.type); printf("%s: imsg type %u len %u peerid %u pid %d\n", imn->name, imsg->hdr.type, imsg->hdr.len, imsg->hdr.peerid, imsg->hdr.pid); - printf("\ttimestamp: %lld, %s", (long long)now, ctime(&now)); + printf("\ttimestamp: %u, %s", now, ctime(&now)); if (imn->type == -1) done = 1; if (imn->func != NULL) diff --git a/ikectl/parser.c b/ikectl/parser.c index 5d1e406..c4a7cb4 100644 --- a/ikectl/parser.c +++ b/ikectl/parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.c,v 1.14 2015/08/19 13:30:54 reyk Exp $ */ +/* $OpenBSD: parser.c,v 1.12 2013/01/08 10:38:19 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -18,10 +18,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include -#include -#include +#include "openbsd-compat/sys-queue.h" +#include "openbsd-compat/sys-tree.h" #include #include @@ -283,7 +284,7 @@ parse_addr(const char *word) const struct token * match_token(char *word, const struct token table[]) { - unsigned int i, match = 0; + u_int i, match = 0; const struct token *t = NULL; for (i = 0; table[i].type != ENDTOKEN; i++) { diff --git a/ikectl/parser.h b/ikectl/parser.h index 250bae0..4281400 100644 --- a/ikectl/parser.h +++ b/ikectl/parser.h @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.h,v 1.13 2015/06/11 18:49:09 reyk Exp $ */ +/* $OpenBSD: parser.h,v 1.12 2013/01/08 10:38:19 reyk Exp $ */ /* * Copyright (c) 2007-2013 Reyk Floeter @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef IKECTL_PARSER_H -#define IKECTL_PARSER_H +#ifndef _IKECTL_PARSER_H +#define _IKECTL_PARSER_H enum actions { NONE, @@ -88,4 +88,4 @@ int ca_key_delete(struct ca *, char *); int ca_key_install(struct ca *, char *, char *); int ca_key_import(struct ca *, char *, char *); -#endif /* IKECTL_PARSER_H */ +#endif /* _IKECTL_PARSER_H */ diff --git a/iked/.cvsignore b/iked/.cvsignore index 3d1e8c4..d822aec 100644 --- a/iked/.cvsignore +++ b/iked/.cvsignore @@ -1,5 +1,6 @@ .cvsignore .deps +Makefile Makefile.am Makefile.in iked.conf diff --git a/iked/CVS/Entries b/iked/CVS/Entries index da5cfbb..ac67746 100644 --- a/iked/CVS/Entries +++ b/iked/CVS/Entries @@ -1,33 +1,31 @@ -/Makefile/1.12/Thu Oct 8 08:37:37 2015// -/ca.c/1.37/Thu Oct 8 08:37:38 2015// -/chap_ms.c/1.9/Thu Oct 8 08:37:38 2015// -/chap_ms.h/1.6/Thu Oct 8 08:37:38 2015// -/config.c/1.37/Thu Oct 8 08:37:38 2015// -/control.c/1.16/Thu Oct 8 08:37:38 2015// -/crypto.c/1.18/Thu Oct 8 08:37:38 2015// -/dh.c/1.17/Thu Oct 8 08:37:38 2015// -/dh.h/1.9/Thu Oct 8 08:37:38 2015// -/eap.c/1.14/Thu Oct 8 08:37:38 2015// -/eap.h/1.5/Thu Oct 8 08:37:38 2015// -/genmap.sh/1.7/Thu Oct 8 08:37:38 2015// -/iked.8/1.19/Thu Oct 8 08:37:38 2015// -/iked.c/1.25/Thu Oct 8 08:37:38 2015// -/iked.conf.5/1.39/Thu Oct 8 08:37:39 2015// -/iked.h/1.89/Thu Oct 8 08:37:39 2015// -/ikev1.c/1.18/Thu Oct 8 08:37:39 2015// -/ikev2.c/1.125/Thu Oct 8 08:37:39 2015// -/ikev2.h/1.22/Thu Oct 8 08:37:39 2015// -/ikev2_msg.c/1.43/Thu Oct 8 08:37:39 2015// -/ikev2_pld.c/1.54/Thu Oct 8 08:37:39 2015// -/imsg_util.c/1.10/Thu Oct 8 08:37:39 2015// -/log.c/1.4/Thu Oct 8 08:37:39 2015// -/ocsp.c/1.6/Fri Aug 21 11:59:27 2015// -/parse.y/1.51/Thu Oct 8 08:37:40 2015// -/pfkey.c/1.45/Thu Oct 8 08:37:40 2015// -/policy.c/1.40/Thu Oct 8 08:37:40 2015// -/proc.c/1.23/Thu Oct 8 08:37:40 2015// -/smult_curve25519_ref.c/1.1/Wed Aug 27 10:28:57 2014// -/timer.c/1.12/Thu Oct 8 08:37:40 2015// -/types.h/1.21/Thu Oct 8 08:37:40 2015// -/util.c/1.27/Thu Oct 8 08:37:40 2015// +/Makefile/1.8/Result of merge+Fri Jan 11 08:22:53 2013// +/chap_ms.c/1.6/Result of merge// +/crypto.c/1.9/Result of merge// +/iked.8/1.13/Result of merge// +/iked.h/1.56/Result of merge// +/log.c/1.3/Result of merge// +/policy.c/1.23/Result of merge+Fri Jan 11 08:23:08 2013// +/timer.c/1.10/Result of merge// +/util.c/1.18/Result of merge// +/ca.c/1.22/Result of merge+Tue Apr 2 09:13:18 2013// +/chap_ms.h/1.3/Mon Jan 14 14:11:49 2013// +/config.c/1.20/Result of merge+Tue Apr 2 09:13:19 2013// +/control.c/1.12/Result of merge// +/dh.c/1.10/Mon Jan 14 14:11:49 2013// +/dh.h/1.5/Mon Jan 14 14:11:49 2013// +/eap.c/1.9/Result of merge+Tue Apr 2 09:13:20 2013// +/eap.h/1.3/Mon Jan 14 14:11:49 2013// +/genmap.sh/1.6/Mon Jan 14 14:11:49 2013// +/iked.c/1.17/Result of merge+Tue Apr 2 09:13:21 2013// +/iked.conf.5/1.23/Tue Apr 2 09:13:22 2013// +/ikev1.c/1.13/Result of merge+Tue Apr 2 09:13:23 2013// +/ikev2.c/1.82/Result of merge+Tue Apr 2 09:13:24 2013// +/ikev2.h/1.12/Tue Apr 2 09:13:26 2013// +/ikev2_msg.c/1.25/Result of merge+Tue Apr 2 09:13:26 2013// +/ikev2_pld.c/1.31/Result of merge+Tue Apr 2 09:13:27 2013// +/imsg_util.c/1.7/Result of merge+Tue Apr 2 09:13:28 2013// +/parse.y/1.30/Result of merge// +/pfkey.c/1.23/Result of merge// +/proc.c/1.9/Result of merge+Tue Apr 2 09:13:31 2013// +/types.h/1.17/Mon Jan 14 14:11:49 2013// D diff --git a/iked/Makefile b/iked/Makefile deleted file mode 100644 index 85d4c39..0000000 --- a/iked/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# $OpenBSD: Makefile,v 1.12 2014/08/27 10:28:57 reyk Exp $ - -PROG= iked -SRCS= ca.c chap_ms.c config.c control.c crypto.c dh.c \ - eap.c iked.c ikev1.c ikev2.c ikev2_msg.c ikev2_pld.c \ - log.c ocsp.c pfkey.c policy.c proc.c timer.c util.c \ - imsg_util.c smult_curve25519_ref.c -SRCS+= eap_map.c ikev2_map.c -SRCS+= parse.y -MAN= iked.conf.5 iked.8 -#NOMAN= yes - -LDADD= -lutil -levent -lcrypto -DPADD= ${LIBUTIL} ${LIBEVENT} ${LIBCRYPTO} -CFLAGS+= -Wall -I${.CURDIR} -CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes -CFLAGS+= -Wmissing-declarations -CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual -CFLAGS+= -Wsign-compare -CLEANFILES+= y.tab.h ikev2_map.c eap_map.c -GENERATED= ikev2_map.c eap_map.c - -ikev2_map.c: genmap.sh ikev2.h - /bin/sh ${.CURDIR}/genmap.sh ${.CURDIR}/ikev2.h ikev2 > $@ - @touch $@ - -eap_map.c: genmap.sh eap.h - /bin/sh ${.CURDIR}/genmap.sh ${.CURDIR}/eap.h eap > $@ - @touch $@ - -${PROG} beforedepend: ${GENERATED} - -.include diff --git a/iked/Makefile.am b/iked/Makefile.am new file mode 100644 index 0000000..a1dc4a7 --- /dev/null +++ b/iked/Makefile.am @@ -0,0 +1,76 @@ +sbin_PROGRAMS= iked + +iked_MAPS= eap_map.c ikev2_map.c +iked_MAPS_IN= eap.h ikev2.h +iked_SOURCES= ca.c chap_ms.c config.c control.c crypto.c dh.c \ + eap.c iked.c ikev1.c ikev2.c ikev2_msg.c ikev2_pld.c \ + log.c policy.c proc.c timer.c util.c imsg_util.c \ + parse.y $(iked_MAPS) +iked_CFLAGS= + +libpfkey_a_SOURCES= pfkey.c +libpfkey_a_CPPFLAGS= @PFKEY_CPPFLAGS@ + +noinst_LIBRARIES= libpfkey.a + +LIBCOMPAT= $(top_builddir)/openbsd-compat/libopenbsd-compat.a +LDADD= $(LIBCOMPAT) libpfkey.a +CPPFLAGS= -include $(top_srcdir)/openbsd-compat/includes.h \ + -I$(top_srcdir)/openbsd-compat \ + -I$(srcdir) @CPPFLAGS@ @DEFS@ +MANPAGES= iked.8.out iked.conf.5.out +MANPAGES_IN= iked.8 iked.conf.5 +CONFIGFILES= iked.conf.out +CONFIGFILES_IN= iked.conf +EXTRA_DIST= $(CONFIGFILES_IN) $(MANPAGES_IN) +CLEANFILES= $(iked_MAPS) $(CONFIGFILES) $(MANPAGES) +PATHSUBS= -e 's|/etc/iked/|$(sysconfdir)/iked/|g' \ + -e 's|/usr/libexec|$(libexecdir)|g' \ + -e 's|/var/run/iked.sock|$(sockdir)/iked.sock|g' +FIXPATHSCMD= $(SED) $(PATHSUBS) + +$(iked_MAPS): genmap.sh $(iked_MAPS_IN) + mapname=`echo $@ | sed 's/_map\.c$$//'`; \ + hdrname=$${mapname}.h; \ + $(SH) genmap.sh $${hdrname} $${mapname} > $@ + @touch $@ + +$(MANPAGES): $(MANPAGES_IN) + if test "$(MANTYPE)" = "cat"; then \ + manpage=$(srcdir)/`echo $@ | sed 's/\.[1-9]\.out$$/\.0/'`; \ + else \ + manpage=$(srcdir)/`echo $@ | sed 's/\.out$$//'`; \ + fi; \ + if test "$(MANTYPE)" = "man"; then \ + $(FIXPATHSCMD) $${manpage} | $(AWK) -f $(top_srcdir)/mdoc2man.awk > $@; \ + else \ + $(FIXPATHSCMD) $${manpage} > $@; \ + fi + +$(CONFIGFILES): $(CONFIGFILES_IN) + conffile=`echo $@ | sed 's/.out$$//'`; \ + $(FIXPATHSCMD) $(srcdir)/$${conffile} > $@ + +install-exec-hook: $(CONFIGFILES) $(MANPAGES) + $(INSTALL) -d $(DESTDIR)$(sysconfdir)/iked/ + $(INSTALL) -d $(DESTDIR)$(sysconfdir)/iked/ca + $(INSTALL) -d $(DESTDIR)$(sysconfdir)/iked/certs + $(INSTALL) -d $(DESTDIR)$(sysconfdir)/iked/crls + $(INSTALL) -d $(DESTDIR)$(sysconfdir)/iked/pubkeys/fqdn + $(INSTALL) -d $(DESTDIR)$(sysconfdir)/iked/pubkeys/ufqdn + $(INSTALL) -d $(DESTDIR)$(sysconfdir)/iked/pubkeys/ipv4 + $(INSTALL) -d $(DESTDIR)$(sysconfdir)/iked/pubkeys/ipv6 + $(INSTALL) -d -m 700 $(DESTDIR)$(sysconfdir)/iked/private + $(INSTALL) -d $(DESTDIR)$(sysconfdir)/iked/ + $(INSTALL) -d $(DESTDIR)$(sbindir) + $(INSTALL) -d $(DESTDIR)$(mandir)/$(mansubdir)8 + $(INSTALL) -d $(DESTDIR)$(mandir)/$(mansubdir)5 + + @if [ ! -f $(DESTDIR)$(sysconfdir)/iked.conf ]; then \ + $(INSTALL) -m 600 iked.conf.out $(DESTDIR)$(sysconfdir)/iked.conf; \ + else \ + echo "$(DESTDIR)$(sysconfdir)/iked.conf already exists, install will not overwrite"; \ + fi + + $(INSTALL) -m 644 iked.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/iked.8 + $(INSTALL) -m 644 iked.conf.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/iked.conf.5 diff --git a/iked/ca.c b/iked/ca.c index dd0ef9e..5f55b1f 100644 --- a/iked/ca.c +++ b/iked/ca.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ca.c,v 1.37 2015/10/01 10:59:23 reyk Exp $ */ +/* $OpenBSD: ca.c,v 1.22 2013/03/21 04:30:14 deraadt Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,7 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +#include +#include "openbsd-compat/sys-queue.h" #include #include #include @@ -26,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -41,21 +43,19 @@ #include #include #include -#include #include "iked.h" #include "ikev2.h" -void ca_reset(struct privsep *, struct privsep_proc *, void *); +void ca_reset(struct privsep *, void *); int ca_reload(struct iked *); int ca_getreq(struct iked *, struct imsg *); int ca_getcert(struct iked *, struct imsg *); int ca_getauth(struct iked *, struct imsg *); -X509 *ca_by_subjectpubkey(X509_STORE *, uint8_t *, size_t); +X509 *ca_by_subjectpubkey(X509_STORE *, u_int8_t *, size_t); X509 *ca_by_issuer(X509_STORE *, X509_NAME *, struct iked_static_id *); -int ca_subjectpubkey_digest(X509 *, uint8_t *, unsigned int *); -int ca_x509_subject_cmp(X509 *, struct iked_static_id *); +int ca_subjectpubkey_digest(X509 *, u_int8_t *, u_int *); int ca_validate_pubkey(struct iked *, struct iked_static_id *, void *, size_t); int ca_validate_cert(struct iked *, struct iked_static_id *, @@ -64,8 +64,7 @@ struct ibuf * ca_x509_serialize(X509 *); int ca_x509_subjectaltname_cmp(X509 *, struct iked_static_id *); int ca_x509_subjectaltname(X509 *cert, struct iked_id *); -int ca_privkey_serialize(EVP_PKEY *, struct iked_id *); -int ca_pubkey_serialize(EVP_PKEY *, struct iked_id *); +int ca_key_serialize(EVP_PKEY *, struct iked_id *); int ca_dispatch_parent(int, struct privsep_proc *, struct imsg *); int ca_dispatch_ikev1(int, struct privsep_proc *, struct imsg *); int ca_dispatch_ikev2(int, struct privsep_proc *, struct imsg *); @@ -84,7 +83,6 @@ struct ca_store { X509_LOOKUP *ca_certlookup; struct iked_id ca_privkey; - struct iked_id ca_pubkey; }; pid_t @@ -100,7 +98,6 @@ caproc(struct privsep *ps, struct privsep_proc *p) if ((store = calloc(1, sizeof(*store))) == NULL) fatal("ca: failed to allocate cert store"); - /* Read private key */ if ((fp = fopen(IKED_PRIVKEY, "r")) == NULL) fatal("ca: failed to open private key"); @@ -108,18 +105,14 @@ caproc(struct privsep *ps, struct privsep_proc *p) fatalx("ca: failed to read private key"); fclose(fp); - if (ca_privkey_serialize(key, &store->ca_privkey) != 0) + if (ca_key_serialize(key, &store->ca_privkey) != 0) fatalx("ca: failed to serialize private key"); - if (ca_pubkey_serialize(key, &store->ca_pubkey) != 0) - fatalx("ca: failed to serialize public key"); - - EVP_PKEY_free(key); return (proc_run(ps, p, procs, nitems(procs), ca_reset, store)); } void -ca_reset(struct privsep *ps, struct privsep_proc *p, void *arg) +ca_reset(struct privsep *ps, void *arg) { struct iked *env = ps->ps_env; struct ca_store *store = arg; @@ -151,8 +144,8 @@ int ca_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) { struct iked *env = p->p_env; - struct ca_store *store = env->sc_priv; - unsigned int mode; + struct ca_store *store = env->sc_priv; + u_int mode; switch (imsg->hdr.type) { case IMSG_CTL_RESET: @@ -160,15 +153,9 @@ ca_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) memcpy(&mode, imsg->data, sizeof(mode)); if (mode == RESET_ALL || mode == RESET_CA) { log_debug("%s: config reload", __func__); - ca_reset(&env->sc_ps, p, store); + ca_reset(&env->sc_ps, store); } break; - case IMSG_OCSP_FD: - ocsp_receive_fd(env, imsg); - break; - case IMSG_OCSP_URL: - config_getocsp(env, imsg); - break; default: return (-1); } @@ -206,7 +193,7 @@ ca_dispatch_ikev2(int fd, struct privsep_proc *p, struct imsg *imsg) int ca_setcert(struct iked *env, struct iked_sahdr *sh, struct iked_id *id, - uint8_t type, uint8_t *data, size_t len, enum privsep_procid procid) + u_int8_t type, u_int8_t *data, size_t len, enum privsep_procid procid) { struct iovec iov[4]; int iovcnt = 0; @@ -241,15 +228,14 @@ ca_setcert(struct iked *env, struct iked_sahdr *sh, struct iked_id *id, iov[iovcnt].iov_len = len; iovcnt++; - if (proc_composev_imsg(&env->sc_ps, procid, -1, - IMSG_CERT, -1, iov, iovcnt) == -1) + if (proc_composev_imsg(env, procid, IMSG_CERT, -1, iov, iovcnt) == -1) return (-1); return (0); } int -ca_setreq(struct iked *env, struct iked_sa *sa, - struct iked_static_id *localid, uint8_t type, uint8_t *data, +ca_setreq(struct iked *env, struct iked_sahdr *sh, + struct iked_static_id *localid, u_int8_t type, u_int8_t *data, size_t len, enum privsep_procid procid) { struct iovec iov[4]; @@ -273,8 +259,8 @@ ca_setreq(struct iked *env, struct iked_sa *sa, iov[iovcnt].iov_len = sizeof(idb); iovcnt++; - iov[iovcnt].iov_base = &sa->sa_hdr; - iov[iovcnt].iov_len = sizeof(sa->sa_hdr); + iov[iovcnt].iov_base = sh; + iov[iovcnt].iov_len = sizeof(*sh); iovcnt++; iov[iovcnt].iov_base = &type; iov[iovcnt].iov_len = sizeof(type); @@ -283,12 +269,10 @@ ca_setreq(struct iked *env, struct iked_sa *sa, iov[iovcnt].iov_len = len; iovcnt++; - if (proc_composev_imsg(&env->sc_ps, procid, -1, + if (proc_composev_imsg(env, procid, IMSG_CERTREQ, -1, iov, iovcnt) == -1) goto done; - sa_stateflags(sa, IKED_REQ_CERTREQ); - ret = 0; done: ibuf_release(id.id_buf); @@ -302,13 +286,7 @@ ca_setauth(struct iked *env, struct iked_sa *sa, struct iovec iov[3]; int iovcnt = 3; struct iked_policy *policy = sa->sa_policy; - uint8_t type = policy->pol_auth.auth_method; - - /* switch encoding to IKEV2_AUTH_SIG if SHA2 is supported */ - if (sa->sa_sigsha2 && type == IKEV2_AUTH_RSA_SIG) { - log_debug("%s: switching from RSA_SIG to SIG", __func__); - type = IKEV2_AUTH_SIG; - } + u_int8_t type = policy->pol_auth.auth_method; if (type == IKEV2_AUTH_SHARED_KEY_MIC) { sa->sa_stateflags |= IKED_REQ_AUTH; @@ -325,11 +303,10 @@ ca_setauth(struct iked *env, struct iked_sa *sa, else { iov[2].iov_base = ibuf_data(authmsg); iov[2].iov_len = ibuf_size(authmsg); - log_debug("%s: auth length %zu", __func__, ibuf_size(authmsg)); + log_debug("%s: auth length %d", __func__, ibuf_size(authmsg)); } - if (proc_composev_imsg(&env->sc_ps, id, -1, - IMSG_AUTH, -1, iov, iovcnt) == -1) + if (proc_composev_imsg(env, id, IMSG_AUTH, -1, iov, iovcnt) == -1) return (-1); return (0); } @@ -338,15 +315,15 @@ int ca_getcert(struct iked *env, struct imsg *imsg) { struct iked_sahdr sh; - uint8_t type; - uint8_t *ptr; + u_int8_t type; + u_int8_t *ptr; size_t len; struct iked_static_id id; - unsigned int i; + u_int i; struct iovec iov[2]; int iovcnt = 2, cmd, ret = 0; - ptr = (uint8_t *)imsg->data; + ptr = (u_int8_t *)imsg->data; len = IMSG_DATA_SIZE(imsg); i = sizeof(id) + sizeof(sh) + sizeof(type); if (len <= i) @@ -356,7 +333,7 @@ ca_getcert(struct iked *env, struct imsg *imsg) if (id.id_type == IKEV2_ID_NONE) return (-1); memcpy(&sh, ptr + sizeof(id), sizeof(sh)); - memcpy(&type, ptr + sizeof(id) + sizeof(sh), sizeof(uint8_t)); + memcpy(&type, ptr + sizeof(id) + sizeof(sh), sizeof(u_int8_t)); ptr += i; len -= i; @@ -364,11 +341,6 @@ ca_getcert(struct iked *env, struct imsg *imsg) switch (type) { case IKEV2_CERT_X509_CERT: ret = ca_validate_cert(env, &id, ptr, len); - if (ret == 0 && env->sc_ocsp_url) { - ret = ocsp_validate_cert(env, &id, ptr, len, sh, type); - if (ret == 0) - return (0); - } break; case IKEV2_CERT_RSA_KEY: ret = ca_validate_pubkey(env, &id, ptr, len); @@ -389,8 +361,7 @@ ca_getcert(struct iked *env, struct imsg *imsg) iov[1].iov_base = &type; iov[1].iov_len = sizeof(type); - if (proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, - cmd, -1, iov, iovcnt) == -1) + if (proc_composev_imsg(env, PROC_IKEV2, cmd, -1, iov, iovcnt) == -1) return (-1); return (0); } @@ -398,19 +369,19 @@ ca_getcert(struct iked *env, struct imsg *imsg) int ca_getreq(struct iked *env, struct imsg *imsg) { - struct ca_store *store = env->sc_priv; + struct ca_store *store = env->sc_priv; struct iked_sahdr sh; - uint8_t type; - uint8_t *ptr; + u_int8_t type; + u_int8_t *ptr; size_t len; - unsigned int i, n; + u_int i, n; X509 *ca = NULL, *cert = NULL; struct ibuf *buf; struct iked_static_id id; - ptr = (uint8_t *)imsg->data; + ptr = (u_int8_t *)imsg->data; len = IMSG_DATA_SIZE(imsg); - i = sizeof(id) + sizeof(uint8_t) + sizeof(sh); + i = sizeof(id) + sizeof(u_int8_t) + sizeof(sh); if (len < i || ((len - i) % SHA_DIGEST_LENGTH) != 0) return (-1); @@ -418,51 +389,41 @@ ca_getreq(struct iked *env, struct imsg *imsg) if (id.id_type == IKEV2_ID_NONE) return (-1); memcpy(&sh, ptr + sizeof(id), sizeof(sh)); - memcpy(&type, ptr + sizeof(id) + sizeof(sh), sizeof(uint8_t)); - - switch (type) { - case IKEV2_CERT_RSA_KEY: - if (store->ca_pubkey.id_type != type || - (buf = store->ca_pubkey.id_buf) == NULL) - return (-1); + memcpy(&type, ptr + sizeof(id) + sizeof(sh), sizeof(u_int8_t)); + if (type != IKEV2_CERT_X509_CERT) + return (-1); - log_debug("%s: using local public key of type %s", __func__, - print_map(type, ikev2_cert_map)); - break; - case IKEV2_CERT_X509_CERT: - for (n = 1; i < len; n++, i += SHA_DIGEST_LENGTH) { - if ((ca = ca_by_subjectpubkey(store->ca_cas, ptr + i, - SHA_DIGEST_LENGTH)) == NULL) - continue; + for (n = 1; i < len; n++, i += SHA_DIGEST_LENGTH) { + if ((ca = ca_by_subjectpubkey(store->ca_cas, + ptr + i, SHA_DIGEST_LENGTH)) == NULL) { + log_debug("%s: CA %d not found", __func__, n); + print_hex(ptr, i, SHA_DIGEST_LENGTH); + continue; + } - log_debug("%s: found CA %s", __func__, ca->name); + log_debug("%s: found CA %s", __func__, ca->name); - if ((cert = ca_by_issuer(store->ca_certs, - X509_get_subject_name(ca), &id)) != NULL) { - /* XXX - * should we re-validate our own cert here? - */ - break; - } - } - if (ca == NULL || cert == NULL) { - log_warnx("%s: no valid local certificate found", - __func__); - type = IKEV2_CERT_NONE; - ca_setcert(env, &sh, NULL, type, NULL, 0, PROC_IKEV2); - return (0); + if ((cert = ca_by_issuer(store->ca_certs, + X509_get_subject_name(ca), &id)) != NULL) { + /* XXX should we re-validate our own cert here? */ + break; } - log_debug("%s: found local certificate %s", __func__, - cert->name); - if ((buf = ca_x509_serialize(cert)) == NULL) - return (-1); - break; - default: - log_warnx("%s: unknown cert type requested", __func__); - return (-1); + log_debug("%s: no valid certificate for this CA", __func__); + } + if (ca == NULL || cert == NULL) { + log_warnx("%s: no valid local certificate found", __func__); + type = IKEV2_CERT_NONE; + ca_setcert(env, &sh, NULL, type, NULL, 0, PROC_IKEV2); + return (0); } + log_debug("%s: found local certificate %s", __func__, cert->name); + + if ((buf = ca_x509_serialize(cert)) == NULL) + return (-1); + + type = IKEV2_CERT_X509_CERT; ca_setcert(env, &sh, NULL, type, ibuf_data(buf), ibuf_size(buf), PROC_IKEV2); @@ -472,26 +433,26 @@ ca_getreq(struct iked *env, struct imsg *imsg) int ca_getauth(struct iked *env, struct imsg *imsg) { - struct ca_store *store = env->sc_priv; + struct ca_store *store = env->sc_priv; struct iked_sahdr sh; - uint8_t method; - uint8_t *ptr; + u_int8_t method; + u_int8_t *ptr; size_t len; - unsigned int i; + u_int i; int ret = -1; struct iked_sa sa; struct iked_policy policy; struct iked_id *id; struct ibuf *authmsg; - ptr = (uint8_t *)imsg->data; + ptr = (u_int8_t *)imsg->data; len = IMSG_DATA_SIZE(imsg); i = sizeof(method) + sizeof(sh); if (len <= i) return (-1); memcpy(&sh, ptr, sizeof(sh)); - memcpy(&method, ptr + sizeof(sh), sizeof(uint8_t)); + memcpy(&method, ptr + sizeof(sh), sizeof(u_int8_t)); if (method == IKEV2_AUTH_SHARED_KEY_MIC) return (-1); @@ -531,16 +492,17 @@ ca_getauth(struct iked *env, struct imsg *imsg) int ca_reload(struct iked *env) { - struct ca_store *store = env->sc_priv; - uint8_t md[EVP_MAX_MD_SIZE]; - char file[PATH_MAX]; - struct iovec iov[2]; + struct ca_store *store = env->sc_priv; + DIR *dir; struct dirent *entry; + char file[PATH_MAX]; STACK_OF(X509_OBJECT) *h; X509_OBJECT *xo; X509 *x509; - DIR *dir; - int i, len, iovcnt = 0; + int i, len; + u_int8_t md[EVP_MAX_MD_SIZE]; + struct iovec iov[2]; + int iovcnt = 2; /* * Load CAs @@ -561,7 +523,7 @@ ca_reload(struct iked *env) X509_FILETYPE_PEM)) { log_warn("%s: failed to load ca file %s", __func__, entry->d_name); - ca_sslerror(__func__); + ca_sslerror(); continue; } log_debug("%s: loaded ca file %s", __func__, entry->d_name); @@ -587,7 +549,7 @@ ca_reload(struct iked *env) X509_FILETYPE_PEM)) { log_warn("%s: failed to load crl file %s", __func__, entry->d_name); - ca_sslerror(__func__); + ca_sslerror(); continue; } @@ -626,18 +588,16 @@ ca_reload(struct iked *env) env->sc_certreqtype = IKEV2_CERT_X509_CERT; iov[0].iov_base = &env->sc_certreqtype; iov[0].iov_len = sizeof(env->sc_certreqtype); - iovcnt++; iov[1].iov_base = ibuf_data(env->sc_certreq); iov[1].iov_len = ibuf_length(env->sc_certreq); - iovcnt++; - log_debug("%s: loaded %zu ca certificate%s", __func__, + log_debug("%s: loaded %d ca certificate%s", __func__, ibuf_length(env->sc_certreq) / SHA_DIGEST_LENGTH, ibuf_length(env->sc_certreq) == SHA_DIGEST_LENGTH ? "" : "s"); - (void)proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, - IMSG_CERTREQ, -1, iov, iovcnt); + (void)proc_composev_imsg(env, PROC_IKEV2, IMSG_CERTREQ, -1, + iov, iovcnt); } /* @@ -659,7 +619,7 @@ ca_reload(struct iked *env) X509_FILETYPE_PEM)) { log_warn("%s: failed to load cert file %s", __func__, entry->d_name); - ca_sslerror(__func__); + ca_sslerror(); continue; } log_debug("%s: loaded cert file %s", __func__, entry->d_name); @@ -677,31 +637,18 @@ ca_reload(struct iked *env) (void)ca_validate_cert(env, NULL, x509, 0); } - if (!env->sc_certreqtype) - env->sc_certreqtype = store->ca_pubkey.id_type; - - log_debug("%s: local cert type %s", __func__, - print_map(env->sc_certreqtype, ikev2_cert_map)); - - iov[0].iov_base = &env->sc_certreqtype; - iov[0].iov_len = sizeof(env->sc_certreqtype); - if (iovcnt == 0) - iovcnt++; - (void)proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, - IMSG_CERTREQ, -1, iov, iovcnt); - return (0); } X509 * -ca_by_subjectpubkey(X509_STORE *ctx, uint8_t *sig, size_t siglen) +ca_by_subjectpubkey(X509_STORE *ctx, u_int8_t *sig, size_t siglen) { STACK_OF(X509_OBJECT) *h; X509_OBJECT *xo; X509 *ca; int i; - unsigned int len; - uint8_t md[EVP_MAX_MD_SIZE]; + u_int len; + u_int8_t md[EVP_MAX_MD_SIZE]; h = ctx->objs; @@ -743,16 +690,9 @@ ca_by_issuer(X509_STORE *ctx, X509_NAME *subject, struct iked_static_id *id) if ((issuer = X509_get_issuer_name(cert)) == NULL) continue; else if (X509_NAME_cmp(subject, issuer) == 0) { - switch (id->id_type) { - case IKEV2_ID_ASN1_DN: - if (ca_x509_subject_cmp(cert, id) == 0) - return (cert); - break; - default: - if (ca_x509_subjectaltname_cmp(cert, id) == 0) - return (cert); - break; - } + if (ca_x509_subjectaltname_cmp(cert, id) != 0) + continue; + return (cert); } } @@ -760,9 +700,9 @@ ca_by_issuer(X509_STORE *ctx, X509_NAME *subject, struct iked_static_id *id) } int -ca_subjectpubkey_digest(X509 *x509, uint8_t *md, unsigned int *size) +ca_subjectpubkey_digest(X509 *x509, u_int8_t *md, u_int *size) { - uint8_t *buf = NULL; + u_int8_t *buf = NULL; int buflen; if (*size < SHA_DIGEST_LENGTH) @@ -791,7 +731,7 @@ ca_x509_serialize(X509 *x509) { long len; struct ibuf *buf; - uint8_t *d = NULL; + u_int8_t *d = NULL; BIO *out; if ((out = BIO_new(BIO_s_mem())) == NULL) @@ -803,18 +743,16 @@ ca_x509_serialize(X509 *x509) len = BIO_get_mem_data(out, &d); buf = ibuf_new(d, len); - BIO_free(out); return (buf); } int -ca_pubkey_serialize(EVP_PKEY *key, struct iked_id *id) +ca_key_serialize(EVP_PKEY *key, struct iked_id *id) { - RSA *rsa = NULL; - uint8_t *d; - int len = 0; - int ret = -1; + int len; + u_int8_t *d; + RSA *rsa; switch (key->type) { case EVP_PKEY_RSA: @@ -823,60 +761,16 @@ ca_pubkey_serialize(EVP_PKEY *key, struct iked_id *id) ibuf_release(id->id_buf); if ((rsa = EVP_PKEY_get1_RSA(key)) == NULL) - goto done; - if ((len = i2d_RSAPublicKey(rsa, NULL)) <= 0) - goto done; - if ((id->id_buf = ibuf_new(NULL, len)) == NULL) - goto done; - - d = ibuf_data(id->id_buf); - if (i2d_RSAPublicKey(rsa, &d) != len) { - ibuf_release(id->id_buf); - goto done; - } - - id->id_type = IKEV2_CERT_RSA_KEY; - break; - default: - log_debug("%s: unsupported key type %d", __func__, key->type); - return (-1); - } - - log_debug("%s: type %s length %d", __func__, - print_map(id->id_type, ikev2_cert_map), len); - - ret = 0; - done: - if (rsa != NULL) - RSA_free(rsa); - return (ret); -} - -int -ca_privkey_serialize(EVP_PKEY *key, struct iked_id *id) -{ - RSA *rsa = NULL; - uint8_t *d; - int len = 0; - int ret = -1; - - switch (key->type) { - case EVP_PKEY_RSA: - id->id_type = 0; - id->id_offset = 0; - ibuf_release(id->id_buf); - - if ((rsa = EVP_PKEY_get1_RSA(key)) == NULL) - goto done; + return (-1); if ((len = i2d_RSAPrivateKey(rsa, NULL)) <= 0) - goto done; + return (-1); if ((id->id_buf = ibuf_new(NULL, len)) == NULL) - goto done; + return (-1); d = ibuf_data(id->id_buf); if (i2d_RSAPrivateKey(rsa, &d) != len) { ibuf_release(id->id_buf); - goto done; + return (-1); } id->id_type = IKEV2_CERT_RSA_KEY; @@ -886,22 +780,15 @@ ca_privkey_serialize(EVP_PKEY *key, struct iked_id *id) return (-1); } - log_debug("%s: type %s length %d", __func__, - print_map(id->id_type, ikev2_cert_map), len); - - ret = 0; - done: - if (rsa != NULL) - RSA_free(rsa); - return (ret); + return (0); } char * -ca_asn1_name(uint8_t *asn1, size_t len) +ca_asn1_name(u_int8_t *asn1, size_t len) { X509_NAME *name = NULL; char *str = NULL; - const uint8_t *p; + const u_int8_t *p; p = asn1; if ((name = d2i_X509_NAME(NULL, &p, len)) == NULL) @@ -925,112 +812,17 @@ ca_x509_name(void *ptr) return (strdup(buf)); } -/* - * Copy 'src' to 'dst' until 'marker' is found while unescaping '\' - * characters. The return value tells the caller where to continue - * parsing (might be the end of the string) or NULL on error. - */ -static char * -ca_x509_name_unescape(char *src, char *dst, char marker) -{ - while (*src) { - if (*src == marker) { - src++; - break; - } - if (*src == '\\') { - src++; - if (!*src) { - log_warnx("%s: '\\' at end of string", - __func__); - *dst = '\0'; - return (NULL); - } - } - *dst++ = *src++; - } - *dst = '\0'; - return (src); -} -/* - * Parse an X509 subject name where 'subject' is in the format - * /type0=value0/type1=value1/type2=... - * where characters may be escaped by '\'. - * See lib/libssl/src/apps/apps.c:parse_name() - */ -void * -ca_x509_name_parse(char *subject) -{ - char *cp, *value = NULL, *type = NULL; - size_t maxlen; - X509_NAME *name = NULL; - - if (*subject != '/') { - log_warnx("%s: leading '/' missing in '%s'", __func__, subject); - goto err; - } - - /* length of subject is upper bound for unescaped type/value */ - maxlen = strlen(subject) + 1; - - if ((type = calloc(1, maxlen)) == NULL || - (value = calloc(1, maxlen)) == NULL || - (name = X509_NAME_new()) == NULL) - goto err; - - cp = subject + 1; - while (*cp) { - /* unescape type, terminated by '=' */ - cp = ca_x509_name_unescape(cp, type, '='); - if (cp == NULL) { - log_warnx("%s: could not parse type", __func__); - goto err; - } - if (!*cp) { - log_warnx("%s: missing value", __func__); - goto err; - } - /* unescape value, terminated by '/' */ - cp = ca_x509_name_unescape(cp, value, '/'); - if (cp == NULL) { - log_warnx("%s: could not parse value", __func__); - goto err; - } - if (!*type || !*value) { - log_warnx("%s: empty type or value", __func__); - goto err; - } - log_debug("%s: setting '%s' to '%s'", __func__, type, value); - if (!X509_NAME_add_entry_by_txt(name, type, MBSTRING_ASC, - value, -1, -1, 0)) { - log_warnx("%s: setting '%s' to '%s' failed", __func__, - type, value); - ca_sslerror(__func__); - goto err; - } - } - free(type); - free(value); - return (name); - -err: - X509_NAME_free(name); - free(type); - free(value); - return (NULL); -} - int ca_validate_pubkey(struct iked *env, struct iked_static_id *id, void *data, size_t len) { BIO *rawcert = NULL; - RSA *peerrsa = NULL, *localrsa = NULL; + RSA *rsa = NULL; EVP_PKEY *peerkey = NULL, *localkey = NULL; int ret = -1; FILE *fp = NULL; char idstr[IKED_ID_SIZE]; - char file[PATH_MAX]; + char file[MAXPATHLEN]; struct iked_id idp; if (len == 0 && data == NULL) @@ -1063,58 +855,42 @@ ca_validate_pubkey(struct iked *env, struct iked_static_id *id, if ((rawcert = BIO_new_mem_buf(data, len)) == NULL) goto done; - if ((peerrsa = d2i_RSAPublicKey_bio(rawcert, NULL)) == NULL) + if ((rsa = d2i_RSAPublicKey_bio(rawcert, NULL)) == NULL) goto sslerr; if ((peerkey = EVP_PKEY_new()) == NULL) goto sslerr; - if (!EVP_PKEY_set1_RSA(peerkey, peerrsa)) + if (!EVP_PKEY_set1_RSA(peerkey, rsa)) goto sslerr; } lc_string(idstr); if (strlcpy(file, IKED_PUBKEY_DIR, sizeof(file)) >= sizeof(file) || - strlcat(file, idstr, sizeof(file)) >= sizeof(file)) + strlcpy(file, idstr, sizeof(file)) >= sizeof(file)) goto done; + log_debug("%s: looking up %s", __func__, file); + if ((fp = fopen(file, "r")) == NULL) goto done; + localkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL); - if (localkey == NULL) { - /* reading PKCS #8 failed, try PEM */ - rewind(fp); - localrsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL); - fclose(fp); - if (localrsa == NULL) - goto sslerr; - if ((localkey = EVP_PKEY_new()) == NULL) - goto sslerr; - if (!EVP_PKEY_set1_RSA(localkey, localrsa)) - goto sslerr; - } else { - fclose(fp); - } + fclose(fp); if (localkey == NULL) goto sslerr; if (!EVP_PKEY_cmp(peerkey, localkey)) goto done; - log_debug("%s: valid public key in file %s", __func__, file); - ret = 0; sslerr: if (ret != 0) - ca_sslerror(__func__); + ca_sslerror(); done: ibuf_release(idp.id_buf); if (peerkey != NULL) EVP_PKEY_free(peerkey); - if (localkey != NULL) - EVP_PKEY_free(localkey); - if (peerrsa != NULL) - RSA_free(peerrsa); - if (localrsa != NULL) - RSA_free(localrsa); + if (rsa != NULL) + RSA_free(rsa); if (rawcert != NULL) BIO_free(rawcert); @@ -1130,7 +906,9 @@ ca_validate_cert(struct iked *env, struct iked_static_id *id, BIO *rawcert = NULL; X509 *cert = NULL; int ret = -1, result, error; - X509_NAME *subject; + size_t idlen, idoff; + const u_int8_t *idptr; + X509_NAME *idname = NULL, *subject; const char *errstr = "failed"; if (len == 0) { @@ -1153,13 +931,23 @@ ca_validate_cert(struct iked *env, struct iked_static_id *id, if (id != NULL) { if ((ret = ca_validate_pubkey(env, id, X509_get_pubkey(cert), 0)) == 0) { - errstr = "in public key file, ok"; + errstr = "public key found, ok"; goto done; } switch (id->id_type) { case IKEV2_ID_ASN1_DN: - if (ca_x509_subject_cmp(cert, id) < 0) { + idoff = id->id_offset; + if (id->id_length <= idoff) { + errstr = "invalid ASN1_DN id length"; + goto done; + } + idlen = id->id_length - idoff; + idptr = id->id_data + idoff; + + if ((idname = d2i_X509_NAME(NULL, + &idptr, idlen)) == NULL || + X509_NAME_cmp(subject, idname) != 0) { errstr = "ASN1_DN identifier mismatch"; goto done; } @@ -1196,12 +984,14 @@ ca_validate_cert(struct iked *env, struct iked_static_id *id, /* Success */ ret = 0; - errstr = "ok"; done: if (cert != NULL) - log_debug("%s: %s %.100s", __func__, cert->name, errstr); + log_debug("%s: %s %.100s", __func__, cert->name, + ret == 0 ? "ok" : errstr); + if (idname != NULL) + X509_NAME_free(idname); if (rawcert != NULL) { BIO_free(rawcert); if (cert != NULL) @@ -1211,31 +1001,6 @@ ca_validate_cert(struct iked *env, struct iked_static_id *id, return (ret); } -/* check if subject from cert matches the id */ -int -ca_x509_subject_cmp(X509 *cert, struct iked_static_id *id) -{ - X509_NAME *subject, *idname = NULL; - const uint8_t *idptr; - size_t idlen; - int ret = -1; - - if (id->id_type != IKEV2_ID_ASN1_DN) - return (-1); - if ((subject = X509_get_subject_name(cert)) == NULL) - return (-1); - if (id->id_length <= id->id_offset) - return (-1); - idlen = id->id_length - id->id_offset; - idptr = id->id_data + id->id_offset; - if ((idname = d2i_X509_NAME(NULL, &idptr, idlen)) == NULL) - return (-1); - if (X509_NAME_cmp(subject, idname) == 0) - ret = 0; - X509_NAME_free(idname); - return (ret); -} - int ca_x509_subjectaltname_cmp(X509 *cert, struct iked_static_id *id) { @@ -1271,7 +1036,7 @@ int ca_x509_subjectaltname(X509 *cert, struct iked_id *id) { X509_EXTENSION *san; - uint8_t sanhdr[4], *data; + u_int8_t sanhdr[4], *data; int ext, santype, sanlen; char idstr[IKED_ID_SIZE]; @@ -1291,7 +1056,7 @@ ca_x509_subjectaltname(X509 *cert, struct iked_id *id) } /* This is partially based on isakmpd's x509 subjectaltname code */ - data = (uint8_t *)san->value->data; + data = (u_int8_t *)san->value->data; memcpy(&sanhdr, data, sizeof(sanhdr)); santype = sanhdr[2] & 0x3f; sanlen = sanhdr[3]; @@ -1347,14 +1112,16 @@ ca_sslinit(void) /* Init hardware crypto engines. */ ENGINE_load_builtin_engines(); ENGINE_register_all_complete(); + + seed_rng(); } void -ca_sslerror(const char *caller) +ca_sslerror(void) { - unsigned long error; + u_long error; while ((error = ERR_get_error()) != 0) - log_warn("%s: %s: %.100s", __func__, caller, + log_warn("%s: %.100s", __func__, ERR_error_string(error, NULL)); } diff --git a/iked/chap_ms.c b/iked/chap_ms.c index 1e03f1d..dfaff2f 100644 --- a/iked/chap_ms.c +++ b/iked/chap_ms.c @@ -1,4 +1,4 @@ -/* $OpenBSD: chap_ms.c,v 1.9 2015/08/21 11:59:27 reyk Exp $ */ +/* $OpenBSD: chap_ms.c,v 1.6 2013/01/08 10:38:19 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -56,32 +56,32 @@ * "It is unclear to us why this protocol is so complicated." */ -static uint8_t sha1_pad1[40] = { +static u_int8_t sha1_pad1[40] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static uint8_t sha1_pad2[40] = { +static u_int8_t sha1_pad2[40] = { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 }; -uint8_t get7bits(uint8_t *, int); -void mschap_des_addparity(uint8_t *, uint8_t *); -void mschap_des_encrypt(uint8_t *, uint8_t *, uint8_t *); -void mschap_challenge_response(uint8_t *, uint8_t *, uint8_t *); +u_int8_t get7bits(u_int8_t *, int); +void mschap_des_addparity(u_int8_t *, u_int8_t *); +void mschap_des_encrypt(u_int8_t *, u_int8_t *, u_int8_t *); +void mschap_challenge_response(u_int8_t *, u_int8_t *, u_int8_t *); -uint8_t -get7bits(uint8_t *in, int start) +u_int8_t +get7bits(u_int8_t *in, int start) { - unsigned int word; + u_int word; - word = (unsigned int)in[start / 8] << 8; - word |= (unsigned int)in[start / 8 + 1]; + word = (u_int)in[start / 8] << 8; + word |= (u_int)in[start / 8 + 1]; word >>= 15 - (start % 8 + 7); return (word & 0xfe); @@ -90,7 +90,7 @@ get7bits(uint8_t *in, int start) /* IN 56 bit DES key missing parity bits OUT 64 bit DES key with parity bits added */ void -mschap_des_addparity(uint8_t *key, uint8_t *des_key) +mschap_des_addparity(u_int8_t *key, u_int8_t *des_key) { des_key[0] = get7bits(key, 0); des_key[1] = get7bits(key, 7); @@ -105,7 +105,7 @@ mschap_des_addparity(uint8_t *key, uint8_t *des_key) } void -mschap_des_encrypt(uint8_t *clear, uint8_t *key, uint8_t *cipher) +mschap_des_encrypt(u_int8_t *clear, u_int8_t *key, u_int8_t *cipher) { DES_cblock des_key; DES_key_schedule key_schedule; @@ -118,10 +118,10 @@ mschap_des_encrypt(uint8_t *clear, uint8_t *key, uint8_t *cipher) } void -mschap_challenge_response(uint8_t *challenge, uint8_t *pwhash, - uint8_t *response) +mschap_challenge_response(u_int8_t *challenge, u_int8_t *pwhash, + u_int8_t *response) { - uint8_t padpwhash[21 + 1]; + u_int8_t padpwhash[21 + 1]; bzero(&padpwhash, sizeof(padpwhash)); memcpy(padpwhash, pwhash, MSCHAP_HASH_SZ); @@ -132,10 +132,10 @@ mschap_challenge_response(uint8_t *challenge, uint8_t *pwhash, } void -mschap_ntpassword_hash(uint8_t *in, int inlen, uint8_t *hash) +mschap_ntpassword_hash(u_int8_t *in, int inlen, u_int8_t *hash) { EVP_MD_CTX ctx; - unsigned int mdlen; + u_int mdlen; EVP_DigestInit(&ctx, EVP_md4()); EVP_DigestUpdate(&ctx, in, inlen); @@ -143,13 +143,13 @@ mschap_ntpassword_hash(uint8_t *in, int inlen, uint8_t *hash) } void -mschap_challenge_hash(uint8_t *peer_challenge, uint8_t *auth_challenge, - uint8_t *username, int usernamelen, uint8_t *challenge) +mschap_challenge_hash(u_int8_t *peer_challenge, u_int8_t *auth_challenge, + u_int8_t *username, int usernamelen, u_int8_t *challenge) { EVP_MD_CTX ctx; - uint8_t md[SHA_DIGEST_LENGTH]; - unsigned int mdlen; - uint8_t *name; + u_int8_t md[SHA_DIGEST_LENGTH]; + u_int mdlen; + u_int8_t *name; if ((name = strrchr(username, '\\')) == NULL) name = username; @@ -166,12 +166,12 @@ mschap_challenge_hash(uint8_t *peer_challenge, uint8_t *auth_challenge, } void -mschap_nt_response(uint8_t *auth_challenge, uint8_t *peer_challenge, - uint8_t *username, int usernamelen, uint8_t *password, int passwordlen, - uint8_t *response) +mschap_nt_response(u_int8_t *auth_challenge, u_int8_t *peer_challenge, + u_int8_t *username, int usernamelen, u_int8_t *password, int passwordlen, + u_int8_t *response) { - uint8_t challenge[MSCHAP_CHALLENGE_SZ]; - uint8_t password_hash[MSCHAP_HASH_SZ]; + u_int8_t challenge[MSCHAP_CHALLENGE_SZ]; + u_int8_t password_hash[MSCHAP_HASH_SZ]; mschap_challenge_hash(peer_challenge, auth_challenge, username, usernamelen, challenge); @@ -181,25 +181,25 @@ mschap_nt_response(uint8_t *auth_challenge, uint8_t *peer_challenge, } void -mschap_auth_response(uint8_t *password, int passwordlen, - uint8_t *ntresponse, uint8_t *auth_challenge, uint8_t *peer_challenge, - uint8_t *username, int usernamelen, uint8_t *auth_response) +mschap_auth_response(u_int8_t *password, int passwordlen, + u_int8_t *ntresponse, u_int8_t *auth_challenge, u_int8_t *peer_challenge, + u_int8_t *username, int usernamelen, u_int8_t *auth_response) { EVP_MD_CTX ctx; - uint8_t password_hash[MSCHAP_HASH_SZ]; - uint8_t password_hash2[MSCHAP_HASH_SZ]; - uint8_t challenge[MSCHAP_CHALLENGE_SZ]; - uint8_t md[SHA_DIGEST_LENGTH], *ptr; - unsigned int mdlen; + u_int8_t password_hash[MSCHAP_HASH_SZ]; + u_int8_t password_hash2[MSCHAP_HASH_SZ]; + u_int8_t challenge[MSCHAP_CHALLENGE_SZ]; + u_int8_t md[SHA_DIGEST_LENGTH], *ptr; + u_int mdlen; int i; - const uint8_t hex[] = "0123456789ABCDEF"; - static uint8_t magic1[39] = { + const u_int8_t hex[] = "0123456789ABCDEF"; + static u_int8_t magic1[39] = { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 }; - static uint8_t magic2[41] = { + static u_int8_t magic2[41] = { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, @@ -242,13 +242,13 @@ mschap_auth_response(uint8_t *password, int passwordlen, } void -mschap_masterkey(uint8_t *password_hash2, uint8_t *ntresponse, - uint8_t *masterkey) +mschap_masterkey(u_int8_t *password_hash2, u_int8_t *ntresponse, + u_int8_t *masterkey) { - uint8_t md[SHA_DIGEST_LENGTH]; - unsigned int mdlen; + u_int8_t md[SHA_DIGEST_LENGTH]; + u_int mdlen; EVP_MD_CTX ctx; - static uint8_t magic1[27] = { + static u_int8_t magic1[27] = { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 @@ -264,14 +264,14 @@ mschap_masterkey(uint8_t *password_hash2, uint8_t *ntresponse, } void -mschap_asymetric_startkey(uint8_t *masterkey, uint8_t *sessionkey, +mschap_asymetric_startkey(u_int8_t *masterkey, u_int8_t *sessionkey, int sessionkeylen, int issend, int isserver) { EVP_MD_CTX ctx; - uint8_t md[SHA_DIGEST_LENGTH]; - unsigned int mdlen; - uint8_t *s; - static uint8_t magic2[84] = { + u_int8_t md[SHA_DIGEST_LENGTH]; + u_int mdlen; + u_int8_t *s; + static u_int8_t magic2[84] = { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, @@ -282,7 +282,7 @@ mschap_asymetric_startkey(uint8_t *masterkey, uint8_t *sessionkey, 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x2e }; - static uint8_t magic3[84] = { + static u_int8_t magic3[84] = { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, @@ -310,14 +310,14 @@ mschap_asymetric_startkey(uint8_t *masterkey, uint8_t *sessionkey, } void -mschap_msk(uint8_t *password, int passwordlen, - uint8_t *ntresponse, uint8_t *msk) +mschap_msk(u_int8_t *password, int passwordlen, + u_int8_t *ntresponse, u_int8_t *msk) { - uint8_t password_hash[MSCHAP_HASH_SZ]; - uint8_t password_hash2[MSCHAP_HASH_SZ]; - uint8_t masterkey[MSCHAP_MASTERKEY_SZ]; - uint8_t sendkey[MSCHAP_MASTERKEY_SZ]; - uint8_t recvkey[MSCHAP_MASTERKEY_SZ]; + u_int8_t password_hash[MSCHAP_HASH_SZ]; + u_int8_t password_hash2[MSCHAP_HASH_SZ]; + u_int8_t masterkey[MSCHAP_MASTERKEY_SZ]; + u_int8_t sendkey[MSCHAP_MASTERKEY_SZ]; + u_int8_t recvkey[MSCHAP_MASTERKEY_SZ]; mschap_ntpassword_hash(password, passwordlen, password_hash); mschap_ntpassword_hash(password_hash, MSCHAP_HASH_SZ, password_hash2); @@ -333,12 +333,58 @@ mschap_msk(uint8_t *password, int passwordlen, } void -mschap_radiuskey(uint8_t *plain, const uint8_t *crypted, - const uint8_t *authenticator, const uint8_t *secret) +mschap_newkey(u_int8_t *startkey, u_int8_t *sessionkey, + long sessionkeylen, u_int8_t *key) { EVP_MD_CTX ctx; - uint8_t b[MD5_DIGEST_LENGTH], p[32]; - unsigned int i, mdlen; + u_int8_t md[SHA_DIGEST_LENGTH]; + u_int mdlen; + + EVP_DigestInit(&ctx, EVP_sha1()); + EVP_DigestUpdate(&ctx, startkey, sessionkeylen); + EVP_DigestUpdate(&ctx, sha1_pad1, sizeof(sha1_pad1)); + EVP_DigestUpdate(&ctx, sessionkey, sessionkeylen); + EVP_DigestUpdate(&ctx, sha1_pad2, sizeof(sha1_pad2)); + EVP_DigestFinal(&ctx, md, &mdlen); + + memcpy(key, md, sessionkeylen); +} + +void +mschap_nt(u_int8_t *password_hash, u_int8_t *challenge) +{ + u_int8_t response[24]; + + mschap_challenge_response(challenge, password_hash, response); + memcpy(password_hash, response, sizeof(response)); + password_hash[24] = 1; /* NT-style response */ +} + +void +mschap_lanman(u_int8_t *digest, u_int8_t *challenge, u_int8_t *secret) +{ + static u_int8_t salt[] = "KGS!@#$%"; /* RASAPI32.dll */ + u_int8_t SECRET[14 + 1], *ptr, *end; + u_int8_t hash[MSCHAP_HASH_SZ]; + + bzero(&SECRET, sizeof(SECRET)); + end = SECRET + (sizeof(SECRET) - 1); + for (ptr = SECRET; *secret && ptr < end; ptr++, secret++) + *ptr = toupper(*secret); + + mschap_des_encrypt(salt, SECRET, hash); + mschap_des_encrypt(salt, SECRET + 7, hash + 8); + + mschap_challenge_response(challenge, hash, digest); +} + +void +mschap_radiuskey(u_int8_t *plain, const u_int8_t *crypted, + const u_int8_t *authenticator, const u_int8_t *secret) +{ + EVP_MD_CTX ctx; + u_int8_t b[MD5_DIGEST_LENGTH], p[32]; + u_int i, mdlen; EVP_DigestInit(&ctx, EVP_md5()); EVP_DigestUpdate(&ctx, secret, strlen(secret)); diff --git a/iked/chap_ms.h b/iked/chap_ms.h index 53b3adb..f06940c 100644 --- a/iked/chap_ms.h +++ b/iked/chap_ms.h @@ -1,4 +1,4 @@ -/* $OpenBSD: chap_ms.h,v 1.6 2015/08/21 11:59:27 reyk Exp $ */ +/* $OpenBSD: chap_ms.h,v 1.3 2013/01/08 10:38:19 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef CHAP_MS_H -#define CHAP_MS_H +#ifndef _CHAP_MS_H +#define _CHAP_MS_H #define MSCHAP_CHALLENGE_SZ 8 #define MSCHAPV2_CHALLENGE_SZ 16 @@ -29,19 +29,23 @@ #define MSCHAP_MAXNTPASSWORD_SZ 255 /* unicode chars */ -void mschap_nt_response(uint8_t *, uint8_t *, uint8_t *, int, - uint8_t *, int , uint8_t *); -void mschap_auth_response(uint8_t *, int, uint8_t *, uint8_t *, - uint8_t *, uint8_t *, int, uint8_t *); +void mschap_nt_response(u_int8_t *, u_int8_t *, u_int8_t *, int, + u_int8_t *, int , u_int8_t *); +void mschap_auth_response(u_int8_t *, int, u_int8_t *, u_int8_t *, + u_int8_t *, u_int8_t *, int, u_int8_t *); -void mschap_ntpassword_hash(uint8_t *, int, uint8_t *); -void mschap_challenge_hash(uint8_t *, uint8_t *, uint8_t *, - int, uint8_t *); +void mschap_nt(u_int8_t *, u_int8_t *); +void mschap_lanman(u_int8_t *, u_int8_t *, u_int8_t *); -void mschap_asymetric_startkey(uint8_t *, uint8_t *, int, int, int); -void mschap_masterkey(uint8_t *, uint8_t *, uint8_t *); -void mschap_radiuskey(uint8_t *, const uint8_t *, const uint8_t *, - const uint8_t *); -void mschap_msk(uint8_t *, int, uint8_t *, uint8_t *); +void mschap_ntpassword_hash(u_int8_t *, int, u_int8_t *); +void mschap_challenge_hash(u_int8_t *, u_int8_t *, u_int8_t *, + int, u_int8_t *); -#endif /* CHAP_MS_H */ +void mschap_asymetric_startkey(u_int8_t *, u_int8_t *, int, int, int); +void mschap_masterkey(u_int8_t *, u_int8_t *, u_int8_t *); +void mschap_newkey(u_int8_t *, u_int8_t *, long, u_int8_t *); +void mschap_radiuskey(u_int8_t *, const u_int8_t *, const u_int8_t *, + const u_int8_t *); +void mschap_msk(u_int8_t *, int, u_int8_t *, u_int8_t *); + +#endif /* _CHAP_MS_H */ diff --git a/iked/config.c b/iked/config.c index b0d395c..397191d 100644 --- a/iked/config.c +++ b/iked/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.37 2015/08/21 11:59:27 reyk Exp $ */ +/* $OpenBSD: config.c,v 1.20 2013/03/21 04:30:14 deraadt Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,15 +16,24 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +#include +#include "openbsd-compat/sys-queue.h" #include #include #include +#include +#include +#include +#include +#include +#include + #include #include #include #include +#include #include #include #include @@ -61,52 +70,31 @@ config_new_sa(struct iked *env, int initiator) return (sa); } -uint64_t +u_int64_t config_getspi(void) { - uint64_t spi; + u_int64_t spi; - do { - arc4random_buf(&spi, sizeof spi); - } while (spi == 0); + spi = ((u_int64_t)arc4random() << 32) | arc4random(); + if (spi == 0) + return (config_getspi()); return (spi); } -void -config_free_kex(struct iked_kex *kex) -{ - if (kex == NULL) - return; - - ibuf_release(kex->kex_inonce); - ibuf_release(kex->kex_rnonce); - - if (kex->kex_dhgroup != NULL) - group_free(kex->kex_dhgroup); - ibuf_release(kex->kex_dhiexchange); - ibuf_release(kex->kex_dhrexchange); - - free(kex); -} - void config_free_sa(struct iked *env, struct iked_sa *sa) { - timer_del(env, &sa->sa_timer); - timer_del(env, &sa->sa_rekey); + (void)RB_REMOVE(iked_sas, &env->sc_sas, sa); + + timer_deregister(env, &sa->sa_timer); config_free_proposals(&sa->sa_proposals, 0); config_free_childsas(env, &sa->sa_childsas, NULL, NULL); sa_free_flows(env, &sa->sa_flows); - if (sa->sa_addrpool) { - (void)RB_REMOVE(iked_addrpool, &env->sc_addrpool, sa); - free(sa->sa_addrpool); - } - if (sa->sa_policy) { - TAILQ_REMOVE(&sa->sa_policy->pol_sapeers, sa, sa_peer_entry); + (void)RB_REMOVE(iked_sapeers, &sa->sa_policy->pol_sapeers, sa); policy_unref(env, sa->sa_policy); } @@ -157,10 +145,8 @@ config_new_policy(struct iked *env) if ((pol = calloc(1, sizeof(*pol))) == NULL) return (NULL); - /* XXX caller does this again */ TAILQ_INIT(&pol->pol_proposals); - TAILQ_INIT(&pol->pol_sapeers); - RB_INIT(&pol->pol_flows); + RB_INIT(&pol->pol_sapeers); return (pol); } @@ -175,13 +161,10 @@ config_free_policy(struct iked *env, struct iked_policy *pol) TAILQ_REMOVE(&env->sc_policies, pol, pol_entry); - TAILQ_FOREACH(sa, &pol->pol_sapeers, sa_peer_entry) { - /* Remove from the policy list, but keep for existing SAs */ + RB_FOREACH(sa, iked_sapeers, &pol->pol_sapeers) { + /* Remove from the policy tree, but keep for existing SAs */ if (sa->sa_policy == pol) policy_ref(env, pol); - else - log_warnx("%s: ERROR: sa_policy %p != pol %p", - __func__, sa->sa_policy, pol); } if (pol->pol_refcnt) @@ -194,8 +177,7 @@ config_free_policy(struct iked *env, struct iked_policy *pol) } struct iked_proposal * -config_add_proposal(struct iked_proposals *head, unsigned int id, - unsigned int proto) +config_add_proposal(struct iked_proposals *head, u_int id, u_int proto) { struct iked_proposal *pp; @@ -217,7 +199,7 @@ config_add_proposal(struct iked_proposals *head, unsigned int id, } void -config_free_proposals(struct iked_proposals *head, unsigned int proto) +config_free_proposals(struct iked_proposals *head, u_int proto) { struct iked_proposal *prop, *next; @@ -284,13 +266,13 @@ config_free_childsas(struct iked *env, struct iked_childsas *head, } struct iked_transform * -config_add_transform(struct iked_proposal *prop, unsigned int type, - unsigned int id, unsigned int length, unsigned int keylength) +config_add_transform(struct iked_proposal *prop, u_int type, + u_int id, u_int length, u_int keylength) { struct iked_transform *xform; struct iked_constmap *map = NULL; int score = 1; - unsigned int i; + u_int i; switch (type) { case IKEV2_XFORMTYPE_ENCR: @@ -339,8 +321,8 @@ config_add_transform(struct iked_proposal *prop, unsigned int type, } } - if ((xform = reallocarray(prop->prop_xforms, - prop->prop_nxforms + 1, sizeof(*xform))) == NULL) { + if ((xform = realloc(prop->prop_xforms, + (prop->prop_nxforms + 1) * sizeof(*xform))) == NULL) { return (NULL); } @@ -359,18 +341,14 @@ config_add_transform(struct iked_proposal *prop, unsigned int type, } struct iked_transform * -config_findtransform(struct iked_proposals *props, uint8_t type, - unsigned int proto) +config_findtransform(struct iked_proposals *props, u_int8_t type) { struct iked_proposal *prop; struct iked_transform *xform; - unsigned int i; + u_int i; /* Search of the first transform with the desired type */ TAILQ_FOREACH(prop, props, prop_entry) { - /* Find any proposal or only selected SA proto */ - if (proto != 0 && prop->prop_protoid != proto) - continue; for (i = 0; i < prop->prop_nxforms; i++) { xform = prop->prop_xforms + i; if (xform->xform_type == type) @@ -410,41 +388,41 @@ config_new_user(struct iked *env, struct iked_user *new) */ int -config_setcoupled(struct iked *env, unsigned int couple) +config_setcoupled(struct iked *env, u_int couple) { - unsigned int type; + u_int type; type = couple ? IMSG_CTL_COUPLE : IMSG_CTL_DECOUPLE; - proc_compose_imsg(&env->sc_ps, PROC_IKEV1, -1, type, -1, NULL, 0); - proc_compose_imsg(&env->sc_ps, PROC_IKEV2, -1, type, -1, NULL, 0); + proc_compose_imsg(env, PROC_IKEV1, type, -1, NULL, 0); + proc_compose_imsg(env, PROC_IKEV2, type, -1, NULL, 0); return (0); } int -config_getcoupled(struct iked *env, unsigned int type) +config_getcoupled(struct iked *env, u_int type) { return (pfkey_couple(env->sc_pfkey, &env->sc_sas, type == IMSG_CTL_COUPLE ? 1 : 0)); } int -config_setmode(struct iked *env, unsigned int passive) +config_setmode(struct iked *env, u_int passive) { - unsigned int type; + u_int type; type = passive ? IMSG_CTL_PASSIVE : IMSG_CTL_ACTIVE; - proc_compose_imsg(&env->sc_ps, PROC_IKEV1, -1, type, -1, NULL, 0); - proc_compose_imsg(&env->sc_ps, PROC_IKEV2, -1, type, -1, NULL, 0); + proc_compose_imsg(env, PROC_IKEV1, type, -1, NULL, 0); + proc_compose_imsg(env, PROC_IKEV2, type, -1, NULL, 0); return (0); } int -config_getmode(struct iked *env, unsigned int type) +config_getmode(struct iked *env, u_int type) { - uint8_t old; - unsigned char *mode[] = { "active", "passive" }; + u_int8_t old; + u_char *mode[] = { "active", "passive" }; old = env->sc_passive ? 1 : 0; env->sc_passive = type == IMSG_CTL_PASSIVE ? 1 : 0; @@ -459,10 +437,9 @@ config_getmode(struct iked *env, unsigned int type) } int -config_setreset(struct iked *env, unsigned int mode, enum privsep_procid id) +config_setreset(struct iked *env, u_int mode, enum privsep_procid id) { - proc_compose_imsg(&env->sc_ps, id, -1, - IMSG_CTL_RESET, -1, &mode, sizeof(mode)); + proc_compose_imsg(env, id, IMSG_CTL_RESET, -1, &mode, sizeof(mode)); return (0); } @@ -472,7 +449,7 @@ config_getreset(struct iked *env, struct imsg *imsg) struct iked_policy *pol, *nextpol; struct iked_sa *sa, *nextsa; struct iked_user *usr, *nextusr; - unsigned int mode; + u_int mode; IMSG_SIZE_CHECK(imsg, &mode); memcpy(&mode, imsg->data, sizeof(mode)); @@ -491,7 +468,6 @@ config_getreset(struct iked *env, struct imsg *imsg) for (sa = RB_MIN(iked_sas, &env->sc_sas); sa != NULL; sa = nextsa) { nextsa = RB_NEXT(iked_sas, &env->sc_sas, sa); - RB_REMOVE(iked_sas, &env->sc_sas, sa); config_free_sa(env, sa); } } @@ -517,8 +493,8 @@ config_setsocket(struct iked *env, struct sockaddr_storage *ss, if ((s = udp_bind((struct sockaddr *)ss, port)) == -1) return (-1); - proc_compose_imsg(&env->sc_ps, id, -1, - IMSG_UDP_SOCKET, s, ss, sizeof(*ss)); + proc_compose_imsg(env, id, IMSG_UDP_SOCKET, s, + ss, sizeof(*ss)); return (0); } @@ -555,8 +531,7 @@ config_getsocket(struct iked *env, struct imsg *imsg, if (*sptr == NULL) *sptr = sock; if (*nptr == NULL && - socket_getport((struct sockaddr *)&sock->sock_addr) == - IKED_NATT_PORT) + socket_getport(&sock->sock_addr) == IKED_NATT_PORT) *nptr = sock; event_set(&sock->sock_ev, sock->sock_fd, @@ -573,8 +548,7 @@ config_setpfkey(struct iked *env, enum privsep_procid id) if ((s = pfkey_socket()) == -1) return (-1); - proc_compose_imsg(&env->sc_ps, id, -1, - IMSG_PFKEY_SOCKET, s, NULL, 0); + proc_compose_imsg(env, id, IMSG_PFKEY_SOCKET, s, NULL, 0); return (0); } @@ -594,8 +568,7 @@ config_setuser(struct iked *env, struct iked_user *usr, enum privsep_procid id) return (0); } - proc_compose_imsg(&env->sc_ps, id, -1, - IMSG_CFG_USER, -1, usr, sizeof(*usr)); + proc_compose_imsg(env, id, IMSG_CFG_USER, -1, usr, sizeof(*usr)); return (0); } @@ -665,8 +638,8 @@ config_setpolicy(struct iked *env, struct iked_policy *pol, return (0); } - if (proc_composev_imsg(&env->sc_ps, id, -1, - IMSG_CFG_POLICY, -1, iov, iovcnt) == -1) + if (proc_composev_imsg(env, id, IMSG_CFG_POLICY, -1, + iov, iovcnt) == -1) return (-1); return (0); @@ -680,8 +653,8 @@ config_getpolicy(struct iked *env, struct imsg *imsg) struct iked_transform xf, *xform; struct iked_flow *flow; off_t offset = 0; - unsigned int i, j; - uint8_t *buf = (uint8_t *)imsg->data; + u_int i, j; + u_int8_t *buf = (u_int8_t *)imsg->data; IMSG_SIZE_CHECK(imsg, pol); log_debug("%s: received policy", __func__); @@ -693,7 +666,6 @@ config_getpolicy(struct iked *env, struct imsg *imsg) offset += sizeof(*pol); TAILQ_INIT(&pol->pol_proposals); - TAILQ_INIT(&pol->pol_sapeers); RB_INIT(&pol->pol_flows); for (i = 0; i < pol->pol_nproposals; i++) { @@ -722,8 +694,7 @@ config_getpolicy(struct iked *env, struct imsg *imsg) memcpy(flow, buf + offset, sizeof(*flow)); offset += sizeof(*flow); - if (RB_INSERT(iked_flows, &pol->pol_flows, flow)) - free(flow); + RB_INSERT(iked_flows, &pol->pol_flows, flow); } TAILQ_INSERT_TAIL(&env->sc_policies, pol, pol_entry); @@ -746,8 +717,7 @@ config_setcompile(struct iked *env, enum privsep_procid id) if (env->sc_opts & IKED_OPT_NOACTION) return (0); - proc_compose_imsg(&env->sc_ps, id, -1, - IMSG_COMPILE, -1, NULL, 0); + proc_compose_imsg(env, id, IMSG_COMPILE, -1, NULL, 0); return (0); } @@ -763,29 +733,3 @@ config_getcompile(struct iked *env, struct imsg *imsg) log_debug("%s: compilation done", __func__); return (0); } - -int -config_setocsp(struct iked *env) -{ - if (env->sc_opts & IKED_OPT_NOACTION) - return (0); - proc_compose_imsg(&env->sc_ps, PROC_CERT, -1, - IMSG_OCSP_URL, -1, env->sc_ocsp_url, - env->sc_ocsp_url ? strlen(env->sc_ocsp_url) : 0); - - return (0); -} - -int -config_getocsp(struct iked *env, struct imsg *imsg) -{ - if (env->sc_ocsp_url) - free(env->sc_ocsp_url); - if (IMSG_DATA_SIZE(imsg) > 0) - env->sc_ocsp_url = get_string(imsg->data, IMSG_DATA_SIZE(imsg)); - else - env->sc_ocsp_url = NULL; - log_debug("%s: ocsp_url %s", __func__, - env->sc_ocsp_url ? env->sc_ocsp_url : "none"); - return (0); -} diff --git a/iked/control.c b/iked/control.c index 3932008..dfa48b3 100644 --- a/iked/control.c +++ b/iked/control.c @@ -1,4 +1,4 @@ -/* $OpenBSD: control.c,v 1.16 2015/01/16 06:39:58 deraadt Exp $ */ +/* $OpenBSD: control.c,v 1.12 2013/03/21 04:30:14 deraadt Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -17,11 +17,12 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +#include "openbsd-compat/sys-queue.h" +#include #include #include #include -#include +#include "openbsd-compat/sys-tree.h" #include @@ -240,17 +241,22 @@ control_dispatch_imsg(int fd, short event, void *arg) return; } - if (event & EV_READ) { + switch (event) { + case EV_READ: if ((n = imsg_read(&c->iev.ibuf)) == -1 || n == 0) { control_close(fd, cs); return; } - } - if (event & EV_WRITE) { - if (msgbuf_write(&c->iev.ibuf.w) <= 0 && errno != EAGAIN) { + break; + case EV_WRITE: + if (msgbuf_write(&c->iev.ibuf.w) < 0) { control_close(fd, cs); return; } + imsg_event_add(&c->iev); + return; + default: + fatalx("unknown event"); } for (;;) { @@ -282,9 +288,9 @@ control_dispatch_imsg(int fd, short event, void *arg) memcpy(&v, imsg.data, sizeof(v)); log_verbose(v); - proc_forward_imsg(&env->sc_ps, &imsg, PROC_PARENT, -1); - proc_forward_imsg(&env->sc_ps, &imsg, PROC_IKEV2, -1); - proc_forward_imsg(&env->sc_ps, &imsg, PROC_IKEV1, -1); + proc_forward_imsg(env, &imsg, PROC_PARENT); + proc_forward_imsg(env, &imsg, PROC_IKEV2); + proc_forward_imsg(env, &imsg, PROC_IKEV1); break; case IMSG_CTL_RELOAD: case IMSG_CTL_RESET: @@ -292,7 +298,7 @@ control_dispatch_imsg(int fd, short event, void *arg) case IMSG_CTL_DECOUPLE: case IMSG_CTL_ACTIVE: case IMSG_CTL_PASSIVE: - proc_forward_imsg(&env->sc_ps, &imsg, PROC_PARENT, -1); + proc_forward_imsg(env, &imsg, PROC_PARENT); break; default: log_debug("%s: error handling imsg %d", diff --git a/iked/crypto.c b/iked/crypto.c index c956e79..6959c37 100644 --- a/iked/crypto.c +++ b/iked/crypto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: crypto.c,v 1.18 2015/08/21 11:59:27 reyk Exp $ */ +/* $OpenBSD: crypto.c,v 1.9 2013/01/08 10:38:19 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include /* roundup */ -#include +#include +#include "openbsd-compat/sys-queue.h" #include #include @@ -34,44 +34,12 @@ #include #include #include -#include #include "iked.h" #include "ikev2.h" -/* RFC 7427, A.1 */ -static const uint8_t sha256WithRSAEncryption[] = { - 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, - 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00 -}; -static const uint8_t sha384WithRSAEncryption[] = { - 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, - 0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00 -}; -static const uint8_t sha512WithRSAEncryption[] = { - 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, - 0xf7, 0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00 -}; - -struct { - uint8_t sc_len; - const uint8_t *sc_oid; - const EVP_MD *(*sc_md)(void); -} schemes[] = { - { sizeof(sha256WithRSAEncryption), - sha256WithRSAEncryption, EVP_sha256 }, - { sizeof(sha384WithRSAEncryption), - sha384WithRSAEncryption, EVP_sha384 }, - { sizeof(sha512WithRSAEncryption), - sha512WithRSAEncryption, EVP_sha512 }, -}; - -int _dsa_verify_init(struct iked_dsa *, const uint8_t *, size_t); -size_t _dsa_verify_offset(struct iked_dsa *, uint8_t *); -int _dsa_sign_encode(struct iked_dsa *, uint8_t *, size_t *); - struct iked_hash * -hash_new(uint8_t type, uint16_t id) +hash_new(u_int8_t type, u_int16_t id) { struct iked_hash *hash; const EVP_MD *md = NULL; @@ -229,7 +197,7 @@ hash_update(struct iked_hash *hash, void *buf, size_t len) void hash_final(struct iked_hash *hash, void *buf, size_t *len) { - unsigned int length = 0; + u_int length = 0; HMAC_Final(hash->hash_ctx, buf, &length); *len = (size_t)length; @@ -254,7 +222,7 @@ hash_keylength(struct iked_hash *hash) } struct iked_cipher * -cipher_new(uint8_t type, uint16_t id, uint16_t id_length) +cipher_new(u_int8_t type, u_int16_t id, u_int16_t id_length) { struct iked_cipher *encr; const EVP_CIPHER *cipher = NULL; @@ -360,7 +328,7 @@ cipher_setiv(struct iked_cipher *encr, void *iv, size_t len) ibuf_release(encr->encr_iv); if (iv != NULL) { if (len < encr->encr_ivlength) { - log_debug("%s: invalid IV length %zu", __func__, len); + log_debug("%s: invalid IV length %d", __func__, len); return (NULL); } encr->encr_iv = ibuf_new(iv, encr->encr_ivlength); @@ -416,7 +384,7 @@ cipher_update(struct iked_cipher *encr, void *in, size_t inlen, olen = 0; if (!EVP_CipherUpdate(encr->encr_ctx, out, &olen, in, inlen)) { - ca_sslerror(__func__); + ca_sslerror(); *outlen = 0; return; } @@ -430,7 +398,7 @@ cipher_final(struct iked_cipher *encr, void *out, size_t *outlen) olen = 0; if (!EVP_CipherFinal_ex(encr->encr_ctx, out, &olen)) { - ca_sslerror(__func__); + ca_sslerror(); *outlen = 0; return; } @@ -466,22 +434,23 @@ cipher_outlength(struct iked_cipher *encr, size_t inlen) } struct iked_dsa * -dsa_new(uint16_t id, struct iked_hash *prf, int sign) +dsa_new(u_int16_t id, struct iked_hash *prf, int sign) { struct iked_dsa *dsap = NULL, dsa; bzero(&dsa, sizeof(dsa)); switch (id) { - case IKEV2_AUTH_SIG: - if (sign) - dsa.dsa_priv = EVP_sha256(); /* XXX should be passed */ - else - dsa.dsa_priv = NULL; /* set later by dsa_init() */ - break; case IKEV2_AUTH_RSA_SIG: - /* RFC5996 says we SHOULD use SHA1 here */ - dsa.dsa_priv = EVP_sha1(); + /* + * XXX RFC4306 is not very clear about this and the + * XXX informational RFC4718 says that we should use + * XXX SHA1 here, but shouldn't we use the negotiated PRF + * XXX alg instead? + */ + if ((dsa.dsa_priv = + EVP_get_digestbyname("sha1WithRSAEncryption")) == NULL) + fatalx("dsa_new: cipher not available"); break; case IKEV2_AUTH_SHARED_KEY_MIC: if (prf == NULL || prf->hash_priv == NULL) @@ -536,13 +505,13 @@ dsa_new(uint16_t id, struct iked_hash *prf, int sign) } struct iked_dsa * -dsa_sign_new(uint16_t id, struct iked_hash *prf) +dsa_sign_new(u_int16_t id, struct iked_hash *prf) { return (dsa_new(id, prf, 1)); } struct iked_dsa * -dsa_verify_new(uint16_t id, struct iked_hash *prf) +dsa_verify_new(u_int16_t id, struct iked_hash *prf) { return (dsa_new(id, prf, 0)); } @@ -568,7 +537,7 @@ dsa_free(struct iked_dsa *dsa) } struct ibuf * -dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, uint8_t type) +dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, u_int8_t type) { BIO *rawcert = NULL; X509 *cert = NULL; @@ -609,7 +578,6 @@ dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, uint8_t type) if (!EVP_PKEY_set1_RSA(pkey, rsa)) goto sslerr; - RSA_free(rsa); /* pkey now has the reference */ dsa->dsa_cert = NULL; dsa->dsa_key = pkey; break; @@ -623,7 +591,7 @@ dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, uint8_t type) return (dsa->dsa_keydata); sslerr: - ca_sslerror(__func__); + ca_sslerror(); err: log_debug("%s: error", __func__); @@ -640,53 +608,7 @@ dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, uint8_t type) } int -_dsa_verify_init(struct iked_dsa *dsa, const uint8_t *sig, size_t len) -{ - uint8_t oidlen; - size_t i; - - if (dsa->dsa_priv != NULL) - return (0); - /* - * For IKEV2_AUTH_SIG the oid of the authentication signature - * is encoded in the first bytes of the auth message. - */ - if (dsa->dsa_method != IKEV2_AUTH_SIG) { - log_debug("%s: dsa_priv not set for %s", __func__, - print_map(dsa->dsa_method, ikev2_auth_map)); - return (-1); - } - if (sig == NULL) { - log_debug("%s: signature missing", __func__); - return (-1); - } - if (len < 1) { - log_debug("%s: signature (%zu) too small for oid length", - __func__, len); - return (-1); - } - memcpy(&oidlen, sig, sizeof(oidlen)); - if (len < (size_t)oidlen + 1) { - log_debug("%s: signature (%zu) too small for oid (%u)", - __func__, len, oidlen); - return (-1); - } - for (i = 0; i < nitems(schemes); i++) { - if (oidlen == schemes[i].sc_len && - memcmp(sig + 1, schemes[i].sc_oid, - schemes[i].sc_len) == 0) { - dsa->dsa_priv = (*schemes[i].sc_md)(); - log_debug("%s: signature scheme %zd selected", - __func__, i); - return (0); - } - } - log_debug("%s: unsupported signature (%d)", __func__, oidlen); - return (-1); -} - -int -dsa_init(struct iked_dsa *dsa, const void *buf, size_t len) +dsa_init(struct iked_dsa *dsa) { int ret; @@ -699,11 +621,8 @@ dsa_init(struct iked_dsa *dsa, const void *buf, size_t len) if (dsa->dsa_sign) ret = EVP_SignInit_ex(dsa->dsa_ctx, dsa->dsa_priv, NULL); - else { - if ((ret = _dsa_verify_init(dsa, buf, len)) != 0) - return (ret); + else ret = EVP_VerifyInit_ex(dsa->dsa_ctx, dsa->dsa_priv, NULL); - } return (ret ? 0 : -1); } @@ -723,44 +642,18 @@ dsa_update(struct iked_dsa *dsa, const void *buf, size_t len) return (ret ? 0 : -1); } -/* Prefix signature hash with encoded type */ -int -_dsa_sign_encode(struct iked_dsa *dsa, uint8_t *ptr, size_t *offp) -{ - if (offp) - *offp = 0; - if (dsa->dsa_method != IKEV2_AUTH_SIG) - return (0); - if (dsa->dsa_priv != EVP_sha256()) - return (-1); - if (ptr) { - ptr[0] = sizeof(sha256WithRSAEncryption); - memcpy(ptr + 1, sha256WithRSAEncryption, - sizeof(sha256WithRSAEncryption)); - } - if (offp) - *offp = 1 + sizeof(sha256WithRSAEncryption); - return (0); -} - size_t dsa_length(struct iked_dsa *dsa) { - size_t off = 0; - if (dsa->dsa_hmac) return (EVP_MD_size(dsa->dsa_priv)); - if (_dsa_sign_encode(dsa, NULL, &off) < 0) - fatal("dsa_length: internal error"); - return (EVP_PKEY_size(dsa->dsa_key) + off); + return (EVP_PKEY_size(dsa->dsa_key)); } ssize_t dsa_sign_final(struct iked_dsa *dsa, void *buf, size_t len) { - unsigned int siglen; - size_t off = 0; - uint8_t *ptr = buf; + u_int siglen; if (len < dsa_length(dsa)) return (-1); @@ -769,36 +662,19 @@ dsa_sign_final(struct iked_dsa *dsa, void *buf, size_t len) if (!HMAC_Final(dsa->dsa_ctx, buf, &siglen)) return (-1); } else { - if (_dsa_sign_encode(dsa, ptr, &off) < 0) - return (-1); - if (!EVP_SignFinal(dsa->dsa_ctx, ptr + off, &siglen, + if (!EVP_SignFinal(dsa->dsa_ctx, buf, &siglen, dsa->dsa_key)) return (-1); - siglen += off; } return (siglen); } -size_t -_dsa_verify_offset(struct iked_dsa *dsa, uint8_t *ptr) -{ - /* - * XXX assumes that _dsa_verify_init() has already checked - * the encoded method. - */ - if (dsa->dsa_method == IKEV2_AUTH_SIG) - return (ptr[0] + 1); - return (0); -} - ssize_t dsa_verify_final(struct iked_dsa *dsa, void *buf, size_t len) { - uint8_t sig[EVP_MAX_MD_SIZE]; - unsigned int siglen = sizeof(sig); - uint8_t *ptr = buf; - size_t off = 0; + u_int8_t sig[EVP_MAX_MD_SIZE]; + u_int siglen = sizeof(sig); if (dsa->dsa_hmac) { if (!HMAC_Final(dsa->dsa_ctx, sig, &siglen)) @@ -806,11 +682,9 @@ dsa_verify_final(struct iked_dsa *dsa, void *buf, size_t len) if (siglen != len || memcmp(buf, sig, siglen) != 0) return (-1); } else { - if ((off = _dsa_verify_offset(dsa, ptr)) >= len) - return (-1); - if (EVP_VerifyFinal(dsa->dsa_ctx, ptr + off, len - off, + if (EVP_VerifyFinal(dsa->dsa_ctx, buf, len, dsa->dsa_key) != 1) { - ca_sslerror(__func__); + ca_sslerror(); return (-1); } } diff --git a/iked/dh.c b/iked/dh.c index a3c462f..de33d96 100644 --- a/iked/dh.c +++ b/iked/dh.c @@ -1,7 +1,7 @@ -/* $OpenBSD: dh.c,v 1.17 2015/08/21 11:59:27 reyk Exp $ */ +/* $OpenBSD: dh.c,v 1.10 2013/01/08 10:38:19 reyk Exp $ */ /* - * Copyright (c) 2010-2014 Reyk Floeter + * Copyright (c) 2010-2013 Reyk Floeter * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,52 +16,31 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include /* roundup */ +#include #include #include #include #include #include -#include #include "dh.h" int dh_init(struct group *); -/* MODP */ int modp_init(struct group *); int modp_getlen(struct group *); -int modp_create_exchange(struct group *, uint8_t *); -int modp_create_shared(struct group *, uint8_t *, uint8_t *); +int modp_create_exchange(struct group *, u_int8_t *); +int modp_create_shared(struct group *, u_int8_t *, u_int8_t *); -/* EC2N/ECP */ int ec_init(struct group *); int ec_getlen(struct group *); -int ec_create_exchange(struct group *, uint8_t *); -int ec_create_shared(struct group *, uint8_t *, uint8_t *); +int ec_create_exchange(struct group *, u_int8_t *); +int ec_create_shared(struct group *, u_int8_t *, u_int8_t *); -int ec_point2raw(struct group *, const EC_POINT *, uint8_t *, size_t); +int ec_point2raw(struct group *, const EC_POINT *, u_int8_t *, size_t); EC_POINT * - ec_raw2point(struct group *, uint8_t *, size_t); - -/* curve25519 */ -int ec25519_init(struct group *); -int ec25519_getlen(struct group *); -int ec25519_create_exchange(struct group *, uint8_t *); -int ec25519_create_shared(struct group *, uint8_t *, uint8_t *); - -#define CURVE25519_SIZE 32 /* 256 bits */ -struct curve25519_key { - uint8_t secret[CURVE25519_SIZE]; - uint8_t public[CURVE25519_SIZE]; -}; -extern int crypto_scalarmult_curve25519(unsigned char a[CURVE25519_SIZE], - const unsigned char b[CURVE25519_SIZE], - const unsigned char c[CURVE25519_SIZE]) - __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) - __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))) - __attribute__((__bounded__(__minbytes__, 3, CURVE25519_SIZE))); + ec_raw2point(struct group *, u_int8_t *, size_t); struct group_id ike_groups[] = { { GROUP_MODP, 1, 768, @@ -298,14 +277,7 @@ struct group_id ike_groups[] = { "5E2327CFEF98C582664B4C0F6CC41659" }, { GROUP_ECP, 25, 192, NULL, NULL, NID_X9_62_prime192v1 }, - { GROUP_ECP, 26, 224, NULL, NULL, NID_secp224r1 }, - { GROUP_ECP, 27, 224, NULL, NULL, NID_brainpoolP224r1 }, - { GROUP_ECP, 28, 256, NULL, NULL, NID_brainpoolP256r1 }, - { GROUP_ECP, 29, 384, NULL, NULL, NID_brainpoolP384r1 }, - { GROUP_ECP, 30, 512, NULL, NULL, NID_brainpoolP512r1 }, - - /* "Private use" extensions */ - { GROUP_CURVE25519, 1034, CURVE25519_SIZE * 8 } + { GROUP_ECP, 26, 224, NULL, NULL, NID_secp224r1 } }; void @@ -324,21 +296,16 @@ group_free(struct group *group) DH_free(group->dh); if (group->ec != NULL) EC_KEY_free(group->ec); - if (group->curve25519 != NULL) { - explicit_bzero(group->curve25519, - sizeof(struct curve25519_key)); - free(group->curve25519); - } group->spec = NULL; free(group); } struct group * -group_get(uint32_t id) +group_get(u_int32_t id) { struct group_id *p = NULL; struct group *group; - unsigned int i, items; + u_int i, items; items = sizeof(ike_groups) / sizeof(ike_groups[0]); for (i = 0; i < items; i++) { @@ -370,12 +337,6 @@ group_get(uint32_t id) group->exchange = ec_create_exchange; group->shared = ec_create_shared; break; - case GROUP_CURVE25519: - group->init = ec25519_init; - group->getlen = ec25519_getlen; - group->exchange = ec25519_create_exchange; - group->shared = ec25519_create_shared; - break; default: group_free(group); return (NULL); @@ -402,13 +363,13 @@ dh_getlen(struct group *group) } int -dh_create_exchange(struct group *group, uint8_t *buf) +dh_create_exchange(struct group *group, u_int8_t *buf) { return (group->exchange(group, buf)); } int -dh_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) +dh_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange) { return (group->shared(group, secret, exchange)); } @@ -438,7 +399,7 @@ modp_getlen(struct group *group) } int -modp_create_exchange(struct group *group, uint8_t *buf) +modp_create_exchange(struct group *group, u_int8_t *buf) { DH *dh = group->dh; int len, ret; @@ -461,7 +422,7 @@ modp_create_exchange(struct group *group, uint8_t *buf) } int -modp_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) +modp_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange) { BIGNUM *ex; int len, ret; @@ -473,7 +434,7 @@ modp_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) ret = DH_compute_key(secret, ex, group->dh); BN_clear_free(ex); - if (ret <= 0) + if (!ret) return (-1); /* add zero padding */ @@ -492,10 +453,6 @@ ec_init(struct group *group) return (-1); if (!EC_KEY_generate_key(group->ec)) return (-1); - if (!EC_KEY_check_key(group->ec)) { - EC_KEY_free(group->ec); - return (-1); - } return (0); } @@ -509,7 +466,7 @@ ec_getlen(struct group *group) } int -ec_create_exchange(struct group *group, uint8_t *buf) +ec_create_exchange(struct group *group, u_int8_t *buf) { size_t len; @@ -521,11 +478,10 @@ ec_create_exchange(struct group *group, uint8_t *buf) } int -ec_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) +ec_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange) { const EC_GROUP *ecgroup = NULL; const BIGNUM *privkey; - EC_KEY *exkey = NULL; EC_POINT *exchangep = NULL, *secretp = NULL; int ret = -1; @@ -537,17 +493,6 @@ ec_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) ec_raw2point(group, exchange, ec_getlen(group))) == NULL) goto done; - if ((exkey = EC_KEY_new()) == NULL) - goto done; - if (!EC_KEY_set_group(exkey, ecgroup)) - goto done; - if (!EC_KEY_set_public_key(exkey, exchangep)) - goto done; - - /* validate exchangep */ - if (!EC_KEY_check_key(exkey)) - goto done; - if ((secretp = EC_POINT_new(ecgroup)) == NULL) goto done; @@ -557,8 +502,6 @@ ec_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) ret = ec_point2raw(group, secretp, secret, ec_getlen(group)); done: - if (exkey != NULL) - EC_KEY_free(exkey); if (exchangep != NULL) EC_POINT_clear_free(exchangep); if (secretp != NULL) @@ -569,7 +512,7 @@ ec_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) int ec_point2raw(struct group *group, const EC_POINT *point, - uint8_t *buf, size_t len) + u_int8_t *buf, size_t len) { const EC_GROUP *ecgroup = NULL; BN_CTX *bnctx = NULL; @@ -616,11 +559,6 @@ ec_point2raw(struct group *group, const EC_POINT *point, ret = 0; done: - /* Make sure to erase sensitive data */ - if (x != NULL) - BN_clear(x); - if (y != NULL) - BN_clear(y); BN_CTX_end(bnctx); BN_CTX_free(bnctx); @@ -628,7 +566,7 @@ ec_point2raw(struct group *group, const EC_POINT *point, } EC_POINT * -ec_raw2point(struct group *group, uint8_t *buf, size_t len) +ec_raw2point(struct group *group, u_int8_t *buf, size_t len) { const EC_GROUP *ecgroup = NULL; EC_POINT *point = NULL; @@ -674,57 +612,8 @@ ec_raw2point(struct group *group, uint8_t *buf, size_t len) done: if (ret != 0 && point != NULL) EC_POINT_clear_free(point); - /* Make sure to erase sensitive data */ - if (x != NULL) - BN_clear(x); - if (y != NULL) - BN_clear(y); BN_CTX_end(bnctx); BN_CTX_free(bnctx); return (point); } - -int -ec25519_init(struct group *group) -{ - static const uint8_t basepoint[CURVE25519_SIZE] = { 9 }; - struct curve25519_key *curve25519; - - if ((curve25519 = calloc(1, sizeof(*curve25519))) == NULL) - return (-1); - - group->curve25519 = curve25519; - - arc4random_buf(curve25519->secret, CURVE25519_SIZE); - crypto_scalarmult_curve25519(curve25519->public, - curve25519->secret, basepoint); - - return (0); -} - -int -ec25519_getlen(struct group *group) -{ - if (group->spec == NULL) - return (0); - return (CURVE25519_SIZE); -} - -int -ec25519_create_exchange(struct group *group, uint8_t *buf) -{ - struct curve25519_key *curve25519 = group->curve25519; - - memcpy(buf, curve25519->public, ec25519_getlen(group)); - return (0); -} - -int -ec25519_create_shared(struct group *group, uint8_t *shared, uint8_t *public) -{ - struct curve25519_key *curve25519 = group->curve25519; - - crypto_scalarmult_curve25519(shared, curve25519->secret, public); - return (0); -} diff --git a/iked/dh.h b/iked/dh.h index e5b825c..d7b8ea8 100644 --- a/iked/dh.h +++ b/iked/dh.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dh.h,v 1.9 2015/08/21 11:59:27 reyk Exp $ */ +/* $OpenBSD: dh.h,v 1.5 2013/01/08 10:38:19 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,19 +16,18 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef DH_GROUP_H -#define DH_GROUP_H +#ifndef _DH_H_ +#define _DH_H_ enum group_type { - GROUP_MODP = 0, - GROUP_EC2N = 1, - GROUP_ECP = 2, - GROUP_CURVE25519 = 3 + GROUP_MODP = 0, + GROUP_EC2N = 1, + GROUP_ECP = 2 }; struct group_id { enum group_type type; - unsigned int id; + u_int id; int bits; char *prime; char *generator; @@ -41,22 +40,21 @@ struct group { void *dh; void *ec; - void *curve25519; int (*init)(struct group *); int (*getlen)(struct group *); - int (*exchange)(struct group *, uint8_t *); - int (*shared)(struct group *, uint8_t *, uint8_t *); + int (*exchange)(struct group *, u_int8_t *); + int (*shared)(struct group *, u_int8_t *, u_int8_t *); }; #define DH_MAXSZ 1024 /* 8192 bits */ -void group_init(void); -void group_free(struct group *); -struct group *group_get(uint32_t); +void group_init(void); +void group_free(struct group *); +struct group *group_get(u_int32_t); int dh_getlen(struct group *); -int dh_create_exchange(struct group *, uint8_t *); -int dh_create_shared(struct group *, uint8_t *, uint8_t *); +int dh_create_exchange(struct group *, u_int8_t *); +int dh_create_shared(struct group *, u_int8_t *, u_int8_t *); -#endif /* DH_GROUP_H */ +#endif /* _DH_H_ */ diff --git a/iked/eap.c b/iked/eap.c index a7764b1..bbb5a7c 100644 --- a/iked/eap.c +++ b/iked/eap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: eap.c,v 1.14 2015/08/21 11:59:27 reyk Exp $ */ +/* $OpenBSD: eap.c,v 1.9 2013/03/21 04:30:14 deraadt Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,18 +16,23 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +#include +#include "openbsd-compat/sys-queue.h" #include #include #include #include +#if defined(__OpenBSD__) +#include +#endif #include #include #include #include #include +#include #include #include #include @@ -66,19 +71,19 @@ eap_identity_request(struct ibuf *e) char * eap_identity_response(struct eap_message *eap) { - size_t len; - char *str; - uint8_t *ptr = (uint8_t *)eap; + size_t len; + char *str; + u_int8_t *ptr = (u_int8_t *)eap; len = betoh16(eap->eap_length) - sizeof(*eap); ptr += sizeof(*eap); if (len == 0 || (str = get_string(ptr, len)) == NULL) { - log_info("%s: invalid identity response, length %zu", + log_info("%s: invalid identity response, length %d", __func__, len); return (NULL); } - log_debug("%s: identity '%s' length %zd", __func__, str, len); + log_debug("%s: identity '%s' length %d", __func__, str, len); return (str); } @@ -172,11 +177,11 @@ eap_mschap(struct iked *env, struct iked_sa *sa, struct eap_message *eap) struct eap_mschap_peer *msp; struct eap_mschap *ms; struct eap_mschap_success *mss; - uint8_t *ptr, *pass; + u_int8_t *ptr, *pass; size_t len, passlen; char *name, *msg; - uint8_t ntresponse[EAP_MSCHAP_NTRESPONSE_SZ]; - uint8_t successmsg[EAP_MSCHAP_SUCCESS_SZ]; + u_int8_t ntresponse[EAP_MSCHAP_NTRESPONSE_SZ]; + u_int8_t successmsg[EAP_MSCHAP_SUCCESS_SZ]; struct ibuf *eapmsg = NULL; int ret = -1; @@ -203,7 +208,7 @@ eap_mschap(struct iked *env, struct iked_sa *sa, struct eap_message *eap) } ms = (struct eap_mschap *)(eap + 1); - ptr = (uint8_t *)(eap + 1); + ptr = (u_int8_t *)(eap + 1); switch (ms->ms_opcode) { case EAP_MSOPCODE_RESPONSE: @@ -331,7 +336,7 @@ eap_parse(struct iked *env, struct iked_sa *sa, void *data, int response) struct eap_header *hdr = data; struct eap_message *eap = data; size_t len; - uint8_t *ptr; + u_int8_t *ptr; struct eap_mschap *ms; struct eap_mschap_challenge *msc; struct eap_mschap_response *msr; @@ -341,7 +346,7 @@ eap_parse(struct iked *env, struct iked_sa *sa, void *data, int response) /* length is already verified by the caller */ len = betoh16(hdr->eap_length); - ptr = (uint8_t *)(eap + 1); + ptr = (u_int8_t *)(eap + 1); switch (hdr->eap_code) { case EAP_CODE_REQUEST: @@ -394,7 +399,7 @@ eap_parse(struct iked *env, struct iked_sa *sa, void *data, int response) return (-1); } log_info("%s: %s %s id %d " - "length %d valuesize %d name '%s' length %zu", + "length %d valuesize %d name '%s' length %d", __func__, print_map(eap->eap_type, eap_type_map), print_map(ms->ms_opcode, eap_msopcode_map), @@ -415,7 +420,7 @@ eap_parse(struct iked *env, struct iked_sa *sa, void *data, int response) return (-1); } log_info("%s: %s %s id %d " - "length %d valuesize %d name '%s' name-length %zu", + "length %d valuesize %d name '%s' name-length %d", __func__, print_map(eap->eap_type, eap_type_map), print_map(ms->ms_opcode, eap_msopcode_map), @@ -437,7 +442,7 @@ eap_parse(struct iked *env, struct iked_sa *sa, void *data, int response) return (-1); } log_info("%s: %s %s request id %d " - "length %d message '%s' message-len %zu", + "length %d message '%s' message-len %d", __func__, print_map(eap->eap_type, eap_type_map), print_map(ms->ms_opcode, eap_msopcode_map), diff --git a/iked/eap.h b/iked/eap.h index cc567ea..a8d158e 100644 --- a/iked/eap.h +++ b/iked/eap.h @@ -1,4 +1,4 @@ -/* $OpenBSD: eap.h,v 1.5 2015/08/21 11:59:27 reyk Exp $ */ +/* $OpenBSD: eap.h,v 1.3 2013/01/08 10:38:19 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,20 +16,20 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef IKED_EAP_H -#define IKED_EAP_H +#ifndef _IKEV2_EAP_H +#define _IKEV2_EAP_H struct eap_header { - uint8_t eap_code; - uint8_t eap_id; - uint16_t eap_length; + u_int8_t eap_code; + u_int8_t eap_id; + u_int16_t eap_length; } __packed; struct eap_message { - uint8_t eap_code; - uint8_t eap_id; - uint16_t eap_length; - uint8_t eap_type; + u_int8_t eap_code; + u_int8_t eap_id; + u_int16_t eap_length; + u_int8_t eap_type; /* Followed by type-specific data */ } __packed; @@ -114,48 +114,48 @@ extern struct iked_constmap eap_type_map[]; extern struct iked_constmap eap_msopcode_map[]; struct eap_mschap { - uint8_t ms_opcode; + u_int8_t ms_opcode; } __packed; struct eap_mschap_challenge { - uint8_t msc_opcode; - uint8_t msc_id; - uint16_t msc_length; - uint8_t msc_valuesize; - uint8_t msc_challenge[EAP_MSCHAP_CHALLENGE_SZ]; + u_int8_t msc_opcode; + u_int8_t msc_id; + u_int16_t msc_length; + u_int8_t msc_valuesize; + u_int8_t msc_challenge[EAP_MSCHAP_CHALLENGE_SZ]; /* Followed by variable-size name field */ } __packed; struct eap_mschap_peer { - uint8_t msp_challenge[EAP_MSCHAP_CHALLENGE_SZ]; - uint8_t msp_reserved[8]; - uint8_t msp_ntresponse[EAP_MSCHAP_NTRESPONSE_SZ]; - uint8_t msp_flags; + u_int8_t msp_challenge[EAP_MSCHAP_CHALLENGE_SZ]; + u_int8_t msp_reserved[8]; + u_int8_t msp_ntresponse[EAP_MSCHAP_NTRESPONSE_SZ]; + u_int8_t msp_flags; }; struct eap_mschap_response { - uint8_t msr_opcode; - uint8_t msr_id; - uint16_t msr_length; - uint8_t msr_valuesize; + u_int8_t msr_opcode; + u_int8_t msr_id; + u_int16_t msr_length; + u_int8_t msr_valuesize; union { - uint8_t resp_data[EAP_MSCHAP_RESPONSE_SZ]; + u_int8_t resp_data[EAP_MSCHAP_RESPONSE_SZ]; struct eap_mschap_peer resp_peer; } msr_response; /* Followed by variable-size name field */ } __packed; struct eap_mschap_success { - uint8_t mss_opcode; - uint8_t mss_id; - uint16_t mss_length; + u_int8_t mss_opcode; + u_int8_t mss_id; + u_int16_t mss_length; /* Followed by variable-size success message */ } __packed; struct eap_mschap_failure { - uint8_t msf_opcode; - uint8_t msf_id; - uint16_t msf_length; + u_int8_t msf_opcode; + u_int8_t msf_id; + u_int16_t msf_length; /* Followed by variable-size message field */ } __packed; @@ -168,4 +168,4 @@ struct eap_mschap_failure { extern struct iked_constmap eap_mserror_map[]; -#endif /* IKED_EAP_H */ +#endif /* _IKEV2_EAP_H */ diff --git a/iked/genmap.sh b/iked/genmap.sh index 9cd4ba0..685f42e 100644 --- a/iked/genmap.sh +++ b/iked/genmap.sh @@ -1,5 +1,5 @@ #!/bin/sh -# $OpenBSD: genmap.sh,v 1.7 2015/01/16 06:39:58 deraadt Exp $ +# $OpenBSD: genmap.sh,v 1.6 2013/01/08 10:38:19 reyk Exp $ # Copyright (c) 2010-2013 Reyk Floeter # @@ -28,6 +28,7 @@ EOF sed -n '1,/^ \*\//p' $1 cat < #include #include "types.h" diff --git a/iked/iked.8 b/iked/iked.8 index c03ec11..7f2dc16 100644 --- a/iked/iked.8 +++ b/iked/iked.8 @@ -1,6 +1,6 @@ -.\" $OpenBSD: iked.8,v 1.19 2014/11/10 13:57:32 jmc Exp $ +.\" $OpenBSD: iked.8,v 1.13 2013/01/08 10:38:19 reyk Exp $ .\" -.\" Copyright (c) 2010 - 2014 Reyk Floeter +.\" Copyright (c) 2010-2013 Reyk Floeter .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: November 10 2014 $ +.Dd $Mdocdate: January 8 2013 $ .Dt IKED 8 .Os .Sh NAME @@ -23,7 +23,9 @@ .Sh SYNOPSIS .Nm iked .Op Fl 6dnSTtv -.Op Fl D Ar macro Ns = Ns Ar value +.Oo +.Fl D Ar macro Ns = Ns Ar value +.Oc .Op Fl f Ar file .Sh DESCRIPTION .Nm @@ -46,8 +48,10 @@ is provided by .Nm supports mutual authentication using RSA public keys and X.509 certificates. See the -.Sx PUBLIC KEY AUTHENTICATION -section below and PKI AND CERTIFICATE AUTHORITY COMMANDS in +.Sx FILES +section below and +.Sx PKI AND CERTIFICATE AUTHORITY COMMANDS +in .Xr ikectl 8 for more information about creating and maintaining the public key infrastructure. @@ -99,54 +103,6 @@ negotiate NAT-Traversal with the peers. .It Fl v Produce more verbose output. .El -.Sh PUBLIC KEY AUTHENTICATION -It is possible to store trusted public keys to make them directly -usable by -.Nm , -bypassing the need to use certificates. -The keys should be saved in PEM format (see -.Xr openssl 1 ) -and named and stored as follows: -.Pp -.Bl -tag -width "for_ufqdn_identitiesXX" -offset 3n -compact -.It For IPv4 identities: -/etc/iked/pubkeys/ipv4/A.B.C.D -.It For IPv6 identities: -/etc/iked/pubkeys/ipv6/abcd:abcd::ab:bc -.It For FQDN identities: -/etc/iked/pubkeys/fqdn/foo.bar.org -.It For UFQDN identities: -/etc/iked/pubkeys/ufqdn/user@foo.bar.org -.El -.Pp -Depending on the -.Ic srcid -and -.Ic dstid -specifications in -.Xr iked.conf 5 , -keys may be named after their IPv4 address, IPv6 address, -fully qualified domain name (FQDN) or user fully qualified domain name (UFQDN). -.Pp -For example, -.Nm -can authenticate using the pre-generated keys if the local public key, -by default -.Pa /etc/iked/local.pub , -is copied to the remote gateway as -.Pa /etc/iked/pubkeys/ipv4/local.gateway.ip.address -and the remote gateway's public key -is copied to the local gateway as -.Pa /etc/iked/pubkeys/ipv4/remote.gateway.ip.address . -Of course, new keys may also be generated -(the user is not required to use the pre-generated keys). -In this example, -.Ic srcid -and -.Ic dstid -would also have to be set to the specified addresses -in -.Xr iked.conf 5 . .Sh FILES .Bl -tag -width "/etc/iked/private/XXX" -compact .It Pa /etc/iked.conf @@ -198,4 +154,38 @@ program first appeared in The .Nm program was written by -.An Reyk Floeter Aq Mt reyk@openbsd.org . +.An Reyk Floeter Aq reyk@openbsd.org . +.Sh CAVEATS +.Nm +is not yet finished and is missing some important security features. +It should not yet be used in production networks. +.Sh BUGS +The portable version of +.Nm , +.Ic OpenIKED , +might have a few limitations on operating systems other than the most +recent versions of +.Ox . +A major difference between +.Ox +and other systems is the API and availability of the IPsec PFKEYv2 +flow implementation (SADB) and message passing between kernel and +.Nm . +Current known limitations are: +.Bl -tag -width Ds +.It Ic VPN traffic leakage prevention +Automatic blocking of IPv6 traffic is not working on KAME-bases stacks. +.It Ic NAT-T +NAT-T is only supported on OpenBSD and Darwin (OS X). +The NAT-T API is not standardized in PFKEYv2, not even on a semi-level, +and differs in most operating systems, if supported at all. +.It Ic Crypto algorithms +Some of the crypto algorithms are either not supported on other +systems or not implemented correctly. +For example, Linux still uses the broken pre-standard version of +hmac-sha2-256 by default that was specified with 96 bit truncation +instead of the standard 128 bit truncation. +The common workaround that allows to specify the truncation length +would be to use Linux' non-standard XFRM kernel API instead of +PFKEYv2. +.El diff --git a/iked/iked.c b/iked/iked.c index b74251a..7419f13 100644 --- a/iked/iked.c +++ b/iked/iked.c @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.c,v 1.25 2015/08/21 11:59:27 reyk Exp $ */ +/* $OpenBSD: iked.c,v 1.17 2013/03/21 04:30:14 deraadt Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,11 +16,24 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +#include +#include "openbsd-compat/sys-queue.h" #include #include #include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_DEPRECATED_DAEMON +/* Apple deprected daemon() and prints an warning that breaks -Werror */ +#define daemon XXX_daemon +#endif + #include #include #include @@ -35,6 +48,11 @@ #include "iked.h" #include "ikev2.h" +#ifdef HAVE_DEPRECATED_DAEMON +#undef daemon +extern int daemon(int, int); +#endif + __dead void usage(void); void parent_shutdown(struct iked *); @@ -50,6 +68,12 @@ static struct privsep_proc procs[] = { { "ca", PROC_CERT, parent_dispatch_ca, caproc, IKED_CA } }; +#ifndef HAVE_SETPROCTITLE +/* Saved arguments to main(). */ +char **saved_argv; +int saved_argc; +#endif + __dead void usage(void) { @@ -72,6 +96,24 @@ main(int argc, char *argv[]) log_init(1); +#ifndef HAVE_SETPROCTITLE + /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ + saved_argc = argc; + saved_argv = calloc(argc + 1, sizeof(*saved_argv)); + if (saved_argv == NULL) + fatal("calloc: argv"); + for (c = 0; c < argc; c++) { + saved_argv[c] = strdup(argv[c]); + if (saved_argv[c] == NULL) + fatal("strdup: saved_argv[c]"); + } + saved_argv[c] = NULL; + + /* Prepare for later setproctitle emulation */ + compat_init_setproctitle(argc, argv); + argv = saved_argv; +#endif + while ((c = getopt(argc, argv, "6dD:nf:vSTt")) != -1) { switch (c) { case '6': @@ -117,14 +159,13 @@ main(int argc, char *argv[]) ps = &env->sc_ps; ps->ps_env = env; - TAILQ_INIT(&ps->ps_rcsocks); if ((opts & (IKED_OPT_NONATT|IKED_OPT_NATT)) == (IKED_OPT_NONATT|IKED_OPT_NATT)) errx(1, "conflicting NAT-T options"); - if (strlcpy(env->sc_conffile, conffile, PATH_MAX) >= PATH_MAX) - errx(1, "config file exceeds PATH_MAX"); + if (strlcpy(env->sc_conffile, conffile, MAXPATHLEN) >= MAXPATHLEN) + errx(1, "config file exceeds MAXPATHLEN"); ca_sslinit(); policy_init(env); @@ -146,8 +187,6 @@ main(int argc, char *argv[]) err(1, "failed to daemonize"); group_init(); - - ps->ps_ninstances = 1; proc_init(ps, procs, nitems(procs)); setproctitle("parent"); @@ -159,16 +198,14 @@ main(int argc, char *argv[]) signal_set(&ps->ps_evsigchld, SIGCHLD, parent_sig_handler, ps); signal_set(&ps->ps_evsighup, SIGHUP, parent_sig_handler, ps); signal_set(&ps->ps_evsigpipe, SIGPIPE, parent_sig_handler, ps); - signal_set(&ps->ps_evsigusr1, SIGUSR1, parent_sig_handler, ps); signal_add(&ps->ps_evsigint, NULL); signal_add(&ps->ps_evsigterm, NULL); signal_add(&ps->ps_evsigchld, NULL); signal_add(&ps->ps_evsighup, NULL); signal_add(&ps->ps_evsigpipe, NULL); - signal_add(&ps->ps_evsigusr1, NULL); - proc_listen(ps, procs, nitems(procs)); + proc_config(ps, procs, nitems(procs)); if (parent_configure(env) == -1) fatalx("configuration failed"); @@ -184,6 +221,9 @@ int parent_configure(struct iked *env) { struct sockaddr_storage ss; +#if defined(HAVE_APPLE_NATT) + int udpencap; +#endif if (parse_config(env->sc_conffile, env) == -1) { proc_kill(&env->sc_ps); @@ -206,6 +246,15 @@ parent_configure(struct iked *env) bzero(&ss, sizeof(ss)); ss.ss_family = AF_INET; +#if defined(HAVE_APPLE_NATT) + if ((env->sc_opts & IKED_OPT_NONATT) == 0) { + udpencap = IKED_NATT_PORT; + if (sysctlbyname("net.inet.ipsec.esp_port", NULL, NULL, + &udpencap, sizeof(udpencap)) != 0) + fatalx("failed to set NAT-T port"); + } +#endif + if ((env->sc_opts & IKED_OPT_NATT) == 0) config_setsocket(env, &ss, ntohs(IKED_IKE_PORT), PROC_IKEV2); if ((env->sc_opts & IKED_OPT_NONATT) == 0) @@ -221,7 +270,6 @@ parent_configure(struct iked *env) config_setcoupled(env, env->sc_decoupled ? 0 : 1); config_setmode(env, env->sc_passive ? 1 : 0); - config_setocsp(env); return (0); } @@ -251,7 +299,6 @@ parent_reload(struct iked *env, int reset, const char *filename) config_setcoupled(env, env->sc_decoupled ? 0 : 1); config_setmode(env, env->sc_passive ? 1 : 0); - config_setocsp(env); } else { config_setreset(env, reset, PROC_IKEV1); config_setreset(env, reset, PROC_IKEV2); @@ -280,17 +327,12 @@ parent_sig_handler(int sig, short event, void *arg) case SIGPIPE: log_info("%s: ignoring SIGPIPE", __func__); break; - case SIGUSR1: - log_info("%s: ignoring SIGUSR1", __func__); - break; case SIGTERM: case SIGINT: die = 1; /* FALLTHROUGH */ case SIGCHLD: do { - int len; - pid = waitpid(-1, &status, WNOHANG); if (pid <= 0) continue; @@ -298,21 +340,17 @@ parent_sig_handler(int sig, short event, void *arg) fail = 0; if (WIFSIGNALED(status)) { fail = 1; - len = asprintf(&cause, "terminated; signal %d", + asprintf(&cause, "terminated; signal %d", WTERMSIG(status)); } else if (WIFEXITED(status)) { if (WEXITSTATUS(status) != 0) { fail = 1; - len = asprintf(&cause, - "exited abnormally"); + asprintf(&cause, "exited abnormally"); } else - len = asprintf(&cause, "exited okay"); + asprintf(&cause, "exited okay"); } else fatalx("unexpected cause of SIGCHLD"); - if (len == -1) - fatal("asprintf"); - die = 1; for (id = 0; id < PROC_MAX; id++) @@ -362,7 +400,7 @@ parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg) struct iked *env = p->p_ps->ps_env; int v; char *str = NULL; - unsigned int type = imsg->hdr.type; + u_int type = imsg->hdr.type; switch (type) { case IMSG_CTL_RESET: @@ -374,10 +412,8 @@ parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg) case IMSG_CTL_DECOUPLE: case IMSG_CTL_ACTIVE: case IMSG_CTL_PASSIVE: - proc_compose_imsg(&env->sc_ps, PROC_IKEV1, -1, - type, -1, NULL, 0); - proc_compose_imsg(&env->sc_ps, PROC_IKEV2, -1, - type, -1, NULL, 0); + proc_compose_imsg(env, PROC_IKEV1, type, -1, NULL, 0); + proc_compose_imsg(env, PROC_IKEV2, type, -1, NULL, 0); break; case IMSG_CTL_RELOAD: if (IMSG_DATA_SIZE(imsg) > 0) @@ -386,9 +422,6 @@ parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg) if (str != NULL) free(str); break; - case IMSG_OCSP_FD: - ocsp_connect(env); - break; default: return (-1); } diff --git a/iked/iked.conf b/iked/iked.conf new file mode 100644 index 0000000..71ef75c --- /dev/null +++ b/iked/iked.conf @@ -0,0 +1,12 @@ +# OpenIKED client configuration file +# +# See iked.conf(5) for syntax and examples. + +# Connect to a remote IKEv2 gateway using certificates. Please note +# that the srcid has to match the subjectAltName value in the local host +# certificate. The default srcid value is the local hostname. +ikev2 active esp \ + from 10.2.1.0/30 to 10.1.0.0/24 \ + local any peer openbsd-iked.vpn.example.com \ + srcid roadwarrior.vpn.example.com +# psk "you-should-not-use-psk-authentication" diff --git a/iked/iked.conf.5 b/iked/iked.conf.5 index d02e08e..c915ee0 100644 --- a/iked/iked.conf.5 +++ b/iked/iked.conf.5 @@ -1,6 +1,6 @@ -.\" $OpenBSD: iked.conf.5,v 1.39 2015/07/14 13:06:37 jmc Exp $ +.\" $OpenBSD: iked.conf.5,v 1.23 2013/03/05 19:16:01 sobrado Exp $ .\" -.\" Copyright (c) 2010 - 2014 Reyk Floeter +.\" Copyright (c) 2010-2013 Reyk Floeter .\" Copyright (c) 2004 Mathieu Sauve-Frankel All rights reserved. .\" .\" Permission to use, copy, modify, and distribute this software for any @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: July 14 2015 $ +.Dd $Mdocdate: March 5 2013 $ .Dt IKED.CONF 5 .Os .Sh NAME @@ -136,13 +136,6 @@ This is the default. .It Ic set decouple Don't load the negotiated SAs and flows from the kernel. This mode is only useful for testing and debugging. -.It Ic set ocsp Ar URL -Enable OCSP and set the URL of the OCSP responder. -Please note that the matching responder and issuer certificates -have to be placed in -.Pa /etc/iked/ocsp/responder.crt -and -.Pa /etc/iked/ocsp/issuer.crt . .It Ic user Ar name Ar password .Xr iked 8 supports user-based authentication by tunneling the Extensible @@ -246,10 +239,6 @@ is specified, negotiation will be started at once. If omitted, .Ar passive mode will be used. -.It Ic ipcomp -Enable optional support for -.Xr ipcomp 4 , -the IP Payload Compression protocol. .It Op Ar encap .Ar encap specifies the encapsulation protocol to be used. @@ -397,7 +386,7 @@ If omitted, will use the default proposals for the ESP or AH protocol. The .Ic group -option will only be used to enable Perfect Forward Secrecy (PFS) +option will only be used to enable Perfect Forwarding Security (PFS) for additional Child SAs exchanges that are not part of the initial key exchange. .It Ic srcid Ar string Ic dstid Ar string @@ -435,14 +424,6 @@ is similar to .Ic srcid , but instead specifies the ID to be used by the remote peer. -.It Ic ikelifetime Ar time -The optional -.Ic ikelifetime -parameter defines the IKE SA expiration timeout by the -.Ar time -SA was created. -A zero value disables active IKE SA rekeying. -This is the default. .It Ic lifetime Ar time Op Ic bytes Ar bytes The optional .Ic lifetime @@ -492,33 +473,6 @@ or hex value (starting with 0x) for authentication. Use RSA public key authentication. This is the default mode if no option is specified. .El -.It Ic config Ar option address -Send one or more optional configuration payloads (CP) to the peer. -The configuration -.Ar option -can be one of the following with the expected address format: -.Pp -.Bl -tag -width Ds -compact -offset indent -.It Ic address Ar address -Assign a static address on the internal network. -.It Ic address Ar address/prefix -Assign a dynamic address on the internal network. -The address will be assigned from an address pool with the size specified by -.Ar prefix . -.It Ic netmask Ar netmask -The IPv4 netmask of the internal network. -.It Ic name-server Ar address -The DNS server address within the internal network. -.It Ic netbios-server Ar address -The NetBIOS name server (WINS) within the internal network. -This option is provided for compatibility with legacy clients. -.It Ic dhcp-server Ar address -The address of an internal DHCP server for further configuration. -.It Ic protected-subnet Ar address/prefix -The address of the protected subnet within the internal network. -.It Ic access-server Ar address -The address of an internal remote access server. -.El .It Ic tag Ar string Add a .Xr pf 4 @@ -599,7 +553,7 @@ Interface for IKE traffic and encapsulated IPsec traffic. IKE traffic on the external interface. .It proto udp port 4500 IKE NAT-Traversal traffic on the external interface. -.It proto ah | esp +.It proto ah \*(Ba esp Encapsulated IPsec traffic on the external interface. .It enc0 @@ -670,16 +624,17 @@ The following fragment uses queues for all IPsec traffic with special handling for developers and employees: .Bd -literal -offset indent -queue std on ix0 bandwidth 100M -queue deflt parent std bandwidth 10M default -queue developers parent std bandwidth 75M -queue employees parent std bandwidth 5M -queue ipsec parent std bandwidth 10M +altq on ix0 cbq bandwidth 1000Mb \e + queue { deflt, developers, employees, ipsec } + queue deflt bandwidth 10% priority 0 cbq(default ecn) + queue developers bandwidth 75% priority 7 cbq(borrow red) + queue employees bandwidth 5% cbq(red) + queue ipsec bandwidth 10% cbq(red) -pass out on ix0 proto esp set queue ipsec +pass out on ix0 proto esp queue ipsec -pass out on ix0 tagged ipsec-developers.example.com set queue developers -pass out on ix0 tagged ipsec-employees.example.com set queue employees +pass out on ix0 tagged ipsec-developers.example.com queue developers +pass out on ix0 tagged ipsec-employees.example.com queue employees .Ed .Pp The following example assigns the tags in the @@ -718,7 +673,7 @@ a relevant NAT rule is required in For the example above, this would be: .Bd -literal -offset indent -match out on enc0 from 192.168.1.0/24 to 192.168.2.0/24 nat-to 10.10.10.1 +match on enc0 from 192.168.1.0/24 to 192.168.2.0/24 nat-to 10.10.10.1 .Ed .Pp From the peer's point of view, @@ -765,21 +720,16 @@ keyword: .It Li aes-128-gcm Ta "160 bits" Ta "[ESP only]" .It Li aes-192-gcm Ta "224 bits" Ta "[ESP only]" .It Li aes-256-gcm Ta "288 bits" Ta "[ESP only]" -.It Li blowfish Ta "160 bits" Ta "[ESP only]" -.It Li cast Ta "128 bits" Ta "[ESP only]" -.El -.Pp -The following cipher types provide only authentication, -not encryption: -.Bl -column "aes-128-gmac" "Key Length" "[ESP only]" -offset indent .It Li aes-128-gmac Ta "160 bits" Ta "[ESP only]" .It Li aes-192-gmac Ta "224 bits" Ta "[ESP only]" .It Li aes-256-gmac Ta "288 bits" Ta "[ESP only]" +.It Li blowfish Ta "160 bits" Ta "[ESP only]" +.It Li cast Ta "128 bits" Ta "[ESP only]" .It Li null Ta "" Ta "[ESP only]" .El .Pp -Use of DES as an encryption algorithm is considered to be insecure -since brute force attacks are practical due its short key length. +Use of DES as an encryption algorithm is not recommended (except for +backwards compatibility) due to the short key length. .Pp DES requires 8 bytes to form a 56-bit key and 3DES requires 24 bytes to form its 168-bit key. @@ -816,22 +766,17 @@ keyword: .It Li modp2048-256 Ta grp24 Ta 2048 Ta "MODP, 256 bit Prime Order Subgroup" .It Li ecp192 Ta grp25 Ta 192 Ta "ECP" .It Li ecp224 Ta grp26 Ta 224 Ta "ECP" -.It Li brainpool224 Ta grp27 Ta 224 Ta "ECP, brainpoolP224r1" -.It Li brainpool256 Ta grp28 Ta 256 Ta "ECP, brainpoolP256r1" -.It Li brainpool384 Ta grp29 Ta 384 Ta "ECP, brainpoolP384r1" -.It Li brainpool512 Ta grp30 Ta 512 Ta "ECP, brainpoolP512r1" -.It Li curve25519 Ta - Ta 256 Ta "Curve25519" .El .Pp The currently supported group types are either MODP (exponentiation groups modulo a prime), EC2N (elliptic curve groups over GF[2^N]), -ECP (elliptic curve groups modulo a prime), -or the non-standard Curve25519. +or +ECP (elliptic curve groups modulo a prime). Please note that the EC2N groups are considered as insecure and only provided for backwards compatibility. .Sh EXAMPLES -The first example is intended for a server with clients connecting to +The first example is intended for clients connecting to .Xr iked 8 as an IPsec gateway, or IKEv2 responder, using mutual public key authentication and additional challenge-based EAP-MSCHAPv2 password @@ -901,4 +846,4 @@ file format first appeared in The .Xr iked 8 program was written by -.An Reyk Floeter Aq Mt reyk@openbsd.org . +.An Reyk Floeter Aq reyk@openbsd.org . diff --git a/iked/iked.h b/iked/iked.h index 12cb10c..0430274 100644 --- a/iked/iked.h +++ b/iked/iked.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.h,v 1.89 2015/10/01 10:59:23 reyk Exp $ */ +/* $OpenBSD: iked.h,v 1.56 2013/01/08 10:38:19 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -17,30 +17,29 @@ */ #include -#include -#include -#include +#include "openbsd-compat/sys-tree.h" +#include "openbsd-compat/sys-queue.h" #include #include "types.h" #include "dh.h" -#ifndef IKED_H -#define IKED_H +#ifndef _IKED_H +#define _IKED_H /* * Common IKEv1/IKEv2 header */ struct ike_header { - uint64_t ike_ispi; /* Initiator cookie */ - uint64_t ike_rspi; /* Responder cookie */ - uint8_t ike_nextpayload; /* Next payload type */ - uint8_t ike_version; /* Major/Minor version number */ - uint8_t ike_exchange; /* Exchange type */ - uint8_t ike_flags; /* Message options */ - uint32_t ike_msgid; /* Message identifier */ - uint32_t ike_length; /* Total message length */ + u_int64_t ike_ispi; /* Initiator cookie */ + u_int64_t ike_rspi; /* Responder cookie */ + u_int8_t ike_nextpayload; /* Next payload type */ + u_int8_t ike_version; /* Major/Minor version number */ + u_int8_t ike_exchange; /* Exchange type */ + u_int8_t ike_flags; /* Message options */ + u_int32_t ike_msgid; /* Message identifier */ + u_int32_t ike_length; /* Total message length */ } __packed; /* @@ -51,7 +50,6 @@ struct imsgev { struct imsgbuf ibuf; void (*handler)(int, short, void *); struct event ev; - struct privsep_proc *proc; void *data; short events; const char *name; @@ -81,14 +79,11 @@ struct control_sock { int cs_fd; int cs_restricted; void *cs_env; - - TAILQ_ENTRY(control_sock) cs_entry; }; -TAILQ_HEAD(control_socks, control_sock); struct ctl_conn { TAILQ_ENTRY(ctl_conn) entry; - uint8_t flags; + u_int8_t flags; #define CTL_CONN_NOTIFY 0x01 struct imsgev iev; }; @@ -109,20 +104,20 @@ struct iked_timer { }; struct iked_spi { - uint64_t spi; - uint8_t spi_size; - uint8_t spi_protoid; + u_int64_t spi; + u_int8_t spi_size; + u_int8_t spi_protoid; }; struct iked_proposal { - uint8_t prop_id; - uint8_t prop_protoid; + u_int8_t prop_id; + u_int8_t prop_protoid; struct iked_spi prop_localspi; struct iked_spi prop_peerspi; struct iked_transform *prop_xforms; - unsigned int prop_nxforms; + u_int prop_nxforms; TAILQ_ENTRY(iked_proposal) prop_entry; }; @@ -131,7 +126,7 @@ TAILQ_HEAD(iked_proposals, iked_proposal); struct iked_addr { int addr_af; struct sockaddr_storage addr; - uint8_t addr_mask; + u_int8_t addr_mask; int addr_net; in_port_t addr_port; }; @@ -139,13 +134,17 @@ struct iked_addr { struct iked_flow { struct iked_addr flow_src; struct iked_addr flow_dst; - unsigned int flow_dir; /* in/out */ + u_int flow_dir; /* in/out */ + + u_int flow_loaded; /* pfkey done */ - unsigned int flow_loaded; /* pfkey done */ + u_int8_t flow_saproto; + u_int8_t flow_ipproto; + u_int8_t flow_type; + u_int32_t flow_id; - uint8_t flow_saproto; - uint8_t flow_ipproto; - uint8_t flow_type; + struct iked_id *flow_srcid; + struct iked_id *flow_dstid; struct iked_addr *flow_local; /* outer source */ struct iked_addr *flow_peer; /* outer dest */ @@ -158,24 +157,26 @@ RB_HEAD(iked_flows, iked_flow); TAILQ_HEAD(iked_saflows, iked_flow); struct iked_childsa { - uint8_t csa_saproto; /* IPSec protocol */ - unsigned int csa_dir; /* in/out */ + u_int8_t csa_saproto; /* IPSec protocol */ + u_int csa_dir; /* in/out */ - uint64_t csa_peerspi; /* peer relation */ - uint8_t csa_loaded; /* pfkey done */ - uint8_t csa_rekey; /* will be deleted */ - uint8_t csa_allocated; /* from the kernel */ - uint8_t csa_persistent;/* do not rekey */ - uint8_t csa_esn; /* use ESN */ - uint8_t csa_transport; /* transport mode */ + u_int64_t csa_peerspi; /* peer relation */ + u_int8_t csa_loaded; /* pfkey done */ + u_int8_t csa_rekey; /* will be deleted */ + u_int8_t csa_allocated; /* from the kernel */ + u_int8_t csa_persistent;/* do not rekey */ + u_int8_t csa_esn; /* use ESN */ struct iked_spi csa_spi; struct ibuf *csa_encrkey; /* encryption key */ - uint16_t csa_encrid; /* encryption xform id */ + struct iked_transform *csa_encrxf; /* encryption xform */ struct ibuf *csa_integrkey; /* auth key */ - uint16_t csa_integrid; /* auth xform id */ + struct iked_transform *csa_integrxf; /* auth xform */ + + struct iked_id *csa_srcid; + struct iked_id *csa_dstid; struct iked_addr *csa_local; /* outer source */ struct iked_addr *csa_peer; /* outer dest */ @@ -183,9 +184,6 @@ struct iked_childsa { struct iked_childsa *csa_peersa; /* peer */ - struct iked_childsa *csa_parent; /* IPCOMP parent */ - unsigned int csa_children; /* IPCOMP children */ - RB_ENTRY(iked_childsa) csa_node; TAILQ_ENTRY(iked_childsa) csa_entry; }; @@ -194,36 +192,36 @@ TAILQ_HEAD(iked_childsas, iked_childsa); struct iked_static_id { - uint8_t id_type; - uint8_t id_length; - uint8_t id_offset; - uint8_t id_data[IKED_ID_SIZE]; + u_int8_t id_type; + u_int8_t id_length; + u_int8_t id_offset; + u_int8_t id_data[IKED_ID_SIZE]; }; struct iked_auth { - uint8_t auth_method; - uint8_t auth_eap; /* optional EAP */ - uint8_t auth_length; /* zero if EAP */ - uint8_t auth_data[IKED_PSK_SIZE]; + u_int8_t auth_method; + u_int8_t auth_eap; /* optional EAP */ + u_int8_t auth_length; /* zero if EAP */ + u_int8_t auth_data[IKED_PSK_SIZE]; }; struct iked_cfg { - uint8_t cfg_action; - uint16_t cfg_type; + u_int8_t cfg_action; + u_int16_t cfg_type; union { struct iked_addr address; } cfg; }; -TAILQ_HEAD(iked_sapeers, iked_sa); +RB_HEAD(iked_sapeers, iked_sa); struct iked_lifetime { - uint64_t lt_bytes; - uint64_t lt_seconds; + u_int64_t lt_bytes; + u_int64_t lt_seconds; }; struct iked_policy { - unsigned int pol_id; + u_int pol_id; char pol_name[IKED_ID_SIZE]; #define IKED_SKIP_FLAGS 0 @@ -234,22 +232,19 @@ struct iked_policy { #define IKED_SKIP_COUNT 5 struct iked_policy *pol_skip[IKED_SKIP_COUNT]; - uint8_t pol_flags; + u_int8_t pol_flags; #define IKED_POLICY_PASSIVE 0x00 #define IKED_POLICY_DEFAULT 0x01 #define IKED_POLICY_ACTIVE 0x02 #define IKED_POLICY_REFCNT 0x04 #define IKED_POLICY_QUICK 0x08 #define IKED_POLICY_SKIP 0x10 -#define IKED_POLICY_IPCOMP 0x20 int pol_refcnt; - uint8_t pol_certreqtype; - int pol_af; - uint8_t pol_saproto; - unsigned int pol_ipproto; + u_int8_t pol_saproto; + u_int pol_ipproto; struct iked_addr pol_peer; struct group *pol_peerdh; @@ -261,7 +256,7 @@ struct iked_policy { struct iked_auth pol_auth; char pol_tag[IKED_TAG_SIZE]; - unsigned int pol_tap; + u_int pol_tap; struct iked_proposals pol_proposals; size_t pol_nproposals; @@ -270,10 +265,9 @@ struct iked_policy { size_t pol_nflows; struct iked_cfg pol_cfg[IKED_CFG_MAX]; - unsigned int pol_ncfg; + u_int pol_ncfg; - uint32_t pol_rekey; /* ike SA lifetime */ - struct iked_lifetime pol_lifetime; /* child SA lifetime */ + struct iked_lifetime pol_lifetime; struct iked_sapeers pol_sapeers; @@ -282,8 +276,8 @@ struct iked_policy { TAILQ_HEAD(iked_policies, iked_policy); struct iked_hash { - uint8_t hash_type; /* PRF or INTEGR */ - uint16_t hash_id; /* IKE PRF/INTEGR hash id */ + u_int8_t hash_type; /* PRF or INTEGR */ + u_int16_t hash_id; /* IKE PRF/INTEGR hash id */ const void *hash_priv; /* Identifying the hash alg */ void *hash_ctx; /* Context of the current invocation */ int hash_fixedkey; /* Requires fixed key length */ @@ -294,8 +288,8 @@ struct iked_hash { }; struct iked_cipher { - uint8_t encr_type; /* ENCR */ - uint16_t encr_id; /* IKE ENCR hash id */ + u_int8_t encr_type; /* ENCR */ + u_int16_t encr_id; /* IKE ENCR hash id */ const void *encr_priv; /* Identifying the hash alg */ void *encr_ctx; /* Context of the current invocation */ int encr_fixedkey; /* Requires fixed key length */ @@ -306,7 +300,7 @@ struct iked_cipher { }; struct iked_dsa { - uint8_t dsa_method; /* AUTH method */ + u_int8_t dsa_method; /* AUTH method */ const void *dsa_priv; /* PRF or signature hash function */ void *dsa_ctx; /* PRF or signature hash ctx */ struct ibuf *dsa_keydata; /* public, private or shared key */ @@ -317,54 +311,41 @@ struct iked_dsa { }; struct iked_id { - uint8_t id_type; - uint8_t id_offset; + u_int8_t id_type; + u_int8_t id_offset; struct ibuf *id_buf; }; -#define IKED_REQ_CERT 0x0001 /* get local certificate (if required) */ -#define IKED_REQ_CERTVALID 0x0002 /* validated the peer cert */ -#define IKED_REQ_CERTREQ 0x0004 /* CERTREQ has been received */ -#define IKED_REQ_AUTH 0x0008 /* AUTH payload */ -#define IKED_REQ_AUTHVALID 0x0010 /* AUTH payload has been verified */ -#define IKED_REQ_SA 0x0020 /* SA available */ -#define IKED_REQ_EAPVALID 0x0040 /* EAP payload has been verified */ -#define IKED_REQ_CHILDSA 0x0080 /* Child SA initiated */ -#define IKED_REQ_INF 0x0100 /* Informational exchange initiated */ +#define IKED_REQ_CERT 0x01 /* get local certificate (if required) */ +#define IKED_REQ_VALID 0x02 /* validate the peer cert */ +#define IKED_REQ_AUTH 0x04 /* AUTH payload */ +#define IKED_REQ_SA 0x08 /* SA available */ +#define IKED_REQ_CHILDSA 0x10 /* Child SA initiated */ +#define IKED_REQ_INF 0x20 /* Informational exchange initiated */ +#define IKED_REQ_DELETE 0x40 /* Rekeying continuation */ #define IKED_REQ_BITS \ - "\20\01CERT\02CERTVALID\03CERTREQ\04AUTH\05AUTHVALID\06SA\07EAPVALID" \ - "\10CHILDSA\11INF" + "\10\01CERT\02VALID\03AUTH\04SA" TAILQ_HEAD(iked_msgqueue, iked_message); struct iked_sahdr { - uint64_t sh_ispi; /* Initiator SPI */ - uint64_t sh_rspi; /* Responder SPI */ - unsigned int sh_initiator; /* Is initiator? */ + u_int64_t sh_ispi; /* Initiator SPI */ + u_int64_t sh_rspi; /* Responder SPI */ + u_int sh_initiator; /* Is initiator? */ } __packed; -struct iked_kex { - struct ibuf *kex_inonce; /* Ni */ - struct ibuf *kex_rnonce; /* Nr */ - - struct group *kex_dhgroup; /* DH group */ - struct ibuf *kex_dhiexchange; - struct ibuf *kex_dhrexchange; - struct ibuf *kex_dhpeer; /* pointer to i or r */ -}; - struct iked_sa { struct iked_sahdr sa_hdr; - uint32_t sa_msgid; /* Last request rcvd */ - int sa_msgid_set; /* msgid initialized */ - uint32_t sa_reqid; /* Next request sent */ + u_int32_t sa_msgid; + u_int32_t sa_reqid; int sa_type; #define IKED_SATYPE_LOOKUP 0 /* Used for lookup */ #define IKED_SATYPE_LOCAL 1 /* Local SA */ struct iked_addr sa_peer; + struct iked_addr sa_polpeer; struct iked_addr sa_local; int sa_fd; @@ -372,9 +353,9 @@ struct iked_sa { int sa_udpencap; /* for pfkey */ int sa_state; - unsigned int sa_stateflags; - unsigned int sa_stateinit; /* SA_INIT */ - unsigned int sa_statevalid; /* IKE_AUTH */ + u_int sa_stateflags; + u_int sa_stateinit; /* SA_INIT */ + u_int sa_statevalid; /* IKE_AUTH */ int sa_cp; /* XXX */ @@ -384,14 +365,13 @@ struct iked_sa { char *sa_tag; - struct iked_kex sa_kex; -/* XXX compat defines until everything is converted */ -#define sa_inonce sa_kex.kex_inonce -#define sa_rnonce sa_kex.kex_rnonce -#define sa_dhgroup sa_kex.kex_dhgroup -#define sa_dhiexchange sa_kex.kex_dhiexchange -#define sa_dhrexchange sa_kex.kex_dhrexchange -#define sa_dhpeer sa_kex.kex_dhpeer + struct ibuf *sa_inonce; /* Ni */ + struct ibuf *sa_rnonce; /* Nr */ + + struct group *sa_dhgroup; /* DH group */ + struct ibuf *sa_dhiexchange; + struct ibuf *sa_dhrexchange; + struct ibuf *sa_dhpeer; /* pointer to i or r */ struct iked_hash *sa_prf; /* PRF alg */ struct iked_hash *sa_integr; /* integrity alg */ @@ -408,14 +388,11 @@ struct iked_sa { struct ibuf *sa_1stmsg; /* for initiator AUTH */ struct ibuf *sa_2ndmsg; /* for responder AUTH */ struct iked_id sa_localauth; /* local AUTH message */ - int sa_sigsha2; /* use SHA2 for signatures */ struct iked_id sa_iid; /* initiator id */ struct iked_id sa_rid; /* responder id */ struct iked_id sa_icert; /* initiator cert */ struct iked_id sa_rcert; /* responder cert */ -#define IKESA_SRCID(x) ((x)->sa_hdr.sh_initiator ? &(x)->sa_iid : &(x)->sa_rid) -#define IKESA_DSTID(x) ((x)->sa_hdr.sh_initiator ? &(x)->sa_rid : &(x)->sa_iid) char *sa_eapid; /* EAP identity */ struct iked_id sa_eap; /* EAP challenge */ @@ -425,18 +402,8 @@ struct iked_sa { struct iked_childsas sa_childsas; /* IPSec Child SAs */ struct iked_saflows sa_flows; /* IPSec flows */ - struct iked_sa *sa_next; /* IKE SA rekeying */ - uint64_t sa_rekeyspi; /* peerspi for rekey*/ - - uint8_t sa_ipcomp; /* IPcomp transform */ - uint16_t sa_cpi_out; /* IPcomp outgoing */ - uint16_t sa_cpi_in; /* IPcomp incoming*/ - struct iked_timer sa_timer; /* SA timeouts */ -#define IKED_IKE_SA_DELETE_TIMEOUT 300 /* 5 minutes */ -#define IKED_IKE_SA_ALIVE_TIMEOUT 60 /* 1 minute */ - - struct iked_timer sa_rekey; /* rekey timeout */ +#define IKED_IKE_SA_REKEY_TIMEOUT 300 /* 5 minutes */ struct iked_msgqueue sa_requests; /* request queue */ #define IKED_RETRANSMIT_TIMEOUT 2 /* 2 seconds */ @@ -444,18 +411,14 @@ struct iked_sa { struct iked_msgqueue sa_responses; /* response queue */ #define IKED_RESPONSE_TIMEOUT 120 /* 2 minutes */ - TAILQ_ENTRY(iked_sa) sa_peer_entry; + RB_ENTRY(iked_sa) sa_peer_entry; RB_ENTRY(iked_sa) sa_entry; - - struct iked_addr *sa_addrpool; /* address from pool */ - RB_ENTRY(iked_sa) sa_addrpool_entry; /* pool entries */ }; RB_HEAD(iked_sas, iked_sa); -RB_HEAD(iked_addrpool, iked_sa); struct iked_message { struct ibuf *msg_data; - size_t msg_offset; + off_t msg_offset; struct sockaddr_storage msg_local; socklen_t msg_locallen; @@ -467,7 +430,6 @@ struct iked_message { int msg_fd; int msg_response; - int msg_responded; int msg_natt; int msg_error; int msg_e; @@ -477,8 +439,8 @@ struct iked_message { struct iked_policy *msg_policy; struct iked_sa *msg_sa; - uint32_t msg_msgid; - uint8_t msg_exchange; + u_int32_t msg_msgid; + u_int8_t msg_exchange; /* Parsed information */ struct iked_proposals msg_proposals; @@ -491,7 +453,7 @@ struct iked_message { /* Parse stack */ struct iked_proposal *msg_prop; - uint16_t msg_attrlength; + u_int16_t msg_attrlength; /* Retransmit queue */ struct iked_timer msg_timer; @@ -502,32 +464,20 @@ struct iked_message { }; struct iked_user { - char usr_name[LOGIN_NAME_MAX]; + char usr_name[MAXLOGNAME]; char usr_pass[IKED_PASSWORD_SIZE]; RB_ENTRY(iked_user) usr_entry; }; RB_HEAD(iked_users, iked_user); -struct privsep_pipes { - int *pp_pipes[PROC_MAX]; -}; - struct privsep { - struct privsep_pipes *ps_pipes[PROC_MAX]; - struct privsep_pipes *ps_pp; - - struct imsgev *ps_ievs[PROC_MAX]; + int ps_pipes[PROC_MAX][PROC_MAX]; + struct imsgev ps_ievs[PROC_MAX]; const char *ps_title[PROC_MAX]; pid_t ps_pid[PROC_MAX]; struct passwd *ps_pw; - int ps_noaction; struct control_sock ps_csock; - struct control_socks ps_rcsocks; - - unsigned int ps_instances[PROC_MAX]; - unsigned int ps_ninstances; - unsigned int ps_instance; /* Event and signal handlers */ struct event ps_evsigint; @@ -535,7 +485,6 @@ struct privsep { struct event ps_evsigchld; struct event ps_evsighup; struct event ps_evsigpipe; - struct event ps_evsigusr1; struct iked *ps_env; }; @@ -550,26 +499,18 @@ struct privsep_proc { const char *p_chroot; struct privsep *p_ps; struct iked *p_env; - void (*p_shutdown)(void); - unsigned int p_instance; -}; - -struct iked_ocsp_entry { - TAILQ_ENTRY(iked_ocsp_entry) ioe_entry; /* next request */ - void *ioe_ocsp; /* private ocsp request data */ }; -TAILQ_HEAD(iked_ocsp_requests, iked_ocsp_entry); /* * Daemon configuration */ struct iked { - char sc_conffile[PATH_MAX]; + char sc_conffile[MAXPATHLEN]; - uint32_t sc_opts; - uint8_t sc_passive; - uint8_t sc_decoupled; + u_int32_t sc_opts; + u_int8_t sc_passive; + u_int8_t sc_decoupled; struct iked_policies sc_policies; struct iked_policy *sc_defaultcon; @@ -583,7 +524,7 @@ struct iked { int sc_pfkey; /* ike process */ struct event sc_pfkeyev; - uint8_t sc_certreqtype; + u_int8_t sc_certreqtype; struct ibuf *sc_certreq; struct iked_socket *sc_sock4[2]; @@ -594,11 +535,6 @@ struct iked { #define IKED_INITIATOR_INTERVAL 60 struct privsep sc_ps; - - struct iked_ocsp_requests sc_ocsp; - char *sc_ocsp_url; - - struct iked_addrpool sc_addrpool; }; struct iked_socket { @@ -619,32 +555,30 @@ void control_cleanup(struct control_sock *); /* config.c */ struct iked_policy * config_new_policy(struct iked *); -void config_free_kex(struct iked_kex *); void config_free_sa(struct iked *, struct iked_sa *); struct iked_sa * config_new_sa(struct iked *, int); struct iked_user * config_new_user(struct iked *, struct iked_user *); -uint64_t +u_int64_t config_getspi(void); struct iked_transform * - config_findtransform(struct iked_proposals *, uint8_t, unsigned int); + config_findtransform(struct iked_proposals *, u_int8_t); void config_free_policy(struct iked *, struct iked_policy *); struct iked_proposal * - config_add_proposal(struct iked_proposals *, unsigned int, - unsigned int); -void config_free_proposals(struct iked_proposals *, unsigned int); + config_add_proposal(struct iked_proposals *, u_int, u_int); +void config_free_proposals(struct iked_proposals *, u_int); void config_free_flows(struct iked *, struct iked_flows *); void config_free_childsas(struct iked *, struct iked_childsas *, struct iked_spi *, struct iked_spi *); struct iked_transform * config_add_transform(struct iked_proposal *, - unsigned int, unsigned int, unsigned int, unsigned int); -int config_setcoupled(struct iked *, unsigned int); -int config_getcoupled(struct iked *, unsigned int); -int config_setmode(struct iked *, unsigned int); -int config_getmode(struct iked *, unsigned int); -int config_setreset(struct iked *, unsigned int, enum privsep_procid); + u_int, u_int, u_int, u_int); +int config_setcoupled(struct iked *, u_int); +int config_getcoupled(struct iked *, u_int); +int config_setmode(struct iked *, u_int); +int config_getmode(struct iked *, u_int); +int config_setreset(struct iked *, u_int, enum privsep_procid); int config_getreset(struct iked *, struct imsg *); int config_setpolicy(struct iked *, struct iked_policy *, enum privsep_procid); @@ -659,8 +593,6 @@ int config_setuser(struct iked *, struct iked_user *, enum privsep_procid); int config_getuser(struct iked *, struct imsg *); int config_setcompile(struct iked *, enum privsep_procid); int config_getcompile(struct iked *, struct imsg *); -int config_setocsp(struct iked *); -int config_getocsp(struct iked *, struct imsg *); /* policy.c */ void policy_init(struct iked *); @@ -671,32 +603,34 @@ void policy_calc_skip_steps(struct iked_policies *); void policy_ref(struct iked *, struct iked_policy *); void policy_unref(struct iked *, struct iked_policy *); void sa_state(struct iked *, struct iked_sa *, int); -void sa_stateflags(struct iked_sa *, unsigned int); +void sa_stateflags(struct iked_sa *, u_int); int sa_stateok(struct iked_sa *, int); struct iked_sa * - sa_new(struct iked *, uint64_t, uint64_t, unsigned int, + sa_new(struct iked *, u_int64_t, u_int64_t, u_int, struct iked_policy *); void sa_free(struct iked *, struct iked_sa *); void sa_free_flows(struct iked *, struct iked_saflows *); int sa_address(struct iked_sa *, struct iked_addr *, - struct sockaddr_storage *); + struct sockaddr_storage *, int); void childsa_free(struct iked_childsa *); struct iked_childsa * - childsa_lookup(struct iked_sa *, uint64_t, uint8_t); + childsa_lookup(struct iked_sa *, u_int64_t, u_int8_t); void flow_free(struct iked_flow *); struct iked_sa * - sa_lookup(struct iked *, uint64_t, uint64_t, unsigned int); + sa_lookup(struct iked *, u_int64_t, u_int64_t, u_int); +struct iked_sa * + sa_peer_lookup(struct iked_policy *, struct sockaddr_storage *); struct iked_user * user_lookup(struct iked *, const char *); RB_PROTOTYPE(iked_sas, iked_sa, sa_entry, sa_cmp); -RB_PROTOTYPE(iked_addrpool, iked_sa, sa_addrpool_entry, sa_addrpool_cmp); +RB_PROTOTYPE(iked_sapeers, iked_sa, sa_peer_entry, sa_peer_cmp); RB_PROTOTYPE(iked_users, iked_user, user_entry, user_cmp); RB_PROTOTYPE(iked_activesas, iked_childsa, csa_node, childsa_cmp); RB_PROTOTYPE(iked_flows, iked_flow, flow_node, flow_cmp); /* crypto.c */ struct iked_hash * - hash_new(uint8_t, uint16_t); + hash_new(u_int8_t, u_int16_t); struct ibuf * hash_setkey(struct iked_hash *, void *, size_t); void hash_free(struct iked_hash *); @@ -707,7 +641,7 @@ size_t hash_keylength(struct iked_hash *); size_t hash_length(struct iked_hash *); struct iked_cipher * - cipher_new(uint8_t, uint16_t, uint16_t); + cipher_new(u_int8_t, u_int16_t, u_int16_t); struct ibuf * cipher_setkey(struct iked_cipher *, void *, size_t); struct ibuf * @@ -724,15 +658,15 @@ size_t cipher_ivlength(struct iked_cipher *); size_t cipher_outlength(struct iked_cipher *, size_t); struct iked_dsa * - dsa_new(uint16_t, struct iked_hash *, int); + dsa_new(u_int16_t, struct iked_hash *, int); struct iked_dsa * - dsa_sign_new(uint16_t, struct iked_hash *); + dsa_sign_new(u_int16_t, struct iked_hash *); struct iked_dsa * - dsa_verify_new(uint16_t, struct iked_hash *); + dsa_verify_new(u_int16_t, struct iked_hash *); struct ibuf * - dsa_setkey(struct iked_dsa *, void *, size_t, uint8_t); + dsa_setkey(struct iked_dsa *, void *, size_t, u_int8_t); void dsa_free(struct iked_dsa *); -int dsa_init(struct iked_dsa *, const void *, size_t); +int dsa_init(struct iked_dsa *); size_t dsa_length(struct iked_dsa *); int dsa_update(struct iked_dsa *, const void *, size_t); ssize_t dsa_sign_final(struct iked_dsa *, void *, size_t); @@ -745,34 +679,34 @@ pid_t ikev1(struct privsep *, struct privsep_proc *); pid_t ikev2(struct privsep *, struct privsep_proc *); void ikev2_recv(struct iked *, struct iked_message *); void ikev2_init_ike_sa(struct iked *, void *); -int ikev2_sa_negotiate(struct iked_proposals *, struct iked_proposals *, +int ikev2_sa_negotiate(struct iked_sa *, struct iked_proposals *, struct iked_proposals *); int ikev2_policy2id(struct iked_static_id *, struct iked_id *, int); int ikev2_childsa_enable(struct iked *, struct iked_sa *); int ikev2_childsa_delete(struct iked *, struct iked_sa *, - uint8_t, uint64_t, uint64_t *, int); + u_int8_t, u_int64_t, u_int64_t *, int); struct ibuf * ikev2_prfplus(struct iked_hash *, struct ibuf *, struct ibuf *, size_t); -ssize_t ikev2_psk(struct iked_sa *, uint8_t *, size_t, uint8_t **); +ssize_t ikev2_psk(struct iked_sa *, u_int8_t *, size_t, u_int8_t **); ssize_t ikev2_nat_detection(struct iked *, struct iked_message *, - void *, size_t, unsigned int); + void *, size_t, u_int); int ikev2_send_informational(struct iked *, struct iked_message *); int ikev2_send_ike_e(struct iked *, struct iked_sa *, struct ibuf *, - uint8_t, uint8_t, int); + u_int8_t, u_int8_t, int); struct ike_header * ikev2_add_header(struct ibuf *, struct iked_sa *, - uint32_t, uint8_t, uint8_t, uint8_t); + u_int32_t, u_int8_t, u_int8_t, u_int8_t); int ikev2_set_header(struct ike_header *, size_t); struct ikev2_payload * ikev2_add_payload(struct ibuf *); int ikev2_next_payload(struct ikev2_payload *, size_t, - uint8_t); -int ikev2_acquire_sa(struct iked *, struct iked_flow *); + u_int8_t); +void ikev2_acquire_sa(struct iked *, struct iked_flow *); void ikev2_disable_rekeying(struct iked *, struct iked_sa *); -int ikev2_rekey_sa(struct iked *, struct iked_spi *); -int ikev2_drop_sa(struct iked *, struct iked_spi *); +void ikev2_rekey_sa(struct iked *, struct iked_spi *); +void ikev2_drop_sa(struct iked *, struct iked_spi *); int ikev2_print_id(struct iked_id *, char *, size_t); /* ikev2_msg.c */ @@ -784,19 +718,19 @@ struct ibuf * struct iked_message * ikev2_msg_copy(struct iked *, struct iked_message *); void ikev2_msg_cleanup(struct iked *, struct iked_message *); -uint32_t +u_int32_t ikev2_msg_id(struct iked *, struct iked_sa *); struct ibuf *ikev2_msg_auth(struct iked *, struct iked_sa *, int); int ikev2_msg_authsign(struct iked *, struct iked_sa *, struct iked_auth *, struct ibuf *); int ikev2_msg_authverify(struct iked *, struct iked_sa *, - struct iked_auth *, uint8_t *, size_t, struct ibuf *); + struct iked_auth *, u_int8_t *, size_t, struct ibuf *); int ikev2_msg_valid_ike_sa(struct iked *, struct ike_header *, struct iked_message *); int ikev2_msg_send(struct iked *, struct iked_message *); int ikev2_msg_send_encrypt(struct iked *, struct iked_sa *, - struct ibuf **, uint8_t, uint8_t, int); + struct ibuf **, u_int8_t, u_int8_t, int); struct ibuf *ikev2_msg_encrypt(struct iked *, struct iked_sa *, struct ibuf *); struct ibuf * @@ -819,7 +753,7 @@ struct iked_message * /* ikev2_pld.c */ int ikev2_pld_parse(struct iked *, struct ike_header *, - struct iked_message *, size_t); + struct iked_message *, off_t); /* eap.c */ ssize_t eap_identity_request(struct ibuf *); @@ -829,93 +763,88 @@ int eap_parse(struct iked *, struct iked_sa *, void *, int); int pfkey_couple(int, struct iked_sas *, int); int pfkey_flow_add(int fd, struct iked_flow *); int pfkey_flow_delete(int fd, struct iked_flow *); -int pfkey_block(int, int, unsigned int); -int pfkey_sa_init(int, struct iked_childsa *, uint32_t *); +int pfkey_block(int, int, u_int); +int pfkey_sa_init(int, struct iked_childsa *, u_int32_t *); int pfkey_sa_add(int, struct iked_childsa *, struct iked_childsa *); int pfkey_sa_delete(int, struct iked_childsa *); -int pfkey_sa_last_used(int, struct iked_childsa *, uint64_t *); -int pfkey_flush(int); +int pfkey_flush(int, u_int); int pfkey_socket(void); void pfkey_init(struct iked *, int fd); /* ca.c */ pid_t caproc(struct privsep *, struct privsep_proc *); -int ca_setreq(struct iked *, struct iked_sa *, struct iked_static_id *, - uint8_t, uint8_t *, size_t, enum privsep_procid); +int ca_setreq(struct iked *, struct iked_sahdr *, struct iked_static_id *, + u_int8_t, u_int8_t *, size_t, enum privsep_procid); int ca_setcert(struct iked *, struct iked_sahdr *, struct iked_id *, - uint8_t, uint8_t *, size_t, enum privsep_procid); + u_int8_t, u_int8_t *, size_t, enum privsep_procid); int ca_setauth(struct iked *, struct iked_sa *, struct ibuf *, enum privsep_procid); void ca_sslinit(void); -void ca_sslerror(const char *); -char *ca_asn1_name(uint8_t *, size_t); +void ca_sslerror(void); +char *ca_asn1_name(u_int8_t *, size_t); char *ca_x509_name(void *); -void *ca_x509_name_parse(char *); /* timer.c */ -void timer_set(struct iked *, struct iked_timer *, +void timer_initialize(struct iked *, struct iked_timer *, void (*)(struct iked *, void *), void *); -void timer_add(struct iked *, struct iked_timer *, int); -void timer_del(struct iked *, struct iked_timer *); +int timer_initialized(struct iked *, struct iked_timer *); +void timer_register(struct iked *, struct iked_timer *, int); +void timer_deregister(struct iked *, struct iked_timer *); /* proc.c */ -void proc_init(struct privsep *, struct privsep_proc *, unsigned int); +void proc_init(struct privsep *, struct privsep_proc *, u_int); void proc_kill(struct privsep *); -void proc_listen(struct privsep *, struct privsep_proc *, size_t); +void proc_config(struct privsep *, struct privsep_proc *, u_int); void proc_dispatch(int, short event, void *); pid_t proc_run(struct privsep *, struct privsep_proc *, - struct privsep_proc *, unsigned int, - void (*)(struct privsep *, struct privsep_proc *, void *), void *); + struct privsep_proc *, u_int, + void (*)(struct privsep *, void *), void *); void imsg_event_add(struct imsgev *); -int imsg_compose_event(struct imsgev *, uint16_t, uint32_t, - pid_t, int, void *, uint16_t); -int imsg_composev_event(struct imsgev *, uint16_t, uint32_t, +int imsg_compose_event(struct imsgev *, u_int16_t, u_int32_t, + pid_t, int, void *, u_int16_t); +int imsg_composev_event(struct imsgev *, u_int16_t, u_int32_t, pid_t, int, const struct iovec *, int); -int proc_compose_imsg(struct privsep *, enum privsep_procid, int, - uint16_t, int, void *, uint16_t); -int proc_composev_imsg(struct privsep *, enum privsep_procid, int, - uint16_t, int, const struct iovec *, int); -int proc_forward_imsg(struct privsep *, struct imsg *, - enum privsep_procid, int); -struct imsgbuf * - proc_ibuf(struct privsep *, enum privsep_procid, int); -struct imsgev * - proc_iev(struct privsep *, enum privsep_procid, int); +int proc_compose_imsg(struct iked *, enum privsep_procid, + u_int16_t, int, void *, u_int16_t); +int proc_composev_imsg(struct iked *, enum privsep_procid, + u_int16_t, int, const struct iovec *, int); +int proc_forward_imsg(struct iked *, struct imsg *, + enum privsep_procid); +void proc_flush_imsg(struct iked *, enum privsep_procid); /* util.c */ void socket_set_blockmode(int, enum blockmodes); int socket_af(struct sockaddr *, in_port_t); in_port_t - socket_getport(struct sockaddr *); -int socket_setport(struct sockaddr *, in_port_t); + socket_getport(struct sockaddr_storage *); int socket_getaddr(int, struct sockaddr_storage *); int socket_bypass(int, struct sockaddr *); int udp_bind(struct sockaddr *, in_port_t); ssize_t recvfromto(int, void *, size_t, int, struct sockaddr *, socklen_t *, struct sockaddr *, socklen_t *); const char * - print_spi(uint64_t, int); + print_spi(u_int64_t, int); const char * - print_map(unsigned int, struct iked_constmap *); + print_map(u_int, struct iked_constmap *); void lc_string(char *); -void print_hex(uint8_t *, off_t, size_t); -void print_hexval(uint8_t *, off_t, size_t); +void print_hex(u_int8_t *, off_t, size_t); +void print_hexval(u_int8_t *, off_t, size_t); const char * - print_bits(unsigned short, unsigned char *); + print_bits(u_short, char *); int sockaddr_cmp(struct sockaddr *, struct sockaddr *, int); -uint8_t mask2prefixlen(struct sockaddr *); -uint8_t mask2prefixlen6(struct sockaddr *); +u_int8_t mask2prefixlen(struct sockaddr *); +u_int8_t mask2prefixlen6(struct sockaddr *); struct in6_addr * - prefixlen2mask6(uint8_t, uint32_t *); -uint32_t - prefixlen2mask(uint8_t); + prefixlen2mask6(u_int8_t, u_int32_t *); +u_int32_t + prefixlen2mask(u_int8_t); const char * - print_host(struct sockaddr *, char *, size_t); -char *get_string(uint8_t *, size_t); + print_host(struct sockaddr_storage *, char *, size_t); +char *get_string(u_int8_t *, size_t); const char * - print_proto(uint8_t); + print_proto(u_int8_t); int expand_string(char *, size_t, const char *, const char *); -uint8_t *string2unicode(const char *, size_t *); +u_int8_t *string2unicode(const char *, size_t *); /* imsg_util.c */ struct ibuf * @@ -926,7 +855,7 @@ int ibuf_cat(struct ibuf *, struct ibuf *); void ibuf_release(struct ibuf *); size_t ibuf_length(struct ibuf *); int ibuf_setsize(struct ibuf *, size_t); -uint8_t * +u_int8_t * ibuf_data(struct ibuf *); void *ibuf_getdata(struct ibuf *, size_t); struct ibuf * @@ -942,27 +871,21 @@ void ibuf_zero(struct ibuf *); /* log.c */ void log_init(int); void log_verbose(int); -void log_warn(const char *, ...) __attribute__((format(printf, 1, 2))); -void log_warnx(const char *, ...) __attribute__((format(printf, 1, 2))); -void log_info(const char *, ...) __attribute__((format(printf, 1, 2))); -void log_debug(const char *, ...) __attribute__((format(printf, 1, 2))); -void print_debug(const char *, ...) __attribute__((format(printf, 1, 2))); -void print_verbose(const char *, ...) __attribute__((format(printf, 1, 2))); +void log_warn(const char *, ...); +void log_warnx(const char *, ...); +void log_info(const char *, ...); +void log_debug(const char *, ...); +void print_debug(const char *, ...); +void print_verbose(const char *, ...); __dead void fatal(const char *); __dead void fatalx(const char *); -/* ocsp.c */ -int ocsp_connect(struct iked *env); -int ocsp_receive_fd(struct iked *, struct imsg *); -int ocsp_validate_cert(struct iked *, struct iked_static_id *, - void *, size_t, struct iked_sahdr, uint8_t); - /* parse.y */ int parse_config(const char *, struct iked *); void print_user(struct iked_user *); void print_policy(struct iked_policy *); -size_t keylength_xf(unsigned int, unsigned int, unsigned int); -size_t noncelength_xf(unsigned int, unsigned int); +size_t keylength_xf(u_int, u_int, u_int); +size_t noncelength_xf(u_int, u_int); int cmdline_symset(char *); -#endif /* IKED_H */ +#endif /* _IKED_H */ diff --git a/iked/ikev1.c b/iked/ikev1.c index dd2f3ec..fc4f6b2 100644 --- a/iked/ikev1.c +++ b/iked/ikev1.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev1.c,v 1.18 2015/08/21 11:59:27 reyk Exp $ */ +/* $OpenBSD: ikev1.c,v 1.13 2013/03/21 04:30:14 deraadt Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -22,7 +22,8 @@ * XXX or remove this file and ikev1 from the iked tree. */ -#include +#include +#include "openbsd-compat/sys-queue.h" #include #include #include @@ -31,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -90,7 +92,7 @@ ikev1_dispatch_ikev2(int fd, struct privsep_proc *p, struct imsg *imsg) { struct iked *env = p->p_env; struct iked_message msg; - uint8_t *buf; + u_int8_t *buf; ssize_t len; switch (imsg->hdr.type) { @@ -100,13 +102,13 @@ ikev1_dispatch_ikev2(int fd, struct privsep_proc *p, struct imsg *imsg) memcpy(&msg, imsg->data, sizeof(msg)); len = IMSG_DATA_SIZE(imsg) - sizeof(msg); - buf = (uint8_t *)imsg->data + sizeof(msg); + buf = (u_int8_t *)imsg->data + sizeof(msg); if (len <= 0 || (msg.msg_data = ibuf_new(buf, len)) == NULL) { log_debug("%s: short message", __func__); return (0); } - log_debug("%s: message length %zd", __func__, len); + log_debug("%s: message length %d", __func__, len); ikev1_recv(env, &msg); ikev2_msg_cleanup(env, &msg); @@ -131,7 +133,7 @@ ikev1_msg_cb(int fd, short event, void *arg) struct iked *env = sock->sock_env; struct iked_message msg; struct ike_header hdr; - uint8_t buf[IKED_MSGBUF_MAX]; + u_int8_t buf[IKED_MSGBUF_MAX]; size_t len; struct iovec iov[2]; @@ -156,8 +158,8 @@ ikev1_msg_cb(int fd, short event, void *arg) iov[1].iov_base = buf; iov[1].iov_len = len; - proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, - IMSG_IKE_MESSAGE, -1, iov, 2); + proc_composev_imsg(env, PROC_IKEV2, IMSG_IKE_MESSAGE, -1, + iov, 2); goto done; } diff --git a/iked/ikev2.c b/iked/ikev2.c index 9b1ee9b..a24af78 100644 --- a/iked/ikev2.c +++ b/iked/ikev2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.c,v 1.125 2015/10/02 16:13:43 reyk Exp $ */ +/* $OpenBSD: ikev2.c,v 1.82 2013/03/21 04:30:14 deraadt Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,20 +16,24 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include /* roundup */ -#include +#include +#include "openbsd-compat/sys-queue.h" #include #include #include +#include #include +#if defined(__OpenBSD__) #include +#endif #include #include #include #include #include +#include #include #include #include @@ -38,7 +42,6 @@ #include #include -#include #include "iked.h" #include "ikev2.h" @@ -51,13 +54,11 @@ int ikev2_dispatch_cert(int, struct privsep_proc *, struct imsg *); struct iked_sa * ikev2_getimsgdata(struct iked *, struct imsg *, struct iked_sahdr *, - uint8_t *, uint8_t **, size_t *); + u_int8_t *, u_int8_t **, size_t *); void ikev2_recv(struct iked *, struct iked_message *); -int ikev2_ike_auth_compatible(struct iked_sa *, uint8_t, uint8_t); -int ikev2_ike_auth_recv(struct iked *, struct iked_sa *, +int ikev2_ike_auth(struct iked *, struct iked_sa *, struct iked_message *); -int ikev2_ike_auth(struct iked *, struct iked_sa *); void ikev2_init_recv(struct iked *, struct iked_message *, struct ike_header *); @@ -74,61 +75,35 @@ int ikev2_resp_ike_auth(struct iked *, struct iked_sa *); int ikev2_resp_ike_eap(struct iked *, struct iked_sa *, struct ibuf *); int ikev2_send_create_child_sa(struct iked *, struct iked_sa *, - struct iked_spi *, uint8_t); -int ikev2_ikesa_enable(struct iked *, struct iked_sa *, struct iked_sa *); -void ikev2_ikesa_delete(struct iked *, struct iked_sa *, int); + struct iked_spi *, u_int8_t); int ikev2_init_create_child_sa(struct iked *, struct iked_message *); int ikev2_resp_create_child_sa(struct iked *, struct iked_message *); -void ikev2_ike_sa_rekey(struct iked *, void *); void ikev2_ike_sa_timeout(struct iked *env, void *); -void ikev2_ike_sa_alive(struct iked *, void *); int ikev2_sa_initiator(struct iked *, struct iked_sa *, - struct iked_sa *, struct iked_message *); + struct iked_message *); int ikev2_sa_responder(struct iked *, struct iked_sa *, struct iked_sa *, struct iked_message *); -int ikev2_sa_initiator_dh(struct iked_sa *, struct iked_message *, - unsigned int); -int ikev2_sa_responder_dh(struct iked_kex *, struct iked_proposals *, - struct iked_message *, unsigned int); -void ikev2_sa_cleanup_dh(struct iked_sa *); int ikev2_sa_keys(struct iked *, struct iked_sa *, struct ibuf *); int ikev2_sa_tag(struct iked_sa *, struct iked_id *); -int ikev2_set_sa_proposal(struct iked_sa *, struct iked_policy *, - unsigned int); -int ikev2_childsa_negotiate(struct iked *, struct iked_sa *, - struct iked_kex *, struct iked_proposals *, int, int); +int ikev2_childsa_negotiate(struct iked *, struct iked_sa *, int); int ikev2_match_proposals(struct iked_proposal *, struct iked_proposal *, struct iked_transform **); int ikev2_valid_proposal(struct iked_proposal *, struct iked_transform **, struct iked_transform **, int *); ssize_t ikev2_add_proposals(struct iked *, struct iked_sa *, struct ibuf *, - struct iked_proposals *, uint8_t, int, int); + struct iked_proposals *, u_int8_t, int, int); ssize_t ikev2_add_cp(struct iked *, struct iked_sa *, struct ibuf *); ssize_t ikev2_add_transform(struct ibuf *, - uint8_t, uint8_t, uint16_t, uint16_t); + u_int8_t, u_int8_t, u_int16_t, u_int16_t); ssize_t ikev2_add_ts(struct ibuf *, struct ikev2_payload **, ssize_t, struct iked_sa *, int); -ssize_t ikev2_add_certreq(struct ibuf *, struct ikev2_payload **, ssize_t, - struct ibuf *, uint8_t); -ssize_t ikev2_add_ipcompnotify(struct iked *, struct ibuf *, - struct ikev2_payload **, ssize_t, struct iked_sa *); -ssize_t ikev2_add_ts_payload(struct ibuf *, unsigned int, struct iked_sa *); +ssize_t ikev2_add_ts_payload(struct ibuf *, u_int, struct iked_sa *); int ikev2_add_data(struct ibuf *, void *, size_t); int ikev2_add_buf(struct ibuf *buf, struct ibuf *); -int ikev2_ipcomp_enable(struct iked *, struct iked_sa *); -void ikev2_ipcomp_csa_free(struct iked *, struct iked_childsa *); - -int ikev2_cp_setaddr(struct iked *, struct iked_sa *); -int ikev2_cp_fixaddr(struct iked_sa *, struct iked_addr *, - struct iked_addr *); - -ssize_t ikev2_add_sighashnotify(struct ibuf *, struct ikev2_payload **, - ssize_t); - static struct privsep_proc procs[] = { { "parent", PROC_PARENT, ikev2_dispatch_parent }, { "ikev1", PROC_IKEV1, ikev2_dispatch_ikev1 }, @@ -156,9 +131,9 @@ ikev2_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) case IMSG_CTL_PASSIVE: if (config_getmode(env, imsg->hdr.type) == -1) return (0); /* ignore error */ - timer_set(env, &env->sc_inittmr, ikev2_init_ike_sa, + timer_initialize(env, &env->sc_inittmr, ikev2_init_ike_sa, NULL); - timer_add(env, &env->sc_inittmr, IKED_INITIATOR_INITIAL); + timer_register(env, &env->sc_inittmr, IKED_INITIATOR_INITIAL); return (0); case IMSG_UDP_SOCKET: return (config_getsocket(env, imsg, ikev2_msg_cb)); @@ -182,7 +157,7 @@ ikev2_dispatch_ikev1(int fd, struct privsep_proc *p, struct imsg *imsg) { struct iked *env = p->p_env; struct iked_message msg; - uint8_t *buf; + u_int8_t *buf; ssize_t len; switch (imsg->hdr.type) { @@ -192,13 +167,13 @@ ikev2_dispatch_ikev1(int fd, struct privsep_proc *p, struct imsg *imsg) memcpy(&msg, imsg->data, sizeof(msg)); len = IMSG_DATA_SIZE(imsg) - sizeof(msg); - buf = (uint8_t *)imsg->data + sizeof(msg); + buf = (u_int8_t *)imsg->data + sizeof(msg); if (len <= 0 || (msg.msg_data = ibuf_new(buf, len)) == NULL) { log_debug("%s: short message", __func__); return (0); } - log_debug("%s: message length %zd", __func__, len); + log_debug("%s: message length %d", __func__, len); ikev2_recv(env, &msg); ikev2_msg_cleanup(env, &msg); @@ -216,11 +191,10 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) struct iked *env = p->p_env; struct iked_sahdr sh; struct iked_sa *sa; - uint8_t type; - uint8_t *ptr; + u_int8_t type; + u_int8_t *ptr; size_t len; struct iked_id *id = NULL; - int ignore = 0; switch (imsg->hdr.type) { case IMSG_CERTREQ: @@ -235,15 +209,14 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) env->sc_certreq = ibuf_new(ptr, IMSG_DATA_SIZE(imsg) - sizeof(type)); - log_debug("%s: updated local CERTREQ type %s length %zu", - __func__, print_map(type, ikev2_cert_map), - ibuf_length(env->sc_certreq)); + log_debug("%s: updated local CERTREQ signatures length %d", + __func__, ibuf_length(env->sc_certreq)); break; case IMSG_CERTVALID: case IMSG_CERTINVALID: memcpy(&sh, imsg->data, sizeof(sh)); - memcpy(&type, (uint8_t *)imsg->data + sizeof(sh), + memcpy(&type, (u_int8_t *)imsg->data + sizeof(sh), sizeof(type)); /* Ignore invalid or unauthenticated SAs */ @@ -254,12 +227,13 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) if (imsg->hdr.type == IMSG_CERTVALID) { log_debug("%s: peer certificate is valid", __func__); - sa_stateflags(sa, IKED_REQ_CERTVALID); + sa_stateflags(sa, IKED_REQ_VALID); + sa_state(env, sa, IKEV2_STATE_VALID); } else { log_warnx("%s: peer certificate is invalid", __func__); } - if (ikev2_ike_auth(env, sa) != 0) + if (ikev2_ike_auth(env, sa, NULL) != 0) log_debug("%s: failed to send ike auth", __func__); break; case IMSG_CERT: @@ -269,21 +243,6 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) break; } - /* - * Ignore the message if we already got a valid certificate. - * This might happen if the peer sent multiple CERTREQs. - */ - if (sa->sa_stateflags & IKED_REQ_CERT || - type == IKEV2_CERT_NONE) - ignore = 1; - - log_debug("%s: cert type %s length %zu, %s", __func__, - print_map(type, ikev2_cert_map), len, - ignore ? "ignored" : "ok"); - - if (ignore) - break; - if (sh.sh_initiator) id = &sa->sa_icert; else @@ -294,15 +253,21 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) ibuf_release(id->id_buf); id->id_buf = NULL; - if (len <= 0 || (id->id_buf = ibuf_new(ptr, len)) == NULL) { - log_debug("%s: failed to get cert payload", - __func__); - break; + if (type != IKEV2_CERT_NONE) { + if (len <= 0 || + (id->id_buf = ibuf_new(ptr, len)) == NULL) { + log_debug("%s: failed to get cert payload", + __func__); + break; + } } + log_debug("%s: cert type %d length %d", __func__, + id->id_type, ibuf_length(id->id_buf)); + sa_stateflags(sa, IKED_REQ_CERT); - if (ikev2_ike_auth(env, sa) != 0) + if (ikev2_ike_auth(env, sa, NULL) != 0) log_debug("%s: failed to send ike auth", __func__); break; case IMSG_AUTH: @@ -311,13 +276,8 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) log_debug("%s: invalid auth reply", __func__); break; } - if (sa_stateok(sa, IKEV2_STATE_VALID)) { - log_warnx("%s: ignoring AUTH in state %s", __func__, - print_map(sa->sa_state, ikev2_state_map)); - break; - } - log_debug("%s: AUTH type %d len %zu", __func__, type, len); + log_debug("%s: AUTH type %d len %d", __func__, type, len); id = &sa->sa_localauth; id->id_type = type; @@ -335,7 +295,7 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) sa_stateflags(sa, IKED_REQ_AUTH); - if (ikev2_ike_auth(env, sa) != 0) + if (ikev2_ike_auth(env, sa, NULL) != 0) log_debug("%s: failed to send ike auth", __func__); break; default: @@ -347,9 +307,9 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) struct iked_sa * ikev2_getimsgdata(struct iked *env, struct imsg *imsg, struct iked_sahdr *sh, - uint8_t *type, uint8_t **buf, size_t *size) + u_int8_t *type, u_int8_t **buf, size_t *size) { - uint8_t *ptr; + u_int8_t *ptr; size_t len; struct iked_sa *sa; @@ -363,7 +323,7 @@ ikev2_getimsgdata(struct iked *env, struct imsg *imsg, struct iked_sahdr *sh, sa = sa_lookup(env, sh->sh_ispi, sh->sh_rspi, sh->sh_initiator); log_debug("%s: imsg %d rspi %s ispi %s initiator %d sa %s" - " type %d data length %zd", + " type %d data length %d", __func__, imsg->hdr.type, print_spi(sh->sh_rspi, 8), print_spi(sh->sh_ispi, 8), @@ -385,16 +345,17 @@ ikev2_recv(struct iked *env, struct iked_message *msg) struct ike_header *hdr; struct iked_message *m; struct iked_sa *sa; - unsigned int initiator, flag = 0; + u_int initiator, flag = 0; + int response; hdr = ibuf_seek(msg->msg_data, msg->msg_offset, sizeof(*hdr)); - if (hdr == NULL || ibuf_size(msg->msg_data) < + if (hdr == NULL || (ssize_t)ibuf_size(msg->msg_data) < (betoh32(hdr->ike_length) - msg->msg_offset)) return; initiator = (hdr->ike_flags & IKEV2_FLAG_INITIATOR) ? 0 : 1; - msg->msg_response = (hdr->ike_flags & IKEV2_FLAG_RESPONSE) ? 1 : 0; + response = (hdr->ike_flags & IKEV2_FLAG_RESPONSE) ? 1 : 0; msg->msg_sa = sa_lookup(env, betoh64(hdr->ike_ispi), betoh64(hdr->ike_rspi), initiator); @@ -402,12 +363,11 @@ ikev2_recv(struct iked *env, struct iked_message *msg) if (policy_lookup(env, msg) != 0) return; - log_info("%s: %s %s from %s %s to %s policy '%s' id %u, %ld bytes", + log_info("%s: %s from %s %s to %s policy '%s' id %u, %ld bytes", __func__, print_map(hdr->ike_exchange, ikev2_exchange_map), - msg->msg_response ? "response" : "request", initiator ? "responder" : "initiator", - print_host((struct sockaddr *)&msg->msg_peer, NULL, 0), - print_host((struct sockaddr *)&msg->msg_local, NULL, 0), + print_host(&msg->msg_peer, NULL, 0), + print_host(&msg->msg_local, NULL, 0), msg->msg_policy->pol_name, msg->msg_msgid, ibuf_length(msg->msg_data)); log_debug("%s: ispi %s rspi %s", __func__, @@ -422,7 +382,7 @@ ikev2_recv(struct iked *env, struct iked_message *msg) if (hdr->ike_exchange == IKEV2_EXCHANGE_INFORMATIONAL) flag = IKED_REQ_INF; - if (msg->msg_response) { + if (response) { if (msg->msg_msgid > sa->sa_reqid) return; if (hdr->ike_exchange != IKEV2_EXCHANGE_INFORMATIONAL && @@ -431,10 +391,6 @@ ikev2_recv(struct iked *env, struct iked_message *msg) if (flag) { if ((sa->sa_stateflags & flag) == 0) return; - /* - * We have initiated this exchange, even if - * we are not the initiator of the IKE SA. - */ initiator = 1; } /* @@ -457,33 +413,24 @@ ikev2_recv(struct iked *env, struct iked_message *msg) sa_free(env, sa); } return; - } else if (sa->sa_msgid_set && msg->msg_msgid == sa->sa_msgid) { - /* - * Response is being worked on, most likely we're - * waiting for the CA process to get back to us - */ - return; } /* * If it's a new request, make sure to update the peer's - * message ID and dispose of all previous responses. - * We need to set sa_msgid_set in order to distinguish between - * "last msgid was 0" and "msgid not set yet". + * message ID and dispose of all previous responses */ sa->sa_msgid = msg->msg_msgid; - sa->sa_msgid_set = 1; ikev2_msg_prevail(env, &sa->sa_responses, msg); } - if (sa_address(sa, &sa->sa_peer, &msg->msg_peer) == -1 || - sa_address(sa, &sa->sa_local, &msg->msg_local) == -1) + if (sa_address(sa, &sa->sa_peer, &msg->msg_peer, initiator) == -1 || + sa_address(sa, &sa->sa_local, &msg->msg_local, initiator) == -1) return; sa->sa_fd = msg->msg_fd; log_debug("%s: updated SA to peer %s local %s", __func__, - print_host((struct sockaddr *)&sa->sa_peer.addr, NULL, 0), - print_host((struct sockaddr *)&sa->sa_local.addr, NULL, 0)); + print_host(&sa->sa_peer.addr, NULL, 0), + print_host(&sa->sa_local.addr, NULL, 0)); done: if (initiator) @@ -498,18 +445,7 @@ ikev2_recv(struct iked *env, struct iked_message *msg) } int -ikev2_ike_auth_compatible(struct iked_sa *sa, uint8_t want, uint8_t have) -{ - if (want == have) - return (0); - if (sa->sa_sigsha2 && - have == IKEV2_AUTH_SIG && want == IKEV2_AUTH_RSA_SIG) - return (0); - return (-1); -} - -int -ikev2_ike_auth_recv(struct iked *env, struct iked_sa *sa, +ikev2_ike_auth(struct iked *env, struct iked_sa *sa, struct iked_message *msg) { struct iked_id *id, *certid; @@ -518,6 +454,9 @@ ikev2_ike_auth_recv(struct iked *env, struct iked_sa *sa, struct iked_policy *policy = sa->sa_policy; int ret = -1; + if (msg == NULL) + goto done; + if (sa->sa_hdr.sh_initiator) { id = &sa->sa_rid; certid = &sa->sa_rcert; @@ -525,39 +464,20 @@ ikev2_ike_auth_recv(struct iked *env, struct iked_sa *sa, id = &sa->sa_iid; certid = &sa->sa_icert; } - /* try to relookup the policy based on the peerid */ - if (msg->msg_id.id_type && !sa->sa_hdr.sh_initiator) { - struct iked_policy *old = sa->sa_policy; - - sa->sa_policy = NULL; - if (policy_lookup(env, msg) == 0 && msg->msg_policy && - msg->msg_policy != old) { - /* move sa to new policy */ - policy = sa->sa_policy = msg->msg_policy; - TAILQ_REMOVE(&old->pol_sapeers, sa, sa_peer_entry); - TAILQ_INSERT_TAIL(&policy->pol_sapeers, - sa, sa_peer_entry); - } else { - /* restore */ - msg->msg_policy = sa->sa_policy = old; - } - } if (msg->msg_id.id_type) { memcpy(id, &msg->msg_id, sizeof(*id)); bzero(&msg->msg_id, sizeof(msg->msg_id)); - if (!sa->sa_hdr.sh_initiator) { - if ((authmsg = ikev2_msg_auth(env, sa, - !sa->sa_hdr.sh_initiator)) == NULL) { - log_debug("%s: failed to get response " - "auth data", __func__); - return (-1); - } - - ca_setauth(env, sa, authmsg, PROC_CERT); - ibuf_release(authmsg); + if ((authmsg = ikev2_msg_auth(env, sa, + !sa->sa_hdr.sh_initiator)) == NULL) { + log_debug("%s: failed to get response " + "auth data", __func__); + return (-1); } + + ca_setauth(env, sa, authmsg, PROC_CERT); + ibuf_release(authmsg); } if (msg->msg_cert.id_type) { @@ -586,13 +506,11 @@ ikev2_ike_auth_recv(struct iked *env, struct iked_sa *sa, ikeauth.auth_length = ibuf_size(sa->sa_eapmsk); } - if (ikev2_ike_auth_compatible(sa, - ikeauth.auth_method, msg->msg_auth.id_type) < 0) { + if (msg->msg_auth.id_type != ikeauth.auth_method) { log_warnx("%s: unexpected auth method %s", __func__, - print_map(msg->msg_auth.id_type, ikev2_auth_map)); + print_map(ikeauth.auth_method, ikev2_auth_map)); return (-1); } - ikeauth.auth_method = msg->msg_auth.id_type; if ((authmsg = ikev2_msg_auth(env, sa, sa->sa_hdr.sh_initiator)) == NULL) { @@ -606,10 +524,8 @@ ikev2_ike_auth_recv(struct iked *env, struct iked_sa *sa, authmsg); ibuf_release(authmsg); - if (ret != 0) { - log_debug("%s: ikev2_msg_authverify failed", __func__); - return (-1); - } + if (ret != 0) + goto done; if (sa->sa_eapmsk != NULL) { if ((authmsg = ikev2_msg_auth(env, sa, @@ -628,17 +544,13 @@ ikev2_ike_auth_recv(struct iked *env, struct iked_sa *sa, return (-1); } - /* ikev2_msg_authverify verified AUTH */ - sa_stateflags(sa, IKED_REQ_AUTHVALID); - sa_stateflags(sa, IKED_REQ_EAPVALID); - - sa_state(env, sa, IKEV2_STATE_EAP_SUCCESS); + sa_state(env, sa, IKEV2_STATE_EAP_VALID); } } if (!TAILQ_EMPTY(&msg->msg_proposals)) { - if (ikev2_sa_negotiate(&sa->sa_proposals, - &sa->sa_policy->pol_proposals, &msg->msg_proposals) != 0) { + if (ikev2_sa_negotiate(sa, &sa->sa_policy->pol_proposals, + &msg->msg_proposals) != 0) { log_debug("%s: no proposal chosen", __func__); msg->msg_error = IKEV2_N_NO_PROPOSAL_CHOSEN; return (-1); @@ -646,49 +558,13 @@ ikev2_ike_auth_recv(struct iked *env, struct iked_sa *sa, sa_stateflags(sa, IKED_REQ_SA); } - return ikev2_ike_auth(env, sa); -} - -int -ikev2_ike_auth(struct iked *env, struct iked_sa *sa) -{ - struct iked_policy *pol = sa->sa_policy; - uint8_t certreqtype; - - /* Attempt state transition */ - if (sa->sa_state == IKEV2_STATE_EAP_SUCCESS) - sa_state(env, sa, IKEV2_STATE_EAP_VALID); - else if (sa->sa_state == IKEV2_STATE_AUTH_SUCCESS) - sa_state(env, sa, IKEV2_STATE_VALID); - + done: if (sa->sa_hdr.sh_initiator) { if (sa_stateok(sa, IKEV2_STATE_AUTH_SUCCESS)) return (ikev2_init_done(env, sa)); else return (ikev2_init_ike_auth(env, sa)); } - - /* - * If we have to send a local certificate but did not receive an - * optional CERTREQ, use our own certreq to find a local certificate. - * We could alternatively extract the CA from the peer certificate - * to find a matching local one. - */ - if (sa->sa_statevalid & IKED_REQ_CERT) { - if ((sa->sa_stateflags & IKED_REQ_CERTREQ) == 0) { - log_debug("%s: no CERTREQ, using default", __func__); - if (pol->pol_certreqtype) - certreqtype = pol->pol_certreqtype; - else - certreqtype = env->sc_certreqtype; - return (ca_setreq(env, sa, - &pol->pol_localid, certreqtype, - ibuf_data(env->sc_certreq), - ibuf_size(env->sc_certreq), PROC_CERT)); - } else if ((sa->sa_stateflags & IKED_REQ_CERT) == 0) - return (0); /* ignored, wait for cert */ - } - return (ikev2_resp_ike_auth(env, sa)); } @@ -713,8 +589,7 @@ ikev2_init_recv(struct iked *env, struct iked_message *msg, betoh64(hdr->ike_ispi), betoh64(hdr->ike_rspi), 1, NULL)) == NULL || sa != msg->msg_sa) { log_debug("%s: invalid new SA", __func__); - if (sa) - sa_free(env, sa); + sa_free(env, sa); } break; case IKEV2_EXCHANGE_IKE_AUTH: @@ -745,8 +620,7 @@ ikev2_init_recv(struct iked *env, struct iked_message *msg, * Update address information and use the NAT-T * port and socket, if available. */ - port = htons(socket_getport( - (struct sockaddr *)&sock->sock_addr)); + port = htons(socket_getport(&sock->sock_addr)); sa->sa_local.addr_port = port; sa->sa_peer.addr_port = port; (void)socket_af((struct sockaddr *)&sa->sa_local.addr, port); @@ -758,8 +632,8 @@ ikev2_init_recv(struct iked *env, struct iked_message *msg, log_debug("%s: NAT detected, updated SA to " "peer %s local %s", __func__, - print_host((struct sockaddr *)&sa->sa_peer.addr, NULL, 0), - print_host((struct sockaddr *)&sa->sa_local.addr, NULL, 0)); + print_host(&sa->sa_peer.addr, NULL, 0), + print_host(&sa->sa_local.addr, NULL, 0)); } switch (hdr->ike_exchange) { @@ -767,13 +641,12 @@ ikev2_init_recv(struct iked *env, struct iked_message *msg, (void)ikev2_init_auth(env, msg); break; case IKEV2_EXCHANGE_IKE_AUTH: - (void)ikev2_ike_auth_recv(env, sa, msg); + (void)ikev2_ike_auth(env, sa, msg); break; case IKEV2_EXCHANGE_CREATE_CHILD_SA: (void)ikev2_init_create_child_sa(env, msg); break; case IKEV2_EXCHANGE_INFORMATIONAL: - sa->sa_stateflags &= ~IKED_REQ_INF; break; default: log_debug("%s: exchange %s not implemented", __func__, @@ -786,11 +659,24 @@ void ikev2_init_ike_sa(struct iked *env, void *arg) { struct iked_policy *pol; +#ifdef __APPLE__ + static struct timeval waketime = { 0, 0 }; + struct timeval tv; + size_t size = sizeof(tv); + + if (sysctlbyname("kern.waketime", &tv, &size, NULL, 0) == 0) { + if (waketime.tv_sec != 0 && + memcmp(&waketime, &tv, sizeof(waketime)) != 0) { + log_debug("%s: after power resume", __func__); + } + memcpy(&waketime, &tv, sizeof(waketime)); + } +#endif TAILQ_FOREACH(pol, &env->sc_policies, pol_entry) { if ((pol->pol_flags & IKED_POLICY_ACTIVE) == 0) continue; - if (!TAILQ_EMPTY(&pol->pol_sapeers)) { + if (sa_peer_lookup(pol, &pol->pol_peer.addr) != NULL) { log_debug("%s: \"%s\" is already active", __func__, pol->pol_name); continue; @@ -800,13 +686,11 @@ ikev2_init_ike_sa(struct iked *env, void *arg) if (ikev2_init_ike_sa_peer(env, pol, &pol->pol_peer)) log_debug("%s: failed to initiate with peer %s", - __func__, - print_host((struct sockaddr *)&pol->pol_peer.addr, - NULL, 0)); + __func__, print_host(&pol->pol_peer.addr, NULL, 0)); } - timer_set(env, &env->sc_inittmr, ikev2_init_ike_sa, NULL); - timer_add(env, &env->sc_inittmr, IKED_INITIATOR_INTERVAL); + timer_initialize(env, &env->sc_inittmr, ikev2_init_ike_sa, NULL); + timer_register(env, &env->sc_inittmr, IKED_INITIATOR_INTERVAL); } int @@ -822,7 +706,7 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, struct iked_sa *sa; struct ibuf *buf; struct group *group; - uint8_t *ptr; + u_int8_t *ptr; ssize_t len; int ret = -1; struct iked_socket *sock; @@ -836,24 +720,23 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, return (-1); /* Pick peer's DH group if asked */ - /* XXX free old sa_dhgroup ? */ sa->sa_dhgroup = pol->pol_peerdh; - if (ikev2_sa_initiator(env, sa, NULL, NULL) == -1) + if (ikev2_sa_initiator(env, sa, NULL) == -1) goto done; if (pol->pol_local.addr.ss_family == AF_UNSPEC) { if (socket_getaddr(sock->sock_fd, &ss) == -1) goto done; } else - memcpy(&ss, &pol->pol_local.addr, pol->pol_local.addr.ss_len); + memcpy(&ss, &pol->pol_local.addr, SS_LEN(&pol->pol_local.addr)); - if ((buf = ikev2_msg_init(env, &req, &peer->addr, peer->addr.ss_len, - &ss, ss.ss_len, 0)) == NULL) + if ((buf = ikev2_msg_init(env, &req, &peer->addr, SS_LEN(&peer->addr), + &ss, SS_LEN(&ss), 0)) == NULL) goto done; /* Inherit the port from the 1st send socket */ - port = htons(socket_getport((struct sockaddr *)&sock->sock_addr)); + port = htons(socket_getport(&sock->sock_addr)); (void)socket_af((struct sockaddr *)&req.msg_local, port); (void)socket_af((struct sockaddr *)&req.msg_peer, port); @@ -942,9 +825,6 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, len += sizeof(*n); } - if ((len = ikev2_add_sighashnotify(buf, &pld, len)) == -1) - goto done; - if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONE) == -1) goto done; @@ -959,6 +839,12 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, goto done; } + memcpy(&sa->sa_polpeer, &pol->pol_peer, sizeof(sa->sa_polpeer)); + if (RB_INSERT(iked_sapeers, &pol->pol_sapeers, sa)) { + log_debug("%s: conflicting sa", __func__); + goto done; + } + if ((ret = ikev2_msg_send(env, &req)) == 0) sa_state(env, sa, IKEV2_STATE_SA_INIT); @@ -981,7 +867,7 @@ ikev2_init_auth(struct iked *env, struct iked_message *msg) if (sa == NULL) return (-1); - if (ikev2_sa_initiator(env, sa, NULL, msg) == -1) { + if (ikev2_sa_initiator(env, sa, msg) == -1) { log_debug("%s: failed to get IKE keys", __func__); return (-1); } @@ -1009,7 +895,7 @@ ikev2_init_ike_auth(struct iked *env, struct iked_sa *sa) struct ikev2_auth *auth; struct iked_id *id, *certid; struct ibuf *e = NULL; - uint8_t firstpayload; + u_int8_t firstpayload; int ret = -1; ssize_t len; @@ -1051,15 +937,21 @@ ikev2_init_ike_auth(struct iked *env, struct iked_sa *sa) goto done; len = ibuf_size(certid->id_buf) + sizeof(*cert); - /* CERTREQ payload(s) */ - if ((len = ikev2_add_certreq(e, &pld, - len, env->sc_certreq, env->sc_certreqtype)) == -1) - goto done; + if (env->sc_certreqtype) { + if (ikev2_next_payload(pld, len, + IKEV2_PAYLOAD_CERTREQ) == -1) + goto done; - if (env->sc_certreqtype != pol->pol_certreqtype && - (len = ikev2_add_certreq(e, &pld, - len, NULL, pol->pol_certreqtype)) == -1) - goto done; + /* CERTREQ payload */ + if ((pld = ikev2_add_payload(e)) == NULL) + goto done; + if ((cert = ibuf_advance(e, sizeof(*cert))) == NULL) + goto done; + cert->cert_type = env->sc_certreqtype; + if (ikev2_add_buf(e, env->sc_certreq) == -1) + goto done; + len = ibuf_size(env->sc_certreq) + sizeof(*cert); + } } if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_AUTH) == -1) @@ -1086,11 +978,6 @@ ikev2_init_ike_auth(struct iked *env, struct iked_sa *sa) goto done; } - /* compression */ - if ((pol->pol_flags & IKED_POLICY_IPCOMP) && - (len = ikev2_add_ipcompnotify(env, e, &pld, len, sa)) == -1) - goto done; - if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1) goto done; @@ -1124,18 +1011,11 @@ ikev2_init_done(struct iked *env, struct iked_sa *sa) if (!sa_stateok(sa, IKEV2_STATE_VALID)) return (0); /* ignored */ - ret = ikev2_childsa_negotiate(env, sa, &sa->sa_kex, &sa->sa_proposals, - sa->sa_hdr.sh_initiator, 0); + ret = ikev2_childsa_negotiate(env, sa, sa->sa_hdr.sh_initiator); if (ret == 0) ret = ikev2_childsa_enable(env, sa); - if (ret == 0) { + if (ret == 0) sa_state(env, sa, IKEV2_STATE_ESTABLISHED); - timer_set(env, &sa->sa_timer, ikev2_ike_sa_alive, sa); - timer_add(env, &sa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT); - timer_set(env, &sa->sa_rekey, ikev2_ike_sa_rekey, sa); - if (sa->sa_policy->pol_rekey) - timer_add(env, &sa->sa_rekey, sa->sa_policy->pol_rekey); - } if (ret) ikev2_childsa_delete(env, sa, 0, 0, NULL, 1); @@ -1150,9 +1030,6 @@ ikev2_policy2id(struct iked_static_id *polid, struct iked_id *id, int srcid) char idstr[IKED_ID_SIZE]; struct in_addr in4; struct in6_addr in6; - X509_NAME *name = NULL; - uint8_t *p; - int len; /* Fixup the local Id if not specified */ if (srcid && polid->id_type == 0) { @@ -1195,19 +1072,6 @@ ikev2_policy2id(struct iked_static_id *polid, struct iked_id *id, int srcid) return (-1); } break; - case IKEV2_ID_ASN1_DN: - /* policy has ID in string-format, convert to ASN1 */ - if ((name = ca_x509_name_parse(polid->id_data)) == NULL || - (len = i2d_X509_NAME(name, NULL)) < 0 || - (p = ibuf_reserve(id->id_buf, len)) == NULL || - (i2d_X509_NAME(name, &p)) < 0) { - if (name) - X509_NAME_free(name); - ibuf_release(id->id_buf); - return (-1); - } - X509_NAME_free(name); - break; default: if (ibuf_add(id->id_buf, polid->id_data, polid->id_length) != 0) { @@ -1220,7 +1084,7 @@ ikev2_policy2id(struct iked_static_id *polid, struct iked_id *id, int srcid) if (ikev2_print_id(id, idstr, sizeof(idstr)) == -1) return (-1); - log_debug("%s: %s %s length %zu", __func__, + log_debug("%s: %s %s length %d", __func__, srcid ? "srcid" : "dstid", idstr, ibuf_size(id->id_buf)); @@ -1229,8 +1093,8 @@ ikev2_policy2id(struct iked_static_id *polid, struct iked_id *id, int srcid) struct ike_header * ikev2_add_header(struct ibuf *buf, struct iked_sa *sa, - uint32_t msgid, uint8_t nextpayload, - uint8_t exchange, uint8_t flags) + u_int32_t msgid, u_int8_t nextpayload, + u_int8_t exchange, u_int8_t flags) { struct ike_header *hdr; @@ -1257,7 +1121,7 @@ ikev2_add_header(struct ibuf *buf, struct iked_sa *sa, int ikev2_set_header(struct ike_header *hdr, size_t length) { - uint32_t hdrlength = sizeof(*hdr) + length; + u_int32_t hdrlength = sizeof(*hdr) + length; if (hdrlength > UINT32_MAX) { log_debug("%s: message too long", __func__); @@ -1286,17 +1150,16 @@ ikev2_add_payload(struct ibuf *buf) } ssize_t -ikev2_add_ts_payload(struct ibuf *buf, unsigned int type, struct iked_sa *sa) +ikev2_add_ts_payload(struct ibuf *buf, u_int type, struct iked_sa *sa) { struct iked_policy *pol = sa->sa_policy; struct ikev2_tsp *tsp; struct ikev2_ts *ts; struct iked_flow *flow; struct iked_addr *addr; - struct iked_addr pooladdr; - uint8_t *ptr; + u_int8_t *ptr; size_t len = 0; - uint32_t av[4], bv[4], mv[4]; + u_int32_t av[4], bv[4], mv[4]; struct sockaddr_in *in4; struct sockaddr_in6 *in6; @@ -1322,13 +1185,6 @@ ikev2_add_ts_payload(struct ibuf *buf, unsigned int type, struct iked_sa *sa) } else return (-1); - /* patch remote address (if configured to 0.0.0.0) */ - if ((type == IKEV2_PAYLOAD_TSi && !sa->sa_hdr.sh_initiator) || - (type == IKEV2_PAYLOAD_TSr && sa->sa_hdr.sh_initiator)) { - if (ikev2_cp_fixaddr(sa, addr, &pooladdr) != -1) - addr = &pooladdr; - } - ts->ts_protoid = flow->flow_ipproto; if (addr->addr_port) { @@ -1421,136 +1277,9 @@ ikev2_add_ts(struct ibuf *e, struct ikev2_payload **pld, ssize_t len, return (len); } - -ssize_t -ikev2_add_certreq(struct ibuf *e, struct ikev2_payload **pld, ssize_t len, - struct ibuf *certreq, uint8_t type) -{ - struct ikev2_cert *cert; - - if (type == IKEV2_CERT_NONE) - return (len); - - if (ikev2_next_payload(*pld, len, IKEV2_PAYLOAD_CERTREQ) == -1) - return (-1); - - /* CERTREQ payload */ - if ((*pld = ikev2_add_payload(e)) == NULL) - return (-1); - - if ((cert = ibuf_advance(e, sizeof(*cert))) == NULL) - return (-1); - - cert->cert_type = type; - len = sizeof(*cert); - - if (certreq != NULL && cert->cert_type == IKEV2_CERT_X509_CERT) { - if (ikev2_add_buf(e, certreq) == -1) - return (-1); - len += ibuf_size(certreq); - } - - log_debug("%s: type %s length %zd", __func__, - print_map(type, ikev2_cert_map), len); - - return (len); -} - -ssize_t -ikev2_add_ipcompnotify(struct iked *env, struct ibuf *e, - struct ikev2_payload **pld, ssize_t len, struct iked_sa *sa) -{ - struct iked_childsa csa; - struct ikev2_notify *n; - uint8_t *ptr; - uint16_t cpi; - uint32_t spi; - uint8_t transform; - - /* we only support deflate */ - transform = IKEV2_IPCOMP_DEFLATE; - - bzero(&csa, sizeof(csa)); - csa.csa_saproto = IKEV2_SAPROTO_IPCOMP; - csa.csa_ikesa = sa; - csa.csa_local = &sa->sa_peer; - csa.csa_peer = &sa->sa_local; - - if (pfkey_sa_init(env->sc_pfkey, &csa, &spi) == -1) - return (-1); - /* - * We get spi == 0 if the kernel does not support IPcomp, - * so just return the length of the current payload. - */ - if (spi == 0) - return (len); - cpi = htobe16((uint16_t)spi); - if (*pld) - if (ikev2_next_payload(*pld, len, IKEV2_PAYLOAD_NOTIFY) == -1) - return (-1); - if ((*pld = ikev2_add_payload(e)) == NULL) - return (-1); - len = sizeof(*n) + sizeof(cpi) + sizeof(transform); - if ((ptr = ibuf_advance(e, len)) == NULL) - return (-1); - n = (struct ikev2_notify *)ptr; - n->n_protoid = 0; - n->n_spisize = 0; - n->n_type = htobe16(IKEV2_N_IPCOMP_SUPPORTED); - ptr += sizeof(*n); - memcpy(ptr, &cpi, sizeof(cpi)); - ptr += sizeof(cpi); - memcpy(ptr, &transform, sizeof(transform)); - - sa->sa_cpi_in = spi; /* already on host byte order */ - log_debug("%s: sa_cpi_in 0x%04x", __func__, sa->sa_cpi_in); - - return (len); -} - -ssize_t -ikev2_add_sighashnotify(struct ibuf *e, struct ikev2_payload **pld, - ssize_t len) -{ - struct ikev2_notify *n; - uint8_t *ptr; - size_t i; - uint16_t hash, signature_hashes[] = { - IKEV2_SIGHASH_SHA2_256, - IKEV2_SIGHASH_SHA2_384, - IKEV2_SIGHASH_SHA2_512 - }; - - if (ikev2_next_payload(*pld, len, IKEV2_PAYLOAD_NOTIFY) == -1) - return (-1); - - /* XXX signature_hashes are hardcoded for now */ - len = sizeof(*n) + nitems(signature_hashes) * sizeof(hash); - - /* NOTIFY payload */ - if ((*pld = ikev2_add_payload(e)) == NULL) - return (-1); - if ((ptr = ibuf_advance(e, len)) == NULL) - return (-1); - - n = (struct ikev2_notify *)ptr; - n->n_protoid = 0; - n->n_spisize = 0; - n->n_type = htobe16(IKEV2_N_SIGNATURE_HASH_ALGORITHMS); - ptr += sizeof(*n); - - for (i = 0; i < nitems(signature_hashes); i++) { - hash = htobe16(signature_hashes[i]); - memcpy(ptr, &hash, sizeof(hash)); - ptr += sizeof(hash); - } - - return (len); -} - int ikev2_next_payload(struct ikev2_payload *pld, size_t length, - uint8_t nextpayload) + u_int8_t nextpayload) { size_t pldlength = sizeof(*pld) + length; @@ -1559,7 +1288,7 @@ ikev2_next_payload(struct ikev2_payload *pld, size_t length, return (-1); } - log_debug("%s: length %zu nextpayload %s", + log_debug("%s: length %d nextpayload %s", __func__, pldlength, print_map(nextpayload, ikev2_payload_map)); pld->pld_length = htobe16(pldlength); @@ -1570,21 +1299,21 @@ ikev2_next_payload(struct ikev2_payload *pld, size_t length, ssize_t ikev2_nat_detection(struct iked *env, struct iked_message *msg, - void *ptr, size_t len, unsigned int type) + void *ptr, size_t len, u_int type) { EVP_MD_CTX ctx; struct ike_header *hdr; - uint8_t md[SHA_DIGEST_LENGTH]; - unsigned int mdlen = sizeof(md); + u_int8_t md[SHA_DIGEST_LENGTH]; + u_int mdlen = sizeof(md); struct iked_sa *sa = msg->msg_sa; struct sockaddr_in *in4; struct sockaddr_in6 *in6; ssize_t ret = -1; - struct sockaddr *src, *dst, *ss; - uint64_t rspi, ispi; + struct sockaddr_storage *src, *dst, *ss; + u_int64_t rspi, ispi; struct ibuf *buf; int frompeer = 0; - uint32_t rnd; + u_int32_t rnd; if (ptr == NULL) return (mdlen); @@ -1596,14 +1325,14 @@ ikev2_nat_detection(struct iked *env, struct iked_message *msg, ispi = hdr->ike_ispi; rspi = hdr->ike_rspi; frompeer = 1; - src = (struct sockaddr *)&msg->msg_peer; - dst = (struct sockaddr *)&msg->msg_local; + src = &msg->msg_peer; + dst = &msg->msg_local; } else { ispi = htobe64(sa->sa_hdr.sh_ispi); rspi = htobe64(sa->sa_hdr.sh_rspi); frompeer = 0; - src = (struct sockaddr *)&msg->msg_local; - dst = (struct sockaddr *)&msg->msg_peer; + src = &msg->msg_local; + dst = &msg->msg_peer; } EVP_MD_CTX_init(&ctx); @@ -1633,7 +1362,7 @@ ikev2_nat_detection(struct iked *env, struct iked_message *msg, EVP_DigestUpdate(&ctx, &ispi, sizeof(ispi)); EVP_DigestUpdate(&ctx, &rspi, sizeof(rspi)); - switch (ss->sa_family) { + switch (ss->ss_family) { case AF_INET: in4 = (struct sockaddr_in *)ss; EVP_DigestUpdate(&ctx, &in4->sin_addr.s_addr, @@ -1678,12 +1407,11 @@ ikev2_add_cp(struct iked *env, struct iked_sa *sa, struct ibuf *buf) struct ikev2_cp *cp; struct ikev2_cfg *cfg; struct iked_cfg *ikecfg; - unsigned int i; - uint32_t mask4; + u_int i; size_t len; struct sockaddr_in *in4; struct sockaddr_in6 *in6; - uint8_t prefixlen; + u_int8_t prefixlen; if ((cp = ibuf_advance(buf, sizeof(*cp))) == NULL) return (-1); @@ -1719,29 +1447,12 @@ ikev2_add_cp(struct iked *env, struct iked_sa *sa, struct ibuf *buf) case IKEV2_CFG_INTERNAL_IP4_DHCP: case IKEV2_CFG_INTERNAL_IP4_SERVER: /* 4 bytes IPv4 address */ - in4 = (ikecfg->cfg.address.addr_mask != 32 && - (ikecfg->cfg_type == - IKEV2_CFG_INTERNAL_IP4_ADDRESS) && - sa->sa_addrpool && - sa->sa_addrpool->addr_af == AF_INET) ? - (struct sockaddr_in *)&sa->sa_addrpool->addr : - (struct sockaddr_in *)&ikecfg->cfg.address.addr; + in4 = (struct sockaddr_in *)&ikecfg->cfg.address.addr; cfg->cfg_length = htobe16(4); if (ibuf_add(buf, &in4->sin_addr.s_addr, 4) == -1) return (-1); len += 4; break; - case IKEV2_CFG_INTERNAL_IP4_SUBNET: - /* 4 bytes IPv4 address + 4 bytes IPv4 mask + */ - in4 = (struct sockaddr_in *)&ikecfg->cfg.address.addr; - mask4 = prefixlen2mask(ikecfg->cfg.address.addr_mask); - cfg->cfg_length = htobe16(8); - if (ibuf_add(buf, &in4->sin_addr.s_addr, 4) == -1) - return (-1); - if (ibuf_add(buf, &mask4, 4) == -1) - return (-1); - len += 8; - break; case IKEV2_CFG_INTERNAL_IP6_DNS: case IKEV2_CFG_INTERNAL_IP6_NBNS: case IKEV2_CFG_INTERNAL_IP6_DHCP: @@ -1754,15 +1465,8 @@ ikev2_add_cp(struct iked *env, struct iked_sa *sa, struct ibuf *buf) len += 16; break; case IKEV2_CFG_INTERNAL_IP6_ADDRESS: - case IKEV2_CFG_INTERNAL_IP6_SUBNET: /* 16 bytes IPv6 address + 1 byte prefix length */ - in6 = (ikecfg->cfg.address.addr_mask != 128 && - (ikecfg->cfg_type == - IKEV2_CFG_INTERNAL_IP6_ADDRESS) && - sa->sa_addrpool && - sa->sa_addrpool->addr_af == AF_INET6) ? - (struct sockaddr_in6 *)&sa->sa_addrpool->addr : - (struct sockaddr_in6 *)&ikecfg->cfg.address.addr; + in6 = (struct sockaddr_in6 *)&ikecfg->cfg.address.addr; cfg->cfg_length = htobe16(17); if (ibuf_add(buf, &in6->sin6_addr.s6_addr, 16) == -1) return (-1); @@ -1786,7 +1490,7 @@ ikev2_add_cp(struct iked *env, struct iked_sa *sa, struct ibuf *buf) ssize_t ikev2_add_proposals(struct iked *env, struct iked_sa *sa, struct ibuf *buf, - struct iked_proposals *proposals, uint8_t protoid, int initiator, + struct iked_proposals *proposals, u_int8_t protoid, int initiator, int sendikespi) { struct ikev2_sa_proposal *sap; @@ -1794,9 +1498,9 @@ ikev2_add_proposals(struct iked *env, struct iked_sa *sa, struct ibuf *buf, struct iked_proposal *prop; struct iked_childsa csa; ssize_t length = 0, saplength, xflen; - uint64_t spi64; - uint32_t spi32, spi; - unsigned int i; + u_int64_t spi64; + u_int32_t spi32, spi; + u_int i; TAILQ_FOREACH(prop, proposals, prop_entry) { if ((protoid && prop->prop_protoid != protoid) || @@ -1871,14 +1575,14 @@ ikev2_add_proposals(struct iked *env, struct iked_sa *sa, struct ibuf *buf, length += saplength; } - log_debug("%s: length %zd", __func__, length); + log_debug("%s: length %d", __func__, length); return (length); } ssize_t ikev2_add_transform(struct ibuf *buf, - uint8_t more, uint8_t type, uint16_t id, uint16_t length) + u_int8_t more, u_int8_t type, u_int16_t id, u_int16_t length) { struct ikev2_transform *xfrm; struct ikev2_attribute *attr; @@ -2016,7 +1720,7 @@ ikev2_resp_recv(struct iked *env, struct iked_message *msg, sa->sa_policy->pol_auth.auth_eap) sa_state(env, sa, IKEV2_STATE_EAP); - if (ikev2_ike_auth_recv(env, sa, msg) != 0) { + if (ikev2_ike_auth(env, sa, msg) != 0) { log_debug("%s: failed to send auth response", __func__); sa_state(env, sa, IKEV2_STATE_CLOSED); return; @@ -2025,14 +1729,6 @@ ikev2_resp_recv(struct iked *env, struct iked_message *msg, case IKEV2_EXCHANGE_CREATE_CHILD_SA: (void)ikev2_resp_create_child_sa(env, msg); break; - case IKEV2_EXCHANGE_INFORMATIONAL: - if (!msg->msg_responded && !msg->msg_error) { - (void)ikev2_send_ike_e(env, sa, NULL, - IKEV2_PAYLOAD_NONE, IKEV2_EXCHANGE_INFORMATIONAL, - 1); - msg->msg_responded = 1; - } - break; default: break; } @@ -2044,12 +1740,13 @@ ikev2_resp_ike_sa_init(struct iked *env, struct iked_message *msg) struct iked_message resp; struct ike_header *hdr; struct ikev2_payload *pld; + struct ikev2_cert *cert; struct ikev2_keyexchange *ke; struct ikev2_notify *n; struct iked_sa *sa = msg->msg_sa; struct ibuf *buf; struct group *group; - uint8_t *ptr; + u_int8_t *ptr; ssize_t len; int ret = -1; @@ -2144,22 +1841,21 @@ ikev2_resp_ike_sa_init(struct iked *env, struct iked_message *msg) len += sizeof(*n); } - if (sa->sa_statevalid & IKED_REQ_CERT) { - /* CERTREQ payload(s) */ - if ((len = ikev2_add_certreq(buf, &pld, - len, env->sc_certreq, env->sc_certreqtype)) == -1) + if (env->sc_certreqtype && (sa->sa_statevalid & IKED_REQ_CERT)) { + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_CERTREQ) == -1) goto done; - if (env->sc_certreqtype != sa->sa_policy->pol_certreqtype && - (len = ikev2_add_certreq(buf, &pld, - len, NULL, sa->sa_policy->pol_certreqtype)) == -1) + /* CERTREQ payload */ + if ((pld = ikev2_add_payload(buf)) == NULL) + goto done; + if ((cert = ibuf_advance(buf, sizeof(*cert))) == NULL) + goto done; + cert->cert_type = env->sc_certreqtype; + if (ikev2_add_buf(buf, env->sc_certreq) == -1) goto done; + len = ibuf_size(env->sc_certreq) + sizeof(*cert); } - if (sa->sa_sigsha2 && - (len = ikev2_add_sighashnotify(buf, &pld, len)) == -1) - goto done; - if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONE) == -1) goto done; @@ -2192,7 +1888,7 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) struct ikev2_auth *auth; struct iked_id *id, *certid; struct ibuf *e = NULL; - uint8_t firstpayload; + u_int8_t firstpayload; int ret = -1; ssize_t len; @@ -2204,11 +1900,7 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) else if (!sa_stateok(sa, IKEV2_STATE_VALID)) return (0); /* ignore */ - if (ikev2_cp_setaddr(env, sa) < 0) - return (-1); - - if (ikev2_childsa_negotiate(env, sa, &sa->sa_kex, &sa->sa_proposals, - sa->sa_hdr.sh_initiator, 0) < 0) + if (ikev2_childsa_negotiate(env, sa, sa->sa_hdr.sh_initiator) == -1) return (-1); /* New encrypted message buffer */ @@ -2296,11 +1988,6 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) goto done; } - /* compression */ - if (sa->sa_ipcomp && - (len = ikev2_add_ipcompnotify(env, e, &pld, len, sa)) == -1) - goto done; - if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1) goto done; @@ -2322,14 +2009,8 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) IKEV2_EXCHANGE_IKE_AUTH, firstpayload, 1); if (ret == 0) ret = ikev2_childsa_enable(env, sa); - if (ret == 0) { + if (ret == 0) sa_state(env, sa, IKEV2_STATE_ESTABLISHED); - timer_set(env, &sa->sa_timer, ikev2_ike_sa_alive, sa); - timer_add(env, &sa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT); - timer_set(env, &sa->sa_rekey, ikev2_ike_sa_rekey, sa); - if (sa->sa_policy->pol_rekey) - timer_add(env, &sa->sa_rekey, sa->sa_policy->pol_rekey); - } done: if (ret) @@ -2346,18 +2027,17 @@ ikev2_resp_ike_eap(struct iked *env, struct iked_sa *sa, struct ibuf *eapmsg) struct ikev2_auth *auth; struct iked_id *id, *certid; struct ibuf *e = NULL; - uint8_t firstpayload; + u_int8_t firstpayload; int ret = -1; ssize_t len = 0; + if (!sa_stateok(sa, IKEV2_STATE_EAP)) + return (0); + /* Responder only */ if (sa->sa_hdr.sh_initiator) return (-1); - /* Check if "ca" has done it's job yet */ - if (!sa->sa_localauth.id_type) - return (0); - /* New encrypted message buffer */ if ((e = ibuf_static()) == NULL) goto done; @@ -2425,7 +2105,7 @@ ikev2_resp_ike_eap(struct iked *env, struct iked_sa *sa, struct ibuf *eapmsg) int ikev2_send_ike_e(struct iked *env, struct iked_sa *sa, struct ibuf *buf, - uint8_t firstpayload, uint8_t exchange, int response) + u_int8_t firstpayload, u_int8_t exchange, int response) { struct ikev2_payload *pld; struct ibuf *e = NULL; @@ -2437,15 +2117,11 @@ ikev2_send_ike_e(struct iked *env, struct iked_sa *sa, struct ibuf *buf, if ((pld = ikev2_add_payload(e)) == NULL) goto done; + if (ibuf_cat(e, buf) != 0) + goto done; - if (buf) { - if (ibuf_cat(e, buf) != 0) - goto done; - - if (ikev2_next_payload(pld, ibuf_size(buf), - IKEV2_PAYLOAD_NONE) == -1) - goto done; - } + if (ikev2_next_payload(pld, ibuf_size(buf), IKEV2_PAYLOAD_NONE) == -1) + goto done; ret = ikev2_msg_send_encrypt(env, sa, &e, exchange, firstpayload, response); @@ -2456,47 +2132,16 @@ ikev2_send_ike_e(struct iked *env, struct iked_sa *sa, struct ibuf *buf, return (ret); } -int -ikev2_set_sa_proposal(struct iked_sa *sa, struct iked_policy *pol, - unsigned int proto) -{ - struct iked_proposal *prop, *copy; - struct iked_transform *xform; - unsigned int i; - - /* create copy of the policy proposals */ - config_free_proposals(&sa->sa_proposals, proto); - TAILQ_FOREACH(prop, &pol->pol_proposals, prop_entry) { - if (proto != 0 && prop->prop_protoid != proto) - continue; - if ((copy = config_add_proposal(&sa->sa_proposals, - prop->prop_id, prop->prop_protoid)) == NULL) - return (-1); - for (i = 0; i < prop->prop_nxforms; i++) { - xform = &prop->prop_xforms[i]; - if (config_add_transform(copy, xform->xform_type, - xform->xform_id, xform->xform_length, - xform->xform_keylength) == NULL) - return (-1); - } - } - return (0); -} - int ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, - struct iked_spi *rekey, uint8_t protoid) + struct iked_spi *rekey, u_int8_t protoid) { - struct iked_policy *pol = sa->sa_policy; struct iked_childsa *csa = NULL, *csb = NULL; struct ikev2_notify *n; - struct ikev2_payload *pld = NULL; - struct ikev2_keyexchange *ke; - struct group *group; + struct ikev2_payload *pld; struct ibuf *e = NULL, *nonce = NULL; - uint8_t *ptr; - uint8_t firstpayload; - uint32_t spi; + u_int8_t *ptr; + u_int32_t spi; ssize_t len = 0; int initiator, ret = -1; @@ -2507,14 +2152,6 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, else log_debug("%s: creating new CHILD SAs", __func__); - /* XXX cannot initiate multiple concurrent CREATE_CHILD_SA exchanges */ - if (sa->sa_stateflags & IKED_REQ_CHILDSA) { - log_debug("%s: another CREATE_CHILD_SA exchange already active", - __func__); - return (-1); - } - - sa->sa_rekeyspi = 0; /* clear rekey spi */ initiator = sa->sa_hdr.sh_initiator ? 1 : 0; if (rekey && @@ -2523,7 +2160,6 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, (csb = csa->csa_peersa) == NULL)) { log_debug("%s: CHILD SA %s wasn't found", __func__, print_spi(rekey->spi, rekey->spi_size)); - goto done; } /* Generate new nonce */ @@ -2537,32 +2173,9 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, if ((e = ibuf_static()) == NULL) goto done; - /* compression */ - if ((pol->pol_flags & IKED_POLICY_IPCOMP) && - (len = ikev2_add_ipcompnotify(env, e, &pld, 0, sa)) == -1) - goto done; - - if (pld) { - firstpayload = IKEV2_PAYLOAD_NOTIFY; - if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1) - goto done; - } else - firstpayload = IKEV2_PAYLOAD_SA; - /* SA payload */ if ((pld = ikev2_add_payload(e)) == NULL) goto done; - - /* - * We need to reset the sa_proposal. Otherwise it would be - * left over from the IKE_AUTH exchange and would not contain - * any DH groups (e.g. for ESP child SAs). - */ - if (ikev2_set_sa_proposal(sa, pol, protoid) < 0) { - log_debug("%s: ikev2_set_sa_proposal failed", __func__); - goto done; - } - if ((len = ikev2_add_proposals(env, sa, e, &sa->sa_proposals, protoid, 1, 0)) == -1) goto done; @@ -2577,32 +2190,6 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, goto done; len = ibuf_size(nonce); - if (config_findtransform(&pol->pol_proposals, IKEV2_XFORMTYPE_DH, - protoid)) { - log_debug("%s: enable PFS", __func__); - ikev2_sa_cleanup_dh(sa); - if (ikev2_sa_initiator_dh(sa, NULL, protoid) < 0) { - log_debug("%s: failed to setup DH", __func__); - goto done; - } - if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_KE) == -1) - goto done; - - /* KE payload */ - if ((pld = ikev2_add_payload(e)) == NULL) - goto done; - if ((ke = ibuf_advance(e, sizeof(*ke))) == NULL) - goto done; - if ((group = sa->sa_dhgroup) == NULL) { - log_debug("%s: invalid dh", __func__); - goto done; - } - ke->kex_dhgroup = htobe16(group->id); - if (ikev2_add_buf(e, sa->sa_dhiexchange) == -1) - goto done; - len = sizeof(*ke) + dh_getlen(group); - } - if ((len = ikev2_add_ts(e, &pld, len, sa, !initiator)) == -1) goto done; @@ -2621,7 +2208,7 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, if ((ptr = ibuf_advance(e, rekey->spi_size)) == NULL) goto done; len = rekey->spi_size; - spi = htobe32((uint32_t)csa->csa_peerspi); + spi = htobe32((u_int32_t)csa->csa_peerspi); memcpy(ptr, &spi, rekey->spi_size); len += sizeof(*n); } @@ -2630,16 +2217,11 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, goto done; ret = ikev2_msg_send_encrypt(env, sa, &e, - IKEV2_EXCHANGE_CREATE_CHILD_SA, firstpayload, 0); + IKEV2_EXCHANGE_CREATE_CHILD_SA, IKEV2_PAYLOAD_SA, 0); if (ret == 0) { if (rekey) { csa->csa_rekey = 1; csb->csa_rekey = 1; - /* - * Remember the peer spi of the rekeyed - * SA for ikev2_init_create_child_sa(). - */ - sa->sa_rekeyspi = csa->csa_peerspi; } sa->sa_stateflags |= IKED_REQ_CHILDSA; } @@ -2649,131 +2231,28 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, return (ret); } -void -ikev2_ike_sa_rekey(struct iked *env, void *arg) +int +ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) { - struct iked_sa *sa = arg; - struct iked_sa *nsa = NULL; - struct ikev2_payload *pld = NULL; - struct ikev2_keyexchange *ke; - struct group *group; - struct ibuf *e = NULL, *nonce = NULL; - ssize_t len = 0; - int ret = -1; - - log_debug("%s: called for IKE SA %p", __func__, sa); - - if (sa->sa_stateflags & IKED_REQ_CHILDSA) { - /* - * We cannot initiate multiple concurrent CREATE_CHILD_SA - * exchanges, so retry in one minute. - */ - timer_add(env, &sa->sa_rekey, 60); - return; - } - - if ((nsa = sa_new(env, 0, 0, 1, sa->sa_policy)) == NULL) { - log_debug("%s: failed to get new SA", __func__); - goto done; - } - - if (ikev2_sa_initiator(env, nsa, sa, NULL)) { - log_debug("%s: failed to setup DH", __func__); - goto done; - } - sa_state(env, nsa, IKEV2_STATE_AUTH_SUCCESS); - nonce = nsa->sa_inonce; - - if ((e = ibuf_static()) == NULL) - goto done; - - /* SA payload */ - if ((pld = ikev2_add_payload(e)) == NULL) - goto done; - - /* just reuse the old IKE SA proposals */ - if ((len = ikev2_add_proposals(env, nsa, e, &sa->sa_proposals, - IKEV2_SAPROTO_IKE, 1, 1)) == -1) - goto done; - - if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONCE) == -1) - goto done; - - /* NONCE payload */ - if ((pld = ikev2_add_payload(e)) == NULL) - goto done; - if (ikev2_add_buf(e, nonce) == -1) - goto done; - len = ibuf_size(nonce); - - if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_KE) == -1) - goto done; - - /* KE payload */ - if ((pld = ikev2_add_payload(e)) == NULL) - goto done; - if ((ke = ibuf_advance(e, sizeof(*ke))) == NULL) - goto done; - if ((group = nsa->sa_dhgroup) == NULL) { - log_debug("%s: invalid dh", __func__); - goto done; - } - ke->kex_dhgroup = htobe16(group->id); - if (ikev2_add_buf(e, nsa->sa_dhiexchange) == -1) - goto done; - len = sizeof(*ke) + dh_getlen(group); - - if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONE) == -1) - goto done; - - ret = ikev2_msg_send_encrypt(env, sa, &e, - IKEV2_EXCHANGE_CREATE_CHILD_SA, IKEV2_PAYLOAD_SA, 0); - if (ret == 0) { - sa->sa_stateflags |= IKED_REQ_CHILDSA; - sa->sa_next = nsa; - nsa = NULL; - } -done: - if (nsa) - sa_free(env, nsa); - ibuf_release(e); - - if (ret == 0) - log_debug("%s: create child SA sent", __func__); - else - log_debug("%s: could not send create child SA", __func__); - /* XXX should we try again in case of ret != 0 ? */ -} - -int -ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) -{ - struct iked_childsa *csa = NULL; - struct iked_proposal *prop; - struct iked_sa *sa = msg->msg_sa; - struct iked_sa *nsa; - struct iked_spi *spi; - struct ikev2_delete *del; - struct ibuf *buf = NULL; - uint32_t spi32; - int pfs = 0, ret = -1; + struct iked_childsa *csa; + struct iked_proposal *prop; + struct iked_sa *sa = msg->msg_sa; + struct ikev2_delete *del; + struct ibuf *buf = NULL; + u_int64_t peerspi; + u_int32_t spi32; + int rekeying = 0, ret = -1; if (!ikev2_msg_frompeer(msg) || (sa->sa_stateflags & IKED_REQ_CHILDSA) == 0) return (0); - if (msg->msg_prop == NULL || - TAILQ_EMPTY(&msg->msg_proposals)) { + if (msg->msg_prop == NULL) { log_debug("%s: no proposal specified", __func__); return (-1); } - if (ikev2_sa_negotiate(&sa->sa_proposals, &sa->sa_proposals, - &msg->msg_proposals) != 0) { - log_debug("%s: no proposal chosen", __func__); - return (-1); - } - + /* Update peer SPI */ TAILQ_FOREACH(prop, &sa->sa_proposals, prop_entry) { if (prop->prop_protoid == msg->msg_prop->prop_protoid) break; @@ -2784,56 +2263,13 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) return (-1); } - /* IKE SA rekeying */ - if (prop->prop_protoid == IKEV2_SAPROTO_IKE) { - if (sa->sa_next == NULL) { - log_debug("%s: missing IKE SA for rekeying", __func__); - return (-1); - } - /* Update the responder SPI */ - spi = &msg->msg_prop->prop_peerspi; - if ((nsa = sa_new(env, sa->sa_next->sa_hdr.sh_ispi, - spi->spi, 1, NULL)) == NULL || nsa != sa->sa_next) { - log_debug("%s: invalid rekey SA", __func__); - if (nsa) - sa_free(env, nsa); - sa_free(env, sa->sa_next); - sa->sa_next = NULL; - return (-1); - } - if (ikev2_sa_initiator(env, nsa, sa, msg) == -1) { - log_debug("%s: failed to get IKE keys", __func__); - return (-1); - } - sa->sa_stateflags &= ~IKED_REQ_CHILDSA; - sa->sa_next = NULL; - return (ikev2_ikesa_enable(env, sa, nsa)); - } - - /* Child SA rekeying */ - if (sa->sa_rekeyspi && - (csa = childsa_lookup(sa, sa->sa_rekeyspi, prop->prop_protoid)) - != NULL) { - log_debug("%s: rekeying CHILD SA old %s spi %s", __func__, - print_spi(csa->csa_spi.spi, csa->csa_spi.spi_size), - print_spi(prop->prop_peerspi.spi, - prop->prop_peerspi.spi_size)); - } - - /* check KE payload for PFS */ - if (ibuf_length(msg->msg_ke)) { - log_debug("%s: using PFS", __func__); - if (ikev2_sa_initiator_dh(sa, msg, prop->prop_protoid) < 0) { - log_debug("%s: failed to setup DH", __func__); - return (ret); - } - if (sa->sa_dhpeer == NULL) { - log_debug("%s: no peer DH", __func__); - return (ret); - } - pfs = 1; - /* XXX check group against policy ? */ - /* XXX should ikev2_sa_negotiate do this? */ + peerspi = prop->prop_peerspi.spi; + prop->prop_peerspi.spi = msg->msg_prop->prop_peerspi.spi; + + if ((csa = childsa_lookup(sa, peerspi, prop->prop_protoid)) != NULL) { + rekeying = 1; + log_debug("%s: rekeying CHILD SA %s", __func__, + print_spi(peerspi, prop->prop_peerspi.spi_size)); } /* Update responder's nonce */ @@ -2844,13 +2280,12 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) ibuf_release(sa->sa_rnonce); sa->sa_rnonce = ibuf_dup(msg->msg_nonce); - if (ikev2_childsa_negotiate(env, sa, &sa->sa_kex, &sa->sa_proposals, 1, - pfs)) { + if (ikev2_childsa_negotiate(env, sa, 1)) { log_debug("%s: failed to get CHILD SAs", __func__); return (-1); } - if (csa) { + if (rekeying) { /* Child SA rekeying */ if ((buf = ibuf_static()) == NULL) @@ -2863,7 +2298,7 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) del->del_spisize = sizeof(spi32); del->del_nspi = htobe16(1); - spi32 = htobe32(csa->csa_spi.spi); + spi32 = htobe32(csa->csa_peerspi); if (ibuf_add(buf, &spi32, sizeof(spi32))) goto done; @@ -2871,7 +2306,7 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) IKEV2_EXCHANGE_INFORMATIONAL, 0)) goto done; - sa->sa_stateflags |= IKED_REQ_INF; + sa->sa_stateflags |= IKED_REQ_INF | IKED_REQ_DELETE; } ret = ikev2_childsa_enable(env, sa); @@ -2886,159 +2321,29 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) } int -ikev2_ikesa_enable(struct iked *env, struct iked_sa *sa, struct iked_sa *nsa) +ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) { struct iked_childsa *csa, *nextcsa; struct iked_flow *flow, *nextflow; struct iked_proposal *prop, *nextprop; - - log_debug("%s: IKE SA %p ispi %s rspi %s replaced" - " by SA %p ispi %s rspi %s ", - __func__, sa, - print_spi(sa->sa_hdr.sh_ispi, 8), - print_spi(sa->sa_hdr.sh_rspi, 8), - nsa, - print_spi(nsa->sa_hdr.sh_ispi, 8), - print_spi(nsa->sa_hdr.sh_rspi, 8)); - - /* Transfer socket and NAT information */ - nsa->sa_fd = sa->sa_fd; - nsa->sa_natt = sa->sa_natt; - nsa->sa_udpencap = sa->sa_udpencap; - - /* Transfer all Child SAs and flows from the old IKE SA */ - for (flow = TAILQ_FIRST(&sa->sa_flows); flow != NULL; - flow = nextflow) { - nextflow = TAILQ_NEXT(flow, flow_entry); - TAILQ_REMOVE(&sa->sa_flows, flow, flow_entry); - TAILQ_INSERT_TAIL(&nsa->sa_flows, flow, - flow_entry); - flow->flow_ikesa = nsa; - flow->flow_local = &nsa->sa_local; - flow->flow_peer = &nsa->sa_peer; - } - for (csa = TAILQ_FIRST(&sa->sa_childsas); csa != NULL; - csa = nextcsa) { - nextcsa = TAILQ_NEXT(csa, csa_entry); - TAILQ_REMOVE(&sa->sa_childsas, csa, csa_entry); - TAILQ_INSERT_TAIL(&nsa->sa_childsas, csa, - csa_entry); - csa->csa_ikesa = nsa; - if (csa->csa_dir == IPSP_DIRECTION_IN) { - csa->csa_local = &nsa->sa_peer; - csa->csa_peer = &nsa->sa_local; - } else { - csa->csa_local = &nsa->sa_local; - csa->csa_peer = &nsa->sa_peer; - } - } - /* Transfer all non-IKE proposals */ - for (prop = TAILQ_FIRST(&sa->sa_proposals); prop != NULL; - prop = nextprop) { - nextprop = TAILQ_NEXT(prop, prop_entry); - if (prop->prop_protoid == IKEV2_SAPROTO_IKE) - continue; - TAILQ_REMOVE(&sa->sa_proposals, prop, prop_entry); - TAILQ_INSERT_TAIL(&nsa->sa_proposals, prop, - prop_entry); - } - - /* Preserve ID information */ - if (sa->sa_hdr.sh_initiator == nsa->sa_hdr.sh_initiator) { - nsa->sa_iid = sa->sa_iid; - nsa->sa_rid = sa->sa_rid; - } else { - /* initiator and responder role swapped */ - nsa->sa_iid = sa->sa_rid; - nsa->sa_rid = sa->sa_iid; - } - /* duplicate the actual buffer */ - nsa->sa_iid.id_buf = ibuf_dup(nsa->sa_iid.id_buf); - nsa->sa_rid.id_buf = ibuf_dup(nsa->sa_rid.id_buf); - - /* Transfer sa_addrpool address */ - if (sa->sa_addrpool) { - RB_REMOVE(iked_addrpool, &env->sc_addrpool, sa); - nsa->sa_addrpool = sa->sa_addrpool; - sa->sa_addrpool = NULL; - RB_INSERT(iked_addrpool, &env->sc_addrpool, nsa); - } - - log_debug("%s: activating new IKE SA", __func__); - sa_state(env, nsa, IKEV2_STATE_ESTABLISHED); - timer_set(env, &nsa->sa_timer, ikev2_ike_sa_alive, nsa); - timer_add(env, &nsa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT); - timer_set(env, &nsa->sa_rekey, ikev2_ike_sa_rekey, nsa); - if (nsa->sa_policy->pol_rekey) - timer_add(env, &nsa->sa_rekey, nsa->sa_policy->pol_rekey); - nsa->sa_stateflags = nsa->sa_statevalid; /* XXX */ - - /* unregister DPD keep alive timer & rekey first */ - if (sa->sa_state == IKEV2_STATE_ESTABLISHED) { - timer_del(env, &sa->sa_rekey); - timer_del(env, &sa->sa_timer); - } - - ikev2_ikesa_delete(env, sa, nsa->sa_hdr.sh_initiator); - return (0); -} - -void -ikev2_ikesa_delete(struct iked *env, struct iked_sa *sa, int initiator) -{ - struct ibuf *buf = NULL; - struct ikev2_delete *del; - - if (initiator) { - /* Send PAYLOAD_DELETE */ - if ((buf = ibuf_static()) == NULL) - goto done; - if ((del = ibuf_advance(buf, sizeof(*del))) == NULL) - goto done; - del->del_protoid = IKEV2_SAPROTO_IKE; - del->del_spisize = 0; - del->del_nspi = 0; - if (ikev2_send_ike_e(env, sa, buf, IKEV2_PAYLOAD_DELETE, - IKEV2_EXCHANGE_INFORMATIONAL, 0) == -1) - goto done; - log_debug("%s: sent delete, closing SA", __func__); -done: - ibuf_release(buf); - sa_state(env, sa, IKEV2_STATE_CLOSED); - } else { - sa_state(env, sa, IKEV2_STATE_CLOSING); - } - - /* Remove IKE-SA after timeout, e.g. if we don't get a delete */ - timer_set(env, &sa->sa_timer, ikev2_ike_sa_timeout, sa); - timer_add(env, &sa->sa_timer, IKED_IKE_SA_DELETE_TIMEOUT); -} - -int -ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) -{ - struct iked_childsa *csa; - struct iked_proposal *prop; - struct iked_proposals proposals; - struct iked_kex *kex, *kextmp = NULL; struct iked_sa *nsa = NULL, *sa = msg->msg_sa; struct iked_spi *spi, *rekey = &msg->msg_rekey; struct ikev2_keyexchange *ke; - struct ikev2_payload *pld = NULL; - struct ibuf *e = NULL, *nonce = NULL; - uint8_t firstpayload; + struct ikev2_notify *n; + struct ikev2_payload *pld; + struct ibuf *buf = NULL, *e = NULL, *nonce = NULL; + struct group *group; + u_int64_t spi64; + u_int32_t spi32; ssize_t len = 0; int initiator, protoid, rekeying = 1; int ret = -1; - int pfs = 0; initiator = sa->sa_hdr.sh_initiator ? 1 : 0; if (!ikev2_msg_frompeer(msg) || msg->msg_prop == NULL) return (0); - TAILQ_INIT(&proposals); - if ((protoid = rekey->spi_protoid) == 0) { /* * If REKEY_SA notification is not present, then it's either @@ -3084,42 +2389,45 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) sa_state(env, nsa, IKEV2_STATE_AUTH_SUCCESS); nonce = nsa->sa_rnonce; - kex = &nsa->sa_kex; } else { /* Child SA creating/rekeying */ - if ((kex = kextmp = calloc(1, sizeof(*kextmp))) == NULL) { - log_debug("%s: calloc kex", __func__); - goto fail; - } - - if (ikev2_sa_negotiate(&proposals, - &sa->sa_policy->pol_proposals, &msg->msg_proposals) != 0) { - log_debug("%s: no proposal chosen", __func__); - goto fail; - } - - /* check KE payload for PFS */ if (ibuf_length(msg->msg_parent->msg_ke)) { - log_debug("%s: using PFS", __func__); - if (ikev2_sa_responder_dh(kex, &proposals, - msg->msg_parent, protoid) < 0) { - log_debug("%s: failed to setup DH", __func__); - goto fail; + /* We do not support KE payload yet */ + if ((buf = ibuf_static()) == NULL) + return (-1); + if ((n = ibuf_advance(buf, sizeof(*n))) == NULL) { + ibuf_release(buf); + return (-1); + } + n->n_protoid = protoid; + n->n_spisize = rekey->spi_size; + n->n_type = htobe16(IKEV2_N_NO_ADDITIONAL_SAS); + switch (rekey->spi_size) { + case 4: + spi32 = htobe32(rekey->spi); + ibuf_add(buf, &spi32, rekey->spi_size); + break; + case 8: + spi64 = htobe64(rekey->spi); + ibuf_add(buf, &spi64, rekey->spi_size); + break; } - pfs = 1; - /* XXX check group against policy ? */ + ikev2_send_ike_e(env, sa, buf, IKEV2_PAYLOAD_NOTIFY, + IKEV2_EXCHANGE_CREATE_CHILD_SA, 1); + ibuf_release(buf); + return (0); } /* Update peer SPI */ - TAILQ_FOREACH(prop, &proposals, prop_entry) { + TAILQ_FOREACH(prop, &sa->sa_proposals, prop_entry) { if (prop->prop_protoid == protoid) break; } if (prop == NULL) { log_debug("%s: failed to find %s proposals", __func__, print_map(protoid, ikev2_saproto_map)); - goto fail; + return (-1); } else prop->prop_peerspi = msg->msg_prop->prop_peerspi; @@ -3130,13 +2438,13 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) log_debug("%s: CHILD SA %s wasn't found", __func__, print_spi(rekey->spi, rekey->spi_size)); - goto fail; + return (-1); } if (!csa->csa_loaded || !csa->csa_peersa || !csa->csa_peersa->csa_loaded) { log_debug("%s: SA is not loaded or no peer SA", __func__); - goto fail; + return (-1); } csa->csa_rekey = 1; csa->csa_peersa->csa_rekey = 1; @@ -3145,46 +2453,34 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) /* Update initiator's nonce */ if (!ibuf_length(msg->msg_nonce)) { log_debug("%s: initiator didn't send nonce", __func__); - goto fail; + return (-1); } - ibuf_release(kex->kex_inonce); - kex->kex_inonce = ibuf_dup(msg->msg_nonce); + ibuf_release(sa->sa_inonce); + sa->sa_inonce = ibuf_dup(msg->msg_nonce); /* Generate new responder's nonce */ if ((nonce = ibuf_random(IKED_NONCE_SIZE)) == NULL) - goto fail; + return (-1); /* Update responder's nonce */ - ibuf_release(kex->kex_rnonce); - kex->kex_rnonce = nonce; + ibuf_release(sa->sa_rnonce); + sa->sa_rnonce = nonce; - if (ikev2_childsa_negotiate(env, sa, kex, &proposals, 0, pfs)) { + if (ikev2_childsa_negotiate(env, sa, 0)) { log_debug("%s: failed to get CHILD SAs", __func__); - goto fail; + return (-1); } } if ((e = ibuf_static()) == NULL) goto done; - /* compression (unless IKE rekeying) */ - if (!nsa && sa->sa_ipcomp && - (len = ikev2_add_ipcompnotify(env, e, &pld, 0, sa)) == -1) - goto done; - - if (pld) { - firstpayload = IKEV2_PAYLOAD_NOTIFY; - if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1) - goto done; - } else - firstpayload = IKEV2_PAYLOAD_SA; - /* SA payload */ if ((pld = ikev2_add_payload(e)) == NULL) goto done; if ((len = ikev2_add_proposals(env, nsa ? nsa : sa, e, - nsa ? &nsa->sa_proposals : &proposals, + nsa ? &nsa->sa_proposals : &sa->sa_proposals, protoid, 0, nsa ? 1 : 0)) == -1) goto done; @@ -3198,8 +2494,7 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) goto done; len = ibuf_size(nonce); - if (protoid == IKEV2_SAPROTO_IKE || pfs) { - + if (protoid == IKEV2_SAPROTO_IKE) { if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_KE) == -1) goto done; @@ -3208,44 +2503,74 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) goto done; if ((ke = ibuf_advance(e, sizeof(*ke))) == NULL) goto done; - if (kex->kex_dhgroup == NULL) { + if ((group = nsa->sa_dhgroup) == NULL) { log_debug("%s: invalid dh", __func__); goto done; } - ke->kex_dhgroup = htobe16(kex->kex_dhgroup->id); - if (ikev2_add_buf(e, kex->kex_dhrexchange) == -1) + ke->kex_dhgroup = htobe16(group->id); + if (ikev2_add_buf(e, nsa->sa_dhrexchange) == -1) goto done; - len = sizeof(*ke) + dh_getlen(kex->kex_dhgroup); - } - - if (protoid != IKEV2_SAPROTO_IKE) + len = sizeof(*ke) + dh_getlen(group); + } else { if ((len = ikev2_add_ts(e, &pld, len, sa, initiator)) == -1) goto done; + } if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONE) == -1) goto done; if ((ret = ikev2_msg_send_encrypt(env, sa, &e, - IKEV2_EXCHANGE_CREATE_CHILD_SA, firstpayload, 1)) == -1) + IKEV2_EXCHANGE_CREATE_CHILD_SA, IKEV2_PAYLOAD_SA, 1)) == -1) goto done; - if (protoid == IKEV2_SAPROTO_IKE) - ret = ikev2_ikesa_enable(env, sa, nsa); - else + if (protoid == IKEV2_SAPROTO_IKE) { + /* Transfer all Child SAs and flows from the old IKE SA */ + for (flow = TAILQ_FIRST(&sa->sa_flows); flow != NULL; + flow = nextflow) { + nextflow = TAILQ_NEXT(flow, flow_entry); + TAILQ_REMOVE(&sa->sa_flows, flow, flow_entry); + TAILQ_INSERT_TAIL(&nsa->sa_flows, flow, + flow_entry); + flow->flow_ikesa = nsa; + } + for (csa = TAILQ_FIRST(&sa->sa_childsas); csa != NULL; + csa = nextcsa) { + nextcsa = TAILQ_NEXT(csa, csa_entry); + TAILQ_REMOVE(&sa->sa_childsas, csa, csa_entry); + TAILQ_INSERT_TAIL(&nsa->sa_childsas, csa, + csa_entry); + csa->csa_ikesa = nsa; + } + /* Transfer all non-IKE proposals */ + for (prop = TAILQ_FIRST(&sa->sa_proposals); prop != NULL; + prop = nextprop) { + nextprop = TAILQ_NEXT(prop, prop_entry); + if (prop->prop_protoid == IKEV2_SAPROTO_IKE) + continue; + TAILQ_REMOVE(&sa->sa_proposals, prop, prop_entry); + TAILQ_INSERT_TAIL(&nsa->sa_proposals, prop, + prop_entry); + } + /* Preserve ID information */ + nsa->sa_iid = sa->sa_iid; + nsa->sa_iid.id_buf = ibuf_dup(sa->sa_iid.id_buf); + nsa->sa_rid = sa->sa_rid; + nsa->sa_rid.id_buf = ibuf_dup(sa->sa_rid.id_buf); + + log_debug("%s: activating new IKE SA", __func__); + sa_state(env, nsa, IKEV2_STATE_ESTABLISHED); + nsa->sa_stateflags = sa->sa_statevalid; /* XXX */ + + timer_initialize(env, &sa->sa_timer, ikev2_ike_sa_timeout, sa); + timer_register(env, &sa->sa_timer, IKED_IKE_SA_REKEY_TIMEOUT); + } else ret = ikev2_childsa_enable(env, sa); done: if (ret && protoid != IKEV2_SAPROTO_IKE) ikev2_childsa_delete(env, sa, 0, 0, NULL, 1); ibuf_release(e); - config_free_proposals(&proposals, 0); - config_free_kex(kextmp); return (ret); - - fail: - config_free_proposals(&proposals, 0); - config_free_kex(kextmp); - return (-1); } void @@ -3257,50 +2582,6 @@ ikev2_ike_sa_timeout(struct iked *env, void *arg) sa_free(env, sa); } -void -ikev2_ike_sa_alive(struct iked *env, void *arg) -{ - struct iked_sa *sa = arg; - struct iked_childsa *csa = NULL; - struct timeval tv; - uint64_t last_used, diff; - int foundin = 0, foundout = 0; - - /* check for incoming traffic on any child SA */ - TAILQ_FOREACH(csa, &sa->sa_childsas, csa_entry) { - if (!csa->csa_loaded || - csa->csa_saproto == IKEV2_SAPROTO_IPCOMP) - continue; - if (pfkey_sa_last_used(env->sc_pfkey, csa, &last_used) != 0) - continue; - gettimeofday(&tv, NULL); - diff = (uint32_t)(tv.tv_sec - last_used); - log_debug("%s: %s CHILD SA spi %s last used %llu second(s) ago", - __func__, - csa->csa_dir == IPSP_DIRECTION_IN ? "incoming" : "outgoing", - print_spi(csa->csa_spi.spi, csa->csa_spi.spi_size), diff); - if (diff < IKED_IKE_SA_ALIVE_TIMEOUT) { - if (csa->csa_dir == IPSP_DIRECTION_IN) { - foundin = 1; - break; - } else { - foundout = 1; - } - } - } - - /* send probe if any outging SA has been used, but no incoming SA */ - if (!foundin && foundout) { - log_debug("%s: sending alive check", __func__); - ikev2_send_ike_e(env, sa, NULL, IKEV2_PAYLOAD_NONE, - IKEV2_EXCHANGE_INFORMATIONAL, 0); - sa->sa_stateflags |= IKED_REQ_INF; - } - - /* re-register */ - timer_add(env, &sa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT); -} - int ikev2_send_informational(struct iked *env, struct iked_message *msg) { @@ -3415,10 +2696,10 @@ ikev2_send_informational(struct iked *env, struct iked_message *msg) } ssize_t -ikev2_psk(struct iked_sa *sa, uint8_t *data, size_t length, - uint8_t **pskptr) +ikev2_psk(struct iked_sa *sa, u_int8_t *data, size_t length, + u_int8_t **pskptr) { - uint8_t *psk; + u_int8_t *psk; size_t psklen = -1; if (hash_setkey(sa->sa_prf, data, length) == NULL) @@ -3440,8 +2721,8 @@ ikev2_match_proposals(struct iked_proposal *local, struct iked_proposal *peer, struct iked_transform **xforms) { struct iked_transform *tpeer, *tlocal; - unsigned int i, j, type, score; - uint8_t protoid = peer->prop_protoid; + u_int i, j, type, score; + u_int8_t protoid = peer->prop_protoid; for (i = 0; i < peer->prop_nxforms; i++) { tpeer = peer->prop_xforms + i; @@ -3497,17 +2778,16 @@ ikev2_match_proposals(struct iked_proposal *local, struct iked_proposal *peer, } int -ikev2_sa_negotiate(struct iked_proposals *result, struct iked_proposals *local, +ikev2_sa_negotiate(struct iked_sa *sa, struct iked_proposals *local, struct iked_proposals *peer) { struct iked_proposal *ppeer = NULL, *plocal, *prop, vpeer, vlocal; - struct iked_transform chosen[IKEV2_XFORMTYPE_MAX]; - struct iked_transform *valid[IKEV2_XFORMTYPE_MAX]; + struct iked_transform *chosen[IKEV2_XFORMTYPE_MAX]; struct iked_transform *match[IKEV2_XFORMTYPE_MAX]; - unsigned int i, score, chosen_score = 0; - uint8_t protoid = 0; + u_int i, score, chosen_score = 0; + u_int8_t protoid = 0; - bzero(valid, sizeof(valid)); + bzero(chosen, sizeof(chosen)); bzero(&vlocal, sizeof(vlocal)); bzero(&vpeer, sizeof(vpeer)); @@ -3526,11 +2806,8 @@ ikev2_sa_negotiate(struct iked_proposals *result, struct iked_proposals *local, log_debug("%s: score %d", __func__, score); if (score && (!chosen_score || score < chosen_score)) { chosen_score = score; - for (i = 0; i < IKEV2_XFORMTYPE_MAX; i++) { - if ((valid[i] = match[i])) - memcpy(&chosen[i], match[i], - sizeof(chosen[0])); - } + for (i = 0; i < IKEV2_XFORMTYPE_MAX; i++) + chosen[i] = match[i]; memcpy(&vpeer, ppeer, sizeof(vpeer)); memcpy(&vlocal, plocal, sizeof(vlocal)); } @@ -3541,11 +2818,12 @@ ikev2_sa_negotiate(struct iked_proposals *result, struct iked_proposals *local, if (chosen_score == 0) return (-1); - else if (result == NULL) + else if (sa == NULL) return (0); - (void)config_free_proposals(result, vpeer.prop_protoid); - prop = config_add_proposal(result, vpeer.prop_id, vpeer.prop_protoid); + (void)config_free_proposals(&sa->sa_proposals, vpeer.prop_protoid); + prop = config_add_proposal(&sa->sa_proposals, vpeer.prop_id, + vpeer.prop_protoid); if (vpeer.prop_localspi.spi_size) { prop->prop_localspi.spi_size = vpeer.prop_localspi.spi_size; @@ -3557,18 +2835,18 @@ ikev2_sa_negotiate(struct iked_proposals *result, struct iked_proposals *local, } for (i = 0; i < IKEV2_XFORMTYPE_MAX; i++) { - if (valid[i] == NULL) + if (chosen[i] == NULL) continue; print_debug("%s: score %d: %s %s", __func__, - chosen[i].xform_score, print_map(i, ikev2_xformtype_map), - print_map(chosen[i].xform_id, chosen[i].xform_map)); - if (chosen[i].xform_length) - print_debug(" %d", chosen[i].xform_length); + chosen[i]->xform_score, print_map(i, ikev2_xformtype_map), + print_map(chosen[i]->xform_id, chosen[i]->xform_map)); + if (chosen[i]->xform_length) + print_debug(" %d", chosen[i]->xform_length); print_debug("\n"); - if (config_add_transform(prop, chosen[i].xform_type, - chosen[i].xform_id, chosen[i].xform_length, - chosen[i].xform_keylength) == NULL) + if (config_add_transform(prop, chosen[i]->xform_type, + chosen[i]->xform_id, chosen[i]->xform_length, + chosen[i]->xform_keylength) == NULL) break; } @@ -3576,15 +2854,15 @@ ikev2_sa_negotiate(struct iked_proposals *result, struct iked_proposals *local, } int -ikev2_sa_initiator_dh(struct iked_sa *sa, struct iked_message *msg, - unsigned int proto) +ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, + struct iked_message *msg) { struct iked_policy *pol = sa->sa_policy; struct iked_transform *xform; if (sa->sa_dhgroup == NULL) { if ((xform = config_findtransform(&pol->pol_proposals, - IKEV2_XFORMTYPE_DH, proto)) == NULL) { + IKEV2_XFORMTYPE_DH)) == NULL) { log_debug("%s: did not find dh transform", __func__); return (-1); } @@ -3609,10 +2887,28 @@ ikev2_sa_initiator_dh(struct iked_sa *sa, struct iked_message *msg, } } + if (!ibuf_length(sa->sa_inonce)) { + if ((sa->sa_inonce = ibuf_random(IKED_NONCE_SIZE)) == NULL) { + log_debug("%s: failed to get local nonce", __func__); + return (-1); + } + } + /* Initial message */ if (msg == NULL) return (0); + if (!ibuf_length(sa->sa_rnonce)) { + if (!ibuf_length(msg->msg_nonce)) { + log_debug("%s: invalid peer nonce", __func__); + return (-1); + } + if ((sa->sa_rnonce = ibuf_dup(msg->msg_nonce)) == NULL) { + log_debug("%s: failed to get peer nonce", __func__); + return (-1); + } + } + if (!ibuf_length(sa->sa_dhrexchange)) { if (!ibuf_length(msg->msg_ke)) { log_debug("%s: invalid peer dh exchange", __func__); @@ -3632,43 +2928,10 @@ ikev2_sa_initiator_dh(struct iked_sa *sa, struct iked_message *msg, /* Set a pointer to the peer exchange */ sa->sa_dhpeer = sa->sa_dhrexchange; - return (0); -} - -int -ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, - struct iked_sa *osa, struct iked_message *msg) -{ - struct iked_transform *xform; - - if (ikev2_sa_initiator_dh(sa, msg, 0) < 0) - return (-1); - - if (!ibuf_length(sa->sa_inonce)) { - if ((sa->sa_inonce = ibuf_random(IKED_NONCE_SIZE)) == NULL) { - log_debug("%s: failed to get local nonce", __func__); - return (-1); - } - } - - /* Initial message */ - if (msg == NULL) - return (0); - - if (!ibuf_length(sa->sa_rnonce)) { - if (!ibuf_length(msg->msg_nonce)) { - log_debug("%s: invalid peer nonce", __func__); - return (-1); - } - if ((sa->sa_rnonce = ibuf_dup(msg->msg_nonce)) == NULL) { - log_debug("%s: failed to get peer nonce", __func__); - return (-1); - } - } /* XXX we need a better way to get this */ - if (ikev2_sa_negotiate(&sa->sa_proposals, - &msg->msg_policy->pol_proposals, &msg->msg_proposals) != 0) { + if (ikev2_sa_negotiate(sa, &msg->msg_policy->pol_proposals, + &msg->msg_proposals) != 0) { log_debug("%s: no proposal chosen", __func__); msg->msg_error = IKEV2_N_NO_PROPOSAL_CHOSEN; return (-1); @@ -3677,7 +2940,7 @@ ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, if (sa->sa_encr == NULL) { if ((xform = config_findtransform(&sa->sa_proposals, - IKEV2_XFORMTYPE_ENCR, 0)) == NULL) { + IKEV2_XFORMTYPE_ENCR)) == NULL) { log_debug("%s: did not find encr transform", __func__); return (-1); } @@ -3690,7 +2953,7 @@ ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, if (sa->sa_prf == NULL) { if ((xform = config_findtransform(&sa->sa_proposals, - IKEV2_XFORMTYPE_PRF, 0)) == NULL) { + IKEV2_XFORMTYPE_PRF)) == NULL) { log_debug("%s: did not find prf transform", __func__); return (-1); } @@ -3703,7 +2966,7 @@ ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, if (sa->sa_integr == NULL) { if ((xform = config_findtransform(&sa->sa_proposals, - IKEV2_XFORMTYPE_INTEGR, 0)) == NULL) { + IKEV2_XFORMTYPE_INTEGR)) == NULL) { log_debug("%s: did not find integr transform", __func__); return (-1); @@ -3721,57 +2984,9 @@ ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, return (-1); } - return (ikev2_sa_keys(env, sa, osa ? osa->sa_key_d : NULL)); + return (ikev2_sa_keys(env, sa, NULL)); } -int -ikev2_sa_responder_dh(struct iked_kex *kex, struct iked_proposals *proposals, - struct iked_message *msg, unsigned int proto) -{ - struct iked_transform *xform; - - if (kex->kex_dhgroup == NULL) { - if ((xform = config_findtransform(proposals, - IKEV2_XFORMTYPE_DH, proto)) == NULL) { - log_debug("%s: did not find dh transform", __func__); - return (-1); - } - if ((kex->kex_dhgroup = - group_get(xform->xform_id)) == NULL) { - log_debug("%s: invalid dh %d", __func__, - xform->xform_id); - return (-1); - } - } - - if (!ibuf_length(kex->kex_dhrexchange)) { - if ((kex->kex_dhrexchange = ibuf_new(NULL, - dh_getlen(kex->kex_dhgroup))) == NULL) { - log_debug("%s: failed to alloc dh exchange", __func__); - return (-1); - } - if (dh_create_exchange(kex->kex_dhgroup, - kex->kex_dhrexchange->buf) == -1) { - log_debug("%s: failed to get dh exchange", __func__); - return (-1); - } - } - - if (!ibuf_length(kex->kex_dhiexchange)) { - if ((kex->kex_dhiexchange = ibuf_dup(msg->msg_ke)) == NULL || - ((ssize_t)ibuf_length(kex->kex_dhiexchange) != - dh_getlen(kex->kex_dhgroup))) { - /* XXX send notification to peer */ - log_debug("%s: invalid dh, size %d", __func__, - dh_getlen(kex->kex_dhgroup) * 8); - return (-1); - } - } - - /* Set a pointer to the peer exchange */ - kex->kex_dhpeer = kex->kex_dhiexchange; - return (0); -} int ikev2_sa_responder(struct iked *env, struct iked_sa *sa, struct iked_sa *osa, struct iked_message *msg) @@ -3800,8 +3015,8 @@ ikev2_sa_responder(struct iked *env, struct iked_sa *sa, struct iked_sa *osa, } /* XXX we need a better way to get this */ - if (ikev2_sa_negotiate(&sa->sa_proposals, - &msg->msg_policy->pol_proposals, &msg->msg_proposals) != 0) { + if (ikev2_sa_negotiate(sa, &msg->msg_policy->pol_proposals, + &msg->msg_proposals) != 0) { log_debug("%s: no proposal chosen", __func__); msg->msg_error = IKEV2_N_NO_PROPOSAL_CHOSEN; return (-1); @@ -3810,7 +3025,7 @@ ikev2_sa_responder(struct iked *env, struct iked_sa *sa, struct iked_sa *osa, if (sa->sa_encr == NULL) { if ((xform = config_findtransform(&sa->sa_proposals, - IKEV2_XFORMTYPE_ENCR, 0)) == NULL) { + IKEV2_XFORMTYPE_ENCR)) == NULL) { log_debug("%s: did not find encr transform", __func__); return (-1); } @@ -3823,7 +3038,7 @@ ikev2_sa_responder(struct iked *env, struct iked_sa *sa, struct iked_sa *osa, if (sa->sa_prf == NULL) { if ((xform = config_findtransform(&sa->sa_proposals, - IKEV2_XFORMTYPE_PRF, 0)) == NULL) { + IKEV2_XFORMTYPE_PRF)) == NULL) { log_debug("%s: did not find prf transform", __func__); return (-1); } @@ -3836,7 +3051,7 @@ ikev2_sa_responder(struct iked *env, struct iked_sa *sa, struct iked_sa *osa, if (sa->sa_integr == NULL) { if ((xform = config_findtransform(&sa->sa_proposals, - IKEV2_XFORMTYPE_INTEGR, 0)) == NULL) { + IKEV2_XFORMTYPE_INTEGR)) == NULL) { log_debug("%s: did not find integr transform", __func__); return (-1); @@ -3848,8 +3063,45 @@ ikev2_sa_responder(struct iked *env, struct iked_sa *sa, struct iked_sa *osa, } } - if (ikev2_sa_responder_dh(&sa->sa_kex, &sa->sa_proposals, msg, 0) < 0) - return (-1); + if (sa->sa_dhgroup == NULL) { + if ((xform = config_findtransform(&sa->sa_proposals, + IKEV2_XFORMTYPE_DH)) == NULL) { + log_debug("%s: did not find dh transform", __func__); + return (-1); + } + if ((sa->sa_dhgroup = + group_get(xform->xform_id)) == NULL) { + log_debug("%s: invalid dh", __func__); + return (-1); + } + } + + if (!ibuf_length(sa->sa_dhrexchange)) { + if ((sa->sa_dhrexchange = ibuf_new(NULL, + dh_getlen(sa->sa_dhgroup))) == NULL) { + log_debug("%s: failed to alloc dh exchange", __func__); + return (-1); + } + if (dh_create_exchange(sa->sa_dhgroup, + sa->sa_dhrexchange->buf) == -1) { + log_debug("%s: failed to get dh exchange", __func__); + return (-1); + } + } + + if (!ibuf_length(sa->sa_dhiexchange)) { + if ((sa->sa_dhiexchange = ibuf_dup(msg->msg_ke)) == NULL || + ((ssize_t)ibuf_length(sa->sa_dhiexchange) != + dh_getlen(sa->sa_dhgroup))) { + /* XXX send notification to peer */ + log_debug("%s: invalid dh, size %d", __func__, + dh_getlen(sa->sa_dhgroup) * 8); + return (-1); + } + } + + /* Set a pointer to the peer exchange */ + sa->sa_dhpeer = sa->sa_dhiexchange; return (ikev2_sa_keys(env, sa, osa ? osa->sa_key_d : NULL)); } @@ -3862,7 +3114,7 @@ ikev2_sa_keys(struct iked *env, struct iked_sa *sa, struct ibuf *key) struct group *group; struct ibuf *ninr, *dhsecret, *skeyseed, *s, *t; size_t nonceminlen, ilen, rlen, tmplen; - uint64_t ispi, rspi; + u_int64_t ispi, rspi; int ret = -1; ninr = dhsecret = skeyseed = s = t = NULL; @@ -3919,7 +3171,7 @@ ikev2_sa_keys(struct iked *env, struct iked_sa *sa, struct ibuf *key) if (dh_create_shared(group, dhsecret->buf, sa->sa_dhpeer->buf) == -1) { log_debug("%s: failed to get dh secret" - " group %d len %d secret %zu exchange %zu", __func__, + " group %d len %d secret %d exchange %d", __func__, group->id, dh_getlen(group), ibuf_length(dhsecret), ibuf_length(sa->sa_dhpeer)); goto done; @@ -3963,7 +3215,7 @@ ikev2_sa_keys(struct iked *env, struct iked_sa *sa, struct ibuf *key) hash_update(prf, dhsecret->buf, ibuf_length(dhsecret)); hash_final(prf, skeyseed->buf, &tmplen); - log_debug("%s: SKEYSEED with %zu bytes", __func__, tmplen); + log_debug("%s: SKEYSEED with %d bytes", __func__, tmplen); print_hex(skeyseed->buf, 0, tmplen); if (ibuf_setsize(skeyseed, tmplen) == -1) { @@ -3991,7 +3243,7 @@ ikev2_sa_keys(struct iked *env, struct iked_sa *sa, struct ibuf *key) goto done; } - log_debug("%s: S with %zu bytes", __func__, ibuf_length(s)); + log_debug("%s: S with %d bytes", __func__, ibuf_length(s)); print_hex(s->buf, 0, ibuf_length(s)); /* @@ -4023,25 +3275,25 @@ ikev2_sa_keys(struct iked *env, struct iked_sa *sa, struct ibuf *key) goto done; } - log_debug("%s: SK_d with %zu bytes", __func__, + log_debug("%s: SK_d with %d bytes", __func__, ibuf_length(sa->sa_key_d)); print_hex(sa->sa_key_d->buf, 0, ibuf_length(sa->sa_key_d)); - log_debug("%s: SK_ai with %zu bytes", __func__, + log_debug("%s: SK_ai with %d bytes", __func__, ibuf_length(sa->sa_key_iauth)); print_hex(sa->sa_key_iauth->buf, 0, ibuf_length(sa->sa_key_iauth)); - log_debug("%s: SK_ar with %zu bytes", __func__, + log_debug("%s: SK_ar with %d bytes", __func__, ibuf_length(sa->sa_key_rauth)); print_hex(sa->sa_key_rauth->buf, 0, ibuf_length(sa->sa_key_rauth)); - log_debug("%s: SK_ei with %zu bytes", __func__, + log_debug("%s: SK_ei with %d bytes", __func__, ibuf_length(sa->sa_key_iencr)); print_hex(sa->sa_key_iencr->buf, 0, ibuf_length(sa->sa_key_iencr)); - log_debug("%s: SK_er with %zu bytes", __func__, + log_debug("%s: SK_er with %d bytes", __func__, ibuf_length(sa->sa_key_rencr)); print_hex(sa->sa_key_rencr->buf, 0, ibuf_length(sa->sa_key_rencr)); - log_debug("%s: SK_pi with %zu bytes", __func__, + log_debug("%s: SK_pi with %d bytes", __func__, ibuf_length(sa->sa_key_iprf)); print_hex(sa->sa_key_iprf->buf, 0, ibuf_length(sa->sa_key_iprf)); - log_debug("%s: SK_pr with %zu bytes", __func__, + log_debug("%s: SK_pr with %d bytes", __func__, ibuf_length(sa->sa_key_rprf)); print_hex(sa->sa_key_rprf->buf, 0, ibuf_length(sa->sa_key_rprf)); @@ -4057,24 +3309,13 @@ ikev2_sa_keys(struct iked *env, struct iked_sa *sa, struct ibuf *key) return (ret); } -void -ikev2_sa_cleanup_dh(struct iked_sa *sa) -{ - ibuf_release(sa->sa_dhiexchange); - ibuf_release(sa->sa_dhrexchange); - group_free(sa->sa_dhgroup); - sa->sa_dhiexchange = NULL; - sa->sa_dhrexchange = NULL; - sa->sa_dhgroup = NULL; -} - struct ibuf * ikev2_prfplus(struct iked_hash *prf, struct ibuf *key, struct ibuf *seed, size_t keymatlen) { struct ibuf *t = NULL, *t1 = NULL, *t2 = NULL; size_t rlen, i, hashlen = 0; - uint8_t pad = 0; + u_int8_t pad = 0; /* * prf+ (K, S) = T1 | T2 | T3 | T4 | ... @@ -4121,12 +3362,12 @@ ikev2_prfplus(struct iked_hash *prf, struct ibuf *key, struct ibuf *seed, ibuf_release(t2); ibuf_add(t, t1->buf, ibuf_length(t1)); - log_debug("%s: T%d with %zu bytes", __func__, + log_debug("%s: T%d with %d bytes", __func__, pad, ibuf_length(t1)); print_hex(t1->buf, 0, ibuf_length(t1)); } - log_debug("%s: Tn with %zu bytes", __func__, ibuf_length(t)); + log_debug("%s: Tn with %d bytes", __func__, ibuf_length(t)); print_hex(t->buf, 0, ibuf_length(t)); ibuf_release(t1); @@ -4212,7 +3453,7 @@ ikev2_sa_tag(struct iked_sa *sa, struct iked_id *id) } } - log_debug("%s: %s (%zu)", __func__, sa->sa_tag, strlen(sa->sa_tag)); + log_debug("%s: %s (%d)", __func__, sa->sa_tag, strlen(sa->sa_tag)); ret = 0; fail: @@ -4225,29 +3466,35 @@ ikev2_sa_tag(struct iked_sa *sa, struct iked_id *id) } int -ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, - struct iked_kex *kex, struct iked_proposals *proposals, int initiator, - int pfs) +ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) { struct iked_proposal *prop; struct iked_transform *xform, *encrxf = NULL, *integrxf = NULL; struct iked_childsa *csa, *csb; struct iked_flow *flow, *saflow, *flowa, *flowb; - struct ibuf *keymat = NULL, *seed = NULL, *dhsecret = NULL; - struct group *group; - uint32_t spi = 0; - unsigned int i; + struct iked_id *peerid, *localid; + struct ibuf *keymat = NULL, *seed = NULL; + u_int32_t spi = 0; + u_int i; size_t ilen = 0; int esn, skip, ret = -1; if (!sa_stateok(sa, IKEV2_STATE_VALID)) return (-1); - if (ikev2_sa_tag(sa, IKESA_DSTID(sa)) == -1) + if (sa->sa_hdr.sh_initiator) { + peerid = &sa->sa_rid; + localid = &sa->sa_iid; + } else { + peerid = &sa->sa_iid; + localid = &sa->sa_rid; + } + + if (ikev2_sa_tag(sa, peerid) == -1) return (-1); /* We need to determine the key material length first */ - TAILQ_FOREACH(prop, proposals, prop_entry) { + TAILQ_FOREACH(prop, &sa->sa_proposals, prop_entry) { if (prop->prop_protoid == IKEV2_SAPROTO_IKE) continue; log_debug("%s: proposal %d", __func__, prop->prop_id); @@ -4275,40 +3522,10 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, /* double key material length for inbound/outbound */ ilen *= 2; - log_debug("%s: key material length %zu", __func__, ilen); + log_debug("%s: key material length %d", __func__, ilen); - if ((seed = ibuf_new(NULL, 0)) == NULL) { - log_debug("%s: failed to setup IKE SA key material", __func__); - goto done; - } - if (pfs) { - log_debug("%s: using PFS", __func__); - if (kex->kex_dhpeer == NULL || - ibuf_length(kex->kex_dhpeer) == 0 || - (group = kex->kex_dhgroup) == NULL) { - log_debug("%s: no dh group for pfs", __func__); - goto done; - } - if ((dhsecret = ibuf_new(NULL, dh_getlen(group))) == NULL) { - log_debug("%s: failed to alloc dh secret", __func__); - goto done; - } - if (dh_create_shared(group, dhsecret->buf, - kex->kex_dhpeer->buf) == -1) { - log_debug("%s: failed to get dh secret" - " group %d len %d secret %zu exchange %zu", - __func__, group->id, dh_getlen(group), - ibuf_length(dhsecret), - ibuf_length(kex->kex_dhpeer)); - goto done; - } - if (ibuf_cat(seed, dhsecret) != 0) { - log_debug("%s: failed to set dh secret", __func__); - goto done; - } - } - if (ibuf_cat(seed, kex->kex_inonce) != 0 || - ibuf_cat(seed, kex->kex_rnonce) != 0 || + if ((seed = ibuf_dup(sa->sa_inonce)) == NULL || + ibuf_cat(seed, sa->sa_rnonce) != 0 || (keymat = ikev2_prfplus(sa->sa_prf, sa->sa_key_d, seed, ilen)) == NULL) { log_debug("%s: failed to get IKE SA key material", __func__); @@ -4316,7 +3533,7 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, } /* Create the new flows */ - TAILQ_FOREACH(prop, proposals, prop_entry) { + TAILQ_FOREACH(prop, &sa->sa_proposals, prop_entry) { if (ikev2_valid_proposal(prop, NULL, NULL, NULL) != 0) continue; @@ -4327,11 +3544,8 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, &flow->flow_src) && IKED_ADDR_EQ(&saflow->flow_dst, &flow->flow_dst) && - saflow->flow_saproto == - prop->prop_protoid) { + saflow->flow_saproto == prop->prop_protoid) skip = 1; - break; - } } if (skip) continue; @@ -4344,10 +3558,11 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, memcpy(flowa, flow, sizeof(*flow)); flowa->flow_dir = IPSP_DIRECTION_OUT; flowa->flow_saproto = prop->prop_protoid; + flowa->flow_srcid = localid; + flowa->flow_dstid = peerid; flowa->flow_local = &sa->sa_local; flowa->flow_peer = &sa->sa_peer; flowa->flow_ikesa = sa; - ikev2_cp_fixaddr(sa, &flow->flow_dst, &flowa->flow_dst); if ((flowb = calloc(1, sizeof(*flowb))) == NULL) { log_debug("%s: failed to get flow", __func__); @@ -4362,7 +3577,6 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, sizeof(flow->flow_dst)); memcpy(&flowb->flow_dst, &flow->flow_src, sizeof(flow->flow_src)); - ikev2_cp_fixaddr(sa, &flow->flow_dst, &flowb->flow_src); TAILQ_INSERT_TAIL(&sa->sa_flows, flowa, flow_entry); TAILQ_INSERT_TAIL(&sa->sa_flows, flowb, flow_entry); @@ -4370,7 +3584,7 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, } /* create the CHILD SAs using the key material */ - TAILQ_FOREACH(prop, proposals, prop_entry) { + TAILQ_FOREACH(prop, &sa->sa_proposals, prop_entry) { if (ikev2_valid_proposal(prop, &encrxf, &integrxf, &esn) != 0) continue; @@ -4383,6 +3597,8 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, csa->csa_saproto = prop->prop_protoid; csa->csa_ikesa = sa; + csa->csa_srcid = localid; + csa->csa_dstid = peerid; csa->csa_spi.spi_protoid = prop->prop_protoid; csa->csa_esn = esn; @@ -4423,10 +3639,8 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, childsa_free(csa); goto done; } - if (encrxf) - csa->csa_encrid = encrxf->xform_id; - if (integrxf) - csa->csa_integrid = integrxf->xform_id; + csa->csa_encrxf = encrxf; + csa->csa_integrxf = integrxf; if ((csb = calloc(1, sizeof(*csb))) == NULL) { log_debug("%s: failed to get CHILD SA", __func__); @@ -4471,183 +3685,17 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, ret = 0; done: - ibuf_release(dhsecret); ibuf_release(keymat); ibuf_release(seed); return (ret); } -/* free a replaced IPCOMP SA */ -void -ikev2_ipcomp_csa_free(struct iked *env, struct iked_childsa *csa) -{ - if (csa->csa_children) - fatalx("ikev2_ipcomp_csa_free: has children"); - if (csa->csa_ikesa) - TAILQ_REMOVE(&csa->csa_ikesa->sa_childsas, csa, - csa_entry); - if (csa->csa_loaded) { - log_debug("%s: csa %p loaded: calling pfkey_sa_delete", - __func__, csa); - pfkey_sa_delete(env->sc_pfkey, csa); - RB_REMOVE(iked_activesas, &env->sc_activesas, csa); - } - childsa_free(csa); -} - -int -ikev2_ipcomp_enable(struct iked *env, struct iked_sa *sa) -{ - struct iked_childsa *other, *nother, *csa = NULL, *csb = NULL; - struct iked_flow *flow, *flowa = NULL, *flowb = NULL; - struct iked_flow *nflow, *oflow; - - if ((csa = calloc(1, sizeof(*csa))) == NULL || - (csb = calloc(1, sizeof(*csb))) == NULL || - (flowa = calloc(1, sizeof(*flowa))) == NULL || - (flowb = calloc(1, sizeof(*flowb))) == NULL) { - free(csa); - free(csb); - free(flowa); - free(flowb); - return (-1); - } - - /* switch ESP SAs to transport mode */ - TAILQ_FOREACH(other, &sa->sa_childsas, csa_entry) { - if (!other->csa_rekey && !other->csa_loaded && - other->csa_saproto == IKEV2_SAPROTO_ESP) { - other->csa_transport = 1; - if (other->csa_dir == IPSP_DIRECTION_OUT) { - other->csa_parent = csa; - csa->csa_children++; - } else { - other->csa_parent = csb; - csb->csa_children++; - } - } - } - - /* install IPCOMP SAs */ - csa->csa_ikesa = sa; - csa->csa_saproto = IKEV2_SAPROTO_IPCOMP; - csa->csa_spi.spi_size = 2; - csa->csa_spi.spi = sa->sa_cpi_out; - csa->csa_peerspi = sa->sa_cpi_in; - csa->csa_dir = IPSP_DIRECTION_OUT; - csa->csa_local = &sa->sa_local; - csa->csa_peer = &sa->sa_peer; - - memcpy(csb, csa, sizeof(*csb)); - csb->csa_spi.spi = csa->csa_peerspi; - csb->csa_peerspi = csa->csa_spi.spi; - csb->csa_dir = IPSP_DIRECTION_IN; - csb->csa_local = csa->csa_peer; - csb->csa_peer = csa->csa_local; - csb->csa_allocated = 1; - - /* remove old replaced IPCOMP SAs */ - TAILQ_FOREACH_SAFE(other, &sa->sa_childsas, csa_entry, nother) { - if (other->csa_saproto != IKEV2_SAPROTO_IPCOMP || - other->csa_children != 0) - continue; - if (other->csa_dir == csa->csa_dir && - IKED_ADDR_EQ(other->csa_local, csa->csa_local) && - IKED_ADDR_EQ(other->csa_peer, csa->csa_peer)) { - log_debug("%s: csa %p replaces %p", - __func__, csa, other); - ikev2_ipcomp_csa_free(env, other); - } else if (other->csa_dir == csb->csa_dir && - IKED_ADDR_EQ(other->csa_local, csb->csa_local) && - IKED_ADDR_EQ(other->csa_peer, csb->csa_peer)) { - log_debug("%s: csa %p replaces %p", - __func__, csb, other); - ikev2_ipcomp_csa_free(env, other); - } - } - - TAILQ_INSERT_TAIL(&sa->sa_childsas, csa, csa_entry); - TAILQ_INSERT_TAIL(&sa->sa_childsas, csb, csa_entry); - - csa->csa_peersa = csb; - csb->csa_peersa = csa; - - /* redirect flows to IPCOMP */ - /* XXX expensive? should be merged into ikev2_childsa_negotiate() */ - TAILQ_FOREACH_SAFE(flow, &sa->sa_flows, flow_entry, nflow) { - if (flow->flow_loaded || - flow->flow_saproto != IKEV2_SAPROTO_ESP) - continue; - TAILQ_FOREACH(oflow, &sa->sa_flows, flow_entry) - if (IKED_ADDR_EQ(&oflow->flow_src, &flow->flow_src) && - IKED_ADDR_EQ(&oflow->flow_dst, &flow->flow_dst) && - oflow->flow_dir == flow->flow_dir && - oflow->flow_saproto == IKEV2_SAPROTO_IPCOMP) - break; - if (oflow != NULL) { - log_debug("%s: keeping oflow %p, indentical to flow %p", - __func__, oflow, flow); - TAILQ_REMOVE(&sa->sa_flows, flow, flow_entry); - flow_free(flow); - } else { - log_debug("%s: flow %p saproto %d -> %d", __func__, - flow, flow->flow_saproto, IKEV2_SAPROTO_IPCOMP); - flow->flow_saproto = IKEV2_SAPROTO_IPCOMP; - } - } - - /* setup ESP flows for gateways */ - flowa->flow_dir = IPSP_DIRECTION_OUT; - flowa->flow_saproto = IKEV2_SAPROTO_ESP; - flowa->flow_local = &sa->sa_local; - flowa->flow_peer = &sa->sa_peer; - memcpy(&flowa->flow_src, &sa->sa_local, sizeof(sa->sa_local)); - memcpy(&flowa->flow_dst, &sa->sa_peer, sizeof(sa->sa_peer)); - socket_setport((struct sockaddr *)&flowa->flow_src.addr, 0); - socket_setport((struct sockaddr *)&flowa->flow_dst.addr, 0); - flowa->flow_src.addr_port = flowa->flow_dst.addr_port = 0; - flowa->flow_src.addr_mask = flowa->flow_dst.addr_mask = - (sa->sa_local.addr_af == AF_INET) ? 32 : 128; - flowa->flow_ikesa = sa; - - /* skip if flow already exists */ - TAILQ_FOREACH(flow, &sa->sa_flows, flow_entry) { - if (IKED_ADDR_EQ(&flow->flow_src, &flowa->flow_src) && - IKED_ADDR_EQ(&flow->flow_dst, &flowa->flow_dst) && - flow->flow_dir == flowa->flow_dir && - flow->flow_saproto == flowa->flow_saproto) { - free(flowa); - free(flowb); - goto done; - } - } - - memcpy(flowb, flowa, sizeof(*flowb)); - flowb->flow_dir = IPSP_DIRECTION_IN; - memcpy(&flowb->flow_dst, &flowa->flow_src, sizeof(flowa->flow_src)); - memcpy(&flowb->flow_src, &flowa->flow_dst, sizeof(flowa->flow_dst)); - - TAILQ_INSERT_TAIL(&sa->sa_flows, flowa, flow_entry); - TAILQ_INSERT_TAIL(&sa->sa_flows, flowb, flow_entry); - - done: - /* make sure IPCOMP CPIs are not reused */ - sa->sa_ipcomp = 0; - sa->sa_cpi_in = sa->sa_cpi_out = 0; - - return (0); -} - int ikev2_childsa_enable(struct iked *env, struct iked_sa *sa) { struct iked_childsa *csa; - struct iked_flow *flow, *oflow; - - if (sa->sa_ipcomp && sa->sa_cpi_in && sa->sa_cpi_out && - ikev2_ipcomp_enable(env, sa) == -1) - return (-1); + struct iked_flow *flow; TAILQ_FOREACH(csa, &sa->sa_childsas, csa_entry) { if (csa->csa_rekey || csa->csa_loaded) @@ -4675,14 +3723,6 @@ ikev2_childsa_enable(struct iked *env, struct iked_sa *sa) return (-1); } - if ((oflow = RB_FIND(iked_flows, &env->sc_activeflows, flow)) - != NULL) { - log_debug("%s: replaced old flow %p with %p", - __func__, oflow, flow); - oflow->flow_loaded = 0; - RB_REMOVE(iked_flows, &env->sc_activeflows, oflow); - } - RB_INSERT(iked_flows, &env->sc_activeflows, flow); log_debug("%s: loaded flow %p", __func__, flow); @@ -4692,11 +3732,11 @@ ikev2_childsa_enable(struct iked *env, struct iked_sa *sa) } int -ikev2_childsa_delete(struct iked *env, struct iked_sa *sa, uint8_t saproto, - uint64_t spi, uint64_t *spiptr, int cleanup) +ikev2_childsa_delete(struct iked *env, struct iked_sa *sa, u_int8_t saproto, + u_int64_t spi, u_int64_t *spiptr, int cleanup) { struct iked_childsa *csa, *nextcsa = NULL; - uint64_t peerspi = 0; + u_int64_t peerspi = 0; int found = 0; for (csa = TAILQ_FIRST(&sa->sa_childsas); csa != NULL; csa = nextcsa) { @@ -4739,7 +3779,7 @@ ikev2_valid_proposal(struct iked_proposal *prop, struct iked_transform **exf, struct iked_transform **ixf, int *esn) { struct iked_transform *xform, *encrxf, *integrxf; - unsigned int i, doesn = 0; + u_int i, doesn = 0; switch (prop->prop_protoid) { case IKEV2_SAPROTO_ESP: @@ -4782,17 +3822,19 @@ ikev2_valid_proposal(struct iked_proposal *prop, return (0); } -/* return 0 if processed, -1 if busy */ -int +void ikev2_acquire_sa(struct iked *env, struct iked_flow *acquire) { struct iked_flow *flow; struct iked_sa *sa; +#if defined(_OPENBSD_IPSEC_API_VERSION) struct iked_policy pol, *p = NULL; +#endif if (env->sc_passive) - return (0); + return; +#if defined(_OPENBSD_IPSEC_API_VERSION) /* First try to find an active flow with IKE SA */ flow = RB_FIND(iked_flows, &env->sc_activeflows, acquire); if (!flow) { @@ -4808,7 +3850,7 @@ ikev2_acquire_sa(struct iked *env, struct iked_flow *acquire) if ((p = policy_test(env, &pol)) == NULL) { log_warnx("%s: flow wasn't found", __func__); - return (0); + return; } log_debug("%s: found matching policy '%s'", __func__, @@ -4818,20 +3860,21 @@ ikev2_acquire_sa(struct iked *env, struct iked_flow *acquire) log_warnx("%s: failed to initiate a " "IKE_SA_INIT exchange", __func__); } else { +#else + if ((flow = acquire) != NULL) { +#endif log_debug("%s: found active flow", __func__); if ((sa = flow->flow_ikesa) == NULL) { log_warnx("%s: flow without SA", __func__); - return (0); + return; } - if (sa->sa_stateflags & IKED_REQ_CHILDSA) - return (-1); /* busy, retry later */ + if (ikev2_send_create_child_sa(env, sa, NULL, flow->flow_saproto) != 0) log_warnx("%s: failed to initiate a " "CREATE_CHILD_SA exchange", __func__); } - return (0); } void @@ -4847,8 +3890,7 @@ ikev2_disable_rekeying(struct iked *env, struct iked_sa *sa) (void)ikev2_childsa_delete(env, sa, 0, 0, NULL, 1); } -/* return 0 if processed, -1 if busy */ -int +void ikev2_rekey_sa(struct iked *env, struct iked_spi *rekey) { struct iked_childsa *csa, key; @@ -4857,65 +3899,52 @@ ikev2_rekey_sa(struct iked *env, struct iked_spi *rekey) key.csa_spi = *rekey; csa = RB_FIND(iked_activesas, &env->sc_activesas, &key); if (!csa) - return (0); + return; if (csa->csa_rekey) /* See if it's already taken care of */ - return (0); - if (csa->csa_saproto == IKEV2_SAPROTO_IPCOMP) /* no rekey */ - return (0); + return; if ((sa = csa->csa_ikesa) == NULL) { log_warnx("%s: SA %s doesn't have a parent SA", __func__, print_spi(rekey->spi, rekey->spi_size)); - return (0); + return; } if (!sa_stateok(sa, IKEV2_STATE_ESTABLISHED)) { log_warnx("%s: SA %s is not established", __func__, print_spi(rekey->spi, rekey->spi_size)); - return (0); + return; } - if (sa->sa_stateflags & IKED_REQ_CHILDSA) - return (-1); /* busy, retry later */ if (csa->csa_allocated) /* Peer SPI died first, get the local one */ rekey->spi = csa->csa_peerspi; if (ikev2_send_create_child_sa(env, sa, rekey, rekey->spi_protoid)) log_warnx("%s: failed to initiate a CREATE_CHILD_SA exchange", __func__); - return (0); } -/* return 0 if processed, -1 if busy */ -int +void ikev2_drop_sa(struct iked *env, struct iked_spi *drop) { struct ibuf *buf = NULL; struct iked_childsa *csa, key; struct iked_sa *sa; struct ikev2_delete *del; - uint32_t spi32; + u_int32_t spi32; key.csa_spi = *drop; csa = RB_FIND(iked_activesas, &env->sc_activesas, &key); if (!csa || csa->csa_rekey) - return (0); - - sa = csa->csa_ikesa; - if (sa && (sa->sa_stateflags & IKED_REQ_CHILDSA)) - return (-1); /* busy, retry later */ - + return; RB_REMOVE(iked_activesas, &env->sc_activesas, csa); csa->csa_loaded = 0; - csa->csa_rekey = 1; /* prevent re-loading */ - if (sa == NULL) { + if ((sa = csa->csa_ikesa) == NULL) { log_debug("%s: failed to find a parent SA", __func__); - return (0); - } - if (csa->csa_saproto == IKEV2_SAPROTO_IPCOMP) { - /* matching Child SAs (e.g. ESP) should have expired by now */ - if (csa->csa_children == 0) - ikev2_ipcomp_csa_free(env, csa); - return (0); + return; } + if ((buf = ibuf_static()) == NULL) + goto done; + if ((del = ibuf_advance(buf, sizeof(*del))) == NULL) + goto done; + if (csa->csa_allocated) spi32 = htobe32(csa->csa_spi.spi); else @@ -4929,7 +3958,7 @@ ikev2_drop_sa(struct iked *env, struct iked_spi *drop) /* Send PAYLOAD_DELETE */ if ((buf = ibuf_static()) == NULL) - return (0); + return; if ((del = ibuf_advance(buf, sizeof(*del))) == NULL) goto done; del->del_protoid = drop->spi_protoid; @@ -4951,13 +3980,13 @@ ikev2_drop_sa(struct iked *env, struct iked_spi *drop) done: ibuf_release(buf); - return (0); + return; } int ikev2_print_id(struct iked_id *id, char *idstr, size_t idstrlen) { - uint8_t buf[BUFSIZ], *ptr; + u_int8_t buf[BUFSIZ], *ptr; struct sockaddr_in *s4; struct sockaddr_in6 *s6; char *str; @@ -4993,10 +4022,12 @@ ikev2_print_id(struct iked_id *id, char *idstr, size_t idstrlen) case IKEV2_ID_IPV4: s4 = (struct sockaddr_in *)buf; s4->sin_family = AF_INET; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN s4->sin_len = sizeof(*s4); +#endif memcpy(&s4->sin_addr.s_addr, ptr, len); - if (print_host((struct sockaddr *)s4, + if (print_host((struct sockaddr_storage *)s4, idstr, idstrlen) == NULL) return (-1); break; @@ -5017,10 +4048,12 @@ ikev2_print_id(struct iked_id *id, char *idstr, size_t idstrlen) case IKEV2_ID_IPV6: s6 = (struct sockaddr_in6 *)buf; s6->sin6_family = AF_INET6; +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN s6->sin6_len = sizeof(*s6); +#endif memcpy(&s6->sin6_addr, ptr, len); - if (print_host((struct sockaddr *)s6, + if (print_host((struct sockaddr_storage *)s6, idstr, idstrlen) == NULL) return (-1); break; @@ -5043,144 +4076,3 @@ ikev2_print_id(struct iked_id *id, char *idstr, size_t idstrlen) return (0); } - -/* - * If we have an IKEV2_CP_REQUEST for IKEV2_CFG_INTERNAL_IP4_ADDRESS and - * if a network(pool) is configured, then select an address from that pool - * and remember it in the sa_addrpool attribute. - */ -int -ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa) -{ - struct iked_cfg *ikecfg = NULL; - struct iked_policy *pol = sa->sa_policy; - struct sockaddr_in *in4 = NULL, *cfg4 = NULL; - struct sockaddr_in6 *in6 = NULL, *cfg6 = NULL; - struct iked_sa key; - struct iked_addr addr; - uint32_t mask, host, lower, upper, start; - size_t i; - - if (sa->sa_addrpool || pol->pol_ncfg == 0) - return (0); - /* check for an address pool config (address w/ prefixlen != 32) */ - bzero(&addr, sizeof(addr)); - for (i = 0; i < pol->pol_ncfg; i++) { - ikecfg = &pol->pol_cfg[i]; - if (ikecfg->cfg_type == IKEV2_CFG_INTERNAL_IP4_ADDRESS && - ikecfg->cfg.address.addr_mask != 32) { - addr.addr_af = AF_INET; - break; - } - if (ikecfg->cfg_type == IKEV2_CFG_INTERNAL_IP6_ADDRESS && - ikecfg->cfg.address.addr_mask != 128) { - addr.addr_af = AF_INET6; - break; - } - } - if (i == pol->pol_ncfg) - return (0); - - /* - * failure: pool configured, but not requested. - * If we continue, we might end up with flows where 0.0.0.0 is NOT - * replaced with an address from the pool with ikev2_cp_fixaddr(). - */ - if (sa->sa_cp != IKEV2_CP_REQUEST) { - log_debug("%s: pool configured, but IKEV2_CP_REQUEST missing", - __func__); - return (-1); - } - - /* truncate prefixlen in the v6 case */ - mask = prefixlen2mask(ikecfg->cfg.address.addr_mask); - - switch (addr.addr_af) { - case AF_INET: - cfg4 = (struct sockaddr_in *)&ikecfg->cfg.address.addr; - in4 = (struct sockaddr_in *)&addr.addr; - in4->sin_family = AF_INET; - in4->sin_len = sizeof(*in4); - lower = ntohl(cfg4->sin_addr.s_addr & ~mask); - break; - case AF_INET6: - cfg6 = (struct sockaddr_in6 *)&ikecfg->cfg.address.addr; - in6 = (struct sockaddr_in6 *)&addr.addr; - in6->sin6_family = AF_INET6; - in6->sin6_len = sizeof(*in6); - lower = cfg6->sin6_addr.s6_addr[3]; - break; - default: - return (-1); - } - - if (lower == 0) - lower = 1; - /* Note that start, upper and host are in HOST byte order */ - upper = ntohl(~mask); - /* Randomly select start from [lower, upper-1] */ - start = arc4random_uniform(upper - lower) + lower; - - key.sa_addrpool = &addr; - - for (host = start;;) { - log_debug("%s: mask %x start %x lower %x host %x upper %x", - __func__, mask, start, lower, host, upper); - switch (addr.addr_af) { - case AF_INET: - in4->sin_addr.s_addr = - (cfg4->sin_addr.s_addr & mask) | htonl(host); - break; - case AF_INET6: - memcpy(in6, cfg6, sizeof(*in6)); - in6->sin6_addr.s6_addr[3] = htonl(host); - break; - } - if (!RB_FIND(iked_addrpool, &env->sc_addrpool, &key)) - break; - /* try next address */ - host++; - /* but skip broadcast and network address */ - if (host >= upper || host < lower) - host = lower; - if (host == start) - return (-1); /* exhausted */ - } - if (!key.sa_addrpool) - return (-1); /* cannot happen? */ - if ((sa->sa_addrpool = calloc(1, sizeof(addr))) == NULL) - return (-1); - memcpy(sa->sa_addrpool, &addr, sizeof(addr)); - RB_INSERT(iked_addrpool, &env->sc_addrpool, sa); - return (0); -} - -/* - * if 'addr' is 'UNSPECIFIED' replace it with sa_addrpool from - * the ip-pool and store the result in 'patched'. - */ -int -ikev2_cp_fixaddr(struct iked_sa *sa, struct iked_addr *addr, - struct iked_addr *patched) -{ - struct sockaddr_in *in4; - struct sockaddr_in6 *in6; - - if (sa->sa_addrpool == NULL || - sa->sa_addrpool->addr_af != addr->addr_af) - return (-1); - switch (addr->addr_af) { - case AF_INET: - in4 = (struct sockaddr_in *)&addr->addr; - if (in4->sin_addr.s_addr) - return (-1); - break; - case AF_INET6: - in6 = (struct sockaddr_in6 *)&addr->addr; - if (IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) - return (-1); - break; - } - memcpy(patched, sa->sa_addrpool, sizeof(*patched)); - return (0); -} diff --git a/iked/ikev2.h b/iked/ikev2.h index 05df987..439e8ab 100644 --- a/iked/ikev2.h +++ b/iked/ikev2.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.h,v 1.22 2015/10/02 22:14:39 reyk Exp $ */ +/* $OpenBSD: ikev2.h,v 1.12 2013/03/30 16:31:37 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef IKED_IKEV2_H -#define IKED_IKEV2_H +#ifndef _IKEV2_H +#define _IKEV2_H #define IKEV2_VERSION 0x20 /* IKE version 2.0 */ #define IKEV1_VERSION 0x10 /* IKE version 1.0 */ @@ -32,14 +32,12 @@ #define IKEV2_STATE_COOKIE 1 /* cookie requested */ #define IKEV2_STATE_SA_INIT 2 /* init IKE SA */ #define IKEV2_STATE_EAP 3 /* EAP requested */ -#define IKEV2_STATE_EAP_SUCCESS 4 /* EAP succeeded */ -#define IKEV2_STATE_AUTH_REQUEST 5 /* auth received */ -#define IKEV2_STATE_AUTH_SUCCESS 6 /* authenticated */ -#define IKEV2_STATE_VALID 7 /* authenticated AND validated certs */ -#define IKEV2_STATE_EAP_VALID 8 /* EAP validated */ -#define IKEV2_STATE_ESTABLISHED 9 /* active IKE SA */ -#define IKEV2_STATE_CLOSING 10 /* expect delete for this SA */ -#define IKEV2_STATE_CLOSED 11 /* delete this SA */ +#define IKEV2_STATE_AUTH_REQUEST 4 /* auth received */ +#define IKEV2_STATE_AUTH_SUCCESS 5 /* authenticated */ +#define IKEV2_STATE_VALID 6 /* validated peer certs */ +#define IKEV2_STATE_EAP_VALID 7 /* EAP validated */ +#define IKEV2_STATE_ESTABLISHED 8 /* active IKE SA */ +#define IKEV2_STATE_CLOSED 9 /* delete this SA */ extern struct iked_constmap ikev2_state_map[]; @@ -73,9 +71,9 @@ extern struct iked_constmap ikev2_flag_map[]; */ struct ikev2_payload { - uint8_t pld_nextpayload; /* Next payload type */ - uint8_t pld_reserved; /* Contains the critical bit */ - uint16_t pld_length; /* Payload length with header */ + u_int8_t pld_nextpayload; /* Next payload type */ + u_int8_t pld_reserved; /* Contains the critical bit */ + u_int16_t pld_length; /* Payload length with header */ } __packed; #define IKEV2_CRITICAL_PAYLOAD 0x01 /* First bit in the reserved field */ @@ -107,13 +105,13 @@ extern struct iked_constmap ikev2_payload_map[]; */ struct ikev2_sa_proposal { - uint8_t sap_more; /* Last proposal or more */ - uint8_t sap_reserved; /* Must be set to zero */ - uint16_t sap_length; /* Proposal length */ - uint8_t sap_proposalnr; /* Proposal number */ - uint8_t sap_protoid; /* Protocol Id */ - uint8_t sap_spisize; /* SPI size */ - uint8_t sap_transforms; /* Number of transforms */ + u_int8_t sap_more; /* Last proposal or more */ + u_int8_t sap_reserved; /* Must be set to zero */ + u_int16_t sap_length; /* Proposal length */ + u_int8_t sap_proposalnr; /* Proposal number */ + u_int8_t sap_protoid; /* Protocol Id */ + u_int8_t sap_spisize; /* SPI size */ + u_int8_t sap_transforms; /* Number of transforms */ /* Followed by variable-length SPI */ /* Followed by variable-length transforms */ } __packed; @@ -127,17 +125,16 @@ struct ikev2_sa_proposal { #define IKEV2_SAPROTO_ESP 3 /* ESP */ #define IKEV2_SAPROTO_FC_ESP_HEADER 4 /* RFC4595 */ #define IKEV2_SAPROTO_FC_CT_AUTH 5 /* RFC4595 */ -#define IKEV2_SAPROTO_IPCOMP 204 /* private, should be 4 */ extern struct iked_constmap ikev2_saproto_map[]; struct ikev2_transform { - uint8_t xfrm_more; /* Last transform or more */ - uint8_t xfrm_reserved; /* Must be set to zero */ - uint16_t xfrm_length; /* Transform length */ - uint8_t xfrm_type; /* Transform type */ - uint8_t xfrm_reserved1; /* Must be set to zero */ - uint16_t xfrm_id; /* Transform Id */ + u_int8_t xfrm_more; /* Last transform or more */ + u_int8_t xfrm_reserved; /* Must be set to zero */ + u_int16_t xfrm_length; /* Transform length */ + u_int8_t xfrm_type; /* Transform type */ + u_int8_t xfrm_reserved1; /* Must be set to zero */ + u_int16_t xfrm_id; /* Transform Id */ /* Followed by variable-length transform attributes */ } __packed; @@ -180,7 +177,6 @@ extern struct iked_constmap ikev2_xformtype_map[]; #define IKEV2_XFORMENCR_CAMELLIA_CCM_8 25 /* RFC5529 */ #define IKEV2_XFORMENCR_CAMELLIA_CCM_12 26 /* RFC5529 */ #define IKEV2_XFORMENCR_CAMELLIA_CCM_16 27 /* RFC5529 */ -#define IKEV2_XFORMENCR_CHACHA20_POLY1305 28 /* RFC7634 */ extern struct iked_constmap ikev2_xformencr_map[]; @@ -243,7 +239,7 @@ extern struct iked_constmap ikev2_xformauth_map[]; #define IKEV2_XFORMDH_BRAINPOOL_P256R1 28 /* DH Group 28 */ #define IKEV2_XFORMDH_BRAINPOOL_P384R1 29 /* DH Group 29 */ #define IKEV2_XFORMDH_BRAINPOOL_P512R1 30 /* DH Group 30 */ -#define IKEV2_XFORMDH_X_CURVE25519 1034 /* draft-ietf-ipsecme-safecurves-00 */ +#define IKEV2_XFORMDH_MAX 31 extern struct iked_constmap ikev2_xformdh_map[]; @@ -253,8 +249,8 @@ extern struct iked_constmap ikev2_xformdh_map[]; extern struct iked_constmap ikev2_xformesn_map[]; struct ikev2_attribute { - uint16_t attr_type; /* Attribute type */ - uint16_t attr_length; /* Attribute length or value */ + u_int16_t attr_type; /* Attribute type */ + u_int16_t attr_length; /* Attribute length or value */ /* Followed by variable length (TLV) */ } __packed; @@ -270,8 +266,8 @@ extern struct iked_constmap ikev2_attrtype_map[]; */ struct ikev2_keyexchange { - uint16_t kex_dhgroup; /* DH Group # */ - uint16_t kex_reserved; /* Reserved */ + u_int16_t kex_dhgroup; /* DH Group # */ + u_int16_t kex_reserved; /* Reserved */ } __packed; /* @@ -279,9 +275,9 @@ struct ikev2_keyexchange { */ struct ikev2_notify { - uint8_t n_protoid; /* Protocol Id */ - uint8_t n_spisize; /* SPI size */ - uint16_t n_type; /* Notify message type */ + u_int8_t n_protoid; /* Protocol Id */ + u_int8_t n_spisize; /* SPI size */ + u_int16_t n_type; /* Notify message type */ /* Followed by variable length SPI */ /* Followed by variable length notification data */ } __packed; @@ -351,7 +347,6 @@ struct ikev2_notify { #define IKEV2_N_PSK_CONFIRM 16426 /* RFC6631 */ #define IKEV2_N_ERX_SUPPORTED 16427 /* RFC6867 */ #define IKEV2_N_IFOM_CAPABILITY 16428 /* OA3GPP */ -#define IKEV2_N_SIGNATURE_HASH_ALGORITHMS 16431 /* RFC7427 */ extern struct iked_constmap ikev2_n_map[]; @@ -360,9 +355,9 @@ extern struct iked_constmap ikev2_n_map[]; */ struct ikev2_delete { - uint8_t del_protoid; /* Protocol Id */ - uint8_t del_spisize; /* SPI size */ - uint16_t del_nspi; /* Number of SPIs */ + u_int8_t del_protoid; /* Protocol Id */ + u_int8_t del_spisize; /* SPI size */ + u_int16_t del_nspi; /* Number of SPIs */ /* Followed by variable length SPIs */ } __packed; @@ -371,8 +366,8 @@ struct ikev2_delete { */ struct ikev2_id { - uint8_t id_type; /* Id type */ - uint8_t id_reserved[3]; /* Reserved */ + u_int8_t id_type; /* Id type */ + u_int8_t id_reserved[3]; /* Reserved */ /* Followed by the identification data */ } __packed; @@ -393,7 +388,7 @@ extern struct iked_constmap ikev2_id_map[]; */ struct ikev2_cert { - uint8_t cert_type; /* Encoding */ + u_int8_t cert_type; /* Encoding */ /* Followed by the certificate data */ } __packed; @@ -419,17 +414,17 @@ extern struct iked_constmap ikev2_cert_map[]; */ struct ikev2_tsp { - uint8_t tsp_count; /* Number of TSs */ - uint8_t tsp_reserved[3]; /* Reserved */ + u_int8_t tsp_count; /* Number of TSs */ + u_int8_t tsp_reserved[3]; /* Reserved */ /* Followed by the traffic selectors */ } __packed; struct ikev2_ts { - uint8_t ts_type; /* TS type */ - uint8_t ts_protoid; /* Protocol Id */ - uint16_t ts_length; /* Length */ - uint16_t ts_startport; /* Start port */ - uint16_t ts_endport; /* End port */ + u_int8_t ts_type; /* TS type */ + u_int8_t ts_protoid; /* Protocol Id */ + u_int16_t ts_length; /* Length */ + u_int16_t ts_startport; /* Start port */ + u_int16_t ts_endport; /* End port */ } __packed; #define IKEV2_TS_IPV4_ADDR_RANGE 7 /* RFC4306 */ @@ -443,8 +438,8 @@ extern struct iked_constmap ikev2_ts_map[]; */ struct ikev2_auth { - uint8_t auth_method; /* Signature type */ - uint8_t auth_reserved[3]; /* Reserved */ + u_int8_t auth_method; /* Signature type */ + u_int8_t auth_reserved[3]; /* Reserved */ /* Followed by the signature */ } __packed; @@ -456,28 +451,16 @@ struct ikev2_auth { #define IKEV2_AUTH_ECDSA_384 10 /* RFC4754 */ #define IKEV2_AUTH_ECDSA_512 11 /* RFC4754 */ #define IKEV2_AUTH_GSPM 12 /* RFC6467 */ -#define IKEV2_AUTH_NULL 13 /* RFC7619 */ -#define IKEV2_AUTH_SIG 14 /* RFC7427 */ extern struct iked_constmap ikev2_auth_map[]; -/* Notifications used together with IKEV2_AUTH_SIG */ - -#define IKEV2_SIGHASH_RESERVED 0 /* RFC7427 */ -#define IKEV2_SIGHASH_SHA1 1 /* RFC7427 */ -#define IKEV2_SIGHASH_SHA2_256 2 /* RFC7427 */ -#define IKEV2_SIGHASH_SHA2_384 3 /* RFC7427 */ -#define IKEV2_SIGHASH_SHA2_512 4 /* RFC7427 */ - -extern struct iked_constmap ikev2_sighash_map[]; - /* * CP payload */ struct ikev2_cp { - uint8_t cp_type; - uint8_t cp_reserved[3]; + u_int8_t cp_type; + u_int8_t cp_reserved[3]; /* Followed by the attributes */ } __packed; @@ -489,8 +472,8 @@ struct ikev2_cp { extern struct iked_constmap ikev2_cp_map[]; struct ikev2_cfg { - uint16_t cfg_type; /* first bit must be set to zero */ - uint16_t cfg_length; + u_int16_t cfg_type; /* first bit must be set to zero */ + u_int16_t cfg_length; /* Followed by variable-length data */ } __packed; @@ -517,4 +500,4 @@ struct ikev2_cfg { extern struct iked_constmap ikev2_cfg_map[]; -#endif /* IKED_IKEV2_H */ +#endif /* _IKEV2_H */ diff --git a/iked/ikev2_msg.c b/iked/ikev2_msg.c index b03db56..12016c8 100644 --- a/iked/ikev2_msg.c +++ b/iked/ikev2_msg.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2_msg.c,v 1.43 2015/08/21 11:59:27 reyk Exp $ */ +/* $OpenBSD: ikev2_msg.c,v 1.25 2013/03/21 04:30:14 deraadt Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,19 +16,23 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include /* roundup */ -#include +#include +#include "openbsd-compat/sys-queue.h" #include #include #include #include +#if defined(__OpenBSD__) +#include +#endif #include #include #include #include #include +#include #include #include #include @@ -53,8 +57,8 @@ ikev2_msg_cb(int fd, short event, void *arg) struct iked *env = sock->sock_env; struct iked_message msg; struct ike_header hdr; - uint32_t natt = 0x00000000; - uint8_t buf[IKED_MSGBUF_MAX]; + u_int32_t natt = 0x00000000; + u_int8_t buf[IKED_MSGBUF_MAX]; ssize_t len; off_t off; struct iovec iov[2]; @@ -73,9 +77,8 @@ ikev2_msg_cb(int fd, short event, void *arg) (ssize_t)sizeof(natt)) return; - if (socket_getport((struct sockaddr *)&msg.msg_local) == - IKED_NATT_PORT) { - if (memcmp(&natt, buf, sizeof(natt)) != 0) + if (socket_getport(&msg.msg_local) == IKED_NATT_PORT) { + if (bcmp(&natt, buf, sizeof(natt)) != 0) return; msg.msg_natt = 1; off = sizeof(natt); @@ -95,8 +98,8 @@ ikev2_msg_cb(int fd, short event, void *arg) iov[1].iov_base = buf; iov[1].iov_len = len; - proc_composev_imsg(&env->sc_ps, PROC_IKEV1, -1, - IMSG_IKE_MESSAGE, -1, iov, 2); + proc_composev_imsg(env, PROC_IKEV1, IMSG_IKE_MESSAGE, -1, + iov, 2); goto done; } TAILQ_INIT(&msg.msg_proposals); @@ -133,14 +136,11 @@ ikev2_msg_copy(struct iked *env, struct iked_message *msg) { struct iked_message *m = NULL; struct ibuf *buf; - size_t len; + ssize_t len; void *ptr; - if (ibuf_size(msg->msg_data) < msg->msg_offset) - return (NULL); - len = ibuf_size(msg->msg_data) - msg->msg_offset; - - if ((ptr = ibuf_seek(msg->msg_data, msg->msg_offset, len)) == NULL || + if ((len = ibuf_size(msg->msg_data) - msg->msg_offset) <= 0 || + (ptr = ibuf_seek(msg->msg_data, msg->msg_offset, len)) == NULL || (m = malloc(sizeof(*m))) == NULL || (buf = ikev2_msg_init(env, m, &msg->msg_peer, msg->msg_peerlen, &msg->msg_local, msg->msg_locallen, msg->msg_response)) == NULL || @@ -188,22 +188,8 @@ ikev2_msg_valid_ike_sa(struct iked *env, struct ike_header *oldhdr, struct iked_sa sa; #endif - if (msg->msg_sa != NULL && msg->msg_policy != NULL) { - /* - * Only permit informational requests from initiator - * on closing SAs (for DELETE). - */ - if (msg->msg_sa->sa_state == IKEV2_STATE_CLOSING) { - if (((oldhdr->ike_flags & - (IKEV2_FLAG_INITIATOR|IKEV2_FLAG_RESPONSE)) == - IKEV2_FLAG_INITIATOR) && - (oldhdr->ike_exchange == - IKEV2_EXCHANGE_INFORMATIONAL)) - return (0); - return (-1); - } + if (msg->msg_sa != NULL && msg->msg_policy != NULL) return (0); - } #if 0 /* @@ -270,9 +256,8 @@ ikev2_msg_send(struct iked *env, struct iked_message *msg) { struct iked_sa *sa = msg->msg_sa; struct ibuf *buf = msg->msg_data; - uint32_t natt = 0x00000000; + u_int32_t natt = 0x00000000; int isnatt = 0; - uint8_t exchange, flags; struct ike_header *hdr; struct iked_message *m; @@ -282,14 +267,10 @@ ikev2_msg_send(struct iked *env, struct iked_message *msg) isnatt = (msg->msg_natt || (msg->msg_sa && msg->msg_sa->sa_natt)); - exchange = hdr->ike_exchange; - flags = hdr->ike_flags; - log_info("%s: %s %s from %s to %s msgid %u, %ld bytes%s", __func__, - print_map(exchange, ikev2_exchange_map), - (flags & IKEV2_FLAG_RESPONSE) ? "response" : "request", - print_host((struct sockaddr *)&msg->msg_local, NULL, 0), - print_host((struct sockaddr *)&msg->msg_peer, NULL, 0), - betoh32(hdr->ike_msgid), + log_info("%s: %s from %s to %s, %ld bytes%s", __func__, + print_map(hdr->ike_exchange, ikev2_exchange_map), + print_host(&msg->msg_local, NULL, 0), + print_host(&msg->msg_peer, NULL, 0), ibuf_length(buf), isnatt ? ", NAT-T" : ""); if (isnatt) { @@ -313,25 +294,27 @@ ikev2_msg_send(struct iked *env, struct iked_message *msg) log_debug("%s: failed to copy a message", __func__); return (-1); } - m->msg_exchange = exchange; + m->msg_exchange = hdr->ike_exchange; - if (flags & IKEV2_FLAG_RESPONSE) { + if (hdr->ike_flags & IKEV2_FLAG_RESPONSE) { TAILQ_INSERT_TAIL(&sa->sa_responses, m, msg_entry); - timer_set(env, &m->msg_timer, ikev2_msg_response_timeout, m); - timer_add(env, &m->msg_timer, IKED_RESPONSE_TIMEOUT); + timer_initialize(env, &m->msg_timer, + ikev2_msg_response_timeout, m); + timer_register(env, &m->msg_timer, IKED_RESPONSE_TIMEOUT); } else { TAILQ_INSERT_TAIL(&sa->sa_requests, m, msg_entry); - timer_set(env, &m->msg_timer, ikev2_msg_retransmit_timeout, m); - timer_add(env, &m->msg_timer, IKED_RETRANSMIT_TIMEOUT); + timer_initialize(env, &m->msg_timer, + ikev2_msg_retransmit_timeout, m); + timer_register(env, &m->msg_timer, IKED_RETRANSMIT_TIMEOUT); } return (0); } -uint32_t +u_int32_t ikev2_msg_id(struct iked *env, struct iked_sa *sa) { - uint32_t id = sa->sa_reqid; + u_int32_t id = sa->sa_reqid; if (++sa->sa_reqid == UINT32_MAX) { /* XXX we should close and renegotiate the connection now */ @@ -345,13 +328,13 @@ ikev2_msg_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf *src) { size_t len, ivlen, encrlen, integrlen, blocklen, outlen; - uint8_t *buf, pad = 0, *ptr; + u_int8_t *buf, pad = 0, *ptr; struct ibuf *encr, *dst = NULL, *out = NULL; buf = ibuf_data(src); len = ibuf_size(src); - log_debug("%s: decrypted length %zu", __func__, len); + log_debug("%s: decrypted length %d", __func__, len); print_hex(buf, 0, len); if (sa == NULL || @@ -383,7 +366,7 @@ ikev2_msg_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf *src) if (ibuf_add(src, &pad, sizeof(pad)) != 0) goto done; - log_debug("%s: padded length %zu", __func__, ibuf_size(src)); + log_debug("%s: padded length %d", __func__, ibuf_size(src)); print_hex(ibuf_data(src), 0, ibuf_size(src)); cipher_setkey(sa->sa_encr, encr->buf, ibuf_length(encr)); @@ -406,9 +389,9 @@ ikev2_msg_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf *src) if ((ptr = ibuf_advance(dst, integrlen)) == NULL) goto done; - explicit_bzero(ptr, integrlen); + bzero(ptr, integrlen); - log_debug("%s: length %zu, padding %d, output length %zu", + log_debug("%s: length %d, padding %d, output length %d", __func__, len + sizeof(pad), pad, ibuf_size(dst)); print_hex(ibuf_data(dst), 0, ibuf_size(dst)); @@ -428,9 +411,9 @@ ikev2_msg_integr(struct iked *env, struct iked_sa *sa, struct ibuf *src) int ret = -1; size_t integrlen, tmplen; struct ibuf *integr, *tmp = NULL; - uint8_t *ptr; + u_int8_t *ptr; - log_debug("%s: message length %zu", __func__, ibuf_size(src)); + log_debug("%s: message length %d", __func__, ibuf_size(src)); print_hex(ibuf_data(src), 0, ibuf_size(src)); if (sa == NULL || @@ -446,7 +429,7 @@ ikev2_msg_integr(struct iked *env, struct iked_sa *sa, struct ibuf *src) integrlen = hash_length(sa->sa_integr); - log_debug("%s: integrity checksum length %zu", __func__, + log_debug("%s: integrity checksum length %d", __func__, integrlen); /* @@ -486,7 +469,7 @@ ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, { ssize_t ivlen, encrlen, integrlen, blocklen, outlen, tmplen; - uint8_t pad = 0, *ptr; + u_int8_t pad = 0, *ptr; struct ibuf *integr, *encr, *tmp = NULL, *out = NULL; off_t ivoff, encroff, integroff; @@ -519,11 +502,11 @@ ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, goto done; } - log_debug("%s: IV length %zd", __func__, ivlen); + log_debug("%s: IV length %d", __func__, ivlen); print_hex(ibuf_data(src), 0, ivlen); - log_debug("%s: encrypted payload length %zd", __func__, encrlen); + log_debug("%s: encrypted payload length %d", __func__, encrlen); print_hex(ibuf_data(src), encroff, encrlen); - log_debug("%s: integrity checksum length %zd", __func__, integrlen); + log_debug("%s: integrity checksum length %d", __func__, integrlen); print_hex(ibuf_data(src), integroff, integrlen); /* @@ -573,7 +556,7 @@ ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, pad = *ptr; } - log_debug("%s: decrypted payload length %zd/%zd padding %d", + log_debug("%s: decrypted payload length %d/%d padding %d", __func__, outlen, encrlen, pad); print_hex(ibuf_data(out), 0, ibuf_size(out)); @@ -591,7 +574,7 @@ ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, int ikev2_msg_send_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf **ep, - uint8_t exchange, uint8_t firstpayload, int response) + u_int8_t exchange, u_int8_t firstpayload, int response) { struct iked_message resp; struct ike_header *hdr; @@ -600,8 +583,8 @@ ikev2_msg_send_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf **ep, int ret = -1; if ((buf = ikev2_msg_init(env, &resp, &sa->sa_peer.addr, - sa->sa_peer.addr.ss_len, &sa->sa_local.addr, - sa->sa_local.addr.ss_len, response)) == NULL) + SS_LEN(&sa->sa_peer.addr), &sa->sa_local.addr, + SS_LEN(&sa->sa_local.addr), response)) == NULL) goto done; resp.msg_msgid = response ? sa->sa_msgid : ikev2_msg_id(env, sa); @@ -654,7 +637,7 @@ struct ibuf * ikev2_msg_auth(struct iked *env, struct iked_sa *sa, int response) { struct ibuf *authmsg = NULL, *nonce, *prfkey, *buf; - uint8_t *ptr; + u_int8_t *ptr; struct iked_id *id; size_t tmplen; @@ -698,7 +681,7 @@ ikev2_msg_auth(struct iked *env, struct iked_sa *sa, int response) if (tmplen != hash_length(sa->sa_prf)) goto fail; - log_debug("%s: %s auth data length %zu", + log_debug("%s: %s auth data length %d", __func__, response ? "responder" : "initiator", ibuf_size(authmsg)); print_hex(ibuf_data(authmsg), 0, ibuf_size(authmsg)); @@ -712,14 +695,14 @@ ikev2_msg_auth(struct iked *env, struct iked_sa *sa, int response) int ikev2_msg_authverify(struct iked *env, struct iked_sa *sa, - struct iked_auth *auth, uint8_t *buf, size_t len, struct ibuf *authmsg) + struct iked_auth *auth, u_int8_t *buf, size_t len, struct ibuf *authmsg) { - uint8_t *key, *psk = NULL; + u_int8_t *key, *psk = NULL; ssize_t keylen; struct iked_id *id; struct iked_dsa *dsa = NULL; int ret = -1; - uint8_t keytype; + u_int8_t keytype; if (sa->sa_hdr.sh_initiator) id = &sa->sa_rcert; @@ -756,12 +739,12 @@ ikev2_msg_authverify(struct iked *env, struct iked_sa *sa, break; } - log_debug("%s: method %s keylen %zd type %s", __func__, + log_debug("%s: method %s keylen %d type %s", __func__, print_map(auth->auth_method, ikev2_auth_map), keylen, print_map(id->id_type, ikev2_cert_map)); if (dsa_setkey(dsa, key, keylen, keytype) == NULL || - dsa_init(dsa, buf, len) != 0 || + dsa_init(dsa) != 0 || dsa_update(dsa, ibuf_data(authmsg), ibuf_size(authmsg))) { log_debug("%s: failed to compute digital signature", __func__); goto done; @@ -770,7 +753,10 @@ ikev2_msg_authverify(struct iked *env, struct iked_sa *sa, if ((ret = dsa_verify_final(dsa, buf, len)) == 0) { log_debug("%s: authentication successful", __func__); sa_state(env, sa, IKEV2_STATE_AUTH_SUCCESS); - sa_stateflags(sa, IKED_REQ_AUTHVALID); + + if (!sa->sa_policy->pol_auth.auth_eap && + auth->auth_method == IKEV2_AUTH_SHARED_KEY_MIC) + sa_state(env, sa, IKEV2_STATE_VALID); } else { log_debug("%s: authentication failed", __func__); sa_state(env, sa, IKEV2_STATE_AUTH_REQUEST); @@ -788,14 +774,14 @@ int ikev2_msg_authsign(struct iked *env, struct iked_sa *sa, struct iked_auth *auth, struct ibuf *authmsg) { - uint8_t *key, *psk = NULL; + u_int8_t *key, *psk = NULL; ssize_t keylen; struct iked_hash *prf = sa->sa_prf; struct iked_id *id; struct iked_dsa *dsa = NULL; struct ibuf *buf; int ret = -1; - uint8_t keytype; + u_int8_t keytype; if (sa->sa_hdr.sh_initiator) id = &sa->sa_icert; @@ -833,7 +819,7 @@ ikev2_msg_authsign(struct iked *env, struct iked_sa *sa, } if (dsa_setkey(dsa, key, keylen, keytype) == NULL || - dsa_init(dsa, NULL, 0) != 0 || + dsa_init(dsa) != 0 || dsa_update(dsa, ibuf_data(authmsg), ibuf_size(authmsg))) { log_debug("%s: failed to compute digital signature", __func__); goto done; @@ -919,7 +905,7 @@ ikev2_msg_dispose(struct iked *env, struct iked_msgqueue *queue, struct iked_message *msg) { TAILQ_REMOVE(queue, msg, msg_entry); - timer_del(env, &msg->msg_timer); + timer_deregister(env, &msg->msg_timer); ikev2_msg_cleanup(env, msg); free(msg); } @@ -956,10 +942,11 @@ ikev2_msg_retransmit_response(struct iked *env, struct iked_sa *sa, ibuf_size(msg->msg_data), 0, (struct sockaddr *)&msg->msg_peer, msg->msg_peerlen)) == -1) { log_warn("%s: sendto", __func__); + sa_free(env, sa); return (-1); } - timer_add(env, &msg->msg_timer, IKED_RESPONSE_TIMEOUT); + timer_register(env, &msg->msg_timer, IKED_RESPONSE_TIMEOUT); return (0); } @@ -988,11 +975,10 @@ ikev2_msg_retransmit_timeout(struct iked *env, void *arg) return; } /* Exponential timeout */ - timer_add(env, &msg->msg_timer, + timer_register(env, &msg->msg_timer, IKED_RETRANSMIT_TIMEOUT * (2 << (msg->msg_tries++))); } else { - log_debug("%s: retransmit limit reached for msgid %u", - __func__, msg->msg_msgid); + log_debug("%s: retransmit limit reached", __func__); sa_free(env, sa); } } diff --git a/iked/ikev2_pld.c b/iked/ikev2_pld.c index dff525f..9e4ed78 100644 --- a/iked/ikev2_pld.c +++ b/iked/ikev2_pld.c @@ -1,8 +1,7 @@ -/* $OpenBSD: ikev2_pld.c,v 1.54 2015/10/01 13:57:29 sthen Exp $ */ +/* $OpenBSD: ikev2_pld.c,v 1.31 2013/03/21 04:30:14 deraadt Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter - * Copyright (c) 2014 Hans-Joerg Hoexer * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,18 +16,23 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +#include +#include "openbsd-compat/sys-queue.h" #include #include #include #include +#if defined(__OpenBSD__) +#include +#endif #include #include #include #include #include +#include #include #include #include @@ -43,72 +47,42 @@ #include "eap.h" #include "dh.h" -int ikev2_validate_pld(struct iked_message *, size_t, size_t, - struct ikev2_payload *); int ikev2_pld_payloads(struct iked *, struct iked_message *, - size_t, size_t, unsigned int); -int ikev2_validate_sa(struct iked_message *, size_t, size_t, - struct ikev2_payload *, struct ikev2_sa_proposal *); + off_t, size_t, u_int, int); int ikev2_pld_sa(struct iked *, struct ikev2_payload *, - struct iked_message *, size_t, size_t); -int ikev2_validate_xform(struct iked_message *, size_t, size_t, - struct ikev2_transform *); + struct iked_message *, off_t); int ikev2_pld_xform(struct iked *, struct ikev2_sa_proposal *, - struct iked_message *, size_t, size_t); -int ikev2_validate_attr(struct iked_message *, size_t, size_t, - struct ikev2_attribute *); + struct iked_message *, off_t); int ikev2_pld_attr(struct iked *, struct ikev2_transform *, - struct iked_message *, size_t, size_t); -int ikev2_validate_ke(struct iked_message *, size_t, size_t, - struct ikev2_payload *, struct ikev2_keyexchange *); + struct iked_message *, off_t, int); int ikev2_pld_ke(struct iked *, struct ikev2_payload *, - struct iked_message *, size_t, size_t); -int ikev2_validate_id(struct iked_message *, size_t, size_t, - struct ikev2_payload *, struct ikev2_id *); + struct iked_message *, off_t); int ikev2_pld_id(struct iked *, struct ikev2_payload *, - struct iked_message *, size_t, size_t, unsigned int); -int ikev2_validate_cert(struct iked_message *, size_t, size_t, - struct ikev2_payload *, struct ikev2_cert *); + struct iked_message *, off_t, u_int); int ikev2_pld_cert(struct iked *, struct ikev2_payload *, - struct iked_message *, size_t, size_t); -int ikev2_validate_certreq(struct iked_message *, size_t, size_t, - struct ikev2_payload *, struct ikev2_cert *); + struct iked_message *, off_t); int ikev2_pld_certreq(struct iked *, struct ikev2_payload *, - struct iked_message *, size_t, size_t); -int ikev2_validate_nonce(struct iked_message *, size_t, size_t, - struct ikev2_payload *); + struct iked_message *, off_t); int ikev2_pld_nonce(struct iked *, struct ikev2_payload *, - struct iked_message *, size_t, size_t); -int ikev2_validate_notify(struct iked_message *, size_t, size_t, - struct ikev2_payload *, struct ikev2_notify *); + struct iked_message *, off_t); int ikev2_pld_notify(struct iked *, struct ikev2_payload *, - struct iked_message *, size_t, size_t); -int ikev2_validate_delete(struct iked_message *, size_t, size_t, - struct ikev2_payload *, struct ikev2_delete *); + struct iked_message *, off_t); int ikev2_pld_delete(struct iked *, struct ikev2_payload *, - struct iked_message *, size_t, size_t); -int ikev2_validate_ts(struct iked_message *, size_t, size_t, - struct ikev2_payload *, struct ikev2_tsp *); + struct iked_message *, off_t); int ikev2_pld_ts(struct iked *, struct ikev2_payload *, - struct iked_message *, size_t, size_t, unsigned int); -int ikev2_validate_auth(struct iked_message *, size_t, size_t, - struct ikev2_payload *, struct ikev2_auth *); + struct iked_message *, off_t, u_int); int ikev2_pld_auth(struct iked *, struct ikev2_payload *, - struct iked_message *, size_t, size_t); + struct iked_message *, off_t); int ikev2_pld_e(struct iked *, struct ikev2_payload *, - struct iked_message *, size_t); -int ikev2_validate_cp(struct iked_message *, size_t, size_t, - struct ikev2_payload *, struct ikev2_cp *); + struct iked_message *, off_t); int ikev2_pld_cp(struct iked *, struct ikev2_payload *, - struct iked_message *, size_t, size_t); -int ikev2_validate_eap(struct iked_message *, size_t, size_t, - struct ikev2_payload *, struct eap_header *); + struct iked_message *, off_t); int ikev2_pld_eap(struct iked *, struct ikev2_payload *, - struct iked_message *, size_t, size_t); + struct iked_message *, off_t); int ikev2_pld_parse(struct iked *env, struct ike_header *hdr, - struct iked_message *msg, size_t offset) + struct iked_message *msg, off_t offset) { log_debug("%s: header ispi %s rspi %s" " nextpayload %s version 0x%02x exchange %s flags 0x%02x" @@ -131,130 +105,94 @@ ikev2_pld_parse(struct iked *env, struct ike_header *hdr, offset += sizeof(*hdr); return (ikev2_pld_payloads(env, msg, offset, - betoh32(hdr->ike_length), hdr->ike_nextpayload)); -} - -int -ikev2_validate_pld(struct iked_message *msg, size_t offset, size_t left, - struct ikev2_payload *pld) -{ - uint8_t *msgbuf = ibuf_data(msg->msg_data); - size_t pld_length; - - /* We need at least the generic header. */ - if (left < sizeof(*pld)) { - log_debug("%s: malformed payload: too short for generic " - "header (%zu < %zu)", __func__, left, sizeof(*pld)); - return (-1); - } - memcpy(pld, msgbuf + offset, sizeof(*pld)); - - /* - * We need at least the specified number of bytes. - * pld_length is the full size of the payload including - * the generic payload header. - */ - pld_length = betoh16(pld->pld_length); - if (left < pld_length) { - log_debug("%s: malformed payload: shorter than specified " - "(%zu < %zu)", __func__, left, pld_length); - return (-1); - } - /* - * Sanity check the specified payload size, it must - * be at last the size of the generic payload header. - */ - if (pld_length < sizeof(*pld)) { - log_debug("%s: malformed payload: shorter than minimum " - "header size (%zu < %zu)", __func__, pld_length, - sizeof(*pld)); - return (-1); - } - - return (0); + betoh32(hdr->ike_length), hdr->ike_nextpayload, 0)); } int ikev2_pld_payloads(struct iked *env, struct iked_message *msg, - size_t offset, size_t length, unsigned int payload) + off_t offset, size_t length, u_int payload, int quick) { struct ikev2_payload pld; - unsigned int e; + u_int e; int ret; - uint8_t *msgbuf = ibuf_data(msg->msg_data); - size_t left; + u_int8_t *msgbuf = ibuf_data(msg->msg_data); /* Check if message was decrypted in an E payload */ e = msg->msg_e ? IKED_E : 0; - while (payload != 0 && offset < length) { - /* Bytes left in datagram. */ - left = length - offset; + if (quick) + print_debug("%s: %spayloads", __func__, + e ? "decrypted " : ""); + else + ikev2_pld_payloads(env, msg, offset, length, payload, 1); - if (ikev2_validate_pld(msg, offset, left, &pld)) - return (-1); + while (payload != 0 && offset < (off_t)length) { + memcpy(&pld, msgbuf + offset, sizeof(pld)); - log_debug("%s: %spayload %s" - " nextpayload %s critical 0x%02x length %d", - __func__, e ? "decrypted " : "", - print_map(payload, ikev2_payload_map), - print_map(pld.pld_nextpayload, ikev2_payload_map), - pld.pld_reserved & IKEV2_CRITICAL_PAYLOAD, - betoh16(pld.pld_length)); + if (quick) + print_debug(" %s", + print_map(payload, ikev2_payload_map)); + else + log_debug("%s: %spayload %s" + " nextpayload %s critical 0x%02x length %d", + __func__, e ? "decrypted " : "", + print_map(payload, ikev2_payload_map), + print_map(pld.pld_nextpayload, ikev2_payload_map), + pld.pld_reserved & IKEV2_CRITICAL_PAYLOAD, + betoh16(pld.pld_length)); - /* Skip over generic payload header. */ offset += sizeof(pld); - left -= sizeof(pld); ret = 0; + if (quick) + goto next; + switch (payload | e) { case IKEV2_PAYLOAD_SA: case IKEV2_PAYLOAD_SA | IKED_E: - ret = ikev2_pld_sa(env, &pld, msg, offset, left); + ret = ikev2_pld_sa(env, &pld, msg, offset); break; case IKEV2_PAYLOAD_KE: case IKEV2_PAYLOAD_KE | IKED_E: - ret = ikev2_pld_ke(env, &pld, msg, offset, left); + ret = ikev2_pld_ke(env, &pld, msg, offset); break; case IKEV2_PAYLOAD_IDi | IKED_E: case IKEV2_PAYLOAD_IDr | IKED_E: - ret = ikev2_pld_id(env, &pld, msg, offset, left, - payload); + ret = ikev2_pld_id(env, &pld, msg, offset, payload); break; case IKEV2_PAYLOAD_CERT | IKED_E: - ret = ikev2_pld_cert(env, &pld, msg, offset, left); + ret = ikev2_pld_cert(env, &pld, msg, offset); break; case IKEV2_PAYLOAD_CERTREQ: case IKEV2_PAYLOAD_CERTREQ | IKED_E: - ret = ikev2_pld_certreq(env, &pld, msg, offset, left); + ret = ikev2_pld_certreq(env, &pld, msg, offset); break; case IKEV2_PAYLOAD_AUTH | IKED_E: - ret = ikev2_pld_auth(env, &pld, msg, offset, left); + ret = ikev2_pld_auth(env, &pld, msg, offset); break; case IKEV2_PAYLOAD_NONCE: case IKEV2_PAYLOAD_NONCE | IKED_E: - ret = ikev2_pld_nonce(env, &pld, msg, offset, left); + ret = ikev2_pld_nonce(env, &pld, msg, offset); break; case IKEV2_PAYLOAD_NOTIFY: case IKEV2_PAYLOAD_NOTIFY | IKED_E: - ret = ikev2_pld_notify(env, &pld, msg, offset, left); + ret = ikev2_pld_notify(env, &pld, msg, offset); break; case IKEV2_PAYLOAD_DELETE | IKED_E: - ret = ikev2_pld_delete(env, &pld, msg, offset, left); + ret = ikev2_pld_delete(env, &pld, msg, offset); break; case IKEV2_PAYLOAD_TSi | IKED_E: case IKEV2_PAYLOAD_TSr | IKED_E: - ret = ikev2_pld_ts(env, &pld, msg, offset, left, - payload); + ret = ikev2_pld_ts(env, &pld, msg, offset, payload); break; case IKEV2_PAYLOAD_SK: ret = ikev2_pld_e(env, &pld, msg, offset); break; case IKEV2_PAYLOAD_CP | IKED_E: - ret = ikev2_pld_cp(env, &pld, msg, offset, left); + ret = ikev2_pld_cp(env, &pld, msg, offset); break; case IKEV2_PAYLOAD_EAP | IKED_E: - ret = ikev2_pld_eap(env, &pld, msg, offset, left); + ret = ikev2_pld_eap(env, &pld, msg, offset); break; default: print_hex(msgbuf, offset, @@ -271,128 +209,34 @@ ikev2_pld_payloads(struct iked *env, struct iked_message *msg, if (payload == IKEV2_PAYLOAD_SK) return (0); + next: payload = pld.pld_nextpayload; offset += betoh16(pld.pld_length) - sizeof(pld); } - return (0); -} - -int -ikev2_validate_sa(struct iked_message *msg, size_t offset, size_t left, - struct ikev2_payload *pld, struct ikev2_sa_proposal *sap) -{ - uint8_t *msgbuf = ibuf_data(msg->msg_data); - size_t pld_length, sap_length; - - pld_length = betoh16(pld->pld_length); - if (pld_length < sizeof(*pld) + sizeof(*sap)) { - log_debug("%s: malformed payload: specified length smaller " - "than minimum size (%zu < %zu)", __func__, pld_length, - sizeof(*pld) + sizeof(*sap)); - return (-1); - } + if (quick) + print_debug("\n"); - /* This will actually be caught by earlier checks. */ - if (left < sizeof(*sap)) { - log_debug("%s: malformed payload: too short for header " - "(%zu < %zu)", __func__, left, sizeof(*sap)); - return (-1); - } - memcpy(sap, msgbuf + offset, sizeof(*sap)); - - sap_length = betoh16(sap->sap_length); - if (sap_length < sizeof(*sap)) { - log_debug("%s: malformed payload: shorter than minimum header " - "size (%zu < %zu)", __func__, sap_length, sizeof(*sap)); - return (-1); - } - if (left < sap_length) { - log_debug("%s: malformed payload: too long for actual payload " - "size (%zu < %zu)", __func__, left, sap_length); - return (-1); - } - /* - * NB: There might be more proposals, we parse only the first one. - * This condition must never be true. - */ - if (pld_length - sizeof(*pld) < sap_length) { - log_debug("%s: payload malformed: SA payload length mismatches " - "proposal substructure length (%lu < %zu)", __func__, - pld_length - sizeof(*pld), sap_length); - return (-1); - } - /* - * If there is only one proposal, sap_length must be the - * total payload size. - */ - if (!sap->sap_more && ((pld_length - sizeof(*pld)) != sap_length)) { - log_debug("%s: payload malformed: SA payload length mismatches " - "single proposal substructure length (%lu != %zu)", - __func__, pld_length - sizeof(*pld), sap_length); - return (-1); - } - /* - * If there are more than one proposal, there must be bytes - * left in the payload. - */ - if (sap->sap_more && ((pld_length - sizeof(*pld)) <= sap_length)) { - log_debug("%s: payload malformed: SA payload too small for " - "further proposals (%zu <= %zu)", __func__, - pld_length - sizeof(*pld), sap_length); - return (-1); - } return (0); } -/* - * NB: This function parses both the SA header and the first proposal. - * Additional proposals are ignored. - */ int ikev2_pld_sa(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, size_t offset, size_t left) + struct iked_message *msg, off_t offset) { struct ikev2_sa_proposal sap; struct iked_proposal *prop = NULL; - uint32_t spi32; - uint64_t spi = 0, spi64; - uint8_t *msgbuf = ibuf_data(msg->msg_data); + u_int32_t spi32; + u_int64_t spi = 0, spi64; + u_int8_t *msgbuf = ibuf_data(msg->msg_data); struct iked_proposals *props; - size_t total; - - if (ikev2_validate_sa(msg, offset, left, pld, &sap)) - return (-1); - - if (sap.sap_more) - log_debug("%s: more than one proposal specified", __func__); - - /* Assumed size of the first proposals, including SPI if present. */ - total = (betoh16(sap.sap_length) - sizeof(sap)); props = &msg->msg_parent->msg_proposals; + memcpy(&sap, msgbuf + offset, sizeof(sap)); offset += sizeof(sap); - left -= sizeof(sap); if (sap.sap_spisize) { - if (left < sap.sap_spisize) { - log_debug("%s: malformed payload: SPI larger than " - "actual payload (%zu < %d)", __func__, left, - sap.sap_spisize); - return (-1); - } - if (total < sap.sap_spisize) { - log_debug("%s: malformed payload: SPI larger than " - "proposal (%zu < %d)", __func__, total, - sap.sap_spisize); - return (-1); - } - if (total < sap.sap_spisize) { - log_debug("%s: malformed payload: SPI too large " - "(%zu < %d)", __func__, total, sap.sap_spisize); - return (-1); - } switch (sap.sap_spisize) { case 4: memcpy(&spi32, msgbuf + offset, 4); @@ -409,20 +253,6 @@ ikev2_pld_sa(struct iked *env, struct ikev2_payload *pld, } offset += sap.sap_spisize; - left -= sap.sap_spisize; - - /* Assumed size of the proposal, now without SPI. */ - total -= sap.sap_spisize; - } - - /* - * As we verified sanity of packet headers, this check will - * be always false, but just to be sure we keep it. - */ - if (left < total) { - log_debug("%s: payload malformed: too long for payload " - "(%zu < %zu)", __func__, left, total); - return (-1); } log_debug("%s: more %d reserved %d length %d" @@ -451,7 +281,7 @@ ikev2_pld_sa(struct iked *env, struct ikev2_payload *pld, * Parse the attached transforms */ if (sap.sap_transforms && - ikev2_pld_xform(env, &sap, msg, offset, total) != 0) { + ikev2_pld_xform(env, &sap, msg, offset) != 0) { log_debug("%s: invalid proposal transforms", __func__); return (-1); } @@ -459,48 +289,15 @@ ikev2_pld_sa(struct iked *env, struct ikev2_payload *pld, return (0); } -int -ikev2_validate_xform(struct iked_message *msg, size_t offset, size_t total, - struct ikev2_transform *xfrm) -{ - uint8_t *msgbuf = ibuf_data(msg->msg_data); - size_t xfrm_length; - - if (total < sizeof(*xfrm)) { - log_debug("%s: payload malformed: too short for header " - "(%zu < %zu)", __func__, total, sizeof(*xfrm)); - return (-1); - } - memcpy(xfrm, msgbuf + offset, sizeof(*xfrm)); - - xfrm_length = betoh16(xfrm->xfrm_length); - if (xfrm_length < sizeof(*xfrm)) { - log_debug("%s: payload malformed: shorter than minimal header " - "(%zu < %zu)", __func__, xfrm_length, sizeof(*xfrm)); - return (-1); - } - if (total < xfrm_length) { - log_debug("%s: malformed payload: too long for payload size " - "(%zu < %zu)", __func__, total, xfrm_length); - return (-1); - } - - return (0); -} - int ikev2_pld_xform(struct iked *env, struct ikev2_sa_proposal *sap, - struct iked_message *msg, size_t offset, size_t total) + struct iked_message *msg, off_t offset) { struct ikev2_transform xfrm; char id[BUFSIZ]; - int ret = 0; - size_t xfrm_length; + u_int8_t *msgbuf = ibuf_data(msg->msg_data); - if (ikev2_validate_xform(msg, offset, total, &xfrm)) - return (-1); - - xfrm_length = betoh16(xfrm.xfrm_length); + memcpy(&xfrm, msgbuf + offset, sizeof(xfrm)); switch (xfrm.xfrm_type) { case IKEV2_XFORMTYPE_ENCR: @@ -528,21 +325,19 @@ ikev2_pld_xform(struct iked *env, struct ikev2_sa_proposal *sap, break; } - log_debug("%s: more %d reserved %d length %zu" + log_debug("%s: more %d reserved %d length %d" " type %s id %s", - __func__, xfrm.xfrm_more, xfrm.xfrm_reserved, xfrm_length, + __func__, xfrm.xfrm_more, xfrm.xfrm_reserved, + betoh16(xfrm.xfrm_length), print_map(xfrm.xfrm_type, ikev2_xformtype_map), id); /* * Parse transform attributes, if available */ msg->msg_attrlength = 0; - if (xfrm_length > sizeof(xfrm)) { - if (ikev2_pld_attr(env, &xfrm, msg, offset + sizeof(xfrm), - xfrm_length - sizeof(xfrm)) != 0) { - return (-1); - } - } + if ((u_int)betoh16(xfrm.xfrm_length) > sizeof(xfrm)) + ikev2_pld_attr(env, &xfrm, msg, offset + sizeof(xfrm), + betoh16(xfrm.xfrm_length) - sizeof(xfrm)); if (ikev2_msg_frompeer(msg)) { if (config_add_transform(msg->msg_parent->msg_prop, @@ -554,52 +349,26 @@ ikev2_pld_xform(struct iked *env, struct ikev2_sa_proposal *sap, } /* Next transform */ - offset += xfrm_length; - total -= xfrm_length; + offset += betoh16(xfrm.xfrm_length); if (xfrm.xfrm_more == IKEV2_XFORM_MORE) - ret = ikev2_pld_xform(env, sap, msg, offset, total); - else if (total != 0) { - /* No more transforms but still some data left. */ - log_debug("%s: less data than specified, %zu bytes left", - __func__, total); - ret = -1; - } - - return (ret); -} - -int -ikev2_validate_attr(struct iked_message *msg, size_t offset, size_t total, - struct ikev2_attribute *attr) -{ - uint8_t *msgbuf = ibuf_data(msg->msg_data); - - if (total < sizeof(*attr)) { - log_debug("%s: payload malformed: too short for header " - "(%zu < %zu)", __func__, total, sizeof(*attr)); - return (-1); - } - memcpy(attr, msgbuf + offset, sizeof(*attr)); + ikev2_pld_xform(env, sap, msg, offset); return (0); } int ikev2_pld_attr(struct iked *env, struct ikev2_transform *xfrm, - struct iked_message *msg, size_t offset, size_t total) + struct iked_message *msg, off_t offset, int total) { struct ikev2_attribute attr; - unsigned int type; - uint8_t *msgbuf = ibuf_data(msg->msg_data); - int ret = 0; - size_t attr_length; + u_int type; + u_int8_t *msgbuf = ibuf_data(msg->msg_data); - if (ikev2_validate_attr(msg, offset, total, &attr)) - return (-1); + memcpy(&attr, msgbuf + offset, sizeof(attr)); type = betoh16(attr.attr_type) & ~IKEV2_ATTRAF_TV; - log_debug("%s: attribute type %s length %d total %zu", + log_debug("%s: attribute type %s length %d total %d", __func__, print_map(type, ikev2_attrtype_map), betoh16(attr.attr_length), total); @@ -612,70 +381,30 @@ ikev2_pld_attr(struct iked *env, struct ikev2_transform *xfrm, msg->msg_attrlength = betoh16(attr.attr_length); } else { /* Type-Length-Value attribute */ - attr_length = betoh16(attr.attr_length); - if (attr_length < sizeof(attr)) { - log_debug("%s: payload malformed: shorter than " - "minimal header (%zu < %zu)", __func__, - attr_length, sizeof(attr)); - return (-1); - } - if (total < attr_length) { - log_debug("%s: payload malformed: attribute larger " - "than actual payload (%zu < %zu)", __func__, - total, attr_length); - return (-1); - } print_hex(msgbuf, offset + sizeof(attr), - attr_length - sizeof(attr)); - offset += attr_length; - total -= attr_length; + betoh16(attr.attr_length) - sizeof(attr)); + offset += betoh16(attr.attr_length); + total -= betoh16(attr.attr_length); } if (total > 0) { /* Next attribute */ - ret = ikev2_pld_attr(env, xfrm, msg, offset, total); - } - - return (ret); -} - -int -ikev2_validate_ke(struct iked_message *msg, size_t offset, size_t left, - struct ikev2_payload *pld, struct ikev2_keyexchange *kex) -{ - uint8_t *msgbuf = ibuf_data(msg->msg_data); - size_t pld_length; - - pld_length = betoh16(pld->pld_length); - if (pld_length < sizeof(*pld) + sizeof(*kex)) { - log_debug("%s: malformed payload: specified length smaller " - "than minimum size (%zu < %zu)", __func__, pld_length, - sizeof(*pld) + sizeof(*kex)); - return (-1); - } - - /* This will actually be caught by earlier checks. */ - if (left < sizeof(*kex)) { - log_debug("%s: malformed payload: too short for header " - "(%zu < %zu)", __func__, left, sizeof(*kex)); - return (-1); + ikev2_pld_attr(env, xfrm, msg, offset, total); } - memcpy(kex, msgbuf + offset, sizeof(*kex)); return (0); } int ikev2_pld_ke(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, size_t offset, size_t left) + struct iked_message *msg, off_t offset) { struct ikev2_keyexchange kex; - uint8_t *buf; + u_int8_t *buf; size_t len; - uint8_t *msgbuf = ibuf_data(msg->msg_data); + u_int8_t *msgbuf = ibuf_data(msg->msg_data); - if (ikev2_validate_ke(msg, offset, left, pld, &kex)) - return (-1); + memcpy(&kex, msgbuf + offset, sizeof(kex)); log_debug("%s: dh group %s reserved %d", __func__, print_map(betoh16(kex.kex_dhgroup), ikev2_xformdh_map), @@ -684,17 +413,6 @@ ikev2_pld_ke(struct iked *env, struct ikev2_payload *pld, buf = msgbuf + offset + sizeof(kex); len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(kex); - if (len == 0) { - log_debug("%s: malformed payload: no KE data given", __func__); - return (-1); - } - /* This will actually be caught by earlier checks. */ - if (left < len) { - log_debug("%s: malformed payload: smaller than specified " - "(%zu < %zu)", __func__, left, len); - return (-1); - } - print_hex(buf, 0, len); if (ikev2_msg_frompeer(msg)) { @@ -708,47 +426,19 @@ ikev2_pld_ke(struct iked *env, struct ikev2_payload *pld, return (0); } -int -ikev2_validate_id(struct iked_message *msg, size_t offset, size_t left, - struct ikev2_payload *pld, struct ikev2_id *id) -{ - uint8_t *msgbuf = ibuf_data(msg->msg_data); - size_t pld_length; - - pld_length = betoh16(pld->pld_length); - if (pld_length < sizeof(*pld) + sizeof(*id)) { - log_debug("%s: malformed payload: specified length smaller " - "than minimum size (%zu < %zu)", __func__, pld_length, - sizeof(*pld) + sizeof(*id)); - return (-1); - } - - /* This will actually be caught by earlier checks. */ - if (left < sizeof(*id)) { - log_debug("%s: malformed payload: too short for header " - "(%zu < %zu)", __func__, left, sizeof(*id)); - return (-1); - } - memcpy(id, msgbuf + offset, sizeof(*id)); - - return (0); -} - int ikev2_pld_id(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, size_t offset, size_t left, unsigned int payload) + struct iked_message *msg, off_t offset, u_int payload) { - uint8_t *ptr; + u_int8_t *ptr; struct ikev2_id id; size_t len; struct iked_id *idp, idb; struct iked_sa *sa = msg->msg_sa; - uint8_t *msgbuf = ibuf_data(msg->msg_data); + u_int8_t *msgbuf = ibuf_data(msg->msg_data); char idstr[IKED_ID_SIZE]; - if (ikev2_validate_id(msg, offset, left, pld, &id)) - return (-1); - + memcpy(&id, msgbuf + offset, sizeof(id)); bzero(&idb, sizeof(idb)); /* Don't strip the Id payload header */ @@ -765,7 +455,7 @@ ikev2_pld_id(struct iked *env, struct ikev2_payload *pld, return (-1); } - log_debug("%s: id %s length %zu", __func__, idstr, len); + log_debug("%s: id %s length %d", __func__, idstr, len); if (!ikev2_msg_frompeer(msg)) { ibuf_release(idb.id_buf); @@ -791,50 +481,23 @@ ikev2_pld_id(struct iked *env, struct ikev2_payload *pld, return (0); } -int -ikev2_validate_cert(struct iked_message *msg, size_t offset, size_t left, - struct ikev2_payload *pld, struct ikev2_cert *cert) -{ - uint8_t *msgbuf = ibuf_data(msg->msg_data); - size_t pld_length; - - pld_length = betoh16(pld->pld_length); - if (pld_length < sizeof(*pld) + sizeof(*cert)) { - log_debug("%s: malformed payload: specified length smaller " - "than minimum size (%zu < %zu)", __func__, pld_length, - sizeof(*pld) + sizeof(*cert)); - return (-1); - } - - /* This will actually be caught by earlier checks. */ - if (left < sizeof(*cert)) { - log_debug("%s: malformed payload: too short for header " - "(%zu < %zu)", __func__, left, sizeof(*cert)); - return (-1); - } - memcpy(cert, msgbuf + offset, sizeof(*cert)); - - return (0); -} - int ikev2_pld_cert(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, size_t offset, size_t left) + struct iked_message *msg, off_t offset) { struct ikev2_cert cert; - uint8_t *buf; + u_int8_t *buf; size_t len; struct iked_id *certid; - uint8_t *msgbuf = ibuf_data(msg->msg_data); + u_int8_t *msgbuf = ibuf_data(msg->msg_data); - if (ikev2_validate_cert(msg, offset, left, pld, &cert)) - return (-1); + memcpy(&cert, msgbuf + offset, sizeof(cert)); offset += sizeof(cert); buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(cert); - log_debug("%s: type %s length %zu", + log_debug("%s: type %s length %d", __func__, print_map(cert.cert_type, ikev2_cert_map), len); print_hex(buf, 0, len); @@ -858,70 +521,32 @@ ikev2_pld_cert(struct iked *env, struct ikev2_payload *pld, return (0); } -int -ikev2_validate_certreq(struct iked_message *msg, size_t offset, size_t left, - struct ikev2_payload *pld, struct ikev2_cert *cert) -{ - uint8_t *msgbuf = ibuf_data(msg->msg_data); - size_t pld_length; - - pld_length = betoh16(pld->pld_length); - if (pld_length < sizeof(*pld) + sizeof(*cert)) { - log_debug("%s: malformed payload: specified length smaller " - "than minimum size (%zu < %zu)", __func__, pld_length, - sizeof(*pld) + sizeof(*cert)); - return (-1); - } - - /* This will actually be caught by earlier checks. */ - if (left < sizeof(*cert)) { - log_debug("%s: malformed payload: too short for header " - "(%zu < %zu)", __func__, left, sizeof(*cert)); - return (-1); - } - memcpy(cert, msgbuf + offset, sizeof(*cert)); - - return (0); -} - int ikev2_pld_certreq(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, size_t offset, size_t left) + struct iked_message *msg, off_t offset) { struct iked_sa *sa = msg->msg_sa; struct ikev2_cert cert; - uint8_t *buf; - ssize_t len; - uint8_t *msgbuf = ibuf_data(msg->msg_data); + u_int8_t *buf; + size_t len; + u_int8_t *msgbuf = ibuf_data(msg->msg_data); - if (ikev2_validate_certreq(msg, offset, left, pld, &cert)) - return (-1); + memcpy(&cert, msgbuf + offset, sizeof(cert)); offset += sizeof(cert); buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(cert); - log_debug("%s: type %s length %zd", + log_debug("%s: type %s signatures length %d", __func__, print_map(cert.cert_type, ikev2_cert_map), len); - - /* This will actually be caught by earlier checks. */ - if (len < 0) { - log_debug("%s: invalid certificate request length", __func__); - return (-1); - } - print_hex(buf, 0, len); if (!ikev2_msg_frompeer(msg)) return (0); - if (cert.cert_type == IKEV2_CERT_X509_CERT) { - if (!len) - return (0); - if ((len % SHA_DIGEST_LENGTH) != 0) { - log_debug("%s: invalid certificate request", __func__); - return (-1); - } + if (!len || (len % SHA_DIGEST_LENGTH) != 0) { + log_debug("%s: invalid certificate request", __func__); + return (-1); } if (msg->msg_sa == NULL) @@ -933,57 +558,30 @@ ikev2_pld_certreq(struct iked *env, struct ikev2_payload *pld, else sa->sa_statevalid |= IKED_REQ_CERT; - ca_setreq(env, sa, &sa->sa_policy->pol_localid, + ca_setreq(env, &sa->sa_hdr, &sa->sa_policy->pol_localid, cert.cert_type, buf, len, PROC_CERT); return (0); } -int -ikev2_validate_auth(struct iked_message *msg, size_t offset, size_t left, - struct ikev2_payload *pld, struct ikev2_auth *auth) -{ - uint8_t *msgbuf = ibuf_data(msg->msg_data); - size_t pld_length; - - pld_length = betoh16(pld->pld_length); - if (pld_length < sizeof(*pld) + sizeof(*auth)) { - log_debug("%s: malformed payload: specified length smaller " - "than minimum size (%zu < %zu)", __func__, pld_length, - sizeof(*pld) + sizeof(*auth)); - return (-1); - } - - /* This will actually be caught by earlier checks. */ - if (left < sizeof(*auth)) { - log_debug("%s: malformed payload: too short for header " - "(%zu < %zu)", __func__, left, sizeof(*auth)); - return (-1); - } - memcpy(auth, msgbuf + offset, sizeof(*auth)); - - return (0); -} - int ikev2_pld_auth(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, size_t offset, size_t left) + struct iked_message *msg, off_t offset) { struct ikev2_auth auth; struct iked_id *idp; - uint8_t *buf; + u_int8_t *buf; size_t len; struct iked_sa *sa = msg->msg_sa; - uint8_t *msgbuf = ibuf_data(msg->msg_data); + u_int8_t *msgbuf = ibuf_data(msg->msg_data); - if (ikev2_validate_auth(msg, offset, left, pld, &auth)) - return (-1); + memcpy(&auth, msgbuf + offset, sizeof(auth)); offset += sizeof(auth); buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(auth); - log_debug("%s: method %s length %zu", + log_debug("%s: method %s length %d", __func__, print_map(auth.auth_method, ikev2_auth_map), len); print_hex(buf, 0, len); @@ -1010,49 +608,16 @@ ikev2_pld_auth(struct iked *env, struct ikev2_payload *pld, return (0); } -int -ikev2_validate_nonce(struct iked_message *msg, size_t offset, size_t left, - struct ikev2_payload *pld) -{ - size_t pld_length; - - /* This will actually be caught by earlier checks. */ - pld_length = betoh16(pld->pld_length); - if (pld_length < sizeof(*pld)) { - log_debug("%s: malformed payload: specified length smaller " - "than minimum size (%zu < %zu)", __func__, pld_length, - sizeof(*pld)); - return (-1); - } - - return (0); -} - int ikev2_pld_nonce(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, size_t offset, size_t left) + struct iked_message *msg, off_t offset) { size_t len; - uint8_t *buf; - uint8_t *msgbuf = ibuf_data(msg->msg_data); - - if (ikev2_validate_nonce(msg, offset, left, pld)) - return (-1); + u_int8_t *buf; + u_int8_t *msgbuf = ibuf_data(msg->msg_data); buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld); - - if (len == 0) { - log_debug("%s: malformed payload: no NONCE given", __func__); - return (-1); - } - /* This will actually be caught by earlier checks. */ - if (left < len) { - log_debug("%s: malformed payload: smaller than specified " - "(%zu < %zu)", __func__, left, len); - return (-1); - } - print_hex(buf, 0, len); if (ikev2_msg_frompeer(msg)) { @@ -1067,59 +632,30 @@ ikev2_pld_nonce(struct iked *env, struct ikev2_payload *pld, return (0); } -int -ikev2_validate_notify(struct iked_message *msg, size_t offset, size_t left, - struct ikev2_payload *pld, struct ikev2_notify *n) -{ - uint8_t *msgbuf = ibuf_data(msg->msg_data); - size_t pld_length; - - pld_length = betoh16(pld->pld_length); - if (pld_length < sizeof(*pld) + sizeof(*n)) { - log_debug("%s: malformed payload: specified length smaller " - "than minimum size (%zu < %zu)", __func__, pld_length, - sizeof(*pld) + sizeof(*n)); - return (-1); - } - - /* This will actually be caught by earlier checks. */ - if (left < sizeof(*n)) { - log_debug("%s: malformed payload: too short for header " - "(%zu < %zu)", __func__, left, sizeof(*n)); - return (-1); - } - memcpy(n, msgbuf + offset, sizeof(*n)); - - return (0); -} - int ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, size_t offset, size_t left) + struct iked_message *msg, off_t offset) { - struct ikev2_notify n; - uint8_t *buf, md[SHA_DIGEST_LENGTH]; + struct ikev2_notify *n; + u_int8_t *buf, md[SHA_DIGEST_LENGTH]; size_t len; - uint32_t spi32; - uint64_t spi64; + u_int32_t spi32; + u_int64_t spi64; struct iked_spi *rekey; - uint16_t type; - uint16_t group; - uint16_t cpi; - uint16_t signature_hash; - uint8_t transform; + u_int16_t type; + u_int16_t group; - if (ikev2_validate_notify(msg, offset, left, pld, &n)) + if ((n = ibuf_seek(msg->msg_data, offset, sizeof(*n))) == NULL) return (-1); - type = betoh16(n.n_type); + type = betoh16(n->n_type); log_debug("%s: protoid %s spisize %d type %s", __func__, - print_map(n.n_protoid, ikev2_saproto_map), n.n_spisize, + print_map(n->n_protoid, ikev2_saproto_map), n->n_spisize, print_map(type, ikev2_n_map)); - len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(n); - if ((buf = ibuf_seek(msg->msg_data, offset + sizeof(n), len)) == NULL) + len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(*n); + if ((buf = ibuf_seek(msg->msg_data, offset + sizeof(*n), len)) == NULL) return (-1); print_hex(buf, 0, len); @@ -1130,14 +666,9 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, switch (type) { case IKEV2_N_NAT_DETECTION_SOURCE_IP: case IKEV2_N_NAT_DETECTION_DESTINATION_IP: - if (len != sizeof(md)) { - log_debug("%s: malformed payload: hash size mismatch" - " (%zu != %zu)", __func__, len, sizeof(md)); - return (-1); - } if (ikev2_nat_detection(env, msg, md, sizeof(md), type) == -1) return (-1); - if (memcmp(buf, md, len) != 0) { + if (len != sizeof(md) || memcmp(buf, md, len) != 0) { log_debug("%s: %s detected NAT, enabling " "UDP encapsulation", __func__, print_map(type, ikev2_n_map)); @@ -1152,21 +683,13 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, print_hex(md, 0, sizeof(md)); break; case IKEV2_N_INVALID_KE_PAYLOAD: - if (sa_stateok(msg->msg_sa, IKEV2_STATE_VALID) && - !msg->msg_e) { - log_debug("%s: INVALID_KE_PAYLOAD not encrypted", - __func__); - return (-1); - } if (len != sizeof(group)) { - log_debug("%s: malformed payload: group size mismatch" - " (%zu != %zu)", __func__, len, sizeof(group)); + log_debug("%s: malformed notification", __func__); return (-1); } - /* XXX chould also happen for PFS */ if (!msg->msg_sa->sa_hdr.sh_initiator) { log_debug("%s: not an initiator", __func__); - sa_state(env, msg->msg_sa, IKEV2_STATE_CLOSED); + sa_free(env, msg->msg_sa); msg->msg_sa = NULL; return (-1); } @@ -1180,21 +703,13 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, } log_debug("%s: responder selected DH group %d", __func__, group); - sa_state(env, msg->msg_sa, IKEV2_STATE_CLOSED); + sa_free(env, msg->msg_sa); msg->msg_sa = NULL; - - /* - * XXX should also happen for PFS so we have to check state. - */ - timer_set(env, &env->sc_inittmr, ikev2_init_ike_sa, NULL); - timer_add(env, &env->sc_inittmr, IKED_INITIATOR_INITIAL); + timer_initialize(env, &env->sc_inittmr, ikev2_init_ike_sa, + NULL); + timer_register(env, &env->sc_inittmr, IKED_INITIATOR_INITIAL); break; case IKEV2_N_NO_ADDITIONAL_SAS: - if (!msg->msg_e) { - log_debug("%s: NO_ADDITIONAL_SAS not encrypted", - __func__); - return (-1); - } /* This makes sense for Child SAs only atm */ if (msg->msg_sa->sa_stateflags & IKED_REQ_CHILDSA) { ikev2_disable_rekeying(env, msg->msg_sa); @@ -1202,11 +717,7 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, } break; case IKEV2_N_REKEY_SA: - if (!msg->msg_e) { - log_debug("%s: N_REKEY_SA not encrypted", __func__); - return (-1); - } - if (len != n.n_spisize) { + if (len != n->n_spisize) { log_debug("%s: malformed notification", __func__); return (-1); } @@ -1216,7 +727,7 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, __func__); return (-1); } - switch (n.n_spisize) { + switch (n->n_spisize) { case 4: memcpy(&spi32, buf, len); rekey->spi = betoh32(spi32); @@ -1227,130 +738,55 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, break; default: log_debug("%s: invalid spi size %d", __func__, - n.n_spisize); + n->n_spisize); return (-1); } - rekey->spi_size = n.n_spisize; - rekey->spi_protoid = n.n_protoid; + rekey->spi_size = n->n_spisize; + rekey->spi_protoid = n->n_protoid; log_debug("%s: rekey %s spi %s", __func__, - print_map(n.n_protoid, ikev2_saproto_map), - print_spi(rekey->spi, n.n_spisize)); - break; - case IKEV2_N_IPCOMP_SUPPORTED: - if (!msg->msg_e) { - log_debug("%s: N_IPCOMP_SUPPORTED not encrypted", - __func__); - return (-1); - } - if (len < sizeof(cpi) + sizeof(transform)) { - log_debug("%s: ignoring malformed ipcomp notification", - __func__); - return (0); - } - memcpy(&cpi, buf, sizeof(cpi)); - memcpy(&transform, buf + sizeof(cpi), sizeof(transform)); - log_debug("%s: cpi 0x%x, transform %s, len %zu", __func__, - betoh16(cpi), print_map(transform, ikev2_ipcomp_map), len); - /* we only support deflate */ - if ((msg->msg_policy->pol_flags & IKED_POLICY_IPCOMP) && - (transform == IKEV2_IPCOMP_DEFLATE)) { - msg->msg_sa->sa_ipcomp = transform; - msg->msg_sa->sa_cpi_out = betoh16(cpi); - } - break; - case IKEV2_N_SIGNATURE_HASH_ALGORITHMS: - if (msg->msg_e) { - log_debug("%s: SIGNATURE_HASH_ALGORITHMS: encrypted", - __func__); - return (-1); - } - if (msg->msg_sa == NULL || - msg->msg_sa->sa_sigsha2) { - log_debug("%s: SIGNATURE_HASH_ALGORITHMS: no SA or " - "duplicate notify", __func__); - return (-1); - } - if (len < sizeof(signature_hash) || - len % sizeof(signature_hash)) { - log_debug("%s: malformed signature hash notification" - "(%zu bytes)", __func__, len); - return (0); - } - while (len >= sizeof(signature_hash)) { - memcpy(&signature_hash, buf, sizeof(signature_hash)); - signature_hash = betoh16(signature_hash); - log_debug("%s: signature hash %s (%x)", __func__, - print_map(signature_hash, ikev2_sighash_map), - signature_hash); - len -= sizeof(signature_hash); - buf += sizeof(signature_hash); - if (signature_hash == IKEV2_SIGHASH_SHA2_256) - msg->msg_sa->sa_sigsha2 = 1; - } + print_map(n->n_protoid, ikev2_saproto_map), + print_spi(rekey->spi, n->n_spisize)); break; } return (0); } -int -ikev2_validate_delete(struct iked_message *msg, size_t offset, size_t left, - struct ikev2_payload *pld, struct ikev2_delete *del) -{ - uint8_t *msgbuf = ibuf_data(msg->msg_data); - size_t pld_length; - - pld_length = betoh16(pld->pld_length); - if (pld_length < sizeof(*pld) + sizeof(*del)) { - log_debug("%s: malformed payload: specified length smaller " - "than minimum size (%zu < %zu)", __func__, pld_length, - sizeof(*pld) + sizeof(*del)); - return (-1); - } - - /* This will actually be caught by earlier checks. */ - if (left < sizeof(*del)) { - log_debug("%s: malformed payload: too short for header " - "(%zu < %zu)", __func__, left, sizeof(*del)); - return (-1); - } - memcpy(del, msgbuf + offset, sizeof(*del)); - - return (0); -} - int ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, size_t offset, size_t left) + struct iked_message *msg, off_t offset) { struct iked_childsa **peersas = NULL; struct iked_sa *sa = msg->msg_sa; - struct ikev2_delete del, *localdel; + struct ikev2_delete *del, *localdel; struct ibuf *resp = NULL; - uint64_t *localspi = NULL; - uint64_t spi64, spi = 0; - uint32_t spi32; - uint8_t *buf, *msgbuf = ibuf_data(msg->msg_data); + u_int64_t *localspi = NULL; + u_int64_t spi64, spi = 0; + u_int32_t spi32; + u_int8_t *buf, *msgbuf = ibuf_data(msg->msg_data); size_t found = 0, failed = 0; int cnt, i, len, sz, ret = -1; - /* Skip if it's a response, then we don't have to deal with it */ - if (ikev2_msg_frompeer(msg) && - msg->msg_parent->msg_response) - return (0); + /* Skip if it's a reply and we don't have to deal with it */ + if (ikev2_msg_frompeer(msg) && sa && + (sa->sa_stateflags & IKED_REQ_INF)) { + sa->sa_stateflags &= ~IKED_REQ_INF; + if ((sa->sa_stateflags & IKED_REQ_DELETE) == 0) + return (0); + } - if (ikev2_validate_delete(msg, offset, left, pld, &del)) + if ((del = ibuf_seek(msg->msg_data, offset, sizeof(*del))) == NULL) return (-1); - cnt = betoh16(del.del_nspi); - sz = del.del_spisize; + cnt = betoh16(del->del_nspi); + sz = del->del_spisize; log_debug("%s: proto %s spisize %d nspi %d", - __func__, print_map(del.del_protoid, ikev2_saproto_map), + __func__, print_map(del->del_protoid, ikev2_saproto_map), sz, cnt); - buf = msgbuf + offset + sizeof(del); - len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(del); + buf = msgbuf + offset + sizeof(*del); + len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(*del); print_hex(buf, 0, len); @@ -1359,28 +795,20 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, case 8: break; default: - if (del.del_protoid != IKEV2_SAPROTO_IKE) { - log_debug("%s: invalid SPI size", __func__); - return (-1); - } - if (ikev2_msg_frompeer(msg)) { + if (ikev2_msg_frompeer(msg) && + del->del_protoid == IKEV2_SAPROTO_IKE) { /* Send an empty informational response */ if ((resp = ibuf_static()) == NULL) goto done; ret = ikev2_send_ike_e(env, sa, resp, IKEV2_PAYLOAD_NONE, IKEV2_EXCHANGE_INFORMATIONAL, 1); - msg->msg_parent->msg_responded = 1; ibuf_release(resp); sa_state(env, sa, IKEV2_STATE_CLOSED); - } else { - /* - * We're sending a delete message. Upper layer - * must deal with deletion of the IKE SA. - */ - ret = 0; + return (ret); } - return (ret); + log_debug("%s: invalid SPI size", __func__); + return (-1); } if ((len / sz) != cnt) { @@ -1391,7 +819,7 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, if (ikev2_msg_frompeer(msg) && ((peersas = calloc(cnt, sizeof(struct iked_childsa *))) == NULL || - (localspi = calloc(cnt, sizeof(uint64_t))) == NULL)) { + (localspi = calloc(cnt, sizeof(u_int64_t))) == NULL)) { log_warn("%s", __func__); goto done; } @@ -1414,13 +842,13 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, continue; if ((peersas[i] = childsa_lookup(sa, spi, - del.del_protoid)) == NULL) { + del->del_protoid)) == NULL) { log_warnx("%s: CHILD SA doesn't exist for spi %s", - __func__, print_spi(spi, del.del_spisize)); - continue; + __func__, print_spi(spi, del->del_spisize)); + goto done; } - if (ikev2_childsa_delete(env, sa, del.del_protoid, spi, + if (ikev2_childsa_delete(env, sa, del->del_protoid, spi, &localspi[i], 0) == -1) failed++; else @@ -1436,7 +864,9 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, if (!ikev2_msg_frompeer(msg)) goto done; - if (msg->msg_parent->msg_response) { + if (sa && (sa->sa_stateflags & IKED_REQ_DELETE)) { + /* Finish rekeying */ + sa->sa_stateflags &= ~IKED_REQ_DELETE; ret = 0; goto done; } @@ -1450,8 +880,8 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, if ((localdel = ibuf_advance(resp, sizeof(*localdel))) == NULL) goto done; - localdel->del_protoid = del.del_protoid; - localdel->del_spisize = del.del_spisize; + localdel->del_protoid = del->del_protoid; + localdel->del_spisize = del->del_spisize; localdel->del_nspi = htobe16(found); for (i = 0; i < cnt; i++) { @@ -1469,13 +899,12 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, } } - log_warnx("%s: deleted %zu spis", __func__, found); + log_warnx("%s: deleted %d spis", __func__, found); } if (found) { ret = ikev2_send_ike_e(env, sa, resp, IKEV2_PAYLOAD_DELETE, IKEV2_EXCHANGE_INFORMATIONAL, 1); - msg->msg_parent->msg_responded = 1; } else { /* XXX should we send an INVALID_SPI notification? */ ret = 0; @@ -1490,51 +919,24 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, return (ret); } -int -ikev2_validate_ts(struct iked_message *msg, size_t offset, size_t left, - struct ikev2_payload *pld, struct ikev2_tsp *tsp) -{ - uint8_t *msgbuf = ibuf_data(msg->msg_data); - size_t pld_length; - - pld_length = betoh16(pld->pld_length); - if (pld_length < sizeof(*pld) + sizeof(*tsp)) { - log_debug("%s: malformed payload: specified length smaller " - "than minimum size (%zu < %zu)", __func__, pld_length, - sizeof(*pld) + sizeof(*tsp)); - return (-1); - } - - /* This will actually be caught by earlier checks. */ - if (left < sizeof(*tsp)) { - log_debug("%s: malformed payload: too short for header " - "(%zu < %zu)", __func__, left, sizeof(*tsp)); - return (-1); - } - memcpy(tsp, msgbuf + offset, sizeof(*tsp)); - - return (0); -} - int ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, size_t offset, size_t left, unsigned int payload) + struct iked_message *msg, off_t offset, u_int payload) { struct ikev2_tsp tsp; struct ikev2_ts ts; size_t len, i; struct sockaddr_in s4; struct sockaddr_in6 s6; - uint8_t buf[2][128]; - uint8_t *msgbuf = ibuf_data(msg->msg_data); + u_int8_t buf[2][128]; + u_int8_t *msgbuf = ibuf_data(msg->msg_data); - if (ikev2_validate_ts(msg, offset, left, pld, &tsp)) - return (-1); + memcpy(&tsp, msgbuf + offset, sizeof(tsp)); offset += sizeof(tsp); len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(tsp); - log_debug("%s: count %d length %zu", __func__, + log_debug("%s: count %d length %d", __func__, tsp.tsp_count, len); for (i = 0; i < tsp.tsp_count; i++) { @@ -1551,14 +953,16 @@ ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld, case IKEV2_TS_IPV4_ADDR_RANGE: bzero(&s4, sizeof(s4)); s4.sin_family = AF_INET; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN s4.sin_len = sizeof(s4); +#endif memcpy(&s4.sin_addr.s_addr, msgbuf + offset + sizeof(ts), 4); - print_host((struct sockaddr *)&s4, + print_host((struct sockaddr_storage *)&s4, (char *)buf[0], sizeof(buf[0])); memcpy(&s4.sin_addr.s_addr, msgbuf + offset + sizeof(ts) + 4, 4); - print_host((struct sockaddr *)&s4, + print_host((struct sockaddr_storage *)&s4, (char *)buf[1], sizeof(buf[1])); log_debug("%s: start %s end %s", __func__, buf[0], buf[1]); @@ -1566,14 +970,16 @@ ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld, case IKEV2_TS_IPV6_ADDR_RANGE: bzero(&s6, sizeof(s6)); s6.sin6_family = AF_INET6; +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN s6.sin6_len = sizeof(s6); +#endif memcpy(&s6.sin6_addr, msgbuf + offset + sizeof(ts), 16); - print_host((struct sockaddr *)&s6, + print_host((struct sockaddr_storage *)&s6, (char *)buf[0], sizeof(buf[0])); memcpy(&s6.sin6_addr, msgbuf + offset + sizeof(ts) + 16, 16); - print_host((struct sockaddr *)&s6, + print_host((struct sockaddr_storage *)&s6, (char *)buf[1], sizeof(buf[1])); log_debug("%s: start %s end %s", __func__, buf[0], buf[1]); @@ -1590,13 +996,13 @@ ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld, int ikev2_pld_e(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, size_t offset) + struct iked_message *msg, off_t offset) { struct iked_sa *sa = msg->msg_sa; struct ibuf *e = NULL; - uint8_t *msgbuf = ibuf_data(msg->msg_data); + u_int8_t *msgbuf = ibuf_data(msg->msg_data); struct iked_message emsg; - uint8_t *buf; + u_int8_t *buf; size_t len; int ret = -1; @@ -1628,7 +1034,7 @@ ikev2_pld_e(struct iked *env, struct ikev2_payload *pld, TAILQ_INIT(&emsg.msg_proposals); ret = ikev2_pld_payloads(env, &emsg, 0, ibuf_size(e), - pld->pld_nextpayload); + pld->pld_nextpayload, 0); done: ibuf_release(e); @@ -1636,51 +1042,24 @@ ikev2_pld_e(struct iked *env, struct ikev2_payload *pld, return (ret); } -int -ikev2_validate_cp(struct iked_message *msg, size_t offset, size_t left, - struct ikev2_payload *pld, struct ikev2_cp *cp) -{ - uint8_t *msgbuf = ibuf_data(msg->msg_data); - size_t pld_length; - - pld_length = betoh16(pld->pld_length); - if (pld_length < sizeof(*pld) + sizeof(*cp)) { - log_debug("%s: malformed payload: specified length smaller " - "than minimum size (%zu < %zu)", __func__, pld_length, - sizeof(*pld) + sizeof(*cp)); - return (-1); - } - - /* This will actually be caught by earlier checks. */ - if (left < sizeof(*cp)) { - log_debug("%s: malformed payload: too short for header " - "(%zu < %zu)", __func__, left, sizeof(*cp)); - return (-1); - } - memcpy(cp, msgbuf + offset, sizeof(*cp)); - - return (0); -} - int ikev2_pld_cp(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, size_t offset, size_t left) + struct iked_message *msg, off_t offset) { struct ikev2_cp cp; struct ikev2_cfg *cfg; - uint8_t *buf; + u_int8_t *buf; size_t len, i; - uint8_t *msgbuf = ibuf_data(msg->msg_data); + u_int8_t *msgbuf = ibuf_data(msg->msg_data); struct iked_sa *sa = msg->msg_sa; - if (ikev2_validate_cp(msg, offset, left, pld, &cp)) - return (-1); + memcpy(&cp, msgbuf + offset, sizeof(cp)); offset += sizeof(cp); buf = msgbuf + offset; len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(cp); - log_debug("%s: type %s length %zu", + log_debug("%s: type %s length %d", __func__, print_map(cp.cp_type, ikev2_cp_map), len); print_hex(buf, 0, len); @@ -1704,49 +1083,26 @@ ikev2_pld_cp(struct iked *env, struct ikev2_payload *pld, return (0); } -int -ikev2_validate_eap(struct iked_message *msg, size_t offset, size_t left, - struct ikev2_payload *pld, struct eap_header *hdr) -{ - uint8_t *msgbuf = ibuf_data(msg->msg_data); - size_t pld_length; - - pld_length = betoh16(pld->pld_length); - if (pld_length < sizeof(*pld) + sizeof(*hdr)) { - log_debug("%s: malformed payload: specified length smaller " - "than minimum size (%zu < %zu)", __func__, pld_length, - sizeof(*pld) + sizeof(*hdr)); - return (-1); - } - - /* This will actually be caught by earlier checks. */ - if (left < sizeof(*hdr)) { - log_debug("%s: malformed payload: too short for header " - "(%zu < %zu)", __func__, left, sizeof(*hdr)); - return (-1); - } - memcpy(hdr, msgbuf + offset, sizeof(*hdr)); - - return (0); -} - int ikev2_pld_eap(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, size_t offset, size_t left) + struct iked_message *msg, off_t offset) { - struct eap_header hdr; + struct eap_header *hdr; struct eap_message *eap = NULL; struct iked_sa *sa = msg->msg_sa; size_t len; - if (ikev2_validate_eap(msg, offset, left, pld, &hdr)) + if ((hdr = ibuf_seek(msg->msg_data, offset, sizeof(*hdr))) == NULL) { + log_debug("%s: failed to get EAP header", __func__); return (-1); - len = betoh16(hdr.eap_length); + } + + len = betoh16(hdr->eap_length); if (len < sizeof(*eap)) { log_info("%s: %s id %d length %d", __func__, - print_map(hdr.eap_code, eap_code_map), - hdr.eap_id, betoh16(hdr.eap_length)); + print_map(hdr->eap_code, eap_code_map), + hdr->eap_id, betoh16(hdr->eap_length)); } else { /* Now try to get the indicated length */ if ((eap = ibuf_seek(msg->msg_data, offset, len)) == NULL) { @@ -1758,10 +1114,10 @@ ikev2_pld_eap(struct iked *env, struct ikev2_payload *pld, print_map(eap->eap_code, eap_code_map), eap->eap_id, betoh16(eap->eap_length), print_map(eap->eap_type, eap_type_map)); - - if (eap_parse(env, sa, eap, msg->msg_response) == -1) - return (-1); } + if (eap_parse(env, sa, hdr, msg->msg_response) == -1) + return (-1); + return (0); } diff --git a/iked/imsg_util.c b/iked/imsg_util.c index 9bd2003..8dcfab2 100644 --- a/iked/imsg_util.c +++ b/iked/imsg_util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: imsg_util.c,v 1.10 2015/08/21 11:59:27 reyk Exp $ */ +/* $OpenBSD: imsg_util.c,v 1.7 2013/03/21 04:30:14 deraadt Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,11 +16,18 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +#include "openbsd-compat/sys-queue.h" #include #include +#include +#include +#include +#include +#include +#include #include + #include #include #include @@ -45,7 +52,7 @@ ibuf_cat(struct ibuf *dst, struct ibuf *src) void ibuf_zero(struct ibuf *buf) { - explicit_bzero(buf->buf, buf->wpos); + memset(buf->buf, 0, buf->wpos); } struct ibuf * @@ -103,10 +110,8 @@ ibuf_release(struct ibuf *buf) { if (buf == NULL) return; - if (buf->buf != NULL) { - ibuf_zero(buf); + if (buf->buf != NULL) free(buf->buf); - } free(buf); } @@ -118,7 +123,7 @@ ibuf_length(struct ibuf *buf) return (ibuf_size(buf)); } -uint8_t * +u_int8_t * ibuf_data(struct ibuf *buf) { return (ibuf_seek(buf, 0, 0)); diff --git a/iked/log.c b/iked/log.c index 61256f3..e283024 100644 --- a/iked/log.c +++ b/iked/log.c @@ -1,4 +1,4 @@ -/* $OpenBSD: log.c,v 1.4 2015/01/16 06:39:58 deraadt Exp $ */ +/* $OpenBSD: log.c,v 1.3 2013/01/08 10:38:19 reyk Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -16,9 +16,10 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +#include +#include "openbsd-compat/sys-queue.h" #include -#include +#include "openbsd-compat/sys-tree.h" #include #include diff --git a/iked/ocsp.c b/iked/ocsp.c deleted file mode 100644 index 37356d8..0000000 --- a/iked/ocsp.c +++ /dev/null @@ -1,514 +0,0 @@ -/* $OpenBSD: ocsp.c,v 1.6 2015/08/21 11:59:27 reyk Exp $ */ - -/* - * Copyright (c) 2014 Markus Friedl - * Copyright (c) 2005 Marco Pfatschbacher - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "iked.h" - -struct iked_ocsp { - struct iked *ocsp_env; /* back pointer to env */ - struct iked_sahdr ocsp_sh; /* ike sa */ - uint8_t ocsp_type; /* auth type */ - struct iked_socket *ocsp_sock; /* socket to ocsp responder */ - BIO *ocsp_cbio; /* matching OpenSSL obj */ - OCSP_CERTID *ocsp_id; /* ocsp-id for cert */ - OCSP_REQUEST *ocsp_req; /* ocsp-request */ - OCSP_REQ_CTX *ocsp_req_ctx; /* async ocsp-request */ -}; - -struct ocsp_connect { - struct iked_socket oc_sock; - char *oc_path; -}; - -/* priv */ -void ocsp_connect_cb(int, short, void *); -int ocsp_connect_finish(struct iked *, int, struct ocsp_connect *); - -/* unpriv */ -void ocsp_free(struct iked_ocsp *); -void ocsp_callback(int, short, void *); -void ocsp_parse_response(struct iked_ocsp *, OCSP_RESPONSE *); -STACK_OF(X509) *ocsp_load_certs(const char *); -int ocsp_validate_finish(struct iked_ocsp *, int); - - -/* priv */ - -/* async connect to configure ocsp-responder */ -int -ocsp_connect(struct iked *env) -{ - struct ocsp_connect *oc = NULL; - struct addrinfo hints, *res0 = NULL, *res; - char *host = NULL, *port = NULL, *path = NULL; - int use_ssl, fd = -1, ret = -1, error; - - if (env->sc_ocsp_url == 0) { - log_warnx("%s: no ocsp url", __func__); - goto done; - } - if (!OCSP_parse_url(env->sc_ocsp_url, &host, &port, &path, &use_ssl)) { - log_warnx("%s: error parsing OCSP-request-URL: %s", __func__, - env->sc_ocsp_url); - goto done; - } - - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - log_debug("%s: socket failed", __func__); - goto done; - } - if ((oc = calloc(1, sizeof(*oc))) == NULL) { - log_debug("%s: calloc failed", __func__); - goto done; - } - - bzero(&hints, sizeof(struct addrinfo)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - error = getaddrinfo(host, port, &hints, &res0); - if (error) { - log_debug("%s: getaddrinfo(%s, %s) failed", - __func__, host, port); - goto done; - } - /* XXX just pick the first answer. we could loop instead */ - for (res = res0; res; res = res->ai_next) - if (res->ai_family == AF_INET) - break; - if (res == NULL) { - log_debug("%s: no addr to connect to for %s:%s", - __func__, host, port); - goto done; - } - - oc->oc_sock.sock_fd = fd; - oc->oc_sock.sock_env = env; - oc->oc_path = path; - path = NULL; - - log_debug("%s: connect(%s, %s)", __func__, host, port); - socket_set_blockmode(fd, BM_NONBLOCK); - if (connect(fd, res->ai_addr, res->ai_addrlen) == -1) { - /* register callback for ansync connect */ - if (errno == EINPROGRESS) { - event_set(&oc->oc_sock.sock_ev, fd, EV_WRITE, - ocsp_connect_cb, oc); - event_add(&oc->oc_sock.sock_ev, NULL); - ret = 0; - } else - log_debug("%s: error while connecting: %s", __func__, - strerror(errno)); - } else { - ocsp_connect_finish(env, fd, oc); - ret = 0; - } - done: - if (res0) - freeaddrinfo(res0); - free(host); - free(port); - free(path); - if (ret == -1) { - ocsp_connect_finish(env, -1, oc); - if (fd >= 0) - close(fd); - } - return (ret); -} - -/* callback triggered if connection to ocsp-responder completes/fails */ -void -ocsp_connect_cb(int fd, short event, void *arg) -{ - struct ocsp_connect *oc = arg; - int error, send_fd = -1; - socklen_t len; - - len = sizeof(error); - if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { - log_warn("%s: getsockopt SOL_SOCKET SO_ERROR", __func__); - } else if (error) { - log_debug("%s: error while connecting: %s", __func__, - strerror(error)); - } else { - send_fd = fd; - } - ocsp_connect_finish(oc->oc_sock.sock_env, send_fd, oc); - - /* if we did not send the fd, we need to close it ourself */ - if (send_fd == -1) - close(fd); -} - -/* send FD+path or error back to CA process */ -int -ocsp_connect_finish(struct iked *env, int fd, struct ocsp_connect *oc) -{ - struct iovec iov[1]; - int iovcnt = 1, ret; - - if (oc && fd >= 0) { - /* the imsg framework will close the FD after send */ - iov[0].iov_base = oc->oc_path; - iov[0].iov_len = strlen(oc->oc_path); - ret = proc_composev_imsg(&env->sc_ps, PROC_CERT, -1, - IMSG_OCSP_FD, fd, iov, iovcnt); - } else { - ret = proc_compose_imsg(&env->sc_ps, PROC_CERT, -1, - IMSG_OCSP_FD, -1, NULL, 0); - if (fd >= 0) - close(fd); - } - if (oc) { - free(oc->oc_path); - free(oc); - } - return (ret); -} - - -/* unpriv */ - -/* validate the certifcate stored in 'data' by querying the ocsp-responder */ -int -ocsp_validate_cert(struct iked *env, struct iked_static_id *id, - void *data, size_t len, struct iked_sahdr sh, uint8_t type) -{ - struct iked_ocsp_entry *ioe; - struct iked_ocsp *ocsp; - BIO *rawcert = NULL, *bissuer = NULL; - X509 *cert = NULL, *issuer = NULL; - - if ((ioe = calloc(1, sizeof(*ioe))) == NULL) - return (-1); - if ((ocsp = calloc(1, sizeof(*ocsp))) == NULL) { - free(ioe); - return (-1); - } - - ocsp->ocsp_env = env; - ocsp->ocsp_sh = sh; - ocsp->ocsp_type = type; - - if ((rawcert = BIO_new_mem_buf(data, len)) == NULL || - (cert = d2i_X509_bio(rawcert, NULL)) == NULL || - (bissuer = BIO_new_file(IKED_OCSP_ISSUER, "r")) == NULL || - (issuer = PEM_read_bio_X509(bissuer, NULL, NULL, NULL)) == NULL || - (ocsp->ocsp_cbio = BIO_new(BIO_s_socket())) == NULL || - (ocsp->ocsp_req = OCSP_REQUEST_new()) == NULL || - !(ocsp->ocsp_id = OCSP_cert_to_id(NULL, cert, issuer)) || - !OCSP_request_add0_id(ocsp->ocsp_req, ocsp->ocsp_id)) - goto err; - - BIO_free(rawcert); - BIO_free(bissuer); - X509_free(cert); - X509_free(issuer); - - ioe->ioe_ocsp = ocsp; - TAILQ_INSERT_TAIL(&env->sc_ocsp, ioe, ioe_entry); - - /* request connection to ocsp-responder */ - proc_compose_imsg(&env->sc_ps, PROC_PARENT, -1, - IMSG_OCSP_FD, -1, NULL, 0); - return (0); - - err: - ca_sslerror(__func__); - free(ioe); - if (rawcert != NULL) - BIO_free(rawcert); - if (cert != NULL) - X509_free(cert); - if (bissuer != NULL) - BIO_free(bissuer); - if (issuer != NULL) - X509_free(issuer); - ocsp_validate_finish(ocsp, 0); /* failed */ - return (-1); -} - -/* free ocsp query context */ -void -ocsp_free(struct iked_ocsp *ocsp) -{ - if (ocsp != NULL) { - if (ocsp->ocsp_sock != NULL) { - close(ocsp->ocsp_sock->sock_fd); - free(ocsp->ocsp_sock); - } - if (ocsp->ocsp_cbio != NULL) - BIO_free_all(ocsp->ocsp_cbio); - if (ocsp->ocsp_id != NULL) - OCSP_CERTID_free(ocsp->ocsp_id); - - /* XXX not sure about ownership XXX */ - if (ocsp->ocsp_req_ctx != NULL) - OCSP_REQ_CTX_free(ocsp->ocsp_req_ctx); - else if (ocsp->ocsp_req != NULL) - OCSP_REQUEST_free(ocsp->ocsp_req); - - free(ocsp); - } -} - -/* we got a connection to the ocsp responder */ -int -ocsp_receive_fd(struct iked *env, struct imsg *imsg) -{ - struct iked_ocsp_entry *ioe = NULL; - struct iked_ocsp *ocsp = NULL; - struct iked_socket *sock; - char *path = NULL; - int ret = -1; - - log_debug("%s: received socket fd %d", __func__, imsg->fd); - if ((ioe = TAILQ_FIRST(&env->sc_ocsp)) == NULL) { - log_debug("%s: oops, no request for", __func__); - close(imsg->fd); - return (-1); - } - TAILQ_REMOVE(&env->sc_ocsp, ioe, ioe_entry); - ocsp = ioe->ioe_ocsp; - free(ioe); - - if ((sock = calloc(1, sizeof(*sock))) == NULL) - fatal("ocsp_receive_fd: calloc sock"); - - /* note that sock_addr is not set */ - sock->sock_fd = imsg->fd; - sock->sock_env = env; - ocsp->ocsp_sock = sock; - - /* fetch 'path' and 'fd' from imsg */ - if ((path = get_string(imsg->data, IMSG_DATA_SIZE(imsg))) == NULL) - goto done; - - BIO_set_fd(ocsp->ocsp_cbio, imsg->fd, BIO_NOCLOSE); - - if ((ocsp->ocsp_req_ctx = OCSP_sendreq_new(ocsp->ocsp_cbio, - path, NULL, -1)) == NULL) - goto done; - if (!OCSP_REQ_CTX_set1_req(ocsp->ocsp_req_ctx, ocsp->ocsp_req)) - goto done; - - event_set(&sock->sock_ev, sock->sock_fd, EV_WRITE, ocsp_callback, ocsp); - event_add(&sock->sock_ev, NULL); - ret = 0; - done: - if (ret == -1) - ocsp_validate_finish(ocsp, 0); /* failed */ - free(path); - return (ret); -} - -/* load a stack of x509 certificates */ -STACK_OF(X509)* -ocsp_load_certs(const char *file) -{ - BIO *bio = NULL; - STACK_OF(X509) *certs = NULL; - STACK_OF(X509_INFO) *xis = NULL; - X509_INFO *xi; - int i; - - if ((bio = BIO_new_file(file, "r")) == NULL) { - log_warn("%s: BIO_new_file failed for %s", - __func__, file); - return (NULL); - } - if ((xis = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL)) == NULL) { - ca_sslerror(__func__); - goto done; - } - if ((certs = sk_X509_new_null()) == NULL) { - log_debug("%s: sk_X509_new_null failed for %s", __func__, file); - goto done; - } - for (i = 0; i < sk_X509_INFO_num(xis); i++) { - xi = sk_X509_INFO_value(xis, i); - if (xi->x509) { - if (!sk_X509_push(certs, xi->x509)) - goto done; - xi->x509 = NULL; - } - } - - done: - if (bio) - BIO_free(bio); - if (xis) - sk_X509_INFO_pop_free(xis, X509_INFO_free); - if (certs && sk_X509_num(certs) <= 0) { - sk_X509_pop_free(certs, X509_free); - certs = NULL; - } - return (certs); -} - -/* read/write callback that sends the requests and reads the ocsp response */ -void -ocsp_callback(int fd, short event, void *arg) -{ - struct iked_ocsp *ocsp = arg; - struct iked_socket *sock = ocsp->ocsp_sock; - OCSP_RESPONSE *resp = NULL; - - /* - * Only call OCSP_sendreq_nbio() if should_read/write is - * either not requested or read/write can be called. - */ - if ((!BIO_should_read(ocsp->ocsp_cbio) || (event & EV_READ)) && - (!BIO_should_write(ocsp->ocsp_cbio) || (event & EV_WRITE)) && - OCSP_sendreq_nbio(&resp, ocsp->ocsp_req_ctx) != -1 ) { - ocsp_parse_response(ocsp, resp); - return; - } - if (BIO_should_read(ocsp->ocsp_cbio)) - event_set(&sock->sock_ev, sock->sock_fd, EV_READ, - ocsp_callback, ocsp); - else if (BIO_should_write(ocsp->ocsp_cbio)) - event_set(&sock->sock_ev, sock->sock_fd, EV_WRITE, - ocsp_callback, ocsp); - event_add(&sock->sock_ev, NULL); -} - -/* parse the actual OCSP response */ -void -ocsp_parse_response(struct iked_ocsp *ocsp, OCSP_RESPONSE *resp) -{ - int status; - X509_STORE *store = NULL; - STACK_OF(X509) *verify_other = NULL; - OCSP_BASICRESP *bs = NULL; - int verify_flags = 0; - ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; - int reason = 0; - int error = 1; - - if (!resp) { - log_warnx("%s: error querying OCSP responder", __func__); - goto done; - } - - status = OCSP_response_status(resp); - if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { - log_warnx("%s: responder error: %s (%i)\n", __func__, - OCSP_response_status_str(status), status); - goto done; - } - - verify_other = ocsp_load_certs(IKED_OCSP_RESPCERT); - verify_flags |= OCSP_TRUSTOTHER; - if (!verify_other) - goto done; - - bs = OCSP_response_get1_basic(resp); - if (!bs) { - log_warnx("%s: error parsing response", __func__); - goto done; - } - - status = OCSP_check_nonce(ocsp->ocsp_req, bs); - if (status <= 0) { - if (status == -1) - log_warnx("%s: no nonce in response", __func__); - else { - log_warnx("%s: nonce verify error", __func__); - goto done; - } - } - - store = X509_STORE_new(); - status = OCSP_basic_verify(bs, verify_other, store, verify_flags); - if (status < 0) - status = OCSP_basic_verify(bs, NULL, store, 0); - - if (status <= 0) { - ca_sslerror(__func__); - log_warnx("%s: response verify failure", __func__); - goto done; - } else - log_debug("%s: response verify ok", __func__); - - if (!OCSP_resp_find_status(bs, ocsp->ocsp_id, &status, &reason, - &rev, &thisupd, &nextupd)) { - log_warnx("%s: no status found", __func__); - goto done; - } - log_debug("%s: status: %s", __func__, OCSP_cert_status_str(status)); - - if (status == V_OCSP_CERTSTATUS_GOOD) - error = 0; - - done: - if (store) - X509_STORE_free(store); - if (verify_other) - sk_X509_pop_free(verify_other, X509_free); - if (resp) - OCSP_RESPONSE_free(resp); - if (bs) - OCSP_BASICRESP_free(bs); - - ocsp_validate_finish(ocsp, error == 0); -} - -/* - * finish the ocsp_validate_cert() RPC by sending the appropriate - * message back to the IKEv2 process - */ -int -ocsp_validate_finish(struct iked_ocsp *ocsp, int valid) -{ - struct iked *env = ocsp->ocsp_env; - struct iovec iov[2]; - int iovcnt = 2, ret, cmd; - - iov[0].iov_base = &ocsp->ocsp_sh; - iov[0].iov_len = sizeof(ocsp->ocsp_sh); - iov[1].iov_base = &ocsp->ocsp_type; - iov[1].iov_len = sizeof(ocsp->ocsp_type); - - cmd = valid ? IMSG_CERTVALID : IMSG_CERTINVALID; - ret = proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, - cmd, -1, iov, iovcnt); - - ocsp_free(ocsp); - return (ret); -} diff --git a/iked/parse.y b/iked/parse.y index 14ff9ef..7c1bda2 100644 --- a/iked/parse.y +++ b/iked/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.51 2015/10/02 16:56:34 reyk Exp $ */ +/* $OpenBSD: parse.y,v 1.30 2013/03/21 04:30:14 deraadt Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -24,11 +24,14 @@ %{ #include #include -#include +#include "openbsd-compat/sys-queue.h" #include #include #include #include +#if defined(__OpenBSD__) +#include +#endif #include #include @@ -62,12 +65,10 @@ static struct file { struct file *pushfile(const char *, int); int popfile(void); int check_file_secrecy(int, const char *); -int check_pubkey(char *, int ); int yyparse(void); int yylex(void); -int yyerror(const char *, ...) - __attribute__((__format__ (printf, 1, 2))) - __attribute__((__nonnull__ (1))); +int yyerror(const char *, ...); +int yywarn(const char *, ...); int kw_cmp(const void *, const void *); int lookup(char *); int lgetc(int); @@ -92,15 +93,14 @@ static int debug = 0; static int rules = 0; static int passive = 0; static int decouple = 0; -static char *ocsp_url = NULL; struct ipsec_xf { const char *name; - unsigned int id; - unsigned int length; - unsigned int keylength; - unsigned int nonce; - unsigned int noauth; + u_int id; + u_int length; + u_int keylength; + u_int nonce; + u_int noauth; }; struct ipsec_transforms { @@ -113,7 +113,7 @@ struct ipsec_transforms { struct ipsec_mode { struct ipsec_transforms *xfs; - uint8_t ike_exch; + u_int8_t ike_exch; }; struct iked_transform ikev2_default_ike_transforms[] = { @@ -123,8 +123,10 @@ struct iked_transform ikev2_default_ike_transforms[] = { { IKEV2_XFORMTYPE_ENCR, IKEV2_XFORMENCR_3DES }, { IKEV2_XFORMTYPE_PRF, IKEV2_XFORMPRF_HMAC_SHA2_256 }, { IKEV2_XFORMTYPE_PRF, IKEV2_XFORMPRF_HMAC_SHA1 }, + { IKEV2_XFORMTYPE_PRF, IKEV2_XFORMPRF_HMAC_MD5 }, { IKEV2_XFORMTYPE_INTEGR, IKEV2_XFORMAUTH_HMAC_SHA2_256_128 }, { IKEV2_XFORMTYPE_INTEGR, IKEV2_XFORMAUTH_HMAC_SHA1_96 }, + { IKEV2_XFORMTYPE_INTEGR, IKEV2_XFORMAUTH_HMAC_MD5_96 }, { IKEV2_XFORMTYPE_DH, IKEV2_XFORMDH_MODP_2048_256 }, { IKEV2_XFORMTYPE_DH, IKEV2_XFORMDH_MODP_2048 }, { IKEV2_XFORMTYPE_DH, IKEV2_XFORMDH_MODP_1536 }, @@ -138,9 +140,13 @@ struct iked_transform ikev2_default_esp_transforms[] = { { IKEV2_XFORMTYPE_ENCR, IKEV2_XFORMENCR_AES_CBC, 256 }, { IKEV2_XFORMTYPE_ENCR, IKEV2_XFORMENCR_AES_CBC, 192 }, { IKEV2_XFORMTYPE_ENCR, IKEV2_XFORMENCR_AES_CBC, 128 }, +#ifndef BROKEN_HMAC_SHA2_256 { IKEV2_XFORMTYPE_INTEGR, IKEV2_XFORMAUTH_HMAC_SHA2_256_128 }, +#endif { IKEV2_XFORMTYPE_INTEGR, IKEV2_XFORMAUTH_HMAC_SHA1_96 }, +#ifdef HAVE_ESN { IKEV2_XFORMTYPE_ESN, IKEV2_XFORMESN_ESN }, +#endif { IKEV2_XFORMTYPE_ESN, IKEV2_XFORMESN_NONE }, { 0 } }; @@ -235,15 +241,6 @@ const struct ipsec_xf groupxfs[] = { { "grp25", IKEV2_XFORMDH_ECP_192 }, { "ecp224", IKEV2_XFORMDH_ECP_224 }, { "grp26", IKEV2_XFORMDH_ECP_224 }, - { "brainpool224", IKEV2_XFORMDH_BRAINPOOL_P224R1 }, - { "grp27", IKEV2_XFORMDH_BRAINPOOL_P224R1 }, - { "brainpool256", IKEV2_XFORMDH_BRAINPOOL_P256R1 }, - { "grp28", IKEV2_XFORMDH_BRAINPOOL_P256R1 }, - { "brainpool384", IKEV2_XFORMDH_BRAINPOOL_P384R1 }, - { "grp29", IKEV2_XFORMDH_BRAINPOOL_P384R1 }, - { "brainpool512", IKEV2_XFORMDH_BRAINPOOL_P512R1 }, - { "grp30", IKEV2_XFORMDH_BRAINPOOL_P512R1 }, - { "curve25519", IKEV2_XFORMDH_X_CURVE25519 }, { NULL } }; @@ -275,8 +272,7 @@ const struct ipsec_xf cpxfs[] = { { "protected-subnet", IKEV2_CFG_INTERNAL_IP4_SUBNET, AF_INET }, { "protected-subnet", IKEV2_CFG_INTERNAL_IP6_SUBNET, AF_INET6 }, { "access-server", IKEV2_CFG_INTERNAL_IP4_SERVER, AF_INET }, - { "access-server", IKEV2_CFG_INTERNAL_IP6_SERVER, AF_INET6 }, - { NULL } + { "access-server", IKEV2_CFG_INTERNAL_IP6_SERVER, AF_INET6 } }; const struct iked_lifetime deflifetime = { @@ -286,11 +282,11 @@ const struct iked_lifetime deflifetime = { struct ipsec_addr_wrap { struct sockaddr_storage address; - uint8_t mask; + u_int8_t mask; int netaddress; sa_family_t af; - unsigned int type; - unsigned int action; + u_int type; + u_int action; char *name; struct ipsec_addr_wrap *next; struct ipsec_addr_wrap *tail; @@ -300,13 +296,13 @@ struct ipsec_addr_wrap { struct ipsec_hosts { struct ipsec_addr_wrap *src; struct ipsec_addr_wrap *dst; - uint16_t sport; - uint16_t dport; + u_int16_t sport; + u_int16_t dport; }; struct ipsec_filters { - char *tag; - unsigned int tap; + char *tag; + u_int tap; }; struct ipsec_addr_wrap *host(const char *); @@ -319,25 +315,22 @@ void ifa_load(void); int ifa_exists(const char *); struct ipsec_addr_wrap *ifa_lookup(const char *ifa_name); struct ipsec_addr_wrap *ifa_grouplookup(const char *); -void set_ipmask(struct ipsec_addr_wrap *, uint8_t); -const struct ipsec_xf *parse_xf(const char *, unsigned int, - const struct ipsec_xf *); -const char *print_xf(unsigned int, unsigned int, - const struct ipsec_xf *); -void copy_transforms(unsigned int, const struct ipsec_xf *, +void set_ipmask(struct ipsec_addr_wrap *, u_int8_t); +const struct ipsec_xf *parse_xf(const char *, u_int, const struct ipsec_xf *); +const char *print_xf(u_int, u_int, const struct ipsec_xf *); +void copy_transforms(u_int, const struct ipsec_xf *, const struct ipsec_xf *, struct iked_transform *, size_t, - unsigned int *, struct iked_transform *, size_t); -int create_ike(char *, int, uint8_t, struct ipsec_hosts *, - struct ipsec_hosts *, struct ipsec_mode *, - struct ipsec_mode *, uint8_t, - uint8_t, char *, char *, - uint32_t, struct iked_lifetime *, - struct iked_auth *, struct ipsec_filters *, - struct ipsec_addr_wrap *); + u_int *, struct iked_transform *, size_t); +int create_ike(char *, int, u_int8_t, struct ipsec_hosts *, + struct ipsec_hosts *, struct ipsec_mode *, + struct ipsec_mode *, u_int8_t, + u_int8_t, char *, char *, struct iked_lifetime *, + struct iked_auth *, struct ipsec_filters *, + struct ipsec_addr_wrap *); int create_user(const char *, const char *); int get_id_type(char *); -uint8_t x2i(unsigned char *); +u_int8_t x2i(unsigned char *); int parsekey(unsigned char *, size_t, struct iked_auth *); int parsekeyfile(char *, struct iked_auth *); @@ -347,12 +340,12 @@ struct ipsec_filters *ipsec_filters; typedef struct { union { int64_t number; - uint8_t ikemode; - uint8_t dir; - uint8_t satype; - uint8_t proto; + u_int8_t ikemode; + u_int8_t dir; + u_int8_t satype; + u_int8_t proto; char *string; - uint16_t port; + u_int16_t port; struct ipsec_hosts *hosts; struct ipsec_hosts peers; struct ipsec_addr_wrap *anyhost; @@ -363,7 +356,7 @@ typedef struct { char *dstid; } ids; char *id; - uint8_t type; + u_int8_t type; struct iked_lifetime lifetime; struct iked_auth ikeauth; struct iked_auth ikekey; @@ -381,7 +374,6 @@ typedef struct { %token PASSIVE ACTIVE ANY TAG TAP PROTO LOCAL GROUP NAME CONFIG EAP USER %token IKEV1 FLOW SA TCPMD5 TUNNEL TRANSPORT COUPLE DECOUPLE SET %token INCLUDE LIFETIME BYTES INET INET6 QUICK SKIP DEFAULT -%token IPCOMP OCSP IKELIFETIME %token STRING %token NUMBER %type string @@ -398,12 +390,12 @@ typedef struct { %type id %type transforms %type filters -%type ikeflags ikematch ikemode ipcomp +%type ikeflags ikematch ikemode %type ikeauth %type keyspec %type ike_sa child_sa %type lifetime -%type byte_spec time_spec ikelifetime +%type byte_spec time_spec %type name %type cfg ikecfg ikecfgvals %% @@ -442,12 +434,6 @@ set : SET ACTIVE { passive = 0; } | SET PASSIVE { passive = 1; } | SET COUPLE { decouple = 0; } | SET DECOUPLE { decouple = 1; } - | SET OCSP STRING { - if ((ocsp_url = strdup($3)) == NULL) { - yyerror("cannot set ocsp_url"); - YYERROR; - } - } ; user : USER STRING STRING { @@ -457,11 +443,9 @@ user : USER STRING STRING { ; ikev2rule : IKEV2 name ikeflags satype af proto hosts_list peers - ike_sa child_sa ids ikelifetime lifetime ikeauth ikecfg - filters { + ike_sa child_sa ids lifetime ikeauth ikecfg filters { if (create_ike($2, $5, $6, $7, &$8, $9, $10, $4, $3, - $11.srcid, $11.dstid, $12, &$13, &$14, - $16, $15) == -1) + $11.srcid, $11.dstid, &$12, &$13, $15, $14) == -1) YYERROR; } ; @@ -773,7 +757,7 @@ ike_sa : /* empty */ { encxfs = ikeencxfs; } transforms { if (($$ = calloc(1, sizeof(*$$))) == NULL) - err(1, "ike_sa: calloc"); + err(1, "child_sa: calloc"); $$->xfs = $3; } ; @@ -790,7 +774,7 @@ child_sa : /* empty */ { } ; -ikeflags : ikematch ikemode ipcomp { $$ = $1 | $2 | $3; } +ikeflags : ikematch ikemode { $$ = $1 | $2; } ; ikematch : /* empty */ { $$ = 0; } @@ -804,10 +788,6 @@ ikemode : /* empty */ { $$ = IKED_POLICY_PASSIVE; } | ACTIVE { $$ = IKED_POLICY_ACTIVE; } ; -ipcomp : /* empty */ { $$ = 0; } - | IPCOMP { $$ = IKED_POLICY_IPCOMP; } - ; - ikeauth : /* empty */ { $$.auth_method = IKEV2_AUTH_RSA_SIG; $$.auth_length = 0; @@ -821,7 +801,7 @@ ikeauth : /* empty */ { $$.auth_method = IKEV2_AUTH_SHARED_KEY_MIC; } | EAP STRING { - unsigned int i; + u_int i; for (i = 0; i < strlen($2); i++) if ($2[i] == '-') @@ -844,14 +824,14 @@ byte_spec : NUMBER { $$ = $1; } | STRING { - uint64_t bytes = 0; + u_int64_t bytes = 0; char unit = 0; if (sscanf($1, "%llu%c", &bytes, &unit) != 2) { yyerror("invalid byte specification: %s", $1); YYERROR; } - switch (toupper((unsigned char)unit)) { + switch (toupper(unit)) { case 'K': bytes *= 1024; break; @@ -873,14 +853,14 @@ time_spec : NUMBER { $$ = $1; } | STRING { - uint64_t seconds = 0; + u_int64_t seconds = 0; char unit = 0; if (sscanf($1, "%llu%c", &seconds, &unit) != 2) { yyerror("invalid time specification: %s", $1); YYERROR; } - switch (tolower((unsigned char)unit)) { + switch (tolower(unit)) { case 'm': seconds *= 60; break; @@ -908,15 +888,8 @@ lifetime : /* empty */ { } ; -ikelifetime : /* empty */ { - $$ = 0; - } - | IKELIFETIME time_spec { - $$ = $2; - } - keyspec : STRING { - uint8_t *hex; + u_int8_t *hex; bzero(&$$, sizeof($$)); @@ -1061,6 +1034,19 @@ yyerror(const char *fmt, ...) return (0); } +int +yywarn(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "%s: %d: ", file->name, yylval.lineno); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + return (0); +} + int kw_cmp(const void *k, const void *e) { @@ -1091,17 +1077,14 @@ lookup(char *s) { "from", FROM }, { "group", GROUP }, { "ike", IKEV1 }, - { "ikelifetime", IKELIFETIME }, { "ikesa", IKESA }, { "ikev2", IKEV2 }, { "include", INCLUDE }, { "inet", INET }, { "inet6", INET6 }, - { "ipcomp", IPCOMP }, { "lifetime", LIFETIME }, { "local", LOCAL }, { "name", NAME }, - { "ocsp", OCSP }, { "passive", PASSIVE }, { "peer", PEER }, { "port", PORT }, @@ -1140,10 +1123,10 @@ lookup(char *s) #define MAXPUSHBACK 128 -unsigned char *parsebuf; -int parseindex; -unsigned char pushback_buffer[MAXPUSHBACK]; -int pushback_index = 0; +char *parsebuf; +int parseindex; +char pushback_buffer[MAXPUSHBACK]; +int pushback_index = 0; int lgetc(int quotec) @@ -1166,8 +1149,7 @@ lgetc(int quotec) if (quotec) { if ((c = getc(file->stream)) == EOF) { - yyerror("reached end of file while parsing " - "quoted string"); + yyerror("reached end of file while parsing quoted string"); if (popfile() == EOF) return (EOF); return (quotec); @@ -1235,10 +1217,10 @@ findeol(void) int yylex(void) { - unsigned char buf[8096]; - unsigned char *p, *val; - int quotec, next, c; - int token; + char buf[8096]; + char *p, *val; + int quotec, next, c; + int token; top: p = buf; @@ -1259,7 +1241,7 @@ top: return (findeol()); } if (isalnum(c) || c == '_') { - *p++ = c; + *p++ = (char)c; continue; } *p = '\0'; @@ -1299,15 +1281,12 @@ top: } else if (c == quotec) { *p = '\0'; break; - } else if (c == '\0') { - yyerror("syntax error"); - return (findeol()); } if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } - *p++ = c; + *p++ = (char)c; } yylval.v.string = strdup(buf); if (yylval.v.string == NULL) @@ -1394,8 +1373,8 @@ check_file_secrecy(int fd, const char *fname) warnx("%s: owner not root or current user", fname); return (-1); } - if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { - warnx("%s: group writable or world read/writable", fname); + if (st.st_mode & (S_IRWXG | S_IRWXO)) { + warnx("%s: group/world readable/writeable", fname); return (-1); } return (0); @@ -1480,7 +1459,6 @@ parse_config(const char *filename, struct iked *x_env) env->sc_passive = passive ? 1 : 0; env->sc_decoupled = decouple ? 1 : 0; - env->sc_ocsp_url = ocsp_url; if (!rules) log_warnx("%s: no valid configuration rules found", @@ -1577,7 +1555,7 @@ symget(const char *nam) return (NULL); } -uint8_t +u_int8_t x2i(unsigned char *s) { char ss[3]; @@ -1590,13 +1568,13 @@ x2i(unsigned char *s) yyerror("keys need to be specified in hex digits"); return (-1); } - return ((uint8_t)strtoul(ss, NULL, 16)); + return ((u_int8_t)strtoul(ss, NULL, 16)); } int parsekey(unsigned char *hexkey, size_t len, struct iked_auth *auth) { - unsigned int i; + u_int i; bzero(auth, sizeof(*auth)); if ((len / 2) > sizeof(auth->auth_data)) @@ -1653,48 +1631,6 @@ get_id_type(char *string) return (IKEV2_ID_FQDN); } -int -check_pubkey(char *idstr, int type) -{ - char keyfile[PATH_MAX]; - FILE *fp = NULL; - const char *suffix = NULL; - - switch (type) { - case IKEV2_ID_IPV4: - suffix = "ipv4"; - break; - case IKEV2_ID_IPV6: - suffix = "ipv6"; - break; - case IKEV2_ID_FQDN: - suffix = "fqdn"; - break; - case IKEV2_ID_UFQDN: - suffix = "ufqdn"; - break; - default: - /* Unspecified ID or public key not supported for this type */ - return (-1); - } - - lc_string(idstr); - if ((size_t)snprintf(keyfile, sizeof(keyfile), - IKED_CA IKED_PUBKEY_DIR "%s/%s", suffix, - idstr) >= sizeof(keyfile)) { - log_warnx("%s: public key path is too long", __func__); - return (-1); - } - - if ((fp = fopen(keyfile, "r")) == NULL) - return (-1); - fclose(fp); - - log_debug("%s: found public key file %s", __func__, keyfile); - - return (0); -} - struct ipsec_addr_wrap * host(const char *s) { @@ -1774,12 +1710,11 @@ host_v6(const char *s, int prefixlen) if (prefixlen != 128) { ipa->netaddress = 1; - if (asprintf(&ipa->name, "%s/%d", hbuf, prefixlen) == -1) - err(1, "host_v6: asprintf"); - } else { - if ((ipa->name = strdup(hbuf)) == NULL) - err(1, "host_v6: strdup"); - } + asprintf(&ipa->name, "%s/%d", hbuf, prefixlen); + } else + ipa->name = strdup(hbuf); + if (ipa->name == NULL) + err(1, "host_v6: strdup"); freeaddrinfo(res); @@ -1808,7 +1743,9 @@ host_v4(const char *s, int mask) err(1, "host_v4: calloc"); ina.sin_family = AF_INET; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN ina.sin_len = sizeof(ina); +#endif memcpy(&ipa->address, &ina, sizeof(ina)); ipa->name = strdup(s); @@ -1836,7 +1773,6 @@ host_dns(const char *s, int mask) bzero(&hints, sizeof(struct addrinfo)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_ADDRCONFIG; error = getaddrinfo(s, NULL, &hints, &res0); if (error) return (NULL); @@ -1973,12 +1909,15 @@ int ifa_exists(const char *ifa_name) { struct ipsec_addr_wrap *n; +#if defined(SIOCGIFGMEMB) struct ifgroupreq ifgr; int s; +#endif if (iftab == NULL) ifa_load(); +#if defined(SIOCGIFGMEMB) /* check wether this is a group */ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) err(1, "ifa_exists: socket"); @@ -1989,6 +1928,7 @@ ifa_exists(const char *ifa_name) return (1); } close(s); +#endif for (n = iftab; n; n = n->next) { if (n->af == AF_LINK && !strncmp(n->name, ifa_name, @@ -2002,6 +1942,7 @@ ifa_exists(const char *ifa_name) struct ipsec_addr_wrap * ifa_grouplookup(const char *ifa_name) { +#if defined(SIOCGIFGMEMB) struct ifg_req *ifg; struct ifgroupreq ifgr; int s; @@ -2041,6 +1982,9 @@ ifa_grouplookup(const char *ifa_name) close(s); return (h); +#else + return (NULL); +#endif } struct ipsec_addr_wrap * @@ -2048,7 +1992,7 @@ ifa_lookup(const char *ifa_name) { struct ipsec_addr_wrap *p = NULL, *h = NULL, *n = NULL; struct sockaddr_in6 *in6; - uint8_t *s6; + u_int8_t *s6; if (iftab == NULL) ifa_load(); @@ -2073,11 +2017,11 @@ ifa_lookup(const char *ifa_name) break; case AF_INET6: in6 = (struct sockaddr_in6 *)&n->address; - s6 = (uint8_t *)&in6->sin6_addr.s6_addr; + s6 = (u_int8_t *)&in6->sin6_addr.s6_addr; /* route/show.c and bgpd/util.c give KAME credit */ if (IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) { - uint16_t tmp16; + u_int16_t tmp16; /* for now we can not handle link local, * therefore bail for now @@ -2110,13 +2054,13 @@ ifa_lookup(const char *ifa_name) } void -set_ipmask(struct ipsec_addr_wrap *address, uint8_t b) +set_ipmask(struct ipsec_addr_wrap *address, u_int8_t b) { address->mask = b; } const struct ipsec_xf * -parse_xf(const char *name, unsigned int length, const struct ipsec_xf xfs[]) +parse_xf(const char *name, u_int length, const struct ipsec_xf xfs[]) { int i; @@ -2130,7 +2074,7 @@ parse_xf(const char *name, unsigned int length, const struct ipsec_xf xfs[]) } const char * -print_xf(unsigned int id, unsigned int length, const struct ipsec_xf xfs[]) +print_xf(u_int id, u_int length, const struct ipsec_xf xfs[]) { int i; @@ -2144,7 +2088,7 @@ print_xf(unsigned int id, unsigned int length, const struct ipsec_xf xfs[]) } size_t -keylength_xf(unsigned int saproto, unsigned int type, unsigned int id) +keylength_xf(u_int saproto, u_int type, u_int id) { int i; const struct ipsec_xf *xfs; @@ -2171,7 +2115,7 @@ keylength_xf(unsigned int saproto, unsigned int type, unsigned int id) } size_t -noncelength_xf(unsigned int type, unsigned int id) +noncelength_xf(u_int type, u_int id) { const struct ipsec_xf *xfs = ipsecencxfs; int i; @@ -2198,7 +2142,7 @@ print_policy(struct iked_policy *pol) struct iked_transform *xform; struct iked_flow *flow; struct iked_cfg *cfg; - unsigned int i, j; + u_int i, j; const struct ipsec_xf *xfs = NULL; print_verbose("ikev2"); @@ -2232,8 +2176,7 @@ print_policy(struct iked_policy *pol) RB_FOREACH(flow, iked_flows, &pol->pol_flows) { print_verbose(" from %s", - print_host((struct sockaddr *)&flow->flow_src.addr, NULL, - 0)); + print_host(&flow->flow_src.addr, NULL, 0)); if (flow->flow_src.addr_af != AF_UNSPEC && flow->flow_src.addr_net) print_verbose("/%d", flow->flow_src.addr_mask); @@ -2242,8 +2185,7 @@ print_policy(struct iked_policy *pol) ntohs(flow->flow_src.addr_port)); print_verbose(" to %s", - print_host((struct sockaddr *)&flow->flow_dst.addr, NULL, - 0)); + print_host(&flow->flow_dst.addr, NULL, 0)); if (flow->flow_dst.addr_af != AF_UNSPEC && flow->flow_dst.addr_net) print_verbose("/%d", flow->flow_dst.addr_mask); @@ -2254,15 +2196,13 @@ print_policy(struct iked_policy *pol) if ((pol->pol_flags & IKED_POLICY_DEFAULT) == 0) { print_verbose(" local %s", - print_host((struct sockaddr *)&pol->pol_local.addr, NULL, - 0)); + print_host(&pol->pol_local.addr, NULL, 0)); if (pol->pol_local.addr.ss_family != AF_UNSPEC && pol->pol_local.addr_net) print_verbose("/%d", pol->pol_local.addr_mask); print_verbose(" peer %s", - print_host((struct sockaddr *)&pol->pol_peer.addr, NULL, - 0)); + print_host(&pol->pol_peer.addr, NULL, 0)); if (pol->pol_peer.addr.ss_family != AF_UNSPEC && pol->pol_peer.addr_net) print_verbose("/%d", pol->pol_peer.addr_mask); @@ -2326,9 +2266,6 @@ print_policy(struct iked_policy *pol) if (pol->pol_peerid.id_length != 0) print_verbose(" dstid %s", pol->pol_peerid.id_data); - if (pol->pol_rekey) - print_verbose(" ikelifetime %u", pol->pol_rekey); - print_verbose(" lifetime %llu bytes %llu", pol->pol_lifetime.lt_seconds, pol->pol_lifetime.lt_bytes); @@ -2350,8 +2287,7 @@ print_policy(struct iked_policy *pol) cfg = &pol->pol_cfg[i]; print_verbose(" config %s %s", print_xf(cfg->cfg_type, cfg->cfg.address.addr_af, cpxfs), - print_host((struct sockaddr *)&cfg->cfg.address.addr, NULL, - 0)); + print_host(&cfg->cfg.address.addr, NULL, 0)); } if (pol->pol_tag[0] != '\0') @@ -2364,12 +2300,12 @@ print_policy(struct iked_policy *pol) } void -copy_transforms(unsigned int type, const struct ipsec_xf *xf, +copy_transforms(u_int type, const struct ipsec_xf *xf, const struct ipsec_xf *xfs, struct iked_transform *dst, size_t ndst, - unsigned int *n, struct iked_transform *src, size_t nsrc) + u_int *n, struct iked_transform *src, size_t nsrc) { - unsigned int i; + u_int i; struct iked_transform *a, *b; if (xf != NULL) { @@ -2396,31 +2332,26 @@ copy_transforms(unsigned int type, const struct ipsec_xf *xf, } int -create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, +create_ike(char *name, int af, u_int8_t ipproto, struct ipsec_hosts *hosts, struct ipsec_hosts *peers, struct ipsec_mode *ike_sa, - struct ipsec_mode *ipsec_sa, uint8_t saproto, - uint8_t flags, char *srcid, char *dstid, - uint32_t ikelifetime, struct iked_lifetime *lt, + struct ipsec_mode *ipsec_sa, u_int8_t saproto, + u_int8_t flags, char *srcid, char *dstid, struct iked_lifetime *lt, struct iked_auth *authtype, struct ipsec_filters *filter, struct ipsec_addr_wrap *ikecfg) { - char idstr[IKED_ID_SIZE]; - unsigned int idtype = IKEV2_ID_NONE; struct ipsec_addr_wrap *ipa, *ipb; struct iked_policy pol; struct iked_proposal prop[2]; - unsigned int j; + u_int j; struct iked_transform ikexforms[64], ipsecxforms[64]; struct iked_flow flows[64]; - static unsigned int policy_id = 0; + static u_int policy_id = 0; struct iked_cfg *cfg; bzero(&pol, sizeof(pol)); bzero(&prop, sizeof(prop)); - bzero(idstr, sizeof(idstr)); pol.pol_id = ++policy_id; - pol.pol_certreqtype = env->sc_certreqtype; pol.pol_af = af; pol.pol_saproto = saproto; pol.pol_ipproto = ipproto; @@ -2526,9 +2457,6 @@ create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, pol.pol_af = ipb->af; } - if (ikelifetime) - pol.pol_rekey = ikelifetime; - if (lt) pol.pol_lifetime = *lt; else @@ -2628,8 +2556,6 @@ create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, flows[j].flow_dst.addr_net = ipb->netaddress; flows[j].flow_dst.addr_port = hosts->dport; - flows[j].flow_ipproto = ipproto; - pol.pol_nflows++; RB_INSERT(iked_flows, &pol.pol_flows, &flows[j]); } @@ -2649,29 +2575,6 @@ create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, cfg->cfg.address.addr_af = ipa->af; } - if (dstid) { - strlcpy(idstr, dstid, sizeof(idstr)); - idtype = pol.pol_peerid.id_type; - } else if (!pol.pol_peer.addr_net) { - print_host((struct sockaddr *)&pol.pol_peer.addr, idstr, - sizeof(idstr)); - switch (pol.pol_peer.addr.ss_family) { - case AF_INET: - idtype = IKEV2_ID_IPV4; - break; - case AF_INET6: - idtype = IKEV2_ID_IPV6; - break; - default: - log_warnx("%s: unknown address family", __func__); - break; - } - } - - /* Check if we have a raw public key for this peer */ - if (check_pubkey(idstr, idtype) != -1) - pol.pol_certreqtype = IKEV2_CERT_RSA_KEY; - config_setpolicy(env, &pol, PROC_IKEV2); rules++; diff --git a/iked/pfkey.c b/iked/pfkey.c index 413cdd3..343e372 100644 --- a/iked/pfkey.c +++ b/iked/pfkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfkey.c,v 1.45 2015/08/26 02:09:29 jsg Exp $ */ +/* $OpenBSD: pfkey.c,v 1.23 2013/03/21 04:30:14 deraadt Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -19,18 +19,20 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +#include +#include "openbsd-compat/sys-queue.h" #include #include #include +#if defined(__OpenBSD__) #include #include +#endif #include #include #include -#include #include #include #include @@ -42,85 +44,115 @@ #define ROUNDUP(x) (((x) + (PFKEYV2_CHUNK - 1)) & ~(PFKEYV2_CHUNK - 1)) #define IOV_CNT 20 -#define PFKEYV2_CHUNK sizeof(uint64_t) -#define PFKEY_REPLY_TIMEOUT 1000 +#define PFKEYV2_CHUNK sizeof(u_int64_t) -static uint32_t sadb_msg_seq = 0; -static unsigned int sadb_decoupled = 0; -static unsigned int sadb_ipv6refcnt = 0; +static u_int32_t sadb_msg_seq = 0; +static u_int sadb_decoupled = 0; +static u_int sadb_ipv6refcnt = 0; static int pfkey_blockipv6 = 0; -static struct event pfkey_timer_ev; -static struct timeval pfkey_timer_tv; +static struct iked_timer pfkey_timer; +static struct iked_timer pfkey_pwrtimer; struct pfkey_message { SIMPLEQ_ENTRY(pfkey_message) pm_entry; - uint8_t *pm_data; - ssize_t pm_length; + u_int8_t *pm_data; + ssize_t pm_lenght; }; -SIMPLEQ_HEAD(, pfkey_message) pfkey_retry, pfkey_postponed = +SIMPLEQ_HEAD(, pfkey_message) pfkey_postponed = SIMPLEQ_HEAD_INITIALIZER(pfkey_postponed); struct pfkey_constmap { - uint8_t pfkey_id; - unsigned int pfkey_ikeid; - unsigned int pfkey_fixedkey; + u_int8_t pfkey_id; + u_int pfkey_ikeid; + u_int pfkey_fixedkey; }; static const struct pfkey_constmap pfkey_encr[] = { +#ifdef SADB_X_EALG_DES_IV64 { SADB_X_EALG_DES_IV64, IKEV2_XFORMENCR_DES_IV64 }, +#endif { SADB_EALG_DESCBC, IKEV2_XFORMENCR_DES }, { SADB_EALG_3DESCBC, IKEV2_XFORMENCR_3DES }, +#ifdef SADB_X_EALG_RC5 { SADB_X_EALG_RC5, IKEV2_XFORMENCR_RC5 }, +#endif +#ifdef SADB_X_EALG_IDEA { SADB_X_EALG_IDEA, IKEV2_XFORMENCR_IDEA }, +#endif +#ifdef SADB_X_EALG_RC5 { SADB_X_EALG_CAST, IKEV2_XFORMENCR_CAST }, +#endif +#ifdef SADB_X_EALG_BLF { SADB_X_EALG_BLF, IKEV2_XFORMENCR_BLOWFISH }, +#endif +#ifdef SADB_X_EALG_3IDEA { SADB_X_EALG_3IDEA, IKEV2_XFORMENCR_3IDEA }, +#endif +#ifdef SADB_X_EALG_DES_IV32 { SADB_X_EALG_DES_IV32, IKEV2_XFORMENCR_DES_IV32 }, +#endif +#ifdef SADB_X_EALG_RC4 { SADB_X_EALG_RC4, IKEV2_XFORMENCR_RC4 }, +#endif { SADB_EALG_NULL, IKEV2_XFORMENCR_NULL }, { SADB_X_EALG_AES, IKEV2_XFORMENCR_AES_CBC }, +#ifdef SADB_X_EALG_AESCTR { SADB_X_EALG_AESCTR, IKEV2_XFORMENCR_AES_CTR }, +#endif +#ifdef SADB_X_EALG_AESGCM16 { SADB_X_EALG_AESGCM16, IKEV2_XFORMENCR_AES_GCM_16 }, +#endif +#ifdef SADB_X_EALG_AESGMAC { SADB_X_EALG_AESGMAC, IKEV2_XFORMENCR_NULL_AES_GMAC }, +#endif { 0 } }; static const struct pfkey_constmap pfkey_integr[] = { { SADB_AALG_MD5HMAC, IKEV2_XFORMAUTH_HMAC_MD5_96 }, { SADB_AALG_SHA1HMAC, IKEV2_XFORMAUTH_HMAC_SHA1_96 }, +#ifdef SADB_X_AALG_DES { SADB_X_AALG_DES, IKEV2_XFORMAUTH_DES_MAC }, +#endif +#if defined(SADB_X_AALG_SHA2_256) && !defined(BROKEN_HMAC_SHA2_256) { SADB_X_AALG_SHA2_256, IKEV2_XFORMAUTH_HMAC_SHA2_256_128 }, +#endif +#ifdef SADB_X_AALG_SHA2_384 { SADB_X_AALG_SHA2_384, IKEV2_XFORMAUTH_HMAC_SHA2_384_192 }, +#endif +#ifdef SADB_X_AALG_SHA2_512 { SADB_X_AALG_SHA2_512, IKEV2_XFORMAUTH_HMAC_SHA2_512_256 }, +#endif { 0 } }; static const struct pfkey_constmap pfkey_satype[] = { { SADB_SATYPE_AH, IKEV2_SAPROTO_AH }, { SADB_SATYPE_ESP, IKEV2_SAPROTO_ESP }, - { SADB_X_SATYPE_IPCOMP, IKEV2_SAPROTO_IPCOMP }, { 0 } }; -int pfkey_map(const struct pfkey_constmap *, uint16_t, uint8_t *); -int pfkey_flow(int, uint8_t, uint8_t, struct iked_flow *); -int pfkey_sa(int, uint8_t, uint8_t, struct iked_childsa *); -int pfkey_sa_getspi(int, uint8_t, struct iked_childsa *, uint32_t *); -int pfkey_sagroup(int, uint8_t, uint8_t, +int pfkey_map(const struct pfkey_constmap *, u_int16_t, u_int8_t *); +int pfkey_flow(int, u_int8_t, u_int8_t, struct iked_flow *); +int pfkey_sa(int, u_int8_t, u_int8_t, struct iked_childsa *); +int pfkey_sa_getspi(int, u_int8_t, struct iked_childsa *, u_int32_t *); +#if defined(_OPENBSD_IPSEC_API_VERSION) +int pfkey_sagroup(int, u_int8_t, u_int8_t, struct iked_childsa *, struct iked_childsa *); +#endif int pfkey_write(int, struct sadb_msg *, struct iovec *, int, - uint8_t **, ssize_t *); -int pfkey_reply(int, uint8_t **, ssize_t *); + u_int8_t **, ssize_t *); +int pfkey_reply(int, u_int8_t **, ssize_t *); void pfkey_dispatch(int, short, void *); struct sadb_ident * - pfkey_id2ident(struct iked_id *, unsigned int); -void *pfkey_find_ext(uint8_t *, ssize_t, int); + pfkey_id2ident(struct iked_id *, u_int); +void *pfkey_find_ext(u_int8_t *, ssize_t, int); -void pfkey_timer_cb(int, short, void *); -int pfkey_process(struct iked *, struct pfkey_message *); +void pfkey_timer_cb(struct iked *, void *); +void pfkey_process(struct iked *, struct pfkey_message *); int pfkey_couple(int sd, struct iked_sas *sas, int couple) @@ -128,43 +160,42 @@ pfkey_couple(int sd, struct iked_sas *sas, int couple) struct iked_sa *sa; struct iked_flow *flow; struct iked_childsa *csa; + u_int old; const char *mode[] = { "coupled", "decoupled" }; /* Socket is not ready */ if (sd == -1) return (-1); - if (sadb_decoupled == !couple) + old = sadb_decoupled ? 1 : 0; + sadb_decoupled = couple ? 0 : 1; + + if (old == sadb_decoupled) return (0); log_debug("%s: kernel %s -> %s", __func__, - mode[sadb_decoupled], mode[!sadb_decoupled]); - - /* Allow writes to the PF_KEY socket */ - sadb_decoupled = 0; + mode[old], mode[sadb_decoupled]); RB_FOREACH(sa, iked_sas, sas) { TAILQ_FOREACH(csa, &sa->sa_childsas, csa_entry) { - if (!csa->csa_loaded && couple) + if (!csa->csa_loaded && !sadb_decoupled) (void)pfkey_sa_add(sd, csa, NULL); - else if (csa->csa_loaded && !couple) + else if (csa->csa_loaded && sadb_decoupled) (void)pfkey_sa_delete(sd, csa); } TAILQ_FOREACH(flow, &sa->sa_flows, flow_entry) { - if (!flow->flow_loaded && couple) + if (!flow->flow_loaded && !sadb_decoupled) (void)pfkey_flow_add(sd, flow); - else if (flow->flow_loaded && !couple) + else if (flow->flow_loaded && sadb_decoupled) (void)pfkey_flow_delete(sd, flow); } } - sadb_decoupled = !couple; - return (0); } int -pfkey_map(const struct pfkey_constmap *map, uint16_t alg, uint8_t *pfkalg) +pfkey_map(const struct pfkey_constmap *map, u_int16_t alg, u_int8_t *pfkalg) { int i; @@ -177,8 +208,9 @@ pfkey_map(const struct pfkey_constmap *map, uint16_t alg, uint8_t *pfkalg) } int -pfkey_flow(int sd, uint8_t satype, uint8_t action, struct iked_flow *flow) +pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) { +#if defined(_OPENBSD_IPSEC_API_VERSION) struct sadb_msg smsg; struct sadb_address sa_src, sa_dst, sa_local, sa_peer, sa_smask, sa_dmask; @@ -187,16 +219,19 @@ pfkey_flow(int sd, uint8_t satype, uint8_t action, struct iked_flow *flow) struct sockaddr_storage ssrc, sdst, slocal, speer, smask, dmask; struct iovec iov[IOV_CNT]; int iov_cnt, ret = -1; + in_port_t sport, dport; + sport = dport = 0; sa_srcid = sa_dstid = NULL; bzero(&ssrc, sizeof(ssrc)); bzero(&smask, sizeof(smask)); memcpy(&ssrc, &flow->flow_src.addr, sizeof(ssrc)); memcpy(&smask, &flow->flow_src.addr, sizeof(smask)); - socket_af((struct sockaddr *)&ssrc, flow->flow_src.addr_port); - socket_af((struct sockaddr *)&smask, flow->flow_src.addr_port ? - 0xffff : 0); + if ((sport = flow->flow_src.addr_port) != 0) + dport = 0xffff; + socket_af((struct sockaddr *)&ssrc, sport); + socket_af((struct sockaddr *)&smask, dport); switch (flow->flow_src.addr_af) { case AF_INET: @@ -207,7 +242,7 @@ pfkey_flow(int sd, uint8_t satype, uint8_t action, struct iked_flow *flow) case AF_INET6: prefixlen2mask6(flow->flow_src.addr_net ? flow->flow_src.addr_mask : 128, - (uint32_t *)((struct sockaddr_in6 *) + (u_int32_t *)((struct sockaddr_in6 *) &smask)->sin6_addr.s6_addr); break; default: @@ -221,9 +256,10 @@ pfkey_flow(int sd, uint8_t satype, uint8_t action, struct iked_flow *flow) bzero(&dmask, sizeof(dmask)); memcpy(&sdst, &flow->flow_dst.addr, sizeof(sdst)); memcpy(&dmask, &flow->flow_dst.addr, sizeof(dmask)); - socket_af((struct sockaddr *)&sdst, flow->flow_dst.addr_port); - socket_af((struct sockaddr *)&dmask, flow->flow_dst.addr_port ? - 0xffff : 0); + if ((sport = flow->flow_dst.addr_port) != 0) + dport = 0xffff; + socket_af((struct sockaddr *)&sdst, sport); + socket_af((struct sockaddr *)&dmask, dport); switch (flow->flow_dst.addr_af) { case AF_INET: @@ -234,7 +270,7 @@ pfkey_flow(int sd, uint8_t satype, uint8_t action, struct iked_flow *flow) case AF_INET6: prefixlen2mask6(flow->flow_dst.addr_net ? flow->flow_dst.addr_mask : 128, - (uint32_t *)((struct sockaddr_in6 *) + (u_int32_t *)((struct sockaddr_in6 *) &dmask)->sin6_addr.s6_addr); break; default: @@ -309,11 +345,11 @@ pfkey_flow(int sd, uint8_t satype, uint8_t action, struct iked_flow *flow) (sizeof(sa_peer) + ROUNDUP(speer.ss_len)) / 8; /* local id */ - sa_srcid = pfkey_id2ident(IKESA_SRCID(flow->flow_ikesa), + sa_srcid = pfkey_id2ident(flow->flow_srcid, SADB_EXT_IDENTITY_SRC); /* peer id */ - sa_dstid = pfkey_id2ident(IKESA_DSTID(flow->flow_ikesa), + sa_dstid = pfkey_id2ident(flow->flow_dstid, SADB_EXT_IDENTITY_DST); } @@ -416,27 +452,234 @@ pfkey_flow(int sd, uint8_t satype, uint8_t action, struct iked_flow *flow) if (sa_dstid) free(sa_dstid); +#else /* !_OPENBSD_IPSEC_API_VERSION */ + + struct sadb_msg smsg; + struct sadb_address sa_src, sa_dst; + struct sadb_x_ipsecrequest sa_ipsec; + struct sadb_x_policy sa_policy, *sa_polid; + struct sadb_x_sa2 sa_2; + struct sockaddr_storage ssrc, sdst, slocal, speer; + struct iovec iov[IOV_CNT]; + int iov_cnt, ret = -1; + in_port_t sport, dport; + u_int8_t smask, dmask; + u_int8_t zeropad[8]; + size_t padlen; + u_int8_t *reply = NULL; + ssize_t rlen; + + bzero(&ssrc, sizeof(ssrc)); + memcpy(&ssrc, &flow->flow_src.addr, sizeof(ssrc)); + sport = flow->flow_src.addr_port; + socket_af((struct sockaddr *)&ssrc, sport); + + switch (flow->flow_src.addr_af) { + case AF_INET: + smask = flow->flow_src.addr_net ? + flow->flow_src.addr_mask : 32; + break; + case AF_INET6: + smask = flow->flow_src.addr_net ? + flow->flow_src.addr_mask : 128; + break; + default: + log_warnx("%s: unsupported address family %d", + __func__, flow->flow_src.addr_af); + return (-1); + } + + bzero(&sdst, sizeof(sdst)); + memcpy(&sdst, &flow->flow_dst.addr, sizeof(sdst)); + dport = flow->flow_dst.addr_port; + socket_af((struct sockaddr *)&sdst, dport); + + switch (flow->flow_dst.addr_af) { + case AF_INET: + dmask = flow->flow_dst.addr_net ? + flow->flow_dst.addr_mask : 32; + break; + case AF_INET6: + dmask = flow->flow_dst.addr_net ? + flow->flow_dst.addr_mask : 128; + break; + default: + log_warnx("%s: unsupported address family %d", + __func__, flow->flow_dst.addr_af); + return (-1); + } + + bzero(&slocal, sizeof(slocal)); + bzero(&speer, sizeof(speer)); + bzero(&zeropad, sizeof(zeropad)); + if (flow->flow_local == NULL) { + slocal.ss_family = flow->flow_src.addr_af; + speer.ss_family = flow->flow_dst.addr_af; + } else if (flow->flow_dir == IPSEC_DIR_INBOUND) { + memcpy(&speer, &flow->flow_local->addr, sizeof(slocal)); + memcpy(&slocal, &flow->flow_peer->addr, sizeof(speer)); + } else { + memcpy(&slocal, &flow->flow_local->addr, sizeof(slocal)); + memcpy(&speer, &flow->flow_peer->addr, sizeof(speer)); + } + socket_af((struct sockaddr *)&slocal, 0); + socket_af((struct sockaddr *)&speer, 0); + + bzero(&smsg, sizeof(smsg)); + smsg.sadb_msg_version = PF_KEY_V2; + smsg.sadb_msg_seq = ++sadb_msg_seq; + smsg.sadb_msg_pid = getpid(); + smsg.sadb_msg_len = sizeof(smsg) / 8; + smsg.sadb_msg_type = action; + smsg.sadb_msg_satype = SADB_SATYPE_UNSPEC; + + bzero(&sa_2, sizeof(sa_2)); + sa_2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; + sa_2.sadb_x_sa2_len = sizeof(sa_2) / 8; + sa_2.sadb_x_sa2_mode = IPSEC_MODE_TUNNEL; + + bzero(&sa_src, sizeof(sa_src)); + sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + sa_src.sadb_address_proto = IPSEC_ULPROTO_ANY; //flow->flow_ipproto + sa_src.sadb_address_prefixlen = smask; + sa_src.sadb_address_len = ROUNDUP(sizeof(sa_src) + SS_LEN(&ssrc)) / 8; + + bzero(&sa_dst, sizeof(sa_dst)); + sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + sa_dst.sadb_address_proto = IPSEC_ULPROTO_ANY; //flow->flow_ipproto; + sa_dst.sadb_address_prefixlen = dmask; + sa_dst.sadb_address_len = ROUNDUP(sizeof(sa_dst) + SS_LEN(&sdst)) / 8; + + bzero(&sa_policy, sizeof(sa_policy)); + sa_policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY; + sa_policy.sadb_x_policy_dir = flow->flow_dir; + + switch (flow->flow_type) { + case SADB_X_FLOW_TYPE_DENY: + sa_policy.sadb_x_policy_type = IPSEC_POLICY_DISCARD; + sa_policy.sadb_x_policy_len = sizeof(sa_policy) / 8; + break; + default: + sa_policy.sadb_x_policy_type = IPSEC_POLICY_IPSEC; + bzero(&sa_ipsec, sizeof(sa_ipsec)); + sa_ipsec.sadb_x_ipsecrequest_proto = + satype == SADB_SATYPE_AH ? IPPROTO_AH : IPPROTO_ESP; + sa_ipsec.sadb_x_ipsecrequest_mode = IPSEC_MODE_TUNNEL; /* XXX */ + sa_ipsec.sadb_x_ipsecrequest_level = + flow->flow_dir == IPSEC_DIR_INBOUND ? + IPSEC_LEVEL_USE : IPSEC_LEVEL_REQUIRE; + sa_ipsec.sadb_x_ipsecrequest_len = sizeof(sa_ipsec) + + SS_LEN(&slocal) + SS_LEN(&speer); + padlen = ROUNDUP(sa_ipsec.sadb_x_ipsecrequest_len) - + sa_ipsec.sadb_x_ipsecrequest_len; + sa_ipsec.sadb_x_ipsecrequest_len += padlen; + sa_policy.sadb_x_policy_len = + (sizeof(sa_policy) + + sa_ipsec.sadb_x_ipsecrequest_len) / 8; + break; + } + + iov_cnt = 0; + + /* header */ + iov[iov_cnt].iov_base = &smsg; + iov[iov_cnt].iov_len = sizeof(smsg); + iov_cnt++; + + /* add flow SA2 */ + iov[iov_cnt].iov_base = &sa_2; + iov[iov_cnt].iov_len = sizeof(sa_2); + smsg.sadb_msg_len += sa_2.sadb_x_sa2_len; + iov_cnt++; + + /* add source address */ + iov[iov_cnt].iov_base = &sa_src; + iov[iov_cnt].iov_len = sizeof(sa_src); + iov_cnt++; + iov[iov_cnt].iov_base = &ssrc; + iov[iov_cnt].iov_len = SS_LEN(&ssrc); + smsg.sadb_msg_len += sa_src.sadb_address_len; + iov_cnt++; + + /* add destination address */ + iov[iov_cnt].iov_base = &sa_dst; + iov[iov_cnt].iov_len = sizeof(sa_dst); + iov_cnt++; + iov[iov_cnt].iov_base = &sdst; + iov[iov_cnt].iov_len = SS_LEN(&sdst); + smsg.sadb_msg_len += sa_dst.sadb_address_len; + iov_cnt++; + + /* add policy extension */ + iov[iov_cnt].iov_base = &sa_policy; + iov[iov_cnt].iov_len = sizeof(sa_policy); + smsg.sadb_msg_len += sa_policy.sadb_x_policy_len; + iov_cnt++; + + if (sa_policy.sadb_x_policy_type == IPSEC_POLICY_IPSEC) { + iov[iov_cnt].iov_base = &sa_ipsec; + iov[iov_cnt].iov_len = sizeof(sa_ipsec); + iov_cnt++; + iov[iov_cnt].iov_base = &slocal; + iov[iov_cnt].iov_len = SS_LEN(&slocal); + iov_cnt++; + iov[iov_cnt].iov_base = &speer; + iov[iov_cnt].iov_len = SS_LEN(&speer); + if (padlen) { + iov_cnt++; + iov[iov_cnt].iov_base = zeropad; + iov[iov_cnt].iov_len = padlen; + } + iov_cnt++; + } + + ret = -1; + if (pfkey_write(sd, &smsg, iov, iov_cnt, &reply, &rlen) != 0) + goto done; + + if ((sa_polid = pfkey_find_ext(reply, rlen, + SADB_X_EXT_POLICY)) == NULL) { + log_debug("%s: erronous reply", __func__); + goto done; + } + flow->flow_id = sa_polid->sadb_x_policy_id; + + log_debug("%s: flow with policy id 0x%x", __func__, flow->flow_id); + ret = 0; + + done: + free(reply); + +#endif /* !_OPENBSD_IPSEC_API_VERSION */ + return (ret); } int -pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) +pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) { struct sadb_msg smsg; struct sadb_sa sadb; struct sadb_address sa_src, sa_dst; struct sadb_key sa_authkey, sa_enckey; struct sadb_lifetime sa_ltime_hard, sa_ltime_soft; +#if defined(_OPENBSD_IPSEC_API_VERSION) struct sadb_x_udpencap udpencap; struct sadb_x_tag sa_tag; char *tag = NULL; struct sadb_x_tap sa_tap; +#else + struct sadb_x_sa2 sa_2; +#if defined(HAVE_APPLE_NATT) + struct sadb_sa_natt natt; +#endif +#endif struct sockaddr_storage ssrc, sdst; struct sadb_ident *sa_srcid, *sa_dstid; struct iked_lifetime *lt; struct iked_policy *pol; struct iovec iov[IOV_CNT]; - uint32_t jitter; + u_int32_t jitter; int iov_cnt; sa_srcid = sa_dstid = NULL; @@ -477,23 +720,34 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) sadb.sadb_sa_state = SADB_SASTATE_MATURE; sadb.sadb_sa_replay = 64; - if (!sa->csa_transport) - sadb.sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL; +#if defined(_OPENBSD_IPSEC_API_VERSION) + /* XXX we don't support transport mode, yet */ + sadb.sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL; if (sa->csa_esn) sadb.sadb_sa_flags |= SADB_X_SAFLAGS_ESN; +#else + bzero(&sa_2, sizeof(sa_2)); + sa_2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; + sa_2.sadb_x_sa2_len = sizeof(sa_2) / 8; + sa_2.sadb_x_sa2_mode = IPSEC_MODE_TUNNEL; /* XXX */ +#endif bzero(&sa_src, sizeof(sa_src)); - sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; + sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(SS_LEN(&ssrc))) / 8; sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; bzero(&sa_dst, sizeof(sa_dst)); - sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; + sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(SS_LEN(&sdst))) / 8; sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; bzero(&sa_authkey, sizeof(sa_authkey)); bzero(&sa_enckey, sizeof(sa_enckey)); +#if defined(_OPENBSD_IPSEC_API_VERSION) bzero(&udpencap, sizeof udpencap); +#elif defined(HAVE_APPLE_NATT) + bzero(&natt, sizeof(natt)); +#endif bzero(&sa_ltime_hard, sizeof(sa_ltime_hard)); bzero(&sa_ltime_soft, sizeof(sa_ltime_soft)); @@ -507,54 +761,66 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) sa_ltime_hard.sadb_lifetime_bytes = lt->lt_bytes; sa_ltime_hard.sadb_lifetime_addtime = lt->lt_seconds; - /* double the lifetime for IP compression */ - if (satype == SADB_X_SATYPE_IPCOMP) - sa_ltime_hard.sadb_lifetime_addtime *= 2; - sa_ltime_soft.sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; sa_ltime_soft.sadb_lifetime_len = sizeof(sa_ltime_soft) / 8; /* set randomly to 85-95% */ jitter = 850 + arc4random_uniform(100); sa_ltime_soft.sadb_lifetime_bytes = - (sa_ltime_hard.sadb_lifetime_bytes * jitter) / 1000; + (lt->lt_bytes * jitter) / 1000; sa_ltime_soft.sadb_lifetime_addtime = - (sa_ltime_hard.sadb_lifetime_addtime * jitter) / 1000; + (lt->lt_seconds * jitter) / 1000; } /* XXX handle NULL encryption or NULL auth or combined encr/auth */ if (action == SADB_ADD && !ibuf_length(sa->csa_integrkey) && !ibuf_length(sa->csa_encrkey) && - satype != SADB_X_SATYPE_IPCOMP && satype != SADB_X_SATYPE_IPIP) { + satype != SADB_X_SATYPE_IPCOMP +#if defined(_OPENBSD_IPSEC_API_VERSION) + && satype != SADB_X_SATYPE_IPIP +#endif + ) { + log_warnx("%s: no key specified", __func__); return (-1); } - if (satype == SADB_SATYPE_ESP && - sa->csa_ikesa->sa_udpencap && sa->csa_ikesa->sa_natt) { + if (sa->csa_ikesa->sa_udpencap && sa->csa_ikesa->sa_natt) { +#if defined(_OPENBSD_IPSEC_API_VERSION) sadb.sadb_sa_flags |= SADB_X_SAFLAGS_UDPENCAP; udpencap.sadb_x_udpencap_exttype = SADB_X_EXT_UDPENCAP; udpencap.sadb_x_udpencap_len = sizeof(udpencap) / 8; udpencap.sadb_x_udpencap_port = sa->csa_ikesa->sa_peer.addr_port; - - log_debug("%s: udpencap port %d", __func__, - ntohs(udpencap.sadb_x_udpencap_port)); +#elif defined(HAVE_APPLE_NATT) + sadb.sadb_sa_flags |= SADB_X_EXT_NATT; + /* XXX check NAT detection for local/peer hash instead */ + if (sa->csa_dir == IPSP_DIRECTION_OUT) + sadb.sadb_sa_flags |= SADB_X_EXT_NATT_KEEPALIVE; + else + sadb.sadb_sa_flags |= SADB_X_EXT_NATT_DETECTED_PEER; + natt.sadb_sa_natt_port = + ntohs(sa->csa_ikesa->sa_peer.addr_port); +#else +#warning PFKEYv2 NAT-T not supported +#endif + log_debug("%s: udpencap port %u", __func__, + ntohs(sa->csa_ikesa->sa_peer.addr_port)); } - if (sa->csa_integrid) + if (sa->csa_integrxf) if (pfkey_map(pfkey_integr, - sa->csa_integrid, &sadb.sadb_sa_auth) == -1) { + sa->csa_integrxf->xform_id, &sadb.sadb_sa_auth) == -1) { log_warnx("%s: unsupported integrity algorithm %s", - __func__, print_map(sa->csa_integrid, + __func__, print_map(sa->csa_integrxf->xform_id, ikev2_xformauth_map)); return (-1); } - if (sa->csa_encrid) + if (sa->csa_encrxf) if (pfkey_map(pfkey_encr, - sa->csa_encrid, &sadb.sadb_sa_encrypt) == -1) { + sa->csa_encrxf->xform_id, &sadb.sadb_sa_encrypt) == -1) { log_warnx("%s: unsupported encryption algorithm %s", - __func__, print_map(sa->csa_encrid, + __func__, print_map(sa->csa_encrxf->xform_id, ikev2_xformencr_map)); return (-1); } @@ -575,23 +841,13 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) 8 * ibuf_size(sa->csa_encrkey); } - /* we only support deflate */ - if (satype == SADB_X_SATYPE_IPCOMP) - sadb.sadb_sa_encrypt = SADB_X_CALG_DEFLATE; + /* local id */ + sa_srcid = pfkey_id2ident(sa->csa_srcid, SADB_EXT_IDENTITY_SRC); - /* Note that we need to swap the IDs for incoming SAs (SADB_UPDATE) */ - if (action != SADB_UPDATE) { - sa_srcid = pfkey_id2ident( - IKESA_SRCID(sa->csa_ikesa), SADB_EXT_IDENTITY_SRC); - sa_dstid = pfkey_id2ident( - IKESA_DSTID(sa->csa_ikesa), SADB_EXT_IDENTITY_DST); - } else { - sa_srcid = pfkey_id2ident( - IKESA_DSTID(sa->csa_ikesa), SADB_EXT_IDENTITY_SRC); - sa_dstid = pfkey_id2ident( - IKESA_SRCID(sa->csa_ikesa), SADB_EXT_IDENTITY_DST); - } + /* peer id */ + sa_dstid = pfkey_id2ident(sa->csa_dstid, SADB_EXT_IDENTITY_DST); +#if defined(_OPENBSD_IPSEC_API_VERSION) tag = sa->csa_ikesa->sa_tag; if (tag != NULL && *tag != '\0') { bzero(&sa_tag, sizeof(sa_tag)); @@ -608,6 +864,7 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) sa_tap.sadb_x_tap_len = sizeof(sa_tap) / 8; sa_tap.sadb_x_tap_unit = pol->pol_tap; } +#endif send: iov_cnt = 0; @@ -620,15 +877,31 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) /* sa */ iov[iov_cnt].iov_base = &sadb; iov[iov_cnt].iov_len = sizeof(sadb); +#if defined(HAVE_APPLE_NATT) + if (natt.sadb_sa_natt_port) { + iov_cnt++; + iov[iov_cnt].iov_base = &natt; + iov[iov_cnt].iov_len = sizeof(natt); + sadb.sadb_sa_len += sizeof(natt) / 8; + } +#endif smsg.sadb_msg_len += sadb.sadb_sa_len; iov_cnt++; +#if !defined(_OPENBSD_IPSEC_API_VERSION) + /* sa2 */ + iov[iov_cnt].iov_base = &sa_2; + iov[iov_cnt].iov_len = sizeof(sa_2); + smsg.sadb_msg_len += sa_2.sadb_x_sa2_len; + iov_cnt++; +#endif + /* src addr */ iov[iov_cnt].iov_base = &sa_src; iov[iov_cnt].iov_len = sizeof(sa_src); iov_cnt++; iov[iov_cnt].iov_base = &ssrc; - iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); + iov[iov_cnt].iov_len = ROUNDUP(SS_LEN(&ssrc)); smsg.sadb_msg_len += sa_src.sadb_address_len; iov_cnt++; @@ -637,7 +910,7 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) iov[iov_cnt].iov_len = sizeof(sa_dst); iov_cnt++; iov[iov_cnt].iov_base = &sdst; - iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); + iov[iov_cnt].iov_len = ROUNDUP(SS_LEN(&sdst)); smsg.sadb_msg_len += sa_dst.sadb_address_len; iov_cnt++; @@ -657,12 +930,14 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) iov_cnt++; } +#if defined(_OPENBSD_IPSEC_API_VERSION) if (udpencap.sadb_x_udpencap_len) { iov[iov_cnt].iov_base = &udpencap; iov[iov_cnt].iov_len = sizeof(udpencap); smsg.sadb_msg_len += udpencap.sadb_x_udpencap_len; iov_cnt++; } +#endif if (sa_enckey.sadb_key_len) { /* encryption key */ @@ -702,6 +977,7 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) iov_cnt++; } +#if defined(_OPENBSD_IPSEC_API_VERSION) if (tag != NULL) { /* tag identity */ iov[iov_cnt].iov_base = &sa_tag; @@ -720,125 +996,14 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) smsg.sadb_msg_len += sa_tap.sadb_x_tap_len; iov_cnt++; } +#endif return (pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL)); } int -pfkey_sa_last_used(int sd, struct iked_childsa *sa, uint64_t *last_used) -{ - struct sadb_msg *msg, smsg; - struct sadb_address sa_src, sa_dst; - struct sadb_sa sadb; - struct sadb_lifetime *sa_life; - struct sockaddr_storage ssrc, sdst; - struct iovec iov[IOV_CNT]; - uint8_t *data; - ssize_t n; - int iov_cnt, ret = -1; - uint8_t satype; - - *last_used = 0; - - if (pfkey_map(pfkey_satype, sa->csa_saproto, &satype) == -1) - return (-1); - - bzero(&ssrc, sizeof(ssrc)); - memcpy(&ssrc, &sa->csa_local->addr, sizeof(ssrc)); - if (socket_af((struct sockaddr *)&ssrc, 0) == -1) { - log_warn("%s: invalid address", __func__); - return (-1); - } - - bzero(&sdst, sizeof(sdst)); - memcpy(&sdst, &sa->csa_peer->addr, sizeof(sdst)); - if (socket_af((struct sockaddr *)&sdst, 0) == -1) { - log_warn("%s: invalid address", __func__); - return (-1); - } - - bzero(&smsg, sizeof(smsg)); - smsg.sadb_msg_version = PF_KEY_V2; - smsg.sadb_msg_seq = ++sadb_msg_seq; - smsg.sadb_msg_pid = getpid(); - smsg.sadb_msg_len = sizeof(smsg) / 8; - smsg.sadb_msg_type = SADB_GET; - smsg.sadb_msg_satype = satype; - - bzero(&sadb, sizeof(sadb)); - sadb.sadb_sa_len = sizeof(sadb) / 8; - sadb.sadb_sa_exttype = SADB_EXT_SA; - sadb.sadb_sa_spi = htonl(sa->csa_spi.spi); - sadb.sadb_sa_state = SADB_SASTATE_MATURE; - sadb.sadb_sa_replay = 64; - - bzero(&sa_src, sizeof(sa_src)); - sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; - sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; - - bzero(&sa_dst, sizeof(sa_dst)); - sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; - sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; - - iov_cnt = 0; - - /* header */ - iov[iov_cnt].iov_base = &smsg; - iov[iov_cnt].iov_len = sizeof(smsg); - iov_cnt++; - - /* sa */ - iov[iov_cnt].iov_base = &sadb; - iov[iov_cnt].iov_len = sizeof(sadb); - smsg.sadb_msg_len += sadb.sadb_sa_len; - iov_cnt++; - - /* src addr */ - iov[iov_cnt].iov_base = &sa_src; - iov[iov_cnt].iov_len = sizeof(sa_src); - iov_cnt++; - iov[iov_cnt].iov_base = &ssrc; - iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); - smsg.sadb_msg_len += sa_src.sadb_address_len; - iov_cnt++; - - /* dst addr */ - iov[iov_cnt].iov_base = &sa_dst; - iov[iov_cnt].iov_len = sizeof(sa_dst); - iov_cnt++; - iov[iov_cnt].iov_base = &sdst; - iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); - smsg.sadb_msg_len += sa_dst.sadb_address_len; - iov_cnt++; - - if ((ret = pfkey_write(sd, &smsg, iov, iov_cnt, &data, &n)) != 0) - return (-1); - - msg = (struct sadb_msg *)data; - if (msg->sadb_msg_errno != 0) { - errno = msg->sadb_msg_errno; - ret = -1; - log_warn("%s: message", __func__); - goto done; - } - if ((sa_life = pfkey_find_ext(data, n, SADB_X_EXT_LIFETIME_LASTUSE)) - == NULL) { - /* has never been used */ - ret = -1; - goto done; - } - *last_used = sa_life->sadb_lifetime_usetime; - log_debug("%s: last_used %llu", __func__, *last_used); - -done: - bzero(data, n); - free(data); - return (ret); -} - -int -pfkey_sa_getspi(int sd, uint8_t satype, struct iked_childsa *sa, - uint32_t *spip) +pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, + u_int32_t *spip) { struct sadb_msg *msg, smsg; struct sadb_address sa_src, sa_dst; @@ -846,9 +1011,12 @@ pfkey_sa_getspi(int sd, uint8_t satype, struct iked_childsa *sa, struct sadb_spirange sa_spirange; struct sockaddr_storage ssrc, sdst; struct iovec iov[IOV_CNT]; - uint8_t *data; + u_int8_t *data; ssize_t n; int iov_cnt, ret = -1; +#if !defined(_OPENBSD_IPSEC_API_VERSION) + struct sadb_x_sa2 sa_2; +#endif bzero(&ssrc, sizeof(ssrc)); memcpy(&ssrc, &sa->csa_local->addr, sizeof(ssrc)); @@ -872,21 +1040,32 @@ pfkey_sa_getspi(int sd, uint8_t satype, struct iked_childsa *sa, smsg.sadb_msg_type = SADB_GETSPI; smsg.sadb_msg_satype = satype; +#if !defined(_OPENBSD_IPSEC_API_VERSION) + bzero(&sa_2, sizeof(sa_2)); + sa_2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; + sa_2.sadb_x_sa2_len = sizeof(sa_2) / 8; + sa_2.sadb_x_sa2_mode = IPSEC_MODE_TUNNEL; +#endif + bzero(&sa_spirange, sizeof(sa_spirange)); sa_spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE; sa_spirange.sadb_spirange_len = sizeof(sa_spirange) / 8; sa_spirange.sadb_spirange_min = 0x100; - sa_spirange.sadb_spirange_max = (satype == SADB_X_SATYPE_IPCOMP) ? - (CPI_PRIVATE_MIN - 1) : 0xffffffff; - sa_spirange.sadb_spirange_reserved = 0; + sa_spirange.sadb_spirange_max = 0xffffffff; bzero(&sa_src, sizeof(sa_src)); - sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; + sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(SS_LEN(&ssrc))) / 8; sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + sa_src.sadb_address_proto = IPSEC_ULPROTO_ANY; + sa_src.sadb_address_prefixlen = (ssrc.ss_family == AF_INET ? + sizeof(struct in_addr) : sizeof(struct in6_addr)) << 3; bzero(&sa_dst, sizeof(sa_dst)); - sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; + sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(SS_LEN(&sdst))) / 8; sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + sa_dst.sadb_address_proto = IPSEC_ULPROTO_ANY; + sa_dst.sadb_address_prefixlen = (sdst.ss_family == AF_INET ? + sizeof(struct in_addr) : sizeof(struct in6_addr)) << 3; iov_cnt = 0; @@ -895,18 +1074,20 @@ pfkey_sa_getspi(int sd, uint8_t satype, struct iked_childsa *sa, iov[iov_cnt].iov_len = sizeof(smsg); iov_cnt++; - /* SPI range */ - iov[iov_cnt].iov_base = &sa_spirange; - iov[iov_cnt].iov_len = sizeof(sa_spirange); - smsg.sadb_msg_len += sa_spirange.sadb_spirange_len; +#if !defined(_OPENBSD_IPSEC_API_VERSION) + /* extended SA header */ + iov[iov_cnt].iov_base = &sa_2; + iov[iov_cnt].iov_len = sizeof(sa_2); + smsg.sadb_msg_len += sa_2.sadb_x_sa2_len; iov_cnt++; +#endif /* src addr */ iov[iov_cnt].iov_base = &sa_src; iov[iov_cnt].iov_len = sizeof(sa_src); iov_cnt++; iov[iov_cnt].iov_base = &ssrc; - iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); + iov[iov_cnt].iov_len = ROUNDUP(SS_LEN(&ssrc)); smsg.sadb_msg_len += sa_src.sadb_address_len; iov_cnt++; @@ -915,10 +1096,16 @@ pfkey_sa_getspi(int sd, uint8_t satype, struct iked_childsa *sa, iov[iov_cnt].iov_len = sizeof(sa_dst); iov_cnt++; iov[iov_cnt].iov_base = &sdst; - iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); + iov[iov_cnt].iov_len = ROUNDUP(SS_LEN(&sdst)); smsg.sadb_msg_len += sa_dst.sadb_address_len; iov_cnt++; + /* SPI range */ + iov[iov_cnt].iov_base = &sa_spirange; + iov[iov_cnt].iov_len = sizeof(sa_spirange); + smsg.sadb_msg_len += sa_spirange.sadb_spirange_len; + iov_cnt++; + *spip = 0; if ((ret = pfkey_write(sd, &smsg, iov, iov_cnt, &data, &n)) != 0) @@ -944,8 +1131,9 @@ pfkey_sa_getspi(int sd, uint8_t satype, struct iked_childsa *sa, return (ret); } +#if defined(_OPENBSD_IPSEC_API_VERSION) int -pfkey_sagroup(int sd, uint8_t satype1, uint8_t action, +pfkey_sagroup(int sd, u_int8_t satype1, u_int8_t action, struct iked_childsa *sa1, struct iked_childsa *sa2) { struct sadb_msg smsg; @@ -955,7 +1143,7 @@ pfkey_sagroup(int sd, uint8_t satype1, uint8_t action, struct sadb_protocol sa_proto; struct iovec iov[IOV_CNT]; int iov_cnt; - uint8_t satype2; + u_int8_t satype2; if (pfkey_map(pfkey_satype, sa2->csa_saproto, &satype2) == -1) return (-1); @@ -1056,10 +1244,11 @@ pfkey_sagroup(int sd, uint8_t satype1, uint8_t action, return (pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL)); } +#endif int pfkey_write(int sd, struct sadb_msg *smsg, struct iovec *iov, int iov_cnt, - uint8_t **datap, ssize_t *lenp) + u_int8_t **datap, ssize_t *lenp) { ssize_t n, len = smsg->sadb_msg_len * 8; @@ -1090,36 +1279,14 @@ pfkey_write(int sd, struct sadb_msg *smsg, struct iovec *iov, int iov_cnt, } int -pfkey_reply(int sd, uint8_t **datap, ssize_t *lenp) +pfkey_reply(int sd, u_int8_t **datap, ssize_t *lenp) { struct pfkey_message *pm; struct sadb_msg hdr; ssize_t len; - uint8_t *data; - struct pollfd pfd[1]; - int n; - - pfd[0].fd = sd; - pfd[0].events = POLLIN; + u_int8_t *data; for (;;) { - /* - * We should actually expect the reply to get lost - * as PF_KEY is an unreliable service per the specs. - * Currently we do this by setting a short timeout, - * and if it is not readable in that time, we fail - * the read. - */ - n = poll(pfd, 1, PFKEY_REPLY_TIMEOUT / 1000); - if (n == -1) { - log_warn("%s: poll() failed", __func__); - return (-1); - } - if (n == 0) { - log_warnx("%s: no reply from PF_KEY", __func__); - return (-1); - } - if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) { log_warn("%s: short recv", __func__); return (-1); @@ -1130,13 +1297,11 @@ pfkey_reply(int sd, uint8_t **datap, ssize_t *lenp) return (-1); } - if ((data = reallocarray(NULL, hdr.sadb_msg_len, - PFKEYV2_CHUNK)) == NULL) { + len = hdr.sadb_msg_len * PFKEYV2_CHUNK; + if ((data = malloc(len)) == NULL) { log_warn("%s: malloc", __func__); return (-1); } - len = hdr.sadb_msg_len * PFKEYV2_CHUNK; - if (read(sd, data, len) != len) { log_warnx("%s: short read", __func__); free(data); @@ -1145,26 +1310,19 @@ pfkey_reply(int sd, uint8_t **datap, ssize_t *lenp) /* XXX: Only one message can be outstanding. */ if (hdr.sadb_msg_seq == sadb_msg_seq && - hdr.sadb_msg_pid == (uint32_t)getpid()) + hdr.sadb_msg_pid == (u_int32_t)getpid()) break; - /* ignore messages for other processes */ - if (hdr.sadb_msg_pid != 0 && - hdr.sadb_msg_pid != (uint32_t)getpid()) { - free(data); - continue; - } - /* not the reply, enqueue */ if ((pm = malloc(sizeof(*pm))) == NULL) { - log_warn("%s: malloc", __func__); + log_warn("%s", __func__); free(data); return (-1); } pm->pm_data = data; - pm->pm_length = len; + pm->pm_lenght = len; SIMPLEQ_INSERT_TAIL(&pfkey_postponed, pm, pm_entry); - evtimer_add(&pfkey_timer_ev, &pfkey_timer_tv); + timer_register(NULL, &pfkey_timer, 1); } if (datap) { @@ -1187,7 +1345,7 @@ pfkey_reply(int sd, uint8_t **datap, ssize_t *lenp) int pfkey_flow_add(int fd, struct iked_flow *flow) { - uint8_t satype; + u_int8_t satype; if (flow->flow_loaded) return (0); @@ -1212,7 +1370,7 @@ pfkey_flow_add(int fd, struct iked_flow *flow) int pfkey_flow_delete(int fd, struct iked_flow *flow) { - uint8_t satype; + u_int8_t satype; if (!flow->flow_loaded) return (0); @@ -1235,10 +1393,20 @@ pfkey_flow_delete(int fd, struct iked_flow *flow) } int -pfkey_block(int fd, int af, unsigned int action) +pfkey_block(int fd, int af, u_int action) { struct iked_flow flow; +#if !defined(_OPENBSD_IPSEC_API_VERSION) && !defined(XXX_BLOCK_IPV6) + /* + * XXX This is work in progress, I didn't have time to make + * XXX this work with PFKEYv2 on KAME-based platforms yet. + */ +#warning PFKEYv2 IPv6 blocking not supported + log_debug("%s: not yet supported on this platform, ignored", __func__); + return (0); +#endif + if (!pfkey_blockipv6) return (0); @@ -1265,9 +1433,9 @@ pfkey_block(int fd, int af, unsigned int action) } int -pfkey_sa_init(int fd, struct iked_childsa *sa, uint32_t *spi) +pfkey_sa_init(int fd, struct iked_childsa *sa, u_int32_t *spi) { - uint8_t satype; + u_int8_t satype; if (pfkey_map(pfkey_satype, sa->csa_saproto, &satype) == -1) return (-1); @@ -1283,8 +1451,8 @@ pfkey_sa_init(int fd, struct iked_childsa *sa, uint32_t *spi) int pfkey_sa_add(int fd, struct iked_childsa *sa, struct iked_childsa *last) { - uint8_t satype; - unsigned int cmd; + u_int8_t satype; + u_int cmd; if (pfkey_map(pfkey_satype, sa->csa_saproto, &satype) == -1) return (-1); @@ -1298,27 +1466,19 @@ pfkey_sa_add(int fd, struct iked_childsa *sa, struct iked_childsa *last) print_spi(sa->csa_spi.spi, 4)); if (pfkey_sa(fd, satype, cmd, sa) == -1) { - if (cmd == SADB_ADD) { + if (cmd == SADB_ADD) (void)pfkey_sa_delete(fd, sa); - return (-1); - } - if (sa->csa_allocated && !sa->csa_loaded && errno == ESRCH) { - /* Needed for recoupling local SAs */ - log_debug("%s: SADB_UPDATE on local SA returned ESRCH," - " trying SADB_ADD", __func__); - if (pfkey_sa(fd, satype, SADB_ADD, sa) == -1) - return (-1); - } else { - return (-1); - } + return (-1); } if (last && cmd == SADB_ADD) { +#if defined(_OPENBSD_IPSEC_API_VERSION) if (pfkey_sagroup(fd, satype, SADB_X_GRPSPIS, sa, last) == -1) { (void)pfkey_sa_delete(fd, sa); return (-1); } +#endif } sa->csa_loaded = 1; @@ -1328,7 +1488,7 @@ pfkey_sa_add(int fd, struct iked_childsa *sa, struct iked_childsa *last) int pfkey_sa_delete(int fd, struct iked_childsa *sa) { - uint8_t satype; + u_int8_t satype; if (!sa->csa_loaded || sa->csa_spi.spi == 0) return (0); @@ -1344,7 +1504,7 @@ pfkey_sa_delete(int fd, struct iked_childsa *sa) } int -pfkey_flush(int sd) +pfkey_flush(int sd, u_int what) { struct sadb_msg smsg; struct iovec iov[IOV_CNT]; @@ -1355,7 +1515,7 @@ pfkey_flush(int sd) smsg.sadb_msg_seq = ++sadb_msg_seq; smsg.sadb_msg_pid = getpid(); smsg.sadb_msg_len = sizeof(smsg) / 8; - smsg.sadb_msg_type = SADB_FLUSH; + smsg.sadb_msg_type = what; smsg.sadb_msg_satype = SADB_SATYPE_UNSPEC; iov_cnt = 0; @@ -1368,10 +1528,10 @@ pfkey_flush(int sd) } struct sadb_ident * -pfkey_id2ident(struct iked_id *id, unsigned int exttype) +pfkey_id2ident(struct iked_id *id, u_int exttype) { char idstr[IKED_ID_SIZE]; - unsigned int type; + u_int type; size_t len; struct sadb_ident *sa_id; @@ -1412,6 +1572,27 @@ pfkey_id2ident(struct iked_id *id, unsigned int exttype) return (sa_id); } +void +pfkey_pwrtimer_cb(struct iked *env, void *arg) +{ +#ifdef __APPLE__ + static struct timeval waketime = { 0, 0 }; + struct timeval tv; + size_t size = sizeof(tv); + + if (sysctlbyname("kern.waketime", &tv, &size, NULL, 0) == 0) { + if (waketime.tv_sec != 0 && + memcmp(&waketime, &tv, sizeof(waketime)) != 0) { + log_info("%s: after power resume", __func__); + pfkey_flush(env->sc_pfkey, SADB_FLUSH); + } + memcpy(&waketime, &tv, sizeof(waketime)); + } +#endif + + timer_register(env, &pfkey_pwrtimer, 3); +} + int pfkey_socket(void) { @@ -1423,7 +1604,8 @@ pfkey_socket(void) if ((fd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) == -1) fatal("pfkey_socket: failed to open PF_KEY socket"); - pfkey_flush(fd); + pfkey_flush(fd, SADB_FLUSH); + pfkey_flush(fd, SADB_X_SPDFLUSH); return (fd); } @@ -1434,11 +1616,6 @@ pfkey_init(struct iked *env, int fd) struct sadb_msg smsg; struct iovec iov; - /* Set up a timer to process messages deferred by the pfkey_reply */ - pfkey_timer_tv.tv_sec = 1; - pfkey_timer_tv.tv_usec = 0; - evtimer_set(&pfkey_timer_ev, pfkey_timer_cb, env); - /* Register the pfkey socket event handler */ env->sc_pfkey = fd; event_set(&env->sc_pfkeyev, env->sc_pfkey, @@ -1474,6 +1651,13 @@ pfkey_init(struct iked *env, int fd) if (pfkey_write(fd, &smsg, &iov, 1, NULL, NULL)) fatal("pfkey_init: failed to set up AH acquires"); + /* Set up a timer to process messages deferred by the pfkey_reply */ + timer_initialize(env, &pfkey_timer, pfkey_timer_cb, NULL); + + /* Run a timer to flush the SADB after power resume */ + timer_initialize(env, &pfkey_pwrtimer, pfkey_pwrtimer_cb, NULL); + timer_register(env, &pfkey_pwrtimer, 3); + if (env->sc_opts & IKED_OPT_NOIPV6BLOCKING) return; @@ -1484,15 +1668,15 @@ pfkey_init(struct iked *env, int fd) } void * -pfkey_find_ext(uint8_t *data, ssize_t len, int type) +pfkey_find_ext(u_int8_t *data, ssize_t len, int type) { struct sadb_ext *ext = (struct sadb_ext *)(data + sizeof(struct sadb_msg)); - while (ext && ((uint8_t *)ext - data < len)) { + while (ext && ((u_int8_t *)ext - data < len)) { if (ext->sadb_ext_type == type) return (ext); - ext = (struct sadb_ext *)((uint8_t *)ext + + ext = (struct sadb_ext *)((u_int8_t *)ext + ext->sadb_ext_len * PFKEYV2_CHUNK); } @@ -1503,10 +1687,10 @@ void pfkey_dispatch(int sd, short event, void *arg) { struct iked *env = (struct iked *)arg; - struct pfkey_message pm, *pmp; + struct pfkey_message pm; struct sadb_msg hdr; ssize_t len; - uint8_t *data; + u_int8_t *data; if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) { log_warn("%s: short recv", __func__); @@ -1518,128 +1702,100 @@ pfkey_dispatch(int sd, short event, void *arg) return; } - if ((data = reallocarray(NULL, hdr.sadb_msg_len, PFKEYV2_CHUNK)) - == NULL) { + len = hdr.sadb_msg_len * PFKEYV2_CHUNK; + if ((data = malloc(len)) == NULL) { log_warn("%s: malloc", __func__); return; } - len = hdr.sadb_msg_len * PFKEYV2_CHUNK; - if (read(sd, data, len) != len) { log_warn("%s: short read", __func__); free(data); return; } - /* Try postponed requests first, so we do in-order processing */ - if (!SIMPLEQ_EMPTY(&pfkey_postponed)) - pfkey_timer_cb(0, 0, env); - pm.pm_data = data; - pm.pm_length = len; - - if (pfkey_process(env, &pm) == -1 && - (pmp = calloc(1, sizeof(*pmp))) != NULL) { - pmp->pm_data = data; - pmp->pm_length = len; - log_debug("%s: pfkey_process is busy, retry later", __func__); - SIMPLEQ_INSERT_TAIL(&pfkey_postponed, pmp, pm_entry); - evtimer_add(&pfkey_timer_ev, &pfkey_timer_tv); - } else { - free(data); - } + pm.pm_lenght = len; + pfkey_process(env, &pm); + + free(data); } void -pfkey_timer_cb(int unused, short event, void *arg) +pfkey_timer_cb(struct iked *env, void *arg) { - struct iked *env = arg; struct pfkey_message *pm; - SIMPLEQ_INIT(&pfkey_retry); while (!SIMPLEQ_EMPTY(&pfkey_postponed)) { pm = SIMPLEQ_FIRST(&pfkey_postponed); SIMPLEQ_REMOVE_HEAD(&pfkey_postponed, pm_entry); - if (pfkey_process(env, pm) == -1) { - log_debug("%s: pfkey_process is busy, retry later", - __func__); - SIMPLEQ_INSERT_TAIL(&pfkey_retry, pm, pm_entry); - } else { - free(pm->pm_data); - free(pm); - } + pfkey_process(env, pm); + free(pm->pm_data); + free(pm); } - /* move from retry to postponed */ - while ((pm = SIMPLEQ_FIRST(&pfkey_retry)) != NULL) { - SIMPLEQ_REMOVE_HEAD(&pfkey_retry, pm_entry); - SIMPLEQ_INSERT_TAIL(&pfkey_postponed, pm, pm_entry); - } - if (!SIMPLEQ_EMPTY(&pfkey_postponed)) - evtimer_add(&pfkey_timer_ev, &pfkey_timer_tv); } -/* - * pfkey_process returns 0 if the message has been processed and -1 if - * the system is busy and the the message should be passed again, later. - */ -int +void pfkey_process(struct iked *env, struct pfkey_message *pm) { struct iked_spi spi; struct sadb_sa *sa; struct sadb_lifetime *sa_ltime; struct sadb_msg *hdr; +#if defined(_OPENBSD_IPSEC_API_VERSION) struct sadb_msg smsg; struct iked_addr peer; struct iked_flow flow; struct sadb_address *sa_addr; struct sadb_protocol *sa_proto; struct sadb_x_policy sa_pol; - struct sockaddr *ssrc, *sdst, *smask, *dmask, *speer; + struct sadb_x_sa2 sa_2; + struct sockaddr_storage *ssrc, *sdst, *smask, *dmask, *speer; struct iovec iov[IOV_CNT]; - int ret = 0, iov_cnt, sd; - uint8_t *reply; + int iov_cnt, sd = env->sc_pfkey; + u_int8_t *reply; ssize_t rlen; const char *errmsg = NULL; - uint8_t *data = pm->pm_data; - ssize_t len = pm->pm_length; - size_t slen; +#else + struct iked_addr peer; + struct sadb_address *sa_addr; + struct sockaddr_storage *speer; + struct sadb_x_policy *sa_pol; + struct iked_flow *flow; +#endif + u_int8_t *data = pm->pm_data; + ssize_t len = pm->pm_lenght; if (!env || !data || !len) - return (0); + return; - sd = env->sc_pfkey; hdr = (struct sadb_msg *)data; switch (hdr->sadb_msg_type) { case SADB_ACQUIRE: - bzero(&flow, sizeof(flow)); - bzero(&peer, sizeof(peer)); - + /* Get peer from the acquire message */ if ((sa_addr = pfkey_find_ext(data, len, SADB_EXT_ADDRESS_DST)) == NULL) { log_debug("%s: no peer address", __func__); - return (0); + return; } - speer = (struct sockaddr *)(sa_addr + 1); - peer.addr_af = speer->sa_family; + speer = (struct sockaddr_storage *)(sa_addr + 1); + bzero(&peer, sizeof(peer)); + peer.addr_af = speer->ss_family; peer.addr_port = htons(socket_getport(speer)); - if ((slen = speer->sa_len) > sizeof(peer.addr)) { - log_debug("%s: invalid peer address len", __func__); - return (0); - } - memcpy(&peer.addr, speer, slen); + memcpy(&peer.addr, speer, sizeof(*speer)); if (socket_af((struct sockaddr *)&peer.addr, peer.addr_port) == -1) { log_debug("%s: invalid address", __func__); - return (0); + return; } - flow.flow_peer = &peer; - log_debug("%s: acquire request (peer %s)", __func__, print_host(speer, NULL, 0)); - /* get the matching flow */ +#if defined(_OPENBSD_IPSEC_API_VERSION) + /* Get the matching flow */ + bzero(&flow, sizeof(flow)); + flow.flow_peer = &peer; + bzero(&smsg, sizeof(smsg)); smsg.sadb_msg_version = PF_KEY_V2; smsg.sadb_msg_seq = ++sadb_msg_seq; @@ -1665,7 +1821,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) if (pfkey_write(sd, &smsg, iov, iov_cnt, &reply, &rlen)) { log_warnx("%s: failed to get a policy", __func__); - return (0); + return; } if ((sa_addr = pfkey_find_ext(reply, rlen, @@ -1673,18 +1829,14 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) errmsg = "flow source address"; goto out; } - ssrc = (struct sockaddr *)(sa_addr + 1); - flow.flow_src.addr_af = ssrc->sa_family; + ssrc = (struct sockaddr_storage *)(sa_addr + 1); + flow.flow_src.addr_af = ssrc->ss_family; flow.flow_src.addr_port = htons(socket_getport(ssrc)); - if ((slen = ssrc->sa_len) > sizeof(flow.flow_src.addr)) { - log_debug("%s: invalid src address len", __func__); - return (0); - } - memcpy(&flow.flow_src.addr, ssrc, slen); + memcpy(&flow.flow_src.addr, ssrc, sizeof(*ssrc)); if (socket_af((struct sockaddr *)&flow.flow_src.addr, flow.flow_src.addr_port) == -1) { log_debug("%s: invalid address", __func__); - return (0); + return; } if ((sa_addr = pfkey_find_ext(reply, rlen, @@ -1692,18 +1844,14 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) errmsg = "flow destination address"; goto out; } - sdst = (struct sockaddr *)(sa_addr + 1); - flow.flow_dst.addr_af = sdst->sa_family; + sdst = (struct sockaddr_storage *)(sa_addr + 1); + flow.flow_dst.addr_af = sdst->ss_family; flow.flow_dst.addr_port = htons(socket_getport(sdst)); - if ((slen = sdst->sa_len) > sizeof(flow.flow_dst.addr)) { - log_debug("%s: invalid dst address len", __func__); - return (0); - } - memcpy(&flow.flow_dst.addr, sdst, slen); + memcpy(&flow.flow_dst.addr, sdst, sizeof(*sdst)); if (socket_af((struct sockaddr *)&flow.flow_dst.addr, flow.flow_dst.addr_port) == -1) { log_debug("%s: invalid address", __func__); - return (0); + return; } if ((sa_addr = pfkey_find_ext(reply, rlen, @@ -1711,8 +1859,8 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) errmsg = "flow source mask"; goto out; } - smask = (struct sockaddr *)(sa_addr + 1); - switch (smask->sa_family) { + smask = (struct sockaddr_storage *)(sa_addr + 1); + switch (smask->ss_family) { case AF_INET: flow.flow_src.addr_mask = mask2prefixlen((struct sockaddr *)smask); @@ -1728,7 +1876,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) default: log_debug("%s: bad address family", __func__); free(reply); - return (0); + return; } if ((sa_addr = pfkey_find_ext(reply, rlen, @@ -1736,8 +1884,8 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) errmsg = "flow destination mask"; goto out; } - dmask = (struct sockaddr *)(sa_addr + 1); - switch (dmask->sa_family) { + dmask = (struct sockaddr_storage *)(sa_addr + 1); + switch (dmask->ss_family) { case AF_INET: flow.flow_dst.addr_mask = mask2prefixlen((struct sockaddr *)dmask); @@ -1753,7 +1901,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) default: log_debug("%s: bad address family", __func__); free(reply); - return (0); + return; } if ((sa_proto = pfkey_find_ext(reply, rlen, @@ -1769,18 +1917,45 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) print_host(sdst, NULL, 0), print_host(dmask, NULL, 0), print_host(speer, NULL, 0)); - ret = ikev2_acquire_sa(env, &flow); + ikev2_acquire_sa(env, &flow); out: if (errmsg) log_warnx("%s: %s wasn't found", __func__, errmsg); free(reply); +#elif defined(SADB_X_EXT_POLICY) + if ((sa_pol = pfkey_find_ext(data, len, + SADB_X_EXT_POLICY)) == NULL) { + log_debug("%s: no policy extension", __func__); + return; + } + + RB_FOREACH(flow, iked_flows, &env->sc_activeflows) { + /* + * Find existing active policy by policy Id. + * XXX This should use another tree that uses + * XXX the x_policy_id as lookup key. + */ + if (flow->flow_id == sa_pol->sadb_x_policy_id) { + log_debug("%s: flow %s policy id 0x%x ", + __func__, + flow->flow_dir == IPSP_DIRECTION_IN ? + "in" : "out", flow->flow_id); + ikev2_acquire_sa(env, flow); + break; + } + } +#else +#warning PFKEYv2 SADB_ACQUIRE not implemented + log_debug("%s: SADB_ACQUIRE not yet supported here, ignored", + __func__); +#endif break; case SADB_EXPIRE: if ((sa = pfkey_find_ext(data, len, SADB_EXT_SA)) == NULL) { log_warnx("%s: SA extension wasn't found", __func__); - return (0); + return; } if ((sa_ltime = pfkey_find_ext(data, len, SADB_EXT_LIFETIME_SOFT)) == NULL && @@ -1788,7 +1963,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) SADB_EXT_LIFETIME_HARD)) == NULL) { log_warnx("%s: lifetime extension wasn't found", __func__); - return (0); + return; } spi.spi = ntohl(sa->sadb_sa_spi); spi.spi_size = 4; @@ -1799,15 +1974,11 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) case SADB_SATYPE_ESP: spi.spi_protoid = IKEV2_SAPROTO_ESP; break; - case SADB_X_SATYPE_IPCOMP: - spi.spi_size = 2; - spi.spi_protoid = IKEV2_SAPROTO_IPCOMP; - break; default: - log_warnx("%s: unsupported SA type %d spi %s", + log_warnx("%s: usupported SA type %d spi %s", __func__, hdr->sadb_msg_satype, print_spi(spi.spi, spi.spi_size)); - return (0); + return; } log_debug("%s: SA %s is expired, pending %s", __func__, @@ -1816,10 +1987,9 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) "rekeying" : "deletion"); if (sa_ltime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT) - ret = ikev2_rekey_sa(env, &spi); + ikev2_rekey_sa(env, &spi); else - ret = ikev2_drop_sa(env, &spi); + ikev2_drop_sa(env, &spi); break; } - return (ret); } diff --git a/iked/policy.c b/iked/policy.c index 1c85e98..7cff708 100644 --- a/iked/policy.c +++ b/iked/policy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: policy.c,v 1.40 2015/10/01 10:59:23 reyk Exp $ */ +/* $OpenBSD: policy.c,v 1.23 2013/01/08 10:38:19 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -17,10 +17,18 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +#include +#include "openbsd-compat/sys-queue.h" #include #include -#include +#include "openbsd-compat/sys-tree.h" + +#include +#include +#include +#include +#include +#include #include #include @@ -57,8 +65,6 @@ int policy_lookup(struct iked *env, struct iked_message *msg) { struct iked_policy pol; - char *s, idstr[IKED_ID_SIZE]; - if (msg->msg_sa != NULL && msg->msg_sa->sa_policy != NULL) { /* Existing SA with policy */ @@ -70,15 +76,6 @@ policy_lookup(struct iked *env, struct iked_message *msg) pol.pol_af = msg->msg_peer.ss_family; memcpy(&pol.pol_peer.addr, &msg->msg_peer, sizeof(msg->msg_peer)); memcpy(&pol.pol_local.addr, &msg->msg_local, sizeof(msg->msg_local)); - if (msg->msg_id.id_type && - ikev2_print_id(&msg->msg_id, idstr, IKED_ID_SIZE) == 0 && - (s = strchr(idstr, '/')) != NULL) { - pol.pol_peerid.id_type = msg->msg_id.id_type; - pol.pol_peerid.id_length = strlen(s+1); - strlcpy(pol.pol_peerid.id_data, s+1, - sizeof(pol.pol_peerid.id_data)); - log_debug("%s: peerid '%s'", __func__, s+1); - } /* Try to find a matching policy for this message */ if ((msg->msg_policy = policy_test(env, &pol)) != NULL) @@ -100,7 +97,7 @@ policy_test(struct iked *env, struct iked_policy *key) { struct iked_policy *p = NULL, *pol = NULL; struct iked_flow *flow = NULL, *flowkey; - unsigned int cnt = 0; + u_int cnt = 0; p = TAILQ_FIRST(&env->sc_policies); while (p != NULL) { @@ -135,15 +132,6 @@ policy_test(struct iked *env, struct iked_policy *key) p = TAILQ_NEXT(p, pol_entry); continue; } - /* make sure the peer ID matches */ - if (key->pol_peerid.id_type && - (key->pol_peerid.id_type != p->pol_peerid.id_type || - memcmp(key->pol_peerid.id_data, - p->pol_peerid.id_data, - sizeof(key->pol_peerid.id_data)) != 0)) { - p = TAILQ_NEXT(p, pol_entry); - continue; - } /* Policy matched */ pol = p; @@ -214,16 +202,6 @@ policy_unref(struct iked *env, struct iked_policy *pol) return; if (--(pol->pol_refcnt) <= 0) config_free_policy(env, pol); - else { - struct iked_sa *tmp; - int count = 0; - - TAILQ_FOREACH(tmp, &pol->pol_sapeers, sa_peer_entry) - count++; - if (count != pol->pol_refcnt) - log_warnx("%s: ERROR pol %p pol_refcnt %d != count %d", - __func__, pol, pol->pol_refcnt, count); - } } void @@ -231,28 +209,19 @@ sa_state(struct iked *env, struct iked_sa *sa, int state) { const char *a; const char *b; - int ostate = sa->sa_state; - a = print_map(ostate, ikev2_state_map); + a = print_map(sa->sa_state, ikev2_state_map); b = print_map(state, ikev2_state_map); - sa->sa_state = state; - if (ostate != IKEV2_STATE_INIT && - !sa_stateok(sa, state)) { - log_debug("%s: cannot switch: %s -> %s", __func__, a, b); - sa->sa_state = ostate; - } else if (ostate != sa->sa_state) { + if (state > sa->sa_state) { switch (state) { case IKEV2_STATE_ESTABLISHED: case IKEV2_STATE_CLOSED: log_info("%s: %s -> %s from %s to %s policy '%s'", __func__, a, b, - print_host((struct sockaddr *)&sa->sa_peer.addr, - NULL, 0), - print_host((struct sockaddr *)&sa->sa_local.addr, - NULL, 0), - sa->sa_policy ? sa->sa_policy->pol_name : - ""); + print_host(&sa->sa_peer.addr, NULL, 0), + print_host(&sa->sa_local.addr, NULL, 0), + sa->sa_policy->pol_name); break; default: log_debug("%s: %s -> %s", __func__, a, b); @@ -260,19 +229,20 @@ sa_state(struct iked *env, struct iked_sa *sa, int state) } } + sa->sa_state = state; } void -sa_stateflags(struct iked_sa *sa, unsigned int flags) +sa_stateflags(struct iked_sa *sa, u_int flags) { - unsigned int require; + u_int require; if (sa->sa_state > IKEV2_STATE_SA_INIT) require = sa->sa_statevalid; else require = sa->sa_stateinit; - log_debug("%s: 0x%04x -> 0x%04x %s (required 0x%04x %s)", __func__, + log_debug("%s: 0x%02x -> 0x%02x %s (required 0x%02x %s)", __func__, sa->sa_stateflags, sa->sa_stateflags | flags, print_bits(sa->sa_stateflags | flags, IKED_REQ_BITS), require, print_bits(require, IKED_REQ_BITS)); @@ -283,7 +253,7 @@ sa_stateflags(struct iked_sa *sa, unsigned int flags) int sa_stateok(struct iked_sa *sa, int state) { - unsigned int require; + u_int require; if (sa->sa_state < state) return (0); @@ -295,8 +265,8 @@ sa_stateok(struct iked_sa *sa, int state) if (state == IKEV2_STATE_SA_INIT || state == IKEV2_STATE_VALID || - state == IKEV2_STATE_EAP_VALID) { - log_debug("%s: %s flags 0x%04x, require 0x%04x %s", __func__, + state == IKEV2_STATE_EAP) { + log_debug("%s: %s flags 0x%02x, require 0x%02x %s", __func__, print_map(state, ikev2_state_map), (sa->sa_stateflags & require), require, print_bits(require, IKED_REQ_BITS)); @@ -308,58 +278,38 @@ sa_stateok(struct iked_sa *sa, int state) } struct iked_sa * -sa_new(struct iked *env, uint64_t ispi, uint64_t rspi, - unsigned int initiator, struct iked_policy *pol) +sa_new(struct iked *env, u_int64_t ispi, u_int64_t rspi, + u_int initiator, struct iked_policy *pol) { struct iked_sa *sa; - struct iked_sa *old; struct iked_id *localid; - unsigned int diff; + u_int diff; if ((ispi == 0 && rspi == 0) || (sa = sa_lookup(env, ispi, rspi, initiator)) == NULL) { /* Create new SA */ - if (!initiator && ispi == 0) { - log_debug("%s: cannot create responder IKE SA w/o ispi", - __func__); - return (NULL); - } sa = config_new_sa(env, initiator); - if (sa == NULL) { - log_debug("%s: failed to allocate IKE SA", __func__); - return (NULL); - } - if (!initiator) - sa->sa_hdr.sh_ispi = ispi; - old = RB_INSERT(iked_sas, &env->sc_sas, sa); - if (old && old != sa) { - log_warnx("%s: duplicate IKE SA", __func__); - config_free_sa(env, sa); - return (NULL); - } } - /* Update rspi in the initator case */ - if (initiator && sa->sa_hdr.sh_rspi == 0 && rspi) - sa->sa_hdr.sh_rspi = rspi; - - if (sa->sa_policy == NULL) { + if (sa == NULL) { + log_debug("%s: failed to get sa", __func__); + return (NULL); + } + if (sa->sa_policy == NULL) sa->sa_policy = pol; - TAILQ_INSERT_TAIL(&pol->pol_sapeers, sa, sa_peer_entry); - } else + else pol = sa->sa_policy; - sa->sa_statevalid = IKED_REQ_AUTH|IKED_REQ_AUTHVALID|IKED_REQ_SA; + sa->sa_statevalid = IKED_REQ_AUTH|IKED_REQ_SA; if (pol != NULL && pol->pol_auth.auth_eap) { - sa->sa_statevalid |= IKED_REQ_CERT|IKED_REQ_EAPVALID; + sa->sa_statevalid |= IKED_REQ_CERT; } else if (pol != NULL && pol->pol_auth.auth_method != IKEV2_AUTH_SHARED_KEY_MIC) { - sa->sa_statevalid |= IKED_REQ_CERTVALID|IKED_REQ_CERT; + sa->sa_statevalid |= IKED_REQ_VALID|IKED_REQ_CERT; } if (initiator) { localid = &sa->sa_iid; - diff = IKED_REQ_CERTVALID|IKED_REQ_AUTHVALID|IKED_REQ_SA| - IKED_REQ_EAPVALID; + diff = IKED_REQ_VALID|IKED_REQ_SA; sa->sa_stateinit = sa->sa_statevalid & ~diff; sa->sa_statevalid = sa->sa_statevalid & diff; } else @@ -372,6 +322,14 @@ sa_new(struct iked *env, uint64_t ispi, uint64_t rspi, return (NULL); } + if (sa->sa_hdr.sh_ispi == 0) + sa->sa_hdr.sh_ispi = ispi; + if (sa->sa_hdr.sh_rspi == 0) + sa->sa_hdr.sh_rspi = rspi; + + /* Re-insert node into the tree */ + RB_INSERT(iked_sas, &env->sc_sas, sa); + return (sa); } @@ -382,12 +340,6 @@ sa_free(struct iked *env, struct iked_sa *sa) print_spi(sa->sa_hdr.sh_ispi, 8), print_spi(sa->sa_hdr.sh_rspi, 8)); - /* IKE rekeying running? */ - if (sa->sa_next) { - RB_REMOVE(iked_sas, &env->sc_sas, sa->sa_next); - config_free_sa(env, sa->sa_next); - } - RB_REMOVE(iked_sas, &env->sc_sas, sa); config_free_sa(env, sa); } @@ -412,37 +364,45 @@ sa_free_flows(struct iked *env, struct iked_saflows *head) int sa_address(struct iked_sa *sa, struct iked_addr *addr, - struct sockaddr_storage *peer) + struct sockaddr_storage *peer, int initiator) { + struct iked_policy *pol = sa->sa_policy; + + if (pol == NULL) { + log_debug("%s: invalid policy", __func__); + return (-1); + } + bzero(addr, sizeof(*addr)); addr->addr_af = peer->ss_family; - addr->addr_port = htons(socket_getport((struct sockaddr *)peer)); + addr->addr_port = htons(socket_getport(peer)); memcpy(&addr->addr, peer, sizeof(*peer)); if (socket_af((struct sockaddr *)&addr->addr, addr->addr_port) == -1) { log_debug("%s: invalid address", __func__); return (-1); } + + if (addr == &sa->sa_peer) { + /* XXX Re-insert node into the tree */ + RB_REMOVE(iked_sapeers, &pol->pol_sapeers, sa); + memcpy(&sa->sa_polpeer, initiator ? &pol->pol_peer : + &sa->sa_peer, sizeof(sa->sa_polpeer)); + RB_INSERT(iked_sapeers, &pol->pol_sapeers, sa); + } + return (0); } void -childsa_free(struct iked_childsa *csa) +childsa_free(struct iked_childsa *sa) { - if (csa->csa_children) { - /* XXX should not happen */ - log_warnx("%s: trying to remove CSA %p children %u", - __func__, csa, csa->csa_children); - return; - } - if (csa->csa_parent) - csa->csa_parent->csa_children--; - ibuf_release(csa->csa_encrkey); - ibuf_release(csa->csa_integrkey); - free(csa); + ibuf_release(sa->csa_encrkey); + ibuf_release(sa->csa_integrkey); + free(sa); } struct iked_childsa * -childsa_lookup(struct iked_sa *sa, uint64_t spi, uint8_t protoid) +childsa_lookup(struct iked_sa *sa, u_int64_t spi, u_int8_t protoid) { struct iked_childsa *csa; @@ -464,13 +424,13 @@ flow_free(struct iked_flow *flow) } struct iked_sa * -sa_lookup(struct iked *env, uint64_t ispi, uint64_t rspi, - unsigned int initiator) +sa_lookup(struct iked *env, u_int64_t ispi, u_int64_t rspi, + u_int initiator) { struct iked_sa *sa, key; key.sa_hdr.sh_ispi = ispi; - /* key.sa_hdr.sh_rspi = rspi; */ + key.sa_hdr.sh_rspi = rspi; key.sa_hdr.sh_initiator = initiator; if ((sa = RB_FIND(iked_sas, &env->sc_sas, &key)) != NULL) { @@ -478,7 +438,6 @@ sa_lookup(struct iked *env, uint64_t ispi, uint64_t rspi, /* Validate if SPIr matches */ if ((sa->sa_hdr.sh_rspi != 0) && - (rspi != 0) && (sa->sa_hdr.sh_rspi != rspi)) return (NULL); } @@ -489,10 +448,8 @@ sa_lookup(struct iked *env, uint64_t ispi, uint64_t rspi, static __inline int sa_cmp(struct iked_sa *a, struct iked_sa *b) { - if (a->sa_hdr.sh_initiator > b->sa_hdr.sh_initiator) - return (-1); - if (a->sa_hdr.sh_initiator < b->sa_hdr.sh_initiator) - return (1); + if (a->sa_hdr.sh_initiator != b->sa_hdr.sh_initiator) + return (-2); if (a->sa_hdr.sh_ispi > b->sa_hdr.sh_ispi) return (-1); @@ -514,11 +471,20 @@ sa_cmp(struct iked_sa *a, struct iked_sa *b) return (0); } +struct iked_sa * +sa_peer_lookup(struct iked_policy *pol, struct sockaddr_storage *peer) +{ + struct iked_sa key; + + memcpy(&key.sa_polpeer.addr, peer, sizeof(*peer)); + return (RB_FIND(iked_sapeers, &pol->pol_sapeers, &key)); +} + static __inline int -sa_addrpool_cmp(struct iked_sa *a, struct iked_sa *b) +sa_peer_cmp(struct iked_sa *a, struct iked_sa *b) { - return (sockaddr_cmp((struct sockaddr *)&a->sa_addrpool->addr, - (struct sockaddr *)&b->sa_addrpool->addr, -1)); + return (sockaddr_cmp((struct sockaddr *)&a->sa_polpeer.addr, + (struct sockaddr *)&b->sa_polpeer.addr, -1)); } struct iked_user * @@ -581,8 +547,10 @@ flow_cmp(struct iked_flow *a, struct iked_flow *b) return (diff); } +#ifndef __clang_analyzer__ RB_GENERATE(iked_sas, iked_sa, sa_entry, sa_cmp); -RB_GENERATE(iked_addrpool, iked_sa, sa_addrpool_entry, sa_addrpool_cmp); +RB_GENERATE(iked_sapeers, iked_sa, sa_peer_entry, sa_peer_cmp); RB_GENERATE(iked_users, iked_user, usr_entry, user_cmp); RB_GENERATE(iked_activesas, iked_childsa, csa_node, childsa_cmp); RB_GENERATE(iked_flows, iked_flow, flow_node, flow_cmp); +#endif diff --git a/iked/proc.c b/iked/proc.c index 18b219b..331d84b 100644 --- a/iked/proc.c +++ b/iked/proc.c @@ -1,7 +1,7 @@ -/* $OpenBSD: proc.c,v 1.23 2015/08/21 11:59:28 reyk Exp $ */ +/* $OpenBSD: proc.c,v 1.9 2013/03/21 04:30:14 deraadt Exp $ */ /* - * Copyright (c) 2010 - 2014 Reyk Floeter + * Copyright (c) 2010-2013 Reyk Floeter * Copyright (c) 2008 Pierre-Yves Ritschard * * Permission to use, copy, modify, and distribute this software for any @@ -17,15 +17,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include +#include +#include "openbsd-compat/sys-queue.h" +#include "openbsd-compat/sys-tree.h" #include -#include - -#include -#include -#include -#include +#include #include #include @@ -36,98 +32,40 @@ #include #include +#include + #include "iked.h" -void proc_open(struct privsep *, struct privsep_proc *, - struct privsep_proc *, size_t); -void proc_close(struct privsep *); -int proc_ispeer(struct privsep_proc *, unsigned int, enum privsep_procid); +void proc_setup(struct privsep *); void proc_shutdown(struct privsep_proc *); void proc_sig_handler(int, short, void *); -void proc_range(struct privsep *, enum privsep_procid, int *, int *); - -int -proc_ispeer(struct privsep_proc *procs, unsigned int nproc, - enum privsep_procid type) -{ - unsigned int i; - - for (i = 0; i < nproc; i++) - if (procs[i].p_id == type) - return (1); - return (0); -} void -proc_init(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc) +proc_init(struct privsep *ps, struct privsep_proc *p, u_int nproc) { - unsigned int i, j, src, dst; - struct privsep_pipes *pp; + u_int i; /* - * Allocate pipes for all process instances (incl. parent) - * - * - ps->ps_pipes: N:M mapping - * N source processes connected to M destination processes: - * [src][instances][dst][instances], for example - * [PROC_RELAY][3][PROC_CA][3] - * - * - ps->ps_pp: per-process 1:M part of ps->ps_pipes - * Each process instance has a destination array of socketpair fds: - * [dst][instances], for example - * [PROC_PARENT][0] - */ - for (src = 0; src < PROC_MAX; src++) { - /* Allocate destination array for each process */ - if ((ps->ps_pipes[src] = calloc(ps->ps_ninstances, - sizeof(struct privsep_pipes))) == NULL) - fatal("proc_init: calloc"); - - for (i = 0; i < ps->ps_ninstances; i++) { - pp = &ps->ps_pipes[src][i]; - - for (dst = 0; dst < PROC_MAX; dst++) { - /* Allocate maximum fd integers */ - if ((pp->pp_pipes[dst] = - calloc(ps->ps_ninstances, - sizeof(int))) == NULL) - fatal("proc_init: calloc"); - - /* Mark fd as unused */ - for (j = 0; j < ps->ps_ninstances; j++) - pp->pp_pipes[dst][j] = -1; - } - } - } - - /* - * Setup and run the parent and its children + * Called from parent */ privsep_process = PROC_PARENT; - ps->ps_instances[PROC_PARENT] = 1; ps->ps_title[PROC_PARENT] = "parent"; ps->ps_pid[PROC_PARENT] = getpid(); - ps->ps_pp = &ps->ps_pipes[privsep_process][0]; - - for (i = 0; i < nproc; i++) { - /* Default to 1 process instance */ - if (ps->ps_instances[procs[i].p_id] < 1) - ps->ps_instances[procs[i].p_id] = 1; - ps->ps_title[procs[i].p_id] = procs[i].p_title; - } - proc_open(ps, NULL, procs, nproc); + proc_setup(ps); /* Engage! */ - for (i = 0; i < nproc; i++) - ps->ps_pid[procs[i].p_id] = (*procs[i].p_init)(ps, &procs[i]); + for (i = 0; i < nproc; i++, p++) { + ps->ps_title[p->p_id] = p->p_title; + ps->ps_pid[p->p_id] = (*p->p_init)(ps, p); + } } void proc_kill(struct privsep *ps) { pid_t pid; - unsigned int i; + u_int i; if (privsep_process != PROC_PARENT) return; @@ -135,157 +73,83 @@ proc_kill(struct privsep *ps) for (i = 0; i < PROC_MAX; i++) { if (ps->ps_pid[i] == 0) continue; - killpg(ps->ps_pid[i], SIGTERM); + kill(ps->ps_pid[i], SIGTERM); } do { pid = waitpid(WAIT_ANY, NULL, 0); } while (pid != -1 || (pid == -1 && errno == EINTR)); - - proc_close(ps); } void -proc_open(struct privsep *ps, struct privsep_proc *p, - struct privsep_proc *procs, size_t nproc) +proc_setup(struct privsep *ps) { - struct privsep_pipes *pa, *pb; - int fds[2]; - unsigned int i, j, src, proc; - - if (p == NULL) - src = privsep_process; /* parent */ - else - src = p->p_id; - - /* - * Open socket pairs for our peers - */ - for (proc = 0; proc < nproc; proc++) { - procs[proc].p_ps = ps; - procs[proc].p_env = ps->ps_env; - - for (i = 0; i < ps->ps_instances[src]; i++) { - for (j = 0; j < ps->ps_instances[procs[proc].p_id]; - j++) { - pa = &ps->ps_pipes[src][i]; - pb = &ps->ps_pipes[procs[proc].p_id][j]; - - /* Check if fds are already set by peer */ - if (pa->pp_pipes[procs[proc].p_id][j] != -1) - continue; - - if (socketpair(AF_UNIX, SOCK_STREAM, - PF_UNSPEC, fds) == -1) - fatal("socketpair"); - - socket_set_blockmode(fds[0], BM_NONBLOCK); - socket_set_blockmode(fds[1], BM_NONBLOCK); - - pa->pp_pipes[procs[proc].p_id][j] = fds[0]; - pb->pp_pipes[src][i] = fds[1]; - } + int i, j, sockpair[2]; + + for (i = 0; i < PROC_MAX; i++) + for (j = 0; j < PROC_MAX; j++) { + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, + sockpair) == -1) + fatal("sockpair"); + ps->ps_pipes[i][j] = sockpair[0]; + ps->ps_pipes[j][i] = sockpair[1]; + socket_set_blockmode(ps->ps_pipes[i][j], + BM_NONBLOCK); + socket_set_blockmode(ps->ps_pipes[j][i], + BM_NONBLOCK); } - } } void -proc_listen(struct privsep *ps, struct privsep_proc *procs, size_t nproc) +proc_config(struct privsep *ps, struct privsep_proc *p, u_int nproc) { - unsigned int i, dst, src, n, m; - struct privsep_pipes *pp; + u_int src, dst, i, j, k, found; + + src = privsep_process; /* - * Close unused pipes + * close unused pipes */ - for (src = 0; src < PROC_MAX; src++) { - for (n = 0; n < ps->ps_instances[src]; n++) { - /* Ingore current process */ - if (src == (unsigned int)privsep_process && - n == ps->ps_instance) - continue; - - pp = &ps->ps_pipes[src][n]; - - for (dst = 0; dst < PROC_MAX; dst++) { - if (src == dst) - continue; - for (m = 0; m < ps->ps_instances[dst]; m++) { - if (pp->pp_pipes[dst][m] == -1) - continue; - - /* Close and invalidate fd */ - close(pp->pp_pipes[dst][m]); - pp->pp_pipes[dst][m] = -1; + for (i = 0; i < PROC_MAX; i++) { + if (i != privsep_process) { + for (j = 0; j < PROC_MAX; j++) { + close(ps->ps_pipes[i][j]); + ps->ps_pipes[i][j] = -1; + } + } else { + for (j = found = 0; j < PROC_MAX; j++, found = 0) { + for (k = 0; k < nproc; k++) { + if (p[k].p_id == j) + found++; + } + if (!found) { + close(ps->ps_pipes[i][j]); + ps->ps_pipes[i][j] = -1; } } } } - src = privsep_process; - ps->ps_pp = pp = &ps->ps_pipes[src][ps->ps_instance]; - /* - * Listen on appropriate pipes + * listen on appropriate pipes */ - for (i = 0; i < nproc; i++) { - dst = procs[i].p_id; - - if (src == dst) - fatal("proc_listen: cannot peer with oneself"); - - if ((ps->ps_ievs[dst] = calloc(ps->ps_instances[dst], - sizeof(struct imsgev))) == NULL) - fatal("proc_open"); - - for (n = 0; n < ps->ps_instances[dst]; n++) { - if (pp->pp_pipes[dst][n] == -1) - continue; - - imsg_init(&(ps->ps_ievs[dst][n].ibuf), - pp->pp_pipes[dst][n]); - ps->ps_ievs[dst][n].handler = proc_dispatch; - ps->ps_ievs[dst][n].events = EV_READ; - ps->ps_ievs[dst][n].proc = &procs[i]; - ps->ps_ievs[dst][n].data = &ps->ps_ievs[dst][n]; - procs[i].p_instance = n; - - event_set(&(ps->ps_ievs[dst][n].ev), - ps->ps_ievs[dst][n].ibuf.fd, - ps->ps_ievs[dst][n].events, - ps->ps_ievs[dst][n].handler, - ps->ps_ievs[dst][n].data); - event_add(&(ps->ps_ievs[dst][n].ev), NULL); - } - } -} - -void -proc_close(struct privsep *ps) -{ - unsigned int dst, n; - struct privsep_pipes *pp; - - if (ps == NULL) - return; - - pp = ps->ps_pp; - - for (dst = 0; dst < PROC_MAX; dst++) { - if (ps->ps_ievs[dst] == NULL) - continue; - - for (n = 0; n < ps->ps_instances[dst]; n++) { - if (pp->pp_pipes[dst][n] == -1) - continue; - - /* Cancel the fd, close and invalidate the fd */ - event_del(&(ps->ps_ievs[dst][n].ev)); - imsg_clear(&(ps->ps_ievs[dst][n].ibuf)); - close(pp->pp_pipes[dst][n]); - pp->pp_pipes[dst][n] = -1; - } - free(ps->ps_ievs[dst]); + for (i = 0; i < nproc; i++, p++) { + dst = p->p_id; + p->p_ps = ps; + p->p_env = ps->ps_env; + + imsg_init(&ps->ps_ievs[dst].ibuf, + ps->ps_pipes[src][dst]); + ps->ps_ievs[dst].handler = proc_dispatch; + ps->ps_ievs[dst].events = EV_READ; + ps->ps_ievs[dst].data = p; + ps->ps_ievs[dst].name = p->p_title; + event_set(&ps->ps_ievs[dst].ev, + ps->ps_ievs[dst].ibuf.fd, + ps->ps_ievs[dst].events, + ps->ps_ievs[dst].handler, + ps->ps_ievs[dst].data); + event_add(&ps->ps_ievs[dst].ev, NULL); } } @@ -297,13 +161,7 @@ proc_shutdown(struct privsep_proc *p) if (p->p_id == PROC_CONTROL && ps) control_cleanup(&ps->ps_csock); - if (p->p_shutdown != NULL) - (*p->p_shutdown)(); - - proc_close(ps); - - log_info("%s exiting, pid %d", p->p_title, getpid()); - + log_info("%s exiting", p->p_title); _exit(0); } @@ -320,7 +178,6 @@ proc_sig_handler(int sig, short event, void *arg) case SIGCHLD: case SIGHUP: case SIGPIPE: - case SIGUSR1: /* ignore */ break; default: @@ -331,27 +188,18 @@ proc_sig_handler(int sig, short event, void *arg) pid_t proc_run(struct privsep *ps, struct privsep_proc *p, - struct privsep_proc *procs, unsigned int nproc, - void (*init)(struct privsep *, struct privsep_proc *, void *), void *arg) + struct privsep_proc *procs, u_int nproc, + void (*init)(struct privsep *, void *), void *arg) { - pid_t pid; - struct passwd *pw; - const char *root; - struct control_sock *rcs; - unsigned int n; - - if (ps->ps_noaction) - return (0); - - proc_open(ps, p, procs, nproc); + pid_t pid; + struct passwd *pw; + const char *root; + u_int32_t seed[256]; - /* Fork child handlers */ switch (pid = fork()) { case -1: fatal("proc_run: cannot fork"); case 0: - /* Set the process group of the current process */ - setpgid(0, 0); break; default: return (pid); @@ -359,12 +207,9 @@ proc_run(struct privsep *ps, struct privsep_proc *p, pw = ps->ps_pw; - if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { + if (p->p_id == PROC_CONTROL) { if (control_init(ps, &ps->ps_csock) == -1) fatalx(p->p_title); - TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry) - if (control_init(ps, rcs) == -1) - fatalx(p->p_title); } /* Change root directory */ @@ -373,31 +218,30 @@ proc_run(struct privsep *ps, struct privsep_proc *p, else root = pw->pw_dir; +#ifndef DEBUG if (chroot(root) == -1) fatal("proc_run: chroot"); if (chdir("/") == -1) fatal("proc_run: chdir(\"/\")"); +#else +#warning disabling privilege revocation and chroot in DEBUG MODE + if (p->p_chroot != NULL) { + if (chroot(root) == -1) + fatal("proc_run: chroot"); + if (chdir("/") == -1) + fatal("proc_run: chdir(\"/\")"); + } +#endif privsep_process = p->p_id; setproctitle("%s", p->p_title); +#ifndef DEBUG if (setgroups(1, &pw->pw_gid) || setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) fatal("proc_run: cannot drop privileges"); - - /* Fork child handlers */ - for (n = 1; n < ps->ps_instances[p->p_id]; n++) { - if (fork() == 0) { - ps->ps_instance = p->p_instance = n; - break; - } - } - -#ifdef DEBUG - log_debug("%s: %s %d/%d, pid %d", __func__, p->p_title, - ps->ps_instance + 1, ps->ps_instances[p->p_id], getpid()); #endif event_init(); @@ -407,28 +251,26 @@ proc_run(struct privsep *ps, struct privsep_proc *p, signal_set(&ps->ps_evsigchld, SIGCHLD, proc_sig_handler, p); signal_set(&ps->ps_evsighup, SIGHUP, proc_sig_handler, p); signal_set(&ps->ps_evsigpipe, SIGPIPE, proc_sig_handler, p); - signal_set(&ps->ps_evsigusr1, SIGUSR1, proc_sig_handler, p); signal_add(&ps->ps_evsigint, NULL); signal_add(&ps->ps_evsigterm, NULL); signal_add(&ps->ps_evsigchld, NULL); signal_add(&ps->ps_evsighup, NULL); signal_add(&ps->ps_evsigpipe, NULL); - signal_add(&ps->ps_evsigusr1, NULL); - proc_listen(ps, procs, nproc); + proc_config(ps, procs, nproc); + + arc4random_buf(seed, sizeof(seed)); + RAND_seed(seed, sizeof(seed)); - if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { + if (p->p_id == PROC_CONTROL) { TAILQ_INIT(&ctl_conns); if (control_listen(&ps->ps_csock) == -1) fatalx(p->p_title); - TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry) - if (control_listen(rcs) == -1) - fatalx(p->p_title); } if (init != NULL) - init(ps, p, arg); + init(ps, arg); event_dispatch(); @@ -440,9 +282,9 @@ proc_run(struct privsep *ps, struct privsep_proc *p, void proc_dispatch(int fd, short event, void *arg) { - struct imsgev *iev = arg; - struct privsep_proc *p = iev->proc; + struct privsep_proc *p = (struct privsep_proc *)arg; struct privsep *ps = p->p_ps; + struct imsgev *iev; struct imsgbuf *ibuf; struct imsg imsg; ssize_t n; @@ -450,6 +292,7 @@ proc_dispatch(int fd, short event, void *arg) const char *title; title = ps->ps_title[privsep_process]; + iev = &ps->ps_ievs[p->p_id]; ibuf = &iev->ibuf; if (event & EV_READ) { @@ -464,7 +307,7 @@ proc_dispatch(int fd, short event, void *arg) } if (event & EV_WRITE) { - if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) + if (msgbuf_write(&ibuf->w) == -1) fatal(title); } @@ -474,12 +317,6 @@ proc_dispatch(int fd, short event, void *arg) if (n == 0) break; -#if DEBUG > 1 - log_debug("%s: %s %d got imsg %d from %s %d", - __func__, title, ps->ps_instance + 1, - imsg.hdr.type, p->p_title, p->p_instance); -#endif - /* * Check the message with the program callback */ @@ -495,13 +332,13 @@ proc_dispatch(int fd, short event, void *arg) switch (imsg.hdr.type) { case IMSG_CTL_VERBOSE: IMSG_SIZE_CHECK(&imsg, &verbose); + memcpy(&verbose, imsg.data, sizeof(verbose)); log_verbose(verbose); break; default: - log_warnx("%s: %s %d got invalid imsg %d from %s %d", - __func__, title, ps->ps_instance + 1, - imsg.hdr.type, p->p_title, p->p_instance); + log_warnx("%s: %s got imsg %d", __func__, p->p_title, + imsg.hdr.type); fatalx(title); } imsg_free(&imsg); @@ -509,10 +346,6 @@ proc_dispatch(int fd, short event, void *arg) imsg_event_add(iev); } -/* - * imsg helper functions - */ - void imsg_event_add(struct imsgev *iev) { @@ -531,8 +364,8 @@ imsg_event_add(struct imsgev *iev) } int -imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, - pid_t pid, int fd, void *data, uint16_t datalen) +imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, + pid_t pid, int fd, void *data, u_int16_t datalen) { int ret; @@ -544,7 +377,7 @@ imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, } int -imsg_composev_event(struct imsgev *iev, uint16_t type, uint32_t peerid, +imsg_composev_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, pid_t pid, int fd, const struct iovec *iov, int iovcnt) { int ret; @@ -556,72 +389,32 @@ imsg_composev_event(struct imsgev *iev, uint16_t type, uint32_t peerid, return (ret); } -void -proc_range(struct privsep *ps, enum privsep_procid id, int *n, int *m) -{ - if (*n == -1) { - /* Use a range of all target instances */ - *n = 0; - *m = ps->ps_instances[id]; - } else { - /* Use only a single slot of the specified peer process */ - *m = *n + 1; - } -} - int -proc_compose_imsg(struct privsep *ps, enum privsep_procid id, int n, - uint16_t type, int fd, void *data, uint16_t datalen) +proc_compose_imsg(struct iked *env, enum privsep_procid id, + u_int16_t type, int fd, void *data, u_int16_t datalen) { - int m; - - proc_range(ps, id, &n, &m); - for (; n < m; n++) { - if (imsg_compose_event(&ps->ps_ievs[id][n], - type, -1, 0, fd, data, datalen) == -1) - return (-1); - } - - return (0); + return (imsg_compose_event(&env->sc_ps.ps_ievs[id], + type, -1, 0, fd, data, datalen)); } int -proc_composev_imsg(struct privsep *ps, enum privsep_procid id, int n, - uint16_t type, int fd, const struct iovec *iov, int iovcnt) +proc_composev_imsg(struct iked *env, enum privsep_procid id, + u_int16_t type, int fd, const struct iovec *iov, int iovcnt) { - int m; - - proc_range(ps, id, &n, &m); - for (; n < m; n++) - if (imsg_composev_event(&ps->ps_ievs[id][n], - type, -1, 0, fd, iov, iovcnt) == -1) - return (-1); - - return (0); + return (imsg_composev_event(&env->sc_ps.ps_ievs[id], + type, -1, 0, fd, iov, iovcnt)); } int -proc_forward_imsg(struct privsep *ps, struct imsg *imsg, - enum privsep_procid id, int n) +proc_forward_imsg(struct iked *env, struct imsg *imsg, + enum privsep_procid id) { - return (proc_compose_imsg(ps, id, n, imsg->hdr.type, + return (proc_compose_imsg(env, id, imsg->hdr.type, imsg->fd, imsg->data, IMSG_DATA_SIZE(imsg))); } -struct imsgbuf * -proc_ibuf(struct privsep *ps, enum privsep_procid id, int n) -{ - int m; - - proc_range(ps, id, &n, &m); - return (&ps->ps_ievs[id][n].ibuf); -} - -struct imsgev * -proc_iev(struct privsep *ps, enum privsep_procid id, int n) +void +proc_flush_imsg(struct iked *env, enum privsep_procid id) { - int m; - - proc_range(ps, id, &n, &m); - return (&ps->ps_ievs[id][n]); + imsg_flush(&env->sc_ps.ps_ievs[id].ibuf); } diff --git a/iked/smult_curve25519_ref.c b/iked/smult_curve25519_ref.c deleted file mode 100644 index 71c106a..0000000 --- a/iked/smult_curve25519_ref.c +++ /dev/null @@ -1,265 +0,0 @@ -/* $OpenBSD: smult_curve25519_ref.c,v 1.1 2014/08/27 10:28:57 reyk Exp $ */ -/* -version 20081011 -Matthew Dempsky -Public domain. -Derived from public domain code by D. J. Bernstein. -*/ - -int crypto_scalarmult_curve25519(unsigned char *, const unsigned char *, const unsigned char *); - -static void add(unsigned int out[32],const unsigned int a[32],const unsigned int b[32]) -{ - unsigned int j; - unsigned int u; - u = 0; - for (j = 0;j < 31;++j) { u += a[j] + b[j]; out[j] = u & 255; u >>= 8; } - u += a[31] + b[31]; out[31] = u; -} - -static void sub(unsigned int out[32],const unsigned int a[32],const unsigned int b[32]) -{ - unsigned int j; - unsigned int u; - u = 218; - for (j = 0;j < 31;++j) { - u += a[j] + 65280 - b[j]; - out[j] = u & 255; - u >>= 8; - } - u += a[31] - b[31]; - out[31] = u; -} - -static void squeeze(unsigned int a[32]) -{ - unsigned int j; - unsigned int u; - u = 0; - for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; } - u += a[31]; a[31] = u & 127; - u = 19 * (u >> 7); - for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; } - u += a[31]; a[31] = u; -} - -static const unsigned int minusp[32] = { - 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128 -} ; - -static void freeze(unsigned int a[32]) -{ - unsigned int aorig[32]; - unsigned int j; - unsigned int negative; - - for (j = 0;j < 32;++j) aorig[j] = a[j]; - add(a,a,minusp); - negative = -((a[31] >> 7) & 1); - for (j = 0;j < 32;++j) a[j] ^= negative & (aorig[j] ^ a[j]); -} - -static void mult(unsigned int out[32],const unsigned int a[32],const unsigned int b[32]) -{ - unsigned int i; - unsigned int j; - unsigned int u; - - for (i = 0;i < 32;++i) { - u = 0; - for (j = 0;j <= i;++j) u += a[j] * b[i - j]; - for (j = i + 1;j < 32;++j) u += 38 * a[j] * b[i + 32 - j]; - out[i] = u; - } - squeeze(out); -} - -static void mult121665(unsigned int out[32],const unsigned int a[32]) -{ - unsigned int j; - unsigned int u; - - u = 0; - for (j = 0;j < 31;++j) { u += 121665 * a[j]; out[j] = u & 255; u >>= 8; } - u += 121665 * a[31]; out[31] = u & 127; - u = 19 * (u >> 7); - for (j = 0;j < 31;++j) { u += out[j]; out[j] = u & 255; u >>= 8; } - u += out[j]; out[j] = u; -} - -static void square(unsigned int out[32],const unsigned int a[32]) -{ - unsigned int i; - unsigned int j; - unsigned int u; - - for (i = 0;i < 32;++i) { - u = 0; - for (j = 0;j < i - j;++j) u += a[j] * a[i - j]; - for (j = i + 1;j < i + 32 - j;++j) u += 38 * a[j] * a[i + 32 - j]; - u *= 2; - if ((i & 1) == 0) { - u += a[i / 2] * a[i / 2]; - u += 38 * a[i / 2 + 16] * a[i / 2 + 16]; - } - out[i] = u; - } - squeeze(out); -} - -static void select(unsigned int p[64],unsigned int q[64],const unsigned int r[64],const unsigned int s[64],unsigned int b) -{ - unsigned int j; - unsigned int t; - unsigned int bminus1; - - bminus1 = b - 1; - for (j = 0;j < 64;++j) { - t = bminus1 & (r[j] ^ s[j]); - p[j] = s[j] ^ t; - q[j] = r[j] ^ t; - } -} - -static void mainloop(unsigned int work[64],const unsigned char e[32]) -{ - unsigned int xzm1[64]; - unsigned int xzm[64]; - unsigned int xzmb[64]; - unsigned int xzm1b[64]; - unsigned int xznb[64]; - unsigned int xzn1b[64]; - unsigned int a0[64]; - unsigned int a1[64]; - unsigned int b0[64]; - unsigned int b1[64]; - unsigned int c1[64]; - unsigned int r[32]; - unsigned int s[32]; - unsigned int t[32]; - unsigned int u[32]; - unsigned int j; - unsigned int b; - int pos; - - for (j = 0;j < 32;++j) xzm1[j] = work[j]; - xzm1[32] = 1; - for (j = 33;j < 64;++j) xzm1[j] = 0; - - xzm[0] = 1; - for (j = 1;j < 64;++j) xzm[j] = 0; - - for (pos = 254;pos >= 0;--pos) { - b = e[pos / 8] >> (pos & 7); - b &= 1; - select(xzmb,xzm1b,xzm,xzm1,b); - add(a0,xzmb,xzmb + 32); - sub(a0 + 32,xzmb,xzmb + 32); - add(a1,xzm1b,xzm1b + 32); - sub(a1 + 32,xzm1b,xzm1b + 32); - square(b0,a0); - square(b0 + 32,a0 + 32); - mult(b1,a1,a0 + 32); - mult(b1 + 32,a1 + 32,a0); - add(c1,b1,b1 + 32); - sub(c1 + 32,b1,b1 + 32); - square(r,c1 + 32); - sub(s,b0,b0 + 32); - mult121665(t,s); - add(u,t,b0); - mult(xznb,b0,b0 + 32); - mult(xznb + 32,s,u); - square(xzn1b,c1); - mult(xzn1b + 32,r,work); - select(xzm,xzm1,xznb,xzn1b,b); - } - - for (j = 0;j < 64;++j) work[j] = xzm[j]; -} - -static void recip(unsigned int out[32],const unsigned int z[32]) -{ - unsigned int z2[32]; - unsigned int z9[32]; - unsigned int z11[32]; - unsigned int z2_5_0[32]; - unsigned int z2_10_0[32]; - unsigned int z2_20_0[32]; - unsigned int z2_50_0[32]; - unsigned int z2_100_0[32]; - unsigned int t0[32]; - unsigned int t1[32]; - int i; - - /* 2 */ square(z2,z); - /* 4 */ square(t1,z2); - /* 8 */ square(t0,t1); - /* 9 */ mult(z9,t0,z); - /* 11 */ mult(z11,z9,z2); - /* 22 */ square(t0,z11); - /* 2^5 - 2^0 = 31 */ mult(z2_5_0,t0,z9); - - /* 2^6 - 2^1 */ square(t0,z2_5_0); - /* 2^7 - 2^2 */ square(t1,t0); - /* 2^8 - 2^3 */ square(t0,t1); - /* 2^9 - 2^4 */ square(t1,t0); - /* 2^10 - 2^5 */ square(t0,t1); - /* 2^10 - 2^0 */ mult(z2_10_0,t0,z2_5_0); - - /* 2^11 - 2^1 */ square(t0,z2_10_0); - /* 2^12 - 2^2 */ square(t1,t0); - /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { square(t0,t1); square(t1,t0); } - /* 2^20 - 2^0 */ mult(z2_20_0,t1,z2_10_0); - - /* 2^21 - 2^1 */ square(t0,z2_20_0); - /* 2^22 - 2^2 */ square(t1,t0); - /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { square(t0,t1); square(t1,t0); } - /* 2^40 - 2^0 */ mult(t0,t1,z2_20_0); - - /* 2^41 - 2^1 */ square(t1,t0); - /* 2^42 - 2^2 */ square(t0,t1); - /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { square(t1,t0); square(t0,t1); } - /* 2^50 - 2^0 */ mult(z2_50_0,t0,z2_10_0); - - /* 2^51 - 2^1 */ square(t0,z2_50_0); - /* 2^52 - 2^2 */ square(t1,t0); - /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { square(t0,t1); square(t1,t0); } - /* 2^100 - 2^0 */ mult(z2_100_0,t1,z2_50_0); - - /* 2^101 - 2^1 */ square(t1,z2_100_0); - /* 2^102 - 2^2 */ square(t0,t1); - /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { square(t1,t0); square(t0,t1); } - /* 2^200 - 2^0 */ mult(t1,t0,z2_100_0); - - /* 2^201 - 2^1 */ square(t0,t1); - /* 2^202 - 2^2 */ square(t1,t0); - /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { square(t0,t1); square(t1,t0); } - /* 2^250 - 2^0 */ mult(t0,t1,z2_50_0); - - /* 2^251 - 2^1 */ square(t1,t0); - /* 2^252 - 2^2 */ square(t0,t1); - /* 2^253 - 2^3 */ square(t1,t0); - /* 2^254 - 2^4 */ square(t0,t1); - /* 2^255 - 2^5 */ square(t1,t0); - /* 2^255 - 21 */ mult(out,t1,z11); -} - -int crypto_scalarmult_curve25519(unsigned char *q, - const unsigned char *n, - const unsigned char *p) -{ - unsigned int work[96]; - unsigned char e[32]; - unsigned int i; - for (i = 0;i < 32;++i) e[i] = n[i]; - e[0] &= 248; - e[31] &= 127; - e[31] |= 64; - for (i = 0;i < 32;++i) work[i] = p[i]; - mainloop(work,e); - recip(work + 32,work + 32); - mult(work + 64,work,work + 32); - freeze(work + 64); - for (i = 0;i < 32;++i) q[i] = work[64 + i]; - return 0; -} diff --git a/iked/timer.c b/iked/timer.c index 01341cb..150673b 100644 --- a/iked/timer.c +++ b/iked/timer.c @@ -1,4 +1,4 @@ -/* $OpenBSD: timer.c,v 1.12 2015/01/16 06:39:58 deraadt Exp $ */ +/* $OpenBSD: timer.c,v 1.10 2013/01/08 10:38:19 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,7 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +#include +#include "openbsd-compat/sys-queue.h" #include #include @@ -34,7 +35,7 @@ void timer_callback(int, short, void *); void -timer_set(struct iked *env, struct iked_timer *tmr, +timer_initialize(struct iked *env, struct iked_timer *tmr, void (*cb)(struct iked *, void *), void *arg) { tmr->tmr_env = env; @@ -43,8 +44,17 @@ timer_set(struct iked *env, struct iked_timer *tmr, evtimer_set(&tmr->tmr_ev, timer_callback, tmr); } +int +timer_initialized(struct iked *env, struct iked_timer *tmr) +{ + if (tmr && tmr->tmr_env == env && tmr->tmr_cb && + evtimer_initialized(&tmr->tmr_ev)) + return (1); + return (0); +} + void -timer_add(struct iked *env, struct iked_timer *tmr, int timeout) +timer_register(struct iked *env, struct iked_timer *tmr, int timeout) { struct timeval tv = { timeout }; @@ -56,11 +66,9 @@ timer_add(struct iked *env, struct iked_timer *tmr, int timeout) } void -timer_del(struct iked *env, struct iked_timer *tmr) +timer_deregister(struct iked *env, struct iked_timer *tmr) { - if (tmr->tmr_env == env && tmr->tmr_cb && - evtimer_initialized(&tmr->tmr_ev)) - evtimer_del(&tmr->tmr_ev); + evtimer_del(&tmr->tmr_ev); } void diff --git a/iked/types.h b/iked/types.h index 476e845..d0de6e5 100644 --- a/iked/types.h +++ b/iked/types.h @@ -1,4 +1,4 @@ -/* $OpenBSD: types.h,v 1.21 2015/08/21 11:59:28 reyk Exp $ */ +/* $OpenBSD: types.h,v 1.17 2013/01/08 10:38:19 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -16,32 +16,27 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef IKED_TYPES_H -#define IKED_TYPES_H +#ifndef _IKED_TYPES_H +#define _IKED_TYPES_H #ifndef IKED_USER -#define IKED_USER "_iked" +#define IKED_USER "_iked" #endif #ifndef IKED_CONFIG -#define IKED_CONFIG "/etc/iked.conf" +#define IKED_CONFIG "/etc/iked.conf" #endif - -#define IKED_SOCKET "/var/run/iked.sock" +#define IKED_SOCKET "/var/run/iked.sock" #ifndef IKED_CA -#define IKED_CA "/etc/iked/" +#define IKED_CA "/etc/iked/" #endif - -#define IKED_CA_DIR "ca/" -#define IKED_CRL_DIR "crls/" -#define IKED_CERT_DIR "certs/" -#define IKED_PUBKEY_DIR "pubkeys/" -#define IKED_PRIVKEY IKED_CA "private/local.key" -#define IKED_PUBKEY "local.pub" - -#define IKED_OCSP_RESPCERT "ocsp/responder.crt" -#define IKED_OCSP_ISSUER "ocsp/issuer.crt" +#define IKED_CA_DIR "ca/" +#define IKED_CRL_DIR "crls/" +#define IKED_CERT_DIR "certs/" +#define IKED_PUBKEY_DIR "pubkeys/" +#define IKED_PRIVKEY IKED_CA "private/local.key" +#define IKED_PUBKEY "local.pub" #define IKED_OPT_VERBOSE 0x00000001 #define IKED_OPT_NOACTION 0x00000002 @@ -70,17 +65,17 @@ #define IKED_E 0x1000 /* Decrypted flag */ struct iked_constmap { - unsigned int cm_type; + u_int cm_type; const char *cm_name; const char *cm_descr; }; struct iked_transform { - uint8_t xform_type; - uint16_t xform_id; - uint16_t xform_length; - uint16_t xform_keylength; - unsigned int xform_score; + u_int8_t xform_type; + u_int16_t xform_id; + u_int16_t xform_length; + u_int16_t xform_keylength; + u_int xform_score; struct iked_constmap *xform_map; }; @@ -106,8 +101,6 @@ enum imsg_type { IMSG_CERT, IMSG_CERTVALID, IMSG_CERTINVALID, - IMSG_OCSP_FD, - IMSG_OCSP_URL, IMSG_AUTH }; @@ -140,4 +133,4 @@ enum flushmode { #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif -#endif /* IKED_TYPES_H */ +#endif /* _IKED_TYPES_H */ diff --git a/iked/util.c b/iked/util.c index 7b108de..5b0f013 100644 --- a/iked/util.c +++ b/iked/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.27 2015/08/21 11:59:28 reyk Exp $ */ +/* $OpenBSD: util.c,v 1.18 2013/01/08 10:38:19 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -17,17 +17,23 @@ */ #include -#include +#include "openbsd-compat/sys-queue.h" #include #include +#include +#include +#include +#include +#include +#include #include + #include #include #include #include #include -#include #include #include #include @@ -59,13 +65,17 @@ socket_af(struct sockaddr *sa, in_port_t port) switch (sa->sa_family) { case AF_INET: ((struct sockaddr_in *)sa)->sin_port = port; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN ((struct sockaddr_in *)sa)->sin_len = sizeof(struct sockaddr_in); +#endif break; case AF_INET6: ((struct sockaddr_in6 *)sa)->sin6_port = port; +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN ((struct sockaddr_in6 *)sa)->sin6_len = sizeof(struct sockaddr_in6); +#endif break; default: errno = EPFNOSUPPORT; @@ -76,13 +86,13 @@ socket_af(struct sockaddr *sa, in_port_t port) } in_port_t -socket_getport(struct sockaddr *sa) +socket_getport(struct sockaddr_storage *ss) { - switch (sa->sa_family) { + switch (ss->ss_family) { case AF_INET: - return (ntohs(((struct sockaddr_in *)sa)->sin_port)); + return (ntohs(((struct sockaddr_in *)ss)->sin_port)); case AF_INET6: - return (ntohs(((struct sockaddr_in6 *)sa)->sin6_port)); + return (ntohs(((struct sockaddr_in6 *)ss)->sin6_port)); default: return (0); } @@ -91,22 +101,6 @@ socket_getport(struct sockaddr *sa) return (0); } -int -socket_setport(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; - default: - return (-1); - } - return (0); -} - int socket_getaddr(int s, struct sockaddr_storage *ss) { @@ -118,6 +112,7 @@ socket_getaddr(int s, struct sockaddr_storage *ss) int socket_bypass(int s, struct sockaddr *sa) { +#if defined(__OpenBSD__) int v, *a; int a4[] = { IPPROTO_IP, @@ -169,6 +164,47 @@ socket_bypass(int s, struct sockaddr *sa) return (-1); } #endif +#else /* __OpenBSD__ */ + int *a; + int a4[] = { + IPPROTO_IP, + IP_IPSEC_POLICY + }; + int a6[] = { + IPPROTO_IPV6, + IPV6_IPSEC_POLICY, + + }; + struct sadb_x_policy pol = { + SADB_UPDATE, + SADB_EXT_SENSITIVITY, + IPSEC_POLICY_BYPASS, + 0, 0, 0, 0 + }; + + switch (sa->sa_family) { + case AF_INET: + a = a4; + break; + case AF_INET6: + a = a6; + break; + default: + log_warn("%s: invalid address family", __func__); + return (-1); + } + + pol.sadb_x_policy_dir = IPSEC_DIR_INBOUND; + if (setsockopt(s, a[0], a[1], &pol, sizeof(pol)) == -1) { + log_warn("%s: IPSEC_DIR_INBOUND", __func__); + return (-1); + } + pol.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND; + if (setsockopt(s, a[0], a[1], &pol, sizeof(pol)) == -1) { + log_warn("%s: IPSEC_DIR_OUTBOUND", __func__); + return (-1); + } +#endif /* !__OpenBSD__ */ return (0); } @@ -195,26 +231,46 @@ udp_bind(struct sockaddr *sa, in_port_t port) goto bad; } +#ifdef SO_REUSEPORT val = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(int)) == -1) { log_warn("%s: failed to set reuseport", __func__); goto bad; } +#endif +#ifdef SO_REUSEADDR val = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int)) == -1) { log_warn("%s: failed to set reuseaddr", __func__); goto bad; } +#endif if (sa->sa_family == AF_INET) { val = 1; - if (setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, + if (setsockopt(s, IPPROTO_IP, +#if defined(IP_RECVDSTADDR) + IP_RECVDSTADDR, +#elif defined(IP_PKTINFO) + IP_PKTINFO, +#else +#error IPv4 packet info not supported +#endif &val, sizeof(int)) == -1) { log_warn("%s: failed to set IPv4 packet info", __func__); goto bad; } } else { +#ifdef IPV6_V6ONLY + val = 1; + if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, + &val, sizeof(int)) == -1) { + log_warn("%s: failed to set IPv6-only mode", + __func__); + goto bad; + } +#endif val = 1; if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(int)) == -1) { @@ -224,7 +280,7 @@ udp_bind(struct sockaddr *sa, in_port_t port) } } - if (bind(s, sa, sa->sa_len) == -1) { + if (bind(s, sa, SA_LEN(sa)) == -1) { log_warn("%s: failed to bind UDP socket", __func__); goto bad; } @@ -240,7 +296,7 @@ sockaddr_cmp(struct sockaddr *a, struct sockaddr *b, int prefixlen) { struct sockaddr_in *a4, *b4; struct sockaddr_in6 *a6, *b6; - uint32_t av[4], bv[4], mv[4]; + u_int32_t av[4], bv[4], mv[4]; if (a->sa_family == AF_UNSPEC || b->sa_family == AF_UNSPEC) return (0); @@ -313,6 +369,9 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, struct cmsghdr hdr; char buf[CMSG_SPACE(sizeof(struct sockaddr_storage))]; } cmsgbuf; +#if !defined(IP_RECVDSTADDR) && defined(IP_PKTINFO) + struct in_pktinfo *pkt; +#endif bzero(&msg, sizeof(msg)); bzero(&cmsgbuf.buf, sizeof(cmsgbuf.buf)); @@ -329,7 +388,7 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, if ((ret = recvmsg(s, &msg, 0)) == -1) return (-1); - *fromlen = from->sa_len; + *fromlen = SA_LEN(from); *tolen = 0; if (getsockname(s, to, tolen) != 0) @@ -339,6 +398,7 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, cmsg = CMSG_NXTHDR(&msg, cmsg)) { switch (from->sa_family) { case AF_INET: +#if defined(IP_RECVDSTADDR) if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) { in = (struct sockaddr_in *)to; @@ -347,13 +407,32 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, memcpy(&in->sin_addr, CMSG_DATA(cmsg), sizeof(struct in_addr)); } +#elif defined(IP_PKTINFO) + if (cmsg->cmsg_level == IPPROTO_IP && + cmsg->cmsg_type == IP_PKTINFO) { + in = (struct sockaddr_in *)to; + in->sin_family = AF_INET; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + in->sin_len = *tolen = sizeof(*in); +#else + *tolen = sizeof(*in); +#endif + pkt = (struct in_pktinfo *)CMSG_DATA(cmsg); + memcpy(&in->sin_addr, &pkt->ipi_addr, + sizeof(struct in_addr)); + } +#endif break; case AF_INET6: if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) { in6 = (struct sockaddr_in6 *)to; in6->sin6_family = AF_INET6; +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN in6->sin6_len = *tolen = sizeof(*in6); +#else + *tolen = sizeof(*in6); +#endif pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg); memcpy(&in6->sin6_addr, &pkt6->ipi6_addr, sizeof(struct in6_addr)); @@ -369,7 +448,7 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, } const char * -print_spi(uint64_t spi, int size) +print_spi(u_int64_t spi, int size) { static char buf[IKED_CYCLE_BUFFERS][32]; static int i = 0; @@ -378,11 +457,8 @@ print_spi(uint64_t spi, int size) ptr = buf[i]; switch (size) { - case 2: - snprintf(ptr, 32, "0x%04x", (uint16_t)spi); - break; case 4: - snprintf(ptr, 32, "0x%08x", (uint32_t)spi); + snprintf(ptr, 32, "0x%08x", (u_int32_t)spi); break; case 8: snprintf(ptr, 32, "0x%016llx", spi); @@ -399,9 +475,9 @@ print_spi(uint64_t spi, int size) } const char * -print_map(unsigned int type, struct iked_constmap *map) +print_map(u_int type, struct iked_constmap *map) { - unsigned int i; + u_int i; static char buf[IKED_CYCLE_BUFFERS][32]; static int idx = 0; const char *name = NULL; @@ -427,16 +503,16 @@ void lc_string(char *str) { for (; *str != '\0'; str++) - *str = tolower((unsigned char)*str); + *str = tolower(*str); } void -print_hex(uint8_t *buf, off_t offset, size_t length) +print_hex(u_int8_t *buf, off_t offset, size_t length) { - unsigned int i; + u_int i; extern int verbose; - if (verbose < 3 || !length) + if (verbose < 2 || !length) return; for (i = 0; i < length; i++) { @@ -452,9 +528,9 @@ print_hex(uint8_t *buf, off_t offset, size_t length) } void -print_hexval(uint8_t *buf, off_t offset, size_t length) +print_hexval(u_int8_t *buf, off_t offset, size_t length) { - unsigned int i; + u_int i; extern int verbose; if (verbose < 2 || !length) @@ -467,12 +543,12 @@ print_hexval(uint8_t *buf, off_t offset, size_t length) } const char * -print_bits(unsigned short v, unsigned char *bits) +print_bits(u_short v, char *bits) { static char buf[IKED_CYCLE_BUFFERS][BUFSIZ]; static int idx = 0; - unsigned int i, any = 0, j = 0; - unsigned char c; + u_int i, any = 0, j = 0; + char c; if (!bits) return (""); @@ -492,7 +568,7 @@ print_bits(unsigned short v, unsigned char *bits) } any = 1; for (; (c = *bits) > 32; bits++) { - buf[idx][j++] = tolower((unsigned char)c); + buf[idx][j++] = tolower(c); if (j >= sizeof(buf[idx])) return (buf[idx]); } @@ -504,7 +580,7 @@ print_bits(unsigned short v, unsigned char *bits) return (buf[idx]); } -uint8_t +u_int8_t mask2prefixlen(struct sockaddr *sa) { struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; @@ -516,18 +592,18 @@ mask2prefixlen(struct sockaddr *sa) return (33 - ffs(ntohl(ina))); } -uint8_t +u_int8_t mask2prefixlen6(struct sockaddr *sa) { struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; - uint8_t l = 0, *ap, *ep; + u_int8_t l = 0, *ap, *ep; /* * sin6_len is the size of the sockaddr so substract the offset of * the possibly truncated sin6_addr struct. */ - ap = (uint8_t *)&sa_in6->sin6_addr; - ep = (uint8_t *)sa_in6 + sa_in6->sin6_len; + ap = (u_int8_t *)&sa_in6->sin6_addr; + ep = (u_int8_t *)sa_in6 + SA_LEN(sa); for (; ap < ep; ap++) { /* this "beauty" is adopted from sbin/route/show.c ... */ switch (*ap) { @@ -565,8 +641,8 @@ mask2prefixlen6(struct sockaddr *sa) return (l); } -uint32_t -prefixlen2mask(uint8_t prefixlen) +u_int32_t +prefixlen2mask(u_int8_t prefixlen) { if (prefixlen == 0) return (0); @@ -578,7 +654,7 @@ prefixlen2mask(uint8_t prefixlen) } struct in6_addr * -prefixlen2mask6(uint8_t prefixlen, uint32_t *mask) +prefixlen2mask6(u_int8_t prefixlen, u_int32_t *mask) { static struct in6_addr s6; int i; @@ -599,7 +675,7 @@ prefixlen2mask6(uint8_t prefixlen, uint32_t *mask) } const char * -print_host(struct sockaddr *sa, char *buf, size_t len) +print_host(struct sockaddr_storage *ss, char *buf, size_t len) { static char sbuf[IKED_CYCLE_BUFFERS][NI_MAXHOST + 7]; static int idx = 0; @@ -613,18 +689,18 @@ print_host(struct sockaddr *sa, char *buf, size_t len) idx = 0; } - if (sa->sa_family == AF_UNSPEC) { + if (ss->ss_family == AF_UNSPEC) { strlcpy(buf, "any", len); return (buf); } - if (getnameinfo(sa, sa->sa_len, + if (getnameinfo((struct sockaddr *)ss, SS_LEN(ss), buf, len, NULL, 0, NI_NUMERICHOST) != 0) { buf[0] = '\0'; return (NULL); } - if ((port = socket_getport(sa)) != 0) { + if ((port = socket_getport(ss)) != 0) { snprintf(pbuf, sizeof(pbuf), ":%d", port); (void)strlcat(buf, pbuf, len); } @@ -633,13 +709,13 @@ print_host(struct sockaddr *sa, char *buf, size_t len) } char * -get_string(uint8_t *ptr, size_t len) +get_string(u_int8_t *ptr, size_t len) { size_t i; char *str; for (i = 0; i < len; i++) - if (!isprint(ptr[i])) + if (!isprint((char)ptr[i])) break; if ((str = calloc(1, i + 1)) == NULL) @@ -650,7 +726,7 @@ get_string(uint8_t *ptr, size_t len) } const char * -print_proto(uint8_t proto) +print_proto(u_int8_t proto) { struct protoent *p; static char buf[IKED_CYCLE_BUFFERS][BUFSIZ]; @@ -701,10 +777,10 @@ expand_string(char *label, size_t len, const char *srch, const char *repl) return (0); } -uint8_t * +u_int8_t * string2unicode(const char *ascii, size_t *outlen) { - uint8_t *uc = NULL; + u_int8_t *uc = NULL; size_t i, len = strlen(ascii); if ((uc = calloc(1, (len * 2) + 2)) == NULL) diff --git a/mdoc2man.awk b/mdoc2man.awk new file mode 100644 index 0000000..80e8d5f --- /dev/null +++ b/mdoc2man.awk @@ -0,0 +1,370 @@ +#!/usr/bin/awk +# +# $Id: mdoc2man.awk,v 1.9 2009/10/24 00:52:42 dtucker Exp $ +# +# Version history: +# v4+ Adapted for OpenSSH Portable (see cvs Id and history) +# v3, I put the program under a proper license +# Dan Nelson added .An, .Aq and fixed a typo +# v2, fixed to work on GNU awk --posix and MacOS X +# v1, first attempt, didn't work on MacOS X +# +# Copyright (c) 2003 Peter Stuge +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +BEGIN { + optlist=0 + oldoptlist=0 + nospace=0 + synopsis=0 + reference=0 + block=0 + ext=0 + extopt=0 + literal=0 + prenl=0 + breakw=0 + line="" +} + +function wtail() { + retval="" + while(w0;i--) { + add(refauthors[i]) + if(i>1) + add(", ") + } + if(nrefauthors>1) + add(" and ") + if(nrefauthors>0) + add(refauthors[0] ", ") + add("\\fI" reftitle "\\fP") + if(length(refissue)) + add(", " refissue) + if(length(refreport)) { + add(", " refreport) + } + if(length(refdate)) + add(", " refdate) + if(length(refopt)) + add(", " refopt) + add(".") + reference=0 + } else if(reference) { + if(match(words[w],"^%A$")) { refauthors[nrefauthors++]=wtail() } + if(match(words[w],"^%T$")) { + reftitle=wtail() + sub("^\"","",reftitle) + sub("\"$","",reftitle) + } + if(match(words[w],"^%N$")) { refissue=wtail() } + if(match(words[w],"^%D$")) { refdate=wtail() } + if(match(words[w],"^%O$")) { refopt=wtail() } + if(match(words[w],"^%R$")) { refreport=wtail() } + } else if(match(words[w],"^Nm$")) { + if(synopsis) { + add(".br") + prenl++ + } + n=words[++w] + if(!length(name)) + name=n + if(!length(n)) + n=name + add("\\fB" n "\\fP") + if(!nospace&&match(words[w+1],"^[\\.,]")) + nospace=1 + } else if(match(words[w],"^Nd$")) { + add("\\- " wtail()) + } else if(match(words[w],"^Fl$")) { + add("\\fB\\-" words[++w] "\\fP") + if(!nospace&&match(words[w+1],"^[\\.,]")) + nospace=1 + } else if(match(words[w],"^Ar$")) { + add("\\fI") + if(w==nwords) + add("file ...\\fP") + else { + add(words[++w] "\\fP") + while(match(words[w+1],"^\\|$")) + add(OFS words[++w] " \\fI" words[++w] "\\fP") + } + if(!nospace&&match(words[w+1],"^[\\.,]")) + nospace=1 + } else if(match(words[w],"^Cm$")) { + add("\\fB" words[++w] "\\fP") + while(w") + if(option) + add("]") + if(ext&&!extopt&&!match(line," $")) + add(OFS) + if(!ext&&!extopt&&length(line)) { + print line + prenl=0 + line="" + } +} diff --git a/openbsd-compat/Makefile.am b/openbsd-compat/Makefile.am new file mode 100644 index 0000000..80b5eba --- /dev/null +++ b/openbsd-compat/Makefile.am @@ -0,0 +1,14 @@ +noinst_LIBRARIES= libopenbsd-compat.a + +libopenbsd_compat_a_SOURCES= \ + bsd-arc4random.c bsd-closefrom.c \ + daemon.c entropy.c fgetln.c getopt.c imsg.c imsg-buffer.c \ + setresguid.c setproctitle.c \ + strlcat.c strlcpy.c strtonum.c vis.c + +EXTRA_DIST= defines.h imsg.h includes.h \ + openbsd-compat.h sys-queue.h sys-tree.h vis.h + +CPPFLAGS= -include $(top_srcdir)/openbsd-compat/includes.h \ + -I$(top_srcdir) -I$(top_srcdir)/openbsd-compat \ + @CPPFLAGS@ @DEFS@ diff --git a/openbsd-compat/bsd-arc4random.c b/openbsd-compat/bsd-arc4random.c new file mode 100644 index 0000000..a7e562b --- /dev/null +++ b/openbsd-compat/bsd-arc4random.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 1996, David Mazieres + * Copyright (c) 2008, Damien Miller + * Copyright (c) 2013, Markus Friedl + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * ChaCha based random number generator for OpenBSD. + */ + +#include "includes.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define KEYSTREAM_ONLY +#include "chacha_private.h" + +#ifdef __GNUC__ +#define inline __inline +#else /* !__GNUC__ */ +#define inline +#endif /* !__GNUC__ */ + +#define KEYSZ 32 +#define IVSZ 8 +#define BLOCKSZ 64 +#define RSBUFSZ (16*BLOCKSZ) +static int rs_initialized; +static pid_t rs_stir_pid; +static chacha_ctx rs; /* chacha context for random keystream */ +static u_char rs_buf[RSBUFSZ]; /* keystream blocks */ +static size_t rs_have; /* valid bytes at end of rs_buf */ +static size_t rs_count; /* bytes till reseed */ + +static inline void _rs_rekey(u_char *dat, size_t datlen); +static inline void _rs_random_buf(void *_buf, size_t n); + +static inline void +_rs_init(u_char *buf, size_t n) +{ + if (n < KEYSZ + IVSZ) + return; + chacha_keysetup(&rs, buf, KEYSZ * 8, 0); + chacha_ivsetup(&rs, buf + KEYSZ); +} + +static void +_rs_stir(void) +{ + size_t len; + u_char rnd[KEYSZ + IVSZ]; + + len = sizeof(rnd); + + _rs_random_buf(rnd, len); + if (!rs_initialized) { + rs_initialized = 1; + _rs_init(rnd, sizeof(rnd)); + } else + _rs_rekey(rnd, sizeof(rnd)); + memset(rnd, 0, sizeof(rnd)); + + /* invalidate rs_buf */ + rs_have = 0; + memset(rs_buf, 0, RSBUFSZ); + + rs_count = 1600000; +} + +static inline void +_rs_stir_if_needed(size_t len) +{ + pid_t pid = getpid(); + + if (rs_count <= len || !rs_initialized || rs_stir_pid != pid) { + rs_stir_pid = pid; + _rs_stir(); + } else + rs_count -= len; +} + +static inline void +_rs_rekey(u_char *dat, size_t datlen) +{ +#ifndef KEYSTREAM_ONLY + memset(rs_buf, 0,RSBUFSZ); +#endif + /* fill rs_buf with the keystream */ + chacha_encrypt_bytes(&rs, rs_buf, rs_buf, RSBUFSZ); + /* mix in optional user provided data */ + if (dat) { + size_t i, m; + + m = MIN(datlen, KEYSZ + IVSZ); + for (i = 0; i < m; i++) + rs_buf[i] ^= dat[i]; + } + /* immediately reinit for backtracking resistance */ + _rs_init(rs_buf, KEYSZ + IVSZ); + memset(rs_buf, 0, KEYSZ + IVSZ); + rs_have = RSBUFSZ - KEYSZ - IVSZ; +} + +static inline void +_rs_random_buf(void *_buf, size_t n) +{ + u_char *buf = (u_char *)_buf; + size_t m; + + while (n > 0) { + if (rs_have > 0) { + m = MIN(n, rs_have); + memcpy(buf, rs_buf + RSBUFSZ - rs_have, m); + memset(rs_buf + RSBUFSZ - rs_have, 0, m); + buf += m; + n -= m; + rs_have -= m; + } + if (rs_have == 0) + _rs_rekey(NULL, 0); + } +} + +static inline void +_rs_random_u32(u_int32_t *val) +{ + _rs_stir_if_needed(sizeof(*val)); + if (rs_have < sizeof(*val)) + _rs_rekey(NULL, 0); + memcpy(val, rs_buf + RSBUFSZ - rs_have, sizeof(*val)); + memset(rs_buf + RSBUFSZ - rs_have, 0, sizeof(*val)); + rs_have -= sizeof(*val); + return; +} + +#ifndef HAVE_ARC4RANDOM +void +arc4random_stir(void) +{ + _rs_stir(); +} + +void +arc4random_addrandom(u_char *dat, int datlen) +{ + int m; + + if (!rs_initialized) + _rs_stir(); + while (datlen > 0) { + m = MIN(datlen, KEYSZ + IVSZ); + _rs_rekey(dat, m); + dat += m; + datlen -= m; + } +} + +u_int32_t +arc4random(void) +{ + u_int32_t val; + + _rs_random_u32(&val); + return val; +} +#endif /* !HAVE_ARC4RANDOM */ + +#ifndef HAVE_ARC4RANDOM_BUF +void +arc4random_buf(void *buf, size_t n) +{ + _rs_stir_if_needed(n); + _rs_random_buf(buf, n); +} +#endif /* !HAVE_ARC4RANDOM_BUF */ + +#ifndef HAVE_ARC4RANDOM_UNIFORM +/* + * Calculate a uniformly distributed random number less than upper_bound + * avoiding "modulo bias". + * + * Uniformity is achieved by generating new random numbers until the one + * returned is outside the range [0, 2**32 % upper_bound). This + * guarantees the selected random number will be inside + * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) + * after reduction modulo upper_bound. + */ +u_int32_t +arc4random_uniform(u_int32_t upper_bound) +{ + u_int32_t r, min; + + if (upper_bound < 2) + return 0; + + /* 2**32 % x == (2**32 - x) % x */ + min = -upper_bound % upper_bound; + + /* + * This could theoretically loop forever but each retry has + * p > 0.5 (worst case, usually far better) of selecting a + * number inside the range we need, so it should rarely need + * to re-roll. + */ + for (;;) { + r = arc4random(); + if (r >= min) + break; + } + + return r % upper_bound; +} +#endif /* !HAVE_ARC4RANDOM_UNIFORM */ diff --git a/openbsd-compat/bsd-closefrom.c b/openbsd-compat/bsd-closefrom.c new file mode 100644 index 0000000..8598970 --- /dev/null +++ b/openbsd-compat/bsd-closefrom.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2004-2005 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#ifndef HAVE_CLOSEFROM + +#include +#include +#include +#include +#ifdef HAVE_FCNTL_H +# include +#endif +#include +#include +#include +#include +#include + +#if 0 +__unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $"; +#endif /* lint */ + +/* + * Close all file descriptors greater than or equal to lowfd. + */ +#ifdef HAVE_FCNTL_CLOSEM +void +closefrom(int lowfd) +{ + (void) fcntl(lowfd, F_CLOSEM, 0); +} +#else +void +closefrom(int lowfd) +{ + long fd, maxfd; +#if defined(HAVE_DIRFD) && defined(HAVE_PROC_PID) + char fdpath[PATH_MAX], *endp; + struct dirent *dent; + DIR *dirp; + int len; + + /* Check for a /proc/$$/fd directory. */ + len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid()); + if (len > 0 && (size_t)len <= sizeof(fdpath) && (dirp = opendir(fdpath))) { + while ((dent = readdir(dirp)) != NULL) { + fd = strtol(dent->d_name, &endp, 10); + if (dent->d_name != endp && *endp == '\0' && + fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp)) + (void) close((int) fd); + } + (void) closedir(dirp); + } else +#endif + { + /* + * Fall back on sysconf() or getdtablesize(). We avoid checking + * resource limits since it is possible to open a file descriptor + * and then drop the rlimit such that it is below the open fd. + */ +#ifdef HAVE_SYSCONF + maxfd = sysconf(_SC_OPEN_MAX); +#else + maxfd = getdtablesize(); +#endif /* HAVE_SYSCONF */ + if (maxfd < 0) + maxfd = OPEN_MAX; + + for (fd = lowfd; fd < maxfd; fd++) + (void) close((int) fd); + } +} +#endif /* !HAVE_FCNTL_CLOSEM */ +#endif /* HAVE_CLOSEFROM */ diff --git a/openbsd-compat/chacha_private.h b/openbsd-compat/chacha_private.h new file mode 100644 index 0000000..7c3680f --- /dev/null +++ b/openbsd-compat/chacha_private.h @@ -0,0 +1,222 @@ +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +/* $OpenBSD: chacha_private.h,v 1.2 2013/10/04 07:02:27 djm Exp $ */ + +typedef unsigned char u8; +typedef unsigned int u32; + +typedef struct +{ + u32 input[16]; /* could be compressed */ +} chacha_ctx; + +#define U8C(v) (v##U) +#define U32C(v) (v##U) + +#define U8V(v) ((u8)(v) & U8C(0xFF)) +#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) + +#define ROTL32(v, n) \ + (U32V((v) << (n)) | ((v) >> (32 - (n)))) + +#define U8TO32_LITTLE(p) \ + (((u32)((p)[0]) ) | \ + ((u32)((p)[1]) << 8) | \ + ((u32)((p)[2]) << 16) | \ + ((u32)((p)[3]) << 24)) + +#define U32TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + } while (0) + +#define ROTATE(v,c) (ROTL32(v,c)) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +#define QUARTERROUND(a,b,c,d) \ + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + +static const char sigma[16] = "expand 32-byte k"; +static const char tau[16] = "expand 16-byte k"; + +static void +chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ivbits) +{ + const char *constants; + + x->input[4] = U8TO32_LITTLE(k + 0); + x->input[5] = U8TO32_LITTLE(k + 4); + x->input[6] = U8TO32_LITTLE(k + 8); + x->input[7] = U8TO32_LITTLE(k + 12); + if (kbits == 256) { /* recommended */ + k += 16; + constants = sigma; + } else { /* kbits == 128 */ + constants = tau; + } + x->input[8] = U8TO32_LITTLE(k + 0); + x->input[9] = U8TO32_LITTLE(k + 4); + x->input[10] = U8TO32_LITTLE(k + 8); + x->input[11] = U8TO32_LITTLE(k + 12); + x->input[0] = U8TO32_LITTLE(constants + 0); + x->input[1] = U8TO32_LITTLE(constants + 4); + x->input[2] = U8TO32_LITTLE(constants + 8); + x->input[3] = U8TO32_LITTLE(constants + 12); +} + +static void +chacha_ivsetup(chacha_ctx *x,const u8 *iv) +{ + x->input[12] = 0; + x->input[13] = 0; + x->input[14] = U8TO32_LITTLE(iv + 0); + x->input[15] = U8TO32_LITTLE(iv + 4); +} + +static void +chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) +{ + u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + u8 *ctarget = NULL; + u8 tmp[64]; + u_int i; + + if (!bytes) return; + + j0 = x->input[0]; + j1 = x->input[1]; + j2 = x->input[2]; + j3 = x->input[3]; + j4 = x->input[4]; + j5 = x->input[5]; + j6 = x->input[6]; + j7 = x->input[7]; + j8 = x->input[8]; + j9 = x->input[9]; + j10 = x->input[10]; + j11 = x->input[11]; + j12 = x->input[12]; + j13 = x->input[13]; + j14 = x->input[14]; + j15 = x->input[15]; + + for (;;) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) tmp[i] = m[i]; + m = tmp; + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = 20;i > 0;i -= 2) { + QUARTERROUND( x0, x4, x8,x12) + QUARTERROUND( x1, x5, x9,x13) + QUARTERROUND( x2, x6,x10,x14) + QUARTERROUND( x3, x7,x11,x15) + QUARTERROUND( x0, x5,x10,x15) + QUARTERROUND( x1, x6,x11,x12) + QUARTERROUND( x2, x7, x8,x13) + QUARTERROUND( x3, x4, x9,x14) + } + x0 = PLUS(x0,j0); + x1 = PLUS(x1,j1); + x2 = PLUS(x2,j2); + x3 = PLUS(x3,j3); + x4 = PLUS(x4,j4); + x5 = PLUS(x5,j5); + x6 = PLUS(x6,j6); + x7 = PLUS(x7,j7); + x8 = PLUS(x8,j8); + x9 = PLUS(x9,j9); + x10 = PLUS(x10,j10); + x11 = PLUS(x11,j11); + x12 = PLUS(x12,j12); + x13 = PLUS(x13,j13); + x14 = PLUS(x14,j14); + x15 = PLUS(x15,j15); + +#ifndef KEYSTREAM_ONLY + x0 = XOR(x0,U8TO32_LITTLE(m + 0)); + x1 = XOR(x1,U8TO32_LITTLE(m + 4)); + x2 = XOR(x2,U8TO32_LITTLE(m + 8)); + x3 = XOR(x3,U8TO32_LITTLE(m + 12)); + x4 = XOR(x4,U8TO32_LITTLE(m + 16)); + x5 = XOR(x5,U8TO32_LITTLE(m + 20)); + x6 = XOR(x6,U8TO32_LITTLE(m + 24)); + x7 = XOR(x7,U8TO32_LITTLE(m + 28)); + x8 = XOR(x8,U8TO32_LITTLE(m + 32)); + x9 = XOR(x9,U8TO32_LITTLE(m + 36)); + x10 = XOR(x10,U8TO32_LITTLE(m + 40)); + x11 = XOR(x11,U8TO32_LITTLE(m + 44)); + x12 = XOR(x12,U8TO32_LITTLE(m + 48)); + x13 = XOR(x13,U8TO32_LITTLE(m + 52)); + x14 = XOR(x14,U8TO32_LITTLE(m + 56)); + x15 = XOR(x15,U8TO32_LITTLE(m + 60)); +#endif + + j12 = PLUSONE(j12); + if (!j12) { + j13 = PLUSONE(j13); + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } + + U32TO8_LITTLE(c + 0,x0); + U32TO8_LITTLE(c + 4,x1); + U32TO8_LITTLE(c + 8,x2); + U32TO8_LITTLE(c + 12,x3); + U32TO8_LITTLE(c + 16,x4); + U32TO8_LITTLE(c + 20,x5); + U32TO8_LITTLE(c + 24,x6); + U32TO8_LITTLE(c + 28,x7); + U32TO8_LITTLE(c + 32,x8); + U32TO8_LITTLE(c + 36,x9); + U32TO8_LITTLE(c + 40,x10); + U32TO8_LITTLE(c + 44,x11); + U32TO8_LITTLE(c + 48,x12); + U32TO8_LITTLE(c + 52,x13); + U32TO8_LITTLE(c + 56,x14); + U32TO8_LITTLE(c + 60,x15); + + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) ctarget[i] = c[i]; + } + x->input[12] = j12; + x->input[13] = j13; + return; + } + bytes -= 64; + c += 64; +#ifndef KEYSTREAM_ONLY + m += 64; +#endif + } +} diff --git a/openbsd-compat/daemon.c b/openbsd-compat/daemon.c new file mode 100644 index 0000000..3efe14c --- /dev/null +++ b/openbsd-compat/daemon.c @@ -0,0 +1,82 @@ +/* $OpenBSD: daemon.c,v 1.6 2005/08/08 08:05:33 espie Exp $ */ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* OPENBSD ORIGINAL: lib/libc/gen/daemon.c */ + +#include "includes.h" + +#ifndef HAVE_DAEMON + +#include + +#ifdef HAVE_SYS_STAT_H +# include +#endif + +#ifdef HAVE_FCNTL_H +# include +#endif + +#ifdef HAVE_UNISTD_H +# include +#endif + +int +daemon(int nochdir, int noclose) +{ + int fd; + + switch (fork()) { + case -1: + return (-1); + case 0: + break; + default: + _exit(0); + } + + if (setsid() == -1) + return (-1); + + if (!nochdir) + (void)chdir("/"); + + if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { + (void)dup2(fd, STDIN_FILENO); + (void)dup2(fd, STDOUT_FILENO); + (void)dup2(fd, STDERR_FILENO); + if (fd > 2) + (void)close (fd); + } + return (0); +} + +#endif /* !HAVE_DAEMON */ + diff --git a/openbsd-compat/defines.h b/openbsd-compat/defines.h new file mode 100644 index 0000000..fa9dbdf --- /dev/null +++ b/openbsd-compat/defines.h @@ -0,0 +1,881 @@ +/* + * Copyright (c) 2012 Reyk Floeter + * Copyright (c) 1999-2003 Damien Miller. 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. + */ + +#ifndef _DEFINES_H +#define _DEFINES_H + +/* $Id: defines.h,v 1.145 2007/09/26 21:03:20 dtucker Exp $ */ + + +/* Constants */ + +#define YYSTYPE_IS_DECLARED 1 + +#if defined(HAVE_DECL_SHUT_RD) && HAVE_DECL_SHUT_RD == 0 +enum +{ + SHUT_RD = 0, /* No more receptions. */ + SHUT_WR, /* No more transmissions. */ + SHUT_RDWR /* No more receptions or transmissions. */ +}; +# define SHUT_RD SHUT_RD +# define SHUT_WR SHUT_WR +# define SHUT_RDWR SHUT_RDWR +#endif + +#ifndef IPTOS_LOWDELAY +# define IPTOS_LOWDELAY 0x10 +# define IPTOS_THROUGHPUT 0x08 +# define IPTOS_RELIABILITY 0x04 +# define IPTOS_LOWCOST 0x02 +# define IPTOS_MINCOST IPTOS_LOWCOST +#endif /* IPTOS_LOWDELAY */ + +#if !defined(HAVE_NETINET_IP_IPSP_H) && (defined(HAVE_NETINET6_IPSEC_H) || \ + defined(HAVE_NETIPSEC_IPSEC_H) || defined(HAVE_LINUX_IPSEC_H)) +#define IPSP_DIRECTION_IN IPSEC_DIR_INBOUND +#define IPSP_DIRECTION_OUT IPSEC_DIR_OUTBOUND /* XXX Linux: _FWD? */ +#endif + +#if defined(HAVE_NET_PFKEYV2_H) || defined(HAVE_LINUX_PFKEYV2_H) +#if !defined(SADB_X_ADDFLOW) && defined(SADB_X_SPDADD) +#define SADB_X_ADDFLOW SADB_X_SPDADD +#endif +#if !defined(SADB_X_DELFLOW) && defined(SADB_X_SPDDELETE) +#define SADB_X_DELFLOW SADB_X_SPDDELETE +#endif +#if !defined(SADB_X_FLOW_TYPE_DENY) +#define SADB_X_FLOW_TYPE_DENY 1 +#endif +#endif /* HAVE_NET_PFKEYV2_H || HAVE_LINUX_PFKEYV2_H */ + +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 64 +#endif + +#ifndef LOGIN_NAME_MAX +# define LOGIN_NAME_MAX 9 +#endif + +#ifndef PATH_MAX +# ifdef _POSIX_PATH_MAX +# define PATH_MAX _POSIX_PATH_MAX +# else +# define PATH_MAX 64 +# endif +#endif + +/* + * Looks like ugly, but MAX_IMSGSIZE equals 16384, + * and if we don't care it will overflow for some struct + */ +#if PATH_MAX > 1024 +# undef PATH_MAX +# define PATH_MAX 1024 +#endif + +#ifndef MAXPATHLEN +# define MAXPATHLEN PATH_MAX +#endif + +#if MAXPATHLEN > 1024 +# undef MAXPATHLEN +# define MAXPATHLEN 1024 +#endif + +#if defined(HAVE_DECL_MAXSYMLINKS) && HAVE_DECL_MAXSYMLINKS == 0 +# define MAXSYMLINKS 5 +#endif + +#ifndef MAXLOGNAME +#define MAXLOGNAME LOGIN_NAME_MAX +#endif + +#ifndef STDIN_FILENO +# define STDIN_FILENO 0 +#endif +#ifndef STDOUT_FILENO +# define STDOUT_FILENO 1 +#endif +#ifndef STDERR_FILENO +# define STDERR_FILENO 2 +#endif + +#ifndef NGROUPS_MAX /* Disable groupaccess if NGROUP_MAX is not set */ +#ifdef NGROUPS +#define NGROUPS_MAX NGROUPS +#else +#define NGROUPS_MAX 0 +#endif +#endif + +#if defined(HAVE_DECL_O_NONBLOCK) && HAVE_DECL_O_NONBLOCK == 0 +# define O_NONBLOCK 00004 /* Non Blocking Open */ +#endif + +#ifndef S_ISDIR +# define S_ISDIR(mode) (((mode) & (_S_IFMT)) == (_S_IFDIR)) +#endif /* S_ISDIR */ + +#ifndef S_ISREG +# define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG)) +#endif /* S_ISREG */ + +#ifndef S_ISLNK +# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) +#endif /* S_ISLNK */ + +#ifndef S_IXUSR +# define S_IXUSR 0000100 /* execute/search permission, */ +# define S_IXGRP 0000010 /* execute/search permission, */ +# define S_IXOTH 0000001 /* execute/search permission, */ +# define _S_IWUSR 0000200 /* write permission, */ +# define S_IWUSR _S_IWUSR /* write permission, owner */ +# define S_IWGRP 0000020 /* write permission, group */ +# define S_IWOTH 0000002 /* write permission, other */ +# define S_IRUSR 0000400 /* read permission, owner */ +# define S_IRGRP 0000040 /* read permission, group */ +# define S_IROTH 0000004 /* read permission, other */ +# define S_IRWXU 0000700 /* read, write, execute */ +# define S_IRWXG 0000070 /* read, write, execute */ +# define S_IRWXO 0000007 /* read, write, execute */ +#endif /* S_IXUSR */ + +#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) +#define MAP_ANON MAP_ANONYMOUS +#endif + +#ifndef MAP_FAILED +# define MAP_FAILED ((void *)-1) +#endif + +/* *-*-nto-qnx doesn't define this constant in the system headers */ +#ifdef MISSING_NFDBITS +# define NFDBITS (8 * sizeof(unsigned long)) +#endif + +/* +SCO Open Server 3 has INADDR_LOOPBACK defined in rpc/rpc.h but +including rpc/rpc.h breaks Solaris 6 +*/ +#ifndef INADDR_LOOPBACK +#define INADDR_LOOPBACK ((u_long)0x7f000001) +#endif + +/* Types */ + +/* If sys/types.h does not supply intXX_t, supply them ourselves */ +/* (or die trying) */ + +#ifndef HAVE_U_INT +typedef unsigned int u_int; +#endif + +#ifndef HAVE_INTXX_T +# if (SIZEOF_CHAR == 1) +typedef char int8_t; +# else +# error "8 bit int type not found." +# endif +# if (SIZEOF_SHORT_INT == 2) +typedef short int int16_t; +# else +# ifdef _UNICOS +# if (SIZEOF_SHORT_INT == 4) +typedef short int16_t; +# else +typedef long int16_t; +# endif +# else +# error "16 bit int type not found." +# endif /* _UNICOS */ +# endif +# if (SIZEOF_INT == 4) +typedef int int32_t; +# else +# ifdef _UNICOS +typedef long int32_t; +# else +# error "32 bit int type not found." +# endif /* _UNICOS */ +# endif +#endif + +/* If sys/types.h does not supply u_intXX_t, supply them ourselves */ +#ifndef HAVE_U_INTXX_T +# ifdef HAVE_UINTXX_T +typedef uint8_t u_int8_t; +typedef uint16_t u_int16_t; +typedef uint32_t u_int32_t; +# define HAVE_U_INTXX_T 1 +# else +# if (SIZEOF_CHAR == 1) +typedef unsigned char u_int8_t; +# else +# error "8 bit int type not found." +# endif +# if (SIZEOF_SHORT_INT == 2) +typedef unsigned short int u_int16_t; +# else +# ifdef _UNICOS +# if (SIZEOF_SHORT_INT == 4) +typedef unsigned short u_int16_t; +# else +typedef unsigned long u_int16_t; +# endif +# else +# error "16 bit int type not found." +# endif +# endif +# if (SIZEOF_INT == 4) +typedef unsigned int u_int32_t; +# else +# ifdef _UNICOS +typedef unsigned long u_int32_t; +# else +# error "32 bit int type not found." +# endif +# endif +# endif +#define __BIT_TYPES_DEFINED__ +#endif + +/* 64-bit types */ +#ifndef HAVE_INT64_T +# if (SIZEOF_LONG_INT == 8) +typedef long int int64_t; +# else +# if (SIZEOF_LONG_LONG_INT == 8) +typedef long long int int64_t; +# endif +# endif +#endif +#ifndef HAVE_U_INT64_T +# if (SIZEOF_LONG_INT == 8) +typedef unsigned long int u_int64_t; +# else +# if (SIZEOF_LONG_LONG_INT == 8) +typedef unsigned long long int u_int64_t; +# endif +# endif +#endif + +#ifndef HAVE_U_CHAR +typedef unsigned char u_char; +# define HAVE_U_CHAR +#endif /* HAVE_U_CHAR */ + +#ifndef SIZE_T_MAX +#define SIZE_T_MAX ULONG_MAX +#endif /* SIZE_T_MAX */ + +#ifndef HAVE_SIZE_T +typedef unsigned int size_t; +# define HAVE_SIZE_T +# define SIZE_T_MAX UINT_MAX +#endif /* HAVE_SIZE_T */ + +#ifndef HAVE_SSIZE_T +typedef int ssize_t; +# define HAVE_SSIZE_T +#endif /* HAVE_SSIZE_T */ + +#ifndef HAVE_CLOCK_T +typedef long clock_t; +# define HAVE_CLOCK_T +#endif /* HAVE_CLOCK_T */ + +#ifndef HAVE_SA_FAMILY_T +typedef int sa_family_t; +# define HAVE_SA_FAMILY_T +#endif /* HAVE_SA_FAMILY_T */ + +#ifndef HAVE_PID_T +typedef int pid_t; +# define HAVE_PID_T +#endif /* HAVE_PID_T */ + +#ifndef HAVE_SIG_ATOMIC_T +typedef int sig_atomic_t; +# define HAVE_SIG_ATOMIC_T +#endif /* HAVE_SIG_ATOMIC_T */ + +#ifndef HAVE_MODE_T +typedef int mode_t; +# define HAVE_MODE_T +#endif /* HAVE_MODE_T */ + +#if !defined(HAVE_SS_FAMILY_IN_SS) && defined(HAVE___SS_FAMILY_IN_SS) +# define ss_family __ss_family +#endif /* !defined(HAVE_SS_FAMILY_IN_SS) && defined(HAVE_SA_FAMILY_IN_SS) */ + +#ifndef HAVE_SYS_UN_H +struct sockaddr_un { + short sun_family; /* AF_UNIX */ + char sun_path[108]; /* path name (gag) */ +}; +#endif /* HAVE_SYS_UN_H */ + +#if !defined(AF_LINK) && defined(AF_PACKET) +#define AF_LINK AF_PACKET /* XXX workaround on Linux */ +#endif + +#ifndef HAVE_IN_ADDR_T +typedef u_int32_t in_addr_t; +#endif + +#ifndef HAVE_IN_PORT_T +typedef u_int16_t in_port_t; +#endif + +#if defined(BROKEN_SYS_TERMIO_H) && !defined(_STRUCT_WINSIZE) +#define _STRUCT_WINSIZE +struct winsize { + unsigned short ws_row; /* rows, in characters */ + unsigned short ws_col; /* columns, in character */ + unsigned short ws_xpixel; /* horizontal size, pixels */ + unsigned short ws_ypixel; /* vertical size, pixels */ +}; +#endif + +/* *-*-nto-qnx does not define this type in the system headers */ +#ifdef MISSING_FD_MASK + typedef unsigned long int fd_mask; +#endif + +#if defined(HAVE_LIBKERN_OSBYTEORDER_H) +/* Byte conversion on OS X */ +#define betoh16 OSSwapBigToHostInt16 +#define betoh32 OSSwapBigToHostInt32 +#define betoh64 OSSwapBigToHostInt64 +#define htobe16 OSSwapHostToBigInt16 +#define htobe32 OSSwapHostToBigInt32 +#define htobe64 OSSwapHostToBigInt64 +#else +#if !defined(betoh16) +#define betoh16 be16toh +#endif +#if !defined(betoh32) +#define betoh32 be32toh +#endif +#if !defined(betoh64) +#define betoh64 be64toh +#endif +#endif + +#if defined(HAVE_APPLE_NATT) && !defined(SADB_X_EXT_NATT) +/* + * These are hidden in Apple XNU's private pfkeyv2.h header + */ +#define SADB_X_EXT_NATT 0x0002 /* Enable UDP encapsulation */ +#define SADB_X_EXT_NATT_KEEPALIVE 0x0004 /* Send NAT-T keepalives */ +#define SADB_X_EXT_NATT_MULTIPLEUSERS 0x0008 /* Use for VPN gateways */ +#define SADB_X_EXT_NATT_DETECTED_PEER 0x1000 /* Opposite of KEEPALIVE */ + +struct sadb_sa_natt { + u_int16_t sadb_sa_natt_port; + u_int16_t sadb_reserved; + u_int32_t sadb_reserved1; +}; +#endif + +/* Paths */ + +#ifndef _PATH_BSHELL +# define _PATH_BSHELL "/bin/sh" +#endif + +#ifdef USER_PATH +# ifdef _PATH_STDPATH +# undef _PATH_STDPATH +# endif +# define _PATH_STDPATH USER_PATH +#endif + +#ifndef _PATH_STDPATH +# define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin" +#endif + +#ifndef SUPERUSER_PATH +# define SUPERUSER_PATH _PATH_STDPATH +#endif + +#ifndef _PATH_DEVNULL +# define _PATH_DEVNULL "/dev/null" +#endif + +#ifndef MAIL_DIRECTORY +# define MAIL_DIRECTORY "/var/spool/mail" +#endif + +/* remove it +#ifndef MAILDIR +# define MAILDIR MAIL_DIRECTORY +#endif */ + +#if !defined(_PATH_MAILDIR) && defined(MAILDIR) +# define _PATH_MAILDIR MAILDIR +#endif /* !defined(_PATH_MAILDIR) && defined(MAILDIR) */ + +#ifndef _PATH_NOLOGIN +# define _PATH_NOLOGIN "/etc/nologin" +#endif + +/* Define this to be the path of the xauth program. */ +#ifdef XAUTH_PATH +#define _PATH_XAUTH XAUTH_PATH +#endif /* XAUTH_PATH */ + +/* derived from XF4/xc/lib/dps/Xlibnet.h */ +#ifndef X_UNIX_PATH +# ifdef __hpux +# define X_UNIX_PATH "/var/spool/sockets/X11/%u" +# else +# define X_UNIX_PATH "/tmp/.X11-unix/X%u" +# endif +#endif /* X_UNIX_PATH */ +#define _PATH_UNIX_X X_UNIX_PATH + +#ifndef _PATH_TTY +# define _PATH_TTY "/dev/tty" +#endif + +/* Macros */ + +#if defined(HAVE_LOGIN_GETCAPBOOL) && defined(HAVE_LOGIN_CAP_H) +# define HAVE_LOGIN_CAP +#endif + +#ifndef MAX +# define MAX(a,b) (((a)>(b))?(a):(b)) +# define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +#ifndef roundup +# define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) +#endif + +#ifndef timersub +#define timersub(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ + if ((result)->tv_usec < 0) { \ + --(result)->tv_sec; \ + (result)->tv_usec += 1000000; \ + } \ + } while (0) +#endif + +#ifndef timespeccmp +#define timespeccmp(a, b, cmp) \ + (((a)->tv_sec == (b)->tv_sec) ? \ + ((a)->tv_nsec cmp (b)->tv_nsec) : \ + ((a)->tv_sec cmp (b)->tv_sec)) +#endif + +#ifndef timespecsub +#define timespecsub(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ + (result)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec; \ + if ((result)->tv_nsec < 0) { \ + --(result)->tv_sec; \ + (result)->tv_nsec += 1000000000L; \ + } \ + } while (0) +#endif + +#ifndef TIMEVAL_TO_TIMESPEC +#define TIMEVAL_TO_TIMESPEC(tv, ts) { \ + (ts)->tv_sec = (tv)->tv_sec; \ + (ts)->tv_nsec = (tv)->tv_usec * 1000; \ +} +#endif + +#ifndef TIMESPEC_TO_TIMEVAL +#define TIMESPEC_TO_TIMEVAL(tv, ts) { \ + (tv)->tv_sec = (ts)->tv_sec; \ + (tv)->tv_usec = (ts)->tv_nsec / 1000; \ +} +#endif + +#ifndef __P +# define __P(x) x +#endif + +#if !defined(IN6_IS_ADDR_V4MAPPED) +# define IN6_IS_ADDR_V4MAPPED(a) \ + ((((u_int32_t *) (a))[0] == 0) && (((u_int32_t *) (a))[1] == 0) && \ + (((u_int32_t *) (a))[2] == htonl (0xffff))) +#endif /* !defined(IN6_IS_ADDR_V4MAPPED) */ + +#if !defined(__GNUC__) || (__GNUC__ < 2) +# define __attribute__(x) +#endif /* !defined(__GNUC__) || (__GNUC__ < 2) */ + +#ifndef __packed +# define __packed __attribute__((packed)) +#endif + +#if defined(__clang__) +# if defined(__dead) +# undef __dead +# endif +# define __dead __attribute__((noreturn)) __attribute__((analyzer_noreturn)) +#elif !defined(__dead) +# define __dead __attribute__((noreturn)) +#endif + +#if !defined(HAVE_ATTRIBUTE__SENTINEL__) && !defined(__sentinel__) +# define __sentinel__ +#endif + +#if !defined(HAVE_ATTRIBUTE__BOUNDED__) && !defined(__bounded__) +# define __bounded__(x, y, z...) +#endif + +#if !defined(HAVE_ATTRIBUTE__NONNULL__) && !defined(__nonnull__) +# define __nonnull__(x) +#endif + +/* *-*-nto-qnx doesn't define this macro in the system headers */ +#ifdef MISSING_HOWMANY +# define howmany(x,y) (((x)+((y)-1))/(y)) +#endif + +#ifndef OSSH_ALIGNBYTES +#define OSSH_ALIGNBYTES (sizeof(int) - 1) +#endif +#ifndef __CMSG_ALIGN +#define __CMSG_ALIGN(p) (((u_int)(p) + OSSH_ALIGNBYTES) &~ OSSH_ALIGNBYTES) +#endif + +/* Length of the contents of a control message of length len */ +#ifndef CMSG_LEN +#define CMSG_LEN(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + (len)) +#endif + +/* Length of the space taken up by a padded control message of length len */ +#ifndef CMSG_SPACE +#define CMSG_SPACE(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(len)) +#endif + +/* given pointer to struct cmsghdr, return pointer to data */ +#ifndef CMSG_DATA +#define CMSG_DATA(cmsg) ((u_char *)(cmsg) + __CMSG_ALIGN(sizeof(struct cmsghdr))) +#endif /* CMSG_DATA */ + +/* + * RFC 2292 requires to check msg_controllen, in case that the kernel returns + * an empty list for some reasons. + */ +#ifndef CMSG_FIRSTHDR +#define CMSG_FIRSTHDR(mhdr) \ + ((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \ + (struct cmsghdr *)(mhdr)->msg_control : \ + (struct cmsghdr *)NULL) +#endif /* CMSG_FIRSTHDR */ + +#if defined(HAVE_DECL_OFFSETOF) && HAVE_DECL_OFFSETOF == 0 +# define offsetof(type, member) ((size_t) &((type *)0)->member) +#endif + +/* Set up BSD-style BYTE_ORDER definition if it isn't there already */ +/* XXX: doesn't try to cope with strange byte orders (PDP_ENDIAN) */ +#ifndef BYTE_ORDER +# ifndef LITTLE_ENDIAN +# define LITTLE_ENDIAN 1234 +# endif /* LITTLE_ENDIAN */ +# ifndef BIG_ENDIAN +# define BIG_ENDIAN 4321 +# endif /* BIG_ENDIAN */ +# ifdef WORDS_BIGENDIAN +# define BYTE_ORDER BIG_ENDIAN +# else /* WORDS_BIGENDIAN */ +# define BYTE_ORDER LITTLE_ENDIAN +# endif /* WORDS_BIGENDIAN */ +#endif /* BYTE_ORDER */ + +/* Function replacement / compatibility hacks */ + +#if !defined(HAVE_GETADDRINFO) && (defined(HAVE_OGETADDRINFO) || defined(HAVE_NGETADDRINFO)) +# define HAVE_GETADDRINFO +#endif + +#ifndef HAVE_GETOPT_OPTRESET +# undef getopt +# undef opterr +# undef optind +# undef optopt +# undef optreset +# undef optarg +# define getopt(ac, av, o) BSDgetopt(ac, av, o) +# define opterr BSDopterr +# define optind BSDoptind +# define optopt BSDoptopt +# define optreset BSDoptreset +# define optarg BSDoptarg +#endif + +#if defined(BROKEN_GETADDRINFO) && defined(HAVE_GETADDRINFO) +# undef HAVE_GETADDRINFO +#endif +#if defined(BROKEN_GETADDRINFO) && defined(HAVE_FREEADDRINFO) +# undef HAVE_FREEADDRINFO +#endif +#if defined(BROKEN_GETADDRINFO) && defined(HAVE_GAI_STRERROR) +# undef HAVE_GAI_STRERROR +#endif + +#if defined(BROKEN_UPDWTMPX) && defined(HAVE_UPDWTMPX) +# undef HAVE_UPDWTMPX +#endif + +#if defined(BROKEN_SHADOW_EXPIRE) && defined(HAS_SHADOW_EXPIRE) +# undef HAS_SHADOW_EXPIRE +#endif + +#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) && \ + defined(SYSLOG_R_SAFE_IN_SIGHAND) +# define DO_LOG_SAFE_IN_SIGHAND +#endif + +#if !defined(HAVE_MEMMOVE) && defined(HAVE_BCOPY) +# define memmove(s1, s2, n) bcopy((s2), (s1), (n)) +#endif /* !defined(HAVE_MEMMOVE) && defined(HAVE_BCOPY) */ + +#if defined(HAVE_VHANGUP) && !defined(HAVE_DEV_PTMX) +# define USE_VHANGUP +#endif /* defined(HAVE_VHANGUP) && !defined(HAVE_DEV_PTMX) */ + +#ifdef USE_BSM_AUDIT +# define SSH_AUDIT_EVENTS +# define CUSTOM_SSH_AUDIT_EVENTS +#endif + +/* OPENSSL_free() is Free() in versions before OpenSSL 0.9.6 */ +#if !defined(OPENSSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x0090600f) +# define OPENSSL_free(x) Free(x) +#endif + +#if !defined(HAVE___func__) && defined(HAVE___FUNCTION__) +# define __func__ __FUNCTION__ +#elif !defined(HAVE___func__) +# define __func__ "" +#endif + +#if defined(KRB5) && !defined(HEIMDAL) +# define krb5_get_err_text(context,code) error_message(code) +#endif + +#if defined(SKEYCHALLENGE_4ARG) +# define _compat_skeychallenge(a,b,c,d) skeychallenge(a,b,c,d) +#else +# define _compat_skeychallenge(a,b,c,d) skeychallenge(a,b,c) +#endif + +/* Maximum number of file descriptors available */ +#ifndef OPEN_MAX +# ifdef HAVE_SYSCONF +# define OPEN_MAX sysconf(_SC_OPEN_MAX) +# else +# define OPEN_MAX 256 +# endif +#endif + +#if defined(__Lynx__) + /* + * LynxOS defines these in param.h which we do not want to include since + * it will also pull in a bunch of kernel definitions. + */ +# define ALIGNBYTES (sizeof(int) - 1) +# define ALIGN(p) (((unsigned)p + ALIGNBYTES) & ~ALIGNBYTES) + /* Missing prototypes on LynxOS */ + int snprintf (char *, size_t, const char *, ...); + int mkstemp (char *); + char *crypt (const char *, const char *); + int seteuid (uid_t); + int setegid (gid_t); + char *mkdtemp (char *); + int rresvport_af (int *, sa_family_t); + int innetgr (const char *, const char *, const char *, const char *); +#endif + +/* + * Define this to use pipes instead of socketpairs for communicating with the + * client program. Socketpairs do not seem to work on all systems. + * + * configure.ac sets this for a few OS's which are known to have problems + * but you may need to set it yourself + */ +/* #define USE_PIPES 1 */ + +/** + ** login recorder definitions + **/ + +/* FIXME: put default paths back in */ +#ifndef UTMP_FILE +# ifdef _PATH_UTMP +# define UTMP_FILE _PATH_UTMP +# else +# ifdef CONF_UTMP_FILE +# define UTMP_FILE CONF_UTMP_FILE +# endif +# endif +#endif +#ifndef WTMP_FILE +# ifdef _PATH_WTMP +# define WTMP_FILE _PATH_WTMP +# else +# ifdef CONF_WTMP_FILE +# define WTMP_FILE CONF_WTMP_FILE +# endif +# endif +#endif +/* pick up the user's location for lastlog if given */ +#ifndef LASTLOG_FILE +# ifdef _PATH_LASTLOG +# define LASTLOG_FILE _PATH_LASTLOG +# else +# ifdef CONF_LASTLOG_FILE +# define LASTLOG_FILE CONF_LASTLOG_FILE +# endif +# endif +#endif + +#if defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW) +# define USE_SHADOW +#endif + +/* The login() library function in libutil is first choice */ +#if defined(HAVE_LOGIN) && !defined(DISABLE_LOGIN) +# define USE_LOGIN + +#else +/* Simply select your favourite login types. */ +/* Can't do if-else because some systems use several... */ +# if defined(UTMPX_FILE) && !defined(DISABLE_UTMPX) +# define USE_UTMPX +# endif +# if defined(UTMP_FILE) && !defined(DISABLE_UTMP) +# define USE_UTMP +# endif +# if defined(WTMPX_FILE) && !defined(DISABLE_WTMPX) +# define USE_WTMPX +# endif +# if defined(WTMP_FILE) && !defined(DISABLE_WTMP) +# define USE_WTMP +# endif + +#endif + +#ifndef UT_LINESIZE +# define UT_LINESIZE 8 +#endif + +/* I hope that the presence of LASTLOG_FILE is enough to detect this */ +#if defined(LASTLOG_FILE) && !defined(DISABLE_LASTLOG) +# define USE_LASTLOG +#endif + +#ifdef HAVE_OSF_SIA +# ifdef USE_SHADOW +# undef USE_SHADOW +# endif +# define CUSTOM_SYS_AUTH_PASSWD 1 +#endif + +#if defined(HAVE_LIBIAF) && defined(HAVE_SET_ID) +# define CUSTOM_SYS_AUTH_PASSWD 1 +#endif +#if defined(HAVE_LIBIAF) && defined(HAVE_SET_ID) && !defined(BROKEN_LIBIAF) +# define USE_LIBIAF +#endif + +/* HP-UX 11.11 */ +#ifdef BTMP_FILE +# define _PATH_BTMP BTMP_FILE +#endif + +#if defined(USE_BTMP) && defined(_PATH_BTMP) +# define CUSTOM_FAILED_LOGIN +#endif + +/** end of login recorder definitions */ + +#ifdef BROKEN_GETGROUPS +# define getgroups(a,b) ((a)==0 && (b)==NULL ? NGROUPS_MAX : getgroups((a),(b))) +#endif + +#if defined(HAVE_MMAP) && defined(BROKEN_MMAP) +# undef HAVE_MMAP +#endif + +#ifndef IOV_MAX +# if defined(_XOPEN_IOV_MAX) +# define IOV_MAX _XOPEN_IOV_MAX +# elif defined(DEF_IOV_MAX) +# define IOV_MAX DEF_IOV_MAX +# else +# define IOV_MAX 16 +# endif +#endif + +#ifndef EAI_NODATA +# ifdef EAI_NONAME +# define EAI_NODATA EAI_NONAME +# else +# error "Neither EAI_NODATA and EAI_NONAME are defined! :(" +# endif +#endif + +#ifndef CLOCK_MONOTONIC +#define CLOCK_MONOTONIC -1 +#endif + +#ifdef HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_SYS_DIR_H +# include +# endif +# ifdef HAVE_NDIR_H +# include +# endif +#endif + +#ifndef _PASSWORD_LEN +#define _PASSWORD_LEN 128 +#endif + +#endif /* _DEFINES_H */ diff --git a/openbsd-compat/entropy.c b/openbsd-compat/entropy.c new file mode 100644 index 0000000..ea798a7 --- /dev/null +++ b/openbsd-compat/entropy.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2001 Damien Miller. 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. + */ + +#include "includes.h" + +#include +#include +#ifdef HAVE_SYS_UN_H +# include +#endif + +#include +#include + +#include +#include +#include +#include +#include /* for offsetof */ + +#include +#include +#include + +/* + * Portable OpenSSH PRNG seeding: + * If OpenSSL has not "internally seeded" itself (e.g. pulled data from + * /dev/random), then collect RANDOM_SEED_SIZE bytes of randomness from + * PRNGd. + */ +#ifndef OPENSSL_PRNG_ONLY + +#define RANDOM_SEED_SIZE 48 + +/* + * Collect 'len' bytes of entropy into 'buf' from PRNGD/EGD daemon + * listening either on 'tcp_port', or via Unix domain socket at * + * 'socket_path'. + * Either a non-zero tcp_port or a non-null socket_path must be + * supplied. + * Returns 0 on success, -1 on error + */ +int +get_random_bytes_prngd(unsigned char *buf, int len, + unsigned short tcp_port, char *socket_path) +{ + int fd, addr_len, rval, errors; + u_char msg[2]; + struct sockaddr_storage addr; + struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr; + struct sockaddr_un *addr_un = (struct sockaddr_un *)&addr; + mysig_t old_sigpipe; + + /* Sanity checks */ + if (socket_path == NULL && tcp_port == 0) + errx(1, "You must specify a port or a socket"); + if (socket_path != NULL && + strlen(socket_path) >= sizeof(addr_un->sun_path)) + errx(1, "Random pool path is too long"); + if (len <= 0 || len > 255) + errx(1, "Too many bytes (%d) to read from PRNGD", len); + + memset(&addr, '\0', sizeof(addr)); + + if (tcp_port != 0) { + addr_in->sin_family = AF_INET; + addr_in->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr_in->sin_port = htons(tcp_port); + addr_len = sizeof(*addr_in); + } else { + addr_un->sun_family = AF_UNIX; + strlcpy(addr_un->sun_path, socket_path, + sizeof(addr_un->sun_path)); + addr_len = offsetof(struct sockaddr_un, sun_path) + + strlen(socket_path) + 1; + } + + old_sigpipe = mysignal(SIGPIPE, SIG_IGN); + + errors = 0; + rval = -1; +reopen: + fd = socket(addr.ss_family, SOCK_STREAM, 0); + if (fd == -1) { + warn("Couldn't create socket"); + goto done; + } + + if (connect(fd, (struct sockaddr*)&addr, addr_len) == -1) { + if (tcp_port != 0) { + warn("Couldn't connect to PRNGD port %d", + tcp_port); + } else { + warn("Couldn't connect to PRNGD socket \"%s\"", + addr_un->sun_path); + } + goto done; + } + + /* Send blocking read request to PRNGD */ + msg[0] = 0x02; + msg[1] = len; + + if (atomicio(vwrite, fd, msg, sizeof(msg)) != sizeof(msg)) { + if (errno == EPIPE && errors < 10) { + close(fd); + errors++; + goto reopen; + } + warn("Couldn't write to PRNGD socket"); + goto done; + } + + if (atomicio(read, fd, buf, len) != (size_t)len) { + if (errno == EPIPE && errors < 10) { + close(fd); + errors++; + goto reopen; + } + warn("Couldn't read from PRNGD socket"); + goto done; + } + + rval = 0; +done: + mysignal(SIGPIPE, old_sigpipe); + if (fd != -1) + close(fd); + return rval; +} + +static int +seed_from_prngd(unsigned char *buf, size_t bytes) +{ +#ifdef PRNGD_PORT + debug("trying egd/prngd port %d", PRNGD_PORT); + if (get_random_bytes_prngd(buf, bytes, PRNGD_PORT, NULL) == 0) + return 0; +#endif +#ifdef PRNGD_SOCKET + debug("trying egd/prngd socket %s", PRNGD_SOCKET); + if (get_random_bytes_prngd(buf, bytes, 0, PRNGD_SOCKET) == 0) + return 0; +#endif + return -1; +} +#endif /* OPENSSL_PRNG_ONLY */ + +void +seed_rng(void) +{ +#ifndef OPENSSL_PRNG_ONLY + unsigned char buf[RANDOM_SEED_SIZE]; +#endif + /* + * OpenSSL version numbers: MNNFFPPS: major minor fix patch status + * We match major, minor, fix and status (not patch) for <1.0.0. + * After that, we acceptable compatible fix versions (so we + * allow 1.0.1 to work with 1.0.0). Going backwards is only allowed + * within a patch series. + */ + u_long version_mask = SSLeay() >= 0x1000000f ? ~0xffff0L : ~0xff0L; + if (((SSLeay() ^ OPENSSL_VERSION_NUMBER) & version_mask) || + (SSLeay() >> 12) < (OPENSSL_VERSION_NUMBER >> 12)) + errx(1, "OpenSSL version mismatch. Built against %lx, you " + "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay()); + +#ifndef OPENSSL_PRNG_ONLY + if (RAND_status() == 1) { + warnx("RNG is ready, skipping seeding"); + return; + } + + if (seed_from_prngd(buf, sizeof(buf)) == -1) + errx(1, "Could not obtain seed from PRNGd"); + RAND_add(buf, sizeof(buf), sizeof(buf)); + memset(buf, '\0', sizeof(buf)); + +#endif /* OPENSSL_PRNG_ONLY */ + if (RAND_status() != 1) + errx(1, "PRNG is not seeded"); +} diff --git a/openbsd-compat/fgetln.c b/openbsd-compat/fgetln.c new file mode 100644 index 0000000..c7fef41 --- /dev/null +++ b/openbsd-compat/fgetln.c @@ -0,0 +1,63 @@ +/* $OpenBSD: util.c,v 1.23 2007/09/17 09:28:36 espie Exp $ */ +/* $NetBSD: util.c,v 1.10 1996/12/31 17:56:04 christos Exp $ */ + +/* + * Copyright (c) 2001 Marc Espie. + * + * 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 OPENBSD PROJECT AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD + * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* OPENBSD ORIGINAL: usr.bin/make/util.c */ + +#include "includes.h" + +#ifndef HAVE_FGETLN + +#include + +char * +fgetln(stream, len) + FILE *stream; + size_t *len; +{ + static char *buffer = NULL; + static size_t buflen = 0; + + if (buflen == 0) { + buflen = 512; + if ((buffer = malloc(buflen+1)) == NULL) + err(255, "fatal: malloc: out of memory"); + } + if (fgets(buffer, buflen+1, stream) == NULL) + return NULL; + *len = strlen(buffer); + while (*len == buflen && buffer[*len-1] != '\n') { + if ((buffer = realloc(buffer, 2*buflen + 1)) == NULL) + err(255, "fatal: realloc: out of memory"); + if (fgets(buffer + buflen, buflen + 1, stream) == NULL) + return NULL; + *len += strlen(buffer + buflen); + buflen *= 2; + } + return buffer; +} +#endif diff --git a/openbsd-compat/getopt.c b/openbsd-compat/getopt.c new file mode 100644 index 0000000..5450e43 --- /dev/null +++ b/openbsd-compat/getopt.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* OPENBSD ORIGINAL: lib/libc/stdlib/getopt.c */ + +#include "includes.h" +#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET) + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: getopt.c,v 1.5 2003/06/02 20:18:37 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include + +int BSDopterr = 1, /* if error message should be printed */ + BSDoptind = 1, /* index into parent argv vector */ + BSDoptopt, /* character checked for validity */ + BSDoptreset; /* reset getopt */ +char *BSDoptarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +BSDgetopt(nargc, nargv, ostr) + int nargc; + char * const *nargv; + const char *ostr; +{ + extern char *__progname; + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (ostr == NULL) + return (-1); + + if (BSDoptreset || !*place) { /* update scanning pointer */ + BSDoptreset = 0; + if (BSDoptind >= nargc || *(place = nargv[BSDoptind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++BSDoptind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((BSDoptopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, BSDoptopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (BSDoptopt == (int)'-') + return (-1); + if (!*place) + ++BSDoptind; + if (BSDopterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", __progname, BSDoptopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + BSDoptarg = NULL; + if (!*place) + ++BSDoptind; + } + else { /* need an argument */ + if (*place) /* no white space */ + BSDoptarg = place; + else if (nargc <= ++BSDoptind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (BSDopterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + __progname, BSDoptopt); + return (BADCH); + } + else /* white space */ + BSDoptarg = nargv[BSDoptind]; + place = EMSG; + ++BSDoptind; + } + return (BSDoptopt); /* dump back option letter */ +} + +#endif /* !defined(HAVE_GETOPT) || !defined(HAVE_OPTRESET) */ diff --git a/openbsd-compat/imsg-buffer.c b/openbsd-compat/imsg-buffer.c new file mode 100644 index 0000000..2e7aef8 --- /dev/null +++ b/openbsd-compat/imsg-buffer.c @@ -0,0 +1,305 @@ +/* $OpenBSD: imsg-buffer.c,v 1.2 2012/06/02 21:46:53 gilles Exp $ */ + +/* + * Copyright (c) 2003, 2004 Henning Brauer + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "imsg.h" + +int ibuf_realloc(struct ibuf *, size_t); +void ibuf_enqueue(struct msgbuf *, struct ibuf *); +void ibuf_dequeue(struct msgbuf *, struct ibuf *); + +struct ibuf * +ibuf_open(size_t len) +{ + struct ibuf *buf; + + if ((buf = calloc(1, sizeof(struct ibuf))) == NULL) + return (NULL); + if ((buf->buf = malloc(len)) == NULL) { + free(buf); + return (NULL); + } + buf->size = buf->max = len; + buf->fd = -1; + + return (buf); +} + +struct ibuf * +ibuf_dynamic(size_t len, size_t max) +{ + struct ibuf *buf; + + if (max < len) + return (NULL); + + if ((buf = ibuf_open(len)) == NULL) + return (NULL); + + if (max > 0) + buf->max = max; + + return (buf); +} + +int +ibuf_realloc(struct ibuf *buf, size_t len) +{ + u_char *b; + + /* on static buffers max is eq size and so the following fails */ + if (buf->wpos + len > buf->max) { + errno = ENOMEM; + return (-1); + } + + b = realloc(buf->buf, buf->wpos + len); + if (b == NULL) + return (-1); + buf->buf = b; + buf->size = buf->wpos + len; + + return (0); +} + +int +ibuf_add(struct ibuf *buf, const void *data, size_t len) +{ + if (buf->wpos + len > buf->size) + if (ibuf_realloc(buf, len) == -1) + return (-1); + + memcpy(buf->buf + buf->wpos, data, len); + buf->wpos += len; + return (0); +} + +void * +ibuf_reserve(struct ibuf *buf, size_t len) +{ + void *b; + + if (buf->wpos + len > buf->size) + if (ibuf_realloc(buf, len) == -1) + return (NULL); + + b = buf->buf + buf->wpos; + buf->wpos += len; + return (b); +} + +void * +ibuf_seek(struct ibuf *buf, size_t pos, size_t len) +{ + /* only allowed to seek in already written parts */ + if (pos + len > buf->wpos) + return (NULL); + + return (buf->buf + pos); +} + +size_t +ibuf_size(struct ibuf *buf) +{ + return (buf->wpos); +} + +size_t +ibuf_left(struct ibuf *buf) +{ + return (buf->max - buf->wpos); +} + +void +ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf) +{ + ibuf_enqueue(msgbuf, buf); +} + +int +ibuf_write(struct msgbuf *msgbuf) +{ + struct iovec iov[IOV_MAX]; + struct ibuf *buf; + unsigned int i = 0; + ssize_t n; + + bzero(&iov, sizeof(iov)); + TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { + if (i >= IOV_MAX) + break; + iov[i].iov_base = buf->buf + buf->rpos; + iov[i].iov_len = buf->wpos - buf->rpos; + i++; + } + +again: + if ((n = writev(msgbuf->fd, iov, i)) == -1) { + if (errno == EAGAIN || errno == EINTR) + goto again; + if (errno == ENOBUFS) + errno = EAGAIN; + return (-1); + } + + if (n == 0) { /* connection closed */ + errno = 0; + return (0); + } + + msgbuf_drain(msgbuf, n); + + return (1); +} + +void +ibuf_free(struct ibuf *buf) +{ + free(buf->buf); + free(buf); +} + +void +msgbuf_init(struct msgbuf *msgbuf) +{ + msgbuf->queued = 0; + msgbuf->fd = -1; + TAILQ_INIT(&msgbuf->bufs); +} + +void +msgbuf_drain(struct msgbuf *msgbuf, size_t n) +{ + struct ibuf *buf, *next; + + for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; + buf = next) { + next = TAILQ_NEXT(buf, entry); + if (buf->rpos + n >= buf->wpos) { + n -= buf->wpos - buf->rpos; + ibuf_dequeue(msgbuf, buf); + } else { + buf->rpos += n; + n = 0; + } + } +} + +void +msgbuf_clear(struct msgbuf *msgbuf) +{ + struct ibuf *buf; + + while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL) + ibuf_dequeue(msgbuf, buf); +} + +int +msgbuf_write(struct msgbuf *msgbuf) +{ + struct iovec iov[IOV_MAX]; + struct ibuf *buf; + unsigned int i = 0; + ssize_t n; + struct msghdr msg; + struct cmsghdr *cmsg; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; + + bzero(&iov, sizeof(iov)); + bzero(&msg, sizeof(msg)); + TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { + if (i >= IOV_MAX) + break; + iov[i].iov_base = buf->buf + buf->rpos; + iov[i].iov_len = buf->wpos - buf->rpos; + i++; + if (buf->fd != -1) + break; + } + + msg.msg_iov = iov; + msg.msg_iovlen = i; + + if (buf != NULL && buf->fd != -1) { + msg.msg_control = (caddr_t)&cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + *(int *)CMSG_DATA(cmsg) = buf->fd; + } + +again: + if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) { + if (errno == EAGAIN || errno == EINTR) + goto again; + if (errno == ENOBUFS) + errno = EAGAIN; + return (-1); + } + + if (n == 0) { /* connection closed */ + errno = 0; + return (0); + } + + /* + * assumption: fd got sent if sendmsg sent anything + * this works because fds are passed one at a time + */ + if (buf != NULL && buf->fd != -1) { + close(buf->fd); + buf->fd = -1; + } + + msgbuf_drain(msgbuf, n); + + return (1); +} + +void +ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf) +{ + TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry); + msgbuf->queued++; +} + +void +ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf) +{ + TAILQ_REMOVE(&msgbuf->bufs, buf, entry); + + if (buf->fd != -1) + close(buf->fd); + + msgbuf->queued--; + ibuf_free(buf); +} diff --git a/openbsd-compat/imsg.c b/openbsd-compat/imsg.c new file mode 100644 index 0000000..a4536a2 --- /dev/null +++ b/openbsd-compat/imsg.c @@ -0,0 +1,323 @@ +/* $OpenBSD: imsg.c,v 1.2 2012/06/02 21:46:53 gilles Exp $ */ + +/* + * Copyright (c) 2003, 2004 Henning Brauer + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "imsg.h" + +int imsg_fd_overhead = 0; + +int imsg_get_fd(struct imsgbuf *); + +void +imsg_init(struct imsgbuf *ibuf, int fd) +{ + msgbuf_init(&ibuf->w); + bzero(&ibuf->r, sizeof(ibuf->r)); + ibuf->fd = fd; + ibuf->w.fd = fd; + ibuf->pid = getpid(); + TAILQ_INIT(&ibuf->fds); +} + +int +available_fds(int n) +{ + int i, ret, fds[256]; + + if (n > (int)(sizeof(fds)/sizeof(fds[0]))) + return (1); + + ret = 0; + for (i = 0; i < n; i++) { + fds[i] = -1; + if ((fds[i] = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + ret = 1; + break; + } + } + + for (i = 0; i < n && fds[i] >= 0; i++) + close(fds[i]); + + return (ret); +} + +ssize_t +imsg_read(struct imsgbuf *ibuf) +{ + struct msghdr msg; + struct cmsghdr *cmsg; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int) * 1)]; + } cmsgbuf; + struct iovec iov; + ssize_t n = -1; + int fd; + struct imsg_fd *ifd; + + bzero(&msg, sizeof(msg)); + + iov.iov_base = ibuf->r.buf + ibuf->r.wpos; + iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = &cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + + if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) + return (-1); + +again: + if (available_fds(imsg_fd_overhead + + (CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))) { + errno = EAGAIN; + return (-1); + } + + if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) { + if (errno == EMSGSIZE) + goto fail; + if (errno != EINTR && errno != EAGAIN) + goto fail; + goto again; + } + + ibuf->r.wpos += n; + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + int i; + int j; + + /* + * We only accept one file descriptor. Due to C + * padding rules, our control buffer might contain + * more than one fd, and we must close them. + */ + j = ((char *)cmsg + cmsg->cmsg_len - + (char *)CMSG_DATA(cmsg)) / sizeof(int); + for (i = 0; i < j; i++) { + fd = ((int *)CMSG_DATA(cmsg))[i]; + if (ifd != NULL) { + ifd->fd = fd; + TAILQ_INSERT_TAIL(&ibuf->fds, ifd, + entry); + ifd = NULL; + } else + close(fd); + } + } + /* we do not handle other ctl data level */ + } + +fail: + if (ifd) + free(ifd); + return (n); +} + +ssize_t +imsg_get(struct imsgbuf *ibuf, struct imsg *imsg) +{ + size_t av, left, datalen; + + av = ibuf->r.wpos; + + if (IMSG_HEADER_SIZE > av) + return (0); + + memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr)); + if (imsg->hdr.len < IMSG_HEADER_SIZE || + imsg->hdr.len > MAX_IMSGSIZE) { + errno = ERANGE; + return (-1); + } + if (imsg->hdr.len > av) + return (0); + datalen = imsg->hdr.len - IMSG_HEADER_SIZE; + ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE; + if ((imsg->data = malloc(datalen)) == NULL) + return (-1); + + if (imsg->hdr.flags & IMSGF_HASFD) + imsg->fd = imsg_get_fd(ibuf); + else + imsg->fd = -1; + + memcpy(imsg->data, ibuf->r.rptr, datalen); + + if (imsg->hdr.len < av) { + left = av - imsg->hdr.len; + memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left); + ibuf->r.wpos = left; + } else + ibuf->r.wpos = 0; + + return (datalen + IMSG_HEADER_SIZE); +} + +int +imsg_compose(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, + pid_t pid, int fd, void *data, u_int16_t datalen) +{ + struct ibuf *wbuf; + + if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) + return (-1); + + if (imsg_add(wbuf, data, datalen) == -1) + return (-1); + + wbuf->fd = fd; + + imsg_close(ibuf, wbuf); + + return (1); +} + +int +imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, + pid_t pid, int fd, const struct iovec *iov, int iovcnt) +{ + struct ibuf *wbuf; + int i, datalen = 0; + + for (i = 0; i < iovcnt; i++) + datalen += iov[i].iov_len; + + if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) + return (-1); + + for (i = 0; i < iovcnt; i++) + if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1) + return (-1); + + wbuf->fd = fd; + + imsg_close(ibuf, wbuf); + + return (1); +} + +/* ARGSUSED */ +struct ibuf * +imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, + pid_t pid, u_int16_t datalen) +{ + struct ibuf *wbuf; + struct imsg_hdr hdr; + + datalen += IMSG_HEADER_SIZE; + if (datalen > MAX_IMSGSIZE) { + errno = ERANGE; + return (NULL); + } + + hdr.type = type; + hdr.flags = 0; + hdr.peerid = peerid; + if ((hdr.pid = pid) == 0) + hdr.pid = ibuf->pid; + if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) { + return (NULL); + } + if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1) + return (NULL); + + return (wbuf); +} + +int +imsg_add(struct ibuf *msg, void *data, u_int16_t datalen) +{ + if (datalen) + if (ibuf_add(msg, data, datalen) == -1) { + ibuf_free(msg); + return (-1); + } + return (datalen); +} + +void +imsg_close(struct imsgbuf *ibuf, struct ibuf *msg) +{ + struct imsg_hdr *hdr; + + hdr = (struct imsg_hdr *)msg->buf; + + hdr->flags &= ~IMSGF_HASFD; + if (msg->fd != -1) + hdr->flags |= IMSGF_HASFD; + + hdr->len = (u_int16_t)msg->wpos; + + ibuf_close(&ibuf->w, msg); +} + +void +imsg_free(struct imsg *imsg) +{ + free(imsg->data); +} + +int +imsg_get_fd(struct imsgbuf *ibuf) +{ + int fd; + struct imsg_fd *ifd; + + if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL) + return (-1); + + fd = ifd->fd; + TAILQ_REMOVE(&ibuf->fds, ifd, entry); + free(ifd); + + return (fd); +} + +int +imsg_flush(struct imsgbuf *ibuf) +{ + while (ibuf->w.queued) + if (msgbuf_write(&ibuf->w) < 0) + return (-1); + return (0); +} + +void +imsg_clear(struct imsgbuf *ibuf) +{ + int fd; + + msgbuf_clear(&ibuf->w); + while ((fd = imsg_get_fd(ibuf)) != -1) + close(fd); +} diff --git a/openbsd-compat/imsg.h b/openbsd-compat/imsg.h new file mode 100644 index 0000000..d691f7d --- /dev/null +++ b/openbsd-compat/imsg.h @@ -0,0 +1,112 @@ +/* $OpenBSD: imsg.h,v 1.2 2010/06/23 07:53:55 nicm Exp $ */ + +/* + * Copyright (c) 2006, 2007 Pierre-Yves Ritschard + * Copyright (c) 2006, 2007, 2008 Reyk Floeter + * Copyright (c) 2003, 2004 Henning Brauer + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _IMSG_H_ +#define _IMSG_H_ + +#define IBUF_READ_SIZE 65535 +#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) +#define MAX_IMSGSIZE 16384 + +struct ibuf { + TAILQ_ENTRY(ibuf) entry; + u_char *buf; + size_t size; + size_t max; + size_t wpos; + size_t rpos; + int fd; +}; + +struct msgbuf { + TAILQ_HEAD(, ibuf) bufs; + u_int32_t queued; + int fd; +}; + +struct ibuf_read { + u_char buf[IBUF_READ_SIZE]; + u_char *rptr; + size_t wpos; +}; + +struct imsg_fd { + TAILQ_ENTRY(imsg_fd) entry; + int fd; +}; + +struct imsgbuf { + TAILQ_HEAD(, imsg_fd) fds; + struct ibuf_read r; + struct msgbuf w; + int fd; + pid_t pid; +}; + +#define IMSGF_HASFD 1 + +struct imsg_hdr { + u_int32_t type; + u_int16_t len; + u_int16_t flags; + u_int32_t peerid; + u_int32_t pid; +}; + +struct imsg { + struct imsg_hdr hdr; + int fd; + void *data; +}; + + +/* buffer.c */ +struct ibuf *ibuf_open(size_t); +struct ibuf *ibuf_dynamic(size_t, size_t); +int ibuf_add(struct ibuf *, const void *, size_t); +void *ibuf_reserve(struct ibuf *, size_t); +void *ibuf_seek(struct ibuf *, size_t, size_t); +size_t ibuf_size(struct ibuf *); +size_t ibuf_left(struct ibuf *); +void ibuf_close(struct msgbuf *, struct ibuf *); +int ibuf_write(struct msgbuf *); +void ibuf_free(struct ibuf *); +void msgbuf_init(struct msgbuf *); +void msgbuf_clear(struct msgbuf *); +int msgbuf_write(struct msgbuf *); +void msgbuf_drain(struct msgbuf *, size_t); + +/* imsg.c */ +void imsg_init(struct imsgbuf *, int); +ssize_t imsg_read(struct imsgbuf *); +ssize_t imsg_get(struct imsgbuf *, struct imsg *); +int imsg_compose(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, + int, void *, u_int16_t); +int imsg_composev(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, + int, const struct iovec *, int); +struct ibuf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, + u_int16_t); +int imsg_add(struct ibuf *, void *, u_int16_t); +void imsg_close(struct imsgbuf *, struct ibuf *); +void imsg_free(struct imsg *); +int imsg_flush(struct imsgbuf *); +void imsg_clear(struct imsgbuf *); + +#endif diff --git a/openbsd-compat/includes.h b/openbsd-compat/includes.h new file mode 100644 index 0000000..073845d --- /dev/null +++ b/openbsd-compat/includes.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2012 Reyk Floeter + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* based on includes.h from OpenSSH: + * + * $OpenBSD: includes.h,v 1.54 2006/07/22 20:48:23 stevesk Exp $ + * + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * This file includes most of the needed system headers. + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ + +#ifndef INCLUDES_H +#define INCLUDES_H + +#include "config.h" + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* activate extra prototypes for glibc */ +#endif + +#include +#include /* For CMSG_* */ + +#ifdef HAVE_LIMITS_H +# include /* For PATH_MAX */ +#endif + +#ifdef HAVE_BSTRING_H +# include +#endif + +#ifdef HAVE_ASM_BYTEORDER_H +# include +#endif + +#if defined(HAVE_ENDIAN_H) +# include +#elif defined(HAVE_SYS_ENDIAN_H) +# include +#endif + +#ifdef HAVE_PATHS_H +# include +#endif + +/* + *-*-nto-qnx needs these headers for strcasecmp and LASTLOG_FILE respectively + */ +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_LOGIN_H +# include +#endif + +#ifdef HAVE_RPC_TYPES_H +# include /* For INADDR_LOOPBACK */ +#endif +#ifdef USE_PAM +#if defined(HAVE_SECURITY_PAM_APPL_H) +# include +#elif defined (HAVE_PAM_PAM_APPL_H) +# include +#endif +#endif +#include + +#ifdef HAVE_ERR_H +#include +#endif + +#if defined (HAVE_NETINET_IN_H) +#include +#endif + +#ifdef HAVE_NETDB_H +# include +#endif + +#if defined (HAVE_NETINET6_IPSEC_H) +#include +#elif defined(HAVE_NETIPSEC_IPSEC_H) +#include +#elif defined (HAVE_LINUX_IPSEC_H) +#include +#endif + +#if defined(HAVE_LIBKERN_OSBYTEORDER_H) +#include +#endif + +#ifdef HAVE_NET_PFKEYV2_H +#include +#endif + +#ifdef HAVE_LINUX_PFKEYV2_H +#include +#endif + +#ifdef HAVE_SYS_SYSCTL_H +#include +#endif + +#include /* For OPENSSL_VERSION_NUMBER */ + +#include "defines.h" + +#include "openbsd-compat.h" + +#endif /* INCLUDES_H */ diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h new file mode 100644 index 0000000..26bf649 --- /dev/null +++ b/openbsd-compat/openbsd-compat.h @@ -0,0 +1,182 @@ +/* $Id: openbsd-compat.h,v 1.51 2010/10/07 10:25:29 djm Exp $ */ + +/* + * Copyright (c) 1999-2003 Damien Miller. All rights reserved. + * Copyright (c) 2003 Ben Lindstrom. All rights reserved. + * Copyright (c) 2002 Tim Rice. 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. + */ + +#ifndef _OPENBSD_COMPAT_H +#define _OPENBSD_COMPAT_H + +#include "includes.h" + +#include + +#include +#include + +#ifndef AI_MASK +/* valid flags for addrinfo */ +#define AI_MASK \ + (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_NUMERICSERV) +#ifdef AI_FQDN +#define AI_MASK (AI_MASK | AI_FQDN) +#endif +#endif + +#ifndef AI_FQDN +#define AI_FQDN AI_CANONNAME +#endif + +#include "sys-queue.h" +#include "sys-tree.h" +#include "vis.h" + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifndef SIZE_MAX +#include +#endif + +/* From OpenNTPD portable */ +#if !defined(SA_LEN) +# if defined(HAVE_STRUCT_SOCKADDR_SA_LEN) +# define SA_LEN(x) ((x)->sa_len) +# else +# define SA_LEN(x) ((x)->sa_family == AF_INET6 ? \ + sizeof(struct sockaddr_in6) : \ + sizeof(struct sockaddr_in)) +# endif +#endif + +/* From OpenBGPD portable */ +#if !defined(SS_LEN) +# if defined(HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN) +# define SS_LEN(x) ((x)->ss_len) +# else +# define SS_LEN(x) SA_LEN((struct sockaddr *)(x)) +# endif +#endif + +#ifdef HAVE_SS_LEN +# define STORAGE_LEN(X) ((X).ss_len) +# define SET_STORAGE_LEN(X, Y) do { STORAGE_LEN(X) = (Y); } while(0) +#elif defined(HAVE___SS_LEN) +# define STORAGE_LEN(X) ((X).__ss_len) +# define SET_STORAGE_LEN(X, Y) do { STORAGE_LEN(X) = (Y); } while(0) +#else +# define STORAGE_LEN(X) (STORAGE_FAMILY(X) == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)) +# define SET_STORAGE_LEN(X, Y) (void) 0 +#endif + + +#ifndef HAVE_CLOSEFROM +void closefrom(int); +#endif + +#ifndef HAVE_STRLCPY +size_t strlcpy(char *dst, const char *src, size_t size); +#endif + +#ifndef HAVE_STRLCAT +size_t strlcat(char *dst, const char *src, size_t size); +#endif + +#ifndef HAVE_STRMODE +void strmode(int mode, char *p); +#endif + +#ifndef HAVE_DIRNAME +char *dirname(const char *path); +#endif + +#ifndef HAVE_STRSEP +char *strsep(char **stringp, const char *delim); +#endif + +#ifndef HAVE_SETPROCTITLE +void setproctitle(const char *fmt, ...); +void compat_init_setproctitle(int argc, char *argv[]); +#endif + +#ifndef HAVE_SETRESGID +int setresgid(uid_t rgid, uid_t egid, uid_t sgid); +#endif + +#ifndef HAVE_SETRESUID +int setresuid(uid_t ruid, uid_t euid, uid_t suid); +#endif + +#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET) +int BSDgetopt(int argc, char * const *argv, const char *opts); +char *BSDoptarg; /* argument associated with option */ +int BSDoptind; /* index into parent argv vector */ +#endif + +#ifndef HAVE_GETPEEREID +int getpeereid(int , uid_t *, gid_t *); +#endif + +#ifndef HAVE_ARC4RANDOM +unsigned int arc4random(void); +void arc4random_stir(void); +#endif /* !HAVE_ARC4RANDOM */ + +#ifndef HAVE_ARC4RANDOM_BUF +void arc4random_buf(void *, size_t); +#endif + +#ifndef HAVE_ARC4RANDOM_UNIFORM +u_int32_t arc4random_uniform(u_int32_t); +#endif + +#ifndef HAVE_FGETLN +#include +#include +char * fgetln(FILE *stream, size_t *len); +#endif + +#ifndef HAVE_FPARSELN +char * fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags); +#endif + +#ifndef HAVE_STRTONUM +long long strtonum(const char *nptr, long long minval, long long maxval, const char **errstr); +#endif + +#ifndef HAVE_STRMODE +void strmode(int mode, char *p); +#endif + +#ifndef HAVE_FMT_SCALED +#define FMT_SCALED_STRSIZE 7 +int scan_scaled(char *scaled, long long *result); +int fmt_scaled(long long number, char *result); +#endif + +void seed_rng(void); + +#endif /* _OPENBSD_COMPAT_H */ diff --git a/openbsd-compat/setproctitle.c b/openbsd-compat/setproctitle.c new file mode 100644 index 0000000..40a6737 --- /dev/null +++ b/openbsd-compat/setproctitle.c @@ -0,0 +1,163 @@ +/* Based on conf.c from UCB sendmail 8.8.8 */ + +/* + * Copyright 2003 Damien Miller + * Copyright (c) 1983, 1995-1997 Eric P. Allman + * Copyright (c) 1988, 1993 + * The Regents of the University of California. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef HAVE_SETPROCTITLE + +#include +#include +#include +#include +#ifdef HAVE_SYS_PSTAT_H +#include +#endif +#include + +#include + +#define SPT_NONE 0 /* don't use it at all */ +#define SPT_PSTAT 1 /* use pstat(PSTAT_SETCMD, ...) */ +#define SPT_REUSEARGV 2 /* cover argv with title information */ + +#ifndef SPT_TYPE +# define SPT_TYPE SPT_NONE +#endif + +#ifndef SPT_PADCHAR +# define SPT_PADCHAR '\0' +#endif + +#if SPT_TYPE == SPT_REUSEARGV +static char *argv_start = NULL; +static size_t argv_env_len = 0; +#endif + +#endif /* HAVE_SETPROCTITLE */ + +void +compat_init_setproctitle(int argc, char *argv[]) +{ +#if defined(SPT_TYPE) && SPT_TYPE == SPT_REUSEARGV + extern char **environ; + char *lastargv = NULL; + char **envp = environ; + int i; + + /* + * NB: This assumes that argv has already been copied out of the + * way. This is true for sshd, but may not be true for other + * programs. Beware. + */ + + if (argc == 0 || argv[0] == NULL) + return; + + /* Fail if we can't allocate room for the new environment */ + for (i = 0; envp[i] != NULL; i++) + ; + if ((environ = calloc(i + 1, sizeof(*environ))) == NULL) { + environ = envp; /* put it back */ + return; + } + + /* + * Find the last argv string or environment variable within + * our process memory area. + */ + for (i = 0; i < argc; i++) { + if (lastargv == NULL || lastargv + 1 == argv[i]) + lastargv = argv[i] + strlen(argv[i]); + } + for (i = 0; envp[i] != NULL; i++) { + if (lastargv + 1 == envp[i]) + lastargv = envp[i] + strlen(envp[i]); + } + + argv[1] = NULL; + argv_start = argv[0]; + argv_env_len = lastargv - argv[0] - 1; + + /* + * Copy environment + * XXX - will truncate env on strdup fail + */ + for (i = 0; envp[i] != NULL; i++) + environ[i] = strdup(envp[i]); + environ[i] = NULL; +#endif /* SPT_REUSEARGV */ +} + +#ifndef HAVE_SETPROCTITLE +void +setproctitle(const char *fmt, ...) +{ +#if SPT_TYPE != SPT_NONE + va_list ap; + char buf[1024], ptitle[1024]; + size_t len; + extern char *__progname; +#if SPT_TYPE == SPT_PSTAT + union pstun pst; +#endif + +#if SPT_TYPE == SPT_REUSEARGV + if (argv_env_len <= 0) + return; +#endif + + strlcpy(buf, __progname, sizeof(buf)); + + va_start(ap, fmt); + if (fmt != NULL) { + len = strlcat(buf, ": ", sizeof(buf)); + if (len < sizeof(buf)) + vsnprintf(buf + len, sizeof(buf) - len , fmt, ap); + } + va_end(ap); + strnvis(ptitle, buf, sizeof(ptitle), + VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL); + +#if SPT_TYPE == SPT_PSTAT + pst.pst_command = ptitle; + pstat(PSTAT_SETCMD, pst, strlen(ptitle), 0, 0); +#elif SPT_TYPE == SPT_REUSEARGV +/* debug("setproctitle: copy \"%s\" into len %d", + buf, argv_env_len); */ + len = strlcpy(argv_start, ptitle, argv_env_len); + for(; len < argv_env_len; len++) + argv_start[len] = SPT_PADCHAR; +#endif + +#endif /* SPT_NONE */ +} + +#endif /* HAVE_SETPROCTITLE */ diff --git a/openbsd-compat/setresguid.c b/openbsd-compat/setresguid.c new file mode 100644 index 0000000..f332d50 --- /dev/null +++ b/openbsd-compat/setresguid.c @@ -0,0 +1,65 @@ +/* Subset of uidswap.c from portable OpenSSH */ + +/* $OpenBSD: uidswap.c,v 1.35 2006/08/03 03:34:42 deraadt Exp $ */ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Code for uid-swapping. + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ + +#include "includes.h" + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifndef HAVE_SETRESGID +int setresgid(uid_t rgid, uid_t egid, uid_t sgid) +{ + +#if defined(HAVE_SETRESGID) && !defined(BROKEN_SETRESGID) + if (setresgid(rgid, egid, sgid) < 0) + err(1, "setresgid %u", (u_int)rgid); +#elif defined(HAVE_SETREGID) && !defined(BROKEN_SETREGID) + if (setregid(rgid, egid) < 0) + err(1, "setregid %u", (u_int)rgid); +#else + if (setegid(egid) < 0) + err(1, "setegid %u", (u_int)egid); + if (setgid(rgid) < 0) + err(1, "setgid %u", (u_int)rgid); +#endif + return (0); +} +#endif /* HAVE_SETRESGID */ + + + +#ifndef HAVE_SETRESUID +int setresuid(uid_t ruid, uid_t euid, uid_t suid) +{ + +#if defined(HAVE_SETRESUID) && !defined(BROKEN_SETRESUID) + if (setresuid(ruid, euid, suid) < 0) + err(1, "setresuid %u", (u_int)ruid); +#elif defined(HAVE_SETREUID) && !defined(BROKEN_SETREUID) + if (setreuid(ruid, euid) < 0) + err(1, "setreuid %u", (u_int)ruid); +#else +# ifndef SETEUID_BREAKS_SETUID + if (seteuid(euid) < 0) + err(1, "seteuid %u", (u_int)euid); +# endif + if (setuid(ruid) < 0) + err(1, "setuid %u", (u_int)ruid); +#endif + return (0); +} +#endif /* HAVE_SETRESUID */ diff --git a/openbsd-compat/strlcat.c b/openbsd-compat/strlcat.c new file mode 100644 index 0000000..bcc1b61 --- /dev/null +++ b/openbsd-compat/strlcat.c @@ -0,0 +1,62 @@ +/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* OPENBSD ORIGINAL: lib/libc/string/strlcat.c */ + +#include "includes.h" +#ifndef HAVE_STRLCAT + +#include +#include + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +strlcat(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} + +#endif /* !HAVE_STRLCAT */ diff --git a/openbsd-compat/strlcpy.c b/openbsd-compat/strlcpy.c new file mode 100644 index 0000000..b4b1b60 --- /dev/null +++ b/openbsd-compat/strlcpy.c @@ -0,0 +1,58 @@ +/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* OPENBSD ORIGINAL: lib/libc/string/strlcpy.c */ + +#include "includes.h" +#ifndef HAVE_STRLCPY + +#include +#include + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +strlcpy(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0) { + while (--n != 0) { + if ((*d++ = *s++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} + +#endif /* !HAVE_STRLCPY */ diff --git a/openbsd-compat/strtonum.c b/openbsd-compat/strtonum.c new file mode 100644 index 0000000..88c74e2 --- /dev/null +++ b/openbsd-compat/strtonum.c @@ -0,0 +1,74 @@ +/* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */ + +/* + * Copyright (c) 2004 Ted Unangst and Todd Miller + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* OPENBSD ORIGINAL: lib/libc/stdlib/strtonum.c */ + +#ifdef HAVE_CONFIG_H +#include "includes.h" +#endif + +#ifndef HAVE_STRTONUM +#include +#include +#include + +#define INVALID 1 +#define TOOSMALL 2 +#define TOOLARGE 3 + +long long +strtonum(const char *numstr, long long minval, long long maxval, + const char **errstrp) +{ + long long ll = 0; + char *ep; + int error = 0; + struct errval { + const char *errstr; + int err; + } ev[4] = { + { NULL, 0 }, + { "invalid", EINVAL }, + { "too small", ERANGE }, + { "too large", ERANGE }, + }; + + ev[0].err = errno; + errno = 0; + if (minval > maxval) + error = INVALID; + else { + ll = strtoll(numstr, &ep, 10); + if (numstr == ep || *ep != '\0') + error = INVALID; + else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) + error = TOOSMALL; + else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) + error = TOOLARGE; + } + if (errstrp != NULL) + *errstrp = ev[error].errstr; + errno = ev[error].err; + if (error) + ll = 0; + + return (ll); +} + +#endif /* HAVE_STRTONUM */ diff --git a/openbsd-compat/sys-queue.h b/openbsd-compat/sys-queue.h new file mode 100644 index 0000000..a75c754 --- /dev/null +++ b/openbsd-compat/sys-queue.h @@ -0,0 +1,660 @@ +/* $OpenBSD: queue.h,v 1.36 2012/04/11 13:29:14 naddy Exp $ */ +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +/* OPENBSD ORIGINAL: sys/openbsd-compat/sys-queue.h */ + +#ifndef _FAKE_QUEUE_H_ +#define _FAKE_QUEUE_H_ + +/* + * Require for OS/X and other platforms that have old/broken/incomplete + * . + */ +#undef SLIST_HEAD +#undef SLIST_HEAD_INITIALIZER +#undef SLIST_ENTRY +#undef SLIST_FIRST +#undef SLIST_END +#undef SLIST_EMPTY +#undef SLIST_NEXT +#undef SLIST_FOREACH +#undef SLIST_FOREACH_SAFE +#undef SLIST_INIT +#undef SLIST_INSERT_AFTER +#undef SLIST_INSERT_HEAD +#undef SLIST_REMOVE_AFTER +#undef SLIST_REMOVE_HEAD +#undef SLIST_REMOVE +#undef LIST_HEAD +#undef LIST_HEAD_INITIALIZER +#undef LIST_ENTRY +#undef LIST_FIRST +#undef LIST_END +#undef LIST_EMPTY +#undef LIST_NEXT +#undef LIST_FOREACH +#undef LIST_FOREACH_SAFE +#undef LIST_INIT +#undef LIST_INSERT_AFTER +#undef LIST_INSERT_BEFORE +#undef LIST_INSERT_HEAD +#undef LIST_REMOVE +#undef LIST_REPLACE +#undef SIMPLEQ_HEAD +#undef SIMPLEQ_HEAD_INITIALIZER +#undef SIMPLEQ_ENTRY +#undef SIMPLEQ_FIRST +#undef SIMPLEQ_END +#undef SIMPLEQ_EMPTY +#undef SIMPLEQ_NEXT +#undef SIMPLEQ_FOREACH +#undef SIMPLEQ_FOREACH_SAFE +#undef SIMPLEQ_INIT +#undef SIMPLEQ_INSERT_HEAD +#undef SIMPLEQ_INSERT_TAIL +#undef SIMPLEQ_INSERT_AFTER +#undef SIMPLEQ_REMOVE_HEAD +#undef SIMPLEQ_REMOVE_AFTER +#undef TAILQ_HEAD +#undef TAILQ_HEAD_INITIALIZER +#undef TAILQ_ENTRY +#undef TAILQ_FIRST +#undef TAILQ_END +#undef TAILQ_NEXT +#undef TAILQ_LAST +#undef TAILQ_PREV +#undef TAILQ_EMPTY +#undef TAILQ_FOREACH +#undef TAILQ_FOREACH_SAFE +#undef TAILQ_FOREACH_REVERSE +#undef TAILQ_FOREACH_REVERSE_SAFE +#undef TAILQ_INIT +#undef TAILQ_INSERT_HEAD +#undef TAILQ_INSERT_TAIL +#undef TAILQ_INSERT_AFTER +#undef TAILQ_INSERT_BEFORE +#undef TAILQ_REMOVE +#undef TAILQ_REPLACE +#undef CIRCLEQ_HEAD +#undef CIRCLEQ_HEAD_INITIALIZER +#undef CIRCLEQ_ENTRY +#undef CIRCLEQ_FIRST +#undef CIRCLEQ_LAST +#undef CIRCLEQ_END +#undef CIRCLEQ_NEXT +#undef CIRCLEQ_PREV +#undef CIRCLEQ_EMPTY +#undef CIRCLEQ_FOREACH +#undef CIRCLEQ_FOREACH_SAFE +#undef CIRCLEQ_FOREACH_REVERSE +#undef CIRCLEQ_FOREACH_REVERSE_SAFE +#undef CIRCLEQ_INIT +#undef CIRCLEQ_INSERT_AFTER +#undef CIRCLEQ_INSERT_BEFORE +#undef CIRCLEQ_INSERT_HEAD +#undef CIRCLEQ_INSERT_TAIL +#undef CIRCLEQ_REMOVE +#undef CIRCLEQ_REPLACE + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) +#define _Q_INVALIDATE(a) (a) = ((void *)-1) +#else +#define _Q_INVALIDATE(a) +#endif + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List access methods. + */ +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_END(head) NULL +#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = SLIST_FIRST(head); \ + (var) != SLIST_END(head); \ + (var) = SLIST_NEXT(var, field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST(head); \ + (var) && ((tvar) = SLIST_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) { \ + SLIST_FIRST(head) = SLIST_END(head); \ +} + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define SLIST_REMOVE_AFTER(elm, field) do { \ + (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->slh_first; \ + \ + while (curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + _Q_INVALIDATE((elm)->field.sle_next); \ + } \ +} while (0) + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods + */ +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_END(head) NULL +#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_FOREACH(var, head, field) \ + for((var) = LIST_FIRST(head); \ + (var)!= LIST_END(head); \ + (var) = LIST_NEXT(var, field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST(head); \ + (var) && ((tvar) = LIST_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + LIST_FIRST(head) = LIST_END(head); \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +#define LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_END(head) NULL +#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for((var) = SIMPLEQ_FIRST(head); \ + (var) != SIMPLEQ_END(head); \ + (var) = SIMPLEQ_NEXT(var, field)) + +#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SIMPLEQ_FIRST(head); \ + (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \ + if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \ + == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * tail queue access methods + */ +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* XXX */ +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_EMPTY(head) \ + (TAILQ_FIRST(head) == TAILQ_END(head)) + +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head) && \ + ((tvar) = TAILQ_NEXT(var, field), 1); \ + (var) = (tvar)) + + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_PREV(var, headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head) && \ + ((tvar) = TAILQ_PREV(var, headname, field), 1); \ + (var) = (tvar)) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +#define TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue access methods + */ +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_END(head) ((void *)(head)) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#define CIRCLEQ_EMPTY(head) \ + (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_NEXT(var, field)) + +#define CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head) && \ + ((tvar) = CIRCLEQ_NEXT(var, field), 1); \ + (var) = (tvar)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for((var) = CIRCLEQ_LAST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_PREV(var, field)) + +#define CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = CIRCLEQ_LAST(head, headname); \ + (var) != CIRCLEQ_END(head) && \ + ((tvar) = CIRCLEQ_PREV(var, headname, field), 1); \ + (var) = (tvar)) + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = CIRCLEQ_END(head); \ + (head)->cqh_last = CIRCLEQ_END(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = CIRCLEQ_END(head); \ + if ((head)->cqh_last == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = CIRCLEQ_END(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ + CIRCLEQ_END(head)) \ + (head).cqh_last = (elm2); \ + else \ + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ + CIRCLEQ_END(head)) \ + (head).cqh_first = (elm2); \ + else \ + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/openbsd-compat/sys-tree.h b/openbsd-compat/sys-tree.h new file mode 100644 index 0000000..cadfb55 --- /dev/null +++ b/openbsd-compat/sys-tree.h @@ -0,0 +1,750 @@ +/* $OpenBSD: tree.h,v 1.13 2011/07/09 00:19:45 pirofti Exp $ */ +/* + * Copyright 2002 Niels Provos + * 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. + */ + +/* OPENBSD ORIGINAL: sys/openbsd-compat/sys-tree.h */ + +#ifndef _SYS_TREE_H_ +#define _SYS_TREE_H_ + +/* + * This file defines data structures for different types of trees: + * splay trees and red-black trees. + * + * A splay tree is a self-organizing data structure. Every operation + * on the tree causes a splay to happen. The splay moves the requested + * node to the root of the tree and partly rebalances it. + * + * This has the benefit that request locality causes faster lookups as + * the requested nodes move to the top of the tree. On the other hand, + * every lookup causes memory writes. + * + * The Balance Theorem bounds the total access time for m operations + * and n inserts on an initially empty tree as O((m + n)lg n). The + * amortized cost for a sequence of m accesses to a splay tree is O(lg n); + * + * A red-black tree is a binary search tree with the node color as an + * extra attribute. It fulfills a set of conditions: + * - every search path from the root to a leaf consists of the + * same number of black nodes, + * - each red node (except for the root) has a black parent, + * - each leaf node is black. + * + * Every operation on a red-black tree is bounded as O(lg n). + * The maximum height of a red-black tree is 2lg (n+1). + */ + +#define SPLAY_HEAD(name, type) \ +struct name { \ + struct type *sph_root; /* root of the tree */ \ +} + +#define SPLAY_INITIALIZER(root) \ + { NULL } + +#define SPLAY_INIT(root) do { \ + (root)->sph_root = NULL; \ +} while (0) + +#define SPLAY_ENTRY(type) \ +struct { \ + struct type *spe_left; /* left element */ \ + struct type *spe_right; /* right element */ \ +} + +#define SPLAY_LEFT(elm, field) (elm)->field.spe_left +#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right +#define SPLAY_ROOT(head) (head)->sph_root +#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) + +/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ +#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (0) + +#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (0) + +#define SPLAY_LINKLEFT(head, tmp, field) do { \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ +} while (0) + +#define SPLAY_LINKRIGHT(head, tmp, field) do { \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ +} while (0) + +#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ + SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ +} while (0) + +/* Generates prototypes and inline functions */ + +#define SPLAY_PROTOTYPE(name, type, field, cmp) \ +void name##_SPLAY(struct name *, struct type *); \ +void name##_SPLAY_MINMAX(struct name *, int); \ +struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ +struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ + \ +/* Finds the node with the same key as elm */ \ +static __inline struct type * \ +name##_SPLAY_FIND(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) \ + return(NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) \ + return (head->sph_root); \ + return (NULL); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_NEXT(struct name *head, struct type *elm) \ +{ \ + name##_SPLAY(head, elm); \ + if (SPLAY_RIGHT(elm, field) != NULL) { \ + elm = SPLAY_RIGHT(elm, field); \ + while (SPLAY_LEFT(elm, field) != NULL) { \ + elm = SPLAY_LEFT(elm, field); \ + } \ + } else \ + elm = NULL; \ + return (elm); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_MIN_MAX(struct name *head, int val) \ +{ \ + name##_SPLAY_MINMAX(head, val); \ + return (SPLAY_ROOT(head)); \ +} + +/* Main splay operation. + * Moves node close to the key of elm to top + */ +#define SPLAY_GENERATE(name, type, field, cmp) \ +struct type * \ +name##_SPLAY_INSERT(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) { \ + SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ + } else { \ + int __comp; \ + name##_SPLAY(head, elm); \ + __comp = (cmp)(elm, (head)->sph_root); \ + if(__comp < 0) { \ + SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ + SPLAY_RIGHT(elm, field) = (head)->sph_root; \ + SPLAY_LEFT((head)->sph_root, field) = NULL; \ + } else if (__comp > 0) { \ + SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT(elm, field) = (head)->sph_root; \ + SPLAY_RIGHT((head)->sph_root, field) = NULL; \ + } else \ + return ((head)->sph_root); \ + } \ + (head)->sph_root = (elm); \ + return (NULL); \ +} \ + \ +struct type * \ +name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *__tmp; \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) { \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ + } else { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ + name##_SPLAY(head, elm); \ + SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ + } \ + return (elm); \ + } \ + return (NULL); \ +} \ + \ +void \ +name##_SPLAY(struct name *head, struct type *elm) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ + int __comp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while ((__comp = (cmp)(elm, (head)->sph_root))) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) > 0){ \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} \ + \ +/* Splay with either the minimum or the maximum element \ + * Used to find minimum or maximum element in tree. \ + */ \ +void name##_SPLAY_MINMAX(struct name *head, int __comp) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while (1) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp > 0) { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} + +#define SPLAY_NEGINF -1 +#define SPLAY_INF 1 + +#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) +#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) +#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) +#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) +#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) +#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) + +#define SPLAY_FOREACH(x, name, head) \ + for ((x) = SPLAY_MIN(name, head); \ + (x) != NULL; \ + (x) = SPLAY_NEXT(name, head, x)) + +/* Macros that define a red-black tree */ +#define RB_HEAD(name, type) \ +struct name { \ + struct type *rbh_root; /* root of the tree */ \ +} + +#define RB_INITIALIZER(root) \ + { NULL } + +#define RB_INIT(root) do { \ + (root)->rbh_root = NULL; \ +} while (0) + +#define RB_BLACK 0 +#define RB_RED 1 +#define RB_ENTRY(type) \ +struct { \ + struct type *rbe_left; /* left element */ \ + struct type *rbe_right; /* right element */ \ + struct type *rbe_parent; /* parent element */ \ + int rbe_color; /* node color */ \ +} + +#define RB_LEFT(elm, field) (elm)->field.rbe_left +#define RB_RIGHT(elm, field) (elm)->field.rbe_right +#define RB_PARENT(elm, field) (elm)->field.rbe_parent +#define RB_COLOR(elm, field) (elm)->field.rbe_color +#define RB_ROOT(head) (head)->rbh_root +#define RB_EMPTY(head) (RB_ROOT(head) == NULL) + +#define RB_SET(elm, parent, field) do { \ + RB_PARENT(elm, field) = parent; \ + RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ + RB_COLOR(elm, field) = RB_RED; \ +} while (0) + +#define RB_SET_BLACKRED(black, red, field) do { \ + RB_COLOR(black, field) = RB_BLACK; \ + RB_COLOR(red, field) = RB_RED; \ +} while (0) + +#ifndef RB_AUGMENT +#define RB_AUGMENT(x) do {} while (0) +#endif + +#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ + (tmp) = RB_RIGHT(elm, field); \ + if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ + RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_LEFT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (0) + +#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ + (tmp) = RB_LEFT(elm, field); \ + if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ + RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_RIGHT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (0) + +/* Generates prototypes and inline functions */ +#define RB_PROTOTYPE(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) +#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static) +#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ +attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \ +attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ +attr struct type *name##_RB_REMOVE(struct name *, struct type *); \ +attr struct type *name##_RB_INSERT(struct name *, struct type *); \ +attr struct type *name##_RB_FIND(struct name *, struct type *); \ +attr struct type *name##_RB_NFIND(struct name *, struct type *); \ +attr struct type *name##_RB_NEXT(struct type *); \ +attr struct type *name##_RB_PREV(struct type *); \ +attr struct type *name##_RB_MINMAX(struct name *, int); \ + \ + +/* Main rb operation. + * Moves node close to the key of elm to top + */ +#define RB_GENERATE(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp,) +#define RB_GENERATE_STATIC(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static) +#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ +attr void \ +name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ +{ \ + struct type *parent, *gparent, *tmp; \ + while ((parent = RB_PARENT(elm, field)) && \ + RB_COLOR(parent, field) == RB_RED) { \ + gparent = RB_PARENT(parent, field); \ + if (parent == RB_LEFT(gparent, field)) { \ + tmp = RB_RIGHT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_RIGHT(parent, field) == elm) { \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_RIGHT(head, gparent, tmp, field); \ + } else { \ + tmp = RB_LEFT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_LEFT(parent, field) == elm) { \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_LEFT(head, gparent, tmp, field); \ + } \ + } \ + RB_COLOR(head->rbh_root, field) = RB_BLACK; \ +} \ + \ +attr void \ +name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ +{ \ + struct type *tmp; \ + while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ + elm != RB_ROOT(head)) { \ + if (RB_LEFT(parent, field) == elm) { \ + tmp = RB_RIGHT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ + struct type *oleft; \ + if ((oleft = RB_LEFT(tmp, field)))\ + RB_COLOR(oleft, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_RIGHT(head, tmp, oleft, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_RIGHT(tmp, field)) \ + RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } else { \ + tmp = RB_LEFT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ + struct type *oright; \ + if ((oright = RB_RIGHT(tmp, field)))\ + RB_COLOR(oright, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_LEFT(head, tmp, oright, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_LEFT(tmp, field)) \ + RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } \ + } \ + if (elm) \ + RB_COLOR(elm, field) = RB_BLACK; \ +} \ + \ +attr struct type * \ +name##_RB_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *child, *parent, *old = elm; \ + int color; \ + if (RB_LEFT(elm, field) == NULL) \ + child = RB_RIGHT(elm, field); \ + else if (RB_RIGHT(elm, field) == NULL) \ + child = RB_LEFT(elm, field); \ + else { \ + struct type *left; \ + elm = RB_RIGHT(elm, field); \ + while ((left = RB_LEFT(elm, field))) \ + elm = left; \ + child = RB_RIGHT(elm, field); \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ + if (RB_PARENT(elm, field) == old) \ + parent = elm; \ + (elm)->field = (old)->field; \ + if (RB_PARENT(old, field)) { \ + if (RB_LEFT(RB_PARENT(old, field), field) == old)\ + RB_LEFT(RB_PARENT(old, field), field) = elm;\ + else \ + RB_RIGHT(RB_PARENT(old, field), field) = elm;\ + RB_AUGMENT(RB_PARENT(old, field)); \ + } else \ + RB_ROOT(head) = elm; \ + RB_PARENT(RB_LEFT(old, field), field) = elm; \ + if (RB_RIGHT(old, field)) \ + RB_PARENT(RB_RIGHT(old, field), field) = elm; \ + if (parent) { \ + left = parent; \ + do { \ + RB_AUGMENT(left); \ + } while ((left = RB_PARENT(left, field))); \ + } \ + goto color; \ + } \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ +color: \ + if (color == RB_BLACK) \ + name##_RB_REMOVE_COLOR(head, parent, child); \ + return (old); \ +} \ + \ +/* Inserts a node into the RB tree */ \ +attr struct type * \ +name##_RB_INSERT(struct name *head, struct type *elm) \ +{ \ + struct type *tmp; \ + struct type *parent = NULL; \ + int comp = 0; \ + tmp = RB_ROOT(head); \ + while (tmp) { \ + parent = tmp; \ + comp = (cmp)(elm, parent); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + RB_SET(elm, parent, field); \ + if (parent != NULL) { \ + if (comp < 0) \ + RB_LEFT(parent, field) = elm; \ + else \ + RB_RIGHT(parent, field) = elm; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = elm; \ + name##_RB_INSERT_COLOR(head, elm); \ + return (NULL); \ +} \ + \ +/* Finds the node with the same key as elm */ \ +attr struct type * \ +name##_RB_FIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (NULL); \ +} \ + \ +/* Finds the first node greater than or equal to the search key */ \ +attr struct type * \ +name##_RB_NFIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *res = NULL; \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) { \ + res = tmp; \ + tmp = RB_LEFT(tmp, field); \ + } \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (res); \ +} \ + \ +/* ARGSUSED */ \ +attr struct type * \ +name##_RB_NEXT(struct type *elm) \ +{ \ + if (RB_RIGHT(elm, field)) { \ + elm = RB_RIGHT(elm, field); \ + while (RB_LEFT(elm, field)) \ + elm = RB_LEFT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +/* ARGSUSED */ \ +attr struct type * \ +name##_RB_PREV(struct type *elm) \ +{ \ + if (RB_LEFT(elm, field)) { \ + elm = RB_LEFT(elm, field); \ + while (RB_RIGHT(elm, field)) \ + elm = RB_RIGHT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field)))\ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +attr struct type * \ +name##_RB_MINMAX(struct name *head, int val) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *parent = NULL; \ + while (tmp) { \ + parent = tmp; \ + if (val < 0) \ + tmp = RB_LEFT(tmp, field); \ + else \ + tmp = RB_RIGHT(tmp, field); \ + } \ + return (parent); \ +} + +#define RB_NEGINF -1 +#define RB_INF 1 + +#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) +#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) +#define RB_FIND(name, x, y) name##_RB_FIND(x, y) +#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) +#define RB_NEXT(name, x, y) name##_RB_NEXT(y) +#define RB_PREV(name, x, y) name##_RB_PREV(y) +#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) +#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) + +#define RB_FOREACH(x, name, head) \ + for ((x) = RB_MIN(name, head); \ + (x) != NULL; \ + (x) = name##_RB_NEXT(x)) + +#define RB_FOREACH_SAFE(x, name, head, y) \ + for ((x) = RB_MIN(name, head); \ + ((x) != NULL) && ((y) = name##_RB_NEXT(x), 1); \ + (x) = (y)) + +#define RB_FOREACH_REVERSE(x, name, head) \ + for ((x) = RB_MAX(name, head); \ + (x) != NULL; \ + (x) = name##_RB_PREV(x)) + +#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ + for ((x) = RB_MAX(name, head); \ + ((x) != NULL) && ((y) = name##_RB_PREV(x), 1); \ + (x) = (y)) + +#endif /* _SYS_TREE_H_ */ diff --git a/openbsd-compat/vis.c b/openbsd-compat/vis.c new file mode 100644 index 0000000..3a087b3 --- /dev/null +++ b/openbsd-compat/vis.c @@ -0,0 +1,225 @@ +/* $OpenBSD: vis.c,v 1.19 2005/09/01 17:15:49 millert Exp $ */ +/*- + * Copyright (c) 1989, 1993 + * The Regents of the University of California. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* OPENBSD ORIGINAL: lib/libc/gen/vis.c */ + +#include "includes.h" +#if !defined(HAVE_STRNVIS) + +#include +#include + +#include "vis.h" + +#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') +#define isvisible(c) \ + (((u_int)(c) <= UCHAR_MAX && isascii((u_char)(c)) && \ + (((c) != '*' && (c) != '?' && (c) != '[' && (c) != '#') || \ + (flag & VIS_GLOB) == 0) && isgraph((u_char)(c))) || \ + ((flag & VIS_SP) == 0 && (c) == ' ') || \ + ((flag & VIS_TAB) == 0 && (c) == '\t') || \ + ((flag & VIS_NL) == 0 && (c) == '\n') || \ + ((flag & VIS_SAFE) && ((c) == '\b' || \ + (c) == '\007' || (c) == '\r' || \ + isgraph((u_char)(c))))) + +/* + * vis - visually encode characters + */ +char * +vis(char *dst, int c, int flag, int nextc) +{ + if (isvisible(c)) { + *dst++ = c; + if (c == '\\' && (flag & VIS_NOSLASH) == 0) + *dst++ = '\\'; + *dst = '\0'; + return (dst); + } + + if (flag & VIS_CSTYLE) { + switch(c) { + case '\n': + *dst++ = '\\'; + *dst++ = 'n'; + goto done; + case '\r': + *dst++ = '\\'; + *dst++ = 'r'; + goto done; + case '\b': + *dst++ = '\\'; + *dst++ = 'b'; + goto done; + case '\a': + *dst++ = '\\'; + *dst++ = 'a'; + goto done; + case '\v': + *dst++ = '\\'; + *dst++ = 'v'; + goto done; + case '\t': + *dst++ = '\\'; + *dst++ = 't'; + goto done; + case '\f': + *dst++ = '\\'; + *dst++ = 'f'; + goto done; + case ' ': + *dst++ = '\\'; + *dst++ = 's'; + goto done; + case '\0': + *dst++ = '\\'; + *dst++ = '0'; + if (isoctal(nextc)) { + *dst++ = '0'; + *dst++ = '0'; + } + goto done; + } + } + if (((c & 0177) == ' ') || (flag & VIS_OCTAL) || + ((flag & VIS_GLOB) && (c == '*' || c == '?' || c == '[' || c == '#'))) { + *dst++ = '\\'; + *dst++ = ((u_char)c >> 6 & 07) + '0'; + *dst++ = ((u_char)c >> 3 & 07) + '0'; + *dst++ = ((u_char)c & 07) + '0'; + goto done; + } + if ((flag & VIS_NOSLASH) == 0) + *dst++ = '\\'; + if (c & 0200) { + c &= 0177; + *dst++ = 'M'; + } + if (iscntrl((u_char)c)) { + *dst++ = '^'; + if (c == 0177) + *dst++ = '?'; + else + *dst++ = c + '@'; + } else { + *dst++ = '-'; + *dst++ = c; + } +done: + *dst = '\0'; + return (dst); +} + +/* + * strvis, strnvis, strvisx - visually encode characters from src into dst + * + * Dst must be 4 times the size of src to account for possible + * expansion. The length of dst, not including the trailing NULL, + * is returned. + * + * Strnvis will write no more than siz-1 bytes (and will NULL terminate). + * The number of bytes needed to fully encode the string is returned. + * + * Strvisx encodes exactly len bytes from src into dst. + * This is useful for encoding a block of data. + */ +int +strvis(char *dst, const char *src, int flag) +{ + char c; + char *start; + + for (start = dst; (c = *src);) + dst = vis(dst, c, flag, *++src); + *dst = '\0'; + return (dst - start); +} + +int +strnvis(char *dst, const char *src, size_t siz, int flag) +{ + char *start, *end; + char tbuf[5]; + int c, i; + + i = 0; + for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) { + if (isvisible(c)) { + i = 1; + *dst++ = c; + if (c == '\\' && (flag & VIS_NOSLASH) == 0) { + /* need space for the extra '\\' */ + if (dst < end) + *dst++ = '\\'; + else { + dst--; + i = 2; + break; + } + } + src++; + } else { + i = vis(tbuf, c, flag, *++src) - tbuf; + if (dst + i <= end) { + memcpy(dst, tbuf, i); + dst += i; + } else { + src--; + break; + } + } + } + if (siz > 0) + *dst = '\0'; + if (dst + i > end) { + /* adjust return value for truncation */ + while ((c = *src)) + dst += vis(tbuf, c, flag, *++src) - tbuf; + } + return (dst - start); +} + +int +strvisx(char *dst, const char *src, size_t len, int flag) +{ + char c; + char *start; + + for (start = dst; len > 1; len--) { + c = *src; + dst = vis(dst, c, flag, *++src); + } + if (len) + dst = vis(dst, *src, flag, '\0'); + *dst = '\0'; + return (dst - start); +} + +#endif diff --git a/openbsd-compat/vis.h b/openbsd-compat/vis.h new file mode 100644 index 0000000..66c0951 --- /dev/null +++ b/openbsd-compat/vis.h @@ -0,0 +1,98 @@ +/* $OpenBSD: vis.h,v 1.11 2005/08/09 19:38:31 millert Exp $ */ +/* $NetBSD: vis.h,v 1.4 1994/10/26 00:56:41 cgd Exp $ */ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)vis.h 5.9 (Berkeley) 4/3/91 + */ + +/* OPENBSD ORIGINAL: include/vis.h */ + +#ifdef HAVE_CONFIG_H +#include "includes.h" +#endif + +// #if !defined(HAVE_STRNVIS) + +#ifndef _VIS_H_ +#define _VIS_H_ + +#include +#include + +/* + * to select alternate encoding format + */ +#define VIS_OCTAL 0x01 /* use octal \ddd format */ +#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropriate */ + +/* + * to alter set of characters encoded (default is to encode all + * non-graphic except space, tab, and newline). + */ +#define VIS_SP 0x04 /* also encode space */ +#define VIS_TAB 0x08 /* also encode tab */ +#define VIS_NL 0x10 /* also encode newline */ +#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL) +#define VIS_SAFE 0x20 /* only encode "unsafe" characters */ + +/* + * other + */ +#define VIS_NOSLASH 0x40 /* inhibit printing '\' */ +#define VIS_GLOB 0x100 /* encode glob(3) magics and '#' */ + +/* + * unvis return codes + */ +#define UNVIS_VALID 1 /* character valid */ +#define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */ +#define UNVIS_NOCHAR 3 /* valid sequence, no character produced */ +#define UNVIS_SYNBAD -1 /* unrecognized escape sequence */ +#define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */ + +/* + * unvis flags + */ +#define UNVIS_END 1 /* no more characters */ + +char *vis(char *, int, int, int); +int strvis(char *, const char *, int); +int strnvis(char *, const char *, size_t, int) + __attribute__ ((__bounded__(__string__,1,3))); +int strvisx(char *, const char *, size_t, int) + __attribute__ ((__bounded__(__string__,1,3))); +int strunvis(char *, const char *); +int unvis(char *, char, int *, int); +ssize_t strnunvis(char *, const char *, size_t) + __attribute__ ((__bounded__(__string__,1,3))); + +#endif /* !_VIS_H_ */ + +//#endif /* !HAVE_STRNVIS */ From ab23472a5c28aeeb04e7964031d3d7635e1d2564 Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Wed, 8 Jun 2016 09:30:11 -0700 Subject: [PATCH 13/39] Remove CVS directories under regress --- regress/CVS/Entries | 2 -- regress/CVS/Repository | 1 - regress/CVS/Root | 1 - regress/dh/CVS/Entries | 3 --- regress/dh/CVS/Repository | 1 - regress/dh/CVS/Root | 1 - 6 files changed, 9 deletions(-) delete mode 100644 regress/CVS/Entries delete mode 100644 regress/CVS/Repository delete mode 100644 regress/CVS/Root delete mode 100644 regress/dh/CVS/Entries delete mode 100644 regress/dh/CVS/Repository delete mode 100644 regress/dh/CVS/Root diff --git a/regress/CVS/Entries b/regress/CVS/Entries deleted file mode 100644 index 112daed..0000000 --- a/regress/CVS/Entries +++ /dev/null @@ -1,2 +0,0 @@ -/Makefile/1.1/Mon Aug 25 19:22:20 2014// -D/dh//// diff --git a/regress/CVS/Repository b/regress/CVS/Repository deleted file mode 100644 index 512f007..0000000 --- a/regress/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -src/regress/sbin/iked diff --git a/regress/CVS/Root b/regress/CVS/Root deleted file mode 100644 index f9802fd..0000000 --- a/regress/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -anoncvs@ftp.hostserver.de:/cvs diff --git a/regress/dh/CVS/Entries b/regress/dh/CVS/Entries deleted file mode 100644 index 4c4738a..0000000 --- a/regress/dh/CVS/Entries +++ /dev/null @@ -1,3 +0,0 @@ -/Makefile/1.2/Wed Aug 27 10:28:57 2014// -/dhtest.c/1.2/Wed Aug 27 10:28:57 2014// -D diff --git a/regress/dh/CVS/Repository b/regress/dh/CVS/Repository deleted file mode 100644 index 3a5edbe..0000000 --- a/regress/dh/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -src/regress/sbin/iked/dh diff --git a/regress/dh/CVS/Root b/regress/dh/CVS/Root deleted file mode 100644 index f9802fd..0000000 --- a/regress/dh/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -anoncvs@ftp.hostserver.de:/cvs From b3f49aff0c12116536affabacd86f1a37719d636 Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Thu, 9 Jun 2016 07:47:17 -0700 Subject: [PATCH 14/39] Support transport mode If a policy (configuration) does not specify any peers, then flag the policy as being able to use transport mode IPSec. Send the USE_TRANSPORT_MODE notification with the request to signal the peer that we want transport mode. Enable transport mode if we receive the USE_TRANSPORT_MODE notification. --- iked/iked.h | 2 ++ iked/ikev2.c | 58 ++++++++++++++++++++++++++++++++++++++++++++---- iked/ikev2_pld.c | 15 +++++++++++++ iked/parse.y | 5 +++++ iked/pfkey.c | 11 +++++---- 5 files changed, 83 insertions(+), 8 deletions(-) diff --git a/iked/iked.h b/iked/iked.h index 4b3db78..6140c9f 100644 --- a/iked/iked.h +++ b/iked/iked.h @@ -242,6 +242,7 @@ struct iked_policy { #define IKED_POLICY_QUICK 0x08 #define IKED_POLICY_SKIP 0x10 #define IKED_POLICY_IPCOMP 0x20 +#define IKED_POLICY_TRANSPORT 0x40 int pol_refcnt; @@ -426,6 +427,7 @@ struct iked_sa { struct iked_sa *sa_next; /* IKE SA rekeying */ u_int64_t sa_rekeyspi; /* peerspi for rekey*/ + u_int8_t sa_transport; /* Transport mode */ u_int8_t sa_ipcomp; /* IPcomp transform */ u_int16_t sa_cpi_out; /* IPcomp outgoing */ u_int16_t sa_cpi_in; /* IPcomp incoming*/ diff --git a/iked/ikev2.c b/iked/ikev2.c index 927ea48..9d2818b 100644 --- a/iked/ikev2.c +++ b/iked/ikev2.c @@ -111,6 +111,8 @@ ssize_t ikev2_add_ts(struct ibuf *, struct ikev2_payload **, ssize_t, struct iked_sa *, int); ssize_t ikev2_add_certreq(struct ibuf *, struct ikev2_payload **, ssize_t, struct ibuf *, u_int8_t); +ssize_t ikev2_add_transportnotify(struct iked *, struct ibuf *, + struct ikev2_payload **, ssize_t, struct iked_sa *); ssize_t ikev2_add_ipcompnotify(struct iked *, struct ibuf *, struct ikev2_payload **, ssize_t, struct iked_sa *); ssize_t ikev2_add_ts_payload(struct ibuf *, u_int, struct iked_sa *); @@ -1063,6 +1065,11 @@ ikev2_init_ike_auth(struct iked *env, struct iked_sa *sa) (len = ikev2_add_ipcompnotify(env, e, &pld, len, sa)) == -1) goto done; + /* Transport mode IPSec. */ + if ((pol->pol_flags & IKED_POLICY_TRANSPORT) && + (len = ikev2_add_transportnotify(env, e, &pld, len, sa)) == -1) + goto done; + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1) goto done; @@ -1428,6 +1435,29 @@ ikev2_add_certreq(struct ibuf *e, struct ikev2_payload **pld, ssize_t len, return (len); } +ssize_t +ikev2_add_transportnotify(struct iked *env, struct ibuf *e, + struct ikev2_payload **pld, ssize_t len, struct iked_sa *sa) +{ + struct ikev2_notify *n; + + if (*pld) + if (ikev2_next_payload(*pld, len, IKEV2_PAYLOAD_NOTIFY) == -1) + return (-1); + if ((*pld = ikev2_add_payload(e)) == NULL) + return (-1); + len = sizeof(*n); + if ((n = ibuf_advance(e, len)) == NULL) + return (-1); + n->n_protoid = 0; + n->n_spisize = 0; + n->n_type = htobe16(IKEV2_N_USE_TRANSPORT_MODE); + + log_info("%s: Notifying to use transport mode", __func__); + + return (len); +} + ssize_t ikev2_add_ipcompnotify(struct iked *env, struct ibuf *e, struct ikev2_payload **pld, ssize_t len, struct iked_sa *sa) @@ -2273,6 +2303,11 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) (len = ikev2_add_ipcompnotify(env, e, &pld, len, sa)) == -1) goto done; + /* Transport mode IPSec. */ + if (sa->sa_transport && + (len = ikev2_add_transportnotify(env, e, &pld, len, sa)) == -1) + goto done; + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1) goto done; @@ -2483,7 +2518,7 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, u_int8_t *ptr; u_int8_t firstpayload; u_int32_t spi; - ssize_t len = 0; + ssize_t len; int initiator, ret = -1; if (rekey) @@ -2523,9 +2558,16 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, if ((e = ibuf_static()) == NULL) goto done; + len = 0; + /* compression */ if ((pol->pol_flags & IKED_POLICY_IPCOMP) && - (len = ikev2_add_ipcompnotify(env, e, &pld, 0, sa)) == -1) + (len = ikev2_add_ipcompnotify(env, e, &pld, len, sa)) == -1) + goto done; + + /* Transport mode IPSec. */ + if ((pol->pol_flags & IKED_POLICY_TRANSPORT) && + (len = ikev2_add_transportnotify(env, e, &pld, len, sa)) == -1) goto done; if (pld) { @@ -3019,7 +3061,7 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) struct ikev2_payload *pld = NULL; struct ibuf *e = NULL, *nonce = NULL; u_int8_t firstpayload; - ssize_t len = 0; + ssize_t len; int initiator, protoid, rekeying = 1; int ret = -1; int pfs = 0; @@ -3159,9 +3201,16 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) if ((e = ibuf_static()) == NULL) goto done; + len = 0; + /* compression (unless IKE rekeying) */ if (!nsa && sa->sa_ipcomp && - (len = ikev2_add_ipcompnotify(env, e, &pld, 0, sa)) == -1) + (len = ikev2_add_ipcompnotify(env, e, &pld, len, sa)) == -1) + goto done; + + /* Transport mode IPSec (unless IKE rekeying). */ + if (!nsa && sa->sa_transport && + (len = ikev2_add_transportnotify(env, e, &pld, len, sa)) == -1) goto done; if (pld) { @@ -4379,6 +4428,7 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, csa->csa_ikesa = sa; csa->csa_spi.spi_protoid = prop->prop_protoid; csa->csa_esn = esn; + csa->csa_transport = sa->sa_transport; /* Set up responder's SPIs */ if (initiator) { diff --git a/iked/ikev2_pld.c b/iked/ikev2_pld.c index 766aefc..d250912 100644 --- a/iked/ikev2_pld.c +++ b/iked/ikev2_pld.c @@ -1254,6 +1254,21 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, msg->msg_sa->sa_cpi_out = betoh16(cpi); } break; + case IKEV2_N_USE_TRANSPORT_MODE: + if (!msg->msg_e) { + log_debug("%s: USE_TRANSPORT_MODE: %s", __func__, + "notification in unencrypted payload"); + return (-1); + } + if (len != 0) { + log_debug("%s: USE_TRANSPORT_MODE: %s", __func__, + "ignoring malformed notification"); + return (0); + } + log_info("%s: USE_TRANSPORT_MODE: %s", __func__, + "notification received"); + msg->msg_sa->sa_transport = 1; + break; case IKEV2_N_SIGNATURE_HASH_ALGORITHMS: if (msg->msg_e) { log_debug("%s: SIGNATURE_HASH_ALGORITHMS: encrypted", diff --git a/iked/parse.y b/iked/parse.y index 64dea70..4337be6 100644 --- a/iked/parse.y +++ b/iked/parse.y @@ -2497,6 +2497,11 @@ create_ike(char *name, int af, u_int8_t ipproto, struct ipsec_hosts *hosts, if (peers->dst) ipb = peers->dst; if (ipa == NULL && ipb == NULL) { + /* + * If no peers were specified, flag this policy + * as being able to use transport mode. + */ + pol.pol_flags |= IKED_POLICY_TRANSPORT; if (hosts->src && hosts->src->next == NULL) ipa = hosts->src; if (hosts->dst && hosts->dst->next == NULL) diff --git a/iked/pfkey.c b/iked/pfkey.c index c9f6193..23d7aa8 100644 --- a/iked/pfkey.c +++ b/iked/pfkey.c @@ -453,6 +453,7 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) #else /* !_OPENBSD_IPSEC_API_VERSION */ + struct iked_sa *ike_sa = flow->flow_ikesa; struct sadb_msg smsg; struct sadb_address sa_src, sa_dst; struct sadb_x_ipsecrequest sa_ipsec; @@ -535,7 +536,7 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) bzero(&sa_2, sizeof(sa_2)); sa_2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; sa_2.sadb_x_sa2_len = sizeof(sa_2) / 8; - sa_2.sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT; + sa_2.sadb_x_sa2_mode = IPSEC_MODE_ANY; bzero(&sa_src, sizeof(sa_src)); sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; @@ -563,7 +564,8 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) bzero(&sa_ipsec, sizeof(sa_ipsec)); sa_ipsec.sadb_x_ipsecrequest_proto = satype == SADB_SATYPE_AH ? IPPROTO_AH : IPPROTO_ESP; - sa_ipsec.sadb_x_ipsecrequest_mode = IPSEC_MODE_TRANSPORT; /* XXX */ + sa_ipsec.sadb_x_ipsecrequest_mode = (ike_sa->sa_transport) ? + IPSEC_MODE_TRANSPORT : IPSEC_MODE_TUNNEL; sa_ipsec.sadb_x_ipsecrequest_level = flow->flow_dir == IPSEC_DIR_INBOUND ? IPSEC_LEVEL_USE : IPSEC_LEVEL_REQUIRE; @@ -657,7 +659,7 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) int pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) { - struct sadb_msg smsg; + struct sadb_msg smsg; struct sadb_sa sadb; struct sadb_address sa_src, sa_dst; struct sadb_key sa_authkey, sa_enckey; @@ -729,7 +731,8 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) bzero(&sa_2, sizeof(sa_2)); sa_2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; sa_2.sadb_x_sa2_len = sizeof(sa_2) / 8; - sa_2.sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT; /* XXX */ + sa_2.sadb_x_sa2_mode = (sa->csa_transport) ? IPSEC_MODE_TRANSPORT : + IPSEC_MODE_TUNNEL; #endif bzero(&sa_src, sizeof(sa_src)); From d7162699d3f4f8e09b92b1662403e2cee68ad9ef Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Thu, 9 Jun 2016 13:32:37 -0700 Subject: [PATCH 15/39] Make sure to only set transport mode when our policy indicates that such is possible. --- iked/ikev2_pld.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iked/ikev2_pld.c b/iked/ikev2_pld.c index d250912..8326a05 100644 --- a/iked/ikev2_pld.c +++ b/iked/ikev2_pld.c @@ -1267,7 +1267,8 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, } log_info("%s: USE_TRANSPORT_MODE: %s", __func__, "notification received"); - msg->msg_sa->sa_transport = 1; + if (msg->msg_sa->sa_policy->pol_flags & IKED_POLICY_TRANSPORT) + msg->msg_sa->sa_transport = 1; break; case IKEV2_N_SIGNATURE_HASH_ALGORITHMS: if (msg->msg_e) { From 8996fb306d22969ddc73fd7d4b1d13baf205de01 Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Fri, 10 Jun 2016 22:23:16 +0200 Subject: [PATCH 16/39] - Marcel Moolenaar made the work to update OpenIKED-portable and to implement transport mode - thanks a lot! - Update the autoconf framework to work on OpenBSD (not needed since OpenBSD has iked in base). --- configure.ac | 28 ++-- iked/ikev2.c | 5 + iked/pfkey.c | 399 ++++++++++++++++++++++++++------------------------- 3 files changed, 227 insertions(+), 205 deletions(-) diff --git a/configure.ac b/configure.ac index 8648bf1..c592951 100644 --- a/configure.ac +++ b/configure.ac @@ -139,6 +139,18 @@ AC_CHECK_HEADERS([\ getopt.h \ libkern/OSByteOrder.h \ ndir.h \ + sys/cdefs.h \ + sys/endian.h \ + sys/ndir.h \ + sys/param.h \ + sys/pstat.h \ + sys/socket.h \ + sys/stat.h \ + sys/sysctl.h \ + sys/types.h \ + sys/uio.h \ + sys/un.h \ + sys/wait.h \ net/pfkeyv2.h \ linux/pfkeyv2.h \ linux/in.h \ @@ -158,22 +170,14 @@ AC_CHECK_HEADERS([\ stdio.h \ stdlib.h \ string.h \ - sys/cdefs.h \ - sys/endian.h \ - sys/ndir.h \ - sys/param.h \ - sys/pstat.h \ - sys/socket.h \ - sys/stat.h \ - sys/sysctl.h \ - sys/types.h \ - sys/uio.h \ - sys/un.h \ - sys/wait.h \ syslog.h \ ucred.h \ unistd.h \ vis.h \ +], , , [ +#ifdef HAVE_SYS_SOCKET_H +# include +#endif ]) # login_cap.h requires sys/types.h on NetBSD diff --git a/iked/ikev2.c b/iked/ikev2.c index 9d2818b..4ded7f2 100644 --- a/iked/ikev2.c +++ b/iked/ikev2.c @@ -23,7 +23,12 @@ #include #include +#if defined(HAVE_NETIPSEC_IPSEC_H) #include +#endif +#if defined(HAVE_NETINET_IP_IPSP_H) +#include +#endif #include #include diff --git a/iked/pfkey.c b/iked/pfkey.c index 23d7aa8..cdbf610 100644 --- a/iked/pfkey.c +++ b/iked/pfkey.c @@ -24,7 +24,12 @@ #include #include +#if defined(HAVE_NETIPSEC_IPSEC_H) #include +#endif +#if defined(HAVE_NETINET_IP_IPSP_H) +#include +#endif #include #include @@ -72,7 +77,9 @@ static const struct pfkey_constmap pfkey_encr[] = { #ifdef SADB_X_EALG_DES_IV64 { SADB_X_EALG_DES_IV64, IKEV2_XFORMENCR_DES_IV64 }, #endif +#ifdef SADB_X_EALG_DESCBC { SADB_EALG_DESCBC, IKEV2_XFORMENCR_DES }, +#endif { SADB_EALG_3DESCBC, IKEV2_XFORMENCR_3DES }, #ifdef SADB_X_EALG_RC5 { SADB_X_EALG_RC5, IKEV2_XFORMENCR_RC5 }, @@ -242,7 +249,7 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) prefixlen2mask6(flow->flow_src.addr_net ? flow->flow_src.addr_mask : 128, (u_int32_t *)((struct sockaddr_in6 *) - &smask)->sin6_addr.s6_addrek; + &smask)->sin6_addr.s6_addr); default: log_warnx("%s: unsupported address family %d", __func__, flow->flow_src.addr_af); @@ -344,11 +351,11 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) (sizeof(sa_peer) + ROUNDUP(speer.ss_len)) / 8; /* local id */ - sa_srcid = pfkey_id2ident(flow->flow_srcid, + sa_srcid = pfkey_id2ident(IKESA_SRCID(flow->flow_ikesa), SADB_EXT_IDENTITY_SRC); /* peer id */ - sa_dstid = pfkey_id2ident(flow->flow_dstid, + sa_dstid = pfkey_id2ident(IKESA_DSTID(flow->flow_ikesa), SADB_EXT_IDENTITY_DST); } @@ -1863,47 +1870,47 @@ pfkey_timer_cb(int unused, short event, void *arg) int pfkey_process(struct iked *env, struct pfkey_message *pm) { - struct iked_spi spi; - struct sadb_sa *sa; - struct sadb_lifetime *sa_ltime; - struct sadb_msg *hdr; + struct iked_spi spi; + struct sadb_sa *sa; + struct sadb_lifetime *sa_ltime; + struct sadb_msg *hdr; #if defined(_OPENBSD_IPSEC_API_VERSION) - struct sadb_msg smsg; - struct iked_addr peer; - struct iked_flow flow; - struct sadb_address *sa_addr; - struct sadb_protocol *sa_proto; - struct sadb_x_policy sa_pol; - struct sadb_x_sa2 sa_2; - struct sockaddr *ssrc, *sdst, *smask, *dmask, *speer; - struct iovec iov[IOV_CNT]; - int iov_cnt, sd = env->sc_pfkey; - u_int8_t *reply; - ssize_t rlen; - const char *errmsg = NULL; + struct sadb_msg smsg; + struct iked_addr peer; + struct iked_flow flow; + struct sadb_address *sa_addr; + struct sadb_protocol *sa_proto; + struct sadb_x_policy sa_pol; + struct sockaddr *ssrc, *sdst, *smask, *dmask, *speer; + struct iovec iov[IOV_CNT]; + int ret = 0, iov_cnt, sd; + uint8_t *reply; + ssize_t rlen; + const char *errmsg = NULL; + size_t slen; #else - struct iked_addr peer; - struct sadb_address *sa_addr; - struct sockaddr *speer; - struct sadb_x_policy *sa_pol; - struct iked_flow flow; - struct sockaddr *ssrc; + struct iked_addr peer; + struct sadb_address *sa_addr; + struct sockaddr *speer; + struct sadb_x_policy *sa_pol; + struct iked_flow flow; + struct sockaddr *ssrc; #endif - u_int8_t *data = pm->pm_data; - ssize_t len = pm->pm_length; + u_int8_t *data = pm->pm_data; + ssize_t len = pm->pm_length; - if (!env || !data || !len) + if (!env || !data || !len) return 0; - hdr = (struct sadb_msg *)data; + hdr = (struct sadb_msg *)data; - switch (hdr->sadb_msg_type) { - case SADB_ACQUIRE: + switch (hdr->sadb_msg_type) { + case SADB_ACQUIRE: /* Get peer from the acquire message */ if ((sa_addr = pfkey_find_ext(data, len, - SADB_EXT_ADDRESS_DST)) == NULL) { - log_debug("%s: no peer address", __func__); - return 0; + SADB_EXT_ADDRESS_DST)) == NULL) { + log_debug("%s: no peer address", __func__); + return 0; } speer = (struct sockaddr *)(sa_addr + 1); //speer = (struct sockaddr_storage *)(sa_addr + 1); @@ -1912,145 +1919,151 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) peer.addr_port = htons(socket_getport(speer)); memcpy(&peer.addr, speer, sizeof(*speer)); if (socket_af((struct sockaddr *)&peer.addr, - peer.addr_port) == -1) { - log_debug("%s: invalid address", __func__); - return 0; + peer.addr_port) == -1) { + log_debug("%s: invalid address", __func__); + return 0; } log_debug("%s: acquire request (peer %s)", __func__, - print_host(speer, NULL, 0)); + print_host(speer, NULL, 0)); #if defined(_OPENBSD_IPSEC_API_VERSION) - /* Get the matching flow */ - bzero(&flow, sizeof(flow)); - flow.flow_peer = &peer; - bzero(&smsg, sizeof(smsg)); - smsg.sadb_msg_version = PF_KEY_V2; - smsg.sadb_msg_seq = ++sadb_msg_seq; - smsg.sadb_msg_pid = getpid(); - smsg.sadb_msg_len = sizeof(smsg) / 8; - smsg.sadb_msg_type = SADB_X_ASKPOLICY; + /* get the matching flow */ + bzero(&smsg, sizeof(smsg)); + smsg.sadb_msg_version = PF_KEY_V2; + smsg.sadb_msg_seq = ++sadb_msg_seq; + smsg.sadb_msg_pid = getpid(); + smsg.sadb_msg_len = sizeof(smsg) / 8; + smsg.sadb_msg_type = SADB_X_ASKPOLICY; - iov_cnt = 0; + iov_cnt = 0; - iov[iov_cnt].iov_base = &smsg; - iov[iov_cnt].iov_len = sizeof(smsg); - iov_cnt++; + iov[iov_cnt].iov_base = &smsg; + iov[iov_cnt].iov_len = sizeof(smsg); + iov_cnt++; - bzero(&sa_pol, sizeof(sa_pol)); - sa_pol.sadb_x_policy_exttype = SADB_X_EXT_POLICY; - sa_pol.sadb_x_policy_len = sizeof(sa_pol) / 8; - sa_pol.sadb_x_policy_seq = hdr->sadb_msg_seq; + bzero(&sa_pol, sizeof(sa_pol)); + sa_pol.sadb_x_policy_exttype = SADB_X_EXT_POLICY; + sa_pol.sadb_x_policy_len = sizeof(sa_pol) / 8; + sa_pol.sadb_x_policy_seq = hdr->sadb_msg_seq; - iov[iov_cnt].iov_base = &sa_pol; - iov[iov_cnt].iov_len = sizeof(sa_pol); - smsg.sadb_msg_len += sizeof(sa_pol) / 8; - iov_cnt++; + iov[iov_cnt].iov_base = &sa_pol; + iov[iov_cnt].iov_len = sizeof(sa_pol); + smsg.sadb_msg_len += sizeof(sa_pol) / 8; + iov_cnt++; - if (pfkey_write(sd, &smsg, iov, iov_cnt, &reply, &rlen)) { - log_warnx("%s: failed to get a policy", __func__); - return 0; - } + if (pfkey_write(sd, &smsg, iov, iov_cnt, &reply, &rlen)) { + log_warnx("%s: failed to get a policy", __func__); + return (0); + } - if ((sa_addr = pfkey_find_ext(reply, rlen, - SADB_X_EXT_SRC_FLOW)) == NULL) { - errmsg = "flow source address"; - goto out; - } - ssrc = (struct sockaddr_storage *)(sa_addr + 1); - flow.flow_src.addr_af = ssrc->ss_family; - flow.flow_src.addr_port = htons(socket_getport(ssrc)); - memcpy(&flow.flow_src.addr, ssrc, sizeof(*ssrc)); - if (socket_af((struct sockaddr *)&flow.flow_src.addr, - flow.flow_src.addr_port) == -1) { - log_debug("%s: invalid address", __func__); - return 0; - } + if ((sa_addr = pfkey_find_ext(reply, rlen, + SADB_X_EXT_SRC_FLOW)) == NULL) { + errmsg = "flow source address"; + goto out; + } + ssrc = (struct sockaddr *)(sa_addr + 1); + flow.flow_src.addr_af = ssrc->sa_family; + flow.flow_src.addr_port = htons(socket_getport(ssrc)); + if ((slen = ssrc->sa_len) > sizeof(flow.flow_src.addr)) { + log_debug("%s: invalid src address len", __func__); + return (0); + } + memcpy(&flow.flow_src.addr, ssrc, slen); + if (socket_af((struct sockaddr *)&flow.flow_src.addr, + flow.flow_src.addr_port) == -1) { + log_debug("%s: invalid address", __func__); + return (0); + } - if ((sa_addr = pfkey_find_ext(reply, rlen, - SADB_X_EXT_DST_FLOW)) == NULL) { - errmsg = "flow destination address"; - goto out; - } - sdst = (struct sockaddr_storage *)(sa_addr + 1); - flow.flow_dst.addr_af = sdst->ss_family; - flow.flow_dst.addr_port = htons(socket_getport(sdst)); - memcpy(&flow.flow_dst.addr, sdst, sizeof(*sdst)); - if (socket_af((struct sockaddr *)&flow.flow_dst.addr, - flow.flow_dst.addr_port) == -1) { - log_debug("%s: invalid address", __func__); - return 0; - } + if ((sa_addr = pfkey_find_ext(reply, rlen, + SADB_X_EXT_DST_FLOW)) == NULL) { + errmsg = "flow destination address"; + goto out; + } + sdst = (struct sockaddr *)(sa_addr + 1); + flow.flow_dst.addr_af = sdst->sa_family; + flow.flow_dst.addr_port = htons(socket_getport(sdst)); + if ((slen = sdst->sa_len) > sizeof(flow.flow_dst.addr)) { + log_debug("%s: invalid dst address len", __func__); + return (0); + } + memcpy(&flow.flow_dst.addr, sdst, slen); + if (socket_af((struct sockaddr *)&flow.flow_dst.addr, + flow.flow_dst.addr_port) == -1) { + log_debug("%s: invalid address", __func__); + return (0); + } - if ((sa_addr = pfkey_find_ext(reply, rlen, - SADB_X_EXT_SRC_MASK)) == NULL) { - errmsg = "flow source mask"; - goto out; - } - smask = (struct sockaddr_storage *)(sa_addr + 1); - switch (smask->ss_family) { - case AF_INET: - flow.flow_src.addr_mask = - mask2prefixlen((struct sockaddr *)smask); - if (flow.flow_src.addr_mask != 32) - flow.flow_src.addr_net = 1; - break; - case AF_INET6: - flow.flow_src.addr_mask = - mask2prefixlen6((struct sockaddr *)smask); - if (flow.flow_src.addr_mask != 128) - flow.flow_src.addr_net = 1; - break; - default: - log_debug("%s: bad address family", __func__); - free(reply); - return 0; - } + if ((sa_addr = pfkey_find_ext(reply, rlen, + SADB_X_EXT_SRC_MASK)) == NULL) { + errmsg = "flow source mask"; + goto out; + } + smask = (struct sockaddr *)(sa_addr + 1); + switch (smask->sa_family) { + case AF_INET: + flow.flow_src.addr_mask = + mask2prefixlen((struct sockaddr *)smask); + if (flow.flow_src.addr_mask != 32) + flow.flow_src.addr_net = 1; + break; + case AF_INET6: + flow.flow_src.addr_mask = + mask2prefixlen6((struct sockaddr *)smask); + if (flow.flow_src.addr_mask != 128) + flow.flow_src.addr_net = 1; + break; + default: + log_debug("%s: bad address family", __func__); + free(reply); + return (0); + } - if ((sa_addr = pfkey_find_ext(reply, rlen, - SADB_X_EXT_DST_MASK)) == NULL) { - errmsg = "flow destination mask"; - goto out; - } - dmask = (struct sockaddr_storage *)(sa_addr + 1); - switch (dmask->ss_family) { - case AF_INET: - flow.flow_dst.addr_mask = - mask2prefixlen((struct sockaddr *)dmask); - if (flow.flow_src.addr_mask != 32) - flow.flow_src.addr_net = 1; - break; - case AF_INET6: - flow.flow_dst.addr_mask = - mask2prefixlen6((struct sockaddr *)dmask); - if (flow.flow_src.addr_mask != 128) - flow.flow_src.addr_net = 1; - break; - default: - log_debug("%s: bad address family", __func__); - free(reply); - return 0; - } + if ((sa_addr = pfkey_find_ext(reply, rlen, + SADB_X_EXT_DST_MASK)) == NULL) { + errmsg = "flow destination mask"; + goto out; + } + dmask = (struct sockaddr *)(sa_addr + 1); + switch (dmask->sa_family) { + case AF_INET: + flow.flow_dst.addr_mask = + mask2prefixlen((struct sockaddr *)dmask); + if (flow.flow_src.addr_mask != 32) + flow.flow_src.addr_net = 1; + break; + case AF_INET6: + flow.flow_dst.addr_mask = + mask2prefixlen6((struct sockaddr *)dmask); + if (flow.flow_src.addr_mask != 128) + flow.flow_src.addr_net = 1; + break; + default: + log_debug("%s: bad address family", __func__); + free(reply); + return (0); + } - if ((sa_proto = pfkey_find_ext(reply, rlen, - SADB_X_EXT_FLOW_TYPE)) == NULL) { - errmsg = "flow protocol"; - goto out; - } - flow.flow_dir = sa_proto->sadb_protocol_direction; + if ((sa_proto = pfkey_find_ext(reply, rlen, + SADB_X_EXT_FLOW_TYPE)) == NULL) { + errmsg = "flow protocol"; + goto out; + } + flow.flow_dir = sa_proto->sadb_protocol_direction; - log_debug("%s: flow %s from %s/%s to %s/%s via %s", __func__, - flow.flow_dir == IPSP_DIRECTION_IN ? "in" : "out", - print_host(ssrc, NULL, 0), print_host(smask, NULL, 0), - print_host(sdst, NULL, 0), print_host(dmask, NULL, 0), - print_host(speer, NULL, 0)); + log_debug("%s: flow %s from %s/%s to %s/%s via %s", __func__, + flow.flow_dir == IPSP_DIRECTION_IN ? "in" : "out", + print_host(ssrc, NULL, 0), print_host(smask, NULL, 0), + print_host(sdst, NULL, 0), print_host(dmask, NULL, 0), + print_host(speer, NULL, 0)); - ret = ikev2_acquire_sa(env, &flow); + ret = ikev2_acquire_sa(env, &flow); out: - if (errmsg) - log_warnx("%s: %s wasn't found", __func__, errmsg); - free(reply); + if (errmsg) + log_warnx("%s: %s wasn't found", __func__, errmsg); + free(reply); #elif defined(SADB_X_EXT_POLICY) /* * On an upcall from the kernel, reconstruct iked_flow with src @@ -2060,82 +2073,82 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) flow.flow_peer = &peer; flow.flow_dst = peer; if (flow.flow_dst.addr_af == AF_INET) { - flow.flow_dst.addr_mask = 32; + flow.flow_dst.addr_mask = 32; } if ((sa_pol = pfkey_find_ext(data, len, - SADB_X_EXT_POLICY)) == NULL) { - log_debug("%s: no policy extension", __func__); - return 0; + SADB_X_EXT_POLICY)) == NULL) { + log_debug("%s: no policy extension", __func__); + return 0; } if ((sa_addr = pfkey_find_ext(data, len, - SADB_EXT_ADDRESS_SRC)) == NULL) { - log_debug("%s: no src in ext_policy upcall", __func__); - return 0; + SADB_EXT_ADDRESS_SRC)) == NULL) { + log_debug("%s: no src in ext_policy upcall", __func__); + return 0; } ssrc = (struct sockaddr*)(sa_addr + 1); flow.flow_src.addr_af = ssrc->sa_family; flow.flow_src.addr_port = htons(socket_getport(ssrc)); if (flow.flow_src.addr_af == AF_INET) { - flow.flow_src.addr_mask = 32; + flow.flow_src.addr_mask = 32; } memcpy(&flow.flow_src.addr, ssrc, sizeof(*ssrc)); if (socket_af((struct sockaddr *)&flow.flow_src.addr, - flow.flow_src.addr_port) == -1) { - log_debug("%s: invalid address", __func__); - return 0; + flow.flow_src.addr_port) == -1) { + log_debug("%s: invalid address", __func__); + return 0; } log_debug("%s: flow %s from to %s ", __func__, - print_host((struct sockaddr*)&(flow.flow_src.addr), NULL, 0), - print_host((struct sockaddr*)&(flow.flow_dst.addr), NULL, 0)); + print_host((struct sockaddr*)&(flow.flow_src.addr), NULL, 0), + print_host((struct sockaddr*)&(flow.flow_dst.addr), NULL, 0)); ikev2_acquire_sa(env, &flow); #else #warning PFKEYv2 SADB_ACQUIRE not implemented log_debug("%s: SADB_ACQUIRE not yet supported here, ignored", - __func__); + __func__); #endif break; - case SADB_EXPIRE: + case SADB_EXPIRE: if ((sa = pfkey_find_ext(data, len, SADB_EXT_SA)) == NULL) { - log_warnx("%s: SA extension wasn't found", __func__); - return 0; + log_warnx("%s: SA extension wasn't found", __func__); + return 0; } if ((sa_ltime = pfkey_find_ext(data, len, - SADB_EXT_LIFETIME_SOFT)) == NULL && - (sa_ltime = pfkey_find_ext(data, len, - SADB_EXT_LIFETIME_HARD)) == NULL) { - log_warnx("%s: lifetime extension wasn't found", + SADB_EXT_LIFETIME_SOFT)) == NULL && + (sa_ltime = pfkey_find_ext(data, len, + SADB_EXT_LIFETIME_HARD)) == NULL) { + log_warnx("%s: lifetime extension wasn't found", __func__); - return 0; + return 0; } spi.spi = ntohl(sa->sadb_sa_spi); spi.spi_size = 4; switch (hdr->sadb_msg_satype) { case SADB_SATYPE_AH: - spi.spi_protoid = IKEV2_SAPROTO_AH; - break; + spi.spi_protoid = IKEV2_SAPROTO_AH; + break; case SADB_SATYPE_ESP: - spi.spi_protoid = IKEV2_SAPROTO_ESP; - break; + spi.spi_protoid = IKEV2_SAPROTO_ESP; + break; default: - log_warnx("%s: usupported SA type %d spi %s", + log_warnx("%s: usupported SA type %d spi %s", __func__, hdr->sadb_msg_satype, print_spi(spi.spi, spi.spi_size)); - return 0; + return 0; } log_debug("%s: SA %s is expired, pending %s", __func__, - print_spi(spi.spi, spi.spi_size), - sa_ltime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT ? - "rekeying" : "deletion"); + print_spi(spi.spi, spi.spi_size), + sa_ltime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT ? + "rekeying" : "deletion"); - if (sa_ltime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT) - ikev2_rekey_sa(env, &spi); - else - ikev2_drop_sa(env, &spi); - break; - } - return 0; + if (sa_ltime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT) + ikev2_rekey_sa(env, &spi); + else + ikev2_drop_sa(env, &spi); + break; + } + return 0; } From 5dd6e6d8c91a2caf722826a01f787ec6b6ace0aa Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Tue, 14 Jun 2016 09:43:47 +0200 Subject: [PATCH 17/39] Add line breaks to macports example --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 81e2b14..c794000 100644 --- a/README.md +++ b/README.md @@ -56,8 +56,8 @@ also need GNU automake, autoconf (version 2.69 or newer) and libtool. - For example, you can run the following when building on Apple OSX with MacPorts: ``` - ./configure --with-ssl-dir=/opt/local/ - --with-libevent-dir=/opt/local/lib/libevent1/ + ./configure --with-ssl-dir=/opt/local/ \ + --with-libevent-dir=/opt/local/lib/libevent1/ \ --prefix=/opt/local/ ``` 5. Type `make` to build all parts of OpenIKED including iked and ikectl. From 07a2a8bc4dd814ad123cf285a4a9da33fb857fa3 Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Tue, 14 Jun 2016 10:15:41 +0200 Subject: [PATCH 18/39] Include sys-queue.h and sys-tree.h locally again --- iked/ca.c | 2 +- iked/config.c | 2 +- iked/control.c | 4 ++-- iked/crypto.c | 2 +- iked/eap.c | 2 +- iked/iked.c | 2 +- iked/iked.h | 4 ++-- iked/ikev1.c | 2 +- iked/ikev2.c | 2 +- iked/ikev2_msg.c | 2 +- iked/ikev2_pld.c | 2 +- iked/imsg_util.c | 2 +- iked/log.c | 4 ++-- iked/ocsp.c | 2 +- iked/parse.y | 2 +- iked/pfkey.c | 2 +- iked/policy.c | 4 ++-- iked/proc.c | 4 ++-- iked/timer.c | 2 +- iked/util.c | 2 +- 20 files changed, 25 insertions(+), 25 deletions(-) diff --git a/iked/ca.c b/iked/ca.c index 43a5e1b..cc507aa 100644 --- a/iked/ca.c +++ b/iked/ca.c @@ -16,7 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include + #include #include #include diff --git a/iked/config.c b/iked/config.c index 9ff9a3f..65c6843 100644 --- a/iked/config.c +++ b/iked/config.c @@ -16,7 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include + #include #include #include diff --git a/iked/control.c b/iked/control.c index 3932008..e05f6f1 100644 --- a/iked/control.c +++ b/iked/control.c @@ -17,11 +17,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include + #include #include #include -#include + #include diff --git a/iked/crypto.c b/iked/crypto.c index 2fd6f35..9c5a886 100644 --- a/iked/crypto.c +++ b/iked/crypto.c @@ -17,7 +17,7 @@ */ #include /* roundup */ -#include + #include #include diff --git a/iked/eap.c b/iked/eap.c index 5617641..0648e0f 100644 --- a/iked/eap.c +++ b/iked/eap.c @@ -16,7 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include + #include #include #include diff --git a/iked/iked.c b/iked/iked.c index 4f9f997..80df98c 100644 --- a/iked/iked.c +++ b/iked/iked.c @@ -16,7 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include + #include #include #include diff --git a/iked/iked.h b/iked/iked.h index 6140c9f..48a63c5 100644 --- a/iked/iked.h +++ b/iked/iked.h @@ -17,8 +17,8 @@ */ #include -#include -#include + + #include #include "imsg.h" diff --git a/iked/ikev1.c b/iked/ikev1.c index 7d10e86..6073443 100644 --- a/iked/ikev1.c +++ b/iked/ikev1.c @@ -22,7 +22,7 @@ * XXX or remove this file and ikev1 from the iked tree. */ -#include + #include #include #include diff --git a/iked/ikev2.c b/iked/ikev2.c index 4ded7f2..9b1da64 100644 --- a/iked/ikev2.c +++ b/iked/ikev2.c @@ -17,7 +17,7 @@ */ #include /* roundup */ -#include + #include #include #include diff --git a/iked/ikev2_msg.c b/iked/ikev2_msg.c index 399273d..5d87371 100644 --- a/iked/ikev2_msg.c +++ b/iked/ikev2_msg.c @@ -17,7 +17,7 @@ */ #include /* roundup */ -#include + #include #include #include diff --git a/iked/ikev2_pld.c b/iked/ikev2_pld.c index 8326a05..b282293 100644 --- a/iked/ikev2_pld.c +++ b/iked/ikev2_pld.c @@ -17,7 +17,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include + #include #include #include diff --git a/iked/imsg_util.c b/iked/imsg_util.c index f883217..e56f832 100644 --- a/iked/imsg_util.c +++ b/iked/imsg_util.c @@ -16,7 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include + #include #include diff --git a/iked/log.c b/iked/log.c index a514efd..f3727a4 100644 --- a/iked/log.c +++ b/iked/log.c @@ -16,9 +16,9 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include + #include -#include + #include #include diff --git a/iked/ocsp.c b/iked/ocsp.c index 76827ab..4e9c7a7 100644 --- a/iked/ocsp.c +++ b/iked/ocsp.c @@ -15,7 +15,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include + #include #include #include diff --git a/iked/parse.y b/iked/parse.y index 4337be6..0d76ff8 100644 --- a/iked/parse.y +++ b/iked/parse.y @@ -24,7 +24,7 @@ %{ #include #include -#include + #include #include #include diff --git a/iked/pfkey.c b/iked/pfkey.c index cdbf610..346b6dc 100644 --- a/iked/pfkey.c +++ b/iked/pfkey.c @@ -19,7 +19,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include + #include #include diff --git a/iked/policy.c b/iked/policy.c index fcfd6c0..7bd5e18 100644 --- a/iked/policy.c +++ b/iked/policy.c @@ -17,10 +17,10 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include + #include #include -#include + #include #include diff --git a/iked/proc.c b/iked/proc.c index 2e1fdf6..71a9f54 100644 --- a/iked/proc.c +++ b/iked/proc.c @@ -17,10 +17,10 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include + #include #include -#include + #include #include diff --git a/iked/timer.c b/iked/timer.c index bf1514f..3823b62 100644 --- a/iked/timer.c +++ b/iked/timer.c @@ -16,7 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include + #include #include diff --git a/iked/util.c b/iked/util.c index 5ed8b6e..6e959ea 100644 --- a/iked/util.c +++ b/iked/util.c @@ -17,7 +17,7 @@ */ #include -#include + #include #include From d95baaec228dd12002d46cb1976775988b804ee9 Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Tue, 14 Jun 2016 10:30:45 +0200 Subject: [PATCH 19/39] Add more openbsd-compat to compile on macOS --- ikectl/ikectl.c | 4 +- ikectl/parser.c | 4 +- openbsd-compat/Makefile.am | 9 +- openbsd-compat/bsd-arc4random.c | 233 ++++++++++++++++++++++++++++++++ openbsd-compat/bsd-closefrom.c | 89 ++++++++++++ openbsd-compat/chacha_private.h | 222 ++++++++++++++++++++++++++++++ openbsd-compat/daemon.c | 82 +++++++++++ openbsd-compat/defines.h | 15 ++ openbsd-compat/fgetln.c | 63 +++++++++ openbsd-compat/getopt.c | 123 +++++++++++++++++ openbsd-compat/openbsd-compat.h | 44 ++++++ openbsd-compat/setproctitle.c | 163 ++++++++++++++++++++++ openbsd-compat/strlcat.c | 62 +++++++++ openbsd-compat/strlcpy.c | 58 ++++++++ openbsd-compat/sys-tree.h | 2 +- openbsd-compat/vis.c | 225 ++++++++++++++++++++++++++++++ openbsd-compat/vis.h | 98 ++++++++++++++ 17 files changed, 1487 insertions(+), 9 deletions(-) create mode 100644 openbsd-compat/bsd-arc4random.c create mode 100644 openbsd-compat/bsd-closefrom.c create mode 100644 openbsd-compat/chacha_private.h create mode 100644 openbsd-compat/daemon.c create mode 100644 openbsd-compat/fgetln.c create mode 100644 openbsd-compat/getopt.c create mode 100644 openbsd-compat/setproctitle.c create mode 100644 openbsd-compat/strlcat.c create mode 100644 openbsd-compat/strlcpy.c create mode 100644 openbsd-compat/vis.c create mode 100644 openbsd-compat/vis.h diff --git a/ikectl/ikectl.c b/ikectl/ikectl.c index 5e85ab8..50368e9 100644 --- a/ikectl/ikectl.c +++ b/ikectl/ikectl.c @@ -21,9 +21,9 @@ #include #include -#include + #include -#include + #include #include diff --git a/ikectl/parser.c b/ikectl/parser.c index af88b1d..147300e 100644 --- a/ikectl/parser.c +++ b/ikectl/parser.c @@ -20,8 +20,8 @@ #include #include -#include -#include + + #include #include diff --git a/openbsd-compat/Makefile.am b/openbsd-compat/Makefile.am index 6817048..f731f4e 100644 --- a/openbsd-compat/Makefile.am +++ b/openbsd-compat/Makefile.am @@ -1,12 +1,13 @@ noinst_LIBRARIES= libopenbsd-compat.a libopenbsd_compat_a_SOURCES= \ - explicit-bzero.c \ - imsg.c imsg-buffer.c \ - reallocarray.c setresguid.c strtonum.c + bsd-arc4random.c bsd-closefrom.c \ + daemon.c explicit-bzero.c fgetln.c getopt.c imsg.c \ + imsg-buffer.c reallocarray.c setresguid.c setproctitle.c \ + strlcat.c strlcpy.c strtonum.c vis.c EXTRA_DIST= defines.h imsg.h includes.h \ - openbsd-compat.h sys-queue.h sys-tree.h + openbsd-compat.h sys-queue.h sys-tree.h vis.h CPPFLAGS= -include $(top_srcdir)/openbsd-compat/includes.h \ -I$(top_srcdir) -I$(top_srcdir)/openbsd-compat \ diff --git a/openbsd-compat/bsd-arc4random.c b/openbsd-compat/bsd-arc4random.c new file mode 100644 index 0000000..a7e562b --- /dev/null +++ b/openbsd-compat/bsd-arc4random.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 1996, David Mazieres + * Copyright (c) 2008, Damien Miller + * Copyright (c) 2013, Markus Friedl + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * ChaCha based random number generator for OpenBSD. + */ + +#include "includes.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define KEYSTREAM_ONLY +#include "chacha_private.h" + +#ifdef __GNUC__ +#define inline __inline +#else /* !__GNUC__ */ +#define inline +#endif /* !__GNUC__ */ + +#define KEYSZ 32 +#define IVSZ 8 +#define BLOCKSZ 64 +#define RSBUFSZ (16*BLOCKSZ) +static int rs_initialized; +static pid_t rs_stir_pid; +static chacha_ctx rs; /* chacha context for random keystream */ +static u_char rs_buf[RSBUFSZ]; /* keystream blocks */ +static size_t rs_have; /* valid bytes at end of rs_buf */ +static size_t rs_count; /* bytes till reseed */ + +static inline void _rs_rekey(u_char *dat, size_t datlen); +static inline void _rs_random_buf(void *_buf, size_t n); + +static inline void +_rs_init(u_char *buf, size_t n) +{ + if (n < KEYSZ + IVSZ) + return; + chacha_keysetup(&rs, buf, KEYSZ * 8, 0); + chacha_ivsetup(&rs, buf + KEYSZ); +} + +static void +_rs_stir(void) +{ + size_t len; + u_char rnd[KEYSZ + IVSZ]; + + len = sizeof(rnd); + + _rs_random_buf(rnd, len); + if (!rs_initialized) { + rs_initialized = 1; + _rs_init(rnd, sizeof(rnd)); + } else + _rs_rekey(rnd, sizeof(rnd)); + memset(rnd, 0, sizeof(rnd)); + + /* invalidate rs_buf */ + rs_have = 0; + memset(rs_buf, 0, RSBUFSZ); + + rs_count = 1600000; +} + +static inline void +_rs_stir_if_needed(size_t len) +{ + pid_t pid = getpid(); + + if (rs_count <= len || !rs_initialized || rs_stir_pid != pid) { + rs_stir_pid = pid; + _rs_stir(); + } else + rs_count -= len; +} + +static inline void +_rs_rekey(u_char *dat, size_t datlen) +{ +#ifndef KEYSTREAM_ONLY + memset(rs_buf, 0,RSBUFSZ); +#endif + /* fill rs_buf with the keystream */ + chacha_encrypt_bytes(&rs, rs_buf, rs_buf, RSBUFSZ); + /* mix in optional user provided data */ + if (dat) { + size_t i, m; + + m = MIN(datlen, KEYSZ + IVSZ); + for (i = 0; i < m; i++) + rs_buf[i] ^= dat[i]; + } + /* immediately reinit for backtracking resistance */ + _rs_init(rs_buf, KEYSZ + IVSZ); + memset(rs_buf, 0, KEYSZ + IVSZ); + rs_have = RSBUFSZ - KEYSZ - IVSZ; +} + +static inline void +_rs_random_buf(void *_buf, size_t n) +{ + u_char *buf = (u_char *)_buf; + size_t m; + + while (n > 0) { + if (rs_have > 0) { + m = MIN(n, rs_have); + memcpy(buf, rs_buf + RSBUFSZ - rs_have, m); + memset(rs_buf + RSBUFSZ - rs_have, 0, m); + buf += m; + n -= m; + rs_have -= m; + } + if (rs_have == 0) + _rs_rekey(NULL, 0); + } +} + +static inline void +_rs_random_u32(u_int32_t *val) +{ + _rs_stir_if_needed(sizeof(*val)); + if (rs_have < sizeof(*val)) + _rs_rekey(NULL, 0); + memcpy(val, rs_buf + RSBUFSZ - rs_have, sizeof(*val)); + memset(rs_buf + RSBUFSZ - rs_have, 0, sizeof(*val)); + rs_have -= sizeof(*val); + return; +} + +#ifndef HAVE_ARC4RANDOM +void +arc4random_stir(void) +{ + _rs_stir(); +} + +void +arc4random_addrandom(u_char *dat, int datlen) +{ + int m; + + if (!rs_initialized) + _rs_stir(); + while (datlen > 0) { + m = MIN(datlen, KEYSZ + IVSZ); + _rs_rekey(dat, m); + dat += m; + datlen -= m; + } +} + +u_int32_t +arc4random(void) +{ + u_int32_t val; + + _rs_random_u32(&val); + return val; +} +#endif /* !HAVE_ARC4RANDOM */ + +#ifndef HAVE_ARC4RANDOM_BUF +void +arc4random_buf(void *buf, size_t n) +{ + _rs_stir_if_needed(n); + _rs_random_buf(buf, n); +} +#endif /* !HAVE_ARC4RANDOM_BUF */ + +#ifndef HAVE_ARC4RANDOM_UNIFORM +/* + * Calculate a uniformly distributed random number less than upper_bound + * avoiding "modulo bias". + * + * Uniformity is achieved by generating new random numbers until the one + * returned is outside the range [0, 2**32 % upper_bound). This + * guarantees the selected random number will be inside + * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) + * after reduction modulo upper_bound. + */ +u_int32_t +arc4random_uniform(u_int32_t upper_bound) +{ + u_int32_t r, min; + + if (upper_bound < 2) + return 0; + + /* 2**32 % x == (2**32 - x) % x */ + min = -upper_bound % upper_bound; + + /* + * This could theoretically loop forever but each retry has + * p > 0.5 (worst case, usually far better) of selecting a + * number inside the range we need, so it should rarely need + * to re-roll. + */ + for (;;) { + r = arc4random(); + if (r >= min) + break; + } + + return r % upper_bound; +} +#endif /* !HAVE_ARC4RANDOM_UNIFORM */ diff --git a/openbsd-compat/bsd-closefrom.c b/openbsd-compat/bsd-closefrom.c new file mode 100644 index 0000000..8598970 --- /dev/null +++ b/openbsd-compat/bsd-closefrom.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2004-2005 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#ifndef HAVE_CLOSEFROM + +#include +#include +#include +#include +#ifdef HAVE_FCNTL_H +# include +#endif +#include +#include +#include +#include +#include + +#if 0 +__unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $"; +#endif /* lint */ + +/* + * Close all file descriptors greater than or equal to lowfd. + */ +#ifdef HAVE_FCNTL_CLOSEM +void +closefrom(int lowfd) +{ + (void) fcntl(lowfd, F_CLOSEM, 0); +} +#else +void +closefrom(int lowfd) +{ + long fd, maxfd; +#if defined(HAVE_DIRFD) && defined(HAVE_PROC_PID) + char fdpath[PATH_MAX], *endp; + struct dirent *dent; + DIR *dirp; + int len; + + /* Check for a /proc/$$/fd directory. */ + len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid()); + if (len > 0 && (size_t)len <= sizeof(fdpath) && (dirp = opendir(fdpath))) { + while ((dent = readdir(dirp)) != NULL) { + fd = strtol(dent->d_name, &endp, 10); + if (dent->d_name != endp && *endp == '\0' && + fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp)) + (void) close((int) fd); + } + (void) closedir(dirp); + } else +#endif + { + /* + * Fall back on sysconf() or getdtablesize(). We avoid checking + * resource limits since it is possible to open a file descriptor + * and then drop the rlimit such that it is below the open fd. + */ +#ifdef HAVE_SYSCONF + maxfd = sysconf(_SC_OPEN_MAX); +#else + maxfd = getdtablesize(); +#endif /* HAVE_SYSCONF */ + if (maxfd < 0) + maxfd = OPEN_MAX; + + for (fd = lowfd; fd < maxfd; fd++) + (void) close((int) fd); + } +} +#endif /* !HAVE_FCNTL_CLOSEM */ +#endif /* HAVE_CLOSEFROM */ diff --git a/openbsd-compat/chacha_private.h b/openbsd-compat/chacha_private.h new file mode 100644 index 0000000..7c3680f --- /dev/null +++ b/openbsd-compat/chacha_private.h @@ -0,0 +1,222 @@ +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +/* $OpenBSD: chacha_private.h,v 1.2 2013/10/04 07:02:27 djm Exp $ */ + +typedef unsigned char u8; +typedef unsigned int u32; + +typedef struct +{ + u32 input[16]; /* could be compressed */ +} chacha_ctx; + +#define U8C(v) (v##U) +#define U32C(v) (v##U) + +#define U8V(v) ((u8)(v) & U8C(0xFF)) +#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) + +#define ROTL32(v, n) \ + (U32V((v) << (n)) | ((v) >> (32 - (n)))) + +#define U8TO32_LITTLE(p) \ + (((u32)((p)[0]) ) | \ + ((u32)((p)[1]) << 8) | \ + ((u32)((p)[2]) << 16) | \ + ((u32)((p)[3]) << 24)) + +#define U32TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + } while (0) + +#define ROTATE(v,c) (ROTL32(v,c)) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +#define QUARTERROUND(a,b,c,d) \ + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + +static const char sigma[16] = "expand 32-byte k"; +static const char tau[16] = "expand 16-byte k"; + +static void +chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ivbits) +{ + const char *constants; + + x->input[4] = U8TO32_LITTLE(k + 0); + x->input[5] = U8TO32_LITTLE(k + 4); + x->input[6] = U8TO32_LITTLE(k + 8); + x->input[7] = U8TO32_LITTLE(k + 12); + if (kbits == 256) { /* recommended */ + k += 16; + constants = sigma; + } else { /* kbits == 128 */ + constants = tau; + } + x->input[8] = U8TO32_LITTLE(k + 0); + x->input[9] = U8TO32_LITTLE(k + 4); + x->input[10] = U8TO32_LITTLE(k + 8); + x->input[11] = U8TO32_LITTLE(k + 12); + x->input[0] = U8TO32_LITTLE(constants + 0); + x->input[1] = U8TO32_LITTLE(constants + 4); + x->input[2] = U8TO32_LITTLE(constants + 8); + x->input[3] = U8TO32_LITTLE(constants + 12); +} + +static void +chacha_ivsetup(chacha_ctx *x,const u8 *iv) +{ + x->input[12] = 0; + x->input[13] = 0; + x->input[14] = U8TO32_LITTLE(iv + 0); + x->input[15] = U8TO32_LITTLE(iv + 4); +} + +static void +chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) +{ + u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + u8 *ctarget = NULL; + u8 tmp[64]; + u_int i; + + if (!bytes) return; + + j0 = x->input[0]; + j1 = x->input[1]; + j2 = x->input[2]; + j3 = x->input[3]; + j4 = x->input[4]; + j5 = x->input[5]; + j6 = x->input[6]; + j7 = x->input[7]; + j8 = x->input[8]; + j9 = x->input[9]; + j10 = x->input[10]; + j11 = x->input[11]; + j12 = x->input[12]; + j13 = x->input[13]; + j14 = x->input[14]; + j15 = x->input[15]; + + for (;;) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) tmp[i] = m[i]; + m = tmp; + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = 20;i > 0;i -= 2) { + QUARTERROUND( x0, x4, x8,x12) + QUARTERROUND( x1, x5, x9,x13) + QUARTERROUND( x2, x6,x10,x14) + QUARTERROUND( x3, x7,x11,x15) + QUARTERROUND( x0, x5,x10,x15) + QUARTERROUND( x1, x6,x11,x12) + QUARTERROUND( x2, x7, x8,x13) + QUARTERROUND( x3, x4, x9,x14) + } + x0 = PLUS(x0,j0); + x1 = PLUS(x1,j1); + x2 = PLUS(x2,j2); + x3 = PLUS(x3,j3); + x4 = PLUS(x4,j4); + x5 = PLUS(x5,j5); + x6 = PLUS(x6,j6); + x7 = PLUS(x7,j7); + x8 = PLUS(x8,j8); + x9 = PLUS(x9,j9); + x10 = PLUS(x10,j10); + x11 = PLUS(x11,j11); + x12 = PLUS(x12,j12); + x13 = PLUS(x13,j13); + x14 = PLUS(x14,j14); + x15 = PLUS(x15,j15); + +#ifndef KEYSTREAM_ONLY + x0 = XOR(x0,U8TO32_LITTLE(m + 0)); + x1 = XOR(x1,U8TO32_LITTLE(m + 4)); + x2 = XOR(x2,U8TO32_LITTLE(m + 8)); + x3 = XOR(x3,U8TO32_LITTLE(m + 12)); + x4 = XOR(x4,U8TO32_LITTLE(m + 16)); + x5 = XOR(x5,U8TO32_LITTLE(m + 20)); + x6 = XOR(x6,U8TO32_LITTLE(m + 24)); + x7 = XOR(x7,U8TO32_LITTLE(m + 28)); + x8 = XOR(x8,U8TO32_LITTLE(m + 32)); + x9 = XOR(x9,U8TO32_LITTLE(m + 36)); + x10 = XOR(x10,U8TO32_LITTLE(m + 40)); + x11 = XOR(x11,U8TO32_LITTLE(m + 44)); + x12 = XOR(x12,U8TO32_LITTLE(m + 48)); + x13 = XOR(x13,U8TO32_LITTLE(m + 52)); + x14 = XOR(x14,U8TO32_LITTLE(m + 56)); + x15 = XOR(x15,U8TO32_LITTLE(m + 60)); +#endif + + j12 = PLUSONE(j12); + if (!j12) { + j13 = PLUSONE(j13); + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } + + U32TO8_LITTLE(c + 0,x0); + U32TO8_LITTLE(c + 4,x1); + U32TO8_LITTLE(c + 8,x2); + U32TO8_LITTLE(c + 12,x3); + U32TO8_LITTLE(c + 16,x4); + U32TO8_LITTLE(c + 20,x5); + U32TO8_LITTLE(c + 24,x6); + U32TO8_LITTLE(c + 28,x7); + U32TO8_LITTLE(c + 32,x8); + U32TO8_LITTLE(c + 36,x9); + U32TO8_LITTLE(c + 40,x10); + U32TO8_LITTLE(c + 44,x11); + U32TO8_LITTLE(c + 48,x12); + U32TO8_LITTLE(c + 52,x13); + U32TO8_LITTLE(c + 56,x14); + U32TO8_LITTLE(c + 60,x15); + + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) ctarget[i] = c[i]; + } + x->input[12] = j12; + x->input[13] = j13; + return; + } + bytes -= 64; + c += 64; +#ifndef KEYSTREAM_ONLY + m += 64; +#endif + } +} diff --git a/openbsd-compat/daemon.c b/openbsd-compat/daemon.c new file mode 100644 index 0000000..3efe14c --- /dev/null +++ b/openbsd-compat/daemon.c @@ -0,0 +1,82 @@ +/* $OpenBSD: daemon.c,v 1.6 2005/08/08 08:05:33 espie Exp $ */ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* OPENBSD ORIGINAL: lib/libc/gen/daemon.c */ + +#include "includes.h" + +#ifndef HAVE_DAEMON + +#include + +#ifdef HAVE_SYS_STAT_H +# include +#endif + +#ifdef HAVE_FCNTL_H +# include +#endif + +#ifdef HAVE_UNISTD_H +# include +#endif + +int +daemon(int nochdir, int noclose) +{ + int fd; + + switch (fork()) { + case -1: + return (-1); + case 0: + break; + default: + _exit(0); + } + + if (setsid() == -1) + return (-1); + + if (!nochdir) + (void)chdir("/"); + + if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { + (void)dup2(fd, STDIN_FILENO); + (void)dup2(fd, STDOUT_FILENO); + (void)dup2(fd, STDERR_FILENO); + if (fd > 2) + (void)close (fd); + } + return (0); +} + +#endif /* !HAVE_DAEMON */ + diff --git a/openbsd-compat/defines.h b/openbsd-compat/defines.h index 3eb830a..78a5e90 100644 --- a/openbsd-compat/defines.h +++ b/openbsd-compat/defines.h @@ -625,6 +625,21 @@ struct sadb_sa_natt { # define HAVE_GETADDRINFO #endif +#ifndef HAVE_GETOPT_OPTRESET +# undef getopt +# undef opterr +# undef optind +# undef optopt +# undef optreset +# undef optarg +# define getopt(ac, av, o) BSDgetopt(ac, av, o) +# define opterr BSDopterr +# define optind BSDoptind +# define optopt BSDoptopt +# define optreset BSDoptreset +# define optarg BSDoptarg +#endif + #if defined(BROKEN_GETADDRINFO) && defined(HAVE_GETADDRINFO) # undef HAVE_GETADDRINFO #endif diff --git a/openbsd-compat/fgetln.c b/openbsd-compat/fgetln.c new file mode 100644 index 0000000..c7fef41 --- /dev/null +++ b/openbsd-compat/fgetln.c @@ -0,0 +1,63 @@ +/* $OpenBSD: util.c,v 1.23 2007/09/17 09:28:36 espie Exp $ */ +/* $NetBSD: util.c,v 1.10 1996/12/31 17:56:04 christos Exp $ */ + +/* + * Copyright (c) 2001 Marc Espie. + * + * 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 OPENBSD PROJECT AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD + * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* OPENBSD ORIGINAL: usr.bin/make/util.c */ + +#include "includes.h" + +#ifndef HAVE_FGETLN + +#include + +char * +fgetln(stream, len) + FILE *stream; + size_t *len; +{ + static char *buffer = NULL; + static size_t buflen = 0; + + if (buflen == 0) { + buflen = 512; + if ((buffer = malloc(buflen+1)) == NULL) + err(255, "fatal: malloc: out of memory"); + } + if (fgets(buffer, buflen+1, stream) == NULL) + return NULL; + *len = strlen(buffer); + while (*len == buflen && buffer[*len-1] != '\n') { + if ((buffer = realloc(buffer, 2*buflen + 1)) == NULL) + err(255, "fatal: realloc: out of memory"); + if (fgets(buffer + buflen, buflen + 1, stream) == NULL) + return NULL; + *len += strlen(buffer + buflen); + buflen *= 2; + } + return buffer; +} +#endif diff --git a/openbsd-compat/getopt.c b/openbsd-compat/getopt.c new file mode 100644 index 0000000..5450e43 --- /dev/null +++ b/openbsd-compat/getopt.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* OPENBSD ORIGINAL: lib/libc/stdlib/getopt.c */ + +#include "includes.h" +#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET) + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: getopt.c,v 1.5 2003/06/02 20:18:37 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include + +int BSDopterr = 1, /* if error message should be printed */ + BSDoptind = 1, /* index into parent argv vector */ + BSDoptopt, /* character checked for validity */ + BSDoptreset; /* reset getopt */ +char *BSDoptarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +BSDgetopt(nargc, nargv, ostr) + int nargc; + char * const *nargv; + const char *ostr; +{ + extern char *__progname; + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (ostr == NULL) + return (-1); + + if (BSDoptreset || !*place) { /* update scanning pointer */ + BSDoptreset = 0; + if (BSDoptind >= nargc || *(place = nargv[BSDoptind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++BSDoptind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((BSDoptopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, BSDoptopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (BSDoptopt == (int)'-') + return (-1); + if (!*place) + ++BSDoptind; + if (BSDopterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", __progname, BSDoptopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + BSDoptarg = NULL; + if (!*place) + ++BSDoptind; + } + else { /* need an argument */ + if (*place) /* no white space */ + BSDoptarg = place; + else if (nargc <= ++BSDoptind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (BSDopterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + __progname, BSDoptopt); + return (BADCH); + } + else /* white space */ + BSDoptarg = nargv[BSDoptind]; + place = EMSG; + ++BSDoptind; + } + return (BSDoptopt); /* dump back option letter */ +} + +#endif /* !defined(HAVE_GETOPT) || !defined(HAVE_OPTRESET) */ diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h index 9dc43b0..2a95c20 100644 --- a/openbsd-compat/openbsd-compat.h +++ b/openbsd-compat/openbsd-compat.h @@ -51,6 +51,7 @@ #include "sys-queue.h" #include "sys-tree.h" +#include "vis.h" #ifdef HAVE_SYS_TIME_H #include @@ -91,6 +92,19 @@ # define SET_STORAGE_LEN(X, Y) (void) 0 #endif + +#ifndef HAVE_CLOSEFROM +void closefrom(int); +#endif + +#ifndef HAVE_STRLCPY +size_t strlcpy(char *dst, const char *src, size_t size); +#endif + +#ifndef HAVE_STRLCAT +size_t strlcat(char *dst, const char *src, size_t size); +#endif + #ifndef HAVE_STRMODE void strmode(int mode, char *p); #endif @@ -103,6 +117,11 @@ char *dirname(const char *path); char *strsep(char **stringp, const char *delim); #endif +#ifndef HAVE_SETPROCTITLE +void setproctitle(const char *fmt, ...); +void compat_init_setproctitle(int argc, char *argv[]); +#endif + #ifndef HAVE_SETRESGID int setresgid(uid_t rgid, uid_t egid, uid_t sgid); #endif @@ -111,10 +130,35 @@ int setresgid(uid_t rgid, uid_t egid, uid_t sgid); int setresuid(uid_t ruid, uid_t euid, uid_t suid); #endif +#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET) +int BSDgetopt(int argc, char * const *argv, const char *opts); +char *BSDoptarg; /* argument associated with option */ +int BSDoptind; /* index into parent argv vector */ +#endif + #ifndef HAVE_GETPEEREID int getpeereid(int , uid_t *, gid_t *); #endif +#ifndef HAVE_ARC4RANDOM +unsigned int arc4random(void); +void arc4random_stir(void); +#endif /* !HAVE_ARC4RANDOM */ + +#ifndef HAVE_ARC4RANDOM_BUF +void arc4random_buf(void *, size_t); +#endif + +#ifndef HAVE_ARC4RANDOM_UNIFORM +u_int32_t arc4random_uniform(u_int32_t); +#endif + +#ifndef HAVE_FGETLN +#include +#include +char * fgetln(FILE *stream, size_t *len); +#endif + #ifndef HAVE_FPARSELN char * fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags); #endif diff --git a/openbsd-compat/setproctitle.c b/openbsd-compat/setproctitle.c new file mode 100644 index 0000000..40a6737 --- /dev/null +++ b/openbsd-compat/setproctitle.c @@ -0,0 +1,163 @@ +/* Based on conf.c from UCB sendmail 8.8.8 */ + +/* + * Copyright 2003 Damien Miller + * Copyright (c) 1983, 1995-1997 Eric P. Allman + * Copyright (c) 1988, 1993 + * The Regents of the University of California. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef HAVE_SETPROCTITLE + +#include +#include +#include +#include +#ifdef HAVE_SYS_PSTAT_H +#include +#endif +#include + +#include + +#define SPT_NONE 0 /* don't use it at all */ +#define SPT_PSTAT 1 /* use pstat(PSTAT_SETCMD, ...) */ +#define SPT_REUSEARGV 2 /* cover argv with title information */ + +#ifndef SPT_TYPE +# define SPT_TYPE SPT_NONE +#endif + +#ifndef SPT_PADCHAR +# define SPT_PADCHAR '\0' +#endif + +#if SPT_TYPE == SPT_REUSEARGV +static char *argv_start = NULL; +static size_t argv_env_len = 0; +#endif + +#endif /* HAVE_SETPROCTITLE */ + +void +compat_init_setproctitle(int argc, char *argv[]) +{ +#if defined(SPT_TYPE) && SPT_TYPE == SPT_REUSEARGV + extern char **environ; + char *lastargv = NULL; + char **envp = environ; + int i; + + /* + * NB: This assumes that argv has already been copied out of the + * way. This is true for sshd, but may not be true for other + * programs. Beware. + */ + + if (argc == 0 || argv[0] == NULL) + return; + + /* Fail if we can't allocate room for the new environment */ + for (i = 0; envp[i] != NULL; i++) + ; + if ((environ = calloc(i + 1, sizeof(*environ))) == NULL) { + environ = envp; /* put it back */ + return; + } + + /* + * Find the last argv string or environment variable within + * our process memory area. + */ + for (i = 0; i < argc; i++) { + if (lastargv == NULL || lastargv + 1 == argv[i]) + lastargv = argv[i] + strlen(argv[i]); + } + for (i = 0; envp[i] != NULL; i++) { + if (lastargv + 1 == envp[i]) + lastargv = envp[i] + strlen(envp[i]); + } + + argv[1] = NULL; + argv_start = argv[0]; + argv_env_len = lastargv - argv[0] - 1; + + /* + * Copy environment + * XXX - will truncate env on strdup fail + */ + for (i = 0; envp[i] != NULL; i++) + environ[i] = strdup(envp[i]); + environ[i] = NULL; +#endif /* SPT_REUSEARGV */ +} + +#ifndef HAVE_SETPROCTITLE +void +setproctitle(const char *fmt, ...) +{ +#if SPT_TYPE != SPT_NONE + va_list ap; + char buf[1024], ptitle[1024]; + size_t len; + extern char *__progname; +#if SPT_TYPE == SPT_PSTAT + union pstun pst; +#endif + +#if SPT_TYPE == SPT_REUSEARGV + if (argv_env_len <= 0) + return; +#endif + + strlcpy(buf, __progname, sizeof(buf)); + + va_start(ap, fmt); + if (fmt != NULL) { + len = strlcat(buf, ": ", sizeof(buf)); + if (len < sizeof(buf)) + vsnprintf(buf + len, sizeof(buf) - len , fmt, ap); + } + va_end(ap); + strnvis(ptitle, buf, sizeof(ptitle), + VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL); + +#if SPT_TYPE == SPT_PSTAT + pst.pst_command = ptitle; + pstat(PSTAT_SETCMD, pst, strlen(ptitle), 0, 0); +#elif SPT_TYPE == SPT_REUSEARGV +/* debug("setproctitle: copy \"%s\" into len %d", + buf, argv_env_len); */ + len = strlcpy(argv_start, ptitle, argv_env_len); + for(; len < argv_env_len; len++) + argv_start[len] = SPT_PADCHAR; +#endif + +#endif /* SPT_NONE */ +} + +#endif /* HAVE_SETPROCTITLE */ diff --git a/openbsd-compat/strlcat.c b/openbsd-compat/strlcat.c new file mode 100644 index 0000000..bcc1b61 --- /dev/null +++ b/openbsd-compat/strlcat.c @@ -0,0 +1,62 @@ +/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* OPENBSD ORIGINAL: lib/libc/string/strlcat.c */ + +#include "includes.h" +#ifndef HAVE_STRLCAT + +#include +#include + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +strlcat(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} + +#endif /* !HAVE_STRLCAT */ diff --git a/openbsd-compat/strlcpy.c b/openbsd-compat/strlcpy.c new file mode 100644 index 0000000..b4b1b60 --- /dev/null +++ b/openbsd-compat/strlcpy.c @@ -0,0 +1,58 @@ +/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* OPENBSD ORIGINAL: lib/libc/string/strlcpy.c */ + +#include "includes.h" +#ifndef HAVE_STRLCPY + +#include +#include + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +strlcpy(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0) { + while (--n != 0) { + if ((*d++ = *s++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} + +#endif /* !HAVE_STRLCPY */ diff --git a/openbsd-compat/sys-tree.h b/openbsd-compat/sys-tree.h index 4959548..cadfb55 100644 --- a/openbsd-compat/sys-tree.h +++ b/openbsd-compat/sys-tree.h @@ -149,7 +149,7 @@ static __inline struct type * \ name##_SPLAY_MIN_MAX(struct name *head, int val) \ { \ name##_SPLAY_MINMAX(head, val); \ - return (SPLAY_ROOT(head)); \ + return (SPLAY_ROOT(head)); \ } /* Main splay operation. diff --git a/openbsd-compat/vis.c b/openbsd-compat/vis.c new file mode 100644 index 0000000..3a087b3 --- /dev/null +++ b/openbsd-compat/vis.c @@ -0,0 +1,225 @@ +/* $OpenBSD: vis.c,v 1.19 2005/09/01 17:15:49 millert Exp $ */ +/*- + * Copyright (c) 1989, 1993 + * The Regents of the University of California. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* OPENBSD ORIGINAL: lib/libc/gen/vis.c */ + +#include "includes.h" +#if !defined(HAVE_STRNVIS) + +#include +#include + +#include "vis.h" + +#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') +#define isvisible(c) \ + (((u_int)(c) <= UCHAR_MAX && isascii((u_char)(c)) && \ + (((c) != '*' && (c) != '?' && (c) != '[' && (c) != '#') || \ + (flag & VIS_GLOB) == 0) && isgraph((u_char)(c))) || \ + ((flag & VIS_SP) == 0 && (c) == ' ') || \ + ((flag & VIS_TAB) == 0 && (c) == '\t') || \ + ((flag & VIS_NL) == 0 && (c) == '\n') || \ + ((flag & VIS_SAFE) && ((c) == '\b' || \ + (c) == '\007' || (c) == '\r' || \ + isgraph((u_char)(c))))) + +/* + * vis - visually encode characters + */ +char * +vis(char *dst, int c, int flag, int nextc) +{ + if (isvisible(c)) { + *dst++ = c; + if (c == '\\' && (flag & VIS_NOSLASH) == 0) + *dst++ = '\\'; + *dst = '\0'; + return (dst); + } + + if (flag & VIS_CSTYLE) { + switch(c) { + case '\n': + *dst++ = '\\'; + *dst++ = 'n'; + goto done; + case '\r': + *dst++ = '\\'; + *dst++ = 'r'; + goto done; + case '\b': + *dst++ = '\\'; + *dst++ = 'b'; + goto done; + case '\a': + *dst++ = '\\'; + *dst++ = 'a'; + goto done; + case '\v': + *dst++ = '\\'; + *dst++ = 'v'; + goto done; + case '\t': + *dst++ = '\\'; + *dst++ = 't'; + goto done; + case '\f': + *dst++ = '\\'; + *dst++ = 'f'; + goto done; + case ' ': + *dst++ = '\\'; + *dst++ = 's'; + goto done; + case '\0': + *dst++ = '\\'; + *dst++ = '0'; + if (isoctal(nextc)) { + *dst++ = '0'; + *dst++ = '0'; + } + goto done; + } + } + if (((c & 0177) == ' ') || (flag & VIS_OCTAL) || + ((flag & VIS_GLOB) && (c == '*' || c == '?' || c == '[' || c == '#'))) { + *dst++ = '\\'; + *dst++ = ((u_char)c >> 6 & 07) + '0'; + *dst++ = ((u_char)c >> 3 & 07) + '0'; + *dst++ = ((u_char)c & 07) + '0'; + goto done; + } + if ((flag & VIS_NOSLASH) == 0) + *dst++ = '\\'; + if (c & 0200) { + c &= 0177; + *dst++ = 'M'; + } + if (iscntrl((u_char)c)) { + *dst++ = '^'; + if (c == 0177) + *dst++ = '?'; + else + *dst++ = c + '@'; + } else { + *dst++ = '-'; + *dst++ = c; + } +done: + *dst = '\0'; + return (dst); +} + +/* + * strvis, strnvis, strvisx - visually encode characters from src into dst + * + * Dst must be 4 times the size of src to account for possible + * expansion. The length of dst, not including the trailing NULL, + * is returned. + * + * Strnvis will write no more than siz-1 bytes (and will NULL terminate). + * The number of bytes needed to fully encode the string is returned. + * + * Strvisx encodes exactly len bytes from src into dst. + * This is useful for encoding a block of data. + */ +int +strvis(char *dst, const char *src, int flag) +{ + char c; + char *start; + + for (start = dst; (c = *src);) + dst = vis(dst, c, flag, *++src); + *dst = '\0'; + return (dst - start); +} + +int +strnvis(char *dst, const char *src, size_t siz, int flag) +{ + char *start, *end; + char tbuf[5]; + int c, i; + + i = 0; + for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) { + if (isvisible(c)) { + i = 1; + *dst++ = c; + if (c == '\\' && (flag & VIS_NOSLASH) == 0) { + /* need space for the extra '\\' */ + if (dst < end) + *dst++ = '\\'; + else { + dst--; + i = 2; + break; + } + } + src++; + } else { + i = vis(tbuf, c, flag, *++src) - tbuf; + if (dst + i <= end) { + memcpy(dst, tbuf, i); + dst += i; + } else { + src--; + break; + } + } + } + if (siz > 0) + *dst = '\0'; + if (dst + i > end) { + /* adjust return value for truncation */ + while ((c = *src)) + dst += vis(tbuf, c, flag, *++src) - tbuf; + } + return (dst - start); +} + +int +strvisx(char *dst, const char *src, size_t len, int flag) +{ + char c; + char *start; + + for (start = dst; len > 1; len--) { + c = *src; + dst = vis(dst, c, flag, *++src); + } + if (len) + dst = vis(dst, *src, flag, '\0'); + *dst = '\0'; + return (dst - start); +} + +#endif diff --git a/openbsd-compat/vis.h b/openbsd-compat/vis.h new file mode 100644 index 0000000..66c0951 --- /dev/null +++ b/openbsd-compat/vis.h @@ -0,0 +1,98 @@ +/* $OpenBSD: vis.h,v 1.11 2005/08/09 19:38:31 millert Exp $ */ +/* $NetBSD: vis.h,v 1.4 1994/10/26 00:56:41 cgd Exp $ */ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)vis.h 5.9 (Berkeley) 4/3/91 + */ + +/* OPENBSD ORIGINAL: include/vis.h */ + +#ifdef HAVE_CONFIG_H +#include "includes.h" +#endif + +// #if !defined(HAVE_STRNVIS) + +#ifndef _VIS_H_ +#define _VIS_H_ + +#include +#include + +/* + * to select alternate encoding format + */ +#define VIS_OCTAL 0x01 /* use octal \ddd format */ +#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropriate */ + +/* + * to alter set of characters encoded (default is to encode all + * non-graphic except space, tab, and newline). + */ +#define VIS_SP 0x04 /* also encode space */ +#define VIS_TAB 0x08 /* also encode tab */ +#define VIS_NL 0x10 /* also encode newline */ +#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL) +#define VIS_SAFE 0x20 /* only encode "unsafe" characters */ + +/* + * other + */ +#define VIS_NOSLASH 0x40 /* inhibit printing '\' */ +#define VIS_GLOB 0x100 /* encode glob(3) magics and '#' */ + +/* + * unvis return codes + */ +#define UNVIS_VALID 1 /* character valid */ +#define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */ +#define UNVIS_NOCHAR 3 /* valid sequence, no character produced */ +#define UNVIS_SYNBAD -1 /* unrecognized escape sequence */ +#define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */ + +/* + * unvis flags + */ +#define UNVIS_END 1 /* no more characters */ + +char *vis(char *, int, int, int); +int strvis(char *, const char *, int); +int strnvis(char *, const char *, size_t, int) + __attribute__ ((__bounded__(__string__,1,3))); +int strvisx(char *, const char *, size_t, int) + __attribute__ ((__bounded__(__string__,1,3))); +int strunvis(char *, const char *); +int unvis(char *, char, int *, int); +ssize_t strnunvis(char *, const char *, size_t) + __attribute__ ((__bounded__(__string__,1,3))); + +#endif /* !_VIS_H_ */ + +//#endif /* !HAVE_STRNVIS */ From 3249a48f7e14a0833537d9c893b82302680b5d0d Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Tue, 14 Jun 2016 09:17:05 +0200 Subject: [PATCH 20/39] sync iked with -current (needs more work in -portable) --- ikectl/Makefile.am | 4 +- ikectl/ikeca.c | 311 ++++++++++++++++++++++-------- ikectl/ikectl.8 | 15 +- ikectl/ikectl.c | 16 +- ikectl/parser.c | 6 +- ikectl/parser.h | 3 +- iked/Makefile.am | 18 +- iked/ca.c | 140 +++++++------- iked/chap_ms.c | 132 ++++++------- iked/chap_ms.h | 26 +-- iked/config.c | 91 +++++---- iked/control.c | 42 ++++- iked/crypto.c | 68 +++---- iked/dh.c | 53 +++--- iked/dh.h | 14 +- iked/eap.c | 28 +-- iked/eap.h | 58 +++--- iked/iked.c | 73 ++++---- iked/iked.conf.5 | 34 ++-- iked/iked.h | 365 +++++++++++++++++++----------------- iked/ikev1.c | 195 ------------------- iked/ikev2.c | 361 ++++++++++++++++++++--------------- iked/ikev2.h | 92 ++++----- iked/ikev2_msg.c | 91 +++++---- iked/ikev2_pld.c | 135 ++++++------- iked/imsg_util.c | 4 +- iked/log.c | 137 ++++++++------ iked/ocsp.c | 19 +- iked/parse.y | 171 ++++++++--------- iked/pfkey.c | 113 ++++++----- iked/policy.c | 96 ++++++---- iked/proc.c | 116 +++++++----- iked/smult_curve25519_ref.c | 6 +- iked/timer.c | 5 - iked/types.h | 54 +++--- iked/util.c | 112 ++++++----- 36 files changed, 1689 insertions(+), 1515 deletions(-) delete mode 100644 iked/ikev1.c diff --git a/ikectl/Makefile.am b/ikectl/Makefile.am index 4f44e8b..4d70694 100644 --- a/ikectl/Makefile.am +++ b/ikectl/Makefile.am @@ -1,6 +1,8 @@ sbin_PROGRAMS= ikectl -ikectl_SOURCES= ikeca.c ikectl.c parser.c $(top_srcdir)/iked/log.c +ikectl_SOURCES= ikeca.c ikectl.c parser.c \ + $(top_srcdir)/iked/log.c \ + $(top_srcdir)/iked/util.c ikectl_CFLAGS= LIBCOMPAT= $(top_builddir)/openbsd-compat/libopenbsd-compat.a diff --git a/ikectl/ikeca.c b/ikectl/ikeca.c index d8f7e1d..4017715 100644 --- a/ikectl/ikeca.c +++ b/ikectl/ikeca.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikeca.c,v 1.30 2015/01/16 06:40:17 deraadt Exp $ */ +/* $OpenBSD: ikeca.c,v 1.40 2015/11/02 12:21:27 jsg Exp $ */ /* * Copyright (c) 2010 Jonathan Gray @@ -64,6 +64,8 @@ struct ca { char sslpath[PATH_MAX]; char passfile[PATH_MAX]; + char index[PATH_MAX]; + char serial[PATH_MAX]; char sslcnf[PATH_MAX]; char extcnf[PATH_MAX]; char batch[PATH_MAX]; @@ -82,13 +84,41 @@ struct { { "/private", 0700 } }; -int ca_sign(struct ca *, char *, int, char *); +/* explicitly list allowed variables */ +const char *ca_env[][2] = { + { "$ENV::CADB", NULL }, + { "$ENV::CASERIAL", NULL }, + { "$ENV::CERTFQDN", NULL }, + { "$ENV::CERTIP", NULL }, + { "$ENV::CERTPATHLEN", NULL }, + { "$ENV::CERTUSAGE", NULL }, + { "$ENV::CERT_C", NULL }, + { "$ENV::CERT_CN", NULL }, + { "$ENV::CERT_EMAIL", NULL }, + { "$ENV::CERT_L", NULL }, + { "$ENV::CERT_O", NULL }, + { "$ENV::CERT_OU", NULL }, + { "$ENV::CERT_ST", NULL }, + { "$ENV::EXTCERTUSAGE", NULL }, + { "$ENV::NSCERTTYPE", NULL }, + { NULL } +}; + +int ca_sign(struct ca *, char *, int); int ca_request(struct ca *, char *); -int ca_newpass(char *, char *); -char * ca_readpass(char *, size_t *); +void ca_newpass(char *, char *); +char *ca_readpass(char *, size_t *); int fcopy(char *, char *, mode_t); +void fcopy_env(const char *, const char *, mode_t); int rm_dir(char *); -int ca_hier(char *); +void ca_hier(char *); +void ca_setenv(const char *, const char *); +void ca_clrenv(void); +void ca_setcnf(struct ca *, const char *); +void ca_create_index(struct ca *); + +/* util.c */ +int expand_string(char *, size_t, const char *, const char *); int ca_delete(struct ca *ca) @@ -173,10 +203,13 @@ ca_request(struct ca *ca, char *keyname) char cmd[PATH_MAX * 2]; char path[PATH_MAX]; + ca_setenv("$ENV::CERT_CN", keyname); + ca_setcnf(ca, keyname); + snprintf(path, sizeof(path), "%s/private/%s.csr", ca->sslpath, keyname); - snprintf(cmd, sizeof(cmd), "env CERT_CN=%s %s req %s-new" + snprintf(cmd, sizeof(cmd), "%s req %s-new" " -key %s/private/%s.key -out %s -config %s", - keyname, PATH_OPENSSL, ca->batch, ca->sslpath, keyname, + PATH_OPENSSL, ca->batch, ca->sslpath, keyname, path, ca->sslcnf); system(cmd); @@ -186,40 +219,47 @@ ca_request(struct ca *ca, char *keyname) } int -ca_sign(struct ca *ca, char *keyname, int type, char *envargs) +ca_sign(struct ca *ca, char *keyname, int type) { char cmd[PATH_MAX * 2]; - char hostname[MAXHOSTNAMELEN]; + char hostname[HOST_NAME_MAX+1]; char name[128]; + const char *extensions = NULL; strlcpy(name, keyname, sizeof(name)); - if (envargs == NULL) - envargs = ""; - if (type == HOST_IPADDR) { - snprintf(cmd, sizeof(cmd), "env CERTIP=%s%s %s x509 -req" - " -days 365 -in %s/private/%s.csr" - " -CA %s/ca.crt -CAkey %s/private/ca.key -CAcreateserial" - " -extfile %s -extensions x509v3_IPAddr -out %s/%s.crt" - " -passin file:%s", name, envargs, PATH_OPENSSL, - ca->sslpath, keyname, ca->sslpath, ca->sslpath, - ca->extcnf, ca->sslpath, keyname, ca->passfile); + ca_setenv("$ENV::CERTIP", name); + extensions = "x509v3_IPAddr"; } else if (type == HOST_FQDN) { if (!strcmp(keyname, "local")) { if (gethostname(hostname, sizeof(hostname))) err(1, "gethostname"); strlcpy(name, hostname, sizeof(name)); } - snprintf(cmd, sizeof(cmd), "env CERTFQDN=%s%s %s x509 -req" - " -days 365 -in %s/private/%s.csr" - " -CA %s/ca.crt -CAkey %s/private/ca.key -CAcreateserial" - " -extfile %s -extensions x509v3_FQDN -out %s/%s.crt" - " -passin file:%s", name, envargs, PATH_OPENSSL, - ca->sslpath, keyname, ca->sslpath, ca->sslpath, - ca->extcnf, ca->sslpath, keyname, ca->passfile); - } else - err(1, "unknown host type %d", type); + ca_setenv("$ENV::CERTFQDN", name); + extensions = "x509v3_FQDN"; + } else { + errx(1, "unknown host type %d", type); + } + + ca_create_index(ca); + + ca_setenv("$ENV::CADB", ca->index); + ca_setenv("$ENV::CASERIAL", ca->serial); + ca_setcnf(ca, keyname); + + snprintf(cmd, sizeof(cmd), + "%s ca -config %s -keyfile %s/private/ca.key" + " -cert %s/ca.crt" + " -extfile %s -extensions %s -out %s/%s.crt" + " -in %s/private/%s.csr" + " -passin file:%s -outdir %s -batch", + PATH_OPENSSL, ca->sslcnf, ca->sslpath, + ca->sslpath, + ca->extcnf, extensions, ca->sslpath, keyname, + ca->sslpath, keyname, + ca->passfile, ca->sslpath); system(cmd); @@ -229,16 +269,25 @@ ca_sign(struct ca *ca, char *keyname, int type, char *envargs) int ca_certificate(struct ca *ca, char *keyname, int type, int action) { - char *envargs = ""; + ca_clrenv(); switch (action) { case CA_SERVER: - envargs = " EXTCERTUSAGE=serverAuth NSCERTTYPE=server" - " CERTUSAGE=digitalSignature,keyEncipherment"; + ca_setenv("$ENV::EXTCERTUSAGE", "serverAuth"); + ca_setenv("$ENV::NSCERTTYPE", "server"); + ca_setenv("$ENV::CERTUSAGE", + "digitalSignature,keyEncipherment"); break; case CA_CLIENT: - envargs = " EXTCERTUSAGE=clientAuth NSCERTTYPE=client" - " CERTUSAGE=digitalSignature,keyAgreement"; + ca_setenv("$ENV::EXTCERTUSAGE", "clientAuth"); + ca_setenv("$ENV::NSCERTTYPE", "client"); + ca_setenv("$ENV::CERTUSAGE", + "digitalSignature,keyAgreement"); + break; + case CA_OCSP: + ca_setenv("$ENV::EXTCERTUSAGE", "OCSPSigning"); + ca_setenv("$ENV::CERTUSAGE", + "nonRepudiation,digitalSignature,keyEncipherment"); break; default: break; @@ -246,7 +295,7 @@ ca_certificate(struct ca *ca, char *keyname, int type, int action) ca_key_create(ca, keyname); ca_request(ca, keyname); - ca_sign(ca, keyname, type, envargs); + ca_sign(ca, keyname, type); return (0); } @@ -313,7 +362,7 @@ ca_cert_install(struct ca *ca, char *keyname, char *dir) return (0); } -int +void ca_newpass(char *passfile, char *password) { FILE *f; @@ -342,8 +391,6 @@ ca_newpass(char *passfile, char *password) fprintf(f, "%s\n%s\n", pass, pass); fclose(f); - - return (0); } int @@ -352,6 +399,8 @@ ca_create(struct ca *ca) char cmd[PATH_MAX * 2]; char path[PATH_MAX]; + ca_clrenv(); + snprintf(path, sizeof(path), "%s/private/ca.key", ca->sslpath); snprintf(cmd, sizeof(cmd), "%s genrsa -aes256 -out" " %s -passout file:%s 2048", PATH_OPENSSL, @@ -359,8 +408,11 @@ ca_create(struct ca *ca) system(cmd); chmod(path, 0600); + ca_setenv("$ENV::CERT_CN", "VPN CA"); + ca_setcnf(ca, "ca"); + snprintf(path, sizeof(path), "%s/private/ca.csr", ca->sslpath); - snprintf(cmd, sizeof(cmd), "env CERT_CN='VPN CA' %s req %s-new" + snprintf(cmd, sizeof(cmd), "%s req %s-new" " -key %s/private/ca.key" " -config %s -out %s -passin file:%s", PATH_OPENSSL, ca->batch, ca->sslpath, ca->sslcnf, path, ca->passfile); @@ -369,6 +421,7 @@ ca_create(struct ca *ca) snprintf(cmd, sizeof(cmd), "%s x509 -req -days 365" " -in %s/private/ca.csr -signkey %s/private/ca.key" + " -sha256" " -extfile %s -extensions x509v3_CA -out %s/ca.crt -passin file:%s", PATH_OPENSSL, ca->sslpath, ca->sslpath, ca->extcnf, ca->sslpath, ca->passfile); @@ -466,14 +519,16 @@ int fcopy(char *src, char *dst, mode_t mode) { int ifd, ofd; - u_int8_t buf[BUFSIZ]; + uint8_t buf[BUFSIZ]; ssize_t r; if ((ifd = open(src, O_RDONLY)) == -1) err(1, "open %s", src); if ((ofd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) { - err(1, "open %s", dst); + int saved_errno = errno; + close(ifd); + errc(1, saved_errno, "open %s", dst); } while ((r = read(ifd, buf, sizeof(buf))) > 0) { @@ -486,6 +541,45 @@ fcopy(char *src, char *dst, mode_t mode) return (r == -1); } +void +fcopy_env(const char *src, const char *dst, mode_t mode) +{ + int ofd = -1, i; + uint8_t buf[BUFSIZ]; + ssize_t r = -1, len; + FILE *ifp = NULL; + int saved_errno; + + if ((ifp = fopen(src, "r")) == NULL) + err(1, "fopen %s", src); + + if ((ofd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) + goto done; + + while (fgets(buf, sizeof(buf), ifp) != NULL) { + for (i = 0; ca_env[i][0] != NULL; i++) { + if (ca_env[i][1] == NULL) + continue; + if (expand_string(buf, sizeof(buf), + ca_env[i][0], ca_env[i][1]) == -1) + errx(1, "env %s value too long", ca_env[i][0]); + } + len = strlen(buf); + if (write(ofd, buf, len) != len) + goto done; + } + + r = 0; + + done: + saved_errno = errno; + close(ofd); + if (ifp != NULL) + fclose(ifp); + if (r == -1) + errc(1, saved_errno, "open %s", dst); +} + int rm_dir(char *path) { @@ -521,13 +615,12 @@ rm_dir(char *path) return (0); } - -int +void ca_hier(char *path) { struct stat st; char dst[PATH_MAX]; - u_int i; + unsigned int i; for (i = 0; i < nitems(hier); i++) { strlcpy(dst, path, sizeof(dst)); @@ -536,8 +629,6 @@ ca_hier(char *path) mkdir(dst, hier[i].mode) != 0) err(1, "failed to create dir %s", dst); } - - return (0); } int @@ -554,12 +645,12 @@ ca_export(struct ca *ca, char *keyname, char *myname, char *password) char dst[PATH_MAX]; char *p; char tpl[] = "/tmp/ikectl.XXXXXXXXXX"; - u_int i; + unsigned int i; int fd; if (keyname != NULL) { if (strlcpy(oname, keyname, sizeof(oname)) >= sizeof(oname)) - err(1, "name too long"); + errx(1, "name too long"); } else { strlcpy(oname, "ca", sizeof(oname)); } @@ -681,7 +772,7 @@ ca_export(struct ca *ca, char *keyname, char *myname, char *password) de->d_name); snprintf(dst, sizeof(dst), "%s/export/%s", p, de->d_name); - fcopy(src, dst, 644); + fcopy(src, dst, 0644); } closedir(dexp); } @@ -734,13 +825,49 @@ ca_readpass(char *path, size_t *len) return (r); } +/* create index if it doesn't already exist */ +void +ca_create_index(struct ca *ca) +{ + struct stat st; + int fd; + + if (snprintf(ca->index, sizeof(ca->index), "%s/index.txt", + ca->sslpath) < 0) + err(1, "snprintf"); + if (stat(ca->index, &st) != 0) { + if (errno == ENOENT) { + if ((fd = open(ca->index, O_WRONLY | O_CREAT, 0644)) + == -1) + err(1, "could not create file %s", ca->index); + close(fd); + } else + err(1, "could not access %s", ca->index); + } + + if (snprintf(ca->serial, sizeof(ca->serial), "%s/serial.txt", + ca->sslpath) < 0) + err(1, "snprintf"); + if (stat(ca->serial, &st) != 0) { + if (errno == ENOENT) { + if ((fd = open(ca->serial, O_WRONLY | O_CREAT, 0644)) + == -1) + err(1, "could not create file %s", ca->serial); + /* serial file must be created with a number */ + if (write(fd, "01\n", 3) != 3) + err(1, "write %s", ca->serial); + close(fd); + } else + err(1, "could not access %s", ca->serial); + } +} + int ca_revoke(struct ca *ca, char *keyname) { struct stat st; char cmd[PATH_MAX * 2]; char path[PATH_MAX]; - int fd; char *pass; size_t len; @@ -756,40 +883,33 @@ ca_revoke(struct ca *ca, char *keyname) snprintf(path, sizeof(path), "%s/ikeca.passwd", ca->sslpath); pass = ca_readpass(path, &len); if (pass == NULL) - err(1, "could not open passphrase file"); + errx(1, "could not open passphrase file"); - /* create index if it doesn't already exist */ - snprintf(path, sizeof(path), "%s/index.txt", ca->sslpath); - if (stat(path, &st) != 0) { - if (errno == ENOENT) { - if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) == -1) - err(1, "could not create file %s", path); - close(fd); - } else - err(1, "could not access %s", path); - } + ca_create_index(ca); + + ca_setenv("$ENV::CADB", ca->index); + ca_setenv("$ENV::CASERIAL", ca->serial); + ca_setcnf(ca, "ca-revoke"); if (keyname) { - snprintf(cmd, sizeof(cmd), "env CADB='%s/index.txt' " - " %s ca %s-config %s -keyfile %s/private/ca.key" + snprintf(cmd, sizeof(cmd), + "%s ca %s-config %s -keyfile %s/private/ca.key" " -key %s" " -cert %s/ca.crt" - " -md sha1" " -revoke %s/%s.crt", - ca->sslpath, PATH_OPENSSL, ca->batch, ca->sslcnf, + PATH_OPENSSL, ca->batch, ca->sslcnf, ca->sslpath, pass, ca->sslpath, ca->sslpath, keyname); system(cmd); } - snprintf(cmd, sizeof(cmd), "env CADB='%s/index.txt' " - " %s ca %s-config %s -keyfile %s/private/ca.key" + snprintf(cmd, sizeof(cmd), + "%s ca %s-config %s -keyfile %s/private/ca.key" " -key %s" " -gencrl" " -cert %s/ca.crt" - " -md sha1" " -crldays 365" " -out %s/ca.crl", - ca->sslpath, PATH_OPENSSL, ca->batch, ca->sslcnf, ca->sslpath, + PATH_OPENSSL, ca->batch, ca->sslcnf, ca->sslpath, pass, ca->sslpath, ca->sslpath); system(cmd); @@ -799,6 +919,53 @@ ca_revoke(struct ca *ca, char *keyname) return (0); } +void +ca_clrenv(void) +{ + int i; + for (i = 0; ca_env[i][0] != NULL; i++) + ca_env[i][1] = NULL; +} + +void +ca_setenv(const char *key, const char *value) +{ + int i; + + for (i = 0; ca_env[i][0] != NULL; i++) { + if (strcmp(ca_env[i][0], key) == 0) { + if (ca_env[i][1] != NULL) + errx(1, "env %s already set: %s", key, value); + ca_env[i][1] = value; + return; + } + } + errx(1, "env %s invalid", key); +} + +void +ca_setcnf(struct ca *ca, const char *keyname) +{ + struct stat st; + const char *extcnf, *sslcnf; + + if (stat(IKECA_CNF, &st) == 0) { + extcnf = IKECA_CNF; + sslcnf = IKECA_CNF; + } else { + extcnf = X509_CNF; + sslcnf = SSL_CNF; + } + + snprintf(ca->extcnf, sizeof(ca->extcnf), "%s/%s-ext.cnf", + ca->sslpath, keyname); + snprintf(ca->sslcnf, sizeof(ca->sslcnf), "%s/%s-ssl.cnf", + ca->sslpath, keyname); + + fcopy_env(extcnf, ca->extcnf, 0400); + fcopy_env(sslcnf, ca->sslcnf, 0400); +} + struct ca * ca_setup(char *caname, int create, int quiet, char *pass) { @@ -820,14 +987,6 @@ ca_setup(char *caname, int create, int quiet, char *pass) if (quiet) strlcpy(ca->batch, "-batch ", sizeof(ca->batch)); - if (stat(IKECA_CNF, &st) == 0) { - strlcpy(ca->extcnf, IKECA_CNF, sizeof(ca->extcnf)); - strlcpy(ca->sslcnf, IKECA_CNF, sizeof(ca->sslcnf)); - } else { - strlcpy(ca->extcnf, X509_CNF, sizeof(ca->extcnf)); - strlcpy(ca->sslcnf, SSL_CNF, sizeof(ca->sslcnf)); - } - if (create == 0 && stat(ca->sslpath, &st) == -1) { free(ca->caname); free(ca); diff --git a/ikectl/ikectl.8 b/ikectl/ikectl.8 index e03d9f7..40d30ac 100644 --- a/ikectl/ikectl.8 +++ b/ikectl/ikectl.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ikectl.8,v 1.23 2015/07/27 17:28:39 sobrado Exp $ +.\" $OpenBSD: ikectl.8,v 1.25 2015/11/02 10:27:44 jsg Exp $ .\" .\" Copyright (c) 2007-2013 Reyk Floeter .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: July 27 2015 $ +.Dd $Mdocdate: November 2 2015 $ .Dt IKECTL 8 .Os .Sh NAME @@ -149,7 +149,7 @@ as the currently active CA or into the specified .It Xo .Cm ca Ar name Cm certificate Ar host .Cm create -.Op Ic server | client +.Op Ic server | client | ocsp .Xc Create a private key and certificate for .Ar host @@ -163,6 +163,9 @@ this can be restricted using the optional or .Ic client argument. +If the +.Ic ocsp +argument is specified the extended key usage will be set for OCSP signing. .It Xo .Cm ca Ar name Cm certificate Ar host .Cm delete @@ -254,17 +257,17 @@ from the named Active configuration. .It Pa /etc/ssl/ Directory to store the CA files. -.It Pa /usr/share/iked +.It Pa /usr/share/iked/ If this optional directory exists, .Nm will include the contents with the .Cm ca export commands. .It Pa /var/run/iked.sock -default +Default .Ux Ns -domain socket used for communication with -.Xr iked 8 +.Xr iked 8 . .El .Sh EXAMPLES First create a new certificate authority: diff --git a/ikectl/ikectl.c b/ikectl/ikectl.c index 50368e9..749c924 100644 --- a/ikectl/ikectl.c +++ b/ikectl/ikectl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikectl.c,v 1.19 2015/01/16 06:40:17 deraadt Exp $ */ +/* $OpenBSD: ikectl.c,v 1.23 2015/12/05 13:11:18 claudio Exp $ */ /* * Copyright (c) 2007-2013 Reyk Floeter @@ -44,7 +44,7 @@ struct imsgname { void (*func)(struct imsg *); }; -struct imsgname *monitor_lookup(u_int8_t); +struct imsgname *monitor_lookup(uint8_t); void monitor_id(struct imsg *); int monitor(struct imsg *); @@ -113,6 +113,7 @@ ca_opt(struct parse_result *res) case CA_CERT_CREATE: case CA_SERVER: case CA_CLIENT: + case CA_OCSP: ca_certificate(ca, res->host, res->htype, res->action); break; case CA_CERT_DELETE: @@ -193,6 +194,7 @@ main(int argc, char *argv[]) case CA_CERT_CREATE: case CA_CLIENT: case CA_SERVER: + case CA_OCSP: case CA_CERT_DELETE: case CA_CERT_INSTALL: case CA_CERT_EXPORT: @@ -203,6 +205,9 @@ main(int argc, char *argv[]) case CA_KEY_DELETE: case CA_KEY_INSTALL: case CA_KEY_IMPORT: + if (pledge("stdio proc exec rpath wpath cpath fattr tty", NULL) + == -1) + err(1, "pledge"); ca_opt(res); break; case NONE: @@ -233,6 +238,9 @@ main(int argc, char *argv[]) err(1, "connect: %s", sock); } + if (pledge("stdio", NULL) == -1) + err(1, "pledge"); + if (res->ibuf != NULL) ibuf = res->ibuf; else @@ -316,7 +324,7 @@ main(int argc, char *argv[]) err(1, "write error"); while (!done) { - if ((n = imsg_read(ibuf)) == -1) + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) errx(1, "imsg_read error"); if (n == 0) errx(1, "pipe closed"); @@ -343,7 +351,7 @@ main(int argc, char *argv[]) } struct imsgname * -monitor_lookup(u_int8_t type) +monitor_lookup(uint8_t type) { int i; diff --git a/ikectl/parser.c b/ikectl/parser.c index 147300e..1ba0061 100644 --- a/ikectl/parser.c +++ b/ikectl/parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.c,v 1.13 2015/01/16 06:40:17 deraadt Exp $ */ +/* $OpenBSD: parser.c,v 1.15 2015/11/02 10:27:44 jsg Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -67,6 +67,7 @@ static const struct token t_ca_ex_pass[]; static const struct token t_ca_modifiers[]; static const struct token t_ca_cert[]; static const struct token t_ca_cert_extusage[]; +static const struct token t_ca_cert_ex_peer[]; static const struct token t_ca_cert_modifiers[]; static const struct token t_ca_key[]; static const struct token t_ca_key_modifiers[]; @@ -180,6 +181,7 @@ static const struct token t_ca_cert_extusage[] = { { NOTOKEN, "", NONE, NULL}, { KEYWORD, "server", CA_SERVER, NULL }, { KEYWORD, "client", CA_CLIENT, NULL }, + { KEYWORD, "ocsp", CA_OCSP, NULL }, { ENDTOKEN, "", NONE, NULL }, }; @@ -282,7 +284,7 @@ parse_addr(const char *word) const struct token * match_token(char *word, const struct token table[]) { - u_int i, match = 0; + unsigned int i, match = 0; const struct token *t = NULL; for (i = 0; table[i].type != ENDTOKEN; i++) { diff --git a/ikectl/parser.h b/ikectl/parser.h index 250bae0..f87ee36 100644 --- a/ikectl/parser.h +++ b/ikectl/parser.h @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.h,v 1.13 2015/06/11 18:49:09 reyk Exp $ */ +/* $OpenBSD: parser.h,v 1.14 2015/11/02 10:27:44 jsg Exp $ */ /* * Copyright (c) 2007-2013 Reyk Floeter @@ -44,6 +44,7 @@ enum actions { CA_CERT_CREATE, CA_SERVER, CA_CLIENT, + CA_OCSP, CA_CERT_DELETE, CA_CERT_INSTALL, CA_CERT_EXPORT, diff --git a/iked/Makefile.am b/iked/Makefile.am index 564e097..006e2ad 100644 --- a/iked/Makefile.am +++ b/iked/Makefile.am @@ -3,21 +3,23 @@ sbin_PROGRAMS= iked iked_MAPS= eap_map.c ikev2_map.c iked_MAPS_IN= eap.h ikev2.h iked_SOURCES= ca.c chap_ms.c config.c control.c crypto.c dh.c \ - eap.c iked.c ikev1.c ikev2.c ikev2_msg.c ikev2_pld.c \ + eap.c iked.c ikev2.c ikev2_msg.c ikev2_pld.c \ log.c ocsp.c policy.c proc.c \ - smult_curve25519_ref.c timer.c util.c imsg_util.c \ + timer.c util.c imsg_util.c \ parse.y $(iked_MAPS) -iked_CFLAGS= +iked_CPPFLAGS= -include $(top_srcdir)/openbsd-compat/includes.h libpfkey_a_SOURCES= pfkey.c -libpfkey_a_CPPFLAGS= @PFKEY_CPPFLAGS@ +libpfkey_a_CPPFLAGS= @PFKEY_CPPFLAGS@ $(iked_CPPFLAGS) -noinst_LIBRARIES= libpfkey.a +libcurve25519_a_SOURCES=smult_curve25519_ref.c +libcurve25519_a_CPPFLAGS= + +noinst_LIBRARIES= libpfkey.a libcurve25519.a LIBCOMPAT= $(top_builddir)/openbsd-compat/libopenbsd-compat.a -LDADD= $(LIBCOMPAT) libpfkey.a -CPPFLAGS= -include $(top_srcdir)/openbsd-compat/includes.h \ - -I$(top_srcdir)/openbsd-compat \ +LDADD= $(LIBCOMPAT) libpfkey.a libcurve25519.a +CPPFLAGS= -I$(top_srcdir)/openbsd-compat \ -I$(srcdir) @CPPFLAGS@ @DEFS@ MANPAGES= iked.8.out iked.conf.5.out MANPAGES_IN= iked.8 iked.conf.5 diff --git a/iked/ca.c b/iked/ca.c index cc507aa..5f5e0dc 100644 --- a/iked/ca.c +++ b/iked/ca.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ca.c,v 1.35 2015/03/26 19:52:35 markus Exp $ */ +/* $OpenBSD: ca.c,v 1.40 2015/12/07 12:46:37 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -46,15 +46,16 @@ #include "iked.h" #include "ikev2.h" +void ca_run(struct privsep *, struct privsep_proc *, void *); void ca_reset(struct privsep *, struct privsep_proc *, void *); int ca_reload(struct iked *); int ca_getreq(struct iked *, struct imsg *); int ca_getcert(struct iked *, struct imsg *); int ca_getauth(struct iked *, struct imsg *); -X509 *ca_by_subjectpubkey(X509_STORE *, u_int8_t *, size_t); +X509 *ca_by_subjectpubkey(X509_STORE *, uint8_t *, size_t); X509 *ca_by_issuer(X509_STORE *, X509_NAME *, struct iked_static_id *); -int ca_subjectpubkey_digest(X509 *, u_int8_t *, u_int *); +int ca_subjectpubkey_digest(X509 *, uint8_t *, unsigned int *); int ca_x509_subject_cmp(X509 *, struct iked_static_id *); int ca_validate_pubkey(struct iked *, struct iked_static_id *, void *, size_t); @@ -67,7 +68,6 @@ int ca_x509_subjectaltname(X509 *cert, struct iked_id *); int ca_privkey_serialize(EVP_PKEY *, struct iked_id *); int ca_pubkey_serialize(EVP_PKEY *, struct iked_id *); int ca_dispatch_parent(int, struct privsep_proc *, struct imsg *); -int ca_dispatch_ikev1(int, struct privsep_proc *, struct imsg *); int ca_dispatch_ikev2(int, struct privsep_proc *, struct imsg *); static struct privsep_proc procs[] = { @@ -117,6 +117,21 @@ caproc(struct privsep *ps, struct privsep_proc *p) return (proc_run(ps, p, procs, nitems(procs), ca_reset, store)); } +void +ca_run(struct privsep *ps, struct privsep_proc *p, void *arg) +{ + /* + * pledge in the ca process: + * stdio - for malloc and basic I/O including events. + * rpath - for certificate files. + * recvfd - for ocsp sockets. + */ + if (pledge("stdio rpath recvfd", NULL) == -1) + fatal("pledge"); + + ca_reset(ps, p, arg); +} + void ca_reset(struct privsep *ps, struct privsep_proc *p, void *arg) { @@ -150,8 +165,8 @@ int ca_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) { struct iked *env = p->p_env; - struct ca_store *store = env->sc_priv; - u_int mode; + struct ca_store *store = env->sc_priv; + unsigned int mode; switch (imsg->hdr.type) { case IMSG_CTL_RESET: @@ -175,12 +190,6 @@ ca_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) return (0); } -int -ca_dispatch_ikev1(int fd, struct privsep_proc *p, struct imsg *imsg) -{ - return (-1); -} - int ca_dispatch_ikev2(int fd, struct privsep_proc *p, struct imsg *imsg) { @@ -205,7 +214,7 @@ ca_dispatch_ikev2(int fd, struct privsep_proc *p, struct imsg *imsg) int ca_setcert(struct iked *env, struct iked_sahdr *sh, struct iked_id *id, - u_int8_t type, u_int8_t *data, size_t len, enum privsep_procid procid) + uint8_t type, uint8_t *data, size_t len, enum privsep_procid procid) { struct iovec iov[4]; int iovcnt = 0; @@ -240,15 +249,14 @@ ca_setcert(struct iked *env, struct iked_sahdr *sh, struct iked_id *id, iov[iovcnt].iov_len = len; iovcnt++; - if (proc_composev_imsg(&env->sc_ps, procid, -1, - IMSG_CERT, -1, iov, iovcnt) == -1) + if (proc_composev(&env->sc_ps, procid, IMSG_CERT, iov, iovcnt) == -1) return (-1); return (0); } int -ca_setreq(struct iked *env, struct iked_sahdr *sh, - struct iked_static_id *localid, u_int8_t type, u_int8_t *data, +ca_setreq(struct iked *env, struct iked_sa *sa, + struct iked_static_id *localid, uint8_t type, uint8_t *data, size_t len, enum privsep_procid procid) { struct iovec iov[4]; @@ -272,8 +280,8 @@ ca_setreq(struct iked *env, struct iked_sahdr *sh, iov[iovcnt].iov_len = sizeof(idb); iovcnt++; - iov[iovcnt].iov_base = sh; - iov[iovcnt].iov_len = sizeof(*sh); + iov[iovcnt].iov_base = &sa->sa_hdr; + iov[iovcnt].iov_len = sizeof(sa->sa_hdr); iovcnt++; iov[iovcnt].iov_base = &type; iov[iovcnt].iov_len = sizeof(type); @@ -282,10 +290,11 @@ ca_setreq(struct iked *env, struct iked_sahdr *sh, iov[iovcnt].iov_len = len; iovcnt++; - if (proc_composev_imsg(&env->sc_ps, procid, -1, - IMSG_CERTREQ, -1, iov, iovcnt) == -1) + if (proc_composev(&env->sc_ps, procid, IMSG_CERTREQ, iov, iovcnt) == -1) goto done; + sa_stateflags(sa, IKED_REQ_CERTREQ); + ret = 0; done: ibuf_release(id.id_buf); @@ -299,7 +308,7 @@ ca_setauth(struct iked *env, struct iked_sa *sa, struct iovec iov[3]; int iovcnt = 3; struct iked_policy *policy = sa->sa_policy; - u_int8_t type = policy->pol_auth.auth_method; + uint8_t type = policy->pol_auth.auth_method; /* switch encoding to IKEV2_AUTH_SIG if SHA2 is supported */ if (sa->sa_sigsha2 && type == IKEV2_AUTH_RSA_SIG) { @@ -325,8 +334,7 @@ ca_setauth(struct iked *env, struct iked_sa *sa, log_debug("%s: auth length %zu", __func__, ibuf_size(authmsg)); } - if (proc_composev_imsg(&env->sc_ps, id, -1, - IMSG_AUTH, -1, iov, iovcnt) == -1) + if (proc_composev(&env->sc_ps, id, IMSG_AUTH, iov, iovcnt) == -1) return (-1); return (0); } @@ -335,15 +343,15 @@ int ca_getcert(struct iked *env, struct imsg *imsg) { struct iked_sahdr sh; - u_int8_t type; - u_int8_t *ptr; + uint8_t type; + uint8_t *ptr; size_t len; struct iked_static_id id; - u_int i; + unsigned int i; struct iovec iov[2]; int iovcnt = 2, cmd, ret = 0; - ptr = (u_int8_t *)imsg->data; + ptr = (uint8_t *)imsg->data; len = IMSG_DATA_SIZE(imsg); i = sizeof(id) + sizeof(sh) + sizeof(type); if (len <= i) @@ -353,7 +361,7 @@ ca_getcert(struct iked *env, struct imsg *imsg) if (id.id_type == IKEV2_ID_NONE) return (-1); memcpy(&sh, ptr + sizeof(id), sizeof(sh)); - memcpy(&type, ptr + sizeof(id) + sizeof(sh), sizeof(u_int8_t)); + memcpy(&type, ptr + sizeof(id) + sizeof(sh), sizeof(uint8_t)); ptr += i; len -= i; @@ -386,8 +394,7 @@ ca_getcert(struct iked *env, struct imsg *imsg) iov[1].iov_base = &type; iov[1].iov_len = sizeof(type); - if (proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, - cmd, -1, iov, iovcnt) == -1) + if (proc_composev(&env->sc_ps, PROC_IKEV2, cmd, iov, iovcnt) == -1) return (-1); return (0); } @@ -395,19 +402,19 @@ ca_getcert(struct iked *env, struct imsg *imsg) int ca_getreq(struct iked *env, struct imsg *imsg) { - struct ca_store *store = env->sc_priv; + struct ca_store *store = env->sc_priv; struct iked_sahdr sh; - u_int8_t type; - u_int8_t *ptr; + uint8_t type; + uint8_t *ptr; size_t len; - u_int i, n; + unsigned int i, n; X509 *ca = NULL, *cert = NULL; struct ibuf *buf; struct iked_static_id id; - ptr = (u_int8_t *)imsg->data; + ptr = (uint8_t *)imsg->data; len = IMSG_DATA_SIZE(imsg); - i = sizeof(id) + sizeof(u_int8_t) + sizeof(sh); + i = sizeof(id) + sizeof(uint8_t) + sizeof(sh); if (len < i || ((len - i) % SHA_DIGEST_LENGTH) != 0) return (-1); @@ -415,7 +422,7 @@ ca_getreq(struct iked *env, struct imsg *imsg) if (id.id_type == IKEV2_ID_NONE) return (-1); memcpy(&sh, ptr + sizeof(id), sizeof(sh)); - memcpy(&type, ptr + sizeof(id) + sizeof(sh), sizeof(u_int8_t)); + memcpy(&type, ptr + sizeof(id) + sizeof(sh), sizeof(uint8_t)); switch (type) { case IKEV2_CERT_RSA_KEY: @@ -469,26 +476,26 @@ ca_getreq(struct iked *env, struct imsg *imsg) int ca_getauth(struct iked *env, struct imsg *imsg) { - struct ca_store *store = env->sc_priv; + struct ca_store *store = env->sc_priv; struct iked_sahdr sh; - u_int8_t method; - u_int8_t *ptr; + uint8_t method; + uint8_t *ptr; size_t len; - u_int i; + unsigned int i; int ret = -1; struct iked_sa sa; struct iked_policy policy; struct iked_id *id; struct ibuf *authmsg; - ptr = (u_int8_t *)imsg->data; + ptr = (uint8_t *)imsg->data; len = IMSG_DATA_SIZE(imsg); i = sizeof(method) + sizeof(sh); if (len <= i) return (-1); memcpy(&sh, ptr, sizeof(sh)); - memcpy(&method, ptr + sizeof(sh), sizeof(u_int8_t)); + memcpy(&method, ptr + sizeof(sh), sizeof(uint8_t)); if (method == IKEV2_AUTH_SHARED_KEY_MIC) return (-1); @@ -529,7 +536,7 @@ int ca_reload(struct iked *env) { struct ca_store *store = env->sc_priv; - u_int8_t md[EVP_MAX_MD_SIZE]; + uint8_t md[EVP_MAX_MD_SIZE]; char file[PATH_MAX]; struct iovec iov[2]; struct dirent *entry; @@ -537,8 +544,7 @@ ca_reload(struct iked *env) X509_OBJECT *xo; X509 *x509; DIR *dir; - u_int len; - int i, iovcnt = 0; + int i, len, iovcnt = 0; /* * Load CAs @@ -634,8 +640,8 @@ ca_reload(struct iked *env) ibuf_length(env->sc_certreq) == SHA_DIGEST_LENGTH ? "" : "s"); - (void)proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, - IMSG_CERTREQ, -1, iov, iovcnt); + (void)proc_composev(&env->sc_ps, PROC_IKEV2, IMSG_CERTREQ, + iov, iovcnt); } /* @@ -685,21 +691,20 @@ ca_reload(struct iked *env) iov[0].iov_len = sizeof(env->sc_certreqtype); if (iovcnt == 0) iovcnt++; - (void)proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, - IMSG_CERTREQ, -1, iov, iovcnt); + (void)proc_composev(&env->sc_ps, PROC_IKEV2, IMSG_CERTREQ, iov, iovcnt); return (0); } X509 * -ca_by_subjectpubkey(X509_STORE *ctx, u_int8_t *sig, size_t siglen) +ca_by_subjectpubkey(X509_STORE *ctx, uint8_t *sig, size_t siglen) { STACK_OF(X509_OBJECT) *h; X509_OBJECT *xo; X509 *ca; int i; - u_int len; - u_int8_t md[EVP_MAX_MD_SIZE]; + unsigned int len; + uint8_t md[EVP_MAX_MD_SIZE]; h = ctx->objs; @@ -758,9 +763,9 @@ ca_by_issuer(X509_STORE *ctx, X509_NAME *subject, struct iked_static_id *id) } int -ca_subjectpubkey_digest(X509 *x509, u_int8_t *md, u_int *size) +ca_subjectpubkey_digest(X509 *x509, uint8_t *md, unsigned int *size) { - u_int8_t *buf = NULL; + uint8_t *buf = NULL; int buflen; if (*size < SHA_DIGEST_LENGTH) @@ -789,7 +794,7 @@ ca_x509_serialize(X509 *x509) { long len; struct ibuf *buf; - u_int8_t *d = NULL; + uint8_t *d = NULL; BIO *out; if ((out = BIO_new(BIO_s_mem())) == NULL) @@ -810,7 +815,7 @@ int ca_pubkey_serialize(EVP_PKEY *key, struct iked_id *id) { RSA *rsa = NULL; - u_int8_t *d; + uint8_t *d; int len = 0; int ret = -1; @@ -854,7 +859,7 @@ int ca_privkey_serialize(EVP_PKEY *key, struct iked_id *id) { RSA *rsa = NULL; - u_int8_t *d; + uint8_t *d; int len = 0; int ret = -1; @@ -895,11 +900,11 @@ ca_privkey_serialize(EVP_PKEY *key, struct iked_id *id) } char * -ca_asn1_name(u_int8_t *asn1, size_t len) +ca_asn1_name(uint8_t *asn1, size_t len) { X509_NAME *name = NULL; char *str = NULL; - const u_int8_t *p; + const uint8_t *p; p = asn1; if ((name = d2i_X509_NAME(NULL, &p, len)) == NULL) @@ -959,8 +964,7 @@ ca_x509_name_unescape(char *src, char *dst, char marker) void * ca_x509_name_parse(char *subject) { - u_char *value = NULL; - char *cp, *type = NULL; + char *cp, *value = NULL, *type = NULL; size_t maxlen; X509_NAME *name = NULL; @@ -990,7 +994,7 @@ ca_x509_name_parse(char *subject) goto err; } /* unescape value, terminated by '/' */ - cp = ca_x509_name_unescape(cp, (char *)value, '/'); + cp = ca_x509_name_unescape(cp, value, '/'); if (cp == NULL) { log_warnx("%s: could not parse value", __func__); goto err; @@ -1215,7 +1219,7 @@ int ca_x509_subject_cmp(X509 *cert, struct iked_static_id *id) { X509_NAME *subject, *idname = NULL; - const u_int8_t *idptr; + const uint8_t *idptr; size_t idlen; int ret = -1; @@ -1270,7 +1274,7 @@ int ca_x509_subjectaltname(X509 *cert, struct iked_id *id) { X509_EXTENSION *san; - u_int8_t sanhdr[4], *data; + uint8_t sanhdr[4], *data; int ext, santype, sanlen; char idstr[IKED_ID_SIZE]; @@ -1290,7 +1294,7 @@ ca_x509_subjectaltname(X509 *cert, struct iked_id *id) } /* This is partially based on isakmpd's x509 subjectaltname code */ - data = (u_int8_t *)san->value->data; + data = (uint8_t *)san->value->data; memcpy(&sanhdr, data, sizeof(sanhdr)); santype = sanhdr[2] & 0x3f; sanlen = sanhdr[3]; @@ -1351,7 +1355,7 @@ ca_sslinit(void) void ca_sslerror(const char *caller) { - u_long error; + unsigned long error; while ((error = ERR_get_error()) != 0) log_warn("%s: %s: %.100s", __func__, caller, diff --git a/iked/chap_ms.c b/iked/chap_ms.c index 23ca735..1e03f1d 100644 --- a/iked/chap_ms.c +++ b/iked/chap_ms.c @@ -1,4 +1,4 @@ -/* $OpenBSD: chap_ms.c,v 1.8 2014/11/20 03:48:12 tedu Exp $ */ +/* $OpenBSD: chap_ms.c,v 1.9 2015/08/21 11:59:27 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -56,32 +56,32 @@ * "It is unclear to us why this protocol is so complicated." */ -static u_int8_t sha1_pad1[40] = { +static uint8_t sha1_pad1[40] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static u_int8_t sha1_pad2[40] = { +static uint8_t sha1_pad2[40] = { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 }; -u_int8_t get7bits(u_int8_t *, int); -void mschap_des_addparity(u_int8_t *, u_int8_t *); -void mschap_des_encrypt(u_int8_t *, u_int8_t *, u_int8_t *); -void mschap_challenge_response(u_int8_t *, u_int8_t *, u_int8_t *); +uint8_t get7bits(uint8_t *, int); +void mschap_des_addparity(uint8_t *, uint8_t *); +void mschap_des_encrypt(uint8_t *, uint8_t *, uint8_t *); +void mschap_challenge_response(uint8_t *, uint8_t *, uint8_t *); -u_int8_t -get7bits(u_int8_t *in, int start) +uint8_t +get7bits(uint8_t *in, int start) { - u_int word; + unsigned int word; - word = (u_int)in[start / 8] << 8; - word |= (u_int)in[start / 8 + 1]; + word = (unsigned int)in[start / 8] << 8; + word |= (unsigned int)in[start / 8 + 1]; word >>= 15 - (start % 8 + 7); return (word & 0xfe); @@ -90,7 +90,7 @@ get7bits(u_int8_t *in, int start) /* IN 56 bit DES key missing parity bits OUT 64 bit DES key with parity bits added */ void -mschap_des_addparity(u_int8_t *key, u_int8_t *des_key) +mschap_des_addparity(uint8_t *key, uint8_t *des_key) { des_key[0] = get7bits(key, 0); des_key[1] = get7bits(key, 7); @@ -105,7 +105,7 @@ mschap_des_addparity(u_int8_t *key, u_int8_t *des_key) } void -mschap_des_encrypt(u_int8_t *clear, u_int8_t *key, u_int8_t *cipher) +mschap_des_encrypt(uint8_t *clear, uint8_t *key, uint8_t *cipher) { DES_cblock des_key; DES_key_schedule key_schedule; @@ -118,10 +118,10 @@ mschap_des_encrypt(u_int8_t *clear, u_int8_t *key, u_int8_t *cipher) } void -mschap_challenge_response(u_int8_t *challenge, u_int8_t *pwhash, - u_int8_t *response) +mschap_challenge_response(uint8_t *challenge, uint8_t *pwhash, + uint8_t *response) { - u_int8_t padpwhash[21 + 1]; + uint8_t padpwhash[21 + 1]; bzero(&padpwhash, sizeof(padpwhash)); memcpy(padpwhash, pwhash, MSCHAP_HASH_SZ); @@ -132,10 +132,10 @@ mschap_challenge_response(u_int8_t *challenge, u_int8_t *pwhash, } void -mschap_ntpassword_hash(u_int8_t *in, int inlen, u_int8_t *hash) +mschap_ntpassword_hash(uint8_t *in, int inlen, uint8_t *hash) { EVP_MD_CTX ctx; - u_int mdlen; + unsigned int mdlen; EVP_DigestInit(&ctx, EVP_md4()); EVP_DigestUpdate(&ctx, in, inlen); @@ -143,15 +143,15 @@ mschap_ntpassword_hash(u_int8_t *in, int inlen, u_int8_t *hash) } void -mschap_challenge_hash(u_int8_t *peer_challenge, u_int8_t *auth_challenge, - u_int8_t *username, int usernamelen, u_int8_t *challenge) +mschap_challenge_hash(uint8_t *peer_challenge, uint8_t *auth_challenge, + uint8_t *username, int usernamelen, uint8_t *challenge) { EVP_MD_CTX ctx; - u_int8_t md[SHA_DIGEST_LENGTH]; - u_int mdlen; - u_int8_t *name; + uint8_t md[SHA_DIGEST_LENGTH]; + unsigned int mdlen; + uint8_t *name; - if ((name = (u_char *)strrchr((char *)username, '\\')) == NULL) + if ((name = strrchr(username, '\\')) == NULL) name = username; else name++; @@ -159,19 +159,19 @@ mschap_challenge_hash(u_int8_t *peer_challenge, u_int8_t *auth_challenge, EVP_DigestInit(&ctx, EVP_sha1()); EVP_DigestUpdate(&ctx, peer_challenge, MSCHAPV2_CHALLENGE_SZ); EVP_DigestUpdate(&ctx, auth_challenge, MSCHAPV2_CHALLENGE_SZ); - EVP_DigestUpdate(&ctx, name, strlen((char *)name)); + EVP_DigestUpdate(&ctx, name, strlen(name)); EVP_DigestFinal(&ctx, md, &mdlen); memcpy(challenge, md, MSCHAP_CHALLENGE_SZ); } void -mschap_nt_response(u_int8_t *auth_challenge, u_int8_t *peer_challenge, - u_int8_t *username, int usernamelen, u_int8_t *password, int passwordlen, - u_int8_t *response) +mschap_nt_response(uint8_t *auth_challenge, uint8_t *peer_challenge, + uint8_t *username, int usernamelen, uint8_t *password, int passwordlen, + uint8_t *response) { - u_int8_t challenge[MSCHAP_CHALLENGE_SZ]; - u_int8_t password_hash[MSCHAP_HASH_SZ]; + uint8_t challenge[MSCHAP_CHALLENGE_SZ]; + uint8_t password_hash[MSCHAP_HASH_SZ]; mschap_challenge_hash(peer_challenge, auth_challenge, username, usernamelen, challenge); @@ -181,25 +181,25 @@ mschap_nt_response(u_int8_t *auth_challenge, u_int8_t *peer_challenge, } void -mschap_auth_response(u_int8_t *password, int passwordlen, - u_int8_t *ntresponse, u_int8_t *auth_challenge, u_int8_t *peer_challenge, - u_int8_t *username, int usernamelen, u_int8_t *auth_response) +mschap_auth_response(uint8_t *password, int passwordlen, + uint8_t *ntresponse, uint8_t *auth_challenge, uint8_t *peer_challenge, + uint8_t *username, int usernamelen, uint8_t *auth_response) { EVP_MD_CTX ctx; - u_int8_t password_hash[MSCHAP_HASH_SZ]; - u_int8_t password_hash2[MSCHAP_HASH_SZ]; - u_int8_t challenge[MSCHAP_CHALLENGE_SZ]; - u_int8_t md[SHA_DIGEST_LENGTH], *ptr; - u_int mdlen; + uint8_t password_hash[MSCHAP_HASH_SZ]; + uint8_t password_hash2[MSCHAP_HASH_SZ]; + uint8_t challenge[MSCHAP_CHALLENGE_SZ]; + uint8_t md[SHA_DIGEST_LENGTH], *ptr; + unsigned int mdlen; int i; - const u_int8_t hex[] = "0123456789ABCDEF"; - static u_int8_t magic1[39] = { + const uint8_t hex[] = "0123456789ABCDEF"; + static uint8_t magic1[39] = { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 }; - static u_int8_t magic2[41] = { + static uint8_t magic2[41] = { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, @@ -242,13 +242,13 @@ mschap_auth_response(u_int8_t *password, int passwordlen, } void -mschap_masterkey(u_int8_t *password_hash2, u_int8_t *ntresponse, - u_int8_t *masterkey) +mschap_masterkey(uint8_t *password_hash2, uint8_t *ntresponse, + uint8_t *masterkey) { - u_int8_t md[SHA_DIGEST_LENGTH]; - u_int mdlen; + uint8_t md[SHA_DIGEST_LENGTH]; + unsigned int mdlen; EVP_MD_CTX ctx; - static u_int8_t magic1[27] = { + static uint8_t magic1[27] = { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 @@ -264,14 +264,14 @@ mschap_masterkey(u_int8_t *password_hash2, u_int8_t *ntresponse, } void -mschap_asymetric_startkey(u_int8_t *masterkey, u_int8_t *sessionkey, +mschap_asymetric_startkey(uint8_t *masterkey, uint8_t *sessionkey, int sessionkeylen, int issend, int isserver) { EVP_MD_CTX ctx; - u_int8_t md[SHA_DIGEST_LENGTH]; - u_int mdlen; - u_int8_t *s; - static u_int8_t magic2[84] = { + uint8_t md[SHA_DIGEST_LENGTH]; + unsigned int mdlen; + uint8_t *s; + static uint8_t magic2[84] = { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, @@ -282,7 +282,7 @@ mschap_asymetric_startkey(u_int8_t *masterkey, u_int8_t *sessionkey, 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x2e }; - static u_int8_t magic3[84] = { + static uint8_t magic3[84] = { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, @@ -310,14 +310,14 @@ mschap_asymetric_startkey(u_int8_t *masterkey, u_int8_t *sessionkey, } void -mschap_msk(u_int8_t *password, int passwordlen, - u_int8_t *ntresponse, u_int8_t *msk) +mschap_msk(uint8_t *password, int passwordlen, + uint8_t *ntresponse, uint8_t *msk) { - u_int8_t password_hash[MSCHAP_HASH_SZ]; - u_int8_t password_hash2[MSCHAP_HASH_SZ]; - u_int8_t masterkey[MSCHAP_MASTERKEY_SZ]; - u_int8_t sendkey[MSCHAP_MASTERKEY_SZ]; - u_int8_t recvkey[MSCHAP_MASTERKEY_SZ]; + uint8_t password_hash[MSCHAP_HASH_SZ]; + uint8_t password_hash2[MSCHAP_HASH_SZ]; + uint8_t masterkey[MSCHAP_MASTERKEY_SZ]; + uint8_t sendkey[MSCHAP_MASTERKEY_SZ]; + uint8_t recvkey[MSCHAP_MASTERKEY_SZ]; mschap_ntpassword_hash(password, passwordlen, password_hash); mschap_ntpassword_hash(password_hash, MSCHAP_HASH_SZ, password_hash2); @@ -333,15 +333,15 @@ mschap_msk(u_int8_t *password, int passwordlen, } void -mschap_radiuskey(u_int8_t *plain, const u_int8_t *crypted, - const u_int8_t *authenticator, const u_int8_t *secret) +mschap_radiuskey(uint8_t *plain, const uint8_t *crypted, + const uint8_t *authenticator, const uint8_t *secret) { EVP_MD_CTX ctx; - u_int8_t b[MD5_DIGEST_LENGTH], p[32]; - u_int i, mdlen; + uint8_t b[MD5_DIGEST_LENGTH], p[32]; + unsigned int i, mdlen; EVP_DigestInit(&ctx, EVP_md5()); - EVP_DigestUpdate(&ctx, (char *)secret, strlen((char *)secret)); + EVP_DigestUpdate(&ctx, secret, strlen(secret)); EVP_DigestUpdate(&ctx, authenticator, 16); EVP_DigestUpdate(&ctx, crypted, 2); EVP_DigestFinal(&ctx, b, &mdlen); @@ -351,7 +351,7 @@ mschap_radiuskey(u_int8_t *plain, const u_int8_t *crypted, } EVP_DigestInit(&ctx, EVP_md5()); - EVP_DigestUpdate(&ctx, secret, strlen((char *)secret)); + EVP_DigestUpdate(&ctx, secret, strlen(secret)); EVP_DigestUpdate(&ctx, crypted + 2, mdlen); EVP_DigestFinal(&ctx, b, &mdlen); diff --git a/iked/chap_ms.h b/iked/chap_ms.h index d78d335..53b3adb 100644 --- a/iked/chap_ms.h +++ b/iked/chap_ms.h @@ -1,4 +1,4 @@ -/* $OpenBSD: chap_ms.h,v 1.5 2015/06/11 18:49:09 reyk Exp $ */ +/* $OpenBSD: chap_ms.h,v 1.6 2015/08/21 11:59:27 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -29,19 +29,19 @@ #define MSCHAP_MAXNTPASSWORD_SZ 255 /* unicode chars */ -void mschap_nt_response(u_int8_t *, u_int8_t *, u_int8_t *, int, - u_int8_t *, int , u_int8_t *); -void mschap_auth_response(u_int8_t *, int, u_int8_t *, u_int8_t *, - u_int8_t *, u_int8_t *, int, u_int8_t *); +void mschap_nt_response(uint8_t *, uint8_t *, uint8_t *, int, + uint8_t *, int , uint8_t *); +void mschap_auth_response(uint8_t *, int, uint8_t *, uint8_t *, + uint8_t *, uint8_t *, int, uint8_t *); -void mschap_ntpassword_hash(u_int8_t *, int, u_int8_t *); -void mschap_challenge_hash(u_int8_t *, u_int8_t *, u_int8_t *, - int, u_int8_t *); +void mschap_ntpassword_hash(uint8_t *, int, uint8_t *); +void mschap_challenge_hash(uint8_t *, uint8_t *, uint8_t *, + int, uint8_t *); -void mschap_asymetric_startkey(u_int8_t *, u_int8_t *, int, int, int); -void mschap_masterkey(u_int8_t *, u_int8_t *, u_int8_t *); -void mschap_radiuskey(u_int8_t *, const u_int8_t *, const u_int8_t *, - const u_int8_t *); -void mschap_msk(u_int8_t *, int, u_int8_t *, u_int8_t *); +void mschap_asymetric_startkey(uint8_t *, uint8_t *, int, int, int); +void mschap_masterkey(uint8_t *, uint8_t *, uint8_t *); +void mschap_radiuskey(uint8_t *, const uint8_t *, const uint8_t *, + const uint8_t *); +void mschap_msk(uint8_t *, int, uint8_t *, uint8_t *); #endif /* CHAP_MS_H */ diff --git a/iked/config.c b/iked/config.c index 65c6843..cc4e060 100644 --- a/iked/config.c +++ b/iked/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.36 2015/07/07 19:13:31 markus Exp $ */ +/* $OpenBSD: config.c,v 1.42 2016/06/01 11:16:41 patrick Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -62,10 +62,10 @@ config_new_sa(struct iked *env, int initiator) return (sa); } -u_int64_t +uint64_t config_getspi(void) { - u_int64_t spi; + uint64_t spi; do { arc4random_buf(&spi, sizeof spi); @@ -105,6 +105,10 @@ config_free_sa(struct iked *env, struct iked_sa *sa) (void)RB_REMOVE(iked_addrpool, &env->sc_addrpool, sa); free(sa->sa_addrpool); } + if (sa->sa_addrpool6) { + (void)RB_REMOVE(iked_addrpool6, &env->sc_addrpool6, sa); + free(sa->sa_addrpool6); + } if (sa->sa_policy) { TAILQ_REMOVE(&sa->sa_policy->pol_sapeers, sa, sa_peer_entry); @@ -143,8 +147,7 @@ config_free_sa(struct iked *env, struct iked_sa *sa) ibuf_release(sa->sa_rcert.id_buf); ibuf_release(sa->sa_eap.id_buf); - if (sa->sa_eapid != NULL) - free(sa->sa_eapid); + free(sa->sa_eapid); ibuf_release(sa->sa_eapmsk); free(sa); @@ -195,7 +198,8 @@ config_free_policy(struct iked *env, struct iked_policy *pol) } struct iked_proposal * -config_add_proposal(struct iked_proposals *head, u_int id, u_int proto) +config_add_proposal(struct iked_proposals *head, unsigned int id, + unsigned int proto) { struct iked_proposal *pp; @@ -217,7 +221,7 @@ config_add_proposal(struct iked_proposals *head, u_int id, u_int proto) } void -config_free_proposals(struct iked_proposals *head, u_int proto) +config_free_proposals(struct iked_proposals *head, unsigned int proto) { struct iked_proposal *prop, *next; @@ -284,13 +288,13 @@ config_free_childsas(struct iked *env, struct iked_childsas *head, } struct iked_transform * -config_add_transform(struct iked_proposal *prop, u_int type, - u_int id, u_int length, u_int keylength) +config_add_transform(struct iked_proposal *prop, unsigned int type, + unsigned int id, unsigned int length, unsigned int keylength) { struct iked_transform *xform; struct iked_constmap *map = NULL; int score = 1; - u_int i; + unsigned int i; switch (type) { case IKEV2_XFORMTYPE_ENCR: @@ -359,12 +363,12 @@ config_add_transform(struct iked_proposal *prop, u_int type, } struct iked_transform * -config_findtransform(struct iked_proposals *props, u_int8_t type, - u_int proto) +config_findtransform(struct iked_proposals *props, uint8_t type, + unsigned int proto) { struct iked_proposal *prop; struct iked_transform *xform; - u_int i; + unsigned int i; /* Search of the first transform with the desired type */ TAILQ_FOREACH(prop, props, prop_entry) { @@ -410,41 +414,39 @@ config_new_user(struct iked *env, struct iked_user *new) */ int -config_setcoupled(struct iked *env, u_int couple) +config_setcoupled(struct iked *env, unsigned int couple) { - u_int type; + unsigned int type; type = couple ? IMSG_CTL_COUPLE : IMSG_CTL_DECOUPLE; - proc_compose_imsg(&env->sc_ps, PROC_IKEV1, -1, type, -1, NULL, 0); - proc_compose_imsg(&env->sc_ps, PROC_IKEV2, -1, type, -1, NULL, 0); + proc_compose(&env->sc_ps, PROC_IKEV2, type, NULL, 0); return (0); } int -config_getcoupled(struct iked *env, u_int type) +config_getcoupled(struct iked *env, unsigned int type) { return (pfkey_couple(env->sc_pfkey, &env->sc_sas, type == IMSG_CTL_COUPLE ? 1 : 0)); } int -config_setmode(struct iked *env, u_int passive) +config_setmode(struct iked *env, unsigned int passive) { - u_int type; + unsigned int type; type = passive ? IMSG_CTL_PASSIVE : IMSG_CTL_ACTIVE; - proc_compose_imsg(&env->sc_ps, PROC_IKEV1, -1, type, -1, NULL, 0); - proc_compose_imsg(&env->sc_ps, PROC_IKEV2, -1, type, -1, NULL, 0); + proc_compose(&env->sc_ps, PROC_IKEV2, type, NULL, 0); return (0); } int -config_getmode(struct iked *env, u_int type) +config_getmode(struct iked *env, unsigned int type) { - u_int8_t old; - char *mode[] = { "active", "passive" }; + uint8_t old; + unsigned char *mode[] = { "active", "passive" }; old = env->sc_passive ? 1 : 0; env->sc_passive = type == IMSG_CTL_PASSIVE ? 1 : 0; @@ -459,10 +461,9 @@ config_getmode(struct iked *env, u_int type) } int -config_setreset(struct iked *env, u_int mode, enum privsep_procid id) +config_setreset(struct iked *env, unsigned int mode, enum privsep_procid id) { - proc_compose_imsg(&env->sc_ps, id, -1, - IMSG_CTL_RESET, -1, &mode, sizeof(mode)); + proc_compose(&env->sc_ps, id, IMSG_CTL_RESET, &mode, sizeof(mode)); return (0); } @@ -472,7 +473,7 @@ config_getreset(struct iked *env, struct imsg *imsg) struct iked_policy *pol, *nextpol; struct iked_sa *sa, *nextsa; struct iked_user *usr, *nextusr; - u_int mode; + unsigned int mode; IMSG_SIZE_CHECK(imsg, &mode); memcpy(&mode, imsg->data, sizeof(mode)); @@ -518,7 +519,7 @@ config_setsocket(struct iked *env, struct sockaddr_storage *ss, if ((s = udp_bind((struct sockaddr *)ss, port)) == -1) return (-1); proc_compose_imsg(&env->sc_ps, id, -1, - IMSG_UDP_SOCKET, s, ss, sizeof(*ss)); + IMSG_UDP_SOCKET, -1, s, ss, sizeof(*ss)); return (0); } @@ -574,7 +575,7 @@ config_setpfkey(struct iked *env, enum privsep_procid id) if ((s = pfkey_socket()) == -1) return (-1); proc_compose_imsg(&env->sc_ps, id, -1, - IMSG_PFKEY_SOCKET, s, NULL, 0); + IMSG_PFKEY_SOCKET, -1, s, NULL, 0); return (0); } @@ -594,8 +595,7 @@ config_setuser(struct iked *env, struct iked_user *usr, enum privsep_procid id) return (0); } - proc_compose_imsg(&env->sc_ps, id, -1, - IMSG_CFG_USER, -1, usr, sizeof(*usr)); + proc_compose(&env->sc_ps, id, IMSG_CFG_USER, usr, sizeof(*usr)); return (0); } @@ -660,13 +660,12 @@ config_setpolicy(struct iked *env, struct iked_policy *pol, iov[c++].iov_len = sizeof(*flow); } - if (env->sc_opts & IKED_OPT_NOACTION) { - print_policy(pol); + print_policy(pol); + + if (env->sc_opts & IKED_OPT_NOACTION) return (0); - } - if (proc_composev_imsg(&env->sc_ps, id, -1, - IMSG_CFG_POLICY, -1, iov, iovcnt) == -1) + if (proc_composev(&env->sc_ps, id, IMSG_CFG_POLICY, iov, iovcnt) == -1) return (-1); return (0); @@ -680,8 +679,8 @@ config_getpolicy(struct iked *env, struct imsg *imsg) struct iked_transform xf, *xform; struct iked_flow *flow; off_t offset = 0; - u_int i, j; - u_int8_t *buf = (u_int8_t *)imsg->data; + unsigned int i, j; + uint8_t *buf = (uint8_t *)imsg->data; IMSG_SIZE_CHECK(imsg, pol); log_debug("%s: received policy", __func__); @@ -735,8 +734,6 @@ config_getpolicy(struct iked *env, struct imsg *imsg) env->sc_defaultcon = pol; } - print_policy(pol); - return (0); } @@ -746,8 +743,7 @@ config_setcompile(struct iked *env, enum privsep_procid id) if (env->sc_opts & IKED_OPT_NOACTION) return (0); - proc_compose_imsg(&env->sc_ps, id, -1, - IMSG_COMPILE, -1, NULL, 0); + proc_compose(&env->sc_ps, id, IMSG_COMPILE, NULL, 0); return (0); } @@ -769,8 +765,8 @@ config_setocsp(struct iked *env) { if (env->sc_opts & IKED_OPT_NOACTION) return (0); - proc_compose_imsg(&env->sc_ps, PROC_CERT, -1, - IMSG_OCSP_URL, -1, env->sc_ocsp_url, + proc_compose(&env->sc_ps, PROC_CERT, + IMSG_OCSP_URL, env->sc_ocsp_url, env->sc_ocsp_url ? strlen(env->sc_ocsp_url) : 0); return (0); @@ -779,8 +775,7 @@ config_setocsp(struct iked *env) int config_getocsp(struct iked *env, struct imsg *imsg) { - if (env->sc_ocsp_url) - free(env->sc_ocsp_url); + free(env->sc_ocsp_url); if (IMSG_DATA_SIZE(imsg) > 0) env->sc_ocsp_url = get_string(imsg->data, IMSG_DATA_SIZE(imsg)); else diff --git a/iked/control.c b/iked/control.c index e05f6f1..256058b 100644 --- a/iked/control.c +++ b/iked/control.c @@ -1,4 +1,4 @@ -/* $OpenBSD: control.c,v 1.16 2015/01/16 06:39:58 deraadt Exp $ */ +/* $OpenBSD: control.c,v 1.21 2015/12/05 13:09:46 claudio Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -45,7 +45,32 @@ struct ctl_conn *control_connbyfd(int); void control_close(int, struct control_sock *); void control_dispatch_imsg(int, short, void *); +void control_dispatch_parent(int, short, void *); void control_imsg_forward(struct imsg *); +void control_run(struct privsep *, struct privsep_proc *, void *); + +static struct privsep_proc procs[] = { + { "parent", PROC_PARENT, NULL } +}; + +pid_t +control(struct privsep *ps, struct privsep_proc *p) +{ + return (proc_run(ps, p, procs, nitems(procs), control_run, NULL)); +} + +void +control_run(struct privsep *ps, struct privsep_proc *p, void *arg) +{ + /* + * pledge in the control process: + * stdio - for malloc and basic I/O including events. + * cpath - for unlinking the control socket. + * unix - for the control socket. + */ + if (pledge("stdio cpath unix", NULL) == -1) + fatal("pledge"); +} int control_init(struct privsep *ps, struct control_sock *cs) @@ -58,7 +83,7 @@ control_init(struct privsep *ps, struct control_sock *cs) if (cs->cs_name == NULL) return (0); - if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1) { log_warn("%s: socket", __func__); return (-1); } @@ -101,7 +126,6 @@ control_init(struct privsep *ps, struct control_sock *cs) return (-1); } - socket_set_blockmode(fd, BM_NONBLOCK); cs->cs_fd = fd; cs->cs_env = env; @@ -152,8 +176,8 @@ control_accept(int listenfd, short event, void *arg) return; len = sizeof(sun); - if ((connfd = accept(listenfd, - (struct sockaddr *)&sun, &len)) == -1) { + if ((connfd = accept4(listenfd, + (struct sockaddr *)&sun, &len, SOCK_NONBLOCK)) == -1) { /* * Pause accept if we are out of file descriptors, or * libevent will haunt us here too. @@ -169,8 +193,6 @@ control_accept(int listenfd, short event, void *arg) return; } - socket_set_blockmode(connfd, BM_NONBLOCK); - if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { log_warn("%s", __func__); close(connfd); @@ -241,7 +263,8 @@ control_dispatch_imsg(int fd, short event, void *arg) } if (event & EV_READ) { - if ((n = imsg_read(&c->iev.ibuf)) == -1 || n == 0) { + if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) || + n == 0) { control_close(fd, cs); return; } @@ -284,7 +307,6 @@ control_dispatch_imsg(int fd, short event, void *arg) proc_forward_imsg(&env->sc_ps, &imsg, PROC_PARENT, -1); proc_forward_imsg(&env->sc_ps, &imsg, PROC_IKEV2, -1); - proc_forward_imsg(&env->sc_ps, &imsg, PROC_IKEV1, -1); break; case IMSG_CTL_RELOAD: case IMSG_CTL_RESET: @@ -312,7 +334,7 @@ control_imsg_forward(struct imsg *imsg) TAILQ_FOREACH(c, &ctl_conns, entry) if (c->flags & CTL_CONN_NOTIFY) - imsg_compose(&c->iev.ibuf, imsg->hdr.type, + imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid, -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); } diff --git a/iked/crypto.c b/iked/crypto.c index 9c5a886..4931107 100644 --- a/iked/crypto.c +++ b/iked/crypto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: crypto.c,v 1.16 2015/03/26 19:52:35 markus Exp $ */ +/* $OpenBSD: crypto.c,v 1.19 2015/10/31 19:28:19 naddy Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -40,35 +40,38 @@ #include "ikev2.h" /* RFC 7427, A.1 */ -static const u_int8_t sha256WithRSAEncryption[] = { +static const uint8_t sha256WithRSAEncryption[] = { 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00 }; -static const u_int8_t sha384WithRSAEncryption[] = { +static const uint8_t sha384WithRSAEncryption[] = { 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00 }; -static const u_int8_t sha512WithRSAEncryption[] = { +static const uint8_t sha512WithRSAEncryption[] = { 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00 }; struct { - u_int8_t sc_len; - const u_int8_t *sc_oid; + uint8_t sc_len; + const uint8_t *sc_oid; const EVP_MD *(*sc_md)(void); } schemes[] = { - { sizeof(sha256WithRSAEncryption), sha256WithRSAEncryption, EVP_sha256 }, - { sizeof(sha384WithRSAEncryption), sha384WithRSAEncryption, EVP_sha384 }, - { sizeof(sha512WithRSAEncryption), sha512WithRSAEncryption, EVP_sha512 }, + { sizeof(sha256WithRSAEncryption), + sha256WithRSAEncryption, EVP_sha256 }, + { sizeof(sha384WithRSAEncryption), + sha384WithRSAEncryption, EVP_sha384 }, + { sizeof(sha512WithRSAEncryption), + sha512WithRSAEncryption, EVP_sha512 }, }; -int _dsa_verify_init(struct iked_dsa *, const u_int8_t *, size_t); -size_t _dsa_verify_offset(struct iked_dsa *, u_int8_t *); -int _dsa_sign_encode(struct iked_dsa *, u_int8_t *, size_t *); +int _dsa_verify_init(struct iked_dsa *, const uint8_t *, size_t); +size_t _dsa_verify_offset(struct iked_dsa *, uint8_t *); +int _dsa_sign_encode(struct iked_dsa *, uint8_t *, size_t *); struct iked_hash * -hash_new(u_int8_t type, u_int16_t id) +hash_new(uint8_t type, uint16_t id) { struct iked_hash *hash; const EVP_MD *md = NULL; @@ -226,7 +229,7 @@ hash_update(struct iked_hash *hash, void *buf, size_t len) void hash_final(struct iked_hash *hash, void *buf, size_t *len) { - u_int length = 0; + unsigned int length = 0; HMAC_Final(hash->hash_ctx, buf, &length); *len = (size_t)length; @@ -251,7 +254,7 @@ hash_keylength(struct iked_hash *hash) } struct iked_cipher * -cipher_new(u_int8_t type, u_int16_t id, u_int16_t id_length) +cipher_new(uint8_t type, uint16_t id, uint16_t id_length) { struct iked_cipher *encr; const EVP_CIPHER *cipher = NULL; @@ -463,7 +466,7 @@ cipher_outlength(struct iked_cipher *encr, size_t inlen) } struct iked_dsa * -dsa_new(u_int16_t id, struct iked_hash *prf, int sign) +dsa_new(uint16_t id, struct iked_hash *prf, int sign) { struct iked_dsa *dsap = NULL, dsa; @@ -495,7 +498,7 @@ dsa_new(u_int16_t id, struct iked_hash *prf, int sign) case IKEV2_AUTH_ECDSA_384: dsa.dsa_priv = EVP_sha384(); break; - case IKEV2_AUTH_ECDSA_512: + case IKEV2_AUTH_ECDSA_521: dsa.dsa_priv = EVP_sha512(); break; default: @@ -533,13 +536,13 @@ dsa_new(u_int16_t id, struct iked_hash *prf, int sign) } struct iked_dsa * -dsa_sign_new(u_int16_t id, struct iked_hash *prf) +dsa_sign_new(uint16_t id, struct iked_hash *prf) { return (dsa_new(id, prf, 1)); } struct iked_dsa * -dsa_verify_new(u_int16_t id, struct iked_hash *prf) +dsa_verify_new(uint16_t id, struct iked_hash *prf) { return (dsa_new(id, prf, 0)); } @@ -565,7 +568,7 @@ dsa_free(struct iked_dsa *dsa) } struct ibuf * -dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, u_int8_t type) +dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, uint8_t type) { BIO *rawcert = NULL; X509 *cert = NULL; @@ -637,9 +640,9 @@ dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, u_int8_t type) } int -_dsa_verify_init(struct iked_dsa *dsa, const u_int8_t *sig, size_t len) +_dsa_verify_init(struct iked_dsa *dsa, const uint8_t *sig, size_t len) { - u_int8_t oidlen; + uint8_t oidlen; size_t i; if (dsa->dsa_priv != NULL) @@ -670,7 +673,8 @@ _dsa_verify_init(struct iked_dsa *dsa, const u_int8_t *sig, size_t len) } for (i = 0; i < nitems(schemes); i++) { if (oidlen == schemes[i].sc_len && - memcmp(sig + 1, schemes[i].sc_oid, schemes[i].sc_len) == 0) { + memcmp(sig + 1, schemes[i].sc_oid, + schemes[i].sc_len) == 0) { dsa->dsa_priv = (*schemes[i].sc_md)(); log_debug("%s: signature scheme %zd selected", __func__, i); @@ -684,7 +688,7 @@ _dsa_verify_init(struct iked_dsa *dsa, const u_int8_t *sig, size_t len) int dsa_init(struct iked_dsa *dsa, const void *buf, size_t len) { - int ret; + int ret; if (dsa->dsa_hmac) { if (!HMAC_Init_ex(dsa->dsa_ctx, ibuf_data(dsa->dsa_keydata), @@ -721,7 +725,7 @@ dsa_update(struct iked_dsa *dsa, const void *buf, size_t len) /* Prefix signature hash with encoded type */ int -_dsa_sign_encode(struct iked_dsa *dsa, u_int8_t *ptr, size_t *offp) +_dsa_sign_encode(struct iked_dsa *dsa, uint8_t *ptr, size_t *offp) { if (offp) *offp = 0; @@ -754,9 +758,9 @@ dsa_length(struct iked_dsa *dsa) ssize_t dsa_sign_final(struct iked_dsa *dsa, void *buf, size_t len) { - u_int siglen; - size_t off = 0; - u_int8_t *ptr = buf; + unsigned int siglen; + size_t off = 0; + uint8_t *ptr = buf; if (len < dsa_length(dsa)) return (-1); @@ -777,7 +781,7 @@ dsa_sign_final(struct iked_dsa *dsa, void *buf, size_t len) } size_t -_dsa_verify_offset(struct iked_dsa *dsa, u_int8_t *ptr) +_dsa_verify_offset(struct iked_dsa *dsa, uint8_t *ptr) { /* * XXX assumes that _dsa_verify_init() has already checked @@ -791,9 +795,9 @@ _dsa_verify_offset(struct iked_dsa *dsa, u_int8_t *ptr) ssize_t dsa_verify_final(struct iked_dsa *dsa, void *buf, size_t len) { - u_int8_t sig[EVP_MAX_MD_SIZE]; - u_int siglen = sizeof(sig); - u_int8_t *ptr = buf; + uint8_t sig[EVP_MAX_MD_SIZE]; + unsigned int siglen = sizeof(sig); + uint8_t *ptr = buf; size_t off = 0; if (dsa->dsa_hmac) { diff --git a/iked/dh.c b/iked/dh.c index 602ded4..ba4e2cb 100644 --- a/iked/dh.c +++ b/iked/dh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dh.c,v 1.16 2015/01/16 06:39:58 deraadt Exp $ */ +/* $OpenBSD: dh.c,v 1.17 2015/08/21 11:59:27 reyk Exp $ */ /* * Copyright (c) 2010-2014 Reyk Floeter @@ -33,32 +33,33 @@ int dh_init(struct group *); /* MODP */ int modp_init(struct group *); int modp_getlen(struct group *); -int modp_create_exchange(struct group *, u_int8_t *); -int modp_create_shared(struct group *, u_int8_t *, u_int8_t *); +int modp_create_exchange(struct group *, uint8_t *); +int modp_create_shared(struct group *, uint8_t *, uint8_t *); /* EC2N/ECP */ int ec_init(struct group *); int ec_getlen(struct group *); -int ec_create_exchange(struct group *, u_int8_t *); -int ec_create_shared(struct group *, u_int8_t *, u_int8_t *); +int ec_create_exchange(struct group *, uint8_t *); +int ec_create_shared(struct group *, uint8_t *, uint8_t *); -int ec_point2raw(struct group *, const EC_POINT *, u_int8_t *, size_t); +int ec_point2raw(struct group *, const EC_POINT *, uint8_t *, size_t); EC_POINT * - ec_raw2point(struct group *, u_int8_t *, size_t); + ec_raw2point(struct group *, uint8_t *, size_t); /* curve25519 */ int ec25519_init(struct group *); int ec25519_getlen(struct group *); -int ec25519_create_exchange(struct group *, u_int8_t *); -int ec25519_create_shared(struct group *, u_int8_t *, u_int8_t *); +int ec25519_create_exchange(struct group *, uint8_t *); +int ec25519_create_shared(struct group *, uint8_t *, uint8_t *); #define CURVE25519_SIZE 32 /* 256 bits */ struct curve25519_key { - u_int8_t secret[CURVE25519_SIZE]; - u_int8_t public[CURVE25519_SIZE]; + uint8_t secret[CURVE25519_SIZE]; + uint8_t public[CURVE25519_SIZE]; }; -extern int crypto_scalarmult_curve25519(u_char a[CURVE25519_SIZE], - const u_char b[CURVE25519_SIZE], const u_char c[CURVE25519_SIZE]) +extern int crypto_scalarmult_curve25519(unsigned char a[CURVE25519_SIZE], + const unsigned char b[CURVE25519_SIZE], + const unsigned char c[CURVE25519_SIZE]) __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))) __attribute__((__bounded__(__minbytes__, 3, CURVE25519_SIZE))); @@ -342,11 +343,11 @@ group_free(struct group *group) } struct group * -group_get(u_int32_t id) +group_get(uint32_t id) { struct group_id *p = NULL; struct group *group; - u_int i, items; + unsigned int i, items; items = sizeof(ike_groups) / sizeof(ike_groups[0]); for (i = 0; i < items; i++) { @@ -410,13 +411,13 @@ dh_getlen(struct group *group) } int -dh_create_exchange(struct group *group, u_int8_t *buf) +dh_create_exchange(struct group *group, uint8_t *buf) { return (group->exchange(group, buf)); } int -dh_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange) +dh_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) { return (group->shared(group, secret, exchange)); } @@ -446,7 +447,7 @@ modp_getlen(struct group *group) } int -modp_create_exchange(struct group *group, u_int8_t *buf) +modp_create_exchange(struct group *group, uint8_t *buf) { DH *dh = group->dh; int len, ret; @@ -469,7 +470,7 @@ modp_create_exchange(struct group *group, u_int8_t *buf) } int -modp_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange) +modp_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) { BIGNUM *ex; int len, ret; @@ -517,7 +518,7 @@ ec_getlen(struct group *group) } int -ec_create_exchange(struct group *group, u_int8_t *buf) +ec_create_exchange(struct group *group, uint8_t *buf) { size_t len; @@ -529,7 +530,7 @@ ec_create_exchange(struct group *group, u_int8_t *buf) } int -ec_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange) +ec_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) { const EC_GROUP *ecgroup = NULL; const BIGNUM *privkey; @@ -577,7 +578,7 @@ ec_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange) int ec_point2raw(struct group *group, const EC_POINT *point, - u_int8_t *buf, size_t len) + uint8_t *buf, size_t len) { const EC_GROUP *ecgroup = NULL; BN_CTX *bnctx = NULL; @@ -636,7 +637,7 @@ ec_point2raw(struct group *group, const EC_POINT *point, } EC_POINT * -ec_raw2point(struct group *group, u_int8_t *buf, size_t len) +ec_raw2point(struct group *group, uint8_t *buf, size_t len) { const EC_GROUP *ecgroup = NULL; EC_POINT *point = NULL; @@ -696,7 +697,7 @@ ec_raw2point(struct group *group, u_int8_t *buf, size_t len) int ec25519_init(struct group *group) { - static const u_int8_t basepoint[CURVE25519_SIZE] = { 9 }; + static const uint8_t basepoint[CURVE25519_SIZE] = { 9 }; struct curve25519_key *curve25519; if ((curve25519 = calloc(1, sizeof(*curve25519))) == NULL) @@ -720,7 +721,7 @@ ec25519_getlen(struct group *group) } int -ec25519_create_exchange(struct group *group, u_int8_t *buf) +ec25519_create_exchange(struct group *group, uint8_t *buf) { struct curve25519_key *curve25519 = group->curve25519; @@ -729,7 +730,7 @@ ec25519_create_exchange(struct group *group, u_int8_t *buf) } int -ec25519_create_shared(struct group *group, u_int8_t *shared, u_int8_t *public) +ec25519_create_shared(struct group *group, uint8_t *shared, uint8_t *public) { struct curve25519_key *curve25519 = group->curve25519; diff --git a/iked/dh.h b/iked/dh.h index f39d6e9..e5b825c 100644 --- a/iked/dh.h +++ b/iked/dh.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dh.h,v 1.7 2015/06/11 18:49:09 reyk Exp $ */ +/* $OpenBSD: dh.h,v 1.9 2015/08/21 11:59:27 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -28,7 +28,7 @@ enum group_type { struct group_id { enum group_type type; - u_int id; + unsigned int id; int bits; char *prime; char *generator; @@ -45,18 +45,18 @@ struct group { int (*init)(struct group *); int (*getlen)(struct group *); - int (*exchange)(struct group *, u_int8_t *); - int (*shared)(struct group *, u_int8_t *, u_int8_t *); + int (*exchange)(struct group *, uint8_t *); + int (*shared)(struct group *, uint8_t *, uint8_t *); }; #define DH_MAXSZ 1024 /* 8192 bits */ void group_init(void); void group_free(struct group *); -struct group *group_get(u_int32_t); +struct group *group_get(uint32_t); int dh_getlen(struct group *); -int dh_create_exchange(struct group *, u_int8_t *); -int dh_create_shared(struct group *, u_int8_t *, u_int8_t *); +int dh_create_exchange(struct group *, uint8_t *); +int dh_create_shared(struct group *, uint8_t *, uint8_t *); #endif /* DH_GROUP_H */ diff --git a/iked/eap.c b/iked/eap.c index 0648e0f..2b8e87c 100644 --- a/iked/eap.c +++ b/iked/eap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: eap.c,v 1.13 2015/02/06 10:39:01 deraadt Exp $ */ +/* $OpenBSD: eap.c,v 1.14 2015/08/21 11:59:27 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -66,9 +66,9 @@ eap_identity_request(struct ibuf *e) char * eap_identity_response(struct eap_message *eap) { - size_t len; - char *str; - u_int8_t *ptr = (u_int8_t *)eap; + size_t len; + char *str; + uint8_t *ptr = (uint8_t *)eap; len = betoh16(eap->eap_length) - sizeof(*eap); ptr += sizeof(*eap); @@ -172,11 +172,11 @@ eap_mschap(struct iked *env, struct iked_sa *sa, struct eap_message *eap) struct eap_mschap_peer *msp; struct eap_mschap *ms; struct eap_mschap_success *mss; - u_int8_t *ptr, *pass; + uint8_t *ptr, *pass; size_t len, passlen; char *name, *msg; - u_int8_t ntresponse[EAP_MSCHAP_NTRESPONSE_SZ]; - u_int8_t successmsg[EAP_MSCHAP_SUCCESS_SZ]; + uint8_t ntresponse[EAP_MSCHAP_NTRESPONSE_SZ]; + uint8_t successmsg[EAP_MSCHAP_SUCCESS_SZ]; struct ibuf *eapmsg = NULL; int ret = -1; @@ -203,7 +203,7 @@ eap_mschap(struct iked *env, struct iked_sa *sa, struct eap_message *eap) } ms = (struct eap_mschap *)(eap + 1); - ptr = (u_int8_t *)(eap + 1); + ptr = (uint8_t *)(eap + 1); switch (ms->ms_opcode) { case EAP_MSOPCODE_RESPONSE: @@ -235,8 +235,8 @@ eap_mschap(struct iked *env, struct iked_sa *sa, struct eap_message *eap) msp = &msr->msr_response.resp_peer; mschap_nt_response(ibuf_data(sa->sa_eap.id_buf), - msp->msp_challenge, (u_char *)usr->usr_name, - strlen(usr->usr_name), pass, passlen, ntresponse); + msp->msp_challenge, usr->usr_name, strlen(usr->usr_name), + pass, passlen, ntresponse); if (memcmp(ntresponse, msp->msp_ntresponse, sizeof(ntresponse)) != 0) { @@ -251,8 +251,8 @@ eap_mschap(struct iked *env, struct iked_sa *sa, struct eap_message *eap) bzero(&successmsg, sizeof(successmsg)); mschap_auth_response(pass, passlen, ntresponse, ibuf_data(sa->sa_eap.id_buf), - msp->msp_challenge, (u_char *)usr->usr_name, - strlen(usr->usr_name), successmsg); + msp->msp_challenge, usr->usr_name, strlen(usr->usr_name), + successmsg); if ((sa->sa_eapmsk = ibuf_new(NULL, MSCHAP_MSK_SZ)) == NULL) { log_debug("%s: failed to get MSK", __func__); free(pass); @@ -331,7 +331,7 @@ eap_parse(struct iked *env, struct iked_sa *sa, void *data, int response) struct eap_header *hdr = data; struct eap_message *eap = data; size_t len; - u_int8_t *ptr; + uint8_t *ptr; struct eap_mschap *ms; struct eap_mschap_challenge *msc; struct eap_mschap_response *msr; @@ -341,7 +341,7 @@ eap_parse(struct iked *env, struct iked_sa *sa, void *data, int response) /* length is already verified by the caller */ len = betoh16(hdr->eap_length); - ptr = (u_int8_t *)(eap + 1); + ptr = (uint8_t *)(eap + 1); switch (hdr->eap_code) { case EAP_CODE_REQUEST: diff --git a/iked/eap.h b/iked/eap.h index 799750c..cc567ea 100644 --- a/iked/eap.h +++ b/iked/eap.h @@ -1,4 +1,4 @@ -/* $OpenBSD: eap.h,v 1.4 2015/06/11 18:49:09 reyk Exp $ */ +/* $OpenBSD: eap.h,v 1.5 2015/08/21 11:59:27 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -20,16 +20,16 @@ #define IKED_EAP_H struct eap_header { - u_int8_t eap_code; - u_int8_t eap_id; - u_int16_t eap_length; + uint8_t eap_code; + uint8_t eap_id; + uint16_t eap_length; } __packed; struct eap_message { - u_int8_t eap_code; - u_int8_t eap_id; - u_int16_t eap_length; - u_int8_t eap_type; + uint8_t eap_code; + uint8_t eap_id; + uint16_t eap_length; + uint8_t eap_type; /* Followed by type-specific data */ } __packed; @@ -114,48 +114,48 @@ extern struct iked_constmap eap_type_map[]; extern struct iked_constmap eap_msopcode_map[]; struct eap_mschap { - u_int8_t ms_opcode; + uint8_t ms_opcode; } __packed; struct eap_mschap_challenge { - u_int8_t msc_opcode; - u_int8_t msc_id; - u_int16_t msc_length; - u_int8_t msc_valuesize; - u_int8_t msc_challenge[EAP_MSCHAP_CHALLENGE_SZ]; + uint8_t msc_opcode; + uint8_t msc_id; + uint16_t msc_length; + uint8_t msc_valuesize; + uint8_t msc_challenge[EAP_MSCHAP_CHALLENGE_SZ]; /* Followed by variable-size name field */ } __packed; struct eap_mschap_peer { - u_int8_t msp_challenge[EAP_MSCHAP_CHALLENGE_SZ]; - u_int8_t msp_reserved[8]; - u_int8_t msp_ntresponse[EAP_MSCHAP_NTRESPONSE_SZ]; - u_int8_t msp_flags; + uint8_t msp_challenge[EAP_MSCHAP_CHALLENGE_SZ]; + uint8_t msp_reserved[8]; + uint8_t msp_ntresponse[EAP_MSCHAP_NTRESPONSE_SZ]; + uint8_t msp_flags; }; struct eap_mschap_response { - u_int8_t msr_opcode; - u_int8_t msr_id; - u_int16_t msr_length; - u_int8_t msr_valuesize; + uint8_t msr_opcode; + uint8_t msr_id; + uint16_t msr_length; + uint8_t msr_valuesize; union { - u_int8_t resp_data[EAP_MSCHAP_RESPONSE_SZ]; + uint8_t resp_data[EAP_MSCHAP_RESPONSE_SZ]; struct eap_mschap_peer resp_peer; } msr_response; /* Followed by variable-size name field */ } __packed; struct eap_mschap_success { - u_int8_t mss_opcode; - u_int8_t mss_id; - u_int16_t mss_length; + uint8_t mss_opcode; + uint8_t mss_id; + uint16_t mss_length; /* Followed by variable-size success message */ } __packed; struct eap_mschap_failure { - u_int8_t msf_opcode; - u_int8_t msf_id; - u_int16_t msf_length; + uint8_t msf_opcode; + uint8_t msf_id; + uint16_t msf_length; /* Followed by variable-size message field */ } __packed; diff --git a/iked/iked.c b/iked/iked.c index 80df98c..63dc075 100644 --- a/iked/iked.c +++ b/iked/iked.c @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.c,v 1.24 2015/06/03 02:24:36 millert Exp $ */ +/* $OpenBSD: iked.c,v 1.30 2015/12/07 12:46:37 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -39,14 +40,14 @@ __dead void usage(void); void parent_shutdown(struct iked *); void parent_sig_handler(int, short, void *); -int parent_dispatch_ikev1(int, struct privsep_proc *, struct imsg *); -int parent_dispatch_ikev2(int, struct privsep_proc *, struct imsg *); int parent_dispatch_ca(int, struct privsep_proc *, struct imsg *); +int parent_dispatch_control(int, struct privsep_proc *, struct imsg *); int parent_configure(struct iked *); static struct privsep_proc procs[] = { - { "ikev2", PROC_IKEV2, parent_dispatch_ikev2, ikev2 }, - { "ca", PROC_CERT, parent_dispatch_ca, caproc, IKED_CA } + { "ca", PROC_CERT, parent_dispatch_ca, caproc, IKED_CA }, + { "control", PROC_CONTROL, parent_dispatch_control, control }, + { "ikev2", PROC_IKEV2, NULL, ikev2 } }; __dead void @@ -69,7 +70,7 @@ main(int argc, char *argv[]) struct iked *env = NULL; struct privsep *ps; - log_init(1); + log_init(1, LOG_DAEMON); while ((c = getopt(argc, argv, "6dD:nf:vSTt")) != -1) { switch (c) { @@ -138,7 +139,7 @@ main(int argc, char *argv[]) /* Configure the control socket */ ps->ps_csock.cs_name = IKED_SOCKET; - log_init(debug); + log_init(debug, LOG_DAEMON); log_verbose(verbose); if (!debug && daemon(0, 0) == -1) @@ -150,6 +151,7 @@ main(int argc, char *argv[]) proc_init(ps, procs, nitems(procs)); setproctitle("parent"); + log_procinit("parent"); event_init(); @@ -199,7 +201,6 @@ parent_configure(struct iked *env) config_setpfkey(env, PROC_IKEV2); /* Now compile the policies and calculate skip steps */ - config_setcompile(env, PROC_IKEV1); config_setcompile(env, PROC_IKEV2); bzero(&ss, sizeof(ss)); @@ -218,6 +219,24 @@ parent_configure(struct iked *env) if ((env->sc_opts & IKED_OPT_NONATT) == 0) config_setsocket(env, &ss, ntohs(IKED_NATT_PORT), PROC_IKEV2); + /* + * pledge in the parent process: + * It has to run fairly late to allow forking the processes and + * opening the PFKEY socket and the listening UDP sockets (once) + * that need the bypass ioctls that are never allowed by pledge. + * + * Other flags: + * stdio - for malloc and basic I/O including events. + * rpath - for reload to open and read the configuration files. + * proc - run kill to terminate its children safely. + * dns - for reload and ocsp connect. + * inet - for ocsp connect. + * route - for using interfaces in iked.conf (SIOCGIFGMEMB) + * sendfd - for ocsp sockets. + */ + if (pledge("stdio rpath proc dns inet route sendfd", NULL) == -1) + fatal("pledge"); + config_setcoupled(env, env->sc_decoupled ? 0 : 1); config_setmode(env, env->sc_passive ? 1 : 0); config_setocsp(env); @@ -235,7 +254,6 @@ parent_reload(struct iked *env, int reset, const char *filename) log_debug("%s: level %d config file %s", __func__, reset, filename); if (reset == RESET_RELOAD) { - config_setreset(env, RESET_POLICY, PROC_IKEV1); config_setreset(env, RESET_POLICY, PROC_IKEV2); config_setreset(env, RESET_CA, PROC_CERT); @@ -245,14 +263,12 @@ parent_reload(struct iked *env, int reset, const char *filename) } /* Re-compile policies and skip steps */ - config_setcompile(env, PROC_IKEV1); config_setcompile(env, PROC_IKEV2); config_setcoupled(env, env->sc_decoupled ? 0 : 1); config_setmode(env, env->sc_passive ? 1 : 0); config_setocsp(env); } else { - config_setreset(env, reset, PROC_IKEV1); config_setreset(env, reset, PROC_IKEV2); config_setreset(env, reset, PROC_CERT); } @@ -334,34 +350,28 @@ parent_sig_handler(int sig, short event, void *arg) } int -parent_dispatch_ikev1(int fd, struct privsep_proc *p, struct imsg *imsg) +parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg) { - switch (imsg->hdr.type) { - default: - break; - } - - return (-1); -} + struct iked *env = p->p_ps->ps_env; -int -parent_dispatch_ikev2(int fd, struct privsep_proc *p, struct imsg *imsg) -{ switch (imsg->hdr.type) { - default: + case IMSG_OCSP_FD: + ocsp_connect(env); break; + default: + return (-1); } - return (-1); + return (0); } int -parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg) +parent_dispatch_control(int fd, struct privsep_proc *p, struct imsg *imsg) { struct iked *env = p->p_ps->ps_env; int v; char *str = NULL; - u_int type = imsg->hdr.type; + unsigned int type = imsg->hdr.type; switch (type) { case IMSG_CTL_RESET: @@ -373,20 +383,13 @@ parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg) case IMSG_CTL_DECOUPLE: case IMSG_CTL_ACTIVE: case IMSG_CTL_PASSIVE: - proc_compose_imsg(&env->sc_ps, PROC_IKEV1, -1, - type, -1, NULL, 0); - proc_compose_imsg(&env->sc_ps, PROC_IKEV2, -1, - type, -1, NULL, 0); + proc_compose(&env->sc_ps, PROC_IKEV2, type, NULL, 0); break; case IMSG_CTL_RELOAD: if (IMSG_DATA_SIZE(imsg) > 0) str = get_string(imsg->data, IMSG_DATA_SIZE(imsg)); parent_reload(env, 0, str); - if (str != NULL) - free(str); - break; - case IMSG_OCSP_FD: - ocsp_connect(env); + free(str); break; default: return (-1); diff --git a/iked/iked.conf.5 b/iked/iked.conf.5 index d02e08e..d98ced3 100644 --- a/iked/iked.conf.5 +++ b/iked/iked.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: iked.conf.5,v 1.39 2015/07/14 13:06:37 jmc Exp $ +.\" $OpenBSD: iked.conf.5,v 1.44 2015/12/09 21:41:49 naddy Exp $ .\" .\" Copyright (c) 2010 - 2014 Reyk Floeter .\" Copyright (c) 2004 Mathieu Sauve-Frankel All rights reserved. @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: July 14 2015 $ +.Dd $Mdocdate: December 9 2015 $ .Dt IKED.CONF 5 .Os .Sh NAME @@ -678,8 +678,10 @@ queue ipsec parent std bandwidth 10M pass out on ix0 proto esp set queue ipsec -pass out on ix0 tagged ipsec-developers.example.com set queue developers -pass out on ix0 tagged ipsec-employees.example.com set queue employees +pass out on ix0 tagged ipsec-developers.example.com \e + set queue developers +pass out on ix0 tagged ipsec-employees.example.com \e + set queue employees .Ed .Pp The following example assigns the tags in the @@ -718,7 +720,8 @@ a relevant NAT rule is required in For the example above, this would be: .Bd -literal -offset indent -match out on enc0 from 192.168.1.0/24 to 192.168.2.0/24 nat-to 10.10.10.1 +match out on enc0 from 192.168.1.0/24 to 192.168.2.0/24 \e + nat-to 10.10.10.1 .Ed .Pp From the peer's point of view, @@ -740,8 +743,8 @@ keyword: The following pseudo-random function types are permitted with the .Ic prf keyword: -.Bl -column "Authentication" "Key Length" "[IKE only]" -offset indent -.It Em "Authentication" Ta Em "Key Length" Ta "" +.Bl -column "hmac-sha2-512" "Key Length" "[IKE only]" -offset indent +.It Em "PRF" Ta Em "Key Length" Ta "" .It Li hmac-md5 Ta "128 bits" Ta "[IKE only]" .It Li hmac-sha1 Ta "160 bits" Ta "[IKE only]" .It Li hmac-sha2-256 Ta "256 bits" Ta "[IKE only]" @@ -752,9 +755,8 @@ keyword: The following cipher types are permitted with the .Ic enc keyword: -.Bl -column "aes-128-gmac" "Key Length" "[ESP only]" -offset indent +.Bl -column "chacha20-poly1305" "Key Length" "[ESP only]" -offset indent .It Em "Cipher" Ta Em "Key Length" Ta "" -.It Li des Ta "56 bits" Ta "[ESP only]" .It Li 3des Ta "168 bits" Ta "" .It Li aes-128 Ta "128 bits" Ta "" .It Li aes-192 Ta "192 bits" Ta "" @@ -767,31 +769,29 @@ keyword: .It Li aes-256-gcm Ta "288 bits" Ta "[ESP only]" .It Li blowfish Ta "160 bits" Ta "[ESP only]" .It Li cast Ta "128 bits" Ta "[ESP only]" +.It Li chacha20-poly1305 Ta "288 bits" Ta "[ESP only]" .El .Pp The following cipher types provide only authentication, not encryption: -.Bl -column "aes-128-gmac" "Key Length" "[ESP only]" -offset indent +.Bl -column "chacha20-poly1305" "Key Length" "[ESP only]" -offset indent .It Li aes-128-gmac Ta "160 bits" Ta "[ESP only]" .It Li aes-192-gmac Ta "224 bits" Ta "[ESP only]" .It Li aes-256-gmac Ta "288 bits" Ta "[ESP only]" .It Li null Ta "" Ta "[ESP only]" .El .Pp -Use of DES as an encryption algorithm is considered to be insecure -since brute force attacks are practical due its short key length. -.Pp -DES requires 8 bytes to form a 56-bit key and 3DES requires 24 bytes -to form its 168-bit key. +3DES requires 24 bytes to form its 168-bit key. This is because the most significant bit of each byte is used for parity. .Pp The keysize of AES-CTR is actually 128-bit. However as well as the key, a 32-bit nonce has to be supplied. Thus 160 bits of key material have to be supplied. -The same applies to AES-GCM and AES-GMAC. +The same applies to AES-GCM, AES-GMAC and Chacha20-Poly1305, +however in the latter case the keysize is 256 bit. .Pp Using AES-GMAC or NULL with ESP will only provide authentication. -This is useful in setups where AH can not be used, e.g. when NAT is involved. +This is useful in setups where AH cannot be used, e.g. when NAT is involved. .Pp The following group types are permitted with the .Ic group diff --git a/iked/iked.h b/iked/iked.h index 48a63c5..6825a16 100644 --- a/iked/iked.h +++ b/iked/iked.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.h,v 1.86 2015/07/07 19:13:31 markus Exp $ */ +/* $OpenBSD: iked.h,v 1.96 2016/06/01 11:16:41 patrick Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -20,7 +20,7 @@ #include -#include "imsg.h" +#include #include "types.h" #include "dh.h" @@ -33,14 +33,14 @@ */ struct ike_header { - u_int64_t ike_ispi; /* Initiator cookie */ - u_int64_t ike_rspi; /* Responder cookie */ - u_int8_t ike_nextpayload; /* Next payload type */ - u_int8_t ike_version; /* Major/Minor version number */ - u_int8_t ike_exchange; /* Exchange type */ - u_int8_t ike_flags; /* Message options */ - u_int32_t ike_msgid; /* Message identifier */ - u_int32_t ike_length; /* Total message length */ + uint64_t ike_ispi; /* Initiator cookie */ + uint64_t ike_rspi; /* Responder cookie */ + uint8_t ike_nextpayload; /* Next payload type */ + uint8_t ike_version; /* Major/Minor version number */ + uint8_t ike_exchange; /* Exchange type */ + uint8_t ike_flags; /* Message options */ + uint32_t ike_msgid; /* Message identifier */ + uint32_t ike_length; /* Total message length */ } __packed; /* @@ -88,12 +88,12 @@ TAILQ_HEAD(control_socks, control_sock); struct ctl_conn { TAILQ_ENTRY(ctl_conn) entry; - u_int8_t flags; + uint8_t flags; #define CTL_CONN_NOTIFY 0x01 struct imsgev iev; }; TAILQ_HEAD(ctl_connlist, ctl_conn); -extern struct ctl_connlist ctl_conns; +extern struct ctl_connlist ctl_conns; enum privsep_procid privsep_process; @@ -109,20 +109,20 @@ struct iked_timer { }; struct iked_spi { - u_int64_t spi; - u_int8_t spi_size; - u_int8_t spi_protoid; + uint64_t spi; + uint8_t spi_size; + uint8_t spi_protoid; }; struct iked_proposal { - u_int8_t prop_id; - u_int8_t prop_protoid; + uint8_t prop_id; + uint8_t prop_protoid; struct iked_spi prop_localspi; struct iked_spi prop_peerspi; struct iked_transform *prop_xforms; - u_int prop_nxforms; + unsigned int prop_nxforms; TAILQ_ENTRY(iked_proposal) prop_entry; }; @@ -131,7 +131,7 @@ TAILQ_HEAD(iked_proposals, iked_proposal); struct iked_addr { int addr_af; struct sockaddr_storage addr; - u_int8_t addr_mask; + uint8_t addr_mask; int addr_net; in_port_t addr_port; }; @@ -139,14 +139,14 @@ struct iked_addr { struct iked_flow { struct iked_addr flow_src; struct iked_addr flow_dst; - u_int flow_dir; /* in/out */ + unsigned int flow_dir; /* in/out */ - u_int flow_loaded; /* pfkey done */ + unsigned int flow_loaded; /* pfkey done */ + + uint8_t flow_saproto; + uint8_t flow_ipproto; + uint8_t flow_type; - u_int8_t flow_saproto; - u_int8_t flow_ipproto; - u_int8_t flow_type; - u_int32_t flow_id; struct iked_addr *flow_local; /* outer source */ struct iked_addr *flow_peer; /* outer dest */ struct iked_sa *flow_ikesa; /* parent SA */ @@ -158,24 +158,24 @@ RB_HEAD(iked_flows, iked_flow); TAILQ_HEAD(iked_saflows, iked_flow); struct iked_childsa { - u_int8_t csa_saproto; /* IPSec protocol */ - u_int csa_dir; /* in/out */ + uint8_t csa_saproto; /* IPSec protocol */ + unsigned int csa_dir; /* in/out */ - u_int64_t csa_peerspi; /* peer relation */ - u_int8_t csa_loaded; /* pfkey done */ - u_int8_t csa_rekey; /* will be deleted */ - u_int8_t csa_allocated; /* from the kernel */ - u_int8_t csa_persistent;/* do not rekey */ - u_int8_t csa_esn; /* use ESN */ - u_int8_t csa_transport; /* transport mode */ + uint64_t csa_peerspi; /* peer relation */ + uint8_t csa_loaded; /* pfkey done */ + uint8_t csa_rekey; /* will be deleted */ + uint8_t csa_allocated; /* from the kernel */ + uint8_t csa_persistent;/* do not rekey */ + uint8_t csa_esn; /* use ESN */ + uint8_t csa_transport; /* transport mode */ struct iked_spi csa_spi; struct ibuf *csa_encrkey; /* encryption key */ - u_int16_t csa_encrid; /* encryption xform id */ + uint16_t csa_encrid; /* encryption xform id */ struct ibuf *csa_integrkey; /* auth key */ - u_int16_t csa_integrid; /* auth xform id */ + uint16_t csa_integrid; /* auth xform id */ struct iked_addr *csa_local; /* outer source */ struct iked_addr *csa_peer; /* outer dest */ @@ -184,7 +184,7 @@ struct iked_childsa { struct iked_childsa *csa_peersa; /* peer */ struct iked_childsa *csa_parent; /* IPCOMP parent */ - u_int csa_children; /* IPCOMP children */ + unsigned int csa_children; /* IPCOMP children */ RB_ENTRY(iked_childsa) csa_node; TAILQ_ENTRY(iked_childsa) csa_entry; @@ -194,22 +194,22 @@ TAILQ_HEAD(iked_childsas, iked_childsa); struct iked_static_id { - u_int8_t id_type; - u_int8_t id_length; - u_int8_t id_offset; - u_int8_t id_data[IKED_ID_SIZE]; + uint8_t id_type; + uint8_t id_length; + uint8_t id_offset; + uint8_t id_data[IKED_ID_SIZE]; }; struct iked_auth { - u_int8_t auth_method; - u_int8_t auth_eap; /* optional EAP */ - u_int8_t auth_length; /* zero if EAP */ - u_int8_t auth_data[IKED_PSK_SIZE]; + uint8_t auth_method; + uint8_t auth_eap; /* optional EAP */ + uint8_t auth_length; /* zero if EAP */ + uint8_t auth_data[IKED_PSK_SIZE]; }; struct iked_cfg { - u_int8_t cfg_action; - u_int16_t cfg_type; + uint8_t cfg_action; + uint16_t cfg_type; union { struct iked_addr address; } cfg; @@ -218,12 +218,12 @@ struct iked_cfg { TAILQ_HEAD(iked_sapeers, iked_sa); struct iked_lifetime { - u_int64_t lt_bytes; - u_int64_t lt_seconds; + uint64_t lt_bytes; + uint64_t lt_seconds; }; struct iked_policy { - u_int pol_id; + unsigned int pol_id; char pol_name[IKED_ID_SIZE]; #define IKED_SKIP_FLAGS 0 @@ -234,7 +234,7 @@ struct iked_policy { #define IKED_SKIP_COUNT 5 struct iked_policy *pol_skip[IKED_SKIP_COUNT]; - u_int8_t pol_flags; + uint8_t pol_flags; #define IKED_POLICY_PASSIVE 0x00 #define IKED_POLICY_DEFAULT 0x01 #define IKED_POLICY_ACTIVE 0x02 @@ -246,11 +246,11 @@ struct iked_policy { int pol_refcnt; - u_int8_t pol_certreqtype; + uint8_t pol_certreqtype; int pol_af; - u_int8_t pol_saproto; - u_int pol_ipproto; + uint8_t pol_saproto; + unsigned int pol_ipproto; struct iked_addr pol_peer; struct group *pol_peerdh; @@ -262,7 +262,7 @@ struct iked_policy { struct iked_auth pol_auth; char pol_tag[IKED_TAG_SIZE]; - u_int pol_tap; + unsigned int pol_tap; struct iked_proposals pol_proposals; size_t pol_nproposals; @@ -271,9 +271,9 @@ struct iked_policy { size_t pol_nflows; struct iked_cfg pol_cfg[IKED_CFG_MAX]; - u_int pol_ncfg; + unsigned int pol_ncfg; - u_int32_t pol_rekey; /* ike SA lifetime */ + uint32_t pol_rekey; /* ike SA lifetime */ struct iked_lifetime pol_lifetime; /* child SA lifetime */ struct iked_sapeers pol_sapeers; @@ -283,8 +283,8 @@ struct iked_policy { TAILQ_HEAD(iked_policies, iked_policy); struct iked_hash { - u_int8_t hash_type; /* PRF or INTEGR */ - u_int16_t hash_id; /* IKE PRF/INTEGR hash id */ + uint8_t hash_type; /* PRF or INTEGR */ + uint16_t hash_id; /* IKE PRF/INTEGR hash id */ const void *hash_priv; /* Identifying the hash alg */ void *hash_ctx; /* Context of the current invocation */ int hash_fixedkey; /* Requires fixed key length */ @@ -295,8 +295,8 @@ struct iked_hash { }; struct iked_cipher { - u_int8_t encr_type; /* ENCR */ - u_int16_t encr_id; /* IKE ENCR hash id */ + uint8_t encr_type; /* ENCR */ + uint16_t encr_id; /* IKE ENCR hash id */ const void *encr_priv; /* Identifying the hash alg */ void *encr_ctx; /* Context of the current invocation */ int encr_fixedkey; /* Requires fixed key length */ @@ -307,7 +307,7 @@ struct iked_cipher { }; struct iked_dsa { - u_int8_t dsa_method; /* AUTH method */ + uint8_t dsa_method; /* AUTH method */ const void *dsa_priv; /* PRF or signature hash function */ void *dsa_ctx; /* PRF or signature hash ctx */ struct ibuf *dsa_keydata; /* public, private or shared key */ @@ -318,29 +318,31 @@ struct iked_dsa { }; struct iked_id { - u_int8_t id_type; - u_int8_t id_offset; + uint8_t id_type; + uint8_t id_offset; struct ibuf *id_buf; }; -#define IKED_REQ_CERT 0x01 /* get local certificate (if required) */ -#define IKED_REQ_CERTVALID 0x02 /* validated the peer cert */ -#define IKED_REQ_AUTH 0x04 /* AUTH payload */ -#define IKED_REQ_AUTHVALID 0x08 /* AUTH payload has been verified */ -#define IKED_REQ_SA 0x10 /* SA available */ -#define IKED_REQ_EAPVALID 0x20 /* EAP payload has been verified */ -#define IKED_REQ_CHILDSA 0x40 /* Child SA initiated */ -#define IKED_REQ_INF 0x80 /* Informational exchange initiated */ +#define IKED_REQ_CERT 0x0001 /* get local certificate (if required) */ +#define IKED_REQ_CERTVALID 0x0002 /* validated the peer cert */ +#define IKED_REQ_CERTREQ 0x0004 /* CERTREQ has been received */ +#define IKED_REQ_AUTH 0x0008 /* AUTH payload */ +#define IKED_REQ_AUTHVALID 0x0010 /* AUTH payload has been verified */ +#define IKED_REQ_SA 0x0020 /* SA available */ +#define IKED_REQ_EAPVALID 0x0040 /* EAP payload has been verified */ +#define IKED_REQ_CHILDSA 0x0080 /* Child SA initiated */ +#define IKED_REQ_INF 0x0100 /* Informational exchange initiated */ #define IKED_REQ_BITS \ - "\20\01CERT\02CERTVALID\03AUTH\04AUTHVALID\05SA\06EAP" + "\20\01CERT\02CERTVALID\03CERTREQ\04AUTH\05AUTHVALID\06SA\07EAPVALID" \ + "\10CHILDSA\11INF" TAILQ_HEAD(iked_msgqueue, iked_message); struct iked_sahdr { - u_int64_t sh_ispi; /* Initiator SPI */ - u_int64_t sh_rspi; /* Responder SPI */ - u_int sh_initiator; /* Is initiator? */ + uint64_t sh_ispi; /* Initiator SPI */ + uint64_t sh_rspi; /* Responder SPI */ + unsigned int sh_initiator; /* Is initiator? */ } __packed; struct iked_kex { @@ -355,9 +357,9 @@ struct iked_kex { struct iked_sa { struct iked_sahdr sa_hdr; - u_int32_t sa_msgid; /* Last request rcvd */ + uint32_t sa_msgid; /* Last request rcvd */ int sa_msgid_set; /* msgid initialized */ - u_int32_t sa_reqid; /* Next request sent */ + uint32_t sa_reqid; /* Next request sent */ int sa_type; #define IKED_SATYPE_LOOKUP 0 /* Used for lookup */ @@ -371,9 +373,9 @@ struct iked_sa { int sa_udpencap; /* for pfkey */ int sa_state; - u_int sa_stateflags; - u_int sa_stateinit; /* SA_INIT */ - u_int sa_statevalid; /* IKE_AUTH */ + unsigned int sa_stateflags; + unsigned int sa_stateinit; /* SA_INIT */ + unsigned int sa_statevalid; /* IKE_AUTH */ int sa_cp; /* XXX */ @@ -425,12 +427,12 @@ struct iked_sa { struct iked_saflows sa_flows; /* IPSec flows */ struct iked_sa *sa_next; /* IKE SA rekeying */ - u_int64_t sa_rekeyspi; /* peerspi for rekey*/ + uint64_t sa_rekeyspi; /* peerspi for rekey*/ - u_int8_t sa_transport; /* Transport mode */ - u_int8_t sa_ipcomp; /* IPcomp transform */ - u_int16_t sa_cpi_out; /* IPcomp outgoing */ - u_int16_t sa_cpi_in; /* IPcomp incoming*/ + uint8_t sa_transport; /* Transport mode */ + uint8_t sa_ipcomp; /* IPcomp transform */ + uint16_t sa_cpi_out; /* IPcomp outgoing */ + uint16_t sa_cpi_in; /* IPcomp incoming*/ struct iked_timer sa_timer; /* SA timeouts */ #define IKED_IKE_SA_DELETE_TIMEOUT 300 /* 5 minutes */ @@ -449,9 +451,13 @@ struct iked_sa { struct iked_addr *sa_addrpool; /* address from pool */ RB_ENTRY(iked_sa) sa_addrpool_entry; /* pool entries */ + + struct iked_addr *sa_addrpool6; /* address from pool */ + RB_ENTRY(iked_sa) sa_addrpool6_entry; /* pool entries */ }; RB_HEAD(iked_sas, iked_sa); RB_HEAD(iked_addrpool, iked_sa); +RB_HEAD(iked_addrpool6, iked_sa); struct iked_message { struct ibuf *msg_data; @@ -477,8 +483,8 @@ struct iked_message { struct iked_policy *msg_policy; struct iked_sa *msg_sa; - u_int32_t msg_msgid; - u_int8_t msg_exchange; + uint32_t msg_msgid; + uint8_t msg_exchange; /* Parsed information */ struct iked_proposals msg_proposals; @@ -491,7 +497,7 @@ struct iked_message { /* Parse stack */ struct iked_proposal *msg_prop; - u_int16_t msg_attrlength; + uint16_t msg_attrlength; /* Retransmit queue */ struct iked_timer msg_timer; @@ -525,9 +531,9 @@ struct privsep { struct control_sock ps_csock; struct control_socks ps_rcsocks; - u_int ps_instances[PROC_MAX]; - u_int ps_ninstances; - u_int ps_instance; + unsigned int ps_instances[PROC_MAX]; + unsigned int ps_ninstances; + unsigned int ps_instance; /* Event and signal handlers */ struct event ps_evsigint; @@ -551,7 +557,7 @@ struct privsep_proc { struct privsep *p_ps; struct iked *p_env; void (*p_shutdown)(void); - u_int p_instance; + unsigned int p_instance; }; struct iked_ocsp_entry { @@ -567,9 +573,9 @@ TAILQ_HEAD(iked_ocsp_requests, iked_ocsp_entry); struct iked { char sc_conffile[PATH_MAX]; - u_int32_t sc_opts; - u_int8_t sc_passive; - u_int8_t sc_decoupled; + uint32_t sc_opts; + uint8_t sc_passive; + uint8_t sc_decoupled; struct iked_policies sc_policies; struct iked_policy *sc_defaultcon; @@ -583,7 +589,7 @@ struct iked { int sc_pfkey; /* ike process */ struct event sc_pfkeyev; - u_int8_t sc_certreqtype; + uint8_t sc_certreqtype; struct ibuf *sc_certreq; struct iked_socket *sc_sock4[2]; @@ -599,6 +605,7 @@ struct iked { char *sc_ocsp_url; struct iked_addrpool sc_addrpool; + struct iked_addrpool6 sc_addrpool6; }; struct iked_socket { @@ -612,6 +619,7 @@ struct iked_socket { void parent_reload(struct iked *, int, const char *); /* control.c */ +pid_t control(struct privsep *, struct privsep_proc *); int control_init(struct privsep *, struct control_sock *); int control_listen(struct control_sock *); void control_cleanup(struct control_sock *); @@ -625,25 +633,26 @@ struct iked_sa * config_new_sa(struct iked *, int); struct iked_user * config_new_user(struct iked *, struct iked_user *); -u_int64_t +uint64_t config_getspi(void); struct iked_transform * - config_findtransform(struct iked_proposals *, u_int8_t, u_int); + config_findtransform(struct iked_proposals *, uint8_t, unsigned int); void config_free_policy(struct iked *, struct iked_policy *); struct iked_proposal * - config_add_proposal(struct iked_proposals *, u_int, u_int); -void config_free_proposals(struct iked_proposals *, u_int); + config_add_proposal(struct iked_proposals *, unsigned int, + unsigned int); +void config_free_proposals(struct iked_proposals *, unsigned int); void config_free_flows(struct iked *, struct iked_flows *); void config_free_childsas(struct iked *, struct iked_childsas *, struct iked_spi *, struct iked_spi *); struct iked_transform * config_add_transform(struct iked_proposal *, - u_int, u_int, u_int, u_int); -int config_setcoupled(struct iked *, u_int); -int config_getcoupled(struct iked *, u_int); -int config_setmode(struct iked *, u_int); -int config_getmode(struct iked *, u_int); -int config_setreset(struct iked *, u_int, enum privsep_procid); + unsigned int, unsigned int, unsigned int, unsigned int); +int config_setcoupled(struct iked *, unsigned int); +int config_getcoupled(struct iked *, unsigned int); +int config_setmode(struct iked *, unsigned int); +int config_getmode(struct iked *, unsigned int); +int config_setreset(struct iked *, unsigned int, enum privsep_procid); int config_getreset(struct iked *, struct imsg *); int config_setpolicy(struct iked *, struct iked_policy *, enum privsep_procid); @@ -670,10 +679,10 @@ void policy_calc_skip_steps(struct iked_policies *); void policy_ref(struct iked *, struct iked_policy *); void policy_unref(struct iked *, struct iked_policy *); void sa_state(struct iked *, struct iked_sa *, int); -void sa_stateflags(struct iked_sa *, u_int); +void sa_stateflags(struct iked_sa *, unsigned int); int sa_stateok(struct iked_sa *, int); struct iked_sa * - sa_new(struct iked *, u_int64_t, u_int64_t, u_int, + sa_new(struct iked *, uint64_t, uint64_t, unsigned int, struct iked_policy *); void sa_free(struct iked *, struct iked_sa *); void sa_free_flows(struct iked *, struct iked_saflows *); @@ -681,21 +690,22 @@ int sa_address(struct iked_sa *, struct iked_addr *, struct sockaddr_storage *); void childsa_free(struct iked_childsa *); struct iked_childsa * - childsa_lookup(struct iked_sa *, u_int64_t, u_int8_t); + childsa_lookup(struct iked_sa *, uint64_t, uint8_t); void flow_free(struct iked_flow *); struct iked_sa * - sa_lookup(struct iked *, u_int64_t, u_int64_t, u_int); + sa_lookup(struct iked *, uint64_t, uint64_t, unsigned int); struct iked_user * user_lookup(struct iked *, const char *); RB_PROTOTYPE(iked_sas, iked_sa, sa_entry, sa_cmp); RB_PROTOTYPE(iked_addrpool, iked_sa, sa_addrpool_entry, sa_addrpool_cmp); +RB_PROTOTYPE(iked_addrpool6, iked_sa, sa_addrpool6_entry, sa_addrpool6_cmp); RB_PROTOTYPE(iked_users, iked_user, user_entry, user_cmp); RB_PROTOTYPE(iked_activesas, iked_childsa, csa_node, childsa_cmp); RB_PROTOTYPE(iked_flows, iked_flow, flow_node, flow_cmp); /* crypto.c */ struct iked_hash * - hash_new(u_int8_t, u_int16_t); + hash_new(uint8_t, uint16_t); struct ibuf * hash_setkey(struct iked_hash *, void *, size_t); void hash_free(struct iked_hash *); @@ -706,7 +716,7 @@ size_t hash_keylength(struct iked_hash *); size_t hash_length(struct iked_hash *); struct iked_cipher * - cipher_new(u_int8_t, u_int16_t, u_int16_t); + cipher_new(uint8_t, uint16_t, uint16_t); struct ibuf * cipher_setkey(struct iked_cipher *, void *, size_t); struct ibuf * @@ -723,13 +733,13 @@ size_t cipher_ivlength(struct iked_cipher *); size_t cipher_outlength(struct iked_cipher *, size_t); struct iked_dsa * - dsa_new(u_int16_t, struct iked_hash *, int); + dsa_new(uint16_t, struct iked_hash *, int); struct iked_dsa * - dsa_sign_new(u_int16_t, struct iked_hash *); + dsa_sign_new(uint16_t, struct iked_hash *); struct iked_dsa * - dsa_verify_new(u_int16_t, struct iked_hash *); + dsa_verify_new(uint16_t, struct iked_hash *); struct ibuf * - dsa_setkey(struct iked_dsa *, void *, size_t, u_int8_t); + dsa_setkey(struct iked_dsa *, void *, size_t, uint8_t); void dsa_free(struct iked_dsa *); int dsa_init(struct iked_dsa *, const void *, size_t); size_t dsa_length(struct iked_dsa *); @@ -737,9 +747,6 @@ int dsa_update(struct iked_dsa *, const void *, size_t); ssize_t dsa_sign_final(struct iked_dsa *, void *, size_t); ssize_t dsa_verify_final(struct iked_dsa *, void *, size_t); -/* ikev1.c */ -pid_t ikev1(struct privsep *, struct privsep_proc *); - /* ikev2.c */ pid_t ikev2(struct privsep *, struct privsep_proc *); void ikev2_recv(struct iked *, struct iked_message *); @@ -749,25 +756,25 @@ int ikev2_sa_negotiate(struct iked_proposals *, struct iked_proposals *, int ikev2_policy2id(struct iked_static_id *, struct iked_id *, int); int ikev2_childsa_enable(struct iked *, struct iked_sa *); int ikev2_childsa_delete(struct iked *, struct iked_sa *, - u_int8_t, u_int64_t, u_int64_t *, int); + uint8_t, uint64_t, uint64_t *, int); struct ibuf * ikev2_prfplus(struct iked_hash *, struct ibuf *, struct ibuf *, size_t); -ssize_t ikev2_psk(struct iked_sa *, u_int8_t *, size_t, u_int8_t **); +ssize_t ikev2_psk(struct iked_sa *, uint8_t *, size_t, uint8_t **); ssize_t ikev2_nat_detection(struct iked *, struct iked_message *, - void *, size_t, u_int); + void *, size_t, unsigned int); int ikev2_send_informational(struct iked *, struct iked_message *); int ikev2_send_ike_e(struct iked *, struct iked_sa *, struct ibuf *, - u_int8_t, u_int8_t, int); + uint8_t, uint8_t, int); struct ike_header * ikev2_add_header(struct ibuf *, struct iked_sa *, - u_int32_t, u_int8_t, u_int8_t, u_int8_t); + uint32_t, uint8_t, uint8_t, uint8_t); int ikev2_set_header(struct ike_header *, size_t); struct ikev2_payload * ikev2_add_payload(struct ibuf *); int ikev2_next_payload(struct ikev2_payload *, size_t, - u_int8_t); + uint8_t); int ikev2_acquire_sa(struct iked *, struct iked_flow *); void ikev2_disable_rekeying(struct iked *, struct iked_sa *); int ikev2_rekey_sa(struct iked *, struct iked_spi *); @@ -783,19 +790,19 @@ struct ibuf * struct iked_message * ikev2_msg_copy(struct iked *, struct iked_message *); void ikev2_msg_cleanup(struct iked *, struct iked_message *); -u_int32_t +uint32_t ikev2_msg_id(struct iked *, struct iked_sa *); struct ibuf *ikev2_msg_auth(struct iked *, struct iked_sa *, int); int ikev2_msg_authsign(struct iked *, struct iked_sa *, struct iked_auth *, struct ibuf *); int ikev2_msg_authverify(struct iked *, struct iked_sa *, - struct iked_auth *, u_int8_t *, size_t, struct ibuf *); + struct iked_auth *, uint8_t *, size_t, struct ibuf *); int ikev2_msg_valid_ike_sa(struct iked *, struct ike_header *, struct iked_message *); int ikev2_msg_send(struct iked *, struct iked_message *); int ikev2_msg_send_encrypt(struct iked *, struct iked_sa *, - struct ibuf **, u_int8_t, u_int8_t, int); + struct ibuf **, uint8_t, uint8_t, int); struct ibuf *ikev2_msg_encrypt(struct iked *, struct iked_sa *, struct ibuf *); struct ibuf * @@ -828,26 +835,26 @@ int eap_parse(struct iked *, struct iked_sa *, void *, int); int pfkey_couple(int, struct iked_sas *, int); int pfkey_flow_add(int fd, struct iked_flow *); int pfkey_flow_delete(int fd, struct iked_flow *); -int pfkey_block(int, int, u_int); -int pfkey_sa_init(int, struct iked_childsa *, u_int32_t *); +int pfkey_block(int, int, unsigned int); +int pfkey_sa_init(int, struct iked_childsa *, uint32_t *); int pfkey_sa_add(int, struct iked_childsa *, struct iked_childsa *); int pfkey_sa_delete(int, struct iked_childsa *); -int pfkey_sa_last_used(int, struct iked_childsa *, u_int64_t *); +int pfkey_sa_last_used(int, struct iked_childsa *, uint64_t *); int pfkey_flush(int); int pfkey_socket(void); void pfkey_init(struct iked *, int fd); /* ca.c */ pid_t caproc(struct privsep *, struct privsep_proc *); -int ca_setreq(struct iked *, struct iked_sahdr *, struct iked_static_id *, - u_int8_t, u_int8_t *, size_t, enum privsep_procid); +int ca_setreq(struct iked *, struct iked_sa *, struct iked_static_id *, + uint8_t, uint8_t *, size_t, enum privsep_procid); int ca_setcert(struct iked *, struct iked_sahdr *, struct iked_id *, - u_int8_t, u_int8_t *, size_t, enum privsep_procid); + uint8_t, uint8_t *, size_t, enum privsep_procid); int ca_setauth(struct iked *, struct iked_sa *, struct ibuf *, enum privsep_procid); void ca_sslinit(void); void ca_sslerror(const char *); -char *ca_asn1_name(u_int8_t *, size_t); +char *ca_asn1_name(uint8_t *, size_t); char *ca_x509_name(void *); void *ca_x509_name_parse(char *); @@ -858,22 +865,26 @@ void timer_add(struct iked *, struct iked_timer *, int); void timer_del(struct iked *, struct iked_timer *); /* proc.c */ -void proc_init(struct privsep *, struct privsep_proc *, u_int); +void proc_init(struct privsep *, struct privsep_proc *, unsigned int); void proc_kill(struct privsep *); void proc_listen(struct privsep *, struct privsep_proc *, size_t); void proc_dispatch(int, short event, void *); pid_t proc_run(struct privsep *, struct privsep_proc *, - struct privsep_proc *, u_int, + struct privsep_proc *, unsigned int, void (*)(struct privsep *, struct privsep_proc *, void *), void *); void imsg_event_add(struct imsgev *); -int imsg_compose_event(struct imsgev *, u_int16_t, u_int32_t, - pid_t, int, void *, u_int16_t); -int imsg_composev_event(struct imsgev *, u_int16_t, u_int32_t, +int imsg_compose_event(struct imsgev *, uint16_t, uint32_t, + pid_t, int, void *, uint16_t); +int imsg_composev_event(struct imsgev *, uint16_t, uint32_t, pid_t, int, const struct iovec *, int); int proc_compose_imsg(struct privsep *, enum privsep_procid, int, - u_int16_t, int, void *, u_int16_t); + u_int16_t, u_int32_t, int, void *, u_int16_t); +int proc_compose(struct privsep *, enum privsep_procid, + uint16_t, void *, uint16_t); int proc_composev_imsg(struct privsep *, enum privsep_procid, int, - u_int16_t, int, const struct iovec *, int); + u_int16_t, u_int32_t, int, const struct iovec *, int); +int proc_composev(struct privsep *, enum privsep_procid, + uint16_t, const struct iovec *, int); int proc_forward_imsg(struct privsep *, struct imsg *, enum privsep_procid, int); struct imsgbuf * @@ -882,7 +893,6 @@ struct imsgev * proc_iev(struct privsep *, enum privsep_procid, int); /* util.c */ -void socket_set_blockmode(int, enum blockmodes); int socket_af(struct sockaddr *, in_port_t); in_port_t socket_getport(struct sockaddr *); @@ -893,28 +903,32 @@ int udp_bind(struct sockaddr *, in_port_t); ssize_t recvfromto(int, void *, size_t, int, struct sockaddr *, socklen_t *, struct sockaddr *, socklen_t *); const char * - print_spi(u_int64_t, int); + print_spi(uint64_t, int); const char * - print_map(u_int, struct iked_constmap *); + print_map(unsigned int, struct iked_constmap *); void lc_string(char *); -void print_hex(u_int8_t *, off_t, size_t); -void print_hexval(u_int8_t *, off_t, size_t); +void print_hex(uint8_t *, off_t, size_t); +void print_hexval(uint8_t *, off_t, size_t); const char * - print_bits(u_short, u_char *); + print_bits(unsigned short, unsigned char *); int sockaddr_cmp(struct sockaddr *, struct sockaddr *, int); -u_int8_t mask2prefixlen(struct sockaddr *); -u_int8_t mask2prefixlen6(struct sockaddr *); +uint8_t mask2prefixlen(struct sockaddr *); +uint8_t mask2prefixlen6(struct sockaddr *); struct in6_addr * - prefixlen2mask6(u_int8_t, u_int32_t *); -u_int32_t - prefixlen2mask(u_int8_t); + prefixlen2mask6(uint8_t, uint32_t *); +uint32_t + prefixlen2mask(uint8_t); const char * print_host(struct sockaddr *, char *, size_t); -char *get_string(u_int8_t *, size_t); +char *get_string(uint8_t *, size_t); const char * - print_proto(u_int8_t); + print_proto(uint8_t); int expand_string(char *, size_t, const char *, const char *); -u_int8_t *string2unicode(const char *, size_t *); +uint8_t *string2unicode(const char *, size_t *); +void print_debug(const char *, ...) + __attribute__((format(printf, 1, 2))); +void print_verbose(const char *, ...) + __attribute__((format(printf, 1, 2))); /* imsg_util.c */ struct ibuf * @@ -925,7 +939,7 @@ int ibuf_cat(struct ibuf *, struct ibuf *); void ibuf_release(struct ibuf *); size_t ibuf_length(struct ibuf *); int ibuf_setsize(struct ibuf *, size_t); -u_int8_t * +uint8_t * ibuf_data(struct ibuf *); void *ibuf_getdata(struct ibuf *, size_t); struct ibuf * @@ -939,29 +953,38 @@ void *ibuf_advance(struct ibuf *, size_t); void ibuf_zero(struct ibuf *); /* log.c */ -void log_init(int); -void log_verbose(int); -void log_warn(const char *, ...) __attribute__((format(printf, 1, 2))); -void log_warnx(const char *, ...) __attribute__((format(printf, 1, 2))); -void log_info(const char *, ...) __attribute__((format(printf, 1, 2))); -void log_debug(const char *, ...) __attribute__((format(printf, 1, 2))); -void print_debug(const char *, ...) __attribute__((format(printf, 1, 2))); -void print_verbose(const char *, ...) __attribute__((format(printf, 1, 2))); -__dead void fatal(const char *); -__dead void fatalx(const char *); +void log_init(int, int); +void log_procinit(const char *); +void log_verbose(int); +void log_warn(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_warnx(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_info(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_debug(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void logit(int, const char *, ...) + __attribute__((__format__ (printf, 2, 3))); +void vlog(int, const char *, va_list) + __attribute__((__format__ (printf, 2, 0))); +__dead void fatal(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +__dead void fatalx(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); /* ocsp.c */ int ocsp_connect(struct iked *env); int ocsp_receive_fd(struct iked *, struct imsg *); int ocsp_validate_cert(struct iked *, struct iked_static_id *, - void *, size_t, struct iked_sahdr, u_int8_t); + void *, size_t, struct iked_sahdr, uint8_t); /* parse.y */ int parse_config(const char *, struct iked *); void print_user(struct iked_user *); void print_policy(struct iked_policy *); -size_t keylength_xf(u_int, u_int, u_int); -size_t noncelength_xf(u_int, u_int); +size_t keylength_xf(unsigned int, unsigned int, unsigned int); +size_t noncelength_xf(unsigned int, unsigned int); int cmdline_symset(char *); #endif /* IKED_H */ diff --git a/iked/ikev1.c b/iked/ikev1.c deleted file mode 100644 index 6073443..0000000 --- a/iked/ikev1.c +++ /dev/null @@ -1,195 +0,0 @@ -/* $OpenBSD: ikev1.c,v 1.17 2015/02/06 10:39:01 deraadt Exp $ */ - -/* - * Copyright (c) 2010-2013 Reyk Floeter - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* - * XXX Either implement IKEv1, - * XXX or find a way to pass IKEv1 messages to isakmpd, - * XXX or remove this file and ikev1 from the iked tree. - */ - - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "iked.h" -#include "ikev2.h" - -int ikev1_dispatch_parent(int, struct privsep_proc *, struct imsg *); -int ikev1_dispatch_ikev2(int, struct privsep_proc *, struct imsg *); -int ikev1_dispatch_cert(int, struct privsep_proc *, struct imsg *); - -void ikev1_msg_cb(int, short, void *); -void ikev1_recv(struct iked *, struct iked_message *); - -static struct privsep_proc procs[] = { - { "parent", PROC_PARENT, ikev1_dispatch_parent }, - { "ikev2", PROC_IKEV2, ikev1_dispatch_ikev2 }, - { "certstore", PROC_CERT, ikev1_dispatch_cert } -}; - -pid_t -ikev1(struct privsep *ps, struct privsep_proc *p) -{ - return (proc_run(ps, p, procs, nitems(procs), NULL, NULL)); -} - -int -ikev1_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) -{ - struct iked *env = p->p_env; - - switch (imsg->hdr.type) { - case IMSG_CTL_RESET: - log_debug("%s: config reload", __func__); - return (0); - case IMSG_CTL_COUPLE: - case IMSG_CTL_DECOUPLE: - return (0); - case IMSG_CTL_ACTIVE: - case IMSG_CTL_PASSIVE: - return (0); - case IMSG_UDP_SOCKET: - return (config_getsocket(env, imsg, ikev1_msg_cb)); - case IMSG_COMPILE: - return (0); - default: - break; - } - - return (-1); -} - -int -ikev1_dispatch_ikev2(int fd, struct privsep_proc *p, struct imsg *imsg) -{ - struct iked *env = p->p_env; - struct iked_message msg; - u_int8_t *buf; - ssize_t len; - - switch (imsg->hdr.type) { - case IMSG_IKE_MESSAGE: - log_debug("%s: message", __func__); - IMSG_SIZE_CHECK(imsg, &msg); - memcpy(&msg, imsg->data, sizeof(msg)); - - len = IMSG_DATA_SIZE(imsg) - sizeof(msg); - buf = (u_int8_t *)imsg->data + sizeof(msg); - if (len <= 0 || (msg.msg_data = ibuf_new(buf, len)) == NULL) { - log_debug("%s: short message", __func__); - return (0); - } - - log_debug("%s: message length %zd", __func__, len); - - ikev1_recv(env, &msg); - ikev2_msg_cleanup(env, &msg); - return (0); - default: - break; - } - - return (-1); -} - -int -ikev1_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) -{ - return (-1); -} - -void -ikev1_msg_cb(int fd, short event, void *arg) -{ - struct iked_socket *sock = arg; - struct iked *env = sock->sock_env; - struct iked_message msg; - struct ike_header hdr; - u_int8_t buf[IKED_MSGBUF_MAX]; - size_t len; - struct iovec iov[2]; - - msg.msg_peerlen = sizeof(msg.msg_peer); - msg.msg_locallen = sizeof(msg.msg_local); - - if ((len = recvfromto(fd, buf, sizeof(buf), 0, - (struct sockaddr*)&msg.msg_peer, &msg.msg_peerlen, - (struct sockaddr*)&msg.msg_local, &msg.msg_locallen)) < 1) - return; - - if ((size_t)len <= sizeof(hdr)) - return; - memcpy(&hdr, buf, sizeof(hdr)); - - if ((msg.msg_data = ibuf_new(buf, len)) == NULL) - return; - - if (hdr.ike_version == IKEV2_VERSION) { - iov[0].iov_base = &msg; - iov[0].iov_len = sizeof(msg); - iov[1].iov_base = buf; - iov[1].iov_len = len; - - proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, - IMSG_IKE_MESSAGE, -1, iov, 2); - goto done; - } - - ikev1_recv(env, &msg); - - done: - ikev2_msg_cleanup(env, &msg); -} - -void -ikev1_recv(struct iked *env, struct iked_message *msg) -{ - struct ike_header *hdr; - - if (ibuf_size(msg->msg_data) <= sizeof(*hdr)) { - log_debug("%s: short message", __func__); - return; - } - - hdr = (struct ike_header *)ibuf_data(msg->msg_data); - - log_debug("%s: header ispi %s rspi %s" - " nextpayload %u version 0x%02x exchange %u flags 0x%02x" - " msgid %u length %u", __func__, - print_spi(betoh64(hdr->ike_ispi), 8), - print_spi(betoh64(hdr->ike_rspi), 8), - hdr->ike_nextpayload, - hdr->ike_version, - hdr->ike_exchange, - hdr->ike_flags, - betoh32(hdr->ike_msgid), - betoh32(hdr->ike_length)); - - log_debug("%s: IKEv1 not supported", __func__); -} diff --git a/iked/ikev2.c b/iked/ikev2.c index 9b1da64..4f0d436 100644 --- a/iked/ikev2.c +++ b/iked/ikev2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.c,v 1.121 2015/07/07 19:13:31 markus Exp $ */ +/* $OpenBSD: ikev2.c,v 1.131 2016/06/02 07:14:26 patrick Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -50,16 +50,16 @@ #include "eap.h" #include "dh.h" +void ikev2_run(struct privsep *, struct privsep_proc *, void *); int ikev2_dispatch_parent(int, struct privsep_proc *, struct imsg *); -int ikev2_dispatch_ikev1(int, struct privsep_proc *, struct imsg *); int ikev2_dispatch_cert(int, struct privsep_proc *, struct imsg *); struct iked_sa * ikev2_getimsgdata(struct iked *, struct imsg *, struct iked_sahdr *, - u_int8_t *, u_int8_t **, size_t *); + uint8_t *, uint8_t **, size_t *); void ikev2_recv(struct iked *, struct iked_message *); -int ikev2_ike_auth_compatible(struct iked_sa *, u_int8_t, u_int8_t); +int ikev2_ike_auth_compatible(struct iked_sa *, uint8_t, uint8_t); int ikev2_ike_auth_recv(struct iked *, struct iked_sa *, struct iked_message *); int ikev2_ike_auth(struct iked *, struct iked_sa *); @@ -79,7 +79,7 @@ int ikev2_resp_ike_auth(struct iked *, struct iked_sa *); int ikev2_resp_ike_eap(struct iked *, struct iked_sa *, struct ibuf *); int ikev2_send_create_child_sa(struct iked *, struct iked_sa *, - struct iked_spi *, u_int8_t); + struct iked_spi *, uint8_t); int ikev2_ikesa_enable(struct iked *, struct iked_sa *, struct iked_sa *); void ikev2_ikesa_delete(struct iked *, struct iked_sa *, int); int ikev2_init_create_child_sa(struct iked *, struct iked_message *); @@ -92,13 +92,15 @@ int ikev2_sa_initiator(struct iked *, struct iked_sa *, struct iked_sa *, struct iked_message *); int ikev2_sa_responder(struct iked *, struct iked_sa *, struct iked_sa *, struct iked_message *); -int ikev2_sa_initiator_dh(struct iked_sa *, struct iked_message *, u_int); +int ikev2_sa_initiator_dh(struct iked_sa *, struct iked_message *, + unsigned int); int ikev2_sa_responder_dh(struct iked_kex *, struct iked_proposals *, - struct iked_message *, u_int); + struct iked_message *, unsigned int); void ikev2_sa_cleanup_dh(struct iked_sa *); int ikev2_sa_keys(struct iked *, struct iked_sa *, struct ibuf *); int ikev2_sa_tag(struct iked_sa *, struct iked_id *); -int ikev2_set_sa_proposal(struct iked_sa *, struct iked_policy *, u_int); +int ikev2_set_sa_proposal(struct iked_sa *, struct iked_policy *, + unsigned int); int ikev2_childsa_negotiate(struct iked *, struct iked_sa *, struct iked_kex *, struct iked_proposals *, int, int); @@ -108,26 +110,26 @@ int ikev2_valid_proposal(struct iked_proposal *, struct iked_transform **, struct iked_transform **, int *); ssize_t ikev2_add_proposals(struct iked *, struct iked_sa *, struct ibuf *, - struct iked_proposals *, u_int8_t, int, int); + struct iked_proposals *, uint8_t, int, int); ssize_t ikev2_add_cp(struct iked *, struct iked_sa *, struct ibuf *); ssize_t ikev2_add_transform(struct ibuf *, - u_int8_t, u_int8_t, u_int16_t, u_int16_t); + uint8_t, uint8_t, uint16_t, uint16_t); ssize_t ikev2_add_ts(struct ibuf *, struct ikev2_payload **, ssize_t, struct iked_sa *, int); ssize_t ikev2_add_certreq(struct ibuf *, struct ikev2_payload **, ssize_t, - struct ibuf *, u_int8_t); + struct ibuf *, uint8_t); ssize_t ikev2_add_transportnotify(struct iked *, struct ibuf *, struct ikev2_payload **, ssize_t, struct iked_sa *); ssize_t ikev2_add_ipcompnotify(struct iked *, struct ibuf *, struct ikev2_payload **, ssize_t, struct iked_sa *); -ssize_t ikev2_add_ts_payload(struct ibuf *, u_int, struct iked_sa *); +ssize_t ikev2_add_ts_payload(struct ibuf *, unsigned int, struct iked_sa *); int ikev2_add_data(struct ibuf *, void *, size_t); int ikev2_add_buf(struct ibuf *buf, struct ibuf *); int ikev2_ipcomp_enable(struct iked *, struct iked_sa *); void ikev2_ipcomp_csa_free(struct iked *, struct iked_childsa *); -int ikev2_cp_setaddr(struct iked *, struct iked_sa *); +int ikev2_cp_setaddr(struct iked *, struct iked_sa *, sa_family_t); int ikev2_cp_fixaddr(struct iked_sa *, struct iked_addr *, struct iked_addr *); @@ -136,14 +138,27 @@ ssize_t ikev2_add_sighashnotify(struct ibuf *, struct ikev2_payload **, static struct privsep_proc procs[] = { { "parent", PROC_PARENT, ikev2_dispatch_parent }, - { "ikev1", PROC_IKEV1, ikev2_dispatch_ikev1 }, { "certstore", PROC_CERT, ikev2_dispatch_cert } }; pid_t ikev2(struct privsep *ps, struct privsep_proc *p) { - return (proc_run(ps, p, procs, nitems(procs), NULL, NULL)); + return (proc_run(ps, p, procs, nitems(procs), ikev2_run, NULL)); +} + +void +ikev2_run(struct privsep *ps, struct privsep_proc *p, void *arg) +{ + /* + * pledge in the ikev2 process: + * stdio - for malloc and basic I/O including events. + * inet - for sendto with specified peer address. + * recvfd - for PFKEYv2 and the listening UDP sockets. + * In theory, recvfd could be dropped after getting the fds once. + */ + if (pledge("stdio inet recvfd", NULL) == -1) + fatal("pledge"); } int @@ -182,47 +197,14 @@ ikev2_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) return (-1); } -int -ikev2_dispatch_ikev1(int fd, struct privsep_proc *p, struct imsg *imsg) -{ - struct iked *env = p->p_env; - struct iked_message msg; - u_int8_t *buf; - ssize_t len; - - switch (imsg->hdr.type) { - case IMSG_IKE_MESSAGE: - log_debug("%s: message", __func__); - IMSG_SIZE_CHECK(imsg, &msg); - memcpy(&msg, imsg->data, sizeof(msg)); - - len = IMSG_DATA_SIZE(imsg) - sizeof(msg); - buf = (u_int8_t *)imsg->data + sizeof(msg); - if (len <= 0 || (msg.msg_data = ibuf_new(buf, len)) == NULL) { - log_debug("%s: short message", __func__); - return (0); - } - - log_debug("%s: message length %zd", __func__, len); - - ikev2_recv(env, &msg); - ikev2_msg_cleanup(env, &msg); - return (0); - default: - break; - } - - return (-1); -} - int ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) { struct iked *env = p->p_env; struct iked_sahdr sh; struct iked_sa *sa; - u_int8_t type; - u_int8_t *ptr; + uint8_t type; + uint8_t *ptr; size_t len; struct iked_id *id = NULL; int ignore = 0; @@ -248,7 +230,7 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) case IMSG_CERTVALID: case IMSG_CERTINVALID: memcpy(&sh, imsg->data, sizeof(sh)); - memcpy(&type, (u_int8_t *)imsg->data + sizeof(sh), + memcpy(&type, (uint8_t *)imsg->data + sizeof(sh), sizeof(type)); /* Ignore invalid or unauthenticated SAs */ @@ -352,9 +334,9 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) struct iked_sa * ikev2_getimsgdata(struct iked *env, struct imsg *imsg, struct iked_sahdr *sh, - u_int8_t *type, u_int8_t **buf, size_t *size) + uint8_t *type, uint8_t **buf, size_t *size) { - u_int8_t *ptr; + uint8_t *ptr; size_t len; struct iked_sa *sa; @@ -390,7 +372,7 @@ ikev2_recv(struct iked *env, struct iked_message *msg) struct ike_header *hdr; struct iked_message *m; struct iked_sa *sa; - u_int initiator, flag = 0; + unsigned int initiator, flag = 0; hdr = ibuf_seek(msg->msg_data, msg->msg_offset, sizeof(*hdr)); @@ -503,7 +485,7 @@ ikev2_recv(struct iked *env, struct iked_message *msg) } int -ikev2_ike_auth_compatible(struct iked_sa *sa, u_int8_t want, u_int8_t have) +ikev2_ike_auth_compatible(struct iked_sa *sa, uint8_t want, uint8_t have) { if (want == have) return (0); @@ -540,7 +522,8 @@ ikev2_ike_auth_recv(struct iked *env, struct iked_sa *sa, /* move sa to new policy */ policy = sa->sa_policy = msg->msg_policy; TAILQ_REMOVE(&old->pol_sapeers, sa, sa_peer_entry); - TAILQ_INSERT_TAIL(&policy->pol_sapeers, sa, sa_peer_entry); + TAILQ_INSERT_TAIL(&policy->pol_sapeers, + sa, sa_peer_entry); } else { /* restore */ msg->msg_policy = sa->sa_policy = old; @@ -656,6 +639,9 @@ ikev2_ike_auth_recv(struct iked *env, struct iked_sa *sa, int ikev2_ike_auth(struct iked *env, struct iked_sa *sa) { + struct iked_policy *pol = sa->sa_policy; + uint8_t certreqtype; + /* Attempt state transition */ if (sa->sa_state == IKEV2_STATE_EAP_SUCCESS) sa_state(env, sa, IKEV2_STATE_EAP_VALID); @@ -668,6 +654,28 @@ ikev2_ike_auth(struct iked *env, struct iked_sa *sa) else return (ikev2_init_ike_auth(env, sa)); } + + /* + * If we have to send a local certificate but did not receive an + * optional CERTREQ, use our own certreq to find a local certificate. + * We could alternatively extract the CA from the peer certificate + * to find a matching local one. + */ + if (sa->sa_statevalid & IKED_REQ_CERT) { + if ((sa->sa_stateflags & IKED_REQ_CERTREQ) == 0) { + log_debug("%s: no CERTREQ, using default", __func__); + if (pol->pol_certreqtype) + certreqtype = pol->pol_certreqtype; + else + certreqtype = env->sc_certreqtype; + return (ca_setreq(env, sa, + &pol->pol_localid, certreqtype, + ibuf_data(env->sc_certreq), + ibuf_size(env->sc_certreq), PROC_CERT)); + } else if ((sa->sa_stateflags & IKED_REQ_CERT) == 0) + return (0); /* ignored, wait for cert */ + } + return (ikev2_resp_ike_auth(env, sa)); } @@ -801,7 +809,7 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, struct iked_sa *sa; struct ibuf *buf; struct group *group; - u_int8_t *ptr; + uint8_t *ptr; ssize_t len; int ret = -1; struct iked_socket *sock; @@ -988,7 +996,7 @@ ikev2_init_ike_auth(struct iked *env, struct iked_sa *sa) struct ikev2_auth *auth; struct iked_id *id, *certid; struct ibuf *e = NULL; - u_int8_t firstpayload; + uint8_t firstpayload; int ret = -1; ssize_t len; @@ -1135,7 +1143,7 @@ ikev2_policy2id(struct iked_static_id *polid, struct iked_id *id, int srcid) struct in_addr in4; struct in6_addr in6; X509_NAME *name = NULL; - u_int8_t *p; + uint8_t *p; int len; /* Fixup the local Id if not specified */ @@ -1181,8 +1189,8 @@ ikev2_policy2id(struct iked_static_id *polid, struct iked_id *id, int srcid) break; case IKEV2_ID_ASN1_DN: /* policy has ID in string-format, convert to ASN1 */ - name = ca_x509_name_parse((char *)polid->id_data); - if (name == NULL || (len = i2d_X509_NAME(name, NULL)) < 0 || + if ((name = ca_x509_name_parse(polid->id_data)) == NULL || + (len = i2d_X509_NAME(name, NULL)) < 0 || (p = ibuf_reserve(id->id_buf, len)) == NULL || (i2d_X509_NAME(name, &p)) < 0) { if (name) @@ -1213,8 +1221,8 @@ ikev2_policy2id(struct iked_static_id *polid, struct iked_id *id, int srcid) struct ike_header * ikev2_add_header(struct ibuf *buf, struct iked_sa *sa, - u_int32_t msgid, u_int8_t nextpayload, - u_int8_t exchange, u_int8_t flags) + uint32_t msgid, uint8_t nextpayload, + uint8_t exchange, uint8_t flags) { struct ike_header *hdr; @@ -1241,7 +1249,7 @@ ikev2_add_header(struct ibuf *buf, struct iked_sa *sa, int ikev2_set_header(struct ike_header *hdr, size_t length) { - u_int32_t hdrlength = sizeof(*hdr) + length; + uint32_t hdrlength = sizeof(*hdr) + length; if (hdrlength > UINT32_MAX) { log_debug("%s: message too long", __func__); @@ -1270,7 +1278,7 @@ ikev2_add_payload(struct ibuf *buf) } ssize_t -ikev2_add_ts_payload(struct ibuf *buf, u_int type, struct iked_sa *sa) +ikev2_add_ts_payload(struct ibuf *buf, unsigned int type, struct iked_sa *sa) { struct iked_policy *pol = sa->sa_policy; struct ikev2_tsp *tsp; @@ -1278,9 +1286,9 @@ ikev2_add_ts_payload(struct ibuf *buf, u_int type, struct iked_sa *sa) struct iked_flow *flow; struct iked_addr *addr; struct iked_addr pooladdr; - u_int8_t *ptr; + uint8_t *ptr; size_t len = 0; - u_int32_t av[4], bv[4], mv[4]; + uint32_t av[4], bv[4], mv[4]; struct sockaddr_in *in4; struct sockaddr_in6 *in6; @@ -1408,7 +1416,7 @@ ikev2_add_ts(struct ibuf *e, struct ikev2_payload **pld, ssize_t len, ssize_t ikev2_add_certreq(struct ibuf *e, struct ikev2_payload **pld, ssize_t len, - struct ibuf *certreq, u_int8_t type) + struct ibuf *certreq, uint8_t type) { struct ikev2_cert *cert; @@ -1491,7 +1499,7 @@ ikev2_add_ipcompnotify(struct iked *env, struct ibuf *e, */ if (spi == 0) return (len); - cpi = htobe16((u_int16_t)spi); + cpi = htobe16((uint16_t)spi); if (*pld) if (ikev2_next_payload(*pld, len, IKEV2_PAYLOAD_NOTIFY) == -1) return (-1); @@ -1520,9 +1528,9 @@ ikev2_add_sighashnotify(struct ibuf *e, struct ikev2_payload **pld, ssize_t len) { struct ikev2_notify *n; - u_int8_t *ptr; + uint8_t *ptr; size_t i; - u_int16_t hash, signature_hashes[] = { + uint16_t hash, signature_hashes[] = { IKEV2_SIGHASH_SHA2_256, IKEV2_SIGHASH_SHA2_384, IKEV2_SIGHASH_SHA2_512 @@ -1557,7 +1565,7 @@ ikev2_add_sighashnotify(struct ibuf *e, struct ikev2_payload **pld, int ikev2_next_payload(struct ikev2_payload *pld, size_t length, - u_int8_t nextpayload) + uint8_t nextpayload) { size_t pldlength = sizeof(*pld) + length; @@ -1577,21 +1585,21 @@ ikev2_next_payload(struct ikev2_payload *pld, size_t length, ssize_t ikev2_nat_detection(struct iked *env, struct iked_message *msg, - void *ptr, size_t len, u_int type) + void *ptr, size_t len, unsigned int type) { EVP_MD_CTX ctx; struct ike_header *hdr; - u_int8_t md[SHA_DIGEST_LENGTH]; - u_int mdlen = sizeof(md); + uint8_t md[SHA_DIGEST_LENGTH]; + unsigned int mdlen = sizeof(md); struct iked_sa *sa = msg->msg_sa; struct sockaddr_in *in4; struct sockaddr_in6 *in6; ssize_t ret = -1; struct sockaddr *src, *dst, *ss; - u_int64_t rspi, ispi; + uint64_t rspi, ispi; struct ibuf *buf; int frompeer = 0; - u_int32_t rnd; + uint32_t rnd; if (ptr == NULL) return (mdlen); @@ -1685,12 +1693,12 @@ ikev2_add_cp(struct iked *env, struct iked_sa *sa, struct ibuf *buf) struct ikev2_cp *cp; struct ikev2_cfg *cfg; struct iked_cfg *ikecfg; - u_int i; - u_int32_t mask4; + unsigned int i; + uint32_t mask4; size_t len; struct sockaddr_in *in4; struct sockaddr_in6 *in6; - u_int8_t prefixlen; + uint8_t prefixlen; if ((cp = ibuf_advance(buf, sizeof(*cp))) == NULL) return (-1); @@ -1766,9 +1774,9 @@ ikev2_add_cp(struct iked *env, struct iked_sa *sa, struct ibuf *buf) in6 = (ikecfg->cfg.address.addr_mask != 128 && (ikecfg->cfg_type == IKEV2_CFG_INTERNAL_IP6_ADDRESS) && - sa->sa_addrpool && - sa->sa_addrpool->addr_af == AF_INET6) ? - (struct sockaddr_in6 *)&sa->sa_addrpool->addr : + sa->sa_addrpool6 && + sa->sa_addrpool6->addr_af == AF_INET6) ? + (struct sockaddr_in6 *)&sa->sa_addrpool6->addr : (struct sockaddr_in6 *)&ikecfg->cfg.address.addr; cfg->cfg_length = htobe16(17); if (ibuf_add(buf, &in6->sin6_addr.s6_addr, 16) == -1) @@ -1793,7 +1801,7 @@ ikev2_add_cp(struct iked *env, struct iked_sa *sa, struct ibuf *buf) ssize_t ikev2_add_proposals(struct iked *env, struct iked_sa *sa, struct ibuf *buf, - struct iked_proposals *proposals, u_int8_t protoid, int initiator, + struct iked_proposals *proposals, uint8_t protoid, int initiator, int sendikespi) { struct ikev2_sa_proposal *sap; @@ -1801,9 +1809,9 @@ ikev2_add_proposals(struct iked *env, struct iked_sa *sa, struct ibuf *buf, struct iked_proposal *prop; struct iked_childsa csa; ssize_t length = 0, saplength, xflen; - u_int64_t spi64; - u_int32_t spi32, spi; - u_int i; + uint64_t spi64; + uint32_t spi32, spi; + unsigned int i; TAILQ_FOREACH(prop, proposals, prop_entry) { if ((protoid && prop->prop_protoid != protoid) || @@ -1885,7 +1893,7 @@ ikev2_add_proposals(struct iked *env, struct iked_sa *sa, struct ibuf *buf, ssize_t ikev2_add_transform(struct ibuf *buf, - u_int8_t more, u_int8_t type, u_int16_t id, u_int16_t length) + uint8_t more, uint8_t type, uint16_t id, uint16_t length) { struct ikev2_transform *xfrm; struct ikev2_attribute *attr; @@ -2056,7 +2064,7 @@ ikev2_resp_ike_sa_init(struct iked *env, struct iked_message *msg) struct iked_sa *sa = msg->msg_sa; struct ibuf *buf; struct group *group; - u_int8_t *ptr; + uint8_t *ptr; ssize_t len; int ret = -1; @@ -2199,7 +2207,7 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) struct ikev2_auth *auth; struct iked_id *id, *certid; struct ibuf *e = NULL; - u_int8_t firstpayload; + uint8_t firstpayload; int ret = -1; ssize_t len; @@ -2211,7 +2219,8 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) else if (!sa_stateok(sa, IKEV2_STATE_VALID)) return (0); /* ignore */ - if (ikev2_cp_setaddr(env, sa) < 0) + if (ikev2_cp_setaddr(env, sa, AF_INET) < 0 || + ikev2_cp_setaddr(env, sa, AF_INET6) < 0) return (-1); if (ikev2_childsa_negotiate(env, sa, &sa->sa_kex, &sa->sa_proposals, @@ -2372,7 +2381,7 @@ ikev2_resp_ike_eap(struct iked *env, struct iked_sa *sa, struct ibuf *eapmsg) struct ikev2_auth *auth; struct iked_id *id, *certid; struct ibuf *e = NULL; - u_int8_t firstpayload; + uint8_t firstpayload; int ret = -1; ssize_t len = 0; @@ -2451,7 +2460,7 @@ ikev2_resp_ike_eap(struct iked *env, struct iked_sa *sa, struct ibuf *eapmsg) int ikev2_send_ike_e(struct iked *env, struct iked_sa *sa, struct ibuf *buf, - u_int8_t firstpayload, u_int8_t exchange, int response) + uint8_t firstpayload, uint8_t exchange, int response) { struct ikev2_payload *pld; struct ibuf *e = NULL; @@ -2484,11 +2493,11 @@ ikev2_send_ike_e(struct iked *env, struct iked_sa *sa, struct ibuf *buf, int ikev2_set_sa_proposal(struct iked_sa *sa, struct iked_policy *pol, - u_int proto) + unsigned int proto) { struct iked_proposal *prop, *copy; struct iked_transform *xform; - u_int i; + unsigned int i; /* create copy of the policy proposals */ config_free_proposals(&sa->sa_proposals, proto); @@ -2511,7 +2520,7 @@ ikev2_set_sa_proposal(struct iked_sa *sa, struct iked_policy *pol, int ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, - struct iked_spi *rekey, u_int8_t protoid) + struct iked_spi *rekey, uint8_t protoid) { struct iked_policy *pol = sa->sa_policy; struct iked_childsa *csa = NULL, *csb = NULL; @@ -2520,10 +2529,10 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, struct ikev2_keyexchange *ke; struct group *group; struct ibuf *e = NULL, *nonce = NULL; - u_int8_t *ptr; - u_int8_t firstpayload; - u_int32_t spi; - ssize_t len; + uint8_t *ptr; + uint8_t firstpayload; + uint32_t spi; + ssize_t len = 0; int initiator, ret = -1; if (rekey) @@ -2654,7 +2663,7 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa, if ((ptr = ibuf_advance(e, rekey->spi_size)) == NULL) goto done; len = rekey->spi_size; - spi = htobe32((u_int32_t)csa->csa_peerspi); + spi = htobe32((uint32_t)csa->csa_peerspi); memcpy(ptr, &spi, rekey->spi_size); len += sizeof(*n); } @@ -2788,7 +2797,7 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) struct iked_spi *spi; struct ikev2_delete *del; struct ibuf *buf = NULL; - u_int32_t spi32; + uint32_t spi32; int pfs = 0, ret = -1; if (!ikev2_msg_frompeer(msg) || @@ -3002,6 +3011,12 @@ ikev2_ikesa_enable(struct iked *env, struct iked_sa *sa, struct iked_sa *nsa) sa->sa_addrpool = NULL; RB_INSERT(iked_addrpool, &env->sc_addrpool, nsa); } + if (sa->sa_addrpool6) { + RB_REMOVE(iked_addrpool6, &env->sc_addrpool6, sa); + nsa->sa_addrpool6 = sa->sa_addrpool6; + sa->sa_addrpool6 = NULL; + RB_INSERT(iked_addrpool6, &env->sc_addrpool6, nsa); + } log_debug("%s: activating new IKE SA", __func__); sa_state(env, nsa, IKEV2_STATE_ESTABLISHED); @@ -3065,8 +3080,8 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg) struct ikev2_keyexchange *ke; struct ikev2_payload *pld = NULL; struct ibuf *e = NULL, *nonce = NULL; - u_int8_t firstpayload; - ssize_t len; + uint8_t firstpayload; + ssize_t len = 0; int initiator, protoid, rekeying = 1; int ret = -1; int pfs = 0; @@ -3309,7 +3324,7 @@ ikev2_ike_sa_alive(struct iked *env, void *arg) struct iked_sa *sa = arg; struct iked_childsa *csa = NULL; struct timeval tv; - u_int64_t last_used, diff; + uint64_t last_used, diff; int foundin = 0, foundout = 0; /* check for incoming traffic on any child SA */ @@ -3466,10 +3481,10 @@ ikev2_send_informational(struct iked *env, struct iked_message *msg) } ssize_t -ikev2_psk(struct iked_sa *sa, u_int8_t *data, size_t length, - u_int8_t **pskptr) +ikev2_psk(struct iked_sa *sa, uint8_t *data, size_t length, + uint8_t **pskptr) { - u_int8_t *psk; + uint8_t *psk; size_t psklen = -1; if (hash_setkey(sa->sa_prf, data, length) == NULL) @@ -3491,8 +3506,8 @@ ikev2_match_proposals(struct iked_proposal *local, struct iked_proposal *peer, struct iked_transform **xforms) { struct iked_transform *tpeer, *tlocal; - u_int i, j, type, score; - u_int8_t protoid = peer->prop_protoid; + unsigned int i, j, type, score; + uint8_t protoid = peer->prop_protoid; for (i = 0; i < peer->prop_nxforms; i++) { tpeer = peer->prop_xforms + i; @@ -3555,8 +3570,8 @@ ikev2_sa_negotiate(struct iked_proposals *result, struct iked_proposals *local, struct iked_transform chosen[IKEV2_XFORMTYPE_MAX]; struct iked_transform *valid[IKEV2_XFORMTYPE_MAX]; struct iked_transform *match[IKEV2_XFORMTYPE_MAX]; - u_int i, score, chosen_score = 0; - u_int8_t protoid = 0; + unsigned int i, score, chosen_score = 0; + uint8_t protoid = 0; bzero(valid, sizeof(valid)); bzero(&vlocal, sizeof(vlocal)); @@ -3627,7 +3642,8 @@ ikev2_sa_negotiate(struct iked_proposals *result, struct iked_proposals *local, } int -ikev2_sa_initiator_dh(struct iked_sa *sa, struct iked_message *msg, u_int proto) +ikev2_sa_initiator_dh(struct iked_sa *sa, struct iked_message *msg, + unsigned int proto) { struct iked_policy *pol = sa->sa_policy; struct iked_transform *xform; @@ -3776,7 +3792,7 @@ ikev2_sa_initiator(struct iked *env, struct iked_sa *sa, int ikev2_sa_responder_dh(struct iked_kex *kex, struct iked_proposals *proposals, - struct iked_message *msg, u_int proto) + struct iked_message *msg, unsigned int proto) { struct iked_transform *xform; @@ -3912,7 +3928,7 @@ ikev2_sa_keys(struct iked *env, struct iked_sa *sa, struct ibuf *key) struct group *group; struct ibuf *ninr, *dhsecret, *skeyseed, *s, *t; size_t nonceminlen, ilen, rlen, tmplen; - u_int64_t ispi, rspi; + uint64_t ispi, rspi; int ret = -1; ninr = dhsecret = skeyseed = s = t = NULL; @@ -4124,7 +4140,7 @@ ikev2_prfplus(struct iked_hash *prf, struct ibuf *key, struct ibuf *seed, { struct ibuf *t = NULL, *t1 = NULL, *t2 = NULL; size_t rlen, i, hashlen = 0; - u_int8_t pad = 0; + uint8_t pad = 0; /* * prf+ (K, S) = T1 | T2 | T3 | T4 | ... @@ -4198,8 +4214,7 @@ ikev2_sa_tag(struct iked_sa *sa, struct iked_id *id) int ret = -1; size_t len; - if (sa->sa_tag != NULL) - free(sa->sa_tag); + free(sa->sa_tag); sa->sa_tag = NULL; format = sa->sa_policy->pol_tag; @@ -4285,8 +4300,8 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, struct iked_flow *flow, *saflow, *flowa, *flowb; struct ibuf *keymat = NULL, *seed = NULL, *dhsecret = NULL; struct group *group; - u_int32_t spi = 0; - u_int i; + uint32_t spi = 0; + unsigned int i; size_t ilen = 0; int esn, skip, ret = -1; @@ -4333,7 +4348,8 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, } if (pfs) { log_debug("%s: using PFS", __func__); - if (kex->kex_dhpeer == NULL || ibuf_length(kex->kex_dhpeer) == 0 || + if (kex->kex_dhpeer == NULL || + ibuf_length(kex->kex_dhpeer) == 0 || (group = kex->kex_dhgroup) == NULL) { log_debug("%s: no dh group for pfs", __func__); goto done; @@ -4345,8 +4361,9 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, if (dh_create_shared(group, dhsecret->buf, kex->kex_dhpeer->buf) == -1) { log_debug("%s: failed to get dh secret" - " group %d len %d secret %zu exchange %zu", __func__, - group->id, dh_getlen(group), ibuf_length(dhsecret), + " group %d len %d secret %zu exchange %zu", + __func__, group->id, dh_getlen(group), + ibuf_length(dhsecret), ibuf_length(kex->kex_dhpeer)); goto done; } @@ -4692,6 +4709,9 @@ int ikev2_childsa_enable(struct iked *env, struct iked_sa *sa) { struct iked_childsa *csa; +#if defined (_INSTALL_IPSEC_POLICY) + struct iked_flow *flow, *oflow; +#endif if (sa->sa_ipcomp && sa->sa_cpi_in && sa->sa_cpi_out && ikev2_ipcomp_enable(env, sa) == -1) @@ -4789,7 +4809,7 @@ ikev2_valid_proposal(struct iked_proposal *prop, struct iked_transform **exf, struct iked_transform **ixf, int *esn) { struct iked_transform *xform, *encrxf, *integrxf; - u_int i, doesn = 0; + unsigned int i, doesn = 0; switch (prop->prop_protoid) { case IKEV2_SAPROTO_ESP: @@ -4857,9 +4877,7 @@ ikev2_acquire_sa(struct iked *env, struct iked_flow *acquire) pol.pol_nflows = 1; if ((p = policy_test(env, &pol)) == NULL) { - log_warnx("%s: config for peer %s wasn't found", - __func__, print_host((struct sockaddr *) - &((acquire->flow_dst).addr), NULL, 0)); + log_warnx("%s: flow wasn't found", __func__); return (0); } @@ -4943,7 +4961,7 @@ ikev2_drop_sa(struct iked *env, struct iked_spi *drop) struct iked_childsa *csa, key; struct iked_sa *sa; struct ikev2_delete *del; - u_int32_t spi32; + uint32_t spi32; key.csa_spi = *drop; csa = RB_FIND(iked_activesas, &env->sc_activesas, &key); @@ -5009,7 +5027,7 @@ ikev2_drop_sa(struct iked *env, struct iked_spi *drop) int ikev2_print_id(struct iked_id *id, char *idstr, size_t idstrlen) { - u_int8_t buf[BUFSIZ], *ptr; + uint8_t buf[BUFSIZ], *ptr; struct sockaddr_in *s4; struct sockaddr_in6 *s6; char *str; @@ -5102,7 +5120,7 @@ ikev2_print_id(struct iked_id *id, char *idstr, size_t idstrlen) * and remember it in the sa_addrpool attribute. */ int -ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa) +ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa, sa_family_t family) { struct iked_cfg *ikecfg = NULL; struct iked_policy *pol = sa->sa_policy; @@ -5110,21 +5128,35 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa) struct sockaddr_in6 *in6 = NULL, *cfg6 = NULL; struct iked_sa key; struct iked_addr addr; - u_int32_t mask, host, lower, upper, start; + uint32_t mask, host, lower, upper, start, nhost; size_t i; - if (sa->sa_addrpool || pol->pol_ncfg == 0) + switch (family) { + case AF_INET: + if (sa->sa_addrpool) + return (0); + break; + case AF_INET6: + if (sa->sa_addrpool6) + return (0); + break; + default: + return (-1); + } + if (pol->pol_ncfg == 0) return (0); /* check for an address pool config (address w/ prefixlen != 32) */ bzero(&addr, sizeof(addr)); for (i = 0; i < pol->pol_ncfg; i++) { ikecfg = &pol->pol_cfg[i]; - if (ikecfg->cfg_type == IKEV2_CFG_INTERNAL_IP4_ADDRESS && + if (family == AF_INET && + ikecfg->cfg_type == IKEV2_CFG_INTERNAL_IP4_ADDRESS && ikecfg->cfg.address.addr_mask != 32) { addr.addr_af = AF_INET; break; } - if (ikecfg->cfg_type == IKEV2_CFG_INTERNAL_IP6_ADDRESS && + if (family == AF_INET6 && + ikecfg->cfg_type == IKEV2_CFG_INTERNAL_IP6_ADDRESS && ikecfg->cfg.address.addr_mask != 128) { addr.addr_af = AF_INET6; break; @@ -5144,23 +5176,28 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa) return (-1); } - /* truncate prefixlen in the v6 case */ - mask = prefixlen2mask(ikecfg->cfg.address.addr_mask); - switch (addr.addr_af) { case AF_INET: cfg4 = (struct sockaddr_in *)&ikecfg->cfg.address.addr; in4 = (struct sockaddr_in *)&addr.addr; in4->sin_family = AF_INET; in4->sin_len = sizeof(*in4); + mask = prefixlen2mask(ikecfg->cfg.address.addr_mask); lower = ntohl(cfg4->sin_addr.s_addr & ~mask); + key.sa_addrpool = &addr; break; case AF_INET6: cfg6 = (struct sockaddr_in6 *)&ikecfg->cfg.address.addr; in6 = (struct sockaddr_in6 *)&addr.addr; in6->sin6_family = AF_INET6; in6->sin6_len = sizeof(*in6); - lower = cfg6->sin6_addr.s6_addr[3]; + /* truncate prefixlen to get a 32-bit space */ + mask = (ikecfg->cfg.address.addr_mask >= 96) + ? prefixlen2mask(ikecfg->cfg.address.addr_mask - 96) + : prefixlen2mask(0); + memcpy(&lower, &cfg6->sin6_addr.s6_addr[12], sizeof(uint32_t)); + lower = ntohl(lower & ~mask); + key.sa_addrpool6 = &addr; break; default: return (-1); @@ -5173,8 +5210,6 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa) /* Randomly select start from [lower, upper-1] */ start = arc4random_uniform(upper - lower) + lower; - key.sa_addrpool = &addr; - for (host = start;;) { log_debug("%s: mask %x start %x lower %x host %x upper %x", __func__, mask, start, lower, host, upper); @@ -5185,10 +5220,15 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa) break; case AF_INET6: memcpy(in6, cfg6, sizeof(*in6)); - in6->sin6_addr.s6_addr[3] = htonl(host); + nhost = htonl(host); + memcpy(&in6->sin6_addr.s6_addr[12], &nhost, + sizeof(uint32_t)); break; } - if (!RB_FIND(iked_addrpool, &env->sc_addrpool, &key)) + if ((addr.addr_af == AF_INET && + !RB_FIND(iked_addrpool, &env->sc_addrpool, &key)) || + (addr.addr_af == AF_INET6 && + !RB_FIND(iked_addrpool6, &env->sc_addrpool6, &key))) break; /* try next address */ host++; @@ -5198,12 +5238,27 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa) if (host == start) return (-1); /* exhausted */ } - if (!key.sa_addrpool) - return (-1); /* cannot happen? */ - if ((sa->sa_addrpool = calloc(1, sizeof(addr))) == NULL) + + switch (addr.addr_af) { + case AF_INET: + if (!key.sa_addrpool) + return (-1); /* cannot happen? */ + if ((sa->sa_addrpool = calloc(1, sizeof(addr))) == NULL) + return (-1); + memcpy(sa->sa_addrpool, &addr, sizeof(addr)); + RB_INSERT(iked_addrpool, &env->sc_addrpool, sa); + break; + case AF_INET6: + if (!key.sa_addrpool6) + return (-1); /* cannot happen? */ + if ((sa->sa_addrpool6 = calloc(1, sizeof(addr))) == NULL) + return (-1); + memcpy(sa->sa_addrpool6, &addr, sizeof(addr)); + RB_INSERT(iked_addrpool6, &env->sc_addrpool6, sa); + break; + default: return (-1); - memcpy(sa->sa_addrpool, &addr, sizeof(addr)); - RB_INSERT(iked_addrpool, &env->sc_addrpool, sa); + } return (0); } @@ -5218,21 +5273,23 @@ ikev2_cp_fixaddr(struct iked_sa *sa, struct iked_addr *addr, struct sockaddr_in *in4; struct sockaddr_in6 *in6; - if (sa->sa_addrpool == NULL || - sa->sa_addrpool->addr_af != addr->addr_af) - return (-1); switch (addr->addr_af) { case AF_INET: + if (sa->sa_addrpool == NULL) + return (-1); in4 = (struct sockaddr_in *)&addr->addr; if (in4->sin_addr.s_addr) return (-1); + memcpy(patched, sa->sa_addrpool, sizeof(*patched)); break; case AF_INET6: + if (sa->sa_addrpool6 == NULL) + return (-1); in6 = (struct sockaddr_in6 *)&addr->addr; - if (IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) + if (!IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) return (-1); + memcpy(patched, sa->sa_addrpool6, sizeof(*patched)); break; } - memcpy(patched, sa->sa_addrpool, sizeof(*patched)); return (0); } diff --git a/iked/ikev2.h b/iked/ikev2.h index b794665..e2b182c 100644 --- a/iked/ikev2.h +++ b/iked/ikev2.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.h,v 1.19 2015/06/11 18:49:09 reyk Exp $ */ +/* $OpenBSD: ikev2.h,v 1.23 2015/10/31 19:28:19 naddy Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -73,9 +73,9 @@ extern struct iked_constmap ikev2_flag_map[]; */ struct ikev2_payload { - u_int8_t pld_nextpayload; /* Next payload type */ - u_int8_t pld_reserved; /* Contains the critical bit */ - u_int16_t pld_length; /* Payload length with header */ + uint8_t pld_nextpayload; /* Next payload type */ + uint8_t pld_reserved; /* Contains the critical bit */ + uint16_t pld_length; /* Payload length with header */ } __packed; #define IKEV2_CRITICAL_PAYLOAD 0x01 /* First bit in the reserved field */ @@ -107,13 +107,13 @@ extern struct iked_constmap ikev2_payload_map[]; */ struct ikev2_sa_proposal { - u_int8_t sap_more; /* Last proposal or more */ - u_int8_t sap_reserved; /* Must be set to zero */ - u_int16_t sap_length; /* Proposal length */ - u_int8_t sap_proposalnr; /* Proposal number */ - u_int8_t sap_protoid; /* Protocol Id */ - u_int8_t sap_spisize; /* SPI size */ - u_int8_t sap_transforms; /* Number of transforms */ + uint8_t sap_more; /* Last proposal or more */ + uint8_t sap_reserved; /* Must be set to zero */ + uint16_t sap_length; /* Proposal length */ + uint8_t sap_proposalnr; /* Proposal number */ + uint8_t sap_protoid; /* Protocol Id */ + uint8_t sap_spisize; /* SPI size */ + uint8_t sap_transforms; /* Number of transforms */ /* Followed by variable-length SPI */ /* Followed by variable-length transforms */ } __packed; @@ -132,12 +132,12 @@ struct ikev2_sa_proposal { extern struct iked_constmap ikev2_saproto_map[]; struct ikev2_transform { - u_int8_t xfrm_more; /* Last transform or more */ - u_int8_t xfrm_reserved; /* Must be set to zero */ - u_int16_t xfrm_length; /* Transform length */ - u_int8_t xfrm_type; /* Transform type */ - u_int8_t xfrm_reserved1; /* Must be set to zero */ - u_int16_t xfrm_id; /* Transform Id */ + uint8_t xfrm_more; /* Last transform or more */ + uint8_t xfrm_reserved; /* Must be set to zero */ + uint16_t xfrm_length; /* Transform length */ + uint8_t xfrm_type; /* Transform type */ + uint8_t xfrm_reserved1; /* Must be set to zero */ + uint16_t xfrm_id; /* Transform Id */ /* Followed by variable-length transform attributes */ } __packed; @@ -180,6 +180,7 @@ extern struct iked_constmap ikev2_xformtype_map[]; #define IKEV2_XFORMENCR_CAMELLIA_CCM_8 25 /* RFC5529 */ #define IKEV2_XFORMENCR_CAMELLIA_CCM_12 26 /* RFC5529 */ #define IKEV2_XFORMENCR_CAMELLIA_CCM_16 27 /* RFC5529 */ +#define IKEV2_XFORMENCR_CHACHA20_POLY1305 28 /* RFC7634 */ extern struct iked_constmap ikev2_xformencr_map[]; @@ -242,7 +243,7 @@ extern struct iked_constmap ikev2_xformauth_map[]; #define IKEV2_XFORMDH_BRAINPOOL_P256R1 28 /* DH Group 28 */ #define IKEV2_XFORMDH_BRAINPOOL_P384R1 29 /* DH Group 29 */ #define IKEV2_XFORMDH_BRAINPOOL_P512R1 30 /* DH Group 30 */ -#define IKEV2_XFORMDH_X_CURVE25519 1034 /* curve25519 */ +#define IKEV2_XFORMDH_X_CURVE25519 1034 /* draft-ietf-ipsecme-safecurves-00 */ extern struct iked_constmap ikev2_xformdh_map[]; @@ -252,8 +253,8 @@ extern struct iked_constmap ikev2_xformdh_map[]; extern struct iked_constmap ikev2_xformesn_map[]; struct ikev2_attribute { - u_int16_t attr_type; /* Attribute type */ - u_int16_t attr_length; /* Attribute length or value */ + uint16_t attr_type; /* Attribute type */ + uint16_t attr_length; /* Attribute length or value */ /* Followed by variable length (TLV) */ } __packed; @@ -269,8 +270,8 @@ extern struct iked_constmap ikev2_attrtype_map[]; */ struct ikev2_keyexchange { - u_int16_t kex_dhgroup; /* DH Group # */ - u_int16_t kex_reserved; /* Reserved */ + uint16_t kex_dhgroup; /* DH Group # */ + uint16_t kex_reserved; /* Reserved */ } __packed; /* @@ -278,9 +279,9 @@ struct ikev2_keyexchange { */ struct ikev2_notify { - u_int8_t n_protoid; /* Protocol Id */ - u_int8_t n_spisize; /* SPI size */ - u_int16_t n_type; /* Notify message type */ + uint8_t n_protoid; /* Protocol Id */ + uint8_t n_spisize; /* SPI size */ + uint16_t n_type; /* Notify message type */ /* Followed by variable length SPI */ /* Followed by variable length notification data */ } __packed; @@ -359,9 +360,9 @@ extern struct iked_constmap ikev2_n_map[]; */ struct ikev2_delete { - u_int8_t del_protoid; /* Protocol Id */ - u_int8_t del_spisize; /* SPI size */ - u_int16_t del_nspi; /* Number of SPIs */ + uint8_t del_protoid; /* Protocol Id */ + uint8_t del_spisize; /* SPI size */ + uint16_t del_nspi; /* Number of SPIs */ /* Followed by variable length SPIs */ } __packed; @@ -370,8 +371,8 @@ struct ikev2_delete { */ struct ikev2_id { - u_int8_t id_type; /* Id type */ - u_int8_t id_reserved[3]; /* Reserved */ + uint8_t id_type; /* Id type */ + uint8_t id_reserved[3]; /* Reserved */ /* Followed by the identification data */ } __packed; @@ -392,7 +393,7 @@ extern struct iked_constmap ikev2_id_map[]; */ struct ikev2_cert { - u_int8_t cert_type; /* Encoding */ + uint8_t cert_type; /* Encoding */ /* Followed by the certificate data */ } __packed; @@ -418,17 +419,17 @@ extern struct iked_constmap ikev2_cert_map[]; */ struct ikev2_tsp { - u_int8_t tsp_count; /* Number of TSs */ - u_int8_t tsp_reserved[3]; /* Reserved */ + uint8_t tsp_count; /* Number of TSs */ + uint8_t tsp_reserved[3]; /* Reserved */ /* Followed by the traffic selectors */ } __packed; struct ikev2_ts { - u_int8_t ts_type; /* TS type */ - u_int8_t ts_protoid; /* Protocol Id */ - u_int16_t ts_length; /* Length */ - u_int16_t ts_startport; /* Start port */ - u_int16_t ts_endport; /* End port */ + uint8_t ts_type; /* TS type */ + uint8_t ts_protoid; /* Protocol Id */ + uint16_t ts_length; /* Length */ + uint16_t ts_startport; /* Start port */ + uint16_t ts_endport; /* End port */ } __packed; #define IKEV2_TS_IPV4_ADDR_RANGE 7 /* RFC4306 */ @@ -442,8 +443,8 @@ extern struct iked_constmap ikev2_ts_map[]; */ struct ikev2_auth { - u_int8_t auth_method; /* Signature type */ - u_int8_t auth_reserved[3]; /* Reserved */ + uint8_t auth_method; /* Signature type */ + uint8_t auth_reserved[3]; /* Reserved */ /* Followed by the signature */ } __packed; @@ -453,8 +454,9 @@ struct ikev2_auth { #define IKEV2_AUTH_DSS_SIG 3 /* RFC4306 */ #define IKEV2_AUTH_ECDSA_256 9 /* RFC4754 */ #define IKEV2_AUTH_ECDSA_384 10 /* RFC4754 */ -#define IKEV2_AUTH_ECDSA_512 11 /* RFC4754 */ +#define IKEV2_AUTH_ECDSA_521 11 /* RFC4754 */ #define IKEV2_AUTH_GSPM 12 /* RFC6467 */ +#define IKEV2_AUTH_NULL 13 /* RFC7619 */ #define IKEV2_AUTH_SIG 14 /* RFC7427 */ extern struct iked_constmap ikev2_auth_map[]; @@ -474,8 +476,8 @@ extern struct iked_constmap ikev2_sighash_map[]; */ struct ikev2_cp { - u_int8_t cp_type; - u_int8_t cp_reserved[3]; + uint8_t cp_type; + uint8_t cp_reserved[3]; /* Followed by the attributes */ } __packed; @@ -487,8 +489,8 @@ struct ikev2_cp { extern struct iked_constmap ikev2_cp_map[]; struct ikev2_cfg { - u_int16_t cfg_type; /* first bit must be set to zero */ - u_int16_t cfg_length; + uint16_t cfg_type; /* first bit must be set to zero */ + uint16_t cfg_length; /* Followed by variable-length data */ } __packed; diff --git a/iked/ikev2_msg.c b/iked/ikev2_msg.c index 5d87371..2fbc5bd 100644 --- a/iked/ikev2_msg.c +++ b/iked/ikev2_msg.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2_msg.c,v 1.42 2015/03/26 19:52:35 markus Exp $ */ +/* $OpenBSD: ikev2_msg.c,v 1.45 2015/10/19 11:25:35 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -43,6 +43,7 @@ #include "eap.h" #include "dh.h" +void ikev1_recv(struct iked *, struct iked_message *); void ikev2_msg_response_timeout(struct iked *, void *); void ikev2_msg_retransmit_timeout(struct iked *, void *); @@ -53,11 +54,10 @@ ikev2_msg_cb(int fd, short event, void *arg) struct iked *env = sock->sock_env; struct iked_message msg; struct ike_header hdr; - u_int32_t natt = 0x00000000; - u_int8_t buf[IKED_MSGBUF_MAX]; + uint32_t natt = 0x00000000; + uint8_t buf[IKED_MSGBUF_MAX]; ssize_t len; off_t off; - struct iovec iov[2]; bzero(&msg, sizeof(msg)); bzero(buf, sizeof(buf)); @@ -89,25 +89,44 @@ ikev2_msg_cb(int fd, short event, void *arg) if ((msg.msg_data = ibuf_new(buf + off, len - off)) == NULL) return; - if (hdr.ike_version == IKEV1_VERSION) { - iov[0].iov_base = &msg; - iov[0].iov_len = sizeof(msg); - iov[1].iov_base = buf; - iov[1].iov_len = len; - - proc_composev_imsg(&env->sc_ps, PROC_IKEV1, -1, - IMSG_IKE_MESSAGE, -1, iov, 2); - goto done; - } TAILQ_INIT(&msg.msg_proposals); - msg.msg_fd = fd; - ikev2_recv(env, &msg); - done: + if (hdr.ike_version == IKEV1_VERSION) + ikev1_recv(env, &msg); + else + ikev2_recv(env, &msg); + ikev2_msg_cleanup(env, &msg); } +void +ikev1_recv(struct iked *env, struct iked_message *msg) +{ + struct ike_header *hdr; + + if (ibuf_size(msg->msg_data) <= sizeof(*hdr)) { + log_debug("%s: short message", __func__); + return; + } + + hdr = (struct ike_header *)ibuf_data(msg->msg_data); + + log_debug("%s: header ispi %s rspi %s" + " nextpayload %u version 0x%02x exchange %u flags 0x%02x" + " msgid %u length %u", __func__, + print_spi(betoh64(hdr->ike_ispi), 8), + print_spi(betoh64(hdr->ike_rspi), 8), + hdr->ike_nextpayload, + hdr->ike_version, + hdr->ike_exchange, + hdr->ike_flags, + betoh32(hdr->ike_msgid), + betoh32(hdr->ike_length)); + + log_debug("%s: IKEv1 not supported", __func__); +} + struct ibuf * ikev2_msg_init(struct iked *env, struct iked_message *msg, struct sockaddr_storage *peer, socklen_t peerlen, @@ -270,9 +289,9 @@ ikev2_msg_send(struct iked *env, struct iked_message *msg) { struct iked_sa *sa = msg->msg_sa; struct ibuf *buf = msg->msg_data; - u_int32_t natt = 0x00000000; + uint32_t natt = 0x00000000; int isnatt = 0; - u_int8_t exchange, flags; + uint8_t exchange, flags; struct ike_header *hdr; struct iked_message *m; @@ -328,10 +347,10 @@ ikev2_msg_send(struct iked *env, struct iked_message *msg) return (0); } -u_int32_t +uint32_t ikev2_msg_id(struct iked *env, struct iked_sa *sa) { - u_int32_t id = sa->sa_reqid; + uint32_t id = sa->sa_reqid; if (++sa->sa_reqid == UINT32_MAX) { /* XXX we should close and renegotiate the connection now */ @@ -345,7 +364,7 @@ ikev2_msg_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf *src) { size_t len, ivlen, encrlen, integrlen, blocklen, outlen; - u_int8_t *buf, pad = 0, *ptr; + uint8_t *buf, pad = 0, *ptr; struct ibuf *encr, *dst = NULL, *out = NULL; buf = ibuf_data(src); @@ -428,7 +447,7 @@ ikev2_msg_integr(struct iked *env, struct iked_sa *sa, struct ibuf *src) int ret = -1; size_t integrlen, tmplen; struct ibuf *integr, *tmp = NULL; - u_int8_t *ptr; + uint8_t *ptr; log_debug("%s: message length %zu", __func__, ibuf_size(src)); print_hex(ibuf_data(src), 0, ibuf_size(src)); @@ -486,7 +505,7 @@ ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, { ssize_t ivlen, encrlen, integrlen, blocklen, outlen, tmplen; - u_int8_t pad = 0, *ptr; + uint8_t pad = 0, *ptr; struct ibuf *integr, *encr, *tmp = NULL, *out = NULL; off_t ivoff, encroff, integroff; @@ -536,7 +555,7 @@ ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, hash_init(sa->sa_integr); hash_update(sa->sa_integr, ibuf_data(msg), ibuf_size(msg) - integrlen); - hash_final(sa->sa_integr, tmp->buf, (size_t *)&tmplen); + hash_final(sa->sa_integr, tmp->buf, &tmplen); if (memcmp(tmp->buf, ibuf_data(src) + integroff, integrlen) != 0) { log_debug("%s: integrity check failed", __func__); @@ -567,7 +586,7 @@ ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, if ((outlen = ibuf_length(out)) != 0) { cipher_update(sa->sa_encr, ibuf_data(src) + encroff, encrlen, - ibuf_data(out), (size_t *)&outlen); + ibuf_data(out), &outlen); ptr = ibuf_seek(out, outlen - 1, 1); pad = *ptr; @@ -591,7 +610,7 @@ ikev2_msg_decrypt(struct iked *env, struct iked_sa *sa, int ikev2_msg_send_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf **ep, - u_int8_t exchange, u_int8_t firstpayload, int response) + uint8_t exchange, uint8_t firstpayload, int response) { struct iked_message resp; struct ike_header *hdr; @@ -654,7 +673,7 @@ struct ibuf * ikev2_msg_auth(struct iked *env, struct iked_sa *sa, int response) { struct ibuf *authmsg = NULL, *nonce, *prfkey, *buf; - u_int8_t *ptr; + uint8_t *ptr; struct iked_id *id; size_t tmplen; @@ -712,14 +731,14 @@ ikev2_msg_auth(struct iked *env, struct iked_sa *sa, int response) int ikev2_msg_authverify(struct iked *env, struct iked_sa *sa, - struct iked_auth *auth, u_int8_t *buf, size_t len, struct ibuf *authmsg) + struct iked_auth *auth, uint8_t *buf, size_t len, struct ibuf *authmsg) { - u_int8_t *key, *psk = NULL; + uint8_t *key, *psk = NULL; ssize_t keylen; struct iked_id *id; struct iked_dsa *dsa = NULL; int ret = -1; - u_int8_t keytype; + uint8_t keytype; if (sa->sa_hdr.sh_initiator) id = &sa->sa_rcert; @@ -777,8 +796,7 @@ ikev2_msg_authverify(struct iked *env, struct iked_sa *sa, } done: - if (psk != NULL) - free(psk); + free(psk); dsa_free(dsa); return (ret); @@ -788,14 +806,14 @@ int ikev2_msg_authsign(struct iked *env, struct iked_sa *sa, struct iked_auth *auth, struct ibuf *authmsg) { - u_int8_t *key, *psk = NULL; + uint8_t *key, *psk = NULL; ssize_t keylen; struct iked_hash *prf = sa->sa_prf; struct iked_id *id; struct iked_dsa *dsa = NULL; struct ibuf *buf; int ret = -1; - u_int8_t keytype; + uint8_t keytype; if (sa->sa_hdr.sh_initiator) id = &sa->sa_icert; @@ -859,8 +877,7 @@ ikev2_msg_authsign(struct iked *env, struct iked_sa *sa, ret = 0; done: - if (psk != NULL) - free(psk); + free(psk); dsa_free(dsa); return (ret); diff --git a/iked/ikev2_pld.c b/iked/ikev2_pld.c index b282293..2b70f6c 100644 --- a/iked/ikev2_pld.c +++ b/iked/ikev2_pld.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2_pld.c,v 1.50 2015/03/26 19:52:35 markus Exp $ */ +/* $OpenBSD: ikev2_pld.c,v 1.55 2015/10/15 18:40:38 mmcc Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -46,7 +46,7 @@ int ikev2_validate_pld(struct iked_message *, size_t, size_t, struct ikev2_payload *); int ikev2_pld_payloads(struct iked *, struct iked_message *, - size_t, size_t, u_int); + size_t, size_t, unsigned int); int ikev2_validate_sa(struct iked_message *, size_t, size_t, struct ikev2_payload *, struct ikev2_sa_proposal *); int ikev2_pld_sa(struct iked *, struct ikev2_payload *, @@ -66,7 +66,7 @@ int ikev2_pld_ke(struct iked *, struct ikev2_payload *, int ikev2_validate_id(struct iked_message *, size_t, size_t, struct ikev2_payload *, struct ikev2_id *); int ikev2_pld_id(struct iked *, struct ikev2_payload *, - struct iked_message *, size_t, size_t, u_int); + struct iked_message *, size_t, size_t, unsigned int); int ikev2_validate_cert(struct iked_message *, size_t, size_t, struct ikev2_payload *, struct ikev2_cert *); int ikev2_pld_cert(struct iked *, struct ikev2_payload *, @@ -90,7 +90,7 @@ int ikev2_pld_delete(struct iked *, struct ikev2_payload *, int ikev2_validate_ts(struct iked_message *, size_t, size_t, struct ikev2_payload *, struct ikev2_tsp *); int ikev2_pld_ts(struct iked *, struct ikev2_payload *, - struct iked_message *, size_t, size_t, u_int); + struct iked_message *, size_t, size_t, unsigned int); int ikev2_validate_auth(struct iked_message *, size_t, size_t, struct ikev2_payload *, struct ikev2_auth *); int ikev2_pld_auth(struct iked *, struct ikev2_payload *, @@ -138,7 +138,7 @@ int ikev2_validate_pld(struct iked_message *msg, size_t offset, size_t left, struct ikev2_payload *pld) { - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); size_t pld_length; /* We need at least the generic header. */ @@ -176,12 +176,12 @@ ikev2_validate_pld(struct iked_message *msg, size_t offset, size_t left, int ikev2_pld_payloads(struct iked *env, struct iked_message *msg, - size_t offset, size_t length, u_int payload) + size_t offset, size_t length, unsigned int payload) { struct ikev2_payload pld; - u_int e; + unsigned int e; int ret; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); size_t left; /* Check if message was decrypted in an E payload */ @@ -282,7 +282,7 @@ int ikev2_validate_sa(struct iked_message *msg, size_t offset, size_t left, struct ikev2_payload *pld, struct ikev2_sa_proposal *sap) { - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); size_t pld_length, sap_length; pld_length = betoh16(pld->pld_length); @@ -355,9 +355,9 @@ ikev2_pld_sa(struct iked *env, struct ikev2_payload *pld, { struct ikev2_sa_proposal sap; struct iked_proposal *prop = NULL; - u_int32_t spi32; - u_int64_t spi = 0, spi64; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint32_t spi32; + uint64_t spi = 0, spi64; + uint8_t *msgbuf = ibuf_data(msg->msg_data); struct iked_proposals *props; size_t total; @@ -463,7 +463,7 @@ int ikev2_validate_xform(struct iked_message *msg, size_t offset, size_t total, struct ikev2_transform *xfrm) { - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); size_t xfrm_length; if (total < sizeof(*xfrm)) { @@ -572,7 +572,7 @@ int ikev2_validate_attr(struct iked_message *msg, size_t offset, size_t total, struct ikev2_attribute *attr) { - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); if (total < sizeof(*attr)) { log_debug("%s: payload malformed: too short for header " @@ -589,8 +589,8 @@ ikev2_pld_attr(struct iked *env, struct ikev2_transform *xfrm, struct iked_message *msg, size_t offset, size_t total) { struct ikev2_attribute attr; - u_int type; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + unsigned int type; + uint8_t *msgbuf = ibuf_data(msg->msg_data); int ret = 0; size_t attr_length; @@ -643,7 +643,7 @@ int ikev2_validate_ke(struct iked_message *msg, size_t offset, size_t left, struct ikev2_payload *pld, struct ikev2_keyexchange *kex) { - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); size_t pld_length; pld_length = betoh16(pld->pld_length); @@ -670,9 +670,9 @@ ikev2_pld_ke(struct iked *env, struct ikev2_payload *pld, struct iked_message *msg, size_t offset, size_t left) { struct ikev2_keyexchange kex; - u_int8_t *buf; + uint8_t *buf; size_t len; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); if (ikev2_validate_ke(msg, offset, left, pld, &kex)) return (-1); @@ -712,7 +712,7 @@ int ikev2_validate_id(struct iked_message *msg, size_t offset, size_t left, struct ikev2_payload *pld, struct ikev2_id *id) { - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); size_t pld_length; pld_length = betoh16(pld->pld_length); @@ -736,14 +736,14 @@ ikev2_validate_id(struct iked_message *msg, size_t offset, size_t left, int ikev2_pld_id(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, size_t offset, size_t left, u_int payload) + struct iked_message *msg, size_t offset, size_t left, unsigned int payload) { - u_int8_t *ptr; + uint8_t *ptr; struct ikev2_id id; size_t len; struct iked_id *idp, idb; struct iked_sa *sa = msg->msg_sa; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); char idstr[IKED_ID_SIZE]; if (ikev2_validate_id(msg, offset, left, pld, &id)) @@ -795,7 +795,7 @@ int ikev2_validate_cert(struct iked_message *msg, size_t offset, size_t left, struct ikev2_payload *pld, struct ikev2_cert *cert) { - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); size_t pld_length; pld_length = betoh16(pld->pld_length); @@ -822,10 +822,10 @@ ikev2_pld_cert(struct iked *env, struct ikev2_payload *pld, struct iked_message *msg, size_t offset, size_t left) { struct ikev2_cert cert; - u_int8_t *buf; + uint8_t *buf; size_t len; struct iked_id *certid; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); if (ikev2_validate_cert(msg, offset, left, pld, &cert)) return (-1); @@ -862,7 +862,7 @@ int ikev2_validate_certreq(struct iked_message *msg, size_t offset, size_t left, struct ikev2_payload *pld, struct ikev2_cert *cert) { - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); size_t pld_length; pld_length = betoh16(pld->pld_length); @@ -890,9 +890,9 @@ ikev2_pld_certreq(struct iked *env, struct ikev2_payload *pld, { struct iked_sa *sa = msg->msg_sa; struct ikev2_cert cert; - u_int8_t *buf; + uint8_t *buf; ssize_t len; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); if (ikev2_validate_certreq(msg, offset, left, pld, &cert)) return (-1); @@ -916,7 +916,9 @@ ikev2_pld_certreq(struct iked *env, struct ikev2_payload *pld, return (0); if (cert.cert_type == IKEV2_CERT_X509_CERT) { - if (!len || (len % SHA_DIGEST_LENGTH) != 0) { + if (!len) + return (0); + if ((len % SHA_DIGEST_LENGTH) != 0) { log_debug("%s: invalid certificate request", __func__); return (-1); } @@ -931,7 +933,7 @@ ikev2_pld_certreq(struct iked *env, struct ikev2_payload *pld, else sa->sa_statevalid |= IKED_REQ_CERT; - ca_setreq(env, &sa->sa_hdr, &sa->sa_policy->pol_localid, + ca_setreq(env, sa, &sa->sa_policy->pol_localid, cert.cert_type, buf, len, PROC_CERT); return (0); @@ -941,7 +943,7 @@ int ikev2_validate_auth(struct iked_message *msg, size_t offset, size_t left, struct ikev2_payload *pld, struct ikev2_auth *auth) { - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); size_t pld_length; pld_length = betoh16(pld->pld_length); @@ -969,10 +971,10 @@ ikev2_pld_auth(struct iked *env, struct ikev2_payload *pld, { struct ikev2_auth auth; struct iked_id *idp; - u_int8_t *buf; + uint8_t *buf; size_t len; struct iked_sa *sa = msg->msg_sa; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); if (ikev2_validate_auth(msg, offset, left, pld, &auth)) return (-1); @@ -1031,8 +1033,8 @@ ikev2_pld_nonce(struct iked *env, struct ikev2_payload *pld, struct iked_message *msg, size_t offset, size_t left) { size_t len; - u_int8_t *buf; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *buf; + uint8_t *msgbuf = ibuf_data(msg->msg_data); if (ikev2_validate_nonce(msg, offset, left, pld)) return (-1); @@ -1069,7 +1071,7 @@ int ikev2_validate_notify(struct iked_message *msg, size_t offset, size_t left, struct ikev2_payload *pld, struct ikev2_notify *n) { - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); size_t pld_length; pld_length = betoh16(pld->pld_length); @@ -1096,16 +1098,16 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, struct iked_message *msg, size_t offset, size_t left) { struct ikev2_notify n; - u_int8_t *buf, md[SHA_DIGEST_LENGTH]; + uint8_t *buf, md[SHA_DIGEST_LENGTH]; size_t len; - u_int32_t spi32; - u_int64_t spi64; + uint32_t spi32; + uint64_t spi64; struct iked_spi *rekey; - u_int16_t type; - u_int16_t group; - u_int16_t cpi; - u_int16_t signature_hash; - u_int8_t transform; + uint16_t type; + uint16_t group; + uint16_t cpi; + uint16_t signature_hash; + uint8_t transform; if (ikev2_validate_notify(msg, offset, left, pld, &n)) return (-1); @@ -1180,7 +1182,10 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, group); sa_state(env, msg->msg_sa, IKEV2_STATE_CLOSED); msg->msg_sa = NULL; - /* XXX chould also happen for PFS so we have to check state XXX*/ + + /* + * XXX should also happen for PFS so we have to check state. + */ timer_set(env, &env->sc_inittmr, ikev2_init_ike_sa, NULL); timer_add(env, &env->sc_inittmr, IKED_INITIATOR_INITIAL); break; @@ -1309,7 +1314,7 @@ int ikev2_validate_delete(struct iked_message *msg, size_t offset, size_t left, struct ikev2_payload *pld, struct ikev2_delete *del) { - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); size_t pld_length; pld_length = betoh16(pld->pld_length); @@ -1339,10 +1344,10 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, struct iked_sa *sa = msg->msg_sa; struct ikev2_delete del, *localdel; struct ibuf *resp = NULL; - u_int64_t *localspi = NULL; - u_int64_t spi64, spi = 0; - u_int32_t spi32; - u_int8_t *buf, *msgbuf = ibuf_data(msg->msg_data); + uint64_t *localspi = NULL; + uint64_t spi64, spi = 0; + uint32_t spi32; + uint8_t *buf, *msgbuf = ibuf_data(msg->msg_data); size_t found = 0, failed = 0; int cnt, i, len, sz, ret = -1; @@ -1402,7 +1407,7 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, if (ikev2_msg_frompeer(msg) && ((peersas = calloc(cnt, sizeof(struct iked_childsa *))) == NULL || - (localspi = calloc(cnt, sizeof(u_int64_t))) == NULL)) { + (localspi = calloc(cnt, sizeof(uint64_t))) == NULL)) { log_warn("%s", __func__); goto done; } @@ -1493,10 +1498,8 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld, } done: - if (localspi) - free(localspi); - if (peersas) - free(peersas); + free(localspi); + free(peersas); ibuf_release(resp); return (ret); } @@ -1505,7 +1508,7 @@ int ikev2_validate_ts(struct iked_message *msg, size_t offset, size_t left, struct ikev2_payload *pld, struct ikev2_tsp *tsp) { - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); size_t pld_length; pld_length = betoh16(pld->pld_length); @@ -1529,15 +1532,15 @@ ikev2_validate_ts(struct iked_message *msg, size_t offset, size_t left, int ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld, - struct iked_message *msg, size_t offset, size_t left, u_int payload) + struct iked_message *msg, size_t offset, size_t left, unsigned int payload) { struct ikev2_tsp tsp; struct ikev2_ts ts; size_t len, i; struct sockaddr_in s4; struct sockaddr_in6 s6; - u_int8_t buf[2][128]; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t buf[2][128]; + uint8_t *msgbuf = ibuf_data(msg->msg_data); if (ikev2_validate_ts(msg, offset, left, pld, &tsp)) return (-1); @@ -1605,9 +1608,9 @@ ikev2_pld_e(struct iked *env, struct ikev2_payload *pld, { struct iked_sa *sa = msg->msg_sa; struct ibuf *e = NULL; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); struct iked_message emsg; - u_int8_t *buf; + uint8_t *buf; size_t len; int ret = -1; @@ -1651,7 +1654,7 @@ int ikev2_validate_cp(struct iked_message *msg, size_t offset, size_t left, struct ikev2_payload *pld, struct ikev2_cp *cp) { - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); size_t pld_length; pld_length = betoh16(pld->pld_length); @@ -1679,9 +1682,9 @@ ikev2_pld_cp(struct iked *env, struct ikev2_payload *pld, { struct ikev2_cp cp; struct ikev2_cfg *cfg; - u_int8_t *buf; + uint8_t *buf; size_t len, i; - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); struct iked_sa *sa = msg->msg_sa; if (ikev2_validate_cp(msg, offset, left, pld, &cp)) @@ -1719,7 +1722,7 @@ int ikev2_validate_eap(struct iked_message *msg, size_t offset, size_t left, struct ikev2_payload *pld, struct eap_header *hdr) { - u_int8_t *msgbuf = ibuf_data(msg->msg_data); + uint8_t *msgbuf = ibuf_data(msg->msg_data); size_t pld_length; pld_length = betoh16(pld->pld_length); diff --git a/iked/imsg_util.c b/iked/imsg_util.c index e56f832..0a7d886 100644 --- a/iked/imsg_util.c +++ b/iked/imsg_util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: imsg_util.c,v 1.9 2014/05/06 11:11:14 reyk Exp $ */ +/* $OpenBSD: imsg_util.c,v 1.10 2015/08/21 11:59:27 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -118,7 +118,7 @@ ibuf_length(struct ibuf *buf) return (ibuf_size(buf)); } -u_int8_t * +uint8_t * ibuf_data(struct ibuf *buf) { return (ibuf_seek(buf, 0, 0)); diff --git a/iked/log.c b/iked/log.c index f3727a4..7b1783b 100644 --- a/iked/log.c +++ b/iked/log.c @@ -1,4 +1,4 @@ -/* $OpenBSD: log.c,v 1.4 2015/01/16 06:39:58 deraadt Exp $ */ +/* $OpenBSD: log.c,v 1.8 2015/12/07 12:13:51 reyk Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -11,44 +11,65 @@ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ - -#include - - -#include -#include #include #include +#include #include #include -#include - -#include "iked.h" - -int debug; -int verbose; - -void vlog(int, const char *, va_list); -void logit(int, const char *, ...); +#include +#include + +int debug; +int verbose; +const char *log_procname; + +void log_init(int, int); +void log_procinit(const char *); +void log_verbose(int); +void log_warn(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_warnx(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_info(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_debug(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void logit(int, const char *, ...) + __attribute__((__format__ (printf, 2, 3))); +void vlog(int, const char *, va_list) + __attribute__((__format__ (printf, 2, 0))); +__dead void fatal(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +__dead void fatalx(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); void -log_init(int n_debug) +log_init(int n_debug, int facility) { extern char *__progname; debug = n_debug; verbose = n_debug; + log_procinit(__progname); - openlog(__progname, LOG_PID | LOG_NDELAY, LOG_LOCAL2); + if (!debug) + openlog(__progname, LOG_PID | LOG_NDELAY, facility); tzset(); } +void +log_procinit(const char *procname) +{ + if (procname != NULL) + log_procname = procname; +} + void log_verbose(int v) { @@ -68,8 +89,20 @@ logit(int pri, const char *fmt, ...) void vlog(int pri, const char *fmt, va_list ap) { + char *nfmt; - vsyslog(pri, fmt, ap); + if (debug) { + /* best effort in out of mem situations */ + if (asprintf(&nfmt, "%s\n", fmt) == -1) { + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + } else { + vfprintf(stderr, nfmt, ap); + free(nfmt); + } + fflush(stderr); + } else + vsyslog(pri, fmt, ap); } @@ -129,49 +162,45 @@ log_debug(const char *emsg, ...) } } -void -print_debug(const char *emsg, ...) +static void +vfatal(const char *emsg, va_list ap) { - va_list ap; - - if (debug && verbose > 2) { - va_start(ap, emsg); - vlog(LOG_DEBUG, emsg, ap); - va_end(ap); - } -} - -void -print_verbose(const char *emsg, ...) -{ - va_list ap; - - if (verbose) { - va_start(ap, emsg); - vlog(LOG_DEBUG, emsg, ap); - va_end(ap); + static char s[BUFSIZ]; + const char *sep; + + if (emsg != NULL) { + (void)vsnprintf(s, sizeof(s), emsg, ap); + sep = ": "; + } else { + s[0] = '\0'; + sep = ""; } + if (errno) + logit(LOG_CRIT, "%s: %s%s%s", + log_procname, s, sep, strerror(errno)); + else + logit(LOG_CRIT, "%s%s%s", log_procname, sep, s); } void -fatal(const char *emsg) +fatal(const char *emsg, ...) { - if (emsg == NULL) - logit(LOG_CRIT, "fatal: %s", strerror(errno)); - else { - if (errno) - logit(LOG_CRIT, "fatal: %s: %s", - emsg, strerror(errno)); - else - logit(LOG_CRIT, "fatal: %s", emsg); - } + va_list ap; + va_start(ap, emsg); + vfatal(emsg, ap); + va_end(ap); exit(1); } void -fatalx(const char *emsg) +fatalx(const char *emsg, ...) { + va_list ap; + errno = 0; - fatal(emsg); + va_start(ap, emsg); + vfatal(emsg, ap); + va_end(ap); + exit(1); } diff --git a/iked/ocsp.c b/iked/ocsp.c index 4e9c7a7..5efa661 100644 --- a/iked/ocsp.c +++ b/iked/ocsp.c @@ -1,3 +1,5 @@ +/* $OpenBSD: ocsp.c,v 1.8 2015/12/07 12:46:37 reyk Exp $ */ + /* * Copyright (c) 2014 Markus Friedl * Copyright (c) 2005 Marco Pfatschbacher @@ -40,7 +42,7 @@ struct iked_ocsp { struct iked *ocsp_env; /* back pointer to env */ struct iked_sahdr ocsp_sh; /* ike sa */ - u_int8_t ocsp_type; /* auth type */ + uint8_t ocsp_type; /* auth type */ struct iked_socket *ocsp_sock; /* socket to ocsp responder */ BIO *ocsp_cbio; /* matching OpenSSL obj */ OCSP_CERTID *ocsp_id; /* ocsp-id for cert */ @@ -86,7 +88,7 @@ ocsp_connect(struct iked *env) goto done; } - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + if ((fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)) < 0) { log_debug("%s: socket failed", __func__); goto done; } @@ -120,7 +122,6 @@ ocsp_connect(struct iked *env) path = NULL; log_debug("%s: connect(%s, %s)", __func__, host, port); - socket_set_blockmode(fd, BM_NONBLOCK); if (connect(fd, res->ai_addr, res->ai_addrlen) == -1) { /* register callback for ansync connect */ if (errno == EINPROGRESS) { @@ -185,10 +186,10 @@ ocsp_connect_finish(struct iked *env, int fd, struct ocsp_connect *oc) iov[0].iov_base = oc->oc_path; iov[0].iov_len = strlen(oc->oc_path); ret = proc_composev_imsg(&env->sc_ps, PROC_CERT, -1, - IMSG_OCSP_FD, fd, iov, iovcnt); + IMSG_OCSP_FD, -1, fd, iov, iovcnt); } else { ret = proc_compose_imsg(&env->sc_ps, PROC_CERT, -1, - IMSG_OCSP_FD, -1, NULL, 0); + IMSG_OCSP_FD, -1, -1, NULL, 0); if (fd >= 0) close(fd); } @@ -205,7 +206,7 @@ ocsp_connect_finish(struct iked *env, int fd, struct ocsp_connect *oc) /* validate the certifcate stored in 'data' by querying the ocsp-responder */ int ocsp_validate_cert(struct iked *env, struct iked_static_id *id, - void *data, size_t len, struct iked_sahdr sh, u_int8_t type) + void *data, size_t len, struct iked_sahdr sh, uint8_t type) { struct iked_ocsp_entry *ioe; struct iked_ocsp *ocsp; @@ -242,8 +243,7 @@ ocsp_validate_cert(struct iked *env, struct iked_static_id *id, TAILQ_INSERT_TAIL(&env->sc_ocsp, ioe, ioe_entry); /* request connection to ocsp-responder */ - proc_compose_imsg(&env->sc_ps, PROC_PARENT, -1, - IMSG_OCSP_FD, -1, NULL, 0); + proc_compose(&env->sc_ps, PROC_PARENT, IMSG_OCSP_FD, NULL, 0); return (0); err: @@ -504,8 +504,7 @@ ocsp_validate_finish(struct iked_ocsp *ocsp, int valid) iov[1].iov_len = sizeof(ocsp->ocsp_type); cmd = valid ? IMSG_CERTVALID : IMSG_CERTINVALID; - ret = proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, - cmd, -1, iov, iovcnt); + ret = proc_composev(&env->sc_ps, PROC_IKEV2, cmd, iov, iovcnt); ocsp_free(ocsp); return (ret); diff --git a/iked/parse.y b/iked/parse.y index 0d76ff8..c9f6a70 100644 --- a/iked/parse.y +++ b/iked/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.48 2015/07/03 17:46:52 mikeb Exp $ */ +/* $OpenBSD: parse.y,v 1.54 2015/12/09 21:41:49 naddy Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -96,11 +96,11 @@ static char *ocsp_url = NULL; struct ipsec_xf { const char *name; - u_int id; - u_int length; - u_int keylength; - u_int nonce; - u_int noauth; + unsigned int id; + unsigned int length; + unsigned int keylength; + unsigned int nonce; + unsigned int noauth; }; struct ipsec_transforms { @@ -113,7 +113,7 @@ struct ipsec_transforms { struct ipsec_mode { struct ipsec_transforms *xfs; - u_int8_t ike_exch; + uint8_t ike_exch; }; struct iked_transform ikev2_default_ike_transforms[] = { @@ -123,10 +123,8 @@ struct iked_transform ikev2_default_ike_transforms[] = { { IKEV2_XFORMTYPE_ENCR, IKEV2_XFORMENCR_3DES }, { IKEV2_XFORMTYPE_PRF, IKEV2_XFORMPRF_HMAC_SHA2_256 }, { IKEV2_XFORMTYPE_PRF, IKEV2_XFORMPRF_HMAC_SHA1 }, - { IKEV2_XFORMTYPE_PRF, IKEV2_XFORMPRF_HMAC_MD5 }, { IKEV2_XFORMTYPE_INTEGR, IKEV2_XFORMAUTH_HMAC_SHA2_256_128 }, { IKEV2_XFORMTYPE_INTEGR, IKEV2_XFORMAUTH_HMAC_SHA1_96 }, - { IKEV2_XFORMTYPE_INTEGR, IKEV2_XFORMAUTH_HMAC_MD5_96 }, { IKEV2_XFORMTYPE_DH, IKEV2_XFORMDH_MODP_2048_256 }, { IKEV2_XFORMTYPE_DH, IKEV2_XFORMDH_MODP_2048 }, { IKEV2_XFORMTYPE_DH, IKEV2_XFORMDH_MODP_1536 }, @@ -179,7 +177,6 @@ const struct ipsec_xf ikeencxfs[] = { }; const struct ipsec_xf ipsecencxfs[] = { - { "des", IKEV2_XFORMENCR_DES, 8 }, { "3des", IKEV2_XFORMENCR_3DES, 24 }, { "3des-cbc", IKEV2_XFORMENCR_3DES, 24 }, { "aes-128", IKEV2_XFORMENCR_AES_CBC, 16, 16 }, @@ -196,6 +193,8 @@ const struct ipsec_xf ipsecencxfs[] = { { "aes-256-gmac", IKEV2_XFORMENCR_NULL_AES_GMAC, 32, 32, 4, 1 }, { "blowfish", IKEV2_XFORMENCR_BLOWFISH, 20, 20 }, { "cast", IKEV2_XFORMENCR_CAST, 16, 16 }, + { "chacha20-poly1305", IKEV2_XFORMENCR_CHACHA20_POLY1305, + 32, 32, 4, 1 }, { "null", IKEV2_XFORMENCR_NULL, 0, 0 }, { NULL } }; @@ -254,7 +253,7 @@ const struct ipsec_xf methodxfs[] = { { "dss", IKEV2_AUTH_DSS_SIG }, { "ecdsa-256", IKEV2_AUTH_ECDSA_256 }, { "ecdsa-384", IKEV2_AUTH_ECDSA_384 }, - { "ecdsa-512", IKEV2_AUTH_ECDSA_512 }, + { "ecdsa-521", IKEV2_AUTH_ECDSA_521 }, { NULL } }; @@ -288,11 +287,11 @@ const struct iked_lifetime deflifetime = { struct ipsec_addr_wrap { struct sockaddr_storage address; - u_int8_t mask; + uint8_t mask; int netaddress; sa_family_t af; - u_int type; - u_int action; + unsigned int type; + unsigned int action; char *name; struct ipsec_addr_wrap *next; struct ipsec_addr_wrap *tail; @@ -302,13 +301,13 @@ struct ipsec_addr_wrap { struct ipsec_hosts { struct ipsec_addr_wrap *src; struct ipsec_addr_wrap *dst; - u_int16_t sport; - u_int16_t dport; + uint16_t sport; + uint16_t dport; }; struct ipsec_filters { - char *tag; - u_int tap; + char *tag; + unsigned int tap; }; struct ipsec_addr_wrap *host(const char *); @@ -321,23 +320,25 @@ void ifa_load(void); int ifa_exists(const char *); struct ipsec_addr_wrap *ifa_lookup(const char *ifa_name); struct ipsec_addr_wrap *ifa_grouplookup(const char *); -void set_ipmask(struct ipsec_addr_wrap *, u_int8_t); -const struct ipsec_xf *parse_xf(const char *, u_int, const struct ipsec_xf *); -const char *print_xf(u_int, u_int, const struct ipsec_xf *); -void copy_transforms(u_int, const struct ipsec_xf *, +void set_ipmask(struct ipsec_addr_wrap *, uint8_t); +const struct ipsec_xf *parse_xf(const char *, unsigned int, + const struct ipsec_xf *); +const char *print_xf(unsigned int, unsigned int, + const struct ipsec_xf *); +void copy_transforms(unsigned int, const struct ipsec_xf *, const struct ipsec_xf *, struct iked_transform *, size_t, - u_int *, struct iked_transform *, size_t); -int create_ike(char *, int, u_int8_t, struct ipsec_hosts *, - struct ipsec_hosts *, struct ipsec_mode *, - struct ipsec_mode *, u_int8_t, - u_int8_t, char *, char *, - u_int32_t, struct iked_lifetime *, - struct iked_auth *, struct ipsec_filters *, - struct ipsec_addr_wrap *); + unsigned int *, struct iked_transform *, size_t); +int create_ike(char *, int, uint8_t, struct ipsec_hosts *, + struct ipsec_hosts *, struct ipsec_mode *, + struct ipsec_mode *, uint8_t, + uint8_t, char *, char *, + uint32_t, struct iked_lifetime *, + struct iked_auth *, struct ipsec_filters *, + struct ipsec_addr_wrap *); int create_user(const char *, const char *); int get_id_type(char *); -u_int8_t x2i(unsigned char *); +uint8_t x2i(unsigned char *); int parsekey(unsigned char *, size_t, struct iked_auth *); int parsekeyfile(char *, struct iked_auth *); @@ -347,12 +348,12 @@ struct ipsec_filters *ipsec_filters; typedef struct { union { int64_t number; - u_int8_t ikemode; - u_int8_t dir; - u_int8_t satype; - u_int8_t proto; + uint8_t ikemode; + uint8_t dir; + uint8_t satype; + uint8_t proto; char *string; - u_int16_t port; + uint16_t port; struct ipsec_hosts *hosts; struct ipsec_hosts peers; struct ipsec_addr_wrap *anyhost; @@ -363,7 +364,7 @@ typedef struct { char *dstid; } ids; char *id; - u_int8_t type; + uint8_t type; struct iked_lifetime lifetime; struct iked_auth ikeauth; struct iked_auth ikekey; @@ -457,9 +458,11 @@ user : USER STRING STRING { ; ikev2rule : IKEV2 name ikeflags satype af proto hosts_list peers - ike_sa child_sa ids ikelifetime lifetime ikeauth ikecfg filters { + ike_sa child_sa ids ikelifetime lifetime ikeauth ikecfg + filters { if (create_ike($2, $5, $6, $7, &$8, $9, $10, $4, $3, - $11.srcid, $11.dstid, $12, &$13, &$14, $16, $15) == -1) + $11.srcid, $11.dstid, $12, &$13, &$14, + $16, $15) == -1) YYERROR; } ; @@ -654,7 +657,7 @@ host_spec : STRING { | STRING '/' NUMBER { char *buf; - if (asprintf(&buf, "%s/%lld", $1, (long long)$3) == -1) + if (asprintf(&buf, "%s/%lld", $1, $3) == -1) err(1, "host: asprintf"); free($1); if (($$ = host(buf)) == NULL) { @@ -667,7 +670,7 @@ host_spec : STRING { ; host : host_spec { $$ = $1; } - | host_spec '(' host_spec ')' { + | host_spec '(' host_spec ')' { if (($1->af != AF_UNSPEC) && ($3->af != AF_UNSPEC) && ($3->af != $1->af)) { yyerror("Flow NAT address family mismatch"); @@ -809,19 +812,17 @@ ipcomp : /* empty */ { $$ = 0; } ikeauth : /* empty */ { $$.auth_method = IKEV2_AUTH_RSA_SIG; $$.auth_length = 0; - $$.auth_eap = 0; } | RSA { $$.auth_method = IKEV2_AUTH_RSA_SIG; $$.auth_length = 0; - $$.auth_eap = 0; } | PSK keyspec { memcpy(&$$, &$2, sizeof($$)); $$.auth_method = IKEV2_AUTH_SHARED_KEY_MIC; } | EAP STRING { - u_int i; + unsigned int i; for (i = 0; i < strlen($2); i++) if ($2[i] == '-') @@ -844,10 +845,10 @@ byte_spec : NUMBER { $$ = $1; } | STRING { - uintmax_t bytes = 0; + uint64_t bytes = 0; char unit = 0; - if (sscanf($1, "%ju%c", &bytes, &unit) != 2) { + if (sscanf($1, "%llu%c", &bytes, &unit) != 2) { yyerror("invalid byte specification: %s", $1); YYERROR; } @@ -873,10 +874,10 @@ time_spec : NUMBER { $$ = $1; } | STRING { - uintmax_t seconds = 0; + uint64_t seconds = 0; char unit = 0; - if (sscanf($1, "%ju%c", &seconds, &unit) != 2) { + if (sscanf($1, "%llu%c", &seconds, &unit) != 2) { yyerror("invalid time specification: %s", $1); YYERROR; } @@ -916,14 +917,14 @@ ikelifetime : /* empty */ { } keyspec : STRING { - char *hex; + uint8_t *hex; bzero(&$$, sizeof($$)); hex = $1; if (strncmp(hex, "0x", 2) == 0) { hex += 2; - if (parsekey((u_char *)hex, strlen(hex), &$$)) { + if (parsekey(hex, strlen(hex), &$$) != 0) { free($1); YYERROR; } @@ -933,7 +934,7 @@ keyspec : STRING { free($1); YYERROR; } - strlcpy((char *)$$.auth_data, $1, + strlcpy($$.auth_data, $1, sizeof($$.auth_data)); $$.auth_length = strlen($1); } @@ -1140,10 +1141,10 @@ lookup(char *s) #define MAXPUSHBACK 128 -u_char *parsebuf; -int parseindex; -u_char pushback_buffer[MAXPUSHBACK]; -int pushback_index = 0; +unsigned char *parsebuf; +int parseindex; +unsigned char pushback_buffer[MAXPUSHBACK]; +int pushback_index = 0; int lgetc(int quotec) @@ -1166,7 +1167,8 @@ lgetc(int quotec) if (quotec) { if ((c = getc(file->stream)) == EOF) { - yyerror("reached end of file while parsing quoted string"); + yyerror("reached end of file while parsing " + "quoted string"); if (popfile() == EOF) return (EOF); return (quotec); @@ -1234,10 +1236,10 @@ findeol(void) int yylex(void) { - char buf[8096]; - char *p, *val; - int quotec, next, c; - int token; + unsigned char buf[8096]; + unsigned char *p, *val; + int quotec, next, c; + int token; top: p = buf; @@ -1270,7 +1272,7 @@ top: yyerror("macro '%s' not defined", buf); return (findeol()); } - parsebuf = (u_char *)val; + parsebuf = val; parseindex = 0; goto top; } @@ -1576,7 +1578,7 @@ symget(const char *nam) return (NULL); } -u_int8_t +uint8_t x2i(unsigned char *s) { char ss[3]; @@ -1589,13 +1591,13 @@ x2i(unsigned char *s) yyerror("keys need to be specified in hex digits"); return (-1); } - return ((u_int8_t)strtoul(ss, NULL, 16)); + return ((uint8_t)strtoul(ss, NULL, 16)); } int parsekey(unsigned char *hexkey, size_t len, struct iked_auth *auth) { - u_int i; + unsigned int i; bzero(auth, sizeof(*auth)); if ((len / 2) > sizeof(auth->auth_data)) @@ -2054,7 +2056,7 @@ ifa_lookup(const char *ifa_name) { struct ipsec_addr_wrap *p = NULL, *h = NULL, *n = NULL; struct sockaddr_in6 *in6; - u_int8_t *s6; + uint8_t *s6; if (iftab == NULL) ifa_load(); @@ -2079,11 +2081,11 @@ ifa_lookup(const char *ifa_name) break; case AF_INET6: in6 = (struct sockaddr_in6 *)&n->address; - s6 = (u_int8_t *)&in6->sin6_addr.s6_addr; + s6 = (uint8_t *)&in6->sin6_addr.s6_addr; /* route/show.c and bgpd/util.c give KAME credit */ if (IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) { - u_int16_t tmp16; + uint16_t tmp16; /* for now we can not handle link local, * therefore bail for now @@ -2116,13 +2118,13 @@ ifa_lookup(const char *ifa_name) } void -set_ipmask(struct ipsec_addr_wrap *address, u_int8_t b) +set_ipmask(struct ipsec_addr_wrap *address, uint8_t b) { address->mask = b; } const struct ipsec_xf * -parse_xf(const char *name, u_int length, const struct ipsec_xf xfs[]) +parse_xf(const char *name, unsigned int length, const struct ipsec_xf xfs[]) { int i; @@ -2136,7 +2138,7 @@ parse_xf(const char *name, u_int length, const struct ipsec_xf xfs[]) } const char * -print_xf(u_int id, u_int length, const struct ipsec_xf xfs[]) +print_xf(unsigned int id, unsigned int length, const struct ipsec_xf xfs[]) { int i; @@ -2150,7 +2152,7 @@ print_xf(u_int id, u_int length, const struct ipsec_xf xfs[]) } size_t -keylength_xf(u_int saproto, u_int type, u_int id) +keylength_xf(unsigned int saproto, unsigned int type, unsigned int id) { int i; const struct ipsec_xf *xfs; @@ -2177,7 +2179,7 @@ keylength_xf(u_int saproto, u_int type, u_int id) } size_t -noncelength_xf(u_int type, u_int id) +noncelength_xf(unsigned int type, unsigned int id) { const struct ipsec_xf *xfs = ipsecencxfs; int i; @@ -2204,7 +2206,7 @@ print_policy(struct iked_policy *pol) struct iked_transform *xform; struct iked_flow *flow; struct iked_cfg *cfg; - u_int i, j; + unsigned int i, j; const struct ipsec_xf *xfs = NULL; print_verbose("ikev2"); @@ -2336,8 +2338,7 @@ print_policy(struct iked_policy *pol) print_verbose(" ikelifetime %u", pol->pol_rekey); print_verbose(" lifetime %llu bytes %llu", - (unsigned long long)pol->pol_lifetime.lt_seconds, - (unsigned long long)pol->pol_lifetime.lt_bytes); + pol->pol_lifetime.lt_seconds, pol->pol_lifetime.lt_bytes); if (pol->pol_auth.auth_method == IKEV2_AUTH_SHARED_KEY_MIC) { print_verbose(" psk 0x"); @@ -2371,12 +2372,12 @@ print_policy(struct iked_policy *pol) } void -copy_transforms(u_int type, const struct ipsec_xf *xf, +copy_transforms(unsigned int type, const struct ipsec_xf *xf, const struct ipsec_xf *xfs, struct iked_transform *dst, size_t ndst, - u_int *n, struct iked_transform *src, size_t nsrc) + unsigned int *n, struct iked_transform *src, size_t nsrc) { - u_int i; + unsigned int i; struct iked_transform *a, *b; if (xf != NULL) { @@ -2403,23 +2404,23 @@ copy_transforms(u_int type, const struct ipsec_xf *xf, } int -create_ike(char *name, int af, u_int8_t ipproto, struct ipsec_hosts *hosts, +create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, struct ipsec_hosts *peers, struct ipsec_mode *ike_sa, - struct ipsec_mode *ipsec_sa, u_int8_t saproto, - u_int8_t flags, char *srcid, char *dstid, - u_int32_t ikelifetime, struct iked_lifetime *lt, + struct ipsec_mode *ipsec_sa, uint8_t saproto, + uint8_t flags, char *srcid, char *dstid, + uint32_t ikelifetime, struct iked_lifetime *lt, struct iked_auth *authtype, struct ipsec_filters *filter, struct ipsec_addr_wrap *ikecfg) { char idstr[IKED_ID_SIZE]; - u_int idtype = IKEV2_ID_NONE; + unsigned int idtype = IKEV2_ID_NONE; struct ipsec_addr_wrap *ipa, *ipb; struct iked_policy pol; struct iked_proposal prop[2]; - u_int j; + unsigned int j; struct iked_transform ikexforms[64], ipsecxforms[64]; struct iked_flow flows[64]; - static u_int policy_id = 0; + static unsigned int policy_id = 0; struct iked_cfg *cfg; bzero(&pol, sizeof(pol)); diff --git a/iked/pfkey.c b/iked/pfkey.c index 346b6dc..d8caef2 100644 --- a/iked/pfkey.c +++ b/iked/pfkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfkey.c,v 1.43 2015/07/17 14:48:17 mikeb Exp $ */ +/* $OpenBSD: pfkey.c,v 1.51 2016/03/07 19:33:26 mmcc Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -47,12 +47,12 @@ #define ROUNDUP(x) (((x) + (PFKEYV2_CHUNK - 1)) & ~(PFKEYV2_CHUNK - 1)) #define IOV_CNT 20 -#define PFKEYV2_CHUNK sizeof(u_int64_t) +#define PFKEYV2_CHUNK sizeof(uint64_t) #define PFKEY_REPLY_TIMEOUT 1000 -static u_int32_t sadb_msg_seq = 0; -static u_int sadb_decoupled = 0; -static u_int sadb_ipv6refcnt = 0; +static uint32_t sadb_msg_seq = 0; +static unsigned int sadb_decoupled = 0; +static unsigned int sadb_ipv6refcnt = 0; static int pfkey_blockipv6 = 0; static struct event pfkey_timer_ev; @@ -141,20 +141,20 @@ static const struct pfkey_constmap pfkey_satype[] = { { 0 } }; -int pfkey_map(const struct pfkey_constmap *, u_int16_t, u_int8_t *); -int pfkey_flow(int, u_int8_t, u_int8_t, struct iked_flow *); -int pfkey_sa(int, u_int8_t, u_int8_t, struct iked_childsa *); -int pfkey_sa_getspi(int, u_int8_t, struct iked_childsa *, u_int32_t *); -int pfkey_sagroup(int, u_int8_t, u_int8_t, +int pfkey_map(const struct pfkey_constmap *, uint16_t, uint8_t *); +int pfkey_flow(int, uint8_t, uint8_t, struct iked_flow *); +int pfkey_sa(int, uint8_t, uint8_t, struct iked_childsa *); +int pfkey_sa_getspi(int, uint8_t, struct iked_childsa *, uint32_t *); +int pfkey_sagroup(int, uint8_t, uint8_t, struct iked_childsa *, struct iked_childsa *); int pfkey_write(int, struct sadb_msg *, struct iovec *, int, - u_int8_t **, ssize_t *); -int pfkey_reply(int, u_int8_t **, ssize_t *); + uint8_t **, ssize_t *); +int pfkey_reply(int, uint8_t **, ssize_t *); void pfkey_dispatch(int, short, void *); struct sadb_ident * - pfkey_id2ident(struct iked_id *, u_int); -void *pfkey_find_ext(u_int8_t *, ssize_t, int); + pfkey_id2ident(struct iked_id *, unsigned int); +void *pfkey_find_ext(uint8_t *, ssize_t, int); void pfkey_timer_cb(int, short, void *); int pfkey_process(struct iked *, struct pfkey_message *); @@ -201,7 +201,7 @@ pfkey_couple(int sd, struct iked_sas *sas, int couple) } int -pfkey_map(const struct pfkey_constmap *map, u_int16_t alg, u_int8_t *pfkalg) +pfkey_map(const struct pfkey_constmap *map, uint16_t alg, uint8_t *pfkalg) { int i; @@ -214,7 +214,7 @@ pfkey_map(const struct pfkey_constmap *map, u_int16_t alg, u_int8_t *pfkalg) } int -pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) +pfkey_flow(int sd, uint8_t satype, uint8_t action, struct iked_flow *flow) { #if defined(_OPENBSD_IPSEC_API_VERSION) struct sadb_msg smsg; @@ -222,22 +222,19 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) sa_dmask; struct sadb_protocol sa_flowtype, sa_protocol; struct sadb_ident *sa_srcid, *sa_dstid; - struct sockaddr_storage ssrc, sdst, slocal, speer, smask, dmask; + struct sockaddr_storage ssrc, sdst, slocal, speer, smask, dmask; struct iovec iov[IOV_CNT]; int iov_cnt, ret = -1; - in_port_t sport, dport; - sport = dport = 0; sa_srcid = sa_dstid = NULL; bzero(&ssrc, sizeof(ssrc)); bzero(&smask, sizeof(smask)); memcpy(&ssrc, &flow->flow_src.addr, sizeof(ssrc)); memcpy(&smask, &flow->flow_src.addr, sizeof(smask)); - if ((sport = flow->flow_src.addr_port) != 0) - dport = 0xffff; - socket_af((struct sockaddr *)&ssrc, sport); - socket_af((struct sockaddr *)&smask, dport); + socket_af((struct sockaddr *)&ssrc, flow->flow_src.addr_port); + socket_af((struct sockaddr *)&smask, flow->flow_src.addr_port ? + 0xffff : 0); switch (flow->flow_src.addr_af) { case AF_INET: @@ -248,8 +245,9 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) case AF_INET6: prefixlen2mask6(flow->flow_src.addr_net ? flow->flow_src.addr_mask : 128, - (u_int32_t *)((struct sockaddr_in6 *) + (uint32_t *)((struct sockaddr_in6 *) &smask)->sin6_addr.s6_addr); + break; default: log_warnx("%s: unsupported address family %d", __func__, flow->flow_src.addr_af); @@ -261,10 +259,9 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) bzero(&dmask, sizeof(dmask)); memcpy(&sdst, &flow->flow_dst.addr, sizeof(sdst)); memcpy(&dmask, &flow->flow_dst.addr, sizeof(dmask)); - if ((sport = flow->flow_dst.addr_port) != 0) - dport = 0xffff; - socket_af((struct sockaddr *)&sdst, sport); - socket_af((struct sockaddr *)&dmask, dport); + socket_af((struct sockaddr *)&sdst, flow->flow_dst.addr_port); + socket_af((struct sockaddr *)&dmask, flow->flow_dst.addr_port ? + 0xffff : 0); switch (flow->flow_dst.addr_af) { case AF_INET: @@ -275,7 +272,7 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) case AF_INET6: prefixlen2mask6(flow->flow_dst.addr_net ? flow->flow_dst.addr_mask : 128, - (u_int32_t *)((struct sockaddr_in6 *) + (uint32_t *)((struct sockaddr_in6 *) &dmask)->sin6_addr.s6_addr); break; default: @@ -324,7 +321,6 @@ pfkey_flow(int sd, u_int8_t satype, u_int8_t action, struct iked_flow *flow) bzero(&sa_smask, sizeof(sa_smask)); sa_smask.sadb_address_exttype = SADB_X_EXT_SRC_MASK; - sa_smask.sadb_address_len = sa_smask.sadb_address_len = (sizeof(sa_smask) + ROUNDUP(smask.ss_len)) / 8; @@ -702,7 +698,7 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) bzero(&ssrc, sizeof(ssrc)); memcpy(&ssrc, &sa->csa_local->addr, sizeof(ssrc)); if (socket_af((struct sockaddr *)&ssrc, 0) == -1) { - log_warn("%s: invalid address", __func__); + log_warn("%s: invalid address", __func__); return (-1); } @@ -826,7 +822,7 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) return (-1); } - if (sa->csa_encrid != 0) + if (sa->csa_encrid) if (pfkey_map(pfkey_encr, sa->csa_encrid, &sadb.sadb_sa_encrypt) == -1) { log_warnx("%s: unsupported encryption algorithm %s", @@ -963,7 +959,8 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) iov[iov_cnt].iov_base = &sa_authkey; iov[iov_cnt].iov_len = sizeof(sa_authkey); iov_cnt++; - iov[iov_cnt].iov_base = ibuf_data(sa->csa_integrkey); iov[iov_cnt].iov_len = + iov[iov_cnt].iov_base = ibuf_data(sa->csa_integrkey); + iov[iov_cnt].iov_len = ((ibuf_size(sa->csa_integrkey) + 7) / 8) * 8; smsg.sadb_msg_len += sa_authkey.sadb_key_len; iov_cnt++; @@ -1018,10 +1015,10 @@ pfkey_sa_last_used(int sd, struct iked_childsa *sa, u_int64_t *last_used) struct sadb_lifetime *sa_life; struct sockaddr_storage ssrc, sdst; struct iovec iov[IOV_CNT]; - u_int8_t *data; + uint8_t *data; ssize_t n; int iov_cnt, ret = -1; - u_int8_t satype; + uint8_t satype; *last_used = 0; @@ -1132,7 +1129,7 @@ pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, struct sadb_spirange sa_spirange; struct sockaddr_storage ssrc, sdst; struct iovec iov[IOV_CNT]; - u_int8_t *data; + uint8_t *data; ssize_t n; int iov_cnt, ret = -1; @@ -1162,7 +1159,8 @@ pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, sa_spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE; sa_spirange.sadb_spirange_len = sizeof(sa_spirange) / 8; sa_spirange.sadb_spirange_min = 0x100; - sa_spirange.sadb_spirange_max = 0xffffffff; + sa_spirange.sadb_spirange_max = (satype == SADB_X_SATYPE_IPCOMP) ? + (CPI_PRIVATE_MIN - 1) : 0xffffffff; sa_spirange.sadb_spirange_reserved = 0; bzero(&sa_src, sizeof(sa_src)); @@ -1241,7 +1239,7 @@ pfkey_sagroup(int sd, u_int8_t satype1, u_int8_t action, struct sadb_protocol sa_proto; struct iovec iov[IOV_CNT]; int iov_cnt; - u_int8_t satype2; + uint8_t satype2; if (pfkey_map(pfkey_satype, sa2->csa_saproto, &satype2) == -1) return (-1); @@ -1377,12 +1375,12 @@ pfkey_write(int sd, struct sadb_msg *smsg, struct iovec *iov, int iov_cnt, } int -pfkey_reply(int sd, u_int8_t **datap, ssize_t *lenp) +pfkey_reply(int sd, uint8_t **datap, ssize_t *lenp) { struct pfkey_message *pm; struct sadb_msg hdr; ssize_t len; - u_int8_t *data; + uint8_t *data; struct pollfd pfd[1]; int n; @@ -1432,12 +1430,12 @@ pfkey_reply(int sd, u_int8_t **datap, ssize_t *lenp) /* XXX: Only one message can be outstanding. */ if (hdr.sadb_msg_seq == sadb_msg_seq && - hdr.sadb_msg_pid == (u_int32_t)getpid()) + hdr.sadb_msg_pid == (uint32_t)getpid()) break; /* ignore messages for other processes */ if (hdr.sadb_msg_pid != 0 && - hdr.sadb_msg_pid != (u_int32_t)getpid()) { + hdr.sadb_msg_pid != (uint32_t)getpid()) { free(data); continue; } @@ -1474,7 +1472,7 @@ pfkey_reply(int sd, u_int8_t **datap, ssize_t *lenp) int pfkey_flow_add(int fd, struct iked_flow *flow) { - u_int8_t satype; + uint8_t satype; if (flow->flow_loaded) return (0); @@ -1499,7 +1497,7 @@ pfkey_flow_add(int fd, struct iked_flow *flow) int pfkey_flow_delete(int fd, struct iked_flow *flow) { - u_int8_t satype; + uint8_t satype; if (!flow->flow_loaded) return (0); @@ -1522,7 +1520,7 @@ pfkey_flow_delete(int fd, struct iked_flow *flow) } int -pfkey_block(int fd, int af, u_int action) +pfkey_block(int fd, int af, unsigned int action) { struct iked_flow flow; @@ -1531,7 +1529,7 @@ pfkey_block(int fd, int af, u_int action) /* * Prevent VPN traffic leakages in dual-stack hosts/networks. - * http://tools.ietf.org/html/draft-gont-opsec-vpn-leakages. + * https://tools.ietf.org/html/draft-gont-opsec-vpn-leakages. * We forcibly block IPv6 traffic unless it is used in any of * the flows by tracking a sadb_ipv6refcnt reference counter. */ @@ -1552,9 +1550,9 @@ pfkey_block(int fd, int af, u_int action) } int -pfkey_sa_init(int fd, struct iked_childsa *sa, u_int32_t *spi) +pfkey_sa_init(int fd, struct iked_childsa *sa, uint32_t *spi) { - u_int8_t satype; + uint8_t satype; if (pfkey_map(pfkey_satype, sa->csa_saproto, &satype) == -1) return (-1); @@ -1570,8 +1568,8 @@ pfkey_sa_init(int fd, struct iked_childsa *sa, u_int32_t *spi) int pfkey_sa_add(int fd, struct iked_childsa *sa, struct iked_childsa *last) { - u_int8_t satype; - u_int cmd; + uint8_t satype; + unsigned int cmd; if (pfkey_map(pfkey_satype, sa->csa_saproto, &satype) == -1) return (-1); @@ -1617,7 +1615,7 @@ pfkey_sa_add(int fd, struct iked_childsa *sa, struct iked_childsa *last) int pfkey_sa_delete(int fd, struct iked_childsa *sa) { - u_int8_t satype; + uint8_t satype; if (!sa->csa_loaded || sa->csa_spi.spi == 0) return (0); @@ -1657,10 +1655,10 @@ pfkey_flush(int sd) } struct sadb_ident * -pfkey_id2ident(struct iked_id *id, u_int exttype) +pfkey_id2ident(struct iked_id *id, unsigned int exttype) { char idstr[IKED_ID_SIZE]; - u_int type; + unsigned int type; size_t len; struct sadb_ident *sa_id; @@ -1773,15 +1771,15 @@ pfkey_init(struct iked *env, int fd) } void * -pfkey_find_ext(u_int8_t *data, ssize_t len, int type) +pfkey_find_ext(uint8_t *data, ssize_t len, int type) { struct sadb_ext *ext = (struct sadb_ext *)(data + sizeof(struct sadb_msg)); - while (ext && ((u_int8_t *)ext - data < len)) { + while (ext && ((uint8_t *)ext - data < len)) { if (ext->sadb_ext_type == type) return (ext); - ext = (struct sadb_ext *)((u_int8_t *)ext + + ext = (struct sadb_ext *)((uint8_t *)ext + ext->sadb_ext_len * PFKEYV2_CHUNK); } @@ -1795,7 +1793,7 @@ pfkey_dispatch(int sd, short event, void *arg) struct pfkey_message pm, *pmp; struct sadb_msg hdr; ssize_t len; - u_int8_t *data; + uint8_t *data; if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) { log_warn("%s: short recv", __func__); @@ -1903,6 +1901,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) return 0; hdr = (struct sadb_msg *)data; + sd = env->sc_pfkey; switch (hdr->sadb_msg_type) { case SADB_ACQUIRE: diff --git a/iked/policy.c b/iked/policy.c index 7bd5e18..36d0bbd 100644 --- a/iked/policy.c +++ b/iked/policy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: policy.c,v 1.37 2015/07/07 19:13:31 markus Exp $ */ +/* $OpenBSD: policy.c,v 1.42 2016/06/01 11:16:41 patrick Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -22,9 +22,9 @@ #include -#include #include #include +#include #include #include #include @@ -48,6 +48,7 @@ void policy_init(struct iked *env) { TAILQ_INIT(&env->sc_policies); + TAILQ_INIT(&env->sc_ocsp); RB_INIT(&env->sc_users); RB_INIT(&env->sc_sas); RB_INIT(&env->sc_activesas); @@ -76,7 +77,7 @@ policy_lookup(struct iked *env, struct iked_message *msg) (s = strchr(idstr, '/')) != NULL) { pol.pol_peerid.id_type = msg->msg_id.id_type; pol.pol_peerid.id_length = strlen(s+1); - strlcpy((char *)pol.pol_peerid.id_data, s+1, + strlcpy(pol.pol_peerid.id_data, s+1, sizeof(pol.pol_peerid.id_data)); log_debug("%s: peerid '%s'", __func__, s+1); } @@ -99,19 +100,23 @@ policy_lookup(struct iked *env, struct iked_message *msg) /* * Check if host is in a subnet */ -bool is_in_subnet(struct sockaddr_in* host, struct sockaddr_in* subnet, - u_int8_t subnet_mask) { +bool +is_in_subnet(struct sockaddr_in* host, struct sockaddr_in* subnet, + uint8_t subnet_mask) +{ uint32_t host_addr = ntohl(host->sin_addr.s_addr); uint32_t subnet_addr = ntohl(subnet->sin_addr.s_addr); - unsigned int mask = 0xFFFFFFFF << (32 - subnet_mask); + return ((host_addr & mask) == (subnet_addr & mask)); } -bool isipv4_flow_and_policy(struct iked_addr fsrc, struct iked_addr fdst, - struct iked_addr psrc, struct iked_addr pdst) { +bool +isipv4_flow_and_policy(struct iked_addr fsrc, struct iked_addr fdst, + struct iked_addr psrc, struct iked_addr pdst) +{ return (fsrc.addr_af == AF_INET) && (fdst.addr_af == AF_INET) && - (psrc.addr_af == AF_INET) && (pdst.addr_af == AF_INET); + (psrc.addr_af == AF_INET) && (pdst.addr_af == AF_INET); } /* @@ -119,17 +124,18 @@ bool isipv4_flow_and_policy(struct iked_addr fsrc, struct iked_addr fdst, * This routinue checks if an incoming flow matches a preconfigured * policy in the config */ -bool flow_matches_policy(struct iked_addr fsrc, struct iked_addr fdst, - struct iked_addr psrc, struct iked_addr pdst) { - +bool +flow_matches_policy(struct iked_addr fsrc, struct iked_addr fdst, + struct iked_addr psrc, struct iked_addr pdst) +{ struct sockaddr_in *fsrc_addr, *psrc_addr, *fdst_addr, *pdst_addr; fsrc_addr = (struct sockaddr_in*)&(fsrc.addr); psrc_addr = (struct sockaddr_in*)&(psrc.addr); fdst_addr = (struct sockaddr_in*)&(fdst.addr); pdst_addr = (struct sockaddr_in*)&(pdst.addr); return (isipv4_flow_and_policy(fsrc, fdst, psrc, pdst) && - is_in_subnet(fsrc_addr, psrc_addr, psrc.addr_mask) && - is_in_subnet(fdst_addr, pdst_addr, pdst.addr_mask)); + is_in_subnet(fsrc_addr, psrc_addr, psrc.addr_mask) && + is_in_subnet(fdst_addr, pdst_addr, pdst.addr_mask)); } struct iked_policy * @@ -166,7 +172,7 @@ policy_test(struct iked *env, struct iked_policy *key) */ if (key->pol_nflows && (flowkey = RB_MIN(iked_flows, - &key->pol_flows)) != NULL) { + &key->pol_flows)) != NULL) { bool match = false; struct iked_addr psrc, pdst, fsrc, fdst; /* @@ -175,19 +181,19 @@ policy_test(struct iked *env, struct iked_policy *key) * or rules specified in iked.conf */ RB_FOREACH(flow, iked_flows, &p->pol_flows) { - psrc = flow->flow_src; - pdst = flow->flow_dst; - fsrc = flowkey->flow_src; - fdst = flowkey->flow_dst; - if (flow_matches_policy(fsrc, fdst, - psrc, pdst)) { - match = true; - break; - } + psrc = flow->flow_src; + pdst = flow->flow_dst; + fsrc = flowkey->flow_src; + fdst = flowkey->flow_dst; + if (flow_matches_policy(fsrc, fdst, + psrc, pdst)) { + match = true; + break; + } } if (!match) { - p = TAILQ_NEXT(p, pol_entry); - continue; + p = TAILQ_NEXT(p, pol_entry); + continue; } } /* make sure the peer ID matches */ @@ -286,7 +292,7 @@ sa_state(struct iked *env, struct iked_sa *sa, int state) { const char *a; const char *b; - int ostate = sa->sa_state; + int ostate = sa->sa_state; a = print_map(ostate, ikev2_state_map); b = print_map(state, ikev2_state_map); @@ -318,19 +324,19 @@ sa_state(struct iked *env, struct iked_sa *sa, int state) } void -sa_stateflags(struct iked_sa *sa, u_int flags) +sa_stateflags(struct iked_sa *sa, unsigned int flags) { - u_int require; + unsigned int require; if (sa->sa_state > IKEV2_STATE_SA_INIT) require = sa->sa_statevalid; else require = sa->sa_stateinit; - log_debug("%s: 0x%02x -> 0x%02x %s (required 0x%02x %s)", __func__, + log_debug("%s: 0x%04x -> 0x%04x %s (required 0x%04x %s)", __func__, sa->sa_stateflags, sa->sa_stateflags | flags, - print_bits(sa->sa_stateflags | flags, (u_char *)IKED_REQ_BITS), - require, print_bits(require, (u_char *)IKED_REQ_BITS)); + print_bits(sa->sa_stateflags | flags, IKED_REQ_BITS), require, + print_bits(require, IKED_REQ_BITS)); sa->sa_stateflags |= flags; } @@ -338,7 +344,7 @@ sa_stateflags(struct iked_sa *sa, u_int flags) int sa_stateok(struct iked_sa *sa, int state) { - u_int require; + unsigned int require; if (sa->sa_state < state) return (0); @@ -351,10 +357,10 @@ sa_stateok(struct iked_sa *sa, int state) if (state == IKEV2_STATE_SA_INIT || state == IKEV2_STATE_VALID || state == IKEV2_STATE_EAP_VALID) { - log_debug("%s: %s flags 0x%02x, require 0x%02x %s", __func__, + log_debug("%s: %s flags 0x%04x, require 0x%04x %s", __func__, print_map(state, ikev2_state_map), (sa->sa_stateflags & require), require, - print_bits(require, (u_char *)IKED_REQ_BITS)); + print_bits(require, IKED_REQ_BITS)); if ((sa->sa_stateflags & require) != require) return (0); /* not ready, ignore */ @@ -363,13 +369,13 @@ sa_stateok(struct iked_sa *sa, int state) } struct iked_sa * -sa_new(struct iked *env, u_int64_t ispi, u_int64_t rspi, - u_int initiator, struct iked_policy *pol) +sa_new(struct iked *env, uint64_t ispi, uint64_t rspi, + unsigned int initiator, struct iked_policy *pol) { struct iked_sa *sa; struct iked_sa *old; struct iked_id *localid; - u_int diff; + unsigned int diff; if ((ispi == 0 && rspi == 0) || (sa = sa_lookup(env, ispi, rspi, initiator)) == NULL) { @@ -497,7 +503,7 @@ childsa_free(struct iked_childsa *csa) } struct iked_childsa * -childsa_lookup(struct iked_sa *sa, u_int64_t spi, u_int8_t protoid) +childsa_lookup(struct iked_sa *sa, uint64_t spi, uint8_t protoid) { struct iked_childsa *csa; @@ -519,8 +525,8 @@ flow_free(struct iked_flow *flow) } struct iked_sa * -sa_lookup(struct iked *env, u_int64_t ispi, u_int64_t rspi, - u_int initiator) +sa_lookup(struct iked *env, uint64_t ispi, uint64_t rspi, + unsigned int initiator) { struct iked_sa *sa, key; @@ -576,6 +582,13 @@ sa_addrpool_cmp(struct iked_sa *a, struct iked_sa *b) (struct sockaddr *)&b->sa_addrpool->addr, -1)); } +static __inline int +sa_addrpool6_cmp(struct iked_sa *a, struct iked_sa *b) +{ + return (sockaddr_cmp((struct sockaddr *)&a->sa_addrpool6->addr, + (struct sockaddr *)&b->sa_addrpool6->addr, -1)); +} + struct iked_user * user_lookup(struct iked *env, const char *user) { @@ -638,6 +651,7 @@ flow_cmp(struct iked_flow *a, struct iked_flow *b) RB_GENERATE(iked_sas, iked_sa, sa_entry, sa_cmp); RB_GENERATE(iked_addrpool, iked_sa, sa_addrpool_entry, sa_addrpool_cmp); +RB_GENERATE(iked_addrpool6, iked_sa, sa_addrpool6_entry, sa_addrpool6_cmp); RB_GENERATE(iked_users, iked_user, usr_entry, user_cmp); RB_GENERATE(iked_activesas, iked_childsa, csa_node, childsa_cmp); RB_GENERATE(iked_flows, iked_flow, flow_node, flow_cmp); diff --git a/iked/proc.c b/iked/proc.c index 71a9f54..249cb46 100644 --- a/iked/proc.c +++ b/iked/proc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: proc.c,v 1.22 2015/01/16 06:39:58 deraadt Exp $ */ +/* $OpenBSD: proc.c,v 1.29 2015/12/07 16:05:56 reyk Exp $ */ /* * Copyright (c) 2010 - 2014 Reyk Floeter @@ -17,16 +17,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include - -#include -#include -#include -#include - #include #include #include @@ -35,21 +30,24 @@ #include #include #include +#include #include "iked.h" void proc_open(struct privsep *, struct privsep_proc *, struct privsep_proc *, size_t); void proc_close(struct privsep *); -int proc_ispeer(struct privsep_proc *, u_int, enum privsep_procid); +int proc_ispeer(struct privsep_proc *, unsigned int, enum privsep_procid); void proc_shutdown(struct privsep_proc *); void proc_sig_handler(int, short, void *); void proc_range(struct privsep *, enum privsep_procid, int *, int *); +int proc_dispatch_null(int, struct privsep_proc *, struct imsg *); int -proc_ispeer(struct privsep_proc *procs, u_int nproc, enum privsep_procid type) +proc_ispeer(struct privsep_proc *procs, unsigned int nproc, + enum privsep_procid type) { - u_int i; + unsigned int i; for (i = 0; i < nproc; i++) if (procs[i].p_id == type) @@ -58,9 +56,9 @@ proc_ispeer(struct privsep_proc *procs, u_int nproc, enum privsep_procid type) } void -proc_init(struct privsep *ps, struct privsep_proc *procs, u_int nproc) +proc_init(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc) { - u_int i, j, src, dst; + unsigned int i, j, src, dst; struct privsep_pipes *pp; /* @@ -126,7 +124,7 @@ void proc_kill(struct privsep *ps) { pid_t pid; - u_int i; + unsigned int i; if (privsep_process != PROC_PARENT) return; @@ -150,7 +148,7 @@ proc_open(struct privsep *ps, struct privsep_proc *p, { struct privsep_pipes *pa, *pb; int fds[2]; - u_int i, j, src, proc; + unsigned int i, j, src, proc; if (p == NULL) src = privsep_process; /* parent */ @@ -163,6 +161,8 @@ proc_open(struct privsep *ps, struct privsep_proc *p, for (proc = 0; proc < nproc; proc++) { procs[proc].p_ps = ps; procs[proc].p_env = ps->ps_env; + if (procs[proc].p_cb == NULL) + procs[proc].p_cb = proc_dispatch_null; for (i = 0; i < ps->ps_instances[src]; i++) { for (j = 0; j < ps->ps_instances[procs[proc].p_id]; @@ -174,13 +174,11 @@ proc_open(struct privsep *ps, struct privsep_proc *p, if (pa->pp_pipes[procs[proc].p_id][j] != -1) continue; - if (socketpair(AF_UNIX, SOCK_STREAM, + if (socketpair(AF_UNIX, + SOCK_STREAM | SOCK_NONBLOCK, PF_UNSPEC, fds) == -1) fatal("socketpair"); - socket_set_blockmode(fds[0], BM_NONBLOCK); - socket_set_blockmode(fds[1], BM_NONBLOCK); - pa->pp_pipes[procs[proc].p_id][j] = fds[0]; pb->pp_pipes[src][i] = fds[1]; } @@ -191,7 +189,7 @@ proc_open(struct privsep *ps, struct privsep_proc *p, void proc_listen(struct privsep *ps, struct privsep_proc *procs, size_t nproc) { - u_int i, dst, src, n, m; + unsigned int i, dst, src, n, m; struct privsep_pipes *pp; /* @@ -200,7 +198,7 @@ proc_listen(struct privsep *ps, struct privsep_proc *procs, size_t nproc) for (src = 0; src < PROC_MAX; src++) { for (n = 0; n < ps->ps_instances[src]; n++) { /* Ingore current process */ - if (src == (u_int)privsep_process && + if (src == (unsigned int)privsep_process && n == ps->ps_instance) continue; @@ -262,7 +260,7 @@ proc_listen(struct privsep *ps, struct privsep_proc *procs, size_t nproc) void proc_close(struct privsep *ps) { - u_int dst, n; + unsigned int dst, n; struct privsep_pipes *pp; if (ps == NULL) @@ -330,14 +328,14 @@ proc_sig_handler(int sig, short event, void *arg) pid_t proc_run(struct privsep *ps, struct privsep_proc *p, - struct privsep_proc *procs, u_int nproc, - void (*init)(struct privsep *, struct privsep_proc *, void *), void *arg) + struct privsep_proc *procs, unsigned int nproc, + void (*run)(struct privsep *, struct privsep_proc *, void *), void *arg) { pid_t pid; struct passwd *pw; const char *root; struct control_sock *rcs; - u_int n; + unsigned int n; if (ps->ps_noaction) return (0); @@ -349,6 +347,8 @@ proc_run(struct privsep *ps, struct privsep_proc *p, case -1: fatal("proc_run: cannot fork"); case 0: + log_procinit(p->p_title); + /* Set the process group of the current process */ setpgid(0, 0); break; @@ -360,10 +360,10 @@ proc_run(struct privsep *ps, struct privsep_proc *p, if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { if (control_init(ps, &ps->ps_csock) == -1) - fatalx(p->p_title); + fatalx(__func__); TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry) if (control_init(ps, rcs) == -1) - fatalx(p->p_title); + fatalx(__func__); } /* Change root directory */ @@ -420,14 +420,14 @@ proc_run(struct privsep *ps, struct privsep_proc *p, if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { TAILQ_INIT(&ctl_conns); if (control_listen(&ps->ps_csock) == -1) - fatalx(p->p_title); + fatalx(__func__); TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry) if (control_listen(rcs) == -1) - fatalx(p->p_title); + fatalx(__func__); } - if (init != NULL) - init(ps, p, arg); + if (run != NULL) + run(ps, p, arg); event_dispatch(); @@ -452,8 +452,8 @@ proc_dispatch(int fd, short event, void *arg) ibuf = &iev->ibuf; if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1) - fatal(title); + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) + fatal(__func__); if (n == 0) { /* this pipe is dead, so remove the event handler */ event_del(&iev->ev); @@ -464,19 +464,19 @@ proc_dispatch(int fd, short event, void *arg) if (event & EV_WRITE) { if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) - fatal(title); + fatal(__func__); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) - fatal(title); + fatal(__func__); if (n == 0) break; #if DEBUG > 1 - log_debug("%s: %s %d got imsg %d from %s %d", + log_debug("%s: %s %d got imsg %d peerid %d from %s %d", __func__, title, ps->ps_instance + 1, - imsg.hdr.type, p->p_title, p->p_instance); + imsg.hdr.type, imsg.hdr.peerid, p->p_title, p->p_instance); #endif /* @@ -498,16 +498,24 @@ proc_dispatch(int fd, short event, void *arg) log_verbose(verbose); break; default: - log_warnx("%s: %s %d got invalid imsg %d from %s %d", + log_warnx("%s: %s %d got invalid imsg %d peerid %d " + "from %s %d", __func__, title, ps->ps_instance + 1, - imsg.hdr.type, p->p_title, p->p_instance); - fatalx(title); + imsg.hdr.type, imsg.hdr.peerid, + p->p_title, p->p_instance); + fatalx(__func__); } imsg_free(&imsg); } imsg_event_add(iev); } +int +proc_dispatch_null(int fd, struct privsep_proc *p, struct imsg *imsg) +{ + return (-1); +} + /* * imsg helper functions */ @@ -530,8 +538,8 @@ imsg_event_add(struct imsgev *iev) } int -imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, - pid_t pid, int fd, void *data, u_int16_t datalen) +imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, + pid_t pid, int fd, void *data, uint16_t datalen) { int ret; @@ -543,7 +551,7 @@ imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, } int -imsg_composev_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, +imsg_composev_event(struct imsgev *iev, uint16_t type, uint32_t peerid, pid_t pid, int fd, const struct iovec *iov, int iovcnt) { int ret; @@ -570,41 +578,55 @@ proc_range(struct privsep *ps, enum privsep_procid id, int *n, int *m) int proc_compose_imsg(struct privsep *ps, enum privsep_procid id, int n, - u_int16_t type, int fd, void *data, u_int16_t datalen) + uint16_t type, uint32_t peerid, int fd, void *data, uint16_t datalen) { int m; proc_range(ps, id, &n, &m); for (; n < m; n++) { if (imsg_compose_event(&ps->ps_ievs[id][n], - type, -1, 0, fd, data, datalen) == -1) + type, peerid, 0, fd, data, datalen) == -1) return (-1); } return (0); } +int +proc_compose(struct privsep *ps, enum privsep_procid id, + uint16_t type, void *data, uint16_t datalen) +{ + return (proc_compose_imsg(ps, id, -1, type, -1, -1, data, datalen)); +} + int proc_composev_imsg(struct privsep *ps, enum privsep_procid id, int n, - u_int16_t type, int fd, const struct iovec *iov, int iovcnt) + uint16_t type, uint32_t peerid, int fd, const struct iovec *iov, int iovcnt) { int m; proc_range(ps, id, &n, &m); for (; n < m; n++) if (imsg_composev_event(&ps->ps_ievs[id][n], - type, -1, 0, fd, iov, iovcnt) == -1) + type, peerid, 0, fd, iov, iovcnt) == -1) return (-1); return (0); } +int +proc_composev(struct privsep *ps, enum privsep_procid id, + uint16_t type, const struct iovec *iov, int iovcnt) +{ + return (proc_composev_imsg(ps, id, -1, type, -1, -1, iov, iovcnt)); +} + int proc_forward_imsg(struct privsep *ps, struct imsg *imsg, enum privsep_procid id, int n) { return (proc_compose_imsg(ps, id, n, imsg->hdr.type, - imsg->fd, imsg->data, IMSG_DATA_SIZE(imsg))); + imsg->hdr.peerid, imsg->fd, imsg->data, IMSG_DATA_SIZE(imsg))); } struct imsgbuf * diff --git a/iked/smult_curve25519_ref.c b/iked/smult_curve25519_ref.c index 4c65eb5..71c106a 100644 --- a/iked/smult_curve25519_ref.c +++ b/iked/smult_curve25519_ref.c @@ -107,7 +107,7 @@ static void square(unsigned int out[32],const unsigned int a[32]) squeeze(out); } -static void smult_select(unsigned int p[64],unsigned int q[64],const unsigned int r[64],const unsigned int s[64],unsigned int b) +static void select(unsigned int p[64],unsigned int q[64],const unsigned int r[64],const unsigned int s[64],unsigned int b) { unsigned int j; unsigned int t; @@ -152,7 +152,7 @@ static void mainloop(unsigned int work[64],const unsigned char e[32]) for (pos = 254;pos >= 0;--pos) { b = e[pos / 8] >> (pos & 7); b &= 1; - smult_select(xzmb,xzm1b,xzm,xzm1,b); + select(xzmb,xzm1b,xzm,xzm1,b); add(a0,xzmb,xzmb + 32); sub(a0 + 32,xzmb,xzmb + 32); add(a1,xzm1b,xzm1b + 32); @@ -171,7 +171,7 @@ static void mainloop(unsigned int work[64],const unsigned char e[32]) mult(xznb + 32,s,u); square(xzn1b,c1); mult(xzn1b + 32,r,work); - smult_select(xzm,xzm1,xznb,xzn1b,b); + select(xzm,xzm1,xznb,xzn1b,b); } for (j = 0;j < 64;++j) work[j] = xzm[j]; diff --git a/iked/timer.c b/iked/timer.c index 3823b62..3d52291 100644 --- a/iked/timer.c +++ b/iked/timer.c @@ -40,11 +40,6 @@ timer_set(struct iked *env, struct iked_timer *tmr, tmr->tmr_env = env; tmr->tmr_cb = cb; tmr->tmr_cbarg = arg; - - if (evtimer_initialized(&tmr->tmr_ev) && - evtimer_pending(&tmr->tmr_ev, NULL)) { - evtimer_del(&tmr->tmr_ev); - } evtimer_set(&tmr->tmr_ev, timer_callback, tmr); } diff --git a/iked/types.h b/iked/types.h index fd5383c..4648809 100644 --- a/iked/types.h +++ b/iked/types.h @@ -1,4 +1,4 @@ -/* $OpenBSD: types.h,v 1.19 2015/06/11 18:49:09 reyk Exp $ */ +/* $OpenBSD: types.h,v 1.25 2016/01/27 20:20:30 gsoares Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -20,26 +20,28 @@ #define IKED_TYPES_H #ifndef IKED_USER -#define IKED_USER "_iked" +#define IKED_USER "_iked" #endif #ifndef IKED_CONFIG -#define IKED_CONFIG "/etc/iked.conf" +#define IKED_CONFIG "/etc/iked.conf" #endif -#define IKED_SOCKET "/var/run/iked.sock" + +#define IKED_SOCKET "/var/run/iked.sock" #ifndef IKED_CA -#define IKED_CA "/etc/iked/" +#define IKED_CA "/etc/iked/" #endif -#define IKED_CA_DIR "ca/" -#define IKED_CRL_DIR "crls/" -#define IKED_CERT_DIR "certs/" -#define IKED_PUBKEY_DIR "pubkeys/" -#define IKED_PRIVKEY IKED_CA "private/local.key" -#define IKED_PUBKEY "local.pub" -#define IKED_OCSP_RESPCERT "ocsp/responder.crt" -#define IKED_OCSP_ISSUER "ocsp/issuer.crt" +#define IKED_CA_DIR "ca/" +#define IKED_CRL_DIR "crls/" +#define IKED_CERT_DIR "certs/" +#define IKED_PUBKEY_DIR "pubkeys/" +#define IKED_PRIVKEY IKED_CA "private/local.key" +#define IKED_PUBKEY "local.pub" + +#define IKED_OCSP_RESPCERT "ocsp/responder.crt" +#define IKED_OCSP_ISSUER "ocsp/issuer.crt" #define IKED_OPT_VERBOSE 0x00000001 #define IKED_OPT_NOACTION 0x00000002 @@ -54,7 +56,7 @@ #define IKED_NONCE_MIN 16 /* XXX 128 bits */ #define IKED_NONCE_SIZE 32 /* XXX 256 bits */ -#define IKED_ID_SIZE 1024 /* XXX should be dynanic */ +#define IKED_ID_SIZE 1024 /* XXX should be dynamic */ #define IKED_PSK_SIZE 1024 /* XXX should be dynamic */ #define IKED_MSGBUF_MAX 8192 #define IKED_CFG_MAX 16 /* maximum CP attributes */ @@ -68,17 +70,17 @@ #define IKED_E 0x1000 /* Decrypted flag */ struct iked_constmap { - u_int cm_type; + unsigned int cm_type; const char *cm_name; const char *cm_descr; }; struct iked_transform { - u_int8_t xform_type; - u_int16_t xform_id; - u_int16_t xform_length; - u_int16_t xform_keylength; - u_int xform_score; + uint8_t xform_type; + uint16_t xform_id; + uint16_t xform_length; + uint16_t xform_keylength; + unsigned int xform_score; struct iked_constmap *xform_map; }; @@ -111,20 +113,12 @@ enum imsg_type { enum privsep_procid { PROC_PARENT = 0, - PROC_IKEV1, - PROC_IKEV2, + PROC_CONTROL, PROC_CERT, + PROC_IKEV2, PROC_MAX }; -/* Attach the control socket to the following process */ -#define PROC_CONTROL PROC_CERT - -enum blockmodes { - BM_NORMAL, - BM_NONBLOCK -}; - enum flushmode { RESET_RELOAD = 0, RESET_ALL, diff --git a/iked/util.c b/iked/util.c index 6e959ea..8eea67c 100644 --- a/iked/util.c +++ b/iked/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.26 2015/01/16 06:39:58 deraadt Exp $ */ +/* $OpenBSD: util.c,v 1.30 2015/11/23 19:28:34 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -35,22 +35,9 @@ #include "iked.h" #include "ikev2.h" -void -socket_set_blockmode(int fd, enum blockmodes bm) -{ - int flags; - - if ((flags = fcntl(fd, F_GETFL, 0)) == -1) - fatal("fcntl F_GETFL"); - - if (bm == BM_NONBLOCK) - flags |= O_NONBLOCK; - else - flags &= ~O_NONBLOCK; - - if ((flags = fcntl(fd, F_SETFL, flags)) == -1) - fatal("fcntl F_SETFL"); -} +/* log.c */ +extern int debug; +extern int verbose; int socket_af(struct sockaddr *sa, in_port_t port) @@ -150,6 +137,7 @@ socket_bypass(int s, struct sockaddr *sa) log_warn("%s: invalid address family", __func__); return (-1); } + v = IPSEC_LEVEL_BYPASS; if (setsockopt(s, a[0], a[1], &v, sizeof(v)) == -1) { log_warn("%s: AUTH_LEVEL", __func__); @@ -224,7 +212,8 @@ udp_bind(struct sockaddr *sa, in_port_t port) return (-1); } - if ((s = socket(sa->sa_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) { + if ((s = socket(sa->sa_family, + SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP)) == -1) { log_warn("%s: failed to get UDP socket", __func__); return (-1); } @@ -281,7 +270,7 @@ sockaddr_cmp(struct sockaddr *a, struct sockaddr *b, int prefixlen) { struct sockaddr_in *a4, *b4; struct sockaddr_in6 *a6, *b6; - u_int32_t av[4], bv[4], mv[4]; + uint32_t av[4], bv[4], mv[4]; if (a->sa_family == AF_UNSPEC || b->sa_family == AF_UNSPEC) return (0); @@ -410,7 +399,7 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, } const char * -print_spi(u_int64_t spi, int size) +print_spi(uint64_t spi, int size) { static char buf[IKED_CYCLE_BUFFERS][32]; static int i = 0; @@ -420,16 +409,16 @@ print_spi(u_int64_t spi, int size) switch (size) { case 2: - snprintf(ptr, 32, "0x%04x", (u_int16_t)spi); + snprintf(ptr, 32, "0x%04x", (uint16_t)spi); break; case 4: - snprintf(ptr, 32, "0x%08x", (u_int32_t)spi); + snprintf(ptr, 32, "0x%08x", (uint32_t)spi); break; case 8: - snprintf(ptr, 32, "0x%016llx", (unsigned long long)spi); + snprintf(ptr, 32, "0x%016llx", spi); break; default: - snprintf(ptr, 32, "%llu", (unsigned long long)spi); + snprintf(ptr, 32, "%llu", spi); break; } @@ -440,9 +429,9 @@ print_spi(u_int64_t spi, int size) } const char * -print_map(u_int type, struct iked_constmap *map) +print_map(unsigned int type, struct iked_constmap *map) { - u_int i; + unsigned int i; static char buf[IKED_CYCLE_BUFFERS][32]; static int idx = 0; const char *name = NULL; @@ -472,9 +461,9 @@ lc_string(char *str) } void -print_hex(u_int8_t *buf, off_t offset, size_t length) +print_hex(uint8_t *buf, off_t offset, size_t length) { - u_int i; + unsigned int i; extern int verbose; if (verbose < 3 || !length) @@ -493,9 +482,9 @@ print_hex(u_int8_t *buf, off_t offset, size_t length) } void -print_hexval(u_int8_t *buf, off_t offset, size_t length) +print_hexval(uint8_t *buf, off_t offset, size_t length) { - u_int i; + unsigned int i; extern int verbose; if (verbose < 2 || !length) @@ -508,12 +497,12 @@ print_hexval(u_int8_t *buf, off_t offset, size_t length) } const char * -print_bits(u_short v, u_char *bits) +print_bits(unsigned short v, unsigned char *bits) { static char buf[IKED_CYCLE_BUFFERS][BUFSIZ]; static int idx = 0; - u_int i, any = 0, j = 0; - u_char c; + unsigned int i, any = 0, j = 0; + unsigned char c; if (!bits) return (""); @@ -545,7 +534,7 @@ print_bits(u_short v, u_char *bits) return (buf[idx]); } -u_int8_t +uint8_t mask2prefixlen(struct sockaddr *sa) { struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; @@ -557,18 +546,18 @@ mask2prefixlen(struct sockaddr *sa) return (33 - ffs(ntohl(ina))); } -u_int8_t +uint8_t mask2prefixlen6(struct sockaddr *sa) { struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; - u_int8_t l = 0, *ap, *ep; + uint8_t l = 0, *ap, *ep; /* * sin6_len is the size of the sockaddr so substract the offset of * the possibly truncated sin6_addr struct. */ - ap = (u_int8_t *)&sa_in6->sin6_addr; - ep = (u_int8_t *)sa_in6 + sa_in6->sin6_len; + ap = (uint8_t *)&sa_in6->sin6_addr; + ep = (uint8_t *)sa_in6 + sa_in6->sin6_len; for (; ap < ep; ap++) { /* this "beauty" is adopted from sbin/route/show.c ... */ switch (*ap) { @@ -606,8 +595,8 @@ mask2prefixlen6(struct sockaddr *sa) return (l); } -u_int32_t -prefixlen2mask(u_int8_t prefixlen) +uint32_t +prefixlen2mask(uint8_t prefixlen) { if (prefixlen == 0) return (0); @@ -619,9 +608,9 @@ prefixlen2mask(u_int8_t prefixlen) } struct in6_addr * -prefixlen2mask6(u_int8_t prefixlen, u_int32_t *mask) +prefixlen2mask6(uint8_t prefixlen, uint32_t *mask) { - static struct in6_addr s6; + static struct in6_addr s6; int i; if (prefixlen > 128) @@ -674,24 +663,19 @@ print_host(struct sockaddr *sa, char *buf, size_t len) } char * -get_string(u_int8_t *ptr, size_t len) +get_string(uint8_t *ptr, size_t len) { size_t i; - char *str; for (i = 0; i < len; i++) if (!isprint(ptr[i])) break; - if ((str = calloc(1, i + 1)) == NULL) - return (NULL); - memcpy(str, ptr, i); - - return (str); + return strndup(ptr, i); } const char * -print_proto(u_int8_t proto) +print_proto(uint8_t proto) { struct protoent *p; static char buf[IKED_CYCLE_BUFFERS][BUFSIZ]; @@ -742,10 +726,10 @@ expand_string(char *label, size_t len, const char *srch, const char *repl) return (0); } -u_int8_t * +uint8_t * string2unicode(const char *ascii, size_t *outlen) { - u_int8_t *uc = NULL; + uint8_t *uc = NULL; size_t i, len = strlen(ascii); if ((uc = calloc(1, (len * 2) + 2)) == NULL) @@ -759,3 +743,27 @@ string2unicode(const char *ascii, size_t *outlen) return (uc); } + +void +print_debug(const char *emsg, ...) +{ + va_list ap; + + if (debug && verbose > 2) { + va_start(ap, emsg); + vfprintf(stderr, emsg, ap); + va_end(ap); + } +} + +void +print_verbose(const char *emsg, ...) +{ + va_list ap; + + if (verbose) { + va_start(ap, emsg); + vfprintf(stderr, emsg, ap); + va_end(ap); + } +} From 56a4422d15cd0697d6aef55d6456cbcab086f48b Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Tue, 14 Jun 2016 12:46:14 +0200 Subject: [PATCH 21/39] Add updated ikeca.cnf --- ikectl/ikeca.cnf | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/ikectl/ikeca.cnf b/ikectl/ikeca.cnf index cba9bd1..e884090 100644 --- a/ikectl/ikeca.cnf +++ b/ikectl/ikeca.cnf @@ -1,6 +1,4 @@ -# $OpenBSD: ikeca.cnf,v 1.6 2014/11/22 18:15:41 deraadt Exp $ - -RANDFILE = /dev/random +# $OpenBSD: ikeca.cnf,v 1.8 2015/11/02 12:21:27 jsg Exp $ CERT_C = DE CERT_ST = Lower Saxony @@ -17,11 +15,13 @@ EXTCERTUSAGE = serverAuth,clientAuth CERTIP = 0.0.0.0 CERTFQDN = nohost.nodomain CADB = index.txt +CASERIAL = serial.txt NSCERTTYPE = server,client [ req ] -default_bits = 2048 -default_keyfile = privkey.pem +#default_bits = 2048 +#default_md = sha256 +#default_keyfile = privkey.pem distinguished_name = req_distinguished_name #attributes = req_attributes @@ -88,8 +88,21 @@ extendedKeyUsage=$ENV::EXTCERTUSAGE [ca] default_ca = CA_default +[CA_sign_policy] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + [CA_default] database = $ENV::CADB -default_md = sha1 +serial = $ENV::CASERIAL +default_md = sha256 +default_days = 365 default_crl_days = 365 - +unique_subject = yes +email_in_dn = yes +policy = CA_sign_policy From bc38c276b9089222a7a633ff249a247da1c5c195 Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Tue, 14 Jun 2016 12:48:41 +0200 Subject: [PATCH 22/39] More updates to compile -current iked on portable --- configure.ac | 6 ++ ikectl/ikeca.c | 2 +- iked/control.c | 4 +- iked/iked.h | 1 + iked/pfkey.c | 2 +- iked/proc.c | 2 +- iked/util.c | 2 +- openbsd-compat/Makefile.am | 2 +- openbsd-compat/bsd-pledge.c | 31 +++++++++ openbsd-compat/bsd-socket.c | 116 ++++++++++++++++++++++++++++++++ openbsd-compat/defines.h | 18 +++++ openbsd-compat/explicit-bzero.c | 2 + openbsd-compat/openbsd-compat.h | 13 ++++ openbsd-compat/reallocarray.c | 2 + 14 files changed, 196 insertions(+), 7 deletions(-) create mode 100644 openbsd-compat/bsd-pledge.c create mode 100644 openbsd-compat/bsd-socket.c diff --git a/configure.ac b/configure.ac index c592951..9992001 100644 --- a/configure.ac +++ b/configure.ac @@ -432,6 +432,7 @@ else fi AC_CHECK_FUNCS([ \ + accept4 \ arc4random \ arc4random_buf \ arc4random_uniform \ @@ -441,6 +442,7 @@ AC_CHECK_FUNCS([ \ closefrom \ dirfd \ dirname \ + explicit_bzero \ fgetln \ freeaddrinfo \ getaddrinfo \ @@ -448,6 +450,8 @@ AC_CHECK_FUNCS([ \ getopt \ getpeereid \ memmove \ + pledge \ + realloc_array \ setproctitle \ setregid \ setreuid \ @@ -496,6 +500,8 @@ AC_CHECK_DECLS([O_NONBLOCK], , , #endif ]) +AC_CHECK_DECLS([SOCK_NONBLOCK SOCK_CLOEXEC], , , [#include ]) + AC_CHECK_DECLS([writev], , , [ #include #include diff --git a/ikectl/ikeca.c b/ikectl/ikeca.c index 4017715..7bef560 100644 --- a/ikectl/ikeca.c +++ b/ikectl/ikeca.c @@ -222,7 +222,7 @@ int ca_sign(struct ca *ca, char *keyname, int type) { char cmd[PATH_MAX * 2]; - char hostname[HOST_NAME_MAX+1]; + char hostname[_POSIX_HOST_NAME_MAX+1]; char name[128]; const char *extensions = NULL; diff --git a/iked/control.c b/iked/control.c index 256058b..2043c3f 100644 --- a/iked/control.c +++ b/iked/control.c @@ -83,7 +83,7 @@ control_init(struct privsep *ps, struct control_sock *cs) if (cs->cs_name == NULL) return (0); - if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1) { + if ((fd = bsd_socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1) { log_warn("%s: socket", __func__); return (-1); } @@ -176,7 +176,7 @@ control_accept(int listenfd, short event, void *arg) return; len = sizeof(sun); - if ((connfd = accept4(listenfd, + if ((connfd = bsd_accept4(listenfd, (struct sockaddr *)&sun, &len, SOCK_NONBLOCK)) == -1) { /* * Pause accept if we are out of file descriptors, or diff --git a/iked/iked.h b/iked/iked.h index 6825a16..9a4eb08 100644 --- a/iked/iked.h +++ b/iked/iked.h @@ -146,6 +146,7 @@ struct iked_flow { uint8_t flow_saproto; uint8_t flow_ipproto; uint8_t flow_type; + uint32_t flow_id; struct iked_addr *flow_local; /* outer source */ struct iked_addr *flow_peer; /* outer dest */ diff --git a/iked/pfkey.c b/iked/pfkey.c index d8caef2..9072289 100644 --- a/iked/pfkey.c +++ b/iked/pfkey.c @@ -1901,7 +1901,6 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) return 0; hdr = (struct sadb_msg *)data; - sd = env->sc_pfkey; switch (hdr->sadb_msg_type) { case SADB_ACQUIRE: @@ -1926,6 +1925,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) print_host(speer, NULL, 0)); #if defined(_OPENBSD_IPSEC_API_VERSION) + sd = env->sc_pfkey; /* get the matching flow */ bzero(&smsg, sizeof(smsg)); diff --git a/iked/proc.c b/iked/proc.c index 249cb46..55a984a 100644 --- a/iked/proc.c +++ b/iked/proc.c @@ -174,7 +174,7 @@ proc_open(struct privsep *ps, struct privsep_proc *p, if (pa->pp_pipes[procs[proc].p_id][j] != -1) continue; - if (socketpair(AF_UNIX, + if (bsd_socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, PF_UNSPEC, fds) == -1) fatal("socketpair"); diff --git a/iked/util.c b/iked/util.c index 8eea67c..05fa766 100644 --- a/iked/util.c +++ b/iked/util.c @@ -212,7 +212,7 @@ udp_bind(struct sockaddr *sa, in_port_t port) return (-1); } - if ((s = socket(sa->sa_family, + if ((s = bsd_socket(sa->sa_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP)) == -1) { log_warn("%s: failed to get UDP socket", __func__); return (-1); diff --git a/openbsd-compat/Makefile.am b/openbsd-compat/Makefile.am index f731f4e..6ef69ab 100644 --- a/openbsd-compat/Makefile.am +++ b/openbsd-compat/Makefile.am @@ -1,7 +1,7 @@ noinst_LIBRARIES= libopenbsd-compat.a libopenbsd_compat_a_SOURCES= \ - bsd-arc4random.c bsd-closefrom.c \ + bsd-arc4random.c bsd-closefrom.c bsd-pledge.c bsd-socket.c \ daemon.c explicit-bzero.c fgetln.c getopt.c imsg.c \ imsg-buffer.c reallocarray.c setresguid.c setproctitle.c \ strlcat.c strlcpy.c strtonum.c vis.c diff --git a/openbsd-compat/bsd-pledge.c b/openbsd-compat/bsd-pledge.c new file mode 100644 index 0000000..ad76047 --- /dev/null +++ b/openbsd-compat/bsd-pledge.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016 Reyk Floeter + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(HAVE_PLEDGE) +/* + * XXX Implement pledge using other sandbox methods? + */ +int +pledge(const char *promises, const char *paths[]) +{ + int i; + + log_debug("%s: pid %d promises: %s", __func__, getpid(), promises); + for (i = 0; paths != NULL && paths[i] != NULL; i++) + log_debug("%s: pid %d paths[%d]: %s", + __func__, getpid(), i, paths[i]); +} +#endif diff --git a/openbsd-compat/bsd-socket.c b/openbsd-compat/bsd-socket.c new file mode 100644 index 0000000..828c9df --- /dev/null +++ b/openbsd-compat/bsd-socket.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2016 Reyk Floeter + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if defined(SOCK_SETFLAGS) +#include +#include + +static int +bsd_socket_setflags(int s, int flags) +{ + int f; + + if (flags & SOCK_NONBLOCK) { + if (fcntl(s, F_GETFL, &f) == -1) + return (-1); + f |= O_NONBLOCK; + if (fcntl(s, F_SETFL, &f) == -1) + return (-1); + } + + if (flags & SOCK_CLOEXEC) { + if (fcntl(s, F_GETFD, &f) == -1) + return (-1); + f |= FD_CLOEXEC; + if (fcntl(s, F_SETFD, &f) == -1) + return (-1); + } + + return (0); +} +#endif + +int +bsd_socket(int domain, int type, int protocol) +{ + int s; +#if defined(SOCK_SETFLAGS) + int setfl; + + setfl = type & SOCK_SETFLAGS; + type &= ~SOCK_SETFLAGS; +#endif + + if ((s = socket(domain, type, protocol)) == -1) + return (-1); + +#if defined(SOCK_SETFLAGS) + if (bsd_socket_setflags(s, setfl) == -1) { + close(s); + return (-1); + } +#endif + + return (s); +} + +int +bsd_socketpair(int d, int type, int protocol, int sv[2]) +{ +#if defined(SOCK_SETFLAGS) + int setfl; + int i; + + setfl = type & SOCK_SETFLAGS; + type &= ~SOCK_SETFLAGS; +#endif + + if (socketpair(d, type, protocol, sv) == -1) + return (-1); + +#if defined(SOCK_SETFLAGS) + for (i = 0; i < 2; i++) { + if (bsd_socket_setflags(sv[i], setfl) == -1) { + close(sv[0]); + close(sv[1]); + return (-1); + } + } +#endif + + return (0); +} + +int +bsd_accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags) +{ +#if !defined(SOCK_SETFLAGS) && defined(HAVE_ACCEPT4) + return (accept4(s, addr, addrlen, flags)); +#else + int c; + int setfl = flags & SOCK_SETFLAGS; + + if ((c = accept(s, addr, addrlen)) == -1) + return (-1); + + if (bsd_socket_setflags(c, setfl) == -1) { + close(c); + return (-1); + } + + return (c); +#endif +} diff --git a/openbsd-compat/defines.h b/openbsd-compat/defines.h index 78a5e90..19f71f2 100644 --- a/openbsd-compat/defines.h +++ b/openbsd-compat/defines.h @@ -57,6 +57,12 @@ enum defined(HAVE_NETIPSEC_IPSEC_H) || defined(HAVE_LINUX_IPSEC_H)) #define IPSP_DIRECTION_IN IPSEC_DIR_INBOUND #define IPSP_DIRECTION_OUT IPSEC_DIR_OUTBOUND /* XXX Linux: _FWD? */ +#ifndef CPI_PRIVATE_MIN +#define CPI_PRIVATE_MIN 61440 +#endif +#ifndef CPI_PRIVATE_MAX +#define CPI_PRIVATE_MAX 65535 +#endif #endif #if defined(HAVE_NET_PFKEYV2_H) || defined(HAVE_LINUX_PFKEYV2_H) @@ -135,6 +141,18 @@ enum # define O_NONBLOCK 00004 /* Non Blocking Open */ #endif +#if !defined(HAVE_DECL_SOCK_NONBLOCK) +# define SOCK_NONBLOCK 0x4000 /* Set O_NONBLOCK */ +#endif + +#if !defined(HAVE_DECL_SOCK_CLOEXEC) +# define SOCK_CLOEXEC 0x8000 /* Set FD_CLOEXEC */ +#endif + +#if !defined(HAVE_DECL_SOCK_CLOEXEC) || !defined(HAVE_DECL_SOCK_NONBLOCK) +# define SOCK_SETFLAGS 0xf000 /* Set flags as checked above */ +#endif + #ifndef S_ISDIR # define S_ISDIR(mode) (((mode) & (_S_IFMT)) == (_S_IFDIR)) #endif /* S_ISDIR */ diff --git a/openbsd-compat/explicit-bzero.c b/openbsd-compat/explicit-bzero.c index 3e33ca8..76b96ea 100644 --- a/openbsd-compat/explicit-bzero.c +++ b/openbsd-compat/explicit-bzero.c @@ -4,6 +4,7 @@ * Written by Matthew Dempsky. */ +#if !defined(EXPLICIT_BZERO) #include __attribute__((weak)) void @@ -17,3 +18,4 @@ explicit_bzero(void *buf, size_t len) memset(buf, 0, len); __explicit_bzero_hook(buf, len); } +#endif diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h index 2a95c20..4e02020 100644 --- a/openbsd-compat/openbsd-compat.h +++ b/openbsd-compat/openbsd-compat.h @@ -177,7 +177,20 @@ int scan_scaled(char *scaled, long long *result); int fmt_scaled(long long number, char *result); #endif +#ifndef HAVE_REALLOCARRAY void *reallocarray(void *, size_t , size_t); +#endif + +#ifndef HAVE_EXPLICIT_BZERO void explicit_bzero(void *buf, size_t len); +#endif + +#ifndef HAVE_PLEDGE +int pledge(const char *promises, const char *paths[]); +#endif + +int bsd_socket(int domain, int type, int protocol); +int bsd_socketpair(int d, int type, int protocol, int sv[2]); +int bsd_accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags); #endif /* _OPENBSD_COMPAT_H */ diff --git a/openbsd-compat/reallocarray.c b/openbsd-compat/reallocarray.c index ed3244e..fe748bb 100644 --- a/openbsd-compat/reallocarray.c +++ b/openbsd-compat/reallocarray.c @@ -15,6 +15,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#if !defined(HAVE_REALLOCARRAY) #include #include #include @@ -36,3 +37,4 @@ reallocarray(void *optr, size_t nmemb, size_t size) } return realloc(optr, size * nmemb); } +#endif From 09c9da691cb6b7140579fdb13a47e5848c49fba1 Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Tue, 14 Jun 2016 12:58:10 +0200 Subject: [PATCH 23/39] pfkey_block for blocking IPv6 traffic is broken on KAME, turn it off for now --- iked/pfkey.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iked/pfkey.c b/iked/pfkey.c index 9072289..f4d420e 100644 --- a/iked/pfkey.c +++ b/iked/pfkey.c @@ -1522,6 +1522,7 @@ pfkey_flow_delete(int fd, struct iked_flow *flow) int pfkey_block(int fd, int af, unsigned int action) { +#if defined(_OPENBSD_IPSEC_API_VERSION) struct iked_flow flow; if (!pfkey_blockipv6) @@ -1545,6 +1546,10 @@ pfkey_block(int fd, int af, unsigned int action) if (pfkey_flow(fd, 0, action, &flow) == -1) return (-1); +#else + /* XXX the action above currently fails on KAME */ + pfkey_blockipv6 = 0; +#endif return (0); } From 02a8dba9da3a0b0d13194b2d0687e809b129733f Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Tue, 14 Jun 2016 13:27:57 +0200 Subject: [PATCH 24/39] Show dscl example for macOS --- README.md | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c794000..6a51544 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ also need GNU automake, autoconf (version 2.69 or newer) and libtool. `sh bootstrap` to generate the required build files. 4. Run `./configure` in this directory to generate the Makefiles. - `./configure --help` will show you some available build options. - - For example, you can run the following when building on Apple OSX + - For example, you can run the following when building on Apple OS X with MacPorts: ``` ./configure --with-ssl-dir=/opt/local/ \ @@ -76,6 +76,23 @@ on Linux. # useradd -g _iked -c 'iked privsep' -d /var/empty -s /sbin/nologin _iked ``` +For creating system users on newer versions of Apple OS X, refer to +the `dscl` command line utility, eg. +``` + # dscl . -list /Groups gid | sort -n -k 2 + # dscl . -create /Groups/_iked gid 300 + # dscl . -create /Groups/_iked RealName "OpenIKED" + # dscl . -create /Groups/_iked passwd "*" + # dscl . -list /Users UniqueID | sort -n -k 2 + # dscl . -create /Users/_iked + # dscl . -create /Users/_iked NFSHomeDirectory /var/empty + # dscl . -create /Users/_iked uid 300 + # dscl . -create /Users/_iked gid 300 + # dscl . -create /Users/_iked UserShell /usr/bin/false + # dscl . -create /Users/_iked RealName "OpenIKED" + # dscl . -create /Users/_iked passwd "*" +``` + 8. On FreeBSD, NetBSD and maybe other BSD-variants IPsec is not enabled in the default GENERIC kernel. You have to compile a custom kernel and enable options like `IPSEC`. Please refer to the @@ -89,7 +106,7 @@ Supported Platforms Original version: -* OpenBSD 4.8 or newer +* OpenBSD 6.0 or newer Portable version: From fd07d7e03efc3aa6f7dacb0e30a8c0bd66a3e196 Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Tue, 14 Jun 2016 13:33:08 +0200 Subject: [PATCH 25/39] log_info("LOG_SESSION .. are local additions from the xcllnt branch. Just fix the spacing for now, but they should probably go away or fit into iked's style (whithout the custom LOG_SESSION prefix). --- iked/ikev2.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/iked/ikev2.c b/iked/ikev2.c index 4f0d436..dbea251 100644 --- a/iked/ikev2.c +++ b/iked/ikev2.c @@ -2350,9 +2350,9 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) * so that it can be extracted for customer visiblity purposes */ log_info("LOG_SESSION: Secure session established to peer %s \ - local %s", print_host((struct sockaddr *)&sa->sa_peer.addr, - NULL, 0), print_host((struct sockaddr *)&sa->sa_local.addr, - NULL, 0)); + local %s", print_host((struct sockaddr *)&sa->sa_peer.addr, + NULL, 0), print_host((struct sockaddr *)&sa->sa_local.addr, + NULL, 0)); timer_set(env, &sa->sa_timer, ikev2_ike_sa_alive, sa); timer_add(env, &sa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT); timer_set(env, &sa->sa_rekey, ikev2_ike_sa_rekey, sa); @@ -2365,9 +2365,9 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) ikev2_childsa_delete(env, sa, 0, 0, NULL, 1); if (ret != 0) { log_info("LOG_SESSION: Authentication failure in establishing \ - secure session from %s to peer %s", - print_host((struct sockaddr *)&sa->sa_local.addr, NULL, 0), - print_host((struct sockaddr *)&sa->sa_peer.addr, NULL, 0)); + secure session from %s to peer %s", + print_host((struct sockaddr *)&sa->sa_local.addr, NULL, 0), + print_host((struct sockaddr *)&sa->sa_peer.addr, NULL, 0)); } ibuf_release(e); return (ret); @@ -2919,9 +2919,9 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg) ret = ikev2_childsa_enable(env, sa); if ((ret == 0) && (csa)) { log_info("LOG_SESSION: Rekeying secure session key peer %s \ - local %s", print_host((struct sockaddr *)&sa->sa_peer.addr, - NULL, 0), print_host((struct sockaddr *)&sa->sa_local.addr, - NULL, 0)); + local %s", print_host((struct sockaddr *)&sa->sa_peer.addr, + NULL, 0), print_host((struct sockaddr *)&sa->sa_local.addr, + NULL, 0)); } done: From 83ad30d89a4b923f991885980acbe0c021c33ed4 Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Tue, 14 Jun 2016 15:39:30 +0200 Subject: [PATCH 26/39] Fix warnings in the pledge stub --- openbsd-compat/bsd-pledge.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openbsd-compat/bsd-pledge.c b/openbsd-compat/bsd-pledge.c index ad76047..ad3fd41 100644 --- a/openbsd-compat/bsd-pledge.c +++ b/openbsd-compat/bsd-pledge.c @@ -15,6 +15,11 @@ */ #if !defined(HAVE_PLEDGE) +#include + +extern void log_debug(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); + /* * XXX Implement pledge using other sandbox methods? */ @@ -27,5 +32,7 @@ pledge(const char *promises, const char *paths[]) for (i = 0; paths != NULL && paths[i] != NULL; i++) log_debug("%s: pid %d paths[%d]: %s", __func__, getpid(), i, paths[i]); + + return (0); } #endif From 517745fd4452d637eaea634347315912acb38eaf Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Tue, 14 Jun 2016 15:40:03 +0200 Subject: [PATCH 27/39] Sync imsg from OpenBSD's libutil in -current --- openbsd-compat/imsg.c | 25 ++++++++++++++----------- openbsd-compat/imsg.h | 6 +++--- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/openbsd-compat/imsg.c b/openbsd-compat/imsg.c index a4536a2..cb06548 100644 --- a/openbsd-compat/imsg.c +++ b/openbsd-compat/imsg.c @@ -1,4 +1,4 @@ -/* $OpenBSD: imsg.c,v 1.2 2012/06/02 21:46:53 gilles Exp $ */ +/* $OpenBSD: imsg.c,v 1.13 2015/12/09 11:54:12 tb Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -16,7 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +#include #include #include #include @@ -36,7 +36,7 @@ void imsg_init(struct imsgbuf *ibuf, int fd) { msgbuf_init(&ibuf->w); - bzero(&ibuf->r, sizeof(ibuf->r)); + memset(&ibuf->r, 0, sizeof(ibuf->r)); ibuf->fd = fd; ibuf->w.fd = fd; ibuf->pid = getpid(); @@ -80,7 +80,8 @@ imsg_read(struct imsgbuf *ibuf) int fd; struct imsg_fd *ifd; - bzero(&msg, sizeof(msg)); + memset(&msg, 0, sizeof(msg)); + memset(&cmsgbuf, 0, sizeof(cmsgbuf)); iov.iov_base = ibuf->r.buf + ibuf->r.wpos; iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos; @@ -96,9 +97,10 @@ imsg_read(struct imsgbuf *ibuf) if (available_fds(imsg_fd_overhead + (CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))) { errno = EAGAIN; + free(ifd); return (-1); } - + if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) { if (errno == EMSGSIZE) goto fail; @@ -138,8 +140,7 @@ imsg_read(struct imsgbuf *ibuf) } fail: - if (ifd) - free(ifd); + free(ifd); return (n); } @@ -163,7 +164,9 @@ imsg_get(struct imsgbuf *ibuf, struct imsg *imsg) return (0); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE; - if ((imsg->data = malloc(datalen)) == NULL) + if (datalen == 0) + imsg->data = NULL; + else if ((imsg->data = malloc(datalen)) == NULL) return (-1); if (imsg->hdr.flags & IMSGF_HASFD) @@ -185,7 +188,7 @@ imsg_get(struct imsgbuf *ibuf, struct imsg *imsg) int imsg_compose(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, - pid_t pid, int fd, void *data, u_int16_t datalen) + pid_t pid, int fd, const void *data, u_int16_t datalen) { struct ibuf *wbuf; @@ -255,7 +258,7 @@ imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, } int -imsg_add(struct ibuf *msg, void *data, u_int16_t datalen) +imsg_add(struct ibuf *msg, const void *data, u_int16_t datalen) { if (datalen) if (ibuf_add(msg, data, datalen) == -1) { @@ -307,7 +310,7 @@ int imsg_flush(struct imsgbuf *ibuf) { while (ibuf->w.queued) - if (msgbuf_write(&ibuf->w) < 0) + if (msgbuf_write(&ibuf->w) <= 0) return (-1); return (0); } diff --git a/openbsd-compat/imsg.h b/openbsd-compat/imsg.h index d691f7d..8994657 100644 --- a/openbsd-compat/imsg.h +++ b/openbsd-compat/imsg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: imsg.h,v 1.2 2010/06/23 07:53:55 nicm Exp $ */ +/* $OpenBSD: imsg.h,v 1.3 2013/12/26 17:32:33 eric Exp $ */ /* * Copyright (c) 2006, 2007 Pierre-Yves Ritschard @@ -98,12 +98,12 @@ void imsg_init(struct imsgbuf *, int); ssize_t imsg_read(struct imsgbuf *); ssize_t imsg_get(struct imsgbuf *, struct imsg *); int imsg_compose(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, - int, void *, u_int16_t); + int, const void *, u_int16_t); int imsg_composev(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, int, const struct iovec *, int); struct ibuf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, u_int16_t); -int imsg_add(struct ibuf *, void *, u_int16_t); +int imsg_add(struct ibuf *, const void *, u_int16_t); void imsg_close(struct imsgbuf *, struct ibuf *); void imsg_free(struct imsg *); int imsg_flush(struct imsgbuf *); From 6e01363eba811f9b7322e4cd729e41e656eea330 Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Tue, 14 Jun 2016 16:05:48 +0200 Subject: [PATCH 28/39] Sync, remove unused variable --- ikectl/parser.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ikectl/parser.c b/ikectl/parser.c index 1ba0061..13685a8 100644 --- a/ikectl/parser.c +++ b/ikectl/parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.c,v 1.15 2015/11/02 10:27:44 jsg Exp $ */ +/* $OpenBSD: parser.c,v 1.16 2016/06/14 13:45:40 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter @@ -67,7 +67,6 @@ static const struct token t_ca_ex_pass[]; static const struct token t_ca_modifiers[]; static const struct token t_ca_cert[]; static const struct token t_ca_cert_extusage[]; -static const struct token t_ca_cert_ex_peer[]; static const struct token t_ca_cert_modifiers[]; static const struct token t_ca_key[]; static const struct token t_ca_key_modifiers[]; From 2f43acaf735bdc426bec524e0262d33eeb1acecb Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Tue, 14 Jun 2016 16:35:16 +0200 Subject: [PATCH 29/39] - Handle llvm in configure.ac (and set -Wno-pointer-sign) - Fix unsigned len type in iked/ca.c - Prevent LibreSSL from redefining __bounded__ --- configure.ac | 13 +++++++------ iked/ca.c | 3 ++- openbsd-compat/defines.h | 1 + 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index 9992001..29322d0 100644 --- a/configure.ac +++ b/configure.ac @@ -73,16 +73,17 @@ AC_CHECK_DECL([LLONG_MAX], [have_llong_max=1], , [#include ]) if test "$GCC" = "yes" || test "$GCC" = "egcs"; then CFLAGS="$CFLAGS -Wall -Wpointer-arith -Wuninitialized" - GCC_VER=`$CC -v 2>&1 | $AWK '/gcc version /{print $3}'` + GCC_VER=`$CC -v 2>&1 | grep ' version '` case $GCC_VER in - 1.*) no_attrib_nonnull=1 ;; - 2.8* | 2.9*) + gcc*1.*) no_attrib_nonnull=1 ;; + gcc*2.8* | gcc*2.9*) CFLAGS="$CFLAGS -Wsign-compare" no_attrib_nonnull=1 ;; - 2.*) no_attrib_nonnull=1 ;; - 3.*) CFLAGS="$CFLAGS -Wsign-compare" ;; - 4.*) CFLAGS="$CFLAGS -Wsign-compare -Wno-pointer-sign" ;; + gcc*2.*) no_attrib_nonnull=1 ;; + gcc*3.*) CFLAGS="$CFLAGS -Wsign-compare" ;; + gcc*4.*) CFLAGS="$CFLAGS -Wsign-compare -Wno-pointer-sign" ;; + *LLVM*) CFLAGS="$CFLAGS -Wsign-compare -Wno-pointer-sign" ;; *) ;; esac diff --git a/iked/ca.c b/iked/ca.c index 5f5e0dc..3c811df 100644 --- a/iked/ca.c +++ b/iked/ca.c @@ -544,7 +544,8 @@ ca_reload(struct iked *env) X509_OBJECT *xo; X509 *x509; DIR *dir; - int i, len, iovcnt = 0; + int i, iovcnt = 0; + unsigned int len; /* * Load CAs diff --git a/openbsd-compat/defines.h b/openbsd-compat/defines.h index 19f71f2..38ab86c 100644 --- a/openbsd-compat/defines.h +++ b/openbsd-compat/defines.h @@ -573,6 +573,7 @@ struct sadb_sa_natt { #if !defined(HAVE_ATTRIBUTE__BOUNDED__) && !defined(__bounded__) # define __bounded__(x, y, z...) +# define HAVE_ATTRIBUTE__BOUNDED__ /* LibreSSL checks it again */ #endif #if !defined(HAVE_ATTRIBUTE__NONNULL__) && !defined(__nonnull__) From 27c156bfd4dd9bc3aca24ce433861479cf222b6d Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Tue, 14 Jun 2016 16:58:24 +0000 Subject: [PATCH 30/39] Fix compilation on Linux (Ubuntu Server 14.04 LTS) --- configure.ac | 24 ++++++++++---- ikectl/ikeca.c | 4 +-- iked/ikev2.c | 14 ++++----- iked/ikev2_msg.c | 4 +-- iked/ikev2_pld.c | 6 ++-- iked/parse.y | 5 +-- iked/pfkey.c | 14 +++++---- iked/util.c | 22 +++++++------ openbsd-compat/Makefile.am | 4 +-- openbsd-compat/bsd-err.c | 56 +++++++++++++++++++++++++++++++++ openbsd-compat/defines.h | 15 +++++++-- openbsd-compat/openbsd-compat.h | 9 ++++++ 12 files changed, 135 insertions(+), 42 deletions(-) create mode 100644 openbsd-compat/bsd-err.c diff --git a/configure.ac b/configure.ac index 29322d0..a0db453 100644 --- a/configure.ac +++ b/configure.ac @@ -75,13 +75,12 @@ if test "$GCC" = "yes" || test "$GCC" = "egcs"; then CFLAGS="$CFLAGS -Wall -Wpointer-arith -Wuninitialized" GCC_VER=`$CC -v 2>&1 | grep ' version '` case $GCC_VER in - gcc*1.*) no_attrib_nonnull=1 ;; - gcc*2.8* | gcc*2.9*) - CFLAGS="$CFLAGS -Wsign-compare" - no_attrib_nonnull=1 - ;; gcc*2.*) no_attrib_nonnull=1 ;; gcc*3.*) CFLAGS="$CFLAGS -Wsign-compare" ;; + gcc*4.8*) + CFLAGS="$CFLAGS -Wsign-compare -Wno-pointer-sign" + CFLAGS="$CFLAGS -Wno-unused-result" + ;; gcc*4.*) CFLAGS="$CFLAGS -Wsign-compare -Wno-pointer-sign" ;; *LLVM*) CFLAGS="$CFLAGS -Wsign-compare -Wno-pointer-sign" ;; *) ;; @@ -443,6 +442,7 @@ AC_CHECK_FUNCS([ \ closefrom \ dirfd \ dirname \ + errc \ explicit_bzero \ fgetln \ freeaddrinfo \ @@ -463,6 +463,7 @@ AC_CHECK_FUNCS([ \ strmode \ sysconf \ waitpid \ + warnc \ ]) # IRIX has a const char return value for gai_strerror() @@ -501,7 +502,18 @@ AC_CHECK_DECLS([O_NONBLOCK], , , #endif ]) -AC_CHECK_DECLS([SOCK_NONBLOCK SOCK_CLOEXEC], , , [#include ]) +AC_CHECK_DECLS([SOCK_NONBLOCK], , , [#include ]) +AC_CHECK_DECLS([SOCK_CLOEXEC], , , [#include ]) +AC_CHECK_DECLS([IP_RECVDSTADDR], , , [ +#include +#include +#include +]) +AC_CHECK_DECLS([IP_RECVORIGDSTADDR], , , [ +#include +#include +#include +]) AC_CHECK_DECLS([writev], , , [ #include diff --git a/ikectl/ikeca.c b/ikectl/ikeca.c index 7bef560..13a255b 100644 --- a/ikectl/ikeca.c +++ b/ikectl/ikeca.c @@ -496,8 +496,8 @@ ca_show_certs(struct ca *ca, char *name) err(1, "could not open directory %s", ca->sslpath); while ((de = readdir(dir)) != NULL) { - if (de->d_namlen > 4) { - p = de->d_name + de->d_namlen - 4; + if (strlen(de->d_name) > 4) { + p = de->d_name + strlen(de->d_name) - 4; if (strcmp(".crt", p) != 0) continue; snprintf(path, sizeof(path), "%s/%s", ca->sslpath, diff --git a/iked/ikev2.c b/iked/ikev2.c index dbea251..09dad8a 100644 --- a/iked/ikev2.c +++ b/iked/ikev2.c @@ -833,10 +833,10 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, if (socket_getaddr(sock->sock_fd, &ss) == -1) goto done; } else - memcpy(&ss, &pol->pol_local.addr, pol->pol_local.addr.ss_len); + memcpy(&ss, &pol->pol_local.addr, SS_LEN(&pol->pol_local.addr)); - if ((buf = ikev2_msg_init(env, &req, &peer->addr, peer->addr.ss_len, - &ss, ss.ss_len, 0)) == NULL) + if ((buf = ikev2_msg_init(env, &req, &peer->addr, SS_LEN(&peer->addr), + &ss, SS_LEN(&ss), 0)) == NULL) goto done; /* Inherit the port from the 1st send socket */ @@ -5063,7 +5063,7 @@ ikev2_print_id(struct iked_id *id, char *idstr, size_t idstrlen) case IKEV2_ID_IPV4: s4 = (struct sockaddr_in *)buf; s4->sin_family = AF_INET; - s4->sin_len = sizeof(*s4); + SET_STORAGE_LEN(*(struct sockaddr_storage *)s4, sizeof(*s4)); memcpy(&s4->sin_addr.s_addr, ptr, len); if (print_host((struct sockaddr *)s4, @@ -5087,7 +5087,7 @@ ikev2_print_id(struct iked_id *id, char *idstr, size_t idstrlen) case IKEV2_ID_IPV6: s6 = (struct sockaddr_in6 *)buf; s6->sin6_family = AF_INET6; - s6->sin6_len = sizeof(*s6); + SET_STORAGE_LEN(*(struct sockaddr_storage *)s6, sizeof(*s6)); memcpy(&s6->sin6_addr, ptr, len); if (print_host((struct sockaddr *)s6, @@ -5181,7 +5181,7 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa, sa_family_t family) cfg4 = (struct sockaddr_in *)&ikecfg->cfg.address.addr; in4 = (struct sockaddr_in *)&addr.addr; in4->sin_family = AF_INET; - in4->sin_len = sizeof(*in4); + SET_STORAGE_LEN(*(struct sockaddr_storage *)in4, sizeof(*in4)); mask = prefixlen2mask(ikecfg->cfg.address.addr_mask); lower = ntohl(cfg4->sin_addr.s_addr & ~mask); key.sa_addrpool = &addr; @@ -5190,7 +5190,7 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa, sa_family_t family) cfg6 = (struct sockaddr_in6 *)&ikecfg->cfg.address.addr; in6 = (struct sockaddr_in6 *)&addr.addr; in6->sin6_family = AF_INET6; - in6->sin6_len = sizeof(*in6); + SET_STORAGE_LEN(*(struct sockaddr_storage *)in6, sizeof(*in6)); /* truncate prefixlen to get a 32-bit space */ mask = (ikecfg->cfg.address.addr_mask >= 96) ? prefixlen2mask(ikecfg->cfg.address.addr_mask - 96) diff --git a/iked/ikev2_msg.c b/iked/ikev2_msg.c index 2fbc5bd..c335509 100644 --- a/iked/ikev2_msg.c +++ b/iked/ikev2_msg.c @@ -619,8 +619,8 @@ ikev2_msg_send_encrypt(struct iked *env, struct iked_sa *sa, struct ibuf **ep, int ret = -1; if ((buf = ikev2_msg_init(env, &resp, &sa->sa_peer.addr, - sa->sa_peer.addr.ss_len, &sa->sa_local.addr, - sa->sa_local.addr.ss_len, response)) == NULL) + SS_LEN(&sa->sa_peer.addr), &sa->sa_local.addr, + SS_LEN(&sa->sa_local.addr), response)) == NULL) goto done; resp.msg_msgid = response ? sa->sa_msgid : ikev2_msg_id(env, sa); diff --git a/iked/ikev2_pld.c b/iked/ikev2_pld.c index 2b70f6c..20df36c 100644 --- a/iked/ikev2_pld.c +++ b/iked/ikev2_pld.c @@ -1565,7 +1565,8 @@ ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld, case IKEV2_TS_IPV4_ADDR_RANGE: bzero(&s4, sizeof(s4)); s4.sin_family = AF_INET; - s4.sin_len = sizeof(s4); + SET_STORAGE_LEN((struct sockaddr_storage)s4, + sizeof(s4)); memcpy(&s4.sin_addr.s_addr, msgbuf + offset + sizeof(ts), 4); print_host((struct sockaddr *)&s4, @@ -1580,7 +1581,8 @@ ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld, case IKEV2_TS_IPV6_ADDR_RANGE: bzero(&s6, sizeof(s6)); s6.sin6_family = AF_INET6; - s6.sin6_len = sizeof(s6); + SET_STORAGE_LEN((struct sockaddr_storage)s6, + sizeof(s6)); memcpy(&s6.sin6_addr, msgbuf + offset + sizeof(ts), 16); print_host((struct sockaddr *)&s6, diff --git a/iked/parse.y b/iked/parse.y index c9f6a70..1eb9b10 100644 --- a/iked/parse.y +++ b/iked/parse.y @@ -657,7 +657,8 @@ host_spec : STRING { | STRING '/' NUMBER { char *buf; - if (asprintf(&buf, "%s/%lld", $1, $3) == -1) + if (asprintf(&buf, "%s/%lld", $1, + (long long int)$3) == -1) err(1, "host: asprintf"); free($1); if (($$ = host(buf)) == NULL) { @@ -1809,7 +1810,7 @@ host_v4(const char *s, int mask) err(1, "host_v4: calloc"); ina.sin_family = AF_INET; - ina.sin_len = sizeof(ina); + SET_STORAGE_LEN((struct sockaddr_storage)ina, sizeof(ina)); memcpy(&ipa->address, &ina, sizeof(ina)); ipa->name = strdup(s); diff --git a/iked/pfkey.c b/iked/pfkey.c index f4d420e..c44b264 100644 --- a/iked/pfkey.c +++ b/iked/pfkey.c @@ -30,7 +30,9 @@ #if defined(HAVE_NETINET_IP_IPSP_H) #include #endif +#if defined(HAVE_NET_PFKEYV2_H) #include +#endif #include #include @@ -253,7 +255,7 @@ pfkey_flow(int sd, uint8_t satype, uint8_t action, struct iked_flow *flow) __func__, flow->flow_src.addr_af); return (-1); } - smask.ss_len = ssrc.ss_len; + SET_STORAGE_LEN(smask, SS_LEN(ssrc)); bzero(&sdst, sizeof(sdst)); bzero(&dmask, sizeof(dmask)); @@ -463,7 +465,7 @@ pfkey_flow(int sd, uint8_t satype, uint8_t action, struct iked_flow *flow) struct sadb_x_policy sa_policy, *sa_polid; struct sadb_x_sa2 sa_2; struct sockaddr_storage ssrc, sdst, slocal, speer; - struct iovec iov[10]; + struct iovec iov[IOV_CNT]; int iov_cnt, ret = -1; in_port_t sport, dport; u_int8_t smask, dmask; @@ -1164,11 +1166,11 @@ pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, sa_spirange.sadb_spirange_reserved = 0; bzero(&sa_src, sizeof(sa_src)); - sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; + sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(SS_LEN(&ssrc))) / 8; sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; bzero(&sa_dst, sizeof(sa_dst)); - sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; + sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(SS_LEN(&sdst))) / 8; sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; iov_cnt = 0; @@ -1189,7 +1191,7 @@ pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, iov[iov_cnt].iov_len = sizeof(sa_src); iov_cnt++; iov[iov_cnt].iov_base = &ssrc; - iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); + iov[iov_cnt].iov_len = ROUNDUP(SS_LEN(&ssrc)); smsg.sadb_msg_len += sa_src.sadb_address_len; iov_cnt++; @@ -1198,7 +1200,7 @@ pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, iov[iov_cnt].iov_len = sizeof(sa_dst); iov_cnt++; iov[iov_cnt].iov_base = &sdst; - iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); + iov[iov_cnt].iov_len = ROUNDUP(SS_LEN(&sdst)); smsg.sadb_msg_len += sa_dst.sadb_address_len; iov_cnt++; diff --git a/iked/util.c b/iked/util.c index 05fa766..105be53 100644 --- a/iked/util.c +++ b/iked/util.c @@ -46,13 +46,13 @@ socket_af(struct sockaddr *sa, in_port_t port) switch (sa->sa_family) { case AF_INET: ((struct sockaddr_in *)sa)->sin_port = port; - ((struct sockaddr_in *)sa)->sin_len = - sizeof(struct sockaddr_in); + SET_STORAGE_LEN((struct sockaddr_storage)sa, + sizeof(struct sockaddr_in)); break; case AF_INET6: ((struct sockaddr_in6 *)sa)->sin6_port = port; - ((struct sockaddr_in6 *)sa)->sin6_len = - sizeof(struct sockaddr_in6); + SET_STORAGE_LEN((struct sockaddr_storage)sa, + sizeof(struct sockaddr_in6)); break; default: errno = EPFNOSUPPORT; @@ -254,7 +254,7 @@ udp_bind(struct sockaddr *sa, in_port_t port) } } - if (bind(s, sa, sa->sa_len) == -1) { + if (bind(s, sa, SA_LEN(sa)) == -1) { log_warn("%s: failed to bind UDP socket", __func__); goto bad; } @@ -359,7 +359,7 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, if ((ret = recvmsg(s, &msg, 0)) == -1) return (-1); - *fromlen = from->sa_len; + *fromlen = SA_LEN(from); *tolen = 0; if (getsockname(s, to, tolen) != 0) @@ -373,7 +373,8 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, cmsg->cmsg_type == IP_RECVDSTADDR) { in = (struct sockaddr_in *)to; in->sin_family = AF_INET; - in->sin_len = *tolen = sizeof(*in); + SET_STORAGE_LEN(*(struct sockaddr_storage *) + in, sizeof(*in)); memcpy(&in->sin_addr, CMSG_DATA(cmsg), sizeof(struct in_addr)); } @@ -383,7 +384,8 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, cmsg->cmsg_type == IPV6_PKTINFO) { in6 = (struct sockaddr_in6 *)to; in6->sin6_family = AF_INET6; - in6->sin6_len = *tolen = sizeof(*in6); + SET_STORAGE_LEN(*(struct sockaddr_storage *) + in6, sizeof(*in6)); pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg); memcpy(&in6->sin6_addr, &pkt6->ipi6_addr, sizeof(struct in6_addr)); @@ -557,7 +559,7 @@ mask2prefixlen6(struct sockaddr *sa) * the possibly truncated sin6_addr struct. */ ap = (uint8_t *)&sa_in6->sin6_addr; - ep = (uint8_t *)sa_in6 + sa_in6->sin6_len; + ep = (uint8_t *)sa_in6 + SA_LEN((struct sockaddr *)sa_in6); for (; ap < ep; ap++) { /* this "beauty" is adopted from sbin/route/show.c ... */ switch (*ap) { @@ -648,7 +650,7 @@ print_host(struct sockaddr *sa, char *buf, size_t len) return (buf); } - if (getnameinfo(sa, sa->sa_len, + if (getnameinfo(sa, SA_LEN(sa), buf, len, NULL, 0, NI_NUMERICHOST) != 0) { buf[0] = '\0'; return (NULL); diff --git a/openbsd-compat/Makefile.am b/openbsd-compat/Makefile.am index 6ef69ab..4953479 100644 --- a/openbsd-compat/Makefile.am +++ b/openbsd-compat/Makefile.am @@ -1,7 +1,7 @@ noinst_LIBRARIES= libopenbsd-compat.a -libopenbsd_compat_a_SOURCES= \ - bsd-arc4random.c bsd-closefrom.c bsd-pledge.c bsd-socket.c \ +libopenbsd_compat_a_SOURCES= bsd-arc4random.c bsd-err.c \ + bsd-closefrom.c bsd-pledge.c bsd-socket.c \ daemon.c explicit-bzero.c fgetln.c getopt.c imsg.c \ imsg-buffer.c reallocarray.c setresguid.c setproctitle.c \ strlcat.c strlcpy.c strtonum.c vis.c diff --git a/openbsd-compat/bsd-err.c b/openbsd-compat/bsd-err.c new file mode 100644 index 0000000..0ab08fb --- /dev/null +++ b/openbsd-compat/bsd-err.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016 Reyk Floeter + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(HAVE_ERRC) || !defined(HAVE_WARNC) +#include +#include +#include +#endif + +#ifndef HAVE_ERRC +void +errc(int eval, int code, const char *fmt, ...) +{ + va_list ap; + int saved_errno = errno; + + errno = code; + + va_start(ap, fmt); + verr(eval, fmt, ap); + va_end(ap); + + /* NOTREACHED */ + errno = saved_errno; +} +#endif + +#ifndef HAVE_WARNC +void +warnc(int code, const char *fmt, ...) +{ + va_list ap; + int saved_errno = errno; + + errno = code; + + va_start(ap, fmt); + vwarn(fmt, ap); + va_end(ap); + + errno = saved_errno; +} +#endif diff --git a/openbsd-compat/defines.h b/openbsd-compat/defines.h index 38ab86c..4a18d92 100644 --- a/openbsd-compat/defines.h +++ b/openbsd-compat/defines.h @@ -141,15 +141,16 @@ enum # define O_NONBLOCK 00004 /* Non Blocking Open */ #endif -#if !defined(HAVE_DECL_SOCK_NONBLOCK) +#if defined(HAVE_DECL_SOCK_NONBLOCK) && HAVE_DECL_SOCK_NONBLOCK == 0 # define SOCK_NONBLOCK 0x4000 /* Set O_NONBLOCK */ #endif -#if !defined(HAVE_DECL_SOCK_CLOEXEC) +#if defined(HAVE_DECL_SOCK_CLOEXEC) && HAVE_DECL_SOCK_CLOEXEC == 0 # define SOCK_CLOEXEC 0x8000 /* Set FD_CLOEXEC */ #endif -#if !defined(HAVE_DECL_SOCK_CLOEXEC) || !defined(HAVE_DECL_SOCK_NONBLOCK) +#if (defined(HAVE_DECL_SOCK_NONBLOCK) && HAVE_DECL_SOCK_NONBLOCK == 0) || \ + (defined(HAVE_DECL_SOCK_CLOEXEC) && HAVE_DECL_SOCK_CLOEXEC == 0) # define SOCK_SETFLAGS 0xf000 /* Set flags as checked above */ #endif @@ -360,6 +361,14 @@ struct sockaddr_un { #define AF_LINK AF_PACKET /* XXX workaround on Linux */ #endif +#if defined(HAVE_DECL_IP_RECVDSTADDR) && HAVE_DECL_IP_RECVDSTADDR == 0 +#if defined(HAVE_DECL_IP_RECVORIGDSTADDR) && HAVE_DECL_IP_RECVORIGDSTADDR == 1 +#define IP_RECVDSTADDR IP_RECVORIGDSTADDR +#else +#error "IP_RECVDSTADDR not supported" +#endif +#endif + #ifndef HAVE_IN_ADDR_T typedef u_int32_t in_addr_t; #endif diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h index 4e02020..98782aa 100644 --- a/openbsd-compat/openbsd-compat.h +++ b/openbsd-compat/openbsd-compat.h @@ -88,6 +88,7 @@ # define STORAGE_LEN(X) ((X).__ss_len) # define SET_STORAGE_LEN(X, Y) do { STORAGE_LEN(X) = (Y); } while(0) #else +# define STORAGE_FAMILY(x) ((x).ss_family) # define STORAGE_LEN(X) (STORAGE_FAMILY(X) == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)) # define SET_STORAGE_LEN(X, Y) (void) 0 #endif @@ -189,6 +190,14 @@ void explicit_bzero(void *buf, size_t len); int pledge(const char *promises, const char *paths[]); #endif +#ifndef HAVE_ERRC +void errc(int eval, int code, const char *fmt, ...); +#endif + +#ifndef HAVE_WARNC +void warnc(int code, const char *fmt, ...); +#endif + int bsd_socket(int domain, int type, int protocol); int bsd_socketpair(int d, int type, int protocol, int sv[2]); int bsd_accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags); From 1139f17a00e67e4213db6e0ace6589c64b39c01b Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Tue, 14 Jun 2016 17:37:02 +0000 Subject: [PATCH 31/39] Don't limit PATH_MAX to 1024 - this causes problems with functions that expect a PATH_MAX input buffer (like realpath on Linux). Despite the comment, there doesn't seem to be an imsg with a path element. --- openbsd-compat/defines.h | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/openbsd-compat/defines.h b/openbsd-compat/defines.h index 4a18d92..9fb1df4 100644 --- a/openbsd-compat/defines.h +++ b/openbsd-compat/defines.h @@ -89,28 +89,14 @@ enum # ifdef _POSIX_PATH_MAX # define PATH_MAX _POSIX_PATH_MAX # else -# define PATH_MAX 64 +# define PATH_MAX 256 # endif #endif -/* - * Looks like ugly, but MAX_IMSGSIZE equals 16384, - * and if we don't care it will overflow for some struct - */ -#if PATH_MAX > 1024 -# undef PATH_MAX -# define PATH_MAX 1024 -#endif - #ifndef MAXPATHLEN # define MAXPATHLEN PATH_MAX #endif -#if MAXPATHLEN > 1024 -# undef MAXPATHLEN -# define MAXPATHLEN 1024 -#endif - #if defined(HAVE_DECL_MAXSYMLINKS) && HAVE_DECL_MAXSYMLINKS == 0 # define MAXSYMLINKS 5 #endif From be6eaec2eda7b75bffd91defe38edc920a180fa2 Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Tue, 14 Jun 2016 18:21:39 +0000 Subject: [PATCH 32/39] We have to call RAND_seed() when using OpenSSL; this is not needed by LibreSSL since it implements a proper PRNG. Unfortunately, Ubuntu still defaults to OpenSSL. --- iked/proc.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/iked/proc.c b/iked/proc.c index 55a984a..67aa623 100644 --- a/iked/proc.c +++ b/iked/proc.c @@ -31,7 +31,7 @@ #include #include #include - +#include #include "iked.h" void proc_open(struct privsep *, struct privsep_proc *, @@ -336,6 +336,9 @@ proc_run(struct privsep *ps, struct privsep_proc *p, const char *root; struct control_sock *rcs; unsigned int n; +#ifndef LIBRESSL_VERSION_NUMBER + u_int32_t seed[256]; +#endif if (ps->ps_noaction) return (0); @@ -415,6 +418,10 @@ proc_run(struct privsep *ps, struct privsep_proc *p, signal_add(&ps->ps_evsigpipe, NULL); signal_add(&ps->ps_evsigusr1, NULL); +#ifndef LIBRESSL_VERSION_NUMBER + arc4random_buf(seed, sizeof(seed)); + RAND_seed(seed, sizeof(seed)); +#endif proc_listen(ps, procs, nproc); if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) { From c40acb87b7ae6f5b2ab5c036cdfc24e7a1337cee Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Tue, 14 Jun 2016 18:55:56 +0000 Subject: [PATCH 33/39] Linux IP_RECVORIGDSTADDR returns a struct sockaddr_in, BSD IP_RECVDSTADDR returns a struct in_addr. --- iked/util.c | 12 ++++++++++++ openbsd-compat/defines.h | 8 -------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/iked/util.c b/iked/util.c index 105be53..c674846 100644 --- a/iked/util.c +++ b/iked/util.c @@ -238,7 +238,11 @@ udp_bind(struct sockaddr *sa, in_port_t port) if (sa->sa_family == AF_INET) { val = 1; +#if HAVE_DECL_IP_RECVORIGDSTADDR + if (setsockopt(s, IPPROTO_IP, IP_RECVORIGDSTADDR, +#elif HAVE_DECL_IP_RECVDSTADDR if (setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, +#endif &val, sizeof(int)) == -1) { log_warn("%s: failed to set IPv4 packet info", __func__); @@ -369,6 +373,7 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, cmsg = CMSG_NXTHDR(&msg, cmsg)) { switch (from->sa_family) { case AF_INET: +#if HAVE_DECL_IP_RECVDSTADDR if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) { in = (struct sockaddr_in *)to; @@ -378,6 +383,13 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, memcpy(&in->sin_addr, CMSG_DATA(cmsg), sizeof(struct in_addr)); } +#elif HAVE_DECL_IP_RECVORIGDSTADDR + if (cmsg->cmsg_level == IPPROTO_IP && + cmsg->cmsg_type == IP_RECVORIGDSTADDR) { + in = (struct sockaddr_in *)to; + memcpy(in, CMSG_DATA(cmsg), sizeof(*in)); + } +#endif break; case AF_INET6: if (cmsg->cmsg_level == IPPROTO_IPV6 && diff --git a/openbsd-compat/defines.h b/openbsd-compat/defines.h index 9fb1df4..df4bbea 100644 --- a/openbsd-compat/defines.h +++ b/openbsd-compat/defines.h @@ -347,14 +347,6 @@ struct sockaddr_un { #define AF_LINK AF_PACKET /* XXX workaround on Linux */ #endif -#if defined(HAVE_DECL_IP_RECVDSTADDR) && HAVE_DECL_IP_RECVDSTADDR == 0 -#if defined(HAVE_DECL_IP_RECVORIGDSTADDR) && HAVE_DECL_IP_RECVORIGDSTADDR == 1 -#define IP_RECVDSTADDR IP_RECVORIGDSTADDR -#else -#error "IP_RECVDSTADDR not supported" -#endif -#endif - #ifndef HAVE_IN_ADDR_T typedef u_int32_t in_addr_t; #endif From 8a457cd559ec091bf94b5a83f914a01b7da5607b Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Wed, 15 Jun 2016 15:34:58 +0000 Subject: [PATCH 34/39] "compile" on FreeBSD 10 (not yet tested because PFKEYv2 is not enabled by default and I'd have to build a custom kernel as documented in https://www.freebsd.org/doc/handbook/ipsec.html). --- configure.ac | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index a0db453..94c4ab0 100644 --- a/configure.ac +++ b/configure.ac @@ -82,7 +82,9 @@ if test "$GCC" = "yes" || test "$GCC" = "egcs"; then CFLAGS="$CFLAGS -Wno-unused-result" ;; gcc*4.*) CFLAGS="$CFLAGS -Wsign-compare -Wno-pointer-sign" ;; - *LLVM*) CFLAGS="$CFLAGS -Wsign-compare -Wno-pointer-sign" ;; + *LLVM*|*clang*) + CFLAGS="$CFLAGS -Wsign-compare -Wno-pointer-sign" + ;; *) ;; esac @@ -139,6 +141,7 @@ AC_CHECK_HEADERS([\ getopt.h \ libkern/OSByteOrder.h \ ndir.h \ + sys/types.h \ sys/cdefs.h \ sys/endian.h \ sys/ndir.h \ @@ -147,7 +150,6 @@ AC_CHECK_HEADERS([\ sys/socket.h \ sys/stat.h \ sys/sysctl.h \ - sys/types.h \ sys/uio.h \ sys/un.h \ sys/wait.h \ @@ -175,6 +177,9 @@ AC_CHECK_HEADERS([\ unistd.h \ vis.h \ ], , , [ +#ifdef HAVE_SYS_TYPES_H +# include +#endif #ifdef HAVE_SYS_SOCKET_H # include #endif From 819acac409e4c10c4ce17a1cfff3e7714f3804a5 Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Sun, 19 Jun 2016 09:28:02 -0700 Subject: [PATCH 35/39] Fix initialization of the sa_len and ss_len fields in struct sockaddr and struct sockaddr_storage (resp): - Fix openbsd-compat.h and replace SET_STORAGE_LEN with SET_SA_LEN and SET_SS_LEN. Remove the unused STORAGE_LEN and now unused STORAGE_FAMILY. - Make the definition of SET_SA_LEN dependent upon HAVE_STRUCT_SOCKADDR_SA_LEN. if HAVE_STRUCT_SOCKADDR_SA_LEN is not defined, expand SET_SA_LEN to void. - Make the definition of SET_SS_LEN dependent upon HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN. If the latter is not defined, expand SET_SS_LEN to SET_SA_LEN. This to avoid compatibility problems between ss_len and __ss_len. - Avoid excessive back and forth casting and use sockaddr or sockaddr_storage as much as possible. While here, eliminate the af field from struct ipsec_addr_wrap. This makes sure that the ss_family field in address is always properly initialized. Redundant variables tend to have that effect. This fixes setting up SAs on FreeBSD and presumably any OS that have sa_len and ss_len. --- iked/iked.c | 2 + iked/ikev2.c | 42 ++++++++--------- iked/ikev2_pld.c | 40 +++++++--------- iked/parse.y | 84 ++++++++++++++++++--------------- iked/util.c | 30 +++++------- openbsd-compat/openbsd-compat.h | 25 +++++----- 6 files changed, 112 insertions(+), 111 deletions(-) diff --git a/iked/iked.c b/iked/iked.c index 63dc075..6127ee3 100644 --- a/iked/iked.c +++ b/iked/iked.c @@ -205,6 +205,7 @@ parent_configure(struct iked *env) bzero(&ss, sizeof(ss)); ss.ss_family = AF_INET; + SET_SS_LEN(&ss, sizeof(struct sockaddr_in)); if ((env->sc_opts & IKED_OPT_NATT) == 0) config_setsocket(env, &ss, ntohs(IKED_IKE_PORT), PROC_IKEV2); @@ -213,6 +214,7 @@ parent_configure(struct iked *env) bzero(&ss, sizeof(ss)); ss.ss_family = AF_INET6; + SET_SS_LEN(&ss, sizeof(struct sockaddr_in6)); if ((env->sc_opts & IKED_OPT_NATT) == 0) config_setsocket(env, &ss, ntohs(IKED_IKE_PORT), PROC_IKEV2); diff --git a/iked/ikev2.c b/iked/ikev2.c index 09dad8a..1ed6af1 100644 --- a/iked/ikev2.c +++ b/iked/ikev2.c @@ -5028,8 +5028,7 @@ int ikev2_print_id(struct iked_id *id, char *idstr, size_t idstrlen) { uint8_t buf[BUFSIZ], *ptr; - struct sockaddr_in *s4; - struct sockaddr_in6 *s6; + struct sockaddr *sa; char *str; ssize_t len; int i; @@ -5061,13 +5060,11 @@ ikev2_print_id(struct iked_id *id, char *idstr, size_t idstrlen) switch (id->id_type) { case IKEV2_ID_IPV4: - s4 = (struct sockaddr_in *)buf; - s4->sin_family = AF_INET; - SET_STORAGE_LEN(*(struct sockaddr_storage *)s4, sizeof(*s4)); - memcpy(&s4->sin_addr.s_addr, ptr, len); - - if (print_host((struct sockaddr *)s4, - idstr, idstrlen) == NULL) + sa = (struct sockaddr *)buf; + sa->sa_family = AF_INET; + SET_SA_LEN(sa, sizeof(struct sockaddr_in)); + memcpy(&((struct sockaddr_in *)sa)->sin_addr, ptr, len); + if (print_host(sa, idstr, idstrlen) == NULL) return (-1); break; case IKEV2_ID_FQDN: @@ -5085,13 +5082,11 @@ ikev2_print_id(struct iked_id *id, char *idstr, size_t idstrlen) free(str); break; case IKEV2_ID_IPV6: - s6 = (struct sockaddr_in6 *)buf; - s6->sin6_family = AF_INET6; - SET_STORAGE_LEN(*(struct sockaddr_storage *)s6, sizeof(*s6)); - memcpy(&s6->sin6_addr, ptr, len); - - if (print_host((struct sockaddr *)s6, - idstr, idstrlen) == NULL) + sa = (struct sockaddr *)buf; + sa->sa_family = AF_INET6; + SET_SA_LEN(sa, sizeof(struct sockaddr_in6)); + memcpy(&((struct sockaddr_in6 *)sa)->sin6_addr, ptr, len); + if (print_host(sa, idstr, idstrlen) == NULL) return (-1); break; case IKEV2_ID_ASN1_DN: @@ -5179,18 +5174,16 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa, sa_family_t family) switch (addr.addr_af) { case AF_INET: cfg4 = (struct sockaddr_in *)&ikecfg->cfg.address.addr; - in4 = (struct sockaddr_in *)&addr.addr; - in4->sin_family = AF_INET; - SET_STORAGE_LEN(*(struct sockaddr_storage *)in4, sizeof(*in4)); + addr.addr.ss_family = AF_INET; + SET_SS_LEN(&addr.addr, sizeof(struct sockaddr_in)); mask = prefixlen2mask(ikecfg->cfg.address.addr_mask); lower = ntohl(cfg4->sin_addr.s_addr & ~mask); key.sa_addrpool = &addr; break; case AF_INET6: cfg6 = (struct sockaddr_in6 *)&ikecfg->cfg.address.addr; - in6 = (struct sockaddr_in6 *)&addr.addr; - in6->sin6_family = AF_INET6; - SET_STORAGE_LEN(*(struct sockaddr_storage *)in6, sizeof(*in6)); + addr.addr.ss_family = AF_INET6; + SET_SS_LEN(&addr.addr, sizeof(struct sockaddr_in6)); /* truncate prefixlen to get a 32-bit space */ mask = (ikecfg->cfg.address.addr_mask >= 96) ? prefixlen2mask(ikecfg->cfg.address.addr_mask - 96) @@ -5215,11 +5208,14 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa, sa_family_t family) __func__, mask, start, lower, host, upper); switch (addr.addr_af) { case AF_INET: + in4 = (struct sockaddr_in *)&addr.addr; in4->sin_addr.s_addr = (cfg4->sin_addr.s_addr & mask) | htonl(host); break; case AF_INET6: - memcpy(in6, cfg6, sizeof(*in6)); + in6 = (struct sockaddr_in6 *)&addr.addr; + memcpy(&in6->sin6_addr, &cfg6->sin6_addr, + sizeof(in6->sin6_addr)); nhost = htonl(host); memcpy(&in6->sin6_addr.s6_addr[12], &nhost, sizeof(uint32_t)); diff --git a/iked/ikev2_pld.c b/iked/ikev2_pld.c index 20df36c..ef8c9aa 100644 --- a/iked/ikev2_pld.c +++ b/iked/ikev2_pld.c @@ -1537,8 +1537,7 @@ ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld, struct ikev2_tsp tsp; struct ikev2_ts ts; size_t len, i; - struct sockaddr_in s4; - struct sockaddr_in6 s6; + struct sockaddr_storage ss; uint8_t buf[2][128]; uint8_t *msgbuf = ibuf_data(msg->msg_data); @@ -1561,36 +1560,33 @@ ikev2_pld_ts(struct iked *env, struct ikev2_payload *pld, betoh16(ts.ts_startport), betoh16(ts.ts_endport)); + bzero(&ss, sizeof(ss)); switch (ts.ts_type) { case IKEV2_TS_IPV4_ADDR_RANGE: - bzero(&s4, sizeof(s4)); - s4.sin_family = AF_INET; - SET_STORAGE_LEN((struct sockaddr_storage)s4, - sizeof(s4)); - memcpy(&s4.sin_addr.s_addr, + ss.ss_family = AF_INET; + SET_SS_LEN(&ss, sizeof(struct sockaddr_in)); + memcpy(&((struct sockaddr_in *)&ss)->sin_addr, msgbuf + offset + sizeof(ts), 4); - print_host((struct sockaddr *)&s4, - (char *)buf[0], sizeof(buf[0])); - memcpy(&s4.sin_addr.s_addr, + print_host((struct sockaddr *)&ss, (char *)buf[0], + sizeof(buf[0])); + memcpy(&((struct sockaddr_in *)&ss)->sin_addr, msgbuf + offset + sizeof(ts) + 4, 4); - print_host((struct sockaddr *)&s4, - (char *)buf[1], sizeof(buf[1])); + print_host((struct sockaddr *)&ss, (char *)buf[1], + sizeof(buf[1])); log_debug("%s: start %s end %s", __func__, buf[0], buf[1]); break; case IKEV2_TS_IPV6_ADDR_RANGE: - bzero(&s6, sizeof(s6)); - s6.sin6_family = AF_INET6; - SET_STORAGE_LEN((struct sockaddr_storage)s6, - sizeof(s6)); - memcpy(&s6.sin6_addr, + ss.ss_family = AF_INET6; + SET_SS_LEN(&ss, sizeof(struct sockaddr_in6)); + memcpy(&((struct sockaddr_in6 *)&ss)->sin6_addr, msgbuf + offset + sizeof(ts), 16); - print_host((struct sockaddr *)&s6, - (char *)buf[0], sizeof(buf[0])); - memcpy(&s6.sin6_addr, + print_host((struct sockaddr *)&ss, (char *)buf[0], + sizeof(buf[0])); + memcpy(&((struct sockaddr_in6 *)&ss)->sin6_addr, msgbuf + offset + sizeof(ts) + 16, 16); - print_host((struct sockaddr *)&s6, - (char *)buf[1], sizeof(buf[1])); + print_host((struct sockaddr *)&ss, (char *)buf[1], + sizeof(buf[1])); log_debug("%s: start %s end %s", __func__, buf[0], buf[1]); break; diff --git a/iked/parse.y b/iked/parse.y index 1eb9b10..dd4bb67 100644 --- a/iked/parse.y +++ b/iked/parse.y @@ -289,7 +289,6 @@ struct ipsec_addr_wrap { struct sockaddr_storage address; uint8_t mask; int netaddress; - sa_family_t af; unsigned int type; unsigned int action; char *name; @@ -488,7 +487,8 @@ ikecfgvals : cfg { $$ = $1; } cfg : CONFIG STRING host_spec { const struct ipsec_xf *xf; - if ((xf = parse_xf($2, $3->af, cpxfs)) == NULL) { + xf = parse_xf($2, $3->address.ss_family, cpxfs); + if (xf == NULL) { yyerror("not a valid ikecfg option"); free($2); free($3); @@ -672,8 +672,9 @@ host_spec : STRING { host : host_spec { $$ = $1; } | host_spec '(' host_spec ')' { - if (($1->af != AF_UNSPEC) && ($3->af != AF_UNSPEC) && - ($3->af != $1->af)) { + if (($1->address.ss_family != AF_UNSPEC) && + ($3->address.ss_family != AF_UNSPEC) && + ($3->address.ss_family != $1->address.ss_family)) { yyerror("Flow NAT address family mismatch"); YYERROR; } @@ -1761,8 +1762,9 @@ host_v6(const char *s, int prefixlen) ipa = calloc(1, sizeof(struct ipsec_addr_wrap)); if (ipa == NULL) err(1, "host_v6: calloc"); - ipa->af = res->ai_family; memcpy(&ipa->address, res->ai_addr, sizeof(struct sockaddr_in6)); + ipa->address.ss_family = res->ai_family; + SET_SS_LEN(&ipa->address, sizeof(struct sockaddr_in6)); if (prefixlen > 128) prefixlen = 128; ipa->next = NULL; @@ -1809,14 +1811,13 @@ host_v4(const char *s, int mask) if (ipa == NULL) err(1, "host_v4: calloc"); - ina.sin_family = AF_INET; - SET_STORAGE_LEN((struct sockaddr_storage)ina, sizeof(ina)); memcpy(&ipa->address, &ina, sizeof(ina)); + ipa->address.ss_family = AF_INET; + SET_SS_LEN(&ipa->address, sizeof(ina)); ipa->name = strdup(s); if (ipa->name == NULL) err(1, "host_v4: strdup"); - ipa->af = AF_INET; ipa->next = NULL; ipa->tail = ipa; @@ -1832,7 +1833,7 @@ host_dns(const char *s, int mask) { struct ipsec_addr_wrap *ipa = NULL, *head = NULL; struct addrinfo hints, *res0, *res; - int error; + int error, sslen; char hbuf[NI_MAXHOST]; bzero(&hints, sizeof(struct addrinfo)); @@ -1852,22 +1853,26 @@ host_dns(const char *s, int mask) err(1, "host_dns: calloc"); switch (res->ai_family) { case AF_INET: - memcpy(&ipa->address, res->ai_addr, - sizeof(struct sockaddr_in)); + sslen = sizeof(struct sockaddr_in); break; case AF_INET6: - memcpy(&ipa->address, res->ai_addr, - sizeof(struct sockaddr_in6)); + sslen = sizeof(struct sockaddr_in6); + break; + default: + sslen = 0; break; } - error = getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, - sizeof(hbuf), NULL, 0, NI_NUMERICHOST); + if (sslen > 0) + memcpy(&ipa->address, res->ai_addr, sslen); + ipa->address.ss_family = res->ai_family; + SET_SS_LEN(&ipa->address, sslen); + error = getnameinfo((struct sockaddr *)&ipa->address, sslen, + hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST); if (error) err(1, "host_dns: getnameinfo"); ipa->name = strdup(hbuf); if (ipa->name == NULL) err(1, "host_dns: strdup"); - ipa->af = res->ai_family; ipa->next = NULL; ipa->tail = ipa; if (head == NULL) @@ -1883,7 +1888,7 @@ host_dns(const char *s, int mask) * have IPv6 address on a host, you cannot use dns/netmask * syntax. */ - if (ipa->af == AF_INET) + if (ipa->address.ss_family == AF_INET) set_ipmask(ipa, mask == -1 ? 32 : mask); else if (mask != -1) @@ -1914,7 +1919,7 @@ host_any(void) ipa = calloc(1, sizeof(struct ipsec_addr_wrap)); if (ipa == NULL) err(1, "host_any: calloc"); - ipa->af = AF_UNSPEC; + ipa->address.ss_family = AF_UNSPEC; ipa->netaddress = 1; ipa->tail = ipa; return (ipa); @@ -1943,15 +1948,16 @@ ifa_load(void) n = calloc(1, sizeof(struct ipsec_addr_wrap)); if (n == NULL) err(1, "ifa_load: calloc"); - n->af = ifa->ifa_addr->sa_family; + n->address.ss_family = ifa->ifa_addr->sa_family; + SET_SS_LEN(&n->address, SA_LEN(ifa->ifa_addr)); if ((n->name = strdup(ifa->ifa_name)) == NULL) err(1, "ifa_load: strdup"); - if (n->af == AF_INET) { + if (n->address.ss_family == AF_INET) { sa_in = (struct sockaddr_in *)ifa->ifa_addr; memcpy(&n->address, sa_in, sizeof(*sa_in)); sa_in = (struct sockaddr_in *)ifa->ifa_netmask; n->mask = mask2prefixlen((struct sockaddr *)sa_in); - } else if (n->af == AF_INET6) { + } else if (n->address.ss_family == AF_INET6) { sa_in6 = (struct sockaddr_in6 *)ifa->ifa_addr; memcpy(&n->address, sa_in6, sizeof(*sa_in6)); sa_in6 = (struct sockaddr_in6 *)ifa->ifa_netmask; @@ -1997,8 +2003,8 @@ ifa_exists(const char *ifa_name) #endif for (n = iftab; n; n = n->next) { - if (n->af == AF_LINK && !strncmp(n->name, ifa_name, - IFNAMSIZ)) + if (n->address.ss_family == AF_LINK && + !strncmp(n->name, ifa_name, IFNAMSIZ)) return (1); } @@ -2066,7 +2072,8 @@ ifa_lookup(const char *ifa_name) return (n); for (p = iftab; p; p = p->next) { - if (p->af != AF_INET && p->af != AF_INET6) + if (p->address.ss_family != AF_INET && + p->address.ss_family != AF_INET6) continue; if (strncmp(p->name, ifa_name, IFNAMSIZ)) continue; @@ -2076,7 +2083,7 @@ ifa_lookup(const char *ifa_name) memcpy(n, p, sizeof(struct ipsec_addr_wrap)); if ((n->name = strdup(p->name)) == NULL) err(1, "ifa_lookup: strdup"); - switch (n->af) { + switch (n->address.ss_family) { case AF_INET: set_ipmask(n, 32); break; @@ -2481,15 +2488,16 @@ create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, } if (peers && peers->src && peers->dst && - (peers->src->af != AF_UNSPEC) && (peers->dst->af != AF_UNSPEC) && - (peers->src->af != peers->dst->af)) + (peers->src->address.ss_family != AF_UNSPEC) && + (peers->dst->address.ss_family != AF_UNSPEC) && + (peers->src->address.ss_family != peers->dst->address.ss_family)) fatalx("create_ike: peer address family mismatch"); if (peers && (pol.pol_af != AF_UNSPEC) && - ((peers->src && (peers->src->af != AF_UNSPEC) && - (peers->src->af != pol.pol_af)) || - (peers->dst && (peers->dst->af != AF_UNSPEC) && - (peers->dst->af != pol.pol_af)))) + ((peers->src && (peers->src->address.ss_family != AF_UNSPEC) && + (peers->src->address.ss_family != pol.pol_af)) || + (peers->dst && (peers->dst->address.ss_family != AF_UNSPEC) && + (peers->dst->address.ss_family != pol.pol_af)))) fatalx("create_ike: policy address family mismatch"); ipa = ipb = NULL; @@ -2524,20 +2532,20 @@ create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, if (ipa) { memcpy(&pol.pol_local.addr, &ipa->address, sizeof(ipa->address)); - pol.pol_local.addr_af = ipa->af; + pol.pol_local.addr_af = ipa->address.ss_family; pol.pol_local.addr_mask = ipa->mask; pol.pol_local.addr_net = ipa->netaddress; if (pol.pol_af == AF_UNSPEC) - pol.pol_af = ipa->af; + pol.pol_af = ipa->address.ss_family; } if (ipb) { memcpy(&pol.pol_peer.addr, &ipb->address, sizeof(ipb->address)); - pol.pol_peer.addr_af = ipb->af; + pol.pol_peer.addr_af = ipb->address.ss_family; pol.pol_peer.addr_mask = ipb->mask; pol.pol_peer.addr_net = ipb->netaddress; if (pol.pol_af == AF_UNSPEC) - pol.pol_af = ipb->af; + pol.pol_af = ipb->address.ss_family; } if (ikelifetime) @@ -2630,14 +2638,14 @@ create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, ipa = ipa->next, ipb = ipb->next, j++) { memcpy(&flows[j].flow_src.addr, &ipa->address, sizeof(ipa->address)); - flows[j].flow_src.addr_af = ipa->af; + flows[j].flow_src.addr_af = ipa->address.ss_family; flows[j].flow_src.addr_mask = ipa->mask; flows[j].flow_src.addr_net = ipa->netaddress; flows[j].flow_src.addr_port = hosts->sport; memcpy(&flows[j].flow_dst.addr, &ipb->address, sizeof(ipb->address)); - flows[j].flow_dst.addr_af = ipb->af; + flows[j].flow_dst.addr_af = ipb->address.ss_family; flows[j].flow_dst.addr_mask = ipb->mask; flows[j].flow_dst.addr_net = ipb->netaddress; flows[j].flow_dst.addr_port = hosts->dport; @@ -2660,7 +2668,7 @@ create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, sizeof(ipa->address)); cfg->cfg.address.addr_mask = ipa->mask; cfg->cfg.address.addr_net = ipa->netaddress; - cfg->cfg.address.addr_af = ipa->af; + cfg->cfg.address.addr_af = ipa->address.ss_family; } if (dstid) { diff --git a/iked/util.c b/iked/util.c index c674846..d1dba33 100644 --- a/iked/util.c +++ b/iked/util.c @@ -42,23 +42,23 @@ extern int verbose; int socket_af(struct sockaddr *sa, in_port_t port) { + u_int salen; + errno = 0; switch (sa->sa_family) { case AF_INET: ((struct sockaddr_in *)sa)->sin_port = port; - SET_STORAGE_LEN((struct sockaddr_storage)sa, - sizeof(struct sockaddr_in)); + salen = sizeof(struct sockaddr_in); break; case AF_INET6: ((struct sockaddr_in6 *)sa)->sin6_port = port; - SET_STORAGE_LEN((struct sockaddr_storage)sa, - sizeof(struct sockaddr_in6)); + salen = sizeof(struct sockaddr_in6); break; default: errno = EPFNOSUPPORT; return (-1); } - + SET_SA_LEN(sa, salen); return (0); } @@ -340,7 +340,6 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, struct msghdr msg; struct cmsghdr *cmsg; struct in6_pktinfo *pkt6; - struct sockaddr_in *in; struct sockaddr_in6 *in6; ssize_t ret; union { @@ -376,28 +375,25 @@ recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, #if HAVE_DECL_IP_RECVDSTADDR if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) { - in = (struct sockaddr_in *)to; - in->sin_family = AF_INET; - SET_STORAGE_LEN(*(struct sockaddr_storage *) - in, sizeof(*in)); - memcpy(&in->sin_addr, CMSG_DATA(cmsg), - sizeof(struct in_addr)); + to->sa_family = AF_INET; + SET_SA_LEN(to, sizeof(struct sockaddr_in)); + memcpy(&((struct sockaddr_in *)to)->sin_addr, + CMSG_DATA(cmsg), sizeof(struct in_addr)); } #elif HAVE_DECL_IP_RECVORIGDSTADDR if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVORIGDSTADDR) { - in = (struct sockaddr_in *)to; - memcpy(in, CMSG_DATA(cmsg), sizeof(*in)); + memcpy(to, CMSG_DATA(cmsg), + sizeof(struct sockaddr_in)); } #endif break; case AF_INET6: if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) { + to->sa_family = AF_INET6; + SET_SA_LEN(to, sizeof(struct sockaddr_in6)); in6 = (struct sockaddr_in6 *)to; - in6->sin6_family = AF_INET6; - SET_STORAGE_LEN(*(struct sockaddr_storage *) - in6, sizeof(*in6)); pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg); memcpy(&in6->sin6_addr, &pkt6->ipi6_addr, sizeof(struct in6_addr)); diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h index 98782aa..7829c00 100644 --- a/openbsd-compat/openbsd-compat.h +++ b/openbsd-compat/openbsd-compat.h @@ -72,6 +72,14 @@ # endif #endif +#if !defined(SET_SA_LEN) +# if defined(HAVE_STRUCT_SOCKADDR_SA_LEN) +# define SET_SA_LEN(sa, len) ((sa)->sa_len = (len)) +# else +# define SET_SA_LEN(sa, len) (void)0 +# endif +#endif + /* From OpenBGPD portable */ #if !defined(SS_LEN) # if defined(HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN) @@ -81,19 +89,14 @@ # endif #endif -#ifdef HAVE_SS_LEN -# define STORAGE_LEN(X) ((X).ss_len) -# define SET_STORAGE_LEN(X, Y) do { STORAGE_LEN(X) = (Y); } while(0) -#elif defined(HAVE___SS_LEN) -# define STORAGE_LEN(X) ((X).__ss_len) -# define SET_STORAGE_LEN(X, Y) do { STORAGE_LEN(X) = (Y); } while(0) -#else -# define STORAGE_FAMILY(x) ((x).ss_family) -# define STORAGE_LEN(X) (STORAGE_FAMILY(X) == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)) -# define SET_STORAGE_LEN(X, Y) (void) 0 +#if !defined(SET_SS_LEN) +# if defined(HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN) +# define SET_SS_LEN(ss, len) ((ss)->ss_len = (len)) +# else +# define SET_SS_LEN(ss, len) SET_SA_LEN((struct sockaddr *)(ss), len) +# endif #endif - #ifndef HAVE_CLOSEFROM void closefrom(int); #endif From c1481fe60dd5dec3c7165966721e6c64d825194a Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Sun, 19 Jun 2016 14:59:45 -0700 Subject: [PATCH 36/39] Revert _INSTALL_IPSEC_POLICY hack --- iked/ikev2.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/iked/ikev2.c b/iked/ikev2.c index 1ed6af1..87360ed 100644 --- a/iked/ikev2.c +++ b/iked/ikev2.c @@ -4709,9 +4709,7 @@ int ikev2_childsa_enable(struct iked *env, struct iked_sa *sa) { struct iked_childsa *csa; -#if defined (_INSTALL_IPSEC_POLICY) struct iked_flow *flow, *oflow; -#endif if (sa->sa_ipcomp && sa->sa_cpi_in && sa->sa_cpi_out && ikev2_ipcomp_enable(env, sa) == -1) @@ -4734,7 +4732,6 @@ ikev2_childsa_enable(struct iked *env, struct iked_sa *sa) print_spi(csa->csa_spi.spi, csa->csa_spi.spi_size)); } -#if defined (_INSTALL_IPSEC_POLICY) TAILQ_FOREACH(flow, &sa->sa_flows, flow_entry) { if (flow->flow_loaded) continue; @@ -4756,7 +4753,6 @@ ikev2_childsa_enable(struct iked *env, struct iked_sa *sa) log_debug("%s: loaded flow %p", __func__, flow); } -#endif return (0); } From 6ab3f358367a6f9ae780894485380e7810b92058 Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Sun, 19 Jun 2016 15:32:57 -0700 Subject: [PATCH 37/39] Fix PREFIX In configure.ac, if $prefix evaluates to NONE (unspecified), use $ac_default_prefix instead. Use $_prefix internally so that we can test whether --prefix was specified or not. --- configure.ac | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 94c4ab0..4c0d2f9 100644 --- a/configure.ac +++ b/configure.ac @@ -1727,10 +1727,15 @@ AC_DEFINE_UNQUOTED([IKED_USER], ["$IKED_USER"], [non-privileged user for privilege separation]) AC_SUBST([IKED_USER]) +_prefix=`eval echo ${prefix}` +if test x$_prefix = xNONE; then + _prefix=$ac_default_prefix +fi + _sysconfdir=`eval echo ${sysconfdir}` case $_sysconfdir in NONE/*) - _sysconfdir=`echo $_sysconfdir | sed "s~NONE~$ac_default_prefix~"` ;; + _sysconfdir=`echo $_sysconfdir | sed "s~NONE~$_prefix~"` ;; esac ikedconf=`eval echo ${_sysconfdir}/iked.conf` @@ -2486,7 +2491,8 @@ if test "x$ZIP" != "x"; then AC_DEFINE_UNQUOTED([PATH_ZIP], ["$ZIP"], [Path to ZIP binary]) fi -AC_DEFINE_UNQUOTED([PREFIX], ["$prefix"], [Root directory prefix]) + +AC_DEFINE_UNQUOTED([PREFIX], ["$_prefix"], [Root directory prefix]) AC_DEFINE([_GNU_SOURCE], [1], [Enable GNU Extensions]) From 7966b1987aa69be3bc07c746f2520e9812e5e730 Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Sun, 19 Jun 2016 18:07:20 -0700 Subject: [PATCH 38/39] Missed one SET_STORAGE_LEN to SET_SS_LEN substitution --- iked/pfkey.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iked/pfkey.c b/iked/pfkey.c index c44b264..38d07ab 100644 --- a/iked/pfkey.c +++ b/iked/pfkey.c @@ -255,7 +255,7 @@ pfkey_flow(int sd, uint8_t satype, uint8_t action, struct iked_flow *flow) __func__, flow->flow_src.addr_af); return (-1); } - SET_STORAGE_LEN(smask, SS_LEN(ssrc)); + SET_SS_LEN(smask, SS_LEN(ssrc)); bzero(&sdst, sizeof(sdst)); bzero(&dmask, sizeof(dmask)); From ebfbdfa6dd5e10f8a3ac3715fc2733207f1bfe29 Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Thu, 23 Jun 2016 02:37:35 +0000 Subject: [PATCH 39/39] Fix previous commit now that I have OpenBSD running --- iked/pfkey.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iked/pfkey.c b/iked/pfkey.c index 38d07ab..3fec341 100644 --- a/iked/pfkey.c +++ b/iked/pfkey.c @@ -255,7 +255,7 @@ pfkey_flow(int sd, uint8_t satype, uint8_t action, struct iked_flow *flow) __func__, flow->flow_src.addr_af); return (-1); } - SET_SS_LEN(smask, SS_LEN(ssrc)); + SET_SS_LEN(&smask, SS_LEN(&ssrc)); bzero(&sdst, sizeof(sdst)); bzero(&dmask, sizeof(dmask));