alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2004 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans;

import java.io.FileDescriptor;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.URL;
import java.net.MalformedURLException;
import java.security.*;
import java.util.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/** NetBeans security manager implementation.
* @author Ales Novak, Jesse Glick
*/
public class TopSecurityManager extends SecurityManager {

    private static boolean check = !Boolean.getBoolean("netbeans.security.nocheck"); // NOI18N

    private Permission allPermission;
    
    /* JVMPI sometimes deadlocks sync getForeignClassLoader
        and Class.forName
    */
    private static final Class classLoaderClass = ClassLoader.class;
    private static final Class URLClass = URL.class;
    private static final Class runtimePermissionClass = RuntimePermission.class;
    private static final Class accessControllerClass = AccessController.class;

    private static List delegates = new ArrayList(); // List
    /** Register a delegate security manager that can handle some checks for us.
     * Currently only checkExit and checkTopLevelWindow are supported.
     * @param sm the delegate to register
     * @throws SecurityException without RuntimePermission "TopSecurityManager.register"
     */
    public static void register(SecurityManager sm) throws SecurityException {
/*        if (check) {
            try {
                AccessController.checkPermission(new RuntimePermission("TopSecurityManager.register")); // NOI18N
            } catch (SecurityException se) {
                // Something is probably wrong; debug it better.
                ProtectionDomain pd = sm.getClass().getProtectionDomain();
                CodeSource cs = pd.getCodeSource();
                System.err.println("Code source of attempted secman: " + (cs != null ? cs.getLocation().toExternalForm() : "")); // NOI18N
                System.err.println("Its permissions: " + pd); // NOI18N
                throw se;
            }
        }
*/
        synchronized (delegates) {
            if (delegates.contains(sm)) throw new SecurityException();
            delegates.add(sm);
        }
    }
    /** Unregister a delegate security manager.
     * @param sm the delegate to unregister
     * @throws SecurityException without RuntimePermission "TopSecurityManager.unregister"
     */
    public static void unregister(SecurityManager sm) throws SecurityException {
/*        if (check) {
            AccessController.checkPermission(new RuntimePermission("TopSecurityManager.unregister")); // NOI18N
        }
*/
        synchronized (delegates) {
            if (!delegates.contains(sm)) throw new SecurityException();
            delegates.remove(sm);
        }
    }

    /**
    * constructs new TopSecurityManager
    */
    public TopSecurityManager () {
        allPermission = new AllPermission();
    }

    public void checkExit(int status) throws SecurityException {
        if (! check) {
            return;
        }
        
        synchronized (delegates) {
            Iterator it = delegates.iterator();
            while (it.hasNext()) {
                ((SecurityManager)it.next()).checkExit(status);
            }
        }
        
        PrivilegedCheck.checkExit(status, this);
    }


    private static boolean officialExit = false;
    /** Can be called from core classes to exit the system.
     * Direct calls to System.exit will not be honored, for safety.
     * @param status the status code to exit with
     * @see "#20751"
     */
    public static void exit(int status) {
        officialExit = true;
        System.exit(status);
    }

    final void checkExitImpl(int status, AccessControlContext acc) throws SecurityException {             
        if (!officialExit) {
            throw new ExitSecurityException("Illegal attempt to exit early"); // NOI18N
        }

        super.checkExit(status);
    }

    public boolean checkTopLevelWindow(Object window) {
        synchronized (delegates) {
            Iterator it = delegates.iterator();
            while (it.hasNext()) {
                ((SecurityManager)it.next()).checkTopLevelWindow(window);
            }
        }
        
        return super.checkTopLevelWindow(window);
    }

    /* XXX probably unnecessary:
    // Hack against permissions of Launcher$AppLoader.
    public void checkPackageAccess(String pckg) {
        if (pckg == null) return;
        if (pckg.startsWith("sun.")) { // NOI18N
            if (inClazz("sun.misc.Launcher") || inClazz("java.lang.Class")) { // NOI18N
                return;
            }
        }
        super.checkPackageAccess(pckg);
    }

    private boolean inClazz(String s) {
        Class[] classes = getClassContext();
        int i = 0;
        for (; (i < classes.length) && (classes[i] == TopSecurityManager.class); i++);
        if (i == classes.length) {
            return false;
        }
        return classes[i].getName().startsWith(s);
    }
     */

    /** Performance - all props accessible */
    public final void checkPropertyAccess(String x) {
        if ("netbeans.debug.exceptions".equals(x)) { // NOI18N
            // Get rid of this old system property.
            Class[] ctxt = getClassContext();
            for (int i = 0; i < ctxt.length; i++) {
                Class c = ctxt[i];
                if (c != TopSecurityManager.class &&
                        c != System.class &&
                        c != Boolean.class) {
                    String n = c.getName();
                    synchronized (warnedClassesNDE) {
                        if (warnedClassesNDE.add(n)) {
                            System.err.println("Warning: use of system property netbeans.debug.exceptions in " + n + " has been obsoleted in favor of ErrorManager"); // NOI18N
                        }
                    }
                    break;
                }
            }
        }
        if ("netbeans.home".equals(x)) { // NOI18N
            // Get rid of this old system property.
            Class[] ctxt = getClassContext();
            for (int i = 0; i < ctxt.length; i++) {
                Class c = ctxt[i];
                if (c != TopSecurityManager.class &&
                        c != System.class &&
                        c != Boolean.class) {
                    String n = c.getName();
                    synchronized (warnedClassesNH) {
                        if (warnedClassesNH.add(n)) {
                            System.err.println("Warning: use of system property netbeans.home in " + n + " has been obsoleted in favor of InstalledFileLocator"); // NOI18N
                        }
                    }
                    break;
                }
            }
        }
        
        if ("javax.xml.parsers.SAXParserFactory".equals(x)) {
            if (Thread.currentThread().getContextClassLoader().getResource(
                    "org/netbeans/core/xml/SAXFactoryImpl.class") != null) return;
            throw new SecurityException ("");            
        }
        
        if ("javax.xml.parsers.DocumentBuilderFactory".equals(x)) {
            if (Thread.currentThread().getContextClassLoader().getResource(
                    "org/netbeans/core/xml/DOMFactoryImpl.class") != null) return;
            throw new SecurityException ("");            
        }
        
        return;
    }
    private final Set warnedClassesNDE = new HashSet(25); // Set
    private static final Set warnedClassesNH = new HashSet(25); // Set
    static {
        warnedClassesNH.add ("org.netbeans.core.LookupCache"); // NOI18N
        warnedClassesNH.add ("org.netbeans.updater.UpdateTracking"); // NOI18N
        warnedClassesNH.add("org.netbeans.core.ui.ProductInformationPanel"); // #47429; NOI18N
    }

    /* ----------------- private methods ------------- */

    /**
     * The method is empty. This is not "secure", but on the other hand,
     * it reduces performance penalty of startup about 10%
     */
    public void checkRead(String file) {
        // XXX reconsider!
    }
    
    public void checkRead(FileDescriptor fd) {
    }

    public void checkWrite(FileDescriptor fd) {
    }

    /** The method has awful performance in super class */
    public void checkDelete(String file) {
        try {
            checkPermission(allPermission);
            return;
        } catch (SecurityException e) {
            super.checkDelete(file);
        }
    }
    /** The method has awful performance in super class */
    public void checkWrite(String file) {
        try {
            checkPermission(allPermission);
            return;
        } catch (SecurityException e) {
            super.checkWrite(file);
        }
    }
    
    /** Checks connect */
    public void checkConnect(String host, int port) {
        if (! check) {
            return;
        }
        
        try {
            checkPermission(allPermission);
            return;
        } catch (SecurityException e) {
        }
        
        try {
            super.checkConnect(host, port);
            return;
        } catch (SecurityException e) {
        }
        
        PrivilegedCheck.checkConnect(host, port, this);
    }
     
    final void checkConnectImpl(String host, int port) {
        Class insecure = getInsecureClass();
        if (insecure != null) {  
            URL ctx = getClassURL(insecure);
            if (ctx != null) {
                try {
                    String fromHost = ctx.getHost();
                    InetAddress ia2 = InetAddress.getByName(host);
                    InetAddress ia3 = InetAddress.getByName(fromHost);
                    if (ia2.equals(ia3)) {
                        return;
                    }
                } catch (UnknownHostException e) { // ignore
                    e.printStackTrace();
                }
            }
            throw new SecurityException();
        }
    }

    public void checkConnect(String s, int port, Object context) {
        checkConnect(s, port);
    }

    public void checkPermission(Permission perm) {
        checkSetSecurityManager(perm);
        
        //
        // part of makeSwingUseSpecialClipboard that makes it work on
        // JDK 1.5
        //
        if (perm instanceof java.awt.AWTPermission) {
            if ("accessClipboard".equals (perm.getName ())) { // NOI18N
                if (CLIPBOARD_FORBIDDEN.get () != null) {
                    CLIPBOARD_FORBIDDEN.set (this);
                    throw new SecurityException ();
                } else {
                    checkWhetherAccessedFromSwingTransfer ();
                }
            }
        }
        return;
    }
    
    public void checkPermission(Permission perm, Object context) {
        checkSetSecurityManager(perm);
        return;
    }
    
    /** Prohibits to set another SecurityManager */
    private static void checkSetSecurityManager(Permission perm) {
        if (runtimePermissionClass.isInstance(perm)) {
            if ("setSecurityManager".equals(perm.getName())) { // NOI18N - hardcoded in java.lang
                throw new SecurityException();
            }
        }
    }

//    
//    public void checkMemberAccess(Class clazz, int which) {
//        if ((which == java.lang.reflect.Member.PUBLIC) ||
//                javax.swing.text.JTextComponent.class.isAssignableFrom(clazz)) {
//            return;
//        } else {
//            super.checkMemberAccess(clazz, which);
//        }
//    }
//
    private Class getInsecureClass() {

        Class[] ctx = getClassContext();
        ClassLoader cloader;
        boolean firstACClass = false;

LOOP:   for (int i = 0; i < ctx.length; i++) {

            if (ctx[i] == accessControllerClass) {
                // privileged action is on the stack before an untrusted class loader
                // #3950
                if (firstACClass) {
                    return null;
                } else {
                    firstACClass = true;
                    continue LOOP;
                }
            } else if ((cloader = ctx[i].getClassLoader()) != null) {
                final Class hisClass = cloader.getClass();

                if (isSecureClass(ctx[i])) {
                    if (classLoaderClass.isAssignableFrom(ctx[i])) {
                        return null;
                    } else {
                        // OK process next one
                        continue LOOP;
                    }
                }

                return ctx[i];
            } else if (classLoaderClass.isAssignableFrom(ctx[i])) { // cloader == null
                return null; // foreign classloader wants to do work...
            }
        }

        return null;
    }

    /** Checks if the class is loaded through the nbfs URL */
    static boolean isSecureClass(final Class clazz) {
        URL source = getClassURL(clazz);
        if (source != null) {
            return isSecureProtocol(source.getProtocol());
        } else {
            return true;
        }
    }
    
    /** @return a protocol through which was the class loaded (file://...) or null
    */
    static URL getClassURL(Class clazz) {
        java.security.CodeSource cs = clazz.getProtectionDomain().getCodeSource();                                                     
        if (cs != null) {
            URL url = cs.getLocation();
            return url;
        } else { // PROXY CLASS?
            return null;
        }
    }

    static Field getUrlField(Class clazz) {
        if (urlField == null) {
            try {
                Field[] fds = clazz.getDeclaredFields();
                for (int i = 0; i < fds.length; i++) {
                    if (fds[i].getType() == URLClass) {
                        fds[i].setAccessible(true);
                        urlField = fds[i];
                        break;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return urlField;
    }

    private static Field urlField;

    /** @return Boolean.TRUE iff the string is a safe protocol (file, nbfs, ...) */
    static boolean isSecureProtocol(String protocol) {
        if (protocol.equals("http") || // NOI18N
            protocol.equals("ftp") || // NOI18N
            protocol.equals("rmi")) { // NOI18N
            return false;
        } else {
            return true;
        }
    }

    // Workaround for bug 
    // 
    // http://developer.java.sun.com/developer/bugParade/bugs/4818143.html
    //
    // sun.awt.datatransfer.ClipboardTransferable.getClipboardData() can hang
    // for very long time (maxlong == eternity).  We tries to avoid the hang by
    // access the system clipboard from a separate thread.  If the hang happens
    // the thread will wait for the system clipboard forever but not the whole
    // IDE.  See also NbClipboard
    
    private static ThreadLocal CLIPBOARD_FORBIDDEN = new ThreadLocal ();
    
    /** Convinces Swing components that they should use special clipboard
     * and not Toolkit.getSystemClipboard.
     *
     * @param clip clipboard to use
     */
    public static void makeSwingUseSpecialClipboard (java.awt.datatransfer.Clipboard clip) {
        try {
            javax.swing.JComponent source = new javax.swing.JPanel ();
            CLIPBOARD_FORBIDDEN.set (clip);
            javax.swing.TransferHandler.getPasteAction ().actionPerformed (
                new java.awt.event.ActionEvent (source, 0, "")
            );
            javax.swing.TransferHandler.getCopyAction ().actionPerformed (
                new java.awt.event.ActionEvent (source, 0, "")
            );
            javax.swing.TransferHandler.getCutAction ().actionPerformed (
                new java.awt.event.ActionEvent (source, 0, "")
            );
            if (! (CLIPBOARD_FORBIDDEN.get () instanceof TopSecurityManager) ) {
                System.err.println("Cannot install our clipboard to swing components, TopSecurityManager is not the security manager"); // NOI18N
                return;
            }

            Class appContextClass = Class.forName ("sun.awt.AppContext"); // NOI18N
            Method getAppContext = appContextClass.getMethod ("getAppContext", new Class[0]); // NOI18N
            Object appContext = getAppContext.invoke (null, new Object[0]);
            Class c = appContext.getClass();
            
            Class actionClass = javax.swing.TransferHandler.getCopyAction ().getClass ();
            java.lang.reflect.Field sandboxKeyField = actionClass.getDeclaredField ("SandboxClipboardKey"); // NOI18N
            sandboxKeyField.setAccessible (true);
            Object value = sandboxKeyField.get (null);
            
            Method put = appContextClass.getMethod ("put", new Class[] { Object.class, Object.class }); // NOI18N
            put.invoke (appContext, new Object[] { value, clip });
        } catch (ThreadDeath ex) {
            throw ex;
        } catch (Throwable t) {
            t.printStackTrace();
        } finally {
            CLIPBOARD_FORBIDDEN.set (null);
        }
    }
    
    /** the class that needs to be non accessible */
    private static Class transferHandlerTransferAction;
    /** Throws exception if accessed from javax.swing.TransferHandler class
     */
    private void checkWhetherAccessedFromSwingTransfer () throws SecurityException {
        if (transferHandlerTransferAction == null) {
            try {
                transferHandlerTransferAction = Class.forName ("javax.swing.TransferHandler$TransferAction"); // NOI18N
            } catch (ClassNotFoundException ex) {
                ex.printStackTrace();
                throw new SecurityException (ex.getMessage ());
            }
        }
        Class[] arr = getClassContext ();
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == transferHandlerTransferAction) {
                throw new SecurityException ("All swing access to clipboard should be redirected to ExClipboard"); // NOI18N
            }
        }
    }


    private static final class PrivilegedCheck implements PrivilegedExceptionAction {
        int action;
        TopSecurityManager tsm;
        
        // exit
        int status;
        AccessControlContext acc;

        // connect
        String host;
        int port;
        
        
        public PrivilegedCheck(int action, TopSecurityManager tsm) {
            this.action = action;
            this.tsm = tsm;
            
            if (action == 0) {
                acc = AccessController.getContext();
            }
        }
        
        public Object run() throws Exception {
            switch (action) {
                case 0 : 
                    tsm.checkExitImpl(status, acc);
                    break;
                case 1 :
                    tsm.checkConnectImpl(host, port);
                    break;
                default :
            }
            return null;
        }
        
        static void checkExit(int status, TopSecurityManager tsm) {
            PrivilegedCheck pea = new PrivilegedCheck(0, tsm);
            pea.status = status;
            check(pea);
        }
        
        static void checkConnect(String host, int port, TopSecurityManager tsm) {
            PrivilegedCheck pea = new PrivilegedCheck(1, tsm);
            pea.host = host;
            pea.port = port;
            check(pea);
        }
        
        private static void check(PrivilegedCheck action) {
            try {
                AccessController.doPrivileged(action);
            } catch (PrivilegedActionException e) {
                Exception orig = e.getException();
                if (orig instanceof RuntimeException) {
                    throw ((RuntimeException) orig);
                }
                orig.printStackTrace();
            }
        }
    }
    
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.