speedo,w32: Allow installation as normal user

* build-aux/speedo/w32/g4wihelp.c (ENV_HK_USER, ENV_REG_USER):
New defines.
(path_add): Handle is_user_install variable. Don't abort
if Path reg key does not exist. Fix crash if Path reg key
does not contain a semicolon.
(path_remove): Handle is_user_install variable. Fix crash
if Path reg key does not exist.
* build-aux/speedo/w32/inst.nsi: Remove obsolete HAVE_STARTMENU
this was double guarded with WITH_GUI. Add Multiuser plugin and
defines for this. Use SHCTX instead of HKLM / HKCU.
(PrintNonAdminWarning): Only Warn and don't abort.

--
The default is still to install as Adminstrator system wide
but the user now has the option to explicitly install GnuPG without
Administrator rights. A warning will be shown in that case but
a user may continue.

A per user install is by default under %LOCALAPPDATA%\GnuPG

Related Task: T2971

Signed-off-by: Andre Heinecke <aheinecke@intevation.de>
This commit is contained in:
Andre Heinecke 2017-05-03 14:40:16 +02:00
parent 201f868030
commit cacfd4bce9
No known key found for this signature in database
GPG Key ID: 2978E9D40CBABA5C
2 changed files with 138 additions and 69 deletions

View File

@ -964,10 +964,8 @@ read_w32_registry_string (HKEY root, const char *dir, const char *name)
#define ENV_REG "SYSTEM\\CurrentControlSet\\Control\\" \
"Session Manager\\Environment"
/* The following setting can be used for a per-user setting. */
#if 0
#define ENV_HK HKEY_CURRENT_USER
#define ENV_REG "Environment"
#endif
#define ENV_HK_USER HKEY_CURRENT_USER
#define ENV_REG_USER "Environment"
/* Due to a bug in Windows7 (kb 2685893) we better put a lower limit
than 8191 on the maximum length of the PATH variable. Note, that
depending on the used toolchain we used to had a 259 byte limit in
@ -979,12 +977,16 @@ path_add (HWND hwndParent, int string_size, char *variables,
stack_t **stacktop, extra_parameters_t *extra)
{
char dir[PATH_LENGTH_LIMIT];
char is_user_install[2];
char *path;
char *path_new;
int path_new_size;
char *comp;
const char delims[] = ";";
int is_user;
HKEY key_handle = 0;
HKEY root_key;
const char *env_reg;
g_hwndParent = hwndParent;
EXDLL_INIT();
@ -997,13 +999,26 @@ path_add (HWND hwndParent, int string_size, char *variables,
if (popstring (dir, sizeof (dir)))
return;
/* MessageBox (g_hwndParent, "XXX 2", 0, MB_OK); */
/* The expected stack layout: HKEY component. */
if (popstring (is_user_install, sizeof (is_user_install)))
return;
if (!strcmp(is_user_install, "1"))
{
root_key = ENV_HK_USER;
env_reg = ENV_REG_USER;
}
else
{
root_key = ENV_HK;
env_reg = ENV_REG;
}
path = read_w32_registry_string (root_key, env_reg, "Path");
path = read_w32_registry_string (ENV_HK, ENV_REG, "Path");
if (! path)
{
MessageBox (g_hwndParent, "No PATH variable found", 0, MB_OK);
return;
path = strdup ("");
}
/* MessageBox (g_hwndParent, "XXX 3", 0, MB_OK); */
@ -1041,6 +1056,8 @@ path_add (HWND hwndParent, int string_size, char *variables,
do
{
/* MessageBox (g_hwndParent, comp, 0, MB_OK); */
if (!comp)
break;
if (!strcmp (comp, dir))
{
@ -1053,10 +1070,8 @@ path_add (HWND hwndParent, int string_size, char *variables,
while (comp);
free (path);
/* MessageBox (g_hwndParent, "XXX 8", 0, MB_OK); */
/* Set a key for our CLSID. */
RegCreateKey (ENV_HK, ENV_REG, &key_handle);
/* Update the path key. */
RegCreateKey (root_key, env_reg, &key_handle);
RegSetValueEx (key_handle, "Path", 0, REG_EXPAND_SZ,
path_new, path_new_size);
RegCloseKey (key_handle);
@ -1074,6 +1089,7 @@ path_remove (HWND hwndParent, int string_size, char *variables,
stack_t **stacktop, extra_parameters_t *extra)
{
char dir[PATH_LENGTH_LIMIT];
char is_user_install[2];
char *path;
char *path_new;
int path_new_size;
@ -1082,6 +1098,8 @@ path_remove (HWND hwndParent, int string_size, char *variables,
HKEY key_handle = 0;
int changed = 0;
int count = 0;
HKEY root_key;
const char *env_reg;
g_hwndParent = hwndParent;
EXDLL_INIT();
@ -1092,7 +1110,25 @@ path_remove (HWND hwndParent, int string_size, char *variables,
if (popstring (dir, sizeof (dir)))
return;
path = read_w32_registry_string (ENV_HK, ENV_REG, "Path");
/* The expected stack layout: HKEY component. */
if (popstring (is_user_install, sizeof (is_user_install)))
return;
if (!strcmp(is_user_install, "1"))
{
root_key = ENV_HK_USER;
env_reg = ENV_REG_USER;
}
else
{
root_key = ENV_HK;
env_reg = ENV_REG;
}
path = read_w32_registry_string (root_key, env_reg, "Path");
if (!path)
return;
/* Old path plus semicolon plus dir plus terminating nul. */
path_new_size = strlen (path) + 1;
path_new = malloc (path_new_size);
@ -1126,7 +1162,7 @@ path_remove (HWND hwndParent, int string_size, char *variables,
return;
/* Set a key for our CLSID. */
RegCreateKey (ENV_HK, ENV_REG, &key_handle);
RegCreateKey (root_key, env_reg, &key_handle);
RegSetValueEx (key_handle, "Path", 0, REG_EXPAND_SZ,
path_new, path_new_size);
RegCloseKey (key_handle);

View File

@ -1,5 +1,6 @@
# inst.nsi - Installer for GnuPG on Windows. -*- coding: latin-1; -*-
# Copyright (C) 2005, 2014 g10 Code GmbH
# 2017 Intevation GmbH
#
# This file is part of GnuPG.
#
@ -42,7 +43,7 @@
!define PRETTY_PACKAGE "GNU Privacy Guard"
!define PRETTY_PACKAGE_SHORT "GnuPG"
!define COMPANY "The GnuPG Project"
!define COPYRIGHT "Copyright (C) 2015 The GnuPG Project"
!define COPYRIGHT "Copyright (C) 2017 The GnuPG Project"
!define DESCRIPTION "GnuPG: The GNU Privacy Guard for Windows"
!define INSTALL_DIR "GnuPG"
@ -80,9 +81,6 @@ SetCompressor lzma
# SetCompressorDictSize 8
!endif
# Include the generic parts.
!define HAVE_STARTMENU
# We use the modern UI.
!include "MUI.nsh"
@ -90,6 +88,17 @@ SetCompressor lzma
!include "LogicLib.nsh"
!include "x64.nsh"
# We support user mode installation but prefer system wide
!define MULTIUSER_EXECUTIONLEVEL Highest
!define MULTIUSER_MUI
!define MULTIUSER_INSTALLMODE_COMMANDLINE
!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY "Software\${PACKAGE_SHORT}"
!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME ""
!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_KEY "Software\${PACKAGE_SHORT}"
!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME "Install Directory"
!define MULTIUSER_INSTALLMODE_INSTDIR "${PACKAGE_SHORT}"
!include "MultiUser.nsh"
# Set the package name. Note that this name should not be suffixed
# with the version because this would get displayed in the start menu.
# Given that a slash in the name troubles Windows startmenu creation
@ -109,9 +118,6 @@ OutFile "${NAME}-${VERSION}_${BUILD_DATESTR}.exe"
!endif
InstallDir "$PROGRAMFILES\${INSTALL_DIR}"
InstallDirRegKey HKLM "Software\${PACKAGE_SHORT}" "Install Directory"
# Add version information to the file properties.
VIProductVersion "${PROD_VERSION}"
VIAddVersionKey "ProductName" "${PRETTY_PACKAGE_SHORT} (${VERSION})"
@ -161,7 +167,7 @@ VIAddVersionKey "FileVersion" "${PROD_VERSION}"
# We don't have MUI_PAGE_DIRECTORY
!ifdef HAVE_STARTMENU
!ifdef WITH_GUI
Page custom CustomPageOptions
@ -169,7 +175,7 @@ Var STARTMENU_FOLDER
!define MUI_PAGE_CUSTOMFUNCTION_PRE CheckIfStartMenuWanted
!define MUI_STARTMENUPAGE_NODISABLE
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU"
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "SHCTX"
!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\GnuPG"
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
# We need to set the Startmenu name explicitly because a slash in the
@ -354,6 +360,8 @@ FunctionEnd
# OS version without the need for an Administrator is in use. Print a
# diagnostic if this is not the case and abort installation.
Function PrintNonAdminWarning
Var /GLOBAL is_user_install
StrCpy $is_user_install "0"
ClearErrors
UserInfo::GetName
IfErrors leave
@ -361,9 +369,11 @@ Function PrintNonAdminWarning
UserInfo::GetAccountType
Pop $1
StrCmp $1 "Admin" leave +1
MessageBox MB_OK "$(T_AdminNeeded)"
Quit
MessageBox MB_YESNO "$(T_AdminWanted)" IDNO exit
StrCpy $is_user_install "1"
goto leave
exit:
Quit
leave:
FunctionEnd
@ -446,24 +456,30 @@ LangString T_FoundExistingVersion ${LANG_GERMAN} \
eine neuere oder dieselbe Version handelt.)"
LangString T_FoundExistingVersionB ${LANG_ENGLISH} \
"A version of GnuPG has already been installed on the system. \
There will be no problem installing and thus overwriting this \
Version. $\r$\n\
$\r$\n\
$\r$\n\
Do you want to continue installing GnuPG?"
LangString T_FoundExistingVersionB ${LANG_GERMAN} \
"Eine Version von GnuPG ist hier bereits installiert. \
Es ist problemlos möglich, die Installation fortzuführen. $\r$\n\
$\r$\n\
$\r$\n\
Möchten die die Installation von GnuPG fortführen?"
# From Function PrintNonAdminWarning
LangString T_AdminNeeded ${LANG_ENGLISH} \
"Warning: Administrator permissions required for a successful installation"
LangString T_AdminNeeded ${LANG_GERMAN} \
"Achtung: Für eine erfolgreiche Installation werden \
Administratorrechte benötigt."
LangString T_AdminWanted ${LANG_ENGLISH} \
"Warning: It is recommended to install GnuPG system-wide with \
administrator rights. \
$\r$\n\
$\r$\n\
Do you want to continue installing GnuPG without administrator rights?"
LangString T_AdminWanted ${LANG_GERMAN} \
"Achtung: Es wird empfohlen GnuPG systemweit mit \
Administratorrechten zu installieren. \
$\r$\n\
$\r$\n\
Möchten die die Installation von GnuPG ohne Administratorrechte fortführen?"
# From Function PrintCloseOtherApps
LangString T_CloseOtherApps ${LANG_ENGLISH} \
@ -505,7 +521,7 @@ FunctionEnd
# Input - head of the stack
Function AddToPath
Exch $0
g4wihelp::path_add "$0"
g4wihelp::path_add "$0" $is_user_install
StrCmp $R5 "0" add_to_path_done
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
add_to_path_done:
@ -516,8 +532,24 @@ FunctionEnd
# RemoveFromPath - Remove a given dir from the path
# Input: head of the stack
Function un.RemoveFromPath
ClearErrors
UserInfo::GetName
IfErrors remove_admin
Pop $0
UserInfo::GetAccountType
Pop $1
StrCmp $1 "Admin" remove_admin remove_user
remove_admin:
Exch $0
g4wihelp::path_remove "$0"
g4wihelp::path_remove "$0" "0"
goto remove_done
remove_user:
Exch $0
g4wihelp::path_remove "$0" "1"
goto remove_done
remove_done:
StrCmp $R5 "0" remove_from_path_done
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
remove_from_path_done:
@ -540,7 +572,7 @@ Section "-gnupginst"
FileWrite $0 "${VERSION}$\r$\n"
FileClose $0
WriteRegStr HKLM "Software\GnuPG" "Install Directory" $INSTDIR
WriteRegStr SHCTX "Software\GnuPG" "Install Directory" $INSTDIR
# If we are reinstalling, try to kill a possible running gpa using
# an already installed gpa.
@ -1381,7 +1413,7 @@ Section "-un.gnupginst"
RMDir "$INSTDIR"
# Clean the registry.
DeleteRegValue HKLM "Software\GNU\GnuPG" "Install Directory"
DeleteRegValue SHCTX "Software\GNU\GnuPG" "Install Directory"
SectionEnd
@ -1409,8 +1441,25 @@ Function .onInit
!insertmacro MUI_INSTALLOPTIONS_EXTRACT "${W32_SRCDIR}/inst-options.ini"
#Call CalcDepends
Var /GLOBAL changed_dir
# Check if the install directory was modified on the command line
StrCmp "$INSTDIR" "$PROGRAMFILES\${INSTALL_DIR}" unmodified 0
# It is modified. Save that value.
StrCpy $changed_dir "$INSTDIR"
# MULITUSER_INIT overwrites directory setting from command line
!insertmacro MULTIUSER_INIT
StrCpy $INSTDIR "$changed_dir"
goto initDone
unmodified:
!insertmacro MULTIUSER_INIT
initDone:
FunctionEnd
Function "un.onInit"
!insertmacro MULTIUSER_UNINIT
FunctionEnd
#Function .onInstFailed
# Delete $TEMP\gpgspltmp.wav
@ -1439,13 +1488,6 @@ FunctionEnd
!ifdef WITH_GUI
Section "-startmenu"
!ifdef HAVE_STARTMENU
# Make sure that the context of the automatic variables has been set to
# the "all users" shell folder. This guarantees that the menu gets written
# for all users. We have already checked that we are running as Admin; or
# we printed a warning that installation will not succeed.
SetShellVarContext all
# Check if the start menu entries where requested.
!insertmacro MUI_INSTALLOPTIONS_READ $R0 "${W32_SRCDIR}/inst-options.ini" \
"Field 2" "State"
@ -1517,7 +1559,6 @@ no_gpa_quicklaunch:
no_quick_launch:
!endif
SectionEnd
!endif
@ -1533,30 +1574,23 @@ Section
# Windows Add/Remove Programs support
StrCpy $MYTMP "Software\Microsoft\Windows\CurrentVersion\Uninstall\GnuPG"
WriteRegExpandStr HKLM $MYTMP "UninstallString" '"$INSTDIR\gnupg-uninstall.exe"'
WriteRegExpandStr HKLM $MYTMP "InstallLocation" "$INSTDIR"
WriteRegStr HKLM $MYTMP "DisplayName" "${PRETTY_PACKAGE}"
WriteRegExpandStr SHCTX $MYTMP "UninstallString" '"$INSTDIR\gnupg-uninstall.exe"'
WriteRegExpandStr SHCTX $MYTMP "InstallLocation" "$INSTDIR"
WriteRegStr SHCTX $MYTMP "DisplayName" "${PRETTY_PACKAGE}"
!ifdef WITH_GUI
WriteRegStr HKLM $MYTMP "DisplayIcon" "$INSTDIR\bin\gpa.exe,0"
WriteRegStr SHCTX $MYTMP "DisplayIcon" "$INSTDIR\bin\gpa.exe,0"
!else
WriteRegStr SHCTX $MYTMP "DisplayIcon" "$INSTDIR\bin\gpg.exe,0"
!endif
WriteRegStr HKLM $MYTMP "DisplayVersion" "${VERSION}"
WriteRegStr HKLM $MYTMP "Publisher" "The GnuPG Project"
WriteRegStr HKLM $MYTMP "URLInfoAbout" "https://gnupg.org"
WriteRegDWORD HKLM $MYTMP "NoModify" "1"
WriteRegDWORD HKLM $MYTMP "NoRepair" "1"
WriteRegStr SHCTX $MYTMP "DisplayVersion" "${VERSION}"
WriteRegStr SHCTX $MYTMP "Publisher" "The GnuPG Project"
WriteRegStr SHCTX $MYTMP "URLInfoAbout" "https://gnupg.org"
WriteRegDWORD SHCTX $MYTMP "NoModify" "1"
WriteRegDWORD SHCTX $MYTMP "NoRepair" "1"
SectionEnd
Section Uninstall
!ifdef WITH_GUI
!ifdef HAVE_STARTMENU
# Make sure that the context of the automatic variables has been set to
# the "all users" shell folder. This guarantees that the menu gets written
# for all users. We have already checked that we are running as Admin; or
# we printed a warning that installation will not succeed.
SetShellVarContext all
#---------------------------------------------------
# Delete the menu entries and any empty parent menus
#---------------------------------------------------
@ -1574,7 +1608,7 @@ Section Uninstall
StrCmp $MYTMP $SMPROGRAMS startMenuDeleteLoopDone startMenuDeleteLoop
startMenuDeleteLoopDone:
DeleteRegValue HKLM "Software\GNU\GnuPG" "Start Menu Folder"
DeleteRegValue SHCTX "Software\GNU\GnuPG" "Start Menu Folder"
# Delete Desktop links.
Delete "$DESKTOP\GPA.lnk"
@ -1586,15 +1620,14 @@ Section Uninstall
Delete "$QUICKLAUNCH\GPA.lnk"
no_quick_launch_uninstall:
!endif
!endif
Delete "$INSTDIR\gnupg-uninstall.exe"
RMDir "$INSTDIR"
# Clean the registry.
DeleteRegValue HKLM "Software\GnuPG" "Install Directory"
DeleteRegKey /ifempty HKLM "Software\GnuPG"
DeleteRegValue SHCTX "Software\GnuPG" "Install Directory"
DeleteRegKey /ifempty SHCTX "Software\GnuPG"
# Remove Windows Add/Remove Programs support.
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\GnuPG"
DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\GnuPG"
SectionEnd