1/* Copyright (c) 2012 Apple Inc. All rights reserved. */ 2 3#include "mechanism.h" 4#include "authdb.h" 5#include "authutilities.h" 6#include "crc.h" 7#include "debugging.h" 8#include "server.h" 9#include "authitems.h" 10 11#define MECHANISM_ID "id" 12#define MECHANISM_PLUGIN "plugin" 13#define MECHANISM_PARAM "param" 14#define MECHANISM_PRIVILEGED "privileged" 15 16static const char SystemPlugins[] = "/System/Library/CoreServices/SecurityAgentPlugins"; 17static const char LibraryPlugins[] = "/Library/Security/SecurityAgentPlugins"; 18static const char BuiltinMechanismPrefix[] = "builtin"; 19 20typedef struct _mechTypeItem 21{ 22 const char * name; 23 uint64_t type; 24} mechTypeItem; 25 26static mechTypeItem mechTypeMap[] = 27{ 28 { "entitled", kMechanismTypeEntitled } 29}; 30 31struct _mechanism_s { 32 __AUTH_BASE_STRUCT_HEADER__; 33 34 auth_items_t data; 35 36 bool valid; 37 char * string; 38 39 uint64_t type; 40}; 41 42static void 43_mechanism_finalize(CFTypeRef value) 44{ 45 mechanism_t mech = (mechanism_t)value; 46 47 CFReleaseSafe(mech->data); 48 free_safe(mech->string); 49} 50 51static Boolean 52_mechanism_equal(CFTypeRef value1, CFTypeRef value2) 53{ 54 mechanism_t mech1 = (mechanism_t)value1; 55 mechanism_t mech2 = (mechanism_t)value2; 56 57 if (mech1 == mech2) { 58 return true; 59 } 60 61 if (!_compare_string(mechanism_get_plugin(mech1), mechanism_get_plugin(mech2))) { 62 return false; 63 } 64 65 if (!_compare_string(mechanism_get_param(mech1), mechanism_get_param(mech2))) { 66 return false; 67 } 68 69 return mechanism_is_privileged(mech1) == mechanism_is_privileged(mech2); 70} 71 72static CFStringRef 73_mechanism_copy_description(CFTypeRef value) 74{ 75 mechanism_t mech = (mechanism_t)value; 76 return CFCopyDescription(mech->data); 77} 78 79static CFHashCode 80_mechanism_hash(CFTypeRef value) 81{ 82 uint64_t crc = crc64_init(); 83 mechanism_t mech = (mechanism_t)value; 84 85 const char * str = mechanism_get_plugin(mech); 86 crc = crc64_update(crc, str, strlen(str)); 87 str = mechanism_get_plugin(mech); 88 crc = crc64_update(crc, str, strlen(str)); 89 bool priv = mechanism_is_privileged(mech); 90 crc = crc64_update(crc, &priv, sizeof(priv)); 91 crc = crc64_final(crc); 92 93 return crc; 94} 95 96AUTH_TYPE_INSTANCE(mechanism, 97 .init = NULL, 98 .copy = NULL, 99 .finalize = _mechanism_finalize, 100 .equal = _mechanism_equal, 101 .hash = _mechanism_hash, 102 .copyFormattingDesc = NULL, 103 .copyDebugDesc = _mechanism_copy_description 104 ); 105 106static CFTypeID mechanism_get_type_id() { 107 static CFTypeID type_id = _kCFRuntimeNotATypeID; 108 static dispatch_once_t onceToken; 109 110 dispatch_once(&onceToken, ^{ 111 type_id = _CFRuntimeRegisterClass(&_auth_type_mechanism); 112 }); 113 114 return type_id; 115} 116 117static mechanism_t 118_mechanism_create() 119{ 120 mechanism_t mech = (mechanism_t)_CFRuntimeCreateInstance(kCFAllocatorDefault, mechanism_get_type_id(), AUTH_CLASS_SIZE(mechanism), NULL); 121 require(mech != NULL, done); 122 123 mech->data = auth_items_create(); 124 125done: 126 return mech; 127} 128 129static void _mechanism_set_type(mechanism_t mech) 130{ 131 const char * plugin = mechanism_get_plugin(mech); 132 const char * param = mechanism_get_param(mech); 133 if (strncasecmp(plugin, BuiltinMechanismPrefix, sizeof(BuiltinMechanismPrefix)) == 0) { 134 size_t n = sizeof(mechTypeMap)/sizeof(mechTypeItem); 135 for (size_t i = 0; i < n; i++) { 136 if (strcasecmp(mechTypeMap[i].name, param) == 0) { 137 mech->type = mechTypeMap[i].type; 138 break; 139 } 140 } 141 } 142} 143 144mechanism_t 145mechanism_create_with_sql(auth_items_t sql) 146{ 147 mechanism_t mech = NULL; 148 require(sql != NULL, done); 149 require(auth_items_get_int64(sql, MECHANISM_ID) != 0, done); 150 151 mech = _mechanism_create(); 152 require(mech != NULL, done); 153 154 auth_items_copy(mech->data, sql); 155 156 _mechanism_set_type(mech); 157 158done: 159 return mech; 160} 161 162mechanism_t 163mechanism_create_with_string(const char * str, authdb_connection_t dbconn) 164{ 165 mechanism_t mech = NULL; 166 require(str != NULL, done); 167 require(strchr(str,':') != NULL, done); 168 169 mech = _mechanism_create(); 170 require(mech != NULL, done); 171 172 const char delimiters[] = ":,"; 173 size_t buf_len = strlen(str)+1; 174 char * buf = (char*)calloc(1u, buf_len); 175 strlcpy(buf, str, buf_len); 176 177 char * tok = strtok(buf, delimiters); 178 if (tok) { 179 auth_items_set_string(mech->data, MECHANISM_PLUGIN, tok); 180 } 181 tok = strtok(NULL, delimiters); 182 if (tok) { 183 auth_items_set_string(mech->data, MECHANISM_PARAM, tok); 184 } 185 tok = strtok(NULL, delimiters); 186 if (tok) { 187 auth_items_set_int64(mech->data, MECHANISM_PRIVILEGED, strcasecmp("privileged", tok) == 0); 188 } 189 free(buf); 190 191 if (dbconn) { 192 mechanism_sql_fetch(mech, dbconn); 193 } 194 195 _mechanism_set_type(mech); 196 197done: 198 return mech; 199} 200 201static 202bool _pluginExists(const char * plugin, const char * base) 203{ 204 bool result = false; 205 206 require(plugin != NULL, done); 207 require(base != NULL, done); 208 209 char filePath[PATH_MAX]; 210 char realPath[PATH_MAX+1]; 211 snprintf(filePath, sizeof(filePath), "%s/%s.bundle", base, plugin); 212 213 require(realpath(filePath, realPath) != NULL, done); 214 require(strncmp(realPath, base, strlen(base)) == 0, done); 215 216 if (access(filePath, F_OK) == 0) { 217 result = true; 218 } 219 220done: 221 return result; 222} 223 224bool 225mechanism_exists(mechanism_t mech) 226{ 227 if (mech->valid) { 228 return true; 229 } 230 231 const char * plugin = mechanism_get_plugin(mech); 232 if (plugin == NULL) { 233 return false; 234 } 235 236 if (strncasecmp(plugin, BuiltinMechanismPrefix, sizeof(BuiltinMechanismPrefix)) == 0) { 237 mech->valid = true; 238 return true; 239 } 240 241 if (_pluginExists(plugin, SystemPlugins)) { 242 mech->valid = true; 243 return true; 244 } 245 246 if (_pluginExists(plugin,LibraryPlugins)) { 247 mech->valid = true; 248 return true; 249 } 250 251 return false; 252} 253 254bool 255mechanism_sql_fetch(mechanism_t mech, authdb_connection_t dbconn) 256{ 257 __block bool result = false; 258 259 authdb_step(dbconn, "SELECT id FROM mechanisms WHERE plugin = ? AND param = ? AND privileged = ? LIMIT 1", ^(sqlite3_stmt * stmt) { 260 sqlite3_bind_text(stmt, 1, mechanism_get_plugin(mech), -1, NULL); 261 sqlite3_bind_text(stmt, 2, mechanism_get_param(mech), -1, NULL); 262 sqlite3_bind_int(stmt, 3, mechanism_is_privileged(mech)); 263 }, ^bool(auth_items_t data) { 264 result = true; 265 auth_items_copy(mech->data, data); 266 return true; 267 }); 268 269 return result; 270} 271 272bool 273mechanism_sql_commit(mechanism_t mech, authdb_connection_t dbconn) 274{ 275 bool result = false; 276 277 result = authdb_step(dbconn, "INSERT INTO mechanisms VALUES (NULL,?,?,?)", ^(sqlite3_stmt *stmt) { 278 sqlite3_bind_text(stmt, 1, mechanism_get_plugin(mech), -1, NULL); 279 sqlite3_bind_text(stmt, 2, mechanism_get_param(mech), -1, NULL); 280 sqlite3_bind_int(stmt, 3, mechanism_is_privileged(mech)); 281 }, NULL); 282 283 return result; 284} 285 286const char * 287mechanism_get_string(mechanism_t mech) 288{ 289 if (!mech->string) { 290 asprintf(&mech->string, "%s:%s%s", mechanism_get_plugin(mech), mechanism_get_param(mech), mechanism_is_privileged(mech) ? ",privileged" : ""); 291 } 292 293 return mech->string; 294} 295 296int64_t 297mechanism_get_id(mechanism_t mech) 298{ 299 return auth_items_get_int64(mech->data, MECHANISM_ID); 300} 301 302const char * 303mechanism_get_plugin(mechanism_t mech) 304{ 305 return auth_items_get_string(mech->data, MECHANISM_PLUGIN); 306} 307 308const char * 309mechanism_get_param(mechanism_t mech) 310{ 311 return auth_items_get_string(mech->data, MECHANISM_PARAM); 312} 313 314bool 315mechanism_is_privileged(mechanism_t mech) 316{ 317 return auth_items_get_int64(mech->data, MECHANISM_PRIVILEGED); 318} 319 320uint64_t 321mechanism_get_type(mechanism_t mech) 322{ 323 return mech->type; 324} 325