def verify_host_resolvable(fqdn, log): """ See if the hostname has a DNS A/AAAA record. """ if not isinstance(fqdn, DNSName): fqdn = DNSName(fqdn) fqdn = fqdn.make_absolute() for rdtype in ('A', 'AAAA'): try: answers = resolver.query(fqdn, rdtype) log.debug( 'IPA: found %d %s records for %s: %s' % (len(answers), rdtype, fqdn, ' '.join(str(answer) for answer in answers)) ) except DNSException: log.debug( 'IPA: DNS %s record lookup failed for %s' % (rdtype, fqdn) ) continue else: return # dns lookup failed in both tries raise errors.DNSNotARecordError()
def __setup_server_configuration(self): ensure_dnsserver_container_exists(api.Backend.ldap2, self.api) try: self.api.Command.dnsserver_add( self.fqdn, idnssoamname=DNSName(self.fqdn).make_absolute(), ) except errors.DuplicateEntry: # probably reinstallation of DNS pass try: self.api.Command.dnsserver_mod( self.fqdn, idnsforwarders=[unicode(f) for f in self.forwarders], idnsforwardpolicy=unicode(self.forward_policy)) except errors.EmptyModlist: pass sysupgrade.set_upgrade_state('dns', 'server_config_to_ldap', True)
def xml_unwrap(value, encoding='UTF-8'): """ Unwrap all ``xmlrpc.Binary``, decode all ``str`` into ``unicode``. When decoding data from an XML-RPC packet, the following transformations occur: * The binary payloads of all ``xmlrpc.client.Binary`` instances are returned as ``str`` instances. * All ``str`` instances are treated as UTF-8 encoded Unicode strings. They are decoded and the resulting ``unicode`` instance is returned. Also see `xml_wrap()`. :param value: The value to unwrap. :param encoding: The Unicode encoding to use (defaults to ``'UTF-8'``). """ if isinstance(value, (unicode, int, float, bool)): # most common first return value elif value is None: return value elif isinstance(value, bytes): return value.decode(encoding) elif isinstance(value, (list, tuple)): return tuple(xml_unwrap(v, encoding) for v in value) elif isinstance(value, dict): if '__dns_name__' in value: return DNSName(value['__dns_name__']) else: return dict( (k, xml_unwrap(v, encoding)) for (k, v) in value.items() ) elif isinstance(value, Binary): assert type(value.data) is bytes return value.data elif isinstance(value, DateTime): # xmlprc DateTime is converted to string of %Y%m%dT%H:%M:%S format return datetime.datetime.strptime(str(value), "%Y%m%dT%H:%M:%S") raise TypeError(value)
def _add_base_dns_records_for_server( self, zone_obj, hostname, roles=None, include_master_role=True, include_kerberos_realm=True, ): server = self.servers_data[hostname] if roles: eff_roles = server['roles'] & set(roles) else: eff_roles = server['roles'] hostname_abs = DNSName(hostname).make_absolute() if include_kerberos_realm: self.__add_kerberos_txt_rec(zone_obj) # get master records if include_master_role: self.__add_srv_records( zone_obj, hostname_abs, IPA_DEFAULT_MASTER_SRV_REC, weight=server['weight'] ) if 'CA server' in eff_roles: self.__add_ca_records_from_hostname(zone_obj, hostname_abs) if 'AD trust controller' in eff_roles: self.__add_srv_records( zone_obj, hostname_abs, IPA_DEFAULT_ADTRUST_SRV_REC, weight=server['weight'] ) if 'NTP server' in eff_roles: self.__add_srv_records( zone_obj, hostname_abs, IPA_DEFAULT_NTP_SRV_REC, weight=server['weight'] )
def match_hostname(self, hostname): match_cert = {} match_cert['subject'] = match_subject = [] for rdn in self._cert.subject.rdns: match_rdn = [] for ava in rdn: if ava.oid == crypto_x509.oid.NameOID.COMMON_NAME: match_rdn.append(('commonName', ava.value)) match_subject.append(match_rdn) values = self.san_a_label_dns_names if values: match_cert['subjectAltName'] = match_san = [] for value in values: match_san.append(('DNS', value)) # deprecated in Python3.7 without replacement ssl.match_hostname( # pylint: disable=deprecated-method match_cert, DNSName(hostname).ToASCII() )
def json_decode_binary(val): ''' JSON cannot transport binary data. In order to transport binary data we convert binary data to a form like this: {'__base64__' : base64_encoding_of_binary_value} see json_encode_binary() After JSON had decoded the JSON stream back into a Python object we must recursively scan the object looking for any dicts which might represent binary values and replace the dict containing the base64 encoding of the binary value with the decoded binary value. Unlike the encoding problem where the input might consist of immutable object, all JSON decoded container are mutable so the conversion could be done in place. However we don't modify objects in place because of side effects which may be dangerous. Thus we elect to spend a few more cycles and avoid the possibility of unintended side effects in favor of robustness. ''' if isinstance(val, dict): if '__base64__' in val: return base64.b64decode(val['__base64__']) elif '__datetime__' in val: return datetime.datetime.strptime(val['__datetime__'], LDAP_GENERALIZED_TIME_FORMAT) elif '__dns_name__' in val: return DNSName(val['__dns_name__']) else: return dict((k, json_decode_binary(v)) for k, v in val.items()) elif isinstance(val, list): return tuple(json_decode_binary(v) for v in val) else: if isinstance(val, basestring): try: return val.decode('utf-8') except UnicodeDecodeError: raise ConversionError(name=val, error='incorrect type') else: return val
def test_adtrust_system_records(self): """ Test ADTrust dns records with firstly installing a trust then removing the records and using the nsupdate generated by dns-update-system-records.""" self.master.run_command(['ipa-adtrust-install', '-U', '--enable-compat', '--netbios-name', 'IPA', '-a', self.master.config.admin_password, '--add-sids']) # lets re-kinit after adtrust-install and restart named tasks.kinit_admin(self.master) tasks.restart_named(self.master) time.sleep(5) self.delete_update_system_records(rnames=(r[0] for r in IPA_DEFAULT_ADTRUST_SRV_REC)) expected_servers = ( (self.PRIO_HIGH, self.WEIGHT, DNSName(self.master.hostname)), ) for ip in (self.master.ip, self.replicas[0].ip, self.replicas[1].ip): self._test_SRV_rec_against_server( ip, self.domain, expected_servers, rec_list=IPA_DEFAULT_ADTRUST_SRV_REC)
def test_nsupdate_without_locations(self): """Test nsupdate file generated by dns-update-system-records Remove all records and the use nsupdate to restore state and test if all record are there as expected""" domain = DNSName(self.master.domain.name).make_absolute() filepath = '/tmp/ipa.nsupdate' self.master.run_command([ 'ipa', 'dns-update-system-records', '--dry-run', '--out', filepath ]) # delete original records first for rname, _port in IPA_DEFAULT_MASTER_SRV_REC: self.master.run_command([ 'ipa', 'dnsrecord-del', str(domain), str(rname), '--del-all' ]) # allow unauthenticates nsupdate (no need to testing authentication) self.master.run_command([ 'ipa', 'dnszone-mod', str(domain), '--update-policy=grant * wildcard *;' ]) self.master.run_command(['nsupdate', '-g', filepath]) time.sleep(5) # give time to named to process everything from update self.test_without_locations()
def __add_ca_records_from_hostname(self, zone_obj, hostname): assert isinstance(hostname, DNSName) and hostname.is_absolute() r_name = DNSName('ipa-ca') + self.domain_abs rrsets = [] end_time = time() + 120 # timeout in seconds while time() < end_time: try: rrsets = resolve_rrsets(hostname, (rdatatype.A, rdatatype.AAAA)) except DNSException: # logging is done inside resolve_rrsets pass if rrsets: break sleep(5) if not rrsets: root_logger.error('unable to resolve host name %s to IP address, ' 'ipa-ca DNS record will be incomplete', hostname) return for rrset in rrsets: for rd in rrset: rdataset = zone_obj.get_rdataset( r_name, rd.rdtype, create=True) rdataset.add(rd, ttl=86400) # FIXME: use TTL from config
def get_ipa_idnssoamname(self, **kwargs): if self.ipa_params.name_server is not None: return DNSName(self.ipa_params.name_server)
import six import dns.resolver import dns.rrset import dns.rdatatype import dns.rdataclass from ipatests.test_integration.base import IntegrationTest from ipatests.pytest_plugins.integration import tasks from ipapython.dnsutil import DNSName from ipalib.constants import IPA_CA_RECORD logger = logging.getLogger(__name__) IPA_DEFAULT_MASTER_SRV_REC = ( # srv record name, port (DNSName(u'_ldap._tcp'), 389), (DNSName(u'_kerberos._tcp'), 88), (DNSName(u'_kerberos._udp'), 88), (DNSName(u'_kerberos-master._tcp'), 88), (DNSName(u'_kerberos-master._udp'), 88), (DNSName(u'_kpasswd._tcp'), 464), (DNSName(u'_kpasswd._udp'), 464), ) IPA_DEFAULT_ADTRUST_SRV_REC = ( # srv record name, port (DNSName(u'_ldap._tcp.Default-First-Site-Name._sites.dc._msdcs'), 389), (DNSName(u'_ldap._tcp.dc._msdcs'), 389), (DNSName(u'_kerberos._tcp.Default-First-Site-Name._sites.dc._msdcs'), 88), (DNSName(u'_kerberos._udp.Default-First-Site-Name._sites.dc._msdcs'), 88), (DNSName(u'_kerberos._tcp.dc._msdcs'), 88),
def get_ipa_idnssoamname(self, **_kwargs): # pylint: disable=R1710 if self.ipa_params.name_server is not None: return DNSName(self.ipa_params.name_server)
def get_ipa_idnssoarname(self, **kwargs): if self.ipa_params.admin_email is not None: return DNSName( self._replace_at_symbol_in_rname(self.ipa_params.admin_email))
def validate_zonemgr_str(zonemgr): zonemgr = normalize_zonemgr(zonemgr) validate_idna_domain(zonemgr) zonemgr = DNSName(zonemgr) return validate_zonemgr(zonemgr)
def interactive_prompt_callback(self, kw): try: has_cli_options(self, kw, self.no_option_msg) # Some DNS records were entered, do not use full interactive help # We should still ask user for required parts of DNS parts he is # trying to add in the same way we do for standard LDAP parameters # # Do not ask for required parts when any "extra" option is used, # it can be used to fill all required params by itself new_kw = {} for rrparam in iterate_rrparams_by_parts(self, kw, skip_extra=True): rrtype = get_record_rrtype(rrparam.name) user_options = prompt_missing_parts(rrtype, self, kw, prompt_optional=False) new_kw.update(user_options) kw.update(new_kw) return except errors.OptionError: pass try: idnsname = DNSName(kw['idnsname']) except Exception as e: raise errors.ValidationError(name='idnsname', error=unicode(e)) try: zonename = DNSName(kw['dnszoneidnsname']) except Exception as e: raise errors.ValidationError(name='dnszoneidnsname', error=unicode(e)) # check zone type if idnsname.is_empty(): common_types = u', '.join(_zone_top_record_types) elif zonename.is_reverse(): common_types = u', '.join(_rev_top_record_types) else: common_types = u', '.join(_top_record_types) self.Backend.textui.print_plain( _(u'Please choose a type of DNS resource record to be added')) self.Backend.textui.print_plain(_(u'The most common types for this type of zone are: %s\n') %\ common_types) ok = False while not ok: rrtype = self.Backend.textui.prompt(_(u'DNS resource record type')) if rrtype is None: return rrtype = rrtype.upper() try: name = record_name_format % rrtype.lower() param = self.params[name] if 'no_option' in param.flags: raise ValueError() except (KeyError, ValueError): all_types = u', '.join( get_record_rrtype(p.name) for p in self.params() if (get_record_rrtype(p.name) and 'no_option' not in p.flags)) self.Backend.textui.print_plain( _(u'Invalid or unsupported type. Allowed values are: %s') % all_types) continue ok = True user_options = prompt_parts(rrtype, self) kw.update(user_options)
def run(): try: check_client_configuration() except ScriptError as e: print(e.msg) return e.rval fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE) statestore = sysrestore.StateFile(paths.IPA_CLIENT_SYSRESTORE) options, _args = parse_options() logfile = paths.IPACLIENTSAMBA_INSTALL_LOG if options.uninstall: logfile = paths.IPACLIENTSAMBA_UNINSTALL_LOG standard_logging_setup( logfile, verbose=False, debug=options.debug, filemode="a", console_format="%(message)s", ) cfg = dict( context="cli_installer", confdir=paths.ETC_IPA, in_server=False, debug=options.debug, verbose=0, ) # Bootstrap API early so that env object is available api.bootstrap(**cfg) local_config = dict( host_princ=str("host/%s@%s" % (api.env.host, api.env.realm)), smb_princ=str("cifs/%s@%s" % (api.env.host, api.env.realm)), ) # Until api.finalize() is called, we can add our own configuration api.env._merge(**local_config) if options.uninstall: if statestore.has_state("domain_member"): uninstall(fstore, statestore, options) try: keys = ("configured", "hardening", "groupmap", "tdb", "service.principal", "smb.conf") for key in keys: statestore.delete_state("domain_member", key) except Exception as e: print("Error: Failed to remove the domain_member statestores: " "%s" % e) return 1 else: print("Samba configuration is reverted. " "However, Samba databases were fully cleaned and " "old configuration file will not be usable anymore.") else: print("Samba domain member is not configured yet") return 0 ca_cert_path = None if os.path.exists(paths.IPA_CA_CRT): ca_cert_path = paths.IPA_CA_CRT if statestore.has_state("domain_member") and not options.force: print("Samba domain member is already configured") return CLIENT_ALREADY_CONFIGURED if not os.path.exists(paths.SMBD): print("Samba suite is not installed") return CLIENT_NOT_CONFIGURED autodiscover = False ds = discovery.IPADiscovery() if not options.server: print("Searching for IPA server...") ret = ds.search(ca_cert_path=ca_cert_path) logger.debug("Executing DNS discovery") if ret == discovery.NO_LDAP_SERVER: logger.debug("Autodiscovery did not find LDAP server") s = urlsplit(api.env.xmlrpc_uri) server = [s.netloc] logger.debug("Setting server to %s", s.netloc) else: autodiscover = True if not ds.servers: print( "Autodiscovery was successful but didn't return a server") return 1 logger.debug( "Autodiscovery success, possible servers %s", ",".join(ds.servers), ) server = ds.servers[0] else: server = options.server logger.debug("Verifying that %s is an IPA server", server) ldapret = ds.ipacheckldap(server, api.env.realm, ca_cert_path) if ldapret[0] == discovery.NO_ACCESS_TO_LDAP: print("Anonymous access to the LDAP server is disabled.") print("Proceeding without strict verification.") print("Note: This is not an error if anonymous access has been " "explicitly restricted.") elif ldapret[0] == discovery.NO_TLS_LDAP: logger.warning("Unencrypted access to LDAP is not supported.") elif ldapret[0] != 0: print("Unable to confirm that %s is an IPA server" % server) return 1 if not autodiscover: print("IPA server: %s" % server) logger.debug("Using fixed server %s", server) else: print("IPA server: DNS discovery") logger.info("Configured to use DNS discovery") if api.env.host == server: logger.error("Cannot run on IPA master. " "Cannot configure Samba as a domain member on a domain " "controller. Please use ipa-adtrust-install for that!") return 1 if not options.netbiosname: options.netbiosname = DNSName.from_text(api.env.host)[0].decode() options.netbiosname = options.netbiosname.upper() with use_api_as_principal(api.env.host_princ, paths.KRB5_KEYTAB): try: # Try to access 'service_add_smb' command, if it throws # AttributeError exception, the IPA server doesn't support # setting up Samba as a domain member. service_add_smb = api.Command.service_add_smb # Now try to see if SMB principal already exists api.Command.service_show(api.env.smb_princ) # If no exception was raised, the object exists. # We cannot continue because we would break existing configuration print("WARNING: SMB service principal %s already exists. " "Please remove it before proceeding." % (api.env.smb_princ)) if not options.force: return 1 # For --force, we should then delete cifs/.. service object api.Command.service_del(api.env.smb_princ) except AttributeError: logger.error( "Chosen IPA master %s does not have support to " "set up Samba domain members", server, ) return 1 except errors.VersionError as e: print("This client is incompatible: " + str(e)) return 1 except errors.NotFound: logger.debug("No SMB service principal exists, OK to proceed") except errors.PublicError as e: logger.error( "Cannot connect to the server due to " "a generic error: %s", e, ) return 1 # At this point we have proper setup: # - we connected to IPA API end-point as a host principal # - no cifs/... principal exists so we can create it print("Chosen IPA master: %s" % server) print("SMB principal to be created: %s" % api.env.smb_princ) print("NetBIOS name to be used: %s" % options.netbiosname) logger.info("Chosen IPA master: %s", server) logger.info("SMB principal to be created: %s", api.env.smb_princ) logger.info("NetBIOS name to be used: %s", options.netbiosname) # 1. Pull down ID range and other details of known domains domains = retrieve_domain_information(api) if len(domains) == 0: # logger.error() produces both log file and stderr output logger.error("No configured trust controller detected " "on IPA masters. Use ipa-adtrust-install on an IPA " "master to configure trust controller role.") return 1 str_info = pretty_print_domain_information(domains) logger.info("Discovered domains to use:\n%s", str_info) print("Discovered domains to use:\n%s" % str_info) if not options.unattended and not ipautil.user_input( "Continue to configure the system with these values?", False): print("Installation aborted") return 1 # 2. Create SMB service principal, if we are here, the command exists if (not statestore.get_state("domain_member", "service.principal") or options.force): service_add_smb(api.env.host, options.netbiosname) statestore.backup_state("domain_member", "service.principal", "configured") # 3. Generate machine account password for reuse password = generate_smb_machine_account(fstore, statestore, options, domains[0]) # 4. Now that we have all domains retrieved, we can generate smb.conf if (not statestore.get_state("domain_member", "smb.conf") or options.force): configure_smb_conf(fstore, statestore, options, domains) statestore.backup_state("domain_member", "smb.conf", "configured") # 5. Create SMB service if statestore.get_state("domain_member", "service.principal") == "configured": retrieve_service_principal(fstore, statestore, options, domains[0], api.env.smb_princ, password) statestore.backup_state("domain_member", "service.principal", "configured") # 6. Configure databases to contain proper details if not statestore.get_state("domain_member", "tdb") or options.force: populate_samba_databases(fstore, statestore, options, domains[0], password) statestore.backup_state("domain_member", "tdb", "configured") # 7. Configure default group mapping if (not statestore.get_state("domain_member", "groupmap") or options.force): configure_default_groupmap(fstore, statestore, options, domains[0]) statestore.backup_state("domain_member", "groupmap", "configured") # 8. Enable SELinux policies if (not statestore.get_state("domain_member", "hardening") or options.force): harden_configuration(fstore, statestore, options, domains[0]) statestore.backup_state("domain_member", "hardening", "configured") # 9. Finally, store the state of upgrade statestore.backup_state("domain_member", "configured", True) # Suggest service start only after validating smb.conf print("Samba domain member is configured. " "Please check configuration at %s and " "start smb and winbind services" % paths.SMB_CONF) logger.info( "Samba domain member is configured. " "Please check configuration at %s and " "start smb and winbind services", paths.SMB_CONF, ) return 0
def _get_filename(self, domain): basename = DNSName(domain).ToASCII() + '.pem' return os.path.join(self._dirname, basename)
import pytest import dns.resolver import dns.rrset import dns.rdatatype import dns.rdataclass from ipatests.test_integration.base import IntegrationTest from ipatests.pytest_ipa.integration import tasks from ipapython.dnsutil import DNSName, DNSResolver from ipalib.constants import IPA_CA_RECORD logger = logging.getLogger(__name__) IPA_DEFAULT_MASTER_SRV_REC = ( # srv record name, port (DNSName(u'_ldap._tcp'), 389), (DNSName(u'_kerberos._tcp'), 88), (DNSName(u'_kerberos._udp'), 88), (DNSName(u'_kerberos-master._tcp'), 88), (DNSName(u'_kerberos-master._udp'), 88), (DNSName(u'_kpasswd._tcp'), 464), (DNSName(u'_kpasswd._udp'), 464), ) IPA_DEFAULT_MASTER_URI_REC = ( (DNSName('_kerberos'), ("krb5srv:m:tcp:{hostname}", "krb5srv:m:udp:{hostname}")), (DNSName('_kpasswd'), ("krb5srv:m:tcp:{hostname}", "krb5srv:m:udp:{hostname}")), )
import logging import time import dns.resolver import dns.rrset import dns.rdatatype import dns.rdataclass from ipatests.test_integration.base import IntegrationTest from ipatests.pytest_plugins.integration import tasks from ipapython.dnsutil import DNSName logger = logging.getLogger(__name__) IPA_DEFAULT_MASTER_SRV_REC = ( # srv record name, port (DNSName(u'_ldap._tcp'), 389), (DNSName(u'_kerberos._tcp'), 88), (DNSName(u'_kerberos._udp'), 88), (DNSName(u'_kerberos-master._tcp'), 88), (DNSName(u'_kerberos-master._udp'), 88), (DNSName(u'_kpasswd._tcp'), 464), (DNSName(u'_kpasswd._udp'), 464), ) def resolve_records_from_server(rname, rtype, nameserver): res = dns.resolver.Resolver() res.nameservers = [nameserver] res.lifetime = 10 logger.debug("Query: %s %s, nameserver %s", rname, rtype, nameserver) ans = res.query(rname, rtype)
def __init__(self, api_instance, all_servers=False): self.api_instance = api_instance self.domain_abs = DNSName(self.api_instance.env.domain).make_absolute() self.servers_data = OrderedDict() self.__init_data(all_servers=all_servers)
def __get_location_suffix(self, location): return location + DNSName('_locations') + self.domain_abs
from time import sleep, time from ipalib import errors from ipalib.dns import record_name_format from ipapython.dnsutil import DNSName from ipaserver.install import installutils if six.PY3: unicode = str logger = logging.getLogger(__name__) IPA_DEFAULT_MASTER_SRV_REC = ( # srv record name, port (DNSName('_ldap._tcp'), 389), # Kerberos records are provided for MIT KRB5 < 1.15 and AD (DNSName('_kerberos._tcp'), 88), (DNSName('_kerberos._udp'), 88), (DNSName('_kerberos-master._tcp'), 88), (DNSName('_kerberos-master._udp'), 88), (DNSName('_kpasswd._tcp'), 464), (DNSName('_kpasswd._udp'), 464), ) IPA_DEFAULT_MASTER_URI_REC = ( # URI record name, URI template # MIT KRB5 1.15+ prefers URI records for service discovery # scheme: always krb5srv # flags: empty or 'm' for primary server
def interactive_prompt_callback(self, kw): try: has_cli_options(self, kw, self.no_option_msg) # Some DNS records were entered, do not use full interactive help # We should still ask user for required parts of DNS parts he is # trying to add in the same way we do for standard LDAP parameters # # Do not ask for required parts when any "extra" option is used, # it can be used to fill all required params by itself new_kw = {} for rrparam in iterate_rrparams_by_parts(self, kw, skip_extra=True): rrtype = get_record_rrtype(rrparam.name) user_options = prompt_missing_parts(rrtype, self, kw, prompt_optional=False) new_kw.update(user_options) kw.update(new_kw) return except errors.OptionError: pass try: idnsname = DNSName(kw['idnsname']) except Exception as e: raise errors.ValidationError(name='idnsname', error=unicode(e)) try: zonename = DNSName(kw['dnszoneidnsname']) except Exception as e: raise errors.ValidationError(name='dnszoneidnsname', error=unicode(e)) # check zone type if idnsname.is_empty(): common_types = u', '.join(_zone_top_record_types) elif zonename.is_reverse(): common_types = u', '.join(_rev_top_record_types) else: common_types = u', '.join(_top_record_types) self.Backend.textui.print_plain(_(u'Please choose a type of DNS resource record to be added')) self.Backend.textui.print_plain(_(u'The most common types for this type of zone are: %s\n') %\ common_types) ok = False while not ok: rrtype = self.Backend.textui.prompt(_(u'DNS resource record type')) if rrtype is None: return rrtype = rrtype.upper() try: name = record_name_format % rrtype.lower() param = self.params[name] if 'no_option' in param.flags: raise ValueError() except (KeyError, ValueError): all_types = u', '.join(get_record_rrtype(p.name) for p in self.params() if (get_record_rrtype(p.name) and 'no_option' not in p.flags)) self.Backend.textui.print_plain(_(u'Invalid or unsupported type. Allowed values are: %s') % all_types) continue ok = True user_options = prompt_parts(rrtype, self) kw.update(user_options)
class LocationTracker(Tracker): """Tracker for IPA Location tests""" retrieve_keys = { 'idnsname', 'description', 'dn', 'servers_server', 'dns_server' } retrieve_all_keys = retrieve_keys | {'objectclass'} create_keys = {'idnsname', 'description', 'dn', 'objectclass'} find_keys = { 'idnsname', 'description', 'dn', } find_all_keys = find_keys | {'objectclass'} update_keys = {'idnsname', 'description'} def __init__(self, name, description=u"Location description"): super(LocationTracker, self).__init__(default_version=None) # ugly hack to allow testing invalid inputs try: self.idnsname_obj = DNSName(name) except Exception: self.idnsname_obj = DNSName(u"placeholder-for-invalid-value") self.idnsname = name self.description = description self.dn = DN(('idnsname', self.idnsname_obj.ToASCII()), 'cn=locations', 'cn=etc', self.api.env.basedn) self.servers = {} def make_create_command(self): """Make function that creates this location using location-add""" return self.make_command( 'location_add', self.idnsname, description=self.description, ) def make_delete_command(self): """Make function that removes this location using location-del""" return self.make_command('location_del', self.idnsname) def make_retrieve_command(self, all=False, raw=False): """Make function that retrieves this location using location-show""" return self.make_command('location_show', self.idnsname, all=all, raw=raw) def make_find_command(self, *args, **kwargs): """Make function that finds locations using location-find""" return self.make_command('location_find', *args, **kwargs) def make_update_command(self, updates): """Make function that modifies the location using location-mod""" return self.make_command('location_mod', self.idnsname, **updates) def track_create(self): """Update expected state for location creation""" self.attrs = dict( dn=self.dn, idnsname=[self.idnsname_obj], description=[self.description], objectclass=[u'top', u'ipaLocationObject'], ) self.exists = True def check_create(self, result): """Check `location-add` command result""" assert_deepequal( dict(value=self.idnsname_obj, summary=u'Added IPA location "{loc}"'.format( loc=self.idnsname), result=self.filter_attrs(self.create_keys)), result) def check_delete(self, result): """Check `location-del` command result""" assert_deepequal( dict( value=[self.idnsname_obj], summary=u'Deleted IPA location "{loc}"'.format( loc=self.idnsname), result=dict(failed=[]), ), result) def check_retrieve(self, result, all=False, raw=False): """Check `location-show` command result""" if all: expected = self.filter_attrs(self.retrieve_all_keys) else: expected = self.filter_attrs(self.retrieve_keys) assert_deepequal( dict( value=self.idnsname_obj, summary=None, result=expected, servers=self.servers, ), result) def check_find(self, result, all=False, raw=False): """Check `location-find` command result""" if all: expected = self.filter_attrs(self.find_all_keys) else: expected = self.filter_attrs(self.find_keys) assert_deepequal( dict( count=1, truncated=False, summary=u'1 IPA location matched', result=[expected], ), result) def check_update(self, result, extra_keys=()): """Check `location-update` command result""" assert_deepequal( dict(value=self.idnsname_obj, summary=u'Modified IPA location "{loc}"'.format( loc=self.idnsname), result=self.filter_attrs(self.update_keys | set(extra_keys))), result) def add_server_to_location(self, server_name, weight=100, relative_weight=u"100.0%"): self.attrs.setdefault('servers_server', []).append(server_name) self.attrs.setdefault('dns_server', []).append(server_name) self.servers[server_name] = { 'cn': [server_name], 'ipaserviceweight': [unicode(weight)], 'service_relative_weight': [relative_weight], 'enabled_role_servrole': lambda other: True } def remove_server_from_location(self, server_name): if 'servers_server' in self.attrs: try: self.attrs['servers_server'].remove(server_name) self.attrs['dns_server'].remove(server_name) except ValueError: pass else: if not self.attrs['servers_server']: del self.attrs['servers_server'] if not self.attrs['dns_server']: del self.attrs['dns_server'] try: del self.servers[server_name] except KeyError: pass
def test_two_replicas_in_location(self): """Put second replica to location and test if records changed properly """ # create location paris, replica1 --> location prague self.master.run_command(['ipa', 'location-add', self.LOC_PARIS]) self.master.run_command([ 'ipa', 'server-mod', self.replicas[1].hostname, '--location', self.LOC_PARIS ]) tasks.restart_named(self.replicas[1]) servers_without_loc = ( (self.PRIO_HIGH, self.WEIGHT, DNSName(self.master.hostname)), (self.PRIO_HIGH, self.WEIGHT, DNSName(self.replicas[0].hostname)), (self.PRIO_HIGH, self.WEIGHT, DNSName(self.replicas[1].hostname)), ) domain_without_loc = DNSName(self.master.domain.name).make_absolute() servers_prague_loc = ( (self.PRIO_LOW, self.WEIGHT, DNSName(self.master.hostname)), (self.PRIO_HIGH, self.WEIGHT, DNSName(self.replicas[0].hostname)), (self.PRIO_LOW, self.WEIGHT, DNSName(self.replicas[1].hostname)), ) domain_prague_loc = (DNSName('{}._locations'.format(self.LOC_PRAGUE)) + DNSName(self.master.domain.name).make_absolute()) servers_paris_loc = ( (self.PRIO_LOW, self.WEIGHT, DNSName(self.master.hostname)), (self.PRIO_LOW, self.WEIGHT, DNSName(self.replicas[0].hostname)), (self.PRIO_HIGH, self.WEIGHT, DNSName(self.replicas[1].hostname)), ) domain_paris_loc = (DNSName('{}._locations'.format(self.LOC_PARIS)) + DNSName(self.master.domain.name).make_absolute()) self._test_against_server(self.replicas[0].ip, domain_prague_loc, servers_prague_loc) self._test_against_server(self.replicas[1].ip, domain_paris_loc, servers_paris_loc) self._test_against_server(self.master.ip, domain_without_loc, servers_without_loc)
def get_ipa_idnssoarname(self, **_kwargs): # pylint: disable=R1710 if self.ipa_params.admin_email is not None: return DNSName( self._replace_at_symbol_in_rname(self.ipa_params.admin_email))
def __setup_replica_keys(self): keylabel = replica_keylabel_template % DNSName(self.fqdn).\ make_absolute().canonicalize().ToASCII() ldap = api.Backend.ldap2 dn_base = DN(('cn', 'keys'), ('cn', 'sec'), ('cn', 'dns'), api.env.basedn) with open(paths.DNSSEC_SOFTHSM_PIN, "r") as f: pin = f.read() os.environ["SOFTHSM2_CONF"] = paths.DNSSEC_SOFTHSM2_CONF p11 = _ipap11helper.P11_Helper(SOFTHSM_DNSSEC_TOKEN_LABEL, pin, paths.LIBSOFTHSM2_SO) try: # generate replica keypair logger.debug("Creating replica's key pair") key_id = None while True: # check if key with this ID exist in softHSM key_id = _ipap11helper.gen_key_id() replica_pubkey_dn = DN(('ipk11UniqueId', 'autogenerate'), dn_base) pub_keys = p11.find_keys(_ipap11helper.KEY_CLASS_PUBLIC_KEY, label=keylabel, id=key_id) if pub_keys: # key with id exists continue priv_keys = p11.find_keys(_ipap11helper.KEY_CLASS_PRIVATE_KEY, label=keylabel, id=key_id) if not priv_keys: break # we found unique id public_key_handle, _privkey_handle = p11.generate_replica_key_pair( keylabel, key_id, pub_cka_verify=False, pub_cka_verify_recover=False, pub_cka_wrap=True, priv_cka_unwrap=True, priv_cka_sensitive=True, priv_cka_extractable=False) # export public key public_key_blob = p11.export_public_key(public_key_handle) # save key to LDAP replica_pubkey_objectclass = [ 'ipk11Object', 'ipk11PublicKey', 'ipaPublicKeyObject', 'top' ] kw = { 'objectclass': replica_pubkey_objectclass, 'ipk11UniqueId': [u'autogenerate'], 'ipk11Label': [keylabel], 'ipaPublicKey': [public_key_blob], 'ipk11Id': [key_id], 'ipk11Wrap': [True], 'ipk11Verify': [False], 'ipk11VerifyRecover': [False], } logger.debug("Storing replica public key to LDAP, %s", replica_pubkey_dn) entry = ldap.make_entry(replica_pubkey_dn, **kw) ldap.add_entry(entry) logger.debug("Replica public key stored") logger.debug("Setting CKA_WRAP=False for old replica keys") # first create new keys, we don't want disable keys before, we # have new keys in softhsm and LDAP # get replica pub keys with CKA_WRAP=True replica_pub_keys = p11.find_keys( _ipap11helper.KEY_CLASS_PUBLIC_KEY, label=keylabel, cka_wrap=True) # old keys in softHSM for handle in replica_pub_keys: # don't disable wrapping for new key # compare IDs not handle if key_id != p11.get_attribute(handle, _ipap11helper.CKA_ID): p11.set_attribute(handle, _ipap11helper.CKA_WRAP, False) # get old keys from LDAP search_kw = { 'objectclass': u"ipaPublicKeyObject", 'ipk11Label': keylabel, 'ipk11Wrap': True, } filter = ldap.make_filter(search_kw, rules=ldap.MATCH_ALL) entries, _truncated = ldap.find_entries(filter=filter, base_dn=dn_base) for entry in entries: # don't disable wrapping for new key if entry.single_value['ipk11Id'] != key_id: entry['ipk11Wrap'] = [False] ldap.update_entry(entry) finally: p11.finalize() # change tokens mod/owner logger.debug("Changing ownership of token files") for (root, dirs, files) in os.walk(paths.DNSSEC_TOKENS_DIR): for directory in dirs: dir_path = os.path.join(root, directory) os.chmod(dir_path, 0o770 | stat.S_ISGID) # chown to ods:named os.chown(dir_path, self.ods_uid, self.named_gid) for filename in files: file_path = os.path.join(root, filename) os.chmod(file_path, 0o770 | stat.S_ISGID) # chown to ods:named os.chown(file_path, self.ods_uid, self.named_gid)
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) hostname = keys[0] if len(keys) == 2: netbiosname = keys[1] else: # By default take leftmost label from the host name netbiosname = DNSName.from_text(hostname)[0].decode().upper() # SMB service requires existence of the host object # because DCE RPC calls authenticated with GSSAPI are using # host/.. principal by default for validation try: hostresult = self.api.Command['host_show'](hostname)['result'] except errors.NotFound: raise errors.NotFound( reason=_("The host '%s' does not exist to add a service to.") % hostname) # We cannot afford the host not being resolvable even for # clustered environments with CTDB because the target name # has to exist even in that case util.verify_host_resolvable(hostname) smbaccount = '{name}$'.format(name=netbiosname) smbprincipal = 'cifs/{hostname}'.format(hostname=hostname) entry_attrs['krbprincipalname'] = [ str(kerberos.Principal(smbprincipal, realm=self.api.env.realm)), str(kerberos.Principal(smbaccount, realm=self.api.env.realm)) ] entry_attrs['krbcanonicalname'] = entry_attrs['krbprincipalname'][0] # Rewrite DN using proper rdn and new canonical name because when # LDAPCreate.execute() was called, it set DN to krbcanonicalname=$value dn = DN(('krbprincipalname', entry_attrs['krbcanonicalname']), DN(self.obj.container_dn, api.env.basedn)) # Enforce ipaKrbPrincipalAlias to aid case-insensitive searches as # krbPrincipalName/krbCanonicalName are case-sensitive in Kerberos # schema entry_attrs['ipakrbprincipalalias'] = entry_attrs['krbcanonicalname'] for o in ('ipakrbprincipal', 'ipaidobject', 'krbprincipalaux', 'posixaccount'): if o not in entry_attrs['objectclass']: entry_attrs['objectclass'].append(o) entry_attrs['uid'] = [ '/'.join(kerberos.Principal(smbprincipal).components) ] entry_attrs['uid'].append(smbaccount) entry_attrs['cn'] = netbiosname entry_attrs['homeDirectory'] = '/dev/null' entry_attrs['uidNumber'] = DNA_MAGIC entry_attrs['gidNumber'] = DNA_MAGIC self.obj.validate_ipakrbauthzdata(entry_attrs) if 'managedby' not in entry_attrs: entry_attrs['managedby'] = hostresult['dn'] update_krbticketflags(ldap, entry_attrs, attrs_list, options, False) return dn
fuzzy_hex, raises_exact) from ipatests.test_xmlrpc.test_user_plugin import get_group_dn from ipatests.test_xmlrpc import objectclasses from ipatests.test_xmlrpc.tracker.host_plugin import HostTracker from ipatests.test_xmlrpc.testcert import get_testcert, subject_base from ipatests.util import assert_deepequal from ipaplatform.paths import paths # Constants DNS integration tests # TODO: Use tracker fixtures for zones/records/users/groups dnszone = u'test-zone.test' dnszone_absolute = dnszone + '.' dnszone_dn = DN(('idnsname', dnszone_absolute), api.env.container_dns, api.env.basedn) dnszone_rname = u'root.%s' % dnszone_absolute dnszone_rname_dnsname = DNSName(dnszone_rname) revzone = u'29.16.172.in-addr.arpa.' revzone_dn = DN(('idnsname', revzone), api.env.container_dns, api.env.basedn) revipv6zone = u'0.0.0.0.1.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.' revipv6zone_dn = DN(('idnsname', revipv6zone), api.env.container_dns, api.env.basedn) arec = u'172.16.29.22' aaaarec = u'2001:db8:1::beef' arec2 = u'172.16.29.33' aaaarec2 = u'2001:db8:1::dead' ipv4_fromip = u'testipv4fromip'
from dns.exception import DNSException from time import sleep, time from ipalib import errors from ipalib.dns import record_name_format from ipapython.dnsutil import DNSName, resolve_rrsets from ipapython.ipa_log_manager import root_logger if six.PY3: unicode=str IPA_DEFAULT_MASTER_SRV_REC = ( # srv record name, port (DNSName(u'_ldap._tcp'), 389), (DNSName(u'_kerberos._tcp'), 88), (DNSName(u'_kerberos._udp'), 88), (DNSName(u'_kerberos-master._tcp'), 88), (DNSName(u'_kerberos-master._udp'), 88), (DNSName(u'_kpasswd._tcp'), 464), (DNSName(u'_kpasswd._udp'), 464), ) IPA_DEFAULT_ADTRUST_SRV_REC = ( # srv record name, port (DNSName(u'_ldap._tcp.Default-First-Site-Name._sites.dc._msdcs'), 389), (DNSName(u'_ldap._tcp.dc._msdcs'), 389), (DNSName(u'_kerberos._tcp.Default-First-Site-Name._sites.dc._msdcs'), 88), (DNSName(u'_kerberos._udp.Default-First-Site-Name._sites.dc._msdcs'), 88), (DNSName(u'_kerberos._tcp.dc._msdcs'), 88),
def zone_is_reverse(zone_name): return DNSName(zone_name).is_reverse()
def __init__(self, api_instance): self.api_instance = api_instance self.domain_abs = DNSName(self.api_instance.env.domain).make_absolute() self.servers_data = {} self.__init_data()