From 8a32bb3746802a29b2655e4ad2cbbba8481e1eaf Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Fri, 17 Jun 2011 16:47:39 -0400 Subject: Make dogtag an optional (and default un-) installed component in a replica. A dogtag replica file is created as usual. When the replica is installed dogtag is optional and not installed by default. Adding the --setup-ca option will configure it when the replica is installed. A new tool ipa-ca-install will configure dogtag if it wasn't configured when the replica was initially installed. This moves a fair bit of code out of ipa-replica-install into installutils and cainstance to avoid duplication. https://fedorahosted.org/freeipa/ticket/1251 --- freeipa.spec.in | 5 + install/po/Makefile.in | 2 + install/tools/Makefile.am | 1 + install/tools/ipa-ca-install | 183 ++++++++++++++++++++++++++++++++ install/tools/ipa-replica-install | 151 ++++---------------------- install/tools/man/Makefile.am | 1 + install/tools/man/ipa-ca-install.1 | 49 +++++++++ install/tools/man/ipa-replica-install.1 | 6 +- ipaserver/install/cainstance.py | 78 +++++++++++++- ipaserver/install/certs.py | 4 +- ipaserver/install/installutils.py | 57 ++++++++++ ipaserver/install/replication.py | 33 ++++++ 12 files changed, 437 insertions(+), 133 deletions(-) create mode 100755 install/tools/ipa-ca-install create mode 100644 install/tools/man/ipa-ca-install.1 diff --git a/freeipa.spec.in b/freeipa.spec.in index c49ca2b56..5ba38cb02 100644 --- a/freeipa.spec.in +++ b/freeipa.spec.in @@ -356,6 +356,7 @@ fi %files server %defattr(-,root,root,-) %doc COPYING README Contributors.txt +%{_sbindir}/ipa-ca-install %{_sbindir}/ipa-dns-install %{_sbindir}/ipa-server-install %{_sbindir}/ipa-replica-conncheck @@ -436,6 +437,7 @@ fi %{_mandir}/man1/ipa-server-certinstall.1.gz %{_mandir}/man1/ipa-server-install.1.gz %{_mandir}/man1/ipa-dns-install.1.gz +%{_mandir}/man1/ipa-ca-install.1.gz %{_mandir}/man1/ipa-compat-manage.1.gz %{_mandir}/man1/ipa-nis-manage.1.gz %{_mandir}/man1/ipa-host-net-manage.1.gz @@ -498,6 +500,9 @@ fi %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/default.conf %changelog +* Fri Jun 17 2011 Rob Crittenden - 2.0.90-4 +- Ship ipa-ca-install utility + * Thu May 12 2011 Rob Crittenden - 2.0.90-3 - Set min nvr of selinux-policy to 3.9.16-18 on F-15+ - Set min nvr of pki-ca to 9.0.7 on F-15+ diff --git a/install/po/Makefile.in b/install/po/Makefile.in index a1e804f9d..a54687527 100644 --- a/install/po/Makefile.in +++ b/install/po/Makefile.in @@ -53,6 +53,8 @@ PY_EXPLICIT_FILES = \ install/tools/ipa-host-net-manage \ install/tools/ipa-server-install \ install/tools/ipa-ldap-updater \ + install/tools/ipa-dns-install \ + install/tools/ipa-ca-install \ ipa-client/ipa-install/ipa-client-install PYTHON_POTFILES = $(PY_FILES) $(PY_EXPLICIT_FILES) diff --git a/install/tools/Makefile.am b/install/tools/Makefile.am index 9004bb248..c6ecd9287 100644 --- a/install/tools/Makefile.am +++ b/install/tools/Makefile.am @@ -5,6 +5,7 @@ SUBDIRS = \ $(NULL) sbin_SCRIPTS = \ + ipa-ca-install \ ipa-dns-install \ ipa-server-install \ ipa-replica-conncheck \ diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install new file mode 100755 index 000000000..edd8f4cfd --- /dev/null +++ b/install/tools/ipa-ca-install @@ -0,0 +1,183 @@ +#! /usr/bin/python -E +# Authors: Rob Crittenden +# +# Copyright (C) 2011 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import sys +import socket + +import os, traceback, logging, shutil + +from ipapython import ipautil + +from ipaserver.install import installutils, service +from ipaserver.install import certs +from ipaserver.install.installutils import HostnameLocalhost +from ipaserver.install.installutils import ReplicaConfig, expand_replica_info, read_replica_info +from ipaserver.install.installutils import get_host_name +from ipaserver.install import dsinstance, cainstance +from ipaserver.install.replication import replica_conn_check +from ipapython import version +from ipalib import api, util +from ipapython.config import IPAOptionParser +from ipapython import sysrestore + +CACERT="/etc/ipa/ca.crt" +REPLICA_INFO_TOP_DIR=None + +def parse_options(): + usage = "%prog [options] REPLICA_FILE" + parser = IPAOptionParser(usage=usage, version=version.VERSION) + parser.add_option("-d", "--debug", dest="debug", action="store_true", + default=False, help="gather extra debugging information") + parser.add_option("-p", "--password", dest="password", sensitive=True, + help="Directory Manager (existing master) password") + parser.add_option("-w", "--admin-password", dest="admin_password", sensitive=True, + help="Admin user Kerberos password used for connection check") + parser.add_option("--no-host-dns", dest="no_host_dns", action="store_true", + default=False, + help="Do not use DNS for hostname lookup during installation") + parser.add_option("--skip-conncheck", dest="skip_conncheck", action="store_true", + default=False, help="skip connection check to remote master") + parser.add_option("-U", "--unattended", dest="unattended", action="store_true", + default=False, help="unattended installation never prompts the user") + + options, args = parser.parse_args() + safe_options = parser.get_safe_opts(options) + + if len(args) != 1: + parser.error("you must provide a file generated by ipa-replica-prepare") + + return safe_options, options, args[0] + +def get_dirman_password(): + return installutils.read_password("Directory Manager (existing master)", confirm=False, validate=False) + +def main(): + safe_options, options, filename = parse_options() + installutils.standard_logging_setup("/var/log/ipareplica-ca-install.log", options.debug) + logging.debug('%s was invoked with argument "%s" and options: %s' % (sys.argv[0], filename, safe_options)) + + if not ipautil.file_exists(filename): + sys.exit("Replica file %s does not exist" % filename) + + global sstore + sstore = sysrestore.StateFile('/var/lib/ipa/sysrestore') + + if not dsinstance.DsInstance().is_configured(): + sys.exit("IPA server is not configured on this system.\n") + + # get the directory manager password + dirman_password = options.password + if not dirman_password: + if options.unattended: + sys.exit('Directory Manager password required') + try: + dirman_password = get_dirman_password() + except KeyboardInterrupt: + sys.exit(0) + + if not options.admin_password and not options.skip_conncheck and \ + options.unattended: + sys.exit('admin password required') + + try: + top_dir, dir = expand_replica_info(filename, dirman_password) + global REPLICA_INFO_TOP_DIR + REPLICA_INFO_TOP_DIR = top_dir + except Exception, e: + print "ERROR: Failed to decrypt or open the replica file." + print "Verify you entered the correct Directory Manager password." + sys.exit(1) + + config = ReplicaConfig() + read_replica_info(dir, config) + config.dirman_password = dirman_password + try: + host = get_host_name(options.no_host_dns) + except RuntimeError, e: + logging.error(str(e)) + sys.exit(1) + if config.host_name != host: + try: + print "This replica was created for '%s' but this machine is named '%s'" % (config.host_name, host) + if not ipautil.user_input("This may cause problems. Continue?", True): + sys.exit(0) + config.host_name = host + print "" + except KeyboardInterrupt: + sys.exit(0) + config.dir = dir + config.setup_ca = True + + if not options.skip_conncheck: + replica_conn_check(config.master_host_name, config.host_name, config.realm_name, True, options.admin_password) + + api.bootstrap(in_server=True) + api.finalize() + + # Configure the CA if necessary + (CA, cs) = cainstance.install_replica_ca(config, postinstall=True) + + # We need to ldap_enable the CA now that DS is up and running + CA.ldap_enable('CA', config.host_name, config.dirman_password, + util.realm_to_suffix(config.realm_name)) + cs.add_simple_service('dogtagldap/%s@%s' % (config.host_name, config.realm_name)) + cs.add_cert_to_service() + + service.print_msg("Setting the certificate subject base") + CA.set_subject_in_config(util.realm_to_suffix(config.realm_name)) + +try: + if not os.geteuid()==0: + sys.exit("\nYou must be root to run this script.\n") + + main() + sys.exit(0) +except SystemExit, e: + sys.exit(e) +except socket.error, (errno, errstr): + print errstr +except HostnameLocalhost: + print "The hostname resolves to the localhost address (127.0.0.1/::1)" + print "Please change your /etc/hosts file so that the hostname" + print "resolves to the ip address of your network interface." + print "" + print "Please fix your /etc/hosts file and restart the setup program" +except Exception, e: + print "creation of replica failed: %s" % str(e) + message = str(e) + for str in traceback.format_tb(sys.exc_info()[2]): + message = message + "\n" + str + logging.debug(message) +except KeyboardInterrupt: + print "Installation cancelled." +finally: + # always try to remove decrypted replica file + try: + if REPLICA_INFO_TOP_DIR: + shutil.rmtree(REPLICA_INFO_TOP_DIR) + except OSError: + pass + +print "" +print "Your system may be partly configured." +print "Run /usr/sbin/ipa-server-install --uninstall to clean up." + +# the only way to get here is on error or ^C +sys.exit(1) diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install index 3feb2a93d..7daa0e8e3 100755 --- a/install/tools/ipa-replica-install +++ b/install/tools/ipa-replica-install @@ -21,17 +21,19 @@ import sys import socket -import tempfile, os, pwd, traceback, logging, shutil +import os, pwd, traceback, logging, shutil import grp -from ConfigParser import SafeConfigParser from ipapython import ipautil from ipaserver.install import dsinstance, installutils, krbinstance, service from ipaserver.install import bindinstance, httpinstance, ntpinstance, certs -from ipaserver.install.replication import check_replication_plugin +from ipaserver.install.replication import check_replication_plugin, replica_conn_check from ipaserver.install.installutils import HostnameLocalhost, resolve_host +from ipaserver.install.installutils import ReplicaConfig, expand_replica_info, read_replica_info +from ipaserver.install.installutils import get_host_name from ipaserver.plugins.ldap2 import ldap2 +from ipaserver.install import cainstance from ipapython import version from ipalib import api, errors, util from ipapython.config import IPAOptionParser @@ -40,16 +42,6 @@ from ipapython import sysrestore CACERT="/etc/ipa/ca.crt" REPLICA_INFO_TOP_DIR=None -class ReplicaConfig: - def __init__(self): - self.realm_name = "" - self.domain_name = "" - self.master_host_name = "" - self.dirman_password = "" - self.host_name = "" - self.dir = "" - self.subject_base = "" - def parse_options(): usage = "%prog [options] REPLICA_FILE" parser = IPAOptionParser(usage=usage, version=version.VERSION) @@ -76,6 +68,8 @@ def parse_options(): default=True, help="disables pkinit setup steps") parser.add_option("--skip-conncheck", dest="skip_conncheck", action="store_true", default=False, help="skip connection check to remote master") + parser.add_option("--setup-ca", dest="setup_ca", action="store_true", + default=False, help="configure a dogtag CA") parser.add_option("-U", "--unattended", dest="unattended", action="store_true", default=False, help="unattended installation never prompts the user") @@ -102,98 +96,10 @@ def parse_options(): def get_dirman_password(): return installutils.read_password("Directory Manager (existing master)", confirm=False, validate=False) -def expand_info(filename, password): - top_dir = tempfile.mkdtemp("ipa") - tarfile = top_dir+"/files.tar" - dir = top_dir + "/realm_info" - ipautil.decrypt_file(filename, tarfile, password, top_dir) - ipautil.run(["tar", "xf", tarfile, "-C", top_dir]) - os.remove(tarfile) - - return top_dir, dir - -def read_info(dir, rconfig): - filename = dir + "/realm_info" - fd = open(filename) - config = SafeConfigParser() - config.readfp(fd) - - rconfig.realm_name = config.get("realm", "realm_name") - rconfig.master_host_name = config.get("realm", "master_host_name") - rconfig.domain_name = config.get("realm", "domain_name") - rconfig.host_name = config.get("realm", "destination_host") - rconfig.subject_base = config.get("realm", "subject_base") - -def get_host_name(no_host_dns): - hostname = installutils.get_fqdn() - try: - installutils.verify_fqdn(hostname, no_host_dns) - except RuntimeError, e: - logging.error(str(e)) - sys.exit(1) - - return hostname - def set_owner(config, dir): pw = pwd.getpwnam(dsinstance.DS_USER) os.chown(dir, pw.pw_uid, pw.pw_gid) -def install_ca(config): - # FIXME, need to pass along the CA plugin to use - cafile = config.dir + "/cacert.p12" - - if not ipautil.file_exists(cafile): - # CA not used on the server, return empty instances - return (None, None) - - try: - from ipaserver.install import cainstance - except ImportError: - print >> sys.stderr, "Import failed: %s" % sys.exc_value - sys.exit(1) - - if not cainstance.check_inst(): - print "A CA was specified but the dogtag certificate server" - print "is not installed on the system" - print "Please install dogtag and restart the setup program" - sys.exit(1) - - pkcs12_info = None - if ipautil.file_exists(config.dir + "/dogtagcert.p12"): - pkcs12_info = (config.dir + "/dogtagcert.p12", - config.dir + "/dirsrv_pin.txt") - cs = cainstance.CADSInstance() - cs.create_instance(config.realm_name, config.host_name, - config.domain_name, config.dirman_password, - pkcs12_info) - cs.load_pkcs12() - cs.enable_ssl() - cs.restart_instance() - ca = cainstance.CAInstance(config.realm_name, certs.NSS_DIR) - ca.configure_instance(config.host_name, config.dirman_password, - config.dirman_password, pkcs12_info=(cafile,), - master_host=config.master_host_name, - subject_base=config.subject_base) - - # The dogtag DS instance needs to be restarted after installation. - # The procedure for this is: stop dogtag, stop DS, start DS, start - # dogtag - # - # The service_name trickery is due to the service naming we do - # internally. In the case of the dogtag DS the name doesn't match the - # unix service. - - service_name = cs.service_name - service.print_msg("Restarting the directory and certificate servers") - cs.service_name = "dirsrv" - ca.stop() - cs.stop("PKI-IPA") - cs.start("PKI-IPA") - ca.start() - cs.service_name = service_name - - return (ca, cs) - def install_replica_ds(config): dsinstance.check_existing_installation() dsinstance.check_ports() @@ -392,7 +298,7 @@ def main(): sys.exit(0) try: - top_dir, dir = expand_info(filename, dirman_password) + top_dir, dir = expand_replica_info(filename, dirman_password) global REPLICA_INFO_TOP_DIR REPLICA_INFO_TOP_DIR = top_dir except Exception, e: @@ -401,9 +307,13 @@ def main(): sys.exit(1) config = ReplicaConfig() - read_info(dir, config) + read_replica_info(dir, config) config.dirman_password = dirman_password - host = get_host_name(options.no_host_dns) + try: + host = get_host_name(options.no_host_dns) + except RuntimeError, e: + logging.error(str(e)) + sys.exit(1) if config.host_name != host: try: print "This replica was created for '%s' but this machine is named '%s'" % (config.host_name, host) @@ -414,32 +324,12 @@ def main(): except KeyboardInterrupt: sys.exit(0) config.dir = dir + config.setup_ca = options.setup_ca # check connection if not options.skip_conncheck: - print "Run connection check to master" - args = ["/usr/sbin/ipa-replica-conncheck", "--master", config.master_host_name, - "--auto-master-check", "--realm", config.realm_name, - "--principal", "admin", - "--hostname", config.host_name] - - if options.admin_password: - args.extend(["--password", options.admin_password]) - - cafile = config.dir + "/cacert.p12" - if ipautil.file_exists(cafile): # with CA - args.append('--check-ca') - logging.debug("Running ipa-replica-conncheck with following arguments: %s" % - " ".join(args)) - (stdin, stderr, returncode) = ipautil.run(args,raiseonerr=False, capture_output=False) - - if returncode != 0: - sys.exit("Connection check failed!" + - "\nPlease fix your network settings according to error messages above." + - "\nIf the check results are not valid it can be skipped with --skip-conncheck parameter.") - else: - print "Connection check OK" + replica_conn_check(config.master_host_name, config.host_name, config.realm_name, options.setup_ca, options.admin_password) # Create the management framework config file # Note: We must do this before bootstraping and finalizing ipalib.api @@ -516,7 +406,7 @@ def main(): ntp.create_instance() # Configure the CA if necessary - (CA, cs) = install_ca(config) + (CA, cs) = cainstance.install_replica_ca(config) # Always try to install DNS records install_dns_records(config, options) @@ -525,7 +415,7 @@ def main(): ds = install_replica_ds(config) # We need to ldap_enable the CA now that DS is up and running - if CA: + if CA and config.setup_ca: CA.ldap_enable('CA', config.host_name, config.dirman_password, util.realm_to_suffix(config.realm_name)) cs.add_simple_service('dogtagldap/%s@%s' % (config.host_name, config.realm_name)) @@ -537,8 +427,9 @@ def main(): CA.import_ra_cert(dir + "/ra.p12") CA.fix_ra_perms() service.restart("httpd") - service.print_msg("Setting the certificate subject base") - CA.set_subject_in_config(util.realm_to_suffix(config.realm_name)) + if config.setup_ca: + service.print_msg("Setting the certificate subject base") + CA.set_subject_in_config(util.realm_to_suffix(config.realm_name)) # The DS instance is created before the keytab, add the SSL cert we # generated diff --git a/install/tools/man/Makefile.am b/install/tools/man/Makefile.am index be2524e86..63a598ac2 100644 --- a/install/tools/man/Makefile.am +++ b/install/tools/man/Makefile.am @@ -12,6 +12,7 @@ man1_MANS = \ ipa-server-certinstall.1 \ ipa-server-install.1 \ ipa-dns-install.1 \ + ipa-ca-install.1 \ ipa-ldap-updater.1 \ ipa-compat-manage.1 \ ipa-nis-manage.1 \ diff --git a/install/tools/man/ipa-ca-install.1 b/install/tools/man/ipa-ca-install.1 new file mode 100644 index 000000000..90ea84622 --- /dev/null +++ b/install/tools/man/ipa-ca-install.1 @@ -0,0 +1,49 @@ +.\" A man page for ipa-replica-install +.\" Copyright (C) 2011 Red Hat, Inc. +.\" +.\" This program is free software; you can redistribute it and/or modify +.\" it under the terms of the GNU General Public License as published by +.\" the Free Software Foundation, either version 3 of the License, or +.\" (at your option) any later version. +.\" +.\" This program is distributed in the hope that it will be useful, but +.\" WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +.\" General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public License +.\" along with this program. If not, see . +.\" +.\" Author: Rob Crittenden +.\" +.TH "ipa-ca-install" "1" "Jun 17 2011" "freeipa" "" +.SH "NAME" +ipa\-ca\-install \- Install a CA on a replica +.SH "SYNOPSIS" +ipa\-ca\-install [\fIOPTION\fR]... replica_file +.SH "DESCRIPTION" +Adds a CA as an IPA\-managed service. This requires that the IPA server is already installed and configured. + +The replica_file is created using the ipa\-replica\-prepare utility and should be the same one used when originally installing the replica. +.SH "OPTIONS" +\fB\-d\fR, \fB\-\-debug\fR +Enable debug logging when more verbose output is needed +.TP +\fB\-p\fR \fIDM_PASSWORD\fR, \fB\-\-password\fR=\fIDM_PASSWORD\fR +Directory Manager (existing master) password +.TP +\fB\-w\fR \fIADMIN_PASSWORD\fR, \fB\-\-admin\-password\fR=\fIADMIN_PASSWORD\fR +Admin user Kerberos password used for connection check +.TP +\fB\-\-no\-host\-dns\fR +Do not use DNS for hostname lookup during installation +.TP +\fB\-\-skip\-conncheck\fR +Skip connection check to remote master +.TP +\fB\-U\fR, \fB\-\-unattended\fR +An unattended installation that will never prompt for user input +.SH "EXIT STATUS" +0 if the command was successful + +1 if an error occurred diff --git a/install/tools/man/ipa-replica-install.1 b/install/tools/man/ipa-replica-install.1 index 888923546..1dac5faa1 100644 --- a/install/tools/man/ipa-replica-install.1 +++ b/install/tools/man/ipa-replica-install.1 @@ -33,12 +33,16 @@ Do not configure NTP \fB\-d\fR, \fB\-\-debug Enable debug logging when more verbose output is needed .TP -\fB\-p\fR, \fB\-\-password\fR=\fIDM_PASSWORD\fR +\fB\-p\fR \fIDM_PASSWORD\fR, \fB\-\-password\fR=\fIDM_PASSWORD\fR Directory Manager (existing master) password .TP \fB\-w\fR \fIADMIN_PASSWORD\fR, \fB\-\-admin\-password\fR=\fIADMIN_PASSWORD\fR Admin user Kerberos password used for connection check .TP +\fB\-\-setup\-ca\fR +Install and configure a CA on this replica. If a CA is not configured then +certificate operations will be forwarded to a master with a CA installed. +.TP \fB\-\-setup\-dns\fR Generate a DNS zone if it does not exist already and configure the DNS server. This option requires that you either specify at least one DNS forwarder through diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py index 928d01e47..4ace26db5 100644 --- a/ipaserver/install/cainstance.py +++ b/ipaserver/install/cainstance.py @@ -52,6 +52,7 @@ from ipaserver.install import service from ipaserver.install import installutils from ipaserver.install import dsinstance from ipaserver.install import certs +from ipaserver.install.installutils import ReplicaConfig from ipalib import util DEFAULT_DSPORT=7389 @@ -446,6 +447,7 @@ class CAInstance(service.Service): self.csr_file = None self.cert_file = None self.cert_chain_file = None + self.create_ra_agent_db = True # The same database is used for mod_nss because the NSS context # will already have been initialized by Apache by the time @@ -521,7 +523,8 @@ class CAInstance(service.Service): if self.external != 1: if not self.clone: self.step("creating CA agent PKCS#12 file in /root", self.__create_ca_agent_pkcs12) - self.step("creating RA agent certificate database", self.__create_ra_agent_db) + if self.create_ra_agent_db: + self.step("creating RA agent certificate database", self.__create_ra_agent_db) self.step("importing CA chain to RA certificate database", self.__import_ca_chain) if not self.clone: self.step("restarting certificate server", self.__restart_instance) @@ -1091,6 +1094,79 @@ class CAInstance(service.Service): fd.close() os.chmod(location, 0444) +def install_replica_ca(config, postinstall=False): + """ + Install a CA on a replica. + + There are two modes of doing this controlled: + - While the replica is being installed + - Post-replica installation + + config is a ReplicaConfig object + + Returns a tuple of the CA and CADS instances + """ + cafile = config.dir + "/cacert.p12" + + if not ipautil.file_exists(cafile): + # not a dogtag CA replica + sys.exit('Not a dogtag CA installation') + + if not config.setup_ca: + # We aren't configuring the CA in this step but we still need + # a minimum amount of information on the CA for this IPA install. + ca = CAInstance(config.realm_name, certs.NSS_DIR) + ca.dm_password = config.dirman_password + ca.subject_base = config.subject_base + return (ca, None) + + ca = CAInstance(config.realm_name, certs.NSS_DIR) + ca.dm_password = config.dirman_password + ca.subject_base = config.subject_base + if ca.is_installed(): + sys.exit("A CA is already configured on this system.") + + pkcs12_info = None + if ipautil.file_exists(config.dir + "/dogtagcert.p12"): + pkcs12_info = (config.dir + "/dogtagcert.p12", + config.dir + "/dirsrv_pin.txt") + cs = CADSInstance() + cs.create_instance(config.realm_name, config.host_name, + config.domain_name, config.dirman_password, + pkcs12_info) + cs.load_pkcs12() + cs.enable_ssl() + cs.restart_instance() + ca = CAInstance(config.realm_name, certs.NSS_DIR) + if postinstall: + # If installing this afterward the Apache NSS database already + # exists, don't remove it. + ca.create_ra_agent_db = False + ca.configure_instance(config.host_name, config.dirman_password, + config.dirman_password, pkcs12_info=(cafile,), + master_host=config.master_host_name, + subject_base=config.subject_base) + + # The dogtag DS instance needs to be restarted after installation. + # The procedure for this is: stop dogtag, stop DS, start DS, start + # dogtag + # + # + # The service_name trickery is due to the service naming we do + # internally. In the case of the dogtag DS the name doesn't match the + # unix service. + + service_name = cs.service_name + service.print_msg("Restarting the directory and certificate servers") + cs.service_name = "dirsrv" + ca.stop() + cs.stop("PKI-IPA") + cs.start("PKI-IPA") + ca.start() + cs.service_name = service_name + + return (ca, cs) + if __name__ == "__main__": installutils.standard_logging_setup("install.log", False) cs = CADSInstance() diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py index 07dda2cc0..ebe654dd3 100644 --- a/ipaserver/install/certs.py +++ b/ipaserver/install/certs.py @@ -446,6 +446,7 @@ class CertDB(object): return cert else: (cert, start) = find_cert_from_txt(cert, start=0) + cert = x509.strip_header(cert) dercert = base64.b64decode(cert) return dercert except ipautil.CalledProcessError: @@ -475,7 +476,8 @@ class CertDB(object): service.stop("certmonger") cert = self.get_cert_from_db(nickname) - subject = str(x509.get_subject(cert)) + nsscert = x509.load_certificate(cert, dbdir=self.secdir) + subject = str(nsscert.subject) m = re.match('New tracking request "(\d+)" added', stdout) if not m: logging.error('Didn\'t get new certmonger request, got %s' % stdout) diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py index f5a862599..68fce7e69 100644 --- a/ipaserver/install/installutils.py +++ b/ipaserver/install/installutils.py @@ -29,6 +29,8 @@ import struct import fcntl import netaddr import time +import tempfile +from ConfigParser import SafeConfigParser from ipapython import ipautil from ipapython import dnsclient @@ -36,6 +38,17 @@ from ipapython import dnsclient class HostnameLocalhost(Exception): pass +class ReplicaConfig: + def __init__(self): + self.realm_name = "" + self.domain_name = "" + self.master_host_name = "" + self.dirman_password = "" + self.host_name = "" + self.dir = "" + self.subject_base = "" + self.setup_ca = False + def get_fqdn(): fqdn = "" try: @@ -442,3 +455,47 @@ def resolve_host(host_name): return addrinfos[0][4][0] except: return None + +def get_host_name(no_host_dns): + """ + Get the current FQDN from the socket and verify that it is valid. + + no_host_dns is a boolean that determines whether we enforce that the + hostname is resolvable. + + Will raise a RuntimeError on error, returns hostname on success + """ + hostname = get_fqdn() + verify_fqdn(hostname, no_host_dns) + return hostname + +def expand_replica_info(filename, password): + """ + Decrypt and expand a replica installation file into a temporary + location. The caller is responsible to remove this directory. + """ + top_dir = tempfile.mkdtemp("ipa") + tarfile = top_dir+"/files.tar" + dir = top_dir + "/realm_info" + ipautil.decrypt_file(filename, tarfile, password, top_dir) + ipautil.run(["tar", "xf", tarfile, "-C", top_dir]) + os.remove(tarfile) + + return top_dir, dir + +def read_replica_info(dir, rconfig): + """ + Read the contents of a replica installation file. + + rconfig is a ReplicaConfig object + """ + filename = dir + "/realm_info" + fd = open(filename) + config = SafeConfigParser() + config.readfp(fd) + + rconfig.realm_name = config.get("realm", "realm_name") + rconfig.master_host_name = config.get("realm", "master_host_name") + rconfig.domain_name = config.get("realm", "domain_name") + rconfig.host_name = config.get("realm", "destination_host") + rconfig.subject_base = config.get("realm", "subject_base") diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py index e640873ba..fddb73747 100644 --- a/ipaserver/install/replication.py +++ b/ipaserver/install/replication.py @@ -20,6 +20,7 @@ import time, logging import os +import sys import ldap from ipaserver import ipaldap from ipaserver.install.service import restart @@ -27,6 +28,7 @@ import installutils from ldap import modlist from ipalib import util from ipalib import errors +from ipapython import ipautil DIRMAN_CN = "cn=directory manager" CACERT = "/etc/ipa/ca.crt" @@ -40,6 +42,37 @@ TIMEOUT = 120 IPA_REPLICA = 1 WINSYNC = 2 +def replica_conn_check(master_host, host_name, realm, check_ca, + admin_password=None): + """ + Check the ports used by the replica both locally and remotely to be sure + that replication will work. + + Does not return a value, will sys.exit() on failure. + """ + print "Run connection check to master" + args = ["/usr/sbin/ipa-replica-conncheck", "--master", master_host, + "--auto-master-check", "--realm", realm, + "--principal", "admin", + "--hostname", host_name] + + if admin_password: + args.extend(["--password", admin_password]) + + if check_ca: + args.append('--check-ca') + logging.debug("Running ipa-replica-conncheck with following arguments: %s" % + " ".join(args)) + (stdin, stderr, returncode) = ipautil.run(args,raiseonerr=False, capture_output=False) + + if returncode != 0: + sys.exit("Connection check failed!" + + "\nPlease fix your network settings according to error messages above." + + "\nIf the check results are not valid it can be skipped with --skip-conncheck parameter.") + else: + print "Connection check OK" + + def check_replication_plugin(): """ Confirm that the 389-ds replication is installed. -- cgit