MORE INFORMATION
In the following discussion, wherever a COM server is mentioned, keep in
mind that a COM client that allows callbacks (such as via the Connection
Point mechanism) is in fact a COM server, and hence the same factors that
apply to a COM server will apply to such a COM client.
Also, please see the References section for additional KB articles that
describe some of the issues in more detail.
Q1: Does COM work on Windows 95-only networks? Can a Windows 95 machine act as a COM server machine in such a case?
A: The answers to both the questions are Yes. You can run COM clients and
servers on Windows 95-only networks. If there is an NT domain in the
network, Windows 95 can provide authentication/authorization via a pass-
through security mechanism. If there are no NT domains in the network, only
non-secure calls can be made in such networks. Since the default behavior
of COM is to make secure calls, this behavior must be changed before a COM
client can successfully call a COM server on a Windows 95-only network.
Before we discuss how this is accomplished, let's briefly discuss how
security in general works in COM. Security on a remote COM activation is a
three step process.
Security on a Remote COM Activation
Step 1:
First, the authentication level set in the COAUTHINFO structure passed to
an activation API such as CoCreateInstanceEx() determines if the server-
side SCM will attempt to authenticate the client. COAUTHINFO is a field
inside the COSERVERINFO structure. If the authentication level set in the
COAUTHINFO structure is something other than RPC_C_AUTHN_LEVEL_NONE, the
SCM on the server side will attempt to authenticate the client. If this
authentication fails, the activation API is rejected. If the authentication
level set in the COAUTHINFO structure is RPC_C_AUTHN_LEVEL_NONE, then
authentication will not be attempted (this is considered an anonymous
activation attempt).
Step 2:
In either case, in the next step, the SCM performs a check to see if the
client does indeed have launch permissions on the COM server. If the client
does not have launch permissions, the activation API is rejected. If the
client has launch permissions, the COM server is launched. For anonymous
activation requests, the launch permission security descriptor must contain
a NULL DACL or an ACL that allows "Everyone" access. Note that if the
server has already been launched, then the launch permission check is not
performed.
In the case of Windows 95, a COM server must be pre-launched before a COM
client can connect to it, thus there are no launch permissions and hence
there is no check for this. However, the authentication step is still
performed and, therefore, the authentication level set in COAUTHINFO is
important. If the client does not specify an explicit COAUTHINFO structure
and leaves the pointer NULL, by default COM attempts to authenticate the
client first. If it cannot authenticate the client, it checks the launch
security descriptor to see if anonymous activation is allowed. If yes, it
will launch the server (as usual, if the server is already launched this
check is not done).
Step 3:
The third step of the activation process is to obtain a pointer to the
class factory or to the actual object. This step is governed by call
security and the access permissions set on the server, which are discussed
below. Note that for anonymous activation, call security/access permissions
are not checked, but instead if the server permits anonymous activation, a
class factory pointer or an object pointer is returned to the client at
this time.
Security on a Remote Call
Security on a remote call is a two-step process.
Step 1:
First, the authentication level set on the proxy determines security on a
COM call. The default authentication level set on a proxy is determined by
how the client and the server call the CoInitializeSecurity() API. The
default value is the higher of the values specified by the client and the
server for the dwAuthnLevel parameter of this API. For a given call, the
client can change the authentication level on the proxy via
CoSetProxyBlanket(), thus overriding the default setting. However, the
client cannot specify an authentication level on the proxy that is less
than that specified by the server in its call to CoInitializeSecurity().
For example, if the server specifies RPC_C_AUTHN_LEVEL_CONNECT in its call
to CoInitializeSecurity() and the client specifies RPC_C_AUTHN_LEVEL_PKT,
the default authentication level on all proxies in the client is
RPC_C_AUTHN_LEVEL_PKT. The client can change the authentication level on a
call to RPC_C_AUTHN_LEVEL_PKT_PRIVACY by calling CoSetProxyBlanket().
However, the client cannot change the authentication level to
RPC_C_AUTHN_LEVEL_NONE, because the minimum specified by the server is
RPC_C_AUTHN_LEVEL_CONNECT. If a process does not explicitly call the
CoInitializeSecurity() API, the COM runtime calls the API on behalf of the
process. The authentication level for this default call is obtained from
the following registry location (note that this is a machine-wide setting
and not a process-specific one).
HKEY_LOCAL_MACHINE\Software\Microsoft\Ole
LegacyAuthenticationLevel
This is a DWORD named value. A value of 1 corresponds to
RPC_C_AUTHN_LEVEL_NONE, 2 corresponds to RPC_C_AUTHN_LEVEL_CONNECT, and so
on.
Step 2:
When a call arrives, first the authentication level on the call is checked.
If the authentication level is something other than RPC_C_AUTHN_LEVEL_NONE,
the client is authenticated. Then, if there is a security descriptor for
the server's access permissions, an access check is performed by comparing
the client's identity against this security descriptor.
If the call comes in at RPC_C_AUTHN_LEVEL_NONE, then a client
authentication is not performed. In this case, it is erroneous to specify a
security descriptor for the server's access permissions. Therefore, a call
to CoInitializeSecurity specifying a non-NULL security descriptor and an
authentication level of RPC_C_AUTHN_LEVEL_NONE will return an error. Note,
however, that if the server does not call CoInitializeSecurity (instead
relies on the default machine-wide authentication level) and if this
authentication level is RPC_C_AUTHN_LEVEL_NONE, then an access check is not
performed against the (registry-based) security descriptor for the server's
class. The client will still be authenticated if the authentication level
is other than RPC_C_AUTHN_LEVEL_NONE.
If a call comes in at RPC_C_AUTHN_LEVEL_CONNECT or above, then COM performs
an access check to see if the client's account is allowed to call the
server by checking the Access Permissions list for the server. If the
client's account is not allowed access, the call is rejected. Otherwise the
call is allowed.
How to Setup DCOM on a Windows 95-only Network
COM Server:
Call CoInitializeSecurity(), passing RPC_C_AUTHN_LEVEL_NONE as the
authentication level. If the server cannot call this API for some reason
(for example, it is an in-process DLL server), then change the machine-wide
authentication level setting to RPC_C_AUTHN_LEVEL_NONE, by modifying the
registry key mentioned in Step 1 above using the Registry Editor. The
machine needs to be re-booted for this change to take effect.
WARNING: Using Registry Editor incorrectly can cause serious, system-wide
problems that may require you to reinstall Windows 95 to correct them.
Microsoft cannot guarantee that any problems resulting from the use of
Registry Editor can be solved. Use this tool at your own risk.
NOTE: When making the above change in the registry, it is important to
understand that COM call security for the entire machine is turned off. Any
client will be able to call into any COM server process running on the
machine if the client gets hold of an interface pointer to an object in the
server. Therefore, you must be careful when changing this machine-wide
setting. It is strongly recommended that a COM server process call
CoInitializeSecurity() to set its own security level rather than changing
the machine setting.
Upcoming versions of COM will have the ability to specify per-process
authentication levels, so that the above workaround is not required. This
way, you can control the call security on a process-by-process basis. This
feature is available in the DCOM95 1.1 web release (available soon),
Internet Explorer 4.0 for Windows 95, and Windows 98 (beta 2 or later).
COM Client:
First, the activation must specify an authentication level of
RPC_C_AUTHN_LEVEL_NONE. This can be done either by leaving the COAUTHINFO
pointer in COSERVERINFO as NULL (default), or by specifying
RPC_C_AUTHN_LEVEL_NONE in the COAUTHINFO struct. In the former case, COM
attempts an authenticated activation first and then falls back to a non-
authenticated activation. In the latter case, you must also specify
RPC_C_IMP_LEVEL_IMPERSONATE for the dwImpersonationLevel parameter.
Second, calls must specify an authentication level of
RPC_C_AUTHN_LEVEL_NONE. For this, the client must call
CoInitializeSecurity() passing RPC_C_AUTHN_LEVEL_NONE. If you are using
CoSetProxyBlanket(), RPC_C_AUTHN_LEVEL_NONE must be specified to this API
as well. As in the server case, if the client cannot call
CoInitializeSecurity(), then the machine-wide authentication level can be
changed in the registry (discussed above).
Third, make sure that secure reference counting is not enabled. Secure
reference counting can be enabled in DCOMCNFG and appears in the registry
at the following location:
HKEY_LOCAL_MACHINE\Software\Microsoft\Ole
LegacySecureReferences
By default, this key is not present and secure reference counting is not
enabled.
NOTE: It might appear from the above that the client does not need to call
CoInitializeSecurity(), but can use CoSetProxyBlanket() to control the
authentication level on individual proxies. However, this will not work
correctly because the Release() call always uses the default authentication
on the proxy (that is, the one set in CoInitializeSecurity), therefore the
client will not be able to shut down the server object unless it sets the
default authentication on the proxy as RPC_C_AUTHN_LEVEL_NONE. To do this,
you must call CoInitializeSecurity(), either explicitly or implicitly. If
the server object does not care about reference counting, this is not an
issue.
Q2: The DCOMCNFG.EXE program produces an error message when I run it on a
Windows 95 machine with Share Level Access control. Does this mean DCOM
does not work on such machines?
A: No, this is strictly a limitation of Dcomcnfg.exe. Oleview.exe can be
used on machines with share level access control. DCOM works correctly on
Share Level access control Windows 95 machines. The answer to Question 1
shows how to set it up without security on these machines.
Q3: When I call CoCreateInstanceEx() specifying a remote Windows 95 machine
name, the API returns RPC_S_SERVER_UNAVAILABLE. What is the cause of this
error?
A: There are several reasons for this error.
Cause 1: The DNS/WINS Name Resolution Is Not Setup or Working Correctly
First make sure that you can ping the remote machine by name. If you cannot
ping it by name, then most likely the DNS/WINS name resolution is not setup
or not working correctly on your network. In this case, you cannot specify
the machine name to DCOM either. Try pinging it by using its IP address, if
this works, you can specify the IP address instead of the machine name to
DCOM. If pinging by IP address also does not work, then TCP/IP is not
installed properly on your network. You must correct this problem before
you can use DCOM on the network. Note that the ability to enumerate NETBIOS
shares (via the "net view \\NETBIOSNAME" command) does not mean that TCP/IP
is installed correctly, NETBIOS can be running over the NETBEUI transport.
Verify that the EnableDCOM and EnableRemoteConnect registry keys under
HKLM\Software\Microsoft\OLE are set to "Y" on the server machine.
EnableDCOM must be set to "Y" to enable any distributed COM functionality.
EnableRemoteConnect must be set to "Y" to let the machine act as a server.
You need to reboot the server machine for this change to take effect.
Cause 2: Rpcss.exe Is Not Started on the Remote Machine Correctly
The other major cause for this error is that Rpcss.exe is not started on
the remote machine correctly due to a known bug in DCOM95 1.0. Rpcss.exe is
the resolver/end-point mapper process that needs to be running before any
remote DCOM calls can be made. Under Windows NT, RPCSS is a Windows NT
service, which is started when the machine is started. Under Windows 95,
RPCSS process is started on a "lazy" or as-needed basis. Note that for
local-only communications, RPCSS is not needed and is not started. But when
the EnableRemoteConnect registry entry is set to "Y", RPCSS is started
automatically when a COM server calls CoRegisterClassObject() to register
its classes.
This is true regardless of whether the client that started the server is on
the same machine or on a remote machine. This is also true if the server is
started manually (as is the usual case under Windows 95) except under the
following condition:
- The call to CoRegisterClassObject() is made from a Single Threaded
Apartment (STA) server.
In this case due to a bug in DCOM95, RPCSS.EXE is not started automatically
and hence a remote client will fail with an RPC_S_SERVER_UNAVAILABLE error.
The same problem happens if a local client launched the server. The local
client will work fine, but when a remote client tries to connect to the
server, the remote client will get the error.
You can work around this problem by pre-launching RPCSS.EXE before any
class objects are registered. A convenient place to do this is in the
registry at HKLM\Software\Microsoft\Windows\CurrentVersion\Run, which
launches when the shell loads, or \RunServices, which launches immediately
upon booting the machine (that is, before login). Add a named value (any
name) and a value of "Rpcss.exe". This problem is fixed in the DCOM95 1.1
Web release (available soon), Internet Explorer 4.0 for Windows 95, and
Windows 98 (beta 2 or later).
Finally make sure that the COM server process is launched and has
successfully registered its classes by calling CoRegisterClassObject().
Q4: When I call CoCreateInstanceEx() specifying a remote Windows 95 machine
name, the API returns CO_E_SERVER_EXEC_FAILURE. What is the cause of this
error?
A: To resolve this:
- Make sure that the following registry entry on the server is set to "Y":
HKEY_LOCAL_MACHINE\Software\Microsoft\Ole
EnableRemoteConnect='Y'
You need to reboot the server machine for this change to take effect.
- Make sure that the COM server is already launched on the machine and has
successfully registered its classes by calling CoRegisterClassObject().
DCOM95 does not perform remote activation. Therefore, the server needs
to be running before a remote client can connect to it.
Q5: When I call CoCreateInstanceEx() specifying a remote Windows 95 machine
name, the API returns RPC_E_NO_GOOD_SECURITY_PACKAGES. What is the cause of
this error?
A: This error occurs when Rpcss.exe is started after a client process is
started and the client process then makes secure remote COM calls, such as
CoCreateInstanceEx(). For example, assume you have a COM client process "A"
that starts up and perhaps performs some local COM activities (Rpcss.exe is
not yet started). Now another client process "B" starts and performs a
remote COM call, which causes Rpcss.exe to start. Now if client "A"
attempts to make a secure remote COM call, it will get this error. If
client "A" is attempting a non-secure remote COM call, it will get an
RPC_E_INVALID_PARAMETER error.
This error occurs because security information is not being synchronized
properly if, when it is time to launch RPCSS in a client, COM finds that it
has already been launched.
As in the answer to Question 3, you can work around this problem by pre-
launching Rpcss.exe before launching the client process. A convenient place
to do this is in the registry at
HKLM\Software\Microsoft\Windows\CurrentVersion\Run, which launches when the
shell loads, or \RunServices, which launches immediately upon booting the
machine (that is, before login). Add a named value (any name) and a value
of "RPCSS.EXE".
This problem is fixed in the DCOM95 1.1 web release (available soon),
Internet Explorer 4.0 for Windows 95, and Windows 98 (beta 2 or later).
Q6: When I make a call to the remote COM server running on a Windows 95
machine, I get the error RPC_S_UNKNOWN_AUTHN_SERVICE. What is the cause of
this error?
A: This error means that you are attempting to make a secure call (that is,
authentication level on the proxy is RPC_C_AUTHN_LEVEL_CONNECT or above),
but the Windows 95 machine is set to Share Level Access control and cannot
authenticate the call. Please see the answer to Question 1 for information
on how to make non-secure DCOM calls. Note that if the COAUTHINFO structure
specifies RPC_C_AUTHN_LEVEL_CONNECT or above, an activation API such as
CoCreateInstanceEx() will give the same error.
Q7: When I make a call to the remote COM server running on a Windows 95
machine, I get the error RPC_S_SERVER_TOO_BUSY. What is the cause of this
error?
A: This error means that you are attempting to make a secure call at an
authentication level above RPC_C_AUTHN_LEVEL_CONNECT. Windows 95 can accept
incoming COM calls only at an authentication level of
RPC_C_AUTHN_LEVEL_CONNECT or below. There are no restrictions on the
authentication level of outgoing calls. Please see the answer to Question 1
for information on how a client's proxy obtains its default authentication
level and how a client can change it (via CoSetProxyBlanket). Due to this
restriction, a Windows 95 COM server (or a COM client that accepts
callbacks) must call CoInitailizeSecurity() specifying at the most
RPC_C_AUTHN_LEVEL_CONNECT authentication level. It cannot specify anything
above this level. If it does, remote incoming calls will fail with the
above error.
Q8: I have a COM client on a Windows 95 machine that launches a server on a
Windows NT machine. When the server tries to call the client back, the
callback fails with E_ACCESSDENIED. What is the cause of this error?
A: Make sure that the identity of your server is not set to "Launching
User". (You can use Dcomcnfg.exe to examine the identity of your server).
"Launching User" or "Activate as Activator" processes lack credentials to
make secure calls out of their own machine. Note that the same setup will
work if the client is on a Windows NT machine and the authentication level
on the callback is RPC_C_AUTHN_LEVEL_CONNECT. Windows NT uses the NULL
session share mechanism to make this work. This is not possible with
Windows 95. Note that even under Windows NT, if the authentication level on
the callback is above RPC_C_AUTHN_LEVEL_CONNECT, the callback will fail
with the RPC_S_SEC_PKG_ERROR error.
Use Dcomcnfg.exe to change the Identity of the server to either the
"Interactive user" or "This User". This will allow the server to make
secure callbacks. The other option is to make non-secure callbacks by
setting RPC_C_AUTHN_LEVEL_NONE on the callback proxy (see Question 1).
Q9: How do I make Netclip work between two Windows 95 machines on a Windows
95-only network?
A: Netclip is a sample DCOM application that you can use to view a remote
machine's clipboard. You can get Netclip from
http://www.interdesigner.com/downloads.htm
The following instructions explain how to make Netclip communicate between
Windows 95 machines on a Windows 95-only network. Since there are no
Windows NT machines or Windows NT domains on this network, there is no User
Level Security. Therefore, these instructions turn off DCOM call level
security for the whole machine. Please see Question 1 for a discussion of
the security implications of this approach.
- Install DCOM95 on both of the machines.
- Ping the server machine from the client machine using its NETBIOS name,
DNS name, or IP address. If the ping is successful with any of these
names, the same name can be passed as the server machine name to COM. If
pinging by IP address does not work, then you cannot use DCOM. You need
to install and configure TCP/IP first.
- In the registry, the following named value must be set to "Y" on both
machines:
HKEY_LOCAL_MACHINE\Software\Microsoft\Ole
EnableDCOM
The following named value must be set to "Y" on the Netclip server machine:
HKEY_LOCAL_MACHINE\Software\Microsoft\Ole
EnableRemoteConnect
If you are changing these values, keep in mind that you need to reboot
the machine so that this change takes effect.
- The following named value (REG_DWORD) must be set to 1 (None) on both
machines:
HKEY_LOCAL_MACHINE\Software\Microsoft\Ole
LegacyAuthenticationLevel
If this named value does not exist, you can create it.
If you are creating/changing this value, keep in mind that you need to
reboot the machine for this change to take effect.
NOTE: For machines with User Level Security, you can use Dcomcnfg.exe to
make these changes. On a machine with Share Level security, you need to
manually (via REGEDIT) or programatically (using the win32 registry
APIs) make these changes because Dcomcnfg.exe will not run.
- Restart both computers.
- Start Rpcss.exe from the command line on the Windows 95 machine where
the Netclip server is to run. This is a workaround for a known bug in
DCOM95 1.0. (see Question 2 for other ways of pre-starting Rpcss.exe)
This step is not required if you have DCOM95 1.1, Internet Explorer 4.0,
or Windows 98 (beta 2 or later) is installed.
- Start the Netclip server as "netclip /server"
- On the Windows 95 client machine, start Netclip and specify the machine
name (or IP address-see step b) of the server machine.
Q10: How do I make Netclip work securely between two Windows 95 machines on
a Windows 95/Windows NT network?
A: Since there is a Windows NT domain in the network, you can use the
pass-through security provided by the Windows NT domain. To do this, make
sure that both of the Windows 95 machines are set to use User Level Access
Control with the names of users and groups obtained from the Windows NT
domain. You can do this in the Network applet in control panel. Use
Dcomcnfg.exe to set the machine-wide authentication level to Connect on
both machines. On the Netclip server machine, use Dcomcnfg.exe to give
access permissions to the Windows NT domain account that is currently
logged onto the Netclip client machine. This can be done either for the
default access permissions list of the server machine or custom access
permissions of the Netclip server itself. On the Netclip client machine,
use Dcomcnfg.exe to give access permissions to the Windows NT domain
account that is currently logged onto the Netclip server machine. You need
to do this for the default access permissions list of the client machine
because the Netclip server will make callbacks into the client and the
Netclip client must give access permissions to the server's account. Follow
the steps outlined in Question 9 (except Step 4 to turn off call security)
to start the Netclip client/server session.