wineboot: Start items in StartUp folder on boot, includes security measures. [fixed]

Misha Koshelev mk144210 at bcm.tmc.edu
Sun Feb 11 21:46:11 CST 2007


http://bugs.winehq.org/show_bug.cgi?id=7384

Installer requires Startup item execution on boot. This patch is the one
with security measures, it includes the ShellExecute fix so now works 
properly. Also, I added a registry key (HKEY_CURRENT_USER\Software\Wine
\StartupItems) that if set to "always" makes it like Windows, and always
runs startup items without ever asking the user.

Changelog:

	* wineboot: Start items in StartUp folder on boot, includes security
measures. 
-------------- next part --------------
From 7465a6f5e695a33670343cd959fca3fbf763899a Mon Sep 17 00:00:00 2001
From: Misha Koshelev <mk144210 at bcm.tmc.edu>
Date: Sun, 11 Feb 2007 21:41:51 -0600
Subject: wineboot: Start items in StartUp folder on boot, includes security measures.
---
 programs/wineboot/En.rc       |   36 +++++++
 programs/wineboot/Makefile.in |    5 +
 programs/wineboot/wineboot.c  |  222 +++++++++++++++++++++++++++++++++++++++++
 programs/wineboot/wineboot.h  |   21 ++++
 programs/wineboot/wineboot.rc |   26 +++++
 5 files changed, 307 insertions(+), 3 deletions(-)

diff --git a/programs/wineboot/En.rc b/programs/wineboot/En.rc
new file mode 100644
index 0000000..286b03c
--- /dev/null
+++ b/programs/wineboot/En.rc
@@ -0,0 +1,36 @@
+/*
+ * Wine Boot
+ * English Language Support
+ *
+ * Copyright (c) 2007 Misha Koshelev.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
+
+Run_Confirmation_Dialog DIALOG 100, 200, 300, 70
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION
+CAPTION "Simulating Windows Boot"
+FONT 8, "MS Shell Dlg"
+{
+ LTEXT "The following program would like to be run:", -1, 20, 10, 260, 12
+ LTEXT "Program name here", ID_PROGRAM, 20, 22, 260, 12
+ LTEXT "Would you like to run the program?", -1, 20, 34, 260, 12
+ PUSHBUTTON "Always", ID_ALWAYS, 40, 50, 50, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Yes", IDYES, 100, 50, 50, 14, WS_GROUP | WS_TABSTOP
+ DEFPUSHBUTTON "No", IDNO, 160, 50, 50, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Never", ID_NEVER, 220, 50, 50, 14, WS_GROUP | WS_TABSTOP
+}
diff --git a/programs/wineboot/Makefile.in b/programs/wineboot/Makefile.in
index 08c27a5..7437cab 100644
--- a/programs/wineboot/Makefile.in
+++ b/programs/wineboot/Makefile.in
@@ -4,12 +4,15 @@ SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = wineboot.exe
 APPMODE   = -mconsole
-IMPORTS   = version user32 advapi32 kernel32
+IMPORTS   = version user32 advapi32 kernel32 shell32 shlwapi
+EXTRALIBS = -luuid
 
 C_SRCS = \
 	shutdown.c \
 	wineboot.c
 
+RC_SRCS = wineboot.rc
+
 @MAKE_PROG_RULES@
 
 @DEPENDENCIES@  # everything below this line is overwritten by make depend
diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c
index 1434003..ba973cf 100644
--- a/programs/wineboot/wineboot.c
+++ b/programs/wineboot/wineboot.c
@@ -37,7 +37,7 @@
  * - HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce (all, synch)
  * - HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run (all, asynch)
  * - HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run (all, asynch)
- * - Startup folders (all, ?asynch?, no imp)
+ * - Startup folders (all, ?asynch?)
  * - HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce (all, asynch)
  *   
  * Somewhere in there is processing the RunOnceEx entries (also no imp)
@@ -63,6 +63,14 @@ #endif
 #include <windows.h>
 #include <wine/debug.h>
 
+#define COBJMACROS
+#include <shlobj.h>
+#include <shobjidl.h>
+#include <shlwapi.h>
+#include <shellapi.h>
+
+#include "wineboot.h"
+
 WINE_DEFAULT_DEBUG_CHANNEL(wineboot);
 
 #define MAX_LINE_LENGTH (2*MAX_PATH+2)
@@ -616,6 +624,214 @@ static int ProcessWindowsFileProtection(
     return 1;
 }
 
+/* A dialog box handler for the run confirmation dialog box. */
+static INT_PTR rcd_Setup(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    HWND hWndDesktop;
+    RECT rcDesktop, rc;
+    LPCWSTR wProgram;
+
+    switch(uMsg)
+    {
+	case WM_INITDIALOG:
+              /* Center the dialog box */
+	      hWndDesktop = GetDesktopWindow();
+	      GetWindowRect(hWndDesktop, &rcDesktop);
+	      GetWindowRect(hWnd, &rc);
+	      SetWindowPos(hWnd, HWND_TOP, (rcDesktop.right/2)-((rc.right-rc.left)/2), 
+                                           (rcDesktop.bottom/2)-((rc.bottom-rc.top)/2), 
+			   0, 0, SWP_NOSIZE);
+
+	      /* Set the program name. */
+	      wProgram = (LPCWSTR)lParam;
+	      SetDlgItemTextW(hWnd, ID_PROGRAM, wProgram);
+	      return TRUE; 
+
+	case WM_COMMAND:
+	      if (wParam == ID_ALWAYS || wParam == IDYES || wParam == IDNO || wParam == ID_NEVER)
+	         EndDialog(hWnd, wParam);
+	      return TRUE;
+  
+	default:
+	      return FALSE; /* since I don't process this particular message */
+    }
+}
+
+/* Process items in the StartUp group of the user's Programs under the Start Menu. Some installers put
+ * shell links here to restart themselves after boot. User input is solicited to prevent malware by
+ * default. The following registry keys are used:
+ *
+ *     HKEY_CURRENT_USER\Software\Wine\StartupItems - if set to "always" always runs, otherwise asks user 
+ *                                                    (determines run behavior for all items)
+ *     HKEY_CURRENT_USER\Software\Wine\StartupItems\FullPathOfFile - set to always or never
+ *                                                                   (determines run behavior for item) 
+ * */
+static BOOL ProcessStartupItems()
+{
+    static const WCHAR AlwaysW[] = { 'a','l','w','a','y','s',0 };
+    static const WCHAR NeverW[] = { 'n','e','v','e','r',0 }; 
+    static const WCHAR StartupItemsW[] = { 'S','o','f','t','w','a','r','e','\\',
+				     'W','i','n','e','\\',
+				     'S','t','a','r','t','u','p','I','t','e','m','s',0 };
+
+    BOOL ret = FALSE;
+    HRESULT hr;
+    int iRet;
+    IMalloc *ppM = NULL;
+    IShellFolder *psfDesktop = NULL, *psfStartup = NULL;
+    LPITEMIDLIST pidlStartup = NULL, pidlItem;
+    ULONG NumPIDLs;
+    IEnumIDList *iEnumList = NULL;
+    STRRET strret;
+    WCHAR wszCommand[MAX_PATH], wszBuffer[MAX_PATH];
+    HINSTANCE hInst = GetModuleHandle(NULL);  
+    DWORD res, bufLength;
+    HKEY hKeyStartupItems = NULL;
+    BOOL bAskUser = TRUE;      /* Change this default value to change the default behavior */
+
+    WINE_TRACE("Processing items in the StartUp folder.\n");
+
+    /* Get the startup items registry key and record our default ask behavior */
+    RegOpenKeyExW( HKEY_CURRENT_USER, StartupItemsW, 0, KEY_ALL_ACCESS, &hKeyStartupItems );
+    bufLength = MAX_PATH;
+    res = RegQueryValueExW(hKeyStartupItems, NULL, NULL, NULL, (LPBYTE)wszBuffer, &bufLength);
+    if (res == ERROR_SUCCESS) {
+	if (!StrCmpW(wszBuffer, AlwaysW)) bAskUser = FALSE; /* Always run means never ask */
+	else if (!StrCmpW(wszBuffer, NeverW)) bAskUser = TRUE; /* Never ask means always run */
+	else
+	  WINE_ERR("Startup Item Ask Behavior has undefined value %s.\n", wine_dbgstr_w(wszBuffer));
+    }
+
+    hr = SHGetMalloc(&ppM);
+    if (FAILED(hr)) 
+    {
+	WINE_ERR("Couldn't get IMalloc object.\n");
+	goto done;
+    }
+
+    hr = SHGetDesktopFolder(&psfDesktop);
+    if (FAILED(hr))
+    {
+	WINE_ERR("Couldn't get desktop folder.\n");
+	goto done;
+    }
+
+    hr = SHGetSpecialFolderLocation(NULL, CSIDL_STARTUP, &pidlStartup);
+    if (FAILED(hr))
+    {
+	WINE_TRACE("Couldn't get StartUp folder location.\n");
+	goto done;
+    }
+  
+    hr = IShellFolder_BindToObject(psfDesktop, pidlStartup, NULL, &IID_IShellFolder, (LPVOID*)&psfStartup);
+    if (FAILED(hr))
+    {
+	WINE_TRACE("Couldn't bind IShellFolder to StartUp folder.\n");
+	goto done;
+    }
+
+    hr = IShellFolder_EnumObjects(psfStartup, NULL, SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
+    if (FAILED(hr))
+    {
+	WINE_TRACE("Unable to enumerate StartUp objects.\n");
+	goto done;
+    }
+
+    while (IEnumIDList_Next(iEnumList, 1, &pidlItem, &NumPIDLs) == S_OK && 
+	   (NumPIDLs) == 1) 
+    {
+	hr = IShellFolder_GetDisplayNameOf(psfStartup, pidlItem, SHGDN_FORPARSING, &strret);
+	if (FAILED(hr)) 
+	    WINE_TRACE("Unable to get display name of enumeration item.\n");
+	else 
+	{
+	    hr = StrRetToBufW(&strret, pidlItem, wszCommand, MAX_PATH);
+	    if (FAILED(hr))
+		WINE_TRACE("Unable to parse display name.\n");
+	    else {
+		/* Set the default value based on our ask behavior */
+		if (bAskUser)
+		  iRet = IDNO;
+		else
+		  iRet = IDYES;
+  
+		/* If the current behavior is not to start, check the registry for the default behavior for 
+		 * this item. */
+	 	if (iRet == IDNO && hKeyStartupItems) {
+		    bufLength = MAX_PATH;
+		    res = RegQueryValueExW(hKeyStartupItems, wszCommand, NULL, NULL, (LPBYTE)wszBuffer, &bufLength);
+		    if (res == ERROR_SUCCESS) {
+			/* Two possibilities here, always or never */
+			if (!StrCmpW(wszBuffer, AlwaysW)) iRet = ID_ALWAYS;
+			else if (!StrCmpW(wszBuffer, NeverW)) iRet = ID_NEVER;
+			else 
+			    WINE_ERR("StartupItem %s has undefined registry action %s.\n", wine_dbgstr_w(wszCommand), wine_dbgstr_w(wszBuffer));
+		    }
+		}
+
+		/* If our behavior is still no, ask the user */
+		if (iRet == IDNO)
+		    iRet = DialogBoxParam(hInst, "Run_Confirmation_Dialog", NULL, (DLGPROC)rcd_Setup, (LPARAM)wszCommand);
+
+		/* Now do what we determined either from the registry or from the user */
+	        switch (iRet) {
+		    case ID_ALWAYS:
+		      /* Set the appropriate registry key */
+		      if (!hKeyStartupItems &&
+			  (res = RegCreateKeyExW(HKEY_CURRENT_USER, StartupItemsW, 0, NULL, 
+						 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, 
+						 &hKeyStartupItems, NULL)) != ERROR_SUCCESS) 
+			  WINE_ERR("Error %d creating registry key %s.\n", res, wine_dbgstr_w(StartupItemsW));
+		      else if ((res = RegSetValueExW(hKeyStartupItems, wszCommand, 0, REG_SZ, 
+						     (LPBYTE) AlwaysW, 
+						     (lstrlenW(AlwaysW)+1)*sizeof(WCHAR))) != ERROR_SUCCESS)
+			  WINE_ERR("Error %d setting registry key %s value to %s.\n", res,
+				   wine_dbgstr_w(wszCommand), wine_dbgstr_w(AlwaysW));
+			 
+		      /* Go from always to running the command, no break needed here. */
+
+		    case IDYES:
+		      if ((iRet = (int)ShellExecuteW(NULL, NULL, wszCommand, NULL, NULL, SW_SHOWNORMAL)) <= 32)
+			WINE_ERR("Error %d executing command %s.\n", iRet, wine_dbgstr_w(wszCommand));
+		      break;
+
+		    case IDNO: /* don't run, but leave file intact. */
+		      break;
+
+		    case ID_NEVER: /* don't run, set registry key. */
+		      if (!hKeyStartupItems &&
+			  (res = RegCreateKeyExW(HKEY_CURRENT_USER, StartupItemsW, 0, NULL, 
+						 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, 
+						 &hKeyStartupItems, NULL)) != ERROR_SUCCESS) 
+			  WINE_ERR("Error %d creating registry key %s.\n", res, wine_dbgstr_w(StartupItemsW));
+		      else if ((res = RegSetValueExW(hKeyStartupItems, wszCommand, 0, REG_SZ, 
+						    (LPBYTE) NeverW, 
+						    (lstrlenW(NeverW)+1)*sizeof(WCHAR))) != ERROR_SUCCESS)
+			  WINE_ERR("Error %d setting registry key %s value to %s.\n", res,
+				   wine_dbgstr_w(wszCommand), wine_dbgstr_w(NeverW));
+		      break;
+
+		    default: /* Unknown return value */
+		      WINE_ERR("DialogBoxParam returned an unknown value %d.\n", iRet);
+		}
+	    }
+	}
+
+	IMalloc_Free(ppM, pidlItem);
+    }
+
+    /* Return success */
+    ret = TRUE;
+  
+done:
+    if (iEnumList) IEnumIDList_Release(iEnumList);
+    if (psfStartup) IShellFolder_Release(psfStartup);
+    if (pidlStartup) IMalloc_Free(ppM, pidlStartup); 
+    if (hKeyStartupItems) RegCloseKey(hKeyStartupItems);
+
+    return ret;
+}
+
 static void usage(void)
 {
     WINE_MESSAGE( "Usage: wineboot [options]\n" );
@@ -732,7 +948,9 @@ int main( int argc, char *argv[] )
                 FALSE, FALSE )) &&
         (!ops.postlogin || !ops.startup ||
          ProcessRunKeys( HKEY_CURRENT_USER, runkeys_names[RUNKEY_RUN],
-                FALSE, FALSE ));
+                FALSE, FALSE )) &&
+	(!ops.postlogin || !ops.startup ||
+	 ProcessStartupItems( ));
 
     WINE_TRACE("Operation done\n");
 
diff --git a/programs/wineboot/wineboot.h b/programs/wineboot/wineboot.h
new file mode 100644
index 0000000..5c838b4
--- /dev/null
+++ b/programs/wineboot/wineboot.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2007 Misha Koshelev.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define ID_PROGRAM           997
+#define ID_ALWAYS            998
+#define ID_NEVER             999
diff --git a/programs/wineboot/wineboot.rc b/programs/wineboot/wineboot.rc
new file mode 100644
index 0000000..0abd583
--- /dev/null
+++ b/programs/wineboot/wineboot.rc
@@ -0,0 +1,26 @@
+/*
+ * WINEBOOT.RC
+ *
+ * Copyright (c) 2007 Misha Koshelev.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <windows.h>
+#include "wineboot.h"
+
+#include "En.rc"
+
+LANGUAGE LANG_NEUTRAL,SUBLANG_NEUTRAL
-- 
1.4.1



More information about the wine-patches mailing list