Иногда бывают такие ситуации, когда у нас есть доступ к СУБД, но нет доступа к операционной системе. А он нужен вот прям позарез, перенести какие-нибудь файлы или посмотреть структуру каталогов, например.
В такой ситуации на помощь может прийти хранимая процедура на Java.
В этой статье все действия выполняются от имени пользователя SYS. Если хотите повторить действия из под другого пользователя необходимо добавить ему разрешения:
begin
dbms_java.grant_permission(‘MYUSER’, ‘SYS:java.lang.RuntimePermission’, ‘writeFileDescriptor’, »);
dbms_java.grant_permission(‘MYUSER’, ‘SYS:java.lang.RuntimePermission’, ‘readFileDescriptor’, »);
dbms_java.grant_permission(‘MYUSER’, ‘SYS:java.io.FilePermission’, ‘/bin/sh’, ‘execute’);
end;
Для начала необходимо скомпилировать основной класс на Java:
create or replace and compile java source named host as
import java.io.*;
public class Host {
public static String executeCommand(String command) {
String buff = null;
String tmp ="";
try {
String[] finalCommand;
if (System.getProperty("os.name").toLowerCase().indexOf("windows") != -1) {
finalCommand = new String[4];
finalCommand[0] = "C:\\winnt\\system32\\cmd.exe";
finalCommand[1] = "/y";
finalCommand[2] = "/c";
finalCommand[3] = command;
} else { // Linux or Unix System
finalCommand = new String[3];
finalCommand[0] = "/bin/sh";
//finalCommand[0] = "";
finalCommand[1] = "-c";
finalCommand[2] = command;
}
// Execute the command...
final Process pr = Runtime.getRuntime().exec(finalCommand);
// Capture output from STDOUT...
BufferedReader br_in = null;
try {
br_in = new BufferedReader(new InputStreamReader(pr.getInputStream()));
tmp =tmp+"STDOUT: "+"\n";
while ((buff = br_in.readLine()) != null) {
//System.out.println("stdout: " + buff);
tmp=tmp+buff+"\n";
try {Thread.sleep(100); } catch(Exception e) {}
}
br_in.close();
} catch (IOException ioe) {
//System.out.println("Error printing process output.");
tmp =tmp+ "Error printing process output."+"\n";
//ioe.printStackTrace();
} finally {
try {
br_in.close();
} catch (Exception ex) {}
}
// Capture output from STDERR...
BufferedReader br_err = null;
try {
br_err = new BufferedReader(new InputStreamReader(pr.getErrorStream()));
tmp =tmp+"\n"+"STDERR: "+"\n";
while ((buff = br_err.readLine()) != null) {
//System.out.println("stderr: " + buff);
tmp=tmp+buff+"\n";
try {Thread.sleep(100); } catch(Exception e) {}
}
br_err.close();
return tmp;
} catch (IOException ioe) {
//System.out.println("Error printing execution errors.");
tmp =tmp+ "Error printing execution errors."+"\n";
//ioe.printStackTrace();
} finally {
try {
br_err.close();
} catch (Exception ex) {}
}
}
catch (Exception ex) {
tmp =tmp+ ex.getLocalizedMessage()+"\n";
}
return tmp;
}
};
После этого необходимо развернуть обертку к нему на PL/SQL:
create or replace function host (p_command IN VARCHAR2) return varchar2 AS LANGUAGE JAVA NAME 'Host.executeCommand (java.lang.String) return String';
После чего можно приступать к выполнению команд на уровне ОС, например ls:
begin
dbms_output.put_line(host('/bin/ls /opt'));
end;
