1/*
2 * Copyright (c) 2013, 2014 Apple Inc.
3 * All rights reserved.
4 */
5#include <errno.h>
6#include <syslog.h>
7#include <xpc/xpc.h>
8
9#include "SNHelperPrivate.h"
10
11static xpc_connection_t
12create_connection(dispatch_queue_t queue)
13{
14	xpc_connection_t new_connection;
15
16	new_connection = xpc_connection_create_mach_service(kSNHelperService, queue, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
17	if (isa_xpc_connection(new_connection)) {
18		xpc_connection_set_event_handler(new_connection,
19			^(xpc_object_t message) {
20				if (isa_xpc_error(message)) {
21					syslog(LOG_INFO, "Got an error on the snhelper connection");
22				} else if (isa_xpc_dictionary(message)) {
23					syslog(LOG_INFO, "Got an unexpected message on the snhelper connection");
24				}
25			});
26		xpc_connection_resume(new_connection);
27	}
28
29	return new_connection;
30}
31
32static xpc_object_t
33copy_response(xpc_object_t request)
34{
35	dispatch_queue_t conn_queue = dispatch_queue_create("snhelper request", NULL);
36	xpc_connection_t connection = create_connection(conn_queue);
37	xpc_object_t response = NULL;
38
39	if (connection) {
40		response = xpc_connection_send_message_with_reply_sync(connection, request);
41		xpc_connection_cancel(connection);
42		xpc_release(connection);
43	}
44
45	dispatch_release(conn_queue);
46
47	return response;
48}
49
50static int
51flow_divert_uuid_policy_operate(const uuid_t uuid, int operation)
52{
53	int result = 0;
54	xpc_object_t request = xpc_dictionary_create(NULL, NULL, 0);
55	xpc_object_t response;
56
57	xpc_dictionary_set_uint64(request, kSNHelperMessageType, operation);
58	xpc_dictionary_set_uuid(request, kSNHelperMessageUUID, uuid);
59
60	response = copy_response(request);
61
62	if (isa_xpc_dictionary(response)) {
63		result = (int)xpc_dictionary_get_int64(response, kSNHelperMessageResult);
64	} else {
65		result = EINVAL;
66	}
67
68	xpc_release(response);
69	xpc_release(request);
70
71	return result;
72}
73
74int
75snhelper_flow_divert_uuid_policy_add(const uuid_t uuid)
76{
77	return flow_divert_uuid_policy_operate(uuid, kSNHelperMessageTypeFlowDivertUUIDAdd);
78}
79
80int
81snhelper_flow_divert_uuid_policy_remove(const uuid_t uuid)
82{
83	return flow_divert_uuid_policy_operate(uuid, kSNHelperMessageTypeFlowDivertUUIDRemove);
84}
85
86int
87snhelper_flow_divert_uuid_policy_clear(void)
88{
89	int result = 0;
90	xpc_object_t request = xpc_dictionary_create(NULL, NULL, 0);
91	xpc_object_t response;
92
93	xpc_dictionary_set_uint64(request, kSNHelperMessageType, kSNHelperMessageTypeFlowDivertUUIDClear);
94
95	response = copy_response(request);
96
97	if (isa_xpc_dictionary(response)) {
98		result = (int)xpc_dictionary_get_int64(response, kSNHelperMessageResult);
99	} else {
100		result = EINVAL;
101	}
102
103	xpc_release(response);
104	xpc_release(request);
105
106	return result;
107}
108
109int
110snhelper_get_uuid_for_app(const char *appID, uuid_t uuid)
111{
112	int result;
113	xpc_object_t request = xpc_dictionary_create(NULL, NULL, 0);
114	xpc_object_t response;
115
116	xpc_dictionary_set_uint64(request, kSNHelperMessageType, kSNHelperMessageTypeGetUUIDForApp);
117	xpc_dictionary_set_string(request, kSNHelperMessageAppID, appID);
118
119	response = copy_response(request);
120
121	if (isa_xpc_dictionary(response)) {
122		result = (int)xpc_dictionary_get_int64(response, kSNHelperMessageResult);
123		const uint8_t *uuidBytes = xpc_dictionary_get_uuid(response, kSNHelperMessageResultData);
124		if (result == 0 && uuid != NULL && uuidBytes != NULL) {
125			memcpy(uuid, uuidBytes, sizeof(uuid_t));
126		}
127	} else {
128		result = EINVAL;
129	}
130
131	xpc_release(response);
132	xpc_release(request);
133
134	return result;
135}
136
137static bool
138isa_xpc_object_of_type(xpc_object_t obj, xpc_type_t type)
139{
140	return (obj != NULL && xpc_get_type(obj) == type);
141}
142
143bool
144isa_xpc_connection(xpc_object_t obj)
145{
146	return isa_xpc_object_of_type(obj, XPC_TYPE_CONNECTION);
147}
148
149bool
150isa_xpc_bool(xpc_object_t obj)
151{
152	return isa_xpc_object_of_type(obj, XPC_TYPE_BOOL);
153}
154
155bool
156isa_xpc_dictionary(xpc_object_t obj)
157{
158	return isa_xpc_object_of_type(obj, XPC_TYPE_DICTIONARY);
159}
160
161bool
162isa_xpc_error(xpc_object_t obj)
163{
164	return isa_xpc_object_of_type(obj, XPC_TYPE_ERROR);
165}
166
167