URL: https://github.com/freeipa/freeipa/pull/1254 Author: tiran Title: #1254: [WIP] Support sqlite NSSDB Action: opened
PR body: """ Prepare CertDB and NSSDatabase to support sqlite DB format. https://pagure.io/freeipa/issue/7049 Signed-off-by: Christian Heimes <chei...@redhat.com> """ To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/1254/head:pr1254 git checkout pr1254
From 4696378ab9c5549d6020285fb4508091be09e35b Mon Sep 17 00:00:00 2001 From: Christian Heimes <chei...@redhat.com> Date: Wed, 8 Nov 2017 12:10:54 +0100 Subject: [PATCH] [WIP] Support sqlite NSSDB Prepare CertDB and NSSDatabase to support sqlite DB format. https://pagure.io/freeipa/issue/7049 Signed-off-by: Christian Heimes <chei...@redhat.com> --- freeipa.spec.in | 5 ++ ipaclient/install/client.py | 10 +--- ipapython/certdb.py | 85 ++++++++++++++++++++++------- ipaserver/install/certs.py | 50 ++++++++--------- ipaserver/install/ipa_backup.py | 4 +- ipaserver/install/ipa_replica_prepare.py | 7 +-- ipaserver/install/ipa_restore.py | 4 +- ipaserver/install/ipa_server_certinstall.py | 19 +++---- ipaserver/secrets/store.py | 34 +++++++----- 9 files changed, 129 insertions(+), 89 deletions(-) diff --git a/freeipa.spec.in b/freeipa.spec.in index cb71fd7aed..cd430b769b 100644 --- a/freeipa.spec.in +++ b/freeipa.spec.in @@ -1593,9 +1593,14 @@ fi %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/default.conf %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/ca.crt %dir %attr(0755,root,root) %{_sysconfdir}/ipa/nssdb +# old dbm format %ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/cert8.db %ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/key3.db %ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/secmod.db +# new sqlite format +%ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/cert9.db +%ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/key4.db +%ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/pkcs11.txt %ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/pwdfile.txt %ghost %config(noreplace) %{_sysconfdir}/pki/ca-trust/source/ipa.p11-kit %dir %{_localstatedir}/lib/ipa-client diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py index 2f89e7eaed..6fa42e3665 100644 --- a/ipaclient/install/client.py +++ b/ipaclient/install/client.py @@ -2304,9 +2304,6 @@ def create_ipa_nssdb(): db = certdb.NSSDatabase(paths.IPA_NSSDB_DIR) db.create_db(mode=0o755, backup=True) os.chmod(db.pwd_file, 0o600) - os.chmod(os.path.join(db.secdir, 'cert8.db'), 0o644) - os.chmod(os.path.join(db.secdir, 'key3.db'), 0o644) - os.chmod(os.path.join(db.secdir, 'secmod.db'), 0o644) def update_ipa_nssdb(): @@ -3067,11 +3064,8 @@ def uninstall(options): logger.error("%s failed to stop tracking certificate: %s", cmonger.service_name, e) - for filename in (os.path.join(ipa_db.secdir, 'cert8.db'), - os.path.join(ipa_db.secdir, 'key3.db'), - os.path.join(ipa_db.secdir, 'secmod.db'), - os.path.join(ipa_db.secdir, 'pwdfile.txt')): - remove_file(filename) + for filename in certdb.NSS_FILES: + remove_file(os.path.join(ipa_db.secdir, filename)) # Remove any special principal names we added to the IPA CA helper certmonger.remove_principal_from_cas() diff --git a/ipapython/certdb.py b/ipapython/certdb.py index 92da7829ac..5f394e19b8 100644 --- a/ipapython/certdb.py +++ b/ipapython/certdb.py @@ -53,7 +53,9 @@ CA_NICKNAME_FMT = "%s IPA CA" -NSS_FILES = ("cert8.db", "key3.db", "secmod.db", "pwdfile.txt") +NSS_DBM_FILES = ("cert8.db", "key3.db", "secmod.db") +NSS_SQLITE_FILES = ("cert9.db", "key4.db", "pkcs11.txt") +NSS_FILES = NSS_DBM_FILES + NSS_SQLITE_FILES + ("pwdfile.txt",) TrustFlags = collections.namedtuple('TrustFlags', 'has_key trusted ca usages') @@ -224,14 +226,46 @@ class NSSDatabase(object): # got too tied to IPA server details, killing reusability. # BaseCertDB is a class that knows nothing about IPA. # Generic NSS DB code should be moved here. - def __init__(self, nssdir=None): + + default_dbtype = 'dbm' + + def __init__(self, nssdir=None, dbtype='auto'): if nssdir is None: self.secdir = tempfile.mkdtemp() self._is_temporary = True + if dbtype == 'auto': + dbtype = self.default_dbtype + else: + dbtype = dbtype else: self.secdir = nssdir self._is_temporary = False + if self.dbtype == 'auto': + if os.path.isfile(os.path.join(self.secdir, "cert9.db")): + dbtype = 'sqlite' + elif os.path.isfile(os.path.join(self.secdir, "cert8.db")): + dbtype = 'dbm' + else: + dbtype = self.default_dbtype + self.pwd_file = os.path.join(self.secdir, 'pwdfile.txt') + self.dbtype = dbtype + if dbtype == 'dbm': + self.certdb = os.path.join(self.secdir, "cert8.db") + self.keydb = os.path.join(self.secdir, "key3.db") + self.secmod = os.path.join(self.secdir, "secmod.db") + elif dbtype == 'sqlite': + self.certdb = os.path.join(self.secdir, "cert9.db") + self.keydb = os.path.join(self.secdir, "key4.db") + self.secmod = os.path.join(self.secdir, "pkcs11.txt") + else: + raise ValueError(dbtype) + self.filenames = [ + self.certdb, + self.keydb, + self.secmod, + self.pwd_file, + ] def close(self): if self._is_temporary: @@ -244,11 +278,16 @@ def __exit__(self, type, value, tb): self.close() def run_certutil(self, args, stdin=None, **kwargs): - new_args = [CERTUTIL, "-d", self.secdir] - new_args = new_args + args + new_args = [CERTUTIL, "-d", '{}:{}'.format(self.dbtype, self.secdir)] + new_args.extend(args) new_args.extend(['-f', self.pwd_file]) return ipautil.run(new_args, stdin, **kwargs) + def run_pk12util(self, args, stdin=None, **kwargs): + new_args = [PK12UTIL, "-d", '{}:{}'.format(self.dbtype, self.secdir)] + new_args.extend(args) + return ipautil.run(new_args, stdin, **kwargs) + def create_db(self, user=None, group=None, mode=None, backup=False): """Create cert DB @@ -257,13 +296,14 @@ def create_db(self, user=None, group=None, mode=None, backup=False): :param mode: Mode of the secdir :param backup: Backup the sedir files """ - dirmode = 0o750 - filemode = 0o640 - pwdfilemode = 0o640 if mode is not None: dirmode = mode filemode = mode & 0o666 pwdfilemode = mode & 0o660 + else: + dirmode = 0o750 + filemode = 0o640 + pwdfilemode = 0o640 uid = -1 gid = -1 @@ -273,7 +313,7 @@ def create_db(self, user=None, group=None, mode=None, backup=False): gid = grp.getgrnam(group).gr_gid if backup: - for filename in NSS_FILES: + for filename in self.filenames: path = os.path.join(self.secdir, filename) ipautil.backup_file(path) @@ -293,7 +333,7 @@ def create_db(self, user=None, group=None, mode=None, backup=False): # Finally fix up perms os.chown(self.secdir, uid, gid) os.chmod(self.secdir, dirmode) - for filename in NSS_FILES: + for filename in self.filenames: path = os.path.join(self.secdir, filename) if os.path.exists(path): os.chown(path, uid, gid) @@ -304,7 +344,7 @@ def create_db(self, user=None, group=None, mode=None, backup=False): os.chmod(path, new_mode) def restore(self): - for filename in NSS_FILES: + for filename in self.filenames: path = os.path.join(self.secdir, filename) backup_path = path + '.orig' save_path = path + '.ipasave' @@ -367,16 +407,17 @@ def get_trust_chain(self, nickname): return root_nicknames def export_pkcs12(self, nickname, pkcs12_filename, pkcs12_passwd=None): - args = [PK12UTIL, "-d", self.secdir, - "-o", pkcs12_filename, - "-n", nickname, - "-k", self.pwd_file] + args = [ + "-o", pkcs12_filename, + "-n", nickname, + "-k", self.pwd_file + ] pkcs12_password_file = None if pkcs12_passwd is not None: pkcs12_password_file = ipautil.write_tmp_file(pkcs12_passwd + '\n') - args = args + ["-w", pkcs12_password_file.name] + args.extend(["-w", pkcs12_password_file.name]) try: - ipautil.run(args) + self.run_pk12util(args) except ipautil.CalledProcessError as e: if e.returncode == 17: raise RuntimeError("incorrect password for pkcs#12 file %s" % @@ -391,15 +432,17 @@ def export_pkcs12(self, nickname, pkcs12_filename, pkcs12_passwd=None): pkcs12_password_file.close() def import_pkcs12(self, pkcs12_filename, pkcs12_passwd=None): - args = [PK12UTIL, "-d", self.secdir, - "-i", pkcs12_filename, - "-k", self.pwd_file, '-v'] + args = [ + "-i", pkcs12_filename, + "-k", self.pwd_file, + "-v" + ] pkcs12_password_file = None if pkcs12_passwd is not None: pkcs12_password_file = ipautil.write_tmp_file(pkcs12_passwd + '\n') - args = args + ["-w", pkcs12_password_file.name] + args.extend(["-w", pkcs12_password_file.name]) try: - ipautil.run(args) + self.run_pk12util(args) except ipautil.CalledProcessError as e: if e.returncode == 17: raise RuntimeError("incorrect password for pkcs#12 file %s" % diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py index a40aff5e91..ea0784fba4 100644 --- a/ipaserver/install/certs.py +++ b/ipaserver/install/certs.py @@ -103,18 +103,20 @@ class CertDB(object): # TODO: Remove all selfsign code def __init__(self, realm, nssdir, fstore=None, host_name=None, subject_base=None, ca_subject=None, - user=None, group=None, mode=None, create=False): - self.nssdb = NSSDatabase(nssdir) + user=None, group=None, mode=None, create=False, + dbtype='auto'): + self.nssdb = NSSDatabase(nssdir, dbtype=dbtype) self.secdir = nssdir self.realm = realm - self.noise_fname = self.secdir + "/noise.txt" - self.certdb_fname = self.secdir + "/cert8.db" - self.keydb_fname = self.secdir + "/key3.db" - self.secmod_fname = self.secdir + "/secmod.db" - self.pk12_fname = self.secdir + "/cacert.p12" - self.pin_fname = self.secdir + "/pin.txt" + self.noise_fname = os.path.join(self.secdir, "noise.txt") + + self.certdb_fname = self.nssdb.cerdb + self.keydb_fname = self.nssdb.keydb + self.secmod_fname = self.nssdb.secmod + self.pk12_fname = os.path.join(self.secdir, "cacert.p12") + self.pin_fname = os.path.join(self.secdir + "pin.txt") self.reqdir = None self.certreq_fname = None self.certder_fname = None @@ -171,15 +173,7 @@ def exists(self): """ Checks whether all NSS database files + our pwd_file exist """ - db_files = ( - self.secdir, - self.certdb_fname, - self.keydb_fname, - self.secmod_fname, - self.nssdb.pwd_file, - ) - - for f in db_files: + for f in self.nssdb.filenames: if not os.path.exists(f): return False return True @@ -291,11 +285,12 @@ def export_ca_cert(self, nickname, create_pkcs12=False): if create_pkcs12: ipautil.backup_file(self.pk12_fname) - ipautil.run([paths.PK12UTIL, "-d", self.secdir, - "-o", self.pk12_fname, - "-n", self.cacert_name, - "-w", self.passwd_fname, - "-k", self.passwd_fname]) + self.nssdb.run_pk12util([ + "-o", self.pk12_fname, + "-n", self.cacert_name, + "-k", self.passwd_fname, + "-w", self.passwd_fname, + ]) self.set_perms(self.pk12_fname) def load_cacert(self, cacert_fname, trust_flags): @@ -514,11 +509,12 @@ def export_pkcs12(self, pkcs12_fname, pkcs12_pwd_fname, nickname=None): if nickname is None: nickname = get_ca_nickname(api.env.realm) - ipautil.run([paths.PK12UTIL, "-d", self.secdir, - "-o", pkcs12_fname, - "-n", nickname, - "-k", self.passwd_fname, - "-w", pkcs12_pwd_fname]) + self.nssdb.run_pk12util([ + "-o", pkcs12_fname, + "-n", nickname, + "-k", self.passwd_fname, + "-w", pkcs12_pwd_fname + ]) def create_from_cacert(self): cacert_fname = paths.IPA_CA_CRT diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py index ac9b0fc1d7..86cb33e0aa 100644 --- a/ipaserver/install/ipa_backup.py +++ b/ipaserver/install/ipa_backup.py @@ -38,7 +38,7 @@ from ipalib import api, errors from ipapython import version from ipapython.ipautil import run, write_tmp_file -from ipapython import admintool +from ipapython import admintool, certdb from ipapython.dn import DN from ipaserver.install.replication import wait_for_task from ipaserver.install import installutils @@ -192,7 +192,7 @@ class Backup(admintool.AdminTool): paths.HOSTS, ) + tuple( os.path.join(paths.IPA_NSSDB_DIR, file) - for file in ('cert8.db', 'key3.db', 'secmod.db') + for file in (certdb.NSS_DBM_FILES + certdb.NSS_SQLITE_FILES) ) logs=( diff --git a/ipaserver/install/ipa_replica_prepare.py b/ipaserver/install/ipa_replica_prepare.py index 1b82218858..e5808746b0 100644 --- a/ipaserver/install/ipa_replica_prepare.py +++ b/ipaserver/install/ipa_replica_prepare.py @@ -45,7 +45,7 @@ from ipaserver.install.server.replicainstall import install_ca_cert from ipaserver.install.bindinstance import ( add_zone, add_fwd_rr, add_ptr_rr, dns_container_exists) -from ipapython import ipautil, admintool +from ipapython import ipautil, admintool, certdb from ipapython.dn import DN from ipapython import version from ipalib import api @@ -565,9 +565,8 @@ def export_certdb(self, fname, passwd_fname): installutils.remove_file(pkcs12_fname) installutils.remove_file(passwd_fname) - self.remove_info_file("cert8.db") - self.remove_info_file("key3.db") - self.remove_info_file("secmod.db") + for fname in (certdb.NSS_SQLITE_FILES + certdb.NSS_SQLITE_FILES): + self.remove_info_file(fname) self.remove_info_file("noise.txt") orig_filename = passwd_fname + ".orig" diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py index 7bcb0d4924..b19c90e200 100644 --- a/ipaserver/install/ipa_restore.py +++ b/ipaserver/install/ipa_restore.py @@ -40,7 +40,7 @@ from ipalib.constants import FQDN from ipapython import version, ipautil from ipapython.ipautil import run, user_input -from ipapython import admintool +from ipapython import admintool, certdb from ipapython.dn import DN from ipaserver.install.replication import (wait_for_task, ReplicationManager, get_cs_replication_manager) @@ -842,7 +842,7 @@ def cert_restore_prepare(self): krbinstance.KrbInstance().stop_tracking_certs() - for basename in ('cert8.db', 'key3.db', 'secmod.db', 'pwdfile.txt'): + for basename in certdb.NSS_FILES: filename = os.path.join(paths.IPA_NSSDB_DIR, basename) try: ipautil.backup_file(filename) diff --git a/ipaserver/install/ipa_server_certinstall.py b/ipaserver/install/ipa_server_certinstall.py index 36c0a586d6..06f4b61fde 100644 --- a/ipaserver/install/ipa_server_certinstall.py +++ b/ipaserver/install/ipa_server_certinstall.py @@ -30,9 +30,10 @@ from ipaplatform.constants import constants from ipaplatform.paths import paths from ipapython import admintool -from ipapython.certdb import (get_ca_nickname, - NSSDatabase, - verify_kdc_cert_validity) +from ipapython.certdb import ( + NSS_DBM_FILES, NSS_SQLITE_FILES, NSSDatabase, get_ca_nickname, + verify_kdc_cert_validity +) from ipapython.dn import DN from ipalib import api, errors from ipaserver.install import certs, dsinstance, installutils, krbinstance @@ -170,14 +171,12 @@ def install_http_cert(self): quotes=False) # Fix the database permissions - os.chmod(os.path.join(dirname, 'cert8.db'), 0o640) - os.chmod(os.path.join(dirname, 'key3.db'), 0o640) - os.chmod(os.path.join(dirname, 'secmod.db'), 0o640) - pent = pwd.getpwnam(constants.HTTPD_USER) - os.chown(os.path.join(dirname, 'cert8.db'), 0, pent.pw_gid) - os.chown(os.path.join(dirname, 'key3.db'), 0, pent.pw_gid) - os.chown(os.path.join(dirname, 'secmod.db'), 0, pent.pw_gid) + for filename in (NSS_DBM_FILES + NSS_SQLITE_FILES): + absname = os.path.join(dirname, filename) + if os.path.isfile(absname): + os.chmod(absname, 0o640) + os.chown(absname, 0, pent.pw_gid) def install_kdc_cert(self): ca_cert_file = paths.CA_BUNDLE_PEM diff --git a/ipaserver/secrets/store.py b/ipaserver/secrets/store.py index e741d3311e..364b748c06 100644 --- a/ipaserver/secrets/store.py +++ b/ipaserver/secrets/store.py @@ -6,6 +6,7 @@ from jwcrypto.common import json_decode, json_encode from ipaplatform.paths import paths from ipapython import ipautil +from ipapython.certdb import NSSDatabase from ipaserver.secrets.common import iSecLdap import ldap import os @@ -80,10 +81,11 @@ def export_key(self): '--wrap-nickname', self.wrap_nick, '--target-nickname', self.target_nick, '-o', wrapped_key_file]) - ipautil.run([ - paths.CERTUTIL, '-d', self.nssdb_path, + nssdb = NSSDatabase(self.nssdb_path) + nssdb.run_certutil([ '-L', '-n', self.target_nick, - '-a', '-o', certificate_file]) + '-a', '-o', certificate_file, + ]) with open(wrapped_key_file, 'rb') as f: wrapped_key = f.read() with open(certificate_file, 'r') as f: @@ -120,12 +122,13 @@ def export_key(self): with open(pk12pwfile, 'w') as f: f.write(password) pk12file = os.path.join(tdir, 'pk12file') - ipautil.run([paths.PK12UTIL, - "-d", self.nssdb_path, - "-o", pk12file, - "-n", self.nickname, - "-k", nsspwfile, - "-w", pk12pwfile]) + nssdb = NSSDatabase(self.nssdb_path) + nssdb.run_pk12util([ + "-o", pk12file, + "-n", self.nickname, + "-k", nsspwfile, + "-w", pk12pwfile, + ]) with open(pk12file, 'rb') as f: data = f.read() finally: @@ -146,12 +149,13 @@ def import_key(self, value): pk12file = os.path.join(tdir, 'pk12file') with open(pk12file, 'wb') as f: f.write(b64decode(v['pkcs12 data'])) - ipautil.run([paths.PK12UTIL, - "-d", self.nssdb_path, - "-i", pk12file, - "-n", self.nickname, - "-k", nsspwfile, - "-w", pk12pwfile]) + nssdb = NSSDatabase(self.nssdb_path) + nssdb.run_pk12util([ + "-i", pk12file, + "-n", self.nickname, + "-k", nsspwfile, + "-w", pk12pwfile, + ]) finally: shutil.rmtree(tdir)
_______________________________________________ FreeIPA-devel mailing list -- freeipa-devel@lists.fedorahosted.org To unsubscribe send an email to freeipa-devel-le...@lists.fedorahosted.org