def export_key(args, tmpdir): """Export cert and private from PEM files as PKCS#12 file. The PKCS#12 file is encrypted with a password. """ pk12file = os.path.join(tmpdir, 'export.p12') password = ipautil.ipa_generate_password() pk12pwfile = os.path.join(tmpdir, 'passwd') with open(pk12pwfile, 'w') as f: f.write(password) # OpenSSL does not support pkcs12 export of a cert without key ipautil.run([ paths.OPENSSL, 'pkcs12', '-export', '-in', args.certfile, '-out', pk12file, '-inkey', args.keyfile, '-password', 'file:{pk12pwfile}'.format(pk12pwfile=pk12pwfile), ]) with open(pk12file, 'rb') as f: p12data = f.read() data = { 'export password': password, 'pkcs12 data': p12data, } common.json_dump(data, args.exportfile)
def export_key(args, tmpdir): """Export key and certificate from the NSS DB to a PKCS#12 file. The PKCS#12 file is encrypted with a password. """ pk12file = os.path.join(tmpdir, 'export.p12') password = ipautil.ipa_generate_password() pk12pk12pwfile = os.path.join(tmpdir, 'passwd') with open(pk12pk12pwfile, 'w') as f: f.write(password) nssdb = NSSDatabase(args.nssdb_path) nssdb.run_pk12util([ "-o", pk12file, "-n", args.nickname, "-k", args.nssdb_pwdfile, "-w", pk12pk12pwfile, ]) with open(pk12file, 'rb') as f: p12data = f.read() data = { 'export password': password, 'pkcs12 data': p12data, } common.json_dump(data, args.exportfile)
def __setup_sub_dict(self): server_root = find_server_root() try: idrange_size = self.idmax - self.idstart + 1 except TypeError: idrange_size = None self.sub_dict = dict(FQDN=self.fqdn, SERVERID=self.serverid, PASSWORD=self.dm_password, RANDOM_PASSWORD=ipautil.ipa_generate_password(), SUFFIX=self.suffix, REALM=self.realm, USER=DS_USER, SERVER_ROOT=server_root, DOMAIN=self.domain, TIME=int(time.time()), IDSTART=self.idstart, IDMAX=self.idmax, HOST=self.fqdn, ESCAPED_SUFFIX=str(self.suffix), GROUP=DS_GROUP, IDRANGE_SIZE=idrange_size, DOMAIN_LEVEL=self.domainlevel, MAX_DOMAIN_LEVEL=constants.MAX_DOMAIN_LEVEL, MIN_DOMAIN_LEVEL=constants.MIN_DOMAIN_LEVEL, STRIP_ATTRS=" ".join(replication.STRIP_ATTRS), EXCLUDES='(objectclass=*) $ EXCLUDE ' + ' '.join(replication.EXCLUDES), TOTAL_EXCLUDES='(objectclass=*) $ EXCLUDE ' + ' '.join(replication.TOTAL_EXCLUDES), )
def migrate_to_mod_ssl(self): """For upgrades only, migrate from mod_nss to mod_ssl""" db = certs.CertDB(api.env.realm, nssdir=paths.HTTPD_ALIAS_DIR) nickname = self.get_mod_nss_nickname() with tempfile.NamedTemporaryFile() as temp: pk12_password = ipautil.ipa_generate_password() pk12_pwdfile = ipautil.write_tmp_file(pk12_password) db.export_pkcs12(temp.name, pk12_pwdfile.name, nickname) certs.install_pem_from_p12(temp.name, pk12_password, paths.HTTPD_CERT_FILE) certs.install_key_from_p12(temp.name, pk12_password, paths.HTTPD_KEY_FILE) self.backup_ssl_conf() self.configure_mod_ssl_certs() self.set_mod_ssl_protocol() self.set_mod_ssl_logdir() self.__add_include() self.cert = x509.load_certificate_from_file(paths.HTTPD_CERT_FILE) if self.ca_is_configured: db.untrack_server_cert(nickname) self.start_tracking_certificates() # remove nickname and CA certs from NSS db self.disable_nss_conf()
def __setup_sub_dict(self): server_root = find_server_root() try: idrange_size = self.idmax - self.idstart + 1 except TypeError: idrange_size = None self.sub_dict = dict( FQDN=self.fqdn, SERVERID=self.serverid, PASSWORD=self.dm_password, RANDOM_PASSWORD=ipautil.ipa_generate_password(), SUFFIX=self.suffix, REALM=self.realm, USER=DS_USER, SERVER_ROOT=server_root, DOMAIN=self.domain, TIME=int(time.time()), IDSTART=self.idstart, IDMAX=self.idmax, HOST=self.fqdn, ESCAPED_SUFFIX=str(self.suffix), GROUP=DS_GROUP, IDRANGE_SIZE=idrange_size, DOMAIN_LEVEL=self.domainlevel, MAX_DOMAIN_LEVEL=constants.MAX_DOMAIN_LEVEL, MIN_DOMAIN_LEVEL=constants.MIN_DOMAIN_LEVEL, STRIP_ATTRS=" ".join(replication.STRIP_ATTRS), EXCLUDES='(objectclass=*) $ EXCLUDE ' + ' '.join(replication.EXCLUDES), TOTAL_EXCLUDES='(objectclass=*) $ EXCLUDE ' + ' '.join(replication.TOTAL_EXCLUDES), )
def check_chain(self, pkcs12_filename, pkcs12_pin, nssdb): # create a temp nssdb with NSSDatabase() as tempnssdb: db_password = ipautil.ipa_generate_password() db_pwdfile = ipautil.write_tmp_file(db_password) tempnssdb.create_db(db_pwdfile.name) # import the PKCS12 file, then delete all CA certificates # this leaves only the server certs in the temp db tempnssdb.import_pkcs12( pkcs12_filename, db_pwdfile.name, pkcs12_pin) for nickname, flags in tempnssdb.list_certs(): if 'u' not in flags: while tempnssdb.has_nickname(nickname): tempnssdb.delete_cert(nickname) # import all the CA certs from nssdb into the temp db for nickname, flags in nssdb.list_certs(): if 'u' not in flags: cert = nssdb.get_cert_from_db(nickname) tempnssdb.add_cert(cert, nickname, flags) # now get the server certs from tempnssdb and check their validity try: for nick, flags in tempnssdb.find_server_certs(): tempnssdb.verify_server_cert_validity(nick, api.env.host) except ValueError as e: raise admintool.ScriptError( "Peer's certificate issuer is not trusted (%s). " "Please run ipa-cacert-manage install and ipa-certupdate " "to install the CA certificate." % str(e))
def export_key(self): tdir = tempfile.mkdtemp(dir=paths.TMP) try: pk12pwfile = os.path.join(tdir, 'pk12pwfile') password = ipautil.ipa_generate_password() with open(pk12pwfile, 'w') as f: f.write(password) pk12file = os.path.join(tdir, 'pk12file') nssdb = NSSDatabase(self.nssdb_path) nssdb.run_pk12util([ "-o", pk12file, "-n", self.nickname, "-k", self.nssdb_pwdfile, "-w", pk12pwfile, ]) with open(pk12file, 'rb') as f: data = f.read() finally: shutil.rmtree(tdir) return json_encode({ 'export password': password, 'pkcs12 data': b64encode(data).decode('ascii') })
def check_chain(self, pkcs12_filename, pkcs12_pin, nssdb): # create a temp nssdb with NSSDatabase() as tempnssdb: db_password = ipautil.ipa_generate_password() db_pwdfile = ipautil.write_tmp_file(db_password) tempnssdb.create_db(db_pwdfile.name) # import the PKCS12 file, then delete all CA certificates # this leaves only the server certs in the temp db tempnssdb.import_pkcs12(pkcs12_filename, db_pwdfile.name, pkcs12_pin) for nickname, flags in tempnssdb.list_certs(): if 'u' not in flags: while tempnssdb.has_nickname(nickname): tempnssdb.delete_cert(nickname) # import all the CA certs from nssdb into the temp db for nickname, flags in nssdb.list_certs(): if 'u' not in flags: cert = nssdb.get_cert_from_db(nickname) tempnssdb.add_cert(cert, nickname, flags) # now get the server certs from tempnssdb and check their validity try: for nick, flags in tempnssdb.find_server_certs(): tempnssdb.verify_server_cert_validity(nick, api.env.host) except ValueError as e: raise admintool.ScriptError( "Peer's certificate issuer is not trusted (%s). " "Please run ipa-cacert-manage install and ipa-certupdate " "to install the CA certificate." % str(e))
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) if options.get('rename') is not None: config = ldap.get_ipa_config()[1] if 'ipamaxusernamelength' in config: if len(options['rename']) > int(config.get('ipamaxusernamelength')[0]): raise errors.ValidationError( name=self.obj.primary_key.cli_name, error=_('can be at most %(len)d characters') % dict( len = int(config.get('ipamaxusernamelength')[0]) ) ) if 'mail' in entry_attrs: entry_attrs['mail'] = self.obj._normalize_and_validate_email(entry_attrs['mail']) if 'manager' in entry_attrs: entry_attrs['manager'] = self.obj._normalize_manager(entry_attrs['manager']) validate_nsaccountlock(entry_attrs) if 'userpassword' not in entry_attrs and options.get('random'): entry_attrs['userpassword'] = ipa_generate_password(user_pwdchars) # save the password so it can be displayed in post_callback setattr(context, 'randompassword', entry_attrs['userpassword']) if 'ipasshpubkey' in entry_attrs: if 'objectclass' in entry_attrs: obj_classes = entry_attrs['objectclass'] else: (_dn, _entry_attrs) = ldap.get_entry(dn, ['objectclass']) obj_classes = entry_attrs['objectclass'] = _entry_attrs['objectclass'] if 'ipasshuser' not in obj_classes: obj_classes.append('ipasshuser') return dn
def __init__(self, subsystem, fqdn, domain, subject_base, ca_subject, admin_user, admin_password, dm_password, pki_config_override=None): self.pki_config_override = pki_config_override self.defaults = dict( # pretty much static ipa_ca_pem_file=paths.IPA_CA_CRT, pki_configuration_path=paths.PKI_CONFIGURATION, # variable ipa_ca_subject=ca_subject, ipa_subject_base=subject_base, ipa_fqdn=fqdn, ipa_ocsp_uri="http://{}.{}/ca/ocsp".format( IPA_CA_RECORD, ipautil.format_netloc(domain)), ipa_admin_cert_p12=paths.DOGTAG_ADMIN_P12, ipa_admin_user=admin_user, pki_admin_password=admin_password, pki_ds_password=dm_password, # Dogtag's pkiparser defines these config vars by default: pki_dns_domainname=domain, pki_hostname=fqdn, pki_subsystem=subsystem.upper(), pki_subsystem_type=subsystem.lower(), home_dir=os.path.expanduser("~"), # for softhsm2 testing softhsm2_so=paths.LIBSOFTHSM2_SO, # Configure a more secure AJP password by default ipa_ajp_secret=ipautil.ipa_generate_password(special=None))
def load_external_cert(files, subject_base): """ Load and verify external CA certificate chain from multiple files. The files are accepted in PEM and DER certificate and PKCS#7 certificate chain formats. :param files: Names of files to import :param subject_base: Subject name base for IPA certificates :returns: Temporary file with the IPA CA certificate and temporary file with the external CA certificate chain """ with certs.NSSDatabase() as nssdb: db_password = ipautil.ipa_generate_password() db_pwdfile = ipautil.write_tmp_file(db_password) nssdb.create_db(db_pwdfile.name) try: nssdb.import_files(files, db_pwdfile.name) except RuntimeError as e: raise ScriptError(str(e)) ca_subject = DN(('CN', 'Certificate Authority'), subject_base) ca_nickname = None cache = {} for nickname, trust_flags in nssdb.list_certs(): cert = nssdb.get_cert(nickname, pem=True) nss_cert = x509.load_certificate(cert) subject = DN(str(nss_cert.subject)) issuer = DN(str(nss_cert.issuer)) del nss_cert cache[nickname] = (cert, subject, issuer) if subject == ca_subject: ca_nickname = nickname nssdb.trust_root_cert(nickname) if ca_nickname is None: raise ScriptError("IPA CA certificate not found in %s" % (", ".join(files))) trust_chain = reversed(nssdb.get_trust_chain(ca_nickname)) ca_cert_chain = [] for nickname in trust_chain: cert, subject, issuer = cache[nickname] ca_cert_chain.append(cert) if subject == issuer: break else: raise ScriptError("CA certificate chain in %s is incomplete" % (", ".join(files))) for nickname in trust_chain: try: nssdb.verify_ca_cert_validity(nickname) except ValueError, e: raise ScriptError("CA certificate %s in %s is not valid: %s" % (subject, ", ".join(files), e))
def create_passwd_file(self, passwd=None): ipautil.backup_file(self.passwd_fname) with open(self.passwd_fname, "w") as f: self.set_perms(f) if passwd is not None: f.write("%s\n" % passwd) else: f.write(ipautil.ipa_generate_password())
def secure_ajp_connector(self): """ Update AJP connector to use a password protection """ server_xml = lxml.etree.parse(paths.PKI_TOMCAT_SERVER_XML) doc = server_xml.getroot() # no AJP connector means no need to update anything connectors = doc.xpath('//Connector[@protocol="AJP/1.3"]') if len(connectors) == 0: return # AJP protocol is at version 1.3. Assume there is only one as # Dogtag only provisions one. connector = connectors[0] # Detect tomcat version and choose the right option name # pre-9.0.31.0 uses 'requiredSecret' # 9.0.31.0 or later uses 'secret' secretattr = 'requiredSecret' oldattr = 'requiredSecret' if self.__is_newer_tomcat_version('9.0.31.0'): secretattr = 'secret' rewrite = True if secretattr in connector.attrib: # secret is already in place # Perhaps, we need to synchronize it with Apache configuration self.ajp_secret = connector.attrib[secretattr] rewrite = False else: if oldattr in connector.attrib: # Sufficiently new Dogtag versions (10.9.0-a2) handle the # upgrade for us; we need only to ensure that we're not both # attempting to upgrade server.xml at the same time. # Hopefully this is guaranteed for us. self.ajp_secret = connector.attrib[oldattr] connector.attrib[secretattr] = self.ajp_secret del connector.attrib[oldattr] else: # Generate password, don't use special chars to not break XML. # # If we hit this case, pkispawn was run on an older Dogtag # version and we're stuck migrating, choosing a password # ourselves. Dogtag can't generate one randomly because a # Dogtag administrator might've configured AJP and might # not be using IPA. # # Newer Dogtag versions will generate a random password # during pkispawn. self.ajp_secret = ipautil.ipa_generate_password(special=None) connector.attrib[secretattr] = self.ajp_secret if rewrite: pent = pwd.getpwnam(constants.PKI_USER) with open(paths.PKI_TOMCAT_SERVER_XML, "wb") as fd: server_xml.write(fd, pretty_print=True, encoding="utf-8") os.fchmod(fd.fileno(), 0o660) os.fchown(fd.fileno(), pent.pw_uid, pent.pw_gid)
def create_db(self, user=None, group=None, mode=None, backup=False): """Create cert DB :param user: User owner the secdir :param group: Group owner of the secdir :param mode: Mode of the secdir :param backup: Backup the sedir files """ dirmode = 0o750 filemode = 0o640 pwdfilemode = 0o640 if mode is not None: dirmode = mode filemode = mode & 0o666 pwdfilemode = mode & 0o660 uid = -1 gid = -1 if user is not None: uid = pwd.getpwnam(user).pw_uid if group is not None: gid = grp.getgrnam(group).gr_gid if backup: for filename in NSS_FILES: path = os.path.join(self.secdir, filename) ipautil.backup_file(path) if not os.path.exists(self.secdir): os.makedirs(self.secdir, dirmode) if not os.path.exists(self.pwd_file): # Create the password file for this db with io.open(os.open(self.pwd_file, os.O_CREAT | os.O_WRONLY, pwdfilemode), 'w', closefd=True) as f: f.write(ipautil.ipa_generate_password()) f.flush() self.run_certutil(["-N", "-f", self.pwd_file]) # Finally fix up perms os.chown(self.secdir, uid, gid) os.chmod(self.secdir, dirmode) tasks.restore_context(self.secdir) for filename in NSS_FILES: path = os.path.join(self.secdir, filename) if os.path.exists(path): if uid != -1 or gid != -1: os.chown(path, uid, gid) if path == self.pwd_file: new_mode = pwdfilemode else: new_mode = filemode os.chmod(path, new_mode) tasks.restore_context(path)
def install(self): print("Installing CA certificate, please wait") options = self.options cert_filename = self.args[1] nss_cert = None try: try: nss_cert = x509.load_certificate_from_file(cert_filename) except IOError as e: raise admintool.ScriptError( "Can't open \"%s\": %s" % (cert_filename, e)) except (TypeError, NSPRError, ValueError) as e: raise admintool.ScriptError("Not a valid certificate: %s" % e) subject = nss_cert.subject cert = nss_cert.der_data finally: del nss_cert nickname = options.nickname or str(subject) ca_certs = certstore.get_ca_certs_nss(api.Backend.ldap2, api.env.basedn, api.env.realm, False) with certs.NSSDatabase() as tmpdb: pw = ipautil.write_tmp_file(ipautil.ipa_generate_password()) tmpdb.create_db(pw.name) tmpdb.add_cert(cert, nickname, 'C,,') for ca_cert, ca_nickname, ca_trust_flags in ca_certs: tmpdb.add_cert(ca_cert, ca_nickname, ca_trust_flags) try: tmpdb.verify_ca_cert_validity(nickname) except ValueError as e: raise admintool.ScriptError( "Not a valid CA certificate: %s (visit " "http://www.freeipa.org/page/Troubleshooting for " "troubleshooting guide)" % e) trust_flags = options.trust_flags if ((set(trust_flags) - set(',CPTcgpuw')) or len(trust_flags.split(',')) != 3): raise admintool.ScriptError("Invalid trust flags") try: certstore.put_ca_cert_nss( api.Backend.ldap2, api.env.basedn, cert, nickname, trust_flags) except ValueError as e: raise admintool.ScriptError( "Failed to install the certificate: %s" % e) print("CA certificate successfully installed")
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) if options.get('rename') is not None: config = ldap.get_ipa_config() if 'ipamaxusernamelength' in config: if len(options['rename']) > int( config.get('ipamaxusernamelength')[0]): raise errors.ValidationError( name=self.obj.primary_key.cli_name, error=_('can be at most %(len)d characters') % dict(len=int(config.get('ipamaxusernamelength')[0]))) if 'mail' in entry_attrs: entry_attrs['mail'] = self.obj.normalize_and_validate_email( entry_attrs['mail']) if 'manager' in entry_attrs: entry_attrs['manager'] = self.obj.normalize_manager( entry_attrs['manager'], self.obj.active_container_dn) validate_nsaccountlock(entry_attrs) if 'userpassword' not in entry_attrs and options.get('random'): entry_attrs['userpassword'] = ipa_generate_password( baseuser_pwdchars) # save the password so it can be displayed in post_callback setattr(context, 'randompassword', entry_attrs['userpassword']) if ('ipasshpubkey' in entry_attrs or 'ipauserauthtype' in entry_attrs or 'userclass' in entry_attrs or 'ipatokenradiusconfiglink' in entry_attrs): if 'objectclass' in entry_attrs: obj_classes = entry_attrs['objectclass'] else: _entry_attrs = ldap.get_entry(dn, ['objectclass']) obj_classes = entry_attrs['objectclass'] = _entry_attrs[ 'objectclass'] if 'ipasshpubkey' in entry_attrs and 'ipasshuser' not in obj_classes: obj_classes.append('ipasshuser') if 'ipauserauthtype' in entry_attrs and 'ipauserauthtypeclass' not in obj_classes: obj_classes.append('ipauserauthtypeclass') if 'userclass' in entry_attrs and 'ipauser' not in obj_classes: obj_classes.append('ipauser') if 'ipatokenradiusconfiglink' in entry_attrs: cl = entry_attrs['ipatokenradiusconfiglink'] if cl: if 'ipatokenradiusproxyuser' not in obj_classes: obj_classes.append('ipatokenradiusproxyuser') answer = self.api.Object['radiusproxy'].get_dn_if_exists( cl) entry_attrs['ipatokenradiusconfiglink'] = answer return dn
def install(self): print("Installing CA certificate, please wait") options = self.options cert_filename = self.args[1] nss_cert = None try: try: nss_cert = x509.load_certificate_from_file(cert_filename) except IOError as e: raise admintool.ScriptError("Can't open \"%s\": %s" % (cert_filename, e)) except (TypeError, NSPRError, ValueError) as e: raise admintool.ScriptError("Not a valid certificate: %s" % e) subject = nss_cert.subject cert = nss_cert.der_data finally: del nss_cert nickname = options.nickname or str(subject) ca_certs = certstore.get_ca_certs_nss(api.Backend.ldap2, api.env.basedn, api.env.realm, False) with certs.NSSDatabase() as tmpdb: pw = ipautil.write_tmp_file(ipautil.ipa_generate_password()) tmpdb.create_db(pw.name) tmpdb.add_cert(cert, nickname, 'C,,') for ca_cert, ca_nickname, ca_trust_flags in ca_certs: tmpdb.add_cert(ca_cert, ca_nickname, ca_trust_flags) try: tmpdb.verify_ca_cert_validity(nickname) except ValueError as e: raise admintool.ScriptError( "Not a valid CA certificate: %s (visit " "http://www.freeipa.org/page/Troubleshooting for " "troubleshooting guide)" % e) trust_flags = options.trust_flags if ((set(trust_flags) - set(',CPTcgpuw')) or len(trust_flags.split(',')) != 3): raise admintool.ScriptError("Invalid trust flags") try: certstore.put_ca_cert_nss(api.Backend.ldap2, api.env.basedn, cert, nickname, trust_flags) except ValueError as e: raise admintool.ScriptError( "Failed to install the certificate: %s" % e) print("CA certificate successfully installed")
def create_db(self, user=None, group=None, mode=None, backup=False): """Create cert DB :param user: User owner the secdir :param group: Group owner of the secdir :param mode: Mode of the secdir :param backup: Backup the sedir files """ dirmode = 0o750 filemode = 0o640 pwdfilemode = 0o640 if mode is not None: dirmode = mode filemode = mode & 0o666 pwdfilemode = mode & 0o660 uid = -1 gid = -1 if user is not None: uid = pwd.getpwnam(user).pw_uid if group is not None: gid = grp.getgrnam(group).gr_gid if backup: for filename in NSS_FILES: path = os.path.join(self.secdir, filename) ipautil.backup_file(path) if not os.path.exists(self.secdir): os.makedirs(self.secdir, dirmode) if not os.path.exists(self.pwd_file): # Create the password file for this db with io.open(os.open(self.pwd_file, os.O_CREAT | os.O_WRONLY, pwdfilemode), 'w', closefd=True) as f: f.write(ipautil.ipa_generate_password()) f.flush() self.run_certutil(["-N", "-f", self.pwd_file]) # Finally fix up perms os.chown(self.secdir, uid, gid) os.chmod(self.secdir, dirmode) for filename in NSS_FILES: path = os.path.join(self.secdir, filename) if os.path.exists(path): os.chown(path, uid, gid) if path == self.pwd_file: new_mode = pwdfilemode else: new_mode = filemode os.chmod(path, new_mode)
def migrate_to_mod_ssl(self): """For upgrades only, migrate from mod_nss to mod_ssl""" db = certs.CertDB(api.env.realm, nssdir=paths.HTTPD_ALIAS_DIR) nickname = self.get_mod_nss_nickname() with tempfile.NamedTemporaryFile() as temp: pk12_password = ipautil.ipa_generate_password() pk12_pwdfile = ipautil.write_tmp_file(pk12_password) db.export_pkcs12(temp.name, pk12_pwdfile.name, nickname) certs.install_pem_from_p12(temp.name, pk12_password, paths.HTTPD_CERT_FILE) passwd_fname = paths.HTTPD_PASSWD_FILE_FMT.format( host=api.env.host) with open(passwd_fname, 'wb') as passwd_file: os.fchmod(passwd_file.fileno(), 0o600) passwd_file.write( ipautil.ipa_generate_password().encode('utf-8')) certs.install_key_from_p12(temp.name, pk12_password, paths.HTTPD_KEY_FILE, out_passwd_fname=passwd_fname) self.backup_ssl_conf() self.configure_mod_ssl_certs() self.set_mod_ssl_protocol() self.set_mod_ssl_logdir() self.__add_include() self.cert = x509.load_certificate_from_file(paths.HTTPD_CERT_FILE) if self.ca_is_configured: db.untrack_server_cert(nickname) self.start_tracking_certificates() # remove nickname and CA certs from NSS db self.disable_nss_conf()
def setup_admin(self): self.admin_user = "******" % self.fqdn self.admin_password = ipautil.ipa_generate_password() self.admin_dn = _person_dn(self.admin_user) result = self.create_user( uid=self.admin_user, cn=self.admin_user, sn=self.admin_user, user_type='adminType', groups=self.admin_groups, force=True, ) if result is None: return None # something went wrong else: self.admin_password = result # Now wait until the other server gets replicated this data master_conn = ipaldap.LDAPClient.from_hostname_secure(self.master_host) logger.debug("Waiting %s seconds for %s to appear on %s", api.env.replication_wait_timeout, self.admin_dn, master_conn) deadline = time.time() + api.env.replication_wait_timeout while time.time() < deadline: time.sleep(1) try: master_conn.simple_bind(self.admin_dn, self.admin_password) except errors.ACIError: # user not replicated yet pass else: logger.debug("Successfully logged in as %s", self.admin_dn) break else: logger.error("Unable to log in as %s on %s", self.admin_dn, master_conn) logger.info("[hint] tune with replication_wait_timeout") raise errors.NotFound(reason="{} did not replicate to {}".format( self.admin_dn, master_conn)) # wait for group membership for group_dn in (_group_dn(group) for group in self.admin_groups): replication.wait_for_entry( master_conn, group_dn, timeout=api.env.replication_wait_timeout, attr='uniqueMember', attrvalue=self.admin_dn)
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) if options.get('ip_address') and dns_container_exists(ldap): parts = keys[-1].split('.') host = parts[0] domain = unicode('.'.join(parts[1:])) check_reverse = not options.get('no_reverse', False) add_records_for_host_validation('ip_address', DNSName(host), DNSName(domain).make_absolute(), options['ip_address'], check_forward=True, check_reverse=check_reverse) if not options.get('force', False) and not 'ip_address' in options: util.validate_host_dns(self.log, keys[-1]) if 'locality' in entry_attrs: entry_attrs['l'] = entry_attrs['locality'] entry_attrs['cn'] = keys[-1] entry_attrs['serverhostname'] = keys[-1].split('.', 1)[0] if not entry_attrs.get('userpassword', False) and not options.get('random', False): entry_attrs['krbprincipalname'] = 'host/%s@%s' % ( keys[-1], self.api.env.realm ) if 'krbprincipalaux' not in entry_attrs['objectclass']: entry_attrs['objectclass'].append('krbprincipalaux') if 'krbprincipal' not in entry_attrs['objectclass']: entry_attrs['objectclass'].append('krbprincipal') else: if 'krbprincipalaux' in entry_attrs['objectclass']: entry_attrs['objectclass'].remove('krbprincipalaux') if 'krbprincipal' in entry_attrs['objectclass']: entry_attrs['objectclass'].remove('krbprincipal') if options.get('random'): entry_attrs['userpassword'] = ipa_generate_password(characters=host_pwd_chars) # save the password so it can be displayed in post_callback setattr(context, 'randompassword', entry_attrs['userpassword']) certs = options.get('usercertificate', []) certs_der = map(x509.normalize_certificate, certs) for cert in certs_der: x509.verify_cert_subject(ldap, keys[-1], cert) entry_attrs['usercertificate'] = certs_der entry_attrs['managedby'] = dn entry_attrs['objectclass'].append('ieee802device') entry_attrs['objectclass'].append('ipasshhost') update_krbticketflags(ldap, entry_attrs, attrs_list, options, False) if 'krbticketflags' in entry_attrs: entry_attrs['objectclass'].append('krbticketpolicyaux') return dn
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) if options.get('ip_address') and dns_container_exists(ldap): parts = keys[-1].split('.') host = parts[0] domain = unicode('.'.join(parts[1:])) check_reverse = not options.get('no_reverse', False) add_records_for_host_validation('ip_address', DNSName(host), DNSName(domain).make_absolute(), options['ip_address'], check_forward=True, check_reverse=check_reverse) if not options.get('force', False) and not 'ip_address' in options: util.verify_host_resolvable(keys[-1], self.log) if 'locality' in entry_attrs: entry_attrs['l'] = entry_attrs['locality'] entry_attrs['cn'] = keys[-1] entry_attrs['serverhostname'] = keys[-1].split('.', 1)[0] if not entry_attrs.get('userpassword', False) and not options.get('random', False): entry_attrs['krbprincipalname'] = 'host/%s@%s' % ( keys[-1], self.api.env.realm ) if 'krbprincipalaux' not in entry_attrs['objectclass']: entry_attrs['objectclass'].append('krbprincipalaux') if 'krbprincipal' not in entry_attrs['objectclass']: entry_attrs['objectclass'].append('krbprincipal') else: if 'krbprincipalaux' in entry_attrs['objectclass']: entry_attrs['objectclass'].remove('krbprincipalaux') if 'krbprincipal' in entry_attrs['objectclass']: entry_attrs['objectclass'].remove('krbprincipal') if options.get('random'): entry_attrs['userpassword'] = ipa_generate_password(characters=host_pwd_chars) # save the password so it can be displayed in post_callback setattr(context, 'randompassword', entry_attrs['userpassword']) certs = options.get('usercertificate', []) certs_der = [x509.normalize_certificate(c) for c in certs] for cert in certs_der: x509.verify_cert_subject(ldap, keys[-1], cert) entry_attrs['usercertificate'] = certs_der entry_attrs['managedby'] = dn entry_attrs['objectclass'].append('ieee802device') entry_attrs['objectclass'].append('ipasshhost') update_krbticketflags(ldap, entry_attrs, attrs_list, options, False) if 'krbticketflags' in entry_attrs: entry_attrs['objectclass'].append('krbticketpolicyaux') return dn
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) if options.get('rename') is not None: config = ldap.get_ipa_config()[1] if 'ipamaxusernamelength' in config: if len(options['rename']) > int(config.get('ipamaxusernamelength')[0]): raise errors.ValidationError( name=self.obj.primary_key.cli_name, error=_('can be at most %(len)d characters') % dict( len = int(config.get('ipamaxusernamelength')[0]) ) ) if 'mail' in entry_attrs: entry_attrs['mail'] = self.obj._normalize_and_validate_email(entry_attrs['mail']) if 'manager' in entry_attrs: entry_attrs['manager'] = self.obj._normalize_manager(entry_attrs['manager']) validate_nsaccountlock(entry_attrs) if 'userpassword' not in entry_attrs and options.get('random'): entry_attrs['userpassword'] = ipa_generate_password(user_pwdchars) # save the password so it can be displayed in post_callback setattr(context, 'randompassword', entry_attrs['userpassword']) if ('ipasshpubkey' in entry_attrs or 'ipauserauthtype' in entry_attrs or 'userclass' in entry_attrs or 'ipatokenradiusconfiglink' in entry_attrs): if 'objectclass' in entry_attrs: obj_classes = entry_attrs['objectclass'] else: _entry_attrs = ldap.get_entry(dn, ['objectclass']) obj_classes = entry_attrs['objectclass'] = _entry_attrs['objectclass'] if 'ipasshpubkey' in entry_attrs and 'ipasshuser' not in obj_classes: obj_classes.append('ipasshuser') if 'ipauserauthtype' in entry_attrs and 'ipauserauthtypeclass' not in obj_classes: obj_classes.append('ipauserauthtypeclass') if 'userclass' in entry_attrs and 'ipauser' not in obj_classes: obj_classes.append('ipauser') if 'ipatokenradiusconfiglink' in entry_attrs: cl = entry_attrs['ipatokenradiusconfiglink'] if cl: if 'ipatokenradiusproxyuser' not in obj_classes: obj_classes.append('ipatokenradiusproxyuser') answer = self.api.Object['radiusproxy'].get_dn_if_exists(cl) entry_attrs['ipatokenradiusconfiglink'] = answer return dn
def create_ipa_nssdb(): db = NSSDatabase(paths.IPA_NSSDB_DIR) pwdfile = os.path.join(db.secdir, 'pwdfile.txt') ipautil.backup_file(pwdfile) ipautil.backup_file(os.path.join(db.secdir, 'cert8.db')) ipautil.backup_file(os.path.join(db.secdir, 'key3.db')) ipautil.backup_file(os.path.join(db.secdir, 'secmod.db')) with open(pwdfile, 'w') as f: f.write(ipautil.ipa_generate_password(pwd_len=40)) os.chmod(pwdfile, 0o600) db.create_db(pwdfile) os.chmod(os.path.join(db.secdir, 'cert8.db'), 0o644) os.chmod(os.path.join(db.secdir, 'key3.db'), 0o644) os.chmod(os.path.join(db.secdir, 'secmod.db'), 0o644)
def secure_ajp_connector(self): """ Update AJP connector to use a password protection """ server_xml = lxml.etree.parse(paths.PKI_TOMCAT_SERVER_XML) doc = server_xml.getroot() # no AJP connector means no need to update anything connectors = doc.xpath('//Connector[@port="8009"]') if len(connectors) == 0: return # AJP connector is set on port 8009. Use non-greedy search to find it connector = connectors[0] # Detect tomcat version and choose the right option name # pre-9.0.31.0 uses 'requiredSecret' # 9.0.31.0 or later uses 'secret' secretattr = 'requiredSecret' oldattr = 'requiredSecret' if self.__is_newer_tomcat_version('9.0.31.0'): secretattr = 'secret' rewrite = True if secretattr in connector.attrib: # secret is already in place # Perhaps, we need to synchronize it with Apache configuration self.ajp_secret = connector.attrib[secretattr] rewrite = False else: if oldattr in connector.attrib: self.ajp_secret = connector.attrib[oldattr] connector.attrib[secretattr] = self.ajp_secret del connector.attrib[oldattr] else: # Generate password, don't use special chars to not break XML self.ajp_secret = ipautil.ipa_generate_password(special=None) connector.attrib[secretattr] = self.ajp_secret if rewrite: pent = pwd.getpwnam(constants.PKI_USER) with open(paths.PKI_TOMCAT_SERVER_XML, "wb") as fd: server_xml.write(fd, pretty_print=True, encoding="utf-8") os.fchmod(fd.fileno(), 0o660) os.fchown(fd.fileno(), pent.pw_uid, pent.pw_gid)
def __common_setup(self, realm_name, host_name, domain_name, admin_password): self.fqdn = host_name self.realm = realm_name.upper() self.host = host_name.split(".")[0] self.ip = socket.getaddrinfo(host_name, None, socket.AF_UNSPEC, socket.SOCK_STREAM)[0][4][0] self.domain = domain_name self.suffix = ipautil.realm_to_suffix(self.realm) self.kdc_password = ipautil.ipa_generate_password() self.admin_password = admin_password self.dm_password = admin_password self.__setup_sub_dict() self.backup_state("running", self.is_running()) try: self.stop() except Exception: # It could have been not running pass
def install_check(api, replica_config, options): if replica_config is not None and not replica_config.setup_kra: return kra = krainstance.KRAInstance(api.env.realm) if kra.is_installed(): raise RuntimeError("KRA is already installed.") if not options.setup_ca: if cainstance.is_ca_installed_locally(): if api.env.dogtag_version >= 10: # correct dogtag version of CA installed pass else: raise RuntimeError( "Dogtag must be version 10.2 or above to install KRA") else: raise RuntimeError( "Dogtag CA is not installed. Please install the CA first") if replica_config is not None: if not api.Command.kra_is_enabled()['result']: raise RuntimeError( "KRA is not installed on the master system. Please use " "'ipa-kra-install' command to install the first instance.") if options.promote: return with certdb.NSSDatabase() as tmpdb: pw = ipautil.write_tmp_file(ipautil.ipa_generate_password()) tmpdb.create_db(pw.name) tmpdb.import_pkcs12(replica_config.dir + "/cacert.p12", pw.name, replica_config.dirman_password) kra_cert_nicknames = [ "storageCert cert-pki-kra", "transportCert cert-pki-kra", "auditSigningCert cert-pki-kra" ] if not all( tmpdb.has_nickname(nickname) for nickname in kra_cert_nicknames): raise RuntimeError("Missing KRA certificates, please create a " "new replica file.")
def install_check(api, replica_config, options): if replica_config is not None and not replica_config.setup_kra: return kra = krainstance.KRAInstance(api.env.realm) if kra.is_installed(): raise RuntimeError("KRA is already installed.") if not options.setup_ca: if cainstance.is_ca_installed_locally(): if api.env.dogtag_version >= 10: # correct dogtag version of CA installed pass else: raise RuntimeError( "Dogtag must be version 10.2 or above to install KRA") else: raise RuntimeError( "Dogtag CA is not installed. Please install the CA first") if replica_config is not None: if not api.Command.kra_is_enabled()['result']: raise RuntimeError( "KRA is not installed on the master system. Please use " "'ipa-kra-install' command to install the first instance.") if options.promote: return with certdb.NSSDatabase() as tmpdb: pw = ipautil.write_tmp_file(ipautil.ipa_generate_password()) tmpdb.create_db(pw.name) tmpdb.import_pkcs12(replica_config.dir + "/cacert.p12", pw.name, replica_config.dirman_password) kra_cert_nicknames = [ "storageCert cert-pki-kra", "transportCert cert-pki-kra", "auditSigningCert cert-pki-kra" ] if not all(tmpdb.has_nickname(nickname) for nickname in kra_cert_nicknames): raise RuntimeError("Missing KRA certificates, please create a " "new replica file.")
def export_key(self): _fd, tmpfile = tempfile.mkstemp(dir=paths.TMP) password = ipautil.ipa_generate_password() args = [ paths.OPENSSL, "pkcs12", "-export", "-in", self.certfile, "-out", tmpfile, "-password", "pass:{pwd}".format(pwd=password) ] if self.keyfile is not None: args.extend(["-inkey", self.keyfile]) try: ipautil.run(args, nolog=(password, )) with open(tmpfile, 'rb') as f: data = f.read() finally: os.remove(tmpfile) return json_encode({ 'export password': password, 'pkcs12 data': b64encode(data).decode('ascii') })
def export_key(self): tdir = tempfile.mkdtemp(dir=paths.TMP) try: pk12pwfile = os.path.join(tdir, 'pk12pwfile') password = ipautil.ipa_generate_password() with open(pk12pwfile, 'w') as f: f.write(password) pk12file = os.path.join(tdir, 'pk12file') nssdb = NSSDatabase(self.nssdb_path) nssdb.run_pk12util([ "-o", pk12file, "-n", self.nickname, "-k", self.nssdb_pwdfile, "-w", pk12pwfile, ]) with open(pk12file, 'rb') as f: data = f.read() finally: shutil.rmtree(tdir) return json_encode({'export password': password, 'pkcs12 data': b64encode(data).decode('ascii')})
def export_key(self): _fd, tmpfile = tempfile.mkstemp(dir=paths.TMP) password = ipautil.ipa_generate_password() args = [ paths.OPENSSL, "pkcs12", "-export", "-in", self.certfile, "-out", tmpfile, "-password", "pass:{pwd}".format(pwd=password) ] if self.keyfile is not None: args.extend(["-inkey", self.keyfile]) try: ipautil.run(args, nolog=(password, )) with open(tmpfile, 'r') as f: data = f.read() finally: os.remove(tmpfile) return json_encode({'export password': password, 'pkcs12 data': b64encode(data)})
def export_key(self): tdir = tempfile.mkdtemp(dir=paths.TMP) try: nsspwfile = os.path.join(tdir, 'nsspwfile') with open(nsspwfile, 'w+') as f: f.write(self.nssdb_password) pk12pwfile = os.path.join(tdir, 'pk12pwfile') password = ipautil.ipa_generate_password() with open(pk12pwfile, 'w+') as f: f.write(password) pk12file = os.path.join(tdir, 'pk12file') ipautil.run([ paths.PK12UTIL, "-d", self.nssdb_path, "-o", pk12file, "-n", self.nickname, "-k", nsspwfile, "-w", pk12pwfile ]) with open(pk12file, 'r') as f: data = f.read() finally: shutil.rmtree(tdir) return json_encode({ 'export password': password, 'pkcs12 data': b64encode(data) })
def export_key(self): tdir = tempfile.mkdtemp(dir=paths.TMP) try: nsspwfile = os.path.join(tdir, 'nsspwfile') with open(nsspwfile, 'w+') as f: f.write(self.nssdb_password) pk12pwfile = os.path.join(tdir, 'pk12pwfile') password = ipautil.ipa_generate_password() with open(pk12pwfile, 'w+') as f: f.write(password) pk12file = os.path.join(tdir, 'pk12file') ipautil.run([paths.PK12UTIL, "-d", self.nssdb_path, "-o", pk12file, "-n", self.nickname, "-k", nsspwfile, "-w", pk12pwfile]) with open(pk12file, 'r') as f: data = f.read() finally: shutil.rmtree(tdir) return json_encode({'export password': password, 'pkcs12 data': b64encode(data)})
def setup_admin(self): self.admin_user = "******" % self.fqdn self.admin_password = ipautil.ipa_generate_password() self.admin_dn = DN(('uid', self.admin_user), ('ou', 'people'), ('o', 'ipaca')) # remove user if left-over exists try: entry = api.Backend.ldap2.delete_entry(self.admin_dn) except errors.NotFound: pass # add user entry = api.Backend.ldap2.make_entry( self.admin_dn, objectclass=[ "top", "person", "organizationalPerson", "inetOrgPerson", "cmsuser" ], uid=[self.admin_user], cn=[self.admin_user], sn=[self.admin_user], usertype=['adminType'], mail=['root@localhost'], userPassword=[self.admin_password], userstate=['1']) api.Backend.ldap2.add_entry(entry) for group in self.admin_groups: self.__add_admin_to_group(group) # Now wait until the other server gets replicated this data ldap_uri = ipaldap.get_ldap_uri(self.master_host) master_conn = ipaldap.LDAPClient(ldap_uri) master_conn.gssapi_bind() replication.wait_for_entry(master_conn, entry.dn) del master_conn
def setup_admin(self): self.admin_user = "******" % self.fqdn self.admin_password = ipautil.ipa_generate_password() self.admin_dn = DN(('uid', self.admin_user), ('ou', 'people'), ('o', 'ipaca')) # remove user if left-over exists try: entry = api.Backend.ldap2.delete_entry(self.admin_dn) except errors.NotFound: pass # add user entry = api.Backend.ldap2.make_entry( self.admin_dn, objectclass=["top", "person", "organizationalPerson", "inetOrgPerson", "cmsuser"], uid=[self.admin_user], cn=[self.admin_user], sn=[self.admin_user], usertype=['adminType'], mail=['root@localhost'], userPassword=[self.admin_password], userstate=['1'] ) api.Backend.ldap2.add_entry(entry) for group in self.admin_groups: self.__add_admin_to_group(group) # Now wait until the other server gets replicated this data ldap_uri = ipaldap.get_ldap_uri(self.master_host) master_conn = ipaldap.LDAPClient(ldap_uri) master_conn.gssapi_bind() replication.wait_for_entry(master_conn, entry.dn) del master_conn
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
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
def create_noise_file(self): if ipautil.file_exists(self.noise_fname): os.remove(self.noise_fname) with open(self.noise_fname, "w") as f: self.set_perms(f) f.write(ipautil.ipa_generate_password())
def __setup_softhsm(self): assert self.ods_uid is not None assert self.named_gid is not None token_dir_exists = os.path.exists(paths.DNSSEC_TOKENS_DIR) # create dnssec directory if not os.path.exists(paths.IPA_DNSSEC_DIR): self.logger.debug("Creating %s directory", paths.IPA_DNSSEC_DIR) os.mkdir(paths.IPA_DNSSEC_DIR) os.chmod(paths.IPA_DNSSEC_DIR, 0o770) # chown ods:named os.chown(paths.IPA_DNSSEC_DIR, self.ods_uid, self.named_gid) # setup softhsm2 config file softhsm_conf_txt = ("# SoftHSM v2 configuration file \n" "# File generated by IPA instalation\n" "directories.tokendir = %(tokens_dir)s\n" "objectstore.backend = file") % { 'tokens_dir': paths.DNSSEC_TOKENS_DIR } self.logger.debug("Creating new softhsm config file") named_fd = open(paths.DNSSEC_SOFTHSM2_CONF, 'w') named_fd.seek(0) named_fd.truncate(0) named_fd.write(softhsm_conf_txt) named_fd.close() os.chmod(paths.DNSSEC_SOFTHSM2_CONF, 0o644) # setting up named to use softhsm2 if not self.fstore.has_file(paths.SYSCONFIG_NAMED): self.fstore.backup_file(paths.SYSCONFIG_NAMED) # setting up named and ipa-dnskeysyncd to use our softhsm2 config for sysconfig in [paths.SYSCONFIG_NAMED, paths.SYSCONFIG_IPA_DNSKEYSYNCD]: installutils.set_directive(sysconfig, 'SOFTHSM2_CONF', paths.DNSSEC_SOFTHSM2_CONF, quotes=False, separator='=') if (token_dir_exists and os.path.exists(paths.DNSSEC_SOFTHSM_PIN) and os.path.exists(paths.DNSSEC_SOFTHSM_PIN_SO)): # there is initialized softhsm return # remove old tokens if token_dir_exists: self.logger.debug('Removing old tokens directory %s', paths.DNSSEC_TOKENS_DIR) shutil.rmtree(paths.DNSSEC_TOKENS_DIR) # create tokens subdirectory self.logger.debug('Creating tokens %s directory', paths.DNSSEC_TOKENS_DIR) # sticky bit is required by daemon os.mkdir(paths.DNSSEC_TOKENS_DIR) os.chmod(paths.DNSSEC_TOKENS_DIR, 0o770 | stat.S_ISGID) # chown to ods:named os.chown(paths.DNSSEC_TOKENS_DIR, self.ods_uid, self.named_gid) # generate PINs for softhsm allowed_chars = u'123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' pin_length = 30 # Bind allows max 32 bytes including ending '\0' pin = ipautil.ipa_generate_password(allowed_chars, pin_length) pin_so = ipautil.ipa_generate_password(allowed_chars, pin_length) self.logger.debug("Saving user PIN to %s", paths.DNSSEC_SOFTHSM_PIN) named_fd = open(paths.DNSSEC_SOFTHSM_PIN, 'w') named_fd.seek(0) named_fd.truncate(0) named_fd.write(pin) named_fd.close() os.chmod(paths.DNSSEC_SOFTHSM_PIN, 0o770) # chown to ods:named os.chown(paths.DNSSEC_SOFTHSM_PIN, self.ods_uid, self.named_gid) self.logger.debug("Saving SO PIN to %s", paths.DNSSEC_SOFTHSM_PIN_SO) named_fd = open(paths.DNSSEC_SOFTHSM_PIN_SO, 'w') named_fd.seek(0) named_fd.truncate(0) named_fd.write(pin_so) named_fd.close() # owner must be root os.chmod(paths.DNSSEC_SOFTHSM_PIN_SO, 0o400) # initialize SoftHSM command = [ paths.SOFTHSM2_UTIL, '--init-token', '--slot', str(softhsm_slot), '--label', softhsm_token_label, '--pin', pin, '--so-pin', pin_so, ] self.logger.debug("Initializing tokens") os.environ["SOFTHSM2_CONF"] = paths.DNSSEC_SOFTHSM2_CONF ipautil.run(command, nolog=(pin, pin_so,))
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
def check_userpassword(self, entry_attrs, **options): if 'userpassword' not in entry_attrs and options.get('random'): entry_attrs['userpassword'] = ipa_generate_password( entropy_bits=TMP_PWD_ENTROPY_BITS) # save the password so it can be displayed in post_callback setattr(context, 'randompassword', entry_attrs['userpassword'])
def create_db(self, user=None, group=None, mode=None, backup=False): """Create cert DB :param user: User owner the secdir :param group: Group owner of the secdir :param mode: Mode of the secdir :param backup: Backup the sedir files """ if mode is not None: dirmode = mode filemode = mode & 0o666 pwdfilemode = mode & 0o660 else: dirmode = 0o750 filemode = 0o640 pwdfilemode = 0o640 uid = -1 gid = -1 if user is not None: uid = pwd.getpwnam(user).pw_uid if group is not None: gid = grp.getgrnam(group).gr_gid if backup: for filename in self.backup_filenames: ipautil.backup_file(filename) if not os.path.exists(self.secdir): os.makedirs(self.secdir, dirmode) if not os.path.exists(self.pwd_file): # Create the password file for this db with io.open(os.open(self.pwd_file, os.O_CREAT | os.O_WRONLY, pwdfilemode), 'w', closefd=True) as f: f.write(ipautil.ipa_generate_password()) # flush and sync tempfile inode f.flush() os.fsync(f.fileno()) # In case dbtype is auto, let certutil decide which type of DB # to create. if self.dbtype == 'auto': dbdir = self.secdir else: dbdir = '{}:{}'.format(self.dbtype, self.secdir) args = [ paths.CERTUTIL, '-d', dbdir, '-N', '-f', self.pwd_file, # -@ in case it's an old db and it must be migrated '-@', self.pwd_file, ] ipautil.run(args, stdin=None, cwd=self.secdir) self._set_filenames(self._detect_dbtype()) if self.filenames is None: # something went wrong... raise ValueError( "Failed to create NSSDB at '{}'".format(self.secdir) ) # Finally fix up perms os.chown(self.secdir, uid, gid) os.chmod(self.secdir, dirmode) tasks.restore_context(self.secdir, force=True) for filename in self.filenames: if os.path.exists(filename): os.chown(filename, uid, gid) if filename == self.pwd_file: new_mode = pwdfilemode else: new_mode = filemode os.chmod(filename, new_mode) tasks.restore_context(filename, force=True)
def import_files(self, files, import_keys=False, key_password=None, key_nickname=None): """ Import certificates and a single private key from multiple files The files may be in PEM and DER certificate, PKCS#7 certificate chain, PKCS#8 and raw private key and PKCS#12 formats. :param files: Names of files to import :param import_keys: Whether to import private keys :param key_password: Password to decrypt private keys :param key_nickname: Nickname of the private key to import from PKCS#12 files """ key_file = None extracted_key = None extracted_certs = [] for filename in files: try: with open(filename, 'rb') as f: data = f.read() except IOError as e: raise RuntimeError( "Failed to open %s: %s" % (filename, e.strerror)) # Try to parse the file as PEM file matches = list( re.finditer( br'-----BEGIN (.+?)-----(.*?)-----END \1-----', data, re.DOTALL ) ) if matches: loaded = False for match in matches: body = match.group() label = match.group(1) line = len(data[:match.start() + 1].splitlines()) if label in (b'CERTIFICATE', b'X509 CERTIFICATE', b'X.509 CERTIFICATE'): try: cert = x509.load_pem_x509_certificate(body) except ValueError as e: if label != b'CERTIFICATE': logger.warning( "Skipping certificate in %s at line %s: " "%s", filename, line, e) continue else: extracted_certs.append(cert) loaded = True continue if label in (b'PKCS7', b'PKCS #7 SIGNED DATA', b'CERTIFICATE'): try: certs = x509.pkcs7_to_certs(body) except ipautil.CalledProcessError as e: if label == b'CERTIFICATE': logger.warning( "Skipping certificate in %s at line %s: " "%s", filename, line, e) else: logger.warning( "Skipping PKCS#7 in %s at line %s: %s", filename, line, e) continue else: extracted_certs.extend(certs) loaded = True continue if label in (b'PRIVATE KEY', b'ENCRYPTED PRIVATE KEY', b'RSA PRIVATE KEY', b'DSA PRIVATE KEY', b'EC PRIVATE KEY'): if not import_keys: continue if key_file: raise RuntimeError( "Can't load private key from both %s and %s" % (key_file, filename)) # the args -v2 aes256 -v2prf hmacWithSHA256 are needed # on OpenSSL 1.0.2 (fips mode). As soon as FreeIPA # requires OpenSSL 1.1.0 we'll be able to drop them args = [ paths.OPENSSL, 'pkcs8', '-topk8', '-v2', 'aes256', '-v2prf', 'hmacWithSHA256', '-passout', 'file:' + self.pwd_file, ] if ((label != b'PRIVATE KEY' and key_password) or label == b'ENCRYPTED PRIVATE KEY'): key_pwdfile = ipautil.write_tmp_file(key_password) args += [ '-passin', 'file:' + key_pwdfile.name, ] try: result = ipautil.run( args, stdin=body, capture_output=True) except ipautil.CalledProcessError as e: logger.warning( "Skipping private key in %s at line %s: %s", filename, line, e) continue else: extracted_key = result.raw_output key_file = filename loaded = True continue if loaded: continue raise RuntimeError("Failed to load %s" % filename) # Try to load the file as DER certificate try: cert = x509.load_der_x509_certificate(data) except ValueError: pass else: extracted_certs.append(cert) continue # Try to import the file as PKCS#12 file if import_keys: try: self.import_pkcs12(filename, key_password) except Pkcs12ImportUnknownError: # the file may not be a PKCS#12 file, # go to the generic error about unrecognized format pass except RuntimeError as e: raise RuntimeError("Failed to load %s: %s" % (filename, str(e))) else: if key_file: raise RuntimeError( "Can't load private key from both %s and %s" % (key_file, filename)) key_file = filename server_certs = self.find_server_certs() if key_nickname: for nickname, _trust_flags in server_certs: if nickname == key_nickname: break else: raise RuntimeError( "Server certificate \"%s\" not found in %s" % (key_nickname, filename)) else: if len(server_certs) > 1: raise RuntimeError( "%s server certificates found in %s, " "expecting only one" % (len(server_certs), filename)) continue # Supported formats were tried but none succeeded raise RuntimeError("Failed to load %s: unrecognized format" % filename) if import_keys and not key_file: raise RuntimeError( "No server certificates found in %s" % (', '.join(files))) for cert in extracted_certs: nickname = str(DN(cert.subject)) self.add_cert(cert, nickname, EMPTY_TRUST_FLAGS) if extracted_key: with tempfile.NamedTemporaryFile() as in_file, \ tempfile.NamedTemporaryFile() as out_file: for cert in extracted_certs: in_file.write(cert.public_bytes(x509.Encoding.PEM)) in_file.write(extracted_key) in_file.flush() out_password = ipautil.ipa_generate_password() out_pwdfile = ipautil.write_tmp_file(out_password) args = [ paths.OPENSSL, 'pkcs12', '-export', '-in', in_file.name, '-out', out_file.name, '-passin', 'file:' + self.pwd_file, '-passout', 'file:' + out_pwdfile.name, '-certpbe', 'aes-128-cbc', '-keypbe', 'aes-128-cbc', ] try: ipautil.run(args) except ipautil.CalledProcessError as e: raise RuntimeError( "No matching certificate found for private key from " "%s" % key_file) self.import_pkcs12(out_file.name, out_password)
def __spawn_instance(self): """ Create and configure a new KRA instance using pkispawn. Creates a configuration file with IPA-specific parameters and passes it to the base class to call pkispawn """ # Create an empty and secured file (cfg_fd, cfg_file) = tempfile.mkstemp() os.close(cfg_fd) pent = pwd.getpwnam(self.service_user) os.chown(cfg_file, pent.pw_uid, pent.pw_gid) self.tmp_agent_db = tempfile.mkdtemp(prefix="tmp-", dir=paths.VAR_LIB_IPA) tmp_agent_pwd = ipautil.ipa_generate_password() # Create a temporary file for the admin PKCS #12 file (admin_p12_fd, admin_p12_file) = tempfile.mkstemp() os.close(admin_p12_fd) # Create KRA configuration config = RawConfigParser() config.optionxform = str config.add_section("KRA") # Security Domain Authentication config.set("KRA", "pki_security_domain_https_port", "443") config.set("KRA", "pki_security_domain_password", self.admin_password) config.set("KRA", "pki_security_domain_user", self.admin_user) # issuing ca config.set("KRA", "pki_issuing_ca_uri", "https://%s" % ipautil.format_netloc(self.fqdn, 443)) # Server config.set("KRA", "pki_enable_proxy", "True") config.set("KRA", "pki_restart_configured_instance", "False") config.set("KRA", "pki_backup_keys", "True") config.set("KRA", "pki_backup_password", self.admin_password) # Client security database config.set("KRA", "pki_client_database_dir", self.tmp_agent_db) config.set("KRA", "pki_client_database_password", tmp_agent_pwd) config.set("KRA", "pki_client_database_purge", "True") config.set("KRA", "pki_client_pkcs12_password", self.admin_password) # Administrator config.set("KRA", "pki_admin_name", self.admin_user) config.set("KRA", "pki_admin_uid", self.admin_user) config.set("KRA", "pki_admin_email", "root@localhost") config.set("KRA", "pki_admin_password", self.admin_password) config.set("KRA", "pki_admin_nickname", "ipa-ca-agent") config.set("KRA", "pki_admin_subject_dn", str(DN(('cn', 'ipa-ca-agent'), self.subject_base))) config.set("KRA", "pki_import_admin_cert", "False") config.set("KRA", "pki_client_admin_cert_p12", admin_p12_file) # Directory server config.set("KRA", "pki_ds_ldap_port", "389") config.set("KRA", "pki_ds_password", self.dm_password) config.set("KRA", "pki_ds_base_dn", str(self.basedn)) config.set("KRA", "pki_ds_database", "ipaca") config.set("KRA", "pki_ds_create_new_db", "False") self._use_ldaps_during_spawn(config) # Certificate subject DNs config.set("KRA", "pki_subsystem_subject_dn", str(DN(('cn', 'CA Subsystem'), self.subject_base))) config.set("KRA", "pki_sslserver_subject_dn", str(DN(('cn', self.fqdn), self.subject_base))) config.set("KRA", "pki_audit_signing_subject_dn", str(DN(('cn', 'KRA Audit'), self.subject_base))) config.set( "KRA", "pki_transport_subject_dn", str(DN(('cn', 'KRA Transport Certificate'), self.subject_base))) config.set( "KRA", "pki_storage_subject_dn", str(DN(('cn', 'KRA Storage Certificate'), self.subject_base))) # Certificate nicknames # Note that both the server certs and subsystem certs reuse # the ca certs. config.set("KRA", "pki_subsystem_nickname", "subsystemCert cert-pki-ca") config.set("KRA", "pki_sslserver_nickname", "Server-Cert cert-pki-ca") config.set("KRA", "pki_audit_signing_nickname", "auditSigningCert cert-pki-kra") config.set("KRA", "pki_transport_nickname", "transportCert cert-pki-kra") config.set("KRA", "pki_storage_nickname", "storageCert cert-pki-kra") # Shared db settings # Needed because CA and KRA share the same database # We will use the dbuser created for the CA config.set("KRA", "pki_share_db", "True") config.set( "KRA", "pki_share_dbuser_dn", str(DN(('uid', 'pkidbuser'), ('ou', 'people'), ('o', 'ipaca')))) if not (os.path.isdir(paths.PKI_TOMCAT_ALIAS_DIR) and os.path.isfile(paths.PKI_TOMCAT_PASSWORD_CONF)): # generate pin which we know can be used for FIPS NSS database pki_pin = ipautil.ipa_generate_password() config.set("KRA", "pki_pin", pki_pin) else: pki_pin = None _p12_tmpfile_handle, p12_tmpfile_name = tempfile.mkstemp(dir=paths.TMP) if self.clone: krafile = self.pkcs12_info[0] shutil.copy(krafile, p12_tmpfile_name) pent = pwd.getpwnam(self.service_user) os.chown(p12_tmpfile_name, pent.pw_uid, pent.pw_gid) # Security domain registration config.set("KRA", "pki_security_domain_hostname", self.fqdn) config.set("KRA", "pki_security_domain_https_port", "443") config.set("KRA", "pki_security_domain_user", self.admin_user) config.set("KRA", "pki_security_domain_password", self.admin_password) # Clone config.set("KRA", "pki_clone", "True") config.set("KRA", "pki_clone_pkcs12_path", p12_tmpfile_name) config.set("KRA", "pki_clone_pkcs12_password", self.dm_password) config.set("KRA", "pki_clone_setup_replication", "False") config.set( "KRA", "pki_clone_uri", "https://%s" % ipautil.format_netloc(self.master_host, 443)) else: # the admin cert file is needed for the first instance of KRA cert = self.get_admin_cert() # First make sure that the directory exists parentdir = os.path.dirname(paths.ADMIN_CERT_PATH) if not os.path.exists(parentdir): os.makedirs(parentdir) with open(paths.ADMIN_CERT_PATH, "wb") as admin_path: admin_path.write( base64.b64encode(cert.public_bytes(x509.Encoding.DER))) # Generate configuration file with open(cfg_file, "w") as f: config.write(f) try: DogtagInstance.spawn_instance(self, cfg_file, nolog_list=(self.dm_password, self.admin_password, pki_pin, tmp_agent_pwd)) finally: os.remove(p12_tmpfile_name) os.remove(cfg_file) os.remove(admin_p12_file) shutil.move(paths.KRA_BACKUP_KEYS_P12, paths.KRACERT_P12) logger.debug("completed creating KRA instance")
if (options.http_cert_files and options.dirsrv_cert_files and http_ca_cert != dirsrv_ca_cert): sys.exit("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: sys.exit("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: sys.exit("IPA admin password required") else: admin_password = options.admin_password if setup_kra: try: kra.install_check(None, options, False, dogtag.install_constants.DOGTAG_VERSION) except RuntimeError as e:
def generate_random(self): return ipautil.ipa_generate_password()
def renew_external_step_2(self, ca, old_cert): print("Importing the renewed CA certificate, please wait") options = self.options conn = api.Backend.ldap2 cert_file, ca_file = installutils.load_external_cert( options.external_cert_files, x509.subject_base()) nss_cert = None nss.nss_init(paths.PKI_TOMCAT_ALIAS_DIR) try: nss_cert = x509.load_certificate(old_cert, x509.DER) subject = nss_cert.subject der_subject = x509.get_der_subject(old_cert, x509.DER) #pylint: disable=E1101 pkinfo = nss_cert.subject_public_key_info.format() #pylint: enable=E1101 nss_cert = x509.load_certificate_from_file(cert_file.name) cert = nss_cert.der_data if nss_cert.subject != subject: raise admintool.ScriptError( "Subject name mismatch (visit " "http://www.freeipa.org/page/Troubleshooting for " "troubleshooting guide)") if x509.get_der_subject(cert, x509.DER) != der_subject: raise admintool.ScriptError( "Subject name encoding mismatch (visit " "http://www.freeipa.org/page/Troubleshooting for " "troubleshooting guide)") #pylint: disable=E1101 if nss_cert.subject_public_key_info.format() != pkinfo: raise admintool.ScriptError( "Subject public key info mismatch (visit " "http://www.freeipa.org/page/Troubleshooting for " "troubleshooting guide)") #pylint: enable=E1101 finally: del nss_cert nss.nss_shutdown() with certs.NSSDatabase() as tmpdb: pw = ipautil.write_tmp_file(ipautil.ipa_generate_password()) tmpdb.create_db(pw.name) tmpdb.add_cert(old_cert, 'IPA CA', 'C,,') try: tmpdb.add_cert(cert, 'IPA CA', 'C,,') except ipautil.CalledProcessError as e: raise admintool.ScriptError( "Not compatible with the current CA certificate: %s" % e) ca_certs = x509.load_certificate_list_from_file(ca_file.name) for ca_cert in ca_certs: tmpdb.add_cert(ca_cert.der_data, str(ca_cert.subject), 'C,,') del ca_certs del ca_cert try: tmpdb.verify_ca_cert_validity('IPA CA') except ValueError as e: raise admintool.ScriptError( "Not a valid CA certificate: %s (visit " "http://www.freeipa.org/page/Troubleshooting for " "troubleshooting guide)" % e) trust_chain = tmpdb.get_trust_chain('IPA CA')[:-1] for nickname in trust_chain: try: ca_cert = tmpdb.get_cert(nickname) except RuntimeError: break certstore.put_ca_cert_nss( conn, api.env.basedn, ca_cert, nickname, ',,') dn = DN(('cn', self.cert_nickname), ('cn', 'ca_renewal'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) try: entry = conn.get_entry(dn, ['usercertificate']) entry['usercertificate'] = [cert] conn.update_entry(entry) except errors.NotFound: entry = conn.make_entry( dn, objectclass=['top', 'pkiuser', 'nscontainer'], cn=[self.cert_nickname], usercertificate=[cert]) conn.add_entry(entry) except errors.EmptyModlist: pass try: ca.set_renewal_master() except errors.NotFound: raise admintool.ScriptError("CA renewal master not found") self.resubmit_request(ca, 'ipaRetrieval') print("CA certificate successfully renewed")
def create_db(self, user=None, group=None, mode=None, backup=False): """Create cert DB :param user: User owner the secdir :param group: Group owner of the secdir :param mode: Mode of the secdir :param backup: Backup the sedir files """ if mode is not None: dirmode = mode filemode = mode & 0o666 pwdfilemode = mode & 0o660 else: dirmode = 0o750 filemode = 0o640 pwdfilemode = 0o640 uid = -1 gid = -1 if user is not None: uid = pwd.getpwnam(user).pw_uid if group is not None: gid = grp.getgrnam(group).gr_gid if backup: for filename in self.backup_filenames: ipautil.backup_file(filename) if not os.path.exists(self.secdir): os.makedirs(self.secdir, dirmode) if not os.path.exists(self.pwd_file): # Create the password file for this db with io.open(os.open(self.pwd_file, os.O_CREAT | os.O_WRONLY, pwdfilemode), 'w', closefd=True) as f: f.write(ipautil.ipa_generate_password()) f.flush() # In case dbtype is auto, let certutil decide which type of DB # to create. if self.dbtype == 'auto': dbdir = self.secdir else: dbdir = '{}:{}'.format(self.dbtype, self.secdir) args = [ paths.CERTUTIL, '-d', dbdir, '-N', '-f', self.pwd_file, # -@ in case it's an old db and it must be migrated '-@', self.pwd_file, ] ipautil.run(args, stdin=None, cwd=self.secdir) self._set_filenames(self._detect_dbtype()) if self.filenames is None: # something went wrong... raise ValueError( "Failed to create NSSDB at '{}'".format(self.secdir) ) # Finally fix up perms os.chown(self.secdir, uid, gid) os.chmod(self.secdir, dirmode) tasks.restore_context(self.secdir, force=True) for filename in self.filenames: if os.path.exists(filename): os.chown(filename, uid, gid) if filename == self.pwd_file: new_mode = pwdfilemode else: new_mode = filemode os.chmod(filename, new_mode) tasks.restore_context(filename, force=True)
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) # then givenname and sn are required attributes if 'givenname' not in entry_attrs: raise errors.RequirementError(name='givenname', error=_('givenname is required')) if 'sn' not in entry_attrs: raise errors.RequirementError(name='sn', error=_('sn is required')) # we don't want an user private group to be created for this user # add NO_UPG_MAGIC description attribute to let the DS plugin know entry_attrs.setdefault('description', []) entry_attrs['description'].append(NO_UPG_MAGIC) # uidNumber/gidNumber entry_attrs.setdefault('uidnumber', baseldap.DNA_MAGIC) entry_attrs.setdefault('gidnumber', baseldap.DNA_MAGIC) if not client_has_capability( options['version'], 'optional_uid_params'): # https://fedorahosted.org/freeipa/ticket/2886 # Old clients say 999 (OLD_DNA_MAGIC) when they really mean # "assign a value dynamically". OLD_DNA_MAGIC = 999 if entry_attrs.get('uidnumber') == OLD_DNA_MAGIC: entry_attrs['uidnumber'] = baseldap.DNA_MAGIC if entry_attrs.get('gidnumber') == OLD_DNA_MAGIC: entry_attrs['gidnumber'] = baseldap.DNA_MAGIC # Check the lenght of the RDN (uid) value config = ldap.get_ipa_config() if 'ipamaxusernamelength' in config: if len(keys[-1]) > int(config.get('ipamaxusernamelength')[0]): raise errors.ValidationError( name=self.obj.primary_key.cli_name, error=_('can be at most %(len)d characters') % dict( len = int(config.get('ipamaxusernamelength')[0]) ) ) default_shell = config.get('ipadefaultloginshell', [paths.SH])[0] entry_attrs.setdefault('loginshell', default_shell) # hack so we can request separate first and last name in CLI full_name = '%s %s' % (entry_attrs['givenname'], entry_attrs['sn']) entry_attrs.setdefault('cn', full_name) # Homedirectory # (order is : option, placeholder (TBD), CLI default value (here in config)) if 'homedirectory' not in entry_attrs: # get home's root directory from config homes_root = config.get('ipahomesrootdir', [paths.HOME_DIR])[0] # build user's home directory based on his uid entry_attrs['homedirectory'] = posixpath.join(homes_root, keys[-1]) # Kerberos principal entry_attrs.setdefault('krbprincipalname', '%s@%s' % (entry_attrs['uid'], api.env.realm)) # If requested, generate a userpassword if 'userpassword' not in entry_attrs and options.get('random'): entry_attrs['userpassword'] = ipa_generate_password(baseuser_pwdchars) # save the password so it can be displayed in post_callback setattr(context, 'randompassword', entry_attrs['userpassword']) # Check the email or create it if 'mail' in entry_attrs: entry_attrs['mail'] = self.obj.normalize_and_validate_email(entry_attrs['mail'], config) else: # No e-mail passed in. If we have a default e-mail domain set # then we'll add it automatically. defaultdomain = config.get('ipadefaultemaildomain', [None])[0] if defaultdomain: entry_attrs['mail'] = self.obj.normalize_and_validate_email(keys[-1], config) # If the manager is defined, check it is a ACTIVE user to validate it if 'manager' in entry_attrs: entry_attrs['manager'] = self.obj.normalize_manager(entry_attrs['manager'], self.obj.active_container_dn) if ('objectclass' in entry_attrs and 'userclass' in entry_attrs and 'ipauser' not in entry_attrs['objectclass']): entry_attrs['objectclass'].append('ipauser') if 'ipatokenradiusconfiglink' in entry_attrs: cl = entry_attrs['ipatokenradiusconfiglink'] if cl: if 'objectclass' not in entry_attrs: _entry = ldap.get_entry(dn, ['objectclass']) entry_attrs['objectclass'] = _entry['objectclass'] if 'ipatokenradiusproxyuser' not in entry_attrs['objectclass']: entry_attrs['objectclass'].append('ipatokenradiusproxyuser') answer = self.api.Object['radiusproxy'].get_dn_if_exists(cl) entry_attrs['ipatokenradiusconfiglink'] = answer return dn
def import_files(self, files, import_keys=False, key_password=None, key_nickname=None): """ Import certificates and a single private key from multiple files The files may be in PEM and DER certificate, PKCS#7 certificate chain, PKCS#8 and raw private key and PKCS#12 formats. :param files: Names of files to import :param import_keys: Whether to import private keys :param key_password: Password to decrypt private keys :param key_nickname: Nickname of the private key to import from PKCS#12 files """ key_file = None extracted_key = None extracted_certs = [] for filename in files: try: with open(filename, 'rb') as f: data = f.read() except IOError as e: raise RuntimeError( "Failed to open %s: %s" % (filename, e.strerror)) # Try to parse the file as PEM file matches = list( re.finditer( br'-----BEGIN (.+?)-----(.*?)-----END \1-----', data, re.DOTALL ) ) if matches: loaded = False for match in matches: body = match.group() label = match.group(1) line = len(data[:match.start() + 1].splitlines()) if label in (b'CERTIFICATE', b'X509 CERTIFICATE', b'X.509 CERTIFICATE'): try: cert = x509.load_pem_x509_certificate(body) except ValueError as e: if label != b'CERTIFICATE': logger.warning( "Skipping certificate in %s at line %s: " "%s", filename, line, e) continue else: extracted_certs.append(cert) loaded = True continue if label in (b'PKCS7', b'PKCS #7 SIGNED DATA', b'CERTIFICATE'): try: certs = x509.pkcs7_to_certs(body) except ipautil.CalledProcessError as e: if label == b'CERTIFICATE': logger.warning( "Skipping certificate in %s at line %s: " "%s", filename, line, e) else: logger.warning( "Skipping PKCS#7 in %s at line %s: %s", filename, line, e) continue else: extracted_certs.extend(certs) loaded = True continue if label in (b'PRIVATE KEY', b'ENCRYPTED PRIVATE KEY', b'RSA PRIVATE KEY', b'DSA PRIVATE KEY', b'EC PRIVATE KEY'): if not import_keys: continue if key_file: raise RuntimeError( "Can't load private key from both %s and %s" % (key_file, filename)) # the args -v2 aes256 -v2prf hmacWithSHA256 are needed # on OpenSSL 1.0.2 (fips mode). As soon as FreeIPA # requires OpenSSL 1.1.0 we'll be able to drop them args = [ paths.OPENSSL, 'pkcs8', '-topk8', '-v2', 'aes256', '-v2prf', 'hmacWithSHA256', '-passout', 'file:' + self.pwd_file, ] if ((label != b'PRIVATE KEY' and key_password) or label == b'ENCRYPTED PRIVATE KEY'): key_pwdfile = ipautil.write_tmp_file(key_password) args += [ '-passin', 'file:' + key_pwdfile.name, ] try: result = ipautil.run( args, stdin=body, capture_output=True) except ipautil.CalledProcessError as e: logger.warning( "Skipping private key in %s at line %s: %s", filename, line, e) continue else: extracted_key = result.raw_output key_file = filename loaded = True continue if loaded: continue raise RuntimeError("Failed to load %s" % filename) # Try to load the file as DER certificate try: cert = x509.load_der_x509_certificate(data) except ValueError: pass else: extracted_certs.append(cert) continue # Try to import the file as PKCS#12 file if import_keys: try: self.import_pkcs12(filename, key_password) except RuntimeError: pass else: if key_file: raise RuntimeError( "Can't load private key from both %s and %s" % (key_file, filename)) key_file = filename server_certs = self.find_server_certs() if key_nickname: for nickname, _trust_flags in server_certs: if nickname == key_nickname: break else: raise RuntimeError( "Server certificate \"%s\" not found in %s" % (key_nickname, filename)) else: if len(server_certs) > 1: raise RuntimeError( "%s server certificates found in %s, " "expecting only one" % (len(server_certs), filename)) continue raise RuntimeError("Failed to load %s" % filename) if import_keys and not key_file: raise RuntimeError( "No server certificates found in %s" % (', '.join(files))) for cert in extracted_certs: nickname = str(DN(cert.subject)) self.add_cert(cert, nickname, EMPTY_TRUST_FLAGS) if extracted_key: with tempfile.NamedTemporaryFile() as in_file, \ tempfile.NamedTemporaryFile() as out_file: for cert in extracted_certs: in_file.write(cert.public_bytes(x509.Encoding.PEM)) in_file.write(extracted_key) in_file.flush() out_password = ipautil.ipa_generate_password() out_pwdfile = ipautil.write_tmp_file(out_password) args = [ paths.OPENSSL, 'pkcs12', '-export', '-in', in_file.name, '-out', out_file.name, '-passin', 'file:' + self.pwd_file, '-passout', 'file:' + out_pwdfile.name, ] try: ipautil.run(args) except ipautil.CalledProcessError as e: raise RuntimeError( "No matching certificate found for private key from " "%s" % key_file) self.import_pkcs12(out_file.name, out_password)
def create_noise_file(self): if os.path.isfile(self.noise_fname): os.remove(self.noise_fname) with open(self.noise_fname, "w") as f: self.set_perms(f) f.write(ipautil.ipa_generate_password())
def check_userpassword(self, entry_attrs, **options): if 'userpassword' not in entry_attrs and options.get('random'): entry_attrs['userpassword'] = ipa_generate_password( baseuser_pwdchars, pwd_len=GEN_TMP_PWD_LEN) # save the password so it can be displayed in post_callback setattr(context, 'randompassword', entry_attrs['userpassword'])
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) if not options.get('noprivate', False): try: # The Managed Entries plugin will allow a user to be created # even if a group has a duplicate name. This would leave a user # without a private group. Check for both the group and the user. self.api.Object['group'].get_dn_if_exists(keys[-1]) try: self.api.Command['user_show'](keys[-1]) self.obj.handle_duplicate_entry(*keys) except errors.NotFound: raise errors.ManagedGroupExistsError(group=keys[-1]) except errors.NotFound: pass else: # we don't want an user private group to be created for this user # add NO_UPG_MAGIC description attribute to let the DS plugin know entry_attrs.setdefault('description', []) entry_attrs['description'].append(NO_UPG_MAGIC) entry_attrs.setdefault('uidnumber', baseldap.DNA_MAGIC) if not client_has_capability( options['version'], 'optional_uid_params'): # https://fedorahosted.org/freeipa/ticket/2886 # Old clients say 999 (OLD_DNA_MAGIC) when they really mean # "assign a value dynamically". OLD_DNA_MAGIC = 999 if entry_attrs.get('uidnumber') == OLD_DNA_MAGIC: entry_attrs['uidnumber'] = baseldap.DNA_MAGIC if entry_attrs.get('gidnumber') == OLD_DNA_MAGIC: entry_attrs['gidnumber'] = baseldap.DNA_MAGIC validate_nsaccountlock(entry_attrs) config = ldap.get_ipa_config()[1] if 'ipamaxusernamelength' in config: if len(keys[-1]) > int(config.get('ipamaxusernamelength')[0]): raise errors.ValidationError( name=self.obj.primary_key.cli_name, error=_('can be at most %(len)d characters') % dict( len = int(config.get('ipamaxusernamelength')[0]) ) ) default_shell = config.get('ipadefaultloginshell', ['/bin/sh'])[0] entry_attrs.setdefault('loginshell', default_shell) # hack so we can request separate first and last name in CLI full_name = '%s %s' % (entry_attrs['givenname'], entry_attrs['sn']) entry_attrs.setdefault('cn', full_name) if 'homedirectory' not in entry_attrs: # get home's root directory from config homes_root = config.get('ipahomesrootdir', ['/home'])[0] # build user's home directory based on his uid entry_attrs['homedirectory'] = posixpath.join(homes_root, keys[-1]) entry_attrs.setdefault('krbpwdpolicyreference', DN(('cn', 'global_policy'), ('cn', api.env.realm), ('cn', 'kerberos'), api.env.basedn)) entry_attrs.setdefault('krbprincipalname', '%s@%s' % (entry_attrs['uid'], api.env.realm)) if entry_attrs.get('gidnumber') is None: # gidNumber wasn't specified explicity, find out what it should be if not options.get('noprivate', False) and ldap.has_upg(): # User Private Groups - uidNumber == gidNumber entry_attrs['gidnumber'] = entry_attrs['uidnumber'] else: # we're adding new users to a default group, get its gidNumber # get default group name from config def_primary_group = config.get('ipadefaultprimarygroup') group_dn = self.api.Object['group'].get_dn(def_primary_group) try: (group_dn, group_attrs) = ldap.get_entry(group_dn, ['gidnumber']) except errors.NotFound: error_msg = _('Default group for new users not found') raise errors.NotFound(reason=error_msg) if 'gidnumber' not in group_attrs: error_msg = _('Default group for new users is not POSIX') raise errors.NotFound(reason=error_msg) entry_attrs['gidnumber'] = group_attrs['gidnumber'] if 'userpassword' not in entry_attrs and options.get('random'): entry_attrs['userpassword'] = ipa_generate_password(user_pwdchars) # save the password so it can be displayed in post_callback setattr(context, 'randompassword', entry_attrs['userpassword']) if 'mail' in entry_attrs: entry_attrs['mail'] = self.obj._normalize_and_validate_email(entry_attrs['mail'], config) else: # No e-mail passed in. If we have a default e-mail domain set # then we'll add it automatically. defaultdomain = config.get('ipadefaultemaildomain', [None])[0] if defaultdomain: entry_attrs['mail'] = self.obj._normalize_and_validate_email(keys[-1], config) if 'manager' in entry_attrs: entry_attrs['manager'] = self.obj._normalize_manager(entry_attrs['manager']) if ('objectclass' in entry_attrs and 'userclass' in entry_attrs and 'ipauser' not in entry_attrs['objectclass']): entry_attrs['objectclass'].append('ipauser') if 'ipatokenradiusconfiglink' in entry_attrs: cl = entry_attrs['ipatokenradiusconfiglink'] if cl: if 'objectclass' not in entry_attrs: _entry = ldap.get_entry(dn, ['objectclass']) entry_attrs['objectclass'] = _entry['objectclass'] if 'ipatokenradiusproxyuser' not in entry_attrs['objectclass']: entry_attrs['objectclass'].append('ipatokenradiusproxyuser') answer = self.api.Object['radiusproxy'].get_dn_if_exists(cl) entry_attrs['ipatokenradiusconfiglink'] = answer return dn
def import_files(self, files, db_password_filename, import_keys=False, key_password=None, key_nickname=None): """ Import certificates and a single private key from multiple files The files may be in PEM and DER certificate, PKCS#7 certificate chain, PKCS#8 and raw private key and PKCS#12 formats. :param files: Names of files to import :param db_password_filename: Name of file containing the database password :param import_keys: Whether to import private keys :param key_password: Password to decrypt private keys :param key_nickname: Nickname of the private key to import from PKCS#12 files """ key_file = None extracted_key = None extracted_certs = '' for filename in files: try: with open(filename, 'rb') as f: data = f.read() except IOError as e: raise RuntimeError( "Failed to open %s: %s" % (filename, e.strerror)) # Try to parse the file as PEM file matches = list(re.finditer( r'-----BEGIN (.+?)-----(.*?)-----END \1-----', data, re.DOTALL)) if matches: loaded = False for match in matches: body = match.group() label = match.group(1) line = len(data[:match.start() + 1].splitlines()) if label in ('CERTIFICATE', 'X509 CERTIFICATE', 'X.509 CERTIFICATE'): try: x509.load_certificate(match.group(2)) except NSPRError as e: if label != 'CERTIFICATE': root_logger.warning( "Skipping certificate in %s at line %s: %s", filename, line, e) continue else: extracted_certs += body + '\n' loaded = True continue if label in ('PKCS7', 'PKCS #7 SIGNED DATA', 'CERTIFICATE'): args = [ paths.OPENSSL, 'pkcs7', '-print_certs', ] try: result = ipautil.run( args, stdin=body, capture_output=True) except ipautil.CalledProcessError as e: if label == 'CERTIFICATE': root_logger.warning( "Skipping certificate in %s at line %s: %s", filename, line, e) else: root_logger.warning( "Skipping PKCS#7 in %s at line %s: %s", filename, line, e) continue else: extracted_certs += result.output + '\n' loaded = True continue if label in ('PRIVATE KEY', 'ENCRYPTED PRIVATE KEY', 'RSA PRIVATE KEY', 'DSA PRIVATE KEY', 'EC PRIVATE KEY'): if not import_keys: continue if key_file: raise RuntimeError( "Can't load private key from both %s and %s" % (key_file, filename)) args = [ paths.OPENSSL, 'pkcs8', '-topk8', '-passout', 'file:' + db_password_filename, ] if ((label != 'PRIVATE KEY' and key_password) or label == 'ENCRYPTED PRIVATE KEY'): key_pwdfile = ipautil.write_tmp_file(key_password) args += [ '-passin', 'file:' + key_pwdfile.name, ] try: result = ipautil.run( args, stdin=body, capture_output=True) except ipautil.CalledProcessError as e: root_logger.warning( "Skipping private key in %s at line %s: %s", filename, line, e) continue else: extracted_key = result.output key_file = filename loaded = True continue if loaded: continue raise RuntimeError("Failed to load %s" % filename) # Try to load the file as DER certificate try: x509.load_certificate(data, x509.DER) except NSPRError: pass else: data = x509.make_pem(base64.b64encode(data)) extracted_certs += data + '\n' continue # Try to import the file as PKCS#12 file if import_keys: try: self.import_pkcs12( filename, db_password_filename, key_password) except RuntimeError: pass else: if key_file: raise RuntimeError( "Can't load private key from both %s and %s" % (key_file, filename)) key_file = filename server_certs = self.find_server_certs() if key_nickname: for nickname, trust_flags in server_certs: if nickname == key_nickname: break else: raise RuntimeError( "Server certificate \"%s\" not found in %s" % (key_nickname, filename)) else: if len(server_certs) > 1: raise RuntimeError( "%s server certificates found in %s, " "expecting only one" % (len(server_certs), filename)) continue raise RuntimeError("Failed to load %s" % filename) if import_keys and not key_file: raise RuntimeError( "No server certificates found in %s" % (', '.join(files))) nss_certs = x509.load_certificate_list(extracted_certs) nss_cert = None for nss_cert in nss_certs: nickname = str(nss_cert.subject) self.add_cert(nss_cert.der_data, nickname, ',,') del nss_certs, nss_cert if extracted_key: in_file = ipautil.write_tmp_file(extracted_certs + extracted_key) out_file = tempfile.NamedTemporaryFile() out_password = ipautil.ipa_generate_password() out_pwdfile = ipautil.write_tmp_file(out_password) args = [ paths.OPENSSL, 'pkcs12', '-export', '-in', in_file.name, '-out', out_file.name, '-passin', 'file:' + db_password_filename, '-passout', 'file:' + out_pwdfile.name, ] try: ipautil.run(args) except ipautil.CalledProcessError as e: raise RuntimeError( "No matching certificate found for private key from %s" % key_file) self.import_pkcs12(out_file.name, db_password_filename, out_password)