static NTSTATUS create_rpc_bind_resp(struct cli_state *cli, uint32 rpc_call_id, prs_struct *rpc_out) { NTSTATUS nt_status; RPC_HDR hdr; RPC_HDR_AUTHA hdr_autha; DATA_BLOB ntlmssp_null_response = data_blob(NULL, 0); DATA_BLOB ntlmssp_reply; int auth_type, auth_level; /* The response is picked up from the internal cache, where it was placed by the rpc_auth_pipe() code */ nt_status = ntlmssp_update(cli->ntlmssp_pipe_state, ntlmssp_null_response, &ntlmssp_reply); if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { return nt_status; } /* Create the request RPC_HDR */ init_rpc_hdr(&hdr, RPC_BINDRESP, 0x0, rpc_call_id, RPC_HEADER_LEN + RPC_HDR_AUTHA_LEN + ntlmssp_reply.length, ntlmssp_reply.length ); /* Marshall it. */ if(!smb_io_rpc_hdr("hdr", &hdr, rpc_out, 0)) { DEBUG(0,("create_rpc_bind_resp: failed to marshall RPC_HDR.\n")); data_blob_free(&ntlmssp_reply); return NT_STATUS_NO_MEMORY; } get_auth_type_level(cli->pipe_auth_flags, &auth_type, &auth_level); /* Create the request RPC_HDR_AUTHA */ init_rpc_hdr_autha(&hdr_autha, MAX_PDU_FRAG_LEN, MAX_PDU_FRAG_LEN, auth_type, auth_level, 0x00); if(!smb_io_rpc_hdr_autha("hdr_autha", &hdr_autha, rpc_out, 0)) { DEBUG(0,("create_rpc_bind_resp: failed to marshall RPC_HDR_AUTHA.\n")); data_blob_free(&ntlmssp_reply); return NT_STATUS_NO_MEMORY; } /* * Append the auth data to the outgoing buffer. */ if(!prs_copy_data_in(rpc_out, (char *)ntlmssp_reply.data, ntlmssp_reply.length)) { DEBUG(0,("create_rpc_bind_req: failed to grow parse struct to add auth.\n")); data_blob_free(&ntlmssp_reply); return NT_STATUS_NO_MEMORY; } data_blob_free(&ntlmssp_reply); return NT_STATUS_OK; }
static uint32 create_rpc_request(prs_struct *rpc_out, uint8 op_num, int data_len, int auth_len, uint8 flags, uint32 oldid, uint32 data_left) { uint32 alloc_hint; RPC_HDR hdr; RPC_HDR_REQ hdr_req; uint32 callid = oldid ? oldid : get_rpc_call_id(); DEBUG(5,("create_rpc_request: opnum: 0x%x data_len: 0x%x\n", op_num, data_len)); /* create the rpc header RPC_HDR */ init_rpc_hdr(&hdr, RPC_REQUEST, flags, callid, data_len, auth_len); /* * The alloc hint should be the amount of data, not including * RPC headers & footers. */ if (auth_len != 0) alloc_hint = data_len - RPC_HEADER_LEN - RPC_HDR_AUTH_LEN - auth_len; else alloc_hint = data_len - RPC_HEADER_LEN; DEBUG(10,("create_rpc_request: data_len: %x auth_len: %x alloc_hint: %x\n", data_len, auth_len, alloc_hint)); /* Create the rpc request RPC_HDR_REQ */ init_rpc_hdr_req(&hdr_req, alloc_hint, op_num); /* stream-time... */ if(!smb_io_rpc_hdr("hdr ", &hdr, rpc_out, 0)) return 0; if(!smb_io_rpc_hdr_req("hdr_req", &hdr_req, rpc_out, 0)) return 0; if (prs_offset(rpc_out) != RPC_HEADER_LEN + RPC_HDR_REQ_LEN) return 0; return callid; }
static BOOL rpc_check_hdr(prs_struct *rdata, RPC_HDR *rhdr, BOOL *first, BOOL *last, uint32 *len) { DEBUG(5,("rpc_check_hdr: rdata->data_size = %u\n", (uint32)prs_data_size(rdata) )); /* Next call sets endian bit. */ if(!smb_io_rpc_hdr("rpc_hdr ", rhdr, rdata, 0)) { DEBUG(0,("rpc_check_hdr: Failed to unmarshall RPC_HDR.\n")); return False; } if (prs_offset(rdata) != RPC_HEADER_LEN) { DEBUG(0,("rpc_check_hdr: offset was %x, should be %x.\n", prs_offset(rdata), RPC_HEADER_LEN)); return False; } (*first) = ((rhdr->flags & RPC_FLG_FIRST) != 0); (*last) = ((rhdr->flags & RPC_FLG_LAST ) != 0); (*len) = (uint32)rhdr->frag_len - prs_data_size(rdata); return (rhdr->pkt_type != RPC_FAULT); }
static ssize_t unmarshall_rpc_header(pipes_struct *p) { /* * Unmarshall the header to determine the needed length. */ prs_struct rpc_in; if(p->in_data.pdu_received_len != RPC_HEADER_LEN) { DEBUG(0,("unmarshall_rpc_header: assert on rpc header length failed.\n")); set_incoming_fault(p); return -1; } prs_init_empty( &rpc_in, p->mem_ctx, UNMARSHALL); prs_set_endian_data( &rpc_in, p->endian); prs_give_memory( &rpc_in, (char *)&p->in_data.current_in_pdu[0], p->in_data.pdu_received_len, False); /* * Unmarshall the header as this will tell us how much * data we need to read to get the complete pdu. * This also sets the endian flag in rpc_in. */ if(!smb_io_rpc_hdr("", &p->hdr, &rpc_in, 0)) { DEBUG(0,("unmarshall_rpc_header: failed to unmarshall RPC_HDR.\n")); set_incoming_fault(p); prs_mem_free(&rpc_in); return -1; } /* * Validate the RPC header. */ if(p->hdr.major != 5 && p->hdr.minor != 0) { DEBUG(0,("unmarshall_rpc_header: invalid major/minor numbers in RPC_HDR.\n")); set_incoming_fault(p); prs_mem_free(&rpc_in); return -1; } /* * If there's not data in the incoming buffer this should be the start of a new RPC. */ if(prs_offset(&p->in_data.data) == 0) { /* * AS/U doesn't set FIRST flag in a BIND packet it seems. */ if ((p->hdr.pkt_type == RPC_REQUEST) && !(p->hdr.flags & RPC_FLG_FIRST)) { /* * Ensure that the FIRST flag is set. If not then we have * a stream missmatch. */ DEBUG(0,("unmarshall_rpc_header: FIRST flag not set in first PDU !\n")); set_incoming_fault(p); prs_mem_free(&rpc_in); return -1; } /* * If this is the first PDU then set the endianness * flag in the pipe. We will need this when parsing all * data in this RPC. */ p->endian = rpc_in.bigendian_data; DEBUG(5,("unmarshall_rpc_header: using %sendian RPC\n", p->endian == RPC_LITTLE_ENDIAN ? "little-" : "big-" )); } else { /* * If this is *NOT* the first PDU then check the endianness * flag in the pipe is the same as that in the PDU. */ if (p->endian != rpc_in.bigendian_data) { DEBUG(0,("unmarshall_rpc_header: FIRST endianness flag (%d) different in next PDU !\n", (int)p->endian)); set_incoming_fault(p); prs_mem_free(&rpc_in); return -1; } } /* * Ensure that the pdu length is sane. */ if((p->hdr.frag_len < RPC_HEADER_LEN) || (p->hdr.frag_len > RPC_MAX_PDU_FRAG_LEN)) { DEBUG(0,("unmarshall_rpc_header: assert on frag length failed.\n")); set_incoming_fault(p); prs_mem_free(&rpc_in); return -1; } DEBUG(10,("unmarshall_rpc_header: type = %u, flags = %u\n", (unsigned int)p->hdr.pkt_type, (unsigned int)p->hdr.flags )); p->in_data.pdu_needed_len = (uint32)p->hdr.frag_len - RPC_HEADER_LEN; prs_mem_free(&rpc_in); p->in_data.current_in_pdu = TALLOC_REALLOC_ARRAY( p, p->in_data.current_in_pdu, uint8_t, p->hdr.frag_len); if (p->in_data.current_in_pdu == NULL) { DEBUG(0, ("talloc failed\n")); set_incoming_fault(p); return -1; } return 0; /* No extra data processed. */ }
BOOL create_next_pdu(pipes_struct *p) { RPC_HDR_RESP hdr_resp; BOOL auth_verify = ((p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SIGN) != 0); BOOL auth_seal = ((p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SEAL) != 0); uint32 ss_padding_len = 0; uint32 data_len; uint32 data_space_available; uint32 data_len_left; prs_struct outgoing_pdu; uint32 data_pos; /* * If we're in the fault state, keep returning fault PDU's until * the pipe gets closed. JRA. */ if(p->fault_state) { setup_fault_pdu(p, NT_STATUS(0x1c010002)); return True; } memset((char *)&hdr_resp, '\0', sizeof(hdr_resp)); /* Change the incoming request header to a response. */ p->hdr.pkt_type = RPC_RESPONSE; /* Set up rpc header flags. */ if (p->out_data.data_sent_length == 0) { p->hdr.flags = RPC_FLG_FIRST; } else { p->hdr.flags = 0; } /* * Work out how much we can fit in a single PDU. */ data_space_available = sizeof(p->out_data.current_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN; if(p->ntlmssp_auth_validated) { data_space_available -= (RPC_HDR_AUTH_LEN + RPC_AUTH_NTLMSSP_CHK_LEN); } else if(p->netsec_auth_validated) { data_space_available -= (RPC_HDR_AUTH_LEN + RPC_AUTH_NETSEC_SIGN_OR_SEAL_CHK_LEN); } /* * The amount we send is the minimum of the available * space and the amount left to send. */ data_len_left = prs_offset(&p->out_data.rdata) - p->out_data.data_sent_length; /* * Ensure there really is data left to send. */ if(!data_len_left) { DEBUG(0,("create_next_pdu: no data left to send !\n")); return False; } data_len = MIN(data_len_left, data_space_available); /* * Set up the alloc hint. This should be the data left to * send. */ hdr_resp.alloc_hint = data_len_left; /* * Work out if this PDU will be the last. */ if(p->out_data.data_sent_length + data_len >= prs_offset(&p->out_data.rdata)) { p->hdr.flags |= RPC_FLG_LAST; if ((auth_seal || auth_verify) && (data_len_left % 8)) { ss_padding_len = 8 - (data_len_left % 8); DEBUG(10,("create_next_pdu: adding sign/seal padding of %u\n", ss_padding_len )); } } /* * Set up the header lengths. */ if (p->ntlmssp_auth_validated) { p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len + ss_padding_len + RPC_HDR_AUTH_LEN + RPC_AUTH_NTLMSSP_CHK_LEN; p->hdr.auth_len = RPC_AUTH_NTLMSSP_CHK_LEN; } else if (p->netsec_auth_validated) { p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len + ss_padding_len + RPC_HDR_AUTH_LEN + RPC_AUTH_NETSEC_SIGN_OR_SEAL_CHK_LEN; p->hdr.auth_len = RPC_AUTH_NETSEC_SIGN_OR_SEAL_CHK_LEN; } else { p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len; p->hdr.auth_len = 0; } /* * Init the parse struct to point at the outgoing * data. */ prs_init( &outgoing_pdu, 0, p->mem_ctx, MARSHALL); prs_give_memory( &outgoing_pdu, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False); /* Store the header in the data stream. */ if(!smb_io_rpc_hdr("hdr", &p->hdr, &outgoing_pdu, 0)) { DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR.\n")); prs_mem_free(&outgoing_pdu); return False; } if(!smb_io_rpc_hdr_resp("resp", &hdr_resp, &outgoing_pdu, 0)) { DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR_RESP.\n")); prs_mem_free(&outgoing_pdu); return False; } /* Store the current offset. */ data_pos = prs_offset(&outgoing_pdu); /* Copy the data into the PDU. */ if(!prs_append_some_prs_data(&outgoing_pdu, &p->out_data.rdata, p->out_data.data_sent_length, data_len)) { DEBUG(0,("create_next_pdu: failed to copy %u bytes of data.\n", (unsigned int)data_len)); prs_mem_free(&outgoing_pdu); return False; } /* Copy the sign/seal padding data. */ if (ss_padding_len) { char pad[8]; memset(pad, '\0', 8); if (!prs_copy_data_in(&outgoing_pdu, pad, ss_padding_len)) { DEBUG(0,("create_next_pdu: failed to add %u bytes of pad data.\n", (unsigned int)ss_padding_len)); prs_mem_free(&outgoing_pdu); return False; } } if (p->ntlmssp_auth_validated) { /* * NTLMSSP processing. Mutually exclusive with Schannel. */ uint32 crc32 = 0; char *data; DEBUG(5,("create_next_pdu: sign: %s seal: %s data %d auth %d\n", BOOLSTR(auth_verify), BOOLSTR(auth_seal), data_len + ss_padding_len, p->hdr.auth_len)); /* * Set data to point to where we copied the data into. */ data = prs_data_p(&outgoing_pdu) + data_pos; if (auth_seal) { crc32 = crc32_calc_buffer(data, data_len + ss_padding_len); NTLMSSPcalc_p(p, (uchar*)data, data_len + ss_padding_len); } if (auth_seal || auth_verify) { RPC_HDR_AUTH auth_info; init_rpc_hdr_auth(&auth_info, NTLMSSP_AUTH_TYPE, auth_seal ? RPC_PIPE_AUTH_SEAL_LEVEL : RPC_PIPE_AUTH_SIGN_LEVEL, (auth_verify ? ss_padding_len : 0), (auth_verify ? 1 : 0)); if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &outgoing_pdu, 0)) { DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR_AUTH.\n")); prs_mem_free(&outgoing_pdu); return False; } } if (auth_verify) { RPC_AUTH_NTLMSSP_CHK ntlmssp_chk; char *auth_data = prs_data_p(&outgoing_pdu); p->ntlmssp_seq_num++; init_rpc_auth_ntlmssp_chk(&ntlmssp_chk, NTLMSSP_SIGN_VERSION, crc32, p->ntlmssp_seq_num++); auth_data = prs_data_p(&outgoing_pdu) + prs_offset(&outgoing_pdu) + 4; if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &ntlmssp_chk, &outgoing_pdu, 0)) { DEBUG(0,("create_next_pdu: failed to marshall RPC_AUTH_NTLMSSP_CHK.\n")); prs_mem_free(&outgoing_pdu); return False; } NTLMSSPcalc_p(p, (uchar*)auth_data, RPC_AUTH_NTLMSSP_CHK_LEN - 4); } } else if (p->netsec_auth_validated) { /* * Schannel processing. Mutually exclusive with NTLMSSP. */ int auth_type, auth_level; char *data; RPC_HDR_AUTH auth_info; RPC_AUTH_NETSEC_CHK verf; prs_struct rverf; prs_struct rauth; data = prs_data_p(&outgoing_pdu) + data_pos; /* Check it's the type of reply we were expecting to decode */ get_auth_type_level(p->netsec_auth.auth_flags, &auth_type, &auth_level); init_rpc_hdr_auth(&auth_info, auth_type, auth_level, ss_padding_len, 1); if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &outgoing_pdu, 0)) { DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR_AUTH.\n")); prs_mem_free(&outgoing_pdu); return False; } prs_init(&rverf, 0, p->mem_ctx, MARSHALL); prs_init(&rauth, 0, p->mem_ctx, MARSHALL); netsec_encode(&p->netsec_auth, p->netsec_auth.auth_flags, SENDER_IS_ACCEPTOR, &verf, data, data_len + ss_padding_len); smb_io_rpc_auth_netsec_chk("", RPC_AUTH_NETSEC_SIGN_OR_SEAL_CHK_LEN, &verf, &outgoing_pdu, 0); p->netsec_auth.seq_num++; } /* * Setup the counts for this PDU. */ p->out_data.data_sent_length += data_len; p->out_data.current_pdu_len = p->hdr.frag_len; p->out_data.current_pdu_sent = 0; prs_mem_free(&outgoing_pdu); return True; }
static ssize_t unmarshall_rpc_header(pipes_struct *p) { /* * Unmarshall the header to determine the needed length. */ prs_struct rpc_in; if(p->in_data.pdu_received_len != RPC_HEADER_LEN) { DEBUG(0,("unmarshall_rpc_header: assert on rpc header length failed.\n")); set_incoming_fault(p); return -1; } prs_init( &rpc_in, 0, 4, UNMARSHALL); prs_give_memory( &rpc_in, (char *)&p->in_data.current_in_pdu[0], p->in_data.pdu_received_len, False); /* * Unmarshall the header as this will tell us how much * data we need to read to get the complete pdu. */ if(!smb_io_rpc_hdr("", &p->hdr, &rpc_in, 0)) { DEBUG(0,("unmarshall_rpc_header: failed to unmarshall RPC_HDR.\n")); set_incoming_fault(p); return -1; } /* * Validate the RPC header. */ if(p->hdr.major != 5 && p->hdr.minor != 0) { DEBUG(0,("unmarshall_rpc_header: invalid major/minor numbers in RPC_HDR.\n")); set_incoming_fault(p); return -1; } /* * If there is no data in the incoming buffer and it's a requst pdu then * ensure that the FIRST flag is set. If not then we have * a stream missmatch. */ if((p->hdr.pkt_type == RPC_REQUEST) && (prs_offset(&p->in_data.data) == 0) && !(p->hdr.flags & RPC_FLG_FIRST)) { DEBUG(0,("unmarshall_rpc_header: FIRST flag not set in first PDU !\n")); set_incoming_fault(p); return -1; } /* * Ensure that the pdu length is sane. */ if((p->hdr.frag_len < RPC_HEADER_LEN) || (p->hdr.frag_len > MAX_PDU_FRAG_LEN)) { DEBUG(0,("unmarshall_rpc_header: assert on frag length failed.\n")); set_incoming_fault(p); return -1; } DEBUG(10,("unmarshall_rpc_header: type = %u, flags = %u\n", (unsigned int)p->hdr.pkt_type, (unsigned int)p->hdr.flags )); /* * Adjust for the header we just ate. */ p->in_data.pdu_received_len = 0; p->in_data.pdu_needed_len = (uint32)p->hdr.frag_len - RPC_HEADER_LEN; /* * Null the data we just ate. */ memset((char *)&p->in_data.current_in_pdu[0], '\0', RPC_HEADER_LEN); return 0; /* No extra data processed. */ }
static NTSTATUS create_rpc_bind_req(struct cli_state *cli, prs_struct *rpc_out, uint32 rpc_call_id, RPC_IFACE *abstract, RPC_IFACE *transfer, const char *my_name, const char *domain) { RPC_HDR hdr; RPC_HDR_RB hdr_rb; RPC_HDR_AUTH hdr_auth; int auth_len = 0; int auth_type, auth_level; size_t saved_hdr_offset = 0; prs_struct auth_info; prs_init(&auth_info, RPC_HDR_AUTH_LEN, /* we will need at least this much */ prs_get_mem_context(rpc_out), MARSHALL); if (cli->pipe_auth_flags) { get_auth_type_level(cli->pipe_auth_flags, &auth_type, &auth_level); /* * Create the auth structs we will marshall. */ init_rpc_hdr_auth(&hdr_auth, auth_type, auth_level, 0x00, 1); /* * Now marshall the data into the temporary parse_struct. */ if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, &auth_info, 0)) { DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_HDR_AUTH.\n")); prs_mem_free(&auth_info); return NT_STATUS_NO_MEMORY; } saved_hdr_offset = prs_offset(&auth_info); } if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) { NTSTATUS nt_status; DATA_BLOB null_blob = data_blob(NULL, 0); DATA_BLOB request; DEBUG(5, ("Processing NTLMSSP Negotiate\n")); nt_status = ntlmssp_update(cli->ntlmssp_pipe_state, null_blob, &request); if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { prs_mem_free(&auth_info); return nt_status; } /* Auth len in the rpc header doesn't include auth_header. */ auth_len = request.length; prs_copy_data_in(&auth_info, (char *)request.data, request.length); DEBUG(5, ("NTLMSSP Negotiate:\n")); dump_data(5, (const char *)request.data, request.length); data_blob_free(&request); } else if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) { RPC_AUTH_NETSEC_NEG netsec_neg; /* Use lp_workgroup() if domain not specified */ if (!domain || !domain[0]) { DEBUG(10,("create_rpc_bind_req: no domain; assuming my own\n")); domain = lp_workgroup(); } init_rpc_auth_netsec_neg(&netsec_neg, domain, my_name); /* * Now marshall the data into the temporary parse_struct. */ if(!smb_io_rpc_auth_netsec_neg("netsec_neg", &netsec_neg, &auth_info, 0)) { DEBUG(0,("Failed to marshall RPC_AUTH_NETSEC_NEG.\n")); prs_mem_free(&auth_info); return NT_STATUS_NO_MEMORY; } /* Auth len in the rpc header doesn't include auth_header. */ auth_len = prs_offset(&auth_info) - saved_hdr_offset; } /* Create the request RPC_HDR */ init_rpc_hdr(&hdr, RPC_BIND, 0x3, rpc_call_id, RPC_HEADER_LEN + RPC_HDR_RB_LEN + prs_offset(&auth_info), auth_len); if(!smb_io_rpc_hdr("hdr" , &hdr, rpc_out, 0)) { DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_HDR.\n")); prs_mem_free(&auth_info); return NT_STATUS_NO_MEMORY; } /* create the bind request RPC_HDR_RB */ init_rpc_hdr_rb(&hdr_rb, MAX_PDU_FRAG_LEN, MAX_PDU_FRAG_LEN, 0x0, 0x1, 0x0, 0x1, abstract, transfer); /* Marshall the bind request data */ if(!smb_io_rpc_hdr_rb("", &hdr_rb, rpc_out, 0)) { DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_HDR_RB.\n")); prs_mem_free(&auth_info); return NT_STATUS_NO_MEMORY; } /* * Grow the outgoing buffer to store any auth info. */ if(auth_len != 0) { if(!prs_append_prs_data( rpc_out, &auth_info)) { DEBUG(0,("create_rpc_bind_req: failed to grow parse struct to add auth.\n")); prs_mem_free(&auth_info); return NT_STATUS_NO_MEMORY; } } prs_mem_free(&auth_info); return NT_STATUS_OK; }