1dc20a302Sas200622 /* 2dc20a302Sas200622 * CDDL HEADER START 3dc20a302Sas200622 * 4dc20a302Sas200622 * The contents of this file are subject to the terms of the 5dc20a302Sas200622 * Common Development and Distribution License (the "License"). 6dc20a302Sas200622 * You may not use this file except in compliance with the License. 7dc20a302Sas200622 * 8dc20a302Sas200622 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9dc20a302Sas200622 * or http://www.opensolaris.org/os/licensing. 10dc20a302Sas200622 * See the License for the specific language governing permissions 11dc20a302Sas200622 * and limitations under the License. 12dc20a302Sas200622 * 13dc20a302Sas200622 * When distributing Covered Code, include this CDDL HEADER in each 14dc20a302Sas200622 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15dc20a302Sas200622 * If applicable, add the following below this CDDL HEADER, with the 16dc20a302Sas200622 * fields enclosed by brackets "[]" replaced with your own identifying 17dc20a302Sas200622 * information: Portions Copyright [yyyy] [name of copyright owner] 18dc20a302Sas200622 * 19dc20a302Sas200622 * CDDL HEADER END 20dc20a302Sas200622 */ 21dc20a302Sas200622 /* 22cb174861Sjoyce mcintosh * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23*68b2bbf2SGordon Ross * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 24dc20a302Sas200622 */ 25dc20a302Sas200622 26dc20a302Sas200622 /* 27dc20a302Sas200622 * Server side RPC handler. 28dc20a302Sas200622 */ 29dc20a302Sas200622 30dc20a302Sas200622 #include <sys/byteorder.h> 313db3f65cSamw #include <sys/uio.h> 32*68b2bbf2SGordon Ross #include <errno.h> 33dc20a302Sas200622 #include <synch.h> 34dc20a302Sas200622 #include <stdlib.h> 35dc20a302Sas200622 #include <strings.h> 36dc20a302Sas200622 #include <string.h> 37*68b2bbf2SGordon Ross #include <thread.h> 38dc20a302Sas200622 39dc20a302Sas200622 #include <smbsrv/libsmb.h> 40dc20a302Sas200622 #include <smbsrv/libmlrpc.h> 4189dc44ceSjose borrego #include <smbsrv/ntaccess.h> 42dc20a302Sas200622 43*68b2bbf2SGordon Ross #define NDR_PIPE_SEND(np, buf, len) \ 44*68b2bbf2SGordon Ross ((np)->np_send)((np), (buf), (len)) 45*68b2bbf2SGordon Ross #define NDR_PIPE_RECV(np, buf, len) \ 46*68b2bbf2SGordon Ross ((np)->np_recv)((np), (buf), (len)) 473db3f65cSamw 488d7e4166Sjose borrego static int ndr_svc_process(ndr_xa_t *); 498d7e4166Sjose borrego static int ndr_svc_bind(ndr_xa_t *); 508d7e4166Sjose borrego static int ndr_svc_request(ndr_xa_t *); 518d7e4166Sjose borrego static void ndr_reply_prepare_hdr(ndr_xa_t *); 528d7e4166Sjose borrego static int ndr_svc_alter_context(ndr_xa_t *); 538d7e4166Sjose borrego static void ndr_reply_fault(ndr_xa_t *, unsigned long); 54*68b2bbf2SGordon Ross 55*68b2bbf2SGordon Ross static int ndr_recv_request(ndr_xa_t *mxa); 56*68b2bbf2SGordon Ross static int ndr_recv_frag(ndr_xa_t *mxa); 57*68b2bbf2SGordon Ross static int ndr_send_reply(ndr_xa_t *); 58*68b2bbf2SGordon Ross 59*68b2bbf2SGordon Ross static int ndr_pipe_process(ndr_pipe_t *, ndr_xa_t *); 60dc20a302Sas200622 61dc20a302Sas200622 /* 62*68b2bbf2SGordon Ross * External entry point called by smbd. 63dc20a302Sas200622 */ 64*68b2bbf2SGordon Ross void 65*68b2bbf2SGordon Ross ndr_pipe_worker(ndr_pipe_t *np) 66dc20a302Sas200622 { 67*68b2bbf2SGordon Ross ndr_xa_t *mxa; 68*68b2bbf2SGordon Ross int rc; 693db3f65cSamw 708d7e4166Sjose borrego ndr_svc_binding_pool_init(&np->np_binding, np->np_binding_pool, 718d7e4166Sjose borrego NDR_N_BINDING_POOL); 723db3f65cSamw 73*68b2bbf2SGordon Ross if ((mxa = malloc(sizeof (*mxa))) == NULL) 74*68b2bbf2SGordon Ross return; 753db3f65cSamw 76*68b2bbf2SGordon Ross do { 77*68b2bbf2SGordon Ross bzero(mxa, sizeof (*mxa)); 78*68b2bbf2SGordon Ross rc = ndr_pipe_process(np, mxa); 79*68b2bbf2SGordon Ross } while (rc == 0); 803db3f65cSamw 81dc20a302Sas200622 free(mxa); 82dc20a302Sas200622 833db3f65cSamw /* 843db3f65cSamw * Ensure that there are no RPC service policy handles 853db3f65cSamw * (associated with this fid) left around. 863db3f65cSamw */ 87*68b2bbf2SGordon Ross ndr_hdclose(np); 883db3f65cSamw } 893db3f65cSamw 903db3f65cSamw /* 91*68b2bbf2SGordon Ross * Process one server-side RPC request. 923db3f65cSamw */ 93*68b2bbf2SGordon Ross static int 94*68b2bbf2SGordon Ross ndr_pipe_process(ndr_pipe_t *np, ndr_xa_t *mxa) 953db3f65cSamw { 96*68b2bbf2SGordon Ross ndr_stream_t *recv_nds; 97*68b2bbf2SGordon Ross ndr_stream_t *send_nds; 98*68b2bbf2SGordon Ross int rc = ENOMEM; 993db3f65cSamw 100*68b2bbf2SGordon Ross mxa->pipe = np; 101*68b2bbf2SGordon Ross mxa->binding_list = np->np_binding; 1023db3f65cSamw 103*68b2bbf2SGordon Ross if ((mxa->heap = ndr_heap_create()) == NULL) 104*68b2bbf2SGordon Ross goto out1; 1053db3f65cSamw 106*68b2bbf2SGordon Ross recv_nds = &mxa->recv_nds; 107*68b2bbf2SGordon Ross rc = nds_initialize(recv_nds, 0, NDR_MODE_CALL_RECV, mxa->heap); 108*68b2bbf2SGordon Ross if (rc != 0) 109*68b2bbf2SGordon Ross goto out2; 110*68b2bbf2SGordon Ross 111*68b2bbf2SGordon Ross send_nds = &mxa->send_nds; 112*68b2bbf2SGordon Ross rc = nds_initialize(send_nds, 0, NDR_MODE_RETURN_SEND, mxa->heap); 113*68b2bbf2SGordon Ross if (rc != 0) 114*68b2bbf2SGordon Ross goto out3; 115*68b2bbf2SGordon Ross 116*68b2bbf2SGordon Ross rc = ndr_recv_request(mxa); 117*68b2bbf2SGordon Ross if (rc != 0) 118*68b2bbf2SGordon Ross goto out4; 119*68b2bbf2SGordon Ross 120*68b2bbf2SGordon Ross (void) ndr_svc_process(mxa); 121*68b2bbf2SGordon Ross (void) ndr_send_reply(mxa); 122*68b2bbf2SGordon Ross rc = 0; 123*68b2bbf2SGordon Ross 124*68b2bbf2SGordon Ross out4: 125*68b2bbf2SGordon Ross nds_destruct(&mxa->send_nds); 126*68b2bbf2SGordon Ross out3: 127*68b2bbf2SGordon Ross nds_destruct(&mxa->recv_nds); 128*68b2bbf2SGordon Ross out2: 129*68b2bbf2SGordon Ross ndr_heap_destroy(mxa->heap); 130*68b2bbf2SGordon Ross out1: 131*68b2bbf2SGordon Ross return (rc); 1323db3f65cSamw } 1333db3f65cSamw 1343db3f65cSamw /* 1353db3f65cSamw * Check whether or not the specified user has administrator privileges, 1363db3f65cSamw * i.e. is a member of Domain Admins or Administrators. 1373db3f65cSamw * Returns true if the user is an administrator, otherwise returns false. 1383db3f65cSamw */ 1393db3f65cSamw boolean_t 1403db3f65cSamw ndr_is_admin(ndr_xa_t *xa) 1413db3f65cSamw { 142*68b2bbf2SGordon Ross smb_netuserinfo_t *ctx = xa->pipe->np_user; 1433db3f65cSamw 1441fcced4cSJordan Brown return (ctx->ui_flags & SMB_ATF_ADMIN); 1453db3f65cSamw } 1463db3f65cSamw 1473db3f65cSamw /* 1483db3f65cSamw * Check whether or not the specified user has power-user privileges, 1493db3f65cSamw * i.e. is a member of Domain Admins, Administrators or Power Users. 1503db3f65cSamw * This is typically required for operations such as managing shares. 1513db3f65cSamw * Returns true if the user is a power user, otherwise returns false. 1523db3f65cSamw */ 1533db3f65cSamw boolean_t 1543db3f65cSamw ndr_is_poweruser(ndr_xa_t *xa) 1553db3f65cSamw { 156*68b2bbf2SGordon Ross smb_netuserinfo_t *ctx = xa->pipe->np_user; 1573db3f65cSamw 1581fcced4cSJordan Brown return ((ctx->ui_flags & SMB_ATF_ADMIN) || 1591fcced4cSJordan Brown (ctx->ui_flags & SMB_ATF_POWERUSER)); 1603db3f65cSamw } 1613db3f65cSamw 1623db3f65cSamw int32_t 1633db3f65cSamw ndr_native_os(ndr_xa_t *xa) 1643db3f65cSamw { 165*68b2bbf2SGordon Ross smb_netuserinfo_t *ctx = xa->pipe->np_user; 1663db3f65cSamw 1671fcced4cSJordan Brown return (ctx->ui_native_os); 168dc20a302Sas200622 } 169dc20a302Sas200622 170dc20a302Sas200622 /* 171*68b2bbf2SGordon Ross * Receive an entire RPC request (all fragments) 172*68b2bbf2SGordon Ross * Returns zero or an NDR fault code. 173*68b2bbf2SGordon Ross */ 174*68b2bbf2SGordon Ross static int 175*68b2bbf2SGordon Ross ndr_recv_request(ndr_xa_t *mxa) 176*68b2bbf2SGordon Ross { 177*68b2bbf2SGordon Ross ndr_common_header_t *hdr = &mxa->recv_hdr.common_hdr; 178*68b2bbf2SGordon Ross ndr_stream_t *nds = &mxa->recv_nds; 179*68b2bbf2SGordon Ross unsigned long saved_size; 180*68b2bbf2SGordon Ross int rc; 181*68b2bbf2SGordon Ross 182*68b2bbf2SGordon Ross rc = ndr_recv_frag(mxa); 183*68b2bbf2SGordon Ross if (rc != 0) 184*68b2bbf2SGordon Ross return (rc); 185*68b2bbf2SGordon Ross if (!NDR_IS_FIRST_FRAG(hdr->pfc_flags)) 186*68b2bbf2SGordon Ross return (NDR_DRC_FAULT_DECODE_FAILED); 187*68b2bbf2SGordon Ross 188*68b2bbf2SGordon Ross while (!NDR_IS_LAST_FRAG(hdr->pfc_flags)) { 189*68b2bbf2SGordon Ross rc = ndr_recv_frag(mxa); 190*68b2bbf2SGordon Ross if (rc != 0) 191*68b2bbf2SGordon Ross return (rc); 192*68b2bbf2SGordon Ross } 193*68b2bbf2SGordon Ross nds->pdu_scan_offset = 0; 194*68b2bbf2SGordon Ross 195*68b2bbf2SGordon Ross /* 196*68b2bbf2SGordon Ross * This whacks nds->pdu_size, so save/restore. 197*68b2bbf2SGordon Ross * It leaves scan_offset after the header. 198*68b2bbf2SGordon Ross */ 199*68b2bbf2SGordon Ross saved_size = nds->pdu_size; 200*68b2bbf2SGordon Ross rc = ndr_decode_pdu_hdr(mxa); 201*68b2bbf2SGordon Ross nds->pdu_size = saved_size; 202*68b2bbf2SGordon Ross 203*68b2bbf2SGordon Ross return (rc); 204*68b2bbf2SGordon Ross } 205*68b2bbf2SGordon Ross 206*68b2bbf2SGordon Ross /* 207*68b2bbf2SGordon Ross * Read one fragment, leaving the decoded frag header in 208*68b2bbf2SGordon Ross * recv_hdr.common_hdr, and the data in the recv_nds. 209*68b2bbf2SGordon Ross * 210*68b2bbf2SGordon Ross * Returns zero or an NDR fault code. 211*68b2bbf2SGordon Ross * 212*68b2bbf2SGordon Ross * If a first frag, the header is included in the data 213*68b2bbf2SGordon Ross * placed in recv_nds (because it's not fully decoded 214*68b2bbf2SGordon Ross * until later - we only decode the common part here). 215*68b2bbf2SGordon Ross * Additional frags are placed in the recv_nds without 216*68b2bbf2SGordon Ross * the header, so that after the first frag header, 217*68b2bbf2SGordon Ross * the remaining data will be contiguous. We do this 218*68b2bbf2SGordon Ross * by simply not advancing the offset in recv_nds after 219*68b2bbf2SGordon Ross * reading and decoding these additional fragments, so 220*68b2bbf2SGordon Ross * the payload of such frags will overwrite what was 221*68b2bbf2SGordon Ross * (temporarily) the frag header. 222*68b2bbf2SGordon Ross */ 223*68b2bbf2SGordon Ross static int 224*68b2bbf2SGordon Ross ndr_recv_frag(ndr_xa_t *mxa) 225*68b2bbf2SGordon Ross { 226*68b2bbf2SGordon Ross ndr_common_header_t *hdr = &mxa->recv_hdr.common_hdr; 227*68b2bbf2SGordon Ross ndr_stream_t *nds = &mxa->recv_nds; 228*68b2bbf2SGordon Ross unsigned char *data; 229*68b2bbf2SGordon Ross unsigned long next_offset; 230*68b2bbf2SGordon Ross unsigned long pay_size; 231*68b2bbf2SGordon Ross int rc; 232*68b2bbf2SGordon Ross 233*68b2bbf2SGordon Ross /* Make room for the frag header. */ 234*68b2bbf2SGordon Ross next_offset = nds->pdu_scan_offset + NDR_RSP_HDR_SIZE; 235*68b2bbf2SGordon Ross if (!NDS_GROW_PDU(nds, next_offset, 0)) 236*68b2bbf2SGordon Ross return (NDR_DRC_FAULT_OUT_OF_MEMORY); 237*68b2bbf2SGordon Ross 238*68b2bbf2SGordon Ross /* Read the frag header. */ 239*68b2bbf2SGordon Ross data = nds->pdu_base_addr + nds->pdu_scan_offset; 240*68b2bbf2SGordon Ross rc = NDR_PIPE_RECV(mxa->pipe, data, NDR_RSP_HDR_SIZE); 241*68b2bbf2SGordon Ross if (rc != 0) 242*68b2bbf2SGordon Ross return (NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT); 243*68b2bbf2SGordon Ross 244*68b2bbf2SGordon Ross /* 245*68b2bbf2SGordon Ross * Decode the frag header, get the length. 246*68b2bbf2SGordon Ross * NB: It uses nds->pdu_scan_offset 247*68b2bbf2SGordon Ross */ 248*68b2bbf2SGordon Ross ndr_decode_frag_hdr(nds, hdr); 249*68b2bbf2SGordon Ross ndr_show_hdr(hdr); 250*68b2bbf2SGordon Ross if (hdr->frag_length < NDR_RSP_HDR_SIZE || 251*68b2bbf2SGordon Ross hdr->frag_length > mxa->pipe->np_max_xmit_frag) 252*68b2bbf2SGordon Ross return (NDR_DRC_FAULT_DECODE_FAILED); 253*68b2bbf2SGordon Ross 254*68b2bbf2SGordon Ross if (nds->pdu_scan_offset == 0) { 255*68b2bbf2SGordon Ross /* First frag: header stays in the data. */ 256*68b2bbf2SGordon Ross nds->pdu_scan_offset = next_offset; 257*68b2bbf2SGordon Ross } /* else overwrite with the payload */ 258*68b2bbf2SGordon Ross 259*68b2bbf2SGordon Ross /* Make room for the payload. */ 260*68b2bbf2SGordon Ross pay_size = hdr->frag_length - NDR_RSP_HDR_SIZE; 261*68b2bbf2SGordon Ross next_offset = nds->pdu_scan_offset + pay_size; 262*68b2bbf2SGordon Ross if (!NDS_GROW_PDU(nds, next_offset, 0)) 263*68b2bbf2SGordon Ross return (NDR_DRC_FAULT_OUT_OF_MEMORY); 264*68b2bbf2SGordon Ross 265*68b2bbf2SGordon Ross /* Read the payload. */ 266*68b2bbf2SGordon Ross data = nds->pdu_base_addr + nds->pdu_scan_offset; 267*68b2bbf2SGordon Ross rc = NDR_PIPE_RECV(mxa->pipe, data, pay_size); 268*68b2bbf2SGordon Ross if (rc != 0) 269*68b2bbf2SGordon Ross return (NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT); 270*68b2bbf2SGordon Ross nds->pdu_scan_offset = next_offset; 271*68b2bbf2SGordon Ross 272*68b2bbf2SGordon Ross return (NDR_DRC_OK); 273*68b2bbf2SGordon Ross } 274*68b2bbf2SGordon Ross 275*68b2bbf2SGordon Ross /* 276dc20a302Sas200622 * This is the entry point for all server-side RPC processing. 277dc20a302Sas200622 * It is assumed that the PDU has already been received. 278dc20a302Sas200622 */ 279dc20a302Sas200622 static int 2808d7e4166Sjose borrego ndr_svc_process(ndr_xa_t *mxa) 281dc20a302Sas200622 { 282dc20a302Sas200622 int rc; 283dc20a302Sas200622 2848d7e4166Sjose borrego (void) ndr_reply_prepare_hdr(mxa); 285dc20a302Sas200622 286dc20a302Sas200622 switch (mxa->ptype) { 2878d7e4166Sjose borrego case NDR_PTYPE_BIND: 2888d7e4166Sjose borrego rc = ndr_svc_bind(mxa); 289dc20a302Sas200622 break; 290dc20a302Sas200622 2918d7e4166Sjose borrego case NDR_PTYPE_REQUEST: 2928d7e4166Sjose borrego rc = ndr_svc_request(mxa); 293dc20a302Sas200622 break; 294dc20a302Sas200622 2958d7e4166Sjose borrego case NDR_PTYPE_ALTER_CONTEXT: 2968d7e4166Sjose borrego rc = ndr_svc_alter_context(mxa); 297dc20a302Sas200622 break; 298dc20a302Sas200622 299dc20a302Sas200622 default: 3008d7e4166Sjose borrego rc = NDR_DRC_FAULT_RPCHDR_PTYPE_INVALID; 301dc20a302Sas200622 break; 302dc20a302Sas200622 } 303dc20a302Sas200622 3048d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc)) 3058d7e4166Sjose borrego ndr_reply_fault(mxa, rc); 306dc20a302Sas200622 307dc20a302Sas200622 return (rc); 308dc20a302Sas200622 } 309dc20a302Sas200622 310dc20a302Sas200622 /* 311dc20a302Sas200622 * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple 312dc20a302Sas200622 * p_results[] not supported. 313dc20a302Sas200622 */ 314dc20a302Sas200622 static int 3158d7e4166Sjose borrego ndr_svc_bind(ndr_xa_t *mxa) 316dc20a302Sas200622 { 3178d7e4166Sjose borrego ndr_p_cont_list_t *cont_list; 3188d7e4166Sjose borrego ndr_p_result_list_t *result_list; 3198d7e4166Sjose borrego ndr_p_result_t *result; 320dc20a302Sas200622 unsigned p_cont_id; 3218d7e4166Sjose borrego ndr_binding_t *mbind; 322dc20a302Sas200622 ndr_uuid_t *as_uuid; 323dc20a302Sas200622 ndr_uuid_t *ts_uuid; 324dc20a302Sas200622 int as_vers; 325dc20a302Sas200622 int ts_vers; 3268d7e4166Sjose borrego ndr_service_t *msvc; 327dc20a302Sas200622 int rc; 3288d7e4166Sjose borrego ndr_port_any_t *sec_addr; 329dc20a302Sas200622 330dc20a302Sas200622 /* acquire targets */ 331dc20a302Sas200622 cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem; 332dc20a302Sas200622 result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list; 333dc20a302Sas200622 result = &result_list->p_results[0]; 334dc20a302Sas200622 335dc20a302Sas200622 /* 336dc20a302Sas200622 * Set up temporary secondary address port. 337dc20a302Sas200622 * We will correct this later (below). 338dc20a302Sas200622 */ 339dc20a302Sas200622 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 340dc20a302Sas200622 sec_addr->length = 13; 341dc20a302Sas200622 (void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs"); 342dc20a302Sas200622 343dc20a302Sas200622 result_list->n_results = 1; 344dc20a302Sas200622 result_list->reserved = 0; 345dc20a302Sas200622 result_list->reserved2 = 0; 3468d7e4166Sjose borrego result->result = NDR_PCDR_ACCEPTANCE; 347dc20a302Sas200622 result->reason = 0; 348dc20a302Sas200622 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax)); 349dc20a302Sas200622 350dc20a302Sas200622 /* sanity check */ 351dc20a302Sas200622 if (cont_list->n_context_elem != 1 || 352dc20a302Sas200622 cont_list->p_cont_elem[0].n_transfer_syn != 1) { 3538d7e4166Sjose borrego ndo_trace("ndr_svc_bind: warning: multiple p_cont_elem"); 354dc20a302Sas200622 } 355dc20a302Sas200622 356dc20a302Sas200622 p_cont_id = cont_list->p_cont_elem[0].p_cont_id; 357dc20a302Sas200622 3588d7e4166Sjose borrego if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) != NULL) { 359dc20a302Sas200622 /* 3608d7e4166Sjose borrego * Duplicate presentation context id. 361dc20a302Sas200622 */ 3628d7e4166Sjose borrego ndo_trace("ndr_svc_bind: duplicate binding"); 3638d7e4166Sjose borrego return (NDR_DRC_FAULT_BIND_PCONT_BUSY); 364dc20a302Sas200622 } 365dc20a302Sas200622 3668d7e4166Sjose borrego if ((mbind = ndr_svc_new_binding(mxa)) == NULL) { 367dc20a302Sas200622 /* 368dc20a302Sas200622 * No free binding slot 369dc20a302Sas200622 */ 3708d7e4166Sjose borrego result->result = NDR_PCDR_PROVIDER_REJECTION; 3718d7e4166Sjose borrego result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED; 3728d7e4166Sjose borrego ndo_trace("ndr_svc_bind: no resources"); 3738d7e4166Sjose borrego return (NDR_DRC_OK); 374dc20a302Sas200622 } 375dc20a302Sas200622 376dc20a302Sas200622 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid; 377dc20a302Sas200622 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version; 378dc20a302Sas200622 379dc20a302Sas200622 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid; 380dc20a302Sas200622 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version; 381dc20a302Sas200622 3828d7e4166Sjose borrego msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers); 3838d7e4166Sjose borrego if (msvc == NULL) { 3848d7e4166Sjose borrego result->result = NDR_PCDR_PROVIDER_REJECTION; 3858d7e4166Sjose borrego result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 3868d7e4166Sjose borrego return (NDR_DRC_OK); 387dc20a302Sas200622 } 388dc20a302Sas200622 389dc20a302Sas200622 /* 390dc20a302Sas200622 * We can now use the correct secondary address port. 391dc20a302Sas200622 */ 392dc20a302Sas200622 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 393dc20a302Sas200622 sec_addr->length = strlen(msvc->sec_addr_port) + 1; 394dc20a302Sas200622 (void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port, 3958d7e4166Sjose borrego NDR_PORT_ANY_MAX_PORT_SPEC); 396dc20a302Sas200622 397dc20a302Sas200622 mbind->p_cont_id = p_cont_id; 3988d7e4166Sjose borrego mbind->which_side = NDR_BIND_SIDE_SERVER; 399dc20a302Sas200622 /* mbind->context set by app */ 400dc20a302Sas200622 mbind->service = msvc; 401dc20a302Sas200622 mbind->instance_specific = 0; 402dc20a302Sas200622 403dc20a302Sas200622 mxa->binding = mbind; 404dc20a302Sas200622 405dc20a302Sas200622 if (msvc->bind_req) { 406dc20a302Sas200622 /* 407dc20a302Sas200622 * Call the service-specific bind() handler. If 408dc20a302Sas200622 * this fails, we shouild send a specific error 409dc20a302Sas200622 * on the bind ack. 410dc20a302Sas200622 */ 411dc20a302Sas200622 rc = (msvc->bind_req)(mxa); 4128d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc)) { 413dc20a302Sas200622 mbind->service = 0; /* free binding slot */ 414dc20a302Sas200622 mbind->which_side = 0; 415dc20a302Sas200622 mbind->p_cont_id = 0; 416dc20a302Sas200622 mbind->instance_specific = 0; 417dc20a302Sas200622 return (rc); 418dc20a302Sas200622 } 419dc20a302Sas200622 } 420dc20a302Sas200622 421dc20a302Sas200622 result->transfer_syntax = 422dc20a302Sas200622 cont_list->p_cont_elem[0].transfer_syntaxes[0]; 423dc20a302Sas200622 4248d7e4166Sjose borrego return (NDR_DRC_BINDING_MADE); 425dc20a302Sas200622 } 426dc20a302Sas200622 427dc20a302Sas200622 /* 4288d7e4166Sjose borrego * ndr_svc_alter_context 429dc20a302Sas200622 * 430dc20a302Sas200622 * The alter context request is used to request additional presentation 4312c1b14e5Sjose borrego * context for another interface and/or version. It is very similar to 4322c1b14e5Sjose borrego * a bind request. 433dc20a302Sas200622 */ 434dc20a302Sas200622 static int 4358d7e4166Sjose borrego ndr_svc_alter_context(ndr_xa_t *mxa) 436dc20a302Sas200622 { 4378d7e4166Sjose borrego ndr_p_result_list_t *result_list; 4388d7e4166Sjose borrego ndr_p_result_t *result; 4398d7e4166Sjose borrego ndr_p_cont_list_t *cont_list; 4408d7e4166Sjose borrego ndr_binding_t *mbind; 4418d7e4166Sjose borrego ndr_service_t *msvc; 442dc20a302Sas200622 unsigned p_cont_id; 443dc20a302Sas200622 ndr_uuid_t *as_uuid; 444dc20a302Sas200622 ndr_uuid_t *ts_uuid; 445dc20a302Sas200622 int as_vers; 446dc20a302Sas200622 int ts_vers; 4478d7e4166Sjose borrego ndr_port_any_t *sec_addr; 448dc20a302Sas200622 4492c1b14e5Sjose borrego result_list = &mxa->send_hdr.alter_context_rsp_hdr.p_result_list; 450dc20a302Sas200622 result_list->n_results = 1; 451dc20a302Sas200622 result_list->reserved = 0; 452dc20a302Sas200622 result_list->reserved2 = 0; 453dc20a302Sas200622 454dc20a302Sas200622 result = &result_list->p_results[0]; 4558d7e4166Sjose borrego result->result = NDR_PCDR_ACCEPTANCE; 456dc20a302Sas200622 result->reason = 0; 457dc20a302Sas200622 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax)); 458dc20a302Sas200622 4592c1b14e5Sjose borrego cont_list = &mxa->recv_hdr.alter_context_hdr.p_context_elem; 460dc20a302Sas200622 p_cont_id = cont_list->p_cont_elem[0].p_cont_id; 461dc20a302Sas200622 4628d7e4166Sjose borrego if (ndr_svc_find_binding(mxa, p_cont_id) != NULL) 4638d7e4166Sjose borrego return (NDR_DRC_FAULT_BIND_PCONT_BUSY); 464dc20a302Sas200622 4658d7e4166Sjose borrego if ((mbind = ndr_svc_new_binding(mxa)) == NULL) { 4668d7e4166Sjose borrego result->result = NDR_PCDR_PROVIDER_REJECTION; 4678d7e4166Sjose borrego result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED; 4688d7e4166Sjose borrego return (NDR_DRC_OK); 469dc20a302Sas200622 } 470dc20a302Sas200622 471dc20a302Sas200622 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid; 472dc20a302Sas200622 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version; 473dc20a302Sas200622 474dc20a302Sas200622 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid; 475dc20a302Sas200622 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version; 476dc20a302Sas200622 4778d7e4166Sjose borrego msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers); 4788d7e4166Sjose borrego if (msvc == NULL) { 4798d7e4166Sjose borrego result->result = NDR_PCDR_PROVIDER_REJECTION; 4808d7e4166Sjose borrego result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 4818d7e4166Sjose borrego return (NDR_DRC_OK); 482dc20a302Sas200622 } 483dc20a302Sas200622 484dc20a302Sas200622 mbind->p_cont_id = p_cont_id; 4858d7e4166Sjose borrego mbind->which_side = NDR_BIND_SIDE_SERVER; 486dc20a302Sas200622 /* mbind->context set by app */ 487dc20a302Sas200622 mbind->service = msvc; 488dc20a302Sas200622 mbind->instance_specific = 0; 489dc20a302Sas200622 mxa->binding = mbind; 490dc20a302Sas200622 4912c1b14e5Sjose borrego sec_addr = &mxa->send_hdr.alter_context_rsp_hdr.sec_addr; 492dc20a302Sas200622 sec_addr->length = 0; 4938d7e4166Sjose borrego bzero(sec_addr->port_spec, NDR_PORT_ANY_MAX_PORT_SPEC); 494dc20a302Sas200622 495dc20a302Sas200622 result->transfer_syntax = 496dc20a302Sas200622 cont_list->p_cont_elem[0].transfer_syntaxes[0]; 497dc20a302Sas200622 4988d7e4166Sjose borrego return (NDR_DRC_BINDING_MADE); 499dc20a302Sas200622 } 500dc20a302Sas200622 501dc20a302Sas200622 static int 5028d7e4166Sjose borrego ndr_svc_request(ndr_xa_t *mxa) 503dc20a302Sas200622 { 5048d7e4166Sjose borrego ndr_binding_t *mbind; 5058d7e4166Sjose borrego ndr_service_t *msvc; 506dc20a302Sas200622 unsigned p_cont_id; 507dc20a302Sas200622 int rc; 508dc20a302Sas200622 509dc20a302Sas200622 mxa->opnum = mxa->recv_hdr.request_hdr.opnum; 510dc20a302Sas200622 p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id; 511dc20a302Sas200622 5128d7e4166Sjose borrego if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) == NULL) 5138d7e4166Sjose borrego return (NDR_DRC_FAULT_REQUEST_PCONT_INVALID); 514dc20a302Sas200622 515dc20a302Sas200622 mxa->binding = mbind; 516dc20a302Sas200622 msvc = mbind->service; 517dc20a302Sas200622 518dc20a302Sas200622 /* 519dc20a302Sas200622 * Make room for the response hdr. 520dc20a302Sas200622 */ 5218d7e4166Sjose borrego mxa->send_nds.pdu_scan_offset = NDR_RSP_HDR_SIZE; 522dc20a302Sas200622 523dc20a302Sas200622 if (msvc->call_stub) 524dc20a302Sas200622 rc = (*msvc->call_stub)(mxa); 525dc20a302Sas200622 else 5268d7e4166Sjose borrego rc = ndr_generic_call_stub(mxa); 527dc20a302Sas200622 5288d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc)) { 5298d7e4166Sjose borrego ndo_printf(0, 0, "%s[0x%02x]: 0x%04x", 530dc20a302Sas200622 msvc->name, mxa->opnum, rc); 531dc20a302Sas200622 } 532dc20a302Sas200622 533dc20a302Sas200622 return (rc); 534dc20a302Sas200622 } 535dc20a302Sas200622 536dc20a302Sas200622 /* 5378d7e4166Sjose borrego * The transaction and the two nds streams use the same heap, which 538dc20a302Sas200622 * should already exist at this point. The heap will also be available 539dc20a302Sas200622 * to the stub. 540dc20a302Sas200622 */ 541dc20a302Sas200622 int 5428d7e4166Sjose borrego ndr_generic_call_stub(ndr_xa_t *mxa) 543dc20a302Sas200622 { 5448d7e4166Sjose borrego ndr_binding_t *mbind = mxa->binding; 5458d7e4166Sjose borrego ndr_service_t *msvc = mbind->service; 5468d7e4166Sjose borrego ndr_typeinfo_t *intf_ti = msvc->interface_ti; 5478d7e4166Sjose borrego ndr_stub_table_t *ste; 548dc20a302Sas200622 int opnum = mxa->opnum; 549dc20a302Sas200622 unsigned p_len = intf_ti->c_size_fixed_part; 550dc20a302Sas200622 char *param; 551dc20a302Sas200622 int rc; 552dc20a302Sas200622 553dc20a302Sas200622 if (mxa->heap == NULL) { 5548d7e4166Sjose borrego ndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum); 5558d7e4166Sjose borrego return (NDR_DRC_FAULT_OUT_OF_MEMORY); 556dc20a302Sas200622 } 557dc20a302Sas200622 5588d7e4166Sjose borrego if ((ste = ndr_svc_find_stub(msvc, opnum)) == NULL) { 5598d7e4166Sjose borrego ndo_printf(0, 0, "%s[0x%02x]: invalid opnum", 560dc20a302Sas200622 msvc->name, opnum); 5618d7e4166Sjose borrego return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID); 562dc20a302Sas200622 } 563dc20a302Sas200622 5648d7e4166Sjose borrego if ((param = ndr_heap_malloc(mxa->heap, p_len)) == NULL) 5658d7e4166Sjose borrego return (NDR_DRC_FAULT_OUT_OF_MEMORY); 566dc20a302Sas200622 567dc20a302Sas200622 bzero(param, p_len); 568dc20a302Sas200622 5698d7e4166Sjose borrego rc = ndr_decode_call(mxa, param); 5708d7e4166Sjose borrego if (!NDR_DRC_IS_OK(rc)) 571dc20a302Sas200622 return (rc); 572dc20a302Sas200622 573dc20a302Sas200622 rc = (*ste->func)(param, mxa); 5748d7e4166Sjose borrego if (rc == NDR_DRC_OK) 5758d7e4166Sjose borrego rc = ndr_encode_return(mxa, param); 576dc20a302Sas200622 577dc20a302Sas200622 return (rc); 578dc20a302Sas200622 } 579dc20a302Sas200622 580dc20a302Sas200622 /* 581dc20a302Sas200622 * We can perform some initial setup of the response header here. 582dc20a302Sas200622 * We also need to cache some of the information from the bind 583dc20a302Sas200622 * negotiation for use during subsequent RPC calls. 584dc20a302Sas200622 */ 585dc20a302Sas200622 static void 5868d7e4166Sjose borrego ndr_reply_prepare_hdr(ndr_xa_t *mxa) 587dc20a302Sas200622 { 5882c1b14e5Sjose borrego ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr; 5892c1b14e5Sjose borrego ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 590dc20a302Sas200622 591dc20a302Sas200622 hdr->rpc_vers = 5; 592dc20a302Sas200622 hdr->rpc_vers_minor = 0; 5938d7e4166Sjose borrego hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG; 594dc20a302Sas200622 hdr->packed_drep = rhdr->packed_drep; 595dc20a302Sas200622 hdr->frag_length = 0; 596dc20a302Sas200622 hdr->auth_length = 0; 597dc20a302Sas200622 hdr->call_id = rhdr->call_id; 598dc20a302Sas200622 #ifdef _BIG_ENDIAN 5998d7e4166Sjose borrego hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII 6008d7e4166Sjose borrego | NDR_REPLAB_INTG_BIG_ENDIAN; 601dc20a302Sas200622 #else 6028d7e4166Sjose borrego hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII 6038d7e4166Sjose borrego | NDR_REPLAB_INTG_LITTLE_ENDIAN; 604dc20a302Sas200622 #endif 605dc20a302Sas200622 606dc20a302Sas200622 switch (mxa->ptype) { 6078d7e4166Sjose borrego case NDR_PTYPE_BIND: 608dc20a302Sas200622 /* 609*68b2bbf2SGordon Ross * Compute the maximum fragment sizes for xmit/recv 610*68b2bbf2SGordon Ross * and store in the pipe endpoint. Note "xmit" is 611*68b2bbf2SGordon Ross * client-to-server; "recv" is server-to-client. 612dc20a302Sas200622 */ 613*68b2bbf2SGordon Ross if (mxa->pipe->np_max_xmit_frag > 614*68b2bbf2SGordon Ross mxa->recv_hdr.bind_hdr.max_xmit_frag) 6158d7e4166Sjose borrego mxa->pipe->np_max_xmit_frag = 616dc20a302Sas200622 mxa->recv_hdr.bind_hdr.max_xmit_frag; 617*68b2bbf2SGordon Ross if (mxa->pipe->np_max_recv_frag > 618*68b2bbf2SGordon Ross mxa->recv_hdr.bind_hdr.max_recv_frag) 6198d7e4166Sjose borrego mxa->pipe->np_max_recv_frag = 620dc20a302Sas200622 mxa->recv_hdr.bind_hdr.max_recv_frag; 621*68b2bbf2SGordon Ross 622*68b2bbf2SGordon Ross hdr->ptype = NDR_PTYPE_BIND_ACK; 623*68b2bbf2SGordon Ross mxa->send_hdr.bind_ack_hdr.max_xmit_frag = 624*68b2bbf2SGordon Ross mxa->pipe->np_max_xmit_frag; 625*68b2bbf2SGordon Ross mxa->send_hdr.bind_ack_hdr.max_recv_frag = 626*68b2bbf2SGordon Ross mxa->pipe->np_max_recv_frag; 627*68b2bbf2SGordon Ross 628*68b2bbf2SGordon Ross /* 629*68b2bbf2SGordon Ross * We're supposed to assign a unique "assoc group" 630*68b2bbf2SGordon Ross * (identifies this connection for the client). 631*68b2bbf2SGordon Ross * Using the pipe address is adequate. 632*68b2bbf2SGordon Ross */ 633*68b2bbf2SGordon Ross mxa->send_hdr.bind_ack_hdr.assoc_group_id = 634*68b2bbf2SGordon Ross mxa->recv_hdr.bind_hdr.assoc_group_id; 635*68b2bbf2SGordon Ross if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0) 636*68b2bbf2SGordon Ross mxa->send_hdr.bind_ack_hdr.assoc_group_id = 637*68b2bbf2SGordon Ross (DWORD)(uintptr_t)mxa->pipe; 638*68b2bbf2SGordon Ross 639dc20a302Sas200622 break; 640dc20a302Sas200622 6418d7e4166Sjose borrego case NDR_PTYPE_REQUEST: 6428d7e4166Sjose borrego hdr->ptype = NDR_PTYPE_RESPONSE; 643dc20a302Sas200622 /* mxa->send_hdr.response_hdr.alloc_hint */ 644dc20a302Sas200622 mxa->send_hdr.response_hdr.p_cont_id = 645dc20a302Sas200622 mxa->recv_hdr.request_hdr.p_cont_id; 646dc20a302Sas200622 mxa->send_hdr.response_hdr.cancel_count = 0; 647dc20a302Sas200622 mxa->send_hdr.response_hdr.reserved = 0; 648dc20a302Sas200622 break; 649dc20a302Sas200622 6508d7e4166Sjose borrego case NDR_PTYPE_ALTER_CONTEXT: 6518d7e4166Sjose borrego hdr->ptype = NDR_PTYPE_ALTER_CONTEXT_RESP; 652dc20a302Sas200622 /* 6532c1b14e5Sjose borrego * The max_xmit_frag, max_recv_frag and assoc_group_id are 6542c1b14e5Sjose borrego * ignored by the client but it's useful to fill them in. 655dc20a302Sas200622 */ 6562c1b14e5Sjose borrego mxa->send_hdr.alter_context_rsp_hdr.max_xmit_frag = 6572c1b14e5Sjose borrego mxa->recv_hdr.alter_context_hdr.max_xmit_frag; 6582c1b14e5Sjose borrego mxa->send_hdr.alter_context_rsp_hdr.max_recv_frag = 6592c1b14e5Sjose borrego mxa->recv_hdr.alter_context_hdr.max_recv_frag; 6602c1b14e5Sjose borrego mxa->send_hdr.alter_context_rsp_hdr.assoc_group_id = 6612c1b14e5Sjose borrego mxa->recv_hdr.alter_context_hdr.assoc_group_id; 662dc20a302Sas200622 break; 663dc20a302Sas200622 664dc20a302Sas200622 default: 665dc20a302Sas200622 hdr->ptype = 0xFF; 666dc20a302Sas200622 } 667dc20a302Sas200622 } 668dc20a302Sas200622 669dc20a302Sas200622 /* 670dc20a302Sas200622 * Signal an RPC fault. The stream is reset and we overwrite whatever 671dc20a302Sas200622 * was in the response header with the fault information. 672dc20a302Sas200622 */ 673dc20a302Sas200622 static void 6748d7e4166Sjose borrego ndr_reply_fault(ndr_xa_t *mxa, unsigned long drc) 675dc20a302Sas200622 { 6762c1b14e5Sjose borrego ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr; 6772c1b14e5Sjose borrego ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 6788d7e4166Sjose borrego ndr_stream_t *nds = &mxa->send_nds; 679dc20a302Sas200622 unsigned long fault_status; 680dc20a302Sas200622 6818d7e4166Sjose borrego NDS_RESET(nds); 682dc20a302Sas200622 683dc20a302Sas200622 hdr->rpc_vers = 5; 684dc20a302Sas200622 hdr->rpc_vers_minor = 0; 6858d7e4166Sjose borrego hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG; 686dc20a302Sas200622 hdr->packed_drep = rhdr->packed_drep; 687dc20a302Sas200622 hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr); 688dc20a302Sas200622 hdr->auth_length = 0; 689dc20a302Sas200622 hdr->call_id = rhdr->call_id; 690dc20a302Sas200622 #ifdef _BIG_ENDIAN 6918d7e4166Sjose borrego hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII 6928d7e4166Sjose borrego | NDR_REPLAB_INTG_BIG_ENDIAN; 693dc20a302Sas200622 #else 6948d7e4166Sjose borrego hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII 6958d7e4166Sjose borrego | NDR_REPLAB_INTG_LITTLE_ENDIAN; 696dc20a302Sas200622 #endif 697dc20a302Sas200622 6988d7e4166Sjose borrego switch (drc & NDR_DRC_MASK_SPECIFIER) { 6998d7e4166Sjose borrego case NDR_DRC_FAULT_OUT_OF_MEMORY: 7008d7e4166Sjose borrego case NDR_DRC_FAULT_ENCODE_TOO_BIG: 7018d7e4166Sjose borrego fault_status = NDR_FAULT_NCA_OUT_ARGS_TOO_BIG; 702dc20a302Sas200622 break; 703dc20a302Sas200622 7048d7e4166Sjose borrego case NDR_DRC_FAULT_REQUEST_PCONT_INVALID: 7058d7e4166Sjose borrego fault_status = NDR_FAULT_NCA_INVALID_PRES_CONTEXT_ID; 706dc20a302Sas200622 break; 707dc20a302Sas200622 7088d7e4166Sjose borrego case NDR_DRC_FAULT_REQUEST_OPNUM_INVALID: 7098d7e4166Sjose borrego fault_status = NDR_FAULT_NCA_OP_RNG_ERROR; 710dc20a302Sas200622 break; 711dc20a302Sas200622 7128d7e4166Sjose borrego case NDR_DRC_FAULT_DECODE_FAILED: 7138d7e4166Sjose borrego case NDR_DRC_FAULT_ENCODE_FAILED: 7148d7e4166Sjose borrego fault_status = NDR_FAULT_NCA_PROTO_ERROR; 715dc20a302Sas200622 break; 716dc20a302Sas200622 717dc20a302Sas200622 default: 7188d7e4166Sjose borrego fault_status = NDR_FAULT_NCA_UNSPEC_REJECT; 719dc20a302Sas200622 break; 720dc20a302Sas200622 } 721dc20a302Sas200622 7228d7e4166Sjose borrego mxa->send_hdr.fault_hdr.common_hdr.ptype = NDR_PTYPE_FAULT; 723dc20a302Sas200622 mxa->send_hdr.fault_hdr.status = fault_status; 724dc20a302Sas200622 mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length; 725dc20a302Sas200622 } 726dc20a302Sas200622 7272c1b14e5Sjose borrego /* 7282c1b14e5Sjose borrego * Note that the frag_length for bind ack and alter context is 7292c1b14e5Sjose borrego * non-standard. 7302c1b14e5Sjose borrego */ 731dc20a302Sas200622 static int 732*68b2bbf2SGordon Ross ndr_send_reply(ndr_xa_t *mxa) 733dc20a302Sas200622 { 7342c1b14e5Sjose borrego ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 7358d7e4166Sjose borrego ndr_stream_t *nds = &mxa->send_nds; 73619d41fccSamw uint8_t *pdu_buf; 737dc20a302Sas200622 unsigned long pdu_size; 738dc20a302Sas200622 unsigned long frag_size; 739dc20a302Sas200622 unsigned long pdu_data_size; 740dc20a302Sas200622 unsigned long frag_data_size; 741dc20a302Sas200622 742*68b2bbf2SGordon Ross frag_size = mxa->pipe->np_max_recv_frag; 7438d7e4166Sjose borrego pdu_size = nds->pdu_size; 7448d7e4166Sjose borrego pdu_buf = nds->pdu_base_addr; 745dc20a302Sas200622 746dc20a302Sas200622 if (pdu_size <= frag_size) { 747dc20a302Sas200622 /* 748dc20a302Sas200622 * Single fragment response. The PDU size may be zero 749dc20a302Sas200622 * here (i.e. bind or fault response). So don't make 750dc20a302Sas200622 * any assumptions about it until after the header is 751dc20a302Sas200622 * encoded. 752dc20a302Sas200622 */ 753dc20a302Sas200622 switch (hdr->ptype) { 7548d7e4166Sjose borrego case NDR_PTYPE_BIND_ACK: 7558d7e4166Sjose borrego hdr->frag_length = ndr_bind_ack_hdr_size(mxa); 756dc20a302Sas200622 break; 757dc20a302Sas200622 7588d7e4166Sjose borrego case NDR_PTYPE_FAULT: 759dc20a302Sas200622 /* already setup */ 760dc20a302Sas200622 break; 761dc20a302Sas200622 7628d7e4166Sjose borrego case NDR_PTYPE_RESPONSE: 763dc20a302Sas200622 hdr->frag_length = pdu_size; 764dc20a302Sas200622 mxa->send_hdr.response_hdr.alloc_hint = 765dc20a302Sas200622 hdr->frag_length; 766dc20a302Sas200622 break; 767dc20a302Sas200622 7688d7e4166Sjose borrego case NDR_PTYPE_ALTER_CONTEXT_RESP: 7698d7e4166Sjose borrego hdr->frag_length = ndr_alter_context_rsp_hdr_size(); 7702c1b14e5Sjose borrego break; 7712c1b14e5Sjose borrego 772dc20a302Sas200622 default: 773dc20a302Sas200622 hdr->frag_length = pdu_size; 774dc20a302Sas200622 break; 775dc20a302Sas200622 } 776dc20a302Sas200622 7778d7e4166Sjose borrego nds->pdu_scan_offset = 0; 7788d7e4166Sjose borrego (void) ndr_encode_pdu_hdr(mxa); 7798d7e4166Sjose borrego pdu_size = nds->pdu_size; 780*68b2bbf2SGordon Ross (void) NDR_PIPE_SEND(mxa->pipe, pdu_buf, pdu_size); 781dc20a302Sas200622 return (0); 782dc20a302Sas200622 } 783dc20a302Sas200622 784dc20a302Sas200622 /* 785dc20a302Sas200622 * Multiple fragment response. 786*68b2bbf2SGordon Ross * 787*68b2bbf2SGordon Ross * We need to update the RPC header for every fragment. 788dc20a302Sas200622 * 789dc20a302Sas200622 * pdu_data_size: total data remaining to be handled 790dc20a302Sas200622 * frag_size: total fragment size including header 791dc20a302Sas200622 * frag_data_size: data in fragment 7928d7e4166Sjose borrego * (i.e. frag_size - NDR_RSP_HDR_SIZE) 793dc20a302Sas200622 */ 7948d7e4166Sjose borrego pdu_data_size = pdu_size - NDR_RSP_HDR_SIZE; 7958d7e4166Sjose borrego frag_data_size = frag_size - NDR_RSP_HDR_SIZE; 796dc20a302Sas200622 797*68b2bbf2SGordon Ross /* 798*68b2bbf2SGordon Ross * Send the first frag. 799*68b2bbf2SGordon Ross */ 800*68b2bbf2SGordon Ross hdr->pfc_flags = NDR_PFC_FIRST_FRAG; 801*68b2bbf2SGordon Ross hdr->frag_length = frag_size; 802*68b2bbf2SGordon Ross mxa->send_hdr.response_hdr.alloc_hint = pdu_data_size; 803*68b2bbf2SGordon Ross nds->pdu_scan_offset = 0; 804*68b2bbf2SGordon Ross (void) ndr_encode_pdu_hdr(mxa); 805*68b2bbf2SGordon Ross (void) NDR_PIPE_SEND(mxa->pipe, pdu_buf, frag_size); 80619d41fccSamw pdu_data_size -= frag_data_size; 80719d41fccSamw pdu_buf += frag_data_size; 808dc20a302Sas200622 809*68b2bbf2SGordon Ross /* 810*68b2bbf2SGordon Ross * Send "middle" (full-sized) fragments... 811*68b2bbf2SGordon Ross */ 81219d41fccSamw hdr->pfc_flags = 0; 813*68b2bbf2SGordon Ross while (pdu_data_size > frag_data_size) { 814dc20a302Sas200622 81519d41fccSamw hdr->frag_length = frag_size; 816*68b2bbf2SGordon Ross mxa->send_hdr.response_hdr.alloc_hint = pdu_data_size; 8178d7e4166Sjose borrego nds->pdu_scan_offset = 0; 8188d7e4166Sjose borrego (void) ndr_encode_pdu_hdr(mxa); 8198d7e4166Sjose borrego bcopy(nds->pdu_base_addr, pdu_buf, NDR_RSP_HDR_SIZE); 820*68b2bbf2SGordon Ross (void) NDR_PIPE_SEND(mxa->pipe, pdu_buf, frag_size); 821*68b2bbf2SGordon Ross pdu_data_size -= frag_data_size; 822*68b2bbf2SGordon Ross pdu_buf += frag_data_size; 823dc20a302Sas200622 } 82419d41fccSamw 82519d41fccSamw /* 826*68b2bbf2SGordon Ross * Last frag (pdu_data_size <= frag_data_size) 82719d41fccSamw */ 828*68b2bbf2SGordon Ross hdr->pfc_flags = NDR_PFC_LAST_FRAG; 829*68b2bbf2SGordon Ross frag_size = pdu_data_size + NDR_RSP_HDR_SIZE; 830*68b2bbf2SGordon Ross hdr->frag_length = frag_size; 831*68b2bbf2SGordon Ross mxa->send_hdr.response_hdr.alloc_hint = pdu_data_size; 832*68b2bbf2SGordon Ross nds->pdu_scan_offset = 0; 833*68b2bbf2SGordon Ross (void) ndr_encode_pdu_hdr(mxa); 834*68b2bbf2SGordon Ross bcopy(nds->pdu_base_addr, pdu_buf, NDR_RSP_HDR_SIZE); 835*68b2bbf2SGordon Ross (void) NDR_PIPE_SEND(mxa->pipe, pdu_buf, frag_size); 83619d41fccSamw 837*68b2bbf2SGordon Ross return (0); 83819d41fccSamw } 839