1 /* 2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.org.apache.xalan.internal.utils; 27 28 import com.sun.org.apache.xalan.internal.XalanConstants; 29 30 31 /** 32 * This class is not the same as that in Xerces. It is used to manage the 33 * state of corresponding Xerces properties and pass the values over to 34 * the Xerces Security Manager. 35 * 36 * @author Joe Wang Oracle Corp. 37 * 38 */ 39 public final class XMLSecurityManager { 40 41 /** 42 * States of the settings of a property, in the order: default value, value 43 * set by FEATURE_SECURE_PROCESSING, jaxp.properties file, jaxp system 44 * properties, and jaxp api properties 45 */ 46 public static enum State { 47 //this order reflects the overriding order 48 49 DEFAULT("default"), FSP("FEATURE_SECURE_PROCESSING"), 50 JAXPDOTPROPERTIES("jaxp.properties"), SYSTEMPROPERTY("system property"), 51 APIPROPERTY("property"); 52 53 final String literal; 54 State(String literal) { 55 this.literal = literal; 56 } 57 58 String literal() { 59 return literal; 60 } 61 } 62 63 /** 64 * Limits managed by the security manager 65 */ 66 public static enum Limit { 67 68 ENTITY_EXPANSION_LIMIT("EntityExpansionLimit", XalanConstants.JDK_ENTITY_EXPANSION_LIMIT, 69 XalanConstants.SP_ENTITY_EXPANSION_LIMIT, 0, 64000), 70 MAX_OCCUR_NODE_LIMIT("MaxOccurLimit", XalanConstants.JDK_MAX_OCCUR_LIMIT, 71 XalanConstants.SP_MAX_OCCUR_LIMIT, 0, 5000), 72 ELEMENT_ATTRIBUTE_LIMIT("ElementAttributeLimit", XalanConstants.JDK_ELEMENT_ATTRIBUTE_LIMIT, 73 XalanConstants.SP_ELEMENT_ATTRIBUTE_LIMIT, 0, 10000), 74 TOTAL_ENTITY_SIZE_LIMIT("TotalEntitySizeLimit", XalanConstants.JDK_TOTAL_ENTITY_SIZE_LIMIT, 75 XalanConstants.SP_TOTAL_ENTITY_SIZE_LIMIT, 0, 50000000), 76 GENERAL_ENTITY_SIZE_LIMIT("MaxEntitySizeLimit", XalanConstants.JDK_GENERAL_ENTITY_SIZE_LIMIT, 77 XalanConstants.SP_GENERAL_ENTITY_SIZE_LIMIT, 0, 0), 78 PARAMETER_ENTITY_SIZE_LIMIT("MaxEntitySizeLimit", XalanConstants.JDK_PARAMETER_ENTITY_SIZE_LIMIT, 79 XalanConstants.SP_PARAMETER_ENTITY_SIZE_LIMIT, 0, 1000000), 80 MAX_ELEMENT_DEPTH_LIMIT("MaxElementDepthLimit", XalanConstants.JDK_MAX_ELEMENT_DEPTH, 81 XalanConstants.SP_MAX_ELEMENT_DEPTH, 0, 0), 82 MAX_NAME_LIMIT("MaxXMLNameLimit", XalanConstants.JDK_XML_NAME_LIMIT, 83 XalanConstants.SP_XML_NAME_LIMIT, 1000, 1000); 84 85 final String key; 86 final String apiProperty; 87 final String systemProperty; 88 final int defaultValue; 89 final int secureValue; 90 91 Limit(String key, String apiProperty, String systemProperty, int value, int secureValue) { 92 this.key = key; 93 this.apiProperty = apiProperty; 94 this.systemProperty = systemProperty; 95 this.defaultValue = value; 96 this.secureValue = secureValue; 97 } 98 99 public boolean equalsAPIPropertyName(String propertyName) { 100 return (propertyName == null) ? false : apiProperty.equals(propertyName); 101 } 102 103 public boolean equalsSystemPropertyName(String propertyName) { 104 return (propertyName == null) ? false : systemProperty.equals(propertyName); 105 } 106 107 public String key() { 108 return key; 109 } 110 111 public String apiProperty() { 112 return apiProperty; 113 } 114 115 String systemProperty() { 116 return systemProperty; 117 } 118 119 public int defaultValue() { 120 return defaultValue; 121 } 122 123 int secureValue() { 124 return secureValue; 125 } 126 } 127 128 /** 129 * Map old property names with the new ones 130 */ 131 public static enum NameMap { 132 133 ENTITY_EXPANSION_LIMIT(XalanConstants.SP_ENTITY_EXPANSION_LIMIT, 134 XalanConstants.ENTITY_EXPANSION_LIMIT), 135 MAX_OCCUR_NODE_LIMIT(XalanConstants.SP_MAX_OCCUR_LIMIT, 136 XalanConstants.MAX_OCCUR_LIMIT), 137 ELEMENT_ATTRIBUTE_LIMIT(XalanConstants.SP_ELEMENT_ATTRIBUTE_LIMIT, 138 XalanConstants.ELEMENT_ATTRIBUTE_LIMIT); 139 final String newName; 140 final String oldName; 141 142 NameMap(String newName, String oldName) { 143 this.newName = newName; 144 this.oldName = oldName; 145 } 146 147 String getOldName(String newName) { 148 if (newName.equals(this.newName)) { 149 return oldName; 150 } 151 return null; 152 } 153 } 154 /** 155 * Values of the properties 156 */ 157 private final int[] values; 158 /** 159 * States of the settings for each property 160 */ 161 private State[] states; 162 /** 163 * States that determine if properties are set explicitly 164 */ 165 private boolean[] isSet; 166 167 168 /** 169 * Index of the special entityCountInfo property 170 */ 171 private final int indexEntityCountInfo = 10000; 172 private String printEntityCountInfo = ""; 173 174 /** 175 * Default constructor. Establishes default values for known security 176 * vulnerabilities. 177 */ 178 public XMLSecurityManager() { 179 this(false); 180 } 181 182 /** 183 * Instantiate Security Manager in accordance with the status of 184 * secure processing 185 * @param secureProcessing 186 */ 187 public XMLSecurityManager(boolean secureProcessing) { 188 values = new int[Limit.values().length]; 189 states = new State[Limit.values().length]; 190 isSet = new boolean[Limit.values().length]; 191 for (Limit limit : Limit.values()) { 192 if (secureProcessing) { 193 values[limit.ordinal()] = limit.secureValue(); 194 states[limit.ordinal()] = State.FSP; 195 } else { 196 values[limit.ordinal()] = limit.defaultValue(); 197 states[limit.ordinal()] = State.DEFAULT; 198 } 199 } 200 //read system properties or jaxp.properties 201 readSystemProperties(); 202 } 203 204 /** 205 * Setting FEATURE_SECURE_PROCESSING explicitly 206 */ 207 public void setSecureProcessing(boolean secure) { 208 for (Limit limit : Limit.values()) { 209 if (secure) { 210 setLimit(limit.ordinal(), State.FSP, limit.secureValue()); 211 } else { 212 setLimit(limit.ordinal(), State.FSP, limit.defaultValue()); 213 } 214 } 215 } 216 217 /** 218 * Set limit by property name and state 219 * @param propertyName property name 220 * @param state the state of the property 221 * @param value the value of the property 222 * @return true if the property is managed by the security manager; false 223 * if otherwise. 224 */ 225 public boolean setLimit(String propertyName, State state, Object value) { 226 int index = getIndex(propertyName); 227 if (index > -1) { 228 setLimit(index, state, value); 229 return true; 230 } 231 return false; 232 } 233 234 /** 235 * Set the value for a specific limit. 236 * 237 * @param limit the limit 238 * @param state the state of the property 239 * @param value the value of the property 240 */ 241 public void setLimit(Limit limit, State state, int value) { 242 setLimit(limit.ordinal(), state, value); 243 } 244 245 /** 246 * Set the value of a property by its index 247 * 248 * @param index the index of the property 249 * @param state the state of the property 250 * @param value the value of the property 251 */ 252 public void setLimit(int index, State state, Object value) { 253 if (index == indexEntityCountInfo) { 254 //if it's explicitly set, it's treated as yes no matter the value 255 printEntityCountInfo = (String)value; 256 } else { 257 int temp = 0; 258 try { 259 temp = Integer.parseInt((String) value); 260 if (temp < 0) { 261 temp = 0; 262 } 263 } catch (NumberFormatException e) {} 264 setLimit(index, state, temp); } 265 } 266 267 /** 268 * Set the value of a property by its index 269 * 270 * @param index the index of the property 271 * @param state the state of the property 272 * @param value the value of the property 273 */ 274 public void setLimit(int index, State state, int value) { 275 if (index == indexEntityCountInfo) { 276 //if it's explicitly set, it's treated as yes no matter the value 277 printEntityCountInfo = XalanConstants.JDK_YES; 278 } else { 279 //only update if it shall override 280 if (state.compareTo(states[index]) >= 0) { 281 values[index] = value; 282 states[index] = state; 283 isSet[index] = true; 284 } 285 } 286 } 287 288 289 /** 290 * Return the value of the specified property. 291 * 292 * @param propertyName the property name 293 * @return the value of the property as a string. If a property is managed 294 * by this manager, its value shall not be null. 295 */ 296 public String getLimitAsString(String propertyName) { 297 int index = getIndex(propertyName); 298 if (index > -1) { 299 return getLimitValueByIndex(index); 300 } 301 302 return null; 303 } 304 305 /** 306 * Return the value of a property by its ordinal 307 * 308 * @param limit the property 309 * @return value of a property 310 */ 311 public String getLimitValueAsString(Limit limit) { 312 return Integer.toString(values[limit.ordinal()]); 313 } 314 315 /** 316 * Return the value of the specified property 317 * 318 * @param limit the property 319 * @return the value of the property 320 */ 321 public int getLimit(Limit limit) { 322 return values[limit.ordinal()]; 323 } 324 325 /** 326 * Return the value of a property by its ordinal 327 * 328 * @param index the index of a property 329 * @return value of a property 330 */ 331 public int getLimitByIndex(int index) { 332 return values[index]; 333 } 334 /** 335 * Return the value of a property by its index 336 * 337 * @param index the index of a property 338 * @return limit of a property as a string 339 */ 340 public String getLimitValueByIndex(int index) { 341 if (index == indexEntityCountInfo) { 342 return printEntityCountInfo; 343 } 344 345 return Integer.toString(values[index]); 346 } 347 /** 348 * Return the state of the limit property 349 * 350 * @param limit the limit 351 * @return the state of the limit property 352 */ 353 public State getState(Limit limit) { 354 return states[limit.ordinal()]; 355 } 356 357 /** 358 * Return the state of the limit property 359 * 360 * @param limit the limit 361 * @return the state of the limit property 362 */ 363 public String getStateLiteral(Limit limit) { 364 return states[limit.ordinal()].literal(); 365 } 366 367 /** 368 * Get the index by property name 369 * 370 * @param propertyName property name 371 * @return the index of the property if found; return -1 if not 372 */ 373 public int getIndex(String propertyName) { 374 for (Limit limit : Limit.values()) { 375 if (limit.equalsAPIPropertyName(propertyName)) { 376 //internally, ordinal is used as index 377 return limit.ordinal(); 378 } 379 } 380 //special property to return entity count info 381 if (propertyName.equals(XalanConstants.JDK_ENTITY_COUNT_INFO)) { 382 return indexEntityCountInfo; 383 } 384 return -1; 385 } 386 387 /** 388 * Indicate if a property is set explicitly 389 * @param index 390 * @return 391 */ 392 public boolean isSet(int index) { 393 return isSet[index]; 394 } 395 396 public boolean printEntityCountInfo() { 397 return printEntityCountInfo.equals(XalanConstants.JDK_YES); 398 } 399 /** 400 * Read from system properties, or those in jaxp.properties 401 */ 402 private void readSystemProperties() { 403 404 for (Limit limit : Limit.values()) { 405 if (!getSystemProperty(limit, limit.systemProperty())) { 406 //if system property is not found, try the older form if any 407 for (NameMap nameMap : NameMap.values()) { 408 String oldName = nameMap.getOldName(limit.systemProperty()); 409 if (oldName != null) { 410 getSystemProperty(limit, oldName); 411 } 412 } 413 } 414 } 415 416 } 417 418 /** 419 * Read from system properties, or those in jaxp.properties 420 * 421 * @param property the type of the property 422 * @param sysPropertyName the name of system property 423 */ 424 private boolean getSystemProperty(Limit limit, String sysPropertyName) { 425 try { 426 String value = SecuritySupport.getSystemProperty(sysPropertyName); 427 if (value != null && !value.equals("")) { 428 values[limit.ordinal()] = Integer.parseInt(value); 429 states[limit.ordinal()] = State.SYSTEMPROPERTY; 430 return true; 431 } 432 433 value = SecuritySupport.readJAXPProperty(sysPropertyName); 434 if (value != null && !value.equals("")) { 435 values[limit.ordinal()] = Integer.parseInt(value); 436 states[limit.ordinal()] = State.JAXPDOTPROPERTIES; 437 return true; 438 } 439 } catch (NumberFormatException e) { 440 //invalid setting 441 throw new NumberFormatException("Invalid setting for system property: " + limit.systemProperty()); 442 } 443 return false; 444 } 445 }