Come elevare i privilegi solo quando richiesto?


85

Questa domanda si applica a Windows Vista!

Ho un'applicazione che normalmente funziona senza privilegi amministrativi. C'è un'attività che richiede privilegi amministrativi, ma non voglio avviare l'applicazione stessa con privilegi più elevati quando so che la maggior parte delle volte l'utente non utilizzerà nemmeno quella funzione.

Sto pensando a un certo metodo con cui posso elevare i privilegi di applicazione su alcuni eventi (come la pressione di un pulsante). Esempio:

Se l'utente fa clic su questo pulsante, viene richiesto con la finestra di dialogo UAC o il consenso. Come posso fare questo?

Risposte:


58

Non credo che sia possibile elevare il processo attualmente in esecuzione. È integrato in Windows Vista che i privilegi di amministratore vengono assegnati a un processo all'avvio, a quanto ho capito. Se guardi vari programmi che utilizzano l'UAC, dovresti vedere che in realtà avviano un processo separato ogni volta che deve essere eseguita un'azione amministrativa (Task Manager è uno, Paint.NET è un altro, quest'ultimo è infatti un'applicazione .NET ).

La soluzione tipica a questo problema è specificare gli argomenti della riga di comando quando si avvia un processo con privilegi elevati (il suggerimento di abatishchev è un modo per farlo), in modo che il processo avviato sappia solo di visualizzare una certa finestra di dialogo e quindi uscire dopo che questa azione è stata eseguita completato. Quindi non dovrebbe quasi essere notato all'utente che un nuovo processo è stato avviato e poi chiuso, e sembrerebbe piuttosto come se fosse stata aperta una nuova finestra di dialogo all'interno della stessa app (specialmente se hai qualche hacker per rendere la finestra principale del processo elevato un figlio del processo genitore). Se non hai bisogno dell'interfaccia utente per l'accesso elevato, ancora meglio.

Per una discussione completa sull'UAC su Vista, ti consiglio di leggere questo articolo molto approfondito sull'argomento (gli esempi di codice sono in C ++, ma sospetto che dovrai usare WinAPI e P / Invoke per fare la maggior parte delle cose in C # Comunque). Spero che ora tu veda almeno l'approccio giusto da adottare, anche se la progettazione di un programma conforme all'UAC è tutt'altro che banale ...


4
C'è qualche cambiamento con Windows 7 o la risposta "no, usa un nuovo processo" rimane? Grazie ...
Radim Vansa

2
Nessun cambiamento con Windows 7, temo, scusa. (Per quanto ne so, e sono un utente / sviluppatore regolare su Win7.)
Noldorin

2
Questo è esattamente il modo in cui lo fa il task manager. Quando si fa clic sul pulsante per mostrare le attività per tutti gli utenti, esiste il task manager corrente quindi richiama un altro task manager con diritti di amministratore.
Natalie Adams

3
@NathanAdams Tecnicamente, apre prima il nuovo task manager. Altrimenti, cosa sta facendo l'apertura? :-)
wizzwizz4

16

Come è stato detto :

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

eseguirà il processo come amministratore per fare tutto ciò di cui hai bisogno con il registro, ma tornerà alla tua app con i normali privilegi.


Ciò implica lo sviluppo di un nuovo processo. destra? Stavo cercando di elevare i privilegi del processo corrente stesso.
Hemant,

Prova a utilizzare Process.GetCurrentProcess ()
abatishchev

27
Non è possibile elevare un processo attualmente in esecuzione.
Jacob Proffitt,

1
Questo non è vero. È possibile modificare il proprietario del processo e impostare i valori DACL e ACL per l'utente conferendogli poteri amministrativi ....
Nightforce2

4
@ nightforce2: sicuramente funzionerebbe solo se hai già i diritti amministrativi (cioè sei già elevato). Altrimenti AdjustTokenPrivileges ecc. Semplicemente fallirà, no?
Ben Schwehn

13

Il seguente articolo della Knowledge Base di MSDN 981778 descrive come "elevare automaticamente" un'applicazione:

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

Contiene esempi scaricabili in Visual C ++, Visual C #, Visual Basic.NET.

Questo approccio aggira la necessità di avviare un processo separato, ma in realtà è l'applicazione originale che viene riavviata, in esecuzione come utente con privilegi elevati. Tuttavia questo può essere ancora molto utile in alcuni contesti in cui non è pratico duplicare il codice in un eseguibile separato.

Per rimuovere l'elevazione, è necessario chiudere l'applicazione.


1
Comodo per un pulsante, ma quando vuoi lo stesso per una voce di menu, sei pronto per un casino davvero contorto.
Nyerguds


Il link della risposta è morto e il link del commento punta a un lungo elenco di 2608 elementi.
DonBoitnott

Puoi trovarlo qui
mirh


2

Forse qualcuno torna utile questo semplice esempio:

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);
            }
        }

    }
}

1

So che questo è un vecchio post, ma è in risposta a chiunque altro incontri il suggerimento di MarcP. Il post msdn a cui fa riferimento effettivamente riavvia le applicazioni in tutti gli esempi di codice. Gli esempi di codice utilizzano il runasverbo proposto già in altri suggerimenti.

Ho scaricato il codice per esserne sicuro, ma questo è tratto dall'articolo originale di msdn:

4. Fare clic su Sì per approvare l'elevazione. Quindi, l'applicazione originale viene riavviata, in esecuzione come amministratore con privilegi elevati.
5. Chiudere l'applicazione.


1
Puoi aggiungere il collegamento MSDN in questione? Non riesco a trovare un utente chiamato MarcP.
Alf
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.