/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* This class represents access to a network via sockets.
* A SocketPermission consists of a
* host specification and a set of "actions" specifying ways to
* connect to that host. The host is specified as
* <pre>
* host = (hostname | IPv4address | iPv6reference) [:portrange]
* portrange = portnumber | -portnumber | portnumber-[portnumber]
* </pre>
* The host is expressed as a DNS name, as a numerical IP address,
* or as "localhost" (for the local machine).
* The wildcard "*" may be included once in a DNS name host
* specification. If it is included, it must be in the leftmost
* position, as in "*.sun.com".
* <p>
* The format of the IPv6reference should follow that specified in <a
* href="http://www.ietf.org/rfc/rfc2732.txt"><i>RFC 2732: Format
* for Literal IPv6 Addresses in URLs</i></a>:
* <pre>
* ipv6reference = "[" IPv6address "]"
*</pre>
* For example, you can construct a SocketPermission instance
* as the following:
* <pre>
* String hostAddress = inetaddress.getHostAddress();
* if (inetaddress instanceof Inet6Address) {
* sp = new SocketPermission("[" + hostAddress + "]:" + port, action);
* } else {
* sp = new SocketPermission(hostAddress + ":" + port, action);
* }
* </pre>
* or
* <pre>
* String host = url.getHost();
* sp = new SocketPermission(host + ":" + port, action);
* </pre>
* <p>
* The <A HREF="Inet6Address.html#lform">full uncompressed form</A> of
* an IPv6 literal address is also valid.
* <p>
* The port or portrange is optional. A port specification of the
* form "N-", where <i>N</i> is a port number, signifies all ports
* numbered <i>N</i> and above, while a specification of the
* form "-N" indicates all ports numbered <i>N</i> and below.
* <p>
* The possible ways to connect to the host are
* <pre>
* accept
* connect
* listen
* resolve
* </pre>
* The "listen" action is only meaningful when used with "localhost".
* The "resolve" action is implied when any of the other actions are present.
* <P>
* The actions string is converted to lowercase before processing.
* <p>As an example of the creation and meaning of SocketPermissions,
* note that if the following permission:
*
* <pre>
* p1 = new SocketPermission("puffin.eng.sun.com:7777", "connect,accept");
* </pre>
*
* is granted to some code, it allows that code to connect to port 7777 on
* <code>puffin.eng.sun.com</code>, and to accept connections on that port.
*
* <p>Similarly, if the following permission:
*
* <pre>
* p2 = new SocketPermission("localhost:1024-", "accept,connect,listen");
* </pre>
*
* is granted to some code, it allows that code to
* accept connections on, connect to, or listen on any port between
* 1024 and 65535 on the local host.
*
* <p>Note: Granting code permission to accept or make connections to remote
* hosts may be dangerous because malevolent code can then more easily
* transfer and share confidential data among parties who may not
* otherwise have access to the data.
*
* @see java.security.Permissions
* @see SocketPermission
*
*
* @author Marianne Mueller
* @author Roland Schemers
*
* @serial exclude
*/
{
/**
* Connect to host:port
*/
/**
* Listen on host:port
*/
/**
* Accept a connection from host:port
*/
/**
* Resolve DNS queries
*/
/**
* No actions
*/
/**
* All actions
*/
// various port constants
// the actions mask
private transient int mask;
/**
* the actions string.
*
* @serial
*/
// created and re-used in the getAction function.
// hostname part as it is passed
// the canonical name of the host
// in the case of "*.foo.com", cname is ".foo.com".
// all the IP addresses of the host
// true if the hostname is a wildcard (e.g. "*.sun.com")
private transient boolean wildcard;
// true if we were initialized with a single numeric IP address
private transient boolean init_with_ip;
// used for implies when the delayed lookup has already failed
private transient boolean invalid;
// port range on host
private transient int[] portrange;
private transient boolean defaultDeny = false;
// true if this SocketPermission represents a hostname
// that failed our reverse mapping heuristic test
private transient boolean untrusted;
private transient boolean trusted;
// true if the sun.net.trustNameService system property is set
private static boolean trustNameService;
private static boolean debugInit = false;
static {
}
{
if (!debugInit) {
debugInit = true;
}
return debug;
}
/**
* Creates a new SocketPermission object with the specified actions.
* The host is expressed as a DNS name, or as a numerical IP address.
* Optionally, a port or a portrange may be supplied (separated
* from the DNS name or IP address by a colon).
* <p>
* To specify the local machine, use "localhost" as the <i>host</i>.
* Also note: An empty <i>host</i> String ("") is equivalent to "localhost".
* <p>
* The <i>actions</i> parameter contains a comma-separated list of the
* actions granted for the specified host (and port(s)). Possible actions are
* "connect", "listen", "accept", "resolve", or
* any combination of those. "resolve" is automatically added
* when any of the other three are specified.
* <p>
* Examples of SocketPermission instantiation are the following:
* <pre>
* nr = new SocketPermission("www.catalog.com", "connect");
* nr = new SocketPermission("www.sun.com:80", "connect");
* nr = new SocketPermission("*.sun.com", "connect");
* nr = new SocketPermission("*.edu", "resolve");
* nr = new SocketPermission("204.160.241.0", "connect");
* nr = new SocketPermission("localhost:1024-65535", "listen");
* nr = new SocketPermission("204.160.241.0:1024-65535", "connect");
* </pre>
*
* @param host the hostname or IPaddress of the computer, optionally
* including a colon followed by a port or port range.
* @param action the action string.
*/
// name initialized to getHost(host); NPE detected in getHost()
}
// name initialized to getHost(host); NPE detected in getHost()
}
private void setDeny() {
defaultDeny = true;
}
{
return "localhost";
} else {
/* IPv6 literal address used in this context should follow
* the format specified in RFC 2732;
* if not, we try to solve the unambiguous case
*/
int ind;
/* More than one ":", meaning IPv6 address is not
* in RFC 2732 format;
* We will rectify user errors for all unambiguious cases
*/
if (tokens == 9) {
// IPv6 address followed by port
// IPv6 address only, not followed by port
} else {
// could be ambiguous
throw new IllegalArgumentException("Ambiguous"+
" hostport part");
}
}
}
return host;
}
}
throws Exception
{
}
if (dash == -1) {
return new int[] {p, p};
} else {
int l,h;
l = PORT_MIN;
} else {
}
h = PORT_MAX;
} else {
}
if (l < 0 || h < 0 || h<l)
throw new IllegalArgumentException("invalid port range");
return new int[] {l, h};
}
}
/**
* Initialize the SocketPermission object. We don't do any DNS lookups
* as this point, instead we hold off until the implies method is
* called.
*/
// Set the integer mask that represents the actions
throw new IllegalArgumentException("invalid actions mask");
// always OR in RESOLVE if we allow any of the others
// Parse the host name. A name has up to three components, the
// hostname, a port number, or two numbers representing a port
// range. "www.sun.com:8080-9090" is a valid host name.
// With IPv6 an address can be 2010:836B:4179::836B:4179
// An IPv6 address needs to be enclose in []
// For ex: [2010:836B:4179::836B:4179]:8080-9090
// Refer to RFC 2732 for more information.
int rb = 0 ;
int sep = -1;
start = 1;
if (rb != -1) {
} else {
throw new
}
} else {
start = 0;
if (sep != -1) {
}
}
if (sep != -1) {
try {
} catch (Exception e) {
throw new
}
} else {
}
// is this a domain wildcard specification
throw new
IllegalArgumentException("invalid host wildcard specification");
wildcard = true;
cname = "";
} else {
throw new
IllegalArgumentException("invalid host wildcard specification");
}
return;
} else {
// see if we are being initialized with an IP address.
}
try {
new InetAddress[]
init_with_ip = true;
} catch (UnknownHostException uhe) {
// this shouldn't happen
invalid = true;
}
}
}
}
}
}
/**
* Convert an action string to an integer actions mask.
*
* @param action the action string
* @return the action mask
*/
throw new NullPointerException("action can't be null");
}
throw new IllegalArgumentException("action can't be empty");
}
// Check against use of constants (used heavily within the JDK)
return RESOLVE;
return CONNECT;
return LISTEN;
return ACCEPT;
}
char[] a = action.toCharArray();
int i = a.length - 1;
if (i < 0)
return mask;
while (i != -1) {
char c;
// skip whitespace
while ((i!=-1) && ((c = a[i]) == ' ' ||
c == '\r' ||
c == '\n' ||
c == '\f' ||
c == '\t'))
i--;
// check for the known strings
int matchlen;
if (i >= 6 && (a[i-6] == 'c' || a[i-6] == 'C') &&
(a[i-5] == 'o' || a[i-5] == 'O') &&
(a[i-4] == 'n' || a[i-4] == 'N') &&
(a[i-3] == 'n' || a[i-3] == 'N') &&
(a[i-2] == 'e' || a[i-2] == 'E') &&
(a[i-1] == 'c' || a[i-1] == 'C') &&
(a[i] == 't' || a[i] == 'T'))
{
matchlen = 7;
} else if (i >= 6 && (a[i-6] == 'r' || a[i-6] == 'R') &&
(a[i-5] == 'e' || a[i-5] == 'E') &&
(a[i-4] == 's' || a[i-4] == 'S') &&
(a[i-3] == 'o' || a[i-3] == 'O') &&
(a[i-2] == 'l' || a[i-2] == 'L') &&
(a[i-1] == 'v' || a[i-1] == 'V') &&
(a[i] == 'e' || a[i] == 'E'))
{
matchlen = 7;
} else if (i >= 5 && (a[i-5] == 'l' || a[i-5] == 'L') &&
(a[i-4] == 'i' || a[i-4] == 'I') &&
(a[i-3] == 's' || a[i-3] == 'S') &&
(a[i-2] == 't' || a[i-2] == 'T') &&
(a[i-1] == 'e' || a[i-1] == 'E') &&
(a[i] == 'n' || a[i] == 'N'))
{
matchlen = 6;
} else if (i >= 5 && (a[i-5] == 'a' || a[i-5] == 'A') &&
(a[i-4] == 'c' || a[i-4] == 'C') &&
(a[i-3] == 'c' || a[i-3] == 'C') &&
(a[i-2] == 'e' || a[i-2] == 'E') &&
(a[i-1] == 'p' || a[i-1] == 'P') &&
(a[i] == 't' || a[i] == 'T'))
{
matchlen = 6;
} else {
// parse error
throw new IllegalArgumentException(
"invalid permission: " + action);
}
// make sure we didn't just match the tail of a word
// like "ackbarfaccept". Also, skip to the comma.
boolean seencomma = false;
switch(a[i-matchlen]) {
case ',':
seencomma = true;
/*FALLTHROUGH*/
case ' ': case '\r': case '\n':
case '\f': case '\t':
break;
default:
throw new IllegalArgumentException(
"invalid permission: " + action);
}
i--;
}
// point i at the location of the comma minus one (or -1).
i -= matchlen;
}
return mask;
}
private boolean isUntrusted()
throws UnknownHostException
{
if (trusted) return false;
try {
if (!trustNameService && (defaultDeny ||
this.getCanonName();
}
// Last chance
untrusted = true;
debug.println("socket access restriction: proxied host " + "(" + addresses[0] + ")" + " does not match " + cname + " from reverse lookup");
}
return true;
}
}
trusted = true;
}
} catch (UnknownHostException uhe) {
invalid = true;
throw uhe;
}
return false;
}
/**
* attempt to get the fully qualified domain name
*
*/
void getCanonName()
throws UnknownHostException
{
// attempt to get the canonical name
try {
// first get the IP addresses if we don't have them yet
// this is because we need the IP address to then get
// FQDN.
getIP();
}
// we have to do this check, otherwise we might not
// get the fully qualified domain name
if (init_with_ip) {
} else {
getHostName(false).toLowerCase();
}
} catch (UnknownHostException uhe) {
invalid = true;
throw uhe;
}
}
if (a.startsWith(b) &&
return true;
}
}
}
else
return false;
}
try {
authHost = "auth." +
".in-addr.arpa";
// Following check seems unnecessary
// auth = InetAddress.getAllByName0(authHost, false)[0];
return true;
}
debug.println("socket access restriction: IP address of " + auth + " != " + InetAddress.getByAddress(addr));
}
} catch (UnknownHostException uhe) {
}
}
return false;
}
try {
for (int i = 15; i >= 0; i--) {
}
//auth = InetAddress.getAllByName0(authHost, false)[0];
return true;
debug.println("socket access restriction: IP address of " + auth + " != " + InetAddress.getByAddress(addr));
}
} catch (UnknownHostException uhe) {
}
}
return false;
}
/**
* get IP addresses. Sets invalid to true if we can't get them.
*
*/
void getIP()
throws UnknownHostException
{
try {
// now get all the IP addresses
// Literal IPv6 address
} else {
if (i == -1)
else {
}
}
} catch (UnknownHostException uhe) {
invalid = true;
throw uhe;
} catch (IndexOutOfBoundsException iobe) {
invalid = true;
throw new UnknownHostException(getName());
}
}
/**
* Checks if this socket permission object "implies" the
* specified permission.
* <P>
* More specifically, this method first ensures that all of the following
* are true (and returns false if any of them are not):<p>
* <ul>
* <li> <i>p</i> is an instanceof SocketPermission,<p>
* <li> <i>p</i>'s actions are a proper subset of this
* object's actions, and<p>
* <li> <i>p</i>'s port range is included in this port range. Note:
* port range is ignored when p only contains the action, 'resolve'.<p>
* </ul>
*
* Then <code>implies</code> checks each of the following, in order,
* and for each returns true if the stated condition is true:<p>
* <ul>
* <li> If this object was initialized with a single IP address and one of <i>p</i>'s
* IP addresses is equal to this object's IP address.<p>
* <li>If this object is a wildcard domain (such as *.sun.com), and
* <i>p</i>'s canonical name (the name without any preceding *)
* ends with this object's canonical host name. For example, *.sun.com
* implies *.eng.sun.com..<p>
* <li>If this object was not initialized with a single IP address, and one of this
* object's IP addresses equals one of <i>p</i>'s IP addresses.<p>
* <li>If this canonical name equals <i>p</i>'s canonical name.<p>
* </ul>
*
* If none of the above are true, <code>implies</code> returns false.
* @param p the permission to check against.
*
* @return true if the specified permission is implied by this object,
* false if not.
*/
int i,j;
if (!(p instanceof SocketPermission))
return false;
if (p == this)
return true;
}
/**
* Checks if the incoming Permission's action are a proper subset of
* the this object's actions.
* <P>
* Check, in the following order:
* <ul>
* <li> Checks that "p" is an instanceof a SocketPermission
* <li> Checks that "p"'s actions are a proper subset of the
* current object's actions.
* <li> Checks that "p"'s port range is included in this port range
* <li> If this object was initialized with an IP address, checks that
* one of "p"'s IP addresses is equal to this object's IP address.
* <li> If either object is a wildcard domain (i.e., "*.sun.com"),
* attempt to match based on the wildcard.
* <li> If this object was not initialized with an IP address, attempt
* to find a match based on the IP addresses in both objects.
* <li> Attempt to match on the canonical hostnames of both objects.
* </ul>
* @param p the incoming permission request
*
* @return true if "permission" is a proper subset of the current object,
* false if not.
*/
int i,j;
// check port range
return false;
}
}
// allow a "*" wildcard to always match anything
return true;
// return if either one of these NetPerm objects are invalid...
return compareHostnames(that);
}
try {
if (this.init_with_ip) { // we only check IP addresses
return false;
if (that.init_with_ip) {
} else {
}
return true;
}
}
// since "this" was initialized with an IP address, we
// don't check any other cases
return false;
}
// check and see if we have any wildcards...
// if they are both wildcards, return true iff
// that's cname ends with this cname (i.e., *.sun.com
// implies *.eng.sun.com)
// a non-wildcard can't imply a wildcard
return false;
// this is a wildcard, lets see if that's cname ends with
// it...
that.getCanonName();
}
}
// comapare IP addresses
this.getIP();
}
}
return true;
}
}
// XXX: if all else fails, compare hostnames?
// Do we really want this?
this.getCanonName();
}
that.getCanonName();
}
}
} catch (UnknownHostException uhe) {
return compareHostnames(that);
}
// make sure the first thing that is done here is to return
// false. If not, uncomment the return false in the above catch.
return false;
}
return false;
else
}
/**
* Checks two SocketPermission objects for equality.
* <P>
* @param obj the object to test for equality with this object.
*
* @return true if <i>obj</i> is a SocketPermission, and has the
* same hostname, port range, and actions as this
* SocketPermission object. However, port range will be ignored
* in the comparison if <i>obj</i> only contains the action, 'resolve'.
*/
if (obj == this)
return true;
if (! (obj instanceof SocketPermission))
return false;
//this is (overly?) complex!!!
// check the mask first
// now check the port range...
return false;
}
}
// short cut. This catches:
// "crypto" equal to "crypto", or
// "1.2.3.4" equal to "1.2.3.4.", or
// "*.edu" equal to "*.edu", but it
// does not catch "crypto" equal to
// "crypto.eng.sun.com".
return true;
}
// we now attempt to get the Canonical (FQDN) name and
// compare that. If this fails, about all we can do is return
// false.
try {
this.getCanonName();
that.getCanonName();
} catch (UnknownHostException uhe) {
return false;
}
return false;
}
return false;
}
/**
* Returns the hash code value for this object.
*
* @return a hash code value for this object.
*/
public int hashCode() {
/*
* If this SocketPermission was initialized with an IP address
* or a wildcard, use getName().hashCode(), otherwise use
* the hashCode() of the host name returned from
* java.net.InetAddress.getHostName method.
*/
if (init_with_ip || wildcard) {
}
try {
getCanonName();
} catch (UnknownHostException uhe) {
}
else
}
/**
* Return the current action mask.
*
* @return the actions mask.
*/
int getMask() {
return mask;
}
/**
* Returns the "canonical string representation" of the actions in the
* specified mask.
* Always returns present actions in the following order:
* connect, listen, accept, resolve.
*
* @param mask a specific integer action mask to translate into a string
* @return the canonical string representation of the actions
*/
{
boolean comma = false;
comma = true;
}
else comma = true;
}
else comma = true;
}
else comma = true;
}
}
/**
* Returns the canonical string representation of the actions.
* Always returns present actions in the following order:
* connect, listen, accept, resolve.
*
* @return the canonical string representation of the actions.
*/
{
return actions;
}
/**
* Returns a new PermissionCollection object for storing SocketPermission
* objects.
* <p>
* SocketPermission objects must be stored in a manner that allows them
* to be inserted into the collection in any order, but that also enables the
* PermissionCollection <code>implies</code>
* method to be implemented in an efficient (and consistent) manner.
*
* @return a new PermissionCollection object suitable for storing SocketPermissions.
*/
return new SocketPermissionCollection();
}
/**
* WriteObject is called to save the state of the SocketPermission
* to a stream. The actions are serialized, and the superclass
* takes care of the name.
*/
throws IOException
{
// Write out the actions. The superclass takes care of the name
// call getActions to make sure actions field is initialized
getActions();
s.defaultWriteObject();
}
/**
* readObject is called to restore the state of the SocketPermission from
* a stream.
*/
throws IOException, ClassNotFoundException
{
// Read in the action, then initialize the rest
s.defaultReadObject();
}
/*
public String toString()
{
StringBuffer s = new StringBuffer(super.toString() + "\n" +
"cname = " + cname + "\n" +
"wildcard = " + wildcard + "\n" +
"invalid = " + invalid + "\n" +
"portrange = " + portrange[0] + "," + portrange[1] + "\n");
if (addresses != null) for (int i=0; i<addresses.length; i++) {
s.append( addresses[i].getHostAddress());
s.append("\n");
} else {
s.append("(no addresses)\n");
}
return s.toString();
}
public static void main(String args[]) throws Exception {
SocketPermission this_ = new SocketPermission(args[0], "connect");
SocketPermission that_ = new SocketPermission(args[1], "connect");
System.out.println("-----\n");
System.out.println("this.implies(that) = " + this_.implies(that_));
System.out.println("-----\n");
System.out.println("this = "+this_);
System.out.println("-----\n");
System.out.println("that = "+that_);
System.out.println("-----\n");
SocketPermissionCollection nps = new SocketPermissionCollection();
nps.add(this_);
nps.add(new SocketPermission("www-leland.stanford.edu","connect"));
nps.add(new SocketPermission("www-sun.com","connect"));
System.out.println("nps.implies(that) = " + nps.implies(that_));
System.out.println("-----\n");
}
*/
}
/**
if (init'd with IP, key is IP as string)
if wildcard, its the wild card
else its the cname?
*
* @see java.security.Permission
* @see java.security.Permissions
* @see java.security.PermissionCollection
*
*
* @author Roland Schemers
*
* @serial include
*/
implements Serializable
{
// Not serialized; see serialization section at end of class
/**
* Create an empty SocketPermissions object.
*
*/
public SocketPermissionCollection() {
}
/**
* Adds a permission to the SocketPermissions. The key for the hash is
* the name in the case of wildcards, or all the IP addresses.
*
* @param permission the Permission object to add.
*
* @exception IllegalArgumentException - if the permission is not a
* SocketPermission
*
* @exception SecurityException - if this SocketPermissionCollection object
* has been marked readonly
*/
{
if (! (permission instanceof SocketPermission))
throw new IllegalArgumentException("invalid permission: "+
if (isReadOnly())
throw new SecurityException(
"attempt to add a Permission to a readonly PermissionCollection");
// optimization to ensure perms most likely to be tested
// show up early (4301064)
synchronized (this) {
}
}
/**
* Check and see if this collection of permissions implies the permissions
* expressed in "permission".
*
* @param p the Permission object to compare
*
* @return true if "permission" is a proper subset of a permission in
* the collection, false if not.
*/
{
if (! (permission instanceof SocketPermission))
return false;
int effective = 0;
synchronized (this) {
//System.out.println("implies "+np);
for (int i = 0; i < len; i++) {
//System.out.println(" trying "+x);
return true;
}
}
}
return false;
}
/**
* Returns an enumeration of all the SocketPermission objects in the
* container.
*
* @return an enumeration of all the SocketPermission objects.
*/
// Convert Iterator into Enumeration
synchronized (this) {
}
}
// Need to maintain serialization interoperability with earlier releases,
// which had the serializable field:
//
// The SocketPermissions for this set.
// @serial
//
// private Vector permissions;
/**
* @serialField permissions java.util.Vector
* A list of the SocketPermissions for this set.
*/
};
/**
* @serialData "permissions" field (a Vector containing the SocketPermissions).
*/
/*
* Writes the contents of the perms field out as a Vector for
* serialization compatibility with earlier releases.
*/
// Don't call out.defaultWriteObject()
// Write out Vector
synchronized (this) {
}
out.writeFields();
}
/*
* Reads in a Vector of SocketPermissions and saves them in the perms field.
*/
// Don't call in.defaultReadObject()
// Read in serialized fields
// Get the one we want
}
}