Prepare migration of mod_nss NSSDB to sql format

- Refactor CertDB to look up values from its NSSDatabase.
- Add run_modutil() helpers to support sql format. modutil does not
  auto-detect the NSSDB format.
- Add migration helpers to CertDB.
- Add explicit DB format to NSSCertificateDatabase stanza
- Restore SELinux context when migrating NSSDB.
- Add some debugging and sanity checks to httpinstance.

The actual database format is still dbm. Certmonger on Fedora 27 does
neither auto-detect DB format nor support SQL out of the box.

https://pagure.io/freeipa/issue/7354

Signed-off-by: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Stanislav Laznicka <slaznick@redhat.com>
This commit is contained in:
Christian Heimes
2018-01-16 14:57:07 +01:00
parent 88fd3f9435
commit c5fb6c8502
6 changed files with 122 additions and 22 deletions

View File

@@ -45,8 +45,10 @@ from ipalib.errors import CertificateOperationError
from ipalib.install import certstore
from ipalib.util import strip_csr_header
from ipalib.text import _
from ipaplatform.constants import constants
from ipaplatform.paths import paths
logger = logging.getLogger(__name__)
@@ -147,14 +149,10 @@ class CertDB(object):
dbtype='auto'):
self.nssdb = NSSDatabase(nssdir, dbtype=dbtype)
self.secdir = nssdir
self.realm = realm
self.noise_fname = os.path.join(self.secdir, "noise.txt")
self.certdb_fname = self.nssdb.certdb
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
@@ -205,6 +203,27 @@ class CertDB(object):
ca_subject = ipautil.dn_attribute_property('_ca_subject')
subject_base = ipautil.dn_attribute_property('_subject_base')
# migration changes paths, just forward attribute lookup to nssdb
@property
def secdir(self):
return self.nssdb.secdir
@property
def dbtype(self):
return self.nssdb.dbtype
@property
def certdb_fname(self):
return self.nssdb.certdb
@property
def keydb_fname(self):
return self.nssdb.keydb
@property
def secmod_fname(self):
return self.nssdb.secmod
@property
def passwd_fname(self):
return self.nssdb.pwd_file
@@ -213,10 +232,7 @@ class CertDB(object):
"""
Checks whether all NSS database files + our pwd_file exist
"""
for f in self.nssdb.filenames:
if not os.path.exists(f):
return False
return True
return self.nssdb.exists()
def __del__(self):
if self.reqdir is not None:
@@ -261,6 +277,9 @@ class CertDB(object):
def run_certutil(self, args, stdin=None, **kwargs):
return self.nssdb.run_certutil(args, stdin, **kwargs)
def run_modutil(self, args, stdin=None, **kwargs):
return self.nssdb.run_modutil(args, stdin, **kwargs)
def create_noise_file(self):
if os.path.isfile(self.noise_fname):
os.remove(self.noise_fname)
@@ -278,8 +297,10 @@ class CertDB(object):
f.write(ipautil.ipa_generate_password())
def create_certdbs(self):
self.nssdb.create_db(user=self.user, group=self.group, mode=self.mode,
backup=True)
self.nssdb.create_db(
user=self.user, group=self.group, mode=self.mode,
backup=True
)
self.set_perms(self.passwd_fname, write=True)
def restore(self):
@@ -670,6 +691,49 @@ class CertDB(object):
return is_ipa_issued_cert(api, cert)
def disable_system_trust(self):
"""Disable system trust module of NSSDB
"""
name = 'Root Certs'
try:
result = self.run_modutil(
['-force', '-list', name],
env={},
capture_output=True
)
except ipautil.CalledProcessError as e:
if e.returncode == 29: # ERROR: Module not found in database.
logger.debug(
'Module %s not available, treating as disabled', name)
return False
raise
if 'Status: Enabled' in result.output:
self.run_modutil(
['-force', '-disable', name],
env={}
)
return True
return False
def needs_upgrade_format(self):
"""Check if NSSDB file format needs upgrade
Only upgrade if it's an existing dbm database and default
database type is no 'dbm'.
"""
return (
self.nssdb.dbtype == 'dbm' and
self.nssdb.dbtype != constants.NSS_DEFAULT_DBTYPE and
self.exists()
)
def upgrade_format(self):
"""Upgrade NSSDB to new file format
"""
self.nssdb.convert_db()
class _CrossProcessLock(object):
_DATETIME_FORMAT = '%Y%m%d%H%M%S%f'

View File

@@ -361,7 +361,8 @@ class HTTPInstance(service.Service):
ca='IPA',
profile=dogtag.DEFAULT_PROFILE,
dns=[self.fqdn],
post_command='restart_httpd'
post_command='restart_httpd',
storage='FILE',
)
finally:
if prev_helper is not None:

View File

@@ -369,6 +369,8 @@ class Service(object):
This server cert should be in DER format.
"""
if self.cert is None:
raise ValueError("{} has no cert".format(self.service_name))
dn = DN(('krbprincipalname', self.principal), ('cn', 'services'),
('cn', 'accounts'), self.suffix)
entry = api.Backend.ldap2.get_entry(dn)