【问题标题】:Find if a given SID belongs to a group identified by SID查找给定的 SID 是否属于由 SID 标识的组
【发布时间】:2015-03-16 10:57:06
【问题描述】:

我正在编写一个windows服务,它根据不同的规则执行操作,其中一个是基于请求用户身份的。

它因此接收请求的用户 SID,然后将其与其内部 SID 列表进行比较,以决定它将执行什么操作。使用EqualSID API 函数让这一切变得非常简单。

但是,我现在面临服务列表中的某些 SID 是组 SID 而不是用户 SID 的情况。

这意味着我必须找到一种方法来测试接收到的 SID 是等于列表中的那个还是属于列表中的 SID 所代表的组。

我环顾四周,看看有哪些 API 可用,并找到了需要令牌句柄的 CheckTokenMembership。那是我有点迷茫的地方,因为服务不一定位于同一台机器上,我似乎无法找到从收到的 SID 创建有效令牌句柄的方法。

服务本身在默认的“NT 服务”帐户下运行,如果它可以保持这种方式,我更愿意。

您建议我使用什么 API?

目标语言是 Delphi,但我可以理解纯 C 语言的示例。

【问题讨论】:

    标签: winapi


    【解决方案1】:

    好吧,在环顾其他各种事情之后,我终于设法找到了实现这一目标的方法。简而言之,答案是Active Directory Service Interfaces也称为ADSI

    如果其他人正在查看,为了提供更多详细信息,以下是在 Delphi 中实现此目的的一系列步骤:

    1. Active DS Type Library 对象集导入Delphi。这将创建具有所有必要接口的 ActiveDs_TLB 单元
    2. 像这样声明 AdsGetObject

      function ADsGetObject(lpszPathName: WideString; const riid: TGUID; out ppObject): HRESULT; safecall;
      
    3. 使用 SID 语法检索 IADSUser 实例:

      var
        SIDUser: IADSUser;
        User: IADSUser;
      
        SIDGroup: IADSGroup;
        Group: IADSGroup;
      begin
        // Bind using the SID
        AdsGetObject('LDAP://<SID=S-1-5-7>', IADSUser, SIDUser);
      
        // rebind using the distinguished name as suggested by MSDN
        AdsGetObject('LDAP://' + SIDUser.Get('distinguishedName'), IADSUser, User);
      
        // Use the User instance
        ShowMessage(User.FullName);
      
        // Same method for group 
        AdsGetObject('LDAP://<SID=S-1-5-32-545>', IADSGroup, SIDGroup);
        AdsGetObject('LDAP://' + SIDGroup.Get('distinguishedName'), IADSGroup, Group);
      
        // IsMember does not seem to work with LDAP
        // https://groups.google.com/forum/#!topic/microsoft.public.adsi.general/2d-e4HPXGfA
        // http://www.rlmueller.net/Programs/IsMember4.txt
      //  if Group.IsMember(User.ADsPath) then
        if AdsIsMember(User, 'S-1-5-32-545') then
          ShowMessage('InGroup');
      end;
      

    如您所见,有人想使用 IADSGroup 的 IsMember 方法,但显然它不起作用,因为在上述情况下它应该返回 True(S-1-5-32-545 是世界组)。 因此,正如评论中给出的链接所建议的那样,我编写了自己的 IsMember,如下所示:

    function ADsIsMember(const User: IADSUser; const GroupSID: string): Boolean;
    const
      TokenGroupsId = 'tokenGroups';
    var
      PropNames: array of OleVariant;
      TokenGroups: OleVariant;
      TokenGroupLow: Integer;
      TokenGroupHigh: Integer;
      TokenGroupIndex: Integer;
      SIDBytes: array of Byte;
      SIDAsString: PChar;
    begin
      Result := False;
      SetLength(PropNames, 1);
      PropNames[0] := TokenGroupsId;
      User.GetInfoEx(PropNames, 0);
      TokenGroups := User.Get(TokenGroupsId);
      TokenGroupLow := VarArrayLowBound(TokenGroups, 1);
      TokenGroupHigh := VarArrayHighBound(TokenGroups, 1);
      for TokenGroupIndex := TokenGroupLow to TokenGroupHigh do
      begin
        SIDBytes := TokenGroups[TokenGroupIndex];
        ConvertSidToStringSid(@SIDBytes[0], SIDAsString);
        if GroupSID = SIDAsString then
          Exit(True);
      end;
    end;
    

    有了这一切,我现在可以检查给定的 SID 是否属于由其 SID 定义的组。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-20
      • 1970-01-01
      • 2021-04-24
      相关资源
      最近更新 更多