/src/osquery/plugins/config/filesystem_config.cpp
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /**  | 
2  |  |  * Copyright (c) 2014-present, The osquery authors  | 
3  |  |  *  | 
4  |  |  * This source code is licensed as defined by the LICENSE file found in the  | 
5  |  |  * root directory of this source tree.  | 
6  |  |  *  | 
7  |  |  * SPDX-License-Identifier: (Apache-2.0 OR GPL-2.0-only)  | 
8  |  |  */  | 
9  |  |  | 
10  |  | #include <vector>  | 
11  |  |  | 
12  |  | #include <boost/filesystem/operations.hpp>  | 
13  |  | #include <boost/property_tree/json_parser.hpp>  | 
14  |  | #include <boost/property_tree/ptree.hpp>  | 
15  |  |  | 
16  |  | #include <osquery/config/config.h>  | 
17  |  | #include <osquery/core/flags.h>  | 
18  |  | #include <osquery/filesystem/filesystem.h>  | 
19  |  | #include <osquery/logger/logger.h>  | 
20  |  | #include <osquery/registry/registry_factory.h>  | 
21  |  | #include <osquery/utils/config/default_paths.h>  | 
22  |  |  | 
23  |  | #include <osquery/utils/json/json.h>  | 
24  |  |  | 
25  |  | namespace errc = boost::system::errc;  | 
26  |  | namespace fs = boost::filesystem;  | 
27  |  | namespace pt = boost::property_tree;  | 
28  |  |  | 
29  |  | namespace osquery { | 
30  |  |  | 
31  |  | CLI_FLAG(string,  | 
32  |  |          config_path,  | 
33  |  |          (fs::path(OSQUERY_HOME) / "osquery.conf").make_preferred().string(),  | 
34  |  |          "Path to JSON config file");  | 
35  |  |  | 
36  |  | class FilesystemConfigPlugin : public ConfigPlugin { | 
37  |  |  public:  | 
38  |  |   Status genConfig(std::map<std::string, std::string>& config);  | 
39  |  |   Status genPack(const std::string& name,  | 
40  |  |                  const std::string& value,  | 
41  |  |                  std::string& pack);  | 
42  |  | };  | 
43  |  |  | 
44  |  | REGISTER(FilesystemConfigPlugin, "config", "filesystem");  | 
45  |  |  | 
46  |  | Status FilesystemConfigPlugin::genConfig(  | 
47  | 0  |     std::map<std::string, std::string>& config) { | 
48  | 0  |   boost::system::error_code ec;  | 
49  | 0  |   if (!fs::is_regular_file(FLAGS_config_path, ec) ||  | 
50  | 0  |       ec.value() != errc::success) { | 
51  | 0  |     return Status::failure("config file does not exist: " + FLAGS_config_path); | 
52  | 0  |   }  | 
53  |  |  | 
54  | 0  |   std::vector<std::string> conf_files;  | 
55  | 0  |   resolveFilePattern(FLAGS_config_path + ".d/%.conf", conf_files);  | 
56  | 0  |   std::sort(conf_files.begin(), conf_files.end());  | 
57  | 0  |   conf_files.push_back(FLAGS_config_path);  | 
58  |  | 
  | 
59  | 0  |   for (const auto& path : conf_files) { | 
60  | 0  |     std::string content;  | 
61  | 0  |     if (readFile(path, content).ok()) { | 
62  | 0  |       config[path] = content;  | 
63  | 0  |     }  | 
64  | 0  |   }  | 
65  |  | 
  | 
66  | 0  |   return Status(0, "OK");  | 
67  | 0  | }  | 
68  |  |  | 
69  |  | Status FilesystemConfigPlugin::genPack(const std::string& name,  | 
70  |  |                                        const std::string& value,  | 
71  | 0  |                                        std::string& pack) { | 
72  | 0  |   if (name == "*") { | 
73  |  |     // The config requested a multi-pack.  | 
74  | 0  |     std::vector<std::string> paths;  | 
75  | 0  |     resolveFilePattern(value, paths);  | 
76  |  | 
  | 
77  | 0  |     pt::ptree multi_pack;  | 
78  | 0  |     for (const auto& path : paths) { | 
79  | 0  |       std::string content;  | 
80  | 0  |       if (!readFile(path, content)) { | 
81  | 0  |         LOG(WARNING) << "Cannot read multi-pack file: " << path;  | 
82  | 0  |         continue;  | 
83  | 0  |       }  | 
84  |  |  | 
85  |  |       // Assemble an intermediate property tree for simplified parsing.  | 
86  | 0  |       pt::ptree single_pack;  | 
87  | 0  |       stripConfigComments(content);  | 
88  | 0  |       try { | 
89  | 0  |         std::stringstream json_stream;  | 
90  | 0  |         json_stream << content;  | 
91  | 0  |         pt::read_json(json_stream, single_pack);  | 
92  | 0  |       } catch (const pt::json_parser::json_parser_error& /* e */) { | 
93  | 0  |         LOG(WARNING) << "Cannot read multi-pack JSON: " << path;  | 
94  | 0  |         continue;  | 
95  | 0  |       }  | 
96  |  |  | 
97  | 0  |       multi_pack.put_child(fs::path(path).stem().string(), single_pack);  | 
98  | 0  |     }  | 
99  |  |  | 
100  |  |     // We should have a property tree of pack content mimicking embedded  | 
101  |  |     // configuration packs, ready to parse as a string.  | 
102  | 0  |     std::ostringstream output;  | 
103  | 0  |     pt::write_json(output, multi_pack, false);  | 
104  | 0  |     pack = output.str();  | 
105  | 0  |     if (pack.empty()) { | 
106  | 0  |       return Status(1, "Multi-pack content empty");  | 
107  | 0  |     }  | 
108  |  |  | 
109  | 0  |     return Status(0);  | 
110  | 0  |   }  | 
111  |  |  | 
112  | 0  |   boost::system::error_code ec;  | 
113  | 0  |   if (!fs::is_regular_file(value, ec) || ec.value() != errc::success) { | 
114  | 0  |     return Status(1, value + " is not a valid path");  | 
115  | 0  |   }  | 
116  |  |  | 
117  | 0  |   return readFile(value, pack);  | 
118  | 0  | }  | 
119  |  | } // namespace osquery  |