Как правильно согласовать EXPLICIT_ACCESS с jedi-winutils для SetEntriesInAclA?

Я пытаюсь создать новый ACL из массива EXPLICIT_ACCESS_A в Free Pascal, используя SetEntriesInAclA, но продолжаю получать код ошибки 87 (недопустимый параметр) от SetEntriesInAclA со следующим кодом:

uses
  sysutils,
  JwaWinNT,
  JwaAclApi,
  JwaAccCtrl,
  JwaSDDL,
  jwawinbase,
  jwawinsta,
  jwawintype,
  jwawinerror; 

function SetupAccess(owner: jwawinnt.PSID; var acl: jwawinnt.PACL): bool;
  const
    EA_COUNT = 3;
  var
    sidAuthWorld: jwawinnt.SID_IDENTIFIER_AUTHORITY;
    sidAuthNT: jwawinnt.SID_IDENTIFIER_AUTHORITY;
    everyoneSID: jwawinnt.PSID;
    adminSID: jwawinnt.PSID;
    ea: Array[0..(EA_COUNT-1)] of jwaaccctrl.EXPLICIT_ACCESS_A;
    status: jwawintype.DWORD;
  begin
    try
      begin
        WriteLn(IntToStr(SizeOf(jwaaccctrl.EXPLICIT_ACCESS_A)));
        sidAuthWorld := jwawinnt.SECURITY_WORLD_SID_AUTHORITY;
        sidAuthNT := jwawinnt.SECURITY_NT_AUTHORITY;

        if not (jwawinbase.AllocateAndInitializeSid(@sidAuthWorld, 1, jwawinnt.SECURITY_WORLD_RID,
            0, 0, 0, 0, 0, 0, 0, everyoneSID)
          and AllocateAndInitializeSid(@sidAuthNT, 2, jwawinnt.SECURITY_BUILTIN_DOMAIN_RID,
          jwawinnt.DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, adminSID)) then
        begin
          WriteLn('Could not allocate SIDs: ' + SysErrorMessage(getLastError()));
          Result := false;
        end
        else
        begin
          jwawinbase.ZeroMemory(@ea, EA_COUNT * sizeOf(EXPLICIT_ACCESS_A));

          ea[0].grfAccessPermissions := GENERIC_ALL;
          ea[0].grfAccessMode := DENY_ACCESS;
          ea[0].grfInheritance := NO_INHERITANCE;
          ea[0].Trustee.MultipleTrusteeOperation := NO_MULTIPLE_TRUSTEE;
          ea[0].Trustee.pMultipleTrustee := nil;
          ea[0].Trustee.TrusteeForm := TRUSTEE_IS_SID;
          ea[0].Trustee.TrusteeType := TRUSTEE_IS_WELL_KNOWN_GROUP;
          ea[0].Trustee.ptstrName := pointer(everyoneSID);

          ea[1].grfAccessPermissions := GENERIC_ALL;
          ea[1].grfAccessMode := SET_ACCESS;
          ea[1].grfInheritance := NO_INHERITANCE;
          ea[1].Trustee.MultipleTrusteeOperation := NO_MULTIPLE_TRUSTEE;
          ea[1].Trustee.pMultipleTrustee := nil;
          ea[1].Trustee.TrusteeForm := TRUSTEE_IS_SID;
          ea[1].Trustee.TrusteeType := TRUSTEE_IS_GROUP;
          ea[1].Trustee.ptstrName := pointer(adminSID);

          ea[2].grfAccessPermissions := GENERIC_ALL;
          ea[2].grfAccessMode := SET_ACCESS;
          ea[2].grfInheritance := NO_INHERITANCE;
          ea[2].Trustee.MultipleTrusteeOperation := NO_MULTIPLE_TRUSTEE;
          ea[2].Trustee.pMultipleTrustee := nil;
          ea[2].Trustee.TrusteeForm := TRUSTEE_IS_SID;
          ea[2].Trustee.TrusteeType := TRUSTEE_IS_USER;
          ea[2].Trustee.ptstrName := pointer(owner);

          status := jwaaclapi.SetEntriesInAclA(2, @ea, nil, acl);
          if status = ERROR_SUCCESS then
            Result := true
          else
          begin
            WriteLn('Error in SetEntriesInAcl: ' + IntToStr(status));
            Result := false;
          end;
        end;
      end
    finally
      If Assigned(everyoneSID) then
        jwawinbase.FreeSID(everyoneSID);
      If Assigned(adminSID) then
        jwawinbase.FreeSID(adminSID);
    end
  end;

При поиске проблемы я наткнулся на этот вопрос, который намекнул, что проблема, вероятно, связана с выравниванием записи EXPLICIT_ACCESS_A.

И, конечно же, WriteLn(IntToStr(SizeOf(jwaaccctrl.EXPLICIT_ACCESS_A))); показывает, что он имеет размер 20. Это потому, что jedi объявляет структуру как packed. Из связанного вопроса я понял, что EXPLICIT_ACCESS_A должен иметь размер 24, но после тестирования на С++ он на самом деле кажется 32.

Я также попытался скопировать структуры EXPLICIT_ACCESS_A и TRUSTEE_A в свой модуль и удалить ключевое слово packed. Это дало структуры размером 24, но все та же ошибка.

В заключение: могу ли я заставить приведенный выше код работать с джедаем или это ошибка/упущение в джедаях?

Также обратите внимание, что я выполняю кросс-компиляцию с x64 на x86, используя Lazarus 2.0.4 и FPC 3.0.4.


person sternenseemann    schedule 20.11.2019    source источник
comment
Пытался переопределить структуру EXPLICIT_ACCESS. И замените тип enum на DWORD.   -  person Drake Wu    schedule 26.11.2019
comment
@DrakeWu-MSFT Это действительно работает, что говорит о том, что установка минимального размера перечисления на 4 решит проблему. Интересно, почему FPC игнорирует как директиву MINENUMSIZE, так и параметр командной строки -CPPACKENUM=4.   -  person sternenseemann    schedule 27.11.2019
comment
Настоящая проблема заключается в том, что JwaAccCtrl использует размер перечисления 1, на который я никак не могу повлиять. Я не думаю, что это задумано, но fpc 3.0.4 поставляется именно так.   -  person sternenseemann    schedule 27.11.2019
comment
Я открыл отчет об ошибке для FPC, посмотрим, к чему это приведет.   -  person sternenseemann    schedule 27.11.2019
comment
Я обнаружил, что этот отчет помечен как решенный. Не могли бы вы организовать ответ здесь и отметить себя, чтобы помочь людям, у которых такая же проблема?   -  person Drake Wu    schedule 03.12.2019


Ответы (2)


Для 32-битной структуры EXPLICIT_ACCESS_A должно быть 32 байта. Запись, вероятно, была упакована, потому что она содержит объединение. Я проверил это с помощью Jedi ApiLib в Delphi, он возвращает правильный размер:

program SizeTest;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  JwaAccCtrl;

begin
  WriteLn(Format('EXPLICIT_ACCESS_A size: %d', [SizeOf(EXPLICIT_ACCESS_A)]));

Вывод:

Вывод

В Delphi {$MINENUMSIZE 4} используется для принудительной установки перечисления в 4 байта (как в C), возможно, вам нужно установить это в Lazarus/FPC?

person Remko    schedule 20.11.2019
comment
У меня это не работает в Lazarus/FPC. Я также пытался использовать различные директивы компилятора, такие как CODEALIGN, ALIGN, PACKRECORD, а также, как вы предложили, MINENUMSIZE. Также установка {$MODE DELPHI} ничего не меняет. - person sternenseemann; 25.11.2019
comment
Директивы компилятора влияют только на текущий блок, проблема в том, что Jedi по какой-то причине использует размер перечисления 1 в моем случае. - person sternenseemann; 27.11.2019
comment
Все единицы Jwa по умолчанию включают JediAPILib.inc, который основан на jedi.inc и начинается с {$A+} {record alignment on 4 byte boundaries} и {$Z4} {enum size is 4 bytes}. - person Remko; 29.11.2019

В отличие от того, что я ожидал, проблема была связана не с выравниванием записей, а с размером перечислений в записи. Запись EXPLICIT_ACCESS_A и ее подзапись имеют в общей сложности 8 полей, которые, как ожидается, будут иметь размер 4 байта для WinApi (на 32-разрядной версии), в результате чего общий размер составит 32 байта (на 32-разрядной версии). В 64-разрядной версии некоторые поля больше, но размер перечисления по-прежнему должен быть равен 4. Если размер перечисления FPC не равен 4, это предположение нарушается, и WinApi возвращает код ошибки 87.

Предоставленный мной код верен и теоретически должен работать. Проблема возникла из-за ошибки в версии Jedi, предоставленной FPC. Там размер Enum был ошибочно сброшен до 1 путем включения в JediApiLib.inc. Это было исправлено в FPC trunk/Revision 43608 и, надеюсь, будет включено в следующий выпуск. Вы можете ознакомиться с отчетом об ошибке здесь.

До тех пор существует обходной путь, который досадно включает в себя переопределение используемых записей, так как вы можете просто заменить все перечисления на DWORDs, чтобы установить правильный размер. Новые типы будут выглядеть так:

type
  TRUSTEE_FIX = packed record
    pMultipleTrustee: Pointer;
    MultipleTrusteeOperation: DWORD;
    TrusteeForm: DWORD;
    TrusteeType: DWORD;
    ptstrName: LPSTR;
  end;

  EXPLICIT_ACCESS_FIX = packed record
    grfAccessPermissions: DWORD;
    grfAccessMode: DWORD;
    grfInheritance: DWORD;
    Trustee: TRUSTEE_FIX;
  end; 

Конечно, вам нужно будет преобразовать значения Enum в DWORD при заполнении записи EXPLICIT_ACCESS, как здесь, например:

jwawinbase.ZeroMemory(@ea, EA_COUNT * sizeOf(EXPLICIT_ACCESS_FIX));

ea[0].grfAccessPermissions := GENERIC_ALL;
ea[0].grfAccessMode := DWORD(DENY_ACCESS);
ea[0].grfInheritance := NO_INHERITANCE;
ea[0].Trustee.MultipleTrusteeOperation := DWORD(NO_MULTIPLE_TRUSTEE);
ea[0].Trustee.pMultipleTrustee := nil;
ea[0].Trustee.TrusteeForm := DWORD(TRUSTEE_IS_SID);
ea[0].Trustee.TrusteeType := DWORD(TRUSTEE_IS_WELL_KNOWN_GROUP);
ea[0].Trustee.ptstrName := pointer(everyoneSID);

status := jwaaclapi.SetEntriesInAclA(EA_COUNT, @ea, nil, acl);
person sternenseemann    schedule 04.12.2019