Pierre
Pierre

Reputation: 4406

Does changing a Registry Key from Standard User require launching a process?

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.

Upvotes: 0

Views: 144

Answers (2)

Pierre
Pierre

Reputation: 4406

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).

Upvotes: 0

Anders
Anders

Reputation: 101746

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.

Upvotes: 2

Related Questions