certidude/certidude/common.py

139 lines
3.9 KiB
Python

import os
import click
import subprocess
from setproctitle import getproctitle
from random import SystemRandom
random = SystemRandom()
try:
from time import time_ns
except ImportError:
from time import time
def time_ns():
return int(time() * 10**9) # 64 bits integer, 32 ns bits
MAPPING = dict(
common_name="CN",
organizational_unit_name="OU",
organization_name="O",
domain_component="DC"
)
def cert_to_dn(cert):
d = []
for key, value in cert["tbs_certificate"]["subject"].native.items():
if not isinstance(value, list):
value = [value]
for comp in value:
d.append("%s=%s" % (MAPPING[key], comp))
return ", ".join(d)
def cn_to_dn(common_name, namespace, o=None, ou=None):
from asn1crypto.x509 import Name, RelativeDistinguishedName, NameType, DirectoryString, RDNSequence, NameTypeAndValue, UTF8String, DNSName
rdns = []
for dc in reversed(namespace.split(".")):
rdns.append(RelativeDistinguishedName([
NameTypeAndValue({
'type': NameType.map("domain_component"),
'value': DNSName(value=dc)
})
]))
if o:
rdns.append(RelativeDistinguishedName([
NameTypeAndValue({
'type': NameType.map("organization_name"),
'value': DirectoryString(
name="utf8_string",
value=UTF8String(o))
})
]))
if ou:
rdns.append(RelativeDistinguishedName([
NameTypeAndValue({
'type': NameType.map("organizational_unit_name"),
'value': DirectoryString(
name="utf8_string",
value=UTF8String(ou))
})
]))
rdns.append(RelativeDistinguishedName([
NameTypeAndValue({
'type': NameType.map("common_name"),
'value': DirectoryString(
name="utf8_string",
value=UTF8String(common_name))
})
]))
return Name(name='', value=RDNSequence(rdns))
def selinux_fixup(path):
"""
Fix OpenVPN credential store security context on Fedora
"""
if os.path.exists("/usr/bin/chcon"):
cmd = "chcon", "--type=home_cert_t", path
subprocess.call(cmd)
def drop_privileges():
from certidude import config
import pwd
_, _, uid, gid, gecos, root, shell = pwd.getpwnam("certidude")
restricted_groups = []
restricted_groups.append(gid)
# PAM needs access to /etc/shadow
if config.AUTHENTICATION_BACKENDS == {"pam"}:
import grp
name, passwd, num, mem = grp.getgrnam("shadow")
click.echo("Adding current user to shadow group due to PAM authentication backend")
restricted_groups.append(num)
os.setgroups(restricted_groups)
os.setgid(gid)
os.setuid(uid)
click.echo("Switched %s (pid=%d) to user %s (uid=%d, gid=%d); member of groups %s" %
(getproctitle(), os.getpid(), "certidude", os.getuid(), os.getgid(), ", ".join([str(j) for j in os.getgroups()])))
os.umask(0o007)
def apt(packages):
"""
Install packages for Debian and Ubuntu
"""
if os.path.exists("/usr/bin/apt-get"):
cmd = ["/usr/bin/apt-get", "install", "-yqq", "-o", "Dpkg::Options::=--force-confold"] + packages.split(" ")
click.echo("Running: %s" % " ".join(cmd))
subprocess.call(cmd)
return True
return False
def rpm(packages):
"""
Install packages for Fedora and CentOS
"""
if os.path.exists("/usr/bin/dnf"):
cmd = ["/usr/bin/dnf", "install", "-y"] + packages.split(" ")
click.echo("Running: %s" % " ".join(cmd))
subprocess.call(cmd)
return True
return False
def pip(packages):
click.echo("Running: pip3 install %s" % packages)
import pip
pip.main(['install'] + packages.split(" "))
return True
def generate_serial():
return time_ns() << 56 | random.randint(0, 2**56-1)