package org.owasp.webgoat.util; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.BitSet; /** * Copyright (c) 2002 Free Software Foundation developed under the custody of the Open Web * Application Security Project (http://www.owasp.org) This software package org.owasp.webgoat.is published by OWASP * under the GPL. You should read and accept the LICENSE before you use, modify and/or redistribute * this software. * * @author Jeff Williams Aspect Security * @created October 28, 2003 */ public class Exec { /** * Description of the Method * * @param command Description of the Parameter * @param input Description of the Parameter * @return Description of the Return Value */ public static ExecResults execInput( String command, String input ) { return ( execOptions( command, input, 0, 0, false ) ); } /** * Description of the Method * * @param command Description of the Parameter * @return Description of the Return Value */ public static ExecResults execLazy( String command ) { return ( execOptions( command, "", 0, 0, true ) ); } /* * Execute an OS command and capture the output in an ExecResults. * All exceptions are caught and stored in the ExecResults. * @param String command is the OS command to execute * @param String input is piped into the OS command * @param int successCode is the expected return code if the command completes successfully * @param int timeout is the number of milliseconds to wait before interrupting the command * @param boolean quit tells the method to exit when there is no more output waiting */ /** * Description of the Method * * @param command Description of the Parameter * @param input Description of the Parameter * @param successCode Description of the Parameter * @param timeout Description of the Parameter * @param lazy Description of the Parameter * @return Description of the Return Value */ public static ExecResults execOptions( String[] command, String input, int successCode, int timeout, boolean lazy ) { Process child = null; ByteArrayOutputStream output = new ByteArrayOutputStream(); ByteArrayOutputStream errors = new ByteArrayOutputStream(); ExecResults results = new ExecResults( command[0], input, successCode, timeout ); BitSet interrupted = new BitSet( 1 ); boolean lazyQuit = false; ThreadWatcher watcher; try { // start the command child = Runtime.getRuntime().exec( command ); // get the streams in and out of the command InputStream processIn = child.getInputStream(); InputStream processError = child.getErrorStream(); OutputStream processOut = child.getOutputStream(); // start the clock running if ( timeout > 0 ) { watcher = new ThreadWatcher( child, interrupted, timeout ); new Thread( watcher ).start(); } // Write to the child process' input stream if ( ( input != null ) && !input.equals( "" ) ) { try { processOut.write( input.getBytes() ); processOut.flush(); processOut.close(); } catch ( IOException e1 ) { results.setThrowable( e1 ); } } // Read from the child process' output stream // The process may get killed by the watcher at any time int c = 0; try { while ( true ) { if ( interrupted.get( 0 ) || lazyQuit ) { break; } // interrupted c = processIn.read(); if ( c == -1 ) { break; } // end of stream output.write( c ); if ( lazy && ( processIn.available() < 1 ) ) { lazyQuit = true; } // if lazy and nothing then quit (after at least one read) } processIn.close(); } catch ( IOException e2 ) { results.setThrowable( e2 ); } finally { if ( interrupted.get( 0 ) ) { results.setInterrupted(); } results.setOutput( output.toString() ); } // Read from the child process' error stream // The process may get killed by the watcher at any time try { while ( true ) { if ( interrupted.get( 0 ) || lazyQuit ) { break; } // interrupted c = processError.read(); if ( c == -1 ) { break; } // end of stream output.write( c ); if ( lazy && ( processError.available() < 1 ) ) { lazyQuit = true; } // if lazy and nothing then quit (after at least one read) } processError.close(); } catch ( IOException e3 ) { results.setThrowable( e3 ); } finally { if ( interrupted.get( 0 ) ) { results.setInterrupted(); } results.setErrors( errors.toString() ); } // wait for the return value of the child process. if ( !interrupted.get( 0 ) && !lazyQuit ) { int returnCode = child.waitFor(); results.setReturnCode( returnCode ); if ( returnCode != successCode ) { results.setError( ExecResults.BADRETURNCODE ); } } } catch ( InterruptedException i ) { results.setInterrupted(); } catch ( Throwable t ) { results.setThrowable( t ); } finally { if ( child != null ) { child.destroy(); } } return ( results ); } /* * Execute an OS command and capture the output in an ExecResults. * All exceptions are caught and stored in the ExecResults. * @param String command is the OS command to execute * @param String input is piped into the OS command * @param int successCode is the expected return code if the command completes successfully * @param int timeout is the number of milliseconds to wait before interrupting the command * @param boolean quit tells the method to exit when there is no more output waiting */ /** * Description of the Method * * @param command Description of the Parameter * @param input Description of the Parameter * @param successCode Description of the Parameter * @param timeout Description of the Parameter * @param lazy Description of the Parameter * @return Description of the Return Value */ public static ExecResults execOptions( String command, String input, int successCode, int timeout, boolean lazy ) { Process child = null; ByteArrayOutputStream output = new ByteArrayOutputStream(); ByteArrayOutputStream errors = new ByteArrayOutputStream(); ExecResults results = new ExecResults( command, input, successCode, timeout ); BitSet interrupted = new BitSet( 1 ); boolean lazyQuit = false; ThreadWatcher watcher; try { // start the command child = Runtime.getRuntime().exec( command ); // get the streams in and out of the command InputStream processIn = child.getInputStream(); InputStream processError = child.getErrorStream(); OutputStream processOut = child.getOutputStream(); // start the clock running if ( timeout > 0 ) { watcher = new ThreadWatcher( child, interrupted, timeout ); new Thread( watcher ).start(); } // Write to the child process' input stream if ( ( input != null ) && !input.equals( "" ) ) { try { processOut.write( input.getBytes() ); processOut.flush(); processOut.close(); } catch ( IOException e1 ) { results.setThrowable( e1 ); } } // Read from the child process' output stream // The process may get killed by the watcher at any time int c = 0; try { while ( true ) { if ( interrupted.get( 0 ) || lazyQuit ) { break; } // interrupted c = processIn.read(); if ( c == -1 ) { break; } // end of stream output.write( c ); if ( lazy && ( processIn.available() < 1 ) ) { lazyQuit = true; } // if lazy and nothing then quit (after at least one read) } processIn.close(); } catch ( IOException e2 ) { results.setThrowable( e2 ); } finally { if ( interrupted.get( 0 ) ) { results.setInterrupted(); } results.setOutput( output.toString() ); } // Read from the child process' error stream // The process may get killed by the watcher at any time try { while ( true ) { if ( interrupted.get( 0 ) || lazyQuit ) { break; } // interrupted c = processError.read(); if ( c == -1 ) { break; } // end of stream output.write( c ); if ( lazy && ( processError.available() < 1 ) ) { lazyQuit = true; } // if lazy and nothing then quit (after at least one read) } processError.close(); } catch ( IOException e3 ) { results.setThrowable( e3 ); } finally { if ( interrupted.get( 0 ) ) { results.setInterrupted(); } results.setErrors( errors.toString() ); } // wait for the return value of the child process. if ( !interrupted.get( 0 ) && !lazyQuit ) { int returnCode = child.waitFor(); results.setReturnCode( returnCode ); if ( returnCode != successCode ) { results.setError( ExecResults.BADRETURNCODE ); } } } catch ( InterruptedException i ) { results.setInterrupted(); } catch ( Throwable t ) { results.setThrowable( t ); } finally { if ( child != null ) { child.destroy(); } } return ( results ); } /** * Description of the Method * * @param command Description of the Parameter * @return Description of the Return Value */ public static ExecResults execSimple( String[] command ) { return ( execOptions( command, "", 0, 0, false ) ); } /** * Description of the Method * * @param command Description of the Parameter * @return Description of the Return Value */ public static ExecResults execSimple( String command ) { return ( execOptions( command, "", 0, 0, false ) ); } /** * Description of the Method * * @param command Description of the Parameter * @param args Description of the Parameter * @return Description of the Return Value */ public static ExecResults execSimple( String command, String args ) { return ( execOptions( command, args, 0, 0, false ) ); } /** * Description of the Method * * @param command Description of the Parameter * @param timeout Description of the Parameter * @return Description of the Return Value */ public static ExecResults execTimeout( String command, int timeout ) { return ( execOptions( command, "", 0, timeout, false ) ); } /** * The main program for the Exec class * * @param args The command line arguments */ public static void main( String[] args ) { ExecResults results; String sep = System.getProperty( "line.separator" ); System.out.println( "-------------------------------------------" + sep + "TEST 1: execSimple" ); results = Exec.execSimple( "c:/swarm-2.1.1/bin/whoami.exe" ); System.out.println( results ); System.out.println( "-------------------------------------------" + sep + "TEST 2: execSimple (with search)" ); results = Exec.execSimple( "netstat -r" ); System.out.println( results ); if ( results.outputContains( "localhost:1031" ) ) { System.out.println( "ERROR: listening on 1031" ); } System.out.println( "-------------------------------------------" + sep + "TEST 3: execInput" ); results = Exec.execInput( "find \"cde\"", "abcdefg1\nhijklmnop\nqrstuv\nabcdefg2" ); System.out.println( results ); System.out.println( "-------------------------------------------" + sep + "TEST 4:execTimeout" ); results = Exec.execTimeout( "ping -t 127.0.0.1", 5 * 1000 ); System.out.println( results ); System.out.println( "-------------------------------------------" + sep + "TEST 5:execLazy" ); results = Exec.execLazy( "ping -t 127.0.0.1" ); System.out.println( results ); System.out.println( "-------------------------------------------" + sep + "TEST 6:ExecTimeout process never outputs" ); results = Exec.execTimeout( "c:/swarm-2.1.1/bin/sleep.exe 20", 5 * 1000 ); System.out.println( results ); System.out.println( "-------------------------------------------" + sep + "TEST 7:ExecTimeout process waits for input" ); results = Exec.execTimeout( "c:/swarm-2.1.1/bin/cat", 5 * 1000 ); System.out.println( results ); } }