/** * Sends the Goodbye request to restored signaling the end of communication. * * @param client The restore client * * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL, * RESTORE_E_PLIST_ERROR if the device did not acknowledge the request */ restored_error_t restored_goodbye(restored_client_t client) { if (!client) return RESTORE_E_INVALID_ARG; restored_error_t ret = RESTORE_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")); debug_info("called"); ret = restored_send(client, dict); plist_free(dict); dict = NULL; ret = restored_receive(client, &dict); if (!dict) { debug_info("did not get goodbye response back"); return RESTORE_E_PLIST_ERROR; } if (restored_check_result(dict) == RESULT_SUCCESS) { debug_info("success"); ret = RESTORE_E_SUCCESS; } plist_free(dict); dict = NULL; return ret; }
/** * Requests device to reboot. * * @param client The restored client * * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG if a parameter * is NULL */ restored_error_t restored_reboot(restored_client_t client) { if (!client) return RESTORE_E_INVALID_ARG; plist_t dict = NULL; restored_error_t ret = RESTORE_E_UNKNOWN_ERROR; dict = plist_new_dict(); plist_dict_add_label(dict, client->label); plist_dict_insert_item(dict,"Request", plist_new_string("Reboot")); /* send to device */ ret = restored_send(client, dict); plist_free(dict); dict = NULL; if (RESTORE_E_SUCCESS != ret) return ret; ret = restored_receive(client, &dict); if (RESTORE_E_SUCCESS != ret) return ret; if (!dict) return RESTORE_E_PLIST_ERROR; plist_free(dict); dict = NULL; return ret; }
LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_goodbye(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_set_item(dict,"Request", plist_new_string("Goodbye")); debug_info("called"); ret = lockdownd_send(client, dict); plist_free(dict); dict = NULL; ret = lockdownd_receive(client, &dict); if (!dict) { debug_info("did not get goodbye response back"); return LOCKDOWN_E_PLIST_ERROR; } if (lockdown_check_result(dict, "Goodbye") == RESULT_SUCCESS) { debug_info("success"); ret = LOCKDOWN_E_SUCCESS; } plist_free(dict); dict = NULL; return ret; }
LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client) { if (!client) return LOCKDOWN_E_INVALID_ARG; if (!client->session_id) return LOCKDOWN_E_NO_RUNNING_SESSION; lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_add_label(dict, client->label); plist_dict_set_item(dict,"Request", plist_new_string("Deactivate")); ret = lockdownd_send(client, dict); plist_free(dict); dict = NULL; ret = lockdownd_receive(client, &dict); if (!dict) { debug_info("LOCKDOWN_E_PLIST_ERROR"); return LOCKDOWN_E_PLIST_ERROR; } ret = LOCKDOWN_E_UNKNOWN_ERROR; if (lockdown_check_result(dict, "Deactivate") == RESULT_SUCCESS) { debug_info("success"); ret = LOCKDOWN_E_SUCCESS; } plist_free(dict); dict = NULL; return ret; }
LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_enter_recovery(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_set_item(dict,"Request", plist_new_string("EnterRecovery")); debug_info("telling device to enter recovery mode"); ret = lockdownd_send(client, dict); plist_free(dict); dict = NULL; ret = lockdownd_receive(client, &dict); if (lockdown_check_result(dict, "EnterRecovery") == RESULT_SUCCESS) { debug_info("success"); ret = LOCKDOWN_E_SUCCESS; } plist_free(dict); dict = NULL; return ret; }
LIBIMOBILEDEVICE_API restored_error_t restored_query_type(restored_client_t client, char **type, uint64_t *version) { if (!client) return RESTORE_E_INVALID_ARG; restored_error_t ret = RESTORE_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_add_label(dict, client->label); plist_dict_set_item(dict,"Request", plist_new_string("QueryType")); debug_info("called"); ret = restored_send(client, dict); plist_free(dict); dict = NULL; ret = restored_receive(client, &dict); if (RESTORE_E_SUCCESS != ret) return ret; ret = RESTORE_E_UNKNOWN_ERROR; plist_t type_node = plist_dict_get_item(dict, "Type"); if (type_node && (plist_get_node_type(type_node) == PLIST_STRING)) { char* typestr = NULL; /* save our device information info */ client->info = dict; plist_get_string_val(type_node, &typestr); debug_info("success with type %s", typestr); /* return the type if requested */ if (type) { *type = typestr; } else { free(typestr); } /* fetch the restore protocol version */ if (version) { plist_t version_node = plist_dict_get_item(dict, "RestoreProtocolVersion"); if (version_node && PLIST_UINT == plist_get_node_type(version_node)) { plist_get_uint_val(version_node, version); debug_info("restored protocol version %llu", *version); } else { return RESTORE_E_UNKNOWN_ERROR; } } ret = RESTORE_E_SUCCESS; } else { debug_info("hmm. QueryType response does not contain a type?!"); debug_plist(dict); plist_free(dict); } return ret; }
/** * Query the type of the service daemon. Depending on whether the device is * queried in normal mode or restore mode, different types will be returned. * * @param client The restored client * @param type The type returned by the service daemon. Pass NULL to ignore. * @param version The restore protocol version. Pass NULL to ignore. * * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL */ restored_error_t restored_query_type(restored_client_t client, char **type, uint64_t *version) { if (!client) return RESTORE_E_INVALID_ARG; restored_error_t ret = RESTORE_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")); debug_info("called"); ret = restored_send(client, dict); plist_free(dict); dict = NULL; ret = restored_receive(client, &dict); if (RESTORE_E_SUCCESS != ret) return ret; ret = RESTORE_E_UNKNOWN_ERROR; if (restored_check_result(dict) == RESULT_SUCCESS) { /* save our device information info */ client->info = dict; /* return the type if requested */ if (type) { plist_t type_node = plist_dict_get_item(dict, "Type"); if (type_node && PLIST_STRING == plist_get_node_type(type_node)) { plist_get_string_val(type_node, type); debug_info("success with type %s", *type); ret = RESTORE_E_SUCCESS; } else { return RESTORE_E_UNKNOWN_ERROR; } } /* fetch the restore protocol version */ if (version) { plist_t version_node = plist_dict_get_item(dict, "RestoreProtocolVersion"); if (version_node && PLIST_UINT == plist_get_node_type(version_node)) { plist_get_uint_val(version_node, version); debug_info("restored protocol version %llu", *version); ret = RESTORE_E_SUCCESS; } else { return RESTORE_E_UNKNOWN_ERROR; } } ret = RESTORE_E_SUCCESS; } return ret; }
LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, const char *domain, const char *key, plist_t *value) { if (!client) return LOCKDOWN_E_INVALID_ARG; plist_t dict = NULL; lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; /* setup request plist */ dict = plist_new_dict(); plist_dict_add_label(dict, client->label); if (domain) { plist_dict_set_item(dict,"Domain", plist_new_string(domain)); } if (key) { plist_dict_set_item(dict,"Key", plist_new_string(key)); } plist_dict_set_item(dict,"Request", plist_new_string("GetValue")); /* send to device */ ret = lockdownd_send(client, dict); plist_free(dict); dict = NULL; if (ret != LOCKDOWN_E_SUCCESS) return ret; /* Now get device's answer */ ret = lockdownd_receive(client, &dict); if (ret != LOCKDOWN_E_SUCCESS) return ret; if (lockdown_check_result(dict, "GetValue") == RESULT_SUCCESS) { debug_info("success"); ret = LOCKDOWN_E_SUCCESS; } else { ret = LOCKDOWN_E_UNKNOWN_ERROR; } if (ret != LOCKDOWN_E_SUCCESS) { plist_free(dict); return ret; } plist_t value_node = plist_dict_get_item(dict, "Value"); if (value_node) { debug_info("has a value"); *value = plist_copy(value_node); } plist_free(dict); return ret; }
LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, const char *session_id) { if (!client) return LOCKDOWN_E_INVALID_ARG; if (!session_id) { debug_info("no session_id given, cannot stop session"); 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_set_item(dict,"Request", plist_new_string("StopSession")); plist_dict_set_item(dict,"SessionID", plist_new_string(session_id)); debug_info("stopping session %s", session_id); ret = lockdownd_send(client, dict); plist_free(dict); dict = NULL; ret = lockdownd_receive(client, &dict); if (!dict) { debug_info("LOCKDOWN_E_PLIST_ERROR"); return LOCKDOWN_E_PLIST_ERROR; } ret = LOCKDOWN_E_UNKNOWN_ERROR; if (lockdown_check_result(dict, "StopSession") == RESULT_SUCCESS) { debug_info("success"); ret = LOCKDOWN_E_SUCCESS; } plist_free(dict); dict = NULL; if (client->session_id) { free(client->session_id); client->session_id = NULL; } if (client->ssl_enabled) { property_list_service_disable_ssl(client->parent); client->ssl_enabled = 0; } return ret; }
LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist_t activation_record) { if (!client) return LOCKDOWN_E_INVALID_ARG; if (!client->session_id) return LOCKDOWN_E_NO_RUNNING_SESSION; 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_set_item(dict,"Request", plist_new_string("Activate")); plist_dict_set_item(dict,"ActivationRecord", plist_copy(activation_record)); ret = lockdownd_send(client, dict); plist_free(dict); dict = NULL; ret = lockdownd_receive(client, &dict); if (!dict) { debug_info("LOCKDOWN_E_PLIST_ERROR"); return LOCKDOWN_E_PLIST_ERROR; } ret = LOCKDOWN_E_ACTIVATION_FAILED; if (lockdown_check_result(dict, "Activate") == RESULT_SUCCESS) { debug_info("success"); ret = LOCKDOWN_E_SUCCESS; } else { plist_t error_node = plist_dict_get_item(dict, "Error"); if (error_node && PLIST_STRING == plist_get_node_type(error_node)) { char *error = NULL; plist_get_string_val(error_node, &error); if (!strcmp(error, "InvalidActivationRecord")) { ret = LOCKDOWN_E_INVALID_ACTIVATION_RECORD; } free(error); } } plist_free(dict); dict = NULL; return ret; }
LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_query_type(lockdownd_client_t client, char **type) { 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_set_item(dict,"Request", plist_new_string("QueryType")); debug_info("called"); ret = lockdownd_send(client, dict); plist_free(dict); dict = NULL; ret = lockdownd_receive(client, &dict); if (LOCKDOWN_E_SUCCESS != ret) return ret; ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t type_node = plist_dict_get_item(dict, "Type"); if (type_node && (plist_get_node_type(type_node) == PLIST_STRING)) { char* typestr = NULL; plist_get_string_val(type_node, &typestr); debug_info("success with type %s", typestr); /* return the type if requested */ if (type != NULL) { *type = typestr; } else { free(typestr); } ret = LOCKDOWN_E_SUCCESS; } else { debug_info("hmm. QueryType response does not contain a type?!"); debug_plist(dict); } plist_free(dict); dict = NULL; return ret; }
/** * Queries a value from the device specified by a key. * * @param client An initialized restored client. * @param key The key name to request * @param value A plist node representing the result value node * * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL, RESTORE_E_PLIST_ERROR if value for key can't be found */ restored_error_t restored_query_value(restored_client_t client, const char *key, plist_t *value) { if (!client || !key) return RESTORE_E_INVALID_ARG; plist_t dict = NULL; restored_error_t ret = RESTORE_E_UNKNOWN_ERROR; /* setup request plist */ dict = plist_new_dict(); plist_dict_add_label(dict, client->label); if (key) { plist_dict_insert_item(dict,"QueryKey", plist_new_string(key)); } plist_dict_insert_item(dict,"Request", plist_new_string("QueryValue")); /* send to device */ ret = restored_send(client, dict); plist_free(dict); dict = NULL; if (ret != RESTORE_E_SUCCESS) return ret; /* Now get device's answer */ ret = restored_receive(client, &dict); if (ret != RESTORE_E_SUCCESS) return ret; plist_t value_node = plist_dict_get_item(dict, key); if (value_node) { debug_info("has a value"); *value = plist_copy(value_node); } else { ret = RESTORE_E_PLIST_ERROR; } plist_free(dict); return ret; }
/** * Requests to start a restore and retrieve it's port on success. * * @param client The restored client * @param options PLIST_DICT with options for the restore process or NULL * @param version the restore protocol version, see restored_query_type() * * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG if a parameter * is NULL, RESTORE_E_START_RESTORE_FAILED if the request fails */ restored_error_t restored_start_restore(restored_client_t client, plist_t options, uint64_t version) { if (!client) return RESTORE_E_INVALID_ARG; plist_t dict = NULL; restored_error_t ret = RESTORE_E_UNKNOWN_ERROR; dict = plist_new_dict(); plist_dict_add_label(dict, client->label); plist_dict_insert_item(dict,"Request", plist_new_string("StartRestore")); if (options) { plist_dict_insert_item(dict, "RestoreOptions", plist_copy(options)); } plist_dict_insert_item(dict,"RestoreProtocolVersion", plist_new_uint(version)); /* send to device */ ret = restored_send(client, dict); plist_free(dict); dict = NULL; return ret; }
/** * Internal function used by lockdownd_do_start_service to create the * StartService request's plist. * * @param client The lockdownd client * @param identifier The identifier of the service to start * @param send_escrow_bag Should we send the device's escrow bag with the request * @param request The request's plist on success, NULL on failure * * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_CONF on failure * to read the escrow bag from the device's record (when used). */ static lockdownd_error_t lockdownd_build_start_service_request(lockdownd_client_t client, const char *identifier, int send_escrow_bag, plist_t *request) { plist_t dict = plist_new_dict(); /* create the basic request params */ plist_dict_add_label(dict, client->label); plist_dict_set_item(dict, "Request", plist_new_string("StartService")); plist_dict_set_item(dict, "Service", plist_new_string(identifier)); /* if needed - get the escrow bag for the device and send it with the request */ if (send_escrow_bag) { /* get the pairing record */ plist_t pair_record = NULL; userpref_read_pair_record(client->udid, &pair_record); if (!pair_record) { debug_info("ERROR: failed to read pair record for device: %s", client->udid); plist_free(dict); return LOCKDOWN_E_INVALID_CONF; } /* try to read the escrow bag from the record */ plist_t escrow_bag = plist_dict_get_item(pair_record, USERPREF_ESCROW_BAG_KEY); if (!escrow_bag || (PLIST_DATA != plist_get_node_type(escrow_bag))) { debug_info("ERROR: Failed to retrieve the escrow bag from the device's record"); plist_free(dict); plist_free(pair_record); return LOCKDOWN_E_INVALID_CONF; } debug_info("Adding escrow bag to StartService for %s", identifier); plist_dict_set_item(dict, USERPREF_ESCROW_BAG_KEY, plist_copy(escrow_bag)); plist_free(pair_record); } *request = dict; return LOCKDOWN_E_SUCCESS; }
/** * Creates a new restored client for the device. * * @param device The device to create a restored client for * @param client The pointer to the location of the new restored_client * @param label The label to use for communication. Usually the program name. * * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL */ restored_error_t restored_client_new(idevice_t device, restored_client_t *client, const char *label) { if (!client) return RESTORE_E_INVALID_ARG; restored_error_t ret = RESTORE_E_SUCCESS; static struct lockdownd_service_descriptor service = { .port = 0xf27e, .ssl_enabled = 0 }; property_list_service_client_t plistclient = NULL; if (property_list_service_client_new(device, (lockdownd_service_descriptor_t)&service, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) { debug_info("could not connect to restored (device %s)", device->udid); return RESTORE_E_MUX_ERROR; } restored_client_t client_loc = (restored_client_t) malloc(sizeof(struct restored_client_private)); client_loc->parent = plistclient; client_loc->udid = NULL; client_loc->label = NULL; client_loc->info = NULL; if (label != NULL) client_loc->label = strdup(label); ret = idevice_get_udid(device, &client_loc->udid); if (RESTORE_E_SUCCESS != ret) { debug_info("failed to get device udid."); } debug_info("device udid: %s", client_loc->udid); if (RESTORE_E_SUCCESS == ret) { *client = client_loc; } else { restored_client_free(client_loc); } return ret; } /** * Sends the Goodbye request to restored signaling the end of communication. * * @param client The restore client * * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL, * RESTORE_E_PLIST_ERROR if the device did not acknowledge the request */ restored_error_t restored_goodbye(restored_client_t client) { if (!client) return RESTORE_E_INVALID_ARG; restored_error_t ret = RESTORE_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")); debug_info("called"); ret = restored_send(client, dict); plist_free(dict); dict = NULL; ret = restored_receive(client, &dict); if (!dict) { debug_info("did not get goodbye response back"); return RESTORE_E_PLIST_ERROR; } if (restored_check_result(dict) == RESULT_SUCCESS) { debug_info("success"); ret = RESTORE_E_SUCCESS; } plist_free(dict); dict = NULL; return ret; } /** * Requests to start a restore and retrieve it's port on success. * * @param client The restored client * @param options PLIST_DICT with options for the restore process or NULL * @param version the restore protocol version, see restored_query_type() * * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG if a parameter * is NULL, RESTORE_E_START_RESTORE_FAILED if the request fails */ restored_error_t restored_start_restore(restored_client_t client, plist_t options, uint64_t version) { if (!client) return RESTORE_E_INVALID_ARG; plist_t dict = NULL; restored_error_t ret = RESTORE_E_UNKNOWN_ERROR; dict = plist_new_dict(); plist_dict_add_label(dict, client->label); plist_dict_insert_item(dict,"Request", plist_new_string("StartRestore")); if (options) { plist_dict_insert_item(dict, "RestoreOptions", plist_copy(options)); } plist_dict_insert_item(dict,"RestoreProtocolVersion", plist_new_uint(version)); /* send to device */ ret = restored_send(client, dict); plist_free(dict); dict = NULL; return ret; } /** * Requests device to reboot. * * @param client The restored client * * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG if a parameter * is NULL */ restored_error_t restored_reboot(restored_client_t client) { if (!client) return RESTORE_E_INVALID_ARG; plist_t dict = NULL; restored_error_t ret = RESTORE_E_UNKNOWN_ERROR; dict = plist_new_dict(); plist_dict_add_label(dict, client->label); plist_dict_insert_item(dict,"Request", plist_new_string("Reboot")); /* send to device */ ret = restored_send(client, dict); plist_free(dict); dict = NULL; if (RESTORE_E_SUCCESS != ret) return ret; ret = restored_receive(client, &dict); if (RESTORE_E_SUCCESS != ret) return ret; if (!dict) return RESTORE_E_PLIST_ERROR; plist_free(dict); dict = NULL; return ret; }
/** * Requests to start a service and retrieve it's port on success. * * @param client The lockdownd client * @param identifier The identifier of the service to start * @param descriptor The service descriptor on success or NULL on failure * @return LOCKDOWN_E_SUCCESS on success, NP_E_INVALID_ARG if a parameter * is NULL, LOCKDOWN_E_INVALID_SERVICE if the requested service is not known * by the device, LOCKDOWN_E_START_SERVICE_FAILED if the service could not because * started by the device */ lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char *identifier, lockdownd_service_descriptor_t *service) { if (!client || !identifier || !service) return LOCKDOWN_E_INVALID_ARG; if (*service) { // reset fields if service descriptor is reused (*service)->port = 0; (*service)->ssl_enabled = 0; } plist_t dict = NULL; uint16_t port_loc = 0; lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; dict = plist_new_dict(); plist_dict_add_label(dict, client->label); plist_dict_set_item(dict,"Request", plist_new_string("StartService")); plist_dict_set_item(dict,"Service", plist_new_string(identifier)); /* send to device */ ret = lockdownd_send(client, dict); plist_free(dict); dict = NULL; if (LOCKDOWN_E_SUCCESS != ret) return ret; ret = lockdownd_receive(client, &dict); if (LOCKDOWN_E_SUCCESS != ret) return ret; if (!dict) return LOCKDOWN_E_PLIST_ERROR; ret = LOCKDOWN_E_UNKNOWN_ERROR; if (lockdown_check_result(dict, "StartService") == RESULT_SUCCESS) { if (*service == NULL) *service = (lockdownd_service_descriptor_t)malloc(sizeof(struct lockdownd_service_descriptor)); (*service)->port = 0; (*service)->ssl_enabled = 0; /* read service port number */ plist_t node = plist_dict_get_item(dict, "Port"); if (node && (plist_get_node_type(node) == PLIST_UINT)) { uint64_t port_value = 0; plist_get_uint_val(node, &port_value); if (port_value) { port_loc = port_value; ret = LOCKDOWN_E_SUCCESS; } if (port_loc && ret == LOCKDOWN_E_SUCCESS) { (*service)->port = port_loc; } } /* check if the service requires SSL */ node = plist_dict_get_item(dict, "EnableServiceSSL"); if (node && (plist_get_node_type(node) == PLIST_BOOLEAN)) { uint8_t b = 0; plist_get_bool_val(node, &b); (*service)->ssl_enabled = b; } } else { ret = LOCKDOWN_E_START_SERVICE_FAILED; plist_t error_node = plist_dict_get_item(dict, "Error"); if (error_node && PLIST_STRING == plist_get_node_type(error_node)) { char *error = NULL; plist_get_string_val(error_node, &error); if (!strcmp(error, "InvalidService")) { ret = LOCKDOWN_E_INVALID_SERVICE; } else if (!strcmp(error, "NoRunningSession")) { ret = LOCKDOWN_E_NO_RUNNING_SESSION; } free(error); } } plist_free(dict); dict = NULL; return ret; }
LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char *host_id, char **session_id, int *ssl_enabled) { lockdownd_error_t ret = LOCKDOWN_E_SUCCESS; property_list_service_error_t plret; plist_t dict = NULL; if (!client || !host_id) ret = LOCKDOWN_E_INVALID_ARG; /* if we have a running session, stop current one first */ if (client->session_id) { lockdownd_stop_session(client, client->session_id); } /* setup request plist */ dict = plist_new_dict(); plist_dict_add_label(dict, client->label); plist_dict_set_item(dict,"Request", plist_new_string("StartSession")); /* add host id */ if (host_id) { plist_dict_set_item(dict, "HostID", plist_new_string(host_id)); } /* add system buid */ char *system_buid = NULL; userpref_read_system_buid(&system_buid); if (system_buid) { plist_dict_set_item(dict, "SystemBUID", plist_new_string(system_buid)); if (system_buid) { free(system_buid); system_buid = NULL; } } ret = lockdownd_send(client, dict); plist_free(dict); dict = NULL; if (ret != LOCKDOWN_E_SUCCESS) return ret; ret = lockdownd_receive(client, &dict); if (!dict) return LOCKDOWN_E_PLIST_ERROR; if (lockdown_check_result(dict, "StartSession") == RESULT_FAILURE) { plist_t error_node = plist_dict_get_item(dict, "Error"); if (error_node && PLIST_STRING == plist_get_node_type(error_node)) { char *error = NULL; plist_get_string_val(error_node, &error); if (!strcmp(error, "InvalidHostID")) { ret = LOCKDOWN_E_INVALID_HOST_ID; } free(error); } } else { uint8_t use_ssl = 0; plist_t enable_ssl = plist_dict_get_item(dict, "EnableSessionSSL"); if (enable_ssl && (plist_get_node_type(enable_ssl) == PLIST_BOOLEAN)) { plist_get_bool_val(enable_ssl, &use_ssl); } debug_info("Session startup OK"); if (ssl_enabled != NULL) *ssl_enabled = use_ssl; /* store session id, we need it for StopSession */ plist_t session_node = plist_dict_get_item(dict, "SessionID"); if (session_node && (plist_get_node_type(session_node) == PLIST_STRING)) { plist_get_string_val(session_node, &client->session_id); } if (client->session_id) { debug_info("SessionID: %s", client->session_id); if (session_id != NULL) *session_id = strdup(client->session_id); } else { debug_info("Failed to get SessionID!"); } debug_info("Enable SSL Session: %s", (use_ssl?"true":"false")); if (use_ssl) { plret = property_list_service_enable_ssl(client->parent); if (plret == PROPERTY_LIST_SERVICE_E_SUCCESS) { ret = LOCKDOWN_E_SUCCESS; client->ssl_enabled = 1; } else { ret = LOCKDOWN_E_SSL_ERROR; client->ssl_enabled = 0; } } else { client->ssl_enabled = 0; ret = LOCKDOWN_E_SUCCESS; } } plist_free(dict); dict = NULL; return ret; }
/** * Function used internally by lockdownd_pair() and lockdownd_validate_pair() * * @param client The lockdown client to pair with. * @param pair_record The pair record to use for pairing. If NULL is passed, then * the pair records from the current machine are used. New records will be * generated automatically when pairing is done for the first time. * @param verb This is either "Pair", "ValidatePair" or "Unpair". * * @return LOCKDOWN_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL, * LOCKDOWN_E_PLIST_ERROR if the pair_record certificates are wrong, * LOCKDOWN_E_PAIRING_FAILED if the pairing failed, * LOCKDOWN_E_PASSWORD_PROTECTED if the device is password protected, * LOCKDOWN_E_INVALID_HOST_ID if the device does not know the caller's host id */ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record, const char *verb) { if (!client) return LOCKDOWN_E_INVALID_ARG; lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t dict = NULL; plist_t pair_record_plist = NULL; plist_t wifi_node = NULL; int pairing_mode = 0; /* 0 = libimobiledevice, 1 = external */ if (pair_record && pair_record->system_buid && pair_record->host_id) { /* valid pair_record passed? */ if (!pair_record->device_certificate || !pair_record->host_certificate || !pair_record->root_certificate) { return LOCKDOWN_E_PLIST_ERROR; } /* use passed pair_record */ pair_record_plist = lockdownd_pair_record_to_plist(pair_record); pairing_mode = 1; } else { /* generate a new pair record if pairing */ if (!strcmp("Pair", verb)) { ret = pair_record_generate(client, &pair_record_plist); if (ret != LOCKDOWN_E_SUCCESS) { if (pair_record_plist) plist_free(pair_record_plist); return ret; } /* get wifi mac now, if we get it later we fail on iOS 7 which causes a reconnect */ lockdownd_get_value(client, NULL, "WiFiAddress", &wifi_node); } else { /* use existing pair record */ if (userpref_has_pair_record(client->udid)) { userpref_read_pair_record(client->udid, &pair_record_plist); if (!pair_record_plist) { return LOCKDOWN_E_INVALID_CONF; } } else { return LOCKDOWN_E_INVALID_HOST_ID; } } } plist_t request_pair_record = plist_copy(pair_record_plist); /* remove stuff that is private */ plist_dict_remove_item(request_pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY); plist_dict_remove_item(request_pair_record, USERPREF_HOST_PRIVATE_KEY_KEY); /* setup pair request plist */ dict = plist_new_dict(); plist_dict_add_label(dict, client->label); plist_dict_set_item(dict, "PairRecord", request_pair_record); plist_dict_set_item(dict, "Request", plist_new_string(verb)); plist_dict_set_item(dict, "ProtocolVersion", plist_new_string(LOCKDOWN_PROTOCOL_VERSION)); plist_t options = plist_new_dict(); plist_dict_set_item(options, "ExtendedPairingErrors", plist_new_bool(1)); plist_dict_set_item(dict, "PairingOptions", options); /* send to device */ ret = lockdownd_send(client, dict); plist_free(dict); dict = NULL; if (ret != LOCKDOWN_E_SUCCESS) { plist_free(pair_record_plist); if (wifi_node) plist_free(wifi_node); return ret; } /* Now get device's answer */ ret = lockdownd_receive(client, &dict); if (ret != LOCKDOWN_E_SUCCESS) { plist_free(pair_record_plist); if (wifi_node) plist_free(wifi_node); return ret; } if (strcmp(verb, "Unpair") == 0) { /* workaround for Unpair giving back ValidatePair, * seems to be a bug in the device's fw */ if (lockdown_check_result(dict, NULL) != RESULT_SUCCESS) { ret = LOCKDOWN_E_PAIRING_FAILED; } } else { if (lockdown_check_result(dict, verb) != RESULT_SUCCESS) { ret = LOCKDOWN_E_PAIRING_FAILED; } } /* if pairing succeeded */ if (ret == LOCKDOWN_E_SUCCESS) { debug_info("%s success", verb); if (!pairing_mode) { debug_info("internal pairing mode"); if (!strcmp("Unpair", verb)) { /* remove public key from config */ userpref_delete_pair_record(client->udid); } else { if (!strcmp("Pair", verb)) { /* add returned escrow bag if available */ plist_t extra_node = plist_dict_get_item(dict, USERPREF_ESCROW_BAG_KEY); if (extra_node && plist_get_node_type(extra_node) == PLIST_DATA) { debug_info("Saving EscrowBag from response in pair record"); plist_dict_set_item(pair_record_plist, USERPREF_ESCROW_BAG_KEY, plist_copy(extra_node)); plist_free(extra_node); extra_node = NULL; } /* save previously retrieved wifi mac address in pair record */ if (wifi_node) { debug_info("Saving WiFiAddress from device in pair record"); plist_dict_set_item(pair_record_plist, USERPREF_WIFI_MAC_ADDRESS_KEY, plist_copy(wifi_node)); plist_free(wifi_node); wifi_node = NULL; } userpref_save_pair_record(client->udid, pair_record_plist); } } } else { debug_info("external pairing mode"); } } else { debug_info("%s failure", 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); if (value) { /* the first pairing fails if the device is password protected */ if (!strcmp(value, "PasswordProtected")) { ret = LOCKDOWN_E_PASSWORD_PROTECTED; } else if (!strcmp(value, "InvalidHostID")) { ret = LOCKDOWN_E_INVALID_HOST_ID; } else if (!strcmp(value, "UserDeniedPairing")) { ret = LOCKDOWN_E_USER_DENIED_PAIRING; } else if (!strcmp(value, "PairingDialogResponsePending")) { ret = LOCKDOWN_E_PAIRING_DIALOG_PENDING; } free(value); } plist_free(error_node); error_node = NULL; } } if (pair_record_plist) { plist_free(pair_record_plist); pair_record_plist = NULL; } if (wifi_node) { plist_free(wifi_node); wifi_node = NULL; } plist_free(dict); dict = NULL; return ret; }
LIBIMOBILEDEVICE_API restored_error_t restored_client_new(idevice_t device, restored_client_t *client, const char *label) { if (!client) return RESTORE_E_INVALID_ARG; restored_error_t ret = RESTORE_E_SUCCESS; idevice_error_t idev_ret; static struct lockdownd_service_descriptor service = { .port = 0xf27e, .ssl_enabled = 0 }; property_list_service_client_t plistclient = NULL; if (property_list_service_client_new(device, (lockdownd_service_descriptor_t)&service, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) { debug_info("could not connect to restored (device %s)", device->udid); return RESTORE_E_MUX_ERROR; } restored_client_t client_loc = (restored_client_t) malloc(sizeof(struct restored_client_private)); client_loc->parent = plistclient; client_loc->udid = NULL; client_loc->label = NULL; client_loc->info = NULL; if (label != NULL) client_loc->label = strdup(label); idev_ret = idevice_get_udid(device, &client_loc->udid); if (IDEVICE_E_SUCCESS != idev_ret) { debug_info("failed to get device udid."); ret = RESTORE_E_DEVICE_ERROR; } debug_info("device udid: %s", client_loc->udid); if (RESTORE_E_SUCCESS == ret) { *client = client_loc; } else { restored_client_free(client_loc); } return ret; } LIBIMOBILEDEVICE_API restored_error_t restored_goodbye(restored_client_t client) { if (!client) return RESTORE_E_INVALID_ARG; restored_error_t ret = RESTORE_E_UNKNOWN_ERROR; plist_t dict = plist_new_dict(); plist_dict_add_label(dict, client->label); plist_dict_set_item(dict,"Request", plist_new_string("Goodbye")); debug_info("called"); ret = restored_send(client, dict); plist_free(dict); dict = NULL; ret = restored_receive(client, &dict); if (!dict) { debug_info("did not get goodbye response back"); return RESTORE_E_PLIST_ERROR; } if (restored_check_result(dict) == RESULT_SUCCESS) { debug_info("success"); ret = RESTORE_E_SUCCESS; } plist_free(dict); dict = NULL; return ret; } LIBIMOBILEDEVICE_API restored_error_t restored_start_restore(restored_client_t client, plist_t options, uint64_t version) { if (!client) return RESTORE_E_INVALID_ARG; plist_t dict = NULL; restored_error_t ret = RESTORE_E_UNKNOWN_ERROR; dict = plist_new_dict(); plist_dict_add_label(dict, client->label); plist_dict_set_item(dict,"Request", plist_new_string("StartRestore")); if (options) { plist_dict_set_item(dict, "RestoreOptions", plist_copy(options)); } plist_dict_set_item(dict,"RestoreProtocolVersion", plist_new_uint(version)); /* send to device */ ret = restored_send(client, dict); plist_free(dict); dict = NULL; return ret; } LIBIMOBILEDEVICE_API restored_error_t restored_reboot(restored_client_t client) { if (!client) return RESTORE_E_INVALID_ARG; plist_t dict = NULL; restored_error_t ret = RESTORE_E_UNKNOWN_ERROR; dict = plist_new_dict(); plist_dict_add_label(dict, client->label); plist_dict_set_item(dict,"Request", plist_new_string("Reboot")); /* send to device */ ret = restored_send(client, dict); plist_free(dict); dict = NULL; if (RESTORE_E_SUCCESS != ret) return ret; ret = restored_receive(client, &dict); if (RESTORE_E_SUCCESS != ret) return ret; if (!dict) return RESTORE_E_PLIST_ERROR; plist_free(dict); dict = NULL; return ret; }