Salve a tutti.

Oggi, volevo iniziare a discutere di un argomento molto dibattuto e sentito da parte degli sviluppatori: come fare in modo di non mostrare il prompt di UAC in Vista e Windows 7 quando si vuole eseguire del codice privilegiato.

Ho tratto ispirazione per questo programma da questi articoli che vi invito a leggere con la massima attenzione:

How To Design a Service to Interact with Multiple User Sessions

Launching an interactive process from Windows Service in Windows Vista and later

CreateProcessAsUser() windowstations and desktops

Lo scenario è quello ricorrente di Vista e Windows 7.

Quando appare il prompt della UAC? Sono pochi i casi in cui appare il prompt: Identification of Administrative Applications

Il problema nasce quando la nostra applicazione va ad eseguire qualche API che richiede determinati privilegi che adesso il token utente non contiene più, e quindi fallisce con Access Denied.

La UAC deve essere visto come un meccanismo di aiuto agli sviluppatori per capire dove il nostro programma cerca di eseguire codice privilegiato, quindi che necessita di diritti amministrativi per essere eseguito. Una volta che siamo riusciti ad isolare tutto il nostro codice che richiede privilegi, possiamo fare in modo di creare un programma separato o un oggetto COM dove includere tutte le funzionalità “amministrative”, così da minimizzare l’impatto sui nostri utenti, e gestire al meglio la user experience di questi, facendo in modo di visualizzare il prompt UAC una sola volta per sessione o magari anche mai.

La UAC serve a indicare la strada per rimuovere dal nostro codice tutto ciò che richiede privilegi di amministratore, in modo che a tendere sarà possibile per i programmi utente, non richiedere privilegi di nessun tipo se non quelli di utente normale, in modo che si possa finalmente arrivare ad una situazione in cui nel sistema operativo, si possa usare di default un account di tipo User per lavorare sempre senza problemi e usare un account amministrativo solo per l’installazione di programmi o per la configurazione del sistema, così da ridurre al minimo l’impatto di virus, trojan e malaware in genere.

Ora, con Vista e Windows 7, dato che la sessione 0, la sessione dei Servizi è completamente isolata e non si può più creare un servizio che interagisca col Desktop; la modalità supportata per una applicazione del genere, è quella di spezzare in due parti l’applicazione: il servizio, dove avviene l’elaborazione e una user mode application che interagisce con l’utente.

Partendo da questi presupposti, mi è venuta l’idea di usare un servizio che giri in Sessione 0 come Local System, che è un admnistrator della macchina, quindi può fare tutto, e creare una User Mode application dalla cui interfaccia mandare comandi al servizio. Questa è la modalità che consigliamo per la realizzazione di applicazioni di controllo, vedi gli antivirus che hanno quasi sempre l’icona nella Tray Area da cui permettono di configurare il sistema, o come in questo caso per applicazioni di comando ed esecuzione. Leggete a tal proposito la sezione intitolata “The Back-End Service Model“ di questo articolo sulla UAC.

Se avete applicazioni che necessitano di privilegi di administrator per girare su Vista e Windows 7, iniziate a pensare alla nuova versione, dove ad esempio non andrete più ad interagire con la parte HKLM del registry, ma userete solo la HKCU o magari file di configurazione salvati nel profilo utente e se proprio dovete fare delle configurazioni al sistema, le farete durante il setup dell’applicazione, o preparerete un programma apposta da eseguire con privilegi di Administrator.

Una buona soluzione temporanea è questa del servizio di appoggio che gira come Local System.

Local System può all‘avvio creare una pipe con un nome random e andare a scrivere qel nome in HKLM, questo per evitare i tipici problemi di DOS (Denial Of Service) che eventuali malaware potrebbero cercare di sfruttare contro il vostro programma.

La parte client dell’aplicazione può collegarsi al servizio e farsi riconoscere, e quello creare una nuova pipe su cui continuare la comunicazione. Ho pensato al fatto che ormai è comune avere macchine Terminal Server, e quindi ho implementato l’esempio sfruttando al massimo le WTS API.

In questo modo l’applicazione è Terminal Server aware e può essere usata da n sessioni contemporaneamente.

Vi allego adesso un pò di screenshot dell’applicazione client che comunica col servizio per mostrarvi alcune delle potenzialità.

Tab1

Questo è il pannello per eseguire un programma, “In sessione 0 come System”, nella sessione corrente “As Administrator” se l’utente che è collegato è già un Administrator, bypassando il prompt di UAC, sempre nella sessione corrente, ma come System, bypassando il prompt ed essendo comunque Administrator, oppure eseguire come l’utente corrente, magari ad un Integrity Level inferiore, oppure per eseguire un programma come system ma sul desktop di Logon (questo Desktop è gestito da Local System e solo questo account può avviare programmi su questo desktop), oppure come l’utente di un altra sessione (su un Terminal Server), o come uno specifico utente di cui si conoscono le credenziali. Nella griglia in alto sono elencate alcune informazioni sulle sessioni attive al momento. Notate una cosa molto comune sui Terminal Server: la sessione 1 è quella della console fisica, che è connessa, ma è una sessione “remota”, la 2 precisamente, ad essere quella attiva. Bisogna sempre ricordarsi che in ambiente Terminal Server, la console potrebbe non essere attiva, e quindi tante volte quando si usa la WTSGetActiveConsoleSessionId, potrebbe acccadere di ottenere un valore di ritorno valido, come succederebbe su questo server in questo momento, ma quello non indica una sessione attiva. Bisogna sempre elencare le sessioni e cercare quelle attive se si devono prendere delle decisioni basate sul fatto che ci sia una sessione attiva dove eventualmente andare ad eseguire un programma nel contesto di una sessione utente.

 Tab2

Questo è tutto un gioco legato ad un altro post che ho già fatto, dove mostravo come usare la SendSAS. In più, utilizzo una funzione non documentata ufficialmente, ma documentata su Internet, su come mandare la SendSas a qualunque sessione. Due pulsanti servono invece a dimostrare il codice per avviare un programma esterno “As Administrator”, forzando l’apparire del prompt UAC. Vengono mostrati due metodi. Esistono anche quelli relativi a COM che qui non sono mostrati.

 Tab3

Questo pannello da la possibilità di leggere e scrivere qualunque chiave di registry a cui Local System abbia accesso. Esistono delle chiavi a cui anche Local System non ha accesso, e dove solo determinati account possono accedere di default, vedi TrustedInstaller.

 Tab4

Quest’ultimo pannello utilizza un pò di WTS API per mandare messaggi a tutte le sessioni o ad una specifica. Un pò come una volta esisteva il Net Send.

Nei prossimi post entreremo in dettaglio su ogni singola funzionalità, e spiegherò in un post introduttivo il setup dell’applicazione in modalità debug, e poi in seguito la parte principale del servizio che non si vede e anche come potenzialmente può essere migliorato questo programma di esempio e quali funzionalità possono essere aggiunte. Nonchè tute le limitazioni e le assunzioni fatte nel preparare questo che non vuol essere altro che un piccolo esempio da cui partire per realizzare la vostra applicazione. Ci saranno sicuramente dei bug, sia cosmetici che di logica, spero non troppi.. segnalatemeli quando li trovate.

Alla prossima!

Mario Raccagni
Senior Support Engineer
Platform Development Support Team