[RPCRT4]
[reactos.git] / reactos / dll / win32 / 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 "precomp.h"
24
25 #include <winuser.h>
26
27 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
28
29 /* note: the DCE/RPC spec says the alignment amount should be 4, but
30 * MS/RPC servers seem to always use 16 */
31 #define AUTH_ALIGNMENT 16
32
33 /* gets the amount needed to round a value up to the specified alignment */
34 #define ROUND_UP_AMOUNT(value, alignment) \
35 (((alignment) - (((value) % (alignment)))) % (alignment))
36 #define ROUND_UP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment)-1))
37
38 static RPC_STATUS I_RpcReAllocateBuffer(PRPC_MESSAGE pMsg);
39
40 DWORD RPCRT4_GetHeaderSize(const RpcPktHdr *Header)
41 {
42 static const DWORD header_sizes[] = {
43 sizeof(Header->request), 0, sizeof(Header->response),
44 sizeof(Header->fault), 0, 0, 0, 0, 0, 0, 0, sizeof(Header->bind),
45 sizeof(Header->bind_ack), sizeof(Header->bind_nack),
46 0, 0, sizeof(Header->auth3), 0, 0, 0, sizeof(Header->http)
47 };
48 ULONG ret = 0;
49
50 if (Header->common.ptype < sizeof(header_sizes) / sizeof(header_sizes[0])) {
51 ret = header_sizes[Header->common.ptype];
52 if (ret == 0)
53 FIXME("unhandled packet type %u\n", Header->common.ptype);
54 if (Header->common.flags & RPC_FLG_OBJECT_UUID)
55 ret += sizeof(UUID);
56 } else {
57 WARN("invalid packet type %u\n", Header->common.ptype);
58 }
59
60 return ret;
61 }
62
63 static BOOL packet_has_body(const RpcPktHdr *Header)
64 {
65 return (Header->common.ptype == PKT_FAULT) ||
66 (Header->common.ptype == PKT_REQUEST) ||
67 (Header->common.ptype == PKT_RESPONSE);
68 }
69
70 static BOOL packet_has_auth_verifier(const RpcPktHdr *Header)
71 {
72 return !(Header->common.ptype == PKT_BIND_NACK) &&
73 !(Header->common.ptype == PKT_SHUTDOWN);
74 }
75
76 static BOOL packet_does_auth_negotiation(const RpcPktHdr *Header)
77 {
78 switch (Header->common.ptype)
79 {
80 case PKT_BIND:
81 case PKT_BIND_ACK:
82 case PKT_AUTH3:
83 case PKT_ALTER_CONTEXT:
84 case PKT_ALTER_CONTEXT_RESP:
85 return TRUE;
86 default:
87 return FALSE;
88 }
89 }
90
91 static VOID RPCRT4_BuildCommonHeader(RpcPktHdr *Header, unsigned char PacketType,
92 ULONG DataRepresentation)
93 {
94 Header->common.rpc_ver = RPC_VER_MAJOR;
95 Header->common.rpc_ver_minor = RPC_VER_MINOR;
96 Header->common.ptype = PacketType;
97 Header->common.drep[0] = LOBYTE(LOWORD(DataRepresentation));
98 Header->common.drep[1] = HIBYTE(LOWORD(DataRepresentation));
99 Header->common.drep[2] = LOBYTE(HIWORD(DataRepresentation));
100 Header->common.drep[3] = HIBYTE(HIWORD(DataRepresentation));
101 Header->common.auth_len = 0;
102 Header->common.call_id = 1;
103 Header->common.flags = 0;
104 /* Flags and fragment length are computed in RPCRT4_Send. */
105 }
106
107 static RpcPktHdr *RPCRT4_BuildRequestHeader(ULONG DataRepresentation,
108 ULONG BufferLength,
109 unsigned short ProcNum,
110 UUID *ObjectUuid)
111 {
112 RpcPktHdr *header;
113 BOOL has_object;
114 RPC_STATUS status;
115
116 has_object = (ObjectUuid != NULL && !UuidIsNil(ObjectUuid, &status));
117 header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
118 sizeof(header->request) + (has_object ? sizeof(UUID) : 0));
119 if (header == NULL) {
120 return NULL;
121 }
122
123 RPCRT4_BuildCommonHeader(header, PKT_REQUEST, DataRepresentation);
124 header->common.frag_len = sizeof(header->request);
125 header->request.alloc_hint = BufferLength;
126 header->request.context_id = 0;
127 header->request.opnum = ProcNum;
128 if (has_object) {
129 header->common.flags |= RPC_FLG_OBJECT_UUID;
130 header->common.frag_len += sizeof(UUID);
131 memcpy(&header->request + 1, ObjectUuid, sizeof(UUID));
132 }
133
134 return header;
135 }
136
137 RpcPktHdr *RPCRT4_BuildResponseHeader(ULONG DataRepresentation, ULONG BufferLength)
138 {
139 RpcPktHdr *header;
140
141 header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->response));
142 if (header == NULL) {
143 return NULL;
144 }
145
146 RPCRT4_BuildCommonHeader(header, PKT_RESPONSE, DataRepresentation);
147 header->common.frag_len = sizeof(header->response);
148 header->response.alloc_hint = BufferLength;
149
150 return header;
151 }
152
153 RpcPktHdr *RPCRT4_BuildFaultHeader(ULONG DataRepresentation, RPC_STATUS Status)
154 {
155 RpcPktHdr *header;
156
157 header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->fault));
158 if (header == NULL) {
159 return NULL;
160 }
161
162 RPCRT4_BuildCommonHeader(header, PKT_FAULT, DataRepresentation);
163 header->common.frag_len = sizeof(header->fault);
164 header->fault.status = Status;
165
166 return header;
167 }
168
169 RpcPktHdr *RPCRT4_BuildBindHeader(ULONG DataRepresentation,
170 unsigned short MaxTransmissionSize,
171 unsigned short MaxReceiveSize,
172 ULONG AssocGroupId,
173 const RPC_SYNTAX_IDENTIFIER *AbstractId,
174 const RPC_SYNTAX_IDENTIFIER *TransferId)
175 {
176 RpcPktHdr *header;
177 RpcContextElement *ctxt_elem;
178
179 header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
180 sizeof(header->bind) + FIELD_OFFSET(RpcContextElement, transfer_syntaxes[1]));
181 if (header == NULL) {
182 return NULL;
183 }
184 ctxt_elem = (RpcContextElement *)(&header->bind + 1);
185
186 RPCRT4_BuildCommonHeader(header, PKT_BIND, DataRepresentation);
187 header->common.frag_len = sizeof(header->bind) + FIELD_OFFSET(RpcContextElement, transfer_syntaxes[1]);
188 header->bind.max_tsize = MaxTransmissionSize;
189 header->bind.max_rsize = MaxReceiveSize;
190 header->bind.assoc_gid = AssocGroupId;
191 header->bind.num_elements = 1;
192 ctxt_elem->num_syntaxes = 1;
193 ctxt_elem->abstract_syntax = *AbstractId;
194 ctxt_elem->transfer_syntaxes[0] = *TransferId;
195
196 return header;
197 }
198
199 static RpcPktHdr *RPCRT4_BuildAuthHeader(ULONG DataRepresentation)
200 {
201 RpcPktHdr *header;
202
203 header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
204 sizeof(header->auth3));
205 if (header == NULL)
206 return NULL;
207
208 RPCRT4_BuildCommonHeader(header, PKT_AUTH3, DataRepresentation);
209 header->common.frag_len = sizeof(header->auth3);
210
211 return header;
212 }
213
214 RpcPktHdr *RPCRT4_BuildBindNackHeader(ULONG DataRepresentation,
215 unsigned char RpcVersion,
216 unsigned char RpcVersionMinor,
217 unsigned short RejectReason)
218 {
219 RpcPktHdr *header;
220
221 header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET(RpcPktHdr, bind_nack.protocols[1]));
222 if (header == NULL) {
223 return NULL;
224 }
225
226 RPCRT4_BuildCommonHeader(header, PKT_BIND_NACK, DataRepresentation);
227 header->common.frag_len = FIELD_OFFSET(RpcPktHdr, bind_nack.protocols[1]);
228 header->bind_nack.reject_reason = RejectReason;
229 header->bind_nack.protocols_count = 1;
230 header->bind_nack.protocols[0].rpc_ver = RpcVersion;
231 header->bind_nack.protocols[0].rpc_ver_minor = RpcVersionMinor;
232
233 return header;
234 }
235
236 RpcPktHdr *RPCRT4_BuildBindAckHeader(ULONG DataRepresentation,
237 unsigned short MaxTransmissionSize,
238 unsigned short MaxReceiveSize,
239 ULONG AssocGroupId,
240 LPCSTR ServerAddress,
241 unsigned char ResultCount,
242 const RpcResult *Results)
243 {
244 RpcPktHdr *header;
245 ULONG header_size;
246 RpcAddressString *server_address;
247 RpcResultList *results;
248
249 header_size = sizeof(header->bind_ack) +
250 ROUND_UP(FIELD_OFFSET(RpcAddressString, string[strlen(ServerAddress) + 1]), 4) +
251 FIELD_OFFSET(RpcResultList, results[ResultCount]);
252
253 header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, header_size);
254 if (header == NULL) {
255 return NULL;
256 }
257
258 RPCRT4_BuildCommonHeader(header, PKT_BIND_ACK, DataRepresentation);
259 header->common.frag_len = header_size;
260 header->bind_ack.max_tsize = MaxTransmissionSize;
261 header->bind_ack.max_rsize = MaxReceiveSize;
262 header->bind_ack.assoc_gid = AssocGroupId;
263 server_address = (RpcAddressString*)(&header->bind_ack + 1);
264 server_address->length = strlen(ServerAddress) + 1;
265 strcpy(server_address->string, ServerAddress);
266 /* results is 4-byte aligned */
267 results = (RpcResultList*)((ULONG_PTR)server_address + ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4));
268 results->num_results = ResultCount;
269 memcpy(&results->results[0], Results, ResultCount * sizeof(*Results));
270
271 return header;
272 }
273
274 RpcPktHdr *RPCRT4_BuildHttpHeader(ULONG DataRepresentation,
275 unsigned short flags,
276 unsigned short num_data_items,
277 unsigned int payload_size)
278 {
279 RpcPktHdr *header;
280
281 header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->http) + payload_size);
282 if (header == NULL) {
283 ERR("failed to allocate memory\n");
284 return NULL;
285 }
286
287 RPCRT4_BuildCommonHeader(header, PKT_HTTP, DataRepresentation);
288 /* since the packet isn't current sent using RPCRT4_Send, set the flags
289 * manually here */
290 header->common.flags = RPC_FLG_FIRST|RPC_FLG_LAST;
291 header->common.call_id = 0;
292 header->common.frag_len = sizeof(header->http) + payload_size;
293 header->http.flags = flags;
294 header->http.num_data_items = num_data_items;
295
296 return header;
297 }
298
299 #define WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, type, value) \
300 do { \
301 *(unsigned int *)(payload) = (type); \
302 (payload) += 4; \
303 *(unsigned int *)(payload) = (value); \
304 (payload) += 4; \
305 } while (0)
306
307 #define WRITE_HTTP_PAYLOAD_FIELD_UUID(payload, type, uuid) \
308 do { \
309 *(unsigned int *)(payload) = (type); \
310 (payload) += 4; \
311 *(UUID *)(payload) = (uuid); \
312 (payload) += sizeof(UUID); \
313 } while (0)
314
315 #define WRITE_HTTP_PAYLOAD_FIELD_FLOW_CONTROL(payload, bytes_transmitted, flow_control_increment, uuid) \
316 do { \
317 *(unsigned int *)(payload) = 0x00000001; \
318 (payload) += 4; \
319 *(unsigned int *)(payload) = (bytes_transmitted); \
320 (payload) += 4; \
321 *(unsigned int *)(payload) = (flow_control_increment); \
322 (payload) += 4; \
323 *(UUID *)(payload) = (uuid); \
324 (payload) += sizeof(UUID); \
325 } while (0)
326
327 RpcPktHdr *RPCRT4_BuildHttpConnectHeader(int out_pipe,
328 const UUID *connection_uuid,
329 const UUID *pipe_uuid,
330 const UUID *association_uuid)
331 {
332 RpcPktHdr *header;
333 unsigned int size;
334 char *payload;
335
336 size = 8 + 4 + sizeof(UUID) + 4 + sizeof(UUID) + 8;
337 if (!out_pipe)
338 size += 8 + 4 + sizeof(UUID);
339
340 header = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, 0,
341 out_pipe ? 4 : 6, size);
342 if (!header) return NULL;
343 payload = (char *)(&header->http+1);
344
345 /* FIXME: what does this part of the payload do? */
346 WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x00000006, 0x00000001);
347
348 WRITE_HTTP_PAYLOAD_FIELD_UUID(payload, 0x00000003, *connection_uuid);
349 WRITE_HTTP_PAYLOAD_FIELD_UUID(payload, 0x00000003, *pipe_uuid);
350
351 if (out_pipe)
352 /* FIXME: what does this part of the payload do? */
353 WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x00000000, 0x00010000);
354 else
355 {
356 /* FIXME: what does this part of the payload do? */
357 WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x00000004, 0x40000000);
358 /* FIXME: what does this part of the payload do? */
359 WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x00000005, 0x000493e0);
360
361 WRITE_HTTP_PAYLOAD_FIELD_UUID(payload, 0x0000000c, *association_uuid);
362 }
363
364 return header;
365 }
366
367 RpcPktHdr *RPCRT4_BuildHttpFlowControlHeader(BOOL server, ULONG bytes_transmitted,
368 ULONG flow_control_increment,
369 const UUID *pipe_uuid)
370 {
371 RpcPktHdr *header;
372 char *payload;
373
374 header = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, 0x2, 2,
375 5 * sizeof(ULONG) + sizeof(UUID));
376 if (!header) return NULL;
377 payload = (char *)(&header->http+1);
378
379 WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x0000000d, (server ? 0x0 : 0x3));
380
381 WRITE_HTTP_PAYLOAD_FIELD_FLOW_CONTROL(payload, bytes_transmitted,
382 flow_control_increment, *pipe_uuid);
383 return header;
384 }
385
386 VOID RPCRT4_FreeHeader(RpcPktHdr *Header)
387 {
388 HeapFree(GetProcessHeap(), 0, Header);
389 }
390
391 NCA_STATUS RPC2NCA_STATUS(RPC_STATUS status)
392 {
393 switch (status)
394 {
395 case ERROR_INVALID_HANDLE: return NCA_S_FAULT_CONTEXT_MISMATCH;
396 case ERROR_OUTOFMEMORY: return NCA_S_FAULT_REMOTE_NO_MEMORY;
397 case RPC_S_NOT_LISTENING: return NCA_S_SERVER_TOO_BUSY;
398 case RPC_S_UNKNOWN_IF: return NCA_S_UNK_IF;
399 case RPC_S_SERVER_TOO_BUSY: return NCA_S_SERVER_TOO_BUSY;
400 case RPC_S_CALL_FAILED: return NCA_S_FAULT_UNSPEC;
401 case RPC_S_CALL_FAILED_DNE: return NCA_S_MANAGER_NOT_ENTERED;
402 case RPC_S_PROTOCOL_ERROR: return NCA_S_PROTO_ERROR;
403 case RPC_S_UNSUPPORTED_TYPE: return NCA_S_UNSUPPORTED_TYPE;
404 case RPC_S_INVALID_TAG: return NCA_S_FAULT_INVALID_TAG;
405 case RPC_S_INVALID_BOUND: return NCA_S_FAULT_INVALID_BOUND;
406 case RPC_S_PROCNUM_OUT_OF_RANGE: return NCA_S_OP_RNG_ERROR;
407 case RPC_X_SS_HANDLES_MISMATCH: return NCA_S_FAULT_CONTEXT_MISMATCH;
408 case RPC_S_CALL_CANCELLED: return NCA_S_FAULT_CANCEL;
409 case RPC_S_COMM_FAILURE: return NCA_S_COMM_FAILURE;
410 case RPC_X_WRONG_PIPE_ORDER: return NCA_S_FAULT_PIPE_ORDER;
411 case RPC_X_PIPE_CLOSED: return NCA_S_FAULT_PIPE_CLOSED;
412 case RPC_X_PIPE_DISCIPLINE_ERROR: return NCA_S_FAULT_PIPE_DISCIPLINE;
413 case RPC_X_PIPE_EMPTY: return NCA_S_FAULT_PIPE_EMPTY;
414 case STATUS_FLOAT_DIVIDE_BY_ZERO: return NCA_S_FAULT_FP_DIV_ZERO;
415 case STATUS_FLOAT_INVALID_OPERATION: return NCA_S_FAULT_FP_ERROR;
416 case STATUS_FLOAT_OVERFLOW: return NCA_S_FAULT_FP_OVERFLOW;
417 case STATUS_FLOAT_UNDERFLOW: return NCA_S_FAULT_FP_UNDERFLOW;
418 case STATUS_INTEGER_DIVIDE_BY_ZERO: return NCA_S_FAULT_INT_DIV_BY_ZERO;
419 case STATUS_INTEGER_OVERFLOW: return NCA_S_FAULT_INT_OVERFLOW;
420 default: return status;
421 }
422 }
423
424 static RPC_STATUS NCA2RPC_STATUS(NCA_STATUS status)
425 {
426 switch (status)
427 {
428 case NCA_S_COMM_FAILURE: return RPC_S_COMM_FAILURE;
429 case NCA_S_OP_RNG_ERROR: return RPC_S_PROCNUM_OUT_OF_RANGE;
430 case NCA_S_UNK_IF: return RPC_S_UNKNOWN_IF;
431 case NCA_S_YOU_CRASHED: return RPC_S_CALL_FAILED;
432 case NCA_S_PROTO_ERROR: return RPC_S_PROTOCOL_ERROR;
433 case NCA_S_OUT_ARGS_TOO_BIG: return ERROR_NOT_ENOUGH_SERVER_MEMORY;
434 case NCA_S_SERVER_TOO_BUSY: return RPC_S_SERVER_TOO_BUSY;
435 case NCA_S_UNSUPPORTED_TYPE: return RPC_S_UNSUPPORTED_TYPE;
436 case NCA_S_FAULT_INT_DIV_BY_ZERO: return RPC_S_ZERO_DIVIDE;
437 case NCA_S_FAULT_ADDR_ERROR: return RPC_S_ADDRESS_ERROR;
438 case NCA_S_FAULT_FP_DIV_ZERO: return RPC_S_FP_DIV_ZERO;
439 case NCA_S_FAULT_FP_UNDERFLOW: return RPC_S_FP_UNDERFLOW;
440 case NCA_S_FAULT_FP_OVERFLOW: return RPC_S_FP_OVERFLOW;
441 case NCA_S_FAULT_INVALID_TAG: return RPC_S_INVALID_TAG;
442 case NCA_S_FAULT_INVALID_BOUND: return RPC_S_INVALID_BOUND;
443 case NCA_S_RPC_VERSION_MISMATCH: return RPC_S_PROTOCOL_ERROR;
444 case NCA_S_UNSPEC_REJECT: return RPC_S_CALL_FAILED_DNE;
445 case NCA_S_BAD_ACTID: return RPC_S_CALL_FAILED_DNE;
446 case NCA_S_WHO_ARE_YOU_FAILED: return RPC_S_CALL_FAILED;
447 case NCA_S_MANAGER_NOT_ENTERED: return RPC_S_CALL_FAILED_DNE;
448 case NCA_S_FAULT_CANCEL: return RPC_S_CALL_CANCELLED;
449 case NCA_S_FAULT_ILL_INST: return RPC_S_ADDRESS_ERROR;
450 case NCA_S_FAULT_FP_ERROR: return RPC_S_FP_OVERFLOW;
451 case NCA_S_FAULT_INT_OVERFLOW: return RPC_S_ADDRESS_ERROR;
452 case NCA_S_FAULT_UNSPEC: return RPC_S_CALL_FAILED;
453 case NCA_S_FAULT_PIPE_EMPTY: return RPC_X_PIPE_EMPTY;
454 case NCA_S_FAULT_PIPE_CLOSED: return RPC_X_PIPE_CLOSED;
455 case NCA_S_FAULT_PIPE_ORDER: return RPC_X_WRONG_PIPE_ORDER;
456 case NCA_S_FAULT_PIPE_DISCIPLINE: return RPC_X_PIPE_DISCIPLINE_ERROR;
457 case NCA_S_FAULT_PIPE_COMM_ERROR: return RPC_S_COMM_FAILURE;
458 case NCA_S_FAULT_PIPE_MEMORY: return ERROR_OUTOFMEMORY;
459 case NCA_S_FAULT_CONTEXT_MISMATCH: return ERROR_INVALID_HANDLE;
460 case NCA_S_FAULT_REMOTE_NO_MEMORY: return ERROR_NOT_ENOUGH_SERVER_MEMORY;
461 default: return status;
462 }
463 }
464
465 /* assumes the common header fields have already been validated */
466 BOOL RPCRT4_IsValidHttpPacket(RpcPktHdr *hdr, unsigned char *data,
467 unsigned short data_len)
468 {
469 unsigned short i;
470 BYTE *p = data;
471
472 for (i = 0; i < hdr->http.num_data_items; i++)
473 {
474 ULONG type;
475
476 if (data_len < sizeof(ULONG))
477 return FALSE;
478
479 type = *(ULONG *)p;
480 p += sizeof(ULONG);
481 data_len -= sizeof(ULONG);
482
483 switch (type)
484 {
485 case 0x3:
486 case 0xc:
487 if (data_len < sizeof(GUID))
488 return FALSE;
489 p += sizeof(GUID);
490 data_len -= sizeof(GUID);
491 break;
492 case 0x0:
493 case 0x2:
494 case 0x4:
495 case 0x5:
496 case 0x6:
497 case 0xd:
498 if (data_len < sizeof(ULONG))
499 return FALSE;
500 p += sizeof(ULONG);
501 data_len -= sizeof(ULONG);
502 break;
503 case 0x1:
504 if (data_len < 24)
505 return FALSE;
506 p += 24;
507 data_len -= 24;
508 break;
509 default:
510 FIXME("unimplemented type 0x%x\n", type);
511 break;
512 }
513 }
514 return TRUE;
515 }
516
517 /* assumes the HTTP packet has been validated */
518 static unsigned char *RPCRT4_NextHttpHeaderField(unsigned char *data)
519 {
520 ULONG type;
521
522 type = *(ULONG *)data;
523 data += sizeof(ULONG);
524
525 switch (type)
526 {
527 case 0x3:
528 case 0xc:
529 return data + sizeof(GUID);
530 case 0x0:
531 case 0x2:
532 case 0x4:
533 case 0x5:
534 case 0x6:
535 case 0xd:
536 return data + sizeof(ULONG);
537 case 0x1:
538 return data + 24;
539 default:
540 FIXME("unimplemented type 0x%x\n", type);
541 return data;
542 }
543 }
544
545 #define READ_HTTP_PAYLOAD_FIELD_TYPE(data) *(ULONG *)(data)
546 #define GET_HTTP_PAYLOAD_FIELD_DATA(data) ((data) + sizeof(ULONG))
547
548 /* assumes the HTTP packet has been validated */
549 RPC_STATUS RPCRT4_ParseHttpPrepareHeader1(RpcPktHdr *header,
550 unsigned char *data, ULONG *field1)
551 {
552 ULONG type;
553 if (header->http.flags != 0x0)
554 {
555 ERR("invalid flags 0x%x\n", header->http.flags);
556 return RPC_S_PROTOCOL_ERROR;
557 }
558 if (header->http.num_data_items != 1)
559 {
560 ERR("invalid number of data items %d\n", header->http.num_data_items);
561 return RPC_S_PROTOCOL_ERROR;
562 }
563 type = READ_HTTP_PAYLOAD_FIELD_TYPE(data);
564 if (type != 0x00000002)
565 {
566 ERR("invalid type 0x%08x\n", type);
567 return RPC_S_PROTOCOL_ERROR;
568 }
569 *field1 = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data);
570 return RPC_S_OK;
571 }
572
573 /* assumes the HTTP packet has been validated */
574 RPC_STATUS RPCRT4_ParseHttpPrepareHeader2(RpcPktHdr *header,
575 unsigned char *data, ULONG *field1,
576 ULONG *bytes_until_next_packet,
577 ULONG *field3)
578 {
579 ULONG type;
580 if (header->http.flags != 0x0)
581 {
582 ERR("invalid flags 0x%x\n", header->http.flags);
583 return RPC_S_PROTOCOL_ERROR;
584 }
585 if (header->http.num_data_items != 3)
586 {
587 ERR("invalid number of data items %d\n", header->http.num_data_items);
588 return RPC_S_PROTOCOL_ERROR;
589 }
590
591 type = READ_HTTP_PAYLOAD_FIELD_TYPE(data);
592 if (type != 0x00000006)
593 {
594 ERR("invalid type for field 1: 0x%08x\n", type);
595 return RPC_S_PROTOCOL_ERROR;
596 }
597 *field1 = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data);
598 data = RPCRT4_NextHttpHeaderField(data);
599
600 type = READ_HTTP_PAYLOAD_FIELD_TYPE(data);
601 if (type != 0x00000000)
602 {
603 ERR("invalid type for field 2: 0x%08x\n", type);
604 return RPC_S_PROTOCOL_ERROR;
605 }
606 *bytes_until_next_packet = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data);
607 data = RPCRT4_NextHttpHeaderField(data);
608
609 type = READ_HTTP_PAYLOAD_FIELD_TYPE(data);
610 if (type != 0x00000002)
611 {
612 ERR("invalid type for field 3: 0x%08x\n", type);
613 return RPC_S_PROTOCOL_ERROR;
614 }
615 *field3 = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data);
616
617 return RPC_S_OK;
618 }
619
620 RPC_STATUS RPCRT4_ParseHttpFlowControlHeader(RpcPktHdr *header,
621 unsigned char *data, BOOL server,
622 ULONG *bytes_transmitted,
623 ULONG *flow_control_increment,
624 UUID *pipe_uuid)
625 {
626 ULONG type;
627 if (header->http.flags != 0x2)
628 {
629 ERR("invalid flags 0x%x\n", header->http.flags);
630 return RPC_S_PROTOCOL_ERROR;
631 }
632 if (header->http.num_data_items != 2)
633 {
634 ERR("invalid number of data items %d\n", header->http.num_data_items);
635 return RPC_S_PROTOCOL_ERROR;
636 }
637
638 type = READ_HTTP_PAYLOAD_FIELD_TYPE(data);
639 if (type != 0x0000000d)
640 {
641 ERR("invalid type for field 1: 0x%08x\n", type);
642 return RPC_S_PROTOCOL_ERROR;
643 }
644 if (*(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data) != (server ? 0x3 : 0x0))
645 {
646 ERR("invalid type for 0xd field data: 0x%08x\n", *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data));
647 return RPC_S_PROTOCOL_ERROR;
648 }
649 data = RPCRT4_NextHttpHeaderField(data);
650
651 type = READ_HTTP_PAYLOAD_FIELD_TYPE(data);
652 if (type != 0x00000001)
653 {
654 ERR("invalid type for field 2: 0x%08x\n", type);
655 return RPC_S_PROTOCOL_ERROR;
656 }
657 *bytes_transmitted = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data);
658 *flow_control_increment = *(ULONG *)(GET_HTTP_PAYLOAD_FIELD_DATA(data) + 4);
659 *pipe_uuid = *(UUID *)(GET_HTTP_PAYLOAD_FIELD_DATA(data) + 8);
660
661 return RPC_S_OK;
662 }
663
664
665 RPC_STATUS RPCRT4_default_secure_packet(RpcConnection *Connection,
666 enum secure_packet_direction dir,
667 RpcPktHdr *hdr, unsigned int hdr_size,
668 unsigned char *stub_data, unsigned int stub_data_size,
669 RpcAuthVerifier *auth_hdr,
670 unsigned char *auth_value, unsigned int auth_value_size)
671 {
672 SecBufferDesc message;
673 SecBuffer buffers[4];
674 SECURITY_STATUS sec_status;
675
676 message.ulVersion = SECBUFFER_VERSION;
677 message.cBuffers = sizeof(buffers)/sizeof(buffers[0]);
678 message.pBuffers = buffers;
679
680 buffers[0].cbBuffer = hdr_size;
681 buffers[0].BufferType = SECBUFFER_DATA|SECBUFFER_READONLY_WITH_CHECKSUM;
682 buffers[0].pvBuffer = hdr;
683 buffers[1].cbBuffer = stub_data_size;
684 buffers[1].BufferType = SECBUFFER_DATA;
685 buffers[1].pvBuffer = stub_data;
686 buffers[2].cbBuffer = sizeof(*auth_hdr);
687 buffers[2].BufferType = SECBUFFER_DATA|SECBUFFER_READONLY_WITH_CHECKSUM;
688 buffers[2].pvBuffer = auth_hdr;
689 buffers[3].cbBuffer = auth_value_size;
690 buffers[3].BufferType = SECBUFFER_TOKEN;
691 buffers[3].pvBuffer = auth_value;
692
693 if (dir == SECURE_PACKET_SEND)
694 {
695 if ((auth_hdr->auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) && packet_has_body(hdr))
696 {
697 sec_status = EncryptMessage(&Connection->ctx, 0, &message, 0 /* FIXME */);
698 if (sec_status != SEC_E_OK)
699 {
700 ERR("EncryptMessage failed with 0x%08x\n", sec_status);
701 return RPC_S_SEC_PKG_ERROR;
702 }
703 }
704 else if (auth_hdr->auth_level != RPC_C_AUTHN_LEVEL_NONE)
705 {
706 sec_status = MakeSignature(&Connection->ctx, 0, &message, 0 /* FIXME */);
707 if (sec_status != SEC_E_OK)
708 {
709 ERR("MakeSignature failed with 0x%08x\n", sec_status);
710 return RPC_S_SEC_PKG_ERROR;
711 }
712 }
713 }
714 else if (dir == SECURE_PACKET_RECEIVE)
715 {
716 if ((auth_hdr->auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) && packet_has_body(hdr))
717 {
718 sec_status = DecryptMessage(&Connection->ctx, &message, 0 /* FIXME */, 0);
719 if (sec_status != SEC_E_OK)
720 {
721 ERR("DecryptMessage failed with 0x%08x\n", sec_status);
722 return RPC_S_SEC_PKG_ERROR;
723 }
724 }
725 else if (auth_hdr->auth_level != RPC_C_AUTHN_LEVEL_NONE)
726 {
727 sec_status = VerifySignature(&Connection->ctx, &message, 0 /* FIXME */, NULL);
728 if (sec_status != SEC_E_OK)
729 {
730 ERR("VerifySignature failed with 0x%08x\n", sec_status);
731 return RPC_S_SEC_PKG_ERROR;
732 }
733 }
734 }
735
736 return RPC_S_OK;
737 }
738
739 /***********************************************************************
740 * RPCRT4_SendWithAuth (internal)
741 *
742 * Transmit a packet with authorization data over connection in acceptable fragments.
743 */
744 RPC_STATUS RPCRT4_SendWithAuth(RpcConnection *Connection, RpcPktHdr *Header,
745 void *Buffer, unsigned int BufferLength,
746 const void *Auth, unsigned int AuthLength)
747 {
748 PUCHAR buffer_pos;
749 DWORD hdr_size;
750 LONG count;
751 unsigned char *pkt;
752 LONG alen;
753 RPC_STATUS status;
754
755 RPCRT4_SetThreadCurrentConnection(Connection);
756
757 buffer_pos = Buffer;
758 /* The packet building functions save the packet header size, so we can use it. */
759 hdr_size = Header->common.frag_len;
760 if (AuthLength)
761 Header->common.auth_len = AuthLength;
762 else if (Connection->AuthInfo && packet_has_auth_verifier(Header))
763 {
764 if ((Connection->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) && packet_has_body(Header))
765 Header->common.auth_len = Connection->encryption_auth_len;
766 else
767 Header->common.auth_len = Connection->signature_auth_len;
768 }
769 else
770 Header->common.auth_len = 0;
771 Header->common.flags |= RPC_FLG_FIRST;
772 Header->common.flags &= ~RPC_FLG_LAST;
773
774 alen = RPC_AUTH_VERIFIER_LEN(&Header->common);
775
776 while (!(Header->common.flags & RPC_FLG_LAST)) {
777 unsigned char auth_pad_len = Header->common.auth_len ? ROUND_UP_AMOUNT(BufferLength, AUTH_ALIGNMENT) : 0;
778 unsigned int pkt_size = BufferLength + hdr_size + alen + auth_pad_len;
779
780 /* decide if we need to split the packet into fragments */
781 if (pkt_size <= Connection->MaxTransmissionSize) {
782 Header->common.flags |= RPC_FLG_LAST;
783 Header->common.frag_len = pkt_size;
784 } else {
785 auth_pad_len = 0;
786 /* make sure packet payload will be a multiple of 16 */
787 Header->common.frag_len =
788 ((Connection->MaxTransmissionSize - hdr_size - alen) & ~(AUTH_ALIGNMENT-1)) +
789 hdr_size + alen;
790 }
791
792 pkt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Header->common.frag_len);
793
794 memcpy(pkt, Header, hdr_size);
795
796 /* fragment consisted of header only and is the last one */
797 if (hdr_size == Header->common.frag_len)
798 goto write;
799
800 memcpy(pkt + hdr_size, buffer_pos, Header->common.frag_len - hdr_size - auth_pad_len - alen);
801
802 /* add the authorization info */
803 if (Header->common.auth_len)
804 {
805 RpcAuthVerifier *auth_hdr = (RpcAuthVerifier *)&pkt[Header->common.frag_len - alen];
806
807 auth_hdr->auth_type = Connection->AuthInfo->AuthnSvc;
808 auth_hdr->auth_level = Connection->AuthInfo->AuthnLevel;
809 auth_hdr->auth_pad_length = auth_pad_len;
810 auth_hdr->auth_reserved = 0;
811 /* a unique number... */
812 auth_hdr->auth_context_id = Connection->auth_context_id;
813
814 if (AuthLength)
815 memcpy(auth_hdr + 1, Auth, AuthLength);
816 else
817 {
818 status = rpcrt4_conn_secure_packet(Connection, SECURE_PACKET_SEND,
819 (RpcPktHdr *)pkt, hdr_size,
820 pkt + hdr_size, Header->common.frag_len - hdr_size - alen,
821 auth_hdr,
822 (unsigned char *)(auth_hdr + 1), Header->common.auth_len);
823 if (status != RPC_S_OK)
824 {
825 HeapFree(GetProcessHeap(), 0, pkt);
826 RPCRT4_SetThreadCurrentConnection(NULL);
827 return status;
828 }
829 }
830 }
831
832 write:
833 count = rpcrt4_conn_write(Connection, pkt, Header->common.frag_len);
834 HeapFree(GetProcessHeap(), 0, pkt);
835 if (count<0) {
836 WARN("rpcrt4_conn_write failed (auth)\n");
837 RPCRT4_SetThreadCurrentConnection(NULL);
838 return RPC_S_CALL_FAILED;
839 }
840
841 buffer_pos += Header->common.frag_len - hdr_size - alen - auth_pad_len;
842 BufferLength -= Header->common.frag_len - hdr_size - alen - auth_pad_len;
843 Header->common.flags &= ~RPC_FLG_FIRST;
844 }
845
846 RPCRT4_SetThreadCurrentConnection(NULL);
847 return RPC_S_OK;
848 }
849
850 /***********************************************************************
851 * RPCRT4_default_authorize (internal)
852 *
853 * Authorize a client connection.
854 */
855 RPC_STATUS RPCRT4_default_authorize(RpcConnection *conn, BOOL first_time,
856 unsigned char *in_buffer,
857 unsigned int in_size,
858 unsigned char *out_buffer,
859 unsigned int *out_size)
860 {
861 SECURITY_STATUS r;
862 SecBufferDesc out_desc;
863 SecBufferDesc inp_desc;
864 SecPkgContext_Sizes secctx_sizes;
865 BOOL continue_needed;
866 ULONG context_req;
867 SecBuffer in, out;
868
869 if (!out_buffer)
870 {
871 *out_size = conn->AuthInfo->cbMaxToken;
872 return RPC_S_OK;
873 }
874
875 in.BufferType = SECBUFFER_TOKEN;
876 in.pvBuffer = in_buffer;
877 in.cbBuffer = in_size;
878
879 out.BufferType = SECBUFFER_TOKEN;
880 out.pvBuffer = out_buffer;
881 out.cbBuffer = *out_size;
882
883 out_desc.ulVersion = 0;
884 out_desc.cBuffers = 1;
885 out_desc.pBuffers = &out;
886
887 inp_desc.ulVersion = 0;
888 inp_desc.cBuffers = 1;
889 inp_desc.pBuffers = &in;
890
891 if (conn->server)
892 {
893 context_req = ASC_REQ_CONNECTION | ASC_REQ_USE_DCE_STYLE |
894 ASC_REQ_DELEGATE;
895
896 if (conn->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
897 context_req |= ASC_REQ_INTEGRITY;
898 else if (conn->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
899 context_req |= ASC_REQ_CONFIDENTIALITY | ASC_REQ_INTEGRITY;
900
901 r = AcceptSecurityContext(&conn->AuthInfo->cred,
902 first_time ? NULL : &conn->ctx,
903 &inp_desc, context_req, SECURITY_NETWORK_DREP,
904 &conn->ctx,
905 &out_desc, &conn->attr, &conn->exp);
906 if (r == SEC_E_OK || r == SEC_I_COMPLETE_NEEDED)
907 {
908 /* authorisation done, so nothing more to send */
909 out.cbBuffer = 0;
910 }
911 }
912 else
913 {
914 context_req = ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE |
915 ISC_REQ_MUTUAL_AUTH | ISC_REQ_DELEGATE;
916
917 if (conn->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
918 context_req |= ISC_REQ_INTEGRITY;
919 else if (conn->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
920 context_req |= ISC_REQ_CONFIDENTIALITY | ISC_REQ_INTEGRITY;
921
922 r = InitializeSecurityContextW(&conn->AuthInfo->cred,
923 first_time ? NULL: &conn->ctx,
924 first_time ? conn->AuthInfo->server_principal_name : NULL,
925 context_req, 0, SECURITY_NETWORK_DREP,
926 first_time ? NULL : &inp_desc, 0, &conn->ctx,
927 &out_desc, &conn->attr, &conn->exp);
928 }
929 if (FAILED(r))
930 {
931 WARN("InitializeSecurityContext failed with error 0x%08x\n", r);
932 goto failed;
933 }
934
935 TRACE("r = 0x%08x, attr = 0x%08x\n", r, conn->attr);
936 continue_needed = ((r == SEC_I_CONTINUE_NEEDED) ||
937 (r == SEC_I_COMPLETE_AND_CONTINUE));
938
939 if ((r == SEC_I_COMPLETE_NEEDED) || (r == SEC_I_COMPLETE_AND_CONTINUE))
940 {
941 TRACE("complete needed\n");
942 r = CompleteAuthToken(&conn->ctx, &out_desc);
943 if (FAILED(r))
944 {
945 WARN("CompleteAuthToken failed with error 0x%08x\n", r);
946 goto failed;
947 }
948 }
949
950 TRACE("cbBuffer = %d\n", out.cbBuffer);
951
952 if (!continue_needed)
953 {
954 r = QueryContextAttributesA(&conn->ctx, SECPKG_ATTR_SIZES, &secctx_sizes);
955 if (FAILED(r))
956 {
957 WARN("QueryContextAttributes failed with error 0x%08x\n", r);
958 goto failed;
959 }
960 conn->signature_auth_len = secctx_sizes.cbMaxSignature;
961 conn->encryption_auth_len = secctx_sizes.cbSecurityTrailer;
962 }
963
964 *out_size = out.cbBuffer;
965 return RPC_S_OK;
966
967 failed:
968 *out_size = 0;
969 return ERROR_ACCESS_DENIED; /* FIXME: is this correct? */
970 }
971
972 /***********************************************************************
973 * RPCRT4_ClientConnectionAuth (internal)
974 */
975 RPC_STATUS RPCRT4_ClientConnectionAuth(RpcConnection* conn, BYTE *challenge,
976 ULONG count)
977 {
978 RpcPktHdr *resp_hdr;
979 RPC_STATUS status;
980 unsigned char *out_buffer;
981 unsigned int out_len = 0;
982
983 TRACE("challenge %s, %d bytes\n", challenge, count);
984
985 status = rpcrt4_conn_authorize(conn, FALSE, challenge, count, NULL, &out_len);
986 if (status) return status;
987 out_buffer = HeapAlloc(GetProcessHeap(), 0, out_len);
988 if (!out_buffer) return RPC_S_OUT_OF_RESOURCES;
989 status = rpcrt4_conn_authorize(conn, FALSE, challenge, count, out_buffer, &out_len);
990 if (status) return status;
991
992 resp_hdr = RPCRT4_BuildAuthHeader(NDR_LOCAL_DATA_REPRESENTATION);
993
994 if (resp_hdr)
995 status = RPCRT4_SendWithAuth(conn, resp_hdr, NULL, 0, out_buffer, out_len);
996 else
997 status = RPC_S_OUT_OF_RESOURCES;
998
999 HeapFree(GetProcessHeap(), 0, out_buffer);
1000 RPCRT4_FreeHeader(resp_hdr);
1001
1002 return status;
1003 }
1004
1005 /***********************************************************************
1006 * RPCRT4_ServerConnectionAuth (internal)
1007 */
1008 RPC_STATUS RPCRT4_ServerConnectionAuth(RpcConnection* conn,
1009 BOOL start,
1010 RpcAuthVerifier *auth_data_in,
1011 ULONG auth_length_in,
1012 unsigned char **auth_data_out,
1013 ULONG *auth_length_out)
1014 {
1015 unsigned char *out_buffer;
1016 unsigned int out_size;
1017 RPC_STATUS status;
1018
1019 if (start)
1020 {
1021 /* remove any existing authentication information */
1022 if (conn->AuthInfo)
1023 {
1024 RpcAuthInfo_Release(conn->AuthInfo);
1025 conn->AuthInfo = NULL;
1026 }
1027 if (SecIsValidHandle(&conn->ctx))
1028 {
1029 DeleteSecurityContext(&conn->ctx);
1030 SecInvalidateHandle(&conn->ctx);
1031 }
1032 if (auth_length_in >= sizeof(RpcAuthVerifier))
1033 {
1034 CredHandle cred;
1035 TimeStamp exp;
1036 ULONG max_token;
1037
1038 status = RPCRT4_ServerGetRegisteredAuthInfo(
1039 auth_data_in->auth_type, &cred, &exp, &max_token);
1040 if (status != RPC_S_OK)
1041 {
1042 ERR("unknown authentication service %u\n", auth_data_in->auth_type);
1043 return status;
1044 }
1045
1046 status = RpcAuthInfo_Create(auth_data_in->auth_level,
1047 auth_data_in->auth_type, cred, exp,
1048 max_token, NULL, &conn->AuthInfo);
1049 if (status != RPC_S_OK)
1050 return status;
1051
1052 /* FIXME: should auth_data_in->auth_context_id be checked in the !start case? */
1053 conn->auth_context_id = auth_data_in->auth_context_id;
1054 }
1055 }
1056
1057 if (auth_length_in < sizeof(RpcAuthVerifier))
1058 return RPC_S_OK;
1059
1060 if (!conn->AuthInfo)
1061 /* should have filled in authentication info by now */
1062 return RPC_S_PROTOCOL_ERROR;
1063
1064 status = rpcrt4_conn_authorize(
1065 conn, start, (unsigned char *)(auth_data_in + 1),
1066 auth_length_in - sizeof(RpcAuthVerifier), NULL, &out_size);
1067 if (status) return status;
1068
1069 out_buffer = HeapAlloc(GetProcessHeap(), 0, out_size);
1070 if (!out_buffer) return RPC_S_OUT_OF_RESOURCES;
1071
1072 status = rpcrt4_conn_authorize(
1073 conn, start, (unsigned char *)(auth_data_in + 1),
1074 auth_length_in - sizeof(RpcAuthVerifier), out_buffer, &out_size);
1075 if (status != RPC_S_OK)
1076 {
1077 HeapFree(GetProcessHeap(), 0, out_buffer);
1078 return status;
1079 }
1080
1081 if (out_size && !auth_length_out)
1082 {
1083 ERR("expected authentication to be complete but SSP returned data of "
1084 "%u bytes to be sent back to client\n", out_size);
1085 HeapFree(GetProcessHeap(), 0, out_buffer);
1086 return RPC_S_SEC_PKG_ERROR;
1087 }
1088 else
1089 {
1090 *auth_data_out = out_buffer;
1091 *auth_length_out = out_size;
1092 }
1093
1094 return status;
1095 }
1096
1097 /***********************************************************************
1098 * RPCRT4_default_is_authorized (internal)
1099 *
1100 * Has a connection started the process of authorizing with the server?
1101 */
1102 BOOL RPCRT4_default_is_authorized(RpcConnection *Connection)
1103 {
1104 return Connection->AuthInfo && SecIsValidHandle(&Connection->ctx);
1105 }
1106
1107 /***********************************************************************
1108 * RPCRT4_default_impersonate_client (internal)
1109 *
1110 */
1111 RPC_STATUS RPCRT4_default_impersonate_client(RpcConnection *conn)
1112 {
1113 SECURITY_STATUS sec_status;
1114
1115 TRACE("(%p)\n", conn);
1116
1117 if (!conn->AuthInfo || !SecIsValidHandle(&conn->ctx))
1118 return RPC_S_NO_CONTEXT_AVAILABLE;
1119 sec_status = ImpersonateSecurityContext(&conn->ctx);
1120 if (sec_status != SEC_E_OK)
1121 WARN("ImpersonateSecurityContext returned 0x%08x\n", sec_status);
1122 switch (sec_status)
1123 {
1124 case SEC_E_UNSUPPORTED_FUNCTION:
1125 return RPC_S_CANNOT_SUPPORT;
1126 case SEC_E_NO_IMPERSONATION:
1127 return RPC_S_NO_CONTEXT_AVAILABLE;
1128 case SEC_E_OK:
1129 return RPC_S_OK;
1130 default:
1131 return RPC_S_SEC_PKG_ERROR;
1132 }
1133 }
1134
1135 /***********************************************************************
1136 * RPCRT4_default_revert_to_self (internal)
1137 *
1138 */
1139 RPC_STATUS RPCRT4_default_revert_to_self(RpcConnection *conn)
1140 {
1141 SECURITY_STATUS sec_status;
1142
1143 TRACE("(%p)\n", conn);
1144
1145 if (!conn->AuthInfo || !SecIsValidHandle(&conn->ctx))
1146 return RPC_S_NO_CONTEXT_AVAILABLE;
1147 sec_status = RevertSecurityContext(&conn->ctx);
1148 if (sec_status != SEC_E_OK)
1149 WARN("RevertSecurityContext returned 0x%08x\n", sec_status);
1150 switch (sec_status)
1151 {
1152 case SEC_E_UNSUPPORTED_FUNCTION:
1153 return RPC_S_CANNOT_SUPPORT;
1154 case SEC_E_NO_IMPERSONATION:
1155 return RPC_S_NO_CONTEXT_AVAILABLE;
1156 case SEC_E_OK:
1157 return RPC_S_OK;
1158 default:
1159 return RPC_S_SEC_PKG_ERROR;
1160 }
1161 }
1162
1163 /***********************************************************************
1164 * RPCRT4_default_inquire_auth_client (internal)
1165 *
1166 * Default function to retrieve the authentication details that the client
1167 * is using to call the server.
1168 */
1169 RPC_STATUS RPCRT4_default_inquire_auth_client(
1170 RpcConnection *conn, RPC_AUTHZ_HANDLE *privs, RPC_WSTR *server_princ_name,
1171 ULONG *authn_level, ULONG *authn_svc, ULONG *authz_svc, ULONG flags)
1172 {
1173 if (!conn->AuthInfo) return RPC_S_BINDING_HAS_NO_AUTH;
1174
1175 if (privs)
1176 {
1177 FIXME("privs not implemented\n");
1178 *privs = NULL;
1179 }
1180 if (server_princ_name)
1181 {
1182 *server_princ_name = RPCRT4_strdupW(conn->AuthInfo->server_principal_name);
1183 if (!*server_princ_name) return ERROR_OUTOFMEMORY;
1184 }
1185 if (authn_level) *authn_level = conn->AuthInfo->AuthnLevel;
1186 if (authn_svc) *authn_svc = conn->AuthInfo->AuthnSvc;
1187 if (authz_svc)
1188 {
1189 FIXME("authorization service not implemented\n");
1190 *authz_svc = RPC_C_AUTHZ_NONE;
1191 }
1192 if (flags)
1193 FIXME("flags 0x%x not implemented\n", flags);
1194
1195 return RPC_S_OK;
1196 }
1197
1198 /***********************************************************************
1199 * RPCRT4_Send (internal)
1200 *
1201 * Transmit a packet over connection in acceptable fragments.
1202 */
1203 RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header,
1204 void *Buffer, unsigned int BufferLength)
1205 {
1206 RPC_STATUS r;
1207
1208 if (packet_does_auth_negotiation(Header) &&
1209 Connection->AuthInfo &&
1210 !rpcrt4_conn_is_authorized(Connection))
1211 {
1212 unsigned int out_size = 0;
1213 unsigned char *out_buffer;
1214
1215 r = rpcrt4_conn_authorize(Connection, TRUE, NULL, 0, NULL, &out_size);
1216 if (r != RPC_S_OK) return r;
1217
1218 out_buffer = HeapAlloc(GetProcessHeap(), 0, out_size);
1219 if (!out_buffer) return RPC_S_OUT_OF_RESOURCES;
1220
1221 /* tack on a negotiate packet */
1222 r = rpcrt4_conn_authorize(Connection, TRUE, NULL, 0, out_buffer, &out_size);
1223 if (r == RPC_S_OK)
1224 r = RPCRT4_SendWithAuth(Connection, Header, Buffer, BufferLength, out_buffer, out_size);
1225
1226 HeapFree(GetProcessHeap(), 0, out_buffer);
1227 }
1228 else
1229 r = RPCRT4_SendWithAuth(Connection, Header, Buffer, BufferLength, NULL, 0);
1230
1231 return r;
1232 }
1233
1234 /* validates version and frag_len fields */
1235 RPC_STATUS RPCRT4_ValidateCommonHeader(const RpcPktCommonHdr *hdr)
1236 {
1237 DWORD hdr_length;
1238
1239 /* verify if the header really makes sense */
1240 if (hdr->rpc_ver != RPC_VER_MAJOR ||
1241 hdr->rpc_ver_minor != RPC_VER_MINOR)
1242 {
1243 WARN("unhandled packet version\n");
1244 return RPC_S_PROTOCOL_ERROR;
1245 }
1246
1247 hdr_length = RPCRT4_GetHeaderSize((const RpcPktHdr*)hdr);
1248 if (hdr_length == 0)
1249 {
1250 WARN("header length == 0\n");
1251 return RPC_S_PROTOCOL_ERROR;
1252 }
1253
1254 if (hdr->frag_len < hdr_length)
1255 {
1256 WARN("bad frag length %d\n", hdr->frag_len);
1257 return RPC_S_PROTOCOL_ERROR;
1258 }
1259
1260 return RPC_S_OK;
1261 }
1262
1263 /***********************************************************************
1264 * RPCRT4_default_receive_fragment (internal)
1265 *
1266 * Receive a fragment from a connection.
1267 */
1268 static RPC_STATUS RPCRT4_default_receive_fragment(RpcConnection *Connection, RpcPktHdr **Header, void **Payload)
1269 {
1270 RPC_STATUS status;
1271 DWORD hdr_length;
1272 LONG dwRead;
1273 RpcPktCommonHdr common_hdr;
1274
1275 *Header = NULL;
1276 *Payload = NULL;
1277
1278 TRACE("(%p, %p, %p)\n", Connection, Header, Payload);
1279
1280 /* read packet common header */
1281 dwRead = rpcrt4_conn_read(Connection, &common_hdr, sizeof(common_hdr));
1282 if (dwRead != sizeof(common_hdr)) {
1283 WARN("Short read of header, %d bytes\n", dwRead);
1284 status = RPC_S_CALL_FAILED;
1285 goto fail;
1286 }
1287
1288 status = RPCRT4_ValidateCommonHeader(&common_hdr);
1289 if (status != RPC_S_OK) goto fail;
1290
1291 hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr);
1292 if (hdr_length == 0) {
1293 WARN("header length == 0\n");
1294 status = RPC_S_PROTOCOL_ERROR;
1295 goto fail;
1296 }
1297
1298 *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length);
1299 memcpy(*Header, &common_hdr, sizeof(common_hdr));
1300
1301 /* read the rest of packet header */
1302 dwRead = rpcrt4_conn_read(Connection, &(*Header)->common + 1, hdr_length - sizeof(common_hdr));
1303 if (dwRead != hdr_length - sizeof(common_hdr)) {
1304 WARN("bad header length, %d bytes, hdr_length %d\n", dwRead, hdr_length);
1305 status = RPC_S_CALL_FAILED;
1306 goto fail;
1307 }
1308
1309 if (common_hdr.frag_len - hdr_length)
1310 {
1311 *Payload = HeapAlloc(GetProcessHeap(), 0, common_hdr.frag_len - hdr_length);
1312 if (!*Payload)
1313 {
1314 status = RPC_S_OUT_OF_RESOURCES;
1315 goto fail;
1316 }
1317
1318 dwRead = rpcrt4_conn_read(Connection, *Payload, common_hdr.frag_len - hdr_length);
1319 if (dwRead != common_hdr.frag_len - hdr_length)
1320 {
1321 WARN("bad data length, %d/%d\n", dwRead, common_hdr.frag_len - hdr_length);
1322 status = RPC_S_CALL_FAILED;
1323 goto fail;
1324 }
1325 }
1326 else
1327 *Payload = NULL;
1328
1329 /* success */
1330 status = RPC_S_OK;
1331
1332 fail:
1333 if (status != RPC_S_OK) {
1334 RPCRT4_FreeHeader(*Header);
1335 *Header = NULL;
1336 HeapFree(GetProcessHeap(), 0, *Payload);
1337 *Payload = NULL;
1338 }
1339 return status;
1340 }
1341
1342 static RPC_STATUS RPCRT4_receive_fragment(RpcConnection *Connection, RpcPktHdr **Header, void **Payload)
1343 {
1344 if (Connection->ops->receive_fragment)
1345 return Connection->ops->receive_fragment(Connection, Header, Payload);
1346 else
1347 return RPCRT4_default_receive_fragment(Connection, Header, Payload);
1348 }
1349
1350 /***********************************************************************
1351 * RPCRT4_ReceiveWithAuth (internal)
1352 *
1353 * Receive a packet from connection, merge the fragments and return the auth
1354 * data.
1355 */
1356 RPC_STATUS RPCRT4_ReceiveWithAuth(RpcConnection *Connection, RpcPktHdr **Header,
1357 PRPC_MESSAGE pMsg,
1358 unsigned char **auth_data_out,
1359 ULONG *auth_length_out)
1360 {
1361 RPC_STATUS status;
1362 DWORD hdr_length;
1363 unsigned short first_flag;
1364 ULONG data_length;
1365 ULONG buffer_length;
1366 ULONG auth_length = 0;
1367 unsigned char *auth_data = NULL;
1368 RpcPktHdr *CurrentHeader = NULL;
1369 void *payload = NULL;
1370
1371 *Header = NULL;
1372 pMsg->Buffer = NULL;
1373 if (auth_data_out) *auth_data_out = NULL;
1374 if (auth_length_out) *auth_length_out = 0;
1375
1376 TRACE("(%p, %p, %p, %p)\n", Connection, Header, pMsg, auth_data_out);
1377
1378 RPCRT4_SetThreadCurrentConnection(Connection);
1379
1380 status = RPCRT4_receive_fragment(Connection, Header, &payload);
1381 if (status != RPC_S_OK) goto fail;
1382
1383 hdr_length = RPCRT4_GetHeaderSize(*Header);
1384
1385 /* read packet body */
1386 switch ((*Header)->common.ptype) {
1387 case PKT_RESPONSE:
1388 pMsg->BufferLength = (*Header)->response.alloc_hint;
1389 break;
1390 case PKT_REQUEST:
1391 pMsg->BufferLength = (*Header)->request.alloc_hint;
1392 break;
1393 default:
1394 pMsg->BufferLength = (*Header)->common.frag_len - hdr_length - RPC_AUTH_VERIFIER_LEN(&(*Header)->common);
1395 }
1396
1397 TRACE("buffer length = %u\n", pMsg->BufferLength);
1398
1399 pMsg->Buffer = I_RpcAllocate(pMsg->BufferLength);
1400 if (!pMsg->Buffer)
1401 {
1402 status = ERROR_OUTOFMEMORY;
1403 goto fail;
1404 }
1405
1406 first_flag = RPC_FLG_FIRST;
1407 auth_length = (*Header)->common.auth_len;
1408 if (auth_length) {
1409 auth_data = HeapAlloc(GetProcessHeap(), 0, RPC_AUTH_VERIFIER_LEN(&(*Header)->common));
1410 if (!auth_data) {
1411 status = RPC_S_OUT_OF_RESOURCES;
1412 goto fail;
1413 }
1414 }
1415 CurrentHeader = *Header;
1416 buffer_length = 0;
1417 while (TRUE)
1418 {
1419 unsigned int header_auth_len = RPC_AUTH_VERIFIER_LEN(&CurrentHeader->common);
1420
1421 /* verify header fields */
1422
1423 if ((CurrentHeader->common.frag_len < hdr_length) ||
1424 (CurrentHeader->common.frag_len - hdr_length < header_auth_len)) {
1425 WARN("frag_len %d too small for hdr_length %d and auth_len %d\n",
1426 CurrentHeader->common.frag_len, hdr_length, CurrentHeader->common.auth_len);
1427 status = RPC_S_PROTOCOL_ERROR;
1428 goto fail;
1429 }
1430
1431 if (CurrentHeader->common.auth_len != auth_length) {
1432 WARN("auth_len header field changed from %d to %d\n",
1433 auth_length, CurrentHeader->common.auth_len);
1434 status = RPC_S_PROTOCOL_ERROR;
1435 goto fail;
1436 }
1437
1438 if ((CurrentHeader->common.flags & RPC_FLG_FIRST) != first_flag) {
1439 TRACE("invalid packet flags\n");
1440 status = RPC_S_PROTOCOL_ERROR;
1441 goto fail;
1442 }
1443
1444 data_length = CurrentHeader->common.frag_len - hdr_length - header_auth_len;
1445 if (data_length + buffer_length > pMsg->BufferLength) {
1446 TRACE("allocation hint exceeded, new buffer length = %d\n",
1447 data_length + buffer_length);
1448 pMsg->BufferLength = data_length + buffer_length;
1449 status = I_RpcReAllocateBuffer(pMsg);
1450 if (status != RPC_S_OK) goto fail;
1451 }
1452
1453 memcpy((unsigned char *)pMsg->Buffer + buffer_length, payload, data_length);
1454
1455 if (header_auth_len) {
1456 if (header_auth_len < sizeof(RpcAuthVerifier) ||
1457 header_auth_len > RPC_AUTH_VERIFIER_LEN(&(*Header)->common)) {
1458 WARN("bad auth verifier length %d\n", header_auth_len);
1459 status = RPC_S_PROTOCOL_ERROR;
1460 goto fail;
1461 }
1462
1463 /* FIXME: we should accumulate authentication data for the bind,
1464 * bind_ack, alter_context and alter_context_response if necessary.
1465 * however, the details of how this is done is very sketchy in the
1466 * DCE/RPC spec. for all other packet types that have authentication
1467 * verifier data then it is just duplicated in all the fragments */
1468 memcpy(auth_data, (unsigned char *)payload + data_length, header_auth_len);
1469
1470 /* these packets are handled specially, not by the generic SecurePacket
1471 * function */
1472 if (!packet_does_auth_negotiation(*Header) && rpcrt4_conn_is_authorized(Connection))
1473 {
1474 status = rpcrt4_conn_secure_packet(Connection, SECURE_PACKET_RECEIVE,
1475 CurrentHeader, hdr_length,
1476 (unsigned char *)pMsg->Buffer + buffer_length, data_length,
1477 (RpcAuthVerifier *)auth_data,
1478 auth_data + sizeof(RpcAuthVerifier),
1479 header_auth_len - sizeof(RpcAuthVerifier));
1480 if (status != RPC_S_OK) goto fail;
1481 }
1482 }
1483
1484 buffer_length += data_length;
1485 if (!(CurrentHeader->common.flags & RPC_FLG_LAST)) {
1486 TRACE("next header\n");
1487
1488 if (*Header != CurrentHeader)
1489 {
1490 RPCRT4_FreeHeader(CurrentHeader);
1491 CurrentHeader = NULL;
1492 }
1493 HeapFree(GetProcessHeap(), 0, payload);
1494 payload = NULL;
1495
1496 status = RPCRT4_receive_fragment(Connection, &CurrentHeader, &payload);
1497 if (status != RPC_S_OK) goto fail;
1498
1499 first_flag = 0;
1500 } else {
1501 break;
1502 }
1503 }
1504 pMsg->BufferLength = buffer_length;
1505
1506 /* success */
1507 status = RPC_S_OK;
1508
1509 fail:
1510 RPCRT4_SetThreadCurrentConnection(NULL);
1511 if (CurrentHeader != *Header)
1512 RPCRT4_FreeHeader(CurrentHeader);
1513 if (status != RPC_S_OK) {
1514 I_RpcFree(pMsg->Buffer);
1515 pMsg->Buffer = NULL;
1516 RPCRT4_FreeHeader(*Header);
1517 *Header = NULL;
1518 }
1519 if (auth_data_out && status == RPC_S_OK) {
1520 *auth_length_out = auth_length;
1521 *auth_data_out = auth_data;
1522 }
1523 else
1524 HeapFree(GetProcessHeap(), 0, auth_data);
1525 HeapFree(GetProcessHeap(), 0, payload);
1526 return status;
1527 }
1528
1529 /***********************************************************************
1530 * RPCRT4_Receive (internal)
1531 *
1532 * Receive a packet from connection and merge the fragments.
1533 */
1534 static RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header,
1535 PRPC_MESSAGE pMsg)
1536 {
1537 return RPCRT4_ReceiveWithAuth(Connection, Header, pMsg, NULL, NULL);
1538 }
1539
1540 /***********************************************************************
1541 * I_RpcNegotiateTransferSyntax [RPCRT4.@]
1542 *
1543 * Negotiates the transfer syntax used by a client connection by connecting
1544 * to the server.
1545 *
1546 * PARAMS
1547 * pMsg [I] RPC Message structure.
1548 * pAsync [I] Asynchronous state to set.
1549 *
1550 * RETURNS
1551 * Success: RPC_S_OK.
1552 * Failure: Any error code.
1553 */
1554 RPC_STATUS WINAPI I_RpcNegotiateTransferSyntax(PRPC_MESSAGE pMsg)
1555 {
1556 RpcBinding* bind = pMsg->Handle;
1557 RpcConnection* conn;
1558 RPC_STATUS status = RPC_S_OK;
1559
1560 TRACE("(%p)\n", pMsg);
1561
1562 if (!bind || bind->server)
1563 {
1564 ERR("no binding\n");
1565 return RPC_S_INVALID_BINDING;
1566 }
1567
1568 /* if we already have a connection, we don't need to negotiate again */
1569 if (!pMsg->ReservedForRuntime)
1570 {
1571 RPC_CLIENT_INTERFACE *cif = pMsg->RpcInterfaceInformation;
1572 if (!cif) return RPC_S_INTERFACE_NOT_FOUND;
1573
1574 if (!bind->Endpoint || !bind->Endpoint[0])
1575 {
1576 TRACE("automatically resolving partially bound binding\n");
1577 status = RpcEpResolveBinding(bind, cif);
1578 if (status != RPC_S_OK) return status;
1579 }
1580
1581 status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax,
1582 &cif->InterfaceId);
1583
1584 if (status == RPC_S_OK)
1585 {
1586 pMsg->ReservedForRuntime = conn;
1587 RPCRT4_AddRefBinding(bind);
1588 }
1589 }
1590
1591 return status;
1592 }
1593
1594 /***********************************************************************
1595 * I_RpcGetBuffer [RPCRT4.@]
1596 *
1597 * Allocates a buffer for use by I_RpcSend or I_RpcSendReceive and binds to the
1598 * server interface.
1599 *
1600 * PARAMS
1601 * pMsg [I/O] RPC message information.
1602 *
1603 * RETURNS
1604 * Success: RPC_S_OK.
1605 * Failure: RPC_S_INVALID_BINDING if pMsg->Handle is invalid.
1606 * RPC_S_SERVER_UNAVAILABLE if unable to connect to server.
1607 * ERROR_OUTOFMEMORY if buffer allocation failed.
1608 *
1609 * NOTES
1610 * The pMsg->BufferLength field determines the size of the buffer to allocate,
1611 * in bytes.
1612 *
1613 * Use I_RpcFreeBuffer() to unbind from the server and free the message buffer.
1614 *
1615 * SEE ALSO
1616 * I_RpcFreeBuffer(), I_RpcSend(), I_RpcReceive(), I_RpcSendReceive().
1617 */
1618 RPC_STATUS WINAPI I_RpcGetBuffer(PRPC_MESSAGE pMsg)
1619 {
1620 RPC_STATUS status;
1621 RpcBinding* bind = pMsg->Handle;
1622
1623 TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength);
1624
1625 if (!bind)
1626 {
1627 ERR("no binding\n");
1628 return RPC_S_INVALID_BINDING;
1629 }
1630
1631 pMsg->Buffer = I_RpcAllocate(pMsg->BufferLength);
1632 TRACE("Buffer=%p\n", pMsg->Buffer);
1633
1634 if (!pMsg->Buffer)
1635 return ERROR_OUTOFMEMORY;
1636
1637 if (!bind->server)
1638 {
1639 status = I_RpcNegotiateTransferSyntax(pMsg);
1640 if (status != RPC_S_OK)
1641 I_RpcFree(pMsg->Buffer);
1642 }
1643 else
1644 status = RPC_S_OK;
1645
1646 return status;
1647 }
1648
1649 /***********************************************************************
1650 * I_RpcReAllocateBuffer (internal)
1651 */
1652 static RPC_STATUS I_RpcReAllocateBuffer(PRPC_MESSAGE pMsg)
1653 {
1654 TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength);
1655 pMsg->Buffer = HeapReAlloc(GetProcessHeap(), 0, pMsg->Buffer, pMsg->BufferLength);
1656
1657 TRACE("Buffer=%p\n", pMsg->Buffer);
1658 return pMsg->Buffer ? RPC_S_OK : ERROR_OUTOFMEMORY;
1659 }
1660
1661 /***********************************************************************
1662 * I_RpcFreeBuffer [RPCRT4.@]
1663 *
1664 * Frees a buffer allocated by I_RpcGetBuffer or I_RpcReceive and unbinds from
1665 * the server interface.
1666 *
1667 * PARAMS
1668 * pMsg [I/O] RPC message information.
1669 *
1670 * RETURNS
1671 * RPC_S_OK.
1672 *
1673 * SEE ALSO
1674 * I_RpcGetBuffer(), I_RpcReceive().
1675 */
1676 RPC_STATUS WINAPI I_RpcFreeBuffer(PRPC_MESSAGE pMsg)
1677 {
1678 RpcBinding* bind = pMsg->Handle;
1679
1680 TRACE("(%p) Buffer=%p\n", pMsg, pMsg->Buffer);
1681
1682 if (!bind)
1683 {
1684 ERR("no binding\n");
1685 return RPC_S_INVALID_BINDING;
1686 }
1687
1688 if (pMsg->ReservedForRuntime)
1689 {
1690 RpcConnection *conn = pMsg->ReservedForRuntime;
1691 RPCRT4_CloseBinding(bind, conn);
1692 RPCRT4_ReleaseBinding(bind);
1693 pMsg->ReservedForRuntime = NULL;
1694 }
1695 I_RpcFree(pMsg->Buffer);
1696 return RPC_S_OK;
1697 }
1698
1699 static void CALLBACK async_apc_notifier_proc(ULONG_PTR ulParam)
1700 {
1701 RPC_ASYNC_STATE *state = (RPC_ASYNC_STATE *)ulParam;
1702 state->u.APC.NotificationRoutine(state, NULL, state->Event);
1703 }
1704
1705 static DWORD WINAPI async_notifier_proc(LPVOID p)
1706 {
1707 RpcConnection *conn = p;
1708 RPC_ASYNC_STATE *state = conn->async_state;
1709
1710 if (state && conn->ops->wait_for_incoming_data(conn) != -1)
1711 {
1712 state->Event = RpcCallComplete;
1713 switch (state->NotificationType)
1714 {
1715 case RpcNotificationTypeEvent:
1716 TRACE("RpcNotificationTypeEvent %p\n", state->u.hEvent);
1717 SetEvent(state->u.hEvent);
1718 break;
1719 case RpcNotificationTypeApc:
1720 TRACE("RpcNotificationTypeApc %p\n", state->u.APC.hThread);
1721 QueueUserAPC(async_apc_notifier_proc, state->u.APC.hThread, (ULONG_PTR)state);
1722 break;
1723 case RpcNotificationTypeIoc:
1724 TRACE("RpcNotificationTypeIoc %p, 0x%x, 0x%lx, %p\n",
1725 state->u.IOC.hIOPort, state->u.IOC.dwNumberOfBytesTransferred,
1726 state->u.IOC.dwCompletionKey, state->u.IOC.lpOverlapped);
1727 PostQueuedCompletionStatus(state->u.IOC.hIOPort,
1728 state->u.IOC.dwNumberOfBytesTransferred,
1729 state->u.IOC.dwCompletionKey,
1730 state->u.IOC.lpOverlapped);
1731 break;
1732 case RpcNotificationTypeHwnd:
1733 TRACE("RpcNotificationTypeHwnd %p 0x%x\n", state->u.HWND.hWnd,
1734 state->u.HWND.Msg);
1735 PostMessageW(state->u.HWND.hWnd, state->u.HWND.Msg, 0, 0);
1736 break;
1737 case RpcNotificationTypeCallback:
1738 TRACE("RpcNotificationTypeCallback %p\n", state->u.NotificationRoutine);
1739 state->u.NotificationRoutine(state, NULL, state->Event);
1740 break;
1741 case RpcNotificationTypeNone:
1742 TRACE("RpcNotificationTypeNone\n");
1743 break;
1744 default:
1745 FIXME("unknown NotificationType: %d/0x%x\n", state->NotificationType, state->NotificationType);
1746 break;
1747 }
1748 }
1749
1750 return 0;
1751 }
1752
1753 /***********************************************************************
1754 * I_RpcSend [RPCRT4.@]
1755 *
1756 * Sends a message to the server.
1757 *
1758 * PARAMS
1759 * pMsg [I/O] RPC message information.
1760 *
1761 * RETURNS
1762 * Unknown.
1763 *
1764 * NOTES
1765 * The buffer must have been allocated with I_RpcGetBuffer().
1766 *
1767 * SEE ALSO
1768 * I_RpcGetBuffer(), I_RpcReceive(), I_RpcSendReceive().
1769 */
1770 RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg)
1771 {
1772 RpcBinding* bind = pMsg->Handle;
1773 RpcConnection* conn;
1774 RPC_STATUS status;
1775 RpcPktHdr *hdr;
1776
1777 TRACE("(%p)\n", pMsg);
1778 if (!bind || bind->server || !pMsg->ReservedForRuntime) return RPC_S_INVALID_BINDING;
1779
1780 conn = pMsg->ReservedForRuntime;
1781
1782 hdr = RPCRT4_BuildRequestHeader(pMsg->DataRepresentation,
1783 pMsg->BufferLength,
1784 pMsg->ProcNum & ~RPC_FLAGS_VALID_BIT,
1785 &bind->ObjectUuid);
1786 if (!hdr)
1787 return ERROR_OUTOFMEMORY;
1788 hdr->common.call_id = conn->NextCallId++;
1789
1790 status = RPCRT4_Send(conn, hdr, pMsg->Buffer, pMsg->BufferLength);
1791
1792 RPCRT4_FreeHeader(hdr);
1793
1794 if (status == RPC_S_OK && pMsg->RpcFlags & RPC_BUFFER_ASYNC)
1795 {
1796 if (!QueueUserWorkItem(async_notifier_proc, conn, WT_EXECUTEDEFAULT | WT_EXECUTELONGFUNCTION))
1797 status = RPC_S_OUT_OF_RESOURCES;
1798 }
1799
1800 return status;
1801 }
1802
1803 /* is this status something that the server can't recover from? */
1804 static inline BOOL is_hard_error(RPC_STATUS status)
1805 {
1806 switch (status)
1807 {
1808 case 0: /* user-defined fault */
1809 case ERROR_ACCESS_DENIED:
1810 case ERROR_INVALID_PARAMETER:
1811 case RPC_S_PROTOCOL_ERROR:
1812 case RPC_S_CALL_FAILED:
1813 case RPC_S_CALL_FAILED_DNE:
1814 case RPC_S_SEC_PKG_ERROR:
1815 return TRUE;
1816 default:
1817 return FALSE;
1818 }
1819 }
1820
1821 /***********************************************************************
1822 * I_RpcReceive [RPCRT4.@]
1823 */
1824 RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg)
1825 {
1826 RpcBinding* bind = pMsg->Handle;
1827 RPC_STATUS status;
1828 RpcPktHdr *hdr = NULL;
1829 RpcConnection *conn;
1830
1831 TRACE("(%p)\n", pMsg);
1832 if (!bind || bind->server || !pMsg->ReservedForRuntime) return RPC_S_INVALID_BINDING;
1833
1834 conn = pMsg->ReservedForRuntime;
1835 status = RPCRT4_Receive(conn, &hdr, pMsg);
1836 if (status != RPC_S_OK) {
1837 WARN("receive failed with error %x\n", status);
1838 goto fail;
1839 }
1840
1841 switch (hdr->common.ptype) {
1842 case PKT_RESPONSE:
1843 break;
1844 case PKT_FAULT:
1845 ERR ("we got fault packet with status 0x%x\n", hdr->fault.status);
1846 status = NCA2RPC_STATUS(hdr->fault.status);
1847 if (is_hard_error(status))
1848 goto fail;
1849 break;
1850 default:
1851 WARN("bad packet type %d\n", hdr->common.ptype);
1852 status = RPC_S_PROTOCOL_ERROR;
1853 goto fail;
1854 }
1855
1856 /* success */
1857 RPCRT4_FreeHeader(hdr);
1858 return status;
1859
1860 fail:
1861 RPCRT4_FreeHeader(hdr);
1862 RPCRT4_ReleaseConnection(conn);
1863 pMsg->ReservedForRuntime = NULL;
1864 return status;
1865 }
1866
1867 /***********************************************************************
1868 * I_RpcSendReceive [RPCRT4.@]
1869 *
1870 * Sends a message to the server and receives the response.
1871 *
1872 * PARAMS
1873 * pMsg [I/O] RPC message information.
1874 *
1875 * RETURNS
1876 * Success: RPC_S_OK.
1877 * Failure: Any error code.
1878 *
1879 * NOTES
1880 * The buffer must have been allocated with I_RpcGetBuffer().
1881 *
1882 * SEE ALSO
1883 * I_RpcGetBuffer(), I_RpcSend(), I_RpcReceive().
1884 */
1885 RPC_STATUS WINAPI I_RpcSendReceive(PRPC_MESSAGE pMsg)
1886 {
1887 RPC_STATUS status;
1888 void *original_buffer;
1889
1890 TRACE("(%p)\n", pMsg);
1891
1892 original_buffer = pMsg->Buffer;
1893 status = I_RpcSend(pMsg);
1894 if (status == RPC_S_OK)
1895 status = I_RpcReceive(pMsg);
1896 /* free the buffer replaced by a new buffer in I_RpcReceive */
1897 if (status == RPC_S_OK)
1898 I_RpcFree(original_buffer);
1899 return status;
1900 }
1901
1902 /***********************************************************************
1903 * I_RpcAsyncSetHandle [RPCRT4.@]
1904 *
1905 * Sets the asynchronous state of the handle contained in the RPC message
1906 * structure.
1907 *
1908 * PARAMS
1909 * pMsg [I] RPC Message structure.
1910 * pAsync [I] Asynchronous state to set.
1911 *
1912 * RETURNS
1913 * Success: RPC_S_OK.
1914 * Failure: Any error code.
1915 */
1916 RPC_STATUS WINAPI I_RpcAsyncSetHandle(PRPC_MESSAGE pMsg, PRPC_ASYNC_STATE pAsync)
1917 {
1918 RpcBinding* bind = pMsg->Handle;
1919 RpcConnection *conn;
1920
1921 TRACE("(%p, %p)\n", pMsg, pAsync);
1922
1923 if (!bind || bind->server || !pMsg->ReservedForRuntime) return RPC_S_INVALID_BINDING;
1924
1925 conn = pMsg->ReservedForRuntime;
1926 conn->async_state = pAsync;
1927
1928 return RPC_S_OK;
1929 }
1930
1931 /***********************************************************************
1932 * I_RpcAsyncAbortCall [RPCRT4.@]
1933 *
1934 * Aborts an asynchronous call.
1935 *
1936 * PARAMS
1937 * pAsync [I] Asynchronous state.
1938 * ExceptionCode [I] Exception code.
1939 *
1940 * RETURNS
1941 * Success: RPC_S_OK.
1942 * Failure: Any error code.
1943 */
1944 RPC_STATUS WINAPI I_RpcAsyncAbortCall(PRPC_ASYNC_STATE pAsync, ULONG ExceptionCode)
1945 {
1946 FIXME("(%p, %d): stub\n", pAsync, ExceptionCode);
1947 return RPC_S_INVALID_ASYNC_HANDLE;
1948 }