Home | History | Annotate | Download | only in common
      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 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * Server side RPC handler.
     28  */
     29 
     30 #include <sys/byteorder.h>
     31 #include <sys/errno.h>
     32 #include <sys/uio.h>
     33 #include <thread.h>
     34 #include <synch.h>
     35 #include <stdlib.h>
     36 #include <strings.h>
     37 #include <string.h>
     38 #include <time.h>
     39 
     40 #include <smbsrv/libsmb.h>
     41 #include <smbsrv/libmlrpc.h>
     42 #include <smbsrv/ntaccess.h>
     43 
     44 /*
     45  * Fragment size (5680: NT style).
     46  */
     47 #define	NDR_FRAG_SZ		5680
     48 
     49 #define	NDR_PIPE_BUFSZ		65536
     50 #define	NDR_PIPE_MAX		128
     51 static ndr_pipe_t ndr_pipe_table[NDR_PIPE_MAX];
     52 static mutex_t ndr_pipe_lock;
     53 
     54 static int ndr_pipe_transact(ndr_pipe_t *);
     55 static ndr_pipe_t *ndr_pipe_lookup(int);
     56 static void ndr_pipe_release(ndr_pipe_t *);
     57 static ndr_pipe_t *ndr_pipe_allocate(int);
     58 static void ndr_pipe_deallocate(ndr_pipe_t *);
     59 static void ndr_pipe_rewind(ndr_pipe_t *);
     60 static void ndr_pipe_flush(ndr_pipe_t *);
     61 
     62 static int ndr_svc_process(ndr_xa_t *);
     63 static int ndr_svc_bind(ndr_xa_t *);
     64 static int ndr_svc_request(ndr_xa_t *);
     65 static void ndr_reply_prepare_hdr(ndr_xa_t *);
     66 static int ndr_svc_alter_context(ndr_xa_t *);
     67 static void ndr_reply_fault(ndr_xa_t *, unsigned long);
     68 static int ndr_build_reply(ndr_xa_t *);
     69 static void ndr_build_frag(ndr_stream_t *, uint8_t *, uint32_t);
     70 
     71 /*
     72  * Allocate and associate a service context with a fid.
     73  */
     74 int
     75 ndr_pipe_open(int fid, uint8_t *data, uint32_t datalen)
     76 {
     77 	ndr_pipe_t *np;
     78 
     79 	(void) mutex_lock(&ndr_pipe_lock);
     80 
     81 	if ((np = ndr_pipe_lookup(fid)) != NULL) {
     82 		ndr_pipe_release(np);
     83 		(void) mutex_unlock(&ndr_pipe_lock);
     84 		return (EEXIST);
     85 	}
     86 
     87 	if ((np = ndr_pipe_allocate(fid)) == NULL) {
     88 		(void) mutex_unlock(&ndr_pipe_lock);
     89 		return (ENOMEM);
     90 	}
     91 
     92 	if (smb_netuserinfo_decode(&np->np_user, data, datalen, NULL) == -1) {
     93 		ndr_pipe_release(np);
     94 		(void) mutex_unlock(&ndr_pipe_lock);
     95 		return (EINVAL);
     96 	}
     97 
     98 	ndr_svc_binding_pool_init(&np->np_binding, np->np_binding_pool,
     99 	    NDR_N_BINDING_POOL);
    100 
    101 	(void) mutex_unlock(&ndr_pipe_lock);
    102 	return (0);
    103 }
    104 
    105 /*
    106  * Release the context associated with a fid when an opipe is closed.
    107  */
    108 int
    109 ndr_pipe_close(int fid)
    110 {
    111 	ndr_pipe_t *np;
    112 
    113 	(void) mutex_lock(&ndr_pipe_lock);
    114 
    115 	if ((np = ndr_pipe_lookup(fid)) == NULL) {
    116 		(void) mutex_unlock(&ndr_pipe_lock);
    117 		return (ENOENT);
    118 	}
    119 
    120 	/*
    121 	 * Release twice: once for the lookup above
    122 	 * and again to close the fid.
    123 	 */
    124 	ndr_pipe_release(np);
    125 	ndr_pipe_release(np);
    126 	(void) mutex_unlock(&ndr_pipe_lock);
    127 	return (0);
    128 }
    129 
    130 /*
    131  * Write RPC request data to the input stream.  Input data is buffered
    132  * until the response is requested.
    133  */
    134 int
    135 ndr_pipe_write(int fid, uint8_t *buf, uint32_t len)
    136 {
    137 	ndr_pipe_t *np;
    138 	ssize_t nbytes;
    139 
    140 	if (len == 0)
    141 		return (0);
    142 
    143 	(void) mutex_lock(&ndr_pipe_lock);
    144 
    145 	if ((np = ndr_pipe_lookup(fid)) == NULL) {
    146 		(void) mutex_unlock(&ndr_pipe_lock);
    147 		return (ENOENT);
    148 	}
    149 
    150 	nbytes = ndr_uiomove((caddr_t)buf, len, UIO_READ, &np->np_uio);
    151 
    152 	ndr_pipe_release(np);
    153 	(void) mutex_unlock(&ndr_pipe_lock);
    154 	return ((nbytes == len) ? 0 : EIO);
    155 }
    156 
    157 /*
    158  * Read RPC response data.  If the input stream contains an RPC request,
    159  * we need to process the RPC transaction, which will place the RPC
    160  * response in the output (frags) stream.  Otherwise, read data from
    161  * the output stream.
    162  */
    163 int
    164 ndr_pipe_read(int fid, uint8_t *buf, uint32_t *len, uint32_t *resid)
    165 {
    166 	ndr_pipe_t *np;
    167 	ssize_t nbytes = *len;
    168 	int rc;
    169 
    170 	if (nbytes == 0) {
    171 		*resid = 0;
    172 		return (0);
    173 	}
    174 
    175 	(void) mutex_lock(&ndr_pipe_lock);
    176 	if ((np = ndr_pipe_lookup(fid)) == NULL) {
    177 		(void) mutex_unlock(&ndr_pipe_lock);
    178 		return (ENOENT);
    179 	}
    180 	(void) mutex_unlock(&ndr_pipe_lock);
    181 
    182 	if (np->np_uio.uio_offset) {
    183 		if ((rc = ndr_pipe_transact(np)) != 0) {
    184 			ndr_pipe_flush(np);
    185 			(void) mutex_lock(&ndr_pipe_lock);
    186 			ndr_pipe_release(np);
    187 			(void) mutex_unlock(&ndr_pipe_lock);
    188 			return (rc);
    189 		}
    190 
    191 	}
    192 
    193 	*len = ndr_uiomove((caddr_t)buf, nbytes, UIO_WRITE, &np->np_frags.uio);
    194 	*resid = np->np_frags.uio.uio_resid;
    195 
    196 	if (*resid == 0) {
    197 		/*
    198 		 * Nothing left, cleanup the output stream.
    199 		 */
    200 		ndr_pipe_flush(np);
    201 	}
    202 
    203 	(void) mutex_lock(&ndr_pipe_lock);
    204 	ndr_pipe_release(np);
    205 	(void) mutex_unlock(&ndr_pipe_lock);
    206 	return (0);
    207 }
    208 
    209 /*
    210  * Process a server-side RPC request.
    211  */
    212 static int
    213 ndr_pipe_transact(ndr_pipe_t *np)
    214 {
    215 	ndr_xa_t	*mxa;
    216 	ndr_stream_t	*recv_nds;
    217 	ndr_stream_t	*send_nds;
    218 	char		*data;
    219 	int		datalen;
    220 	int		rc;
    221 
    222 	data = np->np_buf;
    223 	datalen = np->np_uio.uio_offset;
    224 
    225 	if ((mxa = (ndr_xa_t *)malloc(sizeof (ndr_xa_t))) == NULL)
    226 		return (ENOMEM);
    227 
    228 	bzero(mxa, sizeof (ndr_xa_t));
    229 	mxa->fid = np->np_fid;
    230 	mxa->pipe = np;
    231 	mxa->binding_list = np->np_binding;
    232 
    233 	if ((mxa->heap = ndr_heap_create()) == NULL) {
    234 		free(mxa);
    235 		return (ENOMEM);
    236 	}
    237 
    238 	recv_nds = &mxa->recv_nds;
    239 	rc = nds_initialize(recv_nds, datalen, NDR_MODE_CALL_RECV, mxa->heap);
    240 	if (rc != 0) {
    241 		ndr_heap_destroy(mxa->heap);
    242 		free(mxa);
    243 		return (ENOMEM);
    244 	}
    245 
    246 	/*
    247 	 * Copy the input data and reset the input stream.
    248 	 */
    249 	bcopy(data, recv_nds->pdu_base_addr, datalen);
    250 	ndr_pipe_rewind(np);
    251 
    252 	send_nds = &mxa->send_nds;
    253 	rc = nds_initialize(send_nds, 0, NDR_MODE_RETURN_SEND, mxa->heap);
    254 	if (rc != 0) {
    255 		nds_destruct(&mxa->recv_nds);
    256 		ndr_heap_destroy(mxa->heap);
    257 		free(mxa);
    258 		return (ENOMEM);
    259 	}
    260 
    261 	(void) ndr_svc_process(mxa);
    262 
    263 	nds_finalize(send_nds, &np->np_frags);
    264 	nds_destruct(&mxa->recv_nds);
    265 	nds_destruct(&mxa->send_nds);
    266 	ndr_heap_destroy(mxa->heap);
    267 	free(mxa);
    268 	return (0);
    269 }
    270 
    271 /*
    272  * Must be called with ndr_pipe_lock held.
    273  */
    274 static ndr_pipe_t *
    275 ndr_pipe_lookup(int fid)
    276 {
    277 	ndr_pipe_t *np;
    278 	int i;
    279 
    280 	for (i = 0; i < NDR_PIPE_MAX; ++i) {
    281 		np = &ndr_pipe_table[i];
    282 
    283 		if (np->np_fid == fid) {
    284 			if (np->np_refcnt == 0)
    285 				return (NULL);
    286 
    287 			np->np_refcnt++;
    288 			return (np);
    289 		}
    290 	}
    291 
    292 	return (NULL);
    293 }
    294 
    295 /*
    296  * Must be called with ndr_pipe_lock held.
    297  */
    298 static void
    299 ndr_pipe_release(ndr_pipe_t *np)
    300 {
    301 	np->np_refcnt--;
    302 	ndr_pipe_deallocate(np);
    303 }
    304 
    305 /*
    306  * Must be called with ndr_pipe_lock held.
    307  */
    308 static ndr_pipe_t *
    309 ndr_pipe_allocate(int fid)
    310 {
    311 	ndr_pipe_t *np = NULL;
    312 	int i;
    313 
    314 	for (i = 0; i < NDR_PIPE_MAX; ++i) {
    315 		np = &ndr_pipe_table[i];
    316 
    317 		if (np->np_fid == 0) {
    318 			bzero(np, sizeof (ndr_pipe_t));
    319 
    320 			if ((np->np_buf = malloc(NDR_PIPE_BUFSZ)) == NULL)
    321 				return (NULL);
    322 
    323 			ndr_pipe_rewind(np);
    324 			np->np_fid = fid;
    325 			np->np_refcnt = 1;
    326 			return (np);
    327 		}
    328 	}
    329 
    330 	return (NULL);
    331 }
    332 
    333 /*
    334  * Must be called with ndr_pipe_lock held.
    335  */
    336 static void
    337 ndr_pipe_deallocate(ndr_pipe_t *np)
    338 {
    339 	if (np->np_refcnt == 0) {
    340 		/*
    341 		 * Ensure that there are no RPC service policy handles
    342 		 * (associated with this fid) left around.
    343 		 */
    344 		ndr_hdclose(np->np_fid);
    345 
    346 		ndr_pipe_rewind(np);
    347 		ndr_pipe_flush(np);
    348 		free(np->np_buf);
    349 		free(np->np_user.ui_domain);
    350 		free(np->np_user.ui_account);
    351 		free(np->np_user.ui_workstation);
    352 		bzero(np, sizeof (ndr_pipe_t));
    353 	}
    354 }
    355 
    356 /*
    357  * Rewind the input data stream, ready for the next write.
    358  */
    359 static void
    360 ndr_pipe_rewind(ndr_pipe_t *np)
    361 {
    362 	np->np_uio.uio_iov = &np->np_iov;
    363 	np->np_uio.uio_iovcnt = 1;
    364 	np->np_uio.uio_offset = 0;
    365 	np->np_uio.uio_segflg = UIO_USERSPACE;
    366 	np->np_uio.uio_resid = NDR_PIPE_BUFSZ;
    367 	np->np_iov.iov_base = np->np_buf;
    368 	np->np_iov.iov_len = NDR_PIPE_BUFSZ;
    369 }
    370 
    371 /*
    372  * Flush the output data stream.
    373  */
    374 static void
    375 ndr_pipe_flush(ndr_pipe_t *np)
    376 {
    377 	ndr_frag_t *frag;
    378 
    379 	while ((frag = np->np_frags.head) != NULL) {
    380 		np->np_frags.head = frag->next;
    381 		free(frag);
    382 	}
    383 
    384 	free(np->np_frags.iov);
    385 	bzero(&np->np_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_netuserinfo_t *ctx = &xa->pipe->np_user;
    397 
    398 	return (ctx->ui_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_netuserinfo_t *ctx = &xa->pipe->np_user;
    411 
    412 	return ((ctx->ui_flags & SMB_ATF_ADMIN) ||
    413 	    (ctx->ui_flags & SMB_ATF_POWERUSER));
    414 }
    415 
    416 int32_t
    417 ndr_native_os(ndr_xa_t *xa)
    418 {
    419 	smb_netuserinfo_t *ctx = &xa->pipe->np_user;
    420 
    421 	return (ctx->ui_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 ndr_svc_process(ndr_xa_t *mxa)
    430 {
    431 	int rc;
    432 
    433 	rc = ndr_decode_pdu_hdr(mxa);
    434 	if (!NDR_DRC_IS_OK(rc))
    435 		return (-1);
    436 
    437 	(void) ndr_reply_prepare_hdr(mxa);
    438 
    439 	switch (mxa->ptype) {
    440 	case NDR_PTYPE_BIND:
    441 		rc = ndr_svc_bind(mxa);
    442 		break;
    443 
    444 	case NDR_PTYPE_REQUEST:
    445 		rc = ndr_svc_request(mxa);
    446 		break;
    447 
    448 	case NDR_PTYPE_ALTER_CONTEXT:
    449 		rc = ndr_svc_alter_context(mxa);
    450 		break;
    451 
    452 	default:
    453 		rc = NDR_DRC_FAULT_RPCHDR_PTYPE_INVALID;
    454 		break;
    455 	}
    456 
    457 	if (NDR_DRC_IS_FAULT(rc))
    458 		ndr_reply_fault(mxa, rc);
    459 
    460 	(void) ndr_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 ndr_svc_bind(ndr_xa_t *mxa)
    470 {
    471 	ndr_p_cont_list_t	*cont_list;
    472 	ndr_p_result_list_t	*result_list;
    473 	ndr_p_result_t		*result;
    474 	unsigned		p_cont_id;
    475 	ndr_binding_t		*mbind;
    476 	ndr_uuid_t		*as_uuid;
    477 	ndr_uuid_t		*ts_uuid;
    478 	int			as_vers;
    479 	int			ts_vers;
    480 	ndr_service_t		*msvc;
    481 	int			rc;
    482 	ndr_port_any_t		*sec_addr;
    483 
    484 	/* acquire targets */
    485 	cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem;
    486 	result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list;
    487 	result = &result_list->p_results[0];
    488 
    489 	/*
    490 	 * Set up temporary secondary address port.
    491 	 * We will correct this later (below).
    492 	 */
    493 	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
    494 	sec_addr->length = 13;
    495 	(void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs");
    496 
    497 	result_list->n_results = 1;
    498 	result_list->reserved = 0;
    499 	result_list->reserved2 = 0;
    500 	result->result = NDR_PCDR_ACCEPTANCE;
    501 	result->reason = 0;
    502 	bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
    503 
    504 	/* sanity check */
    505 	if (cont_list->n_context_elem != 1 ||
    506 	    cont_list->p_cont_elem[0].n_transfer_syn != 1) {
    507 		ndo_trace("ndr_svc_bind: warning: multiple p_cont_elem");
    508 	}
    509 
    510 	p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
    511 
    512 	if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) != NULL) {
    513 		/*
    514 		 * Duplicate presentation context id.
    515 		 */
    516 		ndo_trace("ndr_svc_bind: duplicate binding");
    517 		return (NDR_DRC_FAULT_BIND_PCONT_BUSY);
    518 	}
    519 
    520 	if ((mbind = ndr_svc_new_binding(mxa)) == NULL) {
    521 		/*
    522 		 * No free binding slot
    523 		 */
    524 		result->result = NDR_PCDR_PROVIDER_REJECTION;
    525 		result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED;
    526 		ndo_trace("ndr_svc_bind: no resources");
    527 		return (NDR_DRC_OK);
    528 	}
    529 
    530 	as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
    531 	as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
    532 
    533 	ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
    534 	ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
    535 
    536 	msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers);
    537 	if (msvc == NULL) {
    538 		result->result = NDR_PCDR_PROVIDER_REJECTION;
    539 		result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
    540 		return (NDR_DRC_OK);
    541 	}
    542 
    543 	/*
    544 	 * We can now use the correct secondary address port.
    545 	 */
    546 	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
    547 	sec_addr->length = strlen(msvc->sec_addr_port) + 1;
    548 	(void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port,
    549 	    NDR_PORT_ANY_MAX_PORT_SPEC);
    550 
    551 	mbind->p_cont_id = p_cont_id;
    552 	mbind->which_side = NDR_BIND_SIDE_SERVER;
    553 	/* mbind->context set by app */
    554 	mbind->service = msvc;
    555 	mbind->instance_specific = 0;
    556 
    557 	mxa->binding = mbind;
    558 
    559 	if (msvc->bind_req) {
    560 		/*
    561 		 * Call the service-specific bind() handler.  If
    562 		 * this fails, we shouild send a specific error
    563 		 * on the bind ack.
    564 		 */
    565 		rc = (msvc->bind_req)(mxa);
    566 		if (NDR_DRC_IS_FAULT(rc)) {
    567 			mbind->service = 0;	/* free binding slot */
    568 			mbind->which_side = 0;
    569 			mbind->p_cont_id = 0;
    570 			mbind->instance_specific = 0;
    571 			return (rc);
    572 		}
    573 	}
    574 
    575 	result->transfer_syntax =
    576 	    cont_list->p_cont_elem[0].transfer_syntaxes[0];
    577 
    578 	return (NDR_DRC_BINDING_MADE);
    579 }
    580 
    581 /*
    582  * ndr_svc_alter_context
    583  *
    584  * The alter context request is used to request additional presentation
    585  * context for another interface and/or version.  It is very similar to
    586  * a bind request.
    587  */
    588 static int
    589 ndr_svc_alter_context(ndr_xa_t *mxa)
    590 {
    591 	ndr_p_result_list_t *result_list;
    592 	ndr_p_result_t *result;
    593 	ndr_p_cont_list_t *cont_list;
    594 	ndr_binding_t *mbind;
    595 	ndr_service_t *msvc;
    596 	unsigned p_cont_id;
    597 	ndr_uuid_t *as_uuid;
    598 	ndr_uuid_t *ts_uuid;
    599 	int as_vers;
    600 	int ts_vers;
    601 	ndr_port_any_t *sec_addr;
    602 
    603 	result_list = &mxa->send_hdr.alter_context_rsp_hdr.p_result_list;
    604 	result_list->n_results = 1;
    605 	result_list->reserved = 0;
    606 	result_list->reserved2 = 0;
    607 
    608 	result = &result_list->p_results[0];
    609 	result->result = NDR_PCDR_ACCEPTANCE;
    610 	result->reason = 0;
    611 	bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
    612 
    613 	cont_list = &mxa->recv_hdr.alter_context_hdr.p_context_elem;
    614 	p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
    615 
    616 	if (ndr_svc_find_binding(mxa, p_cont_id) != NULL)
    617 		return (NDR_DRC_FAULT_BIND_PCONT_BUSY);
    618 
    619 	if ((mbind = ndr_svc_new_binding(mxa)) == NULL) {
    620 		result->result = NDR_PCDR_PROVIDER_REJECTION;
    621 		result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED;
    622 		return (NDR_DRC_OK);
    623 	}
    624 
    625 	as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
    626 	as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
    627 
    628 	ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
    629 	ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
    630 
    631 	msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers);
    632 	if (msvc == NULL) {
    633 		result->result = NDR_PCDR_PROVIDER_REJECTION;
    634 		result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
    635 		return (NDR_DRC_OK);
    636 	}
    637 
    638 	mbind->p_cont_id = p_cont_id;
    639 	mbind->which_side = NDR_BIND_SIDE_SERVER;
    640 	/* mbind->context set by app */
    641 	mbind->service = msvc;
    642 	mbind->instance_specific = 0;
    643 	mxa->binding = mbind;
    644 
    645 	sec_addr = &mxa->send_hdr.alter_context_rsp_hdr.sec_addr;
    646 	sec_addr->length = 0;
    647 	bzero(sec_addr->port_spec, NDR_PORT_ANY_MAX_PORT_SPEC);
    648 
    649 	result->transfer_syntax =
    650 	    cont_list->p_cont_elem[0].transfer_syntaxes[0];
    651 
    652 	return (NDR_DRC_BINDING_MADE);
    653 }
    654 
    655 static int
    656 ndr_svc_request(ndr_xa_t *mxa)
    657 {
    658 	ndr_binding_t	*mbind;
    659 	ndr_service_t	*msvc;
    660 	unsigned	p_cont_id;
    661 	int		rc;
    662 
    663 	mxa->opnum = mxa->recv_hdr.request_hdr.opnum;
    664 	p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id;
    665 
    666 	if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) == NULL)
    667 		return (NDR_DRC_FAULT_REQUEST_PCONT_INVALID);
    668 
    669 	mxa->binding = mbind;
    670 	msvc = mbind->service;
    671 
    672 	/*
    673 	 * Make room for the response hdr.
    674 	 */
    675 	mxa->send_nds.pdu_scan_offset = NDR_RSP_HDR_SIZE;
    676 
    677 	if (msvc->call_stub)
    678 		rc = (*msvc->call_stub)(mxa);
    679 	else
    680 		rc = ndr_generic_call_stub(mxa);
    681 
    682 	if (NDR_DRC_IS_FAULT(rc)) {
    683 		ndo_printf(0, 0, "%s[0x%02x]: 0x%04x",
    684 		    msvc->name, mxa->opnum, rc);
    685 	}
    686 
    687 	return (rc);
    688 }
    689 
    690 /*
    691  * The transaction and the two nds streams use the same heap, which
    692  * should already exist at this point.  The heap will also be available
    693  * to the stub.
    694  */
    695 int
    696 ndr_generic_call_stub(ndr_xa_t *mxa)
    697 {
    698 	ndr_binding_t 		*mbind = mxa->binding;
    699 	ndr_service_t		*msvc = mbind->service;
    700 	ndr_typeinfo_t		*intf_ti = msvc->interface_ti;
    701 	ndr_stub_table_t	*ste;
    702 	int			opnum = mxa->opnum;
    703 	unsigned		p_len = intf_ti->c_size_fixed_part;
    704 	char 			*param;
    705 	int			rc;
    706 
    707 	if (mxa->heap == NULL) {
    708 		ndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum);
    709 		return (NDR_DRC_FAULT_OUT_OF_MEMORY);
    710 	}
    711 
    712 	if ((ste = ndr_svc_find_stub(msvc, opnum)) == NULL) {
    713 		ndo_printf(0, 0, "%s[0x%02x]: invalid opnum",
    714 		    msvc->name, opnum);
    715 		return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID);
    716 	}
    717 
    718 	if ((param = ndr_heap_malloc(mxa->heap, p_len)) == NULL)
    719 		return (NDR_DRC_FAULT_OUT_OF_MEMORY);
    720 
    721 	bzero(param, p_len);
    722 
    723 	rc = ndr_decode_call(mxa, param);
    724 	if (!NDR_DRC_IS_OK(rc))
    725 		return (rc);
    726 
    727 	rc = (*ste->func)(param, mxa);
    728 	if (rc == NDR_DRC_OK)
    729 		rc = ndr_encode_return(mxa, param);
    730 
    731 	return (rc);
    732 }
    733 
    734 /*
    735  * We can perform some initial setup of the response header here.
    736  * We also need to cache some of the information from the bind
    737  * negotiation for use during subsequent RPC calls.
    738  */
    739 static void
    740 ndr_reply_prepare_hdr(ndr_xa_t *mxa)
    741 {
    742 	ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
    743 	ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
    744 
    745 	hdr->rpc_vers = 5;
    746 	hdr->rpc_vers_minor = 0;
    747 	hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG;
    748 	hdr->packed_drep = rhdr->packed_drep;
    749 	hdr->frag_length = 0;
    750 	hdr->auth_length = 0;
    751 	hdr->call_id = rhdr->call_id;
    752 #ifdef _BIG_ENDIAN
    753 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
    754 	    | NDR_REPLAB_INTG_BIG_ENDIAN;
    755 #else
    756 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
    757 	    | NDR_REPLAB_INTG_LITTLE_ENDIAN;
    758 #endif
    759 
    760 	switch (mxa->ptype) {
    761 	case NDR_PTYPE_BIND:
    762 		hdr->ptype = NDR_PTYPE_BIND_ACK;
    763 		mxa->send_hdr.bind_ack_hdr.max_xmit_frag =
    764 		    mxa->recv_hdr.bind_hdr.max_xmit_frag;
    765 		mxa->send_hdr.bind_ack_hdr.max_recv_frag =
    766 		    mxa->recv_hdr.bind_hdr.max_recv_frag;
    767 		mxa->send_hdr.bind_ack_hdr.assoc_group_id =
    768 		    mxa->recv_hdr.bind_hdr.assoc_group_id;
    769 
    770 		if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0)
    771 			mxa->send_hdr.bind_ack_hdr.assoc_group_id = time(0);
    772 
    773 		/*
    774 		 * Save the maximum fragment sizes
    775 		 * for use with subsequent requests.
    776 		 */
    777 		mxa->pipe->np_max_xmit_frag =
    778 		    mxa->recv_hdr.bind_hdr.max_xmit_frag;
    779 		mxa->pipe->np_max_recv_frag =
    780 		    mxa->recv_hdr.bind_hdr.max_recv_frag;
    781 		break;
    782 
    783 	case NDR_PTYPE_REQUEST:
    784 		hdr->ptype = NDR_PTYPE_RESPONSE;
    785 		/* mxa->send_hdr.response_hdr.alloc_hint */
    786 		mxa->send_hdr.response_hdr.p_cont_id =
    787 		    mxa->recv_hdr.request_hdr.p_cont_id;
    788 		mxa->send_hdr.response_hdr.cancel_count = 0;
    789 		mxa->send_hdr.response_hdr.reserved = 0;
    790 		break;
    791 
    792 	case NDR_PTYPE_ALTER_CONTEXT:
    793 		hdr->ptype = NDR_PTYPE_ALTER_CONTEXT_RESP;
    794 		/*
    795 		 * The max_xmit_frag, max_recv_frag and assoc_group_id are
    796 		 * ignored by the client but it's useful to fill them in.
    797 		 */
    798 		mxa->send_hdr.alter_context_rsp_hdr.max_xmit_frag =
    799 		    mxa->recv_hdr.alter_context_hdr.max_xmit_frag;
    800 		mxa->send_hdr.alter_context_rsp_hdr.max_recv_frag =
    801 		    mxa->recv_hdr.alter_context_hdr.max_recv_frag;
    802 		mxa->send_hdr.alter_context_rsp_hdr.assoc_group_id =
    803 		    mxa->recv_hdr.alter_context_hdr.assoc_group_id;
    804 		break;
    805 
    806 	default:
    807 		hdr->ptype = 0xFF;
    808 	}
    809 }
    810 
    811 /*
    812  * Signal an RPC fault. The stream is reset and we overwrite whatever
    813  * was in the response header with the fault information.
    814  */
    815 static void
    816 ndr_reply_fault(ndr_xa_t *mxa, unsigned long drc)
    817 {
    818 	ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
    819 	ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
    820 	ndr_stream_t *nds = &mxa->send_nds;
    821 	unsigned long fault_status;
    822 
    823 	NDS_RESET(nds);
    824 
    825 	hdr->rpc_vers = 5;
    826 	hdr->rpc_vers_minor = 0;
    827 	hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG;
    828 	hdr->packed_drep = rhdr->packed_drep;
    829 	hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr);
    830 	hdr->auth_length = 0;
    831 	hdr->call_id = rhdr->call_id;
    832 #ifdef _BIG_ENDIAN
    833 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
    834 	    | NDR_REPLAB_INTG_BIG_ENDIAN;
    835 #else
    836 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
    837 	    | NDR_REPLAB_INTG_LITTLE_ENDIAN;
    838 #endif
    839 
    840 	switch (drc & NDR_DRC_MASK_SPECIFIER) {
    841 	case NDR_DRC_FAULT_OUT_OF_MEMORY:
    842 	case NDR_DRC_FAULT_ENCODE_TOO_BIG:
    843 		fault_status = NDR_FAULT_NCA_OUT_ARGS_TOO_BIG;
    844 		break;
    845 
    846 	case NDR_DRC_FAULT_REQUEST_PCONT_INVALID:
    847 		fault_status = NDR_FAULT_NCA_INVALID_PRES_CONTEXT_ID;
    848 		break;
    849 
    850 	case NDR_DRC_FAULT_REQUEST_OPNUM_INVALID:
    851 		fault_status = NDR_FAULT_NCA_OP_RNG_ERROR;
    852 		break;
    853 
    854 	case NDR_DRC_FAULT_DECODE_FAILED:
    855 	case NDR_DRC_FAULT_ENCODE_FAILED:
    856 		fault_status = NDR_FAULT_NCA_PROTO_ERROR;
    857 		break;
    858 
    859 	default:
    860 		fault_status = NDR_FAULT_NCA_UNSPEC_REJECT;
    861 		break;
    862 	}
    863 
    864 	mxa->send_hdr.fault_hdr.common_hdr.ptype = NDR_PTYPE_FAULT;
    865 	mxa->send_hdr.fault_hdr.status = fault_status;
    866 	mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length;
    867 }
    868 
    869 /*
    870  * Note that the frag_length for bind ack and alter context is
    871  * non-standard.
    872  */
    873 static int
    874 ndr_build_reply(ndr_xa_t *mxa)
    875 {
    876 	ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
    877 	ndr_stream_t *nds = &mxa->send_nds;
    878 	uint8_t *pdu_buf;
    879 	unsigned long pdu_size;
    880 	unsigned long frag_size;
    881 	unsigned long pdu_data_size;
    882 	unsigned long frag_data_size;
    883 
    884 	frag_size = NDR_FRAG_SZ;
    885 	pdu_size = nds->pdu_size;
    886 	pdu_buf = nds->pdu_base_addr;
    887 
    888 	if (pdu_size <= frag_size) {
    889 		/*
    890 		 * Single fragment response. The PDU size may be zero
    891 		 * here (i.e. bind or fault response). So don't make
    892 		 * any assumptions about it until after the header is
    893 		 * encoded.
    894 		 */
    895 		switch (hdr->ptype) {
    896 		case NDR_PTYPE_BIND_ACK:
    897 			hdr->frag_length = ndr_bind_ack_hdr_size(mxa);
    898 			break;
    899 
    900 		case NDR_PTYPE_FAULT:
    901 			/* already setup */
    902 			break;
    903 
    904 		case NDR_PTYPE_RESPONSE:
    905 			hdr->frag_length = pdu_size;
    906 			mxa->send_hdr.response_hdr.alloc_hint =
    907 			    hdr->frag_length;
    908 			break;
    909 
    910 		case NDR_PTYPE_ALTER_CONTEXT_RESP:
    911 			hdr->frag_length = ndr_alter_context_rsp_hdr_size();
    912 			break;
    913 
    914 		default:
    915 			hdr->frag_length = pdu_size;
    916 			break;
    917 		}
    918 
    919 		nds->pdu_scan_offset = 0;
    920 		(void) ndr_encode_pdu_hdr(mxa);
    921 		pdu_size = nds->pdu_size;
    922 		ndr_build_frag(nds, pdu_buf,  pdu_size);
    923 		return (0);
    924 	}
    925 
    926 	/*
    927 	 * Multiple fragment response.
    928 	 */
    929 	hdr->pfc_flags = NDR_PFC_FIRST_FRAG;
    930 	hdr->frag_length = frag_size;
    931 	mxa->send_hdr.response_hdr.alloc_hint = pdu_size - NDR_RSP_HDR_SIZE;
    932 	nds->pdu_scan_offset = 0;
    933 	(void) ndr_encode_pdu_hdr(mxa);
    934 	ndr_build_frag(nds, pdu_buf,  frag_size);
    935 
    936 	/*
    937 	 * We need to update the 24-byte header in subsequent fragments.
    938 	 *
    939 	 * pdu_data_size:	total data remaining to be handled
    940 	 * frag_size:		total fragment size including header
    941 	 * frag_data_size:	data in fragment
    942 	 *			(i.e. frag_size - NDR_RSP_HDR_SIZE)
    943 	 */
    944 	pdu_data_size = pdu_size - NDR_RSP_HDR_SIZE;
    945 	frag_data_size = frag_size - NDR_RSP_HDR_SIZE;
    946 
    947 	while (pdu_data_size) {
    948 		mxa->send_hdr.response_hdr.alloc_hint -= frag_data_size;
    949 		pdu_data_size -= frag_data_size;
    950 		pdu_buf += frag_data_size;
    951 
    952 		if (pdu_data_size <= frag_data_size) {
    953 			frag_data_size = pdu_data_size;
    954 			frag_size = frag_data_size + NDR_RSP_HDR_SIZE;
    955 			hdr->pfc_flags = NDR_PFC_LAST_FRAG;
    956 		} else {
    957 			hdr->pfc_flags = 0;
    958 		}
    959 
    960 		hdr->frag_length = frag_size;
    961 		nds->pdu_scan_offset = 0;
    962 		(void) ndr_encode_pdu_hdr(mxa);
    963 		bcopy(nds->pdu_base_addr, pdu_buf, NDR_RSP_HDR_SIZE);
    964 
    965 		ndr_build_frag(nds, pdu_buf, frag_size);
    966 
    967 		if (hdr->pfc_flags & NDR_PFC_LAST_FRAG)
    968 			break;
    969 	}
    970 
    971 	return (0);
    972 }
    973 
    974 /*
    975  * ndr_build_frag
    976  *
    977  * Build an RPC PDU fragment from the specified buffer.
    978  * If malloc fails, the client will see a header/pdu inconsistency
    979  * and report an error.
    980  */
    981 static void
    982 ndr_build_frag(ndr_stream_t *nds, uint8_t *buf, uint32_t len)
    983 {
    984 	ndr_frag_t *frag;
    985 	int size = sizeof (ndr_frag_t) + len;
    986 
    987 	if ((frag = (ndr_frag_t *)malloc(size)) == NULL)
    988 		return;
    989 
    990 	frag->next = NULL;
    991 	frag->buf = (uint8_t *)frag + sizeof (ndr_frag_t);
    992 	frag->len = len;
    993 	bcopy(buf, frag->buf, len);
    994 
    995 	if (nds->frags.head == NULL) {
    996 		nds->frags.head = frag;
    997 		nds->frags.tail = frag;
    998 		nds->frags.nfrag = 1;
    999 	} else {
   1000 		nds->frags.tail->next = frag;
   1001 		nds->frags.tail = frag;
   1002 		++nds->frags.nfrag;
   1003 	}
   1004 }
   1005