-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Expand file tree
/
Copy pathsqlite_filesystem.cpp
More file actions
210 lines (199 loc) · 6.25 KB
/
Copy pathsqlite_filesystem.cpp
File metadata and controls
210 lines (199 loc) · 6.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/**
* Copyright (c) 2014-present, The osquery authors
*
* This source code is licensed as defined by the LICENSE file found in the
* root directory of this source tree.
*
* SPDX-License-Identifier: (Apache-2.0 OR GPL-2.0-only)
*/
#include <string>
#include <boost/filesystem.hpp>
#include <boost/optional.hpp>
#include <sqlite3.h>
namespace osquery {
static boost::optional<std::string> findExistingProgramPathFromCommand(
const char* path, char escape_symbol, bool allow_quoting, bool shortest) {
size_t length = strlen(path);
std::string result;
size_t pos = 0;
// Skip spaces
for (; pos < length; ++pos) {
if (!isspace(path[pos])) {
break;
}
}
std::string temp_string;
bool is_quoted = false;
bool is_escaped = false;
for (; pos < length; ++pos) {
if (is_escaped) {
temp_string += path[pos];
is_escaped = false;
continue;
}
if (allow_quoting && path[pos] == '"') {
is_quoted = !is_quoted;
continue;
}
if (path[pos] == escape_symbol) {
is_escaped = true;
continue;
}
if (!is_quoted && isspace(path[pos])) {
// validate temp string
boost::filesystem::path test_path = temp_string;
auto status = boost::filesystem::status(test_path);
if (boost::filesystem::exists(status) &&
!boost::filesystem::is_directory(status)) {
result = temp_string;
if (shortest) {
break;
}
}
}
temp_string += path[pos];
}
if (result.length() == 0 || !shortest) {
boost::filesystem::path test_path = temp_string;
auto status = boost::filesystem::status(test_path);
if (boost::filesystem::exists(status) &&
!boost::filesystem::is_directory(status)) {
result = temp_string;
}
}
return result;
}
static boost::optional<std::string> findExistingProgramPathFromCommandSqlArgs(
int argc, sqlite3_value** argv, bool shortest) {
if (argc == 0) {
return boost::none;
}
// NULLs are not allowed
for (int i = 0; i < argc; i++) {
if (SQLITE_NULL == sqlite3_value_type(argv[i])) {
return boost::none;
}
}
const char* path = reinterpret_cast<const char*>(sqlite3_value_text(argv[0]));
bool allow_quoting = false;
if (argc > 1) {
allow_quoting = sqlite3_value_int(argv[1]) != 0 ? true : false;
}
#ifdef WIN32
char escape_symbol = '^';
#else
char escape_symbol = '\\';
#endif
if (argc > 2) {
const char* escape_symbol_string =
reinterpret_cast<const char*>(sqlite3_value_text(argv[2]));
if (escape_symbol_string == NULL ||
std::strlen(escape_symbol_string) != 1) {
return boost::none;
}
escape_symbol = escape_symbol_string[0];
}
return findExistingProgramPathFromCommand(
path, escape_symbol, allow_quoting, shortest);
}
static void findFilePathInLaunchCommand(sqlite3_context* context,
int argc,
sqlite3_value** argv) {
auto result = findExistingProgramPathFromCommandSqlArgs(argc, argv, true);
if (result) {
sqlite3_result_text(context,
result->c_str(),
static_cast<int>(result->size()),
SQLITE_TRANSIENT);
} else {
sqlite3_result_error(
context, "Invalid inputs to find_binary_path_from_cmd", -1);
}
}
static void isPathDeterministic(sqlite3_context* context,
int argc,
sqlite3_value** argv) {
auto shortest = findExistingProgramPathFromCommandSqlArgs(argc, argv, true);
if (shortest) {
const char* path = (const char*)sqlite3_value_text(argv[0]);
if (shortest->length() == 0 || shortest->length() == strlen(path)) {
// There are 2 cases:
// 1 - empty string, all parts of path are invalid,
// so path is deterministic
// 2 - short == full, then there is only 1 valid path
sqlite3_result_int(context, 1);
return;
} else {
auto longest =
findExistingProgramPathFromCommandSqlArgs(argc, argv, false);
if (longest) {
sqlite3_result_int(context,
shortest->length() == longest->length() ? 1 : 0);
return;
}
}
}
sqlite3_result_error(context, "Invalid inputs to is_path_deterministic", -1);
}
static void getParentDirectory(sqlite3_context* context,
int argc,
sqlite3_value** argv) {
if (sqlite3_value_type(argv[0]) != SQLITE_TEXT) {
sqlite3_result_error(
context, "Invalid inputs to parent_directory, TEXT was expected", -1);
return;
}
const char* path = reinterpret_cast<const char*>(sqlite3_value_text(argv[0]));
if (path == nullptr) {
sqlite3_result_null(context);
return;
}
int pos = 0;
int last_slash_pos = -1;
#if defined(OSQUERY_WINDOWS)
char directory_symbol = '\\';
#elif defined(OSQUERY_POSIX)
char directory_symbol = '/';
#else
#error Unsupported platform
#endif
while (path[pos] != '\0') {
if (path[pos] == directory_symbol) {
last_slash_pos = pos;
}
pos++;
}
if (last_slash_pos < 0) {
// No parent directory
sqlite3_result_null(context);
return;
}
sqlite3_result_text(context, path, last_slash_pos, SQLITE_TRANSIENT);
}
void registerFilesystemExtensions(sqlite3* db) {
sqlite3_create_function(db,
"is_path_deterministic",
-1,
SQLITE_UTF8 | SQLITE_DETERMINISTIC,
nullptr,
isPathDeterministic,
nullptr,
nullptr);
sqlite3_create_function(db,
"find_file_path_in_cmd",
-1,
SQLITE_UTF8 | SQLITE_DETERMINISTIC,
nullptr,
findFilePathInLaunchCommand,
nullptr,
nullptr);
sqlite3_create_function(db,
"parent_directory",
1,
SQLITE_UTF8 | SQLITE_DETERMINISTIC,
nullptr,
getParentDirectory,
nullptr,
nullptr);
}
} // namespace osquery