📄 11.1 使用者环境.htm
字号:
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">typedef struct _TOKEN_DEFAULT_DACL { <BR> PACL DefaultDacl; <BR>}TOKEN_DEFAULT_DACL;</PRE></FONT></DIV>
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> TokenOwner </B></FONT>用来读取或设定权杖物件的预设拥有者(有关物件所有权的讨论,请参阅 <A
style="LINE-HEIGHT: 25px"
href="http://e-msbooks.com/relaunch/XML/paser.asp?src=957-2085-84-0_210.xml#"
target=_new>第十章</A> 的内容)。TOKEN_ADJUST_DEFAULT存取权利对设定权杖的拥有者来说是必要的。<BR
style="LINE-HEIGHT: 25px">
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">typedef struct _TOKEN_OWNER { <BR> PSID Owner; <BR>}TOKEN_OWNER;</PRE></FONT></DIV>
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> TokenPrimaryGroup </B></FONT>读取或设定权杖的主要群组。在呼叫SetTokenInformation时,会要求TOKEN_ADJUST_DEFAULT存取权利。<BR
style="LINE-HEIGHT: 25px">
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">typedef struct _TOKEN_PRIMARY_GROUP { <BR> PSID PrimaryGroup; <BR>}TOKEN_PRIMARY_GROUP;</PRE></FONT></DIV>
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> TokenGroups </B></FONT>传回与权杖关联的群组SIDs(这个值不与SetTokenInformation一起使用)。<BR
style="LINE-HEIGHT: 25px">
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">typedef struct _TOKEN_GROUPS { <BR> DWORD GroupCount; <BR> SID_AND_ATTRIBUTES Groups [ANYSIZE_ARRAY ]; <BR>}TOKEN_GROUPS;</PRE></FONT></DIV>
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> TokenPrivileges </B></FONT>传回与权杖关联的权限(这个值不与SetTokenInformation一起使用)。<BR
style="LINE-HEIGHT: 25px">
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">typedef struct _TOKEN_PRIVILEGES { <BR> DWORD PrivilegeCount; <BR> LUID_AND_ATTRIBUTES Privileges [ANYSIZE_ARRAY ]; <BR>}TOKEN_PRIVILEGES;</PRE></FONT></DIV>
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> TokenSource </B></FONT>传回权杖的来源。这是一个表示建立权杖项目的文字字串。TOKEN_QUERY_SOURCE存取权利对撷取这个资讯来说是必要的(这个值不与SetTokenInformation一起使用)。<BR
style="LINE-HEIGHT: 25px">
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">typedef struct _TOKEN_SOURCE { <BR> CHAR SourceName [8 ]; <BR> LUID SourceIdentifier; <BR>}TOKEN_SOURCE;</PRE></FONT></DIV>
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> TokenType </B></FONT>传回权杖的类型。可能的值为TokenPrimary及Token
Impersonation。GetTokenInformation的pTokenInformation参数将传回一个个别的TOKEN_TYPE指出权杖的类型(这个值不与SetTokenInformation一起使用)。<BR
style="LINE-HEIGHT: 25px">
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">typedef enum _TOKEN_TYPE { <BR> TokenPrimary =1, <BR> TokenImpersonation <BR>}TOKEN_TYPE;</PRE></FONT></DIV>
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> TokenImpersonationLevel </B></FONT>传回模拟等级。更多相关资讯请参阅 <A
style="LINE-HEIGHT: 25px"
href="http://www.acejoy.com/doc/serverside/11.htm#591-1"
target=_new>表格11-3</A> (这个值不与SetTokenInformation一起使用)。<BR
style="LINE-HEIGHT: 25px">
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">typedef enum _SECURITY_IMPERSONATION_LEVEL { <BR>SecurityAnonymous, <BR> SecurityIdentification, <BR> SecurityImpersonation, <BR> SecurityDelegation <BR>}SECURITY_IMPERSONATION_LEVEL;</PRE></FONT></DIV>
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> TokenStatistics </B></FONT>传回有关权杖的一般资讯。它的成员包括GroupCount、PrivilegeCount及ModifiedId。ModifiedId成员是本机唯一识别元(LUID),每当权杖被修改时就会改变。您的程序代码可以使用这个值来检查自从上次检查后,权杖是否已被改变。这种侦查能力在编写呼叫到协力厂商DLLs或程序库的容错程序代码时非常有帮助(这个值不与SetTokenInformation一起使用)。<BR
style="LINE-HEIGHT: 25px">
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">typedef struct _TOKEN_STATISTICS { <BR> LUID TokenId; <BR> LUID AuthenticationId; <BR> LARGE_INTEGER ExpirationTime; <BR> TOKEN_TYPE TokenType; <BR> SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; <BR> DWORD DynamicCharged; <BR> DWORD DynamicAvailable; <BR> DWORD GroupCount; <BR> DWORD PrivilegeCount; <BR> LUID ModifiedId; <BR>}TOKEN_STATISTICS;</PRE></FONT></DIV>
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> TokenRestrictedSids </B></FONT>传回权杖的受限SIDs。本章稍后将讨论受限权杖的细节(这个值不与SetTokenInformation一起使用)。<BR
style="LINE-HEIGHT: 25px">
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">typedef struct _TOKEN_GROUPS { <BR> DWORD GroupCount; <BR> SID_AND_ATTRIBUTES Groups [ANYSIZE_ARRAY ]; <BR>}TOKEN_GROUPS;</PRE></FONT></DIV>
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> TokenSessionId </B></FONT>指出终端服务器权杖的工作阶段ID。GetTokenInformation的pTokenInformation参数将传回一个DWORD值。假如终端服务器没有安装在本地端机器或权杖与终端服务器主控台关联的话,DWORD的值会是0。若权杖与终端服务器的客户端关联,则DWORD的值是客户端的工作阶段ID(这个值不与SetTokenInformation一起使用)。<BR
style="LINE-HEIGHT: 25px">
<P>如同前面清单显示,您可以从权杖中读取大量的资讯。以下是从权杖撷取的最常见项目: </P>
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> 权杖使用者SID </B></FONT>权杖所代表的使用者帐户。通常会从权杖收到这个资讯,并找出谁正在执行程序代码。您可以传递这个SID到LookupAccountSid中(在第九章讨论),以取得使用者帐户的文字名称。<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> 登入SID </B></FONT>这个SID与权杖群组一起掩藏,所以会花费一些时间挖掘,以取回它(我们将会马上讨论)。然而,登录SID对于唯一地识别工作阶段是非常方便的。假如某位使用者不只一次登入执行Windows
2000的机器(以互动式或者透过其他方法)时,系统会为每个工作阶段建立一个唯一的登入SID,不管权杖使用者从一个工作阶段到另一个工作阶段是否相同。<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> Token
groups </B></FONT>对找出与权杖关联的群组很有帮助。然而,假如您想找出权杖是否有个别的群组,可以使用CheckTokenMembership函数。<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> Token default
DACL </B></FONT>建立物件时,假如您传递NULL给安全性属性时,对找出最近建立物件的DACL很有帮助。<BR
style="LINE-HEIGHT: 25px"> </LI></UL></FONT>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>从权杖撷取资讯时,您通常必需呼叫GetTokenInformation,以找出被要求的缓冲器长度,然后再次呼叫它,实际撷取资讯。为了产生真正的容错程序代码,您应该有多次呼叫GetTokenInformation的准备,直到您已经成功地撷取要求的资讯为止。这是因为权杖资讯的大小(例如预设DACL)可以在您呼叫GetTokenInformation撷取缓冲器大小之间,以及您在呼叫GetTokenInformation撷取实际资料时改变。这种多重线程程序设计的条件即是竞赛条件(race
condition),而且会导致难以发现的错误,这些错误大约每几个月才出现一次。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>以下的函数显示如何正确地呼叫GetTokenInformation,以撷取有关权杖的资讯。它也传回使用LocalAlloc分配之缓冲器里面的权杖资讯。假如您在程序代码中使用了这个函数,则当您用完缓冲器时,应该使用LocalFree释放传回的缓冲器。</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">LPVOID AllocateTokenInformation(HANDLE hToken, <BR> TOKEN_INFORMATION_CLASS tokenClass ){ <BR> PVOID pvBuffer =NULL; <BR> __try{ <BR> BOOL fSuccess; <BR> //初始缓冲器大小 <BR> ULONG lSize =0 ; <BR> do <BR> { <BR> //我们拥有缓冲器大小了吗? <BR> if (lSize !=0) <BR> { <BR> //我们已经拥有缓冲器吗? <BR> if (pvBuffer !=NULL) <BR> LocalFree(pvBuffer);//Then free it <BR> //分配新的缓冲器 <BR> pvBuffer =LocalAlloc(LPTR,lSize); <BR> if(pvBuffer ==NULL) <BR> __leave; <BR> } <BR> //再试一次 <BR> fSuccess =GetTokenInformation(hToken,tokenClass, <BR> pvBuffer,lSize,&lSize ); <BR> //缓冲器仍旧不够? <BR> }while(!fSuccess &&(GetLastError()== <BR> ERROR_INSUFFICIENT_BUFFER)); <BR> //假如为了某些其他原因而失败,退出 <BR> if(!fSuccess) <BR> { <BR> if(pvBuffer) <BR> LocalFree(pvBuffer); <BR> pvBuffer =NULL; <BR> } <BR> }__finally{} <BR> //传回本地端分配的缓冲器 <BR> return (pvBuffer); <BR>}</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>以下的程序代码片段,显示使用此函数撷取权杖之使用者SID及当前处理程序的预设DACL。</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">HANDLE hToken; <BR>if(!OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&hToken)){ <BR> //错误 <BR>} <BR>TOKEN_USER*ptUser =(TOKEN_USER*)AllocateTokenInformation(hToken, <BR> TokenUser); <BR>if (ptUser !=NULL){ <BR> //对经由ptUser->User指向的SID作些事情 <BR>} <BR>TOKEN_DEFAULT_DACL*ptDACL = <BR> (TOKEN_DEFAULT_DACL*)AllocateTokenInformation(hToken, <BR> TokenDefaultDacl); <BR>if (ptDACL !=NULL){ <BR> //对经由ptDACL->DefaultDacl指向的DACL作些事情 <BR>}</PRE>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>请注意,有一些经由GetTokenInformation传回的结构,使用了SID_AND_ATTRIBUTES结构,其定义如下:</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><PRE style="LINE-HEIGHT: 25px">typedef struct _SID_AND_ATTRIBUTES {</PRE></DIV><PRE style="LINE-HEIGHT: 25px">PSID Sid; <BR> DWORD Attributes; <BR>}SID_AND_ATTRIBUTES ;</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>这个结构包括一个信任成员帐户的SID及一位属性
成员,它包括有关SID的资讯。有关包含一个SID_AND_ATTRIBUTES结构的特殊结构,其属性 成员的含义请参阅《Platform
SDK》文件。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>以下的函数,AllocateTokenLogonSID,使用AllocateTokenInformation范例函数撷取权杖的群组SIDs,然后反覆浏览SIDs,以找到本节先前讨论的登录SID。这个函数经由检查属性
成员的SE_GROUP_LOGON_ID标记找到登录SID。应该使用LocalFree释放传回的PSID。</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">PSID AllocateTokenLogonSID(HANDLE hToken){ <BR> PSID psidLogon =NULL; <BR> TOKEN_GROUPS*ptGroups =NULL; <BR> __try{ <BR> //取得权杖群组 <BR> ptGroups =(TOKEN_GROUPS*) <BR> AllocateTokenInformation(hToken,TokenGroups); <BR> if (ptGroups ==NULL) <BR> __leave; <BR> //找到登录SID <BR> int nCount =ptGroups->GroupCount; <BR> while (nCount--){ <BR> if ((ptGroups->Groups [nCount ].Attributes &SE_GROUP_LOGON_ID) <BR> !=0) <BR> break; <BR> } <BR> if (nCount ==-1) <BR> __leave;//No logon SID found <BR> //为传回SID的取得内存 <BR> ULONG lLen =GetLengthSid(ptGroups->Groups [nCount ].Sid); <BR> psidLogon =(PSID)LocalAlloc(LPTR,lLen); <BR> if (psidLogon ==NULL) <BR> __leave; <BR> //复制登录SID <BR> if(!CopySid(lLen,psidLogon,ptGroups->Groups [nCount ].Sid)){ <BR> LocalFree(psidLogon); <BR> psidLogon =NULL; <BR> __leave; <BR> } <BR> }__finally{ <BR> if (ptGroups !=NULL) <BR> LocalFree(ptGroups); <BR> } <BR> return (psidLogon); <BR>}</PRE></FONT></DIV><A
style="LINE-HEIGHT: 25px" name=579-1></A>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e72d7
size=4><B style="LINE-HEIGHT: 25px">TokenMaster范例应用程序<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>TokenMaster范例应用程序(「11
TokenMaster.exe」)示范与权杖相关之系统函数的使用,包括GetTokenInformation及SetTokenInformation。范例应用程序的原始程序代码及文件存放在随书光碟的11-TokenMaster目录中。这个程序可让您从四个来源之一获得权杖:处理程序、线程、使用者凭证或者经由复制。这个程序也可让您检视及修改权杖资讯。当使用者执行TokenMaster时,会出现如图11-1中的对话盒画面。</FONT></P>
<CENTER style="LINE-HEIGHT: 25px">
<P><INPUT id=1 style="LINE-HEIGHT: 25px" type=image height=554
width=700 src="11.1 使用者环境.files/11-1(800600).gif" border=0
onclick="imgclick"> </P></CENTER>
<CENTER style="LINE-HEIGHT: 25px">
<P></P>
<P class=content_page><STRONG><FONT
color=#ff0033>[1]</FONT></STRONG> <A
href="http://www.acejoy.com/Html/Article/network/6520061102101703_P2.html">[2]</A> <A
href="http://www.acejoy.com/Html/Article/network/6520061102101703_P3.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -