Как упоминалось выше, если у пользователя с правами администратора есть локальная учетная запись на ПК, она будет работать. Однако, если я использую администратора домена, компьютер запросит на экране UAC действительные учетные данные администратора.
Что вы хотите? Чтобы выдать себя за пользователя, вы должны знать его пароль.
В любом случае пользователю необходимо знать пароль администратора домена, поэтому он вводит его в диалоговом окне «Согласие», и установка может продолжаться.
Вы представляете себе систему, в которой приложение может запускаться от имени администратора без необходимости вводить учетные данные администратора домена? Это просто недопустимо.
Можно ли здесь сделать то, что я пытаюсь?
Я не уверен, что вы хотите, чтобы здесь произошло. Вот почему я спрашивал, что именно вы хотите, чтобы произошло.
Я чувствую, что вы хотите запустить процесс как учетную запись с правами администратора; поэтому этот отдельный процесс может выполнять обновление. Проблема, как я понимаю, в том, что зарегистрированный пользователь не является администратором.
Я не могу заставить его работать с администратором домена, у которого нет локальной учетной записи на ПК.
Что, в частности, вы пытаетесь заставить работать с помощью администратора домена? Что, именно вы хотите увидеть? Вы думаете, что с помощью кода вы можете запустить процесс с повышенными привилегиями как пользователь домена без появления запроса UAC? Это не произойдет.
Но это возможно
Все сказанное, то, что вы описываете, возможно. Как Крис Джексон отметил в записи блога, что хитрость заключается в следующем:
- Запустите программу от имени администратора домена, используя
CreateProcessWithLogonW
- В этом приложении используйте
ShellExecute
с глаголом runas
для повышения до администратора
- Выполняйте свои обновления
Я смоделировал это с помощью быстрого приложения 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 := '[email protected]';
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
с глаголом runas
запускает запрос на повышение прав UAC, а затем приложение с повышенными правами, работающее от имени меня (Ян), появляется другой пользователь-администратор с правами администратора:
Функция 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" являются критическими точками.
Функция 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; хотя им останется только продолжить. Я так понимаю, это вам не нравится. И даже если это:
Не делай этого
Критическая проблема в приведенном выше коде, о которой Крис Джекон упоминает в своем блоге:
Чаще всего просят людей, пишущих собственное ПО для развертывания программного обеспечения, при котором они хотели бы кодировать учетные данные прямо в приложении и совершенствовать свой собственный процесс. Настоящая проблема здесь не в отсутствии API, а в том, что у вас есть учетные данные администратора, закодированные в вашем приложении, чтобы мир мог их прочитать. Если он у вас есть, то вам нужен способ как можно быстрее попасть в место, где этого нет, а не упрощать создание этого дизайна.
Ужасный, ужасный, оскорбительный код:
//Relaunch ourselves as a particular domain admin user.
username := '[email protected]';
password := 'correct battery horse staple';
Вы жестко ввели пароль пользователя. Это не хорошо. Вы этого не хотите.
Вы хотите, чтобы администратор действительно подошел к машине и ввел свои учетные данные.
Намного более простой вариант
Вы находитесь в мире, где любой пользователь может обновить приложение. Если это правда, и если всем пользователям разрешено изменять файлы и ключи реестра, то разрешите!
Во время установки приложения измените разрешения NTFS для папки приложения, чтобы все Пользователи имели Полный доступ:
Это правильное решение вашей проблемы.
Хотя ни один из вышеперечисленных ответов не отвечает на ваш вопрос.
Что вы хотите увидеть?
И вот мы прошли полный круг. Что вы хотите увидеть?
Примечание. Любой код является общедоступным. Ссылка на авторство не требуется.
person
Ian Boyd
schedule
01.01.2014