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