]> git.saurik.com Git - apple/security.git/blob - securityd/securityd_service/securityd_service/securityd_service_client.c
047498beff44fa6d6085c9d0e0483b8caf1eee18
[apple/security.git] / securityd / securityd_service / securityd_service / securityd_service_client.c
1 /* Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. */
2
3 #include "securityd_service.h"
4 #include "securityd_service_client.h"
5 #include <xpc/xpc.h>
6 #include <dispatch/dispatch.h>
7 #include <syslog.h>
8 #include <AssertMacros.h>
9
10 static xpc_connection_t
11 _service_get_connection()
12 {
13 static dispatch_once_t onceToken;
14 static xpc_connection_t connection = NULL;
15
16 dispatch_once(&onceToken, ^{
17 connection = xpc_connection_create_mach_service(SECURITYD_SERVICE_NAME, NULL, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
18 require(connection, done);
19
20 xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
21 if (xpc_get_type(event) == XPC_TYPE_ERROR) {
22 if (event == XPC_ERROR_CONNECTION_INVALID) {
23 syslog(LOG_ERR, "securityd_service not available");
24 }
25 // XPC_ERROR_CONNECTION_INTERRUPTED
26 // XPC_ERROR_TERMINATION_IMMINENT
27 } else {
28 char * desc = xpc_copy_description(event);
29 syslog(LOG_ERR, "securityd_service should never get messages on this connection: %s", desc);
30 free(desc);
31 }
32 });
33
34 xpc_connection_resume(connection);
35 done:
36 return;
37 });
38
39 return connection;
40 }
41
42 static int
43 _service_send_msg(service_context_t *context, xpc_object_t message, xpc_object_t * reply_out)
44 {
45 int rc = KB_GeneralError;
46 xpc_object_t reply = NULL;
47 xpc_connection_t conn = NULL;
48
49 require(message, done);
50 conn = _service_get_connection();
51 require(conn, done);
52
53 if (context) {
54 xpc_dictionary_set_data(message, SERVICE_XPC_CONTEXT, context, sizeof(service_context_t));
55 }
56 reply = xpc_connection_send_message_with_reply_sync(conn, message);
57 require(reply, done);
58 require(xpc_get_type(reply) != XPC_TYPE_ERROR, done);
59
60 rc = (int)xpc_dictionary_get_int64(reply, SERVICE_XPC_RC);
61
62 if (reply_out) {
63 *reply_out = reply;
64 reply = NULL;
65 }
66
67 done:
68 if (reply) xpc_release(reply);
69 return rc;
70 }
71
72 int
73 _service_client_send_uid(service_context_t *context, uint64_t request, uid_t uid)
74 {
75 int rc = KB_GeneralError;
76 xpc_object_t message = NULL;
77
78 message = xpc_dictionary_create(NULL, NULL, 0);
79 require_quiet(message, done);
80
81 xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, request);
82 xpc_dictionary_set_uint64(message, SERVICE_XPC_UID, uid);
83
84 rc = _service_send_msg(context, message, NULL);
85
86 done:
87 if (message) xpc_release(message);
88 return rc;
89 }
90
91
92 int
93 _service_client_send_secret(service_context_t *context, uint64_t request, const void * secret, int secret_len, const void * new_secret, int new_secret_len)
94 {
95 int rc = KB_GeneralError;
96 xpc_object_t message = NULL;
97
98 message = xpc_dictionary_create(NULL, NULL, 0);
99 require_quiet(message, done);
100
101 xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, request);
102 if (secret) {
103 xpc_dictionary_set_data(message, SERVICE_XPC_SECRET, secret, secret_len);
104 }
105
106 if (new_secret) {
107 xpc_dictionary_set_data(message, SERVICE_XPC_SECRET_NEW, new_secret, new_secret_len);
108 }
109
110 rc = _service_send_msg(context, message, NULL);
111
112 done:
113 if (message) xpc_release(message);
114 return rc;
115 }
116
117 int
118 service_client_kb_create(service_context_t *context, const void * secret, int secret_len)
119 {
120 return _service_client_send_secret(context, SERVICE_KB_CREATE, secret, secret_len, NULL, 0);
121 }
122
123 int
124 service_client_kb_load(service_context_t *context)
125 {
126 return _service_client_send_secret(context, SERVICE_KB_LOAD, NULL, 0, NULL, 0);
127 }
128
129 int
130 service_client_kb_load_uid(uid_t uid)
131 {
132 return _service_client_send_uid(NULL, SERVICE_KB_LOAD_UID, uid);
133 }
134
135 int
136 service_client_kb_unload(service_context_t *context)
137 {
138 return _service_client_send_secret(context, SERVICE_KB_UNLOAD, NULL, 0, NULL, 0);
139 }
140
141 int
142 service_client_kb_save(service_context_t *context)
143 {
144 return _service_client_send_secret(context, SERVICE_KB_SAVE, NULL, 0, NULL, 0);
145 }
146
147 int
148 service_client_kb_unlock(service_context_t *context, const void * secret, int secret_len)
149 {
150 return _service_client_send_secret(context, SERVICE_KB_UNLOCK, secret, secret_len, NULL, 0);
151 }
152
153 int
154 service_client_kb_lock(service_context_t *context)
155 {
156 return _service_client_send_secret(context, SERVICE_KB_LOCK, NULL, 0, NULL, 0);
157 }
158
159 int
160 service_client_kb_change_secret(service_context_t *context, const void * secret, int secret_len, const void * new_secret, int new_secret_len)
161 {
162 return _service_client_send_secret(context, SERVICE_KB_CHANGE_SECRET, secret, secret_len, new_secret, new_secret_len);
163 }
164
165 int
166 service_client_kb_reset(service_context_t *context, const void * secret, int secret_len)
167 {
168 return _service_client_send_secret(context, SERVICE_KB_RESET, secret, secret_len, NULL, 0);
169 }
170
171 int service_client_kb_is_locked(service_context_t *context, bool *locked, bool *no_pin)
172 {
173 int rc = KB_GeneralError;
174 xpc_object_t message = NULL;
175 xpc_object_t reply = NULL;
176
177 if (locked) *locked = false;
178 if (no_pin) *no_pin = false;
179
180 message = xpc_dictionary_create(NULL, NULL, 0);
181 require_quiet(message, done);
182
183 xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, SERVICE_KB_IS_LOCKED);
184
185 rc = _service_send_msg(context, message, &reply);
186
187 if (rc == KB_Success) {
188 if (locked) {
189 *locked = xpc_dictionary_get_bool(reply, SERVICE_XPC_LOCKED);
190 }
191 if (no_pin) {
192 *no_pin = xpc_dictionary_get_bool(reply, SERVICE_XPC_NO_PIN);
193 }
194 }
195
196 done:
197 if (message) xpc_release(message);
198 if (reply) xpc_release(reply);
199 return rc;
200 }
201
202 int
203 service_client_stash_set_key(service_context_t *context, const void * key, int key_len)
204 {
205 int rc = KB_GeneralError;
206 xpc_object_t message = NULL;
207
208 message = xpc_dictionary_create(NULL, NULL, 0);
209 require_quiet(message, done);
210
211 xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, SERVICE_STASH_SET_KEY);
212
213 if (key)
214 xpc_dictionary_set_data(message, SERVICE_XPC_KEY, key, key_len);
215
216 rc = _service_send_msg(context, message, NULL);
217
218 done:
219 if (message) xpc_release(message);
220 return rc;
221 }
222
223 int
224 service_client_stash_load_key(service_context_t *context, const void * key, int key_len)
225 {
226 int rc = KB_GeneralError;
227 xpc_object_t message = NULL;
228
229 message = xpc_dictionary_create(NULL, NULL, 0);
230 require_quiet(message, done);
231
232 xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, SERVICE_STASH_LOAD_KEY);
233
234 if (key)
235 xpc_dictionary_set_data(message, SERVICE_XPC_KEY, key, key_len);
236
237 rc = _service_send_msg(context, message, NULL);
238
239 done:
240 if (message) xpc_release(message);
241 return rc;
242 }
243
244 int
245 service_client_stash_get_key(service_context_t *context, void ** key, int * key_len)
246 {
247 int rc = KB_GeneralError;
248 xpc_object_t message = NULL;
249 xpc_object_t reply = NULL;
250
251 require(key, done);
252 require(key_len, done);
253
254 message = xpc_dictionary_create(NULL, NULL, 0);
255 require_quiet(message, done);
256
257 xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, SERVICE_STASH_GET_KEY);
258
259 rc = _service_send_msg(context, message, &reply);
260
261 if (rc == KB_Success) {
262 size_t data_len = 0;
263 const void * data = xpc_dictionary_get_data(reply, SERVICE_XPC_KEY, &data_len);
264 if (data) {
265 *key = calloc(1u, data_len);
266 memcpy(*key, data, data_len);
267 *key_len = (int)data_len;
268 }
269 }
270
271 done:
272 if (message) xpc_release(message);
273 if (reply) xpc_release(reply);
274 return rc;
275 }