예제 #1
0
/**
 * Internal function used by lockdownd_do_start_service to create the
 * StartService request's plist.
 *
 * @param client The lockdownd client
 * @param identifier The identifier of the service to start
 * @param send_escrow_bag Should we send the device's escrow bag with the request
 * @param request The request's plist on success, NULL on failure
 *
 * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_CONF on failure
 * to read the escrow bag from the device's record (when used).
 */
static lockdownd_error_t lockdownd_build_start_service_request(lockdownd_client_t client, const char *identifier, int send_escrow_bag, plist_t *request)
{
	plist_t dict = plist_new_dict();

	/* create the basic request params */
	plist_dict_add_label(dict, client->label);
	plist_dict_set_item(dict, "Request", plist_new_string("StartService"));
	plist_dict_set_item(dict, "Service", plist_new_string(identifier));

	/* if needed - get the escrow bag for the device and send it with the request */
	if (send_escrow_bag) {
		/* get the pairing record */
		plist_t pair_record = NULL;
		userpref_read_pair_record(client->udid, &pair_record);
		if (!pair_record) {
			debug_info("ERROR: failed to read pair record for device: %s", client->udid);
			plist_free(dict);
			return LOCKDOWN_E_INVALID_CONF;
		}

		/* try to read the escrow bag from the record */
		plist_t escrow_bag = plist_dict_get_item(pair_record, USERPREF_ESCROW_BAG_KEY);
		if (!escrow_bag || (PLIST_DATA != plist_get_node_type(escrow_bag))) {
			debug_info("ERROR: Failed to retrieve the escrow bag from the device's record");
			plist_free(dict);
			plist_free(pair_record);
			return LOCKDOWN_E_INVALID_CONF;
		}

		debug_info("Adding escrow bag to StartService for %s", identifier);
		plist_dict_set_item(dict, USERPREF_ESCROW_BAG_KEY, plist_copy(escrow_bag));
		plist_free(pair_record);
	}

	*request = dict;
	return LOCKDOWN_E_SUCCESS;
}
예제 #2
0
파일: idevice.c 프로젝트: HSHtime/libiphone
 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);
	/* Set up OpenSSL */
	if (openssl_init_done == 0) {
		SSL_library_init();
		openssl_init_done = 1;
	}
	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());
	SSL_CTX *ssl_ctx = SSL_CTX_new(SSLv3_client_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", ssl_error_to_string(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));
	}
	/* required for proper multi-thread clean up to prevent leaks */
#ifdef HAVE_ERR_REMOVE_THREAD_STATE
	ERR_remove_thread_state(NULL);
#else
	ERR_remove_state(0);
#endif
#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;
}
예제 #3
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;
}
예제 #4
0
LIBIMOBILEDEVICE_API 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;
}

LIBIMOBILEDEVICE_API 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);
	if (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);

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

	return ret;
}
예제 #5
0
LIBIMOBILEDEVICE_API 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;
	plist_t pair_record = 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);
		}
	}
	free(type);

	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) {
		free(host_id);
		host_id = NULL;
		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 (LOCKDOWN_E_SUCCESS == ret) {
		*client = client_loc;
	} else {
		lockdownd_client_free(client_loc);
	}
	free(host_id);
	return ret;
}
예제 #6
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;
}