cli_pipe.c
来自「samba-3.0.22.tar.gz 编译smb服务器的源码」· C语言 代码 · 共 2,128 行 · 第 1/5 页
C
2,128 行
/* * Unix SMB/CIFS implementation. * RPC Pipe client / server routines * Largely rewritten by Jeremy Allison 2005. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include "includes.h"#undef DBGC_CLASS#define DBGC_CLASS DBGC_RPC_CLIextern struct pipe_id_info pipe_names[];/******************************************************************** Map internal value to wire value. ********************************************************************/static int map_pipe_auth_type_to_rpc_auth_type(enum pipe_auth_type auth_type){ switch (auth_type) { case PIPE_AUTH_TYPE_NONE: return RPC_ANONYMOUS_AUTH_TYPE; case PIPE_AUTH_TYPE_NTLMSSP: return RPC_NTLMSSP_AUTH_TYPE; case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP: case PIPE_AUTH_TYPE_SPNEGO_KRB5: return RPC_SPNEGO_AUTH_TYPE; case PIPE_AUTH_TYPE_SCHANNEL: return RPC_SCHANNEL_AUTH_TYPE; case PIPE_AUTH_TYPE_KRB5: return RPC_KRB5_AUTH_TYPE; default: DEBUG(0,("map_pipe_auth_type_to_rpc_type: unknown pipe " "auth type %u\n", (unsigned int)auth_type )); break; } return -1;}/******************************************************************** Rpc pipe call id. ********************************************************************/static uint32 get_rpc_call_id(void){ static uint32 call_id = 0; return ++call_id;}/******************************************************************* Use SMBreadX to get rest of one fragment's worth of rpc data. Will expand the current_pdu struct to the correct size. ********************************************************************/static NTSTATUS rpc_read(struct rpc_pipe_client *cli, prs_struct *current_pdu, uint32 data_to_read, uint32 *current_pdu_offset){ size_t size = (size_t)cli->max_recv_frag; uint32 stream_offset = 0; ssize_t num_read; char *pdata; ssize_t extra_data_size = ((ssize_t)*current_pdu_offset) + ((ssize_t)data_to_read) - (ssize_t)prs_data_size(current_pdu); DEBUG(5,("rpc_read: data_to_read: %u current_pdu offset: %u extra_data_size: %d\n", (unsigned int)data_to_read, (unsigned int)*current_pdu_offset, (int)extra_data_size )); /* * Grow the buffer if needed to accommodate the data to be read. */ if (extra_data_size > 0) { if(!prs_force_grow(current_pdu, (uint32)extra_data_size)) { DEBUG(0,("rpc_read: Failed to grow parse struct by %d bytes.\n", (int)extra_data_size )); return NT_STATUS_NO_MEMORY; } DEBUG(5,("rpc_read: grew buffer by %d bytes to %u\n", (int)extra_data_size, prs_data_size(current_pdu) )); } pdata = prs_data_p(current_pdu) + *current_pdu_offset; do { /* read data using SMBreadX */ if (size > (size_t)data_to_read) { size = (size_t)data_to_read; } num_read = cli_read(cli->cli, cli->fnum, pdata, (off_t)stream_offset, size); DEBUG(5,("rpc_read: num_read = %d, read offset: %u, to read: %u\n", (int)num_read, (unsigned int)stream_offset, (unsigned int)data_to_read)); /* * A dos error of ERRDOS/ERRmoredata is not an error. */ if (cli_is_dos_error(cli->cli)) { uint32 ecode; uint8 eclass; cli_dos_error(cli->cli, &eclass, &ecode); if (eclass != ERRDOS && ecode != ERRmoredata) { DEBUG(0,("rpc_read: DOS Error %d/%u (%s) in cli_read on pipe %s\n", eclass, (unsigned int)ecode, cli_errstr(cli->cli), cli->pipe_name )); return dos_to_ntstatus(eclass, ecode); } } /* * Likewise for NT_STATUS_BUFFER_TOO_SMALL */ if (cli_is_nt_error(cli->cli)) { if (!NT_STATUS_EQUAL(cli_nt_error(cli->cli), NT_STATUS_BUFFER_TOO_SMALL)) { DEBUG(0,("rpc_read: Error (%s) in cli_read on pipe %s\n", nt_errstr(cli_nt_error(cli->cli)), cli->pipe_name )); return cli_nt_error(cli->cli); } } if (num_read == -1) { DEBUG(0,("rpc_read: Error - cli_read on pipe %s returned -1\n", cli->pipe_name )); return cli_get_nt_error(cli->cli); } 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 current_pdu by the amount read. */ *current_pdu_offset += stream_offset; return NT_STATUS_OK;}/**************************************************************************** Try and get a PDU's worth of data from current_pdu. If not, then read more from the wire. ****************************************************************************/static NTSTATUS cli_pipe_get_current_pdu(struct rpc_pipe_client *cli, RPC_HDR *prhdr, prs_struct *current_pdu){ NTSTATUS ret = NT_STATUS_OK; uint32 current_pdu_len = prs_data_size(current_pdu); /* Ensure we have at least RPC_HEADER_LEN worth of data to parse. */ if (current_pdu_len < RPC_HEADER_LEN) { /* rpc_read expands the current_pdu struct as neccessary. */ ret = rpc_read(cli, current_pdu, RPC_HEADER_LEN - current_pdu_len, ¤t_pdu_len); if (!NT_STATUS_IS_OK(ret)) { return ret; } } /* This next call sets the endian bit correctly in current_pdu. */ /* We will propagate this to rbuf later. */ if(!smb_io_rpc_hdr("rpc_hdr ", prhdr, current_pdu, 0)) { DEBUG(0,("cli_pipe_get_current_pdu: Failed to unmarshall RPC_HDR.\n")); return NT_STATUS_BUFFER_TOO_SMALL; } /* Ensure we have frag_len bytes of data. */ if (current_pdu_len < prhdr->frag_len) { /* rpc_read expands the current_pdu struct as neccessary. */ ret = rpc_read(cli, current_pdu, (uint32)prhdr->frag_len - current_pdu_len, ¤t_pdu_len); if (!NT_STATUS_IS_OK(ret)) { return ret; } } if (current_pdu_len < prhdr->frag_len) { return NT_STATUS_BUFFER_TOO_SMALL; } return NT_STATUS_OK;}/**************************************************************************** NTLMSSP specific sign/seal. Virtually identical to rpc_server/srv_pipe.c:api_pipe_ntlmssp_auth_process. In fact I should probably abstract these into identical pieces of code... JRA. ****************************************************************************/static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, RPC_HDR *prhdr, prs_struct *current_pdu, uint8 *p_ss_padding_len){ RPC_HDR_AUTH auth_info; uint32 save_offset = prs_offset(current_pdu); uint32 auth_len = prhdr->auth_len; NTLMSSP_STATE *ntlmssp_state = cli->auth.a_u.ntlmssp_state; unsigned char *data = NULL; size_t data_len; unsigned char *full_packet_data = NULL; size_t full_packet_data_len; DATA_BLOB auth_blob; NTSTATUS status; if (cli->auth.auth_level == PIPE_AUTH_LEVEL_NONE || cli->auth.auth_level == PIPE_AUTH_LEVEL_CONNECT) { return NT_STATUS_OK; } if (!ntlmssp_state) { return NT_STATUS_INVALID_PARAMETER; } /* Ensure there's enough data for an authenticated response. */ if ((auth_len > RPC_MAX_SIGN_SIZE) || (RPC_HEADER_LEN + RPC_HDR_RESP_LEN + RPC_HDR_AUTH_LEN + auth_len > prhdr->frag_len)) { DEBUG(0,("cli_pipe_verify_ntlmssp: auth_len %u is too large.\n", (unsigned int)auth_len )); return NT_STATUS_BUFFER_TOO_SMALL; } /* * We need the full packet data + length (minus auth stuff) as well as the packet data + length * after the RPC header. * We need to pass in the full packet (minus auth len) to the NTLMSSP sign and check seal * functions as NTLMv2 checks the rpc headers also. */ data = (unsigned char *)(prs_data_p(current_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN); data_len = (size_t)(prhdr->frag_len - RPC_HEADER_LEN - RPC_HDR_RESP_LEN - RPC_HDR_AUTH_LEN - auth_len); full_packet_data = (unsigned char *)prs_data_p(current_pdu); full_packet_data_len = prhdr->frag_len - auth_len; /* Pull the auth header and the following data into a blob. */ if(!prs_set_offset(current_pdu, RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len)) { DEBUG(0,("cli_pipe_verify_ntlmssp: cannot move offset to %u.\n", (unsigned int)RPC_HEADER_LEN + (unsigned int)RPC_HDR_RESP_LEN + (unsigned int)data_len )); return NT_STATUS_BUFFER_TOO_SMALL; } if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, current_pdu, 0)) { DEBUG(0,("cli_pipe_verify_ntlmssp: failed to unmarshall RPC_HDR_AUTH.\n")); return NT_STATUS_BUFFER_TOO_SMALL; } auth_blob.data = (unsigned char *)prs_data_p(current_pdu) + prs_offset(current_pdu); auth_blob.length = auth_len; switch (cli->auth.auth_level) { case PIPE_AUTH_LEVEL_PRIVACY: /* Data is encrypted. */ status = ntlmssp_unseal_packet(ntlmssp_state, data, data_len, full_packet_data, full_packet_data_len, &auth_blob); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("cli_pipe_verify_ntlmssp: failed to unseal " "packet from remote machine %s on pipe %s " "fnum 0x%x. Error was %s.\n", cli->cli->desthost, cli->pipe_name, (unsigned int)cli->fnum, nt_errstr(status) )); return status; } break; case PIPE_AUTH_LEVEL_INTEGRITY: /* Data is signed. */ status = ntlmssp_check_packet(ntlmssp_state, data, data_len, full_packet_data, full_packet_data_len, &auth_blob); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("cli_pipe_verify_ntlmssp: check signing failed on " "packet from remote machine %s on pipe %s " "fnum 0x%x. Error was %s.\n", cli->cli->desthost, cli->pipe_name, (unsigned int)cli->fnum, nt_errstr(status) )); return status; } break; default: DEBUG(0,("cli_pipe_verify_ntlmssp: unknown internal auth level %d\n", cli->auth.auth_level )); return NT_STATUS_INVALID_INFO_CLASS; } /* * Return the current pointer to the data offset. */ if(!prs_set_offset(current_pdu, save_offset)) { DEBUG(0,("api_pipe_auth_process: failed to set offset back to %u\n", (unsigned int)save_offset )); return NT_STATUS_BUFFER_TOO_SMALL; } /* * Remember the padding length. We must remove it from the real data * stream once the sign/seal is done. */ *p_ss_padding_len = auth_info.auth_pad_len; return NT_STATUS_OK;}/**************************************************************************** schannel specific sign/seal. ****************************************************************************/static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, RPC_HDR *prhdr, prs_struct *current_pdu, uint8 *p_ss_padding_len){ RPC_HDR_AUTH auth_info; RPC_AUTH_SCHANNEL_CHK schannel_chk; uint32 auth_len = prhdr->auth_len; uint32 save_offset = prs_offset(current_pdu); struct schannel_auth_struct *schannel_auth = cli->auth.a_u.schannel_auth; uint32 data_len; if (cli->auth.auth_level == PIPE_AUTH_LEVEL_NONE || cli->auth.auth_level == PIPE_AUTH_LEVEL_CONNECT) { return NT_STATUS_OK; } if (auth_len != RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN) { DEBUG(0,("cli_pipe_verify_schannel: auth_len %u.\n", (unsigned int)auth_len )); return NT_STATUS_INVALID_PARAMETER; } if (!schannel_auth) { return NT_STATUS_INVALID_PARAMETER; } /* Ensure there's enough data for an authenticated response. */ if ((auth_len > RPC_MAX_SIGN_SIZE) || (RPC_HEADER_LEN + RPC_HDR_RESP_LEN + RPC_HDR_AUTH_LEN + auth_len > prhdr->frag_len)) { DEBUG(0,("cli_pipe_verify_schannel: auth_len %u is too large.\n", (unsigned int)auth_len )); return NT_STATUS_INVALID_PARAMETER; } data_len = prhdr->frag_len - RPC_HEADER_LEN - RPC_HDR_RESP_LEN - RPC_HDR_AUTH_LEN - auth_len; if(!prs_set_offset(current_pdu, RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len)) { DEBUG(0,("cli_pipe_verify_schannel: cannot move offset to %u.\n", (unsigned int)RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len )); return NT_STATUS_BUFFER_TOO_SMALL; } if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, current_pdu, 0)) { DEBUG(0,("cli_pipe_verify_schannel: failed to unmarshall RPC_HDR_AUTH.\n")); return NT_STATUS_BUFFER_TOO_SMALL; } if (auth_info.auth_type != RPC_SCHANNEL_AUTH_TYPE) { DEBUG(0,("cli_pipe_verify_schannel: Invalid auth info %d on schannel\n", auth_info.auth_type)); return NT_STATUS_BUFFER_TOO_SMALL; } if(!smb_io_rpc_auth_schannel_chk("", RPC_AUTH_SCHANNEL_SIGN_OR_SEAL_CHK_LEN, &schannel_chk, current_pdu, 0)) { DEBUG(0,("cli_pipe_verify_schannel: failed to unmarshal RPC_AUTH_SCHANNEL_CHK.\n")); return NT_STATUS_BUFFER_TOO_SMALL; } if (!schannel_decode(schannel_auth, cli->auth.auth_level, SENDER_IS_ACCEPTOR, &schannel_chk, prs_data_p(current_pdu)+RPC_HEADER_LEN+RPC_HDR_RESP_LEN, data_len)) { DEBUG(3,("cli_pipe_verify_schannel: failed to decode PDU " "Connection to remote machine %s " "pipe %s fnum 0x%x.\n", cli->cli->desthost, cli->pipe_name, (unsigned int)cli->fnum )); return NT_STATUS_INVALID_PARAMETER; } /* The sequence number gets incremented on both send and receive. */ schannel_auth->seq_num++; /* * Return the current pointer to the data offset. */ if(!prs_set_offset(current_pdu, save_offset)) { DEBUG(0,("api_pipe_auth_process: failed to set offset back to %u\n", (unsigned int)save_offset )); return NT_STATUS_BUFFER_TOO_SMALL; } /* * Remember the padding length. We must remove it from the real data * stream once the sign/seal is done. */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?