xref: /onnv-gate/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c (revision 8334:5f1c6a3b0fad)
15772Sas200622 /*
25772Sas200622  * CDDL HEADER START
35772Sas200622  *
45772Sas200622  * The contents of this file are subject to the terms of the
55772Sas200622  * Common Development and Distribution License (the "License").
65772Sas200622  * You may not use this file except in compliance with the License.
75772Sas200622  *
85772Sas200622  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95772Sas200622  * or http://www.opensolaris.org/os/licensing.
105772Sas200622  * See the License for the specific language governing permissions
115772Sas200622  * and limitations under the License.
125772Sas200622  *
135772Sas200622  * When distributing Covered Code, include this CDDL HEADER in each
145772Sas200622  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155772Sas200622  * If applicable, add the following below this CDDL HEADER, with the
165772Sas200622  * fields enclosed by brackets "[]" replaced with your own identifying
175772Sas200622  * information: Portions Copyright [yyyy] [name of copyright owner]
185772Sas200622  *
195772Sas200622  * CDDL HEADER END
205772Sas200622  */
215772Sas200622 /*
225772Sas200622  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
235772Sas200622  * Use is subject to license terms.
245772Sas200622  */
255772Sas200622 
265772Sas200622 /*
275772Sas200622  * Server side RPC handler.
285772Sas200622  */
295772Sas200622 
305772Sas200622 #include <sys/byteorder.h>
317052Samw #include <sys/errno.h>
327052Samw #include <sys/uio.h>
335772Sas200622 #include <thread.h>
345772Sas200622 #include <synch.h>
355772Sas200622 #include <stdlib.h>
365772Sas200622 #include <strings.h>
375772Sas200622 #include <string.h>
385772Sas200622 #include <time.h>
395772Sas200622 
405772Sas200622 #include <smbsrv/libsmb.h>
415772Sas200622 #include <smbsrv/libmlrpc.h>
425772Sas200622 
435772Sas200622 /*
445772Sas200622  * Fragment size (5680: NT style).
455772Sas200622  */
46*8334SJose.Borrego@Sun.COM #define	NDR_FRAG_SZ		5680
475772Sas200622 
48*8334SJose.Borrego@Sun.COM #define	NDR_PIPE_BUFSZ		65536
49*8334SJose.Borrego@Sun.COM #define	NDR_PIPE_MAX		128
50*8334SJose.Borrego@Sun.COM static ndr_pipe_t ndr_pipe_table[NDR_PIPE_MAX];
51*8334SJose.Borrego@Sun.COM static mutex_t ndr_pipe_lock;
525772Sas200622 
53*8334SJose.Borrego@Sun.COM static int ndr_pipe_transact(ndr_pipe_t *);
54*8334SJose.Borrego@Sun.COM static ndr_pipe_t *ndr_pipe_lookup(int);
55*8334SJose.Borrego@Sun.COM static void ndr_pipe_release(ndr_pipe_t *);
56*8334SJose.Borrego@Sun.COM static ndr_pipe_t *ndr_pipe_allocate(int);
57*8334SJose.Borrego@Sun.COM static void ndr_pipe_deallocate(ndr_pipe_t *);
58*8334SJose.Borrego@Sun.COM static void ndr_pipe_rewind(ndr_pipe_t *);
59*8334SJose.Borrego@Sun.COM static void ndr_pipe_flush(ndr_pipe_t *);
607052Samw 
61*8334SJose.Borrego@Sun.COM static int ndr_svc_process(ndr_xa_t *);
62*8334SJose.Borrego@Sun.COM static int ndr_svc_bind(ndr_xa_t *);
63*8334SJose.Borrego@Sun.COM static int ndr_svc_request(ndr_xa_t *);
64*8334SJose.Borrego@Sun.COM static void ndr_reply_prepare_hdr(ndr_xa_t *);
65*8334SJose.Borrego@Sun.COM static int ndr_svc_alter_context(ndr_xa_t *);
66*8334SJose.Borrego@Sun.COM static void ndr_reply_fault(ndr_xa_t *, unsigned long);
67*8334SJose.Borrego@Sun.COM static int ndr_build_reply(ndr_xa_t *);
68*8334SJose.Borrego@Sun.COM static void ndr_build_frag(ndr_stream_t *, uint8_t *, uint32_t);
695772Sas200622 
705772Sas200622 /*
717052Samw  * Allocate and associate a service context with a fid.
727052Samw  */
737052Samw int
74*8334SJose.Borrego@Sun.COM ndr_pipe_open(int fid, uint8_t *data, uint32_t datalen)
757052Samw {
76*8334SJose.Borrego@Sun.COM 	ndr_pipe_t *np;
777052Samw 
78*8334SJose.Borrego@Sun.COM 	(void) mutex_lock(&ndr_pipe_lock);
797052Samw 
80*8334SJose.Borrego@Sun.COM 	if ((np = ndr_pipe_lookup(fid)) != NULL) {
81*8334SJose.Borrego@Sun.COM 		ndr_pipe_release(np);
82*8334SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ndr_pipe_lock);
837052Samw 		return (EEXIST);
847052Samw 	}
857052Samw 
86*8334SJose.Borrego@Sun.COM 	if ((np = ndr_pipe_allocate(fid)) == NULL) {
87*8334SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ndr_pipe_lock);
887052Samw 		return (ENOMEM);
897052Samw 	}
907052Samw 
91*8334SJose.Borrego@Sun.COM 	if (smb_opipe_context_decode(&np->np_ctx, data, datalen) == -1) {
92*8334SJose.Borrego@Sun.COM 		ndr_pipe_release(np);
93*8334SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ndr_pipe_lock);
947052Samw 		return (EINVAL);
957052Samw 	}
967052Samw 
97*8334SJose.Borrego@Sun.COM 	ndr_svc_binding_pool_init(&np->np_binding, np->np_binding_pool,
98*8334SJose.Borrego@Sun.COM 	    NDR_N_BINDING_POOL);
997052Samw 
100*8334SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ndr_pipe_lock);
1017052Samw 	return (0);
1027052Samw }
1037052Samw 
1047052Samw /*
1057052Samw  * Release the context associated with a fid when an opipe is closed.
1067052Samw  */
1077052Samw int
108*8334SJose.Borrego@Sun.COM ndr_pipe_close(int fid)
1097052Samw {
110*8334SJose.Borrego@Sun.COM 	ndr_pipe_t *np;
1117052Samw 
112*8334SJose.Borrego@Sun.COM 	(void) mutex_lock(&ndr_pipe_lock);
1137052Samw 
114*8334SJose.Borrego@Sun.COM 	if ((np = ndr_pipe_lookup(fid)) == NULL) {
115*8334SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ndr_pipe_lock);
1167052Samw 		return (ENOENT);
1177052Samw 	}
1187052Samw 
1197052Samw 	/*
1207052Samw 	 * Release twice: once for the lookup above
1217052Samw 	 * and again to close the fid.
1227052Samw 	 */
123*8334SJose.Borrego@Sun.COM 	ndr_pipe_release(np);
124*8334SJose.Borrego@Sun.COM 	ndr_pipe_release(np);
125*8334SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ndr_pipe_lock);
1267052Samw 	return (0);
1277052Samw }
1287052Samw 
1297052Samw /*
1307052Samw  * Write RPC request data to the input stream.  Input data is buffered
1317052Samw  * until the response is requested.
1325772Sas200622  */
1337052Samw int
134*8334SJose.Borrego@Sun.COM ndr_pipe_write(int fid, uint8_t *buf, uint32_t len)
1357052Samw {
136*8334SJose.Borrego@Sun.COM 	ndr_pipe_t *np;
1377052Samw 	ssize_t nbytes;
1387052Samw 
1397052Samw 	if (len == 0)
1407052Samw 		return (0);
1417052Samw 
142*8334SJose.Borrego@Sun.COM 	(void) mutex_lock(&ndr_pipe_lock);
1437052Samw 
144*8334SJose.Borrego@Sun.COM 	if ((np = ndr_pipe_lookup(fid)) == NULL) {
145*8334SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ndr_pipe_lock);
1467052Samw 		return (ENOENT);
1477052Samw 	}
1487052Samw 
149*8334SJose.Borrego@Sun.COM 	nbytes = ndr_uiomove((caddr_t)buf, len, UIO_READ, &np->np_uio);
1507052Samw 
151*8334SJose.Borrego@Sun.COM 	ndr_pipe_release(np);
152*8334SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ndr_pipe_lock);
1537052Samw 	return ((nbytes == len) ? 0 : EIO);
1547052Samw }
1557052Samw 
1567052Samw /*
1577052Samw  * Read RPC response data.  If the input stream contains an RPC request,
1587052Samw  * we need to process the RPC transaction, which will place the RPC
1597052Samw  * response in the output (frags) stream.  Otherwise, read data from
1607052Samw  * the output stream.
1617052Samw  */
1627052Samw int
163*8334SJose.Borrego@Sun.COM ndr_pipe_read(int fid, uint8_t *buf, uint32_t *len, uint32_t *resid)
1645772Sas200622 {
165*8334SJose.Borrego@Sun.COM 	ndr_pipe_t *np;
1667052Samw 	ssize_t nbytes = *len;
1677052Samw 	int rc;
1687052Samw 
1697052Samw 	if (nbytes == 0) {
1707052Samw 		*resid = 0;
1717052Samw 		return (0);
1727052Samw 	}
1737052Samw 
174*8334SJose.Borrego@Sun.COM 	(void) mutex_lock(&ndr_pipe_lock);
175*8334SJose.Borrego@Sun.COM 	if ((np = ndr_pipe_lookup(fid)) == NULL) {
176*8334SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ndr_pipe_lock);
1777052Samw 		return (ENOENT);
1787052Samw 	}
179*8334SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ndr_pipe_lock);
1807052Samw 
181*8334SJose.Borrego@Sun.COM 	if (np->np_uio.uio_offset) {
182*8334SJose.Borrego@Sun.COM 		if ((rc = ndr_pipe_transact(np)) != 0) {
183*8334SJose.Borrego@Sun.COM 			ndr_pipe_flush(np);
184*8334SJose.Borrego@Sun.COM 			(void) mutex_lock(&ndr_pipe_lock);
185*8334SJose.Borrego@Sun.COM 			ndr_pipe_release(np);
186*8334SJose.Borrego@Sun.COM 			(void) mutex_unlock(&ndr_pipe_lock);
1877052Samw 			return (rc);
1887052Samw 		}
1897052Samw 
1907052Samw 	}
1917052Samw 
192*8334SJose.Borrego@Sun.COM 	*len = ndr_uiomove((caddr_t)buf, nbytes, UIO_WRITE, &np->np_frags.uio);
193*8334SJose.Borrego@Sun.COM 	*resid = np->np_frags.uio.uio_resid;
1947052Samw 
1957052Samw 	if (*resid == 0) {
1967052Samw 		/*
1977052Samw 		 * Nothing left, cleanup the output stream.
1987052Samw 		 */
199*8334SJose.Borrego@Sun.COM 		ndr_pipe_flush(np);
2007052Samw 	}
2017052Samw 
202*8334SJose.Borrego@Sun.COM 	(void) mutex_lock(&ndr_pipe_lock);
203*8334SJose.Borrego@Sun.COM 	ndr_pipe_release(np);
204*8334SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ndr_pipe_lock);
2057052Samw 	return (0);
2067052Samw }
2077052Samw 
2087052Samw /*
2097052Samw  * Process a server-side RPC request.
2107052Samw  */
2117052Samw static int
212*8334SJose.Borrego@Sun.COM ndr_pipe_transact(ndr_pipe_t *np)
2137052Samw {
214*8334SJose.Borrego@Sun.COM 	ndr_xa_t	*mxa;
215*8334SJose.Borrego@Sun.COM 	ndr_stream_t	*recv_nds;
216*8334SJose.Borrego@Sun.COM 	ndr_stream_t	*send_nds;
217*8334SJose.Borrego@Sun.COM 	char		*data;
218*8334SJose.Borrego@Sun.COM 	int		datalen;
2195772Sas200622 
220*8334SJose.Borrego@Sun.COM 	data = np->np_buf;
221*8334SJose.Borrego@Sun.COM 	datalen = np->np_uio.uio_offset;
2225772Sas200622 
2237052Samw 	if ((mxa = (ndr_xa_t *)malloc(sizeof (ndr_xa_t))) == NULL)
2247052Samw 		return (ENOMEM);
2255772Sas200622 
226*8334SJose.Borrego@Sun.COM 	bzero(mxa, sizeof (ndr_xa_t));
227*8334SJose.Borrego@Sun.COM 	mxa->fid = np->np_fid;
228*8334SJose.Borrego@Sun.COM 	mxa->pipe = np;
229*8334SJose.Borrego@Sun.COM 	mxa->binding_list = np->np_binding;
2305772Sas200622 
231*8334SJose.Borrego@Sun.COM 	if ((mxa->heap = ndr_heap_create()) == NULL) {
2325772Sas200622 		free(mxa);
2337052Samw 		return (ENOMEM);
2345772Sas200622 	}
2355772Sas200622 
236*8334SJose.Borrego@Sun.COM 	recv_nds = &mxa->recv_nds;
237*8334SJose.Borrego@Sun.COM 	nds_initialize(recv_nds, datalen, NDR_MODE_CALL_RECV, mxa->heap);
2385772Sas200622 
2397052Samw 	/*
2407052Samw 	 * Copy the input data and reset the input stream.
2417052Samw 	 */
242*8334SJose.Borrego@Sun.COM 	bcopy(data, recv_nds->pdu_base_addr, datalen);
243*8334SJose.Borrego@Sun.COM 	ndr_pipe_rewind(np);
2445772Sas200622 
245*8334SJose.Borrego@Sun.COM 	send_nds = &mxa->send_nds;
246*8334SJose.Borrego@Sun.COM 	nds_initialize(send_nds, 0, NDR_MODE_RETURN_SEND, mxa->heap);
2475772Sas200622 
248*8334SJose.Borrego@Sun.COM 	(void) ndr_svc_process(mxa);
2495772Sas200622 
250*8334SJose.Borrego@Sun.COM 	nds_finalize(send_nds, &np->np_frags);
251*8334SJose.Borrego@Sun.COM 	nds_destruct(&mxa->recv_nds);
252*8334SJose.Borrego@Sun.COM 	nds_destruct(&mxa->send_nds);
253*8334SJose.Borrego@Sun.COM 	ndr_heap_destroy(mxa->heap);
2545772Sas200622 	free(mxa);
2557052Samw 	return (0);
2567052Samw }
2577052Samw 
2587052Samw /*
259*8334SJose.Borrego@Sun.COM  * Must be called with ndr_pipe_lock held.
2607052Samw  */
261*8334SJose.Borrego@Sun.COM static ndr_pipe_t *
262*8334SJose.Borrego@Sun.COM ndr_pipe_lookup(int fid)
2637052Samw {
264*8334SJose.Borrego@Sun.COM 	ndr_pipe_t *np;
2657052Samw 	int i;
2667052Samw 
267*8334SJose.Borrego@Sun.COM 	for (i = 0; i < NDR_PIPE_MAX; ++i) {
268*8334SJose.Borrego@Sun.COM 		np = &ndr_pipe_table[i];
2697052Samw 
270*8334SJose.Borrego@Sun.COM 		if (np->np_fid == fid) {
271*8334SJose.Borrego@Sun.COM 			if (np->np_refcnt == 0)
2727052Samw 				return (NULL);
2737052Samw 
274*8334SJose.Borrego@Sun.COM 			np->np_refcnt++;
275*8334SJose.Borrego@Sun.COM 			return (np);
2767052Samw 		}
2777052Samw 	}
2787052Samw 
2797052Samw 	return (NULL);
2805772Sas200622 }
2815772Sas200622 
2825772Sas200622 /*
283*8334SJose.Borrego@Sun.COM  * Must be called with ndr_pipe_lock held.
2845772Sas200622  */
2857052Samw static void
286*8334SJose.Borrego@Sun.COM ndr_pipe_release(ndr_pipe_t *np)
2875772Sas200622 {
288*8334SJose.Borrego@Sun.COM 	np->np_refcnt--;
289*8334SJose.Borrego@Sun.COM 	ndr_pipe_deallocate(np);
2907052Samw }
2917052Samw 
2927052Samw /*
293*8334SJose.Borrego@Sun.COM  * Must be called with ndr_pipe_lock held.
2947052Samw  */
295*8334SJose.Borrego@Sun.COM static ndr_pipe_t *
296*8334SJose.Borrego@Sun.COM ndr_pipe_allocate(int fid)
2977052Samw {
298*8334SJose.Borrego@Sun.COM 	ndr_pipe_t *np = NULL;
2995772Sas200622 	int i;
3005772Sas200622 
301*8334SJose.Borrego@Sun.COM 	for (i = 0; i < NDR_PIPE_MAX; ++i) {
302*8334SJose.Borrego@Sun.COM 		np = &ndr_pipe_table[i];
3035772Sas200622 
304*8334SJose.Borrego@Sun.COM 		if (np->np_fid == 0) {
305*8334SJose.Borrego@Sun.COM 			bzero(np, sizeof (ndr_pipe_t));
3065772Sas200622 
307*8334SJose.Borrego@Sun.COM 			if ((np->np_buf = malloc(NDR_PIPE_BUFSZ)) == NULL)
3087052Samw 				return (NULL);
3095772Sas200622 
310*8334SJose.Borrego@Sun.COM 			ndr_pipe_rewind(np);
311*8334SJose.Borrego@Sun.COM 			np->np_fid = fid;
312*8334SJose.Borrego@Sun.COM 			np->np_refcnt = 1;
313*8334SJose.Borrego@Sun.COM 			return (np);
3145772Sas200622 		}
3155772Sas200622 	}
3165772Sas200622 
3177052Samw 	return (NULL);
3187052Samw }
3195772Sas200622 
3207052Samw /*
321*8334SJose.Borrego@Sun.COM  * Must be called with ndr_pipe_lock held.
3227052Samw  */
3237052Samw static void
324*8334SJose.Borrego@Sun.COM ndr_pipe_deallocate(ndr_pipe_t *np)
3257052Samw {
326*8334SJose.Borrego@Sun.COM 	if (np->np_refcnt == 0) {
3277052Samw 		/*
3287052Samw 		 * Ensure that there are no RPC service policy handles
3297052Samw 		 * (associated with this fid) left around.
3307052Samw 		 */
331*8334SJose.Borrego@Sun.COM 		ndr_hdclose(np->np_fid);
3325772Sas200622 
333*8334SJose.Borrego@Sun.COM 		ndr_pipe_rewind(np);
334*8334SJose.Borrego@Sun.COM 		ndr_pipe_flush(np);
335*8334SJose.Borrego@Sun.COM 		free(np->np_buf);
336*8334SJose.Borrego@Sun.COM 		free(np->np_ctx.oc_domain);
337*8334SJose.Borrego@Sun.COM 		free(np->np_ctx.oc_account);
338*8334SJose.Borrego@Sun.COM 		free(np->np_ctx.oc_workstation);
339*8334SJose.Borrego@Sun.COM 		bzero(np, sizeof (ndr_pipe_t));
3407052Samw 	}
3417052Samw }
3425772Sas200622 
3437052Samw /*
3447052Samw  * Rewind the input data stream, ready for the next write.
3457052Samw  */
3467052Samw static void
347*8334SJose.Borrego@Sun.COM ndr_pipe_rewind(ndr_pipe_t *np)
3487052Samw {
349*8334SJose.Borrego@Sun.COM 	np->np_uio.uio_iov = &np->np_iov;
350*8334SJose.Borrego@Sun.COM 	np->np_uio.uio_iovcnt = 1;
351*8334SJose.Borrego@Sun.COM 	np->np_uio.uio_offset = 0;
352*8334SJose.Borrego@Sun.COM 	np->np_uio.uio_segflg = UIO_USERSPACE;
353*8334SJose.Borrego@Sun.COM 	np->np_uio.uio_resid = NDR_PIPE_BUFSZ;
354*8334SJose.Borrego@Sun.COM 	np->np_iov.iov_base = np->np_buf;
355*8334SJose.Borrego@Sun.COM 	np->np_iov.iov_len = NDR_PIPE_BUFSZ;
3565772Sas200622 }
3575772Sas200622 
3585772Sas200622 /*
3597052Samw  * Flush the output data stream.
3605772Sas200622  */
3617052Samw static void
362*8334SJose.Borrego@Sun.COM ndr_pipe_flush(ndr_pipe_t *np)
3635772Sas200622 {
3647052Samw 	ndr_frag_t *frag;
3655772Sas200622 
366*8334SJose.Borrego@Sun.COM 	while ((frag = np->np_frags.head) != NULL) {
367*8334SJose.Borrego@Sun.COM 		np->np_frags.head = frag->next;
3687052Samw 		free(frag);
3695772Sas200622 	}
3705772Sas200622 
371*8334SJose.Borrego@Sun.COM 	free(np->np_frags.iov);
372*8334SJose.Borrego@Sun.COM 	bzero(&np->np_frags, sizeof (ndr_fraglist_t));
3737052Samw }
3747052Samw 
3757052Samw /*
3767052Samw  * Check whether or not the specified user has administrator privileges,
3777052Samw  * i.e. is a member of Domain Admins or Administrators.
3787052Samw  * Returns true if the user is an administrator, otherwise returns false.
3797052Samw  */
3807052Samw boolean_t
3817052Samw ndr_is_admin(ndr_xa_t *xa)
3827052Samw {
383*8334SJose.Borrego@Sun.COM 	smb_opipe_context_t *ctx = &xa->pipe->np_ctx;
3847052Samw 
385*8334SJose.Borrego@Sun.COM 	return (ctx->oc_flags & SMB_ATF_ADMIN);
3867052Samw }
3877052Samw 
3887052Samw /*
3897052Samw  * Check whether or not the specified user has power-user privileges,
3907052Samw  * i.e. is a member of Domain Admins, Administrators or Power Users.
3917052Samw  * This is typically required for operations such as managing shares.
3927052Samw  * Returns true if the user is a power user, otherwise returns false.
3937052Samw  */
3947052Samw boolean_t
3957052Samw ndr_is_poweruser(ndr_xa_t *xa)
3967052Samw {
397*8334SJose.Borrego@Sun.COM 	smb_opipe_context_t *ctx = &xa->pipe->np_ctx;
3987052Samw 
399*8334SJose.Borrego@Sun.COM 	return ((ctx->oc_flags & SMB_ATF_ADMIN) ||
400*8334SJose.Borrego@Sun.COM 	    (ctx->oc_flags & SMB_ATF_POWERUSER));
4017052Samw }
4027052Samw 
4037052Samw int32_t
4047052Samw ndr_native_os(ndr_xa_t *xa)
4057052Samw {
406*8334SJose.Borrego@Sun.COM 	smb_opipe_context_t *ctx = &xa->pipe->np_ctx;
4077052Samw 
408*8334SJose.Borrego@Sun.COM 	return (ctx->oc_native_os);
4095772Sas200622 }
4105772Sas200622 
4115772Sas200622 /*
4125772Sas200622  * This is the entry point for all server-side RPC processing.
4135772Sas200622  * It is assumed that the PDU has already been received.
4145772Sas200622  */
4155772Sas200622 static int
416*8334SJose.Borrego@Sun.COM ndr_svc_process(ndr_xa_t *mxa)
4175772Sas200622 {
4185772Sas200622 	int rc;
4195772Sas200622 
420*8334SJose.Borrego@Sun.COM 	rc = ndr_decode_pdu_hdr(mxa);
421*8334SJose.Borrego@Sun.COM 	if (!NDR_DRC_IS_OK(rc))
4225772Sas200622 		return (-1);
4235772Sas200622 
424*8334SJose.Borrego@Sun.COM 	(void) ndr_reply_prepare_hdr(mxa);
4255772Sas200622 
4265772Sas200622 	switch (mxa->ptype) {
427*8334SJose.Borrego@Sun.COM 	case NDR_PTYPE_BIND:
428*8334SJose.Borrego@Sun.COM 		rc = ndr_svc_bind(mxa);
4295772Sas200622 		break;
4305772Sas200622 
431*8334SJose.Borrego@Sun.COM 	case NDR_PTYPE_REQUEST:
432*8334SJose.Borrego@Sun.COM 		rc = ndr_svc_request(mxa);
4335772Sas200622 		break;
4345772Sas200622 
435*8334SJose.Borrego@Sun.COM 	case NDR_PTYPE_ALTER_CONTEXT:
436*8334SJose.Borrego@Sun.COM 		rc = ndr_svc_alter_context(mxa);
4375772Sas200622 		break;
4385772Sas200622 
4395772Sas200622 	default:
440*8334SJose.Borrego@Sun.COM 		rc = NDR_DRC_FAULT_RPCHDR_PTYPE_INVALID;
4415772Sas200622 		break;
4425772Sas200622 	}
4435772Sas200622 
444*8334SJose.Borrego@Sun.COM 	if (NDR_DRC_IS_FAULT(rc))
445*8334SJose.Borrego@Sun.COM 		ndr_reply_fault(mxa, rc);
4465772Sas200622 
447*8334SJose.Borrego@Sun.COM 	(void) ndr_build_reply(mxa);
4485772Sas200622 	return (rc);
4495772Sas200622 }
4505772Sas200622 
4515772Sas200622 /*
4525772Sas200622  * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple
4535772Sas200622  * p_results[] not supported.
4545772Sas200622  */
4555772Sas200622 static int
456*8334SJose.Borrego@Sun.COM ndr_svc_bind(ndr_xa_t *mxa)
4575772Sas200622 {
458*8334SJose.Borrego@Sun.COM 	ndr_p_cont_list_t	*cont_list;
459*8334SJose.Borrego@Sun.COM 	ndr_p_result_list_t	*result_list;
460*8334SJose.Borrego@Sun.COM 	ndr_p_result_t		*result;
4615772Sas200622 	unsigned		p_cont_id;
462*8334SJose.Borrego@Sun.COM 	ndr_binding_t		*mbind;
4635772Sas200622 	ndr_uuid_t		*as_uuid;
4645772Sas200622 	ndr_uuid_t		*ts_uuid;
4655772Sas200622 	int			as_vers;
4665772Sas200622 	int			ts_vers;
467*8334SJose.Borrego@Sun.COM 	ndr_service_t		*msvc;
4685772Sas200622 	int			rc;
469*8334SJose.Borrego@Sun.COM 	ndr_port_any_t		*sec_addr;
4705772Sas200622 
4715772Sas200622 	/* acquire targets */
4725772Sas200622 	cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem;
4735772Sas200622 	result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list;
4745772Sas200622 	result = &result_list->p_results[0];
4755772Sas200622 
4765772Sas200622 	/*
4775772Sas200622 	 * Set up temporary secondary address port.
4785772Sas200622 	 * We will correct this later (below).
4795772Sas200622 	 */
4805772Sas200622 	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
4815772Sas200622 	sec_addr->length = 13;
4825772Sas200622 	(void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs");
4835772Sas200622 
4845772Sas200622 	result_list->n_results = 1;
4855772Sas200622 	result_list->reserved = 0;
4865772Sas200622 	result_list->reserved2 = 0;
487*8334SJose.Borrego@Sun.COM 	result->result = NDR_PCDR_ACCEPTANCE;
4885772Sas200622 	result->reason = 0;
4895772Sas200622 	bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
4905772Sas200622 
4915772Sas200622 	/* sanity check */
4925772Sas200622 	if (cont_list->n_context_elem != 1 ||
4935772Sas200622 	    cont_list->p_cont_elem[0].n_transfer_syn != 1) {
494*8334SJose.Borrego@Sun.COM 		ndo_trace("ndr_svc_bind: warning: multiple p_cont_elem");
4955772Sas200622 	}
4965772Sas200622 
4975772Sas200622 	p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
4985772Sas200622 
499*8334SJose.Borrego@Sun.COM 	if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) != NULL) {
5005772Sas200622 		/*
501*8334SJose.Borrego@Sun.COM 		 * Duplicate presentation context id.
5025772Sas200622 		 */
503*8334SJose.Borrego@Sun.COM 		ndo_trace("ndr_svc_bind: duplicate binding");
504*8334SJose.Borrego@Sun.COM 		return (NDR_DRC_FAULT_BIND_PCONT_BUSY);
5055772Sas200622 	}
5065772Sas200622 
507*8334SJose.Borrego@Sun.COM 	if ((mbind = ndr_svc_new_binding(mxa)) == NULL) {
5085772Sas200622 		/*
5095772Sas200622 		 * No free binding slot
5105772Sas200622 		 */
511*8334SJose.Borrego@Sun.COM 		result->result = NDR_PCDR_PROVIDER_REJECTION;
512*8334SJose.Borrego@Sun.COM 		result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED;
513*8334SJose.Borrego@Sun.COM 		ndo_trace("ndr_svc_bind: no resources");
514*8334SJose.Borrego@Sun.COM 		return (NDR_DRC_OK);
5155772Sas200622 	}
5165772Sas200622 
5175772Sas200622 	as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
5185772Sas200622 	as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
5195772Sas200622 
5205772Sas200622 	ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
5215772Sas200622 	ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
5225772Sas200622 
523*8334SJose.Borrego@Sun.COM 	msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers);
524*8334SJose.Borrego@Sun.COM 	if (msvc == NULL) {
525*8334SJose.Borrego@Sun.COM 		result->result = NDR_PCDR_PROVIDER_REJECTION;
526*8334SJose.Borrego@Sun.COM 		result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
527*8334SJose.Borrego@Sun.COM 		return (NDR_DRC_OK);
5285772Sas200622 	}
5295772Sas200622 
5305772Sas200622 	/*
5315772Sas200622 	 * We can now use the correct secondary address port.
5325772Sas200622 	 */
5335772Sas200622 	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
5345772Sas200622 	sec_addr->length = strlen(msvc->sec_addr_port) + 1;
5355772Sas200622 	(void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port,
536*8334SJose.Borrego@Sun.COM 	    NDR_PORT_ANY_MAX_PORT_SPEC);
5375772Sas200622 
5385772Sas200622 	mbind->p_cont_id = p_cont_id;
539*8334SJose.Borrego@Sun.COM 	mbind->which_side = NDR_BIND_SIDE_SERVER;
5405772Sas200622 	/* mbind->context set by app */
5415772Sas200622 	mbind->service = msvc;
5425772Sas200622 	mbind->instance_specific = 0;
5435772Sas200622 
5445772Sas200622 	mxa->binding = mbind;
5455772Sas200622 
5465772Sas200622 	if (msvc->bind_req) {
5475772Sas200622 		/*
5485772Sas200622 		 * Call the service-specific bind() handler.  If
5495772Sas200622 		 * this fails, we shouild send a specific error
5505772Sas200622 		 * on the bind ack.
5515772Sas200622 		 */
5525772Sas200622 		rc = (msvc->bind_req)(mxa);
553*8334SJose.Borrego@Sun.COM 		if (NDR_DRC_IS_FAULT(rc)) {
5545772Sas200622 			mbind->service = 0;	/* free binding slot */
5555772Sas200622 			mbind->which_side = 0;
5565772Sas200622 			mbind->p_cont_id = 0;
5575772Sas200622 			mbind->instance_specific = 0;
5585772Sas200622 			return (rc);
5595772Sas200622 		}
5605772Sas200622 	}
5615772Sas200622 
5625772Sas200622 	result->transfer_syntax =
5635772Sas200622 	    cont_list->p_cont_elem[0].transfer_syntaxes[0];
5645772Sas200622 
565*8334SJose.Borrego@Sun.COM 	return (NDR_DRC_BINDING_MADE);
5665772Sas200622 }
5675772Sas200622 
5685772Sas200622 /*
569*8334SJose.Borrego@Sun.COM  * ndr_svc_alter_context
5705772Sas200622  *
5715772Sas200622  * The alter context request is used to request additional presentation
5727619SJose.Borrego@Sun.COM  * context for another interface and/or version.  It is very similar to
5737619SJose.Borrego@Sun.COM  * a bind request.
5745772Sas200622  */
5755772Sas200622 static int
576*8334SJose.Borrego@Sun.COM ndr_svc_alter_context(ndr_xa_t *mxa)
5775772Sas200622 {
578*8334SJose.Borrego@Sun.COM 	ndr_p_result_list_t *result_list;
579*8334SJose.Borrego@Sun.COM 	ndr_p_result_t *result;
580*8334SJose.Borrego@Sun.COM 	ndr_p_cont_list_t *cont_list;
581*8334SJose.Borrego@Sun.COM 	ndr_binding_t *mbind;
582*8334SJose.Borrego@Sun.COM 	ndr_service_t *msvc;
5835772Sas200622 	unsigned p_cont_id;
5845772Sas200622 	ndr_uuid_t *as_uuid;
5855772Sas200622 	ndr_uuid_t *ts_uuid;
5865772Sas200622 	int as_vers;
5875772Sas200622 	int ts_vers;
588*8334SJose.Borrego@Sun.COM 	ndr_port_any_t *sec_addr;
5895772Sas200622 
5907619SJose.Borrego@Sun.COM 	result_list = &mxa->send_hdr.alter_context_rsp_hdr.p_result_list;
5915772Sas200622 	result_list->n_results = 1;
5925772Sas200622 	result_list->reserved = 0;
5935772Sas200622 	result_list->reserved2 = 0;
5945772Sas200622 
5955772Sas200622 	result = &result_list->p_results[0];
596*8334SJose.Borrego@Sun.COM 	result->result = NDR_PCDR_ACCEPTANCE;
5975772Sas200622 	result->reason = 0;
5985772Sas200622 	bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
5995772Sas200622 
6007619SJose.Borrego@Sun.COM 	cont_list = &mxa->recv_hdr.alter_context_hdr.p_context_elem;
6015772Sas200622 	p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
6025772Sas200622 
603*8334SJose.Borrego@Sun.COM 	if (ndr_svc_find_binding(mxa, p_cont_id) != NULL)
604*8334SJose.Borrego@Sun.COM 		return (NDR_DRC_FAULT_BIND_PCONT_BUSY);
6055772Sas200622 
606*8334SJose.Borrego@Sun.COM 	if ((mbind = ndr_svc_new_binding(mxa)) == NULL) {
607*8334SJose.Borrego@Sun.COM 		result->result = NDR_PCDR_PROVIDER_REJECTION;
608*8334SJose.Borrego@Sun.COM 		result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED;
609*8334SJose.Borrego@Sun.COM 		return (NDR_DRC_OK);
6105772Sas200622 	}
6115772Sas200622 
6125772Sas200622 	as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
6135772Sas200622 	as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
6145772Sas200622 
6155772Sas200622 	ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
6165772Sas200622 	ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
6175772Sas200622 
618*8334SJose.Borrego@Sun.COM 	msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers);
619*8334SJose.Borrego@Sun.COM 	if (msvc == NULL) {
620*8334SJose.Borrego@Sun.COM 		result->result = NDR_PCDR_PROVIDER_REJECTION;
621*8334SJose.Borrego@Sun.COM 		result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
622*8334SJose.Borrego@Sun.COM 		return (NDR_DRC_OK);
6235772Sas200622 	}
6245772Sas200622 
6255772Sas200622 	mbind->p_cont_id = p_cont_id;
626*8334SJose.Borrego@Sun.COM 	mbind->which_side = NDR_BIND_SIDE_SERVER;
6275772Sas200622 	/* mbind->context set by app */
6285772Sas200622 	mbind->service = msvc;
6295772Sas200622 	mbind->instance_specific = 0;
6305772Sas200622 	mxa->binding = mbind;
6315772Sas200622 
6327619SJose.Borrego@Sun.COM 	sec_addr = &mxa->send_hdr.alter_context_rsp_hdr.sec_addr;
6335772Sas200622 	sec_addr->length = 0;
634*8334SJose.Borrego@Sun.COM 	bzero(sec_addr->port_spec, NDR_PORT_ANY_MAX_PORT_SPEC);
6355772Sas200622 
6365772Sas200622 	result->transfer_syntax =
6375772Sas200622 	    cont_list->p_cont_elem[0].transfer_syntaxes[0];
6385772Sas200622 
639*8334SJose.Borrego@Sun.COM 	return (NDR_DRC_BINDING_MADE);
6405772Sas200622 }
6415772Sas200622 
6425772Sas200622 static int
643*8334SJose.Borrego@Sun.COM ndr_svc_request(ndr_xa_t *mxa)
6445772Sas200622 {
645*8334SJose.Borrego@Sun.COM 	ndr_binding_t	*mbind;
646*8334SJose.Borrego@Sun.COM 	ndr_service_t	*msvc;
647*8334SJose.Borrego@Sun.COM 	unsigned	p_cont_id;
648*8334SJose.Borrego@Sun.COM 	int		rc;
6495772Sas200622 
6505772Sas200622 	mxa->opnum = mxa->recv_hdr.request_hdr.opnum;
6515772Sas200622 	p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id;
6525772Sas200622 
653*8334SJose.Borrego@Sun.COM 	if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) == NULL)
654*8334SJose.Borrego@Sun.COM 		return (NDR_DRC_FAULT_REQUEST_PCONT_INVALID);
6555772Sas200622 
6565772Sas200622 	mxa->binding = mbind;
6575772Sas200622 	msvc = mbind->service;
6585772Sas200622 
6595772Sas200622 	/*
6605772Sas200622 	 * Make room for the response hdr.
6615772Sas200622 	 */
662*8334SJose.Borrego@Sun.COM 	mxa->send_nds.pdu_scan_offset = NDR_RSP_HDR_SIZE;
6635772Sas200622 
6645772Sas200622 	if (msvc->call_stub)
6655772Sas200622 		rc = (*msvc->call_stub)(mxa);
6665772Sas200622 	else
667*8334SJose.Borrego@Sun.COM 		rc = ndr_generic_call_stub(mxa);
6685772Sas200622 
669*8334SJose.Borrego@Sun.COM 	if (NDR_DRC_IS_FAULT(rc)) {
670*8334SJose.Borrego@Sun.COM 		ndo_printf(0, 0, "%s[0x%02x]: 0x%04x",
6715772Sas200622 		    msvc->name, mxa->opnum, rc);
6725772Sas200622 	}
6735772Sas200622 
6745772Sas200622 	return (rc);
6755772Sas200622 }
6765772Sas200622 
6775772Sas200622 /*
678*8334SJose.Borrego@Sun.COM  * The transaction and the two nds streams use the same heap, which
6795772Sas200622  * should already exist at this point.  The heap will also be available
6805772Sas200622  * to the stub.
6815772Sas200622  */
6825772Sas200622 int
683*8334SJose.Borrego@Sun.COM ndr_generic_call_stub(ndr_xa_t *mxa)
6845772Sas200622 {
685*8334SJose.Borrego@Sun.COM 	ndr_binding_t 		*mbind = mxa->binding;
686*8334SJose.Borrego@Sun.COM 	ndr_service_t		*msvc = mbind->service;
687*8334SJose.Borrego@Sun.COM 	ndr_typeinfo_t		*intf_ti = msvc->interface_ti;
688*8334SJose.Borrego@Sun.COM 	ndr_stub_table_t	*ste;
6895772Sas200622 	int			opnum = mxa->opnum;
6905772Sas200622 	unsigned		p_len = intf_ti->c_size_fixed_part;
6915772Sas200622 	char 			*param;
6925772Sas200622 	int			rc;
6935772Sas200622 
6945772Sas200622 	if (mxa->heap == NULL) {
695*8334SJose.Borrego@Sun.COM 		ndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum);
696*8334SJose.Borrego@Sun.COM 		return (NDR_DRC_FAULT_OUT_OF_MEMORY);
6975772Sas200622 	}
6985772Sas200622 
699*8334SJose.Borrego@Sun.COM 	if ((ste = ndr_svc_find_stub(msvc, opnum)) == NULL) {
700*8334SJose.Borrego@Sun.COM 		ndo_printf(0, 0, "%s[0x%02x]: invalid opnum",
7015772Sas200622 		    msvc->name, opnum);
702*8334SJose.Borrego@Sun.COM 		return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID);
7035772Sas200622 	}
7045772Sas200622 
705*8334SJose.Borrego@Sun.COM 	if ((param = ndr_heap_malloc(mxa->heap, p_len)) == NULL)
706*8334SJose.Borrego@Sun.COM 		return (NDR_DRC_FAULT_OUT_OF_MEMORY);
7075772Sas200622 
7085772Sas200622 	bzero(param, p_len);
7095772Sas200622 
710*8334SJose.Borrego@Sun.COM 	rc = ndr_decode_call(mxa, param);
711*8334SJose.Borrego@Sun.COM 	if (!NDR_DRC_IS_OK(rc))
7125772Sas200622 		return (rc);
7135772Sas200622 
7145772Sas200622 	rc = (*ste->func)(param, mxa);
715*8334SJose.Borrego@Sun.COM 	if (rc == NDR_DRC_OK)
716*8334SJose.Borrego@Sun.COM 		rc = ndr_encode_return(mxa, param);
7175772Sas200622 
7185772Sas200622 	return (rc);
7195772Sas200622 }
7205772Sas200622 
7215772Sas200622 /*
7225772Sas200622  * We can perform some initial setup of the response header here.
7235772Sas200622  * We also need to cache some of the information from the bind
7245772Sas200622  * negotiation for use during subsequent RPC calls.
7255772Sas200622  */
7265772Sas200622 static void
727*8334SJose.Borrego@Sun.COM ndr_reply_prepare_hdr(ndr_xa_t *mxa)
7285772Sas200622 {
7297619SJose.Borrego@Sun.COM 	ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
7307619SJose.Borrego@Sun.COM 	ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
7315772Sas200622 
7325772Sas200622 	hdr->rpc_vers = 5;
7335772Sas200622 	hdr->rpc_vers_minor = 0;
734*8334SJose.Borrego@Sun.COM 	hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG;
7355772Sas200622 	hdr->packed_drep = rhdr->packed_drep;
7365772Sas200622 	hdr->frag_length = 0;
7375772Sas200622 	hdr->auth_length = 0;
7385772Sas200622 	hdr->call_id = rhdr->call_id;
7395772Sas200622 #ifdef _BIG_ENDIAN
740*8334SJose.Borrego@Sun.COM 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
741*8334SJose.Borrego@Sun.COM 	    | NDR_REPLAB_INTG_BIG_ENDIAN;
7425772Sas200622 #else
743*8334SJose.Borrego@Sun.COM 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
744*8334SJose.Borrego@Sun.COM 	    | NDR_REPLAB_INTG_LITTLE_ENDIAN;
7455772Sas200622 #endif
7465772Sas200622 
7475772Sas200622 	switch (mxa->ptype) {
748*8334SJose.Borrego@Sun.COM 	case NDR_PTYPE_BIND:
749*8334SJose.Borrego@Sun.COM 		hdr->ptype = NDR_PTYPE_BIND_ACK;
7505772Sas200622 		mxa->send_hdr.bind_ack_hdr.max_xmit_frag =
7515772Sas200622 		    mxa->recv_hdr.bind_hdr.max_xmit_frag;
7525772Sas200622 		mxa->send_hdr.bind_ack_hdr.max_recv_frag =
7535772Sas200622 		    mxa->recv_hdr.bind_hdr.max_recv_frag;
7545772Sas200622 		mxa->send_hdr.bind_ack_hdr.assoc_group_id =
7555772Sas200622 		    mxa->recv_hdr.bind_hdr.assoc_group_id;
7565772Sas200622 
7575772Sas200622 		if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0)
7585772Sas200622 			mxa->send_hdr.bind_ack_hdr.assoc_group_id = time(0);
7595772Sas200622 
7605772Sas200622 		/*
7615772Sas200622 		 * Save the maximum fragment sizes
7625772Sas200622 		 * for use with subsequent requests.
7635772Sas200622 		 */
764*8334SJose.Borrego@Sun.COM 		mxa->pipe->np_max_xmit_frag =
7655772Sas200622 		    mxa->recv_hdr.bind_hdr.max_xmit_frag;
766*8334SJose.Borrego@Sun.COM 		mxa->pipe->np_max_recv_frag =
7675772Sas200622 		    mxa->recv_hdr.bind_hdr.max_recv_frag;
7685772Sas200622 		break;
7695772Sas200622 
770*8334SJose.Borrego@Sun.COM 	case NDR_PTYPE_REQUEST:
771*8334SJose.Borrego@Sun.COM 		hdr->ptype = NDR_PTYPE_RESPONSE;
7725772Sas200622 		/* mxa->send_hdr.response_hdr.alloc_hint */
7735772Sas200622 		mxa->send_hdr.response_hdr.p_cont_id =
7745772Sas200622 		    mxa->recv_hdr.request_hdr.p_cont_id;
7755772Sas200622 		mxa->send_hdr.response_hdr.cancel_count = 0;
7765772Sas200622 		mxa->send_hdr.response_hdr.reserved = 0;
7775772Sas200622 		break;
7785772Sas200622 
779*8334SJose.Borrego@Sun.COM 	case NDR_PTYPE_ALTER_CONTEXT:
780*8334SJose.Borrego@Sun.COM 		hdr->ptype = NDR_PTYPE_ALTER_CONTEXT_RESP;
7815772Sas200622 		/*
7827619SJose.Borrego@Sun.COM 		 * The max_xmit_frag, max_recv_frag and assoc_group_id are
7837619SJose.Borrego@Sun.COM 		 * ignored by the client but it's useful to fill them in.
7845772Sas200622 		 */
7857619SJose.Borrego@Sun.COM 		mxa->send_hdr.alter_context_rsp_hdr.max_xmit_frag =
7867619SJose.Borrego@Sun.COM 		    mxa->recv_hdr.alter_context_hdr.max_xmit_frag;
7877619SJose.Borrego@Sun.COM 		mxa->send_hdr.alter_context_rsp_hdr.max_recv_frag =
7887619SJose.Borrego@Sun.COM 		    mxa->recv_hdr.alter_context_hdr.max_recv_frag;
7897619SJose.Borrego@Sun.COM 		mxa->send_hdr.alter_context_rsp_hdr.assoc_group_id =
7907619SJose.Borrego@Sun.COM 		    mxa->recv_hdr.alter_context_hdr.assoc_group_id;
7915772Sas200622 		break;
7925772Sas200622 
7935772Sas200622 	default:
7945772Sas200622 		hdr->ptype = 0xFF;
7955772Sas200622 	}
7965772Sas200622 }
7975772Sas200622 
7985772Sas200622 /*
7995772Sas200622  * Signal an RPC fault. The stream is reset and we overwrite whatever
8005772Sas200622  * was in the response header with the fault information.
8015772Sas200622  */
8025772Sas200622 static void
803*8334SJose.Borrego@Sun.COM ndr_reply_fault(ndr_xa_t *mxa, unsigned long drc)
8045772Sas200622 {
8057619SJose.Borrego@Sun.COM 	ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
8067619SJose.Borrego@Sun.COM 	ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
807*8334SJose.Borrego@Sun.COM 	ndr_stream_t *nds = &mxa->send_nds;
8085772Sas200622 	unsigned long fault_status;
8095772Sas200622 
810*8334SJose.Borrego@Sun.COM 	NDS_RESET(nds);
8115772Sas200622 
8125772Sas200622 	hdr->rpc_vers = 5;
8135772Sas200622 	hdr->rpc_vers_minor = 0;
814*8334SJose.Borrego@Sun.COM 	hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG;
8155772Sas200622 	hdr->packed_drep = rhdr->packed_drep;
8165772Sas200622 	hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr);
8175772Sas200622 	hdr->auth_length = 0;
8185772Sas200622 	hdr->call_id = rhdr->call_id;
8195772Sas200622 #ifdef _BIG_ENDIAN
820*8334SJose.Borrego@Sun.COM 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
821*8334SJose.Borrego@Sun.COM 	    | NDR_REPLAB_INTG_BIG_ENDIAN;
8225772Sas200622 #else
823*8334SJose.Borrego@Sun.COM 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
824*8334SJose.Borrego@Sun.COM 	    | NDR_REPLAB_INTG_LITTLE_ENDIAN;
8255772Sas200622 #endif
8265772Sas200622 
827*8334SJose.Borrego@Sun.COM 	switch (drc & NDR_DRC_MASK_SPECIFIER) {
828*8334SJose.Borrego@Sun.COM 	case NDR_DRC_FAULT_OUT_OF_MEMORY:
829*8334SJose.Borrego@Sun.COM 	case NDR_DRC_FAULT_ENCODE_TOO_BIG:
830*8334SJose.Borrego@Sun.COM 		fault_status = NDR_FAULT_NCA_OUT_ARGS_TOO_BIG;
8315772Sas200622 		break;
8325772Sas200622 
833*8334SJose.Borrego@Sun.COM 	case NDR_DRC_FAULT_REQUEST_PCONT_INVALID:
834*8334SJose.Borrego@Sun.COM 		fault_status = NDR_FAULT_NCA_INVALID_PRES_CONTEXT_ID;
8355772Sas200622 		break;
8365772Sas200622 
837*8334SJose.Borrego@Sun.COM 	case NDR_DRC_FAULT_REQUEST_OPNUM_INVALID:
838*8334SJose.Borrego@Sun.COM 		fault_status = NDR_FAULT_NCA_OP_RNG_ERROR;
8395772Sas200622 		break;
8405772Sas200622 
841*8334SJose.Borrego@Sun.COM 	case NDR_DRC_FAULT_DECODE_FAILED:
842*8334SJose.Borrego@Sun.COM 	case NDR_DRC_FAULT_ENCODE_FAILED:
843*8334SJose.Borrego@Sun.COM 		fault_status = NDR_FAULT_NCA_PROTO_ERROR;
8445772Sas200622 		break;
8455772Sas200622 
8465772Sas200622 	default:
847*8334SJose.Borrego@Sun.COM 		fault_status = NDR_FAULT_NCA_UNSPEC_REJECT;
8485772Sas200622 		break;
8495772Sas200622 	}
8505772Sas200622 
851*8334SJose.Borrego@Sun.COM 	mxa->send_hdr.fault_hdr.common_hdr.ptype = NDR_PTYPE_FAULT;
8525772Sas200622 	mxa->send_hdr.fault_hdr.status = fault_status;
8535772Sas200622 	mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length;
8545772Sas200622 }
8555772Sas200622 
8567619SJose.Borrego@Sun.COM /*
8577619SJose.Borrego@Sun.COM  * Note that the frag_length for bind ack and alter context is
8587619SJose.Borrego@Sun.COM  * non-standard.
8597619SJose.Borrego@Sun.COM  */
8605772Sas200622 static int
861*8334SJose.Borrego@Sun.COM ndr_build_reply(ndr_xa_t *mxa)
8625772Sas200622 {
8637619SJose.Borrego@Sun.COM 	ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
864*8334SJose.Borrego@Sun.COM 	ndr_stream_t *nds = &mxa->send_nds;
8656482Samw 	uint8_t *pdu_buf;
8665772Sas200622 	unsigned long pdu_size;
8675772Sas200622 	unsigned long frag_size;
8685772Sas200622 	unsigned long pdu_data_size;
8695772Sas200622 	unsigned long frag_data_size;
8705772Sas200622 
871*8334SJose.Borrego@Sun.COM 	frag_size = NDR_FRAG_SZ;
872*8334SJose.Borrego@Sun.COM 	pdu_size = nds->pdu_size;
873*8334SJose.Borrego@Sun.COM 	pdu_buf = nds->pdu_base_addr;
8745772Sas200622 
8755772Sas200622 	if (pdu_size <= frag_size) {
8765772Sas200622 		/*
8775772Sas200622 		 * Single fragment response. The PDU size may be zero
8785772Sas200622 		 * here (i.e. bind or fault response). So don't make
8795772Sas200622 		 * any assumptions about it until after the header is
8805772Sas200622 		 * encoded.
8815772Sas200622 		 */
8825772Sas200622 		switch (hdr->ptype) {
883*8334SJose.Borrego@Sun.COM 		case NDR_PTYPE_BIND_ACK:
884*8334SJose.Borrego@Sun.COM 			hdr->frag_length = ndr_bind_ack_hdr_size(mxa);
8855772Sas200622 			break;
8865772Sas200622 
887*8334SJose.Borrego@Sun.COM 		case NDR_PTYPE_FAULT:
8885772Sas200622 			/* already setup */
8895772Sas200622 			break;
8905772Sas200622 
891*8334SJose.Borrego@Sun.COM 		case NDR_PTYPE_RESPONSE:
8925772Sas200622 			hdr->frag_length = pdu_size;
8935772Sas200622 			mxa->send_hdr.response_hdr.alloc_hint =
8945772Sas200622 			    hdr->frag_length;
8955772Sas200622 			break;
8965772Sas200622 
897*8334SJose.Borrego@Sun.COM 		case NDR_PTYPE_ALTER_CONTEXT_RESP:
898*8334SJose.Borrego@Sun.COM 			hdr->frag_length = ndr_alter_context_rsp_hdr_size();
8997619SJose.Borrego@Sun.COM 			break;
9007619SJose.Borrego@Sun.COM 
9015772Sas200622 		default:
9025772Sas200622 			hdr->frag_length = pdu_size;
9035772Sas200622 			break;
9045772Sas200622 		}
9055772Sas200622 
906*8334SJose.Borrego@Sun.COM 		nds->pdu_scan_offset = 0;
907*8334SJose.Borrego@Sun.COM 		(void) ndr_encode_pdu_hdr(mxa);
908*8334SJose.Borrego@Sun.COM 		pdu_size = nds->pdu_size;
909*8334SJose.Borrego@Sun.COM 		ndr_build_frag(nds, pdu_buf,  pdu_size);
9105772Sas200622 		return (0);
9115772Sas200622 	}
9125772Sas200622 
9135772Sas200622 	/*
9145772Sas200622 	 * Multiple fragment response.
9155772Sas200622 	 */
916*8334SJose.Borrego@Sun.COM 	hdr->pfc_flags = NDR_PFC_FIRST_FRAG;
9175772Sas200622 	hdr->frag_length = frag_size;
918*8334SJose.Borrego@Sun.COM 	mxa->send_hdr.response_hdr.alloc_hint = pdu_size - NDR_RSP_HDR_SIZE;
919*8334SJose.Borrego@Sun.COM 	nds->pdu_scan_offset = 0;
920*8334SJose.Borrego@Sun.COM 	(void) ndr_encode_pdu_hdr(mxa);
921*8334SJose.Borrego@Sun.COM 	ndr_build_frag(nds, pdu_buf,  frag_size);
9225772Sas200622 
9235772Sas200622 	/*
9245772Sas200622 	 * We need to update the 24-byte header in subsequent fragments.
9255772Sas200622 	 *
9266482Samw 	 * pdu_data_size:	total data remaining to be handled
9276482Samw 	 * frag_size:		total fragment size including header
9286482Samw 	 * frag_data_size:	data in fragment
929*8334SJose.Borrego@Sun.COM 	 *			(i.e. frag_size - NDR_RSP_HDR_SIZE)
9305772Sas200622 	 */
931*8334SJose.Borrego@Sun.COM 	pdu_data_size = pdu_size - NDR_RSP_HDR_SIZE;
932*8334SJose.Borrego@Sun.COM 	frag_data_size = frag_size - NDR_RSP_HDR_SIZE;
9335772Sas200622 
9346482Samw 	while (pdu_data_size) {
9356482Samw 		mxa->send_hdr.response_hdr.alloc_hint -= frag_data_size;
9366482Samw 		pdu_data_size -= frag_data_size;
9376482Samw 		pdu_buf += frag_data_size;
9385772Sas200622 
9396482Samw 		if (pdu_data_size <= frag_data_size) {
9406482Samw 			frag_data_size = pdu_data_size;
941*8334SJose.Borrego@Sun.COM 			frag_size = frag_data_size + NDR_RSP_HDR_SIZE;
942*8334SJose.Borrego@Sun.COM 			hdr->pfc_flags = NDR_PFC_LAST_FRAG;
9435772Sas200622 		} else {
9446482Samw 			hdr->pfc_flags = 0;
9455772Sas200622 		}
9465772Sas200622 
9476482Samw 		hdr->frag_length = frag_size;
948*8334SJose.Borrego@Sun.COM 		nds->pdu_scan_offset = 0;
949*8334SJose.Borrego@Sun.COM 		(void) ndr_encode_pdu_hdr(mxa);
950*8334SJose.Borrego@Sun.COM 		bcopy(nds->pdu_base_addr, pdu_buf, NDR_RSP_HDR_SIZE);
9515772Sas200622 
952*8334SJose.Borrego@Sun.COM 		ndr_build_frag(nds, pdu_buf, frag_size);
9535772Sas200622 
954*8334SJose.Borrego@Sun.COM 		if (hdr->pfc_flags & NDR_PFC_LAST_FRAG)
9556482Samw 			break;
9565772Sas200622 	}
9575772Sas200622 
9585772Sas200622 	return (0);
9595772Sas200622 }
9606482Samw 
9616482Samw /*
962*8334SJose.Borrego@Sun.COM  * ndr_build_frag
9636482Samw  *
9646482Samw  * Build an RPC PDU fragment from the specified buffer.
9656482Samw  * If malloc fails, the client will see a header/pdu inconsistency
9666482Samw  * and report an error.
9676482Samw  */
9686482Samw static void
969*8334SJose.Borrego@Sun.COM ndr_build_frag(ndr_stream_t *nds, uint8_t *buf, uint32_t len)
9706482Samw {
9716482Samw 	ndr_frag_t *frag;
9726482Samw 	int size = sizeof (ndr_frag_t) + len;
9736482Samw 
9746482Samw 	if ((frag = (ndr_frag_t *)malloc(size)) == NULL)
9756482Samw 		return;
9766482Samw 
9776482Samw 	frag->next = NULL;
9786482Samw 	frag->buf = (uint8_t *)frag + sizeof (ndr_frag_t);
9796482Samw 	frag->len = len;
9806482Samw 	bcopy(buf, frag->buf, len);
9816482Samw 
982*8334SJose.Borrego@Sun.COM 	if (nds->frags.head == NULL) {
983*8334SJose.Borrego@Sun.COM 		nds->frags.head = frag;
984*8334SJose.Borrego@Sun.COM 		nds->frags.tail = frag;
985*8334SJose.Borrego@Sun.COM 		nds->frags.nfrag = 1;
9866482Samw 	} else {
987*8334SJose.Borrego@Sun.COM 		nds->frags.tail->next = frag;
988*8334SJose.Borrego@Sun.COM 		nds->frags.tail = frag;
989*8334SJose.Borrego@Sun.COM 		++nds->frags.nfrag;
9906482Samw 	}
9916482Samw }
992