summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/idevicebackup2.c299
1 files changed, 275 insertions, 24 deletions
diff --git a/tools/idevicebackup2.c b/tools/idevicebackup2.c
index c32e2e4..4ca0f2a 100644
--- a/tools/idevicebackup2.c
+++ b/tools/idevicebackup2.c
@@ -49,6 +49,7 @@
49#include <windows.h> 49#include <windows.h>
50#define sleep(x) Sleep(x*1000) 50#define sleep(x) Sleep(x*1000)
51#else 51#else
52#include <termios.h>
52#include <sys/statvfs.h> 53#include <sys/statvfs.h>
53#endif 54#endif
54 55
@@ -73,6 +74,7 @@ enum cmd_mode {
73 CMD_INFO, 74 CMD_INFO,
74 CMD_LIST, 75 CMD_LIST,
75 CMD_UNBACK, 76 CMD_UNBACK,
77 CMD_CHANGEPW,
76 CMD_LEAVE 78 CMD_LEAVE
77}; 79};
78 80
@@ -86,14 +88,21 @@ enum cmd_flags {
86 CMD_FLAG_RESTORE_REBOOT = (1 << 2), 88 CMD_FLAG_RESTORE_REBOOT = (1 << 2),
87 CMD_FLAG_RESTORE_COPY_BACKUP = (1 << 3), 89 CMD_FLAG_RESTORE_COPY_BACKUP = (1 << 3),
88 CMD_FLAG_RESTORE_SETTINGS = (1 << 4), 90 CMD_FLAG_RESTORE_SETTINGS = (1 << 4),
89 CMD_FLAG_RESTORE_REMOVE_ITEMS = (1 << 5) 91 CMD_FLAG_RESTORE_REMOVE_ITEMS = (1 << 5),
92 CMD_FLAG_ENCRYPTION_ENABLE = (1 << 6),
93 CMD_FLAG_ENCRYPTION_DISABLE = (1 << 7),
94 CMD_FLAG_ENCRYPTION_CHANGEPW = (1 << 8)
90}; 95};
91 96
97static int backup_domain_changed = 0;
98
92static void notify_cb(const char *notification, void *userdata) 99static void notify_cb(const char *notification, void *userdata)
93{ 100{
94 if (!strcmp(notification, NP_SYNC_CANCEL_REQUEST)) { 101 if (!strcmp(notification, NP_SYNC_CANCEL_REQUEST)) {
95 PRINT_VERBOSE(1, "User has cancelled the backup process on the device.\n"); 102 PRINT_VERBOSE(1, "User has cancelled the backup process on the device.\n");
96 quit_flag++; 103 quit_flag++;
104 } else if (!strcmp(notification, NP_BACKUP_DOMAIN_CHANGED)) {
105 backup_domain_changed = 1;
97 } else { 106 } else {
98 PRINT_VERBOSE(1, "Unhandled notification '%s' (TODO: implement)\n", notification); 107 PRINT_VERBOSE(1, "Unhandled notification '%s' (TODO: implement)\n", notification);
99 } 108 }
@@ -1131,6 +1140,72 @@ static void mb2_copy_directory_by_path(const char *src, const char *dst)
1131 } 1140 }
1132} 1141}
1133 1142
1143#ifdef WIN32
1144#define BS_CC '\b'
1145#define my_getch getch
1146#else
1147#define BS_CC 0x7f
1148static int my_getch()
1149{
1150 struct termios oldt, newt;
1151 int ch;
1152 tcgetattr(STDIN_FILENO, &oldt);
1153 newt = oldt;
1154 newt.c_lflag &= ~(ICANON | ECHO);
1155 tcsetattr(STDIN_FILENO, TCSANOW, &newt);
1156 ch = getchar();
1157 tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
1158 return ch;
1159}
1160#endif
1161
1162static void get_hidden_input(char *buf, int maxlen)
1163{
1164 int pwlen = 0;
1165 int c;
1166
1167 while ((c = my_getch())) {
1168 if ((c == '\r') || (c == '\n')) {
1169 break;
1170 } else if (isprint(c)) {
1171 if (pwlen < maxlen-1)
1172 buf[pwlen++] = c;
1173 fputc('*', stderr);
1174 } else if (c == BS_CC) {
1175 if (pwlen > 0) {
1176 fputs("\b \b", stderr);
1177 pwlen--;
1178 }
1179 }
1180 }
1181 buf[pwlen] = 0;
1182}
1183
1184static char* ask_for_password(const char* msg, int type_again)
1185{
1186 char pwbuf[256];
1187
1188 fprintf(stderr, "%s: ", msg);
1189 fflush(stderr);
1190 get_hidden_input(pwbuf, 256);
1191 fputc('\n', stderr);
1192
1193 if (type_again) {
1194 char pwrep[256];
1195
1196 fprintf(stderr, "%s (repeat): ", msg);
1197 fflush(stderr);
1198 get_hidden_input(pwrep, 256);
1199 fputc('\n', stderr);
1200
1201 if (strcmp(pwbuf, pwrep) != 0) {
1202 printf("ERROR: passwords don't match\n");
1203 return NULL;
1204 }
1205 }
1206 return strdup(pwbuf);
1207}
1208
1134/** 1209/**
1135 * signal handler function for cleaning up properly 1210 * signal handler function for cleaning up properly
1136 */ 1211 */
@@ -1157,7 +1232,12 @@ static void print_usage(int argc, char **argv)
1157 printf(" --password PWD\tsupply the password of the source backup\n"); 1232 printf(" --password PWD\tsupply the password of the source backup\n");
1158 printf(" info\t\tshow details about last completed backup of device\n"); 1233 printf(" info\t\tshow details about last completed backup of device\n");
1159 printf(" list\t\tlist files of last completed backup in CSV format\n"); 1234 printf(" list\t\tlist files of last completed backup in CSV format\n");
1160 printf(" unback\tunpack a completed backup in DIRECTORY/_unback_/\n\n"); 1235 printf(" unback\tunpack a completed backup in DIRECTORY/_unback_/\n");
1236 printf(" encryption on|off [PWD]\tenable or disable backup encryption\n");
1237 printf(" NOTE: if password is omitted it will be requested interactively\n");
1238 printf(" changepw [OLD NEW] change backup password on target device\n");
1239 printf(" NOTE: if no passwords are given the change will be performed interactively.\n");
1240 printf("\n");
1161 printf("options:\n"); 1241 printf("options:\n");
1162 printf(" -d, --debug\t\tenable communication debugging\n"); 1242 printf(" -d, --debug\t\tenable communication debugging\n");
1163 printf(" -u, --udid UDID\ttarget specific device by its 40-digit device UDID\n"); 1243 printf(" -u, --udid UDID\ttarget specific device by its 40-digit device UDID\n");
@@ -1178,6 +1258,7 @@ int main(int argc, char *argv[])
1178 int is_full_backup = 0; 1258 int is_full_backup = 0;
1179 char* backup_directory = NULL; 1259 char* backup_directory = NULL;
1180 char* backup_password = NULL; 1260 char* backup_password = NULL;
1261 char* newpw = NULL;
1181 struct stat st; 1262 struct stat st;
1182 plist_t node_tmp = NULL; 1263 plist_t node_tmp = NULL;
1183 plist_t info_plist = NULL; 1264 plist_t info_plist = NULL;
@@ -1263,6 +1344,65 @@ int main(int argc, char *argv[])
1263 else if (!strcmp(argv[i], "unback")) { 1344 else if (!strcmp(argv[i], "unback")) {
1264 cmd = CMD_UNBACK; 1345 cmd = CMD_UNBACK;
1265 } 1346 }
1347 else if (!strcmp(argv[i], "encryption")) {
1348 cmd = CMD_CHANGEPW;
1349 i++;
1350 if (!argv[i]) {
1351 printf("No argument given for encryption command; requires either 'on' or 'off'.\n");
1352 print_usage(argc, argv);
1353 return 0;
1354 }
1355 if (!strcmp(argv[i], "on")) {
1356 cmd_flags |= CMD_FLAG_ENCRYPTION_ENABLE;
1357 } else if (!strcmp(argv[i], "off")) {
1358 cmd_flags |= CMD_FLAG_ENCRYPTION_DISABLE;
1359 } else {
1360 printf("Invalid argument '%s' for encryption command; must be either 'on' or 'off'.\n", argv[i]);
1361 }
1362 // check if a password was given on the command line
1363 if (newpw) {
1364 free(newpw);
1365 newpw = NULL;
1366 }
1367 if (backup_password) {
1368 free(backup_password);
1369 backup_password = NULL;
1370 }
1371 i++;
1372 if (argv[i]) {
1373 if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) {
1374 newpw = strdup(argv[i]);
1375 } else if (cmd_flags & CMD_FLAG_ENCRYPTION_DISABLE) {
1376 backup_password = strdup(argv[i]);
1377 }
1378 }
1379 continue;
1380 }
1381 else if (!strcmp(argv[i], "changepw")) {
1382 cmd = CMD_CHANGEPW;
1383 cmd_flags |= CMD_FLAG_ENCRYPTION_CHANGEPW;
1384 // check if passwords were given on command line
1385 if (newpw) {
1386 free(newpw);
1387 newpw = NULL;
1388 }
1389 if (backup_password) {
1390 free(backup_password);
1391 backup_password = NULL;
1392 }
1393 i++;
1394 if (argv[i]) {
1395 backup_password = strdup(argv[i]);
1396 i++;
1397 if (!argv[i]) {
1398 printf("Old and new passwords have to be passed as arguments for the changepw command\n");
1399 print_usage(argc, argv);
1400 return 0;
1401 }
1402 newpw = strdup(argv[i]);
1403 }
1404 continue;
1405 }
1266 else if (backup_directory == NULL) { 1406 else if (backup_directory == NULL) {
1267 backup_directory = argv[i]; 1407 backup_directory = argv[i];
1268 } 1408 }
@@ -1279,16 +1419,20 @@ int main(int argc, char *argv[])
1279 return -1; 1419 return -1;
1280 } 1420 }
1281 1421
1282 if (backup_directory == NULL) { 1422 if (cmd == CMD_CHANGEPW) {
1283 printf("No target backup directory specified.\n"); 1423 backup_directory = strdup(".this_folder_is_not_present_on_purpose");
1284 print_usage(argc, argv); 1424 } else {
1285 return -1; 1425 if (backup_directory == NULL) {
1286 } 1426 printf("No target backup directory specified.\n");
1427 print_usage(argc, argv);
1428 return -1;
1429 }
1287 1430
1288 /* verify if passed backup directory exists */ 1431 /* verify if passed backup directory exists */
1289 if (stat(backup_directory, &st) != 0) { 1432 if (stat(backup_directory, &st) != 0) {
1290 printf("ERROR: Backup directory \"%s\" does not exist!\n", backup_directory); 1433 printf("ERROR: Backup directory \"%s\" does not exist!\n", backup_directory);
1291 return -1; 1434 return -1;
1435 }
1292 } 1436 }
1293 1437
1294 if (udid) { 1438 if (udid) {
@@ -1312,18 +1456,20 @@ int main(int argc, char *argv[])
1312 source_udid = strdup(udid); 1456 source_udid = strdup(udid);
1313 } 1457 }
1314 1458
1315 /* backup directory must contain an Info.plist */ 1459 char *info_path = NULL;
1316 char *info_path = build_path(backup_directory, source_udid, "Info.plist", NULL); 1460 if (cmd != CMD_CHANGEPW) {
1317 if (cmd == CMD_RESTORE) { 1461 /* backup directory must contain an Info.plist */
1318 if (stat(info_path, &st) != 0) { 1462 info_path = build_path(backup_directory, source_udid, "Info.plist", NULL);
1319 free(info_path); 1463 if (cmd == CMD_RESTORE) {
1320 printf("ERROR: Backup directory \"%s\" is invalid. No Info.plist found for UDID %s.\n", backup_directory, source_udid); 1464 if (stat(info_path, &st) != 0) {
1321 return -1; 1465 free(info_path);
1466 printf("ERROR: Backup directory \"%s\" is invalid. No Info.plist found for UDID %s.\n", backup_directory, source_udid);
1467 return -1;
1468 }
1322 } 1469 }
1470 PRINT_VERBOSE(1, "Backup directory is \"%s\"\n", backup_directory);
1323 } 1471 }
1324 1472
1325 PRINT_VERBOSE(1, "Backup directory is \"%s\"\n", backup_directory);
1326
1327 if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(device, &client, "idevicebackup")) { 1473 if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(device, &client, "idevicebackup")) {
1328 idevice_free(device); 1474 idevice_free(device);
1329 return -1; 1475 return -1;
@@ -1384,7 +1530,7 @@ int main(int argc, char *argv[])
1384 } 1530 }
1385 1531
1386 /* verify existing Info.plist */ 1532 /* verify existing Info.plist */
1387 if (stat(info_path, &st) == 0) { 1533 if (info_path && (stat(info_path, &st) == 0)) {
1388 PRINT_VERBOSE(1, "Reading Info.plist from backup.\n"); 1534 PRINT_VERBOSE(1, "Reading Info.plist from backup.\n");
1389 plist_read_from_filename(&info_plist, info_path); 1535 plist_read_from_filename(&info_plist, info_path);
1390 1536
@@ -1431,6 +1577,16 @@ int main(int argc, char *argv[])
1431 cmd = CMD_LEAVE; 1577 cmd = CMD_LEAVE;
1432 } 1578 }
1433 } 1579 }
1580 uint8_t willEncrypt = 0;
1581 node_tmp = NULL;
1582 lockdownd_get_value(client, "com.apple.mobile.backup", "WillEncrypt", &node_tmp);
1583 if (node_tmp) {
1584 if (plist_get_node_type(node_tmp) == PLIST_BOOLEAN) {
1585 plist_get_bool_val(node_tmp, &willEncrypt);
1586 }
1587 plist_free(node_tmp);
1588 node_tmp = NULL;
1589 }
1434 1590
1435checkpoint: 1591checkpoint:
1436 1592
@@ -1472,8 +1628,12 @@ checkpoint:
1472 info_plist = NULL; 1628 info_plist = NULL;
1473 1629
1474 /* request backup from device with manifest from last backup */ 1630 /* request backup from device with manifest from last backup */
1475 PRINT_VERBOSE(1, "Requesting backup from device...\n"); 1631 if (willEncrypt) {
1476 1632 PRINT_VERBOSE(1, "Backup will be encrypted.\n");
1633 } else {
1634 PRINT_VERBOSE(1, "Backup will be unencrypted.\n");
1635 }
1636 PRINT_VERBOSE(1, "Requesting backup from device...\n");
1477 err = mobilebackup2_send_request(mobilebackup2, "Backup", udid, source_udid, NULL); 1637 err = mobilebackup2_send_request(mobilebackup2, "Backup", udid, source_udid, NULL);
1478 if (err == MOBILEBACKUP2_E_SUCCESS) { 1638 if (err == MOBILEBACKUP2_E_SUCCESS) {
1479 if (is_full_backup) { 1639 if (is_full_backup) {
@@ -1560,6 +1720,76 @@ checkpoint:
1560 cmd = CMD_LEAVE; 1720 cmd = CMD_LEAVE;
1561 } 1721 }
1562 break; 1722 break;
1723 case CMD_CHANGEPW:
1724 opts = plist_new_dict();
1725 plist_dict_insert_item(opts, "TargetIdentifier", plist_new_string(udid));
1726 if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) {
1727 if (!willEncrypt) {
1728 if (!newpw) {
1729 newpw = ask_for_password("Enter new backup password", 1);
1730 }
1731 if (!newpw) {
1732 printf("No backup password given. Aborting.\n");
1733 }
1734 } else {
1735 printf("ERROR: Backup encryption is already enabled. Aborting.\n");
1736 cmd = CMD_LEAVE;
1737 if (newpw) {
1738 free(newpw);
1739 newpw = NULL;
1740 }
1741 }
1742 } else if (cmd_flags & CMD_FLAG_ENCRYPTION_DISABLE) {
1743 if (willEncrypt) {
1744 if (!backup_password) {
1745 backup_password = ask_for_password("Enter current backup password", 0);
1746 }
1747 } else {
1748 printf("ERROR: Backup encryption is not enabled. Aborting.\n");
1749 cmd = CMD_LEAVE;
1750 if (backup_password) {
1751 free(backup_password);
1752 backup_password = NULL;
1753 }
1754 }
1755 } else if (cmd_flags & CMD_FLAG_ENCRYPTION_CHANGEPW) {
1756 if (willEncrypt) {
1757 if (!backup_password) {
1758 backup_password = ask_for_password("Enter old backup password", 0);
1759 newpw = ask_for_password("Enter new backup password", 1);
1760 }
1761 } else {
1762 printf("ERROR: Backup encryption is not enabled so can't change password. Aborting.\n");
1763 cmd = CMD_LEAVE;
1764 if (newpw) {
1765 free(newpw);
1766 newpw = NULL;
1767 }
1768 if (backup_password) {
1769 free(backup_password);
1770 backup_password = NULL;
1771 }
1772 }
1773 }
1774 if (newpw) {
1775 plist_dict_insert_item(opts, "NewPassword", plist_new_string(newpw));
1776 }
1777 if (backup_password) {
1778 plist_dict_insert_item(opts, "OldPassword", plist_new_string(backup_password));
1779 }
1780 if (newpw || backup_password) {
1781 mobilebackup2_send_message(mobilebackup2, "ChangePassword", opts);
1782 /*if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) {
1783 int retr = 10;
1784 while ((retr-- >= 0) && !backup_domain_changed) {
1785 sleep(1);
1786 }
1787 }*/
1788 } else {
1789 cmd = CMD_LEAVE;
1790 }
1791 plist_free(opts);
1792 break;
1563 default: 1793 default:
1564 break; 1794 break;
1565 } 1795 }
@@ -1592,7 +1822,7 @@ checkpoint:
1592 sleep(2); 1822 sleep(2);
1593 goto files_out; 1823 goto files_out;
1594 } 1824 }
1595 1825
1596 if (!strcmp(dlmsg, "DLMessageDownloadFiles")) { 1826 if (!strcmp(dlmsg, "DLMessageDownloadFiles")) {
1597 /* device wants to download files from the computer */ 1827 /* device wants to download files from the computer */
1598 mb2_handle_send_files(message, backup_directory); 1828 mb2_handle_send_files(message, backup_directory);
@@ -1860,6 +2090,27 @@ files_out:
1860 PRINT_VERBOSE(1, "Unback Successful.\n"); 2090 PRINT_VERBOSE(1, "Unback Successful.\n");
1861 } 2091 }
1862 break; 2092 break;
2093 case CMD_CHANGEPW:
2094 if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) {
2095 if (operation_ok) {
2096 PRINT_VERBOSE(1, "Backup encryption has been enabled successfully.\n");
2097 } else {
2098 PRINT_VERBOSE(1, "Could not enable backup encryption.\n");
2099 }
2100 } else if (cmd_flags & CMD_FLAG_ENCRYPTION_DISABLE) {
2101 if (operation_ok) {
2102 PRINT_VERBOSE(1, "Backup encryption has been disabled successfully.\n");
2103 } else {
2104 PRINT_VERBOSE(1, "Could not disable backup encryption.\n");
2105 }
2106 } else if (cmd_flags & CMD_FLAG_ENCRYPTION_CHANGEPW) {
2107 if (operation_ok) {
2108 PRINT_VERBOSE(1, "Backup encryption password has been changed successfully.\n");
2109 } else {
2110 PRINT_VERBOSE(1, "Could not change backup encryption password.\n");
2111 }
2112 }
2113 break;
1863 case CMD_RESTORE: 2114 case CMD_RESTORE:
1864 if (cmd_flags & CMD_FLAG_RESTORE_REBOOT) 2115 if (cmd_flags & CMD_FLAG_RESTORE_REBOOT)
1865 PRINT_VERBOSE(1, "The device should reboot now.\n"); 2116 PRINT_VERBOSE(1, "The device should reboot now.\n");