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*11963SAfshin.Ardakani@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 235772Sas200622 * Use is subject to license terms. 245772Sas200622 */ 255772Sas200622 265772Sas200622 /* 275772Sas200622 * Server side RPC handler. 285772Sas200622 */ 295772Sas200622 305772Sas200622 #include <sys/byteorder.h> 317052Samw #include <sys/errno.h> 327052Samw #include <sys/uio.h> 335772Sas200622 #include <thread.h> 345772Sas200622 #include <synch.h> 355772Sas200622 #include <stdlib.h> 365772Sas200622 #include <strings.h> 375772Sas200622 #include <string.h> 385772Sas200622 #include <time.h> 395772Sas200622 405772Sas200622 #include <smbsrv/libsmb.h> 415772Sas200622 #include <smbsrv/libmlrpc.h> 428474SJose.Borrego@Sun.COM #include <smbsrv/ntaccess.h> 435772Sas200622 445772Sas200622 /* 455772Sas200622 * Fragment size (5680: NT style). 465772Sas200622 */ 478334SJose.Borrego@Sun.COM #define NDR_FRAG_SZ 5680 485772Sas200622 49*11963SAfshin.Ardakani@Sun.COM #define NDR_GROW_SIZE (8 * 1024) 50*11963SAfshin.Ardakani@Sun.COM #define NDR_GROW_MASK (NDR_GROW_SIZE - 1) 51*11963SAfshin.Ardakani@Sun.COM #define NDR_ALIGN_BUF(S) (((S) + NDR_GROW_SIZE) & ~NDR_GROW_MASK) 52*11963SAfshin.Ardakani@Sun.COM 53*11963SAfshin.Ardakani@Sun.COM #define NDR_PIPE_BUFSZ (64 * 1024) 54*11963SAfshin.Ardakani@Sun.COM #define NDR_PIPE_BUFMAX (64 * 1024 * 1024) 558334SJose.Borrego@Sun.COM #define NDR_PIPE_MAX 128 56*11963SAfshin.Ardakani@Sun.COM 578334SJose.Borrego@Sun.COM static ndr_pipe_t ndr_pipe_table[NDR_PIPE_MAX]; 588334SJose.Borrego@Sun.COM static mutex_t ndr_pipe_lock; 595772Sas200622 60*11963SAfshin.Ardakani@Sun.COM static int ndr_pipe_process(ndr_pipe_t *); 618334SJose.Borrego@Sun.COM static ndr_pipe_t *ndr_pipe_lookup(int); 628334SJose.Borrego@Sun.COM static void ndr_pipe_release(ndr_pipe_t *); 638334SJose.Borrego@Sun.COM static ndr_pipe_t *ndr_pipe_allocate(int); 64*11963SAfshin.Ardakani@Sun.COM static int ndr_pipe_grow(ndr_pipe_t *, size_t); 658334SJose.Borrego@Sun.COM static void ndr_pipe_deallocate(ndr_pipe_t *); 668334SJose.Borrego@Sun.COM static void ndr_pipe_rewind(ndr_pipe_t *); 678334SJose.Borrego@Sun.COM static void ndr_pipe_flush(ndr_pipe_t *); 687052Samw 698334SJose.Borrego@Sun.COM static int ndr_svc_process(ndr_xa_t *); 70*11963SAfshin.Ardakani@Sun.COM static int ndr_svc_defrag(ndr_xa_t *); 718334SJose.Borrego@Sun.COM static int ndr_svc_bind(ndr_xa_t *); 728334SJose.Borrego@Sun.COM static int ndr_svc_request(ndr_xa_t *); 738334SJose.Borrego@Sun.COM static void ndr_reply_prepare_hdr(ndr_xa_t *); 748334SJose.Borrego@Sun.COM static int ndr_svc_alter_context(ndr_xa_t *); 758334SJose.Borrego@Sun.COM static void ndr_reply_fault(ndr_xa_t *, unsigned long); 768334SJose.Borrego@Sun.COM static int ndr_build_reply(ndr_xa_t *); 778334SJose.Borrego@Sun.COM static void ndr_build_frag(ndr_stream_t *, uint8_t *, uint32_t); 785772Sas200622 795772Sas200622 /* 807052Samw * Allocate and associate a service context with a fid. 817052Samw */ 827052Samw int 838334SJose.Borrego@Sun.COM ndr_pipe_open(int fid, uint8_t *data, uint32_t datalen) 847052Samw { 858334SJose.Borrego@Sun.COM ndr_pipe_t *np; 867052Samw 878334SJose.Borrego@Sun.COM (void) mutex_lock(&ndr_pipe_lock); 887052Samw 898334SJose.Borrego@Sun.COM if ((np = ndr_pipe_lookup(fid)) != NULL) { 908334SJose.Borrego@Sun.COM ndr_pipe_release(np); 918334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 927052Samw return (EEXIST); 937052Samw } 947052Samw 958334SJose.Borrego@Sun.COM if ((np = ndr_pipe_allocate(fid)) == NULL) { 968334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 977052Samw return (ENOMEM); 987052Samw } 997052Samw 10010122SJordan.Brown@Sun.COM if (smb_netuserinfo_decode(&np->np_user, data, datalen, NULL) == -1) { 1018334SJose.Borrego@Sun.COM ndr_pipe_release(np); 1028334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 1037052Samw return (EINVAL); 1047052Samw } 1057052Samw 1068334SJose.Borrego@Sun.COM ndr_svc_binding_pool_init(&np->np_binding, np->np_binding_pool, 1078334SJose.Borrego@Sun.COM NDR_N_BINDING_POOL); 1087052Samw 1098334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 1107052Samw return (0); 1117052Samw } 1127052Samw 1137052Samw /* 1147052Samw * Release the context associated with a fid when an opipe is closed. 1157052Samw */ 1167052Samw int 1178334SJose.Borrego@Sun.COM ndr_pipe_close(int fid) 1187052Samw { 1198334SJose.Borrego@Sun.COM ndr_pipe_t *np; 1207052Samw 1218334SJose.Borrego@Sun.COM (void) mutex_lock(&ndr_pipe_lock); 1227052Samw 1238334SJose.Borrego@Sun.COM if ((np = ndr_pipe_lookup(fid)) == NULL) { 1248334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 1257052Samw return (ENOENT); 1267052Samw } 1277052Samw 1287052Samw /* 1297052Samw * Release twice: once for the lookup above 1307052Samw * and again to close the fid. 1317052Samw */ 1328334SJose.Borrego@Sun.COM ndr_pipe_release(np); 1338334SJose.Borrego@Sun.COM ndr_pipe_release(np); 1348334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 1357052Samw return (0); 1367052Samw } 1377052Samw 1387052Samw /* 1397052Samw * Write RPC request data to the input stream. Input data is buffered 1407052Samw * until the response is requested. 1415772Sas200622 */ 1427052Samw int 1438334SJose.Borrego@Sun.COM ndr_pipe_write(int fid, uint8_t *buf, uint32_t len) 1447052Samw { 145*11963SAfshin.Ardakani@Sun.COM ndr_pipe_t *np; 146*11963SAfshin.Ardakani@Sun.COM ssize_t nbytes; 147*11963SAfshin.Ardakani@Sun.COM int rc; 1487052Samw 1497052Samw if (len == 0) 1507052Samw return (0); 1517052Samw 1528334SJose.Borrego@Sun.COM (void) mutex_lock(&ndr_pipe_lock); 1537052Samw 1548334SJose.Borrego@Sun.COM if ((np = ndr_pipe_lookup(fid)) == NULL) { 1558334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 1567052Samw return (ENOENT); 1577052Samw } 1587052Samw 159*11963SAfshin.Ardakani@Sun.COM if ((rc = ndr_pipe_grow(np, len)) != 0) { 160*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 161*11963SAfshin.Ardakani@Sun.COM return (rc); 162*11963SAfshin.Ardakani@Sun.COM } 163*11963SAfshin.Ardakani@Sun.COM 1648334SJose.Borrego@Sun.COM nbytes = ndr_uiomove((caddr_t)buf, len, UIO_READ, &np->np_uio); 1657052Samw 1668334SJose.Borrego@Sun.COM ndr_pipe_release(np); 1678334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 1687052Samw return ((nbytes == len) ? 0 : EIO); 1697052Samw } 1707052Samw 1717052Samw /* 172*11963SAfshin.Ardakani@Sun.COM * Read RPC response data. 1737052Samw */ 1747052Samw int 1758334SJose.Borrego@Sun.COM ndr_pipe_read(int fid, uint8_t *buf, uint32_t *len, uint32_t *resid) 1765772Sas200622 { 1778334SJose.Borrego@Sun.COM ndr_pipe_t *np; 1787052Samw ssize_t nbytes = *len; 1797052Samw 1807052Samw if (nbytes == 0) { 1817052Samw *resid = 0; 1827052Samw return (0); 1837052Samw } 1847052Samw 1858334SJose.Borrego@Sun.COM (void) mutex_lock(&ndr_pipe_lock); 1868334SJose.Borrego@Sun.COM if ((np = ndr_pipe_lookup(fid)) == NULL) { 1878334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 1887052Samw return (ENOENT); 1897052Samw } 1908334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 1917052Samw 1928334SJose.Borrego@Sun.COM *len = ndr_uiomove((caddr_t)buf, nbytes, UIO_WRITE, &np->np_frags.uio); 1938334SJose.Borrego@Sun.COM *resid = np->np_frags.uio.uio_resid; 1947052Samw 1957052Samw if (*resid == 0) { 1967052Samw /* 1977052Samw * Nothing left, cleanup the output stream. 1987052Samw */ 1998334SJose.Borrego@Sun.COM ndr_pipe_flush(np); 2007052Samw } 2017052Samw 2028334SJose.Borrego@Sun.COM (void) mutex_lock(&ndr_pipe_lock); 2038334SJose.Borrego@Sun.COM ndr_pipe_release(np); 2048334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 2057052Samw return (0); 2067052Samw } 2077052Samw 2087052Samw /* 209*11963SAfshin.Ardakani@Sun.COM * If the input stream contains an RPC request, process the RPC transaction, 210*11963SAfshin.Ardakani@Sun.COM * which will place the RPC response in the output (frags) stream. 211*11963SAfshin.Ardakani@Sun.COM * 212*11963SAfshin.Ardakani@Sun.COM * arg is freed here; it must have been allocated by malloc(). 213*11963SAfshin.Ardakani@Sun.COM */ 214*11963SAfshin.Ardakani@Sun.COM void * 215*11963SAfshin.Ardakani@Sun.COM ndr_pipe_transact(void *arg) 216*11963SAfshin.Ardakani@Sun.COM { 217*11963SAfshin.Ardakani@Sun.COM uint32_t *tmp = (uint32_t *)arg; 218*11963SAfshin.Ardakani@Sun.COM uint32_t fid; 219*11963SAfshin.Ardakani@Sun.COM ndr_pipe_t *np; 220*11963SAfshin.Ardakani@Sun.COM 221*11963SAfshin.Ardakani@Sun.COM if (arg == NULL) 222*11963SAfshin.Ardakani@Sun.COM return (NULL); 223*11963SAfshin.Ardakani@Sun.COM 224*11963SAfshin.Ardakani@Sun.COM fid = *tmp; 225*11963SAfshin.Ardakani@Sun.COM 226*11963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&ndr_pipe_lock); 227*11963SAfshin.Ardakani@Sun.COM if ((np = ndr_pipe_lookup(fid)) == NULL) { 228*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 229*11963SAfshin.Ardakani@Sun.COM (void) smb_kmod_event_notify(fid); 230*11963SAfshin.Ardakani@Sun.COM free(arg); 231*11963SAfshin.Ardakani@Sun.COM return (NULL); 232*11963SAfshin.Ardakani@Sun.COM } 233*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 234*11963SAfshin.Ardakani@Sun.COM 235*11963SAfshin.Ardakani@Sun.COM if (ndr_pipe_process(np) != 0) 236*11963SAfshin.Ardakani@Sun.COM ndr_pipe_flush(np); 237*11963SAfshin.Ardakani@Sun.COM 238*11963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&ndr_pipe_lock); 239*11963SAfshin.Ardakani@Sun.COM ndr_pipe_release(np); 240*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 241*11963SAfshin.Ardakani@Sun.COM (void) smb_kmod_event_notify(fid); 242*11963SAfshin.Ardakani@Sun.COM free(arg); 243*11963SAfshin.Ardakani@Sun.COM return (NULL); 244*11963SAfshin.Ardakani@Sun.COM } 245*11963SAfshin.Ardakani@Sun.COM 246*11963SAfshin.Ardakani@Sun.COM /* 2477052Samw * Process a server-side RPC request. 2487052Samw */ 2497052Samw static int 250*11963SAfshin.Ardakani@Sun.COM ndr_pipe_process(ndr_pipe_t *np) 2517052Samw { 2528334SJose.Borrego@Sun.COM ndr_xa_t *mxa; 2538334SJose.Borrego@Sun.COM ndr_stream_t *recv_nds; 2548334SJose.Borrego@Sun.COM ndr_stream_t *send_nds; 2558334SJose.Borrego@Sun.COM char *data; 2568334SJose.Borrego@Sun.COM int datalen; 25711337SWilliam.Krier@Sun.COM int rc; 2585772Sas200622 2598334SJose.Borrego@Sun.COM data = np->np_buf; 2608334SJose.Borrego@Sun.COM datalen = np->np_uio.uio_offset; 2615772Sas200622 262*11963SAfshin.Ardakani@Sun.COM if (datalen == 0) 263*11963SAfshin.Ardakani@Sun.COM return (0); 264*11963SAfshin.Ardakani@Sun.COM 2657052Samw if ((mxa = (ndr_xa_t *)malloc(sizeof (ndr_xa_t))) == NULL) 2667052Samw return (ENOMEM); 2675772Sas200622 2688334SJose.Borrego@Sun.COM bzero(mxa, sizeof (ndr_xa_t)); 2698334SJose.Borrego@Sun.COM mxa->fid = np->np_fid; 2708334SJose.Borrego@Sun.COM mxa->pipe = np; 2718334SJose.Borrego@Sun.COM mxa->binding_list = np->np_binding; 2725772Sas200622 2738334SJose.Borrego@Sun.COM if ((mxa->heap = ndr_heap_create()) == NULL) { 2745772Sas200622 free(mxa); 2757052Samw return (ENOMEM); 2765772Sas200622 } 2775772Sas200622 2788334SJose.Borrego@Sun.COM recv_nds = &mxa->recv_nds; 27911337SWilliam.Krier@Sun.COM rc = nds_initialize(recv_nds, datalen, NDR_MODE_CALL_RECV, mxa->heap); 28011337SWilliam.Krier@Sun.COM if (rc != 0) { 28111337SWilliam.Krier@Sun.COM ndr_heap_destroy(mxa->heap); 28211337SWilliam.Krier@Sun.COM free(mxa); 28311337SWilliam.Krier@Sun.COM return (ENOMEM); 28411337SWilliam.Krier@Sun.COM } 2855772Sas200622 2867052Samw /* 2877052Samw * Copy the input data and reset the input stream. 2887052Samw */ 2898334SJose.Borrego@Sun.COM bcopy(data, recv_nds->pdu_base_addr, datalen); 2908334SJose.Borrego@Sun.COM ndr_pipe_rewind(np); 2915772Sas200622 2928334SJose.Borrego@Sun.COM send_nds = &mxa->send_nds; 29311337SWilliam.Krier@Sun.COM rc = nds_initialize(send_nds, 0, NDR_MODE_RETURN_SEND, mxa->heap); 29411337SWilliam.Krier@Sun.COM if (rc != 0) { 29511337SWilliam.Krier@Sun.COM nds_destruct(&mxa->recv_nds); 29611337SWilliam.Krier@Sun.COM ndr_heap_destroy(mxa->heap); 29711337SWilliam.Krier@Sun.COM free(mxa); 29811337SWilliam.Krier@Sun.COM return (ENOMEM); 29911337SWilliam.Krier@Sun.COM } 3005772Sas200622 3018334SJose.Borrego@Sun.COM (void) ndr_svc_process(mxa); 3025772Sas200622 3038334SJose.Borrego@Sun.COM nds_finalize(send_nds, &np->np_frags); 3048334SJose.Borrego@Sun.COM nds_destruct(&mxa->recv_nds); 3058334SJose.Borrego@Sun.COM nds_destruct(&mxa->send_nds); 3068334SJose.Borrego@Sun.COM ndr_heap_destroy(mxa->heap); 3075772Sas200622 free(mxa); 3087052Samw return (0); 3097052Samw } 3107052Samw 3117052Samw /* 3128334SJose.Borrego@Sun.COM * Must be called with ndr_pipe_lock held. 3137052Samw */ 3148334SJose.Borrego@Sun.COM static ndr_pipe_t * 3158334SJose.Borrego@Sun.COM ndr_pipe_lookup(int fid) 3167052Samw { 3178334SJose.Borrego@Sun.COM ndr_pipe_t *np; 3187052Samw int i; 3197052Samw 3208334SJose.Borrego@Sun.COM for (i = 0; i < NDR_PIPE_MAX; ++i) { 3218334SJose.Borrego@Sun.COM np = &ndr_pipe_table[i]; 3227052Samw 3238334SJose.Borrego@Sun.COM if (np->np_fid == fid) { 3248334SJose.Borrego@Sun.COM if (np->np_refcnt == 0) 3257052Samw return (NULL); 3267052Samw 3278334SJose.Borrego@Sun.COM np->np_refcnt++; 3288334SJose.Borrego@Sun.COM return (np); 3297052Samw } 3307052Samw } 3317052Samw 3327052Samw return (NULL); 3335772Sas200622 } 3345772Sas200622 3355772Sas200622 /* 3368334SJose.Borrego@Sun.COM * Must be called with ndr_pipe_lock held. 3375772Sas200622 */ 3387052Samw static void 3398334SJose.Borrego@Sun.COM ndr_pipe_release(ndr_pipe_t *np) 3405772Sas200622 { 3418334SJose.Borrego@Sun.COM np->np_refcnt--; 3428334SJose.Borrego@Sun.COM ndr_pipe_deallocate(np); 3437052Samw } 3447052Samw 3457052Samw /* 3468334SJose.Borrego@Sun.COM * Must be called with ndr_pipe_lock held. 3477052Samw */ 3488334SJose.Borrego@Sun.COM static ndr_pipe_t * 3498334SJose.Borrego@Sun.COM ndr_pipe_allocate(int fid) 3507052Samw { 3518334SJose.Borrego@Sun.COM ndr_pipe_t *np = NULL; 3525772Sas200622 int i; 3535772Sas200622 3548334SJose.Borrego@Sun.COM for (i = 0; i < NDR_PIPE_MAX; ++i) { 3558334SJose.Borrego@Sun.COM np = &ndr_pipe_table[i]; 3565772Sas200622 3578334SJose.Borrego@Sun.COM if (np->np_fid == 0) { 3588334SJose.Borrego@Sun.COM bzero(np, sizeof (ndr_pipe_t)); 3595772Sas200622 3608334SJose.Borrego@Sun.COM if ((np->np_buf = malloc(NDR_PIPE_BUFSZ)) == NULL) 3617052Samw return (NULL); 3625772Sas200622 3638334SJose.Borrego@Sun.COM ndr_pipe_rewind(np); 3648334SJose.Borrego@Sun.COM np->np_fid = fid; 3658334SJose.Borrego@Sun.COM np->np_refcnt = 1; 3668334SJose.Borrego@Sun.COM return (np); 3675772Sas200622 } 3685772Sas200622 } 3695772Sas200622 3707052Samw return (NULL); 3717052Samw } 3725772Sas200622 3737052Samw /* 374*11963SAfshin.Ardakani@Sun.COM * If the desired space exceeds the current pipe size, try to expand 375*11963SAfshin.Ardakani@Sun.COM * the pipe. Leave the current pipe intact if the realloc fails. 376*11963SAfshin.Ardakani@Sun.COM * 377*11963SAfshin.Ardakani@Sun.COM * Must be called with ndr_pipe_lock held. 378*11963SAfshin.Ardakani@Sun.COM */ 379*11963SAfshin.Ardakani@Sun.COM static int 380*11963SAfshin.Ardakani@Sun.COM ndr_pipe_grow(ndr_pipe_t *np, size_t desired) 381*11963SAfshin.Ardakani@Sun.COM { 382*11963SAfshin.Ardakani@Sun.COM char *newbuf; 383*11963SAfshin.Ardakani@Sun.COM size_t current; 384*11963SAfshin.Ardakani@Sun.COM size_t required; 385*11963SAfshin.Ardakani@Sun.COM 386*11963SAfshin.Ardakani@Sun.COM required = np->np_uio.uio_offset + desired; 387*11963SAfshin.Ardakani@Sun.COM current = np->np_uio.uio_offset + np->np_uio.uio_resid; 388*11963SAfshin.Ardakani@Sun.COM 389*11963SAfshin.Ardakani@Sun.COM if (required <= current) 390*11963SAfshin.Ardakani@Sun.COM return (0); 391*11963SAfshin.Ardakani@Sun.COM 392*11963SAfshin.Ardakani@Sun.COM if (required > NDR_PIPE_BUFMAX) { 393*11963SAfshin.Ardakani@Sun.COM smb_tracef("ndr_pipe_grow: required=%d, max=%d (ENOSPC)", 394*11963SAfshin.Ardakani@Sun.COM required, NDR_PIPE_BUFMAX); 395*11963SAfshin.Ardakani@Sun.COM return (ENOSPC); 396*11963SAfshin.Ardakani@Sun.COM } 397*11963SAfshin.Ardakani@Sun.COM 398*11963SAfshin.Ardakani@Sun.COM required = NDR_ALIGN_BUF(required); 399*11963SAfshin.Ardakani@Sun.COM if (required > NDR_PIPE_BUFMAX) 400*11963SAfshin.Ardakani@Sun.COM required = NDR_PIPE_BUFMAX; 401*11963SAfshin.Ardakani@Sun.COM 402*11963SAfshin.Ardakani@Sun.COM if ((newbuf = realloc(np->np_buf, required)) == NULL) { 403*11963SAfshin.Ardakani@Sun.COM smb_tracef("ndr_pipe_grow: realloc failed (ENOMEM)"); 404*11963SAfshin.Ardakani@Sun.COM return (ENOMEM); 405*11963SAfshin.Ardakani@Sun.COM } 406*11963SAfshin.Ardakani@Sun.COM 407*11963SAfshin.Ardakani@Sun.COM np->np_buf = newbuf; 408*11963SAfshin.Ardakani@Sun.COM np->np_uio.uio_resid += desired; 409*11963SAfshin.Ardakani@Sun.COM np->np_iov.iov_len += desired; 410*11963SAfshin.Ardakani@Sun.COM smb_tracef("ndr_pipe_grow: %d bytes", required); 411*11963SAfshin.Ardakani@Sun.COM return (0); 412*11963SAfshin.Ardakani@Sun.COM } 413*11963SAfshin.Ardakani@Sun.COM 414*11963SAfshin.Ardakani@Sun.COM /* 4158334SJose.Borrego@Sun.COM * Must be called with ndr_pipe_lock held. 4167052Samw */ 4177052Samw static void 4188334SJose.Borrego@Sun.COM ndr_pipe_deallocate(ndr_pipe_t *np) 4197052Samw { 4208334SJose.Borrego@Sun.COM if (np->np_refcnt == 0) { 4217052Samw /* 4227052Samw * Ensure that there are no RPC service policy handles 4237052Samw * (associated with this fid) left around. 4247052Samw */ 4258334SJose.Borrego@Sun.COM ndr_hdclose(np->np_fid); 4265772Sas200622 4278334SJose.Borrego@Sun.COM ndr_pipe_rewind(np); 4288334SJose.Borrego@Sun.COM ndr_pipe_flush(np); 4298334SJose.Borrego@Sun.COM free(np->np_buf); 43010122SJordan.Brown@Sun.COM free(np->np_user.ui_domain); 43110122SJordan.Brown@Sun.COM free(np->np_user.ui_account); 43210122SJordan.Brown@Sun.COM free(np->np_user.ui_workstation); 4338334SJose.Borrego@Sun.COM bzero(np, sizeof (ndr_pipe_t)); 4347052Samw } 4357052Samw } 4365772Sas200622 4377052Samw /* 4387052Samw * Rewind the input data stream, ready for the next write. 4397052Samw */ 4407052Samw static void 4418334SJose.Borrego@Sun.COM ndr_pipe_rewind(ndr_pipe_t *np) 4427052Samw { 4438334SJose.Borrego@Sun.COM np->np_uio.uio_iov = &np->np_iov; 4448334SJose.Borrego@Sun.COM np->np_uio.uio_iovcnt = 1; 4458334SJose.Borrego@Sun.COM np->np_uio.uio_offset = 0; 4468334SJose.Borrego@Sun.COM np->np_uio.uio_segflg = UIO_USERSPACE; 4478334SJose.Borrego@Sun.COM np->np_uio.uio_resid = NDR_PIPE_BUFSZ; 4488334SJose.Borrego@Sun.COM np->np_iov.iov_base = np->np_buf; 4498334SJose.Borrego@Sun.COM np->np_iov.iov_len = NDR_PIPE_BUFSZ; 4505772Sas200622 } 4515772Sas200622 4525772Sas200622 /* 4537052Samw * Flush the output data stream. 4545772Sas200622 */ 4557052Samw static void 4568334SJose.Borrego@Sun.COM ndr_pipe_flush(ndr_pipe_t *np) 4575772Sas200622 { 4587052Samw ndr_frag_t *frag; 4595772Sas200622 4608334SJose.Borrego@Sun.COM while ((frag = np->np_frags.head) != NULL) { 4618334SJose.Borrego@Sun.COM np->np_frags.head = frag->next; 4627052Samw free(frag); 4635772Sas200622 } 4645772Sas200622 4658334SJose.Borrego@Sun.COM free(np->np_frags.iov); 4668334SJose.Borrego@Sun.COM bzero(&np->np_frags, sizeof (ndr_fraglist_t)); 4677052Samw } 4687052Samw 4697052Samw /* 4707052Samw * Check whether or not the specified user has administrator privileges, 4717052Samw * i.e. is a member of Domain Admins or Administrators. 4727052Samw * Returns true if the user is an administrator, otherwise returns false. 4737052Samw */ 4747052Samw boolean_t 4757052Samw ndr_is_admin(ndr_xa_t *xa) 4767052Samw { 47710122SJordan.Brown@Sun.COM smb_netuserinfo_t *ctx = &xa->pipe->np_user; 4787052Samw 47910122SJordan.Brown@Sun.COM return (ctx->ui_flags & SMB_ATF_ADMIN); 4807052Samw } 4817052Samw 4827052Samw /* 4837052Samw * Check whether or not the specified user has power-user privileges, 4847052Samw * i.e. is a member of Domain Admins, Administrators or Power Users. 4857052Samw * This is typically required for operations such as managing shares. 4867052Samw * Returns true if the user is a power user, otherwise returns false. 4877052Samw */ 4887052Samw boolean_t 4897052Samw ndr_is_poweruser(ndr_xa_t *xa) 4907052Samw { 49110122SJordan.Brown@Sun.COM smb_netuserinfo_t *ctx = &xa->pipe->np_user; 4927052Samw 49310122SJordan.Brown@Sun.COM return ((ctx->ui_flags & SMB_ATF_ADMIN) || 49410122SJordan.Brown@Sun.COM (ctx->ui_flags & SMB_ATF_POWERUSER)); 4957052Samw } 4967052Samw 4977052Samw int32_t 4987052Samw ndr_native_os(ndr_xa_t *xa) 4997052Samw { 50010122SJordan.Brown@Sun.COM smb_netuserinfo_t *ctx = &xa->pipe->np_user; 5017052Samw 50210122SJordan.Brown@Sun.COM return (ctx->ui_native_os); 5035772Sas200622 } 5045772Sas200622 5055772Sas200622 /* 5065772Sas200622 * This is the entry point for all server-side RPC processing. 5075772Sas200622 * It is assumed that the PDU has already been received. 5085772Sas200622 */ 5095772Sas200622 static int 5108334SJose.Borrego@Sun.COM ndr_svc_process(ndr_xa_t *mxa) 5115772Sas200622 { 512*11963SAfshin.Ardakani@Sun.COM ndr_common_header_t *hdr = &mxa->recv_hdr.common_hdr; 513*11963SAfshin.Ardakani@Sun.COM ndr_stream_t *nds = &mxa->recv_nds; 514*11963SAfshin.Ardakani@Sun.COM unsigned long saved_offset; 515*11963SAfshin.Ardakani@Sun.COM unsigned long saved_size; 516*11963SAfshin.Ardakani@Sun.COM int rc; 5175772Sas200622 5188334SJose.Borrego@Sun.COM rc = ndr_decode_pdu_hdr(mxa); 5198334SJose.Borrego@Sun.COM if (!NDR_DRC_IS_OK(rc)) 5205772Sas200622 return (-1); 5215772Sas200622 5228334SJose.Borrego@Sun.COM (void) ndr_reply_prepare_hdr(mxa); 5235772Sas200622 5245772Sas200622 switch (mxa->ptype) { 5258334SJose.Borrego@Sun.COM case NDR_PTYPE_BIND: 5268334SJose.Borrego@Sun.COM rc = ndr_svc_bind(mxa); 5275772Sas200622 break; 5285772Sas200622 5298334SJose.Borrego@Sun.COM case NDR_PTYPE_REQUEST: 530*11963SAfshin.Ardakani@Sun.COM if (!NDR_IS_FIRST_FRAG(hdr->pfc_flags)) { 531*11963SAfshin.Ardakani@Sun.COM ndr_show_hdr(hdr); 532*11963SAfshin.Ardakani@Sun.COM rc = NDR_DRC_FAULT_DECODE_FAILED; 533*11963SAfshin.Ardakani@Sun.COM goto ndr_svc_process_fault; 534*11963SAfshin.Ardakani@Sun.COM } 535*11963SAfshin.Ardakani@Sun.COM 536*11963SAfshin.Ardakani@Sun.COM if (!NDR_IS_LAST_FRAG(hdr->pfc_flags)) { 537*11963SAfshin.Ardakani@Sun.COM /* 538*11963SAfshin.Ardakani@Sun.COM * Multi-fragment request. Preserve the PDU scan 539*11963SAfshin.Ardakani@Sun.COM * offset and size during defrag so that we can 540*11963SAfshin.Ardakani@Sun.COM * continue as if we had received contiguous data. 541*11963SAfshin.Ardakani@Sun.COM */ 542*11963SAfshin.Ardakani@Sun.COM saved_offset = nds->pdu_scan_offset; 543*11963SAfshin.Ardakani@Sun.COM saved_size = nds->pdu_size; 544*11963SAfshin.Ardakani@Sun.COM 545*11963SAfshin.Ardakani@Sun.COM nds->pdu_scan_offset = hdr->frag_length; 546*11963SAfshin.Ardakani@Sun.COM nds->pdu_size = nds->pdu_max_size; 547*11963SAfshin.Ardakani@Sun.COM 548*11963SAfshin.Ardakani@Sun.COM rc = ndr_svc_defrag(mxa); 549*11963SAfshin.Ardakani@Sun.COM if (NDR_DRC_IS_FAULT(rc)) { 550*11963SAfshin.Ardakani@Sun.COM ndr_show_hdr(hdr); 551*11963SAfshin.Ardakani@Sun.COM nds_show_state(nds); 552*11963SAfshin.Ardakani@Sun.COM goto ndr_svc_process_fault; 553*11963SAfshin.Ardakani@Sun.COM } 554*11963SAfshin.Ardakani@Sun.COM 555*11963SAfshin.Ardakani@Sun.COM nds->pdu_scan_offset = saved_offset; 556*11963SAfshin.Ardakani@Sun.COM nds->pdu_size = saved_size; 557*11963SAfshin.Ardakani@Sun.COM } 558*11963SAfshin.Ardakani@Sun.COM 5598334SJose.Borrego@Sun.COM rc = ndr_svc_request(mxa); 5605772Sas200622 break; 5615772Sas200622 5628334SJose.Borrego@Sun.COM case NDR_PTYPE_ALTER_CONTEXT: 5638334SJose.Borrego@Sun.COM rc = ndr_svc_alter_context(mxa); 5645772Sas200622 break; 5655772Sas200622 5665772Sas200622 default: 5678334SJose.Borrego@Sun.COM rc = NDR_DRC_FAULT_RPCHDR_PTYPE_INVALID; 5685772Sas200622 break; 5695772Sas200622 } 5705772Sas200622 571*11963SAfshin.Ardakani@Sun.COM ndr_svc_process_fault: 5728334SJose.Borrego@Sun.COM if (NDR_DRC_IS_FAULT(rc)) 5738334SJose.Borrego@Sun.COM ndr_reply_fault(mxa, rc); 5745772Sas200622 5758334SJose.Borrego@Sun.COM (void) ndr_build_reply(mxa); 5765772Sas200622 return (rc); 5775772Sas200622 } 5785772Sas200622 5795772Sas200622 /* 580*11963SAfshin.Ardakani@Sun.COM * Remove RPC fragment headers from the received data stream. 581*11963SAfshin.Ardakani@Sun.COM * The first fragment has already been accounted for before this call. 582*11963SAfshin.Ardakani@Sun.COM * 583*11963SAfshin.Ardakani@Sun.COM * NDR stream on entry: 584*11963SAfshin.Ardakani@Sun.COM * 585*11963SAfshin.Ardakani@Sun.COM * |<-- frag 2 -->|<-- frag 3 -->| ... |<- last frag ->| 586*11963SAfshin.Ardakani@Sun.COM * 587*11963SAfshin.Ardakani@Sun.COM * +-----+--------+-----+--------+-----+-----+---------+ 588*11963SAfshin.Ardakani@Sun.COM * | hdr | data | hdr | data | ... | hdr | data | 589*11963SAfshin.Ardakani@Sun.COM * +-----+--------+-----+--------+-----+-----+---------+ 590*11963SAfshin.Ardakani@Sun.COM * 591*11963SAfshin.Ardakani@Sun.COM * NDR stream on return: 592*11963SAfshin.Ardakani@Sun.COM * 593*11963SAfshin.Ardakani@Sun.COM * +----------------------------------+ 594*11963SAfshin.Ardakani@Sun.COM * | data | 595*11963SAfshin.Ardakani@Sun.COM * +----------------------------------+ 596*11963SAfshin.Ardakani@Sun.COM */ 597*11963SAfshin.Ardakani@Sun.COM static int 598*11963SAfshin.Ardakani@Sun.COM ndr_svc_defrag(ndr_xa_t *mxa) 599*11963SAfshin.Ardakani@Sun.COM { 600*11963SAfshin.Ardakani@Sun.COM ndr_stream_t *nds = &mxa->recv_nds; 601*11963SAfshin.Ardakani@Sun.COM ndr_common_header_t frag_hdr; 602*11963SAfshin.Ardakani@Sun.COM int frag_size; 603*11963SAfshin.Ardakani@Sun.COM int last_frag; 604*11963SAfshin.Ardakani@Sun.COM 605*11963SAfshin.Ardakani@Sun.COM do { 606*11963SAfshin.Ardakani@Sun.COM ndr_decode_frag_hdr(nds, &frag_hdr); 607*11963SAfshin.Ardakani@Sun.COM ndr_show_hdr(&frag_hdr); 608*11963SAfshin.Ardakani@Sun.COM 609*11963SAfshin.Ardakani@Sun.COM if (NDR_IS_FIRST_FRAG(frag_hdr.pfc_flags)) 610*11963SAfshin.Ardakani@Sun.COM return (NDR_DRC_FAULT_DECODE_FAILED); 611*11963SAfshin.Ardakani@Sun.COM 612*11963SAfshin.Ardakani@Sun.COM last_frag = NDR_IS_LAST_FRAG(frag_hdr.pfc_flags); 613*11963SAfshin.Ardakani@Sun.COM frag_size = frag_hdr.frag_length; 614*11963SAfshin.Ardakani@Sun.COM 615*11963SAfshin.Ardakani@Sun.COM if (frag_size > (nds->pdu_size - nds->pdu_scan_offset)) 616*11963SAfshin.Ardakani@Sun.COM return (NDR_DRC_FAULT_DECODE_FAILED); 617*11963SAfshin.Ardakani@Sun.COM 618*11963SAfshin.Ardakani@Sun.COM ndr_remove_frag_hdr(nds); 619*11963SAfshin.Ardakani@Sun.COM nds->pdu_scan_offset += frag_size - NDR_RSP_HDR_SIZE; 620*11963SAfshin.Ardakani@Sun.COM } while (!last_frag); 621*11963SAfshin.Ardakani@Sun.COM 622*11963SAfshin.Ardakani@Sun.COM return (NDR_DRC_OK); 623*11963SAfshin.Ardakani@Sun.COM } 624*11963SAfshin.Ardakani@Sun.COM 625*11963SAfshin.Ardakani@Sun.COM /* 6265772Sas200622 * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple 6275772Sas200622 * p_results[] not supported. 6285772Sas200622 */ 6295772Sas200622 static int 6308334SJose.Borrego@Sun.COM ndr_svc_bind(ndr_xa_t *mxa) 6315772Sas200622 { 6328334SJose.Borrego@Sun.COM ndr_p_cont_list_t *cont_list; 6338334SJose.Borrego@Sun.COM ndr_p_result_list_t *result_list; 6348334SJose.Borrego@Sun.COM ndr_p_result_t *result; 6355772Sas200622 unsigned p_cont_id; 6368334SJose.Borrego@Sun.COM ndr_binding_t *mbind; 6375772Sas200622 ndr_uuid_t *as_uuid; 6385772Sas200622 ndr_uuid_t *ts_uuid; 6395772Sas200622 int as_vers; 6405772Sas200622 int ts_vers; 6418334SJose.Borrego@Sun.COM ndr_service_t *msvc; 6425772Sas200622 int rc; 6438334SJose.Borrego@Sun.COM ndr_port_any_t *sec_addr; 6445772Sas200622 6455772Sas200622 /* acquire targets */ 6465772Sas200622 cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem; 6475772Sas200622 result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list; 6485772Sas200622 result = &result_list->p_results[0]; 6495772Sas200622 6505772Sas200622 /* 6515772Sas200622 * Set up temporary secondary address port. 6525772Sas200622 * We will correct this later (below). 6535772Sas200622 */ 6545772Sas200622 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 6555772Sas200622 sec_addr->length = 13; 6565772Sas200622 (void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs"); 6575772Sas200622 6585772Sas200622 result_list->n_results = 1; 6595772Sas200622 result_list->reserved = 0; 6605772Sas200622 result_list->reserved2 = 0; 6618334SJose.Borrego@Sun.COM result->result = NDR_PCDR_ACCEPTANCE; 6625772Sas200622 result->reason = 0; 6635772Sas200622 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax)); 6645772Sas200622 6655772Sas200622 /* sanity check */ 6665772Sas200622 if (cont_list->n_context_elem != 1 || 6675772Sas200622 cont_list->p_cont_elem[0].n_transfer_syn != 1) { 6688334SJose.Borrego@Sun.COM ndo_trace("ndr_svc_bind: warning: multiple p_cont_elem"); 6695772Sas200622 } 6705772Sas200622 6715772Sas200622 p_cont_id = cont_list->p_cont_elem[0].p_cont_id; 6725772Sas200622 6738334SJose.Borrego@Sun.COM if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) != NULL) { 6745772Sas200622 /* 6758334SJose.Borrego@Sun.COM * Duplicate presentation context id. 6765772Sas200622 */ 6778334SJose.Borrego@Sun.COM ndo_trace("ndr_svc_bind: duplicate binding"); 6788334SJose.Borrego@Sun.COM return (NDR_DRC_FAULT_BIND_PCONT_BUSY); 6795772Sas200622 } 6805772Sas200622 6818334SJose.Borrego@Sun.COM if ((mbind = ndr_svc_new_binding(mxa)) == NULL) { 6825772Sas200622 /* 6835772Sas200622 * No free binding slot 6845772Sas200622 */ 6858334SJose.Borrego@Sun.COM result->result = NDR_PCDR_PROVIDER_REJECTION; 6868334SJose.Borrego@Sun.COM result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED; 6878334SJose.Borrego@Sun.COM ndo_trace("ndr_svc_bind: no resources"); 6888334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 6895772Sas200622 } 6905772Sas200622 6915772Sas200622 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid; 6925772Sas200622 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version; 6935772Sas200622 6945772Sas200622 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid; 6955772Sas200622 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version; 6965772Sas200622 6978334SJose.Borrego@Sun.COM msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers); 6988334SJose.Borrego@Sun.COM if (msvc == NULL) { 6998334SJose.Borrego@Sun.COM result->result = NDR_PCDR_PROVIDER_REJECTION; 7008334SJose.Borrego@Sun.COM result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 7018334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 7025772Sas200622 } 7035772Sas200622 7045772Sas200622 /* 7055772Sas200622 * We can now use the correct secondary address port. 7065772Sas200622 */ 7075772Sas200622 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 7085772Sas200622 sec_addr->length = strlen(msvc->sec_addr_port) + 1; 7095772Sas200622 (void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port, 7108334SJose.Borrego@Sun.COM NDR_PORT_ANY_MAX_PORT_SPEC); 7115772Sas200622 7125772Sas200622 mbind->p_cont_id = p_cont_id; 7138334SJose.Borrego@Sun.COM mbind->which_side = NDR_BIND_SIDE_SERVER; 7145772Sas200622 /* mbind->context set by app */ 7155772Sas200622 mbind->service = msvc; 7165772Sas200622 mbind->instance_specific = 0; 7175772Sas200622 7185772Sas200622 mxa->binding = mbind; 7195772Sas200622 7205772Sas200622 if (msvc->bind_req) { 7215772Sas200622 /* 7225772Sas200622 * Call the service-specific bind() handler. If 7235772Sas200622 * this fails, we shouild send a specific error 7245772Sas200622 * on the bind ack. 7255772Sas200622 */ 7265772Sas200622 rc = (msvc->bind_req)(mxa); 7278334SJose.Borrego@Sun.COM if (NDR_DRC_IS_FAULT(rc)) { 7285772Sas200622 mbind->service = 0; /* free binding slot */ 7295772Sas200622 mbind->which_side = 0; 7305772Sas200622 mbind->p_cont_id = 0; 7315772Sas200622 mbind->instance_specific = 0; 7325772Sas200622 return (rc); 7335772Sas200622 } 7345772Sas200622 } 7355772Sas200622 7365772Sas200622 result->transfer_syntax = 7375772Sas200622 cont_list->p_cont_elem[0].transfer_syntaxes[0]; 7385772Sas200622 7398334SJose.Borrego@Sun.COM return (NDR_DRC_BINDING_MADE); 7405772Sas200622 } 7415772Sas200622 7425772Sas200622 /* 7438334SJose.Borrego@Sun.COM * ndr_svc_alter_context 7445772Sas200622 * 7455772Sas200622 * The alter context request is used to request additional presentation 7467619SJose.Borrego@Sun.COM * context for another interface and/or version. It is very similar to 7477619SJose.Borrego@Sun.COM * a bind request. 7485772Sas200622 */ 7495772Sas200622 static int 7508334SJose.Borrego@Sun.COM ndr_svc_alter_context(ndr_xa_t *mxa) 7515772Sas200622 { 7528334SJose.Borrego@Sun.COM ndr_p_result_list_t *result_list; 7538334SJose.Borrego@Sun.COM ndr_p_result_t *result; 7548334SJose.Borrego@Sun.COM ndr_p_cont_list_t *cont_list; 7558334SJose.Borrego@Sun.COM ndr_binding_t *mbind; 7568334SJose.Borrego@Sun.COM ndr_service_t *msvc; 7575772Sas200622 unsigned p_cont_id; 7585772Sas200622 ndr_uuid_t *as_uuid; 7595772Sas200622 ndr_uuid_t *ts_uuid; 7605772Sas200622 int as_vers; 7615772Sas200622 int ts_vers; 7628334SJose.Borrego@Sun.COM ndr_port_any_t *sec_addr; 7635772Sas200622 7647619SJose.Borrego@Sun.COM result_list = &mxa->send_hdr.alter_context_rsp_hdr.p_result_list; 7655772Sas200622 result_list->n_results = 1; 7665772Sas200622 result_list->reserved = 0; 7675772Sas200622 result_list->reserved2 = 0; 7685772Sas200622 7695772Sas200622 result = &result_list->p_results[0]; 7708334SJose.Borrego@Sun.COM result->result = NDR_PCDR_ACCEPTANCE; 7715772Sas200622 result->reason = 0; 7725772Sas200622 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax)); 7735772Sas200622 7747619SJose.Borrego@Sun.COM cont_list = &mxa->recv_hdr.alter_context_hdr.p_context_elem; 7755772Sas200622 p_cont_id = cont_list->p_cont_elem[0].p_cont_id; 7765772Sas200622 7778334SJose.Borrego@Sun.COM if (ndr_svc_find_binding(mxa, p_cont_id) != NULL) 7788334SJose.Borrego@Sun.COM return (NDR_DRC_FAULT_BIND_PCONT_BUSY); 7795772Sas200622 7808334SJose.Borrego@Sun.COM if ((mbind = ndr_svc_new_binding(mxa)) == NULL) { 7818334SJose.Borrego@Sun.COM result->result = NDR_PCDR_PROVIDER_REJECTION; 7828334SJose.Borrego@Sun.COM result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED; 7838334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 7845772Sas200622 } 7855772Sas200622 7865772Sas200622 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid; 7875772Sas200622 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version; 7885772Sas200622 7895772Sas200622 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid; 7905772Sas200622 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version; 7915772Sas200622 7928334SJose.Borrego@Sun.COM msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers); 7938334SJose.Borrego@Sun.COM if (msvc == NULL) { 7948334SJose.Borrego@Sun.COM result->result = NDR_PCDR_PROVIDER_REJECTION; 7958334SJose.Borrego@Sun.COM result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 7968334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 7975772Sas200622 } 7985772Sas200622 7995772Sas200622 mbind->p_cont_id = p_cont_id; 8008334SJose.Borrego@Sun.COM mbind->which_side = NDR_BIND_SIDE_SERVER; 8015772Sas200622 /* mbind->context set by app */ 8025772Sas200622 mbind->service = msvc; 8035772Sas200622 mbind->instance_specific = 0; 8045772Sas200622 mxa->binding = mbind; 8055772Sas200622 8067619SJose.Borrego@Sun.COM sec_addr = &mxa->send_hdr.alter_context_rsp_hdr.sec_addr; 8075772Sas200622 sec_addr->length = 0; 8088334SJose.Borrego@Sun.COM bzero(sec_addr->port_spec, NDR_PORT_ANY_MAX_PORT_SPEC); 8095772Sas200622 8105772Sas200622 result->transfer_syntax = 8115772Sas200622 cont_list->p_cont_elem[0].transfer_syntaxes[0]; 8125772Sas200622 8138334SJose.Borrego@Sun.COM return (NDR_DRC_BINDING_MADE); 8145772Sas200622 } 8155772Sas200622 8165772Sas200622 static int 8178334SJose.Borrego@Sun.COM ndr_svc_request(ndr_xa_t *mxa) 8185772Sas200622 { 8198334SJose.Borrego@Sun.COM ndr_binding_t *mbind; 8208334SJose.Borrego@Sun.COM ndr_service_t *msvc; 8218334SJose.Borrego@Sun.COM unsigned p_cont_id; 8228334SJose.Borrego@Sun.COM int rc; 8235772Sas200622 8245772Sas200622 mxa->opnum = mxa->recv_hdr.request_hdr.opnum; 8255772Sas200622 p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id; 8265772Sas200622 8278334SJose.Borrego@Sun.COM if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) == NULL) 8288334SJose.Borrego@Sun.COM return (NDR_DRC_FAULT_REQUEST_PCONT_INVALID); 8295772Sas200622 8305772Sas200622 mxa->binding = mbind; 8315772Sas200622 msvc = mbind->service; 8325772Sas200622 8335772Sas200622 /* 8345772Sas200622 * Make room for the response hdr. 8355772Sas200622 */ 8368334SJose.Borrego@Sun.COM mxa->send_nds.pdu_scan_offset = NDR_RSP_HDR_SIZE; 8375772Sas200622 8385772Sas200622 if (msvc->call_stub) 8395772Sas200622 rc = (*msvc->call_stub)(mxa); 8405772Sas200622 else 8418334SJose.Borrego@Sun.COM rc = ndr_generic_call_stub(mxa); 8425772Sas200622 8438334SJose.Borrego@Sun.COM if (NDR_DRC_IS_FAULT(rc)) { 8448334SJose.Borrego@Sun.COM ndo_printf(0, 0, "%s[0x%02x]: 0x%04x", 8455772Sas200622 msvc->name, mxa->opnum, rc); 8465772Sas200622 } 8475772Sas200622 8485772Sas200622 return (rc); 8495772Sas200622 } 8505772Sas200622 8515772Sas200622 /* 8528334SJose.Borrego@Sun.COM * The transaction and the two nds streams use the same heap, which 8535772Sas200622 * should already exist at this point. The heap will also be available 8545772Sas200622 * to the stub. 8555772Sas200622 */ 8565772Sas200622 int 8578334SJose.Borrego@Sun.COM ndr_generic_call_stub(ndr_xa_t *mxa) 8585772Sas200622 { 8598334SJose.Borrego@Sun.COM ndr_binding_t *mbind = mxa->binding; 8608334SJose.Borrego@Sun.COM ndr_service_t *msvc = mbind->service; 8618334SJose.Borrego@Sun.COM ndr_typeinfo_t *intf_ti = msvc->interface_ti; 8628334SJose.Borrego@Sun.COM ndr_stub_table_t *ste; 8635772Sas200622 int opnum = mxa->opnum; 8645772Sas200622 unsigned p_len = intf_ti->c_size_fixed_part; 8655772Sas200622 char *param; 8665772Sas200622 int rc; 8675772Sas200622 8685772Sas200622 if (mxa->heap == NULL) { 8698334SJose.Borrego@Sun.COM ndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum); 8708334SJose.Borrego@Sun.COM return (NDR_DRC_FAULT_OUT_OF_MEMORY); 8715772Sas200622 } 8725772Sas200622 8738334SJose.Borrego@Sun.COM if ((ste = ndr_svc_find_stub(msvc, opnum)) == NULL) { 8748334SJose.Borrego@Sun.COM ndo_printf(0, 0, "%s[0x%02x]: invalid opnum", 8755772Sas200622 msvc->name, opnum); 8768334SJose.Borrego@Sun.COM return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID); 8775772Sas200622 } 8785772Sas200622 8798334SJose.Borrego@Sun.COM if ((param = ndr_heap_malloc(mxa->heap, p_len)) == NULL) 8808334SJose.Borrego@Sun.COM return (NDR_DRC_FAULT_OUT_OF_MEMORY); 8815772Sas200622 8825772Sas200622 bzero(param, p_len); 8835772Sas200622 8848334SJose.Borrego@Sun.COM rc = ndr_decode_call(mxa, param); 8858334SJose.Borrego@Sun.COM if (!NDR_DRC_IS_OK(rc)) 8865772Sas200622 return (rc); 8875772Sas200622 8885772Sas200622 rc = (*ste->func)(param, mxa); 8898334SJose.Borrego@Sun.COM if (rc == NDR_DRC_OK) 8908334SJose.Borrego@Sun.COM rc = ndr_encode_return(mxa, param); 8915772Sas200622 8925772Sas200622 return (rc); 8935772Sas200622 } 8945772Sas200622 8955772Sas200622 /* 8965772Sas200622 * We can perform some initial setup of the response header here. 8975772Sas200622 * We also need to cache some of the information from the bind 8985772Sas200622 * negotiation for use during subsequent RPC calls. 8995772Sas200622 */ 9005772Sas200622 static void 9018334SJose.Borrego@Sun.COM ndr_reply_prepare_hdr(ndr_xa_t *mxa) 9025772Sas200622 { 9037619SJose.Borrego@Sun.COM ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr; 9047619SJose.Borrego@Sun.COM ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 9055772Sas200622 9065772Sas200622 hdr->rpc_vers = 5; 9075772Sas200622 hdr->rpc_vers_minor = 0; 9088334SJose.Borrego@Sun.COM hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG; 9095772Sas200622 hdr->packed_drep = rhdr->packed_drep; 9105772Sas200622 hdr->frag_length = 0; 9115772Sas200622 hdr->auth_length = 0; 9125772Sas200622 hdr->call_id = rhdr->call_id; 9135772Sas200622 #ifdef _BIG_ENDIAN 9148334SJose.Borrego@Sun.COM hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII 9158334SJose.Borrego@Sun.COM | NDR_REPLAB_INTG_BIG_ENDIAN; 9165772Sas200622 #else 9178334SJose.Borrego@Sun.COM hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII 9188334SJose.Borrego@Sun.COM | NDR_REPLAB_INTG_LITTLE_ENDIAN; 9195772Sas200622 #endif 9205772Sas200622 9215772Sas200622 switch (mxa->ptype) { 9228334SJose.Borrego@Sun.COM case NDR_PTYPE_BIND: 9238334SJose.Borrego@Sun.COM hdr->ptype = NDR_PTYPE_BIND_ACK; 9245772Sas200622 mxa->send_hdr.bind_ack_hdr.max_xmit_frag = 9255772Sas200622 mxa->recv_hdr.bind_hdr.max_xmit_frag; 9265772Sas200622 mxa->send_hdr.bind_ack_hdr.max_recv_frag = 9275772Sas200622 mxa->recv_hdr.bind_hdr.max_recv_frag; 9285772Sas200622 mxa->send_hdr.bind_ack_hdr.assoc_group_id = 9295772Sas200622 mxa->recv_hdr.bind_hdr.assoc_group_id; 9305772Sas200622 9315772Sas200622 if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0) 9325772Sas200622 mxa->send_hdr.bind_ack_hdr.assoc_group_id = time(0); 9335772Sas200622 9345772Sas200622 /* 9355772Sas200622 * Save the maximum fragment sizes 9365772Sas200622 * for use with subsequent requests. 9375772Sas200622 */ 9388334SJose.Borrego@Sun.COM mxa->pipe->np_max_xmit_frag = 9395772Sas200622 mxa->recv_hdr.bind_hdr.max_xmit_frag; 9408334SJose.Borrego@Sun.COM mxa->pipe->np_max_recv_frag = 9415772Sas200622 mxa->recv_hdr.bind_hdr.max_recv_frag; 9425772Sas200622 break; 9435772Sas200622 9448334SJose.Borrego@Sun.COM case NDR_PTYPE_REQUEST: 9458334SJose.Borrego@Sun.COM hdr->ptype = NDR_PTYPE_RESPONSE; 9465772Sas200622 /* mxa->send_hdr.response_hdr.alloc_hint */ 9475772Sas200622 mxa->send_hdr.response_hdr.p_cont_id = 9485772Sas200622 mxa->recv_hdr.request_hdr.p_cont_id; 9495772Sas200622 mxa->send_hdr.response_hdr.cancel_count = 0; 9505772Sas200622 mxa->send_hdr.response_hdr.reserved = 0; 9515772Sas200622 break; 9525772Sas200622 9538334SJose.Borrego@Sun.COM case NDR_PTYPE_ALTER_CONTEXT: 9548334SJose.Borrego@Sun.COM hdr->ptype = NDR_PTYPE_ALTER_CONTEXT_RESP; 9555772Sas200622 /* 9567619SJose.Borrego@Sun.COM * The max_xmit_frag, max_recv_frag and assoc_group_id are 9577619SJose.Borrego@Sun.COM * ignored by the client but it's useful to fill them in. 9585772Sas200622 */ 9597619SJose.Borrego@Sun.COM mxa->send_hdr.alter_context_rsp_hdr.max_xmit_frag = 9607619SJose.Borrego@Sun.COM mxa->recv_hdr.alter_context_hdr.max_xmit_frag; 9617619SJose.Borrego@Sun.COM mxa->send_hdr.alter_context_rsp_hdr.max_recv_frag = 9627619SJose.Borrego@Sun.COM mxa->recv_hdr.alter_context_hdr.max_recv_frag; 9637619SJose.Borrego@Sun.COM mxa->send_hdr.alter_context_rsp_hdr.assoc_group_id = 9647619SJose.Borrego@Sun.COM mxa->recv_hdr.alter_context_hdr.assoc_group_id; 9655772Sas200622 break; 9665772Sas200622 9675772Sas200622 default: 9685772Sas200622 hdr->ptype = 0xFF; 9695772Sas200622 } 9705772Sas200622 } 9715772Sas200622 9725772Sas200622 /* 9735772Sas200622 * Signal an RPC fault. The stream is reset and we overwrite whatever 9745772Sas200622 * was in the response header with the fault information. 9755772Sas200622 */ 9765772Sas200622 static void 9778334SJose.Borrego@Sun.COM ndr_reply_fault(ndr_xa_t *mxa, unsigned long drc) 9785772Sas200622 { 9797619SJose.Borrego@Sun.COM ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr; 9807619SJose.Borrego@Sun.COM ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 9818334SJose.Borrego@Sun.COM ndr_stream_t *nds = &mxa->send_nds; 9825772Sas200622 unsigned long fault_status; 9835772Sas200622 9848334SJose.Borrego@Sun.COM NDS_RESET(nds); 9855772Sas200622 9865772Sas200622 hdr->rpc_vers = 5; 9875772Sas200622 hdr->rpc_vers_minor = 0; 9888334SJose.Borrego@Sun.COM hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG; 9895772Sas200622 hdr->packed_drep = rhdr->packed_drep; 9905772Sas200622 hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr); 9915772Sas200622 hdr->auth_length = 0; 9925772Sas200622 hdr->call_id = rhdr->call_id; 9935772Sas200622 #ifdef _BIG_ENDIAN 9948334SJose.Borrego@Sun.COM hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII 9958334SJose.Borrego@Sun.COM | NDR_REPLAB_INTG_BIG_ENDIAN; 9965772Sas200622 #else 9978334SJose.Borrego@Sun.COM hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII 9988334SJose.Borrego@Sun.COM | NDR_REPLAB_INTG_LITTLE_ENDIAN; 9995772Sas200622 #endif 10005772Sas200622 10018334SJose.Borrego@Sun.COM switch (drc & NDR_DRC_MASK_SPECIFIER) { 10028334SJose.Borrego@Sun.COM case NDR_DRC_FAULT_OUT_OF_MEMORY: 10038334SJose.Borrego@Sun.COM case NDR_DRC_FAULT_ENCODE_TOO_BIG: 10048334SJose.Borrego@Sun.COM fault_status = NDR_FAULT_NCA_OUT_ARGS_TOO_BIG; 10055772Sas200622 break; 10065772Sas200622 10078334SJose.Borrego@Sun.COM case NDR_DRC_FAULT_REQUEST_PCONT_INVALID: 10088334SJose.Borrego@Sun.COM fault_status = NDR_FAULT_NCA_INVALID_PRES_CONTEXT_ID; 10095772Sas200622 break; 10105772Sas200622 10118334SJose.Borrego@Sun.COM case NDR_DRC_FAULT_REQUEST_OPNUM_INVALID: 10128334SJose.Borrego@Sun.COM fault_status = NDR_FAULT_NCA_OP_RNG_ERROR; 10135772Sas200622 break; 10145772Sas200622 10158334SJose.Borrego@Sun.COM case NDR_DRC_FAULT_DECODE_FAILED: 10168334SJose.Borrego@Sun.COM case NDR_DRC_FAULT_ENCODE_FAILED: 10178334SJose.Borrego@Sun.COM fault_status = NDR_FAULT_NCA_PROTO_ERROR; 10185772Sas200622 break; 10195772Sas200622 10205772Sas200622 default: 10218334SJose.Borrego@Sun.COM fault_status = NDR_FAULT_NCA_UNSPEC_REJECT; 10225772Sas200622 break; 10235772Sas200622 } 10245772Sas200622 10258334SJose.Borrego@Sun.COM mxa->send_hdr.fault_hdr.common_hdr.ptype = NDR_PTYPE_FAULT; 10265772Sas200622 mxa->send_hdr.fault_hdr.status = fault_status; 10275772Sas200622 mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length; 10285772Sas200622 } 10295772Sas200622 10307619SJose.Borrego@Sun.COM /* 10317619SJose.Borrego@Sun.COM * Note that the frag_length for bind ack and alter context is 10327619SJose.Borrego@Sun.COM * non-standard. 10337619SJose.Borrego@Sun.COM */ 10345772Sas200622 static int 10358334SJose.Borrego@Sun.COM ndr_build_reply(ndr_xa_t *mxa) 10365772Sas200622 { 10377619SJose.Borrego@Sun.COM ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 10388334SJose.Borrego@Sun.COM ndr_stream_t *nds = &mxa->send_nds; 10396482Samw uint8_t *pdu_buf; 10405772Sas200622 unsigned long pdu_size; 10415772Sas200622 unsigned long frag_size; 10425772Sas200622 unsigned long pdu_data_size; 10435772Sas200622 unsigned long frag_data_size; 10445772Sas200622 10458334SJose.Borrego@Sun.COM frag_size = NDR_FRAG_SZ; 10468334SJose.Borrego@Sun.COM pdu_size = nds->pdu_size; 10478334SJose.Borrego@Sun.COM pdu_buf = nds->pdu_base_addr; 10485772Sas200622 10495772Sas200622 if (pdu_size <= frag_size) { 10505772Sas200622 /* 10515772Sas200622 * Single fragment response. The PDU size may be zero 10525772Sas200622 * here (i.e. bind or fault response). So don't make 10535772Sas200622 * any assumptions about it until after the header is 10545772Sas200622 * encoded. 10555772Sas200622 */ 10565772Sas200622 switch (hdr->ptype) { 10578334SJose.Borrego@Sun.COM case NDR_PTYPE_BIND_ACK: 10588334SJose.Borrego@Sun.COM hdr->frag_length = ndr_bind_ack_hdr_size(mxa); 10595772Sas200622 break; 10605772Sas200622 10618334SJose.Borrego@Sun.COM case NDR_PTYPE_FAULT: 10625772Sas200622 /* already setup */ 10635772Sas200622 break; 10645772Sas200622 10658334SJose.Borrego@Sun.COM case NDR_PTYPE_RESPONSE: 10665772Sas200622 hdr->frag_length = pdu_size; 10675772Sas200622 mxa->send_hdr.response_hdr.alloc_hint = 10685772Sas200622 hdr->frag_length; 10695772Sas200622 break; 10705772Sas200622 10718334SJose.Borrego@Sun.COM case NDR_PTYPE_ALTER_CONTEXT_RESP: 10728334SJose.Borrego@Sun.COM hdr->frag_length = ndr_alter_context_rsp_hdr_size(); 10737619SJose.Borrego@Sun.COM break; 10747619SJose.Borrego@Sun.COM 10755772Sas200622 default: 10765772Sas200622 hdr->frag_length = pdu_size; 10775772Sas200622 break; 10785772Sas200622 } 10795772Sas200622 10808334SJose.Borrego@Sun.COM nds->pdu_scan_offset = 0; 10818334SJose.Borrego@Sun.COM (void) ndr_encode_pdu_hdr(mxa); 10828334SJose.Borrego@Sun.COM pdu_size = nds->pdu_size; 10838334SJose.Borrego@Sun.COM ndr_build_frag(nds, pdu_buf, pdu_size); 10845772Sas200622 return (0); 10855772Sas200622 } 10865772Sas200622 10875772Sas200622 /* 10885772Sas200622 * Multiple fragment response. 10895772Sas200622 */ 10908334SJose.Borrego@Sun.COM hdr->pfc_flags = NDR_PFC_FIRST_FRAG; 10915772Sas200622 hdr->frag_length = frag_size; 10928334SJose.Borrego@Sun.COM mxa->send_hdr.response_hdr.alloc_hint = pdu_size - NDR_RSP_HDR_SIZE; 10938334SJose.Borrego@Sun.COM nds->pdu_scan_offset = 0; 10948334SJose.Borrego@Sun.COM (void) ndr_encode_pdu_hdr(mxa); 10958334SJose.Borrego@Sun.COM ndr_build_frag(nds, pdu_buf, frag_size); 10965772Sas200622 10975772Sas200622 /* 10985772Sas200622 * We need to update the 24-byte header in subsequent fragments. 10995772Sas200622 * 11006482Samw * pdu_data_size: total data remaining to be handled 11016482Samw * frag_size: total fragment size including header 11026482Samw * frag_data_size: data in fragment 11038334SJose.Borrego@Sun.COM * (i.e. frag_size - NDR_RSP_HDR_SIZE) 11045772Sas200622 */ 11058334SJose.Borrego@Sun.COM pdu_data_size = pdu_size - NDR_RSP_HDR_SIZE; 11068334SJose.Borrego@Sun.COM frag_data_size = frag_size - NDR_RSP_HDR_SIZE; 11075772Sas200622 11086482Samw while (pdu_data_size) { 11096482Samw mxa->send_hdr.response_hdr.alloc_hint -= frag_data_size; 11106482Samw pdu_data_size -= frag_data_size; 11116482Samw pdu_buf += frag_data_size; 11125772Sas200622 11136482Samw if (pdu_data_size <= frag_data_size) { 11146482Samw frag_data_size = pdu_data_size; 11158334SJose.Borrego@Sun.COM frag_size = frag_data_size + NDR_RSP_HDR_SIZE; 11168334SJose.Borrego@Sun.COM hdr->pfc_flags = NDR_PFC_LAST_FRAG; 11175772Sas200622 } else { 11186482Samw hdr->pfc_flags = 0; 11195772Sas200622 } 11205772Sas200622 11216482Samw hdr->frag_length = frag_size; 11228334SJose.Borrego@Sun.COM nds->pdu_scan_offset = 0; 11238334SJose.Borrego@Sun.COM (void) ndr_encode_pdu_hdr(mxa); 11248334SJose.Borrego@Sun.COM bcopy(nds->pdu_base_addr, pdu_buf, NDR_RSP_HDR_SIZE); 11255772Sas200622 11268334SJose.Borrego@Sun.COM ndr_build_frag(nds, pdu_buf, frag_size); 11275772Sas200622 11288334SJose.Borrego@Sun.COM if (hdr->pfc_flags & NDR_PFC_LAST_FRAG) 11296482Samw break; 11305772Sas200622 } 11315772Sas200622 11325772Sas200622 return (0); 11335772Sas200622 } 11346482Samw 11356482Samw /* 11368334SJose.Borrego@Sun.COM * ndr_build_frag 11376482Samw * 11386482Samw * Build an RPC PDU fragment from the specified buffer. 11396482Samw * If malloc fails, the client will see a header/pdu inconsistency 11406482Samw * and report an error. 11416482Samw */ 11426482Samw static void 11438334SJose.Borrego@Sun.COM ndr_build_frag(ndr_stream_t *nds, uint8_t *buf, uint32_t len) 11446482Samw { 11456482Samw ndr_frag_t *frag; 11466482Samw int size = sizeof (ndr_frag_t) + len; 11476482Samw 11486482Samw if ((frag = (ndr_frag_t *)malloc(size)) == NULL) 11496482Samw return; 11506482Samw 11516482Samw frag->next = NULL; 11526482Samw frag->buf = (uint8_t *)frag + sizeof (ndr_frag_t); 11536482Samw frag->len = len; 11546482Samw bcopy(buf, frag->buf, len); 11556482Samw 11568334SJose.Borrego@Sun.COM if (nds->frags.head == NULL) { 11578334SJose.Borrego@Sun.COM nds->frags.head = frag; 11588334SJose.Borrego@Sun.COM nds->frags.tail = frag; 11598334SJose.Borrego@Sun.COM nds->frags.nfrag = 1; 11606482Samw } else { 11618334SJose.Borrego@Sun.COM nds->frags.tail->next = frag; 11628334SJose.Borrego@Sun.COM nds->frags.tail = frag; 11638334SJose.Borrego@Sun.COM ++nds->frags.nfrag; 11646482Samw } 11656482Samw } 1166