1. /*
  2. * Copyright 2003-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.types;
  18. import java.security.UnresolvedPermission;
  19. import java.util.HashSet;
  20. import java.util.Iterator;
  21. import java.util.LinkedList;
  22. import java.util.List;
  23. import java.util.Set;
  24. import java.util.StringTokenizer;
  25. import org.apache.tools.ant.BuildException;
  26. import org.apache.tools.ant.ExitException;
  27. /**
  28. * This class implements a security manager meant for useage by tasks that run inside the
  29. * ant VM. An examples are the Java Task and JUnitTask.
  30. *
  31. * The basic functionality is that nothing (except for a base set of permissions) is allowed, unless
  32. * the permission is granted either explicitly or implicitly.
  33. * If an permission is granted this can be overruled by explicitly revoking the permission.
  34. *
  35. * It is not permissible to add permissions (either granted or revoked) while the Security Manager
  36. * is active (after calling setSecurityManager() but before calling restoreSecurityManager()).
  37. *
  38. * @since Ant 1.6
  39. */
  40. public class Permissions {
  41. private List grantedPermissions = new LinkedList();
  42. private List revokedPermissions = new LinkedList();
  43. private java.security.Permissions granted = null;
  44. private SecurityManager origSm = null;
  45. private boolean active = false;
  46. private boolean delegateToOldSM = false;
  47. /**
  48. * default constructor
  49. */
  50. public Permissions() {
  51. }
  52. /**
  53. * create a new set of permissions
  54. * @param delegateToOldSM if <code>true</code> the old security manager
  55. * will be used if the permission has not been explicitly granted or revoked
  56. * in this instance
  57. * if false, it behaves like the default constructor
  58. */
  59. public Permissions(boolean delegateToOldSM) {
  60. this.delegateToOldSM = delegateToOldSM;
  61. }
  62. /**
  63. * Adds a permission to be granted.
  64. * @param perm The Permissions.Permission to be granted.
  65. */
  66. public void addConfiguredGrant(Permissions.Permission perm) {
  67. grantedPermissions.add(perm);
  68. }
  69. /**
  70. * Adds a permission to be revoked.
  71. * @param perm The Permissions.Permission to be revoked
  72. */
  73. public void addConfiguredRevoke(Permissions.Permission perm) {
  74. revokedPermissions.add(perm);
  75. }
  76. /**
  77. * To be used by tasks wishing to use this security model before executing the part to be
  78. * subject to these Permissions. Note that setting the SecurityManager too early may
  79. * prevent your part from starting, as for instance changing classloaders may be prohibited.
  80. * The classloader for the new situation is supposed to be present.
  81. */
  82. public void setSecurityManager() throws BuildException{
  83. origSm = System.getSecurityManager();
  84. init();
  85. System.setSecurityManager(new MySM());
  86. active = true;
  87. }
  88. /**
  89. * Initializes the list of granted permissions, checks the list of revoked permissions.
  90. */
  91. private void init() throws BuildException {
  92. granted = new java.security.Permissions();
  93. for (Iterator i = revokedPermissions.listIterator(); i.hasNext();) {
  94. Permissions.Permission p = (Permissions.Permission) i.next();
  95. if (p.getClassName() == null) {
  96. throw new BuildException("Revoked permission " + p + " does not contain a class.");
  97. }
  98. }
  99. for (Iterator i = grantedPermissions.listIterator(); i.hasNext();) {
  100. Permissions.Permission p = (Permissions.Permission) i.next();
  101. if (p.getClassName() == null) {
  102. throw new BuildException("Granted permission " + p + " does not contain a class.");
  103. } else {
  104. java.security.Permission perm = new UnresolvedPermission(p.getClassName(),p.getName(),p.getActions(),null);
  105. granted.add(perm);
  106. }
  107. }
  108. // Add base set of permissions
  109. granted.add(new java.net.SocketPermission("localhost:1024-", "listen"));
  110. granted.add(new java.util.PropertyPermission("java.version", "read"));
  111. granted.add(new java.util.PropertyPermission("java.vendor", "read"));
  112. granted.add(new java.util.PropertyPermission("java.vendor.url", "read"));
  113. granted.add(new java.util.PropertyPermission("java.class.version", "read"));
  114. granted.add(new java.util.PropertyPermission("os.name", "read"));
  115. granted.add(new java.util.PropertyPermission("os.version", "read"));
  116. granted.add(new java.util.PropertyPermission("os.arch", "read"));
  117. granted.add(new java.util.PropertyPermission("file.encoding", "read"));
  118. granted.add(new java.util.PropertyPermission("file.separator", "read"));
  119. granted.add(new java.util.PropertyPermission("path.separator", "read"));
  120. granted.add(new java.util.PropertyPermission("line.separator", "read"));
  121. granted.add(new java.util.PropertyPermission("java.specification.version", "read"));
  122. granted.add(new java.util.PropertyPermission("java.specification.vendor", "read"));
  123. granted.add(new java.util.PropertyPermission("java.specification.name", "read"));
  124. granted.add(new java.util.PropertyPermission("java.vm.specification.version", "read"));
  125. granted.add(new java.util.PropertyPermission("java.vm.specification.vendor", "read"));
  126. granted.add(new java.util.PropertyPermission("java.vm.specification.name", "read"));
  127. granted.add(new java.util.PropertyPermission("java.vm.version", "read"));
  128. granted.add(new java.util.PropertyPermission("java.vm.vendor", "read"));
  129. granted.add(new java.util.PropertyPermission("java.vm.name", "read"));
  130. }
  131. /**
  132. * To be used by tasks that just finished executing the parts subject to these permissions.
  133. */
  134. public void restoreSecurityManager() {
  135. active = false;
  136. System.setSecurityManager(origSm);
  137. }
  138. /**
  139. * This inner class implements the actual SecurityManager that can be used by tasks
  140. * supporting Permissions.
  141. */
  142. private class MySM extends SecurityManager {
  143. /**
  144. * Exit is treated in a special way in order to be able to return the exit code towards tasks.
  145. * An ExitException is thrown instead of a simple SecurityException to indicate the exit
  146. * code.
  147. * Overridden from java.lang.SecurityManager
  148. * @param status The exit status requested.
  149. */
  150. public void checkExit(int status) {
  151. java.security.Permission perm = new java.lang.RuntimePermission("exitVM",null);
  152. try {
  153. checkPermission(perm);
  154. } catch (SecurityException e) {
  155. throw new ExitException(e.getMessage(), status);
  156. }
  157. }
  158. /**
  159. * The central point in checking permissions.
  160. * Overridden from java.lang.SecurityManager
  161. *
  162. * @param perm The permission requested.
  163. */
  164. public void checkPermission(java.security.Permission perm) {
  165. if (active) {
  166. if (delegateToOldSM && !perm.getName().equals("exitVM")) {
  167. boolean permOK = false;
  168. if (granted.implies(perm)) {
  169. permOK = true;
  170. }
  171. checkRevoked(perm);
  172. /*
  173. if the permission was not explicitly granted or revoked
  174. the original security manager will do its work
  175. */
  176. if (!permOK && origSm != null) {
  177. origSm.checkPermission(perm);
  178. }
  179. } else {
  180. if (!granted.implies(perm)) {
  181. throw new SecurityException("Permission " + perm + " was not granted.");
  182. }
  183. checkRevoked(perm);
  184. }
  185. }
  186. }
  187. /**
  188. * throws an exception if this permission is revoked
  189. * @param perm the permission being checked
  190. */
  191. private void checkRevoked(java.security.Permission perm) {
  192. for (Iterator i = revokedPermissions.listIterator(); i.hasNext();) {
  193. if (((Permissions.Permission)i.next()).matches(perm)) {
  194. throw new SecurityException("Permission " + perm + " was revoked.");
  195. }
  196. }
  197. }
  198. }
  199. /** Represents a permission. */
  200. public static class Permission {
  201. private String className;
  202. private String name;
  203. private String actionString;
  204. private Set actions;
  205. /**
  206. * Sets the class, mandatory.
  207. * @param aClass The class name of the permission.
  208. */
  209. public void setClass(String aClass) {
  210. className = aClass.trim();
  211. }
  212. /** Get the class of the permission
  213. * @return The class name of the permission.
  214. */
  215. public String getClassName() {
  216. return className;
  217. }
  218. /**
  219. * Sets the name of the permission.
  220. * @param aName The name of the permission.
  221. */
  222. public void setName(String aName) {
  223. name = aName.trim();
  224. }
  225. /**
  226. * Get the name of the permission.
  227. * @return The name of the permission.
  228. */
  229. public String getName() {
  230. return name;
  231. }
  232. /**
  233. * Sets the actions.
  234. * @param actions The actions of the permission.
  235. */
  236. public void setActions(String actions) {
  237. actionString = actions;
  238. if (actions.length() > 0) {
  239. this.actions = parseActions(actions);
  240. }
  241. }
  242. /**
  243. * Gets the actions.
  244. * @return The actions of the permission.
  245. */
  246. public String getActions() {
  247. return actionString;
  248. }
  249. /**
  250. * Checks if the permission matches in case of a revoked permission.
  251. * @param perm The permission to check against.
  252. */
  253. boolean matches(java.security.Permission perm) {
  254. if (!className.equals(perm.getClass().getName())) {
  255. return false;
  256. }
  257. if (name != null) {
  258. if (name.endsWith("*")) {
  259. if (!perm.getName().startsWith(name.substring(0, name.length() - 1))) {
  260. return false;
  261. }
  262. } else {
  263. if (!name.equals(perm.getName())) {
  264. return false;
  265. }
  266. }
  267. }
  268. if (actions != null) {
  269. Set as = parseActions(perm.getActions());
  270. int size = as.size();
  271. as.removeAll(actions);
  272. if (as.size() == size) {
  273. // None of the actions revoked, so all allowed.
  274. return false;
  275. }
  276. }
  277. return true;
  278. }
  279. /**
  280. * Parses the actions into a set of separate strings.
  281. * @param actions The actions to be parsed.
  282. */
  283. private Set parseActions(String actions) {
  284. Set result = new HashSet();
  285. StringTokenizer tk = new StringTokenizer(actions, ",");
  286. while (tk.hasMoreTokens()) {
  287. String item = tk.nextToken().trim();
  288. if (!item.equals("")) {
  289. result.add(item);
  290. }
  291. }
  292. return result;
  293. }
  294. /**
  295. * get a string description of the permissions
  296. * @return string description of the permissions
  297. */
  298. public String toString() {
  299. return ("Permission: " + className + " (\"" + name + "\", \"" + actions + "\")");
  300. }
  301. }
  302. }