1 /*
   2  * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 /*
  21  * $Id: TemplatesImpl.java,v 1.8 2007/03/26 20:12:27 spericas Exp $
  22  */
  23 
  24 package com.sun.org.apache.xalan.internal.xsltc.trax;
  25 
  26 import com.sun.org.apache.xalan.internal.XalanConstants;
  27 import com.sun.org.apache.xalan.internal.utils.ObjectFactory;
  28 import com.sun.org.apache.xalan.internal.xsltc.DOM;
  29 import com.sun.org.apache.xalan.internal.xsltc.Translet;
  30 import com.sun.org.apache.xalan.internal.xsltc.compiler.Constants;
  31 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  32 import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
  33 import java.io.IOException;
  34 import java.io.NotSerializableException;
  35 import java.io.ObjectInputStream;
  36 import java.io.ObjectOutputStream;
  37 import java.io.ObjectStreamField;
  38 import java.io.Serializable;
  39 import java.lang.RuntimePermission;
  40 import java.lang.module.Configuration;
  41 import java.lang.module.ModuleDescriptor;
  42 import java.lang.module.ModuleFinder;
  43 import java.lang.module.ModuleReader;
  44 import java.lang.module.ModuleReference;
  45 import java.lang.reflect.InvocationTargetException;
  46 import java.security.AccessController;
  47 import java.security.CodeSigner;
  48 import java.security.CodeSource;
  49 import java.security.PermissionCollection;
  50 import java.security.PrivilegedAction;
  51 import java.security.ProtectionDomain;
  52 import java.util.Arrays;
  53 import java.util.HashMap;
  54 import java.util.Map;
  55 import java.util.Optional;
  56 import java.util.Properties;
  57 import java.util.Set;
  58 import javax.xml.XMLConstants;
  59 import javax.xml.transform.Templates;
  60 import javax.xml.transform.Transformer;
  61 import javax.xml.transform.TransformerConfigurationException;
  62 import javax.xml.transform.URIResolver;
  63 import jdk.xml.internal.SecuritySupport;
  64 
  65 
  66 /**
  67  * @author Morten Jorgensen
  68  * @author G. Todd Millerj
  69  * @author Jochen Cordes <Jochen.Cordes@t-online.de>
  70  * @author Santiago Pericas-Geertsen
  71  * @LastModified: Nov 2017
  72  */
  73 public final class TemplatesImpl implements Templates, Serializable {
  74     static final long serialVersionUID = 673094361519270707L;
  75     public final static String DESERIALIZE_TRANSLET = "jdk.xml.enableTemplatesImplDeserialization";
  76 
  77     /**
  78      * Name of the superclass of all translets. This is needed to
  79      * determine which, among all classes comprising a translet,
  80      * is the main one.
  81      */
  82     private static String ABSTRACT_TRANSLET
  83         = "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
  84 
  85     /**
  86      * Name of the main class or default name if unknown.
  87      */
  88     private String _name = null;
  89 
  90     /**
  91      * Contains the actual class definition for the translet class and
  92      * any auxiliary classes.
  93      */
  94     private byte[][] _bytecodes = null;
  95 
  96     /**
  97      * Contains the translet class definition(s). These are created when
  98      * this Templates is created or when it is read back from disk.
  99      */
 100     private Class<?>[] _class = null;
 101 
 102     /**
 103      * The index of the main translet class in the arrays _class[] and
 104      * _bytecodes.
 105      */
 106     private int _transletIndex = -1;
 107 
 108     /**
 109      * Contains the list of auxiliary class definitions.
 110      */
 111     private transient Map<String, Class<?>> _auxClasses = null;
 112 
 113     /**
 114      * Output properties of this translet.
 115      */
 116     private Properties _outputProperties;
 117 
 118     /**
 119      * Number of spaces to add for output indentation.
 120      */
 121     private int _indentNumber;
 122 
 123     /**
 124      * This URIResolver is passed to all Transformers.
 125      * Declaring it transient to fix bug 22438
 126      */
 127     private transient URIResolver _uriResolver = null;
 128 
 129     /**
 130      * Cache the DTM for the stylesheet in a thread local variable,
 131      * which is used by the document('') function.
 132      * Use ThreadLocal because a DTM cannot be shared between
 133      * multiple threads.
 134      * Declaring it transient to fix bug 22438
 135      */
 136     private transient ThreadLocal<DOM> _sdom = new ThreadLocal<>();
 137 
 138     /**
 139      * A reference to the transformer factory that this templates
 140      * object belongs to.
 141      */
 142     private transient TransformerFactoryImpl _tfactory = null;
 143 
 144     /**
 145      * A flag to determine whether the Service Mechanism is used
 146      */
 147     private transient boolean _useServicesMechanism;
 148 
 149     /**
 150      * protocols allowed for external references set by the stylesheet processing instruction, Import and Include element.
 151      */
 152     private transient String _accessExternalStylesheet = XalanConstants.EXTERNAL_ACCESS_DEFAULT;
 153 
 154     /**
 155      * @serialField _name String The Name of the main class
 156      * @serialField _bytecodes byte[][] Class definition
 157      * @serialField _class Class[] The translet class definition(s).
 158      * @serialField _transletIndex int The index of the main translet class
 159      * @serialField _outputProperties Properties Output properties of this translet.
 160      * @serialField _indentNumber int Number of spaces to add for output indentation.
 161      */
 162     private static final ObjectStreamField[] serialPersistentFields =
 163         new ObjectStreamField[] {
 164             new ObjectStreamField("_name", String.class),
 165             new ObjectStreamField("_bytecodes", byte[][].class),
 166             new ObjectStreamField("_class", Class[].class),
 167             new ObjectStreamField("_transletIndex", int.class),
 168             new ObjectStreamField("_outputProperties", Properties.class),
 169             new ObjectStreamField("_indentNumber", int.class),
 170         };
 171 
 172     static final class TransletClassLoader extends ClassLoader {
 173         private final Map<String, Class<?>> _loadedExternalExtensionFunctions;
 174 
 175          TransletClassLoader(ClassLoader parent) {
 176              super(parent);
 177             _loadedExternalExtensionFunctions = null;
 178         }
 179 
 180         TransletClassLoader(ClassLoader parent, Map<String, Class<?>> mapEF) {
 181             super(parent);
 182             _loadedExternalExtensionFunctions = mapEF;
 183         }
 184 
 185         @Override
 186         public Class<?> loadClass(String name) throws ClassNotFoundException {
 187             Class<?> ret = null;
 188             // The _loadedExternalExtensionFunctions will be empty when the
 189             // SecurityManager is not set and the FSP is turned off
 190             if (_loadedExternalExtensionFunctions != null) {
 191                 ret = _loadedExternalExtensionFunctions.get(name);
 192             }
 193             if (ret == null) {
 194                 ret = super.loadClass(name);
 195             }
 196             return ret;
 197          }
 198 
 199         /**
 200          * Access to final protected superclass member from outer class.
 201          */
 202         Class<?> defineClass(final byte[] b) {
 203             return defineClass(null, b, 0, b.length);
 204         }
 205 
 206         Class<?> defineClass(final byte[] b, ProtectionDomain pd) {
 207             return defineClass(null, b, 0, b.length, pd);
 208         }
 209     }
 210 
 211 
 212     /**
 213      * Create an XSLTC template object from the bytecodes.
 214      * The bytecodes for the translet and auxiliary classes, plus the name of
 215      * the main translet class, must be supplied.
 216      */
 217     protected TemplatesImpl(byte[][] bytecodes, String transletName,
 218         Properties outputProperties, int indentNumber,
 219         TransformerFactoryImpl tfactory)
 220     {
 221         _bytecodes = bytecodes;
 222         init(transletName, outputProperties, indentNumber, tfactory);
 223     }
 224 
 225     /**
 226      * Create an XSLTC template object from the translet class definition(s).
 227      */
 228     protected TemplatesImpl(Class<?>[] transletClasses, String transletName,
 229         Properties outputProperties, int indentNumber,
 230         TransformerFactoryImpl tfactory)
 231     {
 232         _class     = transletClasses;
 233         _transletIndex = 0;
 234         init(transletName, outputProperties, indentNumber, tfactory);
 235     }
 236 
 237     private void init(String transletName,
 238         Properties outputProperties, int indentNumber,
 239         TransformerFactoryImpl tfactory) {
 240         _name      = transletName;
 241         _outputProperties = outputProperties;
 242         _indentNumber = indentNumber;
 243         _tfactory = tfactory;
 244         _useServicesMechanism = tfactory.useServicesMechnism();
 245         _accessExternalStylesheet = (String) tfactory.getAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET);
 246     }
 247     /**
 248      * Need for de-serialization, see readObject().
 249      */
 250     public TemplatesImpl() { }
 251 
 252     /**
 253      *  Overrides the default readObject implementation since we decided
 254      *  it would be cleaner not to serialize the entire tranformer
 255      *  factory.  [ ref bugzilla 12317 ]
 256      *  We need to check if the user defined class for URIResolver also
 257      *  implemented Serializable
 258      *  if yes then we need to deserialize the URIResolver
 259      *  Fix for bugzilla bug 22438
 260      */
 261     @SuppressWarnings("unchecked")
 262     private void  readObject(ObjectInputStream is)
 263       throws IOException, ClassNotFoundException
 264     {
 265         SecurityManager security = System.getSecurityManager();
 266         if (security != null){
 267             String temp = SecuritySupport.getSystemProperty(DESERIALIZE_TRANSLET);
 268             if (temp == null || !(temp.length()==0 || temp.equalsIgnoreCase("true"))) {
 269                 ErrorMsg err = new ErrorMsg(ErrorMsg.DESERIALIZE_TRANSLET_ERR);
 270                 throw new UnsupportedOperationException(err.toString());
 271             }
 272         }
 273 
 274         // We have to read serialized fields first.
 275         ObjectInputStream.GetField gf = is.readFields();
 276         _name = (String)gf.get("_name", null);
 277         _bytecodes = (byte[][])gf.get("_bytecodes", null);
 278         _class = (Class<?>[])gf.get("_class", null);
 279         _transletIndex = gf.get("_transletIndex", -1);
 280 
 281         _outputProperties = (Properties)gf.get("_outputProperties", null);
 282         _indentNumber = gf.get("_indentNumber", 0);
 283 
 284         if (is.readBoolean()) {
 285             _uriResolver = (URIResolver) is.readObject();
 286         }
 287 
 288         _tfactory = new TransformerFactoryImpl();
 289     }
 290 
 291 
 292     /**
 293      *  This is to fix bugzilla bug 22438
 294      *  If the user defined class implements URIResolver and Serializable
 295      *  then we want it to get serialized
 296      */
 297     private void writeObject(ObjectOutputStream os)
 298         throws IOException, ClassNotFoundException {
 299         if (_auxClasses != null) {
 300             //throw with the same message as when Hashtable was used for compatibility.
 301             throw new NotSerializableException(
 302                     "com.sun.org.apache.xalan.internal.xsltc.runtime.Hashtable");
 303         }
 304 
 305         // Write serialized fields
 306         ObjectOutputStream.PutField pf = os.putFields();
 307         pf.put("_name", _name);
 308         pf.put("_bytecodes", _bytecodes);
 309         pf.put("_class", _class);
 310         pf.put("_transletIndex", _transletIndex);
 311         pf.put("_outputProperties", _outputProperties);
 312         pf.put("_indentNumber", _indentNumber);
 313         os.writeFields();
 314 
 315         if (_uriResolver instanceof Serializable) {
 316             os.writeBoolean(true);
 317             os.writeObject((Serializable) _uriResolver);
 318         }
 319         else {
 320             os.writeBoolean(false);
 321         }
 322     }
 323 
 324     /**
 325      * Return the state of the services mechanism feature.
 326      */
 327     public boolean useServicesMechnism() {
 328         return _useServicesMechanism;
 329     }
 330 
 331      /**
 332      * Store URIResolver needed for Transformers.
 333      */
 334     public synchronized void setURIResolver(URIResolver resolver) {
 335         _uriResolver = resolver;
 336     }
 337 
 338     /**
 339      * The TransformerFactory must pass us the translet bytecodes using this
 340      * method before we can create any translet instances
 341      *
 342      * Note: This method is private for security reasons. See
 343      * CR 6537898. When merging with Apache, we must ensure
 344      * that the privateness of this method is maintained (that
 345      * is why it wasn't removed).
 346      */
 347     private synchronized void setTransletBytecodes(byte[][] bytecodes) {
 348         _bytecodes = bytecodes;
 349     }
 350 
 351     /**
 352      * Returns the translet bytecodes stored in this template
 353      *
 354      * Note: This method is private for security reasons. See
 355      * CR 6537898. When merging with Apache, we must ensure
 356      * that the privateness of this method is maintained (that
 357      * is why it wasn't removed).
 358      */
 359     private synchronized byte[][] getTransletBytecodes() {
 360         return _bytecodes;
 361     }
 362 
 363     /**
 364      * Returns the translet bytecodes stored in this template
 365      *
 366      * Note: This method is private for security reasons. See
 367      * CR 6537898. When merging with Apache, we must ensure
 368      * that the privateness of this method is maintained (that
 369      * is why it wasn't removed).
 370      */
 371     private synchronized Class<?>[] getTransletClasses() {
 372         try {
 373             if (_class == null) defineTransletClasses();
 374         }
 375         catch (TransformerConfigurationException e) {
 376             // Falls through
 377         }
 378         return _class;
 379     }
 380 
 381     /**
 382      * Returns the index of the main class in array of bytecodes
 383      */
 384     public synchronized int getTransletIndex() {
 385         try {
 386             if (_class == null) defineTransletClasses();
 387         }
 388         catch (TransformerConfigurationException e) {
 389             // Falls through
 390         }
 391         return _transletIndex;
 392     }
 393 
 394     /**
 395      * The TransformerFactory should call this method to set the translet name
 396      */
 397     protected synchronized void setTransletName(String name) {
 398         _name = name;
 399     }
 400 
 401     /**
 402      * Returns the name of the main translet class stored in this template
 403      */
 404     protected synchronized String getTransletName() {
 405         return _name;
 406     }
 407 
 408 
 409     /**
 410      * Creates a module layer with one module that is defined to the given class
 411      * loader.
 412      */
 413     private Module createModule(ModuleDescriptor descriptor, ClassLoader loader) {
 414         String mn = descriptor.name();
 415 
 416         ModuleReference mref = new ModuleReference(descriptor, null) {
 417             @Override
 418             public ModuleReader open() {
 419                 throw new UnsupportedOperationException();
 420             }
 421         };
 422 
 423         ModuleFinder finder = new ModuleFinder() {
 424             @Override
 425             public Optional<ModuleReference> find(String name) {
 426                 if (name.equals(mn)) {
 427                     return Optional.of(mref);
 428                 } else {
 429                     return Optional.empty();
 430                 }
 431             }
 432             @Override
 433             public Set<ModuleReference> findAll() {
 434                 return Set.of(mref);
 435             }
 436         };
 437 
 438         ModuleLayer bootLayer = ModuleLayer.boot();
 439 
 440         Configuration cf = bootLayer.configuration()
 441                 .resolve(finder, ModuleFinder.of(), Set.of(mn));
 442 
 443         PrivilegedAction<ModuleLayer> pa = () -> bootLayer.defineModules(cf, name -> loader);
 444         ModuleLayer layer = AccessController.doPrivileged(pa);
 445 
 446         Module m = layer.findModule(mn).get();
 447         assert m.getLayer() == layer;
 448 
 449         return m;
 450     }
 451 
 452     /**
 453      * Defines the translet class and auxiliary classes.
 454      * Returns a reference to the Class object that defines the main class
 455      */
 456     private void defineTransletClasses()
 457         throws TransformerConfigurationException {
 458 
 459         if (_bytecodes == null) {
 460             ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);
 461             throw new TransformerConfigurationException(err.toString());
 462         }
 463 
 464         TransletClassLoader loader =
 465                 AccessController.doPrivileged(new PrivilegedAction<TransletClassLoader>() {
 466                 public TransletClassLoader run() {
 467                     return new TransletClassLoader(ObjectFactory.findClassLoader(),
 468                             _tfactory.getExternalExtensionsMap());
 469                 }
 470             });
 471 
 472         try {
 473             final int classCount = _bytecodes.length;
 474             _class = new Class<?>[classCount];
 475 
 476             if (classCount > 1) {
 477                 _auxClasses = new HashMap<>();
 478             }
 479 
 480             // create a module for the translet
 481 
 482             String mn = "jdk.translet";
 483 
 484             String pn = _tfactory.getPackageName();
 485             assert pn != null && pn.length() > 0;
 486 
 487             ModuleDescriptor descriptor =
 488                 ModuleDescriptor.newModule(mn, Set.of(ModuleDescriptor.Modifier.SYNTHETIC))
 489                                 .requires("java.xml")
 490                                 .exports(pn, Set.of("java.xml"))
 491                                 .build();
 492 
 493             Module m = createModule(descriptor, loader);
 494 
 495             // the module needs access to runtime classes
 496             Module thisModule = TemplatesImpl.class.getModule();
 497             // the module also needs permission to access each package
 498             // that is exported to it
 499             PermissionCollection perms =
 500                 new RuntimePermission("*").newPermissionCollection();
 501             Arrays.asList(Constants.PKGS_USED_BY_TRANSLET_CLASSES).forEach(p -> {
 502                 thisModule.addExports(p, m);
 503                 perms.add(new RuntimePermission("accessClassInPackage." + p));
 504             });
 505 
 506             CodeSource codeSource = new CodeSource(null, (CodeSigner[])null);
 507             ProtectionDomain pd = new ProtectionDomain(codeSource, perms,
 508                                                        loader, null);
 509 
 510             // java.xml needs to instantiate the translet class
 511             thisModule.addReads(m);
 512 
 513             for (int i = 0; i < classCount; i++) {
 514                 _class[i] = loader.defineClass(_bytecodes[i], pd);
 515                 final Class<?> superClass = _class[i].getSuperclass();
 516 
 517                 // Check if this is the main class
 518                 if (superClass.getName().equals(ABSTRACT_TRANSLET)) {
 519                     _transletIndex = i;
 520                 }
 521                 else {
 522                     _auxClasses.put(_class[i].getName(), _class[i]);
 523                 }
 524             }
 525 
 526             if (_transletIndex < 0) {
 527                 ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);
 528                 throw new TransformerConfigurationException(err.toString());
 529             }
 530         }
 531         catch (ClassFormatError e) {
 532             ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name);
 533             throw new TransformerConfigurationException(err.toString(), e);
 534         }
 535         catch (LinkageError e) {
 536             ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
 537             throw new TransformerConfigurationException(err.toString(), e);
 538         }
 539     }
 540 
 541     /**
 542      * This method generates an instance of the translet class that is
 543      * wrapped inside this Template. The translet instance will later
 544      * be wrapped inside a Transformer object.
 545      */
 546     private Translet getTransletInstance()
 547         throws TransformerConfigurationException {
 548         try {
 549             if (_name == null) return null;
 550 
 551             if (_class == null) defineTransletClasses();
 552 
 553             // The translet needs to keep a reference to all its auxiliary
 554             // class to prevent the GC from collecting them
 555             AbstractTranslet translet = (AbstractTranslet)
 556                     _class[_transletIndex].getConstructor().newInstance();
 557             translet.postInitialization();
 558             translet.setTemplates(this);
 559             translet.setServicesMechnism(_useServicesMechanism);
 560             translet.setAllowedProtocols(_accessExternalStylesheet);
 561             if (_auxClasses != null) {
 562                 translet.setAuxiliaryClasses(_auxClasses);
 563             }
 564 
 565             return translet;
 566         }
 567         catch (InstantiationException | IllegalAccessException |
 568                 NoSuchMethodException | InvocationTargetException e) {
 569             ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
 570             throw new TransformerConfigurationException(err.toString(), e);
 571         }
 572     }
 573 
 574     /**
 575      * Implements JAXP's Templates.newTransformer()
 576      *
 577      * @throws TransformerConfigurationException
 578      */
 579     public synchronized Transformer newTransformer()
 580         throws TransformerConfigurationException
 581     {
 582         TransformerImpl transformer;
 583 
 584         transformer = new TransformerImpl(getTransletInstance(), _outputProperties,
 585             _indentNumber, _tfactory);
 586 
 587         if (_uriResolver != null) {
 588             transformer.setURIResolver(_uriResolver);
 589         }
 590 
 591         if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) {
 592             transformer.setSecureProcessing(true);
 593         }
 594         return transformer;
 595     }
 596 
 597     /**
 598      * Implements JAXP's Templates.getOutputProperties(). We need to
 599      * instanciate a translet to get the output settings, so
 600      * we might as well just instanciate a Transformer and use its
 601      * implementation of this method.
 602      */
 603     public synchronized Properties getOutputProperties() {
 604         try {
 605             return newTransformer().getOutputProperties();
 606         }
 607         catch (TransformerConfigurationException e) {
 608             return null;
 609         }
 610     }
 611 
 612     /**
 613      * Return the thread local copy of the stylesheet DOM.
 614      */
 615     public DOM getStylesheetDOM() {
 616         return _sdom.get();
 617     }
 618 
 619     /**
 620      * Set the thread local copy of the stylesheet DOM.
 621      */
 622     public void setStylesheetDOM(DOM sdom) {
 623         _sdom.set(sdom);
 624     }
 625 }