tags:

views:

86

answers:

2

I have a Windows service built with ATL to expose a LocalServer32 COM interface for a set of admin commands used for configuring the service, and these can be used from VBScript for example:

Set myObj = WScript.CreateObject("MySvc.Administrator")
myObj.DoSomething()

I want DoSomething to run elevated, and I would like the UAC prompt to come up automatically when this is called by the VBScript. Is this possible?

I know I can run the script in an elevated command shell, and that I can use

objShell.ShellExecute WScript.FullName, Chr(34) & WScript.ScriptFullName & Chr(34), vbNullString, "runas"

for example, to run the VBScript itself elevated, and either of those work fine -- the COM method finds itself elevated.

However, AFAIK getting an elevated Explorer window on the desktop is convoluted (it's not as simple as right-clicking Start/Accessories/Windows Explorer/Run as Administrator, which doesn't actually elevate, or at least, the COM method doesn't find itself elevated.) I want a user in the local admin group to be able to drag-and-drop files and folders onto the script, and then have the script call the admin COM interface with those pathnames as arguments, and the COM method to be elevated. (And I am hoping for something simpler than monkeying around with the args and using ShellExecute "runas".)

I've tried setting UAC Execution Level to requireAdministrator in the service EXE's manifest, and setting Elevated/Enabled = 1 and LocalizedString in the registry for the MySvc.Administrator class, and these don't do the trick.

EDIT:

When I wrote that the COM method finds itself elevated, what I really meant was the security token of the incoming COM request shows that it came from an admin. I'm checking this token to see if the request is allowed. The Windows service process where the COM object lives is probably running as LocalSystem.

A: 

VBScripts are hosted by a scripting hosting process so the script "inherits" the security context of the windows scripting host. If the hosting process is elevated than the script has elevated rights. There is no way a single interface or single method call to be elevated outside the security context of the hosting process.

Another thing to notice is that when a non-elevated process spawns an elevated process UAC always shows confirmation. So when a non-elevated explorer does a "runas" on a script, user has to confirm. When a non-elevated script does a "runas" on itself, user has to confirm too.

wqw
Then an *existing* process cannot be elevated, but rather, only a *new* process can be started elevated? If that's the case, then it makes sense.
Jim Flood
By using the COM Elevation Moniker in a GetObject call from the vbscript, you can get the COM object instantiated in an elevated process, without elevating the script process, which is what I wanted -- just the DoSomething needs to be elevated, and not the script.
Jim Flood
Not bad! I was totally unaware of this moniker. Being out-of-proc the COM server is a separate elevated process, so at least I was misleading you :-))
wqw
A: 

To answer my own question, yes, is it possible to cause the UAC dialog to come up on-the-fly from a vbscript that is accessing my service's automation interface.

What I have is a class in the Windows service that exposes an admin interface for vbscripts to access. That interface verifies that you have privileges to modify the service before allowing you to do that. What happens on Vista and Server 2008 is that unless you are already in an elevated process (using the admin security token), you are running with the limited security token, and so the service interface refuses to let you do anything.

To get the UAC dialog to come up and elevated something along the way to the service, I created a new COM server (EXE) which puts up the exact same administrator interface in a class, and makes itself available to vbscript through automation. When you ask that COM object to do something, it just turns to the service, creates an instance of the service COM object and asks it the exact same thing, acting as a proxy to forward on the request.

This new COM server is annotated in the registry to enable elevation using the COM Elevation Moniker msdn link.

Then, in a vbscript, instead of CreateObject() you can call GetObject("Elevation:Administrator!new:). At this point, when you create the COM object, the UAC dialog comes up and that object is started in an elevated process, and voila, I get what I wanted: when you need to access the administrator interface, the UAC dialog comes up with display string (and optionally an icon) of your choice, and the call into the service shows administrator privileges.

And I should mention, to retain the administrator privileges from the elevated COM object as it in turn calls into the Windows service COM object, I call SetBlanket to use cloaking on the chained call. I found excellent info on that here: Client-Side Security Programming.

Jim Flood