[pan] Work around corrupt/inconsistent file names.



commit d0cbb97fa2b2ae50581e900c563e2a72dbc62ac5
Author: Olaf Seibert <rhialto falu nl>
Date:   Wed Feb 12 20:15:41 2020 +0100

    Work around corrupt/inconsistent file names.
    
    These changes to allow the file name given in the Subject of a task list
    entry to be used instead of the one from the subject of the part(s) or
    the one that may be included in the encoding format.

 pan/tasks/decoder.cc      | 15 ++++++++---
 pan/tasks/decoder.h       |  4 ++-
 pan/tasks/task-article.cc |  2 +-
 uulib/uucheck.c           | 69 ++++++++++++++++++++++++++++++++++++++++++-----
 uulib/uudeview.h          |  4 +--
 uulib/uulib.c             | 22 +++++++++++++--
 6 files changed, 99 insertions(+), 17 deletions(-)
---
diff --git a/pan/tasks/decoder.cc b/pan/tasks/decoder.cc
index bdfe7cc..6c792a7 100644
--- a/pan/tasks/decoder.cc
+++ b/pan/tasks/decoder.cc
@@ -59,7 +59,8 @@ Decoder :: enqueue (TaskArticle                     * task,
                     const strings_t                 & input_files,
                     const TaskArticle::SaveMode     & save_mode,
                     const TaskArticle::SaveOptions  & options,
-                    const StringView                & filename)
+                    const StringView                & filename,
+                    const Article                   & article)
 {
   disable_progress_update ();
 
@@ -69,6 +70,7 @@ Decoder :: enqueue (TaskArticle                     * task,
   this->save_mode = save_mode;
   this->options = options;
   this->attachment_filename = filename;
+  this->article_subject = article.subject;
 
   mark_read = false;
 
@@ -147,7 +149,12 @@ Decoder :: do_work()
       {
 
         if (was_cancelled()) break;
-        if ((res = UULoadFileWithPartNo (const_cast<char*>(it->c_str()), 0, 0, ++i)) != UURET_OK) {
+        const char *global_subject = NULL;
+        // In SAVE_ALL mode, article_subject is the subject from the NZB file, if known
+        if (options == TaskArticle::SAVE_ALL && !article_subject.empty()) {
+          global_subject = article_subject.c_str();
+        }
+        if ((res = UULoadFileWithPartNo (const_cast<char*>(it->c_str()), 0, 0, ++i, global_subject)) != 
UURET_OK) {
           g_snprintf(buf, bufsz,
                      _("Error reading from %s: %s"),
                      it->c_str(),
@@ -169,8 +176,8 @@ Decoder :: do_work()
       {
         // skip all other attachments in SAVE_AS mode (single attachment download)
         /// DBG why is this failing if article isn't cached????
-        if (!attachment_filename.empty())
-          if(strcmp(item->filename, attachment_filename.str) != 0 && options == TaskArticle::SAVE_AS) 
continue;
+        if (options == TaskArticle::SAVE_AS && !attachment_filename.empty())
+          if(strcmp(item->filename, attachment_filename.str) != 0) continue;
 
         file_errors.clear ();
 
diff --git a/pan/tasks/decoder.h b/pan/tasks/decoder.h
index c5653e4..ad97516 100644
--- a/pan/tasks/decoder.h
+++ b/pan/tasks/decoder.h
@@ -59,7 +59,8 @@ namespace pan
                     const strings_t                & input_files,
                     const TaskArticle::SaveMode    & save_mode,
                     const TaskArticle::SaveOptions & options,
-                    const StringView               & filename);
+                    const StringView               & filename,
+                    const Article                  & article);
 
     public:
 
@@ -80,6 +81,7 @@ namespace pan
       TaskArticle::SaveMode save_mode;
       TaskArticle::SaveOptions options;
       StringView attachment_filename;
+      Quark article_subject;
 
       // These are set in the worker thread and polled in the main thread.
       Mutex mut;
diff --git a/pan/tasks/task-article.cc b/pan/tasks/task-article.cc
index 1dc17ba..307fcc6 100644
--- a/pan/tasks/task-article.cc
+++ b/pan/tasks/task-article.cc
@@ -347,7 +347,7 @@ TaskArticle :: use_decoder (Decoder* decoder)
   _state.set_working();
   const Article::mid_sequence_t mids (_article.get_part_mids());
   ArticleCache :: strings_t filenames (_cache.get_filenames (mids));
-  _decoder->enqueue (this, _save_path, filenames, _save_mode, _options, _attachment);
+  _decoder->enqueue (this, _save_path, filenames, _save_mode, _options, _attachment, _article);
   set_status_va (_("Decoding %s"), _article.subject.c_str());
   debug ("decoder thread was free, enqueued work");
 }
diff --git a/uulib/uucheck.c b/uulib/uucheck.c
index 98cb8e0..0f128d0 100644
--- a/uulib/uucheck.c
+++ b/uulib/uucheck.c
@@ -86,6 +86,12 @@ static char *nofname = "UNKNOWN";
 
 static char *fnchars = "._-~!";
 
+/*
+ * special characters we forbid a quoted filename to have
+ */
+
+static char *fnqchars = "/:\\\"";
+
 /*
  * Policy for extracting a part number from the subject line.
  * usually, look for part numbers in () brackets first, then in []
@@ -148,23 +154,27 @@ UUGetFileName (char *subject, char *ptonum, char *ptonend)
   }
 
   /*
-   * If the file was encoded by uuenview, then the filename is enclosed
-   * in [brackets]. But check what's inside these bracket's, try not to
-   * fall for something other than a filename
+   * Try try to find a file name between quotes.
+   * With yEnc this format is compulsory.
    */
 
   ptr = subject;
-  while ((iter = strchr (ptr, '[')) != NULL) {
-    if (strchr (iter, ']') == NULL) {
+  while ((iter = strchr (ptr, '"')) != NULL) {
+    /* Don't overlap the sequence number */
+    if (ptonum && ptonend && iter >= ptonum && iter <= ptonend) {
       ptr = iter + 1;
       continue;
     }
     iter++;
+    if (strchr (iter, '"') == NULL) {
+      ptr = iter + 1;
+      continue;
+    }
     while (isspace (*iter))
       iter++;
     count = length = alflag = 0;
     while (iter[count] && 
-          (isalnum (iter[count]) || strchr (fnchars, iter[count])!=NULL)) {
+          (strchr (fnqchars, iter[count])==NULL)) {
       if (isalpha (iter[count]))
        alflag++;
       count++;
@@ -173,10 +183,15 @@ UUGetFileName (char *subject, char *ptonum, char *ptonend)
       ptr = iter + 1;
       continue;
     }
+    /* Don't overlap the sequence number */
+    if (ptonum && ptonend && iter+count >= ptonum && iter+count <= ptonend) {
+      ptr = iter + 1;
+      continue;
+    }
     length = count;
     while (isspace (iter[count]))
       count++;
-    if (iter[count] == ']') {
+    if (iter[count] == '"') {
       ptr = iter;
       break;
     }
@@ -184,6 +199,46 @@ UUGetFileName (char *subject, char *ptonum, char *ptonend)
     ptr = iter + 1;
   }
 
+
+  /*
+   * If the file was encoded by uuenview, then the filename is enclosed
+   * in [brackets]. But check what's inside these bracket's, try not to
+   * fall for something other than a filename
+   */
+
+  if (length == 0) {
+    ptr = subject;
+    while ((iter = strchr (ptr, '[')) != NULL) {
+      if (strchr (iter, ']') == NULL) {
+        ptr = iter + 1;
+        continue;
+      }
+      iter++;
+      while (isspace (*iter))
+        iter++;
+      count = length = alflag = 0;
+      while (iter[count] &&
+             (isalnum (iter[count]) || iter[count] == ' ' || strchr (fnchars, iter[count])!=NULL)) {
+        if (isalpha (iter[count]))
+          alflag++;
+        count++;
+      }
+      if (count<4 || alflag==0) {
+        ptr = iter + 1;
+        continue;
+      }
+      length = count;
+      while (isspace (iter[count]))
+        count++;
+      if (iter[count] == ']') {
+        ptr = iter;
+        break;
+      }
+      length = 0;
+      ptr = iter + 1;
+    }
+  }
+
   /*
    * new filename detection routine, fists mostly for files by ftp-by-email
    * servers that create subject lines with ftp.host.address:/full/path/file
diff --git a/uulib/uudeview.h b/uulib/uudeview.h
index 753279d..6d0c6f6 100644
--- a/uulib/uudeview.h
+++ b/uulib/uudeview.h
@@ -206,7 +206,7 @@ int UUEXPORT UUSetFNameFilter       _ANSI_ARGS_((void *,
                                                                 char *)));
 char * UUEXPORT UUFNameFilter          _ANSI_ARGS_((char *));
 int    UUEXPORT UULoadFile             _ANSI_ARGS_((char *, char *, int));
-int    UUEXPORT UULoadFileWithPartNo   _ANSI_ARGS_((char *, char *, int, int));
+int    UUEXPORT UULoadFileWithPartNo   _ANSI_ARGS_((char *, char *, int, int, const char *));
 uulist *UUEXPORT UUGetFileListItem     _ANSI_ARGS_((int));
 int    UUEXPORT UURenameFile           _ANSI_ARGS_((uulist *, char *));
 int    UUEXPORT UUDecodeToTemp         _ANSI_ARGS_((uulist *));
@@ -227,7 +227,7 @@ int UUEXPORT UUEncodeMulti          _ANSI_ARGS_((FILE *, FILE *,
 int    UUEXPORT UUEncodePartial        _ANSI_ARGS_((FILE *, FILE *,
                                                     char *, int,
                                                     char *, char *,
-                                                    int, int, long, unsigned long*));
+                                                    int, int, long, uint32_t*));
 int    UUEXPORT UUEncodePartial_byFSize        _ANSI_ARGS_((FILE *, FILE *,
                                                     char *, int,
                                                     char *, char *,
diff --git a/uulib/uulib.c b/uulib/uulib.c
index 2d6816d..4b7f845 100644
--- a/uulib/uulib.c
+++ b/uulib/uulib.c
@@ -655,11 +655,11 @@ UUFNameFilter (char *fname)
 int UUEXPORT
 UULoadFile (char *filename, char *fileid, int delflag)
 {
-  return UULoadFileWithPartNo(filename, fileid, delflag, -1);
+  return UULoadFileWithPartNo(filename, fileid, delflag, -1, NULL);
 }
 
 int UUEXPORT
-UULoadFileWithPartNo (char *filename, char *fileid, int delflag, int partno)
+UULoadFileWithPartNo (char *filename, char *fileid, int delflag, int partno, const char *global_subject)
 {
   int res, sr, count=0;
   struct stat finfo;
@@ -779,6 +779,14 @@ UULoadFileWithPartNo (char *filename, char *fileid, int delflag, int partno)
       continue;
     }
 
+    if (partno != -1 && global_subject /*&& loaded->uudet == YENC_ENCODED*/) {
+      /*
+       * Sometimes articles derived from an NZB file have corrupt Subject: lines.
+       * That also makes that UUInsertPartToList() fails to combine files properly.
+       */
+      loaded->subject = _FP_strdup(global_subject);
+    }
+
     if ((fload = UUPreProcessPart (loaded, &res)) == NULL) {
       /*
        * no useful data found
@@ -793,6 +801,16 @@ UULoadFileWithPartNo (char *filename, char *fileid, int delflag, int partno)
       continue;
     }
 
+    if (partno != -1 && global_subject /*&& loaded->uudet == YENC_ENCODED*/) {
+      /*
+       * If the yEnc file gives a different file name than the subject,
+       * this is a security risk.
+       *
+       * Override the part file name with the one derived from the global subject.
+       */
+      fload->filename = _FP_strdup(fload->subfname);
+    }
+
     if ((loaded->subject && *(loaded->subject)) ||
        (loaded->mimeid  && *(loaded->mimeid))  ||
        (loaded->filename&& *(loaded->filename))||


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]