Emprunt d'identité
Certains systèmes de fichiers peuvent trouver utile d’effectuer des opérations pour le compte de l’appelant d’origine. Par exemple, un système de fichiers réseau peut avoir besoin de capturer les informations de sécurité de l’appelant au moment de l’ouverture d’un fichier afin qu’une opération ultérieure puisse être effectuée à l’aide des informations d’identification appropriées. Il existe sans aucun doute de nombreux autres cas spéciaux où ce type de fonctionnalité est utile, à la fois dans un système de fichiers et dans des applications spécifiques.
Les routines clés nécessaires à l’emprunt d’identité sont les suivantes :
PsImpersonateClientSeImpersonateClientEx-initie l’emprunt d’identité. Sauf indication d’un thread spécifique, l’emprunt d’identité est effectué dans le contexte de thread actuel.
PsRevertToSelf met fin à l’emprunt d’identité dans le contexte de thread actuel.
PsReferencePrimaryToken contient une référence sur le jeton principal (processus) pour le processus spécifié. Cette fonction peut être utilisée pour capturer le jeton pour n’importe quel processus sur le système.
PsDereferencePrimaryToken--libère une référence sur un jeton principal précédemment référencé.
SeCreateClientSecurityFromSubjectContext: retourne un contexte de sécurité client utile pour l’emprunt d’identité à partir d’un contexte d’objet (fourni au FSD pendant la gestion des IRP_MJ_CREATE , par exemple).
SeCreateClientSecurity : crée un contexte de sécurité client basé sur les informations d’identification de sécurité d’un thread existant sur le système.
ImpersonateSecurityContext : emprunte l’identité du contexte de sécurité au sein de ksecdd.sys, le service de sécurité du noyau.
RevertSecurityContext : met fin à l’emprunt d’identité dans ksecdd.sys, le service de sécurité du noyau.
L’emprunt d’identité est simple à implémenter. L’exemple de code suivant illustre l’emprunt d’identité de base :
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;
}
Il existe de nombreuses variantes de ce code d’emprunt d’identité qui sont disponibles pour les développeurs de systèmes de fichiers, mais cela fournit une illustration de base de la technique.