cli_pipe.c
来自「samba-3.0.22.tar.gz 编译smb服务器的源码」· C语言 代码 · 共 2,128 行 · 第 1/5 页
C
2,128 行
*p_ss_padding_len = auth_info.auth_pad_len; return NT_STATUS_OK;}/**************************************************************************** Do the authentication checks on an incoming pdu. Check sign and unseal etc. ****************************************************************************/static NTSTATUS cli_pipe_validate_rpc_response(struct rpc_pipe_client *cli, RPC_HDR *prhdr, prs_struct *current_pdu, uint8 *p_ss_padding_len){ NTSTATUS ret = NT_STATUS_OK; /* Paranioa checks for auth_len. */ if (prhdr->auth_len) { if (prhdr->auth_len > prhdr->frag_len) { return NT_STATUS_INVALID_PARAMETER; } if (prhdr->auth_len + RPC_HDR_AUTH_LEN < prhdr->auth_len || prhdr->auth_len + RPC_HDR_AUTH_LEN < RPC_HDR_AUTH_LEN) { /* Integer wrap attempt. */ return NT_STATUS_INVALID_PARAMETER; } } /* * Now we have a complete RPC request PDU fragment, try and verify any auth data. */ switch(cli->auth.auth_type) { case PIPE_AUTH_TYPE_NONE: if (prhdr->auth_len) { DEBUG(3, ("cli_pipe_validate_rpc_response: Connection to remote machine %s " "pipe %s fnum 0x%x - got non-zero auth len %u.\n", cli->cli->desthost, cli->pipe_name, (unsigned int)cli->fnum, (unsigned int)prhdr->auth_len )); return NT_STATUS_INVALID_PARAMETER; } break; case PIPE_AUTH_TYPE_NTLMSSP: case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP: ret = cli_pipe_verify_ntlmssp(cli, prhdr, current_pdu, p_ss_padding_len); if (!NT_STATUS_IS_OK(ret)) { return ret; } break; case PIPE_AUTH_TYPE_SCHANNEL: ret = cli_pipe_verify_schannel(cli, prhdr, current_pdu, p_ss_padding_len); if (!NT_STATUS_IS_OK(ret)) { return ret; } break; case PIPE_AUTH_TYPE_KRB5: case PIPE_AUTH_TYPE_SPNEGO_KRB5: default: DEBUG(3, ("cli_pipe_validate_rpc_response: Connection to remote machine %s " "pipe %s fnum %x - unknown internal auth type %u.\n", cli->cli->desthost, cli->pipe_name, (unsigned int)cli->fnum, cli->auth.auth_type )); return NT_STATUS_INVALID_INFO_CLASS; } return NT_STATUS_OK;}/**************************************************************************** Do basic authentication checks on an incoming pdu. ****************************************************************************/static NTSTATUS cli_pipe_validate_current_pdu(struct rpc_pipe_client *cli, RPC_HDR *prhdr, prs_struct *current_pdu, uint8 expected_pkt_type, char **ppdata, uint32 *pdata_len, prs_struct *return_data){ NTSTATUS ret = NT_STATUS_OK; uint32 current_pdu_len = prs_data_size(current_pdu); if (current_pdu_len != prhdr->frag_len) { DEBUG(5,("cli_pipe_validate_current_pdu: incorrect pdu length %u, expected %u\n", (unsigned int)current_pdu_len, (unsigned int)prhdr->frag_len )); return NT_STATUS_INVALID_PARAMETER; } /* * Point the return values at the real data including the RPC * header. Just in case the caller wants it. */ *ppdata = prs_data_p(current_pdu); *pdata_len = current_pdu_len; /* Ensure we have the correct type. */ switch (prhdr->pkt_type) { case RPC_ALTCONTRESP: case RPC_BINDACK: /* Alter context and bind ack share the same packet definitions. */ break; case RPC_RESPONSE: { RPC_HDR_RESP rhdr_resp; uint8 ss_padding_len = 0; if(!smb_io_rpc_hdr_resp("rpc_hdr_resp", &rhdr_resp, current_pdu, 0)) { DEBUG(5,("cli_pipe_validate_current_pdu: failed to unmarshal RPC_HDR_RESP.\n")); return NT_STATUS_BUFFER_TOO_SMALL; } /* Here's where we deal with incoming sign/seal. */ ret = cli_pipe_validate_rpc_response(cli, prhdr, current_pdu, &ss_padding_len); if (!NT_STATUS_IS_OK(ret)) { return ret; } /* Point the return values at the NDR data. Remember to remove any ss padding. */ *ppdata = prs_data_p(current_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN; if (current_pdu_len < RPC_HEADER_LEN + RPC_HDR_RESP_LEN + ss_padding_len) { return NT_STATUS_BUFFER_TOO_SMALL; } *pdata_len = current_pdu_len - RPC_HEADER_LEN - RPC_HDR_RESP_LEN - ss_padding_len; /* Remember to remove the auth footer. */ if (prhdr->auth_len) { /* We've already done integer wrap tests on auth_len in cli_pipe_validate_rpc_response(). */ if (*pdata_len < RPC_HDR_AUTH_LEN + prhdr->auth_len) { return NT_STATUS_BUFFER_TOO_SMALL; } *pdata_len -= (RPC_HDR_AUTH_LEN + prhdr->auth_len); } DEBUG(10,("cli_pipe_validate_current_pdu: got pdu len %u, data_len %u, ss_len %u\n", current_pdu_len, *pdata_len, ss_padding_len )); /* * If this is the first reply, and the allocation hint is reasonably, try and * set up the return_data parse_struct to the correct size. */ if ((prs_data_size(return_data) == 0) && rhdr_resp.alloc_hint && (rhdr_resp.alloc_hint < 15*1024*1024)) { if (!prs_set_buffer_size(return_data, rhdr_resp.alloc_hint)) { DEBUG(0,("cli_pipe_validate_current_pdu: reply alloc hint %u " "too large to allocate\n", (unsigned int)rhdr_resp.alloc_hint )); return NT_STATUS_NO_MEMORY; } } break; } case RPC_BINDNACK: DEBUG(1, ("cli_pipe_validate_current_pdu: Bind NACK received from remote machine %s " "pipe %s fnum 0x%x!\n", cli->cli->desthost, cli->pipe_name, (unsigned int)cli->fnum)); /* Use this for now... */ return NT_STATUS_NETWORK_ACCESS_DENIED; case RPC_FAULT: { RPC_HDR_RESP rhdr_resp; RPC_HDR_FAULT fault_resp; if(!smb_io_rpc_hdr_resp("rpc_hdr_resp", &rhdr_resp, current_pdu, 0)) { DEBUG(5,("cli_pipe_validate_current_pdu: failed to unmarshal RPC_HDR_RESP.\n")); return NT_STATUS_BUFFER_TOO_SMALL; } if(!smb_io_rpc_hdr_fault("fault", &fault_resp, current_pdu, 0)) { DEBUG(5,("cli_pipe_validate_current_pdu: failed to unmarshal RPC_HDR_FAULT.\n")); return NT_STATUS_BUFFER_TOO_SMALL; } DEBUG(1, ("cli_pipe_validate_current_pdu: RPC fault code %s received from remote machine %s " "pipe %s fnum 0x%x!\n", nt_errstr(fault_resp.status), cli->cli->desthost, cli->pipe_name, (unsigned int)cli->fnum)); if (NT_STATUS_IS_OK(fault_resp.status)) { return NT_STATUS_UNSUCCESSFUL; } else { return fault_resp.status; } } default: DEBUG(0, ("cli_pipe_validate_current_pdu: unknown packet type %u received " "from remote machine %s pipe %s fnum 0x%x!\n", (unsigned int)prhdr->pkt_type, cli->cli->desthost, cli->pipe_name, (unsigned int)cli->fnum)); return NT_STATUS_INVALID_INFO_CLASS; } if (prhdr->pkt_type != expected_pkt_type) { DEBUG(3, ("cli_pipe_validate_current_pdu: Connection to remote machine %s " "pipe %s fnum %x got an unexpected RPC packet " "type - %u, not %u\n", cli->cli->desthost, cli->pipe_name, (unsigned int)cli->fnum, prhdr->pkt_type, expected_pkt_type)); return NT_STATUS_INVALID_INFO_CLASS; } /* Do this just before return - we don't want to modify any rpc header data before now as we may have needed to do cryptographic actions on it before. */ if ((prhdr->pkt_type == RPC_BINDACK) && !(prhdr->flags & RPC_FLG_LAST)) { DEBUG(5,("cli_pipe_validate_current_pdu: bug in server (AS/U?), " "setting fragment first/last ON.\n")); prhdr->flags |= RPC_FLG_FIRST|RPC_FLG_LAST; } return NT_STATUS_OK;}/**************************************************************************** Ensure we eat the just processed pdu from the current_pdu prs_struct. Normally the frag_len and buffer size will match, but on the first trans reply there is a theoretical chance that buffer size > frag_len, so we must deal with that. ****************************************************************************/static NTSTATUS cli_pipe_reset_current_pdu(struct rpc_pipe_client *cli, RPC_HDR *prhdr, prs_struct *current_pdu){ uint32 current_pdu_len = prs_data_size(current_pdu); if (current_pdu_len < prhdr->frag_len) { return NT_STATUS_BUFFER_TOO_SMALL; } /* Common case. */ if (current_pdu_len == (uint32)prhdr->frag_len) { prs_mem_free(current_pdu); prs_init(current_pdu, 0, prs_get_mem_context(current_pdu), UNMARSHALL); /* Make current_pdu dynamic with no memory. */ prs_give_memory(current_pdu, 0, 0, True); return NT_STATUS_OK; } /* * Oh no ! More data in buffer than we processed in current pdu. * Cheat. Move the data down and shrink the buffer. */ memcpy(prs_data_p(current_pdu), prs_data_p(current_pdu) + prhdr->frag_len, current_pdu_len - prhdr->frag_len); /* Remember to set the read offset back to zero. */ prs_set_offset(current_pdu, 0); /* Shrink the buffer. */ if (!prs_set_buffer_size(current_pdu, current_pdu_len - prhdr->frag_len)) { return NT_STATUS_BUFFER_TOO_SMALL; } return NT_STATUS_OK;}/**************************************************************************** Send data on an rpc pipe via trans. The prs_struct data must be the last pdu fragment of an NDR data stream. Receive response data from an rpc pipe, which may be large... Read the first fragment: unfortunately have to use SMBtrans for the first bit, then SMBreadX for subsequent bits. If first fragment received also wasn't the last fragment, continue getting fragments until we _do_ receive the last fragment. Request/Response PDU's look like the following... |<------------------PDU len----------------------------------------------->| |<-HDR_LEN-->|<--REQ LEN------>|.............|<-AUTH_HDRLEN->|<-AUTH_LEN-->| +------------+-----------------+-------------+---------------+-------------+ | RPC HEADER | REQ/RESP HEADER | DATA ...... | AUTH_HDR | AUTH DATA | +------------+-----------------+-------------+---------------+-------------+ Where the presence of the AUTH_HDR and AUTH DATA are dependent on the signing & sealing being negotiated. ****************************************************************************/static NTSTATUS rpc_api_pipe(struct rpc_pipe_client *cli, prs_struct *data, /* Outgoing pdu fragment, already formatted for send. */ prs_struct *rbuf, /* Incoming reply - return as an NDR stream. */ uint8 expected_pkt_type){ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; char *rparam = NULL; uint32 rparam_len = 0; uint16 setup[2]; char *pdata = data ? prs_data_p(data) : NULL; uint32 data_len = data ? prs_offset(data) : 0; char *prdata = NULL; uint32 rdata_len = 0; uint32 max_data = cli->max_xmit_frag ? cli->max_xmit_frag : RPC_MAX_PDU_FRAG_LEN; uint32 current_rbuf_offset = 0; prs_struct current_pdu; #ifdef DEVELOPER /* Ensure we're not sending too much. */ SMB_ASSERT(data_len <= max_data);#endif /* Set up the current pdu parse struct. */ prs_init(¤t_pdu, 0, prs_get_mem_context(rbuf), UNMARSHALL); /* Create setup parameters - must be in native byte order. */ setup[0] = TRANSACT_DCERPCCMD; setup[1] = cli->fnum; /* Pipe file handle. */ DEBUG(5,("rpc_api_pipe: Remote machine %s pipe %s fnum 0x%x\n", cli->cli->desthost, cli->pipe_name, (unsigned int)cli->fnum )); /* * Send the last (or only) fragment of an RPC request. For small * amounts of data (about 1024 bytes or so) the RPC request and response * appears in a SMBtrans request and response. */ if (!cli_api_pipe(cli->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, ("rpc_api_pipe: Remote machine %s pipe %s fnum 0x%x" "returned critical error. Error was %s\n", cli->cli->desthost, cli->pipe_name, (unsigned int)cli->fnum, cli_errstr(cli->cli))); ret = cli_get_nt_error(cli->cli); SAFE_FREE(rparam); SAFE_FREE(prdata); goto err; } /* Throw away returned params - we know we won't use them. */ SAFE_FREE(rparam); if (prdata == NULL) { DEBUG(3,("rpc_api_pipe: Remote machine %s pipe %s " "fnum 0x%x failed to return data.\n", cli->cli->desthost, cli->pipe_name, (unsigned int)cli->fnum)); /* Yes - some calls can truely return no data... */ prs_mem_free(¤t_pdu); return NT_STATUS_OK; } /* * Give this memory as dynamic to the current pdu. */ prs_give_memory(¤t_pdu, prdata, rdata_len, True); /* Ensure we can mess with the return prs_struct. */ SMB_ASSERT(UNMARSHALLING(rbuf)); SMB_ASSERT(prs_data_size(rbuf) == 0); /* Make rbuf dynamic with no memory. */ prs_give_memory(rbuf, 0, 0, True); while(1) { RPC_HDR rhdr; char *ret_data; uint32 ret_data_len; /* Ensure we have enough data for a pdu. */ ret = cli_pipe_get_current_pdu(cli, &rhdr, ¤t_pdu); if (!NT_STATUS_IS_OK(ret)) { goto err; } /* We pass in rbuf here so if the alloc hint is set correctly we can set the output size and avoid reallocs. */ ret = cli_pipe_validate_current_pdu(cli, &rhdr, ¤t_pdu, expected_pkt_type, &ret_data, &ret_data_len, rbuf); DEBUG(10,("rpc_api_pipe: got PDU len of %u at offset %u\n", prs_data_size(¤t_pdu), current_rbuf_offset )); if (!NT_STATUS_IS_OK(ret)) { goto err; } if ((rhdr.flags & RPC_FLG_FIRST)) { if (rhdr.pack_type[0] == 0) { /* Set the data type correctly for big-endian data on the first packet. */ DEBUG(10,("rpc_api_pipe: On machine %s pipe %s fnum 0x%x "
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?