X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/c38e3ce98599a410a47dc10253faa4d5830f13b2..427c49bcad63d042b29ada2ac27e3dfc4845c779:/authd/mechanism.c?ds=inline diff --git a/authd/mechanism.c b/authd/mechanism.c new file mode 100644 index 00000000..e57c8200 --- /dev/null +++ b/authd/mechanism.c @@ -0,0 +1,324 @@ +/* Copyright (c) 2012 Apple Inc. All rights reserved. */ + +#include "mechanism.h" +#include "authdb.h" +#include "authutilities.h" +#include "crc.h" +#include "debugging.h" +#include "server.h" +#include "authitems.h" + +#define MECHANISM_ID "id" +#define MECHANISM_PLUGIN "plugin" +#define MECHANISM_PARAM "param" +#define MECHANISM_PRIVILEGED "privileged" + +static const char SystemPlugins[] = "/System/Library/CoreServices/SecurityAgentPlugins"; +static const char LibraryPlugins[] = "/Library/Security/SecurityAgentPlugins"; +static const char BuiltinMechanismPrefix[] = "builtin"; + +typedef struct _mechTypeItem +{ + const char * name; + uint64_t type; +} mechTypeItem; + +static mechTypeItem mechTypeMap[] = +{ + { "entitled", kMechanismTypeEntitled } +}; + +struct _mechanism_s { + __AUTH_BASE_STRUCT_HEADER__; + + auth_items_t data; + + bool valid; + char * string; + + uint64_t type; +}; + +static void +_mechanism_finalize(CFTypeRef value) +{ + mechanism_t mech = (mechanism_t)value; + + CFReleaseSafe(mech->data); + free_safe(mech->string); +} + +static Boolean +_mechanism_equal(CFTypeRef value1, CFTypeRef value2) +{ + mechanism_t mech1 = (mechanism_t)value1; + mechanism_t mech2 = (mechanism_t)value2; + + if (mech1 == mech2) { + return true; + } + + if (!_compare_string(mechanism_get_plugin(mech1), mechanism_get_plugin(mech2))) { + return false; + } + + if (!_compare_string(mechanism_get_param(mech1), mechanism_get_param(mech2))) { + return false; + } + + return mechanism_is_privileged(mech1) == mechanism_is_privileged(mech2); +} + +static CFStringRef +_mechanism_copy_description(CFTypeRef value) +{ + mechanism_t mech = (mechanism_t)value; + return CFCopyDescription(mech->data); +} + +static CFHashCode +_mechanism_hash(CFTypeRef value) +{ + uint64_t crc = crc64_init(); + mechanism_t mech = (mechanism_t)value; + + const char * str = mechanism_get_plugin(mech); + crc = crc64_update(crc, str, strlen(str)); + str = mechanism_get_plugin(mech); + crc = crc64_update(crc, str, strlen(str)); + bool priv = mechanism_is_privileged(mech); + crc = crc64_update(crc, &priv, sizeof(priv)); + crc = crc64_final(crc); + + return crc; +} + +AUTH_TYPE_INSTANCE(mechanism, + .init = NULL, + .copy = NULL, + .finalize = _mechanism_finalize, + .equal = _mechanism_equal, + .hash = _mechanism_hash, + .copyFormattingDesc = NULL, + .copyDebugDesc = _mechanism_copy_description + ); + +static CFTypeID mechanism_get_type_id() { + static CFTypeID type_id = _kCFRuntimeNotATypeID; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + type_id = _CFRuntimeRegisterClass(&_auth_type_mechanism); + }); + + return type_id; +} + +static mechanism_t +_mechanism_create() +{ + mechanism_t mech = (mechanism_t)_CFRuntimeCreateInstance(kCFAllocatorDefault, mechanism_get_type_id(), AUTH_CLASS_SIZE(mechanism), NULL); + require(mech != NULL, done); + + mech->data = auth_items_create(); + +done: + return mech; +} + +static void _mechanism_set_type(mechanism_t mech) +{ + const char * plugin = mechanism_get_plugin(mech); + const char * param = mechanism_get_param(mech); + if (strncasecmp(plugin, BuiltinMechanismPrefix, sizeof(BuiltinMechanismPrefix)) == 0) { + size_t n = sizeof(mechTypeMap)/sizeof(mechTypeItem); + for (size_t i = 0; i < n; i++) { + if (strcasecmp(mechTypeMap[i].name, param) == 0) { + mech->type = mechTypeMap[i].type; + break; + } + } + } +} + +mechanism_t +mechanism_create_with_sql(auth_items_t sql) +{ + mechanism_t mech = NULL; + require(sql != NULL, done); + require(auth_items_get_int64(sql, MECHANISM_ID) != 0, done); + + mech = _mechanism_create(); + require(mech != NULL, done); + + auth_items_copy(mech->data, sql); + + _mechanism_set_type(mech); + +done: + return mech; +} + +mechanism_t +mechanism_create_with_string(const char * str, authdb_connection_t dbconn) +{ + mechanism_t mech = NULL; + require(str != NULL, done); + require(strchr(str,':') != NULL, done); + + mech = _mechanism_create(); + require(mech != NULL, done); + + const char delimiters[] = ":,"; + size_t buf_len = strlen(str)+1; + char * buf = (char*)calloc(1u, buf_len); + strlcpy(buf, str, buf_len); + + char * tok = strtok(buf, delimiters); + if (tok) { + auth_items_set_string(mech->data, MECHANISM_PLUGIN, tok); + } + tok = strtok(NULL, delimiters); + if (tok) { + auth_items_set_string(mech->data, MECHANISM_PARAM, tok); + } + tok = strtok(NULL, delimiters); + if (tok) { + auth_items_set_int64(mech->data, MECHANISM_PRIVILEGED, strcasecmp("privileged", tok) == 0); + } + free(buf); + + if (dbconn) { + mechanism_sql_fetch(mech, dbconn); + } + + _mechanism_set_type(mech); + +done: + return mech; +} + +static +bool _pluginExists(const char * plugin, const char * base) +{ + bool result = false; + + require(plugin != NULL, done); + require(base != NULL, done); + + char filePath[PATH_MAX]; + char realPath[PATH_MAX+1]; + snprintf(filePath, sizeof(filePath), "%s/%s.bundle", base, plugin); + + require(realpath(filePath, realPath) != NULL, done); + require(strncmp(realPath, base, strlen(base)) == 0, done); + + if (access(filePath, F_OK) == 0) { + result = true; + } + +done: + return result; +} + +bool +mechanism_exists(mechanism_t mech) +{ + if (mech->valid) { + return true; + } + + const char * plugin = mechanism_get_plugin(mech); + if (plugin == NULL) { + return false; + } + + if (strncasecmp(plugin, BuiltinMechanismPrefix, sizeof(BuiltinMechanismPrefix)) == 0) { + mech->valid = true; + return true; + } + + if (_pluginExists(plugin, SystemPlugins)) { + mech->valid = true; + return true; + } + + if (_pluginExists(plugin,LibraryPlugins)) { + mech->valid = true; + return true; + } + + return false; +} + +bool +mechanism_sql_fetch(mechanism_t mech, authdb_connection_t dbconn) +{ + __block bool result = false; + + authdb_step(dbconn, "SELECT id FROM mechanisms WHERE plugin = ? AND param = ? AND privileged = ? LIMIT 1", ^(sqlite3_stmt * stmt) { + sqlite3_bind_text(stmt, 1, mechanism_get_plugin(mech), -1, NULL); + sqlite3_bind_text(stmt, 2, mechanism_get_param(mech), -1, NULL); + sqlite3_bind_int(stmt, 3, mechanism_is_privileged(mech)); + }, ^bool(auth_items_t data) { + result = true; + auth_items_copy(mech->data, data); + return true; + }); + + return result; +} + +bool +mechanism_sql_commit(mechanism_t mech, authdb_connection_t dbconn) +{ + bool result = false; + + result = authdb_step(dbconn, "INSERT INTO mechanisms VALUES (NULL,?,?,?)", ^(sqlite3_stmt *stmt) { + sqlite3_bind_text(stmt, 1, mechanism_get_plugin(mech), -1, NULL); + sqlite3_bind_text(stmt, 2, mechanism_get_param(mech), -1, NULL); + sqlite3_bind_int(stmt, 3, mechanism_is_privileged(mech)); + }, NULL); + + return result; +} + +const char * +mechanism_get_string(mechanism_t mech) +{ + if (!mech->string) { + asprintf(&mech->string, "%s:%s%s", mechanism_get_plugin(mech), mechanism_get_param(mech), mechanism_is_privileged(mech) ? ",privileged" : ""); + } + + return mech->string; +} + +int64_t +mechanism_get_id(mechanism_t mech) +{ + return auth_items_get_int64(mech->data, MECHANISM_ID); +} + +const char * +mechanism_get_plugin(mechanism_t mech) +{ + return auth_items_get_string(mech->data, MECHANISM_PLUGIN); +} + +const char * +mechanism_get_param(mechanism_t mech) +{ + return auth_items_get_string(mech->data, MECHANISM_PARAM); +} + +bool +mechanism_is_privileged(mechanism_t mech) +{ + return auth_items_get_int64(mech->data, MECHANISM_PRIVILEGED); +} + +uint64_t +mechanism_get_type(mechanism_t mech) +{ + return mech->type; +}