Процесс Запуск от имени администратора домена из процесса, запущенного пользователем с активированным UAC в доменной сети

Я пытаюсь сделать что-то такое, что теперь, после долгих ударов головой об экран, не уверен, что это можно сделать.

Сценарий следующий:

  • сеть Windows с контроллером домена, где обычные пользователи ПК не имеют административных прав.
  • Программа, которая при обнаружении обновления (MSI) в общем ресурсе сети (путь UNC) запускает обновление.
  • Потому что пользователь не может выполнять установки. Обновление должно запускаться с другим пользователем с правами администратора.

Теория верна, но:

  • он работает только в том случае, если пользователь admin является локальным администратором на данном ПК. Я не могу заставить его работать с администратором домена, у которого нет локальной учетной записи на ПК.

Я пробовал:

  • Выдача себя за пользователя с помощью токена из файла logonUser из advapi32.dll.
  • Процесс-> Start () установить, указав учетные данные администратора домена.
  • Процесс-> Start () Объявите администратору домена, а затем Process-> start () установите с обычным пользователем.

Как упоминалось выше, если у пользователя с правами администратора есть локальная учетная запись на ПК, она будет работать. Однако, если я использую администратора домена, компьютер запросит на экране UAC действительные учетные данные администратора.

Если я проверю с помощью диспетчера задач, процесс запускается с указанными учетными данными. У него просто нет прав на установку.

Можно ли здесь сделать то, что я пытаюсь? Если нет, то в любом случае?

Проблема в том, что сеть администрируется из домена, и на ПК не обязательно есть локально созданная учетная запись администратора.


person Aznarepse    schedule 12.11.2013    source источник
comment
Разве использование GPO для этого не было бы лучшим вариантом, чем реализация настраиваемой службы?   -  person Marvin Smit    schedule 12.11.2013
comment
@ Марвин. Я согласен! Эти ленивые айтишники ...! :) Боюсь, что это не вариант. ИТ-администратору не нужен маршрут GPO.   -  person Aznarepse    schedule 12.11.2013
comment
Простите всех. Я нашел проблему. Учетные данные, которые мне были предоставлены, относились к администраторам группы, но не к администраторам домена группы. Тем не менее, использование LogonUser возвращает Неизвестную ошибку (0xfffffffe), но Процесс- ›Запуск с учетными данными работает. Спасибо!   -  person Aznarepse    schedule 12.11.2013


Ответы (1)


Как упоминалось выше, если у пользователя с правами администратора есть локальная учетная запись на ПК, она будет работать. Однако, если я использую администратора домена, компьютер запросит на экране UAC действительные учетные данные администратора.

Что вы хотите? Чтобы выдать себя за пользователя, вы должны знать его пароль.

В любом случае пользователю необходимо знать пароль администратора домена, поэтому он вводит его в диалоговом окне «Согласие», и установка может продолжаться.

Вы представляете себе систему, в которой приложение может запускаться от имени администратора без необходимости вводить учетные данные администратора домена? Это просто недопустимо.


Можно ли здесь сделать то, что я пытаюсь?

Я не уверен, что вы хотите, чтобы здесь произошло. Вот почему я спрашивал, что именно вы хотите, чтобы произошло.

Я чувствую, что вы хотите запустить процесс как учетную запись с правами администратора; поэтому этот отдельный процесс может выполнять обновление. Проблема, как я понимаю, в том, что зарегистрированный пользователь не является администратором.

Я не могу заставить его работать с администратором домена, у которого нет локальной учетной записи на ПК.

Что, в частности, вы пытаетесь заставить работать с помощью администратора домена? Что, именно вы хотите увидеть? Вы думаете, что с помощью кода вы можете запустить процесс с повышенными привилегиями как пользователь домена без появления запроса UAC? Это не произойдет.

Но это возможно

Все сказанное, то, что вы описываете, возможно. Как Крис Джексон отметил в записи блога, что хитрость заключается в следующем:

  1. Запустите программу от имени администратора домена, используя CreateProcessWithLogonW
  2. В этом приложении используйте ShellExecute с глаголом runas для повышения до администратора
  3. Выполняйте свои обновления

Я смоделировал это с помощью быстрого приложения 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
comment
Спасибо за ваш пост. Однако будет полезно, если вы внимательно прочитаете вопрос и комментарии под ним. - person Aznarepse; 02.01.2014
comment
Привет, еще раз спасибо за такой расширенный пост. Проблема была решена давно, о чем говорилось в комментариях в исходном вопросе (посмотрите). Сетевые правила не позволяют пользователям устанавливать. Программа использует обновление и учетные данные, хранящиеся с шифрованием AES в XML-файле, для автоматического обновления. Он запускает обновление с такими учетными данными с повышенными правами администратора. - person Aznarepse; 02.01.2014
comment
Фактически, программа «благословляет» (рекламирует) обновление с учетными данными администратора, а затем устанавливает его с обычным зарегистрированным пользователем. - person Aznarepse; 02.01.2014