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 
    221 	data = np->np_buf;
    222 	datalen = np->np_uio.uio_offset;
    223 
    224 	if ((mxa = (ndr_xa_t *)malloc(sizeof (ndr_xa_t))) == NULL)
    225 		return (ENOMEM);
    226 
    227 	bzero(mxa, sizeof (ndr_xa_t));
    228 	mxa->fid = np->np_fid;
    229 	mxa->pipe = np;
    230 	mxa->binding_list = np->np_binding;
    231 
    232 	if ((mxa->heap = ndr_heap_create()) == NULL) {
    233 		free(mxa);
    234 		return (ENOMEM);
    235 	}
    236 
    237 	recv_nds = &mxa->recv_nds;
    238 	nds_initialize(recv_nds, datalen, NDR_MODE_CALL_RECV, mxa->heap);
    239 
    240 	/*
    241 	 * Copy the input data and reset the input stream.
    242 	 */
    243 	bcopy(data, recv_nds->pdu_base_addr, datalen);
    244 	ndr_pipe_rewind(np);
    245 
    246 	send_nds = &mxa->send_nds;
    247 	nds_initialize(send_nds, 0, NDR_MODE_RETURN_SEND, mxa->heap);
    248 
    249 	(void) ndr_svc_process(mxa);
    250 
    251 	nds_finalize(send_nds, &np->np_frags);
    252 	nds_destruct(&mxa->recv_nds);
    253 	nds_destruct(&mxa->send_nds);
    254 	ndr_heap_destroy(mxa->heap);
    255 	free(mxa);
    256 	return (0);
    257 }
    258 
    259 /*
    260  * Must be called with ndr_pipe_lock held.
    261  */
    262 static ndr_pipe_t *
    263 ndr_pipe_lookup(int fid)
    264 {
    265 	ndr_pipe_t *np;
    266 	int i;
    267 
    268 	for (i = 0; i < NDR_PIPE_MAX; ++i) {
    269 		np = &ndr_pipe_table[i];
    270 
    271 		if (np->np_fid == fid) {
    272 			if (np->np_refcnt == 0)
    273 				return (NULL);
    274 
    275 			np->np_refcnt++;
    276 			return (np);
    277 		}
    278 	}
    279 
    280 	return (NULL);
    281 }
    282 
    283 /*
    284  * Must be called with ndr_pipe_lock held.
    285  */
    286 static void
    287 ndr_pipe_release(ndr_pipe_t *np)
    288 {
    289 	np->np_refcnt--;
    290 	ndr_pipe_deallocate(np);
    291 }
    292 
    293 /*
    294  * Must be called with ndr_pipe_lock held.
    295  */
    296 static ndr_pipe_t *
    297 ndr_pipe_allocate(int fid)
    298 {
    299 	ndr_pipe_t *np = NULL;
    300 	int i;
    301 
    302 	for (i = 0; i < NDR_PIPE_MAX; ++i) {
    303 		np = &ndr_pipe_table[i];
    304 
    305 		if (np->np_fid == 0) {
    306 			bzero(np, sizeof (ndr_pipe_t));
    307 
    308 			if ((np->np_buf = malloc(NDR_PIPE_BUFSZ)) == NULL)
    309 				return (NULL);
    310 
    311 			ndr_pipe_rewind(np);
    312 			np->np_fid = fid;
    313 			np->np_refcnt = 1;
    314 			return (np);
    315 		}
    316 	}
    317 
    318 	return (NULL);
    319 }
    320 
    321 /*
    322  * Must be called with ndr_pipe_lock held.
    323  */
    324 static void
    325 ndr_pipe_deallocate(ndr_pipe_t *np)
    326 {
    327 	if (np->np_refcnt == 0) {
    328 		/*
    329 		 * Ensure that there are no RPC service policy handles
    330 		 * (associated with this fid) left around.
    331 		 */
    332 		ndr_hdclose(np->np_fid);
    333 
    334 		ndr_pipe_rewind(np);
    335 		ndr_pipe_flush(np);
    336 		free(np->np_buf);
    337 		free(np->np_user.ui_domain);
    338 		free(np->np_user.ui_account);
    339 		free(np->np_user.ui_workstation);
    340 		bzero(np, sizeof (ndr_pipe_t));
    341 	}
    342 }
    343 
    344 /*
    345  * Rewind the input data stream, ready for the next write.
    346  */
    347 static void
    348 ndr_pipe_rewind(ndr_pipe_t *np)
    349 {
    350 	np->np_uio.uio_iov = &np->np_iov;
    351 	np->np_uio.uio_iovcnt = 1;
    352 	np->np_uio.uio_offset = 0;
    353 	np->np_uio.uio_segflg = UIO_USERSPACE;
    354 	np->np_uio.uio_resid = NDR_PIPE_BUFSZ;
    355 	np->np_iov.iov_base = np->np_buf;
    356 	np->np_iov.iov_len = NDR_PIPE_BUFSZ;
    357 }
    358 
    359 /*
    360  * Flush the output data stream.
    361  */
    362 static void
    363 ndr_pipe_flush(ndr_pipe_t *np)
    364 {
    365 	ndr_frag_t *frag;
    366 
    367 	while ((frag = np->np_frags.head) != NULL) {
    368 		np->np_frags.head = frag->next;
    369 		free(frag);
    370 	}
    371 
    372 	free(np->np_frags.iov);
    373 	bzero(&np->np_frags, sizeof (ndr_fraglist_t));
    374 }
    375 
    376 /*
    377  * Check whether or not the specified user has administrator privileges,
    378  * i.e. is a member of Domain Admins or Administrators.
    379  * Returns true if the user is an administrator, otherwise returns false.
    380  */
    381 boolean_t
    382 ndr_is_admin(ndr_xa_t *xa)
    383 {
    384 	smb_netuserinfo_t *ctx = &xa->pipe->np_user;
    385 
    386 	return (ctx->ui_flags & SMB_ATF_ADMIN);
    387 }
    388 
    389 /*
    390  * Check whether or not the specified user has power-user privileges,
    391  * i.e. is a member of Domain Admins, Administrators or Power Users.
    392  * This is typically required for operations such as managing shares.
    393  * Returns true if the user is a power user, otherwise returns false.
    394  */
    395 boolean_t
    396 ndr_is_poweruser(ndr_xa_t *xa)
    397 {
    398 	smb_netuserinfo_t *ctx = &xa->pipe->np_user;
    399 
    400 	return ((ctx->ui_flags & SMB_ATF_ADMIN) ||
    401 	    (ctx->ui_flags & SMB_ATF_POWERUSER));
    402 }
    403 
    404 int32_t
    405 ndr_native_os(ndr_xa_t *xa)
    406 {
    407 	smb_netuserinfo_t *ctx = &xa->pipe->np_user;
    408 
    409 	return (ctx->ui_native_os);
    410 }
    411 
    412 /*
    413  * This is the entry point for all server-side RPC processing.
    414  * It is assumed that the PDU has already been received.
    415  */
    416 static int
    417 ndr_svc_process(ndr_xa_t *mxa)
    418 {
    419 	int rc;
    420 
    421 	rc = ndr_decode_pdu_hdr(mxa);
    422 	if (!NDR_DRC_IS_OK(rc))
    423 		return (-1);
    424 
    425 	(void) ndr_reply_prepare_hdr(mxa);
    426 
    427 	switch (mxa->ptype) {
    428 	case NDR_PTYPE_BIND:
    429 		rc = ndr_svc_bind(mxa);
    430 		break;
    431 
    432 	case NDR_PTYPE_REQUEST:
    433 		rc = ndr_svc_request(mxa);
    434 		break;
    435 
    436 	case NDR_PTYPE_ALTER_CONTEXT:
    437 		rc = ndr_svc_alter_context(mxa);
    438 		break;
    439 
    440 	default:
    441 		rc = NDR_DRC_FAULT_RPCHDR_PTYPE_INVALID;
    442 		break;
    443 	}
    444 
    445 	if (NDR_DRC_IS_FAULT(rc))
    446 		ndr_reply_fault(mxa, rc);
    447 
    448 	(void) ndr_build_reply(mxa);
    449 	return (rc);
    450 }
    451 
    452 /*
    453  * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple
    454  * p_results[] not supported.
    455  */
    456 static int
    457 ndr_svc_bind(ndr_xa_t *mxa)
    458 {
    459 	ndr_p_cont_list_t	*cont_list;
    460 	ndr_p_result_list_t	*result_list;
    461 	ndr_p_result_t		*result;
    462 	unsigned		p_cont_id;
    463 	ndr_binding_t		*mbind;
    464 	ndr_uuid_t		*as_uuid;
    465 	ndr_uuid_t		*ts_uuid;
    466 	int			as_vers;
    467 	int			ts_vers;
    468 	ndr_service_t		*msvc;
    469 	int			rc;
    470 	ndr_port_any_t		*sec_addr;
    471 
    472 	/* acquire targets */
    473 	cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem;
    474 	result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list;
    475 	result = &result_list->p_results[0];
    476 
    477 	/*
    478 	 * Set up temporary secondary address port.
    479 	 * We will correct this later (below).
    480 	 */
    481 	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
    482 	sec_addr->length = 13;
    483 	(void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs");
    484 
    485 	result_list->n_results = 1;
    486 	result_list->reserved = 0;
    487 	result_list->reserved2 = 0;
    488 	result->result = NDR_PCDR_ACCEPTANCE;
    489 	result->reason = 0;
    490 	bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
    491 
    492 	/* sanity check */
    493 	if (cont_list->n_context_elem != 1 ||
    494 	    cont_list->p_cont_elem[0].n_transfer_syn != 1) {
    495 		ndo_trace("ndr_svc_bind: warning: multiple p_cont_elem");
    496 	}
    497 
    498 	p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
    499 
    500 	if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) != NULL) {
    501 		/*
    502 		 * Duplicate presentation context id.
    503 		 */
    504 		ndo_trace("ndr_svc_bind: duplicate binding");
    505 		return (NDR_DRC_FAULT_BIND_PCONT_BUSY);
    506 	}
    507 
    508 	if ((mbind = ndr_svc_new_binding(mxa)) == NULL) {
    509 		/*
    510 		 * No free binding slot
    511 		 */
    512 		result->result = NDR_PCDR_PROVIDER_REJECTION;
    513 		result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED;
    514 		ndo_trace("ndr_svc_bind: no resources");
    515 		return (NDR_DRC_OK);
    516 	}
    517 
    518 	as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
    519 	as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
    520 
    521 	ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
    522 	ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
    523 
    524 	msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers);
    525 	if (msvc == NULL) {
    526 		result->result = NDR_PCDR_PROVIDER_REJECTION;
    527 		result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
    528 		return (NDR_DRC_OK);
    529 	}
    530 
    531 	/*
    532 	 * We can now use the correct secondary address port.
    533 	 */
    534 	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
    535 	sec_addr->length = strlen(msvc->sec_addr_port) + 1;
    536 	(void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port,
    537 	    NDR_PORT_ANY_MAX_PORT_SPEC);
    538 
    539 	mbind->p_cont_id = p_cont_id;
    540 	mbind->which_side = NDR_BIND_SIDE_SERVER;
    541 	/* mbind->context set by app */
    542 	mbind->service = msvc;
    543 	mbind->instance_specific = 0;
    544 
    545 	mxa->binding = mbind;
    546 
    547 	if (msvc->bind_req) {
    548 		/*
    549 		 * Call the service-specific bind() handler.  If
    550 		 * this fails, we shouild send a specific error
    551 		 * on the bind ack.
    552 		 */
    553 		rc = (msvc->bind_req)(mxa);
    554 		if (NDR_DRC_IS_FAULT(rc)) {
    555 			mbind->service = 0;	/* free binding slot */
    556 			mbind->which_side = 0;
    557 			mbind->p_cont_id = 0;
    558 			mbind->instance_specific = 0;
    559 			return (rc);
    560 		}
    561 	}
    562 
    563 	result->transfer_syntax =
    564 	    cont_list->p_cont_elem[0].transfer_syntaxes[0];
    565 
    566 	return (NDR_DRC_BINDING_MADE);
    567 }
    568 
    569 /*
    570  * ndr_svc_alter_context
    571  *
    572  * The alter context request is used to request additional presentation
    573  * context for another interface and/or version.  It is very similar to
    574  * a bind request.
    575  */
    576 static int
    577 ndr_svc_alter_context(ndr_xa_t *mxa)
    578 {
    579 	ndr_p_result_list_t *result_list;
    580 	ndr_p_result_t *result;
    581 	ndr_p_cont_list_t *cont_list;
    582 	ndr_binding_t *mbind;
    583 	ndr_service_t *msvc;
    584 	unsigned p_cont_id;
    585 	ndr_uuid_t *as_uuid;
    586 	ndr_uuid_t *ts_uuid;
    587 	int as_vers;
    588 	int ts_vers;
    589 	ndr_port_any_t *sec_addr;
    590 
    591 	result_list = &mxa->send_hdr.alter_context_rsp_hdr.p_result_list;
    592 	result_list->n_results = 1;
    593 	result_list->reserved = 0;
    594 	result_list->reserved2 = 0;
    595 
    596 	result = &result_list->p_results[0];
    597 	result->result = NDR_PCDR_ACCEPTANCE;
    598 	result->reason = 0;
    599 	bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
    600 
    601 	cont_list = &mxa->recv_hdr.alter_context_hdr.p_context_elem;
    602 	p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
    603 
    604 	if (ndr_svc_find_binding(mxa, p_cont_id) != NULL)
    605 		return (NDR_DRC_FAULT_BIND_PCONT_BUSY);
    606 
    607 	if ((mbind = ndr_svc_new_binding(mxa)) == NULL) {
    608 		result->result = NDR_PCDR_PROVIDER_REJECTION;
    609 		result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED;
    610 		return (NDR_DRC_OK);
    611 	}
    612 
    613 	as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
    614 	as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
    615 
    616 	ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
    617 	ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
    618 
    619 	msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers);
    620 	if (msvc == NULL) {
    621 		result->result = NDR_PCDR_PROVIDER_REJECTION;
    622 		result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
    623 		return (NDR_DRC_OK);
    624 	}
    625 
    626 	mbind->p_cont_id = p_cont_id;
    627 	mbind->which_side = NDR_BIND_SIDE_SERVER;
    628 	/* mbind->context set by app */
    629 	mbind->service = msvc;
    630 	mbind->instance_specific = 0;
    631 	mxa->binding = mbind;
    632 
    633 	sec_addr = &mxa->send_hdr.alter_context_rsp_hdr.sec_addr;
    634 	sec_addr->length = 0;
    635 	bzero(sec_addr->port_spec, NDR_PORT_ANY_MAX_PORT_SPEC);
    636 
    637 	result->transfer_syntax =
    638 	    cont_list->p_cont_elem[0].transfer_syntaxes[0];
    639 
    640 	return (NDR_DRC_BINDING_MADE);
    641 }
    642 
    643 static int
    644 ndr_svc_request(ndr_xa_t *mxa)
    645 {
    646 	ndr_binding_t	*mbind;
    647 	ndr_service_t	*msvc;
    648 	unsigned	p_cont_id;
    649 	int		rc;
    650 
    651 	mxa->opnum = mxa->recv_hdr.request_hdr.opnum;
    652 	p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id;
    653 
    654 	if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) == NULL)
    655 		return (NDR_DRC_FAULT_REQUEST_PCONT_INVALID);
    656 
    657 	mxa->binding = mbind;
    658 	msvc = mbind->service;
    659 
    660 	/*
    661 	 * Make room for the response hdr.
    662 	 */
    663 	mxa->send_nds.pdu_scan_offset = NDR_RSP_HDR_SIZE;
    664 
    665 	if (msvc->call_stub)
    666 		rc = (*msvc->call_stub)(mxa);
    667 	else
    668 		rc = ndr_generic_call_stub(mxa);
    669 
    670 	if (NDR_DRC_IS_FAULT(rc)) {
    671 		ndo_printf(0, 0, "%s[0x%02x]: 0x%04x",
    672 		    msvc->name, mxa->opnum, rc);
    673 	}
    674 
    675 	return (rc);
    676 }
    677 
    678 /*
    679  * The transaction and the two nds streams use the same heap, which
    680  * should already exist at this point.  The heap will also be available
    681  * to the stub.
    682  */
    683 int
    684 ndr_generic_call_stub(ndr_xa_t *mxa)
    685 {
    686 	ndr_binding_t 		*mbind = mxa->binding;
    687 	ndr_service_t		*msvc = mbind->service;
    688 	ndr_typeinfo_t		*intf_ti = msvc->interface_ti;
    689 	ndr_stub_table_t	*ste;
    690 	int			opnum = mxa->opnum;
    691 	unsigned		p_len = intf_ti->c_size_fixed_part;
    692 	char 			*param;
    693 	int			rc;
    694 
    695 	if (mxa->heap == NULL) {
    696 		ndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum);
    697 		return (NDR_DRC_FAULT_OUT_OF_MEMORY);
    698 	}
    699 
    700 	if ((ste = ndr_svc_find_stub(msvc, opnum)) == NULL) {
    701 		ndo_printf(0, 0, "%s[0x%02x]: invalid opnum",
    702 		    msvc->name, opnum);
    703 		return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID);
    704 	}
    705 
    706 	if ((param = ndr_heap_malloc(mxa->heap, p_len)) == NULL)
    707 		return (NDR_DRC_FAULT_OUT_OF_MEMORY);
    708 
    709 	bzero(param, p_len);
    710 
    711 	rc = ndr_decode_call(mxa, param);
    712 	if (!NDR_DRC_IS_OK(rc))
    713 		return (rc);
    714 
    715 	rc = (*ste->func)(param, mxa);
    716 	if (rc == NDR_DRC_OK)
    717 		rc = ndr_encode_return(mxa, param);
    718 
    719 	return (rc);
    720 }
    721 
    722 /*
    723  * We can perform some initial setup of the response header here.
    724  * We also need to cache some of the information from the bind
    725  * negotiation for use during subsequent RPC calls.
    726  */
    727 static void
    728 ndr_reply_prepare_hdr(ndr_xa_t *mxa)
    729 {
    730 	ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
    731 	ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
    732 
    733 	hdr->rpc_vers = 5;
    734 	hdr->rpc_vers_minor = 0;
    735 	hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG;
    736 	hdr->packed_drep = rhdr->packed_drep;
    737 	hdr->frag_length = 0;
    738 	hdr->auth_length = 0;
    739 	hdr->call_id = rhdr->call_id;
    740 #ifdef _BIG_ENDIAN
    741 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
    742 	    | NDR_REPLAB_INTG_BIG_ENDIAN;
    743 #else
    744 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
    745 	    | NDR_REPLAB_INTG_LITTLE_ENDIAN;
    746 #endif
    747 
    748 	switch (mxa->ptype) {
    749 	case NDR_PTYPE_BIND:
    750 		hdr->ptype = NDR_PTYPE_BIND_ACK;
    751 		mxa->send_hdr.bind_ack_hdr.max_xmit_frag =
    752 		    mxa->recv_hdr.bind_hdr.max_xmit_frag;
    753 		mxa->send_hdr.bind_ack_hdr.max_recv_frag =
    754 		    mxa->recv_hdr.bind_hdr.max_recv_frag;
    755 		mxa->send_hdr.bind_ack_hdr.assoc_group_id =
    756 		    mxa->recv_hdr.bind_hdr.assoc_group_id;
    757 
    758 		if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0)
    759 			mxa->send_hdr.bind_ack_hdr.assoc_group_id = time(0);
    760 
    761 		/*
    762 		 * Save the maximum fragment sizes
    763 		 * for use with subsequent requests.
    764 		 */
    765 		mxa->pipe->np_max_xmit_frag =
    766 		    mxa->recv_hdr.bind_hdr.max_xmit_frag;
    767 		mxa->pipe->np_max_recv_frag =
    768 		    mxa->recv_hdr.bind_hdr.max_recv_frag;
    769 		break;
    770 
    771 	case NDR_PTYPE_REQUEST:
    772 		hdr->ptype = NDR_PTYPE_RESPONSE;
    773 		/* mxa->send_hdr.response_hdr.alloc_hint */
    774 		mxa->send_hdr.response_hdr.p_cont_id =
    775 		    mxa->recv_hdr.request_hdr.p_cont_id;
    776 		mxa->send_hdr.response_hdr.cancel_count = 0;
    777 		mxa->send_hdr.response_hdr.reserved = 0;
    778 		break;
    779 
    780 	case NDR_PTYPE_ALTER_CONTEXT:
    781 		hdr->ptype = NDR_PTYPE_ALTER_CONTEXT_RESP;
    782 		/*
    783 		 * The max_xmit_frag, max_recv_frag and assoc_group_id are
    784 		 * ignored by the client but it's useful to fill them in.
    785 		 */
    786 		mxa->send_hdr.alter_context_rsp_hdr.max_xmit_frag =
    787 		    mxa->recv_hdr.alter_context_hdr.max_xmit_frag;
    788 		mxa->send_hdr.alter_context_rsp_hdr.max_recv_frag =
    789 		    mxa->recv_hdr.alter_context_hdr.max_recv_frag;
    790 		mxa->send_hdr.alter_context_rsp_hdr.assoc_group_id =
    791 		    mxa->recv_hdr.alter_context_hdr.assoc_group_id;
    792 		break;
    793 
    794 	default:
    795 		hdr->ptype = 0xFF;
    796 	}
    797 }
    798 
    799 /*
    800  * Signal an RPC fault. The stream is reset and we overwrite whatever
    801  * was in the response header with the fault information.
    802  */
    803 static void
    804 ndr_reply_fault(ndr_xa_t *mxa, unsigned long drc)
    805 {
    806 	ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
    807 	ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
    808 	ndr_stream_t *nds = &mxa->send_nds;
    809 	unsigned long fault_status;
    810 
    811 	NDS_RESET(nds);
    812 
    813 	hdr->rpc_vers = 5;
    814 	hdr->rpc_vers_minor = 0;
    815 	hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG;
    816 	hdr->packed_drep = rhdr->packed_drep;
    817 	hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr);
    818 	hdr->auth_length = 0;
    819 	hdr->call_id = rhdr->call_id;
    820 #ifdef _BIG_ENDIAN
    821 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
    822 	    | NDR_REPLAB_INTG_BIG_ENDIAN;
    823 #else
    824 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
    825 	    | NDR_REPLAB_INTG_LITTLE_ENDIAN;
    826 #endif
    827 
    828 	switch (drc & NDR_DRC_MASK_SPECIFIER) {
    829 	case NDR_DRC_FAULT_OUT_OF_MEMORY:
    830 	case NDR_DRC_FAULT_ENCODE_TOO_BIG:
    831 		fault_status = NDR_FAULT_NCA_OUT_ARGS_TOO_BIG;
    832 		break;
    833 
    834 	case NDR_DRC_FAULT_REQUEST_PCONT_INVALID:
    835 		fault_status = NDR_FAULT_NCA_INVALID_PRES_CONTEXT_ID;
    836 		break;
    837 
    838 	case NDR_DRC_FAULT_REQUEST_OPNUM_INVALID:
    839 		fault_status = NDR_FAULT_NCA_OP_RNG_ERROR;
    840 		break;
    841 
    842 	case NDR_DRC_FAULT_DECODE_FAILED:
    843 	case NDR_DRC_FAULT_ENCODE_FAILED:
    844 		fault_status = NDR_FAULT_NCA_PROTO_ERROR;
    845 		break;
    846 
    847 	default:
    848 		fault_status = NDR_FAULT_NCA_UNSPEC_REJECT;
    849 		break;
    850 	}
    851 
    852 	mxa->send_hdr.fault_hdr.common_hdr.ptype = NDR_PTYPE_FAULT;
    853 	mxa->send_hdr.fault_hdr.status = fault_status;
    854 	mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length;
    855 }
    856 
    857 /*
    858  * Note that the frag_length for bind ack and alter context is
    859  * non-standard.
    860  */
    861 static int
    862 ndr_build_reply(ndr_xa_t *mxa)
    863 {
    864 	ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
    865 	ndr_stream_t *nds = &mxa->send_nds;
    866 	uint8_t *pdu_buf;
    867 	unsigned long pdu_size;
    868 	unsigned long frag_size;
    869 	unsigned long pdu_data_size;
    870 	unsigned long frag_data_size;
    871 
    872 	frag_size = NDR_FRAG_SZ;
    873 	pdu_size = nds->pdu_size;
    874 	pdu_buf = nds->pdu_base_addr;
    875 
    876 	if (pdu_size <= frag_size) {
    877 		/*
    878 		 * Single fragment response. The PDU size may be zero
    879 		 * here (i.e. bind or fault response). So don't make
    880 		 * any assumptions about it until after the header is
    881 		 * encoded.
    882 		 */
    883 		switch (hdr->ptype) {
    884 		case NDR_PTYPE_BIND_ACK:
    885 			hdr->frag_length = ndr_bind_ack_hdr_size(mxa);
    886 			break;
    887 
    888 		case NDR_PTYPE_FAULT:
    889 			/* already setup */
    890 			break;
    891 
    892 		case NDR_PTYPE_RESPONSE:
    893 			hdr->frag_length = pdu_size;
    894 			mxa->send_hdr.response_hdr.alloc_hint =
    895 			    hdr->frag_length;
    896 			break;
    897 
    898 		case NDR_PTYPE_ALTER_CONTEXT_RESP:
    899 			hdr->frag_length = ndr_alter_context_rsp_hdr_size();
    900 			break;
    901 
    902 		default:
    903 			hdr->frag_length = pdu_size;
    904 			break;
    905 		}
    906 
    907 		nds->pdu_scan_offset = 0;
    908 		(void) ndr_encode_pdu_hdr(mxa);
    909 		pdu_size = nds->pdu_size;
    910 		ndr_build_frag(nds, pdu_buf,  pdu_size);
    911 		return (0);
    912 	}
    913 
    914 	/*
    915 	 * Multiple fragment response.
    916 	 */
    917 	hdr->pfc_flags = NDR_PFC_FIRST_FRAG;
    918 	hdr->frag_length = frag_size;
    919 	mxa->send_hdr.response_hdr.alloc_hint = pdu_size - NDR_RSP_HDR_SIZE;
    920 	nds->pdu_scan_offset = 0;
    921 	(void) ndr_encode_pdu_hdr(mxa);
    922 	ndr_build_frag(nds, pdu_buf,  frag_size);
    923 
    924 	/*
    925 	 * We need to update the 24-byte header in subsequent fragments.
    926 	 *
    927 	 * pdu_data_size:	total data remaining to be handled
    928 	 * frag_size:		total fragment size including header
    929 	 * frag_data_size:	data in fragment
    930 	 *			(i.e. frag_size - NDR_RSP_HDR_SIZE)
    931 	 */
    932 	pdu_data_size = pdu_size - NDR_RSP_HDR_SIZE;
    933 	frag_data_size = frag_size - NDR_RSP_HDR_SIZE;
    934 
    935 	while (pdu_data_size) {
    936 		mxa->send_hdr.response_hdr.alloc_hint -= frag_data_size;
    937 		pdu_data_size -= frag_data_size;
    938 		pdu_buf += frag_data_size;
    939 
    940 		if (pdu_data_size <= frag_data_size) {
    941 			frag_data_size = pdu_data_size;
    942 			frag_size = frag_data_size + NDR_RSP_HDR_SIZE;
    943 			hdr->pfc_flags = NDR_PFC_LAST_FRAG;
    944 		} else {
    945 			hdr->pfc_flags = 0;
    946 		}
    947 
    948 		hdr->frag_length = frag_size;
    949 		nds->pdu_scan_offset = 0;
    950 		(void) ndr_encode_pdu_hdr(mxa);
    951 		bcopy(nds->pdu_base_addr, pdu_buf, NDR_RSP_HDR_SIZE);
    952 
    953 		ndr_build_frag(nds, pdu_buf, frag_size);
    954 
    955 		if (hdr->pfc_flags & NDR_PFC_LAST_FRAG)
    956 			break;
    957 	}
    958 
    959 	return (0);
    960 }
    961 
    962 /*
    963  * ndr_build_frag
    964  *
    965  * Build an RPC PDU fragment from the specified buffer.
    966  * If malloc fails, the client will see a header/pdu inconsistency
    967  * and report an error.
    968  */
    969 static void
    970 ndr_build_frag(ndr_stream_t *nds, uint8_t *buf, uint32_t len)
    971 {
    972 	ndr_frag_t *frag;
    973 	int size = sizeof (ndr_frag_t) + len;
    974 
    975 	if ((frag = (ndr_frag_t *)malloc(size)) == NULL)
    976 		return;
    977 
    978 	frag->next = NULL;
    979 	frag->buf = (uint8_t *)frag + sizeof (ndr_frag_t);
    980 	frag->len = len;
    981 	bcopy(buf, frag->buf, len);
    982 
    983 	if (nds->frags.head == NULL) {
    984 		nds->frags.head = frag;
    985 		nds->frags.tail = frag;
    986 		nds->frags.nfrag = 1;
    987 	} else {
    988 		nds->frags.tail->next = frag;
    989 		nds->frags.tail = frag;
    990 		++nds->frags.nfrag;
    991 	}
    992 }
    993