mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 19:34:08 +00:00 
			
		
		
		
	Patch [ 983775 ] Allow bdist_wininst to install for non-admin users
to address bugs: [ 555812 ] installing extension w/o admin rights [ 555810 ] removing extensions without admin rights * When enumerating the Python versions found, also remember the HKEY they were found under. * When installing, if Python was installed under HKCU, we will too. If Python was installed under HKLM, we check the permissions of the current user, and install where we can. * The "root" key we use is a global variable - all registry setting and delete functions use this global rather than a hardcoded HKLM. * A new entry is written to the install log, indicating the key we used. Uninstallation is based on this key. * 'tempnam()' is used rather than 'tmpnam()' - 'tmpnam' creates a temp file on the root of the current drive, and if this is readonly would explain the 'freopen' errors occasionally reported. 'tempnam' creates the temp file in the %TEMP% directory.
This commit is contained in:
		
							parent
							
								
									59ad45689b
								
							
						
					
					
						commit
						f9bfdd850c
					
				
					 1 changed files with 118 additions and 41 deletions
				
			
		| 
						 | 
				
			
			@ -128,6 +128,9 @@ int exe_size;			/* number of bytes for exe-file portion */
 | 
			
		|||
char python_dir[MAX_PATH];
 | 
			
		||||
char pythondll[MAX_PATH];
 | 
			
		||||
BOOL pyc_compile, pyo_compile;
 | 
			
		||||
/* Either HKLM or HKCU, depending on where Python itself is registered, and
 | 
			
		||||
   the permissions of the current user. */
 | 
			
		||||
HKEY hkey_root = (HKEY)-1;
 | 
			
		||||
 | 
			
		||||
BOOL success;			/* Installation successfull? */
 | 
			
		||||
char *failure_reason = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -580,11 +583,19 @@ static PyObject *PyMessageBox(PyObject *self, PyObject *args)
 | 
			
		|||
	return g_Py_BuildValue("i", rc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static PyObject *GetRootHKey(PyObject *self)
 | 
			
		||||
{
 | 
			
		||||
	return g_Py_BuildValue("l", hkey_root);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define METH_VARARGS 0x0001
 | 
			
		||||
#define METH_NOARGS   0x0004
 | 
			
		||||
typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
 | 
			
		||||
 | 
			
		||||
PyMethodDef meth[] = {
 | 
			
		||||
	{"create_shortcut", CreateShortcut, METH_VARARGS, NULL},
 | 
			
		||||
	{"get_special_folder_path", GetSpecialFolderPath, METH_VARARGS, NULL},
 | 
			
		||||
	{"get_root_hkey", (PyCFunction)GetRootHKey, METH_NOARGS, NULL},
 | 
			
		||||
	{"file_created", FileCreated, METH_VARARGS, NULL},
 | 
			
		||||
	{"directory_created", DirectoryCreated, METH_VARARGS, NULL},
 | 
			
		||||
	{"message_box", PyMessageBox, METH_VARARGS, NULL},
 | 
			
		||||
| 
						 | 
				
			
			@ -727,7 +738,7 @@ static int run_simple_script(char *script)
 | 
			
		|||
	int rc;
 | 
			
		||||
	char *tempname;
 | 
			
		||||
	HINSTANCE hPython;
 | 
			
		||||
	tempname = tmpnam(NULL);
 | 
			
		||||
	tempname = tempnam(NULL, NULL);
 | 
			
		||||
	freopen(tempname, "a", stderr);
 | 
			
		||||
	freopen(tempname, "a", stdout);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1320,6 +1331,11 @@ static BOOL GetOtherPythonVersion(HWND hwnd, LPSTR version)
 | 
			
		|||
}
 | 
			
		||||
#endif /* USE_OTHER_PYTHON_VERSIONS */
 | 
			
		||||
 | 
			
		||||
typedef struct _InstalledVersionInfo {
 | 
			
		||||
    char prefix[MAX_PATH+1]; // sys.prefix directory.
 | 
			
		||||
    HKEY hkey; // Is this Python in HKCU or HKLM?
 | 
			
		||||
} InstalledVersionInfo;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Fill the listbox specified by hwnd with all python versions found
 | 
			
		||||
| 
						 | 
				
			
			@ -1342,7 +1358,7 @@ static BOOL GetPythonVersions(HWND hwnd, HKEY hkRoot, LPSTR version)
 | 
			
		|||
	while (ERROR_SUCCESS == RegEnumKeyEx(hKey, index,
 | 
			
		||||
					      core_version, &bufsize, NULL,
 | 
			
		||||
					      NULL, NULL, NULL)) {
 | 
			
		||||
		char subkey_name[80], vers_name[80], prefix_buf[MAX_PATH+1];
 | 
			
		||||
		char subkey_name[80], vers_name[80];
 | 
			
		||||
		int itemindex;
 | 
			
		||||
		DWORD value_size;
 | 
			
		||||
		HKEY hk;
 | 
			
		||||
| 
						 | 
				
			
			@ -1357,14 +1373,18 @@ static BOOL GetPythonVersions(HWND hwnd, HKEY hkRoot, LPSTR version)
 | 
			
		|||
		wsprintf(subkey_name,
 | 
			
		||||
			  "Software\\Python\\PythonCore\\%s\\InstallPath",
 | 
			
		||||
			  core_version);
 | 
			
		||||
		value_size = sizeof(subkey_name);
 | 
			
		||||
		if (ERROR_SUCCESS == RegOpenKeyEx(hkRoot, subkey_name, 0, KEY_READ, &hk)) {
 | 
			
		||||
			if (ERROR_SUCCESS == RegQueryValueEx(hk, NULL, NULL, NULL, prefix_buf,
 | 
			
		||||
							     &value_size)) {
 | 
			
		||||
			InstalledVersionInfo *ivi = 
 | 
			
		||||
			      (InstalledVersionInfo *)malloc(sizeof(InstalledVersionInfo));
 | 
			
		||||
			value_size = sizeof(ivi->prefix);
 | 
			
		||||
			if (ivi && 
 | 
			
		||||
			    ERROR_SUCCESS == RegQueryValueEx(hk, NULL, NULL, NULL,
 | 
			
		||||
			                                     ivi->prefix, &value_size)) {
 | 
			
		||||
				itemindex = SendMessage(hwnd, LB_ADDSTRING, 0,
 | 
			
		||||
							(LPARAM)(LPSTR)vers_name);
 | 
			
		||||
				                        (LPARAM)(LPSTR)vers_name);
 | 
			
		||||
				ivi->hkey = hkRoot;
 | 
			
		||||
				SendMessage(hwnd, LB_SETITEMDATA, itemindex,
 | 
			
		||||
					     (LPARAM)(LPSTR)strdup(prefix_buf));
 | 
			
		||||
				            (LPARAM)(LPSTR)ivi);
 | 
			
		||||
			}
 | 
			
		||||
			RegCloseKey(hk);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -1373,6 +1393,50 @@ static BOOL GetPythonVersions(HWND hwnd, HKEY hkRoot, LPSTR version)
 | 
			
		|||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Determine if the current user can write to HKEY_LOCAL_MACHINE */
 | 
			
		||||
BOOL HasLocalMachinePrivs()
 | 
			
		||||
{
 | 
			
		||||
		HKEY hKey;
 | 
			
		||||
		DWORD result;
 | 
			
		||||
		static char KeyName[] = 
 | 
			
		||||
			"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
 | 
			
		||||
 | 
			
		||||
		result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
 | 
			
		||||
					  KeyName,
 | 
			
		||||
					  0,
 | 
			
		||||
					  KEY_CREATE_SUB_KEY,
 | 
			
		||||
					  &hKey);
 | 
			
		||||
		if (result==0)
 | 
			
		||||
			RegCloseKey(hKey);
 | 
			
		||||
		return result==0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Check the root registry key to use - either HKLM or HKCU.
 | 
			
		||||
// If Python is installed in HKCU, then our extension also must be installed
 | 
			
		||||
// in HKCU - as Python won't be available for other users, we shouldn't either
 | 
			
		||||
// (and will fail if we are!)
 | 
			
		||||
// If Python is installed in HKLM, then we will also prefer to use HKLM, but
 | 
			
		||||
// this may not be possible - so we silently fall back to HKCU.
 | 
			
		||||
//
 | 
			
		||||
// We assume hkey_root is already set to where Python itself is installed.
 | 
			
		||||
void CheckRootKey(HWND hwnd)
 | 
			
		||||
{
 | 
			
		||||
	if (hkey_root==HKEY_CURRENT_USER) {
 | 
			
		||||
		; // as above, always install ourself in HKCU too.
 | 
			
		||||
	} else if (hkey_root==HKEY_LOCAL_MACHINE) {
 | 
			
		||||
		// Python in HKLM, but we may or may not have permissions there.
 | 
			
		||||
		// Open the uninstall key with 'create' permissions - if this fails,
 | 
			
		||||
		// we don't have permission.
 | 
			
		||||
		if (!HasLocalMachinePrivs())
 | 
			
		||||
			hkey_root = HKEY_CURRENT_USER;
 | 
			
		||||
	} else {
 | 
			
		||||
		MessageBox(hwnd, "Don't know Python's installation type",
 | 
			
		||||
				   "Strange", MB_OK | MB_ICONSTOP);
 | 
			
		||||
		/* Default to wherever they can, but preferring HKLM */
 | 
			
		||||
		hkey_root = HasLocalMachinePrivs() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Return the installation scheme depending on Python version number */
 | 
			
		||||
SCHEME *GetScheme(int major, int minor)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1447,7 +1511,6 @@ SelectPythonDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 | 
			
		|||
		case IDC_VERSIONS_LIST:
 | 
			
		||||
			switch (HIWORD(wParam)) {
 | 
			
		||||
				int id;
 | 
			
		||||
				char *cp;
 | 
			
		||||
			case LBN_SELCHANGE:
 | 
			
		||||
			  UpdateInstallDir:
 | 
			
		||||
				PropSheet_SetWizButtons(GetParent(hwnd),
 | 
			
		||||
| 
						 | 
				
			
			@ -1464,15 +1527,18 @@ SelectPythonDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 | 
			
		|||
				} else {
 | 
			
		||||
					char *pbuf;
 | 
			
		||||
					int result;
 | 
			
		||||
					InstalledVersionInfo *ivi;
 | 
			
		||||
					PropSheet_SetWizButtons(GetParent(hwnd),
 | 
			
		||||
								PSWIZB_BACK | PSWIZB_NEXT);
 | 
			
		||||
					/* Get the python directory */
 | 
			
		||||
					cp = (LPSTR)SendDlgItemMessage(hwnd,
 | 
			
		||||
                    ivi = (InstalledVersionInfo *)
 | 
			
		||||
                                SendDlgItemMessage(hwnd,
 | 
			
		||||
									IDC_VERSIONS_LIST,
 | 
			
		||||
									LB_GETITEMDATA,
 | 
			
		||||
									id,
 | 
			
		||||
									0);
 | 
			
		||||
					strcpy(python_dir, cp);
 | 
			
		||||
                    hkey_root = ivi->hkey;
 | 
			
		||||
					strcpy(python_dir, ivi->prefix);
 | 
			
		||||
					SetDlgItemText(hwnd, IDC_PATH, python_dir);
 | 
			
		||||
					/* retrieve the python version and pythondll to use */
 | 
			
		||||
					result = SendDlgItemMessage(hwnd, IDC_VERSIONS_LIST,
 | 
			
		||||
| 
						 | 
				
			
			@ -1555,15 +1621,28 @@ static BOOL OpenLogfile(char *dir)
 | 
			
		|||
	char subkey_name[256];
 | 
			
		||||
	static char KeyName[] = 
 | 
			
		||||
		"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
 | 
			
		||||
	const char *root_name = (hkey_root==HKEY_LOCAL_MACHINE ?
 | 
			
		||||
	                        "HKEY_LOCAL_MACHINE" : "HKEY_CURRENT_USER");
 | 
			
		||||
	DWORD disposition;
 | 
			
		||||
 | 
			
		||||
	result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
 | 
			
		||||
	/* Use Create, as the Uninstall subkey may not exist under HKCU.
 | 
			
		||||
	   Use CreateKeyEx, so we can specify a SAM specifying write access
 | 
			
		||||
	*/
 | 
			
		||||
		result = RegCreateKeyEx(hkey_root,
 | 
			
		||||
			      KeyName,
 | 
			
		||||
			      0,
 | 
			
		||||
			      KEY_CREATE_SUB_KEY,
 | 
			
		||||
			      &hKey);
 | 
			
		||||
			      0, /* reserved */
 | 
			
		||||
			      NULL, /* class */
 | 
			
		||||
			      0, /* options */
 | 
			
		||||
			      KEY_CREATE_SUB_KEY, /* sam */
 | 
			
		||||
			      NULL, /* security */
 | 
			
		||||
			      &hKey, /* result key */
 | 
			
		||||
			      NULL); /* disposition */
 | 
			
		||||
	if (result != ERROR_SUCCESS) {
 | 
			
		||||
		if (result == ERROR_ACCESS_DENIED) {
 | 
			
		||||
			/* This should no longer be able to happen - we have already
 | 
			
		||||
			   checked if they have permissions in HKLM, and all users
 | 
			
		||||
			   should have write access to HKCU.
 | 
			
		||||
			*/
 | 
			
		||||
			MessageBox(GetFocus(),
 | 
			
		||||
				   "You do not seem to have sufficient access rights\n"
 | 
			
		||||
				   "on this machine to install this software",
 | 
			
		||||
| 
						 | 
				
			
			@ -1585,6 +1664,9 @@ static BOOL OpenLogfile(char *dir)
 | 
			
		|||
	fprintf(logfile, buffer);
 | 
			
		||||
	fprintf(logfile, "Source: %s\n", modulename);
 | 
			
		||||
 | 
			
		||||
	/* Root key must be first entry processed by uninstaller. */
 | 
			
		||||
	fprintf(logfile, "999 Root Key: %s\n", root_name);
 | 
			
		||||
 | 
			
		||||
	sprintf(subkey_name, "%s-py%d.%d", meta_name, py_major, py_minor);
 | 
			
		||||
 | 
			
		||||
	result = RegCreateKeyEx(hKey, subkey_name,
 | 
			
		||||
| 
						 | 
				
			
			@ -1723,6 +1805,8 @@ InstallFilesDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 | 
			
		|||
			/* Strip the trailing backslash again */
 | 
			
		||||
			python_dir[strlen(python_dir)-1] = '\0';
 | 
			
		||||
            
 | 
			
		||||
            CheckRootKey(hwnd);
 | 
			
		||||
	    
 | 
			
		||||
			if (!OpenLogfile(python_dir))
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1850,7 +1934,7 @@ FinishedDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 | 
			
		|||
			if (logfile)
 | 
			
		||||
				fprintf(logfile, "300 Run Script: [%s]%s\n", pythondll, fname);
 | 
			
		||||
 | 
			
		||||
			tempname = tmpnam(NULL);
 | 
			
		||||
			tempname = tempnam(NULL, NULL);
 | 
			
		||||
 | 
			
		||||
			if (!freopen(tempname, "a", stderr))
 | 
			
		||||
				MessageBox(GetFocus(), "freopen stderr", NULL, MB_OK);
 | 
			
		||||
| 
						 | 
				
			
			@ -2100,7 +2184,7 @@ void DeleteRegistryKey(char *string)
 | 
			
		|||
	if (delim)
 | 
			
		||||
		*delim = '\0';
 | 
			
		||||
 | 
			
		||||
	result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
 | 
			
		||||
	result = RegOpenKeyEx(hkey_root,
 | 
			
		||||
			      keyname,
 | 
			
		||||
			      0,
 | 
			
		||||
			      KEY_WRITE,
 | 
			
		||||
| 
						 | 
				
			
			@ -2143,7 +2227,7 @@ void DeleteRegistryValue(char *string)
 | 
			
		|||
 | 
			
		||||
	*value++ = '\0';
 | 
			
		||||
 | 
			
		||||
	result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
 | 
			
		||||
	result = RegOpenKeyEx(hkey_root,
 | 
			
		||||
			      keyname,
 | 
			
		||||
			      0,
 | 
			
		||||
			      KEY_WRITE,
 | 
			
		||||
| 
						 | 
				
			
			@ -2209,7 +2293,7 @@ BOOL Run_RemoveScript(char *line)
 | 
			
		|||
 | 
			
		||||
		argv[0] = scriptname;
 | 
			
		||||
 | 
			
		||||
		tempname = tmpnam(NULL);
 | 
			
		||||
		tempname = tempnam(NULL, NULL);
 | 
			
		||||
 | 
			
		||||
		if (!freopen(tempname, "a", stderr))
 | 
			
		||||
			MessageBox(GetFocus(), "freopen stderr", NULL, MB_OK);
 | 
			
		||||
| 
						 | 
				
			
			@ -2268,28 +2352,6 @@ int DoUninstall(int argc, char **argv)
 | 
			
		|||
		return 1; /* Error */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		DWORD result;
 | 
			
		||||
		HKEY hKey;
 | 
			
		||||
		static char KeyName[] = 
 | 
			
		||||
			"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
 | 
			
		||||
 | 
			
		||||
		result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
 | 
			
		||||
				      KeyName,
 | 
			
		||||
				      0,
 | 
			
		||||
				      KEY_CREATE_SUB_KEY,
 | 
			
		||||
				      &hKey);
 | 
			
		||||
		if (result == ERROR_ACCESS_DENIED) {
 | 
			
		||||
			MessageBox(GetFocus(),
 | 
			
		||||
				   "You do not seem to have sufficient access rights\n"
 | 
			
		||||
				   "on this machine to uninstall this software",
 | 
			
		||||
				   NULL,
 | 
			
		||||
				   MB_OK | MB_ICONSTOP);
 | 
			
		||||
			return 1; /* Error */
 | 
			
		||||
		}
 | 
			
		||||
		RegCloseKey(hKey);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logfile = fopen(argv[2], "r");
 | 
			
		||||
	if (!logfile) {
 | 
			
		||||
		MessageBox(NULL,
 | 
			
		||||
| 
						 | 
				
			
			@ -2332,6 +2394,7 @@ int DoUninstall(int argc, char **argv)
 | 
			
		|||
				MB_YESNO | MB_ICONQUESTION))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	hkey_root = HKEY_LOCAL_MACHINE;
 | 
			
		||||
	cp = "";
 | 
			
		||||
	for (i = 0; i < nLines; ++i) {
 | 
			
		||||
		/* Ignore duplicate lines */
 | 
			
		||||
| 
						 | 
				
			
			@ -2339,7 +2402,21 @@ int DoUninstall(int argc, char **argv)
 | 
			
		|||
			int ign;
 | 
			
		||||
			cp = lines[i];
 | 
			
		||||
			/* Parse the lines */
 | 
			
		||||
			if (2 == sscanf(cp, "%d Made Dir: %s", &ign, &buffer)) {
 | 
			
		||||
			if (2 == sscanf(cp, "%d Root Key: %s", &ign, &buffer)) {
 | 
			
		||||
				if (strcmp(buffer, "HKEY_CURRENT_USER")==0)
 | 
			
		||||
					hkey_root = HKEY_CURRENT_USER;
 | 
			
		||||
				else {
 | 
			
		||||
					// HKLM - check they have permissions.
 | 
			
		||||
					if (!HasLocalMachinePrivs()) {
 | 
			
		||||
						MessageBox(GetFocus(),
 | 
			
		||||
							   "You do not seem to have sufficient access rights\n"
 | 
			
		||||
							   "on this machine to uninstall this software",
 | 
			
		||||
							   NULL,
 | 
			
		||||
							   MB_OK | MB_ICONSTOP);
 | 
			
		||||
						return 1; /* Error */
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} else if (2 == sscanf(cp, "%d Made Dir: %s", &ign, &buffer)) {
 | 
			
		||||
				if (MyRemoveDirectory(cp))
 | 
			
		||||
					++nDirs;
 | 
			
		||||
				else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue