The security mechanism of windwos stipulates that Windows will verify the permission of this call when receiving Remote COM + calls. If the permission is insufficient, the classic "Access Denied" error occurs.
The known access methods to solve this problem are:
1. Anonymous Access: Enable guest on the Application Server (AP), and set guest to have permissions to activate and access COM +. This path is feasible, but security cannot be guaranteed.
2. the logon user and password on the client computer are the same as those on the AP, and the user has the corresponding permissions to access COM + on the AP. This method is better than the first one, but which unit of IT system will look like this. Each machine must have its own account password. This method is not good either. Note: This method is also feasible when client software is not required to be released to the machine of novogene. For example, WebServer is used to access COM +.
3. In the network environment of domain management, it can also be implemented, but there is a problem if your customers are unwilling to transform into a domain environment. Therefore, this method also has limitations.
Finally, I thought that if the user name and password used for AP authentication permission can be explicitly specified during Remote Access to COM +, can this problem be solved? In fact, this method is feasible. However, there are no ready-made functions in Delphi7 to achieve this goal.
Comobj. PAS has a function: createremotecomobject (const machinename: widestring;
Const classid: tguid): iunknown; this is used to create a Remote COM + interface. The main function I want to transform is this function.
Function cocreateinstanceex (const CLSID: tclsid;
Unkouter: iunknown; dwclsctx: longint; serverinfo: pcoserverinfo;
Dwcount: longint; rgmqresults: pmultiqiarray): hresult; stdcall; this function can be used to create a Remote COM +
Serverinfo is used to store remote server information, including the account and password for accessing and activating the COM + service.
Let's analyze pcoserverinfo;
Pcoserverinfo = ^ tcoserverinfo;
_ Coserverinfo = record
Dwreserved1: longint;
Pwszname: lpwstr;
Pauthinfo: pointer;
Dwreserved2: longint;
End;
Punshort = ^ word;
Pcoauthidentity = ^ _ coauthidentity;
_ Coauthidentity = record
User: punshort;
Userlength: ulong;
Domain: punshort;
Domainlength: ulong;
Password: punshort;
Passwordlength: ulong;
Flags: ulong;
End;
_ Coauthinfo = record
Dwauthnsvc: DWORD;
Dwauthzsvc: DWORD;
Pwszserverprincname: widestring;
Dwauthnlevel: DWORD;
Dwimpersonationlevel: DWORD;
Pauthidentitydata: pcoauthidentity;
Dwcapabilities: DWORD;
End;
Tsocinfo = Class (tobject)
Public
Fcid: _ coauthidentity;
Fcai: _ coauthinfo;
Serverinfo: tcoserverinfo;
End;
When we call cocreateinstanceex in createremotecomobject, we first assign the following value to serverinfo:
Function createremotecomobjectwh (const machinename: widestring;
Const classid: tguid): iunknown;
Const
Localflags = clsctx_local_server or clsctx_remote_server or clsctx_inproc_server;
Remoteflags = clsctx_remote_server;
VaR
Mqi: tmultiqi;
Serverinfo: tcoserverinfo;
Iid_iunknown: tguid;
Flags, size: DWORD;
Localmachine: array [0 .. max_computername_length] of char;
/// Add by wanghui 2007-07-24
Fcai: _ coauthinfo;
Fcid: _ coauthidentity;
Wuser, wdomain, wpsw: widestring;
IIU: idispatch;
FR: hresult;
Begin
If (getobjectcontext = nil) then
Begin
If @ cocreateinstanceex = nil then
Raise exception. createres (@ sdcomnotinstalled );
Wuser: = getappuserid (); // User Name
Wdomain: = getappserver (); // remote computer name
Wpsw: = getapppassword (); // Password
Fillmemory (@ fcai, sizeof (fcai), 0 );
Fillmemory (@ fcid, sizeof (fcid), 0 );
With fcid do begin
User: = punshort (@ wuser [1]);
Userlength: = length (wuser );
Domain: = punshort (@ wdomain [1]);
Domainlength: = length (wdomain );
Password: = punshort (@ wpsw [1]);
Passwordlength: = length (wpsw );
Flags: = 2;
End;
With fcai do begin
Dwauthnsvc: = 10; // The Default Authentication Service rpc_c_authn_winnt of winnt
Dwauthzsvc: = $ ffffff; // 0; // rpc_c_authz_none
// Pwszserverprincname: = pwidechar (wdomain );
Dwauthnlevel: = 3; // 0;
Dwimpersonationlevel: = 3; // The value must be set to analog.
Pauthidentitydata: [email protected];
Dwcapabilities: = $0; // $0800;
End;
Fillmemory (@ serverinfo, sizeof (serverinfo), 0 );
Serverinfo. pwszname: = pwidechar (wdomain );
Serverinfo. dwreserved1: = 0;
Serverinfo. pauthinfo: [email protected];
Iid_iunknown: = iunknown;
Mqi. IID: = @ iid_iunknown;
Mqi. ITF: = nil;
Mqi. HR: = 0;
If length (machinename)> 0 then
Begin
Size: = sizeof (localmachine); // Win95 is hypersensitive to size
If getcomputername (localmachine, size) and (ansicomparetext (localmachine, machinename) = 0) then
Flags: = localflags
Else
Flags: = remoteflags;
End else flags: = localflags;
Olecheck (cocreateinstanceex (classid, nil, clsctx_remote_server, @ (serverinfo), 1, @ mqi ));
Olecheck (mqi. hr );
Result: = mqi. ITF;
End else
Begin
Getobjectcontext. createinstance (classid, iunknown, result );
End;
End;
The code above ensures that the Remote COM + interface is obtained. The interface type is iunkown.
However, to access the method, you also need to use the following function to set the access permission for remote com local reference.
With fcai do
Cosetproxyblanket (IU, dwauthnsvc, dwauthzsvc, pwidechar (pauthidentitydata ^. domain ),
Dwauthnlevel, dwimpersonationlevel, pauthidentitydata, dwcapabilities );
Encapsulate this function to obtain a new function.
Function setproxyblanket (IU: iunknown): Boolean;
VaR
Fcai: _ coauthinfo;
Fcid: _ coauthidentity;
Wuser, wdomain, wpsw: widestring;
IIU: idispatch;
Si: tsocinfo;
Begin
Wuser: = getappuserid (); // User Name
Wdomain: = getappserver (); // remote computer name
Wpsw: = getapppassword (); // Password
If wdomain = '2014. 0.0.1 'Then exit;
Fillmemory (@ fcai, sizeof (fcai), 0 );
Fillmemory (@ fcid, sizeof (fcid), 0 );
// Fillmemory (@ fsvinfo, sizeof (fsvinfo), 0 );
With fcid do begin
User: = punshort (@ wuser [1]);
Userlength: = length (wuser );
Domain: = punshort (@ wdomain [1]);
Domainlength: = length (wdomain );
Password: = punshort (@ wpsw [1]);
Passwordlength: = length (wpsw );
Flags: = 2; // sec_winnt_auth_identity_unicode
End;
// The above filled _ coauthidentity Structure
With fcai do begin
Dwauthnsvc: = 10; // The Default Authentication Service rpc_c_authn_winnt of winnt
Dwauthzsvc: = $ ffffff; // 0; // rpc_c_authz_none
// Pwszserverprincname: = pwidechar (wdomain );
Dwauthnlevel: = 3; // 0;
Dwimpersonationlevel: = 3; // The value must be set to analog.
Pauthidentitydata: [email protected];
Dwcapabilities: = $0; // $0800;
End;
With fcai do
Cosetproxyblanket (IU, dwauthnsvc, dwauthzsvc, pwidechar (pauthidentitydata ^. domain ),
Dwauthnlevel, dwimpersonationlevel, pauthidentitydata, dwcapabilities );
End;
Finally, we transform the createremote function in * _ TLB. Pas automatically generated by Delphi as follows:
Class function comymenu. createremote (const machinename: string): imymenu;
VaR IU: iunknown;
Begin
IU: = createremotecomobjectwh (machinename, class_mymenu );
Setproxyblanket (IU );
Result: = iu as imymenu;
Setproxyblanket (iunknown (result ));
End;
For more information, see msdn and Windows security programming.
Software environment:
Client WINXP SP2
AP: win2003 SP1
========================================================== ========================================================== ==================================
========================================================== ========================================================== ==================================
Unit usecmconn;
Interface
Uses
Mconnect, classes, ActiveX, windows, sysutils, comconst, comobj;
Const
Rpc_c_authn_none = 0;
Rpc_c_authn_dce_private = 1;
Rpc_c_authn_dce_public = 2;
Rpc_c_authn_dec_public = 4;
Rpc_c_authn_winnt = 10;
Rpc_c_authn_dpa = 16;
Rpc_c_authn_msn = 17;
Rpc_c_authn_gss_kerberos = 18;
Rpc_c_authn_mq = 100;
Rpc_c_authn_default = $ ffffffff;
Rpc_c_authn_level_default = 0;
Rpc_c_authn_level_none = 1;
Rpc_c_authn_level_connect = 2;
Rpc_c_authn_level_call = 3;
Rpc_c_authn_level_pkt = 4;
Rpc_c_authn_level_pkt_integrity = 5;
Rpc_c_authn_level_pkt_privacy = 6;
Rpc_c_imp_level_anonymous = 1;
Rpc_c_imp_level_identify = 2;
Rpc_c_imp_level_impersonate = 3;
Rpc_c_imp_level_delegate = 4;
Sec_winnt_auth_identity_ansi = $1;
Sec_winnt_auth_identity_unicode = $2;
Eoac_none = 0;
Type
Pcoauthidentity = ^ tcoauthidentity;
_ Coauthidentity = record
User: lpwstr;
Userlength: DWORD;
Domain: lpwstr;
Domainlength: DWORD;
Password: lpwstr;
Passwordlength: DWORD;
Flags: DWORD;
End;
Tcoauthidentity = _ coauthidentity;
Pcoauthinfo = ^ tcoauthinfo;
_ Coauthinfo = record
Dwauthnsvc: DWORD;
Dwauthzsvc: DWORD;
Pwszserverprincname: lpwstr;
Dwauthnlevel: DWORD;
Dwimpersonationlevel: DWORD;
Pauthidentitydata: pcoauthidentity;
Dwcapabilities: DWORD;
End;
Tcoauthinfo = _ coauthinfo;
Tsecdcomconnection = Class (tdcomconnection)
Private
Fusername: string;
Fpassword: string;
Protected
Procedure doconnect; override;
Public
Constructor create (aowner: tcomponent); override;
Published
Property computername;
Property objectbroker;
Property Username: String read fusername write fusername;
Property password: String read fpassword write fpassword;
End;
Implementation
Procedure setproxyblanket (ITF: iunknown; const authinfo: tcoauthinfo );
VaR
Qr: hresult;
Begin
With authinfo do
Qr: = cosetproxyblanket (ITF, dwauthnsvc, dwauthzsvc, pwidechar (pauthidentitydata ^. domain ),
Dwauthnlevel, dwimpersonationlevel, pauthidentitydata, dwcapabilities );
Olecheck (QR );
End;
Function createremoteseccomobject (const machinename, username, password: widestring;
Const classid: tguid): idispatch;
Const
Localflags = clsctx_local_server or clsctx_remote_server or clsctx_inproc_server;
Remoteflags = clsctx_remote_server;
VaR
Mqi: tmultiqi;
Serverinfo: tcoserverinfo;
Authinfo: tcoauthinfo;
Authident: tcoauthidentity;
Iid_iunknown: tguid;
Flags, size: DWORD;
Localmachine: array [0 .. max_computername_length] of char;
IIU: idispatch;
Qr: hresult;
Begin
If @ cocreateinstanceex = nil then
Raise exception. createres (@ sdcomnotinstalled );
Fillchar (serverinfo, sizeof (serverinfo), 0 );
Serverinfo. pwszname: = pwidechar (machinename );
Serverinfo. pauthinfo: = @ authinfo;
Serverinfo. dwreserved1: = 0;
Serverinfo. dwreserved2: = 0;
Fillchar (authinfo, sizeof (authinfo), 0 );
Authinfo. dwauthnsvc: = rpc_c_authn_winnt;
Authinfo. dwauthzsvc: = rpc_c_authn_none;
Authinfo. pwszserverprincname: = nil;
Authinfo. dwauthnlevel: = rpc_c_authn_level_default;
Authinfo. dwimpersonationlevel: = rpc_c_imp_level_impersonate;
Authinfo. pauthidentitydata: = @ authident;
Authinfo. dwcapabilities: = eoac_none;
Fillchar (authident, sizeof (authident), 0 );
Authident. User: = pwidechar (username );
Authident. userlength: = length (username );
Authident. Domain: = pwidechar (machinename );
Authident. domainlength: = length (machinename );
Authident. Password: = pwidechar (password );
Authident. passwordlength: = length (password );
Authident. Flags: = sec_winnt_auth_identity_unicode;
Iid_iunknown: = iunknown;
Mqi. IID: = @ iid_iunknown;
Mqi. ITF: = nil;
Mqi. HR: = 0;
{If a machinename is specified check to see if it the local machine.
If it isn't, do not allow localservers to be used .}
If length (machinename)> 0 then
Begin
Size: = sizeof (localmachine); // Win95 is hypersensitive to size
If getcomputername (localmachine, size) and
(Ansicomparetext (localmachine, machinename) = 0) then
Flags: = localflags else
Flags: = remoteflags;
End else
Flags: = localflags;
Olecheck (cocreateinstanceex (classid, nil, flags, @ serverinfo, 1, @ mqi ));
Olecheck (mqi. hr );
Setproxyblanket (mqi. ITF, authinfo );
Qr: = mqi. ITF. QueryInterface (idispatch, IIU );
Olecheck (QR );
Setproxyblanket (iunknown (IIU), authinfo );
Result: = IIU;
End;
{Tsecdcomconnection}
Constructor tsecdcomconnection. Create (aowner: tcomponent );
Begin
Inherited create (aowner );
End;
Procedure tsecdcomconnection. doconnect;
Begin
If (objectbroker <> nil) then
Begin
Repeat
If computername = ''then
Computername: = objectbroker. getcomputerforguid (getserverclsid );
Try
Setappserver (createremotecomobject (computername, getserverclsid) as idispatch );
Objectbroker. setconnectstatus (computername, true );
Except
Objectbroker. setconnectstatus (computername, false );
Computername: = '';
End;
Until connected;
End else begin
If (computername <> '') then begin
If username <> ''then begin
Setappserver (createremoteseccomobject (computername, username, password, getserverclsid ));
End else begin
Setappserver (createremotecomobject (computername, getserverclsid) as idispatch );
End;
End else
Inherited doconnect;
End;
End;
End.
Non-Anonymous Access to Remote COM +