Process Start as domain administrator from user started process with UAC activated in domain network

拜拜、爱过 提交于 2020-01-15 03:07:54

问题


I am trying to do something that, now after much banging my head against the screen, am not sure it can be done.

The scenario is as follows:

  • a windows network with a domain controller where the normal users of the PC's don't have administrative privileges.
  • A program that, when it finds an update (MSI) in a share of the network (UNC path), will run the update.
  • Because the user cannot do installations. The update must be run with some other user with admin rights.

The theory is sound but:

  • it only works if the admin user is a local administrator in the given PC. I cannot make it work with a domain administrator that does not have a local account in the PC.

I have tried with:

  • User impersonation with a token from advapi32.dll LogonUser.
  • Process->Start() install providing the Domain administrator user credentials.
  • Process->Start() Advertise with the Domain administrator and then Process->start() install with the normal user.

As mentioned above, if the admin user has a Local account in the PC, it will work. However, if I use a Domain administrator, the PC will prompt a UAC screen asking for valid administrator credentials.

If I check with task manager, the process is started with the given credentials. It just doesn't have the rights to install.

Is it possible to do what I am trying here? If not, any way around?

The problem is that the network is administered from a domain and the PC's do not necessarily have the admin user account locally created.


回答1:


As mentioned above, if the admin user has a Local account in the PC, it will work. However, if I use a Domain administrator, the PC will prompt a UAC screen asking for valid administrator credentials.

What is it you want to happen? In order to impersonate a user, you have to know their password.

The user needs to know the password of the domain administrator either way, so they type it into the Consent dialog, and the install can proceed.

Are you envisioning a system where an application can be run as an administrator without anyone having to enter the domain admin credentials? That is simply not allowed.


Is it possible to do what I am trying here?

i'm not sure what it is you want to have happen here. Which is why i was asking what exactly you want to have happen.

I get the sense that you want to launch a process as an account with Administrative privileges; so this separate process can perform an update. The issue, i gather, is that the logged in user is not an administrator.

I cannot make it work with a domain administrator that does not have a local account in the PC.

What, in particular, are you trying to make work when using a domain administrator? What, precisely do you want to see happen? Are you thinking that that, through code, you can launch an elevated process as a domain user without a UAC prompt appearing? That's not going to happen.

But it is possible

All that being said, what you describe is possible. As Chris Jackson noted in a blog entry the trick is:

  1. Launch a program as the domain administrator using CreateProcessWithLogonW
  2. From that application, use ShellExecute with the runas verb to elevate to an administrator
  3. Perform your updates

I simulated it with a quick Delphi app.

Initially the test app is running as a standard user (named Forest Gump). I detect that he is not an administrator, and show a UAC shield on the Update Software button:

Clicking the button causes the software to launch a copy of itself, but using the credentials of a domain administrator account (me, Ian). This is done using CreateProcessWithLogonW:

if IsUserAdmin then
begin
    //No need for hoops, we're already an admin. Do the update.
    PerformUpdate();
    Exit;
end;

//Relaunch ourselves as a particular domain admin user.
username := 'ian@redacted.com';
password := 'correct battery horse staple';
applicationName := ParamStr(0);
commandLine := applicationName+' /performUpdates';

ZeroMemory(@si, SizeOf(si));
si.cb := SizeOf(si);

CreateProcessWithLogonW(PWideChar(username), nil, PWideChar(password), 0, PWideChar(applicationName), PWideChar(commandLine), 0, nil, nil, si, {var} pi)

The trick is that we pass the /performUpdates option. When our app starts up, it detects if it's being instructed to perform updates. If so, we use ShellExecute with the runas verb to launch an elevated copy of ourselves:

procedure TForm1.FormActivate(Sender: TObject);
begin
    if FindCmdLineSwitch('performUpdates', True) then
    begin
        //If we're not an admin, then use ShellExecute to launch ourselves as one
        if not IsUserAdmin then
        begin
            //Relaunch ourselves as an admin
            Toolkit.RunAsAdmin(0, ParamStr(0), '/performUpdates'); //don't forget to pass the command option
            Application.Terminate;
            Exit;
        end;

        //We are an admin; do the updates.
        PerformUpdates;
        MessageDlg('Update complete.', mtINformation, [mbOk], 0);

        Application.Terminate;
        Exit;
    end;
end;

The ShellExecute with the runas verb triggers the UAC elevation prompt, and then the elevated app running as me (Ian), a different admin user with admin privileges appears:

The RunAsAdmin function is a simple wrapper around ShellExecute:

function RunAsAdmin(hWnd: HWND; filename: string; Parameters: string): Boolean;
{
    See Step 3: Redesign for UAC Compatibility (UAC)
    http://msdn.microsoft.com/en-us/library/bb756922.aspx
}
var
    sei: TShellExecuteInfo;
begin
    ZeroMemory(@sei, SizeOf(sei));
    sei.cbSize := SizeOf(TShellExecuteInfo);
    sei.Wnd := hwnd;
    sei.fMask := SEE_MASK_FLAG_DDEWAIT or SEE_MASK_FLAG_NO_UI;
    sei.lpVerb := PChar('runas');
    sei.lpFile := PChar(Filename); // PAnsiChar;
    if parameters <> '' then
        sei.lpParameters := PChar(parameters); // PAnsiChar;
    sei.nShow := SW_SHOWNORMAL; //Integer;

    Result := ShellExecuteEx(@sei);
end;

In syntax is slightly easier, but UseShellExecute and Verb = "runas" are the critical points.

The function IsUserAdmin is much easier inside .NET:

//helper function that tells us if we're already running with administrative rights
private Boolean IsUserAnAdmin()
{
    //A user can be a member of the Administrator group, but not an administrator.
    //Conversely, the user can be an administrator and not a member of the administrators group.

    //Check if the current user has administrative privelages
    var identity = WindowsIdentity.GetCurrent();
    return (null != identity && new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator));
}

than it is for native code:

function IsUserAdmin: Boolean;
var
    b: BOOL;
    AdministratorsGroup: PSID;
begin
    {
        This function returns true if you are currently running with admin privelages.
        In Vista and later, if you are non-elevated, this function will return false (you are not running with administrative privelages).
        If you *are* running elevated, then IsUserAdmin will return true, as you are running with admin privelages.

        Windows provides this similar function in Shell32.IsUserAnAdmin. But the function is depricated, and this code is lifted
        from the docs for CheckTokenMembership: http://msdn.microsoft.com/en-us/library/aa376389.aspx
    }

    {
        Routine Description: This routine returns TRUE if the callers
        process is a member of the Administrators local group. Caller is NOT
        expected to be impersonating anyone and is expected to be able to
        open its own process and process token.
        Arguments: None.
        Return Value:
            TRUE - Caller has Administrators local group.
            FALSE - Caller does not have Administrators local group.
    }
    b := AllocateAndInitializeSid(
            SECURITY_NT_AUTHORITY,
            2, //2 sub-authorities
            SECURITY_BUILTIN_DOMAIN_RID,    //sub-authority 0
            DOMAIN_ALIAS_RID_ADMINS,        //sub-authority 1
            0, 0, 0, 0, 0, 0,               //sub-authorities 2-7 not passed
            AdministratorsGroup);
    if (b) then
    begin
        if not CheckTokenMembership(0, AdministratorsGroup, b) then
            b := False;
        FreeSid(AdministratorsGroup);
    end;

    Result := b;
end;

So, all that works, and does what you need. But the user will still be presented a UAC Consent dialog; although they will only have to continue. i gather that's not desirable to you. And even if it is:

Don't do it

The critical problem in the above code, and Chris Jackon mentions it in his blog:

The most common request is for people writing home-grown software deployment software, where they’d like to encode credentials right into the app and elevate their own process. The real problem here is not the lack of the API, it’s that you have admin credentials encoded in your app for the world to read. If you have that, what you want is a way to get to a place where you do not have that as quickly as possible, not make it easier to build on that design.

The horrible, horrible, offending code is:

//Relaunch ourselves as a particular domain admin user.
username := 'ian@redacted.com';
password := 'correct battery horse staple';

You've hard-coded the password of a user. That's no good. You don't want that.

You want an administrator to actually be required to walk to the machine and enter his credentials.

Much simpler option

You're in a world where any user is allowed to update the application. If that is true, if all users are allowed to modify the files and registry keys, then let them!

During application install, change the NTFS permissions on your application's folder so that all Users have Full Control:

This is the correct solution to your problem.

Even though none of the above answers your question.

What do you want to see?

And now we come full circle. What do you want to see?

Note: Any code is released into the public domain. No attribution required.



来源:https://stackoverflow.com/questions/19928161/process-start-as-domain-administrator-from-user-started-process-with-uac-activat

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!