import grp import pwd import os import re import string import subprocess import sys from shutil import rmtree from tempfile import NamedTemporaryFile import click CERTTOOL_COMMAND = "@certtool@" TASKD_COMMAND = "@taskd@" TASKD_DATA_DIR = "@dataDir@" TASKD_USER = "@user@" TASKD_GROUP = "@group@" FQDN = "@fqdn@" RE_CONFIGUSER = re.compile(r'^\s*user\s*=(.*)$') def run_as_taskd_user(): uid = pwd.getpwnam(TASKD_USER).pw_uid gid = grp.getgrnam(TASKD_GROUP).gr_gid os.setgid(gid) os.setuid(uid) def taskd_cmd(cmd, *args, **kwargs): return subprocess.call( [TASKD_COMMAND, cmd, "--data", TASKD_DATA_DIR] + list(args), preexec_fn=run_as_taskd_user, **kwargs ) def label(msg): if sys.stdout.isatty() or sys.stderr.isatty(): sys.stderr.write(msg + "\n") def mkpath(*args): return os.path.join(TASKD_DATA_DIR, "orgs", *args) def fetch_username(org, key): for line in open(mkpath(org, "users", key, "config"), "r"): match = RE_CONFIGUSER.match(line) if match is None: continue return match.group(1).strip() return None def generate_key(org, user): basedir = os.path.join(TASKD_DATA_DIR, "keys", org, user) if os.path.exists(basedir): raise OSError("Keyfile directory for {} already exists.".format(user)) privkey = os.path.join(basedir, "private.key") pubcert = os.path.join(basedir, "public.cert") cakey = os.path.join(TASKD_DATA_DIR, "keys", "ca.key") cacert = os.path.join(TASKD_DATA_DIR, "keys", "ca.cert") try: os.makedirs(basedir, mode=0700) cmd = [CERTTOOL_COMMAND, "-p", "--bits", "2048", "--outfile", privkey] subprocess.call(cmd, preexec_fn=lambda: os.umask(0077)) template = NamedTemporaryFile(mode="w", prefix="certtool-template") template.writelines(map(lambda l: l + "\n", [ "organization = {0}".format(org), "cn = {}".format(FQDN), "tls_www_client", "encryption_key", "signing_key" ])) template.flush() cmd = [CERTTOOL_COMMAND, "-c", "--load-privkey", privkey, "--load-ca-privkey", cakey, "--load-ca-certificate", cacert, "--template", template.name, "--outfile", pubcert] subprocess.call(cmd, preexec_fn=lambda: os.umask(0077)) except: rmtree(basedir) raise def is_key_line(line, match): return line.startswith("---") and line.lstrip("- ").startswith(match) def getkey(*args): path = os.path.join(TASKD_DATA_DIR, "keys", *args) buf = [] for line in open(path, "r"): if len(buf) == 0: if is_key_line(line, "BEGIN"): buf.append(line) continue buf.append(line) if is_key_line(line, "END"): return ''.join(buf) raise IOError("Unable to get key from {}.".format(path)) def mktaskkey(cfg, path, keydata): heredoc = 'cat > "{}" <