Example #1
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 #2
0
/**
 * Creates a new lockdownd client for the device.
 *
 * @note This function does not pair with the device or start a session. This
 *  has to be done manually by the caller after the client is created.
 *  The device disconnects automatically if the lockdown connection idles
 *  for more than 10 seconds. Make sure to call lockdownd_client_free() as soon
 *  as the connection is no longer needed.
 *
 * @param device The device to create a lockdownd client for
 * @param client The pointer to the location of the new lockdownd_client
 * @param label The label to use for communication. Usually the program name.
 *
 * @return LOCKDOWN_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL
 */
lockdownd_error_t lockdownd_client_new(idevice_t device, lockdownd_client_t *client, const char *label)
{
	if (!client)
		return LOCKDOWN_E_INVALID_ARG;

	static struct lockdownd_service_descriptor service = {
		.port = 0xf27e,
		.ssl_enabled = 0
	};

	property_list_service_client_t plistclient = NULL;
	if (property_list_service_client_new(device, (lockdownd_service_descriptor_t)&service, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
		debug_info("could not connect to lockdownd (device %s)", device->udid);
		return LOCKDOWN_E_MUX_ERROR;
	}

	lockdownd_client_t client_loc = (lockdownd_client_t) malloc(sizeof(struct lockdownd_client_private));
	client_loc->parent = plistclient;
	client_loc->ssl_enabled = 0;
	client_loc->session_id = NULL;

	if (idevice_get_udid(device, &client_loc->udid) != IDEVICE_E_SUCCESS) {
		debug_info("failed to get device udid.");
	}
	debug_info("device udid: %s", client_loc->udid);

	client_loc->label = label ? strdup(label) : NULL;

	*client = client_loc;

	return LOCKDOWN_E_SUCCESS;
}

/**
 * Creates a new lockdownd client for the device and starts initial handshake.
 * The handshake consists out of query_type, validate_pair, pair and
 * start_session calls. It uses the internal pairing record management.
 *
 * @note The device disconnects automatically if the lockdown connection idles
 *  for more than 10 seconds. Make sure to call lockdownd_client_free() as soon
 *  as the connection is no longer needed.
 *
 * @param device The device to create a lockdownd client for
 * @param client The pointer to the location of the new lockdownd_client
 * @param label The label to use for communication. Usually the program name.
 *  Pass NULL to disable sending the label in requests to lockdownd.
 *
 * @return LOCKDOWN_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL,
 *  LOCKDOWN_E_INVALID_CONF if configuration data is wrong
 */
lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdownd_client_t *client, const char *label)
{
	if (!client)
		return LOCKDOWN_E_INVALID_ARG;

	lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
	lockdownd_client_t client_loc = NULL;
	char *host_id = NULL;
	char *type = NULL;

	ret = lockdownd_client_new(device, &client_loc, label);
	if (LOCKDOWN_E_SUCCESS != ret) {
		debug_info("failed to create lockdownd client.");
		return ret;
	}

	/* perform handshake */
	if (LOCKDOWN_E_SUCCESS != lockdownd_query_type(client_loc, &type)) {
		debug_info("QueryType failed in the lockdownd client.");
		ret = LOCKDOWN_E_NOT_ENOUGH_DATA;
	} else {
		if (strcmp("com.apple.mobile.lockdown", type)) {
			debug_info("Warning QueryType request returned \"%s\".", type);
		}
	}
	if (type)
		free(type);

	plist_t pair_record = NULL;
	userpref_read_pair_record(client_loc->udid, &pair_record);
	if (pair_record) {
		pair_record_get_host_id(pair_record, &host_id);
	}
	if (LOCKDOWN_E_SUCCESS == ret && !host_id) {
		ret = LOCKDOWN_E_INVALID_CONF;
	}

	if (LOCKDOWN_E_SUCCESS == ret && !pair_record) {
		/* attempt pairing */
		ret = lockdownd_pair(client_loc, NULL);
	}

	plist_free(pair_record);
	pair_record = NULL;

	/* in any case, we need to validate pairing to receive trusted host status */
	ret = lockdownd_validate_pair(client_loc, NULL);

	/* if not paired yet, let's do it now */
	if (LOCKDOWN_E_INVALID_HOST_ID == ret) {
		ret = lockdownd_pair(client_loc, NULL);

		if (LOCKDOWN_E_SUCCESS == ret) {
			ret = lockdownd_validate_pair(client_loc, NULL);
		} else if (LOCKDOWN_E_PAIRING_DIALOG_PENDING == ret) {
			debug_info("Device shows the pairing dialog.");
		}
	}

	if (LOCKDOWN_E_SUCCESS == ret) {
		if (!host_id) {
			userpref_read_pair_record(client_loc->udid, &pair_record);
			if (pair_record) {
				pair_record_get_host_id(pair_record, &host_id);
				plist_free(pair_record);
			}
		}

		ret = lockdownd_start_session(client_loc, host_id, NULL, NULL);
		if (LOCKDOWN_E_SUCCESS != ret) {
			debug_info("Session opening failed.");
		}

		if (host_id) {
			free(host_id);
			host_id = NULL;
		}
	}
	
	if (LOCKDOWN_E_SUCCESS == ret) {
		*client = client_loc;
	} else {
		lockdownd_client_free(client_loc);
	}

	return ret;
}

/**
 * Returns a new plist from the supplied lockdownd pair record. The caller is
 * responsible for freeing the plist.
 *
 * @param pair_record The pair record to create a plist from.
 *
 * @return A pair record plist from the device, NULL if pair_record is not set
 */
static plist_t lockdownd_pair_record_to_plist(lockdownd_pair_record_t pair_record)
{
	if (!pair_record)
		return NULL;

	/* setup request plist */
	plist_t dict = plist_new_dict();
	plist_dict_set_item(dict, "DeviceCertificate", plist_new_data(pair_record->device_certificate, strlen(pair_record->device_certificate)));
	plist_dict_set_item(dict, "HostCertificate", plist_new_data(pair_record->host_certificate, strlen(pair_record->host_certificate)));
	plist_dict_set_item(dict, "HostID", plist_new_string(pair_record->host_id));
	plist_dict_set_item(dict, "RootCertificate", plist_new_data(pair_record->root_certificate, strlen(pair_record->root_certificate)));
	plist_dict_set_item(dict, "SystemBUID", plist_new_string(pair_record->system_buid));

	return dict;
}

/**
 * Generates a pair record plist with required certificates for a specific
 * device. If a pairing exists, it is loaded from the computer instead of being
 * generated.
 *
 * @param pair_record_plist Holds the pair record.
 *
 * @return LOCKDOWN_E_SUCCESS on success
 */
static lockdownd_error_t pair_record_generate(lockdownd_client_t client, plist_t *pair_record)
{
	lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;

	key_data_t public_key = { NULL, 0 };
	char* host_id = NULL;
	char* system_buid = NULL;

	/* retrieve device public key */
	ret = lockdownd_get_device_public_key_as_key_data(client, &public_key);
	if (ret != LOCKDOWN_E_SUCCESS) {
		debug_info("device refused to send public key.");
		goto leave;
	}
	debug_info("device public key follows:\n%.*s", public_key.size, public_key.data);

	*pair_record = plist_new_dict();

	/* generate keys and certificates into pair record */
	userpref_error_t uret = USERPREF_E_SUCCESS;
	uret = pair_record_generate_keys_and_certs(*pair_record, public_key);
	switch(uret) {
		case USERPREF_E_INVALID_ARG:
			ret = LOCKDOWN_E_INVALID_ARG;
			break;
		case USERPREF_E_INVALID_CONF:
			ret = LOCKDOWN_E_INVALID_CONF;
			break;
		case USERPREF_E_SSL_ERROR:
			ret = LOCKDOWN_E_SSL_ERROR;
		default:
			break;
	}

	/* set SystemBUID */
	userpref_read_system_buid(&system_buid);
	plist_dict_set_item(*pair_record, USERPREF_SYSTEM_BUID_KEY, plist_new_string(system_buid));

	/* set HostID */
	host_id = generate_uuid();
	pair_record_set_host_id(*pair_record, host_id);

	if (ret != LOCKDOWN_E_SUCCESS) {
		goto leave;
	}

leave:
	if (host_id)
		free(host_id);
	if (system_buid)
		free(system_buid);
	if (public_key.data)
		free(public_key.data);

	return ret;
}
Example #3
0
idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection)
{
	if (!connection || connection->ssl_data)
		return IDEVICE_E_INVALID_ARG;

	idevice_error_t ret = IDEVICE_E_SSL_ERROR;
	uint32_t return_me = 0;
	plist_t pair_record = NULL;

	userpref_read_pair_record(connection->udid, &pair_record);
	if (!pair_record) {
		debug_info("ERROR: Failed enabling SSL. Unable to read pair record for udid %s.", connection->udid);
		return ret;
	}

#ifdef HAVE_OPENSSL
	key_data_t root_cert = { NULL, 0 };
	key_data_t root_privkey = { NULL, 0 };

	pair_record_import_crt_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, &root_cert);
	pair_record_import_key_with_name(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, &root_privkey);

	if (pair_record)
		plist_free(pair_record);

	BIO *ssl_bio = BIO_new(BIO_s_socket());
	if (!ssl_bio) {
		debug_info("ERROR: Could not create SSL bio.");
		return ret;
	}
	BIO_set_fd(ssl_bio, (int)(long)connection->data, BIO_NOCLOSE);

	SSL_CTX *ssl_ctx = SSL_CTX_new(SSLv3_method());
	if (ssl_ctx == NULL) {
		debug_info("ERROR: Could not create SSL context.");
		BIO_free(ssl_bio);
		return ret;
	}

	BIO* membp;
	X509* rootCert = NULL;
	membp = BIO_new_mem_buf(root_cert.data, root_cert.size);
	PEM_read_bio_X509(membp, &rootCert, NULL, NULL);
	BIO_free(membp);
	if (SSL_CTX_use_certificate(ssl_ctx, rootCert) != 1) {
		debug_info("WARNING: Could not load RootCertificate");
	}
	X509_free(rootCert);
	free(root_cert.data);

	RSA* rootPrivKey = NULL;
	membp = BIO_new_mem_buf(root_privkey.data, root_privkey.size);
	PEM_read_bio_RSAPrivateKey(membp, &rootPrivKey, NULL, NULL);
	BIO_free(membp);
	if (SSL_CTX_use_RSAPrivateKey(ssl_ctx, rootPrivKey) != 1) {
		debug_info("WARNING: Could not load RootPrivateKey");
	}
	RSA_free(rootPrivKey);
	free(root_privkey.data);

	SSL *ssl = SSL_new(ssl_ctx);
	if (!ssl) {
		debug_info("ERROR: Could not create SSL object");
		BIO_free(ssl_bio);
		SSL_CTX_free(ssl_ctx);
		return ret;
	}
	SSL_set_connect_state(ssl);
	SSL_set_verify(ssl, 0, ssl_verify_callback);
	SSL_set_bio(ssl, ssl_bio, ssl_bio);

	return_me = SSL_do_handshake(ssl);
	if (return_me != 1) {
		debug_info("ERROR in SSL_do_handshake: %s", errorstring(SSL_get_error(ssl, return_me)));
		SSL_free(ssl);
		SSL_CTX_free(ssl_ctx);
	} else {
		ssl_data_t ssl_data_loc = (ssl_data_t)malloc(sizeof(struct ssl_data_private));
		ssl_data_loc->session = ssl;
		ssl_data_loc->ctx = ssl_ctx;
		connection->ssl_data = ssl_data_loc;
		ret = IDEVICE_E_SUCCESS;
		debug_info("SSL mode enabled, cipher: %s", SSL_get_cipher(ssl));
	}
#else
	ssl_data_t ssl_data_loc = (ssl_data_t)malloc(sizeof(struct ssl_data_private));

	/* Set up GnuTLS... */
	debug_info("enabling SSL mode");
	errno = 0;
	gnutls_certificate_allocate_credentials(&ssl_data_loc->certificate);
	gnutls_certificate_client_set_retrieve_function(ssl_data_loc->certificate, internal_cert_callback);
	gnutls_init(&ssl_data_loc->session, GNUTLS_CLIENT);
	gnutls_priority_set_direct(ssl_data_loc->session, "NONE:+VERS-SSL3.0:+ANON-DH:+RSA:+AES-128-CBC:+AES-256-CBC:+SHA1:+MD5:+COMP-NULL", NULL);
	gnutls_credentials_set(ssl_data_loc->session, GNUTLS_CRD_CERTIFICATE, ssl_data_loc->certificate);
	gnutls_session_set_ptr(ssl_data_loc->session, ssl_data_loc);

	gnutls_x509_crt_init(&ssl_data_loc->root_cert);
	gnutls_x509_crt_init(&ssl_data_loc->host_cert);
	gnutls_x509_privkey_init(&ssl_data_loc->root_privkey);
	gnutls_x509_privkey_init(&ssl_data_loc->host_privkey);

	pair_record_import_crt_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, ssl_data_loc->root_cert);
	pair_record_import_crt_with_name(pair_record, USERPREF_HOST_CERTIFICATE_KEY, ssl_data_loc->host_cert);
	pair_record_import_key_with_name(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, ssl_data_loc->root_privkey);
	pair_record_import_key_with_name(pair_record, USERPREF_HOST_PRIVATE_KEY_KEY, ssl_data_loc->host_privkey);

	if (pair_record)
		plist_free(pair_record);

	debug_info("GnuTLS step 1...");
	gnutls_transport_set_ptr(ssl_data_loc->session, (gnutls_transport_ptr_t)connection);
	debug_info("GnuTLS step 2...");
	gnutls_transport_set_push_function(ssl_data_loc->session, (gnutls_push_func) & internal_ssl_write);
	debug_info("GnuTLS step 3...");
	gnutls_transport_set_pull_function(ssl_data_loc->session, (gnutls_pull_func) & internal_ssl_read);
	debug_info("GnuTLS step 4 -- now handshaking...");
	if (errno) {
		debug_info("WARNING: errno says %s before handshake!", strerror(errno));
	}
	return_me = gnutls_handshake(ssl_data_loc->session);
	debug_info("GnuTLS handshake done...");

	if (return_me != GNUTLS_E_SUCCESS) {
		internal_ssl_cleanup(ssl_data_loc);
		free(ssl_data_loc);
		debug_info("GnuTLS reported something wrong.");
		gnutls_perror(return_me);
		debug_info("oh.. errno says %s", strerror(errno));
	} else {
		connection->ssl_data = ssl_data_loc;
		ret = IDEVICE_E_SUCCESS;
		debug_info("SSL mode enabled");
	}
#endif
	return ret;
}
Example #4
0
int main(int argc, char **argv)
{
	lockdownd_client_t client = NULL;
	idevice_t device = NULL;
	idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
	lockdownd_error_t lerr;
	int result;

	char *type = NULL;
	char *cmd;
	typedef enum {
		OP_NONE = 0, OP_PAIR, OP_VALIDATE, OP_UNPAIR, OP_LIST, OP_HOSTID, OP_SYSTEMBUID
	} op_t;
	op_t op = OP_NONE;

	parse_opts(argc, argv);

	if ((argc - optind) < 1) {
		printf("ERROR: You need to specify a COMMAND!\n");
		print_usage(argc, argv);
		exit(EXIT_FAILURE);
	}

	cmd = (argv+optind)[0];

	if (!strcmp(cmd, "pair")) {
		op = OP_PAIR;
	} else if (!strcmp(cmd, "validate")) {
		op = OP_VALIDATE;
	} else if (!strcmp(cmd, "unpair")) {
		op = OP_UNPAIR;
	} else if (!strcmp(cmd, "list")) {
		op = OP_LIST;
	} else if (!strcmp(cmd, "hostid")) {
		op = OP_HOSTID;
	} else if (!strcmp(cmd, "systembuid")) {
		op = OP_SYSTEMBUID;
	} else {
		printf("ERROR: Invalid command '%s' specified\n", cmd);
		print_usage(argc, argv);
		exit(EXIT_FAILURE);
	}

	if (op == OP_SYSTEMBUID) {
		char *systembuid = NULL;
		userpref_read_system_buid(&systembuid);

		printf("%s\n", systembuid);

		if (systembuid)
			free(systembuid);

		return EXIT_SUCCESS;
	}

	if (op == OP_LIST) {
		unsigned int i;
		char **udids = NULL;
		unsigned int count = 0;
		userpref_get_paired_udids(&udids, &count);
		for (i = 0; i < count; i++) {
			printf("%s\n", udids[i]);
			free(udids[i]);
		}
		if (udids)
			free(udids);
		if (udid)
			free(udid);
		return EXIT_SUCCESS;
	}

	if (udid) {
		ret = idevice_new(&device, udid);
		free(udid);
		udid = NULL;
		if (ret != IDEVICE_E_SUCCESS) {
			printf("No device found with udid %s, is it plugged in?\n", udid);
			return EXIT_FAILURE;
		}
	} else {
		ret = idevice_new(&device, NULL);
		if (ret != IDEVICE_E_SUCCESS) {
			printf("No device found, is it plugged in?\n");
			return EXIT_FAILURE;
		}
	}

	ret = idevice_get_udid(device, &udid);
	if (ret != IDEVICE_E_SUCCESS) {
		printf("ERROR: Could not get device udid, error code %d\n", ret);
		result = EXIT_FAILURE;
		goto leave;
	}

	if (op == OP_HOSTID) {
		plist_t pair_record = NULL;
		char *hostid = NULL;

		userpref_read_pair_record(udid, &pair_record);
		pair_record_get_host_id(pair_record, &hostid);

		printf("%s\n", hostid);

		if (hostid)
			free(hostid);

		if (pair_record)
			plist_free(pair_record);

		return EXIT_SUCCESS;
	}

	lerr = lockdownd_client_new(device, &client, "idevicepair");
	if (lerr != LOCKDOWN_E_SUCCESS) {
		idevice_free(device);
		printf("ERROR: Could not connect to lockdownd, error code %d\n", lerr);
		return EXIT_FAILURE;
	}

	result = EXIT_SUCCESS;

	lerr = lockdownd_query_type(client, &type);
	if (lerr != LOCKDOWN_E_SUCCESS) {
		printf("QueryType failed, error code %d\n", lerr);
		result = EXIT_FAILURE;
		goto leave;
	} else {
		if (strcmp("com.apple.mobile.lockdown", type)) {
			printf("WARNING: QueryType request returned '%s'\n", type);
		}
		if (type) {
			free(type);
		}
	}

	switch(op) {
		default:
		case OP_PAIR:
		lerr = lockdownd_pair(client, NULL);
		if (lerr == LOCKDOWN_E_SUCCESS) {
			printf("SUCCESS: Paired with device %s\n", udid);
		} else {
			result = EXIT_FAILURE;
			print_error_message(lerr);
		}
		break;

		case OP_VALIDATE:
		lerr = lockdownd_validate_pair(client, NULL);
		if (lerr == LOCKDOWN_E_SUCCESS) {
			printf("SUCCESS: Validated pairing with device %s\n", udid);
		} else {
			result = EXIT_FAILURE;
			print_error_message(lerr);
		}
		break;

		case OP_UNPAIR:
		lerr = lockdownd_unpair(client, NULL);
		if (lerr == LOCKDOWN_E_SUCCESS) {
			printf("SUCCESS: Unpaired with device %s\n", udid);
		} else {
			result = EXIT_FAILURE;
			print_error_message(lerr);
		}
		break;
	}

leave:
	lockdownd_client_free(client);
	idevice_free(device);
	if (udid) {
		free(udid);
	}
	return result;
}
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;
	lockdownd_service_descriptor_t service = NULL;
	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 != (ret = lockdownd_client_new_with_handshake(device, &lockdown_client, "idevicediagnostics"))) {
		idevice_free(device);
		printf("ERROR: Could not connect to lockdownd, error code %d\n", ret);
		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", &service);
	if (ret != LOCKDOWN_E_SUCCESS) {
		/*  attempt to use older diagnostics service */
		ret = lockdownd_start_service(lockdown_client, "com.apple.iosdiagnostics.relay", &service);
	}

	lockdownd_client_free(lockdown_client);

	if ((ret == LOCKDOWN_E_SUCCESS) && service && (service->port > 0)) {
		if (diagnostics_relay_client_new(device, service, &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, DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT) == 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, DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT) == 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");
	}

	if (service) {
		lockdownd_service_descriptor_free(service);
		service = NULL;
	}

	idevice_free(device);

cleanup:
	if (node) {
		plist_free(node);
	}
	if (keys) {
		plist_free(keys);
	}
	if (cmd_arg) {
		free(cmd_arg);
	}
	return result;
}
Example #6
0
static int client_command(struct mux_client *client, struct usbmuxd_header *hdr)
{
    int res;
    usbmuxd_log(LL_DEBUG, "Client command in fd %d len %d ver %d msg %d tag %d", client->fd, hdr->length, hdr->version, hdr->message, hdr->tag);

    if(client->state != CLIENT_COMMAND) {
        usbmuxd_log(LL_ERROR, "Client %d command received in the wrong state", client->fd);
        if(send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0)
            return -1;
        client_close(client);
        return -1;
    }

    if((hdr->version != 0) && (hdr->version != 1)) {
        usbmuxd_log(LL_INFO, "Client %d version mismatch: expected 0 or 1, got %d", client->fd, hdr->version);
        send_result(client, hdr->tag, RESULT_BADVERSION);
        return 0;
    }

    struct usbmuxd_connect_request *ch;
    char *payload;
    uint32_t payload_size;

    switch(hdr->message) {
    case MESSAGE_PLIST:
        client->proto_version = 1;
        payload = (char*)(hdr) + sizeof(struct usbmuxd_header);
        payload_size = hdr->length - sizeof(struct usbmuxd_header);
        plist_t dict = NULL;
        plist_from_xml(payload, payload_size, &dict);
        if (!dict) {
            usbmuxd_log(LL_ERROR, "Could not parse plist from payload!");
            return -1;
        } else {
            char *message = NULL;
            plist_t node = plist_dict_get_item(dict, "MessageType");
            if (!node || plist_get_node_type(node) != PLIST_STRING) {
                usbmuxd_log(LL_ERROR, "Could not read valid MessageType node from plist!");
                plist_free(dict);
                return -1;
            }
            plist_get_string_val(node, &message);
            if (!message) {
                usbmuxd_log(LL_ERROR, "Could not extract MessageType from plist!");
                plist_free(dict);
                return -1;
            }
            if (!strcmp(message, "Listen")) {
                free(message);
                plist_free(dict);
                if (send_result(client, hdr->tag, 0) < 0)
                    return -1;
                usbmuxd_log(LL_DEBUG, "Client %d now LISTENING", client->fd);
                return start_listen(client);
            } else if (!strcmp(message, "Connect")) {
                uint64_t val;
                uint16_t portnum = 0;
                uint32_t device_id = 0;
                free(message);
                // get device id
                node = plist_dict_get_item(dict, "DeviceID");
                if (!node) {
                    usbmuxd_log(LL_ERROR, "Received connect request without device_id!");
                    plist_free(dict);
                    if (send_result(client, hdr->tag, RESULT_BADDEV) < 0)
                        return -1;
                    return 0;
                }
                val = 0;
                plist_get_uint_val(node, &val);
                device_id = (uint32_t)val;

                // get port number
                node = plist_dict_get_item(dict, "PortNumber");
                if (!node) {
                    usbmuxd_log(LL_ERROR, "Received connect request without port number!");
                    plist_free(dict);
                    if (send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0)
                        return -1;
                    return 0;
                }
                val = 0;
                plist_get_uint_val(node, &val);
                portnum = (uint16_t)val;
                plist_free(dict);

                usbmuxd_log(LL_DEBUG, "Client %d connection request to device %d port %d", client->fd, device_id, ntohs(portnum));
                res = device_start_connect(device_id, ntohs(portnum), client);
                if(res < 0) {
                    if (send_result(client, hdr->tag, -res) < 0)
                        return -1;
                } else {
                    client->connect_tag = hdr->tag;
                    client->connect_device = device_id;
                    client->state = CLIENT_CONNECTING1;
                }
                return 0;
            } else if (!strcmp(message, "ListDevices")) {
                free(message);
                plist_free(dict);
                if (send_device_list(client, hdr->tag) < 0)
                    return -1;
                return 0;
            } else if (!strcmp(message, "ReadBUID")) {
                free(message);
                plist_free(dict);
                if (send_system_buid(client, hdr->tag) < 0)
                    return -1;
                return 0;
            } else if (!strcmp(message, "ReadPairRecord")) {
                free(message);
                char* record_id = plist_dict_get_string_val(dict, "PairRecordID");
                plist_free(dict);

                res = send_pair_record(client, hdr->tag, record_id);
                if (record_id)
                    free(record_id);
                if (res < 0)
                    return -1;
                return 0;
            } else if (!strcmp(message, "SavePairRecord")) {
                uint32_t rval = RESULT_OK;
                free(message);
                char* record_id = plist_dict_get_string_val(dict, "PairRecordID");
                char* record_data = NULL;
                uint64_t record_size = 0;
                plist_t rdata = plist_dict_get_item(dict, "PairRecordData");
                if (rdata && plist_get_node_type(rdata) == PLIST_DATA) {
                    plist_get_data_val(rdata, &record_data, &record_size);
                }
                plist_free(dict);

                if (record_id && record_data) {
                    res = config_set_device_record(record_id, record_data, record_size);
                    if (res < 0) {
                        rval = -res;
                    }
                    free(record_id);
                } else {
                    rval = EINVAL;
                }
                if (send_result(client, hdr->tag, rval) < 0)
                    return -1;
                return 0;
            } else if (!strcmp(message, "DeletePairRecord")) {
                uint32_t rval = RESULT_OK;
                free(message);
                char* record_id = plist_dict_get_string_val(dict, "PairRecordID");
                plist_free(dict);
                if (record_id) {
                    res = config_remove_device_record(record_id);
                    if (res < 0) {
                        rval = -res;
                    }
                    free(record_id);
                } else {
                    rval = EINVAL;
                }
                if (send_result(client, hdr->tag, rval) < 0)
                    return -1;
                return 0;
            } else {
                usbmuxd_log(LL_ERROR, "Unexpected command '%s' received!", message);
                free(message);
                plist_free(dict);
                if (send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0)
                    return -1;
                return 0;
            }
        }
        // should not be reached?!
        return -1;
    case MESSAGE_LISTEN:
        if(send_result(client, hdr->tag, 0) < 0)
            return -1;
        usbmuxd_log(LL_DEBUG, "Client %d now LISTENING", client->fd);
        return start_listen(client);
    case MESSAGE_CONNECT:
        ch = (void*)hdr;
        usbmuxd_log(LL_DEBUG, "Client %d connection request to device %d port %d", client->fd, ch->device_id, ntohs(ch->port));
        res = device_start_connect(ch->device_id, ntohs(ch->port), client);
        if(res < 0) {
            if(send_result(client, hdr->tag, -res) < 0)
                return -1;
        } else {
            client->connect_tag = hdr->tag;
            client->connect_device = ch->device_id;
            client->state = CLIENT_CONNECTING1;
        }
        return 0;
    default:
        usbmuxd_log(LL_ERROR, "Client %d invalid command %d", client->fd, hdr->message);
        if(send_result(client, hdr->tag, RESULT_BADCOMMAND) < 0)
            return -1;
        return 0;
    }
    return -1;
}
Example #7
0
LIBIMOBILEDEVICE_API restored_error_t restored_client_new(idevice_t device, restored_client_t *client, const char *label)
{
	if (!client)
		return RESTORE_E_INVALID_ARG;

	restored_error_t ret = RESTORE_E_SUCCESS;
	idevice_error_t idev_ret;

	static struct lockdownd_service_descriptor service = {
		.port = 0xf27e,
		.ssl_enabled = 0
	};

	property_list_service_client_t plistclient = NULL;
	if (property_list_service_client_new(device, (lockdownd_service_descriptor_t)&service, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
		debug_info("could not connect to restored (device %s)", device->udid);
		return RESTORE_E_MUX_ERROR;
	}

	restored_client_t client_loc = (restored_client_t) malloc(sizeof(struct restored_client_private));
	client_loc->parent = plistclient;
	client_loc->udid = NULL;
	client_loc->label = NULL;
	client_loc->info = NULL;
	if (label != NULL)
		client_loc->label = strdup(label);

	idev_ret = idevice_get_udid(device, &client_loc->udid);
	if (IDEVICE_E_SUCCESS != idev_ret) {
		debug_info("failed to get device udid.");
		ret = RESTORE_E_DEVICE_ERROR;
	}
	debug_info("device udid: %s", client_loc->udid);

	if (RESTORE_E_SUCCESS == ret) {
		*client = client_loc;
	} else {
		restored_client_free(client_loc);
	}

	return ret;
}

LIBIMOBILEDEVICE_API restored_error_t restored_goodbye(restored_client_t client)
{
	if (!client)
		return RESTORE_E_INVALID_ARG;

	restored_error_t ret = RESTORE_E_UNKNOWN_ERROR;

	plist_t dict = plist_new_dict();
	plist_dict_add_label(dict, client->label);
	plist_dict_set_item(dict,"Request", plist_new_string("Goodbye"));

	debug_info("called");

	ret = restored_send(client, dict);
	plist_free(dict);
	dict = NULL;

	ret = restored_receive(client, &dict);
	if (!dict) {
		debug_info("did not get goodbye response back");
		return RESTORE_E_PLIST_ERROR;
	}

	if (restored_check_result(dict) == RESULT_SUCCESS) {
		debug_info("success");
		ret = RESTORE_E_SUCCESS;
	}
	plist_free(dict);
	dict = NULL;
	return ret;
}

LIBIMOBILEDEVICE_API restored_error_t restored_start_restore(restored_client_t client, plist_t options, uint64_t version)
{
	if (!client)
		return RESTORE_E_INVALID_ARG;

	plist_t dict = NULL;
	restored_error_t ret = RESTORE_E_UNKNOWN_ERROR;

	dict = plist_new_dict();
	plist_dict_add_label(dict, client->label);
	plist_dict_set_item(dict,"Request", plist_new_string("StartRestore"));
	if (options) {
		plist_dict_set_item(dict, "RestoreOptions", plist_copy(options));
	}
	plist_dict_set_item(dict,"RestoreProtocolVersion", plist_new_uint(version));

	/* send to device */
	ret = restored_send(client, dict);
	plist_free(dict);
	dict = NULL;

	return ret;
}

LIBIMOBILEDEVICE_API restored_error_t restored_reboot(restored_client_t client)
{
	if (!client)
		return RESTORE_E_INVALID_ARG;

	plist_t dict = NULL;
	restored_error_t ret = RESTORE_E_UNKNOWN_ERROR;

	dict = plist_new_dict();
	plist_dict_add_label(dict, client->label);
	plist_dict_set_item(dict,"Request", plist_new_string("Reboot"));

	/* send to device */
	ret = restored_send(client, dict);
	plist_free(dict);
	dict = NULL;

	if (RESTORE_E_SUCCESS != ret)
		return ret;

	ret = restored_receive(client, &dict);
	if (RESTORE_E_SUCCESS != ret)
		return ret;

	if (!dict)
		return RESTORE_E_PLIST_ERROR;

	plist_free(dict);
	dict = NULL;
	return ret;
}
dl_status dl_recv_packet(dl_t self, const char *packet, size_t length) {
  dl_private_t my = self->private_state;

  const char *tail = packet;
  uint32_t len = dl_sscanf_uint32(tail);
  tail += 4;
  if (len != length || len < 16) {
    return DL_ERROR;
  }
  uint32_t version = dl_sscanf_uint32(tail);
  tail += 4;
  uint32_t type = dl_sscanf_uint32(tail);
  tail += 4;
  (void)dl_sscanf_uint32(tail);
  tail += 4;
  const char *xml = tail;
  size_t xml_length = length - 16;

  if (version != 1 || type != TYPE_PLIST) {
    return DL_SUCCESS; // ignore?
  }

  plist_t dict = NULL;
  plist_from_xml(xml, xml_length, &dict);
  char *message = NULL;
  if (dict) {
    plist_t node = plist_dict_get_item(dict, "MessageType");
    if (plist_get_node_type(node) == PLIST_STRING) {
      plist_get_string_val(node, &message);
    }
  }

  dl_status ret = DL_ERROR;
  if (!message) {
    ret = DL_ERROR;
  } else if (!strcmp(message, "Result")) {
    plist_t node = plist_dict_get_item(dict, "Number");
    if (node) {
      uint64_t value = 0;
      plist_get_uint_val(node, &value);
      // just an ack of our Listen?
      ret = (value ? DL_ERROR : DL_SUCCESS);
    }
  } else if (!strcmp(message, "Attached")) {
    plist_t props = plist_dict_get_item(dict, "Properties");
    if (props) {
      uint64_t device_num = 0;
      plist_t node = plist_dict_get_item(props, "DeviceID");
      plist_get_uint_val(node, &device_num);

      uint64_t product_id = 0;
      node = plist_dict_get_item(props, "ProductID");
      plist_get_uint_val(node, &product_id);

      char *device_id = NULL;
      node = plist_dict_get_item(props, "SerialNumber");
      if (node) {
        plist_get_string_val(node, &device_id);
      }

      uint64_t location = 0;
      node = plist_dict_get_item(props, "LocationID");
      plist_get_uint_val(node, &location);

      ht_t d_ht = my->device_num_to_device_id;
      ht_put(d_ht, HT_KEY(device_num), device_id);
      ret = self->on_attach(self, device_id, (int)device_num);
    }
  } else if (strcmp(message, "Detached") == 0) {
    plist_t node = plist_dict_get_item(dict, "DeviceID");
    if (node) {
      uint64_t device_num = 0;
      plist_get_uint_val(node, &device_num);

      ht_t d_ht = my->device_num_to_device_id;
      char *device_id = (char *)ht_remove(d_ht, HT_KEY(device_num));
      if (device_id) {
        ret = self->on_detach(self, device_id, (int)device_num);
        free(device_id);
      }
    }
  }
  free(message);
  plist_free(dict);
  return ret;
}
Example #9
0
void print_lckd_request_result(iphone_lckd_client_t control, const char *domain, const char *request, const char *key, int format) {
	char *xml_doc = NULL;
	char *s = NULL;
	uint32_t xml_length = 0;
	iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
	
	plist_t node = plist_new_dict();
	if (domain) {
		plist_add_sub_key_el(node, "Domain");
		plist_add_sub_string_el(node, domain);
	}
	if (key) {
		plist_add_sub_key_el(node, "Key");
		plist_add_sub_string_el(node, key);
	}
	plist_add_sub_key_el(node, "Request");
	plist_add_sub_string_el(node, request);

	ret = iphone_lckd_send(control, node);
	if (ret == IPHONE_E_SUCCESS) {
		plist_free(node);
		node = NULL;
		ret = iphone_lckd_recv(control, &node);
		if (ret == IPHONE_E_SUCCESS) {
			/* seek to value node */
			for (
				node = plist_get_first_child(node);
				node != NULL;
				node = plist_get_next_sibling(node)
			) {
				if(plist_get_node_type(node) == PLIST_KEY)
				{
					plist_get_key_val(node, &s);

					if (strcmp("Value", s))
						continue;

					node = plist_get_next_sibling(node);

					if (plist_get_node_type(node) == PLIST_DICT) {
						if (plist_get_first_child(node))
						{
							switch (format) {
							case FORMAT_XML:
								plist_to_xml(node, &xml_doc, &xml_length);
								printf(xml_doc);
								free(xml_doc);
								break;
							case FORMAT_KEY_VALUE:
							default:
								plist_children_to_string(node);
								break;
							}
						}
					}
					else if(node && (key != NULL))
						plist_node_to_string(node);
				}
			}
		}
	}
	if (node)
		plist_free(node);
	node = NULL;
}
int main(int argc, char* argv[]) {
	int opt = 0;
	int optindex = 0;
	char* ipsw = NULL;
	char* uuid = NULL;
	int tss_enabled = 0;

	// create an instance of our context
	struct idevicerestore_client_t* client = (struct idevicerestore_client_t*) malloc(sizeof(struct idevicerestore_client_t));
	if (client == NULL) {
		error("ERROR: Out of memory\n");
		return -1;
	}
	memset(client, '\0', sizeof(struct idevicerestore_client_t));

	while ((opt = getopt_long(argc, argv, "dhcexu:", longopts, &optindex)) > 0) {
		switch (opt) {
		case 'h':
			usage(argc, argv);
			return 0;

		case 'd':
			client->flags |= FLAG_DEBUG;
			idevicerestore_debug = 1;
			break;

		case 'e':
			client->flags |= FLAG_ERASE;
			break;

		case 'c':
			client->flags |= FLAG_CUSTOM;
			break;

		case 'x':
			client->flags |= FLAG_EXCLUDE;
			break;

		case 'u':
			uuid = optarg;
			break;

		default:
			usage(argc, argv);
			return -1;
		}
	}

	if ((argc-optind) == 1) {
		argc -= optind;
		argv += optind;

		ipsw = argv[0];
	} else {
		usage(argc, argv);
		return -1;
	}

	if (client->flags & FLAG_DEBUG) {
		idevice_set_debug_level(1);
		irecv_set_debug_level(1);
	}

	client->uuid = uuid;
	client->ipsw = ipsw;

	// check which mode the device is currently in so we know where to start
	if (check_mode(client) < 0 || client->mode->index == MODE_UNKNOWN) {
		error("ERROR: Unable to discover device mode. Please make sure a device is attached.\n");
		return -1;
	}
	info("Found device in %s mode\n", client->mode->string);

	// discover the device type
	if (check_device(client) < 0 || client->device->index == DEVICE_UNKNOWN) {
		error("ERROR: Unable to discover device type\n");
		return -1;
	}
	info("Identified device as %s\n", client->device->product);

	if (client->mode->index == MODE_RESTORE) {
		if (restore_reboot(client) < 0) {
			error("ERROR: Unable to exit restore mode\n");
			return -1;
		}
	}

	// extract buildmanifest
	plist_t buildmanifest = NULL;
	info("Extracting BuildManifest from IPSW\n");
	if (ipsw_extract_build_manifest(ipsw, &buildmanifest, &tss_enabled) < 0) {
		error("ERROR: Unable to extract BuildManifest from %s\n", ipsw);
		return -1;
	}

	/* print iOS information from the manifest */
	build_manifest_print_information(buildmanifest);

	if (client->flags & FLAG_CUSTOM) {
		/* prevent signing custom firmware */
		tss_enabled = 0;
		info("Custom firmware requested. Disabled TSS request.\n");
	}

	// choose whether this is an upgrade or a restore (default to upgrade)
	client->tss = NULL;
	plist_t build_identity = NULL;
	if (client->flags & FLAG_ERASE) {
		build_identity = build_manifest_get_build_identity(buildmanifest, 0);
		if (build_identity == NULL) {
			error("ERROR: Unable to find any build identities\n");
			plist_free(buildmanifest);
			return -1;
		}
	} else {
		// loop through all build identities in the build manifest
		// and list the valid ones
		int i = 0;
		int valid_builds = 0;
		int build_count = build_manifest_get_identity_count(buildmanifest);
		for (i = 0; i < build_count; i++) {
			build_identity = build_manifest_get_build_identity(buildmanifest, i);
			valid_builds++;
		}
	}

	/* print information about current build identity */
	build_identity_print_information(build_identity);

	/* retrieve shsh blobs if required */
	if (tss_enabled) {
		debug("Getting device's ECID for TSS request\n");
		/* fetch the device's ECID for the TSS request */
		if (get_ecid(client, &client->ecid) < 0) {
			error("ERROR: Unable to find device ECID\n");
			return -1;
		}
		info("Found ECID %llu\n", client->ecid);

		if (get_shsh_blobs(client, client->ecid, build_identity, &client->tss) < 0) {
			error("ERROR: Unable to get SHSH blobs for this device\n");
			return -1;
		}
	}

	/* verify if we have tss records if required */
	if ((tss_enabled) && (client->tss == NULL)) {
		error("ERROR: Unable to proceed without a TSS record.\n");
		plist_free(buildmanifest);
		return -1;
	}

	// Extract filesystem from IPSW and return its name
	char* filesystem = NULL;
	if (ipsw_extract_filesystem(client->ipsw, build_identity, &filesystem) < 0) {
		error("ERROR: Unable to extract filesystem from IPSW\n");
		if (client->tss)
			plist_free(client->tss);
		plist_free(buildmanifest);
		return -1;
	}

	// if the device is in normal mode, place device into recovery mode
	if (client->mode->index == MODE_NORMAL) {
		info("Entering recovery mode...\n");
		if (normal_enter_recovery(client) < 0) {
			error("ERROR: Unable to place device into recovery mode\n");
			if (client->tss)
				plist_free(client->tss);
			plist_free(buildmanifest);
			return -1;
		}
	}

	// if the device is in DFU mode, place device into recovery mode
	if (client->mode->index == MODE_DFU) {
		if (dfu_enter_recovery(client, build_identity) < 0) {
			error("ERROR: Unable to place device into recovery mode\n");
			plist_free(buildmanifest);
			if (client->tss)
				plist_free(client->tss);
			return -1;
		}
	}

	// if the device is in recovery mode, place device into restore mode
	if (client->mode->index == MODE_RECOVERY) {
		if (recovery_enter_restore(client, build_identity) < 0) {
			error("ERROR: Unable to place device into restore mode\n");
			plist_free(buildmanifest);
			if (client->tss)
				plist_free(client->tss);
			return -1;
		}
	}

	// device is finally in restore mode, let's do this
	if (client->mode->index == MODE_RESTORE) {
		info("Restoring device... \n");
		if (restore_device(client, build_identity, filesystem) < 0) {
			error("ERROR: Unable to restore device\n");
			return -1;
		}
	}

	info("Cleaning up...\n");
	if (filesystem)
		unlink(filesystem);

	info("DONE\n");
	return 0;
}
/**
 * Uploads an image to the device.
 *
 * @param client The connected mobile_image_mounter client.
 * @param image_type Type of image that is being uploaded.
 * @param image_size Total size of the image.
 * @param upload_cb Callback function that gets the data chunks for uploading
 *    the image.
 * @param userdata User defined data for the upload callback function.
 *
 * @return MOBILE_IMAGE_MOUNTER_E_SUCCESS on succes, or a
 *    MOBILE_IMAGE_MOUNTER_E_* error code otherwise.
 */
mobile_image_mounter_error_t mobile_image_mounter_upload_image(mobile_image_mounter_client_t client, const char *image_type, size_t image_size, mobile_image_mounter_upload_cb_t upload_cb, void* userdata)
{
	if (!client || !image_type || (image_size == 0) || !upload_cb) {
		return MOBILE_IMAGE_MOUNTER_E_INVALID_ARG;
	}
	mobile_image_mounter_lock(client);
	plist_t result = NULL;

	plist_t dict = plist_new_dict();
	plist_dict_set_item(dict, "Command", plist_new_string("ReceiveBytes"));
	plist_dict_set_item(dict, "ImageSize", plist_new_uint(image_size));
	plist_dict_set_item(dict, "ImageType", plist_new_string(image_type));

	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("Error sending XML plist to device!");
		goto leave_unlock;
	}

	res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &result));
	if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
		debug_info("Error receiving response from device!");
		goto leave_unlock;
	}
	res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED;

	char* strval = NULL;
	plist_t node = plist_dict_get_item(result, "Status");
	if (node && plist_get_node_type(node) == PLIST_STRING) {
		plist_get_string_val(node, &strval);
	}
	if (!strval) {
		debug_info("Error: Unexpected response received!");
		goto leave_unlock;
	}
	if (strcmp(strval, "ReceiveBytesAck") != 0) {
		debug_info("Error: didn't get ReceiveBytesAck but %s", strval);
		free(strval);
		goto leave_unlock;
	}
	free(strval);

	size_t tx = 0;
	size_t bufsize = 65536;
	unsigned char *buf = (unsigned char*)malloc(bufsize);
	if (!buf) {
		debug_info("Out of memory");
		res = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR;
		goto leave_unlock;
	}
	debug_info("uploading image (%d bytes)", (int)image_size);
	while (tx < image_size) {
		size_t remaining = image_size - tx;
		size_t amount = (remaining < bufsize) ? remaining : bufsize;
		ssize_t r = upload_cb(buf, amount, userdata);
		if (r < 0) {
			debug_info("upload_cb returned %d", (int)r);
			break;
		}
		uint32_t sent = 0;
		if (service_send(client->parent->parent, (const char*)buf, (uint32_t)r, &sent) != SERVICE_E_SUCCESS) {
			debug_info("service_send failed");
			break;
		}
		tx += r;
	}
	free(buf);
	if (tx < image_size) {
		debug_info("Error: failed to upload image");
		goto leave_unlock;
	}
	debug_info("image uploaded");

	res = mobile_image_mounter_error(property_list_service_receive_plist(client->parent, &result));
	if (res != MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
		debug_info("Error receiving response from device!");
		goto leave_unlock;
	}
	res = MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED;

	strval = NULL;
	node = plist_dict_get_item(result, "Status");
	if (node && plist_get_node_type(node) == PLIST_STRING) {
		plist_get_string_val(node, &strval);
	}
	if (!strval) {
		debug_info("Error: Unexpected response received!");	
		goto leave_unlock;
	}
	if (strcmp(strval, "Complete") != 0) {
		debug_info("Error: didn't get Complete but %s", strval);
		free(strval);
		goto leave_unlock;
	} else {
		res = MOBILE_IMAGE_MOUNTER_E_SUCCESS;
	}
	free(strval);
	

leave_unlock:
	mobile_image_mounter_unlock(client);
	if (result)
		plist_free(result);
	return res;

}
Example #12
0
static void* preflight_worker_handle_device_add(void* userdata)
{
	struct device_info *info = (struct device_info*)userdata;
	struct idevice_private *_dev = (struct idevice_private*)malloc(sizeof(struct idevice_private));
	_dev->udid = strdup(info->serial);
	_dev->mux_id = info->id;
	_dev->conn_type = CONNECTION_USBMUXD;
	_dev->conn_data = NULL;
	_dev->version = 0;

	idevice_t dev = (idevice_t)_dev;

	lockdownd_client_t lockdown = NULL;
	lockdownd_error_t lerr;

	plist_t value = NULL;
	char* version_str = NULL;

	usbmuxd_log(LL_INFO, "%s: Starting preflight on device %s...", __func__, _dev->udid);

retry:
	lerr = lockdownd_client_new(dev, &lockdown, "usbmuxd");
	if (lerr != LOCKDOWN_E_SUCCESS) {
		usbmuxd_log(LL_ERROR, "%s: ERROR: Could not connect to lockdownd on device %s, lockdown error %d", __func__, _dev->udid, lerr);
		goto leave;
	}

	char *type = NULL;
	lerr = lockdownd_query_type(lockdown, &type);
	if (!type) {
		usbmuxd_log(LL_ERROR, "%s: ERROR: Could not get lockdownd type from device %s, lockdown error %d", __func__, _dev->udid, lerr);
		goto leave;
	}

	if (strcmp(type, "com.apple.mobile.lockdown") != 0) {
		// make restore mode devices visible
		free(type);
		usbmuxd_log(LL_INFO, "%s: Finished preflight on device %s", __func__, _dev->udid);
		client_device_add(info);
		goto leave;
	}
	free(type);

	int is_device_paired = 0;
	char *host_id = NULL;
	if (config_has_device_record(dev->udid)) {
		config_device_record_get_host_id(dev->udid, &host_id);
		lerr = lockdownd_start_session(lockdown, host_id, NULL, NULL);
		if (host_id)
			free(host_id);
		if (lerr == LOCKDOWN_E_SUCCESS) {
			usbmuxd_log(LL_INFO, "%s: StartSession success for device %s", __func__, _dev->udid);
			usbmuxd_log(LL_INFO, "%s: Finished preflight on device %s", __func__, _dev->udid);
			client_device_add(info);
			goto leave;
		}

		usbmuxd_log(LL_INFO, "%s: StartSession failed on device %s, lockdown error %d", __func__, _dev->udid, lerr);
	} else {
		lerr = LOCKDOWN_E_INVALID_HOST_ID;
	}
	switch (lerr) {
	case LOCKDOWN_E_INVALID_HOST_ID:
		usbmuxd_log(LL_INFO, "%s: Device %s is not paired with this host.", __func__, _dev->udid);
		break;
	case LOCKDOWN_E_SSL_ERROR:
		usbmuxd_log(LL_ERROR, "%s: The stored pair record for device %s is invalid. Removing.", __func__, _dev->udid);
		if (config_remove_device_record(_dev->udid) == 0) {
			lockdownd_client_free(lockdown);
			lockdown = NULL;
			goto retry;
		} else {
			usbmuxd_log(LL_ERROR, "%s: Could not remove pair record for device %s", __func__, _dev->udid);
		}
		break;
	default:
		is_device_paired = 1;
		break;
	}

	lerr = lockdownd_get_value(lockdown, NULL, "ProductVersion", &value);
	if (lerr != LOCKDOWN_E_SUCCESS) {
		usbmuxd_log(LL_ERROR, "%s: ERROR: Could not get ProductVersion from device %s, lockdown error %d", __func__, _dev->udid, lerr);
		goto leave;
	}

	if (value && plist_get_node_type(value) == PLIST_STRING) {
		plist_get_string_val(value, &version_str);
	}

	if (!version_str) {
		usbmuxd_log(LL_ERROR, "%s: Could not get ProductVersion string from device %s handle %d", __func__, _dev->udid, (int)(long)_dev->conn_data);
		goto leave;
	}

	int version_major = strtol(version_str, NULL, 10);
	if (version_major >= 7) {
		/* iOS 7.0 and later */
		usbmuxd_log(LL_INFO, "%s: Found ProductVersion %s device %s", __func__, version_str, _dev->udid);

		lockdownd_set_untrusted_host_buid(lockdown);

		/* if not paired, trigger the trust dialog to make sure it appears */
		if (!is_device_paired) {
			if (lockdownd_pair(lockdown, NULL) == LOCKDOWN_E_SUCCESS) {
				/* if device is still showing the setup screen it will pair even without trust dialog */
				usbmuxd_log(LL_INFO, "%s: Pair success for device %s", __func__, _dev->udid);
				usbmuxd_log(LL_INFO, "%s: Finished preflight on device %s", __func__, _dev->udid);
				client_device_add(info);
				goto leave;
			}
		}

		lockdownd_service_descriptor_t service = NULL;
		lerr = lockdownd_start_service(lockdown, "com.apple.mobile.insecure_notification_proxy", &service);
		if (lerr != LOCKDOWN_E_SUCCESS) {
			/* even though we failed, simple mode should still work, so only warn of an error */
			usbmuxd_log(LL_INFO, "%s: ERROR: Could not start insecure_notification_proxy on %s, lockdown error %d", __func__, _dev->udid, lerr);
			client_device_add(info);
			goto leave;
		}

		np_client_t np = NULL;
		np_client_new(dev, service, &np);

		lockdownd_service_descriptor_free(service);
		service = NULL;

		lockdownd_client_free(lockdown);
		lockdown = NULL;

		struct cb_data cbdata;
		cbdata.dev = dev;
		cbdata.np = np;
		cbdata.is_device_connected = 1;

		np_set_notify_callback(np, np_callback, (void*)&cbdata);
		device_set_preflight_cb_data(info->id, (void*)&cbdata);

		const char* spec[] = {
			"com.apple.mobile.lockdown.request_pair",
			"com.apple.mobile.lockdown.request_host_buid",
			NULL
		}; 
		np_observe_notifications(np, spec);

		/* TODO send notification to user's desktop */

		usbmuxd_log(LL_INFO, "%s: Waiting for user to trust this computer on device %s", __func__, _dev->udid);

		/* make device visible anyways */
		client_device_add(info);

		while (cbdata.np && cbdata.is_device_connected == 1) {
			sleep(1);
		}
		device_set_preflight_cb_data(info->id, NULL);

		usbmuxd_log(LL_INFO, "%s: Finished waiting for notification from device %s, is_device_connected %d", __func__, _dev->udid, cbdata.is_device_connected);

		if (cbdata.np) {
			np_client_free(cbdata.np);
		}
	} else {
		/* iOS 6.x and earlier */
		lerr = lockdownd_pair(lockdown, NULL);
		if (lerr != LOCKDOWN_E_SUCCESS) {
			if (lerr == LOCKDOWN_E_PASSWORD_PROTECTED) {
				usbmuxd_log(LL_INFO, "%s: Device %s is locked with a passcode. Cannot pair.", __func__, _dev->udid);
				/* TODO send notification to user's desktop */
			} else {
				usbmuxd_log(LL_ERROR, "%s: ERROR: Pair failed for device %s, lockdown error %d", __func__, _dev->udid, lerr);
			}

			usbmuxd_log(LL_INFO, "%s: Finished preflight on device %s", __func__, _dev->udid);

			/* make device visible anyways */
			client_device_add(info);

			goto leave;
		}

		host_id = NULL;
		config_device_record_get_host_id(dev->udid, &host_id);
		lerr = lockdownd_start_session(lockdown, host_id, NULL, NULL);
		free(host_id);
		if (lerr != LOCKDOWN_E_SUCCESS) {
			usbmuxd_log(LL_ERROR, "%s: ERROR StartSession failed on device %s, lockdown error %d", __func__, _dev->udid, lerr);
			goto leave;
		}

		lerr = lockdownd_validate_pair(lockdown, NULL);
		if (lerr != LOCKDOWN_E_SUCCESS) {
			usbmuxd_log(LL_ERROR, "%s: ERROR: ValidatePair failed for device %s, lockdown error %d", __func__, _dev->udid, lerr);
			goto leave;
		}

		usbmuxd_log(LL_INFO, "%s: Finished preflight on device %s", __func__, _dev->udid);

		/* emit device added event and thus make device visible to clients */
		client_device_add(info);
	}

leave:
	if (value)
		plist_free(value);
	if (version_str)
		free(version_str);
	if (lockdown)
		lockdownd_client_free(lockdown);
	if (dev)
		idevice_free(dev);

	free(info);

	return NULL;
}
Example #13
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;
}
Example #14
0
int asr_perform_validation(asr_client_t asr, const char* filesystem) {
	FILE* file = NULL;
	uint64_t length = 0;
	char* command = NULL;
	plist_t node = NULL;
	plist_t packet = NULL;
	plist_t packet_info = NULL;
	plist_t payload_info = NULL;
	int attempts = 0;

	file = fopen(filesystem, "rb");
	if (file == NULL) {
		return -1;
	}

	fseeko(file, 0, SEEK_END);
	length = ftello(file);
	fseeko(file, 0, SEEK_SET);

	payload_info = plist_new_dict();
	plist_dict_set_item(payload_info, "Port", plist_new_uint(1));
	plist_dict_set_item(payload_info, "Size", plist_new_uint(length));

	packet_info = plist_new_dict();
	if (asr->checksum_chunks) {
		plist_dict_set_item(packet_info, "Checksum Chunk Size", plist_new_uint(ASR_CHECKSUM_CHUNK_SIZE));
	}
	plist_dict_set_item(packet_info, "FEC Slice Stride", plist_new_uint(ASR_FEC_SLICE_STRIDE));
	plist_dict_set_item(packet_info, "Packet Payload Size", plist_new_uint(ASR_PAYLOAD_PACKET_SIZE));
	plist_dict_set_item(packet_info, "Packets Per FEC", plist_new_uint(ASR_PACKETS_PER_FEC));
	plist_dict_set_item(packet_info, "Payload", payload_info);
	plist_dict_set_item(packet_info, "Stream ID", plist_new_uint(ASR_STREAM_ID));
	plist_dict_set_item(packet_info, "Version", plist_new_uint(ASR_VERSION));

	if (asr_send(asr, packet_info)) {
		error("ERROR: Unable to sent packet information to ASR\n");
		plist_free(packet_info);
		return -1;
	}
	plist_free(packet_info);

	while (1) {
		if (asr_receive(asr, &packet) < 0) {
			error("ERROR: Unable to receive validation packet\n");
			return -1;
		}

		if (packet == NULL) {
			if (attempts < 5) {
				info("Retrying to receive validation packet... %d\n", attempts);
				attempts++;
				sleep(1);
				continue;
			}
		}

		attempts = 0;

		node = plist_dict_get_item(packet, "Command");
		if (!node || plist_get_node_type(node) != PLIST_STRING) {
			error("ERROR: Unable to find command node in validation request\n");
			return -1;
		}
		plist_get_string_val(node, &command);

		if (!strcmp(command, "OOBData")) {
			int ret = asr_handle_oob_data_request(asr, packet, file);
			plist_free(packet);
			if (ret < 0)
				return ret;
		} else if(!strcmp(command, "Payload")) {
			plist_free(packet);
			break;

		} else {
			error("ERROR: Unknown command received from ASR\n");
			plist_free(packet);
			return -1;
		}
	}

	return 0;
}
Example #15
0
Uid& Uid::operator=(PList::Uid& i)
{
    plist_free(_node);
    _node = plist_copy(i.GetPlist());
    return *this;
}
Example #16
0
void 
_plist_free(void *privdata, void *pl) {
  (void) privdata;
  plist_free(pl);
}
Example #17
0
int main(int argc, char *argv[])
{
	int res = EXIT_FAILURE;
	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
	struct stat mst;
	lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;

	memset(&opts, 0, sizeof(opts));
	opts.service_name = AFC_SERVICE_NAME;

	if (fuse_opt_parse(&args, NULL, ifuse_opts, ifuse_opt_proc) == -1) {
		return EXIT_FAILURE;
	}

	if (!opts.mount_point) {
		fprintf(stderr, "ERROR: No mount point specified\n");
		return EXIT_FAILURE;
	}

	if (opts.device_udid && strlen(opts.device_udid) != 40) {
		fprintf(stderr, "Invalid device UDID specified, length needs to be 40 characters\n");
		return EXIT_FAILURE;
	}

	if (stat(opts.mount_point, &mst) < 0) {
		if (errno == ENOENT) {
			fprintf(stderr, "ERROR: the mount point specified does not exist\n");
			return EXIT_FAILURE;
		}
		
		fprintf(stderr, "There was an error accessing the mount point: %s\n", strerror(errno));
		return EXIT_FAILURE;
	}

	idevice_new(&phone, opts.device_udid ? opts.device_udid : NULL);
	if (!phone) {
		fprintf(stderr, "No device found, is it connected?\n");
		fprintf(stderr, "If it is make sure that your user has permissions to access the raw usb device.\n");
		fprintf(stderr, "If you're still having issues try unplugging the device and reconnecting it.\n");
		return EXIT_FAILURE;
	}
	
	ret = lockdownd_client_new_with_handshake(phone, &control, "ifuse");
	if (ret != LOCKDOWN_E_SUCCESS) {
		idevice_free(phone);
		if (ret == LOCKDOWN_E_PASSWORD_PROTECTED) {
			fprintf(stderr, "Please disable the password protection on your device and try again.\n");
			fprintf(stderr, "The device does not allow pairing as long as a password has been set.\n");
			fprintf(stderr, "You can enable it again after the connection succeeded.\n");
		} else {
			fprintf(stderr, "Failed to connect to lockdownd service on the device.\n");
			fprintf(stderr, "Try again. If it still fails try rebooting your device.\n");
		}
		return EXIT_FAILURE;
	}

	if (
#ifdef HAVE_LIBIMOBILEDEVICE_1_1_5
	(lockdownd_start_service(control, opts.service_name, &opts.service) != LOCKDOWN_E_SUCCESS) || !opts.service
#else
	(lockdownd_start_service(control, opts.service_name, &opts.port) != LOCKDOWN_E_SUCCESS) || !opts.port
#endif
 	) {
		lockdownd_client_free(control);
		idevice_free(phone);
		fprintf(stderr, "Failed to start AFC service '%s' on the device.\n", opts.service_name);
		if (!strcmp(opts.service_name, AFC2_SERVICE_NAME)) {
			fprintf(stderr, "This service enables access to the root filesystem of your device.\n");
			fprintf(stderr, "Your device needs to be jailbroken and have the AFC2 service installed.\n");
		}
		return EXIT_FAILURE;
	}

#ifdef HAVE_LIBIMOBILEDEVICE_1_1
	if (!strcmp(opts.service_name, HOUSE_ARREST_SERVICE_NAME)) {
#ifdef HAVE_LIBIMOBILEDEVICE_1_1_5
		house_arrest_client_new(phone, opts.service, &house_arrest);
#else
		house_arrest_client_new(phone, opts.port, &house_arrest);
#endif
		if (!house_arrest) {
			fprintf(stderr, "Could not start document sharing service!\n");
			return EXIT_FAILURE;
		}
		if (house_arrest_send_command(house_arrest, "VendContainer", opts.appid) != HOUSE_ARREST_E_SUCCESS) {
			fprintf(stderr, "Could not send VendContainer command!\n");
			goto leave_err;
		}

		plist_t dict = NULL;
		if (house_arrest_get_result(house_arrest, &dict) != HOUSE_ARREST_E_SUCCESS) {
			fprintf(stderr, "Could not get result from document sharing service!\n");
			goto leave_err;
		}
		plist_t node = plist_dict_get_item(dict, "Error");
		if (node) {
			char *str = NULL;
			plist_get_string_val(node, &str);
			fprintf(stderr, "ERROR: %s\n", str);
			if (str) free(str);
			goto leave_err;
		}
		plist_free(dict);

		fuse_opt_add_arg(&args, "-omodules=subdir");
		fuse_opt_add_arg(&args, "-osubdir=Documents");
	}
#endif
	res = fuse_main(args.argc, args.argv, &ifuse_oper, NULL);

#ifdef HAVE_LIBIMOBILEDEVICE_1_1
leave_err:
	if (house_arrest) {
		house_arrest_client_free(house_arrest);
	}
#endif
	return res;
}
/**
 * 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;
	}

leave_unlock:
	instproxy_unlock(client);
	return res;
}
Example #19
0
int main(int argc, char** argv)
{
	int res = -1;
	char* udid = NULL;

	int c = 0;
	int optidx = 0;
	const struct option longopts[] = {
		{ "udid", required_argument, NULL, 'u' },
		{ "help", no_argument, NULL, 'h' },
		{ NULL, 0, NULL, 0}
	};

	while ((c = getopt_long(argc, argv, "u:h", longopts, &optidx)) != -1) {
		switch (c) {
		case 'u':
			udid = strdup(optarg);
			break;
		case 'h':
			print_usage();
			return 0;
		default:
			print_usage();
			return -1;
		}
	}

	argc -= optind;
	argv += optind;

	if (argc > 1) {
		print_usage();
		return -1;
	}

	idevice_t device = NULL;
	if (idevice_new(&device, udid) != IDEVICE_E_SUCCESS) {
		fprintf(stderr, "ERROR: Could not connect to device\n");
		return -1;
	}

	lockdownd_client_t lockdown = NULL;
	lockdownd_error_t lerr = lockdownd_client_new_with_handshake(device, &lockdown, "idevicename");
	if (lerr != LOCKDOWN_E_SUCCESS) {
		idevice_free(device);
		fprintf(stderr, "ERROR: lockdown connection failed, lockdown error %d\n", lerr);
		return -1;
	}

	plist_t node = NULL;

	if (argc == 0) {
		// getting device name
		char* name = NULL;
		lerr = lockdownd_get_value(lockdown, NULL, "DeviceName", &node);
		if (node) {
			plist_get_string_val(node, &name);
			plist_free(node);
		}
		if (name) {
			printf("%s\n", name);
			free(name);
			res = 0;
		} else {
			fprintf(stderr, "ERROR: Could not get device name, lockdown error %d\n", lerr);
		}
	} else {
		// setting device name
		lerr = lockdownd_set_value(lockdown, NULL, "DeviceName", plist_new_string(argv[0]));
		if (lerr == LOCKDOWN_E_SUCCESS) {
			printf("device name set to '%s'\n", argv[0]);
			res = 0;
		} else {
			fprintf(stderr, "ERROR: Could not set device name, lockdown error %d\n", lerr);
		}
	}

	lockdownd_client_free(lockdown);
	idevice_free(device);

	if (udid) {
		free(udid);
	}

	return res;
}
/**
 * Internally used function that will synchronously receive messages from
 * the specified installation_proxy until it completes or an error occurs.
 *
 * If status_cb is not NULL, the callback function will be called each time
 * a status update or error message is received.
 *
 * @param client The connected installation proxy client
 * @param status_cb Pointer to a callback function or NULL
 * @param operation Operation name. Will be passed to the callback function
 *        in async mode or shown in debug messages in sync mode. 
 * @param user_data Callback data passed to status_cb.
 */
static instproxy_error_t instproxy_perform_operation(instproxy_client_t client, instproxy_status_cb_t status_cb, const char *operation, void *user_data)
{
	instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR;
	int ok = 1;
	plist_t dict = NULL;

	do {
		instproxy_lock(client);
		res = instproxy_error(property_list_service_receive_plist_with_timeout(client->parent, &dict, 30000));
		instproxy_unlock(client);
		if (res != INSTPROXY_E_SUCCESS) {
			debug_info("could not receive plist, error %d", res);
			break;
		}
		if (dict) {
			/* invoke callback function */
			if (status_cb) {
				status_cb(operation, dict, user_data);
			}
			/* check for 'Error', so we can abort cleanly */
			plist_t err = plist_dict_get_item(dict, "Error");
			if (err) {
#ifndef STRIP_DEBUG_CODE
				char *err_msg = NULL;
				plist_get_string_val(err, &err_msg);
				if (err_msg) {
					debug_info("(%s): ERROR: %s", operation, err_msg);
					free(err_msg);
				}
#endif
				ok = 0;
				res = INSTPROXY_E_OP_FAILED;
			}
			/* get 'Status' */
			plist_t status = plist_dict_get_item(dict, "Status");
			if (status) {
				char *status_msg = NULL;
				plist_get_string_val(status, &status_msg);
				if (status_msg) {
					if (!strcmp(status_msg, "Complete")) {
						ok = 0;
						res = INSTPROXY_E_SUCCESS;
					}
#ifndef STRIP_DEBUG_CODE
					plist_t npercent = plist_dict_get_item(dict, "PercentComplete");
					if (npercent) {
						uint64_t val = 0;
						int percent;
						plist_get_uint_val(npercent, &val);
						percent = val;
						debug_info("(%s): %s (%d%%)", operation, status_msg, percent);
					} else {
						debug_info("(%s): %s", operation, status_msg);
					}
#endif
					free(status_msg);
				}
			}
			plist_free(dict);
			dict = NULL;
		}
	} while (ok && client->parent);

	return res;
}
Example #21
0
int main(int argc, char *argv[])
{
	lockdownd_client_t client = NULL;
	idevice_t device = NULL;
	idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
	int i;
	int simple = 0;
	int format = FORMAT_KEY_VALUE;
	const char* udid = NULL;
	char *domain = NULL;
	char *key = NULL;
	char *xml_doc = NULL;
	uint32_t xml_length;
	plist_t node = 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);
				return 0;
			}
			udid = argv[i];
			continue;
		}
		else if (!strcmp(argv[i], "-q") || !strcmp(argv[i], "--domain")) {
			i++;
			if (!argv[i] || (strlen(argv[i]) < 4)) {
				print_usage(argc, argv);
				return 0;
			}
			if (!is_domain_known(argv[i])) {
				fprintf(stderr, "WARNING: Sending query with unknown domain \"%s\".\n", argv[i]);
			}
			domain = strdup(argv[i]);
			continue;
		}
		else if (!strcmp(argv[i], "-k") || !strcmp(argv[i], "--key")) {
			i++;
			if (!argv[i] || (strlen(argv[i]) <= 1)) {
				print_usage(argc, argv);
				return 0;
			}
			key = strdup(argv[i]);
			continue;
		}
		else if (!strcmp(argv[i], "-x") || !strcmp(argv[i], "--xml")) {
			format = FORMAT_XML;
			continue;
		}
		else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--simple")) {
			simple = 1;
			continue;
		}
		else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
			print_usage(argc, argv);
			return 0;
		}
		else {
			print_usage(argc, argv);
			return 0;
		}
	}

	ret = idevice_new(&device, udid);
	if (ret != IDEVICE_E_SUCCESS) {
		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");
		}
		return -1;
	}

	if (LOCKDOWN_E_SUCCESS != (simple ?
			lockdownd_client_new(device, &client, "ideviceinfo"):
			lockdownd_client_new_with_handshake(device, &client, "ideviceinfo"))) {
		idevice_free(device);
		return -1;
	}

	/* run query and output information */
	if(lockdownd_get_value(client, domain, key, &node) == LOCKDOWN_E_SUCCESS) {
		if (node) {
			switch (format) {
			case FORMAT_XML:
				plist_to_xml(node, &xml_doc, &xml_length);
				printf("%s", xml_doc);
				free(xml_doc);
				break;
			case FORMAT_KEY_VALUE:
				plist_print_to_stream(node, stdout);
				break;
			default:
				if (key != NULL)
					plist_print_to_stream(node, stdout);
			break;
			}
			plist_free(node);
			node = NULL;
		}
	}

	if (domain != NULL)
		free(domain);
	lockdownd_client_free(client);
	idevice_free(device);

	return 0;
}
Example #22
0
int asr_perform_validation(idevice_connection_t asr, const char* filesystem) {
	FILE* file = NULL;
	uint64_t length = 0;
	char* command = NULL;
	plist_t node = NULL;
	plist_t packet = NULL;
	plist_t packet_info = NULL;
	plist_t payload_info = NULL;
	int attempts = 0;

	file = fopen(filesystem, "rb");
	if (file == NULL) {
		return -1;
	}

	fseek(file, 0, SEEK_END);
	length = ftell(file);
	fseek(file, 0, SEEK_SET);

	payload_info = plist_new_dict();
	plist_dict_insert_item(payload_info, "Port", plist_new_uint(1));
	plist_dict_insert_item(payload_info, "Size", plist_new_uint(length));

	packet_info = plist_new_dict();
	plist_dict_insert_item(packet_info, "FEC Slice Stride", plist_new_uint(40));
	plist_dict_insert_item(packet_info, "Packet Payload Size", plist_new_uint(1450));
	plist_dict_insert_item(packet_info, "Packets Per FEC", plist_new_uint(25));
	plist_dict_insert_item(packet_info, "Payload", payload_info);
	plist_dict_insert_item(packet_info, "Stream ID", plist_new_uint(1));
	plist_dict_insert_item(packet_info, "Version", plist_new_uint(1));

	if (asr_send(asr, packet_info)) {
		error("ERROR: Unable to sent packet information to ASR\n");
		plist_free(packet_info);
		return -1;
	}
	plist_free(packet_info);

	while (1) {
		if (asr_receive(asr, &packet) < 0) {
			error("ERROR: Unable to receive validation packet\n");
			return -1;
		}

		if (packet == NULL) {
			if (attempts < 5) {
				info("Retrying to receive validation packet... %d\n", attempts);
				attempts++;
				sleep(1);
				continue;
			}
		}

		attempts = 0;

		node = plist_dict_get_item(packet, "Command");
		if (!node || plist_get_node_type(node) != PLIST_STRING) {
			error("ERROR: Unable to find command node in validation request\n");
			return -1;
		}
		plist_get_string_val(node, &command);

		if (!strcmp(command, "OOBData")) {
			asr_handle_oob_data_request(asr, packet, file);
			plist_free(packet);
		} else if(!strcmp(command, "Payload")) {
			plist_free(packet);
			break;

		} else {
			error("ERROR: Unknown command received from ASR\n");
			plist_free(packet);
			return -1;
		}
	}

	return 0;
}
Example #23
0
 file_relay_error_t file_relay_request_sources_timeout(file_relay_client_t client, const char **sources, idevice_connection_t *connection, unsigned int timeout)
{
	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_set_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, timeout) != 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 if (!strcmp(errmsg, "PermissionDenied")) {
				debug_info("ERROR: Permission denied.");
				err = FILE_RELAY_E_PERMISSION_DENIED;
			} 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->parent->connection;

leave:
	if (dict) {
		plist_free(dict);
	}
	return err;
}
int main(int argc, char *argv[])
{
	heartbeat_client_t heartbeat = NULL;
	idevice_t device = NULL;
	idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
	int i;
	const char* udid = NULL;

	signal(SIGINT, clean_exit);
	signal(SIGTERM, clean_exit);
#ifndef WIN32
	signal(SIGQUIT, clean_exit);
	signal(SIGPIPE, SIG_IGN);
#endif
	/* 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);
				return 0;
			}
			udid = argv[i];
			continue;
		}
		else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
			print_usage(argc, argv);
			return 0;
		}
		else {
			print_usage(argc, argv);
			return 0;
		}
	}

	ret = idevice_new(&device, udid);
	if (ret != IDEVICE_E_SUCCESS) {
		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");
		}
		return -1;
	}

	/* start heartbeat service on device */
	heartbeat_client_start_service(device, &heartbeat, "ideviceheartbeat");
	if (heartbeat) {
		printf("< heartbeat started, listening...\n");
	} else {
		printf("Failed to start heartbeat service\n");
		idevice_free(device);
		return -1;
	}

	/* main loop */
	uint8_t b = 0;
	uint64_t interval = 10000;
	plist_t message = NULL;
	plist_t node = NULL;
	do {
		/* await a "ping" message from the device every interval seconds */
		heartbeat_receive_with_timeout(heartbeat, &message, (uint32_t)interval);
		if (message) {
			/* report device beat settings */
			node = plist_dict_get_item(message, "SupportsSleepyTime");
			if (node && plist_get_node_type(node) == PLIST_BOOLEAN) {
				plist_get_bool_val(node, &b);
			}
			node = plist_dict_get_item(message, "Interval");
			if (node && plist_get_node_type(node) == PLIST_UINT) {
				plist_get_uint_val(node, &interval);
			}

			printf("> marco: supports_sleepy_time %d, interval %llu\n", b, interval);

			plist_free(message);
			message = NULL;

			/* answer with a "pong" message */
			message = plist_new_dict();
			plist_dict_insert_item(message, "Command", plist_new_string("Polo"));
			heartbeat_send(heartbeat, message);

			printf("< polo\n");

			if (message) {
				plist_free(message);
				message = NULL;
			}
		}
	} while(!quit_flag);

	heartbeat_client_free(heartbeat);

	idevice_free(device);

	return 0;
}
Example #25
0
/**
 * Function used internally by lockdownd_start_service and lockdownd_start_service_with_escrow_bag.
 *
 * @param client The lockdownd client
 * @param identifier The identifier of the service to start
 * @param send_escrow_bag Should we send the device's escrow bag with the request
 * @param descriptor The service descriptor on success or NULL on failure
 
 * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG if a parameter
 *  is NULL, LOCKDOWN_E_INVALID_SERVICE if the requested service is not known
 *  by the device, LOCKDOWN_E_START_SERVICE_FAILED if the service could not because
 *  started by the device, LOCKDOWN_E_INVALID_CONF if the host id or escrow bag (when
 *  used) are missing from the device record.
 */
static lockdownd_error_t lockdownd_do_start_service(lockdownd_client_t client, const char *identifier, int send_escrow_bag, lockdownd_service_descriptor_t *service)
{
	if (!client || !identifier || !service)
		return LOCKDOWN_E_INVALID_ARG;
	
	if (*service) {
		// reset fields if service descriptor is reused
		(*service)->port = 0;
		(*service)->ssl_enabled = 0;
	}

	plist_t dict = NULL;
	uint16_t port_loc = 0;
	lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;

	/* Create StartService request */
	ret = lockdownd_build_start_service_request(client, identifier, send_escrow_bag, &dict);
	if (LOCKDOWN_E_SUCCESS != ret)
		return ret;

	/* send to device */
	ret = lockdownd_send(client, dict);
	plist_free(dict);
	dict = NULL;

	if (LOCKDOWN_E_SUCCESS != ret)
		return ret;

	ret = lockdownd_receive(client, &dict);

	if (LOCKDOWN_E_SUCCESS != ret)
		return ret;

	if (!dict)
		return LOCKDOWN_E_PLIST_ERROR;

	ret = LOCKDOWN_E_UNKNOWN_ERROR;
	if (lockdown_check_result(dict, "StartService") == RESULT_SUCCESS) {
		if (*service == NULL)
			*service = (lockdownd_service_descriptor_t)malloc(sizeof(struct lockdownd_service_descriptor));
		(*service)->port = 0;
		(*service)->ssl_enabled = 0;

		/* read service port number */
		plist_t node = plist_dict_get_item(dict, "Port");
		if (node && (plist_get_node_type(node) == PLIST_UINT)) {
			uint64_t port_value = 0;
			plist_get_uint_val(node, &port_value);

			if (port_value) {
				port_loc = port_value;
				ret = LOCKDOWN_E_SUCCESS;
			}
			if (port_loc && ret == LOCKDOWN_E_SUCCESS) {
				(*service)->port = port_loc;
			}
		}

		/* check if the service requires SSL */
		node = plist_dict_get_item(dict, "EnableServiceSSL");
		if (node && (plist_get_node_type(node) == PLIST_BOOLEAN)) {
			uint8_t b = 0;
			plist_get_bool_val(node, &b);
			(*service)->ssl_enabled = b;
		}
	} else {
		ret = LOCKDOWN_E_START_SERVICE_FAILED;
		plist_t error_node = plist_dict_get_item(dict, "Error");
		if (error_node && PLIST_STRING == plist_get_node_type(error_node)) {
			char *error = NULL;
			plist_get_string_val(error_node, &error);
			if (!strcmp(error, "InvalidService")) {
				ret = LOCKDOWN_E_INVALID_SERVICE;
			} else if (!strcmp(error, "NoRunningSession")) {
				ret = LOCKDOWN_E_NO_RUNNING_SESSION;
			}
			free(error);
		}
	}

	plist_free(dict);
	dict = NULL;
	return ret;
}
Example #26
0
/**
 * Creates a new restored client for the device.
 *
 * @param device The device to create a restored client for
 * @param client The pointer to the location of the new restored_client
 * @param label The label to use for communication. Usually the program name.
 *
 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL
 */
restored_error_t restored_client_new(idevice_t device, restored_client_t *client, const char *label)
{
	if (!client)
		return RESTORE_E_INVALID_ARG;

	restored_error_t ret = RESTORE_E_SUCCESS;

	static struct lockdownd_service_descriptor service = {
		.port = 0xf27e,
		.ssl_enabled = 0
	};

	property_list_service_client_t plistclient = NULL;
	if (property_list_service_client_new(device, (lockdownd_service_descriptor_t)&service, &plistclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
		debug_info("could not connect to restored (device %s)", device->udid);
		return RESTORE_E_MUX_ERROR;
	}

	restored_client_t client_loc = (restored_client_t) malloc(sizeof(struct restored_client_private));
	client_loc->parent = plistclient;
	client_loc->udid = NULL;
	client_loc->label = NULL;
	client_loc->info = NULL;
	if (label != NULL)
		client_loc->label = strdup(label);

	ret = idevice_get_udid(device, &client_loc->udid);
	if (RESTORE_E_SUCCESS != ret) {
		debug_info("failed to get device udid.");
	}
	debug_info("device udid: %s", client_loc->udid);

	if (RESTORE_E_SUCCESS == ret) {
		*client = client_loc;
	} else {
		restored_client_free(client_loc);
	}

	return ret;
}

/**
 * Sends the Goodbye request to restored signaling the end of communication.
 *
 * @param client The restore client
 *
 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL,
 *  RESTORE_E_PLIST_ERROR if the device did not acknowledge the request
 */
restored_error_t restored_goodbye(restored_client_t client)
{
	if (!client)
		return RESTORE_E_INVALID_ARG;

	restored_error_t ret = RESTORE_E_UNKNOWN_ERROR;

	plist_t dict = plist_new_dict();
	plist_dict_add_label(dict, client->label);
	plist_dict_insert_item(dict,"Request", plist_new_string("Goodbye"));

	debug_info("called");

	ret = restored_send(client, dict);
	plist_free(dict);
	dict = NULL;

	ret = restored_receive(client, &dict);
	if (!dict) {
		debug_info("did not get goodbye response back");
		return RESTORE_E_PLIST_ERROR;
	}

	if (restored_check_result(dict) == RESULT_SUCCESS) {
		debug_info("success");
		ret = RESTORE_E_SUCCESS;
	}
	plist_free(dict);
	dict = NULL;
	return ret;
}

/**
 * Requests to start a restore and retrieve it's port on success.
 *
 * @param client The restored client
 * @param options PLIST_DICT with options for the restore process or NULL
 * @param version the restore protocol version, see restored_query_type()
 *
 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG if a parameter
 *  is NULL, RESTORE_E_START_RESTORE_FAILED if the request fails
 */
restored_error_t restored_start_restore(restored_client_t client, plist_t options, uint64_t version)
{
	if (!client)
		return RESTORE_E_INVALID_ARG;

	plist_t dict = NULL;
	restored_error_t ret = RESTORE_E_UNKNOWN_ERROR;

	dict = plist_new_dict();
	plist_dict_add_label(dict, client->label);
	plist_dict_insert_item(dict,"Request", plist_new_string("StartRestore"));
	if (options) {
		plist_dict_insert_item(dict, "RestoreOptions", plist_copy(options));
	}
	plist_dict_insert_item(dict,"RestoreProtocolVersion", plist_new_uint(version));

	/* send to device */
	ret = restored_send(client, dict);
	plist_free(dict);
	dict = NULL;

	return ret;
}

/**
 * Requests device to reboot.
 *
 * @param client The restored client
 *
 * @return RESTORE_E_SUCCESS on success, NP_E_INVALID_ARG if a parameter
 *  is NULL
 */
restored_error_t restored_reboot(restored_client_t client)
{
	if (!client)
		return RESTORE_E_INVALID_ARG;

	plist_t dict = NULL;
	restored_error_t ret = RESTORE_E_UNKNOWN_ERROR;

	dict = plist_new_dict();
	plist_dict_add_label(dict, client->label);
	plist_dict_insert_item(dict,"Request", plist_new_string("Reboot"));

	/* send to device */
	ret = restored_send(client, dict);
	plist_free(dict);
	dict = NULL;

	if (RESTORE_E_SUCCESS != ret)
		return ret;

	ret = restored_receive(client, &dict);
	if (RESTORE_E_SUCCESS != ret)
		return ret;

	if (!dict)
		return RESTORE_E_PLIST_ERROR;

	plist_free(dict);
	dict = NULL;
	return ret;
}
Example #27
0
/**
 * Function used internally by lockdownd_pair() and lockdownd_validate_pair()
 *
 * @param client The lockdown client to pair with.
 * @param pair_record The pair record to use for pairing. If NULL is passed, then
 *    the pair records from the current machine are used. New records will be
 *    generated automatically when pairing is done for the first time.
 * @param verb This is either "Pair", "ValidatePair" or "Unpair".
 *
 * @return LOCKDOWN_E_SUCCESS on success, NP_E_INVALID_ARG when client is NULL,
 *  LOCKDOWN_E_PLIST_ERROR if the pair_record certificates are wrong,
 *  LOCKDOWN_E_PAIRING_FAILED if the pairing failed,
 *  LOCKDOWN_E_PASSWORD_PROTECTED if the device is password protected,
 *  LOCKDOWN_E_INVALID_HOST_ID if the device does not know the caller's host id
 */
static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record, const char *verb)
{
	if (!client)
		return LOCKDOWN_E_INVALID_ARG;

	lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
	plist_t dict = NULL;
	plist_t pair_record_plist = NULL;
	plist_t wifi_node = NULL;
	int pairing_mode = 0; /* 0 = libimobiledevice, 1 = external */

	if (pair_record && pair_record->system_buid && pair_record->host_id) {
		/* valid pair_record passed? */
		if (!pair_record->device_certificate || !pair_record->host_certificate || !pair_record->root_certificate) {
			return LOCKDOWN_E_PLIST_ERROR;
		}

		/* use passed pair_record */
		pair_record_plist = lockdownd_pair_record_to_plist(pair_record);

		pairing_mode = 1;
	} else {
		/* generate a new pair record if pairing */
		if (!strcmp("Pair", verb)) {
			ret = pair_record_generate(client, &pair_record_plist);

			if (ret != LOCKDOWN_E_SUCCESS) {
				if (pair_record_plist)
					plist_free(pair_record_plist);
				return ret;
			}

			/* get wifi mac now, if we get it later we fail on iOS 7 which causes a reconnect */
			lockdownd_get_value(client, NULL, "WiFiAddress", &wifi_node);
		} else {
			/* use existing pair record */
			if (userpref_has_pair_record(client->udid)) {
				userpref_read_pair_record(client->udid, &pair_record_plist);
				if (!pair_record_plist) {
					return LOCKDOWN_E_INVALID_CONF;
				}
			} else {
				return LOCKDOWN_E_INVALID_HOST_ID;
			}
		}
	}

	plist_t request_pair_record = plist_copy(pair_record_plist);

	/* remove stuff that is private */
	plist_dict_remove_item(request_pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY);
	plist_dict_remove_item(request_pair_record, USERPREF_HOST_PRIVATE_KEY_KEY);

	/* setup pair request plist */
	dict = plist_new_dict();
	plist_dict_add_label(dict, client->label);
	plist_dict_set_item(dict, "PairRecord", request_pair_record);
	plist_dict_set_item(dict, "Request", plist_new_string(verb));
	plist_dict_set_item(dict, "ProtocolVersion", plist_new_string(LOCKDOWN_PROTOCOL_VERSION));

	plist_t options = plist_new_dict();
	plist_dict_set_item(options, "ExtendedPairingErrors", plist_new_bool(1));
	plist_dict_set_item(dict, "PairingOptions", options);

	/* send to device */
	ret = lockdownd_send(client, dict);
	plist_free(dict);
	dict = NULL;

	if (ret != LOCKDOWN_E_SUCCESS) {
		plist_free(pair_record_plist);
		if (wifi_node)
			plist_free(wifi_node);
		return ret;
	}

	/* Now get device's answer */
	ret = lockdownd_receive(client, &dict);

	if (ret != LOCKDOWN_E_SUCCESS) {
		plist_free(pair_record_plist);
		if (wifi_node)
			plist_free(wifi_node);
		return ret;
	}

	if (strcmp(verb, "Unpair") == 0) {
		/* workaround for Unpair giving back ValidatePair,
		 * seems to be a bug in the device's fw */
		if (lockdown_check_result(dict, NULL) != RESULT_SUCCESS) {
			ret = LOCKDOWN_E_PAIRING_FAILED;
		}
	} else {
		if (lockdown_check_result(dict, verb) != RESULT_SUCCESS) {
			ret = LOCKDOWN_E_PAIRING_FAILED;
		}
	}

	/* if pairing succeeded */
	if (ret == LOCKDOWN_E_SUCCESS) {
		debug_info("%s success", verb);
		if (!pairing_mode) {
			debug_info("internal pairing mode");
			if (!strcmp("Unpair", verb)) {
				/* remove public key from config */
				userpref_delete_pair_record(client->udid);
			} else {
				if (!strcmp("Pair", verb)) {
					/* add returned escrow bag if available */
					plist_t extra_node = plist_dict_get_item(dict, USERPREF_ESCROW_BAG_KEY);
					if (extra_node && plist_get_node_type(extra_node) == PLIST_DATA) {
						debug_info("Saving EscrowBag from response in pair record");
						plist_dict_set_item(pair_record_plist, USERPREF_ESCROW_BAG_KEY, plist_copy(extra_node));
						plist_free(extra_node);
						extra_node = NULL;
					}

					/* save previously retrieved wifi mac address in pair record */
					if (wifi_node) {
						debug_info("Saving WiFiAddress from device in pair record");
						plist_dict_set_item(pair_record_plist, USERPREF_WIFI_MAC_ADDRESS_KEY, plist_copy(wifi_node));
						plist_free(wifi_node);
						wifi_node = NULL;
					}

					userpref_save_pair_record(client->udid, pair_record_plist);
				}
			}
		} else {
			debug_info("external pairing mode");
		}
	} else {
		debug_info("%s failure", verb);
		plist_t error_node = NULL;
		/* verify error condition */
		error_node = plist_dict_get_item(dict, "Error");
		if (error_node) {
			char *value = NULL;
			plist_get_string_val(error_node, &value);
			if (value) {
				/* the first pairing fails if the device is password protected */
				if (!strcmp(value, "PasswordProtected")) {
					ret = LOCKDOWN_E_PASSWORD_PROTECTED;
				} else if (!strcmp(value, "InvalidHostID")) {
					ret = LOCKDOWN_E_INVALID_HOST_ID;
				} else if (!strcmp(value, "UserDeniedPairing")) {
					ret = LOCKDOWN_E_USER_DENIED_PAIRING;
				} else if (!strcmp(value, "PairingDialogResponsePending")) {
					ret = LOCKDOWN_E_PAIRING_DIALOG_PENDING;
				}
				free(value);
			}

			plist_free(error_node);
			error_node = NULL;
		}
	}

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

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

	plist_free(dict);
	dict = NULL;

	return ret;
}
Example #28
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;
	}
	device_link_service_get_message(array, &msg);
	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;
	}
	device_link_service_get_message(array, &msg);
	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 #29
0
LIBIMOBILEDEVICE_API lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char *host_id, char **session_id, int *ssl_enabled)
{
	lockdownd_error_t ret = LOCKDOWN_E_SUCCESS;
	property_list_service_error_t plret;
	plist_t dict = NULL;

	if (!client || !host_id)
		ret = LOCKDOWN_E_INVALID_ARG;

	/* if we have a running session, stop current one first */
	if (client->session_id) {
		lockdownd_stop_session(client, client->session_id);
	}

	/* setup request plist */
	dict = plist_new_dict();
	plist_dict_add_label(dict, client->label);
	plist_dict_set_item(dict,"Request", plist_new_string("StartSession"));

	/* add host id */
	if (host_id) {
		plist_dict_set_item(dict, "HostID", plist_new_string(host_id));
	}

	/* add system buid */
	char *system_buid = NULL;
	userpref_read_system_buid(&system_buid);
	if (system_buid) {
		plist_dict_set_item(dict, "SystemBUID", plist_new_string(system_buid));
		if (system_buid) {
			free(system_buid);
			system_buid = NULL;
		}
	}

	ret = lockdownd_send(client, dict);
	plist_free(dict);
	dict = NULL;

	if (ret != LOCKDOWN_E_SUCCESS)
		return ret;

	ret = lockdownd_receive(client, &dict);

	if (!dict)
		return LOCKDOWN_E_PLIST_ERROR;

	ret = lockdown_check_result(dict, "StartSession");
	if (ret == LOCKDOWN_E_SUCCESS) {
		uint8_t use_ssl = 0;

		plist_t enable_ssl = plist_dict_get_item(dict, "EnableSessionSSL");
		if (enable_ssl && (plist_get_node_type(enable_ssl) == PLIST_BOOLEAN)) {
			plist_get_bool_val(enable_ssl, &use_ssl);
		}
		debug_info("Session startup OK");

		if (ssl_enabled != NULL)
			*ssl_enabled = use_ssl;

		/* store session id, we need it for StopSession */
		plist_t session_node = plist_dict_get_item(dict, "SessionID");
		if (session_node && (plist_get_node_type(session_node) == PLIST_STRING)) {
			plist_get_string_val(session_node, &client->session_id);
		}

		if (client->session_id) {
			debug_info("SessionID: %s", client->session_id);
			if (session_id != NULL)
				*session_id = strdup(client->session_id);
		} else {
			debug_info("Failed to get SessionID!");
		}

		debug_info("Enable SSL Session: %s", (use_ssl?"true":"false"));

		if (use_ssl) {
			plret = property_list_service_enable_ssl(client->parent);
			if (plret == PROPERTY_LIST_SERVICE_E_SUCCESS) {
				ret = LOCKDOWN_E_SUCCESS;
				client->ssl_enabled = 1;
			} else {
				ret = LOCKDOWN_E_SSL_ERROR;
				client->ssl_enabled = 0;
			}
		} else {
			client->ssl_enabled = 0;
			ret = LOCKDOWN_E_SUCCESS;
		}
	}

	plist_free(dict);
	dict = NULL;

	return ret;
}
Example #30
0
int main(int argc, char *argv[])
{
	int res = -1;
	idevice_t device = NULL;
	idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
	instproxy_client_t instproxy_client = NULL;
	debugserver_client_t debugserver_client = NULL;
	int i;
	int debug_level = 0;
	int cmd = CMD_NONE;
	const char* udid = NULL;
	const char* bundle_identifier = NULL;
	char* path = NULL;
	char* working_directory = NULL;
	char **newlist = NULL;
	char** environment = NULL;
	int environment_index = 0;
	int environment_count = 0;
	char* response = NULL;
	debugserver_command_t command = NULL;
	debugserver_error_t dres = DEBUGSERVER_E_UNKNOWN_ERROR;

	/* map signals */
	signal(SIGINT, on_signal);
	signal(SIGTERM, on_signal);
#ifndef WIN32
	signal(SIGQUIT, on_signal);
	signal(SIGPIPE, SIG_IGN);
#endif

	/* parse command line arguments */
	for (i = 1; i < argc; i++) {
		if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
			debug_level++;
			idevice_set_debug_level(debug_level);
			continue;
		} else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) {
			i++;
			if (!argv[i] || (strlen(argv[i]) != 40)) {
				print_usage(argc, argv);
				res = 0;
				goto cleanup;
			}
			udid = argv[i];
			continue;
		} else if (!strcmp(argv[i], "-e") || !strcmp(argv[i], "--env")) {
			i++;
			if (!argv[i] || (strlen(argv[i]) <= 1) || strchr(argv[i], '=') == NULL) {
				print_usage(argc, argv);
				res = 0;
				goto cleanup;
			}
			/* add environment variable */
			if (!newlist)
				newlist = malloc((environment_count + 1) * sizeof(char*));
			else
				newlist = realloc(environment, (environment_count + 1) * sizeof(char*));
			newlist[environment_count++] = strdup(argv[i]);
			environment = newlist;
			continue;
		} else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
			print_usage(argc, argv);
			res = 0;
			goto cleanup;
		} else if (!strcmp(argv[i], "run")) {
			cmd = CMD_RUN;

			i++;
			if (!argv[i]) {
				/* make sure at least the bundle identifier was provided */
				printf("Please supply the bundle identifier of the app to run.\n");
				print_usage(argc, argv);
				res = 0;
				goto cleanup;
			}
			/*  read bundle identifier */
			bundle_identifier = argv[i];
			break;
		} else {
			print_usage(argc, argv);
			res = 0;
			goto cleanup;
		}
	}

	if (environment) {
		newlist = realloc(environment, (environment_count + 1) * sizeof(char*));
		newlist[environment_count] = NULL;
		environment = newlist;
	}

	/* verify options */
	if (cmd == CMD_NONE) {
		print_usage(argc, argv);
		goto cleanup;
	}

	/* connect to the device */
	ret = idevice_new(&device, udid);
	if (ret != IDEVICE_E_SUCCESS) {
		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;
	}

	switch (cmd) {
		case CMD_RUN:
		default:
			/* get the path to the app and it's working directory */
			if (instproxy_client_start_service(device, &instproxy_client, "idevicerun") != INSTPROXY_E_SUCCESS) {
				fprintf(stderr, "Could not start installation proxy service.\n");
				goto cleanup;
			}
			plist_t container = NULL;
			instproxy_client_get_object_by_key_from_info_directionary_for_bundle_identifier(instproxy_client, bundle_identifier, "Container", &container);
			instproxy_client_get_path_for_bundle_identifier(instproxy_client, bundle_identifier, &path);
			instproxy_client_free(instproxy_client);
			instproxy_client = NULL;

			if (container) {
				if (plist_get_node_type(container) == PLIST_STRING) {
					plist_get_string_val(container, &working_directory);
					debug_info("working_directory: %s\n", working_directory);
					plist_free(container);
				} else {
						plist_free(container);
					fprintf(stderr, "Could not determine container path for bundle identifier %s.\n", bundle_identifier);
					goto cleanup;
				}
			}

			/* start and connect to debugserver */
			if (debugserver_client_start_service(device, &debugserver_client, "idevicerun") != DEBUGSERVER_E_SUCCESS) {
				fprintf(stderr,
					"Could not start com.apple.debugserver!\n"
					"Please make sure to mount the developer disk image first:\n"
					"  1) Get the iOS version from `ideviceinfo -k ProductVersion`.\n"
					"  2) Find the matching iPhoneOS DeveloperDiskImage.dmg files.\n"
					"  3) Run `ideviceimagemounter` with the above path.\n");
				goto cleanup;
			}

			/* enable logging for the session in debug mode */
			if (debug_level) {
				debug_info("Setting logging bitmask...");
				debugserver_command_new("QSetLogging:bitmask=LOG_ALL|LOG_RNB_REMOTE|LOG_RNB_PACKETS", 0, NULL, &command);
				dres = debugserver_client_send_command(debugserver_client, command, &response);
				debugserver_command_free(command);
				command = NULL;
				if (response) {
					if (strncmp(response, "OK", 2)) {
						debugserver_client_handle_response(debugserver_client, &response, 0);
						goto cleanup;
					}
					free(response);
					response = NULL;
				}
			}

			/* set maximum packet size */
			debug_info("Setting maximum packet size...");
			const char* packet_size[2] = {"1024", NULL};
			debugserver_command_new("QSetMaxPacketSize:", 1, packet_size, &command);
			dres = debugserver_client_send_command(debugserver_client, command, &response);
			debugserver_command_free(command);
			command = NULL;
			if (response) {
				if (strncmp(response, "OK", 2)) {
					debugserver_client_handle_response(debugserver_client, &response, 0);
					goto cleanup;
				}
				free(response);
				response = NULL;
			}

			/* set working directory */
			debug_info("Setting working directory...");
			const char* working_dir[2] = {working_directory, NULL};
			debugserver_command_new("QSetWorkingDir:", 1, working_dir, &command);
			dres = debugserver_client_send_command(debugserver_client, command, &response);
			debugserver_command_free(command);
			command = NULL;
			if (response) {
				if (strncmp(response, "OK", 2)) {
					debugserver_client_handle_response(debugserver_client, &response, 0);
					goto cleanup;
				}
				free(response);
				response = NULL;
			}

			/* set environment */
			if (environment) {
				debug_info("Setting environment...");
				for (environment_index = 0; environment_index < environment_count; environment_index++) {
					debug_info("setting environment variable: %s", environment[environment_index]);
					debugserver_client_set_environment_hex_encoded(debugserver_client, environment[environment_index], NULL);
				}
			}

			/* set arguments and run app */
			debug_info("Setting argv...");
			i++; /* i is the offset of the bundle identifier, thus skip it */
			int app_argc = (argc - i + 2);
			char **app_argv = (char**)malloc(sizeof(char*) * app_argc);
			app_argv[0] = path;
			debug_info("app_argv[%d] = %s", 0, app_argv[0]);
			app_argc = 1;
			while (i < argc && argv && argv[i]) {
				debug_info("app_argv[%d] = %s", app_argc, argv[i]);
				app_argv[app_argc++] = argv[i];
				i++;
			}
			app_argv[app_argc] = NULL;
			debugserver_client_set_argv(debugserver_client, app_argc, app_argv, NULL);
			free(app_argv);

			/* check if launch succeeded */
			debug_info("Checking if launch succeeded...");
			debugserver_command_new("qLaunchSuccess", 0, NULL, &command);
			dres = debugserver_client_send_command(debugserver_client, command, &response);
			debugserver_command_free(command);
			command = NULL;
			if (response) {
				if (strncmp(response, "OK", 2)) {
					debugserver_client_handle_response(debugserver_client, &response, 0);
					goto cleanup;
				}
				free(response);
				response = NULL;
			}

			/* set thread */
			debug_info("Setting thread...");
			debugserver_command_new("Hc0", 0, NULL, &command);
			dres = debugserver_client_send_command(debugserver_client, command, &response);
			debugserver_command_free(command);
			command = NULL;
			if (response) {
				if (strncmp(response, "OK", 2)) {
					debugserver_client_handle_response(debugserver_client, &response, 0);
					goto cleanup;
				}
				free(response);
				response = NULL;
			}

			/* continue running process */
			debug_info("Continue running process...");
			debugserver_command_new("c", 0, NULL, &command);
			dres = debugserver_client_send_command(debugserver_client, command, &response);
			debugserver_command_free(command);
			command = NULL;

			/* main loop which is parsing/handling packets during the run */
			debug_info("Entering run loop...");
			while (!quit_flag) {
				if (dres != DEBUGSERVER_E_SUCCESS) {
					debug_info("failed to receive response");
					break;
				}

				if (response) {
					debug_info("response: %s", response);
					dres = debugserver_client_handle_response(debugserver_client, &response, 1);
				}

				sleep(1);
			}

			/* kill process after we finished */
			debug_info("Killing process...");
			debugserver_command_new("k", 0, NULL, &command);
			dres = debugserver_client_send_command(debugserver_client, command, &response);
			debugserver_command_free(command);
			command = NULL;
			if (response) {
				if (strncmp(response, "OK", 2)) {
					debugserver_client_handle_response(debugserver_client, &response, 0);
					goto cleanup;
				}
				free(response);
				response = NULL;
			}

			res = (dres == DEBUGSERVER_E_SUCCESS) ? 0: -1;
		break;
	}

cleanup:
	/* cleanup the house */
	if (environment) {
		for (environment_index = 0; environment_index < environment_count; environment_index++) {
			free(environment[environment_index]);
		}
		free(environment);
	}

	if (path)
		free(path);

	if (response)
		free(response);

	if (debugserver_client)
		debugserver_client_free(debugserver_client);

	if (device)
		idevice_free(device);

	return res;
}