diff options
Diffstat (limited to 'src/lockdown.c')
-rw-r--r-- | src/lockdown.c | 191 |
1 files changed, 179 insertions, 12 deletions
diff --git a/src/lockdown.c b/src/lockdown.c index 2532999..24dd4a1 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -108,6 +108,21 @@ static int lockdown_check_result(plist_t dict, const char *query_match) } /** + * Adds a label key with the passed value to a plist dict node. + * + * @param plist The plist to add the key to + * @param label The value for the label key + * + */ +static void plist_dict_add_label(plist_t plist, const char *label) +{ + if (plist && label) { + if (plist_get_node_type(plist) == PLIST_DICT) + plist_dict_insert_item(plist, "Label", plist_new_string(label)); + } +} + +/** * Closes the lockdownd communication session, by sending * the StopSession Request to the device. * @@ -128,6 +143,7 @@ lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client) lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); + plist_dict_add_label(dict, client->label); plist_dict_insert_item(dict,"Request", plist_new_string("StopSession")); plist_dict_insert_item(dict,"SessionID", plist_new_string(client->session_id)); @@ -223,11 +239,27 @@ lockdownd_error_t lockdownd_client_free(lockdownd_client_t client) if (client->uuid) { free(client->uuid); } + if (client->label) { + free(client->label); + } free(client); return ret; } +/** + * Sets the label to send for requests to lockdownd. + * + * @param client The lockdown client + * @param label The label to set or NULL to disable + * + */ +void lockdownd_client_set_label(lockdownd_client_t client, const char *label) +{ + if (client) + client->label = strdup(label); +} + /** Polls the iPhone for lockdownd data. * * @param control The lockdownd client @@ -306,6 +338,7 @@ lockdownd_error_t lockdownd_query_type(lockdownd_client_t client) lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); + plist_dict_add_label(dict, client->label); plist_dict_insert_item(dict,"Request", plist_new_string("QueryType")); log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__); @@ -349,6 +382,7 @@ lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *dom /* setup request plist */ dict = plist_new_dict(); + plist_dict_add_label(dict, client->label); if (domain) { plist_dict_insert_item(dict,"Domain", plist_new_string(domain)); } @@ -410,6 +444,7 @@ lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, const char *dom /* setup request plist */ dict = plist_new_dict(); + plist_dict_add_label(dict, client->label); if (domain) { plist_dict_insert_item(dict,"Domain", plist_new_string(domain)); } @@ -467,6 +502,7 @@ lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, const char * /* setup request plist */ dict = plist_new_dict(); + plist_dict_add_label(dict, client->label); if (domain) { plist_dict_insert_item(dict,"Domain", plist_new_string(domain)); } @@ -576,10 +612,11 @@ lockdownd_error_t lockdownd_get_device_name(lockdownd_client_t client, char **de * * @param phone The iPhone to create a lockdownd client for * @param client The pointer to the location of the new lockdownd_client + * @param label The label to use for communication. Usually the program name * * @return an error code (LOCKDOWN_E_SUCCESS on success) */ -lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_t *client) +lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_t *client, const char *label) { if (!client) return LOCKDOWN_E_INVALID_ARG; @@ -599,6 +636,7 @@ lockdownd_error_t lockdownd_client_new(iphone_device_t device, lockdownd_client_ client_loc->in_SSL = 0; client_loc->session_id = NULL; client_loc->uuid = NULL; + client_loc->label = strdup(label); if (LOCKDOWN_E_SUCCESS != lockdownd_query_type(client_loc)) { log_debug_msg("%s: QueryType failed in the lockdownd client.\n", __func__); @@ -681,6 +719,7 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host /* Setup Pair request plist */ dict = plist_new_dict(); dict_record = plist_new_dict(); + plist_dict_add_label(dict, client->label); plist_dict_insert_item(dict,"PairRecord", dict_record); plist_dict_insert_item(dict_record, "DeviceCertificate", plist_new_data((const char*)device_cert.data, device_cert.size)); @@ -711,16 +750,36 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, char *host if (lockdown_check_result(dict, verb) != RESULT_SUCCESS) { ret = LOCKDOWN_E_PAIRING_FAILED; } - plist_free(dict); - dict = NULL; - /* store public key in config if pairing succeeded */ + /* if pairing succeeded */ if (ret == LOCKDOWN_E_SUCCESS) { log_dbg_msg(DBGMASK_LOCKDOWND, "%s: %s success\n", __func__, verb); - userpref_set_device_public_key(client->uuid, public_key); + if (!strcmp("Unpair", verb)) { + /* remove public key from config */ + userpref_remove_device_public_key(client->uuid); + } else { + /* store public key in config */ + userpref_set_device_public_key(client->uuid, public_key); + } } else { log_dbg_msg(DBGMASK_LOCKDOWND, "%s: %s failure\n", __func__, verb); + plist_t error_node = NULL; + /* verify error condition */ + error_node = plist_dict_get_item(dict, "Error"); + if (error_node) { + char *value = NULL; + plist_get_string_val(error_node, &value); + /* the first pairing fails if the device is password protected */ + if (value && !strcmp(value, "PasswordProtected")) { + ret = LOCKDOWN_E_PASSWORD_PROTECTED; + free(value); + } + plist_free(error_node); + error_node = NULL; + } } + plist_free(dict); + dict = NULL; free(public_key.data); return ret; } @@ -758,6 +817,21 @@ lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, char *host_ return lockdownd_do_pair(client, host_id, "ValidatePair"); } +/** + * Unpairs the device with the given HostID and removes the pairing records + * from the device and host. + * + * @param client The lockdown client to pair with. + * @param host_id The HostID to use for unpairing. If NULL is passed, then + * the HostID of the current machine is used. + * + * @return an error code (LOCKDOWN_E_SUCCESS on success) + */ +lockdownd_error_t lockdownd_unpair(lockdownd_client_t client, char *host_id) +{ + return lockdownd_do_pair(client, host_id, "Unpair"); +} + /** * Tells the device to immediately enter recovery mode. * @@ -773,6 +847,7 @@ lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client) lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); + plist_dict_add_label(dict, client->label); plist_dict_insert_item(dict,"Request", plist_new_string("EnterRecovery")); log_dbg_msg(DBGMASK_LOCKDOWND, "%s: telling device to enter recovery mode\n", __func__); @@ -808,6 +883,7 @@ lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client) lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); + plist_dict_add_label(dict, client->label); plist_dict_insert_item(dict,"Request", plist_new_string("Goodbye")); log_dbg_msg(DBGMASK_LOCKDOWND, "%s: called\n", __func__); @@ -977,7 +1053,7 @@ lockdownd_error_t lockdownd_gen_pair_cert(gnutls_datum_t public_key, gnutls_datu * * @return an error code (LOCKDOWN_E_SUCCESS on success) */ -lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const char *HostID) +lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const char *host_id) { plist_t dict = NULL; uint32_t return_me = 0; @@ -990,7 +1066,8 @@ lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const c /* Setup DevicePublicKey request plist */ dict = plist_new_dict(); - plist_dict_insert_item(dict,"HostID", plist_new_string(HostID)); + plist_dict_add_label(dict, client->label); + plist_dict_insert_item(dict,"HostID", plist_new_string(host_id)); plist_dict_insert_item(dict,"Request", plist_new_string("StartSession")); ret = lockdownd_send(client, dict); @@ -1013,14 +1090,15 @@ lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const c if (!strcmp(error, "InvalidHostID")) { /* hostid is unknown. Pair and try again */ - char *host_id = NULL; - userpref_get_host_id(&host_id); + char *host_id_new = NULL; + userpref_get_host_id(&host_id_new); - if (LOCKDOWN_E_SUCCESS == lockdownd_pair(client, host_id) ) { + if (LOCKDOWN_E_SUCCESS == lockdownd_pair(client, host_id_new) ) { /* start session again */ plist_free(dict); dict = plist_new_dict(); - plist_dict_insert_item(dict,"HostID", plist_new_string(HostID)); + plist_dict_add_label(dict, client->label); + plist_dict_insert_item(dict,"HostID", plist_new_string(host_id_new)); plist_dict_insert_item(dict,"Request", plist_new_string("StartSession")); ret = lockdownd_send(client, dict); @@ -1029,7 +1107,7 @@ lockdownd_error_t lockdownd_start_ssl_session(lockdownd_client_t client, const c ret = lockdownd_recv(client, &dict); } - free(host_id); + free(host_id_new); } free(error); } @@ -1217,6 +1295,7 @@ lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char host_id = NULL; dict = plist_new_dict(); + plist_dict_add_label(dict, client->label); plist_dict_insert_item(dict,"Request", plist_new_string("StartService")); plist_dict_insert_item(dict,"Service", plist_new_string(service)); @@ -1260,3 +1339,91 @@ lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char return ret; } +/** + * Activates the device. Only works within an open session. + * The ActivationRecord plist dictionary must be obtained using the + * activation protocol requesting from Apple's https webservice. + * + * @see http://iphone-docs.org/doku.php?id=docs:protocols:activation + * + * @param control The lockdown client + * @param activation_record The activation record plist dictionary + * + * @return an error code (LOCKDOWN_E_SUCCESS on success) + */ +lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist_t activation_record) +{ + if (!client) + return LOCKDOWN_E_INVALID_ARG; + + if (!activation_record) + return LOCKDOWN_E_INVALID_ARG; + + lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; + + plist_t dict = plist_new_dict(); + plist_dict_add_label(dict, client->label); + plist_dict_insert_item(dict,"Request", plist_new_string("Activate")); + plist_dict_insert_item(dict,"ActivationRecord", activation_record); + + ret = lockdownd_send(client, dict); + plist_free(dict); + dict = NULL; + + ret = lockdownd_recv(client, &dict); + if (!dict) { + log_dbg_msg(DBGMASK_LOCKDOWND, "%s: LOCKDOWN_E_PLIST_ERROR\n", __func__); + return LOCKDOWN_E_PLIST_ERROR; + } + + ret = LOCKDOWN_E_ACTIVATION_FAILED; + if (lockdown_check_result(dict, "Activate") == RESULT_SUCCESS) { + log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); + ret = LOCKDOWN_E_SUCCESS; + } + plist_free(dict); + dict = NULL; + + return ret; +} + +/** + * Deactivates the device, returning it to the locked + * “Activate with iTunes” screen. + * + * @param control The lockdown client + * + * @return an error code (LOCKDOWN_E_SUCCESS on success) + */ +lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client) +{ + if (!client) + return LOCKDOWN_E_INVALID_ARG; + + lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; + + plist_t dict = plist_new_dict(); + plist_dict_add_label(dict, client->label); + plist_dict_insert_item(dict,"Request", plist_new_string("Deactivate")); + + ret = lockdownd_send(client, dict); + plist_free(dict); + dict = NULL; + + ret = lockdownd_recv(client, &dict); + if (!dict) { + log_dbg_msg(DBGMASK_LOCKDOWND, "%s: LOCKDOWN_E_PLIST_ERROR\n", __func__); + return LOCKDOWN_E_PLIST_ERROR; + } + + ret = LOCKDOWN_E_UNKNOWN_ERROR; + if (lockdown_check_result(dict, "Deactivate") == RESULT_SUCCESS) { + log_dbg_msg(DBGMASK_LOCKDOWND, "%s: success\n", __func__); + ret = LOCKDOWN_E_SUCCESS; + } + plist_free(dict); + dict = NULL; + + return ret; +} + |