idevicebackup2.c 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293
  1. /*
  2. * idevicebackup2.c
  3. * Command line interface to use the device's backup and restore service
  4. *
  5. * Copyright (c) 2010-2019 Nikias Bassen, All Rights Reserved.
  6. * Copyright (c) 2009-2010 Martin Szulecki, 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. #define TOOL_NAME "idevicebackup2"
  26. #include "idevicebackup2.h"
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <errno.h>
  30. #include <stdlib.h>
  31. #include <signal.h>
  32. #include <unistd.h>
  33. #include <dirent.h>
  34. #include <libgen.h>
  35. #include <ctype.h>
  36. #include <time.h>
  37. #include <libimobiledevice/libimobiledevice.h>
  38. #include <libimobiledevice/lockdown.h>
  39. #include <libimobiledevice/mobilebackup2.h>
  40. #include <libimobiledevice/notification_proxy.h>
  41. #include <libimobiledevice/afc.h>
  42. #include <libimobiledevice/installation_proxy.h>
  43. #include <libimobiledevice/sbservices.h>
  44. #include <libimobiledevice/diagnostics_relay.h>
  45. #include "utils.h"
  46. #include "endianness.h"
  47. #define LOCK_ATTEMPTS 50
  48. #define LOCK_WAIT 200000
  49. #ifdef WIN32
  50. #include <windows.h>
  51. #include <conio.h>
  52. #define sleep(x) Sleep(x*1000)
  53. #else
  54. #include <termios.h>
  55. #include <sys/statvfs.h>
  56. #endif
  57. #include <sys/stat.h>
  58. #define CODE_SUCCESS 0x00
  59. #define CODE_ERROR_LOCAL 0x06
  60. #define CODE_ERROR_REMOTE 0x0b
  61. #define CODE_FILE_DATA 0x0c
  62. static int verbose = 1;
  63. static int quit_flag = 0;
  64. #define PRINT_VERBOSE(min_level, ...) if (verbose >= min_level) { printf(__VA_ARGS__); };
  65. enum cmd_mode {
  66. CMD_BACKUP,
  67. CMD_RESTORE,
  68. CMD_INFO,
  69. CMD_LIST,
  70. CMD_UNBACK,
  71. CMD_CHANGEPW,
  72. CMD_LEAVE,
  73. CMD_CLOUD
  74. };
  75. enum cmd_flags {
  76. CMD_FLAG_RESTORE_SYSTEM_FILES = (1 << 1),
  77. CMD_FLAG_RESTORE_NO_REBOOT = (1 << 2),
  78. CMD_FLAG_RESTORE_COPY_BACKUP = (1 << 3),
  79. CMD_FLAG_RESTORE_SETTINGS = (1 << 4),
  80. CMD_FLAG_RESTORE_REMOVE_ITEMS = (1 << 5),
  81. CMD_FLAG_ENCRYPTION_ENABLE = (1 << 6),
  82. CMD_FLAG_ENCRYPTION_DISABLE = (1 << 7),
  83. CMD_FLAG_ENCRYPTION_CHANGEPW = (1 << 8),
  84. CMD_FLAG_FORCE_FULL_BACKUP = (1 << 9),
  85. CMD_FLAG_CLOUD_ENABLE = (1 << 10),
  86. CMD_FLAG_CLOUD_DISABLE = (1 << 11),
  87. CMD_FLAG_RESTORE_SKIP_APPS = (1 << 12)
  88. };
  89. static int backup_domain_changed = 0;
  90. static void notify_cb(const char *notification, void *userdata)
  91. {
  92. if (strlen(notification) == 0) {
  93. return;
  94. }
  95. if (!strcmp(notification, NP_SYNC_CANCEL_REQUEST)) {
  96. PRINT_VERBOSE(1, "User has cancelled the backup process on the device.\n");
  97. quit_flag++;
  98. } else if (!strcmp(notification, NP_BACKUP_DOMAIN_CHANGED)) {
  99. backup_domain_changed = 1;
  100. } else {
  101. PRINT_VERBOSE(1, "Unhandled notification '%s' (TODO: implement)\n", notification);
  102. }
  103. }
  104. static void mobilebackup_afc_get_file_contents(afc_client_t afc, const char *filename, char **data, uint64_t *size)
  105. {
  106. if (!afc || !data || !size) {
  107. return;
  108. }
  109. char **fileinfo = NULL;
  110. uint32_t fsize = 0;
  111. afc_get_file_info(afc, filename, &fileinfo);
  112. if (!fileinfo) {
  113. return;
  114. }
  115. int i;
  116. for (i = 0; fileinfo[i]; i+=2) {
  117. if (!strcmp(fileinfo[i], "st_size")) {
  118. fsize = atol(fileinfo[i+1]);
  119. break;
  120. }
  121. }
  122. afc_dictionary_free(fileinfo);
  123. if (fsize == 0) {
  124. return;
  125. }
  126. uint64_t f = 0;
  127. afc_file_open(afc, filename, AFC_FOPEN_RDONLY, &f);
  128. if (!f) {
  129. return;
  130. }
  131. char *buf = (char*)malloc((uint32_t)fsize);
  132. uint32_t done = 0;
  133. while (done < fsize) {
  134. uint32_t bread = 0;
  135. afc_file_read(afc, f, buf+done, 65536, &bread);
  136. if (bread > 0) {
  137. done += bread;
  138. } else {
  139. break;
  140. }
  141. }
  142. if (done == fsize) {
  143. *size = fsize;
  144. *data = buf;
  145. } else {
  146. free(buf);
  147. }
  148. afc_file_close(afc, f);
  149. }
  150. static int __mkdir(const char* path, int mode)
  151. {
  152. #ifdef WIN32
  153. return mkdir(path);
  154. #else
  155. return mkdir(path, mode);
  156. #endif
  157. }
  158. static int mkdir_with_parents(const char *dir, int mode)
  159. {
  160. if (!dir) return -1;
  161. if (__mkdir(dir, mode) == 0) {
  162. return 0;
  163. } else {
  164. if (errno == EEXIST) return 0;
  165. }
  166. int res;
  167. char *parent = strdup(dir);
  168. char *parentdir = dirname(parent);
  169. if (parentdir) {
  170. res = mkdir_with_parents(parentdir, mode);
  171. } else {
  172. res = -1;
  173. }
  174. free(parent);
  175. if (res == 0) {
  176. mkdir_with_parents(dir, mode);
  177. }
  178. return res;
  179. }
  180. #ifdef WIN32
  181. static int win32err_to_errno(int err_value)
  182. {
  183. switch (err_value) {
  184. case ERROR_FILE_NOT_FOUND:
  185. return ENOENT;
  186. case ERROR_ALREADY_EXISTS:
  187. return EEXIST;
  188. default:
  189. return EFAULT;
  190. }
  191. }
  192. #endif
  193. static int remove_file(const char* path)
  194. {
  195. int e = 0;
  196. #ifdef WIN32
  197. if (!DeleteFile(path)) {
  198. e = win32err_to_errno(GetLastError());
  199. }
  200. #else
  201. if (remove(path) < 0) {
  202. e = errno;
  203. }
  204. #endif
  205. return e;
  206. }
  207. static int remove_directory(const char* path)
  208. {
  209. int e = 0;
  210. #ifdef WIN32
  211. if (!RemoveDirectory(path)) {
  212. e = win32err_to_errno(GetLastError());
  213. }
  214. #else
  215. if (remove(path) < 0) {
  216. e = errno;
  217. }
  218. #endif
  219. return e;
  220. }
  221. struct entry_ {
  222. char *name;
  223. struct entry *next;
  224. };
  225. static void scan_directory(const char *path, struct entry **files, struct entry **directories)
  226. {
  227. DIR* cur_dir = opendir(path);
  228. if (cur_dir) {
  229. struct dirent* ep;
  230. while ((ep = readdir(cur_dir))) {
  231. if ((strcmp(ep->d_name, ".") == 0) || (strcmp(ep->d_name, "..") == 0)) {
  232. continue;
  233. }
  234. char *fpath = string_build_path(path, ep->d_name, NULL);
  235. if (fpath) {
  236. #ifdef HAVE_DIRENT_D_TYPE
  237. if (ep->d_type & DT_DIR) {
  238. #else
  239. struct stat st;
  240. if (stat(fpath, &st) != 0) return;
  241. if (S_ISDIR(st.st_mode)) {
  242. #endif
  243. struct entry_ *ent = malloc(sizeof(struct entry_));
  244. if (!ent) return;
  245. ent->name = fpath;
  246. ent->next = *directories;
  247. *directories = ent;
  248. scan_directory(fpath, files, directories);
  249. fpath = NULL;
  250. } else {
  251. struct entry_ *ent = malloc(sizeof(struct entry_));
  252. if (!ent) return;
  253. ent->name = fpath;
  254. ent->next = *files;
  255. *files = ent;
  256. fpath = NULL;
  257. }
  258. }
  259. }
  260. closedir(cur_dir);
  261. }
  262. }
  263. static int rmdir_recursive(const char* path)
  264. {
  265. int res = 0;
  266. struct entry_ *files = NULL;
  267. struct entry_ *directories = NULL;
  268. struct entry_ *ent;
  269. ent = malloc(sizeof(struct entry_));
  270. if (!ent) return ENOMEM;
  271. ent->name = strdup(path);
  272. ent->next = NULL;
  273. directories = ent;
  274. scan_directory(path, &files, &directories);
  275. ent = files;
  276. while (ent) {
  277. struct entry *del = ent;
  278. res = remove_file(ent->name);
  279. free(ent->name);
  280. ent = ent->next;
  281. free(del);
  282. }
  283. ent = directories;
  284. while (ent) {
  285. struct entry *del = ent;
  286. res = remove_directory(ent->name);
  287. free(ent->name);
  288. ent = ent->next;
  289. free(del);
  290. }
  291. return res;
  292. }
  293. static char* get_uuid()
  294. {
  295. const char *chars = "ABCDEF0123456789";
  296. int i = 0;
  297. char *uuid = (char*)malloc(sizeof(char) * 33);
  298. srand(time(NULL));
  299. for (i = 0; i < 32; i++) {
  300. uuid[i] = chars[rand() % 16];
  301. }
  302. uuid[32] = '\0';
  303. return uuid;
  304. }
  305. static plist_t mobilebackup_factory_info_plist_new(const char* udid, idevice_t device, afc_client_t afc)
  306. {
  307. /* gather data from lockdown */
  308. plist_t value_node = NULL;
  309. plist_t root_node = NULL;
  310. plist_t itunes_settings = NULL;
  311. plist_t min_itunes_version = NULL;
  312. char *udid_uppercase = NULL;
  313. lockdownd_client_t lockdown = NULL;
  314. if (lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME) != LOCKDOWN_E_SUCCESS) {
  315. return NULL;
  316. }
  317. plist_t ret = plist_new_dict();
  318. /* get basic device information in one go */
  319. lockdownd_get_value(lockdown, NULL, NULL, &root_node);
  320. /* get iTunes settings */
  321. lockdownd_get_value(lockdown, "com.apple.iTunes", NULL, &itunes_settings);
  322. /* get minimum iTunes version */
  323. lockdownd_get_value(lockdown, "com.apple.mobile.iTunes", "MinITunesVersion", &min_itunes_version);
  324. lockdownd_client_free(lockdown);
  325. /* get a list of installed user applications */
  326. plist_t app_dict = plist_new_dict();
  327. plist_t installed_apps = plist_new_array();
  328. instproxy_client_t ip = NULL;
  329. if (instproxy_client_start_service(device, &ip, TOOL_NAME) == INSTPROXY_E_SUCCESS) {
  330. plist_t client_opts = instproxy_client_options_new();
  331. instproxy_client_options_add(client_opts, "ApplicationType", "User", NULL);
  332. instproxy_client_options_set_return_attributes(client_opts, "CFBundleIdentifier", "ApplicationSINF", "iTunesMetadata", NULL);
  333. plist_t apps = NULL;
  334. instproxy_browse(ip, client_opts, &apps);
  335. sbservices_client_t sbs = NULL;
  336. if (sbservices_client_start_service(device, &sbs, TOOL_NAME) != SBSERVICES_E_SUCCESS) {
  337. printf("Couldn't establish sbservices connection. Continuing anyway.\n");
  338. }
  339. if (apps && (plist_get_node_type(apps) == PLIST_ARRAY)) {
  340. uint32_t app_count = plist_array_get_size(apps);
  341. uint32_t i;
  342. for (i = 0; i < app_count; i++) {
  343. plist_t app_entry = plist_array_get_item(apps, i);
  344. plist_t bundle_id = plist_dict_get_item(app_entry, "CFBundleIdentifier");
  345. if (bundle_id) {
  346. char *bundle_id_str = NULL;
  347. plist_array_append_item(installed_apps, plist_copy(bundle_id));
  348. plist_get_string_val(bundle_id, &bundle_id_str);
  349. plist_t sinf = plist_dict_get_item(app_entry, "ApplicationSINF");
  350. plist_t meta = plist_dict_get_item(app_entry, "iTunesMetadata");
  351. if (sinf && meta) {
  352. plist_t adict = plist_new_dict();
  353. plist_dict_set_item(adict, "ApplicationSINF", plist_copy(sinf));
  354. if (sbs) {
  355. char *pngdata = NULL;
  356. uint64_t pngsize = 0;
  357. sbservices_get_icon_pngdata(sbs, bundle_id_str, &pngdata, &pngsize);
  358. if (pngdata) {
  359. plist_dict_set_item(adict, "PlaceholderIcon", plist_new_data(pngdata, pngsize));
  360. free(pngdata);
  361. }
  362. }
  363. plist_dict_set_item(adict, "iTunesMetadata", plist_copy(meta));
  364. plist_dict_set_item(app_dict, bundle_id_str, adict);
  365. }
  366. free(bundle_id_str);
  367. }
  368. }
  369. }
  370. plist_free(apps);
  371. if (sbs) {
  372. sbservices_client_free(sbs);
  373. }
  374. instproxy_client_options_free(client_opts);
  375. instproxy_client_free(ip);
  376. }
  377. /* Applications */
  378. plist_dict_set_item(ret, "Applications", app_dict);
  379. /* set fields we understand */
  380. value_node = plist_dict_get_item(root_node, "BuildVersion");
  381. plist_dict_set_item(ret, "Build Version", plist_copy(value_node));
  382. value_node = plist_dict_get_item(root_node, "DeviceName");
  383. plist_dict_set_item(ret, "Device Name", plist_copy(value_node));
  384. plist_dict_set_item(ret, "Display Name", plist_copy(value_node));
  385. char *uuid = get_uuid();
  386. plist_dict_set_item(ret, "GUID", plist_new_string(uuid));
  387. free(uuid);
  388. value_node = plist_dict_get_item(root_node, "IntegratedCircuitCardIdentity");
  389. if (value_node)
  390. plist_dict_set_item(ret, "ICCID", plist_copy(value_node));
  391. value_node = plist_dict_get_item(root_node, "InternationalMobileEquipmentIdentity");
  392. if (value_node)
  393. plist_dict_set_item(ret, "IMEI", plist_copy(value_node));
  394. /* Installed Applications */
  395. plist_dict_set_item(ret, "Installed Applications", installed_apps);
  396. plist_dict_set_item(ret, "Last Backup Date", plist_new_date(time(NULL) - MAC_EPOCH, 0));
  397. value_node = plist_dict_get_item(root_node, "MobileEquipmentIdentifier");
  398. if (value_node)
  399. plist_dict_set_item(ret, "MEID", plist_copy(value_node));
  400. value_node = plist_dict_get_item(root_node, "PhoneNumber");
  401. if (value_node && (plist_get_node_type(value_node) == PLIST_STRING)) {
  402. plist_dict_set_item(ret, "Phone Number", plist_copy(value_node));
  403. }
  404. /* FIXME Product Name */
  405. value_node = plist_dict_get_item(root_node, "ProductType");
  406. plist_dict_set_item(ret, "Product Type", plist_copy(value_node));
  407. value_node = plist_dict_get_item(root_node, "ProductVersion");
  408. plist_dict_set_item(ret, "Product Version", plist_copy(value_node));
  409. value_node = plist_dict_get_item(root_node, "SerialNumber");
  410. plist_dict_set_item(ret, "Serial Number", plist_copy(value_node));
  411. /* FIXME Sync Settings? */
  412. value_node = plist_dict_get_item(root_node, "UniqueDeviceID");
  413. plist_dict_set_item(ret, "Target Identifier", plist_new_string(udid));
  414. plist_dict_set_item(ret, "Target Type", plist_new_string("Device"));
  415. /* uppercase */
  416. udid_uppercase = string_toupper((char*)udid);
  417. plist_dict_set_item(ret, "Unique Identifier", plist_new_string(udid_uppercase));
  418. free(udid_uppercase);
  419. char *data_buf = NULL;
  420. uint64_t data_size = 0;
  421. mobilebackup_afc_get_file_contents(afc, "/Books/iBooksData2.plist", &data_buf, &data_size);
  422. if (data_buf) {
  423. plist_dict_set_item(ret, "iBooks Data 2", plist_new_data(data_buf, data_size));
  424. free(data_buf);
  425. }
  426. plist_t files = plist_new_dict();
  427. const char *itunesfiles[] = {
  428. "ApertureAlbumPrefs",
  429. "IC-Info.sidb",
  430. "IC-Info.sidv",
  431. "PhotosFolderAlbums",
  432. "PhotosFolderName",
  433. "PhotosFolderPrefs",
  434. "VoiceMemos.plist",
  435. "iPhotoAlbumPrefs",
  436. "iTunesApplicationIDs",
  437. "iTunesPrefs",
  438. "iTunesPrefs.plist",
  439. NULL
  440. };
  441. int i = 0;
  442. for (i = 0; itunesfiles[i]; i++) {
  443. data_buf = NULL;
  444. data_size = 0;
  445. char *fname = (char*)malloc(strlen("/iTunes_Control/iTunes/") + strlen(itunesfiles[i]) + 1);
  446. strcpy(fname, "/iTunes_Control/iTunes/");
  447. strcat(fname, itunesfiles[i]);
  448. mobilebackup_afc_get_file_contents(afc, fname, &data_buf, &data_size);
  449. free(fname);
  450. if (data_buf) {
  451. plist_dict_set_item(files, itunesfiles[i], plist_new_data(data_buf, data_size));
  452. free(data_buf);
  453. }
  454. }
  455. plist_dict_set_item(ret, "iTunes Files", files);
  456. plist_dict_set_item(ret, "iTunes Settings", itunes_settings ? plist_copy(itunes_settings) : plist_new_dict());
  457. /* since we usually don't have iTunes, let's get the minimum required iTunes version from the device */
  458. if (min_itunes_version) {
  459. plist_dict_set_item(ret, "iTunes Version", plist_copy(min_itunes_version));
  460. } else {
  461. plist_dict_set_item(ret, "iTunes Version", plist_new_string("10.0.1"));
  462. }
  463. plist_free(itunes_settings);
  464. plist_free(min_itunes_version);
  465. plist_free(root_node);
  466. return ret;
  467. }
  468. static int write_restore_applications(plist_t info_plist, afc_client_t afc)
  469. {
  470. int res = -1;
  471. uint64_t restore_applications_file = 0;
  472. char * applications_plist_xml = NULL;
  473. uint32_t applications_plist_xml_length = 0;
  474. plist_t applications_plist = plist_dict_get_item(info_plist, "Applications");
  475. if (applications_plist) {
  476. plist_to_xml(applications_plist, &applications_plist_xml, &applications_plist_xml_length);
  477. }
  478. if (!applications_plist_xml) {
  479. printf("Error preparing RestoreApplications.plist\n");
  480. goto leave;
  481. }
  482. afc_error_t afc_err = 0;
  483. afc_err = afc_make_directory(afc, "/iTunesRestore");
  484. if (afc_err != AFC_E_SUCCESS) {
  485. printf("Error creating directory /iTunesRestore, error code %d\n", afc_err);
  486. goto leave;
  487. }
  488. afc_err = afc_file_open(afc, "/iTunesRestore/RestoreApplications.plist", AFC_FOPEN_WR, &restore_applications_file);
  489. if (afc_err != AFC_E_SUCCESS || !restore_applications_file) {
  490. printf("Error creating /iTunesRestore/RestoreApplications.plist, error code %d\n", afc_err);
  491. goto leave;
  492. }
  493. uint32_t bytes_written = 0;
  494. afc_err = afc_file_write(afc, restore_applications_file, applications_plist_xml, applications_plist_xml_length, &bytes_written);
  495. if (afc_err != AFC_E_SUCCESS || bytes_written != applications_plist_xml_length) {
  496. printf("Error writing /iTunesRestore/RestoreApplications.plist, error code %d, wrote %u of %u bytes\n", afc_err, bytes_written, applications_plist_xml_length);
  497. goto leave;
  498. }
  499. afc_err = afc_file_close(afc, restore_applications_file);
  500. restore_applications_file = 0;
  501. if (afc_err != AFC_E_SUCCESS) {
  502. goto leave;
  503. }
  504. /* success */
  505. res = 0;
  506. leave:
  507. free(applications_plist_xml);
  508. if (restore_applications_file) {
  509. afc_file_close(afc, restore_applications_file);
  510. restore_applications_file = 0;
  511. }
  512. return res;
  513. }
  514. static int mb2_status_check_snapshot_state(const char *path, const char *udid, const char *matches)
  515. {
  516. int ret = 0;
  517. plist_t status_plist = NULL;
  518. char *file_path = string_build_path(path, udid, "Status.plist", NULL);
  519. plist_read_from_filename(&status_plist, file_path);
  520. free(file_path);
  521. if (!status_plist) {
  522. printf("Could not read Status.plist!\n");
  523. return ret;
  524. }
  525. plist_t node = plist_dict_get_item(status_plist, "SnapshotState");
  526. if (node && (plist_get_node_type(node) == PLIST_STRING)) {
  527. char* sval = NULL;
  528. plist_get_string_val(node, &sval);
  529. if (sval) {
  530. ret = (strcmp(sval, matches) == 0) ? 1 : 0;
  531. free(sval);
  532. }
  533. } else {
  534. printf("%s: ERROR could not get SnapshotState key from Status.plist!\n", __func__);
  535. }
  536. plist_free(status_plist);
  537. return ret;
  538. }
  539. static void do_post_notification(idevice_t device, const char *notification)
  540. {
  541. lockdownd_service_descriptor_t service = NULL;
  542. np_client_t np;
  543. lockdownd_client_t lockdown = NULL;
  544. if (lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME) != LOCKDOWN_E_SUCCESS) {
  545. return;
  546. }
  547. lockdownd_start_service(lockdown, NP_SERVICE_NAME, &service);
  548. if (service && service->port) {
  549. np_client_new(device, service, &np);
  550. if (np) {
  551. np_post_notification(np, notification);
  552. np_client_free(np);
  553. }
  554. } else {
  555. printf("Could not start %s\n", NP_SERVICE_NAME);
  556. }
  557. if (service) {
  558. lockdownd_service_descriptor_free(service);
  559. service = NULL;
  560. }
  561. lockdownd_client_free(lockdown);
  562. }
  563. static void print_progress_real(double progress, int flush)
  564. {
  565. int i = 0;
  566. PRINT_VERBOSE(1, "\r[");
  567. for(i = 0; i < 50; i++) {
  568. if(i < progress / 2) {
  569. PRINT_VERBOSE(1, "=");
  570. } else {
  571. PRINT_VERBOSE(1, " ");
  572. }
  573. }
  574. PRINT_VERBOSE(1, "] %3.0f%%", progress);
  575. if (flush > 0) {
  576. fflush(stdout);
  577. if (progress == 100)
  578. PRINT_VERBOSE(1, "\n");
  579. }
  580. }
  581. static void print_progress(uint64_t current, uint64_t total)
  582. {
  583. char *format_size = NULL;
  584. double progress = ((double)current/(double)total)*100;
  585. if (progress < 0)
  586. return;
  587. if (progress > 100)
  588. progress = 100;
  589. print_progress_real((double)progress, 0);
  590. format_size = string_format_size(current);
  591. PRINT_VERBOSE(1, " (%s", format_size);
  592. free(format_size);
  593. format_size = string_format_size(total);
  594. PRINT_VERBOSE(1, "/%s) ", format_size);
  595. free(format_size);
  596. fflush(stdout);
  597. if (progress == 100)
  598. PRINT_VERBOSE(1, "\n");
  599. }
  600. static double overall_progress = 0;
  601. static void mb2_set_overall_progress(double progress)
  602. {
  603. if (progress > 0.0)
  604. overall_progress = progress;
  605. }
  606. static void mb2_set_overall_progress_from_message(plist_t message, char* identifier)
  607. {
  608. plist_t node = NULL;
  609. double progress = 0.0;
  610. if (!strcmp(identifier, "DLMessageDownloadFiles")) {
  611. node = plist_array_get_item(message, 3);
  612. } else if (!strcmp(identifier, "DLMessageUploadFiles")) {
  613. node = plist_array_get_item(message, 2);
  614. } else if (!strcmp(identifier, "DLMessageMoveFiles") || !strcmp(identifier, "DLMessageMoveItems")) {
  615. node = plist_array_get_item(message, 3);
  616. } else if (!strcmp(identifier, "DLMessageRemoveFiles") || !strcmp(identifier, "DLMessageRemoveItems")) {
  617. node = plist_array_get_item(message, 3);
  618. }
  619. if (node != NULL) {
  620. plist_get_real_val(node, &progress);
  621. mb2_set_overall_progress(progress);
  622. }
  623. }
  624. static void mb2_multi_status_add_file_error(plist_t status_dict, const char *path, int error_code, const char *error_message)
  625. {
  626. if (!status_dict) return;
  627. plist_t filedict = plist_new_dict();
  628. plist_dict_set_item(filedict, "DLFileErrorString", plist_new_string(error_message));
  629. plist_dict_set_item(filedict, "DLFileErrorCode", plist_new_uint(error_code));
  630. plist_dict_set_item(status_dict, path, filedict);
  631. }
  632. static int errno_to_device_error(int errno_value)
  633. {
  634. switch (errno_value) {
  635. case ENOENT:
  636. return -6;
  637. case EEXIST:
  638. return -7;
  639. default:
  640. return -errno_value;
  641. }
  642. }
  643. static int mb2_handle_send_file(mobilebackup2_client_t mobilebackup2, const char *backup_dir, const char *path, plist_t *errplist)
  644. {
  645. uint32_t nlen = 0;
  646. uint32_t pathlen = strlen(path);
  647. uint32_t bytes = 0;
  648. char *localfile = string_build_path(backup_dir, path, NULL);
  649. char buf[32768];
  650. #ifdef WIN32
  651. struct _stati64 fst;
  652. #else
  653. struct stat fst;
  654. #endif
  655. FILE *f = NULL;
  656. uint32_t slen = 0;
  657. int errcode = -1;
  658. int result = -1;
  659. uint32_t length;
  660. #ifdef WIN32
  661. uint64_t total;
  662. uint64_t sent;
  663. #else
  664. off_t total;
  665. off_t sent;
  666. #endif
  667. mobilebackup2_error_t err;
  668. /* send path length */
  669. nlen = htobe32(pathlen);
  670. err = mobilebackup2_send_raw(mobilebackup2, (const char*)&nlen, sizeof(nlen), &bytes);
  671. if (err != MOBILEBACKUP2_E_SUCCESS) {
  672. goto leave_proto_err;
  673. }
  674. if (bytes != (uint32_t)sizeof(nlen)) {
  675. err = MOBILEBACKUP2_E_MUX_ERROR;
  676. goto leave_proto_err;
  677. }
  678. /* send path */
  679. err = mobilebackup2_send_raw(mobilebackup2, path, pathlen, &bytes);
  680. if (err != MOBILEBACKUP2_E_SUCCESS) {
  681. goto leave_proto_err;
  682. }
  683. if (bytes != pathlen) {
  684. err = MOBILEBACKUP2_E_MUX_ERROR;
  685. goto leave_proto_err;
  686. }
  687. #ifdef WIN32
  688. if (_stati64(localfile, &fst) < 0)
  689. #else
  690. if (stat(localfile, &fst) < 0)
  691. #endif
  692. {
  693. if (errno != ENOENT)
  694. errcode = errno;
  695. goto leave;
  696. }
  697. total = fst.st_size;
  698. char *format_size = string_format_size(total);
  699. free(format_size);
  700. if (total == 0) {
  701. errcode = 0;
  702. goto leave;
  703. }
  704. f = fopen(localfile, "rb");
  705. if (!f) {
  706. errcode = errno;
  707. goto leave;
  708. }
  709. sent = 0;
  710. do {
  711. length = ((total-sent) < (long long)sizeof(buf)) ? (uint32_t)total-sent : (uint32_t)sizeof(buf);
  712. /* send data size (file size + 1) */
  713. nlen = htobe32(length+1);
  714. memcpy(buf, &nlen, sizeof(nlen));
  715. buf[4] = CODE_FILE_DATA;
  716. err = mobilebackup2_send_raw(mobilebackup2, (const char*)buf, 5, &bytes);
  717. if (err != MOBILEBACKUP2_E_SUCCESS) {
  718. goto leave_proto_err;
  719. }
  720. if (bytes != 5) {
  721. goto leave_proto_err;
  722. }
  723. /* send file contents */
  724. size_t r = fread(buf, 1, sizeof(buf), f);
  725. if (r <= 0) {
  726. printf("%s: read error\n", __func__);
  727. errcode = errno;
  728. goto leave;
  729. }
  730. err = mobilebackup2_send_raw(mobilebackup2, buf, r, &bytes);
  731. if (err != MOBILEBACKUP2_E_SUCCESS) {
  732. goto leave_proto_err;
  733. }
  734. if (bytes != (uint32_t)r) {
  735. printf("Error: sent only %d of %d bytes\n", bytes, (int)r);
  736. goto leave_proto_err;
  737. }
  738. sent += r;
  739. } while (sent < total);
  740. fclose(f);
  741. f = NULL;
  742. errcode = 0;
  743. leave:
  744. if (errcode == 0) {
  745. result = 0;
  746. nlen = 1;
  747. nlen = htobe32(nlen);
  748. memcpy(buf, &nlen, 4);
  749. buf[4] = CODE_SUCCESS;
  750. mobilebackup2_send_raw(mobilebackup2, buf, 5, &bytes);
  751. } else {
  752. if (!*errplist) {
  753. *errplist = plist_new_dict();
  754. }
  755. char *errdesc = strerror(errcode);
  756. mb2_multi_status_add_file_error(*errplist, path, errno_to_device_error(errcode), errdesc);
  757. length = strlen(errdesc);
  758. nlen = htobe32(length+1);
  759. memcpy(buf, &nlen, 4);
  760. buf[4] = CODE_ERROR_LOCAL;
  761. slen = 5;
  762. memcpy(buf+slen, errdesc, length);
  763. slen += length;
  764. err = mobilebackup2_send_raw(mobilebackup2, (const char*)buf, slen, &bytes);
  765. if (err != MOBILEBACKUP2_E_SUCCESS) {
  766. printf("could not send message\n");
  767. }
  768. if (bytes != slen) {
  769. printf("could only send %d from %d\n", bytes, slen);
  770. }
  771. }
  772. leave_proto_err:
  773. if (f)
  774. fclose(f);
  775. free(localfile);
  776. return result;
  777. }
  778. static void mb2_handle_send_files(mobilebackup2_client_t mobilebackup2, plist_t message, const char *backup_dir)
  779. {
  780. uint32_t cnt;
  781. uint32_t i = 0;
  782. uint32_t sent;
  783. plist_t errplist = NULL;
  784. if (!message || (plist_get_node_type(message) != PLIST_ARRAY) || (plist_array_get_size(message) < 2) || !backup_dir) return;
  785. plist_t files = plist_array_get_item(message, 1);
  786. cnt = plist_array_get_size(files);
  787. for (i = 0; i < cnt; i++) {
  788. plist_t val = plist_array_get_item(files, i);
  789. if (plist_get_node_type(val) != PLIST_STRING) {
  790. continue;
  791. }
  792. char *str = NULL;
  793. plist_get_string_val(val, &str);
  794. if (!str)
  795. continue;
  796. if (mb2_handle_send_file(mobilebackup2, backup_dir, str, &errplist) < 0) {
  797. free(str);
  798. //printf("Error when sending file '%s' to device\n", str);
  799. // TODO: perhaps we can continue, we've got a multi status response?!
  800. break;
  801. }
  802. free(str);
  803. }
  804. /* send terminating 0 dword */
  805. uint32_t zero = 0;
  806. mobilebackup2_send_raw(mobilebackup2, (char*)&zero, 4, &sent);
  807. if (!errplist) {
  808. plist_t emptydict = plist_new_dict();
  809. mobilebackup2_send_status_response(mobilebackup2, 0, NULL, emptydict);
  810. plist_free(emptydict);
  811. } else {
  812. mobilebackup2_send_status_response(mobilebackup2, -13, "Multi status", errplist);
  813. plist_free(errplist);
  814. }
  815. }
  816. static int mb2_receive_filename(mobilebackup2_client_t mobilebackup2, char** filename)
  817. {
  818. uint32_t nlen = 0;
  819. uint32_t rlen = 0;
  820. do {
  821. nlen = 0;
  822. rlen = 0;
  823. mobilebackup2_receive_raw(mobilebackup2, (char*)&nlen, 4, &rlen);
  824. nlen = be32toh(nlen);
  825. if ((nlen == 0) && (rlen == 4)) {
  826. // a zero length means no more files to receive
  827. return 0;
  828. } else if(rlen == 0) {
  829. // device needs more time, waiting...
  830. continue;
  831. } else if (nlen > 4096) {
  832. // filename length is too large
  833. printf("ERROR: %s: too large filename length (%d)!\n", __func__, nlen);
  834. return 0;
  835. }
  836. if (*filename != NULL) {
  837. free(*filename);
  838. *filename = NULL;
  839. }
  840. *filename = (char*)malloc(nlen+1);
  841. rlen = 0;
  842. mobilebackup2_receive_raw(mobilebackup2, *filename, nlen, &rlen);
  843. if (rlen != nlen) {
  844. printf("ERROR: %s: could not read filename\n", __func__);
  845. return 0;
  846. }
  847. char* p = *filename;
  848. p[rlen] = 0;
  849. break;
  850. } while(1 && !quit_flag);
  851. return nlen;
  852. }
  853. static int mb2_handle_receive_files(mobilebackup2_client_t mobilebackup2, plist_t message, const char *backup_dir)
  854. {
  855. uint64_t backup_real_size = 0;
  856. uint64_t backup_total_size = 0;
  857. uint32_t blocksize;
  858. uint32_t bdone;
  859. uint32_t rlen;
  860. uint32_t nlen = 0;
  861. uint32_t r;
  862. char buf[32768];
  863. char *fname = NULL;
  864. char *dname = NULL;
  865. char *bname = NULL;
  866. char code = 0;
  867. char last_code = 0;
  868. plist_t node = NULL;
  869. FILE *f = NULL;
  870. unsigned int file_count = 0;
  871. int errcode = 0;
  872. char *errdesc = NULL;
  873. if (!message || (plist_get_node_type(message) != PLIST_ARRAY) || plist_array_get_size(message) < 4 || !backup_dir) return 0;
  874. node = plist_array_get_item(message, 3);
  875. if (plist_get_node_type(node) == PLIST_UINT) {
  876. plist_get_uint_val(node, &backup_total_size);
  877. }
  878. if (backup_total_size > 0) {
  879. PRINT_VERBOSE(1, "Receiving files\n");
  880. }
  881. do {
  882. if (quit_flag)
  883. break;
  884. nlen = mb2_receive_filename(mobilebackup2, &dname);
  885. if (nlen == 0) {
  886. break;
  887. }
  888. nlen = mb2_receive_filename(mobilebackup2, &fname);
  889. if (!nlen) {
  890. break;
  891. }
  892. if (bname != NULL) {
  893. free(bname);
  894. bname = NULL;
  895. }
  896. bname = string_build_path(backup_dir, fname, NULL);
  897. if (fname != NULL) {
  898. free(fname);
  899. fname = NULL;
  900. }
  901. r = 0;
  902. nlen = 0;
  903. mobilebackup2_receive_raw(mobilebackup2, (char*)&nlen, 4, &r);
  904. if (r != 4) {
  905. printf("ERROR: %s: could not receive code length!\n", __func__);
  906. break;
  907. }
  908. nlen = be32toh(nlen);
  909. last_code = code;
  910. code = 0;
  911. mobilebackup2_receive_raw(mobilebackup2, &code, 1, &r);
  912. if (r != 1) {
  913. printf("ERROR: %s: could not receive code!\n", __func__);
  914. break;
  915. }
  916. /* TODO remove this */
  917. if ((code != CODE_SUCCESS) && (code != CODE_FILE_DATA) && (code != CODE_ERROR_REMOTE)) {
  918. PRINT_VERBOSE(1, "Found new flag %02x\n", code);
  919. }
  920. remove_file(bname);
  921. f = fopen(bname, "wb");
  922. while (f && (code == CODE_FILE_DATA)) {
  923. blocksize = nlen-1;
  924. bdone = 0;
  925. rlen = 0;
  926. while (bdone < blocksize) {
  927. if ((blocksize - bdone) < sizeof(buf)) {
  928. rlen = blocksize - bdone;
  929. } else {
  930. rlen = sizeof(buf);
  931. }
  932. mobilebackup2_receive_raw(mobilebackup2, buf, rlen, &r);
  933. if ((int)r <= 0) {
  934. break;
  935. }
  936. fwrite(buf, 1, r, f);
  937. bdone += r;
  938. }
  939. if (bdone == blocksize) {
  940. backup_real_size += blocksize;
  941. }
  942. if (backup_total_size > 0) {
  943. print_progress(backup_real_size, backup_total_size);
  944. }
  945. if (quit_flag)
  946. break;
  947. nlen = 0;
  948. mobilebackup2_receive_raw(mobilebackup2, (char*)&nlen, 4, &r);
  949. nlen = be32toh(nlen);
  950. if (nlen > 0) {
  951. last_code = code;
  952. mobilebackup2_receive_raw(mobilebackup2, &code, 1, &r);
  953. } else {
  954. break;
  955. }
  956. }
  957. if (f) {
  958. fclose(f);
  959. file_count++;
  960. } else {
  961. errcode = errno_to_device_error(errno);
  962. errdesc = strerror(errno);
  963. printf("Error opening '%s' for writing: %s\n", bname, errdesc);
  964. break;
  965. }
  966. if (nlen == 0) {
  967. break;
  968. }
  969. /* check if an error message was received */
  970. if (code == CODE_ERROR_REMOTE) {
  971. /* error message */
  972. char *msg = (char*)malloc(nlen);
  973. mobilebackup2_receive_raw(mobilebackup2, msg, nlen-1, &r);
  974. msg[r] = 0;
  975. /* If sent using CODE_FILE_DATA, end marker will be CODE_ERROR_REMOTE which is not an error! */
  976. if (last_code != CODE_FILE_DATA) {
  977. fprintf(stdout, "\nReceived an error message from device: %s\n", msg);
  978. }
  979. free(msg);
  980. }
  981. } while (1);
  982. if (fname != NULL)
  983. free(fname);
  984. /* if there are leftovers to read, finish up cleanly */
  985. if ((int)nlen-1 > 0) {
  986. PRINT_VERBOSE(1, "\nDiscarding current data hunk.\n");
  987. fname = (char*)malloc(nlen-1);
  988. mobilebackup2_receive_raw(mobilebackup2, fname, nlen-1, &r);
  989. free(fname);
  990. remove_file(bname);
  991. }
  992. /* clean up */
  993. if (bname != NULL)
  994. free(bname);
  995. if (dname != NULL)
  996. free(dname);
  997. plist_t empty_plist = plist_new_dict();
  998. mobilebackup2_send_status_response(mobilebackup2, errcode, errdesc, empty_plist);
  999. plist_free(empty_plist);
  1000. return file_count;
  1001. }
  1002. static void mb2_handle_list_directory(mobilebackup2_client_t mobilebackup2, plist_t message, const char *backup_dir)
  1003. {
  1004. if (!message || (plist_get_node_type(message) != PLIST_ARRAY) || plist_array_get_size(message) < 2 || !backup_dir) return;
  1005. plist_t node = plist_array_get_item(message, 1);
  1006. char *str = NULL;
  1007. if (plist_get_node_type(node) == PLIST_STRING) {
  1008. plist_get_string_val(node, &str);
  1009. }
  1010. if (!str) {
  1011. printf("ERROR: Malformed DLContentsOfDirectory message\n");
  1012. // TODO error handling
  1013. return;
  1014. }
  1015. char *path = string_build_path(backup_dir, str, NULL);
  1016. free(str);
  1017. plist_t dirlist = plist_new_dict();
  1018. DIR* cur_dir = opendir(path);
  1019. if (cur_dir) {
  1020. struct dirent* ep;
  1021. while ((ep = readdir(cur_dir))) {
  1022. if ((strcmp(ep->d_name, ".") == 0) || (strcmp(ep->d_name, "..") == 0)) {
  1023. continue;
  1024. }
  1025. char *fpath = string_build_path(path, ep->d_name, NULL);
  1026. if (fpath) {
  1027. plist_t fdict = plist_new_dict();
  1028. struct stat st;
  1029. stat(fpath, &st);
  1030. const char *ftype = "DLFileTypeUnknown";
  1031. if (S_ISDIR(st.st_mode)) {
  1032. ftype = "DLFileTypeDirectory";
  1033. } else if (S_ISREG(st.st_mode)) {
  1034. ftype = "DLFileTypeRegular";
  1035. }
  1036. plist_dict_set_item(fdict, "DLFileType", plist_new_string(ftype));
  1037. plist_dict_set_item(fdict, "DLFileSize", plist_new_uint(st.st_size));
  1038. plist_dict_set_item(fdict, "DLFileModificationDate",
  1039. plist_new_date(st.st_mtime - MAC_EPOCH, 0));
  1040. plist_dict_set_item(dirlist, ep->d_name, fdict);
  1041. free(fpath);
  1042. }
  1043. }
  1044. closedir(cur_dir);
  1045. }
  1046. free(path);
  1047. /* TODO error handling */
  1048. mobilebackup2_error_t err = mobilebackup2_send_status_response(mobilebackup2, 0, NULL, dirlist);
  1049. plist_free(dirlist);
  1050. if (err != MOBILEBACKUP2_E_SUCCESS) {
  1051. printf("Could not send status response, error %d\n", err);
  1052. }
  1053. }
  1054. static void mb2_handle_make_directory(mobilebackup2_client_t mobilebackup2, plist_t message, const char *backup_dir)
  1055. {
  1056. if (!message || (plist_get_node_type(message) != PLIST_ARRAY) || plist_array_get_size(message) < 2 || !backup_dir) return;
  1057. plist_t dir = plist_array_get_item(message, 1);
  1058. char *str = NULL;
  1059. int errcode = 0;
  1060. char *errdesc = NULL;
  1061. plist_get_string_val(dir, &str);
  1062. char *newpath = string_build_path(backup_dir, str, NULL);
  1063. free(str);
  1064. if (mkdir_with_parents(newpath, 0755) < 0) {
  1065. errdesc = strerror(errno);
  1066. if (errno != EEXIST) {
  1067. printf("mkdir: %s (%d)\n", errdesc, errno);
  1068. }
  1069. errcode = errno_to_device_error(errno);
  1070. }
  1071. free(newpath);
  1072. mobilebackup2_error_t err = mobilebackup2_send_status_response(mobilebackup2, errcode, errdesc, NULL);
  1073. if (err != MOBILEBACKUP2_E_SUCCESS) {
  1074. printf("Could not send status response, error %d\n", err);
  1075. }
  1076. }
  1077. static void mb2_copy_file_by_path(const char *src, const char *dst)
  1078. {
  1079. FILE *from, *to;
  1080. char buf[BUFSIZ];
  1081. size_t length;
  1082. /* open source file */
  1083. if ((from = fopen(src, "rb")) == NULL) {
  1084. printf("Cannot open source path '%s'.\n", src);
  1085. return;
  1086. }
  1087. /* open destination file */
  1088. if ((to = fopen(dst, "wb")) == NULL) {
  1089. printf("Cannot open destination file '%s'.\n", dst);
  1090. fclose(from);
  1091. return;
  1092. }
  1093. /* copy the file */
  1094. while ((length = fread(buf, 1, BUFSIZ, from)) != 0) {
  1095. fwrite(buf, 1, length, to);
  1096. }
  1097. if(fclose(from) == EOF) {
  1098. printf("Error closing source file.\n");
  1099. }
  1100. if(fclose(to) == EOF) {
  1101. printf("Error closing destination file.\n");
  1102. }
  1103. }
  1104. static void mb2_copy_directory_by_path(const char *src, const char *dst)
  1105. {
  1106. if (!src || !dst) {
  1107. return;
  1108. }
  1109. struct stat st;
  1110. /* if src does not exist */
  1111. if ((stat(src, &st) < 0) || !S_ISDIR(st.st_mode)) {
  1112. printf("ERROR: Source directory does not exist '%s': %s (%d)\n", src, strerror(errno), errno);
  1113. return;
  1114. }
  1115. /* if dst directory does not exist */
  1116. if ((stat(dst, &st) < 0) || !S_ISDIR(st.st_mode)) {
  1117. /* create it */
  1118. if (mkdir_with_parents(dst, 0755) < 0) {
  1119. printf("ERROR: Unable to create destination directory '%s': %s (%d)\n", dst, strerror(errno), errno);
  1120. return;
  1121. }
  1122. }
  1123. /* loop over src directory contents */
  1124. DIR *cur_dir = opendir(src);
  1125. if (cur_dir) {
  1126. struct dirent* ep;
  1127. while ((ep = readdir(cur_dir))) {
  1128. if ((strcmp(ep->d_name, ".") == 0) || (strcmp(ep->d_name, "..") == 0)) {
  1129. continue;
  1130. }
  1131. char *srcpath = string_build_path(src, ep->d_name, NULL);
  1132. char *dstpath = string_build_path(dst, ep->d_name, NULL);
  1133. if (srcpath && dstpath) {
  1134. /* copy file */
  1135. mb2_copy_file_by_path(srcpath, dstpath);
  1136. }
  1137. if (srcpath)
  1138. free(srcpath);
  1139. if (dstpath)
  1140. free(dstpath);
  1141. }
  1142. closedir(cur_dir);
  1143. }
  1144. }
  1145. #ifdef WIN32
  1146. #define BS_CC '\b'
  1147. #define my_getch getch
  1148. #else
  1149. #define BS_CC 0x7f
  1150. static int my_getch(void)
  1151. {
  1152. struct termios oldt, newt;
  1153. int ch;
  1154. tcgetattr(STDIN_FILENO, &oldt);
  1155. newt = oldt;
  1156. newt.c_lflag &= ~(ICANON | ECHO);
  1157. tcsetattr(STDIN_FILENO, TCSANOW, &newt);
  1158. ch = getchar();
  1159. tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
  1160. return ch;
  1161. }
  1162. #endif
  1163. static void get_hidden_input(char *buf, int maxlen)
  1164. {
  1165. int pwlen = 0;
  1166. int c;
  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. static char* ask_for_password(const char* msg, int type_again)
  1184. {
  1185. char pwbuf[256];
  1186. fprintf(stderr, "%s: ", msg);
  1187. fflush(stderr);
  1188. get_hidden_input(pwbuf, 256);
  1189. fputc('\n', stderr);
  1190. if (type_again) {
  1191. char pwrep[256];
  1192. fprintf(stderr, "%s (repeat): ", msg);
  1193. fflush(stderr);
  1194. get_hidden_input(pwrep, 256);
  1195. fputc('\n', stderr);
  1196. if (strcmp(pwbuf, pwrep) != 0) {
  1197. printf("ERROR: passwords don't match\n");
  1198. return NULL;
  1199. }
  1200. }
  1201. return strdup(pwbuf);
  1202. }
  1203. /**
  1204. * signal handler function for cleaning up properly
  1205. */
  1206. static void clean_exit(int sig)
  1207. {
  1208. fprintf(stderr, "Exiting...\n");
  1209. quit_flag++;
  1210. }
  1211. static void print_usage(int argc, char **argv)
  1212. {
  1213. char *name = NULL;
  1214. name = strrchr(argv[0], '/');
  1215. printf("Usage: %s [OPTIONS] CMD [CMDOPTIONS] DIRECTORY\n", (name ? name + 1: argv[0]));
  1216. printf("\n");
  1217. printf("Create or restore backup from the current or specified directory.\n");
  1218. printf("\n");
  1219. printf("CMD:\n");
  1220. printf(" backup\tcreate backup for the device\n");
  1221. printf(" --full\t\tforce full backup from device.\n");
  1222. printf(" restore\trestore last backup to the device\n");
  1223. printf(" --system\t\trestore system files, too.\n");
  1224. printf(" --no-reboot\t\tdo NOT reboot the device when done (default: yes).\n");
  1225. printf(" --copy\t\tcreate a copy of backup folder before restoring.\n");
  1226. printf(" --settings\t\trestore device settings from the backup.\n");
  1227. printf(" --remove\t\tremove items which are not being restored\n");
  1228. printf(" --skip-apps\t\tdo not trigger re-installation of apps after restore\n");
  1229. printf(" --password PWD\tsupply the password of the source backup\n");
  1230. printf(" info\t\tshow details about last completed backup of device\n");
  1231. printf(" list\t\tlist files of last completed backup in CSV format\n");
  1232. printf(" unback\tunpack a completed backup in DIRECTORY/_unback_/\n");
  1233. printf(" encryption on|off [PWD]\tenable or disable backup encryption\n");
  1234. printf(" NOTE: password will be requested in interactive mode if omitted\n");
  1235. printf(" changepw [OLD NEW] change backup password on target device\n");
  1236. printf(" NOTE: passwords will be requested in interactive mode if omitted\n");
  1237. printf(" cloud on|off\tenable or disable cloud use (requires iCloud account)\n");
  1238. printf("\n");
  1239. printf("OPTIONS:\n");
  1240. printf(" -u, --udid UDID\ttarget specific device by UDID\n");
  1241. printf(" -s, --source UDID\tuse backup data from device specified by UDID\n");
  1242. printf(" -n, --network\t\tconnect to network device\n");
  1243. printf(" -i, --interactive\trequest passwords interactively\n");
  1244. printf(" -d, --debug\t\tenable communication debugging\n");
  1245. printf(" -h, --help\t\tprints usage information\n");
  1246. printf(" -v, --version\t\tprints version information\n");
  1247. printf("\n");
  1248. }
  1249. #define DEVICE_VERSION(maj, min, patch) (((maj & 0xFF) << 16) | ((min & 0xFF) << 8) | (patch & 0xFF))
  1250. int mainLOL(char *path, char *uuidi)
  1251. {
  1252. idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
  1253. lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR;
  1254. int i;
  1255. char* udid = NULL;
  1256. char* source_udid = "MDMB";
  1257. int use_network = 0;
  1258. lockdownd_service_descriptor_t service = NULL;
  1259. int cmd = -1;
  1260. int cmd_flags = 0;
  1261. int is_full_backup = 0;
  1262. int result_code = -1;
  1263. char* backup_directory = NULL;
  1264. int interactive_mode = 0;
  1265. char* backup_password = NULL;
  1266. char* newpw = NULL;
  1267. struct stat st;
  1268. plist_t node_tmp = NULL;
  1269. plist_t info_plist = NULL;
  1270. plist_t opts = NULL;
  1271. mobilebackup2_error_t err;
  1272. /* we need to exit cleanly on running backups and restores or we cause havok */
  1273. signal(SIGINT, clean_exit);
  1274. signal(SIGTERM, clean_exit);
  1275. #ifndef WIN32
  1276. signal(SIGQUIT, clean_exit);
  1277. signal(SIGPIPE, SIG_IGN);
  1278. #endif
  1279. udid = uuidi;
  1280. backup_directory = path;
  1281. cmd = CMD_RESTORE;
  1282. cmd_flags |= CMD_FLAG_RESTORE_SETTINGS;
  1283. /* verify options */
  1284. if (cmd == -1) {
  1285. printf("No command specified.\n");
  1286. return -1;
  1287. }
  1288. if (backup_directory == NULL) {
  1289. printf("No target backup directory specified.\n");
  1290. return -1;
  1291. }
  1292. /* verify if passed backup directory exists */
  1293. if (stat(backup_directory, &st) != 0) {
  1294. printf("ERROR: Backup directory \"%s\" does not exist!\n", backup_directory);
  1295. return -1;
  1296. }
  1297. idevice_t device = NULL;
  1298. ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX);
  1299. if (ret != IDEVICE_E_SUCCESS) {
  1300. if (udid) {
  1301. printf("No device found with udid %s.\n", udid);
  1302. } else {
  1303. printf("No device found.\n");
  1304. }
  1305. return -1;
  1306. }
  1307. if (!udid) {
  1308. idevice_get_udid(device, &udid);
  1309. }
  1310. if (!source_udid) {
  1311. source_udid = strdup(udid);
  1312. }
  1313. uint8_t is_encrypted = 0;
  1314. char *info_path = NULL;
  1315. if (cmd != CMD_CLOUD) {
  1316. /* backup directory must contain an Info.plist */
  1317. info_path = string_build_path(backup_directory, source_udid, "Info.plist", NULL);
  1318. if (cmd == CMD_RESTORE || cmd == CMD_UNBACK) {
  1319. if (stat(info_path, &st) != 0) {
  1320. idevice_free(device);
  1321. free(info_path);
  1322. return -1;
  1323. }
  1324. char* manifest_path = string_build_path(backup_directory, source_udid, "Manifest.plist", NULL);
  1325. if (stat(manifest_path, &st) != 0) {
  1326. free(info_path);
  1327. }
  1328. plist_t manifest_plist = NULL;
  1329. plist_read_from_filename(&manifest_plist, manifest_path);
  1330. if (!manifest_plist) {
  1331. idevice_free(device);
  1332. free(info_path);
  1333. free(manifest_path);
  1334. return -1;
  1335. }
  1336. node_tmp = plist_dict_get_item(manifest_plist, "IsEncrypted");
  1337. if (node_tmp && (plist_get_node_type(node_tmp) == PLIST_BOOLEAN)) {
  1338. plist_get_bool_val(node_tmp, &is_encrypted);
  1339. }
  1340. plist_free(manifest_plist);
  1341. free(manifest_path);
  1342. }
  1343. }
  1344. lockdownd_client_t lockdown = NULL;
  1345. if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME))) {
  1346. printf("ERROR: Could not connect to lockdownd, error code %d\n", ldret);
  1347. idevice_free(device);
  1348. return -1;
  1349. }
  1350. uint8_t willEncrypt = 0;
  1351. node_tmp = NULL;
  1352. lockdownd_get_value(lockdown, "com.apple.mobile.backup", "WillEncrypt", &node_tmp);
  1353. if (node_tmp) {
  1354. if (plist_get_node_type(node_tmp) == PLIST_BOOLEAN) {
  1355. plist_get_bool_val(node_tmp, &willEncrypt);
  1356. }
  1357. plist_free(node_tmp);
  1358. node_tmp = NULL;
  1359. }
  1360. /* get ProductVersion */
  1361. char *product_version = NULL;
  1362. int device_version = 0;
  1363. node_tmp = NULL;
  1364. lockdownd_get_value(lockdown, NULL, "ProductVersion", &node_tmp);
  1365. if (node_tmp) {
  1366. if (plist_get_node_type(node_tmp) == PLIST_STRING) {
  1367. plist_get_string_val(node_tmp, &product_version);
  1368. }
  1369. plist_free(node_tmp);
  1370. node_tmp = NULL;
  1371. }
  1372. if (product_version) {
  1373. int vers[3] = { 0, 0, 0 };
  1374. if (sscanf(product_version, "%d.%d.%d", &vers[0], &vers[1], &vers[2]) >= 2) {
  1375. device_version = DEVICE_VERSION(vers[0], vers[1], vers[2]);
  1376. }
  1377. }
  1378. /* start notification_proxy */
  1379. np_client_t np = NULL;
  1380. ldret = lockdownd_start_service(lockdown, NP_SERVICE_NAME, &service);
  1381. if ((ldret == LOCKDOWN_E_SUCCESS) && service && service->port) {
  1382. np_client_new(device, service, &np);
  1383. np_set_notify_callback(np, notify_cb, NULL);
  1384. const char *noties[5] = {
  1385. NP_SYNC_CANCEL_REQUEST,
  1386. NP_SYNC_SUSPEND_REQUEST,
  1387. NP_SYNC_RESUME_REQUEST,
  1388. NP_BACKUP_DOMAIN_CHANGED,
  1389. NULL
  1390. };
  1391. np_observe_notifications(np, noties);
  1392. } else {
  1393. printf("ERROR: Could not start service %s.\n", NP_SERVICE_NAME);
  1394. }
  1395. afc_client_t afc = NULL;
  1396. if (cmd == CMD_BACKUP || cmd == CMD_RESTORE) {
  1397. /* start AFC, we need this for the lock file */
  1398. service->port = 0;
  1399. service->ssl_enabled = 0;
  1400. ldret = lockdownd_start_service(lockdown, AFC_SERVICE_NAME, &service);
  1401. if ((ldret == LOCKDOWN_E_SUCCESS) && service->port) {
  1402. afc_client_new(device, service, &afc);
  1403. }
  1404. }
  1405. if (service) {
  1406. lockdownd_service_descriptor_free(service);
  1407. service = NULL;
  1408. }
  1409. /* start mobilebackup service and retrieve port */
  1410. mobilebackup2_client_t mobilebackup2 = NULL;
  1411. ldret = lockdownd_start_service_with_escrow_bag(lockdown, MOBILEBACKUP2_SERVICE_NAME, &service);
  1412. lockdownd_client_free(lockdown);
  1413. lockdown = NULL;
  1414. if ((ldret == LOCKDOWN_E_SUCCESS) && service && service->port) {
  1415. PRINT_VERBOSE(1, "Started \"%s\" service on port %d.\n", MOBILEBACKUP2_SERVICE_NAME, service->port);
  1416. mobilebackup2_client_new(device, service, &mobilebackup2);
  1417. if (service) {
  1418. lockdownd_service_descriptor_free(service);
  1419. service = NULL;
  1420. }
  1421. /* send Hello message */
  1422. double local_versions[2] = {2.0, 2.1};
  1423. double remote_version = 0.0;
  1424. err = mobilebackup2_version_exchange(mobilebackup2, local_versions, 2, &remote_version);
  1425. if (err != MOBILEBACKUP2_E_SUCCESS) {
  1426. printf("Could not perform backup protocol version exchange, error code %d\n", err);
  1427. cmd = CMD_LEAVE;
  1428. goto checkpoint;
  1429. }
  1430. PRINT_VERBOSE(1, "Negotiated Protocol Version %.1f\n", remote_version);
  1431. /* check abort conditions */
  1432. if (quit_flag > 0) {
  1433. PRINT_VERBOSE(1, "Aborting as requested by user...\n");
  1434. cmd = CMD_LEAVE;
  1435. goto checkpoint;
  1436. }
  1437. /* verify existing Info.plist */
  1438. if (info_path && (stat(info_path, &st) == 0) && cmd != CMD_CLOUD) {
  1439. PRINT_VERBOSE(1, "Reading Info.plist from backup.\n");
  1440. plist_read_from_filename(&info_plist, info_path);
  1441. if (!info_plist) {
  1442. printf("Could not read Info.plist\n");
  1443. is_full_backup = 1;
  1444. }
  1445. } else {
  1446. if (cmd == CMD_RESTORE) {
  1447. printf("Aborting restore. Info.plist is missing.\n");
  1448. cmd = CMD_LEAVE;
  1449. } else {
  1450. is_full_backup = 1;
  1451. }
  1452. }
  1453. uint64_t lockfile = 0;
  1454. if (cmd == CMD_BACKUP || cmd == CMD_RESTORE) {
  1455. do_post_notification(device, NP_SYNC_WILL_START);
  1456. afc_file_open(afc, "/com.apple.itunes.lock_sync", AFC_FOPEN_RW, &lockfile);
  1457. }
  1458. if (lockfile) {
  1459. afc_error_t aerr;
  1460. do_post_notification(device, NP_SYNC_LOCK_REQUEST);
  1461. for (i = 0; i < LOCK_ATTEMPTS; i++) {
  1462. aerr = afc_file_lock(afc, lockfile, AFC_LOCK_EX);
  1463. if (aerr == AFC_E_SUCCESS) {
  1464. do_post_notification(device, NP_SYNC_DID_START);
  1465. break;
  1466. } else if (aerr == AFC_E_OP_WOULD_BLOCK) {
  1467. usleep(LOCK_WAIT);
  1468. continue;
  1469. } else {
  1470. fprintf(stderr, "ERROR: could not lock file! error code: %d\n", aerr);
  1471. afc_file_close(afc, lockfile);
  1472. lockfile = 0;
  1473. cmd = CMD_LEAVE;
  1474. }
  1475. }
  1476. if (i == LOCK_ATTEMPTS) {
  1477. fprintf(stderr, "ERROR: timeout while locking for sync\n");
  1478. afc_file_close(afc, lockfile);
  1479. lockfile = 0;
  1480. cmd = CMD_LEAVE;
  1481. }
  1482. }
  1483. checkpoint:
  1484. switch(cmd) {
  1485. case CMD_RESTORE:
  1486. /* TODO: verify battery on AC enough battery remaining */
  1487. /* verify if Status.plist says we read from an successful backup */
  1488. if (!mb2_status_check_snapshot_state(backup_directory, source_udid, "finished")) {
  1489. printf("ERROR: Cannot ensure we restore from a successful backup. Aborting.\n");
  1490. cmd = CMD_LEAVE;
  1491. break;
  1492. }
  1493. PRINT_VERBOSE(1, "Starting Restore...\n");
  1494. opts = plist_new_dict();
  1495. plist_dict_set_item(opts, "RestoreSystemFiles", plist_new_bool(cmd_flags & CMD_FLAG_RESTORE_SYSTEM_FILES));
  1496. if (cmd_flags & CMD_FLAG_RESTORE_NO_REBOOT)
  1497. plist_dict_set_item(opts, "RestoreShouldReboot", plist_new_bool(0));
  1498. if ((cmd_flags & CMD_FLAG_RESTORE_COPY_BACKUP) == 0)
  1499. plist_dict_set_item(opts, "RestoreDontCopyBackup", plist_new_bool(1));
  1500. plist_dict_set_item(opts, "RestorePreserveSettings", plist_new_bool((cmd_flags & CMD_FLAG_RESTORE_SETTINGS) == 0));
  1501. if (cmd_flags & CMD_FLAG_RESTORE_REMOVE_ITEMS)
  1502. plist_dict_set_item(opts, "RemoveItemsNotRestored", plist_new_bool(1));
  1503. if (backup_password != NULL) {
  1504. plist_dict_set_item(opts, "Password", plist_new_string(backup_password));
  1505. }
  1506. if (cmd_flags & CMD_FLAG_RESTORE_SKIP_APPS) {
  1507. } else {
  1508. /* Write /iTunesRestore/RestoreApplications.plist so that the device will start
  1509. * restoring applications once the rest of the restore process is finished */
  1510. if (write_restore_applications(info_plist, afc) < 0) {
  1511. cmd = CMD_LEAVE;
  1512. break;
  1513. } else {
  1514. }
  1515. }
  1516. /* Start restore */
  1517. err = mobilebackup2_send_request(mobilebackup2, "Restore", udid, source_udid, opts);
  1518. plist_free(opts);
  1519. if (err != MOBILEBACKUP2_E_SUCCESS) {
  1520. if (err == MOBILEBACKUP2_E_BAD_VERSION) {
  1521. printf("ERROR: Could not start restore process: backup protocol version mismatch!\n");
  1522. } else if (err == MOBILEBACKUP2_E_REPLY_NOT_OK) {
  1523. printf("ERROR: Could not start restore process: device refused to start the restore process.\n");
  1524. } else {
  1525. printf("ERROR: Could not start restore process: unspecified error occurred\n");
  1526. }
  1527. cmd = CMD_LEAVE;
  1528. }
  1529. break;
  1530. case CMD_INFO:
  1531. PRINT_VERBOSE(1, "Requesting backup info from device...\n");
  1532. err = mobilebackup2_send_request(mobilebackup2, "Info", udid, source_udid, NULL);
  1533. if (err != MOBILEBACKUP2_E_SUCCESS) {
  1534. printf("Error requesting backup info from device, error code %d\n", err);
  1535. cmd = CMD_LEAVE;
  1536. }
  1537. break;
  1538. case CMD_LIST:
  1539. PRINT_VERBOSE(1, "Requesting backup list from device...\n");
  1540. err = mobilebackup2_send_request(mobilebackup2, "List", udid, source_udid, NULL);
  1541. if (err != MOBILEBACKUP2_E_SUCCESS) {
  1542. printf("Error requesting backup list from device, error code %d\n", err);
  1543. cmd = CMD_LEAVE;
  1544. }
  1545. break;
  1546. case CMD_UNBACK:
  1547. PRINT_VERBOSE(1, "Starting to unpack backup...\n");
  1548. if (backup_password != NULL) {
  1549. opts = plist_new_dict();
  1550. plist_dict_set_item(opts, "Password", plist_new_string(backup_password));
  1551. }
  1552. PRINT_VERBOSE(1, "Backup password: %s\n", (backup_password == NULL ? "No":"Yes"));
  1553. err = mobilebackup2_send_request(mobilebackup2, "Unback", udid, source_udid, opts);
  1554. if (backup_password !=NULL) {
  1555. plist_free(opts);
  1556. }
  1557. if (err != MOBILEBACKUP2_E_SUCCESS) {
  1558. printf("Error requesting unback operation from device, error code %d\n", err);
  1559. cmd = CMD_LEAVE;
  1560. }
  1561. break;
  1562. case CMD_CHANGEPW:
  1563. opts = plist_new_dict();
  1564. plist_dict_set_item(opts, "TargetIdentifier", plist_new_string(udid));
  1565. if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) {
  1566. if (!willEncrypt) {
  1567. if (!newpw) {
  1568. newpw = ask_for_password("Enter new backup password", 1);
  1569. }
  1570. if (!newpw) {
  1571. printf("No backup password given. Aborting.\n");
  1572. }
  1573. } else {
  1574. printf("ERROR: Backup encryption is already enabled. Aborting.\n");
  1575. cmd = CMD_LEAVE;
  1576. if (newpw) {
  1577. free(newpw);
  1578. newpw = NULL;
  1579. }
  1580. }
  1581. } else if (cmd_flags & CMD_FLAG_ENCRYPTION_DISABLE) {
  1582. if (willEncrypt) {
  1583. if (!backup_password) {
  1584. backup_password = ask_for_password("Enter current backup password", 0);
  1585. }
  1586. } else {
  1587. printf("ERROR: Backup encryption is not enabled. Aborting.\n");
  1588. cmd = CMD_LEAVE;
  1589. if (backup_password) {
  1590. free(backup_password);
  1591. backup_password = NULL;
  1592. }
  1593. }
  1594. } else if (cmd_flags & CMD_FLAG_ENCRYPTION_CHANGEPW) {
  1595. if (willEncrypt) {
  1596. if (!backup_password) {
  1597. backup_password = ask_for_password("Enter old backup password", 0);
  1598. newpw = ask_for_password("Enter new backup password", 1);
  1599. }
  1600. } else {
  1601. printf("ERROR: Backup encryption is not enabled so can't change password. Aborting.\n");
  1602. cmd = CMD_LEAVE;
  1603. if (newpw) {
  1604. free(newpw);
  1605. newpw = NULL;
  1606. }
  1607. if (backup_password) {
  1608. free(backup_password);
  1609. backup_password = NULL;
  1610. }
  1611. }
  1612. }
  1613. if (newpw) {
  1614. plist_dict_set_item(opts, "NewPassword", plist_new_string(newpw));
  1615. }
  1616. if (backup_password) {
  1617. plist_dict_set_item(opts, "OldPassword", plist_new_string(backup_password));
  1618. }
  1619. if (newpw || backup_password) {
  1620. mobilebackup2_send_message(mobilebackup2, "ChangePassword", opts);
  1621. uint8_t passcode_hint = 0;
  1622. if (device_version >= DEVICE_VERSION(13,0,0)) {
  1623. diagnostics_relay_client_t diag = NULL;
  1624. if (diagnostics_relay_client_start_service(device, &diag, TOOL_NAME) == DIAGNOSTICS_RELAY_E_SUCCESS) {
  1625. plist_t dict = NULL;
  1626. plist_t keys = plist_new_array();
  1627. plist_array_append_item(keys, plist_new_string("PasswordConfigured"));
  1628. if (diagnostics_relay_query_mobilegestalt(diag, keys, &dict) == DIAGNOSTICS_RELAY_E_SUCCESS) {
  1629. plist_t node = plist_access_path(dict, 2, "MobileGestalt", "PasswordConfigured");
  1630. plist_get_bool_val(node, &passcode_hint);
  1631. }
  1632. plist_free(keys);
  1633. plist_free(dict);
  1634. diagnostics_relay_goodbye(diag);
  1635. diagnostics_relay_client_free(diag);
  1636. }
  1637. }
  1638. if (passcode_hint) {
  1639. if (cmd_flags & CMD_FLAG_ENCRYPTION_CHANGEPW) {
  1640. PRINT_VERBOSE(1, "Please confirm changing the backup password by entering the passcode on the device.\n");
  1641. } else if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) {
  1642. PRINT_VERBOSE(1, "Please confirm enabling the backup encryption by entering the passcode on the device.\n");
  1643. } else if (cmd_flags & CMD_FLAG_ENCRYPTION_DISABLE) {
  1644. PRINT_VERBOSE(1, "Please confirm disabling the backup encryption by entering the passcode on the device.\n");
  1645. }
  1646. }
  1647. /*if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) {
  1648. int retr = 10;
  1649. while ((retr-- >= 0) && !backup_domain_changed) {
  1650. sleep(1);
  1651. }
  1652. }*/
  1653. } else {
  1654. cmd = CMD_LEAVE;
  1655. }
  1656. plist_free(opts);
  1657. break;
  1658. default:
  1659. break;
  1660. }
  1661. if (cmd != CMD_LEAVE) {
  1662. /* reset operation success status */
  1663. int operation_ok = 0;
  1664. plist_t message = NULL;
  1665. mobilebackup2_error_t mberr;
  1666. char *dlmsg = NULL;
  1667. int file_count = 0;
  1668. int errcode = 0;
  1669. const char *errdesc = NULL;
  1670. int progress_finished = 0;
  1671. /* process series of DLMessage* operations */
  1672. do {
  1673. free(dlmsg);
  1674. dlmsg = NULL;
  1675. mberr = mobilebackup2_receive_message(mobilebackup2, &message, &dlmsg);
  1676. if (mberr == MOBILEBACKUP2_E_RECEIVE_TIMEOUT) {
  1677. PRINT_VERBOSE(2, "Device is not ready yet, retrying...\n");
  1678. goto files_out;
  1679. } else if (mberr != MOBILEBACKUP2_E_SUCCESS) {
  1680. PRINT_VERBOSE(0, "ERROR: Could not receive from mobilebackup2 (%d)\n", mberr);
  1681. quit_flag++;
  1682. goto files_out;
  1683. }
  1684. if (!strcmp(dlmsg, "DLMessageDownloadFiles")) {
  1685. /* device wants to download files from the computer */
  1686. mb2_set_overall_progress_from_message(message, dlmsg);
  1687. mb2_handle_send_files(mobilebackup2, message, backup_directory);
  1688. } else if (!strcmp(dlmsg, "DLMessageUploadFiles")) {
  1689. /* device wants to send files to the computer */
  1690. mb2_set_overall_progress_from_message(message, dlmsg);
  1691. file_count += mb2_handle_receive_files(mobilebackup2, message, backup_directory);
  1692. } else if (!strcmp(dlmsg, "DLMessageGetFreeDiskSpace")) {
  1693. /* device wants to know how much disk space is available on the computer */
  1694. uint64_t freespace = 0;
  1695. int res = -1;
  1696. #ifdef WIN32
  1697. if (GetDiskFreeSpaceEx(backup_directory, (PULARGE_INTEGER)&freespace, NULL, NULL)) {
  1698. res = 0;
  1699. }
  1700. #else
  1701. struct statvfs fs;
  1702. memset(&fs, '\0', sizeof(fs));
  1703. res = statvfs(backup_directory, &fs);
  1704. if (res == 0) {
  1705. freespace = (uint64_t)fs.f_bavail * (uint64_t)fs.f_bsize;
  1706. }
  1707. #endif
  1708. plist_t freespace_item = plist_new_uint(freespace);
  1709. mobilebackup2_send_status_response(mobilebackup2, res, NULL, freespace_item);
  1710. plist_free(freespace_item);
  1711. } else if (!strcmp(dlmsg, "DLContentsOfDirectory")) {
  1712. /* list directory contents */
  1713. mb2_handle_list_directory(mobilebackup2, message, backup_directory);
  1714. } else if (!strcmp(dlmsg, "DLMessageCreateDirectory")) {
  1715. /* make a directory */
  1716. mb2_handle_make_directory(mobilebackup2, message, backup_directory);
  1717. } else if (!strcmp(dlmsg, "DLMessageMoveFiles") || !strcmp(dlmsg, "DLMessageMoveItems")) {
  1718. /* perform a series of rename operations */
  1719. mb2_set_overall_progress_from_message(message, dlmsg);
  1720. plist_t moves = plist_array_get_item(message, 1);
  1721. uint32_t cnt = plist_dict_get_size(moves);
  1722. PRINT_VERBOSE(1, "Moving %d file%s\n", cnt, (cnt == 1) ? "" : "s");
  1723. plist_dict_iter iter = NULL;
  1724. plist_dict_new_iter(moves, &iter);
  1725. errcode = 0;
  1726. errdesc = NULL;
  1727. if (iter) {
  1728. char *key = NULL;
  1729. plist_t val = NULL;
  1730. do {
  1731. plist_dict_next_item(moves, iter, &key, &val);
  1732. if (key && (plist_get_node_type(val) == PLIST_STRING)) {
  1733. char *str = NULL;
  1734. plist_get_string_val(val, &str);
  1735. if (str) {
  1736. char *newpath = string_build_path(backup_directory, str, NULL);
  1737. free(str);
  1738. char *oldpath = string_build_path(backup_directory, key, NULL);
  1739. if ((stat(newpath, &st) == 0) && S_ISDIR(st.st_mode))
  1740. rmdir_recursive(newpath);
  1741. else
  1742. remove_file(newpath);
  1743. if (rename(oldpath, newpath) < 0) {
  1744. printf("Renameing '%s' to '%s' failed: %s (%d)\n", oldpath, newpath, strerror(errno), errno);
  1745. errcode = errno_to_device_error(errno);
  1746. errdesc = strerror(errno);
  1747. break;
  1748. }
  1749. free(oldpath);
  1750. free(newpath);
  1751. }
  1752. free(key);
  1753. key = NULL;
  1754. }
  1755. } while (val);
  1756. free(iter);
  1757. } else {
  1758. errcode = -1;
  1759. errdesc = "Could not create dict iterator";
  1760. printf("Could not create dict iterator\n");
  1761. }
  1762. plist_t empty_dict = plist_new_dict();
  1763. err = mobilebackup2_send_status_response(mobilebackup2, errcode, errdesc, empty_dict);
  1764. plist_free(empty_dict);
  1765. if (err != MOBILEBACKUP2_E_SUCCESS) {
  1766. printf("Could not send status response, error %d\n", err);
  1767. }
  1768. } else if (!strcmp(dlmsg, "DLMessageRemoveFiles") || !strcmp(dlmsg, "DLMessageRemoveItems")) {
  1769. mb2_set_overall_progress_from_message(message, dlmsg);
  1770. plist_t removes = plist_array_get_item(message, 1);
  1771. uint32_t cnt = plist_array_get_size(removes);
  1772. PRINT_VERBOSE(1, "Removing %d file%s\n", cnt, (cnt == 1) ? "" : "s");
  1773. uint32_t ii = 0;
  1774. errcode = 0;
  1775. errdesc = NULL;
  1776. for (ii = 0; ii < cnt; ii++) {
  1777. plist_t val = plist_array_get_item(removes, ii);
  1778. if (plist_get_node_type(val) == PLIST_STRING) {
  1779. char *str = NULL;
  1780. plist_get_string_val(val, &str);
  1781. if (str) {
  1782. const char *checkfile = strchr(str, '/');
  1783. int suppress_warning = 0;
  1784. if (checkfile) {
  1785. if (strcmp(checkfile+1, "Manifest.mbdx") == 0) {
  1786. suppress_warning = 1;
  1787. }
  1788. }
  1789. char *newpath = string_build_path(backup_directory, str, NULL);
  1790. free(str);
  1791. int res = 0;
  1792. if ((stat(newpath, &st) == 0) && S_ISDIR(st.st_mode)) {
  1793. res = rmdir_recursive(newpath);
  1794. } else {
  1795. res = remove_file(newpath);
  1796. }
  1797. if (res != 0 && res != ENOENT) {
  1798. if (!suppress_warning)
  1799. printf("Could not remove '%s': %s (%d)\n", newpath, strerror(res), res);
  1800. errcode = errno_to_device_error(res);
  1801. errdesc = strerror(res);
  1802. }
  1803. free(newpath);
  1804. }
  1805. }
  1806. }
  1807. plist_t empty_dict = plist_new_dict();
  1808. err = mobilebackup2_send_status_response(mobilebackup2, errcode, errdesc, empty_dict);
  1809. plist_free(empty_dict);
  1810. if (err != MOBILEBACKUP2_E_SUCCESS) {
  1811. printf("Could not send status response, error %d\n", err);
  1812. }
  1813. } else if (!strcmp(dlmsg, "DLMessageCopyItem")) {
  1814. plist_t srcpath = plist_array_get_item(message, 1);
  1815. plist_t dstpath = plist_array_get_item(message, 2);
  1816. errcode = 0;
  1817. errdesc = NULL;
  1818. if ((plist_get_node_type(srcpath) == PLIST_STRING) && (plist_get_node_type(dstpath) == PLIST_STRING)) {
  1819. char *src = NULL;
  1820. char *dst = NULL;
  1821. plist_get_string_val(srcpath, &src);
  1822. plist_get_string_val(dstpath, &dst);
  1823. if (src && dst) {
  1824. char *oldpath = string_build_path(backup_directory, src, NULL);
  1825. char *newpath = string_build_path(backup_directory, dst, NULL);
  1826. PRINT_VERBOSE(1, "Copying '%s' to '%s'\n", src, dst);
  1827. /* check that src exists */
  1828. if ((stat(oldpath, &st) == 0) && S_ISDIR(st.st_mode)) {
  1829. mb2_copy_directory_by_path(oldpath, newpath);
  1830. } else if ((stat(oldpath, &st) == 0) && S_ISREG(st.st_mode)) {
  1831. mb2_copy_file_by_path(oldpath, newpath);
  1832. }
  1833. free(newpath);
  1834. free(oldpath);
  1835. }
  1836. free(src);
  1837. free(dst);
  1838. }
  1839. plist_t empty_dict = plist_new_dict();
  1840. err = mobilebackup2_send_status_response(mobilebackup2, errcode, errdesc, empty_dict);
  1841. plist_free(empty_dict);
  1842. if (err != MOBILEBACKUP2_E_SUCCESS) {
  1843. printf("Could not send status response, error %d\n", err);
  1844. }
  1845. } else if (!strcmp(dlmsg, "DLMessageDisconnect")) {
  1846. break;
  1847. } else if (!strcmp(dlmsg, "DLMessageProcessMessage")) {
  1848. node_tmp = plist_array_get_item(message, 1);
  1849. if (plist_get_node_type(node_tmp) != PLIST_DICT) {
  1850. printf("Unknown message received!\n");
  1851. }
  1852. plist_t nn;
  1853. int error_code = -1;
  1854. nn = plist_dict_get_item(node_tmp, "ErrorCode");
  1855. if (nn && (plist_get_node_type(nn) == PLIST_UINT)) {
  1856. uint64_t ec = 0;
  1857. plist_get_uint_val(nn, &ec);
  1858. error_code = (uint32_t)ec;
  1859. if (error_code == 0) {
  1860. operation_ok = 1;
  1861. result_code = 0;
  1862. } else {
  1863. result_code = -error_code;
  1864. }
  1865. }
  1866. nn = plist_dict_get_item(node_tmp, "ErrorDescription");
  1867. char *str = NULL;
  1868. if (nn && (plist_get_node_type(nn) == PLIST_STRING)) {
  1869. plist_get_string_val(nn, &str);
  1870. }
  1871. if (error_code != 0) {
  1872. if (str) {
  1873. printf("ErrorCode %d: %s\n", error_code, str);
  1874. } else {
  1875. printf("ErrorCode %d: (Unknown)\n", error_code);
  1876. }
  1877. }
  1878. if (str) {
  1879. free(str);
  1880. }
  1881. nn = plist_dict_get_item(node_tmp, "Content");
  1882. if (nn && (plist_get_node_type(nn) == PLIST_STRING)) {
  1883. str = NULL;
  1884. plist_get_string_val(nn, &str);
  1885. PRINT_VERBOSE(1, "Content:\n");
  1886. printf("%s", str);
  1887. free(str);
  1888. }
  1889. break;
  1890. }
  1891. /* print status */
  1892. if ((overall_progress > 0) && !progress_finished) {
  1893. if (overall_progress >= 100.0f) {
  1894. progress_finished = 1;
  1895. }
  1896. print_progress_real(overall_progress, 0);
  1897. PRINT_VERBOSE(1, " Finished\n");
  1898. }
  1899. files_out:
  1900. plist_free(message);
  1901. message = NULL;
  1902. free(dlmsg);
  1903. dlmsg = NULL;
  1904. if (quit_flag > 0) {
  1905. /* need to cancel the backup here */
  1906. //mobilebackup_send_error(mobilebackup, "Cancelling DLSendFile");
  1907. /* remove any atomic Manifest.plist.tmp */
  1908. /*manifest_path = mobilebackup_build_path(backup_directory, "Manifest", ".plist.tmp");
  1909. if (stat(manifest_path, &st) == 0)
  1910. remove(manifest_path);*/
  1911. break;
  1912. }
  1913. } while (1);
  1914. plist_free(message);
  1915. free(dlmsg);
  1916. /* report operation status to user */
  1917. switch (cmd) {
  1918. case CMD_CLOUD:
  1919. if (cmd_flags & CMD_FLAG_CLOUD_ENABLE) {
  1920. if (operation_ok) {
  1921. PRINT_VERBOSE(1, "Cloud backup has been enabled successfully.\n");
  1922. } else {
  1923. PRINT_VERBOSE(1, "Could not enable cloud backup.\n");
  1924. }
  1925. } else if (cmd_flags & CMD_FLAG_CLOUD_DISABLE) {
  1926. if (operation_ok) {
  1927. PRINT_VERBOSE(1, "Cloud backup has been disabled successfully.\n");
  1928. } else {
  1929. PRINT_VERBOSE(1, "Could not disable cloud backup.\n");
  1930. }
  1931. }
  1932. break;
  1933. case CMD_BACKUP:
  1934. PRINT_VERBOSE(1, "Received %d files from device.\n", file_count);
  1935. if (operation_ok && mb2_status_check_snapshot_state(backup_directory, udid, "finished")) {
  1936. PRINT_VERBOSE(1, "Backup Successful.\n");
  1937. } else {
  1938. if (quit_flag) {
  1939. PRINT_VERBOSE(1, "Backup Aborted.\n");
  1940. } else {
  1941. PRINT_VERBOSE(1, "Backup Failed (Error Code %d).\n", -result_code);
  1942. }
  1943. }
  1944. break;
  1945. case CMD_UNBACK:
  1946. if (quit_flag) {
  1947. PRINT_VERBOSE(1, "Unback Aborted.\n");
  1948. } else {
  1949. PRINT_VERBOSE(1, "The files can now be found in the \"_unback_\" directory.\n");
  1950. PRINT_VERBOSE(1, "Unback Successful.\n");
  1951. }
  1952. break;
  1953. case CMD_CHANGEPW:
  1954. if (cmd_flags & CMD_FLAG_ENCRYPTION_ENABLE) {
  1955. if (operation_ok) {
  1956. PRINT_VERBOSE(1, "Backup encryption has been enabled successfully.\n");
  1957. } else {
  1958. PRINT_VERBOSE(1, "Could not enable backup encryption.\n");
  1959. }
  1960. } else if (cmd_flags & CMD_FLAG_ENCRYPTION_DISABLE) {
  1961. if (operation_ok) {
  1962. PRINT_VERBOSE(1, "Backup encryption has been disabled successfully.\n");
  1963. } else {
  1964. PRINT_VERBOSE(1, "Could not disable backup encryption.\n");
  1965. }
  1966. } else if (cmd_flags & CMD_FLAG_ENCRYPTION_CHANGEPW) {
  1967. if (operation_ok) {
  1968. PRINT_VERBOSE(1, "Backup encryption password has been changed successfully.\n");
  1969. } else {
  1970. PRINT_VERBOSE(1, "Could not change backup encryption password.\n");
  1971. }
  1972. }
  1973. break;
  1974. case CMD_RESTORE:
  1975. if (operation_ok) {
  1976. if ((cmd_flags & CMD_FLAG_RESTORE_NO_REBOOT) == 0)
  1977. PRINT_VERBOSE(1, "The device should reboot now.\n");
  1978. PRINT_VERBOSE(1, "Restore Successful.\n");
  1979. } else {
  1980. afc_remove_path(afc, "/iTunesRestore/RestoreApplications.plist");
  1981. afc_remove_path(afc, "/iTunesRestore");
  1982. if (quit_flag) {
  1983. PRINT_VERBOSE(1, "Restore Aborted.\n");
  1984. } else {
  1985. PRINT_VERBOSE(1, "Restore Failed (Error Code %d).\n", -result_code);
  1986. }
  1987. }
  1988. break;
  1989. case CMD_INFO:
  1990. case CMD_LIST:
  1991. case CMD_LEAVE:
  1992. default:
  1993. if (quit_flag) {
  1994. PRINT_VERBOSE(1, "Operation Aborted.\n");
  1995. } else if (cmd == CMD_LEAVE) {
  1996. PRINT_VERBOSE(1, "Operation Failed.\n");
  1997. } else {
  1998. PRINT_VERBOSE(1, "Operation Successful.\n");
  1999. }
  2000. break;
  2001. }
  2002. }
  2003. if (lockfile) {
  2004. afc_file_lock(afc, lockfile, AFC_LOCK_UN);
  2005. afc_file_close(afc, lockfile);
  2006. lockfile = 0;
  2007. if (cmd == CMD_BACKUP || cmd == CMD_RESTORE)
  2008. do_post_notification(device, NP_SYNC_DID_FINISH);
  2009. }
  2010. } else {
  2011. printf("ERROR: Could not start service %s.\n", MOBILEBACKUP2_SERVICE_NAME);
  2012. lockdownd_client_free(lockdown);
  2013. lockdown = NULL;
  2014. }
  2015. if (lockdown) {
  2016. lockdownd_client_free(lockdown);
  2017. lockdown = NULL;
  2018. }
  2019. if (mobilebackup2) {
  2020. mobilebackup2_client_free(mobilebackup2);
  2021. mobilebackup2 = NULL;
  2022. }
  2023. if (afc) {
  2024. afc_client_free(afc);
  2025. afc = NULL;
  2026. }
  2027. if (np) {
  2028. np_client_free(np);
  2029. np = NULL;
  2030. }
  2031. idevice_free(device);
  2032. device = NULL;
  2033. if (backup_password) {
  2034. free(backup_password);
  2035. }
  2036. if (udid) {
  2037. udid = NULL;
  2038. }
  2039. if (source_udid) {
  2040. source_udid = NULL;
  2041. }
  2042. return result_code;
  2043. }