Security-55179.13.tar.gz
[apple/security.git] / sec / ipc / server.c
1 /*
2 * Copyright (c) 2007-2009 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <mach/mach.h>
25 #include <mach/message.h>
26 #include <servers/bootstrap.h>
27
28 #include <stdlib.h>
29 #include <sys/queue.h>
30
31 #include <Security/SecInternal.h>
32 #include <Security/SecBasePriv.h>
33 #include <Security/SecItemPriv.h> /* For SecItemDeleteAll */
34 #include <CoreFoundation/CoreFoundation.h>
35
36 #include <asl.h>
37 #include <bsm/libbsm.h>
38 #include <security_utilities/debugging.h>
39 #include <sys/sysctl.h>
40
41 #include "securityd_client.h"
42 #include "securityd_rep.h"
43 #include "securityd_server.h"
44
45 #include <securityd/spi.h>
46
47 #ifndef SECITEM_SHIM_OSX
48 #include <Security/SecTask.h>
49 #include <Security/SecEntitlements.h>
50 #endif
51
52 #if INDIGO || SECITEM_SHIM_OSX
53 #define CHECK_ENTITLEMENTS 0
54 #else
55 #define CHECK_ENTITLEMENTS 1
56 #endif
57
58 /* Time after which securityd exits. */
59 #if NDEBUG
60 #define TIMEOUT_IN_SECONDS 10.0
61 #else
62 #define TIMEOUT_IN_SECONDS 10000.0
63 #endif
64
65 #if SECITEM_SHIM_OSX
66 /* defines from <Security/SecTask.h> */
67 typedef struct __SecTask *SecTaskRef;
68 /* defines from <Security/SecEntitlements.h> */
69 #define kSecEntitlementGetTaskAllow CFSTR("get-task-allow")
70 #define kSecEntitlementApplicationIdentifier CFSTR("application-identifier")
71 #define kSecEntitlementKeychainAccessGroups CFSTR("keychain-access-groups")
72 #define kSecEntitlementModifyAnchorCertificates CFSTR("modify-anchor-certificates")
73 #define kSecEntitlementDebugApplications CFSTR("com.apple.springboard.debugapplications")
74 #define kSecEntitlementOpenSensitiveURL CFSTR("com.apple.springboard.opensensitiveurl")
75 #define kSecEntitlementWipeDevice CFSTR("com.apple.springboard.wipedevice")
76 #define kSecEntitlementRemoteNotificationConfigure CFSTR("com.apple.remotenotification.configure")
77 #define kSecEntitlementMigrateKeychain CFSTR("migrate-keychain")
78 #define kSecEntitlementRestoreKeychain CFSTR("restore-keychain")
79
80 #endif
81
82 static mach_port_t _server_port = MACH_PORT_NULL;
83 static unsigned int active_requests = 0;
84 static CFRunLoopTimerRef idle_timer = NULL;
85
86 static mach_port_t server_port(void *info)
87 {
88 if (!_server_port) {
89 kern_return_t ret;
90
91 ret = bootstrap_check_in(bootstrap_port, SECURITYSERVER_BOOTSTRAP_NAME, &_server_port);
92 if (ret == KERN_SUCCESS) {
93 secdebug("server", "bootstrap_check_in() succeeded, return checked in port: 0x%x\n", _server_port);
94 return _server_port;
95 }
96
97 #if 0
98 ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &_server_port);
99 if (ret != KERN_SUCCESS) {
100 secdebug("server", "mach_port_allocate(): 0x%x: %s\n", ret, mach_error_string(ret));
101 exit(2);
102 }
103
104 ret = mach_port_insert_right(mach_task_self(), _server_port, _server_port, MACH_MSG_TYPE_MAKE_SEND);
105 if (ret != KERN_SUCCESS) {
106 secdebug("server", "mach_port_insert_right(): 0x%x: %s\n", ret, mach_error_string(ret));
107 exit(3);
108 }
109
110 ret = bootstrap_register(bootstrap_port, SECURITYSERVER_BOOTSTRAP_NAME, _server_port);
111 if (ret != BOOTSTRAP_SUCCESS) {
112 secdebug("server", "bootstrap_register(): 0x%x: %s\n", ret, mach_error_string(ret));
113 exit(4);
114 }
115 #else
116 exit(1);
117 #endif
118
119 }
120
121 return _server_port;
122 }
123
124 #if CHECK_ENTITLEMENTS
125 static CFStringRef SecTaskCopyStringForEntitlement(SecTaskRef task,
126 CFStringRef entitlement)
127 {
128 CFStringRef value = (CFStringRef)SecTaskCopyValueForEntitlement(task,
129 entitlement, NULL);
130 if (value && CFGetTypeID(value) != CFStringGetTypeID()) {
131 CFRelease(value);
132 value = NULL;
133 }
134
135 return value;
136 }
137
138 static CFArrayRef SecTaskCopyArrayOfStringsForEntitlement(SecTaskRef task,
139 CFStringRef entitlement)
140 {
141 CFArrayRef value = (CFArrayRef)SecTaskCopyValueForEntitlement(task,
142 entitlement, NULL);
143 if (value) {
144 if (CFGetTypeID(value) == CFArrayGetTypeID()) {
145 CFIndex ix, count = CFArrayGetCount(value);
146 for (ix = 0; ix < count; ++ix) {
147 CFStringRef string = (CFStringRef)CFArrayGetValueAtIndex(value, ix);
148 if (CFGetTypeID(string) != CFStringGetTypeID()) {
149 CFRelease(value);
150 value = NULL;
151 break;
152 }
153 }
154 } else {
155 CFRelease(value);
156 value = NULL;
157 }
158 }
159
160 return value;
161 }
162 #endif /* CHECK_ENTITLEMENTS */
163
164 static CFArrayRef SecTaskCopyAccessGroups(SecTaskRef task) {
165 #if CHECK_ENTITLEMENTS
166 CFStringRef appID = SecTaskCopyStringForEntitlement(task,
167 kSecEntitlementApplicationIdentifier);
168 CFArrayRef groups = SecTaskCopyArrayOfStringsForEntitlement(task,
169 kSecEntitlementKeychainAccessGroups);
170 if (appID) {
171 if (groups) {
172 CFMutableArrayRef nGroups = CFArrayCreateMutableCopy(
173 CFGetAllocator(groups), CFArrayGetCount(groups) + 1, groups);
174 CFArrayAppendValue(nGroups, appID);
175 CFRelease(groups);
176 groups = nGroups;
177 } else {
178 groups = CFArrayCreate(CFGetAllocator(task),
179 (const void **)&appID, 1, &kCFTypeArrayCallBacks);
180 }
181 CFRelease(appID);
182 }
183 #else
184 CFArrayRef groups = SecAccessGroupsGetCurrent();
185 if (groups)
186 CFRetain(groups);
187 #endif
188 return groups;
189 }
190
191 static bool SecTaskGetBooleanValueForEntitlement(SecTaskRef task,
192 CFStringRef entitlement) {
193 #if CHECK_ENTITLEMENTS
194 CFStringRef canModify = (CFStringRef)SecTaskCopyValueForEntitlement(task,
195 entitlement, NULL);
196 if (!canModify)
197 return false;
198 CFTypeID canModifyType = CFGetTypeID(canModify);
199 if (CFBooleanGetTypeID() == canModifyType) {
200 return CFBooleanGetValue((CFBooleanRef)canModify);
201 } else
202 return false;
203 #else
204 return true;
205 #endif /* !CHECK_ENTITLEMENTS */
206 }
207
208 #if 0
209 static CFDataRef CFArrayGetCheckedDataAtIndex() {
210 }
211 #endif
212
213 static bool isDictionary(CFTypeRef cfType) {
214 return cfType && CFGetTypeID(cfType) == CFDictionaryGetTypeID();
215 }
216
217 static bool isData(CFTypeRef cfType) {
218 return cfType && CFGetTypeID(cfType) == CFDataGetTypeID();
219 }
220
221 static bool isString(CFTypeRef cfType) {
222 return cfType && CFGetTypeID(cfType) == CFStringGetTypeID();
223 }
224
225 static bool isArray(CFTypeRef cfType) {
226 return cfType && CFGetTypeID(cfType) == CFArrayGetTypeID();
227 }
228
229 static bool isArrayOfLength(CFTypeRef cfType, CFIndex length) {
230 return isArray(cfType) && CFArrayGetCount(cfType) == length;
231 }
232
233 static void idle_timer_proc(CFRunLoopTimerRef timer, void *info)
234 {
235 if (active_requests == 0) {
236 /* If the idle timer fired and we have no active requests we exit. */
237 exit(0);
238 }
239 }
240
241 static void cancel_timeout()
242 {
243 if (idle_timer) {
244 CFRunLoopTimerInvalidate(idle_timer);
245 CFRelease(idle_timer);
246 idle_timer = NULL;
247 }
248 }
249
250 static void register_timeout(void)
251 {
252 if (idle_timer == NULL) {
253 idle_timer = CFRunLoopTimerCreate(kCFAllocatorDefault,
254 CFAbsoluteTimeGetCurrent() + TIMEOUT_IN_SECONDS,
255 TIMEOUT_IN_SECONDS, 0, 0, idle_timer_proc, NULL);
256 if (idle_timer == NULL) {
257 asl_log(NULL, NULL, ASL_LEVEL_CRIT,
258 "FATAL: failed to create idle timer, exiting.");
259 exit(1);
260 }
261 CFRunLoopAddTimer(CFRunLoopGetCurrent(), idle_timer,
262 kCFRunLoopDefaultMode);
263 }
264 }
265
266 static void request_begin(void)
267 {
268 if (active_requests++ == 0) {
269 /* First request, cancel timer. */
270 cancel_timeout();
271 }
272 }
273
274 static void request_end(void)
275 {
276 if (--active_requests == 0) {
277 /* Last request, set timer. */
278 register_timeout();
279 }
280 }
281
282 /* AUDIT[securityd](done):
283 reply (checked by mig) is a caller provided mach_port.
284 request_id (checked by mig) is caller provided value, that matches the
285 mig entry for the server function.
286 */
287 kern_return_t securityd_server_send_reply(mach_port_t reply,
288 uint32_t request_id, OSStatus status, CFTypeRef args_out) {
289 CFDataRef data_out = NULL;
290 if (args_out) {
291 #ifndef NDEBUG
292 CFDataRef query_debug = CFPropertyListCreateXMLData(kCFAllocatorDefault,
293 args_out);
294 secdebug("client", "securityd response: %.*s\n",
295 CFDataGetLength(query_debug), CFDataGetBytePtr(query_debug));
296 CFReleaseSafe(query_debug);
297 #endif
298 CFErrorRef error = NULL;
299 data_out = CFPropertyListCreateData(kCFAllocatorDefault, args_out,
300 kCFPropertyListBinaryFormat_v1_0,
301 0, &error);
302 CFRelease(args_out);
303 if (error) {
304 secdebug("server", "failed to encode return data: %@", error);
305 CFReleaseSafe(error);
306 }
307 }
308
309 void *p = (data_out ? (void *)CFDataGetBytePtr(data_out) : NULL);
310 CFIndex l = (data_out ? CFDataGetLength(data_out) : 0);
311 /* 64 bits cast: securityd should never generate replies bigger than 2^32 bytes.
312 Worst case is we are truncating the reply we send to the client. This would only
313 cause the client side to not be able to decode the response. */
314 assert((unsigned long)l<UINT_MAX); /* Debug check */
315 kern_return_t err = securityd_client_reply(reply, request_id, status,
316 p, (unsigned int)l);
317
318 CFReleaseSafe(data_out);
319
320 request_end();
321
322 return err;
323 }
324
325 struct securityd_server_trust_evaluation_context {
326 mach_port_t reply;
327 uint32_t request_id;
328 };
329
330 static void
331 securityd_server_trust_evaluate_done(const void *userData,
332 SecCertificatePathRef chain, CFArrayRef details, CFDictionaryRef info,
333 SecTrustResultType result) {
334 struct securityd_server_trust_evaluation_context *tec =
335 (struct securityd_server_trust_evaluation_context *)userData;
336
337 /* @@@ This code snippit is also in SecTrustServer.c. I'd factor it,
338 but a better fix would be to change the interfaces here to not use
339 single in/out args and do all the argument munging in server.c
340 and client.c. */
341 CFDictionaryRef args_out;
342 CFNumberRef resultNumber = NULL;
343 CFArrayRef chain_certs = NULL;
344 /* Proccess outgoing results. */
345 resultNumber = CFNumberCreate(NULL, kCFNumberSInt32Type, &result);
346 chain_certs = SecCertificatePathCopyArray(chain);
347 const void *out_keys[] = { kSecTrustChainKey, kSecTrustDetailsKey,
348 kSecTrustInfoKey, kSecTrustResultKey };
349 const void *out_values[] = { chain_certs, details, info, resultNumber };
350 args_out = (CFTypeRef)CFDictionaryCreate(kCFAllocatorDefault, out_keys,
351 out_values, sizeof(out_keys) / sizeof(*out_keys),
352 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
353 CFReleaseSafe(chain_certs);
354 CFReleaseSafe(resultNumber);
355
356 /* Send back the response to the client. */
357 securityd_server_send_reply(tec->reply, tec->request_id, noErr, args_out);
358
359 free(tec);
360 }
361
362 kern_return_t securityd_server_request(mach_port_t receiver, mach_port_t reply,
363 audit_token_t auditToken,
364 uint32_t request_id, uint32_t msg_id, uint8_t *msg_data,
365 mach_msg_type_number_t msg_length);
366
367 /* AUDIT[securityd](done):
368 receiver (unused) is a mach_port owned by this process.
369 reply (checked by mig) is a caller provided mach_port.
370 auditToken (ok) is a kernel provided audit token.
371 request_id (checked by mig) is caller provided value, that matches the
372 mig entry for this function.
373 msg_id (ok) is caller provided value.
374 msg_data (ok) is a caller provided data of length:
375 msg_length (ok).
376 */
377 kern_return_t securityd_server_request(mach_port_t receiver, mach_port_t reply,
378 audit_token_t auditToken,
379 uint32_t request_id, uint32_t msg_id, uint8_t *msg_data,
380 mach_msg_type_number_t msg_length)
381 {
382 CFTypeRef args_in = NULL;
383 CFTypeRef args_out = NULL;
384 bool sendResponse = true;
385 const char *op_name;
386
387 request_begin();
388
389 if (msg_length) {
390 CFDataRef data_in = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
391 msg_data, msg_length, kCFAllocatorNull);
392 if (data_in) {
393 args_in = CFPropertyListCreateFromXMLData(kCFAllocatorDefault,
394 data_in, kCFPropertyListImmutable, NULL);
395 CFRelease(data_in);
396 }
397 }
398
399 #if 0
400 static int crash_counter = 0;
401 if (crash_counter++) {
402 secdebug("server", "crash test");
403 exit(1);
404 }
405 #endif
406
407 SecTaskRef clientTask =
408 #if CHECK_ENTITLEMENTS
409 SecTaskCreateWithAuditToken(kCFAllocatorDefault, auditToken);
410 #else
411 NULL;
412 #endif
413 CFArrayRef groups = SecTaskCopyAccessGroups(clientTask);
414 SecAccessGroupsSetCurrent(groups);
415 OSStatus status = errSecParam;
416 switch(msg_id) {
417 case sec_item_add_id:
418 op_name = "SecItemAdd";
419 if (isDictionary(args_in))
420 status = _SecItemAdd(args_in, &args_out, groups);
421 break;
422 case sec_item_copy_matching_id:
423 op_name = "SecItemCopyMatching";
424 if (isDictionary(args_in))
425 status = _SecItemCopyMatching(args_in, &args_out, groups);
426 break;
427 case sec_item_delete_id:
428 op_name = "SecItemDelete";
429 if (isDictionary(args_in))
430 status = _SecItemDelete(args_in, groups);
431 break;
432 case sec_item_update_id:
433 op_name = "SecItemUpdate";
434 if (isArrayOfLength(args_in, 2)) {
435 CFDictionaryRef
436 in0 = (CFDictionaryRef)CFArrayGetValueAtIndex(args_in, 0),
437 in1 = (CFDictionaryRef)CFArrayGetValueAtIndex(args_in, 1);
438 if (isDictionary(in0) && isDictionary(in1))
439 status = _SecItemUpdate(in0, in1, groups);
440 }
441 break;
442 case sec_trust_store_contains_id:
443 {
444 op_name = "SecTrustStoreContains";
445 if (!isArray(args_in))
446 break;
447 CFIndex argc_in = CFArrayGetCount(args_in);
448 if (argc_in != 2)
449 break;
450 CFStringRef domainName = CFArrayGetValueAtIndex(args_in, 0);
451 CFDataRef digest = CFArrayGetValueAtIndex(args_in, 1);
452 if (!isString(domainName) || !isData(digest))
453 break;
454
455 SecTrustStoreRef ts = SecTrustStoreForDomainName(domainName);
456 status = !SecTrustStoreContainsCertificateWithDigest(ts, digest);
457 break;
458 }
459 case sec_trust_store_set_trust_settings_id:
460 {
461 op_name = "SecTrustStoreSetTrustSettings";
462 /* Open the trust store unconditially so we can abuse this method
463 even in clients that just want to read from the truststore,
464 and this call will force it to be created. */
465 SecTrustStoreRef ts = SecTrustStoreForDomain(kSecTrustStoreDomainUser);
466 if (!isArray(args_in))
467 break;
468 CFIndex argc_in = CFArrayGetCount(args_in);
469 if (argc_in != 1 && argc_in != 2)
470 break;
471 if (!SecTaskGetBooleanValueForEntitlement(clientTask,
472 kSecEntitlementModifyAnchorCertificates)) {
473 status = errSecMissingEntitlement;
474 break;
475 }
476 CFDataRef certificateData = (CFDataRef)CFArrayGetValueAtIndex(args_in, 0);
477 if (!isData(certificateData))
478 break;
479 SecCertificateRef certificate = SecCertificateCreateWithData(NULL, certificateData);
480 if (certificate) {
481 CFTypeRef trustSettingsDictOrArray;
482 if (argc_in < 2) {
483 trustSettingsDictOrArray = NULL;
484 } else {
485 trustSettingsDictOrArray = CFArrayGetValueAtIndex(args_in, 1);
486 if (trustSettingsDictOrArray) {
487 CFTypeID tst = CFGetTypeID(trustSettingsDictOrArray);
488 if (tst != CFArrayGetTypeID() && tst != CFDictionaryGetTypeID()) {
489 CFRelease(certificate);
490 break;
491 }
492 }
493 }
494 status = _SecTrustStoreSetTrustSettings(ts, certificate, trustSettingsDictOrArray);
495 CFRelease(certificate);
496 }
497 break;
498 }
499 case sec_trust_store_remove_certificate_id:
500 op_name = "SecTrustStoreRemoveCertificate";
501 if (SecTaskGetBooleanValueForEntitlement(clientTask,
502 kSecEntitlementModifyAnchorCertificates)) {
503 SecTrustStoreRef ts = SecTrustStoreForDomain(kSecTrustStoreDomainUser);
504 if (isData(args_in)) {
505 status = SecTrustStoreRemoveCertificateWithDigest(ts, args_in);
506 }
507 } else {
508 status = errSecMissingEntitlement;
509 }
510 break;
511 case sec_delete_all_id:
512 op_name = "SecDeleteAll";
513 if (SecTaskGetBooleanValueForEntitlement(clientTask,
514 kSecEntitlementWipeDevice)) {
515 status = SecItemDeleteAll();
516 } else {
517 status = errSecMissingEntitlement;
518 }
519 break;
520 case sec_trust_evaluate_id:
521 op_name = "SecTrustEvaluate";
522 if (isDictionary(args_in)) {
523 struct securityd_server_trust_evaluation_context *tec = malloc(sizeof(*tec));
524 tec->reply = reply;
525 tec->request_id = request_id;
526 status = SecTrustServerEvaluateAsync(args_in,
527 securityd_server_trust_evaluate_done, tec);
528 if (status == noErr || status == errSecWaitForCallback) {
529 sendResponse = false;
530 } else {
531 free(tec);
532 }
533 }
534 break;
535 case sec_restore_keychain_id:
536 op_name = "SecRestoreKeychain";
537 if (SecTaskGetBooleanValueForEntitlement(clientTask,
538 kSecEntitlementRestoreKeychain)) {
539 status = _SecServerRestoreKeychain();
540 } else {
541 status = errSecMissingEntitlement;
542 }
543 break;
544 case sec_migrate_keychain_id:
545 op_name = "SecMigrateKeychain";
546 if (isArray(args_in)) {
547 if (SecTaskGetBooleanValueForEntitlement(clientTask,
548 kSecEntitlementMigrateKeychain)) {
549 status = _SecServerMigrateKeychain(args_in, &args_out);
550 } else {
551 status = errSecMissingEntitlement;
552 }
553 }
554 break;
555 case sec_keychain_backup_id:
556 op_name = "SecKeychainBackup";
557 if (!args_in || isArray(args_in)) {
558 if (SecTaskGetBooleanValueForEntitlement(clientTask,
559 kSecEntitlementRestoreKeychain)) {
560 status = _SecServerKeychainBackup(args_in, &args_out);
561 } else {
562 status = errSecMissingEntitlement;
563 }
564 }
565 break;
566 case sec_keychain_restore_id:
567 op_name = "SecKeychainRestore";
568 if (isArray(args_in)) {
569 if (SecTaskGetBooleanValueForEntitlement(clientTask,
570 kSecEntitlementRestoreKeychain)) {
571 status = _SecServerKeychainRestore(args_in, &args_out);
572 } else {
573 status = errSecMissingEntitlement;
574 }
575 }
576 break;
577 default:
578 op_name = "invalid_operation";
579 status = errSecParam;
580 break;
581 }
582
583 const char *proc_name;
584 #ifdef NDEBUG
585 if (status == errSecMissingEntitlement) {
586 #endif
587 pid_t pid;
588 audit_token_to_au32(auditToken, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL);
589 int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
590 struct kinfo_proc kp;
591 size_t len = sizeof(kp);
592 if (sysctl(mib, 4, &kp, &len, NULL, 0) == -1 || len == 0)
593 proc_name = strerror(errno);
594 else
595 proc_name = kp.kp_proc.p_comm;
596
597 #ifndef NDEBUG
598 if (status == errSecMissingEntitlement) {
599 #endif
600 asl_log(NULL, NULL, ASL_LEVEL_ERR,
601 "%s[%u] %s: missing entitlement", proc_name, pid, op_name);
602 /* Remap errSecMissingEntitlement -> errSecInteractionNotAllowed. */
603 status = errSecInteractionNotAllowed;
604 }
605
606 secdebug("ipc", "%s[%u] %s: returning: %d", proc_name, pid, op_name,
607 status);
608
609 CFReleaseSafe(groups);
610 CFReleaseSafe(clientTask);
611 SecAccessGroupsSetCurrent(NULL);
612
613 kern_return_t err = 0;
614 if (sendResponse)
615 err = securityd_server_send_reply(reply, request_id, status, args_out);
616
617 CFReleaseSafe(args_in);
618
619 return err;
620 }
621
622 extern boolean_t securityd_request_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);
623
624 union max_msg_size_union {
625 union __RequestUnion__securityd_client_securityd_reply_subsystem reply;
626 };
627
628 static uint8_t reply_buffer[sizeof(union max_msg_size_union) + MAX_TRAILER_SIZE];
629
630 static void *handle_message(void *msg, CFIndex size,
631 CFAllocatorRef allocator, void *info)
632 {
633 mach_msg_header_t *message = (mach_msg_header_t *)msg;
634 mach_msg_header_t *reply = (mach_msg_header_t *)reply_buffer;
635
636 securityd_request_server(message, reply);
637
638 return NULL;
639 }
640
641
642 static void register_server(void)
643 {
644 CFRunLoopSourceContext1 context = { 1, NULL, NULL, NULL, NULL, NULL, NULL,
645 server_port, handle_message };
646 CFRunLoopSourceRef source = CFRunLoopSourceCreate(NULL, 0,
647 (CFRunLoopSourceContext *)&context);
648
649 if (!source) {
650 secdebug("server", "failed to create source for port, exiting.");
651 exit(1);
652 }
653 CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
654 CFRelease(source);
655 }
656
657
658 int main(int argc, char *argv[])
659 {
660 securityd_init();
661 register_server();
662 register_timeout();
663 CFRunLoopRun();
664 return 0;
665 }
666
667 /* vi:set ts=4 sw=4 et: */