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