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