atl: Add support for the registrar parameter of AtlModuleUpdateRegistryFromResourceD.
[wine] / dlls / kernel32 / tests / pipe.c
1 /*
2  * Unit tests for named pipe functions in Wine
3  *
4  * Copyright (c) 2002 Dan Kegel
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <assert.h>
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <time.h>
25
26 #include <windef.h>
27 #include <winbase.h>
28 #include <winsock.h>
29 #include <wtypes.h>
30 #include <winerror.h>
31
32 #include "wine/test.h"
33
34 #define PIPENAME "\\\\.\\PiPe\\tests_pipe.c"
35
36 #define NB_SERVER_LOOPS 8
37
38 static HANDLE alarm_event;
39 static BOOL (WINAPI *pDuplicateTokenEx)(HANDLE,DWORD,LPSECURITY_ATTRIBUTES,
40                                         SECURITY_IMPERSONATION_LEVEL,TOKEN_TYPE,PHANDLE);
41
42
43 static void test_CreateNamedPipe(int pipemode)
44 {
45     HANDLE hnp;
46     HANDLE hFile;
47     static const char obuf[] = "Bit Bucket";
48     static const char obuf2[] = "More bits";
49     char ibuf[32], *pbuf;
50     DWORD written;
51     DWORD readden;
52     DWORD avail;
53     DWORD lpmode;
54
55     if (pipemode == PIPE_TYPE_BYTE)
56         trace("test_CreateNamedPipe starting in byte mode\n");
57     else
58         trace("test_CreateNamedPipe starting in message mode\n");
59     /* Bad parameter checks */
60     hnp = CreateNamedPipe("not a named pipe", PIPE_ACCESS_DUPLEX, pipemode | PIPE_WAIT,
61         /* nMaxInstances */ 1,
62         /* nOutBufSize */ 1024,
63         /* nInBufSize */ 1024,
64         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
65         /* lpSecurityAttrib */ NULL);
66
67     if (hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
68         /* Is this the right way to notify user of skipped tests? */
69         ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
70             "CreateNamedPipe not supported on this platform, skipping tests.\n");
71         return;
72     }
73     ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_NAME,
74         "CreateNamedPipe should fail if name doesn't start with \\\\.\\pipe\n");
75
76     hnp = CreateNamedPipe(NULL,
77         PIPE_ACCESS_DUPLEX, pipemode | PIPE_WAIT,
78         1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL);
79     ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PATH_NOT_FOUND,
80         "CreateNamedPipe should fail if name is NULL\n");
81
82     hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
83     ok(hFile == INVALID_HANDLE_VALUE
84         && GetLastError() == ERROR_FILE_NOT_FOUND,
85         "connecting to nonexistent named pipe should fail with ERROR_FILE_NOT_FOUND\n");
86
87     /* Functional checks */
88
89     hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, pipemode | PIPE_WAIT,
90         /* nMaxInstances */ 1,
91         /* nOutBufSize */ 1024,
92         /* nInBufSize */ 1024,
93         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
94         /* lpSecurityAttrib */ NULL);
95     ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
96
97     ok(WaitNamedPipeA(PIPENAME, 2000), "WaitNamedPipe failed (%d)\n", GetLastError());
98
99     hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
100     ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError());
101
102     /* don't try to do i/o if one side couldn't be opened, as it hangs */
103     if (hFile != INVALID_HANDLE_VALUE) {
104         HANDLE hFile2;
105
106         /* Make sure we can read and write a few bytes in both directions */
107         memset(ibuf, 0, sizeof(ibuf));
108         ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
109         ok(written == sizeof(obuf), "write file len 1\n");
110         ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL), "Peek\n");
111         ok(readden == sizeof(obuf), "peek 1 got %d bytes\n", readden);
112         ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
113         ok(readden == sizeof(obuf), "read 1 got %d bytes\n", readden);
114         ok(memcmp(obuf, ibuf, written) == 0, "content 1 check\n");
115
116         memset(ibuf, 0, sizeof(ibuf));
117         ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), "WriteFile\n");
118         ok(written == sizeof(obuf2), "write file len 2\n");
119         ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL), "Peek\n");
120         ok(readden == sizeof(obuf2), "peek 2 got %d bytes\n", readden);
121         ok(PeekNamedPipe(hnp, (LPVOID)1, 0, NULL, &readden, NULL), "Peek\n");
122         ok(readden == sizeof(obuf2), "peek 2 got %d bytes\n", readden);
123         ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
124         ok(readden == sizeof(obuf2), "read 2 got %d bytes\n", readden);
125         ok(memcmp(obuf2, ibuf, written) == 0, "content 2 check\n");
126
127         /* Test reading of multiple writes */
128         memset(ibuf, 0, sizeof(ibuf));
129         ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile3a\n");
130         ok(written == sizeof(obuf), "write file len 3a\n");
131         ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), " WriteFile3b\n");
132         ok(written == sizeof(obuf2), "write file len 3b\n");
133         ok(PeekNamedPipe(hFile, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek3\n");
134         if (pipemode == PIPE_TYPE_BYTE) {
135             if (readden != sizeof(obuf))  /* Linux only returns the first message */
136                 ok(readden == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes\n", readden);
137             else
138                 todo_wine ok(readden == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes\n", readden);
139         }
140         else
141         {
142             if (readden != sizeof(obuf) + sizeof(obuf2))  /* MacOS returns both messages */
143                 ok(readden == sizeof(obuf), "peek3 got %d bytes\n", readden);
144             else
145                 todo_wine ok(readden == sizeof(obuf), "peek3 got %d bytes\n", readden);
146         }
147         if (avail != sizeof(obuf)) /* older Linux kernels only return the first write here */
148             ok(avail == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes available\n", avail);
149         pbuf = ibuf;
150         ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "pipe content 3a check\n");
151         if (pipemode == PIPE_TYPE_BYTE && readden >= sizeof(obuf)+sizeof(obuf2)) {
152             pbuf += sizeof(obuf);
153             ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "pipe content 3b check\n");
154         }
155         ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
156         ok(readden == sizeof(obuf) + sizeof(obuf2), "read 3 got %d bytes\n", readden);
157         pbuf = ibuf;
158         ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 3a check\n");
159         pbuf += sizeof(obuf);
160         ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "content 3b check\n");
161
162         /* Multiple writes in the reverse direction */
163         memset(ibuf, 0, sizeof(ibuf));
164         ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile4a\n");
165         ok(written == sizeof(obuf), "write file len 4a\n");
166         ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), " WriteFile4b\n");
167         ok(written == sizeof(obuf2), "write file len 4b\n");
168         ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek4\n");
169         if (pipemode == PIPE_TYPE_BYTE) {
170             if (readden != sizeof(obuf))  /* Linux only returns the first message */
171                 /* should return all 23 bytes */
172                 ok(readden == sizeof(obuf) + sizeof(obuf2), "peek4 got %d bytes\n", readden);
173             else
174                 todo_wine ok(readden == sizeof(obuf) + sizeof(obuf2), "peek4 got %d bytes\n", readden);
175         }
176         else
177         {
178             if (readden != sizeof(obuf) + sizeof(obuf2))  /* MacOS returns both messages */
179                 ok(readden == sizeof(obuf), "peek4 got %d bytes\n", readden);
180             else
181                 todo_wine ok(readden == sizeof(obuf), "peek4 got %d bytes\n", readden);
182         }
183         if (avail != sizeof(obuf)) /* older Linux kernels only return the first write here */
184             ok(avail == sizeof(obuf) + sizeof(obuf2), "peek4 got %d bytes available\n", avail);
185         pbuf = ibuf;
186         ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "pipe content 4a check\n");
187         if (pipemode == PIPE_TYPE_BYTE && readden >= sizeof(obuf)+sizeof(obuf2)) {
188             pbuf += sizeof(obuf);
189             ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "pipe content 4b check\n");
190         }
191         ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
192         if (pipemode == PIPE_TYPE_BYTE) {
193             ok(readden == sizeof(obuf) + sizeof(obuf2), "read 4 got %d bytes\n", readden);
194         }
195         else {
196             todo_wine {
197                 ok(readden == sizeof(obuf), "read 4 got %d bytes\n", readden);
198             }
199         }
200         pbuf = ibuf;
201         ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 4a check\n");
202         if (pipemode == PIPE_TYPE_BYTE) {
203             pbuf += sizeof(obuf);
204             ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "content 4b check\n");
205         }
206
207         /* Test reading of multiple writes after a mode change
208           (CreateFile always creates a byte mode pipe) */
209         lpmode = PIPE_READMODE_MESSAGE;
210         if (pipemode == PIPE_TYPE_BYTE) {
211             /* trying to change the client end of a byte pipe to message mode should fail */
212             ok(!SetNamedPipeHandleState(hFile, &lpmode, NULL, NULL), "Change mode\n");
213         }
214         else {
215             todo_wine {
216                 ok(SetNamedPipeHandleState(hFile, &lpmode, NULL, NULL), "Change mode\n");
217             }
218         
219             memset(ibuf, 0, sizeof(ibuf));
220             ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile5a\n");
221             ok(written == sizeof(obuf), "write file len 3a\n");
222             ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), " WriteFile5b\n");
223             ok(written == sizeof(obuf2), "write file len 3b\n");
224             ok(PeekNamedPipe(hFile, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek5\n");
225             if (readden != sizeof(obuf) + sizeof(obuf2))  /* MacOS returns both writes */
226                 ok(readden == sizeof(obuf), "peek5 got %d bytes\n", readden);
227             else
228                 todo_wine ok(readden == sizeof(obuf), "peek5 got %d bytes\n", readden);
229             if (avail != sizeof(obuf)) /* older Linux kernels only return the first write here */
230                 ok(avail == sizeof(obuf) + sizeof(obuf2), "peek5 got %d bytes available\n", avail);
231             else
232                 todo_wine ok(avail == sizeof(obuf) + sizeof(obuf2), "peek5 got %d bytes available\n", avail);
233             pbuf = ibuf;
234             ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 5a check\n");
235             ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
236             todo_wine {
237                 ok(readden == sizeof(obuf), "read 5 got %d bytes\n", readden);
238             }
239             pbuf = ibuf;
240             ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 5a check\n");
241     
242             /* Multiple writes in the reverse direction */
243             /* the write of obuf2 from write4 should still be in the buffer */
244             ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek6a\n");
245             todo_wine {
246                 ok(readden == sizeof(obuf2), "peek6a got %d bytes\n", readden);
247                 ok(avail == sizeof(obuf2), "peek6a got %d bytes available\n", avail);
248             }
249             if (avail > 0) {
250                 ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
251                 ok(readden == sizeof(obuf2), "read 6a got %d bytes\n", readden);
252                 pbuf = ibuf;
253                 ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "content 6a check\n");
254             }
255             memset(ibuf, 0, sizeof(ibuf));
256             ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile6a\n");
257             ok(written == sizeof(obuf), "write file len 6a\n");
258             ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), " WriteFile6b\n");
259             ok(written == sizeof(obuf2), "write file len 6b\n");
260             ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek6\n");
261             if (readden != sizeof(obuf) + sizeof(obuf2))  /* MacOS returns both writes */
262                 ok(readden == sizeof(obuf), "peek6 got %d bytes\n", readden);
263             else
264                 todo_wine ok(readden == sizeof(obuf), "peek6 got %d bytes\n", readden);
265             if (avail != sizeof(obuf)) /* older Linux kernels only return the first write here */
266                 ok(avail == sizeof(obuf) + sizeof(obuf2), "peek6b got %d bytes available\n", avail);
267             pbuf = ibuf;
268             ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 6a check\n");
269             ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
270             todo_wine {
271                 ok(readden == sizeof(obuf), "read 6b got %d bytes\n", readden);
272             }
273             pbuf = ibuf;
274             ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 6a check\n");
275         }
276
277         /* Picky conformance tests */
278
279         /* Verify that you can't connect to pipe again
280          * until server calls DisconnectNamedPipe+ConnectNamedPipe
281          * or creates a new pipe
282          * case 1: other client not yet closed
283          */
284         hFile2 = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
285         ok(hFile2 == INVALID_HANDLE_VALUE,
286             "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail\n");
287         ok(GetLastError() == ERROR_PIPE_BUSY,
288             "connecting to named pipe before other client closes should fail with ERROR_PIPE_BUSY\n");
289
290         ok(CloseHandle(hFile), "CloseHandle\n");
291
292         /* case 2: other client already closed */
293         hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
294         ok(hFile == INVALID_HANDLE_VALUE,
295             "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail\n");
296         ok(GetLastError() == ERROR_PIPE_BUSY,
297             "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail with ERROR_PIPE_BUSY\n");
298
299         ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe\n");
300
301         /* case 3: server has called DisconnectNamedPipe but not ConnectNamed Pipe */
302         hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
303         ok(hFile == INVALID_HANDLE_VALUE,
304             "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail\n");
305         ok(GetLastError() == ERROR_PIPE_BUSY,
306             "connecting to named pipe after other client closes but before ConnectNamedPipe should fail with ERROR_PIPE_BUSY\n");
307
308         /* to be complete, we'd call ConnectNamedPipe here and loop,
309          * but by default that's blocking, so we'd either have
310          * to turn on the uncommon nonblocking mode, or
311          * use another thread.
312          */
313     }
314
315     ok(CloseHandle(hnp), "CloseHandle\n");
316
317     trace("test_CreateNamedPipe returning\n");
318 }
319
320 static void test_CreateNamedPipe_instances_must_match(void)
321 {
322     HANDLE hnp, hnp2;
323
324     /* Check no mismatch */
325     hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
326         /* nMaxInstances */ 2,
327         /* nOutBufSize */ 1024,
328         /* nInBufSize */ 1024,
329         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
330         /* lpSecurityAttrib */ NULL);
331     ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
332
333     hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
334         /* nMaxInstances */ 2,
335         /* nOutBufSize */ 1024,
336         /* nInBufSize */ 1024,
337         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
338         /* lpSecurityAttrib */ NULL);
339     ok(hnp2 != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
340
341     ok(CloseHandle(hnp), "CloseHandle\n");
342     ok(CloseHandle(hnp2), "CloseHandle\n");
343
344     /* Check nMaxInstances */
345     hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
346         /* nMaxInstances */ 1,
347         /* nOutBufSize */ 1024,
348         /* nInBufSize */ 1024,
349         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
350         /* lpSecurityAttrib */ NULL);
351     ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
352
353     hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
354         /* nMaxInstances */ 1,
355         /* nOutBufSize */ 1024,
356         /* nInBufSize */ 1024,
357         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
358         /* lpSecurityAttrib */ NULL);
359     ok(hnp2 == INVALID_HANDLE_VALUE
360         && GetLastError() == ERROR_PIPE_BUSY, "nMaxInstances not obeyed\n");
361
362     ok(CloseHandle(hnp), "CloseHandle\n");
363
364     /* Check PIPE_ACCESS_* */
365     hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
366         /* nMaxInstances */ 2,
367         /* nOutBufSize */ 1024,
368         /* nInBufSize */ 1024,
369         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
370         /* lpSecurityAttrib */ NULL);
371     ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
372
373     hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE | PIPE_WAIT,
374         /* nMaxInstances */ 1,
375         /* nOutBufSize */ 1024,
376         /* nInBufSize */ 1024,
377         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
378         /* lpSecurityAttrib */ NULL);
379     ok(hnp2 == INVALID_HANDLE_VALUE
380         && GetLastError() == ERROR_ACCESS_DENIED, "PIPE_ACCESS_* mismatch allowed\n");
381
382     ok(CloseHandle(hnp), "CloseHandle\n");
383
384     /* etc, etc */
385 }
386
387 /** implementation of alarm() */
388 static DWORD CALLBACK alarmThreadMain(LPVOID arg)
389 {
390     DWORD timeout = (DWORD) arg;
391     trace("alarmThreadMain\n");
392     if (WaitForSingleObject( alarm_event, timeout ) == WAIT_TIMEOUT)
393     {
394         ok(FALSE, "alarm\n");
395         ExitProcess(1);
396     }
397     return 1;
398 }
399
400 HANDLE hnp = INVALID_HANDLE_VALUE;
401
402 /** Trivial byte echo server - disconnects after each session */
403 static DWORD CALLBACK serverThreadMain1(LPVOID arg)
404 {
405     int i;
406
407     trace("serverThreadMain1 start\n");
408     /* Set up a simple echo server */
409     hnp = CreateNamedPipe(PIPENAME "serverThreadMain1", PIPE_ACCESS_DUPLEX,
410         PIPE_TYPE_BYTE | PIPE_WAIT,
411         /* nMaxInstances */ 1,
412         /* nOutBufSize */ 1024,
413         /* nInBufSize */ 1024,
414         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
415         /* lpSecurityAttrib */ NULL);
416
417     ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
418     for (i = 0; i < NB_SERVER_LOOPS; i++) {
419         char buf[512];
420         DWORD written;
421         DWORD readden;
422         DWORD success;
423
424         /* Wait for client to connect */
425         trace("Server calling ConnectNamedPipe...\n");
426         ok(ConnectNamedPipe(hnp, NULL)
427             || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe\n");
428         trace("ConnectNamedPipe returned.\n");
429
430         /* Echo bytes once */
431         memset(buf, 0, sizeof(buf));
432
433         trace("Server reading...\n");
434         success = ReadFile(hnp, buf, sizeof(buf), &readden, NULL);
435         trace("Server done reading.\n");
436         ok(success, "ReadFile\n");
437         ok(readden, "short read\n");
438
439         trace("Server writing...\n");
440         ok(WriteFile(hnp, buf, readden, &written, NULL), "WriteFile\n");
441         trace("Server done writing.\n");
442         ok(written == readden, "write file len\n");
443
444         /* finish this connection, wait for next one */
445         ok(FlushFileBuffers(hnp), "FlushFileBuffers\n");
446         trace("Server done flushing.\n");
447         ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe\n");
448         trace("Server done disconnecting.\n");
449     }
450     return 0;
451 }
452
453 /** Trivial byte echo server - closes after each connection */
454 static DWORD CALLBACK serverThreadMain2(LPVOID arg)
455 {
456     int i;
457     HANDLE hnpNext = 0;
458
459     trace("serverThreadMain2\n");
460     /* Set up a simple echo server */
461     hnp = CreateNamedPipe(PIPENAME "serverThreadMain2", PIPE_ACCESS_DUPLEX,
462         PIPE_TYPE_BYTE | PIPE_WAIT,
463         /* nMaxInstances */ 2,
464         /* nOutBufSize */ 1024,
465         /* nInBufSize */ 1024,
466         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
467         /* lpSecurityAttrib */ NULL);
468     ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
469
470     for (i = 0; i < NB_SERVER_LOOPS; i++) {
471         char buf[512];
472         DWORD written;
473         DWORD readden;
474         DWORD success;
475
476         /* Wait for client to connect */
477         trace("Server calling ConnectNamedPipe...\n");
478         ok(ConnectNamedPipe(hnp, NULL)
479             || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe\n");
480         trace("ConnectNamedPipe returned.\n");
481
482         /* Echo bytes once */
483         memset(buf, 0, sizeof(buf));
484
485         trace("Server reading...\n");
486         success = ReadFile(hnp, buf, sizeof(buf), &readden, NULL);
487         trace("Server done reading.\n");
488         ok(success, "ReadFile\n");
489
490         trace("Server writing...\n");
491         ok(WriteFile(hnp, buf, readden, &written, NULL), "WriteFile\n");
492         trace("Server done writing.\n");
493         ok(written == readden, "write file len\n");
494
495         /* finish this connection, wait for next one */
496         ok(FlushFileBuffers(hnp), "FlushFileBuffers\n");
497         ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe\n");
498
499         /* Set up next echo server */
500         hnpNext =
501             CreateNamedPipe(PIPENAME "serverThreadMain2", PIPE_ACCESS_DUPLEX,
502             PIPE_TYPE_BYTE | PIPE_WAIT,
503             /* nMaxInstances */ 2,
504             /* nOutBufSize */ 1024,
505             /* nInBufSize */ 1024,
506             /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
507             /* lpSecurityAttrib */ NULL);
508
509         ok(hnpNext != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
510
511         ok(CloseHandle(hnp), "CloseHandle\n");
512         hnp = hnpNext;
513     }
514     return 0;
515 }
516
517 /** Trivial byte echo server - uses overlapped named pipe calls */
518 static DWORD CALLBACK serverThreadMain3(LPVOID arg)
519 {
520     int i;
521     HANDLE hEvent;
522
523     trace("serverThreadMain3\n");
524     /* Set up a simple echo server */
525     hnp = CreateNamedPipe(PIPENAME "serverThreadMain3", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
526         PIPE_TYPE_BYTE | PIPE_WAIT,
527         /* nMaxInstances */ 1,
528         /* nOutBufSize */ 1024,
529         /* nInBufSize */ 1024,
530         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
531         /* lpSecurityAttrib */ NULL);
532     ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
533
534     hEvent = CreateEvent(NULL,  /* security attribute */
535         TRUE,                   /* manual reset event */
536         FALSE,                  /* initial state */
537         NULL);                  /* name */
538     ok(hEvent != NULL, "CreateEvent\n");
539
540     for (i = 0; i < NB_SERVER_LOOPS; i++) {
541         char buf[512];
542         DWORD written;
543         DWORD readden;
544         DWORD dummy;
545         DWORD success;
546         OVERLAPPED oOverlap;
547         int letWFSOEwait = (i & 2);
548         int letGORwait = (i & 1);
549         DWORD err;
550
551         memset(&oOverlap, 0, sizeof(oOverlap));
552         oOverlap.hEvent = hEvent;
553
554         /* Wait for client to connect */
555         trace("Server calling overlapped ConnectNamedPipe...\n");
556         success = ConnectNamedPipe(hnp, &oOverlap);
557         err = GetLastError();
558         ok(success || err == ERROR_IO_PENDING
559             || err == ERROR_PIPE_CONNECTED, "overlapped ConnectNamedPipe\n");
560         trace("overlapped ConnectNamedPipe returned.\n");
561         if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait)
562             ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait ConnectNamedPipe\n");
563         success = GetOverlappedResult(hnp, &oOverlap, &dummy, letGORwait);
564         if (!letGORwait && !letWFSOEwait && !success) {
565             ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult\n");
566             success = GetOverlappedResult(hnp, &oOverlap, &dummy, TRUE);
567         }
568         ok(success, "GetOverlappedResult ConnectNamedPipe\n");
569         trace("overlapped ConnectNamedPipe operation complete.\n");
570
571         /* Echo bytes once */
572         memset(buf, 0, sizeof(buf));
573
574         trace("Server reading...\n");
575         success = ReadFile(hnp, buf, sizeof(buf), NULL, &oOverlap);
576         trace("Server ReadFile returned...\n");
577         err = GetLastError();
578         ok(success || err == ERROR_IO_PENDING, "overlapped ReadFile\n");
579         trace("overlapped ReadFile returned.\n");
580         if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait)
581             ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait ReadFile\n");
582         success = GetOverlappedResult(hnp, &oOverlap, &readden, letGORwait);
583         if (!letGORwait && !letWFSOEwait && !success) {
584             ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult\n");
585             success = GetOverlappedResult(hnp, &oOverlap, &readden, TRUE);
586         }
587         trace("Server done reading.\n");
588         ok(success, "overlapped ReadFile\n");
589
590         trace("Server writing...\n");
591         success = WriteFile(hnp, buf, readden, NULL, &oOverlap);
592         trace("Server WriteFile returned...\n");
593         err = GetLastError();
594         ok(success || err == ERROR_IO_PENDING, "overlapped WriteFile\n");
595         trace("overlapped WriteFile returned.\n");
596         if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait)
597             ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait WriteFile\n");
598         success = GetOverlappedResult(hnp, &oOverlap, &written, letGORwait);
599         if (!letGORwait && !letWFSOEwait && !success) {
600             ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult\n");
601             success = GetOverlappedResult(hnp, &oOverlap, &written, TRUE);
602         }
603         trace("Server done writing.\n");
604         ok(success, "overlapped WriteFile\n");
605         ok(written == readden, "write file len\n");
606
607         /* finish this connection, wait for next one */
608         ok(FlushFileBuffers(hnp), "FlushFileBuffers\n");
609         ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe\n");
610     }
611     return 0;
612 }
613
614 static void exercizeServer(const char *pipename, HANDLE serverThread)
615 {
616     int i;
617
618     trace("exercizeServer starting\n");
619     for (i = 0; i < NB_SERVER_LOOPS; i++) {
620         HANDLE hFile=INVALID_HANDLE_VALUE;
621         static const char obuf[] = "Bit Bucket";
622         char ibuf[32];
623         DWORD written;
624         DWORD readden;
625         int loop;
626
627         for (loop = 0; loop < 3; loop++) {
628             DWORD err;
629             trace("Client connecting...\n");
630             /* Connect to the server */
631             hFile = CreateFileA(pipename, GENERIC_READ | GENERIC_WRITE, 0,
632                 NULL, OPEN_EXISTING, 0, 0);
633             if (hFile != INVALID_HANDLE_VALUE)
634                 break;
635             err = GetLastError();
636             if (loop == 0)
637                 ok(err == ERROR_PIPE_BUSY || err == ERROR_FILE_NOT_FOUND, "connecting to pipe\n");
638             else
639                 ok(err == ERROR_PIPE_BUSY, "connecting to pipe\n");
640             trace("connect failed, retrying\n");
641             Sleep(200);
642         }
643         ok(hFile != INVALID_HANDLE_VALUE, "client opening named pipe\n");
644
645         /* Make sure it can echo */
646         memset(ibuf, 0, sizeof(ibuf));
647         trace("Client writing...\n");
648         ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile to client end of pipe\n");
649         ok(written == sizeof(obuf), "write file len\n");
650         trace("Client reading...\n");
651         ok(ReadFile(hFile, ibuf, sizeof(obuf), &readden, NULL), "ReadFile from client end of pipe\n");
652         ok(readden == sizeof(obuf), "read file len\n");
653         ok(memcmp(obuf, ibuf, written) == 0, "content check\n");
654
655         trace("Client closing...\n");
656         ok(CloseHandle(hFile), "CloseHandle\n");
657     }
658
659     ok(WaitForSingleObject(serverThread,INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject\n");
660     CloseHandle(hnp);
661     trace("exercizeServer returning\n");
662 }
663
664 static void test_NamedPipe_2(void)
665 {
666     HANDLE serverThread;
667     DWORD serverThreadId;
668     HANDLE alarmThread;
669     DWORD alarmThreadId;
670
671     trace("test_NamedPipe_2 starting\n");
672     /* Set up a ten second timeout */
673     alarm_event = CreateEvent( NULL, TRUE, FALSE, NULL );
674     alarmThread = CreateThread(NULL, 0, alarmThreadMain, (void *) 10000, 0, &alarmThreadId);
675
676     /* The servers we're about to exercize do try to clean up carefully,
677      * but to reduce the change of a test failure due to a pipe handle
678      * leak in the test code, we'll use a different pipe name for each server.
679      */
680
681     /* Try server #1 */
682     serverThread = CreateThread(NULL, 0, serverThreadMain1, (void *)8, 0, &serverThreadId);
683     ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread\n");
684     exercizeServer(PIPENAME "serverThreadMain1", serverThread);
685
686     /* Try server #2 */
687     serverThread = CreateThread(NULL, 0, serverThreadMain2, 0, 0, &serverThreadId);
688     ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread\n");
689     exercizeServer(PIPENAME "serverThreadMain2", serverThread);
690
691     if( 0 ) /* overlapped pipe server doesn't work yet - it randomly fails */
692     {
693     /* Try server #3 */
694     serverThread = CreateThread(NULL, 0, serverThreadMain3, 0, 0, &serverThreadId);
695     ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread\n");
696     exercizeServer(PIPENAME "serverThreadMain3", serverThread);
697     }
698
699     ok(SetEvent( alarm_event ), "SetEvent\n");
700     CloseHandle( alarm_event );
701     trace("test_NamedPipe_2 returning\n");
702 }
703
704 static int test_DisconnectNamedPipe(void)
705 {
706     HANDLE hnp;
707     HANDLE hFile;
708     static const char obuf[] = "Bit Bucket";
709     char ibuf[32];
710     DWORD written;
711     DWORD readden;
712
713     hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
714         /* nMaxInstances */ 1,
715         /* nOutBufSize */ 1024,
716         /* nInBufSize */ 1024,
717         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
718         /* lpSecurityAttrib */ NULL);
719     if (INVALID_HANDLE_VALUE == hnp) {
720         trace ("Seems we have no named pipes.\n");
721         return 1;
722     }
723
724     ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL) == 0
725         && GetLastError() == ERROR_PIPE_LISTENING, "WriteFile to not-yet-connected pipe\n");
726     ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL) == 0
727         && GetLastError() == ERROR_PIPE_LISTENING, "ReadFile from not-yet-connected pipe\n");
728
729     hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
730     ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed\n");
731
732     /* don't try to do i/o if one side couldn't be opened, as it hangs */
733     if (hFile != INVALID_HANDLE_VALUE) {
734
735         /* see what happens if server calls DisconnectNamedPipe
736          * when there are bytes in the pipe
737          */
738
739         ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
740         ok(written == sizeof(obuf), "write file len\n");
741         ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe while messages waiting\n");
742         ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL) == 0
743             && GetLastError() == ERROR_PIPE_NOT_CONNECTED, "WriteFile to disconnected pipe\n");
744         ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL) == 0
745             && GetLastError() == ERROR_PIPE_NOT_CONNECTED,
746             "ReadFile from disconnected pipe with bytes waiting\n");
747         ok(CloseHandle(hFile), "CloseHandle\n");
748     }
749
750     ok(CloseHandle(hnp), "CloseHandle\n");
751
752     return 0;
753 }
754 static void test_CreatePipe(void)
755 {
756     SECURITY_ATTRIBUTES pipe_attr;
757     HANDLE piperead, pipewrite;
758     DWORD written;
759     DWORD read;
760     DWORD i, size;
761     BYTE *buffer;
762     char readbuf[32];
763
764     pipe_attr.nLength = sizeof(SECURITY_ATTRIBUTES); 
765     pipe_attr.bInheritHandle = TRUE; 
766     pipe_attr.lpSecurityDescriptor = NULL; 
767     ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, 0) != 0, "CreatePipe failed\n");
768     ok(WriteFile(pipewrite,PIPENAME,sizeof(PIPENAME), &written, NULL), "Write to anonymous pipe failed\n");
769     ok(written == sizeof(PIPENAME), "Write to anonymous pipe wrote %d bytes\n", written);
770     ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL), "Read from non empty pipe failed\n");
771     ok(read == sizeof(PIPENAME), "Read from  anonymous pipe got %d bytes\n", read);
772     ok(CloseHandle(pipewrite), "CloseHandle for the write pipe failed\n");
773     ok(CloseHandle(piperead), "CloseHandle for the read pipe failed\n");
774
775     /* Now write another chunk*/
776     ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, 0) != 0, "CreatePipe failed\n");
777     ok(WriteFile(pipewrite,PIPENAME,sizeof(PIPENAME), &written, NULL), "Write to anonymous pipe failed\n");
778     ok(written == sizeof(PIPENAME), "Write to anonymous pipe wrote %d bytes\n", written);
779     /* and close the write end, read should still succeed*/
780     ok(CloseHandle(pipewrite), "CloseHandle for the Write Pipe failed\n");
781     ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL), "Read from broken pipe withe with pending data failed\n");
782     ok(read == sizeof(PIPENAME), "Read from  anonymous pipe got %d bytes\n", read);
783     /* But now we need to get informed that the pipe is closed */
784     ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL) == 0, "Broken pipe not detected\n");
785     ok(CloseHandle(piperead), "CloseHandle for the read pipe failed\n");
786
787     /* Try bigger chunks */
788     size = 32768;
789     buffer = HeapAlloc( GetProcessHeap(), 0, size );
790     for (i = 0; i < size; i++) buffer[i] = i;
791     ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, size) != 0, "CreatePipe failed\n");
792     ok(WriteFile(pipewrite, buffer, size, &written, NULL), "Write to anonymous pipe failed\n");
793     ok(written == size, "Write to anonymous pipe wrote %d bytes\n", written);
794     /* and close the write end, read should still succeed*/
795     ok(CloseHandle(pipewrite), "CloseHandle for the Write Pipe failed\n");
796     memset( buffer, 0, size );
797     ok(ReadFile(piperead, buffer, size, &read, NULL), "Read from broken pipe withe with pending data failed\n");
798     ok(read == size, "Read from  anonymous pipe got %d bytes\n", read);
799     for (i = 0; i < size; i++) ok( buffer[i] == (BYTE)i, "invalid data %x at %x\n", buffer[i], i );
800     /* But now we need to get informed that the pipe is closed */
801     ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL) == 0, "Broken pipe not detected\n");
802     ok(CloseHandle(piperead), "CloseHandle for the read pipe failed\n");
803 }
804
805 struct named_pipe_client_params
806 {
807     DWORD security_flags;
808     HANDLE token;
809     BOOL revert;
810 };
811
812 #define PIPE_NAME "\\\\.\\pipe\\named_pipe_test"
813
814 static DWORD CALLBACK named_pipe_client_func(LPVOID p)
815 {
816     struct named_pipe_client_params *params = (struct named_pipe_client_params *)p;
817     HANDLE pipe;
818     BOOL ret;
819     const char message[] = "Test";
820     DWORD bytes_read, bytes_written;
821     char dummy;
822     TOKEN_PRIVILEGES *Privileges = NULL;
823
824     if (params->token)
825     {
826         if (params->revert)
827         {
828             /* modify the token so we can tell if the pipe impersonation
829              * token reverts to the process token */
830             ret = AdjustTokenPrivileges(params->token, TRUE, NULL, 0, NULL, NULL);
831             ok(ret, "AdjustTokenPrivileges failed with error %d\n", GetLastError());
832         }
833         ret = SetThreadToken(NULL, params->token);
834         ok(ret, "SetThreadToken failed with error %d\n", GetLastError());
835     }
836     else
837     {
838         DWORD Size = 0;
839         HANDLE process_token;
840
841         ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES, &process_token);
842         ok(ret, "OpenProcessToken failed with error %d\n", GetLastError());
843
844         ret = GetTokenInformation(process_token, TokenPrivileges, NULL, 0, &Size);
845         ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetTokenInformation(TokenPrivileges) failed with %d\n", GetLastError());
846         Privileges = (TOKEN_PRIVILEGES *)HeapAlloc(GetProcessHeap(), 0, Size);
847         ret = GetTokenInformation(process_token, TokenPrivileges, Privileges, Size, &Size);
848         ok(ret, "GetTokenInformation(TokenPrivileges) failed with %d\n", GetLastError());
849
850         ret = AdjustTokenPrivileges(process_token, TRUE, NULL, 0, NULL, NULL);
851         ok(ret, "AdjustTokenPrivileges failed with error %d\n", GetLastError());
852
853         CloseHandle(process_token);
854     }
855
856     pipe = CreateFile(PIPE_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, params->security_flags, NULL);
857     ok(pipe != INVALID_HANDLE_VALUE, "CreateFile for pipe failed with error %d\n", GetLastError());
858
859     ret = WriteFile(pipe, message, sizeof(message), &bytes_written, NULL);
860     ok(ret, "WriteFile failed with error %d\n", GetLastError());
861
862     ret = ReadFile(pipe, &dummy, sizeof(dummy), &bytes_read, NULL);
863     ok(ret, "ReadFile failed with error %d\n", GetLastError());
864
865     if (params->token)
866     {
867         if (params->revert)
868         {
869             ret = RevertToSelf();
870             ok(ret, "RevertToSelf failed with error %d\n", GetLastError());
871         }
872         else
873         {
874             ret = AdjustTokenPrivileges(params->token, TRUE, NULL, 0, NULL, NULL);
875             ok(ret, "AdjustTokenPrivileges failed with error %d\n", GetLastError());
876         }
877     }
878     else
879     {
880         HANDLE process_token;
881
882         ret = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &process_token);
883         ok(ret, "OpenProcessToken failed with error %d\n", GetLastError());
884
885         ret = AdjustTokenPrivileges(process_token, FALSE, Privileges, 0, NULL, NULL);
886         ok(ret, "AdjustTokenPrivileges failed with error %d\n", GetLastError());
887
888         HeapFree(GetProcessHeap(), 0, Privileges);
889
890         CloseHandle(process_token);
891     }
892
893     ret = WriteFile(pipe, message, sizeof(message), &bytes_written, NULL);
894     ok(ret, "WriteFile failed with error %d\n", GetLastError());
895
896     ret = ReadFile(pipe, &dummy, sizeof(dummy), &bytes_read, NULL);
897     ok(ret, "ReadFile failed with error %d\n", GetLastError());
898
899     CloseHandle(pipe);
900
901     return 0;
902 }
903
904 static HANDLE make_impersonation_token(DWORD Access, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
905 {
906     HANDLE ProcessToken;
907     HANDLE Token = NULL;
908     BOOL ret;
909
910     ret = OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE, &ProcessToken);
911     ok(ret, "OpenProcessToken failed with error %d\n", GetLastError());
912
913     ret = pDuplicateTokenEx(ProcessToken, Access, NULL, ImpersonationLevel, TokenImpersonation, &Token);
914     ok(ret, "DuplicateToken failed with error %d\n", GetLastError());
915
916     CloseHandle(ProcessToken);
917
918     return Token;
919 }
920
921 static void test_ImpersonateNamedPipeClient(HANDLE hClientToken, DWORD security_flags, BOOL revert, void (*test_func)(int, HANDLE))
922 {
923     HANDLE hPipeServer;
924     BOOL ret;
925     DWORD dwTid;
926     HANDLE hThread;
927     char buffer[256];
928     DWORD dwBytesRead;
929     DWORD error;
930     struct named_pipe_client_params params;
931     char dummy = 0;
932     DWORD dwBytesWritten;
933     HANDLE hToken = NULL;
934     SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
935     DWORD size;
936
937     hPipeServer = CreateNamedPipe(PIPE_NAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 100, 100, NMPWAIT_USE_DEFAULT_WAIT, NULL);
938     ok(hPipeServer != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with error %d\n", GetLastError());
939
940     params.security_flags = security_flags;
941     params.token = hClientToken;
942     params.revert = revert;
943     hThread = CreateThread(NULL, 0, named_pipe_client_func, &params, 0, &dwTid);
944     ok(hThread != NULL, "CreateThread failed with error %d\n", GetLastError());
945
946     SetLastError(0xdeadbeef);
947     ret = ImpersonateNamedPipeClient(hPipeServer);
948     error = GetLastError();
949     todo_wine
950     ok(!ret && (error == ERROR_CANNOT_IMPERSONATE), "ImpersonateNamedPipeClient should have failed with ERROR_CANNOT_IMPERSONATE instead of %d\n", GetLastError());
951
952     ret = ConnectNamedPipe(hPipeServer, NULL);
953     ok(ret || (GetLastError() == ERROR_PIPE_CONNECTED), "ConnectNamedPipe failed with error %d\n", GetLastError());
954
955     ret = ReadFile(hPipeServer, buffer, sizeof(buffer), &dwBytesRead, NULL);
956     ok(ret, "ReadFile failed with error %d\n", GetLastError());
957
958     ret = ImpersonateNamedPipeClient(hPipeServer);
959     todo_wine
960     ok(ret, "ImpersonateNamedPipeClient failed with error %d\n", GetLastError());
961
962     ret = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken);
963     todo_wine
964     ok(ret, "OpenThreadToken failed with error %d\n", GetLastError());
965
966     (*test_func)(0, hToken);
967
968     ret = GetTokenInformation(hToken, TokenImpersonationLevel, &ImpersonationLevel, sizeof(ImpersonationLevel), &size);
969     todo_wine {
970     ok(ret, "GetTokenInformation(TokenImpersonationLevel) failed with error %d\n", GetLastError());
971     ok(ImpersonationLevel == SecurityImpersonation, "ImpersonationLevel should have been SecurityImpersonation instead of %d\n", ImpersonationLevel);
972     }
973
974     CloseHandle(hToken);
975
976     RevertToSelf();
977
978     ret = WriteFile(hPipeServer, &dummy, sizeof(dummy), &dwBytesWritten, NULL);
979     ok(ret, "WriteFile failed with error %d\n", GetLastError());
980
981     ret = ReadFile(hPipeServer, buffer, sizeof(buffer), &dwBytesRead, NULL);
982     ok(ret, "ReadFile failed with error %d\n", GetLastError());
983
984     ret = ImpersonateNamedPipeClient(hPipeServer);
985     todo_wine
986     ok(ret, "ImpersonateNamedPipeClient failed with error %d\n", GetLastError());
987
988     ret = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken);
989     todo_wine
990     ok(ret, "OpenThreadToken failed with error %d\n", GetLastError());
991
992     (*test_func)(1, hToken);
993
994     CloseHandle(hToken);
995
996     RevertToSelf();
997
998     ret = WriteFile(hPipeServer, &dummy, sizeof(dummy), &dwBytesWritten, NULL);
999     ok(ret, "WriteFile failed with error %d\n", GetLastError());
1000
1001     WaitForSingleObject(hThread, INFINITE);
1002
1003     ret = ImpersonateNamedPipeClient(hPipeServer);
1004     todo_wine
1005     ok(ret, "ImpersonateNamedPipeClient failed with error %d\n", GetLastError());
1006
1007     RevertToSelf();
1008
1009     CloseHandle(hThread);
1010     CloseHandle(hPipeServer);
1011 }
1012
1013 static BOOL are_all_privileges_disabled(HANDLE hToken)
1014 {
1015     BOOL ret;
1016     TOKEN_PRIVILEGES *Privileges = NULL;
1017     DWORD Size = 0;
1018     BOOL all_privs_disabled = TRUE;
1019     DWORD i;
1020
1021     ret = GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &Size);
1022     if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1023     {
1024         Privileges = HeapAlloc(GetProcessHeap(), 0, Size);
1025         ret = GetTokenInformation(hToken, TokenPrivileges, Privileges, Size, &Size);
1026         if (!ret) return FALSE;
1027     }
1028     else
1029         return FALSE;
1030
1031     for (i = 0; i < Privileges->PrivilegeCount; i++)
1032     {
1033         if (Privileges->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED)
1034         {
1035             all_privs_disabled = FALSE;
1036             break;
1037         }
1038     }
1039
1040     HeapFree(GetProcessHeap(), 0, Privileges);
1041
1042     return all_privs_disabled;
1043 }
1044
1045 static DWORD get_privilege_count(HANDLE hToken)
1046 {
1047     TOKEN_STATISTICS Statistics;
1048     DWORD Size = sizeof(Statistics);
1049     BOOL ret;
1050
1051     ret = GetTokenInformation(hToken, TokenStatistics, &Statistics, Size, &Size);
1052     todo_wine
1053     ok(ret, "GetTokenInformation(TokenStatistics)\n");
1054     if (!ret) return -1;
1055
1056     return Statistics.PrivilegeCount;
1057 }
1058
1059 static void test_no_sqos_no_token(int call_index, HANDLE hToken)
1060 {
1061     DWORD priv_count;
1062
1063     switch (call_index)
1064     {
1065     case 0:
1066         priv_count = get_privilege_count(hToken);
1067         todo_wine
1068         ok(priv_count == 0, "privilege count should have been 0 instead of %d\n", priv_count);
1069         break;
1070     case 1:
1071         priv_count = get_privilege_count(hToken);
1072         ok(priv_count > 0, "privilege count should now be > 0 instead of 0\n");
1073         ok(!are_all_privileges_disabled(hToken), "impersonated token should not have been modified\n");
1074         break;
1075     default:
1076         ok(0, "shouldn't happen\n");
1077     }
1078 }
1079
1080 static void test_no_sqos(int call_index, HANDLE hToken)
1081 {
1082     switch (call_index)
1083     {
1084     case 0:
1085         ok(!are_all_privileges_disabled(hToken), "token should be a copy of the process one\n");
1086         break;
1087     case 1:
1088         todo_wine
1089         ok(are_all_privileges_disabled(hToken), "impersonated token should have been modified\n");
1090         break;
1091     default:
1092         ok(0, "shouldn't happen\n");
1093     }
1094 }
1095
1096 static void test_static_context(int call_index, HANDLE hToken)
1097 {
1098     switch (call_index)
1099     {
1100     case 0:
1101         ok(!are_all_privileges_disabled(hToken), "token should be a copy of the process one\n");
1102         break;
1103     case 1:
1104         ok(!are_all_privileges_disabled(hToken), "impersonated token should not have been modified\n");
1105         break;
1106     default:
1107         ok(0, "shouldn't happen\n");
1108     }
1109 }
1110
1111 static void test_dynamic_context(int call_index, HANDLE hToken)
1112 {
1113     switch (call_index)
1114     {
1115     case 0:
1116         ok(!are_all_privileges_disabled(hToken), "token should be a copy of the process one\n");
1117         break;
1118     case 1:
1119         todo_wine
1120         ok(are_all_privileges_disabled(hToken), "impersonated token should have been modified\n");
1121         break;
1122     default:
1123         ok(0, "shouldn't happen\n");
1124     }
1125 }
1126
1127 static void test_dynamic_context_no_token(int call_index, HANDLE hToken)
1128 {
1129     switch (call_index)
1130     {
1131     case 0:
1132         todo_wine
1133         ok(are_all_privileges_disabled(hToken), "token should be a copy of the process one\n");
1134         break;
1135     case 1:
1136         ok(!are_all_privileges_disabled(hToken), "process token modification should have been detected and impersonation token updated\n");
1137         break;
1138     default:
1139         ok(0, "shouldn't happen\n");
1140     }
1141 }
1142
1143 static void test_no_sqos_revert(int call_index, HANDLE hToken)
1144 {
1145     DWORD priv_count;
1146     switch (call_index)
1147     {
1148     case 0:
1149         priv_count = get_privilege_count(hToken);
1150         todo_wine
1151         ok(priv_count == 0, "privilege count should have been 0 instead of %d\n", priv_count);
1152         break;
1153     case 1:
1154         priv_count = get_privilege_count(hToken);
1155         ok(priv_count > 0, "privilege count should now be > 0 instead of 0\n");
1156         ok(!are_all_privileges_disabled(hToken), "impersonated token should not have been modified\n");
1157         break;
1158     default:
1159         ok(0, "shouldn't happen\n");
1160     }
1161 }
1162
1163 static void test_static_context_revert(int call_index, HANDLE hToken)
1164 {
1165     switch (call_index)
1166     {
1167     case 0:
1168         todo_wine
1169         ok(are_all_privileges_disabled(hToken), "privileges should have been disabled\n");
1170         break;
1171     case 1:
1172         todo_wine
1173         ok(are_all_privileges_disabled(hToken), "impersonated token should not have been modified\n");
1174         break;
1175     default:
1176         ok(0, "shouldn't happen\n");
1177     }
1178 }
1179
1180 static void test_dynamic_context_revert(int call_index, HANDLE hToken)
1181 {
1182     switch (call_index)
1183     {
1184     case 0:
1185         todo_wine
1186         ok(are_all_privileges_disabled(hToken), "privileges should have been disabled\n");
1187         break;
1188     case 1:
1189         ok(!are_all_privileges_disabled(hToken), "impersonated token should now be process token\n");
1190         break;
1191     default:
1192         ok(0, "shouldn't happen\n");
1193     }
1194 }
1195
1196 static void test_impersonation(void)
1197 {
1198     HANDLE hClientToken;
1199     HANDLE hProcessToken;
1200     BOOL ret;
1201
1202     if( !pDuplicateTokenEx ) {
1203         skip("DuplicateTokenEx not found\n");
1204         return;
1205     }
1206
1207     ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hProcessToken);
1208     if (!ret)
1209     {
1210         skip("couldn't open process token, skipping impersonation tests\n");
1211         return;
1212     }
1213
1214     if (!get_privilege_count(hProcessToken) || are_all_privileges_disabled(hProcessToken))
1215     {
1216         skip("token didn't have any privileges or they were all disabled. token not suitable for impersonation tests\n");
1217         CloseHandle(hProcessToken);
1218         return;
1219     }
1220     CloseHandle(hProcessToken);
1221
1222     test_ImpersonateNamedPipeClient(NULL, 0, FALSE, test_no_sqos_no_token);
1223     hClientToken = make_impersonation_token(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, SecurityImpersonation);
1224     test_ImpersonateNamedPipeClient(hClientToken, 0, FALSE, test_no_sqos);
1225     CloseHandle(hClientToken);
1226     hClientToken = make_impersonation_token(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, SecurityImpersonation);
1227     test_ImpersonateNamedPipeClient(hClientToken,
1228         SECURITY_SQOS_PRESENT | SECURITY_IMPERSONATION, FALSE,
1229         test_static_context);
1230     CloseHandle(hClientToken);
1231     hClientToken = make_impersonation_token(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, SecurityImpersonation);
1232     test_ImpersonateNamedPipeClient(hClientToken,
1233         SECURITY_SQOS_PRESENT | SECURITY_CONTEXT_TRACKING | SECURITY_IMPERSONATION,
1234         FALSE, test_dynamic_context);
1235     CloseHandle(hClientToken);
1236     test_ImpersonateNamedPipeClient(NULL,
1237         SECURITY_SQOS_PRESENT | SECURITY_CONTEXT_TRACKING | SECURITY_IMPERSONATION,
1238         FALSE, test_dynamic_context_no_token);
1239
1240     hClientToken = make_impersonation_token(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, SecurityImpersonation);
1241     test_ImpersonateNamedPipeClient(hClientToken, 0, TRUE, test_no_sqos_revert);
1242     CloseHandle(hClientToken);
1243     hClientToken = make_impersonation_token(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, SecurityImpersonation);
1244     test_ImpersonateNamedPipeClient(hClientToken,
1245         SECURITY_SQOS_PRESENT | SECURITY_IMPERSONATION, TRUE,
1246         test_static_context_revert);
1247     CloseHandle(hClientToken);
1248     hClientToken = make_impersonation_token(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, SecurityImpersonation);
1249     test_ImpersonateNamedPipeClient(hClientToken,
1250         SECURITY_SQOS_PRESENT | SECURITY_CONTEXT_TRACKING | SECURITY_IMPERSONATION,
1251         TRUE, test_dynamic_context_revert);
1252     CloseHandle(hClientToken);
1253 }
1254
1255 START_TEST(pipe)
1256 {
1257     HMODULE hmod;
1258
1259     hmod = GetModuleHandle("advapi32.dll");
1260     pDuplicateTokenEx = (void *) GetProcAddress(hmod, "DuplicateTokenEx");
1261
1262     trace("test 1 of 7:\n");
1263     if (test_DisconnectNamedPipe())
1264         return;
1265     trace("test 2 of 7:\n");
1266     test_CreateNamedPipe_instances_must_match();
1267     trace("test 3 of 7:\n");
1268     test_NamedPipe_2();
1269     trace("test 4 of 7:\n");
1270     test_CreateNamedPipe(PIPE_TYPE_BYTE);
1271     trace("test 5 of 7\n");
1272     test_CreateNamedPipe(PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE);
1273     trace("test 6 of 7\n");
1274     test_CreatePipe();
1275     trace("test 7 of 7\n");
1276     test_impersonation();
1277     trace("all tests done\n");
1278 }