예제 #1
0
/*
  eventlog6_EvtRpcRegisterLogQuery
*/
static WERROR dcesrv_eventlog6_EvtRpcRegisterLogQuery(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
		       struct eventlog6_EvtRpcRegisterLogQuery *r)
{
	struct dcesrv_handle *handle;

	handle = dcesrv_handle_new(dce_call->context, 0);
	W_ERROR_HAVE_NO_MEMORY(handle);

	r->out.handle = &handle->wire_handle;

	handle = dcesrv_handle_new(dce_call->context, 0);
	W_ERROR_HAVE_NO_MEMORY(handle);

	r->out.opControl = &handle->wire_handle;

	return WERR_OK;
}
예제 #2
0
/* 
  spoolss_ReplyOpenPrinter 
*/
static WERROR dcesrv_spoolss_ReplyOpenPrinter(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
		       struct spoolss_ReplyOpenPrinter *r)
{
	struct dcesrv_handle *handle;

	handle = dcesrv_handle_new(dce_call->context, SPOOLSS_NOTIFY);
	W_ERROR_HAVE_NO_MEMORY(handle);

	/* For now, just return a handle */

	*r->out.handle = handle->wire_handle;

	return WERR_OK;
}
예제 #3
0
/* 
  spoolss_OpenPrinterEx 
*/
static WERROR dcesrv_spoolss_OpenPrinterEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
		       struct spoolss_OpenPrinterEx *r)
{
	struct ntptr_context *ntptr = talloc_get_type(dce_call->context->private_data, struct ntptr_context);
	struct ntptr_GenericHandle *handle;
	struct dcesrv_handle *h;
	const char *server;
	const char *object;
	enum ntptr_HandleType type;
	WERROR status;

	ZERO_STRUCTP(r->out.handle);

	status = dcesrv_spoolss_parse_printer_name(mem_ctx, r->in.printername, &server, &object, &type);
	W_ERROR_NOT_OK_RETURN(status);

	status = dcesrv_spoolss_check_server_name(dce_call, mem_ctx, server);
	W_ERROR_NOT_OK_RETURN(status);

	switch (type) {
		case NTPTR_HANDLE_SERVER:
			status = ntptr_OpenPrintServer(ntptr, mem_ctx, r, server, &handle);
			W_ERROR_NOT_OK_RETURN(status);
			break;
		case NTPTR_HANDLE_PORT:
			status = ntptr_OpenPort(ntptr, mem_ctx, r, object, &handle);
			W_ERROR_NOT_OK_RETURN(status);
			break;
		case NTPTR_HANDLE_MONITOR:
			status = ntptr_OpenMonitor(ntptr, mem_ctx, r, object, &handle);
			W_ERROR_NOT_OK_RETURN(status);
			break;
		case NTPTR_HANDLE_PRINTER:
			status = ntptr_OpenPrinter(ntptr, mem_ctx, r, object, &handle);
			W_ERROR_NOT_OK_RETURN(status);
			break;
		default:
			return WERR_FOOBAR;
	}

	h = dcesrv_handle_new(dce_call->context, handle->type);
	W_ERROR_HAVE_NO_MEMORY(h);

	h->data = talloc_steal(h, handle);

	*r->out.handle	= h->wire_handle;

	return WERR_OK;
}
예제 #4
0
파일: rpc_winreg.c 프로젝트: gojdic/samba
/*
  winreg_CreateKey
*/
static WERROR dcesrv_winreg_CreateKey(struct dcesrv_call_state *dce_call,
				      TALLOC_CTX *mem_ctx,
				      struct winreg_CreateKey *r)
{
	struct dcesrv_handle *h, *newh;
	struct security_descriptor sd;
	struct registry_key *key;
	WERROR result;

	DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
	key = h->data;

	newh = dcesrv_handle_new(dce_call->context, HTYPE_REGKEY);

	switch (security_session_user_level(dce_call->conn->auth_state.session_info))
	{
	case SECURITY_SYSTEM:
	case SECURITY_ADMINISTRATOR:
		/* the security descriptor is optional */
		if (r->in.secdesc != NULL) {
			DATA_BLOB sdblob;
			enum ndr_err_code ndr_err;
			sdblob.data = r->in.secdesc->sd.data;
			sdblob.length = r->in.secdesc->sd.len;
			if (sdblob.data == NULL) {
				return WERR_INVALID_PARAM;
			}
			ndr_err = ndr_pull_struct_blob_all(&sdblob, mem_ctx, NULL, &sd,
							   (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
			if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
				return WERR_INVALID_PARAM;
			}
		}
		
		result = reg_key_add_name(newh, key, r->in.name.name, NULL,
			r->in.secdesc?&sd:NULL, (struct registry_key **)&newh->data);
		if (W_ERROR_IS_OK(result)) {
			r->out.new_handle = &newh->wire_handle;
		} else {
			talloc_free(newh);
		}
		
		return result;
	default:
		return WERR_ACCESS_DENIED;
	}
}
/* 
  lsa_OpenPolicy2
*/
NTSTATUS dcesrv_lsa_OpenPolicy2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
				struct lsa_OpenPolicy2 *r)
{
	enum dcerpc_transport_t transport =
		dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description);
	NTSTATUS status;
	struct lsa_policy_state *state;
	struct dcesrv_handle *handle;

	if (transport != NCACN_NP && transport != NCALRPC) {
		DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
	}

	ZERO_STRUCTP(r->out.handle);

	if (r->in.attr != NULL &&
	    r->in.attr->root_dir != NULL) {
		/* MS-LSAD 3.1.4.4.1 */
		return NT_STATUS_INVALID_PARAMETER;
	}

	status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, &state);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	handle = dcesrv_handle_new(dce_call->context, LSA_HANDLE_POLICY);
	if (!handle) {
		return NT_STATUS_NO_MEMORY;
	}

	handle->data = talloc_steal(handle, state);

	/* need to check the access mask against - need ACLs - fails
	   WSPP test */
	state->access_mask = r->in.access_mask;
	state->handle = handle;
	*r->out.handle = handle->wire_handle;

	/* note that we have completely ignored the attr element of
	   the OpenPolicy. As far as I can tell, this is what w2k3
	   does */

	return NT_STATUS_OK;
}
예제 #6
0
파일: rpc_winreg.c 프로젝트: gojdic/samba
static WERROR dcesrv_winreg_openhive(struct dcesrv_call_state *dce_call,
				     TALLOC_CTX *mem_ctx, uint32_t hkey,
				     struct policy_handle **outh)
{
	struct registry_context *ctx = dce_call->context->private_data;
	struct dcesrv_handle *h;
	WERROR result;

	h = dcesrv_handle_new(dce_call->context, HTYPE_REGKEY);

	result = reg_get_predefined_key(ctx, hkey,
				       (struct registry_key **)&h->data);
	if (!W_ERROR_IS_OK(result)) {
		return result;
	}
	*outh = &h->wire_handle;

	return result;
}
예제 #7
0
파일: handles.c 프로젝트: 0x24bin/winexe-1
/**
  find an internal handle given a wire handle. If the wire handle is NULL then
  allocate a new handle
*/
_PUBLIC_ struct dcesrv_handle *dcesrv_handle_fetch(
					  struct dcesrv_connection_context *context, 
					  struct policy_handle *p,
					  uint8_t handle_type)
{
	struct dcesrv_handle *h;
	struct dom_sid *sid;

	sid = context->conn->auth_state.session_info->security_token->user_sid;

	if (policy_handle_empty(p)) {
		/* TODO: we should probably return a NULL handle here */
		return dcesrv_handle_new(context, handle_type);
	}

	for (h=context->assoc_group->handles; h; h=h->next) {
		if (h->wire_handle.handle_type == p->handle_type &&
		    GUID_equal(&p->uuid, &h->wire_handle.uuid)) {
			if (handle_type != DCESRV_HANDLE_ANY &&
			    p->handle_type != handle_type) {
				DEBUG(0,("client gave us the wrong handle type (%d should be %d)\n",
					 p->handle_type, handle_type));
				return NULL;
			}
			if (!dom_sid_equal(h->sid, sid)) {
				DEBUG(0,(__location__ ": Attempt to use invalid sid %s - %s\n",
					 dom_sid_string(context, h->sid),
					 dom_sid_string(context, sid)));
				return NULL;
			}
			if (h->iface != context->iface) {
				DEBUG(0,(__location__ ": Attempt to use invalid iface\n"));
				return NULL;
			}
			return h;
		}
	}

	return NULL;
}
예제 #8
0
파일: lsa_init.c 프로젝트: AllardJ/Tomato
/* 
  lsa_OpenPolicy2
*/
NTSTATUS dcesrv_lsa_OpenPolicy2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
				struct lsa_OpenPolicy2 *r)
{
	NTSTATUS status;
	struct lsa_policy_state *state;
	struct dcesrv_handle *handle;

	ZERO_STRUCTP(r->out.handle);

	if (r->in.attr != NULL &&
	    r->in.attr->root_dir != NULL) {
		/* MS-LSAD 3.1.4.4.1 */
		return NT_STATUS_INVALID_PARAMETER;
	}

	status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, &state);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	handle = dcesrv_handle_new(dce_call->context, LSA_HANDLE_POLICY);
	if (!handle) {
		return NT_STATUS_NO_MEMORY;
	}

	handle->data = talloc_steal(handle, state);

	/* need to check the access mask against - need ACLs - fails
	   WSPP test */
	state->access_mask = r->in.access_mask;
	state->handle = handle;
	*r->out.handle = handle->wire_handle;

	/* note that we have completely ignored the attr element of
	   the OpenPolicy. As far as I can tell, this is what w2k3
	   does */

	return NT_STATUS_OK;
}
예제 #9
0
파일: rpc_winreg.c 프로젝트: gojdic/samba
/*
  winreg_OpenKey
*/
static WERROR dcesrv_winreg_OpenKey(struct dcesrv_call_state *dce_call,
				    TALLOC_CTX *mem_ctx,
				    struct winreg_OpenKey *r)
{
	struct dcesrv_handle *h, *newh;
	struct registry_key *key;
	WERROR result;

	DCESRV_PULL_HANDLE_FAULT(h, r->in.parent_handle, HTYPE_REGKEY);
	key = h->data;

	switch (security_session_user_level(dce_call->conn->auth_state.session_info))
	{
	case SECURITY_SYSTEM:
	case SECURITY_ADMINISTRATOR:
	case SECURITY_USER:
		if (r->in.keyname.name && strcmp(r->in.keyname.name, "") == 0) {
			newh = talloc_reference(dce_call->context, h);
			result = WERR_OK;
		} else {
			newh = dcesrv_handle_new(dce_call->context, HTYPE_REGKEY);
			result = reg_open_key(newh, key, r->in.keyname.name,
				(struct registry_key **)&newh->data);
		}
		
		if (W_ERROR_IS_OK(result)) {
			r->out.handle = &newh->wire_handle;
		} else {
			talloc_free(newh);
		}
		return result;
	default:
		return WERR_ACCESS_DENIED;
	}

}
예제 #10
0
/**
   \details exchange_nsp NspiBind (0x0) function, Initiates a NSPI
   session with the client.

   This function checks if the user is an Exchange user and input
   parameters like codepage are valid. If it passes the tests, the
   function initializes an emsabp context and returns to the client a
   valid policy_handle and expected reply parameters.

   \param dce_call pointer to the session context
   \param mem_ctx pointer to the memory context
   \param r pointer to the NspiBind call structure

   \return MAPI_E_SUCCESS on success, otherwise a MAPI error
 */
static void dcesrv_NspiBind(struct dcesrv_call_state *dce_call,
				       TALLOC_CTX *mem_ctx,
				       struct NspiBind *r)
{
	struct GUID			*guid = (struct GUID *) NULL;
	struct emsabp_context		*emsabp_ctx;
	struct dcesrv_handle		*handle;
	struct policy_handle		wire_handle;
	struct exchange_nsp_session	*session;

	DEBUG(5, ("exchange_nsp: NspiBind (0x0)\n"));

	/* Step 0. Ensure incoming user is authenticated */
	if (!dcesrv_call_authenticated(dce_call) && (r->in.dwFlags & fAnonymousLogin)) {
		DEBUG(1, ("No challenge requested by client, cannot authenticate\n"));

		wire_handle.handle_type = EXCHANGE_HANDLE_NSP;
		wire_handle.uuid = GUID_zero();
		*r->out.handle = wire_handle;

		r->out.mapiuid = r->in.mapiuid;
		DCESRV_NSP_RETURN(r, MAPI_E_FAILONEPROVIDER, NULL);
	}

	/* Step 1. Initialize the emsabp context */
	emsabp_ctx = emsabp_init(dce_call->conn->dce_ctx->lp_ctx, emsabp_tdb_ctx);
	if (!emsabp_ctx) {
		OC_ABORT(false, ("[exchange_nsp] Unable to initialize emsabp context"));

		wire_handle.handle_type = EXCHANGE_HANDLE_NSP;
		wire_handle.uuid = GUID_zero();
		*r->out.handle = wire_handle;

		r->out.mapiuid = r->in.mapiuid;
		DCESRV_NSP_RETURN(r, MAPI_E_FAILONEPROVIDER, NULL);
	}

	if (lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx, NULL, 
			    "exchange_nsp", "debug", false)) {
		emsabp_enable_debug(emsabp_ctx);
	}

	/* Step 2. Check if incoming user belongs to the Exchange organization */
	if ((emsabp_verify_user(dce_call, emsabp_ctx) == false) && (r->in.dwFlags & fAnonymousLogin)) {
		talloc_free(emsabp_ctx);

		wire_handle.handle_type = EXCHANGE_HANDLE_NSP;
		wire_handle.uuid = GUID_zero();
		*r->out.handle = wire_handle;

		r->out.mapiuid = r->in.mapiuid;
		DCESRV_NSP_RETURN(r, MAPI_E_LOGON_FAILED, emsabp_tdb_ctx);
	}

	/* Step 3. Check if valid cpID has been supplied */
	if (emsabp_verify_codepage(emsabp_ctx, r->in.pStat->CodePage) == false) {
		talloc_free(emsabp_ctx);

		wire_handle.handle_type = EXCHANGE_HANDLE_NSP;
		wire_handle.uuid = GUID_zero();
		*r->out.handle = wire_handle;

		r->out.mapiuid = r->in.mapiuid;
		DCESRV_NSP_RETURN(r, MAPI_E_UNKNOWN_CPID, emsabp_tdb_ctx);
	}

	/* Step 4. Retrieve OpenChange server GUID */
	guid = (struct GUID *) samdb_ntds_objectGUID(emsabp_ctx->samdb_ctx);
	if (!guid) {
		DCESRV_NSP_RETURN(r, MAPI_E_FAILONEPROVIDER, emsabp_ctx);
	}

	/* Step 5. Fill NspiBind reply */
	handle = dcesrv_handle_new(dce_call->context, EXCHANGE_HANDLE_NSP);
	if (!handle) {
		DCESRV_NSP_RETURN(r, MAPI_E_NOT_ENOUGH_RESOURCES, emsabp_ctx);
	}

	handle->data = (void *) emsabp_ctx;
	*r->out.handle = handle->wire_handle;
	r->out.mapiuid = guid;

	/* Search for an existing session and increment ref_count, otherwise create it */
	session = dcesrv_find_nsp_session(&handle->wire_handle.uuid);
	if (session) {
		mpm_session_increment_ref_count(session->session);
		DEBUG(5, ("  [unexpected]: existing nsp_session: %p; session: %p (ref++)\n", session, session->session));
	}
	else {
		DEBUG(5, ("%s: Creating new session\n", __func__));

		/* Step 6. Associate this emsabp context to the session */
		session = talloc((TALLOC_CTX *)nsp_session, struct exchange_nsp_session);
		if (!session) {
			DCESRV_NSP_RETURN(r, MAPI_E_NOT_ENOUGH_RESOURCES, emsabp_ctx);
		}

		session->session = mpm_session_init((TALLOC_CTX *)nsp_session, dce_call);
		if (!session->session) {
			DCESRV_NSP_RETURN(r, MAPI_E_NOT_ENOUGH_RESOURCES, emsabp_ctx);
		}

		session->uuid = handle->wire_handle.uuid;

		mpm_session_set_private_data(session->session, (void *) emsabp_ctx);
		mpm_session_set_destructor(session->session, emsabp_destructor);

		DLIST_ADD_END(nsp_session, session, struct exchange_nsp_session *);
	}

	DCESRV_NSP_RETURN(r, MAPI_E_SUCCESS, NULL);
}
예제 #11
0
/* 
  drsuapi_DsBind 
*/
static WERROR dcesrv_drsuapi_DsBind(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
		       struct drsuapi_DsBind *r)
{
	struct drsuapi_bind_state *b_state;
	struct dcesrv_handle *handle;
	struct drsuapi_DsBindInfoCtr *bind_info;
	struct GUID site_guid;
	struct ldb_result *site_res;
	struct ldb_dn *server_site_dn;
	static const char *site_attrs[] = { "objectGUID", NULL };
	struct ldb_result *ntds_res;
	struct ldb_dn *ntds_dn;
	static const char *ntds_attrs[] = { "ms-DS-ReplicationEpoch", NULL };
	uint32_t pid;
	uint32_t repl_epoch;
	int ret;
	struct auth_session_info *auth_info;
	WERROR werr;

	r->out.bind_info = NULL;
	ZERO_STRUCTP(r->out.bind_handle);

	b_state = talloc_zero(mem_ctx, struct drsuapi_bind_state);
	W_ERROR_HAVE_NO_MEMORY(b_state);

	/* if this is a DC connecting, give them system level access */
	werr = drs_security_level_check(dce_call, NULL);
	if (W_ERROR_IS_OK(werr)) {
		DEBUG(3,(__location__ ": doing DsBind with system_session\n"));
		auth_info = system_session(dce_call->conn->dce_ctx->lp_ctx);
	} else {
		auth_info = dce_call->conn->auth_state.session_info;
	}

	/*
	 * connect to the samdb
	 */
	b_state->sam_ctx = samdb_connect(b_state, dce_call->event_ctx, 
					 dce_call->conn->dce_ctx->lp_ctx, auth_info); 
	if (!b_state->sam_ctx) {
		return WERR_FOOBAR;
	}

	/*
	 * find out the guid of our own site
	 */
	server_site_dn = samdb_server_site_dn(b_state->sam_ctx, mem_ctx);
	W_ERROR_HAVE_NO_MEMORY(server_site_dn);

	ret = ldb_search(b_state->sam_ctx, mem_ctx, &site_res,
				 server_site_dn, LDB_SCOPE_BASE, site_attrs,
				 "(objectClass=*)");
	if (ret != LDB_SUCCESS) {
		return WERR_DS_DRA_INTERNAL_ERROR;
	}
	if (site_res->count != 1) {
		return WERR_DS_DRA_INTERNAL_ERROR;
	}
	site_guid = samdb_result_guid(site_res->msgs[0], "objectGUID");

	/*
	 * lookup the local servers Replication Epoch
	 */
	ntds_dn = samdb_ntds_settings_dn(b_state->sam_ctx);
	W_ERROR_HAVE_NO_MEMORY(ntds_dn);

	ret = ldb_search(b_state->sam_ctx, mem_ctx, &ntds_res,
				 ntds_dn, LDB_SCOPE_BASE, ntds_attrs,
				 "(objectClass=*)");
	if (ret != LDB_SUCCESS) {
		return WERR_DS_DRA_INTERNAL_ERROR;
	}
	if (ntds_res->count != 1) {
		return WERR_DS_DRA_INTERNAL_ERROR;
	}
	repl_epoch = samdb_result_uint(ntds_res->msgs[0], "ms-DS-ReplicationEpoch", 0);

	/*
	 * The "process identifier" of the client.
	 * According to the WSPP docs, sectin 5.35, this is
	 * for informational and debugging purposes only.
	 * The assignment is implementation specific.
	 */
	pid = 0;

	/*
	 * store the clients bind_guid
	 */
	if (r->in.bind_guid) {
		b_state->remote_bind_guid = *r->in.bind_guid;
	}

	/*
	 * store the clients bind_info
	 */
	if (r->in.bind_info) {
		switch (r->in.bind_info->length) {
		case 24: {
			struct drsuapi_DsBindInfo24 *info24;
			info24 = &r->in.bind_info->info.info24;
			b_state->remote_info28.supported_extensions	= info24->supported_extensions;
			b_state->remote_info28.site_guid		= info24->site_guid;
			b_state->remote_info28.pid			= info24->pid;
			b_state->remote_info28.repl_epoch		= 0;
			break;
		}
		case 28:
			b_state->remote_info28 = r->in.bind_info->info.info28;
			break;
		}
	}

	/*
	 * fill in our local bind info 28
	 */
	b_state->local_info28.supported_extensions	= 0;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_BASE;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
#if 0 /* we don't support MSZIP compression (only decompression) */
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
#endif
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_00100000;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
#if 0 /* we don't support XPRESS compression yet */
	b_state->local_info28.supported_extensions	|= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS;
#endif
	b_state->local_info28.site_guid			= site_guid;
	b_state->local_info28.pid			= pid;
	b_state->local_info28.repl_epoch		= repl_epoch;

	/*
	 * allocate the return bind_info
	 */
	bind_info = talloc(mem_ctx, struct drsuapi_DsBindInfoCtr);
	W_ERROR_HAVE_NO_MEMORY(bind_info);

	bind_info->length	= 28;
	bind_info->info.info28	= b_state->local_info28;

	/*
	 * allocate a bind handle
	 */
	handle = dcesrv_handle_new(dce_call->context, DRSUAPI_BIND_HANDLE);
	W_ERROR_HAVE_NO_MEMORY(handle);
	handle->data = talloc_steal(handle, b_state);

	/*
	 * prepare reply
	 */
	r->out.bind_info = bind_info;
	*r->out.bind_handle = handle->wire_handle;

	return WERR_OK;
}