Equipos de sobremesa y estaciones de ventana de CreateProcessAsUser()

Resumen

Cuando se inicia un proceso por medio de la función CreateProcessAsUser , el proceso se iniciará en una estación de ventana y escritorio combinación basándose en el valor de lpDesktop en el parámetro de la estructura STARTUPINFO :

  • Si se especifica una combinación de la estación de ventana y escritorio en el miembro lpDesktop, el sistema intentará iniciar el proceso en la estación de ventana y el escritorio.
  • Si el miembro lpDesktop se inicializa en NULL, el sistema intentará utilizar de la misma estación de ventana y escritorio como el proceso de llamada si el sistema está asociado a la estación de ventana interactiva.
  • Si no se inicializa el miembro lpDesktop en NULL, el sistema creará una nueva estación de ventana y escritorio que no puede ver.
  • Si el sistema se inicializa con la cadena vacía, "", creará una nueva estación de ventana y escritorio que no puede ver, o si uno se ha creado mediante una llamada anterior utilizando el mismo testigo, la estación de ventana existente de acceso y se utilizará el escritorio.

Más información

En ocasiones, el proceso puede no iniciarse y podría aparecer alguno de los siguientes mensajes de error:

Mensaje de error 1
Error al inicializar el \system32\user32.dll biblioteca dinámicos < system >. El proceso está terminando de forma anormal.
Mensaje de error 2
Error de inicialización de la biblioteca dinámica < sistema > de \system32\kernel32.dll. El proceso está terminando de forma anormal.
El mensaje de error se produce cuando el proceso que inició hace que la inicialización de código en ambos el archivo User32.dll o fallan debido a una llamada a la API del proceso iniciado que no tiene el archivo Kernel32.dll corrija el acceso de seguridad a la estación de ventana destino o del escritorio. Por ejemplo, si el proceso que se inició estaba intentando crear una ventana, el proceso tendría que tener acceso DESKTOP_CREATEWINDOW para el objeto de escritorio. Si el proceso no se ha concedido este derecho, que se produciría un error en el archivo User32.dll, lo que ocasionaría que aparezca en el cuadro de error del sistema y el proceso de acceso no se iniciarán.


Nota: A veces el proceso puede iniciar, pero no dibujar correctamente su GUI. El mejor método para resolver estos y otro acceso potencial relacionado con problemas consiste en conceder al usuario acceso completo para el destino de la estación de ventana y el escritorio. Por ejemplo, si desea que el proceso que se inicia con la función CreateProcessAsUser interactivos, especifique la siguiente combinación de estación de ventana y escritorio:
winsta0\default

Windows 2000 y Windows XP

Una nueva API se introdujo a partir de Windows 2000, CreateProcessWithLogonW(). Si el miembro lpDesktop de la estructura STARTUPINFO se inicializa en NULL o "", implementación de CreateProcessWithLogonW() agrega permisos para la cuenta de usuario a la estación de ventana heredado y escritorio. Si la aplicación especifica un escritorio en el miembro lpDesktop, es responsabilidad de la aplicación para agregar el permiso para la cuenta de usuario a la estación de ventana especificado y el escritorio.


El código de ejemplo siguiente concede al usuario el acceso a la estación de ventana interactiva y el escritorio, el "winsta0\\default" franki. Acceso concedido se basa en el inicio de sesión identificador de seguridad (SID) de la franki de usuario.


Para obtener más información acerca de estaciones de ventana y escritorios, consulte la documentación del SDK de Win32.

Para obtener más información, haga clic en el siguiente número de artículo para verlo en Microsoft Knowledge Base:

Seguridad, servicios y el escritorio interactivo de 327618

Código de ejemplo

El siguiente código de ejemplo proporciona al usuario denominado "franki" acceso completo a la estación de ventana interactiva y el escritorio, el "winsta0\\default". La entrada de control de acceso (ACE) para cada objeto se basa en el inicio de sesión de franki SID. El código ejecuta el archivo Cmd.exe.


Nota: Una aplicación que muchos procesos se ejecuta como un servicio de programador que desee quitar la nueva ACE después de que el proceso se ha completado porque se acumulan las entradas ACE en la DACL de la estación de ventana y el objeto de escritorio.


Para obtener más información, haga clic en el siguiente número de artículo para verlo en Microsoft Knowledge Base:

185292 SetUserObjectSecurity devuelve ERROR_NOT_ENOUGH_QUOTA

   #define RTN_OK     0   #define RTN_ERROR 13

#define WINSTA_ALL (WINSTA_ACCESSCLIPBOARD | WINSTA_ACCESSGLOBALATOMS |
WINSTA_CREATEDESKTOP | WINSTA_ENUMDESKTOPS |
WINSTA_ENUMERATE | WINSTA_EXITWINDOWS |
WINSTA_READATTRIBUTES | WINSTA_READSCREEN |
WINSTA_WRITEATTRIBUTES | DELETE |
READ_CONTROL | WRITE_DAC |
WRITE_OWNER)

#define DESKTOP_ALL (DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
DESKTOP_JOURNALPLAYBACK | DESKTOP_JOURNALRECORD |
DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP |
DESKTOP_WRITEOBJECTS | DELETE |
READ_CONTROL | WRITE_DAC |
WRITE_OWNER)

#define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE |
GENERIC_EXECUTE | GENERIC_ALL)

#include <windows.h>
#include <stdio.h>

BOOL ObtainSid(

HANDLE hToken, // Handle to an process access token.
PSID *psid // ptr to the buffer of the logon sid
);

void RemoveSid(
PSID *psid // ptr to the buffer of the logon sid
);

BOOL AddTheAceWindowStation(

HWINSTA hwinsta, // handle to a windowstation
PSID psid // logon sid of the process
);

BOOL AddTheAceDesktop(

HDESK hdesk, // handle to a desktop
PSID psid // logon sid of the process
);

int main(void)
{
HANDLE hToken;
HDESK hdesk;
HWINSTA hwinsta;
PROCESS_INFORMATION pi;
PSID psid;
STARTUPINFO si;

//
// obtain an access token for the user fester
//
if (!LogonUser(
"franki",
NULL,
"franki",
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
&hToken
))
return RTN_ERROR;

//
// obtain a handle to the interactive windowstation
//
hwinsta = OpenWindowStation(
"winsta0",
FALSE,
READ_CONTROL | WRITE_DAC
);
if (hwinsta == NULL)
return RTN_ERROR;

HWINSTA hwinstaold = GetProcessWindowStation();

//
// set the windowstation to winsta0 so that you obtain the
// correct default desktop
//
if (!SetProcessWindowStation(hwinsta))
return RTN_ERROR;

//
// obtain a handle to the "default" desktop
//
hdesk = OpenDesktop(
"default",
0,
FALSE,
READ_CONTROL | WRITE_DAC |
DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS
);
if (hdesk == NULL)
return RTN_ERROR;

//
// obtain the logon sid of the user fester
//
if (!ObtainSid(hToken, &psid))
return RTN_ERROR;

//
// add the user to interactive windowstation
//
if (!AddTheAceWindowStation(hwinsta, psid))
return RTN_ERROR;

//
// add user to "default" desktop
//
if (!AddTheAceDesktop(hdesk, psid))
return RTN_ERROR;

//
// free the buffer for the logon sid
//
RemoveSid(&psid);

//
// close the handles to the interactive windowstation and desktop
//
CloseWindowStation(hwinsta);

CloseDesktop(hdesk);

//
// initialize STARTUPINFO structure
//
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "winsta0\\default";

//
// start the process
//
if (!CreateProcessAsUser(
hToken,
NULL,
"cmd.exe",
NULL,
NULL,
FALSE,
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi
))
return RTN_ERROR;

SetProcessWindowStation(hwinstaold); //set it back

//
// close the handles
//
CloseHandle(pi.hProcess);

CloseHandle(pi.hThread);

return RTN_OK;
}


BOOL ObtainSid(HANDLE hToken, PSID *psid)

{
BOOL bSuccess = FALSE; // assume function will
// fail
DWORD dwIndex;
DWORD dwLength = 0;
TOKEN_INFORMATION_CLASS tic = TokenGroups;
PTOKEN_GROUPS ptg = NULL;

__try
{
//
// determine the size of the buffer
//
if (!GetTokenInformation(
hToken,
tic,
(LPVOID)ptg,
0,
&dwLength
))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
ptg = (PTOKEN_GROUPS)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwLength
);
if (ptg == NULL)
__leave;
}
else
__leave;
}

//
// obtain the groups the access token belongs to
//
if (!GetTokenInformation(
hToken,
tic,
(LPVOID)ptg,
dwLength,
&dwLength
))
__leave;

//
// determine which group is the logon sid
//
for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++)
{
if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID)
== SE_GROUP_LOGON_ID)
{
//
// determine the length of the sid
//
dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);

//
// allocate a buffer for the logon sid
//
*psid = (PSID)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwLength
);
if (*psid == NULL)
__leave;

//
// obtain a copy of the logon sid
//
if (!CopySid(dwLength, *psid, ptg->Groups[dwIndex].Sid))
__leave;

//
// break out of the loop because the logon sid has been
// found
//
break;
}
}

//
// indicate success
//
bSuccess = TRUE;
}
__finally
{
//
// free the buffer for the token group
//
if (ptg != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
}

return bSuccess;

}

void RemoveSid(PSID *psid)
{
HeapFree(GetProcessHeap(), 0, (LPVOID)*psid);
}

BOOL AddTheAceWindowStation(HWINSTA hwinsta, PSID psid)
{

ACCESS_ALLOWED_ACE *pace;
ACL_SIZE_INFORMATION aclSizeInfo;
BOOL bDaclExist;
BOOL bDaclPresent;
BOOL bSuccess = FALSE; // assume function will
//fail
DWORD dwNewAclSize;
DWORD dwSidSize = 0;
DWORD dwSdSizeNeeded;
PACL pacl;
PACL pNewAcl;
PSECURITY_DESCRIPTOR psd = NULL;
PSECURITY_DESCRIPTOR psdNew = NULL;
PVOID pTempAce;
SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
unsigned int i;

__try
{
//
// obtain the dacl for the windowstation
//
if (!GetUserObjectSecurity(
hwinsta,
&si,
psd,
dwSidSize,
&dwSdSizeNeeded
))
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
psd = (PSECURITY_DESCRIPTOR)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwSdSizeNeeded
);
if (psd == NULL)
__leave;

psdNew = (PSECURITY_DESCRIPTOR)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwSdSizeNeeded
);
if (psdNew == NULL)
__leave;

dwSidSize = dwSdSizeNeeded;

if (!GetUserObjectSecurity(
hwinsta,
&si,
psd,
dwSidSize,
&dwSdSizeNeeded
))
__leave;
}
else
__leave;

//
// create a new dacl
//
if (!InitializeSecurityDescriptor(
psdNew,
SECURITY_DESCRIPTOR_REVISION
))
__leave;

//
// get dacl from the security descriptor
//
if (!GetSecurityDescriptorDacl(
psd,
&bDaclPresent,
&pacl,
&bDaclExist
))
__leave;

//
// initialize
//
ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION));
aclSizeInfo.AclBytesInUse = sizeof(ACL);

//
// call only if the dacl is not NULL
//
if (pacl != NULL)
{
// get the file ACL size info
if (!GetAclInformation(
pacl,
(LPVOID)&aclSizeInfo,
sizeof(ACL_SIZE_INFORMATION),
AclSizeInformation
))
__leave;
}

//
// compute the size of the new acl
//
dwNewAclSize = aclSizeInfo.AclBytesInUse + (2 *
sizeof(ACCESS_ALLOWED_ACE)) + (2 * GetLengthSid(psid)) - (2 *
sizeof(DWORD));

//
// allocate memory for the new acl
//
pNewAcl = (PACL)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwNewAclSize
);
if (pNewAcl == NULL)
__leave;

//
// initialize the new dacl
//
if (!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION))
__leave;

//
// if DACL is present, copy it to a new DACL
//
if (bDaclPresent) // only copy if DACL was present
{
// copy the ACEs to our new ACL
if (aclSizeInfo.AceCount)
{
for (i=0; i < aclSizeInfo.AceCount; i++)
{
// get an ACE
if (!GetAce(pacl, i, &pTempAce))
__leave;

// add the ACE to the new ACL
if (!AddAce(
pNewAcl,
ACL_REVISION,
MAXDWORD,
pTempAce,
((PACE_HEADER)pTempAce)->AceSize
))
__leave;
}
}
}

//
// add the first ACE to the windowstation
//
pace = (ACCESS_ALLOWED_ACE *)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psid) -
sizeof(DWORD
));
if (pace == NULL)
__leave;

pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
pace->Header.AceFlags = CONTAINER_INHERIT_ACE |
INHERIT_ONLY_ACE |

OBJECT_INHERIT_ACE;
pace->Header.AceSize = sizeof(ACCESS_ALLOWED_ACE) +

GetLengthSid(psid) - sizeof(DWORD);
pace->Mask = GENERIC_ACCESS;

if (!CopySid(GetLengthSid(psid), &pace->SidStart, psid))
__leave;

if (!AddAce(
pNewAcl,
ACL_REVISION,
MAXDWORD,
(LPVOID)pace,
pace->Header.AceSize
))
__leave;

//
// add the second ACE to the windowstation
//
pace->Header.AceFlags = NO_PROPAGATE_INHERIT_ACE;
pace->Mask = WINSTA_ALL;

if (!AddAce(
pNewAcl,
ACL_REVISION,
MAXDWORD,
(LPVOID)pace,
pace->Header.AceSize
))
__leave;

//
// set new dacl for the security descriptor
//
if (!SetSecurityDescriptorDacl(
psdNew,
TRUE,
pNewAcl,
FALSE
))
__leave;

//
// set the new security descriptor for the windowstation
//
if (!SetUserObjectSecurity(hwinsta, &si, psdNew))
__leave;

//
// indicate success
//
bSuccess = TRUE;
}
__finally
{
//
// free the allocated buffers
//
if (pace != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)pace);

if (pNewAcl != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)pNewAcl);

if (psd != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)psd);

if (psdNew != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)psdNew);
}

return bSuccess;

}

BOOL AddTheAceDesktop(HDESK hdesk, PSID psid)
{

ACL_SIZE_INFORMATION aclSizeInfo;
BOOL bDaclExist;
BOOL bDaclPresent;
BOOL bSuccess = FALSE; // assume function will
// fail
DWORD dwNewAclSize;
DWORD dwSidSize = 0;
DWORD dwSdSizeNeeded;
PACL pacl;
PACL pNewAcl;
PSECURITY_DESCRIPTOR psd = NULL;
PSECURITY_DESCRIPTOR psdNew = NULL;
PVOID pTempAce;
SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
unsigned int i;

__try
{
//
// obtain the security descriptor for the desktop object
//
if (!GetUserObjectSecurity(
hdesk,
&si,
psd,
dwSidSize,
&dwSdSizeNeeded
))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
psd = (PSECURITY_DESCRIPTOR)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwSdSizeNeeded
);
if (psd == NULL)
__leave;

psdNew = (PSECURITY_DESCRIPTOR)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwSdSizeNeeded
);
if (psdNew == NULL)
__leave;

dwSidSize = dwSdSizeNeeded;

if (!GetUserObjectSecurity(
hdesk,
&si,
psd,
dwSidSize,
&dwSdSizeNeeded
))
__leave;
}
else
__leave;
}

//
// create a new security descriptor
//
if (!InitializeSecurityDescriptor(
psdNew,
SECURITY_DESCRIPTOR_REVISION
))
_ _leave;

//
// obtain the dacl from the security descriptor
//
if (!GetSecurityDescriptorDacl(
psd,
&bDaclPresent,
&pacl,
&bDaclExist
))
__leave;

//
// initialize
//
ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION));
aclSizeInfo.AclBytesInUse = sizeof(ACL);

//
// call only if NULL dacl
//
if (pacl != NULL)
{
//
// determine the size of the ACL info
//
if (!GetAclInformation(
pacl,
(LPVOID)&aclSizeInfo,
sizeof(ACL_SIZE_INFORMATION),
AclSizeInformation
))
__leave;
}

//
// compute the size of the new acl
//
dwNewAclSize = aclSizeInfo.AclBytesInUse +
sizeof(ACCESS_ALLOWED_ACE) +
GetLengthSid(psid) - sizeof(DWORD);

//
// allocate buffer for the new acl
//
pNewAcl = (PACL)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwNewAclSize
);
if (pNewAcl == NULL)
__leave;

//
// initialize the new acl
//
if (!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION))
__leave;

//
// if DACL is present, copy it to a new DACL
//
if (bDaclPresent) // only copy if DACL was present
{
// copy the ACEs to our new ACL
if (aclSizeInfo.AceCount)
{
for (i=0; i < aclSizeInfo.AceCount; i++)
{
// get an ACE
if (!GetAce(pacl, i, &pTempAce))
__leave;

// add the ACE to the new ACL
if (!AddAce(
pNewAcl,
ACL_REVISION,
MAXDWORD,
pTempAce,
((PACE_HEADER)pTempAce)->AceSize
))
__leave;
}
}
}

//
// add ace to the dacl
//
if (!AddAccessAllowedAce(
pNewAcl,
ACL_REVISION,
DESKTOP_ALL,
psid
))
__leave;

//
// set new dacl to the new security descriptor
//
if (!SetSecurityDescriptorDacl(
psdNew,
TRUE,
pNewAcl,
FALSE
))
__leave;

//
// set the new security descriptor for the desktop object
//
if (!SetUserObjectSecurity(hdesk, &si, psdNew))
__leave;

//
// indicate success
//
bSuccess = TRUE;
}
__finally
{
//
// free buffers
//
if (pNewAcl != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)pNewAcl);

if (psd != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)psd);

if (psdNew != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)psdNew);
}

return bSuccess;
}

Propiedades

Id. de artículo: 165194 - Última revisión: 01/09/2017 - Revisión: 1

Comentarios