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