63
64
DEVICE_LINK_FILE_STATUS_LAST_HUNK
67
static void sha1_of_data(const char *input, uint32_t size, unsigned char *hash_out)
69
gcry_md_hash_buffer(GCRY_MD_SHA1, hash_out, input, size);
72
static int compare_hash(const unsigned char *hash1, const unsigned char *hash2, int hash_len)
75
for (i = 0; i < hash_len; i++) {
76
if (hash1[i] != hash2[i]) {
83
static void compute_datahash(const char *path, const char *destpath, uint8_t greylist, const char *domain, const char *appid, const char *version, unsigned char *hash_out)
85
gcry_md_hd_t hd = NULL;
86
gcry_md_open(&hd, GCRY_MD_SHA1, 0);
88
printf("ERROR: Could not initialize libgcrypt/SHA1\n");
93
FILE *f = fopen(path, "rb");
95
unsigned char buf[16384];
97
while ((len = fread(buf, 1, 16384, f)) > 0) {
98
gcry_md_write(hd, buf, len);
101
gcry_md_write(hd, destpath, strlen(destpath));
102
gcry_md_write(hd, ";", 1);
104
gcry_md_write(hd, "true", 4);
106
gcry_md_write(hd, "false", 5);
108
gcry_md_write(hd, ";", 1);
110
gcry_md_write(hd, domain, strlen(domain));
112
gcry_md_write(hd, "(null)", 6);
114
gcry_md_write(hd, ";", 1);
116
gcry_md_write(hd, appid, strlen(appid));
118
gcry_md_write(hd, "(null)", 6);
120
gcry_md_write(hd, ";", 1);
122
gcry_md_write(hd, version, strlen(version));
124
gcry_md_write(hd, "(null)", 6);
126
unsigned char *newhash = gcry_md_read(hd, GCRY_MD_SHA1);
127
memcpy(hash_out, newhash, 20);
132
static void print_hash(const unsigned char *hash, int len)
135
for (i = 0; i < len; i++) {
136
printf("%02x", hash[i]);
66
140
static void notify_cb(const char *notification, void *userdata)
68
142
if (!strcmp(notification, NP_SYNC_CANCEL_REQUEST)) {
462
static int mobilebackup_check_file_integrity(const char *backup_directory, const char *hash, plist_t filedata)
466
plist_t mdinfo = NULL;
468
unsigned char file_hash[20];
470
datapath = mobilebackup_build_path(backup_directory, hash, ".mddata");
471
if (stat(datapath, &st) != 0) {
473
printf("ERROR: '%s.mddata' is missing!\n", hash);
478
infopath = mobilebackup_build_path(backup_directory, hash, ".mdinfo");
479
plist_read_from_filename(&mdinfo, infopath);
483
printf("ERROR: '%s.mdinfo' is missing or corrupted!\n", hash);
488
/* sha1 hash verification */
489
plist_t node = plist_dict_get_item(filedata, "DataHash");
490
if (!node || (plist_get_node_type(node) != PLIST_DATA)) {
492
printf("ERROR: Could not get DataHash for file entry '%s'\n", hash);
498
node = plist_dict_get_item(mdinfo, "Metadata");
499
if (!node && (plist_get_node_type(node) != PLIST_DATA)) {
501
printf("ERROR: Could not find Metadata in plist '%s.mdinfo'\n", hash);
507
char *meta_bin = NULL;
508
uint64_t meta_bin_size = 0;
509
plist_get_data_val(node, &meta_bin, &meta_bin_size);
510
plist_t metadata = NULL;
512
plist_from_bin(meta_bin, (uint32_t)meta_bin_size, &metadata);
516
printf("ERROR: Could not get Metadata from plist '%s.mdinfo'\n", hash);
522
char *version = NULL;
523
node = plist_dict_get_item(metadata, "Version");
524
if (node && (plist_get_node_type(node) == PLIST_STRING)) {
525
plist_get_string_val(node, &version);
528
char *destpath = NULL;
529
node = plist_dict_get_item(metadata, "Path");
530
if (node && (plist_get_node_type(node) == PLIST_STRING)) {
531
plist_get_string_val(node, &destpath);
534
uint8_t greylist = 0;
535
node = plist_dict_get_item(metadata, "Greylist");
536
if (node && (plist_get_node_type(node) == PLIST_BOOLEAN)) {
537
plist_get_bool_val(node, &greylist);
541
node = plist_dict_get_item(metadata, "Domain");
542
if (node && (plist_get_node_type(node) == PLIST_STRING)) {
543
plist_get_string_val(node, &domain);
546
char *fnstr = malloc(strlen(domain) + 1 + strlen(destpath) + 1);
547
strcpy(fnstr, domain);
549
strcat(fnstr, destpath);
550
unsigned char fnhash[20];
553
sha1_of_data(fnstr, strlen(fnstr), fnhash);
556
for ( i = 0; i < 20; i++, p += 2 ) {
557
snprintf (p, 3, "%02x", (unsigned char)fnhash[i] );
559
if (strcmp(fnamehash, hash)) {
561
printf("WARNING: filename hash does not match for entry '%s'\n", hash);
564
char *auth_version = NULL;
565
node = plist_dict_get_item(mdinfo, "AuthVersion");
566
if (node && (plist_get_node_type(node) == PLIST_STRING)) {
567
plist_get_string_val(node, &auth_version);
570
if (strcmp(auth_version, "1.0")) {
572
printf("WARNING: Unknown AuthVersion '%s', DataHash cannot be verified!\n", auth_version);
575
node = plist_dict_get_item(filedata, "DataHash");
576
if (!node || (plist_get_node_type(node) != PLIST_DATA)) {
578
printf("WARNING: Could not get DataHash key from file info data for entry '%s'\n", hash);
582
unsigned char *data_hash = NULL;
583
uint64_t data_hash_len = 0;
584
plist_get_data_val(node, (char**)&data_hash, &data_hash_len);
586
if (data_hash && (data_hash_len == 20)) {
587
compute_datahash(datapath, destpath, greylist, domain, NULL, version, file_hash);
588
hash_ok = compare_hash(data_hash, file_hash, 20);
589
} else if (data_hash_len == 0) {
590
/* no datahash present */
600
printf("ERROR: The hash for '%s.mddata' does not match DataHash entry in Manifest\n", hash);
601
printf("datahash: ");
602
print_hash(data_hash, 20);
603
printf("\nfilehash: ");
604
print_hash(file_hash, 20);
364
613
static void do_post_notification(const char *notification)
366
615
uint16_t nport = 0;
934
1199
printf("Backup Failed.\n");
938
g_free(manifest_path);
941
1202
case CMD_RESTORE:
942
printf("Restoring backup is NOT IMPLEMENTED.\n");
943
/* verify battery on AC enough battery remaining */
1203
/* close down the lockdown connection as it is no longer needed */
1205
lockdownd_client_free(client);
1209
/* TODO: verify battery on AC enough battery remaining */
1211
/* verify if Status.plist says we read from an successful backup */
1212
if (mobilebackup_read_status(backup_directory) <= 0) {
1213
printf("ERROR: Cannot ensure we restore from a successful backup. Aborting.\n");
1216
/* now make sure backup integrity is ok! verify all files */
1217
printf("Reading existing Manifest.\n");
1218
plist_read_from_filename(&manifest_plist, manifest_path);
1219
if (!manifest_plist) {
1220
printf("Could not read Manifest.plist. Aborting.\n");
1224
printf("Verifying backup integrity, please wait.\n");
1226
uint64_t binsize = 0;
1227
node = plist_dict_get_item(manifest_plist, "Data");
1228
if (!node || (plist_get_node_type(node) != PLIST_DATA)) {
1229
printf("Could not read Data key from Manifest.plist!\n");
1232
plist_get_data_val(node, &bin, &binsize);
1233
plist_t backup_data = NULL;
1235
char *auth_ver = NULL;
1236
unsigned char *auth_sig = NULL;
1237
uint64_t auth_sig_len = 0;
1238
/* verify AuthSignature */
1239
node = plist_dict_get_item(manifest_plist, "AuthVersion");
1240
plist_get_string_val(node, &auth_ver);
1241
if (auth_ver && (strcmp(auth_ver, "2.0") == 0)) {
1242
node = plist_dict_get_item(manifest_plist, "AuthSignature");
1243
if (node && (plist_get_node_type(node) == PLIST_DATA)) {
1244
plist_get_data_val(node, (char**)&auth_sig, &auth_sig_len);
1246
if (auth_sig && (auth_sig_len == 20)) {
1247
/* calculate the sha1, then compare */
1248
unsigned char data_sha1[20];
1249
sha1_of_data(bin, binsize, data_sha1);
1250
if (compare_hash(auth_sig, data_sha1, 20)) {
1251
printf("AuthSignature is valid\n");
1253
printf("ERROR: AuthSignature is NOT VALID\n");
1256
printf("Could not get AuthSignature from manifest!\n");
1259
} else if (auth_ver) {
1260
printf("Unknown AuthVersion '%s', cannot verify AuthSignature\n", auth_ver);
1262
plist_from_bin(bin, (uint32_t)binsize, &backup_data);
1266
printf("Could not read plist from Manifest.plist Data key!\n");
1269
plist_t files = plist_dict_get_item(backup_data, "Files");
1270
if (files && (plist_get_node_type(files) == PLIST_DICT)) {
1271
plist_dict_iter iter = NULL;
1272
plist_dict_new_iter(files, &iter);
1274
/* loop over Files entries in Manifest data plist */
1277
int total_files = plist_dict_get_size(files);
1280
plist_dict_next_item(files, iter, &hash, &node);
1282
printf("Verifying file %d/%d (%d%%) \r", cur_file, total_files, (cur_file*100/total_files));
1284
/* make sure both .mddata/.mdinfo files are available for each entry */
1285
file_ok = mobilebackup_check_file_integrity(backup_directory, hash, node);
1292
plist_dict_next_item(files, iter, &hash, &node);
1297
plist_free(backup_data);
1300
printf("All backup files appear to be valid\n");
1304
printf("Requesting restore from device...\n");
944
1306
/* request restore from device with manifest (BackupMessageRestoreMigrate) */
945
/* read mddata/mdinfo files and send to devices using DLSendFile */
946
/* signal restore finished message to device */
947
/* close down lockdown connection as it is no longer needed */
948
lockdownd_client_free(client);
1307
int restore_flags = MB_RESTORE_NOTIFY_SPRINGBOARD | MB_RESTORE_PRESERVE_SETTINGS | MB_RESTORE_PRESERVE_CAMERA_ROLL;
1308
err = mobilebackup_request_restore(mobilebackup, manifest_plist, restore_flags, "1.6");
1309
if (err != MOBILEBACKUP_E_SUCCESS) {
1310
if (err == MOBILEBACKUP_E_BAD_VERSION) {
1311
printf("ERROR: Could not start restore process: backup protocol version mismatch!\n");
1312
} else if (err == MOBILEBACKUP_E_REPLY_NOT_OK) {
1313
printf("ERROR: Could not start restore process: device refused to start the restore process.\n");
1315
printf("ERROR: Could not start restore process: unspecified error occured (%d)\n", err);
1317
plist_free(backup_data);
1321
printf("Entered restore mode.\n");
1325
if (files && (plist_get_node_type(files) == PLIST_DICT)) {
1326
plist_dict_iter iter = NULL;
1327
plist_dict_new_iter(files, &iter);
1329
/* loop over Files entries in Manifest data plist */
1331
plist_t file_info = NULL;
1332
char *file_info_path = NULL;
1333
int total_files = plist_dict_get_size(files);
1335
uint64_t file_offset = 0;
1336
uint8_t is_encrypted = 0;
1337
plist_t tmp_node = NULL;
1338
plist_t file_path_node = NULL;
1339
plist_t send_file_node = NULL;
1341
plist_dict_next_item(files, iter, &hash, &node);
1343
/* TODO: read mddata/mdinfo files and send to device using DLSendFile */
1344
file_info_path = mobilebackup_build_path(backup_directory, hash, ".mdinfo");
1345
plist_read_from_filename(&file_info, file_info_path);
1347
/* get encryption state */
1348
tmp_node = plist_dict_get_item(file_info, "IsEncrypted");
1349
plist_get_bool_val(tmp_node, &is_encrypted);
1352
/* get real file path from metadata */
1353
tmp_node = plist_dict_get_item(file_info, "Metadata");
1354
plist_get_data_val(tmp_node, &buffer, &length);
1356
plist_from_bin(buffer, length, &tmp_node);
1357
file_path_node = plist_dict_get_item(tmp_node, "Path");
1358
plist_get_string_val(file_path_node, &file_path);
1360
printf("Restoring file %s %d/%d (%d%%)... ", file_path, cur_file, total_files, (cur_file*100/total_files));
1362
/* add additional device link file information keys */
1363
plist_dict_insert_item(file_info, "DLFileAttributesKey", plist_copy(node));
1364
plist_dict_insert_item(file_info, "DLFileSource", plist_new_string(file_info_path));
1365
plist_dict_insert_item(file_info, "DLFileDest", plist_new_string("/tmp/RestoreFile.plist"));
1366
plist_dict_insert_item(file_info, "DLFileIsEncrypted", plist_new_bool(is_encrypted));
1367
plist_dict_insert_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset));
1368
plist_dict_insert_item(file_info, "DLFileStatusKey", plist_new_uint(file_status));
1370
/* read data from file */
1371
free(file_info_path);
1372
file_info_path = mobilebackup_build_path(backup_directory, hash, ".mddata");
1373
buffer_read_from_filename(file_info_path, &buffer, &length);
1374
free(file_info_path);
1376
/* send DLSendFile messages */
1379
if ((length-file_offset) <= 8192)
1380
file_status = DEVICE_LINK_FILE_STATUS_LAST_HUNK;
1382
file_status = DEVICE_LINK_FILE_STATUS_HUNK;
1384
plist_dict_remove_item(file_info, "DLFileOffsetKey");
1385
plist_dict_insert_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset));
1387
plist_dict_remove_item(file_info, "DLFileStatusKey");
1388
plist_dict_insert_item(file_info, "DLFileStatusKey", plist_new_uint(file_status));
1390
send_file_node = plist_new_array();
1392
plist_array_append_item(send_file_node, plist_new_string("DLSendFile"));
1394
if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK)
1395
plist_array_append_item(send_file_node, plist_new_data(buffer+file_offset, length-file_offset));
1397
plist_array_append_item(send_file_node, plist_new_data(buffer+file_offset, 8192));
1399
plist_array_append_item(send_file_node, plist_copy(file_info));
1401
err = mobilebackup_send(mobilebackup, send_file_node);
1402
if (err != MOBILEBACKUP_E_SUCCESS) {
1403
printf("ERROR: Unable to send file hunk due to error %d. Aborting...\n", err);
1404
file_status = DEVICE_LINK_FILE_STATUS_NONE;
1407
if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) {
1408
/* TODO: if all hunks of a file are sent, device must send ack */
1409
err = mobilebackup_receive_restore_file_received(mobilebackup, NULL);
1410
if (err != MOBILEBACKUP_E_SUCCESS) {
1411
printf("ERROR: Did not receive an ack for the sent file due to error %d. Aborting...\n", err);
1412
file_status = DEVICE_LINK_FILE_STATUS_NONE;
1416
file_offset += 8192;
1418
if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK)
1421
plist_free(send_file_node);
1423
if (file_status == DEVICE_LINK_FILE_STATUS_NONE)
1426
} while((file_offset < length));
1433
if (file_status == DEVICE_LINK_FILE_STATUS_NONE) {
1439
plist_dict_next_item(files, iter, &hash, &node);
1443
printf("Restored %d files on device.\n", cur_file);
1446
/* TODO: observe notification_proxy id com.apple.mobile.application_installed */
1447
/* TODO: loop over Applications entries in Manifest data plist */
1448
plist_t applications = plist_dict_get_item(backup_data, "Applications");
1449
if (applications && (plist_get_node_type(applications) == PLIST_DICT) && restore_ok) {
1450
plist_dict_iter iter = NULL;
1451
plist_dict_new_iter(applications, &iter);
1453
/* loop over Application entries in Manifest data plist */
1455
int total_files = plist_dict_get_size(applications);
1457
plist_t tmp_node = NULL;
1458
plist_t dict = NULL;
1459
plist_t array = NULL;
1461
plist_dict_next_item(applications, iter, &hash, &node);
1463
printf("Restoring Application %s %d/%d (%d%%)...", hash, cur_file, total_files, (cur_file*100/total_files));
1464
/* FIXME: receive com.apple.mobile.application_installed notification */
1465
/* send AppInfo entry */
1466
tmp_node = plist_dict_get_item(node, "AppInfo");
1468
dict = plist_new_dict();
1469
plist_dict_insert_item(dict, "AppInfo", plist_copy(tmp_node));
1470
plist_dict_insert_item(dict, "BackupMessageTypeKey", plist_new_string("BackupMessageRestoreApplicationSent"));
1472
array = plist_new_array();
1473
plist_array_append_item(array, plist_new_string("DLMessageProcessMessage"));
1474
plist_array_append_item(array, dict);
1476
err = mobilebackup_send(mobilebackup, array);
1477
if (err != MOBILEBACKUP_E_SUCCESS) {
1478
printf("ERROR: Unable to restore application %s due to error %d. Aborting...\n", hash, err);
1486
/* receive BackupMessageRestoreApplicationReceived from device */
1488
err = mobilebackup_receive_restore_application_received(mobilebackup, NULL);
1489
if (err != MOBILEBACKUP_E_SUCCESS) {
1490
printf("ERROR: Failed to receive an ack from the device for this application due to error %d. Aborting...\n", err);
1503
plist_dict_next_item(applications, iter, &hash, &node);
1510
printf("All applications restored.\n");
1512
printf("Failed to restore applications.\n");
1516
plist_free(backup_data);
1518
/* signal restore finished message to device; BackupMessageRestoreComplete */
1520
err = mobilebackup_send_restore_complete(mobilebackup);
1521
if (err != MOBILEBACKUP_E_SUCCESS) {
1522
printf("ERROR: Could not send BackupMessageRestoreComplete, error code %d\n", err);
1527
printf("Restore Successful.\n");
1529
printf("Restore Failed.\n");