1 /*
2  * @(#) $Id: JSTKShellServer.java,v 1.2 2003/07/08 08:13:53 pankaj Exp $
3  *
4  * Copyright (c) 2002-03 by Pankaj Kumar (http://www.pankaj-k.net). 
5  * All rights reserved.
6  *
7  * The license governing the use of this file can be found in the 
8  * root directory of the containing software.
9  */
10package org.jstk.jstksh;
11
12import java.util.*;
13import java.util.logging.Logger;
14import java.security.*;
15import java.io.*;
16import javax.security.auth.Subject;
17
18import org.jstk.*;
19
20
21public class JSTKShellServer extends JSTKAbstractTool implements JSTKShell {
22    private String homeDir = null;
23    private String curDir = null;
24    private static int curId = -1;
25    private static HashMap sessionTable = new HashMap();
26
27    static class SessionInfo {
28        String homeDir = null;
29        String curDir = null;
30        public SessionInfo(){
31            homeDir = System.getProperty("user.dir");
32            curDir = homeDir;
33        }
34    }
35
36    static class EchoCommand extends JSTKCommandAdapter {
37        public Object execute(JSTKArgs args) throws JSTKException {
38            StringBuffer msg = new StringBuffer();
39            for (int i = 0; i < args.getNum(); i++){
40                msg.append(args.get(i) + " ");
41            }
42            return new JSTKResult(null, true, msg.toString());
43        }
44    }
45    static class QuitCommand extends JSTKCommandAdapter {
46        public Object execute(JSTKArgs args) throws JSTKException {
47            throw new JSTKQuitException();
48        }
49    }
50
51    static class PWDCommand extends JSTKCommandAdapter {
52        public Object execute(JSTKArgs args) throws JSTKException {
53            String curDir = getCurDir(args);
54            if (curDir == null)
55                return new JSTKResult(null, true, "Session Info. missing or invalid.");
56            return new JSTKResult(null, true, curDir);
57        }
58    }
59
60    static class LSCommand extends JSTKCommandAdapter {
61        public Object execute(JSTKArgs args) throws JSTKException {
62            String curDir = getCurDir(args);
63            if (curDir == null)
64                return new JSTKResult(null, true, "Session Info. missing or invalid.");
65
66            String targetDir = curDir;
67            File file = new File(targetDir);
68            if (!file.isDirectory())
69                return new JSTKResult(null, false, "Not a directory: " + targetDir);
70            String[] fnames = file.list();
71            StringBuffer sb = new StringBuffer();
72            for (int i = 0; i < fnames.length; i++){
73                sb.append(fnames[i] + "\n");
74            }
75            return new JSTKResult(null, true, sb.toString());
76        }
77    }
78
79    static class CDCommand extends JSTKCommandAdapter {
80        public Object execute(JSTKArgs args) throws JSTKException {
81            String curDir = getCurDir(args);
82            String homeDir = getCurDir(args);
83            if (curDir == null || homeDir == null)
84                return new JSTKResult(null, true, "Session Info. missing or invalid.");
85
86            String targetDir = homeDir;
87            if (args.getNum() > 1)
88                return new JSTKResult(null, false, "Specify only one target directory.");
89            else if (args.getNum() == 1)
90                targetDir = args.get(0);
91
92            try {
93                File file = createFile(targetDir, curDir);
94                if (!file.isDirectory())
95                    return new JSTKResult(null, false, "Not a directory: " + targetDir);
96                curDir = file.getCanonicalPath();
97                setCurDir(args, curDir);
98            } catch (IOException ioe){
99                throw new JSTKException("cd failed", ioe);
00            }
01            return new JSTKResult(null, true, "Changed Directory To: " + curDir);
02        }
03    }
04
05    static class MkdirCommand extends JSTKCommandAdapter {
06        public Object execute(JSTKArgs args) throws JSTKException {
07            String curDir = getCurDir(args);
08            if (curDir == null)
09                return new JSTKResult(null, true, "Session Info. missing or invalid.");
10
11            String targetDir = null;
12            if (args.getNum() > 1)
13                return new JSTKResult(null, false, "Specify only one directory name.");
14            else if (args.getNum() == 1)
15                targetDir = args.get(0);
16            else
17                return new JSTKResult(null, false, "No directory name specified.");
18
19            boolean result =false;
20            try {
21                File file = createFile(targetDir, curDir);
22                if (file.exists())
23                    return new JSTKResult(null, false, "File or directory exists: " + targetDir);
24
25                result = file.mkdirs();
26            } catch (IOException ioe){
27                throw new JSTKException("mkdir failed", ioe);
28            }
29
30            if (result)
31                return new JSTKResult(null, true, "Directory Created: " + targetDir);
32            else
33                return new JSTKResult(null, false, "Cannot create directory: " + targetDir);
34        }
35    }
36
37    static class RMCommand extends JSTKCommandAdapter {
38        public Object execute(JSTKArgs args) throws JSTKException {
39            String curDir = getCurDir(args);
40            if (curDir == null)
41                return new JSTKResult(null, true, "Session Info. missing or invalid.");
42
43            String targetFile = null;
44            if (args.getNum() > 1)
45                return new JSTKResult(null, false, "Specify only one target.");
46            else if (args.getNum() == 1)
47                targetFile = args.get(0);
48            else
49                return new JSTKResult(null, false, "No target specified.");
50
51            boolean result = false;
52            try {
53                File file = createFile(targetFile, curDir);
54                if (!file.exists())
55                    return new JSTKResult(null, false, "Target doesn't exist: " + targetFile);
56
57                result = file.delete();
58            } catch (IOException ioe){
59                return new JSTKResult(null, false, "rm failed : " + targetFile + ", Exception: " + ioe);
60            }
61
62            if (result)
63                return new JSTKResult(null, true, "Target removed: " + targetFile);
64            else
65                return new JSTKResult(null, false, "Target ccould not be removed: " + targetFile);
66        }
67    }
68
69    static class CatCommand extends JSTKCommandAdapter {
70        public Object execute(JSTKArgs args) throws JSTKException {
71            String curDir = getCurDir(args);
72            if (curDir == null)
73                return new JSTKResult(null, true, "Session Info. missing or invalid.");
74
75            String targetFile = null;
76            if (args.getNum() > 1)
77                return new JSTKResult(null, false, "Specify only one target.");
78            else if (args.getNum() == 1)
79                targetFile = args.get(0);
80            else
81                return new JSTKResult(null, false, "No target specified.");
82
83            try {
84                File file = createFile(targetFile, curDir);
85                if (!file.exists())
86                    return new JSTKResult(null, false, "Target doesn't exist: " + targetFile);
87
88                ByteArrayOutputStream baos = new ByteArrayOutputStream();
89                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
90                int ch;
91                while ((ch = bis.read()) != -1)
92                    baos.write(ch);
93
94                return new JSTKResult(null, true, baos.toString());
95            } catch (IOException ioe){
96                throw new JSTKException("cat failed", ioe);
97            }
98        }
99    }
00
01    static class CpCommand extends JSTKCommandAdapter {
02        public Object execute(JSTKArgs args) throws JSTKException {
03            String curDir = getCurDir(args);
04            if (curDir == null)
05                return new JSTKResult(null, true, "Session Info. missing or invalid.");
06
07            String srcFile = null;
08            String dstFile = null;
09            if (args.getNum() > 2)
10                return new JSTKResult(null, false, "Too many arguments.");
11            else if (args.getNum() == 2){
12                srcFile = args.get(0);
13                dstFile = args.get(1);
14            } else
15                return new JSTKResult(null, false, "Insufficient arguments.");
16
17            try {
18                File sFile = createFile(srcFile, curDir);
19                if (!sFile.exists())
20                    return new JSTKResult(null, false, "Source doesn't exist: " + srcFile);
21
22                File dFile = createFile(dstFile, curDir);
23                if (dFile.exists())
24                    return new JSTKResult(null, false, "Destination exists: " + dstFile);
25
26                BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dFile));
27                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sFile));
28                int ch;
29                while ((ch = bis.read()) != -1)
30                    bos.write(ch);
31
32                bis.close();
33                bos.close();
34
35                return new JSTKResult(null, true, "cp: " + srcFile + " --> " + dstFile);
36            } catch (IOException ioe){
37                throw new JSTKException("cp failed", ioe);
38            }
39        }
40    }
41
42    static class ShowCommand extends JSTKCommandAdapter {
43        public Object execute(JSTKArgs args) throws JSTKException {
44            String target = "pdomain";
45            if (args.getNum() > 0)
46                target = args.get(0);
47
48            Class cls = ShowCommand.class;
49            ProtectionDomain pDomain = cls.getProtectionDomain();
50            if (target.equalsIgnoreCase("pdom")){
51                StringBuffer sb = new StringBuffer();
52                CodeSource cs = pDomain.getCodeSource();
53                sb.append("CodeSource: " + cs.toString() + "\n");
54                Principal[] principals = pDomain.getPrincipals();
55                if (principals != null){
56                    for (int i = 0; i < principals.length; i++){
57                        sb.append("Principal[" + i + "]: " + principals[i] + "\n");
58                    }
59                }
60                PermissionCollection permsColl = pDomain.getPermissions();
61                sb.append("Permissions: " + permsColl.toString());
62                return new JSTKResult(null, true, sb.toString());
63            } else if (target.equalsIgnoreCase("perms")){
64                CodeSource cs = pDomain.getCodeSource();
65                PermissionCollection permsColl = Policy.getPolicy().getPermissions(cs);
66                return new JSTKResult(null, true, permsColl.toString());
67            } else if (target.equalsIgnoreCase("cs")){
68                CodeSource cs = pDomain.getCodeSource();
69                return new JSTKResult(null, true, cs.toString());
70            } else if (target.equalsIgnoreCase("classloaders")){
71                StringBuffer sb = new StringBuffer();
72                ClassLoader cl = cls.getClassLoader();
73                int idx = 0;
74                while (cl != null){
75                    sb.append("[" + idx + "]ClassLoader: " + cl + "\n");
76                    cl = cl.getParent();
77                    ++idx;
78                }
79                return new JSTKResult(null, true, sb.toString());
80            }
81            return new JSTKResult(null, false, "unknown target: " + target);
82        }
83    }
84
85    static class WhoAmICommand extends JSTKCommandAdapter {
86        public Object execute(JSTKArgs args) throws JSTKException {
87            AccessControlContext acc = AccessController.getContext();
88            Subject sub = Subject.getSubject(acc);
89            Object[] principals = sub.getPrincipals().toArray();
90            StringBuffer sb = new StringBuffer();
91            for (int i = 0; i < principals.length; i++)
92                sb.append("[" + i + "]" + principals[i].toString());
93
94            return new JSTKResult(null, true, sb.toString());
95        }
96    }
97
98    static class TimeCommand extends JSTKCommandAdapter {
99        public Object execute(JSTKArgs args) throws JSTKException {
00            try {
01                int loopcount = 1000;
02                String loopcountS = args.get("loopcount");
03                if (loopcountS != null)
04                    loopcount = Integer.parseInt(loopcountS);
05                if (args.getNum() < 1)
06                    return new JSTKResult(null, false, "No command specified.");
07
08                // Setup command for execution in loop.
09                String cmdString = args.get(0);
10                String[] cmdargs = new String[2 + args.getNum() - 1];
11                cmdargs[0] = "-sessionid";
12                cmdargs[1] = args.get("sessionid");
13                for (int i = 1; i < args.getNum(); i++){
14                    cmdargs[i+1] = args.get(i);
15                }
16
17                JSTKCommand cmd = (JSTKCommand)cmds.get(cmdString);
18                if (cmd == null)    // Unknown command.
19                    return new JSTKResult(null, false, "Unknown Command: " + cmdString);
20
21                JSTKOptions opts = new JSTKOptions();
22                opts.parse(cmdargs, 0);
23                JSTKResult result = (JSTKResult)cmd.execute(opts);
24
25                long ts = System.currentTimeMillis();
26                for (int i = 0; i < loopcount; i++)
27                    cmd.execute(opts);
28                long te = System.currentTimeMillis();
29
30                StringBuffer sb = new StringBuffer();
31                sb.append(result.getText() + "\n");
32                sb.append("Elapsed Time for " + loopcount + " invocations: " + (te - ts) + " millisecs.");
33                return new JSTKResult(null, true, sb.toString());
34            } catch (Exception e){
35                return new JSTKResult(null, false ,"time failed. Exception: " + e);
36            }
37        }
38    }
39
40    public static File createFile(String name, String curDir) throws IOException {
41        File f = new File(name);
42        if (!name.equalsIgnoreCase(f.getCanonicalPath()))   // name not absolute.
43            f = new File(curDir, name);
44        return f;
45    }
46
47    public static String getCurDir(JSTKArgs args){
48        String sessId = args.get("sessionid");
49        if (sessId == null)
50            return null;
51        SessionInfo sessInfo = (SessionInfo)sessionTable.get(sessId);
52        if (sessInfo == null)
53            return null;
54        return sessInfo.curDir;
55    }
56
57    public static void setCurDir(JSTKArgs args, String curDir){
58        String sessId = args.get("sessionid");
59        if (sessId == null)
60            return;
61        SessionInfo sessInfo = (SessionInfo)sessionTable.get(sessId);
62        if (sessInfo == null)
63            return;
64        sessInfo.curDir = curDir;
65    }
66
67    public static String getHomeDir(JSTKArgs args){
68        String sessId = args.get("sessionid");
69        if (sessId == null)
70            return null;
71        SessionInfo sessInfo = (SessionInfo)sessionTable.get(sessId);
72        if (sessInfo == null)
73            return null;
74        return sessInfo.homeDir;
75    }
76
77    public static final Logger logger = Logger.getLogger("org.jstk.access");
78    static {
79        cmds.put("echo", new EchoCommand());
80        cmds.put("pwd", new PWDCommand());
81        cmds.put("ls", new LSCommand());
82        cmds.put("cd", new CDCommand());
83        cmds.put("md", new MkdirCommand());
84        cmds.put("rm", new RMCommand());
85        cmds.put("cat", new CatCommand());
86        cmds.put("cp", new CpCommand());
87        cmds.put("show", new ShowCommand());
88        cmds.put("whoami", new WhoAmICommand());
89        cmds.put("time", new TimeCommand());
90        cmds.put("quit", new QuitCommand());
91        cmds.put("exit", new QuitCommand());
92    }
93
94    public JSTKShellServer(){
95        super();
96
97    }
98
99    public String progName(){
00        String progName = "java org.jstk.access.JSTKShell";
01        return progName;
02    }
03    public String briefDescription(){
04        return "a minimal shell to demostrate Java Access Control features";
05    }
06
07    public void setSubject(Subject sub){
08        // Do nothing.
09    }
10    public String createSession() throws Exception {
11        String sessId = "sess_" + (++curId);
12        SessionInfo sessInfo = new SessionInfo();
13        sessionTable.put(sessId, sessInfo);
14        return sessId;
15    }
16
17    public void destroySession(String sessId) throws Exception {
18        sessionTable.remove(sessId);
19    }
20
21    public String execCommand(String[] args) throws Exception {
22        try {
23            JSTKOptions opts = new JSTKOptions();
24            if (args.length < 1){       // No argument. Print help message.
25                return usageString();
26            }
27            String cmdString = args[0];
28            if (cmdString.equals("-h") || cmdString.equals("help") || cmdString.equals("-?")){
29                return usageString();
30            }
31
32            JSTKCommand cmd = (JSTKCommand)cmds.get(cmdString);
33            if (cmd == null){   // Unknown command.
34                System.out.println("Unknown Command: " + cmdString);
35                return usageString();
36            }
37
38            if (args.length > 1 && (args[1].equals("-h") || args[1].equals("help") || args[1].equals("-?"))){
39                return cmdUsageString(cmd, cmdString);
40            }
41
42            opts.parse(args, 1);
43
44            JSTKResult result = (JSTKResult)cmd.execute(opts);
45            return result.getText();
46        } catch (SecurityException se){
47            return "Security Violation: " + se;
48        }
49    }
50}