2017-12-19 00:04:06 +00:00
|
|
|
/**
|
2016-02-11 19:48:58 +00:00
|
|
|
* Copyright (c) 2014-present, Facebook, Inc.
|
2014-12-18 18:50:47 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
2017-12-19 00:04:06 +00:00
|
|
|
* This source code is licensed under both the Apache 2.0 license (found in the
|
|
|
|
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
|
|
|
* in the COPYING file in the root directory of this source tree).
|
|
|
|
* You may select, at your option, one of the above-listed licenses.
|
2014-12-18 18:50:47 +00:00
|
|
|
*/
|
2014-09-12 04:44:10 +00:00
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2015-11-01 09:12:48 +00:00
|
|
|
#include <limits.h>
|
|
|
|
|
2014-09-12 04:44:10 +00:00
|
|
|
#include <memory>
|
2018-02-16 21:56:38 +00:00
|
|
|
#include <set>
|
2015-11-01 09:12:48 +00:00
|
|
|
#include <string>
|
2016-02-12 17:39:20 +00:00
|
|
|
#include <vector>
|
2014-09-12 04:44:10 +00:00
|
|
|
|
|
|
|
#include <boost/bind.hpp>
|
|
|
|
#include <boost/shared_ptr.hpp>
|
|
|
|
|
2018-04-25 22:12:01 +00:00
|
|
|
#include <osquery/logger.h>
|
2015-11-01 09:12:48 +00:00
|
|
|
#include <osquery/status.h>
|
|
|
|
|
2014-12-10 09:17:24 +00:00
|
|
|
#ifdef DARWIN
|
|
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
|
|
#endif
|
|
|
|
|
2014-09-12 04:44:10 +00:00
|
|
|
namespace osquery {
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void do_release_boost(typename boost::shared_ptr<T> const&, T*) {}
|
|
|
|
|
2014-09-16 07:28:23 +00:00
|
|
|
/**
|
|
|
|
* @brief Convert a boost::shared_ptr to a std::shared_ptr
|
2014-09-16 05:56:11 +00:00
|
|
|
*/
|
2014-09-12 04:44:10 +00:00
|
|
|
template <typename T>
|
|
|
|
typename std::shared_ptr<T> boost_to_std_shared_ptr(
|
|
|
|
typename boost::shared_ptr<T> const& p) {
|
|
|
|
return std::shared_ptr<T>(p.get(), boost::bind(&do_release_boost<T>, p, _1));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void do_release_std(typename std::shared_ptr<T> const&, T*) {}
|
|
|
|
|
2014-09-16 07:28:23 +00:00
|
|
|
/**
|
|
|
|
* @brief Convert a std::shared_ptr to a boost::shared_ptr
|
2014-09-16 05:56:11 +00:00
|
|
|
*/
|
2014-09-12 04:44:10 +00:00
|
|
|
template <typename T>
|
|
|
|
typename boost::shared_ptr<T> std_to_boost_shared_ptr(
|
|
|
|
typename std::shared_ptr<T> const& p) {
|
|
|
|
return boost::shared_ptr<T>(p.get(), boost::bind(&do_release_std<T>, p, _1));
|
|
|
|
}
|
2014-12-10 09:17:24 +00:00
|
|
|
|
2016-02-12 17:39:20 +00:00
|
|
|
/**
|
|
|
|
* @brief Split a given string based on an optional delimiter.
|
|
|
|
*
|
|
|
|
* If no delimiter is supplied, the string will be split based on whitespace.
|
|
|
|
*
|
|
|
|
* @param s the string that you'd like to split
|
|
|
|
* @param delim the delimiter which you'd like to split the string by
|
|
|
|
*
|
|
|
|
* @return a vector of strings split by delim.
|
|
|
|
*/
|
|
|
|
std::vector<std::string> split(const std::string& s,
|
|
|
|
const std::string& delim = "\t ");
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Split a given string based on an delimiter.
|
|
|
|
*
|
|
|
|
* @param s the string that you'd like to split.
|
|
|
|
* @param delim the delimiter which you'd like to split the string by.
|
|
|
|
* @param occurrences the number of times to split by delim.
|
|
|
|
*
|
|
|
|
* @return a vector of strings split by delim for occurrences.
|
|
|
|
*/
|
|
|
|
std::vector<std::string> split(const std::string& s,
|
bug split(string,string,size_t) (#4515)
split(string,string,size_t) contained bug, it was joining on every delimiter, which would result to unusual outcome. However, test could not detect this problem as delim.size() was 1. It turned out, that this split is not used anywhere having delim.size() > 1, so completely fixing bug by changing signature of the method to split(string,char,size_t)
2018-06-12 17:34:09 +00:00
|
|
|
char delim,
|
2016-02-12 17:39:20 +00:00
|
|
|
size_t occurences);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief In-line replace all instances of from with to.
|
|
|
|
*
|
|
|
|
* @param str The input/output mutable string.
|
|
|
|
* @param from Search string
|
|
|
|
* @param to Replace string
|
|
|
|
*/
|
|
|
|
inline void replaceAll(std::string& str,
|
|
|
|
const std::string& from,
|
|
|
|
const std::string& to) {
|
|
|
|
if (from.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t start_pos = 0;
|
|
|
|
while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
|
|
|
|
str.replace(start_pos, from.length(), to);
|
|
|
|
start_pos += to.length();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-03-07 17:54:21 +00:00
|
|
|
* @brief Join a vector of strings inserting a token string between elements
|
2016-02-12 17:39:20 +00:00
|
|
|
*
|
2016-03-07 17:54:21 +00:00
|
|
|
* @param s the vector of strings to be joined.
|
|
|
|
* @param tok a token glue string to be inserted between elements.
|
2016-02-12 17:39:20 +00:00
|
|
|
*
|
2016-03-07 17:54:21 +00:00
|
|
|
* @return the joined string.
|
2016-02-12 17:39:20 +00:00
|
|
|
*/
|
|
|
|
std::string join(const std::vector<std::string>& s, const std::string& tok);
|
|
|
|
|
2018-02-16 21:56:38 +00:00
|
|
|
/**
|
|
|
|
* @brief Join a set of strings inserting a token string between elements
|
|
|
|
*
|
|
|
|
* @param s the set of strings to be joined.
|
|
|
|
* @param tok a token glue string to be inserted between elements.
|
|
|
|
*
|
|
|
|
* @return the joined string.
|
|
|
|
*/
|
|
|
|
std::string join(const std::set<std::string>& s, const std::string& tok);
|
|
|
|
|
2014-12-17 22:03:52 +00:00
|
|
|
/**
|
|
|
|
* @brief Decode a base64 encoded string.
|
|
|
|
*
|
|
|
|
* @param encoded The encode base64 string.
|
|
|
|
* @return Decoded string.
|
|
|
|
*/
|
2018-06-12 17:37:04 +00:00
|
|
|
std::string base64Decode(std::string encoded);
|
2014-12-17 22:03:52 +00:00
|
|
|
|
2015-01-21 02:02:45 +00:00
|
|
|
/**
|
|
|
|
* @brief Encode a string.
|
|
|
|
*
|
|
|
|
* @param A string to encode.
|
|
|
|
* @return Encoded string.
|
|
|
|
*/
|
|
|
|
std::string base64Encode(const std::string& unencoded);
|
|
|
|
|
2015-04-09 00:41:54 +00:00
|
|
|
/**
|
|
|
|
* @brief Check if a string is ASCII printable
|
|
|
|
*
|
|
|
|
* @param A string to check.
|
|
|
|
* @return If the string is printable.
|
|
|
|
*/
|
|
|
|
bool isPrintable(const std::string& check);
|
|
|
|
|
2015-11-01 09:12:48 +00:00
|
|
|
/// Safely convert a string representation of an integer base.
|
|
|
|
inline Status safeStrtol(const std::string& rep, size_t base, long int& out) {
|
|
|
|
char* end{nullptr};
|
2016-09-02 22:04:03 +00:00
|
|
|
out = strtol(rep.c_str(), &end, static_cast<int>(base));
|
2015-11-01 09:12:48 +00:00
|
|
|
if (end == nullptr || end == rep.c_str() || *end != '\0' ||
|
|
|
|
((out == LONG_MIN || out == LONG_MAX) && errno == ERANGE)) {
|
2016-09-12 23:53:42 +00:00
|
|
|
out = 0;
|
|
|
|
return Status(1);
|
|
|
|
}
|
|
|
|
return Status(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Safely convert a string representation of an integer base.
|
|
|
|
inline Status safeStrtoul(const std::string& rep,
|
|
|
|
size_t base,
|
|
|
|
unsigned long int& out) {
|
|
|
|
char* end{nullptr};
|
2016-09-23 17:14:27 +00:00
|
|
|
out = strtoul(rep.c_str(), &end, static_cast<int>(base));
|
2016-09-12 23:53:42 +00:00
|
|
|
if (end == nullptr || end == rep.c_str() || *end != '\0' || errno == ERANGE) {
|
|
|
|
out = 0;
|
2015-11-01 09:12:48 +00:00
|
|
|
return Status(1);
|
|
|
|
}
|
|
|
|
return Status(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Safely convert a string representation of an integer base.
|
|
|
|
inline Status safeStrtoll(const std::string& rep, size_t base, long long& out) {
|
|
|
|
char* end{nullptr};
|
2016-09-02 22:04:03 +00:00
|
|
|
out = strtoll(rep.c_str(), &end, static_cast<int>(base));
|
2015-11-01 09:12:48 +00:00
|
|
|
if (end == nullptr || end == rep.c_str() || *end != '\0' ||
|
|
|
|
((out == LLONG_MIN || out == LLONG_MAX) && errno == ERANGE)) {
|
2016-09-12 23:53:42 +00:00
|
|
|
out = 0;
|
2015-11-01 09:12:48 +00:00
|
|
|
return Status(1);
|
|
|
|
}
|
|
|
|
return Status(0);
|
|
|
|
}
|
|
|
|
|
2018-06-07 02:08:23 +00:00
|
|
|
/// Safely convert a string representation of an integer base.
|
|
|
|
inline Status safeStrtoi(const std::string& rep, int base, int& out) {
|
|
|
|
try {
|
2018-06-19 21:02:07 +00:00
|
|
|
out = std::stoi(rep, nullptr, base);
|
2018-06-07 02:08:23 +00:00
|
|
|
} catch (const std::invalid_argument& ia) {
|
|
|
|
return Status(
|
|
|
|
1, std::string("If no conversion could be performed. ") + ia.what());
|
|
|
|
} catch (const std::out_of_range& oor) {
|
|
|
|
return Status(1,
|
|
|
|
std::string("Value read is out of the range of representable "
|
|
|
|
"values by an int. ") +
|
|
|
|
oor.what());
|
|
|
|
}
|
|
|
|
return Status(0);
|
|
|
|
}
|
|
|
|
|
2017-09-13 23:30:30 +00:00
|
|
|
/// Safely convert a string representation of an integer base.
|
|
|
|
inline Status safeStrtoull(const std::string& rep,
|
|
|
|
size_t base,
|
|
|
|
unsigned long long& out) {
|
|
|
|
char* end{nullptr};
|
|
|
|
out = strtoull(rep.c_str(), &end, static_cast<int>(base));
|
|
|
|
if (end == nullptr || end == rep.c_str() || *end != '\0' ||
|
|
|
|
(out == ULLONG_MAX && errno == ERANGE)) {
|
|
|
|
out = 0;
|
|
|
|
return Status(1);
|
|
|
|
}
|
|
|
|
return Status(0);
|
|
|
|
}
|
|
|
|
|
2015-11-24 22:43:38 +00:00
|
|
|
/// Safely convert unicode escaped ASCII.
|
|
|
|
inline std::string unescapeUnicode(const std::string& escaped) {
|
|
|
|
if (escaped.size() < 6) {
|
|
|
|
return escaped;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string unescaped;
|
|
|
|
unescaped.reserve(escaped.size());
|
|
|
|
for (size_t i = 0; i < escaped.size(); ++i) {
|
|
|
|
if (i < escaped.size() - 5 && '\\' == escaped[i] && 'u' == escaped[i + 1]) {
|
|
|
|
// Assume 2-byte wide unicode.
|
|
|
|
long value{0};
|
2016-09-12 23:53:42 +00:00
|
|
|
Status stat = safeStrtol(escaped.substr(i + 2, 4), 16, value);
|
|
|
|
if (!stat.ok()) {
|
2018-04-25 22:12:01 +00:00
|
|
|
LOG(WARNING) << "Unescaping a string with length: " << escaped.size()
|
|
|
|
<< " failed at: " << i;
|
2016-09-12 23:53:42 +00:00
|
|
|
return "";
|
|
|
|
}
|
2015-11-24 22:43:38 +00:00
|
|
|
if (value < 255) {
|
|
|
|
unescaped += static_cast<char>(value);
|
|
|
|
i += 5;
|
|
|
|
continue;
|
|
|
|
}
|
2018-04-25 22:12:01 +00:00
|
|
|
} else if (i < escaped.size() - 1 && '\\' == escaped[i] &&
|
|
|
|
'\\' == escaped[i + 1]) {
|
|
|
|
// In the case of \\users 'sers' is not a unicode character
|
|
|
|
// If we see \\ we should skip them and we do this by adding
|
|
|
|
// an extra jump forward.
|
|
|
|
unescaped += escaped[i];
|
|
|
|
++i;
|
2015-11-24 22:43:38 +00:00
|
|
|
}
|
|
|
|
unescaped += escaped[i];
|
|
|
|
}
|
|
|
|
return unescaped;
|
|
|
|
}
|
|
|
|
|
2016-02-12 17:39:20 +00:00
|
|
|
/**
|
|
|
|
* @brief In-line helper function for use with utf8StringSize
|
|
|
|
*/
|
|
|
|
template <typename _Iterator1, typename _Iterator2>
|
|
|
|
inline size_t incUtf8StringIterator(_Iterator1& it, const _Iterator2& last) {
|
|
|
|
if (it == last) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t res = 1;
|
|
|
|
for (++it; last != it; ++it, ++res) {
|
|
|
|
unsigned char c = *it;
|
|
|
|
if (!(c & 0x80) || ((c & 0xC0) == 0xC0)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get the length of a UTF-8 string
|
|
|
|
*
|
|
|
|
* @param str The UTF-8 string
|
|
|
|
*
|
|
|
|
* @return the length of the string
|
|
|
|
*/
|
|
|
|
inline size_t utf8StringSize(const std::string& str) {
|
|
|
|
size_t res = 0;
|
|
|
|
std::string::const_iterator it = str.begin();
|
|
|
|
for (; it != str.end(); incUtf8StringIterator(it, str.end())) {
|
|
|
|
res++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2016-12-22 08:37:59 +00:00
|
|
|
/*
|
|
|
|
* @brief Request a SHA1 hash from the contents of a buffer.
|
|
|
|
*
|
|
|
|
* @param buffer A caller-controlled buffer (already allocated).
|
|
|
|
* @param size The length of the controlled buffer.
|
|
|
|
* @return A string (hex) representation of the hash digest.
|
|
|
|
*/
|
|
|
|
std::string getBufferSHA1(const char* buffer, size_t size);
|
|
|
|
|
2014-12-10 09:17:24 +00:00
|
|
|
#ifdef DARWIN
|
2014-12-10 17:12:12 +00:00
|
|
|
/**
|
|
|
|
* @brief Convert a CFStringRef to a std::string.
|
|
|
|
*/
|
2014-12-10 09:52:02 +00:00
|
|
|
std::string stringFromCFString(const CFStringRef& cf_string);
|
2014-12-10 17:12:12 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Convert a CFNumberRef to a std::string.
|
|
|
|
*/
|
2014-12-10 09:17:24 +00:00
|
|
|
std::string stringFromCFNumber(const CFDataRef& cf_number);
|
2015-03-09 06:05:09 +00:00
|
|
|
std::string stringFromCFNumber(const CFDataRef& cf_number, CFNumberType type);
|
|
|
|
|
2015-05-27 22:21:13 +00:00
|
|
|
/**
|
|
|
|
* @brief Convert a CFAbsoluteTime to a std::string.
|
|
|
|
*/
|
|
|
|
std::string stringFromCFAbsoluteTime(const CFDataRef& cf_abstime);
|
|
|
|
|
2014-12-10 22:51:43 +00:00
|
|
|
std::string stringFromCFData(const CFDataRef& cf_data);
|
2014-12-10 09:17:24 +00:00
|
|
|
#endif
|
2014-09-12 04:44:10 +00:00
|
|
|
}
|