summaryrefslogtreecommitdiffstats
path: root/tools/idevicebackup4.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/idevicebackup4.c')
-rw-r--r--tools/idevicebackup4.c388
1 files changed, 45 insertions, 343 deletions
diff --git a/tools/idevicebackup4.c b/tools/idevicebackup4.c
index a44abb6..8c4fe79 100644
--- a/tools/idevicebackup4.c
+++ b/tools/idevicebackup4.c
@@ -54,6 +54,8 @@ static int quit_flag = 0;
54enum cmd_mode { 54enum cmd_mode {
55 CMD_BACKUP, 55 CMD_BACKUP,
56 CMD_RESTORE, 56 CMD_RESTORE,
57 CMD_INFO,
58 CMD_LIST,
57 CMD_LEAVE 59 CMD_LEAVE
58}; 60};
59 61
@@ -1140,6 +1142,12 @@ int main(int argc, char *argv[])
1140 else if (!strcmp(argv[i], "restore")) { 1142 else if (!strcmp(argv[i], "restore")) {
1141 cmd = CMD_RESTORE; 1143 cmd = CMD_RESTORE;
1142 } 1144 }
1145 else if (!strcmp(argv[i], "info")) {
1146 cmd = CMD_INFO;
1147 }
1148 else if (!strcmp(argv[i], "list")) {
1149 cmd = CMD_LIST;
1150 }
1143 else if (backup_directory == NULL) { 1151 else if (backup_directory == NULL) {
1144 backup_directory = argv[i]; 1152 backup_directory = argv[i];
1145 } 1153 }
@@ -1369,12 +1377,6 @@ checkpoint:
1369 plist_free(info_plist); 1377 plist_free(info_plist);
1370 info_plist = NULL; 1378 info_plist = NULL;
1371 1379
1372 /* close down the lockdown connection as it is no longer needed */
1373 if (client) {
1374 lockdownd_client_free(client);
1375 client = NULL;
1376 }
1377
1378 /* create Status.plist with failed status for now */ 1380 /* create Status.plist with failed status for now */
1379 //mobilebackup_write_status(backup_directory, 0); 1381 //mobilebackup_write_status(backup_directory, 0);
1380 1382
@@ -1398,7 +1400,44 @@ checkpoint:
1398 } 1400 }
1399 break; 1401 break;
1400 } 1402 }
1403 break;
1404 case CMD_RESTORE:
1405 /* TODO: verify battery on AC enough battery remaining */
1406 printf("Starting Restore...\n");
1407
1408 plist_t opts = plist_new_dict();
1409 plist_dict_insert_item(opts, "shouldRestoreSystemFiles", plist_new_bool(0));
1410 err = mobilebackup2_send_request(mobilebackup2, "Restore", uuid, uuid, opts);
1411 plist_free(opts);
1412 if (err != MOBILEBACKUP2_E_SUCCESS) {
1413 cmd = CMD_LEAVE;
1414 }
1415 break;
1416 case CMD_INFO:
1417 printf("Requesting backup info from device...\n");
1418 err = mobilebackup2_send_request(mobilebackup2, "Info", uuid, NULL, NULL);
1419 if (err != MOBILEBACKUP2_E_SUCCESS) {
1420 cmd = CMD_LEAVE;
1421 }
1422 break;
1423 case CMD_LIST:
1424 printf("Requesting backup list from device...\n");
1425 err = mobilebackup2_send_request(mobilebackup2, "List", uuid, NULL, NULL);
1426 if (err != MOBILEBACKUP2_E_SUCCESS) {
1427 cmd = CMD_LEAVE;
1428 }
1429 break;
1430 default:
1431 break;
1432 }
1401 1433
1434 /* close down the lockdown connection as it is no longer needed */
1435 if (client) {
1436 lockdownd_client_free(client);
1437 client = NULL;
1438 }
1439
1440 if (cmd != CMD_LEAVE) {
1402 /* reset backup status */ 1441 /* reset backup status */
1403 int backup_ok = 0; 1442 int backup_ok = 0;
1404 plist_t message = NULL; 1443 plist_t message = NULL;
@@ -1769,343 +1808,6 @@ files_out:
1769 } else { 1808 } else {
1770 printf("Backup Failed.\n"); 1809 printf("Backup Failed.\n");
1771 } 1810 }
1772
1773 break;
1774 case CMD_RESTORE:
1775 /* close down the lockdown connection as it is no longer needed */
1776 if (client) {
1777 lockdownd_client_free(client);
1778 client = NULL;
1779 }
1780
1781 /* TODO: verify battery on AC enough battery remaining */
1782
1783 /* verify if Status.plist says we read from an successful backup */
1784#if 0
1785 if (mobilebackup_read_status(backup_directory) <= 0) {
1786 printf("ERROR: Cannot ensure we restore from a successful backup. Aborting.\n");
1787 break;
1788 }
1789 /* now make sure backup integrity is ok! verify all files */
1790 printf("Reading existing Manifest.\n");
1791 plist_read_from_filename(&manifest_plist, manifest_path);
1792 if (!manifest_plist) {
1793 printf("Could not read Manifest.plist. Aborting.\n");
1794 break;
1795 }
1796
1797 printf("Verifying backup integrity, please wait.\n");
1798 char *bin = NULL;
1799 uint64_t binsize = 0;
1800 node = plist_dict_get_item(manifest_plist, "Data");
1801 if (!node || (plist_get_node_type(node) != PLIST_DATA)) {
1802 printf("Could not read Data key from Manifest.plist!\n");
1803 break;
1804 }
1805 plist_get_data_val(node, &bin, &binsize);
1806 plist_t backup_data = NULL;
1807 if (bin) {
1808 char *auth_ver = NULL;
1809 unsigned char *auth_sig = NULL;
1810 uint64_t auth_sig_len = 0;
1811 /* verify AuthSignature */
1812 node = plist_dict_get_item(manifest_plist, "AuthVersion");
1813 plist_get_string_val(node, &auth_ver);
1814 if (auth_ver && (strcmp(auth_ver, "2.0") == 0)) {
1815 node = plist_dict_get_item(manifest_plist, "AuthSignature");
1816 if (node && (plist_get_node_type(node) == PLIST_DATA)) {
1817 plist_get_data_val(node, (char**)&auth_sig, &auth_sig_len);
1818 }
1819 if (auth_sig && (auth_sig_len == 20)) {
1820 /* calculate the sha1, then compare */
1821 unsigned char data_sha1[20];
1822 sha1_of_data(bin, binsize, data_sha1);
1823 if (compare_hash(auth_sig, data_sha1, 20)) {
1824 printf("AuthSignature is valid\n");
1825 } else {
1826 printf("ERROR: AuthSignature is NOT VALID\n");
1827 }
1828 } else {
1829 printf("Could not get AuthSignature from manifest!\n");
1830 }
1831 g_free(auth_sig);
1832 } else if (auth_ver) {
1833 printf("Unknown AuthVersion '%s', cannot verify AuthSignature\n", auth_ver);
1834 }
1835 plist_from_bin(bin, (uint32_t)binsize, &backup_data);
1836 g_free(bin);
1837 }
1838 if (!backup_data) {
1839 printf("Could not read plist from Manifest.plist Data key!\n");
1840 break;
1841 }
1842 plist_t files = plist_dict_get_item(backup_data, "Files");
1843 if (files && (plist_get_node_type(files) == PLIST_DICT)) {
1844 plist_dict_iter iter = NULL;
1845 plist_dict_new_iter(files, &iter);
1846 if (iter) {
1847 /* loop over Files entries in Manifest data plist */
1848 char *hash = NULL;
1849 int file_ok = 0;
1850 int total_files = plist_dict_get_size(files);
1851 int cur_file = 1;
1852 node = NULL;
1853 plist_dict_next_item(files, iter, &hash, &node);
1854 while (node) {
1855 printf("Verifying file %d/%d (%d%%) \r", cur_file, total_files, (cur_file*100/total_files));
1856 cur_file++;
1857 /* make sure both .mddata/.mdinfo files are available for each entry */
1858 file_ok = mobilebackup_check_file_integrity(backup_directory, hash, node);
1859 node = NULL;
1860 free(hash);
1861 hash = NULL;
1862 if (!file_ok) {
1863 break;
1864 }
1865 plist_dict_next_item(files, iter, &hash, &node);
1866 }
1867 printf("\n");
1868 free(iter);
1869 if (!file_ok) {
1870 plist_free(backup_data);
1871 break;
1872 }
1873 printf("All backup files appear to be valid\n");
1874 }
1875 }
1876
1877 printf("Requesting restore from device...\n");
1878
1879 /* request restore from device with manifest (BackupMessageRestoreMigrate) */
1880 int restore_flags = MB_RESTORE_NOTIFY_SPRINGBOARD | MB_RESTORE_PRESERVE_SETTINGS | MB_RESTORE_PRESERVE_CAMERA_ROLL;
1881 err = mobilebackup_request_restore(mobilebackup, manifest_plist, restore_flags, "1.6");
1882 if (err != MOBILEBACKUP_E_SUCCESS) {
1883 if (err == MOBILEBACKUP_E_BAD_VERSION) {
1884 printf("ERROR: Could not start restore process: backup protocol version mismatch!\n");
1885 } else if (err == MOBILEBACKUP_E_REPLY_NOT_OK) {
1886 printf("ERROR: Could not start restore process: device refused to start the restore process.\n");
1887 } else {
1888 printf("ERROR: Could not start restore process: unspecified error occured (%d)\n", err);
1889 }
1890 plist_free(backup_data);
1891 break;
1892 }
1893
1894 printf("Entered restore mode.\n");
1895
1896 int restore_ok = 0;
1897
1898 if (files && (plist_get_node_type(files) == PLIST_DICT)) {
1899 plist_dict_iter iter = NULL;
1900 plist_dict_new_iter(files, &iter);
1901 if (iter) {
1902 /* loop over Files entries in Manifest data plist */
1903 char *hash = NULL;
1904 plist_t file_info = NULL;
1905 char *file_info_path = NULL;
1906 int total_files = plist_dict_get_size(files);
1907 int cur_file = 0;
1908 uint64_t file_offset = 0;
1909 uint8_t is_encrypted = 0;
1910 plist_t tmp_node = NULL;
1911 plist_t file_path_node = NULL;
1912 plist_t send_file_node = NULL;
1913 node = NULL;
1914 plist_dict_next_item(files, iter, &hash, &node);
1915 while (node) {
1916 /* TODO: read mddata/mdinfo files and send to device using DLSendFile */
1917 file_info_path = mobilebackup_build_path(backup_directory, hash, ".mdinfo");
1918 plist_read_from_filename(&file_info, file_info_path);
1919
1920 /* get encryption state */
1921 tmp_node = plist_dict_get_item(file_info, "IsEncrypted");
1922 plist_get_bool_val(tmp_node, &is_encrypted);
1923 tmp_node = NULL;
1924
1925 /* get real file path from metadata */
1926 tmp_node = plist_dict_get_item(file_info, "Metadata");
1927 plist_get_data_val(tmp_node, &buffer, &length);
1928 tmp_node = NULL;
1929 plist_from_bin(buffer, length, &tmp_node);
1930 file_path_node = plist_dict_get_item(tmp_node, "Path");
1931 plist_get_string_val(file_path_node, &file_path);
1932
1933 printf("Restoring file %s %d/%d (%d%%)... ", file_path, cur_file, total_files, (cur_file*100/total_files));
1934
1935 /* add additional device link file information keys */
1936 plist_dict_insert_item(file_info, "DLFileAttributesKey", plist_copy(node));
1937 plist_dict_insert_item(file_info, "DLFileSource", plist_new_string(file_info_path));
1938 plist_dict_insert_item(file_info, "DLFileDest", plist_new_string("/tmp/RestoreFile.plist"));
1939 plist_dict_insert_item(file_info, "DLFileIsEncrypted", plist_new_bool(is_encrypted));
1940 plist_dict_insert_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset));
1941 plist_dict_insert_item(file_info, "DLFileStatusKey", plist_new_uint(file_status));
1942
1943 /* read data from file */
1944 free(file_info_path);
1945 file_info_path = mobilebackup_build_path(backup_directory, hash, ".mddata");
1946 buffer_read_from_filename(file_info_path, &buffer, &length);
1947 free(file_info_path);
1948
1949 /* send DLSendFile messages */
1950 file_offset = 0;
1951 do {
1952 if ((length-file_offset) <= 8192)
1953 file_status = DEVICE_LINK_FILE_STATUS_LAST_HUNK;
1954 else
1955 file_status = DEVICE_LINK_FILE_STATUS_HUNK;
1956
1957 plist_dict_remove_item(file_info, "DLFileOffsetKey");
1958 plist_dict_insert_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset));
1959
1960 plist_dict_remove_item(file_info, "DLFileStatusKey");
1961 plist_dict_insert_item(file_info, "DLFileStatusKey", plist_new_uint(file_status));
1962
1963 send_file_node = plist_new_array();
1964
1965 plist_array_append_item(send_file_node, plist_new_string("DLSendFile"));
1966
1967 if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK)
1968 plist_array_append_item(send_file_node, plist_new_data(buffer+file_offset, length-file_offset));
1969 else
1970 plist_array_append_item(send_file_node, plist_new_data(buffer+file_offset, 8192));
1971
1972 plist_array_append_item(send_file_node, plist_copy(file_info));
1973
1974 err = mobilebackup_send(mobilebackup, send_file_node);
1975 if (err != MOBILEBACKUP_E_SUCCESS) {
1976 printf("ERROR: Unable to send file hunk due to error %d. Aborting...\n", err);
1977 file_status = DEVICE_LINK_FILE_STATUS_NONE;
1978 }
1979
1980 if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) {
1981 /* TODO: if all hunks of a file are sent, device must send ack */
1982 err = mobilebackup_receive_restore_file_received(mobilebackup, NULL);
1983 if (err != MOBILEBACKUP_E_SUCCESS) {
1984 printf("ERROR: Did not receive an ack for the sent file due to error %d. Aborting...\n", err);
1985 file_status = DEVICE_LINK_FILE_STATUS_NONE;
1986 }
1987 }
1988
1989 file_offset += 8192;
1990
1991 if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK)
1992 printf("DONE\n");
1993
1994 plist_free(send_file_node);
1995
1996 if (file_status == DEVICE_LINK_FILE_STATUS_NONE)
1997 break;
1998
1999 } while((file_offset < length));
2000
2001 free(hash);
2002 node = NULL;
2003 hash = NULL;
2004
2005 restore_ok = 1;
2006 if (file_status == DEVICE_LINK_FILE_STATUS_NONE) {
2007 restore_ok = 0;
2008 break;
2009 }
2010
2011 cur_file++;
2012 plist_dict_next_item(files, iter, &hash, &node);
2013 }
2014 free(iter);
2015
2016 printf("Restored %d files on device.\n", cur_file);
2017 }
2018 }
2019 /* TODO: observe notification_proxy id com.apple.mobile.application_installed */
2020 /* TODO: loop over Applications entries in Manifest data plist */
2021 plist_t applications = plist_dict_get_item(backup_data, "Applications");
2022 if (applications && (plist_get_node_type(applications) == PLIST_DICT) && restore_ok) {
2023 plist_dict_iter iter = NULL;
2024 plist_dict_new_iter(applications, &iter);
2025 if (iter) {
2026 /* loop over Application entries in Manifest data plist */
2027 char *hash = NULL;
2028 int total_files = plist_dict_get_size(applications);
2029 int cur_file = 1;
2030 plist_t tmp_node = NULL;
2031 plist_t dict = NULL;
2032 plist_t array = NULL;
2033 node = NULL;
2034 plist_dict_next_item(applications, iter, &hash, &node);
2035 while (node) {
2036 printf("Restoring Application %s %d/%d (%d%%)...", hash, cur_file, total_files, (cur_file*100/total_files));
2037 /* FIXME: receive com.apple.mobile.application_installed notification */
2038 /* send AppInfo entry */
2039 tmp_node = plist_dict_get_item(node, "AppInfo");
2040
2041 dict = plist_new_dict();
2042 plist_dict_insert_item(dict, "AppInfo", plist_copy(tmp_node));
2043 plist_dict_insert_item(dict, "BackupMessageTypeKey", plist_new_string("BackupMessageRestoreApplicationSent"));
2044
2045 array = plist_new_array();
2046 plist_array_append_item(array, plist_new_string("DLMessageProcessMessage"));
2047 plist_array_append_item(array, dict);
2048
2049 err = mobilebackup_send(mobilebackup, array);
2050 if (err != MOBILEBACKUP_E_SUCCESS) {
2051 printf("ERROR: Unable to restore application %s due to error %d. Aborting...\n", hash, err);
2052 restore_ok = 0;
2053 }
2054
2055 plist_free(array);
2056 array = NULL;
2057 dict = NULL;
2058
2059 /* receive BackupMessageRestoreApplicationReceived from device */
2060 if (restore_ok) {
2061 err = mobilebackup_receive_restore_application_received(mobilebackup, NULL);
2062 if (err != MOBILEBACKUP_E_SUCCESS) {
2063 printf("ERROR: Failed to receive an ack from the device for this application due to error %d. Aborting...\n", err);
2064 restore_ok = 0;
2065 }
2066 }
2067
2068 tmp_node = NULL;
2069 node = NULL;
2070 free(hash);
2071 hash = NULL;
2072
2073 if (restore_ok) {
2074 printf("DONE\n");
2075 cur_file++;
2076 plist_dict_next_item(applications, iter, &hash, &node);
2077 } else
2078 break;
2079 }
2080 free(iter);
2081
2082 if (restore_ok)
2083 printf("All applications restored.\n");
2084 else
2085 printf("Failed to restore applications.\n");
2086 }
2087 }
2088
2089 plist_free(backup_data);
2090
2091 /* signal restore finished message to device; BackupMessageRestoreComplete */
2092 if (restore_ok) {
2093 err = mobilebackup_send_restore_complete(mobilebackup);
2094 if (err != MOBILEBACKUP_E_SUCCESS) {
2095 printf("ERROR: Could not send BackupMessageRestoreComplete, error code %d\n", err);
2096 }
2097 }
2098
2099 if (restore_ok) {
2100 printf("Restore Successful.\n");
2101 } else {
2102 printf("Restore Failed.\n");
2103 }
2104#endif
2105 break;
2106 case CMD_LEAVE:
2107 default:
2108 break;
2109 } 1811 }
2110 if (lockfile) { 1812 if (lockfile) {
2111 afc_file_lock(afc, lockfile, AFC_LOCK_UN); 1813 afc_file_lock(afc, lockfile, AFC_LOCK_UN);