]> git.llucax.com Git - software/mutt-debian.git/blobdiff - url.c
584138-mx_update_context-segfault.patch: fix a segfault due to holes in IMAP headers...
[software/mutt-debian.git] / url.c
diff --git a/url.c b/url.c
index 58c3642138cbd42c1affac09cb72a42e1460f976..347047cd98ff1fbeefdb77f461ecd81937689827 100644 (file)
--- a/url.c
+++ b/url.c
@@ -45,28 +45,32 @@ static struct mapping_t UrlMap[] =
   { NULL,      U_UNKNOWN }
 };
 
   { NULL,      U_UNKNOWN }
 };
 
-
-static void url_pct_decode (char *s)
+static int url_pct_decode (char *s)
 {
   char *d;
 
   if (!s)
 {
   char *d;
 
   if (!s)
-    return;
-  
+    return -1;
+
   for (d = s; *s; s++)
   {
   for (d = s; *s; s++)
   {
-    if (*s == '%' && s[1] && s[2] &&
-       isxdigit ((unsigned char) s[1]) &&
-        isxdigit ((unsigned char) s[2]) &&
-       hexval (s[1]) >= 0 && hexval (s[2]) >= 0)
+    if (*s == '%')
     {
     {
-      *d++ = (hexval (s[1]) << 4) | (hexval (s[2]));
-      s += 2;
-    }
-    else
+      if (s[1] && s[2] &&
+         isxdigit ((unsigned char) s[1]) &&
+         isxdigit ((unsigned char) s[2]) &&
+         hexval (s[1]) >= 0 && hexval (s[2]) >= 0)
+      {
+       *d++ = (hexval (s[1]) << 4) | (hexval (s[2]));
+       s += 2;
+      }
+      else
+       return -1;
+    } else
       *d++ = *s;
   }
   *d ='\0';
       *d++ = *s;
   }
   *d ='\0';
+  return 0;
 }
 
 url_scheme_t url_check_scheme (const char *s)
 }
 
 url_scheme_t url_check_scheme (const char *s)
@@ -74,12 +78,12 @@ url_scheme_t url_check_scheme (const char *s)
   char sbuf[STRING];
   char *t;
   int i;
   char sbuf[STRING];
   char *t;
   int i;
-  
+
   if (!s || !(t = strchr (s, ':')))
     return U_UNKNOWN;
   if (!s || !(t = strchr (s, ':')))
     return U_UNKNOWN;
-  if ((t - s) + 1 >= sizeof (sbuf))
+  if ((size_t)(t - s) >= sizeof (sbuf) - 1)
     return U_UNKNOWN;
     return U_UNKNOWN;
-  
+
   strfcpy (sbuf, s, t - s + 1);
   for (t = sbuf; *t; t++)
     *t = ascii_tolower (*t);
   strfcpy (sbuf, s, t - s + 1);
   for (t = sbuf; *t; t++)
     *t = ascii_tolower (*t);
@@ -98,33 +102,33 @@ int url_parse_file (char *d, const char *src, size_t dl)
     return -1;
   else
     strfcpy (d, src + 5, dl);
     return -1;
   else
     strfcpy (d, src + 5, dl);
-  
-  url_pct_decode (d);
-  return 0;
+
+  return url_pct_decode (d);
 }
 
 /* ciss_parse_userhost: fill in components of ciss with info from src. Note
  *   these are pointers into src, which is altered with '\0's. Port of 0
  *   means no port given. */
 }
 
 /* ciss_parse_userhost: fill in components of ciss with info from src. Note
  *   these are pointers into src, which is altered with '\0's. Port of 0
  *   means no port given. */
-static char *ciss_parse_userhost (ciss_url_t *ciss, char *src)
+static int ciss_parse_userhost (ciss_url_t *ciss, char *src)
 {
 {
-  char *t;
-  char *p;
-  char *path;
+  char *t, *p;
 
   ciss->user = NULL;
   ciss->pass = NULL;
   ciss->host = NULL;
   ciss->port = 0;
 
 
   ciss->user = NULL;
   ciss->pass = NULL;
   ciss->host = NULL;
   ciss->port = 0;
 
-  if (strncmp (src, "//", 2))
-    return src;
-  
+  if (strncmp (src, "//", 2) != 0)
+  {
+    ciss->path = src;
+    return url_pct_decode (ciss->path);
+  }
+
   src += 2;
 
   src += 2;
 
-  if ((path = strchr (src, '/')))
-    *path++ = '\0';
-  
+  if ((ciss->path = strchr (src, '/')))
+    *ciss->path++ = '\0';
+
   if ((t = strrchr (src, '@')))
   {
     *t = '\0';
   if ((t = strrchr (src, '@')))
   {
     *t = '\0';
@@ -132,27 +136,31 @@ static char *ciss_parse_userhost (ciss_url_t *ciss, char *src)
     {
       *p = '\0';
       ciss->pass = p + 1;
     {
       *p = '\0';
       ciss->pass = p + 1;
-      url_pct_decode (ciss->pass);
+      if (url_pct_decode (ciss->pass) < 0)
+       return -1;
     }
     ciss->user = src;
     }
     ciss->user = src;
-    url_pct_decode (ciss->user);
+    if (url_pct_decode (ciss->user) < 0)
+      return -1;
     t++;
   }
   else
     t = src;
     t++;
   }
   else
     t = src;
-  
+
   if ((p = strchr (t, ':')))
   {
   if ((p = strchr (t, ':')))
   {
+    int t;
     *p++ = '\0';
     *p++ = '\0';
-    if (mutt_atos (p, (short*) &ciss->port) < 0)
-      return NULL;
+    if (mutt_atoi (p, &t) < 0 || t < 0 || t > 0xffff)
+      return -1;
+    ciss->port = (unsigned short)t;
   }
   else
     ciss->port = 0;
   }
   else
     ciss->port = 0;
-  
+
   ciss->host = t;
   ciss->host = t;
-  url_pct_decode (ciss->host);
-  return path;
+  return url_pct_decode (ciss->host) >= 0 &&
+    (!ciss->path || url_pct_decode (ciss->path) >= 0) ? 0 : -1;
 }
 
 /* url_parse_ciss: Fill in ciss_url_t. char* elements are pointers into src,
 }
 
 /* url_parse_ciss: Fill in ciss_url_t. char* elements are pointers into src,
@@ -166,15 +174,31 @@ int url_parse_ciss (ciss_url_t *ciss, char *src)
 
   tmp = strchr (src, ':') + 1;
 
 
   tmp = strchr (src, ':') + 1;
 
-  if ((ciss->path = ciss_parse_userhost (ciss, tmp)) == NULL)
-    return -1;
-  url_pct_decode (ciss->path);
-  
-  return 0;
+  return ciss_parse_userhost (ciss, tmp);
 }
 
 }
 
-/* url_ciss_tostring: output the URL string for a given CISS object. */
+static void url_pct_encode (char *dst, size_t l, const char *src)
+{
+  static const char *alph = "0123456789ABCDEF";
 
 
+  *dst = 0;
+  l--;
+  while (src && *src && l)
+  {
+    if (strchr ("/:%", *src) && l > 3)
+    {
+      *dst++ = '%';
+      *dst++ = alph[(*src >> 4) & 0xf];
+      *dst++ = alph[*src & 0xf];
+      src++;
+      continue;
+    }
+    *dst++ = *src++;
+  }
+  *dst = 0;
+}
+
+/* url_ciss_tostring: output the URL string for a given CISS object. */
 int url_ciss_tostring (ciss_url_t* ciss, char* dest, size_t len, int flags)
 {
   long l;
 int url_ciss_tostring (ciss_url_t* ciss, char* dest, size_t len, int flags)
 {
   long l;
@@ -189,12 +213,20 @@ int url_ciss_tostring (ciss_url_t* ciss, char* dest, size_t len, int flags)
     if (!(flags & U_PATH))
       safe_strcat (dest, len, "//");
     len -= (l = strlen (dest)); dest += l;
     if (!(flags & U_PATH))
       safe_strcat (dest, len, "//");
     len -= (l = strlen (dest)); dest += l;
-    
-    if (ciss->user) {
+
+    if (ciss->user)
+    {
+      char u[STRING];
+      url_pct_encode (u, sizeof (u), ciss->user);
+
       if (flags & U_DECODE_PASSWD && ciss->pass)
       if (flags & U_DECODE_PASSWD && ciss->pass)
-       snprintf (dest, len, "%s:%s@", ciss->user, ciss->pass);
+      {
+       char p[STRING];
+       url_pct_encode (p, sizeof (p), ciss->pass);
+       snprintf (dest, len, "%s:%s@", u, p);
+      }
       else
       else
-       snprintf (dest, len, "%s@", ciss->user);
+       snprintf (dest, len, "%s@", u);
 
       len -= (l = strlen (dest)); dest += l;
     }
 
       len -= (l = strlen (dest)); dest += l;
     }
@@ -217,26 +249,28 @@ int url_parse_mailto (ENVELOPE *e, char **body, const char *src)
   char *tmp;
   char *headers;
   char *tag, *value;
   char *tmp;
   char *headers;
   char *tag, *value;
-  char scratch[HUGE_STRING];
 
 
-  int taglen, rc = 0;
+  int rc = -1;
 
   LIST *last = NULL;
 
   LIST *last = NULL;
-  
+
   if (!(t = strchr (src, ':')))
     return -1;
   if (!(t = strchr (src, ':')))
     return -1;
-  
+
+  /* copy string for safe use of strtok() */
   if ((tmp = safe_strdup (t + 1)) == NULL)
     return -1;
 
   if ((headers = strchr (tmp, '?')))
     *headers++ = '\0';
 
   if ((tmp = safe_strdup (t + 1)) == NULL)
     return -1;
 
   if ((headers = strchr (tmp, '?')))
     *headers++ = '\0';
 
-  url_pct_decode (tmp);
+  if (url_pct_decode (tmp) < 0)
+    goto out;
+
   e->to = rfc822_parse_adrlist (e->to, tmp);
 
   tag = headers ? strtok_r (headers, "&", &p) : NULL;
   e->to = rfc822_parse_adrlist (e->to, tmp);
 
   tag = headers ? strtok_r (headers, "&", &p) : NULL;
-  
+
   for (; tag; tag = strtok_r (NULL, "&", &p))
   {
     if ((value = strchr (tag, '=')))
   for (; tag; tag = strtok_r (NULL, "&", &p))
   {
     if ((value = strchr (tag, '=')))
@@ -244,31 +278,32 @@ int url_parse_mailto (ENVELOPE *e, char **body, const char *src)
     if (!value || !*value)
       continue;
 
     if (!value || !*value)
       continue;
 
-    url_pct_decode (tag);
-    url_pct_decode (value);
+    if (url_pct_decode (tag) < 0)
+      goto out;
+    if (url_pct_decode (value) < 0)
+      goto out;
 
     if (!ascii_strcasecmp (tag, "body"))
     {
       if (body)
        mutt_str_replace (body, value);
     }
 
     if (!ascii_strcasecmp (tag, "body"))
     {
       if (body)
        mutt_str_replace (body, value);
     }
-    else if ((taglen = mutt_strlen (tag)) <= sizeof (scratch) - 2)
+    else
     {
     {
-      /* only try to parse if we can format it as header for
-       * mutt_parse_rfc822_line (tag fits in scratch) */
-      snprintf (scratch, sizeof (scratch), "%s: %s", tag, value);
-      scratch[taglen] = '\0';
-      value = &scratch[taglen+1];
+      char *scratch;
+      size_t taglen = mutt_strlen (tag);
+     
+      safe_asprintf (&scratch, "%s: %s", tag, value);
+      scratch[taglen] = 0; /* overwrite the colon as mutt_parse_rfc822_line expects */
+      value = &scratch[taglen + 1];
       SKIPWS (value);
       mutt_parse_rfc822_line (e, NULL, scratch, value, 1, 0, 0, &last);
       SKIPWS (value);
       mutt_parse_rfc822_line (e, NULL, scratch, value, 1, 0, 0, &last);
-    }
-    else
-    {
-      rc = -1;
-      goto out;
+      FREE (&scratch);
     }
   }
 
     }
   }
 
+  rc = 0;
+
 out:
   FREE (&tmp);
   return rc;
 out:
   FREE (&tmp);
   return rc;