Condividi tramite


Funzione CreateProcessAsUserA (processthreadsapi.h)

Crea un nuovo processo e il relativo thread primario. Il nuovo processo viene eseguito nel contesto di sicurezza dell'utente rappresentato dal token specificato.

In genere, il processo che chiama la funzione CreateProcessAsUser deve avere il privilegio SE_INCREASE_QUOTA_NAME e potrebbe richiedere il privilegio SE_ASSIGNPRIMARYTOKEN_NAME se il token non è assegnabile. Se questa funzione ha esito negativo con ERROR_PRIVILEGE_NOT_HELD (1314), usare invece la funzione CreateProcessWithLogonW . CreateProcessWithLogonW non richiede privilegi speciali, ma l'account utente specificato deve essere autorizzato ad accedere in modo interattivo. In genere, è consigliabile usare CreateProcessWithLogonW per creare un processo con credenziali alternative.

Sintassi

BOOL CreateProcessAsUserA(
  [in, optional]      HANDLE                hToken,
  [in, optional]      LPCSTR                lpApplicationName,
  [in, out, optional] LPSTR                 lpCommandLine,
  [in, optional]      LPSECURITY_ATTRIBUTES lpProcessAttributes,
  [in, optional]      LPSECURITY_ATTRIBUTES lpThreadAttributes,
  [in]                BOOL                  bInheritHandles,
  [in]                DWORD                 dwCreationFlags,
  [in, optional]      LPVOID                lpEnvironment,
  [in, optional]      LPCSTR                lpCurrentDirectory,
  [in]                LPSTARTUPINFOA        lpStartupInfo,
  [out]               LPPROCESS_INFORMATION lpProcessInformation
);

Parametri

[in, optional] hToken

Handle per il token primario che rappresenta un utente. L'handle deve avere i diritti di accesso TOKEN_QUERY, TOKEN_DUPLICATEe TOKEN_ASSIGN_PRIMARY. Per altre informazioni, vedere Access Rights for Access-Token Objects. L'utente rappresentato dal token deve avere accesso in lettura ed esecuzione all'applicazione specificata dal lpApplicationName o dal parametro lpCommandLine.

Per ottenere un token primario che rappresenta l'utente specificato, chiamare la funzione logonUser . In alternativa, è possibile chiamare la funzione DuplicateTokenEx per convertire un token di rappresentazione in un token primario. Ciò consente a un'applicazione server che rappresenta un client di creare un processo con il contesto di sicurezza del client.

Se hToken è una versione limitata del token primario del chiamante, il privilegio SE_ASSIGNPRIMARYTOKEN_NAME non è obbligatorio. Se i privilegi necessari non sono già abilitati, CreateProcessAsUser li abilita per la durata della chiamata. Per altre informazioni, vedere esecuzione con privilegi speciali.

Servizi terminal: Il processo viene eseguito nella sessione specificata nel token. Per impostazione predefinita, si tratta della stessa sessione chiamata LogonUser. Per modificare la sessione, usare la funzione setTokenInformation .

[in, optional] lpApplicationName

Nome del modulo da eseguire. Questo modulo può essere un'applicazione basata su Windows. Può trattarsi di un altro tipo di modulo (ad esempio, MS-DOS o OS/2) se il sottosistema appropriato è disponibile nel computer locale.

La stringa può specificare il percorso completo e il nome file del modulo da eseguire oppure può specificare un nome parziale. Nel caso di un nome parziale, la funzione usa l'unità corrente e la directory corrente per completare la specifica. La funzione non userà il percorso di ricerca. Questo parametro deve includere l'estensione del nome file; non si presuppone alcuna estensione predefinita.

Il parametro lpApplicationName può essere NULL. In tal caso, il nome del modulo deve essere il primo token delimitato da spazi vuoti nella stringa lpCommandLine. Se si utilizza un nome di file lungo contenente uno spazio, utilizzare le stringhe tra virgolette per indicare dove termina il nome del file e iniziano gli argomenti; in caso contrario, il nome del file è ambiguo. Si consideri ad esempio la stringa "c:\program files\sub dir\program name". Questa stringa può essere interpretata in diversi modi. Il sistema tenta di interpretare le possibilità nell'ordine seguente:

c:\program.exec:\program files\sub.exec:\program files\sub dir\program.exec:\program files\sub dir\program name.exe Se il modulo eseguibile è un'applicazione a 16 bit, lpApplicationName deve essere NULLe la stringa a cui punta lpCommandLine deve specificare il modulo eseguibile e i relativi argomenti. Per impostazione predefinita, tutte le applicazioni basate su Windows a 16 bit create da CreateProcessAsUser vengono eseguite in un VDM separato (equivalente a CREATE_SEPARATE_WOW_VDM in CreateProcess).

[in, out, optional] lpCommandLine

Riga di comando da eseguire. La lunghezza massima di questa stringa è di 32.000 caratteri. Se lpApplicationName è NULL, la parte relativa al nome del modulo di lpCommandLine è limitata ai caratteri MAX_PATH.

La versione Unicode di questa funzione, CreateProcessAsUserW, può modificare il contenuto di questa stringa. Pertanto, questo parametro non può essere un puntatore alla memoria di sola lettura, ad esempio una const variabile o una stringa letterale. Se questo parametro è una stringa costante, la funzione può causare una violazione di accesso.

Il parametro lpCommandLine può essere NULL. In tal caso, la funzione usa la stringa a cui punta lpApplicationName come riga di comando.

Se sia lpApplicationName che lpCommandLine non sonoNULL, *lpApplicationName specifica il modulo da eseguire e *lpCommandLine specifica la riga di comando. Il nuovo processo può usare GetCommandLine per recuperare l'intera riga di comando. I processi della console scritti in C possono usare gli argomenti argc e argv per analizzare la riga di comando. Poiché argv[0] è il nome del modulo, i programmatori C in genere ripetono il nome del modulo come primo token nella riga di comando.

Se lpApplicationName è NULL, il primo token delimitato da spazi vuoti della riga di comando specifica il nome del modulo. Se si usa un nome di file lungo contenente uno spazio, usare le stringhe tra virgolette per indicare dove termina il nome del file e gli argomenti iniziano (vedere la spiegazione per il parametro lpApplicationName). Se il nome file non contiene un'estensione, .exe viene accodato. Pertanto, se l'estensione del nome file è .com, questo parametro deve includere l'estensione .com. Se il nome del file termina con un punto (.) senza estensione o se il nome del file contiene un percorso, .exe non viene accodato. Se il nome del file non contiene un percorso di directory, il sistema cerca il file eseguibile nella sequenza seguente:

  1. Directory da cui è stata caricata l'applicazione.
  2. Directory corrente per il processo padre.
  3. Directory di sistema Windows a 32 bit. Usare la funzione GetSystemDirectory per ottenere il percorso di questa directory.
  4. Directory di sistema Windows a 16 bit. Non esiste alcuna funzione che ottiene il percorso di questa directory, ma viene eseguita la ricerca.
  5. Directory di Windows. Usare la funzione GetWindowsDirectory per ottenere il percorso di questa directory.
  6. Directory elencate nella variabile di ambiente PATH. Si noti che questa funzione non esegue ricerche nel percorso per applicazione specificato dalla Percorsi app chiave del Registro di sistema. Per includere questo percorso per applicazione nella sequenza di ricerca, usare la funzione shellExecute .
Il sistema aggiunge un carattere Null alla stringa della riga di comando per separare il nome file dagli argomenti. In questo modo la stringa originale viene divisa in due stringhe per l'elaborazione interna.

[in, optional] lpProcessAttributes

Puntatore a una struttura SECURITY_ATTRIBUTES che specifica un descrittore di sicurezza per il nuovo oggetto processo e determina se i processi figlio possono ereditare l'handle restituito al processo. Se lpProcessAttributes è NULL o lpSecurityDescriptor è NULL, il processo ottiene un descrittore di sicurezza predefinito e l'handle non può essere ereditato. Il descrittore di sicurezza predefinito è quello dell'utente a cui viene fatto riferimento nel parametro hToken . Questo descrittore di sicurezza potrebbe non consentire l'accesso per il chiamante, nel qual caso il processo potrebbe non essere aperto di nuovo dopo l'esecuzione. L'handle del processo è valido e continuerà ad avere diritti di accesso completi.

[in, optional] lpThreadAttributes

Puntatore a una struttura SECURITY_ATTRIBUTES che specifica un descrittore di sicurezza per il nuovo oggetto thread e determina se i processi figlio possono ereditare l'handle restituito al thread. Se lpThreadAttributes è null o lpSecurityDescriptor è NULL, il thread ottiene un descrittore di sicurezza predefinito e l'handle non può essere ereditato. Il descrittore di sicurezza predefinito è quello dell'utente a cui viene fatto riferimento nel parametro hToken . Questo descrittore di sicurezza potrebbe non consentire l'accesso per il chiamante.

[in] bInheritHandles

Se questo parametro è TRUE, ogni handle ereditabile nel processo chiamante viene ereditato dal nuovo processo. Se il parametro è FALSE, gli handle non vengono ereditati. Si noti che gli handle ereditati hanno lo stesso valore e gli stessi diritti di accesso degli handle originali. Per altre informazioni sugli handle ereditabili, vedere Osservazioni.

Servizi terminal: Non è possibile ereditare handle tra le sessioni. Inoltre, se questo parametro è TRUE, è necessario creare il processo nella stessa sessione del chiamante.

processi PPL (Protected Process Light): L'ereditarietà dell'handle generico viene bloccata quando un processo PPL crea un processo non PPL perché PROCESS_DUP_HANDLE non è consentito da un processo non PPL a un processo PPL. Vedere Process Security and Access Rights

[in] dwCreationFlags

Flag che controllano la classe di priorità e la creazione del processo. Per un elenco di valori, vedere flag di creazione di processi .

Questo parametro controlla anche la classe di priorità del nuovo processo, che viene usata per determinare le priorità di pianificazione dei thread del processo. Per un elenco di valori, vedere GetPriorityClass. Se non viene specificato alcun flag di classe di priorità, per impostazione predefinita la classe priority viene NORMAL_PRIORITY_CLASS a meno che la classe di priorità del processo di creazione non sia IDLE_PRIORITY_CLASS o BELOW_NORMAL_PRIORITY_CLASS. In questo caso, il processo figlio riceve la classe di priorità predefinita del processo chiamante.

Se il parametro dwCreationFlags ha un valore pari a 0:

  • Il processo eredita sia la modalità di errore del chiamante che la console dell'elemento padre.
  • Si presuppone che il blocco di ambiente per il nuovo processo contenga caratteri ANSI (vedere parametro lpEnvironment per altre informazioni).
  • Un'applicazione basata su Windows a 16 bit viene eseguita in una macchina DOS virtuale condivisa (VDM).

[in, optional] lpEnvironment

Puntatore a un blocco di ambiente per il nuovo processo. Se questo parametro è NULL, il nuovo processo usa l'ambiente del processo chiamante.

Un blocco di ambiente è costituito da un blocco con terminazione Null di stringhe con terminazione Null. Ogni stringa è nel formato seguente:

nome=valore\0

Poiché il segno di uguale viene usato come separatore, non deve essere usato nel nome di una variabile di ambiente.

Un blocco di ambiente può contenere caratteri Unicode o ANSI. Se il blocco di ambiente a cui punta lpEnvironment contiene caratteri Unicode, assicurarsi che dwCreationFlags includa CREATE_UNICODE_ENVIRONMENT.

La versione ANSI di questa funzione CreateProcessAsUserA se la dimensione totale del blocco di ambiente per il processo supera i 32.767 caratteri.

Si noti che un blocco di ambiente ANSI viene terminato da due byte zero: uno per l'ultima stringa, uno più per terminare il blocco. Un blocco di ambiente Unicode viene terminato da quattro byte zero: due per l'ultima stringa, altre due per terminare il blocco.

Windows Server 2003 e Windows XP: Se le dimensioni della variabile di ambiente utente e di sistema combinata superano i 8192 byte, il processo creato da CreateProcessAsUser non viene più eseguito con il blocco di ambiente passato alla funzione dal processo padre. Il processo figlio viene invece eseguito con il blocco di ambiente restituito dalla funzione CreateEnvironmentBlock.

Per recuperare una copia del blocco di ambiente per un determinato utente, usare la funzione CreateEnvironmentBlock .

[in, optional] lpCurrentDirectory

Percorso completo della directory corrente per il processo. La stringa può anche specificare un percorso UNC.

Se questo parametro è NULL, il nuovo processo avrà la stessa unità corrente e la stessa directory del processo chiamante. Questa funzionalità viene fornita principalmente per le shell che devono avviare un'applicazione e specificare l'unità iniziale e la directory di lavoro.

[in] lpStartupInfo

Puntatore a una struttura STARTUPINFO o STARTUPINFOEX.

L'utente deve avere accesso completo sia alla stazione della finestra specificata che al desktop. Se si desidera che il processo sia interattivo, specificare winsta0\default. Se il membro lpDesktop è NULL, il nuovo processo eredita la stazione desktop e finestra del processo padre. Se questo membro è una stringa vuota, "", il nuovo processo si connette a una stazione finestra usando le regole descritte in Connessione processo a una stazione finestra.

Per impostare gli attributi estesi, utilizzare una struttura STARTUPINFOEX e specificare EXTENDED_STARTUPINFO_PRESENT nel parametro dwCreationFlags.

Gli handle in STARTUPINFO o STARTUPINFOEX devono essere chiusi con CloseHandle quando non sono più necessari.

Importante Il chiamante è responsabile della verifica che i campi handle standard in STARTUPINFO contengano valori di handle validi. Questi campi vengono copiati invariati nel processo figlio senza convalida, anche quando il membro dwFlags specifica STARTF_USESTDHANDLES. I valori non corretti possono causare un comportamento errato o un arresto anomalo del processo figlio. Usare lo strumento di verifica dell'applicazione strumento di verifica del runtime per rilevare handle non validi.
 

[out] lpProcessInformation

Puntatore a una struttura PROCESS_INFORMATION che riceve informazioni di identificazione sul nuovo processo.

Gli handle in PROCESS_INFORMATION devono essere chiusi con CloseHandle quando non sono più necessari.

Valore restituito

Se la funzione ha esito positivo, il valore restituito è diverso da zero.

Se la funzione ha esito negativo, il valore restituito è zero. Per ottenere informazioni estese sull'errore, chiamare GetLastError.

Si noti che la funzione restituisce prima che il processo abbia terminato l'inizializzazione. Se non è possibile individuare o non inizializzare una DLL necessaria, il processo viene terminato. Per ottenere lo stato di terminazione di un processo, chiamare GetExitCodeProcess.

Osservazioni

CreateProcessAsUser deve essere in grado di aprire il token primario del processo chiamante con i diritti di accesso TOKEN_DUPLICATE e TOKEN_IMPERSONATE.

Per impostazione predefinita, CreateProcessAsUser crea il nuovo processo in una stazione finestra non interattiva con un desktop non visibile e non può ricevere l'input dell'utente. Per abilitare l'interazione dell'utente con il nuovo processo, è necessario specificare il nome della stazione e del desktop della finestra interattiva predefinita, "winsta0\default", nel membro della struttura STARTUPINFO. Inoltre, prima di chiamare CreateProcessAsUser, è necessario modificare l'elenco di controllo di accesso discrezionale (DACL) della stazione della finestra interattiva predefinita e del desktop predefinito. I DACL per la stazione della finestra e il desktop devono concedere l'accesso all'utente o alla sessione di accesso rappresentata dal parametro hToken .

CreateProcessAsUser non carica il profilo dell'utente specificato nella chiave del Registro di sistema HKEY_USERS. Pertanto, per accedere alle informazioni nella chiave del Registro di sistema HKEY_CURRENT_USER, è necessario caricare le informazioni del profilo dell'utente in HKEY_USERS con la funzione LoadUserProfile prima di chiamare CreateProcessAsUser. Assicurarsi di chiamare UnloadUserProfile dopo la chiusura del nuovo processo.

Se il parametro lpEnvironment è NULL, il nuovo processo eredita l'ambiente del processo chiamante. CreateProcessAsUser non modifica automaticamente il blocco di ambiente in modo da includere variabili di ambiente specifiche dell'utente rappresentato da hToken. Ad esempio, le variabili USERNAME e USERDOMAIN vengono ereditate dal processo chiamante se lpEnvironment è NULL. È responsabilità dell'utente preparare il blocco di ambiente per il nuovo processo e specificarlo in lpEnvironment.

Le funzioni CreateProcessWithLogonW e CreateProcessWithTokenW sono simili a CreateProcessAsUser, ad eccezione del fatto che il chiamante non deve chiamare la funzione LogonUser per autenticare l'utente e ottenere un token.

CreateProcessAsUser consente di accedere alla directory e all'immagine eseguibile specificata nel contesto di sicurezza del chiamante o dell'utente di destinazione. Per impostazione predefinita, CreateProcessAsUser accede alla directory e all'immagine eseguibile nel contesto di sicurezza del chiamante. In questo caso, se il chiamante non ha accesso alla directory e all'immagine eseguibile, la funzione non riesce. Per accedere alla directory e all'immagine eseguibile usando il contesto di sicurezza dell'utente di destinazione, specificare hToken in una chiamata alla funzione ImpersonateLoggedOnUser prima di chiamare CreateProcessAsUser.

Al processo viene assegnato un identificatore di processo. L'identificatore è valido fino al termine del processo. Può essere usato per identificare il processo o specificato nella funzione OpenProcess per aprire un handle al processo. Al thread iniziale nel processo viene assegnato anche un identificatore di thread. Può essere specificato nella funzione OpenThread per aprire un handle al thread. L'identificatore è valido fino al termine del thread e può essere usato per identificare in modo univoco il thread all'interno del sistema. Questi identificatori vengono restituiti nella struttura PROCESS_INFORMATION.

Il thread chiamante può usare la funzione WaitForInputIdle per attendere il completamento dell'inizializzazione del nuovo processo e attende l'input dell'utente senza input in sospeso. Ciò può essere utile per la sincronizzazione tra processi padre e figlio, perché CreateProcessAsUser restituisce senza attendere il completamento dell'inizializzazione del nuovo processo. Ad esempio, il processo di creazione userà WaitForInputIdle prima di cercare una finestra associata al nuovo processo.

Il modo preferito per arrestare un processo consiste nell'usare la funzione ExitProcess , perché questa funzione invia la notifica di avvicinamento della terminazione a tutte le DLL collegate al processo. Altri mezzi per arrestare un processo non notificano le DLL associate. Si noti che quando un thread chiama ExitProcess, gli altri thread del processo vengono terminati senza la possibilità di eseguire codice aggiuntivo (incluso il codice di terminazione del thread delle DLL associate). Per altre informazioni, vedere Terminazione di un processo.

Per impostazione predefinita, passando TRUE come valore del parametro bInheritHandles fa sì che tutti gli handle ereditabili vengano ereditati dal nuovo processo. Ciò può essere problematico per le applicazioni che creano processi da più thread contemporaneamente, ma desiderano che ogni processo erediti handle diversi. Le applicazioni possono usare la funzione UpdateProcThreadAttributeList con il parametro PROC_THREAD_ATTRIBUTE_HANDLE_LIST per fornire un elenco di handle da ereditare da un particolare processo.

osservazioni sulla sicurezza

Il parametro lpApplicationName può essere NULL, nel qual caso il nome eseguibile deve essere la prima stringa delimitata da spazi vuoti in lpCommandLine. Se il nome del file eseguibile o del percorso contiene uno spazio, esiste il rischio che un eseguibile diverso possa essere eseguito a causa del modo in cui la funzione analizza gli spazi. L'esempio seguente è pericoloso perché la funzione tenterà di eseguire "Program.exe", se esistente, anziché "MyApp.exe".
	LPTSTR szCmdline[] = _tcsdup(TEXT("C:\\Program Files\\MyApp"));
	CreateProcessAsUser(hToken, NULL, szCmdline, /*...*/ );

Se un utente malintenzionato dovesse creare un'applicazione denominata "Program.exe" in un sistema, qualsiasi programma che chiama erroneamente CreateProcessAsUser usando la directory Programmi eseguirà questa applicazione anziché l'applicazione desiderata.

Per evitare questo problema, non passare NULL per lpApplicationName. Se si passa NULL per lpApplicationName, usare le virgolette intorno al percorso eseguibile in lpCommandLine, come illustrato nell'esempio seguente.

	LPTSTR szCmdline[] = _tcsdup(TEXT("\"C:\\Program Files\\MyApp\""));
	CreateProcessAsUser(hToken, NULL, szCmdline, /*...*/);

PowerShell: Quando la funzione CreateProcessAsUser viene usata per implementare un cmdlet in PowerShell versione 2.0, il cmdlet funziona correttamente per le sessioni remote fan-in e fan-out. A causa di alcuni scenari di sicurezza, tuttavia, un cmdlet implementato con CreateProcessAsUser funziona correttamente solo in PowerShell versione 3.0 per le sessioni remote fan-in; Le sessioni remote fan-out avranno esito negativo a causa di privilegi di sicurezza client insufficienti. Per implementare un cmdlet che funziona sia per le sessioni remote fan-in che per le sessioni remote fan-out in PowerShell versione 3.0, usare la funzione CreateProcess.

Esempi

Per un esempio, vedere Avvio di un processo client interattivo.

Nota

L'intestazione processthreadsapi.h definisce CreateProcessAsUser come alias che seleziona automaticamente la versione ANSI o Unicode di questa funzione in base alla definizione della costante del preprocessore UNICODE. La combinazione dell'utilizzo dell'alias indipendente dalla codifica con il codice non indipendente dalla codifica può causare mancate corrispondenze che generano errori di compilazione o di runtime. Per altre informazioni, vedere convenzioni di per i prototipi di funzioni.

Fabbisogno

Requisito Valore
client minimo supportato Windows XP [solo app desktop]
server minimo supportato Windows Server 2003 [solo app desktop]
piattaforma di destinazione Finestre
intestazione processthreadsapi.h (include Windows.h)
libreria Advapi32.lib
dll Advapi32.dll

Vedere anche

CloseHandle

CreateEnvironmentBlock

CreateProcess

CreateProcessWithLogonW

ExitProcess

GetEnvironmentStrings

GetExitCodeProcess

GetStartupInfo

ImpersonateLoggedOnUser

LoadUserProfile

PROCESS_INFORMATION

processi e funzioni thread

processi

SECURITY_ATTRIBUTES

SHCreateProcessAsUserW

STARTUPINFO

STARTUPINFOEX

SetErrorMode

WaitForInputIdle