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 #include <assert.h> 26 #include <strings.h> 27 #include <sys/param.h> 28 29 #include <smbsrv/libsmb.h> 30 #include <smbsrv/libmlrpc.h> 31 32 #ifdef _BIG_ENDIAN 33 static const int ndr_native_byte_order = NDR_REPLAB_INTG_BIG_ENDIAN; 34 #else 35 static const int ndr_native_byte_order = NDR_REPLAB_INTG_LITTLE_ENDIAN; 36 #endif 37 38 static int ndr_decode_hdr_common(ndr_stream_t *, ndr_common_header_t *); 39 static int ndr_decode_pac_hdr(ndr_stream_t *, ndr_pac_hdr_t *); 40 41 static int 42 ndr_encode_decode_common(ndr_stream_t *nds, unsigned opnum, 43 ndr_typeinfo_t *ti, void *datum) 44 { 45 int rc; 46 47 /* 48 * Perform the (un)marshalling 49 */ 50 if (ndo_operation(nds, ti, opnum, datum)) 51 return (NDR_DRC_OK); 52 53 switch (nds->error) { 54 case NDR_ERR_MALLOC_FAILED: 55 rc = NDR_DRC_FAULT_OUT_OF_MEMORY; 56 break; 57 58 case NDR_ERR_SWITCH_VALUE_INVALID: 59 rc = NDR_DRC_FAULT_PARAM_0_INVALID; 60 break; 61 62 case NDR_ERR_UNDERFLOW: 63 rc = NDR_DRC_FAULT_RECEIVED_RUNT; 64 break; 65 66 case NDR_ERR_GROW_FAILED: 67 rc = NDR_DRC_FAULT_ENCODE_TOO_BIG; 68 break; 69 70 default: 71 if (nds->m_op == NDR_M_OP_MARSHALL) 72 rc = NDR_DRC_FAULT_ENCODE_FAILED; 73 else 74 rc = NDR_DRC_FAULT_DECODE_FAILED; 75 break; 76 } 77 78 return (rc); 79 } 80 81 ndr_buf_t * 82 ndr_buf_init(ndr_typeinfo_t *ti) 83 { 84 ndr_buf_t *nbuf; 85 86 if ((nbuf = calloc(1, sizeof (ndr_buf_t))) == NULL) 87 return (NULL); 88 89 if ((nbuf->nb_heap = ndr_heap_create()) == NULL) { 90 free(nbuf); 91 return (NULL); 92 } 93 94 nbuf->nb_ti = ti; 95 nbuf->nb_magic = NDR_BUF_MAGIC; 96 return (nbuf); 97 } 98 99 void 100 ndr_buf_fini(ndr_buf_t *nbuf) 101 { 102 assert(nbuf->nb_magic == NDR_BUF_MAGIC); 103 104 nds_destruct(&nbuf->nb_nds); 105 ndr_heap_destroy(nbuf->nb_heap); 106 nbuf->nb_magic = 0; 107 free(nbuf); 108 } 109 110 /* 111 * Decode an NDR encoded buffer. The buffer is expected to contain 112 * a single fragment packet with a valid PDU header followed by NDR 113 * encoded data. The structure to which result points should be 114 * of the appropriate type to hold the decoded output. For example: 115 * 116 * pac_info_t info; 117 * 118 * if ((nbuf = ndr_buf_init(&TYPEINFO(ndr_pac)) != NULL) { 119 * rc = ndr_decode_buf(nbuf, opnum, data, datalen, &info); 120 * ... 121 * ndr_buf_fini(nbuf); 122 * } 123 */ 124 int 125 ndr_buf_decode(ndr_buf_t *nbuf, unsigned hdr_type, unsigned opnum, 126 const char *data, size_t datalen, void *result) 127 { 128 ndr_common_header_t hdr; 129 ndr_pac_hdr_t pac_hdr; 130 unsigned pdu_size_hint; 131 int rc; 132 133 assert(nbuf->nb_magic == NDR_BUF_MAGIC); 134 assert(nbuf->nb_heap != NULL); 135 assert(nbuf->nb_ti != NULL); 136 137 if (datalen < NDR_PDU_SIZE_HINT_DEFAULT) 138 pdu_size_hint = NDR_PDU_SIZE_HINT_DEFAULT; 139 else 140 pdu_size_hint = datalen; 141 142 rc = nds_initialize(&nbuf->nb_nds, pdu_size_hint, NDR_MODE_BUF_DECODE, 143 nbuf->nb_heap); 144 if (NDR_DRC_IS_FAULT(rc)) 145 return (rc); 146 147 bcopy(data, nbuf->nb_nds.pdu_base_addr, datalen); 148 149 switch (hdr_type) { 150 case NDR_PTYPE_COMMON: 151 rc = ndr_decode_hdr_common(&nbuf->nb_nds, &hdr); 152 if (NDR_DRC_IS_FAULT(rc)) 153 return (rc); 154 155 if (!NDR_IS_SINGLE_FRAG(hdr.pfc_flags)) 156 return (NDR_DRC_FAULT_DECODE_FAILED); 157 break; 158 159 case NDR_PTYPE_PAC: 160 rc = ndr_decode_pac_hdr(&nbuf->nb_nds, &pac_hdr); 161 if (NDR_DRC_IS_FAULT(rc)) 162 return (rc); 163 164 if (pac_hdr.common_hdr.hdrlen != sizeof (ndr_serialtype1_hdr_t)) 165 return (NDR_DRC_FAULT_DECODE_FAILED); 166 break; 167 168 default: 169 return (NDR_ERR_UNIMPLEMENTED); 170 } 171 172 rc = ndr_encode_decode_common(&nbuf->nb_nds, opnum, nbuf->nb_ti, 173 result); 174 return (rc); 175 } 176 177 /* 178 * Use the receive stream to unmarshall data (NDR_MODE_CALL_RECV). 179 */ 180 int 181 ndr_decode_call(ndr_xa_t *mxa, void *params) 182 { 183 ndr_stream_t *nds = &mxa->recv_nds; 184 int rc; 185 186 if (!NDR_MODE_MATCH(nds, NDR_MODE_CALL_RECV)) 187 return (NDR_DRC_FAULT_MODE_MISMATCH); 188 189 rc = ndr_encode_decode_common(nds, mxa->opnum, 190 mxa->binding->service->interface_ti, params); 191 192 return (rc + NDR_PTYPE_REQUEST); 193 } 194 195 /* 196 * Use the send stream to marshall data (NDR_MODE_RETURN_SEND). 197 */ 198 int 199 ndr_encode_return(ndr_xa_t *mxa, void *params) 200 { 201 ndr_stream_t *nds = &mxa->send_nds; 202 int rc; 203 204 if (!NDR_MODE_MATCH(nds, NDR_MODE_RETURN_SEND)) 205 return (NDR_DRC_FAULT_MODE_MISMATCH); 206 207 rc = ndr_encode_decode_common(nds, mxa->opnum, 208 mxa->binding->service->interface_ti, params); 209 210 return (rc + NDR_PTYPE_RESPONSE); 211 } 212 213 /* 214 * Use the send stream to marshall data (NDR_MODE_CALL_SEND). 215 */ 216 int 217 ndr_encode_call(ndr_xa_t *mxa, void *params) 218 { 219 ndr_stream_t *nds = &mxa->send_nds; 220 int rc; 221 222 if (!NDR_MODE_MATCH(nds, NDR_MODE_CALL_SEND)) 223 return (NDR_DRC_FAULT_MODE_MISMATCH); 224 225 rc = ndr_encode_decode_common(nds, mxa->opnum, 226 mxa->binding->service->interface_ti, params); 227 228 return (rc + NDR_PTYPE_REQUEST); 229 } 230 231 /* 232 * Use the receive stream to unmarshall data (NDR_MODE_RETURN_RECV). 233 */ 234 int 235 ndr_decode_return(ndr_xa_t *mxa, void *params) 236 { 237 ndr_stream_t *nds = &mxa->recv_nds; 238 int rc; 239 240 if (!NDR_MODE_MATCH(nds, NDR_MODE_RETURN_RECV)) 241 return (NDR_DRC_FAULT_MODE_MISMATCH); 242 243 rc = ndr_encode_decode_common(nds, mxa->opnum, 244 mxa->binding->service->interface_ti, params); 245 246 return (rc + NDR_PTYPE_RESPONSE); 247 } 248 249 int 250 ndr_decode_pdu_hdr(ndr_xa_t *mxa) 251 { 252 ndr_common_header_t *hdr = &mxa->recv_hdr.common_hdr; 253 ndr_stream_t *nds = &mxa->recv_nds; 254 int rc; 255 256 rc = ndr_decode_hdr_common(nds, hdr); 257 if (NDR_DRC_IS_FAULT(rc)) 258 return (rc); 259 260 /* 261 * Verify the protocol version. 262 */ 263 if ((hdr->rpc_vers != 5) || (hdr->rpc_vers_minor != 0)) 264 return (NDR_DRC_FAULT_RPCHDR_DECODE_FAILED); 265 266 mxa->ptype = hdr->ptype; 267 return (NDR_DRC_OK); 268 } 269 270 static int 271 ndr_decode_hdr_common(ndr_stream_t *nds, ndr_common_header_t *hdr) 272 { 273 int ptype; 274 int rc; 275 int charset; 276 int byte_order; 277 278 if (nds->m_op != NDR_M_OP_UNMARSHALL) 279 return (NDR_DRC_FAULT_RPCHDR_MODE_MISMATCH); 280 281 /* 282 * All PDU headers are at least this big 283 */ 284 rc = NDS_GROW_PDU(nds, sizeof (ndr_common_header_t), 0); 285 if (!rc) 286 return (NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT); 287 288 /* 289 * Peek at the first eight bytes to figure out what we're doing. 290 */ 291 rc = NDS_GET_PDU(nds, 0, 8, (char *)hdr, 0, 0); 292 if (!rc) 293 return (NDR_DRC_FAULT_RPCHDR_DECODE_FAILED); 294 295 /* 296 * Check for ASCII as the character set. This is an ASCII 297 * versus EBCDIC option and has nothing to do with Unicode. 298 */ 299 charset = hdr->packed_drep.intg_char_rep & NDR_REPLAB_CHAR_MASK; 300 if (charset != NDR_REPLAB_CHAR_ASCII) 301 return (NDR_DRC_FAULT_RPCHDR_DECODE_FAILED); 302 303 /* 304 * Set the byte swap flag if the PDU byte-order 305 * is different from the local byte-order. 306 */ 307 byte_order = hdr->packed_drep.intg_char_rep & NDR_REPLAB_INTG_MASK; 308 nds->swap = (byte_order != ndr_native_byte_order) ? 1 : 0; 309 310 ptype = hdr->ptype; 311 if (ptype == NDR_PTYPE_REQUEST && 312 (hdr->pfc_flags & NDR_PFC_OBJECT_UUID) != 0) { 313 ptype = NDR_PTYPE_REQUEST_WITH; /* fake for sizing */ 314 } 315 316 rc = ndr_encode_decode_common(nds, ptype, &TYPEINFO(ndr_hdr), hdr); 317 318 return (NDR_DRC_PTYPE_RPCHDR(rc)); 319 } 320 321 static int 322 ndr_decode_pac_hdr(ndr_stream_t *nds, ndr_pac_hdr_t *hdr) 323 { 324 int rc; 325 326 if (nds->m_op != NDR_M_OP_UNMARSHALL) 327 return (NDR_DRC_FAULT_RPCHDR_MODE_MISMATCH); 328 329 /* 330 * All PDU headers are at least this big 331 */ 332 rc = NDS_GROW_PDU(nds, sizeof (ndr_pac_hdr_t), 0); 333 if (!rc) 334 return (NDR_DRC_FAULT_RPCHDR_RECEIVED_RUNT); 335 336 /* 337 * Peek at the first eight bytes to figure out what we're doing. 338 */ 339 rc = NDS_GET_PDU(nds, 0, 8, (char *)hdr, 0, 0); 340 if (!rc) 341 return (NDR_DRC_FAULT_RPCHDR_DECODE_FAILED); 342 343 /* Must be set to 1 to indicate type serialization version 1. */ 344 if (hdr->common_hdr.version != 1) 345 return (NDR_DRC_FAULT_RPCHDR_DECODE_FAILED); 346 347 /* 348 * Set the byte swap flag if the PDU byte-order 349 * is different from the local byte-order. 350 */ 351 nds->swap = 352 (hdr->common_hdr.endianness != ndr_native_byte_order) ? 1 : 0; 353 354 rc = ndr_encode_decode_common(nds, NDR_PTYPE_PAC, 355 &TYPEINFO(ndr_hdr), hdr); 356 357 return (NDR_DRC_PTYPE_RPCHDR(rc)); 358 } 359 360 /* 361 * Decode an RPC fragment header. Use ndr_decode_pdu_hdr() to process 362 * the first fragment header then this function to process additional 363 * fragment headers. 364 */ 365 void 366 ndr_decode_frag_hdr(ndr_stream_t *nds, ndr_common_header_t *hdr) 367 { 368 ndr_common_header_t *tmp; 369 uint8_t *pdu; 370 int byte_order; 371 372 pdu = (uint8_t *)nds->pdu_base_offset + nds->pdu_scan_offset; 373 bcopy(pdu, hdr, NDR_RSP_HDR_SIZE); 374 375 /* 376 * Swap non-byte fields if the PDU byte-order 377 * is different from the local byte-order. 378 */ 379 byte_order = hdr->packed_drep.intg_char_rep & NDR_REPLAB_INTG_MASK; 380 381 if (byte_order != ndr_native_byte_order) { 382 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 383 tmp = (ndr_common_header_t *)pdu; 384 385 nds_bswap(&tmp->frag_length, &hdr->frag_length, 386 sizeof (WORD)); 387 nds_bswap(&tmp->auth_length, &hdr->auth_length, 388 sizeof (WORD)); 389 nds_bswap(&tmp->call_id, &hdr->call_id, sizeof (DWORD)); 390 } 391 } 392 393 /* 394 * Remove an RPC fragment header from the received data stream. 395 * 396 * NDR stream on entry: 397 * 398 * |<--- frag --->| 399 * +-----+--------+-----+--------+-----+---------+-----+ 400 * | hdr | data | hdr | data | hdr | data | ... | 401 * +-----+--------+-----+--------+-----+---------+-----+ 402 * <---- 403 * 404 * NDR stream on return: 405 * 406 * +-----+----------------+-----+---------+-----+ 407 * | hdr | data | hdr | data | ... | 408 * +-----+----------------+-----+---------+-----+ 409 */ 410 void 411 ndr_remove_frag_hdr(ndr_stream_t *nds) 412 { 413 char *hdr; 414 char *data; 415 int nbytes; 416 417 hdr = (char *)nds->pdu_base_offset + nds->pdu_scan_offset; 418 data = hdr + NDR_RSP_HDR_SIZE; 419 nbytes = nds->pdu_size - nds->pdu_scan_offset - NDR_RSP_HDR_SIZE; 420 421 bcopy(data, hdr, nbytes); 422 nds->pdu_size -= NDR_RSP_HDR_SIZE; 423 } 424 425 void 426 ndr_show_hdr(ndr_common_header_t *hdr) 427 { 428 char *fragtype; 429 430 if (hdr == NULL) { 431 ndo_printf(NULL, NULL, "ndr hdr: <null>"); 432 return; 433 } 434 435 if (NDR_IS_SINGLE_FRAG(hdr->pfc_flags)) 436 fragtype = "single"; 437 else if (NDR_IS_FIRST_FRAG(hdr->pfc_flags)) 438 fragtype = "first"; 439 else if (NDR_IS_LAST_FRAG(hdr->pfc_flags)) 440 fragtype = "last"; 441 else 442 fragtype = "intermediate"; 443 444 ndo_printf(NULL, NULL, 445 "ndr hdr: %d.%d ptype=%d, %s frag (flags=0x%08x) len=%d", 446 hdr->rpc_vers, hdr->rpc_vers_minor, hdr->ptype, 447 fragtype, hdr->pfc_flags, hdr->frag_length); 448 } 449 450 int 451 ndr_encode_pdu_hdr(ndr_xa_t *mxa) 452 { 453 ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr; 454 ndr_stream_t *nds = &mxa->send_nds; 455 int ptype; 456 int rc; 457 458 if (nds->m_op != NDR_M_OP_MARSHALL) 459 return (NDR_DRC_FAULT_RPCHDR_MODE_MISMATCH); 460 461 ptype = hdr->ptype; 462 if (ptype == NDR_PTYPE_REQUEST && 463 (hdr->pfc_flags & NDR_PFC_OBJECT_UUID) != 0) { 464 ptype = NDR_PTYPE_REQUEST_WITH; /* fake for sizing */ 465 } 466 467 rc = ndr_encode_decode_common(nds, ptype, &TYPEINFO(ndr_hdr), hdr); 468 469 return (NDR_DRC_PTYPE_RPCHDR(rc)); 470 } 471 472 /* 473 * This is a hand-coded derivative of the automatically generated 474 * (un)marshalling routine for bind_ack headers. bind_ack headers 475 * have an interior conformant array, which is inconsistent with 476 * IDL/NDR rules. 477 */ 478 extern struct ndr_typeinfo ndt__uchar; 479 extern struct ndr_typeinfo ndt__ushort; 480 extern struct ndr_typeinfo ndt__ulong; 481 482 int ndr__ndr_bind_ack_hdr(ndr_ref_t *encl_ref); 483 ndr_typeinfo_t ndt__ndr_bind_ack_hdr = { 484 1, /* NDR version */ 485 3, /* alignment */ 486 NDR_F_STRUCT, /* flags */ 487 ndr__ndr_bind_ack_hdr, /* ndr_func */ 488 68, /* pdu_size_fixed_part */ 489 0, /* pdu_size_variable_part */ 490 68, /* c_size_fixed_part */ 491 0, /* c_size_variable_part */ 492 }; 493 494 /* 495 * [_no_reorder] 496 */ 497 int 498 ndr__ndr_bind_ack_hdr(ndr_ref_t *encl_ref) 499 { 500 ndr_stream_t *nds = encl_ref->stream; 501 struct ndr_bind_ack_hdr *val = /*LINTED E_BAD_PTR_CAST_ALIGN*/ 502 (struct ndr_bind_ack_hdr *)encl_ref->datum; 503 ndr_ref_t myref; 504 unsigned long offset; 505 506 bzero(&myref, sizeof (myref)); 507 myref.enclosing = encl_ref; 508 myref.stream = encl_ref->stream; 509 myref.packed_alignment = 0; 510 511 /* do all members in order */ 512 NDR_MEMBER(_ndr_common_header, common_hdr, 0UL); 513 NDR_MEMBER(_ushort, max_xmit_frag, 16UL); 514 NDR_MEMBER(_ushort, max_recv_frag, 18UL); 515 NDR_MEMBER(_ulong, assoc_group_id, 20UL); 516 517 /* port any is the conformant culprit */ 518 offset = 24UL; 519 520 switch (nds->m_op) { 521 case NDR_M_OP_MARSHALL: 522 val->sec_addr.length = 523 strlen((char *)val->sec_addr.port_spec) + 1; 524 break; 525 526 case NDR_M_OP_UNMARSHALL: 527 break; 528 529 default: 530 NDR_SET_ERROR(encl_ref, NDR_ERR_M_OP_INVALID); 531 return (0); 532 } 533 534 NDR_MEMBER(_ushort, sec_addr.length, offset); 535 NDR_MEMBER_ARR_WITH_DIMENSION(_uchar, sec_addr.port_spec, 536 offset+2UL, val->sec_addr.length); 537 538 offset += 2; 539 offset += val->sec_addr.length; 540 offset += NDR_ALIGN4(offset); 541 542 NDR_MEMBER(_ndr_p_result_list, p_result_list, offset); 543 return (1); 544 } 545 546 /* 547 * Assume a single presentation context element in the result list. 548 */ 549 unsigned 550 ndr_bind_ack_hdr_size(ndr_xa_t *mxa) 551 { 552 ndr_bind_ack_hdr_t *bahdr = &mxa->send_hdr.bind_ack_hdr; 553 unsigned offset; 554 unsigned length; 555 556 /* port any is the conformant culprit */ 557 offset = 24UL; 558 559 length = strlen((char *)bahdr->sec_addr.port_spec) + 1; 560 561 offset += 2; 562 offset += length; 563 offset += NDR_ALIGN4(offset); 564 offset += sizeof (ndr_p_result_list_t); 565 return (offset); 566 } 567 568 /* 569 * This is a hand-coded derivative of the automatically generated 570 * (un)marshalling routine for alter_context_rsp headers. 571 * Alter context response headers have an interior conformant array, 572 * which is inconsistent with IDL/NDR rules. 573 */ 574 int ndr__ndr_alter_context_rsp_hdr(ndr_ref_t *encl_ref); 575 ndr_typeinfo_t ndt__ndr_alter_context_rsp_hdr = { 576 1, /* NDR version */ 577 3, /* alignment */ 578 NDR_F_STRUCT, /* flags */ 579 ndr__ndr_alter_context_rsp_hdr, /* ndr_func */ 580 56, /* pdu_size_fixed_part */ 581 0, /* pdu_size_variable_part */ 582 56, /* c_size_fixed_part */ 583 0, /* c_size_variable_part */ 584 }; 585 586 /* 587 * [_no_reorder] 588 */ 589 int 590 ndr__ndr_alter_context_rsp_hdr(ndr_ref_t *encl_ref) 591 { 592 ndr_stream_t *nds = encl_ref->stream; 593 ndr_alter_context_rsp_hdr_t *val = /*LINTED E_BAD_PTR_CAST_ALIGN*/ 594 (ndr_alter_context_rsp_hdr_t *)encl_ref->datum; 595 ndr_ref_t myref; 596 unsigned long offset; 597 598 bzero(&myref, sizeof (myref)); 599 myref.enclosing = encl_ref; 600 myref.stream = encl_ref->stream; 601 myref.packed_alignment = 0; 602 603 /* do all members in order */ 604 NDR_MEMBER(_ndr_common_header, common_hdr, 0UL); 605 NDR_MEMBER(_ushort, max_xmit_frag, 16UL); 606 NDR_MEMBER(_ushort, max_recv_frag, 18UL); 607 NDR_MEMBER(_ulong, assoc_group_id, 20UL); 608 609 offset = 24UL; /* offset of sec_addr */ 610 611 switch (nds->m_op) { 612 case NDR_M_OP_MARSHALL: 613 val->sec_addr.length = 0; 614 break; 615 616 case NDR_M_OP_UNMARSHALL: 617 break; 618 619 default: 620 NDR_SET_ERROR(encl_ref, NDR_ERR_M_OP_INVALID); 621 return (0); 622 } 623 624 NDR_MEMBER(_ushort, sec_addr.length, offset); 625 NDR_MEMBER_ARR_WITH_DIMENSION(_uchar, sec_addr.port_spec, 626 offset+2UL, val->sec_addr.length); 627 628 offset += 2; /* sizeof (sec_addr.length) */ 629 offset += NDR_ALIGN4(offset); 630 631 NDR_MEMBER(_ndr_p_result_list, p_result_list, offset); 632 return (1); 633 } 634 635 /* 636 * Assume a single presentation context element in the result list. 637 */ 638 unsigned 639 ndr_alter_context_rsp_hdr_size(void) 640 { 641 unsigned offset; 642 643 offset = 24UL; /* offset of sec_addr */ 644 offset += 2; /* sizeof (sec_addr.length) */ 645 offset += NDR_ALIGN4(offset); 646 offset += sizeof (ndr_p_result_list_t); 647 return (offset); 648 } 649