Funzione CreateProcessWithLogonW (winbase.h)
Crea un nuovo processo e il relativo thread primario. Il nuovo processo esegue quindi il file eseguibile specificato nel contesto di sicurezza delle credenziali specificate (utente, dominio e password). Facoltativamente, può caricare il profilo utente per un utente specificato.
Questa funzione è simile alle funzioni CreateProcessAsUser e CreateProcessWithTokenW , ad eccezione del fatto che il chiamante non deve chiamare la funzione LogonUser per autenticare l'utente e ottenere un token.
Sintassi
BOOL CreateProcessWithLogonW(
[in] LPCWSTR lpUsername,
[in, optional] LPCWSTR lpDomain,
[in] LPCWSTR lpPassword,
[in] DWORD dwLogonFlags,
[in, optional] LPCWSTR lpApplicationName,
[in, out, optional] LPWSTR lpCommandLine,
[in] DWORD dwCreationFlags,
[in, optional] LPVOID lpEnvironment,
[in, optional] LPCWSTR lpCurrentDirectory,
[in] LPSTARTUPINFOW lpStartupInfo,
[out] LPPROCESS_INFORMATION lpProcessInformation
);
Parametri
[in] lpUsername
Nome dell'utente. Si tratta del nome dell'account utente a cui accedere. Se si usa il formato UPN, l'utente@DNS_domain_name, il parametro lpDomain deve essere NULL.
L'account utente deve disporre dell'autorizzazione Accesso locale nel computer locale. Questa autorizzazione viene concessa a tutti gli utenti nelle workstation e nei server, ma solo agli amministratori nei controller di dominio.
[in, optional] lpDomain
Nome del dominio o del server il cui database account contiene lpUsername account. Se questo parametro è NULL, il nome utente deve essere specificato in formato UPN.
[in] lpPassword
Password cancellata per l'account lpUsername .
[in] dwLogonFlags
Opzione di accesso. Questo parametro può essere 0 (zero) o uno dei valori seguenti.
[in, optional] lpApplicationName
Nome del modulo da eseguire. Questo modulo può essere un'applicazione basata su Windows. Può essere 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 del file del modulo da eseguire oppure può specificare un nome parziale. Se è un nome parziale, la funzione usa l'unità corrente e la directory corrente per completare la specifica. La funzione non usa 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 e il nome del modulo deve essere il primo token delimitato da spazi vuoti nella stringa lpCommandLine . Se si usa un nome di file lungo che contiene uno spazio, usare stringhe con virgolette per indicare dove termina il nome del file e gli argomenti iniziano; in caso contrario, il nome del file è ambiguo.
Ad esempio, la stringa seguente può essere interpretata in modi diversi:
"c:\program files\sub dir\program name"
Il sistema tenta di interpretare le possibilità nell'ordine seguente:
- c:\program.exe files\sub dir\program name
- c:\program files\sub.exe nome dir\programma
- c:\program files\sub dir\program.exe name
- c:\programmi\sub dir\program name.exe
Se il modulo eseguibile è un'applicazione a 16 bit, lpApplicationName deve essere NULL e la stringa puntata a lpCommandLine deve specificare il modulo eseguibile e i relativi argomenti.
[in, out, optional] lpCommandLine
Riga di comando da eseguire. La lunghezza massima di questa stringa è di 1024 caratteri. Se lpApplicationName è NULL, la parte del nome del modulo di lpCommandLine è limitata a MAX_PATH caratteri.
La funzione può modificare il contenuto di questa stringa. Pertanto, questo parametro non può essere un puntatore alla memoria di sola lettura,ad esempio una variabile const o una stringa letterale. Se questo parametro è una stringa costante, la funzione può causare una violazione di accesso.
Il parametro lpCommandLine può essere NULL e la funzione usa la stringa puntata da lpApplicationName come riga di comando.
Se sia lpApplicationName che lpCommandLine non sono NULL, *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 ripetano in genere 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 stringhe virgolette per indicare dove termina il nome del file e gli argomenti iniziano (vedere la spiegazione per il parametro lpApplicationName ). Se il nome del file non contiene un'estensione, .exe viene aggiunto. Pertanto, se l'estensione del nome file è .com, questo parametro deve includere l'estensione .com. Se il nome del file termina in un punto senza estensione o se il nome del file contiene un percorso, .exe non viene aggiunto. Se il nome del file non contiene un percorso di directory, il sistema cerca il file eseguibile nella sequenza seguente:
- Directory da cui è stata caricata l'applicazione.
- Directory corrente per il processo padre.
- Directory di sistema Windows a 32 bit. Usare la funzione GetSystemDirectory per ottenere il percorso di questa directory.
- Directory di sistema Windows a 16 bit. Non esiste alcuna funzione che ottiene il percorso di questa directory, ma viene eseguita la ricerca.
- La directory Windows. Usare la funzione GetWindowsDirectory per ottenere il percorso di questa directory.
- Directory elencate nella variabile di ambiente PATH. Si noti che questa funzione non cerca il percorso per applicazione specificato dalla chiave del Registro di sistema Percorsi app . Per includere questo percorso per applicazione nella sequenza di ricerca, usare la funzione ShellExecute .
[in] dwCreationFlags
Flag che controllano la modalità di creazione del processo. I flag CREATE_DEFAULT_ERROR_MODE, CREATE_NEW_CONSOLE e CREATE_NEW_PROCESS_GROUP sono abilitati per impostazione predefinita. Per un elenco di valori, vedere Flag di creazione dei processi.
Questo parametro controlla anche la classe priorità del nuovo processo, 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 priorità, la classe priority viene predefinita per 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 ottiene la modalità di errore predefinita, crea una nuova console e crea un nuovo gruppo di processi.
- Si presuppone che il blocco di ambiente per il nuovo processo contenga caratteri ANSI (vedere il parametro lpEnvironment per altre informazioni).
- Un'applicazione basata su Windows a 16 bit viene eseguita in una macchina virtuale virtuale condivisa (VDM).
[in, optional] lpEnvironment
Puntatore a un blocco di ambiente per il nuovo processo. Se questo parametro è NULL, il nuovo processo usa un ambiente creato dal profilo dell'utente specificato da lpUsername.
Un blocco di ambiente è costituito da un blocco con terminazione Null di stringhe con terminazione null. Ogni stringa è nel formato seguente:
Nome=Valore
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.
Un blocco di ambiente ANSI viene terminato da due byte 0 (zero): uno per l'ultima stringa e uno più per terminare il blocco. Un blocco di ambiente Unicode viene terminato da quattro byte zero: due per l'ultima stringa e altre due per terminare il blocco.
Per recuperare una copia del blocco di ambiente per un utente specifico, 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 ha la stessa unità e la stessa directory correnti 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 .
L'applicazione deve aggiungere l'autorizzazione per l'account utente specificato alla stazione della finestra e al desktop specificati, anche per WinSta0\Default.
Se il membro lpDesktop è NULL o una stringa vuota, il nuovo processo eredita il desktop e la stazione finestra del processo padre. L'applicazione deve aggiungere l'autorizzazione per l'account utente specificato alla stazione della finestra ereditata e al desktop.
Windows XP: CreateProcessWithLogonW aggiunge l'autorizzazione per l'account utente specificato alla stazione della finestra ereditata e al desktop.
Gli handle in STARTUPINFO devono essere chiusi con CloseHandle quando non sono più necessari.
[out] lpProcessInformation
Puntatore a una struttura PROCESS_INFORMATION che riceve informazioni di identificazione per il nuovo processo, incluso un handle per il processo.
Gli handle in PROCESS_INFORMATION devono essere chiusi con la funzione CloseHandle quando non sono necessari.
Valore restituito
Se la funzione ha esito positivo, il valore restituito è diverso da zero.
Se la funzione ha esito negativo, il valore restituito è 0 (zero). Per informazioni dettagliate sull'errore, chiamare GetLastError.
Si noti che la funzione viene restituita 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.
Commenti
Per impostazione predefinita, CreateProcessWithLogonW non carica il profilo utente specificato nella chiave del Registro di sistema HKEY_USERS. Ciò significa che l'accesso alle informazioni nella chiave del Registro di sistema HKEY_CURRENT_USER potrebbe non produrre risultati coerenti con un normale accesso interattivo. È responsabilità dell'utente caricare l'hive del Registro di sistema utente in HKEY_USERS prima di chiamare CreateProcessWithLogonW, usando LOGON_WITH_PROFILE o chiamando la funzione LoadUserProfile .
Se il parametro lpEnvironment è NULL, il nuovo processo usa un blocco di ambiente creato dal profilo dell'utente specificato da lpUserName. Se le variabili HOMEDRIVE e HOMEPATH non sono impostate, CreateProcessWithLogonW modifica il blocco di ambiente per usare l'unità e il percorso della directory di lavoro dell'utente.
Al momento della creazione, il nuovo processo e gli handle di thread ricevono diritti di accesso completi (PROCESS_ALL_ACCESS e THREAD_ALL_ACCESS). Per entrambi gli handle, se non viene fornito un descrittore di sicurezza, l'handle può essere usato in qualsiasi funzione che richiede un handle oggetto di tale tipo. Quando viene fornito un descrittore di sicurezza, viene eseguito un controllo di accesso su tutti gli usi successivi dell'handle prima che venga concesso l'accesso. Se l'accesso viene negato, il processo di richiesta non può usare l'handle per ottenere l'accesso al processo o al thread.
Per recuperare un token di sicurezza, passare l'handle di processo nella struttura PROCESS_INFORMATION alla funzione OpenProcessToken .
Al processo viene assegnato un identificatore di processo. L'identificatore è valido fino al termine del processo. Può essere usato per identificare il processo oppure può essere 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 in PROCESS_INFORMATION.
Il thread chiamante può usare la funzione WaitForInputIdle per attendere il completamento dell'inizializzazione del nuovo processo ed è in attesa dell'input dell'utente senza input in sospeso. Ciò può essere utile per la sincronizzazione tra processi padre e figlio, perché CreateProcessWithLogonW restituisce senza attendere il completamento dell'inizializzazione del nuovo processo. Ad esempio, il processo di creazione usa 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 una notifica relativa all'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 collegate). Per altre informazioni, vedere Terminazione di un processo.
CreateProcessWithLogonW accede alla directory e all'immagine eseguibile specificata nel contesto di sicurezza dell'utente di destinazione. Se l'immagine eseguibile si trova in una rete e nel percorso viene specificata una lettera di unità di rete, la lettera di unità di rete non è disponibile per l'utente di destinazione, perché è possibile assegnare lettere di unità di rete per ogni accesso. Se viene specificata una lettera di unità di rete, questa funzione ha esito negativo. Se l'immagine eseguibile si trova in una rete, usare il percorso UNC.
Esiste un limite al numero di processi figlio che possono essere creati da questa funzione ed eseguiti contemporaneamente. Ad esempio, in Windows XP questo limite è MAXIMUM_WAIT_OBJECTS*4. Tuttavia, potrebbe non essere possibile creare questo numero di processi a causa di limiti di quota a livello di sistema.
Windows XP con SP2, Windows Server 2003 o versione successiva: Non è possibile chiamare CreateProcessWithLogonW da un processo in esecuzione con l'account "LocalSystem", perché la funzione usa il SID di accesso nel token del chiamante e il token per l'account "LocalSystem" non contiene questo SID. In alternativa, usare le funzioni CreateProcessAsUser e LogonUser .
Per compilare un'applicazione che usa questa funzione, definire _WIN32_WINNT come 0x0500 o versione successiva. Per altre informazioni, vedere Uso delle intestazioni di Windows.
Osservazioni sulla sicurezza
Il parametro lpApplicationName può essere NULL e il nome dell'eseguibile deve essere la prima stringa delimitata da spazi vuoti in lpCommandLine. Se il nome dell'eseguibile o del percorso contiene uno spazio, esiste il rischio che sia possibile eseguire un file eseguibile diverso a causa del modo in cui la funzione analizza gli spazi. Evitare l'esempio seguente, perché la funzione tenta di eseguire "Program.exe", se esistente, anziché "MyApp.exe".LPTSTR szCmdline[]=_tcsdup(TEXT("C:\\Program Files\\MyApp"));
CreateProcessWithLogonW(..., szCmdline, ...)
Se un utente malintenzionato crea un'applicazione denominata "Program.exe" in un sistema, qualsiasi programma che chiama erroneamente CreateProcessWithLogonW usando la directory Programmi esegue l'applicazione utente dannosa 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\""));
CreateProcessWithLogonW(..., szCmdline, ...)
Esempio
Nell'esempio seguente viene illustrato come chiamare questa funzione.
#include <windows.h>
#include <stdio.h>
#include <userenv.h>
void DisplayError(LPWSTR pszAPI)
{
LPVOID lpvMessageBuffer;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&lpvMessageBuffer, 0, NULL);
//
//... now display this string
//
wprintf(L"ERROR: API = %s.\n", pszAPI);
wprintf(L" error code = %d.\n", GetLastError());
wprintf(L" message = %s.\n", (LPWSTR)lpvMessageBuffer);
//
// Free the buffer allocated by the system
//
LocalFree(lpvMessageBuffer);
ExitProcess(GetLastError());
}
void wmain(int argc, WCHAR *argv[])
{
DWORD dwSize;
HANDLE hToken;
LPVOID lpvEnv;
PROCESS_INFORMATION pi = {0};
STARTUPINFO si = {0};
WCHAR szUserProfile[256] = L"";
si.cb = sizeof(STARTUPINFO);
if (argc != 4)
{
wprintf(L"Usage: %s [user@domain] [password] [cmd]", argv[0]);
wprintf(L"\n\n");
return;
}
//
// TO DO: change NULL to '.' to use local account database
//
if (!LogonUser(argv[1], NULL, argv[2], LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, &hToken))
DisplayError(L"LogonUser");
if (!CreateEnvironmentBlock(&lpvEnv, hToken, TRUE))
DisplayError(L"CreateEnvironmentBlock");
dwSize = sizeof(szUserProfile)/sizeof(WCHAR);
if (!GetUserProfileDirectory(hToken, szUserProfile, &dwSize))
DisplayError(L"GetUserProfileDirectory");
//
// TO DO: change NULL to '.' to use local account database
//
if (!CreateProcessWithLogonW(argv[1], NULL, argv[2],
LOGON_WITH_PROFILE, NULL, argv[3],
CREATE_UNICODE_ENVIRONMENT, lpvEnv, szUserProfile,
&si, &pi))
DisplayError(L"CreateProcessWithLogonW");
if (!DestroyEnvironmentBlock(lpvEnv))
DisplayError(L"DestroyEnvironmentBlock");
CloseHandle(hToken);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
Requisiti
Requisito | Valore |
---|---|
Client minimo supportato | Windows XP [solo app desktop] |
Server minimo supportato | Windows Server 2003 [solo app desktop] |
Piattaforma di destinazione | Windows |
Intestazione | winbase.h (include Windows.h) |
Libreria | Advapi32.lib |
DLL | Advapi32.dll |