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 #pragma ident "%Z%%M% %I% %E% SMI" 275772Sas200622 285772Sas200622 /* 295772Sas200622 * Server side RPC handler. 305772Sas200622 */ 315772Sas200622 325772Sas200622 #include <sys/byteorder.h> 33*7052Samw #include <sys/errno.h> 34*7052Samw #include <sys/uio.h> 355772Sas200622 #include <thread.h> 365772Sas200622 #include <synch.h> 375772Sas200622 #include <stdlib.h> 385772Sas200622 #include <strings.h> 395772Sas200622 #include <string.h> 405772Sas200622 #include <time.h> 415772Sas200622 425772Sas200622 #include <smbsrv/libsmb.h> 435772Sas200622 #include <smbsrv/libmlrpc.h> 445772Sas200622 #include <smbsrv/mlsvc.h> 455772Sas200622 #include <smbsrv/ndr.h> 465772Sas200622 #include <smbsrv/mlrpc.h> 475772Sas200622 #include <smbsrv/mlsvc_util.h> 48*7052Samw 49*7052Samw 50*7052Samw #define SMB_CTXT_BUFSZ 65536 515772Sas200622 525772Sas200622 /* 535772Sas200622 * Fragment size (5680: NT style). 545772Sas200622 */ 555772Sas200622 #define MLRPC_FRAG_SZ 5680 565772Sas200622 static unsigned long mlrpc_frag_size = MLRPC_FRAG_SZ; 575772Sas200622 585772Sas200622 /* 59*7052Samw * Service context table. 605772Sas200622 */ 615772Sas200622 #define CTXT_TABLE_ENTRIES 128 625772Sas200622 static struct mlsvc_rpc_context context_table[CTXT_TABLE_ENTRIES]; 635772Sas200622 static mutex_t mlrpc_context_lock; 645772Sas200622 65*7052Samw static int ndr_s_transact(struct mlsvc_rpc_context *); 66*7052Samw static struct mlsvc_rpc_context *ndr_s_lookup(int); 67*7052Samw static void ndr_s_release(struct mlsvc_rpc_context *); 68*7052Samw static struct mlsvc_rpc_context *ndr_s_allocate(int); 69*7052Samw static void ndr_s_deallocate(struct mlsvc_rpc_context *); 70*7052Samw static void ndr_s_rewind(struct mlsvc_rpc_context *); 71*7052Samw static void ndr_s_flush(struct mlsvc_rpc_context *); 72*7052Samw 735772Sas200622 static int mlrpc_s_process(struct mlrpc_xaction *); 745772Sas200622 static int mlrpc_s_bind(struct mlrpc_xaction *); 755772Sas200622 static int mlrpc_s_request(struct mlrpc_xaction *); 765772Sas200622 static void mlrpc_reply_prepare_hdr(struct mlrpc_xaction *); 775772Sas200622 static int mlrpc_s_alter_context(struct mlrpc_xaction *); 785772Sas200622 static void mlrpc_reply_bind_ack(struct mlrpc_xaction *); 795772Sas200622 static void mlrpc_reply_fault(struct mlrpc_xaction *, unsigned long); 805772Sas200622 static int mlrpc_build_reply(struct mlrpc_xaction *); 816482Samw static void mlrpc_build_frag(struct mlndr_stream *, uint8_t *, uint32_t); 825772Sas200622 835772Sas200622 /* 84*7052Samw * Allocate and associate a service context with a fid. 85*7052Samw */ 86*7052Samw int 87*7052Samw ndr_s_open(int fid, uint8_t *data, uint32_t datalen) 88*7052Samw { 89*7052Samw struct mlsvc_rpc_context *svc; 90*7052Samw 91*7052Samw (void) mutex_lock(&mlrpc_context_lock); 92*7052Samw 93*7052Samw if ((svc = ndr_s_lookup(fid)) != NULL) { 94*7052Samw ndr_s_release(svc); 95*7052Samw (void) mutex_unlock(&mlrpc_context_lock); 96*7052Samw return (EEXIST); 97*7052Samw } 98*7052Samw 99*7052Samw if ((svc = ndr_s_allocate(fid)) == NULL) { 100*7052Samw (void) mutex_unlock(&mlrpc_context_lock); 101*7052Samw return (ENOMEM); 102*7052Samw } 103*7052Samw 104*7052Samw if (smb_opipe_context_decode(&svc->svc_ctx, data, datalen) == -1) { 105*7052Samw ndr_s_release(svc); 106*7052Samw (void) mutex_unlock(&mlrpc_context_lock); 107*7052Samw return (EINVAL); 108*7052Samw } 109*7052Samw 110*7052Samw mlrpc_binding_pool_initialize(&svc->binding, svc->binding_pool, 111*7052Samw CTXT_N_BINDING_POOL); 112*7052Samw 113*7052Samw (void) mutex_unlock(&mlrpc_context_lock); 114*7052Samw return (0); 115*7052Samw } 116*7052Samw 117*7052Samw /* 118*7052Samw * Release the context associated with a fid when an opipe is closed. 119*7052Samw */ 120*7052Samw int 121*7052Samw ndr_s_close(int fid) 122*7052Samw { 123*7052Samw struct mlsvc_rpc_context *svc; 124*7052Samw 125*7052Samw (void) mutex_lock(&mlrpc_context_lock); 126*7052Samw 127*7052Samw if ((svc = ndr_s_lookup(fid)) == NULL) { 128*7052Samw (void) mutex_unlock(&mlrpc_context_lock); 129*7052Samw return (ENOENT); 130*7052Samw } 131*7052Samw 132*7052Samw /* 133*7052Samw * Release twice: once for the lookup above 134*7052Samw * and again to close the fid. 135*7052Samw */ 136*7052Samw ndr_s_release(svc); 137*7052Samw ndr_s_release(svc); 138*7052Samw (void) mutex_unlock(&mlrpc_context_lock); 139*7052Samw return (0); 140*7052Samw } 141*7052Samw 142*7052Samw /* 143*7052Samw * Write RPC request data to the input stream. Input data is buffered 144*7052Samw * until the response is requested. 1455772Sas200622 */ 146*7052Samw int 147*7052Samw ndr_s_write(int fid, uint8_t *buf, uint32_t len) 148*7052Samw { 149*7052Samw struct mlsvc_rpc_context *svc; 150*7052Samw ssize_t nbytes; 151*7052Samw 152*7052Samw if (len == 0) 153*7052Samw return (0); 154*7052Samw 155*7052Samw (void) mutex_lock(&mlrpc_context_lock); 156*7052Samw 157*7052Samw if ((svc = ndr_s_lookup(fid)) == NULL) { 158*7052Samw (void) mutex_unlock(&mlrpc_context_lock); 159*7052Samw return (ENOENT); 160*7052Samw } 161*7052Samw 162*7052Samw nbytes = ndr_uiomove((caddr_t)buf, len, UIO_READ, &svc->in_uio); 163*7052Samw 164*7052Samw ndr_s_release(svc); 165*7052Samw (void) mutex_unlock(&mlrpc_context_lock); 166*7052Samw return ((nbytes == len) ? 0 : EIO); 167*7052Samw } 168*7052Samw 169*7052Samw /* 170*7052Samw * Read RPC response data. If the input stream contains an RPC request, 171*7052Samw * we need to process the RPC transaction, which will place the RPC 172*7052Samw * response in the output (frags) stream. Otherwise, read data from 173*7052Samw * the output stream. 174*7052Samw */ 175*7052Samw int 176*7052Samw ndr_s_read(int fid, uint8_t *buf, uint32_t *len, uint32_t *resid) 1775772Sas200622 { 178*7052Samw struct mlsvc_rpc_context *svc; 179*7052Samw ssize_t nbytes = *len; 180*7052Samw int rc; 181*7052Samw 182*7052Samw if (nbytes == 0) { 183*7052Samw *resid = 0; 184*7052Samw return (0); 185*7052Samw } 186*7052Samw 187*7052Samw (void) mutex_lock(&mlrpc_context_lock); 188*7052Samw if ((svc = ndr_s_lookup(fid)) == NULL) { 189*7052Samw (void) mutex_unlock(&mlrpc_context_lock); 190*7052Samw return (ENOENT); 191*7052Samw } 192*7052Samw (void) mutex_unlock(&mlrpc_context_lock); 193*7052Samw 194*7052Samw if (svc->in_uio.uio_offset) { 195*7052Samw if ((rc = ndr_s_transact(svc)) != 0) { 196*7052Samw ndr_s_flush(svc); 197*7052Samw (void) mutex_lock(&mlrpc_context_lock); 198*7052Samw ndr_s_release(svc); 199*7052Samw (void) mutex_unlock(&mlrpc_context_lock); 200*7052Samw return (rc); 201*7052Samw } 202*7052Samw 203*7052Samw } 204*7052Samw 205*7052Samw *len = ndr_uiomove((caddr_t)buf, nbytes, UIO_WRITE, &svc->frags.uio); 206*7052Samw *resid = svc->frags.uio.uio_resid; 207*7052Samw 208*7052Samw if (*resid == 0) { 209*7052Samw /* 210*7052Samw * Nothing left, cleanup the output stream. 211*7052Samw */ 212*7052Samw ndr_s_flush(svc); 213*7052Samw } 214*7052Samw 215*7052Samw (void) mutex_lock(&mlrpc_context_lock); 216*7052Samw ndr_s_release(svc); 217*7052Samw (void) mutex_unlock(&mlrpc_context_lock); 218*7052Samw return (0); 219*7052Samw } 220*7052Samw 221*7052Samw /* 222*7052Samw * Process a server-side RPC request. 223*7052Samw */ 224*7052Samw static int 225*7052Samw ndr_s_transact(struct mlsvc_rpc_context *svc) 226*7052Samw { 227*7052Samw ndr_xa_t *mxa; 2285772Sas200622 struct mlndr_stream *recv_mlnds; 2295772Sas200622 struct mlndr_stream *send_mlnds; 2305772Sas200622 char *data; 2315772Sas200622 int datalen; 2325772Sas200622 233*7052Samw data = svc->in_buf; 234*7052Samw datalen = svc->in_uio.uio_offset; 2355772Sas200622 236*7052Samw if ((mxa = (ndr_xa_t *)malloc(sizeof (ndr_xa_t))) == NULL) 237*7052Samw return (ENOMEM); 2385772Sas200622 2395772Sas200622 bzero(mxa, sizeof (struct mlrpc_xaction)); 240*7052Samw mxa->fid = svc->fid; 241*7052Samw mxa->context = svc; 242*7052Samw mxa->binding_list = svc->binding; 2435772Sas200622 2445772Sas200622 if ((mxa->heap = mlrpc_heap_create()) == NULL) { 2455772Sas200622 free(mxa); 246*7052Samw return (ENOMEM); 2475772Sas200622 } 2485772Sas200622 2495772Sas200622 recv_mlnds = &mxa->recv_mlnds; 250*7052Samw mlnds_initialize(recv_mlnds, datalen, NDR_MODE_CALL_RECV, mxa->heap); 2515772Sas200622 252*7052Samw /* 253*7052Samw * Copy the input data and reset the input stream. 254*7052Samw */ 2555772Sas200622 bcopy(data, recv_mlnds->pdu_base_addr, datalen); 256*7052Samw ndr_s_rewind(svc); 2575772Sas200622 2585772Sas200622 send_mlnds = &mxa->send_mlnds; 259*7052Samw mlnds_initialize(send_mlnds, 0, NDR_MODE_RETURN_SEND, mxa->heap); 2605772Sas200622 2615772Sas200622 (void) mlrpc_s_process(mxa); 2625772Sas200622 263*7052Samw mlnds_finalize(send_mlnds, &svc->frags); 2645772Sas200622 mlnds_destruct(&mxa->recv_mlnds); 2655772Sas200622 mlnds_destruct(&mxa->send_mlnds); 2665772Sas200622 mlrpc_heap_destroy(mxa->heap); 2675772Sas200622 free(mxa); 268*7052Samw return (0); 269*7052Samw } 270*7052Samw 271*7052Samw /* 272*7052Samw * Must be called with mlrpc_context_lock held. 273*7052Samw */ 274*7052Samw static struct mlsvc_rpc_context * 275*7052Samw ndr_s_lookup(int fid) 276*7052Samw { 277*7052Samw struct mlsvc_rpc_context *svc; 278*7052Samw int i; 279*7052Samw 280*7052Samw for (i = 0; i < CTXT_TABLE_ENTRIES; ++i) { 281*7052Samw svc = &context_table[i]; 282*7052Samw 283*7052Samw if (svc->fid == fid) { 284*7052Samw if (svc->refcnt == 0) 285*7052Samw return (NULL); 286*7052Samw 287*7052Samw svc->refcnt++; 288*7052Samw return (svc); 289*7052Samw } 290*7052Samw } 291*7052Samw 292*7052Samw return (NULL); 2935772Sas200622 } 2945772Sas200622 2955772Sas200622 /* 296*7052Samw * Must be called with mlrpc_context_lock held. 2975772Sas200622 */ 298*7052Samw static void 299*7052Samw ndr_s_release(struct mlsvc_rpc_context *svc) 3005772Sas200622 { 301*7052Samw svc->refcnt--; 302*7052Samw ndr_s_deallocate(svc); 303*7052Samw } 304*7052Samw 305*7052Samw /* 306*7052Samw * Must be called with mlrpc_context_lock held. 307*7052Samw */ 308*7052Samw static struct mlsvc_rpc_context * 309*7052Samw ndr_s_allocate(int fid) 310*7052Samw { 311*7052Samw struct mlsvc_rpc_context *svc = NULL; 3125772Sas200622 int i; 3135772Sas200622 314*7052Samw for (i = 0; i < CTXT_TABLE_ENTRIES; ++i) { 315*7052Samw svc = &context_table[i]; 3165772Sas200622 317*7052Samw if (svc->fid == 0) { 318*7052Samw bzero(svc, sizeof (struct mlsvc_rpc_context)); 3195772Sas200622 320*7052Samw if ((svc->in_buf = malloc(SMB_CTXT_BUFSZ)) == NULL) 321*7052Samw return (NULL); 3225772Sas200622 323*7052Samw ndr_s_rewind(svc); 324*7052Samw svc->fid = fid; 325*7052Samw svc->refcnt = 1; 326*7052Samw return (svc); 3275772Sas200622 } 3285772Sas200622 } 3295772Sas200622 330*7052Samw return (NULL); 331*7052Samw } 3325772Sas200622 333*7052Samw /* 334*7052Samw * Must be called with mlrpc_context_lock held. 335*7052Samw */ 336*7052Samw static void 337*7052Samw ndr_s_deallocate(struct mlsvc_rpc_context *svc) 338*7052Samw { 339*7052Samw if (svc->refcnt == 0) { 340*7052Samw /* 341*7052Samw * Ensure that there are no RPC service policy handles 342*7052Samw * (associated with this fid) left around. 343*7052Samw */ 344*7052Samw ndr_hdclose(svc->fid); 3455772Sas200622 346*7052Samw ndr_s_rewind(svc); 347*7052Samw ndr_s_flush(svc); 348*7052Samw free(svc->in_buf); 349*7052Samw free(svc->svc_ctx.oc_domain); 350*7052Samw free(svc->svc_ctx.oc_account); 351*7052Samw free(svc->svc_ctx.oc_workstation); 352*7052Samw bzero(svc, sizeof (struct mlsvc_rpc_context)); 353*7052Samw } 354*7052Samw } 3555772Sas200622 356*7052Samw /* 357*7052Samw * Rewind the input data stream, ready for the next write. 358*7052Samw */ 359*7052Samw static void 360*7052Samw ndr_s_rewind(struct mlsvc_rpc_context *svc) 361*7052Samw { 362*7052Samw svc->in_uio.uio_iov = &svc->in_iov; 363*7052Samw svc->in_uio.uio_iovcnt = 1; 364*7052Samw svc->in_uio.uio_offset = 0; 365*7052Samw svc->in_uio.uio_segflg = UIO_USERSPACE; 366*7052Samw svc->in_uio.uio_resid = SMB_CTXT_BUFSZ; 367*7052Samw svc->in_iov.iov_base = svc->in_buf; 368*7052Samw svc->in_iov.iov_len = SMB_CTXT_BUFSZ; 3695772Sas200622 } 3705772Sas200622 3715772Sas200622 /* 372*7052Samw * Flush the output data stream. 3735772Sas200622 */ 374*7052Samw static void 375*7052Samw ndr_s_flush(struct mlsvc_rpc_context *svc) 3765772Sas200622 { 377*7052Samw ndr_frag_t *frag; 3785772Sas200622 379*7052Samw while ((frag = svc->frags.head) != NULL) { 380*7052Samw svc->frags.head = frag->next; 381*7052Samw free(frag); 3825772Sas200622 } 3835772Sas200622 384*7052Samw free(svc->frags.iov); 385*7052Samw bzero(&svc->frags, sizeof (ndr_fraglist_t)); 386*7052Samw } 387*7052Samw 388*7052Samw /* 389*7052Samw * Check whether or not the specified user has administrator privileges, 390*7052Samw * i.e. is a member of Domain Admins or Administrators. 391*7052Samw * Returns true if the user is an administrator, otherwise returns false. 392*7052Samw */ 393*7052Samw boolean_t 394*7052Samw ndr_is_admin(ndr_xa_t *xa) 395*7052Samw { 396*7052Samw smb_opipe_context_t *svc = &xa->context->svc_ctx; 397*7052Samw 398*7052Samw return (svc->oc_flags & SMB_ATF_ADMIN); 399*7052Samw } 400*7052Samw 401*7052Samw /* 402*7052Samw * Check whether or not the specified user has power-user privileges, 403*7052Samw * i.e. is a member of Domain Admins, Administrators or Power Users. 404*7052Samw * This is typically required for operations such as managing shares. 405*7052Samw * Returns true if the user is a power user, otherwise returns false. 406*7052Samw */ 407*7052Samw boolean_t 408*7052Samw ndr_is_poweruser(ndr_xa_t *xa) 409*7052Samw { 410*7052Samw smb_opipe_context_t *svc = &xa->context->svc_ctx; 411*7052Samw 412*7052Samw return ((svc->oc_flags & SMB_ATF_ADMIN) || 413*7052Samw (svc->oc_flags & SMB_ATF_POWERUSER)); 414*7052Samw } 415*7052Samw 416*7052Samw int32_t 417*7052Samw ndr_native_os(ndr_xa_t *xa) 418*7052Samw { 419*7052Samw smb_opipe_context_t *svc = &xa->context->svc_ctx; 420*7052Samw 421*7052Samw return (svc->oc_native_os); 4225772Sas200622 } 4235772Sas200622 4245772Sas200622 /* 4255772Sas200622 * This is the entry point for all server-side RPC processing. 4265772Sas200622 * It is assumed that the PDU has already been received. 4275772Sas200622 */ 4285772Sas200622 static int 4295772Sas200622 mlrpc_s_process(struct mlrpc_xaction *mxa) 4305772Sas200622 { 4315772Sas200622 int rc; 4325772Sas200622 4335772Sas200622 rc = mlrpc_decode_pdu_hdr(mxa); 4345772Sas200622 if (!MLRPC_DRC_IS_OK(rc)) 4355772Sas200622 return (-1); 4365772Sas200622 4375772Sas200622 (void) mlrpc_reply_prepare_hdr(mxa); 4385772Sas200622 4395772Sas200622 switch (mxa->ptype) { 4405772Sas200622 case MLRPC_PTYPE_BIND: 4415772Sas200622 rc = mlrpc_s_bind(mxa); 4425772Sas200622 break; 4435772Sas200622 4445772Sas200622 case MLRPC_PTYPE_REQUEST: 4455772Sas200622 rc = mlrpc_s_request(mxa); 4465772Sas200622 break; 4475772Sas200622 4485772Sas200622 case MLRPC_PTYPE_ALTER_CONTEXT: 4495772Sas200622 rc = mlrpc_s_alter_context(mxa); 4505772Sas200622 break; 4515772Sas200622 4525772Sas200622 default: 4535772Sas200622 rc = MLRPC_DRC_FAULT_RPCHDR_PTYPE_INVALID; 4545772Sas200622 break; 4555772Sas200622 } 4565772Sas200622 4575772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 4585772Sas200622 mlrpc_reply_fault(mxa, rc); 4595772Sas200622 4605772Sas200622 (void) mlrpc_build_reply(mxa); 4615772Sas200622 return (rc); 4625772Sas200622 } 4635772Sas200622 4645772Sas200622 /* 4655772Sas200622 * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple 4665772Sas200622 * p_results[] not supported. 4675772Sas200622 */ 4685772Sas200622 static int 4695772Sas200622 mlrpc_s_bind(struct mlrpc_xaction *mxa) 4705772Sas200622 { 4715772Sas200622 mlrpc_p_cont_list_t *cont_list; 4725772Sas200622 mlrpc_p_result_list_t *result_list; 4735772Sas200622 mlrpc_p_result_t *result; 4745772Sas200622 unsigned p_cont_id; 4755772Sas200622 struct mlrpc_binding *mbind; 4765772Sas200622 ndr_uuid_t *as_uuid; 4775772Sas200622 ndr_uuid_t *ts_uuid; 4785772Sas200622 char as_buf[64]; 4795772Sas200622 char ts_buf[64]; 4805772Sas200622 int as_vers; 4815772Sas200622 int ts_vers; 4825772Sas200622 struct mlndr_stream *send_mlnds; 4835772Sas200622 struct mlrpc_service *msvc; 4845772Sas200622 int rc; 4855772Sas200622 mlrpc_port_any_t *sec_addr; 4865772Sas200622 4875772Sas200622 /* acquire targets */ 4885772Sas200622 cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem; 4895772Sas200622 result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list; 4905772Sas200622 result = &result_list->p_results[0]; 4915772Sas200622 4925772Sas200622 /* 4935772Sas200622 * Set up temporary secondary address port. 4945772Sas200622 * We will correct this later (below). 4955772Sas200622 */ 4965772Sas200622 send_mlnds = &mxa->send_mlnds; 4975772Sas200622 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 4985772Sas200622 sec_addr->length = 13; 4995772Sas200622 (void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs"); 5005772Sas200622 5015772Sas200622 result_list->n_results = 1; 5025772Sas200622 result_list->reserved = 0; 5035772Sas200622 result_list->reserved2 = 0; 5045772Sas200622 result->result = MLRPC_PCDR_ACCEPTANCE; 5055772Sas200622 result->reason = 0; 5065772Sas200622 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax)); 5075772Sas200622 5085772Sas200622 /* sanity check */ 5095772Sas200622 if (cont_list->n_context_elem != 1 || 5105772Sas200622 cont_list->p_cont_elem[0].n_transfer_syn != 1) { 5115772Sas200622 mlndo_trace("mlrpc_s_bind: warning: multiple p_cont_elem"); 5125772Sas200622 } 5135772Sas200622 5145772Sas200622 p_cont_id = cont_list->p_cont_elem[0].p_cont_id; 5155772Sas200622 5165772Sas200622 if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) != NULL) { 5175772Sas200622 /* 5185772Sas200622 * Duplicate p_cont_id. 5195772Sas200622 * Send a bind_ack with a better error. 5205772Sas200622 */ 5215772Sas200622 mlndo_trace("mlrpc_s_bind: duplicate binding"); 5225772Sas200622 return (MLRPC_DRC_FAULT_BIND_PCONT_BUSY); 5235772Sas200622 } 5245772Sas200622 5255772Sas200622 if ((mbind = mlrpc_new_binding(mxa)) == NULL) { 5265772Sas200622 /* 5275772Sas200622 * No free binding slot 5285772Sas200622 */ 5295772Sas200622 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 5305772Sas200622 result->reason = MLRPC_PPR_LOCAL_LIMIT_EXCEEDED; 5315772Sas200622 mlndo_trace("mlrpc_s_bind: no resources"); 5325772Sas200622 return (MLRPC_DRC_OK); 5335772Sas200622 } 5345772Sas200622 5355772Sas200622 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid; 5365772Sas200622 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version; 5375772Sas200622 5385772Sas200622 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid; 5395772Sas200622 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version; 5405772Sas200622 5415772Sas200622 msvc = mlrpc_find_service_by_uuids(as_uuid, as_vers, ts_uuid, ts_vers); 5425772Sas200622 if (!msvc) { 5435772Sas200622 mlrpc_uuid_to_str(as_uuid, as_buf); 5445772Sas200622 mlrpc_uuid_to_str(ts_uuid, ts_buf); 5455772Sas200622 5465772Sas200622 mlndo_printf(send_mlnds, 0, "mlrpc_s_bind: unknown service"); 5475772Sas200622 mlndo_printf(send_mlnds, 0, "abs=%s v%d, xfer=%s v%d", 5485772Sas200622 as_buf, as_vers, ts_buf, ts_vers); 5495772Sas200622 5505772Sas200622 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 5515772Sas200622 result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 5525772Sas200622 return (MLRPC_DRC_OK); 5535772Sas200622 } 5545772Sas200622 5555772Sas200622 /* 5565772Sas200622 * We can now use the correct secondary address port. 5575772Sas200622 */ 5585772Sas200622 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 5595772Sas200622 sec_addr->length = strlen(msvc->sec_addr_port) + 1; 5605772Sas200622 (void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port, 5615772Sas200622 MLRPC_PORT_ANY_MAX_PORT_SPEC); 5625772Sas200622 5635772Sas200622 mbind->p_cont_id = p_cont_id; 5645772Sas200622 mbind->which_side = MLRPC_BIND_SIDE_SERVER; 5655772Sas200622 /* mbind->context set by app */ 5665772Sas200622 mbind->service = msvc; 5675772Sas200622 mbind->instance_specific = 0; 5685772Sas200622 5695772Sas200622 mxa->binding = mbind; 5705772Sas200622 5715772Sas200622 if (msvc->bind_req) { 5725772Sas200622 /* 5735772Sas200622 * Call the service-specific bind() handler. If 5745772Sas200622 * this fails, we shouild send a specific error 5755772Sas200622 * on the bind ack. 5765772Sas200622 */ 5775772Sas200622 rc = (msvc->bind_req)(mxa); 5785772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) { 5795772Sas200622 mbind->service = 0; /* free binding slot */ 5805772Sas200622 mbind->which_side = 0; 5815772Sas200622 mbind->p_cont_id = 0; 5825772Sas200622 mbind->instance_specific = 0; 5835772Sas200622 return (rc); 5845772Sas200622 } 5855772Sas200622 } 5865772Sas200622 5875772Sas200622 result->transfer_syntax = 5885772Sas200622 cont_list->p_cont_elem[0].transfer_syntaxes[0]; 5895772Sas200622 5905772Sas200622 /* 5915772Sas200622 * Special rejection of Windows 2000 DSSETUP interface. 5925772Sas200622 * This interface was introduced in Windows 2000 but has 5935772Sas200622 * been subsequently deprecated due to problems. 5945772Sas200622 */ 5955772Sas200622 if (strcmp(msvc->name, "DSSETUP") == 0) { 5965772Sas200622 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 5975772Sas200622 result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 5985772Sas200622 } 5995772Sas200622 6005772Sas200622 return (MLRPC_DRC_BINDING_MADE); 6015772Sas200622 } 6025772Sas200622 6035772Sas200622 /* 6045772Sas200622 * mlrpc_s_alter_context 6055772Sas200622 * 6065772Sas200622 * The alter context request is used to request additional presentation 6075772Sas200622 * context for another interface and/or version. It's very similar to a 6085772Sas200622 * bind request. 6095772Sas200622 * 6105772Sas200622 * We don't fully support multiple contexts so, for now, we reject this 6115772Sas200622 * request. Windows 2000 clients attempt to use an alternate LSA context 6125772Sas200622 * when ACLs are modified. 6135772Sas200622 */ 6145772Sas200622 static int 6155772Sas200622 mlrpc_s_alter_context(struct mlrpc_xaction *mxa) 6165772Sas200622 { 6175772Sas200622 mlrpc_p_result_list_t *result_list; 6185772Sas200622 mlrpc_p_result_t *result; 6195772Sas200622 mlrpc_p_cont_list_t *cont_list; 6205772Sas200622 struct mlrpc_binding *mbind; 6215772Sas200622 struct mlrpc_service *msvc; 6225772Sas200622 unsigned p_cont_id; 6235772Sas200622 ndr_uuid_t *as_uuid; 6245772Sas200622 ndr_uuid_t *ts_uuid; 6255772Sas200622 int as_vers; 6265772Sas200622 int ts_vers; 6275772Sas200622 mlrpc_port_any_t *sec_addr; 6285772Sas200622 6295772Sas200622 result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list; 6305772Sas200622 result_list->n_results = 1; 6315772Sas200622 result_list->reserved = 0; 6325772Sas200622 result_list->reserved2 = 0; 6335772Sas200622 6345772Sas200622 result = &result_list->p_results[0]; 6355772Sas200622 result->result = MLRPC_PCDR_ACCEPTANCE; 6365772Sas200622 result->reason = 0; 6375772Sas200622 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax)); 6385772Sas200622 6395772Sas200622 if (mxa != NULL) { 6405772Sas200622 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 6415772Sas200622 result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 6425772Sas200622 return (MLRPC_DRC_OK); 6435772Sas200622 } 6445772Sas200622 6455772Sas200622 cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem; 6465772Sas200622 p_cont_id = cont_list->p_cont_elem[0].p_cont_id; 6475772Sas200622 6485772Sas200622 if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) != NULL) 6495772Sas200622 return (MLRPC_DRC_FAULT_BIND_PCONT_BUSY); 6505772Sas200622 6515772Sas200622 if ((mbind = mlrpc_new_binding(mxa)) == NULL) { 6525772Sas200622 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 6535772Sas200622 result->reason = MLRPC_PPR_LOCAL_LIMIT_EXCEEDED; 6545772Sas200622 return (MLRPC_DRC_OK); 6555772Sas200622 } 6565772Sas200622 6575772Sas200622 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid; 6585772Sas200622 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version; 6595772Sas200622 6605772Sas200622 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid; 6615772Sas200622 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version; 6625772Sas200622 6635772Sas200622 msvc = mlrpc_find_service_by_uuids(as_uuid, as_vers, ts_uuid, ts_vers); 6645772Sas200622 if (msvc == 0) { 6655772Sas200622 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 6665772Sas200622 result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 6675772Sas200622 return (MLRPC_DRC_OK); 6685772Sas200622 } 6695772Sas200622 6705772Sas200622 mbind->p_cont_id = p_cont_id; 6715772Sas200622 mbind->which_side = MLRPC_BIND_SIDE_SERVER; 6725772Sas200622 /* mbind->context set by app */ 6735772Sas200622 mbind->service = msvc; 6745772Sas200622 mbind->instance_specific = 0; 6755772Sas200622 mxa->binding = mbind; 6765772Sas200622 6775772Sas200622 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 6785772Sas200622 sec_addr->length = 0; 6795772Sas200622 bzero(sec_addr->port_spec, MLRPC_PORT_ANY_MAX_PORT_SPEC); 6805772Sas200622 6815772Sas200622 result->transfer_syntax = 6825772Sas200622 cont_list->p_cont_elem[0].transfer_syntaxes[0]; 6835772Sas200622 6845772Sas200622 return (MLRPC_DRC_BINDING_MADE); 6855772Sas200622 } 6865772Sas200622 6875772Sas200622 static int 6885772Sas200622 mlrpc_s_request(struct mlrpc_xaction *mxa) 6895772Sas200622 { 6905772Sas200622 struct mlrpc_binding *mbind; 6915772Sas200622 struct mlrpc_service *msvc; 6925772Sas200622 unsigned p_cont_id; 6935772Sas200622 int rc; 6945772Sas200622 6955772Sas200622 mxa->opnum = mxa->recv_hdr.request_hdr.opnum; 6965772Sas200622 p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id; 6975772Sas200622 6985772Sas200622 if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) == NULL) 6995772Sas200622 return (MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID); 7005772Sas200622 7015772Sas200622 mxa->binding = mbind; 7025772Sas200622 msvc = mbind->service; 7035772Sas200622 7045772Sas200622 /* 7055772Sas200622 * Make room for the response hdr. 7065772Sas200622 */ 7075772Sas200622 mxa->send_mlnds.pdu_scan_offset = MLRPC_RSP_HDR_SIZE; 7085772Sas200622 7095772Sas200622 if (msvc->call_stub) 7105772Sas200622 rc = (*msvc->call_stub)(mxa); 7115772Sas200622 else 7125772Sas200622 rc = mlrpc_generic_call_stub(mxa); 7135772Sas200622 7145772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) { 7155772Sas200622 mlndo_printf(0, 0, "%s[0x%02x]: 0x%04x", 7165772Sas200622 msvc->name, mxa->opnum, rc); 7175772Sas200622 } 7185772Sas200622 7195772Sas200622 return (rc); 7205772Sas200622 } 7215772Sas200622 7225772Sas200622 /* 7235772Sas200622 * The transaction and the two mlnds streams use the same heap, which 7245772Sas200622 * should already exist at this point. The heap will also be available 7255772Sas200622 * to the stub. 7265772Sas200622 */ 7275772Sas200622 int 7285772Sas200622 mlrpc_generic_call_stub(struct mlrpc_xaction *mxa) 7295772Sas200622 { 7305772Sas200622 struct mlrpc_binding *mbind = mxa->binding; 7315772Sas200622 struct mlrpc_service *msvc = mbind->service; 7325772Sas200622 struct ndr_typeinfo *intf_ti = msvc->interface_ti; 7335772Sas200622 struct mlrpc_stub_table *ste; 7345772Sas200622 int opnum = mxa->opnum; 7355772Sas200622 unsigned p_len = intf_ti->c_size_fixed_part; 7365772Sas200622 char *param; 7375772Sas200622 int rc; 7385772Sas200622 7395772Sas200622 if (mxa->heap == NULL) { 7405772Sas200622 mlndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum); 7415772Sas200622 return (MLRPC_DRC_FAULT_OUT_OF_MEMORY); 7425772Sas200622 } 7435772Sas200622 7445772Sas200622 if ((ste = mlrpc_find_stub_in_svc(msvc, opnum)) == NULL) { 7455772Sas200622 mlndo_printf(0, 0, "%s[0x%02x]: invalid opnum", 7465772Sas200622 msvc->name, opnum); 7475772Sas200622 return (MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID); 7485772Sas200622 } 7495772Sas200622 7505772Sas200622 if ((param = mlrpc_heap_malloc(mxa->heap, p_len)) == NULL) 7515772Sas200622 return (MLRPC_DRC_FAULT_OUT_OF_MEMORY); 7525772Sas200622 7535772Sas200622 bzero(param, p_len); 7545772Sas200622 7555772Sas200622 rc = mlrpc_decode_call(mxa, param); 7565772Sas200622 if (!MLRPC_DRC_IS_OK(rc)) 7575772Sas200622 return (rc); 7585772Sas200622 7595772Sas200622 rc = (*ste->func)(param, mxa); 7605772Sas200622 if (rc == MLRPC_DRC_OK) 7615772Sas200622 rc = mlrpc_encode_return(mxa, param); 7625772Sas200622 7635772Sas200622 return (rc); 7645772Sas200622 } 7655772Sas200622 7665772Sas200622 /* 7675772Sas200622 * We can perform some initial setup of the response header here. 7685772Sas200622 * We also need to cache some of the information from the bind 7695772Sas200622 * negotiation for use during subsequent RPC calls. 7705772Sas200622 */ 7715772Sas200622 static void 7725772Sas200622 mlrpc_reply_prepare_hdr(struct mlrpc_xaction *mxa) 7735772Sas200622 { 7745772Sas200622 mlrpcconn_common_header_t *rhdr = &mxa->recv_hdr.common_hdr; 7755772Sas200622 mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr; 7765772Sas200622 7775772Sas200622 hdr->rpc_vers = 5; 7785772Sas200622 hdr->rpc_vers_minor = 0; 7795772Sas200622 hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG; 7805772Sas200622 hdr->packed_drep = rhdr->packed_drep; 7815772Sas200622 hdr->frag_length = 0; 7825772Sas200622 hdr->auth_length = 0; 7835772Sas200622 hdr->call_id = rhdr->call_id; 7845772Sas200622 #ifdef _BIG_ENDIAN 7855772Sas200622 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII 7865772Sas200622 | MLRPC_REPLAB_INTG_BIG_ENDIAN; 7875772Sas200622 #else 7885772Sas200622 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII 7895772Sas200622 | MLRPC_REPLAB_INTG_LITTLE_ENDIAN; 7905772Sas200622 #endif 7915772Sas200622 7925772Sas200622 switch (mxa->ptype) { 7935772Sas200622 case MLRPC_PTYPE_BIND: 7945772Sas200622 hdr->ptype = MLRPC_PTYPE_BIND_ACK; 7955772Sas200622 mxa->send_hdr.bind_ack_hdr.max_xmit_frag = 7965772Sas200622 mxa->recv_hdr.bind_hdr.max_xmit_frag; 7975772Sas200622 mxa->send_hdr.bind_ack_hdr.max_recv_frag = 7985772Sas200622 mxa->recv_hdr.bind_hdr.max_recv_frag; 7995772Sas200622 mxa->send_hdr.bind_ack_hdr.assoc_group_id = 8005772Sas200622 mxa->recv_hdr.bind_hdr.assoc_group_id; 8015772Sas200622 8025772Sas200622 if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0) 8035772Sas200622 mxa->send_hdr.bind_ack_hdr.assoc_group_id = time(0); 8045772Sas200622 8055772Sas200622 /* 8065772Sas200622 * Save the maximum fragment sizes 8075772Sas200622 * for use with subsequent requests. 8085772Sas200622 */ 8095772Sas200622 mxa->context->max_xmit_frag = 8105772Sas200622 mxa->recv_hdr.bind_hdr.max_xmit_frag; 8115772Sas200622 8125772Sas200622 mxa->context->max_recv_frag = 8135772Sas200622 mxa->recv_hdr.bind_hdr.max_recv_frag; 8145772Sas200622 8155772Sas200622 break; 8165772Sas200622 8175772Sas200622 case MLRPC_PTYPE_REQUEST: 8185772Sas200622 hdr->ptype = MLRPC_PTYPE_RESPONSE; 8195772Sas200622 /* mxa->send_hdr.response_hdr.alloc_hint */ 8205772Sas200622 mxa->send_hdr.response_hdr.p_cont_id = 8215772Sas200622 mxa->recv_hdr.request_hdr.p_cont_id; 8225772Sas200622 mxa->send_hdr.response_hdr.cancel_count = 0; 8235772Sas200622 mxa->send_hdr.response_hdr.reserved = 0; 8245772Sas200622 break; 8255772Sas200622 8265772Sas200622 case MLRPC_PTYPE_ALTER_CONTEXT: 8275772Sas200622 hdr->ptype = MLRPC_PTYPE_ALTER_CONTEXT_RESP; 8285772Sas200622 /* 8295772Sas200622 * The max_xmit_frag, max_recv_frag 8305772Sas200622 * and assoc_group_id are ignored. 8315772Sas200622 */ 8325772Sas200622 break; 8335772Sas200622 8345772Sas200622 default: 8355772Sas200622 hdr->ptype = 0xFF; 8365772Sas200622 } 8375772Sas200622 } 8385772Sas200622 8395772Sas200622 /* 8405772Sas200622 * Finish and encode the bind acknowledge (MLRPC_PTYPE_BIND_ACK) header. 8415772Sas200622 * The frag_length is different from a regular RPC response. 8425772Sas200622 */ 8435772Sas200622 static void 8445772Sas200622 mlrpc_reply_bind_ack(struct mlrpc_xaction *mxa) 8455772Sas200622 { 8465772Sas200622 mlrpcconn_common_header_t *hdr; 8475772Sas200622 mlrpcconn_bind_ack_hdr_t *bahdr; 8485772Sas200622 8495772Sas200622 hdr = &mxa->send_hdr.common_hdr; 8505772Sas200622 bahdr = &mxa->send_hdr.bind_ack_hdr; 8515772Sas200622 hdr->frag_length = mlrpc_bind_ack_hdr_size(bahdr); 8525772Sas200622 } 8535772Sas200622 8545772Sas200622 /* 8555772Sas200622 * Signal an RPC fault. The stream is reset and we overwrite whatever 8565772Sas200622 * was in the response header with the fault information. 8575772Sas200622 */ 8585772Sas200622 static void 8595772Sas200622 mlrpc_reply_fault(struct mlrpc_xaction *mxa, unsigned long drc) 8605772Sas200622 { 8615772Sas200622 mlrpcconn_common_header_t *rhdr = &mxa->recv_hdr.common_hdr; 8625772Sas200622 mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr; 8635772Sas200622 struct mlndr_stream *mlnds = &mxa->send_mlnds; 8645772Sas200622 unsigned long fault_status; 8655772Sas200622 8665772Sas200622 MLNDS_RESET(mlnds); 8675772Sas200622 8685772Sas200622 hdr->rpc_vers = 5; 8695772Sas200622 hdr->rpc_vers_minor = 0; 8705772Sas200622 hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG; 8715772Sas200622 hdr->packed_drep = rhdr->packed_drep; 8725772Sas200622 hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr); 8735772Sas200622 hdr->auth_length = 0; 8745772Sas200622 hdr->call_id = rhdr->call_id; 8755772Sas200622 #ifdef _BIG_ENDIAN 8765772Sas200622 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII 8775772Sas200622 | MLRPC_REPLAB_INTG_BIG_ENDIAN; 8785772Sas200622 #else 8795772Sas200622 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII 8805772Sas200622 | MLRPC_REPLAB_INTG_LITTLE_ENDIAN; 8815772Sas200622 #endif 8825772Sas200622 8835772Sas200622 switch (drc & MLRPC_DRC_MASK_SPECIFIER) { 8845772Sas200622 case MLRPC_DRC_FAULT_OUT_OF_MEMORY: 8855772Sas200622 case MLRPC_DRC_FAULT_ENCODE_TOO_BIG: 8865772Sas200622 fault_status = MLRPC_FAULT_NCA_OUT_ARGS_TOO_BIG; 8875772Sas200622 break; 8885772Sas200622 8895772Sas200622 case MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID: 8905772Sas200622 fault_status = MLRPC_FAULT_NCA_INVALID_PRES_CONTEXT_ID; 8915772Sas200622 break; 8925772Sas200622 8935772Sas200622 case MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID: 8945772Sas200622 fault_status = MLRPC_FAULT_NCA_OP_RNG_ERROR; 8955772Sas200622 break; 8965772Sas200622 8975772Sas200622 case MLRPC_DRC_FAULT_DECODE_FAILED: 8985772Sas200622 case MLRPC_DRC_FAULT_ENCODE_FAILED: 8995772Sas200622 fault_status = MLRPC_FAULT_NCA_PROTO_ERROR; 9005772Sas200622 break; 9015772Sas200622 9025772Sas200622 default: 9035772Sas200622 fault_status = MLRPC_FAULT_NCA_UNSPEC_REJECT; 9045772Sas200622 break; 9055772Sas200622 } 9065772Sas200622 9075772Sas200622 mxa->send_hdr.fault_hdr.common_hdr.ptype = MLRPC_PTYPE_FAULT; 9085772Sas200622 mxa->send_hdr.fault_hdr.status = fault_status; 9095772Sas200622 mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length; 9105772Sas200622 } 9115772Sas200622 9125772Sas200622 static int 9135772Sas200622 mlrpc_build_reply(struct mlrpc_xaction *mxa) 9145772Sas200622 { 9155772Sas200622 mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr; 9165772Sas200622 struct mlndr_stream *mlnds = &mxa->send_mlnds; 9176482Samw uint8_t *pdu_buf; 9185772Sas200622 unsigned long pdu_size; 9195772Sas200622 unsigned long frag_size; 9205772Sas200622 unsigned long pdu_data_size; 9215772Sas200622 unsigned long frag_data_size; 9225772Sas200622 9235772Sas200622 frag_size = mlrpc_frag_size; 9245772Sas200622 pdu_size = mlnds->pdu_size; 9256482Samw pdu_buf = mlnds->pdu_base_addr; 9265772Sas200622 9275772Sas200622 if (pdu_size <= frag_size) { 9285772Sas200622 /* 9295772Sas200622 * Single fragment response. The PDU size may be zero 9305772Sas200622 * here (i.e. bind or fault response). So don't make 9315772Sas200622 * any assumptions about it until after the header is 9325772Sas200622 * encoded. 9335772Sas200622 */ 9345772Sas200622 switch (hdr->ptype) { 9355772Sas200622 case MLRPC_PTYPE_BIND_ACK: 9365772Sas200622 mlrpc_reply_bind_ack(mxa); 9375772Sas200622 break; 9385772Sas200622 9395772Sas200622 case MLRPC_PTYPE_FAULT: 9405772Sas200622 /* already setup */ 9415772Sas200622 break; 9425772Sas200622 9435772Sas200622 case MLRPC_PTYPE_RESPONSE: 9445772Sas200622 hdr->frag_length = pdu_size; 9455772Sas200622 mxa->send_hdr.response_hdr.alloc_hint = 9465772Sas200622 hdr->frag_length; 9475772Sas200622 break; 9485772Sas200622 9495772Sas200622 default: 9505772Sas200622 hdr->frag_length = pdu_size; 9515772Sas200622 break; 9525772Sas200622 } 9535772Sas200622 9545772Sas200622 mlnds->pdu_scan_offset = 0; 9555772Sas200622 (void) mlrpc_encode_pdu_hdr(mxa); 9566482Samw pdu_size = mlnds->pdu_size; 9576482Samw mlrpc_build_frag(mlnds, pdu_buf, pdu_size); 9585772Sas200622 return (0); 9595772Sas200622 } 9605772Sas200622 9615772Sas200622 /* 9625772Sas200622 * Multiple fragment response. 9635772Sas200622 */ 9645772Sas200622 hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG; 9655772Sas200622 hdr->frag_length = frag_size; 9665772Sas200622 mxa->send_hdr.response_hdr.alloc_hint = pdu_size - MLRPC_RSP_HDR_SIZE; 9675772Sas200622 mlnds->pdu_scan_offset = 0; 9685772Sas200622 (void) mlrpc_encode_pdu_hdr(mxa); 9696482Samw mlrpc_build_frag(mlnds, pdu_buf, frag_size); 9705772Sas200622 9715772Sas200622 /* 9725772Sas200622 * We need to update the 24-byte header in subsequent fragments. 9735772Sas200622 * 9746482Samw * pdu_data_size: total data remaining to be handled 9756482Samw * frag_size: total fragment size including header 9766482Samw * frag_data_size: data in fragment 9775772Sas200622 * (i.e. frag_size - MLRPC_RSP_HDR_SIZE) 9785772Sas200622 */ 9795772Sas200622 pdu_data_size = pdu_size - MLRPC_RSP_HDR_SIZE; 9805772Sas200622 frag_data_size = frag_size - MLRPC_RSP_HDR_SIZE; 9815772Sas200622 9826482Samw while (pdu_data_size) { 9836482Samw mxa->send_hdr.response_hdr.alloc_hint -= frag_data_size; 9846482Samw pdu_data_size -= frag_data_size; 9856482Samw pdu_buf += frag_data_size; 9865772Sas200622 9876482Samw if (pdu_data_size <= frag_data_size) { 9886482Samw frag_data_size = pdu_data_size; 9896482Samw frag_size = frag_data_size + MLRPC_RSP_HDR_SIZE; 9906482Samw hdr->pfc_flags = MLRPC_PFC_LAST_FRAG; 9915772Sas200622 } else { 9926482Samw hdr->pfc_flags = 0; 9935772Sas200622 } 9945772Sas200622 9956482Samw hdr->frag_length = frag_size; 9966482Samw mlnds->pdu_scan_offset = 0; 9976483Samw (void) mlrpc_encode_pdu_hdr(mxa); 9986482Samw bcopy(mlnds->pdu_base_addr, pdu_buf, MLRPC_RSP_HDR_SIZE); 9995772Sas200622 10006482Samw mlrpc_build_frag(mlnds, pdu_buf, frag_size); 10015772Sas200622 10026482Samw if (hdr->pfc_flags & MLRPC_PFC_LAST_FRAG) 10036482Samw break; 10045772Sas200622 } 10055772Sas200622 10065772Sas200622 return (0); 10075772Sas200622 } 10086482Samw 10096482Samw /* 10106482Samw * mlrpc_build_frag 10116482Samw * 10126482Samw * Build an RPC PDU fragment from the specified buffer. 10136482Samw * If malloc fails, the client will see a header/pdu inconsistency 10146482Samw * and report an error. 10156482Samw */ 10166482Samw static void 10176482Samw mlrpc_build_frag(struct mlndr_stream *mlnds, uint8_t *buf, uint32_t len) 10186482Samw { 10196482Samw ndr_frag_t *frag; 10206482Samw int size = sizeof (ndr_frag_t) + len; 10216482Samw 10226482Samw if ((frag = (ndr_frag_t *)malloc(size)) == NULL) 10236482Samw return; 10246482Samw 10256482Samw frag->next = NULL; 10266482Samw frag->buf = (uint8_t *)frag + sizeof (ndr_frag_t); 10276482Samw frag->len = len; 10286482Samw bcopy(buf, frag->buf, len); 10296482Samw 1030*7052Samw if (mlnds->frags.head == NULL) { 1031*7052Samw mlnds->frags.head = frag; 1032*7052Samw mlnds->frags.tail = frag; 1033*7052Samw mlnds->frags.nfrag = 1; 10346482Samw } else { 1035*7052Samw mlnds->frags.tail->next = frag; 1036*7052Samw mlnds->frags.tail = frag; 1037*7052Samw ++mlnds->frags.nfrag; 10386482Samw } 10396482Samw } 1040