xref: /onnv-gate/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c (revision 11963:061945695ce1)
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 /*
22*11963SAfshin.Ardakani@Sun.COM  * Copyright 2010 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>
428474SJose.Borrego@Sun.COM #include <smbsrv/ntaccess.h>
435772Sas200622 
445772Sas200622 /*
455772Sas200622  * Fragment size (5680: NT style).
465772Sas200622  */
478334SJose.Borrego@Sun.COM #define	NDR_FRAG_SZ		5680
485772Sas200622 
49*11963SAfshin.Ardakani@Sun.COM #define	NDR_GROW_SIZE		(8 * 1024)
50*11963SAfshin.Ardakani@Sun.COM #define	NDR_GROW_MASK		(NDR_GROW_SIZE - 1)
51*11963SAfshin.Ardakani@Sun.COM #define	NDR_ALIGN_BUF(S)	(((S) + NDR_GROW_SIZE) & ~NDR_GROW_MASK)
52*11963SAfshin.Ardakani@Sun.COM 
53*11963SAfshin.Ardakani@Sun.COM #define	NDR_PIPE_BUFSZ		(64 * 1024)
54*11963SAfshin.Ardakani@Sun.COM #define	NDR_PIPE_BUFMAX		(64 * 1024 * 1024)
558334SJose.Borrego@Sun.COM #define	NDR_PIPE_MAX		128
56*11963SAfshin.Ardakani@Sun.COM 
578334SJose.Borrego@Sun.COM static ndr_pipe_t ndr_pipe_table[NDR_PIPE_MAX];
588334SJose.Borrego@Sun.COM static mutex_t ndr_pipe_lock;
595772Sas200622 
60*11963SAfshin.Ardakani@Sun.COM static int ndr_pipe_process(ndr_pipe_t *);
618334SJose.Borrego@Sun.COM static ndr_pipe_t *ndr_pipe_lookup(int);
628334SJose.Borrego@Sun.COM static void ndr_pipe_release(ndr_pipe_t *);
638334SJose.Borrego@Sun.COM static ndr_pipe_t *ndr_pipe_allocate(int);
64*11963SAfshin.Ardakani@Sun.COM static int ndr_pipe_grow(ndr_pipe_t *, size_t);
658334SJose.Borrego@Sun.COM static void ndr_pipe_deallocate(ndr_pipe_t *);
668334SJose.Borrego@Sun.COM static void ndr_pipe_rewind(ndr_pipe_t *);
678334SJose.Borrego@Sun.COM static void ndr_pipe_flush(ndr_pipe_t *);
687052Samw 
698334SJose.Borrego@Sun.COM static int ndr_svc_process(ndr_xa_t *);
70*11963SAfshin.Ardakani@Sun.COM static int ndr_svc_defrag(ndr_xa_t *);
718334SJose.Borrego@Sun.COM static int ndr_svc_bind(ndr_xa_t *);
728334SJose.Borrego@Sun.COM static int ndr_svc_request(ndr_xa_t *);
738334SJose.Borrego@Sun.COM static void ndr_reply_prepare_hdr(ndr_xa_t *);
748334SJose.Borrego@Sun.COM static int ndr_svc_alter_context(ndr_xa_t *);
758334SJose.Borrego@Sun.COM static void ndr_reply_fault(ndr_xa_t *, unsigned long);
768334SJose.Borrego@Sun.COM static int ndr_build_reply(ndr_xa_t *);
778334SJose.Borrego@Sun.COM static void ndr_build_frag(ndr_stream_t *, uint8_t *, uint32_t);
785772Sas200622 
795772Sas200622 /*
807052Samw  * Allocate and associate a service context with a fid.
817052Samw  */
827052Samw int
838334SJose.Borrego@Sun.COM ndr_pipe_open(int fid, uint8_t *data, uint32_t datalen)
847052Samw {
858334SJose.Borrego@Sun.COM 	ndr_pipe_t *np;
867052Samw 
878334SJose.Borrego@Sun.COM 	(void) mutex_lock(&ndr_pipe_lock);
887052Samw 
898334SJose.Borrego@Sun.COM 	if ((np = ndr_pipe_lookup(fid)) != NULL) {
908334SJose.Borrego@Sun.COM 		ndr_pipe_release(np);
918334SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ndr_pipe_lock);
927052Samw 		return (EEXIST);
937052Samw 	}
947052Samw 
958334SJose.Borrego@Sun.COM 	if ((np = ndr_pipe_allocate(fid)) == NULL) {
968334SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ndr_pipe_lock);
977052Samw 		return (ENOMEM);
987052Samw 	}
997052Samw 
10010122SJordan.Brown@Sun.COM 	if (smb_netuserinfo_decode(&np->np_user, data, datalen, NULL) == -1) {
1018334SJose.Borrego@Sun.COM 		ndr_pipe_release(np);
1028334SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ndr_pipe_lock);
1037052Samw 		return (EINVAL);
1047052Samw 	}
1057052Samw 
1068334SJose.Borrego@Sun.COM 	ndr_svc_binding_pool_init(&np->np_binding, np->np_binding_pool,
1078334SJose.Borrego@Sun.COM 	    NDR_N_BINDING_POOL);
1087052Samw 
1098334SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ndr_pipe_lock);
1107052Samw 	return (0);
1117052Samw }
1127052Samw 
1137052Samw /*
1147052Samw  * Release the context associated with a fid when an opipe is closed.
1157052Samw  */
1167052Samw int
1178334SJose.Borrego@Sun.COM ndr_pipe_close(int fid)
1187052Samw {
1198334SJose.Borrego@Sun.COM 	ndr_pipe_t *np;
1207052Samw 
1218334SJose.Borrego@Sun.COM 	(void) mutex_lock(&ndr_pipe_lock);
1227052Samw 
1238334SJose.Borrego@Sun.COM 	if ((np = ndr_pipe_lookup(fid)) == NULL) {
1248334SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ndr_pipe_lock);
1257052Samw 		return (ENOENT);
1267052Samw 	}
1277052Samw 
1287052Samw 	/*
1297052Samw 	 * Release twice: once for the lookup above
1307052Samw 	 * and again to close the fid.
1317052Samw 	 */
1328334SJose.Borrego@Sun.COM 	ndr_pipe_release(np);
1338334SJose.Borrego@Sun.COM 	ndr_pipe_release(np);
1348334SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ndr_pipe_lock);
1357052Samw 	return (0);
1367052Samw }
1377052Samw 
1387052Samw /*
1397052Samw  * Write RPC request data to the input stream.  Input data is buffered
1407052Samw  * until the response is requested.
1415772Sas200622  */
1427052Samw int
1438334SJose.Borrego@Sun.COM ndr_pipe_write(int fid, uint8_t *buf, uint32_t len)
1447052Samw {
145*11963SAfshin.Ardakani@Sun.COM 	ndr_pipe_t	*np;
146*11963SAfshin.Ardakani@Sun.COM 	ssize_t		nbytes;
147*11963SAfshin.Ardakani@Sun.COM 	int		rc;
1487052Samw 
1497052Samw 	if (len == 0)
1507052Samw 		return (0);
1517052Samw 
1528334SJose.Borrego@Sun.COM 	(void) mutex_lock(&ndr_pipe_lock);
1537052Samw 
1548334SJose.Borrego@Sun.COM 	if ((np = ndr_pipe_lookup(fid)) == NULL) {
1558334SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ndr_pipe_lock);
1567052Samw 		return (ENOENT);
1577052Samw 	}
1587052Samw 
159*11963SAfshin.Ardakani@Sun.COM 	if ((rc = ndr_pipe_grow(np, len)) != 0) {
160*11963SAfshin.Ardakani@Sun.COM 		(void) mutex_unlock(&ndr_pipe_lock);
161*11963SAfshin.Ardakani@Sun.COM 		return (rc);
162*11963SAfshin.Ardakani@Sun.COM 	}
163*11963SAfshin.Ardakani@Sun.COM 
1648334SJose.Borrego@Sun.COM 	nbytes = ndr_uiomove((caddr_t)buf, len, UIO_READ, &np->np_uio);
1657052Samw 
1668334SJose.Borrego@Sun.COM 	ndr_pipe_release(np);
1678334SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ndr_pipe_lock);
1687052Samw 	return ((nbytes == len) ? 0 : EIO);
1697052Samw }
1707052Samw 
1717052Samw /*
172*11963SAfshin.Ardakani@Sun.COM  * Read RPC response data.
1737052Samw  */
1747052Samw int
1758334SJose.Borrego@Sun.COM ndr_pipe_read(int fid, uint8_t *buf, uint32_t *len, uint32_t *resid)
1765772Sas200622 {
1778334SJose.Borrego@Sun.COM 	ndr_pipe_t *np;
1787052Samw 	ssize_t nbytes = *len;
1797052Samw 
1807052Samw 	if (nbytes == 0) {
1817052Samw 		*resid = 0;
1827052Samw 		return (0);
1837052Samw 	}
1847052Samw 
1858334SJose.Borrego@Sun.COM 	(void) mutex_lock(&ndr_pipe_lock);
1868334SJose.Borrego@Sun.COM 	if ((np = ndr_pipe_lookup(fid)) == NULL) {
1878334SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ndr_pipe_lock);
1887052Samw 		return (ENOENT);
1897052Samw 	}
1908334SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ndr_pipe_lock);
1917052Samw 
1928334SJose.Borrego@Sun.COM 	*len = ndr_uiomove((caddr_t)buf, nbytes, UIO_WRITE, &np->np_frags.uio);
1938334SJose.Borrego@Sun.COM 	*resid = np->np_frags.uio.uio_resid;
1947052Samw 
1957052Samw 	if (*resid == 0) {
1967052Samw 		/*
1977052Samw 		 * Nothing left, cleanup the output stream.
1987052Samw 		 */
1998334SJose.Borrego@Sun.COM 		ndr_pipe_flush(np);
2007052Samw 	}
2017052Samw 
2028334SJose.Borrego@Sun.COM 	(void) mutex_lock(&ndr_pipe_lock);
2038334SJose.Borrego@Sun.COM 	ndr_pipe_release(np);
2048334SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ndr_pipe_lock);
2057052Samw 	return (0);
2067052Samw }
2077052Samw 
2087052Samw /*
209*11963SAfshin.Ardakani@Sun.COM  * If the input stream contains an RPC request, process the RPC transaction,
210*11963SAfshin.Ardakani@Sun.COM  * which will place the RPC response in the output (frags) stream.
211*11963SAfshin.Ardakani@Sun.COM  *
212*11963SAfshin.Ardakani@Sun.COM  * arg is freed here; it must have been allocated by malloc().
213*11963SAfshin.Ardakani@Sun.COM  */
214*11963SAfshin.Ardakani@Sun.COM void *
215*11963SAfshin.Ardakani@Sun.COM ndr_pipe_transact(void *arg)
216*11963SAfshin.Ardakani@Sun.COM {
217*11963SAfshin.Ardakani@Sun.COM 	uint32_t	*tmp = (uint32_t *)arg;
218*11963SAfshin.Ardakani@Sun.COM 	uint32_t	fid;
219*11963SAfshin.Ardakani@Sun.COM 	ndr_pipe_t	*np;
220*11963SAfshin.Ardakani@Sun.COM 
221*11963SAfshin.Ardakani@Sun.COM 	if (arg == NULL)
222*11963SAfshin.Ardakani@Sun.COM 		return (NULL);
223*11963SAfshin.Ardakani@Sun.COM 
224*11963SAfshin.Ardakani@Sun.COM 	fid = *tmp;
225*11963SAfshin.Ardakani@Sun.COM 
226*11963SAfshin.Ardakani@Sun.COM 	(void) mutex_lock(&ndr_pipe_lock);
227*11963SAfshin.Ardakani@Sun.COM 	if ((np = ndr_pipe_lookup(fid)) == NULL) {
228*11963SAfshin.Ardakani@Sun.COM 		(void) mutex_unlock(&ndr_pipe_lock);
229*11963SAfshin.Ardakani@Sun.COM 		(void) smb_kmod_event_notify(fid);
230*11963SAfshin.Ardakani@Sun.COM 		free(arg);
231*11963SAfshin.Ardakani@Sun.COM 		return (NULL);
232*11963SAfshin.Ardakani@Sun.COM 	}
233*11963SAfshin.Ardakani@Sun.COM 	(void) mutex_unlock(&ndr_pipe_lock);
234*11963SAfshin.Ardakani@Sun.COM 
235*11963SAfshin.Ardakani@Sun.COM 	if (ndr_pipe_process(np) != 0)
236*11963SAfshin.Ardakani@Sun.COM 		ndr_pipe_flush(np);
237*11963SAfshin.Ardakani@Sun.COM 
238*11963SAfshin.Ardakani@Sun.COM 	(void) mutex_lock(&ndr_pipe_lock);
239*11963SAfshin.Ardakani@Sun.COM 	ndr_pipe_release(np);
240*11963SAfshin.Ardakani@Sun.COM 	(void) mutex_unlock(&ndr_pipe_lock);
241*11963SAfshin.Ardakani@Sun.COM 	(void) smb_kmod_event_notify(fid);
242*11963SAfshin.Ardakani@Sun.COM 	free(arg);
243*11963SAfshin.Ardakani@Sun.COM 	return (NULL);
244*11963SAfshin.Ardakani@Sun.COM }
245*11963SAfshin.Ardakani@Sun.COM 
246*11963SAfshin.Ardakani@Sun.COM /*
2477052Samw  * Process a server-side RPC request.
2487052Samw  */
2497052Samw static int
250*11963SAfshin.Ardakani@Sun.COM ndr_pipe_process(ndr_pipe_t *np)
2517052Samw {
2528334SJose.Borrego@Sun.COM 	ndr_xa_t	*mxa;
2538334SJose.Borrego@Sun.COM 	ndr_stream_t	*recv_nds;
2548334SJose.Borrego@Sun.COM 	ndr_stream_t	*send_nds;
2558334SJose.Borrego@Sun.COM 	char		*data;
2568334SJose.Borrego@Sun.COM 	int		datalen;
25711337SWilliam.Krier@Sun.COM 	int		rc;
2585772Sas200622 
2598334SJose.Borrego@Sun.COM 	data = np->np_buf;
2608334SJose.Borrego@Sun.COM 	datalen = np->np_uio.uio_offset;
2615772Sas200622 
262*11963SAfshin.Ardakani@Sun.COM 	if (datalen == 0)
263*11963SAfshin.Ardakani@Sun.COM 		return (0);
264*11963SAfshin.Ardakani@Sun.COM 
2657052Samw 	if ((mxa = (ndr_xa_t *)malloc(sizeof (ndr_xa_t))) == NULL)
2667052Samw 		return (ENOMEM);
2675772Sas200622 
2688334SJose.Borrego@Sun.COM 	bzero(mxa, sizeof (ndr_xa_t));
2698334SJose.Borrego@Sun.COM 	mxa->fid = np->np_fid;
2708334SJose.Borrego@Sun.COM 	mxa->pipe = np;
2718334SJose.Borrego@Sun.COM 	mxa->binding_list = np->np_binding;
2725772Sas200622 
2738334SJose.Borrego@Sun.COM 	if ((mxa->heap = ndr_heap_create()) == NULL) {
2745772Sas200622 		free(mxa);
2757052Samw 		return (ENOMEM);
2765772Sas200622 	}
2775772Sas200622 
2788334SJose.Borrego@Sun.COM 	recv_nds = &mxa->recv_nds;
27911337SWilliam.Krier@Sun.COM 	rc = nds_initialize(recv_nds, datalen, NDR_MODE_CALL_RECV, mxa->heap);
28011337SWilliam.Krier@Sun.COM 	if (rc != 0) {
28111337SWilliam.Krier@Sun.COM 		ndr_heap_destroy(mxa->heap);
28211337SWilliam.Krier@Sun.COM 		free(mxa);
28311337SWilliam.Krier@Sun.COM 		return (ENOMEM);
28411337SWilliam.Krier@Sun.COM 	}
2855772Sas200622 
2867052Samw 	/*
2877052Samw 	 * Copy the input data and reset the input stream.
2887052Samw 	 */
2898334SJose.Borrego@Sun.COM 	bcopy(data, recv_nds->pdu_base_addr, datalen);
2908334SJose.Borrego@Sun.COM 	ndr_pipe_rewind(np);
2915772Sas200622 
2928334SJose.Borrego@Sun.COM 	send_nds = &mxa->send_nds;
29311337SWilliam.Krier@Sun.COM 	rc = nds_initialize(send_nds, 0, NDR_MODE_RETURN_SEND, mxa->heap);
29411337SWilliam.Krier@Sun.COM 	if (rc != 0) {
29511337SWilliam.Krier@Sun.COM 		nds_destruct(&mxa->recv_nds);
29611337SWilliam.Krier@Sun.COM 		ndr_heap_destroy(mxa->heap);
29711337SWilliam.Krier@Sun.COM 		free(mxa);
29811337SWilliam.Krier@Sun.COM 		return (ENOMEM);
29911337SWilliam.Krier@Sun.COM 	}
3005772Sas200622 
3018334SJose.Borrego@Sun.COM 	(void) ndr_svc_process(mxa);
3025772Sas200622 
3038334SJose.Borrego@Sun.COM 	nds_finalize(send_nds, &np->np_frags);
3048334SJose.Borrego@Sun.COM 	nds_destruct(&mxa->recv_nds);
3058334SJose.Borrego@Sun.COM 	nds_destruct(&mxa->send_nds);
3068334SJose.Borrego@Sun.COM 	ndr_heap_destroy(mxa->heap);
3075772Sas200622 	free(mxa);
3087052Samw 	return (0);
3097052Samw }
3107052Samw 
3117052Samw /*
3128334SJose.Borrego@Sun.COM  * Must be called with ndr_pipe_lock held.
3137052Samw  */
3148334SJose.Borrego@Sun.COM static ndr_pipe_t *
3158334SJose.Borrego@Sun.COM ndr_pipe_lookup(int fid)
3167052Samw {
3178334SJose.Borrego@Sun.COM 	ndr_pipe_t *np;
3187052Samw 	int i;
3197052Samw 
3208334SJose.Borrego@Sun.COM 	for (i = 0; i < NDR_PIPE_MAX; ++i) {
3218334SJose.Borrego@Sun.COM 		np = &ndr_pipe_table[i];
3227052Samw 
3238334SJose.Borrego@Sun.COM 		if (np->np_fid == fid) {
3248334SJose.Borrego@Sun.COM 			if (np->np_refcnt == 0)
3257052Samw 				return (NULL);
3267052Samw 
3278334SJose.Borrego@Sun.COM 			np->np_refcnt++;
3288334SJose.Borrego@Sun.COM 			return (np);
3297052Samw 		}
3307052Samw 	}
3317052Samw 
3327052Samw 	return (NULL);
3335772Sas200622 }
3345772Sas200622 
3355772Sas200622 /*
3368334SJose.Borrego@Sun.COM  * Must be called with ndr_pipe_lock held.
3375772Sas200622  */
3387052Samw static void
3398334SJose.Borrego@Sun.COM ndr_pipe_release(ndr_pipe_t *np)
3405772Sas200622 {
3418334SJose.Borrego@Sun.COM 	np->np_refcnt--;
3428334SJose.Borrego@Sun.COM 	ndr_pipe_deallocate(np);
3437052Samw }
3447052Samw 
3457052Samw /*
3468334SJose.Borrego@Sun.COM  * Must be called with ndr_pipe_lock held.
3477052Samw  */
3488334SJose.Borrego@Sun.COM static ndr_pipe_t *
3498334SJose.Borrego@Sun.COM ndr_pipe_allocate(int fid)
3507052Samw {
3518334SJose.Borrego@Sun.COM 	ndr_pipe_t *np = NULL;
3525772Sas200622 	int i;
3535772Sas200622 
3548334SJose.Borrego@Sun.COM 	for (i = 0; i < NDR_PIPE_MAX; ++i) {
3558334SJose.Borrego@Sun.COM 		np = &ndr_pipe_table[i];
3565772Sas200622 
3578334SJose.Borrego@Sun.COM 		if (np->np_fid == 0) {
3588334SJose.Borrego@Sun.COM 			bzero(np, sizeof (ndr_pipe_t));
3595772Sas200622 
3608334SJose.Borrego@Sun.COM 			if ((np->np_buf = malloc(NDR_PIPE_BUFSZ)) == NULL)
3617052Samw 				return (NULL);
3625772Sas200622 
3638334SJose.Borrego@Sun.COM 			ndr_pipe_rewind(np);
3648334SJose.Borrego@Sun.COM 			np->np_fid = fid;
3658334SJose.Borrego@Sun.COM 			np->np_refcnt = 1;
3668334SJose.Borrego@Sun.COM 			return (np);
3675772Sas200622 		}
3685772Sas200622 	}
3695772Sas200622 
3707052Samw 	return (NULL);
3717052Samw }
3725772Sas200622 
3737052Samw /*
374*11963SAfshin.Ardakani@Sun.COM  * If the desired space exceeds the current pipe size, try to expand
375*11963SAfshin.Ardakani@Sun.COM  * the pipe.  Leave the current pipe intact if the realloc fails.
376*11963SAfshin.Ardakani@Sun.COM  *
377*11963SAfshin.Ardakani@Sun.COM  * Must be called with ndr_pipe_lock held.
378*11963SAfshin.Ardakani@Sun.COM  */
379*11963SAfshin.Ardakani@Sun.COM static int
380*11963SAfshin.Ardakani@Sun.COM ndr_pipe_grow(ndr_pipe_t *np, size_t desired)
381*11963SAfshin.Ardakani@Sun.COM {
382*11963SAfshin.Ardakani@Sun.COM 	char	*newbuf;
383*11963SAfshin.Ardakani@Sun.COM 	size_t	current;
384*11963SAfshin.Ardakani@Sun.COM 	size_t	required;
385*11963SAfshin.Ardakani@Sun.COM 
386*11963SAfshin.Ardakani@Sun.COM 	required = np->np_uio.uio_offset + desired;
387*11963SAfshin.Ardakani@Sun.COM 	current = np->np_uio.uio_offset + np->np_uio.uio_resid;
388*11963SAfshin.Ardakani@Sun.COM 
389*11963SAfshin.Ardakani@Sun.COM 	if (required <= current)
390*11963SAfshin.Ardakani@Sun.COM 		return (0);
391*11963SAfshin.Ardakani@Sun.COM 
392*11963SAfshin.Ardakani@Sun.COM 	if (required > NDR_PIPE_BUFMAX) {
393*11963SAfshin.Ardakani@Sun.COM 		smb_tracef("ndr_pipe_grow: required=%d, max=%d (ENOSPC)",
394*11963SAfshin.Ardakani@Sun.COM 		    required, NDR_PIPE_BUFMAX);
395*11963SAfshin.Ardakani@Sun.COM 		return (ENOSPC);
396*11963SAfshin.Ardakani@Sun.COM 	}
397*11963SAfshin.Ardakani@Sun.COM 
398*11963SAfshin.Ardakani@Sun.COM 	required = NDR_ALIGN_BUF(required);
399*11963SAfshin.Ardakani@Sun.COM 	if (required > NDR_PIPE_BUFMAX)
400*11963SAfshin.Ardakani@Sun.COM 		required = NDR_PIPE_BUFMAX;
401*11963SAfshin.Ardakani@Sun.COM 
402*11963SAfshin.Ardakani@Sun.COM 	if ((newbuf = realloc(np->np_buf, required)) == NULL) {
403*11963SAfshin.Ardakani@Sun.COM 		smb_tracef("ndr_pipe_grow: realloc failed (ENOMEM)");
404*11963SAfshin.Ardakani@Sun.COM 		return (ENOMEM);
405*11963SAfshin.Ardakani@Sun.COM 	}
406*11963SAfshin.Ardakani@Sun.COM 
407*11963SAfshin.Ardakani@Sun.COM 	np->np_buf = newbuf;
408*11963SAfshin.Ardakani@Sun.COM 	np->np_uio.uio_resid += desired;
409*11963SAfshin.Ardakani@Sun.COM 	np->np_iov.iov_len += desired;
410*11963SAfshin.Ardakani@Sun.COM 	smb_tracef("ndr_pipe_grow: %d bytes", required);
411*11963SAfshin.Ardakani@Sun.COM 	return (0);
412*11963SAfshin.Ardakani@Sun.COM }
413*11963SAfshin.Ardakani@Sun.COM 
414*11963SAfshin.Ardakani@Sun.COM /*
4158334SJose.Borrego@Sun.COM  * Must be called with ndr_pipe_lock held.
4167052Samw  */
4177052Samw static void
4188334SJose.Borrego@Sun.COM ndr_pipe_deallocate(ndr_pipe_t *np)
4197052Samw {
4208334SJose.Borrego@Sun.COM 	if (np->np_refcnt == 0) {
4217052Samw 		/*
4227052Samw 		 * Ensure that there are no RPC service policy handles
4237052Samw 		 * (associated with this fid) left around.
4247052Samw 		 */
4258334SJose.Borrego@Sun.COM 		ndr_hdclose(np->np_fid);
4265772Sas200622 
4278334SJose.Borrego@Sun.COM 		ndr_pipe_rewind(np);
4288334SJose.Borrego@Sun.COM 		ndr_pipe_flush(np);
4298334SJose.Borrego@Sun.COM 		free(np->np_buf);
43010122SJordan.Brown@Sun.COM 		free(np->np_user.ui_domain);
43110122SJordan.Brown@Sun.COM 		free(np->np_user.ui_account);
43210122SJordan.Brown@Sun.COM 		free(np->np_user.ui_workstation);
4338334SJose.Borrego@Sun.COM 		bzero(np, sizeof (ndr_pipe_t));
4347052Samw 	}
4357052Samw }
4365772Sas200622 
4377052Samw /*
4387052Samw  * Rewind the input data stream, ready for the next write.
4397052Samw  */
4407052Samw static void
4418334SJose.Borrego@Sun.COM ndr_pipe_rewind(ndr_pipe_t *np)
4427052Samw {
4438334SJose.Borrego@Sun.COM 	np->np_uio.uio_iov = &np->np_iov;
4448334SJose.Borrego@Sun.COM 	np->np_uio.uio_iovcnt = 1;
4458334SJose.Borrego@Sun.COM 	np->np_uio.uio_offset = 0;
4468334SJose.Borrego@Sun.COM 	np->np_uio.uio_segflg = UIO_USERSPACE;
4478334SJose.Borrego@Sun.COM 	np->np_uio.uio_resid = NDR_PIPE_BUFSZ;
4488334SJose.Borrego@Sun.COM 	np->np_iov.iov_base = np->np_buf;
4498334SJose.Borrego@Sun.COM 	np->np_iov.iov_len = NDR_PIPE_BUFSZ;
4505772Sas200622 }
4515772Sas200622 
4525772Sas200622 /*
4537052Samw  * Flush the output data stream.
4545772Sas200622  */
4557052Samw static void
4568334SJose.Borrego@Sun.COM ndr_pipe_flush(ndr_pipe_t *np)
4575772Sas200622 {
4587052Samw 	ndr_frag_t *frag;
4595772Sas200622 
4608334SJose.Borrego@Sun.COM 	while ((frag = np->np_frags.head) != NULL) {
4618334SJose.Borrego@Sun.COM 		np->np_frags.head = frag->next;
4627052Samw 		free(frag);
4635772Sas200622 	}
4645772Sas200622 
4658334SJose.Borrego@Sun.COM 	free(np->np_frags.iov);
4668334SJose.Borrego@Sun.COM 	bzero(&np->np_frags, sizeof (ndr_fraglist_t));
4677052Samw }
4687052Samw 
4697052Samw /*
4707052Samw  * Check whether or not the specified user has administrator privileges,
4717052Samw  * i.e. is a member of Domain Admins or Administrators.
4727052Samw  * Returns true if the user is an administrator, otherwise returns false.
4737052Samw  */
4747052Samw boolean_t
4757052Samw ndr_is_admin(ndr_xa_t *xa)
4767052Samw {
47710122SJordan.Brown@Sun.COM 	smb_netuserinfo_t *ctx = &xa->pipe->np_user;
4787052Samw 
47910122SJordan.Brown@Sun.COM 	return (ctx->ui_flags & SMB_ATF_ADMIN);
4807052Samw }
4817052Samw 
4827052Samw /*
4837052Samw  * Check whether or not the specified user has power-user privileges,
4847052Samw  * i.e. is a member of Domain Admins, Administrators or Power Users.
4857052Samw  * This is typically required for operations such as managing shares.
4867052Samw  * Returns true if the user is a power user, otherwise returns false.
4877052Samw  */
4887052Samw boolean_t
4897052Samw ndr_is_poweruser(ndr_xa_t *xa)
4907052Samw {
49110122SJordan.Brown@Sun.COM 	smb_netuserinfo_t *ctx = &xa->pipe->np_user;
4927052Samw 
49310122SJordan.Brown@Sun.COM 	return ((ctx->ui_flags & SMB_ATF_ADMIN) ||
49410122SJordan.Brown@Sun.COM 	    (ctx->ui_flags & SMB_ATF_POWERUSER));
4957052Samw }
4967052Samw 
4977052Samw int32_t
4987052Samw ndr_native_os(ndr_xa_t *xa)
4997052Samw {
50010122SJordan.Brown@Sun.COM 	smb_netuserinfo_t *ctx = &xa->pipe->np_user;
5017052Samw 
50210122SJordan.Brown@Sun.COM 	return (ctx->ui_native_os);
5035772Sas200622 }
5045772Sas200622 
5055772Sas200622 /*
5065772Sas200622  * This is the entry point for all server-side RPC processing.
5075772Sas200622  * It is assumed that the PDU has already been received.
5085772Sas200622  */
5095772Sas200622 static int
5108334SJose.Borrego@Sun.COM ndr_svc_process(ndr_xa_t *mxa)
5115772Sas200622 {
512*11963SAfshin.Ardakani@Sun.COM 	ndr_common_header_t	*hdr = &mxa->recv_hdr.common_hdr;
513*11963SAfshin.Ardakani@Sun.COM 	ndr_stream_t		*nds = &mxa->recv_nds;
514*11963SAfshin.Ardakani@Sun.COM 	unsigned long		saved_offset;
515*11963SAfshin.Ardakani@Sun.COM 	unsigned long		saved_size;
516*11963SAfshin.Ardakani@Sun.COM 	int			rc;
5175772Sas200622 
5188334SJose.Borrego@Sun.COM 	rc = ndr_decode_pdu_hdr(mxa);
5198334SJose.Borrego@Sun.COM 	if (!NDR_DRC_IS_OK(rc))
5205772Sas200622 		return (-1);
5215772Sas200622 
5228334SJose.Borrego@Sun.COM 	(void) ndr_reply_prepare_hdr(mxa);
5235772Sas200622 
5245772Sas200622 	switch (mxa->ptype) {
5258334SJose.Borrego@Sun.COM 	case NDR_PTYPE_BIND:
5268334SJose.Borrego@Sun.COM 		rc = ndr_svc_bind(mxa);
5275772Sas200622 		break;
5285772Sas200622 
5298334SJose.Borrego@Sun.COM 	case NDR_PTYPE_REQUEST:
530*11963SAfshin.Ardakani@Sun.COM 		if (!NDR_IS_FIRST_FRAG(hdr->pfc_flags)) {
531*11963SAfshin.Ardakani@Sun.COM 			ndr_show_hdr(hdr);
532*11963SAfshin.Ardakani@Sun.COM 			rc = NDR_DRC_FAULT_DECODE_FAILED;
533*11963SAfshin.Ardakani@Sun.COM 			goto ndr_svc_process_fault;
534*11963SAfshin.Ardakani@Sun.COM 		}
535*11963SAfshin.Ardakani@Sun.COM 
536*11963SAfshin.Ardakani@Sun.COM 		if (!NDR_IS_LAST_FRAG(hdr->pfc_flags)) {
537*11963SAfshin.Ardakani@Sun.COM 			/*
538*11963SAfshin.Ardakani@Sun.COM 			 * Multi-fragment request.  Preserve the PDU scan
539*11963SAfshin.Ardakani@Sun.COM 			 * offset and size during defrag so that we can
540*11963SAfshin.Ardakani@Sun.COM 			 * continue as if we had received contiguous data.
541*11963SAfshin.Ardakani@Sun.COM 			 */
542*11963SAfshin.Ardakani@Sun.COM 			saved_offset = nds->pdu_scan_offset;
543*11963SAfshin.Ardakani@Sun.COM 			saved_size = nds->pdu_size;
544*11963SAfshin.Ardakani@Sun.COM 
545*11963SAfshin.Ardakani@Sun.COM 			nds->pdu_scan_offset = hdr->frag_length;
546*11963SAfshin.Ardakani@Sun.COM 			nds->pdu_size = nds->pdu_max_size;
547*11963SAfshin.Ardakani@Sun.COM 
548*11963SAfshin.Ardakani@Sun.COM 			rc = ndr_svc_defrag(mxa);
549*11963SAfshin.Ardakani@Sun.COM 			if (NDR_DRC_IS_FAULT(rc)) {
550*11963SAfshin.Ardakani@Sun.COM 				ndr_show_hdr(hdr);
551*11963SAfshin.Ardakani@Sun.COM 				nds_show_state(nds);
552*11963SAfshin.Ardakani@Sun.COM 				goto ndr_svc_process_fault;
553*11963SAfshin.Ardakani@Sun.COM 			}
554*11963SAfshin.Ardakani@Sun.COM 
555*11963SAfshin.Ardakani@Sun.COM 			nds->pdu_scan_offset = saved_offset;
556*11963SAfshin.Ardakani@Sun.COM 			nds->pdu_size = saved_size;
557*11963SAfshin.Ardakani@Sun.COM 		}
558*11963SAfshin.Ardakani@Sun.COM 
5598334SJose.Borrego@Sun.COM 		rc = ndr_svc_request(mxa);
5605772Sas200622 		break;
5615772Sas200622 
5628334SJose.Borrego@Sun.COM 	case NDR_PTYPE_ALTER_CONTEXT:
5638334SJose.Borrego@Sun.COM 		rc = ndr_svc_alter_context(mxa);
5645772Sas200622 		break;
5655772Sas200622 
5665772Sas200622 	default:
5678334SJose.Borrego@Sun.COM 		rc = NDR_DRC_FAULT_RPCHDR_PTYPE_INVALID;
5685772Sas200622 		break;
5695772Sas200622 	}
5705772Sas200622 
571*11963SAfshin.Ardakani@Sun.COM ndr_svc_process_fault:
5728334SJose.Borrego@Sun.COM 	if (NDR_DRC_IS_FAULT(rc))
5738334SJose.Borrego@Sun.COM 		ndr_reply_fault(mxa, rc);
5745772Sas200622 
5758334SJose.Borrego@Sun.COM 	(void) ndr_build_reply(mxa);
5765772Sas200622 	return (rc);
5775772Sas200622 }
5785772Sas200622 
5795772Sas200622 /*
580*11963SAfshin.Ardakani@Sun.COM  * Remove RPC fragment headers from the received data stream.
581*11963SAfshin.Ardakani@Sun.COM  * The first fragment has already been accounted for before this call.
582*11963SAfshin.Ardakani@Sun.COM  *
583*11963SAfshin.Ardakani@Sun.COM  * NDR stream on entry:
584*11963SAfshin.Ardakani@Sun.COM  *
585*11963SAfshin.Ardakani@Sun.COM  * |<-- frag 2 -->|<-- frag 3 -->| ... |<- last frag ->|
586*11963SAfshin.Ardakani@Sun.COM  *
587*11963SAfshin.Ardakani@Sun.COM  * +-----+--------+-----+--------+-----+-----+---------+
588*11963SAfshin.Ardakani@Sun.COM  * | hdr |  data  | hdr |  data  | ... | hdr |  data   |
589*11963SAfshin.Ardakani@Sun.COM  * +-----+--------+-----+--------+-----+-----+---------+
590*11963SAfshin.Ardakani@Sun.COM  *
591*11963SAfshin.Ardakani@Sun.COM  * NDR stream on return:
592*11963SAfshin.Ardakani@Sun.COM  *
593*11963SAfshin.Ardakani@Sun.COM  * +----------------------------------+
594*11963SAfshin.Ardakani@Sun.COM  * |               data               |
595*11963SAfshin.Ardakani@Sun.COM  * +----------------------------------+
596*11963SAfshin.Ardakani@Sun.COM  */
597*11963SAfshin.Ardakani@Sun.COM static int
598*11963SAfshin.Ardakani@Sun.COM ndr_svc_defrag(ndr_xa_t *mxa)
599*11963SAfshin.Ardakani@Sun.COM {
600*11963SAfshin.Ardakani@Sun.COM 	ndr_stream_t		*nds = &mxa->recv_nds;
601*11963SAfshin.Ardakani@Sun.COM 	ndr_common_header_t	frag_hdr;
602*11963SAfshin.Ardakani@Sun.COM 	int			frag_size;
603*11963SAfshin.Ardakani@Sun.COM 	int			last_frag;
604*11963SAfshin.Ardakani@Sun.COM 
605*11963SAfshin.Ardakani@Sun.COM 	do {
606*11963SAfshin.Ardakani@Sun.COM 		ndr_decode_frag_hdr(nds, &frag_hdr);
607*11963SAfshin.Ardakani@Sun.COM 		ndr_show_hdr(&frag_hdr);
608*11963SAfshin.Ardakani@Sun.COM 
609*11963SAfshin.Ardakani@Sun.COM 		if (NDR_IS_FIRST_FRAG(frag_hdr.pfc_flags))
610*11963SAfshin.Ardakani@Sun.COM 			return (NDR_DRC_FAULT_DECODE_FAILED);
611*11963SAfshin.Ardakani@Sun.COM 
612*11963SAfshin.Ardakani@Sun.COM 		last_frag = NDR_IS_LAST_FRAG(frag_hdr.pfc_flags);
613*11963SAfshin.Ardakani@Sun.COM 		frag_size = frag_hdr.frag_length;
614*11963SAfshin.Ardakani@Sun.COM 
615*11963SAfshin.Ardakani@Sun.COM 		if (frag_size > (nds->pdu_size - nds->pdu_scan_offset))
616*11963SAfshin.Ardakani@Sun.COM 			return (NDR_DRC_FAULT_DECODE_FAILED);
617*11963SAfshin.Ardakani@Sun.COM 
618*11963SAfshin.Ardakani@Sun.COM 		ndr_remove_frag_hdr(nds);
619*11963SAfshin.Ardakani@Sun.COM 		nds->pdu_scan_offset += frag_size - NDR_RSP_HDR_SIZE;
620*11963SAfshin.Ardakani@Sun.COM 	} while (!last_frag);
621*11963SAfshin.Ardakani@Sun.COM 
622*11963SAfshin.Ardakani@Sun.COM 	return (NDR_DRC_OK);
623*11963SAfshin.Ardakani@Sun.COM }
624*11963SAfshin.Ardakani@Sun.COM 
625*11963SAfshin.Ardakani@Sun.COM /*
6265772Sas200622  * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple
6275772Sas200622  * p_results[] not supported.
6285772Sas200622  */
6295772Sas200622 static int
6308334SJose.Borrego@Sun.COM ndr_svc_bind(ndr_xa_t *mxa)
6315772Sas200622 {
6328334SJose.Borrego@Sun.COM 	ndr_p_cont_list_t	*cont_list;
6338334SJose.Borrego@Sun.COM 	ndr_p_result_list_t	*result_list;
6348334SJose.Borrego@Sun.COM 	ndr_p_result_t		*result;
6355772Sas200622 	unsigned		p_cont_id;
6368334SJose.Borrego@Sun.COM 	ndr_binding_t		*mbind;
6375772Sas200622 	ndr_uuid_t		*as_uuid;
6385772Sas200622 	ndr_uuid_t		*ts_uuid;
6395772Sas200622 	int			as_vers;
6405772Sas200622 	int			ts_vers;
6418334SJose.Borrego@Sun.COM 	ndr_service_t		*msvc;
6425772Sas200622 	int			rc;
6438334SJose.Borrego@Sun.COM 	ndr_port_any_t		*sec_addr;
6445772Sas200622 
6455772Sas200622 	/* acquire targets */
6465772Sas200622 	cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem;
6475772Sas200622 	result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list;
6485772Sas200622 	result = &result_list->p_results[0];
6495772Sas200622 
6505772Sas200622 	/*
6515772Sas200622 	 * Set up temporary secondary address port.
6525772Sas200622 	 * We will correct this later (below).
6535772Sas200622 	 */
6545772Sas200622 	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
6555772Sas200622 	sec_addr->length = 13;
6565772Sas200622 	(void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs");
6575772Sas200622 
6585772Sas200622 	result_list->n_results = 1;
6595772Sas200622 	result_list->reserved = 0;
6605772Sas200622 	result_list->reserved2 = 0;
6618334SJose.Borrego@Sun.COM 	result->result = NDR_PCDR_ACCEPTANCE;
6625772Sas200622 	result->reason = 0;
6635772Sas200622 	bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
6645772Sas200622 
6655772Sas200622 	/* sanity check */
6665772Sas200622 	if (cont_list->n_context_elem != 1 ||
6675772Sas200622 	    cont_list->p_cont_elem[0].n_transfer_syn != 1) {
6688334SJose.Borrego@Sun.COM 		ndo_trace("ndr_svc_bind: warning: multiple p_cont_elem");
6695772Sas200622 	}
6705772Sas200622 
6715772Sas200622 	p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
6725772Sas200622 
6738334SJose.Borrego@Sun.COM 	if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) != NULL) {
6745772Sas200622 		/*
6758334SJose.Borrego@Sun.COM 		 * Duplicate presentation context id.
6765772Sas200622 		 */
6778334SJose.Borrego@Sun.COM 		ndo_trace("ndr_svc_bind: duplicate binding");
6788334SJose.Borrego@Sun.COM 		return (NDR_DRC_FAULT_BIND_PCONT_BUSY);
6795772Sas200622 	}
6805772Sas200622 
6818334SJose.Borrego@Sun.COM 	if ((mbind = ndr_svc_new_binding(mxa)) == NULL) {
6825772Sas200622 		/*
6835772Sas200622 		 * No free binding slot
6845772Sas200622 		 */
6858334SJose.Borrego@Sun.COM 		result->result = NDR_PCDR_PROVIDER_REJECTION;
6868334SJose.Borrego@Sun.COM 		result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED;
6878334SJose.Borrego@Sun.COM 		ndo_trace("ndr_svc_bind: no resources");
6888334SJose.Borrego@Sun.COM 		return (NDR_DRC_OK);
6895772Sas200622 	}
6905772Sas200622 
6915772Sas200622 	as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
6925772Sas200622 	as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
6935772Sas200622 
6945772Sas200622 	ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
6955772Sas200622 	ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
6965772Sas200622 
6978334SJose.Borrego@Sun.COM 	msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers);
6988334SJose.Borrego@Sun.COM 	if (msvc == NULL) {
6998334SJose.Borrego@Sun.COM 		result->result = NDR_PCDR_PROVIDER_REJECTION;
7008334SJose.Borrego@Sun.COM 		result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
7018334SJose.Borrego@Sun.COM 		return (NDR_DRC_OK);
7025772Sas200622 	}
7035772Sas200622 
7045772Sas200622 	/*
7055772Sas200622 	 * We can now use the correct secondary address port.
7065772Sas200622 	 */
7075772Sas200622 	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
7085772Sas200622 	sec_addr->length = strlen(msvc->sec_addr_port) + 1;
7095772Sas200622 	(void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port,
7108334SJose.Borrego@Sun.COM 	    NDR_PORT_ANY_MAX_PORT_SPEC);
7115772Sas200622 
7125772Sas200622 	mbind->p_cont_id = p_cont_id;
7138334SJose.Borrego@Sun.COM 	mbind->which_side = NDR_BIND_SIDE_SERVER;
7145772Sas200622 	/* mbind->context set by app */
7155772Sas200622 	mbind->service = msvc;
7165772Sas200622 	mbind->instance_specific = 0;
7175772Sas200622 
7185772Sas200622 	mxa->binding = mbind;
7195772Sas200622 
7205772Sas200622 	if (msvc->bind_req) {
7215772Sas200622 		/*
7225772Sas200622 		 * Call the service-specific bind() handler.  If
7235772Sas200622 		 * this fails, we shouild send a specific error
7245772Sas200622 		 * on the bind ack.
7255772Sas200622 		 */
7265772Sas200622 		rc = (msvc->bind_req)(mxa);
7278334SJose.Borrego@Sun.COM 		if (NDR_DRC_IS_FAULT(rc)) {
7285772Sas200622 			mbind->service = 0;	/* free binding slot */
7295772Sas200622 			mbind->which_side = 0;
7305772Sas200622 			mbind->p_cont_id = 0;
7315772Sas200622 			mbind->instance_specific = 0;
7325772Sas200622 			return (rc);
7335772Sas200622 		}
7345772Sas200622 	}
7355772Sas200622 
7365772Sas200622 	result->transfer_syntax =
7375772Sas200622 	    cont_list->p_cont_elem[0].transfer_syntaxes[0];
7385772Sas200622 
7398334SJose.Borrego@Sun.COM 	return (NDR_DRC_BINDING_MADE);
7405772Sas200622 }
7415772Sas200622 
7425772Sas200622 /*
7438334SJose.Borrego@Sun.COM  * ndr_svc_alter_context
7445772Sas200622  *
7455772Sas200622  * The alter context request is used to request additional presentation
7467619SJose.Borrego@Sun.COM  * context for another interface and/or version.  It is very similar to
7477619SJose.Borrego@Sun.COM  * a bind request.
7485772Sas200622  */
7495772Sas200622 static int
7508334SJose.Borrego@Sun.COM ndr_svc_alter_context(ndr_xa_t *mxa)
7515772Sas200622 {
7528334SJose.Borrego@Sun.COM 	ndr_p_result_list_t *result_list;
7538334SJose.Borrego@Sun.COM 	ndr_p_result_t *result;
7548334SJose.Borrego@Sun.COM 	ndr_p_cont_list_t *cont_list;
7558334SJose.Borrego@Sun.COM 	ndr_binding_t *mbind;
7568334SJose.Borrego@Sun.COM 	ndr_service_t *msvc;
7575772Sas200622 	unsigned p_cont_id;
7585772Sas200622 	ndr_uuid_t *as_uuid;
7595772Sas200622 	ndr_uuid_t *ts_uuid;
7605772Sas200622 	int as_vers;
7615772Sas200622 	int ts_vers;
7628334SJose.Borrego@Sun.COM 	ndr_port_any_t *sec_addr;
7635772Sas200622 
7647619SJose.Borrego@Sun.COM 	result_list = &mxa->send_hdr.alter_context_rsp_hdr.p_result_list;
7655772Sas200622 	result_list->n_results = 1;
7665772Sas200622 	result_list->reserved = 0;
7675772Sas200622 	result_list->reserved2 = 0;
7685772Sas200622 
7695772Sas200622 	result = &result_list->p_results[0];
7708334SJose.Borrego@Sun.COM 	result->result = NDR_PCDR_ACCEPTANCE;
7715772Sas200622 	result->reason = 0;
7725772Sas200622 	bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
7735772Sas200622 
7747619SJose.Borrego@Sun.COM 	cont_list = &mxa->recv_hdr.alter_context_hdr.p_context_elem;
7755772Sas200622 	p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
7765772Sas200622 
7778334SJose.Borrego@Sun.COM 	if (ndr_svc_find_binding(mxa, p_cont_id) != NULL)
7788334SJose.Borrego@Sun.COM 		return (NDR_DRC_FAULT_BIND_PCONT_BUSY);
7795772Sas200622 
7808334SJose.Borrego@Sun.COM 	if ((mbind = ndr_svc_new_binding(mxa)) == NULL) {
7818334SJose.Borrego@Sun.COM 		result->result = NDR_PCDR_PROVIDER_REJECTION;
7828334SJose.Borrego@Sun.COM 		result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED;
7838334SJose.Borrego@Sun.COM 		return (NDR_DRC_OK);
7845772Sas200622 	}
7855772Sas200622 
7865772Sas200622 	as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
7875772Sas200622 	as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
7885772Sas200622 
7895772Sas200622 	ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
7905772Sas200622 	ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
7915772Sas200622 
7928334SJose.Borrego@Sun.COM 	msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers);
7938334SJose.Borrego@Sun.COM 	if (msvc == NULL) {
7948334SJose.Borrego@Sun.COM 		result->result = NDR_PCDR_PROVIDER_REJECTION;
7958334SJose.Borrego@Sun.COM 		result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
7968334SJose.Borrego@Sun.COM 		return (NDR_DRC_OK);
7975772Sas200622 	}
7985772Sas200622 
7995772Sas200622 	mbind->p_cont_id = p_cont_id;
8008334SJose.Borrego@Sun.COM 	mbind->which_side = NDR_BIND_SIDE_SERVER;
8015772Sas200622 	/* mbind->context set by app */
8025772Sas200622 	mbind->service = msvc;
8035772Sas200622 	mbind->instance_specific = 0;
8045772Sas200622 	mxa->binding = mbind;
8055772Sas200622 
8067619SJose.Borrego@Sun.COM 	sec_addr = &mxa->send_hdr.alter_context_rsp_hdr.sec_addr;
8075772Sas200622 	sec_addr->length = 0;
8088334SJose.Borrego@Sun.COM 	bzero(sec_addr->port_spec, NDR_PORT_ANY_MAX_PORT_SPEC);
8095772Sas200622 
8105772Sas200622 	result->transfer_syntax =
8115772Sas200622 	    cont_list->p_cont_elem[0].transfer_syntaxes[0];
8125772Sas200622 
8138334SJose.Borrego@Sun.COM 	return (NDR_DRC_BINDING_MADE);
8145772Sas200622 }
8155772Sas200622 
8165772Sas200622 static int
8178334SJose.Borrego@Sun.COM ndr_svc_request(ndr_xa_t *mxa)
8185772Sas200622 {
8198334SJose.Borrego@Sun.COM 	ndr_binding_t	*mbind;
8208334SJose.Borrego@Sun.COM 	ndr_service_t	*msvc;
8218334SJose.Borrego@Sun.COM 	unsigned	p_cont_id;
8228334SJose.Borrego@Sun.COM 	int		rc;
8235772Sas200622 
8245772Sas200622 	mxa->opnum = mxa->recv_hdr.request_hdr.opnum;
8255772Sas200622 	p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id;
8265772Sas200622 
8278334SJose.Borrego@Sun.COM 	if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) == NULL)
8288334SJose.Borrego@Sun.COM 		return (NDR_DRC_FAULT_REQUEST_PCONT_INVALID);
8295772Sas200622 
8305772Sas200622 	mxa->binding = mbind;
8315772Sas200622 	msvc = mbind->service;
8325772Sas200622 
8335772Sas200622 	/*
8345772Sas200622 	 * Make room for the response hdr.
8355772Sas200622 	 */
8368334SJose.Borrego@Sun.COM 	mxa->send_nds.pdu_scan_offset = NDR_RSP_HDR_SIZE;
8375772Sas200622 
8385772Sas200622 	if (msvc->call_stub)
8395772Sas200622 		rc = (*msvc->call_stub)(mxa);
8405772Sas200622 	else
8418334SJose.Borrego@Sun.COM 		rc = ndr_generic_call_stub(mxa);
8425772Sas200622 
8438334SJose.Borrego@Sun.COM 	if (NDR_DRC_IS_FAULT(rc)) {
8448334SJose.Borrego@Sun.COM 		ndo_printf(0, 0, "%s[0x%02x]: 0x%04x",
8455772Sas200622 		    msvc->name, mxa->opnum, rc);
8465772Sas200622 	}
8475772Sas200622 
8485772Sas200622 	return (rc);
8495772Sas200622 }
8505772Sas200622 
8515772Sas200622 /*
8528334SJose.Borrego@Sun.COM  * The transaction and the two nds streams use the same heap, which
8535772Sas200622  * should already exist at this point.  The heap will also be available
8545772Sas200622  * to the stub.
8555772Sas200622  */
8565772Sas200622 int
8578334SJose.Borrego@Sun.COM ndr_generic_call_stub(ndr_xa_t *mxa)
8585772Sas200622 {
8598334SJose.Borrego@Sun.COM 	ndr_binding_t 		*mbind = mxa->binding;
8608334SJose.Borrego@Sun.COM 	ndr_service_t		*msvc = mbind->service;
8618334SJose.Borrego@Sun.COM 	ndr_typeinfo_t		*intf_ti = msvc->interface_ti;
8628334SJose.Borrego@Sun.COM 	ndr_stub_table_t	*ste;
8635772Sas200622 	int			opnum = mxa->opnum;
8645772Sas200622 	unsigned		p_len = intf_ti->c_size_fixed_part;
8655772Sas200622 	char 			*param;
8665772Sas200622 	int			rc;
8675772Sas200622 
8685772Sas200622 	if (mxa->heap == NULL) {
8698334SJose.Borrego@Sun.COM 		ndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum);
8708334SJose.Borrego@Sun.COM 		return (NDR_DRC_FAULT_OUT_OF_MEMORY);
8715772Sas200622 	}
8725772Sas200622 
8738334SJose.Borrego@Sun.COM 	if ((ste = ndr_svc_find_stub(msvc, opnum)) == NULL) {
8748334SJose.Borrego@Sun.COM 		ndo_printf(0, 0, "%s[0x%02x]: invalid opnum",
8755772Sas200622 		    msvc->name, opnum);
8768334SJose.Borrego@Sun.COM 		return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID);
8775772Sas200622 	}
8785772Sas200622 
8798334SJose.Borrego@Sun.COM 	if ((param = ndr_heap_malloc(mxa->heap, p_len)) == NULL)
8808334SJose.Borrego@Sun.COM 		return (NDR_DRC_FAULT_OUT_OF_MEMORY);
8815772Sas200622 
8825772Sas200622 	bzero(param, p_len);
8835772Sas200622 
8848334SJose.Borrego@Sun.COM 	rc = ndr_decode_call(mxa, param);
8858334SJose.Borrego@Sun.COM 	if (!NDR_DRC_IS_OK(rc))
8865772Sas200622 		return (rc);
8875772Sas200622 
8885772Sas200622 	rc = (*ste->func)(param, mxa);
8898334SJose.Borrego@Sun.COM 	if (rc == NDR_DRC_OK)
8908334SJose.Borrego@Sun.COM 		rc = ndr_encode_return(mxa, param);
8915772Sas200622 
8925772Sas200622 	return (rc);
8935772Sas200622 }
8945772Sas200622 
8955772Sas200622 /*
8965772Sas200622  * We can perform some initial setup of the response header here.
8975772Sas200622  * We also need to cache some of the information from the bind
8985772Sas200622  * negotiation for use during subsequent RPC calls.
8995772Sas200622  */
9005772Sas200622 static void
9018334SJose.Borrego@Sun.COM ndr_reply_prepare_hdr(ndr_xa_t *mxa)
9025772Sas200622 {
9037619SJose.Borrego@Sun.COM 	ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
9047619SJose.Borrego@Sun.COM 	ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
9055772Sas200622 
9065772Sas200622 	hdr->rpc_vers = 5;
9075772Sas200622 	hdr->rpc_vers_minor = 0;
9088334SJose.Borrego@Sun.COM 	hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG;
9095772Sas200622 	hdr->packed_drep = rhdr->packed_drep;
9105772Sas200622 	hdr->frag_length = 0;
9115772Sas200622 	hdr->auth_length = 0;
9125772Sas200622 	hdr->call_id = rhdr->call_id;
9135772Sas200622 #ifdef _BIG_ENDIAN
9148334SJose.Borrego@Sun.COM 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
9158334SJose.Borrego@Sun.COM 	    | NDR_REPLAB_INTG_BIG_ENDIAN;
9165772Sas200622 #else
9178334SJose.Borrego@Sun.COM 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
9188334SJose.Borrego@Sun.COM 	    | NDR_REPLAB_INTG_LITTLE_ENDIAN;
9195772Sas200622 #endif
9205772Sas200622 
9215772Sas200622 	switch (mxa->ptype) {
9228334SJose.Borrego@Sun.COM 	case NDR_PTYPE_BIND:
9238334SJose.Borrego@Sun.COM 		hdr->ptype = NDR_PTYPE_BIND_ACK;
9245772Sas200622 		mxa->send_hdr.bind_ack_hdr.max_xmit_frag =
9255772Sas200622 		    mxa->recv_hdr.bind_hdr.max_xmit_frag;
9265772Sas200622 		mxa->send_hdr.bind_ack_hdr.max_recv_frag =
9275772Sas200622 		    mxa->recv_hdr.bind_hdr.max_recv_frag;
9285772Sas200622 		mxa->send_hdr.bind_ack_hdr.assoc_group_id =
9295772Sas200622 		    mxa->recv_hdr.bind_hdr.assoc_group_id;
9305772Sas200622 
9315772Sas200622 		if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0)
9325772Sas200622 			mxa->send_hdr.bind_ack_hdr.assoc_group_id = time(0);
9335772Sas200622 
9345772Sas200622 		/*
9355772Sas200622 		 * Save the maximum fragment sizes
9365772Sas200622 		 * for use with subsequent requests.
9375772Sas200622 		 */
9388334SJose.Borrego@Sun.COM 		mxa->pipe->np_max_xmit_frag =
9395772Sas200622 		    mxa->recv_hdr.bind_hdr.max_xmit_frag;
9408334SJose.Borrego@Sun.COM 		mxa->pipe->np_max_recv_frag =
9415772Sas200622 		    mxa->recv_hdr.bind_hdr.max_recv_frag;
9425772Sas200622 		break;
9435772Sas200622 
9448334SJose.Borrego@Sun.COM 	case NDR_PTYPE_REQUEST:
9458334SJose.Borrego@Sun.COM 		hdr->ptype = NDR_PTYPE_RESPONSE;
9465772Sas200622 		/* mxa->send_hdr.response_hdr.alloc_hint */
9475772Sas200622 		mxa->send_hdr.response_hdr.p_cont_id =
9485772Sas200622 		    mxa->recv_hdr.request_hdr.p_cont_id;
9495772Sas200622 		mxa->send_hdr.response_hdr.cancel_count = 0;
9505772Sas200622 		mxa->send_hdr.response_hdr.reserved = 0;
9515772Sas200622 		break;
9525772Sas200622 
9538334SJose.Borrego@Sun.COM 	case NDR_PTYPE_ALTER_CONTEXT:
9548334SJose.Borrego@Sun.COM 		hdr->ptype = NDR_PTYPE_ALTER_CONTEXT_RESP;
9555772Sas200622 		/*
9567619SJose.Borrego@Sun.COM 		 * The max_xmit_frag, max_recv_frag and assoc_group_id are
9577619SJose.Borrego@Sun.COM 		 * ignored by the client but it's useful to fill them in.
9585772Sas200622 		 */
9597619SJose.Borrego@Sun.COM 		mxa->send_hdr.alter_context_rsp_hdr.max_xmit_frag =
9607619SJose.Borrego@Sun.COM 		    mxa->recv_hdr.alter_context_hdr.max_xmit_frag;
9617619SJose.Borrego@Sun.COM 		mxa->send_hdr.alter_context_rsp_hdr.max_recv_frag =
9627619SJose.Borrego@Sun.COM 		    mxa->recv_hdr.alter_context_hdr.max_recv_frag;
9637619SJose.Borrego@Sun.COM 		mxa->send_hdr.alter_context_rsp_hdr.assoc_group_id =
9647619SJose.Borrego@Sun.COM 		    mxa->recv_hdr.alter_context_hdr.assoc_group_id;
9655772Sas200622 		break;
9665772Sas200622 
9675772Sas200622 	default:
9685772Sas200622 		hdr->ptype = 0xFF;
9695772Sas200622 	}
9705772Sas200622 }
9715772Sas200622 
9725772Sas200622 /*
9735772Sas200622  * Signal an RPC fault. The stream is reset and we overwrite whatever
9745772Sas200622  * was in the response header with the fault information.
9755772Sas200622  */
9765772Sas200622 static void
9778334SJose.Borrego@Sun.COM ndr_reply_fault(ndr_xa_t *mxa, unsigned long drc)
9785772Sas200622 {
9797619SJose.Borrego@Sun.COM 	ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
9807619SJose.Borrego@Sun.COM 	ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
9818334SJose.Borrego@Sun.COM 	ndr_stream_t *nds = &mxa->send_nds;
9825772Sas200622 	unsigned long fault_status;
9835772Sas200622 
9848334SJose.Borrego@Sun.COM 	NDS_RESET(nds);
9855772Sas200622 
9865772Sas200622 	hdr->rpc_vers = 5;
9875772Sas200622 	hdr->rpc_vers_minor = 0;
9888334SJose.Borrego@Sun.COM 	hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG;
9895772Sas200622 	hdr->packed_drep = rhdr->packed_drep;
9905772Sas200622 	hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr);
9915772Sas200622 	hdr->auth_length = 0;
9925772Sas200622 	hdr->call_id = rhdr->call_id;
9935772Sas200622 #ifdef _BIG_ENDIAN
9948334SJose.Borrego@Sun.COM 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
9958334SJose.Borrego@Sun.COM 	    | NDR_REPLAB_INTG_BIG_ENDIAN;
9965772Sas200622 #else
9978334SJose.Borrego@Sun.COM 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
9988334SJose.Borrego@Sun.COM 	    | NDR_REPLAB_INTG_LITTLE_ENDIAN;
9995772Sas200622 #endif
10005772Sas200622 
10018334SJose.Borrego@Sun.COM 	switch (drc & NDR_DRC_MASK_SPECIFIER) {
10028334SJose.Borrego@Sun.COM 	case NDR_DRC_FAULT_OUT_OF_MEMORY:
10038334SJose.Borrego@Sun.COM 	case NDR_DRC_FAULT_ENCODE_TOO_BIG:
10048334SJose.Borrego@Sun.COM 		fault_status = NDR_FAULT_NCA_OUT_ARGS_TOO_BIG;
10055772Sas200622 		break;
10065772Sas200622 
10078334SJose.Borrego@Sun.COM 	case NDR_DRC_FAULT_REQUEST_PCONT_INVALID:
10088334SJose.Borrego@Sun.COM 		fault_status = NDR_FAULT_NCA_INVALID_PRES_CONTEXT_ID;
10095772Sas200622 		break;
10105772Sas200622 
10118334SJose.Borrego@Sun.COM 	case NDR_DRC_FAULT_REQUEST_OPNUM_INVALID:
10128334SJose.Borrego@Sun.COM 		fault_status = NDR_FAULT_NCA_OP_RNG_ERROR;
10135772Sas200622 		break;
10145772Sas200622 
10158334SJose.Borrego@Sun.COM 	case NDR_DRC_FAULT_DECODE_FAILED:
10168334SJose.Borrego@Sun.COM 	case NDR_DRC_FAULT_ENCODE_FAILED:
10178334SJose.Borrego@Sun.COM 		fault_status = NDR_FAULT_NCA_PROTO_ERROR;
10185772Sas200622 		break;
10195772Sas200622 
10205772Sas200622 	default:
10218334SJose.Borrego@Sun.COM 		fault_status = NDR_FAULT_NCA_UNSPEC_REJECT;
10225772Sas200622 		break;
10235772Sas200622 	}
10245772Sas200622 
10258334SJose.Borrego@Sun.COM 	mxa->send_hdr.fault_hdr.common_hdr.ptype = NDR_PTYPE_FAULT;
10265772Sas200622 	mxa->send_hdr.fault_hdr.status = fault_status;
10275772Sas200622 	mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length;
10285772Sas200622 }
10295772Sas200622 
10307619SJose.Borrego@Sun.COM /*
10317619SJose.Borrego@Sun.COM  * Note that the frag_length for bind ack and alter context is
10327619SJose.Borrego@Sun.COM  * non-standard.
10337619SJose.Borrego@Sun.COM  */
10345772Sas200622 static int
10358334SJose.Borrego@Sun.COM ndr_build_reply(ndr_xa_t *mxa)
10365772Sas200622 {
10377619SJose.Borrego@Sun.COM 	ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
10388334SJose.Borrego@Sun.COM 	ndr_stream_t *nds = &mxa->send_nds;
10396482Samw 	uint8_t *pdu_buf;
10405772Sas200622 	unsigned long pdu_size;
10415772Sas200622 	unsigned long frag_size;
10425772Sas200622 	unsigned long pdu_data_size;
10435772Sas200622 	unsigned long frag_data_size;
10445772Sas200622 
10458334SJose.Borrego@Sun.COM 	frag_size = NDR_FRAG_SZ;
10468334SJose.Borrego@Sun.COM 	pdu_size = nds->pdu_size;
10478334SJose.Borrego@Sun.COM 	pdu_buf = nds->pdu_base_addr;
10485772Sas200622 
10495772Sas200622 	if (pdu_size <= frag_size) {
10505772Sas200622 		/*
10515772Sas200622 		 * Single fragment response. The PDU size may be zero
10525772Sas200622 		 * here (i.e. bind or fault response). So don't make
10535772Sas200622 		 * any assumptions about it until after the header is
10545772Sas200622 		 * encoded.
10555772Sas200622 		 */
10565772Sas200622 		switch (hdr->ptype) {
10578334SJose.Borrego@Sun.COM 		case NDR_PTYPE_BIND_ACK:
10588334SJose.Borrego@Sun.COM 			hdr->frag_length = ndr_bind_ack_hdr_size(mxa);
10595772Sas200622 			break;
10605772Sas200622 
10618334SJose.Borrego@Sun.COM 		case NDR_PTYPE_FAULT:
10625772Sas200622 			/* already setup */
10635772Sas200622 			break;
10645772Sas200622 
10658334SJose.Borrego@Sun.COM 		case NDR_PTYPE_RESPONSE:
10665772Sas200622 			hdr->frag_length = pdu_size;
10675772Sas200622 			mxa->send_hdr.response_hdr.alloc_hint =
10685772Sas200622 			    hdr->frag_length;
10695772Sas200622 			break;
10705772Sas200622 
10718334SJose.Borrego@Sun.COM 		case NDR_PTYPE_ALTER_CONTEXT_RESP:
10728334SJose.Borrego@Sun.COM 			hdr->frag_length = ndr_alter_context_rsp_hdr_size();
10737619SJose.Borrego@Sun.COM 			break;
10747619SJose.Borrego@Sun.COM 
10755772Sas200622 		default:
10765772Sas200622 			hdr->frag_length = pdu_size;
10775772Sas200622 			break;
10785772Sas200622 		}
10795772Sas200622 
10808334SJose.Borrego@Sun.COM 		nds->pdu_scan_offset = 0;
10818334SJose.Borrego@Sun.COM 		(void) ndr_encode_pdu_hdr(mxa);
10828334SJose.Borrego@Sun.COM 		pdu_size = nds->pdu_size;
10838334SJose.Borrego@Sun.COM 		ndr_build_frag(nds, pdu_buf,  pdu_size);
10845772Sas200622 		return (0);
10855772Sas200622 	}
10865772Sas200622 
10875772Sas200622 	/*
10885772Sas200622 	 * Multiple fragment response.
10895772Sas200622 	 */
10908334SJose.Borrego@Sun.COM 	hdr->pfc_flags = NDR_PFC_FIRST_FRAG;
10915772Sas200622 	hdr->frag_length = frag_size;
10928334SJose.Borrego@Sun.COM 	mxa->send_hdr.response_hdr.alloc_hint = pdu_size - NDR_RSP_HDR_SIZE;
10938334SJose.Borrego@Sun.COM 	nds->pdu_scan_offset = 0;
10948334SJose.Borrego@Sun.COM 	(void) ndr_encode_pdu_hdr(mxa);
10958334SJose.Borrego@Sun.COM 	ndr_build_frag(nds, pdu_buf,  frag_size);
10965772Sas200622 
10975772Sas200622 	/*
10985772Sas200622 	 * We need to update the 24-byte header in subsequent fragments.
10995772Sas200622 	 *
11006482Samw 	 * pdu_data_size:	total data remaining to be handled
11016482Samw 	 * frag_size:		total fragment size including header
11026482Samw 	 * frag_data_size:	data in fragment
11038334SJose.Borrego@Sun.COM 	 *			(i.e. frag_size - NDR_RSP_HDR_SIZE)
11045772Sas200622 	 */
11058334SJose.Borrego@Sun.COM 	pdu_data_size = pdu_size - NDR_RSP_HDR_SIZE;
11068334SJose.Borrego@Sun.COM 	frag_data_size = frag_size - NDR_RSP_HDR_SIZE;
11075772Sas200622 
11086482Samw 	while (pdu_data_size) {
11096482Samw 		mxa->send_hdr.response_hdr.alloc_hint -= frag_data_size;
11106482Samw 		pdu_data_size -= frag_data_size;
11116482Samw 		pdu_buf += frag_data_size;
11125772Sas200622 
11136482Samw 		if (pdu_data_size <= frag_data_size) {
11146482Samw 			frag_data_size = pdu_data_size;
11158334SJose.Borrego@Sun.COM 			frag_size = frag_data_size + NDR_RSP_HDR_SIZE;
11168334SJose.Borrego@Sun.COM 			hdr->pfc_flags = NDR_PFC_LAST_FRAG;
11175772Sas200622 		} else {
11186482Samw 			hdr->pfc_flags = 0;
11195772Sas200622 		}
11205772Sas200622 
11216482Samw 		hdr->frag_length = frag_size;
11228334SJose.Borrego@Sun.COM 		nds->pdu_scan_offset = 0;
11238334SJose.Borrego@Sun.COM 		(void) ndr_encode_pdu_hdr(mxa);
11248334SJose.Borrego@Sun.COM 		bcopy(nds->pdu_base_addr, pdu_buf, NDR_RSP_HDR_SIZE);
11255772Sas200622 
11268334SJose.Borrego@Sun.COM 		ndr_build_frag(nds, pdu_buf, frag_size);
11275772Sas200622 
11288334SJose.Borrego@Sun.COM 		if (hdr->pfc_flags & NDR_PFC_LAST_FRAG)
11296482Samw 			break;
11305772Sas200622 	}
11315772Sas200622 
11325772Sas200622 	return (0);
11335772Sas200622 }
11346482Samw 
11356482Samw /*
11368334SJose.Borrego@Sun.COM  * ndr_build_frag
11376482Samw  *
11386482Samw  * Build an RPC PDU fragment from the specified buffer.
11396482Samw  * If malloc fails, the client will see a header/pdu inconsistency
11406482Samw  * and report an error.
11416482Samw  */
11426482Samw static void
11438334SJose.Borrego@Sun.COM ndr_build_frag(ndr_stream_t *nds, uint8_t *buf, uint32_t len)
11446482Samw {
11456482Samw 	ndr_frag_t *frag;
11466482Samw 	int size = sizeof (ndr_frag_t) + len;
11476482Samw 
11486482Samw 	if ((frag = (ndr_frag_t *)malloc(size)) == NULL)
11496482Samw 		return;
11506482Samw 
11516482Samw 	frag->next = NULL;
11526482Samw 	frag->buf = (uint8_t *)frag + sizeof (ndr_frag_t);
11536482Samw 	frag->len = len;
11546482Samw 	bcopy(buf, frag->buf, len);
11556482Samw 
11568334SJose.Borrego@Sun.COM 	if (nds->frags.head == NULL) {
11578334SJose.Borrego@Sun.COM 		nds->frags.head = frag;
11588334SJose.Borrego@Sun.COM 		nds->frags.tail = frag;
11598334SJose.Borrego@Sun.COM 		nds->frags.nfrag = 1;
11606482Samw 	} else {
11618334SJose.Borrego@Sun.COM 		nds->frags.tail->next = frag;
11628334SJose.Borrego@Sun.COM 		nds->frags.tail = frag;
11638334SJose.Borrego@Sun.COM 		++nds->frags.nfrag;
11646482Samw 	}
11656482Samw }
1166