a5319efe78298498bc004bc3529dd250d2a11503
[platform/core/security/vist.git] / src / osquery / core / init.cpp
1 /**
2  *  Copyright (c) 2014-present, Facebook, Inc.
3  *  All rights reserved.
4  *
5  *  This source code is licensed in accordance with the terms specified in
6  *  the LICENSE file found in the root directory of this source tree.
7  */
8
9 #include <chrono>
10 #include <iostream>
11 #include <random>
12 #include <thread>
13
14 #include <stdio.h>
15 #include <time.h>
16
17 #include <osquery/system.h>
18
19 #ifdef WIN32
20
21 #include <osquery/utils/system/system.h>
22
23 #include <WbemIdl.h>
24 #include <signal.h>
25
26 #else
27 #include <unistd.h>
28 #endif
29
30 #ifndef WIN32
31 #include <sys/resource.h>
32 #endif
33
34 #include <boost/filesystem.hpp>
35
36 #include "osquery/utils/config/default_paths.h"
37 #include "osquery/utils/info/platform_type.h"
38 #include <osquery/core.h>
39 #include <osquery/data_logger.h>
40 #include <osquery/registry.h>
41 #include <osquery/utils/info/version.h>
42 #include <osquery/utils/system/time.h>
43
44 #ifdef __linux__
45 #include <sys/syscall.h>
46
47 /*
48  * These are the io priority groups as implemented by CFQ. RT is the realtime
49  * class, it always gets premium service. BE is the best-effort scheduling
50  * class, the default for any process. IDLE is the idle scheduling class, it
51  * is only served when no one else is using the disk.
52  */
53 enum {
54   IOPRIO_CLASS_NONE,
55   IOPRIO_CLASS_RT,
56   IOPRIO_CLASS_BE,
57   IOPRIO_CLASS_IDLE,
58 };
59
60 /*
61  * 8 best effort priority levels are supported
62  */
63 #define IOPRIO_BE_NR (8)
64
65 enum {
66   IOPRIO_WHO_PROCESS = 1,
67   IOPRIO_WHO_PGRP,
68   IOPRIO_WHO_USER,
69 };
70 #endif
71
72 #define DESCRIPTION                                                            \
73   "osquery %s, your OS as a high-performance relational database\n"
74 #define EPILOG "\nosquery project page <https://osquery.io>.\n"
75 #define OPTIONS                                                                \
76   "\nosquery configuration options (set by config or CLI flags):\n\n"
77 #define OPTIONS_SHELL "\nosquery shell-only CLI flags:\n\n"
78 #define OPTIONS_CLI "osquery%s command line flags:\n\n"
79 #define USAGE "Usage: %s [OPTION]... %s\n\n"
80
81 namespace {
82 extern "C" {
83 volatile std::sig_atomic_t kHandledSignal{0};
84
85 void signalHandler(int num) {
86   // Inform exit status of main threads blocked by service joins.
87   if (kHandledSignal == 0) {
88     kHandledSignal = num;
89     // If no part of osquery requested an interruption then the exit 'wanted'
90     // code becomes the signal number.
91     if (num != SIGUSR1 && osquery::kExitCode == 0) {
92       // The only exception is SIGUSR1 which is used to signal the main thread
93       // to interrupt dispatched services.
94       osquery::kExitCode = 128 + num;
95     }
96
97     if (num == SIGTERM || num == SIGINT || num == SIGABRT ||
98         num == SIGUSR1) {
99       // Restore the default signal handler.
100       std::signal(num, SIG_DFL);
101     }
102   }
103 }
104 }
105 }
106
107 using chrono_clock = std::chrono::high_resolution_clock;
108
109 namespace fs = boost::filesystem;
110
111 namespace osquery {
112
113 ToolType kToolType{ToolType::UNKNOWN};
114
115 /// The saved exit code from a thread's request to stop the process.
116 volatile std::sig_atomic_t kExitCode{0};
117
118 /// The saved thread ID for shutdown to short-circuit raising a signal.
119 static std::thread::id kMainThreadId;
120
121 /// Legacy thread ID to ensure that the windows service waits before exiting
122 unsigned long kLegacyThreadId;
123
124 std::function<void()> Initializer::shutdown_{nullptr};
125 RecursiveMutex Initializer::shutdown_mutex_;
126
127 static inline void printUsage(const std::string& binary, ToolType tool) {
128   // Parse help options before gflags. Only display osquery-related options.
129   fprintf(stdout, DESCRIPTION, kVersion.c_str());
130   if (tool == ToolType::SHELL) {
131     // The shell allows a caller to run a single SQL statement and exit.
132     fprintf(stdout, USAGE, binary.c_str(), "[SQL STATEMENT]");
133   } else {
134     fprintf(stdout, USAGE, binary.c_str(), "");
135   }
136
137   fprintf(stdout, EPILOG);
138 }
139
140 Initializer::Initializer(int& argc,
141                          char**& argv,
142                          ToolType tool,
143                          bool const init_glog)
144     : argc_(&argc), argv_(&argv) {
145   // Initialize random number generated based on time.
146   std::srand(static_cast<unsigned int>(
147       chrono_clock::now().time_since_epoch().count()));
148
149   // osquery can function as the daemon or shell depending on argv[0].
150   if (tool == ToolType::SHELL_DAEMON) {
151     if (fs::path(argv[0]).filename().string().find("osqueryd") !=
152         std::string::npos) {
153       kToolType = ToolType::DAEMON;
154       binary_ = "osqueryd";
155     } else {
156       kToolType = ToolType::SHELL;
157       binary_ = "osqueryi";
158     }
159   } else {
160     // Set the tool type to allow runtime decisions based on daemon, shell, etc.
161     kToolType = tool;
162   }
163
164   // The 'main' thread is that which executes the initializer.
165   kMainThreadId = std::this_thread::get_id();
166
167   // Initialize the COM libs
168   platformSetup();
169 }
170
171 void Initializer::initDaemon() const {
172 }
173
174 void Initializer::initShell() const {
175 }
176
177 void Initializer::initWorker(const std::string& name) const {
178   // Clear worker's arguments.
179   auto original_name = std::string((*argv_)[0]);
180   for (int i = 1; i < *argc_; i++) {
181     if ((*argv_)[i] != nullptr) {
182       memset((*argv_)[i], '\0', strlen((*argv_)[i]));
183     }
184   }
185 }
186
187 void Initializer::initActivePlugin(const std::string& type,
188                                    const std::string& name) const {
189   auto rs = RegistryFactory::get().setActive(type, name);
190   if (!rs.ok()) {
191     LOG(ERROR) << "Cannot activate " << name << " " << type
192                << " plugin: " << rs.getMessage();
193     requestShutdown(EXIT_CATASTROPHIC);
194   }
195 }
196
197 void Initializer::installShutdown(std::function<void()>& handler) {
198   RecursiveLock lock(shutdown_mutex_);
199   shutdown_ = std::move(handler);
200 }
201
202 void Initializer::start() const {
203   // Run the setup for all lazy registries (tables, SQL).
204   Registry::setUp();
205 }
206
207 void Initializer::waitForShutdown() {
208   {
209     RecursiveLock lock(shutdown_mutex_);
210     if (shutdown_ != nullptr) {
211       // Copy the callable, then remove it, prevent callable recursion.
212       auto shutdown = shutdown_;
213       shutdown_ = nullptr;
214
215       // Call the shutdown callable.
216       shutdown();
217     }
218   }
219
220   auto excode = (kExitCode != 0) ? kExitCode : EXIT_SUCCESS;
221   exit(excode);
222 }
223
224 void Initializer::requestShutdown(int retcode) {
225   if (kExitCode == 0) {
226     kExitCode = retcode;
227   }
228 }
229
230 void Initializer::requestShutdown(int retcode, const std::string& system_log) {
231   requestShutdown(retcode);
232 }
233
234 void Initializer::shutdown(int retcode) {
235   platformTeardown();
236   ::exit(retcode);
237 }
238 }