1 /**********************************************************************
2 
3   Audacity: A Digital Audio Editor
4 
5   XMLTagHandler.cpp
6 
7   Dominic Mazzoni
8   Vaughan Johnson
9 
10 
11 *//****************************************************************//**
12 
13 \class XMLTagHandler
14 \brief This class is an interface which should be implemented by
15   classes which wish to be able to load and save themselves
16   using XML files.
17 
18 \class XMLValueChecker
19 \brief XMLValueChecker implements static bool methods for checking
20   input values from XML files.
21 
22 *//*******************************************************************/
23 
24 #include "XMLTagHandler.h"
25 
26 #ifdef _WIN32
27    #include <windows.h>
28    #include <wx/msw/winundef.h>
29 #endif
30 
31 #include <wx/defs.h>
32 #include <wx/arrstr.h>
33 #include <wx/filename.h>
34 
35 #include "FileNames.h"
36 
37 
38 // "Good" means the name is well-formed and names an existing file or folder.
IsGoodFileName(const FilePath & strFileName,const FilePath & strDirName)39 bool XMLValueChecker::IsGoodFileName(const FilePath & strFileName, const FilePath & strDirName /* = "{} */)
40 {
41    // Test strFileName.
42    if (!IsGoodFileString(strFileName) ||
43          (strDirName.length() + 1 + strFileName.length() > PLATFORM_MAX_PATH))
44       return false;
45 
46    // Test the corresponding wxFileName.
47    wxFileName fileName(strDirName, strFileName);
48    return (fileName.IsOk() && fileName.FileExists());
49 }
50 
IsGoodFileString(const FilePath & str)51 bool XMLValueChecker::IsGoodFileString(const FilePath &str)
52 {
53    return (!str.empty() &&
54 
55             // FILENAME_MAX is 260 in MSVC, but inconsistent across platforms,
56             // sometimes huge, but we use 260 for all platforms.
57             (str.length() <= 260) &&
58 
59             (str.Find(wxFileName::GetPathSeparator()) == -1)); // No path separator characters.
60 }
61 
IsGoodSubdirName(const FilePath & strSubdirName,const FilePath & strDirName)62 bool XMLValueChecker::IsGoodSubdirName(const FilePath & strSubdirName, const FilePath & strDirName /* = {} */)
63 {
64    // Test strSubdirName.
65    // Note this prevents path separators, and relative path to parents (strDirName),
66    // so fixes vulnerability #3 in the NGS report for UmixIt,
67    // where an attacker could craft an AUP file with relative pathnames to get to system files, for example.
68    if (!IsGoodFileString(strSubdirName) ||
69          (strSubdirName == wxT(".")) || (strSubdirName == wxT("..")) ||
70          (strDirName.length() + 1 + strSubdirName.length() > PLATFORM_MAX_PATH))
71       return false;
72 
73    // Test the corresponding wxFileName.
74    wxFileName fileName(strDirName, strSubdirName);
75    return (fileName.IsOk() && fileName.DirExists());
76 }
77 
IsGoodPathName(const FilePath & strPathName)78 bool XMLValueChecker::IsGoodPathName(const FilePath & strPathName)
79 {
80    // Test the corresponding wxFileName.
81    wxFileName fileName(strPathName);
82    return XMLValueChecker::IsGoodFileName(fileName.GetFullName(), fileName.GetPath(wxPATH_GET_VOLUME));
83 }
84 
IsGoodPathString(const FilePath & str)85 bool XMLValueChecker::IsGoodPathString(const FilePath &str)
86 {
87    return (!str.empty() &&
88             (str.length() <= PLATFORM_MAX_PATH));
89 }
90 
ReadXMLTag(const char * tag,const char ** attrs)91 bool XMLTagHandler::ReadXMLTag(const char *tag, const char **attrs)
92 {
93    mCurrentTagAttributes.clear();
94 
95    while (*attrs) {
96       const char* name = *attrs++;
97       const char* value = *attrs++;
98 
99       mCurrentTagAttributes.emplace_back(
100          std::string_view(name), XMLAttributeValueView(std::string_view(value)));
101    }
102 
103    bool result = HandleXMLTag(tag, mCurrentTagAttributes);
104 
105    return result;
106 }
107 
ReadXMLEndTag(const char * tag)108 void XMLTagHandler::ReadXMLEndTag(const char *tag)
109 {
110    HandleXMLEndTag(tag);
111 }
112 
ReadXMLContent(const char * s,int len)113 void XMLTagHandler::ReadXMLContent(const char *s, int len)
114 {
115    HandleXMLContent(std::string_view(s, len));
116 }
117 
ReadXMLChild(const char * tag)118 XMLTagHandler *XMLTagHandler::ReadXMLChild(const char *tag)
119 {
120    return HandleXMLChild(tag);
121 }
122