Beispiel #1
0
int asr_receive(asr_client_t asr, plist_t* data) {
	uint32_t size = 0;
	char* buffer = NULL;
	plist_t request = NULL;
	idevice_error_t device_error = IDEVICE_E_SUCCESS;

	*data = NULL;

	buffer = (char*) malloc(ASR_BUFFER_SIZE);
	if (buffer == NULL) {
		error("ERROR: Unable to allocate memory for ASR receive buffer\n");
		return -1;
	}
	memset(buffer, '\0', ASR_BUFFER_SIZE);

	device_error = idevice_connection_receive(asr->connection, buffer, ASR_BUFFER_SIZE, &size);
	if (device_error != IDEVICE_E_SUCCESS) {
		error("ERROR: Unable to receive data from ASR\n");
		free(buffer);
		return -1;
	}
	plist_from_xml(buffer, size, &request);

	*data = request;

	debug("Received %d bytes:\n", size);
	if (idevicerestore_debug)
		debug_plist(request);
	free(buffer);
	return 0;
}
/**
 * Hangs up the connection to the mobile_image_mounter service.
 * This functions has to be called before freeing up a mobile_image_mounter
 * instance. If not, errors appear in the device's syslog.
 *
 * @param client The client to hang up
 *
 * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on success,
 *     MOBILE_IMAGE_MOUNTER_E_INVALID_ARG if client is invalid,
 *     or another error code otherwise.
 */
mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_client_t client)
{
	if (!client) {
		return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG;
	}
	mobile_image_mounter_lock(client);

	plist_t dict = plist_new_dict();
	plist_dict_insert_item(dict, "Command", plist_new_string("Hangup"));

	mobile_image_mounter_error_t res = mobile_image_mounter_error(property_list_service_send_xml_plist(client->parent, dict));
	plist_free(dict);

	if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
		debug_info("%s: Error sending XML plist to device!", __func__);
		goto leave_unlock;
	}

	dict = NULL;
	res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &dict));
	if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
		debug_info("%s: Error receiving response from device!", __func__);
	}
	if (dict) {
		debug_plist(dict);
		plist_free(dict);
	}

leave_unlock:
	mobile_image_mounter_unlock(client);
	return res;
}
Beispiel #3
0
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;
}
/**
 * Tells the device that the restore process is complete and waits for the
 * device to close the connection. After that, the device should reboot.
 *
 * @param client The connected MobileBackup client to use.
 * 
 * @return MOBILEBACKUP_E_SUCCESS on success, MOBILEBACKUP_E_INVALID_ARG if
 *    client is invalid, MOBILEBACKUP_E_PLIST_ERROR if the received disconnect
 *    message plist is invalid, or MOBILEBACKUP_E_MUX_ERROR if a communication
 *    error occurs.
 */
mobilebackup_error_t mobilebackup_send_restore_complete(mobilebackup_client_t client)
{
	mobilebackup_error_t err = mobilebackup_send_message(client, "BackupMessageRestoreComplete", NULL);
	if (err != MOBILEBACKUP_E_SUCCESS) {
		return err;
	}
	plist_t dlmsg = NULL;
	err = mobilebackup_receive(client, &dlmsg);
	if ((err != MOBILEBACKUP_E_SUCCESS) || !dlmsg || (plist_get_node_type(dlmsg) != PLIST_ARRAY) || (plist_array_get_size(dlmsg) != 2)) {
		if (dlmsg) {
			debug_info("ERROR: Did not receive DLMessageDisconnect:");
			debug_plist(dlmsg);
			plist_free(dlmsg);
		}
		if (err == MOBILEBACKUP_E_SUCCESS) {
			err = MOBILEBACKUP_E_PLIST_ERROR;
		}
		return err;
	}
	plist_t node = plist_array_get_item (dlmsg, 0);
	char *msg = NULL;
	if (node && (plist_get_node_type(node) == PLIST_STRING)) {
		plist_get_string_val(node, &msg);
	}

	if (msg && !strcmp(msg, "DLMessageDisconnect")) {
		err = MOBILEBACKUP_E_SUCCESS;
		/* we need to do this here, otherwise mobilebackup_client_free
		   will fail */
		device_link_service_client_free(client->parent);
		client->parent = NULL;
	} else {
		debug_info("ERROR: Malformed plist received:");
		debug_plist(dlmsg);
		err = MOBILEBACKUP_E_PLIST_ERROR;
	}

	plist_free(dlmsg);

	if (msg)
		free(msg);

	return err;
}
webinspector_error_t webinspector_send(webinspector_client_t client, plist_t plist)
{
	webinspector_error_t res = WEBINSPECTOR_E_UNKNOWN_ERROR;

	uint32_t offset = 0;
	int is_final_message = 0;

	char *packet = NULL;
	uint32_t packet_length = 0;

	debug_info("Sending webinspector message...");
	debug_plist(plist);

	/* convert plist to packet */
	plist_to_bin(plist, &packet, &packet_length);
	if (!packet || packet_length == 0) {
		debug_info("Error converting plist to binary.");
		return res;
	}

	do {	
		/* determine if we need to send partial messages */
		if (packet_length < WEBINSPECTOR_PARTIAL_PACKET_CHUNK_SIZE) {
			is_final_message = 1;
		} else {
			/* send partial packet */
			is_final_message = 0;
		}

		plist_t outplist = plist_new_dict();
		if (!is_final_message) {
			/* split packet into partial chunks */
			plist_dict_set_item(outplist, "WIRPartialMessageKey", plist_new_data(packet + offset, WEBINSPECTOR_PARTIAL_PACKET_CHUNK_SIZE));
			offset += WEBINSPECTOR_PARTIAL_PACKET_CHUNK_SIZE;
			packet_length -= WEBINSPECTOR_PARTIAL_PACKET_CHUNK_SIZE;
		} else {
			/* send final chunk */
			plist_dict_set_item(outplist, "WIRFinalMessageKey", plist_new_data(packet + offset, packet_length));
			offset += packet_length;
			packet_length -= packet_length;
		}

		res = webinspector_error(property_list_service_send_binary_plist(client->parent, outplist));
		plist_free(outplist);
		outplist = NULL;
		if (res != WEBINSPECTOR_E_SUCCESS) {
			debug_info("Sending plist failed with error %d", res);
			return res;
		}
	} while(packet_length > 0);

	free(packet);
	packet = NULL;

	return res;
}
/**
 * Receives a plist using the given property list service client.
 * Internally used generic plist receive function.
 *
 * @param client The property list service client to use for receiving
 * @param plist pointer to a plist_t that will point to the received plist
 *      upon successful return
 * @param timeout Maximum time in milliseconds to wait for data.
 *
 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
 *      PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or *plist is NULL,
 *      PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be
 *      converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a
 *      communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR
 *      when an unspecified error occurs.
 */
static property_list_service_error_t internal_plist_receive_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout)
{
	property_list_service_error_t res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR;
	uint32_t pktlen = 0;
	uint32_t bytes = 0;

	if (!client || (client && !client->connection) || !plist) {
		return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
	}

	idevice_connection_receive_timeout(client->connection, (char*)&pktlen, sizeof(pktlen), &bytes, timeout);
	debug_info("initial read=%i", bytes);
	if (bytes < 4) {
		debug_info("initial read failed!");
		return PROPERTY_LIST_SERVICE_E_MUX_ERROR;
	} else {
		pktlen = be32toh(pktlen);
		if (pktlen < (1 << 24)) { /* prevent huge buffers */
			uint32_t curlen = 0;
			char *content = NULL;
			debug_info("%d bytes following", pktlen);
			content = (char*)malloc(pktlen);

			while (curlen < pktlen) {
				idevice_connection_receive(client->connection, content+curlen, pktlen-curlen, &bytes);
				if (bytes <= 0) {
					res = PROPERTY_LIST_SERVICE_E_MUX_ERROR;
					break;
				}
				debug_info("received %d bytes", bytes);
				curlen += bytes;
			}
			if (!memcmp(content, "bplist00", 8)) {
				plist_from_bin(content, pktlen, plist);
			} else {
				/* iOS 4.3+ hack: plist data might contain invalid characters, thus we convert those to spaces */
				for (bytes = 0; bytes < pktlen-1; bytes++) {
					if ((content[bytes] >= 0) && (content[bytes] < 0x20) && (content[bytes] != 0x09) && (content[bytes] != 0x0a) && (content[bytes] != 0x0d))
						content[bytes] = 0x20;
				}
				plist_from_xml(content, pktlen, plist);
			}
			if (*plist) {
				debug_plist(*plist);
				res = PROPERTY_LIST_SERVICE_E_SUCCESS;
			} else {
				res = PROPERTY_LIST_SERVICE_E_PLIST_ERROR;
			}
			free(content);
			content = NULL;
		} else {
			res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR;
		}
	}
	return res;
}
LIBIMOBILEDEVICE_API np_error_t np_client_free(np_client_t client)
{
	plist_t dict;
	property_list_service_client_t parent;

	if (!client)
		return NP_E_INVALID_ARG;

	dict = plist_new_dict();
	plist_dict_set_item(dict,"Command", plist_new_string("Shutdown"));
	property_list_service_send_xml_plist(client->parent, dict);
	plist_free(dict);

	parent = client->parent;
	/* notifies the client->notifier thread that it should terminate */
	client->parent = NULL;

	if (client->notifier) {
		debug_info("joining np callback");
		thread_join(client->notifier);
		thread_free(client->notifier);
		client->notifier = (thread_t)NULL;
	} else {
		dict = NULL;
		property_list_service_receive_plist(parent, &dict);
		if (dict) {
#ifndef STRIP_DEBUG_CODE
			char *cmd_value = NULL;
			plist_t cmd_value_node = plist_dict_get_item(dict, "Command");
			if (plist_get_node_type(cmd_value_node) == PLIST_STRING) {
				plist_get_string_val(cmd_value_node, &cmd_value);
			}
			if (cmd_value && !strcmp(cmd_value, "ProxyDeath")) {
				// this is the expected answer
			} else {
				debug_info("Did not get ProxyDeath but:");
				debug_plist(dict);
			}
			if (cmd_value) {
				free(cmd_value);
			}
#endif
			plist_free(dict);
		}
	}

	property_list_service_client_free(parent);

	mutex_destroy(&client->mutex);
	free(client);

	return NP_E_SUCCESS;
}
Beispiel #8
0
heartbeat_error_t heartbeat_send(heartbeat_client_t client, plist_t plist)
{
	heartbeat_error_t res = HEARTBEAT_E_UNKNOWN_ERROR;

	res = heartbeat_error(property_list_service_send_binary_plist(client->parent, plist));
	if (res != HEARTBEAT_E_SUCCESS) {
		debug_info("Sending plist failed with error %d", res);
		return res;
	}

	debug_plist(plist);

	return res;
}
/**
 * Sends a notification to the device's notification_proxy.
 *
 * @param client The client to send to
 * @param notification The notification message to send
 *
 * @return NP_E_SUCCESS on success, or an error returned by np_plist_send
 */
np_error_t np_post_notification(np_client_t client, const char *notification)
{
	if (!client || !notification) {
		return NP_E_INVALID_ARG;
	}
	np_lock(client);

	plist_t dict = plist_new_dict();
	plist_dict_set_item(dict,"Command", plist_new_string("PostNotification"));
	plist_dict_set_item(dict,"Name", plist_new_string(notification));

	np_error_t res = np_error(property_list_service_send_xml_plist(client->parent, dict));
	plist_free(dict);

	dict = plist_new_dict();
	plist_dict_set_item(dict,"Command", plist_new_string("Shutdown"));

	res = np_error(property_list_service_send_xml_plist(client->parent, dict));
	plist_free(dict);

	if (res != NP_E_SUCCESS) {
		debug_info("Error sending XML plist to device!");
	}

	// try to read an answer, we just ignore errors here
	dict = NULL;
	property_list_service_receive_plist(client->parent, &dict);
	if (dict) {
#ifndef STRIP_DEBUG_CODE
		char *cmd_value = NULL;
		plist_t cmd_value_node = plist_dict_get_item(dict, "Command");
		if (plist_get_node_type(cmd_value_node) == PLIST_STRING) {
			plist_get_string_val(cmd_value_node, &cmd_value);
		}

		if (cmd_value && !strcmp(cmd_value, "ProxyDeath")) {
			// this is the expected answer
		} else {
			debug_plist(dict);
		}
		if (cmd_value) {
			free(cmd_value);
		}
#endif
		plist_free(dict);
	}

	np_unlock(client);
	return res;
}
Beispiel #10
0
int isManifestBufSignedForDevice(char *buildManifestBuffer, char *device, uint64_t ecid, int checkBaseband){
    int isSigned = 0;
    plist_t tssreq = NULL;
    plist_t apticket = NULL;
    
    tssrequest(&tssreq, buildManifestBuffer, device, ecid, checkBaseband);
    isSigned = ((apticket = tss_request_send(tssreq, NULL)) > 0);
    
    
    if (print_tss_response) debug_plist(apticket);
    
error:
    if (tssreq) plist_free(tssreq);
    if (apticket) plist_free(apticket);
    return isSigned;
}
Beispiel #11
0
int asr_send(idevice_connection_t asr, plist_t* data) {
	uint32_t size = 0;
	char* buffer = NULL;

	plist_to_xml(data, &buffer, &size);
	if (asr_send_buffer(asr, buffer, size) < 0) {
		error("ERROR: Unable to send plist to ASR\n");
		free(buffer);
		return -1;
	}

	debug("Sent %d bytes:\n", size);
	debug_plist(data);
	free(buffer);
	return 0;
}
/**
 * Sends a plist using the given property list service client.
 * Internally used generic plist send function.
 *
 * @param client The property list service client to use for sending.
 * @param plist plist to send
 * @param binary 1 = send binary plist, 0 = send xml plist
 *
 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
 *      PROPERTY_LIST_SERVICE_E_INVALID_ARG when one or more parameters are
 *      invalid, PROPERTY_LIST_SERVICE_E_PLIST_ERROR when dict is not a valid
 *      plist, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR when an unspecified
 *      error occurs.
 */
static property_list_service_error_t internal_plist_send(property_list_service_client_t client, plist_t plist, int binary)
{
	property_list_service_error_t res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR;
	char *content = NULL;
	uint32_t length = 0;
	uint32_t nlen = 0;
	int bytes = 0;

	if (!client || (client && !client->parent) || !plist) {
		return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
	}

	if (binary) {
		plist_to_bin(plist, &content, &length);
	} else {
		plist_to_xml(plist, &content, &length);
	}

	if (!content || length == 0) {
		return PROPERTY_LIST_SERVICE_E_PLIST_ERROR;
	}

	nlen = htobe32(length);
	debug_info("sending %d bytes", length);
	service_send(client->parent, (const char*)&nlen, sizeof(nlen), (uint32_t*)&bytes);
	if (bytes == sizeof(nlen)) {
		service_send(client->parent, content, length, (uint32_t*)&bytes);
		if (bytes > 0) {
			debug_info("sent %d bytes", bytes);
			debug_plist(plist);
			if ((uint32_t)bytes == length) {
				res = PROPERTY_LIST_SERVICE_E_SUCCESS;
			} else {
				debug_info("ERROR: Could not send all data (%d of %d)!", bytes, length);
			}
		}
	}
	if (bytes <= 0) {
		debug_info("ERROR: sending to device failed.");
	}

	free(content);

	return res;
}
Beispiel #13
0
heartbeat_error_t heartbeat_receive_with_timeout(heartbeat_client_t client, plist_t * plist, uint32_t timeout_ms)
{
	heartbeat_error_t res = HEARTBEAT_E_UNKNOWN_ERROR;
	plist_t outplist = NULL;

	res = heartbeat_error(property_list_service_receive_plist_with_timeout(client->parent, &outplist, timeout_ms));
	if (res != HEARTBEAT_E_SUCCESS || !outplist) {
		debug_info("Could not receive plist, error %d", res);
		plist_free(outplist);
		return HEARTBEAT_E_MUX_ERROR;
	}

	*plist = outplist;

	debug_plist(*plist);

	return res;
}
Beispiel #14
0
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;
}
Beispiel #15
0
int restore_handle_status_msg(restored_client_t client, plist_t msg) {
	uint64_t value = 0;
	info("Got status message\n");
	debug_plist(msg);

	plist_t node = plist_dict_get_item(msg, "Status");
	plist_get_uint_val(node, &value);

	switch(value) {
		case 0:
			info("Status: Restore Finished\n");
			break;
		case 6:
			info("Status: Disk Failure\n");
			break;
		case 14:
			info("Status: Fail\n");
			break;
		default:
			info("Unknown status message.\n");
	}

	return 0;
}
/**
 * Receives a plist using the given property list service client.
 * Internally used generic plist receive function.
 *
 * @param client The property list service client to use for receiving
 * @param plist pointer to a plist_t that will point to the received plist
 *      upon successful return
 * @param timeout Maximum time in milliseconds to wait for data.
 *
 * @return PROPERTY_LIST_SERVICE_E_SUCCESS on success,
 *      PROPERTY_LIST_SERVICE_E_INVALID_ARG when client or *plist is NULL,
 *      PROPERTY_LIST_SERVICE_E_PLIST_ERROR when the received data cannot be
 *      converted to a plist, PROPERTY_LIST_SERVICE_E_MUX_ERROR when a
 *      communication error occurs, or PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR
 *      when an unspecified error occurs.
 */
static property_list_service_error_t internal_plist_receive_timeout(property_list_service_client_t client, plist_t *plist, unsigned int timeout)
{
	property_list_service_error_t res = PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR;
	uint32_t pktlen = 0;
	uint32_t bytes = 0;

	if (!client || (client && !client->parent) || !plist) {
		return PROPERTY_LIST_SERVICE_E_INVALID_ARG;
	}

	*plist = NULL;
	service_error_t serr = service_receive_with_timeout(client->parent, (char*)&pktlen, sizeof(pktlen), &bytes, timeout);
	if ((serr == SERVICE_E_SUCCESS) && (bytes == 0)) {
		return PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT;
	}
	debug_info("initial read=%i", bytes);
	if (bytes < 4) {
		debug_info("initial read failed!");
		return PROPERTY_LIST_SERVICE_E_MUX_ERROR;
	} else {
		uint32_t curlen = 0;
		char *content = NULL;

		pktlen = be32toh(pktlen);
		debug_info("%d bytes following", pktlen);
		content = (char*)malloc(pktlen);
		if (!content) {
			debug_info("out of memory when allocating %d bytes", pktlen);
			return PROPERTY_LIST_SERVICE_E_UNKNOWN_ERROR;
		}

		while (curlen < pktlen) {
			service_receive(client->parent, content+curlen, pktlen-curlen, &bytes);
			if (bytes <= 0) {
				res = PROPERTY_LIST_SERVICE_E_MUX_ERROR;
				break;
			}
			debug_info("received %d bytes", bytes);
			curlen += bytes;
		}
		if (curlen < pktlen) {
			debug_info("received incomplete packet (%d of %d bytes)", curlen, pktlen);
			if (curlen > 0) {
				debug_info("incomplete packet following:");
				debug_buffer(content, curlen);
			}
			free(content);
			return res;
		}
		if ((pktlen > 8) && !memcmp(content, "bplist00", 8)) {
			plist_from_bin(content, pktlen, plist);
		} else if ((pktlen > 5) && !memcmp(content, "<?xml", 5)) {
			/* iOS 4.3+ hack: plist data might contain invalid characters, thus we convert those to spaces */
			for (bytes = 0; bytes < pktlen-1; bytes++) {
				if ((content[bytes] >= 0) && (content[bytes] < 0x20) && (content[bytes] != 0x09) && (content[bytes] != 0x0a) && (content[bytes] != 0x0d))
					content[bytes] = 0x20;
			}
			plist_from_xml(content, pktlen, plist);
		} else {
			debug_info("WARNING: received unexpected non-plist content");
			debug_buffer(content, pktlen);
		}
		if (*plist) {
			debug_plist(*plist);
			res = PROPERTY_LIST_SERVICE_E_SUCCESS;
		} else {
			res = PROPERTY_LIST_SERVICE_E_PLIST_ERROR;
		}
		free(content);
		content = NULL;
	}
	return res;
}
Beispiel #17
0
plist_t tss_create_request(plist_t build_identity, uint64_t ecid, unsigned char* nonce, int nonce_size) {
	uint64_t unique_build_size = 0;
	char* unique_build_data = NULL;
	plist_t unique_build_node = plist_dict_get_item(build_identity, "UniqueBuildID");
	if (!unique_build_node || plist_get_node_type(unique_build_node) != PLIST_DATA) {
		error("ERROR: Unable to find UniqueBuildID node\n");
		return NULL;
	}
	plist_get_data_val(unique_build_node, &unique_build_data, &unique_build_size);

	int chip_id = 0;
	char* chip_id_string = NULL;
	plist_t chip_id_node = plist_dict_get_item(build_identity, "ApChipID");
	if (!chip_id_node || plist_get_node_type(chip_id_node) != PLIST_STRING) {
		error("ERROR: Unable to find ApChipID node\n");
		return NULL;
	}
	plist_get_string_val(chip_id_node, &chip_id_string);
	sscanf(chip_id_string, "%x", &chip_id);

	int board_id = 0;
	char* board_id_string = NULL;
	plist_t board_id_node = plist_dict_get_item(build_identity, "ApBoardID");
	if (!board_id_node || plist_get_node_type(board_id_node) != PLIST_STRING) {
		error("ERROR: Unable to find ApBoardID node\n");
		return NULL;
	}
	plist_get_string_val(board_id_node, &board_id_string);
	sscanf(board_id_string, "%x", &board_id);

	int security_domain = 0;
	char* security_domain_string = NULL;
	plist_t security_domain_node = plist_dict_get_item(build_identity, "ApSecurityDomain");
	if (!security_domain_node || plist_get_node_type(security_domain_node) != PLIST_STRING) {
		error("ERROR: Unable to find ApSecurityDomain node\n");
		return NULL;
	}
	plist_get_string_val(security_domain_node, &security_domain_string);
	sscanf(security_domain_string, "%x", &security_domain);

	char ecid_string[ECID_STRSIZE];
	memset(ecid_string, '\0', ECID_STRSIZE);
	if (ecid == 0) {
		error("ERROR: Unable to get ECID\n");
		return NULL;
	}
	snprintf(ecid_string, ECID_STRSIZE, FMT_qu, (long long unsigned int)ecid);

	// Add build information to TSS request
	plist_t tss_request = plist_new_dict();
	plist_dict_insert_item(tss_request, "@APTicket", plist_new_bool(1));
	plist_dict_insert_item(tss_request, "@BBTicket", plist_new_bool(1));
	plist_dict_insert_item(tss_request, "@HostIpAddress", plist_new_string("192.168.0.1"));
	plist_dict_insert_item(tss_request, "@HostPlatformInfo", plist_new_string("mac"));
	plist_dict_insert_item(tss_request, "@Locality", plist_new_string("en_US"));
	char* guid = generate_guid();
	if (guid) {
		plist_dict_insert_item(tss_request, "@UUID", plist_new_string(guid));
		free(guid);
	}
	plist_dict_insert_item(tss_request, "@VersionInfo", plist_new_string("libauthinstall-107.3"));
	plist_dict_insert_item(tss_request, "ApBoardID", plist_new_uint(board_id));
	plist_dict_insert_item(tss_request, "ApChipID", plist_new_uint(chip_id));
	plist_dict_insert_item(tss_request, "ApECID", plist_new_string(ecid_string));
	if (nonce && (nonce_size > 0)) {
		plist_dict_insert_item(tss_request, "ApNonce", plist_new_data(nonce, nonce_size));
	}
	plist_dict_insert_item(tss_request, "ApProductionMode", plist_new_bool(1));
	plist_dict_insert_item(tss_request, "ApSecurityDomain", plist_new_uint(security_domain));
	plist_dict_insert_item(tss_request, "UniqueBuildID", plist_new_data(unique_build_data, unique_build_size));
	free(unique_build_data);

	// Add all firmware files to TSS request
	plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest");
	if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
		error("ERROR: Unable to find restore manifest\n");
		plist_free(tss_request);
		return NULL;
	}

	char* key = NULL;
	plist_t manifest_entry = NULL;
	plist_dict_iter iter = NULL;
	plist_dict_new_iter(manifest_node, &iter);
	while (1) {
		plist_dict_next_item(manifest_node, iter, &key, &manifest_entry);
		if (key == NULL)
			break;
		if (!manifest_entry || plist_get_node_type(manifest_entry) != PLIST_DICT) {
			error("ERROR: Unable to fetch BuildManifest entry\n");
			free(tss_request);
			return NULL;
		}

		if (strcmp(key, "BasebandFirmware") == 0) {
			free(key);
			continue;
		}

		plist_t tss_entry = plist_copy(manifest_entry);
		plist_dict_insert_item(tss_request, key, tss_entry);
		free(key);
	}

	if (idevicerestore_debug) {
		debug_plist(tss_request);
	}

	return tss_request;
}
Beispiel #18
0
plist_t tss_send_request(plist_t tss_request) {
	curl_global_init(CURL_GLOBAL_ALL);

	int status_code = -1;
	char* request = NULL;
	int retry = 0;
	int max_retries = 15;
	unsigned int size = 0;
	plist_to_xml(tss_request, &request, &size);

	tss_response* response = NULL;

	while (retry++ < max_retries) {
		response = NULL;
		CURL* handle = curl_easy_init();
		if (handle == NULL) {
			break;
		}
		struct curl_slist* header = NULL;
		header = curl_slist_append(header, "Cache-Control: no-cache");
		header = curl_slist_append(header, "Content-type: text/xml; charset=\"utf-8\"");
		header = curl_slist_append(header, "Expect:");

		response = malloc(sizeof(tss_response));
		if (response == NULL) {
			fprintf(stderr, "Unable to allocate sufficent memory\n");
			return NULL;
		}

		response->length = 0;
		response->content = malloc(1);
		response->content[0] = '\0';

		curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)&tss_write_callback);
		curl_easy_setopt(handle, CURLOPT_WRITEDATA, response);
		curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header);
		curl_easy_setopt(handle, CURLOPT_POSTFIELDS, request);
		curl_easy_setopt(handle, CURLOPT_USERAGENT, "InetURL/1.0");
		curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, strlen(request));
		if (use_apple_server==0) {
			curl_easy_setopt(handle, CURLOPT_URL, "http://cydia.saurik.com/TSS/controller?action=2");
		} else {
			curl_easy_setopt(handle, CURLOPT_URL, "http://gs.apple.com/TSS/controller?action=2");
		}

		curl_easy_perform(handle);
		curl_slist_free_all(header);
		curl_easy_cleanup(handle);
	
		if (strstr(response->content, "MESSAGE=SUCCESS")) {
			status_code = 0;
			break;
		}

		if (response->length > 0) {
			error("TSS server returned: %s\n", response->content);
		}

		char* status = strstr(response->content, "STATUS=");
		if (status) {
			sscanf(status+7, "%d&%*s", &status_code);
		}
		if (status_code == -1) {
			// no status code in response. retry
			free(response->content);
			free(response);
			sleep(2);
			continue;
		} else if (status_code == 94) {
			// This device isn't eligible for the requested build.
			break;
		} else if (status_code == 100) {
			// server error, most likely the request was malformed
			break;
		} else {
			error("ERROR: tss_send_request: Unhandled status code %d\n", status_code);
		}
	}

	if (status_code != 0) {
		error("ERROR: TSS request failed (status=%d)\n", status_code);
		free(response->content);
		free(response);
		free(request);
		return NULL;
	}

	char* tss_data = strstr(response->content, "<?xml");
	if (tss_data == NULL) {
		error("ERROR: Incorrectly formatted TSS response\n");
		free(response->content);
		free(response);
		free(request);
		return NULL;
	}

	uint32_t tss_size = 0;
	plist_t tss_response = NULL;
	tss_size = response->length - (tss_data - response->content);
	plist_from_xml(tss_data, tss_size, &tss_response);
	free(response->content);
	free(response);

	if (idevicerestore_debug) {
		debug_plist(tss_response);
	}

	free(request);
	curl_global_cleanup();

	return tss_response;
}
webinspector_error_t webinspector_receive_with_timeout(webinspector_client_t client, plist_t * plist, uint32_t timeout_ms)
{
	webinspector_error_t res = WEBINSPECTOR_E_UNKNOWN_ERROR;
	plist_t message = NULL;
	plist_t key = NULL;

	int is_final_message = 1;

	char* buffer = NULL;
	uint64_t length = 0;

	char* packet = NULL;
	char* newpacket = NULL;
	uint64_t packet_length = 0;

	debug_info("Receiving webinspector message...");

	do {
		/* receive message */
		res = webinspector_error(property_list_service_receive_plist_with_timeout(client->parent, &message, timeout_ms));
		if (res != WEBINSPECTOR_E_SUCCESS || !message) {
			debug_info("Could not receive message, error %d", res);
			plist_free(message);
			return WEBINSPECTOR_E_MUX_ERROR;
		}

		/* get message key */
		key = plist_dict_get_item(message, "WIRFinalMessageKey");
		if (!key) {
			key = plist_dict_get_item(message, "WIRPartialMessageKey");
			if (!key) {
				debug_info("ERROR: Unable to read message key.");
				plist_free(message);
				return WEBINSPECTOR_E_PLIST_ERROR;
			}
			is_final_message = 0;
		} else {
			is_final_message = 1;
		}

		/* read partial data */
		plist_get_data_val(key, &buffer, &length);
		if (!buffer || length == 0 || length > 0xFFFFFFFF) {
			debug_info("ERROR: Unable to get the inner plist binary data.");
			free(packet);
			free(buffer);
			return WEBINSPECTOR_E_PLIST_ERROR;
		}

		/* (re)allocate packet data */
		if (!packet) {
			packet = (char*)malloc(length * sizeof(char));
		} else {
			newpacket = (char*)realloc(packet, (packet_length + length) * sizeof(char));
			packet = newpacket;
		}

		/* copy partial data into final packet data */
		memcpy(packet + packet_length, buffer, length);

		/* cleanup buffer */
		free(buffer);
		buffer = NULL;

		if (message) {
			plist_free(message);
			message = NULL;
		}

		/* adjust packet length */
		packet_length += length;
		length = 0;
	} while(!is_final_message);

	/* read final message */
	if (packet_length) {
		plist_from_bin(packet, (uint32_t)packet_length, plist);
		if (!*plist) {
			debug_info("Error restoring the final plist.");
			free(packet);
			return WEBINSPECTOR_E_PLIST_ERROR;
		}

		debug_plist(*plist);
	}

	if (packet) {
		free(packet);
	}

	return res;
}
Beispiel #20
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;
}
/**
 * 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;
}
Beispiel #22
0
plist_t tss_request_send(plist_t tss_request, const char* server_url_string) {

	if (idevicerestore_debug) {
		debug_plist(tss_request);
	}

	char* request = NULL;
	int status_code = -1;
	int retry = 0;
	int max_retries = 15;
	unsigned int size = 0;
	char curl_error_message[CURL_ERROR_SIZE];

	const char* urls[6] = {
		"https://gs.apple.com/TSS/controller?action=2",
		"https://17.171.36.30/TSS/controller?action=2",
		"https://17.151.36.30/TSS/controller?action=2",
		"http://gs.apple.com/TSS/controller?action=2",
		"http://17.171.36.30/TSS/controller?action=2",
		"http://17.151.36.30/TSS/controller?action=2"
	};

	plist_to_xml(tss_request, &request, &size);

	tss_response* response = NULL;
	memset(curl_error_message, '\0', CURL_ERROR_SIZE);

	while (retry++ < max_retries) {
		response = NULL;
		CURL* handle = curl_easy_init();
		if (handle == NULL) {
			break;
		}
		struct curl_slist* header = NULL;
		header = curl_slist_append(header, "Cache-Control: no-cache");
		header = curl_slist_append(header, "Content-type: text/xml; charset=\"utf-8\"");
		header = curl_slist_append(header, "Expect:");

		response = malloc(sizeof(tss_response));
		if (response == NULL) {
			fprintf(stderr, "Unable to allocate sufficent memory\n");
			return NULL;
		}

		response->length = 0;
		response->content = malloc(1);
		response->content[0] = '\0';

		/* disable SSL verification to allow download from untrusted https locations */
		curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0);

		curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, curl_error_message);
		curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)&tss_write_callback);
		curl_easy_setopt(handle, CURLOPT_WRITEDATA, response);
		curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header);
		curl_easy_setopt(handle, CURLOPT_POSTFIELDS, request);
		curl_easy_setopt(handle, CURLOPT_USERAGENT, "InetURL/1.0");
		curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, strlen(request));
		if (server_url_string) {
			curl_easy_setopt(handle, CURLOPT_URL, server_url_string);
		} else {
			int url_index = (retry - 1) % 6;
			curl_easy_setopt(handle, CURLOPT_URL, urls[url_index]);
			info("Request URL set to %s\n", urls[url_index]);
		}

		info("Sending TSS request attempt %d... ", retry);

		curl_easy_perform(handle);
		curl_slist_free_all(header);
		curl_easy_cleanup(handle);
	
		if (strstr(response->content, "MESSAGE=SUCCESS")) {
			status_code = 0;
			info("response successfully received\n");
			break;
		}

		if (response->length > 0) {
			error("TSS server returned: %s\n", response->content);
		}

		char* status = strstr(response->content, "STATUS=");
		if (status) {
			sscanf(status+7, "%d&%*s", &status_code);
		}
		if (status_code == -1) {
			error("%s\n", curl_error_message);
			// no status code in response. retry
			free(response->content);
			free(response);
			sleep(2);
			continue;
		} else if (status_code == 8) {
			// server error (invalid bb request?)
			break;
		} else if (status_code == 49) {
			// server error (invalid bb data, e.g. BbSNUM?)
			break;
		} else if (status_code == 69 || status_code == 94) {
			// This device isn't eligible for the requested build.
			break;
		} else if (status_code == 100) {
			// server error, most likely the request was malformed
			break;
		} else if (status_code == 126) {
			// An internal error occured, most likely the request was malformed
			break;
		} else {
			error("ERROR: tss_send_request: Unhandled status code %d\n", status_code);
		}
	}

	if (status_code != 0) {
		if (strstr(response->content, "MESSAGE=") != NULL) {
			char* message = strstr(response->content, "MESSAGE=") + strlen("MESSAGE=");
			error("ERROR: TSS request failed (status=%d, message=%s)\n", status_code, message);
		} else {
			error("ERROR: TSS request failed: %s (status=%d)\n", curl_error_message, status_code);
		}
		free(request);
		free(response->content);
		free(response);
		return NULL;
	}

	char* tss_data = strstr(response->content, "<?xml");
	if (tss_data == NULL) {
		error("ERROR: Incorrectly formatted TSS response\n");
		free(request);
		free(response->content);
		free(response);
		return NULL;
	}

	uint32_t tss_size = 0;
	plist_t tss_response = NULL;
	tss_size = response->length - (tss_data - response->content);
	plist_from_xml(tss_data, tss_size, &tss_response);
	free(response->content);
	free(response);

	if (idevicerestore_debug) {
		debug_plist(tss_response);
	}

	free(request);

	return tss_response;
}
Beispiel #23
0
int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* filesystem) {
	int error = 0;
	char* type = NULL;
	char* kernel = NULL;
	plist_t node = NULL;
	plist_t message = NULL;
	idevice_t device = NULL;
	restored_client_t restore = NULL;
	idevice_error_t device_error = IDEVICE_E_SUCCESS;
	restored_error_t restore_error = RESTORE_E_SUCCESS;

	// open our connection to the device and verify we're in restore mode
	if (restore_open_with_timeout(uuid, &device, &restore) < 0) {
		error("ERROR: Unable to open device in restore mode\n");
		return -1;
	}
	info("Device has successfully entered restore mode\n");

	// start the restore process
	restore_error = restored_start_restore(restore);
	if (restore_error != RESTORE_E_SUCCESS) {
		error("ERROR: Unable to start the restore process\n");
		restore_close(device, restore);
		return -1;
	}

	// this is the restore process loop, it reads each message in from
	// restored and passes that data on to it's specific handler
	while (!idevicerestore_quit) {
		restore_error = restored_receive(restore, &message);
		if (restore_error != RESTORE_E_SUCCESS) {
			debug("No data to read\n");
			message = NULL;
			continue;
		}

		// discover what kind of message has been received
		node = plist_dict_get_item(message, "MsgType");
		if (!node || plist_get_node_type(node) != PLIST_STRING) {
			debug("Unknown message received\n");
			debug_plist(message);
			plist_free(message);
			message = NULL;
			continue;
		}
		plist_get_string_val(node, &type);

		// data request messages are sent by restored whenever it requires
		// files sent to the server by the client. these data requests include
		// SystemImageData, KernelCache, and NORData requests
		if (!strcmp(type, "DataRequestMsg")) {
			error = restore_handle_data_request_msg(device, restore, message, tss, ipsw, filesystem);
		}

		// progress notification messages sent by the restored inform the client
		// of it's current operation and sometimes percent of progress is complete
		else if (!strcmp(type, "ProgressMsg")) {
			error = restore_handle_progress_msg(restore, message);
		}

		// status messages usually indicate the current state of the restored
		// process or often to signal an error has been encountered
		else if (!strcmp(type, "StatusMsg")) {
			error = restore_handle_status_msg(restore, message);
		}

		// there might be some other message types i'm not aware of, but I think
		// at least the "previous error logs" messages usually end up here
		else {
			debug("Unknown message type received\n");
			debug_plist(message);
		}

		// finally, if any of these message handlers returned -1 then we encountered
		// an unrecoverable error, so we need to bail.
		if (error < 0) {
			error("ERROR: Unable to successfully restore device\n");
			idevicerestore_quit = 1;
		}

		plist_free(message);
		message = NULL;
	}

	restore_close(device, restore);
	return 0;
}
Beispiel #24
0
int asr_open_with_timeout(idevice_t device, asr_client_t* asr) {
	int i = 0;
	int attempts = 10;
	idevice_connection_t connection = NULL;
	idevice_error_t device_error = IDEVICE_E_SUCCESS;

	*asr = NULL;

	if (device == NULL) {
		return -1;
	}

	debug("Connecting to ASR\n");
	for (i = 1; i <= attempts; i++) {
		device_error = idevice_connect(device, ASR_PORT, &connection);
		if (device_error == IDEVICE_E_SUCCESS) {
			break;
		}

		if (i >= attempts) {
			error("ERROR: Unable to connect to ASR client\n");
			return -1;
		}

		sleep(2);
		debug("Retrying connection...\n");
	}

	asr_client_t asr_loc = (asr_client_t)malloc(sizeof(struct asr_client));
	memset(asr_loc, '\0', sizeof(struct asr_client));
	asr_loc->connection = connection;

	/* receive Initiate command message */
	plist_t data = NULL;
	asr_loc->checksum_chunks = 0;
	if (asr_receive(asr_loc, &data) < 0) {
		error("ERROR: Unable to receive data from ASR\n");
		asr_free(asr_loc);
		plist_free(data);
		return -1;
	}
	plist_t node;
	node = plist_dict_get_item(data, "Command");
	if (node && (plist_get_node_type(node) == PLIST_STRING)) {
		char* strval = NULL;
		plist_get_string_val(node, &strval);
		if (strval && (strcmp(strval, "Initiate") != 0)) {
			error("ERROR: unexpected ASR plist received:\n");
			debug_plist(data);
			plist_free(data);
			asr_free(asr_loc);
			return -1;
		}
	}

	node = plist_dict_get_item(data, "Checksum Chunks");
	if (node && (plist_get_node_type(node) == PLIST_BOOLEAN)) {
		plist_get_bool_val(node, &(asr_loc->checksum_chunks));
	}
	plist_free(data);

	*asr = asr_loc;

	return 0;
}