Beispiel #1
0
/*
 * Dispose of a preserved heap.
 */
static void
ndr_xa_release(ndr_client_t *clnt)
{
	if (clnt->heap_preserved) {
		ndr_heap_destroy(clnt->heap);
		clnt->heap = NULL;
		clnt->heap_preserved = B_FALSE;
	}
}
Beispiel #2
0
/*
 * Dispose of the transaction streams.  If the heap has not been
 * preserved, we can destroy it here.
 */
static void
ndr_xa_destruct(ndr_client_t *clnt, ndr_xa_t *mxa)
{
	nds_destruct(&mxa->recv_nds);
	nds_destruct(&mxa->send_nds);

	if (!clnt->heap_preserved) {
		ndr_heap_destroy(mxa->heap);
		mxa->heap = NULL;
		clnt->heap = NULL;
	}
}
Beispiel #3
0
/*
 * Must be called by RPC clients to free the heap after a successful RPC
 * call, i.e. ndr_rpc_call returned 0.  The caller should take a copy
 * of any data returned by the RPC prior to calling this function because
 * returned data is in the heap.
 */
void
ndr_rpc_release(mlsvc_handle_t *handle)
{
	ndr_client_t *clnt = handle->clnt;

	if (clnt->heap_preserved)
		ndr_clnt_free_heap(clnt);
	else
		ndr_heap_destroy(clnt->heap);

	clnt->heap = NULL;
}
Beispiel #4
0
/*
 * Unbind and close the pipe to an RPC service.
 *
 * If the heap has been preserved we need to go through an xa release.
 * The heap is preserved during an RPC call because that's where data
 * returned from the server is stored.
 *
 * Otherwise we destroy the heap directly.
 */
void
ndr_rpc_unbind(mlsvc_handle_t *handle)
{
	ndr_client_t *clnt = handle->clnt;
	struct smb_ctx *ctx = clnt->xa_private;

	if (clnt->heap_preserved)
		ndr_clnt_free_heap(clnt);
	else
		ndr_heap_destroy(clnt->heap);

	(void) smb_fh_close(clnt->xa_fd);
	smbrdr_ctx_free(ctx);
	free(clnt);
	bzero(handle, sizeof (mlsvc_handle_t));
}
Beispiel #5
0
/*
 * Process one server-side RPC request.
 */
static int
ndr_pipe_process(ndr_pipe_t *np, ndr_xa_t *mxa)
{
	ndr_stream_t	*recv_nds;
	ndr_stream_t	*send_nds;
	int		rc = ENOMEM;

	mxa->pipe = np;
	mxa->binding_list = np->np_binding;

	if ((mxa->heap = ndr_heap_create()) == NULL)
		goto out1;

	recv_nds = &mxa->recv_nds;
	rc = nds_initialize(recv_nds, 0, NDR_MODE_CALL_RECV, mxa->heap);
	if (rc != 0)
		goto out2;

	send_nds = &mxa->send_nds;
	rc = nds_initialize(send_nds, 0, NDR_MODE_RETURN_SEND, mxa->heap);
	if (rc != 0)
		goto out3;

	rc = ndr_recv_request(mxa);
	if (rc != 0)
		goto out4;

	(void) ndr_svc_process(mxa);
	(void) ndr_send_reply(mxa);
	rc = 0;

out4:
	nds_destruct(&mxa->send_nds);
out3:
	nds_destruct(&mxa->recv_nds);
out2:
	ndr_heap_destroy(mxa->heap);
out1:
	return (rc);
}
Beispiel #6
0
/*
 * The following functions provide the client callback interface.
 * If the caller hasn't provided a heap, create one here.
 */
static int
ndr_xa_init(ndr_client_t *clnt, ndr_xa_t *mxa)
{
	ndr_stream_t	*recv_nds = &mxa->recv_nds;
	ndr_stream_t	*send_nds = &mxa->send_nds;
	ndr_heap_t	*heap = clnt->heap;
	int		rc;

	if (heap == NULL) {
		if ((heap = ndr_heap_create()) == NULL)
			return (-1);

		clnt->heap = heap;
	}

	mxa->heap = heap;

	rc = nds_initialize(send_nds, 0, NDR_MODE_CALL_SEND, heap);
	if (rc == 0)
		rc = nds_initialize(recv_nds, NDR_PDU_SIZE_HINT_DEFAULT,
		    NDR_MODE_RETURN_RECV, heap);

	if (rc != 0) {
		nds_destruct(&mxa->recv_nds);
		nds_destruct(&mxa->send_nds);
		ndr_heap_destroy(mxa->heap);
		mxa->heap = NULL;
		clnt->heap = NULL;
		return (-1);
	}

	if (clnt->nonull)
		NDS_SETF(send_nds, NDS_F_NONULL);

	return (0);
}
Beispiel #7
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);
}