using CreateProcessAsUser to launch a url - c#

Recently I bumped into an issue where I need to open a webpage from an elevated application. I need the browser to be opened non elevated so I looked around and found this solution
This would definitely solve my issue except that CreateProcessAsUser does not accept URIs as a filename, the execution will fail with the error message being "The filename, directory name, or volume label syntax is incorrect"
Can someone tell me if there is a way to launch a website through CreateProcessAsUser or if there is a similar API that does the job.. Please note that my actual application is always elevated and thus I cannot uses the usual Process.Start(), CreateProcess() or ShellExecute()

There are two distinct families of functions that you will need to use to get this task done:
CreateProcess and related functions. These can be used to start a new process. You must supply a filename of an executable image.
ShellExecute and friends. These will apply verbs to files using the shell's rules for associating file classes to executables.
In order to open a URI you need to use one of the ShellExecute family. And in order to execute as a standard user from your elevated process, you need to use one of the CreateProcess family.
You cannot meet both your requirements with a single function. Your solution therefore is to use one of the CreateProcessXXX functions to create a process that runs as standard user. That process in turn will call ShellExecuteXXX. You will pass the URI as command line arguments to CreateProcessXXX.
You will therefore need to either create a distinct executable as your standard user launcher. Or re-use your existing executable but make it switch into launcher mode depending on the arguments that you pass it.

Related

Open file with associated application and with specific user in C#

I need to open files of different types with their associated application. It works fine like this:
System.Diagnostics.Process.Start(#"C:\foo.jpg");
But when I need to open it with a specific user, I need to supply an executable, I can't open a document/image etc. ("The specified executable is not a valid application for this OS platform") Is there a smart workaround or would I need to get the associated application's data from registry and run the application with the document/image as argument? (So the question is not about how to run Process.Start() with arguments!)

Why does WScript work when I run my script from the desktop, but not when run as part of Setup.exe?

I've been working on this issue for about 6 hours now and feel like I'm getting nowhere. I have a vbscript to write to the windows registry that I want to use during the installation of a .net Visual Studio program. It writes to the Local Machine part of the registry, so permissions have to be edited to accomplish that. The code in question is as follows:
If Not WScript.Arguments.Named.Exists("elevate") Then
CreateObject("Shell.Application").ShellExecute WScript.FullName _
, WScript.ScriptFullName & " /elevate", "", "runas", 1
WScript.Quit
End If
The code works perfectly when I just run the script from my desktop, and does exactly what I need it to do. But when I run the setup.exe that includes the script (even if I run setup.exe from my desktop), I get an Object Required error from the WScript code above. I need to know either 1) why I am getting this error and how to allow access to the WScript object, or if that is impossible 2) how to give my script the proper admin privileges required to write to the Local Machine Registry without using WScript.
If you are running this script as a VBScript custom action, then Windows Installer uses a custom VB script host. Unlike wscript.exe and cscript.exe, this host does not provide the WScript object, so any references to it will fail. You could choose to launch it as an EXE action via wscript.exe instead. I would not recommend this, at least not without reading my third paragraph.
Also, as a general recommendation, you should avoid elevating within a custom action, as doing so leads to the potential of multiple UAC prompts during a single installation. So to write to per-machine areas of the registry you should prefer using the Registry view, and thus entries in the Registry table. If you need custom values, note that you can specify property references in the view/table, and they will be evaluated when writing the values.
If you absolutely need to write to the registry through a custom action, consider carefully the rollback scenarios, and prefer to use an action that is "deferred in system context," as this kind of custom action will have access to administrative privileges if the installation is per-machine. Note that deferred custom actions do not have access to most properties.

Execute several elevated commands in shell (or similar)

I have a requirement to execute several commands with elevated rights, something like:
call program that modifies a .config file of a service (needs admin rights)
net stop myservice (needs admin rights)
net start myservice (needs admin rights)
All of this dynamic, e. g. the first line could contain proxy settings, including user name and password, or any other modification to the settings file. (Settings file is in program folder, program to modify the settings file is externally provided. The actual info would be user entered through a GUI.)
I thought to create a very flexible solution, using a cmd.exe process with redirected stdin and stdout. But.. it looks like "runas" (needs ShellExecute) and redirected in-/output are exclusive.
(Also, I noticed that redirection and cmd.exe are quite hard to handle.. I had to write my own functions e. g. as a replacement for ReadLine, since the ReadLine expects a NewLine at the end and waits e. g. if there is a command prompt (meaning you have text in the line like c:\bla> but no NewLine. Still, not knowing what one gets as a result makes writing something generic difficult.)
There are 3 alternatives I can think of:
get the UAC prompt for every single command (I would not like that)
start a process that is elevated, this can then call whatever it wants -> needs an additional project (.exe) which I would like to avoid, also makes deployment more difficult (additional file)
create a batch file on the fly, run it elevated. This I also want to avoid, since there could be password information in plain text in that file (e. g. user/password for proxy). I would at least have to make sure to always overwrite its contents and then delete it.
How to handle this?
I think you've already diagnosed the issue, and enumerated your available options. To my mind the best option is to use runas to create a new elevated process, and get that process to do the work.
The other process need not be a different executable it could be your existing executable started with particular command line arguments. Once you have another process running elevated, you can certainly use cmd with redirected stdin/stdout to do the work. However, why use net stop/start rather than the service API? And can you do the .config file modification without starting a separate process?

Detect when exe launched via Google Chrome Native Message Passing

I'm trying to retrofit an existing NPAPI plugin to use Google's native message passing technology. Since it's an existing exe, we already have some console behavior programmed in so that users can call our program from the terminal. Is there any way for us to detect, in a C# application, that the exe has been launched by Google Chrome for message passing? If we could do that, we could launch the message passing loop if we're called from Chrome but resume normal behavior if called from Powershell/cmd.
I've tried inspecting the command line arguments passed to the program when launched by Chrome, but there are none. Having a configurable option there would solve this for us, but as far as I can tell it's not possible. I haven't yet had a chance to inspect the current working directory in case it could also be used as an identifier.
Actually, yes, I believe it is possible.
When, for example, a C# console application is started as a native message client host, it is passed two arguments:
--parent-window=<number>
and
chrome-extension://<extension identifier>/
I think the second argument is probably the ideal one for determining that not only was it Chrome that launched the process, but that the specific extension you authored and intended to call it launched it!
Please make note in the above, the "<" and ">" are not literally part of the argument, and just used to denote the beginning and end of that part of the message, much like double quotes.
Alternatively, just have your extension invoke a script (.bat, .sh, etc.) that passes special arguments to your native host. This way you could pass specific arguments of your own.
The API doesn't support passing command line arguments, but your host process should be able to inspect its own parent process to determine if it was launched by Chrome or something else.
An alternative to checking the arguments as suggested by #aikeru would be to check for the existence of certain environment variables that were passed from Chrome to the native messaging host. My host has the following variables that seem to be specific to Chrome (found with Sysinternals Process Monitor):
CHROME_ALLOCATOR=TCMALLOC
CHROME_BREAKPAD_PIPE_NAME=\\.\pipe\GoogleCrashServices\S-1-5-18
CHROME_MAIN_TIME=13037817851797830
CHROME_METRO_DLL=0
CHROME_PRE_READ_EXPERIMENT=100-pct-default
CHROME_RESTART=Google Chrome|Whoa! Google Chrome has crashed. Relaunch now?|LEFT_TO_RIGHT
CHROME_VERSION=33.0.1750.117

Find out whether an application needs administrator privileges

Windows 7 uses an automatic mechanism to detect whether an application needs elevated administrator privileges. Or the application itself has a manifest.
Is there a way to find out programmatically whether a specified application needs elevated administrator privileges or not?
I don't want to start it to find it out.
Thank you ;).
There's really just one way to tell Windows that a program needs to be elevated and that's through the manifest file. Manifest files can either be embedded within an assembly (exe/dll) or can live in a separate file named <YOUR_APP>.exe.manifest. That's really the only way and probably the only way that you can safely check. Officially.
Windows also contains a giant database that's used for application compatibility. If Microsoft has tested an app and found that it breaks when an OS upgrade happens they sometimes creates an entry in the database to essentially hack the app. Sometimes they lie about the current OS version, sometimes they automatically run as administrator, sometimes they do a bunch of other things. You can view the database using the Application Compatibility Toolkit. I don't know if there's an official way to query the database via code. This blog post talks about a tool that the blogger made but apparently never release.
The last automatic elevation mechanism is algorithm that tries to determine if that app is an installer. According to MSDN these attributes are checked:
Filename includes keywords like "install," "setup," "update," etc.
Keywords in the following Versioning Resource fields: Vendor, Company Name, Product Name, File Description, Original Filename,
Internal Name, and Export Name.
Keywords in the side-by-side manifest embedded in the executable.
Keywords in specific StringTable entries linked in the executable.
Key attributes in the RC data linked in the executable.
Targeted sequences of bytes within the executable.
The keywords and sequences of bytes were derived from common
characteristics observed from various installer technologies.
Lastly, an app can run as a normal user but spawn a child process that requires elevated privileges. I don't know if there's really any way to actually detect that short of decompiling the app itself.

Categories