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.

686 lines
19 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name :
  4. setup.c
  5. Abstract :
  6. Setup program for the AppSec tool.
  7. Setup the Registry keys and gives Read Permission for 'Everyone' to these keys.
  8. Also copies the AppSec.dll file to the %SystemRoot%\system32 directory
  9. Revision history :
  10. 09.02.2000 - Adding support for command line arguments - taking a text file containing
  11. Authorized Applications and a integer for Enabling Appsec - SriramSa
  12. Returns :
  13. TRUE if success
  14. FALSE if failed
  15. Author :
  16. Sriram (t-srisam) July 1999
  17. --*/
  18. #include "pch.h"
  19. #pragma hdrstop
  20. #include "setup.h"
  21. #include "aclapi.h"
  22. #include <accctrl.h>
  23. WCHAR g_szSystemRoot[MAX_PATH] ;
  24. INT _cdecl main ( INT argc, CHAR *argv[] )
  25. {
  26. DWORD Disp, size, error_code ;
  27. HKEY AppCertKey, AppsKey ;
  28. WCHAR *AppSecDllPath = L"%SystemRoot%\\system32\\appsec.dll" ;
  29. WCHAR *OldFileName = L".\\appsec.dll" ;
  30. WCHAR NewFileName[MAX_PATH] ;
  31. WCHAR HelpMessage[HELP_MSG_SIZE];
  32. WCHAR szTitle[MAX_PATH];
  33. WCHAR szMsg[MAX_PATH];
  34. CHAR FileName[MAX_PATH] ;
  35. INT IsEnabled = 0; // by default AppSec is disabled initially
  36. BOOL IsInitialFile = FALSE; // assume no initial file was provided
  37. BOOL status, IsNoGUI = FALSE ;
  38. // Process the command line arguments
  39. if (argc > 1) {
  40. IsInitialFile = TRUE ;
  41. strcpy(FileName, argv[1]) ;
  42. if (argc > 2) {
  43. IsEnabled = atoi(argv[2]) ;
  44. }
  45. // Check if user does not want any GUI
  46. if ((argc > 3) && (_stricmp(argv[3], "/N") == 0)) {
  47. IsNoGUI = TRUE ;
  48. }
  49. }
  50. // Display Help Message if asked for
  51. if (strcmp(FileName,"/?") == 0) {
  52. LoadString( NULL, IDS_HELP_MESSAGE ,HelpMessage, HELP_MSG_SIZE );
  53. LoadString( NULL, IDS_HELP_TITLE ,szTitle, MAX_PATH );
  54. MessageBox( NULL, HelpMessage, szTitle, MB_OK);
  55. return TRUE ;
  56. }
  57. // Check the second argument
  58. if ((IsEnabled != 0) && (IsEnabled != 1)) {
  59. LoadString( NULL, IDS_ARGUMENT_ERROR, szMsg, MAX_PATH );
  60. LoadString( NULL, IDS_ERROR, szTitle, MAX_PATH );
  61. MessageBox( NULL, szMsg, szTitle, MB_OK);
  62. return TRUE ;
  63. }
  64. // Display warning message regarding authorized apps already in the Registry
  65. if (IsNoGUI == FALSE) {
  66. LoadString( NULL, IDS_WARNING, szMsg, MAX_PATH );
  67. LoadString( NULL, IDS_WARNING_TITLE ,szTitle, MAX_PATH );
  68. if ( MessageBox( NULL, szMsg, szTitle, MB_OKCANCEL) == IDCANCEL ) {
  69. return TRUE ;
  70. }
  71. }
  72. // Create the AppCertDlls Key
  73. if (RegCreateKeyEx(
  74. HKEY_LOCAL_MACHINE,
  75. APPCERTDLLS_REG_NAME,
  76. 0,
  77. NULL,
  78. REG_OPTION_NON_VOLATILE,
  79. KEY_ALL_ACCESS,
  80. NULL,
  81. &AppCertKey,
  82. &Disp
  83. ) != ERROR_SUCCESS ) {
  84. LoadString( NULL, IDS_REG_ERROR ,szMsg, MAX_PATH );
  85. LoadString( NULL, IDS_ERROR ,szTitle, MAX_PATH );
  86. MessageBox( NULL, szMsg, szTitle, MB_OK);
  87. return FALSE ;
  88. }
  89. // After creating the key, give READ access to EVERYONE
  90. AddEveryoneToRegKey( APPCERTDLLS_REG_NAME ) ;
  91. // Set the AppSecDll value to the path of the AppSec.dll
  92. size = wcslen(AppSecDllPath) ;
  93. RegSetValueEx(
  94. AppCertKey,
  95. APPSECDLL_VAL,
  96. 0,
  97. REG_EXPAND_SZ,
  98. (CONST BYTE *)AppSecDllPath,
  99. (size + 1) * sizeof(WCHAR)
  100. ) ;
  101. // Create the AuthorizedApplications Key and give Read access to Evereone
  102. if (RegCreateKeyEx(
  103. HKEY_LOCAL_MACHINE,
  104. AUTHORIZEDAPPS_REG_NAME,
  105. 0,
  106. NULL,
  107. REG_OPTION_NON_VOLATILE,
  108. KEY_ALL_ACCESS,
  109. NULL,
  110. &AppsKey,
  111. &Disp
  112. ) != ERROR_SUCCESS ) {
  113. LoadString( NULL, IDS_REG_ERROR ,szMsg, MAX_PATH );
  114. LoadString( NULL, IDS_ERROR ,szTitle, MAX_PATH );
  115. MessageBox( NULL, szMsg, szTitle, MB_OK);
  116. RegCloseKey(AppCertKey) ;
  117. return FALSE ;
  118. }
  119. // After creating the key, give READ access to EVERYONE
  120. AddEveryoneToRegKey( AUTHORIZEDAPPS_REG_NAME ) ;
  121. RegCloseKey(AppCertKey) ;
  122. GetEnvironmentVariable( L"SystemRoot", g_szSystemRoot, MAX_PATH ) ;
  123. // Load the initial set of authorized apps into the Registry
  124. status = LoadInitApps( AppsKey, IsInitialFile, FileName) ;
  125. if (status == FALSE) {
  126. LoadString( NULL, IDS_APPS_WARNING, szMsg, MAX_PATH );
  127. LoadString( NULL, IDS_WARNING_TITLE, szTitle, MAX_PATH );
  128. MessageBox( NULL, szMsg, szTitle, MB_OK);
  129. }
  130. // Set the fEnabled key now
  131. RegSetValueEx(
  132. AppsKey,
  133. FENABLED_KEY,
  134. 0,
  135. REG_DWORD,
  136. (BYTE *) &IsEnabled,
  137. sizeof(DWORD) );
  138. RegCloseKey(AppsKey) ;
  139. // Copy the appsec.dll file to %SystemRoot%\system32 directory
  140. swprintf(NewFileName, L"%s\\system32\\appsec.dll", g_szSystemRoot ) ;
  141. if ( CopyFile(
  142. OldFileName,
  143. NewFileName,
  144. TRUE
  145. ) == 0 ) {
  146. error_code = GetLastError() ;
  147. // If AppSec.dll already exists in Target Directory, print appropriate Message
  148. if (error_code == ERROR_FILE_EXISTS) {
  149. if (IsNoGUI == FALSE) {
  150. LoadString( NULL, IDS_FILE_ALREADY_EXISTS ,szMsg, MAX_PATH );
  151. LoadString( NULL, IDS_ERROR ,szTitle, MAX_PATH );
  152. MessageBox( NULL, szMsg, szTitle, MB_OK);
  153. }
  154. return FALSE ;
  155. }
  156. // If AppSec.dll does not exist in the current directory, print appropriate Message
  157. if (error_code == ERROR_FILE_NOT_FOUND) {
  158. LoadString( NULL, IDS_FILE_NOT_FOUND ,szMsg, MAX_PATH );
  159. LoadString( NULL, IDS_ERROR ,szTitle, MAX_PATH );
  160. MessageBox( NULL, szMsg, szTitle, MB_OK);
  161. return FALSE ;
  162. }
  163. LoadString( NULL, IDS_ERROR_TEXT ,szMsg, MAX_PATH );
  164. LoadString( NULL, IDS_ERROR ,szTitle, MAX_PATH );
  165. MessageBox( NULL, szMsg, szTitle, MB_OK);
  166. return FALSE ;
  167. }
  168. // File was copied successfully - Installation was successful
  169. if (IsNoGUI == FALSE) {
  170. LoadString( NULL, IDS_SUCCESS_TEXT ,szMsg, MAX_PATH );
  171. LoadString( NULL, IDS_SUCCESS ,szTitle, MAX_PATH );
  172. MessageBox( NULL, szMsg, szTitle, MB_OK);
  173. }
  174. return TRUE ;
  175. }
  176. /*++
  177. The following two functions are used to change the permissions of the
  178. relevant Regsitry Keys, to give READ access to everyone, to take
  179. care of Guest users.
  180. --*/
  181. BOOL
  182. AddSidToObjectsSecurityDescriptor(
  183. HANDLE hObject,
  184. SE_OBJECT_TYPE ObjectType,
  185. PSID pSid,
  186. DWORD dwNewAccess,
  187. ACCESS_MODE AccessMode,
  188. DWORD dwInheritance
  189. )
  190. {
  191. BOOL fReturn = FALSE;
  192. DWORD dwRet;
  193. EXPLICIT_ACCESS ExpAccess;
  194. PACL pOldDacl = NULL, pNewDacl = NULL;
  195. PSECURITY_DESCRIPTOR pSecDesc = NULL;
  196. //
  197. // pSid cannot be NULL.
  198. //
  199. if (pSid == NULL) {
  200. SetLastError(ERROR_INVALID_PARAMETER);
  201. return(FALSE);
  202. }
  203. //
  204. // Get the objects security descriptor and current DACL.
  205. //
  206. dwRet = GetSecurityInfo(
  207. hObject,
  208. ObjectType,
  209. DACL_SECURITY_INFORMATION,
  210. NULL,
  211. NULL,
  212. &pOldDacl,
  213. NULL,
  214. &pSecDesc
  215. );
  216. if (dwRet != ERROR_SUCCESS) {
  217. return(FALSE);
  218. }
  219. //
  220. // Initialize an EXPLICIT_ACCESS structure for the new ACE.
  221. //
  222. ZeroMemory(&ExpAccess, sizeof(EXPLICIT_ACCESS));
  223. ExpAccess.grfAccessPermissions = dwNewAccess;
  224. ExpAccess.grfAccessMode = AccessMode;
  225. ExpAccess.grfInheritance = dwInheritance;
  226. ExpAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID;
  227. ExpAccess.Trustee.ptstrName = (PTSTR)pSid;
  228. //
  229. // Merge the new ACE into the existing DACL.
  230. //
  231. dwRet = SetEntriesInAcl(
  232. 1,
  233. &ExpAccess,
  234. pOldDacl,
  235. &pNewDacl
  236. );
  237. if (dwRet != ERROR_SUCCESS) {
  238. goto ErrorCleanup;
  239. }
  240. //
  241. // Set the new security for the object.
  242. //
  243. dwRet = SetSecurityInfo(
  244. hObject,
  245. ObjectType,
  246. DACL_SECURITY_INFORMATION,
  247. NULL,
  248. NULL,
  249. pNewDacl,
  250. NULL
  251. );
  252. if (dwRet != ERROR_SUCCESS) {
  253. goto ErrorCleanup;
  254. }
  255. fReturn = TRUE;
  256. ErrorCleanup:
  257. if (pNewDacl != NULL) {
  258. LocalFree(pNewDacl);
  259. }
  260. if (pSecDesc != NULL) {
  261. LocalFree(pSecDesc);
  262. }
  263. return(fReturn);
  264. }
  265. VOID
  266. AddEveryoneToRegKey(
  267. WCHAR *RegPath
  268. )
  269. {
  270. HKEY hKey;
  271. PSID pSid = NULL;
  272. SID_IDENTIFIER_AUTHORITY SepWorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
  273. LONG status ;
  274. status = RegOpenKeyEx(
  275. HKEY_LOCAL_MACHINE,
  276. RegPath,
  277. 0,
  278. KEY_ALL_ACCESS,
  279. &hKey
  280. );
  281. if (status != ERROR_SUCCESS) {
  282. return ;
  283. }
  284. AllocateAndInitializeSid(
  285. &SepWorldAuthority,
  286. 1,
  287. SECURITY_WORLD_RID,
  288. 0, 0, 0, 0, 0, 0, 0,
  289. &pSid
  290. );
  291. AddSidToObjectsSecurityDescriptor(
  292. hKey,
  293. SE_REGISTRY_KEY,
  294. pSid,
  295. KEY_READ,
  296. GRANT_ACCESS,
  297. CONTAINER_INHERIT_ACE
  298. );
  299. LocalFree(pSid);
  300. RegCloseKey(hKey);
  301. }
  302. /*++
  303. Routine Description :
  304. This function loads a initial set of authorized applications to the registry.
  305. Arguments :
  306. AppsecKey - Key to the registry entry where authorized applications are stored
  307. IsInitialFile - Was a initial file given as command line argument to load applications
  308. other than the default ones
  309. FileName - Name of the file given as command line argument
  310. Return Value :
  311. A BOOL indicating if the desired task succeeded or not.
  312. --*/
  313. BOOL LoadInitApps(
  314. HKEY AppsecKey,
  315. BOOL IsInitialFile,
  316. CHAR *FileName
  317. )
  318. {
  319. FILE *fp ;
  320. INT MaxInitApps ;
  321. WCHAR *BufferWritten ;
  322. INT BufferLength = 0 ;
  323. WCHAR AppsInFile[MAX_FILE_APPS][MAX_PATH] ;
  324. CHAR FileRead[MAX_PATH] ;
  325. INT size, count = 0, NumOfApps = 0 ;
  326. INT i, j, k ;
  327. BOOL IsFileExist = TRUE ;
  328. WCHAR InitApps[MAX_FILE_APPS][MAX_PATH];
  329. WCHAR szMsg[MAX_PATH], szTitle[MAX_PATH];
  330. WCHAR ResolvedAppName[MAX_PATH];
  331. DWORD RetValue;
  332. // Below is the list of default (necessary) applications
  333. LPWSTR DefaultInitApps[] = {
  334. L"system32\\loadwc.exe",
  335. L"system32\\cmd.exe",
  336. L"system32\\subst.exe",
  337. L"system32\\xcopy.exe",
  338. L"system32\\net.exe",
  339. L"system32\\regini.exe",
  340. L"system32\\systray.exe",
  341. L"explorer.exe",
  342. L"system32\\attrib.exe",
  343. L"Application Compatibility Scripts\\ACRegL.exe",
  344. L"Application Compatibility Scripts\\ACsr.exe",
  345. L"system32\\ntsd.exe",
  346. L"system32\\userinit.exe",
  347. L"system32\\wfshell.exe",
  348. L"system32\\chgcdm.exe",
  349. L"system32\\nddeagnt.exe",
  350. };
  351. MaxInitApps = sizeof(DefaultInitApps)/sizeof(DefaultInitApps[0]) ;
  352. // Prefix the default apps with %SystemRoot%
  353. for (i = 0; i < MaxInitApps; i++) {
  354. swprintf(InitApps[i], L"%ws\\%ws", g_szSystemRoot, DefaultInitApps[i]);
  355. }
  356. // Calculate the size of buffer to allocate to hold initial apps
  357. for (i = 0; i < MaxInitApps; i++) {
  358. BufferLength += wcslen(InitApps[i]) ;
  359. }
  360. BufferLength += MaxInitApps ; // for the terminating NULLS
  361. if (IsInitialFile == FALSE) {
  362. BufferLength += 1 ; //last terminating NULL in REG_MULTI_SZ
  363. } else {
  364. // A initial file was given to us
  365. fp = fopen(FileName, "r") ;
  366. if (fp == NULL) {
  367. // Display a Message Box saying Unable to open the file
  368. // Just load the default apps and return
  369. LoadString( NULL, IDS_APPFILE_NOT_FOUND ,szMsg, MAX_PATH );
  370. LoadString( NULL, IDS_WARNING_TITLE, szTitle, MAX_PATH );
  371. MessageBox( NULL, szMsg, szTitle, MB_OK);
  372. IsFileExist = FALSE ;
  373. } else {
  374. // build the array AppsInFile after UNICODE conversion
  375. while( fgets( FileRead, MAX_PATH, fp) != NULL ) {
  376. FileRead[strlen(FileRead)- 1] = '\0' ;
  377. // Convert from Short to Long name
  378. if ( GetLongPathNameA((LPCSTR)FileRead, FileRead, MAX_PATH) == 0 ) {
  379. // GetLongPathName returns error
  380. // some problem with the app listed in the file
  381. // Terminate further handling of apps in the file
  382. LoadString( NULL, IDS_ERROR_LOAD, szMsg, MAX_PATH );
  383. LoadString( NULL, IDS_WARNING_TITLE, szTitle, MAX_PATH );
  384. MessageBox( NULL, szMsg, szTitle, MB_OK);
  385. break;
  386. }
  387. // Convert to UNICODE format
  388. // Get the size of the buffer required first
  389. size = MultiByteToWideChar(
  390. CP_ACP,
  391. MB_PRECOMPOSED,
  392. FileRead,
  393. -1,
  394. NULL,
  395. 0) ;
  396. if (size > MAX_PATH) {
  397. // Something is wrong in the list of apps in the File
  398. // Terminate further handling of apps in the file
  399. LoadString( NULL, IDS_ERROR_LOAD, szMsg, MAX_PATH );
  400. LoadString( NULL, IDS_WARNING_TITLE, szTitle, MAX_PATH );
  401. MessageBox( NULL, szMsg, szTitle, MB_OK);
  402. break;
  403. } else {
  404. MultiByteToWideChar(
  405. CP_ACP,
  406. MB_PRECOMPOSED,
  407. FileRead,
  408. -1,
  409. AppsInFile[count],
  410. MAX_PATH) ;
  411. count++ ;
  412. }
  413. }
  414. fclose(fp) ;
  415. NumOfApps = count ;
  416. // Now any of these apps may be in remote Server and Share - so resolve them into UNC names
  417. // Copy the resolved names back into the same buffer
  418. for(i = 0; i < NumOfApps; i++) {
  419. ResolveName((LPCWSTR)AppsInFile[i], ResolvedAppName) ;
  420. wcscpy(AppsInFile[i], ResolvedAppName);
  421. }
  422. // Continue calculation of BufferLength
  423. for (i = 0; i < NumOfApps; i++) {
  424. BufferLength += wcslen(AppsInFile[i]) ;
  425. }
  426. BufferLength += NumOfApps ; // for the Terminating NULLs in REG_MULTI_SZ
  427. BufferLength += 1 ; // for the last NULL char in REG_MULTI_SZ
  428. }
  429. }
  430. BufferWritten = (WCHAR *) malloc (BufferLength * sizeof(WCHAR)) ;
  431. if (BufferWritten == NULL) {
  432. return FALSE ;
  433. }
  434. memset(BufferWritten, 0, BufferLength * sizeof(WCHAR)) ;
  435. // Build the LPWSTR BufferWritten with Initial Default Apps
  436. j = 0 ;
  437. for (i = 0; i < MaxInitApps; i++) {
  438. for(k = 0 ; k < (int) wcslen(InitApps[i]); k++) {
  439. BufferWritten[j++] = InitApps[i][k];
  440. }
  441. BufferWritten[j++] = L'\0' ;
  442. }
  443. if (IsInitialFile && IsFileExist ) {
  444. for (i = 0; i < NumOfApps; i++) {
  445. for(k = 0 ; k < (int) wcslen(AppsInFile[i]); k++) {
  446. BufferWritten[j++] = AppsInFile[i][k];
  447. }
  448. BufferWritten[j++] = L'\0' ;
  449. }
  450. }
  451. BufferWritten[j] = L'\0' ; // Last NULL char in REG_MULTI_SZ
  452. // Write this Buffer into the Registry Key
  453. if ( RegSetValueEx(
  454. AppsecKey,
  455. AUTHORIZED_APPS_KEY,
  456. 0,
  457. REG_MULTI_SZ,
  458. (CONST BYTE *) BufferWritten,
  459. (j+1) * sizeof(WCHAR)
  460. ) != ERROR_SUCCESS ) {
  461. // Free all the buffers which were allocated
  462. free(BufferWritten) ;
  463. return FALSE ;
  464. }
  465. free(BufferWritten) ;
  466. return TRUE ;
  467. }// end of function LoadInitApps
  468. /*++
  469. Routine Description :
  470. This Routine checks if the application resides in a local drive
  471. or a remote network share. If it is a remote share, the UNC path
  472. of the application is returned.
  473. Arguments :
  474. appname - name of the application
  475. Return Value :
  476. The UNC path of the appname if it resides in a remote server share.
  477. The same appname if it resides in a local drive.
  478. --*/
  479. VOID
  480. ResolveName(
  481. LPCWSTR appname,
  482. WCHAR *ResolvedName
  483. )
  484. {
  485. UINT i ;
  486. INT length ;
  487. WCHAR LocalName[3] ;
  488. WCHAR RootPathName[4] ;
  489. WCHAR RemoteName[MAX_PATH] ;
  490. DWORD size = MAX_PATH ;
  491. DWORD DriveType, error_status ;
  492. //
  493. // ResolvedName will hold the name of the UNC path of the appname if it is in
  494. // a remote server and share
  495. memset(ResolvedName, 0, MAX_PATH * sizeof(WCHAR)) ;
  496. // check if appname is a app in local drive or remote server share
  497. // Parse the first 3 chars in appname to get the root directory of the drive
  498. // where it resides
  499. wcsncpy(RootPathName, appname, 3 ) ;
  500. RootPathName[3] = L'\0';
  501. // Find the type of the Drive where the app is
  502. DriveType = GetDriveType(RootPathName) ;
  503. if (DriveType == DRIVE_REMOTE) {
  504. // Use WNetGetConnection to get the name of the remote share
  505. // Parse the first two chars of the appname to get the local drive
  506. // which is mapped onto the remote server and share
  507. wcsncpy(LocalName, appname, 2 ) ;
  508. LocalName[2] = L'\0' ;
  509. error_status = WNetGetConnection (
  510. LocalName,
  511. RemoteName,
  512. &size
  513. ) ;
  514. if (error_status != NO_ERROR) {
  515. wcscpy(ResolvedName,appname) ;
  516. return ;
  517. }
  518. //
  519. // Prepare ResolvedName - it will contain the Remote Server and Share name
  520. // followed by a \ and then the appname
  521. //
  522. wcscpy( ResolvedName, RemoteName ) ;
  523. length = wcslen(ResolvedName) ;
  524. ResolvedName[length++] = L'\\' ;
  525. for (i = 3 ; i <= wcslen(appname) ; i++ ) {
  526. ResolvedName[length++] = appname[i] ;
  527. }
  528. ResolvedName[length] = L'\0' ;
  529. return ;
  530. } else {
  531. // This application is in local drive and not in a remote server and share
  532. // Just send the appname back to the calling function
  533. wcscpy(ResolvedName,appname) ;
  534. return ;
  535. }
  536. }