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