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 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Server side RPC handler. 30 */ 31 32 #include <sys/byteorder.h> 33 #include <sys/errno.h> 34 #include <sys/uio.h> 35 #include <thread.h> 36 #include <synch.h> 37 #include <stdlib.h> 38 #include <strings.h> 39 #include <string.h> 40 #include <time.h> 41 42 #include <smbsrv/libsmb.h> 43 #include <smbsrv/libmlrpc.h> 44 #include <smbsrv/mlsvc.h> 45 #include <smbsrv/ndr.h> 46 #include <smbsrv/mlrpc.h> 47 #include <smbsrv/mlsvc_util.h> 48 49 50 #define SMB_CTXT_BUFSZ 65536 51 52 /* 53 * Fragment size (5680: NT style). 54 */ 55 #define MLRPC_FRAG_SZ 5680 56 static unsigned long mlrpc_frag_size = MLRPC_FRAG_SZ; 57 58 /* 59 * Service context table. 60 */ 61 #define CTXT_TABLE_ENTRIES 128 62 static struct mlsvc_rpc_context context_table[CTXT_TABLE_ENTRIES]; 63 static mutex_t mlrpc_context_lock; 64 65 static int ndr_s_transact(struct mlsvc_rpc_context *); 66 static struct mlsvc_rpc_context *ndr_s_lookup(int); 67 static void ndr_s_release(struct mlsvc_rpc_context *); 68 static struct mlsvc_rpc_context *ndr_s_allocate(int); 69 static void ndr_s_deallocate(struct mlsvc_rpc_context *); 70 static void ndr_s_rewind(struct mlsvc_rpc_context *); 71 static void ndr_s_flush(struct mlsvc_rpc_context *); 72 73 static int mlrpc_s_process(struct mlrpc_xaction *); 74 static int mlrpc_s_bind(struct mlrpc_xaction *); 75 static int mlrpc_s_request(struct mlrpc_xaction *); 76 static void mlrpc_reply_prepare_hdr(struct mlrpc_xaction *); 77 static int mlrpc_s_alter_context(struct mlrpc_xaction *); 78 static void mlrpc_reply_bind_ack(struct mlrpc_xaction *); 79 static void mlrpc_reply_fault(struct mlrpc_xaction *, unsigned long); 80 static int mlrpc_build_reply(struct mlrpc_xaction *); 81 static void mlrpc_build_frag(struct mlndr_stream *, uint8_t *, uint32_t); 82 83 /* 84 * Allocate and associate a service context with a fid. 85 */ 86 int 87 ndr_s_open(int fid, uint8_t *data, uint32_t datalen) 88 { 89 struct mlsvc_rpc_context *svc; 90 91 (void) mutex_lock(&mlrpc_context_lock); 92 93 if ((svc = ndr_s_lookup(fid)) != NULL) { 94 ndr_s_release(svc); 95 (void) mutex_unlock(&mlrpc_context_lock); 96 return (EEXIST); 97 } 98 99 if ((svc = ndr_s_allocate(fid)) == NULL) { 100 (void) mutex_unlock(&mlrpc_context_lock); 101 return (ENOMEM); 102 } 103 104 if (smb_opipe_context_decode(&svc->svc_ctx, data, datalen) == -1) { 105 ndr_s_release(svc); 106 (void) mutex_unlock(&mlrpc_context_lock); 107 return (EINVAL); 108 } 109 110 mlrpc_binding_pool_initialize(&svc->binding, svc->binding_pool, 111 CTXT_N_BINDING_POOL); 112 113 (void) mutex_unlock(&mlrpc_context_lock); 114 return (0); 115 } 116 117 /* 118 * Release the context associated with a fid when an opipe is closed. 119 */ 120 int 121 ndr_s_close(int fid) 122 { 123 struct mlsvc_rpc_context *svc; 124 125 (void) mutex_lock(&mlrpc_context_lock); 126 127 if ((svc = ndr_s_lookup(fid)) == NULL) { 128 (void) mutex_unlock(&mlrpc_context_lock); 129 return (ENOENT); 130 } 131 132 /* 133 * Release twice: once for the lookup above 134 * and again to close the fid. 135 */ 136 ndr_s_release(svc); 137 ndr_s_release(svc); 138 (void) mutex_unlock(&mlrpc_context_lock); 139 return (0); 140 } 141 142 /* 143 * Write RPC request data to the input stream. Input data is buffered 144 * until the response is requested. 145 */ 146 int 147 ndr_s_write(int fid, uint8_t *buf, uint32_t len) 148 { 149 struct mlsvc_rpc_context *svc; 150 ssize_t nbytes; 151 152 if (len == 0) 153 return (0); 154 155 (void) mutex_lock(&mlrpc_context_lock); 156 157 if ((svc = ndr_s_lookup(fid)) == NULL) { 158 (void) mutex_unlock(&mlrpc_context_lock); 159 return (ENOENT); 160 } 161 162 nbytes = ndr_uiomove((caddr_t)buf, len, UIO_READ, &svc->in_uio); 163 164 ndr_s_release(svc); 165 (void) mutex_unlock(&mlrpc_context_lock); 166 return ((nbytes == len) ? 0 : EIO); 167 } 168 169 /* 170 * Read RPC response data. If the input stream contains an RPC request, 171 * we need to process the RPC transaction, which will place the RPC 172 * response in the output (frags) stream. Otherwise, read data from 173 * the output stream. 174 */ 175 int 176 ndr_s_read(int fid, uint8_t *buf, uint32_t *len, uint32_t *resid) 177 { 178 struct mlsvc_rpc_context *svc; 179 ssize_t nbytes = *len; 180 int rc; 181 182 if (nbytes == 0) { 183 *resid = 0; 184 return (0); 185 } 186 187 (void) mutex_lock(&mlrpc_context_lock); 188 if ((svc = ndr_s_lookup(fid)) == NULL) { 189 (void) mutex_unlock(&mlrpc_context_lock); 190 return (ENOENT); 191 } 192 (void) mutex_unlock(&mlrpc_context_lock); 193 194 if (svc->in_uio.uio_offset) { 195 if ((rc = ndr_s_transact(svc)) != 0) { 196 ndr_s_flush(svc); 197 (void) mutex_lock(&mlrpc_context_lock); 198 ndr_s_release(svc); 199 (void) mutex_unlock(&mlrpc_context_lock); 200 return (rc); 201 } 202 203 } 204 205 *len = ndr_uiomove((caddr_t)buf, nbytes, UIO_WRITE, &svc->frags.uio); 206 *resid = svc->frags.uio.uio_resid; 207 208 if (*resid == 0) { 209 /* 210 * Nothing left, cleanup the output stream. 211 */ 212 ndr_s_flush(svc); 213 } 214 215 (void) mutex_lock(&mlrpc_context_lock); 216 ndr_s_release(svc); 217 (void) mutex_unlock(&mlrpc_context_lock); 218 return (0); 219 } 220 221 /* 222 * Process a server-side RPC request. 223 */ 224 static int 225 ndr_s_transact(struct mlsvc_rpc_context *svc) 226 { 227 ndr_xa_t *mxa; 228 struct mlndr_stream *recv_mlnds; 229 struct mlndr_stream *send_mlnds; 230 char *data; 231 int datalen; 232 233 data = svc->in_buf; 234 datalen = svc->in_uio.uio_offset; 235 236 if ((mxa = (ndr_xa_t *)malloc(sizeof (ndr_xa_t))) == NULL) 237 return (ENOMEM); 238 239 bzero(mxa, sizeof (struct mlrpc_xaction)); 240 mxa->fid = svc->fid; 241 mxa->context = svc; 242 mxa->binding_list = svc->binding; 243 244 if ((mxa->heap = mlrpc_heap_create()) == NULL) { 245 free(mxa); 246 return (ENOMEM); 247 } 248 249 recv_mlnds = &mxa->recv_mlnds; 250 mlnds_initialize(recv_mlnds, datalen, NDR_MODE_CALL_RECV, mxa->heap); 251 252 /* 253 * Copy the input data and reset the input stream. 254 */ 255 bcopy(data, recv_mlnds->pdu_base_addr, datalen); 256 ndr_s_rewind(svc); 257 258 send_mlnds = &mxa->send_mlnds; 259 mlnds_initialize(send_mlnds, 0, NDR_MODE_RETURN_SEND, mxa->heap); 260 261 (void) mlrpc_s_process(mxa); 262 263 mlnds_finalize(send_mlnds, &svc->frags); 264 mlnds_destruct(&mxa->recv_mlnds); 265 mlnds_destruct(&mxa->send_mlnds); 266 mlrpc_heap_destroy(mxa->heap); 267 free(mxa); 268 return (0); 269 } 270 271 /* 272 * Must be called with mlrpc_context_lock held. 273 */ 274 static struct mlsvc_rpc_context * 275 ndr_s_lookup(int fid) 276 { 277 struct mlsvc_rpc_context *svc; 278 int i; 279 280 for (i = 0; i < CTXT_TABLE_ENTRIES; ++i) { 281 svc = &context_table[i]; 282 283 if (svc->fid == fid) { 284 if (svc->refcnt == 0) 285 return (NULL); 286 287 svc->refcnt++; 288 return (svc); 289 } 290 } 291 292 return (NULL); 293 } 294 295 /* 296 * Must be called with mlrpc_context_lock held. 297 */ 298 static void 299 ndr_s_release(struct mlsvc_rpc_context *svc) 300 { 301 svc->refcnt--; 302 ndr_s_deallocate(svc); 303 } 304 305 /* 306 * Must be called with mlrpc_context_lock held. 307 */ 308 static struct mlsvc_rpc_context * 309 ndr_s_allocate(int fid) 310 { 311 struct mlsvc_rpc_context *svc = NULL; 312 int i; 313 314 for (i = 0; i < CTXT_TABLE_ENTRIES; ++i) { 315 svc = &context_table[i]; 316 317 if (svc->fid == 0) { 318 bzero(svc, sizeof (struct mlsvc_rpc_context)); 319 320 if ((svc->in_buf = malloc(SMB_CTXT_BUFSZ)) == NULL) 321 return (NULL); 322 323 ndr_s_rewind(svc); 324 svc->fid = fid; 325 svc->refcnt = 1; 326 return (svc); 327 } 328 } 329 330 return (NULL); 331 } 332 333 /* 334 * Must be called with mlrpc_context_lock held. 335 */ 336 static void 337 ndr_s_deallocate(struct mlsvc_rpc_context *svc) 338 { 339 if (svc->refcnt == 0) { 340 /* 341 * Ensure that there are no RPC service policy handles 342 * (associated with this fid) left around. 343 */ 344 ndr_hdclose(svc->fid); 345 346 ndr_s_rewind(svc); 347 ndr_s_flush(svc); 348 free(svc->in_buf); 349 free(svc->svc_ctx.oc_domain); 350 free(svc->svc_ctx.oc_account); 351 free(svc->svc_ctx.oc_workstation); 352 bzero(svc, sizeof (struct mlsvc_rpc_context)); 353 } 354 } 355 356 /* 357 * Rewind the input data stream, ready for the next write. 358 */ 359 static void 360 ndr_s_rewind(struct mlsvc_rpc_context *svc) 361 { 362 svc->in_uio.uio_iov = &svc->in_iov; 363 svc->in_uio.uio_iovcnt = 1; 364 svc->in_uio.uio_offset = 0; 365 svc->in_uio.uio_segflg = UIO_USERSPACE; 366 svc->in_uio.uio_resid = SMB_CTXT_BUFSZ; 367 svc->in_iov.iov_base = svc->in_buf; 368 svc->in_iov.iov_len = SMB_CTXT_BUFSZ; 369 } 370 371 /* 372 * Flush the output data stream. 373 */ 374 static void 375 ndr_s_flush(struct mlsvc_rpc_context *svc) 376 { 377 ndr_frag_t *frag; 378 379 while ((frag = svc->frags.head) != NULL) { 380 svc->frags.head = frag->next; 381 free(frag); 382 } 383 384 free(svc->frags.iov); 385 bzero(&svc->frags, sizeof (ndr_fraglist_t)); 386 } 387 388 /* 389 * Check whether or not the specified user has administrator privileges, 390 * i.e. is a member of Domain Admins or Administrators. 391 * Returns true if the user is an administrator, otherwise returns false. 392 */ 393 boolean_t 394 ndr_is_admin(ndr_xa_t *xa) 395 { 396 smb_opipe_context_t *svc = &xa->context->svc_ctx; 397 398 return (svc->oc_flags & SMB_ATF_ADMIN); 399 } 400 401 /* 402 * Check whether or not the specified user has power-user privileges, 403 * i.e. is a member of Domain Admins, Administrators or Power Users. 404 * This is typically required for operations such as managing shares. 405 * Returns true if the user is a power user, otherwise returns false. 406 */ 407 boolean_t 408 ndr_is_poweruser(ndr_xa_t *xa) 409 { 410 smb_opipe_context_t *svc = &xa->context->svc_ctx; 411 412 return ((svc->oc_flags & SMB_ATF_ADMIN) || 413 (svc->oc_flags & SMB_ATF_POWERUSER)); 414 } 415 416 int32_t 417 ndr_native_os(ndr_xa_t *xa) 418 { 419 smb_opipe_context_t *svc = &xa->context->svc_ctx; 420 421 return (svc->oc_native_os); 422 } 423 424 /* 425 * This is the entry point for all server-side RPC processing. 426 * It is assumed that the PDU has already been received. 427 */ 428 static int 429 mlrpc_s_process(struct mlrpc_xaction *mxa) 430 { 431 int rc; 432 433 rc = mlrpc_decode_pdu_hdr(mxa); 434 if (!MLRPC_DRC_IS_OK(rc)) 435 return (-1); 436 437 (void) mlrpc_reply_prepare_hdr(mxa); 438 439 switch (mxa->ptype) { 440 case MLRPC_PTYPE_BIND: 441 rc = mlrpc_s_bind(mxa); 442 break; 443 444 case MLRPC_PTYPE_REQUEST: 445 rc = mlrpc_s_request(mxa); 446 break; 447 448 case MLRPC_PTYPE_ALTER_CONTEXT: 449 rc = mlrpc_s_alter_context(mxa); 450 break; 451 452 default: 453 rc = MLRPC_DRC_FAULT_RPCHDR_PTYPE_INVALID; 454 break; 455 } 456 457 if (MLRPC_DRC_IS_FAULT(rc)) 458 mlrpc_reply_fault(mxa, rc); 459 460 (void) mlrpc_build_reply(mxa); 461 return (rc); 462 } 463 464 /* 465 * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple 466 * p_results[] not supported. 467 */ 468 static int 469 mlrpc_s_bind(struct mlrpc_xaction *mxa) 470 { 471 mlrpc_p_cont_list_t *cont_list; 472 mlrpc_p_result_list_t *result_list; 473 mlrpc_p_result_t *result; 474 unsigned p_cont_id; 475 struct mlrpc_binding *mbind; 476 ndr_uuid_t *as_uuid; 477 ndr_uuid_t *ts_uuid; 478 char as_buf[64]; 479 char ts_buf[64]; 480 int as_vers; 481 int ts_vers; 482 struct mlndr_stream *send_mlnds; 483 struct mlrpc_service *msvc; 484 int rc; 485 mlrpc_port_any_t *sec_addr; 486 487 /* acquire targets */ 488 cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem; 489 result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list; 490 result = &result_list->p_results[0]; 491 492 /* 493 * Set up temporary secondary address port. 494 * We will correct this later (below). 495 */ 496 send_mlnds = &mxa->send_mlnds; 497 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 498 sec_addr->length = 13; 499 (void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs"); 500 501 result_list->n_results = 1; 502 result_list->reserved = 0; 503 result_list->reserved2 = 0; 504 result->result = MLRPC_PCDR_ACCEPTANCE; 505 result->reason = 0; 506 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax)); 507 508 /* sanity check */ 509 if (cont_list->n_context_elem != 1 || 510 cont_list->p_cont_elem[0].n_transfer_syn != 1) { 511 mlndo_trace("mlrpc_s_bind: warning: multiple p_cont_elem"); 512 } 513 514 p_cont_id = cont_list->p_cont_elem[0].p_cont_id; 515 516 if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) != NULL) { 517 /* 518 * Duplicate p_cont_id. 519 * Send a bind_ack with a better error. 520 */ 521 mlndo_trace("mlrpc_s_bind: duplicate binding"); 522 return (MLRPC_DRC_FAULT_BIND_PCONT_BUSY); 523 } 524 525 if ((mbind = mlrpc_new_binding(mxa)) == NULL) { 526 /* 527 * No free binding slot 528 */ 529 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 530 result->reason = MLRPC_PPR_LOCAL_LIMIT_EXCEEDED; 531 mlndo_trace("mlrpc_s_bind: no resources"); 532 return (MLRPC_DRC_OK); 533 } 534 535 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid; 536 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version; 537 538 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid; 539 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version; 540 541 msvc = mlrpc_find_service_by_uuids(as_uuid, as_vers, ts_uuid, ts_vers); 542 if (!msvc) { 543 mlrpc_uuid_to_str(as_uuid, as_buf); 544 mlrpc_uuid_to_str(ts_uuid, ts_buf); 545 546 mlndo_printf(send_mlnds, 0, "mlrpc_s_bind: unknown service"); 547 mlndo_printf(send_mlnds, 0, "abs=%s v%d, xfer=%s v%d", 548 as_buf, as_vers, ts_buf, ts_vers); 549 550 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 551 result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 552 return (MLRPC_DRC_OK); 553 } 554 555 /* 556 * We can now use the correct secondary address port. 557 */ 558 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 559 sec_addr->length = strlen(msvc->sec_addr_port) + 1; 560 (void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port, 561 MLRPC_PORT_ANY_MAX_PORT_SPEC); 562 563 mbind->p_cont_id = p_cont_id; 564 mbind->which_side = MLRPC_BIND_SIDE_SERVER; 565 /* mbind->context set by app */ 566 mbind->service = msvc; 567 mbind->instance_specific = 0; 568 569 mxa->binding = mbind; 570 571 if (msvc->bind_req) { 572 /* 573 * Call the service-specific bind() handler. If 574 * this fails, we shouild send a specific error 575 * on the bind ack. 576 */ 577 rc = (msvc->bind_req)(mxa); 578 if (MLRPC_DRC_IS_FAULT(rc)) { 579 mbind->service = 0; /* free binding slot */ 580 mbind->which_side = 0; 581 mbind->p_cont_id = 0; 582 mbind->instance_specific = 0; 583 return (rc); 584 } 585 } 586 587 result->transfer_syntax = 588 cont_list->p_cont_elem[0].transfer_syntaxes[0]; 589 590 /* 591 * Special rejection of Windows 2000 DSSETUP interface. 592 * This interface was introduced in Windows 2000 but has 593 * been subsequently deprecated due to problems. 594 */ 595 if (strcmp(msvc->name, "DSSETUP") == 0) { 596 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 597 result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 598 } 599 600 return (MLRPC_DRC_BINDING_MADE); 601 } 602 603 /* 604 * mlrpc_s_alter_context 605 * 606 * The alter context request is used to request additional presentation 607 * context for another interface and/or version. It's very similar to a 608 * bind request. 609 * 610 * We don't fully support multiple contexts so, for now, we reject this 611 * request. Windows 2000 clients attempt to use an alternate LSA context 612 * when ACLs are modified. 613 */ 614 static int 615 mlrpc_s_alter_context(struct mlrpc_xaction *mxa) 616 { 617 mlrpc_p_result_list_t *result_list; 618 mlrpc_p_result_t *result; 619 mlrpc_p_cont_list_t *cont_list; 620 struct mlrpc_binding *mbind; 621 struct mlrpc_service *msvc; 622 unsigned p_cont_id; 623 ndr_uuid_t *as_uuid; 624 ndr_uuid_t *ts_uuid; 625 int as_vers; 626 int ts_vers; 627 mlrpc_port_any_t *sec_addr; 628 629 result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list; 630 result_list->n_results = 1; 631 result_list->reserved = 0; 632 result_list->reserved2 = 0; 633 634 result = &result_list->p_results[0]; 635 result->result = MLRPC_PCDR_ACCEPTANCE; 636 result->reason = 0; 637 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax)); 638 639 if (mxa != NULL) { 640 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 641 result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 642 return (MLRPC_DRC_OK); 643 } 644 645 cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem; 646 p_cont_id = cont_list->p_cont_elem[0].p_cont_id; 647 648 if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) != NULL) 649 return (MLRPC_DRC_FAULT_BIND_PCONT_BUSY); 650 651 if ((mbind = mlrpc_new_binding(mxa)) == NULL) { 652 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 653 result->reason = MLRPC_PPR_LOCAL_LIMIT_EXCEEDED; 654 return (MLRPC_DRC_OK); 655 } 656 657 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid; 658 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version; 659 660 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid; 661 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version; 662 663 msvc = mlrpc_find_service_by_uuids(as_uuid, as_vers, ts_uuid, ts_vers); 664 if (msvc == 0) { 665 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 666 result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 667 return (MLRPC_DRC_OK); 668 } 669 670 mbind->p_cont_id = p_cont_id; 671 mbind->which_side = MLRPC_BIND_SIDE_SERVER; 672 /* mbind->context set by app */ 673 mbind->service = msvc; 674 mbind->instance_specific = 0; 675 mxa->binding = mbind; 676 677 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 678 sec_addr->length = 0; 679 bzero(sec_addr->port_spec, MLRPC_PORT_ANY_MAX_PORT_SPEC); 680 681 result->transfer_syntax = 682 cont_list->p_cont_elem[0].transfer_syntaxes[0]; 683 684 return (MLRPC_DRC_BINDING_MADE); 685 } 686 687 static int 688 mlrpc_s_request(struct mlrpc_xaction *mxa) 689 { 690 struct mlrpc_binding *mbind; 691 struct mlrpc_service *msvc; 692 unsigned p_cont_id; 693 int rc; 694 695 mxa->opnum = mxa->recv_hdr.request_hdr.opnum; 696 p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id; 697 698 if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) == NULL) 699 return (MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID); 700 701 mxa->binding = mbind; 702 msvc = mbind->service; 703 704 /* 705 * Make room for the response hdr. 706 */ 707 mxa->send_mlnds.pdu_scan_offset = MLRPC_RSP_HDR_SIZE; 708 709 if (msvc->call_stub) 710 rc = (*msvc->call_stub)(mxa); 711 else 712 rc = mlrpc_generic_call_stub(mxa); 713 714 if (MLRPC_DRC_IS_FAULT(rc)) { 715 mlndo_printf(0, 0, "%s[0x%02x]: 0x%04x", 716 msvc->name, mxa->opnum, rc); 717 } 718 719 return (rc); 720 } 721 722 /* 723 * The transaction and the two mlnds streams use the same heap, which 724 * should already exist at this point. The heap will also be available 725 * to the stub. 726 */ 727 int 728 mlrpc_generic_call_stub(struct mlrpc_xaction *mxa) 729 { 730 struct mlrpc_binding *mbind = mxa->binding; 731 struct mlrpc_service *msvc = mbind->service; 732 struct ndr_typeinfo *intf_ti = msvc->interface_ti; 733 struct mlrpc_stub_table *ste; 734 int opnum = mxa->opnum; 735 unsigned p_len = intf_ti->c_size_fixed_part; 736 char *param; 737 int rc; 738 739 if (mxa->heap == NULL) { 740 mlndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum); 741 return (MLRPC_DRC_FAULT_OUT_OF_MEMORY); 742 } 743 744 if ((ste = mlrpc_find_stub_in_svc(msvc, opnum)) == NULL) { 745 mlndo_printf(0, 0, "%s[0x%02x]: invalid opnum", 746 msvc->name, opnum); 747 return (MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID); 748 } 749 750 if ((param = mlrpc_heap_malloc(mxa->heap, p_len)) == NULL) 751 return (MLRPC_DRC_FAULT_OUT_OF_MEMORY); 752 753 bzero(param, p_len); 754 755 rc = mlrpc_decode_call(mxa, param); 756 if (!MLRPC_DRC_IS_OK(rc)) 757 return (rc); 758 759 rc = (*ste->func)(param, mxa); 760 if (rc == MLRPC_DRC_OK) 761 rc = mlrpc_encode_return(mxa, param); 762 763 return (rc); 764 } 765 766 /* 767 * We can perform some initial setup of the response header here. 768 * We also need to cache some of the information from the bind 769 * negotiation for use during subsequent RPC calls. 770 */ 771 static void 772 mlrpc_reply_prepare_hdr(struct mlrpc_xaction *mxa) 773 { 774 mlrpcconn_common_header_t *rhdr = &mxa->recv_hdr.common_hdr; 775 mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr; 776 777 hdr->rpc_vers = 5; 778 hdr->rpc_vers_minor = 0; 779 hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG; 780 hdr->packed_drep = rhdr->packed_drep; 781 hdr->frag_length = 0; 782 hdr->auth_length = 0; 783 hdr->call_id = rhdr->call_id; 784 #ifdef _BIG_ENDIAN 785 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII 786 | MLRPC_REPLAB_INTG_BIG_ENDIAN; 787 #else 788 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII 789 | MLRPC_REPLAB_INTG_LITTLE_ENDIAN; 790 #endif 791 792 switch (mxa->ptype) { 793 case MLRPC_PTYPE_BIND: 794 hdr->ptype = MLRPC_PTYPE_BIND_ACK; 795 mxa->send_hdr.bind_ack_hdr.max_xmit_frag = 796 mxa->recv_hdr.bind_hdr.max_xmit_frag; 797 mxa->send_hdr.bind_ack_hdr.max_recv_frag = 798 mxa->recv_hdr.bind_hdr.max_recv_frag; 799 mxa->send_hdr.bind_ack_hdr.assoc_group_id = 800 mxa->recv_hdr.bind_hdr.assoc_group_id; 801 802 if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0) 803 mxa->send_hdr.bind_ack_hdr.assoc_group_id = time(0); 804 805 /* 806 * Save the maximum fragment sizes 807 * for use with subsequent requests. 808 */ 809 mxa->context->max_xmit_frag = 810 mxa->recv_hdr.bind_hdr.max_xmit_frag; 811 812 mxa->context->max_recv_frag = 813 mxa->recv_hdr.bind_hdr.max_recv_frag; 814 815 break; 816 817 case MLRPC_PTYPE_REQUEST: 818 hdr->ptype = MLRPC_PTYPE_RESPONSE; 819 /* mxa->send_hdr.response_hdr.alloc_hint */ 820 mxa->send_hdr.response_hdr.p_cont_id = 821 mxa->recv_hdr.request_hdr.p_cont_id; 822 mxa->send_hdr.response_hdr.cancel_count = 0; 823 mxa->send_hdr.response_hdr.reserved = 0; 824 break; 825 826 case MLRPC_PTYPE_ALTER_CONTEXT: 827 hdr->ptype = MLRPC_PTYPE_ALTER_CONTEXT_RESP; 828 /* 829 * The max_xmit_frag, max_recv_frag 830 * and assoc_group_id are ignored. 831 */ 832 break; 833 834 default: 835 hdr->ptype = 0xFF; 836 } 837 } 838 839 /* 840 * Finish and encode the bind acknowledge (MLRPC_PTYPE_BIND_ACK) header. 841 * The frag_length is different from a regular RPC response. 842 */ 843 static void 844 mlrpc_reply_bind_ack(struct mlrpc_xaction *mxa) 845 { 846 mlrpcconn_common_header_t *hdr; 847 mlrpcconn_bind_ack_hdr_t *bahdr; 848 849 hdr = &mxa->send_hdr.common_hdr; 850 bahdr = &mxa->send_hdr.bind_ack_hdr; 851 hdr->frag_length = mlrpc_bind_ack_hdr_size(bahdr); 852 } 853 854 /* 855 * Signal an RPC fault. The stream is reset and we overwrite whatever 856 * was in the response header with the fault information. 857 */ 858 static void 859 mlrpc_reply_fault(struct mlrpc_xaction *mxa, unsigned long drc) 860 { 861 mlrpcconn_common_header_t *rhdr = &mxa->recv_hdr.common_hdr; 862 mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr; 863 struct mlndr_stream *mlnds = &mxa->send_mlnds; 864 unsigned long fault_status; 865 866 MLNDS_RESET(mlnds); 867 868 hdr->rpc_vers = 5; 869 hdr->rpc_vers_minor = 0; 870 hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG; 871 hdr->packed_drep = rhdr->packed_drep; 872 hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr); 873 hdr->auth_length = 0; 874 hdr->call_id = rhdr->call_id; 875 #ifdef _BIG_ENDIAN 876 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII 877 | MLRPC_REPLAB_INTG_BIG_ENDIAN; 878 #else 879 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII 880 | MLRPC_REPLAB_INTG_LITTLE_ENDIAN; 881 #endif 882 883 switch (drc & MLRPC_DRC_MASK_SPECIFIER) { 884 case MLRPC_DRC_FAULT_OUT_OF_MEMORY: 885 case MLRPC_DRC_FAULT_ENCODE_TOO_BIG: 886 fault_status = MLRPC_FAULT_NCA_OUT_ARGS_TOO_BIG; 887 break; 888 889 case MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID: 890 fault_status = MLRPC_FAULT_NCA_INVALID_PRES_CONTEXT_ID; 891 break; 892 893 case MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID: 894 fault_status = MLRPC_FAULT_NCA_OP_RNG_ERROR; 895 break; 896 897 case MLRPC_DRC_FAULT_DECODE_FAILED: 898 case MLRPC_DRC_FAULT_ENCODE_FAILED: 899 fault_status = MLRPC_FAULT_NCA_PROTO_ERROR; 900 break; 901 902 default: 903 fault_status = MLRPC_FAULT_NCA_UNSPEC_REJECT; 904 break; 905 } 906 907 mxa->send_hdr.fault_hdr.common_hdr.ptype = MLRPC_PTYPE_FAULT; 908 mxa->send_hdr.fault_hdr.status = fault_status; 909 mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length; 910 } 911 912 static int 913 mlrpc_build_reply(struct mlrpc_xaction *mxa) 914 { 915 mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr; 916 struct mlndr_stream *mlnds = &mxa->send_mlnds; 917 uint8_t *pdu_buf; 918 unsigned long pdu_size; 919 unsigned long frag_size; 920 unsigned long pdu_data_size; 921 unsigned long frag_data_size; 922 923 frag_size = mlrpc_frag_size; 924 pdu_size = mlnds->pdu_size; 925 pdu_buf = mlnds->pdu_base_addr; 926 927 if (pdu_size <= frag_size) { 928 /* 929 * Single fragment response. The PDU size may be zero 930 * here (i.e. bind or fault response). So don't make 931 * any assumptions about it until after the header is 932 * encoded. 933 */ 934 switch (hdr->ptype) { 935 case MLRPC_PTYPE_BIND_ACK: 936 mlrpc_reply_bind_ack(mxa); 937 break; 938 939 case MLRPC_PTYPE_FAULT: 940 /* already setup */ 941 break; 942 943 case MLRPC_PTYPE_RESPONSE: 944 hdr->frag_length = pdu_size; 945 mxa->send_hdr.response_hdr.alloc_hint = 946 hdr->frag_length; 947 break; 948 949 default: 950 hdr->frag_length = pdu_size; 951 break; 952 } 953 954 mlnds->pdu_scan_offset = 0; 955 (void) mlrpc_encode_pdu_hdr(mxa); 956 pdu_size = mlnds->pdu_size; 957 mlrpc_build_frag(mlnds, pdu_buf, pdu_size); 958 return (0); 959 } 960 961 /* 962 * Multiple fragment response. 963 */ 964 hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG; 965 hdr->frag_length = frag_size; 966 mxa->send_hdr.response_hdr.alloc_hint = pdu_size - MLRPC_RSP_HDR_SIZE; 967 mlnds->pdu_scan_offset = 0; 968 (void) mlrpc_encode_pdu_hdr(mxa); 969 mlrpc_build_frag(mlnds, pdu_buf, frag_size); 970 971 /* 972 * We need to update the 24-byte header in subsequent fragments. 973 * 974 * pdu_data_size: total data remaining to be handled 975 * frag_size: total fragment size including header 976 * frag_data_size: data in fragment 977 * (i.e. frag_size - MLRPC_RSP_HDR_SIZE) 978 */ 979 pdu_data_size = pdu_size - MLRPC_RSP_HDR_SIZE; 980 frag_data_size = frag_size - MLRPC_RSP_HDR_SIZE; 981 982 while (pdu_data_size) { 983 mxa->send_hdr.response_hdr.alloc_hint -= frag_data_size; 984 pdu_data_size -= frag_data_size; 985 pdu_buf += frag_data_size; 986 987 if (pdu_data_size <= frag_data_size) { 988 frag_data_size = pdu_data_size; 989 frag_size = frag_data_size + MLRPC_RSP_HDR_SIZE; 990 hdr->pfc_flags = MLRPC_PFC_LAST_FRAG; 991 } else { 992 hdr->pfc_flags = 0; 993 } 994 995 hdr->frag_length = frag_size; 996 mlnds->pdu_scan_offset = 0; 997 (void) mlrpc_encode_pdu_hdr(mxa); 998 bcopy(mlnds->pdu_base_addr, pdu_buf, MLRPC_RSP_HDR_SIZE); 999 1000 mlrpc_build_frag(mlnds, pdu_buf, frag_size); 1001 1002 if (hdr->pfc_flags & MLRPC_PFC_LAST_FRAG) 1003 break; 1004 } 1005 1006 return (0); 1007 } 1008 1009 /* 1010 * mlrpc_build_frag 1011 * 1012 * Build an RPC PDU fragment from the specified buffer. 1013 * If malloc fails, the client will see a header/pdu inconsistency 1014 * and report an error. 1015 */ 1016 static void 1017 mlrpc_build_frag(struct mlndr_stream *mlnds, uint8_t *buf, uint32_t len) 1018 { 1019 ndr_frag_t *frag; 1020 int size = sizeof (ndr_frag_t) + len; 1021 1022 if ((frag = (ndr_frag_t *)malloc(size)) == NULL) 1023 return; 1024 1025 frag->next = NULL; 1026 frag->buf = (uint8_t *)frag + sizeof (ndr_frag_t); 1027 frag->len = len; 1028 bcopy(buf, frag->buf, len); 1029 1030 if (mlnds->frags.head == NULL) { 1031 mlnds->frags.head = frag; 1032 mlnds->frags.tail = frag; 1033 mlnds->frags.nfrag = 1; 1034 } else { 1035 mlnds->frags.tail->next = frag; 1036 mlnds->frags.tail = frag; 1037 ++mlnds->frags.nfrag; 1038 } 1039 } 1040