Unsupported SetRegView mode must fail all registry operations

git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6865 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
anders_k 2017-06-04 22:48:13 +00:00
parent a2aa3ed305
commit b558dea54d
12 changed files with 186 additions and 154 deletions

View file

@ -10,6 +10,8 @@ Released on ? ?th, 2017
\b Fixed RegTool Win9x bug
\b Unsupported SetRegView mode fails all registry operations
\b Added \R{execshellwait}{ExecShellWait}
\b Added \R{writeregmultistr}{WriteRegMultiStr} (\W{http://sf.net/p/nsis/feature-requests/382}{RFE #382}, \W{http://sf.net/p/nsis/patches/219}{patch #219}) and WriteRegNone

View file

@ -248,7 +248,7 @@ The compiler will check your script and give you warnings or an error. If an err
NSIS supports different compression methods, as explained \R{asetcompressor}{here}. ZLIB is the default compression method, which is fast and uses only a little bit of memory. LZMA is a good method for the creation of small installers for internet distribution. BZIP2 usually compresses better than ZLIB but not as good as LZMA, it is useful if you need lower memory usage or fast script compilation.
It it also possible to compile Windows installers on Linux, BSD or Mac OS X servers. See \R{build}{Building NSIS} for details.
It is also possible to compile Windows installers on Linux, BSD or Mac OS X servers. See \R{build}{Building NSIS} for details.
\H{tutmodernui} Modern UI

View file

@ -376,7 +376,7 @@ CEXEBuild::CEXEBuild(signed char pponly) :
m_ShellConstants.add(_T("RESOURCES_LOCALIZED"), CSIDL_RESOURCES_LOCALIZED, CSIDL_RESOURCES_LOCALIZED);
m_ShellConstants.add(_T("CDBURN_AREA"), CSIDL_CDBURN_AREA, CSIDL_CDBURN_AREA);
// PROGRAMFILES&COMMONFILES does a registry lookup and the required string offsets are filled in later.
// We do this because the unicode mode has to be locked when we call add_string...
// We do this later because the unicode mode has to be locked when we call add_string...
m_ShellConstants.add(_T("PROGRAMFILES"), 0, 0);
m_ShellConstants.add(_T("PROGRAMFILES32"), 0, 0);
m_ShellConstants.add(_T("PROGRAMFILES64"), 0, 0);

View file

@ -28,9 +28,7 @@
#ifndef LOAD_LIBRARY_SEARCH_USER_DIRS
#define LOAD_LIBRARY_SEARCH_USER_DIRS 0x00000400
#endif
#ifndef LOAD_LIBRARY_SEARCH_SYSTEM32
#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800
#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800
#endif
#ifndef SHTDN_REASON_FLAG_PLANNED
#define SHTDN_REASON_FLAG_PLANNED 0x80000000
@ -63,6 +61,8 @@ TCHAR g_caption[NSIS_MAX_STRLEN*2]; // Why does this have to be NSIS_MAX_STRLEN*
HWND g_hwnd;
HANDLE g_hInstance;
#endif
void *g_SHGetFolderPath;
DWORD g_WinVer;
void NSISCALL CleanUp();
@ -77,14 +77,12 @@ TCHAR *ValidateTempDir()
return my_GetTempFileName(state_language, state_temp_dir);
}
void *g_SHGetFolderPath;
NSIS_ENTRYPOINT_GUINOCRT
EXTERN_C void NSISWinMainNOCRT()
{
int ret = 0;
const TCHAR *m_Err = _LANG_ERRORWRITINGTEMP;
int cl_flags = 0;
TCHAR *realcmds;
@ -92,13 +90,14 @@ EXTERN_C void NSISWinMainNOCRT()
TCHAR *cmdline;
SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
g_WinVer = GetVersion() & ~(NSIS_WINVER_WOW64FLAG); // We store a private flag in the build number bits
{
// bug #1125: Don't load modules from the application nor current directory.
// SetDefaultDllDirectories() allows us to restrict implicitly loaded and
// dynamically loaded modules to just %windir%\System32 and directories
// added with AddDllDirectory(). This prevents DLL search order attacks (CAPEC-471).
DWORD winver = GetVersion();
DWORD winver = g_WinVer;
// CoCreateInstance(CLSID_ShellLink, ...) fails on Vista if SetDefaultDllDirectories is called
BOOL avoidwinbug = LOWORD(winver) == MAKEWORD(6, 0);
if (!avoidwinbug)
@ -145,6 +144,16 @@ EXTERN_C void NSISWinMainNOCRT()
#endif
g_SHGetFolderPath = myGetProcAddress(MGA_SHGetFolderPath); // and SHFOLDER
#ifndef _WIN64
{
// KEY_WOW64_xxKEY causes registry functions to fail on WinNT4 & Win2000.
// We don't filter them out because all registry instructions are supposed to fail when
// accessing a unsupported view and RegKey* takes care of that by looking at the WOW64 flag.
FARPROC fp = myGetProcAddress(MGA_IsOS);
enum { os_wow6432 = 30 };
if (fp && ((BOOL(WINAPI*)(UINT))fp)(os_wow6432)) g_WinVer |= NSIS_WINVER_WOW64FLAG;
}
#endif
InitCommonControls();

View file

@ -41,20 +41,19 @@ typedef UINT_PTR (*NSISPLUGINCALLBACK)(enum NSPIM);
typedef struct
{
int autoclose;
int all_user_var;
int exec_error;
int abort;
int all_user_var; // SetShellVarContext: User context = 0, Machine context = 1
int exec_error; // IfErrors
int abort; // IfAbort
int exec_reboot; // NSIS_SUPPORT_REBOOT
int reboot_called; // NSIS_SUPPORT_REBOOT
int XXX_cur_insttype; // Deprecated
int plugin_api_version; // see NSISPIAPIVER_CURR
// used to be XXX_insttype_changed
int plugin_api_version; // See NSISPIAPIVER_CURR (Note: used to be XXX_insttype_changed)
int silent; // NSIS_CONFIG_SILENT_SUPPORT
int instdir_error;
int rtl;
int errlvl;
int alter_reg_view;
int status_update;
int errlvl; // SetErrorLevel
int alter_reg_view; // SetRegView: Default View = 0, Alternative View = (sizeof(void*) > 4 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY)
int status_update; // SetDetailsPrint
} exec_flags_t;
#ifndef NSISCALL

View file

@ -156,30 +156,41 @@ static TCHAR * NSISCALL GetStringFromParm(int id_)
}
#ifdef NSIS_SUPPORT_REGISTRYFUNCTIONS
#define AlterRegistrySAM(sam) (sam | g_exec_flags.alter_reg_view)
// based loosely on code from Tim Kosse
// in win9x this isn't necessary (RegDeleteKey() can delete a tree of keys),
// but in win2k you need to do this manually.
static LONG NSISCALL myRegDeleteKeyEx(HKEY thiskey, LPCTSTR lpSubKey, int onlyifempty)
static HKEY NSISCALL GetRegRootKey(int RootKey)
{
HKEY key;
int retval=RegOpenKeyEx(thiskey,lpSubKey,0,AlterRegistrySAM(KEY_ENUMERATE_SUB_KEYS),&key);
if (retval==ERROR_SUCCESS)
if (RootKey != (int) HKSHCTX) return (HKEY) (UINT_PTR) RootKey;
return (HKEY) ((UINT_PTR) HKEY_CURRENT_USER + g_exec_flags.all_user_var); // SHCTX: HKEY_CURRENT_USER + 1 == HKEY_LOCAL_MACHINE
}
static HKEY NSISCALL RegOpenScriptKey(REGSAM RS)
{
HKEY hKey;
return RegKeyOpen(GetRegRootKey(g_parms[1]), GetStringFromParm(0x22), RS|KEY_FROMSCRIPT, &hKey) ? NULL : hKey;
}
static HKEY NSISCALL RegCreateScriptKey(int RootKey, LPCTSTR SubKey, REGSAM RS)
{
HKEY hKey;
return RegKeyCreate(GetRegRootKey(RootKey), SubKey, RS|KEY_FROMSCRIPT, &hKey) ? NULL : hKey;
}
// RegDeleteKey on Win9x will delete a tree of keys, WinNT will only delete a key without subkeys.
// RegDeleteKeyEx on 32-bit Windows accepts but ignores the KEY_WOW64_xxKEY flags and always uses the
// one and only native key. Our RegKeyOpen will intentionally fail if a incompatible WoW64 flag is used.
#define RegDeleteScriptKey(RootKey, SubKey, Flags) RegDeleteScriptKeyWorker(GetRegRootKey(RootKey), (SubKey), (Flags))
static LONG NSISCALL RegDeleteScriptKeyWorker(HKEY hThisKey, LPCTSTR SubKey, UINT Flags)
{
HKEY hKey;
UINT onlyifempty = Flags;
REGSAM viewsam = g_exec_flags.alter_reg_view; // Not using KEY_ALTERVIEW here because viewsam is also passed to RegDeleteKeyEx.
LONG retval = RegKeyOpen(hThisKey, SubKey, KEY_ENUMERATE_SUB_KEYS|viewsam, &hKey);
if (retval == ERROR_SUCCESS)
{
// NB - don't change this to static (recursive function)
TCHAR buffer[MAX_PATH+1];
while (RegEnumKey(key,0,buffer,MAX_PATH+1)==ERROR_SUCCESS)
TCHAR child[MAX_PATH+1]; // NB - don't change this to static (recursive function)
while (RegEnumKey(hKey, 0, child, COUNTOF(child)) == ERROR_SUCCESS)
{
if (onlyifempty)
{
RegCloseKey(key);
return !ERROR_SUCCESS;
}
if ((retval=myRegDeleteKeyEx(key,buffer,0)) != ERROR_SUCCESS) break;
if (onlyifempty) return (RegCloseKey(hKey), !ERROR_SUCCESS);
if ((retval = RegDeleteScriptKeyWorker(hKey, child, Flags)) != ERROR_SUCCESS) break;
}
RegCloseKey(key);
RegCloseKey(hKey);
{
typedef LONG (WINAPI * RegDeleteKeyExPtr)(HKEY, LPCTSTR, REGSAM, DWORD);
RegDeleteKeyExPtr RDKE = (RegDeleteKeyExPtr)
@ -189,32 +200,13 @@ static LONG NSISCALL myRegDeleteKeyEx(HKEY thiskey, LPCTSTR lpSubKey, int onlyif
myGetProcAddress(MGA_RegDeleteKeyEx);
#endif
if (RDKE)
retval=RDKE(thiskey,lpSubKey,AlterRegistrySAM(0),0);
retval = RDKE(hThisKey, SubKey, viewsam, 0);
else
retval=g_exec_flags.alter_reg_view||RegDeleteKey(thiskey,lpSubKey);
retval = RegDeleteKey(hThisKey, SubKey);
}
}
return retval;
}
static HKEY NSISCALL GetRegRootKey(int hRootKey)
{
if (hRootKey)
return (HKEY) (UINT_PTR) hRootKey;
// HKEY_LOCAL_MACHINE - HKEY_CURRENT_USER == 1
return (HKEY) ((UINT_PTR) HKEY_CURRENT_USER + g_exec_flags.all_user_var);
}
static HKEY NSISCALL myRegOpenKey(REGSAM samDesired)
{
HKEY hKey;
if (RegOpenKeyEx(GetRegRootKey(g_parms[1]), GetStringFromParm(0x22), 0, AlterRegistrySAM(samDesired), &hKey) == ERROR_SUCCESS)
{
return hKey;
}
return NULL;
}
#endif//NSIS_SUPPORT_REGISTRYFUNCTIONS
// returns EXEC_ERROR on error
@ -1212,11 +1204,11 @@ static int NSISCALL ExecuteEntry(entry *entry_)
#ifdef NSIS_SUPPORT_REGISTRYFUNCTIONS
case EW_DELREG:
{
long res=!ERROR_SUCCESS;
const TCHAR *rkn UNUSED=RegKeyHandleToName((HKEY)parm1);
if (!parm4)
long res=!ERROR_SUCCESS, rootkey=parm1;
const TCHAR *rkn UNUSED=RegKeyHandleToName((HKEY)rootkey);
if (!parm4) // TOK_DELETEREGVALUE
{
HKEY hKey=myRegOpenKey(KEY_SET_VALUE);
HKEY hKey=RegOpenScriptKey(KEY_SET_VALUE);
if (hKey)
{
TCHAR *buf3=GetStringFromParm(0x33);
@ -1225,11 +1217,11 @@ static int NSISCALL ExecuteEntry(entry *entry_)
RegCloseKey(hKey);
}
}
else
else // TOK_DELETEREGKEY
{
TCHAR *buf2=GetStringFromParm(0x22);
log_printf3(_T("DeleteRegKey: \"%s\\%s\""),rkn,buf2);
res = myRegDeleteKeyEx(GetRegRootKey(parm1),buf2,parm4&2);
res = RegDeleteScriptKey(rootkey,buf2,parm4 >> 1); // Shifting away the TOK_DELETEREGKEY bit, onlyifempty is now the bottom bit (">> 1" is 1 byte smaller than "& 2")
}
if (res != ERROR_SUCCESS)
exec_error++;
@ -1237,16 +1229,14 @@ static int NSISCALL ExecuteEntry(entry *entry_)
break;
case EW_WRITEREG: // write registry value
{
int rootkey=parm0, type=parm4, rtype=parm5;
const TCHAR *rkn UNUSED=RegKeyHandleToName((HKEY)rootkey);
HKEY hKey;
HKEY rootkey=GetRegRootKey(parm0);
int type=parm4;
int rtype=parm5;
TCHAR *buf0=GetStringFromParm(0x02);
TCHAR *buf1=GetStringFromParm(0x11);
const TCHAR *rkn UNUSED=RegKeyHandleToName(rootkey);
exec_error++;
if (RegCreateKeyEx(rootkey,buf1,0,0,0,AlterRegistrySAM(KEY_SET_VALUE),0,&hKey,0) == ERROR_SUCCESS)
if ((hKey = RegCreateScriptKey(rootkey, buf1, KEY_SET_VALUE)))
{
LPBYTE data = (LPBYTE) buf2;
DWORD size = 0;
@ -1297,7 +1287,7 @@ static int NSISCALL ExecuteEntry(entry *entry_)
break;
case EW_READREGSTR: // read registry string
{
HKEY hKey=myRegOpenKey(KEY_READ);
HKEY hKey=RegOpenScriptKey(KEY_READ);
TCHAR *p=var0;
TCHAR *buf3=GetStringFromParm(0x33); // buf3 == key name
p[0]=0;
@ -1333,21 +1323,19 @@ static int NSISCALL ExecuteEntry(entry *entry_)
break;
case EW_REGENUM:
{
HKEY key=myRegOpenKey(KEY_READ);
HKEY hKey=RegOpenScriptKey(KEY_READ);
TCHAR *p=var0;
int b=GetIntFromParm(3);
p[0]=0;
if (key)
p[0]=0; // "" on error. This assumes that RegEnumKey and RegEnumValue do not party on our buffer!
if (hKey)
{
DWORD d=NSIS_MAX_STRLEN-1;
if (parm4) RegEnumKey(key,b,p,d);
else if (RegEnumValue(key,b,p,&d,NULL,NULL,NULL,NULL)!=ERROR_SUCCESS)
{
DWORD d=NSIS_MAX_STRLEN-1; // -1 is not required here?
if (parm4)
RegEnumKey(hKey,b,p,d);
else if (RegEnumValue(hKey,b,p,&d,NULL,NULL,NULL,NULL) != ERROR_SUCCESS)
exec_error++;
break;
}
p[NSIS_MAX_STRLEN-1]=0;
RegCloseKey(key);
p[NSIS_MAX_STRLEN-1]=0; // Not required?
RegCloseKey(hKey);
}
else exec_error++;
}

View file

@ -155,7 +155,7 @@ enum
#endif
#ifdef NSIS_SUPPORT_REGISTRYFUNCTIONS
EW_DELREG, // DeleteRegValue/DeleteRegKey: 4, [root key(int), KeyName, ValueName, delkeyonlyifempty]. ValueName is -1 if delete key
EW_DELREG, // DeleteRegValue/DeleteRegKey: 4, [root key(int), KeyName, ValueName, ActionAndFlags]
EW_WRITEREG, // Write Registry value: 5, [RootKey(int),KeyName,ItemName,ItemData,typelen]
// typelen=1 for str, 2 for dword, 3 for binary, 0 for expanded str
EW_READREGSTR, // ReadRegStr: 5 [output, rootkey(int), keyname, itemname, ==1?int::str]
@ -510,6 +510,8 @@ typedef struct {
#define DEL_REBOOT 4
#define DEL_SIMPLE 8
#define HKSHCTX ( (HKEY) 0 ) // Converted to HKCU or HKLM by GetRegRootKey
#ifdef NSIS_SUPPORT_CREATESHORTCUT
#define CS_HK_MASK 0xffff0000 // HotKey
#define CS_HK_SHIFT 16

View file

@ -539,7 +539,7 @@ void RenameViaWininit(const TCHAR* prevName, const TCHAR* newName)
int spn; // length of the short path name in TCHARs.
lstrcpy(tmpbuf, _T("NUL"));
mystrcpy(tmpbuf, _T("NUL"));
if (newName) {
// create the file if it's not already there to prevent GetShortPathName from failing
@ -643,22 +643,38 @@ void NSISCALL MoveFileOnReboot(LPCTSTR pszExisting, LPCTSTR pszNew)
}
#endif
// The value of registry->sub->name is stored in out. If failure, then out becomes
// an empty string "".
void NSISCALL myRegGetStr(HKEY root, const TCHAR *sub, const TCHAR *name, TCHAR *out, int altview)
#define GetAltViewREGSAM() ( sizeof(void*) > 4 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY )
static HKEY GetRegKeyAndSAM(HKEY hKey, REGSAM*pRS)
{
REGSAM sam = *pRS, otherview = GetAltViewREGSAM();
REGSAM incompatsam = SystemSupportsAltRegView() ? 0 : otherview;
if (sam & KEY_ALTERVIEW) sam |= g_exec_flags.alter_reg_view;
*pRS = sam & ~(NSIS_REGSAM_PRIVATEMASK); // Filter away internal flags
return (incompatsam & sam) ? NULL : hKey; // Fail if the requested view is not supported
}
LONG NSISCALL RegKeyOpen(HKEY hBase, LPCTSTR SubKey, REGSAM RS, HKEY*phKey)
{
if (!(hBase = GetRegKeyAndSAM(hBase, &RS))) return ERROR_INVALID_HANDLE; // ERROR_CANTOPEN?
return RegOpenKeyEx(hBase, SubKey, 0, RS, phKey);
}
LONG NSISCALL RegKeyCreate(HKEY hBase, LPCTSTR SubKey, REGSAM RS, HKEY*phKey)
{
if (!(hBase = GetRegKeyAndSAM(hBase, &RS))) return ERROR_INVALID_HANDLE; // ERROR_CANTOPEN?
return RegCreateKeyEx(hBase, SubKey, 0, 0, 0, RS, 0, phKey, 0);
}
void NSISCALL myRegGetStr(HKEY root, const TCHAR *sub, const TCHAR *name, TCHAR *out, UINT altview)
{
HKEY hKey;
const REGSAM wowsam = altview ? (sizeof(void*) > 4 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY) : 0;
*out=0;
if (RegOpenKeyEx(root,sub,0,KEY_READ|wowsam,&hKey) == ERROR_SUCCESS)
DWORD cb = NSIS_MAX_STRLEN*sizeof(TCHAR), rt, ec;
REGSAM viewsam = altview ? GetAltViewREGSAM() : 0;
if ((ec = RegKeyOpen(root, sub, KEY_READ|viewsam, &hKey)) == ERROR_SUCCESS)
{
DWORD l = NSIS_MAX_STRLEN*sizeof(TCHAR), t;
// Note that RegQueryValueEx returns Unicode strings if _UNICODE is defined for the
// REG_SZ type.
if (RegQueryValueEx(hKey,name,NULL,&t,(LPBYTE)out,&l ) != ERROR_SUCCESS || (t != REG_SZ && t != REG_EXPAND_SZ)) *out=0;
out[NSIS_MAX_STRLEN-1]=0;
ec = RegQueryValueEx(hKey, name, NULL, &rt, (LPBYTE)out, &cb);
RegCloseKey(hKey);
out[NSIS_MAX_STRLEN-1] = 0; // Make sure the string is terminated. This could potentially truncate a long string by 1 character!
}
if (ec != ERROR_SUCCESS || (rt != REG_SZ && rt != REG_EXPAND_SZ)) *out = 0; // Empty string on failure
}
void NSISCALL iptrtostr(TCHAR *s, INT_PTR d)
@ -764,8 +780,10 @@ TCHAR * NSISCALL GetNSISString(TCHAR *outbuf, int strtab)
int fldrs[4];
if (nVarIdx < NS_SKIP_CODE)
{
// the next 2 BYTEs in the string might be coding either a value 0..MAX_CODED (nData), or 2 CSIDL of Special folders (for NS_SHELL_CODE)
// The next 2 BYTEs in the string might be coding either a value 0..MAX_CODED (nData), or 2 CSIDL of Special folders (for NS_SHELL_CODE)
nData = DECODE_SHORT(in);
// There are 2 CSIDL parameters for each context and query must be used before create
// because of bug #820 (CSIDL_FLAG_CREATE failures on root paths are cached in Vista).
#ifdef _UNICODE
fldrs[1] = LOBYTE(*in); // current user
fldrs[0] = fldrs[1] | CSIDL_FLAG_CREATE;
@ -777,7 +795,6 @@ TCHAR * NSISCALL GetNSISString(TCHAR *outbuf, int strtab)
fldrs[2] = in[1] | CSIDL_FLAG_CREATE; // all users
fldrs[3] = in[1];
#endif
//TODO: are fldrs[1] and fldrs[3] really useful? why not force folder creation directly?
in += sizeof(SHORT)/sizeof(TCHAR);
if (nVarIdx == NS_SHELL_CODE)
@ -785,10 +802,8 @@ TCHAR * NSISCALL GetNSISString(TCHAR *outbuf, int strtab)
LPITEMIDLIST idl;
int x = 2;
DWORD ver = GetVersion();
DWORD ver = sizeof(void*) > 4 ? MAKEWORD(5, 2) : g_WinVer; // We only care about 95/98 vs ME/NT4+
/*
SHGetFolderPath as provided by shfolder.dll is used to get special folders
unless the installer is running on Windows 95/98. For 95/98 shfolder.dll is
only used for the Application Data and Documents folder (if the DLL exists).
@ -802,9 +817,7 @@ TCHAR * NSISCALL GetNSISString(TCHAR *outbuf, int strtab)
SHGetFolderPath in shell32.dll could be called directly for Windows versions
later than 95/98 but there is no need to do so, because shfolder.dll is still
provided and calls shell32.dll.
*/
BOOL use_shfolder =
// Use shfolder if not on 95/98
!((ver & 0x80000000) && (LOWORD(ver) != 0x5A04)) ||
@ -819,7 +832,7 @@ TCHAR * NSISCALL GetNSISString(TCHAR *outbuf, int strtab)
if (g_exec_flags.all_user_var)
{
x = 4;
x = 4; // Get common folder > Create common folder > Get user folder > Create user folder
}
if (fldrs[1] & 0x80)
@ -829,12 +842,12 @@ TCHAR * NSISCALL GetNSISString(TCHAR *outbuf, int strtab)
GetNSISString(out, fldrs[3]);
x = 0;
}
else if (fldrs[1] == CSIDL_SYSTEM)
else if (fldrs[1] == CSIDL_SYSTEM) // Does not work on 95, 98 nor NT4. Works on ME and 2000+.
{
GetSystemDirectory(out, NSIS_MAX_STRLEN);
x = 0;
}
else if (fldrs[1] == CSIDL_WINDOWS)
else if (fldrs[1] == CSIDL_WINDOWS) // Does not work on 95, 98 nor NT4. Works on ME and 2000+.
{
GetWindowsDirectory(out, NSIS_MAX_STRLEN);
x = 0;
@ -982,22 +995,14 @@ void NSISCALL log_write(int close)
const TCHAR * _RegKeyHandleToName(HKEY hKey)
{
if (hKey == HKEY_CLASSES_ROOT)
return _T("HKEY_CLASSES_ROOT");
else if (hKey == HKEY_CURRENT_USER)
return _T("HKEY_CURRENT_USER");
else if (hKey == HKEY_LOCAL_MACHINE)
return _T("HKEY_LOCAL_MACHINE");
else if (hKey == HKEY_USERS)
return _T("HKEY_USERS");
else if (hKey == HKEY_PERFORMANCE_DATA)
return _T("HKEY_PERFORMANCE_DATA");
else if (hKey == HKEY_CURRENT_CONFIG)
return _T("HKEY_CURRENT_CONFIG");
else if (hKey == HKEY_DYN_DATA)
return _T("HKEY_DYN_DATA");
else
return _T("invalid registry key");
if (hKey == HKEY_CLASSES_ROOT) return _T("HKEY_CLASSES_ROOT");
if (hKey == HKEY_CURRENT_USER) return _T("HKEY_CURRENT_USER");
if (hKey == HKEY_LOCAL_MACHINE) return _T("HKEY_LOCAL_MACHINE");
if (hKey == HKEY_USERS) return _T("HKEY_USERS");
if (hKey == HKEY_PERFORMANCE_DATA) return _T("HKEY_PERFORMANCE_DATA");
if (hKey == HKEY_CURRENT_CONFIG) return _T("HKEY_CURRENT_CONFIG");
if (hKey == HKEY_DYN_DATA) return _T("HKEY_DYN_DATA");
return _T("HK??");
}
void _LogData2Hex(TCHAR *buf, size_t cchbuf, BYTE *data, size_t cbdata)
@ -1103,6 +1108,9 @@ struct MGA_FUNC MGA_FUNCS[] = {
#endif
{"ADVAPI32", "InitiateShutdownW"},
{"SHELL32", (CHAR*) 680}, // IsUserAnAdmin
#ifndef _WIN64
{"SHLWAPI", (CHAR*) 437}, // IsOS
#endif
{"SHLWAPI", "SHAutoComplete"},
{"SHFOLDER", "SHGetFolderPathW"},
#ifdef NSIS_SUPPORT_GETDLLVERSION
@ -1118,6 +1126,9 @@ struct MGA_FUNC MGA_FUNCS[] = {
{"ADVAPI32", "RegDeleteKeyExA"},
{"ADVAPI32", "InitiateShutdownA"},
{"SHELL32", (CHAR*) 680}, // IsUserAnAdmin
#ifndef _WIN64
{"SHLWAPI", (CHAR*) 437}, // IsOS
#endif
{"SHLWAPI", "SHAutoComplete"},
{"SHFOLDER", "SHGetFolderPathA"},
#ifdef NSIS_SUPPORT_GETDLLVERSION

View file

@ -32,7 +32,6 @@ TCHAR * NSISCALL GetNSISString(TCHAR *outbuf, int strtab);
// use the LANG_STR_TAB() macro to decode it.
#define GetNSISTab(strtab) (strtab < 0 ? LANG_STR_TAB(strtab) : strtab)
void NSISCALL myRegGetStr(HKEY root, const TCHAR *sub, const TCHAR *name, TCHAR *out, int altview);
#define myatoi(s) ( (int)strtoiptr(s) )
INT_PTR NSISCALL strtoiptr(const TCHAR *s);
#define myitoa iptrtostr
@ -41,6 +40,22 @@ TCHAR * NSISCALL mystrcpy(TCHAR *out, const TCHAR *in);
int NSISCALL mystrlen(const TCHAR *in);
TCHAR * NSISCALL mystrcat(TCHAR *out, const TCHAR *concat);
TCHAR * NSISCALL mystrstr(TCHAR *a, TCHAR *b);
#define KEY_ALTERVIEW SYNCHRONIZE // Our private flag used by RegKey* to indicate that we want it to apply g_exec_flags.alter_reg_view. (MSDN:"Registry keys do not support the SYNCHRONIZE standard access right")
#define KEY_FROMSCRIPT (KEY_ALTERVIEW) // Use this flag for registry operations from a .nsi script
#define NSIS_REGSAM_PRIVATEMASK (KEY_FROMSCRIPT|KEY_ALTERVIEW)
LONG NSISCALL RegKeyOpen(HKEY hBase, LPCTSTR SubKey, REGSAM RS, HKEY*phKey);
LONG NSISCALL RegKeyCreate(HKEY hBase, LPCTSTR SubKey, REGSAM RS, HKEY*phKey);
void NSISCALL myRegGetStr(HKEY root, const TCHAR *sub, const TCHAR *name, TCHAR *out, UINT altview);
extern DWORD g_WinVer; // GetVersion()
#define NSIS_WINVER_WOW64FLAG ( sizeof(void*) > 4 ? ( 0 ) : ( 0x40000000 ) )
#define IsWow64() ( sizeof(void*) > 4 ? ( FALSE ) : ( g_WinVer & NSIS_WINVER_WOW64FLAG ) )
#define SystemSupportsAltRegView() ( sizeof(void*) > 4 ? ( TRUE ) : ( IsWow64() ) )
WIN32_FIND_DATA * NSISCALL file_exists(TCHAR *buf);
TCHAR * NSISCALL my_GetTempFileName(TCHAR *buf, const TCHAR *dir);
BOOL NSISCALL myReadFile(HANDLE h, LPVOID buf, DWORD cb);
@ -134,6 +149,9 @@ enum myGetProcAddressFunctions {
#endif
MGA_InitiateShutdown,
MGA_IsUserAnAdmin,
#ifndef _WIN64
MGA_IsOS,
#endif
MGA_SHAutoComplete, // x64 can link to shlwapi directly but as long as MGA_SHGetFolderPath is used we can stick with myGetProcAddress
MGA_SHGetFolderPath, // TODO: This can probably call something else directly on x64
#ifdef NSIS_SUPPORT_GETDLLVERSION

View file

@ -704,8 +704,10 @@ int main(int argc, char **argv)
int wargc = 0;
wchar_t term[1], *p, **wargv = (wchar_t **) malloc((argc+1) * sizeof(void*));
if (wargv)
{
for ( ; wargc < argc; ++wargc )
if ((p = NSISRT_mbtowc(argv[wargc]))) { wargv[wargc] = p; } else { break; }
if ((p = NSISRT_mbtowc(argv[wargc]))) wargv[wargc] = p; else break;
}
if (wargc == argc)
*term = L'\0', wargv[wargc] = term, errno = _tmain(wargc,wargv);
else

View file

@ -845,16 +845,23 @@ int CEXEBuild::process_jump(LineParser &line, int wt, int *offs)
#define SECTION_FIELD_GET(field) (FIELD_OFFSET(section, field)/sizeof(int))
#define SECTION_FIELD_SET(field) (-1 - (int)(FIELD_OFFSET(section, field)/sizeof(int)))
int CEXEBuild::doCommand(int which_token, LineParser &line)
#define INVALIDREGROOT ( (HKEY) 0x8000baad )
static HKEY ParseRegRootKey(LineParser &line, int tok)
{
static const TCHAR *rootkeys[2] = {
_T("HKCR\0HKLM\0HKCU\0HKU\0HKCC\0HKDD\0HKPD\0SHCTX\0"),
_T("HKEY_CLASSES_ROOT\0HKEY_LOCAL_MACHINE\0HKEY_CURRENT_USER\0HKEY_USERS\0HKEY_CURRENT_CONFIG\0HKEY_DYN_DATA\0HKEY_PERFORMANCE_DATA\0SHELL_CONTEXT\0")
};
static const HKEY rootkey_tab[] = {
HKEY_CLASSES_ROOT,HKEY_LOCAL_MACHINE,HKEY_CURRENT_USER,HKEY_USERS,HKEY_CURRENT_CONFIG,HKEY_DYN_DATA,HKEY_PERFORMANCE_DATA,0
HKEY_CLASSES_ROOT,HKEY_LOCAL_MACHINE,HKEY_CURRENT_USER,HKEY_USERS,HKEY_CURRENT_CONFIG,HKEY_DYN_DATA,HKEY_PERFORMANCE_DATA,HKSHCTX
};
int k = line.gettoken_enum(tok, rootkeys[0]);
if (k == -1) k = line.gettoken_enum(tok, rootkeys[1]);
return k == -1 ? INVALIDREGROOT : rootkey_tab[k];
}
int CEXEBuild::doCommand(int which_token, LineParser &line)
{
#ifdef NSIS_CONFIG_PLUGIN_SUPPORT
if (PS_OK != initialize_default_plugins()) return PS_ERROR;
#endif
@ -1680,11 +1687,10 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
if (build_header.install_reg_key_ptr)
warning_fl(DW_STRING_MULTISETWASTE, _T("%") NPRIs _T(": specified multiple times, wasting space"),line.gettoken_str(0));
int k=line.gettoken_enum(1,rootkeys[0]);
if (k == -1) k=line.gettoken_enum(1,rootkeys[1]);
if (k == -1) PRINTHELP()
build_header.install_reg_rootkey=REGROOTKEYTOINT(rootkey_tab[k]);
if (!build_header.install_reg_rootkey) PRINTHELP() // SHCTX is invalid here
HKEY hRK = ParseRegRootKey(line,1);
if (INVALIDREGROOT == hRK) PRINTHELP()
if (HKSHCTX == hRK) PRINTHELP() // SHCTX is invalid here
build_header.install_reg_rootkey=REGROOTKEYTOINT(hRK);
build_header.install_reg_key_ptr = add_string(line.gettoken_str(2),0);
if (line.gettoken_str(2)[0] == _T('\\'))
warning_fl(DW_PARSE_REGPATHPREFIX, _T("%") NPRIs _T(": registry path name begins with \'\\\', may cause problems"),line.gettoken_str(0));
@ -2875,12 +2881,12 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
{
ent.which=EW_SETFLAG;
ent.offsets[0]=FLAG_OFFSET(alter_reg_view);
int k=line.gettoken_enum(1,_T("32\0") _T("64\0default\0lastused\0")); // TODO: Can we support "native" without OS sniffing? Must verify on 9x, NT4 and 2000!
if (k<0) PRINTHELP()
int k=line.gettoken_enum(1,_T("32\0") _T("64\0default\0lastused\0"));
if (k == 0) ent.offsets[1]=add_intstring(is_target_64bit() ? KEY_WOW64_32KEY : 0); // 32
else if (k == 1) ent.offsets[1]=add_intstring(KEY_WOW64_64KEY); // 64
else if (k == 2) ent.offsets[1]=add_intstring(0); // default
else if (k == 3) ent.offsets[2]=1; // last used
else PRINTHELP()
SCRIPT_MSG(_T("SetRegView: %") NPRIs _T("\n"),line.gettoken_str(1));
}
return add_entry(&ent);
@ -4163,10 +4169,9 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
{
ent.which=EW_READREGSTR;
ent.offsets[0]=GetUserVarIndex(line, 1);
int k=line.gettoken_enum(2,rootkeys[0]);
if (k == -1) k=line.gettoken_enum(2,rootkeys[1]);
if (ent.offsets[0] == -1 || k == -1) PRINTHELP()
ent.offsets[1]=REGROOTKEYTOINT(rootkey_tab[k]);
HKEY hRK = ParseRegRootKey(line,2);
if (ent.offsets[0] == -1 || INVALIDREGROOT == hRK) PRINTHELP()
ent.offsets[1]=REGROOTKEYTOINT(hRK);
ent.offsets[2]=add_string(line.gettoken_str(3));
ent.offsets[3]=add_string(line.gettoken_str(4));
if (which_token == TOK_READREGDWORD) ent.offsets[4]=1;
@ -4181,29 +4186,27 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
case TOK_DELETEREGVALUE:
case TOK_DELETEREGKEY:
{
int a=1;
if (which_token==TOK_DELETEREGKEY)
int a=1, iskeyop, delkeyflag=1, onlyifemptyflag=2;
if ((iskeyop = which_token == TOK_DELETEREGKEY))
{
ent.offsets[4]=1;
ent.offsets[4]=(delkeyflag);
TCHAR *s=line.gettoken_str(a);
if (s[0] == _T('/'))
{
if (_tcsicmp(s,_T("/ifempty"))) PRINTHELP()
a++;
ent.offsets[4]=3;
a++, ent.offsets[4]=(delkeyflag|onlyifemptyflag);
}
if (line.gettoken_str(a+2)[0]) PRINTHELP()
}
int k=line.gettoken_enum(a,rootkeys[0]);
if (k == -1) k=line.gettoken_enum(a,rootkeys[1]);
if (k == -1) PRINTHELP()
HKEY hRK=ParseRegRootKey(line,a);
if (INVALIDREGROOT == hRK) PRINTHELP()
ent.which=EW_DELREG;
ent.offsets[1]=REGROOTKEYTOINT(rootkey_tab[k]);
ent.offsets[1]=REGROOTKEYTOINT(hRK);
ent.offsets[2]=add_string(line.gettoken_str(a+1));
ent.offsets[3]=(which_token==TOK_DELETEREGKEY)?0:add_string(line.gettoken_str(a+2));
ent.offsets[3]=iskeyop ? 0 : add_string(line.gettoken_str(a+2));
if (line.gettoken_str(a+1)[0] == _T('\\'))
warning_fl(DW_PARSE_REGPATHPREFIX, _T("%") NPRIs _T(": registry path name begins with \'\\\', may cause problems"),line.gettoken_str(0));
if (which_token==TOK_DELETEREGKEY)
if (iskeyop)
SCRIPT_MSG(_T("DeleteRegKey: %") NPRIs _T("\\%") NPRIs _T("\n"),line.gettoken_str(a),line.gettoken_str(a+1));
else
SCRIPT_MSG(_T("DeleteRegValue: %") NPRIs _T("\\%") NPRIs _T("\\%") NPRIs _T("\n"),line.gettoken_str(a),line.gettoken_str(a+1),line.gettoken_str(a+2));
@ -4217,11 +4220,10 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
const TCHAR*cmdname=get_commandtoken_name(which_token);
int reg5=0==line.gettoken_enum(1,_T("/REGEDIT5\0")), multisz=which_token == TOK_WRITEREGMULTISZ;
if (reg5) line.eattoken();
int k=line.gettoken_enum(1,rootkeys[0]);
if (k == -1) k=line.gettoken_enum(1,rootkeys[1]);
if (k == -1 || reg5 != multisz) PRINTHELPEX(cmdname); // WriteRegMultiStr only supports the /REGEDIT5 serialized format right now but we really should allow variables at some point.
HKEY hRK=ParseRegRootKey(line,1);
if (INVALIDREGROOT == hRK || reg5 != multisz) PRINTHELPEX(cmdname); // WriteRegMultiStr only supports the /REGEDIT5 serialized format right now but we really should allow variables at some point.
ent.which=EW_WRITEREG;
ent.offsets[0]=REGROOTKEYTOINT(rootkey_tab[k]);
ent.offsets[0]=REGROOTKEYTOINT(hRK);
ent.offsets[1]=add_string(line.gettoken_str(2));
if (line.gettoken_str(2)[0] == _T('\\'))
warning_fl(DW_PARSE_REGPATHPREFIX, _T("%") NPRIs _T(": registry path name begins with \'\\\', may cause problems"),cmdname);
@ -4268,10 +4270,9 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
{
ent.which=EW_REGENUM;
ent.offsets[0]=GetUserVarIndex(line, 1);
int k=line.gettoken_enum(2,rootkeys[0]);
if (k == -1) k=line.gettoken_enum(2,rootkeys[1]);
if (ent.offsets[0] == -1 || k == -1) PRINTHELP()
ent.offsets[1]=REGROOTKEYTOINT(rootkey_tab[k]);
HKEY hRK=ParseRegRootKey(line,2);
if (ent.offsets[0] == -1 || INVALIDREGROOT == hRK) PRINTHELP()
ent.offsets[1]=REGROOTKEYTOINT(hRK);
ent.offsets[2]=add_string(line.gettoken_str(3));
ent.offsets[3]=add_string(line.gettoken_str(4));
ent.offsets[4]=which_token == TOK_ENUMREGKEY;

View file

@ -241,7 +241,7 @@ static tokenType tokenlist[TOK__LAST] =
{TOK_WRITEREGDWORD,_T("WriteRegDWORD"),4,0,_T("rootkey subkey entry_name new_value_dword\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)"),TP_CODE},
{TOK_WRITEREGSTR,_T("WriteRegStr"),4,0,_T("rootkey subkey entry_name new_value_string\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)"),TP_CODE},
{TOK_WRITEREGEXPANDSTR,_T("WriteRegExpandStr"),4,0,_T("rootkey subkey entry_name new_value_string\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)"),TP_CODE},
{TOK_WRITEREGNONE,_T("WriteRegNone"),3,1,_T("rootkey subkey entry_name [hex_data]\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)"),TP_CODE},
{TOK_WRITEREGNONE,_T("WriteRegNone"),3,1,_T("rootkey subkey entry_name [hex_data]"),TP_CODE},
{TOK_WRITEUNINSTALLER,_T("WriteUninstaller"),1,0,_T("uninstall_exe_name"),TP_CODE},
{TOK_PEDLLCHARACTERISTICS, _T("PEDllCharacteristics"),2,0,_T("addbits removebits"),TP_GLOBAL},
{TOK_PESUBSYSVER, _T("PESubsysVer"),1,0,_T("major.minor"),TP_GLOBAL},