コード例 #1
0
LIBIMOBILEDEVICE_API mobileactivation_error_t mobileactivation_create_activation_info_with_session(mobileactivation_client_t client, plist_t handshake_response, plist_t *info)
{
	if (!client || !info)
		return MOBILEACTIVATION_E_INVALID_ARG;

	plist_t result = NULL;
	plist_t data = plist_data_from_plist(handshake_response);
	mobileactivation_error_t ret = mobileactivation_send_command(client, "CreateTunnel1ActivationInfoRequest", data, &result);
	plist_free(data);
	if (ret == MOBILEACTIVATION_E_SUCCESS) {
		plist_t node = plist_dict_get_item(result, "Value");
		if (!node) {
			debug_info("ERROR: CreateTunnel1ActivationInfoRequest command returned success but has no value in reply");
			ret = MOBILEACTIVATION_E_UNKNOWN_ERROR;
		} else {
			*info = plist_copy(node);
		}
	}
	plist_free(result);
	result = NULL;

	return ret;	
}
コード例 #2
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;
}
コード例 #3
0
/**
 * Sends a DLMessageStatusResponse to the device.
 * 
 * @param client The MobileBackup client to use.
 * @param status_code The status code to send.
 * @param status1 A status message to send. Can be NULL if not required.
 * @param status2 An additional status plist to attach to the response.
 *     Can be NULL if not required.
 *
 * @return MOBILEBACKUP2_E_SUCCESS on success, MOBILEBACKUP2_E_INVALID_ARG
 *     if client is invalid, or another MOBILEBACKUP2_E_* otherwise.
 */
mobilebackup2_error_t mobilebackup2_send_status_response(mobilebackup2_client_t client, int status_code, const char *status1, plist_t status2)
{
	if (!client || !client->parent)
		return MOBILEBACKUP2_E_INVALID_ARG;

	plist_t array = plist_new_array();
	plist_array_append_item(array, plist_new_string("DLMessageStatusResponse"));
	plist_array_append_item(array, plist_new_uint(status_code));
	if (status1) {
		plist_array_append_item(array, plist_new_string(status1));
	} else {
		plist_array_append_item(array, plist_new_string("___EmptyParameterString___"));
	}
	if (status2) {
		plist_array_append_item(array, plist_copy(status2));
	} else {
		plist_array_append_item(array, plist_new_string("___EmptyParameterString___"));
	}

	mobilebackup2_error_t err = mobilebackup2_error(device_link_service_send(client->parent, array));
	plist_free(array);

	return err;
}
コード例 #4
0
LIBIMOBILEDEVICE_API void instproxy_status_get_current_list(plist_t status, uint64_t* total, uint64_t* current_index, uint64_t* current_amount, plist_t* list)
{
	plist_t node = NULL;

	if (status && plist_get_node_type(status) == PLIST_DICT) {
		/* command specific logic: parse browsed list */
		if (list != NULL) {
			node = plist_dict_get_item(status, "CurrentList");
			if (node) {
				*current_amount = plist_array_get_size(node);
				*list = plist_copy(node);
			}
		}

		if (total != NULL) {
			node = plist_dict_get_item(status, "Total");
			if (node) {
				plist_get_uint_val(node, total);
			}
		}

		if (current_amount != NULL) {
			node = plist_dict_get_item(status, "CurrentAmount");
			if (node) {
				plist_get_uint_val(node, current_amount);
			}
		}

		if (current_index != NULL) {
			node = plist_dict_get_item(status, "CurrentIndex");
			if (node) {
				plist_get_uint_val(node, current_index);
			}
		}
	}
}
コード例 #5
0
LIBIMOBILEDEVICE_API instproxy_error_t instproxy_check_capabilities_match(instproxy_client_t client, const char** capabilities, plist_t client_options, plist_t *result)
{
	if (!capabilities || (plist_get_node_type(capabilities) != PLIST_ARRAY && plist_get_node_type(capabilities) != PLIST_DICT))
		return INSTPROXY_E_INVALID_ARG;

	plist_t lookup_result = NULL;

	instproxy_error_t res = INSTPROXY_E_UNKNOWN_ERROR;

	plist_t command = plist_new_dict();
	plist_dict_set_item(command, "Command", plist_new_string("CheckCapabilitiesMatch"));
	if (client_options)
		plist_dict_set_item(command, "ClientOptions", plist_copy(client_options));

	if (capabilities) {
		int i = 0;
		plist_t capabilities_array = plist_new_array();
		while (capabilities[i]) {
			plist_array_append_item(capabilities_array, plist_new_string(capabilities[i]));
			i++;
		}
		plist_dict_set_item(command, "Capabilities", capabilities_array);
	}

	res = instproxy_perform_command(client, command, INSTPROXY_COMMAND_TYPE_SYNC, instproxy_copy_lookup_result_cb, (void*)&lookup_result);

	if (res == INSTPROXY_E_SUCCESS) {
		*result = lookup_result;
	} else {
		plist_free(lookup_result);
	}

	plist_free(command);

	return res;
}
コード例 #6
0
/**
 * Installs the given provisioning profile. Only works with valid profiles.
 *
 * @param client The connected misagent to use for installation
 * @param profile The valid provisioning profile to install. This has to be
 *    passed as a PLIST_DATA, otherwise the function will fail.
 *
 * @return MISAGENT_E_SUCCESS on success, MISAGENT_E_INVALID_ARG when
 *     client is invalid, or an MISAGENT_E_* error code otherwise.
 */
misagent_error_t misagent_install(misagent_client_t client, plist_t profile)
{
	if (!client || !client->parent || !profile || (plist_get_node_type(profile) != PLIST_DATA))
                return MISAGENT_E_INVALID_ARG;

	client->last_error = MISAGENT_E_UNKNOWN_ERROR;

	plist_t dict = plist_new_dict();
	plist_dict_insert_item(dict, "MessageType", plist_new_string("Install"));
	plist_dict_insert_item(dict, "Profile", plist_copy(profile));
	plist_dict_insert_item(dict, "ProfileType", plist_new_string("Provisioning"));

	misagent_error_t res = misagent_error(property_list_service_send_xml_plist(client->parent, dict));
	plist_free(dict);
	dict = NULL;

        if (res != MISAGENT_E_SUCCESS) {
                debug_info("could not send plist, error %d", res);
		return res;
        }

	res = misagent_error(property_list_service_receive_plist(client->parent, &dict));
	if (res != MISAGENT_E_SUCCESS) {
		debug_info("could not receive response, error %d", res);
		return res;
	}
	if (!dict) {
		debug_info("could not get response plist");
		return MISAGENT_E_UNKNOWN_ERROR;
	}

	res = misagent_check_result(dict, &client->last_error);
	plist_free(dict);

	return res;
}
コード例 #7
0
ファイル: tss.c プロジェクト: zweed4u/idevicerestore
int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity)
{
	plist_t node = NULL;
	char* string = NULL;

	/* UniqueBuildID */
	node = plist_dict_get_item(build_identity, "UniqueBuildID");
	if (!node || plist_get_node_type(node) != PLIST_DATA) {
		error("ERROR: Unable to find UniqueBuildID node\n");
		return -1;
	}
	plist_dict_set_item(parameters, "UniqueBuildID", plist_copy(node));
	node = NULL;

	/* ApChipID */
	int chip_id = 0;
	node = plist_dict_get_item(build_identity, "ApChipID");
	if (!node || plist_get_node_type(node) != PLIST_STRING) {
		error("ERROR: Unable to find ApChipID node\n");
		return -1;
	}
	plist_get_string_val(node, &string);
	sscanf(string, "%x", &chip_id);
	plist_dict_set_item(parameters, "ApChipID", plist_new_uint(chip_id));
	free(string);
	string = NULL;
	node = NULL;

	/* ApBoardID */
	int board_id = 0;
	node = plist_dict_get_item(build_identity, "ApBoardID");
	if (!node || plist_get_node_type(node) != PLIST_STRING) {
		error("ERROR: Unable to find ApBoardID node\n");
		return -1;
	}
	plist_get_string_val(node, &string);
	sscanf(string, "%x", &board_id);
	plist_dict_set_item(parameters, "ApBoardID", plist_new_uint(board_id));
	free(string);
	string = NULL;
	node = NULL;

	/* ApSecurityDomain */
	int security_domain = 0;
	node = plist_dict_get_item(build_identity, "ApSecurityDomain");
	if (!node || plist_get_node_type(node) != PLIST_STRING) {
		error("ERROR: Unable to find ApSecurityDomain node\n");
		return -1;
	}
	plist_get_string_val(node, &string);
	sscanf(string, "%x", &security_domain);
	plist_dict_set_item(parameters, "ApSecurityDomain", plist_new_uint(security_domain));
	free(string);
	string = NULL;
	node = NULL;

	/* BbChipID */
	int bb_chip_id = 0;
	char* bb_chip_id_string = NULL;
	node = plist_dict_get_item(build_identity, "BbChipID");
	if (node && plist_get_node_type(node) == PLIST_STRING) {
		plist_get_string_val(node, &bb_chip_id_string);
		sscanf(bb_chip_id_string, "%x", &bb_chip_id);
		plist_dict_set_item(parameters, "BbChipID", plist_new_uint(bb_chip_id));
	} else {
		error("WARNING: Unable to find BbChipID node\n");
	}
	node = NULL;

	/* BbProvisioningManifestKeyHash */
	node = plist_dict_get_item(build_identity, "BbProvisioningManifestKeyHash");
	if (node && plist_get_node_type(node) == PLIST_DATA) {
		plist_dict_set_item(parameters, "BbProvisioningManifestKeyHash", plist_copy(node));
	} else {
		debug("NOTE: Unable to find BbProvisioningManifestKeyHash node\n");
	}
	node = NULL;

	/* BbActivationManifestKeyHash - Used by Qualcomm MDM6610 */
	node = plist_dict_get_item(build_identity, "BbActivationManifestKeyHash");
	if (node && plist_get_node_type(node) == PLIST_DATA) {
		plist_dict_set_item(parameters, "BbActivationManifestKeyHash", plist_copy(node));
	} else {
		debug("NOTE: Unable to find BbActivationManifestKeyHash node\n");
	}
	node = NULL;

	node = plist_dict_get_item(build_identity, "BbCalibrationManifestKeyHash");
	if (node && plist_get_node_type(node) == PLIST_DATA) {
		plist_dict_set_item(parameters, "BbCalibrationManifestKeyHash", plist_copy(node));
	} else {
		debug("NOTE: Unable to find BbCalibrationManifestKeyHash node\n");
	}
	node = NULL;

	/* BbFactoryActivationManifestKeyHash */
	node = plist_dict_get_item(build_identity, "BbFactoryActivationManifestKeyHash");
	if (node && plist_get_node_type(node) == PLIST_DATA) {
		plist_dict_set_item(parameters, "BbFactoryActivationManifestKeyHash", plist_copy(node));
	} else {
		debug("NOTE: Unable to find BbFactoryActivationManifestKeyHash node\n");
	}
	node = NULL;

	/* BbFDRSecurityKeyHash */
	node = plist_dict_get_item(build_identity, "BbFDRSecurityKeyHash");
	if (node && plist_get_node_type(node) == PLIST_DATA) {
		plist_dict_set_item(parameters, "BbFDRSecurityKeyHash", plist_copy(node));
	} else {
		debug("NOTE: Unable to find BbFDRSecurityKeyHash node\n");
	}
	node = NULL;

	/* BbSkeyId - Used by XMM 6180/GSM */
	node = plist_dict_get_item(build_identity, "BbSkeyId");
	if (node && plist_get_node_type(node) == PLIST_DATA) {
		plist_dict_set_item(parameters, "BbSkeyId", plist_copy(node));
	} else {
		error("WARNING: Unable to find BbSkeyId node\n");
	}
	node = NULL;

	/* add build identity manifest dictionary */
	node = plist_dict_get_item(build_identity, "Manifest");
	if (!node || plist_get_node_type(node) != PLIST_DICT) {
		error("ERROR: Unable to find Manifest node\n");
		return -1;
	}
	plist_dict_set_item(parameters, "Manifest", plist_copy(node));

	return 0;
}
コード例 #8
0
ファイル: tss.c プロジェクト: zweed4u/idevicerestore
int tss_request_add_se_tags(plist_t request, plist_t parameters, plist_t overrides)
{
	plist_t node = NULL;

	plist_t manifest_node = plist_dict_get_item(parameters, "Manifest");
	if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
		error("ERROR: %s: Unable to get restore manifest from parameters\n", __func__);
		return -1;
	}

	/* add tags indicating we want to get the SE,Ticket */
	plist_dict_set_item(request, "@BBTicket", plist_new_bool(1));
	plist_dict_set_item(request, "@SE,Ticket", plist_new_bool(1));

	/* add SE,ChipID */
	node = plist_dict_get_item(parameters, "SE,ChipID");
	if (!node) {
		error("ERROR: %s: Unable to find required SE,ChipID in parameters\n", __func__);
		return -1;
	}
	plist_dict_set_item(request, "SE,ChipID", plist_copy(node));
	node = NULL;

	/* add SE,ID */
	node = plist_dict_get_item(parameters, "SE,ID");
	if (!node) {
		error("ERROR: %s: Unable to find required SE,ID in parameters\n", __func__);
		return -1;
	}
	plist_dict_set_item(request, "SE,ID", plist_copy(node));
	node = NULL;

	/* add SE,Nonce */
	node = plist_dict_get_item(parameters, "SE,Nonce");
	if (!node) {
		error("ERROR: %s: Unable to find required SE,Nonce in parameters\n", __func__);
		return -1;
	}
	plist_dict_set_item(request, "SE,Nonce", plist_copy(node));
	node = NULL;

	/* add SE,RootKeyIdentifier */
	node = plist_dict_get_item(parameters, "SE,RootKeyIdentifier");
	if (!node) {
		error("ERROR: %s: Unable to find required SE,RootKeyIdentifier in parameters\n", __func__);
		return -1;
	}
	plist_dict_set_item(request, "SE,RootKeyIdentifier", plist_copy(node));
	node = NULL;

	/* 'IsDev' determines whether we have Production or Development */
	const char *removing_cmac_key = "DevelopmentCMAC";
	node = plist_dict_get_item(parameters, "SE,IsDev");
	if (node && plist_get_node_type(node) == PLIST_BOOLEAN) {
		uint8_t is_dev = 0;
		plist_get_bool_val(node, &is_dev);
		removing_cmac_key = (is_dev) ? "ProductionCMAC" : "DevelopmentCMAC";
	}

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

		if (strncmp(key, "SE,", 3)) {
			free(key);
			continue;
		}

		/* copy this entry */
		plist_t tss_entry = plist_copy(manifest_entry);

		/* remove Info node */
		plist_dict_remove_item(tss_entry, "Info");

		/* remove 'DevelopmentCMAC' (or 'ProductionCMAC') node */
		if (plist_dict_get_item(tss_entry, removing_cmac_key)) {
			plist_dict_remove_item(tss_entry, removing_cmac_key);
		}

		/* add entry to request */
		plist_dict_set_item(request, key, tss_entry);

		free(key);
	}
	free(iter);

	/* apply overrides */
	if (overrides) {
		plist_dict_merge(&request, overrides);
	}

	return 0;
}
コード例 #9
0
ファイル: tss.c プロジェクト: zweed4u/idevicerestore
int tss_request_add_baseband_tags(plist_t request, plist_t parameters, plist_t overrides) {
	plist_t node = NULL;

	/* BbChipID */
	node = plist_dict_get_item(parameters, "BbChipID");
	if (node) {
		plist_dict_set_item(request, "BbChipID", plist_copy(node));
	}
	node = NULL;

	/* BbProvisioningManifestKeyHash */
	node = plist_dict_get_item(parameters, "BbProvisioningManifestKeyHash");
	if (node) {
		plist_dict_set_item(request, "BbProvisioningManifestKeyHash", plist_copy(node));
	}
	node = NULL;

	/* BbActivationManifestKeyHash - Used by Qualcomm MDM6610 */
	node = plist_dict_get_item(parameters, "BbActivationManifestKeyHash");
	if (node) {
		plist_dict_set_item(request, "BbActivationManifestKeyHash", plist_copy(node));
	}
	node = NULL;

	node = plist_dict_get_item(parameters, "BbCalibrationManifestKeyHash");
	if (node) {
		plist_dict_set_item(request, "BbCalibrationManifestKeyHash", plist_copy(node));
	}
	node = NULL;

	/* BbFactoryActivationManifestKeyHash */
	node = plist_dict_get_item(parameters, "BbFactoryActivationManifestKeyHash");
	if (node) {
		plist_dict_set_item(request, "BbFactoryActivationManifestKeyHash", plist_copy(node));
	}
	node = NULL;

	/* BbFDRSecurityKeyHash */
	node = plist_dict_get_item(parameters, "BbFDRSecurityKeyHash");
	if (node) {
		plist_dict_set_item(request, "BbFDRSecurityKeyHash", plist_copy(node));
	}
	node = NULL;

	/* BbSkeyId - Used by XMM 6180/GSM */
	node = plist_dict_get_item(parameters, "BbSkeyId");
	if (node) {
		plist_dict_set_item(request, "BbSkeyId", plist_copy(node));
	}
	node = NULL;

	/* BbNonce */
	node = plist_dict_get_item(parameters, "BbNonce");
	if (node) {
		plist_dict_set_item(request, "BbNonce", plist_copy(node));
	}
	node = NULL;

	/* @BBTicket */
	plist_dict_set_item(request, "@BBTicket", plist_new_bool(1));

	/* BbGoldCertId */
	node = plist_dict_get_item(parameters, "BbGoldCertId");
	if (!node || plist_get_node_type(node) != PLIST_UINT) {
		error("ERROR: Unable to find required BbGoldCertId in parameters\n");
		return -1;
	}
	node = plist_copy(node);
	uint64_t val;
	plist_get_uint_val(node, &val);
	plist_set_uint_val(node, (int32_t)val);
	plist_dict_set_item(request, "BbGoldCertId", node);
	node = NULL;

	/* BbSNUM */
	node = plist_dict_get_item(parameters, "BbSNUM");
	if (!node || plist_get_node_type(node) != PLIST_DATA) {
		error("ERROR: Unable to find required BbSNUM in parameters\n");
		return -1;
	}
	plist_dict_set_item(request, "BbSNUM", plist_copy(node));
	node = NULL;

	/* BasebandFirmware */
	node = plist_access_path(parameters, 2, "Manifest", "BasebandFirmware");
	if (!node || plist_get_node_type(node) != PLIST_DICT) {
		error("ERROR: Unable to get BasebandFirmware node\n");
		return -1;
	}
	plist_t bbfwdict = plist_copy(node);
	node = NULL;
	if (plist_dict_get_item(bbfwdict, "Info")) {
		plist_dict_remove_item(bbfwdict, "Info");
	}
	plist_dict_set_item(request, "BasebandFirmware", bbfwdict);

	/* apply overrides */
	if (overrides) {
		plist_dict_merge(&request, overrides);
	}

	return 0;
}
コード例 #10
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;
}
コード例 #11
0
ファイル: Uid.cpp プロジェクト: Clstroud/libplist
Uid& Uid::operator=(PList::Uid& i)
{
    plist_free(_node);
    _node = plist_copy(i.GetPlist());
    return *this;
}
コード例 #12
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;
}
コード例 #13
0
ファイル: Key.cpp プロジェクト: UnveN/libplist
Key& Key::operator=(PList::Key& k)
{
    plist_free(_node);
    _node = plist_copy(k.GetPlist());
    return *this;
}
コード例 #14
0
ファイル: mobilesync.c プロジェクト: KobyBo/libimobiledevice
/**
 * Receives any remapped identifiers reported after the device merged submitted changes.
 *
 * @param client The mobilesync client
 * @param mapping A pointer to an array plist containing a dict of identifier remappings
 *
 * @retval MOBILESYNC_E_SUCCESS on success
 * @retval MOBILESYNC_E_INVALID_ARG if one of the parameters is invalid
 * @retval MOBILESYNC_E_PLIST_ERROR if the received plist is not of valid
 * form
 * @retval MOBILESYNC_E_WRONG_DIRECTION if the current sync direction does
 * not permit this call
 * @retval MOBILESYNC_E_CANCELLED if the device explicitly cancelled the
 * session
 */
mobilesync_error_t mobilesync_remap_identifiers(mobilesync_client_t client, plist_t *mapping)
{
	if (!client || !client->data_class) {
		return MOBILESYNC_E_INVALID_ARG;
	}

	if (client->direction == MOBILESYNC_SYNC_DIR_DEVICE_TO_COMPUTER) {
		return MOBILESYNC_E_WRONG_DIRECTION;
	}

	plist_t msg = NULL;
	plist_t response_type_node = NULL;
	char *response_type = NULL;

	mobilesync_error_t err = mobilesync_receive(client, &msg);
	if (err != MOBILESYNC_E_SUCCESS) {
		goto out;
	}

	response_type_node = plist_array_get_item(msg, 0);
	if (!response_type_node) {
		err = MOBILESYNC_E_PLIST_ERROR;
		goto out;
	}

	plist_get_string_val(response_type_node, &response_type);
	if (!response_type) {
		err = MOBILESYNC_E_PLIST_ERROR;
		goto out;
	}

	if (!strcmp(response_type, "SDMessageCancelSession")) {
		char *reason = NULL;
		err = MOBILESYNC_E_CANCELLED;
		plist_get_string_val(plist_array_get_item(msg, 2), &reason);
		debug_info("Device cancelled: %s", reason);
		free(reason);
		goto out;
	}

	if (strcmp(response_type, "SDMessageRemapRecordIdentifiers") != 0) {
		err = MOBILESYNC_E_PLIST_ERROR;
		goto out;
	}

	if (mapping != NULL) {
		plist_t map = plist_array_get_item(msg, 2);
		if (plist_get_node_type(map) == PLIST_DICT) {
			*mapping = plist_copy(map);
		} else {
			*mapping = NULL;
		}
	}

	err = MOBILESYNC_E_SUCCESS;

	out:
	if (response_type) {
		free(response_type);
		response_type = NULL;
	}
	if (msg) {
		plist_free(msg);
		msg = NULL;
	}

	return err;
}
コード例 #15
0
ファイル: mobilesync.c プロジェクト: KobyBo/libimobiledevice
/**
 * Receives changed entitites of the currently set data class from the device
 *
 * @param client The mobilesync client
 * @param entities A pointer to store the changed entity records as a PLIST_DICT
 * @param is_last_record A pointer to store a flag indicating if this submission is the last one
 * @param actions A pointer to additional flags the device is sending or NULL to ignore
 *
 * @retval MOBILESYNC_E_SUCCESS on success
 * @retval MOBILESYNC_E_INVALID_ARG if one of the parameters is invalid
 * @retval MOBILESYNC_E_CANCELLED if the device explicitly cancelled the
 * session
 */
mobilesync_error_t mobilesync_receive_changes(mobilesync_client_t client, plist_t *entities, uint8_t *is_last_record, plist_t *actions)
{
	if (!client || !client->data_class) {
		return MOBILESYNC_E_INVALID_ARG;
	}

	plist_t msg = NULL;
	plist_t response_type_node = NULL;
	plist_t actions_node = NULL;
	char *response_type = NULL;
	uint8_t has_more_changes = 0;

	mobilesync_error_t err = mobilesync_receive(client, &msg);
	if (err != MOBILESYNC_E_SUCCESS) {
		goto out;
	}

	response_type_node = plist_array_get_item(msg, 0);
	if (!response_type_node) {
		err = MOBILESYNC_E_PLIST_ERROR;
		goto out;
	}

	plist_get_string_val(response_type_node, &response_type);
	if (!response_type) {
		err = MOBILESYNC_E_PLIST_ERROR;
		goto out;
	}

	if (!strcmp(response_type, "SDMessageCancelSession")) {
		char *reason = NULL;
		err = MOBILESYNC_E_CANCELLED;
		plist_get_string_val(plist_array_get_item(msg, 2), &reason);
		debug_info("Device cancelled: %s", reason);
		free(reason);
		goto out;
	}

	if (entities != NULL) {
		*entities = plist_copy(plist_array_get_item(msg, 2));
	}

	if (is_last_record != NULL) {
		plist_get_bool_val(plist_array_get_item(msg, 3), &has_more_changes);
		*is_last_record = (has_more_changes > 0 ? 0 : 1);
	}

	if (actions != NULL) {
		actions_node = plist_array_get_item(msg, 4);
		if (plist_get_node_type(actions) == PLIST_DICT)
			*actions = plist_copy(actions_node);
		else
			*actions = NULL;
	}

	out:
	if (response_type) {
		free(response_type);
		response_type = NULL;
	}
	if (msg) {
		plist_free(msg);
		msg = NULL;
	}
	return err;
}
コード例 #16
0
int idevicerestore_start(struct idevicerestore_client_t* client)
{
	int tss_enabled = 0;
	int result = 0;

	if (!client) {
		return -1;
	}

	if ((client->flags & FLAG_LATEST) && (client->flags & FLAG_CUSTOM)) {
		error("ERROR: FLAG_LATEST cannot be used with FLAG_CUSTOM.\n");
		return -1;
	}

	if (!client->ipsw && !(client->flags & FLAG_PWN) && !(client->flags & FLAG_LATEST)) {
		error("ERROR: no ipsw file given\n");
		return -1;
	}

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

	idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.0);

	// update version data (from cache, or apple if too old)
	load_version_data(client);

	// 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;
	}
	idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.1);
	info("Found device in %s mode\n", client->mode->string);

	if (client->mode->index == MODE_WTF) {
		unsigned int cpid = 0;

		if (dfu_client_new(client) != 0) {
			error("ERROR: Could not open device in WTF mode\n");
			return -1;
		}
		if ((dfu_get_cpid(client, &cpid) < 0) || (cpid == 0)) { 
			error("ERROR: Could not get CPID for WTF mode device\n");
			dfu_client_free(client);
			return -1;
		}

		char wtfname[256];
		sprintf(wtfname, "Firmware/dfu/WTF.s5l%04xxall.RELEASE.dfu", cpid);
		unsigned char* wtftmp = NULL;
		unsigned int wtfsize = 0;

		// Prefer to get WTF file from the restore IPSW
		ipsw_extract_to_memory(client->ipsw, wtfname, &wtftmp, &wtfsize);
		if (!wtftmp) {
			// Download WTF IPSW
			char* s_wtfurl = NULL;
			plist_t wtfurl = plist_access_path(client->version_data, 7, "MobileDeviceSoftwareVersionsByVersion", "5", "RecoverySoftwareVersions", "WTF", "304218112", "5", "FirmwareURL");
			if (wtfurl && (plist_get_node_type(wtfurl) == PLIST_STRING)) {
				plist_get_string_val(wtfurl, &s_wtfurl);
			}
			if (!s_wtfurl) {
				info("Using hardcoded x12220000_5_Recovery.ipsw URL\n");
				s_wtfurl = strdup("http://appldnld.apple.com.edgesuite.net/content.info.apple.com/iPhone/061-6618.20090617.Xse7Y/x12220000_5_Recovery.ipsw");
			}

			// make a local file name
			char* fnpart = strrchr(s_wtfurl, '/');
			if (!fnpart) {
				fnpart = "x12220000_5_Recovery.ipsw";
			} else {
				fnpart++;
			}
			struct stat fst;
			char wtfipsw[1024];
			if (client->cache_dir) {
				if (stat(client->cache_dir, &fst) < 0) {
					mkdir_with_parents(client->cache_dir, 0755);
				}
				strcpy(wtfipsw, client->cache_dir);
				strcat(wtfipsw, "/");
				strcat(wtfipsw, fnpart);
			} else {
				strcpy(wtfipsw, fnpart);
			}
			if (stat(wtfipsw, &fst) != 0) {
				download_to_file(s_wtfurl, wtfipsw, 0);
			}

			ipsw_extract_to_memory(wtfipsw, wtfname, &wtftmp, &wtfsize);
			if (!wtftmp) {
				error("ERROR: Could not extract WTF\n");
			}
		}

		if (wtftmp) {
			if (dfu_send_buffer(client, wtftmp, wtfsize) != 0) {
				error("ERROR: Could not send WTF...\n");
			}
		}
		dfu_client_free(client);

		sleep(1);

		free(wtftmp);
		client->mode = &idevicerestore_modes[MODE_DFU];
	}

	// discover the device type
	if (check_product_type(client) == NULL || client->device == NULL) {
		error("ERROR: Unable to discover device type\n");
		return -1;
	}
	idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.2);
	info("Identified device as %s\n", client->device->product_type);

	if ((client->flags & FLAG_PWN) && (client->mode->index != MODE_DFU)) {
		error("ERROR: you need to put your device into DFU mode to pwn it.\n");
		return -1;
	}

	if (client->flags & FLAG_PWN) {
		recovery_client_free(client);

		info("connecting to DFU\n");
		if (dfu_client_new(client) < 0) {
			return -1;
		}
		info("exploiting with limera1n...\n");
		// TODO: check for non-limera1n device and fail
		if (limera1n_exploit(client->device, &client->dfu->client) != 0) {
			error("ERROR: limera1n exploit failed\n");
			dfu_client_free(client);
			return -1;
		}
		dfu_client_free(client);
		info("Device should be in pwned DFU state now.\n");

		return 0;
	}

	if (client->flags & FLAG_LATEST) {
		char* ipsw = NULL;
		int res = ipsw_download_latest_fw(client->version_data, client->device->product_type, "cache", &ipsw);
		if (res != 0) {
			if (ipsw) {
				free(ipsw);
			}
			return res;
		} else {
			client->ipsw = ipsw;
		}
	}
	idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.6);

	if (client->flags & FLAG_NOACTION) {
		return 0;
	}

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

		// we need to refresh the current mode again
		check_mode(client);
		info("Found device in %s mode\n", client->mode->string);
	}

	// verify if ipsw file exists
	if (access(client->ipsw, F_OK) < 0) {
		error("ERROR: Firmware file %s does not exist.\n", client->ipsw);
		return -1;
	}

	// extract buildmanifest
	plist_t buildmanifest = NULL;
	if (client->flags & FLAG_CUSTOM) {
		info("Extracting Restore.plist from IPSW\n");
		if (ipsw_extract_restore_plist(client->ipsw, &buildmanifest) < 0) {
			error("ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw);
			return -1;
		}
	} else {
		info("Extracting BuildManifest from IPSW\n");
		if (ipsw_extract_build_manifest(client->ipsw, &buildmanifest, &tss_enabled) < 0) {
			error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw);
			return -1;
		}
	}
	idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.8);

	/* check if device type is supported by the given build manifest */
	if (build_manifest_check_compatibility(buildmanifest, client->device->product_type) < 0) {
		error("ERROR: Could not make sure this firmware is suitable for the current device. Refusing to continue.\n");
		return -1;
	}

	/* print iOS information from the manifest */
	build_manifest_get_version_information(buildmanifest, client);

	info("Product Version: %s\n", client->version);
	info("Product Build: %s Major: %d\n", client->build, client->build_major);

	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_CUSTOM) {
		build_identity = plist_new_dict();
		{
			plist_t node;
			plist_t comp;
			plist_t inf;
			plist_t manifest;

			char tmpstr[256];
			char p_all_flash[128];
			char lcmodel[8];
			strcpy(lcmodel, client->device->hardware_model);
			int x = 0;
			while (lcmodel[x]) {
				lcmodel[x] = tolower(lcmodel[x]);
				x++;
			}

			sprintf(p_all_flash, "Firmware/all_flash/all_flash.%s.%s", lcmodel, "production");
			strcpy(tmpstr, p_all_flash);
			strcat(tmpstr, "/manifest");

			// get all_flash file manifest
			char *files[16];
			char *fmanifest = NULL;
			uint32_t msize = 0;
			if (ipsw_extract_to_memory(client->ipsw, tmpstr, (unsigned char**)&fmanifest, &msize) < 0) {
				error("ERROR: could not extract %s from IPSW\n", tmpstr);
				return -1;
			}

			char *tok = strtok(fmanifest, "\r\n");
			int fc = 0;
			while (tok) {
				files[fc++] = strdup(tok);
				if (fc >= 16) {
					break;
				}
				tok = strtok(NULL, "\r\n");
			}
			free(fmanifest);

			manifest = plist_new_dict();

			for (x = 0; x < fc; x++) {
				inf = plist_new_dict();
				strcpy(tmpstr, p_all_flash);
				strcat(tmpstr, "/");
				strcat(tmpstr, files[x]);
				plist_dict_insert_item(inf, "Path", plist_new_string(tmpstr));
				comp = plist_new_dict();
				plist_dict_insert_item(comp, "Info", inf);
				const char* compname = get_component_name(files[x]);
				if (compname) {
					plist_dict_insert_item(manifest, compname, comp);
					if (!strncmp(files[x], "DeviceTree", 10)) {
						plist_dict_insert_item(manifest, "RestoreDeviceTree", plist_copy(comp));
					}
				} else {
					error("WARNING: unhandled component %s\n", files[x]);
					plist_free(comp);
				}
				free(files[x]);
				files[x] = NULL;
			}

			// add iBSS
			sprintf(tmpstr, "Firmware/dfu/iBSS.%s.%s.dfu", lcmodel, "RELEASE");
			inf = plist_new_dict();
			plist_dict_insert_item(inf, "Path", plist_new_string(tmpstr));
			comp = plist_new_dict();
			plist_dict_insert_item(comp, "Info", inf);
			plist_dict_insert_item(manifest, "iBSS", comp);

			// add iBEC
			sprintf(tmpstr, "Firmware/dfu/iBEC.%s.%s.dfu", lcmodel, "RELEASE");
			inf = plist_new_dict();
			plist_dict_insert_item(inf, "Path", plist_new_string(tmpstr));
			comp = plist_new_dict();
			plist_dict_insert_item(comp, "Info", inf);
			plist_dict_insert_item(manifest, "iBEC", comp);

			// add kernel cache
			plist_t kdict = NULL;

			node = plist_dict_get_item(buildmanifest, "KernelCachesByTarget");
			if (node && (plist_get_node_type(node) == PLIST_DICT)) {
				char tt[4];
				strncpy(tt, lcmodel, 3);
				tt[3] = 0;
				kdict = plist_dict_get_item(node, tt);
			} else {
				// Populated in older iOS IPSWs
				kdict = plist_dict_get_item(buildmanifest, "RestoreKernelCaches");
			}
			if (kdict && (plist_get_node_type(kdict) == PLIST_DICT)) {
				plist_t kc = plist_dict_get_item(kdict, "Release");
				if (kc && (plist_get_node_type(kc) == PLIST_STRING)) {
					inf = plist_new_dict();
					plist_dict_insert_item(inf, "Path", plist_copy(kc));
					comp = plist_new_dict();
					plist_dict_insert_item(comp, "Info", inf);
					plist_dict_insert_item(manifest, "KernelCache", comp);
					plist_dict_insert_item(manifest, "RestoreKernelCache", plist_copy(comp));
				}
			}

			// add ramdisk
			node = plist_dict_get_item(buildmanifest, "RestoreRamDisks");
			if (node && (plist_get_node_type(node) == PLIST_DICT)) {
				plist_t rd = plist_dict_get_item(node, (client->flags & FLAG_ERASE) ? "User" : "Update");
				// if no "Update" ram disk entry is found try "User" ram disk instead
				if (!rd && !(client->flags & FLAG_ERASE)) {
					rd = plist_dict_get_item(node, "User");
					// also, set the ERASE flag since we actually change the restore variant
					client->flags |= FLAG_ERASE;
				}
				if (rd && (plist_get_node_type(rd) == PLIST_STRING)) {
					inf = plist_new_dict();
					plist_dict_insert_item(inf, "Path", plist_copy(rd));
					comp = plist_new_dict();
					plist_dict_insert_item(comp, "Info", inf);
					plist_dict_insert_item(manifest, "RestoreRamDisk", comp);
				}
			}

			// add OS filesystem
			node = plist_dict_get_item(buildmanifest, "SystemRestoreImages");
			if (!node) {
				error("ERROR: missing SystemRestoreImages in Restore.plist\n");
			}
			plist_t os = plist_dict_get_item(node, "User");
			if (!os) {
				error("ERROR: missing filesystem in Restore.plist\n");
			} else {
				inf = plist_new_dict();
				plist_dict_insert_item(inf, "Path", plist_copy(os));
				comp = plist_new_dict();
				plist_dict_insert_item(comp, "Info", inf);
				plist_dict_insert_item(manifest, "OS", comp);
			}

			// add info
			inf = plist_new_dict();
			plist_dict_insert_item(inf, "RestoreBehavior", plist_new_string((client->flags & FLAG_ERASE) ? "Erase" : "Update"));
			plist_dict_insert_item(inf, "Variant", plist_new_string((client->flags & FLAG_ERASE) ? "Customer Erase Install (IPSW)" : "Customer Upgrade Install (IPSW)"));
			plist_dict_insert_item(build_identity, "Info", inf);

			// finally add manifest
			plist_dict_insert_item(build_identity, "Manifest", manifest);
		}
	} else 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);

	idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.0);
	/* 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 " FMT_qu "\n", (long long unsigned int)client->ecid);

		if (client->build_major > 8) {
			unsigned char* nonce = NULL;
			int nonce_size = 0;
			int nonce_changed = 0;
			if (get_nonce(client, &nonce, &nonce_size) < 0) {
				/* the first nonce request with older firmware releases can fail and it's OK */
				info("NOTE: Unable to get nonce from device\n");
			}

			if (!client->nonce || (nonce_size != client->nonce_size) || (memcmp(nonce, client->nonce, nonce_size) != 0)) {
				nonce_changed = 1;
				if (client->nonce) {
					free(client->nonce);
				}
				client->nonce = nonce;
				client->nonce_size = nonce_size;
			} else {
				free(nonce);
			}
		}

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

	if (client->flags & FLAG_SHSHONLY) {
		if (!tss_enabled) {
			info("This device does not require a TSS record");
			return 0;
		}
		if (!client->tss) {
			error("ERROR: could not fetch TSS record");
			plist_free(buildmanifest);
			return -1;
		} else {
			char *bin = NULL;
			uint32_t blen = 0;
			plist_to_bin(client->tss, &bin, &blen);
			if (bin) {
				char zfn[1024];
				if (client->cache_dir) {
					strcpy(zfn, client->cache_dir);
					strcat(zfn, "/shsh");
				} else {
					strcpy(zfn, "shsh");
				}
				mkdir_with_parents(zfn, 0755);
				sprintf(zfn+strlen(zfn), "/" FMT_qu "-%s-%s.shsh", (long long int)client->ecid, client->device->product_type, client->version);
				struct stat fst;
				if (stat(zfn, &fst) != 0) {
					gzFile zf = gzopen(zfn, "wb");
					gzwrite(zf, bin, blen);
					gzclose(zf);
					info("SHSH saved to '%s'\n", zfn);
				} else {
					info("SHSH '%s' already present.\n", zfn);
				}
				free(bin);
			} else {
				error("ERROR: could not get TSS record data\n");
			}
			plist_free(client->tss);
			plist_free(buildmanifest);
			return 0;
		}
	}

	/* 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;
	}

	if ((tss_enabled) && client->tss) {
		/* fix empty dicts */
		fixup_tss(client->tss);
	}
	idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.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 from %s mode\n", client->mode->string);
			if (client->tss)
				plist_free(client->tss);
			plist_free(buildmanifest);
			return -5;
		}
	}

	// Get filesystem name from build identity
	char* fsname = NULL;
	if (build_identity_get_component_path(build_identity, "OS", &fsname) < 0) {
		error("ERROR: Unable get path for filesystem component\n");
		return -1;
	}

	// check if we already have an extracted filesystem
	int delete_fs = 0;
	char* filesystem = NULL;
	struct stat st;
	memset(&st, '\0', sizeof(struct stat));
	char tmpf[1024];
	if (client->cache_dir) {
		if (stat(client->cache_dir, &st) < 0) {
			mkdir_with_parents(client->cache_dir, 0755);
		}
		strcpy(tmpf, client->cache_dir);
		strcat(tmpf, "/");
		char *ipswtmp = strdup(client->ipsw);
		strcat(tmpf, basename(ipswtmp));
		free(ipswtmp);
	} else {
		strcpy(tmpf, client->ipsw);
	}
	char* p = strrchr((const char*)tmpf, '.');
	if (p) {
		*p = '\0';
	}

	if (stat(tmpf, &st) < 0) {
		__mkdir(tmpf, 0755);
	}
	strcat(tmpf, "/");
	strcat(tmpf, fsname);

	memset(&st, '\0', sizeof(struct stat));
	if (stat(tmpf, &st) == 0) {
		off_t fssize = 0;
		ipsw_get_file_size(client->ipsw, fsname, &fssize);
		if ((fssize > 0) && (st.st_size == fssize)) {
			info("Using cached filesystem from '%s'\n", tmpf);
			filesystem = strdup(tmpf);
		}
	}

	if (!filesystem) {
		char extfn[1024];
		strcpy(extfn, tmpf);
		strcat(extfn, ".extract");
		char lockfn[1024];
		strcpy(lockfn, tmpf);
		strcat(lockfn, ".lock");
		lock_info_t li;

		lock_file(lockfn, &li);
		FILE* extf = NULL;
		if (access(extfn, F_OK) != 0) {
			extf = fopen(extfn, "w");
		}
		unlock_file(&li);
		if (!extf) {
			// use temp filename
			filesystem = tempnam(NULL, "ipsw_");
			if (!filesystem) {
				error("WARNING: Could not get temporary filename, using '%s' in current directory\n", fsname);
				filesystem = strdup(fsname);
			}
			delete_fs = 1;
		} else {
			// use <fsname>.extract as filename
			filesystem = strdup(extfn);
			fclose(extf);
		}
		remove(lockfn);

		// Extract filesystem from IPSW
		info("Extracting filesystem from IPSW\n");
		if (ipsw_extract_to_file(client->ipsw, fsname, filesystem) < 0) {
			error("ERROR: Unable to extract filesystem from IPSW\n");
			if (client->tss)
				plist_free(client->tss);
			plist_free(buildmanifest);
			return -1;
		}

		if (strstr(filesystem, ".extract")) {
			// rename <fsname>.extract to <fsname>
			rename(filesystem, tmpf);
			free(filesystem);
			filesystem = strdup(tmpf); 
		}
	}

	idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.3);

	// if the device is in DFU mode, place device into recovery mode
	if (client->mode->index == MODE_DFU) {
		recovery_client_free(client);
		if ((client->flags & FLAG_CUSTOM) && limera1n_is_supported(client->device)) {
			info("connecting to DFU\n");
			if (dfu_client_new(client) < 0) {
				if (delete_fs && filesystem)
					unlink(filesystem);
				return -1;
			}
			info("exploiting with limera1n\n");
			// TODO: check for non-limera1n device and fail
			if (limera1n_exploit(client->device, &client->dfu->client) != 0) {
				error("ERROR: limera1n exploit failed\n");
				dfu_client_free(client);
				if (delete_fs && filesystem)
					unlink(filesystem);
				return -1;
			}
			dfu_client_free(client);
			info("exploited\n");
		}
		if (dfu_enter_recovery(client, build_identity) < 0) {
			error("ERROR: Unable to place device into recovery mode from %s mode\n", client->mode->string);
			plist_free(buildmanifest);
			if (client->tss)
				plist_free(client->tss);
			if (delete_fs && filesystem)
				unlink(filesystem);
			return -2;
		}
	}

	if (client->mode->index == MODE_DFU) {
		client->mode = &idevicerestore_modes[MODE_RECOVERY];
	} else {
		if ((client->build_major > 8) && !(client->flags & FLAG_CUSTOM)) {
			/* send ApTicket */
			if (recovery_send_ticket(client) < 0) {
				error("WARNING: Unable to send APTicket\n");
			}
		}

		/* now we load the iBEC */
		if (recovery_send_ibec(client, build_identity) < 0) {
			error("ERROR: Unable to send iBEC\n");
			if (delete_fs && filesystem)
				unlink(filesystem);
			return -2;
		}
		recovery_client_free(client);
	
		/* this must be long enough to allow the device to run the iBEC */
		/* FIXME: Probably better to detect if the device is back then */
		sleep(7);
	}
	idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.5);

	if (client->build_major > 8) {
		// we need another tss request with nonce.
		unsigned char* nonce = NULL;
		int nonce_size = 0;
		int nonce_changed = 0;
		if (get_nonce(client, &nonce, &nonce_size) < 0) {
			error("ERROR: Unable to get nonce from device!\n");
			recovery_send_reset(client);
			if (delete_fs && filesystem)
				unlink(filesystem);
			return -2;
		}

		if (!client->nonce || (nonce_size != client->nonce_size) || (memcmp(nonce, client->nonce, nonce_size) != 0)) {
			nonce_changed = 1;
			if (client->nonce) {
				free(client->nonce);
			}
			client->nonce = nonce;
			client->nonce_size = nonce_size;
		} else {
			free(nonce);
		}

		if (nonce_changed && !(client->flags & FLAG_CUSTOM)) {
			// Welcome iOS5. We have to re-request the TSS with our nonce.
			plist_free(client->tss);
			if (get_shsh_blobs(client, client->ecid, client->nonce, client->nonce_size, build_identity, &client->tss) < 0) {
				error("ERROR: Unable to get SHSH blobs for this device\n");
				if (delete_fs && filesystem)
					unlink(filesystem);
				return -1;
			}
			if (!client->tss) {
				error("ERROR: can't continue without TSS\n");
				if (delete_fs && filesystem)
					unlink(filesystem);
				return -1;
			}
			fixup_tss(client->tss);
		}
	}
	idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.7);

	// now finally do the magic to put the device into restore mode
	if (client->mode->index == MODE_RECOVERY) {
		if (client->srnm == NULL) {
			error("ERROR: could not retrieve device serial number. Can't continue.\n");
			if (delete_fs && filesystem)
				unlink(filesystem);
			return -1;
		}
		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);
			if (delete_fs && filesystem)
				unlink(filesystem);
			return -2;
		}
		recovery_client_free(client);
	}
	idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.9);

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

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

	/* special handling of AppleTVs */
	if (strncmp(client->device->product_type, "AppleTV", 7) == 0) {
		if (recovery_client_new(client) == 0) {
			if (recovery_set_autoboot(client, 1) == 0) {
				recovery_send_reset(client);
			} else {
				error("Setting auto-boot failed?!\n");
			}
		} else {
			error("Could not connect to device in recovery mode.\n");
		}
	}

	info("DONE\n");

	if (result == 0) {
		idevicerestore_progress(client, RESTORE_NUM_STEPS-1, 1.0);
	}

	return result;
}
コード例 #17
0
ファイル: restore.c プロジェクト: Darren1414/libimobiledevice
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;
}
コード例 #18
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;
}
コード例 #19
0
ファイル: tss.c プロジェクト: libimobiledevice/idevicerestore
int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t overrides, char **component_name)
{
	plist_t node = NULL;

	plist_t manifest_node = plist_dict_get_item(parameters, "Manifest");
	if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
		error("ERROR: %s: Unable to get restore manifest from parameters\n", __func__);
		return -1;
	}

	/* add tags indicating we want to get the Savage,Ticket */
	plist_dict_set_item(request, "@BBTicket", plist_new_bool(1));
	plist_dict_set_item(request, "@Savage,Ticket", plist_new_bool(1));

	/* add Savage,UID */
	node = plist_dict_get_item(parameters, "Savage,UID");
	if (!node) {
		error("ERROR: %s: Unable to find required Savage,UID in parameters\n", __func__);
		return -1;
	}
	plist_dict_set_item(request, "Savage,UID", plist_copy(node));
	node = NULL;

	/* add SEP */
	node = plist_access_path(manifest_node, 2, "SEP", "Digest");
	if (!node) {
		error("ERROR: Unable to get SEP digest from manifest\n");
		return -1;
	}
	plist_t dict = plist_new_dict();
	plist_dict_set_item(dict, "Digest", plist_copy(node));
	plist_dict_set_item(request, "SEP", dict);

	/* add Savage,PatchEpoch */
	node = plist_dict_get_item(parameters, "Savage,PatchEpoch");
	if (!node) {
		error("ERROR: %s: Unable to find required Savage,PatchEpoch in parameters\n", __func__);
		return -1;
	}
	plist_dict_set_item(request, "Savage,PatchEpoch", plist_copy(node));
	node = NULL;

	/* add Savage,ChipID */
	node = plist_dict_get_item(parameters, "Savage,ChipID");
	if (!node) {
		error("ERROR: %s: Unable to find required Savage,ChipID in parameters\n", __func__);
		return -1;
	}
	plist_dict_set_item(request, "Savage,ChipID", plist_copy(node));
	node = NULL;

	/* add Savage,AllowOfflineBoot */
	node = plist_dict_get_item(parameters, "Savage,AllowOfflineBoot");
	if (!node) {
		error("ERROR: %s: Unable to find required Savage,AllowOfflineBoot in parameters\n", __func__);
		return -1;
	}
	plist_dict_set_item(request, "Savage,AllowOfflineBoot", plist_copy(node));
	node = NULL;

	/* add Savage,ReadFWKey */
	node = plist_dict_get_item(parameters, "Savage,ReadFWKey");
	if (!node) {
		error("ERROR: %s: Unable to find required Savage,ReadFWKey in parameters\n", __func__);
		return -1;
	}
	plist_dict_set_item(request, "Savage,ReadFWKey", plist_copy(node));
	node = NULL;

	/* add Savage,ProductionMode */
	node = plist_dict_get_item(parameters, "Savage,ProductionMode");
	if (!node) {
		error("ERROR: %s: Unable to find required Savage,ProductionMode in parameters\n", __func__);
		return -1;
	}
	plist_dict_set_item(request, "Savage,ProductionMode", plist_copy(node));
	const char *comp_name = NULL;
	uint8_t isprod = 0;
	plist_get_bool_val(node, &isprod);
	node = NULL;

	/* get the right component name */
	comp_name = (isprod) ?  "Savage,B0-Prod-Patch" : "Savage,B0-Dev-Patch";
	node = plist_dict_get_item(parameters, "Savage,Revision");
	if (node && (plist_get_node_type(node) == PLIST_DATA)) {
		unsigned char *savage_rev = NULL;
		uint64_t savage_rev_len = 0;
		plist_get_data_val(node, (char**)&savage_rev, &savage_rev_len);
		if (savage_rev_len > 0) {
			if (((savage_rev[0] | 0x10) & 0xF0) == 0x30) {
				comp_name = (isprod) ? "Savage,B2-Prod-Patch" : "Savage,B2-Dev-Patch";
			} else if ((savage_rev[0] & 0xF0) == 0xA0) {
				comp_name = (isprod) ? "Savage,BA-Prod-Patch" : "Savage,BA-Dev-Patch";
			}
		}
		free(savage_rev);
	}

	/* add Savage,B?-*-Patch */
	node = plist_dict_get_item(manifest_node, comp_name);
	if (!node) {
		error("ERROR: Unable to get %s entry from manifest\n", comp_name);
		return -1;
	}
	dict = plist_copy(node);
	plist_dict_remove_item(dict, "Info");
	plist_dict_set_item(request, comp_name, dict);

	if (component_name) {
		*component_name = strdup(comp_name);
	}

	/* add Savage,Nonce */
	node = plist_dict_get_item(parameters, "Savage,Nonce");
	if (!node) {
		error("ERROR: %s: Unable to find required Savage,Nonce in parameters\n", __func__);
		return -1;
	}
	plist_dict_set_item(request, "Savage,Nonce", plist_copy(node));
	node = NULL;

	/* add Savage,ReadECKey */
	node = plist_dict_get_item(parameters, "Savage,ReadECKey");
	if (!node) {
		error("ERROR: %s: Unable to find required Savage,ReadECKey in parameters\n", __func__);
		return -1;
	}
	plist_dict_set_item(request, "Savage,ReadECKey", plist_copy(node));
	node = NULL;

	/* apply overrides */
	if (overrides) {
		plist_dict_merge(&request, overrides);
	}

	return 0;
}
コード例 #20
0
Real& Real::operator=(PList::Real& d)
{
    plist_free(_node);
    _node = plist_copy(d.GetPlist());
    return *this;
}
コード例 #21
0
/**
 * 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;
	} else {
		plist_free(apps_array);
	}

leave_unlock:
	instproxy_unlock(client);
	return res;
}
コード例 #22
0
ファイル: tss.c プロジェクト: libimobiledevice/idevicerestore
int tss_request_add_yonkers_tags(plist_t request, plist_t parameters, plist_t overrides, char **component_name)
{
	plist_t node = NULL;

	plist_t manifest_node = plist_dict_get_item(parameters, "Manifest");
	if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
		error("ERROR: %s: Unable to get restore manifest from parameters\n", __func__);
		return -1;
	}

	/* add tags indicating we want to get the Savage,Ticket */
	plist_dict_set_item(request, "@BBTicket", plist_new_bool(1));
	plist_dict_set_item(request, "@Yonkers,Ticket", plist_new_bool(1));

	/* add SEP */
	node = plist_access_path(manifest_node, 2, "SEP", "Digest");
	if (!node) {
		error("ERROR: Unable to get SEP digest from manifest\n");
		return -1;
	}
	plist_t dict = plist_new_dict();
	plist_dict_set_item(dict, "Digest", plist_copy(node));
	plist_dict_set_item(request, "SEP", dict);

	{
		static const char *keys[] = {"Yonkers,AllowOfflineBoot", "Yonkers,BoardID", "Yonkers,ChipID", "Yonkers,ECID", "Yonkers,Nonce", "Yonkers,PatchEpoch", "Yonkers,ProductionMode", "Yonkers,ReadECKey", "Yonkers,ReadFWKey", };
		int i;
		for (i = 0; i < (int)(sizeof(keys) / sizeof(keys[0])); ++i) {
			node = plist_dict_get_item(parameters, keys[i]);
			if (!node) {
				error("ERROR: %s: Unable to find required %s in parameters\n", __func__, keys[i]);
			}
			plist_dict_set_item(request, keys[i], plist_copy(node));
			node = NULL;
		}
	}

	char *comp_name = NULL;
	plist_t comp_node = NULL;
	uint8_t isprod = 1;
	uint64_t fabrevision = (uint64_t)-1;

	node = plist_dict_get_item(parameters, "Yonkers,ProductionMode");
	if (node && (plist_get_node_type(node) == PLIST_BOOLEAN)) {
		plist_get_bool_val(node, &isprod);
	}

	node = plist_dict_get_item(parameters, "Yonkers,FabRevision");
	if (node && (plist_get_node_type(node) == PLIST_UINT)) {
		plist_get_uint_val(node, &fabrevision);
	}

	plist_dict_iter iter = NULL;
	plist_dict_new_iter(manifest_node, &iter);
	while (iter) {
		node = NULL;
		comp_name = NULL;
		plist_dict_next_item(manifest_node, iter, &comp_name, &node);
		if (comp_name == NULL) {
			node = NULL;
			break;
		}
		if (strncmp(comp_name, "Yonkers,", 8) == 0) {
			int target_node = 1;
			plist_t sub_node;
			if ((sub_node = plist_dict_get_item(node, "EPRO")) != NULL && plist_get_node_type(sub_node) == PLIST_BOOLEAN) {
				uint8_t b = 0;
				plist_get_bool_val(sub_node, &b);
				target_node &= ((isprod) ? b : !b);
			}
			if ((sub_node = plist_dict_get_item(node, "FabRevision")) != NULL && plist_get_node_type(sub_node) == PLIST_UINT) {
				uint64_t v = 0;
				plist_get_uint_val(sub_node, &v);
				target_node &= (v == fabrevision);
			}
			if (target_node) {
				comp_node = node;
				break;
			}
		}
		free(comp_name);
	}
	free(iter);

	if (comp_name == NULL) {
		error("ERROR: No Yonkers node for %s/%lu\n", (isprod) ? "Production" : "Development", (unsigned long)fabrevision);
		return -1;
	}

	/* add Yonkers,SysTopPatch* */
	if (comp_node != NULL) {
		plist_t comp_dict = plist_copy(comp_node);
		plist_dict_remove_item(comp_dict, "Info");
		plist_dict_set_item(request, comp_name, comp_dict);
	}

	if (component_name) {
		*component_name = comp_name;
	} else {
		free(comp_name);
	}

	/* apply overrides */
	if (overrides) {
		plist_dict_merge(&request, overrides);
	}

	return 0;
}
コード例 #23
0
ファイル: tss.c プロジェクト: MephistoLa/bootsigned
plist_t tss_create_request(plist_t build_identity, uint64_t ecid, unsigned char* nonce, int nonce_size) {
	uint64_t unique_build_size = 0;
	char* unique_build_data = NULL;
	plist_t unique_build_node = plist_dict_get_item(build_identity, "UniqueBuildID");
	if (!unique_build_node || plist_get_node_type(unique_build_node) != PLIST_DATA) {
		error("ERROR: Unable to find UniqueBuildID node\n");
		return NULL;
	}
	plist_get_data_val(unique_build_node, &unique_build_data, &unique_build_size);

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

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

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

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

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

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

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

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

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

	if (idevicerestore_debug) {
		debug_plist(tss_request);
	}

	return tss_request;
}
コード例 #24
0
int activate_fetch_record(lockdownd_client_t client, plist_t* record) {
	int size = 0;
	char* request = NULL;
	struct curl_httppost* post = NULL;
	struct curl_httppost* last = NULL;
	activate_response* response = NULL;

	char* imei = NULL;
	char* imsi = NULL;
	char* iccid = NULL;
	char* serial_number = NULL;
	char* activation_info = NULL;

	plist_t imei_node = NULL;
	plist_t imsi_node = NULL;
	plist_t iccid_node = NULL;
	plist_t serial_number_node = NULL;
	plist_t activation_info_node = NULL;

	char* device_class = NULL;
	plist_t device_class_node = NULL;
	lockdownd_get_value(client, NULL, "DeviceClass", &device_class_node);
	if (!device_class_node || plist_get_node_type(device_class_node) != PLIST_STRING) {
		fprintf(stderr, "Unable to get DeviceClass from lockdownd\n");
		return -1;
	}
	plist_get_string_val(device_class_node, &device_class);
	plist_free(device_class_node);

	if (!strcmp(device_class, "iPhone")) {
		lockdownd_get_value(client, NULL, "IntegratedCircuitCardIdentity", &iccid_node);
		if (!iccid_node || plist_get_node_type(iccid_node) != PLIST_STRING) {
			fprintf(stderr, "Unable to get ICCID from lockdownd\n");
			return -1;
		}
		plist_get_string_val(iccid_node, &iccid);
		plist_free(iccid_node);

		lockdownd_get_value(client, NULL, "InternationalMobileEquipmentIdentity", &imei_node);
		if (!imei_node || plist_get_node_type(imei_node) != PLIST_STRING) {
			fprintf(stderr, "Unable to get IMEI from lockdownd\n");
			return -1;
		}
		plist_get_string_val(imei_node, &imei);
		plist_free(imei_node);

		lockdownd_get_value(client, NULL, "InternationalMobileSubscriberIdentity", &imsi_node);
		if (!imsi_node || plist_get_node_type(imsi_node) != PLIST_STRING) {
			fprintf(stderr, "Unable to get IMSI from lockdownd\n");
			return -1;
		}
		plist_get_string_val(imsi_node, &imsi);
		plist_free(imsi_node);
	}

	lockdownd_get_value(client, NULL, "SerialNumber", &serial_number_node);
	if (!serial_number_node || plist_get_node_type(serial_number_node) != PLIST_STRING) {
		fprintf(stderr, "Unable to get SerialNumber from lockdownd\n");
		return -1;
	}
	plist_get_string_val(serial_number_node, &serial_number);
	plist_free(serial_number_node);

	lockdownd_get_value(client, NULL, "ActivationInfo", &activation_info_node);
	int type = plist_get_node_type(activation_info_node);
	if (!activation_info_node || plist_get_node_type(activation_info_node) != PLIST_DICT) {
		fprintf(stderr, "Unable to get ActivationInfo from lockdownd\n");
		return -1;
	}
	//plist_get_string_val(activation_info_node, &activation_info);

	uint32_t activation_info_size = 0;
	char* activation_info_data = NULL;
	plist_to_xml(activation_info_node, &activation_info_data, &activation_info_size);
	plist_free(activation_info_node);
	printf("%s\n\n", activation_info_data);

	char* activation_info_start = strstr(activation_info_data, "<dict>");
	if (activation_info_start == NULL) {
		fprintf(stderr, "Unable to locate beginning of ActivationInfo\n");
		return -1;
	}

	char* activation_info_stop = strstr(activation_info_data, "</dict>");
	if (activation_info_stop == NULL) {
		fprintf(stderr, "Unable to locate end of ActivationInfo\n");
		return -1;
	}

	activation_info_stop += strlen("</dict>");
	activation_info_size = activation_info_stop - activation_info_start;
	activation_info = malloc(activation_info_size + 1);
	memset(activation_info, '\0', activation_info_size + 1);
	memcpy(activation_info, activation_info_start, activation_info_size);
	free(activation_info_data);

	curl_global_init(CURL_GLOBAL_ALL);
	CURL* handle = curl_easy_init();
	if (handle == NULL) {
		fprintf(stderr, "Unable to initialize libcurl\n");
		curl_global_cleanup();
		return -1;
	}

	curl_formadd(&post, &last, CURLFORM_COPYNAME, "machineName", CURLFORM_COPYCONTENTS, "linux", CURLFORM_END);
	curl_formadd(&post, &last, CURLFORM_COPYNAME, "InStoreActivation", CURLFORM_COPYCONTENTS, "false", CURLFORM_END);
	if (imei != NULL) {
		curl_formadd(&post, &last, CURLFORM_COPYNAME, "IMEI", CURLFORM_COPYCONTENTS, imei, CURLFORM_END);
		free(imei);
	}

	if (imsi != NULL) {
		curl_formadd(&post, &last, CURLFORM_COPYNAME, "IMSI", CURLFORM_COPYCONTENTS, imsi, CURLFORM_END);
		free(imsi);
	}

	if (iccid != NULL) {
		curl_formadd(&post, &last, CURLFORM_COPYNAME, "ICCID", CURLFORM_COPYCONTENTS, iccid, CURLFORM_END);
		free(iccid);
	}

	if (serial_number != NULL) {
		curl_formadd(&post, &last, CURLFORM_COPYNAME, "AppleSerialNumber", CURLFORM_COPYCONTENTS, serial_number, CURLFORM_END);
		free(serial_number);
	}

	if (activation_info != NULL) {
		curl_formadd(&post, &last, CURLFORM_COPYNAME, "activation-info", CURLFORM_COPYCONTENTS, activation_info, CURLFORM_END);
		free(activation_info);
	}

	struct curl_slist* header = NULL;
	header = curl_slist_append(header, "X-Apple-Tz: -14400");
	header = curl_slist_append(header, "X-Apple-Store-Front: 143441-1");

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

	response->length = 0;
	response->content = malloc(1);

	curl_easy_setopt(handle, CURLOPT_HTTPPOST, post);
	curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header);
	curl_easy_setopt(handle, CURLOPT_WRITEDATA, response);
	curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, &activate_write_callback);
	curl_easy_setopt(handle, CURLOPT_USERAGENT, "iTunes/9.1 (Macintosh; U; Intel Mac OS X 10.5.6)");
	curl_easy_setopt(handle, CURLOPT_URL, "https://albert.apple.com/WebObjects/ALUnbrick.woa/wa/deviceActivation");

	curl_easy_perform(handle);
	curl_slist_free_all(header);
	curl_easy_cleanup(handle);
	curl_global_cleanup();

	uint32_t ticket_size = response->length;
	char* ticket_data = response->content;

	char* ticket_start = strstr(ticket_data, "<plist");
	if (ticket_start == NULL) {
		fprintf(stderr, "Unable to locate beginning of ActivationInfo\n");
		return -1;
	}

	char* ticket_stop = strstr(ticket_data, "</plist>");
	if (ticket_stop == NULL) {
		fprintf(stderr, "Unable to locate end of ActivationInfo\n");
		return -1;
	}

	ticket_stop += strlen("</plist>");
	ticket_size = ticket_stop - ticket_start;
	char* ticket = malloc(ticket_size + 1);
	memset(ticket, '\0', ticket_size + 1);
	memcpy(ticket, ticket_start, ticket_size);
	//free(ticket_data);

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

	plist_t ticket_dict = NULL;
	plist_from_xml(ticket, ticket_size, &ticket_dict);
	if (ticket_dict == NULL) {
		printf("Unable to convert activation ticket into plist\n");
		return -1;
	}

	plist_t iphone_activation_node = plist_dict_get_item(ticket_dict, "iphone-activation");
	if (!iphone_activation_node) {
		iphone_activation_node = plist_dict_get_item(ticket_dict, "device-activation");
		if (!iphone_activation_node) {
			printf("Unable to find device activation node\n");
			return -1;
		}
	}

	plist_t activation_record = plist_dict_get_item(iphone_activation_node, "activation-record");
	if (!activation_record) {
		printf("Unable to find activation record node");
		return -1;
	}

	*record = plist_copy(activation_record);

	//free(response->content);
	//free(response);
	//free(request);
	return 0;
}
コード例 #25
0
ファイル: tss.c プロジェクト: zweed4u/idevicerestore
int tss_request_add_ap_tags(plist_t request, plist_t parameters, plist_t overrides) {
	/* loop over components from build manifest */
	plist_t manifest_node = plist_dict_get_item(parameters, "Manifest");
	if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
		error("ERROR: Unable to find restore manifest\n");
		return -1;
	}

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

		/* do not populate BaseBandFirmware, only in basebaseband request */
		if ((strcmp(key, "BasebandFirmware") == 0)) {
			free(key);
			continue;
		}

		/* FIXME: only used with diagnostics firmware */
		if (strcmp(key, "Diags") == 0) {
			free(key);
			continue;
		}

		/* copy this entry */
		plist_t tss_entry = plist_copy(manifest_entry);

		/* remove obsolete Info node */
		plist_dict_remove_item(tss_entry, "Info");

		/* handle RestoreRequestRules */
		plist_t rules = plist_access_path(manifest_entry, 2, "Info", "RestoreRequestRules");
		if (rules) {
			debug("DEBUG: Applying restore request rules for entry %s\n", key);
			tss_entry_apply_restore_request_rules(tss_entry, parameters, rules);
		}

		/* Make sure we have a Digest key for Trusted items even if empty */
		plist_t node = plist_dict_get_item(manifest_entry, "Trusted");
		if (node && plist_get_node_type(node) == PLIST_BOOLEAN) {
			uint8_t trusted;
			plist_get_bool_val(node, &trusted);
			if (trusted && !plist_access_path(manifest_entry, 1, "Digest")) {
				debug("DEBUG: No Digest data, using empty value for entry %s\n", key);
				plist_dict_set_item(tss_entry, "Digest", plist_new_data(NULL, 0));
			}
		}

		/* finally add entry to request */
		plist_dict_set_item(request, key, tss_entry);

		free(key);
	}
	free(iter);

	/* apply overrides */
	if (overrides) {
		plist_dict_merge(&request, overrides);
	}

	return 0;
}
コード例 #26
0
int main(int argc, char* argv[]) {
	int opt = 0;
	int optindex = 0;
	char* ipsw = NULL;
	char* uuid = NULL;
	int tss_enabled = 0;
	int shsh_only = 0;
	char* shsh_dir = NULL;
	use_apple_server=1;

	// 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, "dhcesxtpi:u:", 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 's':
			use_apple_server=0;
			break;

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

		case 'i':
			if (optarg) {
				char* tail = NULL;
				client->ecid = strtoull(optarg, &tail, 16);
				if (tail && (tail[0] != '\0')) {
					client->ecid = 0;
				}
				if (client->ecid == 0) {
					error("ERROR: Could not parse ECID from '%s'\n", optarg);
					return -1;
				}
			}
			break;

		case 'u':
			uuid = optarg;
			break;

		case 't':
			shsh_only = 1;
			break;

		case 'p':
			client->flags |= FLAG_PWN;
			break;

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

	if (((argc-optind) == 1) || (client->flags & FLAG_PWN)) {
		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;

	// update version data (from cache, or apple if too old)
	load_version_data(client);

	// 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);

	if (client->mode->index == MODE_WTF) {
		int cpid = 0;

		if (dfu_client_new(client) != 0) {
			error("ERROR: Could not open device in WTF mode\n");
			return -1;
		}
		if ((dfu_get_cpid(client, &cpid) < 0) || (cpid == 0)) { 
			error("ERROR: Could not get CPID for WTF mode device\n");
			dfu_client_free(client);
			return -1;
		}

		char* s_wtfurl = NULL;
		plist_t wtfurl = plist_access_path(client->version_data, 7, "MobileDeviceSoftwareVersionsByVersion", "5", "RecoverySoftwareVersions", "WTF", "304218112", "5", "FirmwareURL");
		if (wtfurl && (plist_get_node_type(wtfurl) == PLIST_STRING)) {
			plist_get_string_val(wtfurl, &s_wtfurl);
		}
		if (!s_wtfurl) {
			info("Using hardcoded x12220000_5_Recovery.ipsw URL\n");
			s_wtfurl = strdup("http://appldnld.apple.com.edgesuite.net/content.info.apple.com/iPhone/061-6618.20090617.Xse7Y/x12220000_5_Recovery.ipsw");
		}

		// make a local file name
		char* fnpart = strrchr(s_wtfurl, '/');
		if (!fnpart) {
			fnpart = "x12220000_5_Recovery.ipsw";
		} else {
			fnpart++;
		}
		struct stat fst;
		char wtfipsw[256];
		sprintf(wtfipsw, "cache/%s", fnpart);
		if (stat(wtfipsw, &fst) != 0) {
			__mkdir("cache", 0755);
			download_to_file(s_wtfurl, wtfipsw);
		}

		char wtfname[256];
		sprintf(wtfname, "Firmware/dfu/WTF.s5l%04xxall.RELEASE.dfu", cpid);
		char* wtftmp = NULL;
		uint32_t wtfsize = 0;
		ipsw_extract_to_memory(wtfipsw, wtfname, &wtftmp, &wtfsize);
		if (!wtftmp) {
			error("ERROR: Could not extract WTF\n");
		} else {
			if (dfu_send_buffer(client, wtftmp, wtfsize) != 0) {
				error("ERROR: Could not send WTF...\n");
			}
		}
		dfu_client_free(client);

		sleep(1);

		free(wtftmp);
		client->mode = &idevicerestore_modes[MODE_DFU];
	}

	// 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->flags & FLAG_PWN) && (client->mode->index != MODE_DFU)) {
		error("ERROR: you need to put your device into DFU mode to pwn it.\n");
		return -1;
	}

	if (client->flags & FLAG_PWN) {
		recovery_client_free(client);

		info("connecting to DFU\n");
		if (dfu_client_new(client) < 0) {
			return -1;
		}
		info("exploiting with limera1n...\n");
		// TODO: check for non-limera1n device and fail
		if (limera1n_exploit(client->device, client->dfu->client) != 0) {
			error("ERROR: limera1n exploit failed\n");
			dfu_client_free(client);
			return -1;
		}
		dfu_client_free(client);
		info("Device should be in pwned DFU state now.\n");

		return 0;
	}

	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;
	if (client->flags & FLAG_CUSTOM) {
		info("Extracting Restore.plist from IPSW\n");
		if (ipsw_extract_restore_plist(ipsw, &buildmanifest) < 0) {
			error("ERROR: Unable to extract Restore.plist from %s\n", ipsw);
			return -1;
		}
	} else {
		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;
		}
	}

	/* check if device type is supported by the given build manifest */
	if (build_manifest_check_compatibility(buildmanifest, client->device->product) < 0) {
		error("ERROR: could not make sure this firmware is suitable for the current device. refusing to continue.\n");
		return -1;
	}

	/* print iOS information from the manifest */
	build_manifest_get_version_information(buildmanifest, &client->version, &client->build);

	info("Product Version: %s\n", client->version);
	info("Product Build: %s\n", client->build);

	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_CUSTOM) {
		build_identity = plist_new_dict();
		{
			plist_t node;
			plist_t comp;
			plist_t info;
			plist_t manifest;

			info = plist_new_dict();
			plist_dict_insert_item(info, "RestoreBehavior", plist_new_string((client->flags & FLAG_ERASE) ? "Erase" : "Update"));
			plist_dict_insert_item(info, "Variant", plist_new_string((client->flags & FLAG_ERASE) ? "Customer Erase Install (IPSW)" : "Customer Upgrade Install (IPSW)"));
			plist_dict_insert_item(build_identity, "Info", info);

			manifest = plist_new_dict();

			char tmpstr[256];
			char p_all_flash[128];
			char lcmodel[8];
			strcpy(lcmodel, client->device->model);
			int x = 0;
			while (lcmodel[x]) {
				lcmodel[x] = tolower(lcmodel[x]);
				x++;
			}

			sprintf(p_all_flash, "Firmware/all_flash/all_flash.%s.%s", lcmodel, "production");
			strcpy(tmpstr, p_all_flash);
			strcat(tmpstr, "/manifest");

			// get all_flash file manifest
			char *files[16];
			char *fmanifest = NULL;
			uint32_t msize = 0;
			if (ipsw_extract_to_memory(ipsw, tmpstr, &fmanifest, &msize) < 0) {
				error("ERROR: could not extract %s from IPSW\n", tmpstr);
				return -1;
			}

			char *tok = strtok(fmanifest, "\r\n");
			int fc = 0;
			while (tok) {
				files[fc++] = strdup(tok);
				if (fc >= 16) {
					break;
				}
				tok = strtok(NULL, "\r\n");
			}
			free(fmanifest);

			for (x = 0; x < fc; x++) {
				info = plist_new_dict();
				strcpy(tmpstr, p_all_flash);
				strcat(tmpstr, "/");
				strcat(tmpstr, files[x]);
				plist_dict_insert_item(info, "Path", plist_new_string(tmpstr));
				comp = plist_new_dict();
				plist_dict_insert_item(comp, "Info", info);
				const char* compname = get_component_name(files[x]);
				if (compname) {
					plist_dict_insert_item(manifest, compname, comp);
					if (!strncmp(files[x], "DeviceTree", 10)) {
						plist_dict_insert_item(manifest, "RestoreDeviceTree", plist_copy(comp));
					}
				} else {
					error("WARNING: unhandled component %s\n", files[x]);
					plist_free(comp);
				}
				free(files[x]);
				files[x] = NULL;
			}

			// add iBSS
			sprintf(tmpstr, "Firmware/dfu/iBSS.%s.%s.dfu", lcmodel, "RELEASE");
			info = plist_new_dict();
			plist_dict_insert_item(info, "Path", plist_new_string(tmpstr));
			comp = plist_new_dict();
			plist_dict_insert_item(comp, "Info", info);
			plist_dict_insert_item(manifest, "iBSS", comp);

			// add iBEC
			sprintf(tmpstr, "Firmware/dfu/iBEC.%s.%s.dfu", lcmodel, "RELEASE");
			info = plist_new_dict();
			plist_dict_insert_item(info, "Path", plist_new_string(tmpstr));
			comp = plist_new_dict();
			plist_dict_insert_item(comp, "Info", info);
			plist_dict_insert_item(manifest, "iBEC", comp);

			// add kernel cache
			node = plist_dict_get_item(buildmanifest, "KernelCachesByTarget");
			if (node && (plist_get_node_type(node) == PLIST_DICT)) {
				char tt[4];
				strncpy(tt, lcmodel, 3);
				tt[3] = 0;
				plist_t kdict = plist_dict_get_item(node, tt);
				if (kdict && (plist_get_node_type(kdict) == PLIST_DICT)) {
					plist_t kc = plist_dict_get_item(kdict, "Release");
					if (kc && (plist_get_node_type(kc) == PLIST_STRING)) {
						info = plist_new_dict();
						plist_dict_insert_item(info, "Path", plist_copy(kc));
						comp = plist_new_dict();
						plist_dict_insert_item(comp, "Info", info);
						plist_dict_insert_item(manifest, "KernelCache", comp);
						plist_dict_insert_item(manifest, "RestoreKernelCache", plist_copy(comp));

					}
				}
			}

			// add ramdisk
			node = plist_dict_get_item(buildmanifest, "RestoreRamDisks");
			if (node && (plist_get_node_type(node) == PLIST_DICT)) {
				plist_t rd = plist_dict_get_item(node, (client->flags & FLAG_ERASE) ? "User" : "Update");
				if (rd && (plist_get_node_type(rd) == PLIST_STRING)) {
					info = plist_new_dict();
					plist_dict_insert_item(info, "Path", plist_copy(rd));
					comp = plist_new_dict();
					plist_dict_insert_item(comp, "Info", info);
					plist_dict_insert_item(manifest, "RestoreRamDisk", comp);
				}
			}

			// add OS filesystem
			node = plist_dict_get_item(buildmanifest, "SystemRestoreImages");
			if (!node) {
				error("ERROR: missing SystemRestoreImages in Restore.plist\n");
			}
			plist_t os = plist_dict_get_item(node, "User");
			if (!os) {
				error("ERROR: missing filesystem in Restore.plist\n");
			} else {
				info = plist_new_dict();
				plist_dict_insert_item(info, "Path", plist_copy(os));
				comp = plist_new_dict();
				plist_dict_insert_item(comp, "Info", info);
				plist_dict_insert_item(manifest, "OS", comp);
			}

			// finally add manifest
			plist_dict_insert_item(build_identity, "Manifest", manifest);
		}
	} else 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 " FMT_qu "\n", (long long unsigned int)client->ecid);

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

	if (shsh_only) {
		if (!tss_enabled) {
			info("This device does not require a TSS record");
			return 0;
		}
		if (!client->tss) {
			error("ERROR: could not fetch TSS record");
			plist_free(buildmanifest);
			return -1;
		} else {
			char *bin = NULL;
			uint32_t blen = 0;
			plist_to_bin(client->tss, &bin, &blen);
			if (bin) {
				char zfn[512];
				sprintf(zfn, "shsh/" FMT_qu "-%s-%s.shsh", (long long int)client->ecid, client->device->product, client->version);
				__mkdir("shsh", 0755);
				struct stat fst;
				if (stat(zfn, &fst) != 0) {
					gzFile zf = gzopen(zfn, "wb");
					gzwrite(zf, bin, blen);
					gzclose(zf);
					info("SHSH saved to '%s'\n", zfn);
				} else {
					info("SHSH '%s' already present.\n", zfn);
				}
				free(bin);
			} else {
				error("ERROR: could not get TSS record data\n");
			}
			plist_free(client->tss);
			plist_free(buildmanifest);
			return 0;
		}
	}

	/* 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;
	}

	if ((tss_enabled) && client->tss) {
		/* fix empty dicts */
		fixup_tss(client->tss);
	}

	// 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) {
		recovery_client_free(client);
		if (client->flags & FLAG_CUSTOM) {
			info("connecting to DFU\n");
			if (dfu_client_new(client) < 0) {
				return -1;
			}
			info("exploiting with limera1n\n");
			// TODO: check for non-limera1n device and fail
			if (limera1n_exploit(client->device, client->dfu->client) != 0) {
				error("ERROR: limera1n exploit failed\n");
				dfu_client_free(client);
				return -1;
			}
			dfu_client_free(client);
			info("exploited\n");
		}
		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 (client->mode->index == MODE_DFU) {
		client->mode = &idevicerestore_modes[MODE_RECOVERY];
	} else {
		/* now we load the iBEC */
		if (recovery_send_ibec(client, build_identity) < 0) {
			error("ERROR: Unable to send iBEC\n");
			return -1;
		}
		recovery_client_free(client);
	
		/* this must be long enough to allow the device to run the iBEC */
		/* FIXME: Probably better to detect if the device is back then */
		sleep(7);
	}

	if (client->build[0] > '8') {
		// we need another tss request with nonce.
		unsigned char* nonce = NULL;
		int nonce_size = 0;
		int nonce_changed = 0;
		if (get_nonce(client, &nonce, &nonce_size) < 0) {
			error("ERROR: Unable to get nonce from device!\n");
			recovery_send_reset(client);
			return -1;
		}

		if (!client->nonce || (nonce_size != client->nonce_size) || (memcmp(nonce, client->nonce, nonce_size) != 0)) {
			nonce_changed = 1;
			if (client->nonce) {
				free(client->nonce);
			}
			client->nonce = nonce;
			client->nonce_size = nonce_size;
		} else {
			free(nonce);
		}

		info("Nonce: ");
		int i;
		for (i = 0; i < client->nonce_size; i++) {
			info("%02x ", client->nonce[i]);
		}
		info("\n");

		if (nonce_changed && !(client->flags & FLAG_CUSTOM)) {
			// Welcome iOS5. We have to re-request the TSS with our nonce.
			plist_free(client->tss);
			if (get_shsh_blobs(client, client->ecid, client->nonce, client->nonce_size, build_identity, &client->tss) < 0) {
				error("ERROR: Unable to get SHSH blobs for this device\n");
				return -1;
			}
			if (!client->tss) {
				error("ERROR: can't continue without TSS\n");
				return -1;
			}
			fixup_tss(client->tss);
		}
	}

	// now finally do the magic to put the device into restore mode
	if (client->mode->index == MODE_RECOVERY) {
		if (client->srnm == NULL) {
			error("ERROR: could not retrieve device serial number. Can't continue.\n");
			return -1;
		}
		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("About to restore 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;
}