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