Changes in crossover-wine-src-6.1.0 except for configure
[wine/hacks.git] / dlls / rpcrt4 / rpc_message.c
blobaf487b3d8a61248db43323c57b4a264f3fb55ba6
1 /*
2 * RPC messages
4 * Copyright 2001-2002 Ove Kåven, TransGaming Technologies
5 * Copyright 2004 Filip Navara
6 * Copyright 2006 CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <string.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winerror.h"
30 #include "winreg.h"
32 #include "rpc.h"
33 #include "rpcndr.h"
34 #include "rpcdcep.h"
36 #include "wine/debug.h"
38 #include "rpc_binding.h"
39 #include "rpc_misc.h"
40 #include "rpc_defs.h"
41 #include "rpc_message.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
45 /* note: the DCE/RPC spec says the alignment amount should be 4, but
46 * MS/RPC servers seem to always use 16 */
47 #define AUTH_ALIGNMENT 16
49 /* gets the amount needed to round a value up to the specified alignment */
50 #define ROUND_UP_AMOUNT(value, alignment) \
51 (((alignment) - (((value) % (alignment)))) % (alignment))
52 #define ROUND_UP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment)-1))
54 enum secure_packet_direction
56 SECURE_PACKET_SEND,
57 SECURE_PACKET_RECEIVE
60 static RPC_STATUS I_RpcReAllocateBuffer(PRPC_MESSAGE pMsg);
62 static DWORD RPCRT4_GetHeaderSize(const RpcPktHdr *Header)
64 static const DWORD header_sizes[] = {
65 sizeof(Header->request), 0, sizeof(Header->response),
66 sizeof(Header->fault), 0, 0, 0, 0, 0, 0, 0, sizeof(Header->bind),
67 sizeof(Header->bind_ack), sizeof(Header->bind_nack),
68 0, 0, 0, 0, 0, 0, sizeof(Header->http)
70 ULONG ret = 0;
72 if (Header->common.ptype < sizeof(header_sizes) / sizeof(header_sizes[0])) {
73 ret = header_sizes[Header->common.ptype];
74 if (ret == 0)
75 FIXME("unhandled packet type\n");
76 if (Header->common.flags & RPC_FLG_OBJECT_UUID)
77 ret += sizeof(UUID);
78 } else {
79 WARN("invalid packet type %u\n", Header->common.ptype);
82 return ret;
85 static int packet_has_body(const RpcPktHdr *Header)
87 return (Header->common.ptype == PKT_FAULT) ||
88 (Header->common.ptype == PKT_REQUEST) ||
89 (Header->common.ptype == PKT_RESPONSE);
92 static int packet_has_auth_verifier(const RpcPktHdr *Header)
94 return !(Header->common.ptype == PKT_BIND_NACK) &&
95 !(Header->common.ptype == PKT_SHUTDOWN);
98 static VOID RPCRT4_BuildCommonHeader(RpcPktHdr *Header, unsigned char PacketType,
99 unsigned long DataRepresentation)
101 Header->common.rpc_ver = RPC_VER_MAJOR;
102 Header->common.rpc_ver_minor = RPC_VER_MINOR;
103 Header->common.ptype = PacketType;
104 Header->common.drep[0] = LOBYTE(LOWORD(DataRepresentation));
105 Header->common.drep[1] = HIBYTE(LOWORD(DataRepresentation));
106 Header->common.drep[2] = LOBYTE(HIWORD(DataRepresentation));
107 Header->common.drep[3] = HIBYTE(HIWORD(DataRepresentation));
108 Header->common.auth_len = 0;
109 Header->common.call_id = 1;
110 Header->common.flags = 0;
111 /* Flags and fragment length are computed in RPCRT4_Send. */
114 static RpcPktHdr *RPCRT4_BuildRequestHeader(unsigned long DataRepresentation,
115 unsigned long BufferLength,
116 unsigned short ProcNum,
117 UUID *ObjectUuid)
119 RpcPktHdr *header;
120 BOOL has_object;
121 RPC_STATUS status;
123 has_object = (ObjectUuid != NULL && !UuidIsNil(ObjectUuid, &status));
124 header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
125 sizeof(header->request) + (has_object ? sizeof(UUID) : 0));
126 if (header == NULL) {
127 return NULL;
130 RPCRT4_BuildCommonHeader(header, PKT_REQUEST, DataRepresentation);
131 header->common.frag_len = sizeof(header->request);
132 header->request.alloc_hint = BufferLength;
133 header->request.context_id = 0;
134 header->request.opnum = ProcNum;
135 if (has_object) {
136 header->common.flags |= RPC_FLG_OBJECT_UUID;
137 header->common.frag_len += sizeof(UUID);
138 memcpy(&header->request + 1, ObjectUuid, sizeof(UUID));
141 return header;
144 static RpcPktHdr *RPCRT4_BuildResponseHeader(unsigned long DataRepresentation,
145 unsigned long BufferLength)
147 RpcPktHdr *header;
149 header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->response));
150 if (header == NULL) {
151 return NULL;
154 RPCRT4_BuildCommonHeader(header, PKT_RESPONSE, DataRepresentation);
155 header->common.frag_len = sizeof(header->response);
156 header->response.alloc_hint = BufferLength;
158 return header;
161 RpcPktHdr *RPCRT4_BuildFaultHeader(unsigned long DataRepresentation,
162 RPC_STATUS Status)
164 RpcPktHdr *header;
166 header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->fault));
167 if (header == NULL) {
168 return NULL;
171 RPCRT4_BuildCommonHeader(header, PKT_FAULT, DataRepresentation);
172 header->common.frag_len = sizeof(header->fault);
173 header->fault.status = Status;
175 return header;
178 RpcPktHdr *RPCRT4_BuildBindHeader(unsigned long DataRepresentation,
179 unsigned short MaxTransmissionSize,
180 unsigned short MaxReceiveSize,
181 RPC_SYNTAX_IDENTIFIER *AbstractId,
182 RPC_SYNTAX_IDENTIFIER *TransferId)
184 RpcPktHdr *header;
186 header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->bind));
187 if (header == NULL) {
188 return NULL;
191 RPCRT4_BuildCommonHeader(header, PKT_BIND, DataRepresentation);
192 header->common.frag_len = sizeof(header->bind);
193 header->bind.max_tsize = MaxTransmissionSize;
194 header->bind.max_rsize = MaxReceiveSize;
195 header->bind.num_elements = 1;
196 header->bind.num_syntaxes = 1;
197 memcpy(&header->bind.abstract, AbstractId, sizeof(RPC_SYNTAX_IDENTIFIER));
198 memcpy(&header->bind.transfer, TransferId, sizeof(RPC_SYNTAX_IDENTIFIER));
200 return header;
203 static RpcPktHdr *RPCRT4_BuildAuthHeader(unsigned long DataRepresentation)
205 RpcPktHdr *header;
207 header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
208 sizeof(header->common) + 12);
209 if (header == NULL)
210 return NULL;
212 RPCRT4_BuildCommonHeader(header, PKT_AUTH3, DataRepresentation);
213 header->common.frag_len = 0x14;
214 header->common.auth_len = 0;
216 return header;
219 RpcPktHdr *RPCRT4_BuildBindNackHeader(unsigned long DataRepresentation,
220 unsigned char RpcVersion,
221 unsigned char RpcVersionMinor)
223 RpcPktHdr *header;
225 header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->bind_nack));
226 if (header == NULL) {
227 return NULL;
230 RPCRT4_BuildCommonHeader(header, PKT_BIND_NACK, DataRepresentation);
231 header->common.frag_len = sizeof(header->bind_nack);
232 header->bind_nack.protocols_count = 1;
233 header->bind_nack.protocols[0].rpc_ver = RpcVersion;
234 header->bind_nack.protocols[0].rpc_ver_minor = RpcVersionMinor;
236 return header;
239 RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation,
240 unsigned short MaxTransmissionSize,
241 unsigned short MaxReceiveSize,
242 LPSTR ServerAddress,
243 unsigned long Result,
244 unsigned long Reason,
245 RPC_SYNTAX_IDENTIFIER *TransferId)
247 RpcPktHdr *header;
248 unsigned long header_size;
249 RpcAddressString *server_address;
250 RpcResults *results;
251 RPC_SYNTAX_IDENTIFIER *transfer_id;
253 header_size = sizeof(header->bind_ack) +
254 ROUND_UP(FIELD_OFFSET(RpcAddressString, string[strlen(ServerAddress) + 1]), 4) +
255 sizeof(RpcResults) +
256 sizeof(RPC_SYNTAX_IDENTIFIER);
258 header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, header_size);
259 if (header == NULL) {
260 return NULL;
263 RPCRT4_BuildCommonHeader(header, PKT_BIND_ACK, DataRepresentation);
264 header->common.frag_len = header_size;
265 header->bind_ack.max_tsize = MaxTransmissionSize;
266 header->bind_ack.max_rsize = MaxReceiveSize;
267 server_address = (RpcAddressString*)(&header->bind_ack + 1);
268 server_address->length = strlen(ServerAddress) + 1;
269 strcpy(server_address->string, ServerAddress);
270 /* results is 4-byte aligned */
271 results = (RpcResults*)((ULONG_PTR)server_address + ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4));
272 results->num_results = 1;
273 results->results[0].result = Result;
274 results->results[0].reason = Reason;
275 transfer_id = (RPC_SYNTAX_IDENTIFIER*)(results + 1);
276 memcpy(transfer_id, TransferId, sizeof(RPC_SYNTAX_IDENTIFIER));
278 return header;
281 RpcPktHdr *RPCRT4_BuildHttpHeader(unsigned long DataRepresentation,
282 unsigned short flags,
283 unsigned short num_data_items,
284 unsigned int payload_size)
286 RpcPktHdr *header;
288 header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->http) + payload_size);
289 if (header == NULL) {
290 ERR("failed to allocate memory\n");
291 return NULL;
294 RPCRT4_BuildCommonHeader(header, PKT_HTTP, DataRepresentation);
295 /* since the packet isn't current sent using RPCRT4_Send, set the flags
296 * manually here */
297 header->common.flags = RPC_FLG_FIRST|RPC_FLG_LAST;
298 header->common.call_id = 0;
299 header->common.frag_len = sizeof(header->http) + payload_size;
300 header->http.flags = flags;
301 header->http.num_data_items = num_data_items;
303 return header;
306 #define WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, type, value) \
307 do { \
308 *(unsigned int *)(payload) = (type); \
309 (payload) += 4; \
310 *(unsigned int *)(payload) = (value); \
311 (payload) += 4; \
312 } while (0)
314 #define WRITE_HTTP_PAYLOAD_FIELD_UUID(payload, type, uuid) \
315 do { \
316 *(unsigned int *)(payload) = (type); \
317 (payload) += 4; \
318 *(UUID *)(payload) = (uuid); \
319 (payload) += sizeof(UUID); \
320 } while (0)
322 #define WRITE_HTTP_PAYLOAD_FIELD_FLOW_CONTROL(payload, bytes_transmitted, flow_control_increment, uuid) \
323 do { \
324 *(unsigned int *)(payload) = 0x00000001; \
325 (payload) += 4; \
326 *(unsigned int *)(payload) = (bytes_transmitted); \
327 (payload) += 4; \
328 *(unsigned int *)(payload) = (flow_control_increment); \
329 (payload) += 4; \
330 *(UUID *)(payload) = (uuid); \
331 (payload) += sizeof(UUID); \
332 } while (0)
334 RpcPktHdr *RPCRT4_BuildHttpConnectHeader(unsigned short flags, int out_pipe,
335 const UUID *connection_uuid,
336 const UUID *pipe_uuid)
338 RpcPktHdr *header;
339 unsigned int size;
340 char *payload;
342 size = 8 + 4 + sizeof(UUID) + 4 + sizeof(UUID) + 8;
343 if (!out_pipe)
344 size += 8 + 4 + sizeof(UUID);
346 header = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, flags,
347 out_pipe ? 4 : 6, size);
348 if (!header) return NULL;
349 payload = (char *)(&header->http+1);
351 /* FIXME: what does this part of the payload do? */
352 WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x00000006, 0x00000001);
354 WRITE_HTTP_PAYLOAD_FIELD_UUID(payload, 0x00000003, *connection_uuid);
355 WRITE_HTTP_PAYLOAD_FIELD_UUID(payload, 0x00000003, *pipe_uuid);
357 if (out_pipe)
358 /* FIXME: what does this part of the payload do? */
359 WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x00000000, 0x00010000);
360 else
362 UUID unknown_uuid;
364 /* FIXME: what does this part of the payload do? */
365 WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x00000004, 0x40000000);
366 /* FIXME: what does this part of the payload do? */
367 WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x00000005, 0x000493e0);
369 UuidCreate(&unknown_uuid);
370 WRITE_HTTP_PAYLOAD_FIELD_UUID(payload, 0x0000000c, unknown_uuid);
373 return header;
376 RpcPktHdr *RPCRT4_BuildHttpFlowControlHeader(BOOL server, ULONG bytes_transmitted,
377 ULONG flow_control_increment,
378 const UUID *pipe_uuid)
380 RpcPktHdr *header;
381 char *payload;
383 header = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, 0x2, 2,
384 5 * sizeof(ULONG) + sizeof(UUID));
385 if (!header) return NULL;
386 payload = (char *)(&header->http+1);
388 WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x0000000d, (server ? 0x0 : 0x3));
390 WRITE_HTTP_PAYLOAD_FIELD_FLOW_CONTROL(payload, bytes_transmitted,
391 flow_control_increment, *pipe_uuid);
392 return header;
395 VOID RPCRT4_FreeHeader(RpcPktHdr *Header)
397 HeapFree(GetProcessHeap(), 0, Header);
401 /* assumes the common header fields have already been validated */
402 BOOL RPCRT4_IsValidHttpPacket(RpcPktHdr *hdr, unsigned char *data,
403 unsigned short data_len)
405 unsigned short i;
406 BYTE *p = data;
408 for (i = 0; i < hdr->http.num_data_items; i++)
410 ULONG type;
412 if (data_len < sizeof(ULONG))
413 return FALSE;
415 type = *(ULONG *)p;
416 p += sizeof(ULONG);
417 data_len -= sizeof(ULONG);
419 switch (type)
421 case 0x3:
422 case 0xc:
423 if (data_len < sizeof(GUID))
424 return FALSE;
425 p += sizeof(GUID);
426 data_len -= sizeof(GUID);
427 break;
428 case 0x0:
429 case 0x2:
430 case 0x4:
431 case 0x5:
432 case 0x6:
433 case 0xd:
434 if (data_len < sizeof(ULONG))
435 return FALSE;
436 p += sizeof(ULONG);
437 data_len -= sizeof(ULONG);
438 break;
439 case 0x1:
440 if (data_len < 24)
441 return FALSE;
442 p += 24;
443 data_len -= 24;
444 break;
445 default:
446 FIXME("unimplemented type 0x%x\n", type);
447 break;
450 return TRUE;
453 /* assumes the HTTP packet has been validated */
454 unsigned char *RPCRT4_NextHttpHeaderField(unsigned char *data)
456 ULONG type;
458 type = *(ULONG *)data;
459 data += sizeof(ULONG);
461 switch (type)
463 case 0x3:
464 case 0xc:
465 return data + sizeof(GUID);
466 case 0x0:
467 case 0x2:
468 case 0x4:
469 case 0x5:
470 case 0x6:
471 case 0xd:
472 return data + sizeof(ULONG);
473 case 0x1:
474 return data + 24;
475 default:
476 FIXME("unimplemented type 0x%x\n", type);
477 return data;
481 #define READ_HTTP_PAYLOAD_FIELD_TYPE(data) *(ULONG *)(data)
482 #define GET_HTTP_PAYLOAD_FIELD_DATA(data) ((data) + sizeof(ULONG))
484 /* assumes the HTTP packet has been validated */
485 RPC_STATUS RPCRT4_ParseHttpPrepareHeader1(RpcPktHdr *header,
486 unsigned char *data, ULONG *field1)
488 ULONG type;
489 if (header->http.flags != 0x0)
491 ERR("invalid flags 0x%x\n", header->http.flags);
492 return RPC_S_PROTOCOL_ERROR;
494 if (header->http.num_data_items != 1)
496 ERR("invalid number of data items %d\n", header->http.num_data_items);
497 return RPC_S_PROTOCOL_ERROR;
499 type = READ_HTTP_PAYLOAD_FIELD_TYPE(data);
500 if (type != 0x00000002)
502 ERR("invalid type 0x%08x\n", type);
503 return RPC_S_PROTOCOL_ERROR;
505 *field1 = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data);
506 return RPC_S_OK;
509 /* assumes the HTTP packet has been validated */
510 RPC_STATUS RPCRT4_ParseHttpPrepareHeader2(RpcPktHdr *header,
511 unsigned char *data, ULONG *field1,
512 ULONG *bytes_until_next_packet,
513 ULONG *field3)
515 ULONG type;
516 if (header->http.flags != 0x0)
518 ERR("invalid flags 0x%x\n", header->http.flags);
519 return RPC_S_PROTOCOL_ERROR;
521 if (header->http.num_data_items != 3)
523 ERR("invalid number of data items %d\n", header->http.num_data_items);
524 return RPC_S_PROTOCOL_ERROR;
527 type = READ_HTTP_PAYLOAD_FIELD_TYPE(data);
528 if (type != 0x00000006)
530 ERR("invalid type for field 1: 0x%08x\n", type);
531 return RPC_S_PROTOCOL_ERROR;
533 *field1 = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data);
534 data = RPCRT4_NextHttpHeaderField(data);
536 type = READ_HTTP_PAYLOAD_FIELD_TYPE(data);
537 if (type != 0x00000000)
539 ERR("invalid type for field 2: 0x%08x\n", type);
540 return RPC_S_PROTOCOL_ERROR;
542 *bytes_until_next_packet = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data);
543 data = RPCRT4_NextHttpHeaderField(data);
545 type = READ_HTTP_PAYLOAD_FIELD_TYPE(data);
546 if (type != 0x00000002)
548 ERR("invalid type for field 3: 0x%08x\n", type);
549 return RPC_S_PROTOCOL_ERROR;
551 *field3 = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data);
553 return RPC_S_OK;
556 RPC_STATUS RPCRT4_ParseHttpFlowControlHeader(RpcPktHdr *header,
557 unsigned char *data, BOOL server,
558 ULONG *bytes_transmitted,
559 ULONG *flow_control_increment,
560 UUID *pipe_uuid)
562 ULONG type;
563 if (header->http.flags != 0x2)
565 ERR("invalid flags 0x%x\n", header->http.flags);
566 return RPC_S_PROTOCOL_ERROR;
568 if (header->http.num_data_items != 2)
570 ERR("invalid number of data items %d\n", header->http.num_data_items);
571 return RPC_S_PROTOCOL_ERROR;
574 type = READ_HTTP_PAYLOAD_FIELD_TYPE(data);
575 if (type != 0x0000000d)
577 ERR("invalid type for field 1: 0x%08x\n", type);
578 return RPC_S_PROTOCOL_ERROR;
580 if (*(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data) != (server ? 0x3 : 0x0))
582 ERR("invalid type for 0xd field data: 0x%08x\n", *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data));
583 return RPC_S_PROTOCOL_ERROR;
585 data = RPCRT4_NextHttpHeaderField(data);
587 type = READ_HTTP_PAYLOAD_FIELD_TYPE(data);
588 if (type != 0x00000001)
590 ERR("invalid type for field 2: 0x%08x\n", type);
591 return RPC_S_PROTOCOL_ERROR;
593 *bytes_transmitted = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data);
594 *flow_control_increment = *(ULONG *)(GET_HTTP_PAYLOAD_FIELD_DATA(data) + 4);
595 *pipe_uuid = *(UUID *)(GET_HTTP_PAYLOAD_FIELD_DATA(data) + 8);
597 return RPC_S_OK;
601 static RPC_STATUS RPCRT4_SecurePacket(RpcConnection *Connection,
602 enum secure_packet_direction dir,
603 RpcPktHdr *hdr, unsigned int hdr_size,
604 unsigned char *stub_data, unsigned int stub_data_size,
605 RpcAuthVerifier *auth_hdr,
606 unsigned char *auth_value, unsigned int auth_value_size)
608 SecBufferDesc message;
609 SecBuffer buffers[4];
610 SECURITY_STATUS sec_status;
612 message.ulVersion = SECBUFFER_VERSION;
613 message.cBuffers = sizeof(buffers)/sizeof(buffers[0]);
614 message.pBuffers = buffers;
616 buffers[0].cbBuffer = hdr_size;
617 buffers[0].BufferType = SECBUFFER_DATA|SECBUFFER_READONLY_WITH_CHECKSUM;
618 buffers[0].pvBuffer = hdr;
619 buffers[1].cbBuffer = stub_data_size;
620 buffers[1].BufferType = SECBUFFER_DATA;
621 buffers[1].pvBuffer = stub_data;
622 buffers[2].cbBuffer = sizeof(*auth_hdr);
623 buffers[2].BufferType = SECBUFFER_DATA|SECBUFFER_READONLY_WITH_CHECKSUM;
624 buffers[2].pvBuffer = auth_hdr;
625 buffers[3].cbBuffer = auth_value_size;
626 buffers[3].BufferType = SECBUFFER_TOKEN;
627 buffers[3].pvBuffer = auth_value;
629 if (dir == SECURE_PACKET_SEND)
631 if ((auth_hdr->auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) && packet_has_body(hdr))
633 sec_status = EncryptMessage(&Connection->ctx, 0, &message, 0 /* FIXME */);
634 if (sec_status != SEC_E_OK)
636 ERR("EncryptMessage failed with 0x%08x\n", sec_status);
637 return RPC_S_SEC_PKG_ERROR;
640 else if (auth_hdr->auth_level != RPC_C_AUTHN_LEVEL_NONE)
642 sec_status = MakeSignature(&Connection->ctx, 0, &message, 0 /* FIXME */);
643 if (sec_status != SEC_E_OK)
645 /* FIXME: hack - work around lack of MakeSignature support in
646 * the version of secur32 in CXOFFICE-6.0 */
648 memset(auth_value, 0, auth_value_size);
649 auth_value[0] = 1; /* version number lsb */
650 return RPC_S_OK;
653 ERR("MakeSignature failed with 0x%08x\n", sec_status);
654 return RPC_S_SEC_PKG_ERROR;
658 else if (dir == SECURE_PACKET_RECEIVE)
660 if ((auth_hdr->auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) && packet_has_body(hdr))
662 sec_status = DecryptMessage(&Connection->ctx, &message, 0 /* FIXME */, 0);
663 if (sec_status != SEC_E_OK)
665 ERR("EncryptMessage failed with 0x%08x\n", sec_status);
666 return RPC_S_SEC_PKG_ERROR;
669 else if (auth_hdr->auth_level != RPC_C_AUTHN_LEVEL_NONE)
671 sec_status = VerifySignature(&Connection->ctx, &message, 0 /* FIXME */, NULL);
672 if (sec_status != SEC_E_OK)
674 ERR("VerifySignature failed with 0x%08x\n", sec_status);
675 return RPC_S_SEC_PKG_ERROR;
680 return RPC_S_OK;
683 /***********************************************************************
684 * RPCRT4_SendAuth (internal)
686 * Transmit a packet with authorization data over connection in acceptable fragments.
688 static RPC_STATUS RPCRT4_SendAuth(RpcConnection *Connection, RpcPktHdr *Header,
689 void *Buffer, unsigned int BufferLength,
690 void *Auth, unsigned int AuthLength)
692 PUCHAR buffer_pos;
693 DWORD hdr_size;
694 LONG count;
695 unsigned char *pkt;
696 LONG alen;
697 RPC_STATUS status;
699 buffer_pos = Buffer;
700 /* The packet building functions save the packet header size, so we can use it. */
701 hdr_size = Header->common.frag_len;
702 if (AuthLength)
703 Header->common.auth_len = AuthLength;
704 else if (Connection->AuthInfo && packet_has_auth_verifier(Header))
706 if ((Connection->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) && packet_has_body(Header))
707 Header->common.auth_len = Connection->encryption_auth_len;
708 else
709 Header->common.auth_len = Connection->signature_auth_len;
711 else
712 Header->common.auth_len = 0;
713 Header->common.flags |= RPC_FLG_FIRST;
714 Header->common.flags &= ~RPC_FLG_LAST;
716 alen = RPC_AUTH_VERIFIER_LEN(&Header->common);
718 while (!(Header->common.flags & RPC_FLG_LAST)) {
719 unsigned char auth_pad_len = Header->common.auth_len ? ROUND_UP_AMOUNT(BufferLength, AUTH_ALIGNMENT) : 0;
720 unsigned int pkt_size = BufferLength + hdr_size + alen + auth_pad_len;
722 /* decide if we need to split the packet into fragments */
723 if (pkt_size <= Connection->MaxTransmissionSize) {
724 Header->common.flags |= RPC_FLG_LAST;
725 Header->common.frag_len = pkt_size;
726 } else {
727 auth_pad_len = 0;
728 /* make sure packet payload will be a multiple of 16 */
729 Header->common.frag_len =
730 ((Connection->MaxTransmissionSize - hdr_size - alen) & ~(AUTH_ALIGNMENT-1)) +
731 hdr_size + alen;
734 pkt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Header->common.frag_len);
736 memcpy(pkt, Header, hdr_size);
738 /* fragment consisted of header only and is the last one */
739 if (hdr_size == Header->common.frag_len)
740 goto write;
742 memcpy(pkt + hdr_size, buffer_pos, Header->common.frag_len - hdr_size - auth_pad_len - alen);
744 /* add the authorization info */
745 if (Connection->AuthInfo && packet_has_auth_verifier(Header))
747 RpcAuthVerifier *auth_hdr = (RpcAuthVerifier *)&pkt[Header->common.frag_len - alen];
749 auth_hdr->auth_type = Connection->AuthInfo->AuthnSvc;
750 auth_hdr->auth_level = Connection->AuthInfo->AuthnLevel;
751 auth_hdr->auth_pad_length = auth_pad_len;
752 auth_hdr->auth_reserved = 0;
753 /* a unique number... */
754 auth_hdr->auth_context_id = (unsigned long)Connection;
756 if (AuthLength)
757 memcpy(auth_hdr + 1, Auth, AuthLength);
758 else
760 status = RPCRT4_SecurePacket(Connection, SECURE_PACKET_SEND,
761 (RpcPktHdr *)pkt, hdr_size,
762 pkt + hdr_size, Header->common.frag_len - hdr_size - alen,
763 auth_hdr,
764 (unsigned char *)(auth_hdr + 1), Header->common.auth_len);
765 if (status != RPC_S_OK)
767 HeapFree(GetProcessHeap(), 0, pkt);
768 return status;
773 write:
774 count = rpcrt4_conn_write(Connection, pkt, Header->common.frag_len);
775 HeapFree(GetProcessHeap(), 0, pkt);
776 if (count<0) {
777 WARN("rpcrt4_conn_write failed (auth)\n");
778 return RPC_S_PROTOCOL_ERROR;
781 buffer_pos += Header->common.frag_len - hdr_size - alen - auth_pad_len;
782 BufferLength -= Header->common.frag_len - hdr_size - alen - auth_pad_len;
783 Header->common.flags &= ~RPC_FLG_FIRST;
786 return RPC_S_OK;
789 /***********************************************************************
790 * RPCRT4_ClientAuthorize (internal)
792 * Authorize a client connection. A NULL in param signifies a new connection.
794 static RPC_STATUS RPCRT4_ClientAuthorize(RpcConnection *conn, SecBuffer *in,
795 SecBuffer *out)
797 SECURITY_STATUS r;
798 SecBufferDesc out_desc;
799 SecBufferDesc inp_desc;
800 SecPkgContext_Sizes secctx_sizes;
801 BOOL continue_needed;
802 ULONG context_req = ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE |
803 ISC_REQ_MUTUAL_AUTH | ISC_REQ_DELEGATE;
805 if (conn->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
806 context_req |= ISC_REQ_INTEGRITY;
807 else if (conn->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
808 context_req |= ISC_REQ_CONFIDENTIALITY | ISC_REQ_INTEGRITY;
810 out->BufferType = SECBUFFER_TOKEN;
811 out->cbBuffer = conn->AuthInfo->cbMaxToken;
812 out->pvBuffer = HeapAlloc(GetProcessHeap(), 0, out->cbBuffer);
813 if (!out->pvBuffer) return ERROR_OUTOFMEMORY;
815 out_desc.ulVersion = 0;
816 out_desc.cBuffers = 1;
817 out_desc.pBuffers = out;
819 inp_desc.cBuffers = 1;
820 inp_desc.pBuffers = in;
821 inp_desc.ulVersion = 0;
823 r = InitializeSecurityContextA(&conn->AuthInfo->cred, in ? &conn->ctx : NULL,
824 NULL, context_req, 0, SECURITY_NETWORK_DREP,
825 in ? &inp_desc : NULL, 0, &conn->ctx, &out_desc, &conn->attr,
826 &conn->exp);
827 if (FAILED(r))
829 WARN("InitializeSecurityContext failed with error 0x%08x\n", r);
830 goto failed;
833 TRACE("r = 0x%08x, attr = 0x%08x\n", r, conn->attr);
834 continue_needed = ((r == SEC_I_CONTINUE_NEEDED) ||
835 (r == SEC_I_COMPLETE_AND_CONTINUE));
837 if ((r == SEC_I_COMPLETE_NEEDED) || (r == SEC_I_COMPLETE_AND_CONTINUE))
839 TRACE("complete needed\n");
840 r = CompleteAuthToken(&conn->ctx, &out_desc);
841 if (FAILED(r))
843 WARN("CompleteAuthToken failed with error 0x%08x\n", r);
844 goto failed;
848 TRACE("cbBuffer = %ld\n", out->cbBuffer);
850 if (!continue_needed)
852 r = QueryContextAttributesA(&conn->ctx, SECPKG_ATTR_SIZES, &secctx_sizes);
853 if (FAILED(r))
855 WARN("QueryContextAttributes failed with error 0x%08x\n", r);
856 goto failed;
858 conn->signature_auth_len = secctx_sizes.cbMaxSignature;
859 conn->encryption_auth_len = secctx_sizes.cbSecurityTrailer;
862 return RPC_S_OK;
864 failed:
865 HeapFree(GetProcessHeap(), 0, out->pvBuffer);
866 out->pvBuffer = NULL;
867 return ERROR_ACCESS_DENIED; /* FIXME: is this correct? */
870 /***********************************************************************
871 * RPCRT4_AuthorizeBinding (internal)
873 static RPC_STATUS RPCRT_AuthorizeConnection(RpcConnection* conn,
874 BYTE *challenge, ULONG count)
876 SecBuffer inp, out;
877 RpcPktHdr *resp_hdr;
878 RPC_STATUS status;
880 TRACE("challenge %s, %d bytes\n", challenge, count);
882 inp.BufferType = SECBUFFER_TOKEN;
883 inp.pvBuffer = challenge;
884 inp.cbBuffer = count;
886 status = RPCRT4_ClientAuthorize(conn, &inp, &out);
887 if (status) return status;
889 resp_hdr = RPCRT4_BuildAuthHeader(NDR_LOCAL_DATA_REPRESENTATION);
890 if (!resp_hdr)
891 return E_OUTOFMEMORY;
893 status = RPCRT4_SendAuth(conn, resp_hdr, NULL, 0, out.pvBuffer, out.cbBuffer);
895 HeapFree(GetProcessHeap(), 0, out.pvBuffer);
896 RPCRT4_FreeHeader(resp_hdr);
898 return status;
901 /***********************************************************************
902 * RPCRT4_Send (internal)
904 * Transmit a packet over connection in acceptable fragments.
906 RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header,
907 void *Buffer, unsigned int BufferLength)
909 RPC_STATUS r;
910 SecBuffer out;
912 if (!Connection->AuthInfo || SecIsValidHandle(&Connection->ctx))
914 return RPCRT4_SendAuth(Connection, Header, Buffer, BufferLength, NULL, 0);
917 /* tack on a negotiate packet */
918 RPCRT4_ClientAuthorize(Connection, NULL, &out);
919 r = RPCRT4_SendAuth(Connection, Header, Buffer, BufferLength, out.pvBuffer, out.cbBuffer);
920 HeapFree(GetProcessHeap(), 0, out.pvBuffer);
922 return r;
925 /***********************************************************************
926 * RPCRT4_Receive (internal)
928 * Receive a packet from connection and merge the fragments.
930 RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header,
931 PRPC_MESSAGE pMsg)
933 RPC_STATUS status;
934 DWORD hdr_length;
935 LONG dwRead;
936 unsigned short first_flag;
937 unsigned long data_length;
938 unsigned long buffer_length;
939 unsigned long auth_length;
940 unsigned char *auth_data = NULL;
941 RpcPktCommonHdr common_hdr;
943 *Header = NULL;
945 TRACE("(%p, %p, %p)\n", Connection, Header, pMsg);
947 /* read packet common header */
948 dwRead = rpcrt4_conn_read(Connection, &common_hdr, sizeof(common_hdr));
949 if (dwRead != sizeof(common_hdr)) {
950 WARN("Short read of header, %d bytes\n", dwRead);
951 status = RPC_S_PROTOCOL_ERROR;
952 goto fail;
955 /* verify if the header really makes sense */
956 if (common_hdr.rpc_ver != RPC_VER_MAJOR ||
957 common_hdr.rpc_ver_minor != RPC_VER_MINOR) {
958 WARN("unhandled packet version\n");
959 status = RPC_S_PROTOCOL_ERROR;
960 goto fail;
963 hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr);
964 if (hdr_length == 0) {
965 WARN("header length == 0\n");
966 status = RPC_S_PROTOCOL_ERROR;
967 goto fail;
970 *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length);
971 memcpy(*Header, &common_hdr, sizeof(common_hdr));
973 /* read the rest of packet header */
974 dwRead = rpcrt4_conn_read(Connection, &(*Header)->common + 1, hdr_length - sizeof(common_hdr));
975 if (dwRead != hdr_length - sizeof(common_hdr)) {
976 WARN("bad header length, %d bytes, hdr_length %d\n", dwRead, hdr_length);
977 status = RPC_S_PROTOCOL_ERROR;
978 goto fail;
981 /* read packet body */
982 switch (common_hdr.ptype) {
983 case PKT_RESPONSE:
984 pMsg->BufferLength = (*Header)->response.alloc_hint;
985 break;
986 case PKT_REQUEST:
987 pMsg->BufferLength = (*Header)->request.alloc_hint;
988 break;
989 default:
990 pMsg->BufferLength = common_hdr.frag_len - hdr_length - RPC_AUTH_VERIFIER_LEN(&common_hdr);
993 TRACE("buffer length = %u\n", pMsg->BufferLength);
995 status = I_RpcGetBuffer(pMsg);
996 if (status != RPC_S_OK) goto fail;
998 first_flag = RPC_FLG_FIRST;
999 auth_length = common_hdr.auth_len;
1000 if (auth_length) {
1001 auth_data = HeapAlloc(GetProcessHeap(), 0, RPC_AUTH_VERIFIER_LEN(&common_hdr));
1002 if (!auth_data) {
1003 status = RPC_S_PROTOCOL_ERROR;
1004 goto fail;
1007 buffer_length = 0;
1008 while (TRUE)
1010 unsigned int header_auth_len = RPC_AUTH_VERIFIER_LEN(&(*Header)->common);
1012 /* verify header fields */
1014 if (((*Header)->common.frag_len < hdr_length) ||
1015 ((*Header)->common.frag_len - hdr_length < header_auth_len)) {
1016 WARN("frag_len %d too small for hdr_length %d and auth_len %d\n",
1017 common_hdr.frag_len, hdr_length, common_hdr.auth_len);
1018 status = RPC_S_PROTOCOL_ERROR;
1019 goto fail;
1022 if ((*Header)->common.auth_len != auth_length) {
1023 WARN("auth_len header field changed from %ld to %d\n",
1024 auth_length, (*Header)->common.auth_len);
1025 status = RPC_S_PROTOCOL_ERROR;
1026 goto fail;
1029 if (((*Header)->common.flags & RPC_FLG_FIRST) != first_flag) {
1030 TRACE("invalid packet flags\n");
1031 status = RPC_S_PROTOCOL_ERROR;
1032 goto fail;
1035 data_length = (*Header)->common.frag_len - hdr_length - header_auth_len;
1036 if (data_length + buffer_length > pMsg->BufferLength) {
1037 TRACE("allocation hint exceeded, new buffer length = %ld\n",
1038 data_length + buffer_length);
1039 pMsg->BufferLength = data_length + buffer_length;
1040 status = I_RpcReAllocateBuffer(pMsg);
1041 if (status != RPC_S_OK) goto fail;
1044 if (data_length == 0) dwRead = 0; else
1045 dwRead = rpcrt4_conn_read(Connection,
1046 (unsigned char *)pMsg->Buffer + buffer_length, data_length);
1047 if (dwRead != data_length) {
1048 WARN("bad data length, %d/%ld\n", dwRead, data_length);
1049 status = RPC_S_PROTOCOL_ERROR;
1050 goto fail;
1053 if (header_auth_len) {
1054 if (header_auth_len < sizeof(RpcAuthVerifier)) {
1055 WARN("bad auth verifier length %d\n", header_auth_len);
1056 status = RPC_S_PROTOCOL_ERROR;
1057 goto fail;
1060 /* FIXME: we should accumulate authentication data for the bind,
1061 * bind_ack, alter_context and alter_context_response if necessary.
1062 * however, the details of how this is done is very sketchy in the
1063 * DCE/RPC spec. for all other packet types that have authentication
1064 * verifier data then it is just duplicated in all the fragments */
1065 dwRead = rpcrt4_conn_read(Connection, auth_data, header_auth_len);
1066 if (dwRead != header_auth_len) {
1067 WARN("bad authentication data length, %d/%d\n", dwRead,
1068 header_auth_len);
1069 status = RPC_S_PROTOCOL_ERROR;
1070 goto fail;
1073 /* these packets are handled specially, not by the generic SecurePacket
1074 * function */
1075 if ((common_hdr.ptype != PKT_BIND) &&
1076 (common_hdr.ptype != PKT_BIND_ACK) &&
1077 (common_hdr.ptype != PKT_AUTH3))
1078 status = RPCRT4_SecurePacket(Connection, SECURE_PACKET_RECEIVE,
1079 *Header, hdr_length,
1080 (unsigned char *)pMsg->Buffer + buffer_length, data_length,
1081 (RpcAuthVerifier *)auth_data,
1082 (unsigned char *)auth_data + sizeof(RpcAuthVerifier),
1083 header_auth_len - sizeof(RpcAuthVerifier));
1086 buffer_length += data_length;
1087 if (!((*Header)->common.flags & RPC_FLG_LAST)) {
1088 TRACE("next header\n");
1090 /* read the header of next packet */
1091 dwRead = rpcrt4_conn_read(Connection, *Header, hdr_length);
1092 if (dwRead != hdr_length) {
1093 WARN("invalid packet header size (%d)\n", dwRead);
1094 status = RPC_S_PROTOCOL_ERROR;
1095 goto fail;
1098 first_flag = 0;
1099 } else {
1100 break;
1103 pMsg->BufferLength = buffer_length;
1105 /* respond to authorization request */
1106 if (common_hdr.ptype == PKT_BIND_ACK && auth_length > sizeof(RpcAuthVerifier))
1108 status = RPCRT_AuthorizeConnection(Connection,
1109 auth_data + sizeof(RpcAuthVerifier),
1110 auth_length);
1111 if (status)
1112 goto fail;
1115 /* success */
1116 status = RPC_S_OK;
1118 fail:
1119 if (status != RPC_S_OK) {
1120 RPCRT4_FreeHeader(*Header);
1121 *Header = NULL;
1123 HeapFree(GetProcessHeap(), 0, auth_data);
1124 return status;
1127 /***********************************************************************
1128 * I_RpcGetBuffer [RPCRT4.@]
1130 * Allocates a buffer for use by I_RpcSend or I_RpcSendReceive and binds to the
1131 * server interface.
1133 * PARAMS
1134 * pMsg [I/O] RPC message information.
1136 * RETURNS
1137 * Success: RPC_S_OK.
1138 * Failure: RPC_S_INVALID_BINDING if pMsg->Handle is invalid.
1139 * RPC_S_SERVER_UNAVAILABLE if unable to connect to server.
1140 * ERROR_OUTOFMEMORY if buffer allocation failed.
1142 * NOTES
1143 * The pMsg->BufferLength field determines the size of the buffer to allocate,
1144 * in bytes.
1146 * Use I_RpcFreeBuffer() to unbind from the server and free the message buffer.
1148 * SEE ALSO
1149 * I_RpcFreeBuffer(), I_RpcSend(), I_RpcReceive(), I_RpcSendReceive().
1151 RPC_STATUS WINAPI I_RpcGetBuffer(PRPC_MESSAGE pMsg)
1153 TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength);
1154 /* FIXME: pfnAllocate? */
1155 pMsg->Buffer = HeapAlloc(GetProcessHeap(), 0, pMsg->BufferLength);
1157 TRACE("Buffer=%p\n", pMsg->Buffer);
1158 /* FIXME: which errors to return? */
1159 return pMsg->Buffer ? S_OK : E_OUTOFMEMORY;
1162 /***********************************************************************
1163 * I_RpcReAllocateBuffer (internal)
1165 static RPC_STATUS I_RpcReAllocateBuffer(PRPC_MESSAGE pMsg)
1167 TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength);
1168 pMsg->Buffer = HeapReAlloc(GetProcessHeap(), 0, pMsg->Buffer, pMsg->BufferLength);
1170 TRACE("Buffer=%p\n", pMsg->Buffer);
1171 return pMsg->Buffer ? RPC_S_OK : RPC_S_OUT_OF_RESOURCES;
1174 /***********************************************************************
1175 * I_RpcFreeBuffer [RPCRT4.@]
1177 * Frees a buffer allocated by I_RpcGetBuffer or I_RpcReceive and unbinds from
1178 * the server interface.
1180 * PARAMS
1181 * pMsg [I/O] RPC message information.
1183 * RETURNS
1184 * RPC_S_OK.
1186 * SEE ALSO
1187 * I_RpcGetBuffer(), I_RpcReceive().
1189 RPC_STATUS WINAPI I_RpcFreeBuffer(PRPC_MESSAGE pMsg)
1191 TRACE("(%p) Buffer=%p\n", pMsg, pMsg->Buffer);
1192 /* FIXME: pfnFree? */
1193 HeapFree(GetProcessHeap(), 0, pMsg->Buffer);
1194 pMsg->Buffer = NULL;
1195 return S_OK;
1198 /***********************************************************************
1199 * I_RpcSend [RPCRT4.@]
1201 * Sends a message to the server.
1203 * PARAMS
1204 * pMsg [I/O] RPC message information.
1206 * RETURNS
1207 * Unknown.
1209 * NOTES
1210 * The buffer must have been allocated with I_RpcGetBuffer().
1212 * SEE ALSO
1213 * I_RpcGetBuffer(), I_RpcReceive(), I_RpcSendReceive().
1215 RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg)
1217 RpcBinding* bind = (RpcBinding*)pMsg->Handle;
1218 RpcConnection* conn;
1219 RPC_CLIENT_INTERFACE* cif = NULL;
1220 RPC_SERVER_INTERFACE* sif = NULL;
1221 RPC_STATUS status;
1222 RpcPktHdr *hdr;
1224 TRACE("(%p)\n", pMsg);
1225 if (!bind) return RPC_S_INVALID_BINDING;
1227 if (bind->server) {
1228 sif = pMsg->RpcInterfaceInformation;
1229 if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */
1230 status = RPCRT4_OpenBinding(bind, &conn, &sif->TransferSyntax,
1231 &sif->InterfaceId);
1232 } else {
1233 cif = pMsg->RpcInterfaceInformation;
1234 if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */
1236 if (!bind->Endpoint || !bind->Endpoint[0])
1238 TRACE("automatically resolving partially bound binding\n");
1239 status = RpcEpResolveBinding(bind, cif);
1240 if (status != RPC_S_OK) return status;
1243 status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax,
1244 &cif->InterfaceId);
1247 if (status != RPC_S_OK) return status;
1249 if (bind->server) {
1250 if (pMsg->RpcFlags & WINE_RPCFLAG_EXCEPTION) {
1251 hdr = RPCRT4_BuildFaultHeader(pMsg->DataRepresentation,
1252 RPC_S_CALL_FAILED);
1253 } else {
1254 hdr = RPCRT4_BuildResponseHeader(pMsg->DataRepresentation,
1255 pMsg->BufferLength);
1257 } else {
1258 hdr = RPCRT4_BuildRequestHeader(pMsg->DataRepresentation,
1259 pMsg->BufferLength, pMsg->ProcNum,
1260 &bind->ObjectUuid);
1261 hdr->common.call_id = conn->NextCallId++;
1264 status = RPCRT4_Send(conn, hdr, pMsg->Buffer, pMsg->BufferLength);
1266 RPCRT4_FreeHeader(hdr);
1268 /* success */
1269 if (!bind->server) {
1270 /* save the connection, so the response can be read from it */
1271 pMsg->ReservedForRuntime = conn;
1272 return status;
1274 RPCRT4_CloseBinding(bind, conn);
1276 return status;
1279 /***********************************************************************
1280 * I_RpcReceive [RPCRT4.@]
1282 RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg)
1284 RpcBinding* bind = (RpcBinding*)pMsg->Handle;
1285 RpcConnection* conn;
1286 RPC_CLIENT_INTERFACE* cif = NULL;
1287 RPC_SERVER_INTERFACE* sif = NULL;
1288 RPC_STATUS status;
1289 RpcPktHdr *hdr = NULL;
1291 TRACE("(%p)\n", pMsg);
1292 if (!bind) return RPC_S_INVALID_BINDING;
1294 if (pMsg->ReservedForRuntime) {
1295 conn = pMsg->ReservedForRuntime;
1296 pMsg->ReservedForRuntime = NULL;
1297 } else {
1298 if (bind->server) {
1299 sif = pMsg->RpcInterfaceInformation;
1300 if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */
1301 status = RPCRT4_OpenBinding(bind, &conn, &sif->TransferSyntax,
1302 &sif->InterfaceId);
1303 } else {
1304 cif = pMsg->RpcInterfaceInformation;
1305 if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */
1307 if (!bind->Endpoint || !bind->Endpoint[0])
1309 TRACE("automatically resolving partially bound binding\n");
1310 status = RpcEpResolveBinding(bind, cif);
1311 if (status != RPC_S_OK) return status;
1314 status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax,
1315 &cif->InterfaceId);
1317 if (status != RPC_S_OK) return status;
1320 receive:
1321 status = RPCRT4_Receive(conn, &hdr, pMsg);
1322 if (status != RPC_S_OK) {
1323 WARN("receive failed with error %lx\n", status);
1324 goto fail;
1327 status = RPC_S_PROTOCOL_ERROR;
1329 switch (hdr->common.ptype) {
1330 case PKT_RESPONSE:
1331 if (bind->server) goto fail;
1332 break;
1333 case PKT_REQUEST:
1334 if (!bind->server) goto fail;
1335 break;
1336 case PKT_FAULT:
1337 pMsg->RpcFlags |= WINE_RPCFLAG_EXCEPTION;
1338 ERR ("we got fault packet with status 0x%lx\n", hdr->fault.status);
1339 status = hdr->fault.status; /* FIXME: do translation from nca error codes */
1340 /* FIXME: hack - only translates one nca error code */
1341 if (status == 0x1c010002)
1342 status = RPC_S_PROCNUM_OUT_OF_RANGE;
1343 goto fail;
1344 case PKT_HTTP:
1345 if (!RPCRT4_IsValidHttpPacket(hdr, pMsg->Buffer, pMsg->BufferLength))
1347 ERR("invalid http packet of length %d bytes\n", hdr->common.frag_len);
1348 goto fail;
1350 if (hdr->http.flags == 0x0001)
1352 TRACE("http idle packet, waiting for real packet\n");
1353 if (hdr->http.num_data_items != 0)
1355 ERR("HTTP idle packet should have no data items instead of %d\n", hdr->http.num_data_items);
1356 goto fail;
1359 else if (hdr->http.flags == 0x0002)
1361 ULONG bytes_transmitted;
1362 ULONG flow_control_increment;
1363 UUID pipe_uuid;
1364 status = RPCRT4_ParseHttpFlowControlHeader(hdr, pMsg->Buffer,
1365 bind->server,
1366 &bytes_transmitted,
1367 &flow_control_increment,
1368 &pipe_uuid);
1369 if (status != RPC_S_OK)
1370 goto fail;
1371 TRACE("received http flow control header (0x%x, 0x%x, %s)\n",
1372 bytes_transmitted, flow_control_increment, debugstr_guid(&pipe_uuid));
1373 /* FIXME: do something with parsed data */
1375 else
1377 FIXME("unrecognised http packet with flags 0x%04x\n", hdr->http.flags);
1378 goto fail;
1380 I_RpcFreeBuffer(pMsg);
1381 RPCRT4_FreeHeader(hdr);
1382 goto receive;
1383 default:
1384 WARN("bad packet type %d\n", hdr->common.ptype);
1385 goto fail;
1388 /* success */
1389 status = RPC_S_OK;
1391 fail:
1392 RPCRT4_FreeHeader(hdr);
1393 RPCRT4_CloseBinding(bind, conn);
1394 return status;
1397 /***********************************************************************
1398 * I_RpcSendReceive [RPCRT4.@]
1400 * Sends a message to the server and receives the response.
1402 * PARAMS
1403 * pMsg [I/O] RPC message information.
1405 * RETURNS
1406 * Success: RPC_S_OK.
1407 * Failure: Any error code.
1409 * NOTES
1410 * The buffer must have been allocated with I_RpcGetBuffer().
1412 * SEE ALSO
1413 * I_RpcGetBuffer(), I_RpcSend(), I_RpcReceive().
1415 RPC_STATUS WINAPI I_RpcSendReceive(PRPC_MESSAGE pMsg)
1417 RPC_STATUS status;
1418 RPC_MESSAGE original_message;
1420 TRACE("(%p)\n", pMsg);
1422 original_message = *pMsg;
1423 status = I_RpcSend(pMsg);
1424 if (status == RPC_S_OK)
1425 status = I_RpcReceive(pMsg);
1426 /* free the buffer replaced by a new buffer in I_RpcReceive */
1427 if (status == RPC_S_OK)
1428 I_RpcFreeBuffer(&original_message);
1429 return status;