def dns_transaction_tcp(self, packet, host, dump=False, timeout=None): "send a DNS query and read the reply, also return the raw packet" s = None if timeout is None: timeout = self.timeout try: send_packet = ndr.ndr_pack(packet) if dump: print(self.hexdump(send_packet)) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) s.settimeout(timeout) s.connect((host, 53)) tcp_packet = struct.pack('!H', len(send_packet)) tcp_packet += send_packet s.sendall(tcp_packet) recv_packet = s.recv(0xffff + 2, 0) if dump: print(self.hexdump(recv_packet)) response = ndr.ndr_unpack(dns.name_packet, recv_packet[2:]) finally: if s is not None: s.close() # unpacking and packing again should produce same bytestream my_packet = ndr.ndr_pack(response) self.assertEquals(my_packet, recv_packet[2:]) return (response, recv_packet[2:])
def test_no_flag_recursive_forwarder(self): ad = contact_real_server(server_ip, 53) name = "dsfsfds.dsfsdfs" p = self.make_name_packet(dns.DNS_OPCODE_QUERY) questions = [] q = self.make_name_question(name, dns.DNS_QTYPE_TXT, dns.DNS_QCLASS_IN) questions.append(q) self.finish_name_packet(p, questions) send_packet = ndr.ndr_pack(p) self.finish_name_packet(p, questions) # Leave off the recursive flag send_packet = ndr.ndr_pack(p) ad.send(send_packet, 0) ad.settimeout(timeout) try: data = ad.recv(0xffff + 2, 0) data = ndr.ndr_unpack(dns.name_packet, data) self.assert_dns_rcode_equals(data, dns.DNS_RCODE_NXDOMAIN) self.assertEqual(data.ancount, 0) except socket.timeout: self.fail("DNS server is too slow (timeout %s)" % timeout)
def verify_packet(self, response, response_packet, request_mac=""): self.assertEqual(response.additional[0].rr_type, dns.DNS_QTYPE_TSIG) tsig_record = response.additional[0].rdata mac = ''.join([chr(x) for x in tsig_record.mac]) # Cut off tsig record from dns response packet for MAC verification # and reset additional record count. key_name_len = len(self.key_name) + 2 tsig_record_len = len(ndr.ndr_pack(tsig_record)) + key_name_len + 10 response_packet_list = list(response_packet) del response_packet_list[-tsig_record_len:] response_packet_list[11] = chr(0) response_packet_wo_tsig = ''.join(response_packet_list) fake_tsig = dns.fake_tsig_rec() fake_tsig.name = self.key_name fake_tsig.rr_class = dns.DNS_QCLASS_ANY fake_tsig.ttl = 0 fake_tsig.time_prefix = tsig_record.time_prefix fake_tsig.time = tsig_record.time fake_tsig.algorithm_name = tsig_record.algorithm_name fake_tsig.fudge = tsig_record.fudge fake_tsig.error = 0 fake_tsig.other_size = 0 fake_tsig_packet = ndr.ndr_pack(fake_tsig) data = request_mac + response_packet_wo_tsig + fake_tsig_packet self.g.check_packet(data, data, mac)
def add_at_record(samdb, container_dn, prefix, hostname, dnsdomain, hostip, hostip6): fqdn_hostname = "%s.%s" % (hostname, dnsdomain) at_records = [] # SOA record at_soa_record = SOARecord(fqdn_hostname, "hostmaster.%s" % dnsdomain) at_records.append(ndr_pack(at_soa_record)) # NS record at_ns_record = NSRecord(fqdn_hostname) at_records.append(ndr_pack(at_ns_record)) if hostip is not None: # A record at_a_record = ARecord(hostip) at_records.append(ndr_pack(at_a_record)) if hostip6 is not None: # AAAA record at_aaaa_record = AAAARecord(hostip6) at_records.append(ndr_pack(at_aaaa_record)) msg = ldb.Message(ldb.Dn(samdb, "DC=@,%s" % container_dn)) msg["objectClass"] = ["top", "dnsNode"] msg["dnsRecord"] = ldb.MessageElement(at_records, ldb.FLAG_MOD_ADD, "dnsRecord") samdb.add(msg)
def test_no_active_forwarder(self): ad = contact_real_server(server_ip, 53) name = "dsfsfds.dsfsdfs" p = self.make_name_packet(dns.DNS_OPCODE_QUERY) questions = [] q = self.make_name_question(name, dns.DNS_QTYPE_TXT, dns.DNS_QCLASS_IN) questions.append(q) self.finish_name_packet(p, questions) send_packet = ndr.ndr_pack(p) self.finish_name_packet(p, questions) p.operation |= dns.DNS_FLAG_RECURSION_DESIRED send_packet = ndr.ndr_pack(p) ad.send(send_packet, 0) ad.settimeout(timeout) try: data = ad.recv(0xffff + 2, 0) data = ndr.ndr_unpack(dns.name_packet, data) self.assert_dns_rcode_equals(data, dns.DNS_RCODE_SERVFAIL) self.assertEqual(data.ancount, 0) except socket.timeout: self.fail("DNS server is too slow (timeout %s)" % timeout)
def _samdb_fetch_pfm_and_schi(self): """Fetch prefixMap and schemaInfo stored in SamDB using LDB connection""" samdb = self.ldb_dc1 res = samdb.search(base=samdb.get_schema_basedn(), scope=SCOPE_BASE, attrs=["prefixMap", "schemaInfo"]) pfm = ndr_unpack(drsblobs.prefixMapBlob, str(res[0]['prefixMap'])) schi = drsuapi.DsReplicaOIDMapping() schi.id_prefix = 0 if 'schemaInfo' in res[0]: schi.oid.length = len(map(ord, str(res[0]['schemaInfo']))) schi.oid.binary_oid = map(ord, str(res[0]['schemaInfo'])) else: schema_info = drsblobs.schemaInfoBlob() schema_info.revision = 0 schema_info.marker = 0xFF schema_info.invocation_id = misc.GUID(samdb.get_invocation_id()) schi.oid.length = len(map(ord, ndr_pack(schema_info))) schi.oid.binary_oid = map(ord, ndr_pack(schema_info)) pfm.ctr.mappings = pfm.ctr.mappings + [schi] pfm.ctr.num_mappings += 1 return pfm.ctr
def __init__(self, attid, flags, identifier, targetGUID): self.attid = attid self.flags = flags self.identifier = str(identifier) self.selfGUID_blob = ndr_pack(identifier) self.targetGUID = str(targetGUID) self.targetGUID_blob = ndr_pack(targetGUID)
def _test_pack_unpack(self, desc, cycles=5000, cls=security.descriptor): blob2 = ndr_pack(desc) for i in range(SCALE * cycles): blob = ndr_pack(desc) desc = ndr_unpack(cls, blob) self.assertEqual(blob, blob2)
def s4_zone_create(s4connector, object): _d=ud.function('s4_zone_create') zoneDn, zoneName=__create_default_s4_zone_dn(s4connector, object) # Create the forward zone in S4 if it does not exist try: searchResult=s4connector.lo_s4.lo.search_s(zoneDn, ldap.SCOPE_BASE, '(objectClass=*)',['dn']) except ldap.NO_SUCH_OBJECT: __create_s4_forward_zone(s4connector, zoneDn, zoneName) # Create @ object zoneDnAt='DC=@,%s' % zoneDn old_dnsRecords=[] try: searchResult=s4connector.lo_s4.lo.search_s(zoneDnAt, ldap.SCOPE_BASE, '(objectClass=*)') if searchResult and searchResult[0][1]: old_dnsRecords=searchResult[0][1].get('dnsRecord') except ldap.NO_SUCH_OBJECT: __create_s4_forward_zone_at(s4connector, zoneDnAt, zoneName) dnsRecords=[] __pack_nsRecord(object, dnsRecords) __pack_soaRecord(object, dnsRecords) # The IP address of the DNS forward zone will be used to determine the # sysvol share. On a selective replicated DC only a short list of DCs # should be returned aRecords = s4connector.configRegistry.get('connector/s4/mapping/dns/forward_zone/%s/static/ipv4' % zoneName[0].lower()) aAAARecords = s4connector.configRegistry.get('connector/s4/mapping/dns/forward_zone/%s/static/ipv6' % zoneName[0].lower()) if aRecords or aAAARecords: #IPv4 if aRecords: for a in aRecords.split(' '): a=univention.s4connector.s4.compatible_modstring(a) a_record=ARecord(a) dnsRecords.append(ndr_pack(a_record)) #IPv6 if aAAARecords: for a in aAAARecords.split(' '): a=univention.s4connector.s4.compatible_modstring(a) a_record=AAAARecord(a) dnsRecords.append(ndr_pack(a_record)) else: __pack_aRecord(object, dnsRecords) __pack_mxRecord(object, dnsRecords) s4connector.lo_s4.modify(zoneDnAt, [('dnsRecord', old_dnsRecords, dnsRecords)]) return True
def save_profile(self, profile): # Check if profile exists cn = profile.get('cn', None) # Check if profile exists old_profile = None if cn is not None: ldap_filter = '(CN=%s)' % cn old_profile_data = self._get_ldap_profile_data(ldap_filter) if old_profile_data: old_profile = self._data_to_profile(old_profile_data) if old_profile is not None: logging.debug('Profile with cn %s already exists. Modifying' % cn) logging.debug('Old profile: %s' % old_profile) logging.debug('New profile: %s' % profile) # Modify existing profile sd = self._security_descriptor_from_profile(profile) gpo_uuid = profile['cn'] ldif = [ (ldap.MOD_REPLACE, 'displayName', (FC_PROFILE_PREFIX % profile['name']).encode()), (ldap.MOD_REPLACE, 'description', profile['description'].encode()), (ldap.MOD_REPLACE, 'nTSecurityDescriptor', ndr_pack(sd)), ] logging.debug('LDIF data to be sent to LDAP: %s' % ldif) dn = "CN=%s,CN=Policies,CN=System,%s" % ( gpo_uuid, self._get_domain_dn()) logging.debug('Modifying profile under %s' % dn) self.connection.modify_s(dn, ldif) self._save_smb_data(gpo_uuid, profile, sd.as_sddl()) else: logging.debug('Saving new profile') # Create new profile gpo_uuid = self._generate_gpo_uuid() logging.debug('New profile UUID = %s' % gpo_uuid) attrs = self.GPO_BASE_ATTRIBUTES.copy() attrs['cn'] = gpo_uuid.encode() attrs['displayName'] = (FC_PROFILE_PREFIX % profile['name']).encode() attrs['description'] = profile['description'].encode() attrs['gPCFileSysPath'] = (GPO_SMB_PATH % ( self._get_server_name(), self.domain, gpo_uuid)).encode() logging.debug('Preparing security descriptor') sd = self._security_descriptor_from_profile(profile) attrs['nTSecurityDescriptor'] = ndr_pack(sd) logging.debug('Profile data to be sent to LDAP: %s' % attrs) ldif = ldap.modlist.addModlist(attrs) logging.debug('LDIF data to be sent to LDAP: %s' % ldif) dn = "CN=%s,CN=Policies,CN=System,%s" % ( gpo_uuid, self._get_domain_dn()) logging.debug('Adding profile under %s' % dn) self.connection.add_s(dn, ldif) # Save SMB data self._save_smb_data(gpo_uuid, profile, sd.as_sddl()) return gpo_uuid
def __pack_mxRecord(object, dnsRecords): for mXRecord in object['attributes'].get('mXRecord', []): if mXRecord: ud.debug(ud.LDAP, ud.INFO, '__pack_mxRecord: %s' % mXRecord) mXRecord=univention.s4connector.s4.compatible_modstring(mXRecord) mx=mXRecord.split(' ') priority=mx[0] name=mx[1] mx_record=MXRecord(name, int(priority)) dnsRecords.append(ndr_pack(mx_record)) ud.debug(ud.LDAP, ud.INFO, '__pack_mxRecord: %s' % ndr_pack(mx_record))
def add_rootservers(samdb, domaindn, prefix): rootservers = {} rootservers["a.root-servers.net"] = "198.41.0.4" rootservers["b.root-servers.net"] = "192.228.79.201" rootservers["c.root-servers.net"] = "192.33.4.12" rootservers["d.root-servers.net"] = "128.8.10.90" rootservers["e.root-servers.net"] = "192.203.230.10" rootservers["f.root-servers.net"] = "192.5.5.241" rootservers["g.root-servers.net"] = "192.112.36.4" rootservers["h.root-servers.net"] = "128.63.2.53" rootservers["i.root-servers.net"] = "192.36.148.17" rootservers["j.root-servers.net"] = "192.58.128.30" rootservers["k.root-servers.net"] = "193.0.14.129" rootservers["l.root-servers.net"] = "199.7.83.42" rootservers["m.root-servers.net"] = "202.12.27.33" rootservers_v6 = {} rootservers_v6["a.root-servers.net"] = "2001:503:ba3e::2:30" rootservers_v6["f.root-servers.net"] = "2001:500:2f::f" rootservers_v6["h.root-servers.net"] = "2001:500:1::803f:235" rootservers_v6["j.root-servers.net"] = "2001:503:c27::2:30" rootservers_v6["k.root-servers.net"] = "2001:7fd::1" rootservers_v6["m.root-servers.net"] = "2001:dc3::35" container_dn = "DC=RootDNSServers,CN=MicrosoftDNS,%s,%s" % (prefix, domaindn) # Add DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN> msg = ldb.Message(ldb.Dn(samdb, container_dn)) msg["objectClass"] = ["top", "dnsZone"] msg["cn"] = ldb.MessageElement("Zone", ldb.FLAG_MOD_ADD, "cn") samdb.add(msg) # Add DC=@,DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN> record = [] for rserver in rootservers: record.append(ndr_pack(NSRecord(rserver, serial=0, ttl=0, rank=dnsp.DNS_RANK_ROOT_HINT))) msg = ldb.Message(ldb.Dn(samdb, "DC=@,%s" % container_dn)) msg["objectClass"] = ["top", "dnsNode"] msg["dnsRecord"] = ldb.MessageElement(record, ldb.FLAG_MOD_ADD, "dnsRecord") samdb.add(msg) # Add DC=<rootserver>,DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN> for rserver in rootservers: record = [ndr_pack(ARecord(rootservers[rserver], serial=0, ttl=0, rank=dnsp.DNS_RANK_ROOT_HINT))] # Add AAAA record as well (How does W2K* add IPv6 records?) #if rserver in rootservers_v6: # record.append(ndr_pack(AAAARecord(rootservers_v6[rserver], serial=0, ttl=0))) msg = ldb.Message(ldb.Dn(samdb, "DC=%s,%s" % (rserver, container_dn))) msg["objectClass"] = ["top", "dnsNode"] msg["dnsRecord"] = ldb.MessageElement(record, ldb.FLAG_MOD_ADD, "dnsRecord") samdb.add(msg)
def add_host_record(samdb, container_dn, prefix, hostip, hostip6): host_records = [] if hostip: a_record = ARecord(hostip) host_records.append(ndr_pack(a_record)) if hostip6: aaaa_record = AAAARecord(hostip6) host_records.append(ndr_pack(aaaa_record)) if host_records: msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn))) msg["objectClass"] = ["top", "dnsNode"] msg["dnsRecord"] = ldb.MessageElement(host_records, ldb.FLAG_MOD_ADD, "dnsRecord") samdb.add(msg)
def add_domain_record(samdb, domaindn, prefix, dnsdomain, domainsid, dnsadmins_sid): # DC=<DNSDOMAIN>,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN> sddl = "O:SYG:BAD:AI" \ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA)" \ "(A;;CC;;;AU)" \ "(A;;RPLCLORC;;;WD)" \ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \ "(A;CI;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)" \ "(A;CIID;RPWPCRCCDCLCRCWOWDSDDTSW;;;%s)" \ "(A;CIID;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)" \ "(OA;CIID;RPWPCR;91e647de-d96f-4b70-9557-d63ff4f3ccd8;;PS)" \ "(A;CIID;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \ "(A;CIID;LC;;;RU)" \ "(A;CIID;RPWPCRCCLCLORCWOWDSDSW;;;BA)" \ "S:AI" % dnsadmins_sid sec = security.descriptor.from_sddl(sddl, domainsid) props = [] props.append(ndr_pack(TypeProperty())) props.append(ndr_pack(AllowUpdateProperty())) props.append(ndr_pack(SecureTimeProperty())) props.append(ndr_pack(NorefreshIntervalProperty(norefresh_interval=168))) props.append(ndr_pack(RefreshIntervalProperty(refresh_interval=168))) props.append(ndr_pack(AgingStateProperty())) props.append(ndr_pack(AgingEnabledTimeProperty())) msg = ldb.Message(ldb.Dn(samdb, "DC=%s,CN=MicrosoftDNS,%s,%s" % (dnsdomain, prefix, domaindn))) msg["objectClass"] = ["top", "dnsZone"] msg["ntSecurityDescriptor"] = ldb.MessageElement(ndr_pack(sec), ldb.FLAG_MOD_ADD, "nTSecurityDescriptor") msg["dNSProperty"] = ldb.MessageElement(props, ldb.FLAG_MOD_ADD, "dNSProperty") samdb.add(msg)
def __pack_aRecord(object, dnsRecords): # add aRecords #IPv4 for a in object['attributes'].get('aRecord', []): a=univention.s4connector.s4.compatible_modstring(a) a_record=ARecord(a) dnsRecords.append(ndr_pack(a_record)) #IPv6 for a in object['attributes'].get('aAAARecord', []): a=univention.s4connector.s4.compatible_modstring(a) a_record=AAAARecord(a) dnsRecords.append(ndr_pack(a_record))
def test_cname_forwarding_with_server_down(self): if len(dns_servers) < 2: print("Ignoring test_cname_forwarding_with_server_down") return s2 = self.start_toy_server(dns_servers[1], 53, 'forwarder2') name1 = 'resolve1.cname.%s' % self.get_dns_domain() name2 = 'resolve2.cname.%s' % self.get_dns_domain() self.make_cname_update(name1, name2) self.make_cname_update(name2, "dsfsfds.dsfsdfs") ad = contact_real_server(server_ip, 53) p = self.make_name_packet(dns.DNS_OPCODE_QUERY) questions = [] q = self.make_name_question(name1, dns.DNS_QTYPE_A, dns.DNS_QCLASS_IN) questions.append(q) self.finish_name_packet(p, questions) p.operation |= dns.DNS_FLAG_RECURSION_DESIRED send_packet = ndr.ndr_pack(p) ad.send(send_packet, 0) ad.settimeout(timeout) try: data = ad.recv(0xffff + 2, 0) data = ndr.ndr_unpack(dns.name_packet, data) self.assert_dns_rcode_equals(data, dns.DNS_RCODE_OK) self.assertEqual('forwarder2', data.answers[-1].rdata) except socket.timeout: self.fail("DNS server is too slow (timeout %s)" % timeout)
def test_double_cname(self): s1 = self.start_toy_server(dns_servers[0], 53, 'forwarder1') name = 'resolve.cname.%s' % self.get_dns_domain() self.make_cname_update(name, "dsfsfds.dsfsdfs") ad = contact_real_server(server_ip, 53) p = self.make_name_packet(dns.DNS_OPCODE_QUERY) questions = [] q = self.make_name_question(name, dns.DNS_QTYPE_A, dns.DNS_QCLASS_IN) questions.append(q) self.finish_name_packet(p, questions) p.operation |= dns.DNS_FLAG_RECURSION_DESIRED send_packet = ndr.ndr_pack(p) ad.send(send_packet, 0) ad.settimeout(timeout) try: data = ad.recv(0xffff + 2, 0) data = ndr.ndr_unpack(dns.name_packet, data) self.assert_dns_rcode_equals(data, dns.DNS_RCODE_OK) self.assertEqual('forwarder1', data.answers[1].rdata) except socket.timeout: self.fail("DNS server is too slow (timeout %s)" % timeout)
def test_double_forwarder_both_slow(self): if len(dns_servers) < 2: print("Ignoring test_double_forwarder_both_slow") return s1 = self.start_toy_server(dns_servers[0], 53, 'forwarder1') s2 = self.start_toy_server(dns_servers[1], 53, 'forwarder2') s1.send('timeout 1.5', 0) s2.send('timeout 1.5', 0) ad = contact_real_server(server_ip, 53) name = "dsfsfds.dsfsdfs" p = self.make_name_packet(dns.DNS_OPCODE_QUERY) questions = [] q = self.make_name_question(name, dns.DNS_QTYPE_CNAME, dns.DNS_QCLASS_IN) questions.append(q) self.finish_name_packet(p, questions) p.operation |= dns.DNS_FLAG_RECURSION_DESIRED send_packet = ndr.ndr_pack(p) ad.send(send_packet, 0) ad.settimeout(timeout) try: data = ad.recv(0xffff + 2, 0) data = ndr.ndr_unpack(dns.name_packet, data) self.assert_dns_rcode_equals(data, dns.DNS_RCODE_OK) self.assertEqual('forwarder1', data.answers[0].rdata) except socket.timeout: self.fail("DNS server is too slow (timeout %s)" % timeout)
def test_wbint_Principals(self): principals = [] for i in range(0, 10): x = winbind.wbint_Principal() x.sid = security.dom_sid(security.SID_NT_SCHANNEL_AUTHENTICATION) x.type = lsa.SID_NAME_USER x.name = None principals.append(x) wb_principals = winbind.wbint_Principals() wb_principals.num_principals = 10 wb_principals.principals = principals b = ndr.ndr_pack(wb_principals) unpacked_principals = ndr.ndr_unpack(winbind.wbint_Principals, b) self.assertEqual(wb_principals.num_principals, unpacked_principals.num_principals) for i in range(0, 10): x = principals[i] y = unpacked_principals.principals[i] self.assertEqual(x.sid, y.sid) self.assertEqual(x.type, y.type) self.assertEqual(x.name, y.name)
def _test_wbint_Principals(self, num): principals = [] for i in range(0, num): x = winbind.wbint_Principal() x.sid = security.dom_sid(security.SID_NT_SCHANNEL_AUTHENTICATION + "-%d" % num) x.type = lsa.SID_NAME_USER x.name = "fred%d" % num principals.append(x) wb_principals = winbind.wbint_Principals() wb_principals.num_principals = num wb_principals.principals = principals b = ndr.ndr_pack(wb_principals) try: unpacked_principals = ndr.ndr_unpack(winbind.wbint_Principals, b) except RuntimeError as e: self.fail(e) self.assertEqual(wb_principals.num_principals, unpacked_principals.num_principals) return (principals, unpacked_principals)
def test_duplicate_objectSIDs_not_allowed_on_local_objects(self): dom_sid = self.samdb.get_domain_sid() rid = self.allocate_rid() sid_str = str(dom_sid) + "-" + rid sid = ndr_pack(security.dom_sid(sid_str)) basedn = self.samdb.get_default_basedn() cn = "dsdb_test_01" dn = "cn=%s,cn=Users,%s" % (cn, basedn) self.samdb.add({ "dn": dn, "objectClass": "user", "objectSID": sid}) self.samdb.delete(dn) try: self.samdb.add({ "dn": dn, "objectClass": "user", "objectSID": sid}) self.fail("No exception should get LDB_ERR_CONSTRAINT_VIOLATION") except ldb.LdbError as e: (code, msg) = e.args if code != ldb.ERR_CONSTRAINT_VIOLATION: self.fail("Got %d - %s should have got " "LDB_ERR_CONSTRAINT_VIOLATION" % (code, msg))
def test_cname(self): s1 = self.start_toy_server(dns_servers[0], 53, 'forwarder1') ad = contact_real_server(server_ip, 53) name = "resolve.cname" p = self.make_name_packet(dns.DNS_OPCODE_QUERY) questions = [] q = self.make_name_question(name, dns.DNS_QTYPE_CNAME, dns.DNS_QCLASS_IN) questions.append(q) self.finish_name_packet(p, questions) p.operation |= dns.DNS_FLAG_RECURSION_DESIRED send_packet = ndr.ndr_pack(p) ad.send(send_packet, 0) ad.settimeout(timeout) try: data = ad.recv(0xffff + 2, 0) data = ndr.ndr_unpack(dns.name_packet, data) self.assert_dns_rcode_equals(data, dns.DNS_RCODE_OK) self.assertEqual(len(data.answers), 1) self.assertEqual('forwarder1', data.answers[0].rdata) except socket.timeout: self.fail("DNS server is too slow (timeout %s)" % timeout)
def test_modify_nonreplicated_reps_attributes(self): # some timestamp ones dn = self.base_dn m = ldb.Message() m.dn = ldb.Dn(self.samdb, dn) attr = 'repsFrom' res = self.samdb.search(dn, scope=ldb.SCOPE_BASE, attrs=['repsFrom']) rep = ndr_unpack(drsblobs.repsFromToBlob, res[0]['repsFrom'][0], allow_remaining=True) rep.ctr.result_last_attempt = -1 value = ndr_pack(rep) m[attr] = ldb.MessageElement(value, ldb.FLAG_MOD_REPLACE, attr) try: self.samdb.modify(m) self.fail("Failed to fail to modify %s %s" % (dn, attr)) except ldb.LdbError as (ecode, emsg): if ecode != ldb.ERR_REFERRAL: self.fail("Failed to REFER when trying to modify %s %s" % (dn, attr)) else: m = re.search(r'(ldap://[^>]+)>', emsg) if m is None: self.fail("referral seems not to refer to anything") address = m.group(1) if address.lower().startswith(self.samdb.domain_dns_name()): self.fail("referral address did not give a specific DC")
def send_pdu(self, req, ndr_print=None, hexdump=None): if ndr_print is None: ndr_print = self.do_ndr_print if hexdump is None: hexdump = self.do_hexdump try: req_pdu = ndr_pack(req) if ndr_print: sys.stderr.write("send_pdu: %s" % samba.ndr.ndr_print(req)) if hexdump: sys.stderr.write("send_pdu: %d\n%s" % (len(req_pdu), self.hexdump(req_pdu))) while True: sent = self.s.send(req_pdu, 0) if sent == len(req_pdu): break req_pdu = req_pdu[sent:] except socket.error as e: self._disconnect("send_pdu: %s" % e) raise except IOError as e: self._disconnect("send_pdu: %s" % e) raise finally: pass
def _samdb_fetch_pfm_and_schi(self): """Fetch prefixMap and schemaInfo stored in SamDB using LDB connection""" samdb = self.ldb_dc1 res = samdb.search(base=samdb.get_schema_basedn(), scope=SCOPE_BASE, attrs=["prefixMap", "schemaInfo"]) pfm = ndr_unpack(drsblobs.prefixMapBlob, res[0]['prefixMap'][0]) schi = drsuapi.DsReplicaOIDMapping() schi.id_prefix = 0 if 'schemaInfo' in res[0]: binary_oid = [x if isinstance(x, int) else ord(x) for x in res[0]['schemaInfo'][0]] schi.oid.length = len(binary_oid) schi.oid.binary_oid = binary_oid else: schema_info = drsblobs.schemaInfoBlob() schema_info.revision = 0 schema_info.marker = 0xFF schema_info.invocation_id = misc.GUID(samdb.get_invocation_id()) binary_oid = [x if isinstance(x, int) else ord(x) for x in ndr_pack(schema_info)] # you have to set the length before setting binary_oid schi.oid.length = len(binary_oid) schi.oid.binary_oid = binary_oid pfm.ctr.mappings = pfm.ctr.mappings + [schi] pfm.ctr.num_mappings += 1 return pfm.ctr
def err_missing_sd_owner(self, dn, sd): '''re-write the SD due to a missing owner or group''' sd_attr = "nTSecurityDescriptor" sd_val = ndr_pack(sd) sd_flags = security.SECINFO_OWNER | security.SECINFO_GROUP if not self.confirm_all('Fix missing owner or group in %s on %s?' % (sd_attr, dn), 'fix_ntsecuritydescriptor_owner_group'): self.report('Not fixing missing owner or group %s on %s\n' % (sd_attr, dn)) return nmsg = ldb.Message() nmsg.dn = dn nmsg[sd_attr] = ldb.MessageElement(sd_val, ldb.FLAG_MOD_REPLACE, sd_attr) # By setting the session_info to admin_session_info and # setting the security.SECINFO_OWNER | security.SECINFO_GROUP # flags we cause the descriptor module to set the correct # owner and group on the SD, replacing the None/NULL values # for owner_sid and group_sid currently present. # # The admin_session_info matches that used in provision, and # is the best guess we can make for an existing object that # hasn't had something specifically set. # # This is important for the dns related naming contexts. self.samdb.set_session_info(self.admin_session_info) if self.do_modify(nmsg, ["sd_flags:1:%d" % sd_flags], "Failed to fix metadata for attribute %s" % sd_attr): self.report("Fixed attribute '%s' of '%s'\n" % (sd_attr, dn)) self.samdb.set_session_info(self.system_session_info)
def test_cname_forwarding_with_server_down(self): if len(dns_servers) < 2: print "Ignoring test_cname_forwarding_with_server_down" return s2 = self.start_toy_server(dns_servers[1], 53, 'forwarder2') name1 = 'resolve1.cname.%s' % self.get_dns_domain() name2 = 'resolve2.cname.%s' % self.get_dns_domain() self.make_cname_update(name1, name2) self.make_cname_update(name2, "dsfsfds.dsfsdfs") ad = contact_real_server(server_ip, 53) p = self.make_name_packet(dns.DNS_OPCODE_QUERY) questions = [] q = self.make_name_question(name1, dns.DNS_QTYPE_A, dns.DNS_QCLASS_IN) questions.append(q) self.finish_name_packet(p, questions) p.operation |= dns.DNS_FLAG_RECURSION_DESIRED send_packet = ndr.ndr_pack(p) ad.send(send_packet, 0) ad.settimeout(timeout) try: data = ad.recv(0xffff + 2, 0) data = ndr.ndr_unpack(dns.name_packet, data) self.assert_dns_rcode_equals(data, dns.DNS_RCODE_OK) self.assertEqual('forwarder2', data.answers[-1].rdata) except socket.timeout: self.fail("DNS server is too slow (timeout %s)" % timeout)
def generate_pdu(self, ptype, call_id, payload, rpc_vers=5, rpc_vers_minor=0, pfc_flags=(samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST | samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST), drep=[samba.dcerpc.dcerpc.DCERPC_DREP_LE, 0, 0, 0], ndr_print=None, hexdump=None): if getattr(payload, 'auth_info', None): ai = payload.auth_info else: ai = b"" p = samba.dcerpc.dcerpc.ncacn_packet() p.rpc_vers = rpc_vers p.rpc_vers_minor = rpc_vers_minor p.ptype = ptype p.pfc_flags = pfc_flags p.drep = drep p.frag_length = 0 if len(ai) > samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH: p.auth_length = len(ai) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH else: p.auth_length = 0 p.call_id = call_id p.u = payload pdu = ndr_pack(p) p.frag_length = len(pdu) return p
def test_array_from_ndr(self): rmd = drsblobs.replPropertyMetaDataBlob() rmd.version = 1 rmd.ctr = drsblobs.replPropertyMetaDataCtr1() rmd.ctr.count = 3 rmd1 = drsblobs.replPropertyMetaData1() rmd1.attid = 1 rmd1.version = 2 rmd2 = drsblobs.replPropertyMetaData1() rmd2.attid = 2 rmd2.version = 2 rmd3 = drsblobs.replPropertyMetaData1() rmd3.attid = 3 rmd3.version = 2 rmd.ctr.array = [rmd1, rmd2, rmd3] packed = ndr_pack(rmd) gc.collect() rmd_unpacked = ndr_unpack(drsblobs.replPropertyMetaDataBlob, packed) self.assertIsNotNone(rmd_unpacked) self.assertEqual(rmd_unpacked.version, 1) self.assertIsNotNone(rmd_unpacked.ctr) self.assertEqual(rmd_unpacked.ctr.count, 3) self.assertEqual(len(rmd_unpacked.ctr.array), rmd_unpacked.ctr.count) self.assertIsNotNone(rmd_unpacked.ctr.array[0]) self.assertEqual(rmd_unpacked.ctr.array[0].attid, 1) self.assertEqual(rmd.ctr.array[0].attid, rmd_unpacked.ctr.array[0].attid)
def test_double_forwarder_both_slow(self): if len(dns_servers) < 2: print "Ignoring test_double_forwarder_both_slow" return s1 = self.start_toy_server(dns_servers[0], 53, 'forwarder1') s2 = self.start_toy_server(dns_servers[1], 53, 'forwarder2') s1.send('timeout 1.5', 0) s2.send('timeout 1.5', 0) ad = contact_real_server(server_ip, 53) name = "dsfsfds.dsfsdfs" p = self.make_name_packet(dns.DNS_OPCODE_QUERY) questions = [] q = self.make_name_question(name, dns.DNS_QTYPE_CNAME, dns.DNS_QCLASS_IN) questions.append(q) self.finish_name_packet(p, questions) p.operation |= dns.DNS_FLAG_RECURSION_DESIRED send_packet = ndr.ndr_pack(p) ad.send(send_packet, 0) ad.settimeout(timeout) try: data = ad.recv(0xffff + 2, 0) data = ndr.ndr_unpack(dns.name_packet, data) self.assert_dns_rcode_equals(data, dns.DNS_RCODE_OK) self.assertEqual('forwarder1', data.answers[0].rdata) except socket.timeout: self.fail("DNS server is too slow (timeout %s)" % timeout)
def handle(self): data, sock = self.request query = ndr.ndr_unpack(dns.name_packet, data) name = query.questions[0].name forwarder = self.forwarder(name) response = None if forwarder is 'ignore': return elif forwarder is 'fail': pass elif forwarder is not None: response = self.dns_transaction_udp(query, forwarder) else: response = query response.operation |= dns.DNS_FLAG_REPLY response.operation |= dns.DNS_FLAG_RECURSION_AVAIL response.operation |= dns.DNS_RCODE_NXDOMAIN if response is None: response = query response.operation |= dns.DNS_FLAG_REPLY response.operation |= dns.DNS_FLAG_RECURSION_AVAIL response.operation |= dns.DNS_RCODE_SERVFAIL send_packet = ndr.ndr_pack(response) print("dns_hub: sending %s to address %s for name %s\n" % (forwarder, self.client_address, name)) try: sock.sendto(send_packet, self.client_address) except socket.error as err: print("Error sending %s to address %s for name %s: %s\n" % (forwarder, self.client_address, name, err))
def s4_srv_record_create(s4connector, object): _d=ud.function('s4_srv_record_create') dnsRecords=[] zoneDn, zoneName=__create_default_s4_zone_dn(s4connector, object) relativeDomainName=object['attributes'].get('relativeDomainName') relativeDomainName=univention.s4connector.s4.compatible_list(relativeDomainName) # ucr set connector/s4/mapping/dns/srv_record/_ldap._tcp.test.local/location='100 0 389 foobar.test.local.' # ucr set connector/s4/mapping/dns/srv_record/_ldap._tcp.test.local/location='100 0 389 foobar.test.local. 100 0 389 foobar2.test.local.' ucr_locations = s4connector.configRegistry.get('connector/s4/mapping/dns/srv_record/%s.%s/location' % (relativeDomainName[0].lower(),zoneName[0].lower())) ud.debug(ud.LDAP, ud.INFO, 's4_srv_record_create: ucr_locations for connector/s4/mapping/dns/srv_record/%s.%s/location: %s' % (relativeDomainName[0].lower(),zoneName[0].lower(),ucr_locations)) if ucr_locations: if ucr_locations.lower() == 'ignore': return # Convert ucr variable priority=None; weight=None; port=None; target=None for v in ucr_locations.split(' '): # Check explicit for None, because the int values may be 0 if priority == None: priority=int(v) elif weight == None: weight=int(v) elif port == None: port=int(v) elif not target: target=__remove_dot(v) if priority != None and weight != None and port != None and target: ud.debug(ud.LDAP, ud.INFO, 'priority=%d weight=%d port=%d target=%s' % (priority,weight,port,target)) s=SRVRecord(target, port, priority, weight) dnsRecords.append(ndr_pack(s)) priority=None; weight=None; port=None; target=None else: __pack_sRVrecord(object, dnsRecords) dnsNodeDn=s4_dns_node_base_create(s4connector, object, dnsRecords)
def dns_transaction_udp(self, packet, host): "send a DNS query and read the reply" s = None flags = socket.AddressInfo.AI_NUMERICHOST flags |= socket.AddressInfo.AI_NUMERICSERV flags |= socket.AddressInfo.AI_PASSIVE addr_info = socket.getaddrinfo(host, int(53), type=socket.SocketKind.SOCK_DGRAM, flags=flags) assert len(addr_info) == 1 try: send_packet = ndr.ndr_pack(packet) s = socket.socket(addr_info[0][0], addr_info[0][1], 0) s.settimeout(DNS_REQUEST_TIMEOUT) s.connect(addr_info[0][4]) s.sendall(send_packet, 0) recv_packet = s.recv(2048, 0) return ndr.ndr_unpack(dns.name_packet, recv_packet) except socket.error as err: print("Error sending to host %s for name %s: %s\n" % (host, packet.questions[0].name, err.errno)) raise finally: if s is not None: s.close() return None
def test_one_a_reply(self): "send a reply instead of a query" global timeout p = self.make_name_packet(dns.DNS_OPCODE_QUERY) questions = [] name = "%s.%s" % ('fakefakefake', self.get_dns_domain()) q = self.make_name_question(name, dns.DNS_QTYPE_A, dns.DNS_QCLASS_IN) print "asking for ", q.name questions.append(q) self.finish_name_packet(p, questions) p.operation |= dns.DNS_FLAG_REPLY s = None try: send_packet = ndr.ndr_pack(p) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) s.settimeout(timeout) host = self.server_ip s.connect((host, 53)) tcp_packet = struct.pack('!H', len(send_packet)) tcp_packet += send_packet s.send(tcp_packet, 0) recv_packet = s.recv(0xffff + 2, 0) self.assertEquals(0, len(recv_packet)) except socket.timeout: # Windows chooses not to respond to incorrectly formatted queries. # Although this appears to be non-deterministic even for the same # request twice, it also appears to be based on a how poorly the # request is formatted. pass finally: if s is not None: s.close()
def get_schema_descriptor(domain_sid, name_map={}): sddl = "O:SAG:SAD:AI(OA;;CR;e12b56b6-0a95-11d1-adbb-00c04fd8d5cd;;SA)" \ "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \ "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \ "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \ "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \ "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \ "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \ "(A;CI;RPLCLORC;;;AU)" \ "(A;CI;RPWPCRCCLCLORCWOWDSW;;;SA)" \ "(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \ "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \ "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \ "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \ "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \ "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ER)" \ "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ER)" \ "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ER)" \ "S:(AU;SA;WPCCDCWOWDSDDTSW;;;WD)" \ "(AU;CISA;WP;;;WD)" \ "(AU;SA;CR;;;BA)" \ "(AU;SA;CR;;;DU)" \ "(OU;SA;CR;e12b56b6-0a95-11d1-adbb-00c04fd8d5cd;;WD)" \ "(OU;SA;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;WD)" sec = security.descriptor.from_sddl(sddl, domain_sid) return ndr_pack(sec)
def join_add_ntdsdsa(ctx): '''add the ntdsdsa object''' print "Adding %s" % ctx.ntds_dn rec = { "dn" : ctx.ntds_dn, "objectclass" : "nTDSDSA", "systemFlags" : str(samba.dsdb.SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE), "dMDLocation" : ctx.schema_dn} nc_list = [ ctx.base_dn, ctx.config_dn, ctx.schema_dn ] if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003: rec["msDS-Behavior-Version"] = str(samba.dsdb.DS_DOMAIN_FUNCTION_2008_R2) if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003: rec["msDS-HasDomainNCs"] = ctx.base_dn if ctx.RODC: rec["objectCategory"] = "CN=NTDS-DSA-RO,%s" % ctx.schema_dn rec["msDS-HasFullReplicaNCs"] = ctx.nc_list rec["options"] = "37" ctx.samdb.add(rec, ["rodc_join:1:1"]) else: rec["objectCategory"] = "CN=NTDS-DSA,%s" % ctx.schema_dn rec["HasMasterNCs"] = nc_list if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003: rec["msDS-HasMasterNCs"] = ctx.nc_list rec["options"] = "1" rec["invocationId"] = ndr_pack(ctx.invocation_id) ctx.DsAddEntry([rec]) # find the GUID of our NTDS DN res = ctx.samdb.search(base=ctx.ntds_dn, scope=ldb.SCOPE_BASE, attrs=["objectGUID"]) ctx.ntds_guid = misc.GUID(ctx.samdb.schema_format_value("objectGUID", res[0]["objectGUID"][0]))
def generate_auth(self, auth_type=None, auth_level=None, auth_pad_length=0, auth_context_id=None, auth_blob=None, ndr_print=None, hexdump=None): if ndr_print is None: ndr_print = self.do_ndr_print if hexdump is None: hexdump = self.do_hexdump if auth_type is not None: a = samba.dcerpc.dcerpc.auth() a.auth_type = auth_type a.auth_level = auth_level a.auth_pad_length = auth_pad_length a.auth_context_id = auth_context_id a.credentials = auth_blob ai = ndr_pack(a) if ndr_print: sys.stderr.write("generate_auth: %s" % samba.ndr.ndr_print(a)) if hexdump: sys.stderr.write("generate_auth: %d\n%s" % (len(ai), self.hexdump(ai))) else: ai = "" return ai
def add_group_from_mapping_entry(samdb, groupmap, logger): """Add or modify group from group mapping entry param samdb: Samba4 SAM database param groupmap: Groupmap entry param logger: Logger object """ # First try to see if we already have this entry try: msg = samdb.search(base='<SID=%s>' % str(groupmap.sid), scope=ldb.SCOPE_BASE) found = True except ldb.LdbError as e1: (ecode, emsg) = e1.args if ecode == ldb.ERR_NO_SUCH_OBJECT: found = False else: raise ldb.LdbError(ecode, emsg) if found: logger.warn( 'Group already exists sid=%s, groupname=%s existing_groupname=%s, Ignoring.', str(groupmap.sid), groupmap.nt_name, msg[0]['sAMAccountName'][0]) else: if groupmap.sid_name_use == lsa.SID_NAME_WKN_GRP: # In a lot of Samba3 databases, aliases are marked as well known groups (group_dom_sid, rid) = groupmap.sid.split() if (group_dom_sid != security.dom_sid(security.SID_BUILTIN)): return m = ldb.Message() # We avoid using the format string to avoid needing to escape the CN values m.dn = ldb.Dn(samdb, "CN=X,CN=Users") m.dn.set_component(0, "CN", groupmap.nt_name) m.dn.add_base(samdb.get_default_basedn()) m['objectClass'] = ldb.MessageElement('group', ldb.FLAG_MOD_ADD, 'objectClass') m['objectSid'] = ldb.MessageElement(ndr_pack(groupmap.sid), ldb.FLAG_MOD_ADD, 'objectSid') m['sAMAccountName'] = ldb.MessageElement(groupmap.nt_name, ldb.FLAG_MOD_ADD, 'sAMAccountName') if groupmap.comment: m['description'] = ldb.MessageElement(groupmap.comment, ldb.FLAG_MOD_ADD, 'description') # Fix up incorrect 'well known' groups that are actually builtin (per test above) to be aliases if groupmap.sid_name_use == lsa.SID_NAME_ALIAS or groupmap.sid_name_use == lsa.SID_NAME_WKN_GRP: m['groupType'] = ldb.MessageElement( str(dsdb.GTYPE_SECURITY_DOMAIN_LOCAL_GROUP), ldb.FLAG_MOD_ADD, 'groupType') try: samdb.add(m, controls=["relax:0"]) except ldb.LdbError as e: logger.warn('Could not add group name=%s (%s)', groupmap.nt_name, str(e))
def test_one_a_reply(self): "send a reply instead of a query" p = self.make_name_packet(dns.DNS_OPCODE_QUERY) questions = [] name = "%s.%s" % ('fakefakefake', self.get_dns_domain()) q = self.make_name_question(name, dns.DNS_QTYPE_A, dns.DNS_QCLASS_IN) print "asking for ", q.name questions.append(q) self.finish_name_packet(p, questions) p.operation |= dns.DNS_FLAG_REPLY s = None try: send_packet = ndr.ndr_pack(p) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) host = os.getenv('SERVER_IP') s.connect((host, 53)) tcp_packet = struct.pack('!H', len(send_packet)) tcp_packet += send_packet s.send(tcp_packet, 0) recv_packet = s.recv(0xffff + 2, 0) self.assertEquals(0, len(recv_packet)) finally: if s is not None: s.close()
def join_add_ntdsdsa(ctx): '''add the ntdsdsa object''' # FIXME: the partition (NC) assignment has to be made dynamic print "Adding %s" % ctx.ntds_dn rec = { "dn" : ctx.ntds_dn, "objectclass" : "nTDSDSA", "systemFlags" : str(samba.dsdb.SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE), "dMDLocation" : ctx.schema_dn} nc_list = [ ctx.base_dn, ctx.config_dn, ctx.schema_dn ] if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003: rec["msDS-Behavior-Version"] = str(ctx.behavior_version) if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003: rec["msDS-HasDomainNCs"] = ctx.base_dn if ctx.RODC: rec["objectCategory"] = "CN=NTDS-DSA-RO,%s" % ctx.schema_dn rec["msDS-HasFullReplicaNCs"] = nc_list rec["options"] = "37" ctx.samdb.add(rec, ["rodc_join:1:1"]) else: rec["objectCategory"] = "CN=NTDS-DSA,%s" % ctx.schema_dn rec["HasMasterNCs"] = nc_list if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003: rec["msDS-HasMasterNCs"] = nc_list rec["options"] = "1" rec["invocationId"] = ndr_pack(ctx.invocation_id) ctx.DsAddEntry([rec]) # find the GUID of our NTDS DN res = ctx.samdb.search(base=ctx.ntds_dn, scope=ldb.SCOPE_BASE, attrs=["objectGUID"]) ctx.ntds_guid = misc.GUID(ctx.samdb.schema_format_value("objectGUID", res[0]["objectGUID"][0]))
def test_cname_forwarding_with_lots_of_cnames(self): name3 = 'resolve3.cname.%s' % self.get_dns_domain() s1 = self.start_toy_server(dns_servers[0], 53, name3) name1 = 'resolve1.cname.%s' % self.get_dns_domain() name2 = 'resolve2.cname.%s' % self.get_dns_domain() self.make_cname_update(name1, name2) self.make_cname_update(name3, name1) self.make_cname_update(name2, "dsfsfds.dsfsdfs") ad = contact_real_server(server_ip, 53) p = self.make_name_packet(dns.DNS_OPCODE_QUERY) questions = [] q = self.make_name_question(name1, dns.DNS_QTYPE_A, dns.DNS_QCLASS_IN) questions.append(q) self.finish_name_packet(p, questions) p.operation |= dns.DNS_FLAG_RECURSION_DESIRED send_packet = ndr.ndr_pack(p) ad.send(send_packet, 0) ad.settimeout(timeout) try: data = ad.recv(0xffff + 2, 0) data = ndr.ndr_unpack(dns.name_packet, data) # This should cause a loop in Windows # (which is restricted by a 20 CNAME limit) # # The reason it doesn't here is because forwarded CNAME have no # additional processing in the internal DNS server. self.assert_dns_rcode_equals(data, dns.DNS_RCODE_OK) self.assertEqual(name3, data.answers[-1].rdata) except socket.timeout: self.fail("DNS server is too slow (timeout %s)" % timeout)
def modify_descriptor(self, samdb, object_dn, desc, controls=None): assert (isinstance(desc, security.descriptor)) m = ldb.Message() m.dn = ldb.Dn(samdb, object_dn) m["nTSecurityDescriptor"] = ldb.MessageElement( (ndr_pack(desc)), ldb.FLAG_MOD_REPLACE, "nTSecurityDescriptor") samdb.modify(m)
def newgroup( self, groupname, groupou=None, grouptype=None, description=None, mailaddress=None, notes=None, sd=None ): """Adds a new group with additional parameters :param groupname: Name of the new group :param grouptype: Type of the new group :param description: Description of the new group :param mailaddress: Email address of the new group :param notes: Notes of the new group :param sd: security descriptor of the object """ group_dn = "CN=%s,%s,%s" % (groupname, (groupou or "CN=Users"), self.domain_dn()) # The new user record. Note the reliance on the SAMLDB module which # fills in the default informations ldbmessage = {"dn": group_dn, "sAMAccountName": groupname, "objectClass": "group"} if grouptype is not None: ldbmessage["groupType"] = normalise_int32(grouptype) if description is not None: ldbmessage["description"] = description if mailaddress is not None: ldbmessage["mail"] = mailaddress if notes is not None: ldbmessage["info"] = notes if sd is not None: ldbmessage["nTSecurityDescriptor"] = ndr_pack(sd) self.add(ldbmessage)
def test_modify_nonreplicated_reps_attributes(self): # some timestamp ones dn = self.base_dn m = ldb.Message() m.dn = ldb.Dn(self.samdb, dn) attr = 'repsFrom' res = self.samdb.search(dn, scope=ldb.SCOPE_BASE, attrs=['repsFrom']) rep = ndr_unpack(drsblobs.repsFromToBlob, res[0]['repsFrom'][0], allow_remaining=True) rep.ctr.result_last_attempt = -1 value = ndr_pack(rep) m[attr] = ldb.MessageElement(value, ldb.FLAG_MOD_REPLACE, attr) try: self.samdb.modify(m) self.fail("Failed to fail to modify %s %s" % (dn, attr)) except ldb.LdbError as e3: (ecode, emsg) = e3.args if ecode != ldb.ERR_REFERRAL: self.fail("Failed to REFER when trying to modify %s %s" % (dn, attr)) else: m = re.search(r'(ldap://[^>]+)>', emsg) if m is None: self.fail("referral seems not to refer to anything") address = m.group(1) if address.lower().startswith(self.samdb.domain_dns_name()): self.fail("referral address did not give a specific DC")
def get_schema_descriptor(domain_sid): sddl = "O:SAG:SAD:AI(OA;;CR;e12b56b6-0a95-11d1-adbb-00c04fd8d5cd;;SA)" \ "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \ "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \ "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \ "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \ "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \ "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \ "(A;CI;RPLCLORC;;;AU)" \ "(A;CI;RPWPCRCCLCLORCWOWDSW;;;SA)" \ "(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \ "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \ "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \ "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \ "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \ "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ER)" \ "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ER)" \ "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ER)" \ "S:(AU;SA;WPCCDCWOWDSDDTSW;;;WD)" \ "(AU;CISA;WP;;;WD)" \ "(AU;SA;CR;;;BA)" \ "(AU;SA;CR;;;DU)" \ "(OU;SA;CR;e12b56b6-0a95-11d1-adbb-00c04fd8d5cd;;WD)" \ "(OU;SA;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;WD)" sec = security.descriptor.from_sddl(sddl, domain_sid) return ndr_pack(sec)
def test_one_a_reply(self): "send a reply instead of a query" p = self.make_name_packet(dns.DNS_OPCODE_QUERY) questions = [] name = "%s.%s" % ('fakefakefake', self.get_dns_domain()) q = self.make_name_question(name, dns.DNS_QTYPE_A, dns.DNS_QCLASS_IN) print "asking for ", q.name questions.append(q) self.finish_name_packet(p, questions) p.operation |= dns.DNS_FLAG_REPLY s = None try: send_packet = ndr.ndr_pack(p) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) host=os.getenv('SERVER_IP') s.connect((host, 53)) tcp_packet = struct.pack('!H', len(send_packet)) tcp_packet += send_packet s.send(tcp_packet, 0) recv_packet = s.recv(0xffff + 2, 0) self.assertEquals(0, len(recv_packet)) finally: if s is not None: s.close()
def test_one_a_reply(self): "send a reply instead of a query" global timeout p = self.make_name_packet(dns.DNS_OPCODE_QUERY) questions = [] name = "%s.%s" % ('fakefakefake', self.get_dns_domain()) q = self.make_name_question(name, dns.DNS_QTYPE_A, dns.DNS_QCLASS_IN) print "asking for ", q.name questions.append(q) self.finish_name_packet(p, questions) p.operation |= dns.DNS_FLAG_REPLY s = None try: send_packet = ndr.ndr_pack(p) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) s.settimeout(timeout) host=self.server_ip s.connect((host, 53)) tcp_packet = struct.pack('!H', len(send_packet)) tcp_packet += send_packet s.send(tcp_packet, 0) recv_packet = s.recv(0xffff + 2, 0) self.assertEquals(0, len(recv_packet)) except socket.timeout: # Windows chooses not to respond to incorrectly formatted queries. # Although this appears to be non-deterministic even for the same # request twice, it also appears to be based on a how poorly the # request is formatted. pass finally: if s is not None: s.close()
def rename_or_modify_idmap_entry(old_sambaSID, new_sambaSID, xidNumber, type_string, idmap=None): if not idmap: # need to open idmap here in case it has been removed since the module was loaded idmap = open_idmap() try: res = idmap.search('', ldb.SCOPE_SUBTREE, "(&(objectClass=sidMap)(cn=%s))" % old_sambaSID, attrs=["objectSid", "type"]) if not res: univention.debug.debug( univention.debug.LISTENER, univention.debug.INFO, "%s: rename_or_modify_idmap_entry: no mapping for objectSid %s, treating as add", (name, old_sambaSID)) add_or_modify_idmap_entry(new_sambaSID, xidNumber, type_string, idmap) else: record = res.msgs[0] if record["type"][0] != type_string: univention.debug.debug( univention.debug.LISTENER, univention.debug.ERROR, "%s: %s entry type %s does not match object type %s" % (name, old_sambaSID, record["type"][0], type_string)) univention.debug.debug( univention.debug.LISTENER, univention.debug.ERROR, "%s: skipping rename of %s to %s" % (name, old_sambaSID, new_sambaSID)) return False univention.debug.debug( univention.debug.LISTENER, univention.debug.PROCESS, "%s: renaming entry for %s to %s" % (name, old_sambaSID, new_sambaSID)) # try a modrdn idmap.rename(str(record.dn), "CN=%s" % new_sambaSID) # and update related attributes msg = ldb.Message() msg.dn = ldb.Dn(idmap, "CN=%s" % new_sambaSID) msg["cn"] = ldb.MessageElement([new_sambaSID], ldb.FLAG_MOD_REPLACE, "cn") new_objectSid = ndr_pack(security.dom_sid(new_sambaSID)) msg["objectSid"] = ldb.MessageElement([new_objectSid], ldb.FLAG_MOD_REPLACE, "objectSid") idmap.modify(msg) except ldb.LdbError as exc: (enum, estr) = exc.args univention.debug.debug(univention.debug.LISTENER, univention.debug.WARN, estr) # ok, there is an entry for the target sambaSID, let's remove the old sambaSID and modify the target remove_idmap_entry(old_sambaSID, xidNumber, type_string, idmap) modify_idmap_entry(new_sambaSID, xidNumber, type_string, idmap)
def add_cname_record(samdb, container_dn, prefix, host): cname_record = CNameRecord(host) msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn))) msg["objectClass"] = ["top", "dnsNode"] msg["dnsRecord"] = ldb.MessageElement(ndr_pack(cname_record), ldb.FLAG_MOD_ADD, "dnsRecord") samdb.add(msg)
def add_ns_glue_record(samdb, container_dn, prefix, host): ns_record = NSRecord(host, rank=dnsp.DNS_RANK_NS_GLUE) msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn))) msg["objectClass"] = ["top", "dnsNode"] msg["dnsRecord"] = ldb.MessageElement(ndr_pack(ns_record), ldb.FLAG_MOD_ADD, "dnsRecord") samdb.add(msg)
def sddl2binary(sddl_in, domain_sid, name_map): sddl = "%s" % sddl_in for [name, sid] in name_map.items(): sddl = sddl.replace(name, sid) sec = security.descriptor.from_sddl(sddl, domain_sid) return ndr_pack(sec)
def modify_descriptor(self, samdb, object_dn, desc, controls=None): assert(isinstance(desc, security.descriptor)) m = ldb.Message() m.dn = ldb.Dn(samdb, object_dn) m["nTSecurityDescriptor"]= ldb.MessageElement( (ndr_pack(desc)), ldb.FLAG_MOD_REPLACE, "nTSecurityDescriptor") samdb.modify(m)
def join_add_objects2(ctx): """add the various objects needed for the join, for subdomains post replication""" print "Adding %s" % ctx.partition_dn # NOTE: windows sends a ntSecurityDescriptor here, we # let it default rec = { "dn" : ctx.partition_dn, "objectclass" : "crossRef", "objectCategory" : "CN=Cross-Ref,%s" % ctx.schema_dn, "nCName" : ctx.base_dn, "nETBIOSName" : ctx.domain_name, "dnsRoot": ctx.dnsdomain, "trustParent" : ctx.parent_partition_dn, "systemFlags" : str(samba.dsdb.SYSTEM_FLAG_CR_NTDS_NC|samba.dsdb.SYSTEM_FLAG_CR_NTDS_DOMAIN)} if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003: rec["msDS-Behavior-Version"] = str(ctx.behavior_version) rec2 = { "dn" : ctx.ntds_dn, "objectclass" : "nTDSDSA", "systemFlags" : str(samba.dsdb.SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE), "dMDLocation" : ctx.schema_dn} nc_list = [ ctx.base_dn, ctx.config_dn, ctx.schema_dn ] if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003: rec2["msDS-Behavior-Version"] = str(ctx.behavior_version) if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003: rec2["msDS-HasDomainNCs"] = ctx.base_dn rec2["objectCategory"] = "CN=NTDS-DSA,%s" % ctx.schema_dn rec2["HasMasterNCs"] = nc_list if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003: rec2["msDS-HasMasterNCs"] = ctx.nc_list rec2["options"] = "1" rec2["invocationId"] = ndr_pack(ctx.invocation_id) objects = ctx.DsAddEntry([rec, rec2]) if len(objects) != 2: raise DCJoinException("Expected 2 objects from DsAddEntry") ctx.ntds_guid = objects[1].guid print("Replicating partition DN") ctx.repl.replicate(ctx.partition_dn, misc.GUID("00000000-0000-0000-0000-000000000000"), ctx.ntds_guid, exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ, replica_flags=drsuapi.DRSUAPI_DRS_WRIT_REP) print("Replicating NTDS DN") ctx.repl.replicate(ctx.ntds_dn, misc.GUID("00000000-0000-0000-0000-000000000000"), ctx.ntds_guid, exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ, replica_flags=drsuapi.DRSUAPI_DRS_WRIT_REP)
def set_attribute_replmetadata_version(self, dn, att, value, addifnotexist=False): res = self.search(expression="distinguishedName=%s" % dn, scope=ldb.SCOPE_SUBTREE, controls=["search_options:1:2"], attrs=["replPropertyMetaData"]) if len(res) == 0: return None repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, res[0]["replPropertyMetaData"][0]) ctr = repl.ctr now = samba.unix2nttime(int(time.time())) found = False if len(self.hash_oid_name.keys()) == 0: self._populate_oid_attid() for o in ctr.array: # Search for Description att_oid = self.get_oid_from_attid(o.attid) if att_oid in self.hash_oid_name and\ att.lower() == self.hash_oid_name[att_oid].lower(): found = True seq = self.sequence_number(ldb.SEQ_NEXT) o.version = value o.originating_change_time = now o.originating_invocation_id = misc.GUID( self.get_invocation_id()) o.originating_usn = seq o.local_usn = seq if not found and addifnotexist and len(ctr.array) > 0: o2 = drsblobs.replPropertyMetaData1() o2.attid = 589914 att_oid = self.get_oid_from_attid(o2.attid) seq = self.sequence_number(ldb.SEQ_NEXT) o2.version = value o2.originating_change_time = now o2.originating_invocation_id = misc.GUID(self.get_invocation_id()) o2.originating_usn = seq o2.local_usn = seq found = True tab = ctr.array tab.append(o2) ctr.count = ctr.count + 1 ctr.array = tab if found: replBlob = ndr_pack(repl) msg = ldb.Message() msg.dn = res[0].dn msg["replPropertyMetaData"] = \ ldb.MessageElement(replBlob, ldb.FLAG_MOD_REPLACE, "replPropertyMetaData") self.modify(msg, ["local_oid:1.3.6.1.4.1.7165.4.3.14:0"])
def newgroup(self, groupname, groupou=None, grouptype=None, description=None, mailaddress=None, notes=None, sd=None, gidnumber=None, nisdomain=None): """Adds a new group with additional parameters :param groupname: Name of the new group :param grouptype: Type of the new group :param description: Description of the new group :param mailaddress: Email address of the new group :param notes: Notes of the new group :param gidnumber: GID Number of the new group :param nisdomain: NIS Domain Name of the new group :param sd: security descriptor of the object """ group_dn = "CN=%s,%s,%s" % (groupname, (groupou or "CN=Users"), self.domain_dn()) # The new user record. Note the reliance on the SAMLDB module which # fills in the default informations ldbmessage = { "dn": group_dn, "sAMAccountName": groupname, "objectClass": "group" } ldbmessage["msSFU30Name"] = groupname if grouptype is not None: ldbmessage["groupType"] = normalise_int32(grouptype) if description is not None: ldbmessage["description"] = description if mailaddress is not None: ldbmessage["mail"] = mailaddress if notes is not None: ldbmessage["info"] = notes if gidnumber is not None: ldbmessage["gidNumber"] = normalise_int32(gidnumber) if nisdomain is not None: ldbmessage["msSFU30NisDomain"] = nisdomain if sd is not None: ldbmessage["nTSecurityDescriptor"] = ndr_pack(sd) self.add(ldbmessage)
def generate_auth(self, trustdom_secret): def arcfour_encrypt(key, data): c = RC4.RC4(key) return c.update(data) def string_to_array(what): blob = [0] * len(what) for i in range(len(what)): blob[i] = ord(what[i]) return blob password_blob = string_to_array(trustdom_secret.encode('utf-16-le')) clear_value = drsblobs.AuthInfoClear() clear_value.size = len(password_blob) clear_value.password = password_blob clear_authentication_information = drsblobs.AuthenticationInformation() clear_authentication_information.LastUpdateTime = samba.unix2nttime( int(time.time())) clear_authentication_information.AuthType = lsa.TRUST_AUTH_TYPE_CLEAR clear_authentication_information.AuthInfo = clear_value authentication_information_array = drsblobs.AuthenticationInformationArray( ) authentication_information_array.count = 1 authentication_information_array.array = [ clear_authentication_information ] outgoing = drsblobs.trustAuthInOutBlob() outgoing.count = 1 outgoing.current = authentication_information_array confounder = [3] * 512 for i in range(512): confounder[i] = random.randint(0, 255) trustpass = drsblobs.trustDomainPasswords() trustpass.confounder = confounder trustpass.outgoing = outgoing trustpass.incoming = outgoing trustpass_blob = ndr_pack(trustpass) encrypted_trustpass = arcfour_encrypt(self._pipe.session_key, trustpass_blob) auth_blob = lsa.DATA_BUF2() auth_blob.size = len(encrypted_trustpass) auth_blob.data = string_to_array(encrypted_trustpass) auth_info = lsa.TrustDomainInfoAuthInfoInternal() auth_info.auth_blob = auth_blob self.auth_info = auth_info
def sign_packet(self, packet, key_name): "Sign a packet, calculate a MAC and add TSIG record" packet_data = ndr.ndr_pack(packet) fake_tsig = dns.fake_tsig_rec() fake_tsig.name = key_name fake_tsig.rr_class = dns.DNS_QCLASS_ANY fake_tsig.ttl = 0 fake_tsig.time_prefix = 0 fake_tsig.time = int(time.time()) fake_tsig.algorithm_name = "gss-tsig" fake_tsig.fudge = 300 fake_tsig.error = 0 fake_tsig.other_size = 0 fake_tsig_packet = ndr.ndr_pack(fake_tsig) data = packet_data + fake_tsig_packet mac = self.g.sign_packet(data, data) mac_list = [ord(x) for x in list(mac)] rdata = dns.tsig_record() rdata.algorithm_name = "gss-tsig" rdata.time_prefix = 0 rdata.time = fake_tsig.time rdata.fudge = 300 rdata.original_id = packet.id rdata.error = 0 rdata.other_size = 0 rdata.mac = mac_list rdata.mac_size = len(mac_list) r = dns.res_rec() r.name = key_name r.rr_type = dns.DNS_QTYPE_TSIG r.rr_class = dns.DNS_QCLASS_ANY r.ttl = 0 r.length = 0xffff r.rdata = rdata additional = [r] packet.additional = additional packet.arcount = 1 return mac
def sid_to_s4(s4connector, key, object): ud.debug(ud.LDAP, ud.INFO, "sid_to_s4 object: %s" % object) sidAttribute = 'sambaSID' if s4connector.configRegistry.is_false('connector/s4/mapping/sid', False): ud.debug( ud.LDAP, ud.INFO, 'sid_to_s4: SID mapping is disabled via UCR: connector/s4/mapping/sid' ) sidAttribute = 'univentionSamba4SID' else: # This case will be handled by direct mapping return # object dn was already mapped to the s4 DN: s4_dn = object['dn'] modlist = [] # search the ucs object via if not object['attributes'].has_key(sidAttribute): ud.debug(ud.LDAP, ud.INFO, 'sid_to_s4: UCS object does not have a %s' % sidAttribute) return sambaSID = object['attributes'][sidAttribute] # get the ad sid (s4_dn, s4_attributes) = s4connector.lo_s4.lo.search_s(s4_dn, ldap.SCOPE_BASE, '(objectSid=*)', ['objectSid'])[0] objectSid = s4_attributes.get('objectSid') if objectSid: # decoded_s4_sid = univention.s4connector.s4.decode_sid(objectSid[0]) s4_objectSid = ndr_unpack(security.dom_sid, objectSid[0]) decoded_s4_sid = str(s4_objectSid) if decoded_s4_sid == sambaSID[0]: ud.debug(ud.LDAP, ud.INFO, 'sid_to_s4: objectSid and %s are equal' % sidAttribute) return ### change objectSID # http://serverfault.com/questions/53717/how-can-i-change-the-sid-of-a-user-account-in-the-active-directory # http://technet.microsoft.com/en-us/library/cc961998.aspx ud.debug( ud.LDAP, ud.INFO, 'sid_to_s4: changing objectSid from %s to %s' % (decoded_s4_sid, sambaSID[0])) new_objectSid_ndr = ndr_pack(security.dom_sid(sambaSID[0])) modlist.append((ldap.MOD_REPLACE, 'objectSid', new_objectSid_ndr)) # objectSid modification for an Samba4 object is only possible with the "provision" control: LDB_CONTROL_PROVISION_OID = '1.3.6.1.4.1.7165.4.3.16' controls = [LDAPControl(LDB_CONTROL_PROVISION_OID, criticality=0)] s4connector.lo_s4.lo.modify_ext_s(s4_dn, modlist, serverctrls=controls) pass