Поделиться через


Олицетворение

В некоторых файловых системах может оказаться полезным выполнять операции от имени исходного вызывающего объекта. Например, сетевой файловой системе может потребоваться записать сведения о безопасности вызывающего абонента во время открытия файла, чтобы можно было выполнить последующую операцию с использованием соответствующих учетных данных. Несомненно, существует множество других особых случаев, когда этот тип функции полезен как в файловой системе, так и в конкретных приложениях.

Основные процедуры, необходимые для олицетворения:

  • PsImpersonateClientSeImpersonateClientEx — инициирует олицетворение. Если не указан конкретный поток, олицетворение выполняется в контексте текущего потока.

  • PsRevertToSelf завершает олицетворение в контексте текущего потока.

  • PsReferencePrimaryToken — содержит ссылку на основной маркер (процесс) для указанного процесса. Эта функция может использоваться для записи маркера для любого процесса в системе.

  • PsDereferencePrimaryToken — освобождает ссылку на ранее упоминавшийся первичный токен.

  • SeCreateClientSecurityFromSubjectContext — возвращает контекст безопасности клиента, полезный для олицетворения из контекста субъекта (например, предоставляется FSD во время обработки IRP_MJ_CREATE ).

  • SeCreateClientSecurity создает контекст безопасности клиента на основе учетных данных безопасности существующего потока в системе.

  • ImpersonateSecurityContext — олицетворяет контекст безопасности в ksecdd.sys, службе безопасности ядра.

  • RevertSecurityContext — завершает олицетворение в ksecdd.sys, службе безопасности ядра.

Олицетворение — это прямая реализация. В следующем примере кода демонстрируется базовое олицетворение:

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;
}

Существует множество вариантов этого кода олицетворения, доступных разработчикам файловых систем, но это дает базовую иллюстрацию метода.