From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 30479 invoked by alias); 6 Nov 2013 23:52:17 -0000 Mailing-List: contact cygwin-apps-help@cygwin.com; run by ezmlm Precedence: bulk Sender: cygwin-apps-owner@cygwin.com List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Mail-Followup-To: cygwin-apps@cygwin.com Received: (qmail 30466 invoked by uid 89); 6 Nov 2013 23:52:16 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=1.0 required=5.0 tests=AWL,BAYES_50,FROM_12LTRDOM,RDNS_NONE,URIBL_BLOCKED autolearn=no version=3.3.2 X-HELO: mail104.syd.optusnet.com.au Received: from Unknown (HELO mail104.syd.optusnet.com.au) (211.29.132.246) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 06 Nov 2013 23:52:15 +0000 Received: from [0.0.0.0] (c122-106-16-37.rivrw1.nsw.optusnet.com.au [122.106.16.37]) by mail104.syd.optusnet.com.au (Postfix) with ESMTP id 823CA424516 for ; Thu, 7 Nov 2013 10:52:03 +1100 (EST) Message-ID: <527AD620.2020902@shaddybaddah.name> Date: Wed, 06 Nov 2013 23:52:00 -0000 From: Shaddy Baddah User-Agent: Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20130922 Icedove/17.0.9 MIME-Version: 1.0 To: cygwin-apps@cygwin.com Subject: [PATCH] setup: allow running as non-admin Content-Type: multipart/mixed; boundary="------------070807040909060900030501" X-Optus-CM-Score: 0 X-Optus-CM-Analysis: v=2.1 cv=DstvpgP+ c=1 sm=1 tr=0 a=RkPObcNqpdaXDoCDBSw5Xw==:117 a=RkPObcNqpdaXDoCDBSw5Xw==:17 a=PO7r1zJSAAAA:8 a=cm-COJMw1PoA:10 a=wd1Q20-SIcQA:10 a=Ka6jRcsEzXcA:10 a=r77TgQKjGQsHNAKrUKIA:9 a=9iDbn-4jx3cA:10 a=cKsnjEOsciEA:10 a=OdUXT2KJUB638fika6QA:9 a=wPNLvfGTeEIA:10 a=hNQj6bWjt8UA:10 a=JWyYdkh5-2YA:10 a=48D0-LxZqNpJMkXUleMA:9 X-IsSubscribed: yes X-SW-Source: 2013-11/txt/msg00019.txt.bz2 This is a multi-part message in MIME format. --------------070807040909060900030501 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 128 Hi, As discussed, please find the patch to allow setup to be run as a non-admin user include clear text. -- Regards, Shaddy --------------070807040909060900030501 Content-Type: text/x-patch; name="setup-sans-admin-november-02-bare.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="setup-sans-admin-november-02-bare.patch" Content-length: 7254 2013-11-06 Shaddy Baddah * LogFile.cc (LogFile::flushAll): New function to flush log all logging to files without exiting (as LogFile::exit does). * LogFile.h: Declare new method closeAll. * main.cc (NoAdminOption): Add new CLI options -B/--no-admin. This option allows the user to suppress privilege elevation (in tandem with "asInvoker" requestedExecutionLevel changes to exe manifests). (WinMain): check if setup run with Administrator privilege and if the NoAdminOption has not been specified, attempt to elevate privilege to an Administrator via WINAPI ShellExecuteEx(). * setup.exe.manifest: Add requestedExecutionLevel of asInvoker to allow suppression of privilege elevation. * setup64.exe.manifest: Modify requestedExecutionLevel from requireAdministrator to asInvoker to allow suppression of privilege elevation. Continuity of privilege elevation attempt on startup is implemented by main.cc changes to WinMain(). * win32.cc (NTSecurity::isRunAsAdmin): New function to allow main.cc to check if setup.exe has been run with privilege elevated to Administrator level. * win32.h: Declare new method isRunAsAdmin. diff --git a/LogFile.cc b/LogFile.cc index 53c6ed7..ff8e260 100644 --- a/LogFile.cc +++ b/LogFile.cc @@ -149,6 +149,18 @@ LogFile::exit (int const exit_code) } void +LogFile::flushAll () +{ + log (LOG_TIMESTAMP) << "Writing messages to log files without exiting" << endLog; + + for (FileSet::iterator i = files.begin(); + i != files.end(); ++i) + { + log_save (i->level, i->key, i->append); + } +} + +void LogFile::log_save (int babble, const std::string& filename, bool append) { static int been_here = 0; diff --git a/LogFile.h b/LogFile.h index 912d2c5..3bed1d6 100644 --- a/LogFile.h +++ b/LogFile.h @@ -32,6 +32,7 @@ public: * but doesn't call generic C++ destructors */ virtual void exit (int const exit_code) __attribute__ ((noreturn)); + virtual void flushAll (); virtual ~LogFile(); // get a specific verbosity stream. virtual std::ostream &operator() (enum log_level level); diff --git a/main.cc b/main.cc index d4c6828..2be633e 100644 --- a/main.cc +++ b/main.cc @@ -35,6 +35,7 @@ static const char *cvsid = #define _WIN32_WINNT 0x0501 #include "win32.h" #include +#include #include "shlobj.h" #include @@ -93,6 +94,7 @@ HINSTANCE hinstance; static StringOption Arch ("", 'a', "arch", "architecture to install (x86_64 or x86)", false); static BoolOption UnattendedOption (false, 'q', "quiet-mode", "Unattended setup mode"); static BoolOption PackageManagerOption (false, 'M', "package-manager", "Semi-attended chooser-only mode"); +static BoolOption NoAdminOption (false, 'B', "no-admin", "Do not check for and enforce running as Administrator"); static BoolOption HelpOption (false, 'h', "help", "print help"); static BOOL WINAPI (*dyn_AttachConsole) (DWORD); static BOOL WINAPI (*dyn_GetLongPathName) (LPCTSTR, LPTSTR, DWORD); @@ -289,6 +291,57 @@ WinMain (HINSTANCE h, << "\nCommand Line Options:\n"); else { + OSVERSIONINFO version; + version.dwOSVersionInfoSize = sizeof version; + GetVersionEx (&version); + if ((version.dwMajorVersion >= 6) + && !NoAdminOption && !nt_sec.isRunAsAdmin ()) + { + log (LOG_PLAIN) << "Attempting to elevate to Administrator" << endLog; + char exe_path[MAX_PATH]; + if (!GetModuleFileName(NULL, exe_path, ARRAYSIZE(exe_path))) + { + log (LOG_TIMESTAMP) << "GetModuleFileName() failed: " << GetLastError () << endLog; + goto finish_up; + } + + SHELLEXECUTEINFO sei = { sizeof(sei) }; + sei.lpVerb = "runas"; + sei.lpFile = exe_path; + sei.nShow = SW_NORMAL; + + // Note, this is necessary to avoid an infinite loop. + // The understanding is that pre-Vista, the runas verb will not + // result in a privilege elevated process. Therefore we need to + // indicate to the forked process that it should be happy with + // whatever privileges it is run with. + std::string command_line_cs (command_line); + command_line_cs += " -"; + command_line_cs += NoAdminOption.shortOption(); + sei.lpParameters = command_line_cs.c_str (); + + // avoid the ambiguity of having both the parent and child + // process logging simultaneously, by ending it here. perhaps + // overkill, but safe. + theLog->flushAll (); + theLog->clearFiles (); + + if (!ShellExecuteEx(&sei)) + { + // Note: if user declined, we get an ERROR_CANCELLED. + // Merely to be compatible with existing Cygwin Setup + // behaviour. we do nothing with it but just exit. + // Future improvement is possible here. + + // TODO: because we have been prudent and closed off the + // logging, we can't actually log in this way. Though it + // would be helpful +// log (LOG_TIMESTAMP) << "ShellExecuteEx() failed: " << GetLastError () << endLog; + } + // once we are set on a course to privilege elevate, the parent + // process is unnecessary + goto finish_up; + } UserSettings Settings (local_dir); main_display (); @@ -296,6 +349,7 @@ WinMain (HINSTANCE h, Settings.save (); // Clean exit.. save user options. } +finish_up: if (rebootneeded) { theLog->exit (IDS_REBOOT_REQUIRED); diff --git a/setup.exe.manifest b/setup.exe.manifest index c195ebc..394f19f 100755 --- a/setup.exe.manifest +++ b/setup.exe.manifest @@ -19,6 +19,13 @@ /> + + + + + + + diff --git a/setup64.exe.manifest b/setup64.exe.manifest index 61c5241..f0bf282 100755 --- a/setup64.exe.manifest +++ b/setup64.exe.manifest @@ -22,7 +22,7 @@ - + diff --git a/win32.cc b/win32.cc index 31a923d..11e323d 100644 --- a/win32.cc +++ b/win32.cc @@ -400,6 +400,18 @@ NTSecurity::setDefaultSecurity () setAdminGroup (); } +bool +NTSecurity::isRunAsAdmin () +{ + BOOL is_run_as_admin = FALSE; + if (!CheckTokenMembership(NULL, administratorsSID.theSID (), &is_run_as_admin)) + { + NoteFailedAPI("CheckTokenMembership(administratorsSID)"); + } + return (is_run_as_admin == TRUE); +} + + VersionInfo::VersionInfo () { v.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); diff --git a/win32.h b/win32.h index 7838dcc..91ff184 100644 --- a/win32.h +++ b/win32.h @@ -132,6 +132,7 @@ public: void resetPrimaryGroup(); void setAdminGroup (); void setDefaultSecurity(); + bool isRunAsAdmin (); private: void NoteFailedAPI (const std::string &); bool wellKnownSIDsinitialized () const { return _wellKnownSIDsinitialized; } --------------070807040909060900030501--