summaryrefslogtreecommitdiffstats
path: root/tdehtml/java/org/kde/kjas/server/KJASSecurityManager.java
blob: 0525bba0c0e60775a3ca96cb465c7bc6dea70c06 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
package org.kde.kjas.server;

import java.security.*;
import java.security.cert.*;
import java.net.*;
import java.util.*;


public class KJASSecurityManager extends SecurityManager
{
    static Hashtable confirmRequests = new Hashtable();
    static int confirmId = 0;
    Hashtable grantedPermissions = new Hashtable();
    HashSet grantAllPermissions = new HashSet();
    HashSet rejectAllPermissions = new HashSet();

    private static final char [] base64table = {
      'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
      'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
      'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
      'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
    };
    static String encode64( byte [] data)
    {
        StringBuffer buf = new StringBuffer( 4*((data.length + 2)/3) );
        int i = 0, b1, b2, b3;
        while (i < data.length - 2) {
            b1 = data[i++];
            b2 = data[i++];
            b3 = data[i++];
            buf.append( base64table[(b1 >>> 2) & 0x3F] );
            buf.append( base64table[((b1 << 4) & 0x30) | ((b2 >>> 4) & 0xF)] );
            buf.append( base64table[((b2 << 2) & 0x3C) | ((b3 >>> 6) & 0x03)] );
            buf.append( base64table[b3 & 0x3F] );
        }
        if ( i < data.length ) {
            b1 = data[i++];
            buf.append( base64table[(b1 >>> 2) & 0x3F] );
            if ( i < data.length ) {
                b2 = data[i++];
                buf.append( base64table[((b1 << 4) & 0x30) | ((b2 >>> 4) & 0xF)] );
                buf.append( base64table[(b2 << 2) & 0x3C] );
            } else {
                buf.append( base64table[(b1 << 4) & 0x30] );
                buf.append( "=" );
            }
            buf.append( '=' );
        }
        return buf.toString();
    }
    public KJASSecurityManager()
    {
    }
    /**
     * checks for an applets permission to access certain resources
     * currently, only a check for SocketPermission is done, that the
     * applet cannot connect to any other but the host, where it comes from.
     * Anything else seems to be handled automagically
     */
    public void checkPermission(Permission perm) throws SecurityException, NullPointerException {
        // ClassLoader cl = Thread.currentThread().getContextClassLoader();
        try {
            super.checkPermission(perm);
        } catch (SecurityException se) {
            // Don't annoy users with these
            if (/*perm instanceof java.lang.RuntimePermission || */
                    perm instanceof java.awt.AWTPermission)
                throw se;

            // Collect certificates
            HashSet signers = new HashSet();
            Class [] cls = getClassContext();
            for (int i = 1; i < cls.length; i++) {
                Object[] objs = cls[i].getSigners();
                if (objs != null && objs.length > 0) {
                    for (int j = 0; j < objs.length; j++)
                        if (objs[j] instanceof X509Certificate)
                            signers.add( ((X509Certificate) objs[j]) );
                }
            }
            Main.debug("Certificates " + signers.size() + " for " + perm);

            // Check granted/denied permission
            if ( grantAllPermissions.contains(signers) )
                return;
            if ( rejectAllPermissions.contains(signers) )
                throw se;
            Permissions permissions = (Permissions) grantedPermissions.get(signers);
            if (permissions != null && permissions.implies(perm))
                return;

            // Ok, ask user what to do
            String [] certs = new String[signers.size()];
            int certsnr = 0;
            for (Iterator i = signers.iterator(); i.hasNext(); ) {
                try {
                    certs[certsnr] = encode64( ((X509Certificate) i.next()).getEncoded() );
                    certsnr++;
                } catch (CertificateEncodingException cee) {}
            }
            if (certsnr == 0)
                throw se;
            String id = "" + confirmId++;
            confirmRequests.put(id, Thread.currentThread());
            Main.protocol.sendSecurityConfirm(certs, certsnr, perm.toString(), id);
            boolean granted = false;
            try {
                Thread.sleep(300000);
            } catch (InterruptedException ie) {
                if (((String) confirmRequests.get(id)).equals("yes")) {
                    granted = true;
                    permissions = (Permissions) grantedPermissions.get(signers);
                    if (permissions == null) {
                        permissions = new Permissions();
                        grantedPermissions.put(signers, permissions);
                    }
                    permissions.add(perm);
                } else if (((String) confirmRequests.get(id)).equals("grant")) {
                    grantAllPermissions.add( signers );
                    granted = true;
                } else if (((String) confirmRequests.get(id)).equals("reject")) {
                    rejectAllPermissions.add( signers );
                } // else "no", "nossl" or "invalid"
            } finally {
                confirmRequests.remove(id);
            }
            if (!granted) {
                Main.debug("Permission denied" + perm);
                throw se;
            }
        }
    }

    // keytool -genkey -keystore mystore -alias myalias
    // keytool -export -keystore mystore -alias myalias -file mycert
    // keytool -printcert -file mycert
    // keytool -import -keystore myotherstore -alias myalias -file mycert
    // jarsigner -keystore mystore myjar.jar myalias
    // jarsigner -verify -keystore myotherstore myjar.jar
    //
    // policy file (use policytool and check java.security):
    // keystore "file:myotherstore", "JKS"
    // grant signedBy "myalias"
    // {
    //     permission java.io.FilePermission "<<ALL FILES>>", "read"
    // }
    // 
    // java code:
    // KeyStore store = KeyStore.getInstance("JKS", "SUN");
    public void disabled___checkPermission(Permission perm) throws SecurityException, NullPointerException
    {
        // does not seem to work as expected, Problems with proxy - and it seems that the default
        // implementation already does all that well, what I wanted to do here.
        // It is likely that this method will hence disappear soon again.
        Object context = getSecurityContext();
        Thread thread = Thread.currentThread();
        if (perm instanceof SocketPermission) {
            // check if this is a connection back to the originating host
            // if not, fall through and call super.checkPermission
            // this gives normally access denied
            Main.debug("*** checkPermission " + perm + " in context=" + context + " Thread=" + thread);
            // use the context class loader to determine if this is one
            // of our applets
            ClassLoader contextClassLoader = thread.getContextClassLoader();
            Main.debug("*   ClassLoader=" + contextClassLoader);
            try {
                // try to cast ...
                KJASAppletClassLoader loader = (KJASAppletClassLoader)contextClassLoader;
                // ok. cast succeeded. Now get the codebase of the loader
                // because it contains the host name
                URL codebase = loader.getCodeBase();
                URL docbase = loader.getDocBase();
                Main.debug("*   Class Loader docbase=" + docbase + " codebase=" + codebase);
                String hostname = perm.getName();
                // extract the hostname from the permission name
                // which is something like "some.host.domain:XX"
                // with XX as the port number
                int colonIdx = hostname.indexOf(':');
                if (colonIdx > 0) {
                    // strip of the port
                    hostname = hostname.substring(0, colonIdx);
                }
                // Main.info("Checking " + hostname + "<->" + codebase.getHost());
                
                if (hostsAreEqual(hostname, codebase.getHost())) {
                    // ok, host matches
                    String actions = perm.getActions();
                    // just check if listen is specified which we do not want
                    // to allow
                    if (actions != null && actions.indexOf("listen") >= 0) {
                        Main.debug("*   Listen is not allowed.");
                    } else {
                        // ok, just return and throw _no_ exception
                        Main.debug("*   Hostname equals. Permission granted.");
                        return;
                    }
                } else {
                    Main.info("Host mismatch: " + perm + " != " + codebase.getHost());
                }
            } catch (ClassCastException e) {
                Main.debug("*   ClassLoader is not a KJASAppletClassLoader");
            }
            Main.debug("*   Fall through to super.checkPermission()");
        }
        super.checkPermission(perm);
    }
    
    private static final boolean hostsAreEqual(String host1, String host2) {
        if (host1 == null || host2 == null) {
            return false;
        }
        if (host1.length() == 0 || host2.length() == 0) {
            return false;
        }
        if (host1.equalsIgnoreCase(host2)) {
            return true;
        }
       
        if ( Main.proxyHost != null && Main.proxyPort != 0) {
            // if we use a proxy, we certainly cannot use DNS
            return false;
        }

        InetAddress inet1=null, inet2=null;
        try {
            inet1 = InetAddress.getByName(host1);
        } catch (UnknownHostException e) {
            Main.kjas_err("Unknown host:" + host1, e);
            return false;
        }
        try {
            inet2 = InetAddress.getByName(host2);
        } catch (UnknownHostException e) {
            Main.kjas_err("Unknown host:" + host2, e);
            return false;
        }
        if (inet1.equals(inet2)) {
            return true;
        }       
        return false;
    }
}