//*************************************************************
//  File name: profile.c
//
//  Description:   Fixes hard coded paths in the registry for
//                 special folder locations.  Also fixes security
//                 on a few registry keys.
//
//  Microsoft Confidential
//  Copyright (c) Microsoft Corporation 1996
//  All rights reserved
//
//*************************************************************

#include <windows.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <xpsp1res.h>
#include <userenv.h>
#include <userenvp.h>
#include <tchar.h>
#include "shmgdefs.h"


//*************************************************************
//
//  ApplySecurityToRegistryTree()
//
//  Purpose:    Applies the passed security descriptor to the passed
//              key and all its descendants.  Only the parts of
//              the descriptor inddicated in the security
//              info value are actually applied to each registry key.
//
//  Parameters: RootKey   -     Registry key
//              pSD       -     Security Descriptor
//
//  Return:     ERROR_SUCCESS if successful
//
//  Comments:
//
//  History:    Date        Author     Comment
//              7/19/95     ericflo    Created
//              6/16/96     bobday     Stolen directly from USERENV
//
//*************************************************************

DWORD ApplySecurityToRegistryTree(HKEY RootKey, PSECURITY_DESCRIPTOR pSD)

{
    DWORD Error;
    DWORD SubKeyIndex;
    LPTSTR SubKeyName;
    HKEY SubKey;
    DWORD cchSubKeySize = MAX_PATH + 1;



    //
    // First apply security
    //

    Error = RegSetKeySecurity(RootKey, DACL_SECURITY_INFORMATION, pSD);

    if (Error != ERROR_SUCCESS) {
        return Error;
    }


    //
    // Open each sub-key and apply security to its sub-tree
    //

    SubKeyIndex = 0;

    SubKeyName = GlobalAlloc (GPTR, cchSubKeySize * sizeof(TCHAR));

    if (!SubKeyName) {
        return GetLastError();
    }

    while (TRUE) {

        //
        // Get the next sub-key name
        //

        Error = RegEnumKey(RootKey, SubKeyIndex, SubKeyName, cchSubKeySize);


        if (Error != ERROR_SUCCESS) {

            if (Error == ERROR_NO_MORE_ITEMS) {

                //
                // Successful end of enumeration
                //

                Error = ERROR_SUCCESS;

            } else {

            }

            break;
        }


        //
        // Open the sub-key
        //

        Error = RegOpenKeyEx(RootKey,
                             SubKeyName,
                             0,
                             WRITE_DAC | KEY_ENUMERATE_SUB_KEYS | READ_CONTROL,
                             &SubKey);

        if (Error != ERROR_SUCCESS) {
            break;
        }

        //
        // Apply security to the sub-tree
        //

        Error = ApplySecurityToRegistryTree(SubKey, pSD);


        //
        // We're finished with the sub-key
        //

        RegCloseKey(SubKey);

        //
        // See if we set the security on the sub-tree successfully.
        //

        if (Error != ERROR_SUCCESS) {
            break;
        }

        //
        // Go enumerate the next sub-key
        //

        SubKeyIndex ++;
    }


    GlobalFree (SubKeyName);

    return Error;

}

//*************************************************************
//
//  MakeKeyOrTreeSecure()
//
//  Purpose:    Sets the attributes on the registry key and possibly sub-keys
//              such that Administrators and the OS can delete it and Everyone
//              else has read permission only (OR general read/write access)
//
//  Parameters: RootKey -   Key to set security on
//              fWrite  -   Allow write (or just read)
//
//  Return:     (BOOL) TRUE if successful
//                     FALSE if an error occurs
//
//  Comments:
//
//  History:    Date        Author     Comment
//              11/6/95     ericflo    Created
//              06/16/96    bobday     Ported from MakeFileSecure in USERENV
//
//*************************************************************

BOOL MakeKeyOrTreeSecure (HKEY RootKey, BOOL fWrite)
{
    SECURITY_DESCRIPTOR sd;
    SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY;
    SID_IDENTIFIER_AUTHORITY authWorld = SECURITY_WORLD_SID_AUTHORITY;
    PACL pAcl = NULL;
    PSID  psidSystem = NULL, psidAdmin = NULL, psidEveryone = NULL;
    DWORD cbAcl, aceIndex;
    ACE_HEADER * lpAceHeader;
    BOOL bRetVal = FALSE;
    DWORD Error;
    DWORD dwAccess;



    if (fWrite) {
        dwAccess = KEY_ALL_ACCESS;
    } else {
        dwAccess = KEY_READ;
    }

    //
    // Get the system sid
    //

    if (!AllocateAndInitializeSid(&authNT, 1, SECURITY_LOCAL_SYSTEM_RID,
                                  0, 0, 0, 0, 0, 0, 0, &psidSystem)) {
         goto Exit;
    }


    //
    // Get the Admin sid
    //

    if (!AllocateAndInitializeSid(&authNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
                                  DOMAIN_ALIAS_RID_ADMINS, 0, 0,
                                  0, 0, 0, 0, &psidAdmin)) {
         goto Exit;
    }


    //
    // Get the World sid
    //

    if (!AllocateAndInitializeSid(&authWorld, 1, SECURITY_WORLD_RID,
                                  0, 0, 0, 0, 0, 0, 0, &psidEveryone)) {

         goto Exit;
    }


    //
    // Allocate space for the ACL
    //

    cbAcl = (3 * GetLengthSid (psidSystem)) +
            (3 * GetLengthSid (psidAdmin)) + sizeof(ACL) +
            (6 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)));


    pAcl = (PACL) GlobalAlloc(GMEM_FIXED, cbAcl);
    if (!pAcl) {
        goto Exit;
    }


    if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION)) {
        goto Exit;
    }



    //
    // Add Aces.  Non-inheritable ACEs first
    //

    aceIndex = 0;
    if (!AddAccessAllowedAce(pAcl, ACL_REVISION, KEY_ALL_ACCESS, psidSystem)) {
        goto Exit;
    }


    aceIndex++;
    if (!AddAccessAllowedAce(pAcl, ACL_REVISION, KEY_ALL_ACCESS, psidAdmin)) {
        goto Exit;
    }


    aceIndex++;
    if (!AddAccessAllowedAce(pAcl, ACL_REVISION, dwAccess, psidEveryone)) {
        goto Exit;
    }



    //
    // Now the inheritable ACEs
    //
    if (fWrite) {
        dwAccess = GENERIC_ALL;
    } else {
        dwAccess = GENERIC_READ;
    }


    aceIndex++;
    if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidSystem)) {
        goto Exit;
    }

    if (!GetAce(pAcl, aceIndex, &lpAceHeader)) {
        goto Exit;
    }

    lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);


    aceIndex++;
    if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidAdmin)) {
        goto Exit;
    }

    if (!GetAce(pAcl, aceIndex, &lpAceHeader)) {
        goto Exit;
    }

    lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);

    aceIndex++;
    if (!AddAccessAllowedAce(pAcl, ACL_REVISION, dwAccess, psidEveryone)) {
        goto Exit;
    }

    if (!GetAce(pAcl, aceIndex, &lpAceHeader)) {
        goto Exit;
    }

    lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);


    //
    // Put together the security descriptor
    //

    if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
        goto Exit;
    }


    if (!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) {
        goto Exit;
    }


    //
    // Set the security
    //
    Error = ApplySecurityToRegistryTree(RootKey, &sd);

    if (Error == ERROR_SUCCESS) {
        bRetVal = TRUE;
    }


Exit:

    if (psidSystem) {
        FreeSid(psidSystem);
    }

    if (psidAdmin) {
        FreeSid(psidAdmin);
    }


    if (psidEveryone) {
        FreeSid(psidEveryone);
    }


    if (pAcl) {
        GlobalFree (pAcl);
    }

    return bRetVal;
}

void FixWindowsProfileSecurity( void )
{
    HKEY    hkeyWindows;
    HKEY    hkeyShellExt;
    DWORD   Error;

    Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
                          TEXT("Software\\Microsoft\\Windows"),
                          0,
                          WRITE_DAC | KEY_ENUMERATE_SUB_KEYS | READ_CONTROL,
                          &hkeyWindows);

    if (Error == ERROR_SUCCESS)
    {
        MakeKeyOrTreeSecure(hkeyWindows, TRUE);
        RegCloseKey(hkeyWindows);
    }

    Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
                          TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions"),
                          0,
                          WRITE_DAC | KEY_ENUMERATE_SUB_KEYS | READ_CONTROL,
                          &hkeyShellExt);
    if (Error == ERROR_SUCCESS)
    {
        MakeKeyOrTreeSecure(hkeyShellExt, FALSE);
        RegCloseKey(hkeyShellExt);
    }
}

void FixUserProfileSecurity( void )
{
    HKEY    hkeyPolicies;
    DWORD   Error;

    Error = RegOpenKeyEx( HKEY_CURRENT_USER,
                          TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies"),
                          0,
                          WRITE_DAC | KEY_ENUMERATE_SUB_KEYS | READ_CONTROL,
                          &hkeyPolicies);

    if (Error == ERROR_SUCCESS)
    {
        MakeKeyOrTreeSecure(hkeyPolicies, FALSE);
        RegCloseKey(hkeyPolicies);
    }
}

void FixPoliciesSecurity( void )
{
    HKEY    hkeyPolicies;
    DWORD   Error, dwDisp;

    Error = RegCreateKeyEx( HKEY_CURRENT_USER,
                            TEXT("Software\\Policies"),
                            0,
                            NULL,
                            REG_OPTION_NON_VOLATILE,
                            WRITE_DAC | KEY_ENUMERATE_SUB_KEYS | READ_CONTROL,
                            NULL,
                            &hkeyPolicies,
                            &dwDisp);

    if (Error == ERROR_SUCCESS)
    {
        MakeKeyOrTreeSecure(hkeyPolicies, FALSE);
        RegCloseKey(hkeyPolicies);
    }
}

void SetSystemBitOnCAPIDir(void)
{
    HRESULT hr;
    TCHAR szPath[MAX_PATH];
    TCHAR szAppData[MAX_PATH];
    DWORD FileAttributes;


    if (S_OK == SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, szAppData)){

        //
        // It is better to use tcscpy and tcscat. This is just a temp fix and it is build with
        // Unicode anyway. Not worth to include extra header file.
        // We do not check error case here. This is just a best effort. If we got error, so what?
        // MAX_PATH should be enough for these DIRs. Not worth to take care of \\?\ format.
        //

        lstrcpyn(szPath, szAppData, ARRAYSIZE(szPath));
        StrCatBuff(szPath, TEXT("\\Microsoft\\Protect"), ARRAYSIZE(szPath));
        FileAttributes = GetFileAttributes(szPath);
        if ((FileAttributes != -1) && ((FileAttributes & FILE_ATTRIBUTE_SYSTEM) == 0)) {
            FileAttributes |= FILE_ATTRIBUTE_SYSTEM;
            SetFileAttributes(szPath, FileAttributes);
        }

        lstrcpyn(szPath, szAppData, ARRAYSIZE(szPath));
        StrCatBuff(szPath, TEXT("\\Microsoft\\Crypto"), ARRAYSIZE(szPath));
        FileAttributes = GetFileAttributes(szPath);
        if ((FileAttributes != -1) && ((FileAttributes & FILE_ATTRIBUTE_SYSTEM) == 0)) {
            FileAttributes |= FILE_ATTRIBUTE_SYSTEM;
            SetFileAttributes(szPath, FileAttributes);
        }
    }

}

void SetScreensaverOnFriendlyUI()
{
    if (IsOS(OS_FRIENDLYLOGONUI)       &&
        IsOS(OS_FASTUSERSWITCHING))
    {
        HKEY hkey;

        if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop"), 0, KEY_SET_VALUE, &hkey) == ERROR_SUCCESS)
        {
            TCHAR szTemp[MAX_PATH];

            RegSetValueEx(hkey, TEXT("ScreenSaveActive"), 0, REG_SZ, (BYTE*)TEXT("1"), sizeof(TEXT("1")));
    
            if (RegQueryValueEx(hkey, TEXT("SCRNSAVE.EXE"), NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
            {
                // if the user dosen't already have a screensaver set, then choose one for them!
                if (ExpandEnvironmentStrings(TEXT("%SystemRoot%\\System32\\logon.scr"), szTemp, ARRAYSIZE(szTemp)))
                {
                    RegSetValueEx(hkey, TEXT("SCRNSAVE.EXE"), 0, REG_SZ, (BYTE*)szTemp, (lstrlen(szTemp) + 1) * sizeof(TCHAR));
                }
            }

            RegCloseKey(hkey);
        }
    }
}


#define OTHERSIDS_EVERYONE             1
#define OTHERSIDS_POWERUSERS           2

BOOL MakeFileSecure (LPTSTR lpFile, DWORD dwOtherSids)
{
    SECURITY_DESCRIPTOR sd;
    SECURITY_ATTRIBUTES sa;
    SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY;
    SID_IDENTIFIER_AUTHORITY authWORLD = SECURITY_WORLD_SID_AUTHORITY;
    PACL pAcl = NULL;
    PSID  psidSystem = NULL, psidAdmin = NULL, psidUsers = NULL, psidPowerUsers = NULL;
    PSID  psidEveryOne = NULL;
    DWORD cbAcl, aceIndex;
    ACE_HEADER * lpAceHeader;
    BOOL bRetVal = FALSE;
    BOOL bAddPowerUsersAce=TRUE;
    BOOL bAddEveryOneAce=FALSE;
    DWORD dwAccMask;


    //
    // Get the system sid
    //

    if (!AllocateAndInitializeSid(&authNT, 1, SECURITY_LOCAL_SYSTEM_RID,
                                  0, 0, 0, 0, 0, 0, 0, &psidSystem)) {
         goto Exit;
    }


    //
    // Get the Admin sid
    //

    if (!AllocateAndInitializeSid(&authNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
                                  DOMAIN_ALIAS_RID_ADMINS, 0, 0,
                                  0, 0, 0, 0, &psidAdmin)) {
         goto Exit;
    }


    //
    // Get the users sid
    //

    if (!AllocateAndInitializeSid(&authNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
                                  DOMAIN_ALIAS_RID_USERS,
                                  0, 0, 0, 0, 0, 0, &psidUsers)) {

         goto Exit;
    }


    //
    // Allocate space for the ACL
    //

    cbAcl = (2 * GetLengthSid (psidSystem)) +
            (2 * GetLengthSid (psidAdmin))  +
            (2 * GetLengthSid (psidUsers))  +
            sizeof(ACL) +
            (6 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)));

    //
    // Get the power users sid, if required.
    // Don't fail if you don't get because it might not be available on DCs??
    //

    bAddPowerUsersAce = TRUE;
    if (!AllocateAndInitializeSid(&authNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
        DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0, &psidPowerUsers)) {

        bAddPowerUsersAce = FALSE;
    }

    if (bAddPowerUsersAce)
        cbAcl += (2 * GetLengthSid (psidPowerUsers)) + (2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)));

    //
    // Get the EveryOne sid, if required.
    //

    if (dwOtherSids & OTHERSIDS_EVERYONE) {
        bAddEveryOneAce = TRUE;
        if (!AllocateAndInitializeSid(&authWORLD, 1, SECURITY_WORLD_RID,
                                  0, 0, 0, 0, 0, 0, 0, &psidEveryOne)) {

            goto Exit;
        }
    }

    if (bAddEveryOneAce)
        cbAcl += (2 * GetLengthSid (psidEveryOne)) + (2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)));


    pAcl = (PACL) GlobalAlloc(GMEM_FIXED, cbAcl);
    if (!pAcl) {
        goto Exit;
    }


    if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION)) {
        goto Exit;
    }


    //
    // Add Aces.  Non-inheritable ACEs first
    //

    aceIndex = 0;
    if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidSystem)) {
        goto Exit;
    }


    aceIndex++;
    if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidAdmin)) {
        goto Exit;
    }


    aceIndex++;
    if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, /*GENERIC_READ | GENERIC_EXECUTE,*/ psidUsers)) {
        goto Exit;
    }


    if (bAddPowerUsersAce) {

        //
        // By default give read permissions, otherwise give modify permissions
        //

        dwAccMask = (dwOtherSids & OTHERSIDS_POWERUSERS) ? (FILE_ALL_ACCESS ^ (WRITE_DAC | WRITE_OWNER)):
                                                           (GENERIC_READ | GENERIC_EXECUTE);

        aceIndex++;
        if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, /*dwAccMask,*/ psidPowerUsers)) {
            goto Exit;
        }
    }

    if (bAddEveryOneAce) {
        aceIndex++;
        if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, /*GENERIC_READ | GENERIC_EXECUTE,*/ psidEveryOne)) {
            goto Exit;
        }
    }

    //
    // Now the inheritable ACEs
    //

    aceIndex++;
    if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidSystem)) {
        goto Exit;
    }

    if (!GetAce(pAcl, aceIndex, &lpAceHeader)) {
        goto Exit;
    }

    lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);


    aceIndex++;
    if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidAdmin)) {
        goto Exit;
    }

    if (!GetAce(pAcl, aceIndex, &lpAceHeader)) {
        goto Exit;
    }

    lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);


    aceIndex++;
    if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, /*GENERIC_READ | GENERIC_EXECUTE,*/ psidUsers)) {
        goto Exit;
    }

    if (!GetAce(pAcl, aceIndex, &lpAceHeader)) {
        goto Exit;
    }

    lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);


    if (bAddPowerUsersAce) {
        aceIndex++;
        dwAccMask = (dwOtherSids & OTHERSIDS_POWERUSERS) ? (FILE_ALL_ACCESS ^ (WRITE_DAC | WRITE_OWNER)):
                                                           (GENERIC_READ | GENERIC_EXECUTE);

        if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, /*dwAccMask,*/ psidPowerUsers)) {
            goto Exit;
        }

        if (!GetAce(pAcl, aceIndex, &lpAceHeader)) {
            goto Exit;
        }

        lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
    }

    if (bAddEveryOneAce) {
        aceIndex++;

        if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, /*GENERIC_READ | GENERIC_EXECUTE,*/ psidEveryOne)) {
            goto Exit;
        }

        if (!GetAce(pAcl, aceIndex, &lpAceHeader)) {
            goto Exit;
        }

        lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
    }

    //
    // Put together the security descriptor
    //

    if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
        goto Exit;
    }


    if (!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) {
        goto Exit;
    }


    //
    // Set the security
    //

    if (SetFileSecurity (lpFile, DACL_SECURITY_INFORMATION, &sd)) {
        bRetVal = TRUE;
    } else {
    }



Exit:

    if (psidSystem) {
        FreeSid(psidSystem);
    }

    if (psidAdmin) {
        FreeSid(psidAdmin);
    }


    if (psidUsers) {
        FreeSid(psidUsers);
    }

    if ((bAddPowerUsersAce) && (psidPowerUsers)) {
        FreeSid(psidPowerUsers);
    }

    if ((bAddEveryOneAce) && (psidEveryOne)) {
        FreeSid(psidEveryOne);
    }

    if (pAcl) {
        GlobalFree (pAcl);
    }

    return bRetVal;
}


#ifdef SHMG_DBG

void SHMGLogErrMsg(char *szErrMsg, DWORD dwError)
{
    DWORD   dwBytesWritten = 0;
    char    szMsg[256];
    static HANDLE  hLogFile = 0;

    if (!hLogFile) {
        hLogFile = CreateFile(_T("shmgrate.log"), GENERIC_WRITE,
                                FILE_SHARE_WRITE, 0,
                                CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0 );
    }                                
                                                                   
    sprintf(szMsg, "%s : (%X)\r\n", szErrMsg, dwError);
    WriteFile(hLogFile, szMsg, strlen(szMsg), &dwBytesWritten, 0);
}            

#endif

void
FixHtmlHelp(
    void
    )
{
    TCHAR AppDataPath[MAX_PATH*2];
    TCHAR HtmlHelpPath[MAX_PATH];

    SHMGLogErrMsg("FixHtmlHelp Called",0);
    
    if (SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, AppDataPath) == S_OK &&
        LoadString( GetModuleHandle(NULL), IDS_HTML_HELP_DIR, HtmlHelpPath, sizeof(HtmlHelpPath)/sizeof(WCHAR) ) > 0)
    {
        _tcscat( AppDataPath, HtmlHelpPath );
                        
        if (CreateDirectory( AppDataPath, NULL )) {
            if (!MakeFileSecure(AppDataPath,OTHERSIDS_EVERYONE|OTHERSIDS_POWERUSERS)) 
                SHMGLogErrMsg("Could not apply security attributes", 0);
        }        
        else
            SHMGLogErrMsg("Could not create the directory", GetLastError());
    } 
    else
       SHMGLogErrMsg("Could not get APPDATA path", GetLastError());
}

// Add the SP1 "Configure Programs" shortcut to the common start menu
// On a clean install, this is handled by syssetup.inf, but on a
// RTM->SP1 upgrade, we need to do it by hand.
//

void AddConfigurePrograms()
{
    if (!IsOS(OS_ANYSERVER))
    {
        TCHAR szPath[MAX_PATH];

        if (GetSystemDirectory(szPath, ARRAYSIZE(szPath)) &&
            PathAppend(szPath, TEXT("XPSP1RES.DLL")))
        {
            HINSTANCE hinstSp1 = LoadLibraryEx(szPath, NULL, LOAD_LIBRARY_AS_DATAFILE);
            if (hinstSp1)
            {
                TCHAR szTitle[MAX_PATH];
                LoadString(hinstSp1, IDS_APPWIZ_CONFIGUREPROGRAMS, szTitle, ARRAYSIZE(szTitle));
                CreateLinkFile(CSIDL_COMMON_STARTMENU, NULL, szTitle,
                               TEXT("control.exe appwiz.cpl,,3"),
                               TEXT("moricons.dll"), -114,
                               NULL, 0, SW_SHOWNORMAL, TEXT("@xpsp1res.dll,-10078"));
                if (S_OK == SHGetFolderPath(NULL, CSIDL_COMMON_STARTMENU, NULL, SHGFP_TYPE_CURRENT, szPath) &&
                    PathAppend(szPath, szTitle) &&
                    PathAddExtension(szPath, TEXT(".lnk")))
                {
                    SHSetLocalizedName(szPath, L"xpsp1res.dll", IDS_APPWIZ_CONFIGUREPROGRAMS);
                }
            }
            FreeLibrary(hinstSp1);
        }
    }
}