From 47a35d8e5296a094b14b03d01ab001f90a60b50e Mon Sep 17 00:00:00 2001 From: Misha Koshelev Date: Sun, 11 Feb 2007 15:19:46 -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 | 201 +++++++++++++++++++++++++++++++++++++++++ programs/wineboot/wineboot.h | 21 ++++ programs/wineboot/wineboot.rc | 26 +++++ 5 files changed, 286 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..d4095aa 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 #include +#define COBJMACROS +#include +#include +#include +#include + +#include "wineboot.h" + WINE_DEFAULT_DEBUG_CHANNEL(wineboot); #define MAX_LINE_LENGTH (2*MAX_PATH+2) @@ -616,6 +624,193 @@ 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. */ +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; + + WINE_TRACE("Processing items in the StartUp folder.\n"); + + RegOpenKeyExW( HKEY_CURRENT_USER, StartupItemsW, 0, KEY_ALL_ACCESS, &hKeyStartupItems ); + + 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 { + /* Our default behavior is not to run */ + iRet = IDNO; + + /* Check the registry to see if a default behavior was previously selected for this item */ + if (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 did not find a key (our behavior is still not to run), 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, 0)) <= 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 +927,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 +#include "wineboot.h" + +#include "En.rc" + +LANGUAGE LANG_NEUTRAL,SUBLANG_NEUTRAL -- 1.4.1