chiark / gitweb /
Import release 0.1.16 v0.1.16
authorStephen Early <steve@greenend.org.uk>
Fri, 19 Sep 2003 14:40:00 +0000 (15:40 +0100)
committerStephen Early <steve@greenend.org.uk>
Wed, 18 May 2011 17:53:02 +0000 (18:53 +0100)
31 files changed:
CREDITS
INSTALL
Makefile.in
NEWS
README
TODO
ac_prog_cc_no_writeable_strings.m4 [new file with mode: 0644]
alloca.c [deleted file]
conffile.c
config.h.in
configure
configure.in
debian/changelog
debian/dirs [deleted file]
example.conf
getopt.c
hackypar.c [new file with mode: 0644]
hackypar.h [new file with mode: 0644]
ipaddr.c
make-secnet-sites
netlink.c
rsa.c
secnet.c
secnet.h
serpent.c
serpent.h
site.c
transform.c
tun.c
udp.c
util.h

diff --git a/CREDITS b/CREDITS
index 3b078bd..c934ab7 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1,6 +1,7 @@
 Stephen Early <steve@greenend.org.uk> - original author
 Ross Anderson, Eli Biham, Lars Knudsen - serpent
 Colin Plumb, Ian Jackson - MD5 implementation
+Ian Jackson - hacky parallelism, serpent keying and endianness bugfixes
 Steve Reid <sreid@sea-to-sky.net>, James H. Brown <jbrown@burgoyne.com> - 
   SHA1 implementation
 Cendio Systems AB - ipaddr.py
@@ -8,4 +9,5 @@ Mark Martinec <mark.martinec@ijs.si> - portable snprintf
 
 Simon Tatham, Jonathan Amery, Ian Jackson - testing and debugging
 Simon Tatham - RSA signatures using Chinese Remainder Theorem
-Richard Kettlewell - assorted bugfixes
+Simon Tatham - endianness cleanups in transform.c
+Richard Kettlewell, Peter Benie - assorted bugfixes
diff --git a/INSTALL b/INSTALL
index 49476d8..08eac9a 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -4,11 +4,6 @@ USE AT YOUR OWN RISK.  THIS IS ALPHA TEST SOFTWARE.  I DO NOT
 GUARANTEE THAT THERE WILL BE PROTOCOL COMPATIBILITY BETWEEN DIFFERENT
 VERSIONS.
 
-PROTOCOL COMPATIBILITY WAS BROKEN BETWEEN secnet-0.06, secnet-0.07 AND
-secnet-0.08 FOR ENDIANNESS FIXES.
-
-THERE WILL BE ANOTHER CHANGE IN PROTOCOL IN THE secnet-0.1.x SERIES
-
 * Preparation
 
 ** System software support
@@ -32,12 +27,6 @@ linux/Documentation/networking/tuntap.txt
 If you're using TUN/TAP on a platform other than Linux-2.4, see
 http://vtun.sourceforge.net/tun/
 
-Note than TUN comes in several flavours.  Their names in the
-configuration file are:
- tun:  Linux-2.4; only one device file (usually /dev/net/tun)
- tun-old:  Linux-2.2, BSD; device files /dev/tun*
- tun-solaris:  Solaris (not yet implemented)
-
 ** System and network configuration
 
 If you intend to start secnet as root, I suggest you create a userid
@@ -118,7 +107,7 @@ If installing for the first time, do
 
 # cp example.conf /etc/secnet/secnet.conf
 # cd /etc/secnet
-# ssh-keygen -f key -N ""
+# ssh-keygen -f key -t rsa1 -N ""
 
 [On BSD use
 $ LDFLAGS="-L/usr/local/lib" ./configure
index af33bf5..60e63cd 100644 (file)
@@ -18,7 +18,7 @@
 .PHONY:        all clean realclean distclean dist install
 
 PACKAGE:=secnet
-VERSION:=0.1.15
+VERSION:=0.1.16
 
 @SET_MAKE@
 
@@ -31,6 +31,9 @@ CC:=@CC@
 INSTALL:=@INSTALL@
 INSTALL_PROGRAM:=@INSTALL_PROGRAM@
 
+# Use -DHACKY_PARALLEL if you are compiling secnet for an extremely
+# slow machine
+#CFLAGS:=-Wall @WRITESTRINGS@ @CFLAGS@ -DHACKY_PARALLEL
 CFLAGS:=-Wall @WRITESTRINGS@ @CFLAGS@
 ALL_CFLAGS:=@DEFS@ -I$(srcdir) -I. $(CFLAGS)
 LDFLAGS:=@LDFLAGS@
@@ -47,15 +50,17 @@ TARGETS:=secnet
 OBJECTS:=secnet.o util.o conffile.yy.o conffile.tab.o conffile.o modules.o \
        resolver.o random.o udp.o site.o transform.o netlink.o rsa.o dh.o \
        serpent.o md5.o version.o tun.o slip.o sha1.o ipaddr.o log.o \
-       process.o @LIBOBJS@
+       process.o @LIBOBJS@ \
+       hackypar.o
 
+DISTDIRS:=debian
 DISTFILES:=BUGS COPYING CREDITS INSTALL LICENSE.txt Makefile.in \
        NEWS NOTES README TODO \
-       alloca.c \
+       ac_prog_cc_no_writeable_strings.m4 \
        conffile.c conffile.fl conffile.h conffile.y \
        conffile_internal.h config.h.bot \
        config.h.in config.h.top configure \
-       configure.in debian depend.sh dh.c \
+       configure.in depend.sh dh.c \
        example.conf \
        getopt.c getopt1.c getopt.h \
        install-sh ipaddr.c ipaddr.h ipaddr.py linux log.c \
@@ -66,7 +71,10 @@ DISTFILES:=BUGS COPYING CREDITS INSTALL LICENSE.txt Makefile.in \
        secnet.c secnet.h serpent.c serpent.h serpentsboxes.h \
        snprintf.c snprintf.h \
        sha1.c site.c slip.c stamp-h.in transform.c tun.c udp.c \
-       unaligned.h util.c util.h
+       unaligned.h util.c util.h \
+       hackypar.c hackypar.h
+DISTSUBDIRS:=debian/conffiles debian/copyright debian/changelog \
+       debian/control debian/init debian/rules
 
 %.c:   %.y
 
@@ -144,7 +152,9 @@ pfname:=$(PACKAGE)-$(VERSION)
 dist:
        $(RM) -rf $(pfname)
        mkdir $(pfname)
+       for i in $(DISTDIRS) ; do mkdir $(pfname)/$$i ; done
        for i in $(DISTFILES) ; do ln -s ../$(srcdir)/$$i $(pfname)/ ; done
+       for i in $(DISTSUBDIRS) ; do ln -s ../../$(srcdir)/$$i $(pfname)/$$i ; done
        tar hcf ../$(pfname).tar --exclude=CVS --exclude=.cvsignore $(pfname)
        gzip -9f ../$(pfname).tar
        $(RM) -rf $(pfname)
diff --git a/NEWS b/NEWS
index 4af3024..4b50c59 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,22 +1,53 @@
 * Planned for the future
 
-Netlink device that implements an Ethernet bridge.
-
-Modular transform code: choice of block ciphers, modes, sequence
-numbers / timestamps, etc. similar to IWJ's udptunnel
-
-Path-MTU discovery for each tunnel, and fragmentation/DF support in
-netlink code.
-
-Separation of device drivers from IP router code - driver produces a
-stream of packets (which has a tag indicating type and parameters).
-Router module can be connected to stream to multiplex it between
-different tunnels.
-
-Support for dynamic creation of streams/tunnels to cope with laptops,
-etc.
-
-See also file "TODO".
+Please note that the 0.1 series of secnet releases is now 'maintenance
+only'; further development continues in secnet-0.2.
+
+* Planned for version 0.1.17
+
+Debconf support - if you are using the Debian packaged version and
+your secnet configuration is autogenerated using debconf then the
+upgrade to version 0.2.0 should just involve installing the package;
+an appropriate 0.2-style configuration file will be generated
+automatically.
+
+* New in version 0.1.16
+
+XXX XXX PROTOCOL COMPATIBILITY IS BROKEN BETWEEN VERSION 0.1.16 AND
+XXX XXX ALL PREVIOUS VERSIONS.
+
+Bugfix: rsa.c private-key now works properly when you choose not to
+verify it.
+
+Bugfix: serpent key setup was only using the first 8 bytes of the key
+material. (Oops!)  Ian Jackson contributed a fix so the full 32 bytes
+are used, in big-endian mode.
+
+Debatable-bugfix: RSA operations now use PKCS1 v1.5-style padding
+
+"Hacky parallelism" contributed by Ian Jackson; this permits
+public-key operations to be performed in a subprocess during key
+exchange, to make secnet more usable on very slow machines.  This is
+not compiled in by default; if you find you need it (because key
+exchanges are taking more than a second or two) then add
+-DHACKY_PARALLEL to FLAGS in the Makefile.in and recompile.
+
+udp module updates from Peter Benie:
+  1) Handle the case where authbind-helper terminates with a signal
+  2) Cope with signals being delivered during waitpid
+  3) Add 'address' (optional) to the udp settings. This is an IP address
+     that the socket will be bound to.
+  4) Change the endianess of the arguments to authbind-helper.
+     sprintf("%04X") already translates from machine repesentation to most
+     significant octet first so htons reversed it again.
+
+All uses of alloca() expunged by Peter Benie.
+
+make-secnet-sites now supports configurations where each tunnel gets
+its own interface on the host, and the IP router code in secnet is
+disabled.  make-secnet-sites has been rewritten for clarity.  For
+information on how to configure secnet for one-interface-per-tunnel,
+see the example.conf file.
 
 * New in version 0.1.15
 
diff --git a/README b/README
index 46df881..564b216 100644 (file)
--- a/README
+++ b/README
@@ -2,7 +2,7 @@ secnet - flexible VPN software
 
 * Copying
 
-secnet is Copyright (C) 1995--2001 Stephen Early <steve@greenend.org.uk>
+secnet is Copyright (C) 1995--2003 Stephen Early <steve@greenend.org.uk>
 It is distributed under the terms of the GNU General Public License,
 version 2 or later.  See the file COPYING for more information.
 
@@ -139,6 +139,9 @@ some keys in the root dictionary.  The main ones are:
   makelist:   turns a dictionary (arg1) into a list of definitions
               (ignoring the keys)
   readfile:   reads a file (arg1) and returns it as a string
+  map:        applies the closure specified as arg1 to each of the
+              remaining elements in the list in turn.  Returns a list
+              made up of the outputs of the closure.
 
 Keys defined by modules are described below, in the module
 documentation.
@@ -196,6 +199,7 @@ Defines:
   udp (closure => comm closure)
 
 udp: dict argument
+  address (string): IP address to listen and send on
   port (integer): UDP port to listen and send on
   buffer (buffer closure): buffer for incoming packets
   authbind (string): optional, path to authbind-helper program
diff --git a/TODO b/TODO
index 8e8800d..2d5e447 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,13 +1,9 @@
 dh.c: change format to binary from decimal string (without introducing
 endianness problems)
 
-log.c: implement a file-descriptor-to-log module
-
 netlink.c: test the 'allow_route' option properly.
 Add fragmentation code.  Check that we comply with RFC1812.
 
-process.c: capture output from children in sys_cmd() and log it
-
 random.c: test properly
 
 resolver.c: ought to return a list of addresses for each address; the
@@ -16,9 +12,6 @@ site code ought to remember them and try contacting them in turn.
 rsa.c: check padding type, change format to binary from decimal string
 (without introducing endianness problems)
 
-secnet.c: optionally pipe stderr to a log when we become a daemon.
-Don't just close it.
-
 site.c: Abandon key exchanges when a bad packet is received. Modify
 protocol to include version fields, as described in the NOTES
 file. Implement keepalive mode. Make policy about when to initiate key
diff --git a/ac_prog_cc_no_writeable_strings.m4 b/ac_prog_cc_no_writeable_strings.m4
new file mode 100644 (file)
index 0000000..273085c
--- /dev/null
@@ -0,0 +1,113 @@
+dnl @synopsis AC_PROG_CC_NO_WRITEABLE_STRINGS(substvar [,hard])
+dnl
+dnl Try to find a compiler option that warns when a stringliteral is
+dnl used in a place that could potentially modify the address. This
+dnl should warn on giving an stringliteral to a function that asks of
+dnl a non-const-modified char-pointer.
+dnl
+dnl The sanity check is done by looking at string.h which has a set
+dnl of strcpy definitions that should be defined with const-modifiers
+dnl to not emit a warning in all so many places.
+dnl
+dnl Currently this macro knows about GCC.
+dnl hopefully will evolve to use:    Solaris C compiler,
+dnl Digital Unix C compiler, C for AIX Compiler, HP-UX C compiler,
+dnl and IRIX C compiler.
+dnl
+dnl @version $Id: ac_prog_cc_no_writeable_strings.m4,v 1.1 2002/02/20 16:18:18 steve Exp $
+dnl @author Guido Draheim <guidod@gmx.de>
+dnl
+AC_DEFUN([AC_PROG_CC_NO_WRITEABLE_STRINGS], [
+  pushdef([CV],ac_cv_prog_cc_no_writeable_strings)dnl
+  hard=$2
+  if test -z "$hard"; then
+    msg="C to warn about writing to stringliterals"
+  else
+    msg="C to prohibit any write to stringliterals"
+  fi
+  AC_CACHE_CHECK($msg, CV, [
+  cat > conftest.c <<EOF
+#include <string.h>
+int main (void)
+{
+   char test[[16]];
+   if (strcpy (test, "test")) return 0;
+   return 1;
+}
+EOF
+  dnl GCC
+  if test "$GCC" = "yes"; 
+  then
+       if test -z "$hard"; then
+           CV="-Wwrite-strings"
+        else
+            CV="-fno-writable-strings -Wwrite-strings"
+        fi
+
+        if test -n "`${CC-cc} -c $CV conftest.c 2>&1`" ; then
+            CV="suppressed: string.h"
+        fi
+
+  dnl Solaris C compiler
+  elif  $CC -flags 2>&1 | grep "Xc.*strict ANSI C" > /dev/null 2>&1 &&
+       $CC -c -xstrconst conftest.c > /dev/null 2>&1 &&
+       test -f conftest.o 
+  then
+        # strings go into readonly segment
+       CV="-xstrconst"
+
+       rm conftest.o
+        if test -n "`${CC-cc} -c $CV conftest.c 2>&1`" ; then
+             CV="suppressed: string.h"
+        fi
+  
+  dnl HP-UX C compiler
+  elif  $CC > /dev/null 2>&1 &&
+       $CC -c +ESlit conftest.c > /dev/null 2>&1 &&
+       test -f conftest.o 
+  then
+       # strings go into readonly segment
+       CV="+ESlit"
+       
+       rm conftest.o
+        if test -n "`${CC-cc} -c $CV conftest.c 2>&1`" ; then
+             CV="suppressed: string.h"
+        fi
+
+  dnl Digital Unix C compiler
+  elif ! $CC > /dev/null 2>&1 &&
+       $CC -c -readonly_strings conftest.c > /dev/null 2>&1 &&
+       test -f conftest.o
+  then 
+       # strings go into readonly segment
+       CV="-readonly_strings"
+       
+       rm conftest.o
+        if test -n "`${CC-cc} -c $CV conftest.c 2>&1`" ; then
+             CV="suppressed: string.h"
+        fi
+
+  dnl C for AIX Compiler
+
+  dnl IRIX C compiler
+       # -use_readonly_const is the default for IRIX C, 
+       # puts them into .rodata, but they are copied later.
+       # need to be "-G0 -rdatashared" for strictmode but
+       # I am not sure what effect that has really.
+
+  fi
+  rm -f conftest.*
+  ])
+  if test -z "[$]$1" ; then
+    if test -n "$CV" ; then
+      case "$CV" in
+        suppressed*) $1="" ;; # known but suppressed
+        *)  $1="$CV" ;;
+      esac
+    fi
+  fi
+  AC_SUBST($1)
+  popdef([CV])dnl
+])
+
+
diff --git a/alloca.c b/alloca.c
deleted file mode 100644 (file)
index bc34529..0000000
--- a/alloca.c
+++ /dev/null
@@ -1,460 +0,0 @@
-/* alloca.c -- allocate automatically reclaimed memory
-   (Mostly) portable public-domain implementation -- D A Gwyn
-
-   This implementation of the PWB library alloca function,
-   which is used to allocate space off the run-time stack so
-   that it is automatically reclaimed upon procedure exit,
-   was inspired by discussions with J. Q. Johnson of Cornell.
-   J.Otto Tennant <jot@cray.com> contributed the Cray support.
-
-   There are some preprocessor constants that can
-   be defined when compiling for your specific system, for
-   improved efficiency; however, the defaults should be okay.
-
-   The general concept of this implementation is to keep
-   track of all alloca-allocated blocks, and reclaim any
-   that are found to be deeper in the stack than the current
-   invocation.  This heuristic does not reclaim storage as
-   soon as it becomes invalid, but it will do so eventually.
-
-   As a special case, alloca(0) reclaims storage without
-   allocating any.  It is a good idea to use alloca(0) in
-   your main control loop, etc. to force garbage collection.  */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-/* If compiling with GCC, this file's not needed.  */
-#ifndef alloca
-
-#ifdef emacs
-#ifdef static
-/* actually, only want this if static is defined as ""
-   -- this is for usg, in which emacs must undefine static
-   in order to make unexec workable
-   */
-#ifndef STACK_DIRECTION
-you
-lose
--- must know STACK_DIRECTION at compile-time
-#endif /* STACK_DIRECTION undefined */
-#endif /* static */
-#endif /* emacs */
-
-/* If your stack is a linked list of frames, you have to
-   provide an "address metric" ADDRESS_FUNCTION macro.  */
-
-#ifdef CRAY
-long i00afunc ();
-#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
-#else
-#define ADDRESS_FUNCTION(arg) &(arg)
-#endif
-
-#if __STDC__
-typedef void *pointer;
-#else
-typedef char *pointer;
-#endif
-
-#define        NULL    0
-
-/* Define STACK_DIRECTION if you know the direction of stack
-   growth for your system; otherwise it will be automatically
-   deduced at run-time.
-
-   STACK_DIRECTION > 0 => grows toward higher addresses
-   STACK_DIRECTION < 0 => grows toward lower addresses
-   STACK_DIRECTION = 0 => direction of growth unknown  */
-
-#ifndef STACK_DIRECTION
-#define        STACK_DIRECTION 0       /* Direction unknown.  */
-#endif
-
-#if STACK_DIRECTION != 0
-
-#define        STACK_DIR       STACK_DIRECTION /* Known at compile-time.  */
-
-#else /* STACK_DIRECTION == 0; need run-time code.  */
-
-static int stack_dir;          /* 1 or -1 once known.  */
-#define        STACK_DIR       stack_dir
-
-static void
-find_stack_direction ()
-{
-  static char *addr = NULL;    /* Address of first `dummy', once known.  */
-  auto char dummy;             /* To get stack address.  */
-
-  if (addr == NULL)
-    {                          /* Initial entry.  */
-      addr = ADDRESS_FUNCTION (dummy);
-
-      find_stack_direction (); /* Recurse once.  */
-    }
-  else
-    {
-      /* Second entry.  */
-      if (ADDRESS_FUNCTION (dummy) > addr)
-       stack_dir = 1;          /* Stack grew upward.  */
-      else
-       stack_dir = -1;         /* Stack grew downward.  */
-    }
-}
-
-#endif /* STACK_DIRECTION == 0 */
-
-/* An "alloca header" is used to:
-   (a) chain together all alloca'ed blocks;
-   (b) keep track of stack depth.
-
-   It is very important that sizeof(header) agree with malloc
-   alignment chunk size.  The following default should work okay.  */
-
-#ifndef        ALIGN_SIZE
-#define        ALIGN_SIZE      sizeof(double)
-#endif
-
-typedef union hdr
-{
-  char align[ALIGN_SIZE];      /* To force sizeof(header).  */
-  struct
-    {
-      union hdr *next;         /* For chaining headers.  */
-      char *deep;              /* For stack depth measure.  */
-    } h;
-} header;
-
-static header *last_alloca_header = NULL;      /* -> last alloca header.  */
-
-/* Return a pointer to at least SIZE bytes of storage,
-   which will be automatically reclaimed upon exit from
-   the procedure that called alloca.  Originally, this space
-   was supposed to be taken from the current stack frame of the
-   caller, but that method cannot be made to work for some
-   implementations of C, for example under Gould's UTX/32.  */
-
-pointer
-alloca (size)
-     unsigned size;
-{
-  auto char probe;             /* Probes stack depth: */
-  register char *depth = ADDRESS_FUNCTION (probe);
-
-#if STACK_DIRECTION == 0
-  if (STACK_DIR == 0)          /* Unknown growth direction.  */
-    find_stack_direction ();
-#endif
-
-  /* Reclaim garbage, defined as all alloca'd storage that
-     was allocated from deeper in the stack than currently. */
-
-  {
-    register header *hp;       /* Traverses linked list.  */
-
-    for (hp = last_alloca_header; hp != NULL;)
-      if ((STACK_DIR > 0 && hp->h.deep > depth)
-         || (STACK_DIR < 0 && hp->h.deep < depth))
-       {
-         register header *np = hp->h.next;
-
-         free ((pointer) hp);  /* Collect garbage.  */
-
-         hp = np;              /* -> next header.  */
-       }
-      else
-       break;                  /* Rest are not deeper.  */
-
-    last_alloca_header = hp;   /* -> last valid storage.  */
-  }
-
-  if (size == 0)
-    return NULL;               /* No allocation required.  */
-
-  /* Allocate combined header + user data storage.  */
-
-  {
-    register pointer new = malloc (sizeof (header) + size);
-    /* Address of header.  */
-
-    ((header *) new)->h.next = last_alloca_header;
-    ((header *) new)->h.deep = depth;
-
-    last_alloca_header = (header *) new;
-
-    /* User storage begins just after header.  */
-
-    return (pointer) ((char *) new + sizeof (header));
-  }
-}
-
-#ifdef CRAY
-
-#ifdef DEBUG_I00AFUNC
-#include <stdio.h>
-#endif
-
-#ifndef CRAY_STACK
-#define CRAY_STACK
-#ifndef CRAY2
-/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
-struct stack_control_header
-  {
-    long shgrow:32;            /* Number of times stack has grown.  */
-    long shaseg:32;            /* Size of increments to stack.  */
-    long shhwm:32;             /* High water mark of stack.  */
-    long shsize:32;            /* Current size of stack (all segments).  */
-  };
-
-/* The stack segment linkage control information occurs at
-   the high-address end of a stack segment.  (The stack
-   grows from low addresses to high addresses.)  The initial
-   part of the stack segment linkage control information is
-   0200 (octal) words.  This provides for register storage
-   for the routine which overflows the stack.  */
-
-struct stack_segment_linkage
-  {
-    long ss[0200];             /* 0200 overflow words.  */
-    long sssize:32;            /* Number of words in this segment.  */
-    long ssbase:32;            /* Offset to stack base.  */
-    long:32;
-    long sspseg:32;            /* Offset to linkage control of previous
-                                  segment of stack.  */
-    long:32;
-    long sstcpt:32;            /* Pointer to task common address block.  */
-    long sscsnm;               /* Private control structure number for
-                                  microtasking.  */
-    long ssusr1;               /* Reserved for user.  */
-    long ssusr2;               /* Reserved for user.  */
-    long sstpid;               /* Process ID for pid based multi-tasking.  */
-    long ssgvup;               /* Pointer to multitasking thread giveup.  */
-    long sscray[7];            /* Reserved for Cray Research.  */
-    long ssa0;
-    long ssa1;
-    long ssa2;
-    long ssa3;
-    long ssa4;
-    long ssa5;
-    long ssa6;
-    long ssa7;
-    long sss0;
-    long sss1;
-    long sss2;
-    long sss3;
-    long sss4;
-    long sss5;
-    long sss6;
-    long sss7;
-  };
-
-#else /* CRAY2 */
-/* The following structure defines the vector of words
-   returned by the STKSTAT library routine.  */
-struct stk_stat
-  {
-    long now;                  /* Current total stack size.  */
-    long maxc;                 /* Amount of contiguous space which would
-                                  be required to satisfy the maximum
-                                  stack demand to date.  */
-    long high_water;           /* Stack high-water mark.  */
-    long overflows;            /* Number of stack overflow ($STKOFEN) calls.  */
-    long hits;                 /* Number of internal buffer hits.  */
-    long extends;              /* Number of block extensions.  */
-    long stko_mallocs;         /* Block allocations by $STKOFEN.  */
-    long underflows;           /* Number of stack underflow calls ($STKRETN).  */
-    long stko_free;            /* Number of deallocations by $STKRETN.  */
-    long stkm_free;            /* Number of deallocations by $STKMRET.  */
-    long segments;             /* Current number of stack segments.  */
-    long maxs;                 /* Maximum number of stack segments so far.  */
-    long pad_size;             /* Stack pad size.  */
-    long current_address;      /* Current stack segment address.  */
-    long current_size;         /* Current stack segment size.  This
-                                  number is actually corrupted by STKSTAT to
-                                  include the fifteen word trailer area.  */
-    long initial_address;      /* Address of initial segment.  */
-    long initial_size;         /* Size of initial segment.  */
-  };
-
-/* The following structure describes the data structure which trails
-   any stack segment.  I think that the description in 'asdef' is
-   out of date.  I only describe the parts that I am sure about.  */
-
-struct stk_trailer
-  {
-    long this_address;         /* Address of this block.  */
-    long this_size;            /* Size of this block (does not include
-                                  this trailer).  */
-    long unknown2;
-    long unknown3;
-    long link;                 /* Address of trailer block of previous
-                                  segment.  */
-    long unknown5;
-    long unknown6;
-    long unknown7;
-    long unknown8;
-    long unknown9;
-    long unknown10;
-    long unknown11;
-    long unknown12;
-    long unknown13;
-    long unknown14;
-  };
-
-#endif /* CRAY2 */
-#endif /* not CRAY_STACK */
-
-#ifdef CRAY2
-/* Determine a "stack measure" for an arbitrary ADDRESS.
-   I doubt that "lint" will like this much. */
-
-static long
-i00afunc (long *address)
-{
-  struct stk_stat status;
-  struct stk_trailer *trailer;
-  long *block, size;
-  long result = 0;
-
-  /* We want to iterate through all of the segments.  The first
-     step is to get the stack status structure.  We could do this
-     more quickly and more directly, perhaps, by referencing the
-     $LM00 common block, but I know that this works.  */
-
-  STKSTAT (&status);
-
-  /* Set up the iteration.  */
-
-  trailer = (struct stk_trailer *) (status.current_address
-                                   + status.current_size
-                                   - 15);
-
-  /* There must be at least one stack segment.  Therefore it is
-     a fatal error if "trailer" is null.  */
-
-  if (trailer == 0)
-    abort ();
-
-  /* Discard segments that do not contain our argument address.  */
-
-  while (trailer != 0)
-    {
-      block = (long *) trailer->this_address;
-      size = trailer->this_size;
-      if (block == 0 || size == 0)
-       abort ();
-      trailer = (struct stk_trailer *) trailer->link;
-      if ((block <= address) && (address < (block + size)))
-       break;
-    }
-
-  /* Set the result to the offset in this segment and add the sizes
-     of all predecessor segments.  */
-
-  result = address - block;
-
-  if (trailer == 0)
-    {
-      return result;
-    }
-
-  do
-    {
-      if (trailer->this_size <= 0)
-       abort ();
-      result += trailer->this_size;
-      trailer = (struct stk_trailer *) trailer->link;
-    }
-  while (trailer != 0);
-
-  /* We are done.  Note that if you present a bogus address (one
-     not in any segment), you will get a different number back, formed
-     from subtracting the address of the first block.  This is probably
-     not what you want.  */
-
-  return (result);
-}
-
-#else /* not CRAY2 */
-/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
-   Determine the number of the cell within the stack,
-   given the address of the cell.  The purpose of this
-   routine is to linearize, in some sense, stack addresses
-   for alloca.  */
-
-static long
-i00afunc (long address)
-{
-  long stkl = 0;
-
-  long size, pseg, this_segment, stack;
-  long result = 0;
-
-  struct stack_segment_linkage *ssptr;
-
-  /* Register B67 contains the address of the end of the
-     current stack segment.  If you (as a subprogram) store
-     your registers on the stack and find that you are past
-     the contents of B67, you have overflowed the segment.
-
-     B67 also points to the stack segment linkage control
-     area, which is what we are really interested in.  */
-
-  stkl = CRAY_STACKSEG_END ();
-  ssptr = (struct stack_segment_linkage *) stkl;
-
-  /* If one subtracts 'size' from the end of the segment,
-     one has the address of the first word of the segment.
-
-     If this is not the first segment, 'pseg' will be
-     nonzero.  */
-
-  pseg = ssptr->sspseg;
-  size = ssptr->sssize;
-
-  this_segment = stkl - size;
-
-  /* It is possible that calling this routine itself caused
-     a stack overflow.  Discard stack segments which do not
-     contain the target address.  */
-
-  while (!(this_segment <= address && address <= stkl))
-    {
-#ifdef DEBUG_I00AFUNC
-      fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
-#endif
-      if (pseg == 0)
-       break;
-      stkl = stkl - pseg;
-      ssptr = (struct stack_segment_linkage *) stkl;
-      size = ssptr->sssize;
-      pseg = ssptr->sspseg;
-      this_segment = stkl - size;
-    }
-
-  result = address - this_segment;
-
-  /* If you subtract pseg from the current end of the stack,
-     you get the address of the previous stack segment's end.
-     This seems a little convoluted to me, but I'll bet you save
-     a cycle somewhere.  */
-
-  while (pseg != 0)
-    {
-#ifdef DEBUG_I00AFUNC
-      fprintf (stderr, "%011o %011o\n", pseg, size);
-#endif
-      stkl = stkl - pseg;
-      ssptr = (struct stack_segment_linkage *) stkl;
-      size = ssptr->sssize;
-      pseg = ssptr->sspseg;
-      result += size;
-    }
-  return (result);
-}
-
-#endif /* not CRAY2 */
-#endif /* CRAY */
-
-#endif /* no alloca */
index b17517b..660606e 100644 (file)
@@ -466,6 +466,9 @@ static dict_t *process_config(struct p_node *c)
     context=root;
 
     /* Predefined keys for boolean values */
+    /* "nowise" and "verily" have the advantage of being the same
+       length, so they line up nicely...  thanks VKC and SGT (who also
+       point out that "mayhap" is a good "maybe" value as well) */
     i=new_item(t_bool,no_loc);
     i->data.bool=False;
     false=list_append(NULL,i);
@@ -478,12 +481,18 @@ static dict_t *process_config(struct p_node *c)
     dict_add(root,"no",false);
     dict_add(root,"No",false);
     dict_add(root,"NO",false);
+    dict_add(root,"nowise",false);
+    dict_add(root,"Nowise",false);
+    dict_add(root,"NOWISE",false);
     dict_add(root,"true",true);
     dict_add(root,"True",true);
     dict_add(root,"TRUE",true);
     dict_add(root,"yes",true);
     dict_add(root,"Yes",true);
     dict_add(root,"YES",true);
+    dict_add(root,"verily",true);
+    dict_add(root,"Verily",true);
+    dict_add(root,"VERILY",true);
 
     add_closure(root,"makelist",makelist);
     add_closure(root,"readfile",readfile);
@@ -619,6 +628,7 @@ void add_closure(dict_t *dict, cstring_t name, apply_fn apply)
     closure_t *c;
     c=safe_malloc(sizeof(*c),"add_closure");
     c->description=name;
+    c->type=CL_PURE;
     c->apply=apply;
     c->interface=NULL;
 
index 8492df2..ec607ac 100644 (file)
@@ -3,28 +3,6 @@
 #define _CONFIG_H
 
 
-/* Define if using alloca.c.  */
-#undef C_ALLOCA
-
-/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
-   This function is required for alloca.c support on those systems.  */
-#undef CRAY_STACKSEG_END
-
-/* Define if you have alloca, as a function or macro.  */
-#undef HAVE_ALLOCA
-
-/* Define if you have <alloca.h> and it should be used (not on Ultrix).  */
-#undef HAVE_ALLOCA_H
-
-/* If using the C implementation of alloca, define if you know the
-   direction of stack growth for your system; otherwise it will be
-   automatically deduced at run-time.
- STACK_DIRECTION > 0 => grows toward higher addresses
- STACK_DIRECTION < 0 => grows toward lower addresses
- STACK_DIRECTION = 0 => direction of growth unknown
- */
-#undef STACK_DIRECTION
-
 /* Define if you have the ANSI C header files.  */
 #undef STDC_HEADERS
 
index fecb0ca..c55421e 100755 (executable)
--- a/configure
+++ b/configure
@@ -2211,240 +2211,6 @@ LIBOBJS="$LIBOBJS snprintf.o"
 fi
 done
 
-# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
-# for constant arguments.  Useless!
-echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6
-echo "configure:2218: checking for working alloca.h" >&5
-if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2223 "configure"
-#include "confdefs.h"
-#include <alloca.h>
-int main() {
-char *p = alloca(2 * sizeof(int));
-; return 0; }
-EOF
-if { (eval echo configure:2230: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  ac_cv_header_alloca_h=yes
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  ac_cv_header_alloca_h=no
-fi
-rm -f conftest*
-fi
-
-echo "$ac_t""$ac_cv_header_alloca_h" 1>&6
-if test $ac_cv_header_alloca_h = yes; then
-  cat >> confdefs.h <<\EOF
-#define HAVE_ALLOCA_H 1
-EOF
-
-fi
-
-echo $ac_n "checking for alloca""... $ac_c" 1>&6
-echo "configure:2251: checking for alloca" >&5
-if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2256 "configure"
-#include "confdefs.h"
-
-#ifdef __GNUC__
-# define alloca __builtin_alloca
-#else
-# ifdef _MSC_VER
-#  include <malloc.h>
-#  define alloca _alloca
-# else
-#  if HAVE_ALLOCA_H
-#   include <alloca.h>
-#  else
-#   ifdef _AIX
- #pragma alloca
-#   else
-#    ifndef alloca /* predefined by HP cc +Olibcalls */
-char *alloca ();
-#    endif
-#   endif
-#  endif
-# endif
-#endif
-
-int main() {
-char *p = (char *) alloca(1);
-; return 0; }
-EOF
-if { (eval echo configure:2284: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  ac_cv_func_alloca_works=yes
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  ac_cv_func_alloca_works=no
-fi
-rm -f conftest*
-fi
-
-echo "$ac_t""$ac_cv_func_alloca_works" 1>&6
-if test $ac_cv_func_alloca_works = yes; then
-  cat >> confdefs.h <<\EOF
-#define HAVE_ALLOCA 1
-EOF
-
-fi
-
-if test $ac_cv_func_alloca_works = no; then
-  # The SVR3 libPW and SVR4 libucb both contain incompatible functions
-  # that cause trouble.  Some versions do not even contain alloca or
-  # contain a buggy version.  If you still want to use their alloca,
-  # use ar to extract alloca.o from them instead of compiling alloca.c.
-  ALLOCA=alloca.${ac_objext}
-  cat >> confdefs.h <<\EOF
-#define C_ALLOCA 1
-EOF
-
-
-echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6
-echo "configure:2316: checking whether alloca needs Cray hooks" >&5
-if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2321 "configure"
-#include "confdefs.h"
-#if defined(CRAY) && ! defined(CRAY2)
-webecray
-#else
-wenotbecray
-#endif
-
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  egrep "webecray" >/dev/null 2>&1; then
-  rm -rf conftest*
-  ac_cv_os_cray=yes
-else
-  rm -rf conftest*
-  ac_cv_os_cray=no
-fi
-rm -f conftest*
-
-fi
-
-echo "$ac_t""$ac_cv_os_cray" 1>&6
-if test $ac_cv_os_cray = yes; then
-for ac_func in _getb67 GETB67 getb67; do
-  echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:2346: checking for $ac_func" >&5
-if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2351 "configure"
-#include "confdefs.h"
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func(); below.  */
-#include <assert.h>
-/* Override any gcc2 internal prototype to avoid an error.  */
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char $ac_func();
-
-int main() {
-
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
-choke me
-#else
-$ac_func();
-#endif
-
-; return 0; }
-EOF
-if { (eval echo configure:2374: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_func_$ac_func=yes"
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_func_$ac_func=no"
-fi
-rm -f conftest*
-fi
-
-if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-  cat >> confdefs.h <<EOF
-#define CRAY_STACKSEG_END $ac_func
-EOF
-
-  break
-else
-  echo "$ac_t""no" 1>&6
-fi
-
-done
-fi
-
-echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6
-echo "configure:2401: checking stack direction for C alloca" >&5
-if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  if test "$cross_compiling" = yes; then
-  ac_cv_c_stack_direction=0
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2409 "configure"
-#include "confdefs.h"
-find_stack_direction ()
-{
-  static char *addr = 0;
-  auto char dummy;
-  if (addr == 0)
-    {
-      addr = &dummy;
-      return find_stack_direction ();
-    }
-  else
-    return (&dummy > addr) ? 1 : -1;
-}
-main ()
-{
-  exit (find_stack_direction() < 0);
-}
-EOF
-if { (eval echo configure:2428: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
-then
-  ac_cv_c_stack_direction=1
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -fr conftest*
-  ac_cv_c_stack_direction=-1
-fi
-rm -fr conftest*
-fi
-
-fi
-
-echo "$ac_t""$ac_cv_c_stack_direction" 1>&6
-cat >> confdefs.h <<EOF
-#define STACK_DIRECTION $ac_cv_c_stack_direction
-EOF
-
-fi
-
 
 trap '' 1 2 15
 cat > confcache <<\EOF
@@ -2588,7 +2354,6 @@ s%@RM@%$RM%g
 s%@CPP@%$CPP%g
 s%@WRITESTRINGS@%$WRITESTRINGS%g
 s%@LIBOBJS@%$LIBOBJS%g
-s%@ALLOCA@%$ALLOCA%g
 
 CEOF
 EOF
index b57f9d4..cda2a2b 100644 (file)
@@ -5,7 +5,7 @@ sinclude(ac_prog_cc_no_writeable_strings.m4)
 AC_INIT(secnet.c)
 AC_CONFIG_HEADER(config.h)
 
-AC_REVISION($Id: configure.in,v 1.3 2002/02/20 16:18:18 steve Exp $)
+AC_REVISION($Id: configure.in,v 1.4 2002/09/09 22:05:02 steve Exp $)
 
 AC_LANG_C
 
@@ -42,8 +42,6 @@ AC_CHECK_LIB(adns,adns_init)
 dnl check for getopt in standard library
 AC_SUBST(LIBOBJS)
 AC_CHECK_FUNCS(getopt_long , , [LIBOBJS="$LIBOBJS getopt.o getopt1.o"] ) 
-dnl check for alloca
 AC_CHECK_FUNCS(snprintf , , [LIBOBJS="$LIBOBJS snprintf.o"] )
-AC_FUNC_ALLOCA()
 
 AC_OUTPUT(Makefile,echo timestamp >stamp-h)
index 3da4b51..39e6dcd 100644 (file)
@@ -1,5 +1,5 @@
-secnet (0.1.15-1) unstable; urgency=low
+secnet (0.1.16-1) unstable; urgency=high
 
   * New upstream version.
 
- -- Stephen Early <steve@greenend.org.uk>  Thu, 21 Feb 2002 13:40:00 +0000
+ -- Stephen Early <steve@greenend.org.uk>  Sat,  19 Jul 2003 17:00:00 +0100
diff --git a/debian/dirs b/debian/dirs
deleted file mode 100644 (file)
index 80a26ab..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-etc/secnet
-usr/sbin
index 634467c..d6908ff 100644 (file)
@@ -1,6 +1,9 @@
 # secnet example configuration file
 
 # Log facility
+# If you use this unaltered you should consider providing automatic log
+# rotation for /var/log/secnet.  secnet will close and re-open its logfiles
+# when it receives SIGHUP.
 log logfile {
        filename "/var/log/secnet";
        class "info","notice","warning","error","security","fatal";
@@ -11,7 +14,7 @@ log logfile {
        #  'quiet'   -> fatal
 };
 
-# Alternatively you could log to syslog:
+# Alternatively you could log through syslog:
 # log syslog {
 #      ident "secnet";
 #      facility "local0";
@@ -23,6 +26,8 @@ log logfile {
 # userid       who we try to run as after setup
 # pidfile
 system {
+       # Note that you should not specify 'userid' here unless secnet
+       # is being invoked as root.
        userid "secnet";
        pidfile "/var/run/secnet.pid";
 };
@@ -61,10 +66,19 @@ system {
 # wait-time             wait between unsuccessful key setup attempts, in ms
 # renegotiate-time      set up a new key if we see any traffic after this time
 
+# Defaults that may be overridden on a per-site basis:
 setup-retries 10;
 setup-timeout 2000;
 
-# Use the universal TUN/TAP driver to get packets to and from the kernel
+# Use the universal TUN/TAP driver to get packets to and from the kernel,
+# through a single interface.  secnet will act as a router; it requires
+# its own IP address which is specified below (you'll see it on traceroute,
+# etc. for routes that go via tunnels).  If you don't want secnet to act
+# as a router, and instead want a separate kernel network interface per
+# tunnel, then see the alternative configuration below
+
+# If you want to use userv-ipif to manage interfaces then replace the
+# word "tun" with "userv-ipif".
 netlink tun {
        name "netlink-tun"; # Printed in log messages from this netlink
 #      interface "tun0"; # You may set your own interface name if you wish;
@@ -90,19 +104,17 @@ netlink tun {
        buffer sysbuffer(2048);
 };
 
-# Alternatively (or additionally, if you like) use userv-ipif to get
-# packets to and from the kernel.
-#netlink userv-ipif {
-#      name "netlink-userv-ipif";
-#      # userv-path "/usr/bin/userv";
-#      # service-user "root";
-#      # service-name "ipif";
-#      networks "whatever";
-#      local-address "whatever";
-#      secnet-address "whatever";
-#      mtu 1400;
-#      buffer sysbuffer(2048);
-#};    
+# This alternative configuration allows you to create one kernel network
+# interface per tunnel. IT WILL ONLY WORK WITH "tun" - IT WILL NOT
+# WORK WITH "userv-ipif".  This is because "tun" can share a single
+# buffer between multiple network interfaces, but userv-ipif can't.
+# To use userv-ipif in this style, process the sites.conf file so that
+# each "netlink" section contains a "buffer sysbuffer(2048);" line.
+#netlink tun;
+#local-address "192.168.x.x"; # Address of local interfaces - all the same
+#mtu 1400;
+#buffer sysbuffer(2048);
+
 
 # This defines the port that this instance of secnet will listen on, and
 # originate packets on. It does not _have_ to correspond to the advertised
@@ -142,22 +154,25 @@ transform serpent256-cbc {
 
 include /etc/secnet/sites.conf
 
-# Here you must list all the VPN sites that you wish to communicate with.
 # The /etc/secnet/sites file contains information on all reachable sites;
 # if the site you want to communicate with isn't listed, you should get
 # a newer version. MAKE SURE YOU GET AN AUTHENTIC COPY OF THE FILE - it
 # contains public keys for all sites.
 
-sites map(site,
-       vpn-data/example/location1/site1,
-       vpn-data/example/location2/site1,
-       vpn-data/example/location2/site2);
-
 # If you want to communicate with all the VPN sites, you can use something
-# like the following instead:
+# like the following:
 
-# sites map(site,vpn/example/all-sites);
+sites map(site,vpn/example/all-sites);
+
+# If you only want to communicate with a subset of the VPN sites, list
+# them explicitly:
+
+# sites map(site,
+#      vpn-data/example/location1/site1,
+#      vpn-data/example/location2/site1,
+#      vpn-data/example/location2/site2);
 
 # If you want to communicate with a subset of locations, try the following:
 
 # sites map(site,vpn/example/location1,vpn/example/location2);
+
index a59a013..27128c5 100644 (file)
--- a/getopt.c
+++ b/getopt.c
    along with this program; if not, write to the Free Software
    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 \f
-/* NOTE!!!  AIX requires this to be the first thing in the file.
-   Do not put ANYTHING before it!  */
-#if !defined (__GNUC__) && defined (_AIX)
- #pragma alloca
-#endif
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-#ifdef __GNUC__
-#define alloca __builtin_alloca
-#else /* not __GNUC__ */
-#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
-#include <alloca.h>
-#else
-#ifndef _AIX
-char *alloca ();
-#endif
-#endif /* alloca.h */
-#endif /* not __GNUC__ */
-
 #if !__STDC__ && !defined(const) && IN_GCC
 #define const
 #endif
@@ -67,12 +49,9 @@ char *alloca ();
 /* This needs to come after some library #include
    to get __GNU_LIBRARY__ defined.  */
 #ifdef __GNU_LIBRARY__
-#undef alloca
 /* Don't include stdlib.h for non-GNU C libraries because some of them
    contain conflicting prototypes for getopt.  */
 #include <stdlib.h>
-#else  /* Not GNU C library.  */
-#define        __alloca        alloca
 #endif /* GNU C library.  */
 
 /* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
@@ -237,7 +216,7 @@ exchange (argv)
      char **argv;
 {
   int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
-  char **temp = (char **) __alloca (nonopts_size);
+  char **temp = (char **) safe_malloc (nonopts_size, "getopt");
 
   /* Interchange the two blocks of data in ARGV.  */
 
@@ -252,6 +231,7 @@ exchange (argv)
 
   first_nonopt += (optind - last_nonopt);
   last_nonopt = optind;
+  free(temp);
 }
 \f
 /* Scan elements of ARGV (whose length is ARGC) for option characters
diff --git a/hackypar.c b/hackypar.c
new file mode 100644 (file)
index 0000000..ebab051
--- /dev/null
@@ -0,0 +1,121 @@
+/* Hacky parallelism; Ian Jackson */
+
+#define _GNU_SOURCE
+
+#include "secnet.h"
+#include "util.h"
+#include "hackypar.h"
+
+#ifdef HACKY_PARALLEL
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <assert.h>
+#include <sys/wait.h>
+
+#define HASHSIZE 16
+#define CACHESIZE 16
+
+typedef enum { hp_idle, hp_compute, hp_deferring, hp_fail } HPState;
+
+static HPState state;
+static pid_t child;
+
+static void checkchild(void) {
+  int r, status;
+  
+  if (!child) return;
+
+  r= waitpid(child,&status,WNOHANG); if (!r) return;
+  if (r==-1) {
+    Message(M_ERR,"hacky_par: waitpid: %s\n",strerror(errno));
+    return;
+  }
+  child= 0;
+  
+  if (WIFSIGNALED(status)) {
+    Message(M_ERR,"hacky_par: signaled! %s\n",strsignal(WTERMSIG(status)));
+  } else if (!WIFEXITED(status)) {
+    Message(M_ERR,"hacky_par: unexpected status! %d\n", r);
+  }
+}
+
+static HPState start(void) {
+  assert(!child);
+
+  child= fork();
+  if (child == -1) {
+    Message(M_ERR,"hacky_par: fork failed: %s\n",strerror(errno));
+    return hp_fail;
+  }
+
+  if (!child) { /* we are the child */
+    return hp_compute;
+  }
+
+  Message(M_INFO,"hacky_par: started, punting\n");
+  return hp_deferring;
+}
+
+int hacky_par_start_failnow(void) {
+  state= hp_idle;
+  checkchild();
+  if (child) {
+    state= hp_deferring;
+    Message(M_INFO,"hacky_par: busy, punting\n");
+    return 1;
+  }
+  return 0;
+}
+
+int hacky_par_mid_failnow(void) {
+  state= start();
+  return state != hp_compute;
+}
+
+bool_t (*packy_par_gen)(struct site *st);
+
+void hacky_par_end(int *ok,
+                  uint32_t retries, uint32_t timeout,
+                  bool_t (*send_msg)(struct site *st), struct site *st) {
+  int i;
+  
+  switch (state) {
+  case hp_deferring:
+    assert(!*ok);
+    *ok= 1;
+    return;
+  case hp_fail:
+    assert(!*ok);
+    return;
+  case hp_idle:
+    return;
+  case hp_compute:
+    if (!ok) {
+      Message(M_ERR,"hacky_par: compute failed\n");
+      _exit(2);
+    }
+    Message(M_INFO,"hacky_par: got result, sending\n");
+    for (i=1; i<retries; i++) {
+        sleep((timeout + 999)/1000);
+       if (!send_msg(st)) {
+           Message(M_ERR,"hacky_par: retry failed\n");
+           _exit(1);
+       }
+    }
+    _exit(0);
+  }
+}
+
+#else /*!HACKY_PARALLEL*/
+
+int hacky_par_start_failnow(void) { return 0; }
+int hacky_par_mid_failnow(void) { return 0; }
+void hacky_par_end(int *ok,
+                  uint32_t retries, uint32_t timeout,
+                  bool_t (*send_msg)(struct site *st), struct site *st) { }
+
+#endif /*HACKY_PARALLEL...else*/
diff --git a/hackypar.h b/hackypar.h
new file mode 100644 (file)
index 0000000..fbbff3c
--- /dev/null
@@ -0,0 +1,17 @@
+/* Hacky parallelism
+ * Ian Jackson
+ * We fork, and return false !
+ */
+
+#ifndef hackympzpar_h
+#define hackympzpar_h
+
+struct site;
+
+int hacky_par_start_failnow(void);
+int hacky_par_mid_failnow(void);
+void hacky_par_end(int *ok,
+                  uint32_t retries, uint32_t timeout,
+                  bool_t (*send_msg)(struct site *st), struct site *st);
+
+#endif /* hackympzpar_h */
index 7dd0476..d8661da 100644 (file)
--- a/ipaddr.c
+++ b/ipaddr.c
@@ -3,6 +3,7 @@
 
 #include "secnet.h"
 #include <stdio.h>
+#include <string.h>
 #include "ipaddr.h"
 
 #define DEFAULT_ALLOC 2
index 682840f..8024c16 100755 (executable)
@@ -1,5 +1,5 @@
 #! /usr/bin/env python
-# Copyright (C) 2001 Stephen Early <steve@greenend.org.uk>
+# Copyright (C) 2001-2002 Stephen Early <steve@greenend.org.uk>
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -53,217 +53,319 @@ import string
 import time
 import sys
 import os
+import getopt
 
+# The ipaddr library is installed as part of secnet
 sys.path.append("/usr/local/share/secnet")
 sys.path.append("/usr/share/secnet")
 import ipaddr
 
-VERSION="0.1.13"
-
-class vpn:
-       def __init__(self,name):
-               self.name=name
-               self.allow_defs=0
-               self.locations={}
-               self.defs={}
-
-class location:
-       def __init__(self,name,vpn):
-               self.group=None
-               self.name=name
-               self.allow_defs=1
-               self.vpn=vpn
-               self.sites={}
-               self.defs={}
-
-class site:
-       def __init__(self,name,location):
-               self.name=name
-               self.allow_defs=1
-               self.location=location
-               self.defs={}
-
-class nets:
+VERSION="0.1.16"
+
+# Classes describing possible datatypes in the configuration file
+
+class single_ipaddr:
+       "An IP address"
+       def __init__(self,w):
+               self.addr=ipaddr.ipaddr(w[1])
+       def __str__(self):
+               return '"%s"'%self.addr.ip_str()
+
+class networks:
+       "A set of IP addresses specified as a list of networks"
        def __init__(self,w):
-               self.w=w
                self.set=ipaddr.ip_set()
                for i in w[1:]:
                        x=string.split(i,"/")
                        self.set.append(ipaddr.network(x[0],x[1],
                                ipaddr.DEMAND_NETWORK))
-       def subsetof(self,s):
-               # I'd like to do this:
-               # return self.set.is_subset(s)
-               # but there isn't an is_subset() method
-               # Instead we see if we intersect with the complement of s
-               sc=s.set.complement()
-               i=sc.intersection(self.set)
-               return i.is_empty()
-       def out(self):
-               if (self.w[0]=='restrict-nets'): pattern="# restrict-nets %s;"
-               else:
-                       pattern="link netlink { routes %s; };"
-               return pattern%string.join(map(lambda x:'"%s/%s"'%(x.ip_str(),
-                               x.mask.netmask_bits_str),
-                               self.set.as_list_of_networks()),",")
+       def __str__(self):
+               return string.join(map(lambda x:'"%s/%s"'%(x.ip_str(),
+                       x.mask.netmask_bits_str),
+                       self.set.as_list_of_networks()),",")
 
 class dhgroup:
+       "A Diffie-Hellman group"
        def __init__(self,w):
                self.mod=w[1]
                self.gen=w[2]
-       def out(self):
-               return 'dh diffie-hellman("%s","%s");'%(self.mod,self.gen)
+       def __str__(self):
+               return 'diffie-hellman("%s","%s")'%(self.mod,self.gen)
 
 class hash:
+       "A choice of hash function"
        def __init__(self,w):
                self.ht=w[1]
                if (self.ht!='md5' and self.ht!='sha1'):
                        complain("unknown hash type %s"%(self.ht))
-       def out(self):
-               return 'hash %s;'%(self.ht)
+       def __str__(self):
+               return '%s'%(self.ht)
 
 class email:
+       "An email address"
        def __init__(self,w):
                self.addr=w[1]
-       def out(self):
-               return '# Contact email address: <%s>'%(self.addr)
+       def __str__(self):
+               return '<%s>'%(self.addr)
 
 class num:
+       "A decimal number"
        def __init__(self,w):
-               self.what=w[0]
                self.n=string.atol(w[1])
-       def out(self):
-               return '%s %d;'%(self.what,self.n)
+       def __str__(self):
+               return '%d'%(self.n)
 
 class address:
+       "A DNS name and UDP port number"
        def __init__(self,w):
-               self.w=w
                self.adr=w[1]
                self.port=string.atoi(w[2])
                if (self.port<1 or self.port>65535):
                        complain("invalid port number")
-       def out(self):
-               return 'address "%s"; port %d;'%(self.adr,self.port)
+       def __str__(self):
+               return '"%s"; port %d'%(self.adr,self.port)
 
 class rsakey:
+       "An RSA public key"
        def __init__(self,w):
                self.l=string.atoi(w[1])
                self.e=w[2]
                self.n=w[3]
-       def out(self):
-               return 'key rsa-public("%s","%s");'%(self.e,self.n)
-
-class mobileoption:
+       def __str__(self):
+               return 'rsa-public("%s","%s")'%(self.e,self.n)
+
+# Possible properties of configuration nodes
+keywords={
+ 'contact':(email,"Contact address"),
+ 'dh':(dhgroup,"Diffie-Hellman group"),
+ 'hash':(hash,"Hash function"),
+ 'key-lifetime':(num,"Maximum key lifetime (ms)"),
+ 'setup-timeout':(num,"Key setup timeout (ms)"),
+ 'setup-retries':(num,"Maximum key setup packet retries"),
+ 'wait-time':(num,"Time to wait after unsuccessful key setup (ms)"),
+ 'renegotiate-time':(num,"Time after key setup to begin renegotiation (ms)"),
+ 'restrict-nets':(networks,"Allowable networks"),
+ 'networks':(networks,"Claimed networks"),
+ 'pubkey':(rsakey,"RSA public site key"),
+ 'peer':(single_ipaddr,"Tunnel peer IP address"),
+ 'address':(address,"External contact address and port")
+}
+
+def sp(name,value):
+       "Simply output a property - the default case"
+       return "%s %s;\n"%(name,value)
+
+# All levels support these properties
+global_properties={
+       'contact':(lambda name,value:"# Contact email address: %s\n"%(value)),
+       'dh':sp,
+       'hash':sp,
+       'key-lifetime':sp,
+       'setup-timeout':sp,
+       'setup-retries':sp,
+       'wait-time':sp,
+       'renegotiate-time':sp,
+       'restrict-nets':(lambda name,value:"# restrict-nets %s\n"%value)
+}
+
+class level:
+       "A level in the configuration hierarchy"
+       depth=0
+       leaf=0
+       allow_properties={}
+       require_properties={}
+       def __init__(self,w):
+               self.name=w[1]
+               self.properties={}
+               self.children={}
+       def indent(self,w,t):
+               w.write("                 "[:t])
+       def prop_out(self,n):
+               return self.allow_properties[n](n,str(self.properties[n]))
+       def output_props(self,w,ind):
+               for i in self.properties.keys():
+                       if self.allow_properties[i]:
+                               self.indent(w,ind)
+                               w.write("%s"%self.prop_out(i))
+       def output_data(self,w,ind,np):
+               self.indent(w,ind)
+               w.write("%s {\n"%(self.name))
+               self.output_props(w,ind+2)
+               if self.depth==1: w.write("\n");
+               for c in self.children.values():
+                       c.output_data(w,ind+2,np+self.name+"/")
+               self.indent(w,ind)
+               w.write("};\n")
+
+class vpnlevel(level):
+       "VPN level in the configuration hierarchy"
+       depth=1
+       leaf=0
+       type="vpn"
+       allow_properties=global_properties.copy()
+       require_properties={
+        'contact':"VPN admin contact address"
+       }
+       def __init__(self,w):
+               level.__init__(self,w)
+       def output_vpnflat(self,w,ind,h):
+               "Output flattened list of site names for this VPN"
+               self.indent(w,ind)
+               w.write("%s {\n"%(self.name))
+               for i in self.children.keys():
+                       self.children[i].output_vpnflat(w,ind+2,
+                               h+"/"+self.name+"/"+i)
+               w.write("\n")
+               self.indent(w,ind+2)
+               w.write("all-sites %s;\n"%
+                       string.join(self.children.keys(),','))
+               self.indent(w,ind)
+               w.write("};\n")
+
+class locationlevel(level):
+       "Location level in the configuration hierarchy"
+       depth=2
+       leaf=0
+       type="location"
+       allow_properties=global_properties.copy()
+       require_properties={
+        'contact':"Location admin contact address",
+       }
+       def __init__(self,w):
+               level.__init__(self,w)
+               self.group=w[2]
+       def output_vpnflat(self,w,ind,h):
+               self.indent(w,ind)
+               # The "h=h,self=self" abomination below exists because
+               # Python didn't support nested_scopes until version 2.1
+               w.write("%s %s;\n"%(self.name,string.join(
+                       map(lambda x,h=h,self=self:
+                               h+"/"+x,self.children.keys()),',')))
+
+class sitelevel(level):
+       "Site level (i.e. a leafnode) in the configuration hierarchy"
+       depth=3
+       leaf=1
+       type="site"
+       allow_properties=global_properties.copy()
+       allow_properties.update({
+        'address':sp,
+        'networks':None,
+        'peer':None,
+        'pubkey':(lambda n,v:"key %s;\n"%v)
+       })
+       require_properties={
+        'dh':"Diffie-Hellman group",
+        'contact':"Site admin contact address",
+        'address':"Site external access address",
+        'networks':"Networks claimed by the site",
+        'hash':"hash function",
+        'peer':"Gateway address of the site",
+        'pubkey':"RSA public key of the site"
+       }
        def __init__(self,w):
-               self.w=w
-       def out(self):
-               return '# netlink-options "soft";'
+               level.__init__(self,w)
+       def output_data(self,w,ind,np):
+               self.indent(w,ind)
+               w.write("%s {\n"%(self.name))
+               self.indent(w,ind+2)
+               w.write("name \"%s\";\n"%(np+self.name))
+               self.output_props(w,ind+2)
+               self.indent(w,ind+2)
+               w.write("link netlink {\n");
+               self.indent(w,ind+4)
+               w.write("routes %s;\n"%str(self.properties["networks"]))
+               self.indent(w,ind+4)
+               w.write("ptp-address %s;\n"%str(self.properties["peer"]))
+               self.indent(w,ind+2)
+               w.write("};\n")
+               self.indent(w,ind)
+               w.write("};\n")
+
+# Levels in the configuration file
+# (depth,properties)
+levels={'vpn':vpnlevel, 'location':locationlevel, 'site':sitelevel}
+
+# Reserved vpn/location/site names
+reserved={'all-sites':None}
+reserved.update(keywords)
+reserved.update(levels)
 
 def complain(msg):
+       "Complain about a particular input line"
        global complaints
        print ("%s line %d: "%(file,line))+msg
        complaints=complaints+1
 def moan(msg):
+       "Complain about something in general"
        global complaints
        print msg;
        complaints=complaints+1
 
-# We don't allow redefinition of properties (because that would allow things
-# like restrict-nets to be redefined, which would be bad)
-def set(obj,defs,w):
-       if (obj.allow_defs | allow_defs):
-               if (obj.defs.has_key(w[0])):
-                       complain("%s is already defined"%(w[0]))
-               else:
-                       t=defs[w[0]]
-                       obj.defs[w[0]]=t(w)
+root=level(['root','root'])   # All vpns are children of this node
+obstack=[root]
+allow_defs=0   # Level above which new definitions are permitted
+
+def set_property(obj,w):
+       "Set a property on a configuration node"
+       if obj.properties.has_key(w[0]):
+               complain("%s %s already has property %s defined"%
+                       (obj.type,obj.name,w[0]))
+       else:
+               obj.properties[w[0]]=keywords[w[0]][0](w)
 
-# Process a line of configuration file
 def pline(i):
-       global allow_defs, group, current_vpn, current_location, current_object
+       "Process a configuration file line"
+       global allow_defs, obstack, root
        w=string.split(i)
        if len(w)==0: return
        keyword=w[0]
+       current=obstack[len(obstack)-1]
        if keyword=='end-definitions':
-               allow_defs=0
-               current_vpn=None
-               current_location=None
-               current_object=None
+               allow_defs=sitelevel.depth
+               obstack=[root]
                return
-       if keyword=='vpn':
-               if vpns.has_key(w[1]):
-                       current_vpn=vpns[w[1]]
-                       current_object=current_vpn
+       if levels.has_key(keyword):
+               # We may go up any number of levels, but only down by one
+               newdepth=levels[keyword].depth
+               currentdepth=len(obstack) # actually +1...
+               if newdepth<=currentdepth:
+                       obstack=obstack[:newdepth]
+               if newdepth>currentdepth:
+                       complain("May not go from level %d to level %d"%
+                               (currentdepth-1,newdepth))
+               # See if it's a new one (and whether that's permitted)
+               # or an existing one
+               current=obstack[len(obstack)-1]
+               if current.children.has_key(w[1]):
+                       # Not new
+                       current=current.children[w[1]]
+                       if service and group and current.depth==2:
+                               if group!=current.group:
+                                       complain("Incorrect group!")
                else:
-                       if allow_defs:
-                               current_vpn=vpn(w[1])
-                               vpns[w[1]]=current_vpn
-                               current_object=current_vpn
-                       else:
-                               complain("no new VPN definitions allowed")
+                       # New
+                       # Ignore depth check for now
+                       nl=levels[keyword](w)
+                       if nl.depth<allow_defs:
+                               complain("New definitions not allowed at "
+                                       "level %d"%nl.depth)
+                       current.children[w[1]]=nl
+                       current=nl
+               obstack.append(current)
                return
-       if (current_vpn==None):
-               complain("no VPN defined yet")
-               return
-       # Keywords that can apply at all levels
-       if mldefs.has_key(w[0]):
-               set(current_object,mldefs,w)
-               return
-       if keyword=='location':
-               if (current_vpn.locations.has_key(w[1])):
-                       current_location=current_vpn.locations[w[1]]
-                       current_object=current_location
-                       if (group and not allow_defs and 
-                               current_location.group!=group):
-                               complain(("must be group %s to access "+
-                                       "location %s")%(current_location.group,
-                                       w[1]))
-               else:
-                       if allow_defs:
-                               if reserved.has_key(w[1]):
-                                       complain("reserved location name")
-                                       return
-                               current_location=location(w[1],current_vpn)
-                               current_vpn.locations[w[1]]=current_location
-                               current_object=current_location
-                       else:
-                               complain("no new location definitions allowed")
+       if current.allow_properties.has_key(keyword):
+               set_property(current,w)
                return
-       if (current_location==None):
-               complain("no locations defined yet")
-               return
-       if keyword=='group':
-               current_location.group=w[1]
-               return
-       if keyword=='site':
-               if (current_location.sites.has_key(w[1])):
-                       current_object=current_location.sites[w[1]]
-               else:
-                       if reserved.has_key(w[1]):
-                               complain("reserved site name")
-                               return
-                       current_object=site(w[1],current_location)
-                       current_location.sites[w[1]]=current_object
-               return
-       if keyword=='endsite':
-               if isinstance(current_object,site):
-                       current_object=current_object.location
-               else:
-                       complain("not currently defining a site")
-               return
-       # Keywords that can only apply to sites
-       if isinstance(current_object,site):
-               if sitedefs.has_key(w[0]):
-                       set(current_object,sitedefs,w)
-                       return
        else:
-               if sitedefs.has_key(w[0]):
-                       complain("keyword '%s' can only be used in the "
-                               "context of a site definition"%(w[0]))
-                       return
-       complain("unknown keyword '%s'"%(w[0]))
+               complain("Property %s not allowed at %s level"%
+                       (keyword,current.type))
+               return
+
+       complain("unknown keyword '%s'"%(keyword))
 
 def pfile(name,lines):
+       "Process a file"
        global file,line
        file=name
        line=0
@@ -274,99 +376,37 @@ def pfile(name,lines):
                pline(i)
 
 def outputsites(w):
-       w.write("# secnet sites file autogenerated by make-secnet-sites.py "
+       "Output include file for secnet configuration"
+       w.write("# secnet sites file autogenerated by make-secnet-sites "
                +"version %s\n"%VERSION)
-       w.write("# %s\n\n"%time.asctime(time.localtime(time.time())))
+       w.write("# %s\n"%time.asctime(time.localtime(time.time())))
+       w.write("# Command line: %s\n\n"%string.join(sys.argv))
 
        # Raw VPN data section of file
        w.write("vpn-data {\n")
-       for i in vpns.values():
-               w.write("  %s {\n"%i.name)
-               for d in i.defs.values():
-                       w.write("    %s\n"%d.out())
-               w.write("\n")
-               for l in i.locations.values():
-                       w.write("    %s {\n"%l.name)
-                       for d in l.defs.values():
-                               w.write("      %s\n"%d.out())
-                       for s in l.sites.values():
-                               w.write("      %s {\n"%s.name)
-                               w.write('        name "%s/%s/%s";\n'%
-                                       (i.name,l.name,s.name))
-                               for d in s.defs.values():
-                                       w.write("        %s\n"%d.out())
-                               w.write("      };\n")
-                       w.write("    };\n")
-               w.write("  };\n")
+       for i in root.children.values():
+               i.output_data(w,2,"")
        w.write("};\n")
 
        # Per-VPN flattened lists
        w.write("vpn {\n")
-       for i in vpns.values():
-               w.write("  %s {\n"%(i.name))
-               for l in i.locations.values():
-                       tmpl="vpn-data/%s/%s/%%s"%(i.name,l.name)
-                       slist=[]
-                       for s in l.sites.values(): slist.append(tmpl%s.name)
-                       w.write("    %s %s;\n"%(l.name,string.join(slist,",")))
-               w.write("\n    all-sites %s;\n"%
-                       string.join(i.locations.keys(),","))
-               w.write("  };\n")
+       for i in root.children.values():
+               i.output_vpnflat(w,2,"vpn-data")
        w.write("};\n")
 
        # Flattened list of sites
        w.write("all-sites %s;\n"%string.join(map(lambda x:"vpn/%s/all-sites"%
-               x,vpns.keys()),","))
+               x,root.children.keys()),","))
 
 # Are we being invoked from userv?
 service=0
 # If we are, which group does the caller want to modify?
 group=None
 
-vpns={}
-allow_defs=1
-current_vpn=None
-current_location=None
-current_object=None
-
 line=0
 file=None
 complaints=0
 
-# Things that can be defined at any level
-mldefs={
-       'dh':dhgroup,
-       'hash':hash,
-       'contact':email,
-       'key-lifetime':num,
-       'setup-retries':num,
-       'setup-timeout':num,
-       'wait-time':num,
-       'renegotiate-time':num,
-       'restrict-nets':nets
-       }
-
-# Things that can only be defined for sites
-sitedefs={
-       'address':address,
-       'networks':nets,
-       'pubkey':rsakey,
-       'mobile':mobileoption
-       }
-
-# Reserved vpn/location/site names
-reserved={'all-sites':None}
-reserved.update(mldefs)
-reserved.update(sitedefs)
-
-# Each site must have the following defined at some level:
-required={
-       'dh':"Diffie-Hellman group",
-       'networks':"network list",
-       'pubkey':"public key",
-       'hash':"hash function"
-       }
-
 if len(sys.argv)<2:
        pfile("stdin",sys.stdin.readlines())
        of=sys.stdout
@@ -413,52 +453,58 @@ else:
                        of=open(sys.argv[2],'w')
 
 # Sanity check section
-
-# Delete locations that have no sites defined
-for i in vpns.values():
-       for l in i.locations.keys():
-               if (len(i.locations[l].sites.values())==0):
-                       del i.locations[l]
-
-# Delete VPNs that have no locations with sites defined
-for i in vpns.keys():
-       if (len(vpns[i].locations.values())==0):
-               del vpns[i]
-
-# Check all sites
-for i in vpns.values():
-       if i.defs.has_key('restrict-nets'):
-               vr=i.defs['restrict-nets']
+# Delete nodes where leaf=0 that have no children
+
+def live(n):
+       "Number of leafnodes below node n"
+       if n.leaf: return 1
+       for i in n.children.keys():
+               if live(n.children[i]): return 1
+       return 0
+def delempty(n):
+       "Delete nodes that have no leafnode children"
+       for i in n.children.keys():
+               delempty(n.children[i])
+               if not live(n.children[i]):
+                       del n.children[i]
+delempty(root)
+
+# Check that all constraints are met (as far as I can tell
+# restrict-nets/networks/peer are the only special cases)
+
+def checkconstraints(n,p,ra):
+       new_p=p.copy()
+       new_p.update(n.properties)
+       for i in n.require_properties.keys():
+               if not new_p.has_key(i):
+                       moan("%s %s is missing property %s"%
+                               (n.type,n.name,i))
+       for i in new_p.keys():
+               if not n.allow_properties.has_key(i):
+                       moan("%s %s has forbidden property %s"%
+                               (n.type,n.name,i))
+       # Check address range restrictions
+       if n.properties.has_key("restrict-nets"):
+               new_ra=ra.intersection(n.properties["restrict-nets"].set)
        else:
-               vr=None
-       for l in i.locations.values():
-               if l.defs.has_key('restrict-nets'):
-                       lr=l.defs['restrict-nets']
-                       if (not lr.subsetof(vr)):
-                               moan("location %s/%s restrict-nets is invalid"%
-                                       (i.name,l.name))
-               else:
-                       lr=vr
-               for s in l.sites.values():
-                       sn="%s/%s/%s"%(i.name,l.name,s.name)
-                       for r in required.keys():
-                               if (not (s.defs.has_key(r) or
-                                       l.defs.has_key(r) or
-                                       i.defs.has_key(r))):
-                                       moan("site %s missing parameter %s"%
-                                               (sn,r))
-                       if s.defs.has_key('restrict-nets'):
-                               sr=s.defs['restrict-nets']
-                               if (not sr.subsetof(lr)):
-                                       moan("site %s restrict-nets not valid"%
-                                               sn)
-                       else:
-                               sr=lr
-                       if not s.defs.has_key('networks'): continue
-                       nets=s.defs['networks']
-                       if (not nets.subsetof(sr)):
-                               moan("site %s networks exceed restriction"%sn)
-
+               new_ra=ra
+       if n.properties.has_key("networks"):
+               # I'd like to do this:
+               # n.properties["networks"].set.is_subset(new_ra)
+               # but there isn't an is_subset() method
+               # Instead we see if we intersect with the complement of new_ra
+               rac=new_ra.complement()
+               i=rac.intersection(n.properties["networks"].set)
+               if not i.is_empty():
+                       moan("%s %s networks out of bounds"%(n.type,n.name))
+               if n.properties.has_key("peer"):
+                       if not n.properties["networks"].set.contains(
+                               n.properties["peer"].addr):
+                               moan("%s %s peer not in networks"%(n.type,n.name))
+       for i in n.children.keys():
+               checkconstraints(n.children[i],new_p,new_ra)
+
+checkconstraints(root,{},ipaddr.complete_set)
 
 if complaints>0:
        if complaints==1: print "There was 1 problem."
@@ -471,7 +517,7 @@ if service:
        f=open(groupfiledir+"/T"+group,'w')
        f.write("# Section submitted by user %s, %s\n"%
                (user,time.asctime(time.localtime(time.time()))))
-       f.write("# Checked by make-secnet-sites.py version %s\n\n"%VERSION)
+       f.write("# Checked by make-secnet-sites version %s\n\n"%VERSION)
        for i in userinput: f.write(i)
        f.write("\n")
        f.close()
index 568cb2e..466e68f 100644 (file)
--- a/netlink.c
+++ b/netlink.c
@@ -97,6 +97,7 @@ their use.
 
 */
 
+#include <string.h>
 #include "secnet.h"
 #include "util.h"
 #include "ipaddr.h"
diff --git a/rsa.c b/rsa.c
index 55bd24f..3c82a40 100644 (file)
--- a/rsa.c
+++ b/rsa.c
@@ -1,6 +1,13 @@
-/* CRT work by Simon Tatham */
+/* This file is part of secnet, and is distributed under the terms of
+   the GNU General Public License version 2 or later.
+
+   Copyright (C) 1995-2002 Stephen Early
+   Copyright (C) 2001 Simon Tatham
+   Copyright (C) 2002 Ian Jackson
+   */
 
 #include <stdio.h>
+#include <string.h>
 #include <gmp.h>
 #include "secnet.h"
 #include "util.h"
@@ -40,22 +47,42 @@ static string_t rsa_sign(void *sst, uint8_t *data, uint32_t datalen)
     mpz_init(&a);
     mpz_init(&b);
 
+    /* RSA PKCS#1 v1.5 signature padding:
+     *
+     * <------------ msize hex digits ---------->
+     *
+     * 00 01 ff ff .... ff ff 00 vv vv vv .... vv
+     *
+     *                           <--- datalen -->
+     *                                 bytes
+     *                         = datalen*2 hex digits
+     *
+     * NB that according to PKCS#1 v1.5 we're supposed to include a
+     * hash function OID in the data.  We don't do that (because we
+     * don't have the hash function OID to hand here), thus violating
+     * the spec in a way that affects interop but not security.
+     *
+     * -iwj 17.9.2002
+     */
+
     msize=mpz_sizeinbase(&st->n, 16);
 
-    if (datalen*2+4>=msize) {
+    if (datalen*2+6>=msize) {
        fatal("rsa_sign: message too big");
     }
 
     strcpy(buff,"0001");
 
     for (i=0; i<datalen; i++) {
-       buff[4+i*2]=hexchars[(data[i]&0xf0)>>4];
-       buff[5+i*2]=hexchars[data[i]&0xf];
+       buff[msize+(-datalen+i)*2]=hexchars[(data[i]&0xf0)>>4];
+       buff[msize+(-datalen+i)*2+1]=hexchars[data[i]&0xf];
     }
-    buff[4+datalen*2]=0;
     
-    for (i=datalen*2+4; i<msize; i++)
-       buff[i]='f';
+    buff[msize-datalen*2-2]= '0';
+    buff[msize-datalen*2-1]= '0';
+    for (i=4; i<msize-datalen*2-2; i++)
+       buff[i]='f';
 
     buff[msize]=0;
 
@@ -121,12 +148,14 @@ static bool_t rsa_sig_check(void *sst, uint8_t *data, uint32_t datalen,
     strcpy(buff,"0001");
 
     for (i=0; i<datalen; i++) {
-       buff[4+i*2]=hexchars[(data[i]&0xf0)>>4];
-       buff[5+i*2]=hexchars[data[i]&0xf];
+       buff[msize+(-datalen+i)*2]=hexchars[(data[i]&0xf0)>>4];
+       buff[msize+(-datalen+i)*2+1]=hexchars[data[i]&0xf];
     }
-    buff[4+datalen*2]=0;
 
-    for (i=datalen*2+4; i<msize; i++)
+    buff[msize-datalen*2-2]= '0';
+    buff[msize-datalen*2-1]= '0';
+
+    for (i=4; i<msize-datalen*2-2; i++)
        buff[i]='f';
 
     buff[msize]=0;
@@ -223,6 +252,7 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context,
     uint8_t *b, *c;
     int cipher_type;
     MP_INT e,d,iqmp,tmp,tmp2,tmp3;
+    bool_t valid;
 
     st=safe_malloc(sizeof(*st),"rsapriv_apply");
     st->cl.description="rsapriv";
@@ -383,16 +413,15 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context,
      * Now verify the validity of the key, and set up the auxiliary
      * values for fast CRT signing.
      */
+    valid=False;
     i=list_elem(args,1);
+    mpz_init(&tmp);
+    mpz_init(&tmp2);
+    mpz_init(&tmp3);
     if (i && i->type==t_bool && i->data.bool==False) {
        Message(M_INFO,"rsa-private (%s:%d): skipping RSA key validity "
                "check\n",loc.file,loc.line);
     } else {
-       int valid = 0;
-       mpz_init(&tmp);
-       mpz_init(&tmp2);
-       mpz_init(&tmp3);
-
        /* Verify that p*q is equal to n. */
        mpz_mul(&tmp, &st->p, &st->q);
        if (mpz_cmp(&tmp, &st->n) != 0)
@@ -419,33 +448,35 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context,
        mpz_mod(&tmp2, &tmp, &st->p);
        if (mpz_cmp_si(&tmp2, 1) != 0)
            goto done_checks;
-
-       /* Now we know the key is valid. */
-       valid = 1;
-
-       /*
-        * Now we compute auxiliary values dp, dq and w to allow us
-        * to use the CRT optimisation when signing.
-        * 
-        *   dp == d mod (p-1)      so that a^dp == a^d mod p, for all a
-        *   dq == d mod (q-1)      similarly mod q
-        *   w == iqmp * q          so that w == 0 mod q, and w == 1 mod p
-        */
-       mpz_sub_ui(&tmp, &st->p, 1);
-       mpz_mod(&st->dp, &d, &tmp);
-       mpz_sub_ui(&tmp, &st->q, 1);
-       mpz_mod(&st->dq, &d, &tmp);
-       mpz_mul(&st->w, &iqmp, &st->q);
-
-       done_checks:
-       if (!valid) {
-           cfgfatal(loc,"rsa-private","file \"%s\" does not contain a "
-                    "valid RSA key!\n",filename);
-       }
-       mpz_clear(&tmp);
-       mpz_clear(&tmp2);
-       mpz_clear(&tmp3);
     }
+    /* Now we know the key is valid (or we don't care). */
+    valid = True;
+    
+    /*
+     * Now we compute auxiliary values dp, dq and w to allow us
+     * to use the CRT optimisation when signing.
+     * 
+     *   dp == d mod (p-1)      so that a^dp == a^d mod p, for all a
+     *   dq == d mod (q-1)      similarly mod q
+     *   w == iqmp * q          so that w == 0 mod q, and w == 1 mod p
+     */
+    mpz_init(&st->dp);
+    mpz_init(&st->dq);
+    mpz_init(&st->w);
+    mpz_sub_ui(&tmp, &st->p, 1);
+    mpz_mod(&st->dp, &d, &tmp);
+    mpz_sub_ui(&tmp, &st->q, 1);
+    mpz_mod(&st->dq, &d, &tmp);
+    mpz_mul(&st->w, &iqmp, &st->q);
+    
+done_checks:
+    if (!valid) {
+       cfgfatal(loc,"rsa-private","file \"%s\" does not contain a "
+                "valid RSA key!\n",filename);
+    }
+    mpz_clear(&tmp);
+    mpz_clear(&tmp2);
+    mpz_clear(&tmp3);
 
     free(c);
     mpz_clear(&e);
index bef236d..efe52b3 100644 (file)
--- a/secnet.c
+++ b/secnet.c
@@ -263,10 +263,7 @@ static void run(void)
     int timeout;
     struct pollfd *fds;
 
-    fds=alloca(sizeof(*fds)*total_nfds);
-    if (!fds) {
-       fatal("run: couldn't alloca");
-    }
+    fds=safe_malloc(sizeof(*fds)*total_nfds, "run");
 
     Message(M_NOTICE,"%s [%d]: starting\n",version,secnet_pid);
 
@@ -309,6 +306,7 @@ static void run(void)
            }
        } while (rv<0);
     } while (!finished);
+    free(fds);
 }
 
 static void droppriv(void)
index 4b211f5..7327350 100644 (file)
--- a/secnet.h
+++ b/secnet.h
 #include <sys/time.h>
 #include <netinet/in.h>
 
+/*
+ * Macros added by SGT for endianness-independence
+ */
+#define GET_32BIT_MSB_FIRST(cp) \
+  (((unsigned long)(unsigned char)(cp)[0] << 24) | \
+  ((unsigned long)(unsigned char)(cp)[1] << 16) | \
+  ((unsigned long)(unsigned char)(cp)[2] << 8) | \
+  ((unsigned long)(unsigned char)(cp)[3]))
+
+#define PUT_32BIT_MSB_FIRST(cp, value) ( \
+  (cp)[0] = (char)((value) >> 24), \
+  (cp)[1] = (char)((value) >> 16), \
+  (cp)[2] = (char)((value) >> 8), \
+  (cp)[3] = (char)(value) )
+
 typedef char *string_t;
 typedef const char *cstring_t;
 typedef enum {False,True} bool_t;
index 51b27ba..e41f3ce 100644 (file)
--- a/serpent.c
+++ b/serpent.c
@@ -32,9 +32,10 @@ void serpent_makekey(struct keyInstance *key, int keyLen,
     uint32_t w[132],k[132];
 
     for(i=0; i<keyLen/32; i++)
-       w[i]=keyMaterial[i];
+       w[i]=GET_32BIT_MSB_FIRST(keyMaterial + (keyLen/8 - i*4) - 4);
     if(keyLen<256)
-       w[i]=(keyMaterial[i]&((1L<<((keyLen&31)))-1))|(1L<<((keyLen&31)));
+       w[i]=(GET_32BIT_MSB_FIRST(keyMaterial + (keyLen/8 - i*4) - 4)
+              & ((1L<<((keyLen&31)))-1)) | (1L<<((keyLen&31)));
     for(i++; i<8; i++)
        w[i]=0;
     for(i=8; i<16; i++)
@@ -84,16 +85,16 @@ void serpent_makekey(struct keyInstance *key, int keyLen,
 }
 
 void serpent_encrypt(struct keyInstance *key,
-                    uint32_t plaintext[4], 
-                    uint32_t ciphertext[4])
+                    uint8_t plaintext[16], 
+                    uint8_t ciphertext[16])
 {
     register uint32_t x0, x1, x2, x3;
     register uint32_t y0, y1, y2, y3;
 
-    x0=plaintext[0];
-    x1=plaintext[1];
-    x2=plaintext[2];
-    x3=plaintext[3];
+    x0=GET_32BIT_MSB_FIRST(plaintext+12);
+    x1=GET_32BIT_MSB_FIRST(plaintext+8);
+    x2=GET_32BIT_MSB_FIRST(plaintext+4);
+    x3=GET_32BIT_MSB_FIRST(plaintext);
 
     /* Start to encrypt the plaintext x */
     keying(x0, x1, x2, x3, key->subkeys[ 0]);
@@ -195,23 +196,23 @@ void serpent_encrypt(struct keyInstance *key,
     keying(x0, x1, x2, x3, key->subkeys[32]);
     /* The ciphertext is now in x */
 
-    ciphertext[0] = x0;
-    ciphertext[1] = x1;
-    ciphertext[2] = x2;
-    ciphertext[3] = x3;
+    PUT_32BIT_MSB_FIRST(ciphertext+12, x0);
+    PUT_32BIT_MSB_FIRST(ciphertext+8, x1);
+    PUT_32BIT_MSB_FIRST(ciphertext+4, x2);
+    PUT_32BIT_MSB_FIRST(ciphertext, x3);
 }
 
 void serpent_decrypt(struct keyInstance *key,
-                    uint32_t ciphertext[4],
-                    uint32_t plaintext[4])
+                    uint8_t ciphertext[16],
+                    uint8_t plaintext[16])
 {
     register uint32_t x0, x1, x2, x3;
     register uint32_t y0, y1, y2, y3;
 
-    x0=ciphertext[0];
-    x1=ciphertext[1];
-    x2=ciphertext[2];
-    x3=ciphertext[3];
+    x0=GET_32BIT_MSB_FIRST(ciphertext+12);
+    x1=GET_32BIT_MSB_FIRST(ciphertext+8);
+    x2=GET_32BIT_MSB_FIRST(ciphertext+4);
+    x3=GET_32BIT_MSB_FIRST(ciphertext);
 
     /* Start to decrypt the ciphertext x */
     keying(x0, x1, x2, x3, key->subkeys[32]);
@@ -313,8 +314,8 @@ void serpent_decrypt(struct keyInstance *key,
     keying(x0, x1, x2, x3, key->subkeys[ 0]);
     /* The plaintext is now in x */
 
-    plaintext[0] = x0;
-    plaintext[1] = x1;
-    plaintext[2] = x2;
-    plaintext[3] = x3;
+    PUT_32BIT_MSB_FIRST(plaintext+12, x0);
+    PUT_32BIT_MSB_FIRST(plaintext+8, x1);
+    PUT_32BIT_MSB_FIRST(plaintext+4, x2);
+    PUT_32BIT_MSB_FIRST(plaintext, x3);
 }
index dbbd36e..07176d7 100644 (file)
--- a/serpent.h
+++ b/serpent.h
@@ -10,10 +10,10 @@ struct keyInstance {
 void serpent_makekey(struct keyInstance *key, int keyLen,
                     uint8_t *keyMaterial);
 
-void serpent_encrypt(struct keyInstance *key, uint32_t plaintext[4],
-                    uint32_t ciphertext[4]);
+void serpent_encrypt(struct keyInstance *key, uint8_t plaintext[16],
+                    uint8_t ciphertext[16]);
 
-void serpent_decrypt(struct keyInstance *key, uint32_t ciphertext[4],
-                    uint32_t plaintext[4]);
+void serpent_decrypt(struct keyInstance *key, uint8_t ciphertext[16],
+                    uint8_t plaintext[16]);
 
 #endif /* serpent_h */
diff --git a/site.c b/site.c
index 9df0a2b..49e1b14 100644 (file)
--- a/site.c
+++ b/site.c
@@ -260,7 +260,7 @@ struct msg {
 static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what)
 {
     void *hst;
-    uint8_t *hash=alloca(st->hash->len);
+    uint8_t *hash;
     string_t dhpub, sig;
 
     st->retries=st->setup_retries;
@@ -276,15 +276,20 @@ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what)
     if (type==LABEL_MSG1) return True;
     memcpy(buf_append(&st->buffer,NONCELEN),st->remoteN,NONCELEN);
     if (type==LABEL_MSG2) return True;
+
+    if (hacky_par_mid_failnow()) return False;
+
     dhpub=st->dh->makepublic(st->dh->st,st->dhsecret,st->dh->len);
     buf_append_string(&st->buffer,dhpub);
     free(dhpub);
+    hash=safe_malloc(st->hash->len, "generate_msg");
     hst=st->hash->init();
     st->hash->update(hst,st->buffer.start,st->buffer.size);
     st->hash->final(hst,hash);
     sig=st->privkey->sign(st->privkey->st,hash,st->hash->len);
     buf_append_string(&st->buffer,sig);
     free(sig);
+    free(hash);
     return True;
 }
 
@@ -417,7 +422,7 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3,
                           struct sockaddr_in *src)
 {
     struct msg m;
-    uint8_t *hash=alloca(st->hash->len);
+    uint8_t *hash;
     void *hst;
     cstring_t err;
 
@@ -428,6 +433,7 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3,
     }
 
     /* Check signature and store g^x mod m */
+    hash=safe_malloc(st->hash->len, "process_msg3");
     hst=st->hash->init();
     st->hash->update(hst,m.hashstart,m.hashlen);
     st->hash->final(hst,hash);
@@ -435,8 +441,10 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3,
     m.sig[m.siglen]=0;
     if (!st->pubkey->check(st->pubkey->st,hash,st->hash->len,m.sig)) {
        slog(st,LOG_SEC,"msg3 signature failed check!");
+       free(hash);
        return False;
     }
+    free(hash);
 
     /* Terminate their DH public key with a '0' */
     m.pk[m.pklen]=0;
@@ -465,7 +473,7 @@ static bool_t process_msg4(struct site *st, struct buffer_if *msg4,
                           struct sockaddr_in *src)
 {
     struct msg m;
-    uint8_t *hash=alloca(st->hash->len);
+    uint8_t *hash;
     void *hst;
     cstring_t err;
 
@@ -476,6 +484,7 @@ static bool_t process_msg4(struct site *st, struct buffer_if *msg4,
     }
     
     /* Check signature and store g^x mod m */
+    hash=safe_malloc(st->hash->len, "process_msg4");
     hst=st->hash->init();
     st->hash->update(hst,m.hashstart,m.hashlen);
     st->hash->final(hst,hash);
@@ -483,8 +492,10 @@ static bool_t process_msg4(struct site *st, struct buffer_if *msg4,
     m.sig[m.siglen]=0;
     if (!st->pubkey->check(st->pubkey->st,hash,st->hash->len,m.sig)) {
        slog(st,LOG_SEC,"msg4 signature failed check!");
+       free(hash);
        return False;
     }
+    free(hash);
 
     /* Terminate their DH public key with a '0' */
     m.pk[m.pklen]=0;
@@ -821,6 +832,8 @@ static bool_t enter_state_resolve(struct site *st)
 static bool_t enter_new_state(struct site *st, uint32_t next)
 {
     bool_t (*gen)(struct site *st);
+    int r;
+
     slog(st,LOG_STATE,"entering state %s",state_name(next));
     switch(next) {
     case SITE_SENTMSG1:
@@ -858,7 +871,15 @@ static bool_t enter_new_state(struct site *st, uint32_t next)
        break;
     }
 
-    if (gen(st) && send_msg(st)) {
+    if (hacky_par_start_failnow()) return False;
+
+    r= gen(st) && send_msg(st);
+
+    hacky_par_end(&r,
+                 st->setup_retries, st->setup_timeout,
+                 send_msg, st);
+    
+    if (r) {
        st->state=next;
        if (next==SITE_RUN) {
            BUF_FREE(&st->buffer); /* Never reused */
@@ -949,9 +970,10 @@ static void site_afterpoll(void *sst, struct pollfd *fds, int nfds,
     st->now=*now;
     if (st->timeout && *now>st->timeout) {
        st->timeout=0;
-       if (st->state>=SITE_SENTMSG1 && st->state<=SITE_SENTMSG5)
-           send_msg(st);
-       else if (st->state==SITE_WAIT) {
+       if (st->state>=SITE_SENTMSG1 && st->state<=SITE_SENTMSG5) {
+           if (!hacky_par_start_failnow())
+               send_msg(st);
+       } else if (st->state==SITE_WAIT) {
            enter_state_run(st);
        } else {
            slog(st,LOG_ERROR,"site_afterpoll: unexpected timeout, state=%d",
index 53ff448..dc6ac3e 100644 (file)
 /* Required key length in bytes */
 #define REQUIRED_KEYLEN ((512+64+32)/8)
 
-#ifdef WORDS_BIGENDIAN
-static inline uint32_t byteswap(uint32_t a)
-{
-    return
-       ((a&0x000000ff)<<24) |
-       ((a&0x0000ff00)<<8) |
-       ((a&0x00ff0000)>>8) |
-       ((a&0xff000000)>>24);
-}
-#endif
-
 struct transform {
     closure_t cl;
     uint32_t line;
@@ -71,9 +60,9 @@ static bool_t transform_setkey(void *sst, uint8_t *key, uint32_t keylen)
 
     serpent_makekey(&ti->cryptkey,256,key);
     serpent_makekey(&ti->mackey,256,key+32);
-    ti->cryptiv=ntohl(*(uint32_t *)(key+64));
-    ti->maciv=ntohl(*(uint32_t *)(key+68));
-    ti->sendseq=ntohl(*(uint32_t *)(key+72));
+    ti->cryptiv=GET_32BIT_MSB_FIRST(key+64);
+    ti->maciv=GET_32BIT_MSB_FIRST(key+68);
+    ti->sendseq=GET_32BIT_MSB_FIRST(key+72);
     ti->lastrecvseq=ti->sendseq;
     ti->keyed=True;
 
@@ -95,10 +84,11 @@ static uint32_t transform_forward(void *sst, struct buffer_if *buf,
     struct transform_inst *ti=sst;
     uint8_t *padp;
     int padlen;
-    uint32_t iv[4];
-    uint32_t macplain[4];
-    uint32_t macacc[4];
-    uint32_t *n, *p;
+    uint8_t iv[16];
+    uint8_t macplain[16];
+    uint8_t macacc[16];
+    uint8_t *p, *n;
+    int i;
 
     if (!ti->keyed) {
        *errmsg="transform unkeyed";
@@ -125,73 +115,35 @@ static uint32_t transform_forward(void *sst, struct buffer_if *buf,
        it we've have to add 16 bytes to each message, not 4, so that the
        message stays a multiple of 16 bytes long.) */
     memset(iv,0,16);
-    iv[0]=ti->maciv;
+    PUT_32BIT_MSB_FIRST(iv, ti->maciv);
     serpent_encrypt(&ti->mackey,iv,macacc);
 
     /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted
        block encrypted once again. */
-    for (n=(uint32_t *)buf->start; n<(uint32_t *)(buf->start+buf->size); n+=4)
+    for (n=buf->start; n<buf->start+buf->size; n+=16)
     {
-#ifdef WORDS_BIGENDIAN
-       macplain[0]=macacc[0]^byteswap(n[0]);
-       macplain[1]=macacc[1]^byteswap(n[1]);
-       macplain[2]=macacc[2]^byteswap(n[2]);
-       macplain[3]=macacc[3]^byteswap(n[3]);
-#else
-       macplain[0]=macacc[0]^n[0];
-       macplain[1]=macacc[1]^n[1];
-       macplain[2]=macacc[2]^n[2];
-       macplain[3]=macacc[3]^n[3];
-#endif
+       for (i = 0; i < 16; i++)
+           macplain[i] = macacc[i] ^ n[i];
        serpent_encrypt(&ti->mackey,macplain,macacc);
     }
     serpent_encrypt(&ti->mackey,macacc,macacc);
-#ifdef WORDS_BIGENDIAN
-    macacc[0]=byteswap(macacc[0]);
-    macacc[1]=byteswap(macacc[1]);
-    macacc[2]=byteswap(macacc[2]);
-    macacc[3]=byteswap(macacc[3]);
-#endif
     memcpy(buf_append(buf,16),macacc,16);
 
     /* Serpent-CBC. We expand the ID as for CBCMAC, do the encryption,
        and prepend the IV before increasing it. */
     memset(iv,0,16);
-    iv[0]=ti->cryptiv;
+    PUT_32BIT_MSB_FIRST(iv, ti->cryptiv);
     serpent_encrypt(&ti->cryptkey,iv,iv);
 
     /* CBC: each block is XORed with the previous encrypted block (or the IV)
        before being encrypted. */
     p=iv;
-#ifdef WORDS_BIGENDIAN
-    /* This counters the byteswap() in the first half of the loop, which in
-       turn counters the byteswap() in the second half of the loop. Ick. */
-    iv[0]=byteswap(iv[0]);
-    iv[1]=byteswap(iv[1]);
-    iv[2]=byteswap(iv[2]);
-    iv[3]=byteswap(iv[3]);
-#endif
-    for (n=(uint32_t *)buf->start; n<(uint32_t *)(buf->start+buf->size); n+=4)
+
+    for (n=buf->start; n<buf->start+buf->size; n+=16)
     {
-#ifdef WORDS_BIGENDIAN
-       /* Think of this as byteswap(p[x])^byteswap(n[x]) */
-       n[0]=byteswap(p[0]^n[0]);
-       n[1]=byteswap(p[1]^n[1]);
-       n[2]=byteswap(p[2]^n[2]);
-       n[3]=byteswap(p[3]^n[3]);
-#else
-       n[0]=p[0]^n[0];
-       n[1]=p[1]^n[1];
-       n[2]=p[2]^n[2];
-       n[3]=p[3]^n[3];
-#endif
+       for (i = 0; i < 16; i++)
+           n[i] ^= p[i];
        serpent_encrypt(&ti->cryptkey,n,n);
-#ifdef WORDS_BIGENDIAN
-       n[0]=byteswap(n[0]);
-       n[1]=byteswap(n[1]);
-       n[2]=byteswap(n[2]);
-       n[3]=byteswap(n[3]);
-#endif
        p=n;
     }
 
@@ -208,12 +160,12 @@ static uint32_t transform_reverse(void *sst, struct buffer_if *buf,
     unsigned padlen;
     int i;
     uint32_t seqnum, skew;
-    uint32_t iv[4];
-    uint32_t pct[4];
-    uint32_t macplain[4];
-    uint32_t macacc[4];
-    uint32_t *n;
-    uint32_t *macexpected;
+    uint8_t iv[16];
+    uint8_t pct[16];
+    uint8_t macplain[16];
+    uint8_t macacc[16];
+    uint8_t *n;
+    uint8_t *macexpected;
 
     if (!ti->keyed) {
        *errmsg="transform unkeyed";
@@ -223,66 +175,40 @@ static uint32_t transform_reverse(void *sst, struct buffer_if *buf,
 
     /* CBC */
     memset(iv,0,16);
-    iv[0]=buf_unprepend_uint32(buf);
+    {
+       uint32_t ivword = buf_unprepend_uint32(buf);
+       PUT_32BIT_MSB_FIRST(iv, ivword);
+    }
     /* Assert bufsize is multiple of blocksize */
     if (buf->size&0xf) {
        *errmsg="msg not multiple of cipher blocksize";
     }
     serpent_encrypt(&ti->cryptkey,iv,iv);
-    for (n=(uint32_t *)buf->start; n<(uint32_t *)(buf->start+buf->size); n+=4)
+    for (n=buf->start; n<buf->start+buf->size; n+=16)
     {
-#ifdef WORDS_BIGENDIAN
-       n[0]=byteswap(n[0]);
-       n[1]=byteswap(n[1]);
-       n[2]=byteswap(n[2]);
-       n[3]=byteswap(n[3]);
-#endif
-       pct[0]=n[0]; pct[1]=n[1]; pct[2]=n[2]; pct[3]=n[3];
+       for (i = 0; i < 16; i++)
+           pct[i] = n[i];
        serpent_decrypt(&ti->cryptkey,n,n);
-#ifdef WORDS_BIGENDIAN
-       n[0]=byteswap(iv[0]^n[0]);
-       n[1]=byteswap(iv[1]^n[1]);
-       n[2]=byteswap(iv[2]^n[2]);
-       n[3]=byteswap(iv[3]^n[3]);
-#else
-       n[0]=iv[0]^n[0];
-       n[1]=iv[1]^n[1];
-       n[2]=iv[2]^n[2];
-       n[3]=iv[3]^n[3];
-#endif
-       iv[0]=pct[0]; iv[1]=pct[1]; iv[2]=pct[2]; iv[3]=pct[3];
+       for (i = 0; i < 16; i++)
+           n[i] ^= iv[i];
+       memcpy(iv, pct, 16);
     }
 
     /* CBCMAC */
     macexpected=buf_unappend(buf,16);
     memset(iv,0,16);
-    iv[0]=ti->maciv;
+    PUT_32BIT_MSB_FIRST(iv, ti->maciv);
     serpent_encrypt(&ti->mackey,iv,macacc);
 
     /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted
        block encrypted once again. */
-    for (n=(uint32_t *)buf->start; n<(uint32_t *)(buf->start+buf->size); n+=4)
+    for (n=buf->start; n<buf->start+buf->size; n+=16)
     {
-#ifdef WORDS_BIGENDIAN
-       macplain[0]=macacc[0]^byteswap(n[0]);
-       macplain[1]=macacc[1]^byteswap(n[1]);
-       macplain[2]=macacc[2]^byteswap(n[2]);
-       macplain[3]=macacc[3]^byteswap(n[3]);
-#else
-       macplain[0]=macacc[0]^n[0];
-       macplain[1]=macacc[1]^n[1];
-       macplain[2]=macacc[2]^n[2];
-       macplain[3]=macacc[3]^n[3];
-#endif
+       for (i = 0; i < 16; i++)
+           macplain[i] = macacc[i] ^ n[i];
        serpent_encrypt(&ti->mackey,macplain,macacc);
     }
     serpent_encrypt(&ti->mackey,macacc,macacc);
-#ifdef WORDS_BIGENDIAN
-    macacc[0]=byteswap(macacc[0]);
-    macacc[1]=byteswap(macacc[1]);
-    macacc[2]=byteswap(macacc[2]);
-    macacc[3]=byteswap(macacc[3]);
-#endif
     if (memcmp(macexpected,macacc,16)!=0) {
        *errmsg="invalid MAC";
        return 1;
@@ -390,30 +316,74 @@ void transform_module(dict_t *dict)
 {
     struct keyInstance k;
     uint8_t data[32];
-    uint32_t plaintext[4];
-    uint32_t ciphertext[4];
+    uint8_t plaintext[16];
+    uint8_t ciphertext[16];
+
+    /*
+     * Serpent self-test.
+     * 
+     * This test pattern is taken directly from the Serpent test
+     * vectors, to ensure we have all endianness issues correct. -sgt
+     */
 
     /* Serpent self-test */
-    memset(data,0,32);
+    memcpy(data,
+           "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff"
+           "\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\x00",
+           32);
     serpent_makekey(&k,256,data);
-    plaintext[0]=0x00000000;
-    plaintext[1]=0x00000001;
-    plaintext[2]=0x00000002;
-    plaintext[3]=0x00000003;
+
+    memcpy(plaintext,
+           "\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           16);
     serpent_encrypt(&k,plaintext,ciphertext);
-    if (ciphertext[3]!=0x7ca73bb0 ||
-       ciphertext[2]!=0x83C31E69 ||
-       ciphertext[1]!=0xec52bd82 ||
-       ciphertext[0]!=0x27a46120) {
+
+    if (memcmp(ciphertext, "\xca\x7f\xa1\x93\xe3\xeb\x9e\x99"
+               "\xbd\x87\xe3\xaf\x3c\x9a\xdf\x93", 16)) {
        fatal("transform_module: serpent failed self-test (encrypt)");
     }
     serpent_decrypt(&k,ciphertext,plaintext);
-    if (plaintext[0]!=0 ||
-       plaintext[1]!=1 ||
-       plaintext[2]!=2 ||
-       plaintext[3]!=3) {
+    if (memcmp(plaintext, "\x01\x23\x45\x67\x89\xab\xcd\xef"
+               "\xfe\xdc\xba\x98\x76\x54\x32\x10", 16)) {
        fatal("transform_module: serpent failed self-test (decrypt)");
     }
 
     add_closure(dict,"serpent256-cbc",transform_apply);
+
+#ifdef TEST_WHOLE_TRANSFORM
+    {
+       struct transform *tr;
+       void *ti;
+       struct buffer_if buf;
+       const char text[] = "This is a piece of test text.";
+       char keymaterial[76] =
+           "Seventy-six bytes i"
+           "n four rows of 19; "
+           "this looks almost l"
+           "ike a poem but not.";
+       const char *errmsg;
+       int i;
+
+       tr = malloc(sizeof(struct transform));
+       tr->max_seq_skew = 20;
+       ti = transform_create(tr);
+
+       transform_setkey(ti, keymaterial, 76);
+
+        buf.base = malloc(4096);
+       buffer_init(&buf, 2048);
+       memcpy(buf_append(&buf, sizeof(text)), text, sizeof(text));
+       if (transform_forward(ti, &buf, &errmsg)) {
+           fatal("transform_forward test: %s", errmsg);
+       }
+       printf("transformed text is:\n");
+       for (i = 0; i < buf.size; i++)
+           printf("%02x%c", buf.start[i],
+                  (i%16==15 || i==buf.size-1 ? '\n' : ' '));
+       if (transform_reverse(ti, &buf, &errmsg)) {
+           fatal("transform_reverse test: %s", errmsg);
+       }
+       printf("transform reversal worked OK\n");
+    }
+#endif
 }
diff --git a/tun.c b/tun.c
index bf8cb1b..f7c0561 100644 (file)
--- a/tun.c
+++ b/tun.c
@@ -106,7 +106,7 @@ static int tun_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
 }
 
 static void tun_afterpoll(void *sst, struct pollfd *fds, int nfds,
-                           const struct timeval *tv_now, uint64_t *now)
+                         const struct timeval *tv_now, uint64_t *now)
 {
     struct tun *st=sst;
     int l;
diff --git a/udp.c b/udp.c
index add7d8d..9615a17 100644 (file)
--- a/udp.c
+++ b/udp.c
@@ -36,6 +36,7 @@ struct udp {
     closure_t cl;
     struct comm_if ops;
     struct cloc loc;
+    uint32_t addr;
     uint16_t port;
     int fd;
     string_t authbind;
@@ -182,7 +183,7 @@ static void udp_phase_hook(void *sst, uint32_t new_phase)
     struct udp *st=sst;
     struct sockaddr_in addr;
 
-    st->fd=socket(AF_INET, SOCK_DGRAM, 0);
+    st->fd=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
     if (st->fd<0) {
        fatal_perror("udp (%s:%d): socket",st->loc.file,st->loc.line);
     }
@@ -197,6 +198,7 @@ static void udp_phase_hook(void *sst, uint32_t new_phase)
 
     memset(&addr, 0, sizeof(addr));
     addr.sin_family=AF_INET;
+    addr.sin_addr.s_addr=htonl(st->addr);
     addr.sin_port=htons(st->port);
     if (st->authbind) {
        pid_t c;
@@ -209,23 +211,29 @@ static void udp_phase_hook(void *sst, uint32_t new_phase)
            fatal_perror("udp_phase_hook: fork() for authbind");
        }
        if (c==0) {
-           char *argv[4];
+           char *argv[4], addrstr[9], portstr[5];
+           sprintf(addrstr,"%08lX",(long)st->addr);
+           sprintf(portstr,"%04X",st->port);
            argv[0]=st->authbind;
-           argv[1]=strdup("00000000");
-           if (!argv[1]) exit(ENOMEM);
-           argv[2]=alloca(8);
-           if (!argv[2]) exit(ENOMEM);
-           sprintf(argv[2],"%04X",htons(st->port));
+           argv[1]=addrstr;
+           argv[2]=portstr;
            argv[3]=NULL;
            dup2(st->fd,0);
            execvp(st->authbind,argv);
-           exit(ENOEXEC);
+           _exit(255);
        }
-       waitpid(c,&status,0);
-       if (WEXITSTATUS(status)!=0) {
-           errno=WEXITSTATUS(status);
+       while (waitpid(c,&status,0)==-1) {
+           if (errno==EINTR) continue;
            fatal_perror("udp (%s:%d): authbind",st->loc.file,st->loc.line);
        }
+       if (WIFSIGNALED(status)) {
+           fatal("udp (%s:%d): authbind died on signal %d",st->loc.file,
+                 st->loc.line, WTERMSIG(status));
+       }
+       if (WIFEXITED(status) && WEXITSTATUS(status)!=0) {
+           fatal("udp (%s:%d): authbind died with status %d",st->loc.file,
+                 st->loc.line, WEXITSTATUS(status));
+       }
     } else {
        if (bind(st->fd, (struct sockaddr *)&addr, sizeof(addr))!=0) {
            fatal_perror("udp (%s:%d): bind",st->loc.file,st->loc.line);
@@ -239,7 +247,7 @@ static list_t *udp_apply(closure_t *self, struct cloc loc, dict_t *context,
                         list_t *args)
 {
     struct udp *st;
-    item_t *i;
+    item_t *i,*j;
     dict_t *d;
     list_t *l;
     uint32_t a;
@@ -265,6 +273,8 @@ static list_t *udp_apply(closure_t *self, struct cloc loc, dict_t *context,
     }
     d=i->data.dict;
 
+    j=dict_find_item(d,"address",False,"udp",st->loc);
+    st->addr=j?st->addr=string_item_to_ipaddr(j, "udp"):INADDR_ANY;
     st->port=dict_read_number(d,"port",True,"udp",st->loc,0);
     st->rbuf=find_cl_if(d,"buffer",CL_BUFFER,True,"udp",st->loc);
     st->authbind=dict_read_string(d,"authbind",False,"udp",st->loc);
diff --git a/util.h b/util.h
index 4563a24..f1be586 100644 (file)
--- a/util.h
+++ b/util.h
@@ -4,6 +4,8 @@
 #include "secnet.h"
 #include <gmp.h>
 
+#include "hackypar.h"
+
 #define BUF_ASSERT_FREE(buf) do { buffer_assert_free((buf), \
                                                     __FILE__,__LINE__); } \
 while(0)