Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

922 lines
30 KiB

  1. /*+
  2. *
  3. * Microsoft Windows
  4. * Copyright (C) Microsoft Corporation, 1997 - 1998.
  5. *
  6. * Name : cseclogn.cxx
  7. * Author:Jeffrey Richter (v-jeffrr)
  8. *
  9. * Abstract:
  10. * This is the client side for Secondary Logon Service
  11. * implemented as CreateProcessWithLogon API
  12. * in advapi32.dll
  13. *
  14. * Revision History:
  15. * PraeritG 10/8/97 To integrate this in to services.exe
  16. *
  17. -*/
  18. #define UNICODE
  19. #define SECURITY_WIN32
  20. #include <Windows.h>
  21. #include <wincred.h>
  22. #include <rpc.h>
  23. #include "seclogon.h"
  24. #include "security.h"
  25. #include "dbgdef.h"
  26. //
  27. // must move to winbase.h soon!
  28. #define LOGON_WITH_PROFILE 0x00000001
  29. #define LOGON_NETCREDENTIALS_ONLY 0x00000002
  30. //
  31. // Global function pointers to user32 functions
  32. // This is to dynamically load user32 when CreateProcessWithLogon
  33. // is called.
  34. //
  35. HMODULE hModule1 = NULL;
  36. typedef HDESK (*OPENDESKTOP) (
  37. LPWSTR lpszDesktop,
  38. DWORD dwFlags,
  39. BOOL fInherit,
  40. ACCESS_MASK dwDesiredAccess);
  41. OPENDESKTOP myOpenDesktop = NULL;
  42. typedef HDESK (*GETTHREADDESKTOP)(
  43. DWORD dwThreadId);
  44. GETTHREADDESKTOP myGetThreadDesktop = NULL;
  45. typedef BOOL (*CLOSEDESKTOP)(
  46. HDESK hDesktop);
  47. CLOSEDESKTOP myCloseDesktop = NULL;
  48. typedef HWINSTA (*OPENWINDOWSTATION)(
  49. LPWSTR lpszWinSta,
  50. BOOL fInherit,
  51. ACCESS_MASK dwDesiredAccess);
  52. OPENWINDOWSTATION myOpenWindowStation = NULL;
  53. typedef HWINSTA (*GETPROCESSWINDOWSTATION)(
  54. VOID);
  55. GETPROCESSWINDOWSTATION myGetProcessWindowStation = NULL;
  56. typedef BOOL (*SETPROCESSWINDOWSTATION)(HWINSTA hWinSta);
  57. SETPROCESSWINDOWSTATION mySetProcessWindowStation;
  58. typedef BOOL (*CLOSEWINDOWSTATION)(
  59. HWINSTA hWinSta);
  60. CLOSEWINDOWSTATION myCloseWindowStation = NULL;
  61. typedef BOOL (*SETUSEROBJECTSECURITY)(
  62. HANDLE hObj,
  63. PSECURITY_INFORMATION pSIRequested,
  64. PSECURITY_DESCRIPTOR pSID);
  65. SETUSEROBJECTSECURITY mySetUserObjectSecurity = NULL;
  66. typedef BOOL (*GETUSEROBJECTSECURITY)(
  67. HANDLE hObj,
  68. PSECURITY_INFORMATION pSIRequested,
  69. PSECURITY_DESCRIPTOR pSID,
  70. DWORD nLength,
  71. LPDWORD lpnLengthNeeded);
  72. GETUSEROBJECTSECURITY myGetUserObjectSecurity = NULL;
  73. typedef BOOL (*GETUSEROBJECTINFORMATION)(
  74. HANDLE hObj,
  75. int nIndex,
  76. PVOID pvInfo,
  77. DWORD nLength,
  78. LPDWORD lpnLengthNeeded);
  79. GETUSEROBJECTINFORMATION myGetUserObjectInformation = NULL;
  80. ////////////////////////////////////////////////////////////////////////
  81. //
  82. // Function prototypes:
  83. //
  84. ////////////////////////////////////////////////////////////////////////
  85. DWORD c_SeclCreateProcessWithLogonW(IN SECL_SLI *psli,
  86. OUT SECL_SLRI *pslri);
  87. DWORD To_SECL_BLOB_A(IN LPVOID lpEnvironment,
  88. OUT SECL_BLOB *psb);
  89. DWORD To_SECL_BLOB_W(IN LPVOID lpEnvironment,
  90. OUT SECL_BLOB *psb);
  91. /////////////////////////////////////////////////////////////////////////
  92. //
  93. // Useful macros:
  94. //
  95. /////////////////////////////////////////////////////////////////////////
  96. #define ARRAYSIZE(array) ((sizeof(array)) / (sizeof(array[0])))
  97. #define ASSIGN_SECL_STRING(ss, wsz) \
  98. { \
  99. ss.pwsz = wsz; \
  100. if (NULL != wsz) {\
  101. ss.ccLength = ss.ccSize = (wcslen(wsz) + 1); \
  102. } \
  103. else { \
  104. ss.ccLength = ss.ccSize = 0; \
  105. } \
  106. }
  107. ////////////////////////////////////////////////////////////////////////
  108. //
  109. // Module implementation:
  110. //
  111. //////////////////////////////////////////////////////////////////////////
  112. extern "C" void *__cdecl _alloca(size_t);
  113. BOOL
  114. WINAPI
  115. CreateProcessWithLogonW(
  116. LPCWSTR lpUsername,
  117. LPCWSTR lpDomain,
  118. LPCWSTR lpPassword,
  119. DWORD dwLogonFlags,
  120. LPCWSTR lpApplicationName,
  121. LPWSTR lpCommandLine,
  122. DWORD dwCreationFlags,
  123. LPVOID lpEnvironment,
  124. LPCWSTR lpCurrentDirectory,
  125. LPSTARTUPINFOW lpStartupInfo,
  126. LPPROCESS_INFORMATION lpProcessInformation)
  127. /*++
  128. Routine Description:
  129. Arguments:
  130. Return Value:
  131. --*/
  132. {
  133. BOOL AccessWasAllowed = FALSE;
  134. BOOL fOk = FALSE;
  135. BOOL fRevertWinsta = FALSE;
  136. DWORD LastError = ERROR_SUCCESS;
  137. HANDLE hheap = GetProcessHeap();
  138. HDESK hDesk = NULL;
  139. HWINSTA hWinsta = NULL;
  140. HWINSTA hWinstaSave = NULL;
  141. LPWSTR pszApplName = NULL;
  142. LPWSTR pszCmdLine = NULL;
  143. LPWSTR pwszEmptyString = L"";
  144. SECL_SLI sli;
  145. SECL_SLRI slri;
  146. WCHAR wszDesktopName[2*MAX_PATH + 1];
  147. ZeroMemory(&sli, sizeof(sli));
  148. ZeroMemory(&slri, sizeof(slri));
  149. ZeroMemory(&wszDesktopName, sizeof(wszDesktopName));
  150. //
  151. // dynamically load user32.dll and resolve the functions.
  152. //
  153. // note: last error is left as returned by loadlib or getprocaddress
  154. if(hModule1 == NULL)
  155. {
  156. hModule1 = LoadLibrary(L"user32.dll");
  157. if(hModule1)
  158. {
  159. myOpenDesktop = (OPENDESKTOP) GetProcAddress(hModule1,
  160. "OpenDesktopW");
  161. if(!myOpenDesktop) return FALSE;
  162. myGetThreadDesktop = (GETTHREADDESKTOP)
  163. GetProcAddress( hModule1,
  164. "GetThreadDesktop");
  165. if(!myGetThreadDesktop) return FALSE;
  166. myCloseDesktop = (CLOSEDESKTOP) GetProcAddress(hModule1,
  167. "CloseDesktop");
  168. if(!myCloseDesktop) return FALSE;
  169. myOpenWindowStation = (OPENWINDOWSTATION)
  170. GetProcAddress(hModule1,
  171. "OpenWindowStationW");
  172. if(!myOpenWindowStation) return FALSE;
  173. myGetProcessWindowStation = (GETPROCESSWINDOWSTATION)
  174. GetProcAddress(hModule1,
  175. "GetProcessWindowStation");
  176. if(!myGetProcessWindowStation) return FALSE;
  177. mySetProcessWindowStation = (SETPROCESSWINDOWSTATION)GetProcAddress(hModule1, "SetProcessWindowStation");
  178. if (!mySetProcessWindowStation) return FALSE;
  179. myCloseWindowStation = (CLOSEWINDOWSTATION) GetProcAddress(hModule1,
  180. "CloseWindowStation");
  181. if(!myCloseWindowStation) return FALSE;
  182. myGetUserObjectSecurity = (GETUSEROBJECTSECURITY)
  183. GetProcAddress(hModule1,
  184. "GetUserObjectSecurity");
  185. if(!myGetUserObjectSecurity) return FALSE;
  186. mySetUserObjectSecurity = (SETUSEROBJECTSECURITY)
  187. GetProcAddress(hModule1,
  188. "SetUserObjectSecurity");
  189. if(!mySetUserObjectSecurity) return FALSE;
  190. myGetUserObjectInformation = (GETUSEROBJECTINFORMATION)
  191. GetProcAddress(hModule1,
  192. "GetUserObjectInformationW");
  193. if(!mySetUserObjectSecurity) return FALSE;
  194. }
  195. else
  196. {
  197. return FALSE;
  198. }
  199. }
  200. __try {
  201. //
  202. // JMR: Do these flags work: CREATE_SEPARATE_WOW_VDM,
  203. // CREATE_SHARED_WOW_VDM
  204. // Valid flags: CREATE_SUSPENDED, CREATE_UNICODE_ENVIRONMENT,
  205. // *_PRIORITY_CLASS
  206. //
  207. // The following flags are illegal. Fail the call if any are specified.
  208. //
  209. if ((dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS
  210. | DETACHED_PROCESS)) != 0) {
  211. LastError = ERROR_INVALID_PARAMETER;
  212. __leave;
  213. }
  214. if(dwLogonFlags & ~(LOGON_WITH_PROFILE | LOGON_NETCREDENTIALS_ONLY))
  215. {
  216. LastError = ERROR_INVALID_PARAMETER;
  217. __leave;
  218. }
  219. //
  220. // Turn on the flags that MUST be turned on
  221. //
  222. // We are overloading CREATE_NEW_CONSOLE to
  223. // CREATE_WITH_NETWORK_LOGON
  224. //
  225. dwCreationFlags |= CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE
  226. | CREATE_NEW_PROCESS_GROUP;
  227. //
  228. // If no priority class explicitly specified and this process is IDLE, force IDLE (See CreateProcess documentation)
  229. //
  230. if ((dwCreationFlags & (NORMAL_PRIORITY_CLASS | IDLE_PRIORITY_CLASS
  231. | HIGH_PRIORITY_CLASS
  232. | REALTIME_PRIORITY_CLASS)) == 0) {
  233. if (GetPriorityClass(GetCurrentProcess()) == IDLE_PRIORITY_CLASS)
  234. dwCreationFlags |= IDLE_PRIORITY_CLASS;
  235. }
  236. pszApplName = (LPWSTR) HeapAlloc(hheap, 0, sizeof(WCHAR) * (MAX_PATH));
  237. //
  238. // Lookup the fullpathname of the specified executable
  239. //
  240. pszCmdLine = (LPWSTR) HeapAlloc(hheap, 0, sizeof(WCHAR) *
  241. (MAX_PATH + lstrlenW(lpCommandLine)));
  242. if(pszApplName == NULL || pszCmdLine == NULL)
  243. {
  244. LastError = ERROR_INVALID_PARAMETER;
  245. __leave;
  246. }
  247. if(lpApplicationName == NULL)
  248. {
  249. if(lpCommandLine != NULL)
  250. {
  251. //
  252. // Commandline contains the name, we should parse it out and get
  253. // the full path so that correct executable is invoked.
  254. //
  255. DWORD Length;
  256. DWORD fileattr;
  257. WCHAR TempChar = L'\0';
  258. LPWSTR TempApplName = NULL;
  259. LPWSTR TempRemainderString = NULL;
  260. LPWSTR WhiteScan = NULL;
  261. BOOL SearchRetry = TRUE;
  262. LPWSTR ApplName = (LPWSTR) HeapAlloc(
  263. hheap, 0,
  264. sizeof(WCHAR) * (lstrlenW(lpCommandLine)+1));
  265. LPWSTR NameBuffer = (LPWSTR) HeapAlloc(
  266. hheap, 0,
  267. sizeof(WCHAR) * (MAX_PATH+1));
  268. if (ApplName == NULL || NameBuffer == NULL)
  269. {
  270. LastError = ERROR_NOT_ENOUGH_MEMORY;
  271. __leave;
  272. }
  273. lstrcpy(ApplName, lpCommandLine);
  274. WhiteScan = ApplName;
  275. //
  276. // if there is a leading quote
  277. //
  278. if(*WhiteScan == L'\"')
  279. {
  280. // we will NOT retry search, as app name is quoted.
  281. SearchRetry = FALSE;
  282. WhiteScan++;
  283. TempApplName = WhiteScan;
  284. while(*WhiteScan) {
  285. if( *WhiteScan == L'\"')
  286. {
  287. TempChar = *WhiteScan;
  288. *WhiteScan = L'\0';
  289. TempRemainderString = WhiteScan;
  290. break;
  291. }
  292. WhiteScan++;
  293. }
  294. }
  295. else
  296. {
  297. // skip to the first non-white char
  298. while(*WhiteScan) {
  299. if( *WhiteScan == L' ' || *WhiteScan == L'\t')
  300. {
  301. WhiteScan++;
  302. }
  303. else
  304. break;
  305. }
  306. TempApplName = WhiteScan;
  307. while(*WhiteScan) {
  308. if( *WhiteScan == L' ' || *WhiteScan == L'\t')
  309. {
  310. TempChar = *WhiteScan;
  311. *WhiteScan = L'\0';
  312. TempRemainderString = WhiteScan;
  313. break;
  314. }
  315. WhiteScan++;
  316. }
  317. }
  318. RetrySearch:
  319. Length = SearchPathW(
  320. NULL,
  321. TempApplName,
  322. (PWSTR)L".exe",
  323. MAX_PATH,
  324. NameBuffer,
  325. NULL
  326. );
  327. if(!Length || Length > MAX_PATH)
  328. {
  329. if(LastError)
  330. SetLastError(LastError);
  331. else
  332. LastError = GetLastError();
  333. CoverForDirectoryCase:
  334. //
  335. // If we still have command line left, then keep going
  336. // the point is to march through the command line looking
  337. // for whitespace so we can try to find an image name
  338. // launches of things like:
  339. // c:\word 95\winword.exe /embedding -automation
  340. // require this. Our first iteration will
  341. // stop at c:\word, our next
  342. // will stop at c:\word 95\winword.exe
  343. //
  344. if(TempRemainderString)
  345. {
  346. *TempRemainderString = TempChar;
  347. WhiteScan++;
  348. }
  349. if(*WhiteScan & SearchRetry)
  350. {
  351. // again skip to the first non-white char
  352. while(*WhiteScan) {
  353. if( *WhiteScan == L' ' || *WhiteScan == L'\t')
  354. {
  355. WhiteScan++;
  356. }
  357. else
  358. break;
  359. }
  360. while(*WhiteScan) {
  361. if( *WhiteScan == L' ' || *WhiteScan == L'\t')
  362. {
  363. TempChar = *WhiteScan;
  364. *WhiteScan = L'\0';
  365. TempRemainderString = WhiteScan;
  366. break;
  367. }
  368. WhiteScan++;
  369. }
  370. // we'll do one last try of the whole string.
  371. if(!WhiteScan) SearchRetry = FALSE;
  372. goto RetrySearch;
  373. }
  374. //
  375. // otherwise we have failed.
  376. //
  377. if(NameBuffer) HeapFree(hheap, 0, NameBuffer);
  378. if(ApplName) HeapFree(hheap, 0, ApplName);
  379. // we should let CreateProcess do its job.
  380. if (pszApplName)
  381. {
  382. HeapFree(hheap, 0, pszApplName);
  383. pszApplName = NULL;
  384. }
  385. lstrcpy(pszCmdLine, lpCommandLine);
  386. }
  387. else
  388. {
  389. // searchpath succeeded.
  390. // but it can find a directory!
  391. fileattr = GetFileAttributesW(NameBuffer);
  392. if ( fileattr != 0xffffffff &&
  393. (fileattr & FILE_ATTRIBUTE_DIRECTORY) ) {
  394. Length = 0;
  395. goto CoverForDirectoryCase;
  396. }
  397. //
  398. // so it is not a directory.. it must be the real thing!
  399. //
  400. lstrcpy(pszApplName, NameBuffer);
  401. lstrcpy(pszCmdLine, lpCommandLine);
  402. HeapFree(hheap, 0, ApplName);
  403. HeapFree(hheap, 0, NameBuffer);
  404. }
  405. }
  406. else
  407. {
  408. LastError = ERROR_INVALID_PARAMETER;
  409. __leave;
  410. }
  411. }
  412. else
  413. {
  414. //
  415. // If ApplicationName is not null, we need to handle
  416. // one case here -- the application name is present in
  417. // current directory. All other cases will be handled by
  418. // CreateProcess in the server side anyway.
  419. //
  420. //
  421. // let us get a FullPath relative to current directory
  422. // and try to open it. If it succeeds, then the full path
  423. // is what we'll give as app name.. otherwise will just
  424. // pass what we got from caller and let CreateProcess deal with it.
  425. LPWSTR lpFilePart;
  426. DWORD cchFullPath = GetFullPathName(
  427. lpApplicationName,
  428. MAX_PATH,
  429. pszApplName,
  430. &lpFilePart
  431. );
  432. if(cchFullPath)
  433. {
  434. HANDLE hFile;
  435. //
  436. // let us try to open it.
  437. // if it works, pszApplName is already setup correctly.
  438. // just close the handle.
  439. hFile = CreateFile(lpApplicationName, GENERIC_READ,
  440. FILE_SHARE_READ | FILE_SHARE_WRITE,
  441. NULL,
  442. OPEN_EXISTING,
  443. 0,
  444. NULL
  445. );
  446. if(hFile == INVALID_HANDLE_VALUE)
  447. {
  448. // otherwise, keep what the caller gave us.
  449. lstrcpy(pszApplName,lpApplicationName);
  450. }
  451. else
  452. CloseHandle(hFile);
  453. }
  454. else
  455. // lets keep what the caller gave us.
  456. lstrcpyn(pszApplName, lpApplicationName, MAX_PATH);
  457. //
  458. // Commandline should be kept as is.
  459. //
  460. if(lpCommandLine != NULL)
  461. lstrcpy(pszCmdLine, lpCommandLine);
  462. else
  463. {
  464. HeapFree(hheap, 0, pszCmdLine);
  465. pszCmdLine = NULL;
  466. }
  467. }
  468. #if 0
  469. if(lpApplicationName != NULL) lstrcpy(pszApplName,lpApplicationName);
  470. else {
  471. HeapFree(hheap, 0, pszApplName);
  472. pszApplName = NULL;
  473. }
  474. if(lpCommandLine != NULL) lstrcpy(pszCmdLine, lpCommandLine);
  475. else {
  476. HeapFree(hheap, 0, pszCmdLine);
  477. pszCmdLine = NULL;
  478. }
  479. #endif
  480. // Construct a memory block will all the info that needs to go to the server
  481. sli.lLogonIdHighPart = 0;
  482. sli.ulLogonIdLowPart = 0;
  483. sli.ulLogonFlags = dwLogonFlags;
  484. sli.ulProcessId = GetCurrentProcessId();
  485. sli.ulCreationFlags = dwCreationFlags;
  486. ASSIGN_SECL_STRING(sli.ssUsername, (LPWSTR) lpUsername);
  487. ASSIGN_SECL_STRING(sli.ssDomain, (LPWSTR) lpDomain);
  488. ASSIGN_SECL_STRING(sli.ssPassword, (LPWSTR)lpPassword);
  489. ASSIGN_SECL_STRING(sli.ssApplicationName, pszApplName);
  490. ASSIGN_SECL_STRING(sli.ssCommandLine, pszCmdLine);
  491. ASSIGN_SECL_STRING(sli.ssCurrentDirectory, (LPWSTR)lpCurrentDirectory);
  492. ASSIGN_SECL_STRING(sli.ssDesktop, lpStartupInfo->lpDesktop);
  493. ASSIGN_SECL_STRING(sli.ssTitle, lpStartupInfo->lpTitle);
  494. if (0 != (sli.ulCreationFlags & CREATE_UNICODE_ENVIRONMENT)) {
  495. LastError = To_SECL_BLOB_W(lpEnvironment, &(sli.sbEnvironment));
  496. }
  497. else {
  498. LastError = To_SECL_BLOB_A(lpEnvironment, &(sli.sbEnvironment));
  499. }
  500. if (ERROR_SUCCESS != LastError) { __leave; }
  501. // If the caller hasn't specified their own desktop, we'll do it for
  502. // them (the seclogon service will take care of granting access
  503. // to the desktop).
  504. if (sli.ssDesktop.pwsz == NULL || sli.ssDesktop.pwsz[0] == L'\0')
  505. {
  506. DWORD Length;
  507. HWINSTA Winsta = myGetProcessWindowStation();
  508. HDESK Desk = myGetThreadDesktop(GetCurrentThreadId());
  509. // Send seclogon handles to the current windowstation and desktop:
  510. if (0 == (dwLogonFlags & LOGON_NETCREDENTIALS_ONLY))
  511. {
  512. sli.hWinsta = (unsigned __int64)Winsta;
  513. sli.hDesk = (unsigned __int64)Desk;
  514. }
  515. else
  516. {
  517. // In the /netonly case, we don't need to grant access to the desktop:
  518. sli.hWinsta = 0;
  519. sli.hDesk = 0;
  520. }
  521. // Send seclogon the name of the current windowstation and desktop.
  522. // Default to empty string if we can't get the name:
  523. ASSIGN_SECL_STRING(sli.ssDesktop, pwszEmptyString);
  524. if (myGetUserObjectInformation(Winsta, UOI_NAME, wszDesktopName, (MAX_PATH*sizeof(WCHAR)), &Length))
  525. {
  526. Length = wcslen(wszDesktopName);
  527. wszDesktopName[Length++] = L'\\';
  528. if(myGetUserObjectInformation(Desk, UOI_NAME, &wszDesktopName[Length], (MAX_PATH*sizeof(WCHAR)), &Length))
  529. {
  530. // sli.ssDesktop now contains "windowstation\desktop"
  531. ASSIGN_SECL_STRING(sli.ssDesktop, wszDesktopName);
  532. }
  533. }
  534. }
  535. else
  536. {
  537. LPWSTR pwszDeskName;
  538. // The caller specified their own desktop
  539. sli.ulSeclogonFlags |= SECLOGON_CALLER_SPECIFIED_DESKTOP;
  540. // Open a handle to the specified windowstation and desktop:
  541. wcscpy(wszDesktopName, sli.ssDesktop.pwsz);
  542. pwszDeskName = wcschr(wszDesktopName, L'\\');
  543. if (NULL == pwszDeskName)
  544. {
  545. SetLastError(ERROR_INVALID_PARAMETER);
  546. __leave;
  547. }
  548. *pwszDeskName++ = L'\0';
  549. hWinsta = myOpenWindowStation(wszDesktopName, TRUE, MAXIMUM_ALLOWED);
  550. if (NULL == hWinsta)
  551. __leave;
  552. hWinstaSave = myGetProcessWindowStation();
  553. if (NULL == hWinstaSave)
  554. __leave;
  555. if (!mySetProcessWindowStation(hWinsta))
  556. __leave;
  557. fRevertWinsta = TRUE;
  558. hDesk = myOpenDesktop(pwszDeskName, 0, TRUE, MAXIMUM_ALLOWED);
  559. if (NULL == hDesk)
  560. __leave;
  561. // Pass the windowstation and desktop handles to seclogon:
  562. sli.hWinsta = (unsigned __int64)hWinsta;
  563. sli.hDesk = (unsigned __int64)hDesk;
  564. }
  565. // Perform the RPC call to the seclogon service:
  566. LastError = c_SeclCreateProcessWithLogonW(&sli, &slri);
  567. if (ERROR_SUCCESS != LastError) __leave;
  568. fOk = (slri.ulErrorCode == NO_ERROR); // This function succeeds if the server's function succeeds
  569. if (!fOk) {
  570. //
  571. // If the server function failed, set the server's
  572. // returned eror code as this thread's error code
  573. //
  574. LastError = slri.ulErrorCode;
  575. SetLastError(slri.ulErrorCode);
  576. } else {
  577. //
  578. // The server function succeeded, return the
  579. // PROCESS_INFORMATION info
  580. //
  581. lpProcessInformation->hProcess = (HANDLE)slri.hProcess;
  582. lpProcessInformation->hThread = (HANDLE)slri.hThread;
  583. lpProcessInformation->dwProcessId = slri.ulProcessId;
  584. lpProcessInformation->dwThreadId = slri.ulThreadId;
  585. LastError = ERROR_SUCCESS;
  586. }
  587. }
  588. __finally {
  589. if (NULL != pszCmdLine) HeapFree(hheap, 0, pszCmdLine);
  590. if (NULL != pszApplName) HeapFree(hheap, 0, pszApplName);
  591. if (fRevertWinsta) mySetProcessWindowStation(hWinstaSave);
  592. if (NULL != hWinsta) myCloseWindowStation(hWinsta);
  593. if (NULL != hDesk) myCloseDesktop(hDesk);
  594. SetLastError(LastError);
  595. }
  596. return(fOk);
  597. }
  598. ////////////////////////////////////////////////////////////////////////
  599. //
  600. // RPC Utility methods:
  601. //
  602. ////////////////////////////////////////////////////////////////////////
  603. DWORD To_SECL_BLOB_W(IN LPVOID lpEnvironment,
  604. OUT SECL_BLOB *psb) {
  605. DWORD cb = 0;
  606. DWORD dwResult = NULL;
  607. HANDLE hHeap = NULL;
  608. LPBYTE pb = NULL;
  609. LPWSTR pwsz = NULL;
  610. hHeap = GetProcessHeap();
  611. _JumpCondition(NULL == hHeap, GetProcessHeapError);
  612. if (NULL != lpEnvironment) {
  613. for (pwsz = (LPWSTR)lpEnvironment; pwsz[0] != L'\0'; pwsz += wcslen(pwsz) + 1);
  614. cb = sizeof(WCHAR) * (DWORD)(((1 + (pwsz - (LPWSTR)lpEnvironment))) & 0xFFFFFFFF);
  615. pb = (LPBYTE)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, cb);
  616. _JumpCondition(NULL == pb, MemoryError);
  617. CopyMemory(pb, (LPBYTE)lpEnvironment, cb);
  618. }
  619. psb->cb = cb;
  620. psb->pb = pb;
  621. dwResult = ERROR_SUCCESS;
  622. CommonReturn:
  623. return dwResult;
  624. ErrorReturn:
  625. if (NULL != pb) { HeapFree(hHeap, 0, pb); }
  626. goto CommonReturn;
  627. SET_DWRESULT(GetProcessHeapError, GetLastError());
  628. SET_DWRESULT(MemoryError, ERROR_NOT_ENOUGH_MEMORY);
  629. }
  630. DWORD To_SECL_BLOB_A(IN LPVOID lpEnvironment,
  631. OUT SECL_BLOB *psb) {
  632. DWORD cb = 0;
  633. DWORD dwResult;
  634. HANDLE hHeap = NULL;
  635. LPBYTE pb = NULL;
  636. LPSTR psz = NULL;
  637. hHeap = GetProcessHeap();
  638. _JumpCondition(NULL == hHeap, GetProcessHeapError);
  639. if (NULL != lpEnvironment) {
  640. for (psz = (LPSTR)lpEnvironment; psz[0] != '\0'; psz += strlen(psz) + 1);
  641. cb = (DWORD)((1 + (psz - (LPSTR)lpEnvironment) & 0xFFFFFFFF));
  642. pb = (LPBYTE)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, cb);
  643. _JumpCondition(NULL == pb, MemoryError);
  644. CopyMemory(pb, (LPBYTE)lpEnvironment, cb);
  645. }
  646. psb->cb = cb;
  647. psb->pb = pb;
  648. dwResult = ERROR_SUCCESS;
  649. CommonReturn:
  650. return dwResult;
  651. ErrorReturn:
  652. if (NULL != pb) { HeapFree(hHeap, 0, pb); }
  653. goto CommonReturn;
  654. SET_DWRESULT(GetProcessHeapError, GetLastError());
  655. SET_DWRESULT(MemoryError, ERROR_NOT_ENOUGH_MEMORY);
  656. }
  657. DWORD StartSeclogonService() {
  658. BOOL fResult;
  659. DWORD dwInitialCount;
  660. DWORD dwResult;
  661. SC_HANDLE hSCM;
  662. SC_HANDLE hService;
  663. SERVICE_STATUS sSvcStatus;
  664. hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  665. _JumpCondition(hSCM == NULL, OpenSCManagerError);
  666. hService = OpenService(hSCM, wszSvcName, SERVICE_START | SERVICE_QUERY_STATUS);
  667. _JumpCondition(NULL == hService, OpenServiceError);
  668. fResult = StartService(hService, NULL, NULL);
  669. _JumpCondition(FALSE == fResult, StartServiceError);
  670. // Wait until the service has actually started.
  671. // Set timeout to 20 seconds.
  672. dwInitialCount = GetTickCount();
  673. // Keep polling to see if the service has started ...
  674. while (TRUE)
  675. {
  676. fResult = QueryServiceStatus(hService, &sSvcStatus);
  677. _JumpCondition(FALSE == fResult, QueryServiceStatusError);
  678. // The service is running. We can stop waiting for it.
  679. if (sSvcStatus.dwCurrentState == SERVICE_RUNNING)
  680. break;
  681. // Check to see if we've timed out. If GetTickCount() rolls over,
  682. // then at worst we time out early.
  683. _JumpCondition((GetTickCount() - dwInitialCount) > 20000, ServiceTimeoutError);
  684. // Don't hose the service.
  685. SleepEx(100, FALSE);
  686. }
  687. // Ok, the service has successfully started.
  688. dwResult = ERROR_SUCCESS;
  689. CommonReturn:
  690. if (NULL != hSCM) { CloseServiceHandle(hSCM); }
  691. if (NULL != hService) { CloseServiceHandle(hService); }
  692. return dwResult;
  693. ErrorReturn:
  694. goto CommonReturn;
  695. SET_DWRESULT(OpenSCManagerError, GetLastError());
  696. SET_DWRESULT(OpenServiceError, GetLastError());
  697. SET_DWRESULT(QueryServiceStatusError, GetLastError());
  698. SET_DWRESULT(StartServiceError, GetLastError());
  699. SET_DWRESULT(ServiceTimeoutError, ERROR_SERVICE_REQUEST_TIMEOUT);
  700. }
  701. DWORD c_SeclCreateProcessWithLogonW
  702. (IN SECL_SLI *psli,
  703. OUT SECL_SLRI *pslri)
  704. {
  705. BOOL fResult;
  706. DWORD dwResult;
  707. LPWSTR pwszBinding = NULL;
  708. RPC_BINDING_HANDLE hRPCBinding = NULL;
  709. dwResult = RpcStringBindingCompose
  710. (NULL,
  711. (USHORT *)L"ncacn_np",
  712. NULL,
  713. (USHORT *)L"\\PIPE\\" wszSeclogonSharedProcEndpointName,
  714. (USHORT *)L"Security=impersonation static false",
  715. (USHORT **)&pwszBinding);
  716. _JumpCondition(RPC_S_OK != dwResult, RpcStringBindingComposeError);
  717. dwResult = RpcBindingFromStringBinding((USHORT *)pwszBinding, &hRPCBinding);
  718. _JumpCondition(0 != dwResult, RpcBindingFromStringBindingError);
  719. // Perform the RPC call to the seclogon service. If the call fails because the
  720. // service was not started, try again. If the call still fails, give up.
  721. for (BOOL fFirstTry = TRUE; TRUE; fFirstTry = FALSE) {
  722. __try {
  723. SeclCreateProcessWithLogonW(hRPCBinding, psli, pslri);
  724. break;
  725. }
  726. __except(EXCEPTION_EXECUTE_HANDLER) {
  727. dwResult = RpcExceptionCode();
  728. if ((RPC_S_SERVER_UNAVAILABLE == dwResult || RPC_S_UNKNOWN_IF == dwResult) &&
  729. (TRUE == fFirstTry)) {
  730. // Ok, the seclogon service is probably just not started.
  731. // Attempt to start it up and try again.
  732. dwResult = StartSeclogonService();
  733. _JumpCondition(ERROR_SUCCESS != dwResult, SeclCreateProcessWithLogonWError);
  734. }
  735. else {
  736. goto SeclCreateProcessWithLogonWError;
  737. }
  738. }
  739. }
  740. dwResult = ERROR_SUCCESS;
  741. CommonReturn:
  742. if (NULL != pwszBinding) { RpcStringFree((USHORT **)&pwszBinding); }
  743. if (NULL != hRPCBinding) { RpcBindingFree(&hRPCBinding); }
  744. return dwResult;
  745. ErrorReturn:
  746. goto CommonReturn;
  747. SET_DWRESULT(RpcBindingFromStringBindingError, dwResult);
  748. SET_DWRESULT(RpcStringBindingComposeError, dwResult);
  749. SET_DWRESULT(SeclCreateProcessWithLogonWError, dwResult);
  750. }
  751. void DbgPrintf( DWORD dwSubSysId, LPCSTR pszFormat , ...)
  752. {
  753. }
  754. //////////////////////////////// End Of File /////////////////////////////////