0

My app runs as Standard User. Occasionally I need to create a Registry Key that requires Admin access. I would like to prompt the user for Admin permission.

If I do something along these lines:

GetNamedSecurityInfo
AllocateAndInitializeSid
SetEntriesInAcl
SetNamedSecurityInfo (or RegSetKeySecurity)

should this cause Windows to automatically pop up a dialog prompting the user for authorization?

Do I instead have to launch a process just to get access to the Registry? In which case, how do I prompt the user to obtain Admin rights for the process?

I prefer not to use CredUIPromptForCredentials because I don't want to see the user's password.

I've read through the Access Control documentation, can't seem to see the forest for the trees.

Pierre
  • 4,114
  • 2
  • 34
  • 39

2 Answers2

2

Windows will not display the UAC dialog just because you called some API that requires elevation to perform its task, the API will simply fail with ERROR_ACCESS_DENIED.

You basically have three options:

  1. Implement a elevated COM object.
  2. ShellExecute yourself with the RunAs verb and a command line parameter so you can detect that you are in this mode.
  3. Create a NT service that you can start on demand and communicate with over a named pipe. I don't recommend this approach.
Anders
  • 97,548
  • 12
  • 110
  • 164
  • Thank you @Anders! That clears up a major hurdle. Very helpful. The COM approach looks feasible, except that it will prompt the user for every privileged operation, which could be burdensome. I've looked at ShellExecuteEx, can't see where to request Admin-level in the SHELLEXECUTEINFO structure. Would that have to be in a manifest? – Pierre May 16 '17 at 13:40
  • Set the verb string in `SHELLEXECUTEINFO` to `"RunAs"`. – Anders May 16 '17 at 13:54
  • Excellent. I have also found confirmation in the following posts: http://stackoverflow.com/questions/11586139/how-to-run-application-which-requires-admin-rights-from-one-that-doesnt-have-th, http://stackoverflow.com/questions/8915744/is-it-possible-for-the-executable-to-ask-for-administrator-rights-windows-7. Houston, we have a solution. – Pierre May 16 '17 at 14:42
0

Here's what I have come up with, thanks to @Anders' excellent advice:

// launch separate process for elevation to Admin
void launchAsAdmin(void)
{   SHELLEXECUTEINFO shelinfo;
    char *err = NULL;
    DWORD exitCode;

    memset(&shelinfo, 0, sizeof(shelinfo));
    shelinfo.cbSize = sizeof(shelinfo);
    shelinfo.hwnd = NULL;
    shelinfo.fMask = SEE_MASK_NOCLOSEPROCESS;
    shelinfo.lpVerb = "RunAs";
    shelinfo.lpFile = "notepad.exe";
    shelinfo.lpParameters = "C:\\Windows\\System32\\drivers\\etc\\hosts";
    shelinfo.nShow = SW_SHOW;

    ShellExecuteEx(&shelinfo);  
    switch((int)shelinfo.hInstApp)
    {   case SE_ERR_FNF:
            err = "File not found"; break;
        case SE_ERR_PNF:
            err = "Path not found"; break;
        case SE_ERR_ACCESSDENIED:
            err = "Access denied"; break;
        case SE_ERR_OOM:
            err = "Out of memory"; break;
        case SE_ERR_DLLNOTFOUND:
            err = "Dynamic-link library not found"; break;
        case SE_ERR_SHARE:
            err = "Cannot share an open file"; break;
        case SE_ERR_ASSOCINCOMPLETE:
            err = "File association information not complete"; break;
        case SE_ERR_DDETIMEOUT:
            err = "DDE operation timed out"; break;
        case SE_ERR_DDEFAIL:
            err = "DDE operation failed"; break;
        case SE_ERR_DDEBUSY:
            err = "DDE operation is busy"; break;
        case SE_ERR_NOASSOC:
            err = "File association not available"; break;
    }
    if((int)shelinfo.hInstApp <= 32)
        return;     // failed
    if(shelinfo.hProcess == 0)
        return;     // nothing to monitor

    // wait until the process has finished
    time_t st = clock();
    do
    {   if(!GetExitCodeProcess(shelinfo.hProcess, &exitCode))
            break;
        if(clock() - st > CLOCKS_PER_SEC * 5)       // max 5 seconds - give up
            break;
    } while(exitCode != STATUS_WAIT_0); // STILL_ACTIVE
    CloseHandle(shelinfo.hProcess);
}

This works. If I am Standard User and I run a program that calls this function, I am prompted for Admin login ID & password, and allowed to change and save the "HOSTS" system file. (Normally this file is off-limits to a Standard User).

Pierre
  • 4,114
  • 2
  • 34
  • 39