summaryrefslogtreecommitdiffstats
path: root/src/lockdown.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lockdown.c')
-rw-r--r--src/lockdown.c777
1 files changed, 441 insertions, 336 deletions
diff --git a/src/lockdown.c b/src/lockdown.c
index 2532999..1befb72 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -28,9 +28,10 @@
28#include <gnutls/x509.h> 28#include <gnutls/x509.h>
29#include <plist/plist.h> 29#include <plist/plist.h>
30 30
31#include "property_list_service.h"
31#include "lockdown.h" 32#include "lockdown.h"
32#include "iphone.h" 33#include "iphone.h"
33#include "utils.h" 34#include "debug.h"
34#include "userpref.h" 35#include "userpref.h"
35 36
36#define RESULT_SUCCESS 0 37#define RESULT_SUCCESS 0
@@ -98,7 +99,7 @@ static int lockdown_check_result(plist_t dict, const char *query_match)
98 } else if (!strcmp(result_value, "Failure")) { 99 } else if (!strcmp(result_value, "Failure")) {
99 ret = RESULT_FAILURE; 100 ret = RESULT_FAILURE;
100 } else { 101 } else {
101 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: ERROR: unknown result value '%s'\n", __func__, result_value); 102 debug_info("ERROR: unknown result value '%s'", result_value);
102 } 103 }
103 } 104 }
104 if (result_value) 105 if (result_value)
@@ -108,30 +109,49 @@ static int lockdown_check_result(plist_t dict, const char *query_match)
108} 109}
109 110
110/** 111/**
111 * Closes the lockdownd communication session, by sending 112 * Adds a label key with the passed value to a plist dict node.
112 * the StopSession Request to the device. 113 *
114 * @param plist The plist to add the key to
115 * @param label The value for the label key
116 *
117 */
118static void plist_dict_add_label(plist_t plist, const char *label)
119{
120 if (plist && label) {
121 if (plist_get_node_type(plist) == PLIST_DICT)
122 plist_dict_insert_item(plist, "Label", plist_new_string(label));
123 }
124}
125
126/**
127 * Closes the lockdownd communication session, by sending the StopSession
128 * Request to the device.
129 *
130 * @see lockdownd_start_session
113 * 131 *
114 * @param control The lockdown client 132 * @param control The lockdown client
133 * @param session_id The id of a running session
115 * 134 *
116 * @return an error code (LOCKDOWN_E_SUCCESS on success) 135 * @return an error code (LOCKDOWN_E_SUCCESS on success)
117 */ 136 */
118lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client) 137lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char *session_id)
119{ 138{
120 if (!client) 139 if (!client)
121 return LOCKDOWN_E_INVALID_ARG; 140 return LOCKDOWN_E_INVALID_ARG;
122 141
123 if (!client->session_id) { 142 if (!session_id) {
124 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: no session_id given, cannot stop session\n", __func__); 143 debug_info("no session_id given, cannot stop session");
125 return LOCKDOWN_E_INVALID_ARG; 144 return LOCKDOWN_E_INVALID_ARG;
126 } 145 }
127 146
128 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 147 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
129 148
130 plist_t dict = plist_new_dict(); 149 plist_t dict = plist_new_dict();
150 plist_dict_add_label(dict, client->label);
131 plist_dict_insert_item(dict,"Request", plist_new_string("StopSession")); 151 plist_dict_insert_item(dict,"Request", plist_new_string("StopSession"));
132 plist_dict_insert_item(dict,"SessionID", plist_new_string(client->session_id)); 152 plist_dict_insert_item(dict,"SessionID", plist_new_string(session_id));
133 153
134 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: stopping session %s\n", __func__, client->session_id); 154 debug_info("stopping session %s", session_id);
135 155
136 ret = lockdownd_send(client, dict); 156 ret = lockdownd_send(client, dict);
137 157
@@ -141,55 +161,20 @@ lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client)
141 ret = lockdownd_recv(client, &dict); 161 ret = lockdownd_recv(client, &dict);
142 162
143 if (!dict) { 163 if (!dict) {
144 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: LOCKDOWN_E_PLIST_ERROR\n", __func__); 164 debug_info("LOCKDOWN_E_PLIST_ERROR");
145 return LOCKDOWN_E_PLIST_ERROR; 165 return LOCKDOWN_E_PLIST_ERROR;
146 } 166 }
147 167
148 ret = LOCKDOWN_E_UNKNOWN_ERROR; 168 ret = LOCKDOWN_E_UNKNOWN_ERROR;
149 if (lockdown_check_result(dict, "StopSession") == RESULT_SUCCESS) { 169 if (lockdown_check_result(dict, "StopSession") == RESULT_SUCCESS) {
150 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); 170 debug_info("success");
151 ret = LOCKDOWN_E_SUCCESS; 171 ret = LOCKDOWN_E_SUCCESS;
152 } 172 }
153 plist_free(dict); 173 plist_free(dict);
154 dict = NULL; 174 dict = NULL;
155 175 if (client->ssl_enabled) {
156 free(client->session_id); 176 property_list_service_disable_ssl(client->parent);
157 client->session_id = NULL;
158
159 return ret;
160}
161
162/**
163 * Shuts down the SSL session by first calling iphone_lckd_stop_session
164 * to cleanly close the lockdownd communication session, and then
165 * performing a close notify, which is done by "gnutls_bye".
166 *
167 * @param client The lockdown client
168 *
169 * @return an error code (LOCKDOWN_E_SUCCESS on success)
170 */
171static lockdownd_error_t lockdownd_stop_ssl_session(lockdownd_client_t client)
172{
173 if (!client) {
174 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: invalid argument!\n", __func__);
175 return LOCKDOWN_E_INVALID_ARG;
176 } 177 }
177 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
178
179 if (client->in_SSL) {
180 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: stopping SSL session\n", __func__);
181 ret = lockdownd_stop_session(client);
182 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: sending SSL close notify\n", __func__);
183 gnutls_bye(client->ssl_session, GNUTLS_SHUT_RDWR);
184 }
185 if (client->ssl_session) {
186 gnutls_deinit(client->ssl_session);
187 }
188 if (client->ssl_certificate) {
189 gnutls_certificate_free_credentials(client->ssl_certificate);
190 }
191 client->in_SSL = 0;
192
193 return ret; 178 return ret;
194} 179}
195 180
@@ -205,29 +190,45 @@ lockdownd_error_t lockdownd_client_free(lockdownd_client_t client)
205 return LOCKDOWN_E_INVALID_ARG; 190 return LOCKDOWN_E_INVALID_ARG;
206 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 191 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
207 192
208 lockdownd_stop_ssl_session(client); 193 if (client->session_id)
194 lockdownd_stop_session(client, client->session_id);
209 195
210 if (client->connection) { 196 if (client->parent) {
211 lockdownd_goodbye(client); 197 lockdownd_goodbye(client);
212 198
213 // IMO, read of final "sessionUpcall connection closed" packet 199 if (property_list_service_client_free(client->parent) == PROPERTY_LIST_SERVICE_E_SUCCESS) {
214 // should come here instead of in iphone_free_device 200 ret = LOCKDOWN_E_SUCCESS;
215 if ((ret = iphone_device_disconnect(client->connection)) != IPHONE_E_SUCCESS) {
216 ret = LOCKDOWN_E_UNKNOWN_ERROR;
217 } 201 }
218 } 202 }
219 203
220 if (client->session_id) {
221 free(client->session_id);
222 }
223 if (client->uuid) { 204 if (client->uuid) {
224 free(client->uuid); 205 free(client->uuid);
225 } 206 }
207 if (client->label) {
208 free(client->label);
209 }
226 210
227 free(client); 211 free(client);
228 return ret; 212 return ret;
229} 213}
230 214
215/**
216 * Sets the label to send for requests to lockdownd.
217 *
218 * @param client The lockdown client
219 * @param label The label to set or NULL to disable sending a label
220 *
221 */
222void lockdownd_client_set_label(lockdownd_client_t client, const char *label)
223{
224 if (client) {
225 if (client->label)
226 free(client->label);
227
228 client->label = (label != NULL) ? strdup(label): NULL;
229 }
230}
231
231/** Polls the iPhone for lockdownd data. 232/** Polls the iPhone for lockdownd data.
232 * 233 *
233 * @param control The lockdownd client 234 * @param control The lockdownd client
@@ -240,18 +241,11 @@ lockdownd_error_t lockdownd_recv(lockdownd_client_t client, plist_t *plist)
240 if (!client || !plist || (plist && *plist)) 241 if (!client || !plist || (plist && *plist))
241 return LOCKDOWN_E_INVALID_ARG; 242 return LOCKDOWN_E_INVALID_ARG;
242 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; 243 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
243 iphone_error_t err; 244 property_list_service_error_t err;
244 245
245 if (!client->in_SSL) { 246 err = property_list_service_receive_plist(client->parent, plist);
246 err = iphone_device_receive_plist(client->connection, plist); 247 if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) {
247 if (err != IPHONE_E_SUCCESS) { 248 ret = LOCKDOWN_E_UNKNOWN_ERROR;
248 ret = LOCKDOWN_E_UNKNOWN_ERROR;
249 }
250 } else {
251 err = iphone_device_receive_encrypted_plist(client->ssl_session, plist);
252 if (err != IPHONE_E_SUCCESS) {
253 return LOCKDOWN_E_SSL_ERROR;
254 }
255 } 249 }
256 250
257 if (!*plist) 251 if (!*plist)
@@ -278,27 +272,22 @@ lockdownd_error_t lockdownd_send(lockdownd_client_t client, plist_t plist)
278 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; 272 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
279 iphone_error_t err; 273 iphone_error_t err;
280 274
281 if (!client->in_SSL) { 275 err = property_list_service_send_xml_plist(client->parent, plist);
282 err = iphone_device_send_xml_plist(client->connection, plist); 276 if (err != PROPERTY_LIST_SERVICE_E_SUCCESS) {
283 if (err != IPHONE_E_SUCCESS) { 277 ret = LOCKDOWN_E_UNKNOWN_ERROR;
284 ret = LOCKDOWN_E_UNKNOWN_ERROR;
285 }
286 } else {
287 err = iphone_device_send_encrypted_xml_plist(client->ssl_session, plist);
288 if (err != IPHONE_E_SUCCESS) {
289 ret = LOCKDOWN_E_SSL_ERROR;
290 }
291 } 278 }
292 return ret; 279 return ret;
293} 280}
294 281
295/** Initiates the handshake for the lockdown session. Part of the lockdownd handshake. 282/** Query the type of the service daemon. Depending on whether the device is
283 * queried in normal mode or restore mode, different types will be returned.
296 * 284 *
297 * @param client The lockdownd client 285 * @param client The lockdownd client
286 * @param type The type returned by the service daemon. Can be NULL to ignore.
298 * 287 *
299 * @return an error code (LOCKDOWN_E_SUCCESS on success) 288 * @return an error code (LOCKDOWN_E_SUCCESS on success)
300 */ 289 */
301lockdownd_error_t lockdownd_query_type(lockdownd_client_t client) 290lockdownd_error_t lockdownd_query_type(lockdownd_client_t client, char **type)
302{ 291{
303 if (!client) 292 if (!client)
304 return LOCKDOWN_E_INVALID_ARG; 293 return LOCKDOWN_E_INVALID_ARG;
@@ -306,9 +295,10 @@ lockdownd_error_t lockdownd_query_type(lockdownd_client_t client)
306 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 295 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
307 296
308 plist_t dict = plist_new_dict(); 297 plist_t dict = plist_new_dict();
298 plist_dict_add_label(dict, client->label);
309 plist_dict_insert_item(dict,"Request", plist_new_string("QueryType")); 299 plist_dict_insert_item(dict,"Request", plist_new_string("QueryType"));
310 300
311 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__); 301 debug_info("called");
312 ret = lockdownd_send(client, dict); 302 ret = lockdownd_send(client, dict);
313 303
314 plist_free(dict); 304 plist_free(dict);
@@ -321,7 +311,12 @@ lockdownd_error_t lockdownd_query_type(lockdownd_client_t client)
321 311
322 ret = LOCKDOWN_E_UNKNOWN_ERROR; 312 ret = LOCKDOWN_E_UNKNOWN_ERROR;
323 if (lockdown_check_result(dict, "QueryType") == RESULT_SUCCESS) { 313 if (lockdown_check_result(dict, "QueryType") == RESULT_SUCCESS) {
324 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); 314 /* return the type if requested */
315 if (type != NULL) {
316 plist_t type_node = plist_dict_get_item(dict, "Type");
317 plist_get_string_val(type_node, type);
318 }
319 debug_info("success with type %s", *type);
325 ret = LOCKDOWN_E_SUCCESS; 320 ret = LOCKDOWN_E_SUCCESS;
326 } 321 }
327 plist_free(dict); 322 plist_free(dict);
@@ -349,6 +344,7 @@ lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *dom
349 344
350 /* setup request plist */ 345 /* setup request plist */
351 dict = plist_new_dict(); 346 dict = plist_new_dict();
347 plist_dict_add_label(dict, client->label);
352 if (domain) { 348 if (domain) {
353 plist_dict_insert_item(dict,"Domain", plist_new_string(domain)); 349 plist_dict_insert_item(dict,"Domain", plist_new_string(domain));
354 } 350 }
@@ -372,7 +368,7 @@ lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *dom
372 return ret; 368 return ret;
373 369
374 if (lockdown_check_result(dict, "GetValue") == RESULT_SUCCESS) { 370 if (lockdown_check_result(dict, "GetValue") == RESULT_SUCCESS) {
375 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); 371 debug_info("success");
376 ret = LOCKDOWN_E_SUCCESS; 372 ret = LOCKDOWN_E_SUCCESS;
377 } 373 }
378 if (ret != LOCKDOWN_E_SUCCESS) { 374 if (ret != LOCKDOWN_E_SUCCESS) {
@@ -383,7 +379,7 @@ lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *dom
383 plist_t value_node = plist_dict_get_item(dict, "Value"); 379 plist_t value_node = plist_dict_get_item(dict, "Value");
384 380
385 if (value_node) { 381 if (value_node) {
386 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: has a value\n", __func__); 382 debug_info("has a value");
387 *value = plist_copy(value_node); 383 *value = plist_copy(value_node);
388 } 384 }
389 385
@@ -410,6 +406,7 @@ lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *dom
410 406
411 /* setup request plist */ 407 /* setup request plist */
412 dict = plist_new_dict(); 408 dict = plist_new_dict();
409 plist_dict_add_label(dict, client->label);
413 if (domain) { 410 if (domain) {
414 plist_dict_insert_item(dict,"Domain", plist_new_string(domain)); 411 plist_dict_insert_item(dict,"Domain", plist_new_string(domain));
415 } 412 }
@@ -434,7 +431,7 @@ lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *dom
434 return ret; 431 return ret;
435 432
436 if (lockdown_check_result(dict, "SetValue") == RESULT_SUCCESS) { 433 if (lockdown_check_result(dict, "SetValue") == RESULT_SUCCESS) {
437 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); 434 debug_info("success");
438 ret = LOCKDOWN_E_SUCCESS; 435 ret = LOCKDOWN_E_SUCCESS;
439 } 436 }
440 437
@@ -467,6 +464,7 @@ lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char *
467 464
468 /* setup request plist */ 465 /* setup request plist */
469 dict = plist_new_dict(); 466 dict = plist_new_dict();
467 plist_dict_add_label(dict, client->label);
470 if (domain) { 468 if (domain) {
471 plist_dict_insert_item(dict,"Domain", plist_new_string(domain)); 469 plist_dict_insert_item(dict,"Domain", plist_new_string(domain));
472 } 470 }
@@ -490,7 +488,7 @@ lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char *
490 return ret; 488 return ret;
491 489
492 if (lockdown_check_result(dict, "RemoveValue") == RESULT_SUCCESS) { 490 if (lockdown_check_result(dict, "RemoveValue") == RESULT_SUCCESS) {
493 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); 491 debug_info("success");
494 ret = LOCKDOWN_E_SUCCESS; 492 ret = LOCKDOWN_E_SUCCESS;
495 } 493 }
496 494
@@ -572,44 +570,85 @@ lockdownd_error_t lockdownd_get_device_name(lockdownd_client_t client, char **de
572 return ret; 570 return ret;
573} 571}
574 572
575/** Creates a lockdownd client for the give iPhone 573/** Creates a lockdownd client for the device.
576 * 574 *
577 * @param phone The iPhone to create a lockdownd client for 575 * @param phone The device to create a lockdownd client for
578 * @param client The pointer to the location of the new lockdownd_client 576 * @param client The pointer to the location of the new lockdownd_client
577 * @param label The label to use for communication. Usually the program name
579 * 578 *
580 * @return an error code (LOCKDOWN_E_SUCCESS on success) 579 * @return an error code (LOCKDOWN_E_SUCCESS on success)
581 */ 580 */
582lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_t *client) 581lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_t *client, const char *label)
583{ 582{
584 if (!client) 583 if (!client)
585 return LOCKDOWN_E_INVALID_ARG; 584 return LOCKDOWN_E_INVALID_ARG;
585
586 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; 586 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
587 char *host_id = NULL;
588 587
589 iphone_connection_t connection; 588 property_list_service_client_t plistclient = NULL;
590 if (iphone_device_connect(device, 0xf27e, &connection) != IPHONE_E_SUCCESS) { 589 if (property_list_service_client_new(device, 0xf27e, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
591 log_debug_msg("%s: could not connect to lockdownd (device %s)\n", __func__, device->uuid); 590 debug_info("could not connect to lockdownd (device %s)", device->uuid);
592 return LOCKDOWN_E_MUX_ERROR; 591 return LOCKDOWN_E_MUX_ERROR;
593 } 592 }
594 593
595 lockdownd_client_t client_loc = (lockdownd_client_t) malloc(sizeof(struct lockdownd_client_int)); 594 lockdownd_client_t client_loc = (lockdownd_client_t) malloc(sizeof(struct lockdownd_client_int));
596 client_loc->connection = connection; 595 client_loc->parent = plistclient;
597 client_loc->ssl_session = NULL; 596 client_loc->ssl_enabled = 0;
598 client_loc->ssl_certificate = NULL;
599 client_loc->in_SSL = 0;
600 client_loc->session_id = NULL; 597 client_loc->session_id = NULL;
601 client_loc->uuid = NULL; 598 client_loc->uuid = NULL;
599 client_loc->label = NULL;
600 if (label != NULL)
601 strdup(label);
602
603 if (LOCKDOWN_E_SUCCESS == ret) {
604 *client = client_loc;
605 } else {
606 lockdownd_client_free(client_loc);
607 }
608
609 return ret;
610}
611
612/** Creates a lockdownd client for the device and starts initial handshake.
613 * The handshake consists of query_type, validate_pair, pair and
614 * start_session calls.
615 *
616 * @param phone The device to create a lockdownd client for
617 * @param client The pointer to the location of the new lockdownd_client
618 * @param label The label to use for communication. Usually the program name
619 *
620 * @return an error code (LOCKDOWN_E_SUCCESS on success)
621 */
622lockdownd_error_t lockdownd_client_new_with_handshake(iphone_device_t device, lockdownd_client_t *client, const char *label)
623{
624 if (!client)
625 return LOCKDOWN_E_INVALID_ARG;
626
627 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
628 lockdownd_client_t client_loc = NULL;
629 char *host_id = NULL;
630 char *type = NULL;
602 631
603 if (LOCKDOWN_E_SUCCESS != lockdownd_query_type(client_loc)) { 632
604 log_debug_msg("%s: QueryType failed in the lockdownd client.\n", __func__); 633 ret = lockdownd_client_new(device, &client_loc, label);
634
635 /* perform handshake */
636 if (LOCKDOWN_E_SUCCESS != lockdownd_query_type(client_loc, &type)) {
637 debug_info("QueryType failed in the lockdownd client.");
605 ret = LOCKDOWN_E_NOT_ENOUGH_DATA; 638 ret = LOCKDOWN_E_NOT_ENOUGH_DATA;
639 } else {
640 if (strcmp("com.apple.mobile.lockdown", type)) {
641 debug_info("Warning QueryType request returned \"%s\".", type);
642 }
643 if (type)
644 free(type);
606 } 645 }
607 646
608 ret = iphone_device_get_uuid(device, &client_loc->uuid); 647 ret = iphone_device_get_uuid(device, &client_loc->uuid);
609 if (LOCKDOWN_E_SUCCESS != ret) { 648 if (LOCKDOWN_E_SUCCESS != ret) {
610 log_debug_msg("%s: failed to get device uuid.\n", __func__); 649 debug_info("failed to get device uuid.");
611 } 650 }
612 log_debug_msg("%s: device uuid: %s\n", __func__, client_loc->uuid); 651 debug_info("device uuid: %s", client_loc->uuid);
613 652
614 userpref_get_host_id(&host_id); 653 userpref_get_host_id(&host_id);
615 if (LOCKDOWN_E_SUCCESS == ret && !host_id) { 654 if (LOCKDOWN_E_SUCCESS == ret && !host_id) {
@@ -617,77 +656,135 @@ lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_
617 } 656 }
618 657
619 if (LOCKDOWN_E_SUCCESS == ret && !userpref_has_device_public_key(client_loc->uuid)) 658 if (LOCKDOWN_E_SUCCESS == ret && !userpref_has_device_public_key(client_loc->uuid))
620 ret = lockdownd_pair(client_loc, host_id); 659 ret = lockdownd_pair(client_loc, NULL);
660
661 /* in any case, we need to validate pairing to receive trusted host status */
662 ret = lockdownd_validate_pair(client_loc, NULL);
621 663
622 if (LOCKDOWN_E_SUCCESS == ret) { 664 if (LOCKDOWN_E_SUCCESS == ret) {
623 ret = lockdownd_start_ssl_session(client_loc, host_id); 665 ret = lockdownd_start_session(client_loc, host_id, NULL, NULL);
624 if (LOCKDOWN_E_SUCCESS != ret) { 666 if (LOCKDOWN_E_SUCCESS != ret) {
625 ret = LOCKDOWN_E_SSL_ERROR; 667 debug_info("Session opening failed.");
626 log_debug_msg("%s: SSL Session opening failed.\n", __func__);
627 } 668 }
628 669
629 if (host_id) { 670 if (host_id) {
630 free(host_id); 671 free(host_id);
631 host_id = NULL; 672 host_id = NULL;
632 } 673 }
674 }
675
676 if (LOCKDOWN_E_SUCCESS == ret) {
677 *client = client_loc;
678 } else {
679 lockdownd_client_free(client_loc);
680 }
633 681
634 if (LOCKDOWN_E_SUCCESS == ret) 682 return ret;
635 *client = client_loc; 683}
684
685static plist_t lockdownd_pair_record_to_plist(lockdownd_pair_record_t pair_record)
686{
687 if (!pair_record)
688 return NULL;
689
690 char *host_id_loc = pair_record->host_id;
691
692 /* setup request plist */
693 plist_t dict = plist_new_dict();
694 plist_dict_insert_item(dict, "DeviceCertificate", plist_new_data(pair_record->device_certificate, strlen(pair_record->device_certificate)));
695 plist_dict_insert_item(dict, "HostCertificate", plist_new_data(pair_record->host_certificate, strlen(pair_record->host_certificate)));
696 if (!pair_record->host_id)
697 userpref_get_host_id(&host_id_loc);
698 plist_dict_insert_item(dict, "HostID", plist_new_string(host_id_loc));
699 plist_dict_insert_item(dict, "RootCertificate", plist_new_data(pair_record->root_certificate, strlen(pair_record->root_certificate)));
700
701 if (!pair_record->host_id)
702 free(host_id_loc);
703
704 return dict;
705}
706
707static lockdownd_error_t generate_pair_record_plist(gnutls_datum_t public_key, char *host_id, plist_t *pair_record_plist)
708{
709 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
710
711 gnutls_datum_t device_cert = { NULL, 0 };
712 gnutls_datum_t host_cert = { NULL, 0 };
713 gnutls_datum_t root_cert = { NULL, 0 };
714
715 ret = lockdownd_gen_pair_cert(public_key, &device_cert, &host_cert, &root_cert);
716 if (ret != LOCKDOWN_E_SUCCESS) {
717 return ret;
636 } 718 }
637 719
720 char *host_id_loc = host_id;
721
722 if (!host_id)
723 userpref_get_host_id(&host_id_loc);
724
725 /* setup request plist */
726 *pair_record_plist = plist_new_dict();
727 plist_dict_insert_item(*pair_record_plist, "DeviceCertificate", plist_new_data((const char*)device_cert.data, device_cert.size));
728 plist_dict_insert_item(*pair_record_plist, "HostCertificate", plist_new_data((const char*)host_cert.data, host_cert.size));
729 plist_dict_insert_item(*pair_record_plist, "HostID", plist_new_string(host_id_loc));
730 plist_dict_insert_item(*pair_record_plist, "RootCertificate", plist_new_data((const char*)root_cert.data, root_cert.size));
731
732 if (!host_id)
733 free(host_id_loc);
734
638 return ret; 735 return ret;
639} 736}
640 737
641/** Function used internally by lockdownd_pair() and lockdownd_validate_pair() 738/** Function used internally by lockdownd_pair() and lockdownd_validate_pair()
642 * 739 *
643 * @param client The lockdown client to pair with. 740 * @param client The lockdown client to pair with.
644 * @param host_id The HostID to use for pairing. If NULL is passed, then 741 * @param pair_record The pair record to use for pairing. If NULL is passed, then
645 * the HostID of the current machine is used. A new HostID will be 742 * the pair records from the current machine are used. New records will be
646 * generated automatically when pairing is done for the first time. 743 * generated automatically when pairing is done for the first time.
647 * @param verb This is either "Pair" or "ValidatePair". 744 * @param verb This is either "Pair", "ValidatePair" or "Unpair".
648 * 745 *
649 * @return an error code (LOCKDOWN_E_SUCCESS on success) 746 * @return an error code (LOCKDOWN_E_SUCCESS on success)
650 */ 747 */
651static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host_id, const char *verb) 748static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record, const char *verb)
652{ 749{
653 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 750 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
654 plist_t dict = NULL; 751 plist_t dict = NULL;
655 plist_t dict_record = NULL; 752 plist_t dict_record = NULL;
656
657 gnutls_datum_t device_cert = { NULL, 0 };
658 gnutls_datum_t host_cert = { NULL, 0 };
659 gnutls_datum_t root_cert = { NULL, 0 };
660 gnutls_datum_t public_key = { NULL, 0 }; 753 gnutls_datum_t public_key = { NULL, 0 };
754 int pairing_mode = 0; /* 0 = libiphone, 1 = external */
661 755
662 char *host_id_loc = host_id; 756 if (pair_record && pair_record->host_id) {
663 757 /* valid pair_record passed? */
664 ret = lockdownd_get_device_public_key(client, &public_key); 758 if (!pair_record->device_certificate || !pair_record->host_certificate || !pair_record->root_certificate) {
665 if (ret != LOCKDOWN_E_SUCCESS) { 759 return LOCKDOWN_E_PLIST_ERROR;
666 log_debug_msg("%s: device refused to send public key.\n", __func__); 760 }
667 return ret;
668 }
669 log_debug_msg("%s: device public key follows:\n%s\n", __func__, public_key.data);
670 761
671 ret = lockdownd_gen_pair_cert(public_key, &device_cert, &host_cert, &root_cert); 762 /* use passed pair_record */
672 if (ret != LOCKDOWN_E_SUCCESS) { 763 dict_record = lockdownd_pair_record_to_plist(pair_record);
673 free(public_key.data);
674 return ret;
675 }
676 764
677 if (!host_id) { 765 pairing_mode = 1;
678 userpref_get_host_id(&host_id_loc); 766 } else {
767 ret = lockdownd_get_device_public_key(client, &public_key);
768 if (ret != LOCKDOWN_E_SUCCESS) {
769 if (public_key.data)
770 free(public_key.data);
771 debug_info("device refused to send public key.");
772 return ret;
773 }
774 debug_info("device public key follows:\n%s", public_key.data);
775 /* get libiphone pair_record */
776 ret = generate_pair_record_plist(public_key, NULL, &dict_record);
777 if (ret != LOCKDOWN_E_SUCCESS) {
778 if (dict_record)
779 plist_free(dict_record);
780 return ret;
781 }
679 } 782 }
680 783
681 /* Setup Pair request plist */ 784 /* Setup Pair request plist */
682 dict = plist_new_dict(); 785 dict = plist_new_dict();
683 dict_record = plist_new_dict(); 786 plist_dict_add_label(dict, client->label);
684 plist_dict_insert_item(dict,"PairRecord", dict_record); 787 plist_dict_insert_item(dict,"PairRecord", dict_record);
685
686 plist_dict_insert_item(dict_record, "DeviceCertificate", plist_new_data((const char*)device_cert.data, device_cert.size));
687 plist_dict_insert_item(dict_record, "HostCertificate", plist_new_data((const char*)host_cert.data, host_cert.size));
688 plist_dict_insert_item(dict_record, "HostID", plist_new_string(host_id_loc));
689 plist_dict_insert_item(dict_record, "RootCertificate", plist_new_data((const char*)root_cert.data, root_cert.size));
690
691 plist_dict_insert_item(dict, "Request", plist_new_string(verb)); 788 plist_dict_insert_item(dict, "Request", plist_new_string(verb));
692 789
693 /* send to iPhone */ 790 /* send to iPhone */
@@ -695,10 +792,6 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host
695 plist_free(dict); 792 plist_free(dict);
696 dict = NULL; 793 dict = NULL;
697 794
698 if (!host_id) {
699 free(host_id_loc);
700 }
701
702 if (ret != LOCKDOWN_E_SUCCESS) 795 if (ret != LOCKDOWN_E_SUCCESS)
703 return ret; 796 return ret;
704 797
@@ -711,17 +804,40 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host
711 if (lockdown_check_result(dict, verb) != RESULT_SUCCESS) { 804 if (lockdown_check_result(dict, verb) != RESULT_SUCCESS) {
712 ret = LOCKDOWN_E_PAIRING_FAILED; 805 ret = LOCKDOWN_E_PAIRING_FAILED;
713 } 806 }
714 plist_free(dict);
715 dict = NULL;
716 807
717 /* store public key in config if pairing succeeded */ 808 /* if pairing succeeded */
718 if (ret == LOCKDOWN_E_SUCCESS) { 809 if (ret == LOCKDOWN_E_SUCCESS) {
719 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: %s success\n", __func__, verb); 810 debug_info("%s success", verb);
720 userpref_set_device_public_key(client->uuid, public_key); 811 if (!pairing_mode) {
812 if (!strcmp("Unpair", verb)) {
813 /* remove public key from config */
814 userpref_remove_device_public_key(client->uuid);
815 } else {
816 /* store public key in config */
817 userpref_set_device_public_key(client->uuid, public_key);
818 }
819 }
721 } else { 820 } else {
722 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: %s failure\n", __func__, verb); 821 debug_info("%s failure", verb);
822 plist_t error_node = NULL;
823 /* verify error condition */
824 error_node = plist_dict_get_item(dict, "Error");
825 if (error_node) {
826 char *value = NULL;
827 plist_get_string_val(error_node, &value);
828 /* the first pairing fails if the device is password protected */
829 if (value && !strcmp(value, "PasswordProtected")) {
830 ret = LOCKDOWN_E_PASSWORD_PROTECTED;
831 free(value);
832 }
833 plist_free(error_node);
834 error_node = NULL;
835 }
723 } 836 }
724 free(public_key.data); 837 plist_free(dict);
838 dict = NULL;
839 if (public_key.data)
840 free(public_key.data);
725 return ret; 841 return ret;
726} 842}
727 843
@@ -730,15 +846,15 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host
730 * It's part of the lockdownd handshake. 846 * It's part of the lockdownd handshake.
731 * 847 *
732 * @param client The lockdown client to pair with. 848 * @param client The lockdown client to pair with.
733 * @param host_id The HostID to use for pairing. If NULL is passed, then 849 * @param pair_record The pair record to use for pairing. If NULL is passed, then
734 * the HostID of the current machine is used. A new HostID will be 850 * the pair records from the current machine are used. New records will be
735 * generated automatically when pairing is done for the first time. 851 * generated automatically when pairing is done for the first time.
736 * 852 *
737 * @return an error code (LOCKDOWN_E_SUCCESS on success) 853 * @return an error code (LOCKDOWN_E_SUCCESS on success)
738 */ 854 */
739lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id) 855lockdownd_error_t lockdownd_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record)
740{ 856{
741 return lockdownd_do_pair(client, host_id, "Pair"); 857 return lockdownd_do_pair(client, pair_record, "Pair");
742} 858}
743 859
744/** 860/**
@@ -747,15 +863,31 @@ lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id)
747 * It's part of the lockdownd handshake. 863 * It's part of the lockdownd handshake.
748 * 864 *
749 * @param client The lockdown client to pair with. 865 * @param client The lockdown client to pair with.
750 * @param host_id The HostID to use for pairing. If NULL is passed, then 866 * @param pair_record The pair record to validate pairing with. If NULL is
751 * the HostID of the current machine is used. A new HostID will be 867 * passed, then the pair records from the current machine are used.
752 * generated automatically when pairing is done for the first time. 868 * New records will be generated automatically when pairing is done
869 * for the first time.
753 * 870 *
754 * @return an error code (LOCKDOWN_E_SUCCESS on success) 871 * @return an error code (LOCKDOWN_E_SUCCESS on success)
755 */ 872 */
756lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, char *host_id) 873lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record)
757{ 874{
758 return lockdownd_do_pair(client, host_id, "ValidatePair"); 875 return lockdownd_do_pair(client, pair_record, "ValidatePair");
876}
877
878/**
879 * Unpairs the device with the given HostID and removes the pairing records
880 * from the device and host.
881 *
882 * @param client The lockdown client to pair with.
883 * @param pair_record The pair record to use for unpair. If NULL is passed, then
884 * the pair records from the current machine are used.
885 *
886 * @return an error code (LOCKDOWN_E_SUCCESS on success)
887 */
888lockdownd_error_t lockdownd_unpair(lockdownd_client_t client, lockdownd_pair_record_t pair_record)
889{
890 return lockdownd_do_pair(client, pair_record, "Unpair");
759} 891}
760 892
761/** 893/**
@@ -773,9 +905,10 @@ lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client)
773 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 905 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
774 906
775 plist_t dict = plist_new_dict(); 907 plist_t dict = plist_new_dict();
908 plist_dict_add_label(dict, client->label);
776 plist_dict_insert_item(dict,"Request", plist_new_string("EnterRecovery")); 909 plist_dict_insert_item(dict,"Request", plist_new_string("EnterRecovery"));
777 910
778 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: telling device to enter recovery mode\n", __func__); 911 debug_info("telling device to enter recovery mode");
779 912
780 ret = lockdownd_send(client, dict); 913 ret = lockdownd_send(client, dict);
781 plist_free(dict); 914 plist_free(dict);
@@ -784,7 +917,7 @@ lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client)
784 ret = lockdownd_recv(client, &dict); 917 ret = lockdownd_recv(client, &dict);
785 918
786 if (lockdown_check_result(dict, "EnterRecovery") == RESULT_SUCCESS) { 919 if (lockdown_check_result(dict, "EnterRecovery") == RESULT_SUCCESS) {
787 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); 920 debug_info("success");
788 ret = LOCKDOWN_E_SUCCESS; 921 ret = LOCKDOWN_E_SUCCESS;
789 } 922 }
790 plist_free(dict); 923 plist_free(dict);
@@ -808,9 +941,10 @@ lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client)
808 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 941 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
809 942
810 plist_t dict = plist_new_dict(); 943 plist_t dict = plist_new_dict();
944 plist_dict_add_label(dict, client->label);
811 plist_dict_insert_item(dict,"Request", plist_new_string("Goodbye")); 945 plist_dict_insert_item(dict,"Request", plist_new_string("Goodbye"));
812 946
813 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__); 947 debug_info("called");
814 948
815 ret = lockdownd_send(client, dict); 949 ret = lockdownd_send(client, dict);
816 plist_free(dict); 950 plist_free(dict);
@@ -818,12 +952,12 @@ lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client)
818 952
819 ret = lockdownd_recv(client, &dict); 953 ret = lockdownd_recv(client, &dict);
820 if (!dict) { 954 if (!dict) {
821 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: did not get goodbye response back\n", __func__); 955 debug_info("did not get goodbye response back");
822 return LOCKDOWN_E_PLIST_ERROR; 956 return LOCKDOWN_E_PLIST_ERROR;
823 } 957 }
824 958
825 if (lockdown_check_result(dict, "Goodbye") == RESULT_SUCCESS) { 959 if (lockdown_check_result(dict, "Goodbye") == RESULT_SUCCESS) {
826 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); 960 debug_info("success");
827 ret = LOCKDOWN_E_SUCCESS; 961 ret = LOCKDOWN_E_SUCCESS;
828 } 962 }
829 plist_free(dict); 963 plist_free(dict);
@@ -879,7 +1013,7 @@ lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datu
879 asn1_delete_structure(&pkcs1); 1013 asn1_delete_structure(&pkcs1);
880 } 1014 }
881 1015
882 /* now generate certifcates */ 1016 /* now generate certificates */
883 if (LOCKDOWN_E_SUCCESS == ret && 0 != modulus.size && 0 != exponent.size) { 1017 if (LOCKDOWN_E_SUCCESS == ret && 0 != modulus.size && 0 != exponent.size) {
884 1018
885 gnutls_global_init(); 1019 gnutls_global_init();
@@ -973,24 +1107,29 @@ lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datu
973 * and if the device requires it, switches to SSL mode. 1107 * and if the device requires it, switches to SSL mode.
974 * 1108 *
975 * @param client The lockdownd client 1109 * @param client The lockdownd client
976 * @param HostID The HostID used with this phone 1110 * @param host_id The HostID of the computer
1111 * @param session_id The session_id of the created session
1112 * @param ssl_enabled Whether SSL communication is used in the session
977 * 1113 *
978 * @return an error code (LOCKDOWN_E_SUCCESS on success) 1114 * @return an error code (LOCKDOWN_E_SUCCESS on success)
979 */ 1115 */
980lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const char *HostID) 1116lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char *host_id, char **session_id, int *ssl_enabled)
981{ 1117{
1118 lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
982 plist_t dict = NULL; 1119 plist_t dict = NULL;
983 uint32_t return_me = 0;
984 1120
985 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 1121 if (!client || !host_id)
1122 ret = LOCKDOWN_E_INVALID_ARG;
1123
1124 /* if we have a running session, stop current one first */
986 if (client->session_id) { 1125 if (client->session_id) {
987 free(client->session_id); 1126 lockdownd_stop_session(client, client->session_id);
988 client->session_id = NULL;
989 } 1127 }
990 1128
991 /* Setup DevicePublicKey request plist */ 1129 /* setup request plist */
992 dict = plist_new_dict(); 1130 dict = plist_new_dict();
993 plist_dict_insert_item(dict,"HostID", plist_new_string(HostID)); 1131 plist_dict_add_label(dict, client->label);
1132 plist_dict_insert_item(dict,"HostID", plist_new_string(host_id));
994 plist_dict_insert_item(dict,"Request", plist_new_string("StartSession")); 1133 plist_dict_insert_item(dict,"Request", plist_new_string("StartSession"));
995 1134
996 ret = lockdownd_send(client, dict); 1135 ret = lockdownd_send(client, dict);
@@ -1010,183 +1149,54 @@ lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const c
1010 if (error_node && PLIST_STRING == plist_get_node_type(error_node)) { 1149 if (error_node && PLIST_STRING == plist_get_node_type(error_node)) {
1011 char *error = NULL; 1150 char *error = NULL;
1012 plist_get_string_val(error_node, &error); 1151 plist_get_string_val(error_node, &error);
1013
1014 if (!strcmp(error, "InvalidHostID")) { 1152 if (!strcmp(error, "InvalidHostID")) {
1015 /* hostid is unknown. Pair and try again */ 1153 ret = LOCKDOWN_E_INVALID_HOST_ID;
1016 char *host_id = NULL;
1017 userpref_get_host_id(&host_id);
1018
1019 if (LOCKDOWN_E_SUCCESS == lockdownd_pair(client, host_id) ) {
1020 /* start session again */
1021 plist_free(dict);
1022 dict = plist_new_dict();
1023 plist_dict_insert_item(dict,"HostID", plist_new_string(HostID));
1024 plist_dict_insert_item(dict,"Request", plist_new_string("StartSession"));
1025
1026 ret = lockdownd_send(client, dict);
1027 plist_free(dict);
1028 dict = NULL;
1029
1030 ret = lockdownd_recv(client, &dict);
1031 }
1032 free(host_id);
1033 } 1154 }
1034 free(error); 1155 free(error);
1035 } 1156 }
1036 } 1157 } else {
1037 1158 uint8_t use_ssl = 0;
1038 ret = LOCKDOWN_E_SSL_ERROR;
1039
1040 int session_ok = 0;
1041 uint8_t UseSSL = 0;
1042 1159
1043 if (lockdown_check_result(dict, "StartSession") == RESULT_SUCCESS) {
1044 plist_t enable_ssl = plist_dict_get_item(dict, "EnableSessionSSL"); 1160 plist_t enable_ssl = plist_dict_get_item(dict, "EnableSessionSSL");
1045 if (enable_ssl && (plist_get_node_type(enable_ssl) == PLIST_BOOLEAN)) { 1161 if (enable_ssl && (plist_get_node_type(enable_ssl) == PLIST_BOOLEAN)) {
1046 plist_get_bool_val(enable_ssl, &UseSSL); 1162 plist_get_bool_val(enable_ssl, &use_ssl);
1047 } 1163 }
1048 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Session startup OK\n", __func__); 1164 debug_info("Session startup OK");
1049 session_ok = 1; 1165
1050 } 1166 if (ssl_enabled != NULL)
1051 if (session_ok && !UseSSL) { 1167 *ssl_enabled = use_ssl;
1052 client->in_SSL = 0; 1168
1053 ret = LOCKDOWN_E_SUCCESS; 1169 /* store session id, we need it for StopSession */
1054 } else if (session_ok) { 1170 plist_t session_node = plist_dict_get_item(dict, "SessionID");
1055 // Set up GnuTLS... 1171 if (session_node && (plist_get_node_type(session_node) == PLIST_STRING)) {
1056 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Switching to SSL mode\n", __func__); 1172 plist_get_string_val(session_node, &client->session_id);
1057 errno = 0;
1058 gnutls_global_init();
1059 //gnutls_anon_allocate_client_credentials(&anoncred);
1060 gnutls_certificate_allocate_credentials(&client->ssl_certificate);
1061 gnutls_certificate_set_x509_trust_file(client->ssl_certificate, "hostcert.pem", GNUTLS_X509_FMT_PEM);
1062 gnutls_init(&client->ssl_session, GNUTLS_CLIENT);
1063 {
1064 int protocol_priority[16] = { GNUTLS_SSL3, 0 };
1065 int kx_priority[16] = { GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA, 0 };
1066 int cipher_priority[16] = { GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_AES_256_CBC, 0 };
1067 int mac_priority[16] = { GNUTLS_MAC_SHA1, GNUTLS_MAC_MD5, 0 };
1068 int comp_priority[16] = { GNUTLS_COMP_NULL, 0 };
1069
1070 gnutls_cipher_set_priority(client->ssl_session, cipher_priority);
1071 gnutls_compression_set_priority(client->ssl_session, comp_priority);
1072 gnutls_kx_set_priority(client->ssl_session, kx_priority);
1073 gnutls_protocol_set_priority(client->ssl_session, protocol_priority);
1074 gnutls_mac_set_priority(client->ssl_session, mac_priority);
1075 } 1173 }
1076 gnutls_credentials_set(client->ssl_session, GNUTLS_CRD_CERTIFICATE, client->ssl_certificate); // this part is killing me. 1174 if (client->session_id) {
1077 1175 debug_info("SessionID: %s", client->session_id);
1078 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 1...\n", __func__); 1176 if (session_id != NULL)
1079 gnutls_transport_set_ptr(client->ssl_session, (gnutls_transport_ptr_t) client); 1177 *session_id = strdup(client->session_id);
1080 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 2...\n", __func__);
1081 gnutls_transport_set_push_function(client->ssl_session, (gnutls_push_func) & lockdownd_secuwrite);
1082 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 3...\n", __func__);
1083 gnutls_transport_set_pull_function(client->ssl_session, (gnutls_pull_func) & lockdownd_securead);
1084 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS step 4 -- now handshaking...\n", __func__);
1085 if (errno)
1086 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: WARN: errno says %s before handshake!\n", __func__, strerror(errno));
1087 return_me = gnutls_handshake(client->ssl_session);
1088 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS handshake done...\n", __func__);
1089
1090 if (return_me != GNUTLS_E_SUCCESS) {
1091 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: GnuTLS reported something wrong.\n", __func__);
1092 gnutls_perror(return_me);
1093 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: oh.. errno says %s\n", __func__, strerror(errno));
1094 return LOCKDOWN_E_SSL_ERROR;
1095 } else { 1178 } else {
1096 client->in_SSL = 1; 1179 debug_info("Failed to get SessionID!");
1180 }
1181 debug_info("Enable SSL Session: %s", (use_ssl?"true":"false"));
1182 if (use_ssl) {
1183 ret = property_list_service_enable_ssl(client->parent);
1184 if (ret == PROPERTY_LIST_SERVICE_E_SUCCESS) {
1185 client->ssl_enabled = 1;
1186 } else {
1187 ret = LOCKDOWN_E_SSL_ERROR;
1188 client->ssl_enabled = 0;
1189 }
1190 } else {
1191 client->ssl_enabled = 0;
1097 ret = LOCKDOWN_E_SUCCESS; 1192 ret = LOCKDOWN_E_SUCCESS;
1098 } 1193 }
1099 } 1194 }
1100 /* store session id, we need it for StopSession */ 1195
1101 plist_t session_node = plist_dict_get_item(dict, "SessionID");
1102 if (session_node && (plist_get_node_type(session_node) == PLIST_STRING)) {
1103 plist_get_string_val(session_node, &client->session_id);
1104 }
1105 if (client->session_id) {
1106 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: SessionID: %s\n", __func__, client->session_id);
1107 } else {
1108 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Failed to get SessionID!\n", __func__);
1109 }
1110 plist_free(dict); 1196 plist_free(dict);
1111 dict = NULL; 1197 dict = NULL;
1112 1198
1113 if (ret == LOCKDOWN_E_SUCCESS) 1199 return ret;
1114 return ret;
1115
1116 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: Apparently failed negotiating with lockdownd.\n", __func__);
1117 return LOCKDOWN_E_SSL_ERROR;
1118}
1119
1120/** gnutls callback for writing data to the iPhone.
1121 *
1122 * @param transport It's really the lockdownd client, but the method signature has to match
1123 * @param buffer The data to send
1124 * @param length The length of data to send in bytes
1125 *
1126 * @return The number of bytes sent
1127 */
1128ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size_t length)
1129{
1130 uint32_t bytes = 0;
1131 lockdownd_client_t client;
1132 client = (lockdownd_client_t) transport;
1133 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__);
1134 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: pre-send length = %zi\n", __func__, length);
1135 iphone_device_send(client->connection, buffer, length, &bytes);
1136 log_dbg_msg(DBGMASK_LOCKDOWND, "%s: post-send sent %i bytes\n", __func__, bytes);
1137 return bytes;
1138}
1139
1140/** gnutls callback for reading data from the iPhone
1141 *
1142 * @param transport It's really the lockdownd client, but the method signature has to match
1143 * @param buffer The buffer to store data in
1144 * @param length The length of data to read in bytes
1145 *
1146 * @return The number of bytes read
1147 */
1148ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_t length)
1149{
1150 int bytes = 0, pos_start_fill = 0;
1151 size_t tbytes = 0;
1152 int this_len = length;
1153 iphone_error_t res;
1154 lockdownd_client_t client;
1155 client = (lockdownd_client_t) transport;
1156 char *recv_buffer;
1157
1158 log_debug_msg("%s: pre-read client wants %zi bytes\n", __func__, length);
1159
1160 recv_buffer = (char *) malloc(sizeof(char) * this_len);
1161
1162 // repeat until we have the full data or an error occurs.
1163 do {
1164 if ((res = iphone_device_recv(client->connection, recv_buffer, this_len, (uint32_t*)&bytes)) != LOCKDOWN_E_SUCCESS) {
1165 log_debug_msg("%s: ERROR: usbmux_recv returned %d\n", __func__, res);
1166 return res;
1167 }
1168 log_debug_msg("%s: post-read we got %i bytes\n", __func__, bytes);
1169
1170 // increase read count
1171 tbytes += bytes;
1172
1173 // fill the buffer with what we got right now
1174 memcpy(buffer + pos_start_fill, recv_buffer, bytes);
1175 pos_start_fill += bytes;
1176
1177 if (tbytes >= length) {
1178 break;
1179 }
1180
1181 this_len = length - tbytes;
1182 log_debug_msg("%s: re-read trying to read missing %i bytes\n", __func__, this_len);
1183 } while (tbytes < length);
1184
1185 if (recv_buffer) {
1186 free(recv_buffer);
1187 }
1188
1189 return tbytes;
1190} 1200}
1191 1201
1192/** Command to start the desired service 1202/** Command to start the desired service
@@ -1197,7 +1207,7 @@ ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_
1197 1207
1198 * @return an error code (LOCKDOWN_E_SUCCESS on success) 1208 * @return an error code (LOCKDOWN_E_SUCCESS on success)
1199 */ 1209 */
1200lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *service, int *port) 1210lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *service, uint16_t *port)
1201{ 1211{
1202 if (!client || !service || !port) 1212 if (!client || !service || !port)
1203 return LOCKDOWN_E_INVALID_ARG; 1213 return LOCKDOWN_E_INVALID_ARG;
@@ -1206,17 +1216,18 @@ lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char
1206 userpref_get_host_id(&host_id); 1216 userpref_get_host_id(&host_id);
1207 if (!host_id) 1217 if (!host_id)
1208 return LOCKDOWN_E_INVALID_CONF; 1218 return LOCKDOWN_E_INVALID_CONF;
1209 if (!client->in_SSL && !lockdownd_start_ssl_session(client, host_id)) 1219 if (!client->session_id)
1210 return LOCKDOWN_E_SSL_ERROR; 1220 return LOCKDOWN_E_NO_RUNNING_SESSION;
1211 1221
1212 plist_t dict = NULL; 1222 plist_t dict = NULL;
1213 uint32_t port_loc = 0; 1223 uint16_t port_loc = 0;
1214 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; 1224 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
1215 1225
1216 free(host_id); 1226 free(host_id);
1217 host_id = NULL; 1227 host_id = NULL;
1218 1228
1219 dict = plist_new_dict(); 1229 dict = plist_new_dict();
1230 plist_dict_add_label(dict, client->label);
1220 plist_dict_insert_item(dict,"Request", plist_new_string("StartService")); 1231 plist_dict_insert_item(dict,"Request", plist_new_string("StartService"));
1221 plist_dict_insert_item(dict,"Service", plist_new_string(service)); 1232 plist_dict_insert_item(dict,"Service", plist_new_string(service));
1222 1233
@@ -1260,3 +1271,97 @@ lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char
1260 return ret; 1271 return ret;
1261} 1272}
1262 1273
1274/**
1275 * Activates the device. Only works within an open session.
1276 * The ActivationRecord plist dictionary must be obtained using the
1277 * activation protocol requesting from Apple's https webservice.
1278 *
1279 * @see http://iphone-docs.org/doku.php?id=docs:protocols:activation
1280 *
1281 * @param control The lockdown client
1282 * @param activation_record The activation record plist dictionary
1283 *
1284 * @return an error code (LOCKDOWN_E_SUCCESS on success)
1285 */
1286lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist_t activation_record)
1287{
1288 if (!client)
1289 return LOCKDOWN_E_INVALID_ARG;
1290
1291 if (!client->session_id)
1292 return LOCKDOWN_E_NO_RUNNING_SESSION;
1293
1294 if (!activation_record)
1295 return LOCKDOWN_E_INVALID_ARG;
1296
1297 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
1298
1299 plist_t dict = plist_new_dict();
1300 plist_dict_add_label(dict, client->label);
1301 plist_dict_insert_item(dict,"Request", plist_new_string("Activate"));
1302 plist_dict_insert_item(dict,"ActivationRecord", activation_record);
1303
1304 ret = lockdownd_send(client, dict);
1305 plist_free(dict);
1306 dict = NULL;
1307
1308 ret = lockdownd_recv(client, &dict);
1309 if (!dict) {
1310 debug_info("LOCKDOWN_E_PLIST_ERROR");
1311 return LOCKDOWN_E_PLIST_ERROR;
1312 }
1313
1314 ret = LOCKDOWN_E_ACTIVATION_FAILED;
1315 if (lockdown_check_result(dict, "Activate") == RESULT_SUCCESS) {
1316 debug_info("success");
1317 ret = LOCKDOWN_E_SUCCESS;
1318 }
1319 plist_free(dict);
1320 dict = NULL;
1321
1322 return ret;
1323}
1324
1325/**
1326 * Deactivates the device, returning it to the locked
1327 * “Activate with iTunes” screen.
1328 *
1329 * @param control The lockdown client
1330 *
1331 * @return an error code (LOCKDOWN_E_SUCCESS on success)
1332 */
1333lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client)
1334{
1335 if (!client)
1336 return LOCKDOWN_E_INVALID_ARG;
1337
1338 if (!client->session_id)
1339 return LOCKDOWN_E_NO_RUNNING_SESSION;
1340
1341 lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
1342
1343 plist_t dict = plist_new_dict();
1344 plist_dict_add_label(dict, client->label);
1345 plist_dict_insert_item(dict,"Request", plist_new_string("Deactivate"));
1346
1347 ret = lockdownd_send(client, dict);
1348 plist_free(dict);
1349 dict = NULL;
1350
1351 ret = lockdownd_recv(client, &dict);
1352 if (!dict) {
1353 debug_info("LOCKDOWN_E_PLIST_ERROR");
1354 return LOCKDOWN_E_PLIST_ERROR;
1355 }
1356
1357 ret = LOCKDOWN_E_UNKNOWN_ERROR;
1358 if (lockdown_check_result(dict, "Deactivate") == RESULT_SUCCESS) {
1359 debug_info("success");
1360 ret = LOCKDOWN_E_SUCCESS;
1361 }
1362 plist_free(dict);
1363 dict = NULL;
1364
1365 return ret;
1366}
1367