1 /* 2 * Copyright (c) 2013, 2017, 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 import java.util.concurrent.CopyOnWriteArrayList; 30 import jdk.xml.internal.SecuritySupport; 31 import org.xml.sax.SAXException; 32 33 34 /** 35 * This class is not the same as that in Xerces. It is used to manage the 36 * state of corresponding Xerces properties and pass the values over to 37 * the Xerces Security Manager. 38 * 39 * @author Joe Wang Oracle Corp. 40 * 41 */ 42 public final class XMLSecurityManager { 43 44 /** 45 * States of the settings of a property, in the order: default value, value 46 * set by FEATURE_SECURE_PROCESSING, jaxp.properties file, jaxp system 47 * properties, and jaxp api properties 48 */ 49 public static enum State { 50 //this order reflects the overriding order 51 52 DEFAULT("default"), FSP("FEATURE_SECURE_PROCESSING"), 53 JAXPDOTPROPERTIES("jaxp.properties"), SYSTEMPROPERTY("system property"), 54 APIPROPERTY("property"); 55 56 final String literal; 57 State(String literal) { 58 this.literal = literal; 59 } 60 61 String literal() { 62 return literal; 63 } 64 } 65 66 /** 67 * Limits managed by the security manager 68 */ 69 public static enum Limit { 70 71 ENTITY_EXPANSION_LIMIT("EntityExpansionLimit", XalanConstants.JDK_ENTITY_EXPANSION_LIMIT, 72 XalanConstants.SP_ENTITY_EXPANSION_LIMIT, 0, 64000), 73 MAX_OCCUR_NODE_LIMIT("MaxOccurLimit", XalanConstants.JDK_MAX_OCCUR_LIMIT, 74 XalanConstants.SP_MAX_OCCUR_LIMIT, 0, 5000), 75 ELEMENT_ATTRIBUTE_LIMIT("ElementAttributeLimit", XalanConstants.JDK_ELEMENT_ATTRIBUTE_LIMIT, 76 XalanConstants.SP_ELEMENT_ATTRIBUTE_LIMIT, 0, 10000), 77 TOTAL_ENTITY_SIZE_LIMIT("TotalEntitySizeLimit", XalanConstants.JDK_TOTAL_ENTITY_SIZE_LIMIT, 78 XalanConstants.SP_TOTAL_ENTITY_SIZE_LIMIT, 0, 50000000), 79 GENERAL_ENTITY_SIZE_LIMIT("MaxEntitySizeLimit", XalanConstants.JDK_GENERAL_ENTITY_SIZE_LIMIT, 80 XalanConstants.SP_GENERAL_ENTITY_SIZE_LIMIT, 0, 0), 81 PARAMETER_ENTITY_SIZE_LIMIT("MaxEntitySizeLimit", XalanConstants.JDK_PARAMETER_ENTITY_SIZE_LIMIT, 82 XalanConstants.SP_PARAMETER_ENTITY_SIZE_LIMIT, 0, 1000000), 83 MAX_ELEMENT_DEPTH_LIMIT("MaxElementDepthLimit", XalanConstants.JDK_MAX_ELEMENT_DEPTH, 84 XalanConstants.SP_MAX_ELEMENT_DEPTH, 0, 0), 85 MAX_NAME_LIMIT("MaxXMLNameLimit", XalanConstants.JDK_XML_NAME_LIMIT, 86 XalanConstants.SP_XML_NAME_LIMIT, 1000, 1000), 87 ENTITY_REPLACEMENT_LIMIT("EntityReplacementLimit", XalanConstants.JDK_ENTITY_REPLACEMENT_LIMIT, 88 XalanConstants.SP_ENTITY_REPLACEMENT_LIMIT, 0, 3000000); 89 90 final String key; 91 final String apiProperty; 92 final String systemProperty; 93 final int defaultValue; 94 final int secureValue; 95 96 Limit(String key, String apiProperty, String systemProperty, int value, int secureValue) { 97 this.key = key; 98 this.apiProperty = apiProperty; 99 this.systemProperty = systemProperty; 100 this.defaultValue = value; 101 this.secureValue = secureValue; 102 } 103 104 public boolean equalsAPIPropertyName(String propertyName) { 105 return (propertyName == null) ? false : apiProperty.equals(propertyName); 106 } 107 108 public boolean equalsSystemPropertyName(String propertyName) { 109 return (propertyName == null) ? false : systemProperty.equals(propertyName); 110 } 111 112 public String key() { 113 return key; 114 } 115 116 public String apiProperty() { 117 return apiProperty; 118 } 119 120 String systemProperty() { 121 return systemProperty; 122 } 123 124 public int defaultValue() { 125 return defaultValue; 126 } 127 128 int secureValue() { 129 return secureValue; 130 } 131 } 132 133 /** 134 * Map old property names with the new ones 135 */ 136 public static enum NameMap { 137 138 ENTITY_EXPANSION_LIMIT(XalanConstants.SP_ENTITY_EXPANSION_LIMIT, 139 XalanConstants.ENTITY_EXPANSION_LIMIT), 140 MAX_OCCUR_NODE_LIMIT(XalanConstants.SP_MAX_OCCUR_LIMIT, 141 XalanConstants.MAX_OCCUR_LIMIT), 142 ELEMENT_ATTRIBUTE_LIMIT(XalanConstants.SP_ELEMENT_ATTRIBUTE_LIMIT, 143 XalanConstants.ELEMENT_ATTRIBUTE_LIMIT); 144 final String newName; 145 final String oldName; 146 147 NameMap(String newName, String oldName) { 148 this.newName = newName; 149 this.oldName = oldName; 150 } 151 152 String getOldName(String newName) { 153 if (newName.equals(this.newName)) { 154 return oldName; 155 } 156 return null; 157 } 158 } 159 /** 160 * Values of the properties 161 */ 162 private final int[] values; 163 /** 164 * States of the settings for each property 165 */ 166 private State[] states; 167 /** 168 * States that determine if properties are set explicitly 169 */ 170 private boolean[] isSet; 171 172 173 /** 174 * Index of the special entityCountInfo property 175 */ 176 private final int indexEntityCountInfo = 10000; 177 private String printEntityCountInfo = ""; 178 179 /** 180 * Default constructor. Establishes default values for known security 181 * vulnerabilities. 182 */ 183 public XMLSecurityManager() { 184 this(false); 185 } 186 187 /** 188 * Instantiate Security Manager in accordance with the status of 189 * secure processing 190 * @param secureProcessing 191 */ 192 public XMLSecurityManager(boolean secureProcessing) { 193 values = new int[Limit.values().length]; 194 states = new State[Limit.values().length]; 195 isSet = new boolean[Limit.values().length]; 196 for (Limit limit : Limit.values()) { 197 if (secureProcessing) { 198 values[limit.ordinal()] = limit.secureValue(); 199 states[limit.ordinal()] = State.FSP; 200 } else { 201 values[limit.ordinal()] = limit.defaultValue(); 202 states[limit.ordinal()] = State.DEFAULT; 203 } 204 } 205 //read system properties or jaxp.properties 206 readSystemProperties(); 207 } 208 209 /** 210 * Setting FEATURE_SECURE_PROCESSING explicitly 211 */ 212 public void setSecureProcessing(boolean secure) { 213 for (Limit limit : Limit.values()) { 214 if (secure) { 215 setLimit(limit.ordinal(), State.FSP, limit.secureValue()); 216 } else { 217 setLimit(limit.ordinal(), State.FSP, limit.defaultValue()); 218 } 219 } 220 } 221 222 /** 223 * Set limit by property name and state 224 * @param propertyName property name 225 * @param state the state of the property 226 * @param value the value of the property 227 * @return true if the property is managed by the security manager; false 228 * if otherwise. 229 */ 230 public boolean setLimit(String propertyName, State state, Object value) { 231 int index = getIndex(propertyName); 232 if (index > -1) { 233 setLimit(index, state, value); 234 return true; 235 } 236 return false; 237 } 238 239 /** 240 * Set the value for a specific limit. 241 * 242 * @param limit the limit 243 * @param state the state of the property 244 * @param value the value of the property 245 */ 246 public void setLimit(Limit limit, State state, int value) { 247 setLimit(limit.ordinal(), state, value); 248 } 249 250 /** 251 * Set the value of a property by its index 252 * 253 * @param index the index of the property 254 * @param state the state of the property 255 * @param value the value of the property 256 */ 257 public void setLimit(int index, State state, Object value) { 258 if (index == indexEntityCountInfo) { 259 //if it's explicitly set, it's treated as yes no matter the value 260 printEntityCountInfo = (String)value; 261 } else { 262 int temp = 0; 263 try { 264 temp = Integer.parseInt((String) value); 265 if (temp < 0) { 266 temp = 0; 267 } 268 } catch (NumberFormatException e) {} 269 setLimit(index, state, temp); } 270 } 271 272 /** 273 * Set the value of a property by its index 274 * 275 * @param index the index of the property 276 * @param state the state of the property 277 * @param value the value of the property 278 */ 279 public void setLimit(int index, State state, int value) { 280 if (index == indexEntityCountInfo) { 281 //if it's explicitly set, it's treated as yes no matter the value 282 printEntityCountInfo = XalanConstants.JDK_YES; 283 } else { 284 //only update if it shall override 285 if (state.compareTo(states[index]) >= 0) { 286 values[index] = value; 287 states[index] = state; 288 isSet[index] = true; 289 } 290 } 291 } 292 293 294 /** 295 * Return the value of the specified property. 296 * 297 * @param propertyName the property name 298 * @return the value of the property as a string. If a property is managed 299 * by this manager, its value shall not be null. 300 */ 301 public String getLimitAsString(String propertyName) { 302 int index = getIndex(propertyName); 303 if (index > -1) { 304 return getLimitValueByIndex(index); 305 } 306 307 return null; 308 } 309 310 /** 311 * Return the value of a property by its ordinal 312 * 313 * @param limit the property 314 * @return value of a property 315 */ 316 public String getLimitValueAsString(Limit limit) { 317 return Integer.toString(values[limit.ordinal()]); 318 } 319 320 /** 321 * Return the value of the specified property 322 * 323 * @param limit the property 324 * @return the value of the property 325 */ 326 public int getLimit(Limit limit) { 327 return values[limit.ordinal()]; 328 } 329 330 /** 331 * Return the value of a property by its ordinal 332 * 333 * @param index the index of a property 334 * @return value of a property 335 */ 336 public int getLimitByIndex(int index) { 337 return values[index]; 338 } 339 /** 340 * Return the value of a property by its index 341 * 342 * @param index the index of a property 343 * @return limit of a property as a string 344 */ 345 public String getLimitValueByIndex(int index) { 346 if (index == indexEntityCountInfo) { 347 return printEntityCountInfo; 348 } 349 350 return Integer.toString(values[index]); 351 } 352 /** 353 * Return the state of the limit property 354 * 355 * @param limit the limit 356 * @return the state of the limit property 357 */ 358 public State getState(Limit limit) { 359 return states[limit.ordinal()]; 360 } 361 362 /** 363 * Return the state of the limit property 364 * 365 * @param limit the limit 366 * @return the state of the limit property 367 */ 368 public String getStateLiteral(Limit limit) { 369 return states[limit.ordinal()].literal(); 370 } 371 372 /** 373 * Get the index by property name 374 * 375 * @param propertyName property name 376 * @return the index of the property if found; return -1 if not 377 */ 378 public int getIndex(String propertyName) { 379 for (Limit limit : Limit.values()) { 380 if (limit.equalsAPIPropertyName(propertyName)) { 381 //internally, ordinal is used as index 382 return limit.ordinal(); 383 } 384 } 385 //special property to return entity count info 386 if (propertyName.equals(XalanConstants.JDK_ENTITY_COUNT_INFO)) { 387 return indexEntityCountInfo; 388 } 389 return -1; 390 } 391 392 /** 393 * Indicate if a property is set explicitly 394 * @param index 395 * @return 396 */ 397 public boolean isSet(int index) { 398 return isSet[index]; 399 } 400 401 public boolean printEntityCountInfo() { 402 return printEntityCountInfo.equals(XalanConstants.JDK_YES); 403 } 404 /** 405 * Read from system properties, or those in jaxp.properties 406 */ 407 private void readSystemProperties() { 408 409 for (Limit limit : Limit.values()) { 410 if (!getSystemProperty(limit, limit.systemProperty())) { 411 //if system property is not found, try the older form if any 412 for (NameMap nameMap : NameMap.values()) { 413 String oldName = nameMap.getOldName(limit.systemProperty()); 414 if (oldName != null) { 415 getSystemProperty(limit, oldName); 416 } 417 } 418 } 419 } 420 421 } 422 423 // Array list to store printed warnings for each SAX parser used 424 private static final CopyOnWriteArrayList<String> printedWarnings = new CopyOnWriteArrayList<>(); 425 426 /** 427 * Prints out warnings if a parser does not support the specified feature/property. 428 * 429 * @param parserClassName the name of the parser class 430 * @param propertyName the property name 431 * @param exception the exception thrown by the parser 432 */ 433 public static void printWarning(String parserClassName, String propertyName, SAXException exception) { 434 String key = parserClassName+":"+propertyName; 435 if (printedWarnings.addIfAbsent(key)) { 436 System.err.println( "Warning: "+parserClassName+": "+exception.getMessage()); 437 } 438 } 439 440 /** 441 * Read from system properties, or those in jaxp.properties 442 * 443 * @param property the type of the property 444 * @param sysPropertyName the name of system property 445 */ 446 private boolean getSystemProperty(Limit limit, String sysPropertyName) { 447 try { 448 String value = SecuritySupport.getSystemProperty(sysPropertyName); 449 if (value != null && !value.equals("")) { 450 values[limit.ordinal()] = Integer.parseInt(value); 451 states[limit.ordinal()] = State.SYSTEMPROPERTY; 452 return true; 453 } 454 455 value = SecuritySupport.readJAXPProperty(sysPropertyName); 456 if (value != null && !value.equals("")) { 457 values[limit.ordinal()] = Integer.parseInt(value); 458 states[limit.ordinal()] = State.JAXPDOTPROPERTIES; 459 return true; 460 } 461 } catch (NumberFormatException e) { 462 //invalid setting 463 throw new NumberFormatException("Invalid setting for system property: " + limit.systemProperty()); 464 } 465 return false; 466 } 467 }