[KERNEL32] Implement NpGetUserNamep()
[reactos.git] / dll / win32 / kernel32 / client / file / npipe.c
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 = GetProcAddress(hAdvapi, "RevertToSelf");
49 pGetUserNameW = GetProcAddress(hAdvapi, "GetUserNameW");
50 pImpersonateNamedPipeClient = 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(HANDLE));
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.%08x.%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 PFILE_PIPE_WAIT_FOR_BUFFER WaitPipeInfo;
472
473 /* Start by making a unicode string of the name */
474 TRACE("Sent path: %S\n", lpNamedPipeName);
475 if (!RtlCreateUnicodeString(&NamedPipeName, lpNamedPipeName))
476 {
477 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
478 return FALSE;
479 }
480 NameLength = NamedPipeName.Length / sizeof(WCHAR);
481
482 /* All slashes must become backslashes */
483 for (i = 0; i < NameLength; i++)
484 {
485 /* Check and convert */
486 if (NamedPipeName.Buffer[i] == L'/') NamedPipeName.Buffer[i] = L'\\';
487 }
488
489 /* Find the path type of the name we were given */
490 NewName = NamedPipeName;
491 Type = RtlDetermineDosPathNameType_U(lpNamedPipeName);
492
493 /* Check if this was a device path, ie : "\\.\pipe\name" */
494 if (Type == RtlPathTypeLocalDevice)
495 {
496 /* Make sure it's a valid prefix */
497 RtlInitUnicodeString(&PipePrefix, L"\\\\.\\pipe\\");
498 if (!RtlPrefixUnicodeString(&PipePrefix, &NewName, TRUE))
499 {
500 /* The name is invalid */
501 WARN("Invalid name!\n");
502 RtlFreeUnicodeString(&NamedPipeName);
503 BaseSetLastNTError(STATUS_OBJECT_PATH_SYNTAX_BAD);
504 return FALSE;
505 }
506
507 /* Move past it */
508 NewName.Buffer += PipePrefix.Length / sizeof(WCHAR);
509 NewName.Length -= PipePrefix.Length;
510 NewName.MaximumLength -= PipePrefix.Length;
511
512 /* Initialize the Dos Devices name */
513 TRACE("NewName: %wZ\n", &NewName);
514 RtlInitUnicodeString(&DevicePath, L"\\DosDevices\\pipe\\");
515 }
516 else if (Type == RtlPathTypeUncAbsolute)
517 {
518 /* The path is \\server\\pipe\name; find the pipename itself */
519 p = &NewName.Buffer[2];
520
521 /* First loop to get past the server name */
522 do
523 {
524 /* Check if this is a backslash */
525 if (*p == L'\\') break;
526
527 /* Check next */
528 p++;
529 } while (*p);
530
531 /* Now make sure the full name contains "pipe\" */
532 if ((*p) && !(_wcsnicmp(p + 1, L"pipe\\", sizeof("pipe\\") - sizeof(ANSI_NULL))))
533 {
534 /* Get to the pipe name itself now */
535 p += sizeof("pipe\\") - sizeof(ANSI_NULL);
536 }
537 else
538 {
539 /* The name is invalid */
540 WARN("Invalid name!\n");
541 RtlFreeUnicodeString(&NamedPipeName);
542 BaseSetLastNTError(STATUS_OBJECT_PATH_SYNTAX_BAD);
543 return FALSE;
544 }
545
546 /* FIXME: Open \DosDevices\Unc\Server\Pipe\Name */
547 }
548 else
549 {
550 WARN("Invalid path type\n");
551 RtlFreeUnicodeString(&NamedPipeName);
552 BaseSetLastNTError(STATUS_OBJECT_PATH_SYNTAX_BAD);
553 return FALSE;
554 }
555
556 /* Now calculate the total length of the structure and allocate it */
557 WaitPipeInfoSize = FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name[0]) +
558 NewName.Length;
559 WaitPipeInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, WaitPipeInfoSize);
560 if (WaitPipeInfo == NULL)
561 {
562 RtlFreeUnicodeString(&NamedPipeName);
563 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
564 return FALSE;
565 }
566
567 /* Initialize the object attributes */
568 TRACE("Opening: %wZ\n", &DevicePath);
569 InitializeObjectAttributes(&ObjectAttributes,
570 &DevicePath,
571 OBJ_CASE_INSENSITIVE,
572 NULL,
573 NULL);
574
575 /* Open the path */
576 Status = NtOpenFile(&FileHandle,
577 FILE_READ_ATTRIBUTES | SYNCHRONIZE,
578 &ObjectAttributes,
579 &IoStatusBlock,
580 FILE_SHARE_READ | FILE_SHARE_WRITE,
581 FILE_SYNCHRONOUS_IO_NONALERT);
582 if (!NT_SUCCESS(Status))
583 {
584 /* Fail; couldn't open */
585 WARN("Status: %lx\n", Status);
586 RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo);
587 RtlFreeUnicodeString(&NamedPipeName);
588 BaseSetLastNTError(Status);
589 return FALSE;
590 }
591
592 /* Check what timeout we got */
593 if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT)
594 {
595 /* Don't use a timeout */
596 WaitPipeInfo->TimeoutSpecified = FALSE;
597 }
598 else
599 {
600 /* Check if we should wait forever */
601 if (nTimeOut == NMPWAIT_WAIT_FOREVER)
602 {
603 /* Set the max */
604 WaitPipeInfo->Timeout.LowPart = 0;
605 WaitPipeInfo->Timeout.HighPart = 0x80000000;
606 }
607 else
608 {
609 /* Convert to NT format */
610 WaitPipeInfo->Timeout.QuadPart = nTimeOut * -10000LL;
611 }
612
613 /* In both cases, we do have a timeout */
614 WaitPipeInfo->TimeoutSpecified = TRUE;
615 }
616
617 /* Set the length and copy the name */
618 WaitPipeInfo->NameLength = NewName.Length;
619 RtlCopyMemory(WaitPipeInfo->Name, NewName.Buffer, NewName.Length);
620
621 /* Get rid of the full name */
622 RtlFreeUnicodeString(&NamedPipeName);
623
624 /* Let NPFS know of our request */
625 Status = NtFsControlFile(FileHandle,
626 NULL,
627 NULL,
628 NULL,
629 &IoStatusBlock,
630 FSCTL_PIPE_WAIT,
631 WaitPipeInfo,
632 WaitPipeInfoSize,
633 NULL,
634 0);
635
636 /* Free our pipe info data and close the handle */
637 RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo);
638 NtClose(FileHandle);
639
640 /* Check the status */
641 if (!NT_SUCCESS(Status))
642 {
643 /* Failure to wait on the pipe */
644 WARN("Status: %lx\n", Status);
645 BaseSetLastNTError(Status);
646 return FALSE;
647 }
648
649 /* Success */
650 return TRUE;
651 }
652
653 /*
654 * @implemented
655 */
656 BOOL
657 WINAPI
658 ConnectNamedPipe(IN HANDLE hNamedPipe,
659 IN LPOVERLAPPED lpOverlapped)
660 {
661 NTSTATUS Status;
662
663 if (lpOverlapped != NULL)
664 {
665 PVOID ApcContext;
666
667 lpOverlapped->Internal = STATUS_PENDING;
668 ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
669
670 Status = NtFsControlFile(hNamedPipe,
671 lpOverlapped->hEvent,
672 NULL,
673 ApcContext,
674 (PIO_STATUS_BLOCK)lpOverlapped,
675 FSCTL_PIPE_LISTEN,
676 NULL,
677 0,
678 NULL,
679 0);
680
681 /* return FALSE in case of failure and pending operations! */
682 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
683 {
684 BaseSetLastNTError(Status);
685 return FALSE;
686 }
687 }
688 else
689 {
690 IO_STATUS_BLOCK Iosb;
691
692 Status = NtFsControlFile(hNamedPipe,
693 NULL,
694 NULL,
695 NULL,
696 &Iosb,
697 FSCTL_PIPE_LISTEN,
698 NULL,
699 0,
700 NULL,
701 0);
702
703 /* wait in case operation is pending */
704 if (Status == STATUS_PENDING)
705 {
706 Status = NtWaitForSingleObject(hNamedPipe,
707 FALSE,
708 NULL);
709 if (NT_SUCCESS(Status))
710 {
711 Status = Iosb.Status;
712 }
713 }
714
715 if (!NT_SUCCESS(Status))
716 {
717 BaseSetLastNTError(Status);
718 return FALSE;
719 }
720 }
721
722 return TRUE;
723 }
724
725
726 /*
727 * @implemented
728 */
729 BOOL
730 WINAPI
731 SetNamedPipeHandleState(HANDLE hNamedPipe,
732 LPDWORD lpMode,
733 LPDWORD lpMaxCollectionCount,
734 LPDWORD lpCollectDataTimeout)
735 {
736 IO_STATUS_BLOCK Iosb;
737 NTSTATUS Status;
738
739 /* Check if the Mode is being changed */
740 if (lpMode)
741 {
742 FILE_PIPE_INFORMATION Settings;
743
744 /* Set the Completion Mode */
745 Settings.CompletionMode = (*lpMode & PIPE_NOWAIT) ?
746 FILE_PIPE_COMPLETE_OPERATION : FILE_PIPE_QUEUE_OPERATION;
747
748 /* Set the Read Mode */
749 Settings.ReadMode = (*lpMode & PIPE_READMODE_MESSAGE) ?
750 FILE_PIPE_MESSAGE_MODE: FILE_PIPE_BYTE_STREAM_MODE;
751
752 /* Send the changes to the Driver */
753 Status = NtSetInformationFile(hNamedPipe,
754 &Iosb,
755 &Settings,
756 sizeof(FILE_PIPE_INFORMATION),
757 FilePipeInformation);
758 if (!NT_SUCCESS(Status))
759 {
760 BaseSetLastNTError(Status);
761 return FALSE;
762 }
763 }
764
765 /* Check if the Collection count or Timeout are being changed */
766 if (lpMaxCollectionCount || lpCollectDataTimeout)
767 {
768 FILE_PIPE_REMOTE_INFORMATION RemoteSettings;
769
770 /* Setting one without the other would delete it, so we read old one */
771 if (!lpMaxCollectionCount || !lpCollectDataTimeout)
772 {
773 Status = NtQueryInformationFile(hNamedPipe,
774 &Iosb,
775 &RemoteSettings,
776 sizeof(FILE_PIPE_REMOTE_INFORMATION),
777 FilePipeRemoteInformation);
778 if (!NT_SUCCESS(Status))
779 {
780 BaseSetLastNTError(Status);
781 return FALSE;
782 }
783 }
784
785 /* Now set the new settings */
786 RemoteSettings.MaximumCollectionCount = (lpMaxCollectionCount) ?
787 *lpMaxCollectionCount :
788 RemoteSettings.MaximumCollectionCount;
789 if (lpCollectDataTimeout)
790 {
791 /* Convert it to Quad */
792 RemoteSettings.CollectDataTime.QuadPart = *lpCollectDataTimeout * -10000LL;
793 }
794
795 /* Tell the driver to change them */
796 Status = NtSetInformationFile(hNamedPipe,
797 &Iosb,
798 &RemoteSettings,
799 sizeof(FILE_PIPE_REMOTE_INFORMATION),
800 FilePipeRemoteInformation);
801 if (!NT_SUCCESS(Status))
802 {
803 BaseSetLastNTError(Status);
804 return FALSE;
805 }
806 }
807
808 return TRUE;
809 }
810
811
812 /*
813 * @implemented
814 */
815 BOOL
816 WINAPI
817 CallNamedPipeA(LPCSTR lpNamedPipeName,
818 LPVOID lpInBuffer,
819 DWORD nInBufferSize,
820 LPVOID lpOutBuffer,
821 DWORD nOutBufferSize,
822 LPDWORD lpBytesRead,
823 DWORD nTimeOut)
824 {
825 PUNICODE_STRING PipeName = &NtCurrentTeb()->StaticUnicodeString;
826 ANSI_STRING AnsiPipe;
827
828 /* Initialize the string as ANSI_STRING and convert to Unicode */
829 RtlInitAnsiString(&AnsiPipe, (LPSTR)lpNamedPipeName);
830 RtlAnsiStringToUnicodeString(PipeName, &AnsiPipe, FALSE);
831
832 /* Call the Unicode function */
833 return CallNamedPipeW(PipeName->Buffer,
834 lpInBuffer,
835 nInBufferSize,
836 lpOutBuffer,
837 nOutBufferSize,
838 lpBytesRead,
839 nTimeOut);
840 }
841
842
843 /*
844 * @implemented
845 */
846 BOOL
847 WINAPI
848 CallNamedPipeW(LPCWSTR lpNamedPipeName,
849 LPVOID lpInBuffer,
850 DWORD nInBufferSize,
851 LPVOID lpOutBuffer,
852 DWORD nOutBufferSize,
853 LPDWORD lpBytesRead,
854 DWORD nTimeOut)
855 {
856 HANDLE hPipe;
857 BOOL bRetry = TRUE;
858 BOOL bError;
859 DWORD dwPipeMode;
860
861 while (TRUE)
862 {
863 /* Try creating it */
864 hPipe = CreateFileW(lpNamedPipeName,
865 GENERIC_READ | GENERIC_WRITE,
866 FILE_SHARE_READ | FILE_SHARE_WRITE,
867 NULL,
868 OPEN_EXISTING,
869 FILE_ATTRIBUTE_NORMAL,
870 NULL);
871
872 /* Success, break out */
873 if (hPipe != INVALID_HANDLE_VALUE)
874 break;
875
876 /* Already tried twice, give up */
877 if (bRetry == FALSE)
878 return FALSE;
879
880 /* Wait on it */
881 WaitNamedPipeW(lpNamedPipeName, nTimeOut);
882
883 /* Get ready to try again */
884 bRetry = FALSE;
885 }
886
887 /* Set the pipe mode */
888 dwPipeMode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
889 bError = SetNamedPipeHandleState(hPipe, &dwPipeMode, NULL, NULL);
890 if (!bError)
891 {
892 /* Couldn't change state, fail */
893 CloseHandle(hPipe);
894 return FALSE;
895 }
896
897 /* Do the transact */
898 bError = TransactNamedPipe(hPipe,
899 lpInBuffer,
900 nInBufferSize,
901 lpOutBuffer,
902 nOutBufferSize,
903 lpBytesRead,
904 NULL);
905
906 /* Close the handle */
907 CloseHandle(hPipe);
908
909 return bError;
910 }
911
912
913 /*
914 * @implemented
915 */
916 BOOL
917 WINAPI
918 DisconnectNamedPipe(HANDLE hNamedPipe)
919 {
920 IO_STATUS_BLOCK Iosb;
921 NTSTATUS Status;
922
923 /* Send the FSCTL to the driver */
924 Status = NtFsControlFile(hNamedPipe,
925 NULL,
926 NULL,
927 NULL,
928 &Iosb,
929 FSCTL_PIPE_DISCONNECT,
930 NULL,
931 0,
932 NULL,
933 0);
934 if (Status == STATUS_PENDING)
935 {
936 /* Wait on NPFS to finish and get updated status */
937 Status = NtWaitForSingleObject(hNamedPipe, FALSE, NULL);
938 if (NT_SUCCESS(Status))
939 Status = Iosb.Status;
940 }
941
942 /* Check for error */
943 if (!NT_SUCCESS(Status))
944 {
945 /* Fail */
946 BaseSetLastNTError(Status);
947 return FALSE;
948 }
949
950 return TRUE;
951 }
952
953
954 /*
955 * @unimplemented
956 */
957 BOOL
958 WINAPI
959 GetNamedPipeHandleStateW(HANDLE hNamedPipe,
960 LPDWORD lpState,
961 LPDWORD lpCurInstances,
962 LPDWORD lpMaxCollectionCount,
963 LPDWORD lpCollectDataTimeout,
964 LPWSTR lpUserName,
965 DWORD nMaxUserNameSize)
966 {
967 IO_STATUS_BLOCK StatusBlock;
968 NTSTATUS Status;
969
970 if (lpState != NULL)
971 {
972 FILE_PIPE_INFORMATION PipeInfo;
973
974 Status = NtQueryInformationFile(hNamedPipe,
975 &StatusBlock,
976 &PipeInfo,
977 sizeof(FILE_PIPE_INFORMATION),
978 FilePipeInformation);
979 if (!NT_SUCCESS(Status))
980 {
981 BaseSetLastNTError(Status);
982 return FALSE;
983 }
984
985 *lpState = ((PipeInfo.CompletionMode != FILE_PIPE_QUEUE_OPERATION) ? PIPE_NOWAIT : PIPE_WAIT);
986 *lpState |= ((PipeInfo.ReadMode != FILE_PIPE_BYTE_STREAM_MODE) ? PIPE_READMODE_MESSAGE : PIPE_READMODE_BYTE);
987 }
988
989 if(lpCurInstances != NULL)
990 {
991 FILE_PIPE_LOCAL_INFORMATION LocalInfo;
992
993 Status = NtQueryInformationFile(hNamedPipe,
994 &StatusBlock,
995 &LocalInfo,
996 sizeof(FILE_PIPE_LOCAL_INFORMATION),
997 FilePipeLocalInformation);
998 if (!NT_SUCCESS(Status))
999 {
1000 BaseSetLastNTError(Status);
1001 return FALSE;
1002 }
1003
1004 *lpCurInstances = min(LocalInfo.CurrentInstances, PIPE_UNLIMITED_INSTANCES);
1005 }
1006
1007 if (lpMaxCollectionCount != NULL || lpCollectDataTimeout != NULL)
1008 {
1009 FILE_PIPE_REMOTE_INFORMATION RemoteInfo;
1010
1011 Status = NtQueryInformationFile(hNamedPipe,
1012 &StatusBlock,
1013 &RemoteInfo,
1014 sizeof(FILE_PIPE_REMOTE_INFORMATION),
1015 FilePipeRemoteInformation);
1016 if (!NT_SUCCESS(Status))
1017 {
1018 BaseSetLastNTError(Status);
1019 return FALSE;
1020 }
1021
1022 if (lpMaxCollectionCount != NULL)
1023 {
1024 *lpMaxCollectionCount = RemoteInfo.MaximumCollectionCount;
1025 }
1026
1027 if (lpCollectDataTimeout != NULL)
1028 {
1029 LARGE_INTEGER CollectDataTime;
1030
1031 /* Convert time and return it */
1032 RemoteInfo.CollectDataTime.QuadPart *= -1;
1033 CollectDataTime = RtlExtendedLargeIntegerDivide(RemoteInfo.CollectDataTime, 10000, NULL);
1034 /* In case of overflow, just return MAX - 1 */
1035 if (CollectDataTime.HighPart != 0)
1036 {
1037 *lpCollectDataTimeout = -2;
1038 }
1039 else
1040 {
1041 *lpCollectDataTimeout = CollectDataTime.LowPart;
1042 }
1043 }
1044 }
1045
1046 if (lpUserName != NULL)
1047 {
1048 return NpGetUserNamep(hNamedPipe, lpUserName, nMaxUserNameSize);
1049 }
1050
1051 return TRUE;
1052 }
1053
1054
1055 /*
1056 * @implemented
1057 */
1058 BOOL
1059 WINAPI
1060 GetNamedPipeHandleStateA(HANDLE hNamedPipe,
1061 LPDWORD lpState,
1062 LPDWORD lpCurInstances,
1063 LPDWORD lpMaxCollectionCount,
1064 LPDWORD lpCollectDataTimeout,
1065 LPSTR lpUserName,
1066 DWORD nMaxUserNameSize)
1067 {
1068 UNICODE_STRING UserNameW = { 0, 0, NULL };
1069 ANSI_STRING UserNameA;
1070 BOOL Ret;
1071
1072 if(lpUserName != NULL)
1073 {
1074 UserNameW.MaximumLength = (USHORT)nMaxUserNameSize * sizeof(WCHAR);
1075 UserNameW.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, UserNameW.MaximumLength);
1076 if (UserNameW.Buffer == NULL)
1077 {
1078 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1079 return FALSE;
1080 }
1081
1082 UserNameA.Buffer = lpUserName;
1083 UserNameA.Length = 0;
1084 UserNameA.MaximumLength = (USHORT)nMaxUserNameSize;
1085 }
1086
1087 Ret = GetNamedPipeHandleStateW(hNamedPipe,
1088 lpState,
1089 lpCurInstances,
1090 lpMaxCollectionCount,
1091 lpCollectDataTimeout,
1092 UserNameW.Buffer,
1093 nMaxUserNameSize);
1094 if (Ret && lpUserName != NULL)
1095 {
1096 NTSTATUS Status;
1097
1098 RtlInitUnicodeString(&UserNameW, UserNameW.Buffer);
1099 Status = RtlUnicodeStringToAnsiString(&UserNameA, &UserNameW, FALSE);
1100 if (!NT_SUCCESS(Status))
1101 {
1102 BaseSetLastNTError(Status);
1103 Ret = FALSE;
1104 }
1105 }
1106
1107 if (UserNameW.Buffer != NULL)
1108 {
1109 RtlFreeHeap(RtlGetProcessHeap(), 0, UserNameW.Buffer);
1110 }
1111
1112 return Ret;
1113 }
1114
1115
1116 /*
1117 * @implemented
1118 */
1119 BOOL
1120 WINAPI
1121 GetNamedPipeInfo(HANDLE hNamedPipe,
1122 LPDWORD lpFlags,
1123 LPDWORD lpOutBufferSize,
1124 LPDWORD lpInBufferSize,
1125 LPDWORD lpMaxInstances)
1126 {
1127 FILE_PIPE_LOCAL_INFORMATION PipeLocalInformation;
1128 IO_STATUS_BLOCK StatusBlock;
1129 NTSTATUS Status;
1130
1131 Status = NtQueryInformationFile(hNamedPipe,
1132 &StatusBlock,
1133 &PipeLocalInformation,
1134 sizeof(FILE_PIPE_LOCAL_INFORMATION),
1135 FilePipeLocalInformation);
1136 if (!NT_SUCCESS(Status))
1137 {
1138 BaseSetLastNTError(Status);
1139 return FALSE;
1140 }
1141
1142 if (lpFlags != NULL)
1143 {
1144 *lpFlags = (PipeLocalInformation.NamedPipeEnd == FILE_PIPE_SERVER_END) ? PIPE_SERVER_END : PIPE_CLIENT_END;
1145 *lpFlags |= (PipeLocalInformation.NamedPipeType == 1) ? PIPE_TYPE_MESSAGE : PIPE_TYPE_BYTE;
1146 }
1147
1148 if (lpOutBufferSize != NULL)
1149 *lpOutBufferSize = PipeLocalInformation.OutboundQuota;
1150
1151 if (lpInBufferSize != NULL)
1152 *lpInBufferSize = PipeLocalInformation.InboundQuota;
1153
1154 if (lpMaxInstances != NULL)
1155 {
1156 if (PipeLocalInformation.MaximumInstances >= 255)
1157 *lpMaxInstances = PIPE_UNLIMITED_INSTANCES;
1158 else
1159 *lpMaxInstances = PipeLocalInformation.MaximumInstances;
1160 }
1161
1162 return TRUE;
1163 }
1164
1165
1166 /*
1167 * @implemented
1168 */
1169 BOOL
1170 WINAPI
1171 PeekNamedPipe(HANDLE hNamedPipe,
1172 LPVOID lpBuffer,
1173 DWORD nBufferSize,
1174 LPDWORD lpBytesRead,
1175 LPDWORD lpTotalBytesAvail,
1176 LPDWORD lpBytesLeftThisMessage)
1177 {
1178 PFILE_PIPE_PEEK_BUFFER Buffer;
1179 IO_STATUS_BLOCK Iosb;
1180 ULONG BufferSize;
1181 ULONG BytesRead;
1182 NTSTATUS Status;
1183
1184 /* Calculate the buffer space that we'll need and allocate it */
1185 BufferSize = FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[nBufferSize]);
1186 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
1187 if (Buffer == NULL)
1188 {
1189 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1190 return FALSE;
1191 }
1192
1193 /* Tell the driver to seek */
1194 Status = NtFsControlFile(hNamedPipe,
1195 NULL,
1196 NULL,
1197 NULL,
1198 &Iosb,
1199 FSCTL_PIPE_PEEK,
1200 NULL,
1201 0,
1202 Buffer,
1203 BufferSize);
1204 if (Status == STATUS_PENDING)
1205 {
1206 /* Wait for npfs to be done, and update the status */
1207 Status = NtWaitForSingleObject(hNamedPipe, FALSE, NULL);
1208 if (NT_SUCCESS(Status))
1209 Status = Iosb.Status;
1210 }
1211
1212 /* Overflow is success for us */
1213 if (Status == STATUS_BUFFER_OVERFLOW)
1214 Status = STATUS_SUCCESS;
1215
1216 /* If we failed */
1217 if (!NT_SUCCESS(Status))
1218 {
1219 /* Free the buffer and return failure */
1220 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1221 BaseSetLastNTError(Status);
1222 return FALSE;
1223 }
1224
1225 /* Check if caller requested bytes available */
1226 if (lpTotalBytesAvail)
1227 {
1228 /* Return bytes available */
1229 *lpTotalBytesAvail = Buffer->ReadDataAvailable;
1230 }
1231
1232 /* Calculate the bytes returned, minus our structure overhead */
1233 BytesRead = (ULONG)(Iosb.Information -
1234 FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]));
1235 ASSERT(BytesRead <= nBufferSize);
1236
1237 /* Check if caller requested bytes read */
1238 if (lpBytesRead)
1239 {
1240 /* Return the bytes read */
1241 *lpBytesRead = BytesRead;
1242 }
1243
1244 /* Check if caller requested bytes left */
1245 if (lpBytesLeftThisMessage)
1246 {
1247 /* Calculate total minus what we returned and our structure overhead */
1248 *lpBytesLeftThisMessage = Buffer->MessageLength - BytesRead;
1249 }
1250
1251 /* Check if the caller wanted to see the actual data */
1252 if (lpBuffer)
1253 {
1254 /* Give him what he wants */
1255 RtlCopyMemory(lpBuffer,
1256 Buffer->Data,
1257 BytesRead);
1258 }
1259
1260 /* Free the buffer */
1261 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1262
1263 return TRUE;
1264 }
1265
1266
1267 /*
1268 * @implemented
1269 */
1270 BOOL
1271 WINAPI
1272 TransactNamedPipe(IN HANDLE hNamedPipe,
1273 IN LPVOID lpInBuffer,
1274 IN DWORD nInBufferSize,
1275 OUT LPVOID lpOutBuffer,
1276 IN DWORD nOutBufferSize,
1277 OUT LPDWORD lpBytesRead OPTIONAL,
1278 IN LPOVERLAPPED lpOverlapped OPTIONAL)
1279 {
1280 NTSTATUS Status;
1281
1282 if (lpBytesRead != NULL)
1283 {
1284 *lpBytesRead = 0;
1285 }
1286
1287 if (lpOverlapped != NULL)
1288 {
1289 PVOID ApcContext;
1290
1291 ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
1292 lpOverlapped->Internal = STATUS_PENDING;
1293
1294 Status = NtFsControlFile(hNamedPipe,
1295 lpOverlapped->hEvent,
1296 NULL,
1297 ApcContext,
1298 (PIO_STATUS_BLOCK)lpOverlapped,
1299 FSCTL_PIPE_TRANSCEIVE,
1300 lpInBuffer,
1301 nInBufferSize,
1302 lpOutBuffer,
1303 nOutBufferSize);
1304 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
1305 {
1306 BaseSetLastNTError(Status);
1307 return FALSE;
1308 }
1309
1310 if (lpBytesRead != NULL)
1311 {
1312 *lpBytesRead = lpOverlapped->InternalHigh;
1313 }
1314 }
1315 else
1316 {
1317 IO_STATUS_BLOCK Iosb;
1318
1319 Status = NtFsControlFile(hNamedPipe,
1320 NULL,
1321 NULL,
1322 NULL,
1323 &Iosb,
1324 FSCTL_PIPE_TRANSCEIVE,
1325 lpInBuffer,
1326 nInBufferSize,
1327 lpOutBuffer,
1328 nOutBufferSize);
1329 if (Status == STATUS_PENDING)
1330 {
1331 Status = NtWaitForSingleObject(hNamedPipe,
1332 FALSE,
1333 NULL);
1334 if (NT_SUCCESS(Status))
1335 Status = Iosb.Status;
1336 }
1337
1338 if (NT_SUCCESS(Status))
1339 {
1340 /* lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
1341 check that case either and crashes (only after the operation
1342 completed) */
1343 *lpBytesRead = Iosb.Information;
1344 }
1345 else
1346 {
1347 BaseSetLastNTError(Status);
1348 return FALSE;
1349 }
1350 }
1351
1352 return TRUE;
1353 }
1354
1355 /* EOF */