1 /* 2 * Copyright (c) 2013, 2015, 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.xerces.internal.utils; 27 28 import com.sun.org.apache.xerces.internal.impl.Constants; 29 import com.sun.org.apache.xerces.internal.util.SecurityManager; 30 31 /** 32 * This class manages standard and implementation-specific limitations. 33 * 34 */ 35 public final class XMLSecurityManager { 36 37 /** 38 * States of the settings of a property, in the order: default value, value 39 * set by FEATURE_SECURE_PROCESSING, jaxp.properties file, jaxp system 40 * properties, and jaxp api properties 41 */ 42 public static enum State { 43 //this order reflects the overriding order 44 45 DEFAULT("default"), FSP("FEATURE_SECURE_PROCESSING"), 46 JAXPDOTPROPERTIES("jaxp.properties"), SYSTEMPROPERTY("system property"), 47 APIPROPERTY("property"); 48 49 final String literal; 50 State(String literal) { 51 this.literal = literal; 52 } 53 54 String literal() { 55 return literal; 56 } 57 } 58 59 /** 60 * Limits managed by the security manager 61 */ 62 public static enum Limit { 63 64 ENTITY_EXPANSION_LIMIT("EntityExpansionLimit", 65 Constants.JDK_ENTITY_EXPANSION_LIMIT, Constants.SP_ENTITY_EXPANSION_LIMIT, 0, 64000), 66 MAX_OCCUR_NODE_LIMIT("MaxOccurLimit", 67 Constants.JDK_MAX_OCCUR_LIMIT, Constants.SP_MAX_OCCUR_LIMIT, 0, 5000), 68 ELEMENT_ATTRIBUTE_LIMIT("ElementAttributeLimit", 69 Constants.JDK_ELEMENT_ATTRIBUTE_LIMIT, Constants.SP_ELEMENT_ATTRIBUTE_LIMIT, 0, 10000), 70 TOTAL_ENTITY_SIZE_LIMIT("TotalEntitySizeLimit", 71 Constants.JDK_TOTAL_ENTITY_SIZE_LIMIT, Constants.SP_TOTAL_ENTITY_SIZE_LIMIT, 0, 50000000), 72 GENERAL_ENTITY_SIZE_LIMIT("MaxEntitySizeLimit", 73 Constants.JDK_GENERAL_ENTITY_SIZE_LIMIT, Constants.SP_GENERAL_ENTITY_SIZE_LIMIT, 0, 0), 74 PARAMETER_ENTITY_SIZE_LIMIT("MaxEntitySizeLimit", 75 Constants.JDK_PARAMETER_ENTITY_SIZE_LIMIT, Constants.SP_PARAMETER_ENTITY_SIZE_LIMIT, 0, 1000000), 76 MAX_ELEMENT_DEPTH_LIMIT("MaxElementDepthLimit", 77 Constants.JDK_MAX_ELEMENT_DEPTH, Constants.SP_MAX_ELEMENT_DEPTH, 0, 0), 78 MAX_NAME_LIMIT("MaxXMLNameLimit", 79 Constants.JDK_XML_NAME_LIMIT, Constants.SP_XML_NAME_LIMIT, 1000, 1000); 80 81 final String key; 82 final String apiProperty; 83 final String systemProperty; 84 final int defaultValue; 85 final int secureValue; 86 87 Limit(String key, String apiProperty, String systemProperty, int value, int secureValue) { 88 this.key = key; 89 this.apiProperty = apiProperty; 90 this.systemProperty = systemProperty; 91 this.defaultValue = value; 92 this.secureValue = secureValue; 93 } 94 95 public boolean equalsAPIPropertyName(String propertyName) { 96 return (propertyName == null) ? false : apiProperty.equals(propertyName); 97 } 98 99 public boolean equalsSystemPropertyName(String propertyName) { 100 return (propertyName == null) ? false : systemProperty.equals(propertyName); 101 } 102 103 public String key() { 104 return key; 105 } 106 107 public String apiProperty() { 108 return apiProperty; 109 } 110 111 String systemProperty() { 112 return systemProperty; 113 } 114 115 public int defaultValue() { 116 return defaultValue; 117 } 118 119 int secureValue() { 120 return secureValue; 121 } 122 } 123 124 /** 125 * Map old property names with the new ones 126 */ 127 public static enum NameMap { 128 129 ENTITY_EXPANSION_LIMIT(Constants.SP_ENTITY_EXPANSION_LIMIT, Constants.ENTITY_EXPANSION_LIMIT), 130 MAX_OCCUR_NODE_LIMIT(Constants.SP_MAX_OCCUR_LIMIT, Constants.MAX_OCCUR_LIMIT), 131 ELEMENT_ATTRIBUTE_LIMIT(Constants.SP_ELEMENT_ATTRIBUTE_LIMIT, Constants.ELEMENT_ATTRIBUTE_LIMIT); 132 final String newName; 133 final String oldName; 134 135 NameMap(String newName, String oldName) { 136 this.newName = newName; 137 this.oldName = oldName; 138 } 139 140 String getOldName(String newName) { 141 if (newName.equals(this.newName)) { 142 return oldName; 143 } 144 return null; 145 } 146 } 147 private static final int NO_LIMIT = 0; 148 /** 149 * Values of the properties 150 */ 151 private final int[] values; 152 /** 153 * States of the settings for each property 154 */ 155 private State[] states; 156 /** 157 * Flag indicating if secure processing is set 158 */ 159 boolean secureProcessing; 160 161 /** 162 * States that determine if properties are set explicitly 163 */ 164 private boolean[] isSet; 165 166 167 /** 168 * Index of the special entityCountInfo property 169 */ 170 private final int indexEntityCountInfo = 10000; 171 private String printEntityCountInfo = ""; 172 173 /** 174 * Default constructor. Establishes default values for known security 175 * vulnerabilities. 176 */ 177 public XMLSecurityManager() { 178 this(false); 179 } 180 181 /** 182 * Instantiate Security Manager in accordance with the status of 183 * secure processing 184 * @param secureProcessing 185 */ 186 public XMLSecurityManager(boolean secureProcessing) { 187 values = new int[Limit.values().length]; 188 states = new State[Limit.values().length]; 189 isSet = new boolean[Limit.values().length]; 190 this.secureProcessing = secureProcessing; 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 secureProcessing = secure; 209 for (Limit limit : Limit.values()) { 210 if (secure) { 211 setLimit(limit.ordinal(), State.FSP, limit.secureValue()); 212 } else { 213 setLimit(limit.ordinal(), State.FSP, limit.defaultValue()); 214 } 215 } 216 } 217 218 /** 219 * Return the state of secure processing 220 * @return the state of secure processing 221 */ 222 public boolean isSecureProcessing() { 223 return secureProcessing; 224 } 225 226 227 /** 228 * Set limit by property name and state 229 * @param propertyName property name 230 * @param state the state of the property 231 * @param value the value of the property 232 * @return true if the property is managed by the security manager; false 233 * if otherwise. 234 */ 235 public boolean setLimit(String propertyName, State state, Object value) { 236 int index = getIndex(propertyName); 237 if (index > -1) { 238 setLimit(index, state, value); 239 return true; 240 } 241 return false; 242 } 243 244 /** 245 * Set the value for a specific limit. 246 * 247 * @param limit the limit 248 * @param state the state of the property 249 * @param value the value of the property 250 */ 251 public void setLimit(Limit limit, State state, int value) { 252 setLimit(limit.ordinal(), state, value); 253 } 254 255 /** 256 * Set the value of a property by its index 257 * 258 * @param index the index of the property 259 * @param state the state of the property 260 * @param value the value of the property 261 */ 262 public void setLimit(int index, State state, Object value) { 263 if (index == indexEntityCountInfo) { 264 printEntityCountInfo = (String)value; 265 } else { 266 int temp; 267 if (Integer.class.isAssignableFrom(value.getClass())) { 268 temp = ((Integer)value).intValue(); 269 } else { 270 temp = Integer.parseInt((String) value); 271 if (temp < 0) { 272 temp = 0; 273 } 274 } 275 setLimit(index, state, temp); 276 } 277 } 278 279 /** 280 * Set the value of a property by its index 281 * 282 * @param index the index of the property 283 * @param state the state of the property 284 * @param value the value of the property 285 */ 286 public void setLimit(int index, State state, int value) { 287 if (index == indexEntityCountInfo) { 288 //if it's explicitly set, it's treated as yes no matter the value 289 printEntityCountInfo = Constants.JDK_YES; 290 } else { 291 //only update if it shall override 292 if (state.compareTo(states[index]) >= 0) { 293 values[index] = value; 294 states[index] = state; 295 isSet[index] = true; 296 } 297 } 298 } 299 300 /** 301 * Return the value of the specified property 302 * 303 * @param propertyName the property name 304 * @return the value of the property as a string. If a property is managed 305 * by this manager, its value shall not be null. 306 */ 307 public String getLimitAsString(String propertyName) { 308 int index = getIndex(propertyName); 309 if (index > -1) { 310 return getLimitValueByIndex(index); 311 } 312 313 return null; 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 limit the property 329 * @return value of a property 330 */ 331 public String getLimitValueAsString(Limit limit) { 332 return Integer.toString(values[limit.ordinal()]); 333 } 334 335 /** 336 * Return the value of a property by its ordinal 337 * 338 * @param index the index of a property 339 * @return limit of a property as a string 340 */ 341 public String getLimitValueByIndex(int index) { 342 if (index == indexEntityCountInfo) { 343 return printEntityCountInfo; 344 } 345 346 return Integer.toString(values[index]); 347 } 348 349 /** 350 * Return the state of the limit property 351 * 352 * @param limit the limit 353 * @return the state of the limit property 354 */ 355 public State getState(Limit limit) { 356 return states[limit.ordinal()]; 357 } 358 359 /** 360 * Return the state of the limit property 361 * 362 * @param limit the limit 363 * @return the state of the limit property 364 */ 365 public String getStateLiteral(Limit limit) { 366 return states[limit.ordinal()].literal(); 367 } 368 369 /** 370 * Get the index by property name 371 * 372 * @param propertyName property name 373 * @return the index of the property if found; return -1 if not 374 */ 375 public int getIndex(String propertyName) { 376 for (Limit limit : Limit.values()) { 377 if (limit.equalsAPIPropertyName(propertyName)) { 378 //internally, ordinal is used as index 379 return limit.ordinal(); 380 } 381 } 382 //special property to return entity count info 383 if (propertyName.equals(Constants.JDK_ENTITY_COUNT_INFO)) { 384 return indexEntityCountInfo; 385 } 386 return -1; 387 } 388 389 /** 390 * Check if there's no limit defined by the Security Manager 391 * @param limit 392 * @return 393 */ 394 public boolean isNoLimit(int limit) { 395 return limit==NO_LIMIT; 396 } 397 /** 398 * Check if the size (length or count) of the specified limit property is 399 * over the limit 400 * 401 * @param limit the type of the limit property 402 * @param entityName the name of the entity 403 * @param size the size (count or length) of the entity 404 * @return true if the size is over the limit, false otherwise 405 */ 406 public boolean isOverLimit(Limit limit, String entityName, int size, 407 XMLLimitAnalyzer limitAnalyzer) { 408 return isOverLimit(limit.ordinal(), entityName, size, limitAnalyzer); 409 } 410 411 /** 412 * Check if the value (length or count) of the specified limit property is 413 * over the limit 414 * 415 * @param index the index of the limit property 416 * @param entityName the name of the entity 417 * @param size the size (count or length) of the entity 418 * @return true if the size is over the limit, false otherwise 419 */ 420 public boolean isOverLimit(int index, String entityName, int size, 421 XMLLimitAnalyzer limitAnalyzer) { 422 if (values[index] == NO_LIMIT) { 423 return false; 424 } 425 if (size > values[index]) { 426 limitAnalyzer.addValue(index, entityName, size); 427 return true; 428 } 429 return false; 430 } 431 432 /** 433 * Check against cumulated value 434 * 435 * @param limit the type of the limit property 436 * @param size the size (count or length) of the entity 437 * @return true if the size is over the limit, false otherwise 438 */ 439 public boolean isOverLimit(Limit limit, XMLLimitAnalyzer limitAnalyzer) { 440 return isOverLimit(limit.ordinal(), limitAnalyzer); 441 } 442 443 public boolean isOverLimit(int index, XMLLimitAnalyzer limitAnalyzer) { 444 if (values[index] == NO_LIMIT) { 445 return false; 446 } 447 448 if (index == Limit.ELEMENT_ATTRIBUTE_LIMIT.ordinal() || 449 index == Limit.ENTITY_EXPANSION_LIMIT.ordinal() || 450 index == Limit.TOTAL_ENTITY_SIZE_LIMIT.ordinal() || 451 index == Limit.MAX_ELEMENT_DEPTH_LIMIT.ordinal() || 452 index == Limit.MAX_NAME_LIMIT.ordinal() 453 ) { 454 return (limitAnalyzer.getTotalValue(index) > values[index]); 455 } else { 456 return (limitAnalyzer.getValue(index) > values[index]); 457 } 458 } 459 460 public void debugPrint(XMLLimitAnalyzer limitAnalyzer) { 461 if (printEntityCountInfo.equals(Constants.JDK_YES)) { 462 limitAnalyzer.debugPrint(this); 463 } 464 } 465 466 467 /** 468 * Indicate if a property is set explicitly 469 * @param index 470 * @return 471 */ 472 public boolean isSet(int index) { 473 return isSet[index]; 474 } 475 476 public boolean printEntityCountInfo() { 477 return printEntityCountInfo.equals(Constants.JDK_YES); 478 } 479 480 /** 481 * Read from system properties, or those in jaxp.properties 482 */ 483 private void readSystemProperties() { 484 485 for (Limit limit : Limit.values()) { 486 if (!getSystemProperty(limit, limit.systemProperty())) { 487 //if system property is not found, try the older form if any 488 for (NameMap nameMap : NameMap.values()) { 489 String oldName = nameMap.getOldName(limit.systemProperty()); 490 if (oldName != null) { 491 getSystemProperty(limit, oldName); 492 } 493 } 494 } 495 } 496 497 } 498 499 /** 500 * Read from system properties, or those in jaxp.properties 501 * 502 * @param property the type of the property 503 * @param sysPropertyName the name of system property 504 */ 505 private boolean getSystemProperty(Limit limit, String sysPropertyName) { 506 try { 507 String value = SecuritySupport.getSystemProperty(sysPropertyName); 508 if (value != null && !value.equals("")) { 509 values[limit.ordinal()] = Integer.parseInt(value); 510 states[limit.ordinal()] = State.SYSTEMPROPERTY; 511 return true; 512 } 513 514 value = SecuritySupport.readJAXPProperty(sysPropertyName); 515 if (value != null && !value.equals("")) { 516 values[limit.ordinal()] = Integer.parseInt(value); 517 states[limit.ordinal()] = State.JAXPDOTPROPERTIES; 518 return true; 519 } 520 } catch (NumberFormatException e) { 521 //invalid setting 522 throw new NumberFormatException("Invalid setting for system property: " + limit.systemProperty()); 523 } 524 return false; 525 } 526 527 528 /** 529 * Convert a value set through setProperty to XMLSecurityManager. 530 * If the value is an instance of XMLSecurityManager, use it to override the default; 531 * If the value is an old SecurityManager, convert to the new XMLSecurityManager. 532 * 533 * @param value user specified security manager 534 * @param securityManager an instance of XMLSecurityManager 535 * @return an instance of the new security manager XMLSecurityManager 536 */ 537 static public XMLSecurityManager convert(Object value, XMLSecurityManager securityManager) { 538 if (value == null) { 539 if (securityManager == null) { 540 securityManager = new XMLSecurityManager(true); 541 } 542 return securityManager; 543 } 544 if (XMLSecurityManager.class.isAssignableFrom(value.getClass())) { 545 return (XMLSecurityManager)value; 546 } else { 547 if (securityManager == null) { 548 securityManager = new XMLSecurityManager(true); 549 } 550 if (SecurityManager.class.isAssignableFrom(value.getClass())) { 551 SecurityManager origSM = (SecurityManager)value; 552 securityManager.setLimit(Limit.MAX_OCCUR_NODE_LIMIT, State.APIPROPERTY, origSM.getMaxOccurNodeLimit()); 553 securityManager.setLimit(Limit.ENTITY_EXPANSION_LIMIT, State.APIPROPERTY, origSM.getEntityExpansionLimit()); 554 securityManager.setLimit(Limit.ELEMENT_ATTRIBUTE_LIMIT, State.APIPROPERTY, origSM.getElementAttrLimit()); 555 } 556 return securityManager; 557 } 558 } 559 }