Example #1
0
static bool test_handles_drsuapi(struct torture_context *torture)
{
	NTSTATUS status;
	struct dcerpc_pipe *p1, *p2;
	struct policy_handle handle;
	struct policy_handle handle2;
	struct GUID bind_guid;
	struct drsuapi_DsBind r;
	struct drsuapi_DsUnbind c;
	TALLOC_CTX *mem_ctx = talloc_new(torture);

	torture_comment(torture, "RPC-HANDLE-DRSUAPI\n");

	status = torture_rpc_connection(mem_ctx, &p1, &dcerpc_table_drsuapi);
	torture_assert_ntstatus_ok(torture, status, "opening drsuapi pipe1");

	status = torture_rpc_connection(mem_ctx, &p2, &dcerpc_table_drsuapi);
	torture_assert_ntstatus_ok(torture, status, "opening drsuapi pipe1");

	GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid);

	r.in.bind_guid = &bind_guid;
	r.in.bind_info = NULL;
	r.out.bind_handle = &handle;

	status = dcerpc_drsuapi_DsBind(p1, mem_ctx, &r);
	if (!NT_STATUS_IS_OK(status)) {
		torture_comment(torture, "drsuapi_DsBind not supported - skipping\n");
		talloc_free(mem_ctx);
		return true;
	}

	c.in.bind_handle = &handle;
	c.out.bind_handle = &handle2;

	status = dcerpc_drsuapi_DsUnbind(p2, mem_ctx, &c);
	torture_assert_ntstatus_equal(torture, status, NT_STATUS_NET_WRITE_FAULT, 
				      "closing policy handle on p2");
	torture_assert_int_equal(torture, p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH, 
				      "closing policy handle on p2");

	status = dcerpc_drsuapi_DsUnbind(p1, mem_ctx, &c);
	torture_assert_ntstatus_ok(torture, status, "closing policy handle on p1");

	status = dcerpc_drsuapi_DsUnbind(p1, mem_ctx, &c);
	torture_assert_ntstatus_equal(torture, status, NT_STATUS_NET_WRITE_FAULT, 
				      "closing policy handle on p1 again");
	torture_assert_int_equal(torture, p1->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH, 
				      "closing policy handle on p1 again");
	
	talloc_free(mem_ctx);

	return true;
}
Example #2
0
/*
  get a DRSUAPI policy handle
*/
static bool get_policy_handle(struct dcerpc_pipe *p,
			      TALLOC_CTX *mem_ctx, 
			      struct policy_handle *handle)
{
	NTSTATUS status;
	struct drsuapi_DsBind r;

	ZERO_STRUCT(r);
	r.out.bind_handle = handle;

	status = dcerpc_drsuapi_DsBind(p, mem_ctx, &r);
	if (!NT_STATUS_IS_OK(status)) {
		printf("drsuapi_DsBind failed - %s\n", nt_errstr(status));
		return false;
	}

	return true;
}
Example #3
0
bool test_DsBind(struct dcerpc_pipe *p,
		 struct torture_context *tctx,
		 struct DsPrivate *priv)
{
	NTSTATUS status;
	struct drsuapi_DsBind r;

	GUID_from_string(DRSUAPI_DS_BIND_GUID, &priv->bind_guid);

	r.in.bind_guid = &priv->bind_guid;
	r.in.bind_info = NULL;
	r.out.bind_handle = &priv->bind_handle;

	torture_comment(tctx, "testing DsBind\n");

	status = dcerpc_drsuapi_DsBind(p, tctx, &r);
	torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsBind");

	return true;
}
Example #4
0
static NTSTATUS libnet_dssync_bind(TALLOC_CTX *mem_ctx,
				   struct dssync_context *ctx)
{
	NTSTATUS status;
	WERROR werr;

	struct GUID bind_guid;
	struct drsuapi_DsBindInfoCtr bind_info;
	struct drsuapi_DsBindInfo28 info28;
	struct dcerpc_binding_handle *b = ctx->cli->binding_handle;

	ZERO_STRUCT(info28);

	GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid);

	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_BASE;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
	info28.site_guid		= GUID_zero();
	info28.pid			= 508;
	info28.repl_epoch		= 0;

	bind_info.length = 28;
	bind_info.info.info28 = info28;

	status = dcerpc_drsuapi_DsBind(b, mem_ctx,
				       &bind_guid,
				       &bind_info,
				       &ctx->bind_handle,
				       &werr);

	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	if (!W_ERROR_IS_OK(werr)) {
		return werror_to_ntstatus(werr);
	}

	ZERO_STRUCT(ctx->remote_info28);
	switch (bind_info.length) {
	case 24: {
		struct drsuapi_DsBindInfo24 *info24;
		info24 = &bind_info.info.info24;
		ctx->remote_info28.site_guid		= info24->site_guid;
		ctx->remote_info28.supported_extensions	= info24->supported_extensions;
		ctx->remote_info28.pid			= info24->pid;
		ctx->remote_info28.repl_epoch		= 0;
		break;
	}
	case 28: {
		ctx->remote_info28 = bind_info.info.info28;
		break;
	}
	case 32: {
		struct drsuapi_DsBindInfo32 *info32;
		info32 = &bind_info.info.info32;
		ctx->remote_info28.site_guid		= info32->site_guid;
		ctx->remote_info28.supported_extensions	= info32->supported_extensions;
		ctx->remote_info28.pid			= info32->pid;
		ctx->remote_info28.repl_epoch		= info32->repl_epoch;
		break;
	}
	case 48: {
		struct drsuapi_DsBindInfo48 *info48;
		info48 = &bind_info.info.info48;
		ctx->remote_info28.site_guid		= info48->site_guid;
		ctx->remote_info28.supported_extensions	= info48->supported_extensions;
		ctx->remote_info28.pid			= info48->pid;
		ctx->remote_info28.repl_epoch		= info48->repl_epoch;
		break;
	}
	case 52: {
		struct drsuapi_DsBindInfo52 *info52;
		info52 = &bind_info.info.info52;
		ctx->remote_info28.site_guid		= info52->site_guid;
		ctx->remote_info28.supported_extensions	= info52->supported_extensions;
		ctx->remote_info28.pid			= info52->pid;
		ctx->remote_info28.repl_epoch		= info52->repl_epoch;
		break;
	}
	default:
		DEBUG(1, ("Warning: invalid info length in bind info: %d\n",
			  bind_info.length));
		break;
	}

	return status;
}
Example #5
0
static WERROR cmd_drsuapi_cracknames(struct rpc_pipe_client *cli,
				     TALLOC_CTX *mem_ctx, int argc,
				     const char **argv)
{
	NTSTATUS status;
	WERROR werr;
	int i;

	struct GUID bind_guid;
	struct policy_handle bind_handle;
	struct dcerpc_binding_handle *b = cli->binding_handle;

	union drsuapi_DsNameCtr ctr;

	if (argc < 2) {
		printf("usage: %s name\n", argv[0]);
		return WERR_OK;
	}

	GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid);

	status = dcerpc_drsuapi_DsBind(b, mem_ctx,
				       &bind_guid,
				       NULL,
				       &bind_handle,
				       &werr);

	if (!NT_STATUS_IS_OK(status)) {
		return ntstatus_to_werror(status);
	}

	if (!W_ERROR_IS_OK(werr)) {
		return werr;
	}

	werr = cracknames(cli, mem_ctx,
			  &bind_handle,
			  DRSUAPI_DS_NAME_FORMAT_UNKNOWN,
			  DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
			  1,
			  argv+1,
			  &ctr);

	if (!W_ERROR_IS_OK(werr)) {
		goto out;
	}

	for (i=0; i < ctr.ctr1->count; i++) {
		printf("status: %d\n",
			ctr.ctr1->array[i].status);
		printf("dns_domain_name: %s\n",
			ctr.ctr1->array[i].dns_domain_name);
		printf("result_name: %s\n",
			ctr.ctr1->array[i].result_name);
	}

 out:
	if (is_valid_policy_hnd(&bind_handle)) {
		WERROR _werr;
		dcerpc_drsuapi_DsUnbind(b, mem_ctx, &bind_handle, &_werr);
	}

	return werr;
}
Example #6
0
static WERROR cmd_drsuapi_getncchanges(struct rpc_pipe_client *cli,
				       TALLOC_CTX *mem_ctx, int argc,
				       const char **argv)
{
	NTSTATUS status;
	WERROR werr;

	struct policy_handle bind_handle;
	struct dcerpc_binding_handle *b = cli->binding_handle;

	struct GUID bind_guid;
	struct drsuapi_DsBindInfoCtr bind_info;
	struct drsuapi_DsBindInfo28 info28;

	const char *nc_dn = NULL;

	DATA_BLOB session_key;

	uint32_t level = 8;
	bool single = false;
	uint32_t level_out = 0;
	union drsuapi_DsGetNCChangesRequest req;
	union drsuapi_DsGetNCChangesCtr ctr;
	struct drsuapi_DsReplicaObjectIdentifier nc;

	struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
	struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
	uint32_t out_level = 0;
	int y;

	uint32_t supported_extensions = 0;
	uint32_t replica_flags	= DRSUAPI_DRS_WRIT_REP |
				  DRSUAPI_DRS_INIT_SYNC |
				  DRSUAPI_DRS_PER_SYNC |
				  DRSUAPI_DRS_GET_ANC |
				  DRSUAPI_DRS_NEVER_SYNCED;

	if (argc > 3) {
		printf("usage: %s [naming_context_or_object_dn [single]]\n", argv[0]);
		return WERR_OK;
	}

	if (argc >= 2) {
		nc_dn = argv[1];
	}

	if (argc == 3) {
		if (strequal(argv[2], "single")) {
			single = true;
		} else {
			printf("warning: ignoring unknown argument '%s'\n",
			       argv[2]);
		}
	}

	ZERO_STRUCT(info28);

	ZERO_STRUCT(req);

	GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid);

	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_BASE;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
	info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
	info28.site_guid		= GUID_zero();
	info28.pid			= 0;
	info28.repl_epoch		= 0;

	bind_info.length = 28;
	bind_info.info.info28 = info28;

	status = dcerpc_drsuapi_DsBind(b, mem_ctx,
				       &bind_guid,
				       &bind_info,
				       &bind_handle,
				       &werr);

	if (!NT_STATUS_IS_OK(status)) {
		return ntstatus_to_werror(status);
	}

	if (!W_ERROR_IS_OK(werr)) {
		return werr;
	}

	if (bind_info.length == 24) {
		supported_extensions = bind_info.info.info24.supported_extensions;
	} else if (bind_info.length == 28) {
		supported_extensions = bind_info.info.info28.supported_extensions;
	} else if (bind_info.length == 32) {
		supported_extensions = bind_info.info.info32.supported_extensions;
	} else if (bind_info.length == 48) {
		supported_extensions = bind_info.info.info48.supported_extensions;
	} else if (bind_info.length == 52) {
		supported_extensions = bind_info.info.info52.supported_extensions;
	}

	if (!nc_dn) {

		union drsuapi_DsNameCtr crack_ctr;
		const char *name;

		name = talloc_asprintf(mem_ctx, "%s\\", lp_workgroup());
		W_ERROR_HAVE_NO_MEMORY(name);

		werr = cracknames(cli, mem_ctx,
				  &bind_handle,
				  DRSUAPI_DS_NAME_FORMAT_UNKNOWN,
				  DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
				  1,
				  &name,
				  &crack_ctr);
		if (!W_ERROR_IS_OK(werr)) {
			return werr;
		}

		if (crack_ctr.ctr1->count != 1) {
			return WERR_NO_SUCH_DOMAIN;
		}

		if (crack_ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
			return WERR_NO_SUCH_DOMAIN;
		}

		nc_dn = talloc_strdup(mem_ctx, crack_ctr.ctr1->array[0].result_name);
		W_ERROR_HAVE_NO_MEMORY(nc_dn);

		printf("using: %s\n", nc_dn);
	}

	nc.dn = nc_dn;
	nc.guid = GUID_zero();
	nc.sid = (struct dom_sid) {0};

	if (supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
		level = 8;
		req.req8.naming_context		= &nc;
		req.req8.replica_flags		= replica_flags;
		req.req8.max_object_count	= 402;
		req.req8.max_ndr_size		= 402116;
		if (single) {
			req.req8.extended_op	= DRSUAPI_EXOP_REPL_OBJ;
		}
	} else {
		level = 5;
		req.req5.naming_context		= &nc;
		req.req5.replica_flags		= replica_flags;
		req.req5.max_object_count	= 402;
		req.req5.max_ndr_size		= 402116;
		if (single) {
			req.req5.extended_op	= DRSUAPI_EXOP_REPL_OBJ;
		}
	}

	for (y=0; ;y++) {

		if (level == 8) {
			DEBUG(1,("start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",y,
				(long long)req.req8.highwatermark.tmp_highest_usn,
				(long long)req.req8.highwatermark.highest_usn));
		}

		status = dcerpc_drsuapi_DsGetNCChanges(b, mem_ctx,
						       &bind_handle,
						       level,
						       &req,
						       &level_out,
						       &ctr,
						       &werr);
		if (!NT_STATUS_IS_OK(status)) {
			werr = ntstatus_to_werror(status);
			printf("Failed to get NC Changes: %s",
				get_friendly_nt_error_msg(status));
			goto out;
		}

		if (!W_ERROR_IS_OK(werr)) {
			printf("Failed to get NC Changes: %s",
				get_friendly_werror_msg(werr));
			goto out;
		}

		if (level_out == 1) {
			out_level = 1;
			ctr1 = &ctr.ctr1;
		} else if (level_out == 2 && ctr.ctr2.mszip1.ts) {
			out_level = 1;
			ctr1 = &ctr.ctr2.mszip1.ts->ctr1;
		}

		status = cli_get_session_key(mem_ctx, cli, &session_key);
		if (!NT_STATUS_IS_OK(status)) {
			printf("Failed to get Session Key: %s",
				nt_errstr(status));
			return ntstatus_to_werror(status);
		}

		if (out_level == 1) {
			DEBUG(1,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y,
				(long long)ctr1->new_highwatermark.tmp_highest_usn,
				(long long)ctr1->new_highwatermark.highest_usn));
#if 0
			libnet_dssync_decrypt_attributes(mem_ctx,
							 &session_key,
							 ctr1->first_object);
#endif
			if (ctr1->more_data) {
				req.req5.highwatermark = ctr1->new_highwatermark;
				continue;
			}
		}

		if (level_out == 6) {
			out_level = 6;
			ctr6 = &ctr.ctr6;
		} else if (level_out == 7
			   && ctr.ctr7.level == 6
			   && ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP
			   && ctr.ctr7.ctr.mszip6.ts) {
			out_level = 6;
			ctr6 = &ctr.ctr7.ctr.mszip6.ts->ctr6;
		} else if (level_out == 7
			   && ctr.ctr7.level == 6
			   && ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS
			   && ctr.ctr7.ctr.xpress6.ts) {
			out_level = 6;
			ctr6 = &ctr.ctr7.ctr.xpress6.ts->ctr6;
		}

		if (out_level == 6) {
			DEBUG(1,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y,
				(long long)ctr6->new_highwatermark.tmp_highest_usn,
				(long long)ctr6->new_highwatermark.highest_usn));
#if 0
			libnet_dssync_decrypt_attributes(mem_ctx,
							 &session_key,
							 ctr6->first_object);
#endif
			if (ctr6->more_data) {
				req.req8.highwatermark = ctr6->new_highwatermark;
				continue;
			}
		}

		break;
	}

 out:
	return werr;
}

/* List of commands exported by this module */

struct cmd_set drsuapi_commands[] = {

	{ "DRSUAPI" },
	{ "dscracknames", RPC_RTYPE_WERROR, NULL, cmd_drsuapi_cracknames, &ndr_table_drsuapi, NULL, "Crack Name", "" },
	{ "dsgetdcinfo", RPC_RTYPE_WERROR, NULL, cmd_drsuapi_getdcinfo, &ndr_table_drsuapi, NULL, "Get Domain Controller Info", "" },
	{ "dsgetncchanges", RPC_RTYPE_WERROR, NULL, cmd_drsuapi_getncchanges, &ndr_table_drsuapi, NULL, "Get NC Changes", "" },
	{ "dswriteaccountspn", RPC_RTYPE_WERROR, NULL, cmd_drsuapi_writeaccountspn, &ndr_table_drsuapi, NULL, "Write Account SPN", "" },
	{ NULL }
};
Example #7
0
static WERROR cmd_drsuapi_writeaccountspn(struct rpc_pipe_client *cli,
					  TALLOC_CTX *mem_ctx, int argc,
					  const char **argv)
{
	NTSTATUS status;
	WERROR werr;

	struct GUID bind_guid;
	struct policy_handle bind_handle;
	struct dcerpc_binding_handle *b = cli->binding_handle;
	struct drsuapi_DsNameString *spn_names = NULL;

	int i = 0;
	uint32_t level_out;
	union drsuapi_DsWriteAccountSpnRequest req;
	union drsuapi_DsWriteAccountSpnResult result;

	if (argc < 4) {
		printf("usage: %s [add|replace|delete] dn [spn_names]+\n", argv[0]);
		return WERR_OK;
	}

	req.req1.unknown1 = 0;  /* Unused, must be 0 */
	req.req1.object_dn = argv[2];
	req.req1.count = argc - 3;

	if (strcmp(argv[1], "add") == 0) {
		req.req1.operation = DRSUAPI_DS_SPN_OPERATION_ADD;
	} else if (strcmp(argv[1], "replace") == 0) {
		req.req1.operation = DRSUAPI_DS_SPN_OPERATION_REPLACE;
	} else if (strcmp(argv[1], "delete") == 0) {
		req.req1.operation = DRSUAPI_DS_SPN_OPERATION_DELETE;
	} else {
		printf("usage: %s [add|replace|delete] dn [spn_names]+\n", argv[0]);
		return WERR_OK;
	}

	spn_names = talloc_zero_array(mem_ctx,
				      struct drsuapi_DsNameString,
				      req.req1.count);
	W_ERROR_HAVE_NO_MEMORY(spn_names);

	for (i=0; i<req.req1.count; i++) {
		spn_names[i].str = argv[i + 3];
	}

	req.req1.spn_names = spn_names;

	GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid);

	status = dcerpc_drsuapi_DsBind(b, mem_ctx,
				       &bind_guid,
				       NULL,
				       &bind_handle,
				       &werr);

	if (!NT_STATUS_IS_OK(status)) {
		return ntstatus_to_werror(status);
	}

	if (!W_ERROR_IS_OK(werr)) {
		return werr;
	}

	status = dcerpc_drsuapi_DsWriteAccountSpn(b, mem_ctx,
						  &bind_handle,
						  1,
						  &req,
						  &level_out,
						  &result,
						  &werr);

	if (!NT_STATUS_IS_OK(status)) {
		werr = ntstatus_to_werror(status);
		goto out;
	}

	if (!W_ERROR_IS_OK(werr)) {
		goto out;
	}

 out:
	if (is_valid_policy_hnd(&bind_handle)) {
		WERROR _werr;
		dcerpc_drsuapi_DsUnbind(b, mem_ctx, &bind_handle, &_werr);
	}

	return werr;
}
Example #8
0
static WERROR cmd_drsuapi_getdcinfo(struct rpc_pipe_client *cli,
				    TALLOC_CTX *mem_ctx, int argc,
				    const char **argv)
{
	NTSTATUS status;
	WERROR werr;

	struct GUID bind_guid;
	struct policy_handle bind_handle;
	struct dcerpc_binding_handle *b = cli->binding_handle;

	const char *domain = NULL;
	int32_t level = 1;
	int32_t level_out;
	union drsuapi_DsGetDCInfoRequest req;
	union drsuapi_DsGetDCInfoCtr ctr;

	if (argc < 2) {
		printf("usage: %s domain [level]\n", argv[0]);
		return WERR_OK;
	}

	domain = argv[1];
	if (argc >= 3) {
		level = atoi(argv[2]);
	}

	GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid);

	status = dcerpc_drsuapi_DsBind(b, mem_ctx,
				       &bind_guid,
				       NULL,
				       &bind_handle,
				       &werr);

	if (!NT_STATUS_IS_OK(status)) {
		return ntstatus_to_werror(status);
	}

	if (!W_ERROR_IS_OK(werr)) {
		return werr;
	}

	req.req1.domain_name = domain;
	req.req1.level = level;

	status = dcerpc_drsuapi_DsGetDomainControllerInfo(b, mem_ctx,
							  &bind_handle,
							  1,
							  &req,
							  &level_out,
							  &ctr,
							  &werr);
	if (!NT_STATUS_IS_OK(status)) {
		werr = ntstatus_to_werror(status);
		goto out;
	}

	if (!W_ERROR_IS_OK(werr)) {
		goto out;
	}

	display_domain_controller_info(level_out, &ctr);
 out:
	if (is_valid_policy_hnd(&bind_handle)) {
		WERROR _werr;
		dcerpc_drsuapi_DsUnbind(b, mem_ctx, &bind_handle, &_werr);
	}

	return werr;
}
Example #9
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;

	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(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(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			= 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, int32_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(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_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, NULL);
	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 (! 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;
	}

	/* 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;

	{
		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_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;
}