/** * Cancels a running synchronization session with a device at any time. * * @param client The mobilesync client * @param reason The reason to supply to the device for cancelling * * @retval MOBILESYNC_E_SUCCESS on success * @retval MOBILESYNC_E_INVALID_ARG if one of the parameters is invalid */ mobilesync_error_t mobilesync_cancel(mobilesync_client_t client, const char* reason) { if (!client || !client->data_class || !reason) { return MOBILESYNC_E_INVALID_ARG; } mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR; plist_t msg = NULL; msg = plist_new_array(); plist_array_append_item(msg, plist_new_string("SDMessageCancelSession")); plist_array_append_item(msg, plist_new_string(client->data_class)); plist_array_append_item(msg, plist_new_string(reason)); err = mobilesync_send(client, msg); plist_free(msg); msg = NULL; free(client->data_class); client->data_class = NULL; client->direction = MOBILESYNC_SYNC_DIR_DEVICE_TO_COMPUTER; return err; }
static void mobilesync_disconnect(mobilesync_client_t client) { if (!client) return; plist_t array = plist_new_array(); plist_array_append_item(array, plist_new_string("DLMessageDisconnect")); plist_array_append_item(array, plist_new_string("All done, thanks for the memories")); mobilesync_send(client, array); plist_free(array); array = NULL; }
/** * Performs a disconnect with the connected device link service client. * * @param client The device link service client to disconnect. * * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, * DEVICE_LINK_SERVICE_E_INVALID_ARG if client is NULL, * or DEVICE_LINK_SERVICE_E_MUX_ERROR when there's an error when sending * the the disconnect message. */ device_link_service_error_t device_link_service_disconnect(device_link_service_client_t client) { if (!client) return DEVICE_LINK_SERVICE_E_INVALID_ARG; plist_t array = plist_new_array(); plist_array_append_item(array, plist_new_string("DLMessageDisconnect")); plist_array_append_item(array, plist_new_string("All done, thanks for the memories")); device_link_service_error_t err = DEVICE_LINK_SERVICE_E_SUCCESS; if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { err = DEVICE_LINK_SERVICE_E_MUX_ERROR; } plist_free(array); return err; }
/** * Sends a DLMessagePing plist. * * @param client The device link service client to use. * @param message String to send as ping message. * * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, * DEVICE_LINK_SERVICE_E_INVALID_ARG if client or message is invalid, * or DEVICE_LINK_SERVICE_E_MUX_ERROR if the DLMessagePing plist could * not be sent. */ device_link_service_error_t device_link_service_send_ping(device_link_service_client_t client, const char *message) { if (!client || !client->parent || !message) return DEVICE_LINK_SERVICE_E_INVALID_ARG; plist_t array = plist_new_array(); plist_array_append_item(array, plist_new_string("DLMessagePing")); plist_array_append_item(array, plist_new_string(message)); device_link_service_error_t err = DEVICE_LINK_SERVICE_E_SUCCESS; if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { err = DEVICE_LINK_SERVICE_E_MUX_ERROR; } plist_free(array); return err; }
static int send_device_list(struct mux_client *client, uint32_t tag) { int res = -1; plist_t dict = plist_new_dict(); plist_t devices = plist_new_array(); struct device_info *devs = NULL; struct device_info *dev; int i; int count = device_get_list(0, &devs); dev = devs; for (i = 0; devs && i < count; i++) { plist_t device = create_device_attached_plist(dev++); if (device) { plist_array_append_item(devices, device); } } if (devs) free(devs); plist_dict_insert_item(dict, "DeviceList", devices); res = send_plist_pkt(client, tag, dict); plist_free(dict); return res; }
/** * Acknowledges to the device that the changes have been merged on the computer * * @param client The mobilesync client * * @retval MOBILESYNC_E_SUCCESS on success * @retval MOBILESYNC_E_INVALID_ARG if one of the parameters is invalid */ mobilesync_error_t mobilesync_acknowledge_changes_from_device(mobilesync_client_t client) { if (!client || !client->data_class) { return MOBILESYNC_E_INVALID_ARG; } plist_t msg = NULL; mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR; msg = plist_new_array(); plist_array_append_item(msg, plist_new_string("SDMessageAcknowledgeChangesFromDevice")); plist_array_append_item(msg, plist_new_string(client->data_class)); err = mobilesync_send(client, msg); plist_free(msg); return err; }
/** * Performs the mobilebackup2 protocol version exchange. * * @param client The MobileBackup client to use. * @param local_versions An array of supported versions to send to the remote. * @param count The number of items in local_versions. * @param remote_version Holds the protocol version of the remote on success. * * @return MOBILEBACKUP2_E_SUCCESS on success, or a MOBILEBACKUP2_E_* error * code otherwise. */ mobilebackup2_error_t mobilebackup2_version_exchange(mobilebackup2_client_t client, double local_versions[], char count, double *remote_version) { int i; if (!client || !client->parent) return MOBILEBACKUP2_E_INVALID_ARG; plist_t dict = plist_new_dict(); plist_t array = plist_new_array(); for (i = 0; i < count; i++) { plist_array_append_item(array, plist_new_real(local_versions[i])); } plist_dict_insert_item(dict, "SupportedProtocolVersions", array); mobilebackup2_error_t err = mobilebackup2_send_message(client, "Hello", dict); plist_free(dict); if (err != MOBILEBACKUP2_E_SUCCESS) goto leave; dict = NULL; err = internal_mobilebackup2_receive_message(client, "Response", &dict); if (err != MOBILEBACKUP2_E_SUCCESS) goto leave; /* check if we received an error */ plist_t node = plist_dict_get_item(dict, "ErrorCode"); if (!node || (plist_get_node_type(node) != PLIST_UINT)) { err = MOBILEBACKUP2_E_PLIST_ERROR; goto leave; } uint64_t val = 0; plist_get_uint_val(node, &val); if (val != 0) { if (val == 1) { err = MOBILEBACKUP2_E_NO_COMMON_VERSION; } else { err = MOBILEBACKUP2_E_REPLY_NOT_OK; } goto leave; } /* retrieve the protocol version of the device */ node = plist_dict_get_item(dict, "ProtocolVersion"); if (!node || (plist_get_node_type(node) != PLIST_REAL)) { err = MOBILEBACKUP2_E_PLIST_ERROR; goto leave; } *remote_version = 0.0; plist_get_real_val(node, remote_version); leave: if (dict) plist_free(dict); return err; }
void Array::Append(Node* node) { if (node) { Node* clone = node->Clone(); UpdateNodeParent(clone); plist_array_append_item(_node, clone->GetPlist()); _array.push_back(clone); } }
/** * Performs a disconnect with the connected device link service client. * * @param client The device link service client to disconnect. * @param message Optional message to send send to the device or NULL. * * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, * DEVICE_LINK_SERVICE_E_INVALID_ARG if client is NULL, * or DEVICE_LINK_SERVICE_E_MUX_ERROR when there's an error when sending * the the disconnect message. */ device_link_service_error_t device_link_service_disconnect(device_link_service_client_t client, const char *message) { if (!client) return DEVICE_LINK_SERVICE_E_INVALID_ARG; plist_t array = plist_new_array(); plist_array_append_item(array, plist_new_string("DLMessageDisconnect")); if (message) plist_array_append_item(array, plist_new_string(message)); else plist_array_append_item(array, plist_new_string("___EmptyParameterString___")); device_link_service_error_t err = DEVICE_LINK_SERVICE_E_SUCCESS; if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { err = DEVICE_LINK_SERVICE_E_MUX_ERROR; } plist_free(array); return err; }
/** * Sends a DLMessageProcessMessage plist. * * @param client The device link service client to use. * @param message PLIST_DICT to send. * * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, * DEVICE_LINK_SERVICE_E_INVALID_ARG if client or message is invalid or * message is not a PLIST_DICT, or DEVICE_LINK_SERVICE_E_MUX_ERROR if * the DLMessageProcessMessage plist could not be sent. */ device_link_service_error_t device_link_service_send_process_message(device_link_service_client_t client, plist_t message) { if (!client || !client->parent || !message) return DEVICE_LINK_SERVICE_E_INVALID_ARG; if (plist_get_node_type(message) != PLIST_DICT) return DEVICE_LINK_SERVICE_E_INVALID_ARG; plist_t array = plist_new_array(); plist_array_append_item(array, plist_new_string("DLMessageProcessMessage")); plist_array_append_item(array, plist_copy(message)); device_link_service_error_t err = DEVICE_LINK_SERVICE_E_SUCCESS; if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { err = DEVICE_LINK_SERVICE_E_MUX_ERROR; } plist_free(array); return err; }
static mobilesync_error_t mobilesync_get_records(mobilesync_client_t client, const char *operation) { if (!client || !client->data_class || !operation) { return MOBILESYNC_E_INVALID_ARG; } mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR; plist_t msg = NULL; msg = plist_new_array(); plist_array_append_item(msg, plist_new_string(operation)); plist_array_append_item(msg, plist_new_string(client->data_class)); err = mobilesync_send(client, msg); if (msg) { plist_free(msg); msg = NULL; } return err; }
LIBIMOBILEDEVICE_API instproxy_error_t instproxy_lookup(instproxy_client_t client, const char** appids, plist_t client_options, plist_t *result) { instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; int i = 0; plist_t lookup_result = NULL; plist_t command = NULL; plist_t appid_array = NULL; plist_t node = NULL; if (!client || !client->parent || !result) return INSTPROXY_E_INVALID_ARG; command = plist_new_dict(); plist_dict_set_item(command, "Command", plist_new_string("Lookup")); if (client_options) { node = plist_copy(client_options); } else if (appids) { node = plist_new_dict(); } /* add bundle identifiers to client options */ if (appids) { appid_array = plist_new_array(); while (appids[i]) { plist_array_append_item(appid_array, plist_new_string(appids[i])); i++; } plist_dict_set_item(node, "BundleIDs", appid_array); } if (node) { plist_dict_set_item(command, "ClientOptions", node); } res = instproxy_perform_command(client, command, INSTPROXY_COMMAND_TYPE_SYNC, instproxy_copy_lookup_result_cb, (void*)&lookup_result); if (res == INSTPROXY_E_SUCCESS) { *result = lookup_result; } else { plist_free(lookup_result); } plist_free(command); return res; }
static plist_t create_process_changes_message(const char *data_class, plist_t entities, uint8_t more_changes, plist_t actions) { plist_t msg = plist_new_array(); plist_array_append_item(msg, plist_new_string("SDMessageProcessChanges")); plist_array_append_item(msg, plist_new_string(data_class)); plist_array_append_item(msg, plist_copy(entities)); plist_array_append_item(msg, plist_new_bool(more_changes)); if (actions) plist_array_append_item(msg, plist_copy(actions)); else plist_array_append_item(msg, plist_new_string(EMPTY_PARAMETER_STRING)); return msg; }
static void instproxy_append_current_list_to_result_cb(plist_t command, plist_t status, void *user_data) { plist_t *result_array = (plist_t*)user_data; uint64_t current_amount = 0; plist_t current_list = NULL; uint64_t i; instproxy_status_get_current_list(status, NULL, NULL, ¤t_amount, ¤t_list); debug_info("current_amount: %d", current_amount); if (current_amount > 0) { for (i = 0; current_list && (i < current_amount); i++) { plist_t item = plist_array_get_item(current_list, i); plist_array_append_item(*result_array, plist_copy(item)); } } if (current_list) plist_free(current_list); }
/** * Add one or more new key:value pairs to the given actions plist. * * @param actions The actions to modify. * @param ... KEY, VALUE, [KEY, VALUE], NULL * * @note The known keys so far are "SyncDeviceLinkEntityNamesKey" which expects * an array of entity names, followed by a count paramter as well as * "SyncDeviceLinkAllRecordsOfPulledEntityTypeSentKey" which expects an * integer to use as a boolean value indicating that the device should * link submitted changes and report remapped identifiers. */ void mobilesync_actions_add(plist_t actions, ...) { if (!actions) return; va_list args; va_start(args, actions); char *arg = va_arg(args, char*); while (arg) { char *key = strdup(arg); if (!strcmp(key, "SyncDeviceLinkEntityNamesKey")) { char **entity_names = va_arg(args, char**); int entity_names_length = va_arg(args, int); int i = 0; plist_t array = plist_new_array(); for (i = 0; i < entity_names_length; i++) { plist_array_append_item(array, plist_new_string(entity_names[i])); } plist_dict_set_item(actions, key, array); } else if (!strcmp(key, "SyncDeviceLinkAllRecordsOfPulledEntityTypeSentKey")) {
LIBIMOBILEDEVICE_API instproxy_error_t instproxy_check_capabilities_match(instproxy_client_t client, const char** capabilities, plist_t client_options, plist_t *result) { if (!capabilities || (plist_get_node_type(capabilities) != PLIST_ARRAY && plist_get_node_type(capabilities) != PLIST_DICT)) return INSTPROXY_E_INVALID_ARG; plist_t lookup_result = NULL; instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; plist_t command = plist_new_dict(); plist_dict_set_item(command, "Command", plist_new_string("CheckCapabilitiesMatch")); if (client_options) plist_dict_set_item(command, "ClientOptions", plist_copy(client_options)); if (capabilities) { int i = 0; plist_t capabilities_array = plist_new_array(); while (capabilities[i]) { plist_array_append_item(capabilities_array, plist_new_string(capabilities[i])); i++; } plist_dict_set_item(command, "Capabilities", capabilities_array); } res = instproxy_perform_command(client, command, INSTPROXY_COMMAND_TYPE_SYNC, instproxy_copy_lookup_result_cb, (void*)&lookup_result); if (res == INSTPROXY_E_SUCCESS) { *result = lookup_result; } else { plist_free(lookup_result); } plist_free(command); return res; }
/** * Sends a DLMessageStatusResponse to the device. * * @param client The MobileBackup client to use. * @param status_code The status code to send. * @param status1 A status message to send. Can be NULL if not required. * @param status2 An additional status plist to attach to the response. * Can be NULL if not required. * * @return MOBILEBACKUP2_E_SUCCESS on success, MOBILEBACKUP2_E_INVALID_ARG * if client is invalid, or another MOBILEBACKUP2_E_* otherwise. */ mobilebackup2_error_t mobilebackup2_send_status_response(mobilebackup2_client_t client, int status_code, const char *status1, plist_t status2) { if (!client || !client->parent) return MOBILEBACKUP2_E_INVALID_ARG; plist_t array = plist_new_array(); plist_array_append_item(array, plist_new_string("DLMessageStatusResponse")); plist_array_append_item(array, plist_new_uint(status_code)); if (status1) { plist_array_append_item(array, plist_new_string(status1)); } else { plist_array_append_item(array, plist_new_string("___EmptyParameterString___")); } if (status2) { plist_array_append_item(array, plist_copy(status2)); } else { plist_array_append_item(array, plist_new_string("___EmptyParameterString___")); } mobilebackup2_error_t err = mobilebackup2_error(device_link_service_send(client->parent, array)); plist_free(array); return err; }
static instproxy_error_t instproxy_client_get_object_by_key_from_info_directionary_for_bundle_identifier(instproxy_client_t client, const char* appid, const char* key, plist_t* node) { if (!client || !appid || !key) return INSTPROXY_E_INVALID_ARG; plist_t apps = NULL; // create client options for any application types plist_t client_opts = instproxy_client_options_new(); instproxy_client_options_add(client_opts, "ApplicationType", "Any", NULL); // only return attributes we need plist_t return_attributes = plist_new_array(); plist_array_append_item(return_attributes, plist_new_string("CFBundleIdentifier")); plist_array_append_item(return_attributes, plist_new_string("CFBundleExecutable")); plist_array_append_item(return_attributes, plist_new_string(key)); instproxy_client_options_add(client_opts, "ReturnAttributes", return_attributes, NULL); plist_free(return_attributes); return_attributes = NULL; // query device for list of apps instproxy_error_t ierr = instproxy_browse(client, client_opts, &apps); instproxy_client_options_free(client_opts); if (ierr != INSTPROXY_E_SUCCESS) { return ierr; } plist_t app_found = NULL; uint32_t i; for (i = 0; i < plist_array_get_size(apps); i++) { char *appid_str = NULL; plist_t app_info = plist_array_get_item(apps, i); plist_t idp = plist_dict_get_item(app_info, "CFBundleIdentifier"); if (idp) { plist_get_string_val(idp, &appid_str); } if (appid_str && strcmp(appid, appid_str) == 0) { app_found = app_info; } free(appid_str); if (app_found) { break; } } if (!app_found) { if (apps) plist_free(apps); *node = NULL; return INSTPROXY_E_OP_FAILED; } plist_t object = plist_dict_get_item(app_found, key); if (object) { *node = plist_copy(object); } else { debug_info("key %s not found", key); return INSTPROXY_E_OP_FAILED; } plist_free(apps); return INSTPROXY_E_SUCCESS; }
int main(int argc, char **argv) { idevice_t device = NULL; lockdownd_client_t lockdown_client = NULL; diagnostics_relay_client_t diagnostics_client = NULL; lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; uint16_t port = 0; int result = -1; int i; const char *udid = NULL; int cmd = CMD_NONE; char* cmd_arg = NULL; plist_t node = NULL; plist_t keys = NULL; /* parse cmdline args */ for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { idevice_set_debug_level(1); continue; } else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) { i++; if (!argv[i] || (strlen(argv[i]) != 40)) { print_usage(argc, argv); result = 0; goto cleanup; } udid = argv[i]; continue; } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { print_usage(argc, argv); result = 0; goto cleanup; } else if (!strcmp(argv[i], "sleep")) { cmd = CMD_SLEEP; } else if (!strcmp(argv[i], "restart")) { cmd = CMD_RESTART; } else if (!strcmp(argv[i], "shutdown")) { cmd = CMD_SHUTDOWN; } else if (!strcmp(argv[i], "diagnostics")) { cmd = CMD_DIAGNOSTICS; /* read type */ i++; if (!argv[i] || ((strcmp(argv[i], "All") != 0) && (strcmp(argv[i], "WiFi") != 0) && (strcmp(argv[i], "GasGauge") != 0) && (strcmp(argv[i], "NAND") != 0))) { if (argv[i] == NULL) { cmd_arg = strdup("All"); continue; } if (!strncmp(argv[i], "-", 1)) { cmd_arg = strdup("All"); i--; continue; } printf("Unknown TYPE %s\n", argv[i]); print_usage(argc, argv); goto cleanup; } cmd_arg = strdup(argv[i]); continue; } else if (!strcmp(argv[i], "mobilegestalt")) { cmd = CMD_MOBILEGESTALT; /* read keys */ i++; if (!argv[i] || argv[i] == NULL || (!strncmp(argv[i], "-", 1))) { printf("Please supply the key to query.\n"); print_usage(argc, argv); goto cleanup; } keys = plist_new_array(); while(1) { if (argv[i] && (strlen(argv[i]) >= 2) && (strncmp(argv[i], "-", 1) != 0)) { plist_array_append_item(keys, plist_new_string(argv[i])); i++; } else { i--; break; } } continue; } else if (!strcmp(argv[i], "ioreg")) { cmd = CMD_IOREGISTRY; /* read plane */ i++; if (argv[i]) { cmd_arg = strdup(argv[i]); } continue; } else { print_usage(argc, argv); return 0; } } /* verify options */ if (cmd == CMD_NONE) { print_usage(argc, argv); goto cleanup; } if (IDEVICE_E_SUCCESS != idevice_new(&device, udid)) { if (udid) { printf("No device found with udid %s, is it plugged in?\n", udid); } else { printf("No device found, is it plugged in?\n"); } goto cleanup; } if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(device, &lockdown_client, NULL)) { idevice_free(device); printf("Unable to connect to lockdownd.\n"); goto cleanup; } /* attempt to use newer diagnostics service available on iOS 5 and later */ ret = lockdownd_start_service(lockdown_client, "com.apple.mobile.diagnostics_relay", &port); if (ret != LOCKDOWN_E_SUCCESS) { /* attempt to use older diagnostics service */ ret = lockdownd_start_service(lockdown_client, "com.apple.iosdiagnostics.relay", &port); } lockdownd_client_free(lockdown_client); if ((ret == LOCKDOWN_E_SUCCESS) && (port > 0)) { if (diagnostics_relay_client_new(device, port, &diagnostics_client) != DIAGNOSTICS_RELAY_E_SUCCESS) { printf("Could not connect to diagnostics_relay!\n"); result = -1; } else { switch (cmd) { case CMD_SLEEP: if (diagnostics_relay_sleep(diagnostics_client) == DIAGNOSTICS_RELAY_E_SUCCESS) { printf("Putting device into deep sleep mode.\n"); result = EXIT_SUCCESS; } else { printf("Failed to put device into deep sleep mode.\n"); } break; case CMD_RESTART: if (diagnostics_relay_restart(diagnostics_client, 0) == DIAGNOSTICS_RELAY_E_SUCCESS) { printf("Restarting device.\n"); result = EXIT_SUCCESS; } else { printf("Failed to restart device.\n"); } break; case CMD_SHUTDOWN: if (diagnostics_relay_shutdown(diagnostics_client, 0) == DIAGNOSTICS_RELAY_E_SUCCESS) { printf("Shutting down device.\n"); result = EXIT_SUCCESS; } else { printf("Failed to shutdown device.\n"); } break; case CMD_MOBILEGESTALT: if (diagnostics_relay_query_mobilegestalt(diagnostics_client, keys, &node) == DIAGNOSTICS_RELAY_E_SUCCESS) { if (node) { print_xml(node); result = EXIT_SUCCESS; } } else { printf("Unable to query mobilegestalt keys.\n"); } break; case CMD_IOREGISTRY: if (diagnostics_relay_query_ioregistry_plane(diagnostics_client, cmd_arg == NULL ? "": cmd_arg, &node) == DIAGNOSTICS_RELAY_E_SUCCESS) { if (node) { print_xml(node); result = EXIT_SUCCESS; } } else { printf("Unable to retrieve IORegistry from device.\n"); } break; case CMD_DIAGNOSTICS: default: if (diagnostics_relay_request_diagnostics(diagnostics_client, cmd_arg, &node) == DIAGNOSTICS_RELAY_E_SUCCESS) { if (node) { print_xml(node); result = EXIT_SUCCESS; } } else { printf("Unable to retrieve diagnostics from device.\n"); } break; } diagnostics_relay_goodbye(diagnostics_client); diagnostics_relay_client_free(diagnostics_client); } } else { printf("Could not start diagnostics service!\n"); } idevice_free(device); cleanup: if (node) { plist_free(node); } if (keys) { plist_free(keys); } if (cmd_arg) { free(cmd_arg); } return result; }
mobilesync_error_t mobilesync_client_new(iphone_device_t device, int dst_port, mobilesync_client_t * client) { if (!device || dst_port == 0 || !client || *client) return MOBILESYNC_E_INVALID_ARG; mobilesync_error_t ret = MOBILESYNC_E_UNKNOWN_ERROR; /* Attempt connection */ iphone_connection_t connection = NULL; if (iphone_device_connect(device, dst_port, &connection) != IPHONE_E_SUCCESS) { return ret; } mobilesync_client_t client_loc = (mobilesync_client_t) malloc(sizeof(struct mobilesync_client_int)); client_loc->connection = connection; /* perform handshake */ plist_t array = NULL; /* first receive version */ ret = mobilesync_recv(client_loc, &array); plist_t msg_node = plist_find_node_by_string(array, "DLMessageVersionExchange"); plist_t ver_1 = plist_get_next_sibling(msg_node); plist_t ver_2 = plist_get_next_sibling(ver_1); plist_type ver_1_type = plist_get_node_type(ver_1); plist_type ver_2_type = plist_get_node_type(ver_2); if (PLIST_UINT == ver_1_type && PLIST_UINT == ver_2_type) { uint64_t ver_1_val = 0; uint64_t ver_2_val = 0; plist_get_uint_val(ver_1, &ver_1_val); plist_get_uint_val(ver_2, &ver_2_val); plist_free(array); array = NULL; if (ver_1_type == PLIST_UINT && ver_2_type == PLIST_UINT && ver_1_val == MSYNC_VERSION_INT1 && ver_2_val == MSYNC_VERSION_INT2) { array = plist_new_array(); plist_array_append_item(array, plist_new_string("DLMessageVersionExchange")); plist_array_append_item(array, plist_new_string("DLVersionsOk")); ret = mobilesync_send(client_loc, array); plist_free(array); array = NULL; ret = mobilesync_recv(client_loc, &array); plist_t rep_node = plist_find_node_by_string(array, "DLMessageDeviceReady"); if (rep_node) { ret = MOBILESYNC_E_SUCCESS; *client = client_loc; } else { ret = MOBILESYNC_E_BAD_VERSION; } plist_free(array); array = NULL; } } if (MOBILESYNC_E_SUCCESS != ret) mobilesync_client_free(client_loc); return ret; }
/** * Request data for the given sources. * * @param client The connected file_relay client. * @param sources A NULL-terminated list of sources to retrieve. * Valid sources are: * - AppleSupport * - Network * - VPN * - WiFi * - UserDatabases * - CrashReporter * - tmp * - SystemConfiguration * @param connection The connection that has to be used for receiving the * data using idevice_connection_receive(). The connection will be closed * automatically by the device, but use file_relay_client_free() to clean * up properly. * * @note WARNING: Don't call this function without reading the data afterwards. * A directory mobile_file_relay.XXXX used for creating the archive will * remain in the /tmp directory otherwise. * * @return FILE_RELAY_E_SUCCESS on succes, FILE_RELAY_E_INVALID_ARG when one or * more parameters are invalid, FILE_RELAY_E_MUX_ERROR if a communication * error occurs, FILE_RELAY_E_PLIST_ERROR when the received result is NULL * or is not a valid plist, FILE_RELAY_E_INVALID_SOURCE if one or more * sources are invalid, FILE_RELAY_E_STAGING_EMPTY if no data is available * for the given sources, or FILE_RELAY_E_UNKNOWN_ERROR otherwise. */ file_relay_error_t file_relay_request_sources(file_relay_client_t client, const char **sources, idevice_connection_t *connection) { if (!client || !client->parent || !sources || !sources[0]) { return FILE_RELAY_E_INVALID_ARG; } *connection = NULL; file_relay_error_t err = FILE_RELAY_E_UNKNOWN_ERROR; /* set up request plist */ plist_t array = plist_new_array(); int i = 0; while (sources[i]) { plist_array_append_item(array, plist_new_string(sources[i])); i++; } plist_t dict = plist_new_dict(); plist_dict_insert_item(dict, "Sources", array); if (property_list_service_send_xml_plist(client->parent, dict) != PROPERTY_LIST_SERVICE_E_SUCCESS) { debug_info("ERROR: Could not send request to device!"); err = FILE_RELAY_E_MUX_ERROR; goto leave; } plist_free(dict); dict = NULL; if (property_list_service_receive_plist_with_timeout(client->parent, &dict, 60000) != PROPERTY_LIST_SERVICE_E_SUCCESS) { debug_info("ERROR: Could not receive answer from device!"); err = FILE_RELAY_E_MUX_ERROR; goto leave; } if (!dict) { debug_info("ERROR: Did not receive any plist!"); err = FILE_RELAY_E_PLIST_ERROR; goto leave; } plist_t error = plist_dict_get_item(dict, "Error"); if (error) { char *errmsg = NULL; plist_get_string_val(error, &errmsg); if (errmsg) { if (!strcmp(errmsg, "InvalidSource")) { debug_info("ERROR: One or more given sources are invalid!"); err = FILE_RELAY_E_INVALID_SOURCE; } else if (!strcmp(errmsg, "StagingEmpty")) { debug_info("ERROR: StagingEmpty - No data available!"); err = FILE_RELAY_E_STAGING_EMPTY; } else { debug_info("ERROR: Unknown error '%s'", errmsg); } free(errmsg); } else { debug_info("ERROR: Could not get error message!"); } goto leave; } plist_t status = plist_dict_get_item(dict, "Status"); if (!status) { debug_info("ERROR: Unexpected plist received!"); debug_plist(dict); err = FILE_RELAY_E_PLIST_ERROR; goto leave; } char *ack = NULL; plist_get_string_val(status, &ack); if (!ack) { debug_info("ERROR: Could not get 'Acknowledged' string!"); goto leave; } if (strcmp(ack, "Acknowledged")) { debug_info("ERROR: Did not receive 'Acknowledged' but '%s'", ack); goto leave; } free(ack); err = FILE_RELAY_E_SUCCESS; *connection = client->parent->connection; leave: if (dict) { plist_free(dict); } return err; }
/** * List installed applications. This function runs synchronously. * * @param client The connected installation_proxy client * @param client_options The client options to use, as PLIST_DICT, or NULL. * Valid client options include: * "ApplicationType" -> "User" * "ApplicationType" -> "System" * @param result Pointer that will be set to a plist that will hold an array * of PLIST_DICT holding information about the applications found. * * @return INSTPROXY_E_SUCCESS on success or an INSTPROXY_E_* error value if * an error occured. */ instproxy_error_t instproxy_browse(instproxy_client_t client, plist_t client_options, plist_t *result) { if (!client || !client->parent || !result) return INSTPROXY_E_INVALID_ARG; instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR; instproxy_lock(client); res = instproxy_send_command(client, "Browse", client_options, NULL, NULL); if (res != INSTPROXY_E_SUCCESS) { debug_info("could not send plist"); goto leave_unlock; } int browsing = 0; plist_t apps_array = plist_new_array(); plist_t dict = NULL; do { browsing = 0; dict = NULL; res = instproxy_error(property_list_service_receive_plist(client->parent, &dict)); if (res != INSTPROXY_E_SUCCESS) { break; } if (dict) { uint64_t i; uint64_t current_amount = 0; char *status = NULL; plist_t camount = plist_dict_get_item(dict, "CurrentAmount"); plist_t pstatus = plist_dict_get_item(dict, "Status"); if (camount) { plist_get_uint_val(camount, ¤t_amount); } if (current_amount > 0) { plist_t current_list = plist_dict_get_item(dict, "CurrentList"); for (i = 0; current_list && (i < current_amount); i++) { plist_t item = plist_array_get_item(current_list, i); plist_array_append_item(apps_array, plist_copy(item)); } } if (pstatus) { plist_get_string_val(pstatus, &status); } if (status) { if (!strcmp(status, "BrowsingApplications")) { browsing = 1; } else if (!strcmp(status, "Complete")) { debug_info("Browsing applications completed"); res = INSTPROXY_E_SUCCESS; } free(status); } plist_free(dict); } } while (browsing); if (res == INSTPROXY_E_SUCCESS) { *result = apps_array; } else { plist_free(apps_array); } leave_unlock: instproxy_unlock(client); return res; }
int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { char* llb_path = NULL; if (tss_get_entry_path(tss, "LLB", &llb_path) < 0) { error("ERROR: Unable to get LLB info from TSS response\n"); return -1; } char* llb_filename = strstr(llb_path, "LLB"); if (llb_filename == NULL) { error("ERROR: Unable to extract firmware path from LLB filename\n"); free(llb_path); return -1; } char firmware_path[256]; memset(firmware_path, '\0', sizeof(firmware_path)); memcpy(firmware_path, llb_path, (llb_filename - 1) - llb_path); info("Found firmware path %s\n", firmware_path); char manifest_file[256]; memset(manifest_file, '\0', sizeof(manifest_file)); snprintf(manifest_file, sizeof(manifest_file), "%s/manifest", firmware_path); info("Getting firmware manifest %s\n", manifest_file); int manifest_size = 0; char* manifest_data = NULL; if (ipsw_extract_to_memory(ipsw, manifest_file, &manifest_data, &manifest_size) < 0) { error("ERROR: Unable to extract firmware manifest from ipsw\n"); free(llb_path); return -1; } char firmware_filename[256]; memset(firmware_filename, '\0', sizeof(firmware_filename)); int llb_size = 0; char* llb_data = NULL; plist_t dict = plist_new_dict(); char* filename = strtok(manifest_data, "\n"); if (filename != NULL) { memset(firmware_filename, '\0', sizeof(firmware_filename)); snprintf(firmware_filename, sizeof(firmware_filename), "%s/%s", firmware_path, filename); if (get_signed_component(ipsw, tss, firmware_filename, &llb_data, &llb_size) < 0) { error("ERROR: Unable to get signed LLB\n"); return -1; } plist_dict_insert_item(dict, "LlbImageData", plist_new_data(llb_data, (uint64_t) llb_size)); } int nor_size = 0; char* nor_data = NULL; filename = strtok(NULL, "\n"); plist_t norimage_array = plist_new_array(); while (filename != NULL) { memset(firmware_filename, '\0', sizeof(firmware_filename)); snprintf(firmware_filename, sizeof(firmware_filename), "%s/%s", firmware_path, filename); if (get_signed_component(ipsw, tss, firmware_filename, &nor_data, &nor_size) < 0) { error("ERROR: Unable to get signed firmware %s\n", firmware_filename); break; } plist_array_append_item(norimage_array, plist_new_data(nor_data, (uint64_t) nor_size)); free(nor_data); nor_data = NULL; nor_size = 0; filename = strtok(NULL, "\n"); } plist_dict_insert_item(dict, "NorImageData", norimage_array); debug_plist(dict); restored_error_t ret = restored_send(client, dict); if (ret != RESTORE_E_SUCCESS) { error("ERROR: Unable to send kernelcache data\n"); plist_free(dict); return -1; } plist_free(dict); return 0; }
/** * Requests starting synchronization of a data class with the device * * @param client The mobilesync client * @param data_class The data class identifier to sync * @param anchors The anchors required to exchange with the device. The anchors * allow the device to tell if the synchronization information on the computer * and device are consistent to determine what sync type is required. * @param computer_data_class_version The version of the data class storage on the computer * @param sync_type A pointer to store the sync type reported by the device_anchor * @param device_data_class_version The version of the data class storage on the device * @param error_description A pointer to store an error message if reported by the device * * @retval MOBILESYNC_E_SUCCESS on success * @retval MOBILESYNC_E_INVALID_ARG if one of the parameters is invalid * @retval MOBILESYNC_E_PLIST_ERROR if the received plist is not of valid form * @retval MOBILESYNC_E_SYNC_REFUSED if the device refused to sync * @retval MOBILESYNC_E_CANCELLED if the device explicitly cancelled the * sync request */ mobilesync_error_t mobilesync_start(mobilesync_client_t client, const char *data_class, mobilesync_anchors_t anchors, uint64_t computer_data_class_version, mobilesync_sync_type_t *sync_type, uint64_t *device_data_class_version, char** error_description) { if (!client || client->data_class || !data_class || !anchors || !anchors->computer_anchor) { return MOBILESYNC_E_INVALID_ARG; } mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR; char *response_type = NULL; char *sync_type_str = NULL; plist_t msg = NULL; plist_t response_type_node = NULL; *error_description = NULL; msg = plist_new_array(); plist_array_append_item(msg, plist_new_string("SDMessageSyncDataClassWithDevice")); plist_array_append_item(msg, plist_new_string(data_class)); if (anchors->device_anchor) { plist_array_append_item(msg, plist_new_string(anchors->device_anchor)); } else { plist_array_append_item(msg, plist_new_string("---")); } plist_array_append_item(msg, plist_new_string(anchors->computer_anchor)); plist_array_append_item(msg, plist_new_uint(computer_data_class_version)); plist_array_append_item(msg, plist_new_string(EMPTY_PARAMETER_STRING)); err = mobilesync_send(client, msg); if (err != MOBILESYNC_E_SUCCESS) { goto out; } plist_free(msg); msg = NULL; err = mobilesync_receive(client, &msg); if (err != MOBILESYNC_E_SUCCESS) { goto out; } response_type_node = plist_array_get_item(msg, 0); if (!response_type_node) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } plist_get_string_val(response_type_node, &response_type); if (!response_type) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } // did the device refuse to sync with the computer? if (!strcmp(response_type, "SDMessageRefuseToSyncDataClassWithComputer")) { err = MOBILESYNC_E_SYNC_REFUSED; plist_get_string_val(plist_array_get_item(msg, 2), error_description); debug_info("Device refused sync: %s", error_description); goto out; } // did the device cancel the session? if (!strcmp(response_type, "SDMessageCancelSession")) { err = MOBILESYNC_E_CANCELLED; plist_get_string_val(plist_array_get_item(msg, 2), error_description); debug_info("Device cancelled: %s", error_description); goto out; } if (sync_type != NULL) { plist_t sync_type_node = plist_array_get_item(msg, 4); if (!sync_type_node) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } plist_get_string_val(sync_type_node, &sync_type_str); if (!sync_type_str) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } if (!strcmp(sync_type_str, "SDSyncTypeFast")) { *sync_type = MOBILESYNC_SYNC_TYPE_FAST; } else if (!strcmp(sync_type_str, "SDSyncTypeSlow")) { *sync_type = MOBILESYNC_SYNC_TYPE_SLOW; } else if (!strcmp(sync_type_str, "SDSyncTypeReset")) { *sync_type = MOBILESYNC_SYNC_TYPE_RESET; } else { err = MOBILESYNC_E_PLIST_ERROR; goto out; } } if (device_data_class_version != NULL) { plist_t device_data_class_version_node = plist_array_get_item(msg, 5); if (!device_data_class_version_node) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } plist_get_uint_val(device_data_class_version_node, device_data_class_version); } err = MOBILESYNC_E_SUCCESS; out: if (sync_type_str) { free(sync_type_str); sync_type_str = NULL; } if (response_type) { free(response_type); response_type = NULL; } if (msg) { plist_free(msg); msg = NULL; } client->data_class = strdup(data_class); client->direction = MOBILESYNC_SYNC_DIR_DEVICE_TO_COMPUTER; return err; }
/** * Finish a synchronization session of a data class on the device. * A session must have previously been started using mobilesync_start(). * * @param client The mobilesync client * * @retval MOBILESYNC_E_SUCCESS on success * @retval MOBILESYNC_E_INVALID_ARG if one of the parameters is invalid * @retval MOBILESYNC_E_PLIST_ERROR if the received plist is not of valid * form */ mobilesync_error_t mobilesync_finish(mobilesync_client_t client) { if (!client || !client->data_class) { return MOBILESYNC_E_INVALID_ARG; } mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR; plist_t msg = NULL; plist_t response_type_node = NULL; char *response_type = NULL; msg = plist_new_array(); plist_array_append_item(msg, plist_new_string("SDMessageFinishSessionOnDevice")); plist_array_append_item(msg, plist_new_string(client->data_class)); err = mobilesync_send(client, msg); if (err != MOBILESYNC_E_SUCCESS) { goto out; } plist_free(msg); msg = NULL; err = mobilesync_receive(client, &msg); if (err != MOBILESYNC_E_SUCCESS) { goto out; } response_type_node = plist_array_get_item(msg, 0); if (!response_type_node) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } plist_get_string_val(response_type_node, &response_type); if (!response_type) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } if (!strcmp(response_type, "SDMessageDeviceFinishedSession")) { err = MOBILESYNC_E_SUCCESS; } out: if (response_type) { free(response_type); response_type = NULL; } if (msg) { plist_free(msg); msg = NULL; } free(client->data_class); client->data_class = NULL; client->direction = MOBILESYNC_SYNC_DIR_DEVICE_TO_COMPUTER; return err; }
/** * Performs the DLMessageVersionExchange with the connected device. * This should be the first operation to be executed by an implemented * device link service client. * * @param client The device_link_service client to use. * @param version_major The major version number to check. * @param version_minor The minor version number to check. * * @return DEVICE_LINK_SERVICE_E_SUCCESS on success, * DEVICE_LINK_SERVICE_E_INVALID_ARG when client is NULL, * DEVICE_LINK_SERVICE_E_MUX_ERROR when a communication error occurs, * DEVICE_LINK_SERVICE_E_PLIST_ERROR when the received plist has not the * expected contents, DEVICE_LINK_SERVICE_E_BAD_VERSION when the version * given by the device is larger than the given version, * or DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR otherwise. */ device_link_service_error_t device_link_service_version_exchange(device_link_service_client_t client, uint64_t version_major, uint64_t version_minor) { if (!client) return DEVICE_LINK_SERVICE_E_INVALID_ARG; device_link_service_error_t err = DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR; /* perform version exchange */ plist_t array = NULL; char *msg = NULL; /* receive DLMessageVersionExchange from device */ if (property_list_service_receive_plist(client->parent, &array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { debug_info("Did not receive initial message from device!"); err = DEVICE_LINK_SERVICE_E_MUX_ERROR; goto leave; } msg = device_link_service_get_message(array); if (!msg || strcmp(msg, "DLMessageVersionExchange")) { debug_info("Did not receive DLMessageVersionExchange from device!"); err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; goto leave; } free(msg); msg = NULL; /* get major and minor version number */ if (plist_array_get_size(array) < 3) { debug_info("DLMessageVersionExchange has unexpected format!"); err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; goto leave; } plist_t maj = plist_array_get_item(array, 1); plist_t min = plist_array_get_item(array, 2); uint64_t vmajor = 0; uint64_t vminor = 0; if (maj) { plist_get_uint_val(maj, &vmajor); } if (min) { plist_get_uint_val(min, &vminor); } if (vmajor > version_major) { debug_info("Version mismatch: device=(%lld,%lld) > expected=(%lld,%lld)", vmajor, vminor, version_major, version_minor); err = DEVICE_LINK_SERVICE_E_BAD_VERSION; goto leave; } else if ((vmajor == version_major) && (vminor > version_minor)) { debug_info("WARNING: Version mismatch: device=(%lld,%lld) > expected=(%lld,%lld)", vmajor, vminor, version_major, version_minor); err = DEVICE_LINK_SERVICE_E_BAD_VERSION; goto leave; } plist_free(array); /* version is ok, send reply */ array = plist_new_array(); plist_array_append_item(array, plist_new_string("DLMessageVersionExchange")); plist_array_append_item(array, plist_new_string("DLVersionsOk")); plist_array_append_item(array, plist_new_uint(version_major)); if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { debug_info("Error when sending DLVersionsOk"); err = DEVICE_LINK_SERVICE_E_MUX_ERROR; goto leave; } plist_free(array); /* receive DeviceReady message */ array = NULL; if (property_list_service_receive_plist(client->parent, &array) != PROPERTY_LIST_SERVICE_E_SUCCESS) { debug_info("Error when receiving DLMessageDeviceReady!"); err = DEVICE_LINK_SERVICE_E_MUX_ERROR; goto leave; } msg = device_link_service_get_message(array); if (!msg || strcmp(msg, "DLMessageDeviceReady")) { debug_info("Did not get DLMessageDeviceReady!"); err = DEVICE_LINK_SERVICE_E_PLIST_ERROR; goto leave; } err = DEVICE_LINK_SERVICE_E_SUCCESS; leave: if (msg) { free(msg); } if (array) { plist_free(array); } return err; }
/** * Requests the device to delete all records of the current data class * * @note The operation must be called after starting synchronization. * * @param client The mobilesync client * * @retval MOBILESYNC_E_SUCCESS on success * @retval MOBILESYNC_E_INVALID_ARG if one of the parameters is invalid * @retval MOBILESYNC_E_PLIST_ERROR if the received plist is not of valid form */ mobilesync_error_t mobilesync_clear_all_records_on_device(mobilesync_client_t client) { if (!client || !client->data_class) { return MOBILESYNC_E_INVALID_ARG; } mobilesync_error_t err = MOBILESYNC_E_UNKNOWN_ERROR; plist_t msg = NULL; plist_t response_type_node = NULL; char *response_type = NULL; msg = plist_new_array(); plist_array_append_item(msg, plist_new_string("SDMessageClearAllRecordsOnDevice")); plist_array_append_item(msg, plist_new_string(client->data_class)); plist_array_append_item(msg, plist_new_string(EMPTY_PARAMETER_STRING)); err = mobilesync_send(client, msg); if (err != MOBILESYNC_E_SUCCESS) { goto out; } plist_free(msg); msg = NULL; err = mobilesync_receive(client, &msg); if (err != MOBILESYNC_E_SUCCESS) { goto out; } response_type_node = plist_array_get_item(msg, 0); if (!response_type_node) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } plist_get_string_val(response_type_node, &response_type); if (!response_type) { err = MOBILESYNC_E_PLIST_ERROR; goto out; } if (!strcmp(response_type, "SDMessageCancelSession")) { char *reason = NULL; err = MOBILESYNC_E_CANCELLED; plist_get_string_val(plist_array_get_item(msg, 2), &reason); debug_info("Device cancelled: %s", reason); free(reason); goto out; } if (strcmp(response_type, "SDMessageDeviceWillClearAllRecords")) { err = MOBILESYNC_E_PLIST_ERROR; } out: if (response_type) { free(response_type); response_type = NULL; } if (msg) { plist_free(msg); msg = NULL; } return err; }