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(&current_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(&current_pdu);		return NT_STATUS_OK;	}	/*	 * Give this memory as dynamic to the current pdu.	 */	prs_give_memory(&current_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, &current_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, &current_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(&current_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 + -
显示快捷键?