Exemple #1
0
    def update_setup(self, request):
        fqdn = installutils.get_fqdn()
        pwfile = api.env.dot_ipa + os.sep + ".dmpw"
        if os.path.isfile(pwfile):
            with open(pwfile, "r") as fp:
                self.dm_password = fp.read().rstrip()
        else:
            pytest.skip("No directory manager password")
        self.updater = LDAPUpdate()
        self.ld = ipaldap.LDAPClient.from_hostname_secure(fqdn)
        self.ld.simple_bind(bind_dn=ipaldap.DIRMAN_DN,
                            bind_password=self.dm_password)
        self.testdir = os.path.abspath(os.path.dirname(__file__))
        if not os.path.isfile(os.path.join(self.testdir, "0_reset.update")):
            pytest.skip("Unable to find test update files")

        self.container_dn = DN(
            self.updater._template_str('cn=test, cn=accounts, $SUFFIX'))
        self.user_dn = DN(
            self.updater._template_str(
                'uid=tuser, cn=test, cn=accounts, $SUFFIX'))

        def fin():
            if self.ld:
                self.ld.unbind()

        request.addfinalizer(fin)
Exemple #2
0
    def setUp(self):
        fqdn = installutils.get_fqdn()
        pwfile = api.env.dot_ipa + os.sep + ".dmpw"
        if ipautil.file_exists(pwfile):
            fp = open(pwfile, "r")
            self.dm_password = fp.read().rstrip()
            fp.close()
        else:
            raise nose.SkipTest("No directory manager password")
        self.updater = LDAPUpdate(dm_password=self.dm_password,
                                  sub_dict={},
                                  live_run=True)
        self.ld = ipaldap.IPAdmin(fqdn)
        self.ld.do_simple_bind(bindpw=self.dm_password)
        if ipautil.file_exists("0_reset.update"):
            self.testdir = "./"
        elif ipautil.file_exists("tests/test_install/0_reset.update"):
            self.testdir = "./tests/test_install/"
        else:
            raise nose.SkipTest("Unable to find test update files")

        self.container_dn = DN(
            self.updater._template_str('cn=test, cn=accounts, $SUFFIX'))
        self.user_dn = DN(
            self.updater._template_str(
                'uid=tuser, cn=test, cn=accounts, $SUFFIX'))
Exemple #3
0
 def __populate_local_domain(self):
     # Initialize local domain info using kerberos only
     ld = TrustDomainInstance(self.local_flatname)
     ld.creds = credentials.Credentials()
     ld.creds.set_kerberos_state(credentials.MUST_USE_KERBEROS)
     ld.creds.guess(ld.parm)
     ld.creds.set_workstation(ld.hostname)
     ld.retrieve(installutils.get_fqdn())
     self.local_domain = ld
Exemple #4
0
 def __populate_local_domain(self):
     # Initialize local domain info using kerberos only
     ld = TrustDomainInstance(self.local_flatname)
     ld.creds = credentials.Credentials()
     ld.creds.set_kerberos_state(credentials.MUST_USE_KERBEROS)
     ld.creds.guess(ld.parm)
     ld.creds.set_workstation(ld.hostname)
     ld.retrieve(installutils.get_fqdn())
     self.local_domain = ld
Exemple #5
0
    def setUp(self):
        fqdn = installutils.get_fqdn()
        pwfile = api.env.dot_ipa + os.sep + ".dmpw"
        if ipautil.file_exists(pwfile):
            fp = open(pwfile, "r")
            self.dm_password = fp.read().rstrip()
            fp.close()
        else:
            raise nose.SkipTest("No directory manager password")
        self.updater = LDAPUpdate(dm_password=self.dm_password, sub_dict={})
        self.ld = ipaldap.IPAdmin(fqdn)
        self.ld.do_simple_bind(bindpw=self.dm_password)
        self.testdir = os.path.abspath(os.path.dirname(__file__))
        if not ipautil.file_exists(os.path.join(self.testdir,
                                                "0_reset.update")):
            raise nose.SkipTest("Unable to find test update files")

        self.container_dn = DN(self.updater._template_str('cn=test, cn=accounts, $SUFFIX'))
        self.user_dn = DN(self.updater._template_str('uid=tuser, cn=test, cn=accounts, $SUFFIX'))
Exemple #6
0
    def setUp(self):
        fqdn = installutils.get_fqdn()
        pwfile = api.env.dot_ipa + os.sep + ".dmpw"
        if os.path.isfile(pwfile):
            fp = open(pwfile, "r")
            self.dm_password = fp.read().rstrip()
            fp.close()
        else:
            raise unittest.SkipTest("No directory manager password")
        self.updater = LDAPUpdate(dm_password=self.dm_password, sub_dict={})
        self.ld = ipaldap.LDAPClient.from_hostname_secure(fqdn)
        self.ld.simple_bind(bind_dn=ipaldap.DIRMAN_DN,
                            bind_password=self.dm_password)
        self.testdir = os.path.abspath(os.path.dirname(__file__))
        if not os.path.isfile(os.path.join(self.testdir,
                                                "0_reset.update")):
            raise unittest.SkipTest("Unable to find test update files")

        self.container_dn = DN(self.updater._template_str('cn=test, cn=accounts, $SUFFIX'))
        self.user_dn = DN(self.updater._template_str('uid=tuser, cn=test, cn=accounts, $SUFFIX'))
Exemple #7
0
    def setUp(self):
        fqdn = installutils.get_fqdn()
        pwfile = api.env.dot_ipa + os.sep + ".dmpw"
        if os.path.isfile(pwfile):
            fp = open(pwfile, "r")
            self.dm_password = fp.read().rstrip()
            fp.close()
        else:
            raise unittest.SkipTest("No directory manager password")
        self.updater = LDAPUpdate(dm_password=self.dm_password, sub_dict={})
        self.ld = ipaldap.LDAPClient.from_hostname_secure(fqdn)
        self.ld.simple_bind(bind_dn=ipaldap.DIRMAN_DN,
                            bind_password=self.dm_password)
        self.testdir = os.path.abspath(os.path.dirname(__file__))
        if not os.path.isfile(os.path.join(self.testdir, "0_reset.update")):
            raise unittest.SkipTest("Unable to find test update files")

        self.container_dn = DN(
            self.updater._template_str('cn=test, cn=accounts, $SUFFIX'))
        self.user_dn = DN(
            self.updater._template_str(
                'uid=tuser, cn=test, cn=accounts, $SUFFIX'))
Exemple #8
0
def install(options):
    global dirsrv_pkcs12_info
    global http_pkcs12_info
    global pkinit_pkcs12_info
    global external_cert_file
    global external_ca_file
    global http_ca_cert

    realm_name = options.realm_name
    domain_name = options.domain_name
    dm_password = options.dm_password
    master_password = options.master_password
    admin_password = options.admin_password
    host_name = options.host_name
    ip_addresses = options.ip_address
    setup_ca = options.setup_ca
    setup_kra = options.setup_kra

    global ds
    global installation_cleanup

    # Installation has started. No IPA sysrestore items are restored in case of
    # failure to enable root cause investigation
    installation_cleanup = False

    # Configuration for ipalib, we will bootstrap and finalize later, after
    # we are sure we have the configuration file ready.
    cfg = dict(
        context='installer',
        in_server=True,
        debug=options.debug
    )

    # Figure out what external CA step we're in. See cainstance.py for more
    # info on the 3 states.
    if options.external_cert_files:
        external = 2
    elif options.external_ca:
        external = 1
    else:
        external = 0

    # Create the management framework config file and finalize api
    target_fname = paths.IPA_DEFAULT_CONF
    fd = open(target_fname, "w")
    fd.write("[global]\n")
    fd.write("host=%s\n" % host_name)
    fd.write("basedn=%s\n" % ipautil.realm_to_suffix(realm_name))
    fd.write("realm=%s\n" % realm_name)
    fd.write("domain=%s\n" % domain_name)
    fd.write("xmlrpc_uri=https://%s/ipa/xml\n" % format_netloc(host_name))
    fd.write("ldap_uri=ldapi://%%2fvar%%2frun%%2fslapd-%s.socket\n" %
             installutils.realm_to_serverid(realm_name))
    if setup_ca:
        fd.write("enable_ra=True\n")
        fd.write("ra_plugin=dogtag\n")
        fd.write("dogtag_version=%s\n" %
                 dogtag.install_constants.DOGTAG_VERSION)
    else:
        fd.write("enable_ra=False\n")
        fd.write("ra_plugin=none\n")
    fd.write("enable_kra=%s\n" % setup_kra)
    fd.write("mode=production\n")
    fd.close()

    # Must be readable for everyone
    os.chmod(target_fname, 0644)

    if not options.unattended:
        print ""
        print "The following operations may take some minutes to complete."
        print "Please wait until the prompt is returned."
        print ""

    system_hostname = get_fqdn()
    if host_name != system_hostname:
        root_logger.debug("Chosen hostname (%s) differs from system hostname "
                          "(%s) - change it" % (host_name, system_hostname))
        # configure /etc/sysconfig/network to contain the custom hostname
        tasks.backup_and_replace_hostname(fstore, sstore, host_name)
        # update `api.env.ca_host` to correct hostname
        # https://fedorahosted.org/freeipa/ticket/4936
        api.env.ca_host = host_name

    api.bootstrap(**cfg)
    if setup_ca:
        # ensure profile backend is available
        import ipaserver.plugins.dogtag
    api.finalize()

    # Create DS user/group if it doesn't exist yet
    dsinstance.create_ds_user()

    # Create a directory server instance
    if external != 2:
        # Configure ntpd
        if options.conf_ntp:
            ipaclient.ntpconf.force_ntpd(sstore)
            ntp = ntpinstance.NTPInstance(fstore)
            if not ntp.is_configured():
                ntp.create_instance()

        if options.dirsrv_cert_files:
            ds = dsinstance.DsInstance(fstore=fstore,
                                       domainlevel=options.domainlevel)
            ds.create_instance(realm_name, host_name, domain_name,
                               dm_password, dirsrv_pkcs12_info,
                               idstart=options.idstart, idmax=options.idmax,
                               subject_base=options.subject,
                               hbac_allow=not options.hbac_allow)
        else:
            ds = dsinstance.DsInstance(fstore=fstore,
                                       domainlevel=options.domainlevel)
            ds.create_instance(realm_name, host_name, domain_name,
                               dm_password,
                               idstart=options.idstart, idmax=options.idmax,
                               subject_base=options.subject,
                               hbac_allow=not options.hbac_allow)
    else:
        ds = dsinstance.DsInstance(fstore=fstore,
                                   domainlevel=options.domainlevel)
        ds.init_info(
            realm_name, host_name, domain_name, dm_password,
            options.subject, 1101, 1100, None)

    if setup_ca:
        ca = cainstance.CAInstance(realm_name, certs.NSS_DIR,
                                   dogtag_constants=dogtag.install_constants)
        if external == 0:
            ca.configure_instance(
                host_name, domain_name, dm_password, dm_password,
                subject_base=options.subject,
                ca_signing_algorithm=options.ca_signing_algorithm)
        elif external == 1:
            # stage 1 of external CA installation
            options.realm_name = realm_name
            options.domain_name = domain_name
            options.master_password = master_password
            options.dm_password = dm_password
            options.admin_password = admin_password
            options.host_name = host_name
            options.unattended = True
            options.forwarders = dns.dns_forwarders
            options.reverse_zones = dns.reverse_zones
            write_cache(vars(options))
            ca.configure_instance(
                host_name, domain_name, dm_password, dm_password,
                csr_file=paths.ROOT_IPA_CSR,
                subject_base=options.subject,
                ca_signing_algorithm=options.ca_signing_algorithm,
                ca_type=options.external_ca_type)
        else:
            # stage 2 of external CA installation
            ca.configure_instance(
                host_name, domain_name, dm_password, dm_password,
                cert_file=external_cert_file.name,
                cert_chain_file=external_ca_file.name,
                subject_base=options.subject,
                ca_signing_algorithm=options.ca_signing_algorithm)

        # Now put the CA cert where other instances exepct it
        ca.publish_ca_cert(CACERT)
    else:
        # Put the CA cert where other instances expect it
        x509.write_certificate(http_ca_cert, CACERT)
        os.chmod(CACERT, 0444)

    # we now need to enable ssl on the ds
    ds.enable_ssl()

    if setup_ca:
        # We need to ldap_enable the CA now that DS is up and running
        ca.ldap_enable('CA', host_name, dm_password,
                       ipautil.realm_to_suffix(realm_name),
                       ['caRenewalMaster'])

        # This is done within stopped_service context, which restarts CA
        ca.enable_client_auth_to_db(ca.dogtag_constants.CS_CFG_PATH)

    krb = krbinstance.KrbInstance(fstore)
    if options.pkinit_cert_files:
        krb.create_instance(realm_name, host_name, domain_name,
                            dm_password, master_password,
                            setup_pkinit=options.setup_pkinit,
                            pkcs12_info=pkinit_pkcs12_info,
                            subject_base=options.subject)
    else:
        krb.create_instance(realm_name, host_name, domain_name,
                            dm_password, master_password,
                            setup_pkinit=options.setup_pkinit,
                            subject_base=options.subject)

    # The DS instance is created before the keytab, add the SSL cert we
    # generated
    ds.add_cert_to_service()

    memcache = memcacheinstance.MemcacheInstance()
    memcache.create_instance('MEMCACHE', host_name, dm_password,
                             ipautil.realm_to_suffix(realm_name))

    otpd = otpdinstance.OtpdInstance()
    otpd.create_instance('OTPD', host_name, dm_password,
                         ipautil.realm_to_suffix(realm_name))

    # Create a HTTP instance
    http = httpinstance.HTTPInstance(fstore)
    if options.http_cert_files:
        http.create_instance(
            realm_name, host_name, domain_name, dm_password,
            pkcs12_info=http_pkcs12_info, subject_base=options.subject,
            auto_redirect=options.ui_redirect,
            ca_is_configured=setup_ca)
    else:
        http.create_instance(
            realm_name, host_name, domain_name, dm_password,
            subject_base=options.subject, auto_redirect=options.ui_redirect,
            ca_is_configured=setup_ca)
    tasks.restore_context(paths.CACHE_IPA_SESSIONS)

    # Export full CA chain
    ca_db = certs.CertDB(realm_name)
    os.chmod(CACERT, 0644)
    ca_db.publish_ca_cert(CACERT)

    set_subject_in_config(realm_name, dm_password,
                          ipautil.realm_to_suffix(realm_name), options.subject)

    # Apply any LDAP updates. Needs to be done after the configuration file
    # is created
    service.print_msg("Applying LDAP updates")
    ds.apply_updates()

    # Restart ds and krb after configurations have been changed
    service.print_msg("Restarting the directory server")
    ds.restart()

    service.print_msg("Restarting the KDC")
    krb.restart()

    if setup_ca:
        service.print_msg("Restarting the certificate server")
        ca.restart(dogtag.configured_constants().PKI_INSTANCE_NAME)

        service.print_msg("Importing certificate profiles")
        cainstance.import_included_profiles()

    if options.setup_dns:
        api.Backend.ldap2.connect(autobind=True)
        dns.install(False, False, options)
    else:
        # Create a BIND instance
        bind = bindinstance.BindInstance(fstore, dm_password)
        bind.setup(host_name, ip_addresses, realm_name,
                   domain_name, (), options.conf_ntp, (),
                   zonemgr=options.zonemgr, ca_configured=setup_ca,
                   no_dnssec_validation=options.no_dnssec_validation)
        bind.create_sample_bind_zone()

    # Restart httpd to pick up the new IPA configuration
    service.print_msg("Restarting the web server")
    http.restart()

    if setup_kra:
        kra.install(None, options, dm_password)

    # Set the admin user kerberos password
    ds.change_admin_password(admin_password)

    # Call client install script
    try:
        args = [paths.IPA_CLIENT_INSTALL, "--on-master", "--unattended",
                "--domain", domain_name, "--server", host_name,
                "--realm", realm_name, "--hostname", host_name]
        if not options.create_sshfp:
            args.append("--no-dns-sshfp")
        if options.trust_sshfp:
            args.append("--ssh-trust-dns")
        if not options.conf_ssh:
            args.append("--no-ssh")
        if not options.conf_sshd:
            args.append("--no-sshd")
        if options.mkhomedir:
            args.append("--mkhomedir")
        run(args)
    except Exception, e:
        sys.exit("Configuration of client side components failed!\n"
                 "ipa-client-install returned: " + str(e))
Exemple #9
0
    # check bind packages are installed
    if options.setup_dns:
        # Don't require an external DNS to say who we are if we are
        # setting up a local DNS server.
        options.no_host_dns = True

    # check the hostname is correctly configured, it must be as the kldap
    # utilities just use the hostname as returned by getaddrinfo to set
    # up some of the standard entries

    host_default = ""
    if options.host_name:
        host_default = options.host_name
    else:
        host_default = get_fqdn()

    try:
        if options.unattended or options.host_name:
            verify_fqdn(host_default, options.no_host_dns)
            host_name = host_default
        else:
            host_name = read_host_name(host_default, options.no_host_dns)
    except BadHostError, e:
        sys.exit(str(e) + "\n")

    host_name = host_name.lower()
    root_logger.debug("will use host_name: %s\n" % host_name)

    system_hostname = get_fqdn()
    if host_name != system_hostname:
Exemple #10
0
    def __init__(self, dm_password=None, sub_dict={},
                 online=True, ldapi=False):
        '''
        :parameters:
            dm_password
                Directory Manager password
            sub_dict
                substitution dictionary
            online
                Do an online LDAP update or use an experimental LDIF updater
            ldapi
                Bind using ldapi. This assumes autobind is enabled.

        Data Structure Example:
        -----------------------

        dn_by_rdn_count = {
            3: 'cn=config,dc=example,dc=com':
            4: 'cn=bob,ou=people,dc=example,dc=com',
        }

        all_updates = [
            {
                'dn': 'cn=config,dc=example,dc=com',
                'default': [
                    dict(attr='attr1', value='default1'),
                ],
                'updates': [
                    dict(action='action', attr='attr1', value='value1'),
                    dict(action='replace', attr='attr2', value=['old', 'new']),
                ]
            },
            {
                'dn': 'cn=bob,ou=people,dc=example,dc=com',
                'default': [
                    dict(attr='attr3', value='default3'),
                ],
                'updates': [
                    dict(action='action', attr='attr3', value='value3'),
                    dict(action='action', attr='attr4', value='value4'),
                }
            }
        ]

        Please notice the replace action requires two values in list

        The default and update lists are "dispositions"

        Plugins:

        Plugins has to be specified in update file to be executed, using
        'plugin' directive

        Example:
        plugin: update_uniqueness_plugins_to_new_syntax

        Each plugin returns two values:

        1. restart: dirsrv will be restarted AFTER this update is
                     applied.
        2. updates: A list of updates to be applied.

        The value of an update is a dictionary with the following possible
        values:
          - dn: DN, equal to the dn attribute
          - updates: list of updates against the dn
          - default: list of the default entry to be added if it doesn't
                     exist
          - deleteentry: list of dn's to be deleted (typically single dn)

        For example, this update file:

          dn: cn=global_policy,cn=$REALM,cn=kerberos,$SUFFIX
          replace:krbPwdLockoutDuration:10::600
          replace: krbPwdMaxFailure:3::6

        Generates this list which contain the update dictionary:

        [
          {
            'dn': 'cn=global_policy,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com',
            'updates': [
              dict(action='replace', attr='krbPwdLockoutDuration',
                   value=['10','600']),
              dict(action='replace', attr='krbPwdMaxFailure',
                   value=['3','6']),
            ]
          }
        ]

        Here is another example showing how a default entry is configured:

          dn: cn=Managed Entries,cn=etc,$SUFFIX
          default: objectClass: nsContainer
          default: objectClass: top
          default: cn: Managed Entries

        This generates:

        [
          {
            'dn': 'cn=Managed Entries,cn=etc,dc=example,dc=com',
            'default': [
              dict(attr='objectClass', value='nsContainer'),
              dict(attr='objectClass', value='top'),
              dict(attr='cn', value='Managed Entries'),
            ]
          }
        ]

        Note that the variable substitution in both examples has been completed.

        Either may make changes directly in LDAP or can return updates in
        update format.

        '''
        log_mgr.get_logger(self, True)
        self.sub_dict = sub_dict
        self.dm_password = dm_password
        self.conn = None
        self.modified = False
        self.online = online
        self.ldapi = ldapi
        self.pw_name = pwd.getpwuid(os.geteuid()).pw_name
        self.realm = None
        self.socket_name = (
            paths.SLAPD_INSTANCE_SOCKET_TEMPLATE %
            api.env.realm.replace('.', '-')
        )
        self.ldapuri = 'ldapi://%s' % ipautil.format_netloc(
            self.socket_name
        )
        suffix = None

        if sub_dict.get("REALM"):
            self.realm = sub_dict["REALM"]
        else:
            self.realm = api.env.realm
            suffix = ipautil.realm_to_suffix(self.realm) if self.realm else None

        if suffix is not None:
            assert isinstance(suffix, DN)
        domain = ipautil.get_domain_name()
        libarch = self._identify_arch()

        fqdn = installutils.get_fqdn()
        if fqdn is None:
            raise RuntimeError("Unable to determine hostname")

        if not self.sub_dict.get("REALM") and self.realm is not None:
            self.sub_dict["REALM"] = self.realm
        if not self.sub_dict.get("FQDN"):
            self.sub_dict["FQDN"] = fqdn
        if not self.sub_dict.get("DOMAIN"):
            self.sub_dict["DOMAIN"] = domain
        if not self.sub_dict.get("SUFFIX") and suffix is not None:
            self.sub_dict["SUFFIX"] = suffix
        if not self.sub_dict.get("ESCAPED_SUFFIX"):
            self.sub_dict["ESCAPED_SUFFIX"] = str(suffix)
        if not self.sub_dict.get("LIBARCH"):
            self.sub_dict["LIBARCH"] = libarch
        if not self.sub_dict.get("TIME"):
            self.sub_dict["TIME"] = int(time.time())
        if not self.sub_dict.get("DOMAIN") and domain is not None:
            self.sub_dict["DOMAIN"] = domain
        if not self.sub_dict.get("MIN_DOMAIN_LEVEL"):
            self.sub_dict["MIN_DOMAIN_LEVEL"] = str(constants.MIN_DOMAIN_LEVEL)
        if not self.sub_dict.get("MAX_DOMAIN_LEVEL"):
            self.sub_dict["MAX_DOMAIN_LEVEL"] = str(constants.MAX_DOMAIN_LEVEL)
        if not self.sub_dict.get("STRIP_ATTRS"):
            self.sub_dict["STRIP_ATTRS"] = "%s" % (
                " ".join(constants.REPL_AGMT_STRIP_ATTRS),)
        if not self.sub_dict.get("EXCLUDES"):
            self.sub_dict["EXCLUDES"] = "(objectclass=*) $ EXCLUDE %s" % (
                " ".join(constants.REPL_AGMT_EXCLUDES),)
        if not self.sub_dict.get("TOTAL_EXCLUDES"):
            self.sub_dict["TOTAL_EXCLUDES"] = "(objectclass=*) $ EXCLUDE " + \
                " ".join(constants.REPL_AGMT_TOTAL_EXCLUDES)
        self.api = create_api(mode=None)
        self.api.bootstrap(in_server=True, context='updates')
        self.api.finalize()
        if online:
            # Try out the connection/password
            # (This will raise if the server is not available)
            self.create_connection()
            self.close_connection()
        else:
            raise RuntimeError("Offline updates are not supported.")
Exemple #11
0
def update_schema(schema_files, ldapi=False, dm_password=None, live_run=True):
    """Update schema to match the given ldif files

    Schema elements present in the LDIF files but missing from the DS schema
    are added.
    Schema elements that differ between LDIF files and DS schema are updated
    to match the LDIF files. The comparison ignores tags that python-ldap's
    schema parser does not understand (such as X-ORIGIN).
    Extra elements present only in the DS schema are left untouched.

    An X-ORIGIN tag containing the current IPA version is added to all new
    and updated schema elements.

    :param schema_files: List of filenames to update from
    :param ldapi: if true, use ldapi to connect
    :param dm_password: directory manager password
    :live_run: if false, changes will not be applied

    :return:
        True if modifications were made
        (or *would be* made, for live_run=false)
    """
    conn = connect(ldapi=ldapi, dm_password=dm_password,
                   realm=krbV.default_context().default_realm,
                   fqdn=installutils.get_fqdn())

    old_schema = conn.schema

    schema_entry = conn.get_entry(DN(('cn', 'schema')),
                                  SCHEMA_ELEMENT_CLASSES.keys())

    modified = False

    # The exact representation the DS gives us for each OID
    # (for debug logging)
    old_entries_by_oid = {cls(str(attr)).oid: str(attr)
                          for attrname, cls in SCHEMA_ELEMENT_CLASSES.items()
                          for attr in schema_entry[attrname]}

    for filename in schema_files:
        log.info('Processing schema LDIF file %s', filename)
        dn, new_schema = ldap.schema.subentry.urlfetch(filename)

        for attrname, cls in SCHEMA_ELEMENT_CLASSES.items():

            # Set of all elements of this class, as strings given by the DS
            new_elements = []

            for oid in new_schema.listall(cls):
                new_obj = new_schema.get_obj(cls, oid)
                old_obj = old_schema.get_obj(cls, oid)
                # Compare python-ldap's sanitized string representations
                # to see if the value is different
                # This can give false positives, e.g. with case differences
                # in case-insensitive names.
                # But, false positives are harmless (and infrequent)
                if not old_obj or str(new_obj) != str(old_obj):
                    # Note: An add will automatically replace any existing
                    # schema with the same OID. So, we only add.
                    value = add_x_origin(new_obj)
                    new_elements.append(value)

                    if old_obj:
                        old_attr = old_entries_by_oid.get(oid)
                        log.info('Replace: %s', old_attr)
                        log.info('   with: %s', value)
                    else:
                        log.info('Add: %s', value)

            modified = modified or new_elements
            schema_entry[attrname].extend(new_elements)

    # FIXME: We should have a better way to display the modlist,
    # for now display raw output of our internal routine
    modlist = conn._generate_modlist(schema_entry.dn, schema_entry)
    log.debug("Complete schema modlist:\n%s", pprint.pformat(modlist))

    if modified and live_run:
        conn.update_entry(schema_entry)
    else:
        log.info('Not updating schema')

    return modified
Exemple #12
0
    def __init__(self,
                 dm_password=None,
                 sub_dict={},
                 online=True,
                 ldapi=False):
        '''
        :parameters:
            dm_password
                Directory Manager password
            sub_dict
                substitution dictionary
            online
                Do an online LDAP update or use an experimental LDIF updater
            ldapi
                Bind using ldapi. This assumes autobind is enabled.

        Data Structure Example:
        -----------------------

        dn_by_rdn_count = {
            3: 'cn=config,dc=example,dc=com':
            4: 'cn=bob,ou=people,dc=example,dc=com',
        }

        all_updates = [
            {
                'dn': 'cn=config,dc=example,dc=com',
                'default': [
                    dict(attr='attr1', value='default1'),
                ],
                'updates': [
                    dict(action='action', attr='attr1', value='value1'),
                    dict(action='replace', attr='attr2', value=['old', 'new']),
                ]
            },
            {
                'dn': 'cn=bob,ou=people,dc=example,dc=com',
                'default': [
                    dict(attr='attr3', value='default3'),
                ],
                'updates': [
                    dict(action='action', attr='attr3', value='value3'),
                    dict(action='action', attr='attr4', value='value4'),
                }
            }
        ]

        Please notice the replace action requires two values in list

        The default and update lists are "dispositions"

        Plugins:

        Plugins has to be specified in update file to be executed, using
        'plugin' directive

        Example:
        plugin: update_uniqueness_plugins_to_new_syntax

        Each plugin returns two values:

        1. restart: dirsrv will be restarted AFTER this update is
                     applied.
        2. updates: A list of updates to be applied.

        The value of an update is a dictionary with the following possible
        values:
          - dn: DN, equal to the dn attribute
          - updates: list of updates against the dn
          - default: list of the default entry to be added if it doesn't
                     exist
          - deleteentry: list of dn's to be deleted (typically single dn)

        For example, this update file:

          dn: cn=global_policy,cn=$REALM,cn=kerberos,$SUFFIX
          replace:krbPwdLockoutDuration:10::600
          replace: krbPwdMaxFailure:3::6

        Generates this list which contain the update dictionary:

        [
          {
            'dn': 'cn=global_policy,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com',
            'updates': [
              dict(action='replace', attr='krbPwdLockoutDuration',
                   value=['10','600']),
              dict(action='replace', attr='krbPwdMaxFailure',
                   value=['3','6']),
            ]
          }
        ]

        Here is another example showing how a default entry is configured:

          dn: cn=Managed Entries,cn=etc,$SUFFIX
          default: objectClass: nsContainer
          default: objectClass: top
          default: cn: Managed Entries

        This generates:

        [
          {
            'dn': 'cn=Managed Entries,cn=etc,dc=example,dc=com',
            'default': [
              dict(attr='objectClass', value='nsContainer'),
              dict(attr='objectClass', value='top'),
              dict(attr='cn', value='Managed Entries'),
            ]
          }
        ]

        Note that the variable substitution in both examples has been completed.

        Either may make changes directly in LDAP or can return updates in
        update format.

        '''
        self.sub_dict = sub_dict
        self.dm_password = dm_password
        self.conn = None
        self.modified = False
        self.online = online
        self.ldapi = ldapi
        self.pw_name = pwd.getpwuid(os.geteuid()).pw_name
        self.realm = None
        self.socket_name = (paths.SLAPD_INSTANCE_SOCKET_TEMPLATE %
                            api.env.realm.replace('.', '-'))
        suffix = None

        if sub_dict.get("REALM"):
            self.realm = sub_dict["REALM"]
        else:
            self.realm = api.env.realm
            suffix = ipautil.realm_to_suffix(
                self.realm) if self.realm else None

        self.ldapuri = installutils.realm_to_ldapi_uri(self.realm)
        if suffix is not None:
            assert isinstance(suffix, DN)

        fqdn = installutils.get_fqdn()
        if fqdn is None:
            raise RuntimeError("Unable to determine hostname")

        if not self.sub_dict.get("REALM") and self.realm is not None:
            self.sub_dict["REALM"] = self.realm
        if not self.sub_dict.get("FQDN"):
            self.sub_dict["FQDN"] = fqdn
        if not self.sub_dict.get("DOMAIN"):
            self.sub_dict["DOMAIN"] = api.env.domain
        if not self.sub_dict.get("SUFFIX") and suffix is not None:
            self.sub_dict["SUFFIX"] = suffix
        if not self.sub_dict.get("ESCAPED_SUFFIX"):
            self.sub_dict["ESCAPED_SUFFIX"] = str(suffix)
        if not self.sub_dict.get("LIBARCH"):
            self.sub_dict["LIBARCH"] = paths.LIBARCH
        if not self.sub_dict.get("TIME"):
            self.sub_dict["TIME"] = int(time.time())
        if not self.sub_dict.get("MIN_DOMAIN_LEVEL"):
            self.sub_dict["MIN_DOMAIN_LEVEL"] = str(constants.MIN_DOMAIN_LEVEL)
        if not self.sub_dict.get("MAX_DOMAIN_LEVEL"):
            self.sub_dict["MAX_DOMAIN_LEVEL"] = str(constants.MAX_DOMAIN_LEVEL)
        if not self.sub_dict.get("STRIP_ATTRS"):
            self.sub_dict["STRIP_ATTRS"] = "%s" % (" ".join(
                constants.REPL_AGMT_STRIP_ATTRS), )
        if not self.sub_dict.get("EXCLUDES"):
            self.sub_dict["EXCLUDES"] = "(objectclass=*) $ EXCLUDE %s" % (
                " ".join(constants.REPL_AGMT_EXCLUDES), )
        if not self.sub_dict.get("TOTAL_EXCLUDES"):
            self.sub_dict["TOTAL_EXCLUDES"] = "(objectclass=*) $ EXCLUDE " + \
                " ".join(constants.REPL_AGMT_TOTAL_EXCLUDES)
        self.api = create_api(mode=None)
        self.api.bootstrap(in_server=True,
                           context='updates',
                           confdir=paths.ETC_IPA,
                           ldap_uri=self.ldapuri)
        self.api.finalize()
        if online:
            # Try out the connection/password
            # (This will raise if the server is not available)
            self.create_connection()
            self.close_connection()
        else:
            raise RuntimeError("Offline updates are not supported.")
Exemple #13
0
    def __init__(self,
                 dm_password,
                 sub_dict={},
                 live_run=True,
                 online=True,
                 ldapi=False,
                 plugins=False):
        '''
        :parameters:
            dm_password
                Directory Manager password
            sub_dict
                substitution dictionary
            live_run
                Apply the changes or just test
            online
                Do an online LDAP update or use an experimental LDIF updater
            ldapi
                Bind using ldapi. This assumes autobind is enabled.
            plugins
                execute the pre/post update plugins

        Data Structure Example:
        -----------------------

        dn_by_rdn_count = {
            3: 'cn=config,dc=example,dc=com':
            4: 'cn=bob,ou=people,dc=example,dc=com',
        }

        all_updates = {
        'dn': 'cn=config,dc=example,dc=com':
            {
                'dn': 'cn=config,dc=example,dc=com',
                'default': ['attr1':default1'],
                'updates': ['action:attr1:value1',
                            'action:attr2:value2]
            },
        'dn': 'cn=bob,ou=people,dc=example,dc=com':
            {
                'dn': 'cn=bob,ou=people,dc=example,dc=com',
                'default': ['attr3':default3'],
                'updates': ['action:attr3:value3',
                            'action:attr4:value4],
            }
        }

        The default and update lists are "dispositions"


        '''
        log_mgr.get_logger(self, True)
        self.sub_dict = sub_dict
        self.live_run = live_run
        self.dm_password = dm_password
        self.conn = None
        self.modified = False
        self.online = online
        self.ldapi = ldapi
        self.plugins = plugins
        self.pw_name = pwd.getpwuid(os.geteuid()).pw_name
        self.realm = None
        suffix = None

        if sub_dict.get("REALM"):
            self.realm = sub_dict["REALM"]
        else:
            krbctx = krbV.default_context()
            try:
                self.realm = krbctx.default_realm
                suffix = ipautil.realm_to_suffix(self.realm)
            except krbV.Krb5Error:
                self.realm = None
                suffix = None

        if suffix is not None:
            assert isinstance(suffix, DN)
        domain = ipautil.get_domain_name()
        libarch = self._identify_arch()

        fqdn = installutils.get_fqdn()
        if fqdn is None:
            raise RuntimeError("Unable to determine hostname")
        fqhn = fqdn  # Save this for the sub_dict variable
        if self.ldapi:
            fqdn = "ldapi://%%2fvar%%2frun%%2fslapd-%s.socket" % "-".join(
                self.realm.split("."))

        if not self.sub_dict.get("REALM") and self.realm is not None:
            self.sub_dict["REALM"] = self.realm
        if not self.sub_dict.get("FQDN"):
            self.sub_dict["FQDN"] = fqhn
        if not self.sub_dict.get("DOMAIN"):
            self.sub_dict["DOMAIN"] = domain
        if not self.sub_dict.get("SUFFIX") and suffix is not None:
            self.sub_dict["SUFFIX"] = suffix
        if not self.sub_dict.get("ESCAPED_SUFFIX"):
            self.sub_dict["ESCAPED_SUFFIX"] = str(suffix)
        if not self.sub_dict.get("LIBARCH"):
            self.sub_dict["LIBARCH"] = libarch
        if not self.sub_dict.get("TIME"):
            self.sub_dict["TIME"] = int(time.time())
        if not self.sub_dict.get("DOMAIN") and domain is not None:
            self.sub_dict["DOMAIN"] = domain

        if online:
            # Try out the connection/password
            try:
                conn = ipaldap.IPAdmin(fqdn,
                                       ldapi=self.ldapi,
                                       realm=self.realm)
                if self.dm_password:
                    conn.do_simple_bind(binddn=DN(('cn', 'directory manager')),
                                        bindpw=self.dm_password)
                elif os.getegid() == 0:
                    try:
                        # autobind
                        conn.do_external_bind(self.pw_name)
                    except errors.NotFound:
                        # Fall back
                        conn.do_sasl_gssapi_bind()
                else:
                    conn.do_sasl_gssapi_bind()
                conn.unbind()
            except (ldap.CONNECT_ERROR, ldap.SERVER_DOWN):
                raise RuntimeError("Unable to connect to LDAP server %s" %
                                   fqdn)
            except ldap.INVALID_CREDENTIALS:
                raise RuntimeError(
                    "The password provided is incorrect for LDAP server %s" %
                    fqdn)
            except ldap.LOCAL_ERROR, e:
                raise RuntimeError('%s' % e.args[0].get('info', '').strip())
Exemple #14
0
def update_schema(schema_files, ldapi=False, dm_password=None,):
    """Update schema to match the given ldif files

    Schema elements present in the LDIF files but missing from the DS schema
    are added.
    Schema elements that differ between LDIF files and DS schema are updated
    to match the LDIF files. The comparison ignores tags that python-ldap's
    schema parser does not understand (such as X-ORIGIN).
    Extra elements present only in the DS schema are left untouched.

    An X-ORIGIN tag containing the current IPA version is added to all new
    and updated schema elements.

    :param schema_files: List of filenames to update from
    :param ldapi: if true, use ldapi to connect
    :param dm_password: directory manager password

    :return:
        True if modifications were made
    """
    SCHEMA_ELEMENT_CLASSES_KEYS = [x[0] for x in SCHEMA_ELEMENT_CLASSES]

    conn = connect(ldapi=ldapi, dm_password=dm_password,
                   realm=api.env.realm,
                   fqdn=installutils.get_fqdn())

    old_schema = conn.schema


    schema_entry = conn.get_entry(DN(('cn', 'schema')),
                                  SCHEMA_ELEMENT_CLASSES_KEYS)

    modified = False

    # The exact representation the DS gives us for each OID
    # (for debug logging)
    old_entries_by_oid = {cls(str(attr)).oid: str(attr)
                          for (attrname, cls) in SCHEMA_ELEMENT_CLASSES
                          for attr in schema_entry[attrname]}

    for filename in schema_files:
        log.debug('Processing schema LDIF file %s', filename)
        dn, new_schema = ldap.schema.subentry.urlfetch(filename)

        for attrname, cls in SCHEMA_ELEMENT_CLASSES:
            for oids_set in _get_oid_dependency_order(new_schema, cls):
                # Set of all elements of this class, as strings given by the DS
                new_elements = []
                for oid in oids_set:
                    new_obj = new_schema.get_obj(cls, oid)
                    old_obj = old_schema.get_obj(cls, oid)
                    # Compare python-ldap's sanitized string representations
                    # to see if the value is different
                    # This can give false positives, e.g. with case differences
                    # in case-insensitive names.
                    # But, false positives are harmless (and infrequent)
                    if not old_obj or str(new_obj) != str(old_obj):
                        # Note: An add will automatically replace any existing
                        # schema with the same OID. So, we only add.
                        value = add_x_origin(new_obj)
                        new_elements.append(value)

                        if old_obj:
                            old_attr = old_entries_by_oid.get(oid)
                            log.debug('Replace: %s', old_attr)
                            log.debug('   with: %s', value)
                        else:
                            log.debug('Add: %s', value)

                modified = modified or new_elements
                schema_entry[attrname].extend(new_elements)
                # we need to iterate schema updates, due to dependencies (SUP)
                # schema_entry doesn't respect order of objectclasses/attributes
                # so updates must be executed with groups of independent OIDs
                if new_elements:
                    modlist = schema_entry.generate_modlist()
                    log.debug("Schema modlist:\n%s", pprint.pformat(modlist))
                    conn.update_entry(schema_entry)

    if not modified:
        log.debug('Not updating schema')

    return modified
Exemple #15
0
def install_check(installer):
    options = installer
    dirsrv_pkcs12_file = installer._dirsrv_pkcs12_file
    http_pkcs12_file = installer._http_pkcs12_file
    pkinit_pkcs12_file = installer._pkinit_pkcs12_file
    dirsrv_pkcs12_info = installer._dirsrv_pkcs12_info
    http_pkcs12_info = installer._http_pkcs12_info
    pkinit_pkcs12_info = installer._pkinit_pkcs12_info
    external_cert_file = installer._external_cert_file
    external_ca_file = installer._external_ca_file
    http_ca_cert = installer._ca_cert

    if tasks.is_fips_enabled():
        raise RuntimeError(
            "Installing IPA server in FIPS mode is not supported")

    tasks.check_selinux_status()

    if options.master_password:
        msg = ("WARNING:\noption '-P/--master-password' is deprecated. "
               "KDC master password of sufficient strength is autogenerated "
               "during IPA server installation and should not be set "
               "manually.")
        print(textwrap.fill(msg, width=79, replace_whitespace=False))

    installer._installation_cleanup = True

    print("\nThe log file for this installation can be found in "
          "/var/log/ipaserver-install.log")
    if (not options.external_ca and not options.external_cert_files and
            is_ipa_configured()):
        installer._installation_cleanup = False
        raise ScriptError(
            "IPA server is already configured on this system.\n"
            "If you want to reinstall the IPA server, please uninstall "
            "it first using 'ipa-server-install --uninstall'.")

    client_fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE)
    if client_fstore.has_files():
        installer._installation_cleanup = False
        raise ScriptError(
            "IPA client is already configured on this system.\n"
            "Please uninstall it before configuring the IPA server, "
            "using 'ipa-client-install --uninstall'")

    fstore = sysrestore.FileStore(SYSRESTORE_DIR_PATH)
    sstore = sysrestore.StateFile(SYSRESTORE_DIR_PATH)

    # This will override any settings passed in on the cmdline
    if ipautil.file_exists(paths.ROOT_IPA_CACHE):
        if options.dm_password is not None:
            dm_password = options.dm_password
        else:
            dm_password = read_password("Directory Manager", confirm=False)
        if dm_password is None:
            raise ScriptError("Directory Manager password required")
        try:
            cache_vars = read_cache(dm_password)
            options.__dict__.update(cache_vars)
            if cache_vars.get('external_ca', False):
                options.external_ca = False
                options.interactive = False
        except Exception as e:
            raise ScriptError("Cannot process the cache file: %s" % str(e))

    # We only set up the CA if the PKCS#12 options are not given.
    if options.dirsrv_cert_files:
        setup_ca = False
    else:
        setup_ca = True
    options.setup_ca = setup_ca

    # first instance of KRA must be installed by ipa-kra-install
    options.setup_kra = False

    print("======================================="
          "=======================================")
    print("This program will set up the FreeIPA Server.")
    print("")
    print("This includes:")
    if setup_ca:
        print("  * Configure a stand-alone CA (dogtag) for certificate "
              "management")
    if not options.no_ntp:
        print("  * Configure the Network Time Daemon (ntpd)")
    print("  * Create and configure an instance of Directory Server")
    print("  * Create and configure a Kerberos Key Distribution Center (KDC)")
    print("  * Configure Apache (httpd)")
    if options.setup_dns:
        print("  * Configure DNS (bind)")
    if not options.no_pkinit:
        print("  * Configure the KDC to enable PKINIT")
    if options.no_ntp:
        print("")
        print("Excluded by options:")
        print("  * Configure the Network Time Daemon (ntpd)")
    if installer.interactive:
        print("")
        print("To accept the default shown in brackets, press the Enter key.")
    print("")

    if not options.external_cert_files:
        # Make sure the 389-ds ports are available
        check_dirsrv(not installer.interactive)

    if not options.no_ntp:
        try:
            ipaclient.install.ntpconf.check_timedate_services()
        except ipaclient.install.ntpconf.NTPConflictingService as e:
            print(("WARNING: conflicting time&date synchronization service '%s'"
                  " will be disabled" % e.conflicting_service))
            print("in favor of ntpd")
            print("")
        except ipaclient.install.ntpconf.NTPConfigurationError:
            pass

    # Check to see if httpd is already configured to listen on 443
    if httpinstance.httpd_443_configured():
        raise ScriptError("Aborting installation")

    if not options.setup_dns and installer.interactive:
        if ipautil.user_input("Do you want to configure integrated DNS "
                              "(BIND)?", False):
            options.setup_dns = True
        print("")

    # check bind packages are installed
    if options.setup_dns:
        # Don't require an external DNS to say who we are if we are
        # setting up a local DNS server.
        options.no_host_dns = True

    # check the hostname is correctly configured, it must be as the kldap
    # utilities just use the hostname as returned by getaddrinfo to set
    # up some of the standard entries

    if options.host_name:
        host_default = options.host_name
    else:
        host_default = get_fqdn()

    try:
        if not installer.interactive or options.host_name:
            verify_fqdn(host_default, options.no_host_dns)
            host_name = host_default
        else:
            host_name = read_host_name(host_default, options.no_host_dns)
    except BadHostError as e:
        raise ScriptError(e)

    host_name = host_name.lower()
    root_logger.debug("will use host_name: %s\n" % host_name)

    if not options.domain_name:
        domain_name = read_domain_name(host_name[host_name.find(".")+1:],
                                       not installer.interactive)
        root_logger.debug("read domain_name: %s\n" % domain_name)
        try:
            validate_domain_name(domain_name)
        except ValueError as e:
            raise ScriptError("Invalid domain name: %s" % unicode(e))
    else:
        domain_name = options.domain_name

    domain_name = domain_name.lower()

    if not options.realm_name:
        realm_name = read_realm_name(domain_name, not installer.interactive)
        root_logger.debug("read realm_name: %s\n" % realm_name)
    else:
        realm_name = options.realm_name.upper()

    if not options.subject:
        options.subject = DN(('O', realm_name))

    if options.http_cert_files:
        if options.http_pin is None:
            options.http_pin = installutils.read_password(
                "Enter Apache Server private key unlock",
                confirm=False, validate=False, retry=False)
            if options.http_pin is None:
                raise ScriptError(
                    "Apache Server private key unlock password required")
        http_pkcs12_file, http_pin, http_ca_cert = load_pkcs12(
            cert_files=options.http_cert_files,
            key_password=options.http_pin,
            key_nickname=options.http_cert_name,
            ca_cert_files=options.ca_cert_files,
            host_name=host_name)
        http_pkcs12_info = (http_pkcs12_file.name, http_pin)

    if options.dirsrv_cert_files:
        if options.dirsrv_pin is None:
            options.dirsrv_pin = read_password(
                "Enter Directory Server private key unlock",
                confirm=False, validate=False, retry=False)
            if options.dirsrv_pin is None:
                raise ScriptError(
                    "Directory Server private key unlock password required")
        dirsrv_pkcs12_file, dirsrv_pin, dirsrv_ca_cert = load_pkcs12(
            cert_files=options.dirsrv_cert_files,
            key_password=options.dirsrv_pin,
            key_nickname=options.dirsrv_cert_name,
            ca_cert_files=options.ca_cert_files,
            host_name=host_name)
        dirsrv_pkcs12_info = (dirsrv_pkcs12_file.name, dirsrv_pin)

    if options.pkinit_cert_files:
        if not options.no_pkinit:
            raise ScriptError("Cannot create KDC PKINIT certificate and use "
                              "provided external PKINIT certificate at the "
                              "same time. Please choose one of them.")

        if options.pkinit_pin is None:
            options.pkinit_pin = read_password(
                "Enter Kerberos KDC private key unlock",
                confirm=False, validate=False, retry=False)
            if options.pkinit_pin is None:
                raise ScriptError(
                    "Kerberos KDC private key unlock password required")
        pkinit_pkcs12_file, pkinit_pin, _pkinit_ca_cert = load_pkcs12(
            cert_files=options.pkinit_cert_files,
            key_password=options.pkinit_pin,
            key_nickname=options.pkinit_cert_name,
            ca_cert_files=options.ca_cert_files,
            host_name=host_name)
        pkinit_pkcs12_info = (pkinit_pkcs12_file.name, pkinit_pin)

    if (options.http_cert_files and options.dirsrv_cert_files and
            http_ca_cert != dirsrv_ca_cert):
        raise ScriptError(
            "Apache Server SSL certificate and Directory Server SSL "
            "certificate are not signed by the same CA certificate")

    if not options.dm_password:
        dm_password = read_dm_password()

        if dm_password is None:
            raise ScriptError("Directory Manager password required")
    else:
        dm_password = options.dm_password

    if not options.master_password:
        master_password = ipa_generate_password()
    else:
        master_password = options.master_password

    if not options.admin_password:
        admin_password = read_admin_password()
        if admin_password is None:
            raise ScriptError("IPA admin password required")
    else:
        admin_password = options.admin_password

    # Configuration for ipalib, we will bootstrap and finalize later, after
    # we are sure we have the configuration file ready.
    cfg = dict(
        context='installer',
        confdir=paths.ETC_IPA,
        in_server=True,
        # make sure host name specified by user is used instead of default
        host=host_name,
    )
    if setup_ca:
        # we have an IPA-integrated CA
        cfg['ca_host'] = host_name

    # Create the management framework config file and finalize api
    target_fname = paths.IPA_DEFAULT_CONF
    fd = open(target_fname, "w")
    fd.write("[global]\n")
    fd.write("host=%s\n" % host_name)
    fd.write("basedn=%s\n" % ipautil.realm_to_suffix(realm_name))
    fd.write("realm=%s\n" % realm_name)
    fd.write("domain=%s\n" % domain_name)
    fd.write("xmlrpc_uri=https://%s/ipa/xml\n" % format_netloc(host_name))
    fd.write("ldap_uri=ldapi://%%2fvar%%2frun%%2fslapd-%s.socket\n" %
             installutils.realm_to_serverid(realm_name))
    if setup_ca:
        fd.write("enable_ra=True\n")
        fd.write("ra_plugin=dogtag\n")
        fd.write("dogtag_version=10\n")
    else:
        fd.write("enable_ra=False\n")
        fd.write("ra_plugin=none\n")
    fd.write("mode=production\n")
    fd.close()

    # Must be readable for everyone
    os.chmod(target_fname, 0o644)

    api.bootstrap(**cfg)
    api.finalize()

    if setup_ca:
        ca.install_check(False, None, options)
        kra.install_check(api, None, options)

    if options.setup_dns:
        dns.install_check(False, api, False, options, host_name)
        ip_addresses = dns.ip_addresses
    else:
        ip_addresses = get_server_ip_address(host_name,
                                             not installer.interactive, False,
                                             options.ip_addresses)

        # check addresses here, dns module is doing own check
        network_ip_address_warning(ip_addresses)
        broadcast_ip_address_warning(ip_addresses)

    # installer needs to update hosts file when DNS subsystem will be
    # installed or custom addresses are used
    if options.ip_addresses or options.setup_dns:
        installer._update_hosts_file = True

    print()
    print("The IPA Master Server will be configured with:")
    print("Hostname:       %s" % host_name)
    print("IP address(es): %s" % ", ".join(str(ip) for ip in ip_addresses))
    print("Domain name:    %s" % domain_name)
    print("Realm name:     %s" % realm_name)
    print()

    if options.setup_dns:
        print("BIND DNS server will be configured to serve IPA domain with:")
        print("Forwarders:       %s" % (
            "No forwarders" if not options.forwarders
            else ", ".join([str(ip) for ip in options.forwarders])
        ))
        print('Forward policy:   %s' % options.forward_policy)
        print("Reverse zone(s):  %s" % (
            "No reverse zone" if options.no_reverse or not dns.reverse_zones
            else ", ".join(str(rz) for rz in dns.reverse_zones)
        ))
        print()

    # If domain name and realm does not match, IPA server will not be able
    # to estabilish trust with Active Directory. Print big fat warning.

    realm_not_matching_domain = (domain_name.upper() != realm_name)

    if realm_not_matching_domain:
        print("WARNING: Realm name does not match the domain name.\n"
              "You will not be able to estabilish trusts with Active "
              "Directory unless\nthe realm name of the IPA server matches "
              "its domain name.\n\n")

    if installer.interactive and not user_input(
            "Continue to configure the system with these values?", False):
        raise ScriptError("Installation aborted")

    options.realm_name = realm_name
    options.domain_name = domain_name
    options.dm_password = dm_password
    options.master_password = master_password
    options.admin_password = admin_password
    options._host_name_overridden = bool(options.host_name)
    options.host_name = host_name
    options.ip_addresses = ip_addresses

    installer._fstore = fstore
    installer._sstore = sstore
    installer._dirsrv_pkcs12_file = dirsrv_pkcs12_file
    installer._http_pkcs12_file = http_pkcs12_file
    installer._pkinit_pkcs12_file = pkinit_pkcs12_file
    installer._dirsrv_pkcs12_info = dirsrv_pkcs12_info
    installer._http_pkcs12_info = http_pkcs12_info
    installer._pkinit_pkcs12_info = pkinit_pkcs12_info
    installer._external_cert_file = external_cert_file
    installer._external_ca_file = external_ca_file
    installer._ca_cert = http_ca_cert
Exemple #16
0
    def __init__(self, dm_password, sub_dict={}, live_run=True,
                 online=True, ldapi=False, plugins=False):
        '''
        :parameters:
            dm_password
                Directory Manager password
            sub_dict
                substitution dictionary
            live_run
                Apply the changes or just test
            online
                Do an online LDAP update or use an experimental LDIF updater
            ldapi
                Bind using ldapi. This assumes autobind is enabled.
            plugins
                execute the pre/post update plugins

        Data Structure Example:
        -----------------------

        dn_by_rdn_count = {
            3: 'cn=config,dc=example,dc=com':
            4: 'cn=bob,ou=people,dc=example,dc=com',
        }

        all_updates = {
        'dn': 'cn=config,dc=example,dc=com':
            {
                'dn': 'cn=config,dc=example,dc=com',
                'default': ['attr1':default1'],
                'updates': ['action:attr1:value1',
                            'action:attr2:value2]
            },
        'dn': 'cn=bob,ou=people,dc=example,dc=com':
            {
                'dn': 'cn=bob,ou=people,dc=example,dc=com',
                'default': ['attr3':default3'],
                'updates': ['action:attr3:value3',
                            'action:attr4:value4],
            }
        }

        The default and update lists are "dispositions"


        '''
        log_mgr.get_logger(self, True)
        self.sub_dict = sub_dict
        self.live_run = live_run
        self.dm_password = dm_password
        self.conn = None
        self.modified = False
        self.online = online
        self.ldapi = ldapi
        self.plugins = plugins
        self.pw_name = pwd.getpwuid(os.geteuid()).pw_name
        self.realm = None
        suffix = None

        if sub_dict.get("REALM"):
            self.realm = sub_dict["REALM"]
        else:
            krbctx = krbV.default_context()
            try:
                self.realm = krbctx.default_realm
                suffix = ipautil.realm_to_suffix(self.realm)
            except krbV.Krb5Error:
                self.realm = None
                suffix = None

        if suffix is not None:
            assert isinstance(suffix, DN)
        domain = ipautil.get_domain_name()
        libarch = self._identify_arch()

        fqdn = installutils.get_fqdn()
        if fqdn is None:
            raise RuntimeError("Unable to determine hostname")
        fqhn = fqdn # Save this for the sub_dict variable
        if self.ldapi:
            fqdn = "ldapi://%%2fvar%%2frun%%2fslapd-%s.socket" % "-".join(
                self.realm.split(".")
            )

        if not self.sub_dict.get("REALM") and self.realm is not None:
            self.sub_dict["REALM"] = self.realm
        if not self.sub_dict.get("FQDN"):
            self.sub_dict["FQDN"] = fqhn
        if not self.sub_dict.get("DOMAIN"):
            self.sub_dict["DOMAIN"] = domain
        if not self.sub_dict.get("SUFFIX") and suffix is not None:
            self.sub_dict["SUFFIX"] = suffix
        if not self.sub_dict.get("ESCAPED_SUFFIX"):
            self.sub_dict["ESCAPED_SUFFIX"] = str(suffix)
        if not self.sub_dict.get("LIBARCH"):
            self.sub_dict["LIBARCH"] = libarch
        if not self.sub_dict.get("TIME"):
            self.sub_dict["TIME"] = int(time.time())
        if not self.sub_dict.get("DOMAIN") and domain is not None:
            self.sub_dict["DOMAIN"] = domain

        if online:
            # Try out the connection/password
            # (This will raise if the server is not available)
            self.create_connection()
            self.conn.unbind()
            self.conn = None
        else:
            raise RuntimeError("Offline updates are not supported.")
Exemple #17
0
class join(Command):
    """Join an IPA domain"""

    takes_args = (
        Str(
            'cn',
            validate_host,
            cli_name='hostname',
            doc=_("The hostname to register as"),
            default_from=lambda: unicode(installutils.get_fqdn()),
            autofill=True,
            #normalizer=lamda value: value.lower(),
        ), )
    takes_options = (
        Str(
            'realm',
            doc=_("The IPA realm"),
            default_from=lambda: get_realm(),
            autofill=True,
        ),
        Str(
            'nshardwareplatform?',
            cli_name='platform',
            doc=_('Hardware platform of the host (e.g. Lenovo T61)'),
        ),
        Str(
            'nsosversion?',
            cli_name='os',
            doc=_('Operating System and version of the host (e.g. Fedora 9)'),
        ),
    )

    has_output = tuple()
    use_output_validation = False

    def execute(self, hostname, **kw):
        """
        Execute the machine join operation.

        Returns the entry as it will be created in LDAP.

        :param hostname: The name of the host joined
        :param kw: Keyword arguments for the other attributes.
        """
        assert 'cn' not in kw
        ldap = self.api.Backend.ldap2

        host = None
        try:
            # First see if the host exists
            kw = {'fqdn': hostname, 'all': True}
            attrs_list = api.Command['host_show'](**kw)['result']
            dn = attrs_list['dn']

            # If no principal name is set yet we need to try to add
            # one.
            if 'krbprincipalname' not in attrs_list:
                service = "host/%s@%s" % (hostname, api.env.realm)
                api.Command['host_mod'](hostname, krbprincipalname=service)

            # It exists, can we write the password attributes?
            allowed = ldap.can_write(dn, 'krblastpwdchange')
            if not allowed:
                raise errors.ACIError(info=_(
                    "Insufficient 'write' privilege to the 'krbLastPwdChange' attribute of entry '%s'."
                ) % dn)

            kw = {'fqdn': hostname, 'all': True}
            attrs_list = api.Command['host_show'](**kw)['result']
            dn = attrs_list['dn']
        except errors.NotFound:
            attrs_list = api.Command['host_add'](hostname,
                                                 force=True)['result']
            dn = attrs_list['dn']

        config = api.Command['config_show']()['result']
        attrs_list['ipacertificatesubjectbase'] = config[
            'ipacertificatesubjectbase']

        return (dn, attrs_list)
Exemple #18
0
def install_check(installer):
    options = installer
    dirsrv_pkcs12_file = installer._dirsrv_pkcs12_file
    http_pkcs12_file = installer._http_pkcs12_file
    pkinit_pkcs12_file = installer._pkinit_pkcs12_file
    dirsrv_pkcs12_info = installer._dirsrv_pkcs12_info
    http_pkcs12_info = installer._http_pkcs12_info
    pkinit_pkcs12_info = installer._pkinit_pkcs12_info
    external_cert_file = installer._external_cert_file
    external_ca_file = installer._external_ca_file
    http_ca_cert = installer._ca_cert
    dirsrv_ca_cert = None
    pkinit_ca_cert = None

    tasks.check_ipv6_stack_enabled()
    tasks.check_selinux_status()
    check_ldap_conf()

    mask_str = validate_mask()
    if mask_str:
        print("Unexpected system mask: %s, expected 0022" % mask_str)
        if installer.interactive:
            if not user_input("Do you want to continue anyway?", True):
                raise ScriptError(
                    "Unexpected system mask: %s" % mask_str)
        else:
            raise ScriptError("Unexpected system mask: %s" % mask_str)

    if options.master_password:
        msg = ("WARNING:\noption '-P/--master-password' is deprecated. "
               "KDC master password of sufficient strength is autogenerated "
               "during IPA server installation and should not be set "
               "manually.")
        print(textwrap.fill(msg, width=79, replace_whitespace=False))

    installer._installation_cleanup = True

    print("\nThe log file for this installation can be found in "
          "/var/log/ipaserver-install.log")
    if (not options.external_ca and not options.external_cert_files and
            is_ipa_configured()):
        installer._installation_cleanup = False
        raise ScriptError(
            "IPA server is already configured on this system.\n"
            "If you want to reinstall the IPA server, please uninstall "
            "it first using 'ipa-server-install --uninstall'.")

    client_fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE)
    if client_fstore.has_files():
        installer._installation_cleanup = False
        raise ScriptError(
            "IPA client is already configured on this system.\n"
            "Please uninstall it before configuring the IPA server, "
            "using 'ipa-client-install --uninstall'")

    fstore = sysrestore.FileStore(SYSRESTORE_DIR_PATH)
    sstore = sysrestore.StateFile(SYSRESTORE_DIR_PATH)

    # This will override any settings passed in on the cmdline
    if os.path.isfile(paths.ROOT_IPA_CACHE):
        if options.dm_password is not None:
            dm_password = options.dm_password
        else:
            dm_password = read_password("Directory Manager", confirm=False)
        if dm_password is None:
            raise ScriptError("Directory Manager password required")
        try:
            cache_vars = read_cache(dm_password)
            options.__dict__.update(cache_vars)
            if cache_vars.get('external_ca', False):
                options.external_ca = False
                options.interactive = False
        except Exception as e:
            raise ScriptError("Cannot process the cache file: %s" % str(e))

    # We only set up the CA if the PKCS#12 options are not given.
    if options.dirsrv_cert_files:
        setup_ca = False
    else:
        setup_ca = True
    options.setup_ca = setup_ca

    if not setup_ca and options.ca_subject:
        raise ScriptError(
            "--ca-subject cannot be used with CA-less installation")
    if not setup_ca and options.subject_base:
        raise ScriptError(
            "--subject-base cannot be used with CA-less installation")
    if not setup_ca and options.setup_kra:
        raise ScriptError(
            "--setup-kra cannot be used with CA-less installation")

    print("======================================="
          "=======================================")
    print("This program will set up the FreeIPA Server.")
    print("Version {}".format(version.VERSION))
    print("")
    print("This includes:")
    if setup_ca:
        print("  * Configure a stand-alone CA (dogtag) for certificate "
              "management")
    if not options.no_ntp:
        print("  * Configure the NTP client (chronyd)")
    print("  * Create and configure an instance of Directory Server")
    print("  * Create and configure a Kerberos Key Distribution Center (KDC)")
    print("  * Configure Apache (httpd)")
    if options.setup_kra:
        print("  * Configure KRA (dogtag) for secret management")
    if options.setup_dns:
        print("  * Configure DNS (bind)")
    if options.setup_adtrust:
        print("  * Configure Samba (smb) and winbind for managing AD trusts")
    if not options.no_pkinit:
        print("  * Configure the KDC to enable PKINIT")
    if options.no_ntp:
        print("")
        print("Excluded by options:")
        print("  * Configure the NTP client (chronyd)")
    if installer.interactive:
        print("")
        print("To accept the default shown in brackets, press the Enter key.")
    print("")

    if not options.external_cert_files:
        # Make sure the 389-ds ports are available
        check_dirsrv(not installer.interactive)

    if not options.no_ntp:
        try:
            timeconf.check_timedate_services()
        except timeconf.NTPConflictingService as e:
            print(
                "WARNING: conflicting time&date synchronization service "
                "'{}' will be disabled in favor of chronyd\n".format(
                    e.conflicting_service
                )
            )
        except timeconf.NTPConfigurationError:
            pass

    if not options.setup_dns and installer.interactive:
        if ipautil.user_input("Do you want to configure integrated DNS "
                              "(BIND)?", False):
            options.setup_dns = True
        print("")

    # check bind packages are installed
    if options.setup_dns:
        # Don't require an external DNS to say who we are if we are
        # setting up a local DNS server.
        options.no_host_dns = True

    # check the hostname is correctly configured, it must be as the kldap
    # utilities just use the hostname as returned by getaddrinfo to set
    # up some of the standard entries

    if options.host_name:
        host_default = options.host_name
    else:
        host_default = get_fqdn()

    try:
        if not installer.interactive or options.host_name:
            verify_fqdn(host_default, options.no_host_dns)
            host_name = host_default
        else:
            host_name = read_host_name(host_default, options.no_host_dns)
    except BadHostError as e:
        raise ScriptError(e)

    host_name = host_name.lower()
    logger.debug("will use host_name: %s\n", host_name)

    if not options.domain_name:
        domain_name = read_domain_name(host_name[host_name.find(".")+1:],
                                       not installer.interactive)
        logger.debug("read domain_name: %s\n", domain_name)
        try:
            validate_domain_name(domain_name)
        except ValueError as e:
            raise ScriptError("Invalid domain name: %s" % unicode(e))
    else:
        domain_name = options.domain_name

    domain_name = domain_name.lower()

    if not options.realm_name:
        realm_name = read_realm_name(domain_name, not installer.interactive)
        logger.debug("read realm_name: %s\n", realm_name)

        try:
            validate_domain_name(realm_name, entity="realm")
        except ValueError as e:
            raise ScriptError("Invalid realm name: {}".format(unicode(e)))
    else:
        realm_name = options.realm_name.upper()

    if not options.subject_base:
        options.subject_base = installutils.default_subject_base(realm_name)

    if not options.ca_subject:
        options.ca_subject = \
            installutils.default_ca_subject_dn(options.subject_base)

    if options.http_cert_files:
        if options.http_pin is None:
            options.http_pin = installutils.read_password(
                "Enter Apache Server private key unlock",
                confirm=False, validate=False, retry=False)
            if options.http_pin is None:
                raise ScriptError(
                    "Apache Server private key unlock password required")
        http_pkcs12_file, http_pin, http_ca_cert = load_pkcs12(
            cert_files=options.http_cert_files,
            key_password=options.http_pin,
            key_nickname=options.http_cert_name,
            ca_cert_files=options.ca_cert_files,
            host_name=host_name)
        http_pkcs12_info = (http_pkcs12_file.name, http_pin)

    if options.dirsrv_cert_files:
        if options.dirsrv_pin is None:
            options.dirsrv_pin = read_password(
                "Enter Directory Server private key unlock",
                confirm=False, validate=False, retry=False)
            if options.dirsrv_pin is None:
                raise ScriptError(
                    "Directory Server private key unlock password required")
        dirsrv_pkcs12_file, dirsrv_pin, dirsrv_ca_cert = load_pkcs12(
            cert_files=options.dirsrv_cert_files,
            key_password=options.dirsrv_pin,
            key_nickname=options.dirsrv_cert_name,
            ca_cert_files=options.ca_cert_files,
            host_name=host_name)
        dirsrv_pkcs12_info = (dirsrv_pkcs12_file.name, dirsrv_pin)

    if options.pkinit_cert_files:
        if options.pkinit_pin is None:
            options.pkinit_pin = read_password(
                "Enter Kerberos KDC private key unlock",
                confirm=False, validate=False, retry=False)
            if options.pkinit_pin is None:
                raise ScriptError(
                    "Kerberos KDC private key unlock password required")
        pkinit_pkcs12_file, pkinit_pin, pkinit_ca_cert = load_pkcs12(
            cert_files=options.pkinit_cert_files,
            key_password=options.pkinit_pin,
            key_nickname=options.pkinit_cert_name,
            ca_cert_files=options.ca_cert_files,
            realm_name=realm_name)
        pkinit_pkcs12_info = (pkinit_pkcs12_file.name, pkinit_pin)

    if (options.http_cert_files and options.dirsrv_cert_files and
            http_ca_cert != dirsrv_ca_cert):
        raise ScriptError(
            "Apache Server SSL certificate and Directory Server SSL "
            "certificate are not signed by the same CA certificate")

    if (options.http_cert_files and
            options.pkinit_cert_files and
            http_ca_cert != pkinit_ca_cert):
        raise ScriptError(
            "Apache Server SSL certificate and PKINIT KDC "
            "certificate are not signed by the same CA certificate")

    if not options.dm_password:
        dm_password = read_dm_password()

        if dm_password is None:
            raise ScriptError("Directory Manager password required")
    else:
        dm_password = options.dm_password

    if not options.master_password:
        master_password = ipa_generate_password()
    else:
        master_password = options.master_password

    if not options.admin_password:
        admin_password = read_admin_password()
        if admin_password is None:
            raise ScriptError("IPA admin password required")
    else:
        admin_password = options.admin_password

    # Configuration for ipalib, we will bootstrap and finalize later, after
    # we are sure we have the configuration file ready.
    cfg = dict(
        context='installer',
        confdir=paths.ETC_IPA,
        in_server=True,
        # make sure host name specified by user is used instead of default
        host=host_name,
    )
    if setup_ca:
        # we have an IPA-integrated CA
        cfg['ca_host'] = host_name

    # Create the management framework config file and finalize api
    target_fname = paths.IPA_DEFAULT_CONF
    ipaconf = IPAChangeConf("IPA Server Install")
    ipaconf.setOptionAssignment(" = ")
    ipaconf.setSectionNameDelimiters(("[", "]"))

    xmlrpc_uri = 'https://{0}/ipa/xml'.format(
                    ipautil.format_netloc(host_name))
    ldapi_uri = ipaldap.realm_to_ldapi_uri(realm_name)

    # [global] section
    gopts = [
        ipaconf.setOption('host', host_name),
        ipaconf.setOption('basedn', ipautil.realm_to_suffix(realm_name)),
        ipaconf.setOption('realm', realm_name),
        ipaconf.setOption('domain', domain_name),
        ipaconf.setOption('xmlrpc_uri', xmlrpc_uri),
        ipaconf.setOption('ldap_uri', ldapi_uri),
        ipaconf.setOption('mode', 'production')
    ]

    if setup_ca:
        gopts.extend([
            ipaconf.setOption('enable_ra', 'True'),
            ipaconf.setOption('ra_plugin', 'dogtag'),
            ipaconf.setOption('dogtag_version', '10')
        ])
    else:
        gopts.extend([
            ipaconf.setOption('enable_ra', 'False'),
            ipaconf.setOption('ra_plugin', 'None')
        ])

    opts = [
        ipaconf.setSection('global', gopts),
        {'name': 'empty', 'type': 'empty'}
    ]

    ipaconf.newConf(target_fname, opts)

    # Must be readable for everyone
    os.chmod(target_fname, 0o644)

    api.bootstrap(**cfg)
    api.finalize()

    if setup_ca:
        ca.install_check(False, None, options)
    if options.setup_kra:
        kra.install_check(api, None, options)

    if options.setup_dns:
        dns.install_check(False, api, False, options, host_name)
        ip_addresses = dns.ip_addresses
    else:
        ip_addresses = get_server_ip_address(host_name,
                                             not installer.interactive, False,
                                             options.ip_addresses)

        # check addresses here, dns module is doing own check
        no_matching_interface_for_ip_address_warning(ip_addresses)

    instance_name = "-".join(realm_name.split("."))
    dirsrv = services.knownservices.dirsrv
    if (options.external_cert_files
           and dirsrv.is_installed(instance_name)
           and not dirsrv.is_running(instance_name)):
        logger.debug('Starting Directory Server')
        services.knownservices.dirsrv.start(instance_name)

    if options.setup_adtrust:
        adtrust.install_check(False, options, api)

    # installer needs to update hosts file when DNS subsystem will be
    # installed or custom addresses are used
    if options.ip_addresses or options.setup_dns:
        installer._update_hosts_file = True

    if not options.no_ntp and not options.unattended and not (
            options.ntp_servers or options.ntp_pool):
        options.ntp_servers, options.ntp_pool = timeconf.get_time_source()

    print()
    print("The IPA Master Server will be configured with:")
    print("Hostname:       %s" % host_name)
    print("IP address(es): %s" % ", ".join(str(ip) for ip in ip_addresses))
    print("Domain name:    %s" % domain_name)
    print("Realm name:     %s" % realm_name)
    print()

    if setup_ca:
        ca.print_ca_configuration(options)
        print()

    if options.setup_dns:
        print("BIND DNS server will be configured to serve IPA domain with:")
        print("Forwarders:       %s" % (
            "No forwarders" if not options.forwarders
            else ", ".join([str(ip) for ip in options.forwarders])
        ))
        print('Forward policy:   %s' % options.forward_policy)
        print("Reverse zone(s):  %s" % (
            "No reverse zone" if options.no_reverse or not dns.reverse_zones
            else ", ".join(str(rz) for rz in dns.reverse_zones)
        ))
        print()

    if not options.setup_adtrust:
        # If domain name and realm does not match, IPA server will not be able
        # to establish trust with Active Directory. Print big fat warning.

        realm_not_matching_domain = (domain_name.upper() != realm_name)

        if realm_not_matching_domain:
            print("WARNING: Realm name does not match the domain name.\n"
                  "You will not be able to establish trusts with Active "
                  "Directory unless\nthe realm name of the IPA server matches "
                  "its domain name.\n\n")

    if options.ntp_servers or options.ntp_pool:
        if options.ntp_servers:
            for server in options.ntp_servers:
                print("NTP server:\t{}".format(server))

        if options.ntp_pool:
            print("NTP pool:\t{}".format(options.ntp_pool))

    if installer.interactive and not user_input(
            "Continue to configure the system with these values?", False):
        raise ScriptError("Installation aborted")

    options.realm_name = realm_name
    options.domain_name = domain_name
    options.dm_password = dm_password
    options.master_password = master_password
    options.admin_password = admin_password
    options._host_name_overridden = bool(options.host_name)
    options.host_name = host_name
    options.ip_addresses = ip_addresses

    installer._fstore = fstore
    installer._sstore = sstore
    installer._dirsrv_pkcs12_file = dirsrv_pkcs12_file
    installer._http_pkcs12_file = http_pkcs12_file
    installer._pkinit_pkcs12_file = pkinit_pkcs12_file
    installer._dirsrv_pkcs12_info = dirsrv_pkcs12_info
    installer._http_pkcs12_info = http_pkcs12_info
    installer._pkinit_pkcs12_info = pkinit_pkcs12_info
    installer._external_cert_file = external_cert_file
    installer._external_ca_file = external_ca_file
    installer._ca_cert = http_ca_cert
Exemple #19
0
def install_check(installer):
    options = installer
    dirsrv_pkcs12_file = installer._dirsrv_pkcs12_file
    http_pkcs12_file = installer._http_pkcs12_file
    pkinit_pkcs12_file = installer._pkinit_pkcs12_file
    dirsrv_pkcs12_info = installer._dirsrv_pkcs12_info
    http_pkcs12_info = installer._http_pkcs12_info
    pkinit_pkcs12_info = installer._pkinit_pkcs12_info
    external_cert_file = installer._external_cert_file
    external_ca_file = installer._external_ca_file
    http_ca_cert = installer._ca_cert

    tasks.check_ipv6_stack_enabled()
    tasks.check_selinux_status()

    if options.master_password:
        msg = ("WARNING:\noption '-P/--master-password' is deprecated. "
               "KDC master password of sufficient strength is autogenerated "
               "during IPA server installation and should not be set "
               "manually.")
        print(textwrap.fill(msg, width=79, replace_whitespace=False))

    installer._installation_cleanup = True

    print("\nThe log file for this installation can be found in "
          "/var/log/ipaserver-install.log")
    if (not options.external_ca and not options.external_cert_files
            and is_ipa_configured()):
        installer._installation_cleanup = False
        raise ScriptError(
            "IPA server is already configured on this system.\n"
            "If you want to reinstall the IPA server, please uninstall "
            "it first using 'ipa-server-install --uninstall'.")

    client_fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE)
    if client_fstore.has_files():
        installer._installation_cleanup = False
        raise ScriptError(
            "IPA client is already configured on this system.\n"
            "Please uninstall it before configuring the IPA server, "
            "using 'ipa-client-install --uninstall'")

    fstore = sysrestore.FileStore(SYSRESTORE_DIR_PATH)
    sstore = sysrestore.StateFile(SYSRESTORE_DIR_PATH)

    # This will override any settings passed in on the cmdline
    if ipautil.file_exists(paths.ROOT_IPA_CACHE):
        if options.dm_password is not None:
            dm_password = options.dm_password
        else:
            dm_password = read_password("Directory Manager", confirm=False)
        if dm_password is None:
            raise ScriptError("Directory Manager password required")
        try:
            cache_vars = read_cache(dm_password)
            options.__dict__.update(cache_vars)
            if cache_vars.get('external_ca', False):
                options.external_ca = False
                options.interactive = False
        except Exception as e:
            raise ScriptError("Cannot process the cache file: %s" % str(e))

    # We only set up the CA if the PKCS#12 options are not given.
    if options.dirsrv_cert_files:
        setup_ca = False
    else:
        setup_ca = True
    options.setup_ca = setup_ca

    if not setup_ca and options.ca_subject:
        raise ScriptError(
            "--ca-subject cannot be used with CA-less installation")
    if not setup_ca and options.subject_base:
        raise ScriptError(
            "--subject-base cannot be used with CA-less installation")
    if not setup_ca and options.setup_kra:
        raise ScriptError(
            "--setup-kra cannot be used with CA-less installation")

    print("======================================="
          "=======================================")
    print("This program will set up the FreeIPA Server.")
    print("")
    print("This includes:")
    if setup_ca:
        print("  * Configure a stand-alone CA (dogtag) for certificate "
              "management")
    if not options.no_ntp:
        print("  * Configure the Network Time Daemon (ntpd)")
    print("  * Create and configure an instance of Directory Server")
    print("  * Create and configure a Kerberos Key Distribution Center (KDC)")
    print("  * Configure Apache (httpd)")
    if options.setup_kra:
        print("  * Configure KRA (dogtag) for secret management")
    if options.setup_dns:
        print("  * Configure DNS (bind)")
    if options.setup_adtrust:
        print("  * Configure Samba (smb) and winbind for managing AD trusts")
    if not options.no_pkinit:
        print("  * Configure the KDC to enable PKINIT")
    if options.no_ntp:
        print("")
        print("Excluded by options:")
        print("  * Configure the Network Time Daemon (ntpd)")
    if installer.interactive:
        print("")
        print("To accept the default shown in brackets, press the Enter key.")
    print("")

    if not options.external_cert_files:
        # Make sure the 389-ds ports are available
        check_dirsrv(not installer.interactive)

    if not options.no_ntp:
        try:
            ipaclient.install.ntpconf.check_timedate_services()
        except ipaclient.install.ntpconf.NTPConflictingService as e:
            print(
                ("WARNING: conflicting time&date synchronization service '%s'"
                 " will be disabled" % e.conflicting_service))
            print("in favor of ntpd")
            print("")
        except ipaclient.install.ntpconf.NTPConfigurationError:
            pass

    # Check to see if httpd is already configured to listen on 443
    if httpinstance.httpd_443_configured():
        raise ScriptError("Aborting installation")

    if not options.setup_dns and installer.interactive:
        if ipautil.user_input(
                "Do you want to configure integrated DNS "
                "(BIND)?", False):
            options.setup_dns = True
        print("")

    # check bind packages are installed
    if options.setup_dns:
        # Don't require an external DNS to say who we are if we are
        # setting up a local DNS server.
        options.no_host_dns = True

    # check the hostname is correctly configured, it must be as the kldap
    # utilities just use the hostname as returned by getaddrinfo to set
    # up some of the standard entries

    if options.host_name:
        host_default = options.host_name
    else:
        host_default = get_fqdn()

    try:
        if not installer.interactive or options.host_name:
            verify_fqdn(host_default, options.no_host_dns)
            host_name = host_default
        else:
            host_name = read_host_name(host_default, options.no_host_dns)
    except BadHostError as e:
        raise ScriptError(e)

    host_name = host_name.lower()
    root_logger.debug("will use host_name: %s\n" % host_name)

    if not options.domain_name:
        domain_name = read_domain_name(host_name[host_name.find(".") + 1:],
                                       not installer.interactive)
        root_logger.debug("read domain_name: %s\n" % domain_name)
        try:
            validate_domain_name(domain_name)
        except ValueError as e:
            raise ScriptError("Invalid domain name: %s" % unicode(e))
    else:
        domain_name = options.domain_name

    domain_name = domain_name.lower()

    if not options.realm_name:
        realm_name = read_realm_name(domain_name, not installer.interactive)
        root_logger.debug("read realm_name: %s\n" % realm_name)
    else:
        realm_name = options.realm_name.upper()

    if not options.subject_base:
        options.subject_base = installutils.default_subject_base(realm_name)

    if not options.ca_subject:
        options.ca_subject = \
            installutils.default_ca_subject_dn(options.subject_base)

    if options.http_cert_files:
        if options.http_pin is None:
            options.http_pin = installutils.read_password(
                "Enter Apache Server private key unlock",
                confirm=False,
                validate=False,
                retry=False)
            if options.http_pin is None:
                raise ScriptError(
                    "Apache Server private key unlock password required")
        http_pkcs12_file, http_pin, http_ca_cert = load_pkcs12(
            cert_files=options.http_cert_files,
            key_password=options.http_pin,
            key_nickname=options.http_cert_name,
            ca_cert_files=options.ca_cert_files,
            host_name=host_name)
        http_pkcs12_info = (http_pkcs12_file.name, http_pin)

    if options.dirsrv_cert_files:
        if options.dirsrv_pin is None:
            options.dirsrv_pin = read_password(
                "Enter Directory Server private key unlock",
                confirm=False,
                validate=False,
                retry=False)
            if options.dirsrv_pin is None:
                raise ScriptError(
                    "Directory Server private key unlock password required")
        dirsrv_pkcs12_file, dirsrv_pin, dirsrv_ca_cert = load_pkcs12(
            cert_files=options.dirsrv_cert_files,
            key_password=options.dirsrv_pin,
            key_nickname=options.dirsrv_cert_name,
            ca_cert_files=options.ca_cert_files,
            host_name=host_name)
        dirsrv_pkcs12_info = (dirsrv_pkcs12_file.name, dirsrv_pin)

    if options.pkinit_cert_files:
        if options.pkinit_pin is None:
            options.pkinit_pin = read_password(
                "Enter Kerberos KDC private key unlock",
                confirm=False,
                validate=False,
                retry=False)
            if options.pkinit_pin is None:
                raise ScriptError(
                    "Kerberos KDC private key unlock password required")
        pkinit_pkcs12_file, pkinit_pin, _pkinit_ca_cert = load_pkcs12(
            cert_files=options.pkinit_cert_files,
            key_password=options.pkinit_pin,
            key_nickname=options.pkinit_cert_name,
            ca_cert_files=options.ca_cert_files,
            host_name=host_name)
        pkinit_pkcs12_info = (pkinit_pkcs12_file.name, pkinit_pin)

    if (options.http_cert_files and options.dirsrv_cert_files
            and http_ca_cert != dirsrv_ca_cert):
        raise ScriptError(
            "Apache Server SSL certificate and Directory Server SSL "
            "certificate are not signed by the same CA certificate")

    if not options.dm_password:
        dm_password = read_dm_password()

        if dm_password is None:
            raise ScriptError("Directory Manager password required")
    else:
        dm_password = options.dm_password

    if not options.master_password:
        master_password = ipa_generate_password()
    else:
        master_password = options.master_password

    if not options.admin_password:
        admin_password = read_admin_password()
        if admin_password is None:
            raise ScriptError("IPA admin password required")
    else:
        admin_password = options.admin_password

    # Configuration for ipalib, we will bootstrap and finalize later, after
    # we are sure we have the configuration file ready.
    cfg = dict(
        context='installer',
        confdir=paths.ETC_IPA,
        in_server=True,
        # make sure host name specified by user is used instead of default
        host=host_name,
    )
    if setup_ca:
        # we have an IPA-integrated CA
        cfg['ca_host'] = host_name

    # Create the management framework config file and finalize api
    target_fname = paths.IPA_DEFAULT_CONF
    fd = open(target_fname, "w")
    fd.write("[global]\n")
    fd.write("host=%s\n" % host_name)
    fd.write("basedn=%s\n" % ipautil.realm_to_suffix(realm_name))
    fd.write("realm=%s\n" % realm_name)
    fd.write("domain=%s\n" % domain_name)
    fd.write("xmlrpc_uri=https://%s/ipa/xml\n" % format_netloc(host_name))
    fd.write("ldap_uri=ldapi://%%2fvar%%2frun%%2fslapd-%s.socket\n" %
             installutils.realm_to_serverid(realm_name))
    if setup_ca:
        fd.write("enable_ra=True\n")
        fd.write("ra_plugin=dogtag\n")
        fd.write("dogtag_version=10\n")
    else:
        fd.write("enable_ra=False\n")
        fd.write("ra_plugin=none\n")
    fd.write("mode=production\n")
    fd.close()

    # Must be readable for everyone
    os.chmod(target_fname, 0o644)

    api.bootstrap(**cfg)
    api.finalize()

    if setup_ca:
        ca.install_check(False, None, options)
    if options.setup_kra:
        kra.install_check(api, None, options)

    if options.setup_dns:
        dns.install_check(False, api, False, options, host_name)
        ip_addresses = dns.ip_addresses
    else:
        ip_addresses = get_server_ip_address(host_name,
                                             not installer.interactive, False,
                                             options.ip_addresses)

        # check addresses here, dns module is doing own check
        network_ip_address_warning(ip_addresses)
        broadcast_ip_address_warning(ip_addresses)

    if options.setup_adtrust:
        adtrust.install_check(False, options, api)

    # installer needs to update hosts file when DNS subsystem will be
    # installed or custom addresses are used
    if options.ip_addresses or options.setup_dns:
        installer._update_hosts_file = True

    print()
    print("The IPA Master Server will be configured with:")
    print("Hostname:       %s" % host_name)
    print("IP address(es): %s" % ", ".join(str(ip) for ip in ip_addresses))
    print("Domain name:    %s" % domain_name)
    print("Realm name:     %s" % realm_name)
    print()

    if options.setup_dns:
        print("BIND DNS server will be configured to serve IPA domain with:")
        print("Forwarders:       %s" %
              ("No forwarders" if not options.forwarders else ", ".join(
                  [str(ip) for ip in options.forwarders])))
        print('Forward policy:   %s' % options.forward_policy)
        print("Reverse zone(s):  %s" %
              ("No reverse zone" if options.no_reverse or not dns.reverse_zones
               else ", ".join(str(rz) for rz in dns.reverse_zones)))
        print()

    if not options.setup_adtrust:
        # If domain name and realm does not match, IPA server will not be able
        # to estabilish trust with Active Directory. Print big fat warning.

        realm_not_matching_domain = (domain_name.upper() != realm_name)

        if realm_not_matching_domain:
            print("WARNING: Realm name does not match the domain name.\n"
                  "You will not be able to estabilish trusts with Active "
                  "Directory unless\nthe realm name of the IPA server matches "
                  "its domain name.\n\n")

    if installer.interactive and not user_input(
            "Continue to configure the system with these values?", False):
        raise ScriptError("Installation aborted")

    options.realm_name = realm_name
    options.domain_name = domain_name
    options.dm_password = dm_password
    options.master_password = master_password
    options.admin_password = admin_password
    options._host_name_overridden = bool(options.host_name)
    options.host_name = host_name
    options.ip_addresses = ip_addresses

    installer._fstore = fstore
    installer._sstore = sstore
    installer._dirsrv_pkcs12_file = dirsrv_pkcs12_file
    installer._http_pkcs12_file = http_pkcs12_file
    installer._pkinit_pkcs12_file = pkinit_pkcs12_file
    installer._dirsrv_pkcs12_info = dirsrv_pkcs12_info
    installer._http_pkcs12_info = http_pkcs12_info
    installer._pkinit_pkcs12_info = pkinit_pkcs12_info
    installer._external_cert_file = external_cert_file
    installer._external_ca_file = external_ca_file
    installer._ca_cert = http_ca_cert
Exemple #20
0
    def __init__(self,
                 dm_password=None,
                 sub_dict={},
                 online=True,
                 ldapi=False):
        '''
        :parameters:
            dm_password
                Directory Manager password
            sub_dict
                substitution dictionary
            online
                Do an online LDAP update or use an experimental LDIF updater
            ldapi
                Bind using ldapi. This assumes autobind is enabled.

        Data Structure Example:
        -----------------------

        dn_by_rdn_count = {
            3: 'cn=config,dc=example,dc=com':
            4: 'cn=bob,ou=people,dc=example,dc=com',
        }

        all_updates = [
            {
                'dn': 'cn=config,dc=example,dc=com',
                'default': ['attr1':default1'],
                'updates': ['action:attr1:value1',
                            'action:attr2:value2]
            },
            {
                'dn': 'cn=bob,ou=people,dc=example,dc=com',
                'default': ['attr3':default3'],
                'updates': ['action:attr3:value3',
                            'action:attr4:value4],
            }
        ]

        The default and update lists are "dispositions"

        Plugins:

        Plugins has to be specified in update file to be executed, using
        'plugin' directive

        Example:
        plugin: update_uniqueness_plugins_to_new_syntax

        Each plugin returns two values:

        1. restart: dirsrv will be restarted AFTER this update is
                     applied.
        2. updates: A list of updates to be applied.

        The value of an update is a dictionary with the following possible
        values:
          - dn: DN, equal to the dn attribute
          - updates: list of updates against the dn
          - default: list of the default entry to be added if it doesn't
                     exist
          - deleteentry: list of dn's to be deleted (typically single dn)

        For example, this update file:

          dn: cn=global_policy,cn=$REALM,cn=kerberos,$SUFFIX
          replace:krbPwdLockoutDuration:10::600
          replace: krbPwdMaxFailure:3::6

        Generates this list which contain the update dictionary:

        [
          dict(
            'dn': 'cn=global_policy,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com',
            'updates': ['replace:krbPwdLockoutDuration:10::600',
                        'replace:krbPwdMaxFailure:3::6']
          )
        ]

        Here is another example showing how a default entry is configured:

          dn: cn=Managed Entries,cn=etc,$SUFFIX
          default: objectClass: nsContainer
          default: objectClass: top
          default: cn: Managed Entries

        This generates:

        [
          dict(
            'dn': 'cn=Managed Entries,cn=etc,dc=example,dc=com',
            'default': ['objectClass:nsContainer',
                        'objectClass:top',
                        'cn:Managed Entries'
                       ]
           )
        ]

        Note that the variable substitution in both examples has been completed.

        Either may make changes directly in LDAP or can return updates in
        update format.

        '''
        log_mgr.get_logger(self, True)
        self.sub_dict = sub_dict
        self.dm_password = dm_password
        self.conn = None
        self.modified = False
        self.online = online
        self.ldapi = ldapi
        self.pw_name = pwd.getpwuid(os.geteuid()).pw_name
        self.realm = None
        self.socket_name = (paths.SLAPD_INSTANCE_SOCKET_TEMPLATE %
                            api.env.realm.replace('.', '-'))
        self.ldapuri = 'ldapi://%s' % ipautil.format_netloc(self.socket_name)
        suffix = None

        if sub_dict.get("REALM"):
            self.realm = sub_dict["REALM"]
        else:
            krbctx = krbV.default_context()
            try:
                self.realm = krbctx.default_realm
                suffix = ipautil.realm_to_suffix(self.realm)
            except krbV.Krb5Error:
                self.realm = None
                suffix = None

        if suffix is not None:
            assert isinstance(suffix, DN)
        domain = ipautil.get_domain_name()
        libarch = self._identify_arch()

        fqdn = installutils.get_fqdn()
        if fqdn is None:
            raise RuntimeError("Unable to determine hostname")

        if not self.sub_dict.get("REALM") and self.realm is not None:
            self.sub_dict["REALM"] = self.realm
        if not self.sub_dict.get("FQDN"):
            self.sub_dict["FQDN"] = fqdn
        if not self.sub_dict.get("DOMAIN"):
            self.sub_dict["DOMAIN"] = domain
        if not self.sub_dict.get("SUFFIX") and suffix is not None:
            self.sub_dict["SUFFIX"] = suffix
        if not self.sub_dict.get("ESCAPED_SUFFIX"):
            self.sub_dict["ESCAPED_SUFFIX"] = str(suffix)
        if not self.sub_dict.get("LIBARCH"):
            self.sub_dict["LIBARCH"] = libarch
        if not self.sub_dict.get("TIME"):
            self.sub_dict["TIME"] = int(time.time())
        if not self.sub_dict.get("DOMAIN") and domain is not None:
            self.sub_dict["DOMAIN"] = domain
        self.api = create_api(mode=None)
        self.api.bootstrap(in_server=True, context='updates')
        self.api.finalize()
        if online:
            # Try out the connection/password
            # (This will raise if the server is not available)
            self.create_connection()
            self.close_connection()
        else:
            raise RuntimeError("Offline updates are not supported.")
Exemple #21
0
def install_check(installer):
    options = installer
    dirsrv_pkcs12_file = installer._dirsrv_pkcs12_file
    http_pkcs12_file = installer._http_pkcs12_file
    pkinit_pkcs12_file = installer._pkinit_pkcs12_file
    dirsrv_pkcs12_info = installer._dirsrv_pkcs12_info
    http_pkcs12_info = installer._http_pkcs12_info
    pkinit_pkcs12_info = installer._pkinit_pkcs12_info
    external_cert_file = installer._external_cert_file
    external_ca_file = installer._external_ca_file
    http_ca_cert = installer._ca_cert
    dirsrv_ca_cert = None
    pkinit_ca_cert = None

    tasks.check_ipv6_stack_enabled()
    tasks.check_selinux_status()
    check_ldap_conf()

    mask_str = validate_mask()
    if mask_str:
        print("Unexpected system mask: %s, expected 0022" % mask_str)
        if installer.interactive:
            if not user_input("Do you want to continue anyway?", True):
                raise ScriptError(
                    "Unexpected system mask: %s" % mask_str)
        else:
            raise ScriptError("Unexpected system mask: %s" % mask_str)

    if options.master_password:
        msg = ("WARNING:\noption '-P/--master-password' is deprecated. "
               "KDC master password of sufficient strength is autogenerated "
               "during IPA server installation and should not be set "
               "manually.")
        print(textwrap.fill(msg, width=79, replace_whitespace=False))

    installer._installation_cleanup = True

    print("\nThe log file for this installation can be found in "
          "/var/log/ipaserver-install.log")
    if (not options.external_ca and not options.external_cert_files and
            is_ipa_configured()):
        installer._installation_cleanup = False
        raise ScriptError(
            "IPA server is already configured on this system.\n"
            "If you want to reinstall the IPA server, please uninstall "
            "it first using 'ipa-server-install --uninstall'.")

    client_fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE)
    if client_fstore.has_files():
        installer._installation_cleanup = False
        raise ScriptError(
            "IPA client is already configured on this system.\n"
            "Please uninstall it before configuring the IPA server, "
            "using 'ipa-client-install --uninstall'")

    fstore = sysrestore.FileStore(SYSRESTORE_DIR_PATH)
    sstore = sysrestore.StateFile(SYSRESTORE_DIR_PATH)

    # This will override any settings passed in on the cmdline
    if os.path.isfile(paths.ROOT_IPA_CACHE):
        if options.dm_password is not None:
            dm_password = options.dm_password
        else:
            dm_password = read_password("Directory Manager", confirm=False)
        if dm_password is None:
            raise ScriptError("Directory Manager password required")
        try:
            cache_vars = read_cache(dm_password)
            options.__dict__.update(cache_vars)
            if cache_vars.get('external_ca', False):
                options.external_ca = False
                options.interactive = False
        except Exception as e:
            raise ScriptError("Cannot process the cache file: %s" % str(e))

    # We only set up the CA if the PKCS#12 options are not given.
    if options.dirsrv_cert_files:
        setup_ca = False
    else:
        setup_ca = True
    options.setup_ca = setup_ca

    if not setup_ca and options.ca_subject:
        raise ScriptError(
            "--ca-subject cannot be used with CA-less installation")
    if not setup_ca and options.subject_base:
        raise ScriptError(
            "--subject-base cannot be used with CA-less installation")
    if not setup_ca and options.setup_kra:
        raise ScriptError(
            "--setup-kra cannot be used with CA-less installation")

    print("======================================="
          "=======================================")
    print("This program will set up the FreeIPA Server.")
    print("Version {}".format(version.VERSION))
    print("")
    print("This includes:")
    if setup_ca:
        print("  * Configure a stand-alone CA (dogtag) for certificate "
              "management")
    if not options.no_ntp:
        print("  * Configure the NTP client (chronyd)")
    print("  * Create and configure an instance of Directory Server")
    print("  * Create and configure a Kerberos Key Distribution Center (KDC)")
    print("  * Configure Apache (httpd)")
    if options.setup_kra:
        print("  * Configure KRA (dogtag) for secret management")
    if options.setup_dns:
        print("  * Configure DNS (bind)")
    if options.setup_adtrust:
        print("  * Configure Samba (smb) and winbind for managing AD trusts")
    if not options.no_pkinit:
        print("  * Configure the KDC to enable PKINIT")
    if options.no_ntp:
        print("")
        print("Excluded by options:")
        print("  * Configure the NTP client (chronyd)")
    if installer.interactive:
        print("")
        print("To accept the default shown in brackets, press the Enter key.")
    print("")

    if not options.external_cert_files:
        # Make sure the 389-ds ports are available
        check_dirsrv(not installer.interactive)

    if not options.no_ntp:
        try:
            ipaclient.install.timeconf.check_timedate_services()
        except ipaclient.install.timeconf.NTPConflictingService as e:
            print("WARNING: conflicting time&date synchronization service '{}'"
                  " will be disabled".format(e.conflicting_service))
            print("in favor of chronyd")
            print("")
        except ipaclient.install.timeconf.NTPConfigurationError:
            pass

    if not options.setup_dns and installer.interactive:
        if ipautil.user_input("Do you want to configure integrated DNS "
                              "(BIND)?", False):
            options.setup_dns = True
        print("")

    # check bind packages are installed
    if options.setup_dns:
        # Don't require an external DNS to say who we are if we are
        # setting up a local DNS server.
        options.no_host_dns = True

    # check the hostname is correctly configured, it must be as the kldap
    # utilities just use the hostname as returned by getaddrinfo to set
    # up some of the standard entries

    if options.host_name:
        host_default = options.host_name
    else:
        host_default = get_fqdn()

    try:
        if not installer.interactive or options.host_name:
            verify_fqdn(host_default, options.no_host_dns)
            host_name = host_default
        else:
            host_name = read_host_name(host_default, options.no_host_dns)
    except BadHostError as e:
        raise ScriptError(e)

    host_name = host_name.lower()
    logger.debug("will use host_name: %s\n", host_name)

    if not options.domain_name:
        domain_name = read_domain_name(host_name[host_name.find(".")+1:],
                                       not installer.interactive)
        logger.debug("read domain_name: %s\n", domain_name)
        try:
            validate_domain_name(domain_name)
        except ValueError as e:
            raise ScriptError("Invalid domain name: %s" % unicode(e))
    else:
        domain_name = options.domain_name

    domain_name = domain_name.lower()

    if not options.realm_name:
        realm_name = read_realm_name(domain_name, not installer.interactive)
        logger.debug("read realm_name: %s\n", realm_name)

        try:
            validate_domain_name(realm_name, entity="realm")
        except ValueError as e:
            raise ScriptError("Invalid realm name: {}".format(unicode(e)))
    else:
        realm_name = options.realm_name.upper()

    if not options.subject_base:
        options.subject_base = installutils.default_subject_base(realm_name)

    if not options.ca_subject:
        options.ca_subject = \
            installutils.default_ca_subject_dn(options.subject_base)

    if options.http_cert_files:
        if options.http_pin is None:
            options.http_pin = installutils.read_password(
                "Enter Apache Server private key unlock",
                confirm=False, validate=False, retry=False)
            if options.http_pin is None:
                raise ScriptError(
                    "Apache Server private key unlock password required")
        http_pkcs12_file, http_pin, http_ca_cert = load_pkcs12(
            cert_files=options.http_cert_files,
            key_password=options.http_pin,
            key_nickname=options.http_cert_name,
            ca_cert_files=options.ca_cert_files,
            host_name=host_name)
        http_pkcs12_info = (http_pkcs12_file.name, http_pin)

    if options.dirsrv_cert_files:
        if options.dirsrv_pin is None:
            options.dirsrv_pin = read_password(
                "Enter Directory Server private key unlock",
                confirm=False, validate=False, retry=False)
            if options.dirsrv_pin is None:
                raise ScriptError(
                    "Directory Server private key unlock password required")
        dirsrv_pkcs12_file, dirsrv_pin, dirsrv_ca_cert = load_pkcs12(
            cert_files=options.dirsrv_cert_files,
            key_password=options.dirsrv_pin,
            key_nickname=options.dirsrv_cert_name,
            ca_cert_files=options.ca_cert_files,
            host_name=host_name)
        dirsrv_pkcs12_info = (dirsrv_pkcs12_file.name, dirsrv_pin)

    if options.pkinit_cert_files:
        if options.pkinit_pin is None:
            options.pkinit_pin = read_password(
                "Enter Kerberos KDC private key unlock",
                confirm=False, validate=False, retry=False)
            if options.pkinit_pin is None:
                raise ScriptError(
                    "Kerberos KDC private key unlock password required")
        pkinit_pkcs12_file, pkinit_pin, pkinit_ca_cert = load_pkcs12(
            cert_files=options.pkinit_cert_files,
            key_password=options.pkinit_pin,
            key_nickname=options.pkinit_cert_name,
            ca_cert_files=options.ca_cert_files,
            realm_name=realm_name)
        pkinit_pkcs12_info = (pkinit_pkcs12_file.name, pkinit_pin)

    if (options.http_cert_files and options.dirsrv_cert_files and
            http_ca_cert != dirsrv_ca_cert):
        raise ScriptError(
            "Apache Server SSL certificate and Directory Server SSL "
            "certificate are not signed by the same CA certificate")

    if (options.http_cert_files and
            options.pkinit_cert_files and
            http_ca_cert != pkinit_ca_cert):
        raise ScriptError(
            "Apache Server SSL certificate and PKINIT KDC "
            "certificate are not signed by the same CA certificate")

    if not options.dm_password:
        dm_password = read_dm_password()

        if dm_password is None:
            raise ScriptError("Directory Manager password required")
    else:
        dm_password = options.dm_password

    if not options.master_password:
        master_password = ipa_generate_password()
    else:
        master_password = options.master_password

    if not options.admin_password:
        admin_password = read_admin_password()
        if admin_password is None:
            raise ScriptError("IPA admin password required")
    else:
        admin_password = options.admin_password

    # Configuration for ipalib, we will bootstrap and finalize later, after
    # we are sure we have the configuration file ready.
    cfg = dict(
        context='installer',
        confdir=paths.ETC_IPA,
        in_server=True,
        # make sure host name specified by user is used instead of default
        host=host_name,
    )
    if setup_ca:
        # we have an IPA-integrated CA
        cfg['ca_host'] = host_name

    # Create the management framework config file and finalize api
    target_fname = paths.IPA_DEFAULT_CONF
    ipaconf = IPAChangeConf("IPA Server Install")
    ipaconf.setOptionAssignment(" = ")
    ipaconf.setSectionNameDelimiters(("[", "]"))

    xmlrpc_uri = 'https://{0}/ipa/xml'.format(
                    ipautil.format_netloc(host_name))
    ldapi_uri = ipaldap.realm_to_ldapi_uri(realm_name)

    # [global] section
    gopts = [
        ipaconf.setOption('host', host_name),
        ipaconf.setOption('basedn', ipautil.realm_to_suffix(realm_name)),
        ipaconf.setOption('realm', realm_name),
        ipaconf.setOption('domain', domain_name),
        ipaconf.setOption('xmlrpc_uri', xmlrpc_uri),
        ipaconf.setOption('ldap_uri', ldapi_uri),
        ipaconf.setOption('mode', 'production')
    ]

    if setup_ca:
        gopts.extend([
            ipaconf.setOption('enable_ra', 'True'),
            ipaconf.setOption('ra_plugin', 'dogtag'),
            ipaconf.setOption('dogtag_version', '10')
        ])
    else:
        gopts.extend([
            ipaconf.setOption('enable_ra', 'False'),
            ipaconf.setOption('ra_plugin', 'None')
        ])

    opts = [
        ipaconf.setSection('global', gopts),
        {'name': 'empty', 'type': 'empty'}
    ]

    ipaconf.newConf(target_fname, opts)

    # Must be readable for everyone
    os.chmod(target_fname, 0o644)

    api.bootstrap(**cfg)
    api.finalize()

    if setup_ca:
        ca.install_check(False, None, options)
    if options.setup_kra:
        kra.install_check(api, None, options)

    if options.setup_dns:
        dns.install_check(False, api, False, options, host_name)
        ip_addresses = dns.ip_addresses
    else:
        ip_addresses = get_server_ip_address(host_name,
                                             not installer.interactive, False,
                                             options.ip_addresses)

        # check addresses here, dns module is doing own check
        no_matching_interface_for_ip_address_warning(ip_addresses)

    instance_name = "-".join(realm_name.split("."))
    dirsrv = services.knownservices.dirsrv
    if (options.external_cert_files
           and dirsrv.is_installed(instance_name)
           and not dirsrv.is_running(instance_name)):
        logger.debug('Starting Directory Server')
        services.knownservices.dirsrv.start(instance_name)

    if options.setup_adtrust:
        adtrust.install_check(False, options, api)

    # installer needs to update hosts file when DNS subsystem will be
    # installed or custom addresses are used
    if options.ip_addresses or options.setup_dns:
        installer._update_hosts_file = True

    print()
    print("The IPA Master Server will be configured with:")
    print("Hostname:       %s" % host_name)
    print("IP address(es): %s" % ", ".join(str(ip) for ip in ip_addresses))
    print("Domain name:    %s" % domain_name)
    print("Realm name:     %s" % realm_name)
    print()

    if setup_ca:
        ca.print_ca_configuration(options)
        print()

    if options.setup_dns:
        print("BIND DNS server will be configured to serve IPA domain with:")
        print("Forwarders:       %s" % (
            "No forwarders" if not options.forwarders
            else ", ".join([str(ip) for ip in options.forwarders])
        ))
        print('Forward policy:   %s' % options.forward_policy)
        print("Reverse zone(s):  %s" % (
            "No reverse zone" if options.no_reverse or not dns.reverse_zones
            else ", ".join(str(rz) for rz in dns.reverse_zones)
        ))
        print()

    if not options.setup_adtrust:
        # If domain name and realm does not match, IPA server will not be able
        # to establish trust with Active Directory. Print big fat warning.

        realm_not_matching_domain = (domain_name.upper() != realm_name)

        if realm_not_matching_domain:
            print("WARNING: Realm name does not match the domain name.\n"
                  "You will not be able to establish trusts with Active "
                  "Directory unless\nthe realm name of the IPA server matches "
                  "its domain name.\n\n")

    if installer.interactive and not user_input(
            "Continue to configure the system with these values?", False):
        raise ScriptError("Installation aborted")

    options.realm_name = realm_name
    options.domain_name = domain_name
    options.dm_password = dm_password
    options.master_password = master_password
    options.admin_password = admin_password
    options._host_name_overridden = bool(options.host_name)
    options.host_name = host_name
    options.ip_addresses = ip_addresses

    installer._fstore = fstore
    installer._sstore = sstore
    installer._dirsrv_pkcs12_file = dirsrv_pkcs12_file
    installer._http_pkcs12_file = http_pkcs12_file
    installer._pkinit_pkcs12_file = pkinit_pkcs12_file
    installer._dirsrv_pkcs12_info = dirsrv_pkcs12_info
    installer._http_pkcs12_info = http_pkcs12_info
    installer._pkinit_pkcs12_info = pkinit_pkcs12_info
    installer._external_cert_file = external_cert_file
    installer._external_ca_file = external_ca_file
    installer._ca_cert = http_ca_cert
Exemple #22
0
def update_schema(
    schema_files,
    ldapi=False,
    dm_password=None,
):
    """Update schema to match the given ldif files

    Schema elements present in the LDIF files but missing from the DS schema
    are added.
    Schema elements that differ between LDIF files and DS schema are updated
    to match the LDIF files. The comparison ignores tags that python-ldap's
    schema parser does not understand (such as X-ORIGIN).
    Extra elements present only in the DS schema are left untouched.

    An X-ORIGIN tag containing the current IPA version is added to all new
    and updated schema elements.

    :param schema_files: List of filenames to update from
    :param ldapi: if true, use ldapi to connect
    :param dm_password: directory manager password

    :return:
        True if modifications were made
    """
    SCHEMA_ELEMENT_CLASSES_KEYS = [x[0] for x in SCHEMA_ELEMENT_CLASSES]

    conn = connect(ldapi=ldapi,
                   dm_password=dm_password,
                   realm=api.env.realm,
                   fqdn=installutils.get_fqdn())

    old_schema = conn.schema

    schema_entry = conn.get_entry(DN(('cn', 'schema')),
                                  SCHEMA_ELEMENT_CLASSES_KEYS)

    modified = False

    # The exact representation the DS gives us for each OID
    # (for debug logging)
    old_entries_by_oid = {
        cls(attr).oid: attr.decode('utf-8')
        for (attrname, cls) in SCHEMA_ELEMENT_CLASSES
        for attr in schema_entry[attrname]
    }

    for filename in schema_files:
        log.debug('Processing schema LDIF file %s', filename)
        url = "file://{}".format(filename)
        _dn, new_schema = ldap.schema.subentry.urlfetch(url)

        for attrname, cls in SCHEMA_ELEMENT_CLASSES:
            for oids_set in _get_oid_dependency_order(new_schema, cls):
                # Set of all elements of this class, as strings given by the DS
                new_elements = []
                for oid in oids_set:
                    new_obj = new_schema.get_obj(cls, oid)
                    old_obj = old_schema.get_obj(cls, oid)
                    # Compare python-ldap's sanitized string representations
                    # to see if the value is different
                    # This can give false positives, e.g. with case differences
                    # in case-insensitive names.
                    # But, false positives are harmless (and infrequent)
                    if not old_obj or str(new_obj) != str(old_obj):
                        # Note: An add will automatically replace any existing
                        # schema with the same OID. So, we only add.
                        value = add_x_origin(new_obj)

                        if old_obj:
                            old_attr = old_entries_by_oid.get(oid)
                            log.debug('Replace: %s', old_attr)
                            log.debug('   with: %s', value)
                        else:
                            log.debug('Add: %s', value)

                        new_elements.append(value.encode('utf-8'))

                modified = modified or new_elements
                schema_entry[attrname].extend(new_elements)
                # we need to iterate schema updates, due to dependencies (SUP)
                # schema_entry doesn't respect order of objectclasses/attributes
                # so updates must be executed with groups of independent OIDs
                if new_elements:
                    modlist = schema_entry.generate_modlist()
                    log.debug("Schema modlist:\n%s", pprint.pformat(modlist))
                    conn.update_entry(schema_entry)

    if not modified:
        log.debug('Not updating schema')

    return modified