草庐IT

.net - 在域网络中激活UAC的情况下,从用户启动的过程以域管理员身份启动过程

coder 2024-06-13 原文

我正在尝试做一些事情,现在在将我的头撞到屏幕上很多次之后,我不确定该做些什么。

该方案如下:

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

  • 理论很合理,但是:
  • 仅在管理员用户是给定PC中的本地管理员时才有效。我无法与PC中没有本地帐户的域管理员一起使用。

  • 我尝试过:
  • 使用advapi32.dll LogonUser中的 token 进行用户模拟。
  • Process-> Start()安装提供域管理员用户凭据。
  • Process-> Start()与域管理员一起发布,然后由普通用户进行Process-> start()安装。

  • 如上所述,如果管理员用户在PC中具有本地帐户,则它将起作用。但是,如果我使用域管理员,则PC会提示UAC屏幕,要求输入有效的管理员凭据。

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

    我可以在这里做些什么吗?如果没有,有什么办法吗?

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

    最佳答案

    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.



    您想发生什么事?为了模拟用户,您必须知道其密码。

    用户需要才能以任何一种方式知道域管理员的密码,因此他们将其输入“同意”对话框中,安装就可以继续。

    您是否正在构想一个系统,在该系统中可以以管理员身份运行应用程序,而无需任何人输入域管理员凭据?根本不允许这样做。

    Is it possible to do what I am trying here?



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

    我觉得您想以具有管理特权的帐户启动进程;因此此单独的过程可以执行更新。我发现问题是登录的用户不是管理员。

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



    使用域管理员时,您尤其要尝试做什么?您到底想看到什么?您是否认为通过代码可以以域用户身份启动提升权限的进程而不会出现UAC提示?那不会发生。

    但是有可能

    话虽如此,您所描述的是可能的。作为Chris Jackson noted in a blog entry,窍门是:
  • 使用CreateProcessWithLogonW
  • 以域管理员身份启动程序
  • 在该应用程序中,将ShellExecuterunas动词一起使用,以提升为管理员
  • 执行更新

  • 我用一个快速的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选项。当我们的应用启动时,它会检测是否被指示执行更新。如果是这样,我们将ShellExecuterunas动词一起使用来启动我们自己的高位副本:
    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动词的runas触发UAC提升提示,然后提升的应用程序以我的身份运行( 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;
    

    在语法上稍微容易一些,但是 UseShellExecute Verb =“runas” 是关键点。

    在.NET中,函数 IsUserAdmin 容易得多:
    //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));
    }
    

    比 native 代码要多:
    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在他的博客中提到了:

    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.



    可怕的,可怕的,令人讨厌的代码是:
    //Relaunch ourselves as a particular domain admin user.
    username := 'ian@redacted.com';
    password := 'correct battery horse staple';
    

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

    希望成为管理员,实际上需要他们步行到计算机并输入其凭据。

    更简单的选择

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

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

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

    即使以上方法都不能回答您的问题。

    你要看什么?

    现在,我们来了一个完整的圈子。你要看什么?

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

    关于.net - 在域网络中激活UAC的情况下,从用户启动的过程以域管理员身份启动过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19928161/

    有关.net - 在域网络中激活UAC的情况下,从用户启动的过程以域管理员身份启动过程的更多相关文章

    1. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

      作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

    2. ruby - 默认情况下使选项为 false - 2

      这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb

    3. ruby - 如何模拟 Net::HTTP::Post? - 2

      是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

    4. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

      我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

    5. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

      最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

    6. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

      我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

    7. ruby - Net::HTTP 获取源代码和状态 - 2

      我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

    8. ruby - 在不使用 RVM 的情况下在 Mac 上卸载和升级 Ruby - 2

      我最近决定从我的系统中卸载RVM。在thispage提出的一些论点说服我:实际上,我的决定是,我根本不想担心Ruby的多个版本。我只想使用1.9.2-p290版本而不用担心其他任何事情。但是,当我在我的Mac上运行ruby--version时,它告诉我我的版本是1.8.7。我四处寻找如何简单地从我的Mac上卸载这个Ruby,但奇怪的是我没有找到任何东西。似乎唯一想卸载Ruby的人运行linux,而使用Mac的每个人都推荐RVM。如何从我的Mac上卸载Ruby1.8.7?我想升级到1.9.2-p290版本,并且我希望我的系统上只有一个版本。 最佳答案

    9. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

      是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

    10. UE4 源码阅读:从引擎启动到Receive Begin Play - 2

      一、引擎主循环UE版本:4.27一、引擎主循环的位置:Launch.cpp:GuardedMain函数二、、GuardedMain函数执行逻辑:1、EnginePreInit:加载大多数模块int32ErrorLevel=EnginePreInit(CmdLine);PreInit模块加载顺序:模块加载过程:(1)注册模块中定义的UObject,同时为每个类构造一个类默认对象(CDO,记录类的默认状态,作为模板用于子类实例创建)(2)调用模块的StartUpModule方法2、FEngineLoop::Init()1、检查Engine的配置文件找出使用了哪一个GameEngine类(UGame

    随机推荐