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