xref: /onnv-gate/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c (revision 7052:efa04b030974)
15772Sas200622 /*
25772Sas200622  * CDDL HEADER START
35772Sas200622  *
45772Sas200622  * The contents of this file are subject to the terms of the
55772Sas200622  * Common Development and Distribution License (the "License").
65772Sas200622  * You may not use this file except in compliance with the License.
75772Sas200622  *
85772Sas200622  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95772Sas200622  * or http://www.opensolaris.org/os/licensing.
105772Sas200622  * See the License for the specific language governing permissions
115772Sas200622  * and limitations under the License.
125772Sas200622  *
135772Sas200622  * When distributing Covered Code, include this CDDL HEADER in each
145772Sas200622  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155772Sas200622  * If applicable, add the following below this CDDL HEADER, with the
165772Sas200622  * fields enclosed by brackets "[]" replaced with your own identifying
175772Sas200622  * information: Portions Copyright [yyyy] [name of copyright owner]
185772Sas200622  *
195772Sas200622  * CDDL HEADER END
205772Sas200622  */
215772Sas200622 /*
225772Sas200622  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
235772Sas200622  * Use is subject to license terms.
245772Sas200622  */
255772Sas200622 
265772Sas200622 #pragma ident	"%Z%%M%	%I%	%E% SMI"
275772Sas200622 
285772Sas200622 /*
295772Sas200622  * Server side RPC handler.
305772Sas200622  */
315772Sas200622 
325772Sas200622 #include <sys/byteorder.h>
33*7052Samw #include <sys/errno.h>
34*7052Samw #include <sys/uio.h>
355772Sas200622 #include <thread.h>
365772Sas200622 #include <synch.h>
375772Sas200622 #include <stdlib.h>
385772Sas200622 #include <strings.h>
395772Sas200622 #include <string.h>
405772Sas200622 #include <time.h>
415772Sas200622 
425772Sas200622 #include <smbsrv/libsmb.h>
435772Sas200622 #include <smbsrv/libmlrpc.h>
445772Sas200622 #include <smbsrv/mlsvc.h>
455772Sas200622 #include <smbsrv/ndr.h>
465772Sas200622 #include <smbsrv/mlrpc.h>
475772Sas200622 #include <smbsrv/mlsvc_util.h>
48*7052Samw 
49*7052Samw 
50*7052Samw #define	SMB_CTXT_BUFSZ		65536
515772Sas200622 
525772Sas200622 /*
535772Sas200622  * Fragment size (5680: NT style).
545772Sas200622  */
555772Sas200622 #define	MLRPC_FRAG_SZ		5680
565772Sas200622 static unsigned long mlrpc_frag_size = MLRPC_FRAG_SZ;
575772Sas200622 
585772Sas200622 /*
59*7052Samw  * Service context table.
605772Sas200622  */
615772Sas200622 #define	CTXT_TABLE_ENTRIES	128
625772Sas200622 static struct mlsvc_rpc_context context_table[CTXT_TABLE_ENTRIES];
635772Sas200622 static mutex_t mlrpc_context_lock;
645772Sas200622 
65*7052Samw static int ndr_s_transact(struct mlsvc_rpc_context *);
66*7052Samw static struct mlsvc_rpc_context *ndr_s_lookup(int);
67*7052Samw static void ndr_s_release(struct mlsvc_rpc_context *);
68*7052Samw static struct mlsvc_rpc_context *ndr_s_allocate(int);
69*7052Samw static void ndr_s_deallocate(struct mlsvc_rpc_context *);
70*7052Samw static void ndr_s_rewind(struct mlsvc_rpc_context *);
71*7052Samw static void ndr_s_flush(struct mlsvc_rpc_context *);
72*7052Samw 
735772Sas200622 static int mlrpc_s_process(struct mlrpc_xaction *);
745772Sas200622 static int mlrpc_s_bind(struct mlrpc_xaction *);
755772Sas200622 static int mlrpc_s_request(struct mlrpc_xaction *);
765772Sas200622 static void mlrpc_reply_prepare_hdr(struct mlrpc_xaction *);
775772Sas200622 static int mlrpc_s_alter_context(struct mlrpc_xaction *);
785772Sas200622 static void mlrpc_reply_bind_ack(struct mlrpc_xaction *);
795772Sas200622 static void mlrpc_reply_fault(struct mlrpc_xaction *, unsigned long);
805772Sas200622 static int mlrpc_build_reply(struct mlrpc_xaction *);
816482Samw static void mlrpc_build_frag(struct mlndr_stream *, uint8_t *, uint32_t);
825772Sas200622 
835772Sas200622 /*
84*7052Samw  * Allocate and associate a service context with a fid.
85*7052Samw  */
86*7052Samw int
87*7052Samw ndr_s_open(int fid, uint8_t *data, uint32_t datalen)
88*7052Samw {
89*7052Samw 	struct mlsvc_rpc_context *svc;
90*7052Samw 
91*7052Samw 	(void) mutex_lock(&mlrpc_context_lock);
92*7052Samw 
93*7052Samw 	if ((svc = ndr_s_lookup(fid)) != NULL) {
94*7052Samw 		ndr_s_release(svc);
95*7052Samw 		(void) mutex_unlock(&mlrpc_context_lock);
96*7052Samw 		return (EEXIST);
97*7052Samw 	}
98*7052Samw 
99*7052Samw 	if ((svc = ndr_s_allocate(fid)) == NULL) {
100*7052Samw 		(void) mutex_unlock(&mlrpc_context_lock);
101*7052Samw 		return (ENOMEM);
102*7052Samw 	}
103*7052Samw 
104*7052Samw 	if (smb_opipe_context_decode(&svc->svc_ctx, data, datalen) == -1) {
105*7052Samw 		ndr_s_release(svc);
106*7052Samw 		(void) mutex_unlock(&mlrpc_context_lock);
107*7052Samw 		return (EINVAL);
108*7052Samw 	}
109*7052Samw 
110*7052Samw 	mlrpc_binding_pool_initialize(&svc->binding, svc->binding_pool,
111*7052Samw 	    CTXT_N_BINDING_POOL);
112*7052Samw 
113*7052Samw 	(void) mutex_unlock(&mlrpc_context_lock);
114*7052Samw 	return (0);
115*7052Samw }
116*7052Samw 
117*7052Samw /*
118*7052Samw  * Release the context associated with a fid when an opipe is closed.
119*7052Samw  */
120*7052Samw int
121*7052Samw ndr_s_close(int fid)
122*7052Samw {
123*7052Samw 	struct mlsvc_rpc_context *svc;
124*7052Samw 
125*7052Samw 	(void) mutex_lock(&mlrpc_context_lock);
126*7052Samw 
127*7052Samw 	if ((svc = ndr_s_lookup(fid)) == NULL) {
128*7052Samw 		(void) mutex_unlock(&mlrpc_context_lock);
129*7052Samw 		return (ENOENT);
130*7052Samw 	}
131*7052Samw 
132*7052Samw 	/*
133*7052Samw 	 * Release twice: once for the lookup above
134*7052Samw 	 * and again to close the fid.
135*7052Samw 	 */
136*7052Samw 	ndr_s_release(svc);
137*7052Samw 	ndr_s_release(svc);
138*7052Samw 	(void) mutex_unlock(&mlrpc_context_lock);
139*7052Samw 	return (0);
140*7052Samw }
141*7052Samw 
142*7052Samw /*
143*7052Samw  * Write RPC request data to the input stream.  Input data is buffered
144*7052Samw  * until the response is requested.
1455772Sas200622  */
146*7052Samw int
147*7052Samw ndr_s_write(int fid, uint8_t *buf, uint32_t len)
148*7052Samw {
149*7052Samw 	struct mlsvc_rpc_context *svc;
150*7052Samw 	ssize_t nbytes;
151*7052Samw 
152*7052Samw 	if (len == 0)
153*7052Samw 		return (0);
154*7052Samw 
155*7052Samw 	(void) mutex_lock(&mlrpc_context_lock);
156*7052Samw 
157*7052Samw 	if ((svc = ndr_s_lookup(fid)) == NULL) {
158*7052Samw 		(void) mutex_unlock(&mlrpc_context_lock);
159*7052Samw 		return (ENOENT);
160*7052Samw 	}
161*7052Samw 
162*7052Samw 	nbytes = ndr_uiomove((caddr_t)buf, len, UIO_READ, &svc->in_uio);
163*7052Samw 
164*7052Samw 	ndr_s_release(svc);
165*7052Samw 	(void) mutex_unlock(&mlrpc_context_lock);
166*7052Samw 	return ((nbytes == len) ? 0 : EIO);
167*7052Samw }
168*7052Samw 
169*7052Samw /*
170*7052Samw  * Read RPC response data.  If the input stream contains an RPC request,
171*7052Samw  * we need to process the RPC transaction, which will place the RPC
172*7052Samw  * response in the output (frags) stream.  Otherwise, read data from
173*7052Samw  * the output stream.
174*7052Samw  */
175*7052Samw int
176*7052Samw ndr_s_read(int fid, uint8_t *buf, uint32_t *len, uint32_t *resid)
1775772Sas200622 {
178*7052Samw 	struct mlsvc_rpc_context *svc;
179*7052Samw 	ssize_t nbytes = *len;
180*7052Samw 	int rc;
181*7052Samw 
182*7052Samw 	if (nbytes == 0) {
183*7052Samw 		*resid = 0;
184*7052Samw 		return (0);
185*7052Samw 	}
186*7052Samw 
187*7052Samw 	(void) mutex_lock(&mlrpc_context_lock);
188*7052Samw 	if ((svc = ndr_s_lookup(fid)) == NULL) {
189*7052Samw 		(void) mutex_unlock(&mlrpc_context_lock);
190*7052Samw 		return (ENOENT);
191*7052Samw 	}
192*7052Samw 	(void) mutex_unlock(&mlrpc_context_lock);
193*7052Samw 
194*7052Samw 	if (svc->in_uio.uio_offset) {
195*7052Samw 		if ((rc = ndr_s_transact(svc)) != 0) {
196*7052Samw 			ndr_s_flush(svc);
197*7052Samw 			(void) mutex_lock(&mlrpc_context_lock);
198*7052Samw 			ndr_s_release(svc);
199*7052Samw 			(void) mutex_unlock(&mlrpc_context_lock);
200*7052Samw 			return (rc);
201*7052Samw 		}
202*7052Samw 
203*7052Samw 	}
204*7052Samw 
205*7052Samw 	*len = ndr_uiomove((caddr_t)buf, nbytes, UIO_WRITE, &svc->frags.uio);
206*7052Samw 	*resid = svc->frags.uio.uio_resid;
207*7052Samw 
208*7052Samw 	if (*resid == 0) {
209*7052Samw 		/*
210*7052Samw 		 * Nothing left, cleanup the output stream.
211*7052Samw 		 */
212*7052Samw 		ndr_s_flush(svc);
213*7052Samw 	}
214*7052Samw 
215*7052Samw 	(void) mutex_lock(&mlrpc_context_lock);
216*7052Samw 	ndr_s_release(svc);
217*7052Samw 	(void) mutex_unlock(&mlrpc_context_lock);
218*7052Samw 	return (0);
219*7052Samw }
220*7052Samw 
221*7052Samw /*
222*7052Samw  * Process a server-side RPC request.
223*7052Samw  */
224*7052Samw static int
225*7052Samw ndr_s_transact(struct mlsvc_rpc_context *svc)
226*7052Samw {
227*7052Samw 	ndr_xa_t			*mxa;
2285772Sas200622 	struct mlndr_stream		*recv_mlnds;
2295772Sas200622 	struct mlndr_stream		*send_mlnds;
2305772Sas200622 	char				*data;
2315772Sas200622 	int				datalen;
2325772Sas200622 
233*7052Samw 	data = svc->in_buf;
234*7052Samw 	datalen = svc->in_uio.uio_offset;
2355772Sas200622 
236*7052Samw 	if ((mxa = (ndr_xa_t *)malloc(sizeof (ndr_xa_t))) == NULL)
237*7052Samw 		return (ENOMEM);
2385772Sas200622 
2395772Sas200622 	bzero(mxa, sizeof (struct mlrpc_xaction));
240*7052Samw 	mxa->fid = svc->fid;
241*7052Samw 	mxa->context = svc;
242*7052Samw 	mxa->binding_list = svc->binding;
2435772Sas200622 
2445772Sas200622 	if ((mxa->heap = mlrpc_heap_create()) == NULL) {
2455772Sas200622 		free(mxa);
246*7052Samw 		return (ENOMEM);
2475772Sas200622 	}
2485772Sas200622 
2495772Sas200622 	recv_mlnds = &mxa->recv_mlnds;
250*7052Samw 	mlnds_initialize(recv_mlnds, datalen, NDR_MODE_CALL_RECV, mxa->heap);
2515772Sas200622 
252*7052Samw 	/*
253*7052Samw 	 * Copy the input data and reset the input stream.
254*7052Samw 	 */
2555772Sas200622 	bcopy(data, recv_mlnds->pdu_base_addr, datalen);
256*7052Samw 	ndr_s_rewind(svc);
2575772Sas200622 
2585772Sas200622 	send_mlnds = &mxa->send_mlnds;
259*7052Samw 	mlnds_initialize(send_mlnds, 0, NDR_MODE_RETURN_SEND, mxa->heap);
2605772Sas200622 
2615772Sas200622 	(void) mlrpc_s_process(mxa);
2625772Sas200622 
263*7052Samw 	mlnds_finalize(send_mlnds, &svc->frags);
2645772Sas200622 	mlnds_destruct(&mxa->recv_mlnds);
2655772Sas200622 	mlnds_destruct(&mxa->send_mlnds);
2665772Sas200622 	mlrpc_heap_destroy(mxa->heap);
2675772Sas200622 	free(mxa);
268*7052Samw 	return (0);
269*7052Samw }
270*7052Samw 
271*7052Samw /*
272*7052Samw  * Must be called with mlrpc_context_lock held.
273*7052Samw  */
274*7052Samw static struct mlsvc_rpc_context *
275*7052Samw ndr_s_lookup(int fid)
276*7052Samw {
277*7052Samw 	struct mlsvc_rpc_context *svc;
278*7052Samw 	int i;
279*7052Samw 
280*7052Samw 	for (i = 0; i < CTXT_TABLE_ENTRIES; ++i) {
281*7052Samw 		svc = &context_table[i];
282*7052Samw 
283*7052Samw 		if (svc->fid == fid) {
284*7052Samw 			if (svc->refcnt == 0)
285*7052Samw 				return (NULL);
286*7052Samw 
287*7052Samw 			svc->refcnt++;
288*7052Samw 			return (svc);
289*7052Samw 		}
290*7052Samw 	}
291*7052Samw 
292*7052Samw 	return (NULL);
2935772Sas200622 }
2945772Sas200622 
2955772Sas200622 /*
296*7052Samw  * Must be called with mlrpc_context_lock held.
2975772Sas200622  */
298*7052Samw static void
299*7052Samw ndr_s_release(struct mlsvc_rpc_context *svc)
3005772Sas200622 {
301*7052Samw 	svc->refcnt--;
302*7052Samw 	ndr_s_deallocate(svc);
303*7052Samw }
304*7052Samw 
305*7052Samw /*
306*7052Samw  * Must be called with mlrpc_context_lock held.
307*7052Samw  */
308*7052Samw static struct mlsvc_rpc_context *
309*7052Samw ndr_s_allocate(int fid)
310*7052Samw {
311*7052Samw 	struct mlsvc_rpc_context *svc = NULL;
3125772Sas200622 	int i;
3135772Sas200622 
314*7052Samw 	for (i = 0; i < CTXT_TABLE_ENTRIES; ++i) {
315*7052Samw 		svc = &context_table[i];
3165772Sas200622 
317*7052Samw 		if (svc->fid == 0) {
318*7052Samw 			bzero(svc, sizeof (struct mlsvc_rpc_context));
3195772Sas200622 
320*7052Samw 			if ((svc->in_buf = malloc(SMB_CTXT_BUFSZ)) == NULL)
321*7052Samw 				return (NULL);
3225772Sas200622 
323*7052Samw 			ndr_s_rewind(svc);
324*7052Samw 			svc->fid = fid;
325*7052Samw 			svc->refcnt = 1;
326*7052Samw 			return (svc);
3275772Sas200622 		}
3285772Sas200622 	}
3295772Sas200622 
330*7052Samw 	return (NULL);
331*7052Samw }
3325772Sas200622 
333*7052Samw /*
334*7052Samw  * Must be called with mlrpc_context_lock held.
335*7052Samw  */
336*7052Samw static void
337*7052Samw ndr_s_deallocate(struct mlsvc_rpc_context *svc)
338*7052Samw {
339*7052Samw 	if (svc->refcnt == 0) {
340*7052Samw 		/*
341*7052Samw 		 * Ensure that there are no RPC service policy handles
342*7052Samw 		 * (associated with this fid) left around.
343*7052Samw 		 */
344*7052Samw 		ndr_hdclose(svc->fid);
3455772Sas200622 
346*7052Samw 		ndr_s_rewind(svc);
347*7052Samw 		ndr_s_flush(svc);
348*7052Samw 		free(svc->in_buf);
349*7052Samw 		free(svc->svc_ctx.oc_domain);
350*7052Samw 		free(svc->svc_ctx.oc_account);
351*7052Samw 		free(svc->svc_ctx.oc_workstation);
352*7052Samw 		bzero(svc, sizeof (struct mlsvc_rpc_context));
353*7052Samw 	}
354*7052Samw }
3555772Sas200622 
356*7052Samw /*
357*7052Samw  * Rewind the input data stream, ready for the next write.
358*7052Samw  */
359*7052Samw static void
360*7052Samw ndr_s_rewind(struct mlsvc_rpc_context *svc)
361*7052Samw {
362*7052Samw 	svc->in_uio.uio_iov = &svc->in_iov;
363*7052Samw 	svc->in_uio.uio_iovcnt = 1;
364*7052Samw 	svc->in_uio.uio_offset = 0;
365*7052Samw 	svc->in_uio.uio_segflg = UIO_USERSPACE;
366*7052Samw 	svc->in_uio.uio_resid = SMB_CTXT_BUFSZ;
367*7052Samw 	svc->in_iov.iov_base = svc->in_buf;
368*7052Samw 	svc->in_iov.iov_len = SMB_CTXT_BUFSZ;
3695772Sas200622 }
3705772Sas200622 
3715772Sas200622 /*
372*7052Samw  * Flush the output data stream.
3735772Sas200622  */
374*7052Samw static void
375*7052Samw ndr_s_flush(struct mlsvc_rpc_context *svc)
3765772Sas200622 {
377*7052Samw 	ndr_frag_t *frag;
3785772Sas200622 
379*7052Samw 	while ((frag = svc->frags.head) != NULL) {
380*7052Samw 		svc->frags.head = frag->next;
381*7052Samw 		free(frag);
3825772Sas200622 	}
3835772Sas200622 
384*7052Samw 	free(svc->frags.iov);
385*7052Samw 	bzero(&svc->frags, sizeof (ndr_fraglist_t));
386*7052Samw }
387*7052Samw 
388*7052Samw /*
389*7052Samw  * Check whether or not the specified user has administrator privileges,
390*7052Samw  * i.e. is a member of Domain Admins or Administrators.
391*7052Samw  * Returns true if the user is an administrator, otherwise returns false.
392*7052Samw  */
393*7052Samw boolean_t
394*7052Samw ndr_is_admin(ndr_xa_t *xa)
395*7052Samw {
396*7052Samw 	smb_opipe_context_t *svc = &xa->context->svc_ctx;
397*7052Samw 
398*7052Samw 	return (svc->oc_flags & SMB_ATF_ADMIN);
399*7052Samw }
400*7052Samw 
401*7052Samw /*
402*7052Samw  * Check whether or not the specified user has power-user privileges,
403*7052Samw  * i.e. is a member of Domain Admins, Administrators or Power Users.
404*7052Samw  * This is typically required for operations such as managing shares.
405*7052Samw  * Returns true if the user is a power user, otherwise returns false.
406*7052Samw  */
407*7052Samw boolean_t
408*7052Samw ndr_is_poweruser(ndr_xa_t *xa)
409*7052Samw {
410*7052Samw 	smb_opipe_context_t *svc = &xa->context->svc_ctx;
411*7052Samw 
412*7052Samw 	return ((svc->oc_flags & SMB_ATF_ADMIN) ||
413*7052Samw 	    (svc->oc_flags & SMB_ATF_POWERUSER));
414*7052Samw }
415*7052Samw 
416*7052Samw int32_t
417*7052Samw ndr_native_os(ndr_xa_t *xa)
418*7052Samw {
419*7052Samw 	smb_opipe_context_t *svc = &xa->context->svc_ctx;
420*7052Samw 
421*7052Samw 	return (svc->oc_native_os);
4225772Sas200622 }
4235772Sas200622 
4245772Sas200622 /*
4255772Sas200622  * This is the entry point for all server-side RPC processing.
4265772Sas200622  * It is assumed that the PDU has already been received.
4275772Sas200622  */
4285772Sas200622 static int
4295772Sas200622 mlrpc_s_process(struct mlrpc_xaction *mxa)
4305772Sas200622 {
4315772Sas200622 	int rc;
4325772Sas200622 
4335772Sas200622 	rc = mlrpc_decode_pdu_hdr(mxa);
4345772Sas200622 	if (!MLRPC_DRC_IS_OK(rc))
4355772Sas200622 		return (-1);
4365772Sas200622 
4375772Sas200622 	(void) mlrpc_reply_prepare_hdr(mxa);
4385772Sas200622 
4395772Sas200622 	switch (mxa->ptype) {
4405772Sas200622 	case MLRPC_PTYPE_BIND:
4415772Sas200622 		rc = mlrpc_s_bind(mxa);
4425772Sas200622 		break;
4435772Sas200622 
4445772Sas200622 	case MLRPC_PTYPE_REQUEST:
4455772Sas200622 		rc = mlrpc_s_request(mxa);
4465772Sas200622 		break;
4475772Sas200622 
4485772Sas200622 	case MLRPC_PTYPE_ALTER_CONTEXT:
4495772Sas200622 		rc = mlrpc_s_alter_context(mxa);
4505772Sas200622 		break;
4515772Sas200622 
4525772Sas200622 	default:
4535772Sas200622 		rc = MLRPC_DRC_FAULT_RPCHDR_PTYPE_INVALID;
4545772Sas200622 		break;
4555772Sas200622 	}
4565772Sas200622 
4575772Sas200622 	if (MLRPC_DRC_IS_FAULT(rc))
4585772Sas200622 		mlrpc_reply_fault(mxa, rc);
4595772Sas200622 
4605772Sas200622 	(void) mlrpc_build_reply(mxa);
4615772Sas200622 	return (rc);
4625772Sas200622 }
4635772Sas200622 
4645772Sas200622 /*
4655772Sas200622  * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple
4665772Sas200622  * p_results[] not supported.
4675772Sas200622  */
4685772Sas200622 static int
4695772Sas200622 mlrpc_s_bind(struct mlrpc_xaction *mxa)
4705772Sas200622 {
4715772Sas200622 	mlrpc_p_cont_list_t	*cont_list;
4725772Sas200622 	mlrpc_p_result_list_t	*result_list;
4735772Sas200622 	mlrpc_p_result_t	*result;
4745772Sas200622 	unsigned		p_cont_id;
4755772Sas200622 	struct mlrpc_binding	*mbind;
4765772Sas200622 	ndr_uuid_t		*as_uuid;
4775772Sas200622 	ndr_uuid_t		*ts_uuid;
4785772Sas200622 	char			as_buf[64];
4795772Sas200622 	char			ts_buf[64];
4805772Sas200622 	int			as_vers;
4815772Sas200622 	int			ts_vers;
4825772Sas200622 	struct mlndr_stream	*send_mlnds;
4835772Sas200622 	struct mlrpc_service	*msvc;
4845772Sas200622 	int			rc;
4855772Sas200622 	mlrpc_port_any_t	*sec_addr;
4865772Sas200622 
4875772Sas200622 	/* acquire targets */
4885772Sas200622 	cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem;
4895772Sas200622 	result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list;
4905772Sas200622 	result = &result_list->p_results[0];
4915772Sas200622 
4925772Sas200622 	/*
4935772Sas200622 	 * Set up temporary secondary address port.
4945772Sas200622 	 * We will correct this later (below).
4955772Sas200622 	 */
4965772Sas200622 	send_mlnds = &mxa->send_mlnds;
4975772Sas200622 	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
4985772Sas200622 	sec_addr->length = 13;
4995772Sas200622 	(void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs");
5005772Sas200622 
5015772Sas200622 	result_list->n_results = 1;
5025772Sas200622 	result_list->reserved = 0;
5035772Sas200622 	result_list->reserved2 = 0;
5045772Sas200622 	result->result = MLRPC_PCDR_ACCEPTANCE;
5055772Sas200622 	result->reason = 0;
5065772Sas200622 	bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
5075772Sas200622 
5085772Sas200622 	/* sanity check */
5095772Sas200622 	if (cont_list->n_context_elem != 1 ||
5105772Sas200622 	    cont_list->p_cont_elem[0].n_transfer_syn != 1) {
5115772Sas200622 		mlndo_trace("mlrpc_s_bind: warning: multiple p_cont_elem");
5125772Sas200622 	}
5135772Sas200622 
5145772Sas200622 	p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
5155772Sas200622 
5165772Sas200622 	if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) != NULL) {
5175772Sas200622 		/*
5185772Sas200622 		 * Duplicate p_cont_id.
5195772Sas200622 		 * Send a bind_ack with a better error.
5205772Sas200622 		 */
5215772Sas200622 		mlndo_trace("mlrpc_s_bind: duplicate binding");
5225772Sas200622 		return (MLRPC_DRC_FAULT_BIND_PCONT_BUSY);
5235772Sas200622 	}
5245772Sas200622 
5255772Sas200622 	if ((mbind = mlrpc_new_binding(mxa)) == NULL) {
5265772Sas200622 		/*
5275772Sas200622 		 * No free binding slot
5285772Sas200622 		 */
5295772Sas200622 		result->result = MLRPC_PCDR_PROVIDER_REJECTION;
5305772Sas200622 		result->reason = MLRPC_PPR_LOCAL_LIMIT_EXCEEDED;
5315772Sas200622 		mlndo_trace("mlrpc_s_bind: no resources");
5325772Sas200622 		return (MLRPC_DRC_OK);
5335772Sas200622 	}
5345772Sas200622 
5355772Sas200622 	as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
5365772Sas200622 	as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
5375772Sas200622 
5385772Sas200622 	ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
5395772Sas200622 	ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
5405772Sas200622 
5415772Sas200622 	msvc = mlrpc_find_service_by_uuids(as_uuid, as_vers, ts_uuid, ts_vers);
5425772Sas200622 	if (!msvc) {
5435772Sas200622 		mlrpc_uuid_to_str(as_uuid, as_buf);
5445772Sas200622 		mlrpc_uuid_to_str(ts_uuid, ts_buf);
5455772Sas200622 
5465772Sas200622 		mlndo_printf(send_mlnds, 0, "mlrpc_s_bind: unknown service");
5475772Sas200622 		mlndo_printf(send_mlnds, 0, "abs=%s v%d, xfer=%s v%d",
5485772Sas200622 		    as_buf, as_vers, ts_buf, ts_vers);
5495772Sas200622 
5505772Sas200622 		result->result = MLRPC_PCDR_PROVIDER_REJECTION;
5515772Sas200622 		result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
5525772Sas200622 		return (MLRPC_DRC_OK);
5535772Sas200622 	}
5545772Sas200622 
5555772Sas200622 	/*
5565772Sas200622 	 * We can now use the correct secondary address port.
5575772Sas200622 	 */
5585772Sas200622 	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
5595772Sas200622 	sec_addr->length = strlen(msvc->sec_addr_port) + 1;
5605772Sas200622 	(void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port,
5615772Sas200622 	    MLRPC_PORT_ANY_MAX_PORT_SPEC);
5625772Sas200622 
5635772Sas200622 	mbind->p_cont_id = p_cont_id;
5645772Sas200622 	mbind->which_side = MLRPC_BIND_SIDE_SERVER;
5655772Sas200622 	/* mbind->context set by app */
5665772Sas200622 	mbind->service = msvc;
5675772Sas200622 	mbind->instance_specific = 0;
5685772Sas200622 
5695772Sas200622 	mxa->binding = mbind;
5705772Sas200622 
5715772Sas200622 	if (msvc->bind_req) {
5725772Sas200622 		/*
5735772Sas200622 		 * Call the service-specific bind() handler.  If
5745772Sas200622 		 * this fails, we shouild send a specific error
5755772Sas200622 		 * on the bind ack.
5765772Sas200622 		 */
5775772Sas200622 		rc = (msvc->bind_req)(mxa);
5785772Sas200622 		if (MLRPC_DRC_IS_FAULT(rc)) {
5795772Sas200622 			mbind->service = 0;	/* free binding slot */
5805772Sas200622 			mbind->which_side = 0;
5815772Sas200622 			mbind->p_cont_id = 0;
5825772Sas200622 			mbind->instance_specific = 0;
5835772Sas200622 			return (rc);
5845772Sas200622 		}
5855772Sas200622 	}
5865772Sas200622 
5875772Sas200622 	result->transfer_syntax =
5885772Sas200622 	    cont_list->p_cont_elem[0].transfer_syntaxes[0];
5895772Sas200622 
5905772Sas200622 	/*
5915772Sas200622 	 * Special rejection of Windows 2000 DSSETUP interface.
5925772Sas200622 	 * This interface was introduced in Windows 2000 but has
5935772Sas200622 	 * been subsequently deprecated due to problems.
5945772Sas200622 	 */
5955772Sas200622 	if (strcmp(msvc->name, "DSSETUP") == 0) {
5965772Sas200622 		result->result = MLRPC_PCDR_PROVIDER_REJECTION;
5975772Sas200622 		result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
5985772Sas200622 	}
5995772Sas200622 
6005772Sas200622 	return (MLRPC_DRC_BINDING_MADE);
6015772Sas200622 }
6025772Sas200622 
6035772Sas200622 /*
6045772Sas200622  * mlrpc_s_alter_context
6055772Sas200622  *
6065772Sas200622  * The alter context request is used to request additional presentation
6075772Sas200622  * context for another interface and/or version. It's very similar to a
6085772Sas200622  * bind request.
6095772Sas200622  *
6105772Sas200622  * We don't fully support multiple contexts so, for now, we reject this
6115772Sas200622  * request.  Windows 2000 clients attempt to use an alternate LSA context
6125772Sas200622  * when ACLs are modified.
6135772Sas200622  */
6145772Sas200622 static int
6155772Sas200622 mlrpc_s_alter_context(struct mlrpc_xaction *mxa)
6165772Sas200622 {
6175772Sas200622 	mlrpc_p_result_list_t *result_list;
6185772Sas200622 	mlrpc_p_result_t *result;
6195772Sas200622 	mlrpc_p_cont_list_t *cont_list;
6205772Sas200622 	struct mlrpc_binding *mbind;
6215772Sas200622 	struct mlrpc_service *msvc;
6225772Sas200622 	unsigned p_cont_id;
6235772Sas200622 	ndr_uuid_t *as_uuid;
6245772Sas200622 	ndr_uuid_t *ts_uuid;
6255772Sas200622 	int as_vers;
6265772Sas200622 	int ts_vers;
6275772Sas200622 	mlrpc_port_any_t *sec_addr;
6285772Sas200622 
6295772Sas200622 	result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list;
6305772Sas200622 	result_list->n_results = 1;
6315772Sas200622 	result_list->reserved = 0;
6325772Sas200622 	result_list->reserved2 = 0;
6335772Sas200622 
6345772Sas200622 	result = &result_list->p_results[0];
6355772Sas200622 	result->result = MLRPC_PCDR_ACCEPTANCE;
6365772Sas200622 	result->reason = 0;
6375772Sas200622 	bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
6385772Sas200622 
6395772Sas200622 	if (mxa != NULL) {
6405772Sas200622 		result->result = MLRPC_PCDR_PROVIDER_REJECTION;
6415772Sas200622 		result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
6425772Sas200622 		return (MLRPC_DRC_OK);
6435772Sas200622 	}
6445772Sas200622 
6455772Sas200622 	cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem;
6465772Sas200622 	p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
6475772Sas200622 
6485772Sas200622 	if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) != NULL)
6495772Sas200622 		return (MLRPC_DRC_FAULT_BIND_PCONT_BUSY);
6505772Sas200622 
6515772Sas200622 	if ((mbind = mlrpc_new_binding(mxa)) == NULL) {
6525772Sas200622 		result->result = MLRPC_PCDR_PROVIDER_REJECTION;
6535772Sas200622 		result->reason = MLRPC_PPR_LOCAL_LIMIT_EXCEEDED;
6545772Sas200622 		return (MLRPC_DRC_OK);
6555772Sas200622 	}
6565772Sas200622 
6575772Sas200622 	as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
6585772Sas200622 	as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
6595772Sas200622 
6605772Sas200622 	ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
6615772Sas200622 	ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
6625772Sas200622 
6635772Sas200622 	msvc = mlrpc_find_service_by_uuids(as_uuid, as_vers, ts_uuid, ts_vers);
6645772Sas200622 	if (msvc == 0) {
6655772Sas200622 		result->result = MLRPC_PCDR_PROVIDER_REJECTION;
6665772Sas200622 		result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
6675772Sas200622 		return (MLRPC_DRC_OK);
6685772Sas200622 	}
6695772Sas200622 
6705772Sas200622 	mbind->p_cont_id = p_cont_id;
6715772Sas200622 	mbind->which_side = MLRPC_BIND_SIDE_SERVER;
6725772Sas200622 	/* mbind->context set by app */
6735772Sas200622 	mbind->service = msvc;
6745772Sas200622 	mbind->instance_specific = 0;
6755772Sas200622 	mxa->binding = mbind;
6765772Sas200622 
6775772Sas200622 	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
6785772Sas200622 	sec_addr->length = 0;
6795772Sas200622 	bzero(sec_addr->port_spec, MLRPC_PORT_ANY_MAX_PORT_SPEC);
6805772Sas200622 
6815772Sas200622 	result->transfer_syntax =
6825772Sas200622 	    cont_list->p_cont_elem[0].transfer_syntaxes[0];
6835772Sas200622 
6845772Sas200622 	return (MLRPC_DRC_BINDING_MADE);
6855772Sas200622 }
6865772Sas200622 
6875772Sas200622 static int
6885772Sas200622 mlrpc_s_request(struct mlrpc_xaction *mxa)
6895772Sas200622 {
6905772Sas200622 	struct mlrpc_binding	*mbind;
6915772Sas200622 	struct mlrpc_service	*msvc;
6925772Sas200622 	unsigned		p_cont_id;
6935772Sas200622 	int			rc;
6945772Sas200622 
6955772Sas200622 	mxa->opnum = mxa->recv_hdr.request_hdr.opnum;
6965772Sas200622 	p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id;
6975772Sas200622 
6985772Sas200622 	if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) == NULL)
6995772Sas200622 		return (MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID);
7005772Sas200622 
7015772Sas200622 	mxa->binding = mbind;
7025772Sas200622 	msvc = mbind->service;
7035772Sas200622 
7045772Sas200622 	/*
7055772Sas200622 	 * Make room for the response hdr.
7065772Sas200622 	 */
7075772Sas200622 	mxa->send_mlnds.pdu_scan_offset = MLRPC_RSP_HDR_SIZE;
7085772Sas200622 
7095772Sas200622 	if (msvc->call_stub)
7105772Sas200622 		rc = (*msvc->call_stub)(mxa);
7115772Sas200622 	else
7125772Sas200622 		rc = mlrpc_generic_call_stub(mxa);
7135772Sas200622 
7145772Sas200622 	if (MLRPC_DRC_IS_FAULT(rc)) {
7155772Sas200622 		mlndo_printf(0, 0, "%s[0x%02x]: 0x%04x",
7165772Sas200622 		    msvc->name, mxa->opnum, rc);
7175772Sas200622 	}
7185772Sas200622 
7195772Sas200622 	return (rc);
7205772Sas200622 }
7215772Sas200622 
7225772Sas200622 /*
7235772Sas200622  * The transaction and the two mlnds streams use the same heap, which
7245772Sas200622  * should already exist at this point.  The heap will also be available
7255772Sas200622  * to the stub.
7265772Sas200622  */
7275772Sas200622 int
7285772Sas200622 mlrpc_generic_call_stub(struct mlrpc_xaction *mxa)
7295772Sas200622 {
7305772Sas200622 	struct mlrpc_binding 	*mbind = mxa->binding;
7315772Sas200622 	struct mlrpc_service 	*msvc = mbind->service;
7325772Sas200622 	struct ndr_typeinfo 	*intf_ti = msvc->interface_ti;
7335772Sas200622 	struct mlrpc_stub_table *ste;
7345772Sas200622 	int			opnum = mxa->opnum;
7355772Sas200622 	unsigned		p_len = intf_ti->c_size_fixed_part;
7365772Sas200622 	char 			*param;
7375772Sas200622 	int			rc;
7385772Sas200622 
7395772Sas200622 	if (mxa->heap == NULL) {
7405772Sas200622 		mlndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum);
7415772Sas200622 		return (MLRPC_DRC_FAULT_OUT_OF_MEMORY);
7425772Sas200622 	}
7435772Sas200622 
7445772Sas200622 	if ((ste = mlrpc_find_stub_in_svc(msvc, opnum)) == NULL) {
7455772Sas200622 		mlndo_printf(0, 0, "%s[0x%02x]: invalid opnum",
7465772Sas200622 		    msvc->name, opnum);
7475772Sas200622 		return (MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID);
7485772Sas200622 	}
7495772Sas200622 
7505772Sas200622 	if ((param = mlrpc_heap_malloc(mxa->heap, p_len)) == NULL)
7515772Sas200622 		return (MLRPC_DRC_FAULT_OUT_OF_MEMORY);
7525772Sas200622 
7535772Sas200622 	bzero(param, p_len);
7545772Sas200622 
7555772Sas200622 	rc = mlrpc_decode_call(mxa, param);
7565772Sas200622 	if (!MLRPC_DRC_IS_OK(rc))
7575772Sas200622 		return (rc);
7585772Sas200622 
7595772Sas200622 	rc = (*ste->func)(param, mxa);
7605772Sas200622 	if (rc == MLRPC_DRC_OK)
7615772Sas200622 		rc = mlrpc_encode_return(mxa, param);
7625772Sas200622 
7635772Sas200622 	return (rc);
7645772Sas200622 }
7655772Sas200622 
7665772Sas200622 /*
7675772Sas200622  * We can perform some initial setup of the response header here.
7685772Sas200622  * We also need to cache some of the information from the bind
7695772Sas200622  * negotiation for use during subsequent RPC calls.
7705772Sas200622  */
7715772Sas200622 static void
7725772Sas200622 mlrpc_reply_prepare_hdr(struct mlrpc_xaction *mxa)
7735772Sas200622 {
7745772Sas200622 	mlrpcconn_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
7755772Sas200622 	mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr;
7765772Sas200622 
7775772Sas200622 	hdr->rpc_vers = 5;
7785772Sas200622 	hdr->rpc_vers_minor = 0;
7795772Sas200622 	hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG;
7805772Sas200622 	hdr->packed_drep = rhdr->packed_drep;
7815772Sas200622 	hdr->frag_length = 0;
7825772Sas200622 	hdr->auth_length = 0;
7835772Sas200622 	hdr->call_id = rhdr->call_id;
7845772Sas200622 #ifdef _BIG_ENDIAN
7855772Sas200622 	hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII
7865772Sas200622 	    | MLRPC_REPLAB_INTG_BIG_ENDIAN;
7875772Sas200622 #else
7885772Sas200622 	hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII
7895772Sas200622 	    | MLRPC_REPLAB_INTG_LITTLE_ENDIAN;
7905772Sas200622 #endif
7915772Sas200622 
7925772Sas200622 	switch (mxa->ptype) {
7935772Sas200622 	case MLRPC_PTYPE_BIND:
7945772Sas200622 		hdr->ptype = MLRPC_PTYPE_BIND_ACK;
7955772Sas200622 		mxa->send_hdr.bind_ack_hdr.max_xmit_frag =
7965772Sas200622 		    mxa->recv_hdr.bind_hdr.max_xmit_frag;
7975772Sas200622 		mxa->send_hdr.bind_ack_hdr.max_recv_frag =
7985772Sas200622 		    mxa->recv_hdr.bind_hdr.max_recv_frag;
7995772Sas200622 		mxa->send_hdr.bind_ack_hdr.assoc_group_id =
8005772Sas200622 		    mxa->recv_hdr.bind_hdr.assoc_group_id;
8015772Sas200622 
8025772Sas200622 		if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0)
8035772Sas200622 			mxa->send_hdr.bind_ack_hdr.assoc_group_id = time(0);
8045772Sas200622 
8055772Sas200622 		/*
8065772Sas200622 		 * Save the maximum fragment sizes
8075772Sas200622 		 * for use with subsequent requests.
8085772Sas200622 		 */
8095772Sas200622 		mxa->context->max_xmit_frag =
8105772Sas200622 		    mxa->recv_hdr.bind_hdr.max_xmit_frag;
8115772Sas200622 
8125772Sas200622 		mxa->context->max_recv_frag =
8135772Sas200622 		    mxa->recv_hdr.bind_hdr.max_recv_frag;
8145772Sas200622 
8155772Sas200622 		break;
8165772Sas200622 
8175772Sas200622 	case MLRPC_PTYPE_REQUEST:
8185772Sas200622 		hdr->ptype = MLRPC_PTYPE_RESPONSE;
8195772Sas200622 		/* mxa->send_hdr.response_hdr.alloc_hint */
8205772Sas200622 		mxa->send_hdr.response_hdr.p_cont_id =
8215772Sas200622 		    mxa->recv_hdr.request_hdr.p_cont_id;
8225772Sas200622 		mxa->send_hdr.response_hdr.cancel_count = 0;
8235772Sas200622 		mxa->send_hdr.response_hdr.reserved = 0;
8245772Sas200622 		break;
8255772Sas200622 
8265772Sas200622 	case MLRPC_PTYPE_ALTER_CONTEXT:
8275772Sas200622 		hdr->ptype = MLRPC_PTYPE_ALTER_CONTEXT_RESP;
8285772Sas200622 		/*
8295772Sas200622 		 * The max_xmit_frag, max_recv_frag
8305772Sas200622 		 * and assoc_group_id are ignored.
8315772Sas200622 		 */
8325772Sas200622 		break;
8335772Sas200622 
8345772Sas200622 	default:
8355772Sas200622 		hdr->ptype = 0xFF;
8365772Sas200622 	}
8375772Sas200622 }
8385772Sas200622 
8395772Sas200622 /*
8405772Sas200622  * Finish and encode the bind acknowledge (MLRPC_PTYPE_BIND_ACK) header.
8415772Sas200622  * The frag_length is different from a regular RPC response.
8425772Sas200622  */
8435772Sas200622 static void
8445772Sas200622 mlrpc_reply_bind_ack(struct mlrpc_xaction *mxa)
8455772Sas200622 {
8465772Sas200622 	mlrpcconn_common_header_t	*hdr;
8475772Sas200622 	mlrpcconn_bind_ack_hdr_t	*bahdr;
8485772Sas200622 
8495772Sas200622 	hdr = &mxa->send_hdr.common_hdr;
8505772Sas200622 	bahdr = &mxa->send_hdr.bind_ack_hdr;
8515772Sas200622 	hdr->frag_length = mlrpc_bind_ack_hdr_size(bahdr);
8525772Sas200622 }
8535772Sas200622 
8545772Sas200622 /*
8555772Sas200622  * Signal an RPC fault. The stream is reset and we overwrite whatever
8565772Sas200622  * was in the response header with the fault information.
8575772Sas200622  */
8585772Sas200622 static void
8595772Sas200622 mlrpc_reply_fault(struct mlrpc_xaction *mxa, unsigned long drc)
8605772Sas200622 {
8615772Sas200622 	mlrpcconn_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
8625772Sas200622 	mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr;
8635772Sas200622 	struct mlndr_stream *mlnds = &mxa->send_mlnds;
8645772Sas200622 	unsigned long fault_status;
8655772Sas200622 
8665772Sas200622 	MLNDS_RESET(mlnds);
8675772Sas200622 
8685772Sas200622 	hdr->rpc_vers = 5;
8695772Sas200622 	hdr->rpc_vers_minor = 0;
8705772Sas200622 	hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG;
8715772Sas200622 	hdr->packed_drep = rhdr->packed_drep;
8725772Sas200622 	hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr);
8735772Sas200622 	hdr->auth_length = 0;
8745772Sas200622 	hdr->call_id = rhdr->call_id;
8755772Sas200622 #ifdef _BIG_ENDIAN
8765772Sas200622 	hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII
8775772Sas200622 	    | MLRPC_REPLAB_INTG_BIG_ENDIAN;
8785772Sas200622 #else
8795772Sas200622 	hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII
8805772Sas200622 	    | MLRPC_REPLAB_INTG_LITTLE_ENDIAN;
8815772Sas200622 #endif
8825772Sas200622 
8835772Sas200622 	switch (drc & MLRPC_DRC_MASK_SPECIFIER) {
8845772Sas200622 	case MLRPC_DRC_FAULT_OUT_OF_MEMORY:
8855772Sas200622 	case MLRPC_DRC_FAULT_ENCODE_TOO_BIG:
8865772Sas200622 		fault_status = MLRPC_FAULT_NCA_OUT_ARGS_TOO_BIG;
8875772Sas200622 		break;
8885772Sas200622 
8895772Sas200622 	case MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID:
8905772Sas200622 		fault_status = MLRPC_FAULT_NCA_INVALID_PRES_CONTEXT_ID;
8915772Sas200622 		break;
8925772Sas200622 
8935772Sas200622 	case MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID:
8945772Sas200622 		fault_status = MLRPC_FAULT_NCA_OP_RNG_ERROR;
8955772Sas200622 		break;
8965772Sas200622 
8975772Sas200622 	case MLRPC_DRC_FAULT_DECODE_FAILED:
8985772Sas200622 	case MLRPC_DRC_FAULT_ENCODE_FAILED:
8995772Sas200622 		fault_status = MLRPC_FAULT_NCA_PROTO_ERROR;
9005772Sas200622 		break;
9015772Sas200622 
9025772Sas200622 	default:
9035772Sas200622 		fault_status = MLRPC_FAULT_NCA_UNSPEC_REJECT;
9045772Sas200622 		break;
9055772Sas200622 	}
9065772Sas200622 
9075772Sas200622 	mxa->send_hdr.fault_hdr.common_hdr.ptype = MLRPC_PTYPE_FAULT;
9085772Sas200622 	mxa->send_hdr.fault_hdr.status = fault_status;
9095772Sas200622 	mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length;
9105772Sas200622 }
9115772Sas200622 
9125772Sas200622 static int
9135772Sas200622 mlrpc_build_reply(struct mlrpc_xaction *mxa)
9145772Sas200622 {
9155772Sas200622 	mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr;
9165772Sas200622 	struct mlndr_stream *mlnds = &mxa->send_mlnds;
9176482Samw 	uint8_t *pdu_buf;
9185772Sas200622 	unsigned long pdu_size;
9195772Sas200622 	unsigned long frag_size;
9205772Sas200622 	unsigned long pdu_data_size;
9215772Sas200622 	unsigned long frag_data_size;
9225772Sas200622 
9235772Sas200622 	frag_size = mlrpc_frag_size;
9245772Sas200622 	pdu_size = mlnds->pdu_size;
9256482Samw 	pdu_buf = mlnds->pdu_base_addr;
9265772Sas200622 
9275772Sas200622 	if (pdu_size <= frag_size) {
9285772Sas200622 		/*
9295772Sas200622 		 * Single fragment response. The PDU size may be zero
9305772Sas200622 		 * here (i.e. bind or fault response). So don't make
9315772Sas200622 		 * any assumptions about it until after the header is
9325772Sas200622 		 * encoded.
9335772Sas200622 		 */
9345772Sas200622 		switch (hdr->ptype) {
9355772Sas200622 		case MLRPC_PTYPE_BIND_ACK:
9365772Sas200622 			mlrpc_reply_bind_ack(mxa);
9375772Sas200622 			break;
9385772Sas200622 
9395772Sas200622 		case MLRPC_PTYPE_FAULT:
9405772Sas200622 			/* already setup */
9415772Sas200622 			break;
9425772Sas200622 
9435772Sas200622 		case MLRPC_PTYPE_RESPONSE:
9445772Sas200622 			hdr->frag_length = pdu_size;
9455772Sas200622 			mxa->send_hdr.response_hdr.alloc_hint =
9465772Sas200622 			    hdr->frag_length;
9475772Sas200622 			break;
9485772Sas200622 
9495772Sas200622 		default:
9505772Sas200622 			hdr->frag_length = pdu_size;
9515772Sas200622 			break;
9525772Sas200622 		}
9535772Sas200622 
9545772Sas200622 		mlnds->pdu_scan_offset = 0;
9555772Sas200622 		(void) mlrpc_encode_pdu_hdr(mxa);
9566482Samw 		pdu_size = mlnds->pdu_size;
9576482Samw 		mlrpc_build_frag(mlnds, pdu_buf,  pdu_size);
9585772Sas200622 		return (0);
9595772Sas200622 	}
9605772Sas200622 
9615772Sas200622 	/*
9625772Sas200622 	 * Multiple fragment response.
9635772Sas200622 	 */
9645772Sas200622 	hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG;
9655772Sas200622 	hdr->frag_length = frag_size;
9665772Sas200622 	mxa->send_hdr.response_hdr.alloc_hint = pdu_size - MLRPC_RSP_HDR_SIZE;
9675772Sas200622 	mlnds->pdu_scan_offset = 0;
9685772Sas200622 	(void) mlrpc_encode_pdu_hdr(mxa);
9696482Samw 	mlrpc_build_frag(mlnds, pdu_buf,  frag_size);
9705772Sas200622 
9715772Sas200622 	/*
9725772Sas200622 	 * We need to update the 24-byte header in subsequent fragments.
9735772Sas200622 	 *
9746482Samw 	 * pdu_data_size:	total data remaining to be handled
9756482Samw 	 * frag_size:		total fragment size including header
9766482Samw 	 * frag_data_size:	data in fragment
9775772Sas200622 	 *			(i.e. frag_size - MLRPC_RSP_HDR_SIZE)
9785772Sas200622 	 */
9795772Sas200622 	pdu_data_size = pdu_size - MLRPC_RSP_HDR_SIZE;
9805772Sas200622 	frag_data_size = frag_size - MLRPC_RSP_HDR_SIZE;
9815772Sas200622 
9826482Samw 	while (pdu_data_size) {
9836482Samw 		mxa->send_hdr.response_hdr.alloc_hint -= frag_data_size;
9846482Samw 		pdu_data_size -= frag_data_size;
9856482Samw 		pdu_buf += frag_data_size;
9865772Sas200622 
9876482Samw 		if (pdu_data_size <= frag_data_size) {
9886482Samw 			frag_data_size = pdu_data_size;
9896482Samw 			frag_size = frag_data_size + MLRPC_RSP_HDR_SIZE;
9906482Samw 			hdr->pfc_flags = MLRPC_PFC_LAST_FRAG;
9915772Sas200622 		} else {
9926482Samw 			hdr->pfc_flags = 0;
9935772Sas200622 		}
9945772Sas200622 
9956482Samw 		hdr->frag_length = frag_size;
9966482Samw 		mlnds->pdu_scan_offset = 0;
9976483Samw 		(void) mlrpc_encode_pdu_hdr(mxa);
9986482Samw 		bcopy(mlnds->pdu_base_addr, pdu_buf, MLRPC_RSP_HDR_SIZE);
9995772Sas200622 
10006482Samw 		mlrpc_build_frag(mlnds, pdu_buf, frag_size);
10015772Sas200622 
10026482Samw 		if (hdr->pfc_flags & MLRPC_PFC_LAST_FRAG)
10036482Samw 			break;
10045772Sas200622 	}
10055772Sas200622 
10065772Sas200622 	return (0);
10075772Sas200622 }
10086482Samw 
10096482Samw /*
10106482Samw  * mlrpc_build_frag
10116482Samw  *
10126482Samw  * Build an RPC PDU fragment from the specified buffer.
10136482Samw  * If malloc fails, the client will see a header/pdu inconsistency
10146482Samw  * and report an error.
10156482Samw  */
10166482Samw static void
10176482Samw mlrpc_build_frag(struct mlndr_stream *mlnds, uint8_t *buf, uint32_t len)
10186482Samw {
10196482Samw 	ndr_frag_t *frag;
10206482Samw 	int size = sizeof (ndr_frag_t) + len;
10216482Samw 
10226482Samw 	if ((frag = (ndr_frag_t *)malloc(size)) == NULL)
10236482Samw 		return;
10246482Samw 
10256482Samw 	frag->next = NULL;
10266482Samw 	frag->buf = (uint8_t *)frag + sizeof (ndr_frag_t);
10276482Samw 	frag->len = len;
10286482Samw 	bcopy(buf, frag->buf, len);
10296482Samw 
1030*7052Samw 	if (mlnds->frags.head == NULL) {
1031*7052Samw 		mlnds->frags.head = frag;
1032*7052Samw 		mlnds->frags.tail = frag;
1033*7052Samw 		mlnds->frags.nfrag = 1;
10346482Samw 	} else {
1035*7052Samw 		mlnds->frags.tail->next = frag;
1036*7052Samw 		mlnds->frags.tail = frag;
1037*7052Samw 		++mlnds->frags.nfrag;
10386482Samw 	}
10396482Samw }
1040