查找给定的SID是否属于SID标识的组

时间:2015-03-16 10:57:06

标签: winapi

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

它接收请求用户SID,然后将其与其内部SID列表进行比较,以确定它将执行的操作。使用EqualSID API函数可以非常轻松。

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

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

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

服务本身在默认的" NT服务"如果它可以保持这种状态我会更喜欢。

您建议我使用哪种API?

目标语言是Delphi,但我可以理解普通C中的例子。

1 个答案:

答案 0 :(得分:0)

好吧,在环顾各种其他事情之后,我终于找到了实现这个目标的方法。简而言之,答案是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;
    
  4. 正如您所看到的,人们会想要使用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定义的组。