diff options
Diffstat (limited to 'src/lockdown.c')
| -rw-r--r-- | src/lockdown.c | 777 |
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 | */ | ||
| 118 | static 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 | */ |
| 118 | lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client) | 137 | lockdownd_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 | */ | ||
| 171 | static 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 | */ | ||
| 222 | void 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 | */ |
| 301 | lockdownd_error_t lockdownd_query_type(lockdownd_client_t client) | 290 | lockdownd_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 | */ |
| 582 | lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_t *client) | 581 | lockdownd_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 | */ | ||
| 622 | lockdownd_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 | |||
| 685 | static 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 | |||
| 707 | static 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 | */ |
| 651 | static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host_id, const char *verb) | 748 | static 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 | */ |
| 739 | lockdownd_error_t lockdownd_pair(lockdownd_client_t client, char *host_id) | 855 | lockdownd_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 | */ |
| 756 | lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, char *host_id) | 873 | lockdownd_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 | */ | ||
| 888 | lockdownd_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 | */ |
| 980 | lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const char *HostID) | 1116 | lockdownd_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 | */ | ||
| 1128 | ssize_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 | */ | ||
| 1148 | ssize_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 | */ |
| 1200 | lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *service, int *port) | 1210 | lockdownd_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 | */ | ||
| 1286 | lockdownd_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 | */ | ||
| 1333 | lockdownd_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 | |||
