Windows2003-3790/termsrv/tsappcmp/allusrsm.c

1083 lines
32 KiB
C

/*************************************************************************
*
* allusrsm.c
*
* Move items from a user's start menu to the All Users start menu
*
* copyright notice: Copyright 1998 Micrsoft
*
* When entering install mode, if the start menu snapshot file already
* exists, don't overwrite it. Otherwise, some shortcuts may not get moved
* over. This fixes a problem where an App reboots the machine when it
* finishes installing, without giving the user a chance to switch back to
* execute mode. Now, when the user logs in again, the menu shortcuts will
* be moved because winlogon always does a "change user /install" and then
* "change user /execute". (That's to support RunOnce programs.)
* MS 1057
*
*
*************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
#include <userenv.h>
#include <shlobj.h>
// This program takes a snapshot of the Current User's start menu and
// saves it to a file. When run with the /c option, it compares the
// snapshot to the present contents of the Current User's start menu.
// Each new or changed file/directory is then moved to the All Users
// start menu. Additionally, Read permission is granted to the Everyone
// group for each moved file or directory.
typedef struct File_Struct {
struct File_Struct *Next; // Only used in Memory
WCHAR FileName[MAX_PATH];
BOOL TimeValid;
SYSTEMTIME Time;
} FILENODE, *PFILENODE;
typedef struct Path_Struct {
DWORD FilesInDir;
struct Path_Struct *Next; // Only used in Memory
PFILENODE FileHead; // Only used in Memory
PFILENODE FileTail; // Only used in Memory
WCHAR PathStr[MAX_PATH];
} PATHNODE, *PPATHNODE;
typedef struct Tree_Struct {
DWORD NumPaths;
PPATHNODE PathHead;
PPATHNODE PathTail;
} TREENODE, *PTREENODE;
typedef struct RemoveDir_Struct {
WCHAR PathStr[MAX_PATH];
struct RemoveDir_Struct *Next;
} REMOVEDIRLIST, *PPREMOVEDIRLIST;
int RunMode;
WCHAR SaveName[MAX_PATH];
WCHAR CurUserDir[MAX_PATH];
WCHAR AllUserDir[MAX_PATH];
int CurUserDirLen;
WCHAR StartMenu[MAX_PATH]=L"";
void ReadTree(PTREENODE Tree, WCHAR *Dir);
#define SD_SIZE (65536 + SECURITY_DESCRIPTOR_MIN_LENGTH)
////////////////////////////////////////////////////////////////////////////
BOOLEAN FileExists( WCHAR *path )
{
return( GetFileAttributes(path) == -1 ? FALSE : TRUE );
}
////////////////////////////////////////////////////////////////////////////
NTSTATUS CreateNewSecurityDescriptor( PSECURITY_DESCRIPTOR *ppNewSD,
PSECURITY_DESCRIPTOR pSD,
PACL pAcl )
/*++
Routine Description:
From a SD and a Dacl, create a new SD. The new SD will be fully self
contained (it is self relative) and does not have pointers to other
structures.
Arguments:
ppNewSD - used to return the new SD. Caller should free with LocalFree
pSD - the self relative SD we use to build the new SD
pAcl - the new DACL that will be used for the new SD
Return Value:
NTSTATUS code
--*/
{
PACL pSacl;
PSID psidGroup, psidOwner;
BOOLEAN fSaclPres;
BOOLEAN fSaclDef, fGroupDef, fOwnerDef;
ULONG NewSDSize;
SECURITY_DESCRIPTOR NewSD;
PSECURITY_DESCRIPTOR pNewSD;
NTSTATUS Status;
// extract the originals from the security descriptor
Status = RtlGetSaclSecurityDescriptor(pSD, &fSaclPres, &pSacl, &fSaclDef);
if (!NT_SUCCESS(Status))
return(Status);
Status = RtlGetOwnerSecurityDescriptor(pSD, &psidOwner, &fOwnerDef);
if (!NT_SUCCESS(Status))
return(Status);
Status = RtlGetGroupSecurityDescriptor(pSD, &psidGroup, &fGroupDef);
if (!NT_SUCCESS(Status))
return(Status);
// now create a new SD and set the info in it. we cannot return this one
// since it has pointers to old SD.
Status = RtlCreateSecurityDescriptor(&NewSD, SECURITY_DESCRIPTOR_REVISION);
if (!NT_SUCCESS(Status))
return(Status);
Status = RtlSetDaclSecurityDescriptor(&NewSD, TRUE, pAcl, FALSE);
if (!NT_SUCCESS(Status))
return(Status);
Status = RtlSetSaclSecurityDescriptor(&NewSD, fSaclPres, pSacl, fSaclDef);
if (!NT_SUCCESS(Status))
return(Status);
Status = RtlSetOwnerSecurityDescriptor(&NewSD, psidOwner, fOwnerDef);
if (!NT_SUCCESS(Status))
return(Status);
Status = RtlSetGroupSecurityDescriptor(&NewSD, psidGroup, fGroupDef);
if (!NT_SUCCESS(Status))
return(Status);
// calculate size needed for the returned SD and allocated it
NewSDSize = RtlLengthSecurityDescriptor(&NewSD);
pNewSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LMEM_FIXED, NewSDSize);
if (pNewSD == NULL)
return(STATUS_INSUFFICIENT_RESOURCES);
// convert the absolute to self relative
Status = RtlAbsoluteToSelfRelativeSD(&NewSD, pNewSD, &NewSDSize);
if (NT_SUCCESS(Status))
*ppNewSD = pNewSD;
else
LocalFree(pNewSD);
return(Status);
} // CreateNewSecurityDescriptor
/////////////////////////////////////////////////////////////////////////
// Add Read and Execute permissions for built in "Everyone" Group to
// the indicated file.
BOOLEAN APIENTRY AddEveryoneRXPermissionW( LPCWSTR lpFileName)
{
NTSTATUS Status;
BOOLEAN ExitVal = FALSE;
HANDLE FileHandle=NULL;
OBJECT_ATTRIBUTES Obja;
UNICODE_STRING FileName;
RTL_RELATIVE_NAME_U RelativeName;
BOOLEAN TranslationStatus;
IO_STATUS_BLOCK IoStatusBlock;
PVOID FreeBuffer;
PSECURITY_DESCRIPTOR pSD = NULL;
PSECURITY_DESCRIPTOR pNewSD = NULL;
DWORD LengthNeeded = 0;
static PACCESS_ALLOWED_ACE pNewAce = NULL;
static USHORT NewAceSize;
ACL Acl;
PACL pAcl, pNewAcl = NULL;
BOOLEAN fDaclPresent, fDaclDef;
USHORT NewAclSize;
////////////////////////////////////////////////////////////////////////
// First time through this routine, create an ACE for the built-in
// "Everyone" group.
////////////////////////////////////////////////////////////////////////
if (pNewAce == NULL)
{
PSID psidEveryone = NULL;
SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
// Get the SID of the built-in Everyone group
Status = RtlAllocateAndInitializeSid( &WorldSidAuthority, 1,
SECURITY_WORLD_RID, 0,0,0,0,0,0,0, &psidEveryone);
if (!NT_SUCCESS(Status))
goto ErrorExit;
// allocate and initialize new ACE
NewAceSize = (USHORT)(sizeof(ACE_HEADER) + sizeof(ACCESS_MASK) +
RtlLengthSid(psidEveryone));
pNewAce = (PACCESS_ALLOWED_ACE) LocalAlloc(LMEM_FIXED, NewAceSize);
if (pNewAce == NULL)
goto ErrorExit;
pNewAce->Header.AceFlags = (UCHAR) CONTAINER_INHERIT_ACE |
OBJECT_INHERIT_ACE ;
pNewAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
pNewAce->Header.AceSize = NewAceSize;
pNewAce->Mask = FILE_GENERIC_READ | FILE_EXECUTE;
RtlCopySid(RtlLengthSid(psidEveryone), (PSID)(&pNewAce->SidStart),
psidEveryone);
}
////////////////////////////////////////////////////////////////////////
// Open the indicated file.
////////////////////////////////////////////////////////////////////////
TranslationStatus = RtlDosPathNameToRelativeNtPathName_U( lpFileName,
&FileName, NULL, &RelativeName );
if ( !TranslationStatus ) {
goto ErrorExit;
}
FreeBuffer = FileName.Buffer;
if ( RelativeName.RelativeName.Length )
FileName = RelativeName.RelativeName;
else
RelativeName.ContainingDirectory = NULL;
InitializeObjectAttributes( &Obja, &FileName, OBJ_CASE_INSENSITIVE,
RelativeName.ContainingDirectory, NULL );
Status = NtOpenFile( &FileHandle, READ_CONTROL | WRITE_DAC, &Obja, &IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0 );
RtlReleaseRelativeName(&RelativeName);
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
if (!NT_SUCCESS(Status))
goto ErrorExit;
////////////////////////////////////////////////////////////////////////
// Retrieve the security descriptor for the file and then get the
// file's DACL from it.
////////////////////////////////////////////////////////////////////////
pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LMEM_FIXED, SD_SIZE);
if (pSD == NULL)
goto ErrorExit;
Status = NtQuerySecurityObject( FileHandle, DACL_SECURITY_INFORMATION,
pSD, SD_SIZE, &LengthNeeded );
if (!NT_SUCCESS(Status))
goto ErrorExit;
// extract the originals from the security descriptor
Status = RtlGetDaclSecurityDescriptor(pSD, &fDaclPresent, &pAcl, &fDaclDef);
if (!NT_SUCCESS(Status))
goto ErrorExit;
////////////////////////////////////////////////////////////////////////
// Create a new DACL by copying the existing DACL and appending the
// "Everyone" ACE.
////////////////////////////////////////////////////////////////////////
// if no DACL present, we create one
if ((fDaclPresent == FALSE) || (pAcl == NULL))
{
Status = RtlCreateAcl(&Acl, sizeof(Acl), ACL_REVISION) ;
if (!NT_SUCCESS(Status))
goto ErrorExit;
pAcl = &Acl;
}
// Copy the DACL into a larger buffer and add the new ACE to the end.
NewAclSize = pAcl->AclSize + NewAceSize;
pNewAcl = (PACL) LocalAlloc(LMEM_FIXED, NewAclSize);
if (!pNewAcl)
goto ErrorExit;
RtlCopyMemory(pNewAcl, pAcl, pAcl->AclSize);
pNewAcl->AclSize = NewAclSize;
Status = RtlAddAce(pNewAcl, ACL_REVISION, pNewAcl->AceCount,
pNewAce, NewAceSize);
if (!NT_SUCCESS(Status))
goto ErrorExit;
////////////////////////////////////////////////////////////////////////
// Create self-relative security descriptor with new DACL. Then
// save the security descriptor back to the file.
////////////////////////////////////////////////////////////////////////
Status = CreateNewSecurityDescriptor(&pNewSD, pSD, pNewAcl);
if (!NT_SUCCESS(Status))
goto ErrorExit;
Status = NtSetSecurityObject(FileHandle, DACL_SECURITY_INFORMATION, pNewSD);
if (!NT_SUCCESS(Status))
goto ErrorExit;
ExitVal = TRUE;
ErrorExit:
if (FileHandle != NULL)
NtClose(FileHandle);
if (pNewAcl != NULL)
LocalFree(pNewAcl);
if (pNewSD != NULL)
LocalFree(pNewSD);
if (pSD != NULL)
LocalFree(pSD);
return(ExitVal);
}
////////////////////////////////////////////////////////////////////////////
#if 0
BOOLEAN APIENTRY AddEveryoneRXPermissionA( WCHAR * lpFileName)
{
PUNICODE_STRING Unicode;
ANSI_STRING AnsiString;
NTSTATUS Status;
Unicode = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(&AnsiString,lpFileName);
Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) )
{
ULONG dwErrorCode;
dwErrorCode = RtlNtStatusToDosError( Status );
SetLastError( dwErrorCode );
return FALSE;
}
return ( AddEveryoneRXPermissionW((LPCWSTR)Unicode->Buffer) );
}
#endif
////////////////////////////////////////////////////////////////////////////
// return -1 for dates invalid, 0 for equal, 1 for f1 newer, 2 for f2 newer
int CheckDates(PFILENODE FN1, PFILENODE FN2)
{
SYSTEMTIME f1s = FN1->Time;
SYSTEMTIME f2s = FN2->Time;
if (FN1->TimeValid == FALSE || FN2->TimeValid == FALSE)
return -1;
if (f1s.wYear > f2s.wYear) return 1;
if (f1s.wYear < f2s.wYear) return 2;
if (f1s.wMonth > f2s.wMonth) return 1;
if (f1s.wMonth < f2s.wMonth) return 2;
if (f1s.wDay > f2s.wDay) return 1;
if (f1s.wDay < f2s.wDay) return 2;
if (f1s.wHour > f2s.wHour) return 1;
if (f1s.wHour < f2s.wHour) return 2;
if (f1s.wMinute > f2s.wMinute) return 1;
if (f1s.wMinute < f2s.wMinute) return 2;
if (f1s.wSecond > f2s.wSecond) return 1;
if (f1s.wSecond < f2s.wSecond) return 2;
return 0;
}
////////////////////////////////////////////////////////////////////////////
PPATHNODE GetPathNode(PTREENODE Tree, WCHAR *Dir)
{
PPATHNODE p;
// Handle Empty List
if (Tree->PathTail == NULL)
{
p = (PPATHNODE) LocalAlloc(0,sizeof(PATHNODE));
if (p == NULL)
return NULL;
Tree->PathHead = p;
Tree->PathTail = p;
Tree->NumPaths++;
p->Next = NULL;
p->FileHead = NULL;
p->FileTail = NULL;
p->FilesInDir = 0;
wcscpy(p->PathStr,Dir);
return p;
}
// Last Node Matches
if (wcscmp(Tree->PathTail->PathStr,Dir) == 0)
return Tree->PathTail;
// Need to add a node
p = (PPATHNODE) LocalAlloc(0,sizeof(PATHNODE));
if (p == NULL)
return NULL;
Tree->PathTail->Next = p;
Tree->PathTail = p;
Tree->NumPaths++;
p->Next = NULL;
p->FileHead = NULL;
p->FileTail = NULL;
p->FilesInDir = 0;
wcscpy(p->PathStr,Dir);
return p;
}
////////////////////////////////////////////////////////////////////////////
void AddFileNode(PTREENODE Tree, WCHAR *Dir, PFILENODE FileNode)
{
PPATHNODE PathNode = GetPathNode(Tree, Dir);
if (FileNode == NULL)
return;
if (PathNode == NULL)
{
LocalFree(FileNode);
return;
}
// New node is always the last.
FileNode->Next = NULL;
// If list isn't empty, link to last node in list
// Otherwise, set head pointer.
if (PathNode->FileTail != NULL)
PathNode->FileTail->Next = FileNode;
else
PathNode->FileHead = FileNode;
// Put new node on end of list.
PathNode->FileTail = FileNode;
PathNode->FilesInDir++;
}
////////////////////////////////////////////////////////////////////////////
void ProcessFile(PTREENODE Tree, LPWIN32_FIND_DATA LocalData, WCHAR *LocalDir)
{
PFILENODE FileNode;
// Don't handle directories
if ((LocalData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
return;
// Allocate a file node
FileNode = (PFILENODE) LocalAlloc(0,sizeof(FILENODE));
if (FileNode == NULL)
return;
// Fill in the Local Fields
wcscpy(FileNode->FileName, LocalData->cFileName);
FileNode->TimeValid = FileTimeToSystemTime(&LocalData->ftLastWriteTime,
&FileNode->Time);
// Add to the list
AddFileNode(Tree, LocalDir, FileNode);
}
////////////////////////////////////////////////////////////////////////////
void ProcessDir(PTREENODE Tree, LPWIN32_FIND_DATA FindData, WCHAR *Dir)
{
WCHAR NewDir[MAX_PATH];
PPATHNODE PathNode;
// Only Handle Directories
if ((FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
return;
// Don't recurse into these directories
if (wcscmp(FindData->cFileName, L".") == 0)
return;
if (wcscmp(FindData->cFileName, L"..") == 0)
return;
wcscpy(NewDir,Dir);
wcscat(NewDir,L"\\");
wcscat(NewDir,FindData->cFileName);
// This creates a node for the directory. Nodes get automatically
// created when adding files, but that doesn't handle empty
// directories. This does.
PathNode = GetPathNode(Tree, NewDir);
ReadTree(Tree, NewDir);
}
////////////////////////////////////////////////////////////////////////////
// Creates an in-memory representation of the Current User's start menu.
void ReadTree(PTREENODE Tree, WCHAR *Dir)
{
HANDLE FindHandle;
WIN32_FIND_DATA FindData;
int retval;
// First compare all files in current directory.
retval = SetCurrentDirectory(Dir);
if (retval == 0)
{
// printf("Unable to find directory %s\n",Dir);
return;
}
FindHandle = FindFirstFile(L"*.*", &FindData);
if (FindHandle != INVALID_HANDLE_VALUE)
{
ProcessFile(Tree, &FindData, Dir);
while (FindNextFile(FindHandle, &FindData) != FALSE)
ProcessFile(Tree, &FindData, Dir);
FindClose(FindHandle);
}
// Next, handle subdirectories.
retval = SetCurrentDirectory(Dir);
if (retval == 0)
{
// printf("Unable to find directory %s\n",Dir);
return;
}
FindHandle = FindFirstFile(L"*.*", &FindData);
if (FindHandle != INVALID_HANDLE_VALUE)
{
ProcessDir(Tree, &FindData, Dir);
while (FindNextFile(FindHandle, &FindData) != FALSE)
ProcessDir(Tree, &FindData, Dir);
FindClose(FindHandle);
}
}
////////////////////////////////////////////////////////////////////////////
int WriteTreeToDisk(PTREENODE Tree)
{
PPATHNODE PN;
PFILENODE FN;
HANDLE hFile;
DWORD BytesWritten;
DWORD i;
hFile = CreateFile(SaveName, GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return(-1); // error
// DbgPrint("Tree->NumPaths is %d\n",Tree->NumPaths);
if (WriteFile(hFile,&Tree->NumPaths,sizeof(DWORD),&BytesWritten, NULL) == 0)
{
CloseHandle(hFile);
return(-1); // error
}
for (PN = Tree->PathHead; PN != NULL; PN = PN->Next)
{
if (WriteFile(hFile,PN,sizeof(PATHNODE),&BytesWritten, NULL) == 0)
{
CloseHandle(hFile);
return(-1); // error
}
// DbgPrint("\n%s (%d)\n",PN->PathStr, PN->FilesInDir);
FN = PN->FileHead;
for (i = 0; i < PN->FilesInDir; i++)
{
if (WriteFile(hFile,FN,sizeof(FILENODE),&BytesWritten, NULL) == 0)
{
CloseHandle(hFile);
return(-1); // error
}
// DbgPrint(" %s \n", FN->FileName);
FN = FN->Next;
}
}
CloseHandle(hFile);
return(0);
}
////////////////////////////////////////////////////////////////////////////
int ReadTreeFromDisk(PTREENODE Tree)
{
PATHNODE LocalPath;
PPATHNODE PN;
PFILENODE FN;
HANDLE hFile;
DWORD BytesRead;
DWORD i,j;
DWORD NumFiles, NumTrees;
hFile = CreateFile(SaveName, GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return(-1);
if (ReadFile(hFile,&NumTrees,sizeof(DWORD),&BytesRead, NULL) == 0)
{
CloseHandle(hFile);
return(-1); // error
}
for (i = 0; i < NumTrees; i++)
{
if (ReadFile(hFile,&LocalPath,sizeof(PATHNODE),&BytesRead, NULL) == 0)
{
CloseHandle(hFile);
return(-1); // error
}
PN = GetPathNode(Tree, LocalPath.PathStr);
if (PN == NULL)
{
CloseHandle(hFile);
return(-1); // error
}
NumFiles = LocalPath.FilesInDir;
// DbgPrint("\n<<%s (%d)\n",PN->PathStr, NumFiles);
for (j = 0; j < NumFiles; j++)
{
// Allocate a file node
FN = (PFILENODE) LocalAlloc(0,sizeof(FILENODE));
if (FN == NULL)
{
CloseHandle(hFile);
return(-1); // error
}
if (ReadFile(hFile,FN,sizeof(FILENODE),&BytesRead, NULL) == 0)
{
CloseHandle(hFile);
LocalFree(FN);
return(-1); // error
}
AddFileNode(Tree, PN->PathStr, FN);
// DbgPrint(" %d: %s >>\n", j, FN->FileName);
}
}
CloseHandle(hFile);
return(0);
}
////////////////////////////////////////////////////////////////////////////
// Finds a path in a menu tree. If not found, NULL is returned.
PPATHNODE FindPath(PTREENODE Tree, PPATHNODE PN)
{
PPATHNODE FoundPN;
for (FoundPN = Tree->PathHead; FoundPN != NULL; FoundPN = FoundPN->Next)
{
if (_wcsicmp(FoundPN->PathStr,PN->PathStr) == 0)
return FoundPN;
}
return NULL;
}
////////////////////////////////////////////////////////////////////////////
// Finds a file in a directory node. If not found, NULL is returned.
PFILENODE FindFile(PPATHNODE PN, PFILENODE FN)
{
PFILENODE FoundFN;
for (FoundFN = PN->FileHead; FoundFN != NULL; FoundFN = FoundFN->Next)
{
if (_wcsicmp(FoundFN->FileName,FN->FileName) == 0)
return FoundFN;
}
return NULL;
}
////////////////////////////////////////////////////////////////////////////
/* ==============================================================
Function Name : wcsrevchr
Description : Reverse wcschr
Finds a character in a string starting from the end
Arguments :
Return Value : PWCHAR
============================================================== */
PWCHAR wcsrevchr( PWCHAR string, WCHAR ch )
{
int cLen, iCount;
cLen = wcslen(string);
string += cLen;
for (iCount = cLen; iCount && *string != ch ; iCount--, string--)
;
if (*string == ch)
return string;
else
return NULL;
}
////////////////////////////////////////////////////////////////////////////
// Create the indicated directory. This function creates any parent
// directories that are needed too.
//
// Return: TRUE = directory now exists
// FALSE = directory couldn't be created
BOOLEAN TsCreateDirectory( WCHAR *DirName )
{
BOOL RetVal;
WCHAR *LastSlash;
//
// Try to create the specified directory. If the create works or
// the directory already exists, return TRUE. If the called failed
// because the path wasn't found, continue. This occurs if the
// parent directory doesn't exist.
//
RetVal = CreateDirectory(DirName, NULL);
if ((RetVal == TRUE) || (GetLastError() == ERROR_ALREADY_EXISTS))
return(TRUE);
if (GetLastError() != ERROR_PATH_NOT_FOUND)
return(FALSE);
//
// Remove the last component of the path and try creating the
// parent directory. Upon return, add the last component back
// in and try to create the specified directory again.
//
// Desc : BUG 267014 - replaced
// LastSlash = wcschr(DirName, L'\\');
// Given a full pathname, previous always returns the drive letter.
// Next line returns path components
LastSlash = wcsrevchr(DirName, L'\\');
if (LastSlash == NULL) // Can't reduce path any more
return(FALSE);
*LastSlash = L'\0';
RetVal = TsCreateDirectory(DirName);
*LastSlash = L'\\';
if (RetVal == FALSE) // Couldn't create parent directory
return(FALSE);
RetVal = CreateDirectory(DirName, NULL);
if ((RetVal == TRUE) || (GetLastError() == ERROR_ALREADY_EXISTS))
return(TRUE);
return(FALSE);
}
////////////////////////////////////////////////////////////////////////////
// Moves a file from the current start menu to the All Users start menu.
// Creates any directories that may be needed in the All Users menu.
void TsMoveFile(PPATHNODE PN, PFILENODE FN)
{
WCHAR Src[MAX_PATH];
WCHAR Dest[MAX_PATH];
// Normalize Source Path
wcscpy(Src,PN->PathStr);
if (Src[wcslen(Src)-1] != L'\\')
wcscat(Src,L"\\");
// Create Destination Path.
wcscpy(Dest,AllUserDir);
wcscat(Dest,&Src[CurUserDirLen]);
// If directory doesn't exist, make it. The default permission is fine.
if (TsCreateDirectory(Dest) != TRUE)
return;
wcscat(Src,FN->FileName);
wcscat(Dest,FN->FileName);
// Move Fails if the target already exists. This could happen
// if we're copying a file that has a newer timestamp.
if ( GetFileAttributes(Dest) != -1 )
DeleteFile(Dest);
// DbgPrint("Moving File %s \n to %s\n",Src,Dest);
if (MoveFile(Src, Dest) == FALSE)
return;
AddEveryoneRXPermissionW(Dest);
}
////////////////////////////////////////////////////////////////////////////
// Compare the current start menu with the original. Copy any new or
// changed files to the All Users menu.
void ProcessChanges(PTREENODE OrigTree, PTREENODE NewTree)
{
PPATHNODE NewPN, OrigPN;
PFILENODE NewFN, OrigFN;
BOOL fRet;
PPREMOVEDIRLIST pRemDirList = NULL, pTemp;
for (NewPN = NewTree->PathHead; NewPN != NULL; NewPN = NewPN->Next)
{
// DbgPrint("PC: Dir is %s\n",NewPN->PathStr);
// If directory not found in original tree, move it over
OrigPN = FindPath(OrigTree, NewPN);
if (OrigPN == NULL)
{
for (NewFN = NewPN->FileHead; NewFN != NULL; NewFN = NewFN->Next)
{
// DbgPrint(" Move File is %s\n",NewFN->FileName);
TsMoveFile(NewPN,NewFN);
}
// Desc : BUG 267014 - replaced
// RemoveDirectory(NewPN->PathStr);
// We have a problem if NewPN doesn't contain file items but subfolders.
// In this case, we do not enter the above loop, as there is nothing to move
// But the folder can't be removed because it contains a tree that haven't been moved yet.
// To remove it, we store its name in a LIFO stack. Stack items are removed when the loop exits
fRet = RemoveDirectory(NewPN->PathStr);
if (!fRet && GetLastError() == ERROR_DIR_NOT_EMPTY) {
#if DBG
DbgPrint("Adding to List--%S\n", NewPN->PathStr);
#endif
if (pRemDirList) {
pTemp = (PPREMOVEDIRLIST)LocalAlloc(LMEM_FIXED,sizeof(REMOVEDIRLIST));
wcscpy(pTemp->PathStr, NewPN->PathStr);
pTemp->Next = pRemDirList;
pRemDirList = pTemp;
}
else {
pRemDirList = (PPREMOVEDIRLIST)LocalAlloc(LMEM_FIXED, sizeof(REMOVEDIRLIST));
wcscpy(pRemDirList->PathStr, NewPN->PathStr);
pRemDirList->Next = NULL;
}
}
continue;
}
// Directory was found, check the files
for (NewFN = NewPN->FileHead; NewFN != NULL; NewFN = NewFN->Next)
{
// DbgPrint(" File is %s\n",NewFN->FileName);
// File wasn't found, move it
OrigFN = FindFile(OrigPN,NewFN);
if (OrigFN == NULL)
{
TsMoveFile(NewPN,NewFN);
continue;
}
// Check TimeStamp, if New Scan is more recent, move it.
if (CheckDates(NewFN,OrigFN) == 1)
{
TsMoveFile(NewPN,NewFN);
continue;
}
}
}
// Desc : BUG 267014 - added
// Directories stack removal
if (pRemDirList) {
while (pRemDirList) {
pTemp = pRemDirList;
pRemDirList = pRemDirList->Next;
RemoveDirectory(pTemp->PathStr);
LocalFree(pTemp);
}
}
}
////////////////////////////////////////////////////////////////////////////
// Frees the in-memory representation of a start menu
void FreeTree(PTREENODE Tree)
{
PPATHNODE PN,NextPN;
PFILENODE FN,NextFN;
for (PN = Tree->PathHead; PN != NULL; PN = NextPN)
{
for (FN = PN->FileHead; FN != NULL; FN = NextFN)
{
NextFN = FN->Next;
LocalFree(FN);
}
NextPN = PN->Next;
LocalFree(PN);
}
Tree->PathHead = NULL;
Tree->PathTail = NULL;
Tree->NumPaths = 0;
}
////////////////////////////////////////////////////////////////////////////
// Updates the "All User" menu by moving new items from the Current User's
// start menu. In RunMode 0, a snapshot of the Current User's start menu
// is taken. After modifications to the Current User's start menu are done,
// this function is called again with RunMode 1. Then, it compares the
// current state of the start menu with the saved snapshot. Any new or
// modified files are copied over to the corresponding location in the
// "All User" start menu.
//
// RunMode 0 is invoked when the system is changed into install mode and
// mode 1 is called when the system returns to execute mode.
int TermsrvUpdateAllUserMenu(int RunMode)
{
TREENODE OrigTree;
TREENODE NewTree;
WCHAR p[MAX_PATH];
int retval;
PMESSAGE_RESOURCE_ENTRY MessageEntry;
PVOID DllHandle;
NTSTATUS Status;
DWORD dwlen;
OrigTree.PathHead = NULL;
OrigTree.PathTail = NULL;
OrigTree.NumPaths = 0;
NewTree.PathHead = NULL;
NewTree.PathTail = NULL;
NewTree.NumPaths = 0;
retval = GetEnvironmentVariable(L"UserProfile", p, MAX_PATH);
if (retval == 0)
return(-1);
if (!StartMenu[0]) {
HINSTANCE hInst;
typedef HRESULT (* LPFNSHGETFOLDERPATH)(HWND, int, HANDLE, DWORD, LPWSTR);
LPFNSHGETFOLDERPATH lpfnSHGetFolderPath;
WCHAR ssPath[MAX_PATH];
WCHAR *LastSlash;
wcscpy( StartMenu, L"\\Start Menu");
hInst = LoadLibrary(L"SHELL32.DLL");
if (hInst) {
lpfnSHGetFolderPath = (LPFNSHGETFOLDERPATH)GetProcAddress(hInst,"SHGetFolderPathW");
if (lpfnSHGetFolderPath) {
if (S_OK == lpfnSHGetFolderPath(NULL, CSIDL_STARTMENU, NULL, 0, ssPath)) {
LastSlash = wcsrevchr(ssPath, L'\\');
if (LastSlash) {
wcscpy(StartMenu, LastSlash);
}
}
}
FreeLibrary(hInst);
}
}
wcscpy(SaveName,p);
wcscat(SaveName,L"\\TsAllUsr.Dat");
wcscpy(CurUserDir,p);
wcscat(CurUserDir,StartMenu);
CurUserDirLen = wcslen(CurUserDir);
dwlen = sizeof(AllUserDir)/sizeof(WCHAR);
if (GetAllUsersProfileDirectory(AllUserDir, &dwlen))
{
wcscat(AllUserDir,StartMenu);
#if DBG
DbgPrint("SaveName is '%S'\n",SaveName);
DbgPrint("CurUserDir is '%S'\n",CurUserDir);
DbgPrint("AllUserDir is '%S'\n",AllUserDir);
#endif
if (RunMode == 0)
{
// If the start menu snapshot already exists, don't overwrite it.
// The user may enter "change user /install" twice, or an app may
// force a reboot without changing back to execute mode. The
// existing file is older. If we overwrite it, then some shortcuts
// won't get moved.
if (FileExists(SaveName) != TRUE)
{
ReadTree(&OrigTree, CurUserDir);
if (WriteTreeToDisk(&OrigTree) == -1)
DeleteFile(SaveName);
FreeTree(&OrigTree);
}
}
else if (RunMode == 1)
{
if (ReadTreeFromDisk(&OrigTree) == -1)
{
FreeTree(&OrigTree);
DeleteFile(SaveName); // Could be a bad file. If it doesn't
// exist, this won't hurt anything.
return(-1);
}
ReadTree(&NewTree, CurUserDir);
ProcessChanges(&OrigTree,&NewTree);
DeleteFile(SaveName);
FreeTree(&OrigTree);
FreeTree(&NewTree);
}
}
return(0);
}