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 /* 225772Sas200622 * Copyright 2008 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> 425772Sas200622 435772Sas200622 /* 445772Sas200622 * Fragment size (5680: NT style). 455772Sas200622 */ 46*8334SJose.Borrego@Sun.COM #define NDR_FRAG_SZ 5680 475772Sas200622 48*8334SJose.Borrego@Sun.COM #define NDR_PIPE_BUFSZ 65536 49*8334SJose.Borrego@Sun.COM #define NDR_PIPE_MAX 128 50*8334SJose.Borrego@Sun.COM static ndr_pipe_t ndr_pipe_table[NDR_PIPE_MAX]; 51*8334SJose.Borrego@Sun.COM static mutex_t ndr_pipe_lock; 525772Sas200622 53*8334SJose.Borrego@Sun.COM static int ndr_pipe_transact(ndr_pipe_t *); 54*8334SJose.Borrego@Sun.COM static ndr_pipe_t *ndr_pipe_lookup(int); 55*8334SJose.Borrego@Sun.COM static void ndr_pipe_release(ndr_pipe_t *); 56*8334SJose.Borrego@Sun.COM static ndr_pipe_t *ndr_pipe_allocate(int); 57*8334SJose.Borrego@Sun.COM static void ndr_pipe_deallocate(ndr_pipe_t *); 58*8334SJose.Borrego@Sun.COM static void ndr_pipe_rewind(ndr_pipe_t *); 59*8334SJose.Borrego@Sun.COM static void ndr_pipe_flush(ndr_pipe_t *); 607052Samw 61*8334SJose.Borrego@Sun.COM static int ndr_svc_process(ndr_xa_t *); 62*8334SJose.Borrego@Sun.COM static int ndr_svc_bind(ndr_xa_t *); 63*8334SJose.Borrego@Sun.COM static int ndr_svc_request(ndr_xa_t *); 64*8334SJose.Borrego@Sun.COM static void ndr_reply_prepare_hdr(ndr_xa_t *); 65*8334SJose.Borrego@Sun.COM static int ndr_svc_alter_context(ndr_xa_t *); 66*8334SJose.Borrego@Sun.COM static void ndr_reply_fault(ndr_xa_t *, unsigned long); 67*8334SJose.Borrego@Sun.COM static int ndr_build_reply(ndr_xa_t *); 68*8334SJose.Borrego@Sun.COM static void ndr_build_frag(ndr_stream_t *, uint8_t *, uint32_t); 695772Sas200622 705772Sas200622 /* 717052Samw * Allocate and associate a service context with a fid. 727052Samw */ 737052Samw int 74*8334SJose.Borrego@Sun.COM ndr_pipe_open(int fid, uint8_t *data, uint32_t datalen) 757052Samw { 76*8334SJose.Borrego@Sun.COM ndr_pipe_t *np; 777052Samw 78*8334SJose.Borrego@Sun.COM (void) mutex_lock(&ndr_pipe_lock); 797052Samw 80*8334SJose.Borrego@Sun.COM if ((np = ndr_pipe_lookup(fid)) != NULL) { 81*8334SJose.Borrego@Sun.COM ndr_pipe_release(np); 82*8334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 837052Samw return (EEXIST); 847052Samw } 857052Samw 86*8334SJose.Borrego@Sun.COM if ((np = ndr_pipe_allocate(fid)) == NULL) { 87*8334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 887052Samw return (ENOMEM); 897052Samw } 907052Samw 91*8334SJose.Borrego@Sun.COM if (smb_opipe_context_decode(&np->np_ctx, data, datalen) == -1) { 92*8334SJose.Borrego@Sun.COM ndr_pipe_release(np); 93*8334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 947052Samw return (EINVAL); 957052Samw } 967052Samw 97*8334SJose.Borrego@Sun.COM ndr_svc_binding_pool_init(&np->np_binding, np->np_binding_pool, 98*8334SJose.Borrego@Sun.COM NDR_N_BINDING_POOL); 997052Samw 100*8334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 1017052Samw return (0); 1027052Samw } 1037052Samw 1047052Samw /* 1057052Samw * Release the context associated with a fid when an opipe is closed. 1067052Samw */ 1077052Samw int 108*8334SJose.Borrego@Sun.COM ndr_pipe_close(int fid) 1097052Samw { 110*8334SJose.Borrego@Sun.COM ndr_pipe_t *np; 1117052Samw 112*8334SJose.Borrego@Sun.COM (void) mutex_lock(&ndr_pipe_lock); 1137052Samw 114*8334SJose.Borrego@Sun.COM if ((np = ndr_pipe_lookup(fid)) == NULL) { 115*8334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 1167052Samw return (ENOENT); 1177052Samw } 1187052Samw 1197052Samw /* 1207052Samw * Release twice: once for the lookup above 1217052Samw * and again to close the fid. 1227052Samw */ 123*8334SJose.Borrego@Sun.COM ndr_pipe_release(np); 124*8334SJose.Borrego@Sun.COM ndr_pipe_release(np); 125*8334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 1267052Samw return (0); 1277052Samw } 1287052Samw 1297052Samw /* 1307052Samw * Write RPC request data to the input stream. Input data is buffered 1317052Samw * until the response is requested. 1325772Sas200622 */ 1337052Samw int 134*8334SJose.Borrego@Sun.COM ndr_pipe_write(int fid, uint8_t *buf, uint32_t len) 1357052Samw { 136*8334SJose.Borrego@Sun.COM ndr_pipe_t *np; 1377052Samw ssize_t nbytes; 1387052Samw 1397052Samw if (len == 0) 1407052Samw return (0); 1417052Samw 142*8334SJose.Borrego@Sun.COM (void) mutex_lock(&ndr_pipe_lock); 1437052Samw 144*8334SJose.Borrego@Sun.COM if ((np = ndr_pipe_lookup(fid)) == NULL) { 145*8334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 1467052Samw return (ENOENT); 1477052Samw } 1487052Samw 149*8334SJose.Borrego@Sun.COM nbytes = ndr_uiomove((caddr_t)buf, len, UIO_READ, &np->np_uio); 1507052Samw 151*8334SJose.Borrego@Sun.COM ndr_pipe_release(np); 152*8334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 1537052Samw return ((nbytes == len) ? 0 : EIO); 1547052Samw } 1557052Samw 1567052Samw /* 1577052Samw * Read RPC response data. If the input stream contains an RPC request, 1587052Samw * we need to process the RPC transaction, which will place the RPC 1597052Samw * response in the output (frags) stream. Otherwise, read data from 1607052Samw * the output stream. 1617052Samw */ 1627052Samw int 163*8334SJose.Borrego@Sun.COM ndr_pipe_read(int fid, uint8_t *buf, uint32_t *len, uint32_t *resid) 1645772Sas200622 { 165*8334SJose.Borrego@Sun.COM ndr_pipe_t *np; 1667052Samw ssize_t nbytes = *len; 1677052Samw int rc; 1687052Samw 1697052Samw if (nbytes == 0) { 1707052Samw *resid = 0; 1717052Samw return (0); 1727052Samw } 1737052Samw 174*8334SJose.Borrego@Sun.COM (void) mutex_lock(&ndr_pipe_lock); 175*8334SJose.Borrego@Sun.COM if ((np = ndr_pipe_lookup(fid)) == NULL) { 176*8334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 1777052Samw return (ENOENT); 1787052Samw } 179*8334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 1807052Samw 181*8334SJose.Borrego@Sun.COM if (np->np_uio.uio_offset) { 182*8334SJose.Borrego@Sun.COM if ((rc = ndr_pipe_transact(np)) != 0) { 183*8334SJose.Borrego@Sun.COM ndr_pipe_flush(np); 184*8334SJose.Borrego@Sun.COM (void) mutex_lock(&ndr_pipe_lock); 185*8334SJose.Borrego@Sun.COM ndr_pipe_release(np); 186*8334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 1877052Samw return (rc); 1887052Samw } 1897052Samw 1907052Samw } 1917052Samw 192*8334SJose.Borrego@Sun.COM *len = ndr_uiomove((caddr_t)buf, nbytes, UIO_WRITE, &np->np_frags.uio); 193*8334SJose.Borrego@Sun.COM *resid = np->np_frags.uio.uio_resid; 1947052Samw 1957052Samw if (*resid == 0) { 1967052Samw /* 1977052Samw * Nothing left, cleanup the output stream. 1987052Samw */ 199*8334SJose.Borrego@Sun.COM ndr_pipe_flush(np); 2007052Samw } 2017052Samw 202*8334SJose.Borrego@Sun.COM (void) mutex_lock(&ndr_pipe_lock); 203*8334SJose.Borrego@Sun.COM ndr_pipe_release(np); 204*8334SJose.Borrego@Sun.COM (void) mutex_unlock(&ndr_pipe_lock); 2057052Samw return (0); 2067052Samw } 2077052Samw 2087052Samw /* 2097052Samw * Process a server-side RPC request. 2107052Samw */ 2117052Samw static int 212*8334SJose.Borrego@Sun.COM ndr_pipe_transact(ndr_pipe_t *np) 2137052Samw { 214*8334SJose.Borrego@Sun.COM ndr_xa_t *mxa; 215*8334SJose.Borrego@Sun.COM ndr_stream_t *recv_nds; 216*8334SJose.Borrego@Sun.COM ndr_stream_t *send_nds; 217*8334SJose.Borrego@Sun.COM char *data; 218*8334SJose.Borrego@Sun.COM int datalen; 2195772Sas200622 220*8334SJose.Borrego@Sun.COM data = np->np_buf; 221*8334SJose.Borrego@Sun.COM datalen = np->np_uio.uio_offset; 2225772Sas200622 2237052Samw if ((mxa = (ndr_xa_t *)malloc(sizeof (ndr_xa_t))) == NULL) 2247052Samw return (ENOMEM); 2255772Sas200622 226*8334SJose.Borrego@Sun.COM bzero(mxa, sizeof (ndr_xa_t)); 227*8334SJose.Borrego@Sun.COM mxa->fid = np->np_fid; 228*8334SJose.Borrego@Sun.COM mxa->pipe = np; 229*8334SJose.Borrego@Sun.COM mxa->binding_list = np->np_binding; 2305772Sas200622 231*8334SJose.Borrego@Sun.COM if ((mxa->heap = ndr_heap_create()) == NULL) { 2325772Sas200622 free(mxa); 2337052Samw return (ENOMEM); 2345772Sas200622 } 2355772Sas200622 236*8334SJose.Borrego@Sun.COM recv_nds = &mxa->recv_nds; 237*8334SJose.Borrego@Sun.COM nds_initialize(recv_nds, datalen, NDR_MODE_CALL_RECV, mxa->heap); 2385772Sas200622 2397052Samw /* 2407052Samw * Copy the input data and reset the input stream. 2417052Samw */ 242*8334SJose.Borrego@Sun.COM bcopy(data, recv_nds->pdu_base_addr, datalen); 243*8334SJose.Borrego@Sun.COM ndr_pipe_rewind(np); 2445772Sas200622 245*8334SJose.Borrego@Sun.COM send_nds = &mxa->send_nds; 246*8334SJose.Borrego@Sun.COM nds_initialize(send_nds, 0, NDR_MODE_RETURN_SEND, mxa->heap); 2475772Sas200622 248*8334SJose.Borrego@Sun.COM (void) ndr_svc_process(mxa); 2495772Sas200622 250*8334SJose.Borrego@Sun.COM nds_finalize(send_nds, &np->np_frags); 251*8334SJose.Borrego@Sun.COM nds_destruct(&mxa->recv_nds); 252*8334SJose.Borrego@Sun.COM nds_destruct(&mxa->send_nds); 253*8334SJose.Borrego@Sun.COM ndr_heap_destroy(mxa->heap); 2545772Sas200622 free(mxa); 2557052Samw return (0); 2567052Samw } 2577052Samw 2587052Samw /* 259*8334SJose.Borrego@Sun.COM * Must be called with ndr_pipe_lock held. 2607052Samw */ 261*8334SJose.Borrego@Sun.COM static ndr_pipe_t * 262*8334SJose.Borrego@Sun.COM ndr_pipe_lookup(int fid) 2637052Samw { 264*8334SJose.Borrego@Sun.COM ndr_pipe_t *np; 2657052Samw int i; 2667052Samw 267*8334SJose.Borrego@Sun.COM for (i = 0; i < NDR_PIPE_MAX; ++i) { 268*8334SJose.Borrego@Sun.COM np = &ndr_pipe_table[i]; 2697052Samw 270*8334SJose.Borrego@Sun.COM if (np->np_fid == fid) { 271*8334SJose.Borrego@Sun.COM if (np->np_refcnt == 0) 2727052Samw return (NULL); 2737052Samw 274*8334SJose.Borrego@Sun.COM np->np_refcnt++; 275*8334SJose.Borrego@Sun.COM return (np); 2767052Samw } 2777052Samw } 2787052Samw 2797052Samw return (NULL); 2805772Sas200622 } 2815772Sas200622 2825772Sas200622 /* 283*8334SJose.Borrego@Sun.COM * Must be called with ndr_pipe_lock held. 2845772Sas200622 */ 2857052Samw static void 286*8334SJose.Borrego@Sun.COM ndr_pipe_release(ndr_pipe_t *np) 2875772Sas200622 { 288*8334SJose.Borrego@Sun.COM np->np_refcnt--; 289*8334SJose.Borrego@Sun.COM ndr_pipe_deallocate(np); 2907052Samw } 2917052Samw 2927052Samw /* 293*8334SJose.Borrego@Sun.COM * Must be called with ndr_pipe_lock held. 2947052Samw */ 295*8334SJose.Borrego@Sun.COM static ndr_pipe_t * 296*8334SJose.Borrego@Sun.COM ndr_pipe_allocate(int fid) 2977052Samw { 298*8334SJose.Borrego@Sun.COM ndr_pipe_t *np = NULL; 2995772Sas200622 int i; 3005772Sas200622 301*8334SJose.Borrego@Sun.COM for (i = 0; i < NDR_PIPE_MAX; ++i) { 302*8334SJose.Borrego@Sun.COM np = &ndr_pipe_table[i]; 3035772Sas200622 304*8334SJose.Borrego@Sun.COM if (np->np_fid == 0) { 305*8334SJose.Borrego@Sun.COM bzero(np, sizeof (ndr_pipe_t)); 3065772Sas200622 307*8334SJose.Borrego@Sun.COM if ((np->np_buf = malloc(NDR_PIPE_BUFSZ)) == NULL) 3087052Samw return (NULL); 3095772Sas200622 310*8334SJose.Borrego@Sun.COM ndr_pipe_rewind(np); 311*8334SJose.Borrego@Sun.COM np->np_fid = fid; 312*8334SJose.Borrego@Sun.COM np->np_refcnt = 1; 313*8334SJose.Borrego@Sun.COM return (np); 3145772Sas200622 } 3155772Sas200622 } 3165772Sas200622 3177052Samw return (NULL); 3187052Samw } 3195772Sas200622 3207052Samw /* 321*8334SJose.Borrego@Sun.COM * Must be called with ndr_pipe_lock held. 3227052Samw */ 3237052Samw static void 324*8334SJose.Borrego@Sun.COM ndr_pipe_deallocate(ndr_pipe_t *np) 3257052Samw { 326*8334SJose.Borrego@Sun.COM if (np->np_refcnt == 0) { 3277052Samw /* 3287052Samw * Ensure that there are no RPC service policy handles 3297052Samw * (associated with this fid) left around. 3307052Samw */ 331*8334SJose.Borrego@Sun.COM ndr_hdclose(np->np_fid); 3325772Sas200622 333*8334SJose.Borrego@Sun.COM ndr_pipe_rewind(np); 334*8334SJose.Borrego@Sun.COM ndr_pipe_flush(np); 335*8334SJose.Borrego@Sun.COM free(np->np_buf); 336*8334SJose.Borrego@Sun.COM free(np->np_ctx.oc_domain); 337*8334SJose.Borrego@Sun.COM free(np->np_ctx.oc_account); 338*8334SJose.Borrego@Sun.COM free(np->np_ctx.oc_workstation); 339*8334SJose.Borrego@Sun.COM bzero(np, sizeof (ndr_pipe_t)); 3407052Samw } 3417052Samw } 3425772Sas200622 3437052Samw /* 3447052Samw * Rewind the input data stream, ready for the next write. 3457052Samw */ 3467052Samw static void 347*8334SJose.Borrego@Sun.COM ndr_pipe_rewind(ndr_pipe_t *np) 3487052Samw { 349*8334SJose.Borrego@Sun.COM np->np_uio.uio_iov = &np->np_iov; 350*8334SJose.Borrego@Sun.COM np->np_uio.uio_iovcnt = 1; 351*8334SJose.Borrego@Sun.COM np->np_uio.uio_offset = 0; 352*8334SJose.Borrego@Sun.COM np->np_uio.uio_segflg = UIO_USERSPACE; 353*8334SJose.Borrego@Sun.COM np->np_uio.uio_resid = NDR_PIPE_BUFSZ; 354*8334SJose.Borrego@Sun.COM np->np_iov.iov_base = np->np_buf; 355*8334SJose.Borrego@Sun.COM np->np_iov.iov_len = NDR_PIPE_BUFSZ; 3565772Sas200622 } 3575772Sas200622 3585772Sas200622 /* 3597052Samw * Flush the output data stream. 3605772Sas200622 */ 3617052Samw static void 362*8334SJose.Borrego@Sun.COM ndr_pipe_flush(ndr_pipe_t *np) 3635772Sas200622 { 3647052Samw ndr_frag_t *frag; 3655772Sas200622 366*8334SJose.Borrego@Sun.COM while ((frag = np->np_frags.head) != NULL) { 367*8334SJose.Borrego@Sun.COM np->np_frags.head = frag->next; 3687052Samw free(frag); 3695772Sas200622 } 3705772Sas200622 371*8334SJose.Borrego@Sun.COM free(np->np_frags.iov); 372*8334SJose.Borrego@Sun.COM bzero(&np->np_frags, sizeof (ndr_fraglist_t)); 3737052Samw } 3747052Samw 3757052Samw /* 3767052Samw * Check whether or not the specified user has administrator privileges, 3777052Samw * i.e. is a member of Domain Admins or Administrators. 3787052Samw * Returns true if the user is an administrator, otherwise returns false. 3797052Samw */ 3807052Samw boolean_t 3817052Samw ndr_is_admin(ndr_xa_t *xa) 3827052Samw { 383*8334SJose.Borrego@Sun.COM smb_opipe_context_t *ctx = &xa->pipe->np_ctx; 3847052Samw 385*8334SJose.Borrego@Sun.COM return (ctx->oc_flags & SMB_ATF_ADMIN); 3867052Samw } 3877052Samw 3887052Samw /* 3897052Samw * Check whether or not the specified user has power-user privileges, 3907052Samw * i.e. is a member of Domain Admins, Administrators or Power Users. 3917052Samw * This is typically required for operations such as managing shares. 3927052Samw * Returns true if the user is a power user, otherwise returns false. 3937052Samw */ 3947052Samw boolean_t 3957052Samw ndr_is_poweruser(ndr_xa_t *xa) 3967052Samw { 397*8334SJose.Borrego@Sun.COM smb_opipe_context_t *ctx = &xa->pipe->np_ctx; 3987052Samw 399*8334SJose.Borrego@Sun.COM return ((ctx->oc_flags & SMB_ATF_ADMIN) || 400*8334SJose.Borrego@Sun.COM (ctx->oc_flags & SMB_ATF_POWERUSER)); 4017052Samw } 4027052Samw 4037052Samw int32_t 4047052Samw ndr_native_os(ndr_xa_t *xa) 4057052Samw { 406*8334SJose.Borrego@Sun.COM smb_opipe_context_t *ctx = &xa->pipe->np_ctx; 4077052Samw 408*8334SJose.Borrego@Sun.COM return (ctx->oc_native_os); 4095772Sas200622 } 4105772Sas200622 4115772Sas200622 /* 4125772Sas200622 * This is the entry point for all server-side RPC processing. 4135772Sas200622 * It is assumed that the PDU has already been received. 4145772Sas200622 */ 4155772Sas200622 static int 416*8334SJose.Borrego@Sun.COM ndr_svc_process(ndr_xa_t *mxa) 4175772Sas200622 { 4185772Sas200622 int rc; 4195772Sas200622 420*8334SJose.Borrego@Sun.COM rc = ndr_decode_pdu_hdr(mxa); 421*8334SJose.Borrego@Sun.COM if (!NDR_DRC_IS_OK(rc)) 4225772Sas200622 return (-1); 4235772Sas200622 424*8334SJose.Borrego@Sun.COM (void) ndr_reply_prepare_hdr(mxa); 4255772Sas200622 4265772Sas200622 switch (mxa->ptype) { 427*8334SJose.Borrego@Sun.COM case NDR_PTYPE_BIND: 428*8334SJose.Borrego@Sun.COM rc = ndr_svc_bind(mxa); 4295772Sas200622 break; 4305772Sas200622 431*8334SJose.Borrego@Sun.COM case NDR_PTYPE_REQUEST: 432*8334SJose.Borrego@Sun.COM rc = ndr_svc_request(mxa); 4335772Sas200622 break; 4345772Sas200622 435*8334SJose.Borrego@Sun.COM case NDR_PTYPE_ALTER_CONTEXT: 436*8334SJose.Borrego@Sun.COM rc = ndr_svc_alter_context(mxa); 4375772Sas200622 break; 4385772Sas200622 4395772Sas200622 default: 440*8334SJose.Borrego@Sun.COM rc = NDR_DRC_FAULT_RPCHDR_PTYPE_INVALID; 4415772Sas200622 break; 4425772Sas200622 } 4435772Sas200622 444*8334SJose.Borrego@Sun.COM if (NDR_DRC_IS_FAULT(rc)) 445*8334SJose.Borrego@Sun.COM ndr_reply_fault(mxa, rc); 4465772Sas200622 447*8334SJose.Borrego@Sun.COM (void) ndr_build_reply(mxa); 4485772Sas200622 return (rc); 4495772Sas200622 } 4505772Sas200622 4515772Sas200622 /* 4525772Sas200622 * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple 4535772Sas200622 * p_results[] not supported. 4545772Sas200622 */ 4555772Sas200622 static int 456*8334SJose.Borrego@Sun.COM ndr_svc_bind(ndr_xa_t *mxa) 4575772Sas200622 { 458*8334SJose.Borrego@Sun.COM ndr_p_cont_list_t *cont_list; 459*8334SJose.Borrego@Sun.COM ndr_p_result_list_t *result_list; 460*8334SJose.Borrego@Sun.COM ndr_p_result_t *result; 4615772Sas200622 unsigned p_cont_id; 462*8334SJose.Borrego@Sun.COM ndr_binding_t *mbind; 4635772Sas200622 ndr_uuid_t *as_uuid; 4645772Sas200622 ndr_uuid_t *ts_uuid; 4655772Sas200622 int as_vers; 4665772Sas200622 int ts_vers; 467*8334SJose.Borrego@Sun.COM ndr_service_t *msvc; 4685772Sas200622 int rc; 469*8334SJose.Borrego@Sun.COM ndr_port_any_t *sec_addr; 4705772Sas200622 4715772Sas200622 /* acquire targets */ 4725772Sas200622 cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem; 4735772Sas200622 result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list; 4745772Sas200622 result = &result_list->p_results[0]; 4755772Sas200622 4765772Sas200622 /* 4775772Sas200622 * Set up temporary secondary address port. 4785772Sas200622 * We will correct this later (below). 4795772Sas200622 */ 4805772Sas200622 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 4815772Sas200622 sec_addr->length = 13; 4825772Sas200622 (void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs"); 4835772Sas200622 4845772Sas200622 result_list->n_results = 1; 4855772Sas200622 result_list->reserved = 0; 4865772Sas200622 result_list->reserved2 = 0; 487*8334SJose.Borrego@Sun.COM result->result = NDR_PCDR_ACCEPTANCE; 4885772Sas200622 result->reason = 0; 4895772Sas200622 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax)); 4905772Sas200622 4915772Sas200622 /* sanity check */ 4925772Sas200622 if (cont_list->n_context_elem != 1 || 4935772Sas200622 cont_list->p_cont_elem[0].n_transfer_syn != 1) { 494*8334SJose.Borrego@Sun.COM ndo_trace("ndr_svc_bind: warning: multiple p_cont_elem"); 4955772Sas200622 } 4965772Sas200622 4975772Sas200622 p_cont_id = cont_list->p_cont_elem[0].p_cont_id; 4985772Sas200622 499*8334SJose.Borrego@Sun.COM if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) != NULL) { 5005772Sas200622 /* 501*8334SJose.Borrego@Sun.COM * Duplicate presentation context id. 5025772Sas200622 */ 503*8334SJose.Borrego@Sun.COM ndo_trace("ndr_svc_bind: duplicate binding"); 504*8334SJose.Borrego@Sun.COM return (NDR_DRC_FAULT_BIND_PCONT_BUSY); 5055772Sas200622 } 5065772Sas200622 507*8334SJose.Borrego@Sun.COM if ((mbind = ndr_svc_new_binding(mxa)) == NULL) { 5085772Sas200622 /* 5095772Sas200622 * No free binding slot 5105772Sas200622 */ 511*8334SJose.Borrego@Sun.COM result->result = NDR_PCDR_PROVIDER_REJECTION; 512*8334SJose.Borrego@Sun.COM result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED; 513*8334SJose.Borrego@Sun.COM ndo_trace("ndr_svc_bind: no resources"); 514*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 5155772Sas200622 } 5165772Sas200622 5175772Sas200622 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid; 5185772Sas200622 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version; 5195772Sas200622 5205772Sas200622 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid; 5215772Sas200622 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version; 5225772Sas200622 523*8334SJose.Borrego@Sun.COM msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers); 524*8334SJose.Borrego@Sun.COM if (msvc == NULL) { 525*8334SJose.Borrego@Sun.COM result->result = NDR_PCDR_PROVIDER_REJECTION; 526*8334SJose.Borrego@Sun.COM result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 527*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 5285772Sas200622 } 5295772Sas200622 5305772Sas200622 /* 5315772Sas200622 * We can now use the correct secondary address port. 5325772Sas200622 */ 5335772Sas200622 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 5345772Sas200622 sec_addr->length = strlen(msvc->sec_addr_port) + 1; 5355772Sas200622 (void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port, 536*8334SJose.Borrego@Sun.COM NDR_PORT_ANY_MAX_PORT_SPEC); 5375772Sas200622 5385772Sas200622 mbind->p_cont_id = p_cont_id; 539*8334SJose.Borrego@Sun.COM mbind->which_side = NDR_BIND_SIDE_SERVER; 5405772Sas200622 /* mbind->context set by app */ 5415772Sas200622 mbind->service = msvc; 5425772Sas200622 mbind->instance_specific = 0; 5435772Sas200622 5445772Sas200622 mxa->binding = mbind; 5455772Sas200622 5465772Sas200622 if (msvc->bind_req) { 5475772Sas200622 /* 5485772Sas200622 * Call the service-specific bind() handler. If 5495772Sas200622 * this fails, we shouild send a specific error 5505772Sas200622 * on the bind ack. 5515772Sas200622 */ 5525772Sas200622 rc = (msvc->bind_req)(mxa); 553*8334SJose.Borrego@Sun.COM if (NDR_DRC_IS_FAULT(rc)) { 5545772Sas200622 mbind->service = 0; /* free binding slot */ 5555772Sas200622 mbind->which_side = 0; 5565772Sas200622 mbind->p_cont_id = 0; 5575772Sas200622 mbind->instance_specific = 0; 5585772Sas200622 return (rc); 5595772Sas200622 } 5605772Sas200622 } 5615772Sas200622 5625772Sas200622 result->transfer_syntax = 5635772Sas200622 cont_list->p_cont_elem[0].transfer_syntaxes[0]; 5645772Sas200622 565*8334SJose.Borrego@Sun.COM return (NDR_DRC_BINDING_MADE); 5665772Sas200622 } 5675772Sas200622 5685772Sas200622 /* 569*8334SJose.Borrego@Sun.COM * ndr_svc_alter_context 5705772Sas200622 * 5715772Sas200622 * The alter context request is used to request additional presentation 5727619SJose.Borrego@Sun.COM * context for another interface and/or version. It is very similar to 5737619SJose.Borrego@Sun.COM * a bind request. 5745772Sas200622 */ 5755772Sas200622 static int 576*8334SJose.Borrego@Sun.COM ndr_svc_alter_context(ndr_xa_t *mxa) 5775772Sas200622 { 578*8334SJose.Borrego@Sun.COM ndr_p_result_list_t *result_list; 579*8334SJose.Borrego@Sun.COM ndr_p_result_t *result; 580*8334SJose.Borrego@Sun.COM ndr_p_cont_list_t *cont_list; 581*8334SJose.Borrego@Sun.COM ndr_binding_t *mbind; 582*8334SJose.Borrego@Sun.COM ndr_service_t *msvc; 5835772Sas200622 unsigned p_cont_id; 5845772Sas200622 ndr_uuid_t *as_uuid; 5855772Sas200622 ndr_uuid_t *ts_uuid; 5865772Sas200622 int as_vers; 5875772Sas200622 int ts_vers; 588*8334SJose.Borrego@Sun.COM ndr_port_any_t *sec_addr; 5895772Sas200622 5907619SJose.Borrego@Sun.COM result_list = &mxa->send_hdr.alter_context_rsp_hdr.p_result_list; 5915772Sas200622 result_list->n_results = 1; 5925772Sas200622 result_list->reserved = 0; 5935772Sas200622 result_list->reserved2 = 0; 5945772Sas200622 5955772Sas200622 result = &result_list->p_results[0]; 596*8334SJose.Borrego@Sun.COM result->result = NDR_PCDR_ACCEPTANCE; 5975772Sas200622 result->reason = 0; 5985772Sas200622 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax)); 5995772Sas200622 6007619SJose.Borrego@Sun.COM cont_list = &mxa->recv_hdr.alter_context_hdr.p_context_elem; 6015772Sas200622 p_cont_id = cont_list->p_cont_elem[0].p_cont_id; 6025772Sas200622 603*8334SJose.Borrego@Sun.COM if (ndr_svc_find_binding(mxa, p_cont_id) != NULL) 604*8334SJose.Borrego@Sun.COM return (NDR_DRC_FAULT_BIND_PCONT_BUSY); 6055772Sas200622 606*8334SJose.Borrego@Sun.COM if ((mbind = ndr_svc_new_binding(mxa)) == NULL) { 607*8334SJose.Borrego@Sun.COM result->result = NDR_PCDR_PROVIDER_REJECTION; 608*8334SJose.Borrego@Sun.COM result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED; 609*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 6105772Sas200622 } 6115772Sas200622 6125772Sas200622 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid; 6135772Sas200622 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version; 6145772Sas200622 6155772Sas200622 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid; 6165772Sas200622 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version; 6175772Sas200622 618*8334SJose.Borrego@Sun.COM msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers); 619*8334SJose.Borrego@Sun.COM if (msvc == NULL) { 620*8334SJose.Borrego@Sun.COM result->result = NDR_PCDR_PROVIDER_REJECTION; 621*8334SJose.Borrego@Sun.COM result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 622*8334SJose.Borrego@Sun.COM return (NDR_DRC_OK); 6235772Sas200622 } 6245772Sas200622 6255772Sas200622 mbind->p_cont_id = p_cont_id; 626*8334SJose.Borrego@Sun.COM mbind->which_side = NDR_BIND_SIDE_SERVER; 6275772Sas200622 /* mbind->context set by app */ 6285772Sas200622 mbind->service = msvc; 6295772Sas200622 mbind->instance_specific = 0; 6305772Sas200622 mxa->binding = mbind; 6315772Sas200622 6327619SJose.Borrego@Sun.COM sec_addr = &mxa->send_hdr.alter_context_rsp_hdr.sec_addr; 6335772Sas200622 sec_addr->length = 0; 634*8334SJose.Borrego@Sun.COM bzero(sec_addr->port_spec, NDR_PORT_ANY_MAX_PORT_SPEC); 6355772Sas200622 6365772Sas200622 result->transfer_syntax = 6375772Sas200622 cont_list->p_cont_elem[0].transfer_syntaxes[0]; 6385772Sas200622 639*8334SJose.Borrego@Sun.COM return (NDR_DRC_BINDING_MADE); 6405772Sas200622 } 6415772Sas200622 6425772Sas200622 static int 643*8334SJose.Borrego@Sun.COM ndr_svc_request(ndr_xa_t *mxa) 6445772Sas200622 { 645*8334SJose.Borrego@Sun.COM ndr_binding_t *mbind; 646*8334SJose.Borrego@Sun.COM ndr_service_t *msvc; 647*8334SJose.Borrego@Sun.COM unsigned p_cont_id; 648*8334SJose.Borrego@Sun.COM int rc; 6495772Sas200622 6505772Sas200622 mxa->opnum = mxa->recv_hdr.request_hdr.opnum; 6515772Sas200622 p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id; 6525772Sas200622 653*8334SJose.Borrego@Sun.COM if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) == NULL) 654*8334SJose.Borrego@Sun.COM return (NDR_DRC_FAULT_REQUEST_PCONT_INVALID); 6555772Sas200622 6565772Sas200622 mxa->binding = mbind; 6575772Sas200622 msvc = mbind->service; 6585772Sas200622 6595772Sas200622 /* 6605772Sas200622 * Make room for the response hdr. 6615772Sas200622 */ 662*8334SJose.Borrego@Sun.COM mxa->send_nds.pdu_scan_offset = NDR_RSP_HDR_SIZE; 6635772Sas200622 6645772Sas200622 if (msvc->call_stub) 6655772Sas200622 rc = (*msvc->call_stub)(mxa); 6665772Sas200622 else 667*8334SJose.Borrego@Sun.COM rc = ndr_generic_call_stub(mxa); 6685772Sas200622 669*8334SJose.Borrego@Sun.COM if (NDR_DRC_IS_FAULT(rc)) { 670*8334SJose.Borrego@Sun.COM ndo_printf(0, 0, "%s[0x%02x]: 0x%04x", 6715772Sas200622 msvc->name, mxa->opnum, rc); 6725772Sas200622 } 6735772Sas200622 6745772Sas200622 return (rc); 6755772Sas200622 } 6765772Sas200622 6775772Sas200622 /* 678*8334SJose.Borrego@Sun.COM * The transaction and the two nds streams use the same heap, which 6795772Sas200622 * should already exist at this point. The heap will also be available 6805772Sas200622 * to the stub. 6815772Sas200622 */ 6825772Sas200622 int 683*8334SJose.Borrego@Sun.COM ndr_generic_call_stub(ndr_xa_t *mxa) 6845772Sas200622 { 685*8334SJose.Borrego@Sun.COM ndr_binding_t *mbind = mxa->binding; 686*8334SJose.Borrego@Sun.COM ndr_service_t *msvc = mbind->service; 687*8334SJose.Borrego@Sun.COM ndr_typeinfo_t *intf_ti = msvc->interface_ti; 688*8334SJose.Borrego@Sun.COM ndr_stub_table_t *ste; 6895772Sas200622 int opnum = mxa->opnum; 6905772Sas200622 unsigned p_len = intf_ti->c_size_fixed_part; 6915772Sas200622 char *param; 6925772Sas200622 int rc; 6935772Sas200622 6945772Sas200622 if (mxa->heap == NULL) { 695*8334SJose.Borrego@Sun.COM ndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum); 696*8334SJose.Borrego@Sun.COM return (NDR_DRC_FAULT_OUT_OF_MEMORY); 6975772Sas200622 } 6985772Sas200622 699*8334SJose.Borrego@Sun.COM if ((ste = ndr_svc_find_stub(msvc, opnum)) == NULL) { 700*8334SJose.Borrego@Sun.COM ndo_printf(0, 0, "%s[0x%02x]: invalid opnum", 7015772Sas200622 msvc->name, opnum); 702*8334SJose.Borrego@Sun.COM return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID); 7035772Sas200622 } 7045772Sas200622 705*8334SJose.Borrego@Sun.COM if ((param = ndr_heap_malloc(mxa->heap, p_len)) == NULL) 706*8334SJose.Borrego@Sun.COM return (NDR_DRC_FAULT_OUT_OF_MEMORY); 7075772Sas200622 7085772Sas200622 bzero(param, p_len); 7095772Sas200622 710*8334SJose.Borrego@Sun.COM rc = ndr_decode_call(mxa, param); 711*8334SJose.Borrego@Sun.COM if (!NDR_DRC_IS_OK(rc)) 7125772Sas200622 return (rc); 7135772Sas200622 7145772Sas200622 rc = (*ste->func)(param, mxa); 715*8334SJose.Borrego@Sun.COM if (rc == NDR_DRC_OK) 716*8334SJose.Borrego@Sun.COM rc = ndr_encode_return(mxa, param); 7175772Sas200622 7185772Sas200622 return (rc); 7195772Sas200622 } 7205772Sas200622 7215772Sas200622 /* 7225772Sas200622 * We can perform some initial setup of the response header here. 7235772Sas200622 * We also need to cache some of the information from the bind 7245772Sas200622 * negotiation for use during subsequent RPC calls. 7255772Sas200622 */ 7265772Sas200622 static void 727*8334SJose.Borrego@Sun.COM ndr_reply_prepare_hdr(ndr_xa_t *mxa) 7285772Sas200622 { 7297619SJose.Borrego@Sun.COM ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr; 7307619SJose.Borrego@Sun.COM ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 7315772Sas200622 7325772Sas200622 hdr->rpc_vers = 5; 7335772Sas200622 hdr->rpc_vers_minor = 0; 734*8334SJose.Borrego@Sun.COM hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG; 7355772Sas200622 hdr->packed_drep = rhdr->packed_drep; 7365772Sas200622 hdr->frag_length = 0; 7375772Sas200622 hdr->auth_length = 0; 7385772Sas200622 hdr->call_id = rhdr->call_id; 7395772Sas200622 #ifdef _BIG_ENDIAN 740*8334SJose.Borrego@Sun.COM hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII 741*8334SJose.Borrego@Sun.COM | NDR_REPLAB_INTG_BIG_ENDIAN; 7425772Sas200622 #else 743*8334SJose.Borrego@Sun.COM hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII 744*8334SJose.Borrego@Sun.COM | NDR_REPLAB_INTG_LITTLE_ENDIAN; 7455772Sas200622 #endif 7465772Sas200622 7475772Sas200622 switch (mxa->ptype) { 748*8334SJose.Borrego@Sun.COM case NDR_PTYPE_BIND: 749*8334SJose.Borrego@Sun.COM hdr->ptype = NDR_PTYPE_BIND_ACK; 7505772Sas200622 mxa->send_hdr.bind_ack_hdr.max_xmit_frag = 7515772Sas200622 mxa->recv_hdr.bind_hdr.max_xmit_frag; 7525772Sas200622 mxa->send_hdr.bind_ack_hdr.max_recv_frag = 7535772Sas200622 mxa->recv_hdr.bind_hdr.max_recv_frag; 7545772Sas200622 mxa->send_hdr.bind_ack_hdr.assoc_group_id = 7555772Sas200622 mxa->recv_hdr.bind_hdr.assoc_group_id; 7565772Sas200622 7575772Sas200622 if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0) 7585772Sas200622 mxa->send_hdr.bind_ack_hdr.assoc_group_id = time(0); 7595772Sas200622 7605772Sas200622 /* 7615772Sas200622 * Save the maximum fragment sizes 7625772Sas200622 * for use with subsequent requests. 7635772Sas200622 */ 764*8334SJose.Borrego@Sun.COM mxa->pipe->np_max_xmit_frag = 7655772Sas200622 mxa->recv_hdr.bind_hdr.max_xmit_frag; 766*8334SJose.Borrego@Sun.COM mxa->pipe->np_max_recv_frag = 7675772Sas200622 mxa->recv_hdr.bind_hdr.max_recv_frag; 7685772Sas200622 break; 7695772Sas200622 770*8334SJose.Borrego@Sun.COM case NDR_PTYPE_REQUEST: 771*8334SJose.Borrego@Sun.COM hdr->ptype = NDR_PTYPE_RESPONSE; 7725772Sas200622 /* mxa->send_hdr.response_hdr.alloc_hint */ 7735772Sas200622 mxa->send_hdr.response_hdr.p_cont_id = 7745772Sas200622 mxa->recv_hdr.request_hdr.p_cont_id; 7755772Sas200622 mxa->send_hdr.response_hdr.cancel_count = 0; 7765772Sas200622 mxa->send_hdr.response_hdr.reserved = 0; 7775772Sas200622 break; 7785772Sas200622 779*8334SJose.Borrego@Sun.COM case NDR_PTYPE_ALTER_CONTEXT: 780*8334SJose.Borrego@Sun.COM hdr->ptype = NDR_PTYPE_ALTER_CONTEXT_RESP; 7815772Sas200622 /* 7827619SJose.Borrego@Sun.COM * The max_xmit_frag, max_recv_frag and assoc_group_id are 7837619SJose.Borrego@Sun.COM * ignored by the client but it's useful to fill them in. 7845772Sas200622 */ 7857619SJose.Borrego@Sun.COM mxa->send_hdr.alter_context_rsp_hdr.max_xmit_frag = 7867619SJose.Borrego@Sun.COM mxa->recv_hdr.alter_context_hdr.max_xmit_frag; 7877619SJose.Borrego@Sun.COM mxa->send_hdr.alter_context_rsp_hdr.max_recv_frag = 7887619SJose.Borrego@Sun.COM mxa->recv_hdr.alter_context_hdr.max_recv_frag; 7897619SJose.Borrego@Sun.COM mxa->send_hdr.alter_context_rsp_hdr.assoc_group_id = 7907619SJose.Borrego@Sun.COM mxa->recv_hdr.alter_context_hdr.assoc_group_id; 7915772Sas200622 break; 7925772Sas200622 7935772Sas200622 default: 7945772Sas200622 hdr->ptype = 0xFF; 7955772Sas200622 } 7965772Sas200622 } 7975772Sas200622 7985772Sas200622 /* 7995772Sas200622 * Signal an RPC fault. The stream is reset and we overwrite whatever 8005772Sas200622 * was in the response header with the fault information. 8015772Sas200622 */ 8025772Sas200622 static void 803*8334SJose.Borrego@Sun.COM ndr_reply_fault(ndr_xa_t *mxa, unsigned long drc) 8045772Sas200622 { 8057619SJose.Borrego@Sun.COM ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr; 8067619SJose.Borrego@Sun.COM ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 807*8334SJose.Borrego@Sun.COM ndr_stream_t *nds = &mxa->send_nds; 8085772Sas200622 unsigned long fault_status; 8095772Sas200622 810*8334SJose.Borrego@Sun.COM NDS_RESET(nds); 8115772Sas200622 8125772Sas200622 hdr->rpc_vers = 5; 8135772Sas200622 hdr->rpc_vers_minor = 0; 814*8334SJose.Borrego@Sun.COM hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG; 8155772Sas200622 hdr->packed_drep = rhdr->packed_drep; 8165772Sas200622 hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr); 8175772Sas200622 hdr->auth_length = 0; 8185772Sas200622 hdr->call_id = rhdr->call_id; 8195772Sas200622 #ifdef _BIG_ENDIAN 820*8334SJose.Borrego@Sun.COM hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII 821*8334SJose.Borrego@Sun.COM | NDR_REPLAB_INTG_BIG_ENDIAN; 8225772Sas200622 #else 823*8334SJose.Borrego@Sun.COM hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII 824*8334SJose.Borrego@Sun.COM | NDR_REPLAB_INTG_LITTLE_ENDIAN; 8255772Sas200622 #endif 8265772Sas200622 827*8334SJose.Borrego@Sun.COM switch (drc & NDR_DRC_MASK_SPECIFIER) { 828*8334SJose.Borrego@Sun.COM case NDR_DRC_FAULT_OUT_OF_MEMORY: 829*8334SJose.Borrego@Sun.COM case NDR_DRC_FAULT_ENCODE_TOO_BIG: 830*8334SJose.Borrego@Sun.COM fault_status = NDR_FAULT_NCA_OUT_ARGS_TOO_BIG; 8315772Sas200622 break; 8325772Sas200622 833*8334SJose.Borrego@Sun.COM case NDR_DRC_FAULT_REQUEST_PCONT_INVALID: 834*8334SJose.Borrego@Sun.COM fault_status = NDR_FAULT_NCA_INVALID_PRES_CONTEXT_ID; 8355772Sas200622 break; 8365772Sas200622 837*8334SJose.Borrego@Sun.COM case NDR_DRC_FAULT_REQUEST_OPNUM_INVALID: 838*8334SJose.Borrego@Sun.COM fault_status = NDR_FAULT_NCA_OP_RNG_ERROR; 8395772Sas200622 break; 8405772Sas200622 841*8334SJose.Borrego@Sun.COM case NDR_DRC_FAULT_DECODE_FAILED: 842*8334SJose.Borrego@Sun.COM case NDR_DRC_FAULT_ENCODE_FAILED: 843*8334SJose.Borrego@Sun.COM fault_status = NDR_FAULT_NCA_PROTO_ERROR; 8445772Sas200622 break; 8455772Sas200622 8465772Sas200622 default: 847*8334SJose.Borrego@Sun.COM fault_status = NDR_FAULT_NCA_UNSPEC_REJECT; 8485772Sas200622 break; 8495772Sas200622 } 8505772Sas200622 851*8334SJose.Borrego@Sun.COM mxa->send_hdr.fault_hdr.common_hdr.ptype = NDR_PTYPE_FAULT; 8525772Sas200622 mxa->send_hdr.fault_hdr.status = fault_status; 8535772Sas200622 mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length; 8545772Sas200622 } 8555772Sas200622 8567619SJose.Borrego@Sun.COM /* 8577619SJose.Borrego@Sun.COM * Note that the frag_length for bind ack and alter context is 8587619SJose.Borrego@Sun.COM * non-standard. 8597619SJose.Borrego@Sun.COM */ 8605772Sas200622 static int 861*8334SJose.Borrego@Sun.COM ndr_build_reply(ndr_xa_t *mxa) 8625772Sas200622 { 8637619SJose.Borrego@Sun.COM ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 864*8334SJose.Borrego@Sun.COM ndr_stream_t *nds = &mxa->send_nds; 8656482Samw uint8_t *pdu_buf; 8665772Sas200622 unsigned long pdu_size; 8675772Sas200622 unsigned long frag_size; 8685772Sas200622 unsigned long pdu_data_size; 8695772Sas200622 unsigned long frag_data_size; 8705772Sas200622 871*8334SJose.Borrego@Sun.COM frag_size = NDR_FRAG_SZ; 872*8334SJose.Borrego@Sun.COM pdu_size = nds->pdu_size; 873*8334SJose.Borrego@Sun.COM pdu_buf = nds->pdu_base_addr; 8745772Sas200622 8755772Sas200622 if (pdu_size <= frag_size) { 8765772Sas200622 /* 8775772Sas200622 * Single fragment response. The PDU size may be zero 8785772Sas200622 * here (i.e. bind or fault response). So don't make 8795772Sas200622 * any assumptions about it until after the header is 8805772Sas200622 * encoded. 8815772Sas200622 */ 8825772Sas200622 switch (hdr->ptype) { 883*8334SJose.Borrego@Sun.COM case NDR_PTYPE_BIND_ACK: 884*8334SJose.Borrego@Sun.COM hdr->frag_length = ndr_bind_ack_hdr_size(mxa); 8855772Sas200622 break; 8865772Sas200622 887*8334SJose.Borrego@Sun.COM case NDR_PTYPE_FAULT: 8885772Sas200622 /* already setup */ 8895772Sas200622 break; 8905772Sas200622 891*8334SJose.Borrego@Sun.COM case NDR_PTYPE_RESPONSE: 8925772Sas200622 hdr->frag_length = pdu_size; 8935772Sas200622 mxa->send_hdr.response_hdr.alloc_hint = 8945772Sas200622 hdr->frag_length; 8955772Sas200622 break; 8965772Sas200622 897*8334SJose.Borrego@Sun.COM case NDR_PTYPE_ALTER_CONTEXT_RESP: 898*8334SJose.Borrego@Sun.COM hdr->frag_length = ndr_alter_context_rsp_hdr_size(); 8997619SJose.Borrego@Sun.COM break; 9007619SJose.Borrego@Sun.COM 9015772Sas200622 default: 9025772Sas200622 hdr->frag_length = pdu_size; 9035772Sas200622 break; 9045772Sas200622 } 9055772Sas200622 906*8334SJose.Borrego@Sun.COM nds->pdu_scan_offset = 0; 907*8334SJose.Borrego@Sun.COM (void) ndr_encode_pdu_hdr(mxa); 908*8334SJose.Borrego@Sun.COM pdu_size = nds->pdu_size; 909*8334SJose.Borrego@Sun.COM ndr_build_frag(nds, pdu_buf, pdu_size); 9105772Sas200622 return (0); 9115772Sas200622 } 9125772Sas200622 9135772Sas200622 /* 9145772Sas200622 * Multiple fragment response. 9155772Sas200622 */ 916*8334SJose.Borrego@Sun.COM hdr->pfc_flags = NDR_PFC_FIRST_FRAG; 9175772Sas200622 hdr->frag_length = frag_size; 918*8334SJose.Borrego@Sun.COM mxa->send_hdr.response_hdr.alloc_hint = pdu_size - NDR_RSP_HDR_SIZE; 919*8334SJose.Borrego@Sun.COM nds->pdu_scan_offset = 0; 920*8334SJose.Borrego@Sun.COM (void) ndr_encode_pdu_hdr(mxa); 921*8334SJose.Borrego@Sun.COM ndr_build_frag(nds, pdu_buf, frag_size); 9225772Sas200622 9235772Sas200622 /* 9245772Sas200622 * We need to update the 24-byte header in subsequent fragments. 9255772Sas200622 * 9266482Samw * pdu_data_size: total data remaining to be handled 9276482Samw * frag_size: total fragment size including header 9286482Samw * frag_data_size: data in fragment 929*8334SJose.Borrego@Sun.COM * (i.e. frag_size - NDR_RSP_HDR_SIZE) 9305772Sas200622 */ 931*8334SJose.Borrego@Sun.COM pdu_data_size = pdu_size - NDR_RSP_HDR_SIZE; 932*8334SJose.Borrego@Sun.COM frag_data_size = frag_size - NDR_RSP_HDR_SIZE; 9335772Sas200622 9346482Samw while (pdu_data_size) { 9356482Samw mxa->send_hdr.response_hdr.alloc_hint -= frag_data_size; 9366482Samw pdu_data_size -= frag_data_size; 9376482Samw pdu_buf += frag_data_size; 9385772Sas200622 9396482Samw if (pdu_data_size <= frag_data_size) { 9406482Samw frag_data_size = pdu_data_size; 941*8334SJose.Borrego@Sun.COM frag_size = frag_data_size + NDR_RSP_HDR_SIZE; 942*8334SJose.Borrego@Sun.COM hdr->pfc_flags = NDR_PFC_LAST_FRAG; 9435772Sas200622 } else { 9446482Samw hdr->pfc_flags = 0; 9455772Sas200622 } 9465772Sas200622 9476482Samw hdr->frag_length = frag_size; 948*8334SJose.Borrego@Sun.COM nds->pdu_scan_offset = 0; 949*8334SJose.Borrego@Sun.COM (void) ndr_encode_pdu_hdr(mxa); 950*8334SJose.Borrego@Sun.COM bcopy(nds->pdu_base_addr, pdu_buf, NDR_RSP_HDR_SIZE); 9515772Sas200622 952*8334SJose.Borrego@Sun.COM ndr_build_frag(nds, pdu_buf, frag_size); 9535772Sas200622 954*8334SJose.Borrego@Sun.COM if (hdr->pfc_flags & NDR_PFC_LAST_FRAG) 9556482Samw break; 9565772Sas200622 } 9575772Sas200622 9585772Sas200622 return (0); 9595772Sas200622 } 9606482Samw 9616482Samw /* 962*8334SJose.Borrego@Sun.COM * ndr_build_frag 9636482Samw * 9646482Samw * Build an RPC PDU fragment from the specified buffer. 9656482Samw * If malloc fails, the client will see a header/pdu inconsistency 9666482Samw * and report an error. 9676482Samw */ 9686482Samw static void 969*8334SJose.Borrego@Sun.COM ndr_build_frag(ndr_stream_t *nds, uint8_t *buf, uint32_t len) 9706482Samw { 9716482Samw ndr_frag_t *frag; 9726482Samw int size = sizeof (ndr_frag_t) + len; 9736482Samw 9746482Samw if ((frag = (ndr_frag_t *)malloc(size)) == NULL) 9756482Samw return; 9766482Samw 9776482Samw frag->next = NULL; 9786482Samw frag->buf = (uint8_t *)frag + sizeof (ndr_frag_t); 9796482Samw frag->len = len; 9806482Samw bcopy(buf, frag->buf, len); 9816482Samw 982*8334SJose.Borrego@Sun.COM if (nds->frags.head == NULL) { 983*8334SJose.Borrego@Sun.COM nds->frags.head = frag; 984*8334SJose.Borrego@Sun.COM nds->frags.tail = frag; 985*8334SJose.Borrego@Sun.COM nds->frags.nfrag = 1; 9866482Samw } else { 987*8334SJose.Borrego@Sun.COM nds->frags.tail->next = frag; 988*8334SJose.Borrego@Sun.COM nds->frags.tail = frag; 989*8334SJose.Borrego@Sun.COM ++nds->frags.nfrag; 9906482Samw } 9916482Samw } 992