How to run application which requires admin rights from one that doesn't have them

Samuel picture Samuel · Jul 20, 2012 · Viewed 39.7k times · Source

I've been stuck on this for a few hours until I've finally managed to do it. There are already links which pointed me the right direction:

But I've thought that simple overview of the problem could help someone :).

Answer

Samuel picture Samuel · Jul 20, 2012

Real problem: (from Wikipedia: http://en.wikipedia.org/wiki/User_Account_Control)

An executable that is marked as "requireAdministrator" in its manifest cannot be started from a non-elevated process using CreateProcess(). Instead, ERROR_ELEVATION_REQUIRED will be returned. ShellExecute() or ShellExecuteEx() must be used instead.

(BTW, ERROR_ELEVATION_REQUIRED error == 740)

Solution: (same site)

In a native Win32 application the same "runas" verb can be added to a ShellExecute() or ShellExecuteEx() call.

ShellExecute(hwnd, "runas", "C:\\Windows\\Notepad.exe", 0, 0, SW_SHOWNORMAL);

This may be also helpful: (source: http://mark.koli.ch/2009/12/uac-prompt-from-java-createprocess-error740-the-requested-operation-requires-elevation.html)

2 - Basic UAC Flow

Ok, so before you dig into it, I thought it might be helpful to explain the basic flow of a UAC aware application and how everything fits together. Normally, your application runs as an unprivileged user. But, sometimes it needs to be an Administrator (to do whatever). So, here's the basic idea, in pseudo code:

int main (int argc, char **argv) {

  HRESULT operation = tryToDoSomethingPrivileged();

  if (operation == ACCESS_DENIED && !alreadyElevated) {

    // Spawn a copy of ourselves, via ShellExecuteEx().
    // The "runas" verb is important because that's what
    // internally triggers Windows to open up a UAC prompt.
    HANDLE child = ShellExecuteEx(argc, argv, "runas");

    if (child) {
      // User accepted UAC prompt (gave permission).
      // The unprivileged parent should wait for
      // the privileged child to finish.
      WaitForSingleObject(child, INFINITE);
      CloseHandle(pid);
    }
    else {
      // User rejected UAC prompt.
      return FAILURE;
    }

    return SUCCESS;

  }  

  return SUCCESS;

}

Finally, this is how I've done it:

if(0 == CreateProcess(argv[2], params, NULL, NULL, false, 0, NULL, NULL, &si, &pi)) {
        //runas word is a hack to require UAC elevation
        ShellExecute(NULL, "runas", argv[2], params, NULL, SW_SHOWNORMAL);
}

And just for completness's sake - MSDN links to ShellExecute and CreateProcess:

http://msdn.microsoft.com/en-us/library/bb762153%28v=vs.85%29.aspx

http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx