summaryrefslogtreecommitdiffstats
path: root/src/kim/agent/mac
diff options
context:
space:
mode:
authorAlexandra Ellwood <lxs@mit.edu>2008-09-27 00:46:39 +0000
committerAlexandra Ellwood <lxs@mit.edu>2008-09-27 00:46:39 +0000
commit06847c646f5630878d6f28025993cee57f2839a8 (patch)
treec853a823d1cdc5b7bd7cf0bacac3e2aaff3d275d /src/kim/agent/mac
parentf0098982775d44d490bae733f386a5432e712a8e (diff)
downloadkrb5-06847c646f5630878d6f28025993cee57f2839a8.tar.gz
krb5-06847c646f5630878d6f28025993cee57f2839a8.tar.xz
krb5-06847c646f5630878d6f28025993cee57f2839a8.zip
KerberosAgent MachIPC support
ticket: 6055 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@20763 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/kim/agent/mac')
-rw-r--r--src/kim/agent/mac/ServerDemux.m618
-rw-r--r--src/kim/agent/mac/ServerThread.h92
-rw-r--r--src/kim/agent/mac/ServerThread.m221
3 files changed, 931 insertions, 0 deletions
diff --git a/src/kim/agent/mac/ServerDemux.m b/src/kim/agent/mac/ServerDemux.m
new file mode 100644
index 000000000..b7f208417
--- /dev/null
+++ b/src/kim/agent/mac/ServerDemux.m
@@ -0,0 +1,618 @@
+/*
+ * Copyright 2008 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#import "kim_migServer.h"
+#import "ServerThread.h"
+
+// ---------------------------------------------------------------------------
+
+static kim_boolean caller_is_front_process (task_t in_task,
+ NSString *in_path)
+{
+ kim_error err = KIM_NO_ERROR;
+ Boolean is_front_process;
+ pid_t task_pid;
+ ProcessSerialNumber task_psn, front_psn;
+
+ NSBundle *bundle = [NSBundle bundleWithPath: in_path];
+ if (bundle) {
+ NSString *identifier = [bundle bundleIdentifier];
+ if (identifier &&
+ ([identifier compare: @"edu.mit.Kerberos.KerberosMenu"] == NSOrderedSame ||
+ [identifier compare: @"com.apple.systemuiserver"] == NSOrderedSame)) {
+ return TRUE;
+ }
+ }
+
+ if (!err) {
+ err = pid_for_task (in_task, &task_pid);
+ }
+
+ if (!err) {
+ err = GetProcessForPID (task_pid, &task_psn);
+ }
+
+ if (!err) {
+ err = GetFrontProcess (&front_psn);
+ }
+
+ if (!err) {
+ err = SameProcess (&task_psn, &front_psn, &is_front_process);
+ }
+
+ return !err ? is_front_process : FALSE;
+}
+
+#pragma mark -
+
+/* ------------------------------------------------------------------------ */
+
+kern_return_t kim_mipc_srv_init (mach_port_t in_server_port,
+ task_t in_application_task,
+ kim_mipc_in_string in_application_name,
+ mach_msg_type_number_t in_application_nameCnt,
+ kim_mipc_in_string in_application_path,
+ mach_msg_type_number_t in_application_pathCnt,
+ kim_mipc_error *out_error)
+{
+ kern_return_t err = 0;
+ ServerThread *sthread = NULL;
+
+ if (!err) {
+ sthread = [ServerThread sharedServerThread];
+ if (!sthread) { err = KIM_OUT_OF_MEMORY_ERR; }
+ }
+
+ if (!err) {
+ kim_mipc_error result = KIM_NO_ERROR;
+ NSString *name = NULL;
+ NSString *path = NULL;
+
+ if (in_application_name) {
+ name = [NSString stringWithUTF8String: in_application_name];
+ }
+
+ if (in_application_path) {
+ path = [NSString stringWithUTF8String: in_application_path];
+ }
+
+ [sthread addConnectionWithPort: in_server_port
+ name: name
+ path: path
+ frontProcess: caller_is_front_process (in_application_task,
+ path)];
+ *out_error = result;
+ }
+
+ return err;
+}
+
+/* ------------------------------------------------------------------------ */
+
+kern_return_t kim_mipc_srv_enter_identity (mach_port_t in_server_port,
+ kim_mipc_out_string *out_identity,
+ mach_msg_type_number_t *out_identityCnt,
+ kim_mipc_error *out_error)
+{
+ kern_return_t err = 0;
+ kim_error result = KIM_NO_ERROR;
+ ClientConnection *client = NULL;
+ kim_identity identity = NULL;
+ kim_string identity_string = NULL;
+ mach_msg_type_number_t identity_len = 0;
+ kim_mipc_out_string identity_buf = NULL;
+
+ if (!err) {
+ ServerThread *sthread = [ServerThread sharedServerThread];
+ if (!sthread) { err = KIM_OUT_OF_MEMORY_ERR; }
+
+ if (!err) {
+ client = [sthread connectionForPort: in_server_port];
+ if (!client) { err = KIM_OUT_OF_MEMORY_ERR; }
+ }
+ }
+
+ if (!err) {
+ identity = [client enterIdentityWithError: &result];
+ }
+
+ if (!err && !result) {
+ err = kim_identity_get_string (identity, &identity_string);
+ }
+
+ if (!err && !result && identity_string) {
+ identity_len = strlen (identity_string) + 1;
+ err = vm_allocate (mach_task_self (),
+ (vm_address_t *) &identity_buf, identity_len, TRUE);
+
+ }
+
+ if (!err && !result) {
+ memmove (identity_buf, identity_string, identity_len);
+ *out_identity = identity_buf;
+ *out_identityCnt = identity_len;
+ identity_buf = NULL;
+ }
+
+ if (!err) {
+ *out_error = result;
+ }
+
+ if (identity_buf) { vm_deallocate (mach_task_self (), (vm_address_t) identity_buf, identity_len); }
+ kim_string_free (&identity_string);
+ kim_identity_free (&identity);
+
+ return err;
+}
+
+/* ------------------------------------------------------------------------ */
+
+kern_return_t kim_mipc_srv_select_identity (mach_port_t in_server_port,
+ kim_mipc_in_string in_application_id,
+ mach_msg_type_number_t in_application_idCnt,
+ kim_mipc_in_string in_explanation,
+ mach_msg_type_number_t in_explanationCnt,
+ kim_mipc_time in_start_time,
+ kim_mipc_lifetime in_lifetime,
+ kim_mipc_boolean in_renewable,
+ kim_mipc_lifetime in_renewal_lifetime,
+ kim_mipc_boolean in_forwardable,
+ kim_mipc_boolean in_proxiable,
+ kim_mipc_boolean in_addressless,
+ kim_mipc_in_string in_service_name,
+ mach_msg_type_number_t in_service_nameCnt,
+ kim_mipc_in_string in_service_identity_hint,
+ mach_msg_type_number_t in_service_identity_hintCnt,
+ kim_mipc_in_string in_client_realm_hint,
+ mach_msg_type_number_t in_client_realm_hintCnt,
+ kim_mipc_in_string in_user_hint,
+ mach_msg_type_number_t in_user_hintCnt,
+ kim_mipc_in_string in_service_realm_hint,
+ mach_msg_type_number_t in_service_realm_hintCnt,
+ kim_mipc_in_string in_service_hint,
+ mach_msg_type_number_t in_service_hintCnt,
+ kim_mipc_in_string in_server_hint,
+ mach_msg_type_number_t in_server_hintCnt,
+ kim_mipc_out_string *out_identity,
+ mach_msg_type_number_t *out_identityCnt,
+ kim_mipc_error *out_error)
+{
+ kern_return_t err = 0;
+ kim_error result = KIM_NO_ERROR;
+ ClientConnection *client = NULL;
+ kim_selection_hints hints = NULL;
+ kim_identity identity = NULL;
+ kim_string identity_string = NULL;
+ mach_msg_type_number_t identity_len = 0;
+ kim_mipc_out_string identity_buf = NULL;
+
+ if (!err) {
+ err = kim_selection_hints_create (&hints, in_application_id);
+ }
+
+ if (!err) {
+ kim_options options = NULL;
+
+ err = kim_options_create (&options);
+
+ if (!err) {
+ err = kim_options_set_start_time (options, in_start_time);
+ }
+
+ if (!err) {
+ err = kim_options_set_lifetime (options, in_lifetime);
+ }
+
+ if (!err) {
+ err = kim_options_set_renewable (options, in_renewable);
+ }
+
+ if (!err) {
+ err = kim_options_set_renewal_lifetime (options, in_renewal_lifetime);
+ }
+
+ if (!err) {
+ err = kim_options_set_forwardable (options, in_forwardable);
+ }
+
+ if (!err) {
+ err = kim_options_set_proxiable (options, in_proxiable);
+ }
+
+ if (!err) {
+ err = kim_options_set_addressless (options, in_addressless);
+ }
+
+ if (!err) {
+ err = kim_options_set_service_name (options, in_service_name);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_set_options (hints, options);
+ }
+
+ kim_options_free (&options);
+ }
+
+ if (!err) {
+ err = kim_selection_hints_set_explanation (hints, in_explanation);
+ }
+
+ if (!err && in_service_identity_hint) {
+ err = kim_selection_hints_set_hint (hints,
+ kim_hint_key_service_identity,
+ in_service_identity_hint);
+ }
+
+ if (!err && in_client_realm_hint) {
+ err = kim_selection_hints_set_hint (hints,
+ kim_hint_key_client_realm,
+ in_client_realm_hint);
+ }
+
+ if (!err && in_user_hint) {
+ err = kim_selection_hints_set_hint (hints,
+ kim_hint_key_user,
+ in_user_hint);
+ }
+
+ if (!err && in_service_realm_hint) {
+ err = kim_selection_hints_set_hint (hints,
+ kim_hint_key_service_realm,
+ in_service_realm_hint);
+ }
+
+ if (!err && in_service_hint) {
+ err = kim_selection_hints_set_hint (hints,
+ kim_hint_key_service,
+ in_service_hint);
+ }
+
+ if (!err && in_server_hint) {
+ err = kim_selection_hints_set_hint (hints,
+ kim_hint_key_server,
+ in_server_hint);
+ }
+
+ if (!err) {
+ ServerThread *sthread = [ServerThread sharedServerThread];
+ if (!sthread) { err = KIM_OUT_OF_MEMORY_ERR; }
+
+ if (!err) {
+ client = [sthread connectionForPort: in_server_port];
+ if (!client) { err = KIM_OUT_OF_MEMORY_ERR; }
+ }
+ }
+
+ if (!err) {
+ identity = [client selectIdentityWithHints: hints
+ error: &result];
+ }
+
+ if (!err && !result) {
+ err = kim_identity_get_string (identity, &identity_string);
+ }
+
+ if (!err && !result && identity_string) {
+ identity_len = strlen (identity_string) + 1;
+ err = vm_allocate (mach_task_self (),
+ (vm_address_t *) &identity_buf, identity_len, TRUE);
+ }
+
+ if (!err && !result) {
+ memmove (identity_buf, identity_string, identity_len);
+ *out_identity = identity_buf;
+ *out_identityCnt = identity_len;
+ identity_buf = NULL;
+ }
+
+ if (!err) {
+ *out_error = result;
+ }
+
+ if (identity_buf) { vm_deallocate (mach_task_self (),
+ (vm_address_t) identity_buf,
+ identity_len); }
+ kim_string_free (&identity_string);
+ kim_identity_free (&identity);
+ kim_selection_hints_free (&hints);
+
+ return err;
+}
+
+/* ------------------------------------------------------------------------ */
+
+kern_return_t kim_mipc_srv_auth_prompt (mach_port_t in_server_port,
+ kim_mipc_in_string in_identity,
+ mach_msg_type_number_t in_identityCnt,
+ kim_mipc_prompt_type in_prompt_type,
+ kim_mipc_boolean in_hide_reply,
+ kim_mipc_in_string in_title,
+ mach_msg_type_number_t in_titleCnt,
+ kim_mipc_in_string in_message,
+ mach_msg_type_number_t in_messageCnt,
+ kim_mipc_in_string in_description,
+ mach_msg_type_number_t in_descriptionCnt,
+ kim_mipc_out_string *out_response,
+ mach_msg_type_number_t *out_responseCnt,
+ kim_mipc_error *out_error)
+{
+ kern_return_t err = 0;
+ kim_error result = KIM_NO_ERROR;
+ ClientConnection *client = NULL;
+ kim_identity identity = NULL;
+ const char *response_string = NULL;
+ mach_msg_type_number_t response_len = 0;
+ kim_mipc_out_string response_buf = NULL;
+
+ if (!err) {
+ ServerThread *sthread = [ServerThread sharedServerThread];
+ if (!sthread) { err = KIM_OUT_OF_MEMORY_ERR; }
+
+ if (!err) {
+ client = [sthread connectionForPort: in_server_port];
+ if (!client) { err = KIM_OUT_OF_MEMORY_ERR; }
+ }
+ }
+
+ if (!err) {
+ err = kim_identity_create_from_string (&identity, in_identity);
+ }
+
+ if (!err) {
+ NSString *title = NULL;
+ NSString *message = NULL;
+ NSString *description = NULL;
+
+ if (in_title) {
+ title = [NSString stringWithUTF8String: in_title];
+ }
+
+ if (in_message) {
+ message = [NSString stringWithUTF8String: in_message];
+ }
+
+ if (in_description) {
+ description = [NSString stringWithUTF8String: in_description];
+ }
+
+ response_string = [[client authPromptWithIdentity: identity
+ type: in_prompt_type
+ hideReply: in_hide_reply
+ title: title
+ message: message
+ description: description
+ error: &result] UTF8String];
+ }
+
+ if (!err && !result && response_string) {
+ response_len = strlen (response_string) + 1;
+ err = vm_allocate (mach_task_self (),
+ (vm_address_t *) &response_buf, response_len, TRUE);
+
+ }
+
+ if (!err && !result) {
+ memmove (response_buf, response_string, response_len);
+ *out_response = response_buf;
+ *out_responseCnt = response_len;
+ response_buf = NULL;
+ }
+
+ if (!err) {
+ *out_error = result;
+ }
+
+ if (response_buf) { vm_deallocate (mach_task_self (),
+ (vm_address_t) response_buf,
+ response_len); }
+ kim_identity_free (&identity);
+
+ return err;
+}
+
+/* ------------------------------------------------------------------------ */
+
+kern_return_t kim_mipc_srv_change_password (mach_port_t in_server_port,
+ kim_mipc_in_string in_identity,
+ mach_msg_type_number_t in_identityCnt,
+ kim_mipc_boolean in_old_password_expired,
+ kim_mipc_out_string *out_old_password,
+ mach_msg_type_number_t *out_old_passwordCnt,
+ kim_mipc_out_string *out_new_password,
+ mach_msg_type_number_t *out_new_passwordCnt,
+ kim_mipc_out_string *out_vfy_password,
+ mach_msg_type_number_t *out_vfy_passwordCnt,
+ kim_mipc_error *out_error)
+{
+ kern_return_t err = 0;
+ kim_error result = KIM_NO_ERROR;
+ ClientConnection *client = NULL;
+ kim_identity identity = NULL;
+ NSArray *passwords = NULL;
+ const char *old_password_string = NULL;
+ const char *new_password_string = NULL;
+ const char *vfy_password_string = NULL;
+ mach_msg_type_number_t old_password_len = 0;
+ mach_msg_type_number_t new_password_len = 0;
+ mach_msg_type_number_t vfy_password_len = 0;
+ kim_mipc_out_string old_password_buf = NULL;
+ kim_mipc_out_string new_password_buf = NULL;
+ kim_mipc_out_string vfy_password_buf = NULL;
+
+ if (!err) {
+ ServerThread *sthread = [ServerThread sharedServerThread];
+ if (!sthread) { err = KIM_OUT_OF_MEMORY_ERR; }
+
+ if (!err) {
+ client = [sthread connectionForPort: in_server_port];
+ if (!client) { err = KIM_OUT_OF_MEMORY_ERR; }
+ }
+ }
+
+ if (!err) {
+ err = kim_identity_create_from_string (&identity, in_identity);
+ }
+
+ if (!err) {
+ passwords = [client changePasswordWithIdentity: identity
+ oldPasswordIsExpired: in_old_password_expired
+ error: &result];
+ }
+
+ if (!err && !result) {
+ if (passwords && [passwords count] == 3) {
+ old_password_string = [[passwords objectAtIndex: 1] UTF8String];
+ new_password_string = [[passwords objectAtIndex: 2] UTF8String];
+ vfy_password_string = [[passwords objectAtIndex: 3] UTF8String];
+ } else {
+ err = KIM_OUT_OF_MEMORY_ERR;
+ }
+ }
+
+ if (!err && !result && old_password_string) {
+ old_password_len = strlen (old_password_string) + 1;
+ err = vm_allocate (mach_task_self (), (vm_address_t *) &old_password_buf, old_password_len, TRUE);
+
+ }
+
+ if (!err && !result && new_password_string) {
+ new_password_len = strlen (new_password_string) + 1;
+ err = vm_allocate (mach_task_self (), (vm_address_t *) &new_password_buf, new_password_len, TRUE);
+
+ }
+
+ if (!err && !result && vfy_password_string) {
+ vfy_password_len = strlen (vfy_password_string) + 1;
+ err = vm_allocate (mach_task_self (), (vm_address_t *) &vfy_password_buf, vfy_password_len, TRUE);
+ }
+
+ if (!err && !result) {
+ memmove (old_password_buf, old_password_string, old_password_len);
+ memmove (new_password_buf, new_password_string, new_password_len);
+ memmove (vfy_password_buf, vfy_password_string, vfy_password_len);
+ *out_old_password = old_password_buf;
+ *out_new_password = new_password_buf;
+ *out_vfy_password = vfy_password_buf;
+ *out_old_passwordCnt = old_password_len;
+ *out_new_passwordCnt = new_password_len;
+ *out_vfy_passwordCnt = vfy_password_len;
+ old_password_buf = NULL;
+ new_password_buf = NULL;
+ vfy_password_buf = NULL;
+ }
+
+ if (!err) {
+ *out_error = result;
+ }
+
+ if (old_password_buf) { vm_deallocate (mach_task_self (), (vm_address_t) old_password_buf, old_password_len); }
+ if (new_password_buf) { vm_deallocate (mach_task_self (), (vm_address_t) new_password_buf, new_password_len); }
+ if (vfy_password_buf) { vm_deallocate (mach_task_self (), (vm_address_t) vfy_password_buf, vfy_password_len); }
+ kim_identity_free (&identity);
+
+ return err;
+}
+
+/* ------------------------------------------------------------------------ */
+
+kern_return_t kim_mipc_srv_handle_error (mach_port_t in_server_port,
+ kim_mipc_in_string in_identity,
+ mach_msg_type_number_t in_identityCnt,
+ kim_mipc_error in_error,
+ kim_mipc_in_string in_message,
+ mach_msg_type_number_t in_messageCnt,
+ kim_mipc_in_string in_description,
+ mach_msg_type_number_t in_descriptionCnt,
+ kim_mipc_error *out_error)
+{
+ kern_return_t err = 0;
+ kim_error result = KIM_NO_ERROR;
+ ClientConnection *client = NULL;
+ kim_identity identity = NULL;
+
+ if (!err) {
+ ServerThread *sthread = [ServerThread sharedServerThread];
+ if (!sthread) { err = KIM_OUT_OF_MEMORY_ERR; }
+
+ if (!err) {
+ client = [sthread connectionForPort: in_server_port];
+ if (!client) { err = KIM_OUT_OF_MEMORY_ERR; }
+ }
+ }
+
+ if (!err) {
+ err = kim_identity_create_from_string (&identity, in_identity);
+ }
+
+ if (!err) {
+ NSString *message = NULL;
+ NSString *description = NULL;
+
+ if (in_message) {
+ message = [NSString stringWithUTF8String: in_message];
+ }
+
+ if (in_description) {
+ description = [NSString stringWithUTF8String: in_description];
+ }
+
+ result = [client handleError: in_error
+ identity: identity
+ message: message
+ description: description];
+ }
+
+ if (!err) {
+ *out_error = result;
+ }
+
+ kim_identity_free (&identity);
+
+ return err;
+}
+
+/* ------------------------------------------------------------------------ */
+
+kern_return_t kim_mipc_srv_fini (mach_port_t in_server_port,
+ kim_mipc_error *out_error)
+{
+ kern_return_t err = 0;
+ ServerThread *sthread = NULL;
+
+ if (!err) {
+ sthread = [ServerThread sharedServerThread];
+ if (!sthread) { err = KIM_OUT_OF_MEMORY_ERR; }
+ }
+
+ if (!err) {
+ [sthread removeConnectionWithPort: in_server_port];
+ }
+
+ if (!err) {
+ *out_error = KIM_NO_ERROR;
+ }
+
+ return err;
+}
diff --git a/src/kim/agent/mac/ServerThread.h b/src/kim/agent/mac/ServerThread.h
new file mode 100644
index 000000000..4457f2a62
--- /dev/null
+++ b/src/kim/agent/mac/ServerThread.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2008 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <Kerberos/kim.h>
+#include <Kerberos/kim_ui_plugin.h>
+
+@interface ClientConnection : NSObject {
+ mach_port_t port;
+ bool callerIsFrontProcess;
+ NSString *applicationName;
+ NSString *applicationPath;
+}
+
+@property(readonly) mach_port_t port;
+
+- (id) initWithPort: (mach_port_t) port
+ name: (NSString *) name
+ path: (NSString *) path
+ front_process: (bool) frontProcess;
+
+- (kim_identity) enterIdentityWithError: (kim_error *) outError;
+
+- (kim_identity) selectIdentityWithHints: (kim_selection_hints) hints
+ error: (kim_error *) outError;
+
+- (NSString *) authPromptWithIdentity: (kim_identity) identity
+ type: (kim_prompt_type) type
+ hideReply: (bool) hideReply
+ title: (NSString *) title
+ message: (NSString *) message
+ description: (NSString *) description
+ error: (kim_error *) outError;
+
+- (NSArray *) changePasswordWithIdentity: (kim_identity) identity
+ oldPasswordIsExpired: (bool) oldPasswordIsExpired
+ error: (kim_error *) outError;
+
+- (kim_error) handleError: (kim_error) error
+ identity: (kim_identity) identity
+ message: (NSString *) message
+ description: (NSString *) description;
+
+- (void) dealloc;
+
+@end
+
+/* ------------------------------------------------------------------------ */
+
+@interface ServerThread : NSObject {
+ NSMutableArray *connections;
+}
+
++ (ServerThread *) sharedServerThread;
+
+- (id) init;
+
+- (void) dealloc;
+
+- (kern_return_t) listen;
+
+- (void) addConnectionWithPort: (mach_port_t) port
+ name: (NSString *) name
+ path: (NSString *) path
+ frontProcess: (bool) frontProcess;
+
+- (void) removeConnectionWithPort: (mach_port_t) port;
+
+
+- (ClientConnection *) connectionForPort: (mach_port_t) port;
+
+@end
diff --git a/src/kim/agent/mac/ServerThread.m b/src/kim/agent/mac/ServerThread.m
new file mode 100644
index 000000000..6d5ba5ed5
--- /dev/null
+++ b/src/kim/agent/mac/ServerThread.m
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2008 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+#import "ServerThread.h"
+#import <Kerberos/kim.h>
+#import <Kerberos/kipc_server.h>
+#import "kim_migServer.h"
+
+
+@implementation ClientConnection
+
+@synthesize port;
+
+/* ------------------------------------------------------------------------ */
+
+- (id) initWithPort: (mach_port_t) connectionPort
+ name: (NSString *) name
+ path: (NSString *) path
+ front_process: (bool) frontProcess
+{
+ if ((self = [super init])) {
+ port = connectionPort;
+ callerIsFrontProcess = frontProcess;
+ applicationName = [name retain];
+ applicationPath = [path retain];
+ }
+
+ return self;
+}
+
+/* ------------------------------------------------------------------------ */
+
+- (kim_identity) enterIdentityWithError: (kim_error *) outError
+{
+ kim_error err = KIM_NO_ERROR;
+ kim_identity identity = NULL;
+
+ *outError = err;
+ return identity;
+}
+
+/* ------------------------------------------------------------------------ */
+
+- (kim_identity) selectIdentityWithHints: (kim_selection_hints) hints
+ error: (kim_error *) outError
+{
+ kim_error err = KIM_NO_ERROR;
+ kim_identity identity = NULL;
+
+ *outError = err;
+ return identity;
+}
+
+/* ------------------------------------------------------------------------ */
+
+- (NSString *) authPromptWithIdentity: (kim_identity) identity
+ type: (kim_prompt_type) type
+ hideReply: (bool) hideReply
+ title: (NSString *) title
+ message: (NSString *) message
+ description: (NSString *) description
+ error: (kim_error *) outError
+{
+ kim_error err = KIM_NO_ERROR;
+ NSString *reply = @"A reply";
+
+ *outError = err;
+ return reply;
+}
+
+/* ------------------------------------------------------------------------ */
+
+- (NSArray *) changePasswordWithIdentity: (kim_identity) identity
+ oldPasswordIsExpired: (bool) oldPasswordIsExpired
+ error: (kim_error *) outError
+{
+ kim_error err = KIM_NO_ERROR;
+ NSString *oldPassword = @"an old password";
+ NSString *newPassword = @"a new password";
+ NSString *verifyPassword = @"a verify password";
+
+ *outError = err;
+ return !err ? [NSArray arrayWithObjects: oldPassword, newPassword, verifyPassword, NULL] : NULL;
+}
+
+/* ------------------------------------------------------------------------ */
+
+- (kim_error) handleError: (kim_error) error
+ identity: (kim_identity) identity
+ message: (NSString *) message
+ description: (NSString *) description
+{
+ kim_error err = KIM_NO_ERROR;
+
+ return err;
+}
+
+/* ------------------------------------------------------------------------ */
+
+- (void) dealloc
+{
+ [applicationName release];
+ [applicationPath release];
+ [super dealloc];
+}
+
+@end
+
+@implementation ServerThread
+
+/* ------------------------------------------------------------------------ */
+
++ (ServerThread *) sharedServerThread
+{
+ static ServerThread *gServerThread = NULL;
+
+ if (!gServerThread) {
+ gServerThread = [[ServerThread alloc] init];
+ }
+
+ return gServerThread;
+}
+
+/* ------------------------------------------------------------------------ */
+
+- (id) init
+{
+ if ((self = [super init])) {
+ connections = [[NSMutableArray alloc] init];
+ if (!connections) {
+ [self release];
+ self = nil;
+ }
+ }
+
+ return self;
+}
+
+/* ------------------------------------------------------------------------ */
+
+- (void) dealloc
+{
+ [connections release];
+ [super dealloc];
+}
+
+/* ------------------------------------------------------------------------ */
+
+- (kern_return_t) listen
+{
+ return kipc_server_run_server (kim_server);
+}
+
+/* ------------------------------------------------------------------------ */
+
+- (void) addConnectionWithPort: (mach_port_t) port
+ name: (NSString *) name
+ path: (NSString *) path
+ frontProcess: (bool) frontProcess
+{
+ ClientConnection *client = [[ClientConnection alloc] initWithPort: port
+ name: name
+ path: path
+ front_process: frontProcess];
+ if (client) {
+ [connections addObject: client];
+ }
+
+ [client release];
+}
+
+/* ------------------------------------------------------------------------ */
+
+- (void) removeConnectionWithPort: (mach_port_t) port
+{
+ for (ClientConnection *client in connections) {
+ if (client.port == port) {
+ [connections removeObject: client];
+ }
+ }
+
+ if (![connections count]) {
+ kipc_server_quit ();
+ }
+}
+
+
+/* ------------------------------------------------------------------------ */
+
+- (ClientConnection *) connectionForPort: (mach_port_t) port
+{
+ for (ClientConnection *client in connections) {
+ if (client.port == port) {
+ return client;
+ }
+ }
+ return NULL;
+}
+
+@end
+