From 92c2879d16148f47ff38f3490f24768bb8eb61f6 Mon Sep 17 00:00:00 2001
From: Joshua Hill
Date: Mon, 24 May 2010 15:35:08 -0400
Subject: Have it sending DeviceTree now and started on ramdisk. Started to
 clean up a little bit, but not everything yet.

---
 src/idevicerestore.c | 469 +++++++++++++++++++++++++++++++++++++++++----------
 src/ipsw.c           |  11 +-
 src/ipsw.h           |   8 +-
 src/tss.c            |   8 +-
 4 files changed, 401 insertions(+), 95 deletions(-)

diff --git a/src/idevicerestore.c b/src/idevicerestore.c
index 1c8b24a..ec449d9 100644
--- a/src/idevicerestore.c
+++ b/src/idevicerestore.c
@@ -41,6 +41,11 @@ int idevicerestore_debug = 0;
 
 void usage(int argc, char* argv[]);
 int write_file(const char* filename, char* data, int size);
+int send_ibec(char* ipsw, plist_t tss);
+int send_devicetree(char* ipsw, plist_t tss);
+int send_ramdisk(char* ipsw, plist_t tss);
+int send_kernelcache(char* ipsw, plist_t tss);
+int get_tss_data(plist_t tss, const char* entry, char** path, char** blob);
 
 int main(int argc, char* argv[]) {
 	int opt = 0;
@@ -76,7 +81,7 @@ int main(int argc, char* argv[]) {
 		}
 	}
 
-	if(ipsw == NULL) {
+	if (ipsw == NULL) {
 		error("ERROR: Please supply an IPSW\n");
 		return -1;
 	}
@@ -90,10 +95,10 @@ int main(int argc, char* argv[]) {
 
 	info("Checking for device in normal mode...\n");
 	device_error = idevice_new(&device, uuid);
-	if(device_error != IDEVICE_E_SUCCESS) {
+	if (device_error != IDEVICE_E_SUCCESS) {
 		info("Checking for the device in recovery mode...\n");
-		recovery_error = irecv_open(&recovery, uuid);
-		if(recovery_error != IRECV_E_SUCCESS) {
+		recovery_error = irecv_open(&recovery);
+		if (recovery_error != IRECV_E_SUCCESS) {
 			error("ERROR: Unable to find device, is it plugged in?\n");
 			return -1;
 		}
@@ -105,9 +110,9 @@ int main(int argc, char* argv[]) {
 		mode = NORMAL_MODE;
 	}
 
-	if(mode == NORMAL_MODE) {
+	if (mode == NORMAL_MODE) {
 		lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore");
-		if(lockdown_error != LOCKDOWN_E_SUCCESS) {
+		if (lockdown_error != LOCKDOWN_E_SUCCESS) {
 			error("ERROR: Unable to connect to lockdownd\n");
 			idevice_free(device);
 			return -1;
@@ -115,14 +120,14 @@ int main(int argc, char* argv[]) {
 
 		plist_t unique_chip_node = NULL;
 		lockdown_error = lockdownd_get_value(lockdown, NULL, "UniqueChipID", &unique_chip_node);
-		if(lockdown_error != LOCKDOWN_E_SUCCESS) {
+		if (lockdown_error != LOCKDOWN_E_SUCCESS) {
 			error("ERROR: Unable to get UniqueChipID from lockdownd\n");
 			lockdownd_client_free(lockdown);
 			idevice_free(device);
 			return -1;
 		}
 
-		if(!unique_chip_node || plist_get_node_type(unique_chip_node) != PLIST_UINT) {
+		if (!unique_chip_node || plist_get_node_type(unique_chip_node) != PLIST_UINT) {
 			error("ERROR: Unable to get ECID\n");
 			lockdownd_client_free(lockdown);
 			idevice_free(device);
@@ -134,10 +139,9 @@ int main(int argc, char* argv[]) {
 		idevice_free(device);
 		lockdown = NULL;
 		device = NULL;
-	}
-	else if(mode == RECOVERY_MODE) {
+	} else if (mode == RECOVERY_MODE) {
 		recovery_error = irecv_get_ecid(recovery, &ecid);
-		if(recovery_error != IRECV_E_SUCCESS) {
+		if (recovery_error != IRECV_E_SUCCESS) {
 			error("ERROR: Unable to get device ECID\n");
 			irecv_close(recovery);
 			return -1;
@@ -146,7 +150,7 @@ int main(int argc, char* argv[]) {
 		recovery = NULL;
 	}
 
-	if(ecid != 0) {
+	if (ecid != 0) {
 		info("Found ECID %llu\n", ecid);
 	} else {
 		error("Unable to find device ECID\n");
@@ -154,27 +158,19 @@ int main(int argc, char* argv[]) {
 	}
 
 	info("Extracting BuildManifest.plist from IPSW\n");
-	ipsw_archive* archive = ipsw_open(ipsw);
-	if(archive == NULL) {
-		error("ERROR: Unable to open IPSW\n");
-		return -1;
-	}
-
-	ipsw_file* buildmanifest = ipsw_extract_file(archive, "BuildManifest.plist");
-	if(buildmanifest == NULL) {
+	ipsw_file* buildmanifest = ipsw_extract_file(ipsw, "BuildManifest.plist");
+	if (buildmanifest == NULL) {
 		error("ERROR: Unable to extract BuildManifest.plist IPSW\n");
-		ipsw_close(archive);
 		return -1;
 	}
 
 	plist_t manifest = NULL;
 	plist_from_xml(buildmanifest->data, buildmanifest->size, &manifest);
 	ipsw_free_file(buildmanifest);
-	ipsw_close(archive);
 
 	info("Creating TSS request\n");
 	plist_t tss_request = tss_create_request(manifest, ecid);
-	if(tss_request == NULL) {
+	if (tss_request == NULL) {
 		error("ERROR: Unable to create TSS request\n");
 		plist_free(manifest);
 		return -1;
@@ -183,7 +179,7 @@ int main(int argc, char* argv[]) {
 
 	info("Sending TSS request\n");
 	plist_t tss_response = tss_send_request(tss_request);
-	if(tss_response == NULL) {
+	if (tss_response == NULL) {
 		error("ERROR: Unable to get response from TSS server\n");
 		plist_free(tss_request);
 		return -1;
@@ -191,18 +187,18 @@ int main(int argc, char* argv[]) {
 	plist_free(tss_request);
 	info("Got TSS response\n");
 
-	if(mode == NORMAL_MODE) {
+	if (mode == NORMAL_MODE) {
 		// Place the device in recovery mode
 		info("Entering recovery mode...\n");
 		device_error = idevice_new(&device, uuid);
-		if(device_error != IDEVICE_E_SUCCESS) {
+		if (device_error != IDEVICE_E_SUCCESS) {
 			error("ERROR: Unable to find device\n");
 			plist_free(tss_response);
 			return -1;
 		}
 
 		lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore");
-		if(lockdown_error != LOCKDOWN_E_SUCCESS) {
+		if (lockdown_error != LOCKDOWN_E_SUCCESS) {
 			error("ERROR: Unable to connect to lockdownd service\n");
 			plist_free(tss_response);
 			idevice_free(device);
@@ -210,7 +206,7 @@ int main(int argc, char* argv[]) {
 		}
 
 		lockdown_error = lockdownd_enter_recovery(lockdown);
-		if(lockdown_error != LOCKDOWN_E_SUCCESS) {
+		if (lockdown_error != LOCKDOWN_E_SUCCESS) {
 			error("ERROR: Unable to place device in recovery mode\n");
 			lockdownd_client_free(lockdown);
 			plist_free(tss_response);
@@ -224,117 +220,212 @@ int main(int argc, char* argv[]) {
 		device = NULL;
 	}
 
-	recovery_error = irecv_open(&recovery, uuid);
-	while(recovery_error != IRECV_E_SUCCESS) {
+	if (send_ibec(ipsw, tss_response) < 0) {
+		error("ERROR: Unable to send iBEC\n");
+		return -1;
+	}
+
+	// Reconnect to iBEC
+	info("Connecting to iBEC\n");
+	recovery_error = irecv_open(&recovery);
+	while (recovery_error != IRECV_E_SUCCESS) {
 		sleep(1);
 		info("Retrying connection...\n");
-		recovery_error = irecv_open(&recovery, uuid);
-		if(recovery_error == IRECV_E_SUCCESS) {
-			mode = RECOVERY_MODE;
+		recovery_error = irecv_open(&recovery);
+		if (recovery_error == IRECV_E_SUCCESS) {
 			break;
 		}
 	}
 
-	info("Extracting iBEC from IPSW\n");
-	archive = ipsw_open(ipsw);
-	if(archive == NULL) {
-		error("ERROR: Unable to open IPSW\n");
+	// Sending DeviceTree
+	info("Extracting DeviceTree from IPSW\n");
+	plist_t devicetree_entry = plist_dict_get_item(tss_response, "RestoreDeviceTree");
+	if (!devicetree_entry || plist_get_node_type(devicetree_entry) != PLIST_DICT) {
+		error("ERROR: Unable to find DeviceTree entry in TSS response\n");
 		plist_free(tss_response);
 		irecv_close(recovery);
 		return -1;
 	}
 
-	plist_t ibec_entry = plist_dict_get_item(tss_response, "iBEC");
-	if(!ibec_entry || plist_get_node_type(ibec_entry) != PLIST_DICT) {
-		error("ERROR: Unable to find iBEC entry in TSS response\n");
+	char* devicetree_path = NULL;
+	plist_t devicetree_path_node = plist_dict_get_item(devicetree_entry, "Path");
+	if (!devicetree_path_node || plist_get_node_type(devicetree_path_node) != PLIST_STRING) {
+		error("ERROR: Unable to find DeviceTree path in entry\n");
 		plist_free(tss_response);
+		plist_free(devicetree_entry);
 		irecv_close(recovery);
-		ipsw_close(archive);
+		recovery = NULL;
 		return -1;
 	}
+	plist_get_string_val(devicetree_path_node, &devicetree_path);
 
-	char* ibec_path = NULL;
-	plist_t ibec_path_node = plist_dict_get_item(ibec_entry, "Path");
-	if(!ibec_path_node || plist_get_node_type(ibec_path_node) != PLIST_STRING) {
-		error("ERROR: Unable to find iBEC path in entry\n");
+	char* devicetree_blob = NULL;
+	uint64_t devicetree_blob_size = 0;
+	plist_t devicetree_blob_node = plist_dict_get_item(devicetree_entry, "Blob");
+	if (!devicetree_blob_node || plist_get_node_type(devicetree_blob_node) != PLIST_DATA) {
+		error("ERROR: Unable to find DeviceTree blob in entry\n");
 		plist_free(tss_response);
-		plist_free(ibec_entry);
+		plist_free(devicetree_entry);
 		irecv_close(recovery);
-		ipsw_close(archive);
 		recovery = NULL;
 		return -1;
 	}
-	plist_get_string_val(ibec_path_node, &ibec_path);
+	plist_get_data_val(devicetree_blob_node, &devicetree_blob, &devicetree_blob_size);
+	plist_free(devicetree_blob_node);
+	plist_free(devicetree_entry);
 
-	char* ibec_blob = NULL;
-	uint64_t ibec_blob_size = 0;
-	plist_t ibec_blob_node = plist_dict_get_item(ibec_entry, "Blob");
-	if(!ibec_blob_node || plist_get_node_type(ibec_blob_node) != PLIST_DATA) {
-		error("ERROR: Unable to find iBEC blob in entry\n");
-		plist_free(tss_response);
-		plist_free(ibec_entry);
+	ipsw_file* devicetree = ipsw_extract_file(ipsw, devicetree_path);
+	if (devicetree == NULL) {
+		error("ERROR: Unable to extract %s from IPSW\n", devicetree_path);
 		irecv_close(recovery);
-		ipsw_close(archive);
 		recovery = NULL;
 		return -1;
 	}
-	plist_get_data_val(ibec_blob_node, &ibec_blob, &ibec_blob_size);
-	plist_free(ibec_blob_node);
-	plist_free(ibec_entry);
 
-	ipsw_file* ibec = ipsw_extract_file(archive, ibec_path);
-	if(ibec == NULL) {
-		error("ERROR: Unable to extract %s from IPSW\n", ibec_path);
+	img3_file* devicetree_img3 = img3_parse_file(devicetree->data, devicetree->size);
+	if (devicetree_img3 == NULL) {
+		error("ERROR: Unable to parse IMG3: %s\n", devicetree_path);
+		irecv_close(recovery);
+		ipsw_free_file(devicetree);
+		recovery = NULL;
+		return -1;
+	}
+	ipsw_free_file(devicetree);
+
+	img3_replace_signature(devicetree_img3, devicetree_blob);
+	free(devicetree_blob);
+
+	int devicetree_size = 0;
+	char* devicetree_data = NULL;
+	img3_get_data(devicetree_img3, &devicetree_data, &devicetree_size);
+	write_file("devicetree.img3", devicetree_data, devicetree_size);
+	recovery_error = irecv_send_buffer(recovery, devicetree_data, devicetree_size);
+	if (recovery_error != IRECV_E_SUCCESS) {
+		error("ERROR: Unable to send IMG3: %s\n", devicetree_path);
 		irecv_close(recovery);
-		ipsw_close(archive);
+		img3_free(devicetree_img3);
 		recovery = NULL;
 		return -1;
 	}
-	ipsw_close(archive);
+	img3_free(devicetree_img3);
 
-	img3_file* ibec_img3 = img3_parse_file(ibec->data, ibec->size);
-	if(ibec_img3 == NULL) {
-		error("ERROR: Unable to parse IMG3: %s\n", ibec_path);
+	recovery_error = irecv_send_command(recovery, "devicetree");
+	if (recovery_error != IRECV_E_SUCCESS) {
+		error("ERROR: Unable to execute DeviceTree\n");
 		irecv_close(recovery);
-		ipsw_free_file(ibec);
+		img3_free(devicetree_img3);
 		recovery = NULL;
 		return -1;
 	}
-	ipsw_free_file(ibec);
+	free(devicetree_data);
+	sleep(1);
+
+	// Sending RestoreRamdisk
+	info("Extracting Ramdisk from IPSW\n");
+	plist_t ramdisk_entry = plist_dict_get_item(tss_response, "RestoreRamDisk");
+	if (!ramdisk_entry || plist_get_node_type(ramdisk_entry) != PLIST_DICT) {
+		error("ERROR: Unable to find RestoreRamDisk entry in TSS response\n");
+		plist_free(tss_response);
+		irecv_close(recovery);
+		return -1;
+	}
 
-	img3_replace_signature(ibec_img3, ibec_blob);
+	char* ramdisk_path = NULL;
+	plist_t ramdisk_path_node = plist_dict_get_item(ramdisk_entry, "Path");
+	if (!ramdisk_path_node || plist_get_node_type(ramdisk_path_node) != PLIST_STRING) {
+		error("ERROR: Unable to find RestoreRamDisk path in entry\n");
+		plist_free(tss_response);
+		plist_free(ramdisk_entry);
+		irecv_close(recovery);
+		recovery = NULL;
+		return -1;
+	}
+	plist_get_string_val(ramdisk_path_node, &ramdisk_path);
 
-	int ibec_size = 0;
-	char* ibec_data = NULL;
-	img3_get_data(ibec_img3, &ibec_data, &ibec_size);
-	write_file("ibec.dfu", ibec_data, ibec_size);
-	recovery_error = irecv_send_buffer(recovery, ibec_data, ibec_size);
-	if(recovery_error != IRECV_E_SUCCESS) {
-		error("ERROR: Unable to send IMG3: %s\n", ibec_path);
+	char* ramdisk_blob = NULL;
+	uint64_t ramdisk_blob_size = 0;
+	plist_t ramdisk_blob_node = plist_dict_get_item(ramdisk_entry, "Blob");
+	if (!ramdisk_blob_node || plist_get_node_type(ramdisk_blob_node) != PLIST_DATA) {
+		error("ERROR: Unable to find RestoreRamdisk blob in entry\n");
+		plist_free(tss_response);
+		plist_free(ramdisk_entry);
 		irecv_close(recovery);
-		img3_free(ibec_img3);
 		recovery = NULL;
 		return -1;
 	}
+	plist_get_data_val(ramdisk_blob_node, &ramdisk_blob, &ramdisk_blob_size);
+	plist_free(ramdisk_blob_node);
+	plist_free(ramdisk_entry);
 
-	recovery_error = irecv_send_command(recovery, "go");
-	if(recovery_error != IRECV_E_SUCCESS) {
-		error("ERROR: Unable to execute iBEC\n");
+	ipsw_file* ramdisk = ipsw_extract_file(ipsw, ramdisk_path);
+	if (ramdisk == NULL) {
+		error("ERROR: Unable to extract %s from IPSW\n", ramdisk_path);
 		irecv_close(recovery);
-		img3_free(ibec_img3);
 		recovery = NULL;
 		return -1;
 	}
 
-	free(ibec_data);
+	img3_file* ramdisk_img3 = img3_parse_file(ramdisk->data, ramdisk->size);
+	if (ramdisk_img3 == NULL) {
+		error("ERROR: Unable to parse IMG3: %s\n", ramdisk_path);
+		irecv_close(recovery);
+		ipsw_free_file(ramdisk);
+		recovery = NULL;
+		return -1;
+	}
+	ipsw_free_file(ramdisk);
+
+	img3_replace_signature(ramdisk_img3, ramdisk_blob);
+	free(ramdisk_blob);
+
+	int ramdisk_size = 0;
+	char* ramdisk_data = NULL;
+	img3_get_data(ramdisk_img3, &ramdisk_data, &ramdisk_size);
+	write_file("ramdisk.dmg", ramdisk_data, ramdisk_size);
+	recovery_error = irecv_send_buffer(recovery, ramdisk_data, ramdisk_size);
+	if (recovery_error != IRECV_E_SUCCESS) {
+		error("ERROR: Unable to send IMG3: %s\n", ramdisk_path);
+		irecv_close(recovery);
+		img3_free(ramdisk_img3);
+		recovery = NULL;
+		return -1;
+	}
+	img3_free(ramdisk_img3);
+
+	recovery_error = irecv_send_command(recovery, "ramdisk");
+	if (recovery_error != IRECV_E_SUCCESS) {
+		error("ERROR: Unable to execute DeviceTree\n");
+		irecv_close(recovery);
+		recovery = NULL;
+		return -1;
+	}
+	free(ramdisk_data);
+	irecv_close(recovery);
+	recovery = NULL;
+
+	printf("Please unplug your device, then plug it back in, hit any key to continue\n");
+	getchar();
+
+	// Reconnect to iBEC
+	recovery_error = irecv_open(&recovery);
+	while (recovery_error != IRECV_E_SUCCESS) {
+		sleep(1);
+		info("Retrying connection...\n");
+		recovery_error = irecv_open(&recovery);
+		if (recovery_error == IRECV_E_SUCCESS) {
+			break;
+		}
+	}
+
 	irecv_close(recovery);
+	recovery = NULL;
 	plist_free(tss_response);
 	return 0;
 }
 
 void usage(int argc, char* argv[]) {
 	char *name = strrchr(argv[0], '/');
-	printf("Usage: %s [OPTIONS]\n", (name ? name + 1: argv[0]));
+	printf("Usage: %s [OPTIONS]\n", (name ? name + 1 : argv[0]));
 	printf("Restore firmware and filesystem to iPhone/iPod Touch.\n");
 	printf("  -d, \t\tenable communication debugging\n");
 	printf("  -v, \t\tenable incremental levels of verboseness\n");
@@ -357,10 +448,218 @@ int write_file(const char* filename, char* data, int size) {
 	int bytes = fwrite(data, 1, size, file);
 	fclose(file);
 
-	if(bytes != size) {
+	if (bytes != size) {
 		error("ERROR: Unable to write entire file: %s: %d %d\n", filename, bytes, size);
 		return -1;
 	}
 
 	return size;
 }
+
+int get_tss_data(plist_t tss, const char* entry, char** ppath, char** pblob) {
+	*ppath = NULL;
+	*pblob = NULL;
+
+	plist_t node = plist_dict_get_item(tss, entry);
+	if (!node || plist_get_node_type(node) != PLIST_DICT) {
+		error("ERROR: Unable to find %s entry in TSS response\n", entry);
+		return -1;
+	}
+
+	char* path = NULL;
+	plist_t path_node = plist_dict_get_item(node, "Path");
+	if (!path_node || plist_get_node_type(path_node) != PLIST_STRING) {
+		error("ERROR: Unable to find %s path in entry\n", entry);
+		plist_free(node);
+		return -1;
+	}
+	plist_get_string_val(path_node, &path);
+	plist_free(path_node);
+
+	char* blob = NULL;
+	uint64_t blob_size = 0;
+	plist_t blob_node = plist_dict_get_item(node, "Blob");
+	if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) {
+		error("ERROR: Unable to find %s blob in entry\n", entry);
+		plist_free(node);
+		free(path);
+		return -1;
+	}
+
+	plist_get_data_val(blob_node, &blob, &blob_size);
+	plist_free(blob_node);
+	plist_free(node);
+
+	*ppath = path;
+	*pblob = blob;
+	return 0;
+}
+
+int send_ibec(char* ipsw, plist_t tss) {
+	int i = 0;
+	irecv_client_t client = NULL;
+	info("Connecting to iBoot...\n");
+	irecv_error_t error = irecv_open(&client);
+	for (i = 10; i > 0; i--) {
+		if (error == IRECV_E_SUCCESS) {
+			irecv_send_command(client, "setenv auto-boot true");
+			irecv_send_command(client, "saveenv");
+			break;
+		}
+		sleep(1);
+		info("Retrying connection...\n");
+		error = irecv_open(&client);
+	}
+
+	char* path = NULL;
+	char* blob = NULL;
+	info("Extracting iBEC data from TSS response\n");
+	if (get_tss_data(tss, "iBEC", &path, &blob) < 0) {
+		error("ERROR: Unable to get data for TSS entry\n");
+		irecv_close(client);
+		client = NULL;
+		return -1;
+	}
+
+	info("Extracting %s from %s\n", path, ipsw);
+	ipsw_file* ibec = ipsw_extract_file(ipsw, path);
+	if (ibec == NULL) {
+		error("ERROR: Unable to extract %s from %s\n", path, ipsw);
+		irecv_close(client);
+		client = NULL;
+		free(path);
+		free(blob);
+		return -1;
+	}
+
+	img3_file* img3 = img3_parse_file(ibec->data, ibec->size);
+	if (img3 == NULL) {
+		error("ERROR: Unable to parse IMG3: %s\n", path);
+		ipsw_free_file(ibec);
+		irecv_close(client);
+		client = NULL;
+		free(path);
+		free(blob);
+		return -1;
+	}
+	if (ibec) {
+		ipsw_free_file(ibec);
+		ibec = NULL;
+	}
+
+	if (img3_replace_signature(img3, blob) < 0) {
+		error("ERROR: Unable to replace IMG3 signature\n");
+		irecv_close(client);
+		client = NULL;
+		free(path);
+		free(blob);
+		return -1;
+	}
+	if (blob) {
+		free(blob);
+		blob = NULL;
+	}
+
+	int size = 0;
+	char* data = NULL;
+	if (img3_get_data(img3, &data, &size) < 0) {
+		error("ERROR: Unable to reconstruct IMG3\n");
+		irecv_close(client);
+		img3_free(img3);
+		client = NULL;
+		free(path);
+		return -1;
+	}
+
+	path = strrchr(path, '/');
+	write_file(path + 1, data, size);
+	error = irecv_send_buffer(client, data, size);
+	if (error != IRECV_E_SUCCESS) {
+		error("ERROR: Unable to send IMG3: %s\n", path);
+		irecv_close(client);
+		img3_free(img3);
+		client = NULL;
+		free(data);
+		free(path);
+		return -1;
+	}
+	if (img3) {
+		img3_free(img3);
+		img3 = NULL;
+	}
+	if (data) {
+		free(data);
+		data = NULL;
+	}
+	if (path) {
+		free(path);
+		path = NULL;
+	}
+
+	error = irecv_send_command(client, "go");
+	if (error != IRECV_E_SUCCESS) {
+		error("ERROR: Unable to execute iBEC\n");
+		irecv_close(client);
+		client = NULL;
+		free(data);
+		return -1;
+	}
+
+	irecv_close(client);
+	client = NULL;
+	return 0;
+}
+
+int send_devicetree(char* ipsw, plist_t tss) {
+	int i = 0;
+	info("Sending devicetree\n");
+	irecv_client_t client = NULL;
+	irecv_error_t error = irecv_open(&client);
+	for (i = 10; i > 0; i--) {
+		if (error == IRECV_E_SUCCESS) {
+			break;
+		}
+		sleep(1);
+		info("Retrying connection...\n");
+		error = irecv_open(&client);
+	}
+
+	irecv_close(client);
+	return 0;
+}
+
+int send_ramdisk(char* ipsw, plist_t tss) {
+	int i = 0;
+	info("Sending ramdisk\n");
+	irecv_client_t client = NULL;
+	irecv_error_t error = irecv_open(&client);
+	for (i = 10; i > 0; i--) {
+		if (error == IRECV_E_SUCCESS) {
+			break;
+		}
+		sleep(1);
+		info("Retrying connection...\n");
+		error = irecv_open(&client);
+	}
+
+	irecv_close(client);
+	return 0;
+}
+
+int send_kernelcache(char* ipsw, plist_t tss) {
+	int i = 0;
+	info("Sending kernelcache\n");
+	irecv_client_t client = NULL;
+	irecv_error_t error = irecv_open(&client);
+	for (i = 10; i > 0; i--) {
+		if (error == IRECV_E_SUCCESS) {
+			break;
+		}
+		sleep(1);
+		info("Retrying connection...\n");
+		error = irecv_open(&client);
+	}
+
+	irecv_close(client);
+	return 0;
+}
diff --git a/src/ipsw.c b/src/ipsw.c
index f601201..56fd216 100644
--- a/src/ipsw.c
+++ b/src/ipsw.c
@@ -26,6 +26,13 @@
 #include "ipsw.h"
 #include "idevicerestore.h"
 
+typedef struct {
+	struct zip* zip;
+} ipsw_archive;
+
+ipsw_archive* ipsw_open(const char* ipsw);
+void ipsw_close(ipsw_archive* archive);
+
 ipsw_archive* ipsw_open(const char* ipsw) {
 	int err = 0;
 	ipsw_archive* archive = (ipsw_archive*) malloc(sizeof(ipsw_archive));
@@ -44,7 +51,8 @@ ipsw_archive* ipsw_open(const char* ipsw) {
 	return archive;
 }
 
-ipsw_file* ipsw_extract_file(ipsw_archive* archive, const char* filename) {
+ipsw_file* ipsw_extract_file(const char* ipsw, const char* filename) {
+	ipsw_archive* archive = ipsw_open(ipsw);
 	if(archive == NULL || archive->zip == NULL) {
 		error("ERROR: Invalid archive\n");
 		return NULL;
@@ -95,6 +103,7 @@ ipsw_file* ipsw_extract_file(ipsw_archive* archive, const char* filename) {
 	}
 
 	zip_fclose(zfile);
+	ipsw_close(archive);
 	return file;
 }
 
diff --git a/src/ipsw.h b/src/ipsw.h
index 5cbad19..6a49937 100644
--- a/src/ipsw.h
+++ b/src/ipsw.h
@@ -24,10 +24,6 @@
 
 #include <zip.h>
 
-typedef struct {
-	struct zip* zip;
-} ipsw_archive;
-
 typedef struct {
 	int index;
 	char* name;
@@ -35,9 +31,7 @@ typedef struct {
 	unsigned char* data;
 } ipsw_file;
 
-ipsw_archive* ipsw_open(const char* ipsw);
-ipsw_file* ipsw_extract_file(ipsw_archive* archive, const char* filename);
+ipsw_file* ipsw_extract_file(const char* ipsw, const char* filename);
 void ipsw_free_file(ipsw_file* file);
-void ipsw_close(ipsw_archive* archive);
 
 #endif
diff --git a/src/tss.c b/src/tss.c
index 2b2991d..81b0658 100644
--- a/src/tss.c
+++ b/src/tss.c
@@ -109,6 +109,7 @@ plist_t tss_create_request(plist_t buildmanifest, uint64_t ecid) {
 	plist_dict_insert_item(tss_request, "ApBoardID", plist_new_uint(board_id));
 	plist_dict_insert_item(tss_request, "ApSecurityDomain", plist_new_uint(security_domain));
 	plist_dict_insert_item(tss_request, "UniqueBuildID", plist_new_data(unique_build_data, unique_build_size));
+	free(unique_build_data);
 
 	// Add all firmware files to TSS request
 	plist_t manifest_node = plist_dict_get_item(restore_identity_dict, "Manifest");
@@ -135,11 +136,13 @@ plist_t tss_create_request(plist_t buildmanifest, uint64_t ecid) {
 		plist_dict_insert_item(tss_request, key, tss_entry);
 		free(key);
 	}
+	plist_free(manifest_node);
 
 	int sz = 0;
 	char* xml = NULL;
 	plist_to_xml(tss_request, &xml, &sz);
-	printf("%s", xml);
+	debug("%s", xml);
+	free(xml);
 
 	return tss_request;
 }
@@ -218,7 +221,8 @@ plist_t tss_send_request(plist_t tss_request) {
 	int sz = 0;
 	char* xml = NULL;
 	plist_to_xml(tss_response, &xml, &sz);
-	printf("%s", xml);
+	debug("%s", xml);
+	free(xml);
 
 	return tss_response;
 }
-- 
cgit v1.1-32-gdbae