diff -ru Kerberos.orig/KerberosFramework/Kerberos5/Sources/util/mac/k5_mig_server.c Kerberos/KerberosFramework/Kerberos5/Sources/util/mac/k5_mig_server.c --- Kerberos.orig/KerberosFramework/Kerberos5/Sources/util/mac/k5_mig_server.c 2008-12-18 21:34:46.000000000 -0800 +++ Kerberos/KerberosFramework/Kerberos5/Sources/util/mac/k5_mig_server.c 2008-12-19 00:31:02.000000000 -0800 @@ -37,6 +37,11 @@ #include #include +/* Map of receive rights to libdispatch sources. */ +static CFMutableDictionaryRef mig_clients = NULL; +__unused static int _assert_mach_port_can_be_used_as_cfdictionary_key_ + [sizeof(mach_port_t) <= sizeof(void *) ? 0 : -1]; + /* ------------------------------------------------------------------------ */ static boolean_t k5_ipc_request_demux (mach_msg_header_t *request, @@ -55,12 +60,11 @@ err = k5_ipc_server_remove_client (request->msgh_local_port); if (!err) { - err = mach_port_mod_refs (mach_task_self (), - request->msgh_local_port, - MACH_PORT_RIGHT_RECEIVE, -1); - } - - if (!err) { + void *key = (void *)((uintptr_t)request->msgh_local_port); + dispatch_source_t source = (dispatch_source_t)CFDictionaryGetValue + (mig_clients, key); + CFDictionaryRemoveValue (mig_clients, key); + dispatch_release (source); handled = 1; /* was a port we are tracking */ } } @@ -76,6 +80,8 @@ kern_return_t err = KERN_SUCCESS; mach_port_t connection_port = MACH_PORT_NULL; mach_port_t old_notification_target = MACH_PORT_NULL; + dispatch_source_attr_t attr = NULL; + dispatch_source_t source = NULL; if (!err) { err = mach_port_allocate (mach_task_self (), @@ -97,18 +103,44 @@ } if (!err) { + attr = dispatch_source_attr_create (); + if (attr == NULL) { + err = KERN_FAILURE; + } + } + + if (!err) { + dispatch_source_finalizer_t finalizer; + finalizer = ^(dispatch_source_t s){ + mach_port_mod_refs (mach_task_self (), connection_port, + MACH_PORT_RIGHT_RECEIVE, -1); + }; + if (dispatch_source_attr_set_finalizer (attr, finalizer)) { + err = KERN_FAILURE; + } + } + + if (!err) { dispatch_queue_t queue; - queue = dispatch_get_main_queue(); - dispatch_source_mig_create(connection_port, K5_IPC_MAX_MSG_SIZE, - NULL, queue, k5_ipc_request_demux); + queue = dispatch_get_main_queue (); + source = dispatch_source_mig_create (connection_port, + K5_IPC_MAX_MSG_SIZE, attr, queue, + k5_ipc_request_demux); + if (source == NULL) { + err = KERN_FAILURE; + } } if (!err) { + CFDictionaryAddValue (mig_clients, + (void *)((uintptr_t)connection_port), source); *out_connection_port = connection_port; connection_port = MACH_PORT_NULL; } if (MACH_PORT_VALID (connection_port)) { mach_port_deallocate (mach_task_self (), connection_port); } + + if (attr != NULL) { dispatch_release (attr); } return err; } @@ -223,11 +255,14 @@ if (launch_data_get_type(obj) == LAUNCH_DATA_MACHPORT) { mach_port_t port = launch_data_get_machport(obj); - dispatch_source_mig_create(port, - K5_IPC_MAX_MSG_SIZE, - NULL, - dispatch_get_main_queue(), - k5_ipc_request_demux); + source = dispatch_source_mig_create(port, + K5_IPC_MAX_MSG_SIZE, + NULL, + dispatch_get_main_queue(), + k5_ipc_request_demux); + if (source == NULL) { + syslog(LOG_NOTICE, "Failed to register Mach source."); + } } else { syslog(LOG_NOTICE, "%s: not a mach port", key); } @@ -254,6 +289,13 @@ syslog(LOG_NOTICE, "launch_msg() response: %s", strerror(errno)); return 1; } + + mig_clients = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL); + + if (mig_clients == NULL) { + syslog(LOG_NOTICE, "Failed to create client dictionary."); + return 1; + } tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_MACHSERVICES);