/** connect to the schannel ldb */ struct ldb_context *schannel_db_connect(TALLOC_CTX *mem_ctx) { char *path; struct ldb_context *ldb; BOOL existed; const char *init_ldif = "dn: @ATTRIBUTES\n" \ "computerName: CASE_INSENSITIVE\n" \ "flatname: CASE_INSENSITIVE\n"; path = smbd_tmp_path(mem_ctx, "schannel.ldb"); if (!path) { return NULL; } existed = file_exist(path); ldb = ldb_wrap_connect(mem_ctx, path, system_session(mem_ctx), NULL, LDB_FLG_NOSYNC, NULL); talloc_free(path); if (!ldb) { return NULL; } if (!existed) { gendb_add_ldif(ldb, init_ldif); } return ldb; }
static NTSTATUS sldb_init(TALLOC_CTX *mem_ctx, const struct share_ops *ops, struct tevent_context *ev_ctx, struct loadparm_context *lp_ctx, struct share_context **ctx) { struct ldb_context *sdb; *ctx = talloc(mem_ctx, struct share_context); if (!*ctx) { DEBUG(0, ("ERROR: Out of memory!\n")); return NT_STATUS_NO_MEMORY; } sdb = ldb_wrap_connect(*ctx, ev_ctx, lp_ctx, private_path(*ctx, lp_ctx, "share.ldb"), system_session(lp_ctx), NULL, 0); if (!sdb) { talloc_free(*ctx); return NT_STATUS_UNSUCCESSFUL; } (*ctx)->ops = ops; (*ctx)->priv_data = (void *)sdb; return NT_STATUS_OK; }
/* connect to the sam database */ NTSTATUS ldapsrv_backend_Init(struct ldapsrv_connection *conn) { conn->ldb = ldb_wrap_connect(conn, lp_sam_url(), conn->session_info, NULL, conn->global_catalog ? LDB_FLG_RDONLY : 0, NULL); if (conn->ldb == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } if (conn->server_credentials) { char **sasl_mechs = NULL; struct gensec_security_ops **backends = gensec_security_all(); enum credentials_use_kerberos use_kerberos = cli_credentials_get_kerberos_state(conn->server_credentials); struct gensec_security_ops **ops = gensec_use_kerberos_mechs(conn, backends, use_kerberos); int i, j = 0; for (i = 0; ops && ops[i]; i++) { if (ops[i]->sasl_name && ops[i]->server_start) { char *sasl_name = talloc_strdup(conn, ops[i]->sasl_name); if (!sasl_name) { return NT_STATUS_NO_MEMORY; } sasl_mechs = talloc_realloc(conn, sasl_mechs, char *, j + 2); if (!sasl_mechs) { return NT_STATUS_NO_MEMORY; } sasl_mechs[j] = sasl_name; talloc_steal(sasl_mechs, sasl_name); sasl_mechs[j+1] = NULL; j++; } }
static struct ldb_context *wins_config_db_connect(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx, struct loadparm_context *lp_ctx) { return ldb_wrap_connect(mem_ctx, ev_ctx, lp_ctx, private_path(mem_ctx, lp_ctx, lp_wins_config_url(lp_ctx)), system_session(mem_ctx, lp_ctx), NULL, 0, NULL); }
/** * Find out user's samAccountName for given * user RDN. We need samAccountName value * when deleting users. */ static bool _get_account_name_for_user_rdn(struct torture_context *tctx, const char *user_rdn, TALLOC_CTX *mem_ctx, const char **_account_name) { const char *url; struct ldb_context *ldb; TALLOC_CTX *tmp_ctx; bool test_res = true; const char *hostname = torture_setting_string(tctx, "host", NULL); int ldb_ret; struct ldb_result *ldb_res; const char *account_name = NULL; static const char *attrs[] = { "samAccountName", NULL }; torture_assert(tctx, hostname != NULL, "Failed to get hostname"); tmp_ctx = talloc_new(tctx); torture_assert(tctx, tmp_ctx != NULL, "Failed to create temporary mem context"); url = talloc_asprintf(tmp_ctx, "ldap://%s/", hostname); torture_assert_goto(tctx, url != NULL, test_res, done, "Failed to allocate URL for ldb"); ldb = ldb_wrap_connect(tmp_ctx, tctx->ev, tctx->lp_ctx, url, NULL, cmdline_credentials, 0); torture_assert_goto(tctx, ldb != NULL, test_res, done, "Failed to make LDB connection"); ldb_ret = ldb_search(ldb, tmp_ctx, &ldb_res, ldb_get_default_basedn(ldb), LDB_SCOPE_SUBTREE, attrs, "(&(objectClass=user)(name=%s))", user_rdn); if (LDB_SUCCESS == ldb_ret && 1 == ldb_res->count) { account_name = ldb_msg_find_attr_as_string(ldb_res->msgs[0], "samAccountName", NULL); } /* return user_rdn by default */ if (!account_name) { account_name = user_rdn; } /* duplicate memory in parent context */ *_account_name = talloc_strdup(mem_ctx, account_name); done: talloc_free(tmp_ctx); return test_res; }
static NTSTATUS unbecomeDC_ldap_connect(struct libnet_UnbecomeDC_state *s) { char *url; url = talloc_asprintf(s, "ldap://%s/", s->source_dsa.dns_name); NT_STATUS_HAVE_NO_MEMORY(url); s->ldap.ldb = ldb_wrap_connect(s, s->libnet->event_ctx, s->libnet->lp_ctx, url, NULL, s->libnet->cred, 0); talloc_free(url); if (s->ldap.ldb == NULL) { return NT_STATUS_UNEXPECTED_NETWORK_ERROR; } return NT_STATUS_OK; }
static ADS_STATUS ads_connect(ADS_STRUCT *ads) { struct libnet_LookupDCs *io; char *url; io = talloc_zero(ads, struct libnet_LookupDCs); /* We are looking for the PDC of the active domain. */ io->in.name_type = NBT_NAME_PDC; io->in.domain_name = lp_workgroup(ads->netctx->lp_ctx); libnet_LookupDCs(ads->netctx, ads, io); url = talloc_asprintf(ads, "ldap://%s", io->out.dcs[0].name); ads->ldbctx = ldb_wrap_connect(ads, ads->netctx->event_ctx, ads->netctx->lp_ctx, url, NULL, ads->netctx->cred, 0); if (ads->ldbctx == NULL) { return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); } return ADS_ERROR_NT(NT_STATUS_OK); }
/* connect to the SPOOLSS database return a ldb_context pointer on success, or NULL on failure */ static struct ldb_context *sptr_db_connect(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx, struct loadparm_context *lp_ctx) { return ldb_wrap_connect(mem_ctx, ev_ctx, lp_ctx, "spoolss.ldb", system_session(lp_ctx), NULL, 0); }
/* test ldb speed */ static bool test_ldb_speed(struct torture_context *torture, const void *_data) { struct timeval tv; struct ldb_context *ldb; int timelimit = torture_setting_int(torture, "timelimit", 10); int i, count; TALLOC_CTX *tmp_ctx = talloc_new(torture); struct ldb_ldif *ldif; const char *init_ldif = "dn: @INDEXLIST\n" \ "@IDXATTR: UID\n"; float ldb_speed; unlink("./test.ldb"); torture_comment(torture, "Testing ldb speed for sidmap\n"); ldb = ldb_wrap_connect(tmp_ctx, torture->ev, torture->lp_ctx, "tdb://test.ldb", NULL, NULL, LDB_FLG_NOSYNC, NULL); if (!ldb) { unlink("./test.ldb"); talloc_free(tmp_ctx); torture_fail(torture, "Failed to open test.ldb"); } /* add an index */ ldif = ldb_ldif_read_string(ldb, &init_ldif); if (ldif == NULL) goto failed; if (ldb_add(ldb, ldif->msg) != LDB_SUCCESS) goto failed; talloc_free(ldif); torture_comment(torture, "Adding %d SID records\n", torture_entries); for (i=0;i<torture_entries;i++) { if (!ldb_add_record(ldb, i)) { torture_result(torture, TORTURE_FAIL, "Failed to add SID %d\n", i); goto failed; } } if (talloc_total_blocks(torture) > 100) { torture_result(torture, TORTURE_FAIL, "memory leak in ldb add\n"); goto failed; } torture_comment(torture, "Testing for %d seconds\n", timelimit); tv = timeval_current(); for (count=0;timeval_elapsed(&tv) < timelimit;count++) { struct ldb_dn *dn; struct ldb_result *res; i = random() % torture_entries; dn = ldb_dn_new_fmt(tmp_ctx, ldb, "SID=S-1-5-21-53173311-3623041448-2049097239-%u", i); if (ldb_search(ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL) != LDB_SUCCESS || res->count != 1) { torture_fail(torture, talloc_asprintf(torture, "Failed to find SID %d", i)); } talloc_free(res); talloc_free(dn); if (ldb_search(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, NULL, "(UID=%u)", i) != LDB_SUCCESS || res->count != 1) { torture_fail(torture, talloc_asprintf(torture, "Failed to find UID %d", i)); } talloc_free(res); } if (talloc_total_blocks(torture) > 100) { unlink("./test.ldb"); talloc_free(tmp_ctx); torture_fail(torture, "memory leak in ldb search"); } ldb_speed = count/timeval_elapsed(&tv); torture_comment(torture, "ldb speed %.2f ops/sec\n", ldb_speed); torture_comment(torture, "ldb/tdb speed ratio is %.2f%%\n", (100*ldb_speed/tdb_speed)); unlink("./test.ldb"); talloc_free(tmp_ctx); return true; failed: unlink("./test.ldb"); talloc_free(tmp_ctx); return false; }
static int set_ldap_credentials(struct ldb_context *ldb, bool use_external) { const char *secrets_ldb_path, *sam_ldb_path; char *private_dir, *p, *error_string; struct ldb_context *secrets_ldb; struct cli_credentials *cred; struct loadparm_context *lp_ctx = ldb_get_opaque(ldb, "loadparm"); TALLOC_CTX *tmp_ctx = talloc_new(ldb); if (!tmp_ctx) { return ldb_oom(ldb); } cred = cli_credentials_init(ldb); if (!cred) { talloc_free(tmp_ctx); return ldb_oom(ldb); } cli_credentials_set_anonymous(cred); if (use_external) { cli_credentials_set_forced_sasl_mech(cred, "EXTERNAL"); } else { cli_credentials_set_forced_sasl_mech(cred, "DIGEST-MD5"); /* * We don't want to use krb5 to talk to our samdb - recursion * here would be bad, and this account isn't in the KDC * anyway */ cli_credentials_set_kerberos_state(cred, CRED_DONT_USE_KERBEROS); /* * Work out where *our* secrets.ldb is. It must be in * the same directory as sam.ldb */ sam_ldb_path = (const char *)ldb_get_opaque(ldb, "ldb_url"); if (!sam_ldb_path) { talloc_free(tmp_ctx); return ldb_operr(ldb); } if (strncmp("tdb://", sam_ldb_path, 6) == 0) { sam_ldb_path += 6; } private_dir = talloc_strdup(tmp_ctx, sam_ldb_path); p = strrchr(private_dir, '/'); if (p) { *p = '\0'; } else { private_dir = talloc_strdup(tmp_ctx, "."); } secrets_ldb_path = talloc_asprintf(private_dir, "tdb://%s/secrets.ldb", private_dir); if (!secrets_ldb_path) { talloc_free(tmp_ctx); return ldb_oom(ldb); } /* * Now that we have found the location, connect to * secrets.ldb so we can read the SamDB Credentials * record */ secrets_ldb = ldb_wrap_connect(tmp_ctx, NULL, lp_ctx, secrets_ldb_path, NULL, NULL, 0); if (!NT_STATUS_IS_OK(cli_credentials_set_secrets(cred, NULL, secrets_ldb, NULL, SECRETS_LDAP_FILTER, &error_string))) { ldb_asprintf_errstring(ldb, "Failed to read LDAP backend password from %s", secrets_ldb_path); talloc_free(tmp_ctx); return LDB_ERR_STRONG_AUTH_REQUIRED; } } /* * Finally overwrite any supplied credentials with * these ones, as only secrets.ldb contains the magic * credentials to talk on the ldapi socket */ if (ldb_set_opaque(ldb, "credentials", cred)) { talloc_free(tmp_ctx); return ldb_operr(ldb); } talloc_free(tmp_ctx); return LDB_SUCCESS; }
/* * complete a domain join, when joining to a AD domain: * 1.) connect and bind to the DRSUAPI pipe * 2.) do a DsCrackNames() to find the machine account dn * 3.) connect to LDAP * 4.) do an ldap search to find the "msDS-KeyVersionNumber" of the machine account * 5.) set the servicePrincipalName's of the machine account via LDAP, (maybe we should use DsWriteAccountSpn()...) * 6.) do a DsCrackNames() to find the domain dn * 7.) find out Site specific stuff, look at libnet_JoinSite() for details */ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_JoinDomain *r) { NTSTATUS status; TALLOC_CTX *tmp_ctx; const char *realm = r->out.realm; struct dcerpc_binding *samr_binding = r->out.samr_binding; struct dcerpc_pipe *drsuapi_pipe; struct dcerpc_binding *drsuapi_binding; struct drsuapi_DsBind r_drsuapi_bind; struct drsuapi_DsCrackNames r_crack_names; struct drsuapi_DsNameString names[1]; struct policy_handle drsuapi_bind_handle; struct GUID drsuapi_bind_guid; struct ldb_context *remote_ldb; struct ldb_dn *account_dn; const char *account_dn_str; const char *remote_ldb_url; struct ldb_result *res; struct ldb_message *msg; int ret, rtn; const char * const attrs[] = { "msDS-KeyVersionNumber", "servicePrincipalName", "dNSHostName", "objectGUID", NULL, }; r->out.error_string = NULL; /* We need to convert between a samAccountName and domain to a * DN in the directory. The correct way to do this is with * DRSUAPI CrackNames */ /* Fiddle with the bindings, so get to DRSUAPI on * NCACN_IP_TCP, sealed */ tmp_ctx = talloc_named(r, 0, "libnet_JoinADSDomain temp context"); if (!tmp_ctx) { r->out.error_string = NULL; return NT_STATUS_NO_MEMORY; } drsuapi_binding = talloc_zero(tmp_ctx, struct dcerpc_binding); if (!drsuapi_binding) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } *drsuapi_binding = *samr_binding; /* DRSUAPI is only available on IP_TCP, and locally on NCALRPC */ if (drsuapi_binding->transport != NCALRPC) { drsuapi_binding->transport = NCACN_IP_TCP; } drsuapi_binding->endpoint = NULL; drsuapi_binding->flags |= DCERPC_SEAL; status = dcerpc_pipe_connect_b(tmp_ctx, &drsuapi_pipe, drsuapi_binding, &ndr_table_drsuapi, ctx->cred, ctx->event_ctx, ctx->lp_ctx); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(r, "Connection to DRSUAPI pipe of PDC of domain '%s' failed: %s", r->out.domain_name, nt_errstr(status)); talloc_free(tmp_ctx); return status; } /* get a DRSUAPI pipe handle */ GUID_from_string(DRSUAPI_DS_BIND_GUID, &drsuapi_bind_guid); r_drsuapi_bind.in.bind_guid = &drsuapi_bind_guid; r_drsuapi_bind.in.bind_info = NULL; r_drsuapi_bind.out.bind_handle = &drsuapi_bind_handle; status = dcerpc_drsuapi_DsBind_r(drsuapi_pipe->binding_handle, tmp_ctx, &r_drsuapi_bind); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsBind failed - %s", nt_errstr(status)); talloc_free(tmp_ctx); return status; } else if (!W_ERROR_IS_OK(r_drsuapi_bind.out.result)) { r->out.error_string = talloc_asprintf(r, "DsBind failed - %s", win_errstr(r_drsuapi_bind.out.result)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* Actually 'crack' the names */ ZERO_STRUCT(r_crack_names); r_crack_names.in.bind_handle = &drsuapi_bind_handle; r_crack_names.in.level = 1; r_crack_names.in.req = talloc(r, union drsuapi_DsNameRequest); if (!r_crack_names.in.req) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } r_crack_names.in.req->req1.codepage = 1252; /* western european */ r_crack_names.in.req->req1.language = 0x00000407; /* german */ r_crack_names.in.req->req1.count = 1; r_crack_names.in.req->req1.names = names; r_crack_names.in.req->req1.format_flags = DRSUAPI_DS_NAME_FLAG_NO_FLAGS; r_crack_names.in.req->req1.format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY; r_crack_names.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779; names[0].str = dom_sid_string(tmp_ctx, r->out.account_sid); if (!names[0].str) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } r_crack_names.out.ctr = talloc(r, union drsuapi_DsNameCtr); r_crack_names.out.level_out = talloc(r, uint32_t); if (!r_crack_names.out.ctr || !r_crack_names.out.level_out) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } status = dcerpc_drsuapi_DsCrackNames_r(drsuapi_pipe->binding_handle, tmp_ctx, &r_crack_names); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", names[0].str, nt_errstr(status)); talloc_free(tmp_ctx); return status; } else if (!W_ERROR_IS_OK(r_crack_names.out.result)) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed - %s", win_errstr(r_crack_names.out.result)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } else if (*r_crack_names.out.level_out != 1 || !r_crack_names.out.ctr->ctr1 || r_crack_names.out.ctr->ctr1->count != 1) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed"); talloc_free(tmp_ctx); return NT_STATUS_INVALID_PARAMETER; } else if (r_crack_names.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed: %d", r_crack_names.out.ctr->ctr1->array[0].status); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } else if (r_crack_names.out.ctr->ctr1->array[0].result_name == NULL) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed: no result name"); talloc_free(tmp_ctx); return NT_STATUS_INVALID_PARAMETER; } /* Store the DN of our machine account. */ account_dn_str = r_crack_names.out.ctr->ctr1->array[0].result_name; /* Now we know the user's DN, open with LDAP, read and modify a few things */ remote_ldb_url = talloc_asprintf(tmp_ctx, "ldap://%s", drsuapi_binding->target_hostname); if (!remote_ldb_url) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } remote_ldb = ldb_wrap_connect(tmp_ctx, ctx->event_ctx, ctx->lp_ctx, remote_ldb_url, NULL, ctx->cred, 0); if (!remote_ldb) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } account_dn = ldb_dn_new(tmp_ctx, remote_ldb, account_dn_str); if (account_dn == NULL) { r->out.error_string = talloc_asprintf(r, "Invalid account dn: %s", account_dn_str); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* search for the user's record */ ret = ldb_search(remote_ldb, tmp_ctx, &res, account_dn, LDB_SCOPE_BASE, attrs, NULL); if (ret != LDB_SUCCESS) { r->out.error_string = talloc_asprintf(r, "ldb_search for %s failed - %s", account_dn_str, ldb_errstring(remote_ldb)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } if (res->count != 1) { r->out.error_string = talloc_asprintf(r, "ldb_search for %s failed - found %d entries", account_dn_str, res->count); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* Prepare a new message, for the modify */ msg = ldb_msg_new(tmp_ctx); if (!msg) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } msg->dn = res->msgs[0]->dn; { unsigned int i; const char *service_principal_name[2]; const char *dns_host_name = strlower_talloc(msg, talloc_asprintf(msg, "%s.%s", r->in.netbios_name, realm)); if (!dns_host_name) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } service_principal_name[0] = talloc_asprintf(msg, "HOST/%s", dns_host_name); service_principal_name[1] = talloc_asprintf(msg, "HOST/%s", r->in.netbios_name); for (i=0; i < ARRAY_SIZE(service_principal_name); i++) { if (!service_principal_name[i]) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rtn = ldb_msg_add_string(msg, "servicePrincipalName", service_principal_name[i]); if (rtn != LDB_SUCCESS) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } } rtn = ldb_msg_add_string(msg, "dNSHostName", dns_host_name); if (rtn != LDB_SUCCESS) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rtn = dsdb_replace(remote_ldb, msg, 0); if (rtn != LDB_SUCCESS) { r->out.error_string = talloc_asprintf(r, "Failed to replace entries on %s", ldb_dn_get_linearized(msg->dn)); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } } msg = ldb_msg_new(tmp_ctx); if (!msg) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } msg->dn = res->msgs[0]->dn; rtn = samdb_msg_add_uint(remote_ldb, msg, msg, "msDS-SupportedEncryptionTypes", ENC_ALL_TYPES); if (rtn != LDB_SUCCESS) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rtn = dsdb_replace(remote_ldb, msg, 0); /* The remote server may not support this attribute, if it * isn't a modern schema */ if (rtn != LDB_SUCCESS && rtn != LDB_ERR_NO_SUCH_ATTRIBUTE) { r->out.error_string = talloc_asprintf(r, "Failed to replace msDS-SupportedEncryptionTypes on %s", ldb_dn_get_linearized(msg->dn)); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } /* DsCrackNames to find out the DN of the domain. */ r_crack_names.in.req->req1.format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT; r_crack_names.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779; names[0].str = talloc_asprintf(tmp_ctx, "%s\\", r->out.domain_name); if (!names[0].str) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } status = dcerpc_drsuapi_DsCrackNames_r(drsuapi_pipe->binding_handle, tmp_ctx, &r_crack_names); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", r->in.domain_name, nt_errstr(status)); talloc_free(tmp_ctx); return status; } else if (!W_ERROR_IS_OK(r_crack_names.out.result)) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed - %s", win_errstr(r_crack_names.out.result)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } else if (*r_crack_names.out.level_out != 1 || !r_crack_names.out.ctr->ctr1 || r_crack_names.out.ctr->ctr1->count != 1 || !r_crack_names.out.ctr->ctr1->array[0].result_name || r_crack_names.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed"); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* Store the account DN. */ r->out.account_dn_str = account_dn_str; talloc_steal(r, account_dn_str); /* Store the domain DN. */ r->out.domain_dn_str = r_crack_names.out.ctr->ctr1->array[0].result_name; talloc_steal(r, r_crack_names.out.ctr->ctr1->array[0].result_name); /* Store the KVNO of the account, critical for some kerberos * operations */ r->out.kvno = ldb_msg_find_attr_as_uint(res->msgs[0], "msDS-KeyVersionNumber", 0); /* Store the account GUID. */ r->out.account_guid = samdb_result_guid(res->msgs[0], "objectGUID"); if (r->in.acct_type == ACB_SVRTRUST) { status = libnet_JoinSite(ctx, remote_ldb, r); } talloc_free(tmp_ctx); return status; }
static bool test_referrals(struct torture_context *tctx, TALLOC_CTX *mem_ctx, const char *url, const char *basedn, const char **partitions) { struct ldb_context *ldb; struct ldb_result *res; const char * const *attrs = { NULL }; struct ldb_dn *dn1, *dn2; int ret; int i, j, k; char *tempstr; bool found, l_found; printf("Testing referrals\n"); if (partitions[0] == NULL) { printf("Partitions list empty!\n"); return false; } if (strcmp(partitions[0], basedn) != 0) { printf("The first (root) partition DN should be the base DN!\n"); return false; } ldb = ldb_wrap_connect(mem_ctx, tctx->ev, tctx->lp_ctx, url, NULL, popt_get_cmdline_credentials(), 0); /* "partitions[i]" are the partitions for which we search the parents */ for (i = 1; partitions[i] != NULL; i++) { dn1 = ldb_dn_new(mem_ctx, ldb, partitions[i]); if (dn1 == NULL) { printf("Out of memory\n"); talloc_free(ldb); return false; } /* search using base scope */ /* "partitions[j]" are the parent candidates */ for (j = str_list_length(partitions) - 1; j >= 0; --j) { dn2 = ldb_dn_new(mem_ctx, ldb, partitions[j]); if (dn2 == NULL) { printf("Out of memory\n"); talloc_free(ldb); return false; } ret = ldb_search(ldb, mem_ctx, &res, dn2, LDB_SCOPE_BASE, attrs, "(foo=bar)"); if (ret != LDB_SUCCESS) { printf("%s", ldb_errstring(ldb)); talloc_free(ldb); return false; } if (res->refs != NULL) { printf("There shouldn't be generated any referrals in the base scope!\n"); talloc_free(ldb); return false; } talloc_free(res); talloc_free(dn2); } /* search using onelevel scope */ found = false; /* "partitions[j]" are the parent candidates */ for (j = str_list_length(partitions) - 1; j >= 0; --j) { dn2 = ldb_dn_new(mem_ctx, ldb, partitions[j]); if (dn2 == NULL) { printf("Out of memory\n"); talloc_free(ldb); return false; } ret = ldb_search(ldb, mem_ctx, &res, dn2, LDB_SCOPE_ONELEVEL, attrs, "(foo=bar)"); if (ret != LDB_SUCCESS) { printf("%s", ldb_errstring(ldb)); talloc_free(ldb); return false; } tempstr = talloc_asprintf(mem_ctx, "/%s??base", partitions[i]); if (tempstr == NULL) { printf("Out of memory\n"); talloc_free(ldb); return false; } /* Try to find or find not a matching referral */ l_found = false; for (k = 0; (!l_found) && (res->refs != NULL) && (res->refs[k] != NULL); k++) { if (strstr(res->refs[k], tempstr) != NULL) { l_found = true; } } talloc_free(tempstr); if ((!found) && (ldb_dn_compare_base(dn2, dn1) == 0) && (ldb_dn_compare(dn2, dn1) != 0)) { /* This is a referral candidate */ if (!l_found) { printf("A required referral hasn't been found on onelevel scope (%s -> %s)!\n", partitions[j], partitions[i]); talloc_free(ldb); return false; } found = true; } else { /* This isn't a referral candidate */ if (l_found) { printf("A unrequired referral has been found on onelevel scope (%s -> %s)!\n", partitions[j], partitions[i]); talloc_free(ldb); return false; } } talloc_free(res); talloc_free(dn2); } /* search using subtree scope */ found = false; /* "partitions[j]" are the parent candidates */ for (j = str_list_length(partitions) - 1; j >= 0; --j) { dn2 = ldb_dn_new(mem_ctx, ldb, partitions[j]); if (dn2 == NULL) { printf("Out of memory\n"); talloc_free(ldb); return false; } ret = ldb_search(ldb, mem_ctx, &res, dn2, LDB_SCOPE_SUBTREE, attrs, "(foo=bar)"); if (ret != LDB_SUCCESS) { printf("%s", ldb_errstring(ldb)); talloc_free(ldb); return false; } tempstr = talloc_asprintf(mem_ctx, "/%s", partitions[i]); if (tempstr == NULL) { printf("Out of memory\n"); talloc_free(ldb); return false; } /* Try to find or find not a matching referral */ l_found = false; for (k = 0; (!l_found) && (res->refs != NULL) && (res->refs[k] != NULL); k++) { if (strstr(res->refs[k], tempstr) != NULL) { l_found = true; } } talloc_free(tempstr); if ((!found) && (ldb_dn_compare_base(dn2, dn1) == 0) && (ldb_dn_compare(dn2, dn1) != 0)) { /* This is a referral candidate */ if (!l_found) { printf("A required referral hasn't been found on subtree scope (%s -> %s)!\n", partitions[j], partitions[i]); talloc_free(ldb); return false; } found = true; } else { /* This isn't a referral candidate */ if (l_found) { printf("A unrequired referral has been found on subtree scope (%s -> %s)!\n", partitions[j], partitions[i]); talloc_free(ldb); return false; } } talloc_free(res); talloc_free(dn2); } talloc_free(dn1); } talloc_free(ldb); return true; }
bool torture_ldap_sort(struct torture_context *torture) { struct ldb_context *ldb; bool ret = false; const char *host = torture_setting_string(torture, "host", NULL); char *url; int i; codepoint_t j; struct ldb_message_element *elem; struct ldb_message *msg; struct ldb_server_sort_control **control; struct ldb_request *req; struct ldb_result *ctx; struct ldb_val *prev = NULL; const char *prev_txt = NULL; int prev_len = 0; struct ldb_val *cur = NULL; const char *cur_txt = NULL; int cur_len = 0; struct ldb_dn *dn; /* TALLOC_CTX* ctx;*/ url = talloc_asprintf(torture, "ldap://%s/", host); ldb = ldb_wrap_connect(torture, torture->ev, torture->lp_ctx, url, NULL, popt_get_cmdline_credentials(), 0); torture_assert(torture, ldb, "Failed to make LDB connection to target"); ctx = talloc_zero(ldb, struct ldb_result); control = talloc_array(ctx, struct ldb_server_sort_control *, 2); control[0] = talloc(control, struct ldb_server_sort_control); control[0]->attributeName = talloc_strdup(control, "cn"); control[0]->orderingRule = NULL; control[0]->reverse = 0; control[1] = NULL; dn = ldb_get_default_basedn(ldb); ldb_dn_add_child_fmt(dn, "cn=users"); ret = ldb_build_search_req(&req, ldb, ctx, dn, LDB_SCOPE_SUBTREE, "(objectClass=*)", NULL, NULL, ctx, ldb_search_default_callback, NULL); torture_assert(torture, ret == LDB_SUCCESS, "Failed to build search request"); ret = ldb_request_add_control(req, LDB_CONTROL_SERVER_SORT_OID, true, control); torture_assert(torture, ret == LDB_SUCCESS, "Failed to add control to search request"); ret = ldb_request(ldb, req); torture_assert(torture, ret == LDB_SUCCESS, ldb_errstring(ldb)); ret = ldb_wait(req->handle, LDB_WAIT_ALL); torture_assert(torture, ret == LDB_SUCCESS, ldb_errstring(ldb)); ret = true; if (ctx->count > 1) { for (i=0;i<ctx->count;i++) { msg = ctx->msgs[i]; elem = ldb_msg_find_element(msg,"cn"); torture_assert_not_null(torture, elem, "msg lacks CN"); cur = elem->values; torture_comment(torture, "cn: %s\n",cur->data); if (prev != NULL) { /* Do only the ascii case right now ... */ cur_txt = (const char *) cur->data; cur_len = cur->length; prev_txt = (const char *) prev->data; prev_len = prev->length; /* Remove leading whitespace as the sort function do so ... */ while ( cur_txt[0] == cur_txt[1] ) { cur_txt++; cur_len--;} while ( prev_txt[0] == prev_txt[1] ) { prev_txt++; prev_len--;} while( *(cur_txt) && *(prev_txt) && cur_len && prev_len ) { j = toupper_m(*(prev_txt))-toupper_m(*(cur_txt)); if ( j > 0 ) { /* Just check that is not due to trailling white space in prev_txt * That is to say *cur_txt = 0 and prev_txt = 20 */ /* Remove trailling whitespace */ while ( *prev_txt == ' ' ) { prev_txt++; prev_len--;} while ( *cur_txt == ' ' ) { cur_txt++; cur_len--;} /* Now that potential whitespace are removed if we are at the end * of the cur_txt then it means that in fact strings were identical */ torture_assert(torture, *cur_txt && *prev_txt, "Data wrongly sorted"); break; } else { if ( j == 0 ) { if ( *(cur_txt) == ' ') { while ( cur_txt[0] == cur_txt[1] ) { cur_txt++; cur_len--;} while ( prev_txt[0] == prev_txt[1] ) { prev_txt++; prev_len--;} } cur_txt++; prev_txt++; prev_len--; cur_len--; } else { break; } } } if ( ret != 1 ) { break; } } prev = cur; } } return ret; }
/** connect to the secrets ldb */ struct ldb_context *secrets_db_connect(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx) { return ldb_wrap_connect(mem_ctx, NULL, lp_ctx, "secrets.ldb", NULL, NULL, 0); }
/* connect to the privilege database */ struct ldb_context *privilege_connect(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx) { return ldb_wrap_connect(mem_ctx, NULL, lp_ctx, "privilege.ldb", NULL, NULL, 0); }
/* * complete a domain join, when joining to a AD domain: * 1.) connect and bind to the DRSUAPI pipe * 2.) do a DsCrackNames() to find the machine account dn * 3.) connect to LDAP * 4.) do an ldap search to find the "msDS-KeyVersionNumber" of the machine account * 5.) set the servicePrincipalName's of the machine account via LDAP, (maybe we should use DsWriteAccountSpn()...) * 6.) do a DsCrackNames() to find the domain dn * 7.) find out Site specific stuff, look at libnet_JoinSite() for details */ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_JoinDomain *r) { NTSTATUS status; TALLOC_CTX *tmp_ctx; const char *realm = r->out.realm; struct dcerpc_binding *samr_binding = r->out.samr_binding; struct dcerpc_pipe *drsuapi_pipe; struct dcerpc_binding *drsuapi_binding; struct drsuapi_DsBind r_drsuapi_bind; struct drsuapi_DsCrackNames r_crack_names; struct drsuapi_DsNameString names[1]; struct policy_handle drsuapi_bind_handle; struct GUID drsuapi_bind_guid; struct ldb_context *remote_ldb; struct ldb_dn *account_dn; const char *account_dn_str; const char *remote_ldb_url; struct ldb_result *res; struct ldb_message *msg; int ret, rtn; unsigned int kvno; const char * const attrs[] = { "msDS-KeyVersionNumber", "servicePrincipalName", "dNSHostName", NULL, }; r->out.error_string = NULL; /* We need to convert between a samAccountName and domain to a * DN in the directory. The correct way to do this is with * DRSUAPI CrackNames */ /* Fiddle with the bindings, so get to DRSUAPI on * NCACN_IP_TCP, sealed */ tmp_ctx = talloc_named(r, 0, "libnet_JoinADSDomain temp context"); if (!tmp_ctx) { r->out.error_string = NULL; return NT_STATUS_NO_MEMORY; } drsuapi_binding = talloc(tmp_ctx, struct dcerpc_binding); if (!drsuapi_binding) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } *drsuapi_binding = *samr_binding; /* DRSUAPI is only available on IP_TCP, and locally on NCALRPC */ if (drsuapi_binding->transport != NCALRPC) { drsuapi_binding->transport = NCACN_IP_TCP; } drsuapi_binding->endpoint = NULL; drsuapi_binding->flags |= DCERPC_SEAL; status = dcerpc_pipe_connect_b(tmp_ctx, &drsuapi_pipe, drsuapi_binding, &dcerpc_table_drsuapi, ctx->cred, ctx->event_ctx); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(r, "Connection to DRSUAPI pipe of PDC of domain '%s' failed: %s", r->in.domain_name, nt_errstr(status)); talloc_free(tmp_ctx); return status; } /* get a DRSUAPI pipe handle */ GUID_from_string(DRSUAPI_DS_BIND_GUID, &drsuapi_bind_guid); r_drsuapi_bind.in.bind_guid = &drsuapi_bind_guid; r_drsuapi_bind.in.bind_info = NULL; r_drsuapi_bind.out.bind_handle = &drsuapi_bind_handle; status = dcerpc_drsuapi_DsBind(drsuapi_pipe, tmp_ctx, &r_drsuapi_bind); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsBind failed - %s", dcerpc_errstr(tmp_ctx, drsuapi_pipe->last_fault_code)); talloc_free(tmp_ctx); return status; } else { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsBind failed - %s", nt_errstr(status)); talloc_free(tmp_ctx); return status; } } else if (!W_ERROR_IS_OK(r_drsuapi_bind.out.result)) { r->out.error_string = talloc_asprintf(r, "DsBind failed - %s", win_errstr(r_drsuapi_bind.out.result)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* Actually 'crack' the names */ ZERO_STRUCT(r_crack_names); r_crack_names.in.bind_handle = &drsuapi_bind_handle; r_crack_names.in.level = 1; r_crack_names.in.req.req1.unknown1 = 0x000004e4; r_crack_names.in.req.req1.unknown2 = 0x00000407; r_crack_names.in.req.req1.count = 1; r_crack_names.in.req.req1.names = names; r_crack_names.in.req.req1.format_flags = DRSUAPI_DS_NAME_FLAG_NO_FLAGS; r_crack_names.in.req.req1.format_offered= DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY; r_crack_names.in.req.req1.format_desired= DRSUAPI_DS_NAME_FORMAT_FQDN_1779; names[0].str = dom_sid_string(tmp_ctx, r->out.account_sid); if (!names[0].str) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } status = dcerpc_drsuapi_DsCrackNames(drsuapi_pipe, tmp_ctx, &r_crack_names); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", names[0].str, dcerpc_errstr(tmp_ctx, drsuapi_pipe->last_fault_code)); talloc_free(tmp_ctx); return status; } else { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", names[0].str, nt_errstr(status)); talloc_free(tmp_ctx); return status; } } else if (!W_ERROR_IS_OK(r_crack_names.out.result)) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed - %s", win_errstr(r_crack_names.out.result)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } else if (r_crack_names.out.level != 1 || !r_crack_names.out.ctr.ctr1 || r_crack_names.out.ctr.ctr1->count != 1) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed"); talloc_free(tmp_ctx); return NT_STATUS_INVALID_PARAMETER; } else if (r_crack_names.out.ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed: %d", r_crack_names.out.ctr.ctr1->array[0].status); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } else if (r_crack_names.out.ctr.ctr1->array[0].result_name == NULL) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed: no result name"); talloc_free(tmp_ctx); return NT_STATUS_INVALID_PARAMETER; } /* Store the DN of our machine account. */ account_dn_str = r_crack_names.out.ctr.ctr1->array[0].result_name; account_dn = ldb_dn_new(tmp_ctx, remote_ldb, account_dn_str); if (! ldb_dn_validate(account_dn)) { r->out.error_string = talloc_asprintf(r, "Invalid account dn: %s", account_dn_str); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* Now we know the user's DN, open with LDAP, read and modify a few things */ remote_ldb_url = talloc_asprintf(tmp_ctx, "ldap://%s", drsuapi_binding->target_hostname); if (!remote_ldb_url) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } remote_ldb = ldb_wrap_connect(tmp_ctx, remote_ldb_url, NULL, ctx->cred, 0, NULL); if (!remote_ldb) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* search for the user's record */ ret = ldb_search(remote_ldb, account_dn, LDB_SCOPE_BASE, NULL, attrs, &res); if (ret != LDB_SUCCESS) { r->out.error_string = talloc_asprintf(r, "ldb_search for %s failed - %s", account_dn_str, ldb_errstring(remote_ldb)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } talloc_steal(tmp_ctx, res); if (res->count != 1) { r->out.error_string = talloc_asprintf(r, "ldb_search for %s failed - found %d entries", account_dn_str, res->count); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* If we have a kvno recorded in AD, we need it locally as well */ kvno = ldb_msg_find_attr_as_uint(res->msgs[0], "msDS-KeyVersionNumber", 0); /* Prepare a new message, for the modify */ msg = ldb_msg_new(tmp_ctx); if (!msg) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } msg->dn = res->msgs[0]->dn; { int i; const char *service_principal_name[6]; const char *dns_host_name = strlower_talloc(tmp_ctx, talloc_asprintf(tmp_ctx, "%s.%s", r->in.netbios_name, realm)); if (!dns_host_name) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } service_principal_name[0] = talloc_asprintf(tmp_ctx, "host/%s", dns_host_name); service_principal_name[1] = talloc_asprintf(tmp_ctx, "host/%s", strlower_talloc(tmp_ctx, r->in.netbios_name)); service_principal_name[2] = talloc_asprintf(tmp_ctx, "host/%s/%s", dns_host_name, realm); service_principal_name[3] = talloc_asprintf(tmp_ctx, "host/%s/%s", strlower_talloc(tmp_ctx, r->in.netbios_name), realm); service_principal_name[4] = talloc_asprintf(tmp_ctx, "host/%s/%s", dns_host_name, r->out.domain_name); service_principal_name[5] = talloc_asprintf(tmp_ctx, "host/%s/%s", strlower_talloc(tmp_ctx, r->in.netbios_name), r->out.domain_name); for (i=0; i < ARRAY_SIZE(service_principal_name); i++) { if (!service_principal_name[i]) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rtn = samdb_msg_add_string(remote_ldb, tmp_ctx, msg, "servicePrincipalName", service_principal_name[i]); if (rtn == -1) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } } rtn = samdb_msg_add_string(remote_ldb, tmp_ctx, msg, "dNSHostName", dns_host_name); if (rtn == -1) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rtn = samdb_replace(remote_ldb, tmp_ctx, msg); if (rtn != 0) { r->out.error_string = talloc_asprintf(r, "Failed to replace entries on %s", ldb_dn_get_linearized(msg->dn)); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } } /* DsCrackNames to find out the DN of the domain. */ r_crack_names.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT; r_crack_names.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779; names[0].str = talloc_asprintf(tmp_ctx, "%s\\", r->out.domain_name); if (!names[0].str) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } status = dcerpc_drsuapi_DsCrackNames(drsuapi_pipe, tmp_ctx, &r_crack_names); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", r->in.domain_name, dcerpc_errstr(tmp_ctx, drsuapi_pipe->last_fault_code)); talloc_free(tmp_ctx); return status; } else { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", r->in.domain_name, nt_errstr(status)); talloc_free(tmp_ctx); return status; } } else if (!W_ERROR_IS_OK(r_crack_names.out.result)) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed - %s", win_errstr(r_crack_names.out.result)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } else if (r_crack_names.out.level != 1 || !r_crack_names.out.ctr.ctr1 || r_crack_names.out.ctr.ctr1->count != 1 || !r_crack_names.out.ctr.ctr1->array[0].result_name || r_crack_names.out.ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed"); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* Store the account DN. */ r->out.account_dn_str = account_dn_str; talloc_steal(r, account_dn_str); /* Store the domain DN. */ r->out.domain_dn_str = r_crack_names.out.ctr.ctr1->array[0].result_name; talloc_steal(r, r_crack_names.out.ctr.ctr1->array[0].result_name); r->out.kvno = kvno; if (r->in.acct_type == ACB_SVRTRUST) { status = libnet_JoinSite(remote_ldb, r); } talloc_free(tmp_ctx); return status; }