Como elevar privilégios apenas quando necessário?

85

Esta questão se aplica ao Windows Vista!

Tenho um aplicativo que normalmente funciona sem privilégios administrativos. Há uma atividade que precisa de privilégio administrativo, mas não quero iniciar o próprio aplicativo com privilégios mais altos, pois sei que na maioria das vezes o usuário nem mesmo usará esse recurso.

Estou pensando em certo método pelo qual posso elevar os privilégios de aplicação em algum evento (como pressionar um botão). Exemplo:

Se o usuário clicar neste botão, ele será solicitado com uma caixa de diálogo ou consentimento do UAC. Como posso fazer isso?

Hemant
fonte

Respostas:

58

Não acredito que seja possível elevar o processo atualmente em execução. É integrado ao Windows Vista que privilégios de administrador são dados a um processo na inicialização, pelo que entendi. Se você olhar para vários programas que utilizam UAC, você verá que eles realmente iniciam um processo separado cada vez que uma ação administrativa precisa ser executada (Gerenciador de Tarefas é um, Paint.NET é outro, o último sendo um aplicativo .NET na verdade )

A solução típica para este problema é especificar argumentos de linha de comando ao iniciar um processo elevado (a sugestão de abatishchev é uma maneira de fazer isso), de modo que o processo iniciado saiba apenas para exibir uma determinada caixa de diálogo e, em seguida, saia após esta ação ter sido concluído. Assim, dificilmente deve ser notado para o usuário que um novo processo foi iniciado e, em seguida, encerrado, e prefere aparecer como se uma nova caixa de diálogo dentro do mesmo aplicativo tivesse sido aberta (especialmente se você algum hackery para tornar a janela principal do processo elevado, filho do processo pai). Se você não precisa da IU para o acesso elevado, melhor ainda.

Para uma discussão completa do UAC no Vista, recomendo que você leia este artigo completo sobre o assunto (os exemplos de código estão em C ++, mas eu suspeito que você precisará usar o WinAPI e P / Invoke para fazer a maioria das coisas em C # de qualquer forma). Esperamos que você agora pelo menos veja a abordagem certa a ser tomada, embora projetar um programa compatível com o UAC esteja longe de ser trivial ...

Noldorin
fonte
4
Há alguma mudança no Windows 7 ou a resposta "não, use um novo processo" se mantém? Obrigado ...
Radim Vansa
2
Nenhuma mudança com o Windows 7, infelizmente. (Pelo que eu sei, sou um usuário / desenvolvedor regular no Win7.)
Noldorin
2
É exatamente assim que o gerenciador de tarefas faz. Quando você clica no botão para mostrar tarefas para todos os usuários, o gerenciador de tarefas atual chama outro gerenciador de tarefas com direitos de administrador.
Natalie Adams
3
@NathanAdams Tecnicamente, ele abre o novo gerenciador de tarefas primeiro. Caso contrário, o que está fazendo a abertura? :-)
wizzwizz4
16

Como foi dito :

Process.StartInfo.UseShellExecute = true;
Process.StartInfo.Verb = "runas";

executará o processo como administrador para fazer o que for necessário com o registro, mas retornará ao seu aplicativo com os privilégios normais.

Abatishchev
fonte
Isso envolve abranger um novo processo. direito? Eu estava procurando elevar os privilégios do próprio processo atual.
Hemant
Tente usar para Process.GetCurrentProcess ()
abatishchev
27
Você não pode elevar um processo em execução no momento.
Jacob Proffitt
1
Isso não é verdade. Você pode alterar o proprietário do processo e definir os valores DACL e ACL para o usuário, dando-lhe poderes administrativos ....
Nightforce2
4
@ nightforce2: com certeza isso só funcionaria se você já tiver direitos administrativos (ou seja, você já está elevado). Caso contrário, AdjustTokenPrivileges etc simplesmente falhará, não?
Ben Schwehn
13

O seguinte artigo do MSDN KB 981778 descreve como 'auto-elevar' um aplicativo:

http://support.microsoft.com/kb/981778

Ele contém exemplos para download em Visual C ++, Visual C #, Visual Basic.NET.

Essa abordagem contorna a necessidade de iniciar um processo separado, mas na verdade é o aplicativo original que é reiniciado, executando como um usuário elevado. No entanto, isso ainda pode ser muito útil em alguns contextos onde não é prático duplicar o código em um executável separado.

Para remover a elevação, você precisa sair do aplicativo.

FruitBreak
fonte
1
Útil para um botão, mas quando você quer o mesmo para um item de menu, você está em uma bagunça realmente complicada.
Nyerguds
3
@Todd Você pode encontrar o código aqui: https://code.msdn.microsoft.com/windowsapps/CSUACSelfElevation-644673d3
Matthiee
O link da resposta está morto e o link do comentário aponta para uma longa lista de 2.608 itens.
DonBoitnott
Você pode encontrá-lo aqui
mirh
2

Talvez alguém seja útil com este exemplo simples:

using System;
using System.Linq;
using System.Reflection;
using System.Diagnostics;
using System.Security.Principal;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    internal static class Program
    {
        private class Form1 : Form
        {
            internal Form1()
            {
                var button = new Button{ Dock = DockStyle.Fill };
                button.Click += (sender, args) => RunAsAdmin();
                Controls.Add(button);

                ElevatedAction();
            }
        }

        [STAThread]
        internal static void Main(string[] arguments)
        {
            if (arguments?.Contains("/run_elevated_action") == true)
            {
                ElevatedAction();
                return;
            }

            Application.Run(new Form1());
        }

        private static void RunAsAdmin()
        {
            var path = Assembly.GetExecutingAssembly().Location;
            using (var process = Process.Start(new ProcessStartInfo(path, "/run_elevated_action")
            {
                Verb = "runas"
            }))
            {
                process?.WaitForExit();
            }
        }

        private static void ElevatedAction()
        {
            MessageBox.Show($@"IsElevated: {IsElevated()}");
        }

        private static bool IsElevated()
        {
            using (var identity = WindowsIdentity.GetCurrent())
            {
                var principal = new WindowsPrincipal(identity);

                return principal.IsInRole(WindowsBuiltInRole.Administrator);
            }
        }

    }
}
Konstantin S.
fonte
1

Eu sei que este é um post antigo, mas isso é uma resposta a qualquer pessoa que venha com a sugestão de MarcP. A postagem do msdn que ele referenciou realmente reinicia os aplicativos em todos os exemplos de código. Os exemplos de código usam o runasverbo proposto já em outras sugestões.

Baixei o código para ter certeza, mas este é do artigo msdn original:

4. Clique em Sim para aprovar a elevação. Em seguida, o aplicativo original é reiniciado, executando como um administrador elevado.
5. Feche o aplicativo.

SpaceGhost440
fonte
1
Você pode adicionar o link do MSDN em questão? Não consigo encontrar um usuário chamado MarcP.
Alf