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