xref: /titanic_51/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c (revision 87c5f7b3eef6309c168257f261ac6ace4581d234)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Server side RPC handler.
30  */
31 
32 #include <sys/byteorder.h>
33 #include <sys/errno.h>
34 #include <sys/uio.h>
35 #include <thread.h>
36 #include <synch.h>
37 #include <stdlib.h>
38 #include <strings.h>
39 #include <string.h>
40 #include <time.h>
41 
42 #include <smbsrv/libsmb.h>
43 #include <smbsrv/libmlrpc.h>
44 #include <smbsrv/mlsvc.h>
45 #include <smbsrv/ndr.h>
46 #include <smbsrv/mlrpc.h>
47 #include <smbsrv/mlsvc_util.h>
48 
49 
50 #define	SMB_CTXT_BUFSZ		65536
51 
52 /*
53  * Fragment size (5680: NT style).
54  */
55 #define	MLRPC_FRAG_SZ		5680
56 static unsigned long mlrpc_frag_size = MLRPC_FRAG_SZ;
57 
58 /*
59  * Service context table.
60  */
61 #define	CTXT_TABLE_ENTRIES	128
62 static struct mlsvc_rpc_context context_table[CTXT_TABLE_ENTRIES];
63 static mutex_t mlrpc_context_lock;
64 
65 static int ndr_s_transact(struct mlsvc_rpc_context *);
66 static struct mlsvc_rpc_context *ndr_s_lookup(int);
67 static void ndr_s_release(struct mlsvc_rpc_context *);
68 static struct mlsvc_rpc_context *ndr_s_allocate(int);
69 static void ndr_s_deallocate(struct mlsvc_rpc_context *);
70 static void ndr_s_rewind(struct mlsvc_rpc_context *);
71 static void ndr_s_flush(struct mlsvc_rpc_context *);
72 
73 static int mlrpc_s_process(struct mlrpc_xaction *);
74 static int mlrpc_s_bind(struct mlrpc_xaction *);
75 static int mlrpc_s_request(struct mlrpc_xaction *);
76 static void mlrpc_reply_prepare_hdr(struct mlrpc_xaction *);
77 static int mlrpc_s_alter_context(struct mlrpc_xaction *);
78 static void mlrpc_reply_bind_ack(struct mlrpc_xaction *);
79 static void mlrpc_reply_fault(struct mlrpc_xaction *, unsigned long);
80 static int mlrpc_build_reply(struct mlrpc_xaction *);
81 static void mlrpc_build_frag(struct mlndr_stream *, uint8_t *, uint32_t);
82 
83 /*
84  * Allocate and associate a service context with a fid.
85  */
86 int
87 ndr_s_open(int fid, uint8_t *data, uint32_t datalen)
88 {
89 	struct mlsvc_rpc_context *svc;
90 
91 	(void) mutex_lock(&mlrpc_context_lock);
92 
93 	if ((svc = ndr_s_lookup(fid)) != NULL) {
94 		ndr_s_release(svc);
95 		(void) mutex_unlock(&mlrpc_context_lock);
96 		return (EEXIST);
97 	}
98 
99 	if ((svc = ndr_s_allocate(fid)) == NULL) {
100 		(void) mutex_unlock(&mlrpc_context_lock);
101 		return (ENOMEM);
102 	}
103 
104 	if (smb_opipe_context_decode(&svc->svc_ctx, data, datalen) == -1) {
105 		ndr_s_release(svc);
106 		(void) mutex_unlock(&mlrpc_context_lock);
107 		return (EINVAL);
108 	}
109 
110 	mlrpc_binding_pool_initialize(&svc->binding, svc->binding_pool,
111 	    CTXT_N_BINDING_POOL);
112 
113 	(void) mutex_unlock(&mlrpc_context_lock);
114 	return (0);
115 }
116 
117 /*
118  * Release the context associated with a fid when an opipe is closed.
119  */
120 int
121 ndr_s_close(int fid)
122 {
123 	struct mlsvc_rpc_context *svc;
124 
125 	(void) mutex_lock(&mlrpc_context_lock);
126 
127 	if ((svc = ndr_s_lookup(fid)) == NULL) {
128 		(void) mutex_unlock(&mlrpc_context_lock);
129 		return (ENOENT);
130 	}
131 
132 	/*
133 	 * Release twice: once for the lookup above
134 	 * and again to close the fid.
135 	 */
136 	ndr_s_release(svc);
137 	ndr_s_release(svc);
138 	(void) mutex_unlock(&mlrpc_context_lock);
139 	return (0);
140 }
141 
142 /*
143  * Write RPC request data to the input stream.  Input data is buffered
144  * until the response is requested.
145  */
146 int
147 ndr_s_write(int fid, uint8_t *buf, uint32_t len)
148 {
149 	struct mlsvc_rpc_context *svc;
150 	ssize_t nbytes;
151 
152 	if (len == 0)
153 		return (0);
154 
155 	(void) mutex_lock(&mlrpc_context_lock);
156 
157 	if ((svc = ndr_s_lookup(fid)) == NULL) {
158 		(void) mutex_unlock(&mlrpc_context_lock);
159 		return (ENOENT);
160 	}
161 
162 	nbytes = ndr_uiomove((caddr_t)buf, len, UIO_READ, &svc->in_uio);
163 
164 	ndr_s_release(svc);
165 	(void) mutex_unlock(&mlrpc_context_lock);
166 	return ((nbytes == len) ? 0 : EIO);
167 }
168 
169 /*
170  * Read RPC response data.  If the input stream contains an RPC request,
171  * we need to process the RPC transaction, which will place the RPC
172  * response in the output (frags) stream.  Otherwise, read data from
173  * the output stream.
174  */
175 int
176 ndr_s_read(int fid, uint8_t *buf, uint32_t *len, uint32_t *resid)
177 {
178 	struct mlsvc_rpc_context *svc;
179 	ssize_t nbytes = *len;
180 	int rc;
181 
182 	if (nbytes == 0) {
183 		*resid = 0;
184 		return (0);
185 	}
186 
187 	(void) mutex_lock(&mlrpc_context_lock);
188 	if ((svc = ndr_s_lookup(fid)) == NULL) {
189 		(void) mutex_unlock(&mlrpc_context_lock);
190 		return (ENOENT);
191 	}
192 	(void) mutex_unlock(&mlrpc_context_lock);
193 
194 	if (svc->in_uio.uio_offset) {
195 		if ((rc = ndr_s_transact(svc)) != 0) {
196 			ndr_s_flush(svc);
197 			(void) mutex_lock(&mlrpc_context_lock);
198 			ndr_s_release(svc);
199 			(void) mutex_unlock(&mlrpc_context_lock);
200 			return (rc);
201 		}
202 
203 	}
204 
205 	*len = ndr_uiomove((caddr_t)buf, nbytes, UIO_WRITE, &svc->frags.uio);
206 	*resid = svc->frags.uio.uio_resid;
207 
208 	if (*resid == 0) {
209 		/*
210 		 * Nothing left, cleanup the output stream.
211 		 */
212 		ndr_s_flush(svc);
213 	}
214 
215 	(void) mutex_lock(&mlrpc_context_lock);
216 	ndr_s_release(svc);
217 	(void) mutex_unlock(&mlrpc_context_lock);
218 	return (0);
219 }
220 
221 /*
222  * Process a server-side RPC request.
223  */
224 static int
225 ndr_s_transact(struct mlsvc_rpc_context *svc)
226 {
227 	ndr_xa_t			*mxa;
228 	struct mlndr_stream		*recv_mlnds;
229 	struct mlndr_stream		*send_mlnds;
230 	char				*data;
231 	int				datalen;
232 
233 	data = svc->in_buf;
234 	datalen = svc->in_uio.uio_offset;
235 
236 	if ((mxa = (ndr_xa_t *)malloc(sizeof (ndr_xa_t))) == NULL)
237 		return (ENOMEM);
238 
239 	bzero(mxa, sizeof (struct mlrpc_xaction));
240 	mxa->fid = svc->fid;
241 	mxa->context = svc;
242 	mxa->binding_list = svc->binding;
243 
244 	if ((mxa->heap = mlrpc_heap_create()) == NULL) {
245 		free(mxa);
246 		return (ENOMEM);
247 	}
248 
249 	recv_mlnds = &mxa->recv_mlnds;
250 	mlnds_initialize(recv_mlnds, datalen, NDR_MODE_CALL_RECV, mxa->heap);
251 
252 	/*
253 	 * Copy the input data and reset the input stream.
254 	 */
255 	bcopy(data, recv_mlnds->pdu_base_addr, datalen);
256 	ndr_s_rewind(svc);
257 
258 	send_mlnds = &mxa->send_mlnds;
259 	mlnds_initialize(send_mlnds, 0, NDR_MODE_RETURN_SEND, mxa->heap);
260 
261 	(void) mlrpc_s_process(mxa);
262 
263 	mlnds_finalize(send_mlnds, &svc->frags);
264 	mlnds_destruct(&mxa->recv_mlnds);
265 	mlnds_destruct(&mxa->send_mlnds);
266 	mlrpc_heap_destroy(mxa->heap);
267 	free(mxa);
268 	return (0);
269 }
270 
271 /*
272  * Must be called with mlrpc_context_lock held.
273  */
274 static struct mlsvc_rpc_context *
275 ndr_s_lookup(int fid)
276 {
277 	struct mlsvc_rpc_context *svc;
278 	int i;
279 
280 	for (i = 0; i < CTXT_TABLE_ENTRIES; ++i) {
281 		svc = &context_table[i];
282 
283 		if (svc->fid == fid) {
284 			if (svc->refcnt == 0)
285 				return (NULL);
286 
287 			svc->refcnt++;
288 			return (svc);
289 		}
290 	}
291 
292 	return (NULL);
293 }
294 
295 /*
296  * Must be called with mlrpc_context_lock held.
297  */
298 static void
299 ndr_s_release(struct mlsvc_rpc_context *svc)
300 {
301 	svc->refcnt--;
302 	ndr_s_deallocate(svc);
303 }
304 
305 /*
306  * Must be called with mlrpc_context_lock held.
307  */
308 static struct mlsvc_rpc_context *
309 ndr_s_allocate(int fid)
310 {
311 	struct mlsvc_rpc_context *svc = NULL;
312 	int i;
313 
314 	for (i = 0; i < CTXT_TABLE_ENTRIES; ++i) {
315 		svc = &context_table[i];
316 
317 		if (svc->fid == 0) {
318 			bzero(svc, sizeof (struct mlsvc_rpc_context));
319 
320 			if ((svc->in_buf = malloc(SMB_CTXT_BUFSZ)) == NULL)
321 				return (NULL);
322 
323 			ndr_s_rewind(svc);
324 			svc->fid = fid;
325 			svc->refcnt = 1;
326 			return (svc);
327 		}
328 	}
329 
330 	return (NULL);
331 }
332 
333 /*
334  * Must be called with mlrpc_context_lock held.
335  */
336 static void
337 ndr_s_deallocate(struct mlsvc_rpc_context *svc)
338 {
339 	if (svc->refcnt == 0) {
340 		/*
341 		 * Ensure that there are no RPC service policy handles
342 		 * (associated with this fid) left around.
343 		 */
344 		ndr_hdclose(svc->fid);
345 
346 		ndr_s_rewind(svc);
347 		ndr_s_flush(svc);
348 		free(svc->in_buf);
349 		free(svc->svc_ctx.oc_domain);
350 		free(svc->svc_ctx.oc_account);
351 		free(svc->svc_ctx.oc_workstation);
352 		bzero(svc, sizeof (struct mlsvc_rpc_context));
353 	}
354 }
355 
356 /*
357  * Rewind the input data stream, ready for the next write.
358  */
359 static void
360 ndr_s_rewind(struct mlsvc_rpc_context *svc)
361 {
362 	svc->in_uio.uio_iov = &svc->in_iov;
363 	svc->in_uio.uio_iovcnt = 1;
364 	svc->in_uio.uio_offset = 0;
365 	svc->in_uio.uio_segflg = UIO_USERSPACE;
366 	svc->in_uio.uio_resid = SMB_CTXT_BUFSZ;
367 	svc->in_iov.iov_base = svc->in_buf;
368 	svc->in_iov.iov_len = SMB_CTXT_BUFSZ;
369 }
370 
371 /*
372  * Flush the output data stream.
373  */
374 static void
375 ndr_s_flush(struct mlsvc_rpc_context *svc)
376 {
377 	ndr_frag_t *frag;
378 
379 	while ((frag = svc->frags.head) != NULL) {
380 		svc->frags.head = frag->next;
381 		free(frag);
382 	}
383 
384 	free(svc->frags.iov);
385 	bzero(&svc->frags, sizeof (ndr_fraglist_t));
386 }
387 
388 /*
389  * Check whether or not the specified user has administrator privileges,
390  * i.e. is a member of Domain Admins or Administrators.
391  * Returns true if the user is an administrator, otherwise returns false.
392  */
393 boolean_t
394 ndr_is_admin(ndr_xa_t *xa)
395 {
396 	smb_opipe_context_t *svc = &xa->context->svc_ctx;
397 
398 	return (svc->oc_flags & SMB_ATF_ADMIN);
399 }
400 
401 /*
402  * Check whether or not the specified user has power-user privileges,
403  * i.e. is a member of Domain Admins, Administrators or Power Users.
404  * This is typically required for operations such as managing shares.
405  * Returns true if the user is a power user, otherwise returns false.
406  */
407 boolean_t
408 ndr_is_poweruser(ndr_xa_t *xa)
409 {
410 	smb_opipe_context_t *svc = &xa->context->svc_ctx;
411 
412 	return ((svc->oc_flags & SMB_ATF_ADMIN) ||
413 	    (svc->oc_flags & SMB_ATF_POWERUSER));
414 }
415 
416 int32_t
417 ndr_native_os(ndr_xa_t *xa)
418 {
419 	smb_opipe_context_t *svc = &xa->context->svc_ctx;
420 
421 	return (svc->oc_native_os);
422 }
423 
424 /*
425  * This is the entry point for all server-side RPC processing.
426  * It is assumed that the PDU has already been received.
427  */
428 static int
429 mlrpc_s_process(struct mlrpc_xaction *mxa)
430 {
431 	int rc;
432 
433 	rc = mlrpc_decode_pdu_hdr(mxa);
434 	if (!MLRPC_DRC_IS_OK(rc))
435 		return (-1);
436 
437 	(void) mlrpc_reply_prepare_hdr(mxa);
438 
439 	switch (mxa->ptype) {
440 	case MLRPC_PTYPE_BIND:
441 		rc = mlrpc_s_bind(mxa);
442 		break;
443 
444 	case MLRPC_PTYPE_REQUEST:
445 		rc = mlrpc_s_request(mxa);
446 		break;
447 
448 	case MLRPC_PTYPE_ALTER_CONTEXT:
449 		rc = mlrpc_s_alter_context(mxa);
450 		break;
451 
452 	default:
453 		rc = MLRPC_DRC_FAULT_RPCHDR_PTYPE_INVALID;
454 		break;
455 	}
456 
457 	if (MLRPC_DRC_IS_FAULT(rc))
458 		mlrpc_reply_fault(mxa, rc);
459 
460 	(void) mlrpc_build_reply(mxa);
461 	return (rc);
462 }
463 
464 /*
465  * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple
466  * p_results[] not supported.
467  */
468 static int
469 mlrpc_s_bind(struct mlrpc_xaction *mxa)
470 {
471 	mlrpc_p_cont_list_t	*cont_list;
472 	mlrpc_p_result_list_t	*result_list;
473 	mlrpc_p_result_t	*result;
474 	unsigned		p_cont_id;
475 	struct mlrpc_binding	*mbind;
476 	ndr_uuid_t		*as_uuid;
477 	ndr_uuid_t		*ts_uuid;
478 	char			as_buf[64];
479 	char			ts_buf[64];
480 	int			as_vers;
481 	int			ts_vers;
482 	struct mlndr_stream	*send_mlnds;
483 	struct mlrpc_service	*msvc;
484 	int			rc;
485 	mlrpc_port_any_t	*sec_addr;
486 
487 	/* acquire targets */
488 	cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem;
489 	result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list;
490 	result = &result_list->p_results[0];
491 
492 	/*
493 	 * Set up temporary secondary address port.
494 	 * We will correct this later (below).
495 	 */
496 	send_mlnds = &mxa->send_mlnds;
497 	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
498 	sec_addr->length = 13;
499 	(void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs");
500 
501 	result_list->n_results = 1;
502 	result_list->reserved = 0;
503 	result_list->reserved2 = 0;
504 	result->result = MLRPC_PCDR_ACCEPTANCE;
505 	result->reason = 0;
506 	bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
507 
508 	/* sanity check */
509 	if (cont_list->n_context_elem != 1 ||
510 	    cont_list->p_cont_elem[0].n_transfer_syn != 1) {
511 		mlndo_trace("mlrpc_s_bind: warning: multiple p_cont_elem");
512 	}
513 
514 	p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
515 
516 	if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) != NULL) {
517 		/*
518 		 * Duplicate p_cont_id.
519 		 * Send a bind_ack with a better error.
520 		 */
521 		mlndo_trace("mlrpc_s_bind: duplicate binding");
522 		return (MLRPC_DRC_FAULT_BIND_PCONT_BUSY);
523 	}
524 
525 	if ((mbind = mlrpc_new_binding(mxa)) == NULL) {
526 		/*
527 		 * No free binding slot
528 		 */
529 		result->result = MLRPC_PCDR_PROVIDER_REJECTION;
530 		result->reason = MLRPC_PPR_LOCAL_LIMIT_EXCEEDED;
531 		mlndo_trace("mlrpc_s_bind: no resources");
532 		return (MLRPC_DRC_OK);
533 	}
534 
535 	as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
536 	as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
537 
538 	ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
539 	ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
540 
541 	msvc = mlrpc_find_service_by_uuids(as_uuid, as_vers, ts_uuid, ts_vers);
542 	if (!msvc) {
543 		mlrpc_uuid_to_str(as_uuid, as_buf);
544 		mlrpc_uuid_to_str(ts_uuid, ts_buf);
545 
546 		mlndo_printf(send_mlnds, 0, "mlrpc_s_bind: unknown service");
547 		mlndo_printf(send_mlnds, 0, "abs=%s v%d, xfer=%s v%d",
548 		    as_buf, as_vers, ts_buf, ts_vers);
549 
550 		result->result = MLRPC_PCDR_PROVIDER_REJECTION;
551 		result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
552 		return (MLRPC_DRC_OK);
553 	}
554 
555 	/*
556 	 * We can now use the correct secondary address port.
557 	 */
558 	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
559 	sec_addr->length = strlen(msvc->sec_addr_port) + 1;
560 	(void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port,
561 	    MLRPC_PORT_ANY_MAX_PORT_SPEC);
562 
563 	mbind->p_cont_id = p_cont_id;
564 	mbind->which_side = MLRPC_BIND_SIDE_SERVER;
565 	/* mbind->context set by app */
566 	mbind->service = msvc;
567 	mbind->instance_specific = 0;
568 
569 	mxa->binding = mbind;
570 
571 	if (msvc->bind_req) {
572 		/*
573 		 * Call the service-specific bind() handler.  If
574 		 * this fails, we shouild send a specific error
575 		 * on the bind ack.
576 		 */
577 		rc = (msvc->bind_req)(mxa);
578 		if (MLRPC_DRC_IS_FAULT(rc)) {
579 			mbind->service = 0;	/* free binding slot */
580 			mbind->which_side = 0;
581 			mbind->p_cont_id = 0;
582 			mbind->instance_specific = 0;
583 			return (rc);
584 		}
585 	}
586 
587 	result->transfer_syntax =
588 	    cont_list->p_cont_elem[0].transfer_syntaxes[0];
589 
590 	/*
591 	 * Special rejection of Windows 2000 DSSETUP interface.
592 	 * This interface was introduced in Windows 2000 but has
593 	 * been subsequently deprecated due to problems.
594 	 */
595 	if (strcmp(msvc->name, "DSSETUP") == 0) {
596 		result->result = MLRPC_PCDR_PROVIDER_REJECTION;
597 		result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
598 	}
599 
600 	return (MLRPC_DRC_BINDING_MADE);
601 }
602 
603 /*
604  * mlrpc_s_alter_context
605  *
606  * The alter context request is used to request additional presentation
607  * context for another interface and/or version. It's very similar to a
608  * bind request.
609  *
610  * We don't fully support multiple contexts so, for now, we reject this
611  * request.  Windows 2000 clients attempt to use an alternate LSA context
612  * when ACLs are modified.
613  */
614 static int
615 mlrpc_s_alter_context(struct mlrpc_xaction *mxa)
616 {
617 	mlrpc_p_result_list_t *result_list;
618 	mlrpc_p_result_t *result;
619 	mlrpc_p_cont_list_t *cont_list;
620 	struct mlrpc_binding *mbind;
621 	struct mlrpc_service *msvc;
622 	unsigned p_cont_id;
623 	ndr_uuid_t *as_uuid;
624 	ndr_uuid_t *ts_uuid;
625 	int as_vers;
626 	int ts_vers;
627 	mlrpc_port_any_t *sec_addr;
628 
629 	result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list;
630 	result_list->n_results = 1;
631 	result_list->reserved = 0;
632 	result_list->reserved2 = 0;
633 
634 	result = &result_list->p_results[0];
635 	result->result = MLRPC_PCDR_ACCEPTANCE;
636 	result->reason = 0;
637 	bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
638 
639 	if (mxa != NULL) {
640 		result->result = MLRPC_PCDR_PROVIDER_REJECTION;
641 		result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
642 		return (MLRPC_DRC_OK);
643 	}
644 
645 	cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem;
646 	p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
647 
648 	if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) != NULL)
649 		return (MLRPC_DRC_FAULT_BIND_PCONT_BUSY);
650 
651 	if ((mbind = mlrpc_new_binding(mxa)) == NULL) {
652 		result->result = MLRPC_PCDR_PROVIDER_REJECTION;
653 		result->reason = MLRPC_PPR_LOCAL_LIMIT_EXCEEDED;
654 		return (MLRPC_DRC_OK);
655 	}
656 
657 	as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
658 	as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
659 
660 	ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
661 	ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
662 
663 	msvc = mlrpc_find_service_by_uuids(as_uuid, as_vers, ts_uuid, ts_vers);
664 	if (msvc == 0) {
665 		result->result = MLRPC_PCDR_PROVIDER_REJECTION;
666 		result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
667 		return (MLRPC_DRC_OK);
668 	}
669 
670 	mbind->p_cont_id = p_cont_id;
671 	mbind->which_side = MLRPC_BIND_SIDE_SERVER;
672 	/* mbind->context set by app */
673 	mbind->service = msvc;
674 	mbind->instance_specific = 0;
675 	mxa->binding = mbind;
676 
677 	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
678 	sec_addr->length = 0;
679 	bzero(sec_addr->port_spec, MLRPC_PORT_ANY_MAX_PORT_SPEC);
680 
681 	result->transfer_syntax =
682 	    cont_list->p_cont_elem[0].transfer_syntaxes[0];
683 
684 	return (MLRPC_DRC_BINDING_MADE);
685 }
686 
687 static int
688 mlrpc_s_request(struct mlrpc_xaction *mxa)
689 {
690 	struct mlrpc_binding	*mbind;
691 	struct mlrpc_service	*msvc;
692 	unsigned		p_cont_id;
693 	int			rc;
694 
695 	mxa->opnum = mxa->recv_hdr.request_hdr.opnum;
696 	p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id;
697 
698 	if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) == NULL)
699 		return (MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID);
700 
701 	mxa->binding = mbind;
702 	msvc = mbind->service;
703 
704 	/*
705 	 * Make room for the response hdr.
706 	 */
707 	mxa->send_mlnds.pdu_scan_offset = MLRPC_RSP_HDR_SIZE;
708 
709 	if (msvc->call_stub)
710 		rc = (*msvc->call_stub)(mxa);
711 	else
712 		rc = mlrpc_generic_call_stub(mxa);
713 
714 	if (MLRPC_DRC_IS_FAULT(rc)) {
715 		mlndo_printf(0, 0, "%s[0x%02x]: 0x%04x",
716 		    msvc->name, mxa->opnum, rc);
717 	}
718 
719 	return (rc);
720 }
721 
722 /*
723  * The transaction and the two mlnds streams use the same heap, which
724  * should already exist at this point.  The heap will also be available
725  * to the stub.
726  */
727 int
728 mlrpc_generic_call_stub(struct mlrpc_xaction *mxa)
729 {
730 	struct mlrpc_binding 	*mbind = mxa->binding;
731 	struct mlrpc_service 	*msvc = mbind->service;
732 	struct ndr_typeinfo 	*intf_ti = msvc->interface_ti;
733 	struct mlrpc_stub_table *ste;
734 	int			opnum = mxa->opnum;
735 	unsigned		p_len = intf_ti->c_size_fixed_part;
736 	char 			*param;
737 	int			rc;
738 
739 	if (mxa->heap == NULL) {
740 		mlndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum);
741 		return (MLRPC_DRC_FAULT_OUT_OF_MEMORY);
742 	}
743 
744 	if ((ste = mlrpc_find_stub_in_svc(msvc, opnum)) == NULL) {
745 		mlndo_printf(0, 0, "%s[0x%02x]: invalid opnum",
746 		    msvc->name, opnum);
747 		return (MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID);
748 	}
749 
750 	if ((param = mlrpc_heap_malloc(mxa->heap, p_len)) == NULL)
751 		return (MLRPC_DRC_FAULT_OUT_OF_MEMORY);
752 
753 	bzero(param, p_len);
754 
755 	rc = mlrpc_decode_call(mxa, param);
756 	if (!MLRPC_DRC_IS_OK(rc))
757 		return (rc);
758 
759 	rc = (*ste->func)(param, mxa);
760 	if (rc == MLRPC_DRC_OK)
761 		rc = mlrpc_encode_return(mxa, param);
762 
763 	return (rc);
764 }
765 
766 /*
767  * We can perform some initial setup of the response header here.
768  * We also need to cache some of the information from the bind
769  * negotiation for use during subsequent RPC calls.
770  */
771 static void
772 mlrpc_reply_prepare_hdr(struct mlrpc_xaction *mxa)
773 {
774 	mlrpcconn_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
775 	mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr;
776 
777 	hdr->rpc_vers = 5;
778 	hdr->rpc_vers_minor = 0;
779 	hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG;
780 	hdr->packed_drep = rhdr->packed_drep;
781 	hdr->frag_length = 0;
782 	hdr->auth_length = 0;
783 	hdr->call_id = rhdr->call_id;
784 #ifdef _BIG_ENDIAN
785 	hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII
786 	    | MLRPC_REPLAB_INTG_BIG_ENDIAN;
787 #else
788 	hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII
789 	    | MLRPC_REPLAB_INTG_LITTLE_ENDIAN;
790 #endif
791 
792 	switch (mxa->ptype) {
793 	case MLRPC_PTYPE_BIND:
794 		hdr->ptype = MLRPC_PTYPE_BIND_ACK;
795 		mxa->send_hdr.bind_ack_hdr.max_xmit_frag =
796 		    mxa->recv_hdr.bind_hdr.max_xmit_frag;
797 		mxa->send_hdr.bind_ack_hdr.max_recv_frag =
798 		    mxa->recv_hdr.bind_hdr.max_recv_frag;
799 		mxa->send_hdr.bind_ack_hdr.assoc_group_id =
800 		    mxa->recv_hdr.bind_hdr.assoc_group_id;
801 
802 		if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0)
803 			mxa->send_hdr.bind_ack_hdr.assoc_group_id = time(0);
804 
805 		/*
806 		 * Save the maximum fragment sizes
807 		 * for use with subsequent requests.
808 		 */
809 		mxa->context->max_xmit_frag =
810 		    mxa->recv_hdr.bind_hdr.max_xmit_frag;
811 
812 		mxa->context->max_recv_frag =
813 		    mxa->recv_hdr.bind_hdr.max_recv_frag;
814 
815 		break;
816 
817 	case MLRPC_PTYPE_REQUEST:
818 		hdr->ptype = MLRPC_PTYPE_RESPONSE;
819 		/* mxa->send_hdr.response_hdr.alloc_hint */
820 		mxa->send_hdr.response_hdr.p_cont_id =
821 		    mxa->recv_hdr.request_hdr.p_cont_id;
822 		mxa->send_hdr.response_hdr.cancel_count = 0;
823 		mxa->send_hdr.response_hdr.reserved = 0;
824 		break;
825 
826 	case MLRPC_PTYPE_ALTER_CONTEXT:
827 		hdr->ptype = MLRPC_PTYPE_ALTER_CONTEXT_RESP;
828 		/*
829 		 * The max_xmit_frag, max_recv_frag
830 		 * and assoc_group_id are ignored.
831 		 */
832 		break;
833 
834 	default:
835 		hdr->ptype = 0xFF;
836 	}
837 }
838 
839 /*
840  * Finish and encode the bind acknowledge (MLRPC_PTYPE_BIND_ACK) header.
841  * The frag_length is different from a regular RPC response.
842  */
843 static void
844 mlrpc_reply_bind_ack(struct mlrpc_xaction *mxa)
845 {
846 	mlrpcconn_common_header_t	*hdr;
847 	mlrpcconn_bind_ack_hdr_t	*bahdr;
848 
849 	hdr = &mxa->send_hdr.common_hdr;
850 	bahdr = &mxa->send_hdr.bind_ack_hdr;
851 	hdr->frag_length = mlrpc_bind_ack_hdr_size(bahdr);
852 }
853 
854 /*
855  * Signal an RPC fault. The stream is reset and we overwrite whatever
856  * was in the response header with the fault information.
857  */
858 static void
859 mlrpc_reply_fault(struct mlrpc_xaction *mxa, unsigned long drc)
860 {
861 	mlrpcconn_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
862 	mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr;
863 	struct mlndr_stream *mlnds = &mxa->send_mlnds;
864 	unsigned long fault_status;
865 
866 	MLNDS_RESET(mlnds);
867 
868 	hdr->rpc_vers = 5;
869 	hdr->rpc_vers_minor = 0;
870 	hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG;
871 	hdr->packed_drep = rhdr->packed_drep;
872 	hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr);
873 	hdr->auth_length = 0;
874 	hdr->call_id = rhdr->call_id;
875 #ifdef _BIG_ENDIAN
876 	hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII
877 	    | MLRPC_REPLAB_INTG_BIG_ENDIAN;
878 #else
879 	hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII
880 	    | MLRPC_REPLAB_INTG_LITTLE_ENDIAN;
881 #endif
882 
883 	switch (drc & MLRPC_DRC_MASK_SPECIFIER) {
884 	case MLRPC_DRC_FAULT_OUT_OF_MEMORY:
885 	case MLRPC_DRC_FAULT_ENCODE_TOO_BIG:
886 		fault_status = MLRPC_FAULT_NCA_OUT_ARGS_TOO_BIG;
887 		break;
888 
889 	case MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID:
890 		fault_status = MLRPC_FAULT_NCA_INVALID_PRES_CONTEXT_ID;
891 		break;
892 
893 	case MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID:
894 		fault_status = MLRPC_FAULT_NCA_OP_RNG_ERROR;
895 		break;
896 
897 	case MLRPC_DRC_FAULT_DECODE_FAILED:
898 	case MLRPC_DRC_FAULT_ENCODE_FAILED:
899 		fault_status = MLRPC_FAULT_NCA_PROTO_ERROR;
900 		break;
901 
902 	default:
903 		fault_status = MLRPC_FAULT_NCA_UNSPEC_REJECT;
904 		break;
905 	}
906 
907 	mxa->send_hdr.fault_hdr.common_hdr.ptype = MLRPC_PTYPE_FAULT;
908 	mxa->send_hdr.fault_hdr.status = fault_status;
909 	mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length;
910 }
911 
912 static int
913 mlrpc_build_reply(struct mlrpc_xaction *mxa)
914 {
915 	mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr;
916 	struct mlndr_stream *mlnds = &mxa->send_mlnds;
917 	uint8_t *pdu_buf;
918 	unsigned long pdu_size;
919 	unsigned long frag_size;
920 	unsigned long pdu_data_size;
921 	unsigned long frag_data_size;
922 
923 	frag_size = mlrpc_frag_size;
924 	pdu_size = mlnds->pdu_size;
925 	pdu_buf = mlnds->pdu_base_addr;
926 
927 	if (pdu_size <= frag_size) {
928 		/*
929 		 * Single fragment response. The PDU size may be zero
930 		 * here (i.e. bind or fault response). So don't make
931 		 * any assumptions about it until after the header is
932 		 * encoded.
933 		 */
934 		switch (hdr->ptype) {
935 		case MLRPC_PTYPE_BIND_ACK:
936 			mlrpc_reply_bind_ack(mxa);
937 			break;
938 
939 		case MLRPC_PTYPE_FAULT:
940 			/* already setup */
941 			break;
942 
943 		case MLRPC_PTYPE_RESPONSE:
944 			hdr->frag_length = pdu_size;
945 			mxa->send_hdr.response_hdr.alloc_hint =
946 			    hdr->frag_length;
947 			break;
948 
949 		default:
950 			hdr->frag_length = pdu_size;
951 			break;
952 		}
953 
954 		mlnds->pdu_scan_offset = 0;
955 		(void) mlrpc_encode_pdu_hdr(mxa);
956 		pdu_size = mlnds->pdu_size;
957 		mlrpc_build_frag(mlnds, pdu_buf,  pdu_size);
958 		return (0);
959 	}
960 
961 	/*
962 	 * Multiple fragment response.
963 	 */
964 	hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG;
965 	hdr->frag_length = frag_size;
966 	mxa->send_hdr.response_hdr.alloc_hint = pdu_size - MLRPC_RSP_HDR_SIZE;
967 	mlnds->pdu_scan_offset = 0;
968 	(void) mlrpc_encode_pdu_hdr(mxa);
969 	mlrpc_build_frag(mlnds, pdu_buf,  frag_size);
970 
971 	/*
972 	 * We need to update the 24-byte header in subsequent fragments.
973 	 *
974 	 * pdu_data_size:	total data remaining to be handled
975 	 * frag_size:		total fragment size including header
976 	 * frag_data_size:	data in fragment
977 	 *			(i.e. frag_size - MLRPC_RSP_HDR_SIZE)
978 	 */
979 	pdu_data_size = pdu_size - MLRPC_RSP_HDR_SIZE;
980 	frag_data_size = frag_size - MLRPC_RSP_HDR_SIZE;
981 
982 	while (pdu_data_size) {
983 		mxa->send_hdr.response_hdr.alloc_hint -= frag_data_size;
984 		pdu_data_size -= frag_data_size;
985 		pdu_buf += frag_data_size;
986 
987 		if (pdu_data_size <= frag_data_size) {
988 			frag_data_size = pdu_data_size;
989 			frag_size = frag_data_size + MLRPC_RSP_HDR_SIZE;
990 			hdr->pfc_flags = MLRPC_PFC_LAST_FRAG;
991 		} else {
992 			hdr->pfc_flags = 0;
993 		}
994 
995 		hdr->frag_length = frag_size;
996 		mlnds->pdu_scan_offset = 0;
997 		(void) mlrpc_encode_pdu_hdr(mxa);
998 		bcopy(mlnds->pdu_base_addr, pdu_buf, MLRPC_RSP_HDR_SIZE);
999 
1000 		mlrpc_build_frag(mlnds, pdu_buf, frag_size);
1001 
1002 		if (hdr->pfc_flags & MLRPC_PFC_LAST_FRAG)
1003 			break;
1004 	}
1005 
1006 	return (0);
1007 }
1008 
1009 /*
1010  * mlrpc_build_frag
1011  *
1012  * Build an RPC PDU fragment from the specified buffer.
1013  * If malloc fails, the client will see a header/pdu inconsistency
1014  * and report an error.
1015  */
1016 static void
1017 mlrpc_build_frag(struct mlndr_stream *mlnds, uint8_t *buf, uint32_t len)
1018 {
1019 	ndr_frag_t *frag;
1020 	int size = sizeof (ndr_frag_t) + len;
1021 
1022 	if ((frag = (ndr_frag_t *)malloc(size)) == NULL)
1023 		return;
1024 
1025 	frag->next = NULL;
1026 	frag->buf = (uint8_t *)frag + sizeof (ndr_frag_t);
1027 	frag->len = len;
1028 	bcopy(buf, frag->buf, len);
1029 
1030 	if (mlnds->frags.head == NULL) {
1031 		mlnds->frags.head = frag;
1032 		mlnds->frags.tail = frag;
1033 		mlnds->frags.nfrag = 1;
1034 	} else {
1035 		mlnds->frags.tail->next = frag;
1036 		mlnds->frags.tail = frag;
1037 		++mlnds->frags.nfrag;
1038 	}
1039 }
1040