Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP2:Update
postgresql-jdbc.27335
0001-Fix-for-XXE-vulnerability.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0001-Fix-for-XXE-vulnerability.patch of Package postgresql-jdbc.27335
From 9118df20563b924727960c31316d6d2f88854452 Mon Sep 17 00:00:00 2001 From: Ondrej Dubaj <odubaj@redhat.com> Date: Fri, 24 Jul 2020 14:08:54 +0200 Subject: [PATCH] Fix for XXE vulnerability by defaulting to disabling external access and doc types. The legacy insecure behavior can be restored via the new connection property xmlFactoryFactory with a value of LEGACY_INSECURE. Alternatively, a custom class name can be specified that implements org.postgresql.xml.PGXmlFactoryFactory and takes a no argument constructor. * refactor: Clean up whitespace in existing PgSQLXMLTest * fix: Fix XXE vulnerability in PgSQLXML by disabling external access and doctypes * fix: Add missing getter and setter for XML_FACTORY_FACTORY to BasicDataSource --- build.xml | 4 + org/postgresql/PGProperty.java | 5 + org/postgresql/core/BaseConnection.java | 9 ++ org/postgresql/ds/common/BaseDataSource.java | 7 + org/postgresql/jdbc4/Jdbc4Connection.java | 44 ++++++ org/postgresql/jdbc4/Jdbc4SQLXML.java | 37 +++-- .../xml/DefaultPGXmlFactoryFactory.java | 140 ++++++++++++++++++ .../xml/EmptyStringEntityResolver.java | 23 +++ .../LegacyInsecurePGXmlFactoryFactory.java | 57 +++++++ org/postgresql/xml/NullErrorHandler.java | 25 ++++ org/postgresql/xml/PGXmlFactoryFactory.java | 30 ++++ 11 files changed, 361 insertions(+), 20 deletions(-) create mode 100644 org/postgresql/xml/DefaultPGXmlFactoryFactory.java create mode 100644 org/postgresql/xml/EmptyStringEntityResolver.java create mode 100644 org/postgresql/xml/LegacyInsecurePGXmlFactoryFactory.java create mode 100644 org/postgresql/xml/NullErrorHandler.java create mode 100644 org/postgresql/xml/PGXmlFactoryFactory.java diff --git a/build.xml b/build.xml index 29bab602..1a18d71e 100644 --- a/build.xml +++ b/build.xml @@ -48,6 +48,7 @@ <include name="${package}/largeobject/**" /> <include name="${package}/hostchooser/**" /> <include name="${package}/util/**" /> + <include name="${package}/xml/**" /> <!-- Each jdbcN subpackage is used only if the driver supports *at least* that @@ -111,6 +112,9 @@ <include name="${package}/xa/jdbc3/*.java"/> <include name="${package}/xa/jdbc4/*.java" if="jdbc4any"/> + <!-- XML stuff --> + <include name="${package}/xml/*.java" if="jdbc4any" /> + <!-- OSGi package --> <include name="${package}/osgi/*.java"/> </patternset> diff --git a/org/postgresql/PGProperty.java b/org/postgresql/PGProperty.java index f8c0be54..1f739e1d 100644 --- a/org/postgresql/PGProperty.java +++ b/org/postgresql/PGProperty.java @@ -220,6 +220,11 @@ public enum PGProperty */ KERBEROS_SERVER_NAME("kerberosServerName", null, "The Kerberos service name to use when authenticating with GSSAPI."), + /** + * Factory class to instantiate factories for XML processing. + */ + XML_FACTORY_FACTORY("xmlFactoryFactory", "", "Factory class to instantiate factories for XML processing."), + /** * Use SPNEGO in SSPI authentication requests */ diff --git a/org/postgresql/core/BaseConnection.java b/org/postgresql/core/BaseConnection.java index 8ffa1ace..3fd6ac35 100644 --- a/org/postgresql/core/BaseConnection.java +++ b/org/postgresql/core/BaseConnection.java @@ -11,6 +11,7 @@ import java.util.TimerTask; import java.sql.*; import org.postgresql.PGConnection; import org.postgresql.jdbc2.TimestampUtils; +import org.postgresql.xml.PGXmlFactoryFactory; /** * Driver-internal connection interface. Application code should not use @@ -208,4 +209,12 @@ public interface BaseConnection extends PGConnection, Connection * Invoke purge() on the underlying shared Timer so that internal resources will be released. */ public void purgeTimerTasks(); + + /** + * Retrieve the factory to instantiate XML processing factories. + * + * @return The factory to use to instantiate XML processing factories + * @throws SQLException if the class cannot be found or instantiated. + */ + PGXmlFactoryFactory getXmlFactoryFactory() throws SQLException; } diff --git a/org/postgresql/ds/common/BaseDataSource.java b/org/postgresql/ds/common/BaseDataSource.java index bd6f79a7..73c6886c 100644 --- a/org/postgresql/ds/common/BaseDataSource.java +++ b/org/postgresql/ds/common/BaseDataSource.java @@ -1133,4 +1133,11 @@ public abstract class BaseDataSource implements Referenceable readBaseObject(ois); } + public String getXmlFactoryFactory() { + return PGProperty.XML_FACTORY_FACTORY.get(properties); + } + + public void setXmlFactoryFactory(String xmlFactoryFactory) { + PGProperty.XML_FACTORY_FACTORY.set(properties, xmlFactoryFactory); + } } diff --git a/org/postgresql/jdbc4/Jdbc4Connection.java b/org/postgresql/jdbc4/Jdbc4Connection.java index c16ca534..173d3752 100644 --- a/org/postgresql/jdbc4/Jdbc4Connection.java +++ b/org/postgresql/jdbc4/Jdbc4Connection.java @@ -10,6 +10,12 @@ package org.postgresql.jdbc4; import java.util.Map; import java.util.Properties; import java.sql.SQLException; +import org.postgresql.util.GT; +import org.postgresql.util.PSQLState; +import org.postgresql.xml.DefaultPGXmlFactoryFactory; +import org.postgresql.xml.LegacyInsecurePGXmlFactoryFactory; +import org.postgresql.xml.PGXmlFactoryFactory; +import org.postgresql.util.PSQLException; import org.postgresql.util.HostSpec; @@ -20,8 +26,13 @@ import org.postgresql.util.HostSpec; */ public class Jdbc4Connection extends AbstractJdbc4Connection implements java.sql.Connection { + + private final String xmlFactoryFactoryClass; + private PGXmlFactoryFactory xmlFactoryFactory; + public Jdbc4Connection(HostSpec[] hostSpecs, String user, String database, Properties info, String url) throws SQLException { super(hostSpecs, user, database, info, url); + xmlFactoryFactoryClass = info.getProperty("xmlFactoryFactory"); } public java.sql.Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException @@ -62,4 +73,37 @@ public class Jdbc4Connection extends AbstractJdbc4Connection implements java.sql setTypeMapImpl(map); } + @Override + public PGXmlFactoryFactory getXmlFactoryFactory() throws SQLException { + if (xmlFactoryFactory == null) { + if (xmlFactoryFactoryClass == null || xmlFactoryFactoryClass.equals("")) { + xmlFactoryFactory = DefaultPGXmlFactoryFactory.INSTANCE; + } else if (xmlFactoryFactoryClass.equals("LEGACY_INSECURE")) { + xmlFactoryFactory = LegacyInsecurePGXmlFactoryFactory.INSTANCE; + } else { + Class<?> clazz; + try { + clazz = Class.forName(xmlFactoryFactoryClass); + } catch (ClassNotFoundException ex) { + throw new PSQLException( + GT.tr("Could not instantiate xmlFactoryFactory: {0}", xmlFactoryFactoryClass), + PSQLState.INVALID_PARAMETER_VALUE, ex); + } + if (!clazz.isAssignableFrom(PGXmlFactoryFactory.class)) { + throw new PSQLException( + GT.tr("Connection property xmlFactoryFactory must implement PGXmlFactoryFactory: {0}", xmlFactoryFactoryClass), + PSQLState.INVALID_PARAMETER_VALUE); + } + try { + xmlFactoryFactory = (PGXmlFactoryFactory) clazz.newInstance(); + } catch (Exception ex) { + throw new PSQLException( + GT.tr("Could not instantiate xmlFactoryFactory: {0}", xmlFactoryFactoryClass), + PSQLState.INVALID_PARAMETER_VALUE, ex); + } + } + } + return xmlFactoryFactory; + } + } diff --git a/org/postgresql/jdbc4/Jdbc4SQLXML.java b/org/postgresql/jdbc4/Jdbc4SQLXML.java index 23021853..7b4ebba5 100644 --- a/org/postgresql/jdbc4/Jdbc4SQLXML.java +++ b/org/postgresql/jdbc4/Jdbc4SQLXML.java @@ -4,6 +4,8 @@ import org.postgresql.util.GT; import org.postgresql.util.PSQLState; import org.postgresql.util.PSQLException; import org.postgresql.core.BaseConnection; +import org.postgresql.xml.PGXmlFactoryFactory; +import org.postgresql.xml.DefaultPGXmlFactoryFactory; import java.io.*; import java.sql.SQLXML; @@ -14,7 +16,6 @@ import javax.xml.transform.Result; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.dom.DOMResult; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerException; @@ -22,8 +23,7 @@ import javax.xml.transform.TransformerException; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.sax.SAXResult; import org.xml.sax.InputSource; -import org.xml.sax.ErrorHandler; -import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; @@ -69,6 +69,13 @@ public class Jdbc4SQLXML implements SQLXML { _freed = false; } + private PGXmlFactoryFactory getXmlFactoryFactory() throws SQLException { + if (_conn != null) { + return _conn.getXmlFactoryFactory(); + } + return DefaultPGXmlFactoryFactory.INSTANCE; + } + public synchronized void free() { _freed = true; @@ -122,16 +129,15 @@ public class Jdbc4SQLXML implements SQLXML { try { if (sourceClass == null || DOMSource.class.equals(sourceClass)) { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = factory.newDocumentBuilder(); - builder.setErrorHandler(new NonPrintingErrorHandler()); + DocumentBuilder builder = getXmlFactoryFactory().newDocumentBuilder(); InputSource input = new InputSource(new StringReader(_data)); return new DOMSource(builder.parse(input)); } else if (SAXSource.class.equals(sourceClass)) { + XMLReader reader = getXmlFactoryFactory().createXMLReader(); InputSource is = new InputSource(new StringReader(_data)); - return new SAXSource(is); + return new SAXSource(reader, is); } else if (StreamSource.class.equals(sourceClass)) { @@ -139,7 +145,7 @@ public class Jdbc4SQLXML implements SQLXML { } else if (StAXSource.class.equals(sourceClass)) { - XMLInputFactory xif = XMLInputFactory.newInstance(); + XMLInputFactory xif = getXmlFactoryFactory().newXMLInputFactory(); XMLStreamReader xsr = xif.createXMLStreamReader(new StringReader(_data)); return new StAXSource(xsr); } @@ -185,7 +191,7 @@ public class Jdbc4SQLXML implements SQLXML { return _domResult; } else if (SAXResult.class.equals(resultClass)) { try { - SAXTransformerFactory transformerFactory = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); + SAXTransformerFactory transformerFactory = getXmlFactoryFactory().newSAXTransformerFactory(); TransformerHandler transformerHandler = transformerFactory.newTransformerHandler(); _stringWriter = new StringWriter(); transformerHandler.setResult(new StreamResult(_stringWriter)); @@ -201,7 +207,7 @@ public class Jdbc4SQLXML implements SQLXML { } else if (StAXResult.class.equals(resultClass)) { _stringWriter = new StringWriter(); try { - XMLOutputFactory xof = XMLOutputFactory.newInstance(); + XMLOutputFactory xof = getXmlFactoryFactory().newXMLOutputFactory(); XMLStreamWriter xsw = xof.createXMLStreamWriter(_stringWriter); _active = true; return new StAXResult(xsw); @@ -258,7 +264,7 @@ public class Jdbc4SQLXML implements SQLXML { // and use the identify transform to get it into a // friendlier result format. try { - TransformerFactory factory = TransformerFactory.newInstance(); + TransformerFactory factory = getXmlFactoryFactory().newTransformerFactory(); Transformer transformer = factory.newTransformer(); DOMSource domSource = new DOMSource(_domResult.getNode()); StringWriter stringWriter = new StringWriter(); @@ -284,14 +290,5 @@ public class Jdbc4SQLXML implements SQLXML { _initialized = true; } - // Don't clutter System.err with errors the user can't silence. - // If something bad really happens an exception will be thrown. - static class NonPrintingErrorHandler implements ErrorHandler - { - public void error(SAXParseException e) { } - public void fatalError(SAXParseException e) { } - public void warning(SAXParseException e) { } - } - } diff --git a/org/postgresql/xml/DefaultPGXmlFactoryFactory.java b/org/postgresql/xml/DefaultPGXmlFactoryFactory.java new file mode 100644 index 00000000..73349357 --- /dev/null +++ b/org/postgresql/xml/DefaultPGXmlFactoryFactory.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2020, PostgreSQL Global Development Group + * See the LICENSE file in the project root for more information. + */ + +package org.postgresql.xml; + +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.sax.SAXTransformerFactory; + +/** + * Default implementation of PGXmlFactoryFactory that configures each factory per OWASP recommendations. + * + * @see <a href="https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html">https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html</a> + */ +public class DefaultPGXmlFactoryFactory implements PGXmlFactoryFactory { + public static final DefaultPGXmlFactoryFactory INSTANCE = new DefaultPGXmlFactoryFactory(); + + private DefaultPGXmlFactoryFactory() { + } + + private DocumentBuilderFactory getDocumentBuilderFactory() { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + setFactoryProperties(factory); + factory.setXIncludeAware(false); + factory.setExpandEntityReferences(false); + return factory; + } + + @Override + public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException { + DocumentBuilder builder = getDocumentBuilderFactory().newDocumentBuilder(); + builder.setEntityResolver(EmptyStringEntityResolver.INSTANCE); + builder.setErrorHandler(NullErrorHandler.INSTANCE); + return builder; + } + + @Override + public TransformerFactory newTransformerFactory() { + TransformerFactory factory = TransformerFactory.newInstance(); + setFactoryProperties(factory); + return factory; + } + + @Override + public SAXTransformerFactory newSAXTransformerFactory() { + SAXTransformerFactory factory = (SAXTransformerFactory) SAXTransformerFactory.newInstance(); + setFactoryProperties(factory); + return factory; + } + + @Override + public XMLInputFactory newXMLInputFactory() { + XMLInputFactory factory = XMLInputFactory.newInstance(); + setPropertyQuietly(factory, XMLInputFactory.SUPPORT_DTD, false); + setPropertyQuietly(factory, XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); + return factory; + } + + @Override + public XMLOutputFactory newXMLOutputFactory() { + XMLOutputFactory factory = XMLOutputFactory.newInstance(); + return factory; + } + + @Override + public XMLReader createXMLReader() throws SAXException { + XMLReader factory = XMLReaderFactory.createXMLReader(); + setFeatureQuietly(factory, "http://apache.org/xml/features/disallow-doctype-decl", true); + setFeatureQuietly(factory, "http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + setFeatureQuietly(factory, "http://xml.org/sax/features/external-general-entities", false); + setFeatureQuietly(factory, "http://xml.org/sax/features/external-parameter-entities", false); + factory.setErrorHandler(NullErrorHandler.INSTANCE); + return factory; + } + + private static void setFeatureQuietly(Object factory, String name, boolean value) { + try { + if (factory instanceof DocumentBuilderFactory) { + ((DocumentBuilderFactory) factory).setFeature(name, value); + } else if (factory instanceof TransformerFactory) { + ((TransformerFactory) factory).setFeature(name, value); + } else if (factory instanceof XMLReader) { + ((XMLReader) factory).setFeature(name, value); + } else { + throw new Error("Invalid factory class: " + factory.getClass()); + } + return; + } catch (Exception ignore) { + } + } + + private static void setAttributeQuietly(Object factory, String name, Object value) { + try { + if (factory instanceof DocumentBuilderFactory) { + ((DocumentBuilderFactory) factory).setAttribute(name, value); + } else if (factory instanceof TransformerFactory) { + ((TransformerFactory) factory).setAttribute(name, value); + } else { + throw new Error("Invalid factory class: " + factory.getClass()); + } + } catch (Exception ignore) { + } + } + + private static void setFactoryProperties(Object factory) { + setFeatureQuietly(factory, XMLConstants.FEATURE_SECURE_PROCESSING, true); + setFeatureQuietly(factory, "http://apache.org/xml/features/disallow-doctype-decl", true); + setFeatureQuietly(factory, "http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + setFeatureQuietly(factory, "http://xml.org/sax/features/external-general-entities", false); + setFeatureQuietly(factory, "http://xml.org/sax/features/external-parameter-entities", false); + // Values from XMLConstants inlined for JDK 1.6 compatibility + setAttributeQuietly(factory, "http://javax.xml.XMLConstants/property/accessExternalDTD", ""); + setAttributeQuietly(factory, "http://javax.xml.XMLConstants/property/accessExternalSchema", ""); + setAttributeQuietly(factory, "http://javax.xml.XMLConstants/property/accessExternalStylesheet", ""); + } + + private static void setPropertyQuietly(Object factory, String name, Object value) { + try { + if (factory instanceof XMLReader) { + ((XMLReader) factory).setProperty(name, value); + } else if (factory instanceof XMLInputFactory) { + ((XMLInputFactory) factory).setProperty(name, value); + } else { + throw new Error("Invalid factory class: " + factory.getClass()); + } + } catch (Exception ignore) { + } + } +} \ No newline at end of file diff --git a/org/postgresql/xml/EmptyStringEntityResolver.java b/org/postgresql/xml/EmptyStringEntityResolver.java new file mode 100644 index 00000000..e96a39b8 --- /dev/null +++ b/org/postgresql/xml/EmptyStringEntityResolver.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2020, PostgreSQL Global Development Group + * See the LICENSE file in the project root for more information. + */ + +package org.postgresql.xml; + +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import java.io.IOException; +import java.io.StringReader; + +public class EmptyStringEntityResolver implements EntityResolver { + public static final EmptyStringEntityResolver INSTANCE = new EmptyStringEntityResolver(); + + @Override + public InputSource resolveEntity(String publicId, String systemId) + throws SAXException, IOException { + return new InputSource(new StringReader("")); + } +} diff --git a/org/postgresql/xml/LegacyInsecurePGXmlFactoryFactory.java b/org/postgresql/xml/LegacyInsecurePGXmlFactoryFactory.java new file mode 100644 index 00000000..ed7a66b5 --- /dev/null +++ b/org/postgresql/xml/LegacyInsecurePGXmlFactoryFactory.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020, PostgreSQL Global Development Group + * See the LICENSE file in the project root for more information. + */ + +package org.postgresql.xml; + +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.sax.SAXTransformerFactory; + +public class LegacyInsecurePGXmlFactoryFactory implements PGXmlFactoryFactory { + public static final LegacyInsecurePGXmlFactoryFactory INSTANCE = new LegacyInsecurePGXmlFactoryFactory(); + + private LegacyInsecurePGXmlFactoryFactory() { + } + + @Override + public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException { + DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + builder.setErrorHandler(NullErrorHandler.INSTANCE); + return builder; + } + + @Override + public TransformerFactory newTransformerFactory() { + return TransformerFactory.newInstance(); + } + + @Override + public SAXTransformerFactory newSAXTransformerFactory() { + return (SAXTransformerFactory) SAXTransformerFactory.newInstance(); + } + + @Override + public XMLInputFactory newXMLInputFactory() { + return XMLInputFactory.newInstance(); + } + + @Override + public XMLOutputFactory newXMLOutputFactory() { + return XMLOutputFactory.newInstance(); + } + + @Override + public XMLReader createXMLReader() throws SAXException { + return XMLReaderFactory.createXMLReader(); + } +} \ No newline at end of file diff --git a/org/postgresql/xml/NullErrorHandler.java b/org/postgresql/xml/NullErrorHandler.java new file mode 100644 index 00000000..d12a4fa6 --- /dev/null +++ b/org/postgresql/xml/NullErrorHandler.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020, PostgreSQL Global Development Group + * See the LICENSE file in the project root for more information. + */ + +package org.postgresql.xml; + +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXParseException; + +/** + * Error handler that silently suppresses all errors. + */ +public class NullErrorHandler implements ErrorHandler { + public static final NullErrorHandler INSTANCE = new NullErrorHandler(); + + public void error(SAXParseException e) { + } + + public void fatalError(SAXParseException e) { + } + + public void warning(SAXParseException e) { + } +} diff --git a/org/postgresql/xml/PGXmlFactoryFactory.java b/org/postgresql/xml/PGXmlFactoryFactory.java new file mode 100644 index 00000000..4bb98e4a --- /dev/null +++ b/org/postgresql/xml/PGXmlFactoryFactory.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020, PostgreSQL Global Development Group + * See the LICENSE file in the project root for more information. + */ + +package org.postgresql.xml; + +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.sax.SAXTransformerFactory; + +public interface PGXmlFactoryFactory { + DocumentBuilder newDocumentBuilder() throws ParserConfigurationException; + + TransformerFactory newTransformerFactory(); + + SAXTransformerFactory newSAXTransformerFactory(); + + XMLInputFactory newXMLInputFactory(); + + XMLOutputFactory newXMLOutputFactory(); + + XMLReader createXMLReader() throws SAXException; +} \ No newline at end of file -- 2.26.2
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor