我正试图做一些事情,现在我的头撞在屏幕上后,我不确定是否可以做到。
情况如下:
理论是有道理的,但是:
我曾尝试过:
如上所述,如果pipe理员用户在PC中有一个本地帐户,它将工作。 但是,如果我使用域pipe理员,则PC将提示UAC屏幕询问有效的pipe理员凭据。
如果我使用任务pipe理器进行检查,则进程将使用给定的凭证启动。 它只是没有安装的权利。
是否有可能做我在这里尝试的? 如果没有,任何方式?
问题是networking是从一个域进行pipe理的,PC不一定有本地创build的pipe理员用户帐户。
如上所述,如果管理员用户在PC中有一个本地帐户,它将工作。 但是,如果我使用域管理员,则PC将提示UAC屏幕询问有效的管理员凭据。
你想要发生什么? 为了模仿一个用户,你必须知道他们的密码。
用户需要知道域管理员的密码,所以他们将其输入到“同意”对话框中,然后安装即可继续。
您是否想象一个系统,可以以管理员身份运行应用程序,而无需任何人输入域管理员凭据? 这是根本不允许的。
有可能做我在这里尝试的吗?
我不确定你想在这里发生什么。 这就是为什么我问你到底想要发生什么。
我知道你想要启动一个具有管理权限的帐户的流程; 所以这个单独的过程可以执行更新。 我收集的问题是登录的用户不是管理员。
我无法使它与在PC中没有本地帐户的域管理员一起工作。
特别是在使用域管理员时,你想要做些什么? 什么,你想看到发生? 你是否认为,通过代码,你可以启动一个升级过程作为域用户没有UAC提示出现? 这不会发生。
所有这些话,你所描述的是可能的。 正如克里斯·杰克逊在博客中指出的那样 :
CreateProcessWithLogonW
作为域管理员启动程序 runas
谓词的ShellExecute
提升为管理员 我用一个快速的Delphi应用程序来模拟它。
最初,测试应用程序是以标准用户身份运行的(名为Forest Gump )。 我检测到他不是管理员,并在“ 更新软件”按钮上显示UAC屏蔽:
点击按钮会导致软件启动自己的副本,但使用域管理员帐户(我, 伊恩 )的凭据。 这是使用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;
带有runas
动词的ShellExecute
触发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)); }
比原生代码还要多:
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 同意对话框; 尽管他们只会继续下去。 我收集这对你不合适。 即使是这样:
上面的代码中的关键问题,克里斯·杰克逊在他的博客中提到:
最常见的要求是编写自制软件部署软件的人,他们希望将凭证直接编码到应用程序中,并提升自己的流程。 这里真正的问题不在于API的缺乏,而在于您的应用程序中已有管理员凭据编码,供全世界阅读 。 如果你有这个想法,你想要的就是尽快到达一个你没有的地方,而不是让这个设计更容易。
可怕的,可怕的,违规的代码是:
//Relaunch ourselves as a particular domain admin user. username := 'ian@redacted.com'; password := 'correct battery horse staple';
你已经硬编码了用户的密码。 这不好。 你不要那个。
您希望管理员实际需要走到机器并输入他的凭据。
您正处于允许任何用户更新应用程序的世界。 如果这是真的,如果所有的用户都被允许修改文件和注册表项,那就让他们 !
在应用程序安装过程中,更改您的应用程序的文件夹的NTFS权限,以便所有用户具有完全控制 :
这是解决您的问题的正确方法。
即使上面没有回答你的问题。
现在我们来了整整一圈。 你要看什么?
注意 :任何代码都被释放到公共领域。 不需要归属