chiark / gitweb /
Import release 0.1.5 v0.1.5
authorStephen Early <steve@greenend.org.uk>
Thu, 11 Oct 2001 17:16:00 +0000 (18:16 +0100)
committerStephen Early <steve@greenend.org.uk>
Wed, 18 May 2011 12:33:58 +0000 (13:33 +0100)
20 files changed:
INSTALL
Makefile.in
NOTES
README
TODO
conffile.c
debian/changelog
debian/rules
example.conf
make-secnet-sites.py
netlink.c
netlink.h
secnet.c
secnet.h
site.c
slip.c
tun.c
udp.c
util.c
util.h

diff --git a/INSTALL b/INSTALL
index 8ad676f3766d0174b6aace6e19b30831c9a43090..c8d90281e181e8ac592702657778655bd6ec3b3a 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -45,17 +45,27 @@ for it to run as once it's ready to drop its privileges.  Example (on
 Debian):
 # adduser --system --no-create-home secnet
 
+If you're using the 'soft routes' feature (for some classes of mobile
+device) you'll have to run as root all the time, to enable secnet to
+add and remove routes from your kernel's routing table.  (This
+restriction may be relaxed later if someone writes a userv service to
+modify the routing table.)
+
+If you are joining an existing VPN, read that VPN's documentation now.
+It may supersede the next paragraph.
+
 You will need to allocate two IP addresses for use by secnet.  One
 will be for the tunnel interface on your tunnel endpoint machine (i.e.
 the address you see in 'ifconfig' when you look at the tunnel
 interface).  The other will be for secnet itself.  These addresses
-could possibly be allocated from the range used by your internal
-network: if you do this, you should think about providing appropriate
-proxy-ARP on the internal network interface of the machine running
-secnet (eg. add an entry net/ipv4/conf/eth_whatever/proxy_arp = 1 to
-/etc/sysctl.conf on Debian systems and run sysctl -p).  Alternatively
-the addresses could be from some other range - this works well if the
-machine running secnet is the default route out of your network.
+should probably be allocated from the range used by your internal
+network: if you do this, you should provide appropriate proxy-ARP on
+the internal network interface of the machine running secnet (eg. add
+an entry net/ipv4/conf/eth_whatever/proxy_arp = 1 to /etc/sysctl.conf
+on Debian systems and run sysctl -p).  Alternatively the addresses
+could be from some other range - this works well if the machine
+running secnet is the default route out of your network - but this
+requires more thought.
 
 http://www.ucam.org/cam-grin/ may be useful.
 
@@ -96,7 +106,12 @@ XXX this should eventually be worked out automatically by 'configure'.]
 Generate a site file fragment for your site (see below), and submit it
 for inclusion in your VPN's 'sites' file.  Download the vpn-sites file
 to /etc/secnet/sites - MAKE SURE YOU GET AN AUTHENTIC COPY because the
-sites file contains public keys for all the sites in the VPN.
+sites file contains public keys for all the sites in the VPN.  Use the
+make-secnet-sites.py program provided with the secnet distribution to
+convert the distributed sites file into one that can be included in a
+secnet configuration file:
+
+# make-secnet-sites.py sites sites.conf
 
 * Configuration
 
@@ -109,13 +124,15 @@ is described in the README file at the moment.
 
 You need the following information:
 
-1. a short name for your site, eg. "greenend".  This is used to
-identify your site in the vpn-sites file.
+1. the name of your VPN.
 
-2. the name your site will use in the key setup protocol,
-eg. "greenend" (these two will usually be similar or the same).
+2. the name of your location(s).
 
-3. the DNS name of the machine that will be the "front-end" for your
+3. a short name for your site, eg. "sinister".  This is used to
+identify your site in the vpn-sites file, and should probably be the
+same as its hostname.
+
+4. the DNS name of the machine that will be the "front-end" for your
 secnet installation.  This will typically be the name of the gateway
 machine for your network, eg. sinister.dynamic.greenend.org.uk
 
@@ -123,18 +140,19 @@ secnet does not actually have to run on this machine, as long as the
 machine can be configured to forward UDP packets to the machine that
 is running secnet.
 
-4. the port number used to contact secnet at your site.  This is the
+5. the port number used to contact secnet at your site.  This is the
 port number on the front-end machine, and does not necessarily have to
-match the port number on the machine running secnet.
+match the port number on the machine running secnet.  If you want to
+use a privileged port number we suggest 410.  An appropriate
+unprivileged port number is 51396.  (These numbers were picked at
+random.)
 
-5. the list of networks accessible at your site over the VPN.
+6. the list of networks accessible at your site over the VPN.
 
-6. the public part of the RSA key you generated during installation
+7. the public part of the RSA key you generated during installation
 (in /etc/secnet/key.pub if you followed the installation
 instructions).  This file contains three numbers and a comment on one
-line.  The first number is the key length in bits, and should be
-ignored.  The second number (typically small) is the encryption key
-'e', and the third number (large) is the modulus 'n'.
+line.
 
 If you are running secnet on a particularly slow machine, you may like
 to specify a larger value for the key setup retry timeout than the
@@ -143,12 +161,10 @@ See the notes in the example configuration file for more on this.
 
 The site file fragment should look something like this:
 
-shortname {
-               name "sitename";
-               address "your.public.address.org.uk";
-               port 5678;
-               networks "172.18.45.0/24";
-               key rsa-public("35","153279875126380522437827076871354104097683702803616313419670959273217685015951590424876274370401136371563604396779864283483623325238228723798087715987495590765759771552692972297669972616769731553560605291312242789575053620182470998166393580503400960149506261455420521811814445675652857085993458063584337404329");
-       };
-
-See 'example-sites-file' for more examples.
+vpn sgo
+location greenend
+contact steve@greenend.org.uk
+site sinister
+  networks 192.168.73.0/24 192.168.1.0/24 172.19.71.0/24
+  address sinister.dynamic.greenend.org.uk 51396
+  pubkey 1024 35 142982503......[lots more].....0611 steve@sinister
index f53957e0cc98f9c3d55c8a874d109f2e7203d77e..4ec1a6c40190b3fe2c32bdb8a1034a32c235f8e4 100644 (file)
@@ -18,7 +18,7 @@
 .PHONY:        all clean realclean dist install
 
 PACKAGE:=secnet
-VERSION:=0.1.4
+VERSION:=0.1.5
 
 @SET_MAKE@
 
diff --git a/NOTES b/NOTES
index ae65e4cecf58759b67b66278bda916a58decc5f6..2443549cb67232ce64fe9b8f127ba20a31e32019 100644 (file)
--- a/NOTES
+++ b/NOTES
@@ -113,6 +113,22 @@ networks a b c ...
 pubkey x y z: x=keylen, y=encryption key, z=modulus
 mobile: declare this to be a 'mobile' site
 
+** Logging etc.
+
+There are several possible ways of running secnet:
+
+'reporting' only: --version, --help, etc. command line options and the
+--just-check-config mode.
+
+'normal' run: perform setup in the foreground, and then background.
+
+'failed' run: setup in the foreground, and terminate with an error
+before going to background.
+
+'reporting' modes should never output anything except to stdout/stderr.
+'normal' and 'failed' runs output to stdout/stderr before
+backgrounding, then thereafter output only to log destinations.
+
 ** Protocols
 
 *** Protocol environment:
diff --git a/README b/README
index 35041831e5e83b17a39eec71129b44fbcb05484c..957fe0658a9cee7a63ce3e3cfe0f31ff0989a7f6 100644 (file)
--- a/README
+++ b/README
@@ -165,13 +165,59 @@ Defines:
 udp: dict argument
   port (integer): UDP port to listen and send on
   buffer (buffer closure): buffer for incoming packets
+  authbind (string): optional, path to authbind-helper program
 
 ** util
 
 Defines:
   logfile (closure => log closure)
+  syslog (closure => log closure)
   sysbuffer (closure => buffer closure)
 
+logfile: dict argument
+  filename (string): where to log to
+  class (string list): what type of messages to log
+    { "debug-config", M_DEBUG_CONFIG },
+    { "debug-phase", M_DEBUG_PHASE },
+    { "debug", M_DEBUG },
+    { "all-debug", M_DEBUG|M_DEBUG_PHASE|M_DEBUG_CONFIG },
+    { "info", M_INFO },
+    { "notice", M_NOTICE },
+    { "warning", M_WARNING },
+    { "error", M_ERROR },
+    { "security", M_SECURITY },
+    { "fatal", M_FATAL },
+    { "default", M_WARNING|M_ERROR|M_SECURITY|M_FATAL },
+    { "verbose", M_INFO|M_NOTICE|M_WARNING|M_ERROR|M_SECURITY|M_FATAL },
+    { "quiet", M_FATAL }
+
+syslog: dict argument
+  ident (string): include this string in every log message
+  facility (string): facility to log as
+    { "authpriv", LOG_AUTHPRIV },
+    { "cron", LOG_CRON },
+    { "daemon", LOG_DAEMON },
+    { "kern", LOG_KERN },
+    { "local0", LOG_LOCAL0 },
+    { "local1", LOG_LOCAL1 },
+    { "local2", LOG_LOCAL2 },
+    { "local3", LOG_LOCAL3 },
+    { "local4", LOG_LOCAL4 },
+    { "local5", LOG_LOCAL5 },
+    { "local6", LOG_LOCAL6 },
+    { "local7", LOG_LOCAL7 },
+    { "lpr", LOG_LPR },
+    { "mail", LOG_MAIL },
+    { "news", LOG_NEWS },
+    { "syslog", LOG_SYSLOG },
+    { "user", LOG_USER },
+    { "uucp", LOG_UUCP }
+
+sysbuffer: integer[,dict]
+  arg1: buffer length
+  arg2: options:
+    lockdown (boolean): if True, mlock() the buffer
+
 ** site
 
 Defines:
diff --git a/TODO b/TODO
index e9ae871bb7214e82427a9becfa17f3561288b4ed..af3a4686efd4ad5be8ee2a6f870b4f78aaa48323 100644 (file)
--- a/TODO
+++ b/TODO
@@ -6,7 +6,8 @@ endianness problems)
 netlink.c: investigate why 'default' routes don't appear to work
 (reported by JDA).
 
-slip.c: detect failure of userv-ipif to start.
+slip.c: detect failure of userv-ipif to start. Restart userv-ipif to
+cope with soft routes? Restart it if it fails in use?
 
 tun.c: jdamery reports tun-old code works on Linux-2.2.
 Unresolved problem with ioctl(TUNSETIFF) sometimes returning EINVAL, seems
@@ -23,9 +24,7 @@ cleanly using a table. There's still quite a lot of redundancy in this
 file. Abandon key exchanges when a bad packet is received. Modify
 protocol to include version fields, as described in the NOTES file.
 
-transform.c: make generic
-
-util.c: sort out logging
+transform.c: see below
 
 sha1.c: test
 
@@ -35,7 +34,4 @@ user to plug in different block ciphers, invent an authenticity-only
 mode, etc.
 
 Signal handling! Really just cope with SIGCHLD and SIGTERM. Possibly
-use SIGUSR1/2 for prodding things.
-
-Write scripts to generate the 'real' sites file from a less-expressive
-version that's more easily checked by external tools.
+use SIGUSR1/2 for prodding things. Manage child processes properly.
index 5bd735c75a77c051e4fb679f265f52c2bec30208..061fd7a98f2c0a17d58b5423122f49eb914b5e6e 100644 (file)
@@ -551,6 +551,14 @@ list_t *list_new(void)
     return NULL;
 }
 
+uint32_t list_length(list_t *a)
+{
+    uint32_t l=0;
+    list_t *i;
+    for (i=a; i; i=i->next) l++;
+    return l;
+}
+
 list_t *list_copy(list_t *a)
 {
     list_t *r, *i, *b, *l;
@@ -791,6 +799,17 @@ void dict_read_subnet_list(dict_t *dict, string_t key, bool_t required,
     }
 }
 
+uint32_t string_to_word(string_t s, struct cloc loc,
+                       struct flagstr *f, string_t desc)
+{
+    struct flagstr *j;
+    for (j=f; j->name; j++)
+       if (strcmp(s,j->name)==0)
+           return j->value;
+    cfgfatal(loc,desc,"option \"%s\" not known\n",s);
+    return 0;
+}
+
 uint32_t string_list_to_word(list_t *l, struct flagstr *f, string_t desc)
 {
     list_t *i;
@@ -803,8 +822,7 @@ uint32_t string_list_to_word(list_t *l, struct flagstr *f, string_t desc)
                     "strings\n");
        }
        for (j=f; j->name; j++)
-           if (strcmp(i->item->data.string,j->name)==0)
-               r|=j->value;
+           r|=string_to_word(i->item->data.string,i->item->loc,f,desc);
     }
     return r;
 }
index 27e885f2da335e1d108e64174fc85c5f917908eb..8a69a5e28521cfa319f63cc5da841837e0fa2ad9 100644 (file)
@@ -1,4 +1,4 @@
-secnet (0.1.2-1) unstable; urgency=low
+secnet (0.1.5-1) unstable; urgency=low
 
   * New upstream version.
 
index 6237c9d9c4ef8eb56c919324fcbfc38d5317eceb..ca7a449db29bdb93949b24b8126d17aabbbb23a3 100755 (executable)
@@ -47,7 +47,7 @@ binary-arch: build install
        dh_testroot
 #      dh_installdebconf       
        dh_installdocs INSTALL README NOTES TODO
-       dh_installexamples example.conf example-sites-file
+       dh_installexamples example.conf make-secnet-sites.py ipaddr.py
 #      dh_installmenu
 #      dh_installlogrotate
 #      dh_installemacsen
index 0d7a546684df550603f4bcca17624aae7c4aff48..03e5f436bde0db63538dc81b782a04b2b962b008 100644 (file)
@@ -1,7 +1,21 @@
 # secnet example configuration file
 
 # Log facility
-log logfile("secnet","local2"); # Not yet implemented, goes to stderr
+log syslog {
+       ident "secnet";
+       facility "local0";
+};
+
+# Alternatively you could log to a file:
+# log logfile {
+#      filename "/var/log/secnet";
+#      class "info","notice","warning","error","security","fatal";
+#      # There are some useful message classes that could replace
+#      # this list:
+#      #  'default' -> warning,error,security,fatal
+#      #  'verbose' -> info,notice,default
+#      #  'quiet'   -> fatal
+# };
 
 # Systemwide configuration (all other configuration is per-site):
 # log          a log facility for program messages
index 8479aaa0f9554841dfe1c8625f6aa9d0fd6e85d0..cb2b9e88054159be7dbfc88238604ac8111d3054 100755 (executable)
@@ -55,7 +55,7 @@ import sys
 import os
 import ipaddr
 
-VERSION="0.1.4"
+VERSION="0.1.5"
 
 class vpn:
        def __init__(self,name):
@@ -106,41 +106,49 @@ class nets:
 
 class dhgroup:
        def __init__(self,w):
-               self.w=w
+               self.mod=w[1]
+               self.gen=w[2]
        def out(self):
-               return 'dh diffie-hellman("%s","%s");'%(self.w[1],self.w[2])
+               return 'dh diffie-hellman("%s","%s");'%(self.mod,self.gen)
 
 class hash:
        def __init__(self,w):
-               self.w=w
-               if (w[1]!='md5' and w[1]!='sha1'):
-                       complain("unknown hash type %s"%(w[1]))
+               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.w[1])
+               return 'hash %s;'%(self.ht)
 
 class email:
        def __init__(self,w):
-               self.w=w
+               self.addr=w[1]
        def out(self):
-               return '# Contact email address: <%s>'%(self.w[1])
+               return '# Contact email address: <%s>'%(self.addr)
 
 class num:
        def __init__(self,w):
-               self.w=w
+               self.what=w[0]
+               self.n=string.atol(w[1])
        def out(self):
-               return '%s %s;'%(self.w[0],self.w[1])
+               return '%s %d;'%(self.what,self.n)
 
 class address:
        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 %s;'%(self.w[1],self.w[2])
+               return 'address "%s"; port %d;'%(self.adr,self.port)
 
 class rsakey:
        def __init__(self,w):
-               self.w=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.w[2],self.w[3])
+               return 'key rsa-public("%s","%s");'%(self.e,self.n)
 
 class mobileoption:
        def __init__(self,w):
@@ -294,9 +302,9 @@ def outputsites(w):
        for i in vpns.values():
                w.write("  %s {\n"%(i.name))
                for l in i.locations.values():
-                       slist=map(lambda x:"vpn-data/%s/%s/%s"%
-                               (i.name,l.name,x.name),
-                               l.sites.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(),","))
index 708205b9eb6d0743d30188c0a8c4f5651197d647..022ddf1c00ae7a7c440c6245aca9494cf096fa46 100644 (file)
--- a/netlink.c
+++ b/netlink.c
@@ -659,11 +659,9 @@ netlink_deliver_fn *netlink_init(struct netlink *st,
                          &st->networks);
     dict_read_subnet_list(dict, "exclude-remote-networks", False, "netlink",
                          loc, &st->exclude_remote_networks);
-    /* local-address and secnet-address do not have to be in local-networks;
-       however, they should be advertised in the 'sites' file for the
+    /* secnet-address does not have to be in local-networks;
+       however, it should be advertised in the 'sites' file for the
        local site. */
-    st->local_address=string_to_ipaddr(
-       dict_find_item(dict,"local-address", True, "netlink", loc),"netlink");
     st->secnet_address=string_to_ipaddr(
        dict_find_item(dict,"secnet-address", True, "netlink", loc),"netlink");
     st->mtu=dict_read_number(dict, "mtu", False, "netlink", loc, DEFAULT_MTU);
index f1144441fb094623781435889d709c5d9f2c5a4d..077e828ef6c6c246efd5a481c9e5d06da1672c22 100644 (file)
--- a/netlink.h
+++ b/netlink.h
@@ -39,7 +39,6 @@ struct netlink {
     uint32_t max_end_pad;
     struct subnet_list networks;
     struct subnet_list exclude_remote_networks;
-    uint32_t local_address; /* host interface address */
     uint32_t secnet_address; /* our own address */
     uint32_t mtu;
     struct netlink_client *clients;
index ab562f1e8e6f0891c16ea84d68910d2a96917d6e..cb6823873a5b55581fcae640490b69a7a9a49780 100644 (file)
--- a/secnet.c
+++ b/secnet.c
@@ -19,12 +19,12 @@ extern char version[];
 #include "util.h"
 #include "conffile.h"
 
-/* Command-line options (possibly config-file options too) */
+/* XXX should be from autoconf */
 static char *configfile="/etc/secnet/secnet.conf";
 bool_t just_check_config=False;
 static char *userid=NULL;
 static uid_t uid=0;
-static bool_t background=True;
+bool_t background=True;
 static char *pidfile=NULL;
 bool_t require_root_privileges=False;
 string_t require_root_privileges_explanation=NULL;
@@ -95,21 +95,26 @@ static void parse_options(int argc, char **argv)
            break;
 
        case 'v':
-           message_level|=M_INFO|M_WARNING|M_ERROR|M_FATAL;
+           message_level|=M_INFO|M_NOTICE|M_WARNING|M_ERROR|M_SECURITY|
+               M_FATAL;
            break;
 
-       case 'n':
-           background=False;
+       case 'w':
+           message_level&=(~M_WARNING);
            break;
 
        case 'd':
-           message_level|=M_DEBUG_CONFIG|M_DEBUG_PHASE;
+           message_level|=M_DEBUG_CONFIG|M_DEBUG_PHASE|M_DEBUG;
            break;
 
        case 'f':
            message_level=M_FATAL;
            break;
 
+       case 'n':
+           background=False;
+           break;
+
        case 'c':
            if (optarg)
                configfile=safe_strdup(optarg,"config_filename");
@@ -125,12 +130,12 @@ static void parse_options(int argc, char **argv)
            break;
 
        default:
-           Message(M_WARNING,"secnet: Unknown getopt code %c\n",c);
+           Message(M_ERROR,"secnet: Unknown getopt code %c\n",c);
        }
     }
 
     if (argc-optind != 0) {
-       Message(M_WARNING,"secnet: You gave extra command line parameters, "
+       Message(M_ERROR,"secnet: You gave extra command line parameters, "
                "which were ignored.\n");
     }
 }
@@ -140,7 +145,6 @@ static void setup(dict_t *config)
     list_t *l;
     item_t *site;
     dict_t *system;
-    struct log_if *log;
     struct passwd *pw;
     struct cloc loc;
     int i;
@@ -158,8 +162,7 @@ static void setup(dict_t *config)
     if (!l) {
        fatal("configuration does not include a system/log facility\n");
     }
-    log=init_log(l);
-    log->log(log->st,LOG_DEBUG,"%s: logging started",version);
+    system_log=init_log(l);
 
     /* Who are we supposed to run as? */
     userid=dict_read_string(system,"userid",False,"system",loc);
@@ -248,6 +251,8 @@ static void run(void)
        fatal("run: couldn't alloca\n");
     }
 
+    Message(M_NOTICE,"%s: starting\n",version);
+
     while (!finished) {
        if (gettimeofday(&tv_now, NULL)!=0) {
            fatal_perror("main loop: gettimeofday");
@@ -294,20 +299,26 @@ static void droppriv(void)
 
     add_hook(PHASE_SHUTDOWN,system_phase_hook,NULL);
 
-    /* Background now, if we're supposed to: we may be unable to write the
-       pidfile if we don't. */
-    if (background) {
-       /* Open the pidfile before forking - that way the parent can tell
-          whether it succeeds */
-       if (pidfile) {
-           pf=fopen(pidfile,"w");
-           if (!pf) {
-               fatal_perror("cannot open pidfile \"%s\"",pidfile);
-           }
-       } else {
-           Message(M_WARNING,"secnet: no pidfile configured, but "
-                   "backgrounding anyway\n");
+    /* Open the pidfile for writing now: we may be unable to do so
+       once we drop privileges. */
+    if (pidfile) {
+       pf=fopen(pidfile,"w");
+       if (!pf) {
+           fatal_perror("cannot open pidfile \"%s\"",pidfile);
        }
+    }
+    if (!background && pf) {
+       fprintf(pf,"%d\n",getpid());
+       fclose(pf);
+    }
+
+    /* Now drop privileges */
+    if (uid!=0) {
+       if (setuid(uid)!=0) {
+           fatal_perror("can't set uid to \"%s\"",userid);
+       }
+    }
+    if (background) {
        p=fork();
        if (p>0) {
            if (pf) {
@@ -319,28 +330,14 @@ static void droppriv(void)
        } else if (p==0) {
            /* Child process - all done, just carry on */
            if (pf) fclose(pf);
+           secnet_is_daemon=True;
        } else {
            /* Error */
            fatal_perror("cannot fork");
            exit(1);
        }
-    } else {
-       if (pidfile) {
-           pf=fopen(pidfile,"w");
-           if (!pf) {
-               fatal_perror("cannot open pidfile \"%s\"",pidfile);
-           }
-           fprintf(pf,"%d\n",getpid());
-           fclose(pf);
-       }
     }
 
-    /* Drop privilege now, if configured to do so */
-    if (uid!=0) {
-       if (setuid(uid)!=0) {
-           fatal_perror("can't set uid to \"%s\"",userid);
-       }
-    }
 }
 
 int main(int argc, char **argv)
index c85f90f3aab21e6166998f752e5bd81d87b13bc9..ec630db092602bd1a6548ee7003fa73af72400b4 100644 (file)
--- a/secnet.h
+++ b/secnet.h
@@ -6,7 +6,6 @@
 #include "config.h"
 #include <stdlib.h>
 #include <stdarg.h>
-#include <syslog.h>
 #include <sys/poll.h>
 #include <sys/types.h>
 #include <sys/time.h>
@@ -48,6 +47,7 @@ extern bool_t subnet_lists_intersect(struct subnet_list *a,
 
 extern bool_t just_check_config; /* If True then we're going to exit after
                                    reading the configuration file */
+extern bool_t background; /* If True then we'll eventually run as a daemon */
 
 typedef struct dict dict_t;        /* Configuration dictionary */
 typedef struct closure closure_t;
@@ -102,6 +102,7 @@ extern string_t *dict_keys(dict_t *dict);
 
 /* List-manipulation functions */
 extern list_t *list_new(void);
+extern uint32_t list_length(list_t *a);
 extern list_t *list_append(list_t *a, item_t *i);
 extern list_t *list_append_list(list_t *a, list_t *b);
 /* Returns an item from the list (index starts at 0), or NULL */
@@ -129,6 +130,8 @@ struct flagstr {
     string_t name;
     uint32_t value;
 };
+extern uint32_t string_to_word(string_t s, struct cloc loc,
+                              struct flagstr *f, string_t desc);
 extern uint32_t string_list_to_word(list_t *l, struct flagstr *f,
                                    string_t desc);
 
@@ -136,12 +139,15 @@ extern uint32_t string_list_to_word(list_t *l, struct flagstr *f,
 
 /***** UTILITY functions *****/
 
-#define M_WARNING      1
-#define M_ERROR                2
-#define M_FATAL                4
-#define M_INFO         8
-#define M_DEBUG_CONFIG 16
-#define M_DEBUG_PHASE  32
+#define M_DEBUG_CONFIG 0x001
+#define M_DEBUG_PHASE  0x002
+#define M_DEBUG        0x004
+#define M_INFO        0x008
+#define M_NOTICE       0x010
+#define M_WARNING      0x020
+#define M_ERROR               0x040
+#define M_SECURITY     0x080
+#define M_FATAL               0x100
 
 extern void fatal(char *message, ...);
 extern void fatal_perror(char *message, ...);
@@ -308,15 +314,15 @@ struct comm_if {
 
 /* LOG interface */
 
-typedef void log_msg_fn(void *st, int priority, char *message, ...);
-typedef void log_vmsg_fn(void *st, int priority, char *message, va_list args);
+typedef void log_msg_fn(void *st, int class, char *message, ...);
+typedef void log_vmsg_fn(void *st, int class, char *message, va_list args);
 struct log_if {
     void *st;
     log_msg_fn *log;
     log_vmsg_fn *vlog;
 };
 /* (convenience function, defined in util.c) */
-extern void log(struct log_if *lf, int priority, char *message, ...);
+extern void log(struct log_if *lf, int class, char *message, ...);
 
 /* SITE interface */
 
diff --git a/site.c b/site.c
index 989ad3ee28d925b36fd0ad9151631e962e321508..da410c0c1a1fe6a93b2429337f83cdde6f424e9f 100644 (file)
--- a/site.c
+++ b/site.c
@@ -194,12 +194,27 @@ static void slog(struct site *st, uint32_t event, string_t msg, ...)
 {
     va_list ap;
     uint8_t buf[240];
+    uint32_t class;
 
     va_start(ap,msg);
 
     if (event&st->log_events) {
+       switch(event) {
+       case LOG_UNEXPECTED: class=M_INFO; break;
+       case LOG_SETUP_INIT: class=M_INFO; break;
+       case LOG_SETUP_TIMEOUT: class=M_NOTICE; break;
+       case LOG_ACTIVATE_KEY: class=M_INFO; break;
+       case LOG_TIMEOUT_KEY: class=M_INFO; break;
+       case LOG_SEC: class=M_SECURITY; break;
+       case LOG_STATE: class=M_DEBUG; break;
+       case LOG_DROP: class=M_DEBUG; break;
+       case LOG_DUMP: class=M_DEBUG; break;
+       case LOG_ERROR: class=M_ERROR; break;
+       default: class=M_ERROR; break;
+       }
+
        vsnprintf(buf,240,msg,ap);
-       st->log->log(st->log->st,0,"%s: %s",st->tunname,buf);
+       st->log->log(st->log->st,class,"%s: %s",st->tunname,buf);
     }
     va_end(ap);
 }
@@ -638,7 +653,7 @@ static void dump_packet(struct site *st, struct buffer_if *buf,
     uint32_t msgtype=ntohl(*(uint32_t *)(buf->start+8));
 
     if (st->log_events & LOG_DUMP)
-       log(st->log,0,"%s: %s: %08x<-%08x: %08x:",
+       log(st->log,M_DEBUG,"%s: %s: %08x<-%08x: %08x:",
            st->tunname,incoming?"incoming":"outgoing",
            dest,source,msgtype);
 }
@@ -1150,7 +1165,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
        site() closures for all sites including our own): refuse to
        talk to ourselves */
     if (strcmp(st->localname,st->remotename)==0) {
-       Message(M_INFO,"site %s: local-name==name -> ignoring this site\n",
+       Message(M_DEBUG,"site %s: local-name==name -> ignoring this site\n",
                st->localname);
        free(st);
        return NULL;
diff --git a/slip.c b/slip.c
index 2928c1f26e47eb17deca67650c3c1910b44cc0ae..afc0528e238ccefff6125923e783203c6b2095ce 100644 (file)
--- a/slip.c
+++ b/slip.c
@@ -29,6 +29,7 @@ struct userv {
                               and send them to the site code. */
     bool_t pending_esc;
     netlink_deliver_fn *netlink_to_tunnel;
+    uint32_t local_address; /* host interface address */
 };
 
 static int userv_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
@@ -155,7 +156,7 @@ static void userv_phase_hook(void *sst, uint32_t newphase)
        be using should already have been registered. */
 
     addrs=safe_malloc(512,"userv_phase_hook:addrs");
-    snprintf(addrs,512,"%s,%s,%d,slip",ipaddr_to_string(st->nl.local_address),
+    snprintf(addrs,512,"%s,%s,%d,slip",ipaddr_to_string(st->local_address),
             ipaddr_to_string(st->nl.secnet_address),st->nl.mtu);
 
     nets=safe_malloc(1024,"userv_phase_hook:nets");
@@ -259,6 +260,8 @@ static list_t *userv_apply(closure_t *self, struct cloc loc, dict_t *context,
     if (!st->service_user) st->service_user="root";
     if (!st->service_name) st->service_name="ipif";
     st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"userv-netlink",loc);
+    st->local_address=string_to_ipaddr(
+       dict_find_item(dict,"local-address", True, "netlink", loc),"netlink");
     BUF_ALLOC(st->buff,"netlink:userv_apply");
 
     st->rxfd=-1; st->txfd=-1;
diff --git a/tun.c b/tun.c
index a36f444adf78d281a5e46426c6672a3235a468d8..01c0cb8960f942d505ccf8d3bc3d1fd077d2717d 100644 (file)
--- a/tun.c
+++ b/tun.c
@@ -28,6 +28,7 @@ struct tun {
     struct buffer_if *buff; /* We receive packets into here
                               and send them to the netlink code. */
     netlink_deliver_fn *netlink_to_tunnel;
+    uint32_t local_address; /* host interface address */
 };
 
 static int tun_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
@@ -156,7 +157,7 @@ static void tun_phase_hook(void *sst, uint32_t newphase)
                                                no extra headers */
        if (st->interface_name)
            strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
-       Message(M_INFO,"%s: about to ioctl(TUNSETIFF)...\n",st->nl.name);
+       Message(M_DEBUG,"%s: about to ioctl(TUNSETIFF)...\n",st->nl.name);
        if (ioctl(st->fd,TUNSETIFF,&ifr)<0) {
            fatal_perror("%s: ioctl(TUNSETIFF)",st->nl.name);
        }
@@ -174,7 +175,7 @@ static void tun_phase_hook(void *sst, uint32_t newphase)
        to set the TUN device's address, and route to add routes to all
        our networks. */
 
-    hostaddr=ipaddr_to_string(st->nl.local_address);
+    hostaddr=ipaddr_to_string(st->local_address);
     secnetaddr=ipaddr_to_string(st->nl.secnet_address);
     snprintf(mtu,6,"%d",st->nl.mtu);
     mtu[5]=0;
@@ -232,6 +233,8 @@ static list_t *tun_apply(closure_t *self, struct cloc loc, dict_t *context,
     if (!st->ifconfig_path) st->ifconfig_path="ifconfig";
     if (!st->route_path) st->route_path="route";
     st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"tun-netlink",loc);
+    st->local_address=string_to_ipaddr(
+       dict_find_item(dict,"local-address", True, "netlink", loc),"netlink");
 
     add_hook(PHASE_GETRESOURCES,tun_phase_hook,st);
 
@@ -276,6 +279,8 @@ static list_t *tun_old_apply(closure_t *self, struct cloc loc, dict_t *context,
     if (!st->ifconfig_path) st->ifconfig_path="ifconfig";
     if (!st->route_path) st->route_path="route";
     st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"tun-netlink",loc);
+    st->local_address=string_to_ipaddr(
+       dict_find_item(dict,"local-address", True, "netlink", loc),"netlink");
 
     /* Old TUN interface: the network interface name depends on which
        /dev/tunX file we open. If 'interface-search' is set to true, treat
diff --git a/udp.c b/udp.c
index ba9f9d6fe5f0cb095089c37f667aa53c4cc6631b..307a67a9f7d67cdb8dd42758040d3435e054d070 100644 (file)
--- a/udp.c
+++ b/udp.c
@@ -19,6 +19,7 @@
 #include <string.h>
 #include <errno.h>
 #include <sys/socket.h>
+#include <sys/wait.h>
 #include "util.h"
 
 static beforepoll_fn udp_beforepoll;
@@ -43,6 +44,7 @@ struct udp {
     struct cloc loc;
     uint16_t port;
     int fd;
+    string_t authbind;
     struct buffer_if *rbuf;
     struct notify_list *notify;
 };
@@ -167,8 +169,37 @@ static void udp_phase_hook(void *sst, uint32_t new_phase)
     memset(&addr, 0, sizeof(addr));
     addr.sin_family=AF_INET;
     addr.sin_port=htons(st->port);
-    if (bind(st->fd, (struct sockaddr *)&addr, sizeof(addr))!=0) {
-       fatal_perror("udp (%s:%d): bind",st->loc.file,st->loc.line);
+    if (st->authbind) {
+       pid_t c;
+       int status;
+
+       /* XXX this fork() and waitpid() business needs to be hidden
+          in some system-specific library functions. */
+       c=fork();
+       if (c==-1) {
+           fatal_perror("udp_phase_hook: fork() for authbind");
+       }
+       if (c==0) {
+           char *argv[4];
+           argv[0]=st->authbind;
+           argv[1]="00000000";
+           argv[2]=alloca(8);
+           if (!argv[2]) exit(ENOMEM);
+           sprintf(argv[2],"%04X",htons(st->port));
+           argv[3]=NULL;
+           dup2(st->fd,0);
+           execvp(st->authbind,argv);
+           exit(ENOEXEC);
+       }
+       waitpid(c,&status,0);
+       if (WEXITSTATUS(status)!=0) {
+           errno=WEXITSTATUS(status);
+           fatal_perror("udp (%s:%d): authbind",st->loc.file,st->loc.line);
+       }
+    } else {
+       if (bind(st->fd, (struct sockaddr *)&addr, sizeof(addr))!=0) {
+           fatal_perror("udp (%s:%d): bind",st->loc.file,st->loc.line);
+       }
     }
 
     register_for_poll(st,udp_beforepoll,udp_afterpoll,1,"udp");
@@ -201,6 +232,7 @@ static list_t *udp_apply(closure_t *self, struct cloc loc, dict_t *context,
 
     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);
 
     add_hook(PHASE_GETRESOURCES,udp_phase_hook,st);
 
diff --git a/util.c b/util.c
index 503dfe27b3aa0f3fd740b5aef0a258fe6d1d083c..480f6bce64915c641b7c17ca4fcf68e36daf1aee 100644 (file)
--- a/util.c
+++ b/util.c
@@ -1,21 +1,43 @@
-/* $Log: util.c,v $
- * Revision 1.2  1996/04/14 16:34:36  sde1000
- * Added syslog support
- * mpbin/mpstring functions moved from dh.c
- *
- * Revision 1.1  1996/03/14 17:05:03  sde1000
- * Initial revision
+/*
+ * util.c
+ * - output and logging support
+ * - program lifetime support
+ * - IP address and subnet munging routines
+ * - MPI convenience functions
+ */
+/*
+ *  This file is
+ *    Copyright (C) 1995--2001 Stephen Early <steve@greenend.org.uk>
  *
+ *  It is part of secnet, which is
+ *    Copyright (C) 1995--2001 Stephen Early <steve@greenend.org.uk>
+ *    Copyright (C) 1998 Ross Anderson, Eli Biham, Lars Knudsen
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software Foundation,
+ *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
  */
 
 #include "secnet.h"
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
+#include <syslog.h>
 #include <unistd.h>
 #include <limits.h>
 #include <assert.h>
 #include <sys/wait.h>
+#include <time.h>
 #include "util.h"
 #include "unaligned.h"
 
@@ -25,8 +47,9 @@
 
 static char *hexdigits="0123456789abcdef";
 
-uint32_t message_level=M_WARNING|M_ERROR|M_FATAL;
-uint32_t syslog_level=M_WARNING|M_ERROR|M_FATAL;
+bool_t secnet_is_daemon=False;
+uint32_t message_level=M_WARNING|M_ERROR|M_SECURITY|M_FATAL;
+struct log_if *system_log=NULL;
 static uint32_t current_phase=0;
 
 struct phase_hook {
@@ -40,19 +63,30 @@ static struct phase_hook *hooks[NR_PHASES]={NULL,};
 static void vMessage(uint32_t class, char *message, va_list args)
 {
     FILE *dest=stdout;
-    if (class & message_level) {
-       if (class&M_FATAL || class&M_ERROR || class&M_WARNING) {
-           dest=stderr;
+#define MESSAGE_BUFLEN 1023
+    static char buff[MESSAGE_BUFLEN+1]={0,};
+    uint32_t bp;
+    char *nlp;
+
+    if (secnet_is_daemon) {
+       /* Messages go to the system log interface */
+       bp=strlen(buff);
+       vsnprintf(buff+bp,MESSAGE_BUFLEN-bp,message,args);
+       /* Each line is sent separately */
+       while ((nlp=strchr(buff,'\n'))) {
+           *nlp=0;
+           log(system_log,class,buff);
+           memmove(buff,nlp+1,strlen(nlp+1)+1);
+       }
+    } else {
+       /* Messages go to stdout/stderr */
+       if (class & message_level) {
+           if (class&M_FATAL || class&M_ERROR || class&M_WARNING) {
+               dest=stderr;
+           }
+           vfprintf(dest,message,args);
        }
-       vfprintf(dest,message,args);
     }
-/* XXX do something about syslog output here */
-#if 0
-    /* Maybe send message to syslog */
-    vsprintf(buff, message, args);
-    /* XXX Send each line as a separate log entry */
-    log(syslog_prio[level], buff);
-#endif /* 0 */
 }  
 
 void Message(uint32_t class, char *message, ...)
@@ -60,9 +94,7 @@ void Message(uint32_t class, char *message, ...)
     va_list ap;
 
     va_start(ap,message);
-
     vMessage(class,message,ap);
-
     va_end(ap);
 }
 
@@ -139,6 +171,295 @@ void cfgfatal(struct cloc loc, string_t facility, char *message, ...)
     exit(current_phase);
 }
 
+/* Take a list of log closures and merge them */
+struct loglist {
+    struct log_if *l;
+    struct loglist *next;
+};
+
+static void log_vmulti(void *sst, int class, char *message, va_list args)
+{
+    struct loglist *st=sst, *i;
+
+    if (secnet_is_daemon) {
+       for (i=st; i; i=i->next) {
+           i->l->vlog(i->l->st,class,message,args);
+       }
+    } else {
+       vMessage(class,message,args);
+       Message(class,"\n");
+    }
+}
+
+static void log_multi(void *st, int priority, char *message, ...)
+{
+    va_list ap;
+
+    va_start(ap,message);
+    log_vmulti(st,priority,message,ap);
+    va_end(ap);
+}
+
+struct log_if *init_log(list_t *ll)
+{
+    int i=0;
+    item_t *item;
+    closure_t *cl;
+    struct loglist *l=NULL, *n;
+    struct log_if *r;
+
+    if (list_length(ll)==1) {
+       item=list_elem(ll,0);
+       cl=item->data.closure;
+       if (cl->type!=CL_LOG) {
+           cfgfatal(item->loc,"init_log","closure is not a logger");
+       }
+       return cl->interface;
+    }
+    while ((item=list_elem(ll,i++))) {
+       if (item->type!=t_closure) {
+           cfgfatal(item->loc,"init_log","item is not a closure");
+       }
+       cl=item->data.closure;
+       if (cl->type!=CL_LOG) {
+           cfgfatal(item->loc,"init_log","closure is not a logger");
+       }
+       n=safe_malloc(sizeof(*n),"init_log");
+       n->l=cl->interface;
+       n->next=l;
+       l=n;
+    }
+    if (!l) {
+       fatal("init_log: no log");
+    }
+    r=safe_malloc(sizeof(*r), "init_log");
+    r->st=l;
+    r->log=log_multi;
+    r->vlog=log_vmulti;
+    return r;
+}
+
+struct logfile {
+    closure_t cl;
+    struct log_if ops;
+    struct cloc loc;
+    string_t logfile;
+    uint32_t level;
+    FILE *f;
+};
+
+static string_t months[]={
+    "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
+
+static void logfile_vlog(void *sst, int class, char *message, va_list args)
+{
+    struct logfile *st=sst;
+    time_t t;
+    struct tm *tm;
+
+    if (secnet_is_daemon) {
+       if (class&st->level) {
+           t=time(NULL);
+           tm=localtime(&t);
+           fprintf(st->f,"%s %2d %02d:%02d:%02d ",
+                   months[tm->tm_mon],tm->tm_mday,tm->tm_hour,tm->tm_min,
+                   tm->tm_sec);
+           vfprintf(st->f,message,args);
+           fprintf(st->f,"\n");
+           fflush(st->f);
+       }
+    } else {
+       vMessage(class,message,args);
+       Message(class,"\n");
+    }
+}
+
+static void logfile_log(void *state, int priority, char *message, ...)
+{
+    va_list ap;
+
+    va_start(ap,message);
+    logfile_vlog(state,priority,message,ap);
+    va_end(ap);
+}
+
+static void logfile_phase_hook(void *sst, uint32_t new_phase)
+{
+    struct logfile *st=sst;
+    FILE *f;
+
+    if (background) {
+       f=fopen(st->logfile,"a");
+       if (!f) fatal_perror("logfile (%s:%d): cannot open \"%s\"",
+                            st->loc.file,st->loc.line,st->logfile);
+       st->f=f;
+    }
+}
+
+static struct flagstr message_class_table[]={
+    { "debug-config", M_DEBUG_CONFIG },
+    { "debug-phase", M_DEBUG_PHASE },
+    { "debug", M_DEBUG },
+    { "all-debug", M_DEBUG|M_DEBUG_PHASE|M_DEBUG_CONFIG },
+    { "info", M_INFO },
+    { "notice", M_NOTICE },
+    { "warning", M_WARNING },
+    { "error", M_ERROR },
+    { "security", M_SECURITY },
+    { "fatal", M_FATAL },
+    { "default", M_WARNING|M_ERROR|M_SECURITY|M_FATAL },
+    { "verbose", M_INFO|M_NOTICE|M_WARNING|M_ERROR|M_SECURITY|M_FATAL },
+    { "quiet", M_FATAL },
+    { NULL, 0 }
+};
+
+static list_t *logfile_apply(closure_t *self, struct cloc loc, dict_t *context,
+                            list_t *args)
+{
+    struct logfile *st;
+    item_t *item;
+    dict_t *dict;
+
+    /* We should defer opening the logfile until the getresources
+       phase.  We should defer writing into the logfile until after we
+       become a daemon. */
+    
+    st=safe_malloc(sizeof(*st),"logfile_apply");
+    st->cl.description="logfile";
+    st->cl.type=CL_LOG;
+    st->cl.apply=NULL;
+    st->cl.interface=&st->ops;
+    st->ops.st=st;
+    st->ops.log=logfile_log;
+    st->ops.vlog=logfile_vlog;
+    st->loc=loc;
+    st->f=stderr;
+
+    item=list_elem(args,0);
+    if (!item || item->type!=t_dict) {
+       cfgfatal(loc,"logfile","argument must be a dictionary\n");
+    }
+    dict=item->data.dict;
+
+    st->logfile=dict_read_string(dict,"filename",True,"logfile",loc);
+    st->level=string_list_to_word(dict_lookup(dict,"class"),
+                                      message_class_table,"logfile");
+
+    add_hook(PHASE_GETRESOURCES,logfile_phase_hook,st);
+
+    return new_closure(&st->cl);
+}
+
+struct syslog {
+    closure_t cl;
+    struct log_if ops;
+    string_t ident;
+    int facility;
+    bool_t open;
+};
+
+static int msgclass_to_syslogpriority(uint32_t m)
+{
+    switch (m) {
+    case M_DEBUG_CONFIG: return LOG_DEBUG;
+    case M_DEBUG_PHASE: return LOG_DEBUG;
+    case M_DEBUG: return LOG_DEBUG;
+    case M_INFO: return LOG_INFO;
+    case M_NOTICE: return LOG_NOTICE;
+    case M_WARNING: return LOG_WARNING;
+    case M_ERROR: return LOG_ERR;
+    case M_SECURITY: return LOG_CRIT;
+    case M_FATAL: return LOG_EMERG;
+    default: return LOG_NOTICE;
+    }
+}
+    
+static void syslog_vlog(void *sst, int class, char *message,
+                        va_list args)
+{
+    struct syslog *st=sst;
+
+    if (st->open)
+       vsyslog(msgclass_to_syslogpriority(class),message,args);
+    else {
+       vMessage(class,message,args);
+       Message(class,"\n");
+    }
+}
+
+static void syslog_log(void *sst, int priority, char *message, ...)
+{
+    va_list ap;
+
+    va_start(ap,message);
+    syslog_vlog(sst,priority,message,ap);
+    va_end(ap);
+}
+
+static struct flagstr syslog_facility_table[]={
+    { "authpriv", LOG_AUTHPRIV },
+    { "cron", LOG_CRON },
+    { "daemon", LOG_DAEMON },
+    { "kern", LOG_KERN },
+    { "local0", LOG_LOCAL0 },
+    { "local1", LOG_LOCAL1 },
+    { "local2", LOG_LOCAL2 },
+    { "local3", LOG_LOCAL3 },
+    { "local4", LOG_LOCAL4 },
+    { "local5", LOG_LOCAL5 },
+    { "local6", LOG_LOCAL6 },
+    { "local7", LOG_LOCAL7 },
+    { "lpr", LOG_LPR },
+    { "mail", LOG_MAIL },
+    { "news", LOG_NEWS },
+    { "syslog", LOG_SYSLOG },
+    { "user", LOG_USER },
+    { "uucp", LOG_UUCP },
+    { NULL, 0 }
+};
+
+static void syslog_phase_hook(void *sst, uint32_t newphase)
+{
+    struct syslog *st=sst;
+
+    if (background) {
+       openlog(st->ident,0,st->facility);
+       st->open=True;
+    }
+}
+
+static list_t *syslog_apply(closure_t *self, struct cloc loc, dict_t *context,
+                           list_t *args)
+{
+    struct syslog *st;
+    dict_t *d;
+    item_t *item;
+    string_t facstr;
+
+    st=safe_malloc(sizeof(*st),"syslog_apply");
+    st->cl.description="syslog";
+    st->cl.type=CL_LOG;
+    st->cl.apply=NULL;
+    st->cl.interface=&st->ops;
+    st->ops.st=st;
+    st->ops.log=syslog_log;
+    st->ops.vlog=syslog_vlog;
+
+    item=list_elem(args,0);
+    if (!item || item->type!=t_dict)
+       cfgfatal(loc,"syslog","parameter must be a dictionary\n");
+    d=item->data.dict;
+
+    st->ident=dict_read_string(d, "ident", False, "syslog", loc);
+    facstr=dict_read_string(d, "facility", True, "syslog", loc);
+    st->facility=string_to_word(facstr,loc,
+                               syslog_facility_table,"syslog");
+    st->open=False;
+    add_hook(PHASE_GETRESOURCES,syslog_phase_hook,st);
+
+    return new_closure(&st->cl);
+}    
+
 char *safe_strdup(char *s, char *message)
 {
     char *d;
@@ -344,105 +665,6 @@ int sys_cmd(const char *path, char *arg, ...)
     return rv;
 }
 
-/* Take a list of log closures and merge them */
-struct loglist {
-    struct log_if *l;
-    struct loglist *next;
-};
-
-static void log_vmulti(void *state, int priority, char *message, va_list args)
-{
-    struct loglist *st=state, *i;
-
-    for (i=st; i; i=i->next) {
-       i->l->vlog(i->l->st,priority,message,args);
-    }
-}
-
-static void log_multi(void *st, int priority, char *message, ...)
-{
-    va_list ap;
-
-    va_start(ap,message);
-
-    log_vmulti(st,priority,message,ap);
-
-    va_end(ap);
-}
-
-struct log_if *init_log(list_t *ll)
-{
-    int i=0;
-    item_t *item;
-    closure_t *cl;
-    struct loglist *l=NULL, *n;
-    struct log_if *r;
-
-    while ((item=list_elem(ll,i++))) {
-       if (item->type!=t_closure) {
-           cfgfatal(item->loc,"init_log","item is not a closure");
-       }
-       cl=item->data.closure;
-       if (cl->type!=CL_LOG) {
-           cfgfatal(item->loc,"init_log","closure is not a logger");
-       }
-       n=safe_malloc(sizeof(*n),"init_log");
-       n->l=cl->interface;
-       n->next=l;
-       l=n;
-    }
-    if (!l) {
-       fatal("init_log: none of the items in the list are loggers");
-    }
-    r=safe_malloc(sizeof(*r), "init_log");
-    r->st=l;
-    r->log=log_multi;
-    r->vlog=log_vmulti;
-    return r;
-}
-
-struct logfile {
-    closure_t cl;
-    struct log_if ops;
-    FILE *f;
-};
-
-static void logfile_vlog(void *state, int priority, char *message,
-                        va_list args)
-{
-    struct logfile *st=state;
-
-    vfprintf(st->f,message,args);
-    fprintf(st->f,"\n");
-}
-
-static void logfile_log(void *state, int priority, char *message, ...)
-{
-    va_list ap;
-
-    va_start(ap,message);
-    logfile_vlog(state,priority,message,ap);
-    va_end(ap);
-}
-
-static list_t *logfile_apply(closure_t *self, struct cloc loc, dict_t *context,
-                            list_t *data)
-{
-    struct logfile *st;
-    
-    st=safe_malloc(sizeof(*st),"logfile_apply");
-    st->cl.description="logfile";
-    st->cl.type=CL_LOG;
-    st->cl.apply=NULL;
-    st->cl.interface=&st->ops;
-    st->ops.st=st;
-    st->ops.log=logfile_log;
-    st->ops.vlog=logfile_vlog;
-    st->f=stderr; /* XXX ignore args */
-
-    return new_closure(&st->cl);
-}
-       
 static char *phases[NR_PHASES]={
     "PHASE_INIT",
     "PHASE_GETOPTS",
@@ -625,5 +847,6 @@ init_module util_module;
 void util_module(dict_t *dict)
 {
     add_closure(dict,"logfile",logfile_apply);
+    add_closure(dict,"syslog",syslog_apply);
     add_closure(dict,"sysbuffer",buffer_apply);
 }
diff --git a/util.h b/util.h
index bb298f6d3aa151cc23e74404ca39cc782c1debc9..0c661a8876a7e974efbd58ab022b31089e0d50ed 100644 (file)
--- a/util.h
+++ b/util.h
@@ -11,7 +11,8 @@
 #include <gmp.h>
 
 extern uint32_t message_level;
-extern uint32_t syslog_level;
+extern bool_t secnet_is_daemon;
+extern struct log_if *system_log;
 
 #define BUF_ASSERT_FREE(buf) do { buffer_assert_free((buf), \
                                                     __FILE__,__LINE__); } \