aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2016-03-21 02:39:08 +0000
committerRob Austein <sra@hactrn.net>2016-03-21 02:39:08 +0000
commit004393bdc2f3df5d85da88819bf47d72a883f7bb (patch)
treef325be9f47b29c5f134832f4933ff0066529c8de
parentd3cb2a1152bdb9a0cb391a388c702ff2f3be8371 (diff)
Rework rpkic setuid handling to something a bit more robust.
svn path=/branches/tk705/; revision=6322
-rwxr-xr-xca/rpkic19
-rw-r--r--rpki/cli.py22
-rw-r--r--rpki/irdb/zookeeper.py13
-rw-r--r--rpki/rpkic.py98
4 files changed, 122 insertions, 30 deletions
diff --git a/ca/rpkic b/ca/rpkic
index 2e215095..598c075f 100755
--- a/ca/rpkic
+++ b/ca/rpkic
@@ -15,19 +15,32 @@ if __name__ == "__main__":
import sys
import rpki.autoconf
+ argv = [sys.executable, os.path.abspath(sys.argv[0])]
+ argv.extend(sys.argv[1:])
+
+ already_ran_sudo = os.getenv("SUDO_COMMAND") == " ".join(argv)
+
try:
uid = pwd.getpwnam(rpki.autoconf.RPKI_USER).pw_uid
except:
uid = None
- if uid is None or uid == os.geteuid():
+ euid = os.geteuid()
+
+ if already_ran_sudo or uid is None or uid == euid or euid == 0:
+
+ if not already_ran_sudo:
+ for name in ("SUDO_COMMAND", "SUDO_GID", "SUDO_UID", "SUDO_USER"):
+ if name in os.environ:
+ del os.environ[name]
+
import rpki.rpkic
rpki.rpkic.main()
else:
+
try:
- argv = [rpki.autoconf.SUDO, "-u", rpki.autoconf.RPKI_USER, sys.executable]
- argv.extend(os.path.abspath(a) if i == 0 else a for i, a in enumerate(sys.argv))
+ argv.insert(0, rpki.autoconf.SUDO)
os.execv(argv[0], argv)
sys.exit("rpkic startup failure, no exception so don't know why, sorry")
diff --git a/rpki/cli.py b/rpki/cli.py
index 2f007101..cbd2b1e1 100644
--- a/rpki/cli.py
+++ b/rpki/cli.py
@@ -165,7 +165,7 @@ class Cmd(cmd.Cmd):
old_completer_delims = readline.get_completer_delims()
if self.histfile is not None:
try:
- readline.read_history_file(self.histfile)
+ self.read_history()
except IOError:
pass
try:
@@ -174,11 +174,29 @@ class Cmd(cmd.Cmd):
finally:
if self.histfile is not None and readline.get_current_history_length():
try:
- readline.write_history_file(self.histfile)
+ self.save_history()
except IOError:
pass
readline.set_completer_delims(old_completer_delims)
+ def read_history(self):
+ """
+ Read readline history from file.
+
+ This is a separate method so that subclasses can wrap it when necessary.
+ """
+
+ readline.read_history_file(self.histfile)
+
+ def save_history(self):
+ """
+ Save readline history to file.
+
+ This is a separate method so that subclasses can wrap it when necessary.
+ """
+
+ readline.write_history_file(self.histfile)
+
else:
cmdloop_with_history = cmd.Cmd.cmdloop
diff --git a/rpki/irdb/zookeeper.py b/rpki/irdb/zookeeper.py
index e7d9965c..9d40263c 100644
--- a/rpki/irdb/zookeeper.py
+++ b/rpki/irdb/zookeeper.py
@@ -382,15 +382,10 @@ class Zookeeper(object):
configure_rootd() because that's easier for the GUI.
"""
- try:
- self.resource_ca.repositories.get(handle = self.handle)
- return None
-
- except rpki.irdb.models.Repository.DoesNotExist:
- e = Element(tag_oob_publisher_request, nsmap = oob_nsmap, version = oob_version,
- publisher_handle = self.handle)
- B64Element(e, tag_oob_publisher_bpki_ta, self.resource_ca.certificate)
- return etree_wrapper(e, msg = 'This is the "repository offer" file for you to use if you want to publish in your own repository')
+ e = Element(tag_oob_publisher_request, nsmap = oob_nsmap, version = oob_version,
+ publisher_handle = self.handle)
+ B64Element(e, tag_oob_publisher_bpki_ta, self.resource_ca.certificate)
+ return etree_wrapper(e, msg = 'This is the "repository offer" file for you to use if you want to publish in your own repository')
def write_bpki_files(self):
diff --git a/rpki/rpkic.py b/rpki/rpkic.py
index 7d63bbe7..68cac4b2 100644
--- a/rpki/rpkic.py
+++ b/rpki/rpkic.py
@@ -24,17 +24,11 @@ an overview of the available commands; type "help foo" for (more) detailed help
on the "foo" command.
"""
-# NB: As of this writing, I'm trying really hard to avoid having this
-# program depend on a Django settings.py file. This may prove to be a
-# waste of time in the long run, but for for now, this means that one
-# has to be careful about exactly how and when one imports Django
-# modules, or anything that imports Django modules. Bottom line is
-# that we don't import such modules until we need them.
-
import os
-import argparse
import sys
+import pwd
import time
+import argparse
import rpki.config
import rpki.sundial
import rpki.log
@@ -51,6 +45,25 @@ from rpki.cli import Cmd, parsecmd, cmdarg
module_doc = __doc__
+
+class swap_uids(object):
+ """
+ Context manager to wrap os.setreuid() calls safely.
+ """
+
+ def __init__(self):
+ self.uid = os.getuid()
+ self.euid = os.geteuid()
+
+ def __enter__(self):
+ os.setreuid(self.euid, self.uid)
+ return self
+
+ def __exit__(self, _type, value, traceback):
+ os.setreuid(self.uid, self.euid)
+ return False
+
+
class main(Cmd):
prompt = "rpkic> "
@@ -77,6 +90,8 @@ class main(Cmd):
def __init__(self):
+ self.drop_privs()
+
Cmd.__init__(self)
os.environ["TZ"] = "UTC"
time.tzset()
@@ -114,6 +129,50 @@ class main(Cmd):
else:
args.func(self, args)
+
+ def drop_privs(self):
+ """
+ Initialize UID swapping and drop unneeded privs.
+
+ Any error here we don't understand is dangerous and therefore fatal.
+ """
+
+ try:
+
+ try:
+ os.setgid(int(os.environ["SUDO_GID"]))
+ except KeyError:
+ pass
+
+ try:
+ uid = int(os.environ["SUDO_UID"])
+ except KeyError:
+ uid = os.getuid()
+
+ try:
+ os.setreuid(uid, pwd.getpwnam(rpki.autoconf.RPKI_USER).pw_uid)
+ except (KeyError, OSError) as e:
+ sys.exit("Couldn't drop privs to user {}: {!s}".format(rpki.autoconf.RPKI_USER, e))
+
+ except Exception as e:
+ sys.exit("Fatal error trying to drop privs: {!s}".format(e))
+
+ def read_history(self):
+ """
+ UID-swapping wrapper for parent .read_history() method.
+ """
+
+ with swap_uids():
+ Cmd.read_history(self)
+
+ def save_history(self):
+ """
+ UID-swapping wrapper for parent .save_history() method.
+ """
+
+ with swap_uids():
+ Cmd.save_history(self)
+
def read_config(self):
# pylint: disable=W0201,W0602,W0621
@@ -224,13 +283,15 @@ class main(Cmd):
rootd_case = self.zoo.run_rootd and self.zoo.handle == self.zoo.cfg.get("handle")
r = self.zoo.initialize()
- r.save("%s.identity.xml" % self.zoo.handle,
- None if rootd_case else sys.stdout)
+ with swap_uids():
+ r.save("%s.identity.xml" % self.zoo.handle,
+ None if rootd_case else sys.stdout)
if rootd_case:
r = self.zoo.configure_rootd()
if r is not None:
- r.save("%s.%s.repository-request.xml" % (self.zoo.handle, self.zoo.handle), sys.stdout)
+ with swap_uids():
+ r.save("%s.%s.repository-request.xml" % (self.zoo.handle, self.zoo.handle), sys.stdout)
self.zoo.write_bpki_files()
@@ -250,7 +311,8 @@ class main(Cmd):
self.zoo.reset_identity(args.handle)
r = self.zoo.initialize_resource_bpki()
- r.save("%s.identity.xml" % self.zoo.handle, sys.stdout)
+ with swap_uids():
+ r.save("%s.identity.xml" % self.zoo.handle, sys.stdout)
@parsecmd(argsubparsers)
@@ -304,7 +366,8 @@ class main(Cmd):
"""
r, child_handle = self.zoo.configure_child(args.child_xml, args.child_handle, args.valid_until)
- r.save("%s.%s.parent-response.xml" % (self.zoo.handle, child_handle), sys.stdout)
+ with swap_uids():
+ r.save("%s.%s.parent-response.xml" % (self.zoo.handle, child_handle), sys.stdout)
self.zoo.synchronize_ca()
@@ -350,7 +413,8 @@ class main(Cmd):
"""
r, parent_handle = self.zoo.configure_parent(args.parent_xml, args.parent_handle)
- r.save("%s.%s.repository-request.xml" % (self.zoo.handle, parent_handle), sys.stdout)
+ with swap_uids():
+ r.save("%s.%s.repository-request.xml" % (self.zoo.handle, parent_handle), sys.stdout)
@parsecmd(argsubparsers,
@@ -383,7 +447,8 @@ class main(Cmd):
r = self.zoo.configure_rootd()
if r is not None:
- r.save("%s.%s.repository-request.xml" % (self.zoo.handle, self.zoo.handle), sys.stdout)
+ with swap_uids():
+ r.save("%s.%s.repository-request.xml" % (self.zoo.handle, self.zoo.handle), sys.stdout)
self.zoo.write_bpki_files()
@@ -419,7 +484,8 @@ class main(Cmd):
"""
r, client_handle = self.zoo.configure_publication_client(args.client_xml, args.sia_base, args.flat)
- r.save("%s.repository-response.xml" % client_handle.replace("/", "."), sys.stdout)
+ with swap_uids():
+ r.save("%s.repository-response.xml" % client_handle.replace("/", "."), sys.stdout)
try:
self.zoo.synchronize_pubd()
except rpki.irdb.models.Repository.DoesNotExist: