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