/src/osquery/plugins/logger/tls_logger.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  |  | // clang-format off  | 
11  |  | // Keep it on top of all other includes to fix double include WinSock.h header file  | 
12  |  | // which is windows specific boost build problem  | 
13  |  | #include <osquery/remote/utility.h>  | 
14  |  | // clang-format on  | 
15  |  |  | 
16  |  | #include "tls_logger.h"  | 
17  |  |  | 
18  |  | #include <boost/property_tree/ptree.hpp>  | 
19  |  |  | 
20  |  | #include <osquery/remote/enroll/enroll.h>  | 
21  |  | #include <osquery/core/flags.h>  | 
22  |  | #include <osquery/core/flagalias.h>  | 
23  |  | #include <osquery/registry/registry.h>  | 
24  |  |  | 
25  |  | #include <osquery/remote/serializers/json.h>  | 
26  |  |  | 
27  |  | #include <plugins/config/parsers/decorators.h>  | 
28  |  | #include <osquery/utils/json/json.h>  | 
29  |  |  | 
30  |  | namespace osquery { | 
31  |  |  | 
32  |  | FLAG(uint64,  | 
33  |  |      logger_tls_max_lines,  | 
34  |  |      1024,  | 
35  |  |      "Max number of logs to send per period");  | 
36  |  |  | 
37  |  | FLAG(string, logger_tls_endpoint, "", "TLS/HTTPS endpoint for results logging");  | 
38  |  |  | 
39  |  | FLAG(uint64,  | 
40  |  |      logger_tls_period,  | 
41  |  |      4,  | 
42  |  |      "Seconds between flushing logs over TLS/HTTPS");  | 
43  |  |  | 
44  |  | FLAG(uint64,  | 
45  |  |      logger_tls_backoff_max,  | 
46  |  |      60 * 60,  | 
47  |  |      "Maximum seconds to wait before flushing logs over TLS/HTTPS. Backoff "  | 
48  |  |      "kicks in when regular flush fails. Should be a multiple of "  | 
49  |  |      "logger_tls_period. 0 disables backoff");  | 
50  |  |  | 
51  |  | FLAG(uint64,  | 
52  |  |      logger_tls_max_linesize,  | 
53  |  |      1 * 1024 * 1024,  | 
54  |  |      "Max size in bytes allowed per log line");  | 
55  |  |  | 
56  |  | FLAG(bool, tls_disable_status_log, false, "Disable sending status logs");  | 
57  |  |  | 
58  |  | // The flag name logger_tls_max is deprecated.  | 
59  |  | FLAG_ALIAS(google::uint64, logger_tls_max, logger_tls_max_linesize);  | 
60  |  |  | 
61  |  | FLAG(bool, logger_tls_compress, false, "GZip compress TLS/HTTPS request body");  | 
62  |  |  | 
63  |  | REGISTER(TLSLoggerPlugin, "logger", "tls");  | 
64  |  |  | 
65  |  | TLSLogForwarder::TLSLogForwarder()  | 
66  | 0  |     : BufferedLogForwarder("TLSLogForwarder", | 
67  | 0  |                            "tls",  | 
68  | 0  |                            std::chrono::seconds(FLAGS_logger_tls_period),  | 
69  | 0  |                            FLAGS_logger_tls_max_lines,  | 
70  | 0  |                            std::chrono::seconds(FLAGS_logger_tls_backoff_max)) { | 
71  | 0  |   uri_ = TLSRequestHelper::makeURI(FLAGS_logger_tls_endpoint);  | 
72  | 0  | }  | 
73  |  |  | 
74  | 0  | Status TLSLoggerPlugin::logString(const std::string& s) { | 
75  | 0  |   return forwarder_->logString(s);  | 
76  | 0  | }  | 
77  |  |  | 
78  | 0  | Status TLSLoggerPlugin::logStatus(const std::vector<StatusLogLine>& log) { | 
79  | 0  |   return forwarder_->logStatus(log);  | 
80  | 0  | }  | 
81  |  |  | 
82  | 0  | Status TLSLoggerPlugin::setUp() { | 
83  |  |   // Start the log forwarding/flushing thread.  | 
84  | 0  |   forwarder_ = std::make_shared<TLSLogForwarder>();  | 
85  | 0  |   Status s = forwarder_->setUp();  | 
86  | 0  |   if (!s.ok()) { | 
87  | 0  |     LOG(ERROR) << "Error initializing TLS logger: " << s.getMessage();  | 
88  | 0  |     return s;  | 
89  | 0  |   }  | 
90  |  |  | 
91  | 0  |   auto node_key = getNodeKey("tls"); | 
92  | 0  |   if (!FLAGS_disable_enrollment && node_key.size() == 0) { | 
93  |  |     // Could not generate a node key, continue logging to stderr.  | 
94  | 0  |     return Status(1, "No node key, TLS logging disabled.");  | 
95  | 0  |   }  | 
96  |  |  | 
97  | 0  |   Dispatcher::addService(forwarder_);  | 
98  |  | 
  | 
99  | 0  |   return Status(0);  | 
100  | 0  | }  | 
101  |  |  | 
102  |  | void TLSLoggerPlugin::init(const std::string& name,  | 
103  | 0  |                            const std::vector<StatusLogLine>& log) { | 
104  | 0  |   logStatus(log);  | 
105  | 0  | }  | 
106  |  |  | 
107  | 0  | void TLSLoggerPlugin::configure() { | 
108  | 0  |   if (forwarder_ != nullptr) { | 
109  | 0  |     std::unique_lock<decltype(forwarder_->configuration_mutex)> lock(  | 
110  | 0  |         forwarder_->configuration_mutex);  | 
111  | 0  |     forwarder_->configuration_updated = true;  | 
112  | 0  |     forwarder_->updated_uri =  | 
113  | 0  |         TLSRequestHelper::makeURI(FLAGS_logger_tls_endpoint);  | 
114  | 0  |     forwarder_->updated_log_period =  | 
115  | 0  |         std::chrono::seconds(FLAGS_logger_tls_period);  | 
116  | 0  |     forwarder_->updated_max_log_lines = FLAGS_logger_tls_max_lines;  | 
117  | 0  |     forwarder_->updated_max_backoff_period =  | 
118  | 0  |         std::chrono::seconds(FLAGS_logger_tls_backoff_max);  | 
119  | 0  |   }  | 
120  | 0  | }  | 
121  |  |  | 
122  |  | Status TLSLogForwarder::send(std::vector<std::string>& log_data,  | 
123  | 0  |                              const std::string& log_type) { | 
124  |  |   // Skip sending status logs to remote server if disabled  | 
125  | 0  |   if (FLAGS_tls_disable_status_log && log_type == "status") { | 
126  | 0  |     return Status::success();  | 
127  | 0  |   }  | 
128  |  |  | 
129  | 0  |   JSON params;  | 
130  | 0  |   params.add("node_key", getNodeKey("tls")); | 
131  | 0  |   params.add("log_type", log_type); | 
132  |  | 
  | 
133  | 0  |   { | 
134  |  |     // Read each logged line into JSON and populate a list of lines.  | 
135  |  |     // The result list will use the 'data' key.  | 
136  | 0  |     auto children = params.newArray();  | 
137  | 0  |     iterate(log_data, ([¶ms, &children](std::string& item) { | 
138  |  |               // Enforce a max log line size for TLS logging.  | 
139  | 0  |               if (item.size() > FLAGS_logger_tls_max_linesize) { | 
140  | 0  |                 LOG(WARNING)  | 
141  | 0  |                     << "Linesize exceeds TLS logger maximum: " << item.size();  | 
142  | 0  |                 return;  | 
143  | 0  |               }  | 
144  |  |  | 
145  | 0  |               JSON child;  | 
146  | 0  |               Status s = child.fromString(item);  | 
147  | 0  |               if (!s.ok()) { | 
148  |  |                 // The log line entered was not valid JSON, skip it.  | 
149  | 0  |                 return;  | 
150  | 0  |               }  | 
151  | 0  |               std::string().swap(item);  | 
152  | 0  |               params.push(child.doc(), children.doc());  | 
153  | 0  |             }));  | 
154  | 0  |     params.add("data", children.doc()); | 
155  | 0  |   }  | 
156  |  |  | 
157  |  |   // The response body is ignored (status is set appropriately by  | 
158  |  |   // TLSRequestHelper::go())  | 
159  | 0  |   std::string response;  | 
160  | 0  |   if (FLAGS_logger_tls_compress) { | 
161  | 0  |     params.add("_compress", true); | 
162  | 0  |   }  | 
163  | 0  |   return TLSRequestHelper::go<JSONSerializer>(uri_, params, response);  | 
164  | 0  | }  | 
165  |  |  | 
166  | 0  | void TLSLogForwarder::applyNewConfiguration() { | 
167  | 0  |   std::unique_lock<decltype(configuration_mutex)> lock(configuration_mutex);  | 
168  | 0  |   if (configuration_updated) { | 
169  | 0  |     uri_ = updated_uri;  | 
170  | 0  |     log_period_ = updated_log_period;  | 
171  | 0  |     max_log_lines_ = updated_max_log_lines;  | 
172  | 0  |     max_backoff_period_ = updated_max_backoff_period;  | 
173  | 0  |   }  | 
174  | 0  |   configuration_updated = false;  | 
175  | 0  | }  | 
176  |  |  | 
177  |  | } // namespace osquery  |