📄 rpc_message.c
字号:
((*Header)->common.frag_len - hdr_length < header_auth_len)) { WARN("frag_len %d too small for hdr_length %d and auth_len %d\n", (*Header)->common.frag_len, hdr_length, header_auth_len); status = RPC_S_PROTOCOL_ERROR; goto fail; } if ((*Header)->common.auth_len != auth_length) { WARN("auth_len header field changed from %ld to %d\n", auth_length, (*Header)->common.auth_len); status = RPC_S_PROTOCOL_ERROR; goto fail; } if (((*Header)->common.flags & RPC_FLG_FIRST) != first_flag) { TRACE("invalid packet flags\n"); status = RPC_S_PROTOCOL_ERROR; goto fail; } data_length = (*Header)->common.frag_len - hdr_length - header_auth_len; if (data_length + buffer_length > pMsg->BufferLength) { TRACE("allocation hint exceeded, new buffer length = %ld\n", data_length + buffer_length); pMsg->BufferLength = data_length + buffer_length; status = I_RpcReAllocateBuffer(pMsg); if (status != RPC_S_OK) goto fail; } if (data_length == 0) dwRead = 0; else dwRead = rpcrt4_conn_read(Connection, (unsigned char *)pMsg->Buffer + buffer_length, data_length); if (dwRead != data_length) { WARN("bad data length, %d/%ld\n", dwRead, data_length); status = RPC_S_PROTOCOL_ERROR; goto fail; } if (header_auth_len) { if (header_auth_len < sizeof(RpcAuthVerifier)) { WARN("bad auth verifier length %d\n", header_auth_len); status = RPC_S_PROTOCOL_ERROR; goto fail; } /* FIXME: we should accumulate authentication data for the bind, * bind_ack, alter_context and alter_context_response if necessary. * however, the details of how this is done is very sketchy in the * DCE/RPC spec. for all other packet types that have authentication * verifier data then it is just duplicated in all the fragments */ dwRead = rpcrt4_conn_read(Connection, auth_data, header_auth_len); if (dwRead != header_auth_len) { WARN("bad authentication data length, %d/%d\n", dwRead, header_auth_len); status = RPC_S_PROTOCOL_ERROR; goto fail; } /* these packets are handled specially, not by the generic SecurePacket * function */ if ((common_hdr.ptype != PKT_BIND) && (common_hdr.ptype != PKT_BIND_ACK) && (common_hdr.ptype != PKT_AUTH3)) status = RPCRT4_SecurePacket(Connection, SECURE_PACKET_RECEIVE, *Header, hdr_length, (unsigned char *)pMsg->Buffer + buffer_length, data_length, (RpcAuthVerifier *)auth_data, (unsigned char *)auth_data + sizeof(RpcAuthVerifier), header_auth_len - sizeof(RpcAuthVerifier)); } buffer_length += data_length; if (!((*Header)->common.flags & RPC_FLG_LAST)) { TRACE("next header\n"); /* read the header of next packet */ dwRead = rpcrt4_conn_read(Connection, *Header, hdr_length); if (dwRead != hdr_length) { WARN("invalid packet header size (%d)\n", dwRead); status = RPC_S_PROTOCOL_ERROR; goto fail; } first_flag = 0; } else { break; } } pMsg->BufferLength = buffer_length; /* respond to authorization request */ if (common_hdr.ptype == PKT_BIND_ACK && auth_length > sizeof(RpcAuthVerifier)) { status = RPCRT_AuthorizeConnection(Connection, auth_data + sizeof(RpcAuthVerifier), auth_length); if (status) goto fail; } /* success */ status = RPC_S_OK;fail: if (status != RPC_S_OK) { RPCRT4_FreeHeader(*Header); *Header = NULL; } HeapFree(GetProcessHeap(), 0, auth_data); return status;}/*********************************************************************** * I_RpcGetBuffer [RPCRT4.@] * * Allocates a buffer for use by I_RpcSend or I_RpcSendReceive and binds to the * server interface. * * PARAMS * pMsg [I/O] RPC message information. * * RETURNS * Success: RPC_S_OK. * Failure: RPC_S_INVALID_BINDING if pMsg->Handle is invalid. * RPC_S_SERVER_UNAVAILABLE if unable to connect to server. * ERROR_OUTOFMEMORY if buffer allocation failed. * * NOTES * The pMsg->BufferLength field determines the size of the buffer to allocate, * in bytes. * * Use I_RpcFreeBuffer() to unbind from the server and free the message buffer. * * SEE ALSO * I_RpcFreeBuffer(), I_RpcSend(), I_RpcReceive(), I_RpcSendReceive(). */RPC_STATUS WINAPI I_RpcGetBuffer(PRPC_MESSAGE pMsg){ TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength); /* FIXME: pfnAllocate? */ pMsg->Buffer = HeapAlloc(GetProcessHeap(), 0, pMsg->BufferLength); TRACE("Buffer=%p\n", pMsg->Buffer); /* FIXME: which errors to return? */ return pMsg->Buffer ? S_OK : E_OUTOFMEMORY;}/*********************************************************************** * I_RpcReAllocateBuffer (internal) */static RPC_STATUS I_RpcReAllocateBuffer(PRPC_MESSAGE pMsg){ TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength); pMsg->Buffer = HeapReAlloc(GetProcessHeap(), 0, pMsg->Buffer, pMsg->BufferLength); TRACE("Buffer=%p\n", pMsg->Buffer); return pMsg->Buffer ? RPC_S_OK : RPC_S_OUT_OF_RESOURCES;}/*********************************************************************** * I_RpcFreeBuffer [RPCRT4.@] * * Frees a buffer allocated by I_RpcGetBuffer or I_RpcReceive and unbinds from * the server interface. * * PARAMS * pMsg [I/O] RPC message information. * * RETURNS * RPC_S_OK. * * SEE ALSO * I_RpcGetBuffer(), I_RpcReceive(). */RPC_STATUS WINAPI I_RpcFreeBuffer(PRPC_MESSAGE pMsg){ TRACE("(%p) Buffer=%p\n", pMsg, pMsg->Buffer); /* FIXME: pfnFree? */ HeapFree(GetProcessHeap(), 0, pMsg->Buffer); pMsg->Buffer = NULL; return S_OK;}/*********************************************************************** * I_RpcSend [RPCRT4.@] * * Sends a message to the server. * * PARAMS * pMsg [I/O] RPC message information. * * RETURNS * Unknown. * * NOTES * The buffer must have been allocated with I_RpcGetBuffer(). * * SEE ALSO * I_RpcGetBuffer(), I_RpcReceive(), I_RpcSendReceive(). */RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg){ RpcBinding* bind = (RpcBinding*)pMsg->Handle; RpcConnection* conn; RPC_CLIENT_INTERFACE* cif = NULL; RPC_STATUS status; RpcPktHdr *hdr; TRACE("(%p)\n", pMsg); if (!bind || bind->server) return RPC_S_INVALID_BINDING; cif = pMsg->RpcInterfaceInformation; if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ if (!bind->Endpoint || !bind->Endpoint[0]) { TRACE("automatically resolving partially bound binding\n"); status = RpcEpResolveBinding(bind, cif); if (status != RPC_S_OK) return status; } status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax, &cif->InterfaceId); if (status != RPC_S_OK) return status; hdr = RPCRT4_BuildRequestHeader(pMsg->DataRepresentation, pMsg->BufferLength, pMsg->ProcNum, &bind->ObjectUuid); if (!hdr) { RPCRT4_CloseBinding(bind, conn); return ERROR_OUTOFMEMORY; } hdr->common.call_id = conn->NextCallId++; status = RPCRT4_Send(conn, hdr, pMsg->Buffer, pMsg->BufferLength); RPCRT4_FreeHeader(hdr); /* save the connection, so the response can be read from it */ pMsg->ReservedForRuntime = conn; return status;}/* is this status something that the server can't recover from? */static inline BOOL is_hard_error(RPC_STATUS status){ switch (status) { case 0: /* user-defined fault */ case ERROR_ACCESS_DENIED: case ERROR_INVALID_PARAMETER: case RPC_S_PROTOCOL_ERROR: case RPC_S_CALL_FAILED: case RPC_S_CALL_FAILED_DNE: return TRUE; default: return FALSE; }}/*********************************************************************** * I_RpcReceive [RPCRT4.@] */RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg){ RpcBinding* bind = (RpcBinding*)pMsg->Handle; RpcConnection* conn; RPC_CLIENT_INTERFACE* cif = NULL; RPC_SERVER_INTERFACE* sif = NULL; RPC_STATUS status; RpcPktHdr *hdr = NULL; TRACE("(%p)\n", pMsg); if (!bind) return RPC_S_INVALID_BINDING; if (pMsg->ReservedForRuntime) { conn = pMsg->ReservedForRuntime; pMsg->ReservedForRuntime = NULL; } else { if (bind->server) { sif = pMsg->RpcInterfaceInformation; if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ status = RPCRT4_OpenBinding(bind, &conn, &sif->TransferSyntax, &sif->InterfaceId); } else { cif = pMsg->RpcInterfaceInformation; if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ if (!bind->Endpoint || !bind->Endpoint[0]) { TRACE("automatically resolving partially bound binding\n"); status = RpcEpResolveBinding(bind, cif); if (status != RPC_S_OK) return status; } status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax, &cif->InterfaceId); } if (status != RPC_S_OK) return status; } status = RPCRT4_Receive(conn, &hdr, pMsg); if (status != RPC_S_OK) { WARN("receive failed with error %lx\n", status); goto fail; } switch (hdr->common.ptype) { case PKT_RESPONSE: if (bind->server) { status = RPC_S_PROTOCOL_ERROR; goto fail; } break; case PKT_REQUEST: if (!bind->server) { status = RPC_S_PROTOCOL_ERROR; goto fail; } break; case PKT_FAULT: ERR ("we got fault packet with status 0x%lx\n", hdr->fault.status); status = NCA2RPC_STATUS(hdr->fault.status); if (is_hard_error(status)) goto fail; break; default: WARN("bad packet type %d\n", hdr->common.ptype); status = RPC_S_PROTOCOL_ERROR; goto fail; } /* success */ RPCRT4_CloseBinding(bind, conn); RPCRT4_FreeHeader(hdr); return status;fail: RPCRT4_FreeHeader(hdr); RPCRT4_DestroyConnection(conn); return status;}/*********************************************************************** * I_RpcSendReceive [RPCRT4.@] * * Sends a message to the server and receives the response. * * PARAMS * pMsg [I/O] RPC message information. * * RETURNS * Success: RPC_S_OK. * Failure: Any error code. * * NOTES * The buffer must have been allocated with I_RpcGetBuffer(). * * SEE ALSO * I_RpcGetBuffer(), I_RpcSend(), I_RpcReceive(). */RPC_STATUS WINAPI I_RpcSendReceive(PRPC_MESSAGE pMsg){ RPC_STATUS status; RPC_MESSAGE original_message; TRACE("(%p)\n", pMsg); original_message = *pMsg; status = I_RpcSend(pMsg); if (status == RPC_S_OK) status = I_RpcReceive(pMsg); /* free the buffer replaced by a new buffer in I_RpcReceive */ if (status == RPC_S_OK) I_RpcFreeBuffer(&original_message); return status;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -