1/* Copyright (c) 2012 Apple Inc. All rights reserved. */ 2 3#include "debugging.h" 4#include "server.h" 5#include "process.h" 6#include "session.h" 7#include "authtoken.h" 8#include "engine.h" 9#include "authd_private.h" 10#include "connection.h" 11 12#include <Security/Authorization.h> 13 14#include <xpc/xpc.h> 15#include <xpc/private.h> 16#include <dispatch/dispatch.h> 17#include <assert.h> 18#include <sandbox.h> 19 20#if DEBUG 21#include <malloc/malloc.h> 22#endif 23 24static void 25security_auth_peer_event_handler(xpc_connection_t connection, xpc_object_t event) 26{ 27 __block OSStatus status = errAuthorizationDenied; 28 29 connection_t conn = (connection_t)xpc_connection_get_context(connection); 30 require_action(conn != NULL, done, LOGE("xpc[%i]: process context not found", xpc_connection_get_pid(connection))); 31 32 CFRetainSafe(conn); 33 34 xpc_type_t type = xpc_get_type(event); 35 36 if (type == XPC_TYPE_ERROR) { 37 if (event == XPC_ERROR_CONNECTION_INVALID) { 38 // The client process on the other end of the connection has either 39 // crashed or cancelled the connection. After receiving this error, 40 // the connection is in an invalid state, and you do not need to 41 // call xpc_connection_cancel(). Just tear down any associated state 42 // here. 43 LOGV("xpc[%i]: client disconnected", xpc_connection_get_pid(connection)); 44 connection_destory_agents(conn); 45 } else if (event == XPC_ERROR_TERMINATION_IMMINENT) { 46 // Handle per-connection termination cleanup. 47 LOGD("xpc[%i]: per-connection termination", xpc_connection_get_pid(connection)); 48 } 49 } else { 50 assert(type == XPC_TYPE_DICTIONARY); 51 52 xpc_object_t reply = xpc_dictionary_create_reply(event); 53 require(reply != NULL, done); 54 55 uint64_t auth_type = xpc_dictionary_get_uint64(event, AUTH_XPC_TYPE); 56 LOGV("xpc[%i]: received message type=%llu", connection_get_pid(conn), auth_type); 57 58 switch (auth_type) { 59 case AUTHORIZATION_CREATE: 60 status = authorization_create(conn,event,reply); 61 break; 62 case AUTHORIZATION_CREATE_WITH_AUDIT_TOKEN: 63 status = authorization_create_with_audit_token(conn,event,reply); 64 break; 65 case AUTHORIZATION_FREE: 66 status = authorization_free(conn,event,reply); 67 break; 68 case AUTHORIZATION_COPY_RIGHTS: 69 status = authorization_copy_rights(conn,event,reply); 70 break; 71 case AUTHORIZATION_COPY_INFO: 72 status = authorization_copy_info(conn,event,reply); 73 break; 74 case AUTHORIZATION_MAKE_EXTERNAL_FORM: 75 status = authorization_make_external_form(conn,event,reply); 76 break; 77 case AUTHORIZATION_CREATE_FROM_EXTERNAL_FORM: 78 status = authorization_create_from_external_form(conn,event,reply); 79 break; 80 case AUTHORIZATION_RIGHT_GET: 81 status = authorization_right_get(conn,event,reply); 82 break; 83 case AUTHORIZATION_RIGHT_SET: 84 status = authorization_right_set(conn,event,reply); 85 break; 86 case AUTHORIZATION_RIGHT_REMOVE: 87 status = authorization_right_remove(conn,event,reply); 88 break; 89 case SESSION_SET_USER_PREFERENCES: 90 status = session_set_user_preferences(conn,event,reply); 91 break; 92 case AUTHORIZATION_DISMISS: 93 connection_destory_agents(conn); 94 status = errAuthorizationSuccess; 95 break; 96 case AUTHORIZATION_ENABLE_SMARTCARD: 97 status = authorization_enable_smartcard(conn,event,reply); 98 break; 99 case AUTHORIZATION_SETUP: 100 { 101 mach_port_t bootstrap = xpc_dictionary_copy_mach_send(event, AUTH_XPC_BOOTSTRAP); 102 if (!process_set_bootstrap(connection_get_process(conn), bootstrap)) { 103 if (bootstrap != MACH_PORT_NULL) { 104 mach_port_deallocate(mach_task_self(), bootstrap); 105 } 106 } 107 } 108 status = errAuthorizationSuccess; 109 break; 110#if DEBUG 111 case AUTHORIZATION_DEV: 112 server_dev(); 113 break; 114#endif 115 default: 116 break; 117 } 118 119 xpc_dictionary_set_int64(reply, AUTH_XPC_STATUS, status); 120 xpc_connection_send_message(connection, reply); 121 xpc_release(reply); 122 } 123 124done: 125 CFReleaseSafe(conn); 126} 127 128static void 129connection_finalizer(void * conn) 130{ 131 LOGD("xpc[%i]: connection_finalizer", connection_get_pid(conn)); 132 server_unregister_connection(conn); 133 134//#if DEBUG 135// malloc_printf("-=-=-=- connection_finalizer() -=-=-=-\n"); 136// malloc_zone_print(malloc_default_zone(), false); 137//#endif 138} 139 140static void 141security_auth_event_handler(xpc_connection_t xpc_conn) 142{ 143 connection_t conn = server_register_connection(xpc_conn); 144 145 if (conn) { 146 xpc_connection_set_context(xpc_conn, conn); 147 xpc_connection_set_finalizer_f(xpc_conn, connection_finalizer); 148 149 xpc_connection_set_event_handler(xpc_conn, ^(xpc_object_t event) { 150 xpc_retain(xpc_conn); 151 xpc_retain(event); 152 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 153 security_auth_peer_event_handler(xpc_conn, event); 154 xpc_release(event); 155 xpc_release(xpc_conn); 156 }); 157 }); 158 xpc_connection_resume(xpc_conn); 159 160 } else { 161 LOGE("xpc[%i]: failed to register connection", xpc_connection_get_pid(xpc_conn)); 162 xpc_connection_cancel(xpc_conn); 163 } 164} 165 166static void sandbox() 167{ 168 char * errorbuf; 169 int32_t rc; 170 171 rc = sandbox_init(SECURITY_AUTH_NAME, SANDBOX_NAMED, &errorbuf); 172 173 if (rc) { 174 LOGE("server: sandbox_init failed %s (%i)", errorbuf, rc); 175 sandbox_free_error(errorbuf); 176#ifndef DEBUG 177 abort(); 178#endif 179 } 180} 181 182int main(int argc AUTH_UNUSED, const char *argv[] AUTH_UNUSED) 183{ 184//#if DEBUG 185// malloc_printf("-=-=-=- main() -=-=-=-\n"); 186// malloc_zone_print(malloc_default_zone(), false); 187//#endif 188 189 LOGV("starting"); 190 191 sandbox(); 192 193 if (server_init() != errAuthorizationSuccess) { 194 LOGE("auth: server_init() failed"); 195 return errAuthorizationInternal; 196 } 197 198//#if DEBUG 199// malloc_printf("-=-=-=- server_init() -=-=-=-\n"); 200// malloc_zone_print(malloc_default_zone(), false); 201//#endif 202 203 xpc_main(security_auth_event_handler); 204 205 server_cleanup(); 206 207 return 0; 208} 209