]> git.saurik.com Git - apple/security.git/blob - OSX/authd/mechanism.c
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / authd / mechanism.c
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
16 static const char SystemPlugins[] = "/System/Library/CoreServices/SecurityAgentPlugins";
17 static const char LibraryPlugins[] = "/Library/Security/SecurityAgentPlugins";
18 static const char BuiltinMechanismPrefix[] = "builtin";
19
20 typedef struct _mechTypeItem
21 {
22 const char * name;
23 uint64_t type;
24 } mechTypeItem;
25
26 static mechTypeItem mechTypeMap[] =
27 {
28 { "entitled", kMechanismTypeEntitled }
29 };
30
31 struct _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
42 static void
43 _mechanism_finalize(CFTypeRef value)
44 {
45 mechanism_t mech = (mechanism_t)value;
46
47 CFReleaseNull(mech->data);
48 free_safe(mech->string);
49 }
50
51 static 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
72 static CFStringRef
73 _mechanism_copy_description(CFTypeRef value)
74 {
75 mechanism_t mech = (mechanism_t)value;
76 return CFCopyDescription(mech->data);
77 }
78
79 static 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 (CFHashCode)crc;
94 }
95
96 AUTH_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
106 static 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
117 static 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
125 done:
126 return mech;
127 }
128
129 static 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
144 mechanism_t
145 mechanism_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
158 done:
159 return mech;
160 }
161
162 mechanism_t
163 mechanism_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
197 done:
198 return mech;
199 }
200
201 static
202 bool _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
220 done:
221 return result;
222 }
223
224 bool
225 mechanism_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
254 bool
255 mechanism_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
272 bool
273 mechanism_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
286 const char *
287 mechanism_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
296 int64_t
297 mechanism_get_id(mechanism_t mech)
298 {
299 return auth_items_get_int64(mech->data, MECHANISM_ID);
300 }
301
302 const char *
303 mechanism_get_plugin(mechanism_t mech)
304 {
305 return auth_items_get_string(mech->data, MECHANISM_PLUGIN);
306 }
307
308 const char *
309 mechanism_get_param(mechanism_t mech)
310 {
311 return auth_items_get_string(mech->data, MECHANISM_PARAM);
312 }
313
314 bool
315 mechanism_is_privileged(mechanism_t mech)
316 {
317 return auth_items_get_int64(mech->data, MECHANISM_PRIVILEGED);
318 }
319
320 uint64_t
321 mechanism_get_type(mechanism_t mech)
322 {
323 return mech->type;
324 }