From: Sangwan Kwon Date: Fri, 24 Apr 2020 04:26:08 +0000 (+0900) Subject: Remove osqueryi X-Git-Tag: submit/tizen/20200810.073515~39 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=78823356ed67f0b7be218d41d207fb9af588155e;p=platform%2Fcore%2Fsecurity%2Fvist.git Remove osqueryi Signed-off-by: Sangwan Kwon --- diff --git a/src/osquery/CMakeLists.txt b/src/osquery/CMakeLists.txt index 54a4dd5..7fa8209 100644 --- a/src/osquery/CMakeLists.txt +++ b/src/osquery/CMakeLists.txt @@ -13,7 +13,6 @@ # limitations under the License SET(TARGET_OSQUERY_TEST osquery-test) -SET(TARGET_OSQUERY_SHELL osqueryi) SET(${TARGET_OSQUERY_LIB}_SRCS "") SET(${TARGET_OSQUERY_LIB}_DEPS "") @@ -37,9 +36,6 @@ IF(DEFINED GBS_BUILD) PKG_CHECK_MODULES(GBS_DEPS REQUIRED ${GBS_ONLY_PACKAGES}) INCLUDE_DIRECTORIES(SYSTEM ${GBS_DEPS_INCLUDE_DIRS}) -ELSE(DEFINED GBS_BUILD) - ## osqueryi - ADD_SUBDIRECTORY(devtools) ENDIF(DEFINED GBS_BUILD) ## osquery v4.0.0 @@ -81,19 +77,3 @@ INSTALL(TARGETS ${TARGET_OSQUERY_TEST} GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) - -IF(NOT DEFINED GBS_BUILD) - ADD_EXECUTABLE(${TARGET_OSQUERY_SHELL} devtools/shell.cpp - main/main.cpp - main/posix/main.cpp) - TARGET_LINK_WHOLE(${TARGET_OSQUERY_SHELL} ${TARGET_OSQUERY_LIB}) - INSTALL(TARGETS ${TARGET_OSQUERY_SHELL} - DESTINATION ${CMAKE_INSTALL_BINDIR} - PERMISSIONS OWNER_READ - OWNER_WRITE - OWNER_EXECUTE - GROUP_READ - GROUP_EXECUTE - WORLD_READ - WORLD_EXECUTE) -ENDIF(NOT DEFINED GBS_BUILD) diff --git a/src/osquery/devtools/CMakeLists.txt b/src/osquery/devtools/CMakeLists.txt deleted file mode 100644 index 94054df..0000000 --- a/src/osquery/devtools/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License - -ADD_OSQUERY_LINK(linenoise) - -ADD_OSQUERY_LIBRARY(osquery_devtools printer.cpp) - -FILE(GLOB OSQUERY_DEVTOOLS_TESTS "tests/*.cpp") -ADD_OSQUERY_TEST(${OSQUERY_DEVTOOLS_TESTS}) diff --git a/src/osquery/devtools/devtools.h b/src/osquery/devtools/devtools.h deleted file mode 100644 index 4c01c40..0000000 --- a/src/osquery/devtools/devtools.h +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include - -#include -#include - -namespace osquery { - -/// Show all tables and exit the shell. -DECLARE_bool(L); - -/// Select all from a table an exit the shell. -DECLARE_string(A); - -/// The shell may request execution of all queries in a pack immediately. -DECLARE_string(pack); - -/** - * @brief Run an interactive SQL query shell. - * - * @code{.cpp} - * // Copyright 2004-present Facebook. All Rights Reserved. - * #include - * #include - * - * int main(int argc, char *argv[]) { - * osquery::initOsquery(argc, argv); - * return osquery::launchIntoShell(argc, argv); - * } - * @endcode - * - * @param argc the number of elements in argv - * @param argv the command-line flags - * - * @return an int which represents the "return code" - */ -int launchIntoShell(int argc, char** argv); - -/** - * @brief Pretty print a QueryData object - * - * This is a helper method which called osquery::beautify on the supplied - * QueryData object and prints the results to stdout. - * - * @param results The QueryData object to print - * @param columns The order of the keys (since maps are unordered) - * @param lengths A mutable set of column lengths - */ -void prettyPrint(const QueryData& results, - const std::vector& columns, - std::map& lengths); - -/** - * @brief JSON print a QueryData object - * - * This is a helper method which allows a shell or other tool to print results - * in a JSON format. - * - * @param q The QueryData object to print - */ -void jsonPrint(const QueryData& q); - -/** - * @brief Compute a map of metadata about the supplied QueryData object - * - * @param r A row to analyze - * @param lengths A mutable set of column lengths - * @param use_columns Calculate lengths of column names or values - * - * @return A map of string to int such that the key represents the "column" in - * the supplied QueryData and the int represents the length of the longest key - */ -void computeRowLengths(const Row& r, - std::map& lengths, - bool use_columns = false); - -/** - * @brief Generate the separator string for query results - * - * @param lengths The data returned from computeQueryDataLengths - * @param columns The order of the keys (since maps are unordered) - * - * @return A string, with a newline, representing your separator - */ -std::string generateToken(const std::map& lengths, - const std::vector& columns); - -/** - * @brief Generate the header string for query results - * - * @param lengths The data returned from computeQueryDataLengths - * @param columns The order of the keys (since maps are unordered) - * - * @return A string, with a newline, representing your header - */ -std::string generateHeader(const std::map& lengths, - const std::vector& columns); - -/** - * @brief Generate a row string for query results - * - * @param r A row to analyze - * @param lengths The data returned from computeQueryDataLengths - * @param columns The order of the keys (since maps are unordered) - * - * @return A string, with a newline, representing your row - */ -std::string generateRow(const Row& r, - const std::map& lengths, - const std::vector& columns); -} diff --git a/src/osquery/devtools/printer.cpp b/src/osquery/devtools/printer.cpp deleted file mode 100644 index 96d48c1..0000000 --- a/src/osquery/devtools/printer.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#include -#include - -#include -#include -#include -#include -#include - -namespace osquery { - -static std::vector kOffset = {0, 0}; -static std::string kToken = "|"; - -std::string generateToken(const std::map& lengths, - const std::vector& columns) { - std::string out = "+"; - for (const auto& col : columns) { - size_t size = tryTakeCopy(lengths, col).takeOr(col.size()) + 2; - if (getEnvVar("ENHANCE").is_initialized()) { - std::string e = "\xF0\x9F\x90\x8C"; - e[2] += kOffset[1]; - e[3] += kOffset[0]; - for (size_t i = 0; i < size; i++) { - e[3] = '\x8c' + kOffset[0]++; - if (e[3] == '\xbf') { - e[3] = '\x80'; - kOffset[1] = (kOffset[1] > 3 && kOffset[1] < 8) ? 9 : kOffset[1]; - e[2] = '\x90' + ++kOffset[1]; - kOffset[0] = 0; - } - if (kOffset[1] == ('\x97' - '\x8d')) { - kOffset = {0, 0}; - } - out += e.c_str(); - } - } else { - out += std::string(size, '-'); - } - out += "+"; - } - - out += "\n"; - return out; -} - -std::string generateHeader(const std::map& lengths, - const std::vector& columns) { - if (getEnvVar("ENHANCE").is_initialized()) { - kToken = "\xF0\x9F\x91\x8D"; - } - std::string out = kToken; - for (const auto& col : columns) { - out += " " + col; - if (lengths.count(col) > 0) { - int buffer_size = static_cast(lengths.at(col) - utf8StringSize(col)); - if (buffer_size > 0) { - out += std::string(buffer_size, ' '); - } - } - out += ' '; - out += kToken; - } - out += "\n"; - return out; -} - -std::string generateRow(const Row& r, - const std::map& lengths, - const std::vector& order) { - std::string out; - for (const auto& column : order) { - size_t size = 0; - - // Print a terminator for the previous value or lhs, followed by spaces. - out += kToken + ' '; - if (r.count(column) == 0 || lengths.count(column) == 0) { - size = column.size() - utf8StringSize(""); - out += ""; - } else { - int buffer_size = - static_cast(lengths.at(column) - utf8StringSize(r.at(column))); - if (buffer_size >= 0) { - size = static_cast(buffer_size); - out += r.at(column); - } - } - out += std::string(size + 1, ' '); - } - - if (out.size() > 0) { - // Only append if a row was added. - out += kToken + "\n"; - } - - return out; -} - -void prettyPrint(const QueryData& results, - const std::vector& columns, - std::map& lengths) { - if (results.size() == 0) { - return; - } - - // Call a final compute using the column names as minimum lengths. - computeRowLengths(results.front(), lengths, true); - - // Output a nice header wrapping the column names. - auto separator = generateToken(lengths, columns); - auto header = separator + generateHeader(lengths, columns) + separator; - printf("%s", header.c_str()); - - // Iterate each row and pretty print. - for (const auto& row : results) { - printf("%s", generateRow(row, lengths, columns).c_str()); - } - printf("%s", separator.c_str()); -} - -void jsonPrint(const QueryData& q) { - printf("[\n"); - for (size_t i = 0; i < q.size(); ++i) { - std::string row_string; - - if (serializeRowJSON(q[i], row_string).ok()) { - printf(" %s", row_string.c_str()); - if (i < q.size() - 1) { - printf(",\n"); - } - } - } - printf("\n]\n"); -} - -void computeRowLengths(const Row& r, - std::map& lengths, - bool use_columns) { - for (const auto& col : r) { - size_t current = tryTakeCopy(lengths, col.first).takeOr(std::size_t{0}); - size_t size = - (use_columns) ? utf8StringSize(col.first) : utf8StringSize(col.second); - lengths[col.first] = (size > current) ? size : current; - } -} -} diff --git a/src/osquery/devtools/shell.cpp b/src/osquery/devtools/shell.cpp deleted file mode 100644 index f9c2574..0000000 --- a/src/osquery/devtools/shell.cpp +++ /dev/null @@ -1,1616 +0,0 @@ -/* -** 2001 September 15 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** This file contains code to implement the "sqlite" command line -** utility for accessing SQLite databases. -*/ - -#include -#include -#include -#include - -#ifdef WIN32 - -#include - -#include -#else -#include -#include -#endif - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(SQLITE_ENABLE_WHERETRACE) -extern int sqlite3WhereTrace; -#endif - -namespace fs = boost::filesystem; - -static char zHelp[] = - "Welcome to the osquery shell. Please explore your OS!\n" - "You are connected to a transient 'in-memory' virtual database.\n" - "\n" - ".all [TABLE] Select all from a table\n" - ".bail ON|OFF Stop after hitting an error\n" - ".echo ON|OFF Turn command echo on or off\n" - ".exit Exit this program\n" - ".features List osquery's features and their statuses\n" - ".headers ON|OFF Turn display of headers on or off\n" - ".help Show this message\n" - ".mode MODE Set output mode where MODE is one of:\n" - " csv Comma-separated values\n" - " column Left-aligned columns see .width\n" - " line One value per line\n" - " list Values delimited by .separator string\n" - " pretty Pretty printed SQL results (default)\n" - ".nullvalue STR Use STRING in place of NULL values\n" - ".print STR... Print literal STRING\n" - ".quit Exit this program\n" - ".schema [TABLE] Show the CREATE statements\n" - ".separator STR Change separator used by output mode\n" - ".show Show the current values for various settings\n" - ".summary Alias for the show meta command\n" - ".tables [TABLE] List names of tables\n" - ".types [SQL] Show result of getQueryColumns for the given query\n" - ".width [NUM1]+ Set column widths for \"column\" mode\n"; - -static char zTimerHelp[] = - ".timer ON|OFF Turn the CPU timer measurement on or off\n"; - -// Allowed modes -#define MODE_Line 0 // One column per line. Blank line between records -#define MODE_Column 1 // One record per line in neat columns -#define MODE_List 2 // One record per line with a separator -#define MODE_Semi 3 // Same as MODE_List but append ";" to each line -#define MODE_Csv 4 // Quote strings, numbers are plain -#define MODE_Pretty 5 // Pretty print the SQL results - -static const char* modeDescr[] = { - "line", "column", "list", "semi", "csv", "pretty", -}; - -// ctype macros that work with signed characters -#define IsSpace(X) isspace((unsigned char)(X)) -#define IsDigit(X) isdigit((unsigned char)(X)) - -// True if the timer is enabled -static int enableTimer = 0; - -// Return the current wall-clock time -static sqlite3_int64 timeOfDay() { - static sqlite3_vfs* clockVfs = nullptr; - sqlite3_int64 t; - if (clockVfs == nullptr) { - clockVfs = sqlite3_vfs_find(nullptr); - } - if (clockVfs->iVersion >= 1 && clockVfs->xCurrentTimeInt64 != nullptr) { - clockVfs->xCurrentTimeInt64(clockVfs, &t); - } else { - double r; - clockVfs->xCurrentTime(clockVfs, &r); - t = static_cast(r * 86400000.0); - } - return t; -} - -// Saved resource information for the beginning of an operation -#ifdef WIN32 -struct rusage { - FILETIME ru_utime; - FILETIME ru_stime; -}; -#endif - -static struct rusage sBegin; // CPU time at start -static sqlite3_int64 iBegin; // Wall-clock time at start - -static void beginTimer() { - if (enableTimer != 0) { -#ifdef WIN32 - FILETIME ftCreation, ftExit; - ::GetProcessTimes(::GetCurrentProcess(), - &ftCreation, - &ftExit, - &sBegin.ru_stime, - &sBegin.ru_utime); -#else - getrusage(RUSAGE_SELF, &sBegin); -#endif - - iBegin = timeOfDay(); - } -} - -// Return the difference of two time_structs in seconds -#ifdef WIN32 -static double timeDiff(FILETIME* pStart, FILETIME* pEnd) { - ULARGE_INTEGER start, end; - - start.HighPart = pStart->dwHighDateTime; - start.LowPart = pStart->dwLowDateTime; - - end.HighPart = pEnd->dwHighDateTime; - end.LowPart = pEnd->dwLowDateTime; - - // start, end are in units of 100 nanoseconds - return (end.QuadPart - start.QuadPart) * 0.0000001; -} -#else -static double timeDiff(struct timeval* pStart, struct timeval* pEnd) { - return (pEnd->tv_usec - pStart->tv_usec) * 0.000001 + - static_cast(pEnd->tv_sec - pStart->tv_sec); -} -#endif - -// End the timer and print the results. -static void endTimer() { - if (enableTimer != 0) { - sqlite3_int64 iEnd = timeOfDay(); - struct rusage sEnd {}; - -#ifdef WIN32 - FILETIME ftCreation, ftExit; - ::GetProcessTimes(::GetCurrentProcess(), - &ftCreation, - &ftExit, - &sEnd.ru_stime, - &sEnd.ru_utime); -#else - getrusage(RUSAGE_SELF, &sEnd); -#endif - - printf("Run Time: real %.3f user %f sys %f\n", - (iEnd - iBegin) * 0.001, - timeDiff(&sBegin.ru_utime, &sEnd.ru_utime), - timeDiff(&sBegin.ru_stime, &sEnd.ru_stime)); - } -} - -#define BEGIN_TIMER beginTimer() -#define END_TIMER endTimer() -#define HAS_TIMER 1 - -// If the following flag is set, then command execution stops -// at an error if we are not interactive. -static int bail_on_error = 0; - -// Treat stdin as an interactive input if the following variable -// is true. Otherwise, assume stdin is connected to a file or pipe. -static bool stdin_is_interactive = true; - -// True if an interrupt (Control-C) has been received. -static volatile int seenInterrupt = 0; - -static char mainPrompt[26]; // First line prompt. default: "sqlite> " -static char continuePrompt[26]; // Continuation prompt. default: " ...> " - -// A global char* and an SQL function to access its current value -// from within an SQL statement. This program used to use the -// sqlite_exec_printf() API to substitute a string into an SQL statement. -// The correct way to do this with sqlite3 is to use the bind API, but -// since the shell is built around the callback paradigm it would be a lot -// of work. Instead just use this hack, which is quite harmless. -static const char* zShellStatic = nullptr; -void shellstaticFunc(sqlite3_context* context, - int argc, - sqlite3_value** /* argv */) { - (void)argc; - assert(0 == argc); - assert(zShellStatic); - sqlite3_result_text(context, zShellStatic, -1, SQLITE_STATIC); -} - -/* -** Output text to the console in a font that attracts extra attention. -*/ -static void print_bold(const char* zText) { - if (stdin_is_interactive) { - printf("\033[1m"); - } - printf("%s", zText); - if (stdin_is_interactive) { - printf("\033[0m"); - } -} - -/* -** This routine reads a line of text from FILE in, stores -** the text in memory obtained from malloc() and returns a pointer -** to the text. NULL is returned at end of file, or if malloc() -** fails. -** -** If zLine is not NULL then it is a malloced buffer returned from -** a previous call to this routine that may be reused. -*/ -static char* local_getline(char* zLine, FILE* in) { - int nLine = ((zLine == nullptr) ? 0 : 100); - int n = 0; - - while (true) { - if (n + 100 > nLine) { - nLine = nLine * 2 + 100; - auto zLine_new = reinterpret_cast(realloc(zLine, nLine)); - if (zLine_new == nullptr) { - free(zLine); - return nullptr; - } - zLine = zLine_new; - } - if (fgets(&zLine[n], nLine - n, in) == nullptr) { - if (n == 0) { - free(zLine); - return nullptr; - } - zLine[n] = 0; - break; - } - while (zLine[n] != 0) { - n++; - } - if (n > 0 && zLine[n - 1] == '\n') { - n--; - if (n > 0 && zLine[n - 1] == '\r') { - n--; - } - zLine[n] = 0; - break; - } - } - return zLine; -} - -/* -** Retrieve a single line of input text. -** -** If in==0 then read from standard input and prompt before each line. -** If isContinuation is true, then a continuation prompt is appropriate. -** If isContinuation is zero, then the main prompt should be used. -** -** If zPrior is not NULL then it is a buffer from a prior call to this -** routine that can be reused. -** -** The result is stored in space obtained from malloc() and must either -** be freed by the caller or else passed back into this routine via the -** zPrior argument for reuse. -*/ -static char* one_input_line(FILE* in, char* zPrior, int isContinuation) { - char* zResult; - if (in != nullptr) { - zResult = local_getline(zPrior, in); - } else { - char* zPrompt = isContinuation != 0 ? continuePrompt : mainPrompt; - free(zPrior); - zResult = linenoise(zPrompt); - if ((zResult != nullptr) && (*zResult != 0)) { - linenoiseHistoryAdd(zResult); - } - } - return zResult; -} - -/* -** Pretty print structure -*/ -struct prettyprint_data { - osquery::QueryData results; - std::vector columns; - std::map lengths; -}; - -/* -** An pointer to an instance of this structure is passed from -** the main program to the callback. This is used to communicate -** state and mode information. -*/ -struct callback_data { - int echoOn; /* True to echo input commands */ - int cnt; /* Number of records displayed so far */ - FILE* out; /* Write results here */ - FILE* traceOut; /* Output for sqlite3_trace() */ - int mode; /* An output mode setting */ - int showHeader; /* True to show column names in List or Column mode */ - char* zDestTable; /* Name of destination table when MODE_Insert */ - char separator[20]; /* Separator character for MODE_List */ - int colWidth[100]; /* Requested width of each column when in column mode*/ - int actualWidth[100]; /* Actual width of each column */ - char nullvalue[20]; /* The text to print when a NULL comes back from - ** the database */ - char outfile[FILENAME_MAX]; /* Filename for *out */ - char* zFreeOnClose; /* Filename to free when closing */ - sqlite3_stmt* pStmt; /* Current statement if any. */ - FILE* pLog; /* Write log output here */ - int* aiIndent; /* Array of indents used in MODE_Explain */ - int nIndent; /* Size of array aiIndent[] */ - int iIndent; /* Index of current op in aiIndent[] */ - - /* Additional attributes to be used in pretty mode */ - struct prettyprint_data* prettyPrint; -}; - -// Number of elements in an array -#define ArraySize(X) (int)(sizeof(X) / sizeof((X)[0])) - -/* -** Compute a string length that is limited to what can be stored in -** lower 30 bits of a 32-bit signed integer. -*/ -static int strlen30(const char* z) { - const char* z2 = z; - while (*z2 != 0) { - z2++; - } - return 0x3fffffff & static_cast(z2 - z); -} - -/* -** A callback for the sqlite3_log() interface. -*/ -static void shellLog(void* pArg, int iErrCode, const char* zMsg) { - auto* p = reinterpret_cast(pArg); - if (p->pLog == nullptr) { - return; - } - fprintf(p->pLog, "(%d) %s\n", iErrCode, zMsg); - fflush(p->pLog); -} - -/* -** Output the given string as a quoted according to C or TCL quoting rules. -*/ -static void output_c_string(FILE* out, const char* z) { - unsigned int c; - fputc('"', out); - while ((c = *(z++)) != 0) { - if (c == '\\') { - fputc(c, out); - fputc(c, out); - } else if (c == '"') { - fputc('\\', out); - fputc('"', out); - } else if (c == '\t') { - fputc('\\', out); - fputc('t', out); - } else if (c == '\n') { - fputc('\\', out); - fputc('n', out); - } else if (c == '\r') { - fputc('\\', out); - fputc('r', out); - } else if (isprint(c & 0xff) == 0) { - fprintf(out, R"(\%03o)", c & 0xff); - } else { - fputc(c, out); - } - } - fputc('"', out); -} - -/* -** If a field contains any character identified by a 1 in the following -** array, then the string must be quoted for CSV. -*/ -static const char needCsvQuote[] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -}; - -/* -** Output a single term of CSV. Actually, p->separator is used for -** the separator, which may or may not be a comma. p->nullvalue is -** the null value. Strings are quoted if necessary. -*/ -static void output_csv(struct callback_data* p, const char* z, int bSep) { - FILE* out = p->out; - if (z == nullptr) { - fprintf(out, "%s", p->nullvalue); - } else { - int i; - int nSep = strlen30(p->separator); - for (i = 0; z[i] != 0; i++) { - if ((needCsvQuote[((unsigned char*)z)[i]] != 0) || - (z[i] == p->separator[0] && - (nSep == 1 || memcmp(z, p->separator, nSep) == 0))) { - i = 0; - break; - } - } - if (i == 0) { - putc('"', out); - for (i = 0; z[i] != 0; i++) { - if (z[i] == '"') { - putc('"', out); - } - putc(z[i], out); - } - putc('"', out); - } else { - fprintf(out, "%s", z); - } - } - if (bSep != 0) { - fprintf(p->out, "%s", p->separator); - } -} - -#ifdef SIGINT -/* -** This routine runs when the user presses Ctrl-C -*/ -static void interrupt_handler(int signal) { - if (signal == SIGINT) { - seenInterrupt = 1; - } -} -#endif - -/* -** This is the callback routine that the shell -** invokes for each row of a query result. -*/ -static int shell_callback(void* pArg, - int nArg, - const char** azArg, - const char** azCol, - int* /*aiType*/) { - int i; - auto* p = reinterpret_cast(pArg); - - switch (p->mode) { - case MODE_Pretty: { - if (p->prettyPrint->columns.empty()) { - for (i = 0; i < nArg; i++) { - p->prettyPrint->columns.push_back(std::string(azCol[i])); - } - } - - osquery::Row r; - for (i = 0; i < nArg; ++i) { - if (azCol[i] != nullptr) { - r[std::string(azCol[i])] = (azArg[i] == nullptr) - ? "" - : std::string(azArg[i]); - } - } - osquery::computeRowLengths(r, p->prettyPrint->lengths); - p->prettyPrint->results.push_back(r); - break; - } - case MODE_Line: { - int w = 5; - if (azArg == nullptr) { - break; - } - for (i = 0; i < nArg; i++) { - int len = strlen30(azCol[i] != nullptr ? azCol[i] : ""); - if (len > w) { - w = len; - } - } - if (p->cnt++ > 0) { - fprintf(p->out, "\n"); - } - for (i = 0; i < nArg; i++) { - fprintf(p->out, - "%*s = %s\n", - w, - azCol[i], - azArg[i] != nullptr ? azArg[i] : p->nullvalue); - } - break; - } - case MODE_Column: { - if (p->cnt++ == 0) { - for (i = 0; i < nArg; i++) { - int w; - if (i < ArraySize(p->colWidth)) { - w = p->colWidth[i]; - } else { - w = 0; - } - if (w == 0) { - w = strlen30(azCol[i] != nullptr ? azCol[i] : ""); - if (w < 10) { - w = 10; - } - int n = strlen30((azArg != nullptr) && (azArg[i] != nullptr) - ? azArg[i] - : p->nullvalue); - if (w < n) { - w = n; - } - } - if (i < ArraySize(p->actualWidth)) { - p->actualWidth[i] = w; - } - if (p->showHeader != 0) { - if (w < 0) { - fprintf(p->out, - "%*.*s%s", - -w, - -w, - azCol[i], - i == nArg - 1 ? "\n" : " "); - } else { - fprintf(p->out, - "%-*.*s%s", - w, - w, - azCol[i], - i == nArg - 1 ? "\n" : " "); - } - } - } - if (p->showHeader != 0) { - for (i = 0; i < nArg; i++) { - int w; - if (i < ArraySize(p->actualWidth)) { - w = p->actualWidth[i]; - if (w < 0) { - w = -w; - } - } else { - w = 10; - } - fprintf(p->out, - "%-*.*s%s", - w, - w, - "-----------------------------------" - "----------------------------------------------------------", - i == nArg - 1 ? "\n" : " "); - } - } - } - if (azArg == nullptr) { - break; - } - for (i = 0; i < nArg; i++) { - int w; - if (i < ArraySize(p->actualWidth)) { - w = p->actualWidth[i]; - } else { - w = 10; - } - if (i == 1 && (p->aiIndent != nullptr) && (p->pStmt != nullptr)) { - if (p->iIndent < p->nIndent) { - fprintf(p->out, "%*.s", p->aiIndent[p->iIndent], ""); - } - p->iIndent++; - } - if (w < 0) { - fprintf(p->out, - "%*.*s%s", - -w, - -w, - azArg[i] != nullptr ? azArg[i] : p->nullvalue, - i == nArg - 1 ? "\n" : " "); - } else { - fprintf(p->out, - "%-*.*s%s", - w, - w, - azArg[i] != nullptr ? azArg[i] : p->nullvalue, - i == nArg - 1 ? "\n" : " "); - } - } - break; - } - case MODE_Semi: - case MODE_List: { - if (p->cnt++ == 0 && (p->showHeader != 0)) { - for (i = 0; i < nArg; i++) { - fprintf(p->out, "%s%s", azCol[i], i == nArg - 1 ? "\n" : p->separator); - } - } - if (azArg == nullptr) { - break; - } - for (i = 0; i < nArg; i++) { - const char* z = azArg[i]; - if (z == nullptr) { - z = p->nullvalue; - } - fprintf(p->out, "%s", z); - if (i < nArg - 1) { - fprintf(p->out, "%s", p->separator); - } else if (p->mode == MODE_Semi) { - fprintf(p->out, ";\n"); - } else { - fprintf(p->out, "\n"); - } - } - break; - } - case MODE_Csv: { - if (p->cnt++ == 0 && (p->showHeader != 0)) { - for (i = 0; i < nArg; i++) { - output_csv(p, - azCol[i] != nullptr ? azCol[i] : "", - static_cast(i < nArg - 1)); - } - fprintf(p->out, "\n"); - } - if (azArg == nullptr) { - break; - } - for (i = 0; i < nArg; i++) { - output_csv(p, azArg[i], static_cast(i < nArg - 1)); - } - fprintf(p->out, "\n"); - break; - } - } - return 0; -} - -/* -** Set the destination table field of the callback_data structure to -** the name of the table given. Escape any quote characters in the -** table name. -*/ -static void set_table_name(struct callback_data* p, const char* zName) { - int i, n; - int needQuote; - char* z; - - if (p->zDestTable != nullptr) { - free(p->zDestTable); - p->zDestTable = nullptr; - } - - if (zName == nullptr) { - return; - } - - needQuote = static_cast( - (isalpha(static_cast(*zName)) == 0) && *zName != '_'); - for (i = n = 0; zName[i] != 0; i++, n++) { - if ((isalnum(static_cast(zName[i])) == 0) && - zName[i] != '_') { - needQuote = 1; - if (zName[i] == '\'') { - n++; - } - } - } - if (needQuote != 0) { - n += 2; - } - z = p->zDestTable = reinterpret_cast(malloc(n + 1)); - if (z == nullptr) { - fprintf(stderr, "Error: out of memory\n"); - exit(1); - } - n = 0; - if (needQuote != 0) { - z[n++] = '\''; - } - for (i = 0; zName[i] != 0; i++) { - z[n++] = zName[i]; - if (zName[i] == '\'') { - z[n++] = '\''; - } - } - if (needQuote != 0) { - z[n++] = '\''; - } - z[n] = 0; -} - -static void pretty_print_if_needed(struct callback_data* pArg) { - if ((pArg != nullptr) && pArg->mode == MODE_Pretty) { - osquery::prettyPrint(pArg->prettyPrint->results, - pArg->prettyPrint->columns, - pArg->prettyPrint->lengths); - - pArg->prettyPrint->results.clear(); - pArg->prettyPrint->columns.clear(); - pArg->prettyPrint->lengths.clear(); - } -} - -/* -** Allocate space and save off current error string. -*/ -static char* save_err_msg(sqlite3* db) { - int nErrMsg = 1 + strlen30(sqlite3_errmsg(db)); - auto* zErrMsg = reinterpret_cast(sqlite3_malloc(nErrMsg)); - if (zErrMsg != nullptr) { - memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg); - } - return zErrMsg; -} - -/* -** Execute a statement or set of statements. Print -** any result rows/columns depending on the current mode -** set via the supplied callback. -** -** This is very similar to SQLite's built-in sqlite3_exec() -** function except it takes a slightly different callback -** and callback data argument. -*/ -static int shell_exec( - const char* zSql, /* SQL to be evaluated */ - int (*xCallback)( - void*, int, const char**, const char**, int*), /* Callback function */ - /* (not the same as sqlite3_exec) */ - struct callback_data* pArg, /* Pointer to struct callback_data */ - char** pzErrMsg /* Error msg written here */ -) { - // Grab a lock on the managed DB instance. - auto dbc = osquery::SQLiteDBManager::get(); - auto db = dbc->db(); - - sqlite3_stmt* pStmt = nullptr; /* Statement to execute. */ - int rc = SQLITE_OK; /* Return Code */ - int rc2; - const char* zLeftover; /* Tail of unprocessed SQL */ - - if (pzErrMsg != nullptr) { - *pzErrMsg = nullptr; - } - - while ((zSql[0] != 0) && (SQLITE_OK == rc)) { - auto lock(dbc->attachLock()); - - /* A lock for attaching virtual tables, but also the SQL object states. */ - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); - if (SQLITE_OK != rc) { - if (pzErrMsg != nullptr) { - *pzErrMsg = save_err_msg(db); - } - } else { - if (pStmt == nullptr) { - /* this happens for a comment or white-space */ - zSql = zLeftover; - while (IsSpace(zSql[0])) { - zSql++; - } - continue; - } - - /* save off the prepared statement handle and reset row count */ - if (pArg != nullptr) { - pArg->pStmt = pStmt; - pArg->cnt = 0; - } - - /* echo the sql statement if echo on */ - if ((pArg != nullptr) && (pArg->echoOn != 0)) { - const char* zStmtSql = sqlite3_sql(pStmt); - fprintf(pArg->out, "%s\n", zStmtSql != nullptr ? zStmtSql : zSql); - } - - /* perform the first step. this will tell us if we - ** have a result set or not and how wide it is. - */ - rc = sqlite3_step(pStmt); - /* if we have a result set... */ - if (SQLITE_ROW == rc) { - /* if we have a callback... */ - if (xCallback != nullptr) { - /* allocate space for col name ptr, value ptr, and type */ - int nCol = sqlite3_column_count(pStmt); - void* pData = sqlite3_malloc(3 * nCol * sizeof(const char*) + 1); - if (pData == nullptr) { - rc = SQLITE_NOMEM; - } else { - const auto** azCols = reinterpret_cast( - pData); /* Names of result columns */ - const char** azVals = &azCols[nCol]; /* Results */ - auto* aiTypes = - reinterpret_cast(&azVals[nCol]); /* Result types */ - int i; - assert(sizeof(int) <= sizeof(char*)); - /* save off ptrs to column names */ - for (i = 0; i < nCol; i++) { - azCols[i] = const_cast(sqlite3_column_name(pStmt, i)); - } - do { - /* extract the data and data types */ - for (i = 0; i < nCol; i++) { - aiTypes[i] = sqlite3_column_type(pStmt, i); - azVals[i] = (char*)sqlite3_column_text(pStmt, i); - if ((azVals[i] == nullptr) && (aiTypes[i] != SQLITE_NULL)) { - rc = SQLITE_NOMEM; - break; /* from for */ - } - } /* end for */ - - /* if data and types extracted successfully... */ - if (SQLITE_ROW == rc) { - /* call the supplied callback with the result row data */ - if (xCallback(pArg, nCol, azVals, azCols, aiTypes) != 0) { - rc = SQLITE_ABORT; - } else { - rc = sqlite3_step(pStmt); - } - } - } while (SQLITE_ROW == rc); - sqlite3_free(pData); - } - } else { - do { - rc = sqlite3_step(pStmt); - } while (rc == SQLITE_ROW); - } - } - - /* Finalize the statement just executed. If this fails, save a - ** copy of the error message. Otherwise, set zSql to point to the - ** next statement to execute. */ - rc2 = sqlite3_finalize(pStmt); - if (rc != SQLITE_NOMEM) { - rc = rc2; - } - if (rc == SQLITE_OK) { - zSql = zLeftover; - while (IsSpace(zSql[0])) { - zSql++; - } - } else if (pzErrMsg != nullptr) { - *pzErrMsg = save_err_msg(db); - } - - /* clear saved stmt handle */ - if (pArg != nullptr) { - pArg->pStmt = nullptr; - } - } - } /* end while */ - dbc->clearAffectedTables(); - - pretty_print_if_needed(pArg); - - return rc; -} - -/* Forward reference */ -static int process_input(struct callback_data* p, FILE* in); - -/* -** Do C-language style dequoting. -** -** \t -> tab -** \n -> newline -** \r -> carriage return -** \" -> " -** \NNN -> ascii character NNN in octal -** \\ -> backslash -*/ -static void resolve_backslashes(char* z) { - int i, j; - char c; - for (i = j = 0; (c = z[i]) != 0; i++, j++) { - if (c == '\\') { - c = z[++i]; - if (c == 'n') { - c = '\n'; - } else if (c == 't') { - c = '\t'; - } else if (c == 'r') { - c = '\r'; - } else if (c == '\\') { - c = '\\'; - } else if (c >= '0' && c <= '7') { - c -= '0'; - if (z[i + 1] >= '0' && z[i + 1] <= '7') { - i++; - c = (c << 3) + z[i] - '0'; - if (z[i + 1] >= '0' && z[i + 1] <= '7') { - i++; - c = (c << 3) + z[i] - '0'; - } - } - } - } - z[j] = c; - } - z[j] = 0; -} - -/* -** Return the value of a hexadecimal digit. Return -1 if the input -** is not a hex digit. -*/ -static int hexDigitValue(char c) { - if (c >= '0' && c <= '9') { - return c - '0'; - } - if (c >= 'a' && c <= 'f') { - return c - 'a' + 10; - } - if (c >= 'A' && c <= 'F') { - return c - 'A' + 10; - } - return -1; -} - -/* -** Interpret zArg as an integer value, possibly with suffixes. -*/ -static sqlite3_int64 integerValue(const char* zArg) { - sqlite3_int64 v = 0; - static const struct { - char* zSuffix; - int iMult; - } aMult[] = { - {(char*)"KiB", 1024}, - {(char*)"MiB", 1024 * 1024}, - {(char*)"GiB", 1024 * 1024 * 1024}, - {(char*)"KB", 1000}, - {(char*)"MB", 1000000}, - {(char*)"GB", 1000000000}, - {(char*)"K", 1000}, - {(char*)"M", 1000000}, - {(char*)"G", 1000000000}, - }; - int i; - int isNeg = 0; - if (zArg[0] == '-') { - isNeg = 1; - zArg++; - } else if (zArg[0] == '+') { - zArg++; - } - if (zArg[0] == '0' && zArg[1] == 'x') { - int x; - zArg += 2; - while ((x = hexDigitValue(zArg[0])) >= 0) { - v = (v << 4) + x; - zArg++; - } - } else { - while (IsDigit(zArg[0])) { - v = v * 10 + zArg[0] - '0'; - zArg++; - } - } - for (i = 0; i < ArraySize(aMult); i++) { - if (sqlite3_stricmp(aMult[i].zSuffix, zArg) == 0) { - v *= aMult[i].iMult; - break; - } - } - return isNeg != 0 ? -v : v; -} - -/* -** Interpret zArg as either an integer or a boolean value. Return 1 or 0 -** for TRUE and FALSE. Return the integer value if appropriate. -*/ -static int booleanValue(char* zArg) { - int i; - if (zArg[0] == '0' && zArg[1] == 'x') { - for (i = 2; hexDigitValue(zArg[i]) >= 0; i++) { - } - } else { - for (i = 0; zArg[i] >= '0' && zArg[i] <= '9'; i++) { - } - } - if (i > 0 && zArg[i] == 0) { - return static_cast(integerValue(zArg) & 0xffffffff); - } - auto expected = osquery::tryTo(std::string{zArg}); - if (expected.isError()) { - fprintf( - stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", zArg); - } - return expected.takeOr(false) ? 1 : 0; -} - -inline void meta_tables(int nArg, char** azArg) { - auto tables = osquery::RegistryFactory::get().names("table"); - std::sort(tables.begin(), tables.end()); - for (const auto& table_name : tables) { - if (nArg == 1 || table_name.find(azArg[1]) == 0) { - printf(" => %s\n", table_name.c_str()); - } - } -} - -inline void meta_types(struct callback_data* pArg, char* zSql) { - const char* COLUMN_NAMES[] = {"name", "type"}; - - auto dbc = osquery::SQLiteDBManager::get(); - osquery::TableColumns columns; - auto status = getQueryColumnsInternal(zSql, columns, dbc); - - if (status.ok()) { - for (const auto& column_info : columns) { - const auto& name = std::get<0>(column_info); - const auto& type = columnTypeName(std::get<1>(column_info)); - - std::vector row{{name.c_str(), type.c_str()}}; - - shell_callback(pArg, 2, &row[0], COLUMN_NAMES, nullptr); - } - pretty_print_if_needed(pArg); - } else { - fprintf( - stdout, "Error %d: %s\n", status.getCode(), status.toString().c_str()); - } -} - -inline void meta_schema(int nArg, char** azArg) { - for (const auto& table : osquery::RegistryFactory::get().names("table")) { - if (nArg > 1 && table.find(azArg[1]) != 0) { - continue; - } - - osquery::PluginResponse response; - auto status = osquery::Registry::call( - "table", table, {{"action", "columns"}}, response); - if (status.ok()) { - auto const aliases = true; - auto const is_extension = false; - - fprintf( - stdout, - "CREATE TABLE %s%s;\n", - table.c_str(), - osquery::columnDefinition(response, aliases, is_extension).c_str()); - } - } -} - -inline void meta_features(struct callback_data* p) { - auto results = osquery::SQL( - "select * from osquery_flags where (name like 'disable_%' or name like " - "'enable_%') and type = 'bool'"); - for (const auto& flag : results.rows()) { - fprintf( - p->out, "%s: %s\n", flag.at("name").c_str(), flag.at("value").c_str()); - } -} - -inline void meta_version(struct callback_data* p) { - fprintf(p->out, "osquery %s\n", osquery::kVersion.c_str()); - fprintf(p->out, "using SQLite %s\n", sqlite3_libversion()); -} - -inline void meta_show(struct callback_data* p) { - // The show/summary meta command is provided to help with general debugging. - // All of this information is 'duplicate', and can be found with better - // detail within osquery virtual tables. - print_bold("osquery"); - printf( - " - being built, with love, at Facebook\n" - "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); - meta_version(p); - - fprintf(p->out, "\nShell settings:\n"); - fprintf(p->out, "%13.13s: %s\n", "echo", p->echoOn != 0 ? "on" : "off"); - fprintf( - p->out, "%13.13s: %s\n", "headers", p->showHeader != 0 ? "on" : "off"); - fprintf(p->out, "%13.13s: %s\n", "mode", modeDescr[p->mode]); - fprintf(p->out, "%13.13s: ", "nullvalue"); - output_c_string(p->out, p->nullvalue); - fprintf(p->out, "\n"); - fprintf(p->out, - "%13.13s: %s\n", - "output", - strlen30(p->outfile) != 0 ? p->outfile : "stdout"); - fprintf(p->out, "%13.13s: ", "separator"); - output_c_string(p->out, p->separator); - fprintf(p->out, "\n"); - fprintf(p->out, "%13.13s: ", "width"); - for (int i = 0; i < ArraySize(p->colWidth) && p->colWidth[i] != 0; i++) { - fprintf(p->out, "%d ", p->colWidth[i]); - } - fprintf(p->out, "\n"); - - { - fprintf(p->out, "\nNon-default flags/options:\n"); - auto results = osquery::SQL( - "select * from osquery_flags where default_value <> value"); - for (const auto& flag : results.rows()) { - fprintf(p->out, - " %s: %s\n", - flag.at("name").c_str(), - flag.at("value").c_str()); - } - } -} - -/* -** If an input line begins with "." then invoke this routine to -** process that line. -** -** Return 1 on error, 2 to exit, and 0 otherwise. -*/ -static int do_meta_command(char* zLine, struct callback_data* p) { - int i = 1; - int nArg = 0; - int n, c; - int rc = 0; - char* azArg[50]; - - /* Parse the input line into tokens. - */ - while ((zLine[i] != 0) && nArg < ArraySize(azArg)) { - while (IsSpace(zLine[i])) { - i++; - } - if (zLine[i] == 0) { - break; - } - if (zLine[i] == '\'' || zLine[i] == '"') { - int delim = zLine[i++]; - azArg[nArg++] = &zLine[i]; - while ((zLine[i] != 0) && zLine[i] != delim) { - if (zLine[i] == '\\' && delim == '"' && zLine[i + 1] != 0) { - i++; - } - i++; - } - if (zLine[i] == delim) { - zLine[i++] = 0; - } - if (delim == '"') { - resolve_backslashes(azArg[nArg - 1]); - } - } else { - azArg[nArg++] = &zLine[i]; - while ((zLine[i] != 0) && !IsSpace(zLine[i])) { - i++; - } - if (zLine[i] != 0) { - zLine[i++] = 0; - } - resolve_backslashes(azArg[nArg - 1]); - } - } - - /* Process the input line. - */ - if (nArg == 0) { - return 0; /* no tokens, no error */ - } - n = strlen30(azArg[0]); - c = azArg[0][0]; - if (c == 'a' && strncmp(azArg[0], "all", n) == 0 && nArg == 2) { - struct callback_data data {}; - memcpy(&data, p, sizeof(data)); - auto query = std::string("SELECT * FROM ") + azArg[1]; - rc = shell_exec(query.c_str(), shell_callback, &data, nullptr); - if (rc != SQLITE_OK) { - fprintf(stderr, "Error querying table: %s\n", azArg[1]); - } - return rc; - } - - // A meta command may act on the database, grab a lock and instance. - auto dbc = osquery::SQLiteDBManager::get(); - auto db = dbc->db(); - - if (c == 'b' && n >= 3 && strncmp(azArg[0], "bail", n) == 0 && nArg > 1 && - nArg < 3) { - bail_on_error = booleanValue(azArg[1]); - } else if (c == 'e' && strncmp(azArg[0], "echo", n) == 0 && nArg > 1 && - nArg < 3) { - p->echoOn = booleanValue(azArg[1]); - } else if (c == 'e' && strncmp(azArg[0], "exit", n) == 0) { - if (nArg > 1 && (rc = static_cast(integerValue(azArg[1]))) != 0) { - exit(rc); - } - rc = 2; - } else if (c == 'f' && strncmp(azArg[0], "features", n) == 0 && nArg == 1) { - meta_features(p); - } else if (c == 'h' && - (strncmp(azArg[0], "header", n) == 0 || - strncmp(azArg[0], "headers", n) == 0) && - nArg > 1 && nArg < 3) { - p->showHeader = booleanValue(azArg[1]); - } else if (c == 'h' && strncmp(azArg[0], "help", n) == 0) { - fprintf(stderr, "%s", zHelp); - if (HAS_TIMER) { - fprintf(stderr, "%s", zTimerHelp); - } - } else if (c == 'm' && strncmp(azArg[0], "mode", n) == 0 && nArg == 2) { - int n2 = strlen30(azArg[1]); - if ((n2 == 4 && strncmp(azArg[1], "line", n2) == 0) || - (n2 == 5 && strncmp(azArg[1], "lines", n2) == 0)) { - p->mode = MODE_Line; - } else if ((n2 == 6 && strncmp(azArg[1], "column", n2) == 0) || - (n2 == 7 && strncmp(azArg[1], "columns", n2) == 0)) { - p->mode = MODE_Column; - } else if (n2 == 4 && strncmp(azArg[1], "list", n2) == 0) { - p->mode = MODE_List; - } else if (n2 == 6 && strncmp(azArg[1], "pretty", n2) == 0) { - p->mode = MODE_Pretty; - } else if (n2 == 3 && strncmp(azArg[1], "csv", n2) == 0) { - p->mode = MODE_Csv; - sqlite3_snprintf(sizeof(p->separator), p->separator, ","); - } else { - fprintf(stderr, - "Error: mode should be one of: " - "column csv line list pretty\n"); - rc = 1; - } - } else if (c == 'n' && strncmp(azArg[0], "nullvalue", n) == 0 && nArg == 2) { - sqlite3_snprintf(sizeof(p->nullvalue), - p->nullvalue, - "%.*s", - ArraySize(p->nullvalue) - 1, - azArg[1]); - } else if (c == 'p' && n >= 3 && strncmp(azArg[0], "print", n) == 0) { - int j; - for (j = 1; j < nArg; j++) { - if (j > 1) { - fprintf(p->out, " "); - } - fprintf(p->out, "%s", azArg[j]); - } - fprintf(p->out, "\n"); - } else if (c == 'q' && strncmp(azArg[0], "quit", n) == 0 && nArg == 1) { - rc = 2; - } else if (c == 's' && strncmp(azArg[0], "schema", n) == 0 && nArg < 3) { - meta_schema(nArg, azArg); - } else if (c == 's' && strncmp(azArg[0], "separator", n) == 0 && nArg == 2) { - sqlite3_snprintf(sizeof(p->separator), - p->separator, - "%.*s", - static_cast(sizeof(p->separator)) - 1, - azArg[1]); - } else if (c == 's' && - (strncmp(azArg[0], "show", n) == 0 || - strncmp(azArg[0], "summary", n) == 0) && - nArg == 1) { - meta_show(p); - } else if (c == 't' && n > 1 && strncmp(azArg[0], "tables", n) == 0 && - nArg < 3) { - meta_tables(nArg, azArg); - } else if (c == 'l' && n > 1 && strncmp(azArg[0], "list", n) == 0 && - nArg < 3) { - meta_tables(nArg, azArg); - } else if (c == 't' && n > 4 && strncmp(azArg[0], "timeout", n) == 0 && - nArg == 2) { - sqlite3_busy_timeout(db, static_cast(integerValue(azArg[1]))); - } else if (HAS_TIMER && c == 't' && n >= 5 && - strncmp(azArg[0], "timer", n) == 0 && nArg == 2) { - enableTimer = booleanValue(azArg[1]); - } else if (c == 'v' && strncmp(azArg[0], "version", n) == 0) { - meta_version(p); - } else if (c == 'w' && strncmp(azArg[0], "width", n) == 0 && nArg > 1) { - int j; - assert(nArg <= ArraySize(azArg)); - for (j = 1; j < nArg && j < ArraySize(p->colWidth); j++) { - p->colWidth[j - 1] = static_cast(integerValue(azArg[j])); - } - } else { - fprintf(stderr, - "Error: unknown command or invalid arguments: " - " \"%s\". Enter \".help\" for help\n", - azArg[0]); - rc = 1; - } - - return rc; -} - -/* -** Return TRUE if a semicolon occurs anywhere in the first N characters -** of string z[]. -*/ -static int line_contains_semicolon(const char* z, int N) { - if (z == nullptr) { - return 0; - } - - for (int i = 0; i < N; i++) { - if (z[i] == ';') { - return 1; - } - } - return 0; -} - -/* -** Test to see if a line consists entirely of whitespace. -*/ -static int _all_whitespace(const char* z) { - if (z == nullptr) { - return 0; - } - - for (; *z != 0; z++) { - if (IsSpace(z[0])) { - continue; - } - - if (*z == '/' && z[1] == '*') { - z += 2; - while ((*z != 0) && (*z != '*' || z[1] != '/')) { - z++; - } - if (*z == 0) { - return 0; - } - z++; - continue; - } - if (*z == '-' && z[1] == '-') { - z += 2; - while ((*z != 0) && *z != '\n') { - z++; - } - if (*z == 0) { - return 1; - } - continue; - } - return 0; - } - return 1; -} - -/* -** Read input from *in and process it. If *in==0 then input -** is interactive - the user is typing it it. Otherwise, input -** is coming from a file or device. A prompt is issued and history -** is saved only if input is interactive. An interrupt signal will -** cause this routine to exit immediately, unless input is interactive. -** -** Return the number of errors. -*/ -static int process_input(struct callback_data* p, FILE* in) { - /* A single input line */ - char* zLine = nullptr; - - /* Accumulated SQL text */ - char* zSql = nullptr; - - /* Error message returned */ - char* zErrMsg = nullptr; - - int nLine = 0; /* Length of current line */ - int nSql = 0; /* Bytes of zSql[] used */ - int nAlloc = 0; /* Allocated zSql[] space */ - int nSqlPrior = 0; /* Bytes of zSql[] used by prior line */ - int rc = 0; /* Error code */ - int errCnt = 0; /* Number of errors seen */ - int lineno = 0; /* Current line number */ - int startline = 0; /* Line number for start of current input */ - bool typesQuery = false; - - while (errCnt == 0 || (bail_on_error == 0) || - (in == nullptr && stdin_is_interactive)) { - fflush(p->out); - zLine = one_input_line(in, zLine, static_cast(nSql > 0)); - if (zLine == nullptr) { - /* End of input */ - if (stdin_is_interactive) { - printf("\n"); - } - break; - } - if (seenInterrupt != 0) { - if (in != nullptr) { - break; - } - seenInterrupt = 0; - } - lineno++; - if (nSql == 0 && (_all_whitespace(zLine) != 0)) { - if (p->echoOn != 0) { - printf("%s\n", zLine); - } - continue; - } - if (zLine != nullptr && zLine[0] == '.' && nSql == 0) { - if (p->echoOn != 0) { - printf("%s\n", zLine); - } - if (strncmp(zLine, ".types ", 7) == 0) { - typesQuery = true; - } else { - rc = do_meta_command(zLine, p); - if (rc == 2) { /* exit requested */ - break; - } else if (rc != 0) { - errCnt++; - } - continue; - } - } - nLine = strlen30(zLine); - if (nSql + nLine + 2 >= nAlloc) { - nAlloc = nSql + nLine + 100; - auto qSql = reinterpret_cast(realloc(zSql, nAlloc)); - if (qSql == nullptr) { - fprintf(stderr, "Error: out of memory\n"); - if (zSql != nullptr) { - free(zSql); - } - exit(1); - } else { - zSql = qSql; - } - } - nSqlPrior = nSql; - if (nSql == 0) { - int i; - for (i = typesQuery ? 7 : 0; (zLine[i] != 0) && IsSpace(zLine[i]); i++) { - } - assert(nAlloc > 0 && zSql != nullptr); - if (zSql != nullptr) { - memcpy(zSql, zLine + i, nLine + 1 - i); - } - startline = lineno; - nSql = nLine - i; - } else { - zSql[nSql++] = '\n'; - memcpy(zSql + nSql, zLine, nLine + 1); - nSql += nLine; - } - if ((nSql != 0) && - (line_contains_semicolon(&zSql[nSqlPrior], nSql - nSqlPrior) != 0) && - (sqlite3_complete(zSql) != 0)) { - if (typesQuery) { - meta_types(p, zSql); - typesQuery = false; - } else { - p->cnt = 0; - BEGIN_TIMER; - rc = shell_exec(zSql, shell_callback, p, &zErrMsg); - END_TIMER; - if ((rc != 0) || zErrMsg != nullptr) { - char zPrefix[100] = {0}; - if (in != nullptr || !stdin_is_interactive) { - sqlite3_snprintf( - sizeof(zPrefix), zPrefix, "Error: near line %d:", startline); - } else { - sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:"); - } - if (zErrMsg != nullptr) { - fprintf(stderr, "%s %s\n", zPrefix, zErrMsg); - sqlite3_free(zErrMsg); - zErrMsg = nullptr; - } - errCnt++; - } - } - nSql = 0; - } else if ((nSql != 0) && (_all_whitespace(zSql) != 0)) { - if (p->echoOn != 0) { - printf("%s\n", zSql); - } - nSql = 0; - } - } - - if (nSql != 0) { - if (_all_whitespace(zSql) == 0) { - fprintf(stderr, "Error: incomplete SQL: %s\n", zSql); - } - } - if (zSql != nullptr) { - free(zSql); - } - - free(zLine); - return static_cast(errCnt > 0); -} - -/* -** Initialize the state information in data -*/ -static void main_init(struct callback_data* data) { - memset(data, 0, sizeof(struct callback_data)); - data->prettyPrint = new struct prettyprint_data(); - data->mode = MODE_Pretty; - data->showHeader = 1; - data->separator[0] = '|'; - - sqlite3_config(SQLITE_CONFIG_URI, 1); - sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data); - - auto term = osquery::getEnvVar("TERM"); - if (term.is_initialized() && - (*term).find("xterm-256color") != std::string::npos) { - sqlite3_snprintf( - sizeof(mainPrompt), mainPrompt, "\033[38;5;147mosquery> \033[0m"); - sqlite3_snprintf(sizeof(continuePrompt), - continuePrompt, - "\033[38;5;147m ...> \033[0m"); - } else { - sqlite3_snprintf(sizeof(mainPrompt), mainPrompt, "osquery> "); - sqlite3_snprintf(sizeof(continuePrompt), continuePrompt, " ...> "); - } - sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); -} - -namespace osquery { - -void tableCompletionFunction(char const* prefix, linenoiseCompletions* lc) { - auto tables = osquery::RegistryFactory::get().names("table"); - size_t index = 0; - - while (index < tables.size()) { - const std::string& table = tables.at(index); - ++index; - - if (boost::algorithm::starts_with(table, prefix)) { - linenoiseAddCompletion(lc, table.c_str()); - } - } -} - -int runQuery(struct callback_data* data, const char* query) { - char* error = nullptr; - int rc = shell_exec(query, shell_callback, data, &error); - if (error != nullptr) { - fprintf(stderr, "Error: %s\n", error); - rc = (rc == 0) ? 1 : rc; - } else if (rc != 0) { - fprintf(stderr, "Error: unable to process SQL \"%s\"\n", query); - } - return rc; -} - -int runPack(struct callback_data* data) { - int rc = 0; - return rc; -} - -int launchIntoShell(int argc, char** argv) { - struct callback_data data {}; - main_init(&data); - -#if defined(SQLITE_ENABLE_WHERETRACE) - sqlite3WhereTrace = 0xffffffff; -#endif - - // Move the attach function method into the osquery SQL implementation. - // This allow simple/straightforward control of concurrent DB access. - osquery::attachFunctionInternal("shellstatic", shellstaticFunc); - stdin_is_interactive = platformIsatty(stdin); - - // SQLite: Make sure we have a valid signal handler early - signal(SIGINT, interrupt_handler); - - data.out = stdout; - - set_table_name(&data, nullptr); - sqlite3_free(data.zFreeOnClose); - - if (data.prettyPrint != nullptr) { - delete data.prettyPrint; - } - return 0; -} -} // namespace osquery diff --git a/src/osquery/devtools/tests/CMakeLists.txt b/src/osquery/devtools/tests/CMakeLists.txt deleted file mode 100644 index 7534f8f..0000000 --- a/src/osquery/devtools/tests/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) 2014-present, Facebook, Inc. -# All rights reserved. -# -# This source code is licensed in accordance with the terms specified in -# the LICENSE file found in the root directory of this source tree. - -function(osqueryDevtoolsTestsMain) - generateOsqueryDevtoolsTestsPrintertestsTest() -endfunction() - -function(generateOsqueryDevtoolsTestsPrintertestsTest) - add_osquery_executable(osquery_devtools_tests_printertests-test printer_tests.cpp) - - target_link_libraries(osquery_devtools_tests_printertests-test PRIVATE - global_cxx_settings - osquery_database - osquery_distributed - osquery_events - osquery_extensions - osquery_extensions_implthrift - osquery_registry - osquery_remote_enroll_tlsenroll - osquery_devtools - plugins_config_tlsconfig - plugins_database_ephemeral - specs_tables - thirdparty_googletest - ) -endfunction() - -osqueryDevtoolsTestsMain() diff --git a/src/osquery/devtools/tests/printer_tests.cpp b/src/osquery/devtools/tests/printer_tests.cpp deleted file mode 100644 index 318ac90..0000000 --- a/src/osquery/devtools/tests/printer_tests.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ - -#include - -#include -#include - -namespace osquery { - -class PrinterTests : public testing::Test { - public: - QueryData q; - std::vector order; - void SetUp() { - order = {"name", "age", "food", "number"}; - q = { - { - {"name", "Mike Jones"}, - {"age", "39"}, - {"food", "mac and cheese"}, - {"number", "1"}, - }, - { - {"name", "John Smith"}, - {"age", "44"}, - {"food", "peanut butter and jelly"}, - {"number", "2"}, - }, - { - {"name", "Doctor Who"}, - {"age", "2000"}, - {"food", "fish sticks and custard"}, - {"number", "11"}, - }, - }; - } -}; - -TEST_F(PrinterTests, test_compute_query_data_lengths) { - std::map lengths; - for (const auto& row : q) { - computeRowLengths(row, lengths); - } - - // Check that all value lengths were maxed. - std::map expected = { - {"name", 10}, {"age", 4}, {"food", 23}, {"number", 2}}; - EXPECT_EQ(lengths, expected); - - // Then compute lengths of column names. - computeRowLengths(q.front(), lengths, true); - expected = {{"name", 10}, {"age", 4}, {"food", 23}, {"number", 6}}; - EXPECT_EQ(lengths, expected); -} - -TEST_F(PrinterTests, test_generate_separator) { - std::map lengths; - for (const auto& row : q) { - computeRowLengths(row, lengths); - } - - auto results = generateToken(lengths, order); - auto expected = "+------------+------+-------------------------+----+\n"; - EXPECT_EQ(results, expected); -} - -TEST_F(PrinterTests, test_generate_header) { - std::map lengths; - for (const auto& row : q) { - computeRowLengths(row, lengths); - } - - auto results = generateHeader(lengths, order); - auto expected = "| name | age | food | number |\n"; - EXPECT_EQ(results, expected); -} - -TEST_F(PrinterTests, test_generate_row) { - std::map lengths; - for (const auto& row : q) { - computeRowLengths(row, lengths); - } - - auto results = generateRow(q.front(), lengths, order); - auto expected = "| Mike Jones | 39 | mac and cheese | 1 |\n"; - EXPECT_EQ(results, expected); -} - -TEST_F(PrinterTests, test_unicode) { - Row r = {{"name", "Àlex Smith"}}; - std::map lengths; - computeRowLengths(r, lengths); - - std::map expected = {{"name", 10}}; - EXPECT_EQ(lengths, expected); -} -} // namespace osquery