perl + DBD :: Oracle + mod_perl + oracle LDAP名称解析器=崩溃?

时间:2013-12-04 16:04:48

标签: oracle perl apache mod-perl2

在旧的Fedora系统上发生了这种情况。今天,我建立了一个新的CentOS 6.5,安装了最新的oracle客户端(12.1.0.1.0),最新的DBD :: Oracle来自cpan(1.68),并遇到了同样的问题:apache segfaults当我尝试连接到数据库。当我从命令行或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名称适配器解决问题,但我更愿意在进入生产之前解决这个问题。

1 个答案:

答案 0 :(得分:0)

我将其追溯到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模块 NOT 使用此库,因此在重命名后它仍然可以工作!)。

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