【问题标题】:perl + DBD::Oracle + mod_perl + oracle LDAP name resolver = crash?perl + DBD::Oracle + mod_perl + oracle LDAP 名称解析器 = 崩溃?
【发布时间】:2013-12-21 05:19:12
【问题描述】:

这发生在我较旧的 Fedora 系统上。今天,我设置了一个新的 CentOS 6.5,安装了最新的 oracle 客户端(12.1.0.1.0),来自 cpan(1.68)的最新 DBD::Oracle,并且遇到了同样的问题:当我尝试连接到数据库。当我从命令行或 CGI 尝试相同的 perl 时,它可以工作;当我关闭 sqlnet.ora 文件中的 LDAP 名称解析器时,它也能正常工作。

从头开始:这是我的startup.pl:

$ENV{'NLS_LANG'}='AMERICAN_AMERICA.AL32UTF8';
$ENV{'ORACLE_HOME'}='/opt/oracle/OraHome1';
use DBI ();
use DBD::Oracle ();

这是我的测试程序:

#!/usr/bin/perl
require "startup.pl" unless defined $ENV{'ORACLE_HOME'};
use DBI;
use DBD::Oracle;
print "Content-type: text/plain\n\n";
print "connecting: \n";
my $dbh=DBI->connect("dbi:Oracle:mydb", 'username', 'password');
print "connected! \n";

从 shell 运行它效果很好。作为 CGI 脚本运行效果很好。从 mod_perl 运行它会使 apache 崩溃:

[Wed Dec 04 16:38:01 2013] [notice] Apache/2.2.15 (Unix) DAV/2 PHP/5.3.3 mod_wsgi/3.2 Python/2.6.6 mod_perl/2.0.4 Perl/v5.10.1 configured -- resuming normal operations
[Wed Dec 04 16:38:28 2013] [notice] child pid 25756 exit signal Segmentation fault (11)

对 httpd 进程进行 strace 显示如下:

connect(21, {sa_family=AF_INET, sin_port=htons(389), sin_addr=inet_addr("10.250.52.237")}, 16) = 0
write(21, "0\f\2\1\1`\7\2\1\2\4\0\200\0", 14) = 14
poll([{fd=21, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, -1) = 1 ([{fd=21, revents=POLLIN}])
read(21, "0\204\0\0\0\20\2\1", 8)       = 8
read(21, "\1a\204\0\0\0\7\n\1\0\4\0\4\0", 14) = 14
write(21, "0\201\226\2\1\2c\201\220\0042cn=bpas_p,cn=OracleCo"..., 153) = 153
poll([{fd=21, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 10000) = 1 ([{fd=21, revents=POLLIN}])
read(21, "0\204\0\0\1{\2\1", 8)         = 8
read(21, "\2d\204\0\0\1r\0040cn=bpas_p,cn=OracleCont"..., 377) = 377
--- SIGSEGV (Segmentation fault) @ 0 (0) ---

因此,很明显,httpd 在与 10.250.52.237:389 通信时崩溃,这是 oracle 名称解析器的 ldap 端口。

我的标准sqlnet.ora是:

NAMES.DIRECTORY_PATH    = (LDAP, ONAMES, TNSNAMES)
NAMES.DEFAULT_DOMAIN    = xxx.yyyy.zzz
NAMES.PREFERRED_SERVERS =
  (ADDRESS_LIST =
    (ADDRESS = (PROTOCOL = TCP)(HOST = oranames01.yyyy.zzz)(PORT = 1501))
    (ADDRESS = (PROTOCOL = TCP)(HOST = oranames02.yyyy.zzz)(PORT = 1502))
  )

这是我的 ldap.ora:

DIRECTORY_SERVERS = (oranames01.yyyy.zzz:389:636, oranames02.yyyy.zzz:389:636)
DEFAULT_ADMIN_CONTEXT = "dc=xxx, dc=yyyy, dc=zzz"
DIRECTORY_SERVER_TYPE = OID

来自 strace 转储的地址 (10.250.52.237) 是 oranames01.yyyy.zzz 的 IP 地址。

现在,如果我从 sqlnet.ora 中删除 LDAP 适配器

NAMES.DIRECTORY_PATH    = (ONAMES, TNSNAMES)

并将数据库连接字符串放入 tnsnames.ora

mydb.xxx.yyyy.zzz=(DESCRIPTION=(SOURCE_ROUTE=OFF)(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=ivorapo01.xxx.yyyy.zzz)(PORT=15350)))(CONNECT_DATA=(SERVICE_NAME=mydb.xxx.yyyy.zzz)(FAILOVER_MODE =(TYPE = SELECT)(METHOD = BASIC)(RETRIES = 180)(DELAY = 1))))

一切正常 - 命令行、cgi perl 和 mod_perl。

因此,显然,mod_perl 和 LDAP 名称解析器的组合似乎存在一些问题。

这发生在我的 Fedora 14 系统上,首先是 apache 2.2.17 和 Oracle 客户端 10.2.0.1.0,今天是新安装的 CentOs 6.5、apache 2.2.15 和 oracle 客户端 12.1.0.1.0 .谷歌搜索 mod_perl 和 oracle 显示一些命中,指的是 ORACLE_HOME 设置得太晚(我也有这个,将它放入 startup.pl 解决了这个问题),但似乎没有什么适合我的问题。

谁能证实这一点?或者,任何人都可以确认 mod_perl + DBD::Oracle + oracle LDAP 名称解析在他们的站点上工作吗?现在,我可以通过不使用 LDAP 名称适配器来解决这个问题,但我希望在投入生产之前解决这个问题。

【问题讨论】:

    标签: oracle perl apache mod-perl2


    【解决方案1】:

    我将此追溯到 ldap 库 /lib64/libldap-2.4.so.2。这个库由 mod_ldap、mod_authnz_ldap 和 mod_php 通过可选的依赖项使用(似乎依赖项列表是 php -> libcurl -> libssl -> libldap,但我并没有真正调查)。这个库也复制了 oracle 在libclntsh.so 中定义的几个函数名称。显然,这些功能彼此不兼容。就我而言,崩溃发生在 ldap_search_st。

    一旦我从我的服务器中删除了 mod_php、mod_ldap 和 mod_authnz_ldap,崩溃就停止了。

    由于 libldap 对 php 的依赖似乎是可选的,我尝试重新启用 php,并将 /lib64/libldap-2.4.so.2 重命名为 /lib64/libldap-2.4.so.2.disabled,这样 php 就不会加载它。我重新启用了php,服务器仍然没有崩溃。

    我的服务器上不需要 php,所以我再次禁用了 php 并取消了库重命名。但似乎解决方案是:

    a) 您不能在一个进程中将 oracle LDAP 名称解析器与系统 LDAP 库一起使用。

    b) 如果你想使用 LDAP 解析器,你需要禁用 mod_ldap 和 mod_authnz_ldap。

    c) 如果您的服务器不需要 php,也请禁用它。如果它确实需要 php,你可以让它保持启用状态,但你必须确保它不会加载系统 ldap 库。 php中的ldap函数,以及依赖它的curl,都不起作用。

    d) 您可以重命名系统 ldap 库以确保它不会被拉入,但这会杀死系统上依赖 LDAP 的所有其他内容。 (请注意,perl 中的 Net::LDAP 模块确实使用此库,因此重命名后它仍然可以工作!)。

    e) 如果你真的需要 php 和 ldap 库,我看到的唯一解决方法是将 libldap-2.4.so.2 复制到不在 /etc/ld.so.cache 中的某个目录,然后设置 LD_LIBRARY_PATH到需要该库的程序的目录(但显然不是 http 服务器)。

    【讨论】:

    • 刚刚尝试过:在 /etc/php.d/curl.ini 中禁用 curl 也可以,并且不会像重命名库那样干扰系统。
    猜你喜欢
    • 2015-01-30
    • 2016-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-23
    • 1970-01-01
    • 1970-01-01
    • 2012-10-19
    相关资源
    最近更新 更多