idevicebackup.c 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622
  1. /*
  2. * idevicebackup.c
  3. * Command line interface to use the device's backup and restore service
  4. *
  5. * Copyright (c) 2009-2010 Martin Szulecki All Rights Reserved.
  6. * Copyright (c) 2010 Nikias Bassen All Rights Reserved.
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2.1 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. */
  22. #ifdef HAVE_CONFIG_H
  23. #include <config.h>
  24. #endif
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <errno.h>
  28. #include <stdlib.h>
  29. #include <signal.h>
  30. #ifdef HAVE_OPENSSL
  31. #include <openssl/sha.h>
  32. #else
  33. #include <gcrypt.h>
  34. #endif
  35. #include <unistd.h>
  36. #include <ctype.h>
  37. #include <time.h>
  38. #include <libimobiledevice/libimobiledevice.h>
  39. #include <libimobiledevice/lockdown.h>
  40. #include <libimobiledevice/mobilebackup.h>
  41. #include <libimobiledevice/notification_proxy.h>
  42. #include <libimobiledevice/afc.h>
  43. #include "common/utils.h"
  44. #define MOBILEBACKUP_SERVICE_NAME "com.apple.mobilebackup"
  45. #define NP_SERVICE_NAME "com.apple.mobile.notification_proxy"
  46. #define LOCK_ATTEMPTS 50
  47. #define LOCK_WAIT 200000
  48. #ifdef WIN32
  49. #include <windows.h>
  50. #define sleep(x) Sleep(x*1000)
  51. #endif
  52. static mobilebackup_client_t mobilebackup = NULL;
  53. static lockdownd_client_t client = NULL;
  54. static idevice_t device = NULL;
  55. static int quit_flag = 0;
  56. enum cmd_mode {
  57. CMD_BACKUP,
  58. CMD_RESTORE,
  59. CMD_LEAVE
  60. };
  61. enum device_link_file_status_t {
  62. DEVICE_LINK_FILE_STATUS_NONE = 0,
  63. DEVICE_LINK_FILE_STATUS_HUNK,
  64. DEVICE_LINK_FILE_STATUS_LAST_HUNK
  65. };
  66. static void sha1_of_data(const char *input, uint32_t size, unsigned char *hash_out)
  67. {
  68. #ifdef HAVE_OPENSSL
  69. SHA1((const unsigned char*)input, size, hash_out);
  70. #else
  71. gcry_md_hash_buffer(GCRY_MD_SHA1, hash_out, input, size);
  72. #endif
  73. }
  74. static int compare_hash(const unsigned char *hash1, const unsigned char *hash2, int hash_len)
  75. {
  76. int i;
  77. for (i = 0; i < hash_len; i++) {
  78. if (hash1[i] != hash2[i]) {
  79. return 0;
  80. }
  81. }
  82. return 1;
  83. }
  84. 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. {
  86. #ifdef HAVE_OPENSSL
  87. SHA_CTX sha1;
  88. SHA1_Init(&sha1);
  89. #else
  90. gcry_md_hd_t hd = NULL;
  91. gcry_md_open(&hd, GCRY_MD_SHA1, 0);
  92. if (!hd) {
  93. printf("ERROR: Could not initialize libgcrypt/SHA1\n");
  94. return;
  95. }
  96. gcry_md_reset(hd);
  97. #endif
  98. FILE *f = fopen(path, "rb");
  99. if (f) {
  100. unsigned char buf[16384];
  101. size_t len;
  102. while ((len = fread(buf, 1, 16384, f)) > 0) {
  103. #ifdef HAVE_OPENSSL
  104. SHA1_Update(&sha1, buf, len);
  105. #else
  106. gcry_md_write(hd, buf, len);
  107. #endif
  108. }
  109. fclose(f);
  110. #ifdef HAVE_OPENSSL
  111. SHA1_Update(&sha1, destpath, strlen(destpath));
  112. SHA1_Update(&sha1, ";", 1);
  113. #else
  114. gcry_md_write(hd, destpath, strlen(destpath));
  115. gcry_md_write(hd, ";", 1);
  116. #endif
  117. if (greylist == 1) {
  118. #ifdef HAVE_OPENSSL
  119. SHA1_Update(&sha1, "true", 4);
  120. #else
  121. gcry_md_write(hd, "true", 4);
  122. #endif
  123. } else {
  124. #ifdef HAVE_OPENSSL
  125. SHA1_Update(&sha1, "false", 5);
  126. #else
  127. gcry_md_write(hd, "false", 5);
  128. #endif
  129. }
  130. #ifdef HAVE_OPENSSL
  131. SHA1_Update(&sha1, ";", 1);
  132. #else
  133. gcry_md_write(hd, ";", 1);
  134. #endif
  135. if (domain) {
  136. #ifdef HAVE_OPENSSL
  137. SHA1_Update(&sha1, domain, strlen(domain));
  138. #else
  139. gcry_md_write(hd, domain, strlen(domain));
  140. #endif
  141. } else {
  142. #ifdef HAVE_OPENSSL
  143. SHA1_Update(&sha1, "(null)", 6);
  144. #else
  145. gcry_md_write(hd, "(null)", 6);
  146. #endif
  147. }
  148. #ifdef HAVE_OPENSSL
  149. SHA1_Update(&sha1, ";", 1);
  150. #else
  151. gcry_md_write(hd, ";", 1);
  152. #endif
  153. if (appid) {
  154. #ifdef HAVE_OPENSSL
  155. SHA1_Update(&sha1, appid, strlen(appid));
  156. #else
  157. gcry_md_write(hd, appid, strlen(appid));
  158. #endif
  159. } else {
  160. #ifdef HAVE_OPENSSL
  161. SHA1_Update(&sha1, "(null)", 6);
  162. #else
  163. gcry_md_write(hd, "(null)", 6);
  164. #endif
  165. }
  166. #ifdef HAVE_OPENSSL
  167. SHA1_Update(&sha1, ";", 1);
  168. #else
  169. gcry_md_write(hd, ";", 1);
  170. #endif
  171. if (version) {
  172. #ifdef HAVE_OPENSSL
  173. SHA1_Update(&sha1, version, strlen(version));
  174. #else
  175. gcry_md_write(hd, version, strlen(version));
  176. #endif
  177. } else {
  178. #ifdef HAVE_OPENSSL
  179. SHA1_Update(&sha1, "(null)", 6);
  180. #else
  181. gcry_md_write(hd, "(null)", 6);
  182. #endif
  183. }
  184. #ifdef HAVE_OPENSSL
  185. SHA1_Final(hash_out, &sha1);
  186. #else
  187. unsigned char *newhash = gcry_md_read(hd, GCRY_MD_SHA1);
  188. memcpy(hash_out, newhash, 20);
  189. #endif
  190. }
  191. #ifndef HAVE_OPENSSL
  192. gcry_md_close(hd);
  193. #endif
  194. }
  195. static void print_hash(const unsigned char *hash, int len)
  196. {
  197. int i;
  198. for (i = 0; i < len; i++) {
  199. printf("%02x", hash[i]);
  200. }
  201. }
  202. static void notify_cb(const char *notification, void *userdata)
  203. {
  204. if (!strcmp(notification, NP_SYNC_CANCEL_REQUEST)) {
  205. printf("User has aborted on-device\n");
  206. quit_flag++;
  207. } else {
  208. printf("unhandled notification '%s' (TODO: implement)\n", notification);
  209. }
  210. }
  211. static plist_t mobilebackup_factory_info_plist_new(const char* udid)
  212. {
  213. /* gather data from lockdown */
  214. plist_t value_node = NULL;
  215. plist_t root_node = NULL;
  216. char *udid_uppercase = NULL;
  217. plist_t ret = plist_new_dict();
  218. /* get basic device information in one go */
  219. lockdownd_get_value(client, NULL, NULL, &root_node);
  220. /* set fields we understand */
  221. value_node = plist_dict_get_item(root_node, "BuildVersion");
  222. plist_dict_set_item(ret, "Build Version", plist_copy(value_node));
  223. value_node = plist_dict_get_item(root_node, "DeviceName");
  224. plist_dict_set_item(ret, "Device Name", plist_copy(value_node));
  225. plist_dict_set_item(ret, "Display Name", plist_copy(value_node));
  226. /* FIXME: How is the GUID generated? */
  227. plist_dict_set_item(ret, "GUID", plist_new_string("---"));
  228. value_node = plist_dict_get_item(root_node, "InternationalMobileEquipmentIdentity");
  229. if (value_node)
  230. plist_dict_set_item(ret, "IMEI", plist_copy(value_node));
  231. plist_dict_set_item(ret, "Last Backup Date", plist_new_date(time(NULL), 0));
  232. value_node = plist_dict_get_item(root_node, "ProductType");
  233. plist_dict_set_item(ret, "Product Type", plist_copy(value_node));
  234. value_node = plist_dict_get_item(root_node, "ProductVersion");
  235. plist_dict_set_item(ret, "Product Version", plist_copy(value_node));
  236. value_node = plist_dict_get_item(root_node, "SerialNumber");
  237. plist_dict_set_item(ret, "Serial Number", plist_copy(value_node));
  238. value_node = plist_dict_get_item(root_node, "UniqueDeviceID");
  239. plist_dict_set_item(ret, "Target Identifier", plist_new_string(udid));
  240. /* uppercase */
  241. udid_uppercase = string_toupper((char*)udid);
  242. plist_dict_set_item(ret, "Unique Identifier", plist_new_string(udid_uppercase));
  243. free(udid_uppercase);
  244. /* FIXME: Embed files as <data> nodes */
  245. plist_t files = plist_new_dict();
  246. plist_dict_set_item(ret, "iTunes Files", files);
  247. plist_dict_set_item(ret, "iTunes Version", plist_new_string("9.0.2"));
  248. plist_free(root_node);
  249. return ret;
  250. }
  251. static void mobilebackup_info_update_last_backup_date(plist_t info_plist)
  252. {
  253. plist_t node = NULL;
  254. if (!info_plist)
  255. return;
  256. node = plist_dict_get_item(info_plist, "Last Backup Date");
  257. plist_set_date_val(node, time(NULL), 0);
  258. node = NULL;
  259. }
  260. static int plist_strcmp(plist_t node, const char *str)
  261. {
  262. char *buffer = NULL;
  263. int ret = 0;
  264. if (plist_get_node_type(node) != PLIST_STRING)
  265. return ret;
  266. plist_get_string_val(node, &buffer);
  267. ret = strcmp(buffer, str);
  268. free(buffer);
  269. return ret;
  270. }
  271. static char *mobilebackup_build_path(const char *backup_directory, const char *name, const char *extension)
  272. {
  273. char* filename = (char*)malloc(strlen(name)+(extension == NULL ? 0: strlen(extension))+1);
  274. strcpy(filename, name);
  275. if (extension != NULL)
  276. strcat(filename, extension);
  277. char *path = string_build_path(backup_directory, filename, NULL);
  278. free(filename);
  279. return path;
  280. }
  281. static void mobilebackup_write_status(const char *path, int status)
  282. {
  283. struct stat st;
  284. plist_t status_plist = plist_new_dict();
  285. plist_dict_set_item(status_plist, "Backup Success", plist_new_bool(status));
  286. char *file_path = mobilebackup_build_path(path, "Status", ".plist");
  287. if (stat(file_path, &st) == 0)
  288. remove(file_path);
  289. plist_write_to_filename(status_plist, file_path, PLIST_FORMAT_XML);
  290. plist_free(status_plist);
  291. status_plist = NULL;
  292. free(file_path);
  293. }
  294. static int mobilebackup_read_status(const char *path)
  295. {
  296. int ret = -1;
  297. plist_t status_plist = NULL;
  298. char *file_path = mobilebackup_build_path(path, "Status", ".plist");
  299. plist_read_from_filename(&status_plist, file_path);
  300. free(file_path);
  301. if (!status_plist) {
  302. printf("Could not read Status.plist!\n");
  303. return ret;
  304. }
  305. plist_t node = plist_dict_get_item(status_plist, "Backup Success");
  306. if (node && (plist_get_node_type(node) == PLIST_BOOLEAN)) {
  307. uint8_t bval = 0;
  308. plist_get_bool_val(node, &bval);
  309. ret = bval;
  310. } else {
  311. printf("%s: ERROR could not get Backup Success key from Status.plist!\n", __func__);
  312. }
  313. plist_free(status_plist);
  314. return ret;
  315. }
  316. static int mobilebackup_info_is_current_device(plist_t info)
  317. {
  318. plist_t value_node = NULL;
  319. plist_t node = NULL;
  320. plist_t root_node = NULL;
  321. int ret = 0;
  322. if (!info)
  323. return ret;
  324. if (plist_get_node_type(info) != PLIST_DICT)
  325. return ret;
  326. /* get basic device information in one go */
  327. lockdownd_get_value(client, NULL, NULL, &root_node);
  328. /* verify UDID */
  329. value_node = plist_dict_get_item(root_node, "UniqueDeviceID");
  330. node = plist_dict_get_item(info, "Target Identifier");
  331. if(plist_compare_node_value(value_node, node))
  332. ret = 1;
  333. else {
  334. printf("Info.plist: UniqueDeviceID does not match.\n");
  335. }
  336. /* verify SerialNumber */
  337. if (ret == 1) {
  338. value_node = plist_dict_get_item(root_node, "SerialNumber");
  339. node = plist_dict_get_item(info, "Serial Number");
  340. if(plist_compare_node_value(value_node, node))
  341. ret = 1;
  342. else {
  343. printf("Info.plist: SerialNumber does not match.\n");
  344. ret = 0;
  345. }
  346. }
  347. /* verify ProductVersion to prevent using backup with different OS version */
  348. if (ret == 1) {
  349. value_node = plist_dict_get_item(root_node, "ProductVersion");
  350. node = plist_dict_get_item(info, "Product Version");
  351. if(plist_compare_node_value(value_node, node))
  352. ret = 1;
  353. else {
  354. printf("Info.plist: ProductVersion does not match.\n");
  355. ret = 0;
  356. }
  357. }
  358. plist_free(root_node);
  359. root_node = NULL;
  360. value_node = NULL;
  361. node = NULL;
  362. return ret;
  363. }
  364. static int mobilebackup_delete_backup_file_by_hash(const char *backup_directory, const char *hash)
  365. {
  366. int ret = 0;
  367. char *path = mobilebackup_build_path(backup_directory, hash, ".mddata");
  368. printf("Removing \"%s\" ", path);
  369. if (!remove( path ))
  370. ret = 1;
  371. else
  372. ret = 0;
  373. free(path);
  374. if (!ret)
  375. return ret;
  376. path = mobilebackup_build_path(backup_directory, hash, ".mdinfo");
  377. printf("and \"%s\"... ", path);
  378. if (!remove( path ))
  379. ret = 1;
  380. else
  381. ret = 0;
  382. free(path);
  383. return ret;
  384. }
  385. static int mobilebackup_check_file_integrity(const char *backup_directory, const char *hash, plist_t filedata)
  386. {
  387. char *datapath;
  388. char *infopath;
  389. plist_t mdinfo = NULL;
  390. struct stat st;
  391. unsigned char file_hash[20];
  392. datapath = mobilebackup_build_path(backup_directory, hash, ".mddata");
  393. if (stat(datapath, &st) != 0) {
  394. printf("\r\n");
  395. printf("ERROR: '%s.mddata' is missing!\n", hash);
  396. free(datapath);
  397. return 0;
  398. }
  399. infopath = mobilebackup_build_path(backup_directory, hash, ".mdinfo");
  400. plist_read_from_filename(&mdinfo, infopath);
  401. free(infopath);
  402. if (!mdinfo) {
  403. printf("\r\n");
  404. printf("ERROR: '%s.mdinfo' is missing or corrupted!\n", hash);
  405. free(datapath);
  406. return 0;
  407. }
  408. /* sha1 hash verification */
  409. plist_t node = plist_dict_get_item(filedata, "DataHash");
  410. if (!node || (plist_get_node_type(node) != PLIST_DATA)) {
  411. printf("\r\n");
  412. printf("ERROR: Could not get DataHash for file entry '%s'\n", hash);
  413. plist_free(mdinfo);
  414. free(datapath);
  415. return 0;
  416. }
  417. node = plist_dict_get_item(mdinfo, "Metadata");
  418. if (!node && (plist_get_node_type(node) != PLIST_DATA)) {
  419. printf("\r\n");
  420. printf("ERROR: Could not find Metadata in plist '%s.mdinfo'\n", hash);
  421. plist_free(mdinfo);
  422. free(datapath);
  423. return 0;
  424. }
  425. char *meta_bin = NULL;
  426. uint64_t meta_bin_size = 0;
  427. plist_get_data_val(node, &meta_bin, &meta_bin_size);
  428. plist_t metadata = NULL;
  429. if (meta_bin) {
  430. plist_from_bin(meta_bin, (uint32_t)meta_bin_size, &metadata);
  431. }
  432. if (!metadata) {
  433. printf("\r\n");
  434. printf("ERROR: Could not get Metadata from plist '%s.mdinfo'\n", hash);
  435. plist_free(mdinfo);
  436. free(datapath);
  437. return 0;
  438. }
  439. char *version = NULL;
  440. node = plist_dict_get_item(metadata, "Version");
  441. if (node && (plist_get_node_type(node) == PLIST_STRING)) {
  442. plist_get_string_val(node, &version);
  443. }
  444. char *destpath = NULL;
  445. node = plist_dict_get_item(metadata, "Path");
  446. if (node && (plist_get_node_type(node) == PLIST_STRING)) {
  447. plist_get_string_val(node, &destpath);
  448. }
  449. uint8_t greylist = 0;
  450. node = plist_dict_get_item(metadata, "Greylist");
  451. if (node && (plist_get_node_type(node) == PLIST_BOOLEAN)) {
  452. plist_get_bool_val(node, &greylist);
  453. }
  454. char *domain = NULL;
  455. node = plist_dict_get_item(metadata, "Domain");
  456. if (node && (plist_get_node_type(node) == PLIST_STRING)) {
  457. plist_get_string_val(node, &domain);
  458. }
  459. char *fnstr = malloc(strlen(domain) + 1 + strlen(destpath) + 1);
  460. strcpy(fnstr, domain);
  461. strcat(fnstr, "-");
  462. strcat(fnstr, destpath);
  463. unsigned char fnhash[20];
  464. char fnamehash[41];
  465. char *p = fnamehash;
  466. sha1_of_data(fnstr, strlen(fnstr), fnhash);
  467. free(fnstr);
  468. int i;
  469. for ( i = 0; i < 20; i++, p += 2 ) {
  470. snprintf (p, 3, "%02x", (unsigned char)fnhash[i] );
  471. }
  472. if (strcmp(fnamehash, hash)) {
  473. printf("\r\n");
  474. printf("WARNING: filename hash does not match for entry '%s'\n", hash);
  475. }
  476. char *auth_version = NULL;
  477. node = plist_dict_get_item(mdinfo, "AuthVersion");
  478. if (node && (plist_get_node_type(node) == PLIST_STRING)) {
  479. plist_get_string_val(node, &auth_version);
  480. }
  481. if (strcmp(auth_version, "1.0")) {
  482. printf("\r\n");
  483. printf("WARNING: Unknown AuthVersion '%s', DataHash cannot be verified!\n", auth_version);
  484. }
  485. node = plist_dict_get_item(filedata, "DataHash");
  486. if (!node || (plist_get_node_type(node) != PLIST_DATA)) {
  487. printf("\r\n");
  488. printf("WARNING: Could not get DataHash key from file info data for entry '%s'\n", hash);
  489. }
  490. int res = 1;
  491. unsigned char *data_hash = NULL;
  492. uint64_t data_hash_len = 0;
  493. plist_get_data_val(node, (char**)&data_hash, &data_hash_len);
  494. int hash_ok = 0;
  495. if (data_hash && (data_hash_len == 20)) {
  496. compute_datahash(datapath, destpath, greylist, domain, NULL, version, file_hash);
  497. hash_ok = compare_hash(data_hash, file_hash, 20);
  498. } else if (data_hash_len == 0) {
  499. /* no datahash present */
  500. hash_ok = 1;
  501. }
  502. free(domain);
  503. free(version);
  504. free(destpath);
  505. if (!hash_ok) {
  506. printf("\r\n");
  507. printf("ERROR: The hash for '%s.mddata' does not match DataHash entry in Manifest\n", hash);
  508. printf("datahash: ");
  509. print_hash(data_hash, 20);
  510. printf("\nfilehash: ");
  511. print_hash(file_hash, 20);
  512. printf("\n");
  513. res = 0;
  514. }
  515. free(data_hash);
  516. plist_free(mdinfo);
  517. return res;
  518. }
  519. static void do_post_notification(const char *notification)
  520. {
  521. lockdownd_service_descriptor_t service = NULL;
  522. np_client_t np;
  523. if (!client) {
  524. if (lockdownd_client_new_with_handshake(device, &client, "idevicebackup") != LOCKDOWN_E_SUCCESS) {
  525. return;
  526. }
  527. }
  528. lockdownd_start_service(client, NP_SERVICE_NAME, &service);
  529. if (service && service->port) {
  530. np_client_new(device, service, &np);
  531. if (np) {
  532. np_post_notification(np, notification);
  533. np_client_free(np);
  534. }
  535. } else {
  536. printf("Could not start %s\n", NP_SERVICE_NAME);
  537. }
  538. if (service) {
  539. lockdownd_service_descriptor_free(service);
  540. service = NULL;
  541. }
  542. }
  543. static void print_progress(double progress)
  544. {
  545. int i = 0;
  546. if (progress < 0)
  547. return;
  548. if (progress > 100)
  549. progress = 100;
  550. printf("\r[");
  551. for(i = 0; i < 50; i++) {
  552. if(i < progress / 2) {
  553. printf("=");
  554. } else {
  555. printf(" ");
  556. }
  557. }
  558. printf("] %3.0f%%", progress);
  559. fflush(stdout);
  560. if (progress == 100)
  561. printf("\n");
  562. }
  563. /**
  564. * signal handler function for cleaning up properly
  565. */
  566. static void clean_exit(int sig)
  567. {
  568. fprintf(stderr, "Exiting...\n");
  569. quit_flag++;
  570. }
  571. static void print_usage(int argc, char **argv)
  572. {
  573. char *name = NULL;
  574. name = strrchr(argv[0], '/');
  575. printf("Usage: %s [OPTIONS] CMD [DIRECTORY]\n", (name ? name + 1: argv[0]));
  576. printf("Create or restore backup from the current or specified directory.\n\n");
  577. printf("commands:\n");
  578. printf(" backup\tSaves a device backup into DIRECTORY\n");
  579. printf(" restore\tRestores a device backup from DIRECTORY.\n\n");
  580. printf("options:\n");
  581. printf(" -d, --debug\t\tenable communication debugging\n");
  582. printf(" -u, --udid UDID\ttarget specific device by its 40-digit device UDID\n");
  583. printf(" -h, --help\t\tprints usage information\n");
  584. printf("\n");
  585. printf("Homepage: <http://libimobiledevice.org>\n");
  586. }
  587. int main(int argc, char *argv[])
  588. {
  589. idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
  590. lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR;
  591. int i;
  592. char* udid = NULL;
  593. lockdownd_service_descriptor_t service = NULL;
  594. int cmd = -1;
  595. int is_full_backup = 0;
  596. char *backup_directory = NULL;
  597. struct stat st;
  598. plist_t node = NULL;
  599. plist_t node_tmp = NULL;
  600. plist_t manifest_plist = NULL;
  601. plist_t info_plist = NULL;
  602. char *buffer = NULL;
  603. char *file_path = NULL;
  604. uint64_t length = 0;
  605. uint64_t backup_total_size = 0;
  606. enum device_link_file_status_t file_status = DEVICE_LINK_FILE_STATUS_NONE;
  607. uint64_t c = 0;
  608. /* we need to exit cleanly on running backups and restores or we cause havok */
  609. signal(SIGINT, clean_exit);
  610. signal(SIGTERM, clean_exit);
  611. #ifndef WIN32
  612. signal(SIGQUIT, clean_exit);
  613. signal(SIGPIPE, SIG_IGN);
  614. #endif
  615. /* parse cmdline args */
  616. for (i = 1; i < argc; i++) {
  617. if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
  618. idevice_set_debug_level(1);
  619. continue;
  620. }
  621. else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) {
  622. i++;
  623. if (!argv[i] || (strlen(argv[i]) != 40)) {
  624. print_usage(argc, argv);
  625. return 0;
  626. }
  627. udid = strdup(argv[i]);
  628. continue;
  629. }
  630. else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
  631. print_usage(argc, argv);
  632. return 0;
  633. }
  634. else if (!strcmp(argv[i], "backup")) {
  635. cmd = CMD_BACKUP;
  636. }
  637. else if (!strcmp(argv[i], "restore")) {
  638. cmd = CMD_RESTORE;
  639. }
  640. else if (backup_directory == NULL) {
  641. backup_directory = argv[i];
  642. }
  643. else {
  644. print_usage(argc, argv);
  645. return 0;
  646. }
  647. }
  648. /* verify options */
  649. if (cmd == -1) {
  650. printf("No command specified.\n");
  651. print_usage(argc, argv);
  652. return -1;
  653. }
  654. if (backup_directory == NULL) {
  655. printf("No target backup directory specified.\n");
  656. print_usage(argc, argv);
  657. return -1;
  658. }
  659. /* verify if passed backup directory exists */
  660. if (stat(backup_directory, &st) != 0) {
  661. printf("ERROR: Backup directory \"%s\" does not exist!\n", backup_directory);
  662. return -1;
  663. }
  664. /* restore directory must contain an Info.plist */
  665. char *info_path = mobilebackup_build_path(backup_directory, "Info", ".plist");
  666. if (cmd == CMD_RESTORE) {
  667. if (stat(info_path, &st) != 0) {
  668. free(info_path);
  669. printf("ERROR: Backup directory \"%s\" is invalid. No Info.plist found.\n", backup_directory);
  670. return -1;
  671. }
  672. }
  673. printf("Backup directory is \"%s\"\n", backup_directory);
  674. if (udid) {
  675. ret = idevice_new(&device, udid);
  676. if (ret != IDEVICE_E_SUCCESS) {
  677. printf("No device found with udid %s, is it plugged in?\n", udid);
  678. return -1;
  679. }
  680. }
  681. else
  682. {
  683. ret = idevice_new(&device, NULL);
  684. if (ret != IDEVICE_E_SUCCESS) {
  685. printf("No device found, is it plugged in?\n");
  686. return -1;
  687. }
  688. }
  689. if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &client, "idevicebackup"))) {
  690. printf("ERROR: Could not connect to lockdownd, error code %d\n", ldret);
  691. idevice_free(device);
  692. return -1;
  693. }
  694. node = NULL;
  695. lockdownd_get_value(client, NULL, "ProductVersion", &node);
  696. if (node) {
  697. char* str = NULL;
  698. if (plist_get_node_type(node) == PLIST_STRING) {
  699. plist_get_string_val(node, &str);
  700. }
  701. plist_free(node);
  702. node = NULL;
  703. if (str) {
  704. int maj = strtol(str, NULL, 10);
  705. free(str);
  706. if (maj > 3) {
  707. printf("ERROR: This tool is only compatible with iOS 3 or below. For newer iOS versions please use the idevicebackup2 tool.\n");
  708. lockdownd_client_free(client);
  709. idevice_free(device);
  710. return -1;
  711. }
  712. }
  713. }
  714. /* start notification_proxy */
  715. np_client_t np = NULL;
  716. ldret = lockdownd_start_service(client, NP_SERVICE_NAME, &service);
  717. if ((ldret == LOCKDOWN_E_SUCCESS) && service && service->port) {
  718. np_client_new(device, service, &np);
  719. np_set_notify_callback(np, notify_cb, NULL);
  720. const char *noties[5] = {
  721. NP_SYNC_CANCEL_REQUEST,
  722. NP_SYNC_SUSPEND_REQUEST,
  723. NP_SYNC_RESUME_REQUEST,
  724. NP_BACKUP_DOMAIN_CHANGED,
  725. NULL
  726. };
  727. np_observe_notifications(np, noties);
  728. } else {
  729. printf("ERROR: Could not start service %s.\n", NP_SERVICE_NAME);
  730. }
  731. afc_client_t afc = NULL;
  732. if (cmd == CMD_BACKUP) {
  733. /* start AFC, we need this for the lock file */
  734. service->port = 0;
  735. service->ssl_enabled = 0;
  736. ldret = lockdownd_start_service(client, "com.apple.afc", &service);
  737. if ((ldret == LOCKDOWN_E_SUCCESS) && service->port) {
  738. afc_client_new(device, service, &afc);
  739. }
  740. }
  741. if (service) {
  742. lockdownd_service_descriptor_free(service);
  743. service = NULL;
  744. }
  745. /* start mobilebackup service and retrieve port */
  746. ldret = lockdownd_start_service(client, MOBILEBACKUP_SERVICE_NAME, &service);
  747. if ((ldret == LOCKDOWN_E_SUCCESS) && service && service->port) {
  748. printf("Started \"%s\" service on port %d.\n", MOBILEBACKUP_SERVICE_NAME, service->port);
  749. mobilebackup_client_new(device, service, &mobilebackup);
  750. if (service) {
  751. lockdownd_service_descriptor_free(service);
  752. service = NULL;
  753. }
  754. /* check abort conditions */
  755. if (quit_flag > 0) {
  756. printf("Aborting backup. Cancelled by user.\n");
  757. cmd = CMD_LEAVE;
  758. }
  759. /* verify existing Info.plist */
  760. if (stat(info_path, &st) == 0) {
  761. printf("Reading Info.plist from backup.\n");
  762. plist_read_from_filename(&info_plist, info_path);
  763. if (!info_plist) {
  764. printf("Could not read Info.plist\n");
  765. is_full_backup = 1;
  766. }
  767. if (info_plist && (cmd == CMD_BACKUP)) {
  768. if (mobilebackup_info_is_current_device(info_plist)) {
  769. /* update the last backup time within Info.plist */
  770. mobilebackup_info_update_last_backup_date(info_plist);
  771. remove(info_path);
  772. plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML);
  773. } else {
  774. printf("Aborting backup. Backup is not compatible with the current device.\n");
  775. cmd = CMD_LEAVE;
  776. }
  777. } else if (info_plist && (cmd == CMD_RESTORE)) {
  778. if (!mobilebackup_info_is_current_device(info_plist)) {
  779. printf("Aborting restore. Backup data is not compatible with the current device.\n");
  780. cmd = CMD_LEAVE;
  781. }
  782. }
  783. } else {
  784. if (cmd == CMD_RESTORE) {
  785. printf("Aborting restore. Info.plist is missing.\n");
  786. cmd = CMD_LEAVE;
  787. } else {
  788. is_full_backup = 1;
  789. }
  790. }
  791. uint64_t lockfile = 0;
  792. if (cmd == CMD_BACKUP) {
  793. do_post_notification(NP_SYNC_WILL_START);
  794. afc_file_open(afc, "/com.apple.itunes.lock_sync", AFC_FOPEN_RW, &lockfile);
  795. }
  796. if (lockfile) {
  797. afc_error_t aerr;
  798. do_post_notification(NP_SYNC_LOCK_REQUEST);
  799. for (i = 0; i < LOCK_ATTEMPTS; i++) {
  800. aerr = afc_file_lock(afc, lockfile, AFC_LOCK_EX);
  801. if (aerr == AFC_E_SUCCESS) {
  802. do_post_notification(NP_SYNC_DID_START);
  803. break;
  804. } else if (aerr == AFC_E_OP_WOULD_BLOCK) {
  805. usleep(LOCK_WAIT);
  806. continue;
  807. } else {
  808. fprintf(stderr, "ERROR: could not lock file! error code: %d\n", aerr);
  809. afc_file_close(afc, lockfile);
  810. lockfile = 0;
  811. cmd = CMD_LEAVE;
  812. }
  813. }
  814. if (i == LOCK_ATTEMPTS) {
  815. fprintf(stderr, "ERROR: timeout while locking for sync\n");
  816. afc_file_close(afc, lockfile);
  817. lockfile = 0;
  818. cmd = CMD_LEAVE;
  819. }
  820. }
  821. mobilebackup_error_t err;
  822. /* Manifest.plist (backup manifest (backup state)) */
  823. char *manifest_path = mobilebackup_build_path(backup_directory, "Manifest", ".plist");
  824. switch(cmd) {
  825. case CMD_BACKUP:
  826. printf("Starting backup...\n");
  827. /* TODO: check domain com.apple.mobile.backup key RequiresEncrypt and WillEncrypt with lockdown */
  828. /* TODO: verify battery on AC enough battery remaining */
  829. /* read the last Manifest.plist */
  830. if (!is_full_backup) {
  831. printf("Reading existing Manifest.\n");
  832. plist_read_from_filename(&manifest_plist, manifest_path);
  833. if (!manifest_plist) {
  834. printf("Could not read Manifest.plist, switching to full backup mode.\n");
  835. is_full_backup = 1;
  836. }
  837. }
  838. /* Info.plist (Device infos, IC-Info.sidb, photos, app_ids, iTunesPrefs) */
  839. /* create new Info.plist on new backups */
  840. if (is_full_backup) {
  841. if (info_plist) {
  842. plist_free(info_plist);
  843. info_plist = NULL;
  844. }
  845. remove(info_path);
  846. printf("Creating Info.plist for new backup.\n");
  847. info_plist = mobilebackup_factory_info_plist_new(udid);
  848. plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML);
  849. }
  850. free(info_path);
  851. plist_free(info_plist);
  852. info_plist = NULL;
  853. /* close down the lockdown connection as it is no longer needed */
  854. if (client) {
  855. lockdownd_client_free(client);
  856. client = NULL;
  857. }
  858. /* create Status.plist with failed status for now */
  859. mobilebackup_write_status(backup_directory, 0);
  860. /* request backup from device with manifest from last backup */
  861. printf("Requesting backup from device...\n");
  862. err = mobilebackup_request_backup(mobilebackup, manifest_plist, "/", "1.6");
  863. if (err == MOBILEBACKUP_E_SUCCESS) {
  864. if (is_full_backup)
  865. printf("Full backup mode.\n");
  866. else
  867. printf("Incremental backup mode.\n");
  868. printf("Please wait. Device is preparing backup data...\n");
  869. } else {
  870. if (err == MOBILEBACKUP_E_BAD_VERSION) {
  871. printf("ERROR: Could not start backup process: backup protocol version mismatch!\n");
  872. } else if (err == MOBILEBACKUP_E_REPLY_NOT_OK) {
  873. printf("ERROR: Could not start backup process: device refused to start the backup process.\n");
  874. } else {
  875. printf("ERROR: Could not start backup process: unspecified error occured\n");
  876. }
  877. break;
  878. }
  879. /* reset backup status */
  880. int backup_ok = 0;
  881. plist_t message = NULL;
  882. /* receive and save DLSendFile files and metadata, ACK each */
  883. uint64_t file_size = 0;
  884. uint64_t file_size_current = 0;
  885. int file_index = 0;
  886. int hunk_index = 0;
  887. uint64_t backup_real_size = 0;
  888. char *file_ext = NULL;
  889. char *filename_mdinfo = NULL;
  890. char *filename_mddata = NULL;
  891. char *filename_source = NULL;
  892. char *format_size = NULL;
  893. int is_manifest = 0;
  894. uint8_t b = 0;
  895. /* process series of DLSendFile messages */
  896. do {
  897. mobilebackup_receive(mobilebackup, &message);
  898. if (!message) {
  899. printf("Device is not ready yet. Going to try again in 2 seconds...\n");
  900. sleep(2);
  901. goto files_out;
  902. }
  903. node = plist_array_get_item(message, 0);
  904. /* get out if we don't get a DLSendFile */
  905. if (plist_strcmp(node, "DLSendFile"))
  906. break;
  907. node_tmp = plist_array_get_item(message, 2);
  908. /* first message hunk contains total backup size */
  909. if ((hunk_index == 0) && (file_index == 0)) {
  910. node = plist_dict_get_item(node_tmp, "BackupTotalSizeKey");
  911. if (node) {
  912. plist_get_uint_val(node, &backup_total_size);
  913. format_size = string_format_size(backup_total_size);
  914. printf("Backup data requires %s on the disk.\n", format_size);
  915. free(format_size);
  916. }
  917. }
  918. /* check DLFileStatusKey (codes: 1 = Hunk, 2 = Last Hunk) */
  919. node = plist_dict_get_item(node_tmp, "DLFileStatusKey");
  920. plist_get_uint_val(node, &c);
  921. file_status = c;
  922. /* get source filename */
  923. node = plist_dict_get_item(node_tmp, "BackupManifestKey");
  924. b = 0;
  925. if (node) {
  926. plist_get_bool_val(node, &b);
  927. }
  928. is_manifest = (b == 1) ? 1 : 0;
  929. if ((hunk_index == 0) && (!is_manifest)) {
  930. /* get source filename */
  931. node = plist_dict_get_item(node_tmp, "DLFileSource");
  932. plist_get_string_val(node, &filename_source);
  933. /* increase received size */
  934. node = plist_dict_get_item(node_tmp, "DLFileAttributesKey");
  935. node = plist_dict_get_item(node, "FileSize");
  936. plist_get_uint_val(node, &file_size);
  937. backup_real_size += file_size;
  938. format_size = string_format_size(backup_real_size);
  939. printf("(%s", format_size);
  940. free(format_size);
  941. format_size = string_format_size(backup_total_size);
  942. printf("/%s): ", format_size);
  943. free(format_size);
  944. format_size = string_format_size(file_size);
  945. printf("Receiving file %s (%s)... \n", filename_source, format_size);
  946. free(format_size);
  947. if (filename_source)
  948. free(filename_source);
  949. }
  950. /* check if we completed a file */
  951. if ((file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) && (!is_manifest)) {
  952. /* save <hash>.mdinfo */
  953. node = plist_dict_get_item(node_tmp, "BackupFileInfo");
  954. if (node) {
  955. node = plist_dict_get_item(node_tmp, "DLFileDest");
  956. plist_get_string_val(node, &file_path);
  957. filename_mdinfo = mobilebackup_build_path(backup_directory, file_path, ".mdinfo");
  958. /* remove any existing file */
  959. if (stat(filename_mdinfo, &st) == 0)
  960. remove(filename_mdinfo);
  961. node = plist_dict_get_item(node_tmp, "BackupFileInfo");
  962. plist_write_to_filename(node, filename_mdinfo, PLIST_FORMAT_BINARY);
  963. free(filename_mdinfo);
  964. }
  965. file_index++;
  966. }
  967. /* save <hash>.mddata */
  968. node = plist_dict_get_item(node_tmp, "BackupFileInfo");
  969. if (node_tmp) {
  970. node = plist_dict_get_item(node_tmp, "DLFileDest");
  971. plist_get_string_val(node, &file_path);
  972. filename_mddata = mobilebackup_build_path(backup_directory, file_path, is_manifest ? NULL: ".mddata");
  973. /* if this is the first hunk, remove any existing file */
  974. if ((hunk_index == 0) && (stat(filename_mddata, &st) == 0))
  975. remove(filename_mddata);
  976. /* get file data hunk */
  977. node_tmp = plist_array_get_item(message, 1);
  978. plist_get_data_val(node_tmp, &buffer, &length);
  979. buffer_write_to_filename(filename_mddata, buffer, length);
  980. if (!is_manifest)
  981. file_size_current += length;
  982. /* activate currently sent manifest */
  983. if ((file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) && (is_manifest)) {
  984. rename(filename_mddata, manifest_path);
  985. }
  986. free(buffer);
  987. buffer = NULL;
  988. free(filename_mddata);
  989. }
  990. if ((!is_manifest)) {
  991. if (hunk_index == 0 && file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) {
  992. print_progress(100);
  993. } else {
  994. if (file_size > 0)
  995. print_progress((double)((file_size_current*100)/file_size));
  996. }
  997. }
  998. hunk_index++;
  999. if (file_ext)
  1000. free(file_ext);
  1001. if (message)
  1002. plist_free(message);
  1003. message = NULL;
  1004. if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) {
  1005. /* acknowlegdge that we received the file */
  1006. mobilebackup_send_backup_file_received(mobilebackup);
  1007. /* reset hunk_index */
  1008. hunk_index = 0;
  1009. if (!is_manifest) {
  1010. file_size_current = 0;
  1011. file_size = 0;
  1012. }
  1013. }
  1014. files_out:
  1015. if (quit_flag > 0) {
  1016. /* need to cancel the backup here */
  1017. mobilebackup_send_error(mobilebackup, "Cancelling DLSendFile");
  1018. /* remove any atomic Manifest.plist.tmp */
  1019. if (manifest_path)
  1020. free(manifest_path);
  1021. manifest_path = mobilebackup_build_path(backup_directory, "Manifest", ".plist.tmp");
  1022. if (stat(manifest_path, &st) == 0)
  1023. remove(manifest_path);
  1024. break;
  1025. }
  1026. } while (1);
  1027. printf("Received %d files from device.\n", file_index);
  1028. if (!quit_flag && !plist_strcmp(node, "DLMessageProcessMessage")) {
  1029. node_tmp = plist_array_get_item(message, 1);
  1030. node = plist_dict_get_item(node_tmp, "BackupMessageTypeKey");
  1031. /* check if we received the final "backup finished" message */
  1032. if (node && !plist_strcmp(node, "BackupMessageBackupFinished")) {
  1033. /* backup finished */
  1034. /* process BackupFilesToDeleteKey */
  1035. node = plist_dict_get_item(node_tmp, "BackupFilesToDeleteKey");
  1036. if (node) {
  1037. length = plist_array_get_size(node);
  1038. i = 0;
  1039. while ((node_tmp = plist_array_get_item(node, i++)) != NULL) {
  1040. plist_get_string_val(node_tmp, &file_path);
  1041. if (mobilebackup_delete_backup_file_by_hash(backup_directory, file_path)) {
  1042. printf("DONE\n");
  1043. } else
  1044. printf("FAILED\n");
  1045. }
  1046. }
  1047. /* save last valid Manifest.plist */
  1048. node_tmp = plist_array_get_item(message, 1);
  1049. manifest_plist = plist_dict_get_item(node_tmp, "BackupManifestKey");
  1050. if (manifest_plist) {
  1051. remove(manifest_path);
  1052. printf("Storing Manifest.plist...\n");
  1053. plist_write_to_filename(manifest_plist, manifest_path, PLIST_FORMAT_XML);
  1054. }
  1055. backup_ok = 1;
  1056. }
  1057. }
  1058. if (backup_ok) {
  1059. /* Status.plist (Info on how the backup process turned out) */
  1060. printf("Backup Successful.\n");
  1061. mobilebackup_write_status(backup_directory, 1);
  1062. } else {
  1063. printf("Backup Failed.\n");
  1064. }
  1065. break;
  1066. case CMD_RESTORE:
  1067. /* close down the lockdown connection as it is no longer needed */
  1068. if (client) {
  1069. lockdownd_client_free(client);
  1070. client = NULL;
  1071. }
  1072. /* TODO: verify battery on AC enough battery remaining */
  1073. /* verify if Status.plist says we read from an successful backup */
  1074. if (mobilebackup_read_status(backup_directory) <= 0) {
  1075. printf("ERROR: Cannot ensure we restore from a successful backup. Aborting.\n");
  1076. break;
  1077. }
  1078. /* now make sure backup integrity is ok! verify all files */
  1079. printf("Reading existing Manifest.\n");
  1080. plist_read_from_filename(&manifest_plist, manifest_path);
  1081. if (!manifest_plist) {
  1082. printf("Could not read Manifest.plist. Aborting.\n");
  1083. break;
  1084. }
  1085. printf("Verifying backup integrity, please wait.\n");
  1086. char *bin = NULL;
  1087. uint64_t binsize = 0;
  1088. node = plist_dict_get_item(manifest_plist, "Data");
  1089. if (!node || (plist_get_node_type(node) != PLIST_DATA)) {
  1090. printf("Could not read Data key from Manifest.plist!\n");
  1091. break;
  1092. }
  1093. plist_get_data_val(node, &bin, &binsize);
  1094. plist_t backup_data = NULL;
  1095. if (bin) {
  1096. char *auth_ver = NULL;
  1097. unsigned char *auth_sig = NULL;
  1098. uint64_t auth_sig_len = 0;
  1099. /* verify AuthSignature */
  1100. node = plist_dict_get_item(manifest_plist, "AuthVersion");
  1101. plist_get_string_val(node, &auth_ver);
  1102. if (auth_ver && (strcmp(auth_ver, "2.0") == 0)) {
  1103. node = plist_dict_get_item(manifest_plist, "AuthSignature");
  1104. if (node && (plist_get_node_type(node) == PLIST_DATA)) {
  1105. plist_get_data_val(node, (char**)&auth_sig, &auth_sig_len);
  1106. }
  1107. if (auth_sig && (auth_sig_len == 20)) {
  1108. /* calculate the sha1, then compare */
  1109. unsigned char data_sha1[20];
  1110. sha1_of_data(bin, binsize, data_sha1);
  1111. if (compare_hash(auth_sig, data_sha1, 20)) {
  1112. printf("AuthSignature is valid\n");
  1113. } else {
  1114. printf("ERROR: AuthSignature is NOT VALID\n");
  1115. }
  1116. } else {
  1117. printf("Could not get AuthSignature from manifest!\n");
  1118. }
  1119. free(auth_sig);
  1120. } else if (auth_ver) {
  1121. printf("Unknown AuthVersion '%s', cannot verify AuthSignature\n", auth_ver);
  1122. }
  1123. plist_from_bin(bin, (uint32_t)binsize, &backup_data);
  1124. free(bin);
  1125. }
  1126. if (!backup_data) {
  1127. printf("Could not read plist from Manifest.plist Data key!\n");
  1128. break;
  1129. }
  1130. plist_t files = plist_dict_get_item(backup_data, "Files");
  1131. if (files && (plist_get_node_type(files) == PLIST_DICT)) {
  1132. plist_dict_iter iter = NULL;
  1133. plist_dict_new_iter(files, &iter);
  1134. if (iter) {
  1135. /* loop over Files entries in Manifest data plist */
  1136. char *hash = NULL;
  1137. int file_ok = 0;
  1138. int total_files = plist_dict_get_size(files);
  1139. int cur_file = 1;
  1140. node = NULL;
  1141. plist_dict_next_item(files, iter, &hash, &node);
  1142. while (node) {
  1143. printf("Verifying file %d/%d (%d%%) \r", cur_file, total_files, (cur_file*100/total_files));
  1144. cur_file++;
  1145. /* make sure both .mddata/.mdinfo files are available for each entry */
  1146. file_ok = mobilebackup_check_file_integrity(backup_directory, hash, node);
  1147. node = NULL;
  1148. free(hash);
  1149. hash = NULL;
  1150. if (!file_ok) {
  1151. break;
  1152. }
  1153. plist_dict_next_item(files, iter, &hash, &node);
  1154. }
  1155. printf("\n");
  1156. free(iter);
  1157. if (!file_ok) {
  1158. plist_free(backup_data);
  1159. break;
  1160. }
  1161. printf("All backup files appear to be valid\n");
  1162. }
  1163. }
  1164. printf("Requesting restore from device...\n");
  1165. /* request restore from device with manifest (BackupMessageRestoreMigrate) */
  1166. int restore_flags = MB_RESTORE_NOTIFY_SPRINGBOARD | MB_RESTORE_PRESERVE_SETTINGS | MB_RESTORE_PRESERVE_CAMERA_ROLL;
  1167. err = mobilebackup_request_restore(mobilebackup, manifest_plist, restore_flags, "1.6");
  1168. if (err != MOBILEBACKUP_E_SUCCESS) {
  1169. if (err == MOBILEBACKUP_E_BAD_VERSION) {
  1170. printf("ERROR: Could not start restore process: backup protocol version mismatch!\n");
  1171. } else if (err == MOBILEBACKUP_E_REPLY_NOT_OK) {
  1172. printf("ERROR: Could not start restore process: device refused to start the restore process.\n");
  1173. } else {
  1174. printf("ERROR: Could not start restore process: unspecified error occured (%d)\n", err);
  1175. }
  1176. plist_free(backup_data);
  1177. break;
  1178. }
  1179. printf("Entered restore mode.\n");
  1180. int restore_ok = 0;
  1181. if (files && (plist_get_node_type(files) == PLIST_DICT)) {
  1182. plist_dict_iter iter = NULL;
  1183. plist_dict_new_iter(files, &iter);
  1184. if (iter) {
  1185. /* loop over Files entries in Manifest data plist */
  1186. char *hash = NULL;
  1187. plist_t file_info = NULL;
  1188. char *file_info_path = NULL;
  1189. int total_files = plist_dict_get_size(files);
  1190. int cur_file = 0;
  1191. uint64_t file_offset = 0;
  1192. uint8_t is_encrypted = 0;
  1193. plist_t tmp_node = NULL;
  1194. plist_t file_path_node = NULL;
  1195. plist_t send_file_node = NULL;
  1196. node = NULL;
  1197. plist_dict_next_item(files, iter, &hash, &node);
  1198. while (node) {
  1199. /* TODO: read mddata/mdinfo files and send to device using DLSendFile */
  1200. file_info_path = mobilebackup_build_path(backup_directory, hash, ".mdinfo");
  1201. plist_read_from_filename(&file_info, file_info_path);
  1202. /* get encryption state */
  1203. tmp_node = plist_dict_get_item(file_info, "IsEncrypted");
  1204. plist_get_bool_val(tmp_node, &is_encrypted);
  1205. tmp_node = NULL;
  1206. /* get real file path from metadata */
  1207. tmp_node = plist_dict_get_item(file_info, "Metadata");
  1208. plist_get_data_val(tmp_node, &buffer, &length);
  1209. tmp_node = NULL;
  1210. plist_from_bin(buffer, length, &tmp_node);
  1211. file_path_node = plist_dict_get_item(tmp_node, "Path");
  1212. plist_get_string_val(file_path_node, &file_path);
  1213. printf("Restoring file %s %d/%d (%d%%)... ", file_path, cur_file, total_files, (cur_file*100/total_files));
  1214. /* add additional device link file information keys */
  1215. plist_dict_set_item(file_info, "DLFileAttributesKey", plist_copy(node));
  1216. plist_dict_set_item(file_info, "DLFileSource", plist_new_string(file_info_path));
  1217. plist_dict_set_item(file_info, "DLFileDest", plist_new_string("/tmp/RestoreFile.plist"));
  1218. plist_dict_set_item(file_info, "DLFileIsEncrypted", plist_new_bool(is_encrypted));
  1219. plist_dict_set_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset));
  1220. plist_dict_set_item(file_info, "DLFileStatusKey", plist_new_uint(file_status));
  1221. /* read data from file */
  1222. free(file_info_path);
  1223. file_info_path = mobilebackup_build_path(backup_directory, hash, ".mddata");
  1224. /* determine file size */
  1225. #ifdef WIN32
  1226. struct _stati64 fst;
  1227. if (_stati64(file_info_path, &fst) != 0)
  1228. #else
  1229. struct stat fst;
  1230. if (stat(file_info_path, &fst) != 0)
  1231. #endif
  1232. {
  1233. printf("ERROR: stat() failed for '%s': %s\n", file_info_path, strerror(errno));
  1234. free(file_info_path);
  1235. break;
  1236. }
  1237. length = fst.st_size;
  1238. FILE *f = fopen(file_info_path, "rb");
  1239. if (!f) {
  1240. printf("ERROR: could not open local file '%s': %s\n", file_info_path, strerror(errno));
  1241. free(file_info_path);
  1242. break;
  1243. }
  1244. free(file_info_path);
  1245. /* send DLSendFile messages */
  1246. file_offset = 0;
  1247. do {
  1248. char buf[8192];
  1249. size_t len = fread(buf, 1, sizeof(buf), f);
  1250. if ((length-file_offset) <= sizeof(buf))
  1251. file_status = DEVICE_LINK_FILE_STATUS_LAST_HUNK;
  1252. else
  1253. file_status = DEVICE_LINK_FILE_STATUS_HUNK;
  1254. plist_dict_remove_item(file_info, "DLFileOffsetKey");
  1255. plist_dict_set_item(file_info, "DLFileOffsetKey", plist_new_uint(file_offset));
  1256. plist_dict_remove_item(file_info, "DLFileStatusKey");
  1257. plist_dict_set_item(file_info, "DLFileStatusKey", plist_new_uint(file_status));
  1258. send_file_node = plist_new_array();
  1259. plist_array_append_item(send_file_node, plist_new_string("DLSendFile"));
  1260. plist_array_append_item(send_file_node, plist_new_data(buf, len));
  1261. plist_array_append_item(send_file_node, plist_copy(file_info));
  1262. err = mobilebackup_send(mobilebackup, send_file_node);
  1263. if (err != MOBILEBACKUP_E_SUCCESS) {
  1264. printf("ERROR: Unable to send file hunk due to error %d. Aborting...\n", err);
  1265. file_status = DEVICE_LINK_FILE_STATUS_NONE;
  1266. }
  1267. if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK) {
  1268. /* TODO: if all hunks of a file are sent, device must send ack */
  1269. err = mobilebackup_receive_restore_file_received(mobilebackup, NULL);
  1270. if (err != MOBILEBACKUP_E_SUCCESS) {
  1271. printf("ERROR: Did not receive an ack for the sent file due to error %d. Aborting...\n", err);
  1272. file_status = DEVICE_LINK_FILE_STATUS_NONE;
  1273. }
  1274. }
  1275. file_offset += len;
  1276. if (file_status == DEVICE_LINK_FILE_STATUS_LAST_HUNK)
  1277. printf("DONE\n");
  1278. plist_free(send_file_node);
  1279. if (file_status == DEVICE_LINK_FILE_STATUS_NONE)
  1280. break;
  1281. } while((file_offset < length));
  1282. free(hash);
  1283. node = NULL;
  1284. hash = NULL;
  1285. restore_ok = 1;
  1286. if (file_status == DEVICE_LINK_FILE_STATUS_NONE) {
  1287. restore_ok = 0;
  1288. break;
  1289. }
  1290. cur_file++;
  1291. plist_dict_next_item(files, iter, &hash, &node);
  1292. }
  1293. free(iter);
  1294. printf("Restored %d files on device.\n", cur_file);
  1295. }
  1296. }
  1297. /* TODO: observe notification_proxy id com.apple.mobile.application_installed */
  1298. /* TODO: loop over Applications entries in Manifest data plist */
  1299. plist_t applications = plist_dict_get_item(backup_data, "Applications");
  1300. if (applications && (plist_get_node_type(applications) == PLIST_DICT) && restore_ok) {
  1301. plist_dict_iter iter = NULL;
  1302. plist_dict_new_iter(applications, &iter);
  1303. if (iter) {
  1304. /* loop over Application entries in Manifest data plist */
  1305. char *hash = NULL;
  1306. int total_files = plist_dict_get_size(applications);
  1307. int cur_file = 1;
  1308. plist_t tmp_node = NULL;
  1309. plist_t dict = NULL;
  1310. plist_t array = NULL;
  1311. node = NULL;
  1312. plist_dict_next_item(applications, iter, &hash, &node);
  1313. while (node) {
  1314. printf("Restoring Application %s %d/%d (%d%%)...", hash, cur_file, total_files, (cur_file*100/total_files));
  1315. /* FIXME: receive com.apple.mobile.application_installed notification */
  1316. /* send AppInfo entry */
  1317. tmp_node = plist_dict_get_item(node, "AppInfo");
  1318. dict = plist_new_dict();
  1319. plist_dict_set_item(dict, "AppInfo", plist_copy(tmp_node));
  1320. plist_dict_set_item(dict, "BackupMessageTypeKey", plist_new_string("BackupMessageRestoreApplicationSent"));
  1321. array = plist_new_array();
  1322. plist_array_append_item(array, plist_new_string("DLMessageProcessMessage"));
  1323. plist_array_append_item(array, dict);
  1324. err = mobilebackup_send(mobilebackup, array);
  1325. if (err != MOBILEBACKUP_E_SUCCESS) {
  1326. printf("ERROR: Unable to restore application %s due to error %d. Aborting...\n", hash, err);
  1327. restore_ok = 0;
  1328. }
  1329. plist_free(array);
  1330. array = NULL;
  1331. dict = NULL;
  1332. /* receive BackupMessageRestoreApplicationReceived from device */
  1333. if (restore_ok) {
  1334. err = mobilebackup_receive_restore_application_received(mobilebackup, NULL);
  1335. if (err != MOBILEBACKUP_E_SUCCESS) {
  1336. printf("ERROR: Failed to receive an ack from the device for this application due to error %d. Aborting...\n", err);
  1337. restore_ok = 0;
  1338. }
  1339. }
  1340. tmp_node = NULL;
  1341. node = NULL;
  1342. free(hash);
  1343. hash = NULL;
  1344. if (restore_ok) {
  1345. printf("DONE\n");
  1346. cur_file++;
  1347. plist_dict_next_item(applications, iter, &hash, &node);
  1348. } else
  1349. break;
  1350. }
  1351. free(iter);
  1352. if (restore_ok)
  1353. printf("All applications restored.\n");
  1354. else
  1355. printf("Failed to restore applications.\n");
  1356. }
  1357. }
  1358. plist_free(backup_data);
  1359. /* signal restore finished message to device; BackupMessageRestoreComplete */
  1360. if (restore_ok) {
  1361. err = mobilebackup_send_restore_complete(mobilebackup);
  1362. if (err != MOBILEBACKUP_E_SUCCESS) {
  1363. printf("ERROR: Could not send BackupMessageRestoreComplete, error code %d\n", err);
  1364. }
  1365. }
  1366. if (restore_ok) {
  1367. printf("Restore Successful.\n");
  1368. } else {
  1369. printf("Restore Failed.\n");
  1370. }
  1371. break;
  1372. case CMD_LEAVE:
  1373. default:
  1374. break;
  1375. }
  1376. if (lockfile) {
  1377. afc_file_lock(afc, lockfile, AFC_LOCK_UN);
  1378. afc_file_close(afc, lockfile);
  1379. lockfile = 0;
  1380. do_post_notification(NP_SYNC_DID_FINISH);
  1381. }
  1382. if (manifest_path)
  1383. free(manifest_path);
  1384. } else {
  1385. printf("ERROR: Could not start service %s.\n", MOBILEBACKUP_SERVICE_NAME);
  1386. lockdownd_client_free(client);
  1387. client = NULL;
  1388. }
  1389. if (client) {
  1390. lockdownd_client_free(client);
  1391. client = NULL;
  1392. }
  1393. if (afc)
  1394. afc_client_free(afc);
  1395. if (np)
  1396. np_client_free(np);
  1397. if (mobilebackup)
  1398. mobilebackup_client_free(mobilebackup);
  1399. idevice_free(device);
  1400. if (udid) {
  1401. free(udid);
  1402. }
  1403. return 0;
  1404. }