15772Sas200622 /*
25772Sas200622 * CDDL HEADER START
35772Sas200622 *
45772Sas200622 * The contents of this file are subject to the terms of the
55772Sas200622 * Common Development and Distribution License (the "License").
65772Sas200622 * You may not use this file except in compliance with the License.
75772Sas200622 *
85772Sas200622 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95772Sas200622 * or http://www.opensolaris.org/os/licensing.
105772Sas200622 * See the License for the specific language governing permissions
115772Sas200622 * and limitations under the License.
125772Sas200622 *
135772Sas200622 * When distributing Covered Code, include this CDDL HEADER in each
145772Sas200622 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155772Sas200622 * If applicable, add the following below this CDDL HEADER, with the
165772Sas200622 * fields enclosed by brackets "[]" replaced with your own identifying
175772Sas200622 * information: Portions Copyright [yyyy] [name of copyright owner]
185772Sas200622 *
195772Sas200622 * CDDL HEADER END
205772Sas200622 */
215772Sas200622 /*
22*12890SJoyce.McIntosh@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
235772Sas200622 */
245772Sas200622
255772Sas200622 /*
265772Sas200622 * Server side RPC handler.
275772Sas200622 */
285772Sas200622
295772Sas200622 #include <sys/byteorder.h>
307052Samw #include <sys/errno.h>
317052Samw #include <sys/uio.h>
325772Sas200622 #include <thread.h>
335772Sas200622 #include <synch.h>
345772Sas200622 #include <stdlib.h>
355772Sas200622 #include <strings.h>
365772Sas200622 #include <string.h>
375772Sas200622 #include <time.h>
385772Sas200622
395772Sas200622 #include <smbsrv/libsmb.h>
405772Sas200622 #include <smbsrv/libmlrpc.h>
418474SJose.Borrego@Sun.COM #include <smbsrv/ntaccess.h>
425772Sas200622
435772Sas200622 /*
445772Sas200622 * Fragment size (5680: NT style).
455772Sas200622 */
468334SJose.Borrego@Sun.COM #define NDR_FRAG_SZ 5680
475772Sas200622
4811963SAfshin.Ardakani@Sun.COM #define NDR_GROW_SIZE (8 * 1024)
4911963SAfshin.Ardakani@Sun.COM #define NDR_GROW_MASK (NDR_GROW_SIZE - 1)
5011963SAfshin.Ardakani@Sun.COM #define NDR_ALIGN_BUF(S) (((S) + NDR_GROW_SIZE) & ~NDR_GROW_MASK)
5111963SAfshin.Ardakani@Sun.COM
5211963SAfshin.Ardakani@Sun.COM #define NDR_PIPE_BUFSZ (64 * 1024)
5311963SAfshin.Ardakani@Sun.COM #define NDR_PIPE_BUFMAX (64 * 1024 * 1024)
548334SJose.Borrego@Sun.COM #define NDR_PIPE_MAX 128
5511963SAfshin.Ardakani@Sun.COM
568334SJose.Borrego@Sun.COM static ndr_pipe_t ndr_pipe_table[NDR_PIPE_MAX];
578334SJose.Borrego@Sun.COM static mutex_t ndr_pipe_lock;
585772Sas200622
5911963SAfshin.Ardakani@Sun.COM static int ndr_pipe_process(ndr_pipe_t *);
608334SJose.Borrego@Sun.COM static ndr_pipe_t *ndr_pipe_lookup(int);
618334SJose.Borrego@Sun.COM static void ndr_pipe_release(ndr_pipe_t *);
628334SJose.Borrego@Sun.COM static ndr_pipe_t *ndr_pipe_allocate(int);
6311963SAfshin.Ardakani@Sun.COM static int ndr_pipe_grow(ndr_pipe_t *, size_t);
648334SJose.Borrego@Sun.COM static void ndr_pipe_deallocate(ndr_pipe_t *);
658334SJose.Borrego@Sun.COM static void ndr_pipe_rewind(ndr_pipe_t *);
668334SJose.Borrego@Sun.COM static void ndr_pipe_flush(ndr_pipe_t *);
677052Samw
688334SJose.Borrego@Sun.COM static int ndr_svc_process(ndr_xa_t *);
6911963SAfshin.Ardakani@Sun.COM static int ndr_svc_defrag(ndr_xa_t *);
708334SJose.Borrego@Sun.COM static int ndr_svc_bind(ndr_xa_t *);
718334SJose.Borrego@Sun.COM static int ndr_svc_request(ndr_xa_t *);
728334SJose.Borrego@Sun.COM static void ndr_reply_prepare_hdr(ndr_xa_t *);
738334SJose.Borrego@Sun.COM static int ndr_svc_alter_context(ndr_xa_t *);
748334SJose.Borrego@Sun.COM static void ndr_reply_fault(ndr_xa_t *, unsigned long);
758334SJose.Borrego@Sun.COM static int ndr_build_reply(ndr_xa_t *);
768334SJose.Borrego@Sun.COM static void ndr_build_frag(ndr_stream_t *, uint8_t *, uint32_t);
775772Sas200622
785772Sas200622 /*
797052Samw * Allocate and associate a service context with a fid.
807052Samw */
817052Samw int
ndr_pipe_open(int fid,uint8_t * data,uint32_t datalen)828334SJose.Borrego@Sun.COM ndr_pipe_open(int fid, uint8_t *data, uint32_t datalen)
837052Samw {
848334SJose.Borrego@Sun.COM ndr_pipe_t *np;
857052Samw
868334SJose.Borrego@Sun.COM (void) mutex_lock(&ndr_pipe_lock);
877052Samw
888334SJose.Borrego@Sun.COM if ((np = ndr_pipe_lookup(fid)) != NULL) {
898334SJose.Borrego@Sun.COM ndr_pipe_release(np);
908334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock);
917052Samw return (EEXIST);
927052Samw }
937052Samw
948334SJose.Borrego@Sun.COM if ((np = ndr_pipe_allocate(fid)) == NULL) {
958334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock);
967052Samw return (ENOMEM);
977052Samw }
987052Samw
9910122SJordan.Brown@Sun.COM if (smb_netuserinfo_decode(&np->np_user, data, datalen, NULL) == -1) {
1008334SJose.Borrego@Sun.COM ndr_pipe_release(np);
1018334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock);
1027052Samw return (EINVAL);
1037052Samw }
1047052Samw
1058334SJose.Borrego@Sun.COM ndr_svc_binding_pool_init(&np->np_binding, np->np_binding_pool,
1068334SJose.Borrego@Sun.COM NDR_N_BINDING_POOL);
1077052Samw
1088334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock);
1097052Samw return (0);
1107052Samw }
1117052Samw
1127052Samw /*
1137052Samw * Release the context associated with a fid when an opipe is closed.
1147052Samw */
1157052Samw int
ndr_pipe_close(int fid)1168334SJose.Borrego@Sun.COM ndr_pipe_close(int fid)
1177052Samw {
1188334SJose.Borrego@Sun.COM ndr_pipe_t *np;
1197052Samw
1208334SJose.Borrego@Sun.COM (void) mutex_lock(&ndr_pipe_lock);
1217052Samw
1228334SJose.Borrego@Sun.COM if ((np = ndr_pipe_lookup(fid)) == NULL) {
1238334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock);
1247052Samw return (ENOENT);
1257052Samw }
1267052Samw
1277052Samw /*
1287052Samw * Release twice: once for the lookup above
1297052Samw * and again to close the fid.
1307052Samw */
1318334SJose.Borrego@Sun.COM ndr_pipe_release(np);
1328334SJose.Borrego@Sun.COM ndr_pipe_release(np);
1338334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock);
1347052Samw return (0);
1357052Samw }
1367052Samw
1377052Samw /*
1387052Samw * Write RPC request data to the input stream. Input data is buffered
1397052Samw * until the response is requested.
1405772Sas200622 */
1417052Samw int
ndr_pipe_write(int fid,uint8_t * buf,uint32_t len)1428334SJose.Borrego@Sun.COM ndr_pipe_write(int fid, uint8_t *buf, uint32_t len)
1437052Samw {
14411963SAfshin.Ardakani@Sun.COM ndr_pipe_t *np;
14511963SAfshin.Ardakani@Sun.COM ssize_t nbytes;
14611963SAfshin.Ardakani@Sun.COM int rc;
1477052Samw
1487052Samw if (len == 0)
1497052Samw return (0);
1507052Samw
1518334SJose.Borrego@Sun.COM (void) mutex_lock(&ndr_pipe_lock);
1527052Samw
1538334SJose.Borrego@Sun.COM if ((np = ndr_pipe_lookup(fid)) == NULL) {
1548334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock);
1557052Samw return (ENOENT);
1567052Samw }
1577052Samw
15811963SAfshin.Ardakani@Sun.COM if ((rc = ndr_pipe_grow(np, len)) != 0) {
15911963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&ndr_pipe_lock);
16011963SAfshin.Ardakani@Sun.COM return (rc);
16111963SAfshin.Ardakani@Sun.COM }
16211963SAfshin.Ardakani@Sun.COM
1638334SJose.Borrego@Sun.COM nbytes = ndr_uiomove((caddr_t)buf, len, UIO_READ, &np->np_uio);
1647052Samw
1658334SJose.Borrego@Sun.COM ndr_pipe_release(np);
1668334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock);
1677052Samw return ((nbytes == len) ? 0 : EIO);
1687052Samw }
1697052Samw
1707052Samw /*
17111963SAfshin.Ardakani@Sun.COM * Read RPC response data.
1727052Samw */
1737052Samw int
ndr_pipe_read(int fid,uint8_t * buf,uint32_t * len,uint32_t * resid)1748334SJose.Borrego@Sun.COM ndr_pipe_read(int fid, uint8_t *buf, uint32_t *len, uint32_t *resid)
1755772Sas200622 {
1768334SJose.Borrego@Sun.COM ndr_pipe_t *np;
1777052Samw ssize_t nbytes = *len;
1787052Samw
1797052Samw if (nbytes == 0) {
1807052Samw *resid = 0;
1817052Samw return (0);
1827052Samw }
1837052Samw
1848334SJose.Borrego@Sun.COM (void) mutex_lock(&ndr_pipe_lock);
1858334SJose.Borrego@Sun.COM if ((np = ndr_pipe_lookup(fid)) == NULL) {
1868334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock);
1877052Samw return (ENOENT);
1887052Samw }
1898334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock);
1907052Samw
1918334SJose.Borrego@Sun.COM *len = ndr_uiomove((caddr_t)buf, nbytes, UIO_WRITE, &np->np_frags.uio);
1928334SJose.Borrego@Sun.COM *resid = np->np_frags.uio.uio_resid;
1937052Samw
1947052Samw if (*resid == 0) {
1957052Samw /*
1967052Samw * Nothing left, cleanup the output stream.
1977052Samw */
1988334SJose.Borrego@Sun.COM ndr_pipe_flush(np);
1997052Samw }
2007052Samw
2018334SJose.Borrego@Sun.COM (void) mutex_lock(&ndr_pipe_lock);
2028334SJose.Borrego@Sun.COM ndr_pipe_release(np);
2038334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock);
2047052Samw return (0);
2057052Samw }
2067052Samw
2077052Samw /*
20811963SAfshin.Ardakani@Sun.COM * If the input stream contains an RPC request, process the RPC transaction,
20911963SAfshin.Ardakani@Sun.COM * which will place the RPC response in the output (frags) stream.
21011963SAfshin.Ardakani@Sun.COM *
21111963SAfshin.Ardakani@Sun.COM * arg is freed here; it must have been allocated by malloc().
21211963SAfshin.Ardakani@Sun.COM */
21311963SAfshin.Ardakani@Sun.COM void *
ndr_pipe_transact(void * arg)21411963SAfshin.Ardakani@Sun.COM ndr_pipe_transact(void *arg)
21511963SAfshin.Ardakani@Sun.COM {
21611963SAfshin.Ardakani@Sun.COM uint32_t *tmp = (uint32_t *)arg;
21711963SAfshin.Ardakani@Sun.COM uint32_t fid;
21811963SAfshin.Ardakani@Sun.COM ndr_pipe_t *np;
21911963SAfshin.Ardakani@Sun.COM
22011963SAfshin.Ardakani@Sun.COM if (arg == NULL)
22111963SAfshin.Ardakani@Sun.COM return (NULL);
22211963SAfshin.Ardakani@Sun.COM
22311963SAfshin.Ardakani@Sun.COM fid = *tmp;
22411963SAfshin.Ardakani@Sun.COM
22511963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&ndr_pipe_lock);
22611963SAfshin.Ardakani@Sun.COM if ((np = ndr_pipe_lookup(fid)) == NULL) {
22711963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&ndr_pipe_lock);
22811963SAfshin.Ardakani@Sun.COM (void) smb_kmod_event_notify(fid);
22911963SAfshin.Ardakani@Sun.COM free(arg);
23011963SAfshin.Ardakani@Sun.COM return (NULL);
23111963SAfshin.Ardakani@Sun.COM }
23211963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&ndr_pipe_lock);
23311963SAfshin.Ardakani@Sun.COM
23411963SAfshin.Ardakani@Sun.COM if (ndr_pipe_process(np) != 0)
23511963SAfshin.Ardakani@Sun.COM ndr_pipe_flush(np);
23611963SAfshin.Ardakani@Sun.COM
23711963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&ndr_pipe_lock);
23811963SAfshin.Ardakani@Sun.COM ndr_pipe_release(np);
23911963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&ndr_pipe_lock);
24011963SAfshin.Ardakani@Sun.COM (void) smb_kmod_event_notify(fid);
24111963SAfshin.Ardakani@Sun.COM free(arg);
24211963SAfshin.Ardakani@Sun.COM return (NULL);
24311963SAfshin.Ardakani@Sun.COM }
24411963SAfshin.Ardakani@Sun.COM
24511963SAfshin.Ardakani@Sun.COM /*
2467052Samw * Process a server-side RPC request.
2477052Samw */
2487052Samw static int
ndr_pipe_process(ndr_pipe_t * np)24911963SAfshin.Ardakani@Sun.COM ndr_pipe_process(ndr_pipe_t *np)
2507052Samw {
2518334SJose.Borrego@Sun.COM ndr_xa_t *mxa;
2528334SJose.Borrego@Sun.COM ndr_stream_t *recv_nds;
2538334SJose.Borrego@Sun.COM ndr_stream_t *send_nds;
2548334SJose.Borrego@Sun.COM char *data;
2558334SJose.Borrego@Sun.COM int datalen;
25611337SWilliam.Krier@Sun.COM int rc;
2575772Sas200622
2588334SJose.Borrego@Sun.COM data = np->np_buf;
2598334SJose.Borrego@Sun.COM datalen = np->np_uio.uio_offset;
2605772Sas200622
26111963SAfshin.Ardakani@Sun.COM if (datalen == 0)
26211963SAfshin.Ardakani@Sun.COM return (0);
26311963SAfshin.Ardakani@Sun.COM
2647052Samw if ((mxa = (ndr_xa_t *)malloc(sizeof (ndr_xa_t))) == NULL)
2657052Samw return (ENOMEM);
2665772Sas200622
2678334SJose.Borrego@Sun.COM bzero(mxa, sizeof (ndr_xa_t));
2688334SJose.Borrego@Sun.COM mxa->fid = np->np_fid;
2698334SJose.Borrego@Sun.COM mxa->pipe = np;
2708334SJose.Borrego@Sun.COM mxa->binding_list = np->np_binding;
2715772Sas200622
2728334SJose.Borrego@Sun.COM if ((mxa->heap = ndr_heap_create()) == NULL) {
2735772Sas200622 free(mxa);
2747052Samw return (ENOMEM);
2755772Sas200622 }
2765772Sas200622
2778334SJose.Borrego@Sun.COM recv_nds = &mxa->recv_nds;
27811337SWilliam.Krier@Sun.COM rc = nds_initialize(recv_nds, datalen, NDR_MODE_CALL_RECV, mxa->heap);
27911337SWilliam.Krier@Sun.COM if (rc != 0) {
28011337SWilliam.Krier@Sun.COM ndr_heap_destroy(mxa->heap);
28111337SWilliam.Krier@Sun.COM free(mxa);
28211337SWilliam.Krier@Sun.COM return (ENOMEM);
28311337SWilliam.Krier@Sun.COM }
2845772Sas200622
2857052Samw /*
2867052Samw * Copy the input data and reset the input stream.
2877052Samw */
2888334SJose.Borrego@Sun.COM bcopy(data, recv_nds->pdu_base_addr, datalen);
2898334SJose.Borrego@Sun.COM ndr_pipe_rewind(np);
2905772Sas200622
2918334SJose.Borrego@Sun.COM send_nds = &mxa->send_nds;
29211337SWilliam.Krier@Sun.COM rc = nds_initialize(send_nds, 0, NDR_MODE_RETURN_SEND, mxa->heap);
29311337SWilliam.Krier@Sun.COM if (rc != 0) {
29411337SWilliam.Krier@Sun.COM nds_destruct(&mxa->recv_nds);
29511337SWilliam.Krier@Sun.COM ndr_heap_destroy(mxa->heap);
29611337SWilliam.Krier@Sun.COM free(mxa);
29711337SWilliam.Krier@Sun.COM return (ENOMEM);
29811337SWilliam.Krier@Sun.COM }
2995772Sas200622
3008334SJose.Borrego@Sun.COM (void) ndr_svc_process(mxa);
3015772Sas200622
3028334SJose.Borrego@Sun.COM nds_finalize(send_nds, &np->np_frags);
3038334SJose.Borrego@Sun.COM nds_destruct(&mxa->recv_nds);
3048334SJose.Borrego@Sun.COM nds_destruct(&mxa->send_nds);
3058334SJose.Borrego@Sun.COM ndr_heap_destroy(mxa->heap);
3065772Sas200622 free(mxa);
3077052Samw return (0);
3087052Samw }
3097052Samw
3107052Samw /*
3118334SJose.Borrego@Sun.COM * Must be called with ndr_pipe_lock held.
3127052Samw */
3138334SJose.Borrego@Sun.COM static ndr_pipe_t *
ndr_pipe_lookup(int fid)3148334SJose.Borrego@Sun.COM ndr_pipe_lookup(int fid)
3157052Samw {
3168334SJose.Borrego@Sun.COM ndr_pipe_t *np;
3177052Samw int i;
3187052Samw
3198334SJose.Borrego@Sun.COM for (i = 0; i < NDR_PIPE_MAX; ++i) {
3208334SJose.Borrego@Sun.COM np = &ndr_pipe_table[i];
3217052Samw
3228334SJose.Borrego@Sun.COM if (np->np_fid == fid) {
3238334SJose.Borrego@Sun.COM if (np->np_refcnt == 0)
3247052Samw return (NULL);
3257052Samw
3268334SJose.Borrego@Sun.COM np->np_refcnt++;
3278334SJose.Borrego@Sun.COM return (np);
3287052Samw }
3297052Samw }
3307052Samw
3317052Samw return (NULL);
3325772Sas200622 }
3335772Sas200622
3345772Sas200622 /*
3358334SJose.Borrego@Sun.COM * Must be called with ndr_pipe_lock held.
3365772Sas200622 */
3377052Samw static void
ndr_pipe_release(ndr_pipe_t * np)3388334SJose.Borrego@Sun.COM ndr_pipe_release(ndr_pipe_t *np)
3395772Sas200622 {
3408334SJose.Borrego@Sun.COM np->np_refcnt--;
3418334SJose.Borrego@Sun.COM ndr_pipe_deallocate(np);
3427052Samw }
3437052Samw
3447052Samw /*
3458334SJose.Borrego@Sun.COM * Must be called with ndr_pipe_lock held.
3467052Samw */
3478334SJose.Borrego@Sun.COM static ndr_pipe_t *
ndr_pipe_allocate(int fid)3488334SJose.Borrego@Sun.COM ndr_pipe_allocate(int fid)
3497052Samw {
3508334SJose.Borrego@Sun.COM ndr_pipe_t *np = NULL;
3515772Sas200622 int i;
3525772Sas200622
3538334SJose.Borrego@Sun.COM for (i = 0; i < NDR_PIPE_MAX; ++i) {
3548334SJose.Borrego@Sun.COM np = &ndr_pipe_table[i];
3555772Sas200622
3568334SJose.Borrego@Sun.COM if (np->np_fid == 0) {
3578334SJose.Borrego@Sun.COM bzero(np, sizeof (ndr_pipe_t));
3585772Sas200622
3598334SJose.Borrego@Sun.COM if ((np->np_buf = malloc(NDR_PIPE_BUFSZ)) == NULL)
3607052Samw return (NULL);
3615772Sas200622
3628334SJose.Borrego@Sun.COM ndr_pipe_rewind(np);
3638334SJose.Borrego@Sun.COM np->np_fid = fid;
3648334SJose.Borrego@Sun.COM np->np_refcnt = 1;
3658334SJose.Borrego@Sun.COM return (np);
3665772Sas200622 }
3675772Sas200622 }
3685772Sas200622
3697052Samw return (NULL);
3707052Samw }
3715772Sas200622
3727052Samw /*
37311963SAfshin.Ardakani@Sun.COM * If the desired space exceeds the current pipe size, try to expand
37411963SAfshin.Ardakani@Sun.COM * the pipe. Leave the current pipe intact if the realloc fails.
37511963SAfshin.Ardakani@Sun.COM *
37611963SAfshin.Ardakani@Sun.COM * Must be called with ndr_pipe_lock held.
37711963SAfshin.Ardakani@Sun.COM */
37811963SAfshin.Ardakani@Sun.COM static int
ndr_pipe_grow(ndr_pipe_t * np,size_t desired)37911963SAfshin.Ardakani@Sun.COM ndr_pipe_grow(ndr_pipe_t *np, size_t desired)
38011963SAfshin.Ardakani@Sun.COM {
38111963SAfshin.Ardakani@Sun.COM char *newbuf;
38211963SAfshin.Ardakani@Sun.COM size_t current;
38311963SAfshin.Ardakani@Sun.COM size_t required;
38411963SAfshin.Ardakani@Sun.COM
38511963SAfshin.Ardakani@Sun.COM required = np->np_uio.uio_offset + desired;
38611963SAfshin.Ardakani@Sun.COM current = np->np_uio.uio_offset + np->np_uio.uio_resid;
38711963SAfshin.Ardakani@Sun.COM
38811963SAfshin.Ardakani@Sun.COM if (required <= current)
38911963SAfshin.Ardakani@Sun.COM return (0);
39011963SAfshin.Ardakani@Sun.COM
39111963SAfshin.Ardakani@Sun.COM if (required > NDR_PIPE_BUFMAX) {
39211963SAfshin.Ardakani@Sun.COM smb_tracef("ndr_pipe_grow: required=%d, max=%d (ENOSPC)",
39311963SAfshin.Ardakani@Sun.COM required, NDR_PIPE_BUFMAX);
39411963SAfshin.Ardakani@Sun.COM return (ENOSPC);
39511963SAfshin.Ardakani@Sun.COM }
39611963SAfshin.Ardakani@Sun.COM
39711963SAfshin.Ardakani@Sun.COM required = NDR_ALIGN_BUF(required);
39811963SAfshin.Ardakani@Sun.COM if (required > NDR_PIPE_BUFMAX)
39911963SAfshin.Ardakani@Sun.COM required = NDR_PIPE_BUFMAX;
40011963SAfshin.Ardakani@Sun.COM
40111963SAfshin.Ardakani@Sun.COM if ((newbuf = realloc(np->np_buf, required)) == NULL) {
40211963SAfshin.Ardakani@Sun.COM smb_tracef("ndr_pipe_grow: realloc failed (ENOMEM)");
40311963SAfshin.Ardakani@Sun.COM return (ENOMEM);
40411963SAfshin.Ardakani@Sun.COM }
40511963SAfshin.Ardakani@Sun.COM
40611963SAfshin.Ardakani@Sun.COM np->np_buf = newbuf;
407*12890SJoyce.McIntosh@Sun.COM np->np_iov.iov_base = np->np_buf + np->np_uio.uio_offset;
40811963SAfshin.Ardakani@Sun.COM np->np_uio.uio_resid += desired;
40911963SAfshin.Ardakani@Sun.COM np->np_iov.iov_len += desired;
41011963SAfshin.Ardakani@Sun.COM return (0);
41111963SAfshin.Ardakani@Sun.COM }
41211963SAfshin.Ardakani@Sun.COM
41311963SAfshin.Ardakani@Sun.COM /*
4148334SJose.Borrego@Sun.COM * Must be called with ndr_pipe_lock held.
4157052Samw */
4167052Samw static void
ndr_pipe_deallocate(ndr_pipe_t * np)4178334SJose.Borrego@Sun.COM ndr_pipe_deallocate(ndr_pipe_t *np)
4187052Samw {
4198334SJose.Borrego@Sun.COM if (np->np_refcnt == 0) {
4207052Samw /*
4217052Samw * Ensure that there are no RPC service policy handles
4227052Samw * (associated with this fid) left around.
4237052Samw */
4248334SJose.Borrego@Sun.COM ndr_hdclose(np->np_fid);
4255772Sas200622
4268334SJose.Borrego@Sun.COM ndr_pipe_rewind(np);
4278334SJose.Borrego@Sun.COM ndr_pipe_flush(np);
4288334SJose.Borrego@Sun.COM free(np->np_buf);
42910122SJordan.Brown@Sun.COM free(np->np_user.ui_domain);
43010122SJordan.Brown@Sun.COM free(np->np_user.ui_account);
43110122SJordan.Brown@Sun.COM free(np->np_user.ui_workstation);
4328334SJose.Borrego@Sun.COM bzero(np, sizeof (ndr_pipe_t));
4337052Samw }
4347052Samw }
4355772Sas200622
4367052Samw /*
4377052Samw * Rewind the input data stream, ready for the next write.
4387052Samw */
4397052Samw static void
ndr_pipe_rewind(ndr_pipe_t * np)4408334SJose.Borrego@Sun.COM ndr_pipe_rewind(ndr_pipe_t *np)
4417052Samw {
4428334SJose.Borrego@Sun.COM np->np_uio.uio_iov = &np->np_iov;
4438334SJose.Borrego@Sun.COM np->np_uio.uio_iovcnt = 1;
4448334SJose.Borrego@Sun.COM np->np_uio.uio_offset = 0;
4458334SJose.Borrego@Sun.COM np->np_uio.uio_segflg = UIO_USERSPACE;
4468334SJose.Borrego@Sun.COM np->np_uio.uio_resid = NDR_PIPE_BUFSZ;
4478334SJose.Borrego@Sun.COM np->np_iov.iov_base = np->np_buf;
4488334SJose.Borrego@Sun.COM np->np_iov.iov_len = NDR_PIPE_BUFSZ;
4495772Sas200622 }
4505772Sas200622
4515772Sas200622 /*
4527052Samw * Flush the output data stream.
4535772Sas200622 */
4547052Samw static void
ndr_pipe_flush(ndr_pipe_t * np)4558334SJose.Borrego@Sun.COM ndr_pipe_flush(ndr_pipe_t *np)
4565772Sas200622 {
4577052Samw ndr_frag_t *frag;
4585772Sas200622
4598334SJose.Borrego@Sun.COM while ((frag = np->np_frags.head) != NULL) {
4608334SJose.Borrego@Sun.COM np->np_frags.head = frag->next;
4617052Samw free(frag);
4625772Sas200622 }
4635772Sas200622
4648334SJose.Borrego@Sun.COM free(np->np_frags.iov);
4658334SJose.Borrego@Sun.COM bzero(&np->np_frags, sizeof (ndr_fraglist_t));
4667052Samw }
4677052Samw
4687052Samw /*
4697052Samw * Check whether or not the specified user has administrator privileges,
4707052Samw * i.e. is a member of Domain Admins or Administrators.
4717052Samw * Returns true if the user is an administrator, otherwise returns false.
4727052Samw */
4737052Samw boolean_t
ndr_is_admin(ndr_xa_t * xa)4747052Samw ndr_is_admin(ndr_xa_t *xa)
4757052Samw {
47610122SJordan.Brown@Sun.COM smb_netuserinfo_t *ctx = &xa->pipe->np_user;
4777052Samw
47810122SJordan.Brown@Sun.COM return (ctx->ui_flags & SMB_ATF_ADMIN);
4797052Samw }
4807052Samw
4817052Samw /*
4827052Samw * Check whether or not the specified user has power-user privileges,
4837052Samw * i.e. is a member of Domain Admins, Administrators or Power Users.
4847052Samw * This is typically required for operations such as managing shares.
4857052Samw * Returns true if the user is a power user, otherwise returns false.
4867052Samw */
4877052Samw boolean_t
ndr_is_poweruser(ndr_xa_t * xa)4887052Samw ndr_is_poweruser(ndr_xa_t *xa)
4897052Samw {
49010122SJordan.Brown@Sun.COM smb_netuserinfo_t *ctx = &xa->pipe->np_user;
4917052Samw
49210122SJordan.Brown@Sun.COM return ((ctx->ui_flags & SMB_ATF_ADMIN) ||
49310122SJordan.Brown@Sun.COM (ctx->ui_flags & SMB_ATF_POWERUSER));
4947052Samw }
4957052Samw
4967052Samw int32_t
ndr_native_os(ndr_xa_t * xa)4977052Samw ndr_native_os(ndr_xa_t *xa)
4987052Samw {
49910122SJordan.Brown@Sun.COM smb_netuserinfo_t *ctx = &xa->pipe->np_user;
5007052Samw
50110122SJordan.Brown@Sun.COM return (ctx->ui_native_os);
5025772Sas200622 }
5035772Sas200622
5045772Sas200622 /*
5055772Sas200622 * This is the entry point for all server-side RPC processing.
5065772Sas200622 * It is assumed that the PDU has already been received.
5075772Sas200622 */
5085772Sas200622 static int
ndr_svc_process(ndr_xa_t * mxa)5098334SJose.Borrego@Sun.COM ndr_svc_process(ndr_xa_t *mxa)
5105772Sas200622 {
51111963SAfshin.Ardakani@Sun.COM ndr_common_header_t *hdr = &mxa->recv_hdr.common_hdr;
51211963SAfshin.Ardakani@Sun.COM ndr_stream_t *nds = &mxa->recv_nds;
51311963SAfshin.Ardakani@Sun.COM unsigned long saved_offset;
51411963SAfshin.Ardakani@Sun.COM unsigned long saved_size;
51511963SAfshin.Ardakani@Sun.COM int rc;
5165772Sas200622
5178334SJose.Borrego@Sun.COM rc = ndr_decode_pdu_hdr(mxa);
5188334SJose.Borrego@Sun.COM if (!NDR_DRC_IS_OK(rc))
5195772Sas200622 return (-1);
5205772Sas200622
5218334SJose.Borrego@Sun.COM (void) ndr_reply_prepare_hdr(mxa);
5225772Sas200622
5235772Sas200622 switch (mxa->ptype) {
5248334SJose.Borrego@Sun.COM case NDR_PTYPE_BIND:
5258334SJose.Borrego@Sun.COM rc = ndr_svc_bind(mxa);
5265772Sas200622 break;
5275772Sas200622
5288334SJose.Borrego@Sun.COM case NDR_PTYPE_REQUEST:
52911963SAfshin.Ardakani@Sun.COM if (!NDR_IS_FIRST_FRAG(hdr->pfc_flags)) {
53011963SAfshin.Ardakani@Sun.COM ndr_show_hdr(hdr);
53111963SAfshin.Ardakani@Sun.COM rc = NDR_DRC_FAULT_DECODE_FAILED;
53211963SAfshin.Ardakani@Sun.COM goto ndr_svc_process_fault;
53311963SAfshin.Ardakani@Sun.COM }
53411963SAfshin.Ardakani@Sun.COM
53511963SAfshin.Ardakani@Sun.COM if (!NDR_IS_LAST_FRAG(hdr->pfc_flags)) {
53611963SAfshin.Ardakani@Sun.COM /*
53711963SAfshin.Ardakani@Sun.COM * Multi-fragment request. Preserve the PDU scan
53811963SAfshin.Ardakani@Sun.COM * offset and size during defrag so that we can
53911963SAfshin.Ardakani@Sun.COM * continue as if we had received contiguous data.
54011963SAfshin.Ardakani@Sun.COM */
54111963SAfshin.Ardakani@Sun.COM saved_offset = nds->pdu_scan_offset;
54211963SAfshin.Ardakani@Sun.COM saved_size = nds->pdu_size;
54311963SAfshin.Ardakani@Sun.COM
54411963SAfshin.Ardakani@Sun.COM nds->pdu_scan_offset = hdr->frag_length;
54511963SAfshin.Ardakani@Sun.COM nds->pdu_size = nds->pdu_max_size;
54611963SAfshin.Ardakani@Sun.COM
54711963SAfshin.Ardakani@Sun.COM rc = ndr_svc_defrag(mxa);
54811963SAfshin.Ardakani@Sun.COM if (NDR_DRC_IS_FAULT(rc)) {
54911963SAfshin.Ardakani@Sun.COM ndr_show_hdr(hdr);
55011963SAfshin.Ardakani@Sun.COM nds_show_state(nds);
55111963SAfshin.Ardakani@Sun.COM goto ndr_svc_process_fault;
55211963SAfshin.Ardakani@Sun.COM }
55311963SAfshin.Ardakani@Sun.COM
55411963SAfshin.Ardakani@Sun.COM nds->pdu_scan_offset = saved_offset;
55511963SAfshin.Ardakani@Sun.COM nds->pdu_size = saved_size;
55611963SAfshin.Ardakani@Sun.COM }
55711963SAfshin.Ardakani@Sun.COM
5588334SJose.Borrego@Sun.COM rc = ndr_svc_request(mxa);
5595772Sas200622 break;
5605772Sas200622
5618334SJose.Borrego@Sun.COM case NDR_PTYPE_ALTER_CONTEXT:
5628334SJose.Borrego@Sun.COM rc = ndr_svc_alter_context(mxa);
5635772Sas200622 break;
5645772Sas200622
5655772Sas200622 default:
5668334SJose.Borrego@Sun.COM rc = NDR_DRC_FAULT_RPCHDR_PTYPE_INVALID;
5675772Sas200622 break;
5685772Sas200622 }
5695772Sas200622
57011963SAfshin.Ardakani@Sun.COM ndr_svc_process_fault:
5718334SJose.Borrego@Sun.COM if (NDR_DRC_IS_FAULT(rc))
5728334SJose.Borrego@Sun.COM ndr_reply_fault(mxa, rc);
5735772Sas200622
5748334SJose.Borrego@Sun.COM (void) ndr_build_reply(mxa);
5755772Sas200622 return (rc);
5765772Sas200622 }
5775772Sas200622
5785772Sas200622 /*
57911963SAfshin.Ardakani@Sun.COM * Remove RPC fragment headers from the received data stream.
58011963SAfshin.Ardakani@Sun.COM * The first fragment has already been accounted for before this call.
58111963SAfshin.Ardakani@Sun.COM *
58211963SAfshin.Ardakani@Sun.COM * NDR stream on entry:
58311963SAfshin.Ardakani@Sun.COM *
58411963SAfshin.Ardakani@Sun.COM * |<-- frag 2 -->|<-- frag 3 -->| ... |<- last frag ->|
58511963SAfshin.Ardakani@Sun.COM *
58611963SAfshin.Ardakani@Sun.COM * +-----+--------+-----+--------+-----+-----+---------+
58711963SAfshin.Ardakani@Sun.COM * | hdr | data | hdr | data | ... | hdr | data |
58811963SAfshin.Ardakani@Sun.COM * +-----+--------+-----+--------+-----+-----+---------+
58911963SAfshin.Ardakani@Sun.COM *
59011963SAfshin.Ardakani@Sun.COM * NDR stream on return:
59111963SAfshin.Ardakani@Sun.COM *
59211963SAfshin.Ardakani@Sun.COM * +----------------------------------+
59311963SAfshin.Ardakani@Sun.COM * | data |
59411963SAfshin.Ardakani@Sun.COM * +----------------------------------+
59511963SAfshin.Ardakani@Sun.COM */
59611963SAfshin.Ardakani@Sun.COM static int
ndr_svc_defrag(ndr_xa_t * mxa)59711963SAfshin.Ardakani@Sun.COM ndr_svc_defrag(ndr_xa_t *mxa)
59811963SAfshin.Ardakani@Sun.COM {
59911963SAfshin.Ardakani@Sun.COM ndr_stream_t *nds = &mxa->recv_nds;
60011963SAfshin.Ardakani@Sun.COM ndr_common_header_t frag_hdr;
60111963SAfshin.Ardakani@Sun.COM int frag_size;
60211963SAfshin.Ardakani@Sun.COM int last_frag;
60311963SAfshin.Ardakani@Sun.COM
60411963SAfshin.Ardakani@Sun.COM do {
60511963SAfshin.Ardakani@Sun.COM ndr_decode_frag_hdr(nds, &frag_hdr);
60611963SAfshin.Ardakani@Sun.COM ndr_show_hdr(&frag_hdr);
60711963SAfshin.Ardakani@Sun.COM
60811963SAfshin.Ardakani@Sun.COM if (NDR_IS_FIRST_FRAG(frag_hdr.pfc_flags))
60911963SAfshin.Ardakani@Sun.COM return (NDR_DRC_FAULT_DECODE_FAILED);
61011963SAfshin.Ardakani@Sun.COM
61111963SAfshin.Ardakani@Sun.COM last_frag = NDR_IS_LAST_FRAG(frag_hdr.pfc_flags);
61211963SAfshin.Ardakani@Sun.COM frag_size = frag_hdr.frag_length;
61311963SAfshin.Ardakani@Sun.COM
61411963SAfshin.Ardakani@Sun.COM if (frag_size > (nds->pdu_size - nds->pdu_scan_offset))
61511963SAfshin.Ardakani@Sun.COM return (NDR_DRC_FAULT_DECODE_FAILED);
61611963SAfshin.Ardakani@Sun.COM
61711963SAfshin.Ardakani@Sun.COM ndr_remove_frag_hdr(nds);
61811963SAfshin.Ardakani@Sun.COM nds->pdu_scan_offset += frag_size - NDR_RSP_HDR_SIZE;
61911963SAfshin.Ardakani@Sun.COM } while (!last_frag);
62011963SAfshin.Ardakani@Sun.COM
62111963SAfshin.Ardakani@Sun.COM return (NDR_DRC_OK);
62211963SAfshin.Ardakani@Sun.COM }
62311963SAfshin.Ardakani@Sun.COM
62411963SAfshin.Ardakani@Sun.COM /*
6255772Sas200622 * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple
6265772Sas200622 * p_results[] not supported.
6275772Sas200622 */
6285772Sas200622 static int
ndr_svc_bind(ndr_xa_t * mxa)6298334SJose.Borrego@Sun.COM ndr_svc_bind(ndr_xa_t *mxa)
6305772Sas200622 {
6318334SJose.Borrego@Sun.COM ndr_p_cont_list_t *cont_list;
6328334SJose.Borrego@Sun.COM ndr_p_result_list_t *result_list;
6338334SJose.Borrego@Sun.COM ndr_p_result_t *result;
6345772Sas200622 unsigned p_cont_id;
6358334SJose.Borrego@Sun.COM ndr_binding_t *mbind;
6365772Sas200622 ndr_uuid_t *as_uuid;
6375772Sas200622 ndr_uuid_t *ts_uuid;
6385772Sas200622 int as_vers;
6395772Sas200622 int ts_vers;
6408334SJose.Borrego@Sun.COM ndr_service_t *msvc;
6415772Sas200622 int rc;
6428334SJose.Borrego@Sun.COM ndr_port_any_t *sec_addr;
6435772Sas200622
6445772Sas200622 /* acquire targets */
6455772Sas200622 cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem;
6465772Sas200622 result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list;
6475772Sas200622 result = &result_list->p_results[0];
6485772Sas200622
6495772Sas200622 /*
6505772Sas200622 * Set up temporary secondary address port.
6515772Sas200622 * We will correct this later (below).
6525772Sas200622 */
6535772Sas200622 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
6545772Sas200622 sec_addr->length = 13;
6555772Sas200622 (void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs");
6565772Sas200622
6575772Sas200622 result_list->n_results = 1;
6585772Sas200622 result_list->reserved = 0;
6595772Sas200622 result_list->reserved2 = 0;
6608334SJose.Borrego@Sun.COM result->result = NDR_PCDR_ACCEPTANCE;
6615772Sas200622 result->reason = 0;
6625772Sas200622 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
6635772Sas200622
6645772Sas200622 /* sanity check */
6655772Sas200622 if (cont_list->n_context_elem != 1 ||
6665772Sas200622 cont_list->p_cont_elem[0].n_transfer_syn != 1) {
6678334SJose.Borrego@Sun.COM ndo_trace("ndr_svc_bind: warning: multiple p_cont_elem");
6685772Sas200622 }
6695772Sas200622
6705772Sas200622 p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
6715772Sas200622
6728334SJose.Borrego@Sun.COM if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) != NULL) {
6735772Sas200622 /*
6748334SJose.Borrego@Sun.COM * Duplicate presentation context id.
6755772Sas200622 */
6768334SJose.Borrego@Sun.COM ndo_trace("ndr_svc_bind: duplicate binding");
6778334SJose.Borrego@Sun.COM return (NDR_DRC_FAULT_BIND_PCONT_BUSY);
6785772Sas200622 }
6795772Sas200622
6808334SJose.Borrego@Sun.COM if ((mbind = ndr_svc_new_binding(mxa)) == NULL) {
6815772Sas200622 /*
6825772Sas200622 * No free binding slot
6835772Sas200622 */
6848334SJose.Borrego@Sun.COM result->result = NDR_PCDR_PROVIDER_REJECTION;
6858334SJose.Borrego@Sun.COM result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED;
6868334SJose.Borrego@Sun.COM ndo_trace("ndr_svc_bind: no resources");
6878334SJose.Borrego@Sun.COM return (NDR_DRC_OK);
6885772Sas200622 }
6895772Sas200622
6905772Sas200622 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
6915772Sas200622 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
6925772Sas200622
6935772Sas200622 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
6945772Sas200622 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
6955772Sas200622
6968334SJose.Borrego@Sun.COM msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers);
6978334SJose.Borrego@Sun.COM if (msvc == NULL) {
6988334SJose.Borrego@Sun.COM result->result = NDR_PCDR_PROVIDER_REJECTION;
6998334SJose.Borrego@Sun.COM result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
7008334SJose.Borrego@Sun.COM return (NDR_DRC_OK);
7015772Sas200622 }
7025772Sas200622
7035772Sas200622 /*
7045772Sas200622 * We can now use the correct secondary address port.
7055772Sas200622 */
7065772Sas200622 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
7075772Sas200622 sec_addr->length = strlen(msvc->sec_addr_port) + 1;
7085772Sas200622 (void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port,
7098334SJose.Borrego@Sun.COM NDR_PORT_ANY_MAX_PORT_SPEC);
7105772Sas200622
7115772Sas200622 mbind->p_cont_id = p_cont_id;
7128334SJose.Borrego@Sun.COM mbind->which_side = NDR_BIND_SIDE_SERVER;
7135772Sas200622 /* mbind->context set by app */
7145772Sas200622 mbind->service = msvc;
7155772Sas200622 mbind->instance_specific = 0;
7165772Sas200622
7175772Sas200622 mxa->binding = mbind;
7185772Sas200622
7195772Sas200622 if (msvc->bind_req) {
7205772Sas200622 /*
7215772Sas200622 * Call the service-specific bind() handler. If
7225772Sas200622 * this fails, we shouild send a specific error
7235772Sas200622 * on the bind ack.
7245772Sas200622 */
7255772Sas200622 rc = (msvc->bind_req)(mxa);
7268334SJose.Borrego@Sun.COM if (NDR_DRC_IS_FAULT(rc)) {
7275772Sas200622 mbind->service = 0; /* free binding slot */
7285772Sas200622 mbind->which_side = 0;
7295772Sas200622 mbind->p_cont_id = 0;
7305772Sas200622 mbind->instance_specific = 0;
7315772Sas200622 return (rc);
7325772Sas200622 }
7335772Sas200622 }
7345772Sas200622
7355772Sas200622 result->transfer_syntax =
7365772Sas200622 cont_list->p_cont_elem[0].transfer_syntaxes[0];
7375772Sas200622
7388334SJose.Borrego@Sun.COM return (NDR_DRC_BINDING_MADE);
7395772Sas200622 }
7405772Sas200622
7415772Sas200622 /*
7428334SJose.Borrego@Sun.COM * ndr_svc_alter_context
7435772Sas200622 *
7445772Sas200622 * The alter context request is used to request additional presentation
7457619SJose.Borrego@Sun.COM * context for another interface and/or version. It is very similar to
7467619SJose.Borrego@Sun.COM * a bind request.
7475772Sas200622 */
7485772Sas200622 static int
ndr_svc_alter_context(ndr_xa_t * mxa)7498334SJose.Borrego@Sun.COM ndr_svc_alter_context(ndr_xa_t *mxa)
7505772Sas200622 {
7518334SJose.Borrego@Sun.COM ndr_p_result_list_t *result_list;
7528334SJose.Borrego@Sun.COM ndr_p_result_t *result;
7538334SJose.Borrego@Sun.COM ndr_p_cont_list_t *cont_list;
7548334SJose.Borrego@Sun.COM ndr_binding_t *mbind;
7558334SJose.Borrego@Sun.COM ndr_service_t *msvc;
7565772Sas200622 unsigned p_cont_id;
7575772Sas200622 ndr_uuid_t *as_uuid;
7585772Sas200622 ndr_uuid_t *ts_uuid;
7595772Sas200622 int as_vers;
7605772Sas200622 int ts_vers;
7618334SJose.Borrego@Sun.COM ndr_port_any_t *sec_addr;
7625772Sas200622
7637619SJose.Borrego@Sun.COM result_list = &mxa->send_hdr.alter_context_rsp_hdr.p_result_list;
7645772Sas200622 result_list->n_results = 1;
7655772Sas200622 result_list->reserved = 0;
7665772Sas200622 result_list->reserved2 = 0;
7675772Sas200622
7685772Sas200622 result = &result_list->p_results[0];
7698334SJose.Borrego@Sun.COM result->result = NDR_PCDR_ACCEPTANCE;
7705772Sas200622 result->reason = 0;
7715772Sas200622 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
7725772Sas200622
7737619SJose.Borrego@Sun.COM cont_list = &mxa->recv_hdr.alter_context_hdr.p_context_elem;
7745772Sas200622 p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
7755772Sas200622
7768334SJose.Borrego@Sun.COM if (ndr_svc_find_binding(mxa, p_cont_id) != NULL)
7778334SJose.Borrego@Sun.COM return (NDR_DRC_FAULT_BIND_PCONT_BUSY);
7785772Sas200622
7798334SJose.Borrego@Sun.COM if ((mbind = ndr_svc_new_binding(mxa)) == NULL) {
7808334SJose.Borrego@Sun.COM result->result = NDR_PCDR_PROVIDER_REJECTION;
7818334SJose.Borrego@Sun.COM result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED;
7828334SJose.Borrego@Sun.COM return (NDR_DRC_OK);
7835772Sas200622 }
7845772Sas200622
7855772Sas200622 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
7865772Sas200622 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
7875772Sas200622
7885772Sas200622 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
7895772Sas200622 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
7905772Sas200622
7918334SJose.Borrego@Sun.COM msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers);
7928334SJose.Borrego@Sun.COM if (msvc == NULL) {
7938334SJose.Borrego@Sun.COM result->result = NDR_PCDR_PROVIDER_REJECTION;
7948334SJose.Borrego@Sun.COM result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
7958334SJose.Borrego@Sun.COM return (NDR_DRC_OK);
7965772Sas200622 }
7975772Sas200622
7985772Sas200622 mbind->p_cont_id = p_cont_id;
7998334SJose.Borrego@Sun.COM mbind->which_side = NDR_BIND_SIDE_SERVER;
8005772Sas200622 /* mbind->context set by app */
8015772Sas200622 mbind->service = msvc;
8025772Sas200622 mbind->instance_specific = 0;
8035772Sas200622 mxa->binding = mbind;
8045772Sas200622
8057619SJose.Borrego@Sun.COM sec_addr = &mxa->send_hdr.alter_context_rsp_hdr.sec_addr;
8065772Sas200622 sec_addr->length = 0;
8078334SJose.Borrego@Sun.COM bzero(sec_addr->port_spec, NDR_PORT_ANY_MAX_PORT_SPEC);
8085772Sas200622
8095772Sas200622 result->transfer_syntax =
8105772Sas200622 cont_list->p_cont_elem[0].transfer_syntaxes[0];
8115772Sas200622
8128334SJose.Borrego@Sun.COM return (NDR_DRC_BINDING_MADE);
8135772Sas200622 }
8145772Sas200622
8155772Sas200622 static int
ndr_svc_request(ndr_xa_t * mxa)8168334SJose.Borrego@Sun.COM ndr_svc_request(ndr_xa_t *mxa)
8175772Sas200622 {
8188334SJose.Borrego@Sun.COM ndr_binding_t *mbind;
8198334SJose.Borrego@Sun.COM ndr_service_t *msvc;
8208334SJose.Borrego@Sun.COM unsigned p_cont_id;
8218334SJose.Borrego@Sun.COM int rc;
8225772Sas200622
8235772Sas200622 mxa->opnum = mxa->recv_hdr.request_hdr.opnum;
8245772Sas200622 p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id;
8255772Sas200622
8268334SJose.Borrego@Sun.COM if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) == NULL)
8278334SJose.Borrego@Sun.COM return (NDR_DRC_FAULT_REQUEST_PCONT_INVALID);
8285772Sas200622
8295772Sas200622 mxa->binding = mbind;
8305772Sas200622 msvc = mbind->service;
8315772Sas200622
8325772Sas200622 /*
8335772Sas200622 * Make room for the response hdr.
8345772Sas200622 */
8358334SJose.Borrego@Sun.COM mxa->send_nds.pdu_scan_offset = NDR_RSP_HDR_SIZE;
8365772Sas200622
8375772Sas200622 if (msvc->call_stub)
8385772Sas200622 rc = (*msvc->call_stub)(mxa);
8395772Sas200622 else
8408334SJose.Borrego@Sun.COM rc = ndr_generic_call_stub(mxa);
8415772Sas200622
8428334SJose.Borrego@Sun.COM if (NDR_DRC_IS_FAULT(rc)) {
8438334SJose.Borrego@Sun.COM ndo_printf(0, 0, "%s[0x%02x]: 0x%04x",
8445772Sas200622 msvc->name, mxa->opnum, rc);
8455772Sas200622 }
8465772Sas200622
8475772Sas200622 return (rc);
8485772Sas200622 }
8495772Sas200622
8505772Sas200622 /*
8518334SJose.Borrego@Sun.COM * The transaction and the two nds streams use the same heap, which
8525772Sas200622 * should already exist at this point. The heap will also be available
8535772Sas200622 * to the stub.
8545772Sas200622 */
8555772Sas200622 int
ndr_generic_call_stub(ndr_xa_t * mxa)8568334SJose.Borrego@Sun.COM ndr_generic_call_stub(ndr_xa_t *mxa)
8575772Sas200622 {
8588334SJose.Borrego@Sun.COM ndr_binding_t *mbind = mxa->binding;
8598334SJose.Borrego@Sun.COM ndr_service_t *msvc = mbind->service;
8608334SJose.Borrego@Sun.COM ndr_typeinfo_t *intf_ti = msvc->interface_ti;
8618334SJose.Borrego@Sun.COM ndr_stub_table_t *ste;
8625772Sas200622 int opnum = mxa->opnum;
8635772Sas200622 unsigned p_len = intf_ti->c_size_fixed_part;
8645772Sas200622 char *param;
8655772Sas200622 int rc;
8665772Sas200622
8675772Sas200622 if (mxa->heap == NULL) {
8688334SJose.Borrego@Sun.COM ndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum);
8698334SJose.Borrego@Sun.COM return (NDR_DRC_FAULT_OUT_OF_MEMORY);
8705772Sas200622 }
8715772Sas200622
8728334SJose.Borrego@Sun.COM if ((ste = ndr_svc_find_stub(msvc, opnum)) == NULL) {
8738334SJose.Borrego@Sun.COM ndo_printf(0, 0, "%s[0x%02x]: invalid opnum",
8745772Sas200622 msvc->name, opnum);
8758334SJose.Borrego@Sun.COM return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID);
8765772Sas200622 }
8775772Sas200622
8788334SJose.Borrego@Sun.COM if ((param = ndr_heap_malloc(mxa->heap, p_len)) == NULL)
8798334SJose.Borrego@Sun.COM return (NDR_DRC_FAULT_OUT_OF_MEMORY);
8805772Sas200622
8815772Sas200622 bzero(param, p_len);
8825772Sas200622
8838334SJose.Borrego@Sun.COM rc = ndr_decode_call(mxa, param);
8848334SJose.Borrego@Sun.COM if (!NDR_DRC_IS_OK(rc))
8855772Sas200622 return (rc);
8865772Sas200622
8875772Sas200622 rc = (*ste->func)(param, mxa);
8888334SJose.Borrego@Sun.COM if (rc == NDR_DRC_OK)
8898334SJose.Borrego@Sun.COM rc = ndr_encode_return(mxa, param);
8905772Sas200622
8915772Sas200622 return (rc);
8925772Sas200622 }
8935772Sas200622
8945772Sas200622 /*
8955772Sas200622 * We can perform some initial setup of the response header here.
8965772Sas200622 * We also need to cache some of the information from the bind
8975772Sas200622 * negotiation for use during subsequent RPC calls.
8985772Sas200622 */
8995772Sas200622 static void
ndr_reply_prepare_hdr(ndr_xa_t * mxa)9008334SJose.Borrego@Sun.COM ndr_reply_prepare_hdr(ndr_xa_t *mxa)
9015772Sas200622 {
9027619SJose.Borrego@Sun.COM ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
9037619SJose.Borrego@Sun.COM ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
9045772Sas200622
9055772Sas200622 hdr->rpc_vers = 5;
9065772Sas200622 hdr->rpc_vers_minor = 0;
9078334SJose.Borrego@Sun.COM hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG;
9085772Sas200622 hdr->packed_drep = rhdr->packed_drep;
9095772Sas200622 hdr->frag_length = 0;
9105772Sas200622 hdr->auth_length = 0;
9115772Sas200622 hdr->call_id = rhdr->call_id;
9125772Sas200622 #ifdef _BIG_ENDIAN
9138334SJose.Borrego@Sun.COM hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
9148334SJose.Borrego@Sun.COM | NDR_REPLAB_INTG_BIG_ENDIAN;
9155772Sas200622 #else
9168334SJose.Borrego@Sun.COM hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
9178334SJose.Borrego@Sun.COM | NDR_REPLAB_INTG_LITTLE_ENDIAN;
9185772Sas200622 #endif
9195772Sas200622
9205772Sas200622 switch (mxa->ptype) {
9218334SJose.Borrego@Sun.COM case NDR_PTYPE_BIND:
9228334SJose.Borrego@Sun.COM hdr->ptype = NDR_PTYPE_BIND_ACK;
9235772Sas200622 mxa->send_hdr.bind_ack_hdr.max_xmit_frag =
9245772Sas200622 mxa->recv_hdr.bind_hdr.max_xmit_frag;
9255772Sas200622 mxa->send_hdr.bind_ack_hdr.max_recv_frag =
9265772Sas200622 mxa->recv_hdr.bind_hdr.max_recv_frag;
9275772Sas200622 mxa->send_hdr.bind_ack_hdr.assoc_group_id =
9285772Sas200622 mxa->recv_hdr.bind_hdr.assoc_group_id;
9295772Sas200622
9305772Sas200622 if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0)
9315772Sas200622 mxa->send_hdr.bind_ack_hdr.assoc_group_id = time(0);
9325772Sas200622
9335772Sas200622 /*
9345772Sas200622 * Save the maximum fragment sizes
9355772Sas200622 * for use with subsequent requests.
9365772Sas200622 */
9378334SJose.Borrego@Sun.COM mxa->pipe->np_max_xmit_frag =
9385772Sas200622 mxa->recv_hdr.bind_hdr.max_xmit_frag;
9398334SJose.Borrego@Sun.COM mxa->pipe->np_max_recv_frag =
9405772Sas200622 mxa->recv_hdr.bind_hdr.max_recv_frag;
9415772Sas200622 break;
9425772Sas200622
9438334SJose.Borrego@Sun.COM case NDR_PTYPE_REQUEST:
9448334SJose.Borrego@Sun.COM hdr->ptype = NDR_PTYPE_RESPONSE;
9455772Sas200622 /* mxa->send_hdr.response_hdr.alloc_hint */
9465772Sas200622 mxa->send_hdr.response_hdr.p_cont_id =
9475772Sas200622 mxa->recv_hdr.request_hdr.p_cont_id;
9485772Sas200622 mxa->send_hdr.response_hdr.cancel_count = 0;
9495772Sas200622 mxa->send_hdr.response_hdr.reserved = 0;
9505772Sas200622 break;
9515772Sas200622
9528334SJose.Borrego@Sun.COM case NDR_PTYPE_ALTER_CONTEXT:
9538334SJose.Borrego@Sun.COM hdr->ptype = NDR_PTYPE_ALTER_CONTEXT_RESP;
9545772Sas200622 /*
9557619SJose.Borrego@Sun.COM * The max_xmit_frag, max_recv_frag and assoc_group_id are
9567619SJose.Borrego@Sun.COM * ignored by the client but it's useful to fill them in.
9575772Sas200622 */
9587619SJose.Borrego@Sun.COM mxa->send_hdr.alter_context_rsp_hdr.max_xmit_frag =
9597619SJose.Borrego@Sun.COM mxa->recv_hdr.alter_context_hdr.max_xmit_frag;
9607619SJose.Borrego@Sun.COM mxa->send_hdr.alter_context_rsp_hdr.max_recv_frag =
9617619SJose.Borrego@Sun.COM mxa->recv_hdr.alter_context_hdr.max_recv_frag;
9627619SJose.Borrego@Sun.COM mxa->send_hdr.alter_context_rsp_hdr.assoc_group_id =
9637619SJose.Borrego@Sun.COM mxa->recv_hdr.alter_context_hdr.assoc_group_id;
9645772Sas200622 break;
9655772Sas200622
9665772Sas200622 default:
9675772Sas200622 hdr->ptype = 0xFF;
9685772Sas200622 }
9695772Sas200622 }
9705772Sas200622
9715772Sas200622 /*
9725772Sas200622 * Signal an RPC fault. The stream is reset and we overwrite whatever
9735772Sas200622 * was in the response header with the fault information.
9745772Sas200622 */
9755772Sas200622 static void
ndr_reply_fault(ndr_xa_t * mxa,unsigned long drc)9768334SJose.Borrego@Sun.COM ndr_reply_fault(ndr_xa_t *mxa, unsigned long drc)
9775772Sas200622 {
9787619SJose.Borrego@Sun.COM ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
9797619SJose.Borrego@Sun.COM ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
9808334SJose.Borrego@Sun.COM ndr_stream_t *nds = &mxa->send_nds;
9815772Sas200622 unsigned long fault_status;
9825772Sas200622
9838334SJose.Borrego@Sun.COM NDS_RESET(nds);
9845772Sas200622
9855772Sas200622 hdr->rpc_vers = 5;
9865772Sas200622 hdr->rpc_vers_minor = 0;
9878334SJose.Borrego@Sun.COM hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG;
9885772Sas200622 hdr->packed_drep = rhdr->packed_drep;
9895772Sas200622 hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr);
9905772Sas200622 hdr->auth_length = 0;
9915772Sas200622 hdr->call_id = rhdr->call_id;
9925772Sas200622 #ifdef _BIG_ENDIAN
9938334SJose.Borrego@Sun.COM hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
9948334SJose.Borrego@Sun.COM | NDR_REPLAB_INTG_BIG_ENDIAN;
9955772Sas200622 #else
9968334SJose.Borrego@Sun.COM hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII
9978334SJose.Borrego@Sun.COM | NDR_REPLAB_INTG_LITTLE_ENDIAN;
9985772Sas200622 #endif
9995772Sas200622
10008334SJose.Borrego@Sun.COM switch (drc & NDR_DRC_MASK_SPECIFIER) {
10018334SJose.Borrego@Sun.COM case NDR_DRC_FAULT_OUT_OF_MEMORY:
10028334SJose.Borrego@Sun.COM case NDR_DRC_FAULT_ENCODE_TOO_BIG:
10038334SJose.Borrego@Sun.COM fault_status = NDR_FAULT_NCA_OUT_ARGS_TOO_BIG;
10045772Sas200622 break;
10055772Sas200622
10068334SJose.Borrego@Sun.COM case NDR_DRC_FAULT_REQUEST_PCONT_INVALID:
10078334SJose.Borrego@Sun.COM fault_status = NDR_FAULT_NCA_INVALID_PRES_CONTEXT_ID;
10085772Sas200622 break;
10095772Sas200622
10108334SJose.Borrego@Sun.COM case NDR_DRC_FAULT_REQUEST_OPNUM_INVALID:
10118334SJose.Borrego@Sun.COM fault_status = NDR_FAULT_NCA_OP_RNG_ERROR;
10125772Sas200622 break;
10135772Sas200622
10148334SJose.Borrego@Sun.COM case NDR_DRC_FAULT_DECODE_FAILED:
10158334SJose.Borrego@Sun.COM case NDR_DRC_FAULT_ENCODE_FAILED:
10168334SJose.Borrego@Sun.COM fault_status = NDR_FAULT_NCA_PROTO_ERROR;
10175772Sas200622 break;
10185772Sas200622
10195772Sas200622 default:
10208334SJose.Borrego@Sun.COM fault_status = NDR_FAULT_NCA_UNSPEC_REJECT;
10215772Sas200622 break;
10225772Sas200622 }
10235772Sas200622
10248334SJose.Borrego@Sun.COM mxa->send_hdr.fault_hdr.common_hdr.ptype = NDR_PTYPE_FAULT;
10255772Sas200622 mxa->send_hdr.fault_hdr.status = fault_status;
10265772Sas200622 mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length;
10275772Sas200622 }
10285772Sas200622
10297619SJose.Borrego@Sun.COM /*
10307619SJose.Borrego@Sun.COM * Note that the frag_length for bind ack and alter context is
10317619SJose.Borrego@Sun.COM * non-standard.
10327619SJose.Borrego@Sun.COM */
10335772Sas200622 static int
ndr_build_reply(ndr_xa_t * mxa)10348334SJose.Borrego@Sun.COM ndr_build_reply(ndr_xa_t *mxa)
10355772Sas200622 {
10367619SJose.Borrego@Sun.COM ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
10378334SJose.Borrego@Sun.COM ndr_stream_t *nds = &mxa->send_nds;
10386482Samw uint8_t *pdu_buf;
10395772Sas200622 unsigned long pdu_size;
10405772Sas200622 unsigned long frag_size;
10415772Sas200622 unsigned long pdu_data_size;
10425772Sas200622 unsigned long frag_data_size;
10435772Sas200622
10448334SJose.Borrego@Sun.COM frag_size = NDR_FRAG_SZ;
10458334SJose.Borrego@Sun.COM pdu_size = nds->pdu_size;
10468334SJose.Borrego@Sun.COM pdu_buf = nds->pdu_base_addr;
10475772Sas200622
10485772Sas200622 if (pdu_size <= frag_size) {
10495772Sas200622 /*
10505772Sas200622 * Single fragment response. The PDU size may be zero
10515772Sas200622 * here (i.e. bind or fault response). So don't make
10525772Sas200622 * any assumptions about it until after the header is
10535772Sas200622 * encoded.
10545772Sas200622 */
10555772Sas200622 switch (hdr->ptype) {
10568334SJose.Borrego@Sun.COM case NDR_PTYPE_BIND_ACK:
10578334SJose.Borrego@Sun.COM hdr->frag_length = ndr_bind_ack_hdr_size(mxa);
10585772Sas200622 break;
10595772Sas200622
10608334SJose.Borrego@Sun.COM case NDR_PTYPE_FAULT:
10615772Sas200622 /* already setup */
10625772Sas200622 break;
10635772Sas200622
10648334SJose.Borrego@Sun.COM case NDR_PTYPE_RESPONSE:
10655772Sas200622 hdr->frag_length = pdu_size;
10665772Sas200622 mxa->send_hdr.response_hdr.alloc_hint =
10675772Sas200622 hdr->frag_length;
10685772Sas200622 break;
10695772Sas200622
10708334SJose.Borrego@Sun.COM case NDR_PTYPE_ALTER_CONTEXT_RESP:
10718334SJose.Borrego@Sun.COM hdr->frag_length = ndr_alter_context_rsp_hdr_size();
10727619SJose.Borrego@Sun.COM break;
10737619SJose.Borrego@Sun.COM
10745772Sas200622 default:
10755772Sas200622 hdr->frag_length = pdu_size;
10765772Sas200622 break;
10775772Sas200622 }
10785772Sas200622
10798334SJose.Borrego@Sun.COM nds->pdu_scan_offset = 0;
10808334SJose.Borrego@Sun.COM (void) ndr_encode_pdu_hdr(mxa);
10818334SJose.Borrego@Sun.COM pdu_size = nds->pdu_size;
10828334SJose.Borrego@Sun.COM ndr_build_frag(nds, pdu_buf, pdu_size);
10835772Sas200622 return (0);
10845772Sas200622 }
10855772Sas200622
10865772Sas200622 /*
10875772Sas200622 * Multiple fragment response.
10885772Sas200622 */
10898334SJose.Borrego@Sun.COM hdr->pfc_flags = NDR_PFC_FIRST_FRAG;
10905772Sas200622 hdr->frag_length = frag_size;
10918334SJose.Borrego@Sun.COM mxa->send_hdr.response_hdr.alloc_hint = pdu_size - NDR_RSP_HDR_SIZE;
10928334SJose.Borrego@Sun.COM nds->pdu_scan_offset = 0;
10938334SJose.Borrego@Sun.COM (void) ndr_encode_pdu_hdr(mxa);
10948334SJose.Borrego@Sun.COM ndr_build_frag(nds, pdu_buf, frag_size);
10955772Sas200622
10965772Sas200622 /*
10975772Sas200622 * We need to update the 24-byte header in subsequent fragments.
10985772Sas200622 *
10996482Samw * pdu_data_size: total data remaining to be handled
11006482Samw * frag_size: total fragment size including header
11016482Samw * frag_data_size: data in fragment
11028334SJose.Borrego@Sun.COM * (i.e. frag_size - NDR_RSP_HDR_SIZE)
11035772Sas200622 */
11048334SJose.Borrego@Sun.COM pdu_data_size = pdu_size - NDR_RSP_HDR_SIZE;
11058334SJose.Borrego@Sun.COM frag_data_size = frag_size - NDR_RSP_HDR_SIZE;
11065772Sas200622
11076482Samw while (pdu_data_size) {
11086482Samw mxa->send_hdr.response_hdr.alloc_hint -= frag_data_size;
11096482Samw pdu_data_size -= frag_data_size;
11106482Samw pdu_buf += frag_data_size;
11115772Sas200622
11126482Samw if (pdu_data_size <= frag_data_size) {
11136482Samw frag_data_size = pdu_data_size;
11148334SJose.Borrego@Sun.COM frag_size = frag_data_size + NDR_RSP_HDR_SIZE;
11158334SJose.Borrego@Sun.COM hdr->pfc_flags = NDR_PFC_LAST_FRAG;
11165772Sas200622 } else {
11176482Samw hdr->pfc_flags = 0;
11185772Sas200622 }
11195772Sas200622
11206482Samw hdr->frag_length = frag_size;
11218334SJose.Borrego@Sun.COM nds->pdu_scan_offset = 0;
11228334SJose.Borrego@Sun.COM (void) ndr_encode_pdu_hdr(mxa);
11238334SJose.Borrego@Sun.COM bcopy(nds->pdu_base_addr, pdu_buf, NDR_RSP_HDR_SIZE);
11245772Sas200622
11258334SJose.Borrego@Sun.COM ndr_build_frag(nds, pdu_buf, frag_size);
11265772Sas200622
11278334SJose.Borrego@Sun.COM if (hdr->pfc_flags & NDR_PFC_LAST_FRAG)
11286482Samw break;
11295772Sas200622 }
11305772Sas200622
11315772Sas200622 return (0);
11325772Sas200622 }
11336482Samw
11346482Samw /*
11358334SJose.Borrego@Sun.COM * ndr_build_frag
11366482Samw *
11376482Samw * Build an RPC PDU fragment from the specified buffer.
11386482Samw * If malloc fails, the client will see a header/pdu inconsistency
11396482Samw * and report an error.
11406482Samw */
11416482Samw static void
ndr_build_frag(ndr_stream_t * nds,uint8_t * buf,uint32_t len)11428334SJose.Borrego@Sun.COM ndr_build_frag(ndr_stream_t *nds, uint8_t *buf, uint32_t len)
11436482Samw {
11446482Samw ndr_frag_t *frag;
11456482Samw int size = sizeof (ndr_frag_t) + len;
11466482Samw
11476482Samw if ((frag = (ndr_frag_t *)malloc(size)) == NULL)
11486482Samw return;
11496482Samw
11506482Samw frag->next = NULL;
11516482Samw frag->buf = (uint8_t *)frag + sizeof (ndr_frag_t);
11526482Samw frag->len = len;
11536482Samw bcopy(buf, frag->buf, len);
11546482Samw
11558334SJose.Borrego@Sun.COM if (nds->frags.head == NULL) {
11568334SJose.Borrego@Sun.COM nds->frags.head = frag;
11578334SJose.Borrego@Sun.COM nds->frags.tail = frag;
11588334SJose.Borrego@Sun.COM nds->frags.nfrag = 1;
11596482Samw } else {
11608334SJose.Borrego@Sun.COM nds->frags.tail->next = frag;
11618334SJose.Borrego@Sun.COM nds->frags.tail = frag;
11628334SJose.Borrego@Sun.COM ++nds->frags.nfrag;
11636482Samw }
11646482Samw }
1165