Esempio n. 1
0
static int
ndr_svc_request(ndr_xa_t *mxa)
{
	ndr_binding_t	*mbind;
	ndr_service_t	*msvc;
	unsigned	p_cont_id;
	int		rc;

	mxa->opnum = mxa->recv_hdr.request_hdr.opnum;
	p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id;

	if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) == NULL)
		return (NDR_DRC_FAULT_REQUEST_PCONT_INVALID);

	mxa->binding = mbind;
	msvc = mbind->service;

	/*
	 * Make room for the response hdr.
	 */
	mxa->send_nds.pdu_scan_offset = NDR_RSP_HDR_SIZE;

	if (msvc->call_stub)
		rc = (*msvc->call_stub)(mxa);
	else
		rc = ndr_generic_call_stub(mxa);

	if (NDR_DRC_IS_FAULT(rc)) {
		ndo_printf(0, 0, "%s[0x%02x]: 0x%04x",
		    msvc->name, mxa->opnum, rc);
	}

	return (rc);
}
Esempio n. 2
0
/*
 * This is the entry point for all server-side RPC processing.
 * It is assumed that the PDU has already been received.
 */
static int
ndr_svc_process(ndr_xa_t *mxa)
{
	int			rc;

	(void) ndr_reply_prepare_hdr(mxa);

	switch (mxa->ptype) {
	case NDR_PTYPE_BIND:
		rc = ndr_svc_bind(mxa);
		break;

	case NDR_PTYPE_REQUEST:
		rc = ndr_svc_request(mxa);
		break;

	case NDR_PTYPE_ALTER_CONTEXT:
		rc = ndr_svc_alter_context(mxa);
		break;

	default:
		rc = NDR_DRC_FAULT_RPCHDR_PTYPE_INVALID;
		break;
	}

	if (NDR_DRC_IS_FAULT(rc))
		ndr_reply_fault(mxa, rc);

	return (rc);
}
Esempio n. 3
0
/*
 * Call the RPC function identified by opnum.  The remote service is
 * identified by the handle, which should have been initialized by
 * ndr_rpc_bind.
 *
 * If the RPC call is successful (returns 0), the caller must call
 * ndr_rpc_release to release the heap.  Otherwise, we release the
 * heap here.
 */
int
ndr_rpc_call(mlsvc_handle_t *handle, int opnum, void *params)
{
	ndr_client_t *clnt = handle->clnt;
	int rc;

	if (ndr_rpc_get_heap(handle) == NULL)
		return (-1);

	rc = ndr_clnt_call(clnt->binding, opnum, params);

	/*
	 * Always clear the nonull flag to ensure
	 * it is not applied to subsequent calls.
	 */
	clnt->nonull = B_FALSE;

	if (NDR_DRC_IS_FAULT(rc)) {
		ndr_rpc_release(handle);
		return (-1);
	}

	return (0);
}
Esempio n. 4
0
/*
 * This call must be made to initialize an RPC client structure and bind
 * to the remote service before any RPCs can be exchanged with that service.
 *
 * The mlsvc_handle_t is a wrapper that is used to associate an RPC handle
 * with the client context for an instance of the interface.  The handle
 * is zeroed to ensure that it doesn't look like a valid handle -
 * handle content is provided by the remove service.
 *
 * The client points to this top-level handle so that we know when to
 * unbind and teardown the connection.  As each handle is initialized it
 * will inherit a reference to the client context.
 *
 * Returns 0 or an NT_STATUS:
 *	NT_STATUS_BAD_NETWORK_PATH	(get server addr)
 *	NT_STATUS_NETWORK_ACCESS_DENIED	(connect, auth)
 *	NT_STATUS_BAD_NETWORK_NAME	(tcon, open)
 *	NT_STATUS_ACCESS_DENIED		(open pipe)
 *	NT_STATUS_INVALID_PARAMETER	(rpc bind)
 *
 *	NT_STATUS_INTERNAL_ERROR	(bad args etc)
 *	NT_STATUS_NO_MEMORY
 */
DWORD
ndr_rpc_bind(mlsvc_handle_t *handle, char *server, char *domain,
    char *username, const char *service)
{
	struct smb_ctx		*ctx = NULL;
	ndr_client_t		*clnt = NULL;
	ndr_service_t		*svc;
	srvsvc_server_info_t	svinfo;
	DWORD			status;
	int			fd = -1;
	int			rc;

	if (handle == NULL || server == NULL || server[0] == '\0' ||
	    domain == NULL || username == NULL)
		return (NT_STATUS_INTERNAL_ERROR);

	/* In case the service was not registered... */
	if ((svc = ndr_svc_lookup_name(service)) == NULL)
		return (NT_STATUS_INTERNAL_ERROR);

	/*
	 * Set the default based on the assumption that most
	 * servers will be Windows 2000 or later.  This used to
	 * try to get the actual server version, but that RPC
	 * is not necessarily allowed anymore, so don't bother.
	 */
	bzero(&svinfo, sizeof (srvsvc_server_info_t));
	svinfo.sv_platform_id = SV_PLATFORM_ID_NT;
	svinfo.sv_version_major = 5;
	svinfo.sv_version_minor = 0;
	svinfo.sv_type = SV_TYPE_DEFAULT;
	svinfo.sv_os = NATIVE_OS_WIN2000;

	/*
	 * Some callers pass this when they want a NULL session.
	 * Todo: have callers pass an empty string for that.
	 */
	if (strcmp(username, MLSVC_ANON_USER) == 0)
		username = "";

	/*
	 * Setup smbfs library handle, authenticate, connect to
	 * the IPC$ share.  This will reuse an existing connection
	 * if the driver already has one for this combination of
	 * server, user, domain.  It may return any of:
	 *	NT_STATUS_BAD_NETWORK_PATH	(get server addr)
	 *	NT_STATUS_NETWORK_ACCESS_DENIED	(connect, auth)
	 *	NT_STATUS_BAD_NETWORK_NAME	(tcon)
	 */
	status = smbrdr_ctx_new(&ctx, server, domain, username);
	if (status != NT_STATUS_SUCCESS) {
		syslog(LOG_ERR, "ndr_rpc_bind: smbrdr_ctx_new"
		    "(Srv=%s Dom=%s User=%s), %s (0x%x)",
		    server, domain, username,
		    xlate_nt_status(status), status);
		/* Tell the DC Locator this DC failed. */
		smb_ddiscover_bad_dc(server);
		goto errout;
	}

	/*
	 * Open the named pipe.
	 */
	fd = smb_fh_open(ctx, svc->endpoint, O_RDWR);
	if (fd < 0) {
		rc = errno;
		syslog(LOG_DEBUG, "ndr_rpc_bind: "
		    "smb_fh_open (%s) err=%d",
		    svc->endpoint, rc);
		switch (rc) {
		case EACCES:
			status = NT_STATUS_ACCESS_DENIED;
			break;
		default:
			status = NT_STATUS_BAD_NETWORK_NAME;
			break;
		}
		goto errout;
	}

	/*
	 * Setup the RPC client handle.
	 */
	if ((clnt = malloc(sizeof (ndr_client_t))) == NULL) {
		status = NT_STATUS_NO_MEMORY;
		goto errout;
	}
	bzero(clnt, sizeof (ndr_client_t));

	clnt->handle = &handle->handle;
	clnt->xa_init = ndr_xa_init;
	clnt->xa_exchange = ndr_xa_exchange;
	clnt->xa_read = ndr_xa_read;
	clnt->xa_preserve = ndr_xa_preserve;
	clnt->xa_destruct = ndr_xa_destruct;
	clnt->xa_release = ndr_xa_release;
	clnt->xa_private = ctx;
	clnt->xa_fd = fd;

	ndr_svc_binding_pool_init(&clnt->binding_list,
	    clnt->binding_pool, NDR_N_BINDING_POOL);

	if ((clnt->heap = ndr_heap_create()) == NULL) {
		status = NT_STATUS_NO_MEMORY;
		goto errout;
	}

	/*
	 * Fill in the caller's handle.
	 */
	bzero(&handle->handle, sizeof (ndr_hdid_t));
	handle->clnt = clnt;
	bcopy(&svinfo, &handle->svinfo, sizeof (srvsvc_server_info_t));

	/*
	 * Do the OtW RPC bind.
	 */
	rc = ndr_clnt_bind(clnt, service, &clnt->binding);
	switch (rc) {
	case NDR_DRC_FAULT_OUT_OF_MEMORY:
		status = NT_STATUS_NO_MEMORY;
		break;
	case NDR_DRC_FAULT_API_SERVICE_INVALID:	/* not registered */
		status = NT_STATUS_INTERNAL_ERROR;
		break;
	default:
		if (NDR_DRC_IS_FAULT(rc)) {
			status = NT_STATUS_INVALID_PARAMETER;
			break;
		}
		/* FALLTHROUGH */
	case NDR_DRC_OK:
		return (NT_STATUS_SUCCESS);
	}

	syslog(LOG_DEBUG, "ndr_rpc_bind: "
	    "ndr_clnt_bind, %s (0x%x)",
	    xlate_nt_status(status), status);

errout:
	handle->clnt = NULL;
	if (clnt != NULL) {
		ndr_heap_destroy(clnt->heap);
		free(clnt);
	}
	if (ctx != NULL) {
		if (fd != -1)
			(void) smb_fh_close(fd);
		smbrdr_ctx_free(ctx);
	}

	return (status);
}
Esempio n. 5
0
/*
 * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple
 * p_results[] not supported.
 */
static int
ndr_svc_bind(ndr_xa_t *mxa)
{
	ndr_p_cont_list_t	*cont_list;
	ndr_p_result_list_t	*result_list;
	ndr_p_result_t		*result;
	unsigned		p_cont_id;
	ndr_binding_t		*mbind;
	ndr_uuid_t		*as_uuid;
	ndr_uuid_t		*ts_uuid;
	int			as_vers;
	int			ts_vers;
	ndr_service_t		*msvc;
	int			rc;
	ndr_port_any_t		*sec_addr;

	/* acquire targets */
	cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem;
	result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list;
	result = &result_list->p_results[0];

	/*
	 * Set up temporary secondary address port.
	 * We will correct this later (below).
	 */
	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
	sec_addr->length = 13;
	(void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs");

	result_list->n_results = 1;
	result_list->reserved = 0;
	result_list->reserved2 = 0;
	result->result = NDR_PCDR_ACCEPTANCE;
	result->reason = 0;
	bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));

	/* sanity check */
	if (cont_list->n_context_elem != 1 ||
	    cont_list->p_cont_elem[0].n_transfer_syn != 1) {
		ndo_trace("ndr_svc_bind: warning: multiple p_cont_elem");
	}

	p_cont_id = cont_list->p_cont_elem[0].p_cont_id;

	if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) != NULL) {
		/*
		 * Duplicate presentation context id.
		 */
		ndo_trace("ndr_svc_bind: duplicate binding");
		return (NDR_DRC_FAULT_BIND_PCONT_BUSY);
	}

	if ((mbind = ndr_svc_new_binding(mxa)) == NULL) {
		/*
		 * No free binding slot
		 */
		result->result = NDR_PCDR_PROVIDER_REJECTION;
		result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED;
		ndo_trace("ndr_svc_bind: no resources");
		return (NDR_DRC_OK);
	}

	as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
	as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;

	ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
	ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;

	msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers);
	if (msvc == NULL) {
		result->result = NDR_PCDR_PROVIDER_REJECTION;
		result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
		return (NDR_DRC_OK);
	}

	/*
	 * We can now use the correct secondary address port.
	 */
	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
	sec_addr->length = strlen(msvc->sec_addr_port) + 1;
	(void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port,
	    NDR_PORT_ANY_MAX_PORT_SPEC);

	mbind->p_cont_id = p_cont_id;
	mbind->which_side = NDR_BIND_SIDE_SERVER;
	/* mbind->context set by app */
	mbind->service = msvc;
	mbind->instance_specific = 0;

	mxa->binding = mbind;

	if (msvc->bind_req) {
		/*
		 * Call the service-specific bind() handler.  If
		 * this fails, we shouild send a specific error
		 * on the bind ack.
		 */
		rc = (msvc->bind_req)(mxa);
		if (NDR_DRC_IS_FAULT(rc)) {
			mbind->service = 0;	/* free binding slot */
			mbind->which_side = 0;
			mbind->p_cont_id = 0;
			mbind->instance_specific = 0;
			return (rc);
		}
	}

	result->transfer_syntax =
	    cont_list->p_cont_elem[0].transfer_syntaxes[0];

	return (NDR_DRC_BINDING_MADE);
}