diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/iphone.c | 59 | ||||
| -rw-r--r-- | src/lockdown.c | 178 | ||||
| -rw-r--r-- | src/lockdown.h | 1 | ||||
| -rw-r--r-- | src/usbmux.c | 3 | ||||
| -rw-r--r-- | src/utils.c | 34 | 
5 files changed, 260 insertions, 15 deletions
| diff --git a/src/iphone.c b/src/iphone.c index 32d27f6..1f68180 100644 --- a/src/iphone.c +++ b/src/iphone.c @@ -28,6 +28,49 @@  #include <stdlib.h>  #include <string.h> +/** + * This function sets the configuration of the given device to 3 + * and claims the interface 1. If usb_set_configuration fails, it detaches + * the kernel driver that blocks the device, and retries configuration. + * + * @param phone which device to configure + */ +static void iphone_config_usb_device(iphone_device_t phone) +{ +	int ret; + +	log_debug_msg("setting configuration... "); +	ret = usb_set_configuration(phone->device, 3); +	if (ret != 0) { +		log_debug_msg("Hm, usb_set_configuration returned %d: %s, trying to fix:\n", ret, strerror(-ret)); +		log_debug_msg("-> detaching kernel driver... "); +		ret = +			usb_detach_kernel_driver_np(phone->device, +										phone->__device->config->interface->altsetting->bInterfaceNumber); +		if (ret != 0) { +			log_debug_msg("usb_detach_kernel_driver_np returned %d: %s\n", ret, strerror(-ret)); +		} else { +			log_debug_msg("done.\n"); +			log_debug_msg("setting configuration again... "); +			ret = usb_set_configuration(phone->device, 3); +			if (ret != 0) { +				log_debug_msg("Error: usb_set_configuration returned %d: %s\n", ret, strerror(-ret)); +			} else { +				log_debug_msg("done.\n"); +			} +		} +	} else { +		log_debug_msg("done.\n"); +	} + +	log_debug_msg("claiming interface... "); +	ret = usb_claim_interface(phone->device, 1); +	if (ret != 0) { +		log_debug_msg("Error: usb_claim_interface returned %d: %s\n", ret, strerror(-ret)); +	} else { +		log_debug_msg("done.\n"); +	} +}  /**   * Given a USB bus and device number, returns a device handle to the iPhone on @@ -73,8 +116,7 @@ static iphone_error_t iphone_get_specific_device(unsigned int bus_n, int dev_n,  				if (dev->devnum == dev_n) {  					phone->__device = dev;  					phone->device = usb_open(phone->__device); -					usb_set_configuration(phone->device, 3); -					usb_claim_interface(phone->device, 1); +					iphone_config_usb_device(phone);  					goto found;  				} @@ -115,9 +157,10 @@ static iphone_error_t iphone_get_specific_device(unsigned int bus_n, int dev_n,  		return IPHONE_E_SUCCESS;  	} else {  		// Bad header +		log_debug_msg("get_iPhone(): Received a bad header/invalid version number.\n"); +		log_debug_buffer((char *) version, sizeof(*version));  		iphone_free_device(phone);  		free(version); -		log_debug_msg("get_iPhone(): Received a bad header/invalid version number.");  		return IPHONE_E_BAD_HEADER;  	} @@ -173,13 +216,21 @@ iphone_error_t iphone_free_device(iphone_device_t device)  	if (!device)  		return IPHONE_E_INVALID_ARG;  	iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; +	int bytes; +	unsigned char buf[512]; + +	// read final package +	bytes = usb_bulk_read(device->device, BULKIN, (void *) &buf, 512, 1000); +	if (bytes > 0) { +		log_debug_msg("iphone_free_device: final read returned\n"); +		log_debug_buffer(buf, bytes); +	}  	if (device->buffer) {  		free(device->buffer);  	}  	if (device->device) {  		usb_release_interface(device->device, 1); -		usb_reset(device->device);  		usb_close(device->device);  		ret = IPHONE_E_SUCCESS;  	} diff --git a/src/lockdown.c b/src/lockdown.c index cf0d99e..ab168a3 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -92,6 +92,97 @@ iphone_lckd_client_t new_lockdownd_client(iphone_device_t phone)  	return control;  } +/** + * Closes the lockdownd communication session, by sending + * the StopSession Request to the device.  + * + * @param control The lockdown client + */ +static void iphone_lckd_stop_session(iphone_lckd_client_t control) +{ +	if (!control) +		return;					// IPHONE_E_INVALID_ARG; +	xmlDocPtr plist = new_plist(); +	xmlNode *dict, *key; +	char **dictionary; +	int bytes = 0, i = 0; +	iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; + +	log_debug_msg("lockdownd_stop_session() called\n"); +	dict = add_child_to_plist(plist, "dict", "\n", NULL, 0); +	key = add_key_str_dict_element(plist, dict, "Request", "StopSession", 1); +	key = add_key_str_dict_element(plist, dict, "SessionID", control->session_id, 1); + +	char *XML_content; +	uint32 length; + +	xmlDocDumpMemory(plist, (xmlChar **) & XML_content, &length); +	ret = iphone_lckd_send(control, XML_content, length, &bytes); + +	xmlFree(XML_content); +	xmlFreeDoc(plist); +	plist = NULL; +	ret = iphone_lckd_recv(control, &XML_content, &bytes); + +	plist = xmlReadMemory(XML_content, bytes, NULL, NULL, 0); +	if (!plist) { +		fprintf(stderr, "lockdownd_stop_session(): IPHONE_E_PLIST_ERROR\n"); +		return;					//IPHONE_E_PLIST_ERROR; +	} +	dict = xmlDocGetRootElement(plist); +	for (dict = dict->children; dict; dict = dict->next) { +		if (!xmlStrcmp(dict->name, "dict")) +			break; +	} +	if (!dict) { +		fprintf(stderr, "lockdownd_stop_session(): IPHONE_E_DICT_ERROR\n"); +		return;					//IPHONE_E_DICT_ERROR; +	} +	dictionary = read_dict_element_strings(dict); +	xmlFreeDoc(plist); +	free(XML_content); + +	for (i = 0; dictionary[i]; i += 2) { +		if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i + 1], "Success")) { +			log_debug_msg("lockdownd_stop_session(): success\n"); +			ret = IPHONE_E_SUCCESS; +			break; +		} +	} + +	free_dictionary(dictionary); +	return;						//ret; +} + +/** + * Shuts down the SSL session by first calling iphone_lckd_stop_session + * to cleanly close the lockdownd communication session, and then  + * performing a close notify, which is done by "gnutls_bye". + * + * @param client The lockdown client + */ +static void iphone_lckd_stop_SSL_session(iphone_lckd_client_t client) +{ +	if (!client) { +		log_debug_msg("lockdownd_stop_SSL_session(): invalid argument!\n"); +		return; +	} + +	if (client->in_SSL) { +		log_debug_msg("Stopping SSL Session\n"); +		iphone_lckd_stop_session(client); +		log_debug_msg("Sending SSL close notify\n"); +		gnutls_bye(*client->ssl_session, GNUTLS_SHUT_RDWR); +	} +	if (client->ssl_session) { +		gnutls_deinit(*client->ssl_session); +		free(client->ssl_session); +	} +	client->in_SSL = 0; +	client->gtls_buffer_hack_len = 0;	// dunno if required?! + +	return; +}  /** Closes the lockdownd client and does the necessary housekeeping.   * @@ -103,13 +194,17 @@ iphone_error_t iphone_lckd_free_client(iphone_lckd_client_t client)  		return IPHONE_E_INVALID_ARG;  	iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; +	iphone_lckd_stop_SSL_session(client); +  	if (client->connection) { +		lockdownd_close(client); + +		// IMO, read of final "sessionUpcall connection closed" packet +		//  should come here instead of in iphone_free_device +  		ret = iphone_mux_free_client(client->connection);  	} -	if (client->ssl_session) -		gnutls_deinit(*client->ssl_session); -	free(client->ssl_session);  	free(client);  	return ret;  } @@ -520,6 +615,66 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch  	return ret;  } +/** + * Performs the Goodbye Request to tell the device the communication + * session is now closed. + * + * @param control The lockdown client + */ +void lockdownd_close(iphone_lckd_client_t control) +{ +	if (!control) +		return;					// IPHONE_E_INVALID_ARG; +	xmlDocPtr plist = new_plist(); +	xmlNode *dict, *key; +	char **dictionary; +	int bytes = 0, i = 0; +	iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; + +	log_debug_msg("lockdownd_close() called\n"); +	dict = add_child_to_plist(plist, "dict", "\n", NULL, 0); +	key = add_key_str_dict_element(plist, dict, "Request", "Goodbye", 1); +	char *XML_content; +	uint32 length; + +	xmlDocDumpMemory(plist, (xmlChar **) & XML_content, &length); +	ret = iphone_lckd_send(control, XML_content, length, &bytes); + +	xmlFree(XML_content); +	xmlFreeDoc(plist); +	plist = NULL; +	ret = iphone_lckd_recv(control, &XML_content, &bytes); + +	plist = xmlReadMemory(XML_content, bytes, NULL, NULL, 0); +	if (!plist) { +		fprintf(stderr, "lockdownd_close(): IPHONE_E_PLIST_ERROR\n"); +		return;					//IPHONE_E_PLIST_ERROR; +	} +	dict = xmlDocGetRootElement(plist); +	for (dict = dict->children; dict; dict = dict->next) { +		if (!xmlStrcmp(dict->name, "dict")) +			break; +	} +	if (!dict) { +		fprintf(stderr, "lockdownd_close(): IPHONE_E_DICT_ERROR\n"); +		return;					//IPHONE_E_DICT_ERROR; +	} +	dictionary = read_dict_element_strings(dict); +	xmlFreeDoc(plist); +	free(XML_content); + +	for (i = 0; dictionary[i]; i += 2) { +		if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i + 1], "Success")) { +			log_debug_msg("lockdownd_close(): success\n"); +			ret = IPHONE_E_SUCCESS; +			break; +		} +	} + +	free_dictionary(dictionary); +	return;						//ret; +} +  /** Generates the device certificate from the public key as well as the host   *  and root certificates.   *  @@ -664,6 +819,8 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c  	iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;  	// end variables +	control->session_id[0] = '\0'; +  	key = add_key_str_dict_element(plist, dict, "HostID", HostID, 1);  	if (!key) {  		log_debug_msg("Couldn't add a key.\n"); @@ -699,6 +856,7 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c  		dictionary = read_dict_element_strings(dict);  		xmlFreeDoc(plist);  		free(what2send); +		ret = IPHONE_E_SSL_ERROR;  		for (i = 0; dictionary[i]; i += 2) {  			if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i + 1], "Success")) {  				// Set up GnuTLS... @@ -741,8 +899,6 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c  				return_me = gnutls_handshake(*control->ssl_session);  				log_debug_msg("GnuTLS handshake done...\n"); -				free_dictionary(dictionary); -  				if (return_me != GNUTLS_E_SUCCESS) {  					log_debug_msg("GnuTLS reported something wrong.\n");  					gnutls_perror(return_me); @@ -750,10 +906,20 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c  					return IPHONE_E_SSL_ERROR;  				} else {  					control->in_SSL = 1; -					return IPHONE_E_SUCCESS; +					ret = IPHONE_E_SUCCESS;  				} +			} else if (!strcmp(dictionary[i], "SessionID")) { +				// we need to store the session ID for StopSession +				strcpy(control->session_id, dictionary[i + 1]); +				log_debug_msg("SessionID: %s\n", control->session_id); +				free_dictionary(dictionary); +				return ret;  			}  		} +		if (ret == IPHONE_E_SUCCESS) { +			log_debug_msg("Failed to get SessionID!\n"); +			return ret; +		}  		log_debug_msg("Apparently failed negotiating with lockdownd.\n");  		log_debug_msg("Responding dictionary: \n"); diff --git a/src/lockdown.h b/src/lockdown.h index 79ca37e..8b4f27c 100644 --- a/src/lockdown.h +++ b/src/lockdown.h @@ -38,6 +38,7 @@ struct iphone_lckd_client_int {  	int in_SSL;  	char *gtls_buffer_hack;  	int gtls_buffer_hack_len; +	char session_id[40];  };  char *lockdownd_generate_hostid(void); diff --git a/src/usbmux.c b/src/usbmux.c index 770d0db..c7ac7ef 100644 --- a/src/usbmux.c +++ b/src/usbmux.c @@ -182,8 +182,11 @@ iphone_error_t iphone_mux_free_client(iphone_umux_client_t client)  		return IPHONE_E_INVALID_ARG;  	client->header->tcp_flags = 0x04; +	client->header->length = htonl(0x1C);  	client->header->scnt = htonl(client->header->scnt);  	client->header->ocnt = htonl(client->header->ocnt); +	client->header->window = 0; +	client->header->length16 = htons(0x1C);  	int bytes = 0;  	bytes = usb_bulk_write(client->phone->device, BULKOUT, (char *) client->header, sizeof(usbmux_tcp_header), 800); diff --git a/src/utils.c b/src/utils.c index 049777a..fb98471 100644 --- a/src/utils.c +++ b/src/utils.c @@ -46,7 +46,7 @@ void log_debug_msg(const char *format, ...)  	va_start(args, format);  	if (toto_debug) -		fprintf(stderr, format, args); +		vfprintf(stderr, format, args);  	va_end(args); @@ -56,11 +56,35 @@ void log_debug_msg(const char *format, ...)  inline void log_debug_buffer(const char *data, const int length)  {  #ifndef STRIP_DEBUG_CODE +	int i; +	int j; +	unsigned char c; -	/* run the real fprintf */ -	if (toto_debug) -		fwrite(data, 1, length, stderr); - +	if (toto_debug) { +		for (i = 0; i < length; i += 16) { +			fprintf(stderr, "%04x: ", i); +			for (j = 0; j < 16; j++) { +				if (i + j >= length) { +					fprintf(stderr, "   "); +					continue; +				} +				fprintf(stderr, "%02hhx ", *(data + i + j)); +			} +			fprintf(stderr, "  | "); +			for (j = 0; j < 16; j++) { +				if (i + j >= length) +					break; +				c = *(data + i + j); +				if ((c < 32) || (c > 127)) { +					fprintf(stderr, "."); +					continue; +				} +				fprintf(stderr, "%c", c); +			} +			fprintf(stderr, "\n"); +		} +		fprintf(stderr, "\n"); +	}  #endif  } | 
