Implementing MI Provider (2) – Define Schema


Define Schema

To implement a MI provider, the first step is to model the management data, i.e., to define the schema of data. The schema has to be defined in DMTF’s Managed Object Format (MOF), which is very similar to WMI MOF format except partial syntax of WMI MOF is not compliant with DMTF MOF.

Definition of MOF file can be found at http://www.dmtf.org/education/mof. Following is the copy of the definition from the page, “A MOF file can be encoded in either Unicode or UTF-8 format. MOF files are text files that contains definitions of classes and instances using the Managed Object Format (MOF) language. They can be edited using your favorite text editor or tool of choice.”

For MI provider, the MOF file defines only classes that modeling the underline management objects. One class maps to one category of management objects, for example Win32_Process class was defined to manage processes that running on Windows OS.

As described in Implementing MI Provider (1), there are 3 categories of providers, instance provider, association provider and indication provider. The type of provider actually refers to the type of class that being implemented, while the type of class depends on the class qualifier. Following are MOF examples for the 3 typical classes,

 

class MSFT_WindowsProcess : CIM_Process
{



}

MOF Example 2.0: (normal) Class

 

 

[Association]
class MSFT_WindowsServiceProcess
{



}

MOF Example 2.1: Association Class

 

 

[Indicaiton]

class MSFT_WindowsServiceStopped

{



}

MOF Example 2.2: Indication Class

 

 

Schema Sample

An MI provider could implement one or more of above type’s classes. Be default those classes have fixed number of operations, generally, a (normal) class could have enumerate instance, get instance, delete instance, modify instance, and create instance; an association class could have assoicators of instance and references of instance operation; and an indication class could have enable indication, subscribe, unsubscribe, disable indication operations. Of course, a (normal) class could also have arbitrary number of methods defined, one method maps to one operation. Details will be discussed in the following blog Implementing MI Provider (3).

To understand how to define classes that derives from standard class, following table pastes the MOF file from Windows 8 SDK MIAPI Sample, it contains (normal) class, association class, and indication classes,

(1) MSFT_WindowsProcess derives from CIM_Process (CIM standard class), which models the process objects which is running on Windows Operating System. It is a (normal) class.

(2) MSFT_WindowsService derives from CIM_Service (CIM standard class), which models the win32 services objects configured on Windows Operating System.  It is a (normal) class.

(3) MSFT_WindowsServiceManager defines only an static method, which reads service objects and return to client via streaming approach. The “stream” qualifier will be discussed in future blog.

(4) MSFT_WindowsServiceProcess derives from CIM_ServiceProcess (CIM standard class), which is an association class. The “association” qualifier is inherited from parent class “CIM_ServiceProcess”.

(5) MSFT_WindowsServiceStopped derives from CIM_InstModification (CIM standard class), which is an indication class. It produces indication(s) upon the stop of any running window service.

(6) MSFT_WindowsServiceStarted derives from CIM_InstModification (CIM standard class), which is an indication class. It produces indication(s) upon the start of any window service.

 

//

// THIS CODE AND INFORMATION IS PROVIDED “AS IS” WITHOUT WARRANTY OF

// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO

// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A

// PARTICULAR PURPOSE.

//

// Copyright (c) Microsoft Corporation. All rights reserved

//

#pragma include (“cim_schema_2.26.0.mof”)

#pragma include (“MSFT_Qualifiers.mof”)

 

//

// MSFT_WindowsProcess class derives from CIM_Process class,

// which defines the schema for the processes running on windows OS.

//

[ClassVersion(“1.0.0”)]

class MSFT_WindowsProcess : CIM_Process

{

      String CommandLine;

         [Description(“This instance method demonstrates modifying the ”             

        “and any other number to indicate an win32 error code.”)]

      Uint32 SetPriority([In] uint32 Priority);

 

     [static, Description(“This static method demonstrates creating a process ”          
        “by supplying commandline to start a new process.”

               “It will output the reference to the newly created process.”

               “The method returns an integer value of 0 if the process “

               “was successfully created, and any other number to “

               “indicate an win32 error code.”)]

        uint32 Create([In] string CommandLine, [Out] CIM_Process ref Process);

};

 

//  

// MSFT_WindowsService class derives from CIM_Service class,

// which defines the schema for the services present on windows OS.

//

[ClassVersion(“1.0.0”)]

class MSFT_WindowsService : CIM_Service

{

       // To implement methods defined in parent class,

       // it is mandatory to copy those methods definition

       // from parent class and redefine in child class

       uint32 StartService();

       uint32 StopService();

};

 

[Description(“This class demonstrates designing a WMI class “

 ” having a static method to use the feature of steam output parameter, “

 “which allows provider to send output array element one by one back to “

 “client instead of sending the whole array back at one time.”),

 ClassVersion(“1.0.0”)]

class MSFT_WindowsServiceManager

{

 

// GetWindowsServices method reads list of MSFT_WindowsService instances with specific status,

// value of 0 for stopped services, 1 for running services, and other values for all services.

[static] uint32 GetWindowsServices(

    [in, ValueMap { “0”, “1”, “..”}, Values {“Running”,”Stopped”, “All”}]

    uint32 status,

    [out, stream, EmbeddedInstance(“MSFT_WindowsService”)]
    string services[]);

};

 

// 

// MSFT_WindowsServiceProcess class derives from CIM_ServiceProcess class,

// which associates present services instance with running process instance on windows OS.

//

[ClassVersion(“1.0.0”)]

class MSFT_WindowsServiceProcessCIM_ServiceProcess

{

};

 

//

// MSFT_WindowsServiceStopped class derives from CIM_InstModification class,

// which presents the notification of a stopped service on windows OS.

//

[ClassVersion(“1.0.0”)]

class MSFT_WindowsServiceStopped : CIM_InstModification

{

};

 

//

// MSFT_WindowsServiceStarted class derives from CIM_InstModification class,

// which presents the notification of a started service on windows OS.

//

[ClassVersion(“1.0.0”)]

class MSFT_WindowsServiceStartedCIM_InstModification

{

};

MOF of Windows 8 SDK MIAPI Sample

For complete MOF syntax, please refer to DSP0004 version 2.6.0.

 

Haowei Qin

Senior SDE

Standards Based Management

Comments (10)

  1. Is it possible to host a decoupled MI provider with on-demand activation? The sample code doesn't cover this, and every attempt I have made to achieve this has failed.

    A coupled provider is loaded on-demand by WMI, and unloaded automatically. However, it doesn't seem to be possible to achieve the same result with a decoupled hosting service – the service has to be running all of the time, and if it stops for any reason the provider is permanently inaccessible until a reboot / manual service start.

    I've tried using the normal DCOM activation methods and registry keys for the applicaton/class, but these don't seem to work for MI providers – the service is never started.

  2. To host a decoupled MI provider. Inside the MIAPI sample code, you will find the decouple host code @ MIAPIDecoupledHostDecoupledHost.c, perticularly, the API called MI_Application_NewHostedProvider API is the one used to hook the provider into WMI server.

    However, on-demand activation is NOT supported for now. Can you tell what the perticular scenario that you want to achieve through (on-demand activation service) which cannot be achieved through coupled provider?

  3. Yes, I have used the DecoupledHost sample to host the provider, and that was the basis of my previous investigations. The key problem with coupled providers is that they run in low security contexts only; we require higher privileges for certain internal operations (whilst implementing full security boundaries using impersonation to limit information/access by individual users).

    I'd be more than happy to discuss our exact scenario in detail with you privately – please drop me an email at "firstname lastname at harakan com" (with my name as above, and "." between them and after the domain name).

  4. Thanks Chris for the details of the scenario. (Let's keep the discussion here:))

    From security perspective, each thread that calls into the MI provider (such as Enumerate/Modify/ InvokeMethod/…,  except indication class's operations), It is already impersonated as client, i.e., individual user. Thus individual users calling into the MI provider will run the logic under their impersonated  token, so it is sufficient to "limit information/access";

    A second problem you want to resolve is, "require higher privileges for certain internal operations". There are potentially two solutions,

    (1) Hosting your provider under NetworkService Account. Try to encrypted admin credential info somehow, then your MI provider need to log on the admin user when perform internal operations which require high privileges.

    (2) (Not recommended due to security risk bring to the server where the provider get installed) Host your provider under LocalSystem account. Then for internal operations which require high privileges, MI provider needs to CoReverToSelf first to LocalSystem and do your logic; after internal operations done, MI provider need to CoImpersonateClient again to make sure current thread running under impersonated client token.

    The above solutions are referring to host the provider as coupled provider.

  5. Our provider uses low-level (Admin-only) APIs to collect information from various sources into an abstracted internal object cache, and to execute operations per user requests; the security of these objects and methods is independent of the actual low-level APIs used for communication – this is what I meant by "limit information/access" (the privileges of the impersonated client are used to determine which of our internal objects are visible to that client, and which methods are permitted – this has no direct relationship with the security requirements of the underlying communication APIs being used in any particular case).

    For the moment, our provider is running as a coupled provider as NetworkService, but this limits all access to Admin+elevated clients only. The recommendation from the MS team defining the standard WMI classes we implement is that GetInstance/Enumerate/etc. should provide read-only access to our objects from non-Admin users. We also want to replace our existing DCOM service+client library with the MI provider+client library, but that functionality also requires read-only access from non-privileged users. Requiring all client-side code to run with Elevated Admin privileges is a far greater attack surface from a security standpoint, and the clients include MS-provided and third-party products over which we do not have control.

    Your first suggestion isn't really practical; this would require storing Admin-type credentials in a way that can be accessed by any user (even if encrypted, these could be accessed by reverse-engineering the provider), and that need to be maintained across every server with the provider installed which is an administrative nightmare as an Admin user would have to access each and every system to provide the new credentials every time any change was required. As it may not be clear if/when credentials on a given server are out-of-date or incorrect, this also leads to inconsistent behaviours and very hard-to-diagnose failure modes; a very poor customer experience.

    Running the provider as a coupled provider under LocalSystemHost is an option we have looked at; unfortunately this causes Warning Event 63 messages to be raised by WMI, causing customers to distrust our provider's security and be unwilling to install it (even when we assure them that we have implemented and tested the necessary security measures, and that it is not a security risk).

    If we could run as LocalSystemHost without generating Event 63 warnings that would be a good first step, but ideally we would still prefer running decoupled so that we can control our own lifetime (e.g. to keep the provider running during long external operations whilst no MI objects are referenced by clients, avoiding unnecessary startup delays rebuilding our object cache, and allowing finer-grain handling of external events). As far as I'm aware there is no way to control lifetime from within a coupled provider; if there are MI_xxx functions for this or other recommended techniques, any pointers would be much appreciated!

  6. Also, on the client side do you provide (or have any plans to provide) an equivalent to the WMIv1 "MgmtClassGen" to generate strongly-typed C# classes that can be used with the CIM objects(Microsoft.Management.Infrastructure.CimInstance etc.)?

  7. @Chris,

    Thanks for the details. Unfortunately 1) There is no support of on-demand activation of decoupled provider yet.

    2) For CImInstance, there is no such tool to generate strong-typed C# classes yet.

  8. Thank you for your suggestions and for taking the time to understand our scenario. I hope the devs will consider this feedback and use case for future improvements to the MI framework – it does have a lot of potential, and the combination of MI and PowerShell in Server 2012 is a revolutionary step forward in manageability.

  9. Your feedbacks are highly appreciated. Thank you, Chris.

  10. George Varghese says:

    Hi,

    Can you please add more details about the implementation of indication provider.

    Regards,

    George