[Python-checkins] python/dist/src/PC/bdist_wininst install.c, 1.5, 1.6

mhammond at users.sourceforge.net mhammond at users.sourceforge.net
Fri Jul 2 19:53:19 EDT 2004


Update of /cvsroot/python/python/dist/src/PC/bdist_wininst
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29805

Modified Files:
	install.c 
Log Message:
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.


Index: install.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/PC/bdist_wininst/install.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -C2 -d -r1.5 -r1.6
*** install.c	2 Jul 2004 08:02:40 -0000	1.5
--- install.c	2 Jul 2004 23:53:16 -0000	1.6
***************
*** 129,132 ****
--- 129,135 ----
  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? */
***************
*** 581,589 ****
--- 584,600 ----
  }
  
+ 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},
***************
*** 728,732 ****
  	char *tempname;
  	HINSTANCE hPython;
! 	tempname = tmpnam(NULL);
  	freopen(tempname, "a", stderr);
  	freopen(tempname, "a", stdout);
--- 739,743 ----
  	char *tempname;
  	HINSTANCE hPython;
! 	tempname = tempnam(NULL, NULL);
  	freopen(tempname, "a", stderr);
  	freopen(tempname, "a", stdout);
***************
*** 1321,1324 ****
--- 1332,1340 ----
  #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;
+ 
  
  /*
***************
*** 1343,1347 ****
  					      core_version, &bufsize, NULL,
  					      NULL, NULL, NULL)) {
! 		char subkey_name[80], vers_name[80], prefix_buf[MAX_PATH+1];
  		int itemindex;
  		DWORD value_size;
--- 1359,1363 ----
  					      core_version, &bufsize, NULL,
  					      NULL, NULL, NULL)) {
! 		char subkey_name[80], vers_name[80];
  		int itemindex;
  		DWORD value_size;
***************
*** 1358,1369 ****
  			  "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)) {
  				itemindex = SendMessage(hwnd, LB_ADDSTRING, 0,
! 							(LPARAM)(LPSTR)vers_name);
  				SendMessage(hwnd, LB_SETITEMDATA, itemindex,
! 					     (LPARAM)(LPSTR)strdup(prefix_buf));
  			}
  			RegCloseKey(hk);
--- 1374,1389 ----
  			  "Software\\Python\\PythonCore\\%s\\InstallPath",
  			  core_version);
  		if (ERROR_SUCCESS == RegOpenKeyEx(hkRoot, subkey_name, 0, KEY_READ, &hk)) {
! 			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);
! 				ivi->hkey = hkRoot;
  				SendMessage(hwnd, LB_SETITEMDATA, itemindex,
! 				            (LPARAM)(LPSTR)ivi);
  			}
  			RegCloseKey(hk);
***************
*** 1374,1377 ****
--- 1394,1441 ----
  }
  
+ /* 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)
***************
*** 1448,1452 ****
  			switch (HIWORD(wParam)) {
  				int id;
- 				char *cp;
  			case LBN_SELCHANGE:
  			  UpdateInstallDir:
--- 1512,1515 ----
***************
*** 1465,1477 ****
  					char *pbuf;
  					int result;
  					PropSheet_SetWizButtons(GetParent(hwnd),
  								PSWIZB_BACK | PSWIZB_NEXT);
  					/* Get the python directory */
! 					cp = (LPSTR)SendDlgItemMessage(hwnd,
  									IDC_VERSIONS_LIST,
  									LB_GETITEMDATA,
  									id,
  									0);
! 					strcpy(python_dir, cp);
  					SetDlgItemText(hwnd, IDC_PATH, python_dir);
  					/* retrieve the python version and pythondll to use */
--- 1528,1543 ----
  					char *pbuf;
  					int result;
+ 					InstalledVersionInfo *ivi;
  					PropSheet_SetWizButtons(GetParent(hwnd),
  								PSWIZB_BACK | PSWIZB_NEXT);
  					/* Get the python directory */
!                     ivi = (InstalledVersionInfo *)
!                                 SendDlgItemMessage(hwnd,
  									IDC_VERSIONS_LIST,
  									LB_GETITEMDATA,
  									id,
  									0);
!                     hkey_root = ivi->hkey;
! 					strcpy(python_dir, ivi->prefix);
  					SetDlgItemText(hwnd, IDC_PATH, python_dir);
  					/* retrieve the python version and pythondll to use */
***************
*** 1556,1568 ****
  	static char KeyName[] = 
  		"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
  	DWORD disposition;
  
! 	result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  			      KeyName,
! 			      0,
! 			      KEY_CREATE_SUB_KEY,
! 			      &hKey);
  	if (result != ERROR_SUCCESS) {
  		if (result == ERROR_ACCESS_DENIED) {
  			MessageBox(GetFocus(),
  				   "You do not seem to have sufficient access rights\n"
--- 1622,1647 ----
  	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;
  
! 	/* 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, /* 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"
***************
*** 1586,1589 ****
--- 1665,1671 ----
  	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);
  
***************
*** 1723,1726 ****
--- 1805,1810 ----
  			/* Strip the trailing backslash again */
  			python_dir[strlen(python_dir)-1] = '\0';
+             
+             CheckRootKey(hwnd);
  	    
  			if (!OpenLogfile(python_dir))
***************
*** 1851,1855 ****
  				fprintf(logfile, "300 Run Script: [%s]%s\n", pythondll, fname);
  
! 			tempname = tmpnam(NULL);
  
  			if (!freopen(tempname, "a", stderr))
--- 1935,1939 ----
  				fprintf(logfile, "300 Run Script: [%s]%s\n", pythondll, fname);
  
! 			tempname = tempnam(NULL, NULL);
  
  			if (!freopen(tempname, "a", stderr))
***************
*** 2101,2105 ****
  		*delim = '\0';
  
! 	result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  			      keyname,
  			      0,
--- 2185,2189 ----
  		*delim = '\0';
  
! 	result = RegOpenKeyEx(hkey_root,
  			      keyname,
  			      0,
***************
*** 2144,2148 ****
  	*value++ = '\0';
  
! 	result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  			      keyname,
  			      0,
--- 2228,2232 ----
  	*value++ = '\0';
  
! 	result = RegOpenKeyEx(hkey_root,
  			      keyname,
  			      0,
***************
*** 2210,2214 ****
  		argv[0] = scriptname;
  
! 		tempname = tmpnam(NULL);
  
  		if (!freopen(tempname, "a", stderr))
--- 2294,2298 ----
  		argv[0] = scriptname;
  
! 		tempname = tempnam(NULL, NULL);
  
  		if (!freopen(tempname, "a", stderr))
***************
*** 2269,2294 ****
  	}
  
- 	{
- 		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) {
--- 2353,2356 ----
***************
*** 2333,2336 ****
--- 2395,2399 ----
  		return 0;
  
+ 	hkey_root = HKEY_LOCAL_MACHINE;
  	cp = "";
  	for (i = 0; i < nLines; ++i) {
***************
*** 2340,2344 ****
  			cp = lines[i];
  			/* Parse the lines */
! 			if (2 == sscanf(cp, "%d Made Dir: %s", &ign, &buffer)) {
  				if (MyRemoveDirectory(cp))
  					++nDirs;
--- 2403,2421 ----
  			cp = lines[i];
  			/* Parse the lines */
! 			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;




More information about the Python-checkins mailing list