Sophie

Sophie

distrib > Mandriva > 2009.0 > i586 > by-pkgid > 252a58b0dcde73ec7ca2fef2aa1b611a > files > 3

libneon0.27-0.28.3-1.1mdv2009.0.src.rpm


 rediffed diff between relevant parts of 0.28.5 and 0.28.6

diff -Naurp neon-0.28.3/src/ne_gnutls.c neon-0.28.3.oden/src/ne_gnutls.c
--- neon-0.28.3/src/ne_gnutls.c	2008-07-25 09:39:21.000000000 -0400
+++ neon-0.28.3.oden/src/ne_gnutls.c	2009-08-24 13:14:44.000000000 -0400
@@ -350,7 +350,7 @@ static int check_identity(const ne_uri *
         case GNUTLS_SAN_DNSNAME:
             name[len] = '\0';
             if (identity && !found) *identity = ne_strdup(name);
-            match = ne__ssl_match_hostname(name, hostname);
+            match = ne__ssl_match_hostname(name, len, hostname);
             found = 1;
             break;
         case GNUTLS_SAN_IPADDRESS: {
@@ -419,7 +419,7 @@ static int check_identity(const ne_uri *
                                                 seq, 0, name, &len);
             if (ret == 0) {
                 if (identity) *identity = ne_strdup(name);
-                match = ne__ssl_match_hostname(name, hostname);
+                match = ne__ssl_match_hostname(name, len, hostname);
             }
         } else {
             return -1;
diff -Naurp neon-0.28.3/src/ne_openssl.c neon-0.28.3.oden/src/ne_openssl.c
--- neon-0.28.3/src/ne_openssl.c	2008-07-25 09:39:21.000000000 -0400
+++ neon-0.28.3.oden/src/ne_openssl.c	2009-08-24 13:14:44.000000000 -0400
@@ -92,10 +92,16 @@ static int append_dirstring(ne_buffer *b
     int len;
 
     switch (str->type) {
-    case V_ASN1_UTF8STRING:
     case V_ASN1_IA5STRING: /* definitely ASCII */
     case V_ASN1_VISIBLESTRING: /* probably ASCII */
     case V_ASN1_PRINTABLESTRING: /* subset of ASCII */
+        ne__buffer_qappend(buf, str->data, str->length);
+        break;
+    case V_ASN1_UTF8STRING:
+        /* Fail for embedded NUL bytes. */
+        if (strlen((char *)str->data) != (size_t)str->length) {
+            return -1;
+        }
         ne_buffer_append(buf, (char *)str->data, str->length);
         break;
     case V_ASN1_UNIVERSALSTRING:
@@ -103,8 +109,15 @@ static int append_dirstring(ne_buffer *b
     case V_ASN1_BMPSTRING: 
         len = ASN1_STRING_to_UTF8(&tmp, str);
         if (len > 0) {
-            ne_buffer_append(buf, (char *)tmp, len);
-            OPENSSL_free(tmp);
+            /* Fail if there were embedded NUL bytes. */
+            if (strlen((char *)tmp) != (size_t)len) {
+                OPENSSL_free(tmp);
+                return -1;
+            } 
+            else {
+                ne_buffer_append(buf, (char *)tmp, len);
+                OPENSSL_free(tmp);
+            }
             break;
         } else {
             ERR_clear_error();
@@ -119,13 +132,11 @@ static int append_dirstring(ne_buffer *b
     return 0;
 }
 
-/* Returns a malloc-allocate version of IA5 string AS.  Really only
- * here to prevent char * vs unsigned char * type mismatches without
- * losing all hope at type-safety. */
+/* Returns a malloc-allocated version of IA5 string AS, escaped for
+ * safety. */
 static char *dup_ia5string(const ASN1_IA5STRING *as)
 {
-    unsigned char *data = as->data;
-    return ne_strndup((char *)data, as->length);
+    return ne__strnqdup(as->data, as->length);
 }
 
 char *ne_ssl_readable_dname(const ne_ssl_dname *name)
@@ -236,7 +247,7 @@ static int check_identity(const ne_uri *
 	    if (nm->type == GEN_DNS) {
 		char *name = dup_ia5string(nm->d.ia5);
                 if (identity && !found) *identity = ne_strdup(name);
-		match = ne__ssl_match_hostname(name, hostname);
+		match = ne__ssl_match_hostname(name, strlen(name), hostname);
 		ne_free(name);
 		found = 1;
             } 
@@ -320,7 +331,7 @@ static int check_identity(const ne_uri *
             return -1;
         }
         if (identity) *identity = ne_strdup(cname->data);
-        match = ne__ssl_match_hostname(cname->data, hostname);
+        match = ne__ssl_match_hostname(cname->data, cname->used - 1, hostname);
         ne_buffer_destroy(cname);
     }
 
diff -Naurp neon-0.28.3/src/ne_private.h neon-0.28.3.oden/src/ne_private.h
--- neon-0.28.3/src/ne_private.h	2008-07-25 09:39:21.000000000 -0400
+++ neon-0.28.3.oden/src/ne_private.h	2009-08-24 13:14:44.000000000 -0400
@@ -128,8 +128,17 @@ int ne__negotiate_ssl(ne_session *sess);
 void ne__ssl_set_verify_err(ne_session *sess, int failures);
 
 /* Return non-zero if hostname from certificate (cn) matches hostname
- * used for session (hostname); follows RFC2818 logic.  cn is modified
- * in-place. */
-int ne__ssl_match_hostname(char *cn, const char *hostname);
+ * used for session (hostname); follows RFC2818 logic. */
+int ne__ssl_match_hostname(const char *cn, size_t cnlen, const char *hostname);
+
+/* Return a malloc-allocated copy of 'data', of length 'len', with all
+ * non-ASCII bytes, and ASCII control characters escaped.  (Note that
+ * the escaping includes the NUL byte). */
+char *ne__strnqdup(const unsigned char *data, size_t len);
+
+/* Append 'len' bytes of 'data' to buf.  All non-ASCII bytes, and
+ * ASCII control characters, are escaped.  (Note that this includes
+ * the NUL byte). */
+void ne__buffer_qappend(ne_buffer *buf, const unsigned char *data, size_t len);
 
 #endif /* HTTP_PRIVATE_H */
diff -Naurp neon-0.28.3/src/ne_session.c neon-0.28.3.oden/src/ne_session.c
--- neon-0.28.3/src/ne_session.c	2008-07-25 09:39:21.000000000 -0400
+++ neon-0.28.3.oden/src/ne_session.c	2009-08-24 13:14:44.000000000 -0400
@@ -403,24 +403,21 @@ void ne__ssl_set_verify_err(ne_session *
 
 /* This doesn't actually implement complete RFC 2818 logic; omits
  * "f*.example.com" support for simplicity. */
-int ne__ssl_match_hostname(char *cn, const char *hostname)
+int ne__ssl_match_hostname(const char *cn, size_t cnlen, const char *hostname)
 {
     const char *dot;
 
-    dot = strchr(hostname, '.');
-    if (dot == NULL) {
-	char *pnt = strchr(cn, '.');
-	/* hostname is not fully-qualified; unqualify the cn. */
-	if (pnt != NULL) {
-	    *pnt = '\0';
-	}
-    }
-    else if (strncmp(cn, "*.", 2) == 0) {
+    NE_DEBUG(NE_DBG_SSL, "ssl: Match common name '%s' against '%s'\n",
+             cn, hostname);
+
+    if (strncmp(cn, "*.", 2) == 0 && cnlen > 2
+        && (dot = strchr(hostname, '.')) != NULL) {
 	hostname = dot + 1;
 	cn += 2;
+        cnlen -= 2;
     }
 
-    return !ne_strcasecmp(cn, hostname);
+    return cnlen == strlen(hostname) && !ne_strcasecmp(cn, hostname);
 }
 
 #endif /* NE_HAVE_SSL */
diff -Naurp neon-0.28.3/src/ne_socket.c neon-0.28.3.oden/src/ne_socket.c
--- neon-0.28.3/src/ne_socket.c	2008-07-03 06:11:37.000000000 -0400
+++ neon-0.28.3.oden/src/ne_socket.c	2009-08-24 13:14:44.000000000 -0400
@@ -1251,6 +1251,7 @@ int ne_sock_connect(ne_socket *sock,
 ne_inet_addr *ne_sock_peer(ne_socket *sock, unsigned int *port)
 {
     union saun {
+        struct sockaddr sa;
         struct sockaddr_in sin;
 #if defined(USE_GETADDRINFO) && defined(AF_INET6)
         struct sockaddr_in6 sin6;
@@ -1277,13 +1278,13 @@ ne_inet_addr *ne_sock_peer(ne_socket *so
     ia->ai_addr = ne_malloc(sizeof *ia);
     ia->ai_addrlen = len;
     memcpy(ia->ai_addr, sad, len);
-    ia->ai_family = sad->sa_family;
+    ia->ai_family = saun.sa.sa_family;
 #else
     memcpy(ia, &saun.sin.sin_addr.s_addr, sizeof *ia);
 #endif    
 
 #if defined(USE_GETADDRINFO) && defined(AF_INET6)
-    *port = ntohs(sad->sa_family == AF_INET ? 
+    *port = ntohs(saun.sa.sa_family == AF_INET ? 
                   saun.sin.sin_port : saun.sin6.sin6_port);
 #else
     *port = ntohs(saun.sin.sin_port);
diff -Naurp neon-0.28.3/src/ne_string.c neon-0.28.3.oden/src/ne_string.c
--- neon-0.28.3/src/ne_string.c	2008-03-04 06:56:16.000000000 -0500
+++ neon-0.28.3.oden/src/ne_string.c	2009-08-24 13:14:44.000000000 -0400
@@ -38,6 +38,8 @@
 
 #include "ne_alloc.h"
 #include "ne_string.h"
+/* hack for 0.28.x backport of ne_strnqdup, ne_buffer_qappend */
+#include "ne_private.h"
 
 char *ne_token(char **str, char separator)
 {
@@ -252,6 +254,98 @@ void ne_buffer_altered(ne_buffer *buf)
     buf->used = strlen(buf->data) + 1;
 }
 
+
+/* ascii_quote[n] gives the number of bytes needed by
+ * ne_buffer_qappend() to append character 'n'. */
+static const unsigned char ascii_quote[256] = {
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+};
+
+static const char hex_chars[16] = "0123456789ABCDEF";
+
+/* Return the expected number of bytes needed to append the string
+ * beginning at byte 's', where 'send' points to the last byte after
+ * 's'. */ 
+static size_t qappend_count(const unsigned char *s, const unsigned char *send)
+{
+    const unsigned char *p;
+    size_t ret;
+    
+    for (p = s, ret = 0; p < send; p++) {
+        ret += ascii_quote[*p];
+    }
+
+    return ret;
+}       
+
+/* Append the string 's', up to but not including 'send', to string
+ * 'dest', quoting along the way.  Returns pointer to NUL. */
+static char *quoted_append(char *dest, const unsigned char *s, 
+                           const unsigned char *send)
+{
+    const unsigned char *p;
+    char *q = dest;
+
+    for (p = s; p < send; p++) {
+        if (ascii_quote[*p] == 1) {
+            *q++ = *p;
+        }
+        else {
+            *q++ = '\\';
+            *q++ = 'x';
+            *q++ = hex_chars[(*p >> 4) & 0x0f];
+            *q++ = hex_chars[*p & 0x0f];
+        }
+    }
+
+    /* NUL terminate after the last character */
+    *q = '\0';
+    
+    return q;
+}
+
+void ne__buffer_qappend(ne_buffer *buf, const unsigned char *data, size_t len)
+{
+    const unsigned char *dend = data + len;
+    char *q, *qs;
+
+    ne_buffer_grow(buf, buf->used + qappend_count(data, dend));
+
+    /* buf->used >= 1, so this is safe. */
+    qs = buf->data + buf->used - 1;
+
+    q = quoted_append(qs, data, dend);
+    
+    /* used already accounts for a NUL, so increment by number of
+     * characters appended, *before* the NUL. */
+    buf->used += q - qs;
+}
+
+char *ne__strnqdup(const unsigned char *data, size_t len)
+{
+    const unsigned char *dend = data + len;
+    char *dest = malloc(qappend_count(data, dend) + 1);
+
+    quoted_append(dest, data, dend);
+
+    return dest;
+}
+
 static const char b64_alphabet[] =  
     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
     "abcdefghijklmnopqrstuvwxyz"
@@ -345,9 +439,9 @@ size_t ne_unbase64(const char *data, uns
     return outp - *out;
 }
 
-/* Character map array; array[n] = isprint(n) ? 0x20 : n.  Used by
- * ne_strclean as a locale-independent isprint(). */
-static const unsigned char ascii_printable[256] = {
+/* Character map array; ascii_clean[n] = isprint(n) ? n : 0x20.  Used
+ * by ne_strclean as a locale-independent isprint(). */
+static const unsigned char ascii_clean[256] = {
     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
@@ -387,7 +481,7 @@ char *ne_strclean(char *str)
     unsigned char *pnt;
 
     for (pnt = (unsigned char *)str; *pnt; pnt++)
-        *pnt = (char)ascii_printable[*pnt];
+        *pnt = (char)ascii_clean[*pnt];
 
     return str;
 }
diff -Naurp neon-0.28.3/src/ne_xml.c neon-0.28.3.oden/src/ne_xml.c
--- neon-0.28.3/src/ne_xml.c	2007-08-09 05:46:36.000000000 -0400
+++ neon-0.28.3.oden/src/ne_xml.c	2009-08-24 13:14:44.000000000 -0400
@@ -405,6 +405,28 @@ static void end_element(void *userdata, 
     destroy_element(elm);
 }
 
+#if defined(HAVE_EXPAT) && XML_MAJOR_VERSION > 1
+/* Stop the parser if an entity declaration is hit. */
+static void entity_declaration(void *userData, const XML_Char *entityName,
+                              int is_parameter_entity, const XML_Char *value,
+                              int value_length, const XML_Char *base,
+                              const XML_Char *systemId, const XML_Char *publicId,
+                              const XML_Char *notationName)
+{
+    ne_xml_parser *parser = userData;
+    
+    NE_DEBUG(NE_DBG_XMLPARSE, "XML: entity declaration [%s]. Failing.\n",
+             entityName);
+
+    XML_StopParser(parser->parser, XML_FALSE);
+}
+#elif defined(HAVE_EXPAT)
+/* A noop default_handler. */
+static void default_handler(void *userData, const XML_Char *s, int len)
+{
+}
+#endif
+
 /* Find a namespace definition for 'prefix' in given element, where
  * length of prefix is 'pfxlen'.  Returns the URI or NULL. */
 static const char *resolve_nspace(const struct element *elm, 
@@ -459,14 +481,34 @@ ne_xml_parser *ne_xml_create(void) 
     XML_SetCharacterDataHandler(p->parser, char_data);
     XML_SetUserData(p->parser, (void *) p);
     XML_SetXmlDeclHandler(p->parser, decl_handler);
+
+    /* Prevent the "billion laughs" attack against expat by disabling
+     * internal entity expansion.  With 2.x, forcibly stop the parser
+     * if an entity is declared - this is safer and a more obvious
+     * failure mode.  With older versions, installing a noop
+     * DefaultHandler means that internal entities will be expanded as
+     * the empty string, which is also sufficient to prevent the
+     * attack. */
+#if XML_MAJOR_VERSION > 1
+    XML_SetEntityDeclHandler(p->parser, entity_declaration);
 #else
+    XML_SetDefaultHandler(p->parser, default_handler);
+#endif
+
+#else /* HAVE_LIBXML */
     p->parser = xmlCreatePushParserCtxt(&sax_handler, 
 					(void *)p, NULL, 0, NULL);
     if (p->parser == NULL) {
 	abort();
     }
+#if LIBXML_VERSION < 20602
     p->parser->replaceEntities = 1;
+#else
+    /* Enable expansion of entities, and disable network access. */
+    xmlCtxtUseOptions(p->parser, XML_PARSE_NOENT | XML_PARSE_NONET);
 #endif
+
+#endif /* HAVE_LIBXML || HAVE_EXPAT */
     return p;
 }