|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionFew would challenge the assertion that Windows Management Instrumentation (WMI) has significantly enhanced manageability of the Windows OS desktop. Derived from the Distributed Management Task Force (DMTF) and Web Based Enterprise Management (WBEM) initiatives intended to standardize management of the desktop, WMI allows for standard methods of access to Windows OS components such as registry settings, OS information, PC hardware data, event logs, etc. WMI leverages the Common Information Model (CIM), a general schema describing computer resources and components. The idea of DMTF/WBEM was to standardize access to data and methods across OS platforms previously available only to those who understood the intricacies of the native API set. If you (or a group you are a member of) are not a trustee of the local or domain Administrators group, the default WMI security settings for Windows 2000/XP/2003/Vista (Beta 2) do not allow the ability to remotely connect to the WMI service. This could be problematic since you cannot read what you cannot access. Because organizations may prefer to delegate tasks such as reading remote WMI counters to selected employees without elevating them to Administrator status, the default WMI security may have to be modified. Using the codeWMI security is implemented by granting trustees permissions to WMI namespaces. A WMI namespace is a collection of logically grouped data and methods describing computer components or services. You can view WMI namespace security on the Windows platform by opening the WMI Control in the Computer Management console, and then expand "Services and Applications." Click "WMI Control" to highlight, then right click and choose "Properties."
You should now see all available items for WMI management. Notice you can back up/restore the WMi repository here (Backup/Restore tab), set the default namespace for scripting (under the Advanced tab), or even set the logging level for errors in this applet.
Go to the Security tab and then expand the Root node of the namespace tree. If you click on a namespace, and then select Security, you should be able to observe the security applied to that particular namespace.
If your machine has retained default security, you should notice that the Administrators group in Windows XP and the Domain Administrators group on a Windows 2003 domain controller are the only two groups with the Remote Enable permissions. Technically, WMI is a DCOM application, thus any change to DCOM security (via dcomconfig.exe) may also affect WMI. However, it is much safer to implement any necessary changes through the WMI applet shown above, because changes to DCOM security can potentially affect all DCOM applications, something you probably don’t want to do. Because the group I work for require personnel who are not members of the Domain Administrators group to read CIMv2 data from remote servers, and since I didn’t particularly relish spending valuable time executing terminal service to implement the necessary security modifications, I created the utility described herein. Essentially, I required a tool to read WMI namespace security (possibly to database?) and implement any necessary security changes. Additionally, I wanted a command line utility to script the necessary changes or monitor future WMI namespace settings. Below are possible security settings for WMI namespaces in Windows 2000/XP/ 2003/Vista (Beta 2). Permissions Explanation
Execute Methods: Execute Read/Write/Delete objects from CIM
Partial Write : Write to static WMI objects
Provide Write : Write to dynamic WMI objects
Enable Account : Read properties of WMI objects
Remote Enable : Access WMI from remote systems
Read Security : Read security settings
Edit Security : Change security settings
Since these security settings are hosted by the same security model as other objects in a Microsoft OS, you should know something about how access control in the Windows NT/2000/XP/2003 platforms work. Objects in Windows 32-bit platforms are secured by a security descriptor (SD) which contains, among other things, two types of Access Control Lists (ACLs): a Discretionary Access Control List (DACL) and a System Access Control List (SACL). For this utility, we’re only concerned with the DACL, which specifies what a trustee can or cannot do to the object. The DACL is itself comprised of trustee Security IDs (SIDs) and their requisite Access Control Entries (ACEs). Trustees are identified in the DACL by their SID which is mapped to a trustee by the OS upon account creation. When you log into a Windows OS, the OS grants you a token with you personal SID and any SIDs of groups you are a member of. These SIDs are checked by the OS when you try to access an object secured by the OS, and matched against the SIDs in the DACL. You will get the culmination of access permissions granted to the SIDs in your token unless an explicit access denied is encountered. Now that you have a concept of WMI namespace security, let’s delve into the code to modify it. I wrote the utility for the 1.1 version of the .NET framework, using the C# language. For simplicity, I created two classes, The main program (WmiSecurity.cs) determines whether the user wants to view existing WMI security or modify existing WMI security by the value of the unsigned integer, public static uint CreateAccessMask(string sAccess)
{
if(sAccess.ToUpper()=="READ")
{
return AceStringManager.WBEM_ENABLE;
}
else if (sAccess.ToUpper()=="REMOTEACCESS")
{
return AceStringManager.WBEM_ENABLE|
AceStringManager.WBEM_REMOTE_ACCESS;
}
else if (sAccess.ToUpper()=="PROVIDERWRITE")
{
return AceStringManager.WBEM_ENABLE|
AceStringManager.WBEM_WRITE_PROVIDER;
}
else if (sAccess.ToUpper()=="PARTIALWRITE")
{
return AceStringManager.WBEM_ENABLE|
AceStringManager.WBEM_PARTIAL_WRITE_REP;
}
else if (sAccess.ToUpper()=="FULLWRITE")
{
return AceStringManager.WBEM_ENABLE|
AceStringManager.WBEM_FULL_WRITE_REP;
}
else if (sAccess.ToUpper()=="FULL")
{
return AceStringManager.WBEM_REMOTE_ACCESS|
AceStringManager.WBEM_METHOD_EXECUTE|
AceStringManager.WBEM_FULL_WRITE_REP|
AceStringManager.WBEM_ENABLE|
AceStringManager.READ_CONTROL|
AceStringManager.WRITE_DAC;
}
else
return 0;
}
Be aware that the security settings available were consolidated considerably to match common security choices deemed appropriate. For instance, looking at the The main program (WmiSecurity.cs) calls the if(sTrustee.IndexOf("\\")==npos)
changesec.Modify(sComputer, sTrustee);
else
{
changesec.Modify(sComputer,
changesec.getSidStringFromName(sTrustee));
}
The 2 letter constants are defined in Sddl.h as well know SIDs, i.e. Domain Users, Domain Guests, Domain Admins, etc. Look at the Platform SDK for detailed information, but suffice to say that ‘DA’ represents domain admins, ‘DG’ represents domain guests, and so on. The important thing to understand is that the OS will take care of converting these constants into useable SIDs for us. We are not so lucky for users and groups the OS has not predefined - for these we must convert the name to a SID. public string getSidStringFromName(string sAccount)
{
StringBuilder sbDomain; // Domain name.
Int32 iDomainSize; // Domain name size.
Int32 iSidSize; // Size of the returned SID.
IntPtr pAccountSid = IntPtr.Zero; // Sid of account
IntPtr pSid = IntPtr.Zero; // Set ptr to zero.
int iError; // API error
SID_NAME_USE snu;
string sSid = "";
iSidSize=0;
sbDomain = new StringBuilder();
iDomainSize=0;
// The 1st time this will fail, but we can
// then alloc necessary sid buffer size
LookupAccountName(null, sAccount, pAccountSid,
ref iSidSize, sbDomain, ref iDomainSize, out snu);
pAccountSid=Marshal.AllocHGlobal(iSidSize);
// Try a 2nd time with proper buffer size...
if(!LookupAccountName(null, sAccount, pAccountSid,
ref iSidSize, sbDomain, ref iDomainSize, out snu))
{
iError=Marshal.GetLastWin32Error();
// free up allocation
Marshal.FreeHGlobal(pAccountSid);
throw new Exception("LookupAccountName error: " +
iError.ToString());
}
else
{
if(!ConvertSidToStringSid(pAccountSid, ref sSid))
{
iError=Marshal.GetLastWin32Error();
// free up allocation
Marshal.FreeHGlobal(pAccountSid);
throw new Exception("ConvertSidToStringSid error: " +
iError.ToString());
}
}
Marshal.FreeHGlobal(pAccountSid);
return sSid;
}
Figure 1: getSidStringFromName I use ChangeNameSpaceSecurity uses the Before anything else is done, ace_type;ace_flags;rights;object_guid;inherit_object_guid;account_sid
Notice that each component is separated by a semi-colon and each component must be in order. With this in mind, the AceStringManager object’s constructor is called as shown below: AceStringManager asm = new AceStringManager(sTrusteeSid,
this.m_bAccessAllowed, this.m_bRecursive);
which constructs the new object with the trustee SID (more on this), ace type, and whether or not the modifications will be recursive to other objects in the namespace. To clarify, let’s assume you want to allow the HelpDesk group the remote connect and read ability on your network servers. Back in Now having obtained the necessary Ace string, we make use of If you look up public ManagementBaseObject InvokeMethod, string methodName,
ManagementBaseObject inParameters, InvokeMethodOptions options);
And since we’re looking to get the existing security on the namespace, we use “ Now to view the resulting data, we have to understand a little more about Security Descriptors (SDs). Security Descriptors are defined as an opaque structure of pointers to DACLs and SACLs, Primary Owner SIDs, etc. Opaque means you should never attempt to directly modify the contents of a SD directly – instead you should defer to existing APIs specifically created for this purpose. I alluded to the fact that we’ll be using the high level access control APIs, and here’s where the payoff is. We can take the output of the WMI method You’ll notice the use of Platform Invocation (PInvoke) for calling unmanaged API’s in this utility. For the 1.1 framework, there is no way around it for some of the security API’s, although that may change in the future. A comprehensive look at InteropServices would fill a book, so I’ll just touch on a few things. Notice the error code after the call to
The ConvertStringSecurityDescriptorToSecurityDescriptor(
stringSecurityDescriptor, 1, out pSystemSD, out sdSize)
does. The variable byte[] securityDescriptor = new byte[sdSize];
Marshal.Copy(pSystemSD,securityDescriptor, 0, sdSize);
creates a byte array with size defined by ManagementBaseObject inParams = systemSecurity.GetMethodParameters("SetSD");
Which returns a inParams["SD"] = securityDescriptor;
outParams = systemSecurity.InvokeMethod("SetSD", inParams, null);
Essentially, we pass in a SD formatted the way the system can use, and invoke the
So at this point, some examples should suffice to illustrate the use of the utility. Suppose you wanted to add the domain HelpDesk group to the CIMV2 and subsequent namespaces on the S223001 computer. Further, suppose this group should have the ability to remotely connect and read WMI objects. To do this: WmiSecurity /C=S223001 /A /N=Root\CimV2 /M=MyDomain\HelpDesk:REMOTEACCESS /R Of course, the user executing the utility requires the Edit Security right on the target namespace or the ubiquitous “Access Denied” error will appear. Likewise, to view the existing security on a WMI namespace: WmiSecurity /C=S223001 /N=Root\CimV2 /R Which will present the security on the Root\Cimv2 namespace and all child namespaces. Where /C = Computer (without UNC specification) to view. Where /N = Namespace to target Where /R (optional)= view all subsequent WMI namespaces as well as present one One final thought: please be aware that any modification to WMI namespace security could potentially weaken system security. Thus, extensive testing should preclude any WMI namespace security modification, particularly in a real world environment. Properly planned, WMI security modifications will enhance employee productivity without introducing possible security breaches. Points of InterestThis is my first foray into the managed world code with respect to systems programming. In short, there is a fair amount of research to be done if the appropriate method is not available within the .NET framework to accomplish what you want. On the other hand, the actual coding and testing of the project is much easier, and with built in exception handling, dependable. WMI is a part of the Windows platform I would recommend all systems engineers and programmers look into. HistoryThis project was developed about 11 months ago, and I have since moved onto other things. However, I plan to recode this in C++ so that WMI namespace security fits into my larger overall object security code I have written.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||