kernel32/tests: Fix the last remaining failure on NT4.
[wine/multimedia.git] / dlls / kernel32 / tests / pipe.c
blobee109747d330d03e3759f431ca23aa4d1ba23747
1 /*
2 * Unit tests for named pipe functions in Wine
4 * Copyright (c) 2002 Dan Kegel
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.
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.
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
21 #include <assert.h>
22 #include <stdarg.h>
23 #include <stdio.h>
25 #include <windef.h>
26 #include <winbase.h>
27 #include <winsock.h>
28 #include <wtypes.h>
29 #include <winerror.h>
31 #include "wine/test.h"
33 #define PIPENAME "\\\\.\\PiPe\\tests_pipe.c"
35 #define NB_SERVER_LOOPS 8
37 static HANDLE alarm_event;
38 static BOOL (WINAPI *pDuplicateTokenEx)(HANDLE,DWORD,LPSECURITY_ATTRIBUTES,
39 SECURITY_IMPERSONATION_LEVEL,TOKEN_TYPE,PHANDLE);
42 static void test_CreateNamedPipe(int pipemode)
44 HANDLE hnp;
45 HANDLE hFile;
46 static const char obuf[] = "Bit Bucket";
47 static const char obuf2[] = "More bits";
48 char ibuf[32], *pbuf;
49 DWORD written;
50 DWORD readden;
51 DWORD avail;
52 DWORD lpmode;
54 if (pipemode == PIPE_TYPE_BYTE)
55 trace("test_CreateNamedPipe starting in byte mode\n");
56 else
57 trace("test_CreateNamedPipe starting in message mode\n");
58 /* Bad parameter checks */
59 hnp = CreateNamedPipe("not a named pipe", PIPE_ACCESS_DUPLEX, pipemode | PIPE_WAIT,
60 /* nMaxInstances */ 1,
61 /* nOutBufSize */ 1024,
62 /* nInBufSize */ 1024,
63 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
64 /* lpSecurityAttrib */ NULL);
66 if (hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
67 /* Is this the right way to notify user of skipped tests? */
68 ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
69 "CreateNamedPipe not supported on this platform, skipping tests.\n");
70 return;
72 ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_NAME,
73 "CreateNamedPipe should fail if name doesn't start with \\\\.\\pipe\n");
75 hnp = CreateNamedPipe(NULL,
76 PIPE_ACCESS_DUPLEX, pipemode | PIPE_WAIT,
77 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL);
78 ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PATH_NOT_FOUND,
79 "CreateNamedPipe should fail if name is NULL\n");
81 hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
82 ok(hFile == INVALID_HANDLE_VALUE
83 && GetLastError() == ERROR_FILE_NOT_FOUND,
84 "connecting to nonexistent named pipe should fail with ERROR_FILE_NOT_FOUND\n");
86 /* Functional checks */
88 hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, pipemode | PIPE_WAIT,
89 /* nMaxInstances */ 1,
90 /* nOutBufSize */ 1024,
91 /* nInBufSize */ 1024,
92 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
93 /* lpSecurityAttrib */ NULL);
94 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
96 ok(WaitNamedPipeA(PIPENAME, 2000), "WaitNamedPipe failed (%d)\n", GetLastError());
98 hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
99 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError());
101 ok(!WaitNamedPipeA(PIPENAME, 1000), "WaitNamedPipe succeeded\n");
102 ok(GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError());
104 /* don't try to do i/o if one side couldn't be opened, as it hangs */
105 if (hFile != INVALID_HANDLE_VALUE) {
106 HANDLE hFile2;
108 /* Make sure we can read and write a few bytes in both directions */
109 memset(ibuf, 0, sizeof(ibuf));
110 ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
111 ok(written == sizeof(obuf), "write file len 1\n");
112 ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL), "Peek\n");
113 ok(readden == sizeof(obuf), "peek 1 got %d bytes\n", readden);
114 ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
115 ok(readden == sizeof(obuf), "read 1 got %d bytes\n", readden);
116 ok(memcmp(obuf, ibuf, written) == 0, "content 1 check\n");
118 memset(ibuf, 0, sizeof(ibuf));
119 ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), "WriteFile\n");
120 ok(written == sizeof(obuf2), "write file len 2\n");
121 ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL), "Peek\n");
122 ok(readden == sizeof(obuf2), "peek 2 got %d bytes\n", readden);
123 ok(PeekNamedPipe(hnp, (LPVOID)1, 0, NULL, &readden, NULL), "Peek\n");
124 ok(readden == sizeof(obuf2), "peek 2 got %d bytes\n", readden);
125 ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
126 ok(readden == sizeof(obuf2), "read 2 got %d bytes\n", readden);
127 ok(memcmp(obuf2, ibuf, written) == 0, "content 2 check\n");
129 /* Test reading of multiple writes */
130 memset(ibuf, 0, sizeof(ibuf));
131 ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile3a\n");
132 ok(written == sizeof(obuf), "write file len 3a\n");
133 ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), " WriteFile3b\n");
134 ok(written == sizeof(obuf2), "write file len 3b\n");
135 ok(PeekNamedPipe(hFile, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek3\n");
136 if (pipemode == PIPE_TYPE_BYTE) {
137 if (readden != sizeof(obuf)) /* Linux only returns the first message */
138 ok(readden == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes\n", readden);
139 else
140 todo_wine ok(readden == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes\n", readden);
142 else
144 if (readden != sizeof(obuf) + sizeof(obuf2)) /* MacOS returns both messages */
145 ok(readden == sizeof(obuf), "peek3 got %d bytes\n", readden);
146 else
147 todo_wine ok(readden == sizeof(obuf), "peek3 got %d bytes\n", readden);
149 if (avail != sizeof(obuf)) /* older Linux kernels only return the first write here */
150 ok(avail == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes available\n", avail);
151 pbuf = ibuf;
152 ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "pipe content 3a check\n");
153 if (pipemode == PIPE_TYPE_BYTE && readden >= sizeof(obuf)+sizeof(obuf2)) {
154 pbuf += sizeof(obuf);
155 ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "pipe content 3b check\n");
157 ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
158 ok(readden == sizeof(obuf) + sizeof(obuf2), "read 3 got %d bytes\n", readden);
159 pbuf = ibuf;
160 ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 3a check\n");
161 pbuf += sizeof(obuf);
162 ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "content 3b check\n");
164 /* Multiple writes in the reverse direction */
165 memset(ibuf, 0, sizeof(ibuf));
166 ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile4a\n");
167 ok(written == sizeof(obuf), "write file len 4a\n");
168 ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), " WriteFile4b\n");
169 ok(written == sizeof(obuf2), "write file len 4b\n");
170 ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek4\n");
171 if (pipemode == PIPE_TYPE_BYTE) {
172 if (readden != sizeof(obuf)) /* Linux only returns the first message */
173 /* should return all 23 bytes */
174 ok(readden == sizeof(obuf) + sizeof(obuf2), "peek4 got %d bytes\n", readden);
175 else
176 todo_wine ok(readden == sizeof(obuf) + sizeof(obuf2), "peek4 got %d bytes\n", readden);
178 else
180 if (readden != sizeof(obuf) + sizeof(obuf2)) /* MacOS returns both messages */
181 ok(readden == sizeof(obuf), "peek4 got %d bytes\n", readden);
182 else
183 todo_wine ok(readden == sizeof(obuf), "peek4 got %d bytes\n", readden);
185 if (avail != sizeof(obuf)) /* older Linux kernels only return the first write here */
186 ok(avail == sizeof(obuf) + sizeof(obuf2), "peek4 got %d bytes available\n", avail);
187 pbuf = ibuf;
188 ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "pipe content 4a check\n");
189 if (pipemode == PIPE_TYPE_BYTE && readden >= sizeof(obuf)+sizeof(obuf2)) {
190 pbuf += sizeof(obuf);
191 ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "pipe content 4b check\n");
193 ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
194 if (pipemode == PIPE_TYPE_BYTE) {
195 ok(readden == sizeof(obuf) + sizeof(obuf2), "read 4 got %d bytes\n", readden);
197 else {
198 todo_wine {
199 ok(readden == sizeof(obuf), "read 4 got %d bytes\n", readden);
202 pbuf = ibuf;
203 ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 4a check\n");
204 if (pipemode == PIPE_TYPE_BYTE) {
205 pbuf += sizeof(obuf);
206 ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "content 4b check\n");
209 /* Test reading of multiple writes after a mode change
210 (CreateFile always creates a byte mode pipe) */
211 lpmode = PIPE_READMODE_MESSAGE;
212 if (pipemode == PIPE_TYPE_BYTE) {
213 /* trying to change the client end of a byte pipe to message mode should fail */
214 ok(!SetNamedPipeHandleState(hFile, &lpmode, NULL, NULL), "Change mode\n");
216 else {
217 todo_wine {
218 ok(SetNamedPipeHandleState(hFile, &lpmode, NULL, NULL), "Change mode\n");
221 memset(ibuf, 0, sizeof(ibuf));
222 ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile5a\n");
223 ok(written == sizeof(obuf), "write file len 3a\n");
224 ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), " WriteFile5b\n");
225 ok(written == sizeof(obuf2), "write file len 3b\n");
226 ok(PeekNamedPipe(hFile, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek5\n");
227 if (readden != sizeof(obuf) + sizeof(obuf2)) /* MacOS returns both writes */
228 ok(readden == sizeof(obuf), "peek5 got %d bytes\n", readden);
229 else
230 todo_wine ok(readden == sizeof(obuf), "peek5 got %d bytes\n", readden);
231 if (avail != sizeof(obuf)) /* older Linux kernels only return the first write here */
232 ok(avail == sizeof(obuf) + sizeof(obuf2), "peek5 got %d bytes available\n", avail);
233 else
234 todo_wine ok(avail == sizeof(obuf) + sizeof(obuf2), "peek5 got %d bytes available\n", avail);
235 pbuf = ibuf;
236 ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 5a check\n");
237 ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
238 todo_wine {
239 ok(readden == sizeof(obuf), "read 5 got %d bytes\n", readden);
241 pbuf = ibuf;
242 ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 5a check\n");
244 /* Multiple writes in the reverse direction */
245 /* the write of obuf2 from write4 should still be in the buffer */
246 ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek6a\n");
247 todo_wine {
248 ok(readden == sizeof(obuf2), "peek6a got %d bytes\n", readden);
249 ok(avail == sizeof(obuf2), "peek6a got %d bytes available\n", avail);
251 if (avail > 0) {
252 ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
253 ok(readden == sizeof(obuf2), "read 6a got %d bytes\n", readden);
254 pbuf = ibuf;
255 ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "content 6a check\n");
257 memset(ibuf, 0, sizeof(ibuf));
258 ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile6a\n");
259 ok(written == sizeof(obuf), "write file len 6a\n");
260 ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), " WriteFile6b\n");
261 ok(written == sizeof(obuf2), "write file len 6b\n");
262 ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek6\n");
263 if (readden != sizeof(obuf) + sizeof(obuf2)) /* MacOS returns both writes */
264 ok(readden == sizeof(obuf), "peek6 got %d bytes\n", readden);
265 else
266 todo_wine ok(readden == sizeof(obuf), "peek6 got %d bytes\n", readden);
267 if (avail != sizeof(obuf)) /* older Linux kernels only return the first write here */
268 ok(avail == sizeof(obuf) + sizeof(obuf2), "peek6b got %d bytes available\n", avail);
269 pbuf = ibuf;
270 ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 6a check\n");
271 ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
272 todo_wine {
273 ok(readden == sizeof(obuf), "read 6b got %d bytes\n", readden);
275 pbuf = ibuf;
276 ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 6a check\n");
279 /* Picky conformance tests */
281 /* Verify that you can't connect to pipe again
282 * until server calls DisconnectNamedPipe+ConnectNamedPipe
283 * or creates a new pipe
284 * case 1: other client not yet closed
286 hFile2 = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
287 ok(hFile2 == INVALID_HANDLE_VALUE,
288 "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail\n");
289 ok(GetLastError() == ERROR_PIPE_BUSY,
290 "connecting to named pipe before other client closes should fail with ERROR_PIPE_BUSY\n");
292 ok(CloseHandle(hFile), "CloseHandle\n");
294 /* case 2: other client already closed */
295 hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
296 ok(hFile == INVALID_HANDLE_VALUE,
297 "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail\n");
298 ok(GetLastError() == ERROR_PIPE_BUSY,
299 "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail with ERROR_PIPE_BUSY\n");
301 ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe\n");
303 /* case 3: server has called DisconnectNamedPipe but not ConnectNamed Pipe */
304 hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
305 ok(hFile == INVALID_HANDLE_VALUE,
306 "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail\n");
307 ok(GetLastError() == ERROR_PIPE_BUSY,
308 "connecting to named pipe after other client closes but before ConnectNamedPipe should fail with ERROR_PIPE_BUSY\n");
310 /* to be complete, we'd call ConnectNamedPipe here and loop,
311 * but by default that's blocking, so we'd either have
312 * to turn on the uncommon nonblocking mode, or
313 * use another thread.
317 ok(CloseHandle(hnp), "CloseHandle\n");
319 trace("test_CreateNamedPipe returning\n");
322 static void test_CreateNamedPipe_instances_must_match(void)
324 HANDLE hnp, hnp2;
326 /* Check no mismatch */
327 hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
328 /* nMaxInstances */ 2,
329 /* nOutBufSize */ 1024,
330 /* nInBufSize */ 1024,
331 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
332 /* lpSecurityAttrib */ NULL);
333 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
335 hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
336 /* nMaxInstances */ 2,
337 /* nOutBufSize */ 1024,
338 /* nInBufSize */ 1024,
339 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
340 /* lpSecurityAttrib */ NULL);
341 ok(hnp2 != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
343 ok(CloseHandle(hnp), "CloseHandle\n");
344 ok(CloseHandle(hnp2), "CloseHandle\n");
346 /* Check nMaxInstances */
347 hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
348 /* nMaxInstances */ 1,
349 /* nOutBufSize */ 1024,
350 /* nInBufSize */ 1024,
351 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
352 /* lpSecurityAttrib */ NULL);
353 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
355 hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
356 /* nMaxInstances */ 1,
357 /* nOutBufSize */ 1024,
358 /* nInBufSize */ 1024,
359 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
360 /* lpSecurityAttrib */ NULL);
361 ok(hnp2 == INVALID_HANDLE_VALUE
362 && GetLastError() == ERROR_PIPE_BUSY, "nMaxInstances not obeyed\n");
364 ok(CloseHandle(hnp), "CloseHandle\n");
366 /* Check PIPE_ACCESS_* */
367 hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
368 /* nMaxInstances */ 2,
369 /* nOutBufSize */ 1024,
370 /* nInBufSize */ 1024,
371 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
372 /* lpSecurityAttrib */ NULL);
373 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
375 hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE | PIPE_WAIT,
376 /* nMaxInstances */ 1,
377 /* nOutBufSize */ 1024,
378 /* nInBufSize */ 1024,
379 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
380 /* lpSecurityAttrib */ NULL);
381 ok(hnp2 == INVALID_HANDLE_VALUE
382 && GetLastError() == ERROR_ACCESS_DENIED, "PIPE_ACCESS_* mismatch allowed\n");
384 ok(CloseHandle(hnp), "CloseHandle\n");
386 /* etc, etc */
389 /** implementation of alarm() */
390 static DWORD CALLBACK alarmThreadMain(LPVOID arg)
392 DWORD_PTR timeout = (DWORD_PTR) arg;
393 trace("alarmThreadMain\n");
394 if (WaitForSingleObject( alarm_event, timeout ) == WAIT_TIMEOUT)
396 ok(FALSE, "alarm\n");
397 ExitProcess(1);
399 return 1;
402 HANDLE hnp = INVALID_HANDLE_VALUE;
404 /** Trivial byte echo server - disconnects after each session */
405 static DWORD CALLBACK serverThreadMain1(LPVOID arg)
407 int i;
409 trace("serverThreadMain1 start\n");
410 /* Set up a simple echo server */
411 hnp = CreateNamedPipe(PIPENAME "serverThreadMain1", PIPE_ACCESS_DUPLEX,
412 PIPE_TYPE_BYTE | PIPE_WAIT,
413 /* nMaxInstances */ 1,
414 /* nOutBufSize */ 1024,
415 /* nInBufSize */ 1024,
416 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
417 /* lpSecurityAttrib */ NULL);
419 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
420 for (i = 0; i < NB_SERVER_LOOPS; i++) {
421 char buf[512];
422 DWORD written;
423 DWORD readden;
424 DWORD success;
426 /* Wait for client to connect */
427 trace("Server calling ConnectNamedPipe...\n");
428 ok(ConnectNamedPipe(hnp, NULL)
429 || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe\n");
430 trace("ConnectNamedPipe returned.\n");
432 /* Echo bytes once */
433 memset(buf, 0, sizeof(buf));
435 trace("Server reading...\n");
436 success = ReadFile(hnp, buf, sizeof(buf), &readden, NULL);
437 trace("Server done reading.\n");
438 ok(success, "ReadFile\n");
439 ok(readden, "short read\n");
441 trace("Server writing...\n");
442 ok(WriteFile(hnp, buf, readden, &written, NULL), "WriteFile\n");
443 trace("Server done writing.\n");
444 ok(written == readden, "write file len\n");
446 /* finish this connection, wait for next one */
447 ok(FlushFileBuffers(hnp), "FlushFileBuffers\n");
448 trace("Server done flushing.\n");
449 ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe\n");
450 trace("Server done disconnecting.\n");
452 return 0;
455 /** Trivial byte echo server - closes after each connection */
456 static DWORD CALLBACK serverThreadMain2(LPVOID arg)
458 int i;
459 HANDLE hnpNext = 0;
461 trace("serverThreadMain2\n");
462 /* Set up a simple echo server */
463 hnp = CreateNamedPipe(PIPENAME "serverThreadMain2", PIPE_ACCESS_DUPLEX,
464 PIPE_TYPE_BYTE | PIPE_WAIT,
465 /* nMaxInstances */ 2,
466 /* nOutBufSize */ 1024,
467 /* nInBufSize */ 1024,
468 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
469 /* lpSecurityAttrib */ NULL);
470 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
472 for (i = 0; i < NB_SERVER_LOOPS; i++) {
473 char buf[512];
474 DWORD written;
475 DWORD readden;
476 DWORD success;
478 /* Wait for client to connect */
479 trace("Server calling ConnectNamedPipe...\n");
480 ok(ConnectNamedPipe(hnp, NULL)
481 || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe\n");
482 trace("ConnectNamedPipe returned.\n");
484 /* Echo bytes once */
485 memset(buf, 0, sizeof(buf));
487 trace("Server reading...\n");
488 success = ReadFile(hnp, buf, sizeof(buf), &readden, NULL);
489 trace("Server done reading.\n");
490 ok(success, "ReadFile\n");
492 trace("Server writing...\n");
493 ok(WriteFile(hnp, buf, readden, &written, NULL), "WriteFile\n");
494 trace("Server done writing.\n");
495 ok(written == readden, "write file len\n");
497 /* finish this connection, wait for next one */
498 ok(FlushFileBuffers(hnp), "FlushFileBuffers\n");
499 ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe\n");
501 /* Set up next echo server */
502 hnpNext =
503 CreateNamedPipe(PIPENAME "serverThreadMain2", PIPE_ACCESS_DUPLEX,
504 PIPE_TYPE_BYTE | PIPE_WAIT,
505 /* nMaxInstances */ 2,
506 /* nOutBufSize */ 1024,
507 /* nInBufSize */ 1024,
508 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
509 /* lpSecurityAttrib */ NULL);
511 ok(hnpNext != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
513 ok(CloseHandle(hnp), "CloseHandle\n");
514 hnp = hnpNext;
516 return 0;
519 /** Trivial byte echo server - uses overlapped named pipe calls */
520 static DWORD CALLBACK serverThreadMain3(LPVOID arg)
522 int i;
523 HANDLE hEvent;
525 trace("serverThreadMain3\n");
526 /* Set up a simple echo server */
527 hnp = CreateNamedPipe(PIPENAME "serverThreadMain3", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
528 PIPE_TYPE_BYTE | PIPE_WAIT,
529 /* nMaxInstances */ 1,
530 /* nOutBufSize */ 1024,
531 /* nInBufSize */ 1024,
532 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
533 /* lpSecurityAttrib */ NULL);
534 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
536 hEvent = CreateEvent(NULL, /* security attribute */
537 TRUE, /* manual reset event */
538 FALSE, /* initial state */
539 NULL); /* name */
540 ok(hEvent != NULL, "CreateEvent\n");
542 for (i = 0; i < NB_SERVER_LOOPS; i++) {
543 char buf[512];
544 DWORD written;
545 DWORD readden;
546 DWORD dummy;
547 DWORD success;
548 OVERLAPPED oOverlap;
549 int letWFSOEwait = (i & 2);
550 int letGORwait = (i & 1);
551 DWORD err;
553 memset(&oOverlap, 0, sizeof(oOverlap));
554 oOverlap.hEvent = hEvent;
556 /* Wait for client to connect */
557 trace("Server calling overlapped ConnectNamedPipe...\n");
558 success = ConnectNamedPipe(hnp, &oOverlap);
559 err = GetLastError();
560 ok(success || err == ERROR_IO_PENDING
561 || err == ERROR_PIPE_CONNECTED, "overlapped ConnectNamedPipe\n");
562 trace("overlapped ConnectNamedPipe returned.\n");
563 if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait)
564 ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait ConnectNamedPipe\n");
565 success = GetOverlappedResult(hnp, &oOverlap, &dummy, letGORwait);
566 if (!letGORwait && !letWFSOEwait && !success) {
567 ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult\n");
568 success = GetOverlappedResult(hnp, &oOverlap, &dummy, TRUE);
570 ok(success, "GetOverlappedResult ConnectNamedPipe\n");
571 trace("overlapped ConnectNamedPipe operation complete.\n");
573 /* Echo bytes once */
574 memset(buf, 0, sizeof(buf));
576 trace("Server reading...\n");
577 success = ReadFile(hnp, buf, sizeof(buf), NULL, &oOverlap);
578 trace("Server ReadFile returned...\n");
579 err = GetLastError();
580 ok(success || err == ERROR_IO_PENDING, "overlapped ReadFile\n");
581 trace("overlapped ReadFile returned.\n");
582 if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait)
583 ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait ReadFile\n");
584 success = GetOverlappedResult(hnp, &oOverlap, &readden, letGORwait);
585 if (!letGORwait && !letWFSOEwait && !success) {
586 ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult\n");
587 success = GetOverlappedResult(hnp, &oOverlap, &readden, TRUE);
589 trace("Server done reading.\n");
590 ok(success, "overlapped ReadFile\n");
592 trace("Server writing...\n");
593 success = WriteFile(hnp, buf, readden, NULL, &oOverlap);
594 trace("Server WriteFile returned...\n");
595 err = GetLastError();
596 ok(success || err == ERROR_IO_PENDING, "overlapped WriteFile\n");
597 trace("overlapped WriteFile returned.\n");
598 if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait)
599 ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait WriteFile\n");
600 success = GetOverlappedResult(hnp, &oOverlap, &written, letGORwait);
601 if (!letGORwait && !letWFSOEwait && !success) {
602 ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult\n");
603 success = GetOverlappedResult(hnp, &oOverlap, &written, TRUE);
605 trace("Server done writing.\n");
606 ok(success, "overlapped WriteFile\n");
607 ok(written == readden, "write file len\n");
609 /* finish this connection, wait for next one */
610 ok(FlushFileBuffers(hnp), "FlushFileBuffers\n");
611 ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe\n");
613 return 0;
616 static void exercizeServer(const char *pipename, HANDLE serverThread)
618 int i;
620 trace("exercizeServer starting\n");
621 for (i = 0; i < NB_SERVER_LOOPS; i++) {
622 HANDLE hFile=INVALID_HANDLE_VALUE;
623 static const char obuf[] = "Bit Bucket";
624 char ibuf[32];
625 DWORD written;
626 DWORD readden;
627 int loop;
629 for (loop = 0; loop < 3; loop++) {
630 DWORD err;
631 trace("Client connecting...\n");
632 /* Connect to the server */
633 hFile = CreateFileA(pipename, GENERIC_READ | GENERIC_WRITE, 0,
634 NULL, OPEN_EXISTING, 0, 0);
635 if (hFile != INVALID_HANDLE_VALUE)
636 break;
637 err = GetLastError();
638 if (loop == 0)
639 ok(err == ERROR_PIPE_BUSY || err == ERROR_FILE_NOT_FOUND, "connecting to pipe\n");
640 else
641 ok(err == ERROR_PIPE_BUSY, "connecting to pipe\n");
642 trace("connect failed, retrying\n");
643 Sleep(200);
645 ok(hFile != INVALID_HANDLE_VALUE, "client opening named pipe\n");
647 /* Make sure it can echo */
648 memset(ibuf, 0, sizeof(ibuf));
649 trace("Client writing...\n");
650 ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile to client end of pipe\n");
651 ok(written == sizeof(obuf), "write file len\n");
652 trace("Client reading...\n");
653 ok(ReadFile(hFile, ibuf, sizeof(obuf), &readden, NULL), "ReadFile from client end of pipe\n");
654 ok(readden == sizeof(obuf), "read file len\n");
655 ok(memcmp(obuf, ibuf, written) == 0, "content check\n");
657 trace("Client closing...\n");
658 ok(CloseHandle(hFile), "CloseHandle\n");
661 ok(WaitForSingleObject(serverThread,INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject\n");
662 CloseHandle(hnp);
663 trace("exercizeServer returning\n");
666 static void test_NamedPipe_2(void)
668 HANDLE serverThread;
669 DWORD serverThreadId;
670 HANDLE alarmThread;
671 DWORD alarmThreadId;
673 trace("test_NamedPipe_2 starting\n");
674 /* Set up a ten second timeout */
675 alarm_event = CreateEvent( NULL, TRUE, FALSE, NULL );
676 alarmThread = CreateThread(NULL, 0, alarmThreadMain, (void *) 10000, 0, &alarmThreadId);
678 /* The servers we're about to exercize do try to clean up carefully,
679 * but to reduce the change of a test failure due to a pipe handle
680 * leak in the test code, we'll use a different pipe name for each server.
683 /* Try server #1 */
684 serverThread = CreateThread(NULL, 0, serverThreadMain1, (void *)8, 0, &serverThreadId);
685 ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread\n");
686 exercizeServer(PIPENAME "serverThreadMain1", serverThread);
688 /* Try server #2 */
689 serverThread = CreateThread(NULL, 0, serverThreadMain2, 0, 0, &serverThreadId);
690 ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread\n");
691 exercizeServer(PIPENAME "serverThreadMain2", serverThread);
693 if( 0 ) /* overlapped pipe server doesn't work yet - it randomly fails */
695 /* Try server #3 */
696 serverThread = CreateThread(NULL, 0, serverThreadMain3, 0, 0, &serverThreadId);
697 ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread\n");
698 exercizeServer(PIPENAME "serverThreadMain3", serverThread);
701 ok(SetEvent( alarm_event ), "SetEvent\n");
702 CloseHandle( alarm_event );
703 trace("test_NamedPipe_2 returning\n");
706 static int test_DisconnectNamedPipe(void)
708 HANDLE hnp;
709 HANDLE hFile;
710 static const char obuf[] = "Bit Bucket";
711 char ibuf[32];
712 DWORD written;
713 DWORD readden;
715 SetLastError(0xdeadbeef);
716 hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
717 /* nMaxInstances */ 1,
718 /* nOutBufSize */ 1024,
719 /* nInBufSize */ 1024,
720 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
721 /* lpSecurityAttrib */ NULL);
722 if ((hnp == INVALID_HANDLE_VALUE /* Win98 */ || !hnp /* Win95 */)
723 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
725 win_skip("Named pipes are not implemented\n");
726 return 1;
729 ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL) == 0
730 && GetLastError() == ERROR_PIPE_LISTENING, "WriteFile to not-yet-connected pipe\n");
731 ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL) == 0
732 && GetLastError() == ERROR_PIPE_LISTENING, "ReadFile from not-yet-connected pipe\n");
734 hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
735 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed\n");
737 /* don't try to do i/o if one side couldn't be opened, as it hangs */
738 if (hFile != INVALID_HANDLE_VALUE) {
740 /* see what happens if server calls DisconnectNamedPipe
741 * when there are bytes in the pipe
744 ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
745 ok(written == sizeof(obuf), "write file len\n");
746 ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe while messages waiting\n");
747 ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL) == 0
748 && GetLastError() == ERROR_PIPE_NOT_CONNECTED, "WriteFile to disconnected pipe\n");
749 ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL) == 0
750 && GetLastError() == ERROR_PIPE_NOT_CONNECTED,
751 "ReadFile from disconnected pipe with bytes waiting\n");
752 ok(!DisconnectNamedPipe(hnp) && GetLastError() == ERROR_PIPE_NOT_CONNECTED,
753 "DisconnectNamedPipe worked twice\n");
754 ok(CloseHandle(hFile), "CloseHandle\n");
757 ok(CloseHandle(hnp), "CloseHandle\n");
759 return 0;
761 static void test_CreatePipe(void)
763 SECURITY_ATTRIBUTES pipe_attr;
764 HANDLE piperead, pipewrite;
765 DWORD written;
766 DWORD read;
767 DWORD i, size;
768 BYTE *buffer;
769 char readbuf[32];
771 pipe_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
772 pipe_attr.bInheritHandle = TRUE;
773 pipe_attr.lpSecurityDescriptor = NULL;
774 ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, 0) != 0, "CreatePipe failed\n");
775 ok(WriteFile(pipewrite,PIPENAME,sizeof(PIPENAME), &written, NULL), "Write to anonymous pipe failed\n");
776 ok(written == sizeof(PIPENAME), "Write to anonymous pipe wrote %d bytes\n", written);
777 ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL), "Read from non empty pipe failed\n");
778 ok(read == sizeof(PIPENAME), "Read from anonymous pipe got %d bytes\n", read);
779 ok(CloseHandle(pipewrite), "CloseHandle for the write pipe failed\n");
780 ok(CloseHandle(piperead), "CloseHandle for the read pipe failed\n");
782 /* Now write another chunk*/
783 ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, 0) != 0, "CreatePipe failed\n");
784 ok(WriteFile(pipewrite,PIPENAME,sizeof(PIPENAME), &written, NULL), "Write to anonymous pipe failed\n");
785 ok(written == sizeof(PIPENAME), "Write to anonymous pipe wrote %d bytes\n", written);
786 /* and close the write end, read should still succeed*/
787 ok(CloseHandle(pipewrite), "CloseHandle for the Write Pipe failed\n");
788 ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL), "Read from broken pipe withe with pending data failed\n");
789 ok(read == sizeof(PIPENAME), "Read from anonymous pipe got %d bytes\n", read);
790 /* But now we need to get informed that the pipe is closed */
791 ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL) == 0, "Broken pipe not detected\n");
792 ok(CloseHandle(piperead), "CloseHandle for the read pipe failed\n");
794 /* Try bigger chunks */
795 size = 32768;
796 buffer = HeapAlloc( GetProcessHeap(), 0, size );
797 for (i = 0; i < size; i++) buffer[i] = i;
798 ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, (size + 24)) != 0, "CreatePipe failed\n");
799 ok(WriteFile(pipewrite, buffer, size, &written, NULL), "Write to anonymous pipe failed\n");
800 ok(written == size, "Write to anonymous pipe wrote %d bytes\n", written);
801 /* and close the write end, read should still succeed*/
802 ok(CloseHandle(pipewrite), "CloseHandle for the Write Pipe failed\n");
803 memset( buffer, 0, size );
804 ok(ReadFile(piperead, buffer, size, &read, NULL), "Read from broken pipe withe with pending data failed\n");
805 ok(read == size, "Read from anonymous pipe got %d bytes\n", read);
806 for (i = 0; i < size; i++) ok( buffer[i] == (BYTE)i, "invalid data %x at %x\n", buffer[i], i );
807 /* But now we need to get informed that the pipe is closed */
808 ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL) == 0, "Broken pipe not detected\n");
809 ok(CloseHandle(piperead), "CloseHandle for the read pipe failed\n");
810 HeapFree(GetProcessHeap(), 0, buffer);
813 struct named_pipe_client_params
815 DWORD security_flags;
816 HANDLE token;
817 BOOL revert;
820 #define PIPE_NAME "\\\\.\\pipe\\named_pipe_test"
822 static DWORD CALLBACK named_pipe_client_func(LPVOID p)
824 struct named_pipe_client_params *params = (struct named_pipe_client_params *)p;
825 HANDLE pipe;
826 BOOL ret;
827 const char message[] = "Test";
828 DWORD bytes_read, bytes_written;
829 char dummy;
830 TOKEN_PRIVILEGES *Privileges = NULL;
832 if (params->token)
834 if (params->revert)
836 /* modify the token so we can tell if the pipe impersonation
837 * token reverts to the process token */
838 ret = AdjustTokenPrivileges(params->token, TRUE, NULL, 0, NULL, NULL);
839 ok(ret, "AdjustTokenPrivileges failed with error %d\n", GetLastError());
841 ret = SetThreadToken(NULL, params->token);
842 ok(ret, "SetThreadToken failed with error %d\n", GetLastError());
844 else
846 DWORD Size = 0;
847 HANDLE process_token;
849 ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES, &process_token);
850 ok(ret, "OpenProcessToken failed with error %d\n", GetLastError());
852 ret = GetTokenInformation(process_token, TokenPrivileges, NULL, 0, &Size);
853 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetTokenInformation(TokenPrivileges) failed with %d\n", GetLastError());
854 Privileges = HeapAlloc(GetProcessHeap(), 0, Size);
855 ret = GetTokenInformation(process_token, TokenPrivileges, Privileges, Size, &Size);
856 ok(ret, "GetTokenInformation(TokenPrivileges) failed with %d\n", GetLastError());
858 ret = AdjustTokenPrivileges(process_token, TRUE, NULL, 0, NULL, NULL);
859 ok(ret, "AdjustTokenPrivileges failed with error %d\n", GetLastError());
861 CloseHandle(process_token);
864 pipe = CreateFile(PIPE_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, params->security_flags, NULL);
865 ok(pipe != INVALID_HANDLE_VALUE, "CreateFile for pipe failed with error %d\n", GetLastError());
867 ret = WriteFile(pipe, message, sizeof(message), &bytes_written, NULL);
868 ok(ret, "WriteFile failed with error %d\n", GetLastError());
870 ret = ReadFile(pipe, &dummy, sizeof(dummy), &bytes_read, NULL);
871 ok(ret, "ReadFile failed with error %d\n", GetLastError());
873 if (params->token)
875 if (params->revert)
877 ret = RevertToSelf();
878 ok(ret, "RevertToSelf failed with error %d\n", GetLastError());
880 else
882 ret = AdjustTokenPrivileges(params->token, TRUE, NULL, 0, NULL, NULL);
883 ok(ret, "AdjustTokenPrivileges failed with error %d\n", GetLastError());
886 else
888 HANDLE process_token;
890 ret = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &process_token);
891 ok(ret, "OpenProcessToken failed with error %d\n", GetLastError());
893 ret = AdjustTokenPrivileges(process_token, FALSE, Privileges, 0, NULL, NULL);
894 ok(ret, "AdjustTokenPrivileges failed with error %d\n", GetLastError());
896 HeapFree(GetProcessHeap(), 0, Privileges);
898 CloseHandle(process_token);
901 ret = WriteFile(pipe, message, sizeof(message), &bytes_written, NULL);
902 ok(ret, "WriteFile failed with error %d\n", GetLastError());
904 ret = ReadFile(pipe, &dummy, sizeof(dummy), &bytes_read, NULL);
905 ok(ret, "ReadFile failed with error %d\n", GetLastError());
907 CloseHandle(pipe);
909 return 0;
912 static HANDLE make_impersonation_token(DWORD Access, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
914 HANDLE ProcessToken;
915 HANDLE Token = NULL;
916 BOOL ret;
918 ret = OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE, &ProcessToken);
919 ok(ret, "OpenProcessToken failed with error %d\n", GetLastError());
921 ret = pDuplicateTokenEx(ProcessToken, Access, NULL, ImpersonationLevel, TokenImpersonation, &Token);
922 ok(ret, "DuplicateToken failed with error %d\n", GetLastError());
924 CloseHandle(ProcessToken);
926 return Token;
929 static void test_ImpersonateNamedPipeClient(HANDLE hClientToken, DWORD security_flags, BOOL revert, void (*test_func)(int, HANDLE))
931 HANDLE hPipeServer;
932 BOOL ret;
933 DWORD dwTid;
934 HANDLE hThread;
935 char buffer[256];
936 DWORD dwBytesRead;
937 DWORD error;
938 struct named_pipe_client_params params;
939 char dummy = 0;
940 DWORD dwBytesWritten;
941 HANDLE hToken = NULL;
942 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
943 DWORD size;
945 hPipeServer = CreateNamedPipe(PIPE_NAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 100, 100, NMPWAIT_USE_DEFAULT_WAIT, NULL);
946 ok(hPipeServer != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with error %d\n", GetLastError());
948 params.security_flags = security_flags;
949 params.token = hClientToken;
950 params.revert = revert;
951 hThread = CreateThread(NULL, 0, named_pipe_client_func, &params, 0, &dwTid);
952 ok(hThread != NULL, "CreateThread failed with error %d\n", GetLastError());
954 SetLastError(0xdeadbeef);
955 ret = ImpersonateNamedPipeClient(hPipeServer);
956 error = GetLastError();
957 ok(ret /* win2k3 */ || (error == ERROR_CANNOT_IMPERSONATE),
958 "ImpersonateNamedPipeClient should have failed with ERROR_CANNOT_IMPERSONATE instead of %d\n", GetLastError());
960 ret = ConnectNamedPipe(hPipeServer, NULL);
961 ok(ret || (GetLastError() == ERROR_PIPE_CONNECTED), "ConnectNamedPipe failed with error %d\n", GetLastError());
963 ret = ReadFile(hPipeServer, buffer, sizeof(buffer), &dwBytesRead, NULL);
964 ok(ret, "ReadFile failed with error %d\n", GetLastError());
966 ret = ImpersonateNamedPipeClient(hPipeServer);
967 ok(ret, "ImpersonateNamedPipeClient failed with error %d\n", GetLastError());
969 ret = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken);
970 ok(ret, "OpenThreadToken failed with error %d\n", GetLastError());
972 (*test_func)(0, hToken);
974 ImpersonationLevel = 0xdeadbeef; /* to avoid false positives */
975 ret = GetTokenInformation(hToken, TokenImpersonationLevel, &ImpersonationLevel, sizeof(ImpersonationLevel), &size);
976 ok(ret, "GetTokenInformation(TokenImpersonationLevel) failed with error %d\n", GetLastError());
977 ok(ImpersonationLevel == SecurityImpersonation, "ImpersonationLevel should have been SecurityImpersonation(%d) instead of %d\n", SecurityImpersonation, ImpersonationLevel);
979 CloseHandle(hToken);
981 RevertToSelf();
983 ret = WriteFile(hPipeServer, &dummy, sizeof(dummy), &dwBytesWritten, NULL);
984 ok(ret, "WriteFile failed with error %d\n", GetLastError());
986 ret = ReadFile(hPipeServer, buffer, sizeof(buffer), &dwBytesRead, NULL);
987 ok(ret, "ReadFile failed with error %d\n", GetLastError());
989 ret = ImpersonateNamedPipeClient(hPipeServer);
990 ok(ret, "ImpersonateNamedPipeClient failed with error %d\n", GetLastError());
992 ret = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken);
993 ok(ret, "OpenThreadToken failed with error %d\n", GetLastError());
995 (*test_func)(1, hToken);
997 CloseHandle(hToken);
999 RevertToSelf();
1001 ret = WriteFile(hPipeServer, &dummy, sizeof(dummy), &dwBytesWritten, NULL);
1002 ok(ret, "WriteFile failed with error %d\n", GetLastError());
1004 WaitForSingleObject(hThread, INFINITE);
1006 ret = ImpersonateNamedPipeClient(hPipeServer);
1007 ok(ret, "ImpersonateNamedPipeClient failed with error %d\n", GetLastError());
1009 RevertToSelf();
1011 CloseHandle(hThread);
1012 CloseHandle(hPipeServer);
1015 static BOOL are_all_privileges_disabled(HANDLE hToken)
1017 BOOL ret;
1018 TOKEN_PRIVILEGES *Privileges = NULL;
1019 DWORD Size = 0;
1020 BOOL all_privs_disabled = TRUE;
1021 DWORD i;
1023 ret = GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &Size);
1024 if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1026 Privileges = HeapAlloc(GetProcessHeap(), 0, Size);
1027 ret = GetTokenInformation(hToken, TokenPrivileges, Privileges, Size, &Size);
1028 if (!ret)
1030 HeapFree(GetProcessHeap(), 0, Privileges);
1031 return FALSE;
1034 else
1035 return FALSE;
1037 for (i = 0; i < Privileges->PrivilegeCount; i++)
1039 if (Privileges->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED)
1041 all_privs_disabled = FALSE;
1042 break;
1046 HeapFree(GetProcessHeap(), 0, Privileges);
1048 return all_privs_disabled;
1051 static DWORD get_privilege_count(HANDLE hToken)
1053 TOKEN_STATISTICS Statistics;
1054 DWORD Size = sizeof(Statistics);
1055 BOOL ret;
1057 ret = GetTokenInformation(hToken, TokenStatistics, &Statistics, Size, &Size);
1058 ok(ret, "GetTokenInformation(TokenStatistics)\n");
1059 if (!ret) return -1;
1061 return Statistics.PrivilegeCount;
1064 static void test_no_sqos_no_token(int call_index, HANDLE hToken)
1066 DWORD priv_count;
1068 switch (call_index)
1070 case 0:
1071 priv_count = get_privilege_count(hToken);
1072 todo_wine
1073 ok(priv_count == 0, "privilege count should have been 0 instead of %d\n", priv_count);
1074 break;
1075 case 1:
1076 priv_count = get_privilege_count(hToken);
1077 ok(priv_count > 0, "privilege count should now be > 0 instead of 0\n");
1078 ok(!are_all_privileges_disabled(hToken), "impersonated token should not have been modified\n");
1079 break;
1080 default:
1081 ok(0, "shouldn't happen\n");
1085 static void test_no_sqos(int call_index, HANDLE hToken)
1087 switch (call_index)
1089 case 0:
1090 ok(!are_all_privileges_disabled(hToken), "token should be a copy of the process one\n");
1091 break;
1092 case 1:
1093 todo_wine
1094 ok(are_all_privileges_disabled(hToken), "impersonated token should have been modified\n");
1095 break;
1096 default:
1097 ok(0, "shouldn't happen\n");
1101 static void test_static_context(int call_index, HANDLE hToken)
1103 switch (call_index)
1105 case 0:
1106 ok(!are_all_privileges_disabled(hToken), "token should be a copy of the process one\n");
1107 break;
1108 case 1:
1109 ok(!are_all_privileges_disabled(hToken), "impersonated token should not have been modified\n");
1110 break;
1111 default:
1112 ok(0, "shouldn't happen\n");
1116 static void test_dynamic_context(int call_index, HANDLE hToken)
1118 switch (call_index)
1120 case 0:
1121 ok(!are_all_privileges_disabled(hToken), "token should be a copy of the process one\n");
1122 break;
1123 case 1:
1124 todo_wine
1125 ok(are_all_privileges_disabled(hToken), "impersonated token should have been modified\n");
1126 break;
1127 default:
1128 ok(0, "shouldn't happen\n");
1132 static void test_dynamic_context_no_token(int call_index, HANDLE hToken)
1134 switch (call_index)
1136 case 0:
1137 ok(are_all_privileges_disabled(hToken), "token should be a copy of the process one\n");
1138 break;
1139 case 1:
1140 ok(!are_all_privileges_disabled(hToken), "process token modification should have been detected and impersonation token updated\n");
1141 break;
1142 default:
1143 ok(0, "shouldn't happen\n");
1147 static void test_no_sqos_revert(int call_index, HANDLE hToken)
1149 DWORD priv_count;
1150 switch (call_index)
1152 case 0:
1153 priv_count = get_privilege_count(hToken);
1154 todo_wine
1155 ok(priv_count == 0, "privilege count should have been 0 instead of %d\n", priv_count);
1156 break;
1157 case 1:
1158 priv_count = get_privilege_count(hToken);
1159 ok(priv_count > 0, "privilege count should now be > 0 instead of 0\n");
1160 ok(!are_all_privileges_disabled(hToken), "impersonated token should not have been modified\n");
1161 break;
1162 default:
1163 ok(0, "shouldn't happen\n");
1167 static void test_static_context_revert(int call_index, HANDLE hToken)
1169 switch (call_index)
1171 case 0:
1172 todo_wine
1173 ok(are_all_privileges_disabled(hToken), "privileges should have been disabled\n");
1174 break;
1175 case 1:
1176 todo_wine
1177 ok(are_all_privileges_disabled(hToken), "impersonated token should not have been modified\n");
1178 break;
1179 default:
1180 ok(0, "shouldn't happen\n");
1184 static void test_dynamic_context_revert(int call_index, HANDLE hToken)
1186 switch (call_index)
1188 case 0:
1189 todo_wine
1190 ok(are_all_privileges_disabled(hToken), "privileges should have been disabled\n");
1191 break;
1192 case 1:
1193 ok(!are_all_privileges_disabled(hToken), "impersonated token should now be process token\n");
1194 break;
1195 default:
1196 ok(0, "shouldn't happen\n");
1200 static void test_impersonation(void)
1202 HANDLE hClientToken;
1203 HANDLE hProcessToken;
1204 BOOL ret;
1206 if( !pDuplicateTokenEx ) {
1207 skip("DuplicateTokenEx not found\n");
1208 return;
1211 ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hProcessToken);
1212 if (!ret)
1214 skip("couldn't open process token, skipping impersonation tests\n");
1215 return;
1218 if (!get_privilege_count(hProcessToken) || are_all_privileges_disabled(hProcessToken))
1220 skip("token didn't have any privileges or they were all disabled. token not suitable for impersonation tests\n");
1221 CloseHandle(hProcessToken);
1222 return;
1224 CloseHandle(hProcessToken);
1226 test_ImpersonateNamedPipeClient(NULL, 0, FALSE, test_no_sqos_no_token);
1227 hClientToken = make_impersonation_token(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, SecurityImpersonation);
1228 test_ImpersonateNamedPipeClient(hClientToken, 0, FALSE, test_no_sqos);
1229 CloseHandle(hClientToken);
1230 hClientToken = make_impersonation_token(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, SecurityImpersonation);
1231 test_ImpersonateNamedPipeClient(hClientToken,
1232 SECURITY_SQOS_PRESENT | SECURITY_IMPERSONATION, FALSE,
1233 test_static_context);
1234 CloseHandle(hClientToken);
1235 hClientToken = make_impersonation_token(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, SecurityImpersonation);
1236 test_ImpersonateNamedPipeClient(hClientToken,
1237 SECURITY_SQOS_PRESENT | SECURITY_CONTEXT_TRACKING | SECURITY_IMPERSONATION,
1238 FALSE, test_dynamic_context);
1239 CloseHandle(hClientToken);
1240 test_ImpersonateNamedPipeClient(NULL,
1241 SECURITY_SQOS_PRESENT | SECURITY_CONTEXT_TRACKING | SECURITY_IMPERSONATION,
1242 FALSE, test_dynamic_context_no_token);
1244 hClientToken = make_impersonation_token(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, SecurityImpersonation);
1245 test_ImpersonateNamedPipeClient(hClientToken, 0, TRUE, test_no_sqos_revert);
1246 CloseHandle(hClientToken);
1247 hClientToken = make_impersonation_token(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, SecurityImpersonation);
1248 test_ImpersonateNamedPipeClient(hClientToken,
1249 SECURITY_SQOS_PRESENT | SECURITY_IMPERSONATION, TRUE,
1250 test_static_context_revert);
1251 CloseHandle(hClientToken);
1252 hClientToken = make_impersonation_token(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, SecurityImpersonation);
1253 test_ImpersonateNamedPipeClient(hClientToken,
1254 SECURITY_SQOS_PRESENT | SECURITY_CONTEXT_TRACKING | SECURITY_IMPERSONATION,
1255 TRUE, test_dynamic_context_revert);
1256 CloseHandle(hClientToken);
1259 struct overlapped_server_args
1261 HANDLE pipe_created;
1264 static DWORD CALLBACK overlapped_server(LPVOID arg)
1266 OVERLAPPED ol;
1267 HANDLE pipe;
1268 int ret, err;
1269 struct overlapped_server_args *a = (struct overlapped_server_args*)arg;
1270 DWORD num;
1271 char buf[100];
1273 pipe = CreateNamedPipeA("\\\\.\\pipe\\my pipe", FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, 0, 0, 100000, NULL);
1274 ok(pipe != NULL, "pipe NULL\n");
1276 ol.hEvent = CreateEventA(0, 1, 0, 0);
1277 ok(ol.hEvent != NULL, "event NULL\n");
1278 ret = ConnectNamedPipe(pipe, &ol);
1279 err = GetLastError();
1280 ok(ret == 0, "ret %d\n", ret);
1281 ok(err == ERROR_IO_PENDING, "gle %d\n", err);
1282 SetEvent(a->pipe_created);
1284 ret = WaitForSingleObjectEx(ol.hEvent, INFINITE, 1);
1285 ok(ret == WAIT_OBJECT_0, "ret %x\n", ret);
1287 ret = GetOverlappedResult(pipe, &ol, &num, 1);
1288 ok(ret == 1, "ret %d\n", ret);
1290 /* This should block */
1291 ret = ReadFile(pipe, buf, sizeof(buf), &num, NULL);
1292 ok(ret == 1, "ret %d\n", ret);
1294 DisconnectNamedPipe(pipe);
1295 CloseHandle(ol.hEvent);
1296 CloseHandle(pipe);
1297 return 1;
1300 static void test_overlapped(void)
1302 DWORD tid, num;
1303 HANDLE thread, pipe;
1304 int ret;
1305 struct overlapped_server_args args;
1307 args.pipe_created = CreateEventA(0, 1, 0, 0);
1308 thread = CreateThread(NULL, 0, overlapped_server, &args, 0, &tid);
1310 WaitForSingleObject(args.pipe_created, INFINITE);
1311 pipe = CreateFileA("\\\\.\\pipe\\my pipe", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
1312 ok(pipe != INVALID_HANDLE_VALUE, "cf failed\n");
1314 /* Sleep to try to get the ReadFile in the server to occur before the following WriteFile */
1315 Sleep(1);
1317 ret = WriteFile(pipe, "x", 1, &num, NULL);
1318 ok(ret == 1, "ret %d\n", ret);
1320 WaitForSingleObject(thread, INFINITE);
1321 CloseHandle(pipe);
1322 CloseHandle(args.pipe_created);
1323 CloseHandle(thread);
1326 static void test_NamedPipeHandleState(void)
1328 HANDLE server, client;
1329 BOOL ret;
1330 DWORD state, instances, maxCollectionCount, collectDataTimeout;
1331 char userName[MAX_PATH];
1333 server = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX,
1334 /* dwOpenMode */ PIPE_TYPE_BYTE | PIPE_WAIT,
1335 /* nMaxInstances */ 1,
1336 /* nOutBufSize */ 1024,
1337 /* nInBufSize */ 1024,
1338 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
1339 /* lpSecurityAttrib */ NULL);
1340 ok(server != INVALID_HANDLE_VALUE, "cf failed\n");
1341 ret = GetNamedPipeHandleState(server, NULL, NULL, NULL, NULL, NULL, 0);
1342 todo_wine
1343 ok(ret, "GetNamedPipeHandleState failed: %d\n", GetLastError());
1344 ret = GetNamedPipeHandleState(server, &state, &instances, NULL, NULL, NULL,
1346 todo_wine
1347 ok(ret, "GetNamedPipeHandleState failed: %d\n", GetLastError());
1348 if (ret)
1350 ok(state == 0, "unexpected state %08x\n", state);
1351 ok(instances == 1, "expected 1 instances, got %d\n", instances);
1353 /* Some parameters have no meaning, and therefore can't be retrieved,
1354 * on a local pipe.
1356 SetLastError(0xdeadbeef);
1357 ret = GetNamedPipeHandleState(server, &state, &instances,
1358 &maxCollectionCount, &collectDataTimeout, userName,
1359 sizeof(userName) / sizeof(userName[0]));
1360 todo_wine
1361 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1362 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1363 /* A byte-mode pipe server can't be changed to message mode. */
1364 state = PIPE_READMODE_MESSAGE;
1365 SetLastError(0xdeadbeef);
1366 ret = SetNamedPipeHandleState(server, &state, NULL, NULL);
1367 todo_wine
1368 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1369 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1371 client = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, NULL,
1372 OPEN_EXISTING, 0, NULL);
1373 ok(client != INVALID_HANDLE_VALUE, "cf failed\n");
1375 state = PIPE_READMODE_BYTE;
1376 ret = SetNamedPipeHandleState(client, &state, NULL, NULL);
1377 todo_wine
1378 ok(ret, "SetNamedPipeHandleState failed: %d\n", GetLastError());
1379 /* A byte-mode pipe client can't be changed to message mode, either. */
1380 state = PIPE_READMODE_MESSAGE;
1381 SetLastError(0xdeadbeef);
1382 ret = SetNamedPipeHandleState(server, &state, NULL, NULL);
1383 todo_wine
1384 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1385 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1387 CloseHandle(client);
1388 CloseHandle(server);
1390 server = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX,
1391 /* dwOpenMode */ PIPE_TYPE_MESSAGE | PIPE_WAIT,
1392 /* nMaxInstances */ 1,
1393 /* nOutBufSize */ 1024,
1394 /* nInBufSize */ 1024,
1395 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
1396 /* lpSecurityAttrib */ NULL);
1397 ok(server != INVALID_HANDLE_VALUE, "cf failed\n");
1398 ret = GetNamedPipeHandleState(server, NULL, NULL, NULL, NULL, NULL, 0);
1399 todo_wine
1400 ok(ret, "GetNamedPipeHandleState failed: %d\n", GetLastError());
1401 ret = GetNamedPipeHandleState(server, &state, &instances, NULL, NULL, NULL,
1403 todo_wine
1404 ok(ret, "GetNamedPipeHandleState failed: %d\n", GetLastError());
1405 if (ret)
1407 ok(state == 0, "unexpected state %08x\n", state);
1408 ok(instances == 1, "expected 1 instances, got %d\n", instances);
1410 /* In contrast to byte-mode pipes, a message-mode pipe server can be
1411 * changed to byte mode.
1413 state = PIPE_READMODE_BYTE;
1414 ret = SetNamedPipeHandleState(server, &state, NULL, NULL);
1415 todo_wine
1416 ok(ret, "SetNamedPipeHandleState failed: %d\n", GetLastError());
1418 client = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, NULL,
1419 OPEN_EXISTING, 0, NULL);
1420 ok(client != INVALID_HANDLE_VALUE, "cf failed\n");
1422 state = PIPE_READMODE_MESSAGE;
1423 ret = SetNamedPipeHandleState(client, &state, NULL, NULL);
1424 todo_wine
1425 ok(ret, "SetNamedPipeHandleState failed: %d\n", GetLastError());
1426 /* A message-mode pipe client can also be changed to byte mode.
1428 state = PIPE_READMODE_BYTE;
1429 ret = SetNamedPipeHandleState(client, &state, NULL, NULL);
1430 todo_wine
1431 ok(ret, "SetNamedPipeHandleState failed: %d\n", GetLastError());
1433 CloseHandle(client);
1434 CloseHandle(server);
1437 START_TEST(pipe)
1439 HMODULE hmod;
1441 hmod = GetModuleHandle("advapi32.dll");
1442 pDuplicateTokenEx = (void *) GetProcAddress(hmod, "DuplicateTokenEx");
1444 if (test_DisconnectNamedPipe())
1445 return;
1446 test_CreateNamedPipe_instances_must_match();
1447 test_NamedPipe_2();
1448 test_CreateNamedPipe(PIPE_TYPE_BYTE);
1449 test_CreateNamedPipe(PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE);
1450 test_CreatePipe();
1451 test_impersonation();
1452 test_overlapped();
1453 test_NamedPipeHandleState();