servicios servicio net instalador framework desarrollo como aplicaciones aplicacion c++ windows service impersonation

c++ - net - ¿Cómo suplantar a un usuario de un servicio correctamente?



servicios was (1)

No necesita llamar a ImpersonateLoggedOnUser() ya que está pasando el token del usuario a LoadUserProfile() . Llame a ImpersonateLoggedOnUser() solo si necesita llamar a API que no le permiten pasar un token de usuario.

Si lee el resto de la documentación de LoadUserProfile() , dice:

El proceso de llamada debe tener los privilegios SE_RESTORE_NAME y SE_BACKUP_NAME.

Al suplantar al usuario para el que está intentando cargar un perfil, es probable que pierda esos privilegios. Así que no se haga pasar por el usuario.

Actualización: prueba algo como esto:

// get the active console session ID of the logged on user DWORD dwSessionID = WTSGetActiveConsoleSessionId(); if ( dwSessionID == 0xFFFFFFFF ) { ShowErrorText( "WTSGetActiveConsoleSessionId failed.", GetLastError( ), true ); return; } if ( !WTSQueryUserToken( dwSessionID, &hToken ) ) { ShowErrorText( "WTSQueryUserToken failed.", GetLastError( ), true ); return; } // duplicate the token HANDLE hDuplicated = NULL; if ( !DuplicateToken( hToken, SecurityImpersonation, &hDuplicated ) ) { ShowErrorText( "DuplicateToken failed.", GetLastError( ), true ); CloseHandle( hToken ); return; } // retrieve the DC name if ( !GetPrimaryDC( DC ) ) { ShowErrorText( "GetPrimaryDC failed.", 0, true ); CloseHandle( hDuplicated ); CloseHandle( hToken ); return; } PROFILEINFO lpProfileInfo; ZeroMemory( &lpProfileInfo, sizeof( PROFILEINFO ) ); lpProfileInfo.dwSize = sizeof( PROFILEINFO ); lpProfileInfo.lpUserName = CurrentUser; // get type of profile. roaming, mandatory or temporary USER_INFO_4 *UserInfo = NULL; int ret = GetTypeOfProfile(); if ( ret == 2 ) { // if roaming profile get the path of it if ( NetUserGetInfo( DC, CurrentUser, 4, (LPBYTE*)&UserInfo) != NERR_Success ) { ShowErrorText( "NetUserGetInfo failed.", 0, true ); CloseHandle( hDuplicated ); CloseHandle( hToken ); return; } lpProfileInfo.lpProfilePath = UserInfo->usri3_profile; } if ( !LoadUserProfile( hDuplicated, &lpProfileInfo ) ) { ShowErrorText( "LoadUserProfile failed.", GetLastError(), true ); if ( UserInfo ) NetApiBufferFree(UserInfo); CloseHandle( hDuplicated ); CloseHandle( hToken ); return; } if ( UserInfo ) NetApiBufferFree(UserInfo); ShowErrorText( "LoadUserProfile succeeded.", 0, true ); //do some stuff if ( !UnloadUserProfile( hDuplicated, lpProfileInfo.hProfile ) ) { ShowErrorText( "UnloadUserProfile failed.", GetLastError( ), true ); } else { ShowErrorText( "UnloadUserProfile succeeded.", 0, true ); } CloseHandle( hDuplicated ); CloseHandle( hToken );

En cuanto al Registro, el manejador hProfile es el HKEY abierto para el árbol HKEY_CURRENT_USER del usuario. Simpy lo HKEY de HANDLE a HKEY al pasarlo a las funciones de la API de registro. Ya está abierto, por lo que no necesita llamar a RegOpenKeyEx() para RegOpenKeyEx() a abrir esa misma clave, pero puede usarla como clave raíz al crear / abrir subclaves, o leer / escribir valores en la clave raíz.

Estoy trabajando en un servicio, que debe suplantar al usuario que inició sesión.

Mi código hasta el momento, con manejo básico de errores:

// get the active console session ID of the logged on user if ( !WTSQueryUserToken( WTSGetActiveConsoleSessionId(), &hToken ) ) { ShowErrorText( "WTSQueryUserToken failed.", GetLastError( ), true ); return; } HANDLE hDuplicated; // duplicate the token if ( !DuplicateToken( hToken, SecurityImpersonation, &hDuplicated ) ) { ShowErrorText( "DuplicateToken failed.", GetLastError( ), true ); } else { ShowErrorText( "DuplicateToken succeeded.", 0, true ); } // impersonate the logged on user if ( !ImpersonateLoggedOnUser( hToken ) ) { ShowErrorText( "ImpersonateLoggedOnUser failed.", GetLastError(), true ); return; } // retrieve the DC name if ( !GetPrimaryDC( DC ) ) { ShowErrorText( "GetPrimaryDC failed.", 0, true ); } PROFILEINFO lpProfileInfo; ZeroMemory( &lpProfileInfo, sizeof( PROFILEINFO ) ); lpProfileInfo.dwSize = sizeof( PROFILEINFO ); lpProfileInfo.lpUserName = CurrentUser; // get type of profile. roaming, mandatory or temporary int ret = GetTypeOfProfile(); if ( ret == 2 ) { // if roaming profile get the path of it if ( !GetRoamingProfilePath( DC, CurrentUser, RoamingProfilePath ) ) { ShowErrorText( "Failed to retrieve roaming profile path.", GetLastError(), true ); } } if ( RevertToSelf( ) ) { ShowErrorText( "Impersonation ended successfully.", 0, true ); } if ( !LoadUserProfile( hDuplicated, &lpProfileInfo ) ) { ShowErrorText( "LoadUserProfile failed.", GetLastError(), true ); } else { ShowErrorText( "LoadUserProfile succeeded.", 0, true ); } //do some stuff if ( !UnloadUserProfile( hDuplicated, lpProfileInfo.hProfile ) ) { ShowErrorText( "UnloadUserProfile failed.", GetLastError( ), true ); } else { ShowErrorText( "UnloadUserProfile succeeded.", 0, true ); } if ( !ImpersonateLoggedOnUser( hToken ) ) { ShowErrorText( "ImpersonateLoggedOnUser failed.", GetLastError( ), true ); return; }

De acuerdo con MSDN:

Cuando un usuario inicia sesión de manera interactiva, el sistema carga automáticamente el perfil del usuario. Si un servicio o una aplicación suplanta a un usuario, el sistema no carga el perfil del usuario. Por lo tanto, el servicio o la aplicación debe cargar el perfil del usuario con LoadUserProfile.

Los servicios y aplicaciones que llaman a LoadUserProfile deben verificar si el usuario tiene un perfil itinerante. Si el usuario tiene un perfil itinerante, especifique su ruta como el miembro lpProfilePath de PROFILEINFO. Para recuperar la ruta del perfil móvil del usuario, puede llamar a la función NetUserGetInfo, especificando el nivel de información 3 o 4.

Tras el regreso exitoso, el miembro hProfile de PROFILEINFO es un identificador de clave de registro abierto en la raíz del subárbol del usuario. Se ha abierto con acceso completo (KEY_ALL_ACCESS). Si un servicio que se hace pasar por un usuario necesita leer o escribir en el archivo de registro del usuario, use este controlador en lugar de HKEY_CURRENT_USER. No cierre el mango hProfile. En cambio, páselo a la función UnloadUserProfile.

Si uso mi código como está ahora, entonces funciona. Sin embargo, es un poco extraño, porque primero tengo que suplantar al usuario que ha iniciado sesión y luego termino la suplantación, para cargar el perfil de los usuarios. Si no termino la suplantación, LoadUserProfile fallará con el error 5 (acceso denegado). ¿Y después de que LoadUserProfile tuvo éxito, debería suplantar al usuario nuevamente?

Entonces mi pregunta es, ¿esto se debe hacer de esta manera, o estoy haciendo algo mal? Otra pregunta es, que si LoadUserProfile tuvo éxito, podría usar hProfile como Handle para el registro de usuarios conectados. La pregunta es ¿cómo? Porque para usar RegOpenKeyEy y RegSetValueEx necesito pasar un HKEY, no un HANDLE. Entonces, ¿cómo puedo usar este mango?

¡Gracias!