2

我正在尝试做一些事情,现在在我的头撞到屏幕上之后,我不确定它是否可以完成。

场景如下:

  • 带有域控制器的 Windows 网络,其中 PC 的普通用户没有管理权限。
  • 一个程序,当它在网络共享(UNC 路径)中找到更新 (MSI) 时,将运行更新。
  • 因为用户不能进行安装。更新必须与其他具有管理员权限的用户一起运行。

这个理论是合理的,但是:

  • 它仅在管理员用户是给定 PC 中的本地管理员时才有效。我无法使其与在 PC 中没有本地帐户的域管理员一起工作。

我尝试过:

  • 使用来自 advapi32.dll LogonUser 的令牌进行用户模拟。
  • Process->Start() 安装提供域管理员用户凭据。
  • Process->Start() 向域管理员发布广告,然后使用普通用户进行 Process->start() 安装。

如上所述,如果 admin 用户在 PC 中有本地帐户,它将工作。但是,如果我使用域管理员,PC 将提示一个 UAC 屏幕,要求提供有效的管理员凭据。

如果我检查任务管理器,该过程将使用给定的凭据启动。它只是没有安装权限。

有可能做我在这里尝试的事情吗?如果没有,有什么办法吗?

问题是网络是从域管理的,PC 不一定在本地创建管理员用户帐户。

4

1 回答 1

1

如上所述,如果 admin 用户在 PC 中有本地帐户,它将工作。但是,如果我使用域管理员,PC 将提示一个 UAC 屏幕,要求提供有效的管理员凭据。

你想要发生什么?为了模拟用户,您必须知道他们的密码。

无论哪种方式,用户都需要知道域管理员的密码,因此他们将其输入到“同意”对话框中,然后可以继续安装。

您是否正在设想一个应用程序可以作为管理员运行而无需任何人输入域管理员凭据的系统?这根本是不允许的。


有可能做我在这里尝试的事情吗?

我不确定你想在这里发生什么。这就是为什么我要问你到底想要发生什么。

我感觉您想以具有管理权限的帐户启动进程;所以这个单独的进程可以执行更新。我收集到的问题是登录用户不是管理员。

我无法使其与在 PC 中没有本地帐户的域管理员一起工作。

在使用域管理员时,您特别想做什么?什么,你究竟想看到发生什么?您是否认为,通过代码,您可以在不出现 UAC 提示的情况下以域用户身份启动提升的进程?这不会发生。

但这是可能的

说了这么多,你所描述的都是可能的。正如Chris Jackson 在博客文章中指出的那样,诀窍是:

  1. 以域管理员身份启动程序,使用CreateProcessWithLogonW
  2. 在该应用程序中,ShellExecuterunas动词一起使用以提升为管理员
  3. 执行更新

我用一个快速的 Delphi 应用程序模拟了它。

最初,测试应用程序作为标准用户(名为Forest Gump)运行。我检测到他不是管理员,并在更新软件按钮上显示 UAC 盾牌:

在此处输入图像描述

单击该按钮会使软件启动自身的副本,但使用域管理员帐户(我,Ian)的凭据。这是使用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)

诀窍是我们通过了/performUpdates选项。当我们的应用程序启动时,它会检测它是否被指示执行更新。如果是这样,我们使用ShellExecute动词runas来启动我们自己的提升副本:

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;

ShellExecute带有动词的触发runasUAC 提升提示,然后提升的应用程序以我 ( Ian ) 身份运行,出现具有管理员权限的不同管理员用户:

在此处输入图像描述

RunAsAdmin函数是一个简单的包装器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;

在语法上稍微容易一些,但UseShellExecuteVerb = "runas"是关键点。

IsUserAdmin函数在 .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));
}

比本机代码:

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;

因此,所有这些都有效,并且可以满足您的需求。但是用户仍然会看到一个 UAC同意对话框;尽管他们只需要继续。我认为这对你不利。即使是:

不要这样做

上述代码中的关键问题,Chris Jackon 在他的博客中提到:

最常见的要求是编写本土软件部署软件的人,他们希望将凭据直接编码到应用程序中并提升自己的流程。这里真正的问题不是缺少 API,而是您的应用程序中编码了管理员凭据以供全世界阅读。如果你有它,你想要的是一种尽快到达一个你没有它的地方的方法,而不是让它更容易在那个设计的基础上进行构建。

可怕,可怕,令人反感的代码是:

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

您已经硬编码了用户的密码。那不好。你不想要那个。

希望管理员实际上被要求走到机器前并输入他的凭据。

更简单的选择

您处于一个允许任何用户更新应用程序的世界。如果这是真的,如果所有用户都被允许修改文件和注册表项,那就让他们吧!

在应用程序安装期间,更改应用程序文件夹的 NTFS 权限,以便所有用户都拥有完全控制权

在此处输入图像描述

这是您问题的正确解决方案。

即使以上都没有回答你的问题。

你要看什么?

现在我们绕了一圈。你要看什么?

注意:任何代码都会发布到公共领域。无需归属。

于 2014-01-01T05:23:03.420 回答