msi/tests: Skip some source tests if a required product key cannot be created.
[wine] / dlls / ntdll / tests / port.c
1 /* Unit test suite for Ntdll Port API functions
2  *
3  * Copyright 2006 James Hawkins
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #include <stdio.h>
21 #include <stdarg.h>
22
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "wine/test.h"
31 #include "winternl.h"
32
33 #ifndef __WINE_WINTERNL_H
34
35 typedef struct _CLIENT_ID
36 {
37    HANDLE UniqueProcess;
38    HANDLE UniqueThread;
39 } CLIENT_ID, *PCLIENT_ID;
40
41 typedef struct _LPC_SECTION_WRITE
42 {
43   ULONG Length;
44   HANDLE SectionHandle;
45   ULONG SectionOffset;
46   ULONG ViewSize;
47   PVOID ViewBase;
48   PVOID TargetViewBase;
49 } LPC_SECTION_WRITE, *PLPC_SECTION_WRITE;
50
51 typedef struct _LPC_SECTION_READ
52 {
53   ULONG Length;
54   ULONG ViewSize;
55   PVOID ViewBase;
56 } LPC_SECTION_READ, *PLPC_SECTION_READ;
57
58 typedef struct _LPC_MESSAGE
59 {
60   USHORT DataSize;
61   USHORT MessageSize;
62   USHORT MessageType;
63   USHORT VirtualRangesOffset;
64   CLIENT_ID ClientId;
65   ULONG_PTR MessageId;
66   ULONG_PTR SectionSize;
67   UCHAR Data[ANYSIZE_ARRAY];
68 } LPC_MESSAGE, *PLPC_MESSAGE;
69
70 #endif
71
72 /* on Wow64 we have to use the 64-bit layout */
73 typedef struct
74 {
75   USHORT DataSize;
76   USHORT MessageSize;
77   USHORT MessageType;
78   USHORT VirtualRangesOffset;
79   ULONGLONG ClientId[2];
80   ULONGLONG MessageId;
81   ULONGLONG SectionSize;
82   UCHAR Data[ANYSIZE_ARRAY];
83 } LPC_MESSAGE64;
84
85 union lpc_message
86 {
87     LPC_MESSAGE   msg;
88     LPC_MESSAGE64 msg64;
89 };
90
91 /* Types of LPC messages */
92 #define UNUSED_MSG_TYPE                 0
93 #define LPC_REQUEST                     1
94 #define LPC_REPLY                       2
95 #define LPC_DATAGRAM                    3
96 #define LPC_LOST_REPLY                  4
97 #define LPC_PORT_CLOSED                 5
98 #define LPC_CLIENT_DIED                 6
99 #define LPC_EXCEPTION                   7
100 #define LPC_DEBUG_EVENT                 8
101 #define LPC_ERROR_EVENT                 9
102 #define LPC_CONNECTION_REQUEST         10
103
104 static const WCHAR PORTNAME[] = {'\\','M','y','P','o','r','t',0};
105
106 #define REQUEST1    "Request1"
107 #define REQUEST2    "Request2"
108 #define REPLY       "Reply"
109
110 #define MAX_MESSAGE_LEN    30
111
112 static UNICODE_STRING port;
113
114 /* Function pointers for ntdll calls */
115 static HMODULE hntdll = 0;
116 static NTSTATUS (WINAPI *pNtCompleteConnectPort)(HANDLE);
117 static NTSTATUS (WINAPI *pNtAcceptConnectPort)(PHANDLE,ULONG,PLPC_MESSAGE,ULONG,
118                                                ULONG,PLPC_SECTION_READ);
119 static NTSTATUS (WINAPI *pNtReplyPort)(HANDLE,PLPC_MESSAGE);
120 static NTSTATUS (WINAPI *pNtReplyWaitReceivePort)(PHANDLE,PULONG,PLPC_MESSAGE,
121                                                   PLPC_MESSAGE);
122 static NTSTATUS (WINAPI *pNtCreatePort)(PHANDLE,POBJECT_ATTRIBUTES,ULONG,ULONG,ULONG);
123 static NTSTATUS (WINAPI *pNtRequestWaitReplyPort)(HANDLE,PLPC_MESSAGE,PLPC_MESSAGE);
124 static NTSTATUS (WINAPI *pNtRequestPort)(HANDLE,PLPC_MESSAGE);
125 static NTSTATUS (WINAPI *pNtRegisterThreadTerminatePort)(HANDLE);
126 static NTSTATUS (WINAPI *pNtConnectPort)(PHANDLE,PUNICODE_STRING,
127                                          PSECURITY_QUALITY_OF_SERVICE,
128                                          PLPC_SECTION_WRITE,PLPC_SECTION_READ,
129                                          PVOID,PVOID,PULONG);
130 static NTSTATUS (WINAPI *pRtlInitUnicodeString)(PUNICODE_STRING,LPCWSTR);
131 static NTSTATUS (WINAPI *pNtWaitForSingleObject)(HANDLE,BOOLEAN,PLARGE_INTEGER);
132 static BOOL     (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
133
134 static BOOL is_wow64;
135
136 static BOOL init_function_ptrs(void)
137 {
138     hntdll = LoadLibraryA("ntdll.dll");
139
140     if (!hntdll)
141         return FALSE;
142
143     pNtCompleteConnectPort = (void *)GetProcAddress(hntdll, "NtCompleteConnectPort");
144     pNtAcceptConnectPort = (void *)GetProcAddress(hntdll, "NtAcceptConnectPort");
145     pNtReplyPort = (void *)GetProcAddress(hntdll, "NtReplyPort");
146     pNtReplyWaitReceivePort = (void *)GetProcAddress(hntdll, "NtReplyWaitReceivePort");
147     pNtCreatePort = (void *)GetProcAddress(hntdll, "NtCreatePort");
148     pNtRequestWaitReplyPort = (void *)GetProcAddress(hntdll, "NtRequestWaitReplyPort");
149     pNtRequestPort = (void *)GetProcAddress(hntdll, "NtRequestPort");
150     pNtRegisterThreadTerminatePort = (void *)GetProcAddress(hntdll, "NtRegisterThreadTerminatePort");
151     pNtConnectPort = (void *)GetProcAddress(hntdll, "NtConnectPort");
152     pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString");
153     pNtWaitForSingleObject = (void *)GetProcAddress(hntdll, "NtWaitForSingleObject");
154
155     if (!pNtCompleteConnectPort || !pNtAcceptConnectPort ||
156         !pNtReplyWaitReceivePort || !pNtCreatePort || !pNtRequestWaitReplyPort ||
157         !pNtRequestPort || !pNtRegisterThreadTerminatePort ||
158         !pNtConnectPort || !pRtlInitUnicodeString)
159     {
160         win_skip("Needed port functions are not available\n");
161         FreeLibrary(hntdll);
162         return FALSE;
163     }
164
165     pIsWow64Process = (void *)GetProcAddress(GetModuleHandle("kernel32.dll"), "IsWow64Process");
166     if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
167     return TRUE;
168 }
169
170 static void ProcessConnectionRequest(union lpc_message *LpcMessage, PHANDLE pAcceptPortHandle)
171 {
172     NTSTATUS status;
173
174     if (is_wow64)
175     {
176         ok(LpcMessage->msg64.MessageType == LPC_CONNECTION_REQUEST,
177            "Expected LPC_CONNECTION_REQUEST, got %d\n", LpcMessage->msg64.MessageType);
178         ok(!*LpcMessage->msg64.Data, "Expected empty string!\n");
179     }
180     else
181     {
182         ok(LpcMessage->msg.MessageType == LPC_CONNECTION_REQUEST,
183            "Expected LPC_CONNECTION_REQUEST, got %d\n", LpcMessage->msg.MessageType);
184         ok(!*LpcMessage->msg.Data, "Expected empty string!\n");
185     }
186
187     status = pNtAcceptConnectPort(pAcceptPortHandle, 0, &LpcMessage->msg, 1, 0, NULL);
188     ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status);
189     
190     status = pNtCompleteConnectPort(*pAcceptPortHandle);
191     ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status);
192 }
193
194 static void ProcessLpcRequest(HANDLE PortHandle, union lpc_message *LpcMessage)
195 {
196     NTSTATUS status;
197
198     if (is_wow64)
199     {
200         ok(LpcMessage->msg64.MessageType == LPC_REQUEST,
201            "Expected LPC_REQUEST, got %d\n", LpcMessage->msg64.MessageType);
202         ok(!lstrcmp((LPSTR)LpcMessage->msg64.Data, REQUEST2),
203            "Expected %s, got %s\n", REQUEST2, LpcMessage->msg64.Data);
204         lstrcpy((LPSTR)LpcMessage->msg64.Data, REPLY);
205
206         status = pNtReplyPort(PortHandle, &LpcMessage->msg);
207         ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status);
208         ok(LpcMessage->msg64.MessageType == LPC_REQUEST,
209            "Expected LPC_REQUEST, got %d\n", LpcMessage->msg64.MessageType);
210         ok(!lstrcmp((LPSTR)LpcMessage->msg64.Data, REPLY),
211            "Expected %s, got %s\n", REPLY, LpcMessage->msg64.Data);
212     }
213     else
214     {
215         ok(LpcMessage->msg.MessageType == LPC_REQUEST,
216            "Expected LPC_REQUEST, got %d\n", LpcMessage->msg.MessageType);
217         ok(!lstrcmp((LPSTR)LpcMessage->msg.Data, REQUEST2),
218            "Expected %s, got %s\n", REQUEST2, LpcMessage->msg.Data);
219         lstrcpy((LPSTR)LpcMessage->msg.Data, REPLY);
220
221         status = pNtReplyPort(PortHandle, &LpcMessage->msg);
222         ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status);
223         ok(LpcMessage->msg.MessageType == LPC_REQUEST,
224            "Expected LPC_REQUEST, got %d\n", LpcMessage->msg.MessageType);
225         ok(!lstrcmp((LPSTR)LpcMessage->msg.Data, REPLY),
226            "Expected %s, got %s\n", REPLY, LpcMessage->msg.Data);
227     }
228 }
229
230 static DWORD WINAPI test_ports_client(LPVOID arg)
231 {
232     SECURITY_QUALITY_OF_SERVICE sqos;
233     union lpc_message *LpcMessage, *out;
234     HANDLE PortHandle;
235     ULONG len, size;
236     NTSTATUS status;
237
238     sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
239     sqos.ImpersonationLevel = SecurityImpersonation;
240     sqos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
241     sqos.EffectiveOnly = TRUE;
242
243     status = pNtConnectPort(&PortHandle, &port, &sqos, 0, 0, &len, NULL, NULL);
244     todo_wine ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status);
245     if (status != STATUS_SUCCESS) return 1;
246
247     status = pNtRegisterThreadTerminatePort(PortHandle);
248     ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status);
249
250     if (is_wow64)
251     {
252         size = FIELD_OFFSET(LPC_MESSAGE64, Data[MAX_MESSAGE_LEN]);
253         LpcMessage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
254         out = HeapAlloc(GetProcessHeap(), 0, size);
255
256         LpcMessage->msg64.DataSize = lstrlen(REQUEST1) + 1;
257         LpcMessage->msg64.MessageSize = FIELD_OFFSET(LPC_MESSAGE64, Data[LpcMessage->msg64.DataSize]);
258         lstrcpy((LPSTR)LpcMessage->msg64.Data, REQUEST1);
259
260         status = pNtRequestPort(PortHandle, &LpcMessage->msg);
261         ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status);
262         ok(LpcMessage->msg64.MessageType == 0, "Expected 0, got %d\n", LpcMessage->msg64.MessageType);
263         ok(!lstrcmp((LPSTR)LpcMessage->msg64.Data, REQUEST1),
264            "Expected %s, got %s\n", REQUEST1, LpcMessage->msg64.Data);
265
266         /* Fill in the message */
267         memset(LpcMessage, 0, size);
268         LpcMessage->msg64.DataSize = lstrlen(REQUEST2) + 1;
269         LpcMessage->msg64.MessageSize = FIELD_OFFSET(LPC_MESSAGE64, Data[LpcMessage->msg64.DataSize]);
270         lstrcpy((LPSTR)LpcMessage->msg64.Data, REQUEST2);
271
272         /* Send the message and wait for the reply */
273         status = pNtRequestWaitReplyPort(PortHandle, &LpcMessage->msg, &out->msg);
274         ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status);
275         ok(!lstrcmp((LPSTR)out->msg64.Data, REPLY), "Expected %s, got %s\n", REPLY, out->msg64.Data);
276         ok(out->msg64.MessageType == LPC_REPLY, "Expected LPC_REPLY, got %d\n", out->msg64.MessageType);
277     }
278     else
279     {
280         size = FIELD_OFFSET(LPC_MESSAGE, Data[MAX_MESSAGE_LEN]);
281         LpcMessage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
282         out = HeapAlloc(GetProcessHeap(), 0, size);
283
284         LpcMessage->msg.DataSize = lstrlen(REQUEST1) + 1;
285         LpcMessage->msg.MessageSize = FIELD_OFFSET(LPC_MESSAGE, Data[LpcMessage->msg.DataSize]);
286         lstrcpy((LPSTR)LpcMessage->msg.Data, REQUEST1);
287
288         status = pNtRequestPort(PortHandle, &LpcMessage->msg);
289         ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status);
290         ok(LpcMessage->msg.MessageType == 0, "Expected 0, got %d\n", LpcMessage->msg.MessageType);
291         ok(!lstrcmp((LPSTR)LpcMessage->msg.Data, REQUEST1),
292            "Expected %s, got %s\n", REQUEST1, LpcMessage->msg.Data);
293
294         /* Fill in the message */
295         memset(LpcMessage, 0, size);
296         LpcMessage->msg.DataSize = lstrlen(REQUEST2) + 1;
297         LpcMessage->msg.MessageSize = FIELD_OFFSET(LPC_MESSAGE, Data[LpcMessage->msg.DataSize]);
298         lstrcpy((LPSTR)LpcMessage->msg.Data, REQUEST2);
299
300         /* Send the message and wait for the reply */
301         status = pNtRequestWaitReplyPort(PortHandle, &LpcMessage->msg, &out->msg);
302         ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status);
303         ok(!lstrcmp((LPSTR)out->msg.Data, REPLY), "Expected %s, got %s\n", REPLY, out->msg.Data);
304         ok(out->msg.MessageType == LPC_REPLY, "Expected LPC_REPLY, got %d\n", out->msg.MessageType);
305     }
306
307     HeapFree(GetProcessHeap(), 0, out);
308     HeapFree(GetProcessHeap(), 0, LpcMessage);
309
310     return 0;
311 }
312
313 static void test_ports_server( HANDLE PortHandle )
314 {
315     HANDLE AcceptPortHandle;
316     union lpc_message *LpcMessage;
317     ULONG size;
318     NTSTATUS status;
319     BOOL done = FALSE;
320
321     size = FIELD_OFFSET(LPC_MESSAGE, Data) + MAX_MESSAGE_LEN;
322     LpcMessage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
323
324     while (TRUE)
325     {
326         status = pNtReplyWaitReceivePort(PortHandle, NULL, NULL, &LpcMessage->msg);
327         todo_wine
328         {
329             ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d(%x)\n", status, status);
330         }
331         /* STATUS_INVALID_HANDLE: win2k without admin rights will perform an
332          *                        endless loop here
333          */
334         if ((status == STATUS_NOT_IMPLEMENTED) ||
335             (status == STATUS_INVALID_HANDLE)) return;
336
337         switch (is_wow64 ? LpcMessage->msg64.MessageType : LpcMessage->msg.MessageType)
338         {
339             case LPC_CONNECTION_REQUEST:
340                 ProcessConnectionRequest(LpcMessage, &AcceptPortHandle);
341                 break;
342
343             case LPC_REQUEST:
344                 ProcessLpcRequest(PortHandle, LpcMessage);
345                 done = TRUE;
346                 break;
347
348             case LPC_DATAGRAM:
349                 if (is_wow64)
350                     ok(!lstrcmp((LPSTR)LpcMessage->msg64.Data, REQUEST1),
351                        "Expected %s, got %s\n", REQUEST1, LpcMessage->msg64.Data);
352                 else
353                     ok(!lstrcmp((LPSTR)LpcMessage->msg.Data, REQUEST1),
354                        "Expected %s, got %s\n", REQUEST1, LpcMessage->msg.Data);
355                 break;
356
357             case LPC_CLIENT_DIED:
358                 ok(done, "Expected LPC request to be completed!\n");
359                 HeapFree(GetProcessHeap(), 0, LpcMessage);
360                 return;
361
362             default:
363                 ok(FALSE, "Unexpected message: %d\n",
364                    is_wow64 ? LpcMessage->msg64.MessageType : LpcMessage->msg.MessageType);
365                 break;
366         }
367     }
368
369     HeapFree(GetProcessHeap(), 0, LpcMessage);
370 }
371
372 START_TEST(port)
373 {
374     OBJECT_ATTRIBUTES obj;
375     HANDLE port_handle;
376     NTSTATUS status;
377
378     if (!init_function_ptrs())
379         return;
380
381     pRtlInitUnicodeString(&port, PORTNAME);
382
383     memset(&obj, 0, sizeof(OBJECT_ATTRIBUTES));
384     obj.Length = sizeof(OBJECT_ATTRIBUTES);
385     obj.ObjectName = &port;
386
387     status = pNtCreatePort(&port_handle, &obj, 100, 100, 0);
388     if (status == STATUS_ACCESS_DENIED) skip("Not enough rights\n");
389     else todo_wine ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d\n", status);
390
391     if (status == STATUS_SUCCESS)
392     {
393         DWORD id;
394         HANDLE thread = CreateThread(NULL, 0, test_ports_client, NULL, 0, &id);
395         ok(thread != NULL, "Expected non-NULL thread handle!\n");
396
397         test_ports_server( port_handle );
398         ok( WaitForSingleObject( thread, 10000 ) == 0, "thread didn't exit\n" );
399         CloseHandle(thread);
400     }
401     FreeLibrary(hntdll);
402 }