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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Server side RPC handler. 28 */ 29 30 #include <sys/byteorder.h> 31 #include <sys/errno.h> 32 #include <sys/uio.h> 33 #include <thread.h> 34 #include <synch.h> 35 #include <stdlib.h> 36 #include <strings.h> 37 #include <string.h> 38 #include <time.h> 39 40 #include <smbsrv/libsmb.h> 41 #include <smbsrv/libmlrpc.h> 42 #include <smbsrv/ntaccess.h> 43 44 /* 45 * Fragment size (5680: NT style). 46 */ 47 #define NDR_FRAG_SZ 5680 48 49 #define NDR_PIPE_BUFSZ 65536 50 #define NDR_PIPE_MAX 128 51 static ndr_pipe_t ndr_pipe_table[NDR_PIPE_MAX]; 52 static mutex_t ndr_pipe_lock; 53 54 static int ndr_pipe_transact(ndr_pipe_t *); 55 static ndr_pipe_t *ndr_pipe_lookup(int); 56 static void ndr_pipe_release(ndr_pipe_t *); 57 static ndr_pipe_t *ndr_pipe_allocate(int); 58 static void ndr_pipe_deallocate(ndr_pipe_t *); 59 static void ndr_pipe_rewind(ndr_pipe_t *); 60 static void ndr_pipe_flush(ndr_pipe_t *); 61 62 static int ndr_svc_process(ndr_xa_t *); 63 static int ndr_svc_bind(ndr_xa_t *); 64 static int ndr_svc_request(ndr_xa_t *); 65 static void ndr_reply_prepare_hdr(ndr_xa_t *); 66 static int ndr_svc_alter_context(ndr_xa_t *); 67 static void ndr_reply_fault(ndr_xa_t *, unsigned long); 68 static int ndr_build_reply(ndr_xa_t *); 69 static void ndr_build_frag(ndr_stream_t *, uint8_t *, uint32_t); 70 71 /* 72 * Allocate and associate a service context with a fid. 73 */ 74 int 75 ndr_pipe_open(int fid, uint8_t *data, uint32_t datalen) 76 { 77 ndr_pipe_t *np; 78 79 (void) mutex_lock(&ndr_pipe_lock); 80 81 if ((np = ndr_pipe_lookup(fid)) != NULL) { 82 ndr_pipe_release(np); 83 (void) mutex_unlock(&ndr_pipe_lock); 84 return (EEXIST); 85 } 86 87 if ((np = ndr_pipe_allocate(fid)) == NULL) { 88 (void) mutex_unlock(&ndr_pipe_lock); 89 return (ENOMEM); 90 } 91 92 if (smb_netuserinfo_decode(&np->np_user, data, datalen, NULL) == -1) { 93 ndr_pipe_release(np); 94 (void) mutex_unlock(&ndr_pipe_lock); 95 return (EINVAL); 96 } 97 98 ndr_svc_binding_pool_init(&np->np_binding, np->np_binding_pool, 99 NDR_N_BINDING_POOL); 100 101 (void) mutex_unlock(&ndr_pipe_lock); 102 return (0); 103 } 104 105 /* 106 * Release the context associated with a fid when an opipe is closed. 107 */ 108 int 109 ndr_pipe_close(int fid) 110 { 111 ndr_pipe_t *np; 112 113 (void) mutex_lock(&ndr_pipe_lock); 114 115 if ((np = ndr_pipe_lookup(fid)) == NULL) { 116 (void) mutex_unlock(&ndr_pipe_lock); 117 return (ENOENT); 118 } 119 120 /* 121 * Release twice: once for the lookup above 122 * and again to close the fid. 123 */ 124 ndr_pipe_release(np); 125 ndr_pipe_release(np); 126 (void) mutex_unlock(&ndr_pipe_lock); 127 return (0); 128 } 129 130 /* 131 * Write RPC request data to the input stream. Input data is buffered 132 * until the response is requested. 133 */ 134 int 135 ndr_pipe_write(int fid, uint8_t *buf, uint32_t len) 136 { 137 ndr_pipe_t *np; 138 ssize_t nbytes; 139 140 if (len == 0) 141 return (0); 142 143 (void) mutex_lock(&ndr_pipe_lock); 144 145 if ((np = ndr_pipe_lookup(fid)) == NULL) { 146 (void) mutex_unlock(&ndr_pipe_lock); 147 return (ENOENT); 148 } 149 150 nbytes = ndr_uiomove((caddr_t)buf, len, UIO_READ, &np->np_uio); 151 152 ndr_pipe_release(np); 153 (void) mutex_unlock(&ndr_pipe_lock); 154 return ((nbytes == len) ? 0 : EIO); 155 } 156 157 /* 158 * Read RPC response data. If the input stream contains an RPC request, 159 * we need to process the RPC transaction, which will place the RPC 160 * response in the output (frags) stream. Otherwise, read data from 161 * the output stream. 162 */ 163 int 164 ndr_pipe_read(int fid, uint8_t *buf, uint32_t *len, uint32_t *resid) 165 { 166 ndr_pipe_t *np; 167 ssize_t nbytes = *len; 168 int rc; 169 170 if (nbytes == 0) { 171 *resid = 0; 172 return (0); 173 } 174 175 (void) mutex_lock(&ndr_pipe_lock); 176 if ((np = ndr_pipe_lookup(fid)) == NULL) { 177 (void) mutex_unlock(&ndr_pipe_lock); 178 return (ENOENT); 179 } 180 (void) mutex_unlock(&ndr_pipe_lock); 181 182 if (np->np_uio.uio_offset) { 183 if ((rc = ndr_pipe_transact(np)) != 0) { 184 ndr_pipe_flush(np); 185 (void) mutex_lock(&ndr_pipe_lock); 186 ndr_pipe_release(np); 187 (void) mutex_unlock(&ndr_pipe_lock); 188 return (rc); 189 } 190 191 } 192 193 *len = ndr_uiomove((caddr_t)buf, nbytes, UIO_WRITE, &np->np_frags.uio); 194 *resid = np->np_frags.uio.uio_resid; 195 196 if (*resid == 0) { 197 /* 198 * Nothing left, cleanup the output stream. 199 */ 200 ndr_pipe_flush(np); 201 } 202 203 (void) mutex_lock(&ndr_pipe_lock); 204 ndr_pipe_release(np); 205 (void) mutex_unlock(&ndr_pipe_lock); 206 return (0); 207 } 208 209 /* 210 * Process a server-side RPC request. 211 */ 212 static int 213 ndr_pipe_transact(ndr_pipe_t *np) 214 { 215 ndr_xa_t *mxa; 216 ndr_stream_t *recv_nds; 217 ndr_stream_t *send_nds; 218 char *data; 219 int datalen; 220 221 data = np->np_buf; 222 datalen = np->np_uio.uio_offset; 223 224 if ((mxa = (ndr_xa_t *)malloc(sizeof (ndr_xa_t))) == NULL) 225 return (ENOMEM); 226 227 bzero(mxa, sizeof (ndr_xa_t)); 228 mxa->fid = np->np_fid; 229 mxa->pipe = np; 230 mxa->binding_list = np->np_binding; 231 232 if ((mxa->heap = ndr_heap_create()) == NULL) { 233 free(mxa); 234 return (ENOMEM); 235 } 236 237 recv_nds = &mxa->recv_nds; 238 nds_initialize(recv_nds, datalen, NDR_MODE_CALL_RECV, mxa->heap); 239 240 /* 241 * Copy the input data and reset the input stream. 242 */ 243 bcopy(data, recv_nds->pdu_base_addr, datalen); 244 ndr_pipe_rewind(np); 245 246 send_nds = &mxa->send_nds; 247 nds_initialize(send_nds, 0, NDR_MODE_RETURN_SEND, mxa->heap); 248 249 (void) ndr_svc_process(mxa); 250 251 nds_finalize(send_nds, &np->np_frags); 252 nds_destruct(&mxa->recv_nds); 253 nds_destruct(&mxa->send_nds); 254 ndr_heap_destroy(mxa->heap); 255 free(mxa); 256 return (0); 257 } 258 259 /* 260 * Must be called with ndr_pipe_lock held. 261 */ 262 static ndr_pipe_t * 263 ndr_pipe_lookup(int fid) 264 { 265 ndr_pipe_t *np; 266 int i; 267 268 for (i = 0; i < NDR_PIPE_MAX; ++i) { 269 np = &ndr_pipe_table[i]; 270 271 if (np->np_fid == fid) { 272 if (np->np_refcnt == 0) 273 return (NULL); 274 275 np->np_refcnt++; 276 return (np); 277 } 278 } 279 280 return (NULL); 281 } 282 283 /* 284 * Must be called with ndr_pipe_lock held. 285 */ 286 static void 287 ndr_pipe_release(ndr_pipe_t *np) 288 { 289 np->np_refcnt--; 290 ndr_pipe_deallocate(np); 291 } 292 293 /* 294 * Must be called with ndr_pipe_lock held. 295 */ 296 static ndr_pipe_t * 297 ndr_pipe_allocate(int fid) 298 { 299 ndr_pipe_t *np = NULL; 300 int i; 301 302 for (i = 0; i < NDR_PIPE_MAX; ++i) { 303 np = &ndr_pipe_table[i]; 304 305 if (np->np_fid == 0) { 306 bzero(np, sizeof (ndr_pipe_t)); 307 308 if ((np->np_buf = malloc(NDR_PIPE_BUFSZ)) == NULL) 309 return (NULL); 310 311 ndr_pipe_rewind(np); 312 np->np_fid = fid; 313 np->np_refcnt = 1; 314 return (np); 315 } 316 } 317 318 return (NULL); 319 } 320 321 /* 322 * Must be called with ndr_pipe_lock held. 323 */ 324 static void 325 ndr_pipe_deallocate(ndr_pipe_t *np) 326 { 327 if (np->np_refcnt == 0) { 328 /* 329 * Ensure that there are no RPC service policy handles 330 * (associated with this fid) left around. 331 */ 332 ndr_hdclose(np->np_fid); 333 334 ndr_pipe_rewind(np); 335 ndr_pipe_flush(np); 336 free(np->np_buf); 337 free(np->np_user.ui_domain); 338 free(np->np_user.ui_account); 339 free(np->np_user.ui_workstation); 340 bzero(np, sizeof (ndr_pipe_t)); 341 } 342 } 343 344 /* 345 * Rewind the input data stream, ready for the next write. 346 */ 347 static void 348 ndr_pipe_rewind(ndr_pipe_t *np) 349 { 350 np->np_uio.uio_iov = &np->np_iov; 351 np->np_uio.uio_iovcnt = 1; 352 np->np_uio.uio_offset = 0; 353 np->np_uio.uio_segflg = UIO_USERSPACE; 354 np->np_uio.uio_resid = NDR_PIPE_BUFSZ; 355 np->np_iov.iov_base = np->np_buf; 356 np->np_iov.iov_len = NDR_PIPE_BUFSZ; 357 } 358 359 /* 360 * Flush the output data stream. 361 */ 362 static void 363 ndr_pipe_flush(ndr_pipe_t *np) 364 { 365 ndr_frag_t *frag; 366 367 while ((frag = np->np_frags.head) != NULL) { 368 np->np_frags.head = frag->next; 369 free(frag); 370 } 371 372 free(np->np_frags.iov); 373 bzero(&np->np_frags, sizeof (ndr_fraglist_t)); 374 } 375 376 /* 377 * Check whether or not the specified user has administrator privileges, 378 * i.e. is a member of Domain Admins or Administrators. 379 * Returns true if the user is an administrator, otherwise returns false. 380 */ 381 boolean_t 382 ndr_is_admin(ndr_xa_t *xa) 383 { 384 smb_netuserinfo_t *ctx = &xa->pipe->np_user; 385 386 return (ctx->ui_flags & SMB_ATF_ADMIN); 387 } 388 389 /* 390 * Check whether or not the specified user has power-user privileges, 391 * i.e. is a member of Domain Admins, Administrators or Power Users. 392 * This is typically required for operations such as managing shares. 393 * Returns true if the user is a power user, otherwise returns false. 394 */ 395 boolean_t 396 ndr_is_poweruser(ndr_xa_t *xa) 397 { 398 smb_netuserinfo_t *ctx = &xa->pipe->np_user; 399 400 return ((ctx->ui_flags & SMB_ATF_ADMIN) || 401 (ctx->ui_flags & SMB_ATF_POWERUSER)); 402 } 403 404 int32_t 405 ndr_native_os(ndr_xa_t *xa) 406 { 407 smb_netuserinfo_t *ctx = &xa->pipe->np_user; 408 409 return (ctx->ui_native_os); 410 } 411 412 /* 413 * This is the entry point for all server-side RPC processing. 414 * It is assumed that the PDU has already been received. 415 */ 416 static int 417 ndr_svc_process(ndr_xa_t *mxa) 418 { 419 int rc; 420 421 rc = ndr_decode_pdu_hdr(mxa); 422 if (!NDR_DRC_IS_OK(rc)) 423 return (-1); 424 425 (void) ndr_reply_prepare_hdr(mxa); 426 427 switch (mxa->ptype) { 428 case NDR_PTYPE_BIND: 429 rc = ndr_svc_bind(mxa); 430 break; 431 432 case NDR_PTYPE_REQUEST: 433 rc = ndr_svc_request(mxa); 434 break; 435 436 case NDR_PTYPE_ALTER_CONTEXT: 437 rc = ndr_svc_alter_context(mxa); 438 break; 439 440 default: 441 rc = NDR_DRC_FAULT_RPCHDR_PTYPE_INVALID; 442 break; 443 } 444 445 if (NDR_DRC_IS_FAULT(rc)) 446 ndr_reply_fault(mxa, rc); 447 448 (void) ndr_build_reply(mxa); 449 return (rc); 450 } 451 452 /* 453 * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple 454 * p_results[] not supported. 455 */ 456 static int 457 ndr_svc_bind(ndr_xa_t *mxa) 458 { 459 ndr_p_cont_list_t *cont_list; 460 ndr_p_result_list_t *result_list; 461 ndr_p_result_t *result; 462 unsigned p_cont_id; 463 ndr_binding_t *mbind; 464 ndr_uuid_t *as_uuid; 465 ndr_uuid_t *ts_uuid; 466 int as_vers; 467 int ts_vers; 468 ndr_service_t *msvc; 469 int rc; 470 ndr_port_any_t *sec_addr; 471 472 /* acquire targets */ 473 cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem; 474 result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list; 475 result = &result_list->p_results[0]; 476 477 /* 478 * Set up temporary secondary address port. 479 * We will correct this later (below). 480 */ 481 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 482 sec_addr->length = 13; 483 (void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs"); 484 485 result_list->n_results = 1; 486 result_list->reserved = 0; 487 result_list->reserved2 = 0; 488 result->result = NDR_PCDR_ACCEPTANCE; 489 result->reason = 0; 490 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax)); 491 492 /* sanity check */ 493 if (cont_list->n_context_elem != 1 || 494 cont_list->p_cont_elem[0].n_transfer_syn != 1) { 495 ndo_trace("ndr_svc_bind: warning: multiple p_cont_elem"); 496 } 497 498 p_cont_id = cont_list->p_cont_elem[0].p_cont_id; 499 500 if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) != NULL) { 501 /* 502 * Duplicate presentation context id. 503 */ 504 ndo_trace("ndr_svc_bind: duplicate binding"); 505 return (NDR_DRC_FAULT_BIND_PCONT_BUSY); 506 } 507 508 if ((mbind = ndr_svc_new_binding(mxa)) == NULL) { 509 /* 510 * No free binding slot 511 */ 512 result->result = NDR_PCDR_PROVIDER_REJECTION; 513 result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED; 514 ndo_trace("ndr_svc_bind: no resources"); 515 return (NDR_DRC_OK); 516 } 517 518 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid; 519 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version; 520 521 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid; 522 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version; 523 524 msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers); 525 if (msvc == NULL) { 526 result->result = NDR_PCDR_PROVIDER_REJECTION; 527 result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 528 return (NDR_DRC_OK); 529 } 530 531 /* 532 * We can now use the correct secondary address port. 533 */ 534 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 535 sec_addr->length = strlen(msvc->sec_addr_port) + 1; 536 (void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port, 537 NDR_PORT_ANY_MAX_PORT_SPEC); 538 539 mbind->p_cont_id = p_cont_id; 540 mbind->which_side = NDR_BIND_SIDE_SERVER; 541 /* mbind->context set by app */ 542 mbind->service = msvc; 543 mbind->instance_specific = 0; 544 545 mxa->binding = mbind; 546 547 if (msvc->bind_req) { 548 /* 549 * Call the service-specific bind() handler. If 550 * this fails, we shouild send a specific error 551 * on the bind ack. 552 */ 553 rc = (msvc->bind_req)(mxa); 554 if (NDR_DRC_IS_FAULT(rc)) { 555 mbind->service = 0; /* free binding slot */ 556 mbind->which_side = 0; 557 mbind->p_cont_id = 0; 558 mbind->instance_specific = 0; 559 return (rc); 560 } 561 } 562 563 result->transfer_syntax = 564 cont_list->p_cont_elem[0].transfer_syntaxes[0]; 565 566 return (NDR_DRC_BINDING_MADE); 567 } 568 569 /* 570 * ndr_svc_alter_context 571 * 572 * The alter context request is used to request additional presentation 573 * context for another interface and/or version. It is very similar to 574 * a bind request. 575 */ 576 static int 577 ndr_svc_alter_context(ndr_xa_t *mxa) 578 { 579 ndr_p_result_list_t *result_list; 580 ndr_p_result_t *result; 581 ndr_p_cont_list_t *cont_list; 582 ndr_binding_t *mbind; 583 ndr_service_t *msvc; 584 unsigned p_cont_id; 585 ndr_uuid_t *as_uuid; 586 ndr_uuid_t *ts_uuid; 587 int as_vers; 588 int ts_vers; 589 ndr_port_any_t *sec_addr; 590 591 result_list = &mxa->send_hdr.alter_context_rsp_hdr.p_result_list; 592 result_list->n_results = 1; 593 result_list->reserved = 0; 594 result_list->reserved2 = 0; 595 596 result = &result_list->p_results[0]; 597 result->result = NDR_PCDR_ACCEPTANCE; 598 result->reason = 0; 599 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax)); 600 601 cont_list = &mxa->recv_hdr.alter_context_hdr.p_context_elem; 602 p_cont_id = cont_list->p_cont_elem[0].p_cont_id; 603 604 if (ndr_svc_find_binding(mxa, p_cont_id) != NULL) 605 return (NDR_DRC_FAULT_BIND_PCONT_BUSY); 606 607 if ((mbind = ndr_svc_new_binding(mxa)) == NULL) { 608 result->result = NDR_PCDR_PROVIDER_REJECTION; 609 result->reason = NDR_PPR_LOCAL_LIMIT_EXCEEDED; 610 return (NDR_DRC_OK); 611 } 612 613 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid; 614 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version; 615 616 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid; 617 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version; 618 619 msvc = ndr_svc_lookup_uuid(as_uuid, as_vers, ts_uuid, ts_vers); 620 if (msvc == NULL) { 621 result->result = NDR_PCDR_PROVIDER_REJECTION; 622 result->reason = NDR_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 623 return (NDR_DRC_OK); 624 } 625 626 mbind->p_cont_id = p_cont_id; 627 mbind->which_side = NDR_BIND_SIDE_SERVER; 628 /* mbind->context set by app */ 629 mbind->service = msvc; 630 mbind->instance_specific = 0; 631 mxa->binding = mbind; 632 633 sec_addr = &mxa->send_hdr.alter_context_rsp_hdr.sec_addr; 634 sec_addr->length = 0; 635 bzero(sec_addr->port_spec, NDR_PORT_ANY_MAX_PORT_SPEC); 636 637 result->transfer_syntax = 638 cont_list->p_cont_elem[0].transfer_syntaxes[0]; 639 640 return (NDR_DRC_BINDING_MADE); 641 } 642 643 static int 644 ndr_svc_request(ndr_xa_t *mxa) 645 { 646 ndr_binding_t *mbind; 647 ndr_service_t *msvc; 648 unsigned p_cont_id; 649 int rc; 650 651 mxa->opnum = mxa->recv_hdr.request_hdr.opnum; 652 p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id; 653 654 if ((mbind = ndr_svc_find_binding(mxa, p_cont_id)) == NULL) 655 return (NDR_DRC_FAULT_REQUEST_PCONT_INVALID); 656 657 mxa->binding = mbind; 658 msvc = mbind->service; 659 660 /* 661 * Make room for the response hdr. 662 */ 663 mxa->send_nds.pdu_scan_offset = NDR_RSP_HDR_SIZE; 664 665 if (msvc->call_stub) 666 rc = (*msvc->call_stub)(mxa); 667 else 668 rc = ndr_generic_call_stub(mxa); 669 670 if (NDR_DRC_IS_FAULT(rc)) { 671 ndo_printf(0, 0, "%s[0x%02x]: 0x%04x", 672 msvc->name, mxa->opnum, rc); 673 } 674 675 return (rc); 676 } 677 678 /* 679 * The transaction and the two nds streams use the same heap, which 680 * should already exist at this point. The heap will also be available 681 * to the stub. 682 */ 683 int 684 ndr_generic_call_stub(ndr_xa_t *mxa) 685 { 686 ndr_binding_t *mbind = mxa->binding; 687 ndr_service_t *msvc = mbind->service; 688 ndr_typeinfo_t *intf_ti = msvc->interface_ti; 689 ndr_stub_table_t *ste; 690 int opnum = mxa->opnum; 691 unsigned p_len = intf_ti->c_size_fixed_part; 692 char *param; 693 int rc; 694 695 if (mxa->heap == NULL) { 696 ndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum); 697 return (NDR_DRC_FAULT_OUT_OF_MEMORY); 698 } 699 700 if ((ste = ndr_svc_find_stub(msvc, opnum)) == NULL) { 701 ndo_printf(0, 0, "%s[0x%02x]: invalid opnum", 702 msvc->name, opnum); 703 return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID); 704 } 705 706 if ((param = ndr_heap_malloc(mxa->heap, p_len)) == NULL) 707 return (NDR_DRC_FAULT_OUT_OF_MEMORY); 708 709 bzero(param, p_len); 710 711 rc = ndr_decode_call(mxa, param); 712 if (!NDR_DRC_IS_OK(rc)) 713 return (rc); 714 715 rc = (*ste->func)(param, mxa); 716 if (rc == NDR_DRC_OK) 717 rc = ndr_encode_return(mxa, param); 718 719 return (rc); 720 } 721 722 /* 723 * We can perform some initial setup of the response header here. 724 * We also need to cache some of the information from the bind 725 * negotiation for use during subsequent RPC calls. 726 */ 727 static void 728 ndr_reply_prepare_hdr(ndr_xa_t *mxa) 729 { 730 ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr; 731 ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 732 733 hdr->rpc_vers = 5; 734 hdr->rpc_vers_minor = 0; 735 hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG; 736 hdr->packed_drep = rhdr->packed_drep; 737 hdr->frag_length = 0; 738 hdr->auth_length = 0; 739 hdr->call_id = rhdr->call_id; 740 #ifdef _BIG_ENDIAN 741 hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII 742 | NDR_REPLAB_INTG_BIG_ENDIAN; 743 #else 744 hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII 745 | NDR_REPLAB_INTG_LITTLE_ENDIAN; 746 #endif 747 748 switch (mxa->ptype) { 749 case NDR_PTYPE_BIND: 750 hdr->ptype = NDR_PTYPE_BIND_ACK; 751 mxa->send_hdr.bind_ack_hdr.max_xmit_frag = 752 mxa->recv_hdr.bind_hdr.max_xmit_frag; 753 mxa->send_hdr.bind_ack_hdr.max_recv_frag = 754 mxa->recv_hdr.bind_hdr.max_recv_frag; 755 mxa->send_hdr.bind_ack_hdr.assoc_group_id = 756 mxa->recv_hdr.bind_hdr.assoc_group_id; 757 758 if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0) 759 mxa->send_hdr.bind_ack_hdr.assoc_group_id = time(0); 760 761 /* 762 * Save the maximum fragment sizes 763 * for use with subsequent requests. 764 */ 765 mxa->pipe->np_max_xmit_frag = 766 mxa->recv_hdr.bind_hdr.max_xmit_frag; 767 mxa->pipe->np_max_recv_frag = 768 mxa->recv_hdr.bind_hdr.max_recv_frag; 769 break; 770 771 case NDR_PTYPE_REQUEST: 772 hdr->ptype = NDR_PTYPE_RESPONSE; 773 /* mxa->send_hdr.response_hdr.alloc_hint */ 774 mxa->send_hdr.response_hdr.p_cont_id = 775 mxa->recv_hdr.request_hdr.p_cont_id; 776 mxa->send_hdr.response_hdr.cancel_count = 0; 777 mxa->send_hdr.response_hdr.reserved = 0; 778 break; 779 780 case NDR_PTYPE_ALTER_CONTEXT: 781 hdr->ptype = NDR_PTYPE_ALTER_CONTEXT_RESP; 782 /* 783 * The max_xmit_frag, max_recv_frag and assoc_group_id are 784 * ignored by the client but it's useful to fill them in. 785 */ 786 mxa->send_hdr.alter_context_rsp_hdr.max_xmit_frag = 787 mxa->recv_hdr.alter_context_hdr.max_xmit_frag; 788 mxa->send_hdr.alter_context_rsp_hdr.max_recv_frag = 789 mxa->recv_hdr.alter_context_hdr.max_recv_frag; 790 mxa->send_hdr.alter_context_rsp_hdr.assoc_group_id = 791 mxa->recv_hdr.alter_context_hdr.assoc_group_id; 792 break; 793 794 default: 795 hdr->ptype = 0xFF; 796 } 797 } 798 799 /* 800 * Signal an RPC fault. The stream is reset and we overwrite whatever 801 * was in the response header with the fault information. 802 */ 803 static void 804 ndr_reply_fault(ndr_xa_t *mxa, unsigned long drc) 805 { 806 ndr_common_header_t *rhdr = &mxa->recv_hdr.common_hdr; 807 ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 808 ndr_stream_t *nds = &mxa->send_nds; 809 unsigned long fault_status; 810 811 NDS_RESET(nds); 812 813 hdr->rpc_vers = 5; 814 hdr->rpc_vers_minor = 0; 815 hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG; 816 hdr->packed_drep = rhdr->packed_drep; 817 hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr); 818 hdr->auth_length = 0; 819 hdr->call_id = rhdr->call_id; 820 #ifdef _BIG_ENDIAN 821 hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII 822 | NDR_REPLAB_INTG_BIG_ENDIAN; 823 #else 824 hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII 825 | NDR_REPLAB_INTG_LITTLE_ENDIAN; 826 #endif 827 828 switch (drc & NDR_DRC_MASK_SPECIFIER) { 829 case NDR_DRC_FAULT_OUT_OF_MEMORY: 830 case NDR_DRC_FAULT_ENCODE_TOO_BIG: 831 fault_status = NDR_FAULT_NCA_OUT_ARGS_TOO_BIG; 832 break; 833 834 case NDR_DRC_FAULT_REQUEST_PCONT_INVALID: 835 fault_status = NDR_FAULT_NCA_INVALID_PRES_CONTEXT_ID; 836 break; 837 838 case NDR_DRC_FAULT_REQUEST_OPNUM_INVALID: 839 fault_status = NDR_FAULT_NCA_OP_RNG_ERROR; 840 break; 841 842 case NDR_DRC_FAULT_DECODE_FAILED: 843 case NDR_DRC_FAULT_ENCODE_FAILED: 844 fault_status = NDR_FAULT_NCA_PROTO_ERROR; 845 break; 846 847 default: 848 fault_status = NDR_FAULT_NCA_UNSPEC_REJECT; 849 break; 850 } 851 852 mxa->send_hdr.fault_hdr.common_hdr.ptype = NDR_PTYPE_FAULT; 853 mxa->send_hdr.fault_hdr.status = fault_status; 854 mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length; 855 } 856 857 /* 858 * Note that the frag_length for bind ack and alter context is 859 * non-standard. 860 */ 861 static int 862 ndr_build_reply(ndr_xa_t *mxa) 863 { 864 ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 865 ndr_stream_t *nds = &mxa->send_nds; 866 uint8_t *pdu_buf; 867 unsigned long pdu_size; 868 unsigned long frag_size; 869 unsigned long pdu_data_size; 870 unsigned long frag_data_size; 871 872 frag_size = NDR_FRAG_SZ; 873 pdu_size = nds->pdu_size; 874 pdu_buf = nds->pdu_base_addr; 875 876 if (pdu_size <= frag_size) { 877 /* 878 * Single fragment response. The PDU size may be zero 879 * here (i.e. bind or fault response). So don't make 880 * any assumptions about it until after the header is 881 * encoded. 882 */ 883 switch (hdr->ptype) { 884 case NDR_PTYPE_BIND_ACK: 885 hdr->frag_length = ndr_bind_ack_hdr_size(mxa); 886 break; 887 888 case NDR_PTYPE_FAULT: 889 /* already setup */ 890 break; 891 892 case NDR_PTYPE_RESPONSE: 893 hdr->frag_length = pdu_size; 894 mxa->send_hdr.response_hdr.alloc_hint = 895 hdr->frag_length; 896 break; 897 898 case NDR_PTYPE_ALTER_CONTEXT_RESP: 899 hdr->frag_length = ndr_alter_context_rsp_hdr_size(); 900 break; 901 902 default: 903 hdr->frag_length = pdu_size; 904 break; 905 } 906 907 nds->pdu_scan_offset = 0; 908 (void) ndr_encode_pdu_hdr(mxa); 909 pdu_size = nds->pdu_size; 910 ndr_build_frag(nds, pdu_buf, pdu_size); 911 return (0); 912 } 913 914 /* 915 * Multiple fragment response. 916 */ 917 hdr->pfc_flags = NDR_PFC_FIRST_FRAG; 918 hdr->frag_length = frag_size; 919 mxa->send_hdr.response_hdr.alloc_hint = pdu_size - NDR_RSP_HDR_SIZE; 920 nds->pdu_scan_offset = 0; 921 (void) ndr_encode_pdu_hdr(mxa); 922 ndr_build_frag(nds, pdu_buf, frag_size); 923 924 /* 925 * We need to update the 24-byte header in subsequent fragments. 926 * 927 * pdu_data_size: total data remaining to be handled 928 * frag_size: total fragment size including header 929 * frag_data_size: data in fragment 930 * (i.e. frag_size - NDR_RSP_HDR_SIZE) 931 */ 932 pdu_data_size = pdu_size - NDR_RSP_HDR_SIZE; 933 frag_data_size = frag_size - NDR_RSP_HDR_SIZE; 934 935 while (pdu_data_size) { 936 mxa->send_hdr.response_hdr.alloc_hint -= frag_data_size; 937 pdu_data_size -= frag_data_size; 938 pdu_buf += frag_data_size; 939 940 if (pdu_data_size <= frag_data_size) { 941 frag_data_size = pdu_data_size; 942 frag_size = frag_data_size + NDR_RSP_HDR_SIZE; 943 hdr->pfc_flags = NDR_PFC_LAST_FRAG; 944 } else { 945 hdr->pfc_flags = 0; 946 } 947 948 hdr->frag_length = frag_size; 949 nds->pdu_scan_offset = 0; 950 (void) ndr_encode_pdu_hdr(mxa); 951 bcopy(nds->pdu_base_addr, pdu_buf, NDR_RSP_HDR_SIZE); 952 953 ndr_build_frag(nds, pdu_buf, frag_size); 954 955 if (hdr->pfc_flags & NDR_PFC_LAST_FRAG) 956 break; 957 } 958 959 return (0); 960 } 961 962 /* 963 * ndr_build_frag 964 * 965 * Build an RPC PDU fragment from the specified buffer. 966 * If malloc fails, the client will see a header/pdu inconsistency 967 * and report an error. 968 */ 969 static void 970 ndr_build_frag(ndr_stream_t *nds, uint8_t *buf, uint32_t len) 971 { 972 ndr_frag_t *frag; 973 int size = sizeof (ndr_frag_t) + len; 974 975 if ((frag = (ndr_frag_t *)malloc(size)) == NULL) 976 return; 977 978 frag->next = NULL; 979 frag->buf = (uint8_t *)frag + sizeof (ndr_frag_t); 980 frag->len = len; 981 bcopy(buf, frag->buf, len); 982 983 if (nds->frags.head == NULL) { 984 nds->frags.head = frag; 985 nds->frags.tail = frag; 986 nds->frags.nfrag = 1; 987 } else { 988 nds->frags.tail->next = frag; 989 nds->frags.tail = frag; 990 ++nds->frags.nfrag; 991 } 992 } 993