Example #1
0
/**
 * 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;
}
/**
 * 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;
}
/**
 * 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;
}
Example #4
0
Node::Node(plist_type type, Node* parent) : _parent(parent)
{
    _node = NULL;

    switch (type)
    {
    case PLIST_BOOLEAN:
        _node = plist_new_bool(0);
        break;
    case PLIST_UINT:
        _node = plist_new_uint(0);
        break;
    case PLIST_REAL:
        _node = plist_new_real(0.);
        break;
    case PLIST_STRING:
        _node = plist_new_string("");
        break;
    case PLIST_KEY:
        _node = plist_new_string("");
        plist_set_key_val(_node, "");
        break;
    case PLIST_UID:
	_node = plist_new_uid(0);
	break;
    case PLIST_DATA:
        _node = plist_new_data(NULL,0);
        break;
    case PLIST_DATE:
        _node = plist_new_date(0,0);
        break;
    case PLIST_ARRAY:
        _node = plist_new_array();
        break;
    case PLIST_DICT:
        _node = plist_new_dict();
        break;
    case PLIST_NONE:
    default:
        break;
    }
}
Example #5
0
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;
}
Example #6
0
/**
 * 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")) {
/**
 * 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;
}
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;
}
Example #9
0
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;
}
Example #10
0
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;
}
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;
}
/**
 * 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, &current_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;
}
Example #13
0
/**
 * 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;
}
Example #14
0
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;
}
/**
 * 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;
}
Example #16
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;
}
Example #17
0
/**
 * 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;
}
Example #18
0
/**
 * 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;
}