Representação
Alguns sistemas de arquivos podem achar útil executar operações em nome do chamador original. Por exemplo, um sistema de arquivos de rede pode precisar capturar as informações de segurança do chamador no momento em que um arquivo é aberto para que uma operação subsequente possa ser executada usando as credenciais apropriadas. Sem dúvida, há vários outros casos especiais em que esse tipo de recurso é útil, tanto em um sistema de arquivos quanto em aplicativos específicos.
As principais rotinas necessárias para a representação incluem:
PsImpersonateClientSeImpersonateClientEx – inicia a representação. A menos que um thread específico seja indicado, a representação é feita no contexto de thread atual.
PsRevertToSelf – encerra a representação dentro do contexto de thread atual.
PsReferencePrimaryToken – mantém uma referência no token primário (processo) para o processo especificado. Essa função pode ser usada para capturar o token para qualquer processo no sistema.
PsDereferencePrimaryToken – lança uma referência em um token primário referenciado anteriormente.
SeCreateClientSecurityFromSubjectContext – retorna um contexto de segurança do cliente útil para representação de um contexto de assunto (fornecido ao FSD durante o tratamento de IRP_MJ_CREATE , por exemplo).
SeCreateClientSecurity – cria um contexto de segurança do cliente com base nas credenciais de segurança de um thread existente no sistema.
ImpersonateSecurityContext – representa o contexto de segurança no ksecdd.sys, o serviço de segurança do kernel.
RevertSecurityContext – encerra a representação no ksecdd.sys, o serviço de segurança do kernel.
A representação é direta para implementar. O exemplo de código a seguir demonstra a representação básica:
NTSTATUS PerformSpecialTask(IN PFSD_CONTEXT Context)
{
BOOLEAN CopyOnOpen;
BOOLEAN EffectiveOnly;
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
NTSTATUS Status;
PACCESS_TOKEN oldToken;
//
// We need to perform a task in the system process context
//
if (NULL == Context->SystemProcess) {
return STATUS_NO_TOKEN;
}
//
// Save the existing token, if any (otherwise NULL)
//
oldToken = PsReferenceImpersonationToken(PsGetCurrentThread(),
&CopyOnOpen,
&EffectiveOnly,
&ImpersonationLevel);
Status = PsImpersonateClient( PsGetCurrentThread(),
Context->SystemProcess,
TRUE,
TRUE,
SecurityImpersonation);
if (!NT_SUCCESS(Status)) {
if (oldToken)
PsDereferenceImpersonationToken(oldToken);
return Status;
}
//
// Perform task - whatever it is
//
//
// Restore to previous impersonation level
//
if (oldToken) {
Status = PsImpersonateClient(PsGetCurrentThread(),
oldToken,
CopyOnOpen,
EffectiveOnly,
ImpersonationLevel);
if (!NT_SUCCESS(Status)) {
//
// This is bad - we can't restore, we can't leave it this way
//
PsRevertToSelf();
}
PsDereferenceImpersonationToken(oldToken);
} else {
PsRevertToSelf();
}
return Status;
}
Há várias variantes desse código de representação disponíveis para desenvolvedores de sistemas de arquivos, mas isso fornece uma ilustração básica da técnica.