xref: /reactos/dll/win32/kernel32/client/file/npipe.c (revision 9d33a205)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Win32 Kernel Library
4  * FILE:            dll/win32/kernel32/client/file/npipe.c
5  * PURPOSE:         Named Pipe Functions
6  * PROGRAMMER:      Alex Ionescu (alex@relsoft.net)
7  *                  Ariadne ( ariadne@xs4all.nl)
8  */
9 
10 /* INCLUDES *******************************************************************/
11 
12 #include <k32.h>
13 #define NDEBUG
14 #include <debug.h>
15 DEBUG_CHANNEL(kernel32file);
16 
17 /* GLOBALS ********************************************************************/
18 
19 LONG ProcessPipeId;
20 
21 /* FUNCTIONS ******************************************************************/
22 
23 /*
24  * @implemented
25  */
26 static
27 BOOL
28 NpGetUserNamep(HANDLE hNamedPipe,
29                LPWSTR lpUserName,
30                DWORD nMaxUserNameSize)
31 {
32     BOOL Ret;
33     HANDLE hToken;
34     HMODULE hAdvapi;
35     NTSTATUS Status;
36     BOOL (WINAPI *pRevertToSelf)(void);
37     BOOL (WINAPI *pGetUserNameW)(LPWSTR lpBuffer, LPDWORD lpnSize);
38     BOOL (WINAPI *pImpersonateNamedPipeClient)(HANDLE hNamedPipe);
39 
40     /* Open advapi, we'll funcs from it */
41     hAdvapi = LoadLibraryW(L"advapi32.dll");
42     if (hAdvapi == NULL)
43     {
44         return FALSE;
45     }
46 
47     /* Import the three required functions */
48     pRevertToSelf = (BOOL (WINAPI *)(void))GetProcAddress(hAdvapi, "RevertToSelf");
49     pGetUserNameW = (BOOL (WINAPI *)(LPWSTR, LPDWORD))GetProcAddress(hAdvapi, "GetUserNameW");
50     pImpersonateNamedPipeClient = (BOOL (WINAPI *)(HANDLE))GetProcAddress(hAdvapi, "ImpersonateNamedPipeClient");
51     /* If any couldn't be found, fail */
52     if (pRevertToSelf == NULL || pGetUserNameW == NULL || pImpersonateNamedPipeClient == NULL)
53     {
54         FreeLibrary(hAdvapi);
55         return FALSE;
56     }
57 
58     /* Now, open the thread token for impersonation */
59     Status = NtOpenThreadToken(NtCurrentThread(), TOKEN_IMPERSONATE, TRUE, &hToken);
60     /* Try to impersonate the pipe client */
61     if (pImpersonateNamedPipeClient(hNamedPipe))
62     {
63         DWORD lpnSize;
64 
65         /* It worked, get the user name */
66         lpnSize = nMaxUserNameSize;
67         Ret = pGetUserNameW(lpUserName, &lpnSize);
68         /* Failed to get the thread token? Revert to self */
69         if (!NT_SUCCESS(Status))
70         {
71             pRevertToSelf();
72 
73             FreeLibrary(hAdvapi);
74             return Ret;
75         }
76 
77         /* Restore the thread token */
78         Status = NtSetInformationThread(NtCurrentThread(), ThreadImpersonationToken,
79                                         &hToken, sizeof(hToken));
80         /* We cannot fail closing the thread token! */
81         if (!CloseHandle(hToken))
82         {
83             ASSERT(FALSE);
84         }
85 
86         /* Set last error if it failed */
87         if (!NT_SUCCESS(Status))
88         {
89             BaseSetLastNTError(Status);
90         }
91     }
92     else
93     {
94         /* If opening the thread token succeed, close it */
95         if (NT_SUCCESS(Status))
96         {
97             /* We cannot fail closing it! */
98             if (!CloseHandle(hToken))
99             {
100                 ASSERT(FALSE);
101             }
102         }
103 
104         Ret = FALSE;
105     }
106 
107     FreeLibrary(hAdvapi);
108     return Ret;
109 }
110 
111 
112 /*
113  * @implemented
114  */
115 BOOL
116 WINAPI
117 CreatePipe(PHANDLE hReadPipe,
118            PHANDLE hWritePipe,
119            LPSECURITY_ATTRIBUTES lpPipeAttributes,
120            DWORD nSize)
121 {
122     WCHAR Buffer[64];
123     UNICODE_STRING PipeName;
124     OBJECT_ATTRIBUTES ObjectAttributes;
125     IO_STATUS_BLOCK StatusBlock;
126     LARGE_INTEGER DefaultTimeout;
127     NTSTATUS Status;
128     HANDLE ReadPipeHandle;
129     HANDLE WritePipeHandle;
130     LONG PipeId;
131     ULONG Attributes;
132     PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
133 
134     /* Set the timeout to 120 seconds */
135     DefaultTimeout.QuadPart = -1200000000;
136 
137     /* Use default buffer size if desired */
138     if (!nSize) nSize = 0x1000;
139 
140     /* Increase the Pipe ID */
141     PipeId = InterlockedIncrement(&ProcessPipeId);
142 
143     /* Create the pipe name */
144     swprintf(Buffer,
145              L"\\Device\\NamedPipe\\Win32Pipes.%p.%08x",
146              NtCurrentTeb()->ClientId.UniqueProcess,
147              PipeId);
148     RtlInitUnicodeString(&PipeName, Buffer);
149 
150     /* Always use case insensitive */
151     Attributes = OBJ_CASE_INSENSITIVE;
152 
153     /* Check if we got attributes */
154     if (lpPipeAttributes)
155     {
156         /* Use the attributes' SD instead */
157         SecurityDescriptor = lpPipeAttributes->lpSecurityDescriptor;
158 
159         /* Set OBJ_INHERIT if requested */
160         if (lpPipeAttributes->bInheritHandle) Attributes |= OBJ_INHERIT;
161     }
162 
163     /* Initialize the attributes */
164     InitializeObjectAttributes(&ObjectAttributes,
165                                &PipeName,
166                                Attributes,
167                                NULL,
168                                SecurityDescriptor);
169 
170     /* Create the named pipe */
171     Status = NtCreateNamedPipeFile(&ReadPipeHandle,
172                                    GENERIC_READ | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
173                                    &ObjectAttributes,
174                                    &StatusBlock,
175                                    FILE_SHARE_READ | FILE_SHARE_WRITE,
176                                    FILE_CREATE,
177                                    FILE_SYNCHRONOUS_IO_NONALERT,
178                                    FILE_PIPE_BYTE_STREAM_TYPE,
179                                    FILE_PIPE_BYTE_STREAM_MODE,
180                                    FILE_PIPE_QUEUE_OPERATION,
181                                    1,
182                                    nSize,
183                                    nSize,
184                                    &DefaultTimeout);
185     if (!NT_SUCCESS(Status))
186     {
187         /* Convert error and fail */
188         WARN("Status: %lx\n", Status);
189         BaseSetLastNTError(Status);
190         return FALSE;
191     }
192 
193     /* Now try opening it for write access */
194     Status = NtOpenFile(&WritePipeHandle,
195                         FILE_GENERIC_WRITE,
196                         &ObjectAttributes,
197                         &StatusBlock,
198                         FILE_SHARE_READ,
199                         FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
200     if (!NT_SUCCESS(Status))
201     {
202         /* Convert error and fail */
203         WARN("Status: %lx\n", Status);
204         NtClose(ReadPipeHandle);
205         BaseSetLastNTError(Status);
206         return FALSE;
207     }
208 
209     /* Return both handles */
210     *hReadPipe = ReadPipeHandle;
211     *hWritePipe = WritePipeHandle;
212     return TRUE;
213 }
214 
215 /*
216  * @implemented
217  */
218 HANDLE
219 WINAPI
220 CreateNamedPipeA(LPCSTR lpName,
221                  DWORD dwOpenMode,
222                  DWORD dwPipeMode,
223                  DWORD nMaxInstances,
224                  DWORD nOutBufferSize,
225                  DWORD nInBufferSize,
226                  DWORD nDefaultTimeOut,
227                  LPSECURITY_ATTRIBUTES lpSecurityAttributes)
228 {
229     /* Call the W(ide) function */
230     ConvertWin32AnsiChangeApiToUnicodeApi(CreateNamedPipe,
231                                           lpName,
232                                           dwOpenMode,
233                                           dwPipeMode,
234                                           nMaxInstances,
235                                           nOutBufferSize,
236                                           nInBufferSize,
237                                           nDefaultTimeOut,
238                                           lpSecurityAttributes);
239 }
240 
241 /*
242  * @implemented
243  */
244 HANDLE
245 WINAPI
246 CreateNamedPipeW(LPCWSTR lpName,
247                  DWORD dwOpenMode,
248                  DWORD dwPipeMode,
249                  DWORD nMaxInstances,
250                  DWORD nOutBufferSize,
251                  DWORD nInBufferSize,
252                  DWORD nDefaultTimeOut,
253                  LPSECURITY_ATTRIBUTES lpSecurityAttributes)
254 {
255     UNICODE_STRING NamedPipeName;
256     BOOL Result;
257     NTSTATUS Status;
258     OBJECT_ATTRIBUTES ObjectAttributes;
259     HANDLE PipeHandle;
260     ACCESS_MASK DesiredAccess;
261     ULONG CreateOptions = 0;
262     ULONG WriteModeMessage;
263     ULONG ReadModeMessage;
264     ULONG NonBlocking;
265     IO_STATUS_BLOCK Iosb;
266     ULONG ShareAccess = 0, Attributes;
267     LARGE_INTEGER DefaultTimeOut;
268     PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
269 
270     /* Check for valid instances */
271     if (nMaxInstances == 0 || nMaxInstances > PIPE_UNLIMITED_INSTANCES)
272     {
273         /* Fail */
274         SetLastError(ERROR_INVALID_PARAMETER);
275         return INVALID_HANDLE_VALUE;
276     }
277 
278     /* Convert to NT syntax */
279     if (nMaxInstances == PIPE_UNLIMITED_INSTANCES)
280         nMaxInstances = -1;
281 
282     /* Convert the name */
283     Result = RtlDosPathNameToNtPathName_U(lpName,
284                                            &NamedPipeName,
285                                            NULL,
286                                            NULL);
287     if (!Result)
288     {
289         /* Conversion failed */
290         SetLastError(ERROR_PATH_NOT_FOUND);
291         return INVALID_HANDLE_VALUE;
292     }
293 
294     TRACE("Pipe name: %wZ\n", &NamedPipeName);
295     TRACE("Pipe name: %S\n", NamedPipeName.Buffer);
296 
297     /* Always case insensitive, check if we got extra attributes */
298     Attributes = OBJ_CASE_INSENSITIVE;
299     if (lpSecurityAttributes)
300     {
301         /* We did; get the security descriptor */
302         SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
303 
304         /* And check if this is pipe's handle will beinheritable */
305         if (lpSecurityAttributes->bInheritHandle)
306             Attributes |= OBJ_INHERIT;
307     }
308 
309     /* Now we can initialize the object attributes */
310     InitializeObjectAttributes(&ObjectAttributes,
311                                &NamedPipeName,
312                                Attributes,
313                                NULL,
314                                SecurityDescriptor);
315 
316     /* Setup the default Desired Access */
317     DesiredAccess = SYNCHRONIZE | (dwOpenMode & (WRITE_DAC |
318                                                  WRITE_OWNER |
319                                                  ACCESS_SYSTEM_SECURITY));
320 
321     /* Convert to NT Create Flags */
322     if (dwOpenMode & FILE_FLAG_WRITE_THROUGH)
323     {
324         CreateOptions |= FILE_WRITE_THROUGH;
325     }
326 
327     if (!(dwOpenMode & FILE_FLAG_OVERLAPPED))
328     {
329         CreateOptions |= FILE_SYNCHRONOUS_IO_NONALERT;
330     }
331 
332     /* Handle all open modes */
333     if (dwOpenMode & PIPE_ACCESS_OUTBOUND)
334     {
335         ShareAccess |= FILE_SHARE_READ;
336         DesiredAccess |= GENERIC_WRITE;
337     }
338 
339     if (dwOpenMode & PIPE_ACCESS_INBOUND)
340     {
341         ShareAccess |= FILE_SHARE_WRITE;
342         DesiredAccess |= GENERIC_READ;
343     }
344 
345     /* Handle the type flags */
346     if (dwPipeMode & PIPE_TYPE_MESSAGE)
347     {
348         WriteModeMessage = FILE_PIPE_MESSAGE_TYPE;
349     }
350     else
351     {
352         WriteModeMessage = FILE_PIPE_BYTE_STREAM_TYPE;
353     }
354 
355     /* Handle the mode flags */
356     if (dwPipeMode & PIPE_READMODE_MESSAGE)
357     {
358         ReadModeMessage = FILE_PIPE_MESSAGE_MODE;
359     }
360     else
361     {
362         ReadModeMessage = FILE_PIPE_BYTE_STREAM_MODE;
363     }
364 
365     /* Handle the blocking mode */
366     if (dwPipeMode & PIPE_NOWAIT)
367     {
368         NonBlocking = FILE_PIPE_COMPLETE_OPERATION;
369     }
370     else
371     {
372         NonBlocking = FILE_PIPE_QUEUE_OPERATION;
373     }
374 
375     /* Check if we have a timeout */
376     if (nDefaultTimeOut)
377     {
378         /* Convert the time to NT format */
379         DefaultTimeOut.QuadPart = nDefaultTimeOut * -10000LL;
380     }
381     else
382     {
383         /* Use default timeout of 50 ms */
384         DefaultTimeOut.QuadPart = -500000;
385     }
386 
387     /* Now create the pipe */
388     Status = NtCreateNamedPipeFile(&PipeHandle,
389                                    DesiredAccess,
390                                    &ObjectAttributes,
391                                    &Iosb,
392                                    ShareAccess,
393                                    FILE_OPEN_IF,
394                                    CreateOptions,
395                                    WriteModeMessage,
396                                    ReadModeMessage,
397                                    NonBlocking,
398                                    nMaxInstances,
399                                    nInBufferSize,
400                                    nOutBufferSize,
401                                    &DefaultTimeOut);
402 
403     /* Normalize special error codes */
404     if ((Status == STATUS_INVALID_DEVICE_REQUEST) ||
405         (Status == STATUS_NOT_SUPPORTED))
406     {
407         Status = STATUS_OBJECT_NAME_INVALID;
408     }
409 
410     /* Free the name */
411     RtlFreeHeap(RtlGetProcessHeap(),
412                 0,
413                 NamedPipeName.Buffer);
414 
415     /* Check status */
416     if (!NT_SUCCESS(Status))
417     {
418         /* Failed to create it */
419         WARN("NtCreateNamedPipe failed (Status %x)!\n", Status);
420         BaseSetLastNTError (Status);
421         return INVALID_HANDLE_VALUE;
422     }
423 
424     /* Return the handle */
425     return PipeHandle;
426 }
427 
428 /*
429  * @implemented
430  */
431 BOOL
432 WINAPI
433 WaitNamedPipeA(LPCSTR lpNamedPipeName,
434                DWORD nTimeOut)
435 {
436     BOOL r = FALSE;
437     UNICODE_STRING NameU;
438 
439     /* Convert the name to Unicode */
440     if (Basep8BitStringToDynamicUnicodeString(&NameU, lpNamedPipeName))
441     {
442         /* Call the Unicode API */
443         r = WaitNamedPipeW(NameU.Buffer, nTimeOut);
444 
445         /* Free the Unicode string */
446         RtlFreeUnicodeString(&NameU);
447     }
448 
449     /* Return result */
450     return r;
451 }
452 
453 /*
454  * @implemented
455  */
456 BOOL
457 WINAPI
458 WaitNamedPipeW(LPCWSTR lpNamedPipeName,
459                DWORD nTimeOut)
460 {
461     UNICODE_STRING NamedPipeName, NewName, DevicePath, PipePrefix;
462     ULONG NameLength;
463     ULONG i;
464     PWCHAR p;
465     ULONG Type;
466     OBJECT_ATTRIBUTES ObjectAttributes;
467     NTSTATUS Status;
468     HANDLE FileHandle;
469     IO_STATUS_BLOCK IoStatusBlock;
470     ULONG WaitPipeInfoSize;
471     PVOID DevicePathBuffer;
472     PFILE_PIPE_WAIT_FOR_BUFFER WaitPipeInfo;
473 
474     /* Start by making a unicode string of the name */
475     TRACE("Sent path: %S\n", lpNamedPipeName);
476     if (!RtlCreateUnicodeString(&NamedPipeName, lpNamedPipeName))
477     {
478         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
479         return FALSE;
480     }
481     NameLength = NamedPipeName.Length / sizeof(WCHAR);
482 
483     /* All slashes must become backslashes */
484     for (i = 0; i < NameLength; i++)
485     {
486         /* Check and convert */
487         if (NamedPipeName.Buffer[i] == L'/') NamedPipeName.Buffer[i] = L'\\';
488     }
489 
490     DevicePathBuffer = NULL;
491 
492     /* Find the path type of the name we were given */
493     NewName = NamedPipeName;
494     Type = RtlDetermineDosPathNameType_U(lpNamedPipeName);
495 
496     /* Check if this was a device path, ie : "\\.\pipe\name" */
497     if (Type == RtlPathTypeLocalDevice)
498     {
499         /* Make sure it's a valid prefix */
500         RtlInitUnicodeString(&PipePrefix, L"\\\\.\\pipe\\");
501         if (!RtlPrefixUnicodeString(&PipePrefix, &NewName, TRUE))
502         {
503             /* The name is invalid */
504             WARN("Invalid name!\n");
505             RtlFreeUnicodeString(&NamedPipeName);
506             BaseSetLastNTError(STATUS_OBJECT_PATH_SYNTAX_BAD);
507             return FALSE;
508         }
509 
510         /* Move past it */
511         NewName.Buffer += PipePrefix.Length / sizeof(WCHAR);
512         NewName.Length -= PipePrefix.Length;
513         NewName.MaximumLength -= PipePrefix.Length;
514 
515         /* Initialize the Dos Devices name */
516         TRACE("NewName: %wZ\n", &NewName);
517         RtlInitUnicodeString(&DevicePath, L"\\DosDevices\\pipe\\");
518     }
519     else if (Type == RtlPathTypeUncAbsolute)
520     {
521         PWSTR PipeName;
522 
523         /* The path is \\server\\pipe\name; find the pipename itself */
524         p = &NewName.Buffer[2];
525 
526         /* First loop to get past the server name */
527         do
528         {
529             /* Check if this is a backslash */
530             if (*p == L'\\') break;
531 
532             /* Check next */
533             p++;
534         } while (*p);
535 
536         /* Now make sure the full name contains "pipe\" */
537         if ((*p) && !(_wcsnicmp(p + 1, L"pipe\\", sizeof("pipe\\") - sizeof(ANSI_NULL))))
538         {
539             /* Get to the pipe name itself now */
540             p += sizeof("pipe\\") - sizeof(ANSI_NULL);
541         }
542         else
543         {
544             /* The name is invalid */
545             WARN("Invalid name!\n");
546             RtlFreeUnicodeString(&NamedPipeName);
547             BaseSetLastNTError(STATUS_OBJECT_PATH_SYNTAX_BAD);
548             return FALSE;
549         }
550 
551         /* Skip first backslash */
552         NewName.Buffer++;
553         /* And skip pipe for copying name */
554         PipeName = p + ((sizeof(L"pipe\\") - sizeof(UNICODE_NULL)) / sizeof(WCHAR));
555         /* Update the string */
556         NewName.Length = (USHORT)((ULONG_PTR)PipeName - (ULONG_PTR)NewName.Buffer);
557         NewName.MaximumLength = (USHORT)((ULONG_PTR)PipeName - (ULONG_PTR)NewName.Buffer);
558 
559         /* DevicePath will contain the pipename + the DosDevice prefix */
560         DevicePath.MaximumLength = (USHORT)((ULONG_PTR)PipeName - (ULONG_PTR)NewName.Buffer) + sizeof(L"\\DosDevices\\UNC\\");
561 
562         /* Allocate the buffer for DevicePath */
563         DevicePathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, DevicePath.MaximumLength);
564         if (DevicePathBuffer == NULL)
565         {
566             RtlFreeUnicodeString(&NamedPipeName);
567             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
568             return FALSE;
569         }
570 
571         /* Copy the prefix first */
572         DevicePath.Buffer = DevicePathBuffer;
573         RtlCopyMemory(DevicePathBuffer, L"\\DosDevices\\UNC\\", sizeof(L"\\DosDevices\\UNC\\") - sizeof(UNICODE_NULL));
574         DevicePath.Length = sizeof(L"\\DosDevices\\UNC\\") - sizeof(UNICODE_NULL);
575         /* And append the rest */
576         RtlAppendUnicodeStringToString(&DevicePath, &NewName);
577         /* And fix pipe name without its prefix */
578         RtlInitUnicodeString(&NewName, PipeName + 1);
579     }
580     else
581     {
582         WARN("Invalid path type\n");
583         RtlFreeUnicodeString(&NamedPipeName);
584         BaseSetLastNTError(STATUS_OBJECT_PATH_SYNTAX_BAD);
585         return FALSE;
586     }
587 
588     /* Now calculate the total length of the structure and allocate it */
589     WaitPipeInfoSize = FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name[0]) +
590                        NewName.Length;
591     WaitPipeInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, WaitPipeInfoSize);
592     if (WaitPipeInfo == NULL)
593     {
594         if (DevicePathBuffer != NULL)
595         {
596             RtlFreeHeap(RtlGetProcessHeap(), 0, DevicePathBuffer);
597         }
598 
599         RtlFreeUnicodeString(&NamedPipeName);
600         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
601         return FALSE;
602     }
603 
604     /* Initialize the object attributes */
605     TRACE("Opening: %wZ\n", &DevicePath);
606     InitializeObjectAttributes(&ObjectAttributes,
607                                &DevicePath,
608                                OBJ_CASE_INSENSITIVE,
609                                NULL,
610                                NULL);
611 
612     /* Open the path */
613     Status = NtOpenFile(&FileHandle,
614                         FILE_READ_ATTRIBUTES | SYNCHRONIZE,
615                         &ObjectAttributes,
616                         &IoStatusBlock,
617                         FILE_SHARE_READ | FILE_SHARE_WRITE,
618                         FILE_SYNCHRONOUS_IO_NONALERT);
619 
620     if (DevicePathBuffer != NULL)
621     {
622         RtlFreeHeap(RtlGetProcessHeap(), 0, DevicePathBuffer);
623     }
624 
625     if (!NT_SUCCESS(Status))
626     {
627         /* Fail; couldn't open */
628         WARN("Status: %lx\n", Status);
629         RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo);
630         RtlFreeUnicodeString(&NamedPipeName);
631         BaseSetLastNTError(Status);
632         return FALSE;
633     }
634 
635     /* Check what timeout we got */
636     if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT)
637     {
638         /* Don't use a timeout */
639         WaitPipeInfo->TimeoutSpecified = FALSE;
640     }
641     else
642     {
643         /* Check if we should wait forever */
644         if (nTimeOut == NMPWAIT_WAIT_FOREVER)
645         {
646             /* Set the max */
647             WaitPipeInfo->Timeout.LowPart = 0;
648             WaitPipeInfo->Timeout.HighPart = 0x80000000;
649         }
650         else
651         {
652             /* Convert to NT format */
653             WaitPipeInfo->Timeout.QuadPart = nTimeOut * -10000LL;
654         }
655 
656         /* In both cases, we do have a timeout */
657         WaitPipeInfo->TimeoutSpecified = TRUE;
658     }
659 
660     /* Set the length and copy the name */
661     WaitPipeInfo->NameLength = NewName.Length;
662     RtlCopyMemory(WaitPipeInfo->Name, NewName.Buffer, NewName.Length);
663 
664     /* Get rid of the full name */
665     RtlFreeUnicodeString(&NamedPipeName);
666 
667     /* Let NPFS know of our request */
668     Status = NtFsControlFile(FileHandle,
669                              NULL,
670                              NULL,
671                              NULL,
672                              &IoStatusBlock,
673                              FSCTL_PIPE_WAIT,
674                              WaitPipeInfo,
675                              WaitPipeInfoSize,
676                              NULL,
677                              0);
678 
679     /* Free our pipe info data and close the handle */
680     RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo);
681     NtClose(FileHandle);
682 
683     /* Check the status */
684     if (!NT_SUCCESS(Status))
685     {
686         /* Failure to wait on the pipe */
687         WARN("Status: %lx\n", Status);
688         BaseSetLastNTError(Status);
689         return FALSE;
690      }
691 
692     /* Success */
693     return TRUE;
694 }
695 
696 /*
697  * @implemented
698  */
699 BOOL
700 WINAPI
701 ConnectNamedPipe(IN HANDLE hNamedPipe,
702                  IN LPOVERLAPPED lpOverlapped)
703 {
704     NTSTATUS Status;
705 
706     if (lpOverlapped != NULL)
707     {
708         PVOID ApcContext;
709 
710         lpOverlapped->Internal = STATUS_PENDING;
711         ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
712 
713         Status = NtFsControlFile(hNamedPipe,
714                                  lpOverlapped->hEvent,
715                                  NULL,
716                                  ApcContext,
717                                  (PIO_STATUS_BLOCK)lpOverlapped,
718                                  FSCTL_PIPE_LISTEN,
719                                  NULL,
720                                  0,
721                                  NULL,
722                                  0);
723 
724         /* return FALSE in case of failure and pending operations! */
725         if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
726         {
727             BaseSetLastNTError(Status);
728             return FALSE;
729         }
730     }
731     else
732     {
733         IO_STATUS_BLOCK Iosb;
734 
735         Status = NtFsControlFile(hNamedPipe,
736                                  NULL,
737                                  NULL,
738                                  NULL,
739                                  &Iosb,
740                                  FSCTL_PIPE_LISTEN,
741                                  NULL,
742                                  0,
743                                  NULL,
744                                  0);
745 
746         /* wait in case operation is pending */
747         if (Status == STATUS_PENDING)
748         {
749              Status = NtWaitForSingleObject(hNamedPipe,
750                                             FALSE,
751                                             NULL);
752              if (NT_SUCCESS(Status))
753              {
754                  Status = Iosb.Status;
755              }
756         }
757 
758         if (!NT_SUCCESS(Status))
759         {
760             BaseSetLastNTError(Status);
761             return FALSE;
762         }
763     }
764 
765     return TRUE;
766 }
767 
768 
769 /*
770  * @implemented
771  */
772 BOOL
773 WINAPI
774 SetNamedPipeHandleState(HANDLE hNamedPipe,
775                         LPDWORD lpMode,
776                         LPDWORD lpMaxCollectionCount,
777                         LPDWORD lpCollectDataTimeout)
778 {
779     IO_STATUS_BLOCK Iosb;
780     NTSTATUS Status;
781 
782     /* Check if the Mode is being changed */
783     if (lpMode)
784     {
785         FILE_PIPE_INFORMATION Settings;
786 
787         /* Set the Completion Mode */
788         Settings.CompletionMode = (*lpMode & PIPE_NOWAIT) ?
789                                   FILE_PIPE_COMPLETE_OPERATION : FILE_PIPE_QUEUE_OPERATION;
790 
791         /* Set the Read Mode */
792         Settings.ReadMode = (*lpMode & PIPE_READMODE_MESSAGE) ?
793                             FILE_PIPE_MESSAGE_MODE : FILE_PIPE_BYTE_STREAM_MODE;
794 
795         /* Send the changes to the Driver */
796         Status = NtSetInformationFile(hNamedPipe,
797                                       &Iosb,
798                                       &Settings,
799                                       sizeof(Settings),
800                                       FilePipeInformation);
801         if (!NT_SUCCESS(Status))
802         {
803             BaseSetLastNTError(Status);
804             return FALSE;
805         }
806     }
807 
808     /* Check if the Collection count or Timeout are being changed */
809     if (lpMaxCollectionCount || lpCollectDataTimeout)
810     {
811         FILE_PIPE_REMOTE_INFORMATION RemoteSettings;
812 
813         /* Setting one without the other would delete it, so we read old one */
814         if (!lpMaxCollectionCount || !lpCollectDataTimeout)
815         {
816             Status = NtQueryInformationFile(hNamedPipe,
817                                             &Iosb,
818                                             &RemoteSettings,
819                                             sizeof(RemoteSettings),
820                                             FilePipeRemoteInformation);
821             if (!NT_SUCCESS(Status))
822             {
823                 BaseSetLastNTError(Status);
824                 return FALSE;
825             }
826         }
827 
828         /* Now set the new settings */
829         RemoteSettings.MaximumCollectionCount = (lpMaxCollectionCount) ?
830                                                 *lpMaxCollectionCount :
831                                                 RemoteSettings.MaximumCollectionCount;
832         if (lpCollectDataTimeout)
833         {
834             /* Convert it to Quad */
835             RemoteSettings.CollectDataTime.QuadPart = *lpCollectDataTimeout * -10000LL;
836         }
837 
838         /* Tell the driver to change them */
839         Status = NtSetInformationFile(hNamedPipe,
840                                       &Iosb,
841                                       &RemoteSettings,
842                                       sizeof(RemoteSettings),
843                                       FilePipeRemoteInformation);
844         if (!NT_SUCCESS(Status))
845         {
846             BaseSetLastNTError(Status);
847             return FALSE;
848         }
849     }
850 
851     return TRUE;
852 }
853 
854 
855 /*
856  * @implemented
857  */
858 BOOL
859 WINAPI
860 CallNamedPipeA(LPCSTR lpNamedPipeName,
861                LPVOID lpInBuffer,
862                DWORD nInBufferSize,
863                LPVOID lpOutBuffer,
864                DWORD nOutBufferSize,
865                LPDWORD lpBytesRead,
866                DWORD nTimeOut)
867 {
868     PUNICODE_STRING PipeName = &NtCurrentTeb()->StaticUnicodeString;
869     ANSI_STRING AnsiPipe;
870 
871     /* Initialize the string as ANSI_STRING and convert to Unicode */
872     RtlInitAnsiString(&AnsiPipe, (LPSTR)lpNamedPipeName);
873     RtlAnsiStringToUnicodeString(PipeName, &AnsiPipe, FALSE);
874 
875     /* Call the Unicode function */
876     return CallNamedPipeW(PipeName->Buffer,
877                           lpInBuffer,
878                           nInBufferSize,
879                           lpOutBuffer,
880                           nOutBufferSize,
881                           lpBytesRead,
882                           nTimeOut);
883 }
884 
885 
886 /*
887  * @implemented
888  */
889 BOOL
890 WINAPI
891 CallNamedPipeW(LPCWSTR lpNamedPipeName,
892                LPVOID lpInBuffer,
893                DWORD nInBufferSize,
894                LPVOID lpOutBuffer,
895                DWORD nOutBufferSize,
896                LPDWORD lpBytesRead,
897                DWORD nTimeOut)
898 {
899     HANDLE hPipe;
900     BOOL bRetry = TRUE;
901     BOOL bError;
902     DWORD dwPipeMode;
903 
904     while (TRUE)
905     {
906         /* Try creating it */
907         hPipe = CreateFileW(lpNamedPipeName,
908                             GENERIC_READ | GENERIC_WRITE,
909                             FILE_SHARE_READ | FILE_SHARE_WRITE,
910                             NULL,
911                             OPEN_EXISTING,
912                             FILE_ATTRIBUTE_NORMAL,
913                             NULL);
914 
915         /* Success, break out */
916         if (hPipe != INVALID_HANDLE_VALUE)
917             break;
918 
919         /* Already tried twice, give up */
920         if (bRetry == FALSE)
921             return FALSE;
922 
923         /* Wait on it */
924         WaitNamedPipeW(lpNamedPipeName, nTimeOut);
925 
926         /* Get ready to try again */
927         bRetry = FALSE;
928     }
929 
930     /* Set the pipe mode */
931     dwPipeMode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
932     bError = SetNamedPipeHandleState(hPipe, &dwPipeMode, NULL, NULL);
933     if (!bError)
934     {
935         /* Couldn't change state, fail */
936         CloseHandle(hPipe);
937         return FALSE;
938     }
939 
940     /* Do the transact */
941     bError = TransactNamedPipe(hPipe,
942                                lpInBuffer,
943                                nInBufferSize,
944                                lpOutBuffer,
945                                nOutBufferSize,
946                                lpBytesRead,
947                                NULL);
948 
949     /* Close the handle */
950     CloseHandle(hPipe);
951 
952     return bError;
953 }
954 
955 
956 /*
957  * @implemented
958  */
959 BOOL
960 WINAPI
961 DisconnectNamedPipe(HANDLE hNamedPipe)
962 {
963     IO_STATUS_BLOCK Iosb;
964     NTSTATUS Status;
965 
966     /* Send the FSCTL to the driver */
967     Status = NtFsControlFile(hNamedPipe,
968                              NULL,
969                              NULL,
970                              NULL,
971                              &Iosb,
972                              FSCTL_PIPE_DISCONNECT,
973                              NULL,
974                              0,
975                              NULL,
976                              0);
977     if (Status == STATUS_PENDING)
978     {
979         /* Wait on NPFS to finish and get updated status */
980         Status = NtWaitForSingleObject(hNamedPipe, FALSE, NULL);
981         if (NT_SUCCESS(Status))
982             Status = Iosb.Status;
983     }
984 
985     /* Check for error */
986     if (!NT_SUCCESS(Status))
987     {
988         /* Fail */
989         BaseSetLastNTError(Status);
990         return FALSE;
991     }
992 
993     return TRUE;
994 }
995 
996 
997 /*
998  * @unimplemented
999  */
1000 BOOL
1001 WINAPI
1002 GetNamedPipeHandleStateW(HANDLE hNamedPipe,
1003                          LPDWORD lpState,
1004                          LPDWORD lpCurInstances,
1005                          LPDWORD lpMaxCollectionCount,
1006                          LPDWORD lpCollectDataTimeout,
1007                          LPWSTR lpUserName,
1008                          DWORD nMaxUserNameSize)
1009 {
1010     IO_STATUS_BLOCK StatusBlock;
1011     NTSTATUS Status;
1012 
1013     if (lpState != NULL)
1014     {
1015         FILE_PIPE_INFORMATION PipeInfo;
1016 
1017         Status = NtQueryInformationFile(hNamedPipe,
1018                                         &StatusBlock,
1019                                         &PipeInfo,
1020                                         sizeof(PipeInfo),
1021                                         FilePipeInformation);
1022         if (!NT_SUCCESS(Status))
1023         {
1024             BaseSetLastNTError(Status);
1025             return FALSE;
1026         }
1027 
1028         *lpState = ((PipeInfo.CompletionMode != FILE_PIPE_QUEUE_OPERATION) ? PIPE_NOWAIT : PIPE_WAIT);
1029         *lpState |= ((PipeInfo.ReadMode != FILE_PIPE_BYTE_STREAM_MODE) ? PIPE_READMODE_MESSAGE : PIPE_READMODE_BYTE);
1030     }
1031 
1032     if (lpCurInstances != NULL)
1033     {
1034         FILE_PIPE_LOCAL_INFORMATION LocalInfo;
1035 
1036         Status = NtQueryInformationFile(hNamedPipe,
1037                                         &StatusBlock,
1038                                         &LocalInfo,
1039                                         sizeof(LocalInfo),
1040                                         FilePipeLocalInformation);
1041         if (!NT_SUCCESS(Status))
1042         {
1043             BaseSetLastNTError(Status);
1044             return FALSE;
1045         }
1046 
1047         *lpCurInstances = min(LocalInfo.CurrentInstances, PIPE_UNLIMITED_INSTANCES);
1048     }
1049 
1050     if (lpMaxCollectionCount != NULL || lpCollectDataTimeout != NULL)
1051     {
1052         FILE_PIPE_REMOTE_INFORMATION RemoteInfo;
1053 
1054         Status = NtQueryInformationFile(hNamedPipe,
1055                                         &StatusBlock,
1056                                         &RemoteInfo,
1057                                         sizeof(RemoteInfo),
1058                                         FilePipeRemoteInformation);
1059         if (!NT_SUCCESS(Status))
1060         {
1061             BaseSetLastNTError(Status);
1062             return FALSE;
1063         }
1064 
1065         if (lpMaxCollectionCount != NULL)
1066         {
1067             *lpMaxCollectionCount = RemoteInfo.MaximumCollectionCount;
1068         }
1069 
1070         if (lpCollectDataTimeout != NULL)
1071         {
1072             LARGE_INTEGER CollectDataTime;
1073 
1074             /* Convert time and return it */
1075             RemoteInfo.CollectDataTime.QuadPart *= -1;
1076             CollectDataTime = RtlExtendedLargeIntegerDivide(RemoteInfo.CollectDataTime, 10000, NULL);
1077             /* In case of overflow, just return MAX - 1 */
1078             if (CollectDataTime.HighPart != 0)
1079             {
1080                 *lpCollectDataTimeout = -2;
1081             }
1082             else
1083             {
1084                 *lpCollectDataTimeout = CollectDataTime.LowPart;
1085             }
1086         }
1087     }
1088 
1089     if (lpUserName != NULL)
1090     {
1091         return NpGetUserNamep(hNamedPipe, lpUserName, nMaxUserNameSize);
1092     }
1093 
1094     return TRUE;
1095 }
1096 
1097 
1098 /*
1099  * @implemented
1100  */
1101 BOOL
1102 WINAPI
1103 GetNamedPipeHandleStateA(HANDLE hNamedPipe,
1104                          LPDWORD lpState,
1105                          LPDWORD lpCurInstances,
1106                          LPDWORD lpMaxCollectionCount,
1107                          LPDWORD lpCollectDataTimeout,
1108                          LPSTR lpUserName,
1109                          DWORD nMaxUserNameSize)
1110 {
1111     UNICODE_STRING UserNameW = { 0, 0, NULL };
1112     ANSI_STRING UserNameA;
1113     BOOL Ret;
1114 
1115     if (lpUserName != NULL)
1116     {
1117         UserNameW.MaximumLength = (USHORT)nMaxUserNameSize * sizeof(WCHAR);
1118         UserNameW.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, UserNameW.MaximumLength);
1119         if (UserNameW.Buffer == NULL)
1120         {
1121             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1122             return FALSE;
1123         }
1124 
1125         UserNameA.Buffer = lpUserName;
1126         UserNameA.Length = 0;
1127         UserNameA.MaximumLength = (USHORT)nMaxUserNameSize;
1128     }
1129 
1130     Ret = GetNamedPipeHandleStateW(hNamedPipe,
1131                                    lpState,
1132                                    lpCurInstances,
1133                                    lpMaxCollectionCount,
1134                                    lpCollectDataTimeout,
1135                                    UserNameW.Buffer,
1136                                    nMaxUserNameSize);
1137     if (Ret && lpUserName != NULL)
1138     {
1139         NTSTATUS Status;
1140 
1141         RtlInitUnicodeString(&UserNameW, UserNameW.Buffer);
1142         Status = RtlUnicodeStringToAnsiString(&UserNameA, &UserNameW, FALSE);
1143         if (!NT_SUCCESS(Status))
1144         {
1145             BaseSetLastNTError(Status);
1146             Ret = FALSE;
1147         }
1148     }
1149 
1150     if (UserNameW.Buffer != NULL)
1151     {
1152         RtlFreeHeap(RtlGetProcessHeap(), 0, UserNameW.Buffer);
1153     }
1154 
1155     return Ret;
1156 }
1157 
1158 
1159 /*
1160  * @implemented
1161  */
1162 BOOL
1163 WINAPI
1164 GetNamedPipeInfo(HANDLE hNamedPipe,
1165                  LPDWORD lpFlags,
1166                  LPDWORD lpOutBufferSize,
1167                  LPDWORD lpInBufferSize,
1168                  LPDWORD lpMaxInstances)
1169 {
1170     FILE_PIPE_LOCAL_INFORMATION PipeLocalInformation;
1171     IO_STATUS_BLOCK StatusBlock;
1172     NTSTATUS Status;
1173 
1174     Status = NtQueryInformationFile(hNamedPipe,
1175                                     &StatusBlock,
1176                                     &PipeLocalInformation,
1177                                     sizeof(PipeLocalInformation),
1178                                     FilePipeLocalInformation);
1179     if (!NT_SUCCESS(Status))
1180     {
1181         BaseSetLastNTError(Status);
1182         return FALSE;
1183     }
1184 
1185     if (lpFlags != NULL)
1186     {
1187         *lpFlags = (PipeLocalInformation.NamedPipeEnd == FILE_PIPE_SERVER_END) ? PIPE_SERVER_END : PIPE_CLIENT_END;
1188         *lpFlags |= (PipeLocalInformation.NamedPipeType == FILE_PIPE_MESSAGE_TYPE) ? PIPE_TYPE_MESSAGE : PIPE_TYPE_BYTE;
1189     }
1190 
1191     if (lpOutBufferSize != NULL)
1192         *lpOutBufferSize = PipeLocalInformation.OutboundQuota;
1193 
1194     if (lpInBufferSize != NULL)
1195         *lpInBufferSize = PipeLocalInformation.InboundQuota;
1196 
1197     if (lpMaxInstances != NULL)
1198     {
1199         if (PipeLocalInformation.MaximumInstances >= 255)
1200             *lpMaxInstances = PIPE_UNLIMITED_INSTANCES;
1201         else
1202             *lpMaxInstances = PipeLocalInformation.MaximumInstances;
1203     }
1204 
1205     return TRUE;
1206 }
1207 
1208 
1209 /*
1210  * @implemented
1211  */
1212 BOOL
1213 WINAPI
1214 PeekNamedPipe(HANDLE hNamedPipe,
1215               LPVOID lpBuffer,
1216               DWORD nBufferSize,
1217               LPDWORD lpBytesRead,
1218               LPDWORD lpTotalBytesAvail,
1219               LPDWORD lpBytesLeftThisMessage)
1220 {
1221     PFILE_PIPE_PEEK_BUFFER Buffer;
1222     IO_STATUS_BLOCK Iosb;
1223     ULONG BufferSize;
1224     ULONG BytesRead;
1225     NTSTATUS Status;
1226 
1227     /* Calculate the buffer space that we'll need and allocate it */
1228     BufferSize = FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[nBufferSize]);
1229     Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
1230     if (Buffer == NULL)
1231     {
1232         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1233         return FALSE;
1234     }
1235 
1236     /* Tell the driver to seek */
1237     Status = NtFsControlFile(hNamedPipe,
1238                              NULL,
1239                              NULL,
1240                              NULL,
1241                              &Iosb,
1242                              FSCTL_PIPE_PEEK,
1243                              NULL,
1244                              0,
1245                              Buffer,
1246                              BufferSize);
1247     if (Status == STATUS_PENDING)
1248     {
1249         /* Wait for npfs to be done, and update the status */
1250         Status = NtWaitForSingleObject(hNamedPipe, FALSE, NULL);
1251         if (NT_SUCCESS(Status))
1252             Status = Iosb.Status;
1253     }
1254 
1255     /* Overflow is success for us */
1256     if (Status == STATUS_BUFFER_OVERFLOW)
1257         Status = STATUS_SUCCESS;
1258 
1259     /* If we failed */
1260     if (!NT_SUCCESS(Status))
1261     {
1262         /* Free the buffer and return failure */
1263         RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1264         BaseSetLastNTError(Status);
1265         return FALSE;
1266     }
1267 
1268     /* Check if caller requested bytes available */
1269     if (lpTotalBytesAvail)
1270     {
1271         /* Return bytes available */
1272         *lpTotalBytesAvail = Buffer->ReadDataAvailable;
1273     }
1274 
1275     /* Calculate the bytes returned, minus our structure overhead */
1276     BytesRead = (ULONG)(Iosb.Information -
1277                         FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]));
1278     ASSERT(BytesRead <= nBufferSize);
1279 
1280     /* Check if caller requested bytes read */
1281     if (lpBytesRead)
1282     {
1283         /* Return the bytes read */
1284         *lpBytesRead = BytesRead;
1285     }
1286 
1287     /* Check if caller requested bytes left */
1288     if (lpBytesLeftThisMessage)
1289     {
1290         /* Calculate total minus what we returned and our structure overhead */
1291         *lpBytesLeftThisMessage = Buffer->MessageLength - BytesRead;
1292     }
1293 
1294     /* Check if the caller wanted to see the actual data */
1295     if (lpBuffer)
1296     {
1297         /* Give him what he wants */
1298         RtlCopyMemory(lpBuffer,
1299                       Buffer->Data,
1300                       BytesRead);
1301     }
1302 
1303     /* Free the buffer */
1304     RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1305 
1306     return TRUE;
1307 }
1308 
1309 
1310 /*
1311  * @implemented
1312  */
1313 BOOL
1314 WINAPI
1315 TransactNamedPipe(IN HANDLE hNamedPipe,
1316                   IN LPVOID lpInBuffer,
1317                   IN DWORD nInBufferSize,
1318                   OUT LPVOID lpOutBuffer,
1319                   IN DWORD nOutBufferSize,
1320                   OUT LPDWORD lpBytesRead  OPTIONAL,
1321                   IN LPOVERLAPPED lpOverlapped  OPTIONAL)
1322 {
1323     NTSTATUS Status;
1324 
1325     if (lpBytesRead != NULL)
1326     {
1327         *lpBytesRead = 0;
1328     }
1329 
1330     if (lpOverlapped != NULL)
1331     {
1332         PVOID ApcContext;
1333 
1334         ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
1335         lpOverlapped->Internal = STATUS_PENDING;
1336 
1337         Status = NtFsControlFile(hNamedPipe,
1338                                  lpOverlapped->hEvent,
1339                                  NULL,
1340                                  ApcContext,
1341                                  (PIO_STATUS_BLOCK)lpOverlapped,
1342                                  FSCTL_PIPE_TRANSCEIVE,
1343                                  lpInBuffer,
1344                                  nInBufferSize,
1345                                  lpOutBuffer,
1346                                  nOutBufferSize);
1347         if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
1348         {
1349             BaseSetLastNTError(Status);
1350             return FALSE;
1351         }
1352 
1353         if (lpBytesRead != NULL)
1354         {
1355             *lpBytesRead = lpOverlapped->InternalHigh;
1356         }
1357     }
1358     else
1359     {
1360         IO_STATUS_BLOCK Iosb;
1361 
1362         Status = NtFsControlFile(hNamedPipe,
1363                                  NULL,
1364                                  NULL,
1365                                  NULL,
1366                                  &Iosb,
1367                                  FSCTL_PIPE_TRANSCEIVE,
1368                                  lpInBuffer,
1369                                  nInBufferSize,
1370                                  lpOutBuffer,
1371                                  nOutBufferSize);
1372         if (Status == STATUS_PENDING)
1373         {
1374             Status = NtWaitForSingleObject(hNamedPipe,
1375                                            FALSE,
1376                                            NULL);
1377             if (NT_SUCCESS(Status))
1378                 Status = Iosb.Status;
1379         }
1380 
1381         if (NT_SUCCESS(Status))
1382         {
1383             /* lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
1384                check that case either and crashes (only after the operation
1385                completed) */
1386             *lpBytesRead = Iosb.Information;
1387         }
1388         else
1389         {
1390             BaseSetLastNTError(Status);
1391             return FALSE;
1392         }
1393     }
1394 
1395     return TRUE;
1396 }
1397 
1398 /* EOF */
1399