Patch for CVE-2009-1759.
Source: Upstream SVN, rev 302 from the dtorrent-3 branch.

Index: a/bencode.h
===================================================================
--- a/bencode.h	(revision 300)
+++ b/bencode.h	(revision 302)
@@ -25,7 +25,7 @@
 size_t decode_list(const char *b,size_t len,const char *keylist);
 size_t decode_rev(const char *b,size_t len,const char *keylist);
 size_t decode_query(const char *b,size_t len,const char *keylist,const char **ps,size_t *pi,int64_t *pl,int method);
-size_t decode_list2path(const char *b, size_t n, char *pathname);
+size_t decode_list2path(const char *b, size_t n, char *pathname, size_t maxlen);
 size_t bencode_buf(const char *str,size_t len,FILE *fp);
 size_t bencode_str(const char *str, FILE *fp);
 size_t bencode_int(const uint64_t integer, FILE *fp);
Index: a/bencode.cpp
===================================================================
--- a/bencode.cpp	(revision 300)
+++ b/bencode.cpp	(revision 302)
@@ -233,22 +233,28 @@
   return bencode_end_dict_list(fp);
 }
 
-size_t decode_list2path(const char *b, size_t n, char *pathname)
+size_t decode_list2path(const char *b, size_t n, char *pathname, size_t maxlen)
 {
   const char *pb = b;
   const char *s = (char *) 0;
+  const char *endmax = pathname + maxlen - 1;
   size_t r,q;
 
   if( 'l' != *pb ) return 0;
   pb++;
   n--;
   if( !n ) return 0;
-  for(; n;){
+  while( n && pathname < endmax ){
     if(!(r = buf_str(pb, n, &s, &q)) ) return 0;
+    if( q >= maxlen ) return 0;
     memcpy(pathname, s, q);
     pathname += q;
-    pb += r; n -= r; 
-    if( 'e' != *pb ){*pathname = PATH_SP, pathname++;} else break;
+    maxlen -= q;
+    pb += r;
+    n -= r; 
+    if( 'e' == *pb ) break;
+    if( pathname >= endmax ) return 0;
+    *pathname++ = PATH_SP;
   }
   *pathname = '\0';
   return (pb - b + 1);
Index: a/btfiles.cpp
===================================================================
--- a/btfiles.cpp	(revision 300)
+++ b/btfiles.cpp	(revision 302)
@@ -449,7 +449,8 @@
   return 0;
 }
 
-int btFiles::BuildFromMI(const char *metabuf, const size_t metabuf_len, const char *saveas)
+int btFiles::BuildFromMI(const char *metabuf, const size_t metabuf_len,
+  const char *saveas, unsigned char exam_only)
 {
   char path[MAXPATHLEN];
   const char *s, *p;
@@ -458,11 +459,19 @@
   int f_warned = 0;
 
   if( !decode_query(metabuf, metabuf_len, "info|name", &s, &q, (int64_t*)0,
-      QUERY_STR) || MAXPATHLEN <= q )
+        QUERY_STR) || MAXPATHLEN <= q ){
+    errno = EINVAL;
     return -1;
+  }
 
   memcpy(path, s, q);
   path[q] = '\0';
+  if( !exam_only &&
+      (PATH_SP == path[0] || '/' == path[0] || 0==strncmp("..", path, 2)) ){
+    CONSOLE.Warning(1, "error, unsafe path \"%s\" in torrent data", path);
+    errno = EINVAL;
+    return -1;
+  }
 
   r = decode_query(metabuf, metabuf_len, "info|files", (const char**)0, &q,
                    (int64_t*)0, QUERY_POS);
@@ -471,21 +480,31 @@
     BTFILE *pbf_last = (BTFILE*) 0; 
     BTFILE *pbf = (BTFILE*) 0;
     size_t dl;
+    unsigned long nfiles = 0;
+
     if( decode_query(metabuf,metabuf_len,"info|length",
-                    (const char**) 0,(size_t*) 0,(int64_t*) 0,QUERY_LONG) )
+                    (const char**) 0,(size_t*) 0,(int64_t*) 0,QUERY_LONG) ){
+      errno = EINVAL;
       return -1;
+    }
 
     if( saveas ){
       m_directory = new char[strlen(saveas) + 1];
 #ifndef WINDOWS
-      if(!m_directory) return -1;
+      if( !m_directory ){
+        errno = ENOMEM;
+        return -1;
+      }
 #endif
       strcpy(m_directory,saveas);
     }else{
       int f_conv;
       char *tmpfn = new char[strlen(path)*2+5];
 #ifndef WINDOWS
-      if( !tmpfn ) return -1;
+      if( !tmpfn ){
+        errno = ENOMEM;
+        return -1;
+      }
 #endif
       if( f_conv = ConvertFilename(tmpfn, path, strlen(path)*2+5) ){
         if( arg_flg_convert_filenames ){
@@ -493,6 +512,7 @@
 #ifndef WINDOWS
           if( !m_directory ){
             delete []tmpfn;
+            errno = ENOMEM;
             return -1;
           }
 #endif
@@ -507,7 +527,10 @@
       if( !f_conv || !arg_flg_convert_filenames ){
         m_directory = new char[strlen(path) + 1];
 #ifndef WINDOWS
-        if( !m_directory ) return -1;
+        if( !m_directory ){
+          errno = ENOMEM;
+          return -1;
+        }
 #endif
         strcpy(m_directory,path);
       }
@@ -517,24 +540,50 @@
     p = metabuf + r + 1; 
     q--;
     for(; q && 'e' != *p; p += dl, q -= dl){
-      if(!(dl = decode_dict(p, q, (const char*) 0)) ) return -1;
-      if( !decode_query(p, dl, "length", (const char**) 0,
-                       (size_t*) 0,&t,QUERY_LONG) ) return -1;
+      if( !(dl = decode_dict(p, q, (const char*) 0)) ||
+          !decode_query(p, dl, "length", (const char**) 0, (size_t*) 0, &t,
+                        QUERY_LONG) ){
+        errno = EINVAL;
+        return -1;
+      }
       pbf = _new_bfnode();
 #ifndef WINDOWS
-      if( !pbf ) return -1;
+      if( !pbf ){
+        errno = ENOMEM;
+        return -1;
+      }
 #endif
+      nfiles++;
       pbf->bf_length = t;
       m_total_files_length += t;
       r = decode_query(p, dl, "path", (const char **)0, &n, (int64_t*)0,
                        QUERY_POS);
-      if( !r ) return -1;
-      if(!decode_list2path(p + r, n, path)) return -1;
+      if( !r || !decode_list2path(p + r, n, path, sizeof(path)) ){
+        CONSOLE.Warning(1,
+          "error, invalid path in torrent data for file %lu at offset %llu",
+          nfiles, m_total_files_length - t);
+        delete pbf;
+        errno = EINVAL;
+        return -1;
+      }
+      if( !exam_only &&
+          (PATH_SP == path[0] || '/' == path[0] || 0==strncmp("..", path, 2)) ){
+        CONSOLE.Warning(1,
+          "error, unsafe path \"%s\" in torrent data for file %lu",
+          path, nfiles);
+        delete pbf;
+        errno = EINVAL;
+        return -1;
+      }
 
+
       int f_conv;
       char *tmpfn = new char[strlen(path)*2+5];
 #ifndef WINDOWS
-      if( !tmpfn ) return -1;
+      if( !tmpfn ){
+        errno = ENOMEM;
+        return -1;
+      }
 #endif
       if( f_conv = ConvertFilename(tmpfn, path, strlen(path)*2+5) ){
         if( arg_flg_convert_filenames ){
@@ -542,6 +591,7 @@
 #ifndef WINDOWS
           if( !pbf->bf_filename ){
             delete []tmpfn;
+            errno = ENOMEM;
             return -1;
           }
 #endif
@@ -556,7 +606,10 @@
       if( !f_conv || !arg_flg_convert_filenames ){
         pbf->bf_filename = new char[strlen(path) + 1];
 #ifndef WINDOWS
-        if( !pbf->bf_filename ) return -1;
+        if( !pbf->bf_filename ){
+          errno = ENOMEM;
+          return -1;
+        }
 #endif
         strcpy(pbf->bf_filename, path);
       }
@@ -564,30 +617,42 @@
       pbf_last = pbf;
     }
   }else{
-    if( !decode_query(metabuf,metabuf_len,"info|length",
-                     (const char**) 0,(size_t*) 0,&t,QUERY_LONG) )
+    if( !decode_query(metabuf,metabuf_len, "info|length",
+                      (const char**)0, (size_t*) 0, &t, QUERY_LONG) ){
+      errno = EINVAL;
       return -1;
+    }
     m_btfhead = _new_bfnode();
 #ifndef WINDOWS
-    if( !m_btfhead) return -1;
+    if( !m_btfhead ){
+      errno = ENOMEM;
+      return -1;
+    }
 #endif
     m_btfhead->bf_length = m_total_files_length = t;
     if( saveas ){
       m_btfhead->bf_filename = new char[strlen(saveas) + 1];
 #ifndef WINDOWS
-      if(!m_btfhead->bf_filename ) return -1;
+      if( !m_btfhead->bf_filename ){
+        errno = ENOMEM;
+        return -1;
+      }
 #endif
       strcpy(m_btfhead->bf_filename, saveas);
     }else if( arg_flg_convert_filenames ){
       char *tmpfn = new char[strlen(path)*2+5];
 #ifndef WINDOWS
-      if( !tmpfn ) return -1;
+      if( !tmpfn ){
+        errno = ENOMEM;
+        return -1;
+      }
 #endif
       ConvertFilename(tmpfn, path, strlen(path)*2+5);
       m_btfhead->bf_filename = new char[strlen(tmpfn) + 1];
 #ifndef WINDOWS
       if( !m_btfhead->bf_filename ){
         delete []tmpfn;
+        errno = ENOMEM;
         return -1;
       }
 #endif
@@ -596,7 +661,10 @@
     }else{
       m_btfhead->bf_filename = new char[strlen(path) + 1];
 #ifndef WINDOWS
-      if(!m_btfhead->bf_filename ) return -1;
+      if( !m_btfhead->bf_filename ){
+        errno = ENOMEM;
+        return -1;
+      }
 #endif
       strcpy(m_btfhead->bf_filename, path);
     }
@@ -694,6 +762,32 @@
 size_t btFiles::FillMetaInfo(FILE* fp)
 {
   BTFILE *p;
+  const char *refname, *s;
+  char path[MAXPATHLEN];
+
+  refname = m_directory ? m_directory : m_btfhead->bf_filename;
+  while( (s = strchr(refname, PATH_SP)) && *(s + 1) ){
+    refname = s + 1;
+  }
+  if( m_directory && '.' == *refname ){
+    char dir[MAXPATHLEN];
+    if( getcwd(dir, sizeof(dir)) && 0==chdir(m_directory) ){
+      if( getcwd(path, sizeof(path)) ){
+        refname = path;
+        while( (s = strchr(refname, PATH_SP)) && *(s + 1) ){
+          refname = s + 1;
+        }
+      }
+      chdir(dir);
+    }
+  }
+  if( '/' == *refname || '\0' == *refname || '.' == *refname ){
+    CONSOLE.Warning(1, "error, inappropriate file or directory name \"%s\"",
+      m_directory ? m_directory : m_btfhead->bf_filename);
+    errno = EINVAL;
+    return 0;
+  }
+
   if( m_directory ){
     // multi files
     if( bencode_str("files", fp) != 1 ) return 0;
@@ -715,16 +809,15 @@
     if(bencode_end_dict_list(fp) != 1 ) return 0;
     
     if(bencode_str("name", fp) != 1) return 0;
-    return bencode_str(m_directory, fp);
-    
+    return bencode_str(refname, fp);
   }else{
     if( bencode_str("length", fp) != 1 ) return 0;
     if( bencode_int(m_btfhead->bf_length, fp) != 1) return 0;
     
     if( bencode_str("name", fp) != 1 ) return 0;
-    return bencode_str(m_btfhead->bf_filename, fp);
+    return bencode_str(refname, fp);
   }
-  return 1;
+  return 0;
 }
 
 
Index: a/btcontent.cpp
===================================================================
--- a/btcontent.cpp	(revision 300)
+++ b/btcontent.cpp	(revision 302)
@@ -357,7 +357,11 @@
 
   cfg_req_queue_length = (m_piece_length / cfg_req_slice_size) * 2 - 1;
 
-  if( m_btfiles.BuildFromMI(b, flen, saveas) < 0 ) ERR_RETURN();
+  if( m_btfiles.BuildFromMI(b, flen, saveas, arg_flg_exam_only) < 0 ){
+    if( EINVAL == errno )
+      CONSOLE.Warning(1, "Torrent metainfo file data is invalid or unusable.");
+    ERR_RETURN();
+  }
 
   delete []b;
   b = (char *)0;
Index: a/btfiles.h
===================================================================
--- a/btfiles.h	(revision 300)
+++ b/btfiles.h	(revision 302)
@@ -61,7 +61,7 @@
   
   int BuildFromFS(const char *pathname);
   int BuildFromMI(const char *metabuf, const size_t metabuf_len,
-                  const char *saveas);
+                  const char *saveas, unsigned char exam_only);
 
   char *GetDataName() const;
   uint64_t GetTotalLength() const { return m_total_files_length; }
