我正在编写一个根据不同规则执行操作的Windows服务,其中一个基于请求用户身份。
它接收请求用户SID,然后将其与其内部SID列表进行比较,以确定它将执行的操作。使用EqualSID
API函数可以非常轻松。
但是,我现在面临的情况是服务列表中的某些SID是组SID而不是用户SID。
这意味着我必须找到一种方法来测试收到的SID是否等于列表中的SID或者属于列表中SID所代表的组。
我环顾四周,看看哪些API可用,并找到了需要令牌句柄的CheckTokenMembership
。由于服务不一定位于同一台机器上,我似乎无法找到从我收到的SID创建有效令牌句柄的方法。
服务本身在默认的" NT服务"如果它可以保持这种状态我会更喜欢。
您建议我使用哪种API?
目标语言是Delphi,但我可以理解普通C中的例子。
答案 0 :(得分:0)
好吧,在环顾各种其他事情之后,我终于找到了实现这个目标的方法。简而言之,答案是Active Directory Service Interfaces
,也称为ADSI
如果其他人正在考虑这个问题,请提供更多详细信息,以下是在Delphi中实现此目的的一系列步骤:
Active DS Type Library
个对象集导入Delphi。这将创建具有所有必要接口的ActiveDs_TLB
单元像这样声明AdsGetObject
function ADsGetObject(lpszPathName: WideString; const riid: TGUID; out ppObject): HRESULT; safecall;
使用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定义的组。