rpcrt4: Correctly align the results in the RPC Bind Ack packet.
[wine] / dlls / rpcrt4 / rpc_message.c
1 /*
2  * RPC messages
3  *
4  * Copyright 2001-2002 Ove Kåven, TransGaming Technologies
5  * Copyright 2004 Filip Navara
6  * Copyright 2006 CodeWeavers
7  *
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.
12  *
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.
17  *
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
21  */
22
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winerror.h"
30 #include "winreg.h"
31
32 #include "rpc.h"
33 #include "rpcndr.h"
34 #include "rpcdcep.h"
35
36 #include "wine/debug.h"
37
38 #include "rpc_binding.h"
39 #include "rpc_misc.h"
40 #include "rpc_defs.h"
41 #include "rpc_message.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
44
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
48
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))
53
54 static RPC_STATUS I_RpcReAllocateBuffer(PRPC_MESSAGE pMsg);
55
56 static DWORD RPCRT4_GetHeaderSize(RpcPktHdr *Header)
57 {
58   static const DWORD header_sizes[] = {
59     sizeof(Header->request), 0, sizeof(Header->response),
60     sizeof(Header->fault), 0, 0, 0, 0, 0, 0, 0, sizeof(Header->bind),
61     sizeof(Header->bind_ack), sizeof(Header->bind_nack),
62     0, 0, 0, 0, 0
63   };
64   ULONG ret = 0;
65   
66   if (Header->common.ptype < sizeof(header_sizes) / sizeof(header_sizes[0])) {
67     ret = header_sizes[Header->common.ptype];
68     if (ret == 0)
69       FIXME("unhandled packet type\n");
70     if (Header->common.flags & RPC_FLG_OBJECT_UUID)
71       ret += sizeof(UUID);
72   } else {
73     TRACE("invalid packet type\n");
74   }
75
76   return ret;
77 }
78
79 static VOID RPCRT4_BuildCommonHeader(RpcPktHdr *Header, unsigned char PacketType,
80                               unsigned long DataRepresentation)
81 {
82   Header->common.rpc_ver = RPC_VER_MAJOR;
83   Header->common.rpc_ver_minor = RPC_VER_MINOR;
84   Header->common.ptype = PacketType;
85   Header->common.drep[0] = LOBYTE(LOWORD(DataRepresentation));
86   Header->common.drep[1] = HIBYTE(LOWORD(DataRepresentation));
87   Header->common.drep[2] = LOBYTE(HIWORD(DataRepresentation));
88   Header->common.drep[3] = HIBYTE(HIWORD(DataRepresentation));
89   Header->common.auth_len = 0;
90   Header->common.call_id = 1;
91   Header->common.flags = 0;
92   /* Flags and fragment length are computed in RPCRT4_Send. */
93 }                              
94
95 static RpcPktHdr *RPCRT4_BuildRequestHeader(unsigned long DataRepresentation,
96                                      unsigned long BufferLength,
97                                      unsigned short ProcNum,
98                                      UUID *ObjectUuid)
99 {
100   RpcPktHdr *header;
101   BOOL has_object;
102   RPC_STATUS status;
103
104   has_object = (ObjectUuid != NULL && !UuidIsNil(ObjectUuid, &status));
105   header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
106                      sizeof(header->request) + (has_object ? sizeof(UUID) : 0));
107   if (header == NULL) {
108     return NULL;
109   }
110
111   RPCRT4_BuildCommonHeader(header, PKT_REQUEST, DataRepresentation);
112   header->common.frag_len = sizeof(header->request);
113   header->request.alloc_hint = BufferLength;
114   header->request.context_id = 0;
115   header->request.opnum = ProcNum;
116   if (has_object) {
117     header->common.flags |= RPC_FLG_OBJECT_UUID;
118     header->common.frag_len += sizeof(UUID);
119     memcpy(&header->request + 1, ObjectUuid, sizeof(UUID));
120   }
121
122   return header;
123 }
124
125 static RpcPktHdr *RPCRT4_BuildResponseHeader(unsigned long DataRepresentation,
126                                       unsigned long BufferLength)
127 {
128   RpcPktHdr *header;
129
130   header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->response));
131   if (header == NULL) {
132     return NULL;
133   }
134
135   RPCRT4_BuildCommonHeader(header, PKT_RESPONSE, DataRepresentation);
136   header->common.frag_len = sizeof(header->response);
137   header->response.alloc_hint = BufferLength;
138
139   return header;
140 }
141
142 RpcPktHdr *RPCRT4_BuildFaultHeader(unsigned long DataRepresentation,
143                                    RPC_STATUS Status)
144 {
145   RpcPktHdr *header;
146
147   header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->fault));
148   if (header == NULL) {
149     return NULL;
150   }
151
152   RPCRT4_BuildCommonHeader(header, PKT_FAULT, DataRepresentation);
153   header->common.frag_len = sizeof(header->fault);
154   header->fault.status = Status;
155
156   return header;
157 }
158
159 RpcPktHdr *RPCRT4_BuildBindHeader(unsigned long DataRepresentation,
160                                   unsigned short MaxTransmissionSize,
161                                   unsigned short MaxReceiveSize,
162                                   RPC_SYNTAX_IDENTIFIER *AbstractId,
163                                   RPC_SYNTAX_IDENTIFIER *TransferId)
164 {
165   RpcPktHdr *header;
166
167   header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->bind));
168   if (header == NULL) {
169     return NULL;
170   }
171
172   RPCRT4_BuildCommonHeader(header, PKT_BIND, DataRepresentation);
173   header->common.frag_len = sizeof(header->bind);
174   header->bind.max_tsize = MaxTransmissionSize;
175   header->bind.max_rsize = MaxReceiveSize;
176   header->bind.num_elements = 1;
177   header->bind.num_syntaxes = 1;
178   memcpy(&header->bind.abstract, AbstractId, sizeof(RPC_SYNTAX_IDENTIFIER));
179   memcpy(&header->bind.transfer, TransferId, sizeof(RPC_SYNTAX_IDENTIFIER));
180
181   return header;
182 }
183
184 RpcPktHdr *RPCRT4_BuildAuthHeader(unsigned long DataRepresentation)
185 {
186   RpcPktHdr *header;
187
188   header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
189                      sizeof(header->common) + 12);
190   if (header == NULL)
191     return NULL;
192
193   RPCRT4_BuildCommonHeader(header, PKT_AUTH3, DataRepresentation);
194   header->common.frag_len = 0x14;
195   header->common.auth_len = 0;
196
197   return header;
198 }
199
200 RpcPktHdr *RPCRT4_BuildBindNackHeader(unsigned long DataRepresentation,
201                                       unsigned char RpcVersion,
202                                       unsigned char RpcVersionMinor)
203 {
204   RpcPktHdr *header;
205
206   header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->bind_nack));
207   if (header == NULL) {
208     return NULL;
209   }
210
211   RPCRT4_BuildCommonHeader(header, PKT_BIND_NACK, DataRepresentation);
212   header->common.frag_len = sizeof(header->bind_nack);
213   header->bind_nack.protocols_count = 1;
214   header->bind_nack.protocols[0].rpc_ver = RpcVersion;
215   header->bind_nack.protocols[0].rpc_ver_minor = RpcVersionMinor;
216
217   return header;
218 }
219
220 RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation,
221                                      unsigned short MaxTransmissionSize,
222                                      unsigned short MaxReceiveSize,
223                                      LPSTR ServerAddress,
224                                      unsigned long Result,
225                                      unsigned long Reason,
226                                      RPC_SYNTAX_IDENTIFIER *TransferId)
227 {
228   RpcPktHdr *header;
229   unsigned long header_size;
230   RpcAddressString *server_address;
231   RpcResults *results;
232   RPC_SYNTAX_IDENTIFIER *transfer_id;
233
234   header_size = sizeof(header->bind_ack) +
235                 ROUND_UP(FIELD_OFFSET(RpcAddressString, string[strlen(ServerAddress) + 1]), 4) +
236                 sizeof(RpcResults) +
237                 sizeof(RPC_SYNTAX_IDENTIFIER);
238
239   header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, header_size);
240   if (header == NULL) {
241     return NULL;
242   }
243
244   RPCRT4_BuildCommonHeader(header, PKT_BIND_ACK, DataRepresentation);
245   header->common.frag_len = header_size;
246   header->bind_ack.max_tsize = MaxTransmissionSize;
247   header->bind_ack.max_rsize = MaxReceiveSize;
248   server_address = (RpcAddressString*)(&header->bind_ack + 1);
249   server_address->length = strlen(ServerAddress) + 1;
250   strcpy(server_address->string, ServerAddress);
251   /* results is 4-byte aligned */
252   results = (RpcResults*)((ULONG_PTR)server_address + ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4));
253   results->num_results = 1;
254   results->results[0].result = Result;
255   results->results[0].reason = Reason;
256   transfer_id = (RPC_SYNTAX_IDENTIFIER*)(results + 1);
257   memcpy(transfer_id, TransferId, sizeof(RPC_SYNTAX_IDENTIFIER));
258
259   return header;
260 }
261
262 VOID RPCRT4_FreeHeader(RpcPktHdr *Header)
263 {
264   HeapFree(GetProcessHeap(), 0, Header);
265 }
266
267 /***********************************************************************
268  *           RPCRT4_SendAuth (internal)
269  * 
270  * Transmit a packet with authorization data over connection in acceptable fragments.
271  */
272 static RPC_STATUS RPCRT4_SendAuth(RpcConnection *Connection, RpcPktHdr *Header,
273                                   void *Buffer, unsigned int BufferLength,
274                                   void *Auth, unsigned int AuthLength)
275 {
276   PUCHAR buffer_pos;
277   DWORD hdr_size;
278   LONG count;
279   unsigned char *pkt;
280   LONG alen = AuthLength ? (AuthLength + sizeof(RpcAuthVerifier)) : 0;
281
282   buffer_pos = Buffer;
283   /* The packet building functions save the packet header size, so we can use it. */
284   hdr_size = Header->common.frag_len;
285   Header->common.auth_len = AuthLength;
286   Header->common.flags |= RPC_FLG_FIRST;
287   Header->common.flags &= ~RPC_FLG_LAST;
288   while (!(Header->common.flags & RPC_FLG_LAST)) {
289     unsigned char auth_pad_len = AuthLength ? ROUND_UP_AMOUNT(BufferLength, AUTH_ALIGNMENT) : 0;
290     unsigned int pkt_size = BufferLength + hdr_size + alen + auth_pad_len;
291
292     /* decide if we need to split the packet into fragments */
293    if (pkt_size <= Connection->MaxTransmissionSize) {
294      Header->common.flags |= RPC_FLG_LAST;
295      Header->common.frag_len = pkt_size;
296     } else {
297       auth_pad_len = 0;
298       /* make sure packet payload will be a multiple of 16 */
299       Header->common.frag_len =
300         ((Connection->MaxTransmissionSize - hdr_size - alen) & ~(AUTH_ALIGNMENT-1)) +
301         hdr_size + alen;
302     }
303
304     pkt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Header->common.frag_len);
305
306     memcpy(pkt, Header, hdr_size);
307
308     /* fragment consisted of header only and is the last one */
309     if (hdr_size == Header->common.frag_len)
310       goto write;
311
312     memcpy(pkt + hdr_size, buffer_pos, Header->common.frag_len - hdr_size - auth_pad_len - alen);
313
314     /* add the authorization info */
315     if (Connection->AuthInfo && AuthLength)
316     {
317       RpcAuthVerifier *auth_hdr = (RpcAuthVerifier *)&pkt[Header->common.frag_len - alen];
318
319       auth_hdr->auth_type = Connection->AuthInfo->AuthnSvc;
320       auth_hdr->auth_level = Connection->AuthInfo->AuthnLevel;
321       auth_hdr->auth_pad_length = auth_pad_len;
322       auth_hdr->auth_reserved = 0;
323       /* a unique number... */
324       auth_hdr->auth_context_id = (unsigned long)Connection;
325
326       memcpy(auth_hdr + 1, Auth, AuthLength);
327     }
328
329 write:
330     count = rpcrt4_conn_write(Connection, pkt, Header->common.frag_len);
331     HeapFree(GetProcessHeap(), 0, pkt);
332     if (count<0) {
333       WARN("rpcrt4_conn_write failed (auth)\n");
334       return RPC_S_PROTOCOL_ERROR;
335     }
336
337     buffer_pos += Header->common.frag_len - hdr_size - alen - auth_pad_len;
338     BufferLength -= Header->common.frag_len - hdr_size - alen - auth_pad_len;
339     Header->common.flags &= ~RPC_FLG_FIRST;
340   }
341
342   return RPC_S_OK;
343 }
344
345 /***********************************************************************
346  *           RPCRT4_AuthNegotiate (internal)
347  */
348 static void RPCRT4_AuthNegotiate(RpcConnection *conn, SecBuffer *out)
349 {
350   SECURITY_STATUS r;
351   SecBufferDesc out_desc;
352   unsigned char *buffer;
353
354   buffer = HeapAlloc(GetProcessHeap(), 0, 0x100);
355
356   out->BufferType = SECBUFFER_TOKEN;
357   out->cbBuffer = 0x100;
358   out->pvBuffer = buffer;
359
360   out_desc.ulVersion = 0;
361   out_desc.cBuffers = 1;
362   out_desc.pBuffers = out;
363
364   conn->attr = 0;
365   conn->ctx.dwLower = 0;
366   conn->ctx.dwUpper = 0;
367
368   r = InitializeSecurityContextA(&conn->AuthInfo->cred, NULL, NULL,
369         ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE | ISC_REQ_MUTUAL_AUTH |
370         ISC_REQ_DELEGATE, 0, SECURITY_NETWORK_DREP,
371         NULL, 0, &conn->ctx, &out_desc, &conn->attr, &conn->exp);
372
373   TRACE("r = %08x cbBuffer = %ld attr = %08x\n", r, out->cbBuffer, conn->attr);
374 }
375
376 /***********************************************************************
377  *           RPCRT4_AuthorizeBinding (internal)
378  */
379 static RPC_STATUS RPCRT_AuthorizeConnection(RpcConnection* conn,
380                                             BYTE *challenge, ULONG count)
381 {
382   SecBufferDesc inp_desc, out_desc;
383   SecBuffer inp, out;
384   SECURITY_STATUS r;
385   unsigned char buffer[0x100];
386   RpcPktHdr *resp_hdr;
387   RPC_STATUS status;
388
389   TRACE("challenge %s, %d bytes\n", challenge, count);
390
391   out.BufferType = SECBUFFER_TOKEN;
392   out.cbBuffer = sizeof buffer;
393   out.pvBuffer = buffer;
394
395   out_desc.ulVersion = 0;
396   out_desc.cBuffers = 1;
397   out_desc.pBuffers = &out;
398
399   inp.BufferType = SECBUFFER_TOKEN;
400   inp.pvBuffer = challenge;
401   inp.cbBuffer = count;
402
403   inp_desc.cBuffers = 1;
404   inp_desc.pBuffers = &inp;
405   inp_desc.ulVersion = 0;
406
407   r = InitializeSecurityContextA(&conn->AuthInfo->cred, &conn->ctx, NULL,
408         ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE | ISC_REQ_MUTUAL_AUTH |
409         ISC_REQ_DELEGATE, 0, SECURITY_NETWORK_DREP,
410         &inp_desc, 0, &conn->ctx, &out_desc, &conn->attr, &conn->exp);
411   if (r)
412   {
413     WARN("InitializeSecurityContext failed with error 0x%08x\n", r);
414     return ERROR_ACCESS_DENIED;
415   }
416
417   resp_hdr = RPCRT4_BuildAuthHeader(NDR_LOCAL_DATA_REPRESENTATION);
418   if (!resp_hdr)
419     return E_OUTOFMEMORY;
420
421   status = RPCRT4_SendAuth(conn, resp_hdr, NULL, 0, out.pvBuffer, out.cbBuffer);
422
423   RPCRT4_FreeHeader(resp_hdr);
424
425   return status;
426 }
427
428 /***********************************************************************
429  *           RPCRT4_Send (internal)
430  * 
431  * Transmit a packet over connection in acceptable fragments.
432  */
433 RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header,
434                        void *Buffer, unsigned int BufferLength)
435 {
436   RPC_STATUS r;
437   SecBuffer out;
438
439   /* if we've already authenticated, just send the context */
440   if (Connection->ctx.dwUpper || Connection->ctx.dwLower)
441   {
442     unsigned char buffer[0x10];
443
444     memset(buffer, 0, sizeof buffer);
445     buffer[0] = 1; /* version number lsb */
446
447     return RPCRT4_SendAuth(Connection, Header, Buffer, BufferLength, buffer, sizeof buffer);
448   }
449
450   if (!Connection->AuthInfo ||
451       Connection->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_DEFAULT ||
452       Connection->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_NONE)
453   {
454     return RPCRT4_SendAuth(Connection, Header, Buffer, BufferLength, NULL, 0);
455   }
456
457   out.BufferType = SECBUFFER_TOKEN;
458   out.cbBuffer = 0;
459   out.pvBuffer = NULL;
460
461   /* tack on a negotiate packet */
462   RPCRT4_AuthNegotiate(Connection, &out);
463   r = RPCRT4_SendAuth(Connection, Header, Buffer, BufferLength, out.pvBuffer, out.cbBuffer);
464   HeapFree(GetProcessHeap(), 0, out.pvBuffer);
465
466   return r;
467 }
468
469 /***********************************************************************
470  *           RPCRT4_Receive (internal)
471  * 
472  * Receive a packet from connection and merge the fragments.
473  */
474 RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header,
475                           PRPC_MESSAGE pMsg)
476 {
477   RPC_STATUS status;
478   DWORD hdr_length;
479   LONG dwRead;
480   unsigned short first_flag;
481   unsigned long data_length;
482   unsigned long buffer_length;
483   unsigned long auth_length;
484   unsigned char *auth_data = NULL;
485   RpcPktCommonHdr common_hdr;
486
487   *Header = NULL;
488
489   TRACE("(%p, %p, %p)\n", Connection, Header, pMsg);
490
491   /* read packet common header */
492   dwRead = rpcrt4_conn_read(Connection, &common_hdr, sizeof(common_hdr));
493   if (dwRead != sizeof(common_hdr)) {
494     WARN("Short read of header, %d bytes\n", dwRead);
495     status = RPC_S_PROTOCOL_ERROR;
496     goto fail;
497   }
498
499   /* verify if the header really makes sense */
500   if (common_hdr.rpc_ver != RPC_VER_MAJOR ||
501       common_hdr.rpc_ver_minor != RPC_VER_MINOR) {
502     WARN("unhandled packet version\n");
503     status = RPC_S_PROTOCOL_ERROR;
504     goto fail;
505   }
506
507   hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr);
508   if (hdr_length == 0) {
509     WARN("header length == 0\n");
510     status = RPC_S_PROTOCOL_ERROR;
511     goto fail;
512   }
513
514   *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length);
515   memcpy(*Header, &common_hdr, sizeof(common_hdr));
516
517   /* read the rest of packet header */
518   dwRead = rpcrt4_conn_read(Connection, &(*Header)->common + 1, hdr_length - sizeof(common_hdr));
519   if (dwRead != hdr_length - sizeof(common_hdr)) {
520     WARN("bad header length, %d/%d bytes\n", dwRead, hdr_length - sizeof(common_hdr));
521     status = RPC_S_PROTOCOL_ERROR;
522     goto fail;
523   }
524
525   /* read packet body */
526   switch (common_hdr.ptype) {
527   case PKT_RESPONSE:
528     pMsg->BufferLength = (*Header)->response.alloc_hint;
529     break;
530   case PKT_REQUEST:
531     pMsg->BufferLength = (*Header)->request.alloc_hint;
532     break;
533   default:
534     pMsg->BufferLength = common_hdr.frag_len - hdr_length - RPC_AUTH_VERIFIER_LEN(&common_hdr);
535   }
536
537   TRACE("buffer length = %u\n", pMsg->BufferLength);
538
539   status = I_RpcGetBuffer(pMsg);
540   if (status != RPC_S_OK) goto fail;
541
542   first_flag = RPC_FLG_FIRST;
543   auth_length = common_hdr.auth_len;
544   if (auth_length) {
545     auth_data = HeapAlloc(GetProcessHeap(), 0, RPC_AUTH_VERIFIER_LEN(&common_hdr));
546     if (!auth_data) {
547       status = RPC_S_PROTOCOL_ERROR;
548       goto fail;
549     }
550   }
551   buffer_length = 0;
552   while (TRUE)
553   {
554     unsigned int header_auth_len = RPC_AUTH_VERIFIER_LEN(&(*Header)->common);
555
556     /* verify header fields */
557
558     if (((*Header)->common.frag_len < hdr_length) ||
559         ((*Header)->common.frag_len - hdr_length < header_auth_len)) {
560       WARN("frag_len %d too small for hdr_length %d and auth_len %d\n",
561         common_hdr.frag_len, hdr_length, common_hdr.auth_len);
562       status = RPC_S_PROTOCOL_ERROR;
563       goto fail;
564     }
565
566     if ((*Header)->common.auth_len != auth_length) {
567       WARN("auth_len header field changed from %ld to %d\n",
568         auth_length, (*Header)->common.auth_len);
569       status = RPC_S_PROTOCOL_ERROR;
570       goto fail;
571     }
572
573     if (((*Header)->common.flags & RPC_FLG_FIRST) != first_flag) {
574       TRACE("invalid packet flags\n");
575       status = RPC_S_PROTOCOL_ERROR;
576       goto fail;
577     }
578
579     data_length = (*Header)->common.frag_len - hdr_length - header_auth_len;
580     if (data_length + buffer_length > pMsg->BufferLength) {
581       TRACE("allocation hint exceeded, new buffer length = %ld\n",
582         data_length + buffer_length);
583       pMsg->BufferLength = data_length + buffer_length;
584       status = I_RpcReAllocateBuffer(pMsg);
585       if (status != RPC_S_OK) goto fail;
586     }
587
588     if (data_length == 0) dwRead = 0; else
589     dwRead = rpcrt4_conn_read(Connection,
590         (unsigned char *)pMsg->Buffer + buffer_length, data_length);
591     if (dwRead != data_length) {
592       WARN("bad data length, %d/%ld\n", dwRead, data_length);
593       status = RPC_S_PROTOCOL_ERROR;
594       goto fail;
595     }
596
597     if (header_auth_len) {
598       /* FIXME: we should accumulate authentication data for the bind,
599        * bind_ack, alter_context and alter_context_response if necessary.
600        * however, the details of how this is done is very sketchy in the
601        * DCE/RPC spec. for all other packet types that have authentication
602        * verifier data then it is just duplicated in all the fragments */
603       dwRead = rpcrt4_conn_read(Connection, auth_data, header_auth_len);
604       if (dwRead != header_auth_len) {
605         WARN("bad authentication data length, %d/%d\n", dwRead,
606           header_auth_len);
607         status = RPC_S_PROTOCOL_ERROR;
608         goto fail;
609       }
610     }
611
612     buffer_length += data_length;
613     if (!((*Header)->common.flags & RPC_FLG_LAST)) {
614       TRACE("next header\n");
615
616       /* read the header of next packet */
617       dwRead = rpcrt4_conn_read(Connection, *Header, hdr_length);
618       if (dwRead != hdr_length) {
619         WARN("invalid packet header size (%d)\n", dwRead);
620         status = RPC_S_PROTOCOL_ERROR;
621         goto fail;
622       }
623
624       first_flag = 0;
625     } else {
626       break;
627     }
628   }
629   pMsg->BufferLength = buffer_length;
630
631   /* respond to authorization request */
632   if (common_hdr.ptype == PKT_BIND_ACK && auth_length > sizeof(RpcAuthVerifier))
633   {
634     status = RPCRT_AuthorizeConnection(Connection,
635                                        auth_data + sizeof(RpcAuthVerifier),
636                                        auth_length);
637     if (status)
638         goto fail;
639   }
640
641   /* success */
642   status = RPC_S_OK;
643
644 fail:
645   if (status != RPC_S_OK) {
646     RPCRT4_FreeHeader(*Header);
647     *Header = NULL;
648   }
649   HeapFree(GetProcessHeap(), 0, auth_data);
650   return status;
651 }
652
653 /***********************************************************************
654  *           I_RpcGetBuffer [RPCRT4.@]
655  */
656 RPC_STATUS WINAPI I_RpcGetBuffer(PRPC_MESSAGE pMsg)
657 {
658   TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength);
659   /* FIXME: pfnAllocate? */
660   pMsg->Buffer = HeapAlloc(GetProcessHeap(), 0, pMsg->BufferLength);
661
662   TRACE("Buffer=%p\n", pMsg->Buffer);
663   /* FIXME: which errors to return? */
664   return pMsg->Buffer ? S_OK : E_OUTOFMEMORY;
665 }
666
667 /***********************************************************************
668  *           I_RpcReAllocateBuffer (internal)
669  */
670 static RPC_STATUS I_RpcReAllocateBuffer(PRPC_MESSAGE pMsg)
671 {
672   TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength);
673   pMsg->Buffer = HeapReAlloc(GetProcessHeap(), 0, pMsg->Buffer, pMsg->BufferLength);
674
675   TRACE("Buffer=%p\n", pMsg->Buffer);
676   return pMsg->Buffer ? RPC_S_OK : RPC_S_OUT_OF_RESOURCES;
677 }
678
679 /***********************************************************************
680  *           I_RpcFreeBuffer [RPCRT4.@]
681  */
682 RPC_STATUS WINAPI I_RpcFreeBuffer(PRPC_MESSAGE pMsg)
683 {
684   TRACE("(%p) Buffer=%p\n", pMsg, pMsg->Buffer);
685   /* FIXME: pfnFree? */
686   HeapFree(GetProcessHeap(), 0, pMsg->Buffer);
687   pMsg->Buffer = NULL;
688   return S_OK;
689 }
690
691 /***********************************************************************
692  *           I_RpcSend [RPCRT4.@]
693  */
694 RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg)
695 {
696   RpcBinding* bind = (RpcBinding*)pMsg->Handle;
697   RpcConnection* conn;
698   RPC_CLIENT_INTERFACE* cif = NULL;
699   RPC_SERVER_INTERFACE* sif = NULL;
700   RPC_STATUS status;
701   RpcPktHdr *hdr;
702
703   TRACE("(%p)\n", pMsg);
704   if (!bind) return RPC_S_INVALID_BINDING;
705
706   if (bind->server) {
707     sif = pMsg->RpcInterfaceInformation;
708     if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */
709     status = RPCRT4_OpenBinding(bind, &conn, &sif->TransferSyntax,
710                                 &sif->InterfaceId);
711   } else {
712     cif = pMsg->RpcInterfaceInformation;
713     if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */
714
715     if (!bind->Endpoint || !bind->Endpoint[0])
716     {
717       TRACE("automatically resolving partially bound binding\n");
718       status = RpcEpResolveBinding(bind, cif);
719       if (status != RPC_S_OK) return status;
720     }
721
722     status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax,
723                                 &cif->InterfaceId);
724   }
725
726   if (status != RPC_S_OK) return status;
727
728   if (bind->server) {
729     if (pMsg->RpcFlags & WINE_RPCFLAG_EXCEPTION) {
730       hdr = RPCRT4_BuildFaultHeader(pMsg->DataRepresentation,
731                                     RPC_S_CALL_FAILED);
732     } else {
733       hdr = RPCRT4_BuildResponseHeader(pMsg->DataRepresentation,
734                                        pMsg->BufferLength);
735     }
736   } else {
737     hdr = RPCRT4_BuildRequestHeader(pMsg->DataRepresentation,
738                                     pMsg->BufferLength, pMsg->ProcNum,
739                                     &bind->ObjectUuid);
740     hdr->common.call_id = conn->NextCallId++;
741   }
742
743   status = RPCRT4_Send(conn, hdr, pMsg->Buffer, pMsg->BufferLength);
744
745   RPCRT4_FreeHeader(hdr);
746
747   /* success */
748   if (!bind->server) {
749     /* save the connection, so the response can be read from it */
750     pMsg->ReservedForRuntime = conn;
751     return status;
752   }
753   RPCRT4_CloseBinding(bind, conn);
754
755   return status;
756 }
757
758 /***********************************************************************
759  *           I_RpcReceive [RPCRT4.@]
760  */
761 RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg)
762 {
763   RpcBinding* bind = (RpcBinding*)pMsg->Handle;
764   RpcConnection* conn;
765   RPC_CLIENT_INTERFACE* cif = NULL;
766   RPC_SERVER_INTERFACE* sif = NULL;
767   RPC_STATUS status;
768   RpcPktHdr *hdr = NULL;
769
770   TRACE("(%p)\n", pMsg);
771   if (!bind) return RPC_S_INVALID_BINDING;
772
773   if (pMsg->ReservedForRuntime) {
774     conn = pMsg->ReservedForRuntime;
775     pMsg->ReservedForRuntime = NULL;
776   } else {
777     if (bind->server) {
778       sif = pMsg->RpcInterfaceInformation;
779       if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */
780       status = RPCRT4_OpenBinding(bind, &conn, &sif->TransferSyntax,
781                                   &sif->InterfaceId);
782     } else {
783       cif = pMsg->RpcInterfaceInformation;
784       if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */
785
786       if (!bind->Endpoint || !bind->Endpoint[0])
787       {
788         TRACE("automatically resolving partially bound binding\n");
789         status = RpcEpResolveBinding(bind, cif);
790         if (status != RPC_S_OK) return status;
791       }
792
793       status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax,
794                                   &cif->InterfaceId);
795     }
796     if (status != RPC_S_OK) return status;
797   }
798
799   status = RPCRT4_Receive(conn, &hdr, pMsg);
800   if (status != RPC_S_OK) {
801     WARN("receive failed with error %lx\n", status);
802     goto fail;
803   }
804
805   status = RPC_S_PROTOCOL_ERROR;
806
807   switch (hdr->common.ptype) {
808   case PKT_RESPONSE:
809     if (bind->server) goto fail;
810     break;
811   case PKT_REQUEST:
812     if (!bind->server) goto fail;
813     break;
814   case PKT_FAULT:
815     pMsg->RpcFlags |= WINE_RPCFLAG_EXCEPTION;
816     ERR ("we got fault packet with status 0x%lx\n", hdr->fault.status);
817     status = hdr->fault.status; /* FIXME: do translation from nca error codes */
818     goto fail;
819   default:
820     WARN("bad packet type %d\n", hdr->common.ptype);
821     goto fail;
822   }
823
824   /* success */
825   status = RPC_S_OK;
826
827 fail:
828   RPCRT4_FreeHeader(hdr);
829   RPCRT4_CloseBinding(bind, conn);
830   return status;
831 }
832
833 /***********************************************************************
834  *           I_RpcSendReceive [RPCRT4.@]
835  */
836 RPC_STATUS WINAPI I_RpcSendReceive(PRPC_MESSAGE pMsg)
837 {
838   RPC_STATUS status;
839
840   TRACE("(%p)\n", pMsg);
841   status = I_RpcSend(pMsg);
842   if (status == RPC_S_OK)
843     status = I_RpcReceive(pMsg);
844   return status;
845 }