modified: myjupyterlab.sh
[GalaxyCodeBases.git] / etc / Windows / vlmcsd_old_vancepym / rpc.c
blob0ac8ef0c543646baf40d47f6fcba3022b82f1e9b
1 #ifndef _DEFAULT_SOURCE
2 #define _DEFAULT_SOURCE
3 #endif // _DEFAULT_SOURCE
5 #ifndef CONFIG
6 #define CONFIG "config.h"
7 #endif // CONFIG
8 #include CONFIG
10 #ifndef USE_MSRPC
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdint.h>
16 #include <ctype.h>
17 #include <time.h>
18 #if !defined(_WIN32)
19 #include <sys/socket.h>
20 #include <netdb.h>
21 #endif
22 #include "rpc.h"
23 #include "output.h"
24 #include "crypto.h"
25 #include "endian.h"
26 #include "helpers.h"
27 #include "network.h"
28 #include "shared_globals.h"
30 /* Forwards */
32 static int checkRpcHeader(const RPC_HEADER *const Header, const BYTE desiredPacketType, const PRINTFUNC p);
35 /* Data definitions */
37 // All GUIDs are defined as BYTE[16] here. No big-endian/little-endian byteswapping required.
38 static const BYTE TransferSyntaxNDR32[] = {
39 0x04, 0x5D, 0x88, 0x8A, 0xEB, 0x1C, 0xC9, 0x11, 0x9F, 0xE8, 0x08, 0x00, 0x2B, 0x10, 0x48, 0x60
42 static const BYTE InterfaceUuid[] = {
43 0x75, 0x21, 0xc8, 0x51, 0x4e, 0x84, 0x50, 0x47, 0xB0, 0xD8, 0xEC, 0x25, 0x55, 0x55, 0xBC, 0x06
46 static const BYTE TransferSyntaxNDR64[] = {
47 0x33, 0x05, 0x71, 0x71, 0xba, 0xbe, 0x37, 0x49, 0x83, 0x19, 0xb5, 0xdb, 0xef, 0x9c, 0xcc, 0x36
50 static const BYTE BindTimeFeatureNegotiation[] = {
51 0x2c, 0x1c, 0xb7, 0x6c, 0x12, 0x98, 0x40, 0x45, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
56 // Dispatch RPC payload to kms.c
58 typedef int (*CreateResponse_t)(const void *const, void *const, const char* const);
60 static const struct {
61 unsigned int RequestSize;
62 CreateResponse_t CreateResponse;
63 } _Versions[] = {
64 { sizeof(REQUEST_V4), (CreateResponse_t) CreateResponseV4 },
65 { sizeof(REQUEST_V6), (CreateResponse_t) CreateResponseV6 },
66 { sizeof(REQUEST_V6), (CreateResponse_t) CreateResponseV6 }
69 RPC_FLAGS RpcFlags;
70 static int_fast8_t firstPacketSent;
73 // RPC request (server)
75 #if defined(_PEDANTIC) && !defined(NO_LOG)
76 static void CheckRpcRequest(const RPC_REQUEST64 *const Request, const unsigned int len, WORD* NdrCtx, WORD* Ndr64Ctx, WORD Ctx)
78 uint_fast8_t kmsMajorVersion;
79 uint32_t requestSize = Ctx != *Ndr64Ctx ? sizeof(RPC_REQUEST) : sizeof(RPC_REQUEST64);
81 if (len < requestSize)
83 logger("Fatal: RPC request (including header) must be at least %i bytes but is only %i bytes.\n",
84 (int)(sizeof(RPC_HEADER) + requestSize),
85 (int)(len + sizeof(RPC_HEADER))
88 return;
91 if (len < requestSize + sizeof(DWORD))
93 logger("Fatal: KMS Request too small to contain version info (less than 4 bytes).\n");
94 return;
97 if (Ctx != *Ndr64Ctx)
98 kmsMajorVersion = LE16(((WORD*)Request->Ndr.Data)[1]);
99 else
100 kmsMajorVersion = LE16(((WORD*)Request->Ndr64.Data)[1]);
102 if (kmsMajorVersion > 6)
104 logger("Fatal: KMSv%u is not supported.\n", (unsigned int)kmsMajorVersion);
106 else
108 if (len >_Versions[kmsMajorVersion].RequestSize + requestSize)
109 logger("Warning: %u excess bytes in RPC request.\n",
110 len - _Versions[kmsMajorVersion].RequestSize
114 if (Ctx != *Ndr64Ctx && Ctx != *NdrCtx)
115 logger("Warning: Context id should be %u (NDR32) or %u (NDR64) but is %u.\n",
116 (unsigned int)*NdrCtx,
117 (unsigned int)*Ndr64Ctx,
121 if (Request->Opnum)
122 logger("Warning: OpNum should be 0 but is %u.\n",
123 (unsigned int)LE16(Request->Opnum)
126 if (LE32(Request->AllocHint) != len - sizeof(RPC_REQUEST) + sizeof(Request->Ndr))
127 logger("Warning: Allocation hint should be %u but is %u.\n",
128 len + sizeof(Request->Ndr),
129 LE32(Request->AllocHint)
132 if (Ctx != *Ndr64Ctx)
134 if (LE32(Request->Ndr.DataLength) != len - sizeof(RPC_REQUEST))
135 logger("Warning: NDR32 data length field should be %u but is %u.\n",
136 len - sizeof(RPC_REQUEST),
137 LE32(Request->Ndr.DataLength)
140 if (LE32(Request->Ndr.DataSizeIs) != len - sizeof(RPC_REQUEST))
141 logger("Warning: NDR32 data size field should be %u but is %u.\n",
142 len - sizeof(RPC_REQUEST),
143 LE32(Request->Ndr.DataSizeIs)
146 else
148 if (LE64(Request->Ndr64.DataLength) != len - sizeof(RPC_REQUEST64))
149 logger("Warning: NDR32 data length field should be %u but is %u.\n",
150 len - sizeof(RPC_REQUEST) + sizeof(Request->Ndr),
151 LE64(Request->Ndr64.DataLength)
154 if (LE64(Request->Ndr64.DataSizeIs) != len - sizeof(RPC_REQUEST64))
155 logger("Warning: NDR32 data size field should be %u but is %u.\n",
156 len - sizeof(RPC_REQUEST64),
157 LE64(Request->Ndr64.DataSizeIs)
161 #endif // defined(_PEDANTIC) && !defined(NO_LOG)
164 * check RPC request for (somewhat) correct size
165 * allow any size that does not cause CreateResponse to fail badly
167 static unsigned int checkRpcRequestSize(const RPC_REQUEST64 *const Request, const unsigned int requestSize, WORD* NdrCtx, WORD* Ndr64Ctx)
169 WORD Ctx = LE16(Request->ContextId);
171 # if defined(_PEDANTIC) && !defined(NO_LOG)
172 CheckRpcRequest(Request, requestSize, NdrCtx, Ndr64Ctx, Ctx);
173 # endif // defined(_PEDANTIC) && !defined(NO_LOG)
175 // Anything that is smaller than a v4 request is illegal
176 if (requestSize < sizeof(REQUEST_V4) + (Ctx != *Ndr64Ctx ? sizeof(RPC_REQUEST) : sizeof(RPC_REQUEST64))) return 0;
178 // Get KMS major version
179 uint_fast16_t _v;
181 if (Ctx != *Ndr64Ctx)
182 _v = LE16(((WORD*)Request->Ndr.Data)[1]) - 4;
183 else
184 _v = LE16(((WORD*)Request->Ndr64.Data)[1]) - 4;
186 // Only KMS v4, v5 and v6 are supported
187 if (_v >= vlmcsd_countof(_Versions))
189 # ifndef NO_LOG
190 logger("Fatal: KMSv%i unsupported\n", _v + 4);
191 # endif // NO_LOG
192 return 0;
195 // Could check for equality but allow bigger requests to support buggy RPC clients (e.g. wine)
196 // Buffer overrun is check by caller.
197 return (requestSize >= _Versions[_v].RequestSize);
202 * Handles the actual KMS request from the client.
203 * Calls KMS functions (CreateResponseV4 or CreateResponseV6) in kms.c
204 * Returns size of the KMS response packet or 0 on failure.
206 * The RPC packet size (excluding header) is actually in Response->AllocHint
208 static int rpcRequest(const RPC_REQUEST64 *const Request, RPC_RESPONSE64 *const Response, const DWORD RpcAssocGroup_unused, const SOCKET sock_unused, WORD* NdrCtx, WORD* Ndr64Ctx, BYTE packetType, const char* const ipstr)
210 uint_fast16_t _v;
211 int ResponseSize;
212 WORD Ctx = LE16(Request->ContextId);
213 BYTE* requestData;
214 BYTE* responseData;
215 BYTE* pRpcReturnCode;
216 int len;
218 if (Ctx != *Ndr64Ctx)
220 requestData = (BYTE*)&Request->Ndr.Data;
221 responseData = (BYTE*)&Response->Ndr.Data;
223 else
225 requestData = (BYTE*)&Request->Ndr64.Data;
226 responseData = (BYTE*)&Response->Ndr64.Data;
229 _v = LE16(((WORD*)requestData)[1]) - 4;
231 if (!(ResponseSize = _Versions[_v].CreateResponse(requestData, responseData, ipstr)))
233 return 0;
236 if (Ctx != *Ndr64Ctx)
238 Response->Ndr.DataSizeMax = LE32(0x00020000);
239 Response->Ndr.DataLength = Response->Ndr.DataSizeIs = LE32(ResponseSize);
240 len = ResponseSize + sizeof(Response->Ndr);
242 else
244 Response->Ndr64.DataSizeMax = LE64(0x00020000ULL);
245 Response->Ndr64.DataLength = Response->Ndr64.DataSizeIs = LE64((uint64_t)ResponseSize);
246 len = ResponseSize + sizeof(Response->Ndr64);
249 pRpcReturnCode = ((BYTE*)&Response->Ndr) + len;
250 UA32(pRpcReturnCode) = 0; //LE32 not needed for 0
251 len += sizeof(DWORD);
253 // Pad zeros to 32-bit align (seems not neccassary but Windows RPC does it this way)
254 int pad = ((~len & 3) + 1) & 3;
255 memset(pRpcReturnCode + sizeof(DWORD), 0, pad);
256 len += pad;
258 Response->AllocHint = LE32(len);
259 Response->ContextId = Request->ContextId;
261 *((WORD*)&Response->CancelCount) = 0; // CancelCount + Pad1
263 return len + 8;
267 #if defined(_PEDANTIC) && !defined(NO_LOG)
268 static void CheckRpcBindRequest(const RPC_BIND_REQUEST *const Request, const unsigned int len)
270 uint_fast8_t i, HasTransferSyntaxNDR32 = FALSE;
271 char guidBuffer1[GUID_STRING_LENGTH + 1], guidBuffer2[GUID_STRING_LENGTH + 1];
273 uint32_t CapCtxItems = (len - sizeof(*Request) + sizeof(Request->CtxItems)) / sizeof(Request->CtxItems);
274 DWORD NumCtxItems = LE32(Request->NumCtxItems);
276 if (NumCtxItems < CapCtxItems) // Can't be too small because already handled by RpcBindSize
277 logger("Warning: Excess bytes in RPC bind request.\n");
279 for (i = 0; i < NumCtxItems; i++)
281 if (!IsEqualGUID(&Request->CtxItems[i].InterfaceUUID, InterfaceUuid))
283 uuid2StringLE((GUID*)&Request->CtxItems[i].InterfaceUUID, guidBuffer1);
284 uuid2StringLE((GUID*)InterfaceUuid, guidBuffer2);
285 logger("Warning: Interface UUID is %s but should be %s in Ctx item %u.\n", guidBuffer1, guidBuffer2, (unsigned int)i);
288 if (Request->CtxItems[i].NumTransItems != LE16(1))
289 logger("Fatal: %u NDR32 transfer items detected in Ctx item %u, but only one is supported.\n",
290 (unsigned int)LE16(Request->CtxItems[i].NumTransItems), (unsigned int)i
293 if (Request->CtxItems[i].InterfaceVerMajor != LE16(1) || Request->CtxItems[i].InterfaceVerMinor != 0)
294 logger("Warning: NDR32 Interface version is %u.%u but should be 1.0.\n",
295 (unsigned int)LE16(Request->CtxItems[i].InterfaceVerMajor),
296 (unsigned int)LE16(Request->CtxItems[i].InterfaceVerMinor)
299 if (Request->CtxItems[i].ContextId != LE16((WORD)i))
300 logger("Warning: context id of Ctx item %u is %u.\n", (unsigned int)i, (unsigned int)Request->CtxItems[i].ContextId);
302 if ( IsEqualGUID((GUID*)TransferSyntaxNDR32, &Request->CtxItems[i].TransferSyntax) )
304 HasTransferSyntaxNDR32 = TRUE;
306 if (Request->CtxItems[i].SyntaxVersion != LE32(2))
307 logger("NDR32 transfer syntax version is %u but should be 2.\n", LE32(Request->CtxItems[i].SyntaxVersion));
309 else if ( IsEqualGUID((GUID*)TransferSyntaxNDR64, &Request->CtxItems[i].TransferSyntax) )
311 if (Request->CtxItems[i].SyntaxVersion != LE32(1))
312 logger("NDR64 transfer syntax version is %u but should be 1.\n", LE32(Request->CtxItems[i].SyntaxVersion));
314 else if (!memcmp(BindTimeFeatureNegotiation, (BYTE*)(&Request->CtxItems[i].TransferSyntax), 8))
316 if (Request->CtxItems[i].SyntaxVersion != LE32(1))
317 logger("BTFN syntax version is %u but should be 1.\n", LE32(Request->CtxItems[i].SyntaxVersion));
321 if (!HasTransferSyntaxNDR32)
322 logger("Warning: RPC bind request has no NDR32 CtxItem.\n");
324 #endif // defined(_PEDANTIC) && !defined(NO_LOG)
328 * Check, if we receive enough bytes to return a valid RPC bind response
330 static unsigned int checkRpcBindSize(const RPC_BIND_REQUEST *const Request, const unsigned int RequestSize, WORD* NdrCtx, WORD* Ndr64Ctx)
332 if ( RequestSize < sizeof(RPC_BIND_REQUEST) ) return FALSE;
334 unsigned int _NumCtxItems = LE32(Request->NumCtxItems);
336 if ( RequestSize < sizeof(RPC_BIND_REQUEST) - sizeof(Request->CtxItems[0]) + _NumCtxItems * sizeof(Request->CtxItems[0]) ) return FALSE;
338 #if defined(_PEDANTIC) && !defined(NO_LOG)
339 CheckRpcBindRequest(Request, RequestSize);
340 #endif // defined(_PEDANTIC) && !defined(NO_LOG)
342 return TRUE;
347 * Accepts a bind or alter context request from the client and composes the bind response.
348 * Needs the socket because the tcp port number is part of the response.
349 * len is not used here.
351 * Returns TRUE on success.
353 static int rpcBind(const RPC_BIND_REQUEST *const Request, RPC_BIND_RESPONSE* Response, const DWORD RpcAssocGroup, const SOCKET sock, WORD* NdrCtx, WORD* Ndr64Ctx, BYTE packetType, const char* const ipstr_unused)
355 unsigned int i, _st = FALSE;
356 DWORD numCtxItems = LE32(Request->NumCtxItems);
357 int_fast8_t IsNDR64possible = FALSE;
358 uint_fast8_t portNumberSize;
360 socklen_t socklen;
361 struct sockaddr_storage addr;
363 // M$ RPC does not do this. Pad bytes contain apparently random data
364 // memset(Response->SecondaryAddress, 0, sizeof(Response->SecondaryAddress));
366 socklen = sizeof addr;
368 if (
369 packetType == RPC_PT_ALTERCONTEXT_REQ ||
370 getsockname(sock, (struct sockaddr*)&addr, &socklen) ||
371 getnameinfo((struct sockaddr*)&addr, socklen, NULL, 0, (char*)Response->SecondaryAddress, sizeof(Response->SecondaryAddress), NI_NUMERICSERV))
373 portNumberSize = Response->SecondaryAddressLength = 0;
375 else
377 portNumberSize = strlen((char*)Response->SecondaryAddress) + 1;
378 Response->SecondaryAddressLength = LE16(portNumberSize);
381 Response->MaxXmitFrag = Request->MaxXmitFrag;
382 Response->MaxRecvFrag = Request->MaxRecvFrag;
383 Response->AssocGroup = LE32(RpcAssocGroup);
385 // This is really ugly (but efficient) code to support padding after the secondary address field
386 if (portNumberSize < 3)
388 Response = (RPC_BIND_RESPONSE*)((BYTE*)Response - 4);
391 Response->NumResults = Request->NumCtxItems;
393 if (UseRpcNDR64)
395 for (i = 0; i < numCtxItems; i++)
397 if ( IsEqualGUID((GUID*)TransferSyntaxNDR32, &Request->CtxItems[i].TransferSyntax) )
399 /*if (packetType == RPC_PT_BIND_REQ)*/
400 *NdrCtx = LE16(Request->CtxItems[i].ContextId);
403 if ( IsEqualGUID((GUID*)TransferSyntaxNDR64, &Request->CtxItems[i].TransferSyntax) )
405 IsNDR64possible = TRUE;
407 /*if (packetType == RPC_PT_BIND_REQ)*/
408 *Ndr64Ctx = LE16(Request->CtxItems[i].ContextId);
413 for (i = 0; i < numCtxItems; i++)
415 memset(&Response->Results[i].TransferSyntax, 0, sizeof(GUID));
417 if ( !IsNDR64possible && IsEqualGUID((GUID*)TransferSyntaxNDR32, &Request->CtxItems[i].TransferSyntax) )
419 Response->Results[i].SyntaxVersion = LE32(2);
420 Response->Results[i].AckResult =
421 Response->Results[i].AckReason = RPC_BIND_ACCEPT;
422 memcpy(&Response->Results[i].TransferSyntax, TransferSyntaxNDR32, sizeof(GUID));
424 _st = TRUE;
426 else if ( IsNDR64possible && IsEqualGUID((GUID*)TransferSyntaxNDR64, &Request->CtxItems[i].TransferSyntax) )
428 Response->Results[i].SyntaxVersion = LE32(1);
429 Response->Results[i].AckResult =
430 Response->Results[i].AckReason = RPC_BIND_ACCEPT;
431 memcpy(&Response->Results[i].TransferSyntax, TransferSyntaxNDR64, sizeof(GUID));
433 _st = TRUE;
435 else if ( UseRpcBTFN && !memcmp(BindTimeFeatureNegotiation, (BYTE*)(&Request->CtxItems[i].TransferSyntax), 8) )
437 Response->Results[i].SyntaxVersion = 0;
438 Response->Results[i].AckResult = RPC_BIND_ACK;
440 // Features requested are actually encoded in the GUID
441 Response->Results[i].AckReason =
442 ((WORD*)(&Request->CtxItems[i].TransferSyntax))[4] &
443 (RPC_BTFN_SEC_CONTEXT_MULTIPLEX | RPC_BTFN_KEEP_ORPHAN);
445 else
447 Response->Results[i].SyntaxVersion = 0;
448 Response->Results[i].AckResult =
449 Response->Results[i].AckReason = RPC_BIND_NACK; // Unsupported
453 if ( !_st ) return 0;
455 return sizeof(RPC_BIND_RESPONSE) + numCtxItems * sizeof(((RPC_BIND_RESPONSE *)0)->Results[0]) - (portNumberSize < 3 ? 4 : 0);
460 // Main RPC handling routine
462 typedef unsigned int (*GetResponseSize_t)(const void *const request, const unsigned int requestSize, WORD* NdrCtx, WORD* Ndr64Ctx);
463 typedef int (*GetResponse_t)(const void* const request, void* response, const DWORD rpcAssocGroup, const SOCKET socket, WORD* NdrCtx, WORD* Ndr64Ctx, BYTE packetType, const char* const ipstr);
465 static const struct {
466 BYTE ResponsePacketType;
467 GetResponseSize_t CheckRequestSize;
468 GetResponse_t GetResponse;
470 _Actions[] = {
471 { RPC_PT_BIND_ACK, (GetResponseSize_t)checkRpcBindSize, (GetResponse_t) rpcBind },
472 { RPC_PT_RESPONSE, (GetResponseSize_t)checkRpcRequestSize, (GetResponse_t) rpcRequest },
473 { RPC_PT_ALTERCONTEXT_ACK, (GetResponseSize_t)checkRpcBindSize, (GetResponse_t) rpcBind },
478 * This is the main RPC server loop. Returns after KMS request has been serviced
479 * or a timeout has occured.
481 void rpcServer(const SOCKET sock, const DWORD RpcAssocGroup, const char* const ipstr)
483 RPC_HEADER rpcRequestHeader;
484 WORD NdrCtx = INVALID_NDR_CTX, Ndr64Ctx = INVALID_NDR_CTX;
486 randomNumberInit();
488 while (_recv(sock, &rpcRequestHeader, sizeof(rpcRequestHeader)))
490 //int_fast8_t _st;
491 unsigned int request_len, response_len;
492 uint_fast8_t _a;
494 #if defined(_PEDANTIC) && !defined(NO_LOG)
495 checkRpcHeader(&rpcRequestHeader, rpcRequestHeader.PacketType, &logger);
496 #endif // defined(_PEDANTIC) && !defined(NO_LOG)
498 switch (rpcRequestHeader.PacketType)
500 case RPC_PT_BIND_REQ: _a = 0; break;
501 case RPC_PT_REQUEST: _a = 1; break;
502 case RPC_PT_ALTERCONTEXT_REQ: _a = 2; break;
503 default: return;
506 request_len = LE16(rpcRequestHeader.FragLength) - sizeof(rpcRequestHeader);
508 BYTE requestBuffer[MAX_REQUEST_SIZE + sizeof(RPC_RESPONSE64)];
509 BYTE responseBuffer[MAX_RESPONSE_SIZE + sizeof(RPC_HEADER) + sizeof(RPC_RESPONSE64)];
511 RPC_HEADER *rpcResponseHeader = (RPC_HEADER *)responseBuffer;
512 RPC_RESPONSE* rpcResponse = (RPC_RESPONSE*)(responseBuffer + sizeof(rpcRequestHeader));
514 // The request is larger than the buffer size
515 if (request_len > MAX_REQUEST_SIZE + sizeof(RPC_REQUEST64)) return;
517 // Unable to receive the complete request
518 if (!_recv(sock, requestBuffer, request_len)) return;
520 // Request is invalid
521 if (!_Actions[_a].CheckRequestSize(requestBuffer, request_len, &NdrCtx, &Ndr64Ctx)) return;
523 // Unable to create a valid response from request
524 if (!(response_len = _Actions[_a].GetResponse(requestBuffer, rpcResponse, RpcAssocGroup, sock, &NdrCtx, &Ndr64Ctx, rpcRequestHeader.PacketType, ipstr))) return;
526 response_len += sizeof(RPC_HEADER);
528 memcpy(rpcResponseHeader, &rpcRequestHeader, sizeof(RPC_HEADER));
530 rpcResponseHeader->FragLength = LE16(response_len);
531 rpcResponseHeader->PacketType = _Actions[_a].ResponsePacketType;
533 if (rpcResponseHeader->PacketType == RPC_PT_ALTERCONTEXT_ACK)
534 rpcResponseHeader->PacketFlags = RPC_PF_FIRST | RPC_PF_LAST;
536 if (!_send(sock, responseBuffer, response_len)) return;
538 if (DisconnectImmediately && rpcResponseHeader->PacketType == RPC_PT_RESPONSE)
539 shutdown(sock, VLMCSD_SHUT_RDWR);
544 /* RPC client functions */
546 static DWORD CallId = 2; // M$ starts with CallId 2. So we do the same.
550 * Checks RPC header. Returns 0 on success.
551 * This is mainly for debugging a non Microsoft KMS server that uses its own RPC code.
553 static int checkRpcHeader(const RPC_HEADER *const Header, const BYTE desiredPacketType, const PRINTFUNC p)
555 int status = 0;
557 if (Header->PacketType != desiredPacketType)
559 p("Fatal: Received wrong RPC packet type. Expected %u but got %u\n",
560 (uint32_t)desiredPacketType,
561 Header->PacketType
563 status = !0;
566 if (Header->DataRepresentation != BE32(0x10000000))
568 p("Fatal: RPC response does not conform to Microsoft's limited support of DCE RPC\n");
569 status = !0;
572 if (Header->AuthLength != 0)
574 p("Fatal: RPC response requests authentication\n");
575 status = !0;
578 // vlmcsd does not support fragmented packets (not yet neccassary)
579 if ( (Header->PacketFlags & (RPC_PF_FIRST | RPC_PF_LAST)) != (RPC_PF_FIRST | RPC_PF_LAST) )
581 p("Fatal: RPC packet flags RPC_PF_FIRST and RPC_PF_LAST are not both set.\n");
582 status = !0;
585 if (Header->PacketFlags & RPC_PF_CANCEL_PENDING) p("Warning: %s should not be set\n", "RPC_PF_CANCEL_PENDING");
586 if (Header->PacketFlags & RPC_PF_RESERVED) p("Warning: %s should not be set\n", "RPC_PF_RESERVED");
587 if (Header->PacketFlags & RPC_PF_NOT_EXEC) p("Warning: %s should not be set\n", "RPC_PF_NOT_EXEC");
588 if (Header->PacketFlags & RPC_PF_MAYBE) p("Warning: %s should not be set\n", "RPC_PF_MAYBE");
589 if (Header->PacketFlags & RPC_PF_OBJECT) p("Warning: %s should not be set\n", "RPC_PF_OBJECT");
591 if (Header->VersionMajor != 5 || Header->VersionMinor != 0)
593 p("Fatal: Expected RPC version 5.0 and got %u.%u\n", Header->VersionMajor, Header->VersionMinor);
594 status = !0;
597 return status;
602 * Checks an RPC response header. Does basic header checks by calling checkRpcHeader()
603 * and then does additional checks if response header complies with the respective request header.
604 * PRINTFUNC p can be anything that has the same prototype as printf.
605 * Returns 0 on success.
607 static int checkRpcResponseHeader(const RPC_HEADER *const ResponseHeader, const RPC_HEADER *const RequestHeader, const BYTE desiredPacketType, const PRINTFUNC p)
609 static int_fast8_t WineBugDetected = FALSE;
610 int status = checkRpcHeader(ResponseHeader, desiredPacketType, p);
612 if (desiredPacketType == RPC_PT_BIND_ACK)
614 if ((ResponseHeader->PacketFlags & RPC_PF_MULTIPLEX) != (RequestHeader->PacketFlags & RPC_PF_MULTIPLEX))
616 p("Warning: RPC_PF_MULTIPLEX of RPC request and response should match\n");
619 else
621 if (ResponseHeader->PacketFlags & RPC_PF_MULTIPLEX)
623 p("Warning: %s should not be set\n", "RPC_PF_MULTIPLEX");
627 if (!status && ResponseHeader->CallId == LE32(1))
629 if (!WineBugDetected)
631 p("Warning: Buggy RPC of Wine detected. Call Id of Response is always 1\n");
632 WineBugDetected = TRUE;
635 else if (ResponseHeader->CallId != RequestHeader->CallId)
637 p("Fatal: Sent Call Id %u but received answer for Call Id %u\n",
638 (uint32_t)LE32(RequestHeader->CallId),
639 (uint32_t)LE32(ResponseHeader->CallId)
642 status = !0;
645 return status;
649 * Initializes an RPC request header as needed for KMS, i.e. packet always fits in one fragment.
650 * size cannot be greater than fragment length negotiated during RPC bind.
652 static void createRpcRequestHeader(RPC_HEADER* RequestHeader, BYTE packetType, WORD size)
654 RequestHeader->PacketType = packetType;
655 RequestHeader->PacketFlags = RPC_PF_FIRST | RPC_PF_LAST;
656 RequestHeader->VersionMajor = 5;
657 RequestHeader->VersionMinor = 0;
658 RequestHeader->AuthLength = 0;
659 RequestHeader->DataRepresentation = BE32(0x10000000); // Little endian, ASCII charset, IEEE floating point
660 RequestHeader->CallId = LE32(CallId);
661 RequestHeader->FragLength = LE16(size);
666 * Sends a KMS request via RPC and receives a response.
667 * Parameters are raw (encrypted) reqeuests / responses.
668 * Returns 0 on success.
670 RpcStatus rpcSendRequest(const RpcCtx sock, const BYTE *const KmsRequest, const size_t requestSize, BYTE **KmsResponse, size_t *const responseSize)
672 #define MAX_EXCESS_BYTES 16
673 RPC_HEADER *RequestHeader, ResponseHeader;
674 RPC_REQUEST64 *RpcRequest;
675 RPC_RESPONSE64 _Response;
676 int status = 0;
677 int_fast8_t useNdr64 = UseRpcNDR64 && firstPacketSent;
678 size_t size = sizeof(RPC_HEADER) + (useNdr64 ? sizeof(RPC_REQUEST64) : sizeof(RPC_REQUEST)) + requestSize;
679 size_t responseSize2;
681 *KmsResponse = NULL;
683 BYTE *_Request = (BYTE*)vlmcsd_malloc(size);
685 RequestHeader = (RPC_HEADER*)_Request;
686 RpcRequest = (RPC_REQUEST64*)(_Request + sizeof(RPC_HEADER));
688 createRpcRequestHeader(RequestHeader, RPC_PT_REQUEST, size);
690 // Increment CallId for next Request
691 CallId++;
693 RpcRequest->Opnum = 0;
695 if (useNdr64)
697 RpcRequest->ContextId = LE16(1); // We negotiate NDR64 always as context 1
698 RpcRequest->AllocHint = LE32(requestSize + sizeof(RpcRequest->Ndr64));
699 RpcRequest->Ndr64.DataLength = LE64((uint64_t)requestSize);
700 RpcRequest->Ndr64.DataSizeIs = LE64((uint64_t)requestSize);
701 memcpy(RpcRequest->Ndr64.Data, KmsRequest, requestSize);
703 else
705 RpcRequest->ContextId = 0; // We negotiate NDR32 always as context 0
706 RpcRequest->AllocHint = LE32(requestSize + sizeof(RpcRequest->Ndr));
707 RpcRequest->Ndr.DataLength = LE32(requestSize);
708 RpcRequest->Ndr.DataSizeIs = LE32(requestSize);
709 memcpy(RpcRequest->Ndr.Data, KmsRequest, requestSize);
712 for(;;)
714 int bytesread;
716 if (!_send(sock, _Request, size))
718 errorout("\nFatal: Could not send RPC request\n");
719 status = !0;
720 break;
723 if (!_recv(sock, &ResponseHeader, sizeof(RPC_HEADER)))
725 errorout("\nFatal: No RPC response received from server\n");
726 status = !0;
727 break;
730 if ((status = checkRpcResponseHeader(&ResponseHeader, RequestHeader, RPC_PT_RESPONSE, &errorout))) break;
732 size = useNdr64 ? sizeof(RPC_RESPONSE64) : sizeof(RPC_RESPONSE);
734 if (size > LE16(ResponseHeader.FragLength) - sizeof(ResponseHeader))
735 size = LE16(ResponseHeader.FragLength) - sizeof(ResponseHeader);
737 if (!_recv(sock, &_Response, size))
739 errorout("\nFatal: RPC response is incomplete\n");
740 status = !0;
741 break;
744 if (_Response.CancelCount != 0)
746 errorout("\nFatal: RPC response cancel count is not 0\n");
747 status = !0;
750 if (_Response.ContextId != (useNdr64 ? LE16(1) : 0))
752 errorout("\nFatal: RPC response context id %u is not bound\n", (unsigned int)LE16(_Response.ContextId));
753 status = !0;
756 int_fast8_t sizesMatch;
758 if (useNdr64)
760 *responseSize = (size_t)LE64(_Response.Ndr64.DataLength);
761 responseSize2 = (size_t)LE64(_Response.Ndr64.DataSizeIs);
763 if (!*responseSize || !_Response.Ndr64.DataSizeMax)
765 status = (int)LE32(_Response.Ndr64.status);
766 break;
769 sizesMatch = (size_t)LE64(_Response.Ndr64.DataLength) == responseSize2;
771 else
773 *responseSize = (size_t)LE32(_Response.Ndr.DataLength);
774 responseSize2 = (size_t)LE32(_Response.Ndr.DataSizeIs);
776 if (!*responseSize || !_Response.Ndr.DataSizeMax)
778 status = (int)LE32(_Response.Ndr.status);
779 break;
782 sizesMatch = (size_t)LE32(_Response.Ndr.DataLength) == responseSize2;
785 if (!sizesMatch)
787 errorout("\nFatal: NDR data length (%u) does not match NDR data size (%u)\n",
788 (uint32_t)*responseSize,
789 (uint32_t)LE32(_Response.Ndr.DataSizeIs)
792 status = !0;
795 *KmsResponse = (BYTE*)vlmcsd_malloc(*responseSize + MAX_EXCESS_BYTES);
797 // If RPC stub is too short, assume missing bytes are zero (same ill behavior as MS RPC)
798 memset(*KmsResponse, 0, *responseSize + MAX_EXCESS_BYTES);
800 // Read up to 16 bytes more than bytes expected to detect faulty KMS emulators
801 if ((bytesread = recv(sock, (char*)*KmsResponse, *responseSize + MAX_EXCESS_BYTES, 0)) < (int)*responseSize)
803 errorout("\nFatal: No or incomplete KMS response received. Required %u bytes but only got %i\n",
804 (uint32_t)*responseSize,
805 (int32_t)(bytesread < 0 ? 0 : bytesread)
808 status = !0;
809 break;
812 DWORD *pReturnCode;
814 size_t len = *responseSize + (useNdr64 ? sizeof(_Response.Ndr64) : sizeof(_Response.Ndr)) + sizeof(*pReturnCode);
815 size_t pad = ((~len & 3) + 1) & 3;
817 if (len + pad != LE32(_Response.AllocHint))
819 errorout("\nWarning: RPC stub size is %u, should be %u (probably incorrect padding)\n", (uint32_t)LE32(_Response.AllocHint), (uint32_t)(len + pad));
821 else
823 size_t i;
824 for (i = 0; i < pad; i++)
826 if (*(*KmsResponse + *responseSize + sizeof(*pReturnCode) + i))
828 errorout("\nWarning: RPC stub data not padded to zeros according to Microsoft standard\n");
829 break;
834 pReturnCode = (DWORD*)(*KmsResponse + *responseSize + pad);
835 status = LE32(UA32(pReturnCode));
837 if (status) errorout("\nWarning: RPC stub data reported Error %u\n", (uint32_t)status);
839 break;
842 free(_Request);
843 firstPacketSent = TRUE;
844 return status;
845 #undef MAX_EXCESS_BYTES
849 static int_fast8_t IsNullGuid(BYTE* guidPtr)
851 int_fast8_t i;
853 for (i = 0; i < 16; i++)
855 if (guidPtr[i]) return FALSE;
858 return TRUE;
862 * Perform RPC client bind. Accepts a connected client socket.
863 * Returns 0 on success. RPC binding is required before any payload can be
864 * exchanged. It negotiates about protocol details.
866 RpcStatus rpcBindOrAlterClientContext(const RpcCtx sock, BYTE packetType, const int_fast8_t verbose)
868 RPC_HEADER *RequestHeader, ResponseHeader;
869 RPC_BIND_REQUEST *bindRequest;
870 RPC_BIND_RESPONSE *bindResponse;
871 int status;
872 WORD ctxItems = 1 + (packetType == RPC_PT_BIND_REQ ? UseRpcNDR64 + UseRpcBTFN : 0);
873 size_t rpcBindSize = (sizeof(RPC_HEADER) + sizeof(RPC_BIND_REQUEST) + (ctxItems - 1) * sizeof(bindRequest->CtxItems[0]));
874 WORD ctxIndex = 0;
875 WORD i;
876 WORD CtxBTFN = (WORD)~0, CtxNDR64 = (WORD)~0;
877 BYTE _Request[rpcBindSize];
879 RequestHeader = (RPC_HEADER*)_Request;
880 bindRequest = (RPC_BIND_REQUEST* )(_Request + sizeof(RPC_HEADER));
882 createRpcRequestHeader(RequestHeader, packetType, rpcBindSize);
883 RequestHeader->PacketFlags |= UseMultiplexedRpc ? RPC_PF_MULTIPLEX : 0;
885 bindRequest->AssocGroup = 0;
886 bindRequest->MaxRecvFrag = bindRequest->MaxXmitFrag = LE16(5840);
887 bindRequest->NumCtxItems = LE32(ctxItems);
889 // data that is identical in all Ctx items
890 for (i = 0; i < ctxItems; i++)
892 bindRequest->CtxItems[i].ContextId = LE16(i);
893 bindRequest->CtxItems[i].InterfaceVerMajor = LE16(1);
894 bindRequest->CtxItems[i].InterfaceVerMinor = 0;
895 bindRequest->CtxItems[i].NumTransItems = LE16(1);
896 bindRequest->CtxItems[i].SyntaxVersion = i ? LE32(1) : LE32(2);
898 memcpy(&bindRequest->CtxItems[i].InterfaceUUID, InterfaceUuid, sizeof(GUID));
901 memcpy(&bindRequest->CtxItems[0].TransferSyntax, TransferSyntaxNDR32, sizeof(GUID));
903 if (UseRpcNDR64 && packetType == RPC_PT_BIND_REQ)
905 memcpy(&bindRequest->CtxItems[++ctxIndex].TransferSyntax, TransferSyntaxNDR64, sizeof(GUID));
906 CtxNDR64 = ctxIndex;
909 if (UseRpcBTFN && packetType == RPC_PT_BIND_REQ)
911 memcpy(&bindRequest->CtxItems[++ctxIndex].TransferSyntax, BindTimeFeatureNegotiation, sizeof(GUID));
912 CtxBTFN = ctxIndex;
915 if (!_send(sock, _Request, rpcBindSize))
917 errorout("\nFatal: Sending RPC bind request failed\n");
918 return !0;
921 if (!_recv(sock, &ResponseHeader, sizeof(RPC_HEADER)))
923 errorout("\nFatal: Did not receive a response from server\n");
924 return !0;
927 if ((status = checkRpcResponseHeader
929 &ResponseHeader,
930 RequestHeader,
931 packetType == RPC_PT_BIND_REQ ? RPC_PT_BIND_ACK : RPC_PT_ALTERCONTEXT_ACK,
932 &errorout
935 return status;
938 bindResponse = (RPC_BIND_RESPONSE*)vlmcsd_malloc(LE16(ResponseHeader.FragLength) - sizeof(RPC_HEADER));
939 BYTE* bindResponseBytePtr = (BYTE*)bindResponse;
941 if (!_recv(sock, bindResponse, LE16(ResponseHeader.FragLength) - sizeof(RPC_HEADER)))
943 errorout("\nFatal: Incomplete RPC bind acknowledgement received\n");
944 free(bindResponseBytePtr);
945 return !0;
947 else
950 * checking, whether a bind or alter context response is as expected.
951 * This check is very strict and checks whether a KMS emulator behaves exactly the same way
952 * as Microsoft's RPC does.
954 status = 0;
956 if (bindResponse->SecondaryAddressLength < LE16(3))
957 bindResponse = (RPC_BIND_RESPONSE*)(bindResponseBytePtr - 4);
959 if (bindResponse->NumResults != bindRequest->NumCtxItems)
961 errorout("\nFatal: Expected %u CTX items but got %u\n",
962 (uint32_t)LE32(bindRequest->NumCtxItems),
963 (uint32_t)LE32(bindResponse->NumResults)
966 status = !0;
969 for (i = 0; i < ctxItems; i++)
971 const char* transferSyntaxName =
972 i == CtxBTFN ? "BTFN" : i == CtxNDR64 ? "NDR64" : "NDR32";
974 if (bindResponse->Results[i].AckResult == RPC_BIND_NACK) // transfer syntax was declined
976 if (!IsNullGuid((BYTE*)&bindResponse->Results[i].TransferSyntax))
978 errorout(
979 "\nWarning: Rejected transfer syntax %s did not return NULL Guid\n",
980 transferSyntaxName
984 if (bindResponse->Results[i].SyntaxVersion)
986 errorout(
987 "\nWarning: Rejected transfer syntax %s did not return syntax version 0 but %u\n",
988 transferSyntaxName,
989 LE32(bindResponse->Results[i].SyntaxVersion)
993 if (bindResponse->Results[i].AckReason == RPC_ABSTRACTSYNTAX_UNSUPPORTED)
995 errorout(
996 "\nWarning: Transfer syntax %s does not support KMS activation\n",
997 transferSyntaxName
1000 else if (bindResponse->Results[i].AckReason != RPC_SYNTAX_UNSUPPORTED)
1002 errorout(
1003 "\nWarning: Rejected transfer syntax %s did not return ack reason RPC_SYNTAX_UNSUPPORTED\n",
1004 transferSyntaxName
1008 continue;
1011 if (i == CtxBTFN) // BTFN
1013 if (bindResponse->Results[i].AckResult != RPC_BIND_ACK)
1015 errorout("\nWarning: BTFN did not respond with RPC_BIND_ACK or RPC_BIND_NACK\n");
1018 if (bindResponse->Results[i].AckReason != LE16(3))
1020 errorout("\nWarning: BTFN did not return expected feature mask 0x3 but 0x%X\n", (unsigned int)LE16(bindResponse->Results[i].AckReason));
1023 if (verbose) printf("... BTFN ");
1024 RpcFlags.HasBTFN = TRUE;
1026 continue;
1029 // NDR32 or NDR64 Ctx
1030 if (bindResponse->Results[i].AckResult != RPC_BIND_ACCEPT)
1032 errorout(
1033 "\nFatal: transfer syntax %s returned an invalid status, neither RPC_BIND_ACCEPT nor RPC_BIND_NACK\n",
1034 transferSyntaxName
1037 status = !0;
1040 if (!IsEqualGUID(&bindResponse->Results[i].TransferSyntax, &bindRequest->CtxItems[i].TransferSyntax))
1042 errorout(
1043 "\nFatal: Transfer syntax of RPC bind request and response does not match\n"
1046 status = !0;
1049 if (bindResponse->Results[i].SyntaxVersion != bindRequest->CtxItems[i].SyntaxVersion)
1051 errorout("\nFatal: Expected transfer syntax version %u for %s but got %u\n",
1052 (uint32_t)LE32(bindRequest->CtxItems[0].SyntaxVersion),
1053 transferSyntaxName,
1054 (uint32_t)LE32(bindResponse->Results[0].SyntaxVersion)
1057 status = !0;
1060 // The ack reason field is actually undefined here but Microsoft sets this to 0
1061 if (bindResponse->Results[i].AckReason != 0)
1063 errorout(
1064 "\nWarning: Ack reason should be 0 but is %u\n",
1065 LE16(bindResponse->Results[i].AckReason)
1069 if (!status)
1071 if (i == CtxNDR64)
1073 RpcFlags.HasNDR64 = TRUE;
1074 if (verbose) printf("... NDR64 ");
1076 if (!i)
1078 RpcFlags.HasNDR32 = TRUE;
1079 if (verbose) printf("... NDR32 ");
1086 free(bindResponseBytePtr);
1088 if (!RpcFlags.HasNDR64 && !RpcFlags.HasNDR32)
1090 errorout("\nFatal: Could neither negotiate NDR32 nor NDR64 with the RPC server\n");
1091 status = !0;
1094 return status;
1097 RpcStatus rpcBindClient(const RpcCtx sock, const int_fast8_t verbose)
1099 firstPacketSent = FALSE;
1100 RpcFlags.mask = 0;
1102 RpcStatus status =
1103 rpcBindOrAlterClientContext(sock, RPC_PT_BIND_REQ, verbose);
1105 if (status) return status;
1107 if (!RpcFlags.HasNDR32)
1108 status = rpcBindOrAlterClientContext(sock, RPC_PT_ALTERCONTEXT_REQ, verbose);
1110 return status;
1113 #endif // USE_MSRPC