1 /*
2  * Copyright (c) 2007, 2021, 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.utils.ObjectFactory;
27 import com.sun.org.apache.xalan.internal.xsltc.DOM;
28 import com.sun.org.apache.xalan.internal.xsltc.Translet;
29 import com.sun.org.apache.xalan.internal.xsltc.compiler.Constants;
30 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
31 import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
32 import java.io.IOException;
33 import java.io.NotSerializableException;
34 import java.io.ObjectInputStream;
35 import java.io.ObjectOutputStream;
36 import java.io.ObjectStreamField;
37 import java.io.Serializable;
38 import java.lang.RuntimePermission;
39 import java.lang.module.Configuration;
40 import java.lang.module.ModuleDescriptor;
41 import java.lang.module.ModuleFinder;
42 import java.lang.module.ModuleReader;
43 import java.lang.module.ModuleReference;
44 import java.lang.reflect.InvocationTargetException;
45 import java.security.AccessController;
46 import java.security.CodeSigner;
47 import java.security.CodeSource;
48 import java.security.PermissionCollection;
49 import java.security.PrivilegedAction;
50 import java.security.ProtectionDomain;
51 import java.util.Arrays;
52 import java.util.HashMap;
53 import java.util.Map;
54 import java.util.Optional;
55 import java.util.Properties;
56 import java.util.Set;
57 import javax.xml.XMLConstants;
58 import javax.xml.transform.Templates;
59 import javax.xml.transform.Transformer;
60 import javax.xml.transform.TransformerConfigurationException;
61 import javax.xml.transform.URIResolver;
62 import jdk.xml.internal.JdkConstants;
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: May 2021
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 system-default parser may be overridden
146      */
147     private transient boolean _overrideDefaultParser;
148 
149     /**
150      * protocols allowed for external references set by the stylesheet processing instruction, Import and Include element.
151      */
152     private transient String _accessExternalStylesheet = JdkConstants.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 
TransletClassLoader(ClassLoader parent)175          TransletClassLoader(ClassLoader parent) {
176              super(parent);
177             _loadedExternalExtensionFunctions = null;
178         }
179 
TransletClassLoader(ClassLoader parent, Map<String, Class<?>> mapEF)180         TransletClassLoader(ClassLoader parent, Map<String, Class<?>> mapEF) {
181             super(parent);
182             _loadedExternalExtensionFunctions = mapEF;
183         }
184 
185         @Override
loadClass(String name)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          */
defineClass(final byte[] b)202         Class<?> defineClass(final byte[] b) {
203             return defineClass(null, b, 0, b.length);
204         }
205 
defineClass(final byte[] b, ProtectionDomain pd)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      */
TemplatesImpl(byte[][] bytecodes, String transletName, Properties outputProperties, int indentNumber, TransformerFactoryImpl tfactory)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      */
TemplatesImpl(Class<?>[] transletClasses, String transletName, Properties outputProperties, int indentNumber, TransformerFactoryImpl tfactory)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 
init(String transletName, Properties outputProperties, int indentNumber, TransformerFactoryImpl tfactory)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         _overrideDefaultParser = tfactory.overrideDefaultParser();
245         _accessExternalStylesheet = (String) tfactory.getAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET);
246     }
247     /**
248      * Need for de-serialization, see readObject().
249      */
TemplatesImpl()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")
readObject(ObjectInputStream is)262     private void  readObject(ObjectInputStream is)
263       throws IOException, ClassNotFoundException
264     {
265         @SuppressWarnings("removal")
266         SecurityManager security = System.getSecurityManager();
267         if (security != null){
268             String temp = SecuritySupport.getSystemProperty(DESERIALIZE_TRANSLET);
269             if (temp == null || !(temp.length()==0 || temp.equalsIgnoreCase("true"))) {
270                 ErrorMsg err = new ErrorMsg(ErrorMsg.DESERIALIZE_TRANSLET_ERR);
271                 throw new UnsupportedOperationException(err.toString());
272             }
273         }
274 
275         // We have to read serialized fields first.
276         ObjectInputStream.GetField gf = is.readFields();
277         _name = (String)gf.get("_name", null);
278         _bytecodes = (byte[][])gf.get("_bytecodes", null);
279         _class = (Class<?>[])gf.get("_class", null);
280         _transletIndex = gf.get("_transletIndex", -1);
281 
282         _outputProperties = (Properties)gf.get("_outputProperties", null);
283         _indentNumber = gf.get("_indentNumber", 0);
284 
285         if (is.readBoolean()) {
286             _uriResolver = (URIResolver) is.readObject();
287         }
288 
289         _tfactory = new TransformerFactoryImpl();
290     }
291 
292 
293     /**
294      *  This is to fix bugzilla bug 22438
295      *  If the user defined class implements URIResolver and Serializable
296      *  then we want it to get serialized
297      */
writeObject(ObjectOutputStream os)298     private void writeObject(ObjectOutputStream os)
299         throws IOException {
300         if (_auxClasses != null) {
301             //throw with the same message as when Hashtable was used for compatibility.
302             throw new NotSerializableException(
303                     "com.sun.org.apache.xalan.internal.xsltc.runtime.Hashtable");
304         }
305 
306         // Write serialized fields
307         ObjectOutputStream.PutField pf = os.putFields();
308         pf.put("_name", _name);
309         pf.put("_bytecodes", _bytecodes);
310         pf.put("_class", _class);
311         pf.put("_transletIndex", _transletIndex);
312         pf.put("_outputProperties", _outputProperties);
313         pf.put("_indentNumber", _indentNumber);
314         os.writeFields();
315 
316         if (_uriResolver instanceof Serializable) {
317             os.writeBoolean(true);
318             os.writeObject((Serializable) _uriResolver);
319         }
320         else {
321             os.writeBoolean(false);
322         }
323     }
324 
325     /**
326      * Return the state of the services mechanism feature.
327      */
overrideDefaultParser()328     public boolean overrideDefaultParser() {
329         return _overrideDefaultParser;
330     }
331 
332      /**
333      * Store URIResolver needed for Transformers.
334      */
setURIResolver(URIResolver resolver)335     public synchronized void setURIResolver(URIResolver resolver) {
336         _uriResolver = resolver;
337     }
338 
339     /**
340      * The TransformerFactory must pass us the translet bytecodes using this
341      * method before we can create any translet instances
342      *
343      * Note: This method is private for security reasons. See
344      * CR 6537898. When merging with Apache, we must ensure
345      * that the privateness of this method is maintained (that
346      * is why it wasn't removed).
347      */
setTransletBytecodes(byte[][] bytecodes)348     private synchronized void setTransletBytecodes(byte[][] bytecodes) {
349         _bytecodes = bytecodes;
350     }
351 
352     /**
353      * Returns the translet bytecodes stored in this template
354      *
355      * Note: This method is private for security reasons. See
356      * CR 6537898. When merging with Apache, we must ensure
357      * that the privateness of this method is maintained (that
358      * is why it wasn't removed).
359      */
getTransletBytecodes()360     private synchronized byte[][] getTransletBytecodes() {
361         return _bytecodes;
362     }
363 
364     /**
365      * Returns the translet bytecodes stored in this template
366      *
367      * Note: This method is private for security reasons. See
368      * CR 6537898. When merging with Apache, we must ensure
369      * that the privateness of this method is maintained (that
370      * is why it wasn't removed).
371      */
getTransletClasses()372     private synchronized Class<?>[] getTransletClasses() {
373         try {
374             if (_class == null) defineTransletClasses();
375         }
376         catch (TransformerConfigurationException e) {
377             // Falls through
378         }
379         return _class;
380     }
381 
382     /**
383      * Returns the index of the main class in array of bytecodes
384      */
getTransletIndex()385     public synchronized int getTransletIndex() {
386         try {
387             if (_class == null) defineTransletClasses();
388         }
389         catch (TransformerConfigurationException e) {
390             // Falls through
391         }
392         return _transletIndex;
393     }
394 
395     /**
396      * The TransformerFactory should call this method to set the translet name
397      */
setTransletName(String name)398     protected synchronized void setTransletName(String name) {
399         _name = name;
400     }
401 
402     /**
403      * Returns the name of the main translet class stored in this template
404      */
getTransletName()405     protected synchronized String getTransletName() {
406         return _name;
407     }
408 
409 
410     /**
411      * Creates a module layer with one module that is defined to the given class
412      * loader.
413      */
createModule(ModuleDescriptor descriptor, ClassLoader loader)414     private Module createModule(ModuleDescriptor descriptor, ClassLoader loader) {
415         String mn = descriptor.name();
416 
417         ModuleReference mref = new ModuleReference(descriptor, null) {
418             @Override
419             public ModuleReader open() {
420                 throw new UnsupportedOperationException();
421             }
422         };
423 
424         ModuleFinder finder = new ModuleFinder() {
425             @Override
426             public Optional<ModuleReference> find(String name) {
427                 if (name.equals(mn)) {
428                     return Optional.of(mref);
429                 } else {
430                     return Optional.empty();
431                 }
432             }
433             @Override
434             public Set<ModuleReference> findAll() {
435                 return Set.of(mref);
436             }
437         };
438 
439         ModuleLayer bootLayer = ModuleLayer.boot();
440 
441         Configuration cf = bootLayer.configuration()
442                 .resolve(finder, ModuleFinder.of(), Set.of(mn));
443 
444         PrivilegedAction<ModuleLayer> pa = () -> bootLayer.defineModules(cf, name -> loader);
445         @SuppressWarnings("removal")
446         ModuleLayer layer = AccessController.doPrivileged(pa);
447 
448         Module m = layer.findModule(mn).get();
449         assert m.getLayer() == layer;
450 
451         return m;
452     }
453 
454     /**
455      * Defines the translet class and auxiliary classes.
456      * Returns a reference to the Class object that defines the main class
457      */
defineTransletClasses()458     private void defineTransletClasses()
459         throws TransformerConfigurationException {
460 
461         if (_bytecodes == null) {
462             ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);
463             throw new TransformerConfigurationException(err.toString());
464         }
465 
466         @SuppressWarnings("removal")
467         TransletClassLoader loader =
468                 AccessController.doPrivileged(new PrivilegedAction<TransletClassLoader>() {
469                 public TransletClassLoader run() {
470                     return new TransletClassLoader(ObjectFactory.findClassLoader(),
471                             _tfactory.getExternalExtensionsMap());
472                 }
473             });
474 
475         try {
476             final int classCount = _bytecodes.length;
477             _class = new Class<?>[classCount];
478 
479             if (classCount > 1) {
480                 _auxClasses = new HashMap<>();
481             }
482 
483             // create a module for the translet
484 
485             String mn = "jdk.translet";
486 
487             String pn = _tfactory.getPackageName();
488             assert pn != null && pn.length() > 0;
489 
490             ModuleDescriptor descriptor =
491                 ModuleDescriptor.newModule(mn, Set.of(ModuleDescriptor.Modifier.SYNTHETIC))
492                                 .requires("java.xml")
493                                 .exports(pn, Set.of("java.xml"))
494                                 .build();
495 
496             Module m = createModule(descriptor, loader);
497 
498             // the module needs access to runtime classes
499             Module thisModule = TemplatesImpl.class.getModule();
500             // the module also needs permission to access each package
501             // that is exported to it
502             PermissionCollection perms =
503                 new RuntimePermission("*").newPermissionCollection();
504             Arrays.asList(Constants.PKGS_USED_BY_TRANSLET_CLASSES).forEach(p -> {
505                 thisModule.addExports(p, m);
506                 perms.add(new RuntimePermission("accessClassInPackage." + p));
507             });
508 
509             CodeSource codeSource = new CodeSource(null, (CodeSigner[])null);
510             ProtectionDomain pd = new ProtectionDomain(codeSource, perms,
511                                                        loader, null);
512 
513             // java.xml needs to instantiate the translet class
514             thisModule.addReads(m);
515 
516             for (int i = 0; i < classCount; i++) {
517                 _class[i] = loader.defineClass(_bytecodes[i], pd);
518                 final Class<?> superClass = _class[i].getSuperclass();
519 
520                 // Check if this is the main class
521                 if (superClass.getName().equals(ABSTRACT_TRANSLET)) {
522                     _transletIndex = i;
523                 }
524                 else {
525                     _auxClasses.put(_class[i].getName(), _class[i]);
526                 }
527             }
528 
529             if (_transletIndex < 0) {
530                 ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);
531                 throw new TransformerConfigurationException(err.toString());
532             }
533         }
534         catch (ClassFormatError e) {
535             ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name);
536             throw new TransformerConfigurationException(err.toString(), e);
537         }
538         catch (LinkageError e) {
539             ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
540             throw new TransformerConfigurationException(err.toString(), e);
541         }
542     }
543 
544     /**
545      * This method generates an instance of the translet class that is
546      * wrapped inside this Template. The translet instance will later
547      * be wrapped inside a Transformer object.
548      */
getTransletInstance()549     private Translet getTransletInstance()
550         throws TransformerConfigurationException {
551         try {
552             if (_name == null) return null;
553 
554             if (_class == null) defineTransletClasses();
555 
556             // The translet needs to keep a reference to all its auxiliary
557             // class to prevent the GC from collecting them
558             AbstractTranslet translet = (AbstractTranslet)
559                     _class[_transletIndex].getConstructor().newInstance();
560             translet.postInitialization();
561             translet.setTemplates(this);
562             translet.setOverrideDefaultParser(_overrideDefaultParser);
563             translet.setAllowedProtocols(_accessExternalStylesheet);
564             if (_auxClasses != null) {
565                 translet.setAuxiliaryClasses(_auxClasses);
566             }
567 
568             return translet;
569         }
570         catch (InstantiationException | IllegalAccessException |
571                 NoSuchMethodException | InvocationTargetException e) {
572             ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
573             throw new TransformerConfigurationException(err.toString(), e);
574         }
575     }
576 
577     /**
578      * Implements JAXP's Templates.newTransformer()
579      *
580      * @throws TransformerConfigurationException
581      */
newTransformer()582     public synchronized Transformer newTransformer()
583         throws TransformerConfigurationException
584     {
585         TransformerImpl transformer;
586 
587         transformer = new TransformerImpl(getTransletInstance(), _outputProperties,
588             _indentNumber, _tfactory);
589 
590         if (_uriResolver != null) {
591             transformer.setURIResolver(_uriResolver);
592         }
593 
594         if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) {
595             transformer.setSecureProcessing(true);
596         }
597         return transformer;
598     }
599 
600     /**
601      * Implements JAXP's Templates.getOutputProperties(). We need to
602      * instanciate a translet to get the output settings, so
603      * we might as well just instanciate a Transformer and use its
604      * implementation of this method.
605      */
getOutputProperties()606     public synchronized Properties getOutputProperties() {
607         try {
608             return newTransformer().getOutputProperties();
609         }
610         catch (TransformerConfigurationException e) {
611             return null;
612         }
613     }
614 
615     /**
616      * Return the thread local copy of the stylesheet DOM.
617      */
getStylesheetDOM()618     public DOM getStylesheetDOM() {
619         return _sdom.get();
620     }
621 
622     /**
623      * Set the thread local copy of the stylesheet DOM.
624      */
setStylesheetDOM(DOM sdom)625     public void setStylesheetDOM(DOM sdom) {
626         _sdom.set(sdom);
627     }
628 }
629