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.

1080 lines
30 KiB

  1. /*************************************************************************
  2. *
  3. * allusrsm.c
  4. *
  5. * Move items from a user's start menu to the All Users start menu
  6. *
  7. * copyright notice: Copyright 1998 Micrsoft
  8. *
  9. * When entering install mode, if the start menu snapshot file already
  10. * exists, don't overwrite it. Otherwise, some shortcuts may not get moved
  11. * over. This fixes a problem where an App reboots the machine when it
  12. * finishes installing, without giving the user a chance to switch back to
  13. * execute mode. Now, when the user logs in again, the menu shortcuts will
  14. * be moved because winlogon always does a "change user /install" and then
  15. * "change user /execute". (That's to support RunOnce programs.)
  16. * MS 1057
  17. *
  18. *
  19. *************************************************************************/
  20. #include "precomp.h"
  21. #pragma hdrstop
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <stdlib.h>
  25. #include <windows.h>
  26. #include <userenv.h>
  27. #include <shlobj.h>
  28. // This program takes a snapshot of the Current User's start menu and
  29. // saves it to a file. When run with the /c option, it compares the
  30. // snapshot to the present contents of the Current User's start menu.
  31. // Each new or changed file/directory is then moved to the All Users
  32. // start menu. Additionally, Read permission is granted to the Everyone
  33. // group for each moved file or directory.
  34. typedef struct File_Struct {
  35. struct File_Struct *Next; // Only used in Memory
  36. WCHAR FileName[MAX_PATH];
  37. BOOL TimeValid;
  38. SYSTEMTIME Time;
  39. } FILENODE, *PFILENODE;
  40. typedef struct Path_Struct {
  41. DWORD FilesInDir;
  42. struct Path_Struct *Next; // Only used in Memory
  43. PFILENODE FileHead; // Only used in Memory
  44. PFILENODE FileTail; // Only used in Memory
  45. WCHAR PathStr[MAX_PATH];
  46. } PATHNODE, *PPATHNODE;
  47. typedef struct Tree_Struct {
  48. DWORD NumPaths;
  49. PPATHNODE PathHead;
  50. PPATHNODE PathTail;
  51. } TREENODE, *PTREENODE;
  52. typedef struct RemoveDir_Struct {
  53. WCHAR PathStr[MAX_PATH];
  54. struct RemoveDir_Struct *Next;
  55. } REMOVEDIRLIST, *PPREMOVEDIRLIST;
  56. int RunMode;
  57. WCHAR SaveName[MAX_PATH];
  58. WCHAR CurUserDir[MAX_PATH];
  59. WCHAR AllUserDir[MAX_PATH];
  60. int CurUserDirLen;
  61. WCHAR StartMenu[MAX_PATH]=L"";
  62. void ReadTree(PTREENODE Tree, WCHAR *Dir);
  63. #define SD_SIZE (65536 + SECURITY_DESCRIPTOR_MIN_LENGTH)
  64. ////////////////////////////////////////////////////////////////////////////
  65. BOOLEAN FileExists( WCHAR *path )
  66. {
  67. return( GetFileAttributes(path) == -1 ? FALSE : TRUE );
  68. }
  69. ////////////////////////////////////////////////////////////////////////////
  70. NTSTATUS CreateNewSecurityDescriptor( PSECURITY_DESCRIPTOR *ppNewSD,
  71. PSECURITY_DESCRIPTOR pSD,
  72. PACL pAcl )
  73. /*++
  74. Routine Description:
  75. From a SD and a Dacl, create a new SD. The new SD will be fully self
  76. contained (it is self relative) and does not have pointers to other
  77. structures.
  78. Arguments:
  79. ppNewSD - used to return the new SD. Caller should free with LocalFree
  80. pSD - the self relative SD we use to build the new SD
  81. pAcl - the new DACL that will be used for the new SD
  82. Return Value:
  83. NTSTATUS code
  84. --*/
  85. {
  86. PACL pSacl;
  87. PSID psidGroup, psidOwner;
  88. BOOLEAN fSaclPres;
  89. BOOLEAN fSaclDef, fGroupDef, fOwnerDef;
  90. ULONG NewSDSize;
  91. SECURITY_DESCRIPTOR NewSD;
  92. PSECURITY_DESCRIPTOR pNewSD;
  93. NTSTATUS Status;
  94. // extract the originals from the security descriptor
  95. Status = RtlGetSaclSecurityDescriptor(pSD, &fSaclPres, &pSacl, &fSaclDef);
  96. if (!NT_SUCCESS(Status))
  97. return(Status);
  98. Status = RtlGetOwnerSecurityDescriptor(pSD, &psidOwner, &fOwnerDef);
  99. if (!NT_SUCCESS(Status))
  100. return(Status);
  101. Status = RtlGetGroupSecurityDescriptor(pSD, &psidGroup, &fGroupDef);
  102. if (!NT_SUCCESS(Status))
  103. return(Status);
  104. // now create a new SD and set the info in it. we cannot return this one
  105. // since it has pointers to old SD.
  106. Status = RtlCreateSecurityDescriptor(&NewSD, SECURITY_DESCRIPTOR_REVISION);
  107. if (!NT_SUCCESS(Status))
  108. return(Status);
  109. Status = RtlSetDaclSecurityDescriptor(&NewSD, TRUE, pAcl, FALSE);
  110. if (!NT_SUCCESS(Status))
  111. return(Status);
  112. Status = RtlSetSaclSecurityDescriptor(&NewSD, fSaclPres, pSacl, fSaclDef);
  113. if (!NT_SUCCESS(Status))
  114. return(Status);
  115. Status = RtlSetOwnerSecurityDescriptor(&NewSD, psidOwner, fOwnerDef);
  116. if (!NT_SUCCESS(Status))
  117. return(Status);
  118. Status = RtlSetGroupSecurityDescriptor(&NewSD, psidGroup, fGroupDef);
  119. if (!NT_SUCCESS(Status))
  120. return(Status);
  121. // calculate size needed for the returned SD and allocated it
  122. NewSDSize = RtlLengthSecurityDescriptor(&NewSD);
  123. pNewSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LMEM_FIXED, NewSDSize);
  124. if (pNewSD == NULL)
  125. return(STATUS_INSUFFICIENT_RESOURCES);
  126. // convert the absolute to self relative
  127. Status = RtlAbsoluteToSelfRelativeSD(&NewSD, pNewSD, &NewSDSize);
  128. if (NT_SUCCESS(Status))
  129. *ppNewSD = pNewSD;
  130. else
  131. LocalFree(pNewSD);
  132. return(Status);
  133. } // CreateNewSecurityDescriptor
  134. /////////////////////////////////////////////////////////////////////////
  135. // Add Read and Execute permissions for built in "Everyone" Group to
  136. // the indicated file.
  137. BOOLEAN APIENTRY AddEveryoneRXPermissionW( LPCWSTR lpFileName)
  138. {
  139. NTSTATUS Status;
  140. BOOLEAN ExitVal = FALSE;
  141. HANDLE FileHandle=NULL;
  142. OBJECT_ATTRIBUTES Obja;
  143. UNICODE_STRING FileName;
  144. RTL_RELATIVE_NAME RelativeName;
  145. BOOLEAN TranslationStatus;
  146. IO_STATUS_BLOCK IoStatusBlock;
  147. PVOID FreeBuffer;
  148. PSECURITY_DESCRIPTOR pSD = NULL;
  149. PSECURITY_DESCRIPTOR pNewSD = NULL;
  150. DWORD LengthNeeded = 0;
  151. static PACCESS_ALLOWED_ACE pNewAce = NULL;
  152. static USHORT NewAceSize;
  153. ACL Acl;
  154. PACL pAcl, pNewAcl = NULL;
  155. BOOLEAN fDaclPresent, fDaclDef;
  156. USHORT NewAclSize;
  157. ////////////////////////////////////////////////////////////////////////
  158. // First time through this routine, create an ACE for the built-in
  159. // "Everyone" group.
  160. ////////////////////////////////////////////////////////////////////////
  161. if (pNewAce == NULL)
  162. {
  163. PSID psidEveryone = NULL;
  164. SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
  165. // Get the SID of the built-in Everyone group
  166. Status = RtlAllocateAndInitializeSid( &WorldSidAuthority, 1,
  167. SECURITY_WORLD_RID, 0,0,0,0,0,0,0, &psidEveryone);
  168. if (!NT_SUCCESS(Status))
  169. goto ErrorExit;
  170. // allocate and initialize new ACE
  171. NewAceSize = (USHORT)(sizeof(ACE_HEADER) + sizeof(ACCESS_MASK) +
  172. RtlLengthSid(psidEveryone));
  173. pNewAce = (PACCESS_ALLOWED_ACE) LocalAlloc(LMEM_FIXED, NewAceSize);
  174. if (pNewAce == NULL)
  175. goto ErrorExit;
  176. pNewAce->Header.AceFlags = (UCHAR) CONTAINER_INHERIT_ACE |
  177. OBJECT_INHERIT_ACE ;
  178. pNewAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
  179. pNewAce->Header.AceSize = NewAceSize;
  180. pNewAce->Mask = FILE_GENERIC_READ | FILE_EXECUTE;
  181. RtlCopySid(RtlLengthSid(psidEveryone), (PSID)(&pNewAce->SidStart),
  182. psidEveryone);
  183. }
  184. ////////////////////////////////////////////////////////////////////////
  185. // Open the indicated file.
  186. ////////////////////////////////////////////////////////////////////////
  187. TranslationStatus = RtlDosPathNameToNtPathName_U( lpFileName,
  188. &FileName, NULL, &RelativeName );
  189. if ( !TranslationStatus )
  190. goto ErrorExit;
  191. FreeBuffer = FileName.Buffer;
  192. if ( RelativeName.RelativeName.Length )
  193. FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
  194. else
  195. RelativeName.ContainingDirectory = NULL;
  196. InitializeObjectAttributes( &Obja, &FileName, OBJ_CASE_INSENSITIVE,
  197. RelativeName.ContainingDirectory, NULL );
  198. Status = NtOpenFile( &FileHandle, READ_CONTROL | WRITE_DAC, &Obja, &IoStatusBlock,
  199. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0 );
  200. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  201. if (!NT_SUCCESS(Status))
  202. goto ErrorExit;
  203. ////////////////////////////////////////////////////////////////////////
  204. // Retrieve the security descriptor for the file and then get the
  205. // file's DACL from it.
  206. ////////////////////////////////////////////////////////////////////////
  207. pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LMEM_FIXED, SD_SIZE);
  208. if (pSD == NULL)
  209. goto ErrorExit;
  210. Status = NtQuerySecurityObject( FileHandle, DACL_SECURITY_INFORMATION,
  211. pSD, SD_SIZE, &LengthNeeded );
  212. if (!NT_SUCCESS(Status))
  213. goto ErrorExit;
  214. // extract the originals from the security descriptor
  215. Status = RtlGetDaclSecurityDescriptor(pSD, &fDaclPresent, &pAcl, &fDaclDef);
  216. if (!NT_SUCCESS(Status))
  217. goto ErrorExit;
  218. ////////////////////////////////////////////////////////////////////////
  219. // Create a new DACL by copying the existing DACL and appending the
  220. // "Everyone" ACE.
  221. ////////////////////////////////////////////////////////////////////////
  222. // if no DACL present, we create one
  223. if ((fDaclPresent == FALSE) || (pAcl == NULL))
  224. {
  225. Status = RtlCreateAcl(&Acl, sizeof(Acl), ACL_REVISION) ;
  226. if (!NT_SUCCESS(Status))
  227. goto ErrorExit;
  228. pAcl = &Acl;
  229. }
  230. // Copy the DACL into a larger buffer and add the new ACE to the end.
  231. NewAclSize = pAcl->AclSize + NewAceSize;
  232. pNewAcl = (PACL) LocalAlloc(LMEM_FIXED, NewAclSize);
  233. if (!pNewAcl)
  234. goto ErrorExit;
  235. RtlCopyMemory(pNewAcl, pAcl, pAcl->AclSize);
  236. pNewAcl->AclSize = NewAclSize;
  237. Status = RtlAddAce(pNewAcl, ACL_REVISION, pNewAcl->AceCount,
  238. pNewAce, NewAceSize);
  239. if (!NT_SUCCESS(Status))
  240. goto ErrorExit;
  241. ////////////////////////////////////////////////////////////////////////
  242. // Create self-relative security descriptor with new DACL. Then
  243. // save the security descriptor back to the file.
  244. ////////////////////////////////////////////////////////////////////////
  245. Status = CreateNewSecurityDescriptor(&pNewSD, pSD, pNewAcl);
  246. if (!NT_SUCCESS(Status))
  247. goto ErrorExit;
  248. Status = NtSetSecurityObject(FileHandle, DACL_SECURITY_INFORMATION, pNewSD);
  249. if (!NT_SUCCESS(Status))
  250. goto ErrorExit;
  251. ExitVal = TRUE;
  252. ErrorExit:
  253. if (FileHandle != NULL)
  254. NtClose(FileHandle);
  255. if (pNewAcl != NULL)
  256. LocalFree(pNewAcl);
  257. if (pNewSD != NULL)
  258. LocalFree(pNewSD);
  259. if (pSD != NULL)
  260. LocalFree(pSD);
  261. return(ExitVal);
  262. }
  263. ////////////////////////////////////////////////////////////////////////////
  264. #if 0
  265. BOOLEAN APIENTRY AddEveryoneRXPermissionA( WCHAR * lpFileName)
  266. {
  267. PUNICODE_STRING Unicode;
  268. ANSI_STRING AnsiString;
  269. NTSTATUS Status;
  270. Unicode = &NtCurrentTeb()->StaticUnicodeString;
  271. RtlInitAnsiString(&AnsiString,lpFileName);
  272. Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
  273. if ( !NT_SUCCESS(Status) )
  274. {
  275. ULONG dwErrorCode;
  276. dwErrorCode = RtlNtStatusToDosError( Status );
  277. SetLastError( dwErrorCode );
  278. return FALSE;
  279. }
  280. return ( AddEveryoneRXPermissionW((LPCWSTR)Unicode->Buffer) );
  281. }
  282. #endif
  283. ////////////////////////////////////////////////////////////////////////////
  284. // return -1 for dates invalid, 0 for equal, 1 for f1 newer, 2 for f2 newer
  285. int CheckDates(PFILENODE FN1, PFILENODE FN2)
  286. {
  287. SYSTEMTIME f1s = FN1->Time;
  288. SYSTEMTIME f2s = FN2->Time;
  289. if (FN1->TimeValid == FALSE || FN2->TimeValid == FALSE)
  290. return -1;
  291. if (f1s.wYear > f2s.wYear) return 1;
  292. if (f1s.wYear < f2s.wYear) return 2;
  293. if (f1s.wMonth > f2s.wMonth) return 1;
  294. if (f1s.wMonth < f2s.wMonth) return 2;
  295. if (f1s.wDay > f2s.wDay) return 1;
  296. if (f1s.wDay < f2s.wDay) return 2;
  297. if (f1s.wHour > f2s.wHour) return 1;
  298. if (f1s.wHour < f2s.wHour) return 2;
  299. if (f1s.wMinute > f2s.wMinute) return 1;
  300. if (f1s.wMinute < f2s.wMinute) return 2;
  301. if (f1s.wSecond > f2s.wSecond) return 1;
  302. if (f1s.wSecond < f2s.wSecond) return 2;
  303. return 0;
  304. }
  305. ////////////////////////////////////////////////////////////////////////////
  306. PPATHNODE GetPathNode(PTREENODE Tree, WCHAR *Dir)
  307. {
  308. PPATHNODE p;
  309. // Handle Empty List
  310. if (Tree->PathTail == NULL)
  311. {
  312. p = (PPATHNODE) LocalAlloc(0,sizeof(PATHNODE));
  313. if (p == NULL)
  314. return NULL;
  315. Tree->PathHead = p;
  316. Tree->PathTail = p;
  317. Tree->NumPaths++;
  318. p->Next = NULL;
  319. p->FileHead = NULL;
  320. p->FileTail = NULL;
  321. p->FilesInDir = 0;
  322. wcscpy(p->PathStr,Dir);
  323. return p;
  324. }
  325. // Last Node Matches
  326. if (wcscmp(Tree->PathTail->PathStr,Dir) == 0)
  327. return Tree->PathTail;
  328. // Need to add a node
  329. p = (PPATHNODE) LocalAlloc(0,sizeof(PATHNODE));
  330. if (p == NULL)
  331. return NULL;
  332. Tree->PathTail->Next = p;
  333. Tree->PathTail = p;
  334. Tree->NumPaths++;
  335. p->Next = NULL;
  336. p->FileHead = NULL;
  337. p->FileTail = NULL;
  338. p->FilesInDir = 0;
  339. wcscpy(p->PathStr,Dir);
  340. return p;
  341. }
  342. ////////////////////////////////////////////////////////////////////////////
  343. void AddFileNode(PTREENODE Tree, WCHAR *Dir, PFILENODE FileNode)
  344. {
  345. PPATHNODE PathNode = GetPathNode(Tree, Dir);
  346. if (FileNode == NULL)
  347. return;
  348. if (PathNode == NULL)
  349. {
  350. LocalFree(FileNode);
  351. return;
  352. }
  353. // New node is always the last.
  354. FileNode->Next = NULL;
  355. // If list isn't empty, link to last node in list
  356. // Otherwise, set head pointer.
  357. if (PathNode->FileTail != NULL)
  358. PathNode->FileTail->Next = FileNode;
  359. else
  360. PathNode->FileHead = FileNode;
  361. // Put new node on end of list.
  362. PathNode->FileTail = FileNode;
  363. PathNode->FilesInDir++;
  364. }
  365. ////////////////////////////////////////////////////////////////////////////
  366. void ProcessFile(PTREENODE Tree, LPWIN32_FIND_DATA LocalData, WCHAR *LocalDir)
  367. {
  368. PFILENODE FileNode;
  369. // Don't handle directories
  370. if ((LocalData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
  371. return;
  372. // Allocate a file node
  373. FileNode = (PFILENODE) LocalAlloc(0,sizeof(FILENODE));
  374. if (FileNode == NULL)
  375. return;
  376. // Fill in the Local Fields
  377. wcscpy(FileNode->FileName, LocalData->cFileName);
  378. FileNode->TimeValid = FileTimeToSystemTime(&LocalData->ftLastWriteTime,
  379. &FileNode->Time);
  380. // Add to the list
  381. AddFileNode(Tree, LocalDir, FileNode);
  382. }
  383. ////////////////////////////////////////////////////////////////////////////
  384. void ProcessDir(PTREENODE Tree, LPWIN32_FIND_DATA FindData, WCHAR *Dir)
  385. {
  386. WCHAR NewDir[MAX_PATH];
  387. PPATHNODE PathNode;
  388. // Only Handle Directories
  389. if ((FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  390. return;
  391. // Don't recurse into these directories
  392. if (wcscmp(FindData->cFileName, L".") == 0)
  393. return;
  394. if (wcscmp(FindData->cFileName, L"..") == 0)
  395. return;
  396. wcscpy(NewDir,Dir);
  397. wcscat(NewDir,L"\\");
  398. wcscat(NewDir,FindData->cFileName);
  399. // This creates a node for the directory. Nodes get automatically
  400. // created when adding files, but that doesn't handle empty
  401. // directories. This does.
  402. PathNode = GetPathNode(Tree, NewDir);
  403. ReadTree(Tree, NewDir);
  404. }
  405. ////////////////////////////////////////////////////////////////////////////
  406. // Creates an in-memory representation of the Current User's start menu.
  407. void ReadTree(PTREENODE Tree, WCHAR *Dir)
  408. {
  409. HANDLE FindHandle;
  410. WIN32_FIND_DATA FindData;
  411. int retval;
  412. // First compare all files in current directory.
  413. retval = SetCurrentDirectory(Dir);
  414. if (retval == 0)
  415. {
  416. // printf("Unable to find directory %s\n",Dir);
  417. return;
  418. }
  419. FindHandle = FindFirstFile(L"*.*", &FindData);
  420. if (FindHandle != INVALID_HANDLE_VALUE)
  421. {
  422. ProcessFile(Tree, &FindData, Dir);
  423. while (FindNextFile(FindHandle, &FindData) != FALSE)
  424. ProcessFile(Tree, &FindData, Dir);
  425. FindClose(FindHandle);
  426. }
  427. // Next, handle subdirectories.
  428. retval = SetCurrentDirectory(Dir);
  429. if (retval == 0)
  430. {
  431. // printf("Unable to find directory %s\n",Dir);
  432. return;
  433. }
  434. FindHandle = FindFirstFile(L"*.*", &FindData);
  435. if (FindHandle != INVALID_HANDLE_VALUE)
  436. {
  437. ProcessDir(Tree, &FindData, Dir);
  438. while (FindNextFile(FindHandle, &FindData) != FALSE)
  439. ProcessDir(Tree, &FindData, Dir);
  440. FindClose(FindHandle);
  441. }
  442. }
  443. ////////////////////////////////////////////////////////////////////////////
  444. int WriteTreeToDisk(PTREENODE Tree)
  445. {
  446. PPATHNODE PN;
  447. PFILENODE FN;
  448. HANDLE hFile;
  449. DWORD BytesWritten;
  450. DWORD i;
  451. hFile = CreateFile(SaveName, GENERIC_WRITE, 0, NULL,
  452. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  453. if (hFile == INVALID_HANDLE_VALUE)
  454. return(-1); // error
  455. // DbgPrint("Tree->NumPaths is %d\n",Tree->NumPaths);
  456. if (WriteFile(hFile,&Tree->NumPaths,sizeof(DWORD),&BytesWritten, NULL) == 0)
  457. {
  458. CloseHandle(hFile);
  459. return(-1); // error
  460. }
  461. for (PN = Tree->PathHead; PN != NULL; PN = PN->Next)
  462. {
  463. if (WriteFile(hFile,PN,sizeof(PATHNODE),&BytesWritten, NULL) == 0)
  464. {
  465. CloseHandle(hFile);
  466. return(-1); // error
  467. }
  468. // DbgPrint("\n%s (%d)\n",PN->PathStr, PN->FilesInDir);
  469. FN = PN->FileHead;
  470. for (i = 0; i < PN->FilesInDir; i++)
  471. {
  472. if (WriteFile(hFile,FN,sizeof(FILENODE),&BytesWritten, NULL) == 0)
  473. {
  474. CloseHandle(hFile);
  475. return(-1); // error
  476. }
  477. // DbgPrint(" %s \n", FN->FileName);
  478. FN = FN->Next;
  479. }
  480. }
  481. CloseHandle(hFile);
  482. return(0);
  483. }
  484. ////////////////////////////////////////////////////////////////////////////
  485. int ReadTreeFromDisk(PTREENODE Tree)
  486. {
  487. PATHNODE LocalPath;
  488. PPATHNODE PN;
  489. PFILENODE FN;
  490. HANDLE hFile;
  491. DWORD BytesRead;
  492. DWORD i,j;
  493. DWORD NumFiles, NumTrees;
  494. hFile = CreateFile(SaveName, GENERIC_READ, 0, NULL,
  495. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  496. if (hFile == INVALID_HANDLE_VALUE)
  497. return(-1);
  498. if (ReadFile(hFile,&NumTrees,sizeof(DWORD),&BytesRead, NULL) == 0)
  499. {
  500. CloseHandle(hFile);
  501. return(-1); // error
  502. }
  503. for (i = 0; i < NumTrees; i++)
  504. {
  505. if (ReadFile(hFile,&LocalPath,sizeof(PATHNODE),&BytesRead, NULL) == 0)
  506. {
  507. CloseHandle(hFile);
  508. return(-1); // error
  509. }
  510. PN = GetPathNode(Tree, LocalPath.PathStr);
  511. if (PN == NULL)
  512. {
  513. CloseHandle(hFile);
  514. return(-1); // error
  515. }
  516. NumFiles = LocalPath.FilesInDir;
  517. // DbgPrint("\n<<%s (%d)\n",PN->PathStr, NumFiles);
  518. for (j = 0; j < NumFiles; j++)
  519. {
  520. // Allocate a file node
  521. FN = (PFILENODE) LocalAlloc(0,sizeof(FILENODE));
  522. if (FN == NULL)
  523. {
  524. CloseHandle(hFile);
  525. return(-1); // error
  526. }
  527. if (ReadFile(hFile,FN,sizeof(FILENODE),&BytesRead, NULL) == 0)
  528. {
  529. CloseHandle(hFile);
  530. LocalFree(FN);
  531. return(-1); // error
  532. }
  533. AddFileNode(Tree, PN->PathStr, FN);
  534. // DbgPrint(" %d: %s >>\n", j, FN->FileName);
  535. }
  536. }
  537. CloseHandle(hFile);
  538. return(0);
  539. }
  540. ////////////////////////////////////////////////////////////////////////////
  541. // Finds a path in a menu tree. If not found, NULL is returned.
  542. PPATHNODE FindPath(PTREENODE Tree, PPATHNODE PN)
  543. {
  544. PPATHNODE FoundPN;
  545. for (FoundPN = Tree->PathHead; FoundPN != NULL; FoundPN = FoundPN->Next)
  546. {
  547. if (_wcsicmp(FoundPN->PathStr,PN->PathStr) == 0)
  548. return FoundPN;
  549. }
  550. return NULL;
  551. }
  552. ////////////////////////////////////////////////////////////////////////////
  553. // Finds a file in a directory node. If not found, NULL is returned.
  554. PFILENODE FindFile(PPATHNODE PN, PFILENODE FN)
  555. {
  556. PFILENODE FoundFN;
  557. for (FoundFN = PN->FileHead; FoundFN != NULL; FoundFN = FoundFN->Next)
  558. {
  559. if (_wcsicmp(FoundFN->FileName,FN->FileName) == 0)
  560. return FoundFN;
  561. }
  562. return NULL;
  563. }
  564. ////////////////////////////////////////////////////////////////////////////
  565. /* ==============================================================
  566. Function Name : wcsrevchr
  567. Description : Reverse wcschr
  568. Finds a character in a string starting from the end
  569. Arguments :
  570. Return Value : PWCHAR
  571. ============================================================== */
  572. PWCHAR wcsrevchr( PWCHAR string, WCHAR ch )
  573. {
  574. int cLen, iCount;
  575. cLen = wcslen(string);
  576. string += cLen;
  577. for (iCount = cLen; iCount && *string != ch ; iCount--, string--)
  578. ;
  579. if (*string == ch)
  580. return string;
  581. else
  582. return NULL;
  583. }
  584. ////////////////////////////////////////////////////////////////////////////
  585. // Create the indicated directory. This function creates any parent
  586. // directories that are needed too.
  587. //
  588. // Return: TRUE = directory now exists
  589. // FALSE = directory couldn't be created
  590. BOOLEAN TsCreateDirectory( WCHAR *DirName )
  591. {
  592. BOOL RetVal;
  593. WCHAR *LastSlash;
  594. //
  595. // Try to create the specified directory. If the create works or
  596. // the directory already exists, return TRUE. If the called failed
  597. // because the path wasn't found, continue. This occurs if the
  598. // parent directory doesn't exist.
  599. //
  600. RetVal = CreateDirectory(DirName, NULL);
  601. if ((RetVal == TRUE) || (GetLastError() == ERROR_ALREADY_EXISTS))
  602. return(TRUE);
  603. if (GetLastError() != ERROR_PATH_NOT_FOUND)
  604. return(FALSE);
  605. //
  606. // Remove the last component of the path and try creating the
  607. // parent directory. Upon return, add the last component back
  608. // in and try to create the specified directory again.
  609. //
  610. // Desc : BUG 267014 - replaced
  611. // LastSlash = wcschr(DirName, L'\\');
  612. // Given a full pathname, previous always returns the drive letter.
  613. // Next line returns path components
  614. LastSlash = wcsrevchr(DirName, L'\\');
  615. if (LastSlash == NULL) // Can't reduce path any more
  616. return(FALSE);
  617. *LastSlash = L'\0';
  618. RetVal = TsCreateDirectory(DirName);
  619. *LastSlash = L'\\';
  620. if (RetVal == FALSE) // Couldn't create parent directory
  621. return(FALSE);
  622. RetVal = CreateDirectory(DirName, NULL);
  623. if ((RetVal == TRUE) || (GetLastError() == ERROR_ALREADY_EXISTS))
  624. return(TRUE);
  625. return(FALSE);
  626. }
  627. ////////////////////////////////////////////////////////////////////////////
  628. // Moves a file from the current start menu to the All Users start menu.
  629. // Creates any directories that may be needed in the All Users menu.
  630. void TsMoveFile(PPATHNODE PN, PFILENODE FN)
  631. {
  632. WCHAR Src[MAX_PATH];
  633. WCHAR Dest[MAX_PATH];
  634. // Normalize Source Path
  635. wcscpy(Src,PN->PathStr);
  636. if (Src[wcslen(Src)-1] != L'\\')
  637. wcscat(Src,L"\\");
  638. // Create Destination Path.
  639. wcscpy(Dest,AllUserDir);
  640. wcscat(Dest,&Src[CurUserDirLen]);
  641. // If directory doesn't exist, make it. The default permission is fine.
  642. if (TsCreateDirectory(Dest) != TRUE)
  643. return;
  644. wcscat(Src,FN->FileName);
  645. wcscat(Dest,FN->FileName);
  646. // Move Fails if the target already exists. This could happen
  647. // if we're copying a file that has a newer timestamp.
  648. if ( GetFileAttributes(Dest) != -1 )
  649. DeleteFile(Dest);
  650. // DbgPrint("Moving File %s \n to %s\n",Src,Dest);
  651. if (MoveFile(Src, Dest) == FALSE)
  652. return;
  653. AddEveryoneRXPermissionW(Dest);
  654. }
  655. ////////////////////////////////////////////////////////////////////////////
  656. // Compare the current start menu with the original. Copy any new or
  657. // changed files to the All Users menu.
  658. void ProcessChanges(PTREENODE OrigTree, PTREENODE NewTree)
  659. {
  660. PPATHNODE NewPN, OrigPN;
  661. PFILENODE NewFN, OrigFN;
  662. BOOL fRet;
  663. PPREMOVEDIRLIST pRemDirList = NULL, pTemp;
  664. for (NewPN = NewTree->PathHead; NewPN != NULL; NewPN = NewPN->Next)
  665. {
  666. // DbgPrint("PC: Dir is %s\n",NewPN->PathStr);
  667. // If directory not found in original tree, move it over
  668. OrigPN = FindPath(OrigTree, NewPN);
  669. if (OrigPN == NULL)
  670. {
  671. for (NewFN = NewPN->FileHead; NewFN != NULL; NewFN = NewFN->Next)
  672. {
  673. // DbgPrint(" Move File is %s\n",NewFN->FileName);
  674. TsMoveFile(NewPN,NewFN);
  675. }
  676. // Desc : BUG 267014 - replaced
  677. // RemoveDirectory(NewPN->PathStr);
  678. // We have a problem if NewPN doesn't contain file items but subfolders.
  679. // In this case, we do not enter the above loop, as there is nothing to move
  680. // But the folder can't be removed because it contains a tree that haven't been moved yet.
  681. // To remove it, we store its name in a LIFO stack. Stack items are removed when the loop exits
  682. fRet = RemoveDirectory(NewPN->PathStr);
  683. if (!fRet && GetLastError() == ERROR_DIR_NOT_EMPTY) {
  684. #if DBG
  685. DbgPrint("Adding to List--%S\n", NewPN->PathStr);
  686. #endif
  687. if (pRemDirList) {
  688. pTemp = (PPREMOVEDIRLIST)LocalAlloc(LMEM_FIXED,sizeof(REMOVEDIRLIST));
  689. wcscpy(pTemp->PathStr, NewPN->PathStr);
  690. pTemp->Next = pRemDirList;
  691. pRemDirList = pTemp;
  692. }
  693. else {
  694. pRemDirList = (PPREMOVEDIRLIST)LocalAlloc(LMEM_FIXED, sizeof(REMOVEDIRLIST));
  695. wcscpy(pRemDirList->PathStr, NewPN->PathStr);
  696. pRemDirList->Next = NULL;
  697. }
  698. }
  699. continue;
  700. }
  701. // Directory was found, check the files
  702. for (NewFN = NewPN->FileHead; NewFN != NULL; NewFN = NewFN->Next)
  703. {
  704. // DbgPrint(" File is %s\n",NewFN->FileName);
  705. // File wasn't found, move it
  706. OrigFN = FindFile(OrigPN,NewFN);
  707. if (OrigFN == NULL)
  708. {
  709. TsMoveFile(NewPN,NewFN);
  710. continue;
  711. }
  712. // Check TimeStamp, if New Scan is more recent, move it.
  713. if (CheckDates(NewFN,OrigFN) == 1)
  714. {
  715. TsMoveFile(NewPN,NewFN);
  716. continue;
  717. }
  718. }
  719. }
  720. // Desc : BUG 267014 - added
  721. // Directories stack removal
  722. if (pRemDirList) {
  723. while (pRemDirList) {
  724. pTemp = pRemDirList;
  725. pRemDirList = pRemDirList->Next;
  726. RemoveDirectory(pTemp->PathStr);
  727. LocalFree(pTemp);
  728. }
  729. }
  730. }
  731. ////////////////////////////////////////////////////////////////////////////
  732. // Frees the in-memory representation of a start menu
  733. void FreeTree(PTREENODE Tree)
  734. {
  735. PPATHNODE PN,NextPN;
  736. PFILENODE FN,NextFN;
  737. for (PN = Tree->PathHead; PN != NULL; PN = NextPN)
  738. {
  739. for (FN = PN->FileHead; FN != NULL; FN = NextFN)
  740. {
  741. NextFN = FN->Next;
  742. LocalFree(FN);
  743. }
  744. NextPN = PN->Next;
  745. LocalFree(PN);
  746. }
  747. Tree->PathHead = NULL;
  748. Tree->PathTail = NULL;
  749. Tree->NumPaths = 0;
  750. }
  751. ////////////////////////////////////////////////////////////////////////////
  752. // Updates the "All User" menu by moving new items from the Current User's
  753. // start menu. In RunMode 0, a snapshot of the Current User's start menu
  754. // is taken. After modifications to the Current User's start menu are done,
  755. // this function is called again with RunMode 1. Then, it compares the
  756. // current state of the start menu with the saved snapshot. Any new or
  757. // modified files are copied over to the corresponding location in the
  758. // "All User" start menu.
  759. //
  760. // RunMode 0 is invoked when the system is changed into install mode and
  761. // mode 1 is called when the system returns to execute mode.
  762. int TermsrvUpdateAllUserMenu(int RunMode)
  763. {
  764. TREENODE OrigTree;
  765. TREENODE NewTree;
  766. WCHAR p[MAX_PATH];
  767. int retval;
  768. PMESSAGE_RESOURCE_ENTRY MessageEntry;
  769. PVOID DllHandle;
  770. NTSTATUS Status;
  771. DWORD dwlen;
  772. OrigTree.PathHead = NULL;
  773. OrigTree.PathTail = NULL;
  774. OrigTree.NumPaths = 0;
  775. NewTree.PathHead = NULL;
  776. NewTree.PathTail = NULL;
  777. NewTree.NumPaths = 0;
  778. retval = GetEnvironmentVariable(L"UserProfile", p, MAX_PATH);
  779. if (retval == 0)
  780. return(-1);
  781. if (!StartMenu[0]) {
  782. HINSTANCE hInst;
  783. typedef HRESULT (* LPFNSHGETFOLDERPATH)(HWND, int, HANDLE, DWORD, LPWSTR);
  784. LPFNSHGETFOLDERPATH lpfnSHGetFolderPath;
  785. WCHAR ssPath[MAX_PATH];
  786. WCHAR *LastSlash;
  787. wcscpy( StartMenu, L"\\Start Menu");
  788. hInst = LoadLibrary(L"SHELL32.DLL");
  789. if (hInst) {
  790. lpfnSHGetFolderPath = (LPFNSHGETFOLDERPATH)GetProcAddress(hInst,"SHGetFolderPathW");
  791. if (lpfnSHGetFolderPath) {
  792. if (S_OK == lpfnSHGetFolderPath(NULL, CSIDL_STARTMENU, NULL, 0, ssPath)) {
  793. LastSlash = wcsrevchr(ssPath, L'\\');
  794. if (LastSlash) {
  795. wcscpy(StartMenu, LastSlash);
  796. }
  797. }
  798. }
  799. FreeLibrary(hInst);
  800. }
  801. }
  802. wcscpy(SaveName,p);
  803. wcscat(SaveName,L"\\TsAllUsr.Dat");
  804. wcscpy(CurUserDir,p);
  805. wcscat(CurUserDir,StartMenu);
  806. CurUserDirLen = wcslen(CurUserDir);
  807. dwlen = sizeof(AllUserDir)/sizeof(WCHAR);
  808. if (GetAllUsersProfileDirectory(AllUserDir, &dwlen))
  809. {
  810. wcscat(AllUserDir,StartMenu);
  811. #if DBG
  812. DbgPrint("SaveName is '%S'\n",SaveName);
  813. DbgPrint("CurUserDir is '%S'\n",CurUserDir);
  814. DbgPrint("AllUserDir is '%S'\n",AllUserDir);
  815. #endif
  816. if (RunMode == 0)
  817. {
  818. // If the start menu snapshot already exists, don't overwrite it.
  819. // The user may enter "change user /install" twice, or an app may
  820. // force a reboot without changing back to execute mode. The
  821. // existing file is older. If we overwrite it, then some shortcuts
  822. // won't get moved.
  823. if (FileExists(SaveName) != TRUE)
  824. {
  825. ReadTree(&OrigTree, CurUserDir);
  826. if (WriteTreeToDisk(&OrigTree) == -1)
  827. DeleteFile(SaveName);
  828. FreeTree(&OrigTree);
  829. }
  830. }
  831. else if (RunMode == 1)
  832. {
  833. if (ReadTreeFromDisk(&OrigTree) == -1)
  834. {
  835. FreeTree(&OrigTree);
  836. DeleteFile(SaveName); // Could be a bad file. If it doesn't
  837. // exist, this won't hurt anything.
  838. return(-1);
  839. }
  840. ReadTree(&NewTree, CurUserDir);
  841. ProcessChanges(&OrigTree,&NewTree);
  842. DeleteFile(SaveName);
  843. FreeTree(&OrigTree);
  844. FreeTree(&NewTree);
  845. }
  846. }
  847. return(0);
  848. }