10.3.1 存取控制.htm

来自「Windows2000后台服务程序开发手册」· HTM 代码 · 共 483 行 · 第 1/5 页

HTM
483
字号
            style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">PACE_UNION AllocateACE(ULONG bACEType, ULONG bACEFlags,&nbsp;&nbsp;<BR> ULONG lAccessMask,PSID pSID ){ <BR> PACE_UNION pReturnACE = NULL; <BR> PBYTE pbBuffer = NULL; <BR> try{ <BR>&nbsp;&nbsp;// 取得ACE中SID的偏移量 <BR>&nbsp;&nbsp;ULONG lSIDOffset = (ULONG)(&amp;((ACCESS_ALLOWED_ACE*)0)-&gt;SidStart); <BR>&nbsp;&nbsp;// 取得没有SID的ACE大小 <BR>&nbsp;&nbsp;ULONG lACEStructSize = sizeof(ACCESS_ALLOWED_ACE)- <BR>&nbsp;&nbsp; sizeof(((ACCESS_ALLOWED_ACE*)0)-&gt;SidStart); <BR>&nbsp;&nbsp;// 取得SID的长度 <BR>&nbsp;&nbsp;ULONG lSIDSize = GetLengthSid(pSID); <BR>&nbsp;&nbsp;// 分配一个缓冲器给ACE <BR>&nbsp;&nbsp;pbBuffer = (PBYTE)LocalAlloc(LPTR, lACEStructSize + lSIDSize); <BR>&nbsp;&nbsp;if (pbBuffer == NULL) <BR>&nbsp;&nbsp; goto leave; <BR>&nbsp;&nbsp;// 复制SID到ACE <BR>&nbsp;&nbsp;if(!CopySid(lSIDSize, (PSID)(pbBuffer+lSIDOffset), pSID)){ <BR>&nbsp;&nbsp; goto leave; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp;pReturnACE = (PACE_UNION) pbBuffer; <BR>&nbsp;&nbsp;pReturnACE-&gt;aceHeader.AceSize = (USHORT)(lACEStructSize + lSIDSize); <BR>&nbsp;&nbsp;pReturnACE-&gt;aceHeader.AceType = (BYTE)bACEType; <BR>&nbsp;&nbsp;pReturnACE-&gt;aceHeader.AceFlags = (BYTE)bACEFlags; <BR>&nbsp;&nbsp;pReturnACE-&gt;aceAllowed.Mask = lAccessMask; <BR> leave:; <BR> }catch(...){} <BR> // 在错误实例中释放缓冲器 <BR> if (pbBuffer != (PBYTE)pReturnACE){ <BR>&nbsp;&nbsp;LocalFree(pbBuffer); <BR> } <BR> return (pReturnACE); <BR>}</PRE></FONT></DIV>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>当在使用AllocateAce时,您只须在执行完成时传递回传的ACE给LocalFree。</FONT></P>
            <HR style="LINE-HEIGHT: 25px">

            <P><FONT style="LINE-HEIGHT: 25px" face=Arial color=#3e77d7 size=3 
            Black><B style="LINE-HEIGHT: 25px">说明</B></FONT> </P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>AllocateAce会传回一个PACE_UNION指标,它是本章先前定义的类型,我选择使用此技巧并以一般的方式表示ACEs。选择特定ACE类型之其中一个也是常见的方法,例如ACCESS_ 
            ALLOWED_ACE,可使用在您的ACE之一般操作上。两种方法都行得通;然而,在本章的一些范例函数中,所使用的是PACE_UNION。</FONT></P>
            <HR style="LINE-HEIGHT: 25px">

            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>现在您已经建立了ACE,接下来您必须在对象现存的DACL中搜寻符合的ACEs。您可以经由使用本章先前谈论的ACL读取技巧来实作。在我编写执行此工作程序代码时使用了两个函数:一个用来对照ACEs,另一个则是在ACL中搜寻符合的ACE。</FONT></P>
            <DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT 
            style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">BOOL IsEqualACE(PACE_UNION pACE1,PACE_UNION pACE2 ){&nbsp;&nbsp;<BR> BOOL fReturn =FALSE; <BR> try{{ <BR>&nbsp;&nbsp;if(pACE1-&gt;aceHeader.AceType !=pACE2-&gt;aceHeader.AceType) <BR>&nbsp;&nbsp; goto leave; <BR>&nbsp;&nbsp;//取得ACE中SID的偏移量 <BR>&nbsp;&nbsp;ULONG lSIDOffset =(ULONG)(&amp;((ACCESS_ALLOWED_ACE*)0)-&gt;SidStart); <BR>&nbsp;&nbsp;//取得没有SID的ACE大小 <BR>&nbsp;&nbsp;ULONG lACEStructSize =sizeof(ACCESS_ALLOWED_ACE)- <BR>&nbsp;&nbsp; sizeof(((ACCESS_ALLOWED_ACE*)0)-&gt;SidStart); <BR>&nbsp;&nbsp;PBYTE pbACE1 =(PBYTE)pACE1; <BR>&nbsp;&nbsp;PBYTE pbACE2 =(PBYTE)pACE2; <BR>&nbsp;&nbsp;fReturn =TRUE; <BR>&nbsp;&nbsp;while(lACEStructSize--) <BR>&nbsp;&nbsp; fReturn =(fReturn &amp;&amp;((pbACE1 [lACEStructSize ] === <BR>&nbsp;&nbsp;&nbsp;&nbsp;pbACE2 [lACEStructSize ]))); <BR>&nbsp;&nbsp;/检查SIDs <BR>&nbsp;&nbsp;fReturn =fReturn &amp;&amp;EqualSid((PSID)(pbACE1+lSIDOffset), <BR>&nbsp;&nbsp; (PSID)(pbACE2+lSIDOffset)); <BR> }leave:; <BR> }catch(...){ <BR> } <BR> return (fReturn); <BR>}</PRE></FONT></DIV>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>以下是第二个函数的内容:</FONT></P>
            <DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT 
            style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">int FindACEInACL(PACL pACL, PACE_UNION pACE ){&nbsp;&nbsp;<BR> int nACEIndex =-1; <BR> try{{ <BR>&nbsp;&nbsp;ACL_SIZE_INFORMATION aclSize; <BR>&nbsp;&nbsp;if (!GetAclInformation(pACL, &amp;aclSize, sizeof(aclSize), <BR>&nbsp;&nbsp; AclSizeInformation)){ <BR>&nbsp;&nbsp; goto leave; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp;while (aclSize.AceCount--){ <BR>&nbsp;&nbsp; PACE_UNION pACETemp; <BR>&nbsp;&nbsp; if(!GetAce(pACL, aclSize.AceCount, (PVOID *)&amp;pACETemp)) <BR>&nbsp;&nbsp;&nbsp;&nbsp;goto leave; <BR>&nbsp;&nbsp; if(IsEqualACE(pACETemp, pACE)){ <BR>&nbsp;&nbsp;&nbsp;&nbsp;nACEIndex = (int)aclSize.AceCount; <BR>&nbsp;&nbsp;&nbsp;&nbsp;break; <BR>&nbsp;&nbsp; } <BR>&nbsp;&nbsp;} <BR> }leave:; <BR> }catch(...){ <BR> } <BR> return (nACEIndex); <BR>}</PRE></FONT></DIV>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>FindACEInACL函数会传回DACL中符合的ACE索引值,如果没有找到,则传回 
            -1值。您应该使用此函数或类似的函数,以找出您打算加到对象DACL的ACEs是否已经存在DACL中(FindACEInACL函数对于寻找您想要使用DeleteAce删除的ACEs也是很有帮助的)。</FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>现在您已经知道哪些ACEs必须加入DACL及已建立的ACEs,现在是计算新DACL大小的时候了。您可以使用在本章前面出现过的CalculateACLSize函数。它可让您使用现存的ACL、SIDs阵列及ACEs阵列来计算ACL大小。您可以传递NULL给这些参数。在我们的范例中,您有可能会传递一个现存的ACL及ACEs阵列,以在加入ACEs后用来计算新ACL的大小。</FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>在您分配内存给新的ACL后,应使用InitializeAcl(本章前面讨论过)来初始化新的ACL。接下来您必须从旧的ACL复制ACEs到新的ACL。</FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>以下的函数显示其实行的方法:</FONT></P>
            <DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT 
            style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">BOOL CopyACL(PACL pACLDestination, PACL pACLSource ){&nbsp;&nbsp;<BR> BOOL fReturn = FALSE; <BR> try{{ <BR>&nbsp;&nbsp;// 取得原始ACL中ACEs的数量 <BR>&nbsp;&nbsp;ACL_SIZE_INFORMATION aclSize; <BR>&nbsp;&nbsp;if (!GetAclInformation(pACLSource, &amp;aclSize, <BR>&nbsp;&nbsp; sizeof(aclSize), AclSizeInformation)){ <BR>&nbsp;&nbsp; goto leave; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp;// 使用GetAce及AddAce复制ACEs <BR>&nbsp;&nbsp;for(ULONG lIndex=0;lIndex &lt; aclSize.AceCount;lIndex++){ <BR>&nbsp;&nbsp; ACE_HEADER* pACE; <BR>&nbsp;&nbsp; if(!GetAce(pACLSource, lIndex, (PVOID*)&amp;pACE)) <BR>&nbsp;&nbsp;&nbsp;&nbsp;goto leave; <BR>&nbsp;&nbsp; if(!AddAce(pACLDestination, ACL_REVISION, MAXDWORD, <BR>&nbsp;&nbsp;&nbsp;&nbsp;(PVOID*)pACE, pACE-&gt;AceSize)) <BR>&nbsp;&nbsp;&nbsp;&nbsp;goto leave; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp;fReturn = TRUE; <BR> }leave:; <BR> }catch(...){ <BR> } <BR> return (fReturn); <BR>}</PRE></FONT></DIV>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>CopyACL函数相当简单,它只不过重复着通过现存DACL之ACEs并复制每一个到新DACL的动作而已。CopyACL使用了AddAce系统函数,其定义如下:</FONT></P>
            <DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT 
            style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">BOOL AddAce( <BR> PACL pACL, <BR> DWORD dwACERevision, <BR> DWORD dwStartingACEIndex, <BR> PVOID pACEList, <BR> DWORD dwACEListLength);</PRE></FONT></DIV>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>请注意,AddAce与AddAccessAllowedAce及AddAccessDeniedAce不同。首先您必须提供ACE;系统不会为您收集ACE并放置到DACL里,这意味着您应要定义ACEs的类型,所以AddAce可以把任意类型的ACE加至DACL中;第二,经由使用以0开始的索引值,AddAce可让您决定想要插入新ACE到DACL的位置;第叁,AddAce可让您增加更多的ACE,经由传递连续的ACEs清单给pACEList参数以及清单大小给dwACEListLength参数(不要被清单中的ACEs数量混淆)。</FONT></P>
            <HR style="LINE-HEIGHT: 25px">

            <P><FONT style="LINE-HEIGHT: 25px" face=Arial color=#3e77d7 size=3 
            Black><B style="LINE-HEIGHT: 25px">说明</B></FONT> </P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>经由允许AddAce复制一个个别函数以呼叫之中所有的原始ACEs,CopyACL范例函数可以更有效地被实作。然而,如此做而取得的ACL结构资讯,应该被视为不透明的。</FONT></P>
            <HR style="LINE-HEIGHT: 25px">

            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>在您复制旧DACL到更宽敞的新DACL之后,可以使用AddAce开始加入ACEs。请注意,必须将您的ACEs插入适当的新DACL索引中,以便维护适当的ACE顺序(关于ACE顺序,请参阅&nbsp;<A 
            style="LINE-HEIGHT: 25px" 
            href="http://www.acejoy.com/doc/serverside/10.htm#533_1" 
            target=_new>表10-6</A>&nbsp;)。您可以使用以下的函数为ACL中的新ACE决定适当的索引值:</FONT></P>
            <DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT 
            style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">ULONG GetACEInsertionIndex(PACL pDACL, PACE_UNION pACENew){&nbsp;&nbsp;<BR> ULONG lIndex = (ULONG)-1; <BR> try{{ <BR>&nbsp;&nbsp;// ACL顺序的ACE类型 <BR>&nbsp;&nbsp;ULONG lFilterType[] = { ACCESS_DENIED_ACE_TYPE, <BR>&nbsp;&nbsp;&nbsp;&nbsp; ACCESS_DENIED_OBJECT_ACE_TYPE, <BR>&nbsp;&nbsp;&nbsp;&nbsp; ACCESS_ALLOWED_ACE_TYPE, <BR>&nbsp;&nbsp;&nbsp;&nbsp; ACCESS_ALLOWED_OBJECT_ACE_TYPE}; <BR>&nbsp;&nbsp;// 决定新的ACE应该隶属的群组 <BR>&nbsp;&nbsp;ULONG lNewAceGroup; <BR>&nbsp;&nbsp;for(lNewAceGroup = 0; lNewAceGroup&lt;4 ; lNewAceGroup++){ <BR>&nbsp;&nbsp; if(pACENew-&gt;aceHeader.AceType == lFilterType[lNewAceGroup]) <BR>&nbsp;&nbsp;&nbsp;&nbsp;break; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp;// 假如群组 == 4,则这个ACE类型不好 <BR>&nbsp;&nbsp;if(lNewAceGroup==4) <BR>&nbsp;&nbsp; goto leave; <BR>&nbsp;&nbsp;// 假如新的ACE是个继承的ACE,那么它会追求其他的ACEs <BR>&nbsp;&nbsp;if((pACENew-&gt;aceHeader.AceFlags &amp; INHERITED_ACE) != 0) <BR>&nbsp;&nbsp; lNewAceGroup+=4; <BR>&nbsp;&nbsp;// 取得ACE总数 <BR>&nbsp;&nbsp;ACL_SIZE_INFORMATION aclSize; <BR>&nbsp;&nbsp;if (!GetAclInformation(pDACL, &amp;aclSize, <BR>&nbsp;&nbsp; sizeof(aclSize), AclSizeInformation)){ <BR>&nbsp;&nbsp; goto leave; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp;// 重复通过ACEs <BR>&nbsp;&nbsp;lIndex = 0; <BR>&nbsp;&nbsp;for(lIndex = 0;lIndex &lt; aclSize.AceCount;lIndex++){ <BR>&nbsp;&nbsp; ACE_HEADER* pACE; <BR>&nbsp;&nbsp; if(!GetAce(pDACL, lIndex, (PVOID*)&amp;pACE)) <BR>&nbsp;&nbsp;&nbsp;&nbsp;goto leave; <BR>&nbsp;&nbsp; // 取得ACL之ACE的群组 <BR>&nbsp;&nbsp; ULONG lAceGroup; <BR>&nbsp;&nbsp; for(lAceGroup = 0; lAceGroup&lt;4 ; lAceGroup++){ <BR>&nbsp;&nbsp;&nbsp;&nbsp;if(pACE-&gt;AceType == lFilterType[lAceGroup]) <BR>&nbsp;&nbsp;&nbsp;&nbsp; break; <BR>&nbsp;&nbsp; } <BR>&nbsp;&nbsp; // 测试不好的ACE <BR>&nbsp;&nbsp; if(lAceGroup==4){ <BR>&nbsp;&nbsp;&nbsp;&nbsp;lIndex = (ULONG)-1; <BR>&nbsp;&nbsp;&nbsp;&nbsp;goto leave; <BR>&nbsp;&nbsp; } <BR>&nbsp;&nbsp; // 调整继承 <BR>&nbsp;&nbsp; if((pACE-&gt;AceFlags &amp; INHERITED_ACE) != 0) <BR>&nbsp;&nbsp;&nbsp;&nbsp;lAceGroup+=4; <BR>&nbsp;&nbsp; // 假如是相同的群组,那么找出插入点 <BR>&nbsp;&nbsp; if(lAceGroup&gt;=lNewAceGroup) <BR>&nbsp;&nbsp;&nbsp;&nbsp;break; <BR>&nbsp;&nbsp;} <BR> }leave:; <BR> }catch(...){ <BR> } <BR> return (lIndex); <BR>}</PRE></FONT></DIV>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>GetACEInsertionIndex函数会找出您插入新ACE的索引值,并在过程中考虑对象ACEs及ACE继承的部份。在您知道索引值之后,可以呼叫AddAce,以增加新的ACE到ACL中。</FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>每个新的ACE都会如此做,然后再使用适当的函数设定新的DACL到安全对象。不要忘了在您使用后清理并释放已经分配的任何内存。</FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>在本章稍早,我曾答应要展示一个在DACL中安排ACEs顺序的范例函数。假如在您彻底完成加入ACEs到DACL前,一点也不想要担心ACE顺序的问题,那么此函数对您可能会很有帮助。以下的OrderDACL函数相当简单,它建立在GetACEInsertionIndex范例函数上:</FONT></P>
            <DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT 
            style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">BOOL OrderDACL(PACL pDACL ){&nbsp;&nbsp;<BR> BOOL fReturn = FALSE; <BR> try{{ <BR> // 取得ACL大小及ACE总数 <BR> ACL_SIZE_INFORMATION aclSize; <BR> if (!GetAclInformation(pDACL, &amp;aclSize, <BR>&nbsp;&nbsp;sizeof(aclSize), AclSizeInformation)){ <BR>&nbsp;&nbsp;goto leave; <BR> } <BR> // 为暂时的ACL取得内存 <BR> PACL pTempDACL = (PACL)_alloca(aclSize.AclBytesInUse); <BR> if (pTempDACL==NULL) <BR>&nbsp;&nbsp;goto leave; <BR> // 初始暂时的ACL <BR> if (!InitializeAcl(pTempDACL, aclSize.AclBytesInUse, <BR>&nbsp;&nbsp;ACL_REVISION)) <BR>&nbsp;&nbsp;goto leave; <BR> // 重复通过ACEs <BR> for (ULONG lAceIndex = 0; <BR>&nbsp;&nbsp;lAceIndex &lt; aclSize.AceCount ; lAceIndex++){ <BR>&nbsp;&nbsp;// 取得ACE <BR>&nbsp;&nbsp;PACE_UNION pACE; <BR>&nbsp;&nbsp;if (!GetAce(pDACL, lAceIndex, (PVOID*)&amp;pACE)) <BR>&nbsp;&nbsp; goto leave; <BR>&nbsp;&nbsp;// 找出位置,并且把ACE加入temp DACL <BR>&nbsp;&nbsp;ULONG lWhere = GetACEInsertionIndex(pTempDACL, pACE); <BR>&nbsp;&nbsp; if (!AddAce(pTempDACL, ACL_REVISION, <BR>&nbsp;&nbsp;&nbsp;&nbsp;lWhere, pACE, pACE-&gt;AceSize)) <BR>&nbsp;&nbsp;&nbsp;&nbsp;goto leave; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp;// 复制temp DACL到原始的 <BR>&nbsp;&nbsp;CopyMemory(pDACL, pTempDACL, aclSize.AclBytesInUse); <BR>&nbsp;&nbsp;fReturn = TRUE; <BR> } <BR> leave:; <BR> }catch(...){ <BR> } <BR> return (fReturn); <BR>}</PRE></FONT></DIV>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>让我们看看真实世界实作讨论过的技巧范例。</FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e74d7 
            size=3><B style="LINE-HEIGHT: 25px">修改DACL范例<BR 
            style="LINE-HEIGHT: 25px"> </B></FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>我们的范例提供了一组有用的函数给服务开发人员,它显示如何修改一个现存DACL的方法。我使用了Windows中的window站台及桌面安全对象。</FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e80d7 
            size=2><B 
            style="LINE-HEIGHT: 25px">&nbsp;window站台&nbsp;</B></FONT>是Windows的安全对象,包含了剪贴簿、一组通用元素及桌面对象的集合。window站台可以是互动式的,意味着使用者可以看到它的「桌面」,一个互动式windows站台也包含键盘及滑鼠资讯。一个程序可以有一个与它相关联的个别windows站台。</FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e80d7 
            size=2><B 
            style="LINE-HEIGHT: 25px">&nbsp;桌面&nbsp;</B></FONT>是一个包含在window站台内的安全对象。一个桌面维护着一个逻辑的显示外观,并包含功能表、视窗及萤幕上的其他可视对象。</FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>不与使用者互动的服务和互动式桌面没有关联。当使用者登入系统时,互动式window站台(称为WinSta0)的DACL及其预设桌面(称为Default)会被重新设定,并且把此对象的存取权给予使用者。最后,只有已登录的使用者及系统会被授予对此对象的存取权。</FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e80d7 
            size=2><B 
            style="LINE-HEIGHT: 25px">&nbsp;问题描述&nbsp;</B></FONT>服务有时必须在任一信任成员帐户下(使用下一章要讨论的CreateProcessAsUser函数)建立另一个程序,以在目前没有与系统互相作用的使用者环境下建立一个程序。假如此程序需要与使用者互动,而使用者帐户对互动式window站台及预设桌面没有存取权,则系统呼叫CreateProcessAsUser函数时会失败。</FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>由于发现了这个问题,在建立程序之前,您必须检查这些对象之DACLs的使用者存取权利。假如没有找到这些权利,则它们必须被加入。首先检查权利是很重要的,因为盲目地增加ACE到使用者对象,最后可能会耗尽系统中的资源(通常您只能增加约80个ACEs到window站台)。</FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e80d7 
            size=2><B 
            style="LINE-HEIGHT: 25px">&nbsp;解决方案&nbsp;</B></FONT>现在让我们开始着手处理解决方案。我使用这一节所讨论的工具及观念(和一些范例函数)实作了两个函数:一个可让信任成员存取window站台,而另一个可让信任成员存取桌面。这些函数非常简单。尽管修改对象DACL的程序看起来有点令人怯步,但真实世界中的程序并没有我们所想像的复杂。以下的程序代码可让信任成员存取window站台:</FONT></P>
            <DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT 
            style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">BOOL AllowAccessToWinSta(PSID psidTrustee, HWINSTA hWinSta ){&nbsp;&nbsp;<BR> BOOL fReturn = FALSE; <BR> PSECURITY_DESCRIPTOR psdWinSta = NULL; <BR> PACE_UNION pACENew = NULL; <BR> try{{ <BR>&nbsp;&nbsp;// 取得window站台的DACL <BR>&nbsp;&nbsp;PACL pDACLWinSta; <BR>&nbsp;&nbsp;if(GetSecurityInfo(hWinSta, SE_WINDOW_OBJECT, <BR>&nbsp;&nbsp; DACL_SECURITY_INFORMATION, NULL, NULL, &amp;pDACLWinSta, <BR>&nbsp;&nbsp; NULL, &amp;psdWinSta) != ERROR_SUCCESS) <BR>&nbsp;&nbsp; goto leave; <BR>&nbsp;&nbsp;// 分派新的ACE <BR>&nbsp;&nbsp;// 这个存取授予互动地登录的使用者 <BR>&nbsp;&nbsp;PACE_UNION pACENew = AllocateACE(ACCESS_ALLOWED_ACE_TYPE, 0, <BR>&nbsp;&nbsp; DELETE|WRITE_OWNER|WRITE_DAC|READ_CONTROL| <BR>&nbsp;&nbsp; WINSTA_ENUMDESKTOPS|WINSTA_READATTRIBUTES| <BR>&nbsp;&nbsp; WINSTA_ACCESSCLIPBOARD|WINSTA_CREATEDESKTOP| <BR>&nbsp;&nbsp; WINSTA_WRITEATTRIBUTES|WINSTA_ACCESSGLOBALATOMS| <BR>&nbsp;&nbsp; WINSTA_EXITWINDOWS|WINSTA_ENUMERATE|WINSTA_READSCREEN, <BR>&nbsp;&nbsp; psidTrustee); <BR>&nbsp;&nbsp;// ACE是否已经在DACL中? <BR>&nbsp;&nbsp;if (FindACEInACL(pDACLWinSta,pACENew) == -1){ <BR>&nbsp;&nbsp; // 假如没有,计算新的DACL大小 <BR>&nbsp;&nbsp; ULONG lNewACL = CalculateACLSize(pDACLWinSta, NULL, 0, <BR>&nbsp;&nbsp;&nbsp;&nbsp;&amp;pACENew, 1 ); <BR>&nbsp;&nbsp; // 分派内存给新的DACL <BR>&nbsp;&nbsp; PACL pNewDACL = (PACL)_alloca(lNewACL); <BR>&nbsp;&nbsp; if (pNewDACL == NULL) <BR>&nbsp;&nbsp;&nbsp;&nbsp;goto leave; <BR>&nbsp;&nbsp; // 初始ACL <BR>&nbsp;&nbsp; if (!InitializeAcl(pNewDACL, lNewACL, ACL_REVISION)) <BR>&nbsp;&nbsp; goto leave; <BR>&nbsp;&nbsp; // 复制ACL <BR>&nbsp;&nbsp; if (!CopyACL(pNewDACL, pDACLWinSta)) <BR>&nbsp;&nbsp; goto leave; <BR>&nbsp;&nbsp; // 取得新ACE的位置 <BR>&nbsp;&nbsp; ULONG lIndex = GetACEInsertionIndex(pNewDACL, pACENew); <BR>&nbsp;&nbsp; // 增加新的ACE <BR>&nbsp;&nbsp; if (!AddAce(pNewDACL, ACL_REVISION, lIndex, <BR>&nbsp;&nbsp;&nbsp;&nbsp;pACENew, pACENew-&gt;aceHeader.AceSize)) <BR>&nbsp;&nbsp;&nbsp;&nbsp;goto leave; <BR>&nbsp;&nbsp; // 设定DACL回到window站台 <BR>&nbsp;&nbsp; if (SetSecurityInfo(hWinSta, SE_WINDOW_OBJECT, <BR>&nbsp;&nbsp;&nbsp;&nbsp;DACL_SECURITY_INFORMATION, NULL, NULL, <BR>&nbsp;&nbsp;&nbsp;&nbsp;pNewDACL, NULL)!=ERROR_SUCCESS) <BR>&nbsp;&nbsp;&nbsp;&nbsp;goto leave; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp;fReturn = TRUE; <BR> }leave:; <BR> }catch(...){ <BR> } <BR> // 清除 <BR> if(pACENew != NULL) <BR>&nbsp;&nbsp;LocalFree(pACENew); <BR> if(psdWinSta != NULL) <BR>&nbsp;&nbsp;LocalFree(psdWinSta); <BR> return (fReturn); <BR>}</PRE></FONT></DIV>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>下一个范例函数可让信任成员存取桌面:</FONT></P>
            <DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT 
            style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">BOOL AllowAccessToDesktop( PSID psidTrustee, HDESK hDesk ){&nbsp;&nbsp;<BR> BOOL fReturn = FALSE; <BR> PSECURITY_DESCRIPTOR psdDesk = NULL; <BR> PACE_UNION pACENew = NULL; <BR> try{{ <BR>&nbsp;&nbsp;// 取得桌面的DACL <BR>&nbsp;&nbsp;PACL pDACLDesk; <BR>&nbsp;&nbsp;if(GetSecurityInfo(hDesk, SE_WINDOW_OBJECT, <BR>&nbsp;&nbsp; DACL_SECURITY_INFORMATION, NULL, NULL, &amp;pDACLDesk, <BR>&nbsp;&nbsp; NULL, &amp;psdDesk) != ERROR_SUCCESS) <BR>&nbsp;&nbsp; goto leave; <BR>&nbsp;&nbsp;// 分派新的ACE <BR>&nbsp;&nbsp;// 这个存取授予互动地登录的使用者 <BR>&nbsp;&nbsp;PACE_UNION pACENew = AllocateACE(ACCESS_ALLOWED_ACE_TYPE, 0, <BR>&nbsp;&nbsp; DELETE|WRITE_OWNER|WRITE_DAC|READ_CONTROL| <BR>&nbsp;&nbsp; DESKTOP_READOBJECTS|DESKTOP_CREATEWINDOW| <BR>&nbsp;&nbsp; DESKTOP_CREATEMENU|DESKTOP_HOOKCONTROL| <BR>&nbsp;&nbsp; DESKTOP_JOURNALRECORD|DESKTOP_JOURNALPLAYBACK| <BR>&nbsp;&nbsp; DESKTOP_ENUMERATE|DESKTOP_WRITEOBJECTS|DESKTOP_SWITCHDESKTOP, <BR>&nbsp;&nbsp; psidTrustee); <BR>&nbsp;&nbsp;// ACE是否已经在DACL中? <BR>&nbsp;&nbsp;if (FindACEInACL(pDACLDesk, pACENew) == -1){ <BR>&nbsp;&nbsp; // 假如没有,计算新的DACL大小 <BR>&nbsp;&nbsp; ULONG lNewACL = CalculateACLSize(pDACLDesk, NULL, 0, <BR>&nbsp;&nbsp;&nbsp;&nbsp;&amp;pACENew, 1 ); <BR>&nbsp;&nbsp; // 分配内存给新的DACL <BR>&nbsp;&nbsp; PACL pNewDACL = (PACL)_alloca(lNewACL); <BR>&nbsp;&nbsp; if (pNewDACL == NULL) <BR>&nbsp;&nbsp;&nbsp;&nbsp;goto leave; <BR>&nbsp;&nbsp; // 初始ACL <BR>&nbsp;&nbsp; if (!InitializeAcl(pNewDACL, lNewACL, ACL_REVISION)) <BR>&nbsp;&nbsp;&nbsp;&nbsp;goto leave; <BR>&nbsp;&nbsp; // 复制ACL <BR>&nbsp;&nbsp; if (!CopyACL(pNewDACL, pDACLDesk)) <BR>&nbsp;&nbsp;&nbsp;&nbsp;goto leave; <BR>&nbsp;&nbsp; // 取得新ACE的位置 <BR>&nbsp;&nbsp; ULONG lIndex = GetACEInsertionIndex(pNewDACL, pACENew); <BR>&nbsp;&nbsp; // 增加新的ACE <BR>&nbsp;&nbsp; if (!AddAce(pNewDACL, ACL_REVISION, lIndex, <BR>&nbsp;&nbsp;&nbsp;&nbsp;pACENew, pACENew-&gt;aceHeader.AceSize)) <BR>&nbsp;&nbsp;&nbsp;&nbsp;goto leave; <BR>&nbsp;&nbsp; // 设定DACL回到桌面 <BR>&nbsp;&nbsp; if (SetSecurityInfo(hDesk, SE_WINDOW_OBJECT, <BR>&nbsp;&nbsp;&nbsp;&nbsp;DACL_SECURITY_INFORMATION, NULL, NULL, <BR>&nbsp;&nbsp;&nbsp;&nbsp;pNewDACL, NULL)!=ERROR_SUCCESS) <BR>&nbsp;&nbsp;&nbsp;&nbsp;goto leave; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp;fReturn = TRUE; <BR> }leave:; <BR> }catch(...){ <BR> } <BR> // 清除 <BR> if(pACENew != NULL) <BR> LocalFree(pACENew); <BR> if(psdDesk != NULL) <BR>&nbsp;&nbsp;LocalFree(psdDesk); <BR> return (fReturn); <BR>}</PRE></FONT></DIV>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>以下的程序片段显示如何使用这些函数的范例。此程序代码为内建的Everyone群组建立了一个SID,并将它传递到AllowAccessToWinSta及AllowAccessToDesktop函数中:</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 psidEveryone;&nbsp;&nbsp;<BR>// 为内建的「Everyone」群组建立一个SID <BR>SID_IDENTIFIER_AUTHORITY sidAuth = SECURITY_WORLD_SID_AUTHORITY; <BR>if (!AllocateAndInitializeSid(&amp;sidAuth, 1, SECURITY_WORLD_RID, <BR> 0, 0, 0, 0, 0, 0, 0, &amp;psidEveryone )){ <BR> // 错误 <BR>} <BR>HWINSTA hWinSta = GetProcessWindowStation(); <BR>if (hWinSta == NULL){ <BR> // 错误 <BR>} <BR>AllowAccessToWinSta(psidEveryone, hWinSta); <BR>HDESK hDesk = GetThreadDesktop(GetCurrentThreadId()); <BR>if (hDesk == NULL){ <BR> // 错误 <BR>} <BR>AllowAccessToDesktop(psidEveryone, hDesk);</PRE></FONT></DIV>

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?