CVE-2012-0037: Improper Restriction of XML External Entity Reference (CWE-611)
value: Redland Raptor (aka libraptor) before 2.0.7, as used by OpenOffice 3.3 and 3.4 Beta, LibreOffice before 3.4.6 and 3.5.x before 3.5.1, and other products, allows user-assisted remote attackers to read arbitrary files via a crafted XML external entity (XXE) declaration and reference in an RDF document.
CWE description: The product processes an XML document that can contain XML entities with URIs that resolve to documents outside of the intended sphere of control, causing the product to embed incorrect documents into its output.
CVSS v3 base score: 6.5
Published: 2012-06-17T03:41Z
Repository: https://github.com/dajobe/raptor
Language: C
Files changed: ChangeLog, NEWS.html, RELEASE.html, docs/raptor-1-to-2-map.tsv, librdfa/rdfa.c, src/raptor2.h.in, src/raptor_libxml.c, src/raptor_option.c, src/raptor_rdfxml.c, src/raptor_rss.c, src/raptor_turtle_writer.c
Commit date: 2012-03-15 20:28:07 -0700
Commit message: CVE-2012-0037

Enforce entity loading policy in raptor_libxml_resolveEntity
and raptor_libxml_getEntity by checking for file URIs and network URIs.

Add RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES / loadExternalEntities for
turning on loading of XML external entity loading, disabled by default.

This affects all the parsers that use SAX2: rdfxml, rss-tag-soup (and
aliases) and rdfa.

Diff: diff --git a/ChangeLog b/ChangeLog
index a7f549fd..ca5f4856 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,22 @@
+2012-01-29  Dave Beckett <dave@dajobe.org>
+
+	* librdfa/rdfa.c, src/raptor2.h.in, src/raptor_libxml.c,
+	src/raptor_option.c, src/raptor_rdfxml.c, src/raptor_rss.c,
+	src/raptor_turtle_writer.c: CVE-2012-0037
+
+	Enforce entity loading policy in raptor_libxml_resolveEntity and
+	raptor_libxml_getEntity by checking for file URIs and network
+	URIs.
+
+	Add RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES / loadExternalEntities
+	for turning on loading of XML external entity loading, disabled by
+	default.
+
+	This affects all the parsers that use SAX2: rdfxml, rdfa,
+	rss-tag-soup (and aliases).
+
 2012-03-15  Dave Beckett <dave@dajobe.org>
 
 	* librdfa/rdfa.c: Pass on options NO_NET and NO_FILE to RDFA SAX2
 	object
 
diff --git a/NEWS.html b/NEWS.html
index 9ce54571..4cc90186 100644
--- a/NEWS.html
+++ b/NEWS.html
@@ -6,24 +6,25 @@
 </head>
 <body>
 
 <h1 style="text-align:center">Raptor RDF Syntax Library - News</h1>
 
-<h2 id="D2012-XX-XX-V2.0.7">2012-XX-XX Raptor2 Version 2.0.7 Released</h2>
+<h2 id="D2012-03-22-V2.0.7">2012-03-22 Raptor2 Version 2.0.7 Released</h2>
 
-<p>Not yet released.
-</p>
-
-<p>
+<p>CVE-2012-0037 fixed<br />
 Removed Expat support<br />
 Removed internal Unicode NFC code for better and optional <a href="http://www.icu-project.org/">ICU</a><br />
-Added new options for denying file requests and SSL certificate verifying<br />
+Added options for denying file requests and XML entity loading<br />
+Added options for SSL certificate verifying<br />
 Fixed reported <a href="http://bugs.librdf.org/">issues</a>:
 <a href="http://bugs.librdf.org/mantis/view.php?id=448">0000448</a> and
 <a href="http://bugs.librdf.org/mantis/view.php?id=469">0000469</a>
 </p>
 
+<p>See the <a href="RELEASE.html#rel2_0_7">Raptor2 2.0.7 Release Notes</a>
+for the full details of the changes.</p>
+
 
 <h2 id="D2011-11-27-V2.0.6">2011-11-27 Raptor2 Version 2.0.6 Released</h2>
 
 <p>
 Fixed expat support which was broken in 2.0.5<br />
diff --git a/RELEASE.html b/RELEASE.html
index 6f539f7c..31f64c82 100644
--- a/RELEASE.html
+++ b/RELEASE.html
@@ -9,12 +9,11 @@
 <h1 style="text-align:center">Raptor RDF Syntax Library - Release Notes</h1>
 
 
 <h2 id="rel2_0_7"><a name="rel2_0_7">Raptor2 2.0.7 changes</a></h2>
 
-<p>Not yet released.
-</p>
+<p>CVE-2012-0037 fixed</p>
 
 <p>Issues Fixed:</p>
 <ul>
   <li><a href="http://bugs.librdf.org/mantis/view.php?id=448">0000448</a>: Turtle parser does not return error status from turtle_parse_chunk()</li>
   <li><a href="http://bugs.librdf.org/mantis/view.php?id=469">0000469</a>: Allow rapper to bypass server SSL certs checks in libcurl</li>
@@ -37,10 +36,14 @@ If ICU is not explicitly configured, no literal checking is done.</p>
 <p>Added new options:</p>
 <dl>
   <dt><code>RAPTOR_OPTION_NO_FILE</code><br/></dt>
   <dd>Deny file requests during parsing.</dd>
 
+  <dt><code>RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES</code><br/></dt>
+  <dd>Deny loading of XML external entity loading. Disabled by
+  default.</dd>
+
   <dt><code>RAPTOR_OPTION_WWW_SSL_VERIFY_PEER</code><br/></dt>
   <dd>Controls verifying an SSL peer during parsing / WWW.  Takes an
   integer value: non-0 to verify peer SSL certificate (default
   1).</dd>
 
@@ -51,10 +54,14 @@ If ICU is not explicitly configured, no literal checking is done.</p>
 </dl>
 
 
 <h3>Parser class changes</h3>
 
+<p>The RDF/XML, RSS Tag Soup and RDFa parsers now pass on network,
+file and entity loading parser options to the internal SAX2 to enable
+enforcing of network, file and entity loading policy.</p>
+
 <p>RDF/JSON parser handles an API change between YAJL V1 and V2.
 </p>
 
 <p>Turtle parser now returns parser errors to
 <code>raptor_parse_chunk()</code>.
@@ -62,15 +69,22 @@ Fixes <a href="http://bugs.librdf.org/mantis/view.php?id=488">Issue #0000488</a>
 </p>
 
 
 <h3>SAX2 class changes</h3>
 
-<p>
-Added <code>raptor_sax2_set_uri_filter()</code> to set a URI filter
-for any SAX2 calls that do internal lookups of URIs.
+<p>Added <code>raptor_sax2_set_uri_filter()</code> to set a URI
+filter for any SAX2 calls that do internal lookups of URIs.
 </p>
 
+<p>Control file and network loading inside SAX2.  Option
+<code>RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES</code> now enforces
+loading external XML entities and is by default enabled.  If enabled,
+<code>RAPTOR_OPTION_NO_FILE</code> and
+<code>RAPTOR_OPTION_NO_NET</code> are also checked.  All URIs loaded
+are also passed through any URI filter, if set by
+<code>raptor_sax2_set_uri_filter()</code>.
+</p>
 
 <h3>URI class changes</h3>
 
 <p>Added new URI constructor
 <code>raptor_new_uri_from_uri_or_file_string()</code>
diff --git a/docs/raptor-1-to-2-map.tsv b/docs/raptor-1-to-2-map.tsv
index fc624442..01ef8f78 100644
--- a/docs/raptor-1-to-2-map.tsv
+++ b/docs/raptor-1-to-2-map.tsv
@@ -558,5 +558,6 @@
 1.4.21	enum	-	-	2.0.0	enum	RAPTOR_OPTION_VALUE_TYPE_URI	-	-
 1.4.21	enum	-	-	2.0.0	enum	RAPTOR_OPTION_VALUE_TYPE_LAST	-	-
 2.0.6	enum	-	-	2.0.7	enum	RAPTOR_OPTION_NO_FILE	-	-
 2.0.6	enum	-	-	2.0.7	enum	RAPTOR_OPTION_WWW_SSL_VERIFY_PEER	-	-
 2.0.6	enum	-	-	2.0.7	enum	RAPTOR_OPTION_WWW_SSL_VERIFY_HOST	-	-
+2.0.6	enum	-	-	2.0.7	enum	RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES	-	-
diff --git a/librdfa/rdfa.c b/librdfa/rdfa.c
index 8ec11144..be68b954 100644
--- a/librdfa/rdfa.c
+++ b/librdfa/rdfa.c
@@ -1228,10 +1228,13 @@ int rdfa_parse_start(rdfacontext* context)
                             RAPTOR_OPTION_NO_NET, NULL,
                             RAPTOR_OPTIONS_GET_NUMERIC(rdf_parser, RAPTOR_OPTION_NO_NET));
      raptor_sax2_set_option(context->sax2,
                             RAPTOR_OPTION_NO_FILE, NULL,
                             RAPTOR_OPTIONS_GET_NUMERIC(rdf_parser, RAPTOR_OPTION_NO_FILE));
+     raptor_sax2_set_option(context->sax2,
+                            RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES, NULL,
+                            RAPTOR_OPTIONS_GET_NUMERIC(rdf_parser, RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES));
      if(rdf_parser->uri_filter)
        raptor_sax2_set_uri_filter(context->sax2, rdf_parser->uri_filter,
                                   rdf_parser->uri_filter_user_data);
    }
    
diff --git a/src/raptor2.h.in b/src/raptor2.h.in
index 88d2d637..6da99ca9 100644
--- a/src/raptor2.h.in
+++ b/src/raptor2.h.in
@@ -526,10 +526,11 @@ typedef struct {
  * @RAPTOR_OPTION_WWW_CERT_TYPE: String. SSL client certificate type
  * @RAPTOR_OPTION_WWW_CERT_PASSPHRASE: String. SSL client certificate passphrase
  * @RAPTOR_OPTION_WWW_SSL_VERIFY_PEER:  Integer. SSL verify peer - non-0 to verify peer SSL certificate (default)
  * @RAPTOR_OPTION_WWW_SSL_VERIFY_HOST: Integer. SSL verify host - 0 none, 1 CN match, 2 host match (default). Other values are ignored.
  * @RAPTOR_OPTION_NO_FILE: Deny file reading requests inside other requests.
+ * @RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES: When reading XML, load external entities.
  * @RAPTOR_OPTION_LAST: Internal
  *
  * Raptor parser, serializer or XML writer options.
  */
 typedef enum {
@@ -572,11 +573,12 @@ typedef enum {
   RAPTOR_OPTION_WWW_CERT_TYPE,
   RAPTOR_OPTION_WWW_CERT_PASSPHRASE,
   RAPTOR_OPTION_NO_FILE,
   RAPTOR_OPTION_WWW_SSL_VERIFY_PEER,
   RAPTOR_OPTION_WWW_SSL_VERIFY_HOST,
-  RAPTOR_OPTION_LAST = RAPTOR_OPTION_WWW_SSL_VERIFY_HOST
+  RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES,
+  RAPTOR_OPTION_LAST = RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES
 } raptor_option;
 
 
 /**
  * raptor_term_literal_value:
diff --git a/src/raptor_libxml.c b/src/raptor_libxml.c
index f6a96a43..b60e7480 100644
--- a/src/raptor_libxml.c
+++ b/src/raptor_libxml.c
@@ -143,20 +143,121 @@ raptor_libxml_hasExternalSubset (void* user_data)
 }
 
 
 static xmlParserInputPtr
 raptor_libxml_resolveEntity(void* user_data, 
-                            const xmlChar *publicId, const xmlChar *systemId) {
+                            const xmlChar *publicId, const xmlChar *systemId)
+{
   raptor_sax2* sax2 = (raptor_sax2*)user_data;
-  return libxml2_resolveEntity(sax2->xc, publicId, systemId);
+  xmlParserCtxtPtr ctxt = sax2->xc;
+  const unsigned char *uri_string = NULL;
+  xmlParserInputPtr entity_input;
+  int load_entity = 0;
+
+  if(ctxt->input)
+    uri_string = RAPTOR_GOOD_CAST(const unsigned char *, ctxt->input->filename);
+
+  if(!uri_string)
+    uri_string = RAPTOR_GOOD_CAST(const unsigned char *, ctxt->directory);
+
+  load_entity = RAPTOR_OPTIONS_GET_NUMERIC(sax2, RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES);
+  if(load_entity)
+    load_entity = raptor_sax2_check_load_uri_string(sax2, uri_string);
+
+  if(load_entity) {
+    entity_input = xmlLoadExternalEntity(RAPTOR_GOOD_CAST(const char*, uri_string),
+                                         RAPTOR_GOOD_CAST(const char*, publicId),
+                                         ctxt);
+  } else {
+    RAPTOR_DEBUG4("Not loading entity URI %s by policy for publicId '%s' systemId '%s'\n", uri_string, publicId, systemId);
+  }
+  
+  return entity_input;
 }
 
 
 static xmlEntityPtr
-raptor_libxml_getEntity(void* user_data, const xmlChar *name) {
+raptor_libxml_getEntity(void* user_data, const xmlChar *name)
+{
   raptor_sax2* sax2 = (raptor_sax2*)user_data;
-  return libxml2_getEntity(sax2->xc, name);
+  xmlParserCtxtPtr xc = sax2->xc;
+  xmlEntityPtr ret = NULL;
+
+  if(!xc)
+    return NULL;
+
+  if(!xc->inSubset) {
+    /* looks for hardcoded set of entity names - lt, gt etc. */
+    ret = xmlGetPredefinedEntity(name);
+    if(ret) {
+      RAPTOR_DEBUG2("Entity '%s' found in predefined set\n", name);
+      return ret;
+    }
+  }
+
+  /* This section uses xmlGetDocEntity which looks for entities in
+   * memory only, never from a file or URI 
+   */
+  if(xc->myDoc && (xc->myDoc->standalone == 1)) {
+    RAPTOR_DEBUG2("Entity '%s' document is standalone\n", name);
+    /* Document is standalone: no entities are required to interpret doc */
+    if(xc->inSubset == 2) {
+      xc->myDoc->standalone = 0;
+      ret = xmlGetDocEntity(xc->myDoc, name);
+      xc->myDoc->standalone = 1;
+    } else {
+      ret = xmlGetDocEntity(xc->myDoc, name);
+      if(!ret) {
+        xc->myDoc->standalone = 0;
+        ret = xmlGetDocEntity(xc->myDoc, name);
+        xc->myDoc->standalone = 1;
+      }
+    }
+  } else {
+    ret = xmlGetDocEntity(xc->myDoc, name);
+  }
+
+  if(ret && !ret->children &&
+    (ret->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) {
+    /* Entity is an external general parsed entity. It may be in a
+     * catalog file, user file or user URI
+     */
+    int val = 0;
+    xmlNodePtr children;
+    int load_entity = 0;
+
+    load_entity = RAPTOR_OPTIONS_GET_NUMERIC(sax2, RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES);
+    if(load_entity)
+      load_entity = raptor_sax2_check_load_uri_string(sax2, ret->URI);
+
+    if(!load_entity) {
+      RAPTOR_DEBUG2("Not getting entity URI %s by policy\n", ret->URI);
+      children = xmlNewText((const xmlChar*)"");
+    } else {
+      /* Disable SAX2 handlers so that the SAX2 events do not all get
+       * sent to callbacks during dealing with the entity parsing.
+       */
+      sax2->enabled = 0;
+      val = xmlParseCtxtExternalEntity(xc, ret->URI, ret->ExternalID, &children);
+      sax2->enabled = 1;
+    }
+    
+    if(!val) {
+      xmlAddChildList((xmlNodePtr)ret, children);
+    } else {
+      xc->validate = 0;
+      return NULL;
+    }
+    
+    ret->owner = 1;
+
+    /* Mark this entity as having been checked - never do this again */
+    if(!ret->checked)
+      ret->checked = 1;
+  }
+
+  return ret;
 }
 
 
 static xmlEntityPtr
 raptor_libxml_getParameterEntity(void* user_data, const xmlChar *name) {
diff --git a/src/raptor_option.c b/src/raptor_option.c
index 460d0d79..834c1c65 100644
--- a/src/raptor_option.c
+++ b/src/raptor_option.c
@@ -293,10 +293,16 @@ static const struct
   { RAPTOR_OPTION_WWW_SSL_VERIFY_HOST,
     RAPTOR_OPTION_AREA_PARSER,
     RAPTOR_OPTION_VALUE_TYPE_INT,
     "wwwSslVerifyHost",
     "SSL verify host matching"
+  },
+  { RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES,
+    (raptor_option_area)(RAPTOR_OPTION_AREA_PARSER | RAPTOR_OPTION_AREA_SAX2),
+    RAPTOR_OPTION_VALUE_TYPE_BOOL,
+    "loadExternalEntities",
+    "Parsers and SAX2 should load external entities."
   }
 };
 
 
 static const char * const raptor_option_uri_prefix = "http://feature.librdf.org/raptor-";
diff --git a/src/raptor_rdfxml.c b/src/raptor_rdfxml.c
index 53b1ab7e..7d06299f 100644
--- a/src/raptor_rdfxml.c
+++ b/src/raptor_rdfxml.c
@@ -1002,10 +1002,13 @@ raptor_rdfxml_parse_start(raptor_parser* rdf_parser)
                          RAPTOR_OPTION_NO_NET, NULL,
                          RAPTOR_OPTIONS_GET_NUMERIC(rdf_parser, RAPTOR_OPTION_NO_NET));
   raptor_sax2_set_option(rdf_xml_parser->sax2, 
                          RAPTOR_OPTION_NO_FILE, NULL,
                          RAPTOR_OPTIONS_GET_NUMERIC(rdf_parser, RAPTOR_OPTION_NO_FILE));
+  raptor_sax2_set_option(rdf_xml_parser->sax2, 
+                         RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES, NULL,
+                         RAPTOR_OPTIONS_GET_NUMERIC(rdf_parser, RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES));
   if(rdf_parser->uri_filter)
     raptor_sax2_set_uri_filter(rdf_xml_parser->sax2, rdf_parser->uri_filter,
                                rdf_parser->uri_filter_user_data);
 
   raptor_sax2_parse_start(rdf_xml_parser->sax2, uri);
diff --git a/src/raptor_rss.c b/src/raptor_rss.c
index 46286848..d66ade01 100644
--- a/src/raptor_rss.c
+++ b/src/raptor_rss.c
@@ -250,10 +250,13 @@ raptor_rss_parse_start(raptor_parser *rdf_parser)
                          RAPTOR_OPTION_NO_NET, NULL,
                          RAPTOR_OPTIONS_GET_NUMERIC(rdf_parser, RAPTOR_OPTION_NO_NET));
   raptor_sax2_set_option(rss_parser->sax2, 
                          RAPTOR_OPTION_NO_FILE, NULL,
                          RAPTOR_OPTIONS_GET_NUMERIC(rdf_parser, RAPTOR_OPTION_NO_FILE));
+  raptor_sax2_set_option(rss_parser->sax2, 
+                         RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES, NULL,
+                         RAPTOR_OPTIONS_GET_NUMERIC(rdf_parser, RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES));
   if(rdf_parser->uri_filter)
     raptor_sax2_set_uri_filter(rss_parser->sax2, rdf_parser->uri_filter,
                                rdf_parser->uri_filter_user_data);
   
   raptor_sax2_parse_start(rss_parser->sax2, uri);
diff --git a/src/raptor_turtle_writer.c b/src/raptor_turtle_writer.c
index 7701d314..6eb1c275 100644
--- a/src/raptor_turtle_writer.c
+++ b/src/raptor_turtle_writer.c
@@ -703,10 +703,11 @@ raptor_turtle_writer_set_option(raptor_turtle_writer *turtle_writer,
     case RAPTOR_OPTION_STRICT:
       
     /* Shared */
     case RAPTOR_OPTION_NO_NET:
     case RAPTOR_OPTION_NO_FILE:
+    case RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES:
 
     /* XML writer options */
     case RAPTOR_OPTION_RELATIVE_URIS:
 
     /* DOT serializer options */
@@ -827,10 +828,11 @@ raptor_turtle_writer_get_option(raptor_turtle_writer *turtle_writer,
     case RAPTOR_OPTION_STRICT:
 
     /* Shared */
     case RAPTOR_OPTION_NO_NET:
     case RAPTOR_OPTION_NO_FILE:
+    case RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES:
 
     /* XML writer options */
     case RAPTOR_OPTION_RELATIVE_URIS:
 
     /* DOT serializer options */

Vulnerable code: <h2 id="D2012-XX-XX-V2.0.7">2012-XX-XX Raptor2 Version 2.0.7 Released</h2>
<p>Not yet released.
</p>

<p>
Added new options for denying file requests and SSL certificate verifying<br />
<p>Not yet released.
</p>
<p>
Added <code>raptor_sax2_set_uri_filter()</code> to set a URI filter
for any SAX2 calls that do internal lookups of URIs.
  RAPTOR_OPTION_LAST = RAPTOR_OPTION_WWW_SSL_VERIFY_HOST
                            const xmlChar *publicId, const xmlChar *systemId) {
  return libxml2_resolveEntity(sax2->xc, publicId, systemId);
raptor_libxml_getEntity(void* user_data, const xmlChar *name) {
  return libxml2_getEntity(sax2->xc, name);
Fixed code: 2012-01-29  Dave Beckett <dave@dajobe.org>

	* librdfa/rdfa.c, src/raptor2.h.in, src/raptor_libxml.c,
	src/raptor_option.c, src/raptor_rdfxml.c, src/raptor_rss.c,
	src/raptor_turtle_writer.c: CVE-2012-0037

	Enforce entity loading policy in raptor_libxml_resolveEntity and
	raptor_libxml_getEntity by checking for file URIs and network
	URIs.

	Add RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES / loadExternalEntities
	for turning on loading of XML external entity loading, disabled by
	default.

	This affects all the parsers that use SAX2: rdfxml, rdfa,
	rss-tag-soup (and aliases).

<h2 id="D2012-03-22-V2.0.7">2012-03-22 Raptor2 Version 2.0.7 Released</h2>
<p>CVE-2012-0037 fixed<br />
Added options for denying file requests and XML entity loading<br />
Added options for SSL certificate verifying<br />
<p>See the <a href="RELEASE.html#rel2_0_7">Raptor2 2.0.7 Release Notes</a>
for the full details of the changes.</p>

<p>CVE-2012-0037 fixed</p>
  <dt><code>RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES</code><br/></dt>
  <dd>Deny loading of XML external entity loading. Disabled by
  default.</dd>

<p>The RDF/XML, RSS Tag Soup and RDFa parsers now pass on network,
file and entity loading parser options to the internal SAX2 to enable
enforcing of network, file and entity loading policy.</p>

<p>Added <code>raptor_sax2_set_uri_filter()</code> to set a URI
filter for any SAX2 calls that do internal lookups of URIs.
<p>Control file and network loading inside SAX2.  Option
<code>RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES</code> now enforces
loading external XML entities and is by default enabled.  If enabled,
<code>RAPTOR_OPTION_NO_FILE</code> and
<code>RAPTOR_OPTION_NO_NET</code> are also checked.  All URIs loaded
are also passed through any URI filter, if set by
<code>raptor_sax2_set_uri_filter()</code>.
</p>
2.0.6	enum	-	-	2.0.7	enum	RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES	-	-
     raptor_sax2_set_option(context->sax2,
                            RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES, NULL,
                            RAPTOR_OPTIONS_GET_NUMERIC(rdf_parser, RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES));
 * @RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES: When reading XML, load external entities.
  RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES,
  RAPTOR_OPTION_LAST = RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES
                            const xmlChar *publicId, const xmlChar *systemId)
{
  xmlParserCtxtPtr ctxt = sax2->xc;
  const unsigned char *uri_string = NULL;
  xmlParserInputPtr entity_input;
  int load_entity = 0;

  if(ctxt->input)
    uri_string = RAPTOR_GOOD_CAST(const unsigned char *, ctxt->input->filename);

  if(!uri_string)
    uri_string = RAPTOR_GOOD_CAST(const unsigned char *, ctxt->directory);

  load_entity = RAPTOR_OPTIONS_GET_NUMERIC(sax2, RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES);
  if(load_entity)
    load_entity = raptor_sax2_check_load_uri_string(sax2, uri_string);

  if(load_entity) {
    entity_input = xmlLoadExternalEntity(RAPTOR_GOOD_CAST(const char*, uri_string),
                                         RAPTOR_GOOD_CAST(const char*, publicId),
                                         ctxt);
  } else {
    RAPTOR_DEBUG4("Not loading entity URI %s by policy for publicId '%s' systemId '%s'\n", uri_string, publicId, systemId);
  }
  
  return entity_input;
raptor_libxml_getEntity(void* user_data, const xmlChar *name)
{
  xmlParserCtxtPtr xc = sax2->xc;
  xmlEntityPtr ret = NULL;

  if(!xc)
    return NULL;

  if(!xc->inSubset) {
    /* looks for hardcoded set of entity names - lt, gt etc. */
    ret = xmlGetPredefinedEntity(name);
    if(ret) {
      RAPTOR_DEBUG2("Entity '%s' found in predefined set\n", name);
      return ret;
    }
  }

  /* This section uses xmlGetDocEntity which looks for entities in
   * memory only, never from a file or URI 
   */
  if(xc->myDoc && (xc->myDoc->standalone == 1)) {
    RAPTOR_DEBUG2("Entity '%s' document is standalone\n", name);
    /* Document is standalone: no entities are required to interpret doc */
    if(xc->inSubset == 2) {
      xc->myDoc->standalone = 0;
      ret = xmlGetDocEntity(xc->myDoc, name);
      xc->myDoc->standalone = 1;
    } else {
      ret = xmlGetDocEntity(xc->myDoc, name);
      if(!ret) {
        xc->myDoc->standalone = 0;
        ret = xmlGetDocEntity(xc->myDoc, name);
        xc->myDoc->standalone = 1;
      }
    }
  } else {
    ret = xmlGetDocEntity(xc->myDoc, name);
  }

  if(ret && !ret->children &&
    (ret->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) {
    /* Entity is an external general parsed entity. It may be in a
     * catalog file, user file or user URI
     */
    int val = 0;
    xmlNodePtr children;
    int load_entity = 0;

    load_entity = RAPTOR_OPTIONS_GET_NUMERIC(sax2, RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES);
    if(load_entity)
      load_entity = raptor_sax2_check_load_uri_string(sax2, ret->URI);

    if(!load_entity) {
      RAPTOR_DEBUG2("Not getting entity URI %s by policy\n", ret->URI);
      children = xmlNewText((const xmlChar*)"");
    } else {
      /* Disable SAX2 handlers so that the SAX2 events do not all get
       * sent to callbacks during dealing with the entity parsing.
       */
      sax2->enabled = 0;
      val = xmlParseCtxtExternalEntity(xc, ret->URI, ret->ExternalID, &children);
      sax2->enabled = 1;
    }
    
    if(!val) {
      xmlAddChildList((xmlNodePtr)ret, children);
    } else {
      xc->validate = 0;
      return NULL;
    }
    
    ret->owner = 1;

    /* Mark this entity as having been checked - never do this again */
    if(!ret->checked)
      ret->checked = 1;
  }

  return ret;
  },
  { RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES,
    (raptor_option_area)(RAPTOR_OPTION_AREA_PARSER | RAPTOR_OPTION_AREA_SAX2),
    RAPTOR_OPTION_VALUE_TYPE_BOOL,
    "loadExternalEntities",
    "Parsers and SAX2 should load external entities."
  raptor_sax2_set_option(rdf_xml_parser->sax2, 
                         RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES, NULL,
                         RAPTOR_OPTIONS_GET_NUMERIC(rdf_parser, RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES));
  raptor_sax2_set_option(rss_parser->sax2, 
                         RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES, NULL,
                         RAPTOR_OPTIONS_GET_NUMERIC(rdf_parser, RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES));
    case RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES:
    case RAPTOR_OPTION_LOAD_EXTERNAL_ENTITIES: