summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/iphonebackup.c315
1 files changed, 157 insertions, 158 deletions
diff --git a/tools/iphonebackup.c b/tools/iphonebackup.c
index 611c0f2..1ad4116 100644
--- a/tools/iphonebackup.c
+++ b/tools/iphonebackup.c
@@ -40,7 +40,8 @@ static int quit_flag = 0;
40 40
41enum cmd_mode { 41enum cmd_mode {
42 CMD_BACKUP, 42 CMD_BACKUP,
43 CMD_RESTORE 43 CMD_RESTORE,
44 CMD_LEAVE
44}; 45};
45 46
46static plist_t mobilebackup_factory_info_plist() 47static plist_t mobilebackup_factory_info_plist()
@@ -102,150 +103,24 @@ static plist_t mobilebackup_factory_info_plist()
102 return ret; 103 return ret;
103} 104}
104 105
105static plist_t mobilebackup_factory_metadata_plist()
106{
107 plist_t ret = NULL;
108/*
109Metadata key is:
110<dict>
111 <key>Path</key>
112 <string>Library/SMS/sms.db</string>
113 <key>Version</key>
114 <string>3.0</string>
115 <key>Greylist</key>
116 <false/>
117 <key>Domain</key>
118 <string>HomeDomain</string>
119</dict>
120*/
121/*
122<dict>
123 <key>Metadata</key>
124 <data><!-- binary plist -->
125 YnBsaXN0MDDUAQIDBAUGBwhUUGF0aFdWZXJzaW9uWEdyZXlsaXN0VkRvbWFp
126 bl8QEkxpYnJhcnkvU01TL3Ntcy5kYlMzLjAIWkhvbWVEb21haW4IERYeJy5D
127 R0gAAAAAAAABAQAAAAAAAAAJAAAAAAAAAAAAAAAAAAAAUw==
128 </data>
129 <key>StorageVersion</key>
130 <string>1.0</string>
131 <key>Version</key>
132 <string>3.0</string>
133 <key>AuthVersion</key>
134 <string>1.0</string>
135 <key>IsEncrypted</key>
136 <false/>
137</dict>
138*/
139 return ret;
140}
141
142/**
143 * Generates a manifest data plist with all files and corresponding hashes
144 */
145static plist_t mobilebackup_factory_manifest_data_plist()
146{
147 plist_t ret = NULL;
148 plist_t value_node = NULL;
149 char *uuid = NULL;
150 GTimeVal tv = {0, 0};
151
152 ret = plist_new_dict();
153
154 /* get basic device information in one go */
155 lockdownd_get_value(client, NULL, "IntegratedCircuitCardIdentity", &value_node);
156
157 iphone_device_get_uuid(phone, &uuid);
158 plist_dict_insert_item(ret, "DeviceId", plist_new_string(uuid));
159 free(uuid);
160
161 plist_dict_insert_item(ret, "Version", plist_new_string("6.2"));
162
163 /* TODO: add all Applications */
164
165 /* TODO: add all Files */
166 plist_t files = plist_new_dict();
167
168 /* single file entry */
169 plist_t info_node = plist_new_dict();
170 g_get_current_time(&tv);
171 plist_dict_insert_item(info_node, "ModificationTime", plist_new_date(tv.tv_sec, tv.tv_usec));
172 plist_dict_insert_item(info_node, "FileLength", plist_new_uint(131072));
173 plist_dict_insert_item(info_node, "Domain", plist_new_string("HomeDomain"));
174
175 /* FIXME: calculate correct data hash */
176 /* Data hash is: sha1(<file>) */
177 plist_dict_insert_item(info_node, "DataHash", plist_new_data(NULL, 0));
178 plist_dict_insert_item(info_node, "Group ID", plist_new_uint(501));
179 plist_dict_insert_item(info_node, "User ID", plist_new_uint(501));
180 plist_dict_insert_item(info_node, "Mode ID", plist_new_uint(420));
181
182 /* FIXME: calculate correct file hash */
183 /* File hash is: sha1(<Domain>-<Relative File Path>) */
184 plist_dict_insert_item(files, "3d0d7e5fb2ce288813306e4d4636395e047a3d28", info_node);
185 plist_dict_insert_item(ret, "Files", files);
186
187 /* last node with ICCID */
188 if (value_node)
189 plist_dict_insert_item(ret, "DeviceICCID", &value_node);
190
191 return ret;
192}
193
194/**
195 * Generates a manifest plist with all needed information and hashes
196 */
197static plist_t mobilebackup_factory_manifest_plist(plist_t manifest_data)
198{
199 char *buffer = NULL;
200 char *s = NULL;
201 uint32_t length;
202 unsigned char sha1[20];
203 gsize sha1_len;
204 GChecksum *checksum;
205 plist_t ret = NULL;
206
207 if (!manifest_data)
208 return ret;
209
210 ret = plist_new_dict();
211 plist_dict_insert_item(ret, "AuthVersion", plist_new_string("2.0"));
212
213 /* AuthSignature Hash is: sha1(<manifest_data>) */
214 plist_to_bin(manifest_data, &buffer, &length);
215
216 sha1_len = g_checksum_type_get_length(G_CHECKSUM_SHA1);
217 checksum = g_checksum_new(G_CHECKSUM_SHA1);
218 g_checksum_update(checksum, (guchar *)buffer, length);
219 g_checksum_get_digest(checksum, sha1, &sha1_len);
220 s = (char *)g_checksum_get_string(checksum);
221 printf("SHA1 AuthSignature: %s\n", s);
222 plist_dict_insert_item(ret, "AuthSignature", plist_new_data((char*)sha1, sha1_len));
223 g_checksum_free(checksum);
224
225
226 plist_dict_insert_item(ret, "IsEncrypted", plist_new_uint(0));
227 plist_dict_insert_item(ret, "Data", plist_new_data(buffer, length));
228
229 free(buffer);
230
231 return ret;
232}
233
234enum plist_format_t { 106enum plist_format_t {
235 PLIST_FORMAT_XML, 107 PLIST_FORMAT_XML,
236 PLIST_FORMAT_BINARY 108 PLIST_FORMAT_BINARY
237}; 109};
238 110
239static int plist_read_from_filename(char *filename, plist_t *plist) 111static void buffer_to_filename(char *filename, char *buffer, uint32_t length)
240{ 112{
241 return 1; 113 FILE *f;
114
115 f = fopen(filename, "ab");
116 fwrite(buffer, sizeof(char), length, f);
117 fclose(f);
242} 118}
243 119
244static int plist_write_to_filename(plist_t plist, char *filename, enum plist_format_t format) 120static int plist_write_to_filename(plist_t plist, char *filename, enum plist_format_t format)
245{ 121{
246 char *buffer = NULL; 122 char *buffer = NULL;
247 uint32_t length; 123 uint32_t length;
248 FILE *f;
249 124
250 if (!plist || !filename) 125 if (!plist || !filename)
251 return 0; 126 return 0;
@@ -257,9 +132,7 @@ static int plist_write_to_filename(plist_t plist, char *filename, enum plist_for
257 else 132 else
258 return 0; 133 return 0;
259 134
260 f = fopen(filename, "wb"); 135 buffer_to_filename(filename, buffer, length);
261 fwrite(buffer, sizeof(char), length, f);
262 fclose(f);
263 136
264 free(buffer); 137 free(buffer);
265 138
@@ -281,25 +154,50 @@ static int plist_strcmp(plist_t node, const char *str)
281 return ret; 154 return ret;
282} 155}
283 156
157static plist_t device_link_message_factory_process_message_new(plist_t content)
158{
159 plist_t ret = plist_new_array();
160 plist_array_append_item(ret, plist_new_string("DLMessageProcessMessage"));
161 plist_array_append_item(ret, content);
162 return ret;
163}
164
165static void mobilebackup_cancel_backup_with_error(const char *reason)
166{
167 plist_t node = plist_new_dict();
168 plist_dict_insert_item(node, "BackupMessageTypeKey", plist_new_string("BackupMessageError"));
169 plist_dict_insert_item(node, "BackupErrorReasonKey", plist_new_string(reason));
170
171 plist_t message = device_link_message_factory_process_message_new(node);
172
173 mobilebackup_send(mobilebackup, message);
174
175 plist_free(message);
176 message = NULL;
177}
178
284static void mobilebackup_write_status(char *path, int status) 179static void mobilebackup_write_status(char *path, int status)
285{ 180{
181 struct stat st;
286 plist_t status_plist = plist_new_dict(); 182 plist_t status_plist = plist_new_dict();
287 plist_dict_insert_item(status_plist, "Backup Success", plist_new_bool(status)); 183 plist_dict_insert_item(status_plist, "Backup Success", plist_new_bool(status));
288 char *file_path = g_build_path(G_DIR_SEPARATOR_S, path, "Status.plist", NULL); 184 char *file_path = g_build_path(G_DIR_SEPARATOR_S, path, "Status.plist", NULL);
185 if (stat(file_path, &st) == 0)
186 remove(file_path);
289 plist_write_to_filename(status_plist, file_path, PLIST_FORMAT_XML); 187 plist_write_to_filename(status_plist, file_path, PLIST_FORMAT_XML);
290 g_free(file_path); 188 g_free(file_path);
291 plist_free(status_plist); 189 plist_free(status_plist);
292} 190}
293 191
294static void debug_plist(plist_t plist) 192static void debug_plist(plist_t a)
295{ 193{
296 char *buffer = NULL; 194 char *buffer = NULL;
297 uint32_t length = 0; 195 uint32_t length = 0;
298 196
299 if (!plist) 197 if (a == NULL)
300 return; 198 return;
301 199
302 plist_to_xml(plist, &buffer, &length); 200 plist_to_xml(a, &buffer, &length);
303 201
304 printf("Printing %i bytes plist:\n%s\n", length, buffer); 202 printf("Printing %i bytes plist:\n%s\n", length, buffer);
305 free(buffer); 203 free(buffer);
@@ -341,6 +239,9 @@ int main(int argc, char *argv[])
341 char *backup_directory = NULL; 239 char *backup_directory = NULL;
342 struct stat st; 240 struct stat st;
343 plist_t node = NULL; 241 plist_t node = NULL;
242 plist_t node_tmp = NULL;
243 char *buffer = NULL;
244 uint64_t length = 0;
344 245
345 /* we need to exit cleanly on running backups and restores or we cause havok */ 246 /* we need to exit cleanly on running backups and restores or we cause havok */
346 signal(SIGINT, clean_exit); 247 signal(SIGINT, clean_exit);
@@ -440,6 +341,11 @@ int main(int argc, char *argv[])
440 printf("Started \"%s\" service on port %d.\n", MOBILEBACKUP_SERVICE_NAME, port); 341 printf("Started \"%s\" service on port %d.\n", MOBILEBACKUP_SERVICE_NAME, port);
441 mobilebackup_client_new(phone, port, &mobilebackup); 342 mobilebackup_client_new(phone, port, &mobilebackup);
442 343
344 if (quit_flag > 0) {
345 printf("Aborting backup. Cancelled by user.\n");
346 cmd = CMD_LEAVE;
347 }
348
443 switch(cmd) { 349 switch(cmd) {
444 case CMD_BACKUP: 350 case CMD_BACKUP:
445 printf("Starting backup...\n"); 351 printf("Starting backup...\n");
@@ -451,29 +357,32 @@ int main(int argc, char *argv[])
451 /* create Info.plist (Device infos, IC-Info.sidb, photos, app_ids, iTunesPrefs) */ 357 /* create Info.plist (Device infos, IC-Info.sidb, photos, app_ids, iTunesPrefs) */
452 printf("Creating \"%s/Info.plist\".\n", backup_directory); 358 printf("Creating \"%s/Info.plist\".\n", backup_directory);
453 plist_t info_plist = mobilebackup_factory_info_plist(); 359 plist_t info_plist = mobilebackup_factory_info_plist();
360 if (stat(info_path, &st) == 0)
361 remove(info_path);
454 plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML); 362 plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML);
455 g_free(info_path); 363 g_free(info_path);
456 364
365 if (client) {
366 lockdownd_client_free(client);
367 client = NULL;
368 }
369
457 /* create Manifest.plist (backup manifest (backup state)) */ 370 /* create Manifest.plist (backup manifest (backup state)) */
458 printf("Creating \"%s/Manifest.plist\".\n", backup_directory); 371 printf("Creating \"%s/Manifest.plist\".\n", backup_directory);
459 char *manifest_path = g_build_path(G_DIR_SEPARATOR_S, backup_directory, "Manifest.plist", NULL); 372 char *manifest_path = g_build_path(G_DIR_SEPARATOR_S, backup_directory, "Manifest.plist", NULL);
460 plist_t manifest_data = mobilebackup_factory_manifest_data_plist(); 373 plist_t manifest_plist = NULL;
461 plist_t manifest_plist = mobilebackup_factory_manifest_plist(manifest_data); 374 if (stat(manifest_path, &st) == 0)
462 plist_write_to_filename(manifest_plist, manifest_path, PLIST_FORMAT_XML); 375 remove(manifest_path);
463 g_free(manifest_path);
464 376
465 /* create Status.plist with failed status for now */ 377 /* create Status.plist with failed status for now */
466 mobilebackup_write_status(backup_directory, 0); 378 mobilebackup_write_status(backup_directory, 0);
467 379
468 /* close down lockdown connection as it is no longer needed */ 380 /* request backup from device with manifest from last backup */
469 lockdownd_client_free(client);
470 client = NULL;
471
472 /* request backup from device with manifest */
473 printf("Sending manifest and requesting backup.\n"); 381 printf("Sending manifest and requesting backup.\n");
474 382
475 node = plist_new_dict(); 383 node = plist_new_dict();
476 plist_dict_insert_item(node, "BackupManifestKey", manifest_plist); 384 if (manifest_plist)
385 plist_dict_insert_item(node, "BackupManifestKey", manifest_plist);
477 plist_dict_insert_item(node, "BackupComputerBasePathKey", plist_new_string("/")); 386 plist_dict_insert_item(node, "BackupComputerBasePathKey", plist_new_string("/"));
478 plist_dict_insert_item(node, "BackupMessageTypeKey", plist_new_string("BackupMessageBackupRequest")); 387 plist_dict_insert_item(node, "BackupMessageTypeKey", plist_new_string("BackupMessageBackupRequest"));
479 plist_dict_insert_item(node, "BackupProtocolVersion", plist_new_string("1.6")); 388 plist_dict_insert_item(node, "BackupProtocolVersion", plist_new_string("1.6"));
@@ -514,21 +423,66 @@ int main(int argc, char *argv[])
514 423
515 /* receive and save DLSendFile files and metadata, ACK each */ 424 /* receive and save DLSendFile files and metadata, ACK each */
516 int file_index = 0; 425 int file_index = 0;
426 char *file_path = NULL;
427 char *file_ext = NULL;
428 char *filename_mdinfo = NULL;
429 char *filename_mddata = NULL;
430 char *filename_source = NULL;
517 do { 431 do {
518 mobilebackup_receive(mobilebackup, &message); 432 mobilebackup_receive(mobilebackup, &message);
519 node = plist_array_get_item(message, 0); 433 node = plist_array_get_item(message, 0);
520 if (plist_strcmp(node, "DLSendFile")) 434 if (plist_strcmp(node, "DLSendFile"))
521 break; 435 break;
522 436
523 printf("Receiving file %d...\n", file_index); 437 /* get source filename and print it */
524 /* TODO: save <hash>.mdinfo */ 438 node_tmp = plist_array_get_item(message, 2);
525 /* TODO: save <hash>.mddata */ 439 node = plist_dict_get_item(node_tmp, "DLFileSource");
526 debug_plist(message); 440 plist_get_string_val(node, &filename_source);
441 printf("Received file %s...", filename_source);
442 free(filename_source);
443
444 /* save <hash>.mdinfo */
445 node = plist_dict_get_item(node_tmp, "BackupFileInfo");
446 if (node) {
447 node = plist_dict_get_item(node_tmp, "DLFileDest");
448 plist_get_string_val(node, &file_path);
449 file_ext = (char *)g_strconcat(file_path, ".mdinfo", NULL);
450 filename_mdinfo = g_build_path(G_DIR_SEPARATOR_S, backup_directory, file_ext, NULL);
451 node = plist_dict_get_item(node_tmp, "BackupFileInfo");
452 plist_write_to_filename(node, filename_mdinfo, PLIST_FORMAT_BINARY);
453 g_free(file_ext);
454 g_free(filename_mdinfo);
455 }
456
457 /* save <hash>.mddata */
458 node = plist_dict_get_item(node_tmp, "BackupFileInfo");
459 if (node_tmp && file_path) {
460 node = plist_dict_get_item(node_tmp, "DLFileDest");
461 plist_get_string_val(node, &file_path);
462 file_ext = (char *)g_strconcat(file_path, ".mddata", NULL);
463 filename_mddata = g_build_path(G_DIR_SEPARATOR_S, backup_directory, file_ext, NULL);
464 node_tmp = plist_array_get_item(message, 1);
465 plist_get_data_val(node_tmp, &buffer, &length);
466 buffer_to_filename(filename_mddata, buffer, length);
467 free(buffer);
468 buffer = NULL;
469 g_free(filename_mddata);
470 }
471
472 printf("DONE\n");
473
474 if (file_ext)
475 free(file_ext);
476
527 plist_free(message); 477 plist_free(message);
528 message = NULL; 478 message = NULL;
529 479
530 if (quit_flag) { 480 if (quit_flag > 0) {
531 /* FIXME: need to cancel the backup here */ 481 /* need to cancel the backup here */
482 mobilebackup_cancel_backup_with_error("Cancelling DLSendFile");
483
484 plist_free(message);
485 message = NULL;
532 break; 486 break;
533 } 487 }
534 488
@@ -550,17 +504,58 @@ int main(int argc, char *argv[])
550 printf("Received %d files from device.\n", file_index); 504 printf("Received %d files from device.\n", file_index);
551 505
552 if (!plist_strcmp(node, "DLMessageProcessMessage")) { 506 if (!plist_strcmp(node, "DLMessageProcessMessage")) {
553 node = plist_array_get_item(message, 1); 507 node_tmp = plist_array_get_item(message, 1);
554 node = plist_dict_get_item(node, "BackupMessageTypeKey"); 508 node = plist_dict_get_item(node_tmp, "BackupMessageTypeKey");
555 /* wait until received final backup finished message */ 509 /* wait until received final backup finished message */
556 if (node && !plist_strcmp(node, "BackupMessageBackupFinished")) { 510 if (node && !plist_strcmp(node, "BackupMessageBackupFinished")) {
557 /* backup finished */ 511 /* backup finished */
512
513 /* process BackupFilesToDeleteKey */
514 node = plist_dict_get_item(node_tmp, "BackupFilesToDeleteKey");
515 if (node) {
516 length = plist_array_get_size(node);
517 i = 0;
518 while ((node_tmp = plist_array_get_item(node, i++)) != NULL) {
519 plist_get_string_val(node_tmp, &file_path);
520
521 file_ext = (char *)g_strconcat(file_path, ".mddata", NULL);
522 filename_mddata = g_build_path(G_DIR_SEPARATOR_S, backup_directory, file_ext, NULL);
523 g_free(file_ext);
524 printf("Removing \"%s\"... ", filename_mddata);
525 if (!remove( filename_mddata )) {
526 printf("DONE\n");
527 } else
528 printf("FAILED\n");
529
530 file_ext = (char *)g_strconcat(file_path, ".mdinfo", NULL);
531 filename_mdinfo = g_build_path(G_DIR_SEPARATOR_S, backup_directory, file_ext, NULL);
532 g_free(file_ext);
533 printf("Removing \"%s\"... ", filename_mdinfo);
534 if (!remove( filename_mdinfo )) {
535 printf("DONE\n");
536 } else
537 printf("FAILED\n");
538 }
539 }
540
541 /* save new Manifest.plist */
542 node_tmp = plist_array_get_item(message, 1);
543 manifest_plist = plist_dict_get_item(node_tmp, "BackupManifestKey");
544 if (manifest_plist) {
545 if (stat(manifest_path, &st) != 0)
546 remove(manifest_path);
547 plist_write_to_filename(manifest_plist, manifest_path, PLIST_FORMAT_XML);
548 }
549
558 /* create: Status.plist (Info on how the backup process turned out) */ 550 /* create: Status.plist (Info on how the backup process turned out) */
559 printf("Backup Successful.\n"); 551 printf("Backup Successful.\n");
560 mobilebackup_write_status(backup_directory, 1); 552 mobilebackup_write_status(backup_directory, 1);
561 } 553 }
562 } 554 }
563 555
556 if (manifest_path)
557 g_free(manifest_path);
558
564 if (node) 559 if (node)
565 plist_free(node); 560 plist_free(node);
566 561
@@ -575,6 +570,7 @@ int main(int argc, char *argv[])
575 lockdownd_client_free(client); 570 lockdownd_client_free(client);
576 client = NULL; 571 client = NULL;
577 break; 572 break;
573 case CMD_LEAVE:
578 default: 574 default:
579 break; 575 break;
580 } 576 }
@@ -584,11 +580,14 @@ int main(int argc, char *argv[])
584 client = NULL; 580 client = NULL;
585 } 581 }
586 582
587 if (client) 583 if (client) {
588 lockdownd_client_free(client); 584 lockdownd_client_free(client);
585 client = NULL;
586 }
589 587
590 if (mobilebackup) 588 if (mobilebackup)
591 mobilebackup_client_free(mobilebackup); 589 mobilebackup_client_free(mobilebackup);
590
592 iphone_device_free(phone); 591 iphone_device_free(phone);
593 592
594 return 0; 593 return 0;