Distributed COM

As we saw in our examination of the COM programming model, servers can be run on remote machines. From the programming model perspective, that's all there is to it. COM's location transparency extends cross-apartment, cross-process, and cross-machine. There are some practical matters to consider when you are communicating across machine boundaries. And we haven't yet looked at how location transparency actually works. So let's spend a little time discussing Distributed COM (DCOM).

NOTE

Technically, "DCOM" refers specifically to the wire protocol for making COM calls between two machines. However, you will often see the term used to refer to the whole concept of COM communication across machines. The discussion here focuses on what you need to know to understand at a high level how distributed applications based on COM work. It does not talk about the communication mechanisms or architecture of DCOM in detail. If you want to learn more about DCOM, refer to the bibliography.

Cross-machine COM calls introduce some issues that you normally don't need to consider in the single-machine scenario. First, you might not want everyone in the world to be able to use the components installed on a particular machine. Thus, security becomes an issue. Second, you need some way to tell the people who are allowed to use the components (or more accurately, their computers) where the components are located. You can't rely on the components to register themselves at install time because the components will not be installed on the client machines.

COM Security

The COM security model defines a standard way for COM objects to interact with security services provided by the underlying operating system. The model is independent of the specific security services that might be available.

NOTE

On Windows NT 4.0, the only security service available is NT LAN Manager (NTLM) security. Windows NT 5.0 will provide additional security services, such as Kerberos and Secure Socket Layer (SSL).

COM security addresses the two issues of who is allowed to launch components and how to secure calls through interface pointers by providing activation security and call security.

Activation security

Activation security is applied by the server machine's SCM whenever it receives a request to activate an object. "Activating an object" means either creating a new object or getting an interface pointer to a "published" object such as a registered class object or an object in the running object table. We won't be looking at published objects in this book; instead, we'll focus on creating new objects.

The SCM uses information in the registry (or obtained dynamically from published objects) to determine whether the activation request should be allowed. First the SCM checks a machinewide setting to determine whether any remote activation requests are permitted. If the machinewide check succeeds, the SCM looks for component-specific security settings. We'll talk about these settings in more detail in the section "Registration Revisited" later in this chapter. In essence, however, the registry can contain an access control list (ACL) that indicates which users can activate specific components. The SCM checks the client's identity against the ACL to decide whether the activation request can proceed. If there is no component-specific setting, the SCM looks at a default ACL.

If the access check succeeds, the SCM will launch the component, if necessary, and activate the object. The SCM uses information in the registry to determine what security identity the object should run as. This identity becomes the client identity for any activation requests the object itself might make.

Call security

Once an interface pointer to an object is obtained, a client can make calls to the object. COM also applies security to each method call through an interface pointer. Per-call security has two separate aspects. The first is authentication and authorization of the caller, which is essentially the same as the activation security check just described, except that a different ACL is used and the component and client have some control over how often the check is performed. The other aspect relates to data integrity and privacy—that is, ensuring that the network packets containing the COM method call have not been tampered with and preventing data in the packets from being read during transmission.

As you might imagine, performing security checks on every method call can involve considerable overhead. It might also be overkill for some situations. Thus, COM lets applications configure when and how per-call security will be applied. Both the client and server applications can establish processwide defaults for per-call security by calling the CoInitializeSecurity function. The settings include an ACL for authorization checks and an authentication level that determines how often authentication is performed as well as whether data integrity and/or data privacy should be enforced. If an application does not explicitly call CoInitializeSecurity, the COM run time will call it on the application's behalf before any objects are activated, using information from the registry. As with activation security settings, COM will first look for component-specific settings; if none are found, it uses the default settings.

NOTE

In addition to setting per-call security at a process level, applications and components can tune security settings on individual interfaces and method calls using the standard IClientSecurity and IServerSecurity interfaces. This is a more advanced technique that we will not cover in this book. For many applications, processwide settings are sufficient. As we'll see in Chapter 4, MTS offers an abstraction on top of the COM security model that makes securing access to components even easier.

Registration Revisited

COM security relies on a number of registry entries. On Windows and Windows NT, these settings are usually configured using the DCOM configuration tool, DCOMCNFG.EXE, shown in Figure 2-5. DCOMCNFG lets you set machinewide and per-application settings without worrying about the actual registry keys involved.

Several key DCOM settings can be configured at the machine level. These settings are stored as values under the registry key HKEY_LOCAL_MACHINE\Software\Microsoft\Ole. Table 2-2 lists the major values, their purpose, and how to set them using DCOMCNFG. The values specified using DCOMCNFG will be used by default if no application-specific values are provided.

click to view at full size.

Figure 2-5. The DCOM Configuration tool used to configure DCOM security.

Table 2-2. Machinewide DCOMCNFG registry entries.

Registry Value Purpose Configuration
EnableDCOM Global activation policy for machine On the Default Properties tab, check the Enable Distributed COM On This Computer check box.
LegacyAuthenticationLevel Default authentication level applied to network packets On the Default Properties tab, choose a setting from the Default Authentication Level combo box.
DefaultLaunchPermission Default ACL for activation security On the Default Security tab, click the Edit Default button in the Default Launch Permissions group to edit which users have launch permission.
DefaultAccessPermission Default ACL for per-call security On the Default Security tab, click the Edit Default button in the Default Access Permissions group to edit which users have access permission.

DCOMCNFG also lets you specify settings for specific applications. In COM today, an application is nothing more than an identified process that hosts one or more components. Applications are identified by (you guessed it) GUIDs, which are called AppIDs.

It should be fairly clear how CLSIDs map to AppIDs for components implemented as executables or services—there is one AppID for each executable or service. Components implemented this way should register an AppID and add AppID values to each CLSID they register, as shown in Figure 2-6.

click to view at full size.

Figure 2-6. Registering an AppID for an executable.

Less clear is how CLSIDs map to AppIDs for components implemented as DLLs. If an in-process component is to run remotely, a surrogate process must be defined for the component. First an AppID is defined for the process, as shown in Figure 2-7. For each component that should run in this process, an AppID value should be added to the CLSID key for each class registered by the component. The executable to run when a component is launched is listed under the DllSurrogate value on the AppID key. If the DllSurrogate value is NULL or an empty string, the default system-supplied surrogate is used.

click to view at full size.

Figure 2-7. Registering an AppID for a DLL server.

With the AppID key in place, DCOMCNFG can be used to establish security settings on a per-application basis. These settings will be used if the application does not call CoInitializeSecurity explicitly. The per-application settings are stored as named values under the HKEY_CLASSES_ROOT\APPID\{appid-guid} registry key for the application on the server machine. Table 2-3 lists the security values, their purpose, and how to set them using DCOMCNFG's Application Properties window. To open the Application Properties window, select an application to configure in the Applications list box on the Applications tab, and then click the Properties button.

Table 2-3. Per-application DCOM security configuration registry entries.

Registry Value Purpose Configuration
RunAs Identity used to run the server process On the Identity tab, select the user account to use to run the application.
LaunchPermission ACL for activation security On the Security tab, check Use Default Launch Permissions or check Use Custom Launch Permissions and click the Edit button to select specific user accounts to give launch permission to.
AccessPermission ACL for per-call security On the Security tab, check Use Default Access Permissions or check Use Custom Access Permissions and click the Edit button to select user accounts that will have access permission.
AuthenticationLevel Authentication level applied to network packets (Windows NT 4 Service Pack 4 or later) On the General tab, select a value from the Authentication Level dropdown listbox to set the perapplication Authentication Level.

NOTE

It's important to register an AppID for DLL servers that will be used remotely because DCOMCNFG cannot be used to modify settings of servers unless they have an AppID.

In addition to security settings, the registry also contains information about where the component is located. On the server machine, this information is usually written to the registry by the component itself, when it is installed. All that's needed on the server machine is the path to the server, stored under the InprocServer32 or LocalServer32 key for each CLSID. (Services need some additional entries.)

It is also necessary to put information in the registry of remote client machines for those machines to be able to request remote objects, unless client applications are written to specify the server machine name when CoCreateInstanceEx is called. In particular, the client machine needs an AppID with a RemoteServerName value. The client may also need registry entries for proxy/stub DLLs used to marshal interfaces exposed by the objects. The component can't write the registry information because it isn't installed on the client machine.

There are two common ways to create the client-side registry entries on Windows machines. If no proxy/stub DLLs are required by the component, a .REG file with the registry settings can be distributed to client machines and merged into the local registry. Otherwise, an install program can be distributed that writes the appropriate registry entries and installs any proxy/stub DLLs required for the component to work correctly. In some cases, the install program or .REG file will create the AppID key, but it won't specify where the component is located. If this is the case, DCOMCNFG can be used on the client to set the RemoteServerName value of the AppID.

Remote Activation and Marshaling

With the security and server location information in place, objects can be created remotely. Let's look at how this process works.

As we've seen, creating objects is simple: first you get an IClassFactory pointer to a class object, and then you call IClassFactory CreateInstance to get an interface pointer to the object you've created. The SCM is responsible for locating the class object.

This is still the case for remote objects, but now two SCMs are in play: the client machine SCM needs to detect that a remote object has been requested and contact the SCM on the server machine. The server machine SCM then does its normal work to locate the class object and returns the interface pointer to the client machine SCM (assuming that all security checks pass). This process is illustrated in Figure 2-8.

The client machine SCM detects that a remote object has been requested in one of two ways. First, an application can specify a remote server machine name in the call to create an object. Second, when the SCM looks in the registry for information about where a server is located, it might be pointed to a remote machine (typically, by using the RemoteServerName value on the AppID). Either way, the client SCM ends up with a machine name. It communicates with the SCM on that machine to retrieve the interface pointer. Once the interface pointer to the object is passed back to the client application, the application makes regular method calls through the interface pointer. As far as the application is concerned, it is calling an in-process object—this is the beauty of location transparency.

click to view at full size.

Figure 2-8. Activation of a remote COM object.

Behind the scenes, of course, there's a lot going on to create the illusion of an in-process call, as shown in Figure 2-9. Obviously, the actual interface pointer from the remote machine can't be handed to the client application—the memory address in that pointer has no meaning on the client machine. Instead, the client application is handed an interface pointer to a proxy object. This object is really an in-process object. The job of a proxy object is to do whatever is necessary to communicate with a corresponding stub object located in the component server's process.

When the client application makes a method call, it is really calling a method in the proxy. The proxy takes the parameters passed to the method and packages them in a standard format. This process is called marshaling. The proxy sends a request via the appropriate communication mechanism to the server process. The server process hands the request to the stub, which unpackages the parameters and calls the method on the real object. This process is called unmarshaling. After the method completes, any return values are passed back using the same mechanism in reverse.

click to view at full size.

Figure 2-9. Location transparency using proxies and stubs.

Recall that one of the goals for COM was to hide all the complexity of cross-machine and cross-process communication from the developer. Proxy and stub objects do exactly that. As we've seen, marshaling occurs not just cross-machine, but also cross-process and cross-apartment. Typically, implementations of proxies and stubs are generated automatically from IDL interface definitions using the MIDL compiler. These DLLs call system functions that encapsulate all the details of marshaling and unmarshaling calls, as well as the details of the actual call request. If a cross-machine call is requested, COM uses a remote procedure call (RPC) to make the call. If a cross-process call is requested, a lighter-weight interprocess communication mechanism called Lightweight (LRPC) is used. If a cross-apartment call is requested, COM switches apartment contexts and synchronizes access appropriately—all without any work on the part of the developer.

Normally, the only thing a developer needs to worry about is making sure that the proxy/stub DLLs are installed and registered on the appropriate machines. For a given interface, the proxy/stub DLL must be registered on all machines that use or implement that interface. The proxy/stub DLLs generated by MIDL can be built to be self-registering, so all you need to do is run REGSVR32 on the DLL and the correct registry entries will be defined, as shown in Figure 2-10.

click to view at full size.

Figure 2-10. Proxy/stub DLL registration.



Designing Component-Based Applications
Designing Component-Based Applications
ISBN: 0735605238
EAN: 2147483647
Year: 1997
Pages: 98
Authors: Mary Kirtland
BUY ON AMAZON

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net