1 /* Unit test suite for Ntdll NamedPipe API functions
2  *
3  * Copyright 2011 Bernhard Loos
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 #include <stdio.h>
21 #include <stdarg.h>
22 
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "wine/test.h"
31 #include "winternl.h"
32 #include "winioctl.h"
33 
34 #ifndef __WINE_WINTERNL_H
35 
36 typedef struct {
37   ULONG ReadMode;
38   ULONG CompletionMode;
39 } FILE_PIPE_INFORMATION;
40 
41 typedef struct {
42   ULONG NamedPipeType;
43   ULONG NamedPipeConfiguration;
44   ULONG MaximumInstances;
45   ULONG CurrentInstances;
46   ULONG InboundQuota;
47   ULONG ReadDataAvailable;
48   ULONG OutboundQuota;
49   ULONG WriteQuotaAvailable;
50   ULONG NamedPipeState;
51   ULONG NamedPipeEnd;
52 } FILE_PIPE_LOCAL_INFORMATION;
53 
54 #ifndef FILE_SYNCHRONOUS_IO_ALERT
55 #define FILE_SYNCHRONOUS_IO_ALERT 0x10
56 #endif
57 
58 #ifndef FILE_SYNCHRONOUS_IO_NONALERT
59 #define FILE_SYNCHRONOUS_IO_NONALERT 0x20
60 #endif
61 
62 #ifndef FSCTL_PIPE_LISTEN
63 #define FSCTL_PIPE_LISTEN CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS)
64 #endif
65 #endif
66 
67 static NTSTATUS (WINAPI *pNtFsControlFile) (HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, PVOID apc_context, PIO_STATUS_BLOCK io, ULONG code, PVOID in_buffer, ULONG in_size, PVOID out_buffer, ULONG out_size);
68 static NTSTATUS (WINAPI *pNtCreateNamedPipeFile) (PHANDLE handle, ULONG access,
69                                         POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK iosb,
70                                         ULONG sharing, ULONG dispo, ULONG options,
71                                         ULONG pipe_type, ULONG read_mode,
72                                         ULONG completion_mode, ULONG max_inst,
73                                         ULONG inbound_quota, ULONG outbound_quota,
74                                         PLARGE_INTEGER timeout);
75 static NTSTATUS (WINAPI *pNtQueryInformationFile) (IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass);
76 static NTSTATUS (WINAPI *pNtQueryVolumeInformationFile)(HANDLE handle, PIO_STATUS_BLOCK io, void *buffer, ULONG length, FS_INFORMATION_CLASS info_class);
77 static NTSTATUS (WINAPI *pNtSetInformationFile) (HANDLE handle, PIO_STATUS_BLOCK io, PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class);
78 static NTSTATUS (WINAPI *pNtCancelIoFile) (HANDLE hFile, PIO_STATUS_BLOCK io_status);
79 static NTSTATUS (WINAPI *pNtCancelIoFileEx) (HANDLE hFile, IO_STATUS_BLOCK *iosb, IO_STATUS_BLOCK *io_status);
80 static void (WINAPI *pRtlInitUnicodeString) (PUNICODE_STRING target, PCWSTR source);
81 
82 static HANDLE (WINAPI *pOpenThread)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId);
83 static DWORD (WINAPI *pQueueUserAPC)(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData);
84 
85 
init_func_ptrs(void)86 static BOOL init_func_ptrs(void)
87 {
88     HMODULE module = GetModuleHandleA("ntdll.dll");
89 
90 #define loadfunc(name)  if (!(p##name = (void *)GetProcAddress(module, #name))) { \
91                             trace("GetProcAddress(%s) failed\n", #name); \
92                             return FALSE; \
93                         }
94 
95     loadfunc(NtFsControlFile)
96     loadfunc(NtCreateNamedPipeFile)
97     loadfunc(NtQueryInformationFile)
98     loadfunc(NtQueryVolumeInformationFile)
99     loadfunc(NtSetInformationFile)
100     loadfunc(NtCancelIoFile)
101     loadfunc(RtlInitUnicodeString)
102 
103     /* not fatal */
104     pNtCancelIoFileEx = (void *)GetProcAddress(module, "NtCancelIoFileEx");
105     module = GetModuleHandleA("kernel32.dll");
106     pOpenThread = (void *)GetProcAddress(module, "OpenThread");
107     pQueueUserAPC = (void *)GetProcAddress(module, "QueueUserAPC");
108     return TRUE;
109 }
110 
is_signaled(HANDLE obj)111 static inline BOOL is_signaled( HANDLE obj )
112 {
113     return WaitForSingleObject( obj, 0 ) == WAIT_OBJECT_0;
114 }
115 
116 static const WCHAR testpipe[] = { '\\', '\\', '.', '\\', 'p', 'i', 'p', 'e', '\\',
117                                   't', 'e', 's', 't', 'p', 'i', 'p', 'e', 0 };
118 static const WCHAR testpipe_nt[] = { '\\', '?', '?', '\\', 'p', 'i', 'p', 'e', '\\',
119                                      't', 'e', 's', 't', 'p', 'i', 'p', 'e', 0 };
120 
create_pipe(PHANDLE handle,ULONG sharing,ULONG options)121 static NTSTATUS create_pipe(PHANDLE handle, ULONG sharing, ULONG options)
122 {
123     IO_STATUS_BLOCK iosb;
124     OBJECT_ATTRIBUTES attr;
125     UNICODE_STRING name;
126     LARGE_INTEGER timeout;
127     NTSTATUS res;
128 
129     pRtlInitUnicodeString(&name, testpipe_nt);
130 
131     attr.Length                   = sizeof(attr);
132     attr.RootDirectory            = 0;
133     attr.ObjectName               = &name;
134     attr.Attributes               = 0x40; /*case insensitive */
135     attr.SecurityDescriptor       = NULL;
136     attr.SecurityQualityOfService = NULL;
137 
138     timeout.QuadPart = -100000000;
139 
140     res = pNtCreateNamedPipeFile(handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, sharing,  2 /*FILE_CREATE*/,
141                                  options, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
142     return res;
143 }
144 
145 static BOOL ioapc_called;
ioapc(void * arg,PIO_STATUS_BLOCK io,ULONG reserved)146 static void CALLBACK ioapc(void *arg, PIO_STATUS_BLOCK io, ULONG reserved)
147 {
148     ioapc_called = TRUE;
149 }
150 
listen_pipe(HANDLE hPipe,HANDLE hEvent,PIO_STATUS_BLOCK iosb,BOOL use_apc)151 static NTSTATUS listen_pipe(HANDLE hPipe, HANDLE hEvent, PIO_STATUS_BLOCK iosb, BOOL use_apc)
152 {
153     int dummy;
154 
155     ioapc_called = FALSE;
156 
157     return pNtFsControlFile(hPipe, hEvent, use_apc ? &ioapc: NULL, use_apc ? &dummy: NULL, iosb, FSCTL_PIPE_LISTEN, 0, 0, 0, 0);
158 }
159 
test_create_invalid(void)160 static void test_create_invalid(void)
161 {
162     IO_STATUS_BLOCK iosb;
163     OBJECT_ATTRIBUTES attr;
164     UNICODE_STRING name;
165     LARGE_INTEGER timeout;
166     NTSTATUS res;
167     HANDLE handle, handle2;
168     FILE_PIPE_LOCAL_INFORMATION info;
169 
170     pRtlInitUnicodeString(&name, testpipe_nt);
171 
172     attr.Length                   = sizeof(attr);
173     attr.RootDirectory            = 0;
174     attr.ObjectName               = &name;
175     attr.Attributes               = 0x40; /*case insensitive */
176     attr.SecurityDescriptor       = NULL;
177     attr.SecurityQualityOfService = NULL;
178 
179     timeout.QuadPart = -100000000;
180 
181 /* create a pipe with FILE_OVERWRITE */
182     res = pNtCreateNamedPipeFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ, 4 /*FILE_OVERWRITE*/,
183                                  0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
184     todo_wine ok(res == STATUS_INVALID_PARAMETER, "NtCreateNamedPipeFile returned %x\n", res);
185     if (!res)
186         CloseHandle(handle);
187 
188 /* create a pipe with FILE_OVERWRITE_IF */
189     res = pNtCreateNamedPipeFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ, 5 /*FILE_OVERWRITE_IF*/,
190                                  0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
191     todo_wine ok(res == STATUS_INVALID_PARAMETER, "NtCreateNamedPipeFile returned %x\n", res);
192     if (!res)
193         CloseHandle(handle);
194 
195 /* create a pipe with sharing = 0 */
196     res = pNtCreateNamedPipeFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, 0, 2 /*FILE_CREATE*/,
197                                  0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
198     ok(res == STATUS_INVALID_PARAMETER, "NtCreateNamedPipeFile returned %x\n", res);
199     if (!res)
200         CloseHandle(handle);
201 
202 /* create a pipe without r/w access */
203     res = pNtCreateNamedPipeFile(&handle, SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /*FILE_CREATE*/,
204                                  0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
205     ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
206 
207     res = pNtQueryInformationFile(handle, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24);
208     ok(res == STATUS_ACCESS_DENIED, "NtQueryInformationFile returned %x\n", res);
209 
210 /* test FILE_CREATE creation disposition */
211     res = pNtCreateNamedPipeFile(&handle2, SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /*FILE_CREATE*/,
212                                  0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
213     todo_wine ok(res == STATUS_ACCESS_DENIED, "NtCreateNamedPipeFile returned %x\n", res);
214     if (!res)
215         CloseHandle(handle2);
216 
217     CloseHandle(handle);
218 }
219 
test_create(void)220 static void test_create(void)
221 {
222     HANDLE hserver;
223     NTSTATUS res;
224     int j, k;
225     FILE_PIPE_LOCAL_INFORMATION info;
226     IO_STATUS_BLOCK iosb;
227     HANDLE hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
228 
229     static const DWORD access[] = { 0, GENERIC_READ, GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE};
230     static const DWORD sharing[] =    { FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE };
231     static const DWORD pipe_config[]= {               1,                0,                                  2 };
232 
233     for (j = 0; j < sizeof(sharing) / sizeof(DWORD); j++) {
234         for (k = 0; k < sizeof(access) / sizeof(DWORD); k++) {
235             HANDLE hclient;
236             BOOL should_succeed = TRUE;
237 
238             res  = create_pipe(&hserver, sharing[j], 0);
239             if (res) {
240                 ok(0, "NtCreateNamedPipeFile returned %x, sharing: %x\n", res, sharing[j]);
241                 continue;
242             }
243 
244             res = listen_pipe(hserver, hEvent, &iosb, FALSE);
245             ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
246 
247             res = pNtQueryInformationFile(hserver, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24);
248             ok(!res, "NtQueryInformationFile for server returned %x, sharing: %x\n", res, sharing[j]);
249             ok(info.NamedPipeConfiguration == pipe_config[j], "wrong duplex status for pipe: %d, expected %d\n",
250                info.NamedPipeConfiguration, pipe_config[j]);
251 
252             hclient = CreateFileW(testpipe, access[k], 0, 0, OPEN_EXISTING, 0, 0);
253             if (hclient != INVALID_HANDLE_VALUE) {
254                 res = pNtQueryInformationFile(hclient, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24);
255                 ok(!res, "NtQueryInformationFile for client returned %x, access: %x, sharing: %x\n",
256                    res, access[k], sharing[j]);
257                 ok(info.NamedPipeConfiguration == pipe_config[j], "wrong duplex status for pipe: %d, expected %d\n",
258                    info.NamedPipeConfiguration, pipe_config[j]);
259 
260                 res = listen_pipe(hclient, hEvent, &iosb, FALSE);
261                 ok(res == STATUS_ILLEGAL_FUNCTION, "expected STATUS_ILLEGAL_FUNCTION, got %x\n", res);
262                 CloseHandle(hclient);
263             }
264 
265             if (access[k] & GENERIC_WRITE)
266                 should_succeed &= !!(sharing[j] & FILE_SHARE_WRITE);
267             if (access[k] & GENERIC_READ)
268                 should_succeed &= !!(sharing[j] & FILE_SHARE_READ);
269 
270             if (should_succeed)
271                 ok(hclient != INVALID_HANDLE_VALUE, "CreateFile failed for sharing %x, access: %x, GetLastError: %d\n",
272                    sharing[j], access[k], GetLastError());
273             else
274                 ok(hclient == INVALID_HANDLE_VALUE, "CreateFile succeeded for sharing %x, access: %x\n", sharing[j], access[k]);
275 
276             CloseHandle(hserver);
277         }
278     }
279     CloseHandle(hEvent);
280 }
281 
test_overlapped(void)282 static void test_overlapped(void)
283 {
284     IO_STATUS_BLOCK iosb;
285     HANDLE hEvent;
286     HANDLE hPipe;
287     HANDLE hClient;
288     NTSTATUS res;
289 
290     hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
291     ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
292 
293     res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
294     ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
295 
296     memset(&iosb, 0x55, sizeof(iosb));
297     res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
298     ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
299     ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
300 
301     hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
302     ok(hClient != INVALID_HANDLE_VALUE, "can't open pipe, GetLastError: %x\n", GetLastError());
303 
304     ok(U(iosb).Status == 0, "Wrong iostatus %x\n", U(iosb).Status);
305     ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
306 
307     ok(!ioapc_called, "IOAPC ran too early\n");
308 
309     SleepEx(0, TRUE); /* alertable wait state */
310 
311     ok(ioapc_called, "IOAPC didn't run\n");
312 
313     CloseHandle(hPipe);
314     CloseHandle(hClient);
315 
316     res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
317     ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
318 
319     hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
320     ok(hClient != INVALID_HANDLE_VALUE || broken(GetLastError() == ERROR_PIPE_BUSY) /* > Win 8 */,
321        "can't open pipe, GetLastError: %x\n", GetLastError());
322 
323     if (hClient != INVALID_HANDLE_VALUE)
324     {
325         SetEvent(hEvent);
326         memset(&iosb, 0x55, sizeof(iosb));
327         res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
328         ok(res == STATUS_PIPE_CONNECTED, "NtFsControlFile returned %x\n", res);
329         ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
330         ok(!is_signaled(hEvent), "hEvent not signaled\n");
331 
332         CloseHandle(hClient);
333     }
334 
335     CloseHandle(hPipe);
336     CloseHandle(hEvent);
337 }
338 
test_completion(void)339 static void test_completion(void)
340 {
341     static const char buf[] = "testdata";
342     FILE_IO_COMPLETION_NOTIFICATION_INFORMATION info;
343     HANDLE port, pipe, client;
344     IO_STATUS_BLOCK iosb;
345     OVERLAPPED ov, *pov;
346     IO_STATUS_BLOCK io;
347     NTSTATUS status;
348     DWORD num_bytes;
349     ULONG_PTR key;
350     DWORD dwret;
351     BOOL ret;
352 
353     memset(&ov, 0, sizeof(ov));
354     ov.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
355     ok(ov.hEvent != INVALID_HANDLE_VALUE, "CreateEvent failed, error %u\n", GetLastError());
356 
357     status = create_pipe(&pipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
358     ok(!status, "NtCreateNamedPipeFile returned %x\n", status);
359     status = listen_pipe(pipe, ov.hEvent, &iosb, FALSE);
360     ok(status == STATUS_PENDING, "NtFsControlFile returned %x\n", status);
361 
362     client = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0,
363                          OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
364     ok(client != INVALID_HANDLE_VALUE, "CreateFile failed, error %u\n", GetLastError());
365     dwret = WaitForSingleObject(ov.hEvent, 0);
366     ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", dwret);
367 
368     port = CreateIoCompletionPort(client, NULL, 0xdeadbeef, 0);
369     ok(port != NULL, "CreateIoCompletionPort failed, error %u\n", GetLastError());
370 
371     ret = WriteFile(client, buf, sizeof(buf), &num_bytes, &ov);
372     ok(ret, "WriteFile failed, error %u\n", GetLastError());
373     ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n", num_bytes);
374 
375     key = 0;
376     pov = NULL;
377     ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000);
378     ok(ret, "GetQueuedCompletionStatus failed, error %u\n", GetLastError());
379     ok(key == 0xdeadbeef, "expected 0xdeadbeef, got %lx\n", key);
380     ok(pov == &ov, "expected %p, got %p\n", &ov, pov);
381 
382     info.Flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS;
383     status = pNtSetInformationFile(client, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
384     ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
385 
386     info.Flags = 0;
387     status = pNtQueryInformationFile(client, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
388     ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
389     ok((info.Flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS) != 0, "got %08x\n", info.Flags);
390 
391     ret = WriteFile(client, buf, sizeof(buf), &num_bytes, &ov);
392     ok(ret, "WriteFile failed, error %u\n", GetLastError());
393     ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n", num_bytes);
394 
395     pov = (void *)0xdeadbeef;
396     ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000);
397     ok(!ret, "GetQueuedCompletionStatus succeeded\n");
398     ok(pov == NULL, "expected NULL, got %p\n", pov);
399 
400     CloseHandle(ov.hEvent);
401     CloseHandle(client);
402     CloseHandle(pipe);
403     CloseHandle(port);
404 }
405 
406 static BOOL userapc_called;
userapc(ULONG_PTR dwParam)407 static void CALLBACK userapc(ULONG_PTR dwParam)
408 {
409     userapc_called = TRUE;
410 }
411 
412 static BOOL open_succeeded;
thread(PVOID main_thread)413 static DWORD WINAPI thread(PVOID main_thread)
414 {
415     HANDLE h;
416 
417     Sleep(400);
418 
419     if (main_thread) {
420         DWORD ret;
421         userapc_called = FALSE;
422         ret = pQueueUserAPC(&userapc, main_thread, 0);
423         ok(ret, "can't queue user apc, GetLastError: %x\n", GetLastError());
424         CloseHandle(main_thread);
425     }
426 
427     Sleep(400);
428 
429     h = CreateFileW(testpipe, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
430 
431     if (h != INVALID_HANDLE_VALUE) {
432         open_succeeded = TRUE;
433         Sleep(100);
434         CloseHandle(h);
435     } else
436         open_succeeded = FALSE;
437 
438     return 0;
439 }
440 
test_alertable(void)441 static void test_alertable(void)
442 {
443     IO_STATUS_BLOCK iosb;
444     HANDLE hEvent;
445     HANDLE hPipe;
446     NTSTATUS res;
447     HANDLE hThread;
448     DWORD ret;
449 
450     memset(&iosb, 0x55, sizeof(iosb));
451 
452     hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
453     ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
454 
455     res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_ALERT);
456     ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
457 
458 /* queue an user apc before calling listen */
459     userapc_called = FALSE;
460     ret = pQueueUserAPC(&userapc, GetCurrentThread(), 0);
461     ok(ret, "can't queue user apc, GetLastError: %x\n", GetLastError());
462 
463     res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
464     todo_wine ok(res == STATUS_CANCELLED, "NtFsControlFile returned %x\n", res);
465 
466     todo_wine ok(userapc_called, "user apc didn't run\n");
467     ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
468     todo_wine ok(WaitForSingleObjectEx(hEvent, 0, TRUE) == WAIT_TIMEOUT, "hEvent signaled\n");
469     ok(!ioapc_called, "IOAPC ran\n");
470 
471 /* queue an user apc from a different thread */
472     hThread = CreateThread(NULL, 0, &thread, pOpenThread(MAXIMUM_ALLOWED, FALSE, GetCurrentThreadId()), 0, 0);
473     ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError());
474 
475     /* wine_todo: the earlier NtFsControlFile call gets cancelled after the pipe gets set into listen state
476                   instead of before, so this NtFsControlFile will fail STATUS_INVALID_HANDLE */
477     res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
478     todo_wine ok(res == STATUS_CANCELLED, "NtFsControlFile returned %x\n", res);
479 
480     ok(userapc_called, "user apc didn't run\n");
481     ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
482     ok(WaitForSingleObjectEx(hEvent, 0, TRUE) == WAIT_TIMEOUT, "hEvent signaled\n");
483     ok(!ioapc_called, "IOAPC ran\n");
484 
485     WaitForSingleObject(hThread, INFINITE);
486 
487     SleepEx(0, TRUE); /* get rid of the userapc, if NtFsControlFile failed */
488 
489     ok(open_succeeded, "couldn't open client side pipe\n");
490 
491     CloseHandle(hThread);
492     DisconnectNamedPipe(hPipe);
493 
494 /* finally try without an apc */
495     hThread = CreateThread(NULL, 0, &thread, 0, 0, 0);
496     ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError());
497 
498     res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
499     todo_wine ok(!res, "NtFsControlFile returned %x\n", res);
500 
501     ok(open_succeeded, "couldn't open client side pipe\n");
502     ok(!U(iosb).Status, "Wrong iostatus %x\n", U(iosb).Status);
503     todo_wine ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
504 
505     WaitForSingleObject(hThread, INFINITE);
506     CloseHandle(hThread);
507     CloseHandle(hEvent);
508     CloseHandle(hPipe);
509 }
510 
test_nonalertable(void)511 static void test_nonalertable(void)
512 {
513     IO_STATUS_BLOCK iosb;
514     HANDLE hEvent;
515     HANDLE hPipe;
516     NTSTATUS res;
517     HANDLE hThread;
518     DWORD ret;
519 
520     memset(&iosb, 0x55, sizeof(iosb));
521 
522     hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
523     ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
524 
525     res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
526     ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
527 
528     hThread = CreateThread(NULL, 0, &thread, 0, 0, 0);
529     ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError());
530 
531     userapc_called = FALSE;
532     ret = pQueueUserAPC(&userapc, GetCurrentThread(), 0);
533     ok(ret, "can't queue user apc, GetLastError: %x\n", GetLastError());
534 
535     res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
536     todo_wine ok(!res, "NtFsControlFile returned %x\n", res);
537 
538     ok(open_succeeded, "couldn't open client side pipe\n");
539     todo_wine ok(!U(iosb).Status, "Wrong iostatus %x\n", U(iosb).Status);
540     todo_wine ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
541 
542     ok(!ioapc_called, "IOAPC ran too early\n");
543     ok(!userapc_called, "user apc ran too early\n");
544 
545     SleepEx(0, TRUE); /* alertable wait state */
546 
547     ok(ioapc_called, "IOAPC didn't run\n");
548     ok(userapc_called, "user apc didn't run\n");
549 
550     WaitForSingleObject(hThread, INFINITE);
551     CloseHandle(hThread);
552     CloseHandle(hEvent);
553     CloseHandle(hPipe);
554 }
555 
test_cancelio(void)556 static void test_cancelio(void)
557 {
558     IO_STATUS_BLOCK iosb;
559     IO_STATUS_BLOCK cancel_sb;
560     HANDLE hEvent;
561     HANDLE hPipe;
562     NTSTATUS res;
563 
564     hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
565     ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
566 
567     res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
568     ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
569 
570     memset(&iosb, 0x55, sizeof(iosb));
571 
572     res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
573     ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
574 
575     res = pNtCancelIoFile(hPipe, &cancel_sb);
576     ok(!res, "NtCancelIoFile returned %x\n", res);
577 
578     ok(U(iosb).Status == STATUS_CANCELLED, "Wrong iostatus %x\n", U(iosb).Status);
579     ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
580 
581     ok(!ioapc_called, "IOAPC ran too early\n");
582 
583     SleepEx(0, TRUE); /* alertable wait state */
584 
585     ok(ioapc_called, "IOAPC didn't run\n");
586 
587     CloseHandle(hPipe);
588 
589     if (pNtCancelIoFileEx)
590     {
591         res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
592         ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
593 
594         memset(&iosb, 0x55, sizeof(iosb));
595         res = listen_pipe(hPipe, hEvent, &iosb, FALSE);
596         ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
597 
598         res = pNtCancelIoFileEx(hPipe, &iosb, &cancel_sb);
599         ok(!res, "NtCancelIoFileEx returned %x\n", res);
600 
601         ok(U(iosb).Status == STATUS_CANCELLED, "Wrong iostatus %x\n", U(iosb).Status);
602         ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
603 
604         CloseHandle(hPipe);
605     }
606     else
607         win_skip("NtCancelIoFileEx not available\n");
608 
609     CloseHandle(hEvent);
610 }
611 
_check_pipe_handle_state(int line,HANDLE handle,ULONG read,ULONG completion)612 static void _check_pipe_handle_state(int line, HANDLE handle, ULONG read, ULONG completion)
613 {
614     IO_STATUS_BLOCK iosb;
615     FILE_PIPE_INFORMATION fpi;
616     NTSTATUS res;
617     if (handle != INVALID_HANDLE_VALUE)
618     {
619         memset(&fpi, 0x55, sizeof(fpi));
620         res = pNtQueryInformationFile(handle, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
621         ok_(__FILE__, line)(!res, "NtQueryInformationFile returned %x\n", res);
622         ok_(__FILE__, line)(fpi.ReadMode == read, "Unexpected ReadMode, expected %x, got %x\n",
623                             read, fpi.ReadMode);
624         ok_(__FILE__, line)(fpi.CompletionMode == completion, "Unexpected CompletionMode, expected %x, got %x\n",
625                             completion, fpi.CompletionMode);
626     }
627 }
628 #define check_pipe_handle_state(handle, r, c) _check_pipe_handle_state(__LINE__, handle, r, c)
629 
test_filepipeinfo(void)630 static void test_filepipeinfo(void)
631 {
632     IO_STATUS_BLOCK iosb;
633     OBJECT_ATTRIBUTES attr;
634     UNICODE_STRING name;
635     LARGE_INTEGER timeout;
636     HANDLE hServer, hClient;
637     FILE_PIPE_INFORMATION fpi;
638     NTSTATUS res;
639 
640     pRtlInitUnicodeString(&name, testpipe_nt);
641 
642     attr.Length                   = sizeof(attr);
643     attr.RootDirectory            = 0;
644     attr.ObjectName               = &name;
645     attr.Attributes               = 0x40; /* case insensitive */
646     attr.SecurityDescriptor       = NULL;
647     attr.SecurityQualityOfService = NULL;
648 
649     timeout.QuadPart = -100000000;
650 
651     /* test with INVALID_HANDLE_VALUE */
652     res = pNtQueryInformationFile(INVALID_HANDLE_VALUE, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
653     ok(res == STATUS_OBJECT_TYPE_MISMATCH, "NtQueryInformationFile returned %x\n", res);
654 
655     fpi.ReadMode = 0;
656     fpi.CompletionMode = 0;
657     res = pNtSetInformationFile(INVALID_HANDLE_VALUE, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
658     ok(res == STATUS_OBJECT_TYPE_MISMATCH, "NtSetInformationFile returned %x\n", res);
659 
660     /* server end with read-only attributes */
661     res = pNtCreateNamedPipeFile(&hServer, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb,
662                                  FILE_SHARE_READ | FILE_SHARE_WRITE,  2 /* FILE_CREATE */,
663                                  0, 0, 0, 1, 0xFFFFFFFF, 500, 500, &timeout);
664     ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
665 
666     check_pipe_handle_state(hServer, 0, 1);
667 
668     hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
669     ok(hClient != INVALID_HANDLE_VALUE || broken(GetLastError() == ERROR_PIPE_BUSY) /* > Win 8 */,
670        "can't open pipe, GetLastError: %x\n", GetLastError());
671 
672     check_pipe_handle_state(hServer, 0, 1);
673     check_pipe_handle_state(hClient, 0, 0);
674 
675     fpi.ReadMode = 0;
676     fpi.CompletionMode = 0;
677     res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
678     ok(res == STATUS_ACCESS_DENIED, "NtSetInformationFile returned %x\n", res);
679 
680     check_pipe_handle_state(hServer, 0, 1);
681     check_pipe_handle_state(hClient, 0, 0);
682 
683     fpi.ReadMode = 1; /* invalid on a byte stream pipe */
684     fpi.CompletionMode = 1;
685     res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
686     ok(res == STATUS_ACCESS_DENIED, "NtSetInformationFile returned %x\n", res);
687 
688     check_pipe_handle_state(hServer, 0, 1);
689     check_pipe_handle_state(hClient, 0, 0);
690 
691     if (hClient != INVALID_HANDLE_VALUE)
692     {
693         fpi.ReadMode = 1; /* invalid on a byte stream pipe */
694         fpi.CompletionMode = 1;
695         res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
696         ok(res == STATUS_INVALID_PARAMETER, "NtSetInformationFile returned %x\n", res);
697     }
698 
699     check_pipe_handle_state(hServer, 0, 1);
700     check_pipe_handle_state(hClient, 0, 0);
701 
702     if (hClient != INVALID_HANDLE_VALUE)
703     {
704         fpi.ReadMode = 0;
705         fpi.CompletionMode = 1;
706         res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
707         ok(!res, "NtSetInformationFile returned %x\n", res);
708     }
709 
710     check_pipe_handle_state(hServer, 0, 1);
711     check_pipe_handle_state(hClient, 0, 1);
712 
713     if (hClient != INVALID_HANDLE_VALUE)
714     {
715         fpi.ReadMode = 0;
716         fpi.CompletionMode = 2; /* not in range 0-1 */
717         res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
718         ok(res == STATUS_INVALID_PARAMETER || broken(!res) /* < Vista */, "NtSetInformationFile returned %x\n", res);
719 
720         fpi.ReadMode = 2; /* not in range 0-1 */
721         fpi.CompletionMode = 0;
722         res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
723         ok(res == STATUS_INVALID_PARAMETER || broken(!res) /* < Vista */, "NtSetInformationFile returned %x\n", res);
724     }
725 
726     CloseHandle(hClient);
727 
728     check_pipe_handle_state(hServer, 0, 1);
729 
730     fpi.ReadMode = 0;
731     fpi.CompletionMode = 0;
732     res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
733     ok(res == STATUS_ACCESS_DENIED, "NtSetInformationFile returned %x\n", res);
734 
735     CloseHandle(hServer);
736 
737     /* message mode server with read/write attributes */
738     res = pNtCreateNamedPipeFile(&hServer, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb,
739                                  FILE_SHARE_READ | FILE_SHARE_WRITE,  2 /* FILE_CREATE */,
740                                  0, 1, 1, 0, 0xFFFFFFFF, 500, 500, &timeout);
741     ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
742 
743     check_pipe_handle_state(hServer, 1, 0);
744 
745     hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
746     ok(hClient != INVALID_HANDLE_VALUE || broken(GetLastError() == ERROR_PIPE_BUSY) /* > Win 8 */,
747        "can't open pipe, GetLastError: %x\n", GetLastError());
748 
749     check_pipe_handle_state(hServer, 1, 0);
750     check_pipe_handle_state(hClient, 0, 0);
751 
752     if (hClient != INVALID_HANDLE_VALUE)
753     {
754         fpi.ReadMode = 1;
755         fpi.CompletionMode = 1;
756         res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
757         ok(!res, "NtSetInformationFile returned %x\n", res);
758     }
759 
760     check_pipe_handle_state(hServer, 1, 0);
761     check_pipe_handle_state(hClient, 1, 1);
762 
763     fpi.ReadMode = 0;
764     fpi.CompletionMode = 1;
765     res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
766     ok(!res, "NtSetInformationFile returned %x\n", res);
767 
768     check_pipe_handle_state(hServer, 0, 1);
769     check_pipe_handle_state(hClient, 1, 1);
770 
771     if (hClient != INVALID_HANDLE_VALUE)
772     {
773         fpi.ReadMode = 0;
774         fpi.CompletionMode = 2; /* not in range 0-1 */
775         res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
776         ok(res == STATUS_INVALID_PARAMETER || broken(!res) /* < Vista */, "NtSetInformationFile returned %x\n", res);
777 
778         fpi.ReadMode = 2; /* not in range 0-1 */
779         fpi.CompletionMode = 0;
780         res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
781         ok(res == STATUS_INVALID_PARAMETER || broken(!res) /* < Vista */, "NtSetInformationFile returned %x\n", res);
782     }
783 
784     CloseHandle(hClient);
785 
786     check_pipe_handle_state(hServer, 0, 1);
787 
788     fpi.ReadMode = 1;
789     fpi.CompletionMode = 0;
790     res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23);
791     ok(!res, "NtSetInformationFile returned %x\n", res);
792 
793     check_pipe_handle_state(hServer, 1, 0);
794 
795     CloseHandle(hServer);
796 }
797 
apc(void * arg,IO_STATUS_BLOCK * iosb,ULONG reserved)798 static void WINAPI apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserved )
799 {
800     int *count = arg;
801     (*count)++;
802     ok( !reserved, "reserved is not 0: %x\n", reserved );
803 }
804 
test_peek(HANDLE pipe)805 static void test_peek(HANDLE pipe)
806 {
807     FILE_PIPE_PEEK_BUFFER buf;
808     IO_STATUS_BLOCK iosb;
809     HANDLE event = CreateEventA( NULL, TRUE, FALSE, NULL );
810     NTSTATUS status;
811 
812     memset(&iosb, 0x55, sizeof(iosb));
813     status = NtFsControlFile(pipe, NULL, NULL, NULL, &iosb, FSCTL_PIPE_PEEK, NULL, 0, &buf, sizeof(buf));
814     ok(!status || status == STATUS_PENDING, "NtFsControlFile failed: %x\n", status);
815     ok(!iosb.Status, "iosb.Status = %x\n", iosb.Status);
816     ok(buf.ReadDataAvailable == 1, "ReadDataAvailable = %u\n", buf.ReadDataAvailable);
817 
818     ResetEvent(event);
819     memset(&iosb, 0x55, sizeof(iosb));
820     status = NtFsControlFile(pipe, event, NULL, NULL, &iosb, FSCTL_PIPE_PEEK, NULL, 0, &buf, sizeof(buf));
821     ok(!status || status == STATUS_PENDING, "NtFsControlFile failed: %x\n", status);
822     ok(buf.ReadDataAvailable == 1, "ReadDataAvailable = %u\n", buf.ReadDataAvailable);
823     ok(!iosb.Status, "iosb.Status = %x\n", iosb.Status);
824     ok(is_signaled(event), "event is not signaled\n");
825 
826     CloseHandle(event);
827 }
828 
829 #define PIPENAME "\\\\.\\pipe\\ntdll_tests_pipe.c"
830 
create_pipe_pair(HANDLE * read,HANDLE * write,ULONG flags,ULONG type,ULONG size)831 static BOOL create_pipe_pair( HANDLE *read, HANDLE *write, ULONG flags, ULONG type, ULONG size )
832 {
833     const BOOL server_reader = flags & PIPE_ACCESS_INBOUND;
834     HANDLE client, server;
835 
836     server = CreateNamedPipeA(PIPENAME, flags, PIPE_WAIT | type,
837                               1, size, size, NMPWAIT_USE_DEFAULT_WAIT, NULL);
838     ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
839 
840     client = CreateFileA(PIPENAME, server_reader ? GENERIC_WRITE : GENERIC_READ | FILE_WRITE_ATTRIBUTES, 0,
841                          NULL, OPEN_EXISTING, flags & FILE_FLAG_OVERLAPPED, 0);
842     ok(client != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError());
843 
844     if(server_reader)
845     {
846         *read = server;
847         *write = client;
848     }
849     else
850     {
851         if(type & PIPE_READMODE_MESSAGE)
852         {
853             DWORD read_mode = PIPE_READMODE_MESSAGE;
854             ok(SetNamedPipeHandleState(client, &read_mode, NULL, NULL), "Change mode\n");
855         }
856 
857         *read = client;
858         *write = server;
859     }
860     return TRUE;
861 }
862 
read_pipe_test(ULONG pipe_flags,ULONG pipe_type)863 static void read_pipe_test(ULONG pipe_flags, ULONG pipe_type)
864 {
865     IO_STATUS_BLOCK iosb, iosb2;
866     HANDLE handle, read, write;
867     HANDLE event = CreateEventA( NULL, TRUE, FALSE, NULL );
868     int apc_count = 0;
869     char buffer[128];
870     DWORD written;
871     BOOL ret;
872     NTSTATUS status;
873 
874     if (!create_pipe_pair( &read, &write, FILE_FLAG_OVERLAPPED | pipe_flags, pipe_type, 4096 )) return;
875 
876     /* try read with no data */
877     U(iosb).Status = 0xdeadbabe;
878     iosb.Information = 0xdeadbeef;
879     ok( is_signaled( read ), "read handle is not signaled\n" );
880     status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
881     ok( status == STATUS_PENDING, "wrong status %x\n", status );
882     ok( !is_signaled( read ), "read handle is signaled\n" );
883     ok( !is_signaled( event ), "event is signaled\n" );
884     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
885     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
886     ok( !apc_count, "apc was called\n" );
887     ret = WriteFile( write, buffer, 1, &written, NULL );
888     ok(ret && written == 1, "WriteFile error %d\n", GetLastError());
889     /* iosb updated here by async i/o */
890     ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
891     ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
892     ok( !is_signaled( read ), "read handle is signaled\n" );
893     ok( is_signaled( event ), "event is not signaled\n" );
894     ok( !apc_count, "apc was called\n" );
895     apc_count = 0;
896     SleepEx( 1, FALSE ); /* non-alertable sleep */
897     ok( !apc_count, "apc was called\n" );
898     SleepEx( 1, TRUE ); /* alertable sleep */
899     ok( apc_count == 1, "apc not called\n" );
900 
901     /* with no event, the pipe handle itself gets signaled */
902     apc_count = 0;
903     U(iosb).Status = 0xdeadbabe;
904     iosb.Information = 0xdeadbeef;
905     ok( !is_signaled( read ), "read handle is signaled\n" );
906     status = NtReadFile( read, 0, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
907     ok( status == STATUS_PENDING, "wrong status %x\n", status );
908     ok( !is_signaled( read ), "read handle is signaled\n" );
909     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
910     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
911     ok( !apc_count, "apc was called\n" );
912     ret = WriteFile( write, buffer, 1, &written, NULL );
913     ok(ret && written == 1, "WriteFile error %d\n", GetLastError());
914     /* iosb updated here by async i/o */
915     ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
916     ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
917     ok( is_signaled( read ), "read handle is not signaled\n" );
918     ok( !apc_count, "apc was called\n" );
919     apc_count = 0;
920     SleepEx( 1, FALSE ); /* non-alertable sleep */
921     ok( !apc_count, "apc was called\n" );
922     SleepEx( 1, TRUE ); /* alertable sleep */
923     ok( apc_count == 1, "apc not called\n" );
924 
925     /* now read with data ready */
926     apc_count = 0;
927     U(iosb).Status = 0xdeadbabe;
928     iosb.Information = 0xdeadbeef;
929     ResetEvent( event );
930     ret = WriteFile( write, buffer, 1, &written, NULL );
931     ok(ret && written == 1, "WriteFile error %d\n", GetLastError());
932 
933     test_peek(read);
934 
935     status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
936     ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
937     ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
938     ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
939     ok( is_signaled( event ), "event is not signaled\n" );
940     ok( !apc_count, "apc was called\n" );
941     SleepEx( 1, FALSE ); /* non-alertable sleep */
942     ok( !apc_count, "apc was called\n" );
943     SleepEx( 1, TRUE ); /* alertable sleep */
944     ok( apc_count == 1, "apc not called\n" );
945 
946     /* now partial read with data ready */
947     apc_count = 0;
948     U(iosb).Status = 0xdeadbabe;
949     iosb.Information = 0xdeadbeef;
950     ResetEvent( event );
951     ret = WriteFile( write, buffer, 2, &written, NULL );
952     ok(ret && written == 2, "WriteFile error %d\n", GetLastError());
953     status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
954     if (pipe_type & PIPE_READMODE_MESSAGE)
955     {
956         ok( status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", status );
957         ok( U(iosb).Status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", U(iosb).Status );
958     }
959     else
960     {
961         ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
962         ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
963     }
964     ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
965     ok( is_signaled( event ), "event is not signaled\n" );
966     ok( !apc_count, "apc was called\n" );
967     SleepEx( 1, FALSE ); /* non-alertable sleep */
968     ok( !apc_count, "apc was called\n" );
969     SleepEx( 1, TRUE ); /* alertable sleep */
970     ok( apc_count == 1, "apc not called\n" );
971     apc_count = 0;
972     status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
973     ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
974     ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
975     ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
976     ok( is_signaled( event ), "event is not signaled\n" );
977     ok( !apc_count, "apc was called\n" );
978     SleepEx( 1, FALSE ); /* non-alertable sleep */
979     ok( !apc_count, "apc was called\n" );
980     SleepEx( 1, TRUE ); /* alertable sleep */
981     ok( apc_count == 1, "apc not called\n" );
982 
983     /* try read with no data */
984     apc_count = 0;
985     U(iosb).Status = 0xdeadbabe;
986     iosb.Information = 0xdeadbeef;
987     ok( is_signaled( event ), "event is not signaled\n" ); /* check that read resets the event */
988     status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
989     ok( status == STATUS_PENDING, "wrong status %x\n", status );
990     ok( !is_signaled( event ), "event is signaled\n" );
991     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
992     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
993     ok( !apc_count, "apc was called\n" );
994     ret = WriteFile( write, buffer, 1, &written, NULL );
995     ok(ret && written == 1, "WriteFile error %d\n", GetLastError());
996     /* partial read is good enough */
997     Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
998     ok( is_signaled( event ), "event is not signaled\n" );
999     ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
1000     ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
1001     ok( !apc_count, "apc was called\n" );
1002     SleepEx( 1, TRUE ); /* alertable sleep */
1003     ok( apc_count == 1, "apc was not called\n" );
1004 
1005     /* read from disconnected pipe */
1006     apc_count = 0;
1007     U(iosb).Status = 0xdeadbabe;
1008     iosb.Information = 0xdeadbeef;
1009     CloseHandle( write );
1010     status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
1011     ok( status == STATUS_PIPE_BROKEN, "wrong status %x\n", status );
1012     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
1013     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
1014     ok( !is_signaled( event ), "event is signaled\n" );
1015     ok( !apc_count, "apc was called\n" );
1016     SleepEx( 1, TRUE ); /* alertable sleep */
1017     ok( !apc_count, "apc was called\n" );
1018     CloseHandle( read );
1019 
1020     /* read from disconnected pipe, with invalid event handle */
1021     apc_count = 0;
1022     U(iosb).Status = 0xdeadbabe;
1023     iosb.Information = 0xdeadbeef;
1024     status = NtReadFile( read, (HANDLE)0xdeadbeef, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
1025     ok( status == STATUS_INVALID_HANDLE, "wrong status %x\n", status );
1026     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
1027     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
1028     ok( !apc_count, "apc was called\n" );
1029     SleepEx( 1, TRUE ); /* alertable sleep */
1030     ok( !apc_count, "apc was called\n" );
1031     CloseHandle( read );
1032 
1033     /* read from closed handle */
1034     apc_count = 0;
1035     U(iosb).Status = 0xdeadbabe;
1036     iosb.Information = 0xdeadbeef;
1037     SetEvent( event );
1038     status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
1039     ok( status == STATUS_INVALID_HANDLE, "wrong status %x\n", status );
1040     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
1041     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
1042     ok( is_signaled( event ), "event is not signaled\n" );  /* not reset on invalid handle */
1043     ok( !apc_count, "apc was called\n" );
1044     SleepEx( 1, TRUE ); /* alertable sleep */
1045     ok( !apc_count, "apc was called\n" );
1046 
1047     /* disconnect while async read is in progress */
1048     if (!create_pipe_pair( &read, &write, FILE_FLAG_OVERLAPPED | pipe_flags, pipe_type, 4096 )) return;
1049     apc_count = 0;
1050     U(iosb).Status = 0xdeadbabe;
1051     iosb.Information = 0xdeadbeef;
1052     status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
1053     ok( status == STATUS_PENDING, "wrong status %x\n", status );
1054     ok( !is_signaled( event ), "event is signaled\n" );
1055     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
1056     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
1057     ok( !apc_count, "apc was called\n" );
1058     CloseHandle( write );
1059     Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
1060     ok( U(iosb).Status == STATUS_PIPE_BROKEN, "wrong status %x\n", U(iosb).Status );
1061     ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
1062     ok( is_signaled( event ), "event is not signaled\n" );
1063     ok( !apc_count, "apc was called\n" );
1064     SleepEx( 1, TRUE ); /* alertable sleep */
1065     ok( apc_count == 1, "apc was not called\n" );
1066     CloseHandle( read );
1067 
1068     if (!create_pipe_pair( &read, &write, FILE_FLAG_OVERLAPPED | pipe_flags, pipe_type, 4096 )) return;
1069     ret = DuplicateHandle(GetCurrentProcess(), read, GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS);
1070     ok(ret, "Failed to duplicate handle: %d\n", GetLastError());
1071 
1072     apc_count = 0;
1073     U(iosb).Status = 0xdeadbabe;
1074     iosb.Information = 0xdeadbeef;
1075     status = NtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
1076     ok( status == STATUS_PENDING, "wrong status %x\n", status );
1077     ok( !is_signaled( event ), "event is signaled\n" );
1078     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
1079     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
1080     ok( !apc_count, "apc was called\n" );
1081     /* Cancel by other handle */
1082     status = pNtCancelIoFile( read, &iosb2 );
1083     ok(status == STATUS_SUCCESS, "failed to cancel by different handle: %x\n", status);
1084     Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
1085     ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
1086     ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
1087     ok( is_signaled( event ), "event is not signaled\n" );
1088     ok( !apc_count, "apc was called\n" );
1089     SleepEx( 1, TRUE ); /* alertable sleep */
1090     ok( apc_count == 1, "apc was not called\n" );
1091 
1092     apc_count = 0;
1093     U(iosb).Status = 0xdeadbabe;
1094     iosb.Information = 0xdeadbeef;
1095     status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
1096     ok( status == STATUS_PENDING, "wrong status %x\n", status );
1097     ok( !is_signaled( event ), "event is signaled\n" );
1098     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
1099     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
1100     ok( !apc_count, "apc was called\n" );
1101     /* Close queued handle */
1102     CloseHandle( read );
1103     SleepEx( 1, TRUE ); /* alertable sleep */
1104     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
1105     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
1106     status = pNtCancelIoFile( read, &iosb2 );
1107     ok(status == STATUS_INVALID_HANDLE, "cancelled by closed handle?\n");
1108     status = pNtCancelIoFile( handle, &iosb2 );
1109     ok(status == STATUS_SUCCESS, "failed to cancel: %x\n", status);
1110     Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
1111     ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
1112     ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
1113     ok( is_signaled( event ), "event is not signaled\n" );
1114     ok( !apc_count, "apc was called\n" );
1115     SleepEx( 1, TRUE ); /* alertable sleep */
1116     ok( apc_count == 1, "apc was not called\n" );
1117     CloseHandle( handle );
1118     CloseHandle( write );
1119 
1120     if (pNtCancelIoFileEx)
1121     {
1122         /* Basic Cancel Ex */
1123         if (!create_pipe_pair( &read, &write, FILE_FLAG_OVERLAPPED | pipe_flags, pipe_type, 4096 )) return;
1124 
1125         apc_count = 0;
1126         U(iosb).Status = 0xdeadbabe;
1127         iosb.Information = 0xdeadbeef;
1128         status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
1129         ok( status == STATUS_PENDING, "wrong status %x\n", status );
1130         ok( !is_signaled( event ), "event is signaled\n" );
1131         ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
1132         ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
1133         ok( !apc_count, "apc was called\n" );
1134         status = pNtCancelIoFileEx( read, &iosb, &iosb2 );
1135         ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n");
1136         Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
1137         ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
1138         ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
1139         ok( is_signaled( event ), "event is not signaled\n" );
1140         ok( !apc_count, "apc was called\n" );
1141         SleepEx( 1, TRUE ); /* alertable sleep */
1142         ok( apc_count == 1, "apc was not called\n" );
1143 
1144         /* Duplicate iosb */
1145         apc_count = 0;
1146         U(iosb).Status = 0xdeadbabe;
1147         iosb.Information = 0xdeadbeef;
1148         status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
1149         ok( status == STATUS_PENDING, "wrong status %x\n", status );
1150         ok( !is_signaled( event ), "event is signaled\n" );
1151         ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
1152         ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
1153         ok( !apc_count, "apc was called\n" );
1154         status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
1155         ok( status == STATUS_PENDING, "wrong status %x\n", status );
1156         ok( !is_signaled( event ), "event is signaled\n" );
1157         ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
1158         ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
1159         ok( !apc_count, "apc was called\n" );
1160         status = pNtCancelIoFileEx( read, &iosb, &iosb2 );
1161         ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n");
1162         Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
1163         ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
1164         ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
1165         ok( is_signaled( event ), "event is not signaled\n" );
1166         ok( !apc_count, "apc was called\n" );
1167         SleepEx( 1, TRUE ); /* alertable sleep */
1168         ok( apc_count == 2, "apc was not called\n" );
1169 
1170         CloseHandle( read );
1171         CloseHandle( write );
1172     }
1173     else
1174         win_skip("NtCancelIoFileEx not available\n");
1175 
1176     CloseHandle(event);
1177 }
1178 
test_volume_info(void)1179 static void test_volume_info(void)
1180 {
1181     FILE_FS_DEVICE_INFORMATION *device_info;
1182     IO_STATUS_BLOCK iosb;
1183     HANDLE read, write;
1184     char buffer[128];
1185     NTSTATUS status;
1186 
1187     if (!create_pipe_pair( &read, &write, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_INBOUND,
1188                            PIPE_TYPE_MESSAGE, 4096 )) return;
1189 
1190     memset( buffer, 0xaa, sizeof(buffer) );
1191     status = pNtQueryVolumeInformationFile( read, &iosb, buffer, sizeof(buffer), FileFsDeviceInformation );
1192     ok( status == STATUS_SUCCESS, "NtQueryVolumeInformationFile failed: %x\n", status );
1193     ok( iosb.Information == sizeof(*device_info), "Information = %lu\n", iosb.Information );
1194     device_info = (FILE_FS_DEVICE_INFORMATION*)buffer;
1195     ok( device_info->DeviceType == FILE_DEVICE_NAMED_PIPE, "DeviceType = %u\n", device_info->DeviceType );
1196     ok( !(device_info->Characteristics & ~FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL),
1197         "Characteristics = %x\n", device_info->Characteristics );
1198 
1199     memset( buffer, 0xaa, sizeof(buffer) );
1200     status = pNtQueryVolumeInformationFile( write, &iosb, buffer, sizeof(buffer), FileFsDeviceInformation );
1201     ok( status == STATUS_SUCCESS, "NtQueryVolumeInformationFile failed: %x\n", status );
1202     ok( iosb.Information == sizeof(*device_info), "Information = %lu\n", iosb.Information );
1203     device_info = (FILE_FS_DEVICE_INFORMATION*)buffer;
1204     ok( device_info->DeviceType == FILE_DEVICE_NAMED_PIPE, "DeviceType = %u\n", device_info->DeviceType );
1205     ok( !(device_info->Characteristics & ~FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL),
1206         "Characteristics = %x\n", device_info->Characteristics );
1207 
1208     CloseHandle( read );
1209     CloseHandle( write );
1210 }
1211 
1212 #define test_file_name_fail(a,b) _test_file_name_fail(__LINE__,a,b)
_test_file_name_fail(unsigned line,HANDLE pipe,NTSTATUS expected_status)1213 static void _test_file_name_fail(unsigned line, HANDLE pipe, NTSTATUS expected_status)
1214 {
1215     char buffer[512];
1216     IO_STATUS_BLOCK iosb;
1217     NTSTATUS status;
1218 
1219     status = NtQueryInformationFile( pipe, &iosb, buffer, sizeof(buffer), FileNameInformation );
1220     ok_(__FILE__,line)( status == expected_status, "NtQueryInformationFile failed: %x, expected %x\n",
1221                         status, expected_status );
1222 }
1223 
1224 #define test_file_name(a) _test_file_name(__LINE__,a)
_test_file_name(unsigned line,HANDLE pipe)1225 static void _test_file_name(unsigned line, HANDLE pipe)
1226 {
1227     char buffer[512];
1228     FILE_NAME_INFORMATION *name_info = (FILE_NAME_INFORMATION*)buffer;
1229     IO_STATUS_BLOCK iosb;
1230     NTSTATUS status;
1231 
1232     static const WCHAR nameW[] =
1233         {'\\','n','t','d','l','l','_','t','e','s','t','s','_','p','i','p','e','.','c'};
1234 
1235     memset( buffer, 0xaa, sizeof(buffer) );
1236     memset( &iosb, 0xaa, sizeof(iosb) );
1237     status = NtQueryInformationFile( pipe, &iosb, buffer, sizeof(buffer), FileNameInformation );
1238     ok_(__FILE__,line)( status == STATUS_SUCCESS, "NtQueryInformationFile failed: %x\n", status );
1239     ok_(__FILE__,line)( iosb.Status == STATUS_SUCCESS, "Status = %x\n", iosb.Status );
1240     ok_(__FILE__,line)( iosb.Information == sizeof(name_info->FileNameLength) + sizeof(nameW),
1241         "Information = %lu\n", iosb.Information );
1242     ok( name_info->FileNameLength == sizeof(nameW), "FileNameLength = %u\n", name_info->FileNameLength );
1243     ok( !memcmp(name_info->FileName, nameW, sizeof(nameW)), "FileName = %s\n", wine_dbgstr_w(name_info->FileName) );
1244 
1245     /* too small buffer */
1246     memset( buffer, 0xaa, sizeof(buffer) );
1247     memset( &iosb, 0xaa, sizeof(iosb) );
1248     status = NtQueryInformationFile( pipe, &iosb, buffer, 20, FileNameInformation );
1249     ok( status == STATUS_BUFFER_OVERFLOW, "NtQueryInformationFile failed: %x\n", status );
1250     ok( iosb.Status == STATUS_BUFFER_OVERFLOW, "Status = %x\n", iosb.Status );
1251     ok( iosb.Information == 20, "Information = %lu\n", iosb.Information );
1252     ok( name_info->FileNameLength == sizeof(nameW), "FileNameLength = %u\n", name_info->FileNameLength );
1253     ok( !memcmp(name_info->FileName, nameW, 16), "FileName = %s\n", wine_dbgstr_w(name_info->FileName) );
1254 
1255     /* too small buffer */
1256     memset( buffer, 0xaa, sizeof(buffer) );
1257     memset( &iosb, 0xaa, sizeof(iosb) );
1258     status = NtQueryInformationFile( pipe, &iosb, buffer, 4, FileNameInformation );
1259     ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryInformationFile failed: %x\n", status );
1260 }
1261 
test_file_info(void)1262 static void test_file_info(void)
1263 {
1264     HANDLE server, client;
1265 
1266     if (!create_pipe_pair( &server, &client, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_INBOUND,
1267                            PIPE_TYPE_MESSAGE, 4096 )) return;
1268 
1269     test_file_name( client );
1270     test_file_name( server );
1271 
1272     DisconnectNamedPipe( server );
1273     test_file_name_fail( client, STATUS_PIPE_DISCONNECTED );
1274 
1275     CloseHandle( server );
1276     CloseHandle( client );
1277 }
1278 
get_security_descriptor(HANDLE handle,BOOL todo)1279 static PSECURITY_DESCRIPTOR get_security_descriptor(HANDLE handle, BOOL todo)
1280 {
1281     SECURITY_DESCRIPTOR *sec_desc;
1282     ULONG length = 0;
1283     NTSTATUS status;
1284 
1285     status = NtQuerySecurityObject(handle, GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
1286                                    NULL, 0, &length);
1287     todo_wine_if(todo && status == STATUS_PIPE_DISCONNECTED)
1288     ok(status == STATUS_BUFFER_TOO_SMALL,
1289        "Failed to query object security descriptor length: %08x\n", status);
1290     if(status != STATUS_BUFFER_TOO_SMALL) return NULL;
1291     ok(length != 0, "length = 0\n");
1292 
1293     sec_desc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, length);
1294     status = NtQuerySecurityObject(handle, GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
1295                                    sec_desc, length, &length);
1296     ok(status == STATUS_SUCCESS, "Failed to query object security descriptor: %08x\n", status);
1297 
1298     return sec_desc;
1299 }
1300 
get_current_owner(void)1301 static TOKEN_OWNER *get_current_owner(void)
1302 {
1303     TOKEN_OWNER *owner;
1304     ULONG length = 0;
1305     HANDLE token;
1306     BOOL ret;
1307 
1308     ret = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token);
1309     ok(ret, "Failed to get process token: %u\n", GetLastError());
1310 
1311     ret = GetTokenInformation(token, TokenOwner, NULL, 0, &length);
1312     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1313        "GetTokenInformation failed: %u\n", GetLastError());
1314     ok(length != 0, "Failed to get token owner information length: %u\n", GetLastError());
1315 
1316     owner = HeapAlloc(GetProcessHeap(), 0, length);
1317     ret = GetTokenInformation(token, TokenOwner, owner, length, &length);
1318     ok(ret, "Failed to get token owner information: %u)\n", GetLastError());
1319 
1320     CloseHandle(token);
1321     return owner;
1322 }
1323 
get_current_group(void)1324 static TOKEN_PRIMARY_GROUP *get_current_group(void)
1325 {
1326     TOKEN_PRIMARY_GROUP *group;
1327     ULONG length = 0;
1328     HANDLE token;
1329     BOOL ret;
1330 
1331     ret = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token);
1332     ok(ret, "Failed to get process token: %u\n", GetLastError());
1333 
1334     ret = GetTokenInformation(token, TokenPrimaryGroup, NULL, 0, &length);
1335     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1336        "GetTokenInformation failed: %u\n", GetLastError());
1337     ok(length != 0, "Failed to get primary group token information length: %u\n", GetLastError());
1338 
1339     group = HeapAlloc(GetProcessHeap(), 0, length);
1340     ret = GetTokenInformation(token, TokenPrimaryGroup, group, length, &length);
1341     ok(ret, "Failed to get primary group token information: %u\n", GetLastError());
1342 
1343     CloseHandle(token);
1344     return group;
1345 }
1346 
well_known_sid(WELL_KNOWN_SID_TYPE sid_type)1347 static SID *well_known_sid(WELL_KNOWN_SID_TYPE sid_type)
1348 {
1349     DWORD size = SECURITY_MAX_SID_SIZE;
1350     SID *sid;
1351     BOOL ret;
1352 
1353     sid = HeapAlloc(GetProcessHeap(), 0, size);
1354     ret = CreateWellKnownSid(sid_type, NULL, sid, &size);
1355     ok(ret, "CreateWellKnownSid failed: %u\n", GetLastError());
1356     return sid;
1357 }
1358 
1359 #define test_group(a,b,c) _test_group(__LINE__,a,b,c)
_test_group(unsigned line,HANDLE handle,SID * expected_sid,BOOL todo)1360 static void _test_group(unsigned line, HANDLE handle, SID *expected_sid, BOOL todo)
1361 {
1362     SECURITY_DESCRIPTOR *sec_desc;
1363     BOOLEAN defaulted;
1364     PSID group_sid;
1365     NTSTATUS status;
1366 
1367     sec_desc = get_security_descriptor(handle, todo);
1368     if (!sec_desc) return;
1369 
1370     status = RtlGetGroupSecurityDescriptor(sec_desc, &group_sid, &defaulted);
1371     ok_(__FILE__,line)(status == STATUS_SUCCESS,
1372                        "Failed to query group from security descriptor: %08x\n", status);
1373     todo_wine_if(todo)
1374     ok_(__FILE__,line)(EqualSid(group_sid, expected_sid), "SIDs are not equal\n");
1375 
1376     HeapFree(GetProcessHeap(), 0, sec_desc);
1377 }
1378 
test_security_info(void)1379 static void test_security_info(void)
1380 {
1381     char sec_desc[SECURITY_DESCRIPTOR_MIN_LENGTH];
1382     TOKEN_PRIMARY_GROUP *process_group;
1383     SECURITY_ATTRIBUTES sec_attr;
1384     TOKEN_OWNER *process_owner;
1385     HANDLE server, client, server2;
1386     SID *world_sid, *local_sid;
1387     ULONG length;
1388     NTSTATUS status;
1389     BOOL ret;
1390 
1391     trace("security tests...\n");
1392 
1393     process_owner = get_current_owner();
1394     process_group = get_current_group();
1395     world_sid = well_known_sid(WinWorldSid);
1396     local_sid = well_known_sid(WinLocalSid);
1397 
1398     ret = InitializeSecurityDescriptor(sec_desc, SECURITY_DESCRIPTOR_REVISION);
1399     ok(ret, "InitializeSecurityDescriptor failed\n");
1400 
1401     ret = SetSecurityDescriptorOwner(sec_desc, process_owner->Owner, FALSE);
1402     ok(ret, "SetSecurityDescriptorOwner failed\n");
1403 
1404     ret = SetSecurityDescriptorGroup(sec_desc, process_group->PrimaryGroup, FALSE);
1405     ok(ret, "SetSecurityDescriptorGroup failed\n");
1406 
1407     server = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX | WRITE_OWNER, PIPE_TYPE_BYTE, 10,
1408                               0x20000, 0x20000, 0, NULL);
1409     ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %u\n", GetLastError());
1410 
1411     client = CreateFileA(PIPENAME, GENERIC_ALL, 0, NULL, OPEN_EXISTING, 0, NULL);
1412     ok(client != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
1413 
1414     test_group(server, process_group->PrimaryGroup, TRUE);
1415     test_group(client, process_group->PrimaryGroup, TRUE);
1416 
1417     /* set server group, client changes as well */
1418     ret = SetSecurityDescriptorGroup(sec_desc, world_sid, FALSE);
1419     ok(ret, "SetSecurityDescriptorGroup failed\n");
1420     status = NtSetSecurityObject(server, GROUP_SECURITY_INFORMATION, sec_desc);
1421     ok(status == STATUS_SUCCESS, "NtSetSecurityObject failed: %08x\n", status);
1422 
1423     test_group(server, world_sid, FALSE);
1424     test_group(client, world_sid, FALSE);
1425 
1426     /* new instance of pipe server has the same security descriptor */
1427     server2 = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE, 10,
1428                                0x20000, 0x20000, 0, NULL);
1429     ok(server2 != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %u\n", GetLastError());
1430     test_group(server2, world_sid, FALSE);
1431 
1432     /* set client group, server changes as well */
1433     ret = SetSecurityDescriptorGroup(sec_desc, local_sid, FALSE);
1434     ok(ret, "SetSecurityDescriptorGroup failed\n");
1435     status = NtSetSecurityObject(server, GROUP_SECURITY_INFORMATION, sec_desc);
1436     ok(status == STATUS_SUCCESS, "NtSetSecurityObject failed: %08x\n", status);
1437 
1438     test_group(server, local_sid, FALSE);
1439     test_group(client, local_sid, FALSE);
1440     test_group(server2, local_sid, FALSE);
1441 
1442     CloseHandle(server);
1443     /* SD is preserved after closing server object */
1444     test_group(client, local_sid, TRUE);
1445     CloseHandle(client);
1446 
1447     server = server2;
1448     client = CreateFileA(PIPENAME, GENERIC_ALL, 0, NULL, OPEN_EXISTING, 0, NULL);
1449     ok(client != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
1450 
1451     test_group(client, local_sid, FALSE);
1452 
1453     ret = DisconnectNamedPipe(server);
1454     ok(ret, "DisconnectNamedPipe failed: %u\n", GetLastError());
1455 
1456     /* disconnected server may be queried for security info, but client does not */
1457     test_group(server, local_sid, FALSE);
1458     status = NtQuerySecurityObject(client, GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
1459                                    NULL, 0, &length);
1460     ok(status == STATUS_PIPE_DISCONNECTED, "NtQuerySecurityObject returned %08x\n", status);
1461     status = NtSetSecurityObject(client, GROUP_SECURITY_INFORMATION, sec_desc);
1462     ok(status == STATUS_PIPE_DISCONNECTED, "NtQuerySecurityObject returned %08x\n", status);
1463 
1464     /* attempting to create another pipe instance with specified sd fails */
1465     sec_attr.nLength = sizeof(sec_attr);
1466     sec_attr.lpSecurityDescriptor = sec_desc;
1467     sec_attr.bInheritHandle = FALSE;
1468     ret = SetSecurityDescriptorGroup(sec_desc, local_sid, FALSE);
1469     ok(ret, "SetSecurityDescriptorGroup failed\n");
1470     server2 = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX | WRITE_OWNER, PIPE_TYPE_BYTE, 10,
1471                                0x20000, 0x20000, 0, &sec_attr);
1472     todo_wine
1473     ok(server2 == INVALID_HANDLE_VALUE && GetLastError() == ERROR_ACCESS_DENIED,
1474        "CreateNamedPipe failed: %u\n", GetLastError());
1475     if (server2 != INVALID_HANDLE_VALUE) CloseHandle(server2);
1476 
1477     CloseHandle(server);
1478     CloseHandle(client);
1479 
1480     server = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX | WRITE_OWNER, PIPE_TYPE_BYTE, 10,
1481                               0x20000, 0x20000, 0, &sec_attr);
1482     ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %u\n", GetLastError());
1483     test_group(server, local_sid, FALSE);
1484     CloseHandle(server);
1485 
1486     HeapFree(GetProcessHeap(), 0, process_owner);
1487     HeapFree(GetProcessHeap(), 0, process_group);
1488     HeapFree(GetProcessHeap(), 0, world_sid);
1489     HeapFree(GetProcessHeap(), 0, local_sid);
1490 }
1491 
START_TEST(pipe)1492 START_TEST(pipe)
1493 {
1494     if (!init_func_ptrs())
1495         return;
1496 
1497     trace("starting invalid create tests\n");
1498     test_create_invalid();
1499 
1500     trace("starting create tests\n");
1501     test_create();
1502 
1503     trace("starting overlapped tests\n");
1504     test_overlapped();
1505 
1506     trace("starting completion tests\n");
1507     test_completion();
1508 
1509     trace("starting FILE_PIPE_INFORMATION tests\n");
1510     test_filepipeinfo();
1511 
1512     if (!pOpenThread || !pQueueUserAPC)
1513         return;
1514 
1515     trace("starting alertable tests\n");
1516     test_alertable();
1517 
1518     trace("starting nonalertable tests\n");
1519     test_nonalertable();
1520 
1521     trace("starting cancelio tests\n");
1522     test_cancelio();
1523 
1524     trace("starting byte read in byte mode client -> server\n");
1525     read_pipe_test(PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE);
1526     trace("starting byte read in message mode client -> server\n");
1527     read_pipe_test(PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE);
1528     trace("starting message read in message mode client -> server\n");
1529     read_pipe_test(PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE);
1530     trace("starting byte read in byte mode server -> client\n");
1531     read_pipe_test(PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE);
1532     trace("starting byte read in message mode server -> client\n");
1533     read_pipe_test(PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE);
1534     trace("starting message read in message mode server -> client\n");
1535     read_pipe_test(PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE);
1536 
1537     test_volume_info();
1538     test_file_info();
1539     test_security_info();
1540 }
1541