修改 SAM 密码策略时出错

问题描述 投票:0回答:1

我用 pascal 编写了一个程序,使用 sam api 启用/禁用“密码必须满足复杂性要求”。每个函数都返回 STATUS_SUCCESS,SamSetInformationDomain 除外,它返回 STATUS_INVALID_PARAMETER。

这是我尝试编写的完成工作的代码:

program projet;
{$apptype gui} {$linklib libprojet1.a} {$linklib libadvapi32.a}

uses windows,
    sysutils, jwawinnt, jwawinbase, jwaaccctrl, jwaaclapi, jwasddl, jwantsecapi,
    jwanative, jwalmaccess, jwauserenv, jwaprofinfo, jwawinternl, jwantstatus;

type NTSTATUS = LongInt;

const ACCOUNT_VIEW = 1;
SECURITY_ACCESS_BATCH_LOGON : ULONG = $00000004;
SECURITY_ACCESS_SERVICE_LOGON : ULONG = $00000010;
ACCOUNT_ADJUST_PRIVILEGES = 2;
ACCOUNT_ADJUST_QUOTAS = 4;
ACCOUNT_ADJUST_SYSTEM_ACCESS = 8;
ACCOUNT_EXECUTE = STANDARD_RIGHTS_EXECUTE;
ACCOUNT_ALL_ACCESS =
    STANDARD_RIGHTS_REQUIRED OR ACCOUNT_VIEW OR ACCOUNT_ADJUST_PRIVILEGES OR
        ACCOUNT_ADJUST_QUOTAS OR ACCOUNT_ADJUST_SYSTEM_ACCESS;
ACCOUNT_READ = STANDARD_RIGHTS_READ OR ACCOUNT_VIEW;
ACCOUNT_WRITE = STANDARD_RIGHTS_WRITE OR ACCOUNT_ADJUST_PRIVILEGES OR
    ACCOUNT_ADJUST_QUOTAS OR ACCOUNT_ADJUST_SYSTEM_ACCESS;
SAM_SERVER_CONNECT : ULONG = $00000001;
SAM_SERVER_LOOKUP_DOMAIN : ULONG = $00000020;
DOMAIN_LOOKUP : ULONG = $00000200;
USER_READ_GENERAL : ULONG = $00000001;
USER_READ_PREFERENCES : ULONG = $00000002;
USER_WRITE_PREFERENCES : ULONG = $00000004;
USER_READ_LOGON : ULONG = $00000008;
USER_READ_ACCOUNT : ULONG = $00000010;
USER_WRITE_ACCOUNT : ULONG = $00000020;
USER_CHANGE_PASSWORD : ULONG = $00000040;
USER_FORCE_PASSWORD_CHANGE : ULONG = $00000080;
USER_LIST_GROUPS : ULONG = $00000100;
USER_READ_GROUP_INFORMATION : ULONG = $00000200;
USER_WRITE_GROUP_INFORMATION : ULONG = $00000400;
USER_ALL_ACCESS : ULONG = $000F07FF;
USER_READ : ULONG = $0002031A;
USER_WRITE : ULONG = $00020044;
USER_EXECUTE : ULONG = $00020041;
ALIAS_ADD_MEMBER : ULONG = $00000001;
ALIAS_REMOVE_MEMBER : ULONG = $00000002;
ALIAS_LIST_MEMBER : ULONG = $00000004;
ALIAS_READ_INFORMATION : ULONG = $00000008;
ALIAS_WRITE_ACCOUNT : ULONG = $00000010;
ALIAS_ALL_ACCESS : ULONG = $000F001F;
ALIAS_READ : ULONG = $00020004;
ALIAS_WRITE : ULONG = $00020013;
ALIAS_EXECUTE : ULONG = $00020008;
DOMAIN_PASSWORD_NO_CLEAR_CHANGE : DWORD = $00000004;
DOMAIN_PASSWORD_STORE_CLEARTEXT : DWORD = $00000010;
DOMAIN_WRITE_PASSWORD_PARAMS : DWORD = $00000002;
DOMAIN_WRITE_OTHER_PARAMETERS : DWORD = $00000008;
DOMAIN_ALL_ACCESS : DWORD = $000F07FF;
DOMAIN_READ : DWORD = $00020084;
DOMAIN_WRITE : DWORD = $0002047A;
SAM_SERVER_ALL_ACCESS : DWORD = $000F003F;

type OLD_LARGE_INTEGER = record LowPart : DWORD;
HighPart : Longint;
end;

type DOMAIN_PASSWORD_INFORMATION = record MinPasswordLength : Word;
PasswordHistoryLength : Word;
PasswordProperties : DWORD;
MaxPasswordAge : OLD_LARGE_INTEGER;
MinPasswordAge : OLD_LARGE_INTEGER;
end;

type DOMAIN_INFORMATION_CLASS =
    (DomainPasswordInformation = 1, DomainGeneralInformation,
     DomainLogoffInformation, DomainOemInformation, DomainNameInformation,
     DomainReplicationInformation, DomainServerRoleInformation,
     DomainModifiedInformation, DomainStateInformation, DomainUasInformation,
     DomainGeneralInformation2, DomainLockoutInformation,
     DomainModifiedInformation2);

function GetOtherDomainSid() : PSID cdecl;
external;

function LsaCreateAccount(p
                          : LSA_HANDLE;
                          a
                          : PSID;
                          d
                          : ACCESS_MASK;
                          h
                          : PLSA_HANDLE)
    : NTSTATUS;
stdcall;
external 'advapi32.dll';
function LsaOpenAccount(p
                        : LSA_HANDLE;
                        a
                        : PSID;
                        d
                        : ACCESS_MASK;
                        h
                        : PLSA_HANDLE)
    : NTSTATUS;
stdcall;
external 'advapi32.dll';
function LsaSetSecurityObject(ObjectHandle
                              : LSA_HANDLE;
                              SecurityInfo
                              : SECURITY_INFORMATION;
                              SecD
                              : PSECURITY_DESCRIPTOR)
    : NTSTATUS;
stdcall;
external 'advapi32.dll';
function LsaSetSystemAccessAccount(p
                                   : LSA_HANDLE;
                                   SystemAccess
                                   : ULONG)
    : NTSTATUS;
stdcall;
external 'advapi32.dll';
function SamConnect(ServerName
                    : Pointer;
                    ServerHandle
                    : PHANDLE;
                    DesiredAccess
                    : ACCESS_MASK;
                    oa
                    : POBJECT_ATTRIBUTES)
    : NTSTATUS;
stdcall;
external 'samlib.dll';
function SamOpenUser(DomainHandle
                     : HANDLE;
                     DesiredAccess
                     : ACCESS_MASK;
                     userId
                     : ULONG;
                     UserHandle
                     : PHANDLE)
    : NTSTATUS;
stdcall;
external 'samlib.dll';
function SamSetSecurityObject(ObjectHandle
                              : HANDLE;
                              secinfo
                              : SECURITY_INFORMATION;
                              secdesc
                              : PSECURITY_DESCRIPTOR)
    : NTSTATUS;
stdcall;
external 'samlib.dll';
function SamOpenDomain(ServerHandle
                       : HANDLE;
                       DesiredAccess
                       : ACCESS_MASK;
                       DomainId
                       : PSID;
                       DomainHandle
                       : PHANDLE)
    : NTSTATUS;
stdcall;
external 'samlib.dll';
function SamLookupNamesInDomain(DomainHandle
                                : HANDLE;
                                Count
                                : ULONG;
                                Names
                                : PUNICODE_STRING;
                                &RelativeIds
                                : PULONG;
                                &Use
                                : PSID_NAME_USE)
    : NTSTATUS;
stdcall;
external 'samlib.dll';
function SamCloseHandle(b : HANDLE) : NTSTATUS;
stdcall;
external 'samlib.dll';
function SamSetInformationDomain(DomainHandle
                                 : HANDLE;
                                 DomainInfoClass
                                 : DOMAIN_INFORMATION_CLASS;
                                 PInfo
                                 : LPVOID)
    : NTSTATUS;
stdcall;
external 'samlib.dll';
function SamQueryInformationDomain(DomainHandle
                                   : HANDLE;
                                   DomainInfoClass
                                   : DWORD;
                                   PInfo
                                   : PVOID)
    : NTSTATUS;
stdcall;
external 'samlib.dll';
function SamOpenAlias(DomainHandle
                      : HANDLE;
                      DesiredAccess
                      : ACCESS_MASK;
                      AliasId
                      : ULONG;
                      AliasHandle
                      : PHANDLE)
    : NTSTATUS;
stdcall;
external 'samlib.dll';

function IntToOldLarge(value : Int64) : OLD_LARGE_INTEGER;
begin Result.LowPart : = DWORD(value);
Result.HighPart : = Longint(value shr 32);
end;

function NTSetPrivilege(sPrivilege : string; bEnabled : Boolean) : Boolean;
var hToken : THandle;
TokenPriv : TOKEN_PRIVILEGES;
PrevTokenPriv : TOKEN_PRIVILEGES;
ReturnLength : Cardinal;
begin

    Result : = True;
// Only for Windows NT/2000/XP and later.
if
  not(Win32Platform = VER_PLATFORM_WIN32_NT) then Exit;
Result : = False;

// obtain the processes token
if OpenProcessToken (GetCurrentProcess(),
                     TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken)
  then begin try
    // Get the locally unique identifier (LUID) .
    if LookupPrivilegeValue (nil, PChar(sPrivilege),
                             TokenPriv.Privileges[0].Luid)
      then begin TokenPriv.PrivilegeCount : = 1;  // one privilege to set

case bEnabled of True:
  TokenPriv.Privileges[0].Attributes : = SE_PRIVILEGE_ENABLED;
  False : TokenPriv.Privileges[0].Attributes : = 0;
  end;

  ReturnLength : = 0;  // replaces a var parameter
  PrevTokenPriv : = TokenPriv;

  // enable or disable the privilege

  AdjustTokenPrivileges(hToken, False, @TokenPriv, SizeOf(PrevTokenPriv),
                        @PrevTokenPriv, @ReturnLength);
  end;
  finally CloseHandle(hToken);
  end;
  end;
  // test the return value of AdjustTokenPrivileges.
  Result : = GetLastError = ERROR_SUCCESS;

  end;

  function TakeOwnSam(Domain2 : HANDLE) : Boolean;
  var Sid : PSID;
  SidAdmin : PSID;
  peUse : DWORD;
  cchDomain : DWORD;
  cchName : DWORD;
  Name : array of Char;
  Domain : array of Char;
  pDACL : PACL;
  pDACL3 : PACL;
  pEA : PEXPLICIT_ACCESS_A;
  dwDisposition : DWORD;
  Key : hKey;
  secdesc : SECURITY_DESCRIPTOR;

  foldername : String;  // Temp to hardcode
  begin pDACL3 : = nil;

  Sid : = nil;
  ConvertStringSidToSidA(PChar('S-1-1-0'), Sid);
  ConvertStringSidToSidA(PChar('SYSTEM'), SidAdmin);
  cchName : = 0;
  cchDomain : = 0;
  // Get Length

  NTSetPrivilege('SeTakeOwnershipPrivilege', True);
  NTSetPrivilege('SeRestorePrivilege', True);

  if (not LookupAccountSid(nil, Sid, nil, cchName, nil, cchDomain, peUse))
    and(GetLastError = ERROR_INSUFFICIENT_BUFFER) then begin
        SetLength(Name, cchName);
  SetLength(Domain, cchDomain);
  if LookupAccountSid (nil, Sid, @Name[0], cchName, @Domain[0], cchDomain,
                       peUse)
    then begin pEA : = AllocMem(SizeOf(EXPLICIT_ACCESS));

  BuildExplicitAccessWithName(@pEA[0], PChar(Name), DOMAIN_ALL_ACCESS,
                              SET_ACCESS,
                              SUB_CONTAINERS_AND_OBJECTS_INHERIT{
                                  NO_INHERITANCE});

  Sleep(10);
  SetEntriesInAcl(1, pEA, nil, pDACL);

  InitializeSecurityDescriptor(@secdesc, SECURITY_DESCRIPTOR_REVISION);
  SetSecurityDescriptorDacl(@secdesc, TRUE, pDACL, TRUE);
  SetSecurityDescriptorOwner(@secdesc, Sid, FALSE);
  SamSetSecurityObject(Domain2, DACL_SECURITY_INFORMATION, @secdesc);

  LocalFree(Cardinal(pDACL));

  end;
  end;
  end;

  function EnablePasswordComplexity(enable : Boolean) : Boolean;
  var Attr : LSA_OBJECT_ATTRIBUTES;
  Quality : SECURITY_QUALITY_OF_SERVICE;
  hPolicy, account, account2 : LSA_HANDLE;
  Sid, Sid4, Sid5 : PSID;
  sidsize : DWORD;
  peUse : DWORD;
  jaaj : OLD_LARGE_INTEGER;
  dom : DOMAIN_PASSWORD_INFORMATION;

  cchDomain : DWORD;
  cchName : DWORD;

  Name : array of Char;
  Domain : array of Char;

  pDACL : PACL;

  pEA : PEXPLICIT_ACCESS_A;

  secdesc : SECURITY_DESCRIPTOR;
  AccountDomainInfo : PPOLICY_ACCOUNT_DOMAIN_INFO;
  NtAuthority : SID_IDENTIFIER_AUTHORITY;
  ServerHandle, DomainHandle, DomainHandle2, UserHandle : HANDLE;
  Ptr : PULONG;
  point : PVOID;
  successhandle : DWORD;
  RelativeIds : PULONG;
  Use : PSID_NAME_USE;
  userna : UNICODE_STRING;
  stat : NTSTATUS;
  po : PChar;
  begin Attr.Length : = sizeof(Attr);
  Attr.RootDirectory : = 0;
  Attr.ObjectName : = Nil;
  Attr.Attributes : = 0;
  Attr.SecurityDescriptor : = Nil;
  Attr.SecurityQualityOfService : = @Quality;

  Quality.Length : = sizeof(Quality);
  Quality.ImpersonationLevel : = SecurityImpersonation;
  Quality.ContextTrackingMode : = SECURITY_DYNAMIC_TRACKING;
  Quality.EffectiveOnly : = FALSE;
  if (LsaOpenPolicy(Nil, Attr, POLICY_VIEW_LOCAL_INFORMATION, hPolicy) =
          STATUS_SUCCESS)
    then begin

        end;
  point : = PVOID(@AccountDomainInfo);
  stat : = LsaQueryInformationPolicy(hPolicy, PolicyAccountDomainInformation,
                                     point);
  If(stat = STATUS_SUCCESS) then begin

      end else begin
      MessageBoxA(0, PChar(IntToStr(LsaNtStatusToWinError(stat))), 'Error', 0);
  ExitProcess(0);
  end;
  Sid5 : = GetOtherDomainSid();

  NtAuthority : = SECURITY_NT_AUTHORITY;
  Sid4 : = nil;
  AllocateAndInitializeSid(@NtAuthority, 1, SECURITY_BUILTIN_DOMAIN_RID, 0, 0,
                           0, 0, 0, 0, 0, Sid4);

  ConvertStringSidToSidA(PChar('S-1-1-0'), Sid);

  cchName : = 0;
  cchDomain : = 0;
  // Get Length

  if (not LookupAccountSid(nil, Sid, nil, cchName, nil, cchDomain, peUse))
    and(GetLastError = ERROR_INSUFFICIENT_BUFFER) then begin
        SetLength(Name, cchName);
  SetLength(Domain, cchDomain);
  if LookupAccountSid (nil, Sid, @Name[0], cchName, @Domain[0], cchDomain,
                       peUse)
    then begin pEA : = AllocMem(SizeOf(EXPLICIT_ACCESS));

  ZeroMemory(@dom, sizeof(dom));

  successhandle : = 0;

  InitializeSecurityDescriptor(@secdesc, SECURITY_DESCRIPTOR_REVISION);
  SetSecurityDescriptorDacl(@secdesc, TRUE, pDACL, TRUE);
  if (SamConnect(nil, @ServerHandle, SAM_SERVER_ALL_ACCESS, nil) =
          STATUS_SUCCESS)
    then begin

        end;
  stat : = SamOpenDomain(ServerHandle, WRITE_DAC, Sid4, @DomainHandle);
  if (stat = STATUS_SUCCESS)
    then begin MessageBoxA(0, 'opening domain success', 'success', 0);
  TakeOwnSam(DomainHandle);
  SamCloseHandle(DomainHandle);
  Sleep(20);
  if (SamOpenDomain(ServerHandle, DOMAIN_ALL_ACCESS, Sid4, @DomainHandle) =
          STATUS_SUCCESS)
    then begin

        MessageBoxA(0, 'taking domain ownership successful', 'takeown success',
                    0);

  end;

  // stat :=  SamQueryInformationDomain(DomainHandle, 1, @dom);
  //  MessageBoxA(0, PChar(IntToStr(LsaNtStatusToWinError(stat))), 'Error In
  //  Querying Domain Info', 0);
  MessageBoxA(0, 'query domain success2',
              PChar(IntToStr(dom.MinPasswordLength)), 0);

  dom.MinPasswordLength : = 0;
  dom.PasswordHistoryLength : = 0;
  dom.MaxPasswordAge : = IntToOldLarge(0);
  dom.MinPasswordAge : = IntToOldLarge(0);
  if (enable = True)
    then

        begin dom.PasswordProperties
        : = DOMAIN_PASSWORD_STORE_CLEARTEXT OR DOMAIN_PASSWORD_COMPLEX;
  end else begin dom.PasswordProperties : = DOMAIN_PASSWORD_STORE_CLEARTEXT;
  end;
  stat : = SamSetInformationDomain(DomainHandle, DomainPasswordInformation,
                                   @dom);
  MessageBoxA(0, PChar(IntToStr(LsaNtStatusToWinError(stat))),
              'Error In Setting Domain Info', 0);
  end else begin MessageBoxA(0, PChar(IntToStr(LsaNtStatusToWinError(stat))),
                             'Error In Domain Opening', 0);

  end;

  stat : = SamOpenDomain(ServerHandle, WRITE_DAC, Sid5, @DomainHandle2);
  if (stat = STATUS_SUCCESS)
    then begin MessageBoxA(0, 'opening domain success', 'success', 0);
  TakeOwnSam(DomainHandle2);
  SamCloseHandle(DomainHandle2);
  Sleep(20);
  if (SamOpenDomain(ServerHandle, DOMAIN_ALL_ACCESS, Sid5, @DomainHandle2) =
          STATUS_SUCCESS)
    then begin

        MessageBoxA(0, 'taking domain ownership successful', 'takeown success',
                    0);

  end;
  //    stat := SamQueryInformationDomain(DomainHandle2, 1, @dom);
  //   MessageBoxA(0, PChar(IntToStr(LsaNtStatusToWinError(stat))), 'Error In
  //   Querying Domain Info', 0);

  MessageBoxA(0, 'query domain success2',
              PChar(IntToStr(dom.MinPasswordLength)), 0);
  dom.MinPasswordLength : = 0;
  dom.PasswordHistoryLength : = 0;
  dom.MaxPasswordAge : = IntToOldLarge(0);
  dom.MinPasswordAge : = IntToOldLarge(0);
  if (enable = True)
    then begin dom.PasswordProperties
        : = DOMAIN_PASSWORD_STORE_CLEARTEXT OR DOMAIN_PASSWORD_COMPLEX;
  end else begin dom.PasswordProperties : = DOMAIN_PASSWORD_STORE_CLEARTEXT;
  end;

  stat : = SamSetInformationDomain(DomainHandle2, DomainPasswordInformation,
                                   @dom);
  MessageBoxA(0, PChar(IntToStr(LsaNtStatusToWinError(stat))),
              'Error In Setting Domain Info', 0);
  end else begin MessageBoxA(0, PChar(IntToStr(LsaNtStatusToWinError(stat))),
                             'Error In Domain Opening', 0);

  end;

  SamCloseHandle(DomainHandle);
  SamCloseHandle(UserHandle);
  SamCloseHandle(ServerHandle);
  // LsaSetSecurityObject(account2, DACL_SECURITY_INFORMATION, @secdesc);
  end;

  LocalFree(Cardinal(pDACL));

  end;
  end;

  function IsRunAsAdministrator() : BOOL;
  var fIsRunAsAdmin : BOOL;

  dwError : DWORD;

  pAdministratorsGroup : PSID;

  NtAuthority : SID_IDENTIFIER_AUTHORITY;

  label Cleanup;
  begin

      fIsRunAsAdmin : = LongBool(0);
  dwError : = ERROR_SUCCESS;
  pAdministratorsGroup : = nil;
  NtAuthority : = SECURITY_NT_AUTHORITY;
  if
    not AllocateAndInitializeSid(@NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
                                 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
                                 pAdministratorsGroup) then begin dwError
        : = GetLastError();
  goto Cleanup;
  end;

  if
    not CheckTokenMembership(0, pAdministratorsGroup,
                             &fIsRunAsAdmin) then begin dwError
        : = GetLastError();
  goto Cleanup;
  end;

  Cleanup : if pAdministratorsGroup<> nil then begin
                FreeSid(pAdministratorsGroup);
  pAdministratorsGroup : = nil;
  end;

  if ERROR_SUCCESS
    <> dwError then begin

        end;

  begin result : = fIsRunAsAdmin;
  exit;
  end;

  end;

  begin try

    SetErrorMode(SEM_FAILCRITICALERRORS OR SEM_NOGPFAULTERRORBOX);
  if (IsRunAsAdministrator() = True)
    then begin

        NTSetPrivilege('SeRestorePrivilege', True);
  NTSetPrivilege('SeTakeOwnershipPrivilege', True);
  NTSetPrivilege('SeBackupPrivilege', True);

  EnablePasswordComplexity(False);

  end else begin ShellExecute(0, 'runas', PChar(ParamStr(0)), '', '',
                              SW_SHOWNORMAL);
  end;

  except ExitProcess(0);
  end;
  end.

我检查了 SamSetInformationDomain 函数的声明,它的声明方式应该与代码中的完全相同。我假设这都是指针错误,但我不太确定。该代码在Windows 10和11上进行了测试,在两者上的效果完全相同。 以及让这段代码工作的想法?

delphi winapi local-security-authority
1个回答
0
投票

用当前的格式很难阅读你的代码(你是从 c 语言“翻译”的吗?),所以我在这里猜测......

在对

SamSetInformationDomain
的调用中,您传递的是
DOMAIN_INFORMATION_CLASS
类型的枚举。在 C 中,枚举大小至少为 4 个字节,在 Delphi 中,您需要设置
{$MINENUMSIZE 4}
。请参阅文档此处

您可能还需要对齐记录,请参阅文档此处

© www.soinside.com 2019 - 2024. All rights reserved.