mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-07 09:58:54 +00:00
Merge pull request #1224 from theopolis/duti_table
OS X application duti/scheme listing table
This commit is contained in:
commit
53c407781f
@ -51,6 +51,8 @@ namespace osquery {
|
|||||||
#define BIGINT(x) boost::lexical_cast<std::string>(x)
|
#define BIGINT(x) boost::lexical_cast<std::string>(x)
|
||||||
/// See the affinity type documentation for TEXT.
|
/// See the affinity type documentation for TEXT.
|
||||||
#define UNSIGNED_BIGINT(x) boost::lexical_cast<std::string>(x)
|
#define UNSIGNED_BIGINT(x) boost::lexical_cast<std::string>(x)
|
||||||
|
/// See the affinity type documentation for TEXT.
|
||||||
|
#define DOUBLE(x) boost::lexical_cast<std::string>(x)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The SQLite type affinities as represented as implementation literals.
|
* @brief The SQLite type affinities as represented as implementation literals.
|
||||||
@ -67,6 +69,8 @@ namespace osquery {
|
|||||||
#define BIGINT_LITERAL long long int
|
#define BIGINT_LITERAL long long int
|
||||||
/// See the literal type documentation for TEXT_LITERAL.
|
/// See the literal type documentation for TEXT_LITERAL.
|
||||||
#define UNSIGNED_BIGINT_LITERAL unsigned long long int
|
#define UNSIGNED_BIGINT_LITERAL unsigned long long int
|
||||||
|
/// See the literal type documentation for TEXT_LITERAL.
|
||||||
|
#define DOUBLE_LITERAL double
|
||||||
/// Cast an SQLite affinity type to the literal type.
|
/// Cast an SQLite affinity type to the literal type.
|
||||||
#define AS_LITERAL(literal, value) boost::lexical_cast<literal>(value)
|
#define AS_LITERAL(literal, value) boost::lexical_cast<literal>(value)
|
||||||
|
|
||||||
@ -89,7 +93,7 @@ enum ConstraintOperator : unsigned char {
|
|||||||
GREATER_THAN_OR_EQUALS = 32
|
GREATER_THAN_OR_EQUALS = 32
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Type for flags for what constraint operators are admissable.
|
/// Type for flags for what constraint operators are admissible.
|
||||||
typedef unsigned char ConstraintOperatorFlag;
|
typedef unsigned char ConstraintOperatorFlag;
|
||||||
/// Flag for any operator type.
|
/// Flag for any operator type.
|
||||||
#define ANY_OP 0xFFU
|
#define ANY_OP 0xFFU
|
||||||
|
@ -172,7 +172,7 @@ Initializer::Initializer(int& argc, char**& argv, ToolType tool)
|
|||||||
if (Flag::isDefault("database_path")) {
|
if (Flag::isDefault("database_path")) {
|
||||||
osquery::FLAGS_database_path = homedir + "/shell.db";
|
osquery::FLAGS_database_path = homedir + "/shell.db";
|
||||||
}
|
}
|
||||||
if (Flag::isDefault("extension_socket")) {
|
if (Flag::isDefault("extensions_socket")) {
|
||||||
osquery::FLAGS_extensions_socket = homedir + "/shell.em";
|
osquery::FLAGS_extensions_socket = homedir + "/shell.em";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,6 +144,16 @@ int xColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int col) {
|
|||||||
<< ") to BIGINT";
|
<< ") to BIGINT";
|
||||||
}
|
}
|
||||||
sqlite3_result_int64(ctx, afinite);
|
sqlite3_result_int64(ctx, afinite);
|
||||||
|
} else if (type == "DOUBLE") {
|
||||||
|
double afinite;
|
||||||
|
try {
|
||||||
|
afinite = boost::lexical_cast<double>(value);
|
||||||
|
} catch (const boost::bad_lexical_cast &e) {
|
||||||
|
afinite = 0;
|
||||||
|
VLOG(1) << "Error casting" << column_name << " (" << value
|
||||||
|
<< ") to DOUBLE";
|
||||||
|
}
|
||||||
|
sqlite3_result_double(ctx, afinite);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <CoreServices/CoreServices.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string/join.hpp>
|
#include <boost/algorithm/string/join.hpp>
|
||||||
#include <boost/filesystem/operations.hpp>
|
#include <boost/filesystem/operations.hpp>
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
@ -18,6 +20,8 @@
|
|||||||
#include <osquery/tables.h>
|
#include <osquery/tables.h>
|
||||||
#include <osquery/sql.h>
|
#include <osquery/sql.h>
|
||||||
|
|
||||||
|
#include "osquery/core/conversions.h"
|
||||||
|
|
||||||
namespace fs = boost::filesystem;
|
namespace fs = boost::filesystem;
|
||||||
namespace pt = boost::property_tree;
|
namespace pt = boost::property_tree;
|
||||||
|
|
||||||
@ -47,6 +51,110 @@ const std::vector<std::string> kHomeDirSearchPaths = {
|
|||||||
"Applications", "Desktop", "Downloads",
|
"Applications", "Desktop", "Downloads",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum AppSchemeFlags {
|
||||||
|
kSchemeNormal = 0,
|
||||||
|
// Default flag from the list of schemes on a default OS X 10.10 install.
|
||||||
|
kSchemeSystemDefault = 1,
|
||||||
|
// Protected flag from Apple Reference: Inter-app Communication
|
||||||
|
kSchemeProtected = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::map<std::string, unsigned short> kApplicationSchemes = {
|
||||||
|
{"account", 0},
|
||||||
|
{"addressbook", kSchemeSystemDefault},
|
||||||
|
{"afp", kSchemeSystemDefault | kSchemeProtected},
|
||||||
|
{"aim", kSchemeSystemDefault},
|
||||||
|
{"alfred", 0},
|
||||||
|
{"alfredapp", 0},
|
||||||
|
{"app-prefs", 0},
|
||||||
|
{"applefeedback", kSchemeSystemDefault},
|
||||||
|
{"applescript", kSchemeSystemDefault},
|
||||||
|
{"apupdate", kSchemeSystemDefault},
|
||||||
|
{"at", kSchemeSystemDefault | kSchemeProtected},
|
||||||
|
{"atom", 0},
|
||||||
|
{"bluejeans", 0},
|
||||||
|
{"calinvite", 0},
|
||||||
|
{"calinvitelist", 0},
|
||||||
|
{"callto", 0},
|
||||||
|
{"calshow", 0},
|
||||||
|
{"cloudphoto", kSchemeSystemDefault},
|
||||||
|
{"conf", 0},
|
||||||
|
{"daap", kSchemeSystemDefault},
|
||||||
|
{"dict", kSchemeSystemDefault},
|
||||||
|
{"facetime", kSchemeSystemDefault | kSchemeProtected},
|
||||||
|
{"fb", kSchemeSystemDefault},
|
||||||
|
{"fbauth", 0},
|
||||||
|
{"file", kSchemeSystemDefault | kSchemeProtected},
|
||||||
|
{"ftp", kSchemeSystemDefault | kSchemeProtected},
|
||||||
|
{"gamecenter", kSchemeSystemDefault},
|
||||||
|
{"gopher", 0},
|
||||||
|
{"grammar", 0},
|
||||||
|
{"h323", 0},
|
||||||
|
{"help", kSchemeSystemDefault},
|
||||||
|
{"http", kSchemeSystemDefault | kSchemeProtected},
|
||||||
|
{"https", kSchemeSystemDefault | kSchemeProtected},
|
||||||
|
{"iadoptout", 0},
|
||||||
|
{"ibooks", kSchemeSystemDefault},
|
||||||
|
{"ical", kSchemeSystemDefault},
|
||||||
|
{"ichat", kSchemeSystemDefault},
|
||||||
|
{"icloud-sharing", kSchemeSystemDefault},
|
||||||
|
{"im", kSchemeSystemDefault},
|
||||||
|
{"imessage", kSchemeSystemDefault},
|
||||||
|
{"ipps", kSchemeSystemDefault},
|
||||||
|
{"irc", 0},
|
||||||
|
{"itls", kSchemeSystemDefault},
|
||||||
|
{"itms", kSchemeSystemDefault},
|
||||||
|
{"itms-books", kSchemeSystemDefault},
|
||||||
|
{"itms-bookss", kSchemeSystemDefault},
|
||||||
|
{"itmsp-app", 0},
|
||||||
|
{"itunesradio", kSchemeSystemDefault},
|
||||||
|
{"macappstore", kSchemeSystemDefault},
|
||||||
|
{"macappstores", kSchemeSystemDefault},
|
||||||
|
{"mailto", kSchemeSystemDefault | kSchemeProtected},
|
||||||
|
{"map", 0},
|
||||||
|
{"maps", kSchemeSystemDefault},
|
||||||
|
{"message", kSchemeSystemDefault},
|
||||||
|
{"messages", kSchemeSystemDefault},
|
||||||
|
{"ms-excel", 0},
|
||||||
|
{"ms-word", 0},
|
||||||
|
{"munki", 0},
|
||||||
|
{"news", kSchemeSystemDefault | kSchemeProtected},
|
||||||
|
{"nntp", 0},
|
||||||
|
{"nwnode", kSchemeSystemDefault | kSchemeProtected},
|
||||||
|
{"omnifocus", 0},
|
||||||
|
{"ophttp", 0},
|
||||||
|
{"pcast", kSchemeSystemDefault},
|
||||||
|
{"photos", kSchemeSystemDefault},
|
||||||
|
{"photos-event", 0},
|
||||||
|
{"photos-migrate-iphoto", 0},
|
||||||
|
{"photos-redirect", 0},
|
||||||
|
{"powerpoint", 0},
|
||||||
|
{"prefs", 0},
|
||||||
|
{"qs", 0},
|
||||||
|
{"qsinstall", 0},
|
||||||
|
{"qss-http", 0},
|
||||||
|
{"qssp-http", 0},
|
||||||
|
{"reminders", kSchemeSystemDefault},
|
||||||
|
{"rtsp", kSchemeSystemDefault},
|
||||||
|
{"shoebox", 0},
|
||||||
|
{"slack", 0},
|
||||||
|
{"smb", kSchemeSystemDefault | kSchemeProtected},
|
||||||
|
{"sms", kSchemeSystemDefault | kSchemeProtected},
|
||||||
|
{"ssh", kSchemeSystemDefault},
|
||||||
|
{"tel", kSchemeSystemDefault | kSchemeProtected},
|
||||||
|
{"telnet", kSchemeSystemDefault},
|
||||||
|
{"twitter", kSchemeSystemDefault},
|
||||||
|
{"txmt", 0},
|
||||||
|
{"vnc", kSchemeSystemDefault | kSchemeProtected},
|
||||||
|
{"wais", 0},
|
||||||
|
{"webapp", 0},
|
||||||
|
{"webcal", kSchemeSystemDefault},
|
||||||
|
{"whois", 0},
|
||||||
|
{"wunderlist", 0},
|
||||||
|
{"xmpp", kSchemeSystemDefault},
|
||||||
|
{"yelp", 0},
|
||||||
|
};
|
||||||
|
|
||||||
void genApplicationsFromPath(const fs::path& path,
|
void genApplicationsFromPath(const fs::path& path,
|
||||||
std::vector<std::string>& apps) {
|
std::vector<std::string>& apps) {
|
||||||
std::vector<std::string> new_apps;
|
std::vector<std::string> new_apps;
|
||||||
@ -93,13 +201,20 @@ QueryData genApps(QueryContext& context) {
|
|||||||
|
|
||||||
// Walk through several groups of common search paths that may contain apps.
|
// Walk through several groups of common search paths that may contain apps.
|
||||||
std::vector<std::string> apps;
|
std::vector<std::string> apps;
|
||||||
genApplicationsFromPath("/Applications", apps);
|
if (context.constraints["path"].exists(EQUALS)) {
|
||||||
|
auto app_constraints = context.constraints["path"].getAll(EQUALS);
|
||||||
|
for (const auto& app : app_constraints) {
|
||||||
|
apps.push_back((fs::path(app) / "Contents/Info.plist").string());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
genApplicationsFromPath("/Applications", apps);
|
||||||
|
|
||||||
// List all users on the system, and walk common search paths with homes.
|
// List all users on the system, and walk common search paths with homes.
|
||||||
auto homes = osquery::getHomeDirectories();
|
auto homes = osquery::getHomeDirectories();
|
||||||
for (const auto& home : homes) {
|
for (const auto& home : homes) {
|
||||||
for (const auto& path : kHomeDirSearchPaths) {
|
for (const auto& path : kHomeDirSearchPaths) {
|
||||||
genApplicationsFromPath(home / path, apps);
|
genApplicationsFromPath(home / path, apps);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,11 +225,6 @@ QueryData genApps(QueryContext& context) {
|
|||||||
|
|
||||||
// For each found application (path with an Info.plist) parse the plist.
|
// For each found application (path with an Info.plist) parse the plist.
|
||||||
for (const auto& path : apps) {
|
for (const auto& path : apps) {
|
||||||
if (!context.constraints["path"].matches(path)) {
|
|
||||||
// Optimize by not searching when a path is a constraint.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!osquery::parsePlist(path, tree).ok()) {
|
if (!osquery::parsePlist(path, tree).ok()) {
|
||||||
TLOG << "Error parsing application plist: " << path;
|
TLOG << "Error parsing application plist: " << path;
|
||||||
continue;
|
continue;
|
||||||
@ -126,5 +236,73 @@ QueryData genApps(QueryContext& context) {
|
|||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QueryData genAppSchemes(QueryContext& context) {
|
||||||
|
QueryData results;
|
||||||
|
|
||||||
|
for (const auto& scheme : kApplicationSchemes) {
|
||||||
|
auto protocol = scheme.first + "://";
|
||||||
|
auto cfprotocol = CFStringCreateWithCString(
|
||||||
|
kCFAllocatorDefault, protocol.c_str(), protocol.length());
|
||||||
|
if (cfprotocol == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a "fake" URL that only contains the protocol component of a URI.
|
||||||
|
auto url = CFURLCreateWithString(kCFAllocatorDefault, cfprotocol, nullptr);
|
||||||
|
CFRelease(cfprotocol);
|
||||||
|
if (url == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// List all application bundles that request this protocol scheme.
|
||||||
|
auto apps = LSCopyApplicationURLsForURL(url, kLSRolesAll);
|
||||||
|
if (apps == nullptr) {
|
||||||
|
CFRelease(url);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the default handler assigned to the protocol scheme.
|
||||||
|
auto default_app =
|
||||||
|
LSCopyDefaultApplicationURLForURL(url, kLSRolesAll, nullptr);
|
||||||
|
CFRelease(url);
|
||||||
|
for (CFIndex i = 0; i < CFArrayGetCount(apps); i++) {
|
||||||
|
Row r;
|
||||||
|
r["scheme"] = scheme.first;
|
||||||
|
|
||||||
|
auto app = CFArrayGetValueAtIndex(apps, i);
|
||||||
|
if (app == nullptr || CFGetTypeID(app) != CFURLGetTypeID()) {
|
||||||
|
// Handle problems with application listings.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto path = CFURLCopyFileSystemPath((CFURLRef)app, kCFURLPOSIXPathStyle);
|
||||||
|
if (path == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
r["handler"] = stringFromCFString(path);
|
||||||
|
CFRelease(path);
|
||||||
|
// Check if the handler is set (in the OS) as the default.
|
||||||
|
if (default_app != nullptr &&
|
||||||
|
CFEqual((CFTypeRef)app, (CFTypeRef)default_app)) {
|
||||||
|
r["enabled"] = "1";
|
||||||
|
} else {
|
||||||
|
r["enabled"] = "0";
|
||||||
|
}
|
||||||
|
r["external"] = (scheme.second & kSchemeSystemDefault) ? "0" : "1";
|
||||||
|
r["protected"] = (scheme.second & kSchemeProtected) ? "1" : "0";
|
||||||
|
results.push_back(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (default_app != nullptr) {
|
||||||
|
CFRelease(default_app);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(apps);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,9 +139,9 @@ void parseWhereFrom(QueryData &results, const std::string &path) {
|
|||||||
CFRelease(attributes);
|
CFRelease(attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void extractQuarantineProperty(const std::string table_key_name,
|
void extractQuarantineProperty(const std::string &table_key_name,
|
||||||
CFTypeRef property,
|
CFTypeRef property,
|
||||||
const std::string path,
|
const std::string &path,
|
||||||
QueryData &results) {
|
QueryData &results) {
|
||||||
std::string value;
|
std::string value;
|
||||||
if (CFGetTypeID(property) == CFStringGetTypeID()) {
|
if (CFGetTypeID(property) == CFStringGetTypeID()) {
|
||||||
|
@ -62,8 +62,8 @@ const std::map<CSSM_ACL_AUTHORIZATION_TAG, std::string> kACLAuthorizationTags =
|
|||||||
{CSSM_ACL_AUTHORIZATION_CHANGE_OWNER, "change_owner"},
|
{CSSM_ACL_AUTHORIZATION_CHANGE_OWNER, "change_owner"},
|
||||||
};
|
};
|
||||||
|
|
||||||
Status inline parseKeychainItemACLEntry(SecACLRef acl,
|
Status parseKeychainItemACLEntry(SecACLRef acl,
|
||||||
std::vector<KeychainItemACL> &acls) {
|
std::vector<KeychainItemACL> &acls) {
|
||||||
KeychainItemACL acl_data;
|
KeychainItemACL acl_data;
|
||||||
OSStatus os_status;
|
OSStatus os_status;
|
||||||
|
|
||||||
@ -105,21 +105,22 @@ Status inline parseKeychainItemACLEntry(SecACLRef acl,
|
|||||||
app_index);
|
app_index);
|
||||||
CFDataRef data = nullptr;
|
CFDataRef data = nullptr;
|
||||||
os_status = SecTrustedApplicationCopyData(app, &data);
|
os_status = SecTrustedApplicationCopyData(app, &data);
|
||||||
if (os_status != noErr) {
|
if (os_status != noErr || data == nullptr) {
|
||||||
return Status(os_status, "Coult not copy trusted application data");
|
CFRelease(application_list);
|
||||||
|
if (data != nullptr) {
|
||||||
|
// To be very safe, assume data may have been allocated on error.
|
||||||
|
CFRelease(data);
|
||||||
|
}
|
||||||
|
return Status(os_status, "Could not copy trusted application data");
|
||||||
}
|
}
|
||||||
|
|
||||||
const UInt8 *bytes = CFDataGetBytePtr(data);
|
const UInt8 *bytes = CFDataGetBytePtr(data);
|
||||||
if (bytes && bytes[0] == 0x2f) {
|
if (bytes != nullptr && bytes[0] == '/') {
|
||||||
acl_data.applications.push_back(std::string((const char *)bytes));
|
acl_data.applications.push_back(std::string((const char *)bytes));
|
||||||
}
|
}
|
||||||
if (data != nullptr) {
|
CFRelease(data);
|
||||||
CFRelease(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (application_list != nullptr) {
|
|
||||||
CFRelease(application_list);
|
|
||||||
}
|
}
|
||||||
|
CFRelease(application_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
acls.push_back(acl_data);
|
acls.push_back(acl_data);
|
||||||
@ -131,7 +132,10 @@ Status parseKeychainItemACL(SecAccessRef access,
|
|||||||
OSStatus os_status;
|
OSStatus os_status;
|
||||||
CFArrayRef acl_list = nullptr;
|
CFArrayRef acl_list = nullptr;
|
||||||
os_status = SecAccessCopyACLList(access, &acl_list);
|
os_status = SecAccessCopyACLList(access, &acl_list);
|
||||||
if (os_status != noErr) {
|
if (os_status != noErr || acl_list == nullptr) {
|
||||||
|
if (acl_list != nullptr) {
|
||||||
|
CFRelease(acl_list);
|
||||||
|
}
|
||||||
return Status(os_status, "Could not copy ACL list");
|
return Status(os_status, "Could not copy ACL list");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,14 +148,12 @@ Status parseKeychainItemACL(SecAccessRef access,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (acl_list != nullptr) {
|
|
||||||
CFRelease(acl_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
CFRelease(acl_list);
|
||||||
return Status(0, "OK");
|
return Status(0, "OK");
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string inline attributeBufferToString(const void *data, UInt32 length) {
|
static std::string attributeBufferToString(const void *data, UInt32 length) {
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
uint8 *p = (uint8 *)data;
|
uint8 *p = (uint8 *)data;
|
||||||
while (length--) {
|
while (length--) {
|
||||||
@ -165,10 +167,10 @@ static std::string inline attributeBufferToString(const void *data, UInt32 lengt
|
|||||||
return stream.str();
|
return stream.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
Status inline genKeychainACLAppsForEntry(SecKeychainRef keychain,
|
Status genKeychainACLAppsForEntry(SecKeychainRef keychain,
|
||||||
SecKeychainItemRef item,
|
SecKeychainItemRef item,
|
||||||
const std::string &path,
|
const std::string &path,
|
||||||
QueryData &results) {
|
QueryData &results) {
|
||||||
KeychainItemMetadata item_metadata;
|
KeychainItemMetadata item_metadata;
|
||||||
item_metadata.keychain_path = path;
|
item_metadata.keychain_path = path;
|
||||||
|
|
||||||
@ -180,14 +182,16 @@ Status inline genKeychainACLAppsForEntry(SecKeychainRef keychain,
|
|||||||
OSStatus os_status;
|
OSStatus os_status;
|
||||||
Status s;
|
Status s;
|
||||||
os_status = SecKeychainItemCopyAccess(item, &access);
|
os_status = SecKeychainItemCopyAccess(item, &access);
|
||||||
if (os_status == errSecNoAccessForItem) {
|
if (os_status == errSecNoAccessForItem || access == nullptr) {
|
||||||
s = Status(1, "No ACLs for keychain item");
|
if (access != nullptr) {
|
||||||
|
CFRelease(access);
|
||||||
|
}
|
||||||
|
return Status(os_status, "No ACLs for keychain item");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<KeychainItemACL> acl;
|
std::vector<KeychainItemACL> acl;
|
||||||
s = parseKeychainItemACL(access, acl);
|
s = parseKeychainItemACL(access, acl);
|
||||||
if (access != nullptr) {
|
CFRelease(access);
|
||||||
CFRelease(access);
|
|
||||||
}
|
|
||||||
if (!s.ok()) {
|
if (!s.ok()) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@ -214,7 +218,7 @@ Status inline genKeychainACLAppsForEntry(SecKeychainRef keychain,
|
|||||||
SecKeychainAttributeList *attr_list = nullptr;
|
SecKeychainAttributeList *attr_list = nullptr;
|
||||||
os_status = SecKeychainItemCopyAttributesAndData(
|
os_status = SecKeychainItemCopyAttributesAndData(
|
||||||
item, info, &item_class, &attr_list, nullptr, nullptr);
|
item, info, &item_class, &attr_list, nullptr, nullptr);
|
||||||
if (os_status != noErr) {
|
if (os_status != noErr || attr_list == nullptr || info == nullptr) {
|
||||||
if (attr_list != nullptr) {
|
if (attr_list != nullptr) {
|
||||||
SecKeychainItemFreeAttributesAndData(attr_list, nullptr);
|
SecKeychainItemFreeAttributesAndData(attr_list, nullptr);
|
||||||
}
|
}
|
||||||
@ -225,21 +229,11 @@ Status inline genKeychainACLAppsForEntry(SecKeychainRef keychain,
|
|||||||
"Could not copy attributes and data from the keychain");
|
"Could not copy attributes and data from the keychain");
|
||||||
}
|
}
|
||||||
|
|
||||||
Status copy_attr_status = Status(0, "OK");
|
// Bail if the number of elements from the info/Attr list do not match.
|
||||||
if (info == nullptr || attr_list == nullptr) {
|
|
||||||
copy_attr_status = Status(1, "Could not get info or attr_list");
|
|
||||||
}
|
|
||||||
if (info->count != attr_list->count) {
|
if (info->count != attr_list->count) {
|
||||||
copy_attr_status = Status(1, "Info and attributes don't match");
|
SecKeychainItemFreeAttributesAndData(attr_list, nullptr);
|
||||||
}
|
SecKeychainFreeAttributeInfo(info);
|
||||||
if (!copy_attr_status.ok()) {
|
return Status(1, "Info and attributes do not match");
|
||||||
if (attr_list != nullptr) {
|
|
||||||
SecKeychainItemFreeAttributesAndData(attr_list, nullptr);
|
|
||||||
}
|
|
||||||
if (info != nullptr) {
|
|
||||||
SecKeychainFreeAttributeInfo(info);
|
|
||||||
}
|
|
||||||
return copy_attr_status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < info->count; ++i) {
|
for (int i = 0; i < info->count; ++i) {
|
||||||
@ -254,12 +248,10 @@ Status inline genKeychainACLAppsForEntry(SecKeychainRef keychain,
|
|||||||
attributeBufferToString(attribute->data, attribute->length);
|
attributeBufferToString(attribute->data, attribute->length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (attr_list != nullptr) {
|
|
||||||
SecKeychainItemFreeAttributesAndData(attr_list, nullptr);
|
// Finally, release/free the info/Attr lists.
|
||||||
}
|
SecKeychainItemFreeAttributesAndData(attr_list, nullptr);
|
||||||
if (info != nullptr) {
|
SecKeychainFreeAttributeInfo(info);
|
||||||
SecKeychainFreeAttributeInfo(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &acl_data : acl) {
|
for (const auto &acl_data : acl) {
|
||||||
for (const auto &app_path : acl_data.applications) {
|
for (const auto &app_path : acl_data.applications) {
|
||||||
@ -281,29 +273,24 @@ Status genKeychainACLApps(const std::string &path, QueryData &results) {
|
|||||||
OSStatus os_status = 0;
|
OSStatus os_status = 0;
|
||||||
|
|
||||||
os_status = SecKeychainOpen(path.c_str(), &keychain);
|
os_status = SecKeychainOpen(path.c_str(), &keychain);
|
||||||
if (os_status != noErr) {
|
if (os_status != noErr || keychain == nullptr) {
|
||||||
|
if (keychain != nullptr) {
|
||||||
|
CFRelease(keychain);
|
||||||
|
}
|
||||||
return Status(os_status, "Could not open the keychain at " + path);
|
return Status(os_status, "Could not open the keychain at " + path);
|
||||||
}
|
}
|
||||||
if (keychain == nullptr) {
|
|
||||||
return Status(1, "keychain object was not populated properly");
|
|
||||||
}
|
|
||||||
|
|
||||||
SecKeychainSearchRef search = nullptr;
|
SecKeychainSearchRef search = nullptr;
|
||||||
OSQUERY_USE_DEPRECATED(os_status = SecKeychainSearchCreateFromAttributes(
|
OSQUERY_USE_DEPRECATED(os_status = SecKeychainSearchCreateFromAttributes(
|
||||||
keychain, CSSM_DL_DB_RECORD_ANY, NULL, &search););
|
keychain, CSSM_DL_DB_RECORD_ANY, NULL, &search););
|
||||||
if (os_status != noErr) {
|
if (os_status != noErr || search == nullptr) {
|
||||||
if (keychain != nullptr) {
|
if (search != nullptr) {
|
||||||
CFRelease(keychain);
|
CFRelease(search);
|
||||||
}
|
}
|
||||||
|
CFRelease(keychain);
|
||||||
return Status(os_status,
|
return Status(os_status,
|
||||||
"Could not pull keychain items from the search API");
|
"Could not pull keychain items from the search API");
|
||||||
}
|
}
|
||||||
if (search == nullptr) {
|
|
||||||
if (keychain != nullptr) {
|
|
||||||
CFRelease(keychain);
|
|
||||||
}
|
|
||||||
return Status(1, "keychain search object was not populated properly");
|
|
||||||
}
|
|
||||||
|
|
||||||
SecKeychainItemRef item = nullptr;
|
SecKeychainItemRef item = nullptr;
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -320,19 +307,15 @@ Status genKeychainACLApps(const std::string &path, QueryData &results) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keychain != nullptr) {
|
CFRelease(keychain);
|
||||||
CFRelease(keychain);
|
CFRelease(search);
|
||||||
}
|
|
||||||
if (search != nullptr) {
|
|
||||||
CFRelease(search);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Status(0, "OK");
|
return Status(0, "OK");
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryData genKeychainACLApps(QueryContext &context) {
|
QueryData genKeychainACLApps(QueryContext &context) {
|
||||||
QueryData results;
|
QueryData results;
|
||||||
|
|
||||||
|
SecKeychainSetUserInteractionAllowed(false);
|
||||||
for (const auto &path : getKeychainPaths()) {
|
for (const auto &path : getKeychainPaths()) {
|
||||||
std::vector<std::string> ls_results;
|
std::vector<std::string> ls_results;
|
||||||
auto list_status = listFilesInDirectory(path, ls_results, false);
|
auto list_status = listFilesInDirectory(path, ls_results, false);
|
||||||
@ -344,11 +327,12 @@ QueryData genKeychainACLApps(QueryContext &context) {
|
|||||||
TLOG << "Checking directory: " << keychain;
|
TLOG << "Checking directory: " << keychain;
|
||||||
auto gen_status = genKeychainACLApps(keychain, results);
|
auto gen_status = genKeychainACLApps(keychain, results);
|
||||||
if (!gen_status.ok()) {
|
if (!gen_status.ok()) {
|
||||||
TLOG << "Could not list keychain from " << keychain << ": "
|
TLOG << "Could not list items from " << keychain << ": "
|
||||||
<< gen_status.toString();
|
<< gen_status.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SecKeychainSetUserInteractionAllowed(true);
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
12
specs/darwin/app_schemes.table
Normal file
12
specs/darwin/app_schemes.table
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
table_name("app_schemes")
|
||||||
|
description("OS X application schemes and handlers (e.g., http, file, mailto.")
|
||||||
|
schema([
|
||||||
|
Column("scheme", TEXT, "Name of the scheme/protocol"),
|
||||||
|
Column("handler", TEXT, "Application label for the handler"),
|
||||||
|
Column("enabled", INTEGER, "1 if this handler is the OS default, else 0"),
|
||||||
|
Column("external", INTEGER,
|
||||||
|
"1 if this handler does NOT exist on OS X by default, else 0"),
|
||||||
|
Column("protected", INTEGER,
|
||||||
|
"1 if this handler is protected (reserved) by OS X, else 0"),
|
||||||
|
])
|
||||||
|
implementation("apps@genAppSchemes")
|
@ -5,7 +5,7 @@ schema([
|
|||||||
Column("package_filename", TEXT, "Filename of original .pkg file"),
|
Column("package_filename", TEXT, "Filename of original .pkg file"),
|
||||||
Column("version", TEXT, "Installed package version"),
|
Column("version", TEXT, "Installed package version"),
|
||||||
Column("location", TEXT, "Optional relative install path on volume"),
|
Column("location", TEXT, "Optional relative install path on volume"),
|
||||||
Column("install_time", INTEGER, "Timestamp of install time"),
|
Column("install_time", DOUBLE, "Timestamp of install time"),
|
||||||
Column("installer_name", TEXT, "Name of installer process"),
|
Column("installer_name", TEXT, "Name of installer process"),
|
||||||
Column("path", TEXT, "Path of receipt plist",
|
Column("path", TEXT, "Path of receipt plist",
|
||||||
index=True, additional=True),
|
index=True, additional=True),
|
||||||
|
@ -53,6 +53,7 @@ DATETIME = DataType("TEXT")
|
|||||||
INTEGER = DataType("INTEGER", "int")
|
INTEGER = DataType("INTEGER", "int")
|
||||||
BIGINT = DataType("BIGINT", "long long int")
|
BIGINT = DataType("BIGINT", "long long int")
|
||||||
UNSIGNED_BIGINT = DataType("UNSIGNED_BIGINT", "long long unsigned int")
|
UNSIGNED_BIGINT = DataType("UNSIGNED_BIGINT", "long long unsigned int")
|
||||||
|
DOUBLE = DataType("DOUBLE", "double")
|
||||||
|
|
||||||
# Define table-category MACROS from the table specs
|
# Define table-category MACROS from the table specs
|
||||||
UNKNOWN = "UNKNOWN"
|
UNKNOWN = "UNKNOWN"
|
||||||
|
Loading…
Reference in New Issue
Block a user