Leaked source code of windows server 2003
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.

1082 lines
32 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_U 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 = RtlDosPathNameToRelativeNtPathName_U( lpFileName,
  188. &FileName, NULL, &RelativeName );
  189. if ( !TranslationStatus ) {
  190. goto ErrorExit;
  191. }
  192. FreeBuffer = FileName.Buffer;
  193. if ( RelativeName.RelativeName.Length )
  194. FileName = RelativeName.RelativeName;
  195. else
  196. RelativeName.ContainingDirectory = NULL;
  197. InitializeObjectAttributes( &Obja, &FileName, OBJ_CASE_INSENSITIVE,
  198. RelativeName.ContainingDirectory, NULL );
  199. Status = NtOpenFile( &FileHandle, READ_CONTROL | WRITE_DAC, &Obja, &IoStatusBlock,
  200. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0 );
  201. RtlReleaseRelativeName(&RelativeName);
  202. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  203. if (!NT_SUCCESS(Status))
  204. goto ErrorExit;
  205. ////////////////////////////////////////////////////////////////////////
  206. // Retrieve the security descriptor for the file and then get the
  207. // file's DACL from it.
  208. ////////////////////////////////////////////////////////////////////////
  209. pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LMEM_FIXED, SD_SIZE);
  210. if (pSD == NULL)
  211. goto ErrorExit;
  212. Status = NtQuerySecurityObject( FileHandle, DACL_SECURITY_INFORMATION,
  213. pSD, SD_SIZE, &LengthNeeded );
  214. if (!NT_SUCCESS(Status))
  215. goto ErrorExit;
  216. // extract the originals from the security descriptor
  217. Status = RtlGetDaclSecurityDescriptor(pSD, &fDaclPresent, &pAcl, &fDaclDef);
  218. if (!NT_SUCCESS(Status))
  219. goto ErrorExit;
  220. ////////////////////////////////////////////////////////////////////////
  221. // Create a new DACL by copying the existing DACL and appending the
  222. // "Everyone" ACE.
  223. ////////////////////////////////////////////////////////////////////////
  224. // if no DACL present, we create one
  225. if ((fDaclPresent == FALSE) || (pAcl == NULL))
  226. {
  227. Status = RtlCreateAcl(&Acl, sizeof(Acl), ACL_REVISION) ;
  228. if (!NT_SUCCESS(Status))
  229. goto ErrorExit;
  230. pAcl = &Acl;
  231. }
  232. // Copy the DACL into a larger buffer and add the new ACE to the end.
  233. NewAclSize = pAcl->AclSize + NewAceSize;
  234. pNewAcl = (PACL) LocalAlloc(LMEM_FIXED, NewAclSize);
  235. if (!pNewAcl)
  236. goto ErrorExit;
  237. RtlCopyMemory(pNewAcl, pAcl, pAcl->AclSize);
  238. pNewAcl->AclSize = NewAclSize;
  239. Status = RtlAddAce(pNewAcl, ACL_REVISION, pNewAcl->AceCount,
  240. pNewAce, NewAceSize);
  241. if (!NT_SUCCESS(Status))
  242. goto ErrorExit;
  243. ////////////////////////////////////////////////////////////////////////
  244. // Create self-relative security descriptor with new DACL. Then
  245. // save the security descriptor back to the file.
  246. ////////////////////////////////////////////////////////////////////////
  247. Status = CreateNewSecurityDescriptor(&pNewSD, pSD, pNewAcl);
  248. if (!NT_SUCCESS(Status))
  249. goto ErrorExit;
  250. Status = NtSetSecurityObject(FileHandle, DACL_SECURITY_INFORMATION, pNewSD);
  251. if (!NT_SUCCESS(Status))
  252. goto ErrorExit;
  253. ExitVal = TRUE;
  254. ErrorExit:
  255. if (FileHandle != NULL)
  256. NtClose(FileHandle);
  257. if (pNewAcl != NULL)
  258. LocalFree(pNewAcl);
  259. if (pNewSD != NULL)
  260. LocalFree(pNewSD);
  261. if (pSD != NULL)
  262. LocalFree(pSD);
  263. return(ExitVal);
  264. }
  265. ////////////////////////////////////////////////////////////////////////////
  266. #if 0
  267. BOOLEAN APIENTRY AddEveryoneRXPermissionA( WCHAR * lpFileName)
  268. {
  269. PUNICODE_STRING Unicode;
  270. ANSI_STRING AnsiString;
  271. NTSTATUS Status;
  272. Unicode = &NtCurrentTeb()->StaticUnicodeString;
  273. RtlInitAnsiString(&AnsiString,lpFileName);
  274. Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
  275. if ( !NT_SUCCESS(Status) )
  276. {
  277. ULONG dwErrorCode;
  278. dwErrorCode = RtlNtStatusToDosError( Status );
  279. SetLastError( dwErrorCode );
  280. return FALSE;
  281. }
  282. return ( AddEveryoneRXPermissionW((LPCWSTR)Unicode->Buffer) );
  283. }
  284. #endif
  285. ////////////////////////////////////////////////////////////////////////////
  286. // return -1 for dates invalid, 0 for equal, 1 for f1 newer, 2 for f2 newer
  287. int CheckDates(PFILENODE FN1, PFILENODE FN2)
  288. {
  289. SYSTEMTIME f1s = FN1->Time;
  290. SYSTEMTIME f2s = FN2->Time;
  291. if (FN1->TimeValid == FALSE || FN2->TimeValid == FALSE)
  292. return -1;
  293. if (f1s.wYear > f2s.wYear) return 1;
  294. if (f1s.wYear < f2s.wYear) return 2;
  295. if (f1s.wMonth > f2s.wMonth) return 1;
  296. if (f1s.wMonth < f2s.wMonth) return 2;
  297. if (f1s.wDay > f2s.wDay) return 1;
  298. if (f1s.wDay < f2s.wDay) return 2;
  299. if (f1s.wHour > f2s.wHour) return 1;
  300. if (f1s.wHour < f2s.wHour) return 2;
  301. if (f1s.wMinute > f2s.wMinute) return 1;
  302. if (f1s.wMinute < f2s.wMinute) return 2;
  303. if (f1s.wSecond > f2s.wSecond) return 1;
  304. if (f1s.wSecond < f2s.wSecond) return 2;
  305. return 0;
  306. }
  307. ////////////////////////////////////////////////////////////////////////////
  308. PPATHNODE GetPathNode(PTREENODE Tree, WCHAR *Dir)
  309. {
  310. PPATHNODE p;
  311. // Handle Empty List
  312. if (Tree->PathTail == NULL)
  313. {
  314. p = (PPATHNODE) LocalAlloc(0,sizeof(PATHNODE));
  315. if (p == NULL)
  316. return NULL;
  317. Tree->PathHead = p;
  318. Tree->PathTail = p;
  319. Tree->NumPaths++;
  320. p->Next = NULL;
  321. p->FileHead = NULL;
  322. p->FileTail = NULL;
  323. p->FilesInDir = 0;
  324. wcscpy(p->PathStr,Dir);
  325. return p;
  326. }
  327. // Last Node Matches
  328. if (wcscmp(Tree->PathTail->PathStr,Dir) == 0)
  329. return Tree->PathTail;
  330. // Need to add a node
  331. p = (PPATHNODE) LocalAlloc(0,sizeof(PATHNODE));
  332. if (p == NULL)
  333. return NULL;
  334. Tree->PathTail->Next = p;
  335. Tree->PathTail = p;
  336. Tree->NumPaths++;
  337. p->Next = NULL;
  338. p->FileHead = NULL;
  339. p->FileTail = NULL;
  340. p->FilesInDir = 0;
  341. wcscpy(p->PathStr,Dir);
  342. return p;
  343. }
  344. ////////////////////////////////////////////////////////////////////////////
  345. void AddFileNode(PTREENODE Tree, WCHAR *Dir, PFILENODE FileNode)
  346. {
  347. PPATHNODE PathNode = GetPathNode(Tree, Dir);
  348. if (FileNode == NULL)
  349. return;
  350. if (PathNode == NULL)
  351. {
  352. LocalFree(FileNode);
  353. return;
  354. }
  355. // New node is always the last.
  356. FileNode->Next = NULL;
  357. // If list isn't empty, link to last node in list
  358. // Otherwise, set head pointer.
  359. if (PathNode->FileTail != NULL)
  360. PathNode->FileTail->Next = FileNode;
  361. else
  362. PathNode->FileHead = FileNode;
  363. // Put new node on end of list.
  364. PathNode->FileTail = FileNode;
  365. PathNode->FilesInDir++;
  366. }
  367. ////////////////////////////////////////////////////////////////////////////
  368. void ProcessFile(PTREENODE Tree, LPWIN32_FIND_DATA LocalData, WCHAR *LocalDir)
  369. {
  370. PFILENODE FileNode;
  371. // Don't handle directories
  372. if ((LocalData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
  373. return;
  374. // Allocate a file node
  375. FileNode = (PFILENODE) LocalAlloc(0,sizeof(FILENODE));
  376. if (FileNode == NULL)
  377. return;
  378. // Fill in the Local Fields
  379. wcscpy(FileNode->FileName, LocalData->cFileName);
  380. FileNode->TimeValid = FileTimeToSystemTime(&LocalData->ftLastWriteTime,
  381. &FileNode->Time);
  382. // Add to the list
  383. AddFileNode(Tree, LocalDir, FileNode);
  384. }
  385. ////////////////////////////////////////////////////////////////////////////
  386. void ProcessDir(PTREENODE Tree, LPWIN32_FIND_DATA FindData, WCHAR *Dir)
  387. {
  388. WCHAR NewDir[MAX_PATH];
  389. PPATHNODE PathNode;
  390. // Only Handle Directories
  391. if ((FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  392. return;
  393. // Don't recurse into these directories
  394. if (wcscmp(FindData->cFileName, L".") == 0)
  395. return;
  396. if (wcscmp(FindData->cFileName, L"..") == 0)
  397. return;
  398. wcscpy(NewDir,Dir);
  399. wcscat(NewDir,L"\\");
  400. wcscat(NewDir,FindData->cFileName);
  401. // This creates a node for the directory. Nodes get automatically
  402. // created when adding files, but that doesn't handle empty
  403. // directories. This does.
  404. PathNode = GetPathNode(Tree, NewDir);
  405. ReadTree(Tree, NewDir);
  406. }
  407. ////////////////////////////////////////////////////////////////////////////
  408. // Creates an in-memory representation of the Current User's start menu.
  409. void ReadTree(PTREENODE Tree, WCHAR *Dir)
  410. {
  411. HANDLE FindHandle;
  412. WIN32_FIND_DATA FindData;
  413. int retval;
  414. // First compare all files in current directory.
  415. retval = SetCurrentDirectory(Dir);
  416. if (retval == 0)
  417. {
  418. // printf("Unable to find directory %s\n",Dir);
  419. return;
  420. }
  421. FindHandle = FindFirstFile(L"*.*", &FindData);
  422. if (FindHandle != INVALID_HANDLE_VALUE)
  423. {
  424. ProcessFile(Tree, &FindData, Dir);
  425. while (FindNextFile(FindHandle, &FindData) != FALSE)
  426. ProcessFile(Tree, &FindData, Dir);
  427. FindClose(FindHandle);
  428. }
  429. // Next, handle subdirectories.
  430. retval = SetCurrentDirectory(Dir);
  431. if (retval == 0)
  432. {
  433. // printf("Unable to find directory %s\n",Dir);
  434. return;
  435. }
  436. FindHandle = FindFirstFile(L"*.*", &FindData);
  437. if (FindHandle != INVALID_HANDLE_VALUE)
  438. {
  439. ProcessDir(Tree, &FindData, Dir);
  440. while (FindNextFile(FindHandle, &FindData) != FALSE)
  441. ProcessDir(Tree, &FindData, Dir);
  442. FindClose(FindHandle);
  443. }
  444. }
  445. ////////////////////////////////////////////////////////////////////////////
  446. int WriteTreeToDisk(PTREENODE Tree)
  447. {
  448. PPATHNODE PN;
  449. PFILENODE FN;
  450. HANDLE hFile;
  451. DWORD BytesWritten;
  452. DWORD i;
  453. hFile = CreateFile(SaveName, GENERIC_WRITE, 0, NULL,
  454. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  455. if (hFile == INVALID_HANDLE_VALUE)
  456. return(-1); // error
  457. // DbgPrint("Tree->NumPaths is %d\n",Tree->NumPaths);
  458. if (WriteFile(hFile,&Tree->NumPaths,sizeof(DWORD),&BytesWritten, NULL) == 0)
  459. {
  460. CloseHandle(hFile);
  461. return(-1); // error
  462. }
  463. for (PN = Tree->PathHead; PN != NULL; PN = PN->Next)
  464. {
  465. if (WriteFile(hFile,PN,sizeof(PATHNODE),&BytesWritten, NULL) == 0)
  466. {
  467. CloseHandle(hFile);
  468. return(-1); // error
  469. }
  470. // DbgPrint("\n%s (%d)\n",PN->PathStr, PN->FilesInDir);
  471. FN = PN->FileHead;
  472. for (i = 0; i < PN->FilesInDir; i++)
  473. {
  474. if (WriteFile(hFile,FN,sizeof(FILENODE),&BytesWritten, NULL) == 0)
  475. {
  476. CloseHandle(hFile);
  477. return(-1); // error
  478. }
  479. // DbgPrint(" %s \n", FN->FileName);
  480. FN = FN->Next;
  481. }
  482. }
  483. CloseHandle(hFile);
  484. return(0);
  485. }
  486. ////////////////////////////////////////////////////////////////////////////
  487. int ReadTreeFromDisk(PTREENODE Tree)
  488. {
  489. PATHNODE LocalPath;
  490. PPATHNODE PN;
  491. PFILENODE FN;
  492. HANDLE hFile;
  493. DWORD BytesRead;
  494. DWORD i,j;
  495. DWORD NumFiles, NumTrees;
  496. hFile = CreateFile(SaveName, GENERIC_READ, 0, NULL,
  497. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  498. if (hFile == INVALID_HANDLE_VALUE)
  499. return(-1);
  500. if (ReadFile(hFile,&NumTrees,sizeof(DWORD),&BytesRead, NULL) == 0)
  501. {
  502. CloseHandle(hFile);
  503. return(-1); // error
  504. }
  505. for (i = 0; i < NumTrees; i++)
  506. {
  507. if (ReadFile(hFile,&LocalPath,sizeof(PATHNODE),&BytesRead, NULL) == 0)
  508. {
  509. CloseHandle(hFile);
  510. return(-1); // error
  511. }
  512. PN = GetPathNode(Tree, LocalPath.PathStr);
  513. if (PN == NULL)
  514. {
  515. CloseHandle(hFile);
  516. return(-1); // error
  517. }
  518. NumFiles = LocalPath.FilesInDir;
  519. // DbgPrint("\n<<%s (%d)\n",PN->PathStr, NumFiles);
  520. for (j = 0; j < NumFiles; j++)
  521. {
  522. // Allocate a file node
  523. FN = (PFILENODE) LocalAlloc(0,sizeof(FILENODE));
  524. if (FN == NULL)
  525. {
  526. CloseHandle(hFile);
  527. return(-1); // error
  528. }
  529. if (ReadFile(hFile,FN,sizeof(FILENODE),&BytesRead, NULL) == 0)
  530. {
  531. CloseHandle(hFile);
  532. LocalFree(FN);
  533. return(-1); // error
  534. }
  535. AddFileNode(Tree, PN->PathStr, FN);
  536. // DbgPrint(" %d: %s >>\n", j, FN->FileName);
  537. }
  538. }
  539. CloseHandle(hFile);
  540. return(0);
  541. }
  542. ////////////////////////////////////////////////////////////////////////////
  543. // Finds a path in a menu tree. If not found, NULL is returned.
  544. PPATHNODE FindPath(PTREENODE Tree, PPATHNODE PN)
  545. {
  546. PPATHNODE FoundPN;
  547. for (FoundPN = Tree->PathHead; FoundPN != NULL; FoundPN = FoundPN->Next)
  548. {
  549. if (_wcsicmp(FoundPN->PathStr,PN->PathStr) == 0)
  550. return FoundPN;
  551. }
  552. return NULL;
  553. }
  554. ////////////////////////////////////////////////////////////////////////////
  555. // Finds a file in a directory node. If not found, NULL is returned.
  556. PFILENODE FindFile(PPATHNODE PN, PFILENODE FN)
  557. {
  558. PFILENODE FoundFN;
  559. for (FoundFN = PN->FileHead; FoundFN != NULL; FoundFN = FoundFN->Next)
  560. {
  561. if (_wcsicmp(FoundFN->FileName,FN->FileName) == 0)
  562. return FoundFN;
  563. }
  564. return NULL;
  565. }
  566. ////////////////////////////////////////////////////////////////////////////
  567. /* ==============================================================
  568. Function Name : wcsrevchr
  569. Description : Reverse wcschr
  570. Finds a character in a string starting from the end
  571. Arguments :
  572. Return Value : PWCHAR
  573. ============================================================== */
  574. PWCHAR wcsrevchr( PWCHAR string, WCHAR ch )
  575. {
  576. int cLen, iCount;
  577. cLen = wcslen(string);
  578. string += cLen;
  579. for (iCount = cLen; iCount && *string != ch ; iCount--, string--)
  580. ;
  581. if (*string == ch)
  582. return string;
  583. else
  584. return NULL;
  585. }
  586. ////////////////////////////////////////////////////////////////////////////
  587. // Create the indicated directory. This function creates any parent
  588. // directories that are needed too.
  589. //
  590. // Return: TRUE = directory now exists
  591. // FALSE = directory couldn't be created
  592. BOOLEAN TsCreateDirectory( WCHAR *DirName )
  593. {
  594. BOOL RetVal;
  595. WCHAR *LastSlash;
  596. //
  597. // Try to create the specified directory. If the create works or
  598. // the directory already exists, return TRUE. If the called failed
  599. // because the path wasn't found, continue. This occurs if the
  600. // parent directory doesn't exist.
  601. //
  602. RetVal = CreateDirectory(DirName, NULL);
  603. if ((RetVal == TRUE) || (GetLastError() == ERROR_ALREADY_EXISTS))
  604. return(TRUE);
  605. if (GetLastError() != ERROR_PATH_NOT_FOUND)
  606. return(FALSE);
  607. //
  608. // Remove the last component of the path and try creating the
  609. // parent directory. Upon return, add the last component back
  610. // in and try to create the specified directory again.
  611. //
  612. // Desc : BUG 267014 - replaced
  613. // LastSlash = wcschr(DirName, L'\\');
  614. // Given a full pathname, previous always returns the drive letter.
  615. // Next line returns path components
  616. LastSlash = wcsrevchr(DirName, L'\\');
  617. if (LastSlash == NULL) // Can't reduce path any more
  618. return(FALSE);
  619. *LastSlash = L'\0';
  620. RetVal = TsCreateDirectory(DirName);
  621. *LastSlash = L'\\';
  622. if (RetVal == FALSE) // Couldn't create parent directory
  623. return(FALSE);
  624. RetVal = CreateDirectory(DirName, NULL);
  625. if ((RetVal == TRUE) || (GetLastError() == ERROR_ALREADY_EXISTS))
  626. return(TRUE);
  627. return(FALSE);
  628. }
  629. ////////////////////////////////////////////////////////////////////////////
  630. // Moves a file from the current start menu to the All Users start menu.
  631. // Creates any directories that may be needed in the All Users menu.
  632. void TsMoveFile(PPATHNODE PN, PFILENODE FN)
  633. {
  634. WCHAR Src[MAX_PATH];
  635. WCHAR Dest[MAX_PATH];
  636. // Normalize Source Path
  637. wcscpy(Src,PN->PathStr);
  638. if (Src[wcslen(Src)-1] != L'\\')
  639. wcscat(Src,L"\\");
  640. // Create Destination Path.
  641. wcscpy(Dest,AllUserDir);
  642. wcscat(Dest,&Src[CurUserDirLen]);
  643. // If directory doesn't exist, make it. The default permission is fine.
  644. if (TsCreateDirectory(Dest) != TRUE)
  645. return;
  646. wcscat(Src,FN->FileName);
  647. wcscat(Dest,FN->FileName);
  648. // Move Fails if the target already exists. This could happen
  649. // if we're copying a file that has a newer timestamp.
  650. if ( GetFileAttributes(Dest) != -1 )
  651. DeleteFile(Dest);
  652. // DbgPrint("Moving File %s \n to %s\n",Src,Dest);
  653. if (MoveFile(Src, Dest) == FALSE)
  654. return;
  655. AddEveryoneRXPermissionW(Dest);
  656. }
  657. ////////////////////////////////////////////////////////////////////////////
  658. // Compare the current start menu with the original. Copy any new or
  659. // changed files to the All Users menu.
  660. void ProcessChanges(PTREENODE OrigTree, PTREENODE NewTree)
  661. {
  662. PPATHNODE NewPN, OrigPN;
  663. PFILENODE NewFN, OrigFN;
  664. BOOL fRet;
  665. PPREMOVEDIRLIST pRemDirList = NULL, pTemp;
  666. for (NewPN = NewTree->PathHead; NewPN != NULL; NewPN = NewPN->Next)
  667. {
  668. // DbgPrint("PC: Dir is %s\n",NewPN->PathStr);
  669. // If directory not found in original tree, move it over
  670. OrigPN = FindPath(OrigTree, NewPN);
  671. if (OrigPN == NULL)
  672. {
  673. for (NewFN = NewPN->FileHead; NewFN != NULL; NewFN = NewFN->Next)
  674. {
  675. // DbgPrint(" Move File is %s\n",NewFN->FileName);
  676. TsMoveFile(NewPN,NewFN);
  677. }
  678. // Desc : BUG 267014 - replaced
  679. // RemoveDirectory(NewPN->PathStr);
  680. // We have a problem if NewPN doesn't contain file items but subfolders.
  681. // In this case, we do not enter the above loop, as there is nothing to move
  682. // But the folder can't be removed because it contains a tree that haven't been moved yet.
  683. // To remove it, we store its name in a LIFO stack. Stack items are removed when the loop exits
  684. fRet = RemoveDirectory(NewPN->PathStr);
  685. if (!fRet && GetLastError() == ERROR_DIR_NOT_EMPTY) {
  686. #if DBG
  687. DbgPrint("Adding to List--%S\n", NewPN->PathStr);
  688. #endif
  689. if (pRemDirList) {
  690. pTemp = (PPREMOVEDIRLIST)LocalAlloc(LMEM_FIXED,sizeof(REMOVEDIRLIST));
  691. wcscpy(pTemp->PathStr, NewPN->PathStr);
  692. pTemp->Next = pRemDirList;
  693. pRemDirList = pTemp;
  694. }
  695. else {
  696. pRemDirList = (PPREMOVEDIRLIST)LocalAlloc(LMEM_FIXED, sizeof(REMOVEDIRLIST));
  697. wcscpy(pRemDirList->PathStr, NewPN->PathStr);
  698. pRemDirList->Next = NULL;
  699. }
  700. }
  701. continue;
  702. }
  703. // Directory was found, check the files
  704. for (NewFN = NewPN->FileHead; NewFN != NULL; NewFN = NewFN->Next)
  705. {
  706. // DbgPrint(" File is %s\n",NewFN->FileName);
  707. // File wasn't found, move it
  708. OrigFN = FindFile(OrigPN,NewFN);
  709. if (OrigFN == NULL)
  710. {
  711. TsMoveFile(NewPN,NewFN);
  712. continue;
  713. }
  714. // Check TimeStamp, if New Scan is more recent, move it.
  715. if (CheckDates(NewFN,OrigFN) == 1)
  716. {
  717. TsMoveFile(NewPN,NewFN);
  718. continue;
  719. }
  720. }
  721. }
  722. // Desc : BUG 267014 - added
  723. // Directories stack removal
  724. if (pRemDirList) {
  725. while (pRemDirList) {
  726. pTemp = pRemDirList;
  727. pRemDirList = pRemDirList->Next;
  728. RemoveDirectory(pTemp->PathStr);
  729. LocalFree(pTemp);
  730. }
  731. }
  732. }
  733. ////////////////////////////////////////////////////////////////////////////
  734. // Frees the in-memory representation of a start menu
  735. void FreeTree(PTREENODE Tree)
  736. {
  737. PPATHNODE PN,NextPN;
  738. PFILENODE FN,NextFN;
  739. for (PN = Tree->PathHead; PN != NULL; PN = NextPN)
  740. {
  741. for (FN = PN->FileHead; FN != NULL; FN = NextFN)
  742. {
  743. NextFN = FN->Next;
  744. LocalFree(FN);
  745. }
  746. NextPN = PN->Next;
  747. LocalFree(PN);
  748. }
  749. Tree->PathHead = NULL;
  750. Tree->PathTail = NULL;
  751. Tree->NumPaths = 0;
  752. }
  753. ////////////////////////////////////////////////////////////////////////////
  754. // Updates the "All User" menu by moving new items from the Current User's
  755. // start menu. In RunMode 0, a snapshot of the Current User's start menu
  756. // is taken. After modifications to the Current User's start menu are done,
  757. // this function is called again with RunMode 1. Then, it compares the
  758. // current state of the start menu with the saved snapshot. Any new or
  759. // modified files are copied over to the corresponding location in the
  760. // "All User" start menu.
  761. //
  762. // RunMode 0 is invoked when the system is changed into install mode and
  763. // mode 1 is called when the system returns to execute mode.
  764. int TermsrvUpdateAllUserMenu(int RunMode)
  765. {
  766. TREENODE OrigTree;
  767. TREENODE NewTree;
  768. WCHAR p[MAX_PATH];
  769. int retval;
  770. PMESSAGE_RESOURCE_ENTRY MessageEntry;
  771. PVOID DllHandle;
  772. NTSTATUS Status;
  773. DWORD dwlen;
  774. OrigTree.PathHead = NULL;
  775. OrigTree.PathTail = NULL;
  776. OrigTree.NumPaths = 0;
  777. NewTree.PathHead = NULL;
  778. NewTree.PathTail = NULL;
  779. NewTree.NumPaths = 0;
  780. retval = GetEnvironmentVariable(L"UserProfile", p, MAX_PATH);
  781. if (retval == 0)
  782. return(-1);
  783. if (!StartMenu[0]) {
  784. HINSTANCE hInst;
  785. typedef HRESULT (* LPFNSHGETFOLDERPATH)(HWND, int, HANDLE, DWORD, LPWSTR);
  786. LPFNSHGETFOLDERPATH lpfnSHGetFolderPath;
  787. WCHAR ssPath[MAX_PATH];
  788. WCHAR *LastSlash;
  789. wcscpy( StartMenu, L"\\Start Menu");
  790. hInst = LoadLibrary(L"SHELL32.DLL");
  791. if (hInst) {
  792. lpfnSHGetFolderPath = (LPFNSHGETFOLDERPATH)GetProcAddress(hInst,"SHGetFolderPathW");
  793. if (lpfnSHGetFolderPath) {
  794. if (S_OK == lpfnSHGetFolderPath(NULL, CSIDL_STARTMENU, NULL, 0, ssPath)) {
  795. LastSlash = wcsrevchr(ssPath, L'\\');
  796. if (LastSlash) {
  797. wcscpy(StartMenu, LastSlash);
  798. }
  799. }
  800. }
  801. FreeLibrary(hInst);
  802. }
  803. }
  804. wcscpy(SaveName,p);
  805. wcscat(SaveName,L"\\TsAllUsr.Dat");
  806. wcscpy(CurUserDir,p);
  807. wcscat(CurUserDir,StartMenu);
  808. CurUserDirLen = wcslen(CurUserDir);
  809. dwlen = sizeof(AllUserDir)/sizeof(WCHAR);
  810. if (GetAllUsersProfileDirectory(AllUserDir, &dwlen))
  811. {
  812. wcscat(AllUserDir,StartMenu);
  813. #if DBG
  814. DbgPrint("SaveName is '%S'\n",SaveName);
  815. DbgPrint("CurUserDir is '%S'\n",CurUserDir);
  816. DbgPrint("AllUserDir is '%S'\n",AllUserDir);
  817. #endif
  818. if (RunMode == 0)
  819. {
  820. // If the start menu snapshot already exists, don't overwrite it.
  821. // The user may enter "change user /install" twice, or an app may
  822. // force a reboot without changing back to execute mode. The
  823. // existing file is older. If we overwrite it, then some shortcuts
  824. // won't get moved.
  825. if (FileExists(SaveName) != TRUE)
  826. {
  827. ReadTree(&OrigTree, CurUserDir);
  828. if (WriteTreeToDisk(&OrigTree) == -1)
  829. DeleteFile(SaveName);
  830. FreeTree(&OrigTree);
  831. }
  832. }
  833. else if (RunMode == 1)
  834. {
  835. if (ReadTreeFromDisk(&OrigTree) == -1)
  836. {
  837. FreeTree(&OrigTree);
  838. DeleteFile(SaveName); // Could be a bad file. If it doesn't
  839. // exist, this won't hurt anything.
  840. return(-1);
  841. }
  842. ReadTree(&NewTree, CurUserDir);
  843. ProcessChanges(&OrigTree,&NewTree);
  844. DeleteFile(SaveName);
  845. FreeTree(&OrigTree);
  846. FreeTree(&NewTree);
  847. }
  848. }
  849. return(0);
  850. }