static void unbecomeDC_send_cldap(struct libnet_UnbecomeDC_state *s) { struct composite_context *c = s->creq; struct tevent_req *req; s->cldap.io.in.dest_address = s->source_dsa.address; s->cldap.io.in.dest_port = lp_cldap_port(s->libnet->lp_ctx); s->cldap.io.in.realm = s->domain.dns_name; s->cldap.io.in.host = s->dest_dsa.netbios_name; s->cldap.io.in.user = NULL; s->cldap.io.in.domain_guid = NULL; s->cldap.io.in.domain_sid = NULL; s->cldap.io.in.acct_control = -1; s->cldap.io.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; s->cldap.io.in.map_response = true; c->status = cldap_socket_init(s, s->libnet->event_ctx, NULL, NULL, &s->cldap.sock);//TODO if (!composite_is_ok(c)) return; req = cldap_netlogon_send(s, s->cldap.sock, &s->cldap.io); if (composite_nomem(req, c)) return; tevent_req_set_callback(req, unbecomeDC_recv_cldap, s); }
/* * find out Site specific stuff: * 1. Lookup the Site name. * 2. Add entry CN=<netbios name>,CN=Servers,CN=<site name>,CN=Sites,CN=Configuration,<domain dn>. * TODO: 3.) use DsAddEntry() to create CN=NTDS Settings,CN=<netbios name>,CN=Servers,CN=<site name>,... */ NTSTATUS libnet_JoinSite(struct libnet_context *ctx, struct ldb_context *remote_ldb, struct libnet_JoinDomain *libnet_r) { NTSTATUS status; TALLOC_CTX *tmp_ctx; struct libnet_JoinSite *r; struct ldb_dn *server_dn; struct ldb_message *msg; int rtn; const char *server_dn_str; const char *config_dn_str; struct nbt_name name; const char *dest_addr = NULL; tmp_ctx = talloc_named(libnet_r, 0, "libnet_JoinSite temp context"); if (!tmp_ctx) { libnet_r->out.error_string = NULL; return NT_STATUS_NO_MEMORY; } r = talloc(tmp_ctx, struct libnet_JoinSite); if (!r) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } make_nbt_name_client(&name, libnet_r->out.samr_binding->host); status = resolve_name(lp_resolve_context(ctx->lp_ctx), &name, r, &dest_addr, ctx->event_ctx); if (!NT_STATUS_IS_OK(status)) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return status; } /* Resolve the site name and AD DN's. */ r->in.dest_address = dest_addr; r->in.netbios_name = libnet_r->in.netbios_name; r->in.domain_dn_str = libnet_r->out.domain_dn_str; r->in.cldap_port = lp_cldap_port(ctx->lp_ctx); status = libnet_FindSite(tmp_ctx, ctx, r); if (!NT_STATUS_IS_OK(status)) { libnet_r->out.error_string = talloc_steal(libnet_r, r->out.error_string); talloc_free(tmp_ctx); return status; } config_dn_str = r->out.config_dn_str; server_dn_str = r->out.server_dn_str; /* Add entry CN=<netbios name>,CN=Servers,CN=<site name>,CN=Sites,CN=Configuration,<domain dn>. */ msg = ldb_msg_new(tmp_ctx); if (!msg) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rtn = ldb_msg_add_string(msg, "objectClass", "server"); if (rtn != 0) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rtn = ldb_msg_add_string(msg, "systemFlags", "50000000"); if (rtn != 0) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rtn = ldb_msg_add_string(msg, "serverReference", libnet_r->out.account_dn_str); if (rtn != 0) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } server_dn = ldb_dn_new(tmp_ctx, remote_ldb, server_dn_str); if ( ! ldb_dn_validate(server_dn)) { libnet_r->out.error_string = talloc_asprintf(libnet_r, "Invalid server dn: %s", server_dn_str); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } msg->dn = server_dn; rtn = ldb_add(remote_ldb, msg); if (rtn == LDB_ERR_ENTRY_ALREADY_EXISTS) { int i; /* make a 'modify' msg, and only for serverReference */ msg = ldb_msg_new(tmp_ctx); if (!msg) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } msg->dn = server_dn; rtn = ldb_msg_add_string(msg, "serverReference",libnet_r->out.account_dn_str); if (rtn != 0) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } /* mark all the message elements (should be just one) as LDB_FLAG_MOD_REPLACE */ for (i=0; i<msg->num_elements; i++) { msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; } rtn = ldb_modify(remote_ldb, msg); if (rtn != 0) { libnet_r->out.error_string = talloc_asprintf(libnet_r, "Failed to modify server entry %s: %s: %d", server_dn_str, ldb_errstring(remote_ldb), rtn); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } } else if (rtn != 0) { libnet_r->out.error_string = talloc_asprintf(libnet_r, "Failed to add server entry %s: %s: %d", server_dn_str, ldb_errstring(remote_ldb), rtn); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } DEBUG(0, ("We still need to perform a DsAddEntry() so that we can create the CN=NTDS Settings container.\n")); /* Store the server DN in libnet_r */ libnet_r->out.server_dn_str = server_dn_str; talloc_steal(libnet_r, server_dn_str); talloc_free(tmp_ctx); return NT_STATUS_OK; }
/* test generic cldap operations */ static bool test_cldap_generic(struct torture_context *tctx, const char *dest) { struct cldap_socket *cldap; NTSTATUS status; struct cldap_search search; const char *attrs1[] = { "currentTime", "highestCommittedUSN", NULL }; const char *attrs2[] = { "currentTime", "highestCommittedUSN", "netlogon", NULL }; const char *attrs3[] = { "netlogon", NULL }; status = cldap_socket_init(tctx, NULL, NULL, NULL, &cldap); CHECK_STATUS(status, NT_STATUS_OK); ZERO_STRUCT(search); search.in.dest_address = dest; search.in.dest_port = lp_cldap_port(tctx->lp_ctx); search.in.timeout = 10; search.in.retries = 3; status = cldap_search(cldap, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); printf("fetching whole rootDSE\n"); search.in.filter = "(objectclass=*)"; search.in.attributes = NULL; status = cldap_search(cldap, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); if (DEBUGLVL(3)) cldap_dump_results(&search); printf("fetching currentTime and USN\n"); search.in.filter = "(objectclass=*)"; search.in.attributes = attrs1; status = cldap_search(cldap, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); if (DEBUGLVL(3)) cldap_dump_results(&search); printf("Testing currentTime, USN and netlogon\n"); search.in.filter = "(objectclass=*)"; search.in.attributes = attrs2; status = cldap_search(cldap, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); if (DEBUGLVL(3)) cldap_dump_results(&search); printf("Testing objectClass=* and netlogon\n"); search.in.filter = "(objectclass2=*)"; search.in.attributes = attrs3; status = cldap_search(cldap, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); if (DEBUGLVL(3)) cldap_dump_results(&search); printf("Testing a false expression\n"); search.in.filter = "(&(objectclass=*)(highestCommittedUSN=2))"; search.in.attributes = attrs1; status = cldap_search(cldap, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); if (DEBUGLVL(3)) cldap_dump_results(&search); return true; }
/* test netlogon operations */ static bool test_cldap_netlogon(struct torture_context *tctx, const char *dest) { struct cldap_socket *cldap; NTSTATUS status; struct cldap_netlogon search, empty_search; struct netlogon_samlogon_response n1; struct GUID guid; int i; struct smb_iconv_convenience *iconv_convenience = lp_iconv_convenience(tctx->lp_ctx); struct tsocket_address *dest_addr; int ret; ret = tsocket_address_inet_from_strings(tctx, "ip", dest, lp_cldap_port(tctx->lp_ctx), &dest_addr); status = cldap_socket_init(tctx, NULL, NULL, dest_addr, &cldap); CHECK_STATUS(status, NT_STATUS_OK); ZERO_STRUCT(search); search.in.dest_address = NULL; search.in.dest_port = 0; search.in.acct_control = -1; search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; search.in.map_response = true; empty_search = search; printf("Trying without any attributes\n"); search = empty_search; status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); n1 = search.out.netlogon; search.in.user = "******"; search.in.realm = n1.data.nt5_ex.dns_domain; search.in.host = "__cldap_torture__"; printf("Scanning for netlogon levels\n"); for (i=0;i<256;i++) { search.in.version = i; printf("Trying netlogon level %d\n", i); status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); } printf("Scanning for netlogon level bits\n"); for (i=0;i<31;i++) { search.in.version = (1<<i); printf("Trying netlogon level 0x%x\n", i); status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); } search.in.version = NETLOGON_NT_VERSION_5|NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_IP; status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); printf("Trying with User=NULL\n"); search.in.user = NULL; status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, ""); CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX); printf("Trying with User=Administrator\n"); search.in.user = "******"; status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, search.in.user); CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN_EX); search.in.version = NETLOGON_NT_VERSION_5; status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); printf("Trying with User=NULL\n"); search.in.user = NULL; status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, ""); CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE); printf("Trying with User=Administrator\n"); search.in.user = "******"; status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, search.in.user); CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN); search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; printf("Trying with a GUID\n"); search.in.realm = NULL; search.in.domain_guid = GUID_string(tctx, &n1.data.nt5_ex.domain_uuid); status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN_EX); CHECK_STRING(GUID_string(tctx, &search.out.netlogon.data.nt5_ex.domain_uuid), search.in.domain_guid); printf("Trying with a incorrect GUID\n"); guid = GUID_random(); search.in.user = NULL; search.in.domain_guid = GUID_string(tctx, &guid); status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_NOT_FOUND); printf("Trying with a AAC\n"); search.in.acct_control = ACB_WSTRUST|ACB_SVRTRUST; search.in.realm = n1.data.nt5_ex.dns_domain; status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX); CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, ""); printf("Trying with a zero AAC\n"); search.in.acct_control = 0x0; search.in.realm = n1.data.nt5_ex.dns_domain; status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX); CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, ""); printf("Trying with a zero AAC and user=Administrator\n"); search.in.acct_control = 0x0; search.in.user = "******"; search.in.realm = n1.data.nt5_ex.dns_domain; status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN_EX); CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, "Administrator"); printf("Trying with a bad AAC\n"); search.in.user = NULL; search.in.acct_control = 0xFF00FF00; search.in.realm = n1.data.nt5_ex.dns_domain; status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX); CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, ""); printf("Trying with a user only\n"); search = empty_search; search.in.user = "******"; status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain); CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, search.in.user); printf("Trying with just a bad username\n"); search.in.user = "******"; status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, search.in.user); CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain); CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN_EX); printf("Trying with just a bad domain\n"); search = empty_search; search.in.realm = "___no_such_domain___"; status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_NOT_FOUND); printf("Trying with a incorrect domain and correct guid\n"); search.in.domain_guid = GUID_string(tctx, &n1.data.nt5_ex.domain_uuid); status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain); CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, ""); CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX); printf("Trying with a incorrect domain and incorrect guid\n"); search.in.domain_guid = GUID_string(tctx, &guid); status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_NOT_FOUND); CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain); CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, ""); CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX); printf("Trying with a incorrect GUID and correct domain\n"); search.in.domain_guid = GUID_string(tctx, &guid); search.in.realm = n1.data.nt5_ex.dns_domain; status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain); CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, ""); CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX); return true; }
/* test cldap netlogon server type flag "NBT_SERVER_DS_DNS_FOREST" */ static bool test_cldap_netlogon_flag_ds_dns_forest(struct torture_context *tctx, const char *dest) { struct cldap_socket *cldap; NTSTATUS status; struct cldap_netlogon search; uint32_t server_type; struct netlogon_samlogon_response n1; struct smb_iconv_convenience *iconv_convenience = lp_iconv_convenience(tctx->lp_ctx); bool result = true; status = cldap_socket_init(tctx, NULL, NULL, NULL, &cldap); CHECK_STATUS(status, NT_STATUS_OK); printf("Testing netlogon server type flag NBT_SERVER_DS_DNS_FOREST: "); ZERO_STRUCT(search); search.in.dest_address = dest; search.in.dest_port = lp_cldap_port(tctx->lp_ctx); search.in.acct_control = -1; search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; search.in.map_response = true; status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); n1 = search.out.netlogon; if (n1.ntver == NETLOGON_NT_VERSION_5) server_type = n1.data.nt5.server_type; else if (n1.ntver == NETLOGON_NT_VERSION_5EX) server_type = n1.data.nt5_ex.server_type; if (server_type & DS_DNS_FOREST) { struct cldap_search search2; const char *attrs[] = { "defaultNamingContext", "rootDomainNamingContext", NULL }; struct ldb_context *ldb; struct ldb_message *msg; /* Trying to fetch the attributes "defaultNamingContext" and "rootDomainNamingContext" */ ZERO_STRUCT(search2); search2.in.dest_address = dest; search2.in.dest_port = lp_cldap_port(tctx->lp_ctx); search2.in.timeout = 10; search2.in.retries = 3; search2.in.filter = "(objectclass=*)"; search2.in.attributes = attrs; status = cldap_search(cldap, tctx, &search2); CHECK_STATUS(status, NT_STATUS_OK); ldb = ldb_init(NULL, NULL); msg = ldap_msg_to_ldb(ldb, ldb, search2.out.response); /* Try to compare the two attributes */ if (ldb_msg_element_compare(ldb_msg_find_element(msg, attrs[0]), ldb_msg_find_element(msg, attrs[1]))) result = false; talloc_free(ldb); } if (result) printf("passed\n"); else printf("failed\n"); return result; }
/* test cldap netlogon server type flags */ static bool test_cldap_netlogon_flags(struct torture_context *tctx, const char *dest) { struct cldap_socket *cldap; NTSTATUS status; struct cldap_netlogon search; struct netlogon_samlogon_response n1; uint32_t server_type; struct smb_iconv_convenience *iconv_convenience = lp_iconv_convenience(tctx->lp_ctx); status = cldap_socket_init(tctx, NULL, NULL, NULL, &cldap); CHECK_STATUS(status, NT_STATUS_OK); printf("Printing out netlogon server type flags: %s\n", dest); ZERO_STRUCT(search); search.in.dest_address = dest; search.in.dest_port = lp_cldap_port(tctx->lp_ctx); search.in.acct_control = -1; search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; search.in.map_response = true; status = cldap_netlogon(cldap, iconv_convenience, tctx, &search); CHECK_STATUS(status, NT_STATUS_OK); n1 = search.out.netlogon; if (n1.ntver == NETLOGON_NT_VERSION_5) server_type = n1.data.nt5.server_type; else if (n1.ntver == NETLOGON_NT_VERSION_5EX) server_type = n1.data.nt5_ex.server_type; printf("The word is: %i\n", server_type); if (server_type & NBT_SERVER_PDC) printf("NBT_SERVER_PDC "); if (server_type & NBT_SERVER_GC) printf("NBT_SERVER_GC "); if (server_type & NBT_SERVER_LDAP) printf("NBT_SERVER_LDAP "); if (server_type & NBT_SERVER_DS) printf("NBT_SERVER_DS "); if (server_type & NBT_SERVER_KDC) printf("NBT_SERVER_KDC "); if (server_type & NBT_SERVER_TIMESERV) printf("NBT_SERVER_TIMESERV "); if (server_type & NBT_SERVER_CLOSEST) printf("NBT_SERVER_CLOSEST "); if (server_type & NBT_SERVER_WRITABLE) printf("NBT_SERVER_WRITABLE "); if (server_type & NBT_SERVER_GOOD_TIMESERV) printf("NBT_SERVER_GOOD_TIMESERV "); if (server_type & NBT_SERVER_NDNC) printf("NBT_SERVER_NDNC "); if (server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) printf("NBT_SERVER_SELECT_SECRET_DOMAIN_6"); if (server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) printf("NBT_SERVER_FULL_SECRET_DOMAIN_6"); if (server_type & DS_DNS_CONTROLLER) printf("DS_DNS_CONTROLLER "); if (server_type & DS_DNS_DOMAIN) printf("DS_DNS_DOMAIN "); if (server_type & DS_DNS_FOREST) printf("DS_DNS_FOREST "); printf("\n"); return true; }