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