diff options
Diffstat (limited to 'rpkid')
-rw-r--r-- | rpkid/examples/rpki.conf | 4 | ||||
-rw-r--r-- | rpkid/rpki-start-servers.py | 17 | ||||
-rw-r--r-- | rpkid/rpki/config.py | 17 | ||||
-rw-r--r-- | rpkid/rpki/daemonize.py | 129 | ||||
-rw-r--r-- | rpkid/rpki/irdbd.py | 35 | ||||
-rw-r--r-- | rpkid/rpki/pubd.py | 41 | ||||
-rw-r--r-- | rpkid/rpki/rootd.py | 56 | ||||
-rw-r--r-- | rpkid/rpki/rpkid.py | 43 |
8 files changed, 286 insertions, 56 deletions
diff --git a/rpkid/examples/rpki.conf b/rpkid/examples/rpki.conf index add367da..fdcd4cdd 100644 --- a/rpkid/examples/rpki.conf +++ b/rpkid/examples/rpki.conf @@ -82,7 +82,7 @@ rootd_server_port = 4401 # generated certificates match up with the published objects so that # relying parties can find and verify rpkid's published outputs. -publication_base_directory = publication/ +publication_base_directory = publication # rsyncd module name corresponding to publication_base_directory. # This has to match the module you configured into rsyncd.conf. @@ -317,7 +317,7 @@ rpki-root-cert = ${myrpki::publication_base_directory}/root.cer # Where rootd should stash a copy of the PKCS #10 request it gets from # its one (and only) child -rpki-subject-pkcs10 = rootd.subject.pkcs10 +rpki-subject-pkcs10 = ${myrpki::bpki_servers_directory}/rootd.subject.pkcs10 # Lifetime of the one and only certificate rootd issues diff --git a/rpkid/rpki-start-servers.py b/rpkid/rpki-start-servers.py index 10051e89..e7061062 100644 --- a/rpkid/rpki-start-servers.py +++ b/rpkid/rpki-start-servers.py @@ -43,9 +43,8 @@ time.tzset() cfg_file = None debug = False -piddir = None -opts, argv = getopt.getopt(sys.argv[1:], "c:dhp:?", ["config=", "debug" "help", "piddir="]) +opts, argv = getopt.getopt(sys.argv[1:], "c:dhp:?", ["config=", "debug" "help"]) for o, a in opts: if o in ("-h", "--help", "-?"): print __doc__ @@ -54,23 +53,23 @@ for o, a in opts: cfg_file = a elif o in ("-d", "--debug"): debug = True - elif o in ("-p", "--piddir"): - piddir = a cfg = rpki.config.parser(cfg_file, "myrpki") + def run(name): cmd = (sys.executable, os.path.join(rpkid_dir, name), "-c", cfg.filename) if debug: proc = subprocess.Popen(cmd + ("-d",), stdout = open(name + ".log", "a"), stderr = subprocess.STDOUT) else: proc = subprocess.Popen(cmd) - if proc.poll() is None: - print "Started %r, pid %s" % (name, proc.pid) - if piddir is not None: - open(os.path.join(piddir, "%s.pid" % name), "w").write("%d\n" % proc.pid) + if debug and proc.poll() is None: + print "Started %s, pid %s" % (name, proc.pid) + elif not debug and proc.wait() == 0: + print "Started %s" % name else: - print "Problem starting %r, pid %s" % (name, proc.pid) + print "Problem starting %s, pid %s" % (name, proc.pid) + if cfg.getboolean("start_rpkid", cfg.getboolean("run_rpkid", False)): run("irdbd") diff --git a/rpkid/rpki/config.py b/rpkid/rpki/config.py index bba4a62c..c954ad5f 100644 --- a/rpkid/rpki/config.py +++ b/rpkid/rpki/config.py @@ -195,7 +195,12 @@ class parser(object): its data is less silly than the available alternatives. """ - import rpki.http, rpki.x509, rpki.sql, rpki.async, rpki.log + import rpki.http + import rpki.x509 + import rpki.sql + import rpki.async + import rpki.log + import rpki.daemonize try: rpki.http.debug_http = self.getboolean("debug_http") @@ -270,3 +275,13 @@ class parser(object): rpki.log.enable_tracebacks = self.getboolean("enable_tracebacks") except ConfigParser.NoOptionError: pass + + try: + rpki.daemonize.default_pid_directory = self.get("pid_directory") + except ConfigParser.NoOptionError: + pass + + try: + rpki.daemonize.pid_filename = self.get("pid_filename") + except ConfigParser.NoOptionError: + pass diff --git a/rpkid/rpki/daemonize.py b/rpkid/rpki/daemonize.py new file mode 100644 index 00000000..55dc106a --- /dev/null +++ b/rpkid/rpki/daemonize.py @@ -0,0 +1,129 @@ +""" +Make a normal program into a "daemon", like the 4.4BSD daemon(3) call. + +This quite follow either the 4.4BSD call or the Python 3.x library, +because it was written to fit into an existing package and I didn't +want to drag in yet another external library just for this. + +Some code borrowed from + http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/ + +(which was explicitly placed in public domain by its author), and from + + /usr/src/lib/libc/gen/daemon.c + +(the libc implementation of daemon(3) on FreeBSD). + +$Id$ + +Copyright (C) 2012 Internet Systems Consortium ("ISC") + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +Portions copyright (c) 1990, 1993 + The Regents of the University of California. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. +""" + +import sys +import os +import atexit +import signal + +# Does default_pid_directory need to be autoconf-configurable? + +## @var default_pid_directory +# Default directory to which to write process ID files. + +default_pid_directory = "/var/run/rpki" + +## @var pid_filename +# Configurable filename to which to write process ID file. +# pidfile argument to daemon() overrides this. + +pid_filename = None + +def daemon(nochdir = False, noclose = False, pidfile = None): + """ + Make this program become a daemon, like 4.4BSD daemon(3), and + write its pid out to a file with cleanup on exit. + """ + + if pidfile is None: + if pid_filename is None: + prog = os.path.splitext(os.path.basename(sys.argv[0]))[0] + pidfile = os.path.join(default_pid_directory, "%s.pid" % prog) + else: + pidfile = pid_filename + + old_sighup_action = signal.signal(signal.SIGHUP, signal.SIG_IGN) + + try: + pid = os.fork() + except OSError, e: + sys.exit("fork() failed: %d (%s)" % (e.errno, e.strerror)) + else: + if pid > 0: + os._exit(0) + + if not nochdir: + os.chdir("/") + + os.setsid() + + if not noclose: + sys.stdout.flush() + sys.stderr.flush() + fd = os.open(os.devnull, os.O_RDWR) + os.dup2(fd, 0) + os.dup2(fd, 1) + os.dup2(fd, 2) + if fd > 2: + os.close(fd) + + signal.signal(signal.SIGHUP, old_sighup_action) + + def delete_pid_file(): + try: + os.unlink(pidfile) + except OSError: + pass + + atexit.register(delete_pid_file) + + f = open(pidfile, "w") + f.write("%d\n" % os.getpid()) + f.close() diff --git a/rpkid/rpki/irdbd.py b/rpkid/rpki/irdbd.py index 28e26b07..166b160a 100644 --- a/rpkid/rpki/irdbd.py +++ b/rpkid/rpki/irdbd.py @@ -1,7 +1,10 @@ """ IR database daemon. -Usage: python irdbd.py [ { -c | --config } configfile ] [ { -h | --help } ] +Usage: python irdbd.py [ { -c | --config } configfile ] + [ { -d | --debug } ] + [ { -f | --foreground } ] + [ { -h | --help } ] $Id$ @@ -34,9 +37,21 @@ OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """ -import sys, os, time, getopt, urlparse, warnings -import rpki.http, rpki.config, rpki.resource_set, rpki.relaxng -import rpki.exceptions, rpki.left_right, rpki.log, rpki.x509 +import sys +import os +import time +import getopt +import urlparse +import warnings +import rpki.http +import rpki.config +import rpki.resource_set +import rpki.relaxng +import rpki.exceptions +import rpki.left_right +import rpki.log +import rpki.x509 +import rpki.daemonize class main(object): @@ -127,8 +142,9 @@ class main(object): time.tzset() cfg_file = None + foreground = False - opts, argv = getopt.getopt(sys.argv[1:], "c:dh?", ["config=", "debug", "help"]) + opts, argv = getopt.getopt(sys.argv[1:], "c:dfh?", ["config=", "debug", "foreground", "help"]) for o, a in opts: if o in ("-h", "--help", "-?"): print __doc__ @@ -137,19 +153,24 @@ class main(object): cfg_file = a elif o in ("-d", "--debug"): rpki.log.use_syslog = False + foreground = True + elif o in ("-f", "--foreground"): + foreground = True if argv: raise rpki.exceptions.CommandParseFailure("Unexpected arguments %s" % argv) rpki.log.init("irdbd") cfg = rpki.config.parser(cfg_file, "irdbd") + cfg.set_global_flags() + + if not foreground: + rpki.daemonize.daemon() startup_msg = cfg.get("startup-message", "") if startup_msg: rpki.log.info(startup_msg) - cfg.set_global_flags() - # Do -not- turn on DEBUG here except for short-lived tests, # otherwise irdbd will eventually run out of memory and crash. # diff --git a/rpkid/rpki/pubd.py b/rpkid/rpki/pubd.py index 6968780d..555a4d6e 100644 --- a/rpkid/rpki/pubd.py +++ b/rpkid/rpki/pubd.py @@ -2,12 +2,14 @@ RPKI publication engine. Usage: python pubd.py [ { -c | --config } configfile ] + [ { -d | --debug } ] + [ { -f | --foreground } ] [ { -h | --help } ] [ { -p | --profile } outputfile ] $Id$ -Copyright (C) 2009--2011 Internet Systems Consortium ("ISC") +Copyright (C) 2009--2012 Internet Systems Consortium ("ISC") Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -36,10 +38,22 @@ OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """ -import os, time, getopt, sys, re -import rpki.resource_set, rpki.up_down, rpki.x509, rpki.sql -import rpki.http, rpki.config, rpki.exceptions, rpki.relaxng -import rpki.log, rpki.publication +import os +import time +import getopt +import sys +import re +import rpki.resource_set +import rpki.up_down +import rpki.x509 +import rpki.sql +import rpki.http +import rpki.config +import rpki.exceptions +import rpki.relaxng +import rpki.log +import rpki.publication +import rpki.daemonize class main(object): """ @@ -53,8 +67,10 @@ class main(object): self.cfg_file = None self.profile = False + self.foreground = False - opts, argv = getopt.getopt(sys.argv[1:], "c:dhp:?", ["config=", "debug", "help"]) + opts, argv = getopt.getopt(sys.argv[1:], "c:dfhp:?", + ["config=", "debug", "foreground", "help", "profile="]) for o, a in opts: if o in ("-h", "--help", "-?"): print __doc__ @@ -63,6 +79,9 @@ class main(object): self.cfg_file = a elif o in ("-d", "--debug"): rpki.log.use_syslog = False + self.foreground = True + elif o in ("-f", "--foreground"): + self.foreground = True elif o in ("-p", "--profile"): self.profile = a if argv: @@ -70,6 +89,12 @@ class main(object): rpki.log.init("pubd") + self.cfg = rpki.config.parser(self.cfg_file, "pubd") + self.cfg.set_global_flags() + + if not self.foreground: + rpki.daemonize.daemon() + if self.profile: import cProfile cProfile.run("self.main()", self.profile) @@ -78,13 +103,9 @@ class main(object): def main(self): - self.cfg = rpki.config.parser(self.cfg_file, "pubd") - if self.profile: rpki.log.info("Running in profile mode with output to %s" % self.profile) - self.cfg.set_global_flags() - self.sql = rpki.sql.session(self.cfg) self.bpki_ta = rpki.x509.X509(Auto_update = self.cfg.get("bpki-ta")) diff --git a/rpkid/rpki/rootd.py b/rpkid/rpki/rootd.py index feceffc5..ca2d824c 100644 --- a/rpkid/rpki/rootd.py +++ b/rpkid/rpki/rootd.py @@ -3,7 +3,10 @@ Trivial RPKI up-down protocol root server, for testing. Not suitable for production use. Overrides a bunch of method definitions from the rpki.* classes in order to reuse as much code as possible. -Usage: python rootd.py [ { -c | --config } configfile ] [ { -h | --help } ] +Usage: python rootd.py [ { -c | --config } configfile ] + [ { -d | --debug } ] + [ { -f | --foreground } ] + [ { -h | --help } ] $Id$ @@ -36,10 +39,22 @@ OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """ -import os, time, getopt, sys -import rpki.resource_set, rpki.up_down, rpki.left_right, rpki.x509 -import rpki.http, rpki.config, rpki.exceptions, rpki.relaxng -import rpki.sundial, rpki.log, rpki.oids +import os +import time +import getopt +import sys +import rpki.resource_set +import rpki.up_down +import rpki.left_right +import rpki.x509 +import rpki.http +import rpki.config +import rpki.exceptions +import rpki.relaxng +import rpki.sundial +import rpki.log +import rpki.oids +import rpki.daemonize rootd = None @@ -104,10 +119,10 @@ class main(object): self.rpki_root_cert = rpki.x509.X509(Auto_file = self.rpki_root_cert_file) def root_newer_than_subject(self): - return os.stat(self.rpki_root_cert_file).st_mtime > os.stat(self.rpki_root_dir + self.rpki_subject_cert).st_mtime + return os.stat(self.rpki_root_cert_file).st_mtime > os.stat(os.path.join(self.rpki_root_dir, self.rpki_subject_cert)).st_mtime def get_subject_cert(self): - filename = self.rpki_root_dir + self.rpki_subject_cert + filename = os.path.join(self.rpki_root_dir, self.rpki_subject_cert) try: x = rpki.x509.X509(Auto_file = filename) rpki.log.debug("Read subject cert %s" % filename) @@ -116,14 +131,14 @@ class main(object): return None def set_subject_cert(self, cert): - filename = self.rpki_root_dir + self.rpki_subject_cert + filename = os.path.join(self.rpki_root_dir, self.rpki_subject_cert) rpki.log.debug("Writing subject cert %s, SKI %s" % (filename, cert.hSKI())) f = open(filename, "wb") f.write(cert.get_DER()) f.close() def del_subject_cert(self): - filename = self.rpki_root_dir + self.rpki_subject_cert + filename = os.path.join(self.rpki_root_dir, self.rpki_subject_cert) rpki.log.debug("Deleting subject cert %s" % filename) os.remove(filename) @@ -199,8 +214,8 @@ class main(object): thisUpdate = now, nextUpdate = now + self.rpki_subject_lifetime, revokedCertificates = self.revoked) - rpki.log.debug("Writing CRL %s" % (self.rpki_root_dir + self.rpki_root_crl)) - f = open(self.rpki_root_dir + self.rpki_root_crl, "wb") + rpki.log.debug("Writing CRL %s" % os.path.join(self.rpki_root_dir, self.rpki_root_crl)) + f = open(os.path.join(self.rpki_root_dir, self.rpki_root_crl), "wb") f.write(crl.get_DER()) f.close() manifest_content = [(self.rpki_root_crl, crl)] @@ -226,8 +241,8 @@ class main(object): names_and_objs = manifest_content, keypair = manifest_keypair, certs = manifest_cert) - rpki.log.debug("Writing manifest %s" % (self.rpki_root_dir + self.rpki_root_manifest)) - f = open(self.rpki_root_dir + self.rpki_root_manifest, "wb") + rpki.log.debug("Writing manifest %s" % os.path.join(self.rpki_root_dir, self.rpki_root_manifest)) + f = open(os.path.join(self.rpki_root_dir, self.rpki_root_manifest), "wb") f.write(manifest.get_DER()) f.close() @@ -277,7 +292,7 @@ class main(object): def next_crl_number(self): if self.crl_number is None: try: - crl = rpki.x509.CRL(DER_file = self.rpki_root_dir + self.rpki_root_crl) + crl = rpki.x509.CRL(DER_file = os.path.join(self.rpki_root_dir, self.rpki_root_crl)) self.crl_number = crl.get_POWpkix().getExtension(rpki.oids.name2oid["cRLNumber"])[2] except: self.crl_number = 0 @@ -305,13 +320,14 @@ class main(object): self.serial_number = None self.crl_number = None self.revoked = [] + self.foreground = False os.environ["TZ"] = "UTC" time.tzset() self.cfg_file = None - opts, argv = getopt.getopt(sys.argv[1:], "c:dh?", ["config=", "debug", "help"]) + opts, argv = getopt.getopt(sys.argv[1:], "c:dfh?", ["config=", "debug", "foreground", "help"]) for o, a in opts: if o in ("-h", "--help", "-?"): print __doc__ @@ -320,17 +336,21 @@ class main(object): self.cfg_file = a elif o in ("-d", "--debug"): rpki.log.use_syslog = False + self.foreground = True + elif o in ("-f", "--foreground"): + self.foreground = True + if argv: raise rpki.exceptions.CommandParseFailure, "Unexpected arguments %s" % argv rpki.log.init("rootd") self.cfg = rpki.config.parser(self.cfg_file, "rootd") - - rpki.log.enable_tracebacks = True - self.cfg.set_global_flags() + if not self.foreground: + rpki.daemonize.daemon() + self.bpki_ta = rpki.x509.X509(Auto_update = self.cfg.get("bpki-ta")) self.rootd_bpki_key = rpki.x509.RSA( Auto_update = self.cfg.get("rootd-bpki-key")) self.rootd_bpki_cert = rpki.x509.X509(Auto_update = self.cfg.get("rootd-bpki-cert")) diff --git a/rpkid/rpki/rpkid.py b/rpkid/rpki/rpkid.py index 7501a16a..0fbf4093 100644 --- a/rpkid/rpki/rpkid.py +++ b/rpkid/rpki/rpkid.py @@ -2,12 +2,14 @@ RPKI engine daemon. Usage: python rpkid.py [ { -c | --config } configfile ] + [ { -d | --debug } ] + [ { -f | --foreground } ] [ { -h | --help } ] [ { -p | --profile } outputfile ] $Id$ -Copyright (C) 2009--2011 Internet Systems Consortium ("ISC") +Copyright (C) 2009--2012 Internet Systems Consortium ("ISC") Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -36,9 +38,25 @@ OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """ -import os, time, getopt, sys, lxml.etree, re, random -import rpki.resource_set, rpki.up_down, rpki.left_right, rpki.x509, rpki.sql -import rpki.http, rpki.config, rpki.exceptions, rpki.relaxng, rpki.log, rpki.async +import os +import time +import getopt +import sys +import lxml.etree +import re +import random +import rpki.resource_set +import rpki.up_down +import rpki.left_right +import rpki.x509 +import rpki.sql +import rpki.http +import rpki.config +import rpki.exceptions +import rpki.relaxng +import rpki.log +import rpki.async +import rpki.daemonize class main(object): """ @@ -52,14 +70,19 @@ class main(object): self.cfg_file = None self.profile = None + self.foreground = False - opts, argv = getopt.getopt(sys.argv[1:], "c:dhp:?", ["config=", "debug", "help", "profile="]) + opts, argv = getopt.getopt(sys.argv[1:], "c:dfhp:?", + ["config=", "debug", "foreground", "help", "profile="]) for o, a in opts: if o in ("-h", "--help", "-?"): print __doc__ sys.exit(0) elif o in ("-d", "--debug"): rpki.log.use_syslog = False + self.foreground = True + elif o in ("-f", "--foreground"): + self.foreground = True elif o in ("-c", "--config"): self.cfg_file = a elif o in ("-p", "--profile"): @@ -69,6 +92,12 @@ class main(object): rpki.log.init("rpkid") + self.cfg = rpki.config.parser(self.cfg_file, "rpkid") + self.cfg.set_global_flags() + + if not self.foreground: + rpki.daemonize.daemon() + if self.profile: import cProfile cProfile.run("self.main()", self.profile) @@ -77,8 +106,6 @@ class main(object): def main(self): - self.cfg = rpki.config.parser(self.cfg_file, "rpkid") - startup_msg = self.cfg.get("startup-message", "") if startup_msg: rpki.log.info(startup_msg) @@ -86,8 +113,6 @@ class main(object): if self.profile: rpki.log.info("Running in profile mode with output to %s" % self.profile) - self.cfg.set_global_flags() - self.sql = rpki.sql.session(self.cfg) self.bpki_ta = rpki.x509.X509(Auto_update = self.cfg.get("bpki-ta")) |