13299f39fSGordon Ross /*
23299f39fSGordon Ross * CDDL HEADER START
33299f39fSGordon Ross *
43299f39fSGordon Ross * The contents of this file are subject to the terms of the
53299f39fSGordon Ross * Common Development and Distribution License (the "License").
63299f39fSGordon Ross * You may not use this file except in compliance with the License.
73299f39fSGordon Ross *
83299f39fSGordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93299f39fSGordon Ross * or http://www.opensolaris.org/os/licensing.
103299f39fSGordon Ross * See the License for the specific language governing permissions
113299f39fSGordon Ross * and limitations under the License.
123299f39fSGordon Ross *
133299f39fSGordon Ross * When distributing Covered Code, include this CDDL HEADER in each
143299f39fSGordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153299f39fSGordon Ross * If applicable, add the following below this CDDL HEADER, with the
163299f39fSGordon Ross * fields enclosed by brackets "[]" replaced with your own identifying
173299f39fSGordon Ross * information: Portions Copyright [yyyy] [name of copyright owner]
183299f39fSGordon Ross *
193299f39fSGordon Ross * CDDL HEADER END
203299f39fSGordon Ross */
213299f39fSGordon Ross
223299f39fSGordon Ross /*
233299f39fSGordon Ross * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
243299f39fSGordon Ross * Use is subject to license terms.
253299f39fSGordon Ross *
26*ce8560eeSMatt Barden * Copyright 2020 Tintri by DDN, Inc. All rights reserved.
273299f39fSGordon Ross */
283299f39fSGordon Ross
293299f39fSGordon Ross /*
303299f39fSGordon Ross * ML-RPC Client handle interface and support functions.
313299f39fSGordon Ross */
323299f39fSGordon Ross
333299f39fSGordon Ross #include <sys/types.h>
343299f39fSGordon Ross #include <sys/fcntl.h>
353299f39fSGordon Ross #include <sys/poll.h>
363299f39fSGordon Ross
373299f39fSGordon Ross #include <errno.h>
383299f39fSGordon Ross #include <strings.h>
393299f39fSGordon Ross #include <unistd.h>
403299f39fSGordon Ross
413299f39fSGordon Ross #include <netsmb/smbfs_api.h>
423299f39fSGordon Ross #include <smb/ntstatus.h>
433299f39fSGordon Ross #include <libmlrpc.h>
443299f39fSGordon Ross
453299f39fSGordon Ross #include <assert.h>
463299f39fSGordon Ross
473299f39fSGordon Ross static int ndr_xa_init(ndr_client_t *, ndr_xa_t *);
483299f39fSGordon Ross static int ndr_xa_exchange(ndr_client_t *, ndr_xa_t *);
493299f39fSGordon Ross static int ndr_xa_read(ndr_client_t *, ndr_xa_t *);
503299f39fSGordon Ross static void ndr_xa_preserve(ndr_client_t *, ndr_xa_t *);
513299f39fSGordon Ross static void ndr_xa_destruct(ndr_client_t *, ndr_xa_t *);
523299f39fSGordon Ross static void ndr_xa_release(ndr_client_t *);
533299f39fSGordon Ross
543299f39fSGordon Ross /* See notes in mlrpc_clh_bind */
553299f39fSGordon Ross int rpc_pipe_open_retries = 10;
563299f39fSGordon Ross
573299f39fSGordon Ross /*
583299f39fSGordon Ross * Create an RPC client binding handle using the given smb_ctx.
593299f39fSGordon Ross * That context must already have a session and tree connected.
603299f39fSGordon Ross *
613299f39fSGordon Ross * Returns zero or an errno value.
623299f39fSGordon Ross */
633299f39fSGordon Ross int
mlrpc_clh_create(mlrpc_handle_t * handle,void * ctx)643299f39fSGordon Ross mlrpc_clh_create(mlrpc_handle_t *handle, void *ctx)
653299f39fSGordon Ross {
663299f39fSGordon Ross ndr_client_t *clnt = NULL;
673299f39fSGordon Ross
683299f39fSGordon Ross if (ctx == NULL)
693299f39fSGordon Ross return (EINVAL);
703299f39fSGordon Ross
713299f39fSGordon Ross /*
723299f39fSGordon Ross * Allocate...
733299f39fSGordon Ross */
74*ce8560eeSMatt Barden if ((clnt = calloc(1, sizeof (*clnt))) == NULL)
753299f39fSGordon Ross return (ENOMEM);
763299f39fSGordon Ross
773299f39fSGordon Ross clnt->xa_fd = -1;
783299f39fSGordon Ross
793299f39fSGordon Ross /*
803299f39fSGordon Ross * Setup the transport functions.
813299f39fSGordon Ross * Always a named pipe (for now).
823299f39fSGordon Ross */
833299f39fSGordon Ross clnt->xa_private = ctx;
843299f39fSGordon Ross clnt->xa_init = ndr_xa_init;
853299f39fSGordon Ross clnt->xa_exchange = ndr_xa_exchange;
863299f39fSGordon Ross clnt->xa_read = ndr_xa_read;
873299f39fSGordon Ross clnt->xa_preserve = ndr_xa_preserve;
883299f39fSGordon Ross clnt->xa_destruct = ndr_xa_destruct;
893299f39fSGordon Ross clnt->xa_release = ndr_xa_release;
903299f39fSGordon Ross
913299f39fSGordon Ross /* See _is_bind_handle */
923299f39fSGordon Ross clnt->handle = &handle->handle;
933299f39fSGordon Ross
943299f39fSGordon Ross ndr_svc_binding_pool_init(&clnt->binding_list,
953299f39fSGordon Ross clnt->binding_pool, NDR_N_BINDING_POOL);
963299f39fSGordon Ross
973299f39fSGordon Ross if ((clnt->heap = ndr_heap_create()) == NULL)
983299f39fSGordon Ross goto nomem;
993299f39fSGordon Ross
1003299f39fSGordon Ross /* success! */
1013299f39fSGordon Ross bzero(handle, sizeof (*handle));
1023299f39fSGordon Ross handle->clnt = clnt;
1033299f39fSGordon Ross return (0);
1043299f39fSGordon Ross
1053299f39fSGordon Ross nomem:
1063299f39fSGordon Ross free(clnt);
1073299f39fSGordon Ross return (ENOMEM);
1083299f39fSGordon Ross }
1093299f39fSGordon Ross
110*ce8560eeSMatt Barden /*
111*ce8560eeSMatt Barden * Set up this handle to perform RPC-level authentication.
112*ce8560eeSMatt Barden */
113*ce8560eeSMatt Barden uint32_t
mlrpc_clh_set_auth(mlrpc_handle_t * handle,ndr_auth_ctx_t * auth_ctx)114*ce8560eeSMatt Barden mlrpc_clh_set_auth(mlrpc_handle_t *handle, ndr_auth_ctx_t *auth_ctx)
115*ce8560eeSMatt Barden {
116*ce8560eeSMatt Barden ndr_client_t *clnt = NULL;
117*ce8560eeSMatt Barden
118*ce8560eeSMatt Barden if ((clnt = handle->clnt) == NULL)
119*ce8560eeSMatt Barden return (NT_STATUS_INTERNAL_ERROR);
120*ce8560eeSMatt Barden
121*ce8560eeSMatt Barden if (auth_ctx != NULL) {
122*ce8560eeSMatt Barden /* struct copy */
123*ce8560eeSMatt Barden clnt->auth_ctx = *auth_ctx;
124*ce8560eeSMatt Barden }
125*ce8560eeSMatt Barden
126*ce8560eeSMatt Barden return (NT_STATUS_SUCCESS);
127*ce8560eeSMatt Barden }
1283299f39fSGordon Ross
1293299f39fSGordon Ross /*
1303299f39fSGordon Ross * This call must be made to initialize an RPC client structure and bind
1313299f39fSGordon Ross * to the remote service before any RPCs can be exchanged with that service.
1323299f39fSGordon Ross *
1333299f39fSGordon Ross * The mlrpc_handle_t is a wrapper that is used to associate an RPC handle
1343299f39fSGordon Ross * with the client context for an instance of the interface. The handle
1353299f39fSGordon Ross * is zeroed to ensure that it doesn't look like a valid handle -
1363299f39fSGordon Ross * handle content is provided by the remove service.
1373299f39fSGordon Ross *
1383299f39fSGordon Ross * The client points to this top-level handle so that we know when to
1393299f39fSGordon Ross * unbind and teardown the connection. As each handle is initialized it
1403299f39fSGordon Ross * will inherit a reference to the client context.
1413299f39fSGordon Ross *
1423299f39fSGordon Ross *
1433299f39fSGordon Ross * Similar to MSRPC RpcBindingBind()
1443299f39fSGordon Ross *
1453299f39fSGordon Ross * Returns 0 or an NT_STATUS: (failed in...)
1463299f39fSGordon Ross *
1473299f39fSGordon Ross * RPC_NT_SERVER_TOO_BUSY (open pipe)
1483299f39fSGordon Ross * RPC_NT_SERVER_UNAVAILABLE (open pipe)
1493299f39fSGordon Ross * NT_STATUS_ACCESS_DENIED (open pipe)
1503299f39fSGordon Ross * NT_STATUS_INVALID_PARAMETER (rpc bind)
1513299f39fSGordon Ross * NT_STATUS_INTERNAL_ERROR (bad args etc)
1523299f39fSGordon Ross * NT_STATUS_NO_MEMORY
1533299f39fSGordon Ross */
1543299f39fSGordon Ross uint32_t
mlrpc_clh_bind(mlrpc_handle_t * handle,ndr_service_t * svc)1553299f39fSGordon Ross mlrpc_clh_bind(mlrpc_handle_t *handle, ndr_service_t *svc)
1563299f39fSGordon Ross {
1573299f39fSGordon Ross ndr_client_t *clnt = NULL;
1583299f39fSGordon Ross struct smb_ctx *ctx = NULL;
1593299f39fSGordon Ross uint32_t status = 0;
1603299f39fSGordon Ross int fd = -1;
1613299f39fSGordon Ross int rc, retries;
1623299f39fSGordon Ross
1633299f39fSGordon Ross if ((clnt = handle->clnt) == NULL)
1643299f39fSGordon Ross return (NT_STATUS_INTERNAL_ERROR);
1653299f39fSGordon Ross if ((ctx = clnt->xa_private) == NULL)
1663299f39fSGordon Ross return (NT_STATUS_INTERNAL_ERROR);
1673299f39fSGordon Ross if (clnt->xa_fd != -1)
1683299f39fSGordon Ross return (NT_STATUS_INTERNAL_ERROR);
1693299f39fSGordon Ross
1703299f39fSGordon Ross /*
1713299f39fSGordon Ross * Open the named pipe.
1723299f39fSGordon Ross *
1733299f39fSGordon Ross * Sometimes a DC may return NT_STATUS_PIPE_NOT_AVAILABLE for
1743299f39fSGordon Ross * the first few seconds during service auto-start. The client
1753299f39fSGordon Ross * translates that to EBUSY, so when we see that, wait a bit
1763299f39fSGordon Ross * and retry the open for up to rpc_pipe_open_retries. If we
1773299f39fSGordon Ross * fail even after retries, return RPC_NT_SERVER_TOO_BUSY,
1783299f39fSGordon Ross * which is how callers of this layer expect that reported.
1793299f39fSGordon Ross * We try up to 10 times, with a 0.5 sec. wait after each
1803299f39fSGordon Ross * BUSY failure, giving a total wait here of 5 sec.
1813299f39fSGordon Ross */
1823299f39fSGordon Ross retries = rpc_pipe_open_retries;
1833299f39fSGordon Ross retry_open:
1843299f39fSGordon Ross fd = smb_fh_open(ctx, svc->endpoint, O_RDWR);
1853299f39fSGordon Ross if (fd < 0) {
1863299f39fSGordon Ross rc = errno;
1873299f39fSGordon Ross switch (rc) {
1883299f39fSGordon Ross case EBUSY:
1893299f39fSGordon Ross if (--retries > 0) {
1903299f39fSGordon Ross (void) poll(NULL, 0, 500);
1913299f39fSGordon Ross goto retry_open;
1923299f39fSGordon Ross }
1933299f39fSGordon Ross status = RPC_NT_SERVER_TOO_BUSY;
1943299f39fSGordon Ross break;
1953299f39fSGordon Ross case EACCES:
1963299f39fSGordon Ross status = NT_STATUS_ACCESS_DENIED;
1973299f39fSGordon Ross break;
1983299f39fSGordon Ross default:
1993299f39fSGordon Ross status = RPC_NT_SERVER_UNAVAILABLE;
2003299f39fSGordon Ross break;
2013299f39fSGordon Ross }
2023299f39fSGordon Ross return (status);
2033299f39fSGordon Ross }
2043299f39fSGordon Ross
2053299f39fSGordon Ross clnt->xa_fd = fd;
2063299f39fSGordon Ross
2073299f39fSGordon Ross /* Paranoia, in case of re-bind. */
2083299f39fSGordon Ross bzero(&handle->handle, sizeof (ndr_hdid_t));
2093299f39fSGordon Ross
2103299f39fSGordon Ross /*
2113299f39fSGordon Ross * Do the OtW RPC bind.
2123299f39fSGordon Ross */
2133299f39fSGordon Ross rc = ndr_clnt_bind(clnt, svc, &clnt->binding);
2143299f39fSGordon Ross switch (rc) {
2153299f39fSGordon Ross case NDR_DRC_FAULT_OUT_OF_MEMORY:
2163299f39fSGordon Ross status = NT_STATUS_NO_MEMORY;
2173299f39fSGordon Ross break;
2183299f39fSGordon Ross case NDR_DRC_FAULT_API_SERVICE_INVALID:
2193299f39fSGordon Ross /* svc->..._uuid parse errors */
2203299f39fSGordon Ross status = NT_STATUS_INTERNAL_ERROR;
2213299f39fSGordon Ross break;
2223299f39fSGordon Ross default:
2233299f39fSGordon Ross if (NDR_DRC_IS_FAULT(rc)) {
2243299f39fSGordon Ross status = RPC_NT_PROTOCOL_ERROR;
2253299f39fSGordon Ross break;
2263299f39fSGordon Ross }
2273299f39fSGordon Ross /* FALLTHROUGH */
2283299f39fSGordon Ross case NDR_DRC_OK:
2293299f39fSGordon Ross status = NT_STATUS_SUCCESS;
2303299f39fSGordon Ross }
2313299f39fSGordon Ross
2323299f39fSGordon Ross if (status != 0) {
2333299f39fSGordon Ross if (fd != -1)
2343299f39fSGordon Ross (void) smb_fh_close(fd);
2353299f39fSGordon Ross clnt->xa_fd = -1;
2363299f39fSGordon Ross }
2373299f39fSGordon Ross
2383299f39fSGordon Ross return (status);
2393299f39fSGordon Ross }
2403299f39fSGordon Ross
2413299f39fSGordon Ross /*
2423299f39fSGordon Ross * Unbind and close the pipe to an RPC service.
2433299f39fSGordon Ross *
2443299f39fSGordon Ross * Similar to MSRPC RpcBindingUnbind()
2453299f39fSGordon Ross * This should be called after a dropped connection.
2463299f39fSGordon Ross */
2473299f39fSGordon Ross void
mlrpc_clh_unbind(mlrpc_handle_t * handle)2483299f39fSGordon Ross mlrpc_clh_unbind(mlrpc_handle_t *handle)
2493299f39fSGordon Ross {
2503299f39fSGordon Ross ndr_client_t *clnt = handle->clnt;
2513299f39fSGordon Ross
2523299f39fSGordon Ross if (clnt->xa_fd != -1) {
2533299f39fSGordon Ross (void) smb_fh_close(clnt->xa_fd);
2543299f39fSGordon Ross clnt->xa_fd = -1;
2553299f39fSGordon Ross }
2563299f39fSGordon Ross }
2573299f39fSGordon Ross
2583299f39fSGordon Ross /*
2593299f39fSGordon Ross * If the heap has been preserved we need to go through an xa release.
2603299f39fSGordon Ross * The heap is preserved during an RPC call because that's where data
2613299f39fSGordon Ross * returned from the server is stored.
2623299f39fSGordon Ross *
2633299f39fSGordon Ross * Otherwise we destroy the heap directly.
2643299f39fSGordon Ross *
2653299f39fSGordon Ross * Returns the xa_private pointer (if non-NULL) to inform the caller
2663299f39fSGordon Ross * that it can now be destroyed.
2673299f39fSGordon Ross */
2683299f39fSGordon Ross void *
mlrpc_clh_free(mlrpc_handle_t * handle)2693299f39fSGordon Ross mlrpc_clh_free(mlrpc_handle_t *handle)
2703299f39fSGordon Ross {
2713299f39fSGordon Ross ndr_client_t *clnt = handle->clnt;
2723299f39fSGordon Ross void *private;
2733299f39fSGordon Ross
2743299f39fSGordon Ross if (clnt == NULL)
2753299f39fSGordon Ross return (NULL);
2763299f39fSGordon Ross
2773299f39fSGordon Ross /*
2783299f39fSGordon Ross * Should never get an unbind on inherited handles.
2793299f39fSGordon Ross * Callers of ndr_inherit_handle() check handles
2803299f39fSGordon Ross * with ndr_is_bind_handle() before calling this.
2813299f39fSGordon Ross *
2823299f39fSGordon Ross * Maybe make this function more tolerant?
2833299f39fSGordon Ross */
2843299f39fSGordon Ross assert(handle->clnt->handle == &handle->handle);
2853299f39fSGordon Ross
2863299f39fSGordon Ross mlrpc_clh_unbind(handle);
2873299f39fSGordon Ross
2883299f39fSGordon Ross if (clnt->heap_preserved)
2893299f39fSGordon Ross ndr_clnt_free_heap(clnt); /* xa_release */
2903299f39fSGordon Ross else
2913299f39fSGordon Ross ndr_heap_destroy(clnt->heap);
2923299f39fSGordon Ross
2933299f39fSGordon Ross /*
2943299f39fSGordon Ross * Note: Caller will free the smb_ctx stored in
2953299f39fSGordon Ross * clnt->xa_private (or possibly reuse it).
2963299f39fSGordon Ross */
2973299f39fSGordon Ross private = clnt->xa_private;
2983299f39fSGordon Ross free(clnt);
2993299f39fSGordon Ross bzero(handle, sizeof (*handle));
3003299f39fSGordon Ross return (private);
3013299f39fSGordon Ross }
3023299f39fSGordon Ross
3033299f39fSGordon Ross /*
3043299f39fSGordon Ross * Call the RPC function identified by opnum. The remote service is
3053299f39fSGordon Ross * identified by the handle, which should have been initialized by
3063299f39fSGordon Ross * ndr_rpc_bind.
3073299f39fSGordon Ross *
3083299f39fSGordon Ross * If the RPC call is successful (returns 0), the caller must call
3093299f39fSGordon Ross * ndr_rpc_release to release the heap. Otherwise, we release the
3103299f39fSGordon Ross * heap here.
3113299f39fSGordon Ross */
3123299f39fSGordon Ross int
ndr_rpc_call(mlrpc_handle_t * handle,int opnum,void * params)3133299f39fSGordon Ross ndr_rpc_call(mlrpc_handle_t *handle, int opnum, void *params)
3143299f39fSGordon Ross {
3153299f39fSGordon Ross ndr_client_t *clnt = handle->clnt;
3163299f39fSGordon Ross int rc;
3173299f39fSGordon Ross
3183299f39fSGordon Ross if (ndr_rpc_get_heap(handle) == NULL)
3193299f39fSGordon Ross return (-1);
3203299f39fSGordon Ross
3213299f39fSGordon Ross rc = ndr_clnt_call(clnt->binding, opnum, params);
3223299f39fSGordon Ross
3233299f39fSGordon Ross /*
3243299f39fSGordon Ross * Always clear the nonull flag to ensure
3253299f39fSGordon Ross * it is not applied to subsequent calls.
3263299f39fSGordon Ross */
3273299f39fSGordon Ross clnt->nonull = B_FALSE;
3283299f39fSGordon Ross
3293299f39fSGordon Ross if (NDR_DRC_IS_FAULT(rc)) {
3303299f39fSGordon Ross ndr_rpc_release(handle);
3313299f39fSGordon Ross return (-1);
3323299f39fSGordon Ross }
3333299f39fSGordon Ross
3343299f39fSGordon Ross return (0);
3353299f39fSGordon Ross }
3363299f39fSGordon Ross
3373299f39fSGordon Ross /*
3383299f39fSGordon Ross * Outgoing strings should not be null terminated.
3393299f39fSGordon Ross */
3403299f39fSGordon Ross void
ndr_rpc_set_nonull(mlrpc_handle_t * handle)3413299f39fSGordon Ross ndr_rpc_set_nonull(mlrpc_handle_t *handle)
3423299f39fSGordon Ross {
3433299f39fSGordon Ross handle->clnt->nonull = B_TRUE;
3443299f39fSGordon Ross }
3453299f39fSGordon Ross
3463299f39fSGordon Ross /*
3473299f39fSGordon Ross * Get the session key from a bound RPC client handle.
3483299f39fSGordon Ross *
3493299f39fSGordon Ross * The key returned is the 16-byte "user session key"
3503299f39fSGordon Ross * established by the underlying authentication protocol
3513299f39fSGordon Ross * (either Kerberos or NTLM). This key is needed for
3523299f39fSGordon Ross * SAM RPC calls such as SamrSetInformationUser, etc.
3533299f39fSGordon Ross * See [MS-SAMR] sections: 2.2.3.3, 2.2.7.21, 2.2.7.25.
3543299f39fSGordon Ross *
3553299f39fSGordon Ross * Returns zero (success) or an errno.
3563299f39fSGordon Ross */
3573299f39fSGordon Ross int
ndr_rpc_get_ssnkey(mlrpc_handle_t * handle,uchar_t * key,size_t len)3583299f39fSGordon Ross ndr_rpc_get_ssnkey(mlrpc_handle_t *handle, uchar_t *key, size_t len)
3593299f39fSGordon Ross {
3603299f39fSGordon Ross ndr_client_t *clnt = handle->clnt;
3613299f39fSGordon Ross
3623299f39fSGordon Ross if (clnt == NULL || clnt->xa_fd == -1)
3633299f39fSGordon Ross return (EINVAL);
3643299f39fSGordon Ross
3653299f39fSGordon Ross return (smb_fh_getssnkey(clnt->xa_fd, key, len));
3663299f39fSGordon Ross }
3673299f39fSGordon Ross
3683299f39fSGordon Ross void *
ndr_rpc_malloc(mlrpc_handle_t * handle,size_t size)3693299f39fSGordon Ross ndr_rpc_malloc(mlrpc_handle_t *handle, size_t size)
3703299f39fSGordon Ross {
3713299f39fSGordon Ross ndr_heap_t *heap;
3723299f39fSGordon Ross
3733299f39fSGordon Ross if ((heap = ndr_rpc_get_heap(handle)) == NULL)
3743299f39fSGordon Ross return (NULL);
3753299f39fSGordon Ross
3763299f39fSGordon Ross return (ndr_heap_malloc(heap, size));
3773299f39fSGordon Ross }
3783299f39fSGordon Ross
3793299f39fSGordon Ross ndr_heap_t *
ndr_rpc_get_heap(mlrpc_handle_t * handle)3803299f39fSGordon Ross ndr_rpc_get_heap(mlrpc_handle_t *handle)
3813299f39fSGordon Ross {
3823299f39fSGordon Ross ndr_client_t *clnt = handle->clnt;
3833299f39fSGordon Ross
3843299f39fSGordon Ross if (clnt->heap == NULL)
3853299f39fSGordon Ross clnt->heap = ndr_heap_create();
3863299f39fSGordon Ross
3873299f39fSGordon Ross return (clnt->heap);
3883299f39fSGordon Ross }
3893299f39fSGordon Ross
3903299f39fSGordon Ross /*
3913299f39fSGordon Ross * Must be called by RPC clients to free the heap after a successful RPC
3923299f39fSGordon Ross * call, i.e. ndr_rpc_call returned 0. The caller should take a copy
3933299f39fSGordon Ross * of any data returned by the RPC prior to calling this function because
3943299f39fSGordon Ross * returned data is in the heap.
3953299f39fSGordon Ross */
3963299f39fSGordon Ross void
ndr_rpc_release(mlrpc_handle_t * handle)3973299f39fSGordon Ross ndr_rpc_release(mlrpc_handle_t *handle)
3983299f39fSGordon Ross {
3993299f39fSGordon Ross ndr_client_t *clnt = handle->clnt;
4003299f39fSGordon Ross
4013299f39fSGordon Ross if (clnt->heap_preserved)
4023299f39fSGordon Ross ndr_clnt_free_heap(clnt);
4033299f39fSGordon Ross else
4043299f39fSGordon Ross ndr_heap_destroy(clnt->heap);
4053299f39fSGordon Ross
4063299f39fSGordon Ross clnt->heap = NULL;
4073299f39fSGordon Ross }
4083299f39fSGordon Ross
4093299f39fSGordon Ross /*
4103299f39fSGordon Ross * Returns true if the handle is null.
4113299f39fSGordon Ross * Otherwise returns false.
4123299f39fSGordon Ross */
4133299f39fSGordon Ross boolean_t
ndr_is_null_handle(mlrpc_handle_t * handle)4143299f39fSGordon Ross ndr_is_null_handle(mlrpc_handle_t *handle)
4153299f39fSGordon Ross {
4163299f39fSGordon Ross static const ndr_hdid_t hdid0 = {0};
4173299f39fSGordon Ross
4183299f39fSGordon Ross if (handle == NULL || handle->clnt == NULL)
4193299f39fSGordon Ross return (B_TRUE);
4203299f39fSGordon Ross
4213299f39fSGordon Ross if (!memcmp(&handle->handle, &hdid0, sizeof (hdid0)))
4223299f39fSGordon Ross return (B_TRUE);
4233299f39fSGordon Ross
4243299f39fSGordon Ross return (B_FALSE);
4253299f39fSGordon Ross }
4263299f39fSGordon Ross
4273299f39fSGordon Ross /*
4283299f39fSGordon Ross * Returns true if the handle is the top level bind handle.
4293299f39fSGordon Ross * Otherwise returns false.
4303299f39fSGordon Ross */
4313299f39fSGordon Ross boolean_t
ndr_is_bind_handle(mlrpc_handle_t * handle)4323299f39fSGordon Ross ndr_is_bind_handle(mlrpc_handle_t *handle)
4333299f39fSGordon Ross {
4343299f39fSGordon Ross return (handle->clnt->handle == &handle->handle);
4353299f39fSGordon Ross }
4363299f39fSGordon Ross
4373299f39fSGordon Ross /*
4383299f39fSGordon Ross * Pass the client reference from parent to child.
4393299f39fSGordon Ross */
4403299f39fSGordon Ross void
ndr_inherit_handle(mlrpc_handle_t * child,mlrpc_handle_t * parent)4413299f39fSGordon Ross ndr_inherit_handle(mlrpc_handle_t *child, mlrpc_handle_t *parent)
4423299f39fSGordon Ross {
4433299f39fSGordon Ross child->clnt = parent->clnt;
4443299f39fSGordon Ross }
4453299f39fSGordon Ross
4463299f39fSGordon Ross /*
4473299f39fSGordon Ross * ndr_rpc_status remains in libmlsvc mlsvc_client.c
4483299f39fSGordon Ross */
4493299f39fSGordon Ross
4503299f39fSGordon Ross /*
4513299f39fSGordon Ross * The following functions provide the client callback interface.
4523299f39fSGordon Ross * If the caller hasn't provided a heap, create one here.
4533299f39fSGordon Ross */
4543299f39fSGordon Ross static int
ndr_xa_init(ndr_client_t * clnt,ndr_xa_t * mxa)4553299f39fSGordon Ross ndr_xa_init(ndr_client_t *clnt, ndr_xa_t *mxa)
4563299f39fSGordon Ross {
4573299f39fSGordon Ross ndr_stream_t *recv_nds = &mxa->recv_nds;
4583299f39fSGordon Ross ndr_stream_t *send_nds = &mxa->send_nds;
4593299f39fSGordon Ross ndr_heap_t *heap = clnt->heap;
4603299f39fSGordon Ross int rc;
4613299f39fSGordon Ross
4623299f39fSGordon Ross if (heap == NULL) {
4633299f39fSGordon Ross if ((heap = ndr_heap_create()) == NULL)
4643299f39fSGordon Ross return (-1);
4653299f39fSGordon Ross
4663299f39fSGordon Ross clnt->heap = heap;
4673299f39fSGordon Ross }
4683299f39fSGordon Ross
4693299f39fSGordon Ross mxa->heap = heap;
4703299f39fSGordon Ross
4713299f39fSGordon Ross rc = nds_initialize(send_nds, 0, NDR_MODE_CALL_SEND, heap);
4723299f39fSGordon Ross if (rc == 0)
4733299f39fSGordon Ross rc = nds_initialize(recv_nds, NDR_PDU_SIZE_HINT_DEFAULT,
4743299f39fSGordon Ross NDR_MODE_RETURN_RECV, heap);
4753299f39fSGordon Ross
4763299f39fSGordon Ross if (rc != 0) {
4773299f39fSGordon Ross nds_destruct(&mxa->recv_nds);
4783299f39fSGordon Ross nds_destruct(&mxa->send_nds);
4793299f39fSGordon Ross ndr_heap_destroy(mxa->heap);
4803299f39fSGordon Ross mxa->heap = NULL;
4813299f39fSGordon Ross clnt->heap = NULL;
4823299f39fSGordon Ross return (-1);
4833299f39fSGordon Ross }
4843299f39fSGordon Ross
4853299f39fSGordon Ross if (clnt->nonull)
4863299f39fSGordon Ross NDS_SETF(send_nds, NDS_F_NONULL);
4873299f39fSGordon Ross
4883299f39fSGordon Ross return (0);
4893299f39fSGordon Ross }
4903299f39fSGordon Ross
4913299f39fSGordon Ross /*
4923299f39fSGordon Ross * This is the entry pointy for an RPC client call exchange with
4933299f39fSGordon Ross * a server, which will result in an smbrdr SmbTransact request.
4943299f39fSGordon Ross *
4953299f39fSGordon Ross * SmbTransact should return the number of bytes received, which
4963299f39fSGordon Ross * we record as the PDU size, or a negative error code.
4973299f39fSGordon Ross */
4983299f39fSGordon Ross static int
ndr_xa_exchange(ndr_client_t * clnt,ndr_xa_t * mxa)4993299f39fSGordon Ross ndr_xa_exchange(ndr_client_t *clnt, ndr_xa_t *mxa)
5003299f39fSGordon Ross {
5013299f39fSGordon Ross ndr_stream_t *recv_nds = &mxa->recv_nds;
5023299f39fSGordon Ross ndr_stream_t *send_nds = &mxa->send_nds;
5033299f39fSGordon Ross int err, more, nbytes;
5043299f39fSGordon Ross
5053299f39fSGordon Ross nbytes = recv_nds->pdu_max_size;
5063299f39fSGordon Ross err = smb_fh_xactnp(clnt->xa_fd,
5073299f39fSGordon Ross send_nds->pdu_size, (char *)send_nds->pdu_base_offset,
5083299f39fSGordon Ross &nbytes, (char *)recv_nds->pdu_base_offset, &more);
5093299f39fSGordon Ross if (err) {
5103299f39fSGordon Ross recv_nds->pdu_size = 0;
5113299f39fSGordon Ross return (-1);
5123299f39fSGordon Ross }
5133299f39fSGordon Ross
5143299f39fSGordon Ross recv_nds->pdu_size = nbytes;
5153299f39fSGordon Ross return (0);
5163299f39fSGordon Ross }
5173299f39fSGordon Ross
5183299f39fSGordon Ross /*
5193299f39fSGordon Ross * This entry point will be invoked if the xa-exchange response contained
5203299f39fSGordon Ross * only the first fragment of a multi-fragment response. The RPC client
5213299f39fSGordon Ross * code will then make repeated xa-read requests to obtain the remaining
5223299f39fSGordon Ross * fragments, which will result in smbrdr SmbReadX requests.
5233299f39fSGordon Ross *
5243299f39fSGordon Ross * SmbReadX should return the number of bytes received, in which case we
5253299f39fSGordon Ross * expand the PDU size to include the received data, or a negative error
5263299f39fSGordon Ross * code.
5273299f39fSGordon Ross */
5283299f39fSGordon Ross static int
ndr_xa_read(ndr_client_t * clnt,ndr_xa_t * mxa)5293299f39fSGordon Ross ndr_xa_read(ndr_client_t *clnt, ndr_xa_t *mxa)
5303299f39fSGordon Ross {
5313299f39fSGordon Ross ndr_stream_t *nds = &mxa->recv_nds;
5323299f39fSGordon Ross int len;
5333299f39fSGordon Ross int nbytes;
5343299f39fSGordon Ross
5353299f39fSGordon Ross if ((len = (nds->pdu_max_size - nds->pdu_size)) < 0)
5363299f39fSGordon Ross return (-1);
5373299f39fSGordon Ross
5383299f39fSGordon Ross nbytes = smb_fh_read(clnt->xa_fd, 0, len,
5393299f39fSGordon Ross (char *)nds->pdu_base_offset + nds->pdu_size);
5403299f39fSGordon Ross
5413299f39fSGordon Ross if (nbytes < 0)
5423299f39fSGordon Ross return (-1);
5433299f39fSGordon Ross
5443299f39fSGordon Ross nds->pdu_size += nbytes;
5453299f39fSGordon Ross
5463299f39fSGordon Ross if (nds->pdu_size > nds->pdu_max_size) {
5473299f39fSGordon Ross nds->pdu_size = nds->pdu_max_size;
5483299f39fSGordon Ross return (-1);
5493299f39fSGordon Ross }
5503299f39fSGordon Ross
5513299f39fSGordon Ross return (nbytes);
5523299f39fSGordon Ross }
5533299f39fSGordon Ross
5543299f39fSGordon Ross /*
5553299f39fSGordon Ross * Preserve the heap so that the client application has access to data
5563299f39fSGordon Ross * returned from the server after an RPC call.
5573299f39fSGordon Ross */
5583299f39fSGordon Ross static void
ndr_xa_preserve(ndr_client_t * clnt,ndr_xa_t * mxa)5593299f39fSGordon Ross ndr_xa_preserve(ndr_client_t *clnt, ndr_xa_t *mxa)
5603299f39fSGordon Ross {
5613299f39fSGordon Ross assert(clnt->heap == mxa->heap);
5623299f39fSGordon Ross
5633299f39fSGordon Ross clnt->heap_preserved = B_TRUE;
5643299f39fSGordon Ross mxa->heap = NULL;
5653299f39fSGordon Ross }
5663299f39fSGordon Ross
5673299f39fSGordon Ross /*
5683299f39fSGordon Ross * Dispose of the transaction streams. If the heap has not been
5693299f39fSGordon Ross * preserved, we can destroy it here.
5703299f39fSGordon Ross */
5713299f39fSGordon Ross static void
ndr_xa_destruct(ndr_client_t * clnt,ndr_xa_t * mxa)5723299f39fSGordon Ross ndr_xa_destruct(ndr_client_t *clnt, ndr_xa_t *mxa)
5733299f39fSGordon Ross {
5743299f39fSGordon Ross nds_destruct(&mxa->recv_nds);
5753299f39fSGordon Ross nds_destruct(&mxa->send_nds);
5763299f39fSGordon Ross
5773299f39fSGordon Ross if (!clnt->heap_preserved) {
5783299f39fSGordon Ross ndr_heap_destroy(mxa->heap);
5793299f39fSGordon Ross mxa->heap = NULL;
5803299f39fSGordon Ross clnt->heap = NULL;
5813299f39fSGordon Ross }
5823299f39fSGordon Ross }
5833299f39fSGordon Ross
5843299f39fSGordon Ross /*
5853299f39fSGordon Ross * Dispose of a preserved heap.
5863299f39fSGordon Ross */
5873299f39fSGordon Ross static void
ndr_xa_release(ndr_client_t * clnt)5883299f39fSGordon Ross ndr_xa_release(ndr_client_t *clnt)
5893299f39fSGordon Ross {
5903299f39fSGordon Ross if (clnt->heap_preserved) {
5913299f39fSGordon Ross ndr_heap_destroy(clnt->heap);
5923299f39fSGordon Ross clnt->heap = NULL;
5933299f39fSGordon Ross clnt->heap_preserved = B_FALSE;
5943299f39fSGordon Ross }
5953299f39fSGordon Ross }
596