xref: /titanic_53/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c (revision 68b2bbf26c7040fea4281dcb58b81e7627e46f34)
1dc20a302Sas200622 /*
2dc20a302Sas200622  * CDDL HEADER START
3dc20a302Sas200622  *
4dc20a302Sas200622  * The contents of this file are subject to the terms of the
5dc20a302Sas200622  * Common Development and Distribution License (the "License").
6dc20a302Sas200622  * You may not use this file except in compliance with the License.
7dc20a302Sas200622  *
8dc20a302Sas200622  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9dc20a302Sas200622  * or http://www.opensolaris.org/os/licensing.
10dc20a302Sas200622  * See the License for the specific language governing permissions
11dc20a302Sas200622  * and limitations under the License.
12dc20a302Sas200622  *
13dc20a302Sas200622  * When distributing Covered Code, include this CDDL HEADER in each
14dc20a302Sas200622  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15dc20a302Sas200622  * If applicable, add the following below this CDDL HEADER, with the
16dc20a302Sas200622  * fields enclosed by brackets "[]" replaced with your own identifying
17dc20a302Sas200622  * information: Portions Copyright [yyyy] [name of copyright owner]
18dc20a302Sas200622  *
19dc20a302Sas200622  * CDDL HEADER END
20dc20a302Sas200622  */
21dc20a302Sas200622 /*
22cb174861Sjoyce mcintosh  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23*68b2bbf2SGordon Ross  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
24dc20a302Sas200622  */
25dc20a302Sas200622 
26dc20a302Sas200622 /*
27dc20a302Sas200622  * Server side RPC handler.
28dc20a302Sas200622  */
29dc20a302Sas200622 
30dc20a302Sas200622 #include <sys/byteorder.h>
313db3f65cSamw #include <sys/uio.h>
32*68b2bbf2SGordon Ross #include <errno.h>
33dc20a302Sas200622 #include <synch.h>
34dc20a302Sas200622 #include <stdlib.h>
35dc20a302Sas200622 #include <strings.h>
36dc20a302Sas200622 #include <string.h>
37*68b2bbf2SGordon Ross #include <thread.h>
38dc20a302Sas200622 
39dc20a302Sas200622 #include <smbsrv/libsmb.h>
40dc20a302Sas200622 #include <smbsrv/libmlrpc.h>
4189dc44ceSjose borrego #include <smbsrv/ntaccess.h>
42dc20a302Sas200622 
43*68b2bbf2SGordon Ross #define	NDR_PIPE_SEND(np, buf, len) \
44*68b2bbf2SGordon Ross 	((np)->np_send)((np), (buf), (len))
45*68b2bbf2SGordon Ross #define	NDR_PIPE_RECV(np, buf, len) \
46*68b2bbf2SGordon Ross 	((np)->np_recv)((np), (buf), (len))
473db3f65cSamw 
488d7e4166Sjose borrego static int ndr_svc_process(ndr_xa_t *);
498d7e4166Sjose borrego static int ndr_svc_bind(ndr_xa_t *);
508d7e4166Sjose borrego static int ndr_svc_request(ndr_xa_t *);
518d7e4166Sjose borrego static void ndr_reply_prepare_hdr(ndr_xa_t *);
528d7e4166Sjose borrego static int ndr_svc_alter_context(ndr_xa_t *);
538d7e4166Sjose borrego static void ndr_reply_fault(ndr_xa_t *, unsigned long);
54*68b2bbf2SGordon Ross 
55*68b2bbf2SGordon Ross static int ndr_recv_request(ndr_xa_t *mxa);
56*68b2bbf2SGordon Ross static int ndr_recv_frag(ndr_xa_t *mxa);
57*68b2bbf2SGordon Ross static int ndr_send_reply(ndr_xa_t *);
58*68b2bbf2SGordon Ross 
59*68b2bbf2SGordon Ross static int ndr_pipe_process(ndr_pipe_t *, ndr_xa_t *);
60dc20a302Sas200622 
61dc20a302Sas200622 /*
62*68b2bbf2SGordon Ross  * External entry point called by smbd.
63dc20a302Sas200622  */
64*68b2bbf2SGordon Ross void
ndr_pipe_worker(ndr_pipe_t * np)65*68b2bbf2SGordon Ross ndr_pipe_worker(ndr_pipe_t *np)
66dc20a302Sas200622 {
67*68b2bbf2SGordon Ross 	ndr_xa_t	*mxa;
68*68b2bbf2SGordon Ross 	int rc;
693db3f65cSamw 
708d7e4166Sjose borrego 	ndr_svc_binding_pool_init(&np->np_binding, np->np_binding_pool,
718d7e4166Sjose borrego 	    NDR_N_BINDING_POOL);
723db3f65cSamw 
73*68b2bbf2SGordon Ross 	if ((mxa = malloc(sizeof (*mxa))) == NULL)
74*68b2bbf2SGordon Ross 		return;
753db3f65cSamw 
76*68b2bbf2SGordon Ross 	do {
77*68b2bbf2SGordon Ross 		bzero(mxa, sizeof (*mxa));
78*68b2bbf2SGordon Ross 		rc = ndr_pipe_process(np, mxa);
79*68b2bbf2SGordon Ross 	} while (rc == 0);
803db3f65cSamw 
81dc20a302Sas200622 	free(mxa);
82dc20a302Sas200622 
833db3f65cSamw 	/*
843db3f65cSamw 	 * Ensure that there are no RPC service policy handles
853db3f65cSamw 	 * (associated with this fid) left around.
863db3f65cSamw 	 */
87*68b2bbf2SGordon Ross 	ndr_hdclose(np);
883db3f65cSamw }
893db3f65cSamw 
903db3f65cSamw /*
91*68b2bbf2SGordon Ross  * Process one server-side RPC request.
923db3f65cSamw  */
93*68b2bbf2SGordon Ross static int
ndr_pipe_process(ndr_pipe_t * np,ndr_xa_t * mxa)94*68b2bbf2SGordon Ross ndr_pipe_process(ndr_pipe_t *np, ndr_xa_t *mxa)
953db3f65cSamw {
96*68b2bbf2SGordon Ross 	ndr_stream_t	*recv_nds;
97*68b2bbf2SGordon Ross 	ndr_stream_t	*send_nds;
98*68b2bbf2SGordon Ross 	int		rc = ENOMEM;
993db3f65cSamw 
100*68b2bbf2SGordon Ross 	mxa->pipe = np;
101*68b2bbf2SGordon Ross 	mxa->binding_list = np->np_binding;
1023db3f65cSamw 
103*68b2bbf2SGordon Ross 	if ((mxa->heap = ndr_heap_create()) == NULL)
104*68b2bbf2SGordon Ross 		goto out1;
1053db3f65cSamw 
106*68b2bbf2SGordon Ross 	recv_nds = &mxa->recv_nds;
107*68b2bbf2SGordon Ross 	rc = nds_initialize(recv_nds, 0, NDR_MODE_CALL_RECV, mxa->heap);
108*68b2bbf2SGordon Ross 	if (rc != 0)
109*68b2bbf2SGordon Ross 		goto out2;
110*68b2bbf2SGordon Ross 
111*68b2bbf2SGordon Ross 	send_nds = &mxa->send_nds;
112*68b2bbf2SGordon Ross 	rc = nds_initialize(send_nds, 0, NDR_MODE_RETURN_SEND, mxa->heap);
113*68b2bbf2SGordon Ross 	if (rc != 0)
114*68b2bbf2SGordon Ross 		goto out3;
115*68b2bbf2SGordon Ross 
116*68b2bbf2SGordon Ross 	rc = ndr_recv_request(mxa);
117*68b2bbf2SGordon Ross 	if (rc != 0)
118*68b2bbf2SGordon Ross 		goto out4;
119*68b2bbf2SGordon Ross 
120*68b2bbf2SGordon Ross 	(void) ndr_svc_process(mxa);
121*68b2bbf2SGordon Ross 	(void) ndr_send_reply(mxa);
122*68b2bbf2SGordon Ross 	rc = 0;
123*68b2bbf2SGordon Ross 
124*68b2bbf2SGordon Ross out4:
125*68b2bbf2SGordon Ross 	nds_destruct(&mxa->send_nds);
126*68b2bbf2SGordon Ross out3:
127*68b2bbf2SGordon Ross 	nds_destruct(&mxa->recv_nds);
128*68b2bbf2SGordon Ross out2:
129*68b2bbf2SGordon Ross 	ndr_heap_destroy(mxa->heap);
130*68b2bbf2SGordon Ross out1:
131*68b2bbf2SGordon Ross 	return (rc);
1323db3f65cSamw }
1333db3f65cSamw 
1343db3f65cSamw /*
1353db3f65cSamw  * Check whether or not the specified user has administrator privileges,
1363db3f65cSamw  * i.e. is a member of Domain Admins or Administrators.
1373db3f65cSamw  * Returns true if the user is an administrator, otherwise returns false.
1383db3f65cSamw  */
1393db3f65cSamw boolean_t
ndr_is_admin(ndr_xa_t * xa)1403db3f65cSamw ndr_is_admin(ndr_xa_t *xa)
1413db3f65cSamw {
142*68b2bbf2SGordon Ross 	smb_netuserinfo_t *ctx = xa->pipe->np_user;
1433db3f65cSamw 
1441fcced4cSJordan Brown 	return (ctx->ui_flags & SMB_ATF_ADMIN);
1453db3f65cSamw }
1463db3f65cSamw 
1473db3f65cSamw /*
1483db3f65cSamw  * Check whether or not the specified user has power-user privileges,
1493db3f65cSamw  * i.e. is a member of Domain Admins, Administrators or Power Users.
1503db3f65cSamw  * This is typically required for operations such as managing shares.
1513db3f65cSamw  * Returns true if the user is a power user, otherwise returns false.
1523db3f65cSamw  */
1533db3f65cSamw boolean_t
ndr_is_poweruser(ndr_xa_t * xa)1543db3f65cSamw ndr_is_poweruser(ndr_xa_t *xa)
1553db3f65cSamw {
156*68b2bbf2SGordon Ross 	smb_netuserinfo_t *ctx = xa->pipe->np_user;
1573db3f65cSamw 
1581fcced4cSJordan Brown 	return ((ctx->ui_flags & SMB_ATF_ADMIN) ||
1591fcced4cSJordan Brown 	    (ctx->ui_flags & SMB_ATF_POWERUSER));
1603db3f65cSamw }
1613db3f65cSamw 
1623db3f65cSamw int32_t
ndr_native_os(ndr_xa_t * xa)1633db3f65cSamw ndr_native_os(ndr_xa_t *xa)
1643db3f65cSamw {
165*68b2bbf2SGordon Ross 	smb_netuserinfo_t *ctx = xa->pipe->np_user;
1663db3f65cSamw 
1671fcced4cSJordan Brown 	return (ctx->ui_native_os);
168dc20a302Sas200622 }
169dc20a302Sas200622 
170dc20a302Sas200622 /*
171*68b2bbf2SGordon Ross  * Receive an entire RPC request (all fragments)
172*68b2bbf2SGordon Ross  * Returns zero or an NDR fault code.
173*68b2bbf2SGordon Ross  */
174*68b2bbf2SGordon Ross static int
ndr_recv_request(ndr_xa_t * mxa)175*68b2bbf2SGordon Ross ndr_recv_request(ndr_xa_t *mxa)
176*68b2bbf2SGordon Ross {
177*68b2bbf2SGordon Ross 	ndr_common_header_t	*hdr = &mxa->recv_hdr.common_hdr;
178*68b2bbf2SGordon Ross 	ndr_stream_t		*nds = &mxa->recv_nds;
179*68b2bbf2SGordon Ross 	unsigned long		saved_size;
180*68b2bbf2SGordon Ross 	int			rc;
181*68b2bbf2SGordon Ross 
182*68b2bbf2SGordon Ross 	rc = ndr_recv_frag(mxa);
183*68b2bbf2SGordon Ross 	if (rc != 0)
184*68b2bbf2SGordon Ross 		return (rc);
185*68b2bbf2SGordon Ross 	if (!NDR_IS_FIRST_FRAG(hdr->pfc_flags))
186*68b2bbf2SGordon Ross 		return (NDR_DRC_FAULT_DECODE_FAILED);
187*68b2bbf2SGordon Ross 
188*68b2bbf2SGordon Ross 	while (!NDR_IS_LAST_FRAG(hdr->pfc_flags)) {
189*68b2bbf2SGordon Ross 		rc = ndr_recv_frag(mxa);
190*68b2bbf2SGordon Ross 		if (rc != 0)
191*68b2bbf2SGordon Ross 			return (rc);
192*68b2bbf2SGordon Ross 	}
193*68b2bbf2SGordon Ross 	nds->pdu_scan_offset = 0;
194*68b2bbf2SGordon Ross 
195*68b2bbf2SGordon Ross 	/*
196*68b2bbf2SGordon Ross 	 * This whacks nds->pdu_size, so save/restore.
197*68b2bbf2SGordon Ross 	 * It leaves scan_offset after the header.
198*68b2bbf2SGordon Ross 	 */
199*68b2bbf2SGordon Ross 	saved_size = nds->pdu_size;
200*68b2bbf2SGordon Ross 	rc = ndr_decode_pdu_hdr(mxa);
201*68b2bbf2SGordon Ross 	nds->pdu_size = saved_size;
202*68b2bbf2SGordon Ross 
203*68b2bbf2SGordon Ross 	return (rc);
204*68b2bbf2SGordon Ross }
205*68b2bbf2SGordon Ross 
206*68b2bbf2SGordon Ross /*
207*68b2bbf2SGordon Ross  * Read one fragment, leaving the decoded frag header in
208*68b2bbf2SGordon Ross  * recv_hdr.common_hdr, and the data in the recv_nds.
209*68b2bbf2SGordon Ross  *
210*68b2bbf2SGordon Ross  * Returns zero or an NDR fault code.
211*68b2bbf2SGordon Ross  *
212*68b2bbf2SGordon Ross  * If a first frag, the header is included in the data
213*68b2bbf2SGordon Ross  * placed in recv_nds (because it's not fully decoded
214*68b2bbf2SGordon Ross  * until later - we only decode the common part here).
215*68b2bbf2SGordon Ross  * Additional frags are placed in the recv_nds without
216*68b2bbf2SGordon Ross  * the header, so that after the first frag header,
217*68b2bbf2SGordon Ross  * the remaining data will be contiguous.  We do this
218*68b2bbf2SGordon Ross  * by simply not advancing the offset in recv_nds after
219*68b2bbf2SGordon Ross  * reading and decoding these additional fragments, so
220*68b2bbf2SGordon Ross  * the payload of such frags will overwrite what was
221*68b2bbf2SGordon Ross  * (temporarily) the frag header.
222*68b2bbf2SGordon Ross  */
223*68b2bbf2SGordon Ross static int
ndr_recv_frag(ndr_xa_t * mxa)224*68b2bbf2SGordon Ross ndr_recv_frag(ndr_xa_t *mxa)
225*68b2bbf2SGordon Ross {
226*68b2bbf2SGordon Ross 	ndr_common_header_t	*hdr = &mxa->recv_hdr.common_hdr;
227*68b2bbf2SGordon Ross 	ndr_stream_t		*nds = &mxa->recv_nds;
228*68b2bbf2SGordon Ross 	unsigned char		*data;
229*68b2bbf2SGordon Ross 	unsigned long		next_offset;
230*68b2bbf2SGordon Ross 	unsigned long		pay_size;
231*68b2bbf2SGordon Ross 	int			rc;
232*68b2bbf2SGordon Ross 
233*68b2bbf2SGordon Ross 	/* Make room for the frag header. */
234*68b2bbf2SGordon Ross 	next_offset = nds->pdu_scan_offset + NDR_RSP_HDR_SIZE;
235*68b2bbf2SGordon Ross 	if (!NDS_GROW_PDU(nds, next_offset, 0))
236*68b2bbf2SGordon Ross 		return (NDR_DRC_FAULT_OUT_OF_MEMORY);
237*68b2bbf2SGordon Ross 
238*68b2bbf2SGordon Ross 	/* Read the frag header. */
239*68b2bbf2SGordon Ross 	data = nds->pdu_base_addr + nds->pdu_scan_offset;
240*68b2bbf2SGordon Ross 	rc = NDR_PIPE_RECV(mxa->pipe, data, NDR_RSP_HDR_SIZE);
241*68b2bbf2SGordon Ross 	if (rc != 0)
242*68b2bbf2SGordon Ross 		return (NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT);
243*68b2bbf2SGordon Ross 
244*68b2bbf2SGordon Ross 	/*
245*68b2bbf2SGordon Ross 	 * Decode the frag header, get the length.
246*68b2bbf2SGordon Ross 	 * NB: It uses nds->pdu_scan_offset
247*68b2bbf2SGordon Ross 	 */
248*68b2bbf2SGordon Ross 	ndr_decode_frag_hdr(nds, hdr);
249*68b2bbf2SGordon Ross 	ndr_show_hdr(hdr);
250*68b2bbf2SGordon Ross 	if (hdr->frag_length < NDR_RSP_HDR_SIZE ||
251*68b2bbf2SGordon Ross 	    hdr->frag_length > mxa->pipe->np_max_xmit_frag)
252*68b2bbf2SGordon Ross 		return (NDR_DRC_FAULT_DECODE_FAILED);
253*68b2bbf2SGordon Ross 
254*68b2bbf2SGordon Ross 	if (nds->pdu_scan_offset == 0) {
255*68b2bbf2SGordon Ross 		/* First frag: header stays in the data. */
256*68b2bbf2SGordon Ross 		nds->pdu_scan_offset = next_offset;
257*68b2bbf2SGordon Ross 	} /* else overwrite with the payload */
258*68b2bbf2SGordon Ross 
259*68b2bbf2SGordon Ross 	/* Make room for the payload. */
260*68b2bbf2SGordon Ross 	pay_size = hdr->frag_length - NDR_RSP_HDR_SIZE;
261*68b2bbf2SGordon Ross 	next_offset = nds->pdu_scan_offset + pay_size;
262*68b2bbf2SGordon Ross 	if (!NDS_GROW_PDU(nds, next_offset, 0))
263*68b2bbf2SGordon Ross 		return (NDR_DRC_FAULT_OUT_OF_MEMORY);
264*68b2bbf2SGordon Ross 
265*68b2bbf2SGordon Ross 	/* Read the payload. */
266*68b2bbf2SGordon Ross 	data = nds->pdu_base_addr + nds->pdu_scan_offset;
267*68b2bbf2SGordon Ross 	rc = NDR_PIPE_RECV(mxa->pipe, data, pay_size);
268*68b2bbf2SGordon Ross 	if (rc != 0)
269*68b2bbf2SGordon Ross 		return (NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT);
270*68b2bbf2SGordon Ross 	nds->pdu_scan_offset = next_offset;
271*68b2bbf2SGordon Ross 
272*68b2bbf2SGordon Ross 	return (NDR_DRC_OK);
273*68b2bbf2SGordon Ross }
274*68b2bbf2SGordon Ross 
275*68b2bbf2SGordon Ross /*
276dc20a302Sas200622  * This is the entry point for all server-side RPC processing.
277dc20a302Sas200622  * It is assumed that the PDU has already been received.
278dc20a302Sas200622  */
279dc20a302Sas200622 static int
ndr_svc_process(ndr_xa_t * mxa)2808d7e4166Sjose borrego ndr_svc_process(ndr_xa_t *mxa)
281dc20a302Sas200622 {
282dc20a302Sas200622 	int			rc;
283dc20a302Sas200622 
2848d7e4166Sjose borrego 	(void) ndr_reply_prepare_hdr(mxa);
285dc20a302Sas200622 
286dc20a302Sas200622 	switch (mxa->ptype) {
2878d7e4166Sjose borrego 	case NDR_PTYPE_BIND:
2888d7e4166Sjose borrego 		rc = ndr_svc_bind(mxa);
289dc20a302Sas200622 		break;
290dc20a302Sas200622 
2918d7e4166Sjose borrego 	case NDR_PTYPE_REQUEST:
2928d7e4166Sjose borrego 		rc = ndr_svc_request(mxa);
293dc20a302Sas200622 		break;
294dc20a302Sas200622 
2958d7e4166Sjose borrego 	case NDR_PTYPE_ALTER_CONTEXT:
2968d7e4166Sjose borrego 		rc = ndr_svc_alter_context(mxa);
297dc20a302Sas200622 		break;
298dc20a302Sas200622 
299dc20a302Sas200622 	default:
3008d7e4166Sjose borrego 		rc = NDR_DRC_FAULT_RPCHDR_PTYPE_INVALID;
301dc20a302Sas200622 		break;
302dc20a302Sas200622 	}
303dc20a302Sas200622 
3048d7e4166Sjose borrego 	if (NDR_DRC_IS_FAULT(rc))
3058d7e4166Sjose borrego 		ndr_reply_fault(mxa, rc);
306dc20a302Sas200622 
307dc20a302Sas200622 	return (rc);
308dc20a302Sas200622 }
309dc20a302Sas200622 
310dc20a302Sas200622 /*
311dc20a302Sas200622  * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple
312dc20a302Sas200622  * p_results[] not supported.
313dc20a302Sas200622  */
314dc20a302Sas200622 static int
ndr_svc_bind(ndr_xa_t * mxa)3158d7e4166Sjose borrego ndr_svc_bind(ndr_xa_t *mxa)
316dc20a302Sas200622 {
3178d7e4166Sjose borrego 	ndr_p_cont_list_t	*cont_list;
3188d7e4166Sjose borrego 	ndr_p_result_list_t	*result_list;
3198d7e4166Sjose borrego 	ndr_p_result_t		*result;
320dc20a302Sas200622 	unsigned		p_cont_id;
3218d7e4166Sjose borrego 	ndr_binding_t		*mbind;
322dc20a302Sas200622 	ndr_uuid_t		*as_uuid;
323dc20a302Sas200622 	ndr_uuid_t		*ts_uuid;
324dc20a302Sas200622 	int			as_vers;
325dc20a302Sas200622 	int			ts_vers;
3268d7e4166Sjose borrego 	ndr_service_t		*msvc;
327dc20a302Sas200622 	int			rc;
3288d7e4166Sjose borrego 	ndr_port_any_t		*sec_addr;
329dc20a302Sas200622 
330dc20a302Sas200622 	/* acquire targets */
331dc20a302Sas200622 	cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem;
332dc20a302Sas200622 	result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list;
333dc20a302Sas200622 	result = &result_list->p_results[0];
334dc20a302Sas200622 
335dc20a302Sas200622 	/*
336dc20a302Sas200622 	 * Set up temporary secondary address port.
337dc20a302Sas200622 	 * We will correct this later (below).
338dc20a302Sas200622 	 */
339dc20a302Sas200622 	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
340dc20a302Sas200622 	sec_addr->length = 13;
341dc20a302Sas200622 	(void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs");
342dc20a302Sas200622 
343dc20a302Sas200622 	result_list->n_results = 1;
344dc20a302Sas200622 	result_list->reserved = 0;
345dc20a302Sas200622 	result_list->reserved2 = 0;
3468d7e4166Sjose borrego 	result->result = NDR_PCDR_ACCEPTANCE;
347dc20a302Sas200622 	result->reason = 0;
348dc20a302Sas200622 	bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
349dc20a302Sas200622 
350dc20a302Sas200622 	/* sanity check */
351dc20a302Sas200622 	if (cont_list->n_context_elem != 1 ||
352dc20a302Sas200622 	    cont_list->p_cont_elem[0].n_transfer_syn != 1) {
3538d7e4166Sjose borrego 		ndo_trace("ndr_svc_bind: warning: multiple p_cont_elem");
354dc20a302Sas200622 	}
355dc20a302Sas200622 
356dc20a302Sas200622 	p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
357dc20a302Sas200622 
3588d7e4166Sjose borrego 	if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) != NULL) {
359dc20a302Sas200622 		/*
3608d7e4166Sjose borrego 		 * Duplicate presentation context id.
361dc20a302Sas200622 		 */
3628d7e4166Sjose borrego 		ndo_trace("ndr_svc_bind: duplicate binding");
3638d7e4166Sjose borrego 		return (NDR_DRC_FAULT_BIND_PCONT_BUSY);
364dc20a302Sas200622 	}
365dc20a302Sas200622 
3668d7e4166Sjose borrego 	if ((mbind = ndr_svc_new_binding(mxa)) == NULL) {
367dc20a302Sas200622 		/*
368dc20a302Sas200622 		 * No free binding slot
369dc20a302Sas200622 		 */
3708d7e4166Sjose borrego 		result->result = NDR_PCDR_PROVIDER_REJECTION;
3718d7e4166Sjose borrego 		result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED;
3728d7e4166Sjose borrego 		ndo_trace("ndr_svc_bind: no resources");
3738d7e4166Sjose borrego 		return (NDR_DRC_OK);
374dc20a302Sas200622 	}
375dc20a302Sas200622 
376dc20a302Sas200622 	as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
377dc20a302Sas200622 	as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
378dc20a302Sas200622 
379dc20a302Sas200622 	ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
380dc20a302Sas200622 	ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
381dc20a302Sas200622 
3828d7e4166Sjose borrego 	msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers);
3838d7e4166Sjose borrego 	if (msvc == NULL) {
3848d7e4166Sjose borrego 		result->result = NDR_PCDR_PROVIDER_REJECTION;
3858d7e4166Sjose borrego 		result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
3868d7e4166Sjose borrego 		return (NDR_DRC_OK);
387dc20a302Sas200622 	}
388dc20a302Sas200622 
389dc20a302Sas200622 	/*
390dc20a302Sas200622 	 * We can now use the correct secondary address port.
391dc20a302Sas200622 	 */
392dc20a302Sas200622 	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
393dc20a302Sas200622 	sec_addr->length = strlen(msvc->sec_addr_port) + 1;
394dc20a302Sas200622 	(void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port,
3958d7e4166Sjose borrego 	    NDR_PORT_ANY_MAX_PORT_SPEC);
396dc20a302Sas200622 
397dc20a302Sas200622 	mbind->p_cont_id = p_cont_id;
3988d7e4166Sjose borrego 	mbind->which_side = NDR_BIND_SIDE_SERVER;
399dc20a302Sas200622 	/* mbind->context set by app */
400dc20a302Sas200622 	mbind->service = msvc;
401dc20a302Sas200622 	mbind->instance_specific = 0;
402dc20a302Sas200622 
403dc20a302Sas200622 	mxa->binding = mbind;
404dc20a302Sas200622 
405dc20a302Sas200622 	if (msvc->bind_req) {
406dc20a302Sas200622 		/*
407dc20a302Sas200622 		 * Call the service-specific bind() handler.  If
408dc20a302Sas200622 		 * this fails, we shouild send a specific error
409dc20a302Sas200622 		 * on the bind ack.
410dc20a302Sas200622 		 */
411dc20a302Sas200622 		rc = (msvc->bind_req)(mxa);
4128d7e4166Sjose borrego 		if (NDR_DRC_IS_FAULT(rc)) {
413dc20a302Sas200622 			mbind->service = 0;	/* free binding slot */
414dc20a302Sas200622 			mbind->which_side = 0;
415dc20a302Sas200622 			mbind->p_cont_id = 0;
416dc20a302Sas200622 			mbind->instance_specific = 0;
417dc20a302Sas200622 			return (rc);
418dc20a302Sas200622 		}
419dc20a302Sas200622 	}
420dc20a302Sas200622 
421dc20a302Sas200622 	result->transfer_syntax =
422dc20a302Sas200622 	    cont_list->p_cont_elem[0].transfer_syntaxes[0];
423dc20a302Sas200622 
4248d7e4166Sjose borrego 	return (NDR_DRC_BINDING_MADE);
425dc20a302Sas200622 }
426dc20a302Sas200622 
427dc20a302Sas200622 /*
4288d7e4166Sjose borrego  * ndr_svc_alter_context
429dc20a302Sas200622  *
430dc20a302Sas200622  * The alter context request is used to request additional presentation
4312c1b14e5Sjose borrego  * context for another interface and/or version.  It is very similar to
4322c1b14e5Sjose borrego  * a bind request.
433dc20a302Sas200622  */
434dc20a302Sas200622 static int
ndr_svc_alter_context(ndr_xa_t * mxa)4358d7e4166Sjose borrego ndr_svc_alter_context(ndr_xa_t *mxa)
436dc20a302Sas200622 {
4378d7e4166Sjose borrego 	ndr_p_result_list_t *result_list;
4388d7e4166Sjose borrego 	ndr_p_result_t *result;
4398d7e4166Sjose borrego 	ndr_p_cont_list_t *cont_list;
4408d7e4166Sjose borrego 	ndr_binding_t *mbind;
4418d7e4166Sjose borrego 	ndr_service_t *msvc;
442dc20a302Sas200622 	unsigned p_cont_id;
443dc20a302Sas200622 	ndr_uuid_t *as_uuid;
444dc20a302Sas200622 	ndr_uuid_t *ts_uuid;
445dc20a302Sas200622 	int as_vers;
446dc20a302Sas200622 	int ts_vers;
4478d7e4166Sjose borrego 	ndr_port_any_t *sec_addr;
448dc20a302Sas200622 
4492c1b14e5Sjose borrego 	result_list = &mxa->send_hdr.alter_context_rsp_hdr.p_result_list;
450dc20a302Sas200622 	result_list->n_results = 1;
451dc20a302Sas200622 	result_list->reserved = 0;
452dc20a302Sas200622 	result_list->reserved2 = 0;
453dc20a302Sas200622 
454dc20a302Sas200622 	result = &result_list->p_results[0];
4558d7e4166Sjose borrego 	result->result = NDR_PCDR_ACCEPTANCE;
456dc20a302Sas200622 	result->reason = 0;
457dc20a302Sas200622 	bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
458dc20a302Sas200622 
4592c1b14e5Sjose borrego 	cont_list = &mxa->recv_hdr.alter_context_hdr.p_context_elem;
460dc20a302Sas200622 	p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
461dc20a302Sas200622 
4628d7e4166Sjose borrego 	if (ndr_svc_find_binding(mxa, p_cont_id) != NULL)
4638d7e4166Sjose borrego 		return (NDR_DRC_FAULT_BIND_PCONT_BUSY);
464dc20a302Sas200622 
4658d7e4166Sjose borrego 	if ((mbind = ndr_svc_new_binding(mxa)) == NULL) {
4668d7e4166Sjose borrego 		result->result = NDR_PCDR_PROVIDER_REJECTION;
4678d7e4166Sjose borrego 		result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED;
4688d7e4166Sjose borrego 		return (NDR_DRC_OK);
469dc20a302Sas200622 	}
470dc20a302Sas200622 
471dc20a302Sas200622 	as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
472dc20a302Sas200622 	as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
473dc20a302Sas200622 
474dc20a302Sas200622 	ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
475dc20a302Sas200622 	ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
476dc20a302Sas200622 
4778d7e4166Sjose borrego 	msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers);
4788d7e4166Sjose borrego 	if (msvc == NULL) {
4798d7e4166Sjose borrego 		result->result = NDR_PCDR_PROVIDER_REJECTION;
4808d7e4166Sjose borrego 		result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
4818d7e4166Sjose borrego 		return (NDR_DRC_OK);
482dc20a302Sas200622 	}
483dc20a302Sas200622 
484dc20a302Sas200622 	mbind->p_cont_id = p_cont_id;
4858d7e4166Sjose borrego 	mbind->which_side = NDR_BIND_SIDE_SERVER;
486dc20a302Sas200622 	/* mbind->context set by app */
487dc20a302Sas200622 	mbind->service = msvc;
488dc20a302Sas200622 	mbind->instance_specific = 0;
489dc20a302Sas200622 	mxa->binding = mbind;
490dc20a302Sas200622 
4912c1b14e5Sjose borrego 	sec_addr = &mxa->send_hdr.alter_context_rsp_hdr.sec_addr;
492dc20a302Sas200622 	sec_addr->length = 0;
4938d7e4166Sjose borrego 	bzero(sec_addr->port_spec, NDR_PORT_ANY_MAX_PORT_SPEC);
494dc20a302Sas200622 
495dc20a302Sas200622 	result->transfer_syntax =
496dc20a302Sas200622 	    cont_list->p_cont_elem[0].transfer_syntaxes[0];
497dc20a302Sas200622 
4988d7e4166Sjose borrego 	return (NDR_DRC_BINDING_MADE);
499dc20a302Sas200622 }
500dc20a302Sas200622 
501dc20a302Sas200622 static int
ndr_svc_request(ndr_xa_t * mxa)5028d7e4166Sjose borrego ndr_svc_request(ndr_xa_t *mxa)
503dc20a302Sas200622 {
5048d7e4166Sjose borrego 	ndr_binding_t	*mbind;
5058d7e4166Sjose borrego 	ndr_service_t	*msvc;
506dc20a302Sas200622 	unsigned	p_cont_id;
507dc20a302Sas200622 	int		rc;
508dc20a302Sas200622 
509dc20a302Sas200622 	mxa->opnum = mxa->recv_hdr.request_hdr.opnum;
510dc20a302Sas200622 	p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id;
511dc20a302Sas200622 
5128d7e4166Sjose borrego 	if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) == NULL)
5138d7e4166Sjose borrego 		return (NDR_DRC_FAULT_REQUEST_PCONT_INVALID);
514dc20a302Sas200622 
515dc20a302Sas200622 	mxa->binding = mbind;
516dc20a302Sas200622 	msvc = mbind->service;
517dc20a302Sas200622 
518dc20a302Sas200622 	/*
519dc20a302Sas200622 	 * Make room for the response hdr.
520dc20a302Sas200622 	 */
5218d7e4166Sjose borrego 	mxa->send_nds.pdu_scan_offset = NDR_RSP_HDR_SIZE;
522dc20a302Sas200622 
523dc20a302Sas200622 	if (msvc->call_stub)
524dc20a302Sas200622 		rc = (*msvc->call_stub)(mxa);
525dc20a302Sas200622 	else
5268d7e4166Sjose borrego 		rc = ndr_generic_call_stub(mxa);
527dc20a302Sas200622 
5288d7e4166Sjose borrego 	if (NDR_DRC_IS_FAULT(rc)) {
5298d7e4166Sjose borrego 		ndo_printf(0, 0, "%s[0x%02x]: 0x%04x",
530dc20a302Sas200622 		    msvc->name, mxa->opnum, rc);
531dc20a302Sas200622 	}
532dc20a302Sas200622 
533dc20a302Sas200622 	return (rc);
534dc20a302Sas200622 }
535dc20a302Sas200622 
536dc20a302Sas200622 /*
5378d7e4166Sjose borrego  * The transaction and the two nds streams use the same heap, which
538dc20a302Sas200622  * should already exist at this point.  The heap will also be available
539dc20a302Sas200622  * to the stub.
540dc20a302Sas200622  */
541dc20a302Sas200622 int
ndr_generic_call_stub(ndr_xa_t * mxa)5428d7e4166Sjose borrego ndr_generic_call_stub(ndr_xa_t *mxa)
543dc20a302Sas200622 {
5448d7e4166Sjose borrego 	ndr_binding_t 		*mbind = mxa->binding;
5458d7e4166Sjose borrego 	ndr_service_t		*msvc = mbind->service;
5468d7e4166Sjose borrego 	ndr_typeinfo_t		*intf_ti = msvc->interface_ti;
5478d7e4166Sjose borrego 	ndr_stub_table_t	*ste;
548dc20a302Sas200622 	int			opnum = mxa->opnum;
549dc20a302Sas200622 	unsigned		p_len = intf_ti->c_size_fixed_part;
550dc20a302Sas200622 	char 			*param;
551dc20a302Sas200622 	int			rc;
552dc20a302Sas200622 
553dc20a302Sas200622 	if (mxa->heap == NULL) {
5548d7e4166Sjose borrego 		ndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum);
5558d7e4166Sjose borrego 		return (NDR_DRC_FAULT_OUT_OF_MEMORY);
556dc20a302Sas200622 	}
557dc20a302Sas200622 
5588d7e4166Sjose borrego 	if ((ste = ndr_svc_find_stub(msvc, opnum)) == NULL) {
5598d7e4166Sjose borrego 		ndo_printf(0, 0, "%s[0x%02x]: invalid opnum",
560dc20a302Sas200622 		    msvc->name, opnum);
5618d7e4166Sjose borrego 		return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID);
562dc20a302Sas200622 	}
563dc20a302Sas200622 
5648d7e4166Sjose borrego 	if ((param = ndr_heap_malloc(mxa->heap, p_len)) == NULL)
5658d7e4166Sjose borrego 		return (NDR_DRC_FAULT_OUT_OF_MEMORY);
566dc20a302Sas200622 
567dc20a302Sas200622 	bzero(param, p_len);
568dc20a302Sas200622 
5698d7e4166Sjose borrego 	rc = ndr_decode_call(mxa, param);
5708d7e4166Sjose borrego 	if (!NDR_DRC_IS_OK(rc))
571dc20a302Sas200622 		return (rc);
572dc20a302Sas200622 
573dc20a302Sas200622 	rc = (*ste->func)(param, mxa);
5748d7e4166Sjose borrego 	if (rc == NDR_DRC_OK)
5758d7e4166Sjose borrego 		rc = ndr_encode_return(mxa, param);
576dc20a302Sas200622 
577dc20a302Sas200622 	return (rc);
578dc20a302Sas200622 }
579dc20a302Sas200622 
580dc20a302Sas200622 /*
581dc20a302Sas200622  * We can perform some initial setup of the response header here.
582dc20a302Sas200622  * We also need to cache some of the information from the bind
583dc20a302Sas200622  * negotiation for use during subsequent RPC calls.
584dc20a302Sas200622  */
585dc20a302Sas200622 static void
ndr_reply_prepare_hdr(ndr_xa_t * mxa)5868d7e4166Sjose borrego ndr_reply_prepare_hdr(ndr_xa_t *mxa)
587dc20a302Sas200622 {
5882c1b14e5Sjose borrego 	ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
5892c1b14e5Sjose borrego 	ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
590dc20a302Sas200622 
591dc20a302Sas200622 	hdr->rpc_vers = 5;
592dc20a302Sas200622 	hdr->rpc_vers_minor = 0;
5938d7e4166Sjose borrego 	hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG;
594dc20a302Sas200622 	hdr->packed_drep = rhdr->packed_drep;
595dc20a302Sas200622 	hdr->frag_length = 0;
596dc20a302Sas200622 	hdr->auth_length = 0;
597dc20a302Sas200622 	hdr->call_id = rhdr->call_id;
598dc20a302Sas200622 #ifdef _BIG_ENDIAN
5998d7e4166Sjose borrego 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
6008d7e4166Sjose borrego 	    | NDR_REPLAB_INTG_BIG_ENDIAN;
601dc20a302Sas200622 #else
6028d7e4166Sjose borrego 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
6038d7e4166Sjose borrego 	    | NDR_REPLAB_INTG_LITTLE_ENDIAN;
604dc20a302Sas200622 #endif
605dc20a302Sas200622 
606dc20a302Sas200622 	switch (mxa->ptype) {
6078d7e4166Sjose borrego 	case NDR_PTYPE_BIND:
608dc20a302Sas200622 		/*
609*68b2bbf2SGordon Ross 		 * Compute the maximum fragment sizes for xmit/recv
610*68b2bbf2SGordon Ross 		 * and store in the pipe endpoint.  Note "xmit" is
611*68b2bbf2SGordon Ross 		 * client-to-server; "recv" is server-to-client.
612dc20a302Sas200622 		 */
613*68b2bbf2SGordon Ross 		if (mxa->pipe->np_max_xmit_frag >
614*68b2bbf2SGordon Ross 		    mxa->recv_hdr.bind_hdr.max_xmit_frag)
6158d7e4166Sjose borrego 			mxa->pipe->np_max_xmit_frag =
616dc20a302Sas200622 			    mxa->recv_hdr.bind_hdr.max_xmit_frag;
617*68b2bbf2SGordon Ross 		if (mxa->pipe->np_max_recv_frag >
618*68b2bbf2SGordon Ross 		    mxa->recv_hdr.bind_hdr.max_recv_frag)
6198d7e4166Sjose borrego 			mxa->pipe->np_max_recv_frag =
620dc20a302Sas200622 			    mxa->recv_hdr.bind_hdr.max_recv_frag;
621*68b2bbf2SGordon Ross 
622*68b2bbf2SGordon Ross 		hdr->ptype = NDR_PTYPE_BIND_ACK;
623*68b2bbf2SGordon Ross 		mxa->send_hdr.bind_ack_hdr.max_xmit_frag =
624*68b2bbf2SGordon Ross 		    mxa->pipe->np_max_xmit_frag;
625*68b2bbf2SGordon Ross 		mxa->send_hdr.bind_ack_hdr.max_recv_frag =
626*68b2bbf2SGordon Ross 		    mxa->pipe->np_max_recv_frag;
627*68b2bbf2SGordon Ross 
628*68b2bbf2SGordon Ross 		/*
629*68b2bbf2SGordon Ross 		 * We're supposed to assign a unique "assoc group"
630*68b2bbf2SGordon Ross 		 * (identifies this connection for the client).
631*68b2bbf2SGordon Ross 		 * Using the pipe address is adequate.
632*68b2bbf2SGordon Ross 		 */
633*68b2bbf2SGordon Ross 		mxa->send_hdr.bind_ack_hdr.assoc_group_id =
634*68b2bbf2SGordon Ross 		    mxa->recv_hdr.bind_hdr.assoc_group_id;
635*68b2bbf2SGordon Ross 		if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0)
636*68b2bbf2SGordon Ross 			mxa->send_hdr.bind_ack_hdr.assoc_group_id =
637*68b2bbf2SGordon Ross 			    (DWORD)(uintptr_t)mxa->pipe;
638*68b2bbf2SGordon Ross 
639dc20a302Sas200622 		break;
640dc20a302Sas200622 
6418d7e4166Sjose borrego 	case NDR_PTYPE_REQUEST:
6428d7e4166Sjose borrego 		hdr->ptype = NDR_PTYPE_RESPONSE;
643dc20a302Sas200622 		/* mxa->send_hdr.response_hdr.alloc_hint */
644dc20a302Sas200622 		mxa->send_hdr.response_hdr.p_cont_id =
645dc20a302Sas200622 		    mxa->recv_hdr.request_hdr.p_cont_id;
646dc20a302Sas200622 		mxa->send_hdr.response_hdr.cancel_count = 0;
647dc20a302Sas200622 		mxa->send_hdr.response_hdr.reserved = 0;
648dc20a302Sas200622 		break;
649dc20a302Sas200622 
6508d7e4166Sjose borrego 	case NDR_PTYPE_ALTER_CONTEXT:
6518d7e4166Sjose borrego 		hdr->ptype = NDR_PTYPE_ALTER_CONTEXT_RESP;
652dc20a302Sas200622 		/*
6532c1b14e5Sjose borrego 		 * The max_xmit_frag, max_recv_frag and assoc_group_id are
6542c1b14e5Sjose borrego 		 * ignored by the client but it's useful to fill them in.
655dc20a302Sas200622 		 */
6562c1b14e5Sjose borrego 		mxa->send_hdr.alter_context_rsp_hdr.max_xmit_frag =
6572c1b14e5Sjose borrego 		    mxa->recv_hdr.alter_context_hdr.max_xmit_frag;
6582c1b14e5Sjose borrego 		mxa->send_hdr.alter_context_rsp_hdr.max_recv_frag =
6592c1b14e5Sjose borrego 		    mxa->recv_hdr.alter_context_hdr.max_recv_frag;
6602c1b14e5Sjose borrego 		mxa->send_hdr.alter_context_rsp_hdr.assoc_group_id =
6612c1b14e5Sjose borrego 		    mxa->recv_hdr.alter_context_hdr.assoc_group_id;
662dc20a302Sas200622 		break;
663dc20a302Sas200622 
664dc20a302Sas200622 	default:
665dc20a302Sas200622 		hdr->ptype = 0xFF;
666dc20a302Sas200622 	}
667dc20a302Sas200622 }
668dc20a302Sas200622 
669dc20a302Sas200622 /*
670dc20a302Sas200622  * Signal an RPC fault. The stream is reset and we overwrite whatever
671dc20a302Sas200622  * was in the response header with the fault information.
672dc20a302Sas200622  */
673dc20a302Sas200622 static void
ndr_reply_fault(ndr_xa_t * mxa,unsigned long drc)6748d7e4166Sjose borrego ndr_reply_fault(ndr_xa_t *mxa, unsigned long drc)
675dc20a302Sas200622 {
6762c1b14e5Sjose borrego 	ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
6772c1b14e5Sjose borrego 	ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
6788d7e4166Sjose borrego 	ndr_stream_t *nds = &mxa->send_nds;
679dc20a302Sas200622 	unsigned long fault_status;
680dc20a302Sas200622 
6818d7e4166Sjose borrego 	NDS_RESET(nds);
682dc20a302Sas200622 
683dc20a302Sas200622 	hdr->rpc_vers = 5;
684dc20a302Sas200622 	hdr->rpc_vers_minor = 0;
6858d7e4166Sjose borrego 	hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG;
686dc20a302Sas200622 	hdr->packed_drep = rhdr->packed_drep;
687dc20a302Sas200622 	hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr);
688dc20a302Sas200622 	hdr->auth_length = 0;
689dc20a302Sas200622 	hdr->call_id = rhdr->call_id;
690dc20a302Sas200622 #ifdef _BIG_ENDIAN
6918d7e4166Sjose borrego 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
6928d7e4166Sjose borrego 	    | NDR_REPLAB_INTG_BIG_ENDIAN;
693dc20a302Sas200622 #else
6948d7e4166Sjose borrego 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
6958d7e4166Sjose borrego 	    | NDR_REPLAB_INTG_LITTLE_ENDIAN;
696dc20a302Sas200622 #endif
697dc20a302Sas200622 
6988d7e4166Sjose borrego 	switch (drc & NDR_DRC_MASK_SPECIFIER) {
6998d7e4166Sjose borrego 	case NDR_DRC_FAULT_OUT_OF_MEMORY:
7008d7e4166Sjose borrego 	case NDR_DRC_FAULT_ENCODE_TOO_BIG:
7018d7e4166Sjose borrego 		fault_status = NDR_FAULT_NCA_OUT_ARGS_TOO_BIG;
702dc20a302Sas200622 		break;
703dc20a302Sas200622 
7048d7e4166Sjose borrego 	case NDR_DRC_FAULT_REQUEST_PCONT_INVALID:
7058d7e4166Sjose borrego 		fault_status = NDR_FAULT_NCA_INVALID_PRES_CONTEXT_ID;
706dc20a302Sas200622 		break;
707dc20a302Sas200622 
7088d7e4166Sjose borrego 	case NDR_DRC_FAULT_REQUEST_OPNUM_INVALID:
7098d7e4166Sjose borrego 		fault_status = NDR_FAULT_NCA_OP_RNG_ERROR;
710dc20a302Sas200622 		break;
711dc20a302Sas200622 
7128d7e4166Sjose borrego 	case NDR_DRC_FAULT_DECODE_FAILED:
7138d7e4166Sjose borrego 	case NDR_DRC_FAULT_ENCODE_FAILED:
7148d7e4166Sjose borrego 		fault_status = NDR_FAULT_NCA_PROTO_ERROR;
715dc20a302Sas200622 		break;
716dc20a302Sas200622 
717dc20a302Sas200622 	default:
7188d7e4166Sjose borrego 		fault_status = NDR_FAULT_NCA_UNSPEC_REJECT;
719dc20a302Sas200622 		break;
720dc20a302Sas200622 	}
721dc20a302Sas200622 
7228d7e4166Sjose borrego 	mxa->send_hdr.fault_hdr.common_hdr.ptype = NDR_PTYPE_FAULT;
723dc20a302Sas200622 	mxa->send_hdr.fault_hdr.status = fault_status;
724dc20a302Sas200622 	mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length;
725dc20a302Sas200622 }
726dc20a302Sas200622 
7272c1b14e5Sjose borrego /*
7282c1b14e5Sjose borrego  * Note that the frag_length for bind ack and alter context is
7292c1b14e5Sjose borrego  * non-standard.
7302c1b14e5Sjose borrego  */
731dc20a302Sas200622 static int
ndr_send_reply(ndr_xa_t * mxa)732*68b2bbf2SGordon Ross ndr_send_reply(ndr_xa_t *mxa)
733dc20a302Sas200622 {
7342c1b14e5Sjose borrego 	ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
7358d7e4166Sjose borrego 	ndr_stream_t *nds = &mxa->send_nds;
73619d41fccSamw 	uint8_t *pdu_buf;
737dc20a302Sas200622 	unsigned long pdu_size;
738dc20a302Sas200622 	unsigned long frag_size;
739dc20a302Sas200622 	unsigned long pdu_data_size;
740dc20a302Sas200622 	unsigned long frag_data_size;
741dc20a302Sas200622 
742*68b2bbf2SGordon Ross 	frag_size = mxa->pipe->np_max_recv_frag;
7438d7e4166Sjose borrego 	pdu_size = nds->pdu_size;
7448d7e4166Sjose borrego 	pdu_buf = nds->pdu_base_addr;
745dc20a302Sas200622 
746dc20a302Sas200622 	if (pdu_size <= frag_size) {
747dc20a302Sas200622 		/*
748dc20a302Sas200622 		 * Single fragment response. The PDU size may be zero
749dc20a302Sas200622 		 * here (i.e. bind or fault response). So don't make
750dc20a302Sas200622 		 * any assumptions about it until after the header is
751dc20a302Sas200622 		 * encoded.
752dc20a302Sas200622 		 */
753dc20a302Sas200622 		switch (hdr->ptype) {
7548d7e4166Sjose borrego 		case NDR_PTYPE_BIND_ACK:
7558d7e4166Sjose borrego 			hdr->frag_length = ndr_bind_ack_hdr_size(mxa);
756dc20a302Sas200622 			break;
757dc20a302Sas200622 
7588d7e4166Sjose borrego 		case NDR_PTYPE_FAULT:
759dc20a302Sas200622 			/* already setup */
760dc20a302Sas200622 			break;
761dc20a302Sas200622 
7628d7e4166Sjose borrego 		case NDR_PTYPE_RESPONSE:
763dc20a302Sas200622 			hdr->frag_length = pdu_size;
764dc20a302Sas200622 			mxa->send_hdr.response_hdr.alloc_hint =
765dc20a302Sas200622 			    hdr->frag_length;
766dc20a302Sas200622 			break;
767dc20a302Sas200622 
7688d7e4166Sjose borrego 		case NDR_PTYPE_ALTER_CONTEXT_RESP:
7698d7e4166Sjose borrego 			hdr->frag_length = ndr_alter_context_rsp_hdr_size();
7702c1b14e5Sjose borrego 			break;
7712c1b14e5Sjose borrego 
772dc20a302Sas200622 		default:
773dc20a302Sas200622 			hdr->frag_length = pdu_size;
774dc20a302Sas200622 			break;
775dc20a302Sas200622 		}
776dc20a302Sas200622 
7778d7e4166Sjose borrego 		nds->pdu_scan_offset = 0;
7788d7e4166Sjose borrego 		(void) ndr_encode_pdu_hdr(mxa);
7798d7e4166Sjose borrego 		pdu_size = nds->pdu_size;
780*68b2bbf2SGordon Ross 		(void) NDR_PIPE_SEND(mxa->pipe, pdu_buf, pdu_size);
781dc20a302Sas200622 		return (0);
782dc20a302Sas200622 	}
783dc20a302Sas200622 
784dc20a302Sas200622 	/*
785dc20a302Sas200622 	 * Multiple fragment response.
786*68b2bbf2SGordon Ross 	 *
787*68b2bbf2SGordon Ross 	 * We need to update the RPC header for every fragment.
788dc20a302Sas200622 	 *
789dc20a302Sas200622 	 * pdu_data_size:	total data remaining to be handled
790dc20a302Sas200622 	 * frag_size:		total fragment size including header
791dc20a302Sas200622 	 * frag_data_size:	data in fragment
7928d7e4166Sjose borrego 	 *			(i.e. frag_size - NDR_RSP_HDR_SIZE)
793dc20a302Sas200622 	 */
7948d7e4166Sjose borrego 	pdu_data_size = pdu_size - NDR_RSP_HDR_SIZE;
7958d7e4166Sjose borrego 	frag_data_size = frag_size - NDR_RSP_HDR_SIZE;
796dc20a302Sas200622 
797*68b2bbf2SGordon Ross 	/*
798*68b2bbf2SGordon Ross 	 * Send the first frag.
799*68b2bbf2SGordon Ross 	 */
800*68b2bbf2SGordon Ross 	hdr->pfc_flags = NDR_PFC_FIRST_FRAG;
801*68b2bbf2SGordon Ross 	hdr->frag_length = frag_size;
802*68b2bbf2SGordon Ross 	mxa->send_hdr.response_hdr.alloc_hint = pdu_data_size;
803*68b2bbf2SGordon Ross 	nds->pdu_scan_offset = 0;
804*68b2bbf2SGordon Ross 	(void) ndr_encode_pdu_hdr(mxa);
805*68b2bbf2SGordon Ross 	(void) NDR_PIPE_SEND(mxa->pipe, pdu_buf, frag_size);
80619d41fccSamw 	pdu_data_size -= frag_data_size;
80719d41fccSamw 	pdu_buf += frag_data_size;
808dc20a302Sas200622 
809*68b2bbf2SGordon Ross 	/*
810*68b2bbf2SGordon Ross 	 * Send "middle" (full-sized) fragments...
811*68b2bbf2SGordon Ross 	 */
81219d41fccSamw 	hdr->pfc_flags = 0;
813*68b2bbf2SGordon Ross 	while (pdu_data_size > frag_data_size) {
814dc20a302Sas200622 
81519d41fccSamw 		hdr->frag_length = frag_size;
816*68b2bbf2SGordon Ross 		mxa->send_hdr.response_hdr.alloc_hint = pdu_data_size;
8178d7e4166Sjose borrego 		nds->pdu_scan_offset = 0;
8188d7e4166Sjose borrego 		(void) ndr_encode_pdu_hdr(mxa);
8198d7e4166Sjose borrego 		bcopy(nds->pdu_base_addr, pdu_buf, NDR_RSP_HDR_SIZE);
820*68b2bbf2SGordon Ross 		(void) NDR_PIPE_SEND(mxa->pipe, pdu_buf, frag_size);
821*68b2bbf2SGordon Ross 		pdu_data_size -= frag_data_size;
822*68b2bbf2SGordon Ross 		pdu_buf += frag_data_size;
823dc20a302Sas200622 	}
82419d41fccSamw 
82519d41fccSamw 	/*
826*68b2bbf2SGordon Ross 	 * Last frag (pdu_data_size <= frag_data_size)
82719d41fccSamw 	 */
828*68b2bbf2SGordon Ross 	hdr->pfc_flags = NDR_PFC_LAST_FRAG;
829*68b2bbf2SGordon Ross 	frag_size = pdu_data_size + NDR_RSP_HDR_SIZE;
830*68b2bbf2SGordon Ross 	hdr->frag_length = frag_size;
831*68b2bbf2SGordon Ross 	mxa->send_hdr.response_hdr.alloc_hint = pdu_data_size;
832*68b2bbf2SGordon Ross 	nds->pdu_scan_offset = 0;
833*68b2bbf2SGordon Ross 	(void) ndr_encode_pdu_hdr(mxa);
834*68b2bbf2SGordon Ross 	bcopy(nds->pdu_base_addr, pdu_buf, NDR_RSP_HDR_SIZE);
835*68b2bbf2SGordon Ross 	(void) NDR_PIPE_SEND(mxa->pipe, pdu_buf, frag_size);
83619d41fccSamw 
837*68b2bbf2SGordon Ross 	return (0);
83819d41fccSamw }
839