从PL / SQL调用shell脚本,但shell作为网格用户而不是oracle执行

时间:2014-07-29 17:26:28

标签: sql linux oracle bash shell

我正在尝试使用Runtime.getRuntime()。exec从Oracle数据库内部执行shell脚本。

在Red Hat 5.5上运行的Oracle 11.2.0.4 EE


CREATE OR REPLACE procedure pr_executa_host(p_cmd varchar2)
    as language java name 'Util.RunThis(java.lang.String)';
/

public class Util extends Object
{

  public static int RunThis(java.lang.String args)
  {
  Runtime rt = Runtime.getRuntime();
  int        rc = -1;

  try
  {
     Process p = rt.exec(args);

     int bufSize = 4096;
     BufferedInputStream bis =
      new BufferedInputStream(p.getInputStream(), bufSize);
     int len;
     byte buffer[] = new byte[bufSize];

     // Echo back what the program spit out
     while ((len = bis.read(buffer, 0, bufSize)) != -1)
        System.out.write(buffer, 0, len);

     rc = p.waitFor();
  }
  catch (Exception e)
  {
     e.printStackTrace();
     rc = -1;
  }
  finally
  {
     return rc;
  }
  }
}
/

在java上向db用户SCOTT授予的权限:


kind    grantee    type    name    action

GRANT    SCOTT    java.io.FilePermission    /webstart/mn500/*    readFileDescriptor
GRANT    SCOTT    java.io.FilePermission    /webstart/mn500/*    read,write,execute
GRANT    SCOTT    java.io.FilePermission    /webstart/mn500/*    writeFileDescriptor
GRANT    SCOTT    java.io.FilePermission  /webstart/mn500/CONCLUIDO/MN457560/executa.sh execute
GRANT    SCOTT    java.lang.RuntimePermission    *    writeFileDescriptor
GRANT    SCOTT    java.lang.RuntimePermission /webstart/mn500/CONCLUIDO/MN457560/executa.sh    execute

shell脚本executa.sh,这是我正在尝试执行的脚本:


#!/bin/sh
echo i am `/usr/bin/whoami`
echo environment `/bin/env`
/bin/date>>/webstart/mn500/CONCLUIDO/MN457560/test.txt

目录的权限:


p08[oracle] $ ls -larth /webstart/mn500/CONCLUIDO/MN457560
-rw-r--r--   1 oracle oinstall    1 Jul 29 12:03 test.txt
-rwxr-xr-x   1 oracle orafiles  430 Jul 29 12:04 executa.sh
drwxr-xr-x   2 oracle orafiles 4.0K Jul 29 12:04 .

问题是,当我执行pr_executa_host过程时,它将shell脚本作为grid os运行 用户,而不是oracle! (虽然它保留了oracle环境变量,就像它做了'su grid -m' 在执行shell脚本之前)

由于网格既没有对目录也没有文件的写权限,因此脚本没有 做任何事情,测试文件保持不变。看看:


begin
  dbms_java.set_output(1000000);
  pr_executa_host('/webstart/mn500/CONCLUIDO/MN457560/executa.sh');
  dbms_lock.sleep(2);
end;
/

i am grid
environment HOSTNAME=p08.XXXXXXXXXXXX.com.br SHELL=/bin/bash TERM=xterm HISTSIZE=1000 
SSH_CLIENT=10.141.112.28 56029 22 NLS_LANG=AMERICAN_AMERICA.WE8MSWIN1252 QTDIR=/usr/lib64/qt-3.3 
QTINC=/usr/lib64/qt-3.3/include SSH_TTY=/dev/pts/0 USER=oracle 
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;0
1:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01
;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*
.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.tbz=01;31:*.tbz2=01;31:*.bz=01;31
:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7
z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01
;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;3
5:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*
.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=
01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35
:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.a
ac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=
01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36: ORACLE_SID=sigepshm 
ORACLE_BASE=/oracle ORACLE_HOSTNAME=P08 PATH= MAIL=/var/spool/mail/oracle 
TNS_ADMIN=/grid/product/11.2.0/grid/network/admin PWD=/oracle/product/11.2.0/db/dbs 
KDE_IS_PRELINKED=1 LANG=en_US.UTF-8 ORA_NET2_DESC=27,30 KDEDIRS=/usr ORACLE_TERM=xterm 
ORACLE_SPAWNED_PROCESS=1 HISTCONTROL=ignoredups SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass 
HOME=/home/oracle SHLVL=2 GRID_HOME=/oracle/product/11.2.0/grid LOGNAME=oracle CVS_RSH=ssh 
QTLIB=/usr/lib64/qt-3.3/lib SSH_CONNECTION=10.141.112.28 56029 10.147.0.8 22 
CLASSPATH=/oracle/product/11.2.0/db/JRE:/oracle/product/11.2.0/db/jlib:/oracle/product/11.2.0/db/rdb
ms/jlib LESSOPEN=|/usr/bin/lesspipe.sh %s DISPLAY=localhost:10.0 
ORACLE_HOME=/oracle/product/11.2.0/db G_BROKEN_FILENAMES=1 _=/bin/env

为什么数据库中的java调用unix命令为grid用户,而不是oracle?

非常感谢你的帮助, Stolf

2 个答案:

答案 0 :(得分:3)

正如评论中所指出的那样,问题是Runtime.getRuntime()。exec在EXTPROC中运行,因此通过Grid Listener运行。由于我们的新配置在DB和GRID之间存在操作系统用户隔离,因此会引发FS上的权限问题。

对此的解决方案之一是:

  • 修复FS权限,让网格用户编写文件并将umask更改为774或664,这样网格和oracle用户以后都可以修改文件;

  • 更改sudoers文件并允许网格执行oracle所需的命令而无需密码,并更改shell脚本以包含sudo;

  • 在另一个端口上的DB Home上创建一个新侦听器,并将TNSNAMES.ORA条目更改为指向新端口。然后extproc将作为OS用户oracle执行。您必须在$ OH上手动编辑LISTENER.ORA并使用lsnrctl启动它,因为使用srvctl注册的侦听器将始终由网格启动;

  • 将主侦听器更改为db home。我不推荐(见上面的项目)。

[编辑] 正如@AlexPoole和@jonearles所指出的,还有另外两个选项不适合我的情况,但也可能适用于其他选项:

  • 如果在sqlplus上本地运行脚本,设置ORACLE_SID,则FS访问将由运行sqlplus的OS用户进行。因此,您可以作为oracle或其他一些用户运行并修复FS权限;
  • 如果您将dbms_job调度程序上的作业调度为SYS,则该任务将由oracle执行(此行为可能取决于版本,因此需要进一步测试)。

此致

Daniel Stolf

答案 1 :(得分:1)

在进一步调查中,它以启动会话的OS用户身份运行脚本;但是服务器用户,而不是osuser中的客户v$session

如果您通过SQL * Plus本地连接,而不通过SQL * Net,则shell脚本将作为您自己的操作系统用户运行,而不是grid oracle,除非你作为其中之一登录了这个盒子。因此,当我以自己的身份执行该过程时,脚本会报告i am apoole

当你远程运行时,会话的OS用户是监听器所有者,默认情况下,网格环境中的用户将是grid。并且,当启动侦听器时,您会看到grid用户的环境。

因此,如果您要通过SQL * Net连接的客户端手动执行此操作,那么您自己的答案中的选项是有效的。您可以将数据库侦听器移动到oracle帐户下运行,或者在该帐户下创建一个新侦听器,然后通过该帐户进行连接。然后,当从通过该侦听器连接的任何会话调用时,脚本将以oracle执行。或者让操作系统权限/ sudo为你工作。

如果您将或不可能通过SQL * Net从本地会话执行它,那么您需要使操作系统权限对任何可能调用它的用户有效 - 假设您不能运行来自oracle帐户启动的SQL * Plus。听众不是图片的一部分,因此grid用户不是一个因素。


这是它作为匿名块运行的时候;正如@jonearles在对该问题的评论中指出的那样,预定作业的行为是不同的。默认情况下,它会以nobody执行脚本,这意味着您必须更多地放宽操作系统权限。