Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

winsta.c

Go to the documentation of this file.
00001 /**************************** Module Header ********************************\ 00002 * Module Name: winsta.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * Windowstation Routines 00007 * 00008 * History: 00009 * 01-14-91 JimA Created. 00010 \***************************************************************************/ 00011 00012 #include "precomp.h" 00013 #pragma hdrstop 00014 00015 00016 /***************************************************************************\ 00017 * InitTerminal 00018 * 00019 * Creates the desktop thread for a terminal and also the RIT for the 00020 * IO terminal 00021 * 00022 * History: 00023 * 27-10-97 CLupu Created. 00024 \***************************************************************************/ 00025 00026 NTSTATUS xxxInitTerminal( 00027 PTERMINAL pTerm) 00028 { 00029 NTSTATUS Status; 00030 PKEVENT pEventTermInit; 00031 HANDLE hEventInputReady, hEventTermInit; 00032 HANDLE hThreadDesktop; 00033 00034 CheckCritIn(); 00035 00036 UserAssert(!(pTerm->dwTERMF_Flags & TERMF_INITIALIZED)); 00037 00038 if (pTerm->pEventInputReady != NULL) { 00039 00040 /* 00041 * if we make it here it means that another thread is 00042 * executing xxxInitTerminal for the same terminal and it 00043 * left the critical section. 00044 */ 00045 UserAssert(pTerm->pEventTermInit != NULL); 00046 00047 /* 00048 * use a local variable so we can safely reset 00049 * pTerm->pEventTermInit when we're done with it 00050 */ 00051 pEventTermInit = pTerm->pEventTermInit; 00052 00053 ObReferenceObject(pEventTermInit); 00054 00055 LeaveCrit(); 00056 00057 goto Wait; 00058 } 00059 00060 /* 00061 * Create the input ready event. RIT and desktop thread will wait for it. 00062 * It will be set when the first desktop in this terminal will be created. 00063 */ 00064 Status = ZwCreateEvent( 00065 &hEventInputReady, 00066 EVENT_ALL_ACCESS, 00067 NULL, 00068 NotificationEvent, 00069 FALSE); 00070 00071 if (!NT_SUCCESS(Status)) 00072 return Status; 00073 00074 Status = ObReferenceObjectByHandle( 00075 hEventInputReady, 00076 EVENT_ALL_ACCESS, 00077 *ExEventObjectType, 00078 KernelMode, 00079 &pTerm->pEventInputReady, NULL); 00080 00081 ZwClose(hEventInputReady); 00082 00083 if (!NT_SUCCESS(Status)) 00084 return Status; 00085 00086 /* 00087 * Device and RIT initialization. Don't do it for 00088 * the system terminal. 00089 */ 00090 if (!(pTerm->dwTERMF_Flags & TERMF_NOIO)) { 00091 if (!CreateTerminalInput(pTerm)) { 00092 ObDereferenceObject(pTerm->pEventInputReady); 00093 return STATUS_NO_MEMORY; 00094 } 00095 } 00096 00097 /* 00098 * create an event to syncronize the terminal initialization 00099 */ 00100 Status = ZwCreateEvent( 00101 &hEventTermInit, 00102 EVENT_ALL_ACCESS, 00103 NULL, 00104 NotificationEvent, 00105 FALSE); 00106 00107 if (!NT_SUCCESS(Status)) { 00108 ObDereferenceObject(pTerm->pEventInputReady); 00109 return Status; 00110 } 00111 00112 Status = ObReferenceObjectByHandle( 00113 hEventTermInit, 00114 EVENT_ALL_ACCESS, 00115 *ExEventObjectType, 00116 KernelMode, 00117 &pTerm->pEventTermInit, NULL); 00118 00119 ZwClose(hEventTermInit); 00120 00121 if (!NT_SUCCESS(Status)) { 00122 ObDereferenceObject(pTerm->pEventInputReady); 00123 return Status; 00124 } 00125 00126 /* 00127 * use a local variable so we can safely reset 00128 * pTerm->pEventTermInit when we're done with it 00129 */ 00130 pEventTermInit = pTerm->pEventTermInit; 00131 00132 LeaveCrit(); 00133 00134 /* 00135 * Create the desktop thread. 00136 */ 00137 Status = CreateSystemThread( 00138 (PKSTART_ROUTINE)xxxDesktopThread, 00139 pTerm, 00140 &hThreadDesktop); 00141 00142 if (!NT_SUCCESS(Status)) { 00143 EnterCrit(); 00144 ObDereferenceObject(pTerm->pEventInputReady); 00145 ObDereferenceObject(pEventTermInit); 00146 return STATUS_NO_MEMORY; 00147 } 00148 00149 ZwClose(hThreadDesktop); 00150 00151 Wait: 00152 KeWaitForSingleObject(pEventTermInit, 00153 WrUserRequest, 00154 KernelMode, 00155 FALSE, 00156 NULL); 00157 00158 EnterCrit(); 00159 00160 /* 00161 * dereference the terminal init event. It will eventually 00162 * go away. 00163 */ 00164 ObDereferenceObject(pEventTermInit); 00165 00166 pTerm->pEventTermInit = NULL; 00167 00168 if (pTerm->dwTERMF_Flags & TERMF_DTINITFAILED) { 00169 return STATUS_NO_MEMORY; 00170 } 00171 00172 pTerm->dwTERMF_Flags |= TERMF_INITIALIZED; 00173 return STATUS_SUCCESS; 00174 } 00175 00176 00177 /***************************************************************************\ 00178 * xxxCreateWindowStation 00179 * 00180 * Creates the specified windowstation and starts a logon thread for the 00181 * station. 00182 * 00183 * History: 00184 * 01-15-91 JimA Created. 00185 \***************************************************************************/ 00186 00187 static CONST LPCWSTR lpszStdFormats[] = { 00188 L"StdExit", 00189 L"StdNewDocument", 00190 L"StdOpenDocument", 00191 L"StdEditDocument", 00192 L"StdNewfromTemplate", 00193 L"StdCloseDocument", 00194 L"StdShowItem", 00195 L"StdDoVerbItem", 00196 L"System", 00197 L"OLEsystem", 00198 L"StdDocumentName", 00199 L"Protocols", 00200 L"Topics", 00201 L"Formats", 00202 L"Status", 00203 L"EditEnvItems", 00204 L"True", 00205 L"False", 00206 L"Change", 00207 L"Save", 00208 L"Close", 00209 L"MSDraw" 00210 }; 00211 00212 NTSTATUS CreateGlobalAtomTable( 00213 PVOID* ppAtomTable) 00214 { 00215 NTSTATUS Status; 00216 RTL_ATOM Atom; 00217 ULONG i; 00218 00219 Status = RtlCreateAtomTable(0, ppAtomTable); 00220 00221 if (!NT_SUCCESS(Status)) { 00222 RIPMSG0(RIP_WARNING, "Global atom table not created"); 00223 return Status; 00224 } 00225 00226 for (i = 0; i < ARRAY_SIZE(lpszStdFormats); i++) { 00227 Status = RtlAddAtomToAtomTable(*ppAtomTable, 00228 (PWSTR)lpszStdFormats[i], 00229 &Atom); 00230 if (!NT_SUCCESS(Status)) { 00231 RIPMSG1(RIP_WARNING, "RtlAddAtomToAtomTable failed to add atom %ws", 00232 lpszStdFormats[i]); 00233 00234 RtlDestroyAtomTable(*ppAtomTable); 00235 return Status; 00236 } 00237 00238 RtlPinAtomInAtomTable(*ppAtomTable, Atom); 00239 } 00240 return Status; 00241 } 00242 00243 HWINSTA xxxCreateWindowStation( 00244 POBJECT_ATTRIBUTES ObjectAttributes, 00245 KPROCESSOR_MODE OwnershipMode, 00246 DWORD dwDesiredAccess, 00247 HANDLE hKbdLayoutFile, 00248 DWORD offTable, 00249 PCWSTR pwszKLID, 00250 UINT uKbdInputLocale) 00251 { 00252 PWINDOWSTATION pwinsta; 00253 PTHREADINFO ptiCurrent; 00254 PDESKTOP pdeskTemp; 00255 HDESK hdeskTemp; 00256 PSECURITY_DESCRIPTOR psd; 00257 PSECURITY_DESCRIPTOR psdCapture; 00258 PPROCESSINFO ppiSave; 00259 NTSTATUS Status; 00260 PACCESS_ALLOWED_ACE paceList = NULL, pace; 00261 ULONG ulLength, ulLengthSid; 00262 HANDLE hEvent; 00263 HWINSTA hwinsta; 00264 DWORD dwDisableHooks; 00265 PTERMINAL pTerm = NULL; 00266 PWND pwnd; 00267 WCHAR szBaseNamedObjectDirectory[MAX_SESSION_PATH]; 00268 00269 UserAssert(IsWinEventNotifyDeferredOK()); 00270 00271 /* 00272 * Get the pointer to the security descriptor so we can 00273 * assign it to the new object later. 00274 */ 00275 psdCapture = ObjectAttributes->SecurityDescriptor; 00276 00277 /* 00278 * The first windowstation that gets created is Winsta0 and 00279 * it's the only interactive one. 00280 */ 00281 if (grpWinStaList == NULL) { 00282 00283 /* 00284 * Assert that winlogon is the first to call CreateWindowStation 00285 */ 00286 UserAssert(PsGetCurrentProcess()->UniqueProcessId == gpidLogon); 00287 00288 pTerm = &gTermIO; 00289 } else { 00290 pTerm = &gTermNOIO; 00291 00292 UserAssert(grpWinStaList->rpwinstaNext == NULL || 00293 pTerm->dwTERMF_Flags & TERMF_NOIO); 00294 00295 pTerm->dwTERMF_Flags |= TERMF_NOIO; 00296 } 00297 00298 /* 00299 * Create the WindowStation object 00300 */ 00301 Status = ObCreateObject(KernelMode, *ExWindowStationObjectType, 00302 ObjectAttributes, OwnershipMode, NULL, sizeof(WINDOWSTATION), 00303 0, 0, &pwinsta); 00304 00305 if (!NT_SUCCESS(Status)) { 00306 RIPNTERR0(Status, RIP_WARNING, "Failed to create windowstation"); 00307 return NULL; 00308 } 00309 00310 /* 00311 * Initialize everything 00312 */ 00313 RtlZeroMemory(pwinsta, sizeof(WINDOWSTATION)); 00314 00315 /* 00316 * Store the session id of the session who created the windowstation 00317 */ 00318 pwinsta->dwSessionId = gSessionId; 00319 00320 pwinsta->pTerm = pTerm; 00321 00322 /* 00323 * All the windowstations in the system terminal are non-interactive. 00324 */ 00325 if (pTerm->dwTERMF_Flags & TERMF_NOIO) { 00326 pwinsta->dwWSF_Flags = WSF_NOIO; 00327 } 00328 00329 /* 00330 * Create the global atom table and populate it with the default OLE atoms 00331 * Pin each atom so they can't be deleted by bogus applications like Winword 00332 */ 00333 Status = CreateGlobalAtomTable(&pwinsta->pGlobalAtomTable); 00334 00335 if (pwinsta->pGlobalAtomTable == NULL) { 00336 UserAssert(!NT_SUCCESS(Status)); 00337 RIPNTERR0(Status, RIP_WARNING, "CreateGlobalAtomTable failed"); 00338 goto create_error; 00339 } 00340 00341 /* 00342 * create the desktop thread 00343 * and the RIT (only for the IO terminal) 00344 */ 00345 if (!(pTerm->dwTERMF_Flags & TERMF_INITIALIZED)) { 00346 00347 Status = xxxInitTerminal(pTerm); 00348 00349 if (!NT_SUCCESS(Status)) { 00350 RIPNTERR0(Status, RIP_WARNING, "xxxInitTerminal failed"); 00351 goto create_error; 00352 } 00353 } 00354 00355 if (!(pwinsta->dwWSF_Flags & WSF_NOIO)) { 00356 if (!xxxInitWindowStation(pwinsta)) { 00357 RIPNTERR0(STATUS_NO_MEMORY, RIP_WARNING, "xxxInitWindowStation failed"); 00358 goto create_error; 00359 } 00360 } 00361 00362 /* 00363 * Create only one desktop owner window per terminal. 00364 */ 00365 if (pTerm->spwndDesktopOwner == NULL) { 00366 00367 /* 00368 * Switch ppi values so window will be created using the 00369 * system's desktop window class. 00370 */ 00371 ptiCurrent = PtiCurrent(); 00372 ppiSave = ptiCurrent->ppi; 00373 ptiCurrent->ppi = pTerm->ptiDesktop->ppi; 00374 00375 UserAssert(pTerm->ptiDesktop->ppi->W32PF_Flags & W32PF_CLASSESREGISTERED); 00376 00377 pdeskTemp = ptiCurrent->rpdesk; /* save current desktop */ 00378 hdeskTemp = ptiCurrent->hdesk; 00379 if (pdeskTemp) { 00380 ObReferenceObject(pdeskTemp); 00381 LogDesktop(pdeskTemp, LD_REF_FN_CREATEWINDOWSTATION, TRUE, (ULONG_PTR)PtiCurrent()); 00382 } 00383 00384 /* 00385 * The following code is not supposed to leave the critical section because 00386 * CreateWindowStation is an API so the current thread can be on any state 00387 * setting its pdesk to NULL it's kind of bogus 00388 */ 00389 DeferWinEventNotify(); 00390 BEGINATOMICCHECK(); 00391 zzzSetDesktop(ptiCurrent, NULL, NULL); 00392 00393 00394 /* 00395 * HACK HACK HACK!!! (adams) In order to create the desktop window 00396 * with the correct desktop, we set the desktop of the current thread 00397 * to the new desktop. But in so doing we allow hooks on the current 00398 * thread to also hook this new desktop. This is bad, because we don't 00399 * want the desktop window to be hooked while it is created. So we 00400 * temporarily disable hooks of the current thread and desktop, and 00401 * reenable them after switching back to the original desktop. 00402 */ 00403 00404 dwDisableHooks = ptiCurrent->TIF_flags & TIF_DISABLEHOOKS; 00405 ptiCurrent->TIF_flags |= TIF_DISABLEHOOKS; 00406 00407 /* 00408 * Create the desktop owner window 00409 * 00410 * CONSIDER (adams): Do we want to limit the desktop size so that the 00411 * width and height of a rect will fit in 16bit coordinates? 00412 * 00413 * SHRT_MIN / 2, SHRT_MIN / 2, SHRT_MAX, SHRT_MAX, 00414 * 00415 * Or do we want to limit it so just any point has 16bit coordinates? 00416 * 00417 * -SHRT_MIN, -SHRT_MIN, SHRT_MAX * 2, SHRT_MAX * 2 00418 */ 00419 00420 pwnd = xxxCreateWindowEx( 00421 (DWORD)0, 00422 (PLARGE_STRING)DESKTOPCLASS, 00423 NULL, 00424 (WS_POPUP | WS_CLIPCHILDREN), 00425 SHRT_MIN / 2, 00426 SHRT_MIN / 2, 00427 SHRT_MAX, 00428 SHRT_MAX, 00429 NULL, 00430 NULL, 00431 hModuleWin, 00432 (LPWSTR)NULL, 00433 VER31 00434 ); 00435 00436 if (pwnd == NULL) { 00437 RIPMSG0(RIP_WARNING, "xxxCreateWindowStation: Failed to create mother desktop window"); 00438 Status = STATUS_NO_MEMORY; 00439 EXITATOMICCHECK(); 00440 zzzEndDeferWinEventNotify(); 00441 /* 00442 * Restore caller's ppi 00443 */ 00444 ptiCurrent->ppi = ppiSave; 00445 00446 /* 00447 * Restore the previous desktop 00448 */ 00449 zzzSetDesktop(ptiCurrent, pdeskTemp, hdeskTemp); 00450 00451 goto create_error; 00452 } 00453 00454 /* 00455 * Mark this handle entry that is allocated out of pool 00456 */ 00457 { 00458 PHE phe; 00459 00460 UserAssert(ptiCurrent->rpdesk == NULL); 00461 00462 phe = HMPheFromObject(pwnd); 00463 phe->bFlags |= HANDLEF_POOL; 00464 } 00465 00466 Lock(&(pTerm->spwndDesktopOwner), pwnd); 00467 00468 UserAssert(ptiCurrent->TIF_flags & TIF_DISABLEHOOKS); 00469 ptiCurrent->TIF_flags = (ptiCurrent->TIF_flags & ~TIF_DISABLEHOOKS) | dwDisableHooks; 00470 00471 SetVisible(pTerm->spwndDesktopOwner, SV_SET); 00472 HMChangeOwnerThread(pTerm->spwndDesktopOwner, pTerm->ptiDesktop); 00473 00474 /* 00475 * Restore caller's ppi 00476 */ 00477 ptiCurrent->ppi = ppiSave; 00478 00479 /* 00480 * Restore the previous desktop 00481 */ 00482 zzzSetDesktop(ptiCurrent, pdeskTemp, hdeskTemp); 00483 00484 ENDATOMICCHECK(); 00485 zzzEndDeferWinEventNotify(); 00486 00487 if (pdeskTemp) { 00488 LogDesktop(pdeskTemp, LD_DEREF_FN_CREATEWINDOWSTATION, FALSE, (ULONG_PTR)PtiCurrent()); 00489 ObDereferenceObject(pdeskTemp); 00490 } 00491 } 00492 00493 /* 00494 * If this is the visible windowstation, assign it to 00495 * the server and create the desktop switch notification 00496 * event. 00497 */ 00498 if (!(pwinsta->dwWSF_Flags & WSF_NOIO)) { 00499 UNICODE_STRING strName; 00500 HANDLE hRootDir; 00501 OBJECT_ATTRIBUTES obja; 00502 00503 /* 00504 * Create desktop switch notification event. 00505 */ 00506 ulLengthSid = RtlLengthSid(SeExports->SeWorldSid); 00507 ulLength = ulLengthSid + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK); 00508 00509 /* 00510 * Allocate the ACE list 00511 */ 00512 paceList = (PACCESS_ALLOWED_ACE)UserAllocPoolWithQuota(ulLength, TAG_SECURITY); 00513 00514 if (paceList == NULL) { 00515 Status = STATUS_NO_MEMORY; 00516 goto create_error; 00517 } 00518 00519 /* 00520 * Initialize ACE 0 00521 */ 00522 pace = paceList; 00523 pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE; 00524 pace->Header.AceSize = (USHORT)ulLength; 00525 pace->Header.AceFlags = 0; 00526 pace->Mask = SYNCHRONIZE; 00527 RtlCopySid(ulLengthSid, &pace->SidStart, SeExports->SeWorldSid); 00528 00529 /* 00530 * Create the SD 00531 */ 00532 psd = CreateSecurityDescriptor(paceList, ulLength, FALSE); 00533 00534 UserFreePool(paceList); 00535 00536 if (psd == NULL) { 00537 Status = STATUS_NO_MEMORY; 00538 goto create_error; 00539 } 00540 00541 /* 00542 * Create the named event. 00543 */ 00544 UserAssert(ghEventSwitchDesktop == NULL); 00545 00546 if (gbRemoteSession) { 00547 swprintf(szBaseNamedObjectDirectory, L"\\Sessions\\%ld\\BaseNamedObjects", 00548 gSessionId); 00549 RtlInitUnicodeString(&strName, szBaseNamedObjectDirectory); 00550 } else { 00551 RtlInitUnicodeString(&strName, L"\\BaseNamedObjects"); 00552 } 00553 00554 InitializeObjectAttributes( &obja, 00555 &strName, 00556 OBJ_CASE_INSENSITIVE, 00557 NULL, 00558 NULL 00559 ); 00560 Status = ZwOpenDirectoryObject( &hRootDir, 00561 DIRECTORY_ALL_ACCESS & 00562 ~(DELETE | WRITE_DAC | WRITE_OWNER), 00563 &obja 00564 ); 00565 if (NT_SUCCESS(Status)) { 00566 RtlInitUnicodeString(&strName, L"WinSta0_DesktopSwitch"); 00567 InitializeObjectAttributes(&obja, &strName, OBJ_OPENIF, hRootDir, psd); 00568 Status = ZwCreateEvent(&hEvent, EVENT_ALL_ACCESS, &obja, 00569 NotificationEvent, FALSE); 00570 ZwClose(hRootDir); 00571 00572 if (NT_SUCCESS(Status)) { 00573 Status = ObReferenceObjectByHandle(hEvent, EVENT_ALL_ACCESS, *ExEventObjectType, 00574 KernelMode, &gpEventSwitchDesktop, NULL); 00575 if (NT_SUCCESS(Status)) { 00576 00577 /* 00578 * Attach to the system process and create a handle to the 00579 * object. This will ensure that the object name is retained 00580 * when hEvent is closed. This is simpler than creating a 00581 * permanent object, which takes the 00582 * SeCreatePermanentPrivilege. 00583 */ 00584 KeAttachProcess(&gpepCSRSS->Pcb); 00585 00586 Status = ObOpenObjectByPointer( 00587 gpEventSwitchDesktop, 00588 0, 00589 NULL, 00590 EVENT_ALL_ACCESS, 00591 NULL, 00592 KernelMode, 00593 &ghEventSwitchDesktop); 00594 KeDetachProcess(); 00595 } 00596 ZwClose(hEvent); 00597 } 00598 } 00599 if (!NT_SUCCESS(Status)) 00600 goto create_error; 00601 00602 UserFreePool(psd); 00603 } 00604 00605 /* 00606 * Create a handle to the windowstation 00607 */ 00608 Status = ObInsertObject(pwinsta, NULL, dwDesiredAccess, 1, 00609 &pwinsta, &hwinsta); 00610 00611 if (Status == STATUS_OBJECT_NAME_EXISTS) { 00612 00613 /* 00614 * The windowstation already exists, so deref and leave. 00615 */ 00616 ObDereferenceObject(pwinsta); 00617 00618 } else if (NT_SUCCESS(Status)) { 00619 PSECURITY_DESCRIPTOR psdParent, psdNew; 00620 SECURITY_SUBJECT_CONTEXT Context; 00621 POBJECT_DIRECTORY pParentDirectory; 00622 SECURITY_INFORMATION siNew; 00623 00624 /* 00625 * Create security descriptor for the windowstation. 00626 * ObInsertObject only supports non-container 00627 * objects, so we must assign our own security descriptor. 00628 */ 00629 SeCaptureSubjectContext(&Context); 00630 SeLockSubjectContext(&Context); 00631 00632 pParentDirectory = OBJECT_HEADER_TO_NAME_INFO( 00633 OBJECT_TO_OBJECT_HEADER(pwinsta))->Directory; 00634 if (pParentDirectory != NULL) 00635 psdParent = OBJECT_TO_OBJECT_HEADER(pParentDirectory)->SecurityDescriptor; 00636 else 00637 psdParent = NULL; 00638 00639 Status = SeAssignSecurity( 00640 psdParent, 00641 psdCapture, 00642 &psdNew, 00643 TRUE, 00644 &Context, 00645 (PGENERIC_MAPPING)&WinStaMapping, 00646 PagedPool); 00647 00648 SeUnlockSubjectContext(&Context); 00649 SeReleaseSubjectContext(&Context); 00650 00651 if (!NT_SUCCESS(Status)) { 00652 #if DBG 00653 if (Status == STATUS_ACCESS_DENIED) { 00654 RIPNTERR0(Status, RIP_WARNING, "Access denied during object creation"); 00655 } else { 00656 RIPNTERR1(Status, RIP_ERROR, 00657 "Can't create security descriptor! Status = %#lx", 00658 Status); 00659 } 00660 #endif 00661 } else { 00662 00663 /* 00664 * Call the security method to copy the security descriptor 00665 */ 00666 siNew = (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | 00667 DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION); 00668 Status = ObSetSecurityDescriptorInfo( 00669 pwinsta, 00670 &siNew, 00671 psdNew, 00672 &OBJECT_TO_OBJECT_HEADER(pwinsta)->SecurityDescriptor, 00673 PagedPool, 00674 (PGENERIC_MAPPING)&WinStaMapping); 00675 SeDeassignSecurity(&psdNew); 00676 00677 if (NT_SUCCESS(Status)) { 00678 00679 PWINDOWSTATION* ppwinsta; 00680 00681 /* 00682 * Put it on the tail of the global windowstation list 00683 */ 00684 ppwinsta = &grpWinStaList; 00685 while (*ppwinsta != NULL) 00686 ppwinsta = &(*ppwinsta)->rpwinstaNext; 00687 LockWinSta(ppwinsta, pwinsta); 00688 00689 /* 00690 * For interactive window stations load the keyboard 00691 * layout. !!! 00692 */ 00693 if (!(pwinsta->dwWSF_Flags & WSF_NOIO) && pwszKLID != NULL) { 00694 if (xxxLoadKeyboardLayoutEx( 00695 pwinsta, 00696 hKbdLayoutFile, 00697 (HKL)NULL, 00698 offTable, 00699 pwszKLID, 00700 uKbdInputLocale, 00701 KLF_ACTIVATE | KLF_INITTIME) == NULL) { 00702 Status = STATUS_UNSUCCESSFUL; 00703 } 00704 } 00705 } 00706 } 00707 ObDereferenceObject(pwinsta); 00708 } 00709 00710 if (!NT_SUCCESS(Status)) { 00711 RIPNTERR1(Status, 00712 RIP_WARNING, 00713 "CreateWindowStation: Failed with Status 0x%x", 00714 Status); 00715 return NULL; 00716 } 00717 00718 return hwinsta; 00719 00720 /* 00721 * Goto here if an error occurs so things can be cleaned up 00722 */ 00723 create_error: 00724 00725 RIPNTERR1(Status, 00726 RIP_WARNING, 00727 "CreateWindowStation: Failed with Status 0x%x", 00728 Status); 00729 00730 ObDereferenceObject(pwinsta); 00731 00732 return NULL; 00733 } 00734 00735 /***************************************************************************\ 00736 * FreeWindowStation 00737 * 00738 * Called when last lock to the windowstation is removed. Frees all 00739 * resources owned by the windowstation. 00740 * 00741 * History: 00742 * 12-22-93 JimA Created. 00743 \***************************************************************************/ 00744 00745 VOID FreeWindowStation( 00746 PWINDOWSTATION pwinsta) 00747 { 00748 UserAssert(OBJECT_TO_OBJECT_HEADER(pwinsta)->Type == *ExWindowStationObjectType); 00749 00750 /* 00751 * Mark the windowstation as dying. Make sure we're not recursing. 00752 */ 00753 UserAssert(!(pwinsta->dwWSF_Flags & WSF_DYING)); 00754 pwinsta->dwWSF_Flags |= WSF_DYING; 00755 00756 UserAssert(pwinsta->rpdeskList == NULL); 00757 00758 /* 00759 * Free up the other resources 00760 */ 00761 00762 if (!(pwinsta->dwWSF_Flags & WSF_NOIO) && (gpEventSwitchDesktop != NULL)) { 00763 KeSetEvent(gpEventSwitchDesktop, EVENT_INCREMENT, FALSE); 00764 ObDereferenceObject(gpEventSwitchDesktop); 00765 gpEventSwitchDesktop = NULL; 00766 } 00767 00768 BEGIN_REENTERCRIT(); 00769 00770 RtlDestroyAtomTable(pwinsta->pGlobalAtomTable); 00771 00772 ForceEmptyClipboard(pwinsta); 00773 00774 /* 00775 * Free up keyboard layouts 00776 */ 00777 if (!(pwinsta->dwWSF_Flags & WSF_NOIO) && pwinsta->spklList != NULL) { 00778 00779 PKL pkl = pwinsta->spklList; 00780 PKL pklFirst = pkl; 00781 00782 RIPMSG2(RIP_WARNING, "FreeWindowStation: pwinsta(%p)->spklList is not NULL, %p", pwinsta, pwinsta->spklList); 00783 00784 do { 00785 PKL pklNext = pkl->pklNext; 00786 00787 HMMarkObjectDestroy(pkl); 00788 pkl->dwKL_Flags |= KL_UNLOADED; 00789 00790 Lock(&pwinsta->spklList, pklNext); 00791 00792 pkl = pklNext; 00793 00794 } while (pkl != pkl->pklNext && pkl != pklFirst); 00795 00796 Unlock(&pwinsta->spklList); 00797 00798 HYDRA_HINT(HH_KBDLYOUTFREEWINSTA); 00799 00800 /* 00801 * make sure the logon notify window went away 00802 */ 00803 UserAssert(gspwndLogonNotify == NULL); 00804 } else { 00805 UserAssert(pwinsta->spklList == NULL); 00806 } 00807 00808 /* 00809 * Free the USER sid 00810 */ 00811 if (pwinsta->psidUser != NULL) { 00812 UserFreePool(pwinsta->psidUser); 00813 pwinsta->psidUser = NULL; 00814 } 00815 00816 END_REENTERCRIT(); 00817 } 00818 00819 /***************************************************************************\ 00820 * DestroyWindowStation 00821 * 00822 * Removes the windowstation from the global list. We can't release 00823 * any resources until all locks have been removed. 00824 * station. 00825 * 00826 * History: 00827 * 01-17-91 JimA Created. 00828 \***************************************************************************/ 00829 00830 VOID DestroyWindowStation( 00831 PEPROCESS Process, 00832 PVOID pobj, 00833 ACCESS_MASK amGranted, 00834 ULONG cProcessHandles, 00835 ULONG cSystemHandles) 00836 { 00837 PWINDOWSTATION pwinsta = pobj; 00838 PWINDOWSTATION *ppwinsta; 00839 PDESKTOP pdesk; 00840 PDESKTOP pdeskLock = NULL; 00841 00842 UserAssert(OBJECT_TO_OBJECT_HEADER(pobj)->Type == *ExWindowStationObjectType); 00843 00844 /* 00845 * If this is not the last handle, leave 00846 */ 00847 if (cSystemHandles != 1) 00848 return; 00849 00850 BEGIN_REENTERCRIT(); 00851 00852 /* 00853 * If the window station was linked into the terminal's list, 00854 * go ahead and unlink it. 00855 */ 00856 for (ppwinsta = &grpWinStaList; 00857 *ppwinsta != NULL && pwinsta != *ppwinsta; 00858 ppwinsta = &(*ppwinsta)->rpwinstaNext) 00859 ; 00860 if (*ppwinsta != NULL) { 00861 UnlockWinSta(ppwinsta); 00862 /* 00863 * Assert that unlocking it didn't destroy it. 00864 */ 00865 UserAssert(OBJECT_TO_OBJECT_HEADER(pobj)->Type == *ExWindowStationObjectType); 00866 00867 *ppwinsta = pwinsta->rpwinstaNext; 00868 /* 00869 * The instruction above transfered rpwinstaNext lock ownership to the previous 00870 * element in the list. Hence the value in pwinsta can no longer be considered valid. 00871 */ 00872 pwinsta->rpwinstaNext = NULL; 00873 } 00874 00875 /* 00876 * Notify all console threads and wait for them to 00877 * terminate. 00878 */ 00879 pdesk = pwinsta->rpdeskList; 00880 while (pdesk != NULL) { 00881 if (pdesk != grpdeskLogon && pdesk->dwConsoleThreadId) { 00882 LockDesktop(&pdeskLock, pdesk, LDL_FN_DESTROYWINDOWSTATION, 0); 00883 TerminateConsole(pdesk); 00884 00885 /* 00886 * Restart scan in case desktop list has changed 00887 */ 00888 pdesk = pwinsta->rpdeskList; 00889 UnlockDesktop(&pdeskLock, LDU_FN_DESTROYWINDOWSTATION, 0); 00890 } else 00891 pdesk = pdesk->rpdeskNext; 00892 } 00893 00894 END_REENTERCRIT(); 00895 00896 UNREFERENCED_PARAMETER(Process); 00897 UNREFERENCED_PARAMETER(cProcessHandles); 00898 UNREFERENCED_PARAMETER(amGranted); 00899 } 00900 00901 00902 /***************************************************************************\ 00903 * ParseWindowStation 00904 * 00905 * Parse a windowstation path. 00906 * 00907 * History: 00908 * 06-14-95 JimA Created. 00909 \***************************************************************************/ 00910 00911 NTSTATUS ParseWindowStation( 00912 PVOID pContainerObject, 00913 POBJECT_TYPE pObjectType, 00914 PACCESS_STATE pAccessState, 00915 KPROCESSOR_MODE AccessMode, 00916 ULONG Attributes, 00917 PUNICODE_STRING pstrCompleteName, 00918 PUNICODE_STRING pstrRemainingName, 00919 PVOID Context OPTIONAL, 00920 PSECURITY_QUALITY_OF_SERVICE pqos, 00921 PVOID *pObject) 00922 { 00923 PWINDOWSTATION pwinsta = pContainerObject; 00924 00925 UserAssert(OBJECT_TO_OBJECT_HEADER(pContainerObject)->Type == *ExWindowStationObjectType); 00926 00927 /* 00928 * If nothing remains to be parsed, return the windowstation. 00929 */ 00930 *pObject = NULL; 00931 if (pstrRemainingName->Length == 0) { 00932 if (pObjectType != *ExWindowStationObjectType) 00933 return STATUS_OBJECT_TYPE_MISMATCH; 00934 00935 ObReferenceObject(pwinsta); 00936 *pObject = pwinsta; 00937 return STATUS_SUCCESS; 00938 } 00939 00940 /* 00941 * Skip leading path separator, if present. 00942 */ 00943 if (*(pstrRemainingName->Buffer) == OBJ_NAME_PATH_SEPARATOR) { 00944 pstrRemainingName->Buffer++; 00945 pstrRemainingName->Length -= sizeof(WCHAR); 00946 pstrRemainingName->MaximumLength -= sizeof(WCHAR); 00947 } 00948 00949 /* 00950 * Validate the desktop name. 00951 */ 00952 if (wcschr(pstrRemainingName->Buffer, L'\\')) 00953 return STATUS_OBJECT_PATH_INVALID; 00954 if (pObjectType == *ExDesktopObjectType) { 00955 return ParseDesktop( 00956 pContainerObject, 00957 pObjectType, 00958 pAccessState, 00959 AccessMode, 00960 Attributes, 00961 pstrCompleteName, 00962 pstrRemainingName, 00963 Context, 00964 pqos, 00965 pObject); 00966 } 00967 00968 return STATUS_OBJECT_TYPE_MISMATCH; 00969 } 00970 00971 00972 /***************************************************************************\ 00973 * OkayToCloseWindowStation 00974 * 00975 * We can only close windowstation handles if they're not in use. 00976 * 00977 * History: 00978 * 08-Feb-1999 JerrySh Created. 00979 \***************************************************************************/ 00980 00981 BOOLEAN OkayToCloseWindowStation( 00982 PEPROCESS Process OPTIONAL, 00983 PVOID Object, 00984 HANDLE Handle) 00985 { 00986 PWINDOWSTATION pwinsta = (PWINDOWSTATION)Object; 00987 00988 UNREFERENCED_PARAMETER(Process); 00989 00990 UserAssert(OBJECT_TO_OBJECT_HEADER(Object)->Type == *ExWindowStationObjectType); 00991 00992 /* 00993 * Kernel mode code can close anything. 00994 */ 00995 if (KeGetPreviousMode() == KernelMode) { 00996 return TRUE; 00997 } 00998 00999 /* 01000 * We can't close a windowstation that's being used. 01001 */ 01002 if (CheckHandleInUse(Handle) || CheckHandleFlag(Handle, HF_PROTECTED)) { 01003 RIPMSG1(RIP_WARNING, "Trying to close windowstation %#p while still in use", pwinsta); 01004 return FALSE; 01005 } 01006 01007 return TRUE; 01008 } 01009 01010 /***************************************************************************\ 01011 * _OpenWindowStation 01012 * 01013 * Open a windowstation for the calling process 01014 * 01015 * History: 01016 * 03-19-91 JimA Created. 01017 \***************************************************************************/ 01018 01019 HWINSTA _OpenWindowStation( 01020 POBJECT_ATTRIBUTES pObjA, 01021 DWORD dwDesiredAccess, 01022 KPROCESSOR_MODE AccessMode) 01023 { 01024 HWINSTA hwinsta; 01025 NTSTATUS Status; 01026 01027 /* 01028 * Obja is client-side. Ob interfaces protect and capture is 01029 * appropriate. 01030 */ 01031 Status = ObOpenObjectByName( 01032 pObjA, 01033 *ExWindowStationObjectType, 01034 AccessMode, 01035 NULL, 01036 dwDesiredAccess, 01037 NULL, 01038 &hwinsta); 01039 if (!NT_SUCCESS(Status)) { 01040 RIPNTERR0(Status, RIP_VERBOSE, ""); 01041 hwinsta = NULL; 01042 } 01043 return hwinsta; 01044 } 01045 01046 /***************************************************************************\ 01047 * _CloseWindowStation 01048 * 01049 * Closes a windowstation for the calling process 01050 * 01051 * History: 01052 * 15-Jun-1999 JerrySh Created. 01053 \***************************************************************************/ 01054 01055 BOOL _CloseWindowStation( 01056 HWINSTA hwinsta) 01057 { 01058 HWINSTA hwinstaCurrent; 01059 01060 _GetProcessWindowStation(&hwinstaCurrent); 01061 if (hwinsta != hwinstaCurrent) { 01062 return NT_SUCCESS(ZwClose(hwinsta)); 01063 } 01064 return FALSE; 01065 } 01066 01067 /***************************************************************************\ 01068 * xxxSetProcessWindowStation (API) 01069 * 01070 * Sets the windowstation of the calling process to the windowstation 01071 * specified by pwinsta. 01072 * 01073 * History: 01074 * 01-14-91 JimA Created. 01075 \***************************************************************************/ 01076 01077 BOOL xxxSetProcessWindowStation( 01078 HWINSTA hwinsta, 01079 KPROCESSOR_MODE AccessMode) 01080 { 01081 PETHREAD Thread = PsGetCurrentThread(); 01082 PEPROCESS Process = PsGetCurrentProcess(); 01083 HWINSTA hwinstaDup; 01084 NTSTATUS Status; 01085 PPROCESSINFO ppi; 01086 PWINDOWSTATION pwinsta; 01087 PWINDOWSTATION pwinstaOld; 01088 OBJECT_HANDLE_INFORMATION ohi; 01089 OBJECT_HANDLE_INFORMATION ohiOld; 01090 01091 if (Process == NULL) { 01092 UserAssert(Process); 01093 return FALSE; 01094 } 01095 01096 if (Thread == NULL) { 01097 UserAssert(Thread); 01098 return FALSE; 01099 } 01100 01101 ppi = PpiFromProcess(THREAD_TO_PROCESS(Thread)); 01102 01103 if (!NT_SUCCESS(ObReferenceObjectByHandle( 01104 hwinsta, 01105 0, 01106 *ExWindowStationObjectType, 01107 AccessMode, 01108 &pwinsta, 01109 &ohi))) { 01110 return FALSE; 01111 } 01112 01113 /* 01114 * Bug 38780. Lock the handle to window station so that an app cannot free the 01115 * this handle by calling GetProcessWindowStation() & CloseHandle() 01116 */ 01117 01118 /* 01119 * Unprotect the old hwinsta 01120 */ 01121 if (ppi->hwinsta) { 01122 SetHandleFlag(ppi->hwinsta, HF_PROTECTED, FALSE); 01123 } 01124 01125 /* 01126 * Save the WindowStation information 01127 */ 01128 LockWinSta(&ppi->rpwinsta, pwinsta); 01129 ObDereferenceObject(pwinsta); 01130 ppi->hwinsta = hwinsta; 01131 01132 /* 01133 * Protect the new Window Station Handle 01134 */ 01135 SetHandleFlag(ppi->hwinsta, HF_PROTECTED, TRUE); 01136 01137 /* 01138 * Check the old Atom Manager WindowStation to see if we are 01139 * changing this process' WindowStation. 01140 */ 01141 if (Process->Win32WindowStation) { 01142 /* 01143 * Get a pointer to the old WindowStation object to see if it's 01144 * the same WindowStation that we are setting. 01145 */ 01146 Status = ObReferenceObjectByHandle( 01147 Process->Win32WindowStation, 01148 0, 01149 *ExWindowStationObjectType, 01150 AccessMode, 01151 &pwinstaOld, 01152 &ohiOld); 01153 if (NT_SUCCESS(Status)) { 01154 /* 01155 * Are they different WindowStations? If so, NULL out the 01156 * atom manager cache so we will reset it below. 01157 */ 01158 if (pwinsta != pwinstaOld) { 01159 ZwClose(Process->Win32WindowStation); 01160 Process->Win32WindowStation = NULL; 01161 } 01162 ObDereferenceObject(pwinstaOld); 01163 01164 } else { 01165 /* 01166 * Their Atom Manager handle is bad? Give them a new one. 01167 */ 01168 Process->Win32WindowStation = NULL; 01169 #if DBG 01170 RIPMSG2(RIP_WARNING, 01171 "SetProcessWindowStation: Couldn't reference old WindowStation (0x%X) Status=0x%X", 01172 Process->Win32WindowStation, 01173 Status); 01174 #endif 01175 } 01176 } 01177 01178 /* 01179 * Duplicate the WindowStation handle and stash it in the atom 01180 * manager's cache (Process->Win32WindowStation). We duplicate 01181 * the handle in case 01182 */ 01183 if (Process->Win32WindowStation == NULL) { 01184 Status = xxxUserDuplicateObject( 01185 NtCurrentProcess(), 01186 hwinsta, 01187 NtCurrentProcess(), 01188 &hwinstaDup, 01189 0, 01190 0, 01191 DUPLICATE_SAME_ACCESS); 01192 01193 if (NT_SUCCESS(Status)) { 01194 Process->Win32WindowStation = hwinstaDup; 01195 } 01196 #if DBG 01197 else { 01198 RIPMSG2(RIP_WARNING, 01199 "SetProcessWindowStation: Couldn't duplicate WindowStation handle (0x%X) Status=0x%X", 01200 hwinsta, 01201 Status); 01202 } 01203 #endif 01204 } 01205 01206 ppi->amwinsta = ohi.GrantedAccess; 01207 01208 /* 01209 * Cache WSF_NOIO flag in the W32PROCESS so that GDI can access it. 01210 */ 01211 if (pwinsta->dwWSF_Flags & WSF_NOIO) { 01212 ppi->W32PF_Flags &= ~W32PF_IOWINSTA; 01213 } else { 01214 ppi->W32PF_Flags |= W32PF_IOWINSTA; 01215 } 01216 01217 /* 01218 * Do the access check now for readscreen so that 01219 * blts off of the display will be as fast as possible. 01220 */ 01221 if (RtlAreAllAccessesGranted(ohi.GrantedAccess, WINSTA_READSCREEN)) { 01222 ppi->W32PF_Flags |= W32PF_READSCREENACCESSGRANTED; 01223 } else { 01224 ppi->W32PF_Flags &= ~W32PF_READSCREENACCESSGRANTED; 01225 } 01226 01227 return TRUE; 01228 } 01229 01230 01231 /***************************************************************************\ 01232 * _GetProcessWindowStation (API) 01233 * 01234 * Returns a pointer to the windowstation of the calling process. 01235 * 01236 * History: 01237 * 01-14-91 JimA Created. 01238 \***************************************************************************/ 01239 01240 PWINDOWSTATION _GetProcessWindowStation( 01241 HWINSTA *phwinsta) 01242 { 01243 PPROCESSINFO ppi; 01244 01245 ppi = PpiCurrent(); 01246 UserAssert(ppi); 01247 01248 if (phwinsta) 01249 *phwinsta = ppi->hwinsta; 01250 return ppi->rpwinsta; 01251 } 01252 01253 01254 /***************************************************************************\ 01255 * _BuildNameList 01256 * 01257 * Builds a list of windowstation or desktop names. 01258 * 01259 * History: 01260 * 05-17-94 JimA Created. 01261 * 10-21-96 CLupu Added TERMINAL enumeration 01262 \***************************************************************************/ 01263 01264 NTSTATUS _BuildNameList( 01265 PWINDOWSTATION pwinsta, 01266 PNAMELIST ccxpNameList, 01267 UINT cbNameList, 01268 PUINT pcbNeeded) 01269 { 01270 PBYTE pobj; 01271 PWCHAR ccxpwchDest, ccxpwchMax; 01272 ACCESS_MASK amDesired; 01273 POBJECT_HEADER pHead; 01274 POBJECT_HEADER_NAME_INFO pNameInfo; 01275 DWORD iNext; 01276 NTSTATUS Status; 01277 CONST GENERIC_MAPPING *pGenericMapping; 01278 01279 /* 01280 * Note -- NameList is client-side, and so must be protected. 01281 */ 01282 01283 try { 01284 ccxpNameList->cNames = 0; 01285 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 01286 return STATUS_ACCESS_VIOLATION; 01287 } 01288 01289 ccxpwchDest = ccxpNameList->awchNames; 01290 ccxpwchMax = (PWCHAR)((PBYTE)ccxpNameList + cbNameList - sizeof(WCHAR)); 01291 01292 /* 01293 * If we're enumerating windowstations, pwinsta is NULL. Otherwise, 01294 * we're enumerating desktops. 01295 */ 01296 if (pwinsta == NULL) { 01297 pobj = (PBYTE)grpWinStaList; 01298 amDesired = WINSTA_ENUMERATE; 01299 pGenericMapping = &WinStaMapping; 01300 iNext = FIELD_OFFSET(WINDOWSTATION, rpwinstaNext); 01301 } else { 01302 pobj = (PBYTE)pwinsta->rpdeskList; 01303 amDesired = DESKTOP_ENUMERATE; 01304 pGenericMapping = &DesktopMapping; 01305 iNext = FIELD_OFFSET(DESKTOP, rpdeskNext); 01306 } 01307 01308 Status = STATUS_SUCCESS; 01309 *pcbNeeded = 0; 01310 while (pobj != NULL) { 01311 01312 if (AccessCheckObject(pobj, amDesired, KernelMode, pGenericMapping)) { 01313 01314 /* 01315 * Find object name 01316 */ 01317 pHead = OBJECT_TO_OBJECT_HEADER(pobj); 01318 pNameInfo = OBJECT_HEADER_TO_NAME_INFO(pHead); 01319 01320 /* 01321 * If we run out of space, reset the buffer 01322 * and continue so we can compute the needed 01323 * space. 01324 */ 01325 if ((PWCHAR)((PBYTE)ccxpwchDest + pNameInfo->Name.Length + 01326 sizeof(WCHAR)) >= ccxpwchMax) { 01327 *pcbNeeded += (UINT)((PBYTE)ccxpwchDest - (PBYTE)ccxpNameList); 01328 ccxpwchDest = ccxpNameList->awchNames; 01329 Status = STATUS_BUFFER_TOO_SMALL; 01330 } 01331 01332 try { 01333 ccxpNameList->cNames++; 01334 01335 /* 01336 * Copy and terminate the string 01337 */ 01338 RtlCopyMemory(ccxpwchDest, pNameInfo->Name.Buffer, 01339 pNameInfo->Name.Length); 01340 (PBYTE)ccxpwchDest += pNameInfo->Name.Length; 01341 *ccxpwchDest++ = 0; 01342 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 01343 return STATUS_ACCESS_VIOLATION; 01344 } 01345 } 01346 01347 pobj = *(PBYTE*)(pobj + iNext); 01348 } 01349 01350 /* 01351 * Put an empty string on the end. 01352 */ 01353 try { 01354 *ccxpwchDest++ = 0; 01355 01356 ccxpNameList->cb = (UINT)((PBYTE)ccxpwchDest - (PBYTE)ccxpNameList); 01357 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 01358 return STATUS_ACCESS_VIOLATION; 01359 } 01360 01361 *pcbNeeded += (UINT)((PBYTE)ccxpwchDest - (PBYTE)ccxpNameList); 01362 01363 return Status; 01364 } 01365 01366 NTSTATUS ReferenceWindowStation( 01367 PETHREAD Thread, 01368 HWINSTA hwinsta, 01369 ACCESS_MASK amDesiredAccess, 01370 PWINDOWSTATION *ppwinsta, 01371 BOOL fUseDesktop) 01372 { 01373 PPROCESSINFO ppi; 01374 PTHREADINFO pti; 01375 PWINDOWSTATION pwinsta = NULL; 01376 NTSTATUS Status; 01377 01378 /* 01379 * We prefer to use the thread's desktop to dictate which 01380 * windowstation/Atom table to use rather than the process. 01381 * This allows NetDDE, which has threads running under 01382 * different desktops on different windowstations but whos 01383 * process is set to only one of these windowstations, to 01384 * get global atoms properly without having to change its 01385 * process windowstation a billion times and synchronize. 01386 */ 01387 ppi = PpiFromProcess(Thread->ThreadsProcess); 01388 pti = PtiFromThread(Thread); 01389 01390 /* 01391 * First, try to get the windowstation from the pti, and then 01392 * from the ppi. 01393 */ 01394 if (ppi != NULL) { 01395 if (!fUseDesktop || pti == NULL || pti->rpdesk == NULL || 01396 ppi->rpwinsta == pti->rpdesk->rpwinstaParent) { 01397 01398 /* 01399 * Use the windowstation assigned to the process. 01400 */ 01401 pwinsta = ppi->rpwinsta; 01402 if (pwinsta != NULL) { 01403 RETURN_IF_ACCESS_DENIED(ppi->amwinsta, amDesiredAccess, 01404 STATUS_ACCESS_DENIED); 01405 } 01406 } 01407 01408 /* 01409 * If we aren't using the process' windowstation, try to 01410 * go through the thread's desktop. 01411 */ 01412 if (pwinsta == NULL && pti != NULL && pti->rpdesk != NULL) { 01413 01414 /* 01415 * Perform access check the parent windowstation. This 01416 * is an expensive operation. 01417 */ 01418 pwinsta = pti->rpdesk->rpwinstaParent; 01419 if (!AccessCheckObject(pwinsta, amDesiredAccess, KernelMode, &WinStaMapping)) 01420 return STATUS_ACCESS_DENIED; 01421 } 01422 } 01423 01424 /* 01425 * If we still don't have a windowstation and a handle was 01426 * passed in, use it. 01427 */ 01428 if (pwinsta == NULL) { 01429 if (hwinsta != NULL) { 01430 Status = ObReferenceObjectByHandle( 01431 hwinsta, 01432 amDesiredAccess, 01433 *ExWindowStationObjectType, 01434 KernelMode, 01435 &pwinsta, 01436 NULL); 01437 if (!NT_SUCCESS(Status)) 01438 return Status; 01439 ObDereferenceObject(pwinsta); 01440 } else { 01441 return STATUS_NOT_FOUND; 01442 } 01443 } 01444 01445 *ppwinsta = pwinsta; 01446 01447 return STATUS_SUCCESS; 01448 } 01449 01450 /***************************************************************************\ 01451 * _SetWindowStationUser 01452 * 01453 * Private API for winlogon to associate a windowstation with a user. 01454 * 01455 * History: 01456 * 06-27-94 JimA Created. 01457 \***************************************************************************/ 01458 01459 UINT _SetWindowStationUser( 01460 PWINDOWSTATION pwinsta, 01461 PLUID pluidUser, 01462 PSID ccxpsidUser, 01463 DWORD cbsidUser) 01464 { 01465 01466 /* 01467 * Make sure the caller is the logon process 01468 */ 01469 if (GetCurrentProcessId() != gpidLogon) { 01470 RIPERR0(ERROR_ACCESS_DENIED, 01471 RIP_WARNING, 01472 "Access denied in _SetWindowStationUser: caller must be in the logon process"); 01473 01474 return FALSE; 01475 } 01476 01477 if (pwinsta->psidUser != NULL) 01478 UserFreePool(pwinsta->psidUser); 01479 01480 if (ccxpsidUser != NULL) { 01481 pwinsta->psidUser = UserAllocPoolWithQuota(cbsidUser, TAG_SECURITY); 01482 if (pwinsta->psidUser == NULL) { 01483 RIPERR0(ERROR_OUTOFMEMORY, 01484 RIP_WARNING, 01485 "Memory allocation failed in _SetWindowStationUser"); 01486 01487 return FALSE; 01488 } 01489 try { 01490 RtlCopyMemory(pwinsta->psidUser, ccxpsidUser, cbsidUser); 01491 } except (W32ExceptionHandler(TRUE, RIP_WARNING)) { 01492 01493 UserFreePool(pwinsta->psidUser); 01494 pwinsta->psidUser = NULL; 01495 return FALSE; 01496 } 01497 } else { 01498 pwinsta->psidUser = NULL; 01499 } 01500 01501 pwinsta->luidUser = *pluidUser; 01502 01503 return TRUE; 01504 } 01505 01506 01507 /***************************************************************************\ 01508 * _LockWorkStation (API) 01509 * 01510 * locks the workstation. This API just posts a message to winlogon 01511 * and winlogon does all the work 01512 * 01513 * History: 01514 * 06-11-97 CLupu Created. 01515 \***************************************************************************/ 01516 01517 BOOL _LockWorkStation( 01518 VOID) 01519 { 01520 UserAssert(gspwndLogonNotify != NULL); 01521 01522 _PostMessage(gspwndLogonNotify, 01523 WM_LOGONNOTIFY, LOGON_LOCKWORKSTATION, 0); 01524 01525 return TRUE; 01526 } 01527 01528 #ifdef LATER // HY 01529 BOOL _IsIoDesktop( 01530 HDESK hdesk) 01531 { 01532 BOOL fRet = FALSE; 01533 NTSTATUS Status; 01534 PDESKTOP pdesk = NULL; 01535 01536 Status = ValidateHdesk(hdesk, UserMode, 0, &pdesk); 01537 if (NT_SUCCESS(Status)) { 01538 UserAssert(pdesk && pdesk->rpwinstaParent); 01539 fRet = (pdesk->rpwinstaParent->dwWSF_Flags & WSF_NOIO) == 0; 01540 ObDereferenceObject(pdesk); 01541 } 01542 return fRet; 01543 } 01544 #endif 01545

Generated on Sat May 15 19:42:26 2004 for test by doxygen 1.3.7