/******************************************************************* return the contents of a prs_struct in a DATA_BLOB ********************************************************************/ bool prs_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx) { blob->length = prs_data_size(prs); blob->data = (uint8 *)TALLOC_ZERO_SIZE(mem_ctx, blob->length); /* set the pointer at the end of the buffer */ prs_set_offset( prs, prs_data_size(prs) ); if (!prs_copy_all_data_out((char *)blob->data, prs)) return False; return True; }
static NTSTATUS append_info3_as_ndr(TALLOC_CTX *mem_ctx, struct winbindd_cli_state *state, NET_USER_INFO_3 *info3) { prs_struct ps; uint32 size; if (!prs_init(&ps, 256 /* Random, non-zero number */, mem_ctx, MARSHALL)) { return NT_STATUS_NO_MEMORY; } if (!net_io_user_info3("", info3, &ps, 1, 3)) { prs_mem_free(&ps); return NT_STATUS_UNSUCCESSFUL; } size = prs_data_size(&ps); state->response.extra_data = malloc(size); if (!state->response.extra_data) { prs_mem_free(&ps); return NT_STATUS_NO_MEMORY; } memset( state->response.extra_data, '\0', size ); prs_copy_all_data_out(state->response.extra_data, &ps); state->response.length += size; prs_mem_free(&ps); return NT_STATUS_OK; }
BOOL rpcbuf_alloc_size(RPC_BUFFER *buffer, uint32 buffer_size) { prs_struct *ps; uint32 extra_space; uint32 old_offset; /* if we don't need anything. don't do anything */ if ( buffer_size == 0x0 ) return True; if (!buffer) { return False; } ps= &buffer->prs; /* damn, I'm doing the reverse operation of prs_grow() :) */ if (buffer_size < prs_data_size(ps)) extra_space=0; else extra_space = buffer_size - prs_data_size(ps); /* * save the offset and move to the end of the buffer * prs_grow() checks the extra_space against the offset */ old_offset=prs_offset(ps); prs_set_offset(ps, prs_data_size(ps)); if (!prs_grow(ps, extra_space)) return False; prs_set_offset(ps, old_offset); buffer->string_at_end=prs_data_size(ps); return True; }
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 bool process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p) { uint32 ss_padding_len = 0; size_t data_len = p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN - (p->hdr.auth_len ? RPC_HDR_AUTH_LEN : 0) - p->hdr.auth_len; if(!p->pipe_bound) { DEBUG(0,("process_request_pdu: rpc request with no bind.\n")); set_incoming_fault(p); return False; } /* * Check if we need to do authentication processing. * This is only done on requests, not binds. */ /* * Read the RPC request header. */ if(!smb_io_rpc_hdr_req("req", &p->hdr_req, rpc_in_p, 0)) { DEBUG(0,("process_request_pdu: failed to unmarshall RPC_HDR_REQ.\n")); set_incoming_fault(p); return False; } switch(p->auth.auth_type) { case PIPE_AUTH_TYPE_NONE: break; case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP: case PIPE_AUTH_TYPE_NTLMSSP: { NTSTATUS status; if(!api_pipe_ntlmssp_auth_process(p, rpc_in_p, &ss_padding_len, &status)) { DEBUG(0,("process_request_pdu: failed to do auth processing.\n")); DEBUG(0,("process_request_pdu: error was %s.\n", nt_errstr(status) )); set_incoming_fault(p); return False; } break; } case PIPE_AUTH_TYPE_SCHANNEL: if (!api_pipe_schannel_process(p, rpc_in_p, &ss_padding_len)) { DEBUG(3,("process_request_pdu: failed to do schannel processing.\n")); set_incoming_fault(p); return False; } break; default: DEBUG(0,("process_request_pdu: unknown auth type %u set.\n", (unsigned int)p->auth.auth_type )); set_incoming_fault(p); return False; } /* Now we've done the sign/seal we can remove any padding data. */ if (data_len > ss_padding_len) { data_len -= ss_padding_len; } /* * Check the data length doesn't go over the 15Mb limit. * increased after observing a bug in the Windows NT 4.0 SP6a * spoolsv.exe when the response to a GETPRINTERDRIVER2 RPC * will not fit in the initial buffer of size 0x1068 --jerry 22/01/2002 */ if(prs_offset(&p->in_data.data) + data_len > MAX_RPC_DATA_SIZE) { DEBUG(0,("process_request_pdu: rpc data buffer too large (%u) + (%u)\n", (unsigned int)prs_data_size(&p->in_data.data), (unsigned int)data_len )); set_incoming_fault(p); return False; } /* * Append the data portion into the buffer and return. */ if(!prs_append_some_prs_data(&p->in_data.data, rpc_in_p, prs_offset(rpc_in_p), data_len)) { DEBUG(0,("process_request_pdu: Unable to append data size %u to parse buffer of size %u.\n", (unsigned int)data_len, (unsigned int)prs_data_size(&p->in_data.data) )); set_incoming_fault(p); return False; } if(p->hdr.flags & RPC_FLG_LAST) { bool ret = False; /* * Ok - we finally have a complete RPC stream. * Call the rpc command to process it. */ /* * Ensure the internal prs buffer size is *exactly* the same * size as the current offset. */ if(!prs_set_buffer_size(&p->in_data.data, prs_offset(&p->in_data.data))) { DEBUG(0,("process_request_pdu: Call to prs_set_buffer_size failed!\n")); set_incoming_fault(p); return False; } /* * Set the parse offset to the start of the data and set the * prs_struct to UNMARSHALL. */ prs_set_offset(&p->in_data.data, 0); prs_switch_type(&p->in_data.data, UNMARSHALL); /* * Process the complete data stream here. */ free_pipe_context(p); if(pipe_init_outgoing_data(p)) { ret = api_pipe_request(p); } free_pipe_context(p); /* * We have consumed the whole data stream. Set back to * marshalling and set the offset back to the start of * the buffer to re-use it (we could also do a prs_mem_free() * and then re_init on the next start of PDU. Not sure which * is best here.... JRA. */ prs_switch_type(&p->in_data.data, MARSHALL); prs_set_offset(&p->in_data.data, 0); return ret; } return True; }
static BOOL rpc_read(struct cli_state *cli, prs_struct *rdata, uint32 data_to_read, uint32 *rdata_offset) { size_t size = (size_t)cli->max_recv_frag; int stream_offset = 0; int num_read; char *pdata; int extra_data_size = ((int)*rdata_offset) + ((int)data_to_read) - (int)prs_data_size(rdata); DEBUG(5,("rpc_read: data_to_read: %u rdata offset: %u extra_data_size: %d\n", (int)data_to_read, (unsigned int)*rdata_offset, extra_data_size)); /* * Grow the buffer if needed to accommodate the data to be read. */ if (extra_data_size > 0) { if(!prs_force_grow(rdata, (uint32)extra_data_size)) { DEBUG(0,("rpc_read: Failed to grow parse struct by %d bytes.\n", extra_data_size )); return False; } DEBUG(5,("rpc_read: grew buffer by %d bytes to %u\n", extra_data_size, prs_data_size(rdata) )); } pdata = prs_data_p(rdata) + *rdata_offset; do /* read data using SMBreadX */ { uint32 ecode; uint8 eclass; if (size > (size_t)data_to_read) size = (size_t)data_to_read; num_read = (int)cli_read(cli, cli->nt_pipe_fnum, pdata, (off_t)stream_offset, size); DEBUG(5,("rpc_read: num_read = %d, read offset: %d, to read: %d\n", num_read, stream_offset, data_to_read)); if (cli_is_dos_error(cli)) { cli_dos_error(cli, &eclass, &ecode); if (eclass != ERRDOS && ecode != ERRmoredata) { DEBUG(0,("rpc_read: Error %d/%u in cli_read\n", eclass, (unsigned int)ecode)); return False; } } data_to_read -= num_read; stream_offset += num_read; pdata += num_read; } while (num_read > 0 && data_to_read > 0); /* && err == (0x80000000 | STATUS_BUFFER_OVERFLOW)); */ /* * Update the current offset into rdata by the amount read. */ *rdata_offset += stream_offset; 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 process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p) { BOOL auth_verify = ((p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SIGN) != 0); size_t data_len = p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN - (auth_verify ? RPC_HDR_AUTH_LEN : 0) - p->hdr.auth_len; if(!p->pipe_bound) { DEBUG(0,("process_request_pdu: rpc request with no bind.\n")); set_incoming_fault(p); return False; } /* * Check if we need to do authentication processing. * This is only done on requests, not binds. */ /* * Read the RPC request header. */ if(!smb_io_rpc_hdr_req("req", &p->hdr_req, rpc_in_p, 0)) { DEBUG(0,("process_request_pdu: failed to unmarshall RPC_HDR_REQ.\n")); set_incoming_fault(p); return False; } if(p->ntlmssp_auth_validated && !api_pipe_auth_process(p, rpc_in_p)) { DEBUG(0,("process_request_pdu: failed to do auth processing.\n")); set_incoming_fault(p); return False; } if (p->ntlmssp_auth_requested && !p->ntlmssp_auth_validated) { /* * Authentication _was_ requested and it already failed. */ DEBUG(0,("process_request_pdu: RPC request received on pipe %s " "where authentication failed. Denying the request.\n", p->name)); set_incoming_fault(p); return False; } if (p->netsec_auth_validated && !api_pipe_netsec_process(p, rpc_in_p)) { DEBUG(3,("process_request_pdu: failed to do schannel processing.\n")); set_incoming_fault(p); return False; } /* * Check the data length doesn't go over the 15Mb limit. * increased after observing a bug in the Windows NT 4.0 SP6a * spoolsv.exe when the response to a GETPRINTERDRIVER2 RPC * will not fit in the initial buffer of size 0x1068 --jerry 22/01/2002 */ if(prs_offset(&p->in_data.data) + data_len > 15*1024*1024) { DEBUG(0,("process_request_pdu: rpc data buffer too large (%u) + (%u)\n", (unsigned int)prs_data_size(&p->in_data.data), (unsigned int)data_len )); set_incoming_fault(p); return False; } /* * Append the data portion into the buffer and return. */ if(!prs_append_some_prs_data(&p->in_data.data, rpc_in_p, prs_offset(rpc_in_p), data_len)) { DEBUG(0,("process_request_pdu: Unable to append data size %u to parse buffer of size %u.\n", (unsigned int)data_len, (unsigned int)prs_data_size(&p->in_data.data) )); set_incoming_fault(p); return False; } if(p->hdr.flags & RPC_FLG_LAST) { BOOL ret = False; /* * Ok - we finally have a complete RPC stream. * Call the rpc command to process it. */ /* * Ensure the internal prs buffer size is *exactly* the same * size as the current offset. */ if(!prs_set_buffer_size(&p->in_data.data, prs_offset(&p->in_data.data))) { DEBUG(0,("process_request_pdu: Call to prs_set_buffer_size failed!\n")); set_incoming_fault(p); return False; } /* * Set the parse offset to the start of the data and set the * prs_struct to UNMARSHALL. */ prs_set_offset(&p->in_data.data, 0); prs_switch_type(&p->in_data.data, UNMARSHALL); /* * Process the complete data stream here. */ free_pipe_context(p); if(pipe_init_outgoing_data(p)) ret = api_pipe_request(p); free_pipe_context(p); /* * We have consumed the whole data stream. Set back to * marshalling and set the offset back to the start of * the buffer to re-use it (we could also do a prs_mem_free() * and then re_init on the next start of PDU. Not sure which * is best here.... JRA. */ prs_switch_type(&p->in_data.data, MARSHALL); prs_set_offset(&p->in_data.data, 0); return ret; } return True; }