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.

710 lines
18 KiB

  1. #include <nt.h>
  2. #include <ntrtl.h>
  3. #include <nturtl.h>
  4. #include <windows.h>
  5. #include <shellapi.h>
  6. #include "SmartPtr.h"
  7. #include "strings.h"
  8. extern "C"
  9. {
  10. void PrependToPath( LPWSTR, LPWSTR*);
  11. void PathUnquoteSpaces( LPWSTR );
  12. void UpdateUserEnvironment();
  13. BOOL RegDelnode( HKEY, LPWSTR );
  14. LPWSTR GetSidString( HANDLE UserToken );
  15. void DeleteSidString( LPWSTR SidString );
  16. };
  17. #define GPO_SCRIPTS_KEY L"Software\\Policies\\Microsoft\\Windows\\System\\Scripts"
  18. #define GP_STATE_KEY L"Software\\Microsoft\\Windows\\CurrentVersion\\Group Policy\\State"
  19. #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
  20. #define SCRIPT L"Script"
  21. #define PARAMETERS L"Parameters"
  22. #define EXECTIME L"ExecTime"
  23. #define GPOID L"GPO-ID"
  24. #define SOMID L"SOM-ID"
  25. #define FILESYSPATH L"FileSysPath"
  26. #define SCR_STARTUP L"Startup"
  27. #define SCR_SHUTDOWN L"Shutdown"
  28. #define SCR_LOGON L"Logon"
  29. #define SCR_LOGOFF L"Logoff"
  30. LPTSTR
  31. CheckSlash (LPTSTR lpDir)
  32. {
  33. LPTSTR lpEnd;
  34. lpEnd = lpDir + lstrlen(lpDir);
  35. if (*(lpEnd - 1) != TEXT('\\')) {
  36. *lpEnd = TEXT('\\');
  37. lpEnd++;
  38. *lpEnd = TEXT('\0');
  39. }
  40. return lpEnd;
  41. }
  42. BOOL
  43. RegDelnodeRecurse (HKEY hKeyRoot, LPTSTR lpSubKey)
  44. {
  45. LPTSTR lpEnd;
  46. LONG lResult;
  47. DWORD dwSize;
  48. TCHAR szName[MAX_PATH];
  49. HKEY hKey;
  50. FILETIME ftWrite;
  51. //
  52. // First, see if we can delete the key without having
  53. // to recurse.
  54. //
  55. lResult = RegDeleteKey(hKeyRoot, lpSubKey);
  56. if (lResult == ERROR_SUCCESS) {
  57. return TRUE;
  58. }
  59. lResult = RegOpenKeyEx (hKeyRoot, lpSubKey, 0, KEY_READ, &hKey);
  60. if (lResult != ERROR_SUCCESS) {
  61. return FALSE;
  62. }
  63. lpEnd = CheckSlash(lpSubKey);
  64. //
  65. // Enumerate the keys
  66. //
  67. dwSize = MAX_PATH;
  68. lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL,
  69. NULL, NULL, &ftWrite);
  70. if (lResult == ERROR_SUCCESS) {
  71. do {
  72. lstrcpy (lpEnd, szName);
  73. if (!RegDelnodeRecurse(hKeyRoot, lpSubKey)) {
  74. break;
  75. }
  76. //
  77. // Enumerate again
  78. //
  79. dwSize = MAX_PATH;
  80. lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL,
  81. NULL, NULL, &ftWrite);
  82. } while (lResult == ERROR_SUCCESS);
  83. }
  84. lpEnd--;
  85. *lpEnd = TEXT('\0');
  86. RegCloseKey (hKey);
  87. //
  88. // Try again to delete the key
  89. //
  90. lResult = RegDeleteKey(hKeyRoot, lpSubKey);
  91. if (lResult == ERROR_SUCCESS) {
  92. return TRUE;
  93. }
  94. return FALSE;
  95. }
  96. BOOL
  97. RegDelnode (HKEY hKeyRoot, LPTSTR lpSubKey)
  98. {
  99. TCHAR szDelKey[2 * MAX_PATH];
  100. lstrcpy (szDelKey, lpSubKey);
  101. return RegDelnodeRecurse(hKeyRoot, szDelKey);
  102. }
  103. PSID
  104. GetUserSid( HANDLE UserToken )
  105. {
  106. XPtrLF<TOKEN_USER> pUser;
  107. PTOKEN_USER pTemp;
  108. PSID pSid;
  109. DWORD BytesRequired = 200;
  110. NTSTATUS status;
  111. //
  112. // Allocate space for the user info
  113. //
  114. pUser = (PTOKEN_USER) LocalAlloc( LMEM_FIXED, BytesRequired );
  115. if ( !pUser )
  116. {
  117. return 0;
  118. }
  119. //
  120. // Read in the UserInfo
  121. //
  122. status = NtQueryInformationToken(
  123. UserToken, // Handle
  124. TokenUser, // TokenInformationClass
  125. pUser, // TokenInformation
  126. BytesRequired, // TokenInformationLength
  127. &BytesRequired // ReturnLength
  128. );
  129. if ( status == STATUS_BUFFER_TOO_SMALL )
  130. {
  131. //
  132. // Allocate a bigger buffer and try again.
  133. //
  134. pTemp = (PTOKEN_USER) LocalReAlloc( pUser, BytesRequired, LMEM_MOVEABLE );
  135. if ( !pTemp )
  136. {
  137. return 0;
  138. }
  139. pUser = pTemp;
  140. status = NtQueryInformationToken(
  141. UserToken, // Handle
  142. TokenUser, // TokenInformationClass
  143. pUser, // TokenInformation
  144. BytesRequired, // TokenInformationLength
  145. &BytesRequired // ReturnLength
  146. );
  147. }
  148. if ( !NT_SUCCESS(status) )
  149. {
  150. return 0;
  151. }
  152. BytesRequired = RtlLengthSid(pUser->User.Sid);
  153. pSid = LocalAlloc(LMEM_FIXED, BytesRequired);
  154. if ( !pSid )
  155. {
  156. return NULL;
  157. }
  158. status = RtlCopySid(BytesRequired, pSid, pUser->User.Sid);
  159. if ( !NT_SUCCESS(status) )
  160. {
  161. LocalFree(pSid);
  162. pSid = 0;
  163. }
  164. return pSid;
  165. }
  166. LPWSTR
  167. GetSidString( HANDLE UserToken )
  168. {
  169. NTSTATUS NtStatus;
  170. PSID UserSid;
  171. UNICODE_STRING UnicodeString;
  172. //
  173. // Get the user sid
  174. //
  175. UserSid = GetUserSid( UserToken );
  176. if ( !UserSid )
  177. {
  178. return 0;
  179. }
  180. //
  181. // Convert user SID to a string.
  182. //
  183. NtStatus = RtlConvertSidToUnicodeString(&UnicodeString,
  184. UserSid,
  185. (BOOLEAN)TRUE ); // Allocate
  186. LocalFree( UserSid );
  187. if ( !NT_SUCCESS(NtStatus) )
  188. {
  189. return 0;
  190. }
  191. return UnicodeString.Buffer ;
  192. }
  193. void
  194. DeleteSidString( LPWSTR SidString )
  195. {
  196. UNICODE_STRING String;
  197. RtlInitUnicodeString( &String, SidString );
  198. RtlFreeUnicodeString( &String );
  199. }
  200. typedef BOOL (*PFNSHELLEXECUTEEX)(LPSHELLEXECUTEINFO lpExecInfo);
  201. DWORD
  202. ExecuteScript( LPWSTR szCmdLine,
  203. LPWSTR szArgs,
  204. LPWSTR szWorkingDir,
  205. BOOL bSync,
  206. BOOL bHide,
  207. BOOL bRunMin,
  208. LPWSTR szType,
  209. PFNSHELLEXECUTEEX pfnShellExecuteEx,
  210. HANDLE hEventLog )
  211. {
  212. WCHAR szCmdLineEx[MAX_PATH];
  213. WCHAR szArgsEx[3 * MAX_PATH];
  214. WCHAR szCurDir[MAX_PATH];
  215. LPWSTR szOldPath = 0;
  216. BOOL bResult;
  217. DWORD dwError;
  218. SHELLEXECUTEINFO ExecInfo;
  219. if ( GetSystemDirectory( szCurDir, ARRAYSIZE( szCurDir ) ) )
  220. {
  221. SetCurrentDirectory( szCurDir );
  222. }
  223. //
  224. // Expand the command line and args
  225. //
  226. ExpandEnvironmentStrings( szCmdLine, szCmdLineEx, ARRAYSIZE(szCmdLineEx) );
  227. ExpandEnvironmentStrings( szArgs, szArgsEx, ARRAYSIZE(szArgsEx) );
  228. //
  229. // Put the working directory on the front of the PATH
  230. // environment variable
  231. //
  232. PrependToPath( szWorkingDir, &szOldPath );
  233. //
  234. // Run the script
  235. //
  236. PathUnquoteSpaces( szCmdLineEx );
  237. ZeroMemory(&ExecInfo, sizeof(ExecInfo));
  238. ExecInfo.cbSize = sizeof(ExecInfo);
  239. ExecInfo.fMask = SEE_MASK_DOENVSUBST |
  240. SEE_MASK_FLAG_NO_UI |
  241. SEE_MASK_NOZONECHECKS |
  242. SEE_MASK_NOCLOSEPROCESS;
  243. ExecInfo.lpFile = szCmdLineEx;
  244. ExecInfo.lpParameters = !szArgsEx[0] ? 0 : szArgsEx;
  245. ExecInfo.lpDirectory = szWorkingDir;
  246. if ( bHide )
  247. {
  248. ExecInfo.nShow = SW_HIDE;
  249. }
  250. else
  251. {
  252. ExecInfo.nShow = (bRunMin ? SW_SHOWMINNOACTIVE : SW_SHOWNORMAL );
  253. }
  254. bResult = pfnShellExecuteEx( &ExecInfo );
  255. dwError = GetLastError();
  256. //
  257. // Put the PATH environment variable back the way it was
  258. //
  259. if ( szOldPath )
  260. {
  261. SetEnvironmentVariable( L"PATH", szOldPath );
  262. LocalFree( szOldPath );
  263. szOldPath = 0;
  264. }
  265. if ( bResult )
  266. {
  267. dwError = 0;
  268. if (bSync)
  269. {
  270. WaitForSingleObject(ExecInfo.hProcess, INFINITE);
  271. UpdateUserEnvironment();
  272. }
  273. CloseHandle(ExecInfo.hProcess);
  274. }
  275. else
  276. {
  277. if ( hEventLog != 0 )
  278. {
  279. LPWSTR szMsgBuf[2] = { (LPTSTR) ExecInfo.lpFile, 0 };
  280. FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  281. 0,
  282. dwError,
  283. 0,
  284. (LPTSTR) (&szMsgBuf[1]),
  285. 1,
  286. 0);
  287. ReportEvent(hEventLog,
  288. EVENTLOG_ERROR_TYPE,
  289. 0,
  290. SHELLEXEC_ERROR,
  291. 0,
  292. 2,
  293. 0,
  294. (LPCTSTR*) &szMsgBuf,
  295. 0);
  296. if ( szMsgBuf[1] )
  297. {
  298. LocalFree( szMsgBuf[1] );
  299. }
  300. }
  301. }
  302. return dwError;
  303. }
  304. ScrExecGPOFromReg( HKEY hKeyGPO,
  305. HKEY hKeyStateGPO,
  306. BOOL bSync,
  307. BOOL bHidden,
  308. BOOL bRunMin,
  309. LPWSTR szType,
  310. PFNSHELLEXECUTEEX pfnShellExecuteEx,
  311. HANDLE hEventLog )
  312. {
  313. DWORD dwError = ERROR_SUCCESS;
  314. DWORD cSubKeys = 0;
  315. WCHAR szFileSysPath[3*MAX_PATH];
  316. DWORD dwType;
  317. DWORD dwSize;
  318. //
  319. // FILESYSPATH
  320. //
  321. dwType = REG_SZ;
  322. dwSize = sizeof( szFileSysPath );
  323. dwError = RegQueryValueEx( hKeyGPO,
  324. FILESYSPATH,
  325. 0,
  326. &dwType,
  327. (LPBYTE) szFileSysPath,
  328. &dwSize );
  329. if ( dwError != ERROR_SUCCESS )
  330. {
  331. return dwError;
  332. }
  333. wcscat( szFileSysPath, L"\\Scripts\\" );
  334. wcscat( szFileSysPath, szType );
  335. //
  336. // get the numer of Scripts
  337. //
  338. dwError = RegQueryInfoKey( hKeyGPO,
  339. 0,
  340. 0,
  341. 0,
  342. &cSubKeys,
  343. 0,
  344. 0,
  345. 0,
  346. 0,
  347. 0,
  348. 0,
  349. 0 );
  350. if ( dwError == ERROR_SUCCESS )
  351. {
  352. //
  353. // for every Script
  354. //
  355. for ( DWORD dwIndex = 0 ; dwIndex < cSubKeys ; dwIndex++ )
  356. {
  357. XKey hKeyScript;
  358. XKey hKeyStateScript;
  359. WCHAR szTemp[32];
  360. dwError = RegOpenKeyEx( hKeyStateGPO,
  361. _itow( dwIndex, szTemp, 16 ),
  362. 0,
  363. KEY_ALL_ACCESS,
  364. &hKeyStateScript );
  365. if ( dwError != ERROR_SUCCESS )
  366. {
  367. return dwError;
  368. }
  369. //
  370. // open the Script key (we need only read perms)
  371. //
  372. dwError = RegOpenKeyEx( hKeyGPO,
  373. szTemp,
  374. 0,
  375. KEY_READ,
  376. &hKeyScript );
  377. if ( dwError != ERROR_SUCCESS )
  378. {
  379. return dwError;
  380. }
  381. WCHAR szScript[MAX_PATH];
  382. WCHAR szParameters[MAX_PATH];
  383. SYSTEMTIME execTime;
  384. //
  385. // script
  386. //
  387. dwType = REG_SZ;
  388. dwSize = sizeof( szScript );
  389. dwError = RegQueryValueEx( hKeyScript,
  390. SCRIPT,
  391. 0,
  392. &dwType,
  393. (LPBYTE) szScript,
  394. &dwSize );
  395. if ( dwError != ERROR_SUCCESS )
  396. {
  397. break;
  398. }
  399. //
  400. // parameters
  401. //
  402. dwType = REG_SZ;
  403. dwSize = sizeof( szParameters );
  404. dwError = RegQueryValueEx( hKeyScript,
  405. PARAMETERS,
  406. 0,
  407. &dwType,
  408. (LPBYTE) szParameters,
  409. &dwSize );
  410. if ( dwError != ERROR_SUCCESS )
  411. {
  412. break;
  413. }
  414. //
  415. // execute script
  416. //
  417. GetSystemTime( &execTime );
  418. dwError = ExecuteScript(szScript,
  419. szParameters,
  420. szFileSysPath,
  421. bSync,
  422. bHidden,
  423. bRunMin,
  424. szType,
  425. pfnShellExecuteEx,
  426. hEventLog );
  427. if ( dwError != ERROR_SUCCESS )
  428. {
  429. ZeroMemory( &execTime, sizeof( execTime ) );
  430. }
  431. //
  432. // write exec time
  433. //
  434. RegSetValueEx( hKeyStateScript,
  435. EXECTIME,
  436. 0,
  437. REG_QWORD,
  438. (LPBYTE) &execTime,
  439. sizeof( execTime ) );
  440. }
  441. }
  442. return dwError;
  443. }
  444. extern "C" DWORD
  445. ScrExecGPOListFromReg( LPWSTR szType,
  446. BOOL bMachine,
  447. BOOL bSync,
  448. BOOL bHidden,
  449. BOOL bRunMin,
  450. HANDLE hEventLog )
  451. {
  452. DWORD dwError = ERROR_SUCCESS;
  453. WCHAR szBuffer[MAX_PATH];
  454. XKey hKeyType;
  455. XKey hKeyState;
  456. XKey hKeyStateType;
  457. //
  458. // create the following key
  459. // HKLM\Software\Microsoft\Windows\CurrentVersion\Group Policy\State\<Target>\Scripts\<Type>
  460. //
  461. wcscpy( szBuffer, GP_STATE_KEY L"\\" );
  462. if ( bMachine )
  463. {
  464. wcscat( szBuffer, L"Machine\\Scripts" );
  465. }
  466. else
  467. {
  468. XHandle hToken;
  469. if ( !OpenProcessToken( GetCurrentProcess(),
  470. TOKEN_ALL_ACCESS,
  471. &hToken ) )
  472. {
  473. return GetLastError();
  474. }
  475. LPWSTR szSid = GetSidString( hToken );
  476. if ( !szSid )
  477. {
  478. return GetLastError();
  479. }
  480. wcscat( szBuffer, szSid );
  481. wcscat( szBuffer, L"\\Scripts" );
  482. DeleteSidString( szSid );
  483. }
  484. //
  485. // state
  486. //
  487. dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  488. szBuffer,
  489. 0,
  490. KEY_ALL_ACCESS,
  491. &hKeyState );
  492. if ( dwError != ERROR_SUCCESS )
  493. {
  494. return dwError;
  495. }
  496. dwError = RegOpenKeyEx( hKeyState,
  497. szType,
  498. 0,
  499. KEY_ALL_ACCESS,
  500. &hKeyStateType );
  501. if ( dwError != ERROR_SUCCESS )
  502. {
  503. return dwError;
  504. }
  505. //
  506. // construct "Software\\Policies\\Microsoft\\Windows\\System\\Scripts\\<Type>
  507. //
  508. wcscpy( szBuffer, GPO_SCRIPTS_KEY L"\\" );
  509. wcscat( szBuffer, szType );
  510. //
  511. // open the key
  512. //
  513. dwError = RegOpenKeyEx( bMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
  514. szBuffer,
  515. 0,
  516. KEY_READ,
  517. &hKeyType );
  518. if ( dwError != ERROR_SUCCESS )
  519. {
  520. return dwError;
  521. }
  522. DWORD cSubKeys = 0;
  523. //
  524. // get the numer of GPOs
  525. //
  526. dwError = RegQueryInfoKey( hKeyType,
  527. 0,
  528. 0,
  529. 0,
  530. &cSubKeys,
  531. 0,
  532. 0,
  533. 0,
  534. 0,
  535. 0,
  536. 0,
  537. 0 );
  538. if ( dwError != ERROR_SUCCESS )
  539. {
  540. return dwError;
  541. }
  542. HINSTANCE hShell32;
  543. PFNSHELLEXECUTEEX pfnShellExecuteEx;
  544. hShell32 = LoadLibrary( L"shell32.dll" );
  545. if ( hShell32 )
  546. {
  547. pfnShellExecuteEx = (PFNSHELLEXECUTEEX) GetProcAddress( hShell32, "ShellExecuteExW" );
  548. if ( !pfnShellExecuteEx )
  549. {
  550. return GetLastError();
  551. }
  552. }
  553. //
  554. // for every GPO
  555. //
  556. for ( DWORD dwIndex = 0 ; dwIndex < cSubKeys ; dwIndex++ )
  557. {
  558. XKey hKeyGPO;
  559. XKey hKeyStateGPO;
  560. //
  561. // open the state GPO key
  562. //
  563. dwError = RegOpenKeyEx( hKeyStateType,
  564. _itow( dwIndex, szBuffer, 16 ),
  565. 0,
  566. KEY_ALL_ACCESS,
  567. &hKeyStateGPO );
  568. if ( dwError != ERROR_SUCCESS )
  569. {
  570. break;
  571. }
  572. //
  573. // open the policy GPO key (we need only read perms)
  574. //
  575. dwError = RegOpenKeyEx( hKeyType,
  576. szBuffer,
  577. 0,
  578. KEY_READ,
  579. &hKeyGPO );
  580. if ( dwError != ERROR_SUCCESS )
  581. {
  582. break;
  583. }
  584. //
  585. // execute all scripts in the GPO
  586. //
  587. DWORD dwExecError;
  588. dwExecError = ScrExecGPOFromReg(hKeyGPO,
  589. hKeyStateGPO,
  590. bSync,
  591. bHidden,
  592. bRunMin,
  593. szType,
  594. pfnShellExecuteEx,
  595. hEventLog );
  596. if ( dwExecError != ERROR_SUCCESS )
  597. {
  598. dwError = dwExecError;
  599. }
  600. }
  601. return dwError;
  602. }