OpenWBEM

From openSUSE

OpenWBEM is an enterprise-grade open-source implementation of WBEM, written in C++, suitable for commercial and non-commercial applications. It provides a foundation for development of management frameworks that overcome cross-platform barriers and empower true interoperability. Developers can use OpenWBEM as a management agent and WBEM framework to provide applications for configuration and change management, system health monitoring, and enterprise-wide management functionality.
For more on OpenWBEM

Contents

OpenWBEM-4 Information

There are significant changes in OpenWBEM-4.x over OpenWBEM-3.2.x. Most of these changes are security related.

OpenWBEM-4 Architecture Basis

The OpenWBEM-4 security features are based on the following research:

Major Changes

  • CIMOM daemon (owcimomd) no longer runs as root.
  • Providers run in a separate process from owcimomd (and from each other).
  • A "privilege monitor" runs as root and allows owcimomd and providers to accesss system resources with escalated privileges.
  • The privilege monitor only allows access to a finite, configured set of resources.
  • Providers can be protected by per-provider AppArmor profiles.

Migrating providers from OpenWBEM-3.x to OpenWBEM-4

Most providers should be able to move to OpenWBEM-4.x little effort.

BloCxx

A large portion of the OpenWBEM framework has been split out into a separate general-purpose library called BloCxx (pronounced "blocks", as in "building blocks"). The old OpenWBEM headers are still present, and include the BloCxx headers. Also, the items from the BloCxx namespace have been pulled in to the OpenWBEM namespace, so this change to OpenWBEM is mostly transparent to applications and providers using OpenWBEM.

For SLES10, there is one issue that consumers of OpenWBEM have to be aware of with regard to BloCxx. SLES10 ships blocxx-1, and several componants (such as YaST) use blocxx-1. However, OpenWBEM-4 requires blocxx-2. To minimize the impact on other components that use BloCxx, OpenWBEM-4.x in SLES10 is statically linked to blocxx. You do not need to change any code or include any additional files due to OpenWBEM's use of BloCxx. However, since OpenWBEM-4 uses a different version of BloCxx from the other components of SLES10, the BloCxx include files for the version of BloCxx used by OpenWBEM are installed in /usr/include/openwbem/blocxx/. As a result of this, you need to add the following to your compiler flags: -I/usr/include/openwbem

Exec Functions

OpenWBEM::Exec::Popen() is no longer available. You can use OpenWBEM::Exec::executeProcessAndGatherOutput() instead. For example, this code:

PopenStreams rval = Exec::safePopen( command );
String strResults = rval.out()->readAll();
if (rval.getExitStatus())
{
   // error  
}

Would become this:

String strResults;
Process::Status ps = Exec::executeProcessAndGatherOutput(command, strResults);
if (ps.exitStatus())
{
   // error
}

Provider Installation Location

OpenWBEM-3.x C++ providers were probably installed into /usr/lib/openwbem/c++providers or /opt/novell/lib/openwbem/c++providers/. OpenWBEM-4.x C++ providers cannot be installed into these directories. They can actually be installed just about anywhere else because the provider registration mechanism tells OpenWBEM where to find each provider. However, it is recommended that providers be installed to /opt/novell/lib/openwbem/oopproviders/ or /usr/lib/openwbem/oopproviders/. For 64bit providers, they should be installed in /usr/lib64/openwbem/oopproviders/ or /opt/novell/lib64/openwbem/oopproviders/.

CMPI providers do not need to move. They can remain in /usr/lib/cmpi/, or they can be anywhere else, as the provider registration tells the CIMOM where to find them. For OpenWBEM-4, CMPI providers will no longer be registered with the provider qualifier. CMPI providers are now registered the same way as C++ providers: using the Provider Registration Schema.

Provider Registration

OpenWBEM-4 Out of Process Providers are registered differently from OpenWBEM-3.x C++ providers. The get*ProviderInfo() functions are no longer used. Instead, providers are registered by creating instances of the CIM class OpenWBEM_OOPProviderRegistration in the Interop namespace. This will likely be accomplished by a MOF file included with your provider RPM, and compiled during the RPM %post scriptlet (along with your schema extensions). An example follows.

pragma namespace("Interop")
instance of OpenWBEM_OOPProviderRegistration
{
        InstanceID = "Novell:SUSE:OMC:base:OMC_LinuxMount";
        NamespaceNames = {"root/cimv2","smash"};
        ClassName = "OMC_LinuxMount";
        ProviderTypes = {1, 3}; // Instance, Association
        Process = "/usr/lib/openwbem/bin/openwbem/owoopcpp1pr";
        Args = { "--provider=/usr/lib/openwbem/oopproviders/libomc_linux_mount.so"};
        Protocol = "owcpp1";
        Timeout = "00000000000010.000000:000";
        UserContext = 2; // operation
};

64bit providers need to register with Process = "/usr/lib64/openwbem/bin/openwbem/owoopcpp1pr".

CMPI providers need to register with Process = "/usr/lib/openwbem/bin/openwbem/owoopcmpipr" or Process = "/usr/lib64/openwbem/bin/openwbem/owoopcmpi1pr".

32bit providers can run on a 64bit biarch platform, even if the CIMOM is 64bit, simply by registering with Process = "/usr/lib/openwbem/bin/openwbem/owoopcpp1pr" instead of Process = "/usr/lib64/openwbem/bin/openwbem/owoopcpp1pr".

Multi-threaded Provider Considerations

If a provider is of the type polled, indication or indication export OpenWBEM-4 considers it a persistent provider. A process for a persistent provider is started when the CIMOM initializes and is not shutdown until the CIMOM shuts down. Multi-threading really only makes sense in these types of providers. When doing mutli-threading in a provider it is important that the ProviderEnvironmentIFCRef given to the provider by the CIMOM not be used in any of the threads except the one the CIMOM called in on. The ProviderEnvironmentIFC used in any other threads must be a "clone" of one passed in by the CIMOM:

ProviderEnvironmentIFCRef envToUseInAThread = env->clone();

In the example above, "env" was passed by the CIMOM through some provider interface method on the provider like getInitialPollingInterval. The clone() method on the ProviderEnvironmentIFC basically opens up a new communication channel with the CIMOM. This new communication channel will last as long as the clone exists. No need to worry about closing this channel, that all happens behind the scenes. If the ProviderEnvironmentIFC used by the providers threads did not come from a clone operation, it will not be funcntional. You can think of a clone of a ProviderEnvironmentIFC as separate communication channel to the CIMOM that performs ProviderEnvironment operations. It is advisable that each thread within the provider (excluding the one the CIMOM calls in on) use a clone of a ProviderEnvironmentIFC that was provided by the CIMOM on a previous call.

Performance Considerations

Getting The CIMOM Handle

It is common practice for providers to make up calls into the CIMOM. This has typically be done using a method similar to the following:

CIMClass cc = env->getCIMOMHandle()->getClass(...);
...
CIMInstance ci = env->getCIMOMHandle()->getInstance(...);

While the above code will still be functional in OpenWBEM-4, it should be considered sub-optimal. In OpenWBEM-4 a CIMOMHandle has a dedicated communication channel back to the CIMOM process. In the above example, each time env->getCIMOMHandle() is called, a new communication channel is establish with the CIMOM. A more optimal approach to the above snippet of code would be the following:

CIMOMHandleIFCRef chdl = env->getCIMOMHandle();
CIMClass cc = chdl->getClass(...);
...
CIMInstance ci = chdl->getCIMOMHandle()->getInstance(...);

With this approach, the communication channel established with the call to env->getCIMOMHandle(), will be re-used in subsequent calls to the CIMOM. It is also very important to remember that the CIMOMHandleIFCRef returned from env->getCIMOMHandle() is NOT thread safe. All access to it should be synchronized or each thread should have its own CIMOMHandleIFC retrieved from a separate call to env->getCIMOMHandle().

Using OpenWBEM-4 Security Features

A provider may choose to take advantage of some of the new security features of OpenWBEM-4.

Provider UserContext

One of the properties in the Out of Process Provider (OOPP) registration schema is UserContext. The quickest way to get a provider running with reasonable security is to set this to 2 (Operation). This means that the provider will run as the authenticated user associated with the request that is being routed to the provider.

For increased security, the UserContext can be set to 5 (Operation Monitored). In this mode of operation, the provider runs as an unprivileged system user (owprovdr). However, the provider has a privilege monitor attached to it that allows it to access a finite, configured set of system resources with escalated privileges. The privilege monitor runs as the authenticated user associated with the request that is being routed to the provider. A UserContext of 5 (Operation Monitored) is preferred to a UserContext of 4 (Monitored), because with a UserContext of 4 the privilege monitor for the provider always runs as root. This would allow root access to some system resources to non-root users accessing the CIMOM.

If your provider does not require privileged access to any resources, you should set UserContext = 5 (Operation Monitored) and use a privilege file with no privilges and specify an unpriv_user other than owcimomd (e.g. owprovdr). Even though it would appear to be the most secure, UserContext = 3 (unprivileged) ends up running the provider as the same user as owcimomd, and if the provider were to be compromised, the attacker could then gain control of owcimomd and attempt to gain root access via it's monitor.

UserContext values of 2 and 5 are acceptable. If you think you require 1, 3 or 4, you may want to re-think your design.

Using the Privilege Monitor

To run a provider with UserContext = 5 (Operation Monitored), you need to do a few steps.

  • Create a privilege file under /etc/openwbem/privileges/
  • Specify the privilege file in the MonitorPrivilegesFile property of the registration instance.
  • Add a -m switch to the Args property in the provider registration instance.
  • Use the PrivilegeManager API to perform any task that requires escalated privileges.

The grammer for the privilege file syntax can be found here.

The PrivilegeManager API can be used to do things such as opening files for reading or writing, and executing processes with escalated privileges.

More detailed information about these new features in OpenWBEM 4 can be found here

Per-Provider AppArmor Profiles

To create per-provider apparmor profiles, simply place your profile in /etc/apparmor.d/openwbem/owoopcpp1pr or /etc/apparmor.d/openwbem/owoopcmpipr (depending on whether the provider is C++ or CMPI). The file name needs to be the same as your provider library, with the "lib" and ".so" removed. For example, an apparmor profile for the CMPI provider /usr/lib/cmpi/libfooprovider.so would be found in /etc/apparmor.d/openwbem/owoopcmpipr/fooprovider.

If your provider RPM contains an AppArmor profile, you need to call /usr/sbin/ow_gen_aa_profiles in %post and %postun.