windwos的安全机制规定:windows接收远程的com+调用的时候,会验证这个调用的权限。如果权限不够就出现经典的“拒绝访问”错误。

解决这个问题已知访问方式有:

1、匿名访问;在应用服务器(简称AP)启用guest,并且设置guest具有激活和访问COM+的权限。这条路是可行,不过安全性不能得到保证。

2、客户端电脑的登录用户和密码和AP上的一个用户一致,并且这个用户在AP上也具有相应的访问COM+的权限。这种方式要比第一种好一些,但是哪个单位的IT系统会是这种样子呢。肯定是每台机器都有自己的帐户密码。这个方式也不好。注:这种方式在不需要发布客户端软件到诺干多的机器上的时候也是可行的,比如访问COM+ 的是webServer.

3、在域管理的网络环境中,同样可以实现,但是有个问题,如果您的客户不愿意改造成域环境呢。所以这种方法也是有局限性的。

最后,我想到如果远程访问COM+的时候能够显式的给定用于AP验证权限的用户名和密码不是就可以解决这个问题了吗?事实上这个方式是可行的。不过在delphi7中还没有现成的函数可以达到这个目的。

comobj.pas 中有个函数 function CreateRemoteComObject(const MachineName: WideString;
const ClassID: TGUID): IUnknown; 这个是用来创建远程的com+接口的。我要改造的主要是这个函数。

function CoCreateInstanceEx(const clsid: TCLSID;
unkOuter: IUnknown; dwClsCtx: Longint; ServerInfo: PCoServerInfo;
dwCount: Longint; rgmqResults: PMultiQIArray): HResult; stdcall; 这个函数可以用来创建远程的com+

ServerInfo 用来存储远程的服务器信息,包括访问和激活com+服务的帐户和密码。

我们来分析一下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;

我们在CreateRemoteComObject中调用CoCreateInstanceEx的时候,首先给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();//用户名
wDomain:=getappserver();//远程计算机名
wPsw:=getAppPassword();//密码

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;//winNt默认的鉴证服务 RPC_C_AUTHN_WINNT
dwAuthzSvc:=$FFFFFF;//0; //RPC_C_AUTHZ_NONE
//pwszServerPrincName:=pwidechar(wDomain);
dwAuthnLevel:=3;//0;
dwImpersonationLevel:=3;//必须设置成模拟
pAuthIdentityData:=@fcid;
dwCapabilities:=$0;//$0800;
end;
FillMemory(@ServerInfo, sizeof(ServerInfo), 0);
ServerInfo.pwszName := PWideChar(wDomain);
ServerInfo.dwReserved1:=0;
ServerInfo.pAuthInfo:=@fcai;

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;

以上代码 确保获取远程的com+的接口,接口类型为Iunkown

但是要访问其中的方法还需要用下面的函数来设置远程com本地引用的访问权限。

with fcai do
CoSetProxyBlanket(iu,dwAuthnSvc,dwAuthzSvc,pwidechar(pAuthIdentityData^.Domain),
dwAuthnLevel,dwImpersonationLevel,pAuthIdentityData,dwCapabilities);

将这个函数封装后得到一个新函数

function SetProxyBlanket(iu:IUnknown):boolean;
var
Fcai:_CoAuthInfo;
Fcid:_CoAuthIdentity;
wUser,wDomain,wPsw:WideString;
iiu:idispatch;

si:Tsocinfo;
begin

wUser:=getAppUserid();//用户名
wDomain:=getappserver();//远程计算机名
wPsw:=getAppPassword();//密码
if wDomain='127.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;
//以上填充_CoAuthIdentity结构
with fcai do begin
dwAuthnSvc:=10;//winNt默认的鉴证服务 RPC_C_AUTHN_WINNT
dwAuthzSvc:=$FFFFFF;//0; //RPC_C_AUTHZ_NONE
//pwszServerPrincName:=pwidechar(wDomain);
dwAuthnLevel:=3;//0;
dwImpersonationLevel:=3;//必须设置成模拟
pAuthIdentityData:=@fcid;
dwCapabilities:=$0;//$0800;
end;

with fcai do
CoSetProxyBlanket(iu,dwAuthnSvc,dwAuthzSvc,pwidechar(pAuthIdentityData^.Domain),
dwAuthnLevel,dwImpersonationLevel,pAuthIdentityData,dwCapabilities);
end;

最后我们改造delphi自动生成的*_TLB.pas 中的函数CreateRemote 如下

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;

参考了一些资料:MSDN,《windows安全性编程》。

软件环境:

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.

转载于:https://www.cnblogs.com/spiritofcloud/p/3980393.html

非匿名方式访问远程的com+相关推荐

  1. Spark: Structured JDBC 方式访问远程的高可用HA的HIVE

    1. 背景 Spark: Structured JDBC 方式访问远程的高可用HA的HIVE,hive是看高可用的,连接信息如下 jdbc:hive2://xx.cdh1.test.dtwave.in ...

  2. 此远程计算机不支持remoteapp,[Tips] 使用 RemoteApp 方式访问远程桌面上的应用程序...

    使用 RemoteApp 方式访问远程桌面上的应用程序 补充这篇日志纯粹是为了方便自己,经验技巧当然是很早以前的!原因是最近经常要访问笔记本上的应用,但又不想基于远程桌面环境,所以直接以应用窗口模式打 ...

  3. Python使用SSH代理访问远程Docker

    Python使用SSH代理访问远程Docker Docker 20.10.17 Python 2.7 1 前言 Python中有个叫docker-py的客户端库用来操作docker,关于docker- ...

  4. Confluence 6 匿名访问远程 API

    Confluence 管理员可能希望为匿名用户禁用远程访问 API.这样能够避免恶意软件随意在网站进行批量修改. 希望禁用远程访问 API: 在屏幕的右上角单击 控制台按钮 ,然后选择 General ...

  5. Redis + Java拦截器实现用户匿名和非匿名访问

    文章目录 需求 实现截图 核心代码 WebMvcConfigurer HandlerInterceptor 判断用户是否有权限 ThreadLocal 该篇文章以<Redis实现短信验证码登录& ...

  6. struts的action访问servlet的IOC方式与非IOC方式

    这是IOC方式,要实现相应接口 package loginAction; import com.opensymphony.xwork2.ActionSupport; import javax.serv ...

  7. 怎样访问远程服务器文件夹,访问远程服务器的共享文件夹

    访问远程服务器的共享文件夹 内容精选 换一换 FOTA升级作用:在官方更新新固件后,模组设备无需寄回给官方,而是通过远程FTP/HTTP进行OTA升级固件,以更新新固件版本,从而达到更新设备的功能/B ...

  8. arm服务器获取文件路径中文,ssh 访问远程服务器文件路径

    ssh 访问远程服务器文件路径 内容精选 换一换 在IntelliJ上选择"项目",找到".idea"文件夹,单击右键选择"新建>文件" ...

  9. centos7搭建SVN并配置使用http方式访问SVN服务器

    一.检查SVN是否安装 centos7系统自带SVN # rpm -qa subversion [root@localhost ~]# rpm -qa subversion subversion-1. ...

最新文章

  1. LLVM IR 理解
  2. Genome Biology:人体各部位微生物组时间序列分析
  3. [原] Android持续优化 - 提高流畅度
  4. python中的input函数怎么用_python input()函数怎么用,_Python_ 少侠科技
  5. python苹果下载软件助手哪个好_Mac上有什么实用的必备软件?
  6. word文档老是出现这个提示-----“发现二义性的名称:TmpDDE”错误
  7. 计算机二级办公软件aoa 百度云,计算机二级办公 考生注意事项(二级AOA)
  8. React开发(124):ant design学习指南之form中的this.props.form
  9. fasta文件中DNA to RNA
  10. 解析Tensorflow官方PTB模型的demo
  11. 95-134-114-源码-维表-Hbase维表关联:LRU策略
  12. 《东周列国志》第九十七回 死范睢计逃秦国 假张禄廷辱魏使
  13. OPENCV LOMO效果
  14. selenium 能定位成功 不能输入 和点击的解决办法
  15. 记一次ARM-鲲鹏服务器读写parquet报错解决过程
  16. 最简易的js的按键组合
  17. SpringCloud(Hoxton SR6)微服务工具集学习笔记
  18. [雪峰磁针石博客]可爱的python测试开发库
  19. css background-image 背景图片自适应宽高
  20. C#对接天翼物联网平台,一些坑

热门文章

  1. 粒子寻优算法PSO学习笔记
  2. 数据库原理课后答案 第二章
  3. 第四届国际步态识别竞赛HID2023已经启动,欢迎报名
  4. 1.12 将工作簿导出为PDF文件 [原创Excel教程]
  5. BP 供应商创建与修改
  6. uefi启动 多硬盘gtp_关于UEFI启动+GPT分区的一些经验
  7. csp-202206
  8. c++单链表 一元多项式求和_C++一元多项式相加
  9. c语言对编程对作用,c语言编程心得体会
  10. Ubuntu显示设置