/* useful function to fetch a structure into rpc wire format */ int tdb_prs_fetch(TDB_CONTEXT *tdb, char *keystr, prs_struct *ps, TALLOC_CTX *mem_ctx) { TDB_DATA kbuf, dbuf; kbuf.dptr = keystr; kbuf.dsize = strlen(keystr)+1; dbuf = tdb_fetch(tdb, kbuf); if (!dbuf.dptr) return -1; ZERO_STRUCTP(ps); prs_init(ps, 0, mem_ctx, UNMARSHALL); prs_give_memory(ps, dbuf.dptr, dbuf.dsize, True); return 0; }
/**************************************************************************** set the security descriptor for a open file ****************************************************************************/ BOOL cli_set_secdesc(struct cli_state *cli, int fnum, SEC_DESC *sd) { char param[8]; char *rparam=NULL, *rdata=NULL; unsigned int rparam_count=0, rdata_count=0; uint32 sec_info = 0; TALLOC_CTX *mem_ctx; prs_struct pd; BOOL ret = False; if ((mem_ctx = talloc_init("cli_set_secdesc")) == NULL) { DEBUG(0,("talloc_init failed.\n")); goto cleanup; } prs_init(&pd, 0, mem_ctx, MARSHALL); prs_give_memory(&pd, NULL, 0, True); if (!sec_io_desc("sd data", &sd, &pd, 1)) { DEBUG(1,("Failed to marshall secdesc\n")); goto cleanup; } SIVAL(param, 0, fnum); if (sd->off_dacl) sec_info |= DACL_SECURITY_INFORMATION; if (sd->off_owner_sid) sec_info |= OWNER_SECURITY_INFORMATION; if (sd->off_grp_sid) sec_info |= GROUP_SECURITY_INFORMATION; SSVAL(param, 4, sec_info); if (!cli_send_nt_trans(cli, NT_TRANSACT_SET_SECURITY_DESC, 0, NULL, 0, 0, param, 8, 0, prs_data_p(&pd), prs_offset(&pd), 0)) { DEBUG(1,("Failed to send NT_TRANSACT_SET_SECURITY_DESC\n")); goto cleanup; } if (!cli_receive_nt_trans(cli, &rparam, &rparam_count, &rdata, &rdata_count)) { DEBUG(1,("NT_TRANSACT_SET_SECURITY_DESC failed\n")); goto cleanup; } ret = True; cleanup: SAFE_FREE(rparam); SAFE_FREE(rdata); talloc_destroy(mem_ctx); prs_mem_free(&pd); return ret; }
static void process_complete_pdu(pipes_struct *p) { prs_struct rpc_in; size_t data_len = p->in_data.pdu_received_len - RPC_HEADER_LEN; char *data_p = (char *)&p->in_data.current_in_pdu[RPC_HEADER_LEN]; bool reply = False; if(p->fault_state) { DEBUG(10,("process_complete_pdu: pipe %s in fault state.\n", get_pipe_name_from_iface(&p->syntax))); set_incoming_fault(p); setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR)); return; } prs_init_empty( &rpc_in, p->mem_ctx, UNMARSHALL); /* * Ensure we're using the corrent endianness for both the * RPC header flags and the raw data we will be reading from. */ prs_set_endian_data( &rpc_in, p->endian); prs_set_endian_data( &p->in_data.data, p->endian); prs_give_memory( &rpc_in, data_p, (uint32)data_len, False); DEBUG(10,("process_complete_pdu: processing packet type %u\n", (unsigned int)p->hdr.pkt_type )); switch (p->hdr.pkt_type) { case RPC_REQUEST: reply = process_request_pdu(p, &rpc_in); break; case RPC_PING: /* CL request - ignore... */ DEBUG(0,("process_complete_pdu: Error. Connectionless packet type %u received on pipe %s.\n", (unsigned int)p->hdr.pkt_type, get_pipe_name_from_iface(&p->syntax))); break; case RPC_RESPONSE: /* No responses here. */ DEBUG(0,("process_complete_pdu: Error. RPC_RESPONSE received from client on pipe %s.\n", get_pipe_name_from_iface(&p->syntax))); break; case RPC_FAULT: case RPC_WORKING: /* CL request - reply to a ping when a call in process. */ case RPC_NOCALL: /* CL - server reply to a ping call. */ case RPC_REJECT: case RPC_ACK: case RPC_CL_CANCEL: case RPC_FACK: case RPC_CANCEL_ACK: DEBUG(0,("process_complete_pdu: Error. Connectionless packet type %u received on pipe %s.\n", (unsigned int)p->hdr.pkt_type, get_pipe_name_from_iface(&p->syntax))); break; case RPC_BIND: /* * We assume that a pipe bind is only in one pdu. */ if(pipe_init_outgoing_data(p)) { reply = api_pipe_bind_req(p, &rpc_in); } break; case RPC_BINDACK: case RPC_BINDNACK: DEBUG(0,("process_complete_pdu: Error. RPC_BINDACK/RPC_BINDNACK packet type %u received on pipe %s.\n", (unsigned int)p->hdr.pkt_type, get_pipe_name_from_iface(&p->syntax))); break; case RPC_ALTCONT: /* * We assume that a pipe bind is only in one pdu. */ if(pipe_init_outgoing_data(p)) { reply = api_pipe_alter_context(p, &rpc_in); } break; case RPC_ALTCONTRESP: DEBUG(0,("process_complete_pdu: Error. RPC_ALTCONTRESP on pipe %s: Should only be server -> client.\n", get_pipe_name_from_iface(&p->syntax))); break; case RPC_AUTH3: /* * The third packet in an NTLMSSP auth exchange. */ if(pipe_init_outgoing_data(p)) { reply = api_pipe_bind_auth3(p, &rpc_in); } break; case RPC_SHUTDOWN: DEBUG(0,("process_complete_pdu: Error. RPC_SHUTDOWN on pipe %s: Should only be server -> client.\n", get_pipe_name_from_iface(&p->syntax))); break; case RPC_CO_CANCEL: /* For now just free all client data and continue processing. */ DEBUG(3,("process_complete_pdu: RPC_ORPHANED. Abandoning rpc call.\n")); /* As we never do asynchronous RPC serving, we can never cancel a call (as far as I know). If we ever did we'd have to send a cancel_ack reply. For now, just free all client data and continue processing. */ reply = True; break; #if 0 /* Enable this if we're doing async rpc. */ /* We must check the call-id matches the outstanding callid. */ if(pipe_init_outgoing_data(p)) { /* Send a cancel_ack PDU reply. */ /* We should probably check the auth-verifier here. */ reply = setup_cancel_ack_reply(p, &rpc_in); } break; #endif case RPC_ORPHANED: /* We should probably check the auth-verifier here. For now just free all client data and continue processing. */ DEBUG(3,("process_complete_pdu: RPC_ORPHANED. Abandoning rpc call.\n")); reply = True; break; default: DEBUG(0,("process_complete_pdu: Unknown rpc type = %u received.\n", (unsigned int)p->hdr.pkt_type )); break; } /* Reset to little endian. Probably don't need this but it won't hurt. */ prs_set_endian_data( &p->in_data.data, RPC_LITTLE_ENDIAN); if (!reply) { DEBUG(3,("process_complete_pdu: DCE/RPC fault sent on " "pipe %s\n", get_pipe_name_from_iface(&p->syntax))); set_incoming_fault(p); setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR)); prs_mem_free(&rpc_in); } else { /* * Reset the lengths. We're ready for a new pdu. */ TALLOC_FREE(p->in_data.current_in_pdu); p->in_data.pdu_needed_len = 0; p->in_data.pdu_received_len = 0; } prs_mem_free(&rpc_in); }
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_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. */ }
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 BOOL rpc_api_pipe(struct cli_state *cli, prs_struct *data, prs_struct *rdata, uint8 expected_pkt_type) { uint32 len; char *rparam = NULL; uint32 rparam_len = 0; uint16 setup[2]; BOOL first = True; BOOL last = True; RPC_HDR rhdr; char *pdata = data ? prs_data_p(data) : NULL; uint32 data_len = data ? prs_offset(data) : 0; char *prdata = NULL; uint32 rdata_len = 0; uint32 current_offset = 0; uint32 fragment_start = 0; uint32 max_data = cli->max_xmit_frag ? cli->max_xmit_frag : 1024; int auth_padding_len = 0; /* Create setup parameters - must be in native byte order. */ setup[0] = TRANSACT_DCERPCCMD; setup[1] = cli->nt_pipe_fnum; /* Pipe file handle. */ DEBUG(5,("rpc_api_pipe: fnum:%x\n", (int)cli->nt_pipe_fnum)); /* Send the RPC request and receive a response. For short RPC calls (about 1024 bytes or so) the RPC request and response appears in a SMBtrans request and response. Larger RPC responses are received further on. */ if (!cli_api_pipe(cli, "\\PIPE\\", setup, 2, 0, /* Setup, length, max */ NULL, 0, 0, /* Params, length, max */ pdata, data_len, max_data, /* data, length, max */ &rparam, &rparam_len, /* return params, len */ &prdata, &rdata_len)) /* return data, len */ { DEBUG(0, ("cli_pipe: return critical error. Error was %s\n", cli_errstr(cli))); return False; } /* Throw away returned params - we know we won't use them. */ SAFE_FREE(rparam); if (prdata == NULL) { DEBUG(0,("rpc_api_pipe: pipe %x failed to return data.\n", (int)cli->nt_pipe_fnum)); return False; } /* * Give this memory as dynamically allocated to the return parse * struct. */ prs_give_memory(rdata, prdata, rdata_len, True); current_offset = rdata_len; /* This next call sets the endian bit correctly in rdata. */ if (!rpc_check_hdr(rdata, &rhdr, &first, &last, &len)) { prs_mem_free(rdata); return False; } if (rhdr.pkt_type == RPC_BINDACK) { if (!last && !first) { DEBUG(5,("rpc_api_pipe: bug in server (AS/U?), setting fragment first/last ON.\n")); first = True; last = True; } } if (rhdr.pkt_type == RPC_BINDNACK) { DEBUG(3, ("Bind NACK received on pipe %x!\n", (int)cli->nt_pipe_fnum)); prs_mem_free(rdata); return False; } if (rhdr.pkt_type == RPC_RESPONSE) { RPC_HDR_RESP rhdr_resp; if(!smb_io_rpc_hdr_resp("rpc_hdr_resp", &rhdr_resp, rdata, 0)) { DEBUG(5,("rpc_api_pipe: failed to unmarshal RPC_HDR_RESP.\n")); prs_mem_free(rdata); return False; } } if (rhdr.pkt_type != expected_pkt_type) { DEBUG(3, ("Connection to pipe %x got an unexpected RPC packet type - %d, not %d\n", (int)cli->nt_pipe_fnum, rhdr.pkt_type, expected_pkt_type)); prs_mem_free(rdata); return False; } DEBUG(5,("rpc_api_pipe: len left: %u smbtrans read: %u\n", (unsigned int)len, (unsigned int)rdata_len )); /* check if data to be sent back was too large for one SMBtrans */ /* err status is only informational: the _real_ check is on the length */ if (len > 0) { /* || err == (0x80000000 | STATUS_BUFFER_OVERFLOW)) */ /* Read the remaining part of the first response fragment */ if (!rpc_read(cli, rdata, len, ¤t_offset)) { prs_mem_free(rdata); return False; } } /* * Now we have a complete PDU, check the auth struct if any was sent. */ if(!rpc_auth_pipe(cli, rdata, fragment_start, rhdr.frag_len, rhdr.auth_len, rhdr.pkt_type, &auth_padding_len)) { prs_mem_free(rdata); return False; } if (rhdr.auth_len != 0) { /* * Drop the auth footers from the current offset. * We need this if there are more fragments. * The auth footers consist of the auth_data and the * preceeding 8 byte auth_header. */ current_offset -= (auth_padding_len + RPC_HDR_AUTH_LEN + rhdr.auth_len); } /* * Only one rpc fragment, and it has been read. */ if (first && last) { DEBUG(6,("rpc_api_pipe: fragment first and last both set\n")); return True; } /* * Read more fragments using SMBreadX until we get one with the * last bit set. */ while (!last) { RPC_HDR_RESP rhdr_resp; int num_read; char hdr_data[RPC_HEADER_LEN+RPC_HDR_RESP_LEN]; prs_struct hps; uint8 eclass; uint32 ecode; /* * First read the header of the next PDU. */ prs_init(&hps, 0, cli->mem_ctx, UNMARSHALL); prs_give_memory(&hps, hdr_data, sizeof(hdr_data), False); num_read = cli_read(cli, cli->nt_pipe_fnum, hdr_data, 0, RPC_HEADER_LEN+RPC_HDR_RESP_LEN); if (cli_is_dos_error(cli)) { cli_dos_error(cli, &eclass, &ecode); if (eclass != ERRDOS && ecode != ERRmoredata) { DEBUG(0,("rpc_api_pipe: cli_read error : %d/%d\n", eclass, ecode)); return False; } } DEBUG(5,("rpc_api_pipe: read header (size:%d)\n", num_read)); if (num_read != RPC_HEADER_LEN+RPC_HDR_RESP_LEN) { DEBUG(0,("rpc_api_pipe: Error : requested %d bytes, got %d.\n", RPC_HEADER_LEN+RPC_HDR_RESP_LEN, num_read )); return False; } /* This call sets the endianness in hps. */ if (!rpc_check_hdr(&hps, &rhdr, &first, &last, &len)) return False; /* Ensure the endianness in rdata is set correctly - must be same as hps. */ if (hps.bigendian_data != rdata->bigendian_data) { DEBUG(0,("rpc_api_pipe: Error : Endianness changed from %s to %s\n", rdata->bigendian_data ? "big" : "little", hps.bigendian_data ? "big" : "little" )); return False; } if(!smb_io_rpc_hdr_resp("rpc_hdr_resp", &rhdr_resp, &hps, 0)) { DEBUG(0,("rpc_api_pipe: Error in unmarshalling RPC_HDR_RESP.\n")); return False; } if (first) { DEBUG(0,("rpc_api_pipe: secondary PDU rpc header has 'first' set !\n")); return False; } /* * Now read the rest of the PDU. */ if (!rpc_read(cli, rdata, len, ¤t_offset)) { prs_mem_free(rdata); return False; } fragment_start = current_offset - len - RPC_HEADER_LEN - RPC_HDR_RESP_LEN; /* * Verify any authentication footer. */ if(!rpc_auth_pipe(cli, rdata, fragment_start, rhdr.frag_len, rhdr.auth_len, rhdr.pkt_type, &auth_padding_len)) { prs_mem_free(rdata); return False; } if (rhdr.auth_len != 0 ) { /* * Drop the auth footers from the current offset. * The auth footers consist of the auth_data and the * preceeding 8 byte auth_header. * We need this if there are more fragments. */ current_offset -= (auth_padding_len + RPC_HDR_AUTH_LEN + rhdr.auth_len); } } return True; }
static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata, uint32 fragment_start, int len, int auth_len, uint8 pkt_type, int *pauth_padding_len) { /* * The following is that length of the data we must sign or seal. * This doesn't include the RPC headers or the auth_len or the RPC_HDR_AUTH_LEN * preceeding the auth_data. */ int data_len = len - RPC_HEADER_LEN - RPC_HDR_RESP_LEN - RPC_HDR_AUTH_LEN - auth_len; /* * The start of the data to sign/seal is just after the RPC headers. */ char *reply_data = prs_data_p(rdata) + fragment_start + RPC_HEADER_LEN + RPC_HDR_REQ_LEN; RPC_HDR_AUTH rhdr_auth; char *dp = prs_data_p(rdata) + fragment_start + len - RPC_HDR_AUTH_LEN - auth_len; prs_struct auth_verf; *pauth_padding_len = 0; if (auth_len == 0) { if (cli->pipe_auth_flags == 0) { /* move along, nothing to see here */ return True; } DEBUG(2, ("No authenticaton header recienved on reply, but this pipe is authenticated\n")); return False; } DEBUG(5,("rpc_auth_pipe: pkt_type: %d len: %d auth_len: %d NTLMSSP %s schannel %s sign %s seal %s \n", pkt_type, len, auth_len, BOOLSTR(cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP), BOOLSTR(cli->pipe_auth_flags & AUTH_PIPE_NETSEC), BOOLSTR(cli->pipe_auth_flags & AUTH_PIPE_SIGN), BOOLSTR(cli->pipe_auth_flags & AUTH_PIPE_SEAL))); if (dp - prs_data_p(rdata) > prs_data_size(rdata)) { DEBUG(0,("rpc_auth_pipe: schannel auth data > data size !\n")); return False; } DEBUG(10,("rpc_auth_pipe: packet:\n")); dump_data(100, dp, auth_len); prs_init(&auth_verf, 0, cli->mem_ctx, UNMARSHALL); /* The endinness must be preserved. JRA. */ prs_set_endian_data( &auth_verf, rdata->bigendian_data); /* Point this new parse struct at the auth section of the main parse struct - rather than copying it. Avoids needing to free it on every error */ prs_give_memory(&auth_verf, dp, RPC_HDR_AUTH_LEN + auth_len, False /* not dynamic */); prs_set_offset(&auth_verf, 0); { int auth_type; int auth_level; if (!smb_io_rpc_hdr_auth("auth_hdr", &rhdr_auth, &auth_verf, 0)) { DEBUG(0, ("rpc_auth_pipe: Could not parse auth header\n")); return False; } /* Let the caller know how much padding at the end of the data */ *pauth_padding_len = rhdr_auth.padding; /* Check it's the type of reply we were expecting to decode */ get_auth_type_level(cli->pipe_auth_flags, &auth_type, &auth_level); if (rhdr_auth.auth_type != auth_type) { DEBUG(0, ("BAD auth type %d (should be %d)\n", rhdr_auth.auth_type, auth_type)); return False; } if (rhdr_auth.auth_level != auth_level) { DEBUG(0, ("BAD auth level %d (should be %d)\n", rhdr_auth.auth_level, auth_level)); return False; } } if (pkt_type == RPC_BINDACK) { if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) { /* copy the next auth_len bytes into a buffer for later use */ DATA_BLOB ntlmssp_verf = data_blob(NULL, auth_len); BOOL store_ok; /* save the reply away, for use a little later */ prs_copy_data_out((char *)ntlmssp_verf.data, &auth_verf, auth_len); store_ok = (NT_STATUS_IS_OK(ntlmssp_store_response(cli->ntlmssp_pipe_state, ntlmssp_verf))); data_blob_free(&ntlmssp_verf); return store_ok; } else if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) { /* nothing to do here - we don't seem to be able to validate the bindack based on VL's comments */ return True; } } if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) { NTSTATUS nt_status; DATA_BLOB sig; if ((cli->pipe_auth_flags & AUTH_PIPE_SIGN) || (cli->pipe_auth_flags & AUTH_PIPE_SEAL)) { if (auth_len != RPC_AUTH_NTLMSSP_CHK_LEN) { DEBUG(0,("rpc_auth_pipe: wrong ntlmssp auth len %d\n", auth_len)); return False; } sig = data_blob(NULL, auth_len); prs_copy_data_out((char *)sig.data, &auth_verf, auth_len); } /* * Unseal any sealed data in the PDU, not including the * 8 byte auth_header or the auth_data. */ /* * Now unseal and check the auth verifier in the auth_data at * the end of the packet. */ if (cli->pipe_auth_flags & AUTH_PIPE_SEAL) { if (data_len < 0) { DEBUG(1, ("Can't unseal - data_len < 0!!\n")); return False; } nt_status = ntlmssp_unseal_packet(cli->ntlmssp_pipe_state, (unsigned char *)reply_data, data_len, &sig); } else if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) { nt_status = ntlmssp_check_packet(cli->ntlmssp_pipe_state, (const unsigned char *)reply_data, data_len, &sig); } data_blob_free(&sig); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0, ("rpc_auth_pipe: could not validate " "incoming NTLMSSP packet!\n")); return False; } } if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) { RPC_AUTH_NETSEC_CHK chk; if (auth_len != RPC_AUTH_NETSEC_CHK_LEN) { DEBUG(0,("rpc_auth_pipe: wrong schannel auth len %d\n", auth_len)); return False; } if (!smb_io_rpc_auth_netsec_chk("schannel_auth_sign", &chk, &auth_verf, 0)) { DEBUG(0, ("rpc_auth_pipe: schannel unmarshalling " "RPC_AUTH_NETSECK_CHK failed\n")); return False; } if (!netsec_decode(&cli->auth_info, cli->pipe_auth_flags, SENDER_IS_ACCEPTOR, &chk, reply_data, data_len)) { DEBUG(0, ("rpc_auth_pipe: Could not decode schannel\n")); return False; } cli->auth_info.seq_num++; } return True; }
static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_name) { RPC_IFACE abstract; RPC_IFACE transfer; prs_struct rpc_out; prs_struct rdata; uint32 rpc_call_id; char buffer[MAX_PDU_FRAG_LEN]; if ( (pipe_idx < 0) || (pipe_idx >= PI_MAX_PIPES) ) return False; DEBUG(5,("Bind RPC Pipe[%x]: %s\n", cli->nt_pipe_fnum, pipe_names[pipe_idx].client_pipe)); if (!valid_pipe_name(pipe_idx, &abstract, &transfer)) return False; prs_init(&rpc_out, 0, cli->mem_ctx, MARSHALL); /* * Use the MAX_PDU_FRAG_LEN buffer to store the bind request. */ prs_give_memory( &rpc_out, buffer, sizeof(buffer), False); rpc_call_id = get_rpc_call_id(); if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) { NTSTATUS nt_status; fstring password; DEBUG(5, ("NTLMSSP authenticated pipe selected\n")); nt_status = ntlmssp_client_start(&cli->ntlmssp_pipe_state); if (!NT_STATUS_IS_OK(nt_status)) return False; /* Currently the NTLMSSP code does not implement NTLM2 correctly for signing or sealing */ cli->ntlmssp_pipe_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2; nt_status = ntlmssp_set_username(cli->ntlmssp_pipe_state, cli->user_name); if (!NT_STATUS_IS_OK(nt_status)) return False; nt_status = ntlmssp_set_domain(cli->ntlmssp_pipe_state, cli->domain); if (!NT_STATUS_IS_OK(nt_status)) return False; if (cli->pwd.null_pwd) { nt_status = ntlmssp_set_password(cli->ntlmssp_pipe_state, NULL); if (!NT_STATUS_IS_OK(nt_status)) return False; } else { pwd_get_cleartext(&cli->pwd, password); nt_status = ntlmssp_set_password(cli->ntlmssp_pipe_state, password); if (!NT_STATUS_IS_OK(nt_status)) return False; } if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) { cli->ntlmssp_pipe_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; } if (cli->pipe_auth_flags & AUTH_PIPE_SEAL) { cli->ntlmssp_pipe_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; } } else if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) { cli->auth_info.seq_num = 0; } /* Marshall the outgoing data. */ create_rpc_bind_req(cli, &rpc_out, rpc_call_id, &abstract, &transfer, global_myname(), cli->domain); /* Initialize the incoming data struct. */ prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL); /* send data on \PIPE\. receive a response */ if (rpc_api_pipe(cli, &rpc_out, &rdata, RPC_BINDACK)) { RPC_HDR_BA hdr_ba; DEBUG(5, ("rpc_pipe_bind: rpc_api_pipe returned OK.\n")); if(!smb_io_rpc_hdr_ba("", &hdr_ba, &rdata, 0)) { DEBUG(0,("rpc_pipe_bind: Failed to unmarshall RPC_HDR_BA.\n")); prs_mem_free(&rdata); return False; } if(!check_bind_response(&hdr_ba, pipe_idx, &transfer)) { DEBUG(2,("rpc_pipe_bind: check_bind_response failed.\n")); prs_mem_free(&rdata); return False; } cli->max_xmit_frag = hdr_ba.bba.max_tsize; cli->max_recv_frag = hdr_ba.bba.max_rsize; /* * If we're doing NTLMSSP auth we need to send a reply to * the bind-ack to complete the 3-way challenge response * handshake. */ if ((cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) && !rpc_send_auth_reply(cli, &rdata, rpc_call_id)) { DEBUG(0,("rpc_pipe_bind: rpc_send_auth_reply failed.\n")); prs_mem_free(&rdata); return False; } prs_mem_free(&rdata); return True; } return False; }
static ssize_t process_complete_pdu(pipes_struct *p) { prs_struct rpc_in; size_t data_len = p->in_data.pdu_received_len; char *data_p = (char *)&p->in_data.current_in_pdu[0]; BOOL reply = False; if(p->fault_state) { DEBUG(10,("process_complete_pdu: pipe %s in fault state.\n", p->name )); set_incoming_fault(p); setup_fault_pdu(p, NT_STATUS(0x1c010002)); return (ssize_t)data_len; } prs_init( &rpc_in, 0, p->mem_ctx, UNMARSHALL); /* * Ensure we're using the corrent endianness for both the * RPC header flags and the raw data we will be reading from. */ prs_set_endian_data( &rpc_in, p->endian); prs_set_endian_data( &p->in_data.data, p->endian); prs_give_memory( &rpc_in, data_p, (uint32)data_len, False); DEBUG(10,("process_complete_pdu: processing packet type %u\n", (unsigned int)p->hdr.pkt_type )); switch (p->hdr.pkt_type) { case RPC_BIND: case RPC_ALTCONT: /* * We assume that a pipe bind is only in one pdu. */ if(pipe_init_outgoing_data(p)) reply = api_pipe_bind_req(p, &rpc_in); break; case RPC_BINDRESP: /* * We assume that a pipe bind_resp is only in one pdu. */ if(pipe_init_outgoing_data(p)) reply = api_pipe_bind_auth_resp(p, &rpc_in); break; case RPC_REQUEST: reply = process_request_pdu(p, &rpc_in); break; default: DEBUG(0,("process_complete_pdu: Unknown rpc type = %u received.\n", (unsigned int)p->hdr.pkt_type )); break; } /* Reset to little endian. Probably don't need this but it won't hurt. */ prs_set_endian_data( &p->in_data.data, RPC_LITTLE_ENDIAN); if (!reply) { DEBUG(3,("process_complete_pdu: DCE/RPC fault sent on pipe %s\n", p->pipe_srv_name)); set_incoming_fault(p); setup_fault_pdu(p, NT_STATUS(0x1c010002)); prs_mem_free(&rpc_in); } else { /* * Reset the lengths. We're ready for a new pdu. */ p->in_data.pdu_needed_len = 0; p->in_data.pdu_received_len = 0; } prs_mem_free(&rpc_in); return (ssize_t)data_len; }