Changeset 920 for trunk/server/librpc/rpc/dcerpc_util.c
- Timestamp:
- Jun 9, 2016, 2:23:12 PM (9 years ago)
- Location:
- trunk/server
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/server
- Property svn:mergeinfo changed
/vendor/current merged: 919
- Property svn:mergeinfo changed
-
trunk/server/librpc/rpc/dcerpc_util.c
r862 r920 28 28 #include "librpc/gen_ndr/ndr_dcerpc.h" 29 29 #include "rpc_common.h" 30 #include "lib/util/bitmap.h" 30 31 31 32 /* we need to be able to get/set the fragment length without doing a full … … 92 93 * @return - A NTSTATUS error code. 93 94 */ 94 NTSTATUS dcerpc_pull_auth_trailer( struct ncacn_packet *pkt,95 NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt, 95 96 TALLOC_CTX *mem_ctx, 96 DATA_BLOB *pkt_trailer,97 const DATA_BLOB *pkt_trailer, 97 98 struct dcerpc_auth *auth, 98 uint32_t * auth_length,99 uint32_t *_auth_length, 99 100 bool auth_data_only) 100 101 { 101 102 struct ndr_pull *ndr; 102 103 enum ndr_err_code ndr_err; 103 uint32_t data_and_pad; 104 105 data_and_pad = pkt_trailer->length 106 - (DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length); 107 108 /* paranoia check for pad size. This would be caught anyway by 109 the ndr_pull_advance() a few lines down, but it scared 110 Jeremy enough for him to call me, so we might as well check 111 it now, just to prevent someone posting a bogus YouTube 112 video in the future. 113 */ 114 if (data_and_pad > pkt_trailer->length) { 115 return NT_STATUS_INFO_LENGTH_MISMATCH; 116 } 117 118 *auth_length = pkt_trailer->length - data_and_pad; 104 uint16_t data_and_pad; 105 uint16_t auth_length; 106 uint32_t tmp_length; 107 108 ZERO_STRUCTP(auth); 109 if (_auth_length != NULL) { 110 *_auth_length = 0; 111 } 112 113 /* Paranoia checks for auth_length. The caller should check this... */ 114 if (pkt->auth_length == 0) { 115 return NT_STATUS_INTERNAL_ERROR; 116 } 117 118 /* Paranoia checks for auth_length. The caller should check this... */ 119 if (pkt->auth_length > pkt->frag_length) { 120 return NT_STATUS_INTERNAL_ERROR; 121 } 122 tmp_length = DCERPC_NCACN_PAYLOAD_OFFSET; 123 tmp_length += DCERPC_AUTH_TRAILER_LENGTH; 124 tmp_length += pkt->auth_length; 125 if (tmp_length > pkt->frag_length) { 126 return NT_STATUS_INTERNAL_ERROR; 127 } 128 if (pkt_trailer->length > UINT16_MAX) { 129 return NT_STATUS_INTERNAL_ERROR; 130 } 131 132 auth_length = DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length; 133 if (pkt_trailer->length < auth_length) { 134 return NT_STATUS_RPC_PROTOCOL_ERROR; 135 } 136 137 data_and_pad = pkt_trailer->length - auth_length; 119 138 120 139 ndr = ndr_pull_init_blob(pkt_trailer, mem_ctx); … … 136 155 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 137 156 talloc_free(ndr); 157 ZERO_STRUCTP(auth); 138 158 return ndr_map_error2ntstatus(ndr_err); 139 159 } 140 160 141 if ( auth_data_only && data_and_pad !=auth->auth_pad_length) {142 DEBUG(1, (__location__ ": WARNING: pad length mismatch. "161 if (data_and_pad < auth->auth_pad_length) { 162 DEBUG(1, (__location__ ": ERROR: pad length mismatch. " 143 163 "Calculated %u got %u\n", 144 164 (unsigned)data_and_pad, 145 165 (unsigned)auth->auth_pad_length)); 166 talloc_free(ndr); 167 ZERO_STRUCTP(auth); 168 return NT_STATUS_RPC_PROTOCOL_ERROR; 169 } 170 171 if (auth_data_only && data_and_pad != auth->auth_pad_length) { 172 DEBUG(1, (__location__ ": ERROR: pad length mismatch. " 173 "Calculated %u got %u\n", 174 (unsigned)data_and_pad, 175 (unsigned)auth->auth_pad_length)); 176 talloc_free(ndr); 177 ZERO_STRUCTP(auth); 178 return NT_STATUS_RPC_PROTOCOL_ERROR; 146 179 } 147 180 … … 151 184 talloc_steal(mem_ctx, auth->credentials.data); 152 185 talloc_free(ndr); 186 187 if (_auth_length != NULL) { 188 *_auth_length = auth_length; 189 } 190 191 return NT_STATUS_OK; 192 } 193 194 /** 195 * @brief Verify the fields in ncacn_packet header. 196 * 197 * @param pkt - The ncacn_packet strcuture 198 * @param ptype - The expected PDU type 199 * @param max_auth_info - The maximum size of a possible auth trailer 200 * @param required_flags - The required flags for the pdu. 201 * @param optional_flags - The possible optional flags for the pdu. 202 * 203 * @return - A NTSTATUS error code. 204 */ 205 NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt, 206 enum dcerpc_pkt_type ptype, 207 size_t max_auth_info, 208 uint8_t required_flags, 209 uint8_t optional_flags) 210 { 211 if (pkt->rpc_vers != 5) { 212 return NT_STATUS_RPC_PROTOCOL_ERROR; 213 } 214 215 if (pkt->rpc_vers_minor != 0) { 216 return NT_STATUS_RPC_PROTOCOL_ERROR; 217 } 218 219 if (pkt->auth_length > pkt->frag_length) { 220 return NT_STATUS_RPC_PROTOCOL_ERROR; 221 } 222 223 if (pkt->ptype != ptype) { 224 return NT_STATUS_RPC_PROTOCOL_ERROR; 225 } 226 227 if (max_auth_info > UINT16_MAX) { 228 return NT_STATUS_INTERNAL_ERROR; 229 } 230 231 if (pkt->auth_length > 0) { 232 size_t max_auth_length; 233 234 if (max_auth_info <= DCERPC_AUTH_TRAILER_LENGTH) { 235 return NT_STATUS_RPC_PROTOCOL_ERROR; 236 } 237 max_auth_length = max_auth_info - DCERPC_AUTH_TRAILER_LENGTH; 238 239 if (pkt->auth_length > max_auth_length) { 240 return NT_STATUS_RPC_PROTOCOL_ERROR; 241 } 242 } 243 244 if ((pkt->pfc_flags & required_flags) != required_flags) { 245 return NT_STATUS_RPC_PROTOCOL_ERROR; 246 } 247 if (pkt->pfc_flags & ~(optional_flags|required_flags)) { 248 return NT_STATUS_RPC_PROTOCOL_ERROR; 249 } 250 251 if (pkt->drep[0] & ~DCERPC_DREP_LE) { 252 return NT_STATUS_RPC_PROTOCOL_ERROR; 253 } 254 if (pkt->drep[1] != 0) { 255 return NT_STATUS_RPC_PROTOCOL_ERROR; 256 } 257 if (pkt->drep[2] != 0) { 258 return NT_STATUS_RPC_PROTOCOL_ERROR; 259 } 260 if (pkt->drep[3] != 0) { 261 return NT_STATUS_RPC_PROTOCOL_ERROR; 262 } 153 263 154 264 return NT_STATUS_OK; … … 342 452 return NT_STATUS_OK; 343 453 } 454 455 struct dcerpc_sec_vt_header2 dcerpc_sec_vt_header2_from_ncacn_packet(const struct ncacn_packet *pkt) 456 { 457 struct dcerpc_sec_vt_header2 ret; 458 459 ZERO_STRUCT(ret); 460 ret.ptype = pkt->ptype; 461 memcpy(&ret.drep, pkt->drep, sizeof(ret.drep)); 462 ret.call_id = pkt->call_id; 463 464 switch (pkt->ptype) { 465 case DCERPC_PKT_REQUEST: 466 ret.context_id = pkt->u.request.context_id; 467 ret.opnum = pkt->u.request.opnum; 468 break; 469 470 case DCERPC_PKT_RESPONSE: 471 ret.context_id = pkt->u.response.context_id; 472 break; 473 474 case DCERPC_PKT_FAULT: 475 ret.context_id = pkt->u.fault.context_id; 476 break; 477 478 default: 479 break; 480 } 481 482 return ret; 483 } 484 485 bool dcerpc_sec_vt_header2_equal(const struct dcerpc_sec_vt_header2 *v1, 486 const struct dcerpc_sec_vt_header2 *v2) 487 { 488 if (v1->ptype != v2->ptype) { 489 return false; 490 } 491 492 if (memcmp(v1->drep, v2->drep, sizeof(v1->drep)) != 0) { 493 return false; 494 } 495 496 if (v1->call_id != v2->call_id) { 497 return false; 498 } 499 500 if (v1->context_id != v2->context_id) { 501 return false; 502 } 503 504 if (v1->opnum != v2->opnum) { 505 return false; 506 } 507 508 return true; 509 } 510 511 static bool dcerpc_sec_vt_is_valid(const struct dcerpc_sec_verification_trailer *r) 512 { 513 bool ret = false; 514 TALLOC_CTX *frame = talloc_stackframe(); 515 struct bitmap *commands_seen; 516 int i; 517 518 if (r->count.count == 0) { 519 ret = true; 520 goto done; 521 } 522 523 if (memcmp(r->magic, DCERPC_SEC_VT_MAGIC, sizeof(r->magic)) != 0) { 524 goto done; 525 } 526 527 commands_seen = bitmap_talloc(frame, DCERPC_SEC_VT_COMMAND_ENUM + 1); 528 if (commands_seen == NULL) { 529 goto done; 530 } 531 532 for (i=0; i < r->count.count; i++) { 533 enum dcerpc_sec_vt_command_enum cmd = 534 r->commands[i].command & DCERPC_SEC_VT_COMMAND_ENUM; 535 536 if (bitmap_query(commands_seen, cmd)) { 537 /* Each command must appear at most once. */ 538 goto done; 539 } 540 bitmap_set(commands_seen, cmd); 541 542 switch (cmd) { 543 case DCERPC_SEC_VT_COMMAND_BITMASK1: 544 case DCERPC_SEC_VT_COMMAND_PCONTEXT: 545 case DCERPC_SEC_VT_COMMAND_HEADER2: 546 break; 547 default: 548 if ((r->commands[i].u._unknown.length % 4) != 0) { 549 goto done; 550 } 551 break; 552 } 553 } 554 ret = true; 555 done: 556 TALLOC_FREE(frame); 557 return ret; 558 } 559 560 #define CHECK(msg, ok) \ 561 do { \ 562 if (!ok) { \ 563 DEBUG(10, ("SEC_VT check %s failed\n", msg)); \ 564 return false; \ 565 } \ 566 } while(0) 567 568 #define CHECK_SYNTAX(msg, s1, s2) \ 569 do { \ 570 if (!ndr_syntax_id_equal(&s1, &s2)) { \ 571 TALLOC_CTX *frame = talloc_stackframe(); \ 572 DEBUG(10, ("SEC_VT check %s failed: %s vs. %s\n", msg, \ 573 ndr_syntax_id_to_string(frame, &s1), \ 574 ndr_syntax_id_to_string(frame, &s1))); \ 575 TALLOC_FREE(frame); \ 576 return false; \ 577 } \ 578 } while(0) 579 580 581 bool dcerpc_sec_verification_trailer_check( 582 const struct dcerpc_sec_verification_trailer *vt, 583 const uint32_t *bitmask1, 584 const struct dcerpc_sec_vt_pcontext *pcontext, 585 const struct dcerpc_sec_vt_header2 *header2) 586 { 587 size_t i; 588 589 if (!dcerpc_sec_vt_is_valid(vt)) { 590 return false; 591 } 592 593 for (i=0; i < vt->count.count; i++) { 594 struct dcerpc_sec_vt *c = &vt->commands[i]; 595 596 switch (c->command & DCERPC_SEC_VT_COMMAND_ENUM) { 597 case DCERPC_SEC_VT_COMMAND_BITMASK1: 598 if (bitmask1 == NULL) { 599 CHECK("Bitmask1 must_process_command", 600 !(c->command & DCERPC_SEC_VT_MUST_PROCESS)); 601 break; 602 } 603 604 if (c->u.bitmask1 & DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING) { 605 CHECK("Bitmask1 client_header_signing", 606 *bitmask1 & DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING); 607 } 608 break; 609 610 case DCERPC_SEC_VT_COMMAND_PCONTEXT: 611 if (pcontext == NULL) { 612 CHECK("Pcontext must_process_command", 613 !(c->command & DCERPC_SEC_VT_MUST_PROCESS)); 614 break; 615 } 616 617 CHECK_SYNTAX("Pcontect abstract_syntax", 618 pcontext->abstract_syntax, 619 c->u.pcontext.abstract_syntax); 620 CHECK_SYNTAX("Pcontext transfer_syntax", 621 pcontext->transfer_syntax, 622 c->u.pcontext.transfer_syntax); 623 break; 624 625 case DCERPC_SEC_VT_COMMAND_HEADER2: { 626 if (header2 == NULL) { 627 CHECK("Header2 must_process_command", 628 !(c->command & DCERPC_SEC_VT_MUST_PROCESS)); 629 break; 630 } 631 632 CHECK("Header2", dcerpc_sec_vt_header2_equal(header2, &c->u.header2)); 633 break; 634 } 635 636 default: 637 CHECK("Unknown must_process_command", 638 !(c->command & DCERPC_SEC_VT_MUST_PROCESS)); 639 break; 640 } 641 } 642 643 return true; 644 }
Note:
See TracChangeset
for help on using the changeset viewer.