1 /**
2  * WinPR: Windows Portable Runtime
3  * Network Data Representation (NDR)
4  *
5  * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdarg.h>
27 
28 #include <winpr/ndr.h>
29 
30 #ifndef _WIN32
31 
32 #include "ndr_array.h"
33 #include "ndr_context.h"
34 #include "ndr_pointer.h"
35 #include "ndr_simple.h"
36 #include "ndr_string.h"
37 #include "ndr_structure.h"
38 #include "ndr_union.h"
39 
40 #include "ndr_private.h"
41 
42 #include "../log.h"
43 #define TAG WINPR_TAG("rpc")
44 
45 /**
46  * MSRPC NDR Types Technical Overview:
47  * http://dvlabs.tippingpoint.com/blog/2007/11/24/msrpc-ndr-types/
48  */
49 
NdrPrintParamAttributes(PARAM_ATTRIBUTES attributes)50 static void NdrPrintParamAttributes(PARAM_ATTRIBUTES attributes)
51 {
52 	if (attributes.ServerAllocSize)
53 		WLog_INFO(TAG, "ServerAllocSize, ");
54 
55 	if (attributes.SaveForAsyncFinish)
56 		WLog_INFO(TAG, "SaveForAsyncFinish, ");
57 
58 	if (attributes.IsDontCallFreeInst)
59 		WLog_INFO(TAG, "IsDontCallFreeInst, ");
60 
61 	if (attributes.IsSimpleRef)
62 		WLog_INFO(TAG, "IsSimpleRef, ");
63 
64 	if (attributes.IsByValue)
65 		WLog_INFO(TAG, "IsByValue, ");
66 
67 	if (attributes.IsBasetype)
68 		WLog_INFO(TAG, "IsBaseType, ");
69 
70 	if (attributes.IsReturn)
71 		WLog_INFO(TAG, "IsReturn, ");
72 
73 	if (attributes.IsOut)
74 		WLog_INFO(TAG, "IsOut, ");
75 
76 	if (attributes.IsIn)
77 		WLog_INFO(TAG, "IsIn, ");
78 
79 	if (attributes.IsPipe)
80 		WLog_INFO(TAG, "IsPipe, ");
81 
82 	if (attributes.MustFree)
83 		WLog_INFO(TAG, "MustFree, ");
84 
85 	if (attributes.MustSize)
86 		WLog_INFO(TAG, "MustSize, ");
87 }
88 
NdrProcessParam(PMIDL_STUB_MESSAGE pStubMsg,NDR_PHASE phase,unsigned char * pMemory,NDR_PARAM * param)89 static void NdrProcessParam(PMIDL_STUB_MESSAGE pStubMsg, NDR_PHASE phase, unsigned char* pMemory,
90                             NDR_PARAM* param)
91 {
92 	unsigned char type;
93 	PFORMAT_STRING pFormat;
94 
95 	/* Parameter Descriptors: http://msdn.microsoft.com/en-us/library/windows/desktop/aa374362/ */
96 
97 	if (param->Attributes.IsBasetype)
98 	{
99 		pFormat = &param->Type.FormatChar;
100 
101 		if (param->Attributes.IsSimpleRef)
102 			pMemory = *(unsigned char**)pMemory;
103 	}
104 	else
105 	{
106 		pFormat = &pStubMsg->StubDesc->pFormatTypes[param->Type.Offset];
107 
108 		if (!(param->Attributes.IsByValue))
109 			pMemory = *(unsigned char**)pMemory;
110 	}
111 
112 	type = (pFormat[0] & 0x7F);
113 
114 	if (type > FC_PAD)
115 		return;
116 
117 	if (phase == NDR_PHASE_SIZE)
118 	{
119 		NDR_TYPE_SIZE_ROUTINE pfnSizeRoutine = pfnSizeRoutines[type];
120 
121 		if (pfnSizeRoutine)
122 			pfnSizeRoutine(pStubMsg, pMemory, pFormat);
123 	}
124 	else if (phase == NDR_PHASE_MARSHALL)
125 	{
126 		NDR_TYPE_MARSHALL_ROUTINE pfnMarshallRoutine = pfnMarshallRoutines[type];
127 
128 		if (pfnMarshallRoutine)
129 			pfnMarshallRoutine(pStubMsg, pMemory, *pFormat);
130 	}
131 	else if (phase == NDR_PHASE_UNMARSHALL)
132 	{
133 		NDR_TYPE_UNMARSHALL_ROUTINE pfnUnmarshallRoutine = pfnUnmarshallRoutines[type];
134 
135 		if (pfnUnmarshallRoutine)
136 			pfnUnmarshallRoutine(pStubMsg, pMemory, *pFormat);
137 	}
138 	else if (phase == NDR_PHASE_FREE)
139 	{
140 		NDR_TYPE_FREE_ROUTINE pfnFreeRoutine = pfnFreeRoutines[type];
141 
142 		if (pfnFreeRoutine)
143 			pfnFreeRoutine(pStubMsg, pMemory, pFormat);
144 	}
145 }
146 
NdrProcessParams(PMIDL_STUB_MESSAGE pStubMsg,PFORMAT_STRING pFormat,NDR_PHASE phase,void ** fpuArgs,unsigned short numberParams)147 static void NdrProcessParams(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, NDR_PHASE phase,
148                              void** fpuArgs, unsigned short numberParams)
149 {
150 	unsigned int i;
151 	NDR_PARAM* params;
152 	PFORMAT_STRING fmt;
153 	unsigned char* arg;
154 	unsigned char type;
155 	params = (NDR_PARAM*)pFormat;
156 	WLog_INFO(TAG, "Params = ");
157 
158 	for (i = 0; i < numberParams; i++)
159 	{
160 #ifdef __x86_64__
161 		float tmp;
162 #endif
163 		arg = pStubMsg->StackTop + params[i].StackOffset;
164 		fmt = (PFORMAT_STRING)&pStubMsg->StubDesc->pFormatTypes[params[i].Type.Offset];
165 #ifdef __x86_64__
166 
167 		if ((params[i].Attributes.IsBasetype) && !(params[i].Attributes.IsSimpleRef) &&
168 		    ((params[i].Type.FormatChar) == FC_FLOAT) && !fpuArgs)
169 		{
170 			tmp = *(double*)arg;
171 			arg = (unsigned char*)&tmp;
172 		}
173 
174 #endif
175 		type = (params[i].Attributes.IsBasetype) ? params[i].Type.FormatChar : *fmt;
176 		WLog_INFO(TAG, "'\t#%u\ttype %s (0x%02X) ", i, FC_TYPE_STRINGS[type], type);
177 		NdrPrintParamAttributes(params[i].Attributes);
178 
179 		if (params[i].Attributes.IsIn)
180 		{
181 			NdrProcessParam(pStubMsg, phase, arg, &params[i]);
182 		}
183 	}
184 }
185 
NdrClientInitializeNew(PRPC_MESSAGE pRpcMessage,PMIDL_STUB_MESSAGE pStubMsg,PMIDL_STUB_DESC pStubDesc,unsigned int ProcNum)186 static void NdrClientInitializeNew(PRPC_MESSAGE pRpcMessage, PMIDL_STUB_MESSAGE pStubMsg,
187                                    PMIDL_STUB_DESC pStubDesc, unsigned int ProcNum)
188 {
189 	pRpcMessage->Handle = NULL;
190 	pRpcMessage->RpcFlags = 0;
191 	pRpcMessage->ProcNum = ProcNum;
192 	pRpcMessage->DataRepresentation = 0;
193 	pRpcMessage->ReservedForRuntime = NULL;
194 	pRpcMessage->RpcInterfaceInformation = pStubDesc->RpcInterfaceInformation;
195 	pStubMsg->RpcMsg = pRpcMessage;
196 	pStubMsg->BufferStart = NULL;
197 	pStubMsg->BufferEnd = NULL;
198 	pStubMsg->BufferLength = 0;
199 	pStubMsg->StackTop = NULL;
200 	pStubMsg->StubDesc = pStubDesc;
201 	pStubMsg->IgnoreEmbeddedPointers = 0;
202 	pStubMsg->PointerLength = 0;
203 }
204 
NdrPrintOptFlags(INTERPRETER_OPT_FLAGS optFlags)205 static void NdrPrintOptFlags(INTERPRETER_OPT_FLAGS optFlags)
206 {
207 	if (optFlags.ClientMustSize)
208 		WLog_INFO(TAG, "ClientMustSize, ");
209 
210 	if (optFlags.ServerMustSize)
211 		WLog_INFO(TAG, "ServerMustSize, ");
212 
213 	if (optFlags.HasAsyncUuid)
214 		WLog_INFO(TAG, "HasAsyncUiid, ");
215 
216 	if (optFlags.HasAsyncHandle)
217 		WLog_INFO(TAG, "HasAsyncHandle, ");
218 
219 	if (optFlags.HasReturn)
220 		WLog_INFO(TAG, "HasReturn, ");
221 
222 	if (optFlags.HasPipes)
223 		WLog_INFO(TAG, "HasPipes, ");
224 
225 	if (optFlags.HasExtensions)
226 		WLog_INFO(TAG, "HasExtensions, ");
227 }
228 
NdrPrintExtFlags(INTERPRETER_OPT_FLAGS2 extFlags)229 static void NdrPrintExtFlags(INTERPRETER_OPT_FLAGS2 extFlags)
230 {
231 	if (extFlags.HasNewCorrDesc)
232 		WLog_INFO(TAG, "HasNewCorrDesc, ");
233 
234 	if (extFlags.ClientCorrCheck)
235 		WLog_INFO(TAG, "ClientCorrCheck, ");
236 
237 	if (extFlags.ServerCorrCheck)
238 		WLog_INFO(TAG, "ServerCorrCheck, ");
239 
240 	if (extFlags.HasNotify)
241 		WLog_INFO(TAG, "HasNotify, ");
242 
243 	if (extFlags.HasNotify2)
244 		WLog_INFO(TAG, "HasNotify2, ");
245 }
246 
NdrClientCall(PMIDL_STUB_DESC pStubDescriptor,PFORMAT_STRING pFormat,void ** stackTop,void ** fpuStack)247 CLIENT_CALL_RETURN NdrClientCall(PMIDL_STUB_DESC pStubDescriptor, PFORMAT_STRING pFormat,
248                                  void** stackTop, void** fpuStack)
249 {
250 	RPC_MESSAGE rpcMsg;
251 	unsigned short procNum;
252 	unsigned short stackSize;
253 	unsigned char numberParams;
254 	unsigned char handleType;
255 	MIDL_STUB_MESSAGE stubMsg;
256 	INTERPRETER_FLAGS flags;
257 	INTERPRETER_OPT_FLAGS optFlags;
258 	NDR_PROC_HEADER* procHeader;
259 	NDR_OI2_PROC_HEADER* oi2ProcHeader;
260 	CLIENT_CALL_RETURN client_call_return;
261 	procNum = stackSize = numberParams = 0;
262 	procHeader = (NDR_PROC_HEADER*)&pFormat[0];
263 	client_call_return.Pointer = NULL;
264 	handleType = procHeader->HandleType;
265 	flags = procHeader->OldOiFlags;
266 	procNum = procHeader->ProcNum;
267 	stackSize = procHeader->StackSize;
268 	pFormat += sizeof(NDR_PROC_HEADER);
269 	/* The Header: http://msdn.microsoft.com/en-us/library/windows/desktop/aa378707/ */
270 	/* Procedure Header Descriptor:
271 	 * http://msdn.microsoft.com/en-us/library/windows/desktop/aa374387/ */
272 	/* Handles: http://msdn.microsoft.com/en-us/library/windows/desktop/aa373932/ */
273 	WLog_DBG(TAG, "Oi Header: HandleType: 0x%02X OiFlags: 0x%02X ProcNum: %hu StackSize: 0x%04X",
274 	         handleType, *((unsigned char*)&flags), procNum, stackSize);
275 
276 	if (handleType > 0)
277 	{
278 		/* implicit handle */
279 		WLog_INFO(TAG, "Implicit Handle");
280 		oi2ProcHeader = (NDR_OI2_PROC_HEADER*)&pFormat[0];
281 		pFormat += sizeof(NDR_OI2_PROC_HEADER);
282 	}
283 	else
284 	{
285 		/* explicit handle */
286 		WLog_INFO(TAG, "Explicit Handle");
287 		oi2ProcHeader = (NDR_OI2_PROC_HEADER*)&pFormat[6];
288 		pFormat += sizeof(NDR_OI2_PROC_HEADER) + 6;
289 	}
290 
291 	optFlags = oi2ProcHeader->Oi2Flags;
292 	numberParams = oi2ProcHeader->NumberParams;
293 	WLog_DBG(TAG,
294 	         "Oi2 Header: Oi2Flags: 0x%02X, NumberParams: %u ClientBufferSize: %hu "
295 	         "ServerBufferSize: %hu",
296 	         *((unsigned char*)&optFlags), numberParams, oi2ProcHeader->ClientBufferSize,
297 	         oi2ProcHeader->ServerBufferSize);
298 	WLog_INFO(TAG, "Oi2Flags: ");
299 	NdrPrintOptFlags(optFlags);
300 	NdrClientInitializeNew(&rpcMsg, &stubMsg, pStubDescriptor, procNum);
301 
302 	if (optFlags.HasExtensions)
303 	{
304 		INTERPRETER_OPT_FLAGS2 extFlags;
305 		NDR_PROC_HEADER_EXTS* extensions = (NDR_PROC_HEADER_EXTS*)pFormat;
306 		pFormat += extensions->Size;
307 		extFlags = extensions->Flags2;
308 		WLog_DBG(TAG, "Extensions: Size: %hhu, flags2: 0x%02X", extensions->Size,
309 		         *((unsigned char*)&extensions->Flags2));
310 #ifdef __x86_64__
311 
312 		if (extensions->Size > sizeof(*extensions) && fpuStack)
313 		{
314 			int i;
315 			unsigned short fpuMask = *(unsigned short*)(extensions + 1);
316 
317 			for (i = 0; i < 4; i++, fpuMask >>= 2)
318 			{
319 				switch (fpuMask & 3)
320 				{
321 					case 1:
322 						*(float*)&stackTop[i] = *(float*)&fpuStack[i];
323 						break;
324 
325 					case 2:
326 						*(double*)&stackTop[i] = *(double*)&fpuStack[i];
327 						break;
328 				}
329 			}
330 		}
331 
332 #endif
333 		WLog_INFO(TAG, "ExtFlags: ");
334 		NdrPrintExtFlags(extFlags);
335 	}
336 
337 	stubMsg.StackTop = (unsigned char*)stackTop;
338 	NdrProcessParams(&stubMsg, pFormat, NDR_PHASE_SIZE, fpuStack, numberParams);
339 	WLog_DBG(TAG, "stubMsg BufferLength: %" PRIu32 "", stubMsg.BufferLength);
340 	return client_call_return;
341 }
342 
NdrClientCall2(PMIDL_STUB_DESC pStubDescriptor,PFORMAT_STRING pFormat,...)343 CLIENT_CALL_RETURN NdrClientCall2(PMIDL_STUB_DESC pStubDescriptor, PFORMAT_STRING pFormat, ...)
344 {
345 	va_list args;
346 	CLIENT_CALL_RETURN client_call_return;
347 	va_start(args, pFormat);
348 	client_call_return = NdrClientCall(pStubDescriptor, pFormat, va_arg(args, void**), NULL);
349 	va_end(args);
350 	return client_call_return;
351 }
352 
353 #endif
354