1 #ifndef _DEFAULT_SOURCE
2 #define _DEFAULT_SOURCE
3 #endif // _DEFAULT_SOURCE
6 #define CONFIG "config.h"
19 #include <sys/socket.h>
28 #include "shared_globals.h"
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);
61 unsigned int RequestSize
;
62 CreateResponse_t CreateResponse
;
64 { sizeof(REQUEST_V4
), (CreateResponse_t
) CreateResponseV4
},
65 { sizeof(REQUEST_V6
), (CreateResponse_t
) CreateResponseV6
},
66 { sizeof(REQUEST_V6
), (CreateResponse_t
) CreateResponseV6
}
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
))
91 if (len
< requestSize
+ sizeof(DWORD
))
93 logger("Fatal: KMS Request too small to contain version info (less than 4 bytes).\n");
98 kmsMajorVersion
= LE16(((WORD
*)Request
->Ndr
.Data
)[1]);
100 kmsMajorVersion
= LE16(((WORD
*)Request
->Ndr64
.Data
)[1]);
102 if (kmsMajorVersion
> 6)
104 logger("Fatal: KMSv%u is not supported.\n", (unsigned int)kmsMajorVersion
);
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
,
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
)
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
181 if (Ctx
!= *Ndr64Ctx
)
182 _v
= LE16(((WORD
*)Request
->Ndr
.Data
)[1]) - 4;
184 _v
= LE16(((WORD
*)Request
->Ndr64
.Data
)[1]) - 4;
186 // Only KMS v4, v5 and v6 are supported
187 if (_v
>= vlmcsd_countof(_Versions
))
190 logger("Fatal: KMSv%i unsupported\n", _v
+ 4);
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
)
212 WORD Ctx
= LE16(Request
->ContextId
);
215 BYTE
* pRpcReturnCode
;
218 if (Ctx
!= *Ndr64Ctx
)
220 requestData
= (BYTE
*)&Request
->Ndr
.Data
;
221 responseData
= (BYTE
*)&Response
->Ndr
.Data
;
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
)))
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
);
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
);
258 Response
->AllocHint
= LE32(len
);
259 Response
->ContextId
= Request
->ContextId
;
261 *((WORD
*)&Response
->CancelCount
) = 0; // CancelCount + Pad1
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)
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
;
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
;
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;
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
;
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
));
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
));
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
);
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
;
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
;
488 while (_recv(sock
, &rpcRequestHeader
, sizeof(rpcRequestHeader
)))
491 unsigned int request_len
, response_len
;
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;
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
)
557 if (Header
->PacketType
!= desiredPacketType
)
559 p("Fatal: Received wrong RPC packet type. Expected %u but got %u\n",
560 (uint32_t)desiredPacketType
,
566 if (Header
->DataRepresentation
!= BE32(0x10000000))
568 p("Fatal: RPC response does not conform to Microsoft's limited support of DCE RPC\n");
572 if (Header
->AuthLength
!= 0)
574 p("Fatal: RPC response requests authentication\n");
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");
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
);
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");
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
)
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
;
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
;
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
693 RpcRequest
->Opnum
= 0;
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
);
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
);
716 if (!_send(sock
, _Request
, size
))
718 errorout("\nFatal: Could not send RPC request\n");
723 if (!_recv(sock
, &ResponseHeader
, sizeof(RPC_HEADER
)))
725 errorout("\nFatal: No RPC response received from server\n");
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");
744 if (_Response
.CancelCount
!= 0)
746 errorout("\nFatal: RPC response cancel count is not 0\n");
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
));
756 int_fast8_t sizesMatch
;
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
);
769 sizesMatch
= (size_t)LE64(_Response
.Ndr64
.DataLength
) == responseSize2
;
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
);
782 sizesMatch
= (size_t)LE32(_Response
.Ndr
.DataLength
) == responseSize2
;
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
)
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
)
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
));
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");
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
);
843 firstPacketSent
= TRUE
;
845 #undef MAX_EXCESS_BYTES
849 static int_fast8_t IsNullGuid(BYTE
* guidPtr
)
853 for (i
= 0; i
< 16; i
++)
855 if (guidPtr
[i
]) return FALSE
;
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
;
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]));
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
));
909 if (UseRpcBTFN
&& packetType
== RPC_PT_BIND_REQ
)
911 memcpy(&bindRequest
->CtxItems
[++ctxIndex
].TransferSyntax
, BindTimeFeatureNegotiation
, sizeof(GUID
));
915 if (!_send(sock
, _Request
, rpcBindSize
))
917 errorout("\nFatal: Sending RPC bind request failed\n");
921 if (!_recv(sock
, &ResponseHeader
, sizeof(RPC_HEADER
)))
923 errorout("\nFatal: Did not receive a response from server\n");
927 if ((status
= checkRpcResponseHeader
931 packetType
== RPC_PT_BIND_REQ
? RPC_PT_BIND_ACK
: RPC_PT_ALTERCONTEXT_ACK
,
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
);
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.
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
)
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
))
979 "\nWarning: Rejected transfer syntax %s did not return NULL Guid\n",
984 if (bindResponse
->Results
[i
].SyntaxVersion
)
987 "\nWarning: Rejected transfer syntax %s did not return syntax version 0 but %u\n",
989 LE32(bindResponse
->Results
[i
].SyntaxVersion
)
993 if (bindResponse
->Results
[i
].AckReason
== RPC_ABSTRACTSYNTAX_UNSUPPORTED
)
996 "\nWarning: Transfer syntax %s does not support KMS activation\n",
1000 else if (bindResponse
->Results
[i
].AckReason
!= RPC_SYNTAX_UNSUPPORTED
)
1003 "\nWarning: Rejected transfer syntax %s did not return ack reason RPC_SYNTAX_UNSUPPORTED\n",
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
;
1029 // NDR32 or NDR64 Ctx
1030 if (bindResponse
->Results
[i
].AckResult
!= RPC_BIND_ACCEPT
)
1033 "\nFatal: transfer syntax %s returned an invalid status, neither RPC_BIND_ACCEPT nor RPC_BIND_NACK\n",
1040 if (!IsEqualGUID(&bindResponse
->Results
[i
].TransferSyntax
, &bindRequest
->CtxItems
[i
].TransferSyntax
))
1043 "\nFatal: Transfer syntax of RPC bind request and response does not match\n"
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
),
1054 (uint32_t)LE32(bindResponse
->Results
[0].SyntaxVersion
)
1060 // The ack reason field is actually undefined here but Microsoft sets this to 0
1061 if (bindResponse
->Results
[i
].AckReason
!= 0)
1064 "\nWarning: Ack reason should be 0 but is %u\n",
1065 LE16(bindResponse
->Results
[i
].AckReason
)
1073 RpcFlags
.HasNDR64
= TRUE
;
1074 if (verbose
) printf("... NDR64 ");
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");
1097 RpcStatus
rpcBindClient(const RpcCtx sock
, const int_fast8_t verbose
)
1099 firstPacketSent
= FALSE
;
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
);