1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 24 * Copyright (c) 2018, Joyent, Inc. 25 */ 26 27 /* 28 * Server side RPC handler. 29 */ 30 31 #include <sys/byteorder.h> 32 #include <sys/uio.h> 33 #include <errno.h> 34 #include <synch.h> 35 #include <stdlib.h> 36 #include <strings.h> 37 #include <string.h> 38 #include <thread.h> 39 40 #include <libmlrpc.h> 41 42 #define NDR_PIPE_SEND(np, buf, len) \ 43 ((np)->np_send)((np), (buf), (len)) 44 #define NDR_PIPE_RECV(np, buf, len) \ 45 ((np)->np_recv)((np), (buf), (len)) 46 47 static int ndr_svc_process(ndr_xa_t *); 48 static int ndr_svc_bind(ndr_xa_t *); 49 static int ndr_svc_request(ndr_xa_t *); 50 static void ndr_reply_prepare_hdr(ndr_xa_t *); 51 static int ndr_svc_alter_context(ndr_xa_t *); 52 static void ndr_reply_fault(ndr_xa_t *, unsigned long); 53 54 static int ndr_recv_request(ndr_xa_t *mxa); 55 static int ndr_recv_frag(ndr_xa_t *mxa); 56 static int ndr_send_reply(ndr_xa_t *); 57 58 static int ndr_pipe_process(ndr_pipe_t *, ndr_xa_t *); 59 60 /* 61 * External entry point called by smbd. 62 */ 63 void 64 ndr_pipe_worker(ndr_pipe_t *np) 65 { 66 ndr_xa_t *mxa; 67 int rc; 68 69 ndr_svc_binding_pool_init(&np->np_binding, np->np_binding_pool, 70 NDR_N_BINDING_POOL); 71 72 if ((mxa = malloc(sizeof (*mxa))) == NULL) 73 return; 74 75 do { 76 bzero(mxa, sizeof (*mxa)); 77 rc = ndr_pipe_process(np, mxa); 78 } while (rc == 0); 79 80 free(mxa); 81 82 /* 83 * Ensure that there are no RPC service policy handles 84 * (associated with this fid) left around. 85 */ 86 ndr_hdclose(np); 87 } 88 89 /* 90 * Process one server-side RPC request. 91 */ 92 static int 93 ndr_pipe_process(ndr_pipe_t *np, ndr_xa_t *mxa) 94 { 95 ndr_stream_t *recv_nds; 96 ndr_stream_t *send_nds; 97 int rc = ENOMEM; 98 99 mxa->pipe = np; 100 mxa->binding_list = np->np_binding; 101 102 if ((mxa->heap = ndr_heap_create()) == NULL) 103 goto out1; 104 105 recv_nds = &mxa->recv_nds; 106 rc = nds_initialize(recv_nds, 0, NDR_MODE_CALL_RECV, mxa->heap); 107 if (rc != 0) 108 goto out2; 109 110 send_nds = &mxa->send_nds; 111 rc = nds_initialize(send_nds, 0, NDR_MODE_RETURN_SEND, mxa->heap); 112 if (rc != 0) 113 goto out3; 114 115 rc = ndr_recv_request(mxa); 116 if (rc != 0) 117 goto out4; 118 119 (void) ndr_svc_process(mxa); 120 (void) ndr_send_reply(mxa); 121 rc = 0; 122 123 out4: 124 nds_destruct(&mxa->send_nds); 125 out3: 126 nds_destruct(&mxa->recv_nds); 127 out2: 128 ndr_heap_destroy(mxa->heap); 129 out1: 130 return (rc); 131 } 132 133 /* 134 * Receive an entire RPC request (all fragments) 135 * Returns zero or an NDR fault code. 136 */ 137 static int 138 ndr_recv_request(ndr_xa_t *mxa) 139 { 140 ndr_common_header_t *hdr = &mxa->recv_hdr.common_hdr; 141 ndr_stream_t *nds = &mxa->recv_nds; 142 unsigned long saved_size; 143 int rc; 144 145 rc = ndr_recv_frag(mxa); 146 if (rc != 0) 147 return (rc); 148 if (!NDR_IS_FIRST_FRAG(hdr->pfc_flags)) 149 return (NDR_DRC_FAULT_DECODE_FAILED); 150 151 while (!NDR_IS_LAST_FRAG(hdr->pfc_flags)) { 152 rc = ndr_recv_frag(mxa); 153 if (rc != 0) 154 return (rc); 155 } 156 nds->pdu_scan_offset = 0; 157 158 /* 159 * This whacks nds->pdu_size, so save/restore. 160 * It leaves scan_offset after the header. 161 */ 162 saved_size = nds->pdu_size; 163 rc = ndr_decode_pdu_hdr(mxa); 164 nds->pdu_size = saved_size; 165 166 return (rc); 167 } 168 169 /* 170 * Read one fragment, leaving the decoded frag header in 171 * recv_hdr.common_hdr, and the data in the recv_nds. 172 * 173 * Returns zero or an NDR fault code. 174 * 175 * If a first frag, the header is included in the data 176 * placed in recv_nds (because it's not fully decoded 177 * until later - we only decode the common part here). 178 * Additional frags are placed in the recv_nds without 179 * the header, so that after the first frag header, 180 * the remaining data will be contiguous. We do this 181 * by simply not advancing the offset in recv_nds after 182 * reading and decoding these additional fragments, so 183 * the payload of such frags will overwrite what was 184 * (temporarily) the frag header. 185 */ 186 static int 187 ndr_recv_frag(ndr_xa_t *mxa) 188 { 189 ndr_common_header_t *hdr = &mxa->recv_hdr.common_hdr; 190 ndr_stream_t *nds = &mxa->recv_nds; 191 unsigned char *data; 192 unsigned long next_offset; 193 unsigned long pay_size; 194 int rc; 195 196 /* Make room for the frag header. */ 197 next_offset = nds->pdu_scan_offset + NDR_RSP_HDR_SIZE; 198 if (!NDS_GROW_PDU(nds, next_offset, 0)) 199 return (NDR_DRC_FAULT_OUT_OF_MEMORY); 200 201 /* Read the frag header. */ 202 data = nds->pdu_base_addr + nds->pdu_scan_offset; 203 rc = NDR_PIPE_RECV(mxa->pipe, data, NDR_RSP_HDR_SIZE); 204 if (rc != 0) 205 return (NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT); 206 207 /* 208 * Decode the frag header, get the length. 209 * NB: It uses nds->pdu_scan_offset 210 */ 211 ndr_decode_frag_hdr(nds, hdr); 212 ndr_show_hdr(hdr); 213 if (hdr->frag_length < NDR_RSP_HDR_SIZE || 214 hdr->frag_length > mxa->pipe->np_max_xmit_frag) 215 return (NDR_DRC_FAULT_DECODE_FAILED); 216 217 if (nds->pdu_scan_offset == 0) { 218 /* First frag: header stays in the data. */ 219 nds->pdu_scan_offset = next_offset; 220 } /* else overwrite with the payload */ 221 222 /* Make room for the payload. */ 223 pay_size = hdr->frag_length - NDR_RSP_HDR_SIZE; 224 next_offset = nds->pdu_scan_offset + pay_size; 225 if (!NDS_GROW_PDU(nds, next_offset, 0)) 226 return (NDR_DRC_FAULT_OUT_OF_MEMORY); 227 228 /* Read the payload. */ 229 data = nds->pdu_base_addr + nds->pdu_scan_offset; 230 rc = NDR_PIPE_RECV(mxa->pipe, data, pay_size); 231 if (rc != 0) 232 return (NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT); 233 nds->pdu_scan_offset = next_offset; 234 235 return (NDR_DRC_OK); 236 } 237 238 /* 239 * This is the entry point for all server-side RPC processing. 240 * It is assumed that the PDU has already been received. 241 */ 242 static int 243 ndr_svc_process(ndr_xa_t *mxa) 244 { 245 int rc; 246 247 (void) ndr_reply_prepare_hdr(mxa); 248 249 switch (mxa->ptype) { 250 case NDR_PTYPE_BIND: 251 rc = ndr_svc_bind(mxa); 252 break; 253 254 case NDR_PTYPE_REQUEST: 255 rc = ndr_svc_request(mxa); 256 break; 257 258 case NDR_PTYPE_ALTER_CONTEXT: 259 rc = ndr_svc_alter_context(mxa); 260 break; 261 262 default: 263 rc = NDR_DRC_FAULT_RPCHDR_PTYPE_INVALID; 264 break; 265 } 266 267 if (NDR_DRC_IS_FAULT(rc)) 268 ndr_reply_fault(mxa, rc); 269 270 return (rc); 271 } 272 273 /* 274 * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple 275 * p_results[] not supported. 276 */ 277 static int 278 ndr_svc_bind(ndr_xa_t *mxa) 279 { 280 ndr_p_cont_list_t *cont_list; 281 ndr_p_result_list_t *result_list; 282 ndr_p_result_t *result; 283 unsigned p_cont_id; 284 ndr_binding_t *mbind; 285 ndr_uuid_t *as_uuid; 286 ndr_uuid_t *ts_uuid; 287 int as_vers; 288 int ts_vers; 289 ndr_service_t *msvc; 290 int rc; 291 ndr_port_any_t *sec_addr; 292 293 /* acquire targets */ 294 cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem; 295 result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list; 296 result = &result_list->p_results[0]; 297 298 /* 299 * Set up temporary secondary address port. 300 * We will correct this later (below). 301 */ 302 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 303 sec_addr->length = 13; 304 (void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs"); 305 306 result_list->n_results = 1; 307 result_list->reserved = 0; 308 result_list->reserved2 = 0; 309 result->result = NDR_PCDR_ACCEPTANCE; 310 result->reason = 0; 311 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax)); 312 313 /* sanity check */ 314 if (cont_list->n_context_elem != 1 || 315 cont_list->p_cont_elem[0].n_transfer_syn != 1) { 316 ndo_trace("ndr_svc_bind: warning: multiple p_cont_elem"); 317 } 318 319 p_cont_id = cont_list->p_cont_elem[0].p_cont_id; 320 321 if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) != NULL) { 322 /* 323 * Duplicate presentation context id. 324 */ 325 ndo_trace("ndr_svc_bind: duplicate binding"); 326 return (NDR_DRC_FAULT_BIND_PCONT_BUSY); 327 } 328 329 if ((mbind = ndr_svc_new_binding(mxa)) == NULL) { 330 /* 331 * No free binding slot 332 */ 333 result->result = NDR_PCDR_PROVIDER_REJECTION; 334 result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED; 335 ndo_trace("ndr_svc_bind: no resources"); 336 return (NDR_DRC_OK); 337 } 338 339 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid; 340 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version; 341 342 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid; 343 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version; 344 345 msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers); 346 if (msvc == NULL) { 347 result->result = NDR_PCDR_PROVIDER_REJECTION; 348 result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 349 return (NDR_DRC_OK); 350 } 351 352 /* 353 * We can now use the correct secondary address port. 354 */ 355 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 356 sec_addr->length = strlen(msvc->sec_addr_port) + 1; 357 (void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port, 358 NDR_PORT_ANY_MAX_PORT_SPEC); 359 360 mbind->p_cont_id = p_cont_id; 361 mbind->which_side = NDR_BIND_SIDE_SERVER; 362 /* mbind->context set by app */ 363 mbind->service = msvc; 364 mbind->instance_specific = 0; 365 366 mxa->binding = mbind; 367 368 if (msvc->bind_req) { 369 /* 370 * Call the service-specific bind() handler. If 371 * this fails, we shouild send a specific error 372 * on the bind ack. 373 */ 374 rc = (msvc->bind_req)(mxa); 375 if (NDR_DRC_IS_FAULT(rc)) { 376 mbind->service = 0; /* free binding slot */ 377 mbind->which_side = 0; 378 mbind->p_cont_id = 0; 379 mbind->instance_specific = 0; 380 return (rc); 381 } 382 } 383 384 result->transfer_syntax = 385 cont_list->p_cont_elem[0].transfer_syntaxes[0]; 386 387 return (NDR_DRC_BINDING_MADE); 388 } 389 390 /* 391 * ndr_svc_alter_context 392 * 393 * The alter context request is used to request additional presentation 394 * context for another interface and/or version. It is very similar to 395 * a bind request. 396 */ 397 static int 398 ndr_svc_alter_context(ndr_xa_t *mxa) 399 { 400 ndr_p_result_list_t *result_list; 401 ndr_p_result_t *result; 402 ndr_p_cont_list_t *cont_list; 403 ndr_binding_t *mbind; 404 ndr_service_t *msvc; 405 unsigned p_cont_id; 406 ndr_uuid_t *as_uuid; 407 ndr_uuid_t *ts_uuid; 408 int as_vers; 409 int ts_vers; 410 ndr_port_any_t *sec_addr; 411 412 result_list = &mxa->send_hdr.alter_context_rsp_hdr.p_result_list; 413 result_list->n_results = 1; 414 result_list->reserved = 0; 415 result_list->reserved2 = 0; 416 417 result = &result_list->p_results[0]; 418 result->result = NDR_PCDR_ACCEPTANCE; 419 result->reason = 0; 420 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax)); 421 422 cont_list = &mxa->recv_hdr.alter_context_hdr.p_context_elem; 423 p_cont_id = cont_list->p_cont_elem[0].p_cont_id; 424 425 if (ndr_svc_find_binding(mxa, p_cont_id) != NULL) 426 return (NDR_DRC_FAULT_BIND_PCONT_BUSY); 427 428 if ((mbind = ndr_svc_new_binding(mxa)) == NULL) { 429 result->result = NDR_PCDR_PROVIDER_REJECTION; 430 result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED; 431 return (NDR_DRC_OK); 432 } 433 434 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid; 435 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version; 436 437 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid; 438 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version; 439 440 msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers); 441 if (msvc == NULL) { 442 result->result = NDR_PCDR_PROVIDER_REJECTION; 443 result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 444 return (NDR_DRC_OK); 445 } 446 447 mbind->p_cont_id = p_cont_id; 448 mbind->which_side = NDR_BIND_SIDE_SERVER; 449 /* mbind->context set by app */ 450 mbind->service = msvc; 451 mbind->instance_specific = 0; 452 mxa->binding = mbind; 453 454 sec_addr = &mxa->send_hdr.alter_context_rsp_hdr.sec_addr; 455 sec_addr->length = 0; 456 bzero(sec_addr->port_spec, NDR_PORT_ANY_MAX_PORT_SPEC); 457 458 result->transfer_syntax = 459 cont_list->p_cont_elem[0].transfer_syntaxes[0]; 460 461 return (NDR_DRC_BINDING_MADE); 462 } 463 464 static int 465 ndr_svc_request(ndr_xa_t *mxa) 466 { 467 ndr_binding_t *mbind; 468 ndr_service_t *msvc; 469 unsigned p_cont_id; 470 int rc; 471 472 mxa->opnum = mxa->recv_hdr.request_hdr.opnum; 473 p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id; 474 475 if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) == NULL) 476 return (NDR_DRC_FAULT_REQUEST_PCONT_INVALID); 477 478 mxa->binding = mbind; 479 msvc = mbind->service; 480 481 /* 482 * Make room for the response hdr. 483 */ 484 mxa->send_nds.pdu_scan_offset = NDR_RSP_HDR_SIZE; 485 486 if (msvc->call_stub) 487 rc = (*msvc->call_stub)(mxa); 488 else 489 rc = ndr_generic_call_stub(mxa); 490 491 if (NDR_DRC_IS_FAULT(rc)) { 492 ndo_printf(0, 0, "%s[0x%02x]: 0x%04x", 493 msvc->name, mxa->opnum, rc); 494 } 495 496 return (rc); 497 } 498 499 /* 500 * The transaction and the two nds streams use the same heap, which 501 * should already exist at this point. The heap will also be available 502 * to the stub. 503 */ 504 int 505 ndr_generic_call_stub(ndr_xa_t *mxa) 506 { 507 ndr_binding_t *mbind = mxa->binding; 508 ndr_service_t *msvc = mbind->service; 509 ndr_typeinfo_t *intf_ti = msvc->interface_ti; 510 ndr_stub_table_t *ste; 511 int opnum = mxa->opnum; 512 unsigned p_len = intf_ti->c_size_fixed_part; 513 char *param; 514 int rc; 515 516 if (mxa->heap == NULL) { 517 ndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum); 518 return (NDR_DRC_FAULT_OUT_OF_MEMORY); 519 } 520 521 if ((ste = ndr_svc_find_stub(msvc, opnum)) == NULL) { 522 ndo_printf(0, 0, "%s[0x%02x]: invalid opnum", 523 msvc->name, opnum); 524 return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID); 525 } 526 527 if ((param = ndr_heap_malloc(mxa->heap, p_len)) == NULL) 528 return (NDR_DRC_FAULT_OUT_OF_MEMORY); 529 530 bzero(param, p_len); 531 532 rc = ndr_decode_call(mxa, param); 533 if (!NDR_DRC_IS_OK(rc)) 534 return (rc); 535 536 rc = (*ste->func)(param, mxa); 537 if (rc == NDR_DRC_OK) 538 rc = ndr_encode_return(mxa, param); 539 540 return (rc); 541 } 542 543 /* 544 * We can perform some initial setup of the response header here. 545 * We also need to cache some of the information from the bind 546 * negotiation for use during subsequent RPC calls. 547 */ 548 static void 549 ndr_reply_prepare_hdr(ndr_xa_t *mxa) 550 { 551 ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr; 552 ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 553 554 hdr->rpc_vers = 5; 555 hdr->rpc_vers_minor = 0; 556 hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG; 557 hdr->packed_drep = rhdr->packed_drep; 558 hdr->frag_length = 0; 559 hdr->auth_length = 0; 560 hdr->call_id = rhdr->call_id; 561 #ifdef _BIG_ENDIAN 562 hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII 563 | NDR_REPLAB_INTG_BIG_ENDIAN; 564 #else 565 hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII 566 | NDR_REPLAB_INTG_LITTLE_ENDIAN; 567 #endif 568 569 switch (mxa->ptype) { 570 case NDR_PTYPE_BIND: 571 /* 572 * Compute the maximum fragment sizes for xmit/recv 573 * and store in the pipe endpoint. Note "xmit" is 574 * client-to-server; "recv" is server-to-client. 575 */ 576 if (mxa->pipe->np_max_xmit_frag > 577 mxa->recv_hdr.bind_hdr.max_xmit_frag) 578 mxa->pipe->np_max_xmit_frag = 579 mxa->recv_hdr.bind_hdr.max_xmit_frag; 580 if (mxa->pipe->np_max_recv_frag > 581 mxa->recv_hdr.bind_hdr.max_recv_frag) 582 mxa->pipe->np_max_recv_frag = 583 mxa->recv_hdr.bind_hdr.max_recv_frag; 584 585 hdr->ptype = NDR_PTYPE_BIND_ACK; 586 mxa->send_hdr.bind_ack_hdr.max_xmit_frag = 587 mxa->pipe->np_max_xmit_frag; 588 mxa->send_hdr.bind_ack_hdr.max_recv_frag = 589 mxa->pipe->np_max_recv_frag; 590 591 /* 592 * We're supposed to assign a unique "assoc group" 593 * (identifies this connection for the client). 594 * Using the pipe address is adequate. 595 */ 596 mxa->send_hdr.bind_ack_hdr.assoc_group_id = 597 mxa->recv_hdr.bind_hdr.assoc_group_id; 598 if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0) 599 mxa->send_hdr.bind_ack_hdr.assoc_group_id = 600 (DWORD)(uintptr_t)mxa->pipe; 601 602 break; 603 604 case NDR_PTYPE_REQUEST: 605 hdr->ptype = NDR_PTYPE_RESPONSE; 606 /* mxa->send_hdr.response_hdr.alloc_hint */ 607 mxa->send_hdr.response_hdr.p_cont_id = 608 mxa->recv_hdr.request_hdr.p_cont_id; 609 mxa->send_hdr.response_hdr.cancel_count = 0; 610 mxa->send_hdr.response_hdr.reserved = 0; 611 break; 612 613 case NDR_PTYPE_ALTER_CONTEXT: 614 hdr->ptype = NDR_PTYPE_ALTER_CONTEXT_RESP; 615 /* 616 * The max_xmit_frag, max_recv_frag and assoc_group_id are 617 * ignored by the client but it's useful to fill them in. 618 */ 619 mxa->send_hdr.alter_context_rsp_hdr.max_xmit_frag = 620 mxa->recv_hdr.alter_context_hdr.max_xmit_frag; 621 mxa->send_hdr.alter_context_rsp_hdr.max_recv_frag = 622 mxa->recv_hdr.alter_context_hdr.max_recv_frag; 623 mxa->send_hdr.alter_context_rsp_hdr.assoc_group_id = 624 mxa->recv_hdr.alter_context_hdr.assoc_group_id; 625 break; 626 627 default: 628 hdr->ptype = 0xFF; 629 } 630 } 631 632 /* 633 * Signal an RPC fault. The stream is reset and we overwrite whatever 634 * was in the response header with the fault information. 635 */ 636 static void 637 ndr_reply_fault(ndr_xa_t *mxa, unsigned long drc) 638 { 639 ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr; 640 ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 641 ndr_stream_t *nds = &mxa->send_nds; 642 unsigned long fault_status; 643 644 (void) NDS_RESET(nds); 645 646 hdr->rpc_vers = 5; 647 hdr->rpc_vers_minor = 0; 648 hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG; 649 hdr->packed_drep = rhdr->packed_drep; 650 hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr); 651 hdr->auth_length = 0; 652 hdr->call_id = rhdr->call_id; 653 #ifdef _BIG_ENDIAN 654 hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII 655 | NDR_REPLAB_INTG_BIG_ENDIAN; 656 #else 657 hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII 658 | NDR_REPLAB_INTG_LITTLE_ENDIAN; 659 #endif 660 661 switch (drc & NDR_DRC_MASK_SPECIFIER) { 662 case NDR_DRC_FAULT_OUT_OF_MEMORY: 663 case NDR_DRC_FAULT_ENCODE_TOO_BIG: 664 fault_status = NDR_FAULT_NCA_OUT_ARGS_TOO_BIG; 665 break; 666 667 case NDR_DRC_FAULT_REQUEST_PCONT_INVALID: 668 fault_status = NDR_FAULT_NCA_INVALID_PRES_CONTEXT_ID; 669 break; 670 671 case NDR_DRC_FAULT_REQUEST_OPNUM_INVALID: 672 fault_status = NDR_FAULT_NCA_OP_RNG_ERROR; 673 break; 674 675 case NDR_DRC_FAULT_DECODE_FAILED: 676 case NDR_DRC_FAULT_ENCODE_FAILED: 677 fault_status = NDR_FAULT_NCA_PROTO_ERROR; 678 break; 679 680 default: 681 fault_status = NDR_FAULT_NCA_UNSPEC_REJECT; 682 break; 683 } 684 685 mxa->send_hdr.fault_hdr.common_hdr.ptype = NDR_PTYPE_FAULT; 686 mxa->send_hdr.fault_hdr.status = fault_status; 687 mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length; 688 } 689 690 /* 691 * Note that the frag_length for bind ack and alter context is 692 * non-standard. 693 */ 694 static int 695 ndr_send_reply(ndr_xa_t *mxa) 696 { 697 ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 698 ndr_stream_t *nds = &mxa->send_nds; 699 uint8_t *pdu_buf; 700 unsigned long pdu_size; 701 unsigned long frag_size; 702 unsigned long pdu_data_size; 703 unsigned long frag_data_size; 704 705 frag_size = mxa->pipe->np_max_recv_frag; 706 pdu_size = nds->pdu_size; 707 pdu_buf = nds->pdu_base_addr; 708 709 if (pdu_size <= frag_size) { 710 /* 711 * Single fragment response. The PDU size may be zero 712 * here (i.e. bind or fault response). So don't make 713 * any assumptions about it until after the header is 714 * encoded. 715 */ 716 switch (hdr->ptype) { 717 case NDR_PTYPE_BIND_ACK: 718 hdr->frag_length = ndr_bind_ack_hdr_size(mxa); 719 break; 720 721 case NDR_PTYPE_FAULT: 722 /* already setup */ 723 break; 724 725 case NDR_PTYPE_RESPONSE: 726 hdr->frag_length = pdu_size; 727 mxa->send_hdr.response_hdr.alloc_hint = 728 hdr->frag_length; 729 break; 730 731 case NDR_PTYPE_ALTER_CONTEXT_RESP: 732 hdr->frag_length = ndr_alter_context_rsp_hdr_size(); 733 break; 734 735 default: 736 hdr->frag_length = pdu_size; 737 break; 738 } 739 740 nds->pdu_scan_offset = 0; 741 (void) ndr_encode_pdu_hdr(mxa); 742 pdu_size = nds->pdu_size; 743 (void) NDR_PIPE_SEND(mxa->pipe, pdu_buf, pdu_size); 744 return (0); 745 } 746 747 /* 748 * Multiple fragment response. 749 * 750 * We need to update the RPC header for every fragment. 751 * 752 * pdu_data_size: total data remaining to be handled 753 * frag_size: total fragment size including header 754 * frag_data_size: data in fragment 755 * (i.e. frag_size - NDR_RSP_HDR_SIZE) 756 */ 757 pdu_data_size = pdu_size - NDR_RSP_HDR_SIZE; 758 frag_data_size = frag_size - NDR_RSP_HDR_SIZE; 759 760 /* 761 * Send the first frag. 762 */ 763 hdr->pfc_flags = NDR_PFC_FIRST_FRAG; 764 hdr->frag_length = frag_size; 765 mxa->send_hdr.response_hdr.alloc_hint = pdu_data_size; 766 nds->pdu_scan_offset = 0; 767 (void) ndr_encode_pdu_hdr(mxa); 768 (void) NDR_PIPE_SEND(mxa->pipe, pdu_buf, frag_size); 769 pdu_data_size -= frag_data_size; 770 pdu_buf += frag_data_size; 771 772 /* 773 * Send "middle" (full-sized) fragments... 774 */ 775 hdr->pfc_flags = 0; 776 while (pdu_data_size > frag_data_size) { 777 778 hdr->frag_length = frag_size; 779 mxa->send_hdr.response_hdr.alloc_hint = pdu_data_size; 780 nds->pdu_scan_offset = 0; 781 (void) ndr_encode_pdu_hdr(mxa); 782 bcopy(nds->pdu_base_addr, pdu_buf, NDR_RSP_HDR_SIZE); 783 (void) NDR_PIPE_SEND(mxa->pipe, pdu_buf, frag_size); 784 pdu_data_size -= frag_data_size; 785 pdu_buf += frag_data_size; 786 } 787 788 /* 789 * Last frag (pdu_data_size <= frag_data_size) 790 */ 791 hdr->pfc_flags = NDR_PFC_LAST_FRAG; 792 frag_size = pdu_data_size + NDR_RSP_HDR_SIZE; 793 hdr->frag_length = frag_size; 794 mxa->send_hdr.response_hdr.alloc_hint = pdu_data_size; 795 nds->pdu_scan_offset = 0; 796 (void) ndr_encode_pdu_hdr(mxa); 797 bcopy(nds->pdu_base_addr, pdu_buf, NDR_RSP_HDR_SIZE); 798 (void) NDR_PIPE_SEND(mxa->pipe, pdu_buf, frag_size); 799 800 return (0); 801 }