int afc_send_file(afc_client_t afc, const char* local, const char* remote) { FILE* fd = NULL; uint64_t fh = 0; afc_error_t err = 0; unsigned int got = 0; unsigned int gave = 0; unsigned char buffer[0x800]; fd = fopen(local, "rb"); if (fd != NULL ) { err = afc_file_open(afc, remote, AFC_FOPEN_WR, &fh); if (err == AFC_E_SUCCESS) { while (!feof(fd)) { memset(buffer, '\0', sizeof(buffer)); got = fread(buffer, 1, sizeof(buffer), fd); if (got > 0) { afc_file_write(afc, fh, (const char*) buffer, got, &gave); if (gave != got) { printf("Error!!\n"); break; } } } afc_file_close(afc, fh); } fclose(fd); } else return -1; return 0; }
FB::variant ibrowserAPI::uploadFile(const std::string& fileName, const boost::optional<FB::JSObjectPtr>& pcb, F_ADD) { if(fileName.empty()) return false; THREAD(&ibrowserAPI::uploadFile,fileName,pcb); const char *file_name=fileName.c_str(); char target_file[1024]; sprintf(target_file, "%s/%s",uploadFileDir.c_str(), basename((char *)file_name)); uint64_t target_file_handle = 0; if (AFC_E_SUCCESS != afc_file_open(afc_client, target_file, AFC_FOPEN_WRONLY, &target_file_handle)){ ERRO("afc_file_open error!"); } FILE *file_handle= fopen(file_name, "r"); if (!file_handle) { afc_remove_path(afc_client, target_file); ERRO("open file error!"); } off_t fileSize = 0; struct stat st; if (stat(file_name, &st) == 0) fileSize = st.st_size; static int read_buf_size = 1024; char read_buf[read_buf_size]; int bytes_read; uint32_t bytes_written = 0; uint32_t doneSize = 0; while((bytes_read = fread(read_buf, 1, read_buf_size, file_handle)) >0 ) { if (AFC_E_SUCCESS != afc_file_write(afc_client, target_file_handle, read_buf, bytes_read, &bytes_written) || bytes_read !=bytes_written) { ERRO("afc_file_write error!"); } memset(read_buf, 0, read_buf_size); doneSize = doneSize + bytes_read; if(pcb && fileSize > 0) (*pcb)->InvokeAsync("", FB::variant_list_of((double)doneSize/fileSize)); } SUCC(target_file); return target_file; }
static void check_afc(gpointer data) { //prepare a buffer unsigned int buffersize = BUFFER_SIZE * sizeof(unsigned int); int *buf = (int *) malloc(buffersize); int *buf2 = (int *) malloc(buffersize); unsigned int bytes = 0; uint64_t position = 0; //fill buffer int i = 0; for (i = 0; i < BUFFER_SIZE; i++) { buf[i] = ((param *) data)->id * i; } //now writes buffer on device uint64_t file = 0; char path[50]; sprintf(path, "/Buf%i", ((param *) data)->id); afc_file_open(((param *) data)->afc, path, AFC_FOPEN_RW, &file); afc_file_write(((param *) data)->afc, file, (char *) buf, buffersize, &bytes); afc_file_close(((param *) data)->afc, file); file = 0; if (bytes != buffersize) printf("Write operation failed\n"); //now read it bytes = 0; afc_file_open(((param *) data)->afc, path, AFC_FOPEN_RDONLY, &file); afc_file_read(((param *) data)->afc, file, (char *) buf2, buffersize/2, &bytes); afc_file_read(((param *) data)->afc, file, (char *) buf2 + (buffersize/2), buffersize/2, &bytes); if(AFC_E_SUCCESS != afc_file_tell(((param *) data)->afc, file, &position)) printf("Tell operation failed\n"); afc_file_close(((param *) data)->afc, file); if (position != buffersize) printf("Read operation failed\n"); //compare buffers for (i = 0; i < BUFFER_SIZE; i++) { if (buf[i] != buf2[i]) { printf("Buffers are differents, stream corrupted\n"); break; } } //cleanup afc_remove_path(((param *) data)->afc, path); g_thread_exit(0); }
static int afc_upload_file(afc_client_t afc, const char* filename, const char* dstfn) { FILE *f = NULL; uint64_t af = 0; char buf[1048576]; f = fopen(filename, "rb"); if (!f) { fprintf(stderr, "fopen: %s: %s\n", appid, strerror(errno)); return -1; } if ((afc_file_open(afc, dstfn, AFC_FOPEN_WRONLY, &af) != AFC_E_SUCCESS) || !af) { fclose(f); fprintf(stderr, "afc_file_open on '%s' failed!\n", dstfn); return -1; } size_t amount = 0; do { amount = fread(buf, 1, sizeof(buf), f); if (amount > 0) { uint32_t written, total = 0; while (total < amount) { written = 0; afc_error_t aerr = afc_file_write(afc, af, buf, amount, &written); if (aerr != AFC_E_SUCCESS) { fprintf(stderr, "AFC Write error: %d\n", aerr); break; } total += written; } if (total != amount) { fprintf(stderr, "Error: wrote only %d of %zu\n", total, amount); afc_file_close(afc, af); fclose(f); return -1; } } } while (amount > 0); afc_file_close(afc, af); fclose(f); return 0; }
static int ifuse_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { uint32_t bytes = 0; afc_client_t afc = fuse_get_context()->private_data; if (size == 0) return 0; afc_error_t err = afc_file_seek(afc, fi->fh, offset, SEEK_SET); if (err != AFC_E_SUCCESS) { int res = get_afc_error_as_errno(err); return -res; } err = afc_file_write(afc, fi->fh, buf, size, &bytes); if (err != AFC_E_SUCCESS) { int res = get_afc_error_as_errno(err); return -res; } return bytes; }
G_GNUC_INTERNAL gboolean iphone_write_sysinfo_extended (const char *uuid, const char *xml) { lockdownd_client_t client = NULL; idevice_t device = NULL; afc_client_t afc = NULL; idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; afc_error_t afc_ret; uint16_t afcport = 0; uint64_t handle; uint32_t bytes_written; const char device_dir[] = "/iTunes_Control/Device"; const char sysinfoextended_path[] = "/iTunes_Control/Device/SysInfoExtended"; ret = idevice_new(&device, uuid); if (IDEVICE_E_SUCCESS != ret) { printf("No device found with uuid %s, is it plugged in?\n", uuid); return FALSE; } if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(device, &client, "libgpod")) { idevice_free(device); return FALSE; } if (LOCKDOWN_E_SUCCESS != lockdownd_start_service(client, "com.apple.afc", &afcport)) { lockdownd_client_free(client); idevice_free(device); return FALSE; } g_assert (afcport != 0); if (AFC_E_SUCCESS != afc_client_new(device, afcport, &afc)) { lockdownd_client_free(client); idevice_free(device); return FALSE; } afc_ret = afc_make_directory(afc, device_dir); if ((AFC_E_SUCCESS != afc_ret) && (AFC_E_OBJECT_EXISTS != afc_ret)) { afc_client_free(afc); lockdownd_client_free(client); idevice_free(device); return FALSE; } if (AFC_E_SUCCESS != afc_file_open(afc, sysinfoextended_path, AFC_FOPEN_WRONLY, &handle)) { afc_client_free(afc); lockdownd_client_free(client); idevice_free(device); return FALSE; } if (AFC_E_SUCCESS != afc_file_write(afc, handle, xml, strlen(xml), &bytes_written)) { afc_file_close(afc, handle); afc_client_free(afc); lockdownd_client_free(client); idevice_free(device); return FALSE; } afc_file_close(afc, handle); afc_client_free(afc); lockdownd_client_free(client); idevice_free(device); return TRUE; }
int main(int argc, char **argv) { idevice_t device = NULL; lockdownd_client_t lckd = NULL; mobile_image_mounter_client_t mim = NULL; afc_client_t afc = NULL; lockdownd_service_descriptor_t service = NULL; int res = -1; char *image_path = NULL; char *image_sig_path = NULL; parse_opts(argc, argv); argc -= optind; argv += optind; if (!list_mode) { if (argc < 1) { printf("ERROR: No IMAGE_FILE has been given!\n"); return -1; } image_path = strdup(argv[0]); if (argc >= 2) { image_sig_path = strdup(argv[1]); } else { if (asprintf(&image_sig_path, "%s.signature", image_path) < 0) { printf("Out of memory?!\n"); return -1; } } } if (IDEVICE_E_SUCCESS != idevice_new(&device, udid)) { printf("No device found, is it plugged in?\n"); return -1; } if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(device, &lckd, "ideviceimagemounter")) { printf("ERROR: could not connect to lockdown. Exiting.\n"); goto leave; } lockdownd_start_service(lckd, "com.apple.mobile.mobile_image_mounter", &service); if (!service || service->port == 0) { printf("ERROR: Could not start mobile_image_mounter service!\n"); goto leave; } if (mobile_image_mounter_new(device, service, &mim) != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { printf("ERROR: Could not connect to mobile_image_mounter!\n"); goto leave; } if (service) { lockdownd_service_descriptor_free(service); service = NULL; } if (!list_mode) { struct stat fst; if ((lockdownd_start_service(lckd, "com.apple.afc", &service) != LOCKDOWN_E_SUCCESS) || !service || !service->port) { fprintf(stderr, "Could not start com.apple.afc!\n"); goto leave; } if (afc_client_new(device, service, &afc) != AFC_E_SUCCESS) { fprintf(stderr, "Could not connect to AFC!\n"); goto leave; } if (service) { lockdownd_service_descriptor_free(service); service = NULL; } if (stat(image_path, &fst) != 0) { fprintf(stderr, "ERROR: stat: %s: %s\n", image_path, strerror(errno)); goto leave; } if (stat(image_sig_path, &fst) != 0) { fprintf(stderr, "ERROR: stat: %s: %s\n", image_sig_path, strerror(errno)); goto leave; } } lockdownd_client_free(lckd); lckd = NULL; mobile_image_mounter_error_t err; plist_t result = NULL; if (list_mode) { /* list mounts mode */ if (!imagetype) { imagetype = strdup("Developer"); } err = mobile_image_mounter_lookup_image(mim, imagetype, &result); free(imagetype); if (err == MOBILE_IMAGE_MOUNTER_E_SUCCESS) { res = 0; if (xml_mode) { print_xml(result); } else { plist_dict_to_string(result); } } else { printf("Error: lookup_image returned %d\n", err); } } else { char sig[8192]; size_t sig_length = 0; FILE *f = fopen(image_sig_path, "rb"); if (!f) { fprintf(stderr, "Error opening signature file '%s': %s\n", image_sig_path, strerror(errno)); goto leave; } sig_length = fread(sig, 1, sizeof(sig), f); fclose(f); if (sig_length == 0) { fprintf(stderr, "Could not read signature from file '%s'\n", image_sig_path); goto leave; } f = fopen(image_path, "rb"); if (!f) { fprintf(stderr, "Error opening image file '%s': %s\n", image_path, strerror(errno)); goto leave; } char *targetname = NULL; if (asprintf(&targetname, "%s/%s", PKG_PATH, "staging.dimage") < 0) { fprintf(stderr, "Out of memory!?\n"); goto leave; } char *mountname = NULL; if (asprintf(&mountname, "%s/%s", PATH_PREFIX, targetname) < 0) { fprintf(stderr, "Out of memory!?\n"); goto leave; } printf("Copying '%s' --> '%s'\n", image_path, targetname); char **strs = NULL; if (afc_get_file_info(afc, PKG_PATH, &strs) != AFC_E_SUCCESS) { if (afc_make_directory(afc, PKG_PATH) != AFC_E_SUCCESS) { fprintf(stderr, "WARNING: Could not create directory '%s' on device!\n", PKG_PATH); } } if (strs) { int i = 0; while (strs[i]) { free(strs[i]); i++; } free(strs); } uint64_t af = 0; if ((afc_file_open(afc, targetname, AFC_FOPEN_WRONLY, &af) != AFC_E_SUCCESS) || !af) { fclose(f); fprintf(stderr, "afc_file_open on '%s' failed!\n", targetname); goto leave; } char buf[8192]; size_t amount = 0; do { amount = fread(buf, 1, sizeof(buf), f); if (amount > 0) { uint32_t written, total = 0; while (total < amount) { written = 0; if (afc_file_write(afc, af, buf, amount, &written) != AFC_E_SUCCESS) { fprintf(stderr, "AFC Write error!\n"); break; } total += written; } if (total != amount) { fprintf(stderr, "Error: wrote only %d of %d\n", total, (unsigned int)amount); afc_file_close(afc, af); fclose(f); goto leave; } } } while (amount > 0); afc_file_close(afc, af); fclose(f); printf("done.\n"); printf("Mounting...\n"); if (!imagetype) { imagetype = strdup("Developer"); } err = mobile_image_mounter_mount_image(mim, mountname, sig, sig_length, imagetype, &result); free(imagetype); if (err == MOBILE_IMAGE_MOUNTER_E_SUCCESS) { if (result) { plist_t node = plist_dict_get_item(result, "Status"); if (node) { char *status = NULL; plist_get_string_val(node, &status); if (status) { if (!strcmp(status, "Complete")) { printf("Done.\n"); res = 0; } else { printf("unexpected status value:\n"); if (xml_mode) { print_xml(result); } else { plist_dict_to_string(result); } } free(status); } else { printf("unexpected result:\n"); if (xml_mode) { print_xml(result); } else { plist_dict_to_string(result); } } } node = plist_dict_get_item(result, "Error"); if (node) { char *error = NULL; plist_get_string_val(node, &error); if (error) { printf("Error: %s\n", error); free(error); } else { printf("unexpected result:\n"); if (xml_mode) { print_xml(result); } else { plist_dict_to_string(result); } } } else { if (xml_mode) { print_xml(result); } else { plist_dict_to_string(result); } } } } else { printf("Error: mount_image returned %d\n", err); } } if (result) { plist_free(result); } /* perform hangup command */ mobile_image_mounter_hangup(mim); /* free client */ mobile_image_mounter_free(mim); leave: if (afc) { afc_client_free(afc); } if (lckd) { lockdownd_client_free(lckd); } idevice_free(device); if (image_path) free(image_path); if (image_sig_path) free(image_sig_path); return res; }
int main(int argc, char **argv) { idevice_t dev = NULL; lockdownd_client_t client = NULL; house_arrest_client_t hac = NULL; house_arrest_error_t res; int i; char *udid = NULL; const char *appid = NULL; int test_file_io = 0; /* parse cmdline args */ for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { idevice_set_debug_level(1); continue; } else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) { i++; if (!argv[i] || (strlen(argv[i]) != 40)) { print_usage(argc, argv); return 0; } udid = strdup(argv[i]); continue; } else if (!strcmp(argv[i], "-t") || !strcmp(argv[i], "--test")) { test_file_io = 1; continue; } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { print_usage(argc, argv); return 0; } else { appid = argv[i]; break; } } if (!appid) { print_usage(argc, argv); return 0; } if (idevice_new(&dev, udid) != IDEVICE_E_SUCCESS) { printf("no device connected?!\n"); goto leave_cleanup; } if (lockdownd_client_new_with_handshake(dev, &client, NULL) != LOCKDOWN_E_SUCCESS) { printf("could not connect to lockdownd!\n"); goto leave_cleanup; } uint16_t port = 0; if (lockdownd_start_service(client, "com.apple.mobile.house_arrest", &port) != LOCKDOWN_E_SUCCESS) { printf("could not start house_arrest service!\n"); goto leave_cleanup; } if (client) { lockdownd_client_free(client); client = NULL; } if (house_arrest_client_new(dev, port, &hac) != HOUSE_ARREST_E_SUCCESS) { printf("could not connect to house_arrest service!\n"); goto leave_cleanup; } res = house_arrest_send_command(hac, "VendDocuments", appid); if (res != HOUSE_ARREST_E_SUCCESS) { printf("error %d when trying to get VendDocuments\n", res); goto leave_cleanup; } plist_t dict = NULL; if (house_arrest_get_result(hac, &dict) != HOUSE_ARREST_E_SUCCESS) { if (house_arrest_get_result(hac, &dict) != HOUSE_ARREST_E_SUCCESS) { printf("hmmm....\n"); goto leave_cleanup; } } plist_t node = plist_dict_get_item(dict, "Error"); if (node) { char *str = NULL; plist_get_string_val(node, &str); printf("Error: %s\n", str); if (str) free(str); plist_free(dict); dict = NULL; goto leave_cleanup; } node = plist_dict_get_item(dict, "Status"); if (node) { char *str = NULL; plist_get_string_val(node, &str); if (str && (strcmp(str, "Complete") != 0)) { printf("Warning: Status is not 'Complete' but '%s'\n", str); } if (str) free(str); plist_free(dict); dict = NULL; } if (dict) { plist_free(dict); } afc_client_t afc = NULL; afc_error_t ae = afc_client_new_from_house_arrest_client(hac, &afc); if (ae != AFC_E_SUCCESS) { printf("afc error %d\n", ae); } if (ae == AFC_E_SUCCESS) { char **list = NULL; afc_read_directory(afc, "/", &list); printf("Directory contents:\n"); if (list) { while (list[0]) { if (strcmp(list[0], ".") && strcmp(list[0], "..")) { puts(list[0]); } list++; } } if (test_file_io) { uint64_t tf = 0; printf("\n==== Performing file tests ====\n"); printf("Opening file 'foobar' for writing: "); if (afc_file_open(afc, "/foobar", AFC_FOPEN_RW, &tf) == AFC_E_SUCCESS) { uint32_t wb = 0; printf("OK\n"); printf("Writing to file: "); if (afc_file_write(afc, tf, "test\r\n", 6, &wb) != AFC_E_SUCCESS) { printf("ERROR\n"); } else { printf("OK\n"); } afc_file_close(afc, tf); printf("Deleting file 'foobar': "); if (afc_remove_path(afc, "/foobar") == AFC_E_SUCCESS) { printf("OK\n"); } else { printf("ERROR\n"); } } else { printf("ERROR\n"); } } afc_client_free(afc); } else { printf("failed to connect to afc service, error %d\n", ae); } leave_cleanup: if (hac) { house_arrest_client_free(hac); } if (client) { lockdownd_client_free(client); } if (dev) { idevice_free(dev); } return 0; }
int main(int argc, char *argv[]) { unsigned int bytes = 0; uint16_t i = 0; lockdownd_service_descriptor_t service = NULL; lockdownd_client_t client = NULL; idevice_t phone = NULL; uint64_t lockfile = 0; np_client_t gnp = NULL; if (argc > 1 && !strcasecmp(argv[1], "--debug")) { idevice_set_debug_level(1); } else { idevice_set_debug_level(0); } if (IDEVICE_E_SUCCESS != idevice_new(&phone, NULL)) { printf("No device found, is it plugged in?\n"); return -1; } char *udid = NULL; if (IDEVICE_E_SUCCESS == idevice_get_udid(phone, &udid)) { printf("DeviceUniqueID : %s\n", udid); } if (udid) free(udid); if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(phone, &client, "ideviceclient")) { idevice_free(phone); printf("Exiting.\n"); return -1; } char *nnn = NULL; if (LOCKDOWN_E_SUCCESS == lockdownd_get_device_name(client, &nnn)) { printf("DeviceName : %s\n", nnn); free(nnn); } lockdownd_start_service(client, "com.apple.afc", &service); if (service && service->port) { afc_client_t afc = NULL; afc_client_new(phone, service, &afc); if (afc) { service->port = 0; service->ssl_enabled = 0; lockdownd_start_service(client, "com.apple.mobile.notification_proxy", &service); if (service->port) { printf("Notification Proxy started.\n"); np_client_new(phone, service, &gnp); } else { printf("ERROR: Notification proxy could not be started.\n"); } if (gnp) { const char *nspec[5] = { NP_SYNC_CANCEL_REQUEST, NP_SYNC_SUSPEND_REQUEST, NP_SYNC_RESUME_REQUEST, NP_ITDBPREP_DID_END, NULL }; np_observe_notifications(gnp, nspec); np_set_notify_callback(gnp, notifier, NULL); } perform_notification(phone, client, NP_SYNC_WILL_START); afc_file_open(afc, "/com.apple.itunes.lock_sync", AFC_FOPEN_RW, &lockfile); if (lockfile) { printf("locking file\n"); afc_file_lock(afc, lockfile, AFC_LOCK_EX); perform_notification(phone, client, NP_SYNC_DID_START); } char **dirs = NULL; afc_read_directory(afc, "/eafaedf", &dirs); if (!dirs) afc_read_directory(afc, "/", &dirs); printf("Directory time.\n"); for (i = 0; dirs[i]; i++) { printf("/%s\n", dirs[i]); free(dirs[i]); } if (dirs) free(dirs); dirs = NULL; afc_get_device_info(afc, &dirs); if (dirs) { for (i = 0; dirs[i]; i += 2) { printf("%s: %s\n", dirs[i], dirs[i + 1]); free(dirs[i]); } free(dirs); } uint64_t my_file = 0; char **info = NULL; uint64_t fsize = 0; if (AFC_E_SUCCESS == afc_get_file_info(afc, "/readme.libimobiledevice.fx", &info) && info) { for (i = 0; info[i]; i += 2) { printf("%s: %s\n", info[i], info[i+1]); if (!strcmp(info[i], "st_size")) { fsize = atoll(info[i+1]); } } } if (AFC_E_SUCCESS == afc_file_open(afc, "/readme.libimobiledevice.fx", AFC_FOPEN_RDONLY, &my_file) && my_file) { printf("A file size: %llu\n", (long long)fsize); char *file_data = (char *) malloc(sizeof(char) * fsize); afc_file_read(afc, my_file, file_data, fsize, &bytes); if (bytes > 0) { printf("The file's data:\n"); fwrite(file_data, 1, bytes, stdout); } printf("\nClosing my file.\n"); afc_file_close(afc, my_file); free(file_data); } else printf("couldn't open a file\n"); afc_file_open(afc, "/readme.libimobiledevice.fx", AFC_FOPEN_WR, &my_file); if (my_file) { char *outdatafile = strdup("this is a bitchin text file\n"); afc_file_write(afc, my_file, outdatafile, strlen(outdatafile), &bytes); free(outdatafile); if (bytes > 0) printf("Wrote a surprise. ;)\n"); else printf("I wanted to write a surprise, but... :(\n"); afc_file_close(afc, my_file); } printf("Deleting a file...\n"); bytes = afc_remove_path(afc, "/delme"); if (bytes) printf("Success.\n"); else printf("Failure. (expected unless you have a /delme file on your phone)\n"); printf("Renaming a file...\n"); bytes = afc_rename_path(afc, "/renme", "/renme2"); if (bytes > 0) printf("Success.\n"); else printf("Failure. (expected unless you have a /renme file on your phone)\n"); printf("Seek & read\n"); afc_file_open(afc, "/readme.libimobiledevice.fx", AFC_FOPEN_RDONLY, &my_file); if (AFC_E_SUCCESS != afc_file_seek(afc, my_file, 5, SEEK_CUR)) printf("WARN: SEEK DID NOT WORK\n"); char *threeletterword = (char *) malloc(sizeof(char) * 5); afc_file_read(afc, my_file, threeletterword, 3, &bytes); threeletterword[3] = '\0'; if (bytes > 0) printf("Result: %s\n", threeletterword); else printf("Couldn't read!\n"); free(threeletterword); afc_file_close(afc, my_file); } if (gnp && lockfile) { printf("XXX sleeping\n"); sleep(5); printf("XXX unlocking file\n"); afc_file_lock(afc, lockfile, AFC_LOCK_UN); printf("XXX closing file\n"); afc_file_close(afc, lockfile); printf("XXX sleeping\n"); sleep(5); //perform_notification(phone, client, NP_SYNC_DID_FINISH); } if (gnp) { np_client_free(gnp); gnp = NULL; } afc_client_free(afc); lockdownd_service_descriptor_free(service); service = NULL; } else { printf("Start service failure.\n"); } printf("All done.\n"); lockdownd_client_free(client); idevice_free(phone); return 0; }
int main(int argc, char **argv) { idevice_t phone = NULL; lockdownd_client_t client = NULL; instproxy_client_t ipc = NULL; instproxy_error_t err; np_client_t np = NULL; afc_client_t afc = NULL; #ifdef HAVE_LIBIMOBILEDEVICE_1_1_5 lockdownd_service_descriptor_t service = NULL; #else uint16_t service = 0; #endif int res = 0; char *bundleidentifier = NULL; parse_opts(argc, argv); argc -= optind; argv += optind; if (IDEVICE_E_SUCCESS != idevice_new(&phone, udid)) { fprintf(stderr, "No iOS device found, is it plugged in?\n"); return -1; } if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(phone, &client, "ideviceinstaller")) { fprintf(stderr, "Could not connect to lockdownd. Exiting.\n"); goto leave_cleanup; } if ((lockdownd_start_service (client, "com.apple.mobile.notification_proxy", &service) != LOCKDOWN_E_SUCCESS) || !service) { fprintf(stderr, "Could not start com.apple.mobile.notification_proxy!\n"); goto leave_cleanup; } np_error_t nperr = np_client_new(phone, service, &np); #ifdef HAVE_LIBIMOBILEDEVICE_1_1_5 if (service) { lockdownd_service_descriptor_free(service); } service = NULL; #else service = 0; #endif if (nperr != NP_E_SUCCESS) { fprintf(stderr, "Could not connect to notification_proxy!\n"); goto leave_cleanup; } #ifdef HAVE_LIBIMOBILEDEVICE_1_1 np_set_notify_callback(np, notifier, NULL); #else np_set_notify_callback(np, notifier); #endif const char *noties[3] = { NP_APP_INSTALLED, NP_APP_UNINSTALLED, NULL }; np_observe_notifications(np, noties); run_again: #ifdef HAVE_LIBIMOBILEDEVICE_1_1_5 if (service) { lockdownd_service_descriptor_free(service); } service = NULL; #else service = 0; #endif if ((lockdownd_start_service(client, "com.apple.mobile.installation_proxy", &service) != LOCKDOWN_E_SUCCESS) || !service) { fprintf(stderr, "Could not start com.apple.mobile.installation_proxy!\n"); goto leave_cleanup; } err = instproxy_client_new(phone, service, &ipc); #ifdef HAVE_LIBIMOBILEDEVICE_1_1_5 if (service) { lockdownd_service_descriptor_free(service); } service = NULL; #else service = 0; #endif if (err != INSTPROXY_E_SUCCESS) { fprintf(stderr, "Could not connect to installation_proxy!\n"); goto leave_cleanup; } setbuf(stdout, NULL); if (last_status) { free(last_status); last_status = NULL; } notification_expected = 0; if (cmd == CMD_LIST_APPS) { int xml_mode = 0; plist_t client_opts = instproxy_client_options_new(); instproxy_client_options_add(client_opts, "ApplicationType", "User", NULL); plist_t apps = NULL; /* look for options */ if (options) { char *opts = strdup(options); char *elem = strtok(opts, ","); while (elem) { if (!strcmp(elem, "list_system")) { if (!client_opts) { client_opts = instproxy_client_options_new(); } instproxy_client_options_add(client_opts, "ApplicationType", "System", NULL); } else if (!strcmp(elem, "list_all")) { instproxy_client_options_free(client_opts); client_opts = NULL; } else if (!strcmp(elem, "list_user")) { /* do nothing, we're already set */ } else if (!strcmp(elem, "xml")) { xml_mode = 1; } elem = strtok(NULL, ","); } free(opts); } err = instproxy_browse(ipc, client_opts, &apps); instproxy_client_options_free(client_opts); if (err != INSTPROXY_E_SUCCESS) { fprintf(stderr, "ERROR: instproxy_browse returned %d\n", err); goto leave_cleanup; } if (!apps || (plist_get_node_type(apps) != PLIST_ARRAY)) { fprintf(stderr, "ERROR: instproxy_browse returnd an invalid plist!\n"); goto leave_cleanup; } if (xml_mode) { char *xml = NULL; uint32_t len = 0; plist_to_xml(apps, &xml, &len); if (xml) { puts(xml); free(xml); } plist_free(apps); goto leave_cleanup; } printf("Total: %d apps\n", plist_array_get_size(apps)); uint32_t i = 0; for (i = 0; i < plist_array_get_size(apps); i++) { plist_t app = plist_array_get_item(apps, i); plist_t p_appid = plist_dict_get_item(app, "CFBundleIdentifier"); char *s_appid = NULL; char *s_dispName = NULL; char *s_version = NULL; plist_t dispName = plist_dict_get_item(app, "CFBundleDisplayName"); plist_t version = plist_dict_get_item(app, "CFBundleVersion"); if (p_appid) { plist_get_string_val(p_appid, &s_appid); } if (!s_appid) { fprintf(stderr, "ERROR: Failed to get APPID!\n"); break; } if (dispName) { plist_get_string_val(dispName, &s_dispName); } if (version) { plist_get_string_val(version, &s_version); } if (!s_dispName) { s_dispName = strdup(s_appid); } if (s_version) { printf("%s - %s %s\n", s_appid, s_dispName, s_version); free(s_version); } else { printf("%s - %s\n", s_appid, s_dispName); } free(s_dispName); free(s_appid); } plist_free(apps); } else if (cmd == CMD_INSTALL || cmd == CMD_UPGRADE) { plist_t sinf = NULL; plist_t meta = NULL; char *pkgname = NULL; struct stat fst; uint64_t af = 0; char buf[8192]; #ifdef HAVE_LIBIMOBILEDEVICE_1_1_5 if (service) { lockdownd_service_descriptor_free(service); } service = NULL; #else service = 0; #endif if ((lockdownd_start_service(client, "com.apple.afc", &service) != LOCKDOWN_E_SUCCESS) || !service) { fprintf(stderr, "Could not start com.apple.afc!\n"); goto leave_cleanup; } lockdownd_client_free(client); client = NULL; if (afc_client_new(phone, service, &afc) != INSTPROXY_E_SUCCESS) { fprintf(stderr, "Could not connect to AFC!\n"); goto leave_cleanup; } if (stat(appid, &fst) != 0) { fprintf(stderr, "ERROR: stat: %s: %s\n", appid, strerror(errno)); goto leave_cleanup; } char **strs = NULL; if (afc_get_file_info(afc, PKG_PATH, &strs) != AFC_E_SUCCESS) { if (afc_make_directory(afc, PKG_PATH) != AFC_E_SUCCESS) { fprintf(stderr, "WARNING: Could not create directory '%s' on device!\n", PKG_PATH); } } if (strs) { int i = 0; while (strs[i]) { free(strs[i]); i++; } free(strs); } plist_t client_opts = instproxy_client_options_new(); /* open install package */ int errp = 0; struct zip *zf = NULL; if ((strlen(appid) > 5) && (strcmp(&appid[strlen(appid)-5], ".ipcc") == 0)) { zf = zip_open(appid, 0, &errp); if (!zf) { fprintf(stderr, "ERROR: zip_open: %s: %d\n", appid, errp); goto leave_cleanup; } char* ipcc = strdup(appid); if ((asprintf(&pkgname, "%s/%s", PKG_PATH, basename(ipcc)) > 0) && pkgname) { afc_make_directory(afc, pkgname); } printf("Uploading %s package contents... ", basename(ipcc)); /* extract the contents of the .ipcc file to PublicStaging/<name>.ipcc directory */ zip_uint64_t numzf = zip_get_num_entries(zf, 0); zip_uint64_t i = 0; for (i = 0; numzf > 0 && i < numzf; i++) { const char* zname = zip_get_name(zf, i, 0); char* dstpath = NULL; if (!zname) continue; if (zname[strlen(zname)-1] == '/') { // directory if ((asprintf(&dstpath, "%s/%s/%s", PKG_PATH, basename(ipcc), zname) > 0) && dstpath) { afc_make_directory(afc, dstpath); } free(dstpath); dstpath = NULL; } else { // file struct zip_file* zfile = zip_fopen_index(zf, i, 0); if (!zfile) continue; if ((asprintf(&dstpath, "%s/%s/%s", PKG_PATH, basename(ipcc), zname) <= 0) || !dstpath || (afc_file_open(afc, dstpath, AFC_FOPEN_WRONLY, &af) != AFC_E_SUCCESS)) { fprintf(stderr, "ERROR: can't open afc://%s for writing\n", dstpath); free(dstpath); dstpath = NULL; zip_fclose(zfile); continue; } struct zip_stat zs; zip_stat_init(&zs); if (zip_stat_index(zf, i, 0, &zs) != 0) { fprintf(stderr, "ERROR: zip_stat_index %" PRIu64 " failed!\n", i); free(dstpath); dstpath = NULL; zip_fclose(zfile); continue; } free(dstpath); dstpath = NULL; zip_uint64_t zfsize = 0; while (zfsize < zs.size) { zip_int64_t amount = zip_fread(zfile, buf, sizeof(buf)); if (amount == 0) { break; } if (amount > 0) { uint32_t written, total = 0; while (total < amount) { written = 0; if (afc_file_write(afc, af, buf, amount, &written) != AFC_E_SUCCESS) { fprintf(stderr, "AFC Write error!\n"); break; } total += written; } if (total != amount) { fprintf(stderr, "Error: wrote only %d of %" PRIi64 "\n", total, amount); afc_file_close(afc, af); zip_fclose(zfile); free(dstpath); goto leave_cleanup; } } zfsize += amount; } afc_file_close(afc, af); af = 0; zip_fclose(zfile); } } free(ipcc); printf("DONE.\n"); instproxy_client_options_add(client_opts, "PackageType", "CarrierBundle", NULL); } else if (S_ISDIR(fst.st_mode)) { /* upload developer app directory */ instproxy_client_options_add(client_opts, "PackageType", "Developer", NULL); if (asprintf(&pkgname, "%s/%s", PKG_PATH, basename(appid)) < 0) { fprintf(stderr, "ERROR: Out of memory allocating pkgname!?\n"); goto leave_cleanup; } printf("Uploading %s package contents... ", basename(appid)); afc_upload_dir(afc, appid, pkgname); printf("DONE.\n"); } else { zf = zip_open(appid, 0, &errp); if (!zf) { fprintf(stderr, "ERROR: zip_open: %s: %d\n", appid, errp); goto leave_cleanup; } /* extract iTunesMetadata.plist from package */ char *zbuf = NULL; uint32_t len = 0; plist_t meta_dict = NULL; if (zip_get_contents(zf, ITUNES_METADATA_PLIST_FILENAME, 0, &zbuf, &len) == 0) { meta = plist_new_data(zbuf, len); if (memcmp(zbuf, "bplist00", 8) == 0) { plist_from_bin(zbuf, len, &meta_dict); } else { plist_from_xml(zbuf, len, &meta_dict); } } else { fprintf(stderr, "WARNING: could not locate %s in archive!\n", ITUNES_METADATA_PLIST_FILENAME); } if (zbuf) { free(zbuf); } /* determine .app directory in archive */ zbuf = NULL; len = 0; plist_t info = NULL; char* filename = NULL; char* app_directory_name = NULL; if (zip_get_app_directory(zf, &app_directory_name)) { fprintf(stderr, "Unable to locate app directory in archive!\n"); goto leave_cleanup; } /* construct full filename to Info.plist */ filename = (char*)malloc(strlen(app_directory_name)+10+1); strcpy(filename, app_directory_name); free(app_directory_name); app_directory_name = NULL; strcat(filename, "Info.plist"); if (zip_get_contents(zf, filename, 0, &zbuf, &len) < 0) { fprintf(stderr, "WARNING: could not locate %s in archive!\n", filename); free(filename); zip_unchange_all(zf); zip_close(zf); goto leave_cleanup; } free(filename); if (memcmp(zbuf, "bplist00", 8) == 0) { plist_from_bin(zbuf, len, &info); } else { plist_from_xml(zbuf, len, &info); } free(zbuf); if (!info) { fprintf(stderr, "Could not parse Info.plist!\n"); zip_unchange_all(zf); zip_close(zf); goto leave_cleanup; } char *bundleexecutable = NULL; plist_t bname = plist_dict_get_item(info, "CFBundleExecutable"); if (bname) { plist_get_string_val(bname, &bundleexecutable); } bname = plist_dict_get_item(info, "CFBundleIdentifier"); if (bname) { plist_get_string_val(bname, &bundleidentifier); } plist_free(info); info = NULL; if (!bundleexecutable) { fprintf(stderr, "Could not determine value for CFBundleExecutable!\n"); zip_unchange_all(zf); zip_close(zf); goto leave_cleanup; } char *sinfname = NULL; if (asprintf(&sinfname, "Payload/%s.app/SC_Info/%s.sinf", bundleexecutable, bundleexecutable) < 0) { fprintf(stderr, "Out of memory!?\n"); goto leave_cleanup; } free(bundleexecutable); /* extract .sinf from package */ zbuf = NULL; len = 0; if (zip_get_contents(zf, sinfname, 0, &zbuf, &len) == 0) { sinf = plist_new_data(zbuf, len); } else { fprintf(stderr, "WARNING: could not locate %s in archive!\n", sinfname); } free(sinfname); if (zbuf) { free(zbuf); } /* copy archive to device */ pkgname = NULL; if (asprintf(&pkgname, "%s/%s", PKG_PATH, bundleidentifier) < 0) { fprintf(stderr, "Out of memory!?\n"); goto leave_cleanup; } printf("Copying '%s' to device... ", appid); if (afc_upload_file(afc, appid, pkgname) < 0) { free(pkgname); goto leave_cleanup; } printf("DONE.\n"); if (bundleidentifier) { instproxy_client_options_add(client_opts, "CFBundleIdentifier", bundleidentifier, NULL); } if (sinf) { instproxy_client_options_add(client_opts, "ApplicationSINF", sinf, NULL); } if (meta) { instproxy_client_options_add(client_opts, "iTunesMetadata", meta, NULL); } } if (zf) { zip_unchange_all(zf); zip_close(zf); } /* perform installation or upgrade */ if (cmd == CMD_INSTALL) { printf("Installing '%s'\n", bundleidentifier); #ifdef HAVE_LIBIMOBILEDEVICE_1_1 instproxy_install(ipc, pkgname, client_opts, status_cb, NULL); #else instproxy_install(ipc, pkgname, client_opts, status_cb); #endif } else { printf("Upgrading '%s'\n", bundleidentifier); #ifdef HAVE_LIBIMOBILEDEVICE_1_1 instproxy_upgrade(ipc, pkgname, client_opts, status_cb, NULL); #else instproxy_upgrade(ipc, pkgname, client_opts, status_cb); #endif } instproxy_client_options_free(client_opts); free(pkgname); wait_for_op_complete = 1; notification_expected = 1; } else if (cmd == CMD_UNINSTALL) { printf("Uninstalling '%s'\n", appid); #ifdef HAVE_LIBIMOBILEDEVICE_1_1 instproxy_uninstall(ipc, appid, NULL, status_cb, NULL); #else instproxy_uninstall(ipc, appid, NULL, status_cb); #endif wait_for_op_complete = 1; notification_expected = 0; } else if (cmd == CMD_LIST_ARCHIVES) { int xml_mode = 0; plist_t dict = NULL; plist_t lres = NULL; /* look for options */ if (options) { char *opts = strdup(options); char *elem = strtok(opts, ","); while (elem) { if (!strcmp(elem, "xml")) { xml_mode = 1; } elem = strtok(NULL, ","); } } err = instproxy_lookup_archives(ipc, NULL, &dict); if (err != INSTPROXY_E_SUCCESS) { fprintf(stderr, "ERROR: lookup_archives returned %d\n", err); goto leave_cleanup; } if (!dict) { fprintf(stderr, "ERROR: lookup_archives did not return a plist!?\n"); goto leave_cleanup; } lres = plist_dict_get_item(dict, "LookupResult"); if (!lres || (plist_get_node_type(lres) != PLIST_DICT)) { plist_free(dict); fprintf(stderr, "ERROR: Could not get dict 'LookupResult'\n"); goto leave_cleanup; } if (xml_mode) { char *xml = NULL; uint32_t len = 0; plist_to_xml(lres, &xml, &len); if (xml) { puts(xml); free(xml); } plist_free(dict); goto leave_cleanup; } plist_dict_iter iter = NULL; plist_t node = NULL; char *key = NULL; printf("Total: %d archived apps\n", plist_dict_get_size(lres)); plist_dict_new_iter(lres, &iter); if (!iter) { plist_free(dict); fprintf(stderr, "ERROR: Could not create plist_dict_iter!\n"); goto leave_cleanup; } do { key = NULL; node = NULL; plist_dict_next_item(lres, iter, &key, &node); if (key && (plist_get_node_type(node) == PLIST_DICT)) { char *s_dispName = NULL; char *s_version = NULL; plist_t dispName = plist_dict_get_item(node, "CFBundleDisplayName"); plist_t version = plist_dict_get_item(node, "CFBundleVersion"); if (dispName) { plist_get_string_val(dispName, &s_dispName); } if (version) { plist_get_string_val(version, &s_version); } if (!s_dispName) { s_dispName = strdup(key); } if (s_version) { printf("%s - %s %s\n", key, s_dispName, s_version); free(s_version); } else { printf("%s - %s\n", key, s_dispName); } free(s_dispName); free(key); } } while (node); plist_free(dict); } else if (cmd == CMD_ARCHIVE) { char *copy_path = NULL; int remove_after_copy = 0; int skip_uninstall = 1; int app_only = 0; int docs_only = 0; plist_t client_opts = NULL; /* look for options */ if (options) { char *opts = strdup(options); char *elem = strtok(opts, ","); while (elem) { if (!strcmp(elem, "uninstall")) { skip_uninstall = 0; } else if (!strcmp(elem, "app_only")) { app_only = 1; docs_only = 0; } else if (!strcmp(elem, "docs_only")) { docs_only = 1; app_only = 0; } else if ((strlen(elem) > 5) && !strncmp(elem, "copy=", 5)) { copy_path = strdup(elem+5); } else if (!strcmp(elem, "remove")) { remove_after_copy = 1; } elem = strtok(NULL, ","); } } if (skip_uninstall || app_only || docs_only) { client_opts = instproxy_client_options_new(); if (skip_uninstall) { instproxy_client_options_add(client_opts, "SkipUninstall", 1, NULL); } if (app_only) { instproxy_client_options_add(client_opts, "ArchiveType", "ApplicationOnly", NULL); } else if (docs_only) { instproxy_client_options_add(client_opts, "ArchiveType", "DocumentsOnly", NULL); } } if (copy_path) { struct stat fst; if (stat(copy_path, &fst) != 0) { fprintf(stderr, "ERROR: stat: %s: %s\n", copy_path, strerror(errno)); free(copy_path); goto leave_cleanup; } if (!S_ISDIR(fst.st_mode)) { fprintf(stderr, "ERROR: '%s' is not a directory as expected.\n", copy_path); free(copy_path); goto leave_cleanup; } #ifdef HAVE_LIBIMOBILEDEVICE_1_1_5 if (service) { lockdownd_service_descriptor_free(service); } service = NULL; #else service = 0; #endif if ((lockdownd_start_service(client, "com.apple.afc", &service) != LOCKDOWN_E_SUCCESS) || !service) { fprintf(stderr, "Could not start com.apple.afc!\n"); free(copy_path); goto leave_cleanup; } lockdownd_client_free(client); client = NULL; if (afc_client_new(phone, service, &afc) != INSTPROXY_E_SUCCESS) { fprintf(stderr, "Could not connect to AFC!\n"); goto leave_cleanup; } } #ifdef HAVE_LIBIMOBILEDEVICE_1_1 instproxy_archive(ipc, appid, client_opts, status_cb, NULL); #else instproxy_archive(ipc, appid, client_opts, status_cb); #endif instproxy_client_options_free(client_opts); wait_for_op_complete = 1; if (skip_uninstall) { notification_expected = 0; } else { notification_expected = 1; } idevice_wait_for_operation_to_complete(); if (copy_path) { if (err_occured) { afc_client_free(afc); afc = NULL; goto leave_cleanup; } FILE *f = NULL; uint64_t af = 0; /* local filename */ char *localfile = NULL; if (asprintf(&localfile, "%s/%s.ipa", copy_path, appid) < 0) { fprintf(stderr, "Out of memory!?\n"); goto leave_cleanup; } free(copy_path); f = fopen(localfile, "wb"); if (!f) { fprintf(stderr, "ERROR: fopen: %s: %s\n", localfile, strerror(errno)); free(localfile); goto leave_cleanup; } /* remote filename */ char *remotefile = NULL; if (asprintf(&remotefile, "%s/%s.zip", APPARCH_PATH, appid) < 0) { fprintf(stderr, "Out of memory!?\n"); goto leave_cleanup; } uint32_t fsize = 0; char **fileinfo = NULL; if ((afc_get_file_info(afc, remotefile, &fileinfo) != AFC_E_SUCCESS) || !fileinfo) { fprintf(stderr, "ERROR getting AFC file info for '%s' on device!\n", remotefile); fclose(f); free(remotefile); free(localfile); goto leave_cleanup; } int i; for (i = 0; fileinfo[i]; i+=2) { if (!strcmp(fileinfo[i], "st_size")) { fsize = atoi(fileinfo[i+1]); break; } } i = 0; while (fileinfo[i]) { free(fileinfo[i]); i++; } free(fileinfo); if (fsize == 0) { fprintf(stderr, "Hm... remote file length could not be determined. Cannot copy.\n"); fclose(f); free(remotefile); free(localfile); goto leave_cleanup; } if ((afc_file_open(afc, remotefile, AFC_FOPEN_RDONLY, &af) != AFC_E_SUCCESS) || !af) { fclose(f); fprintf(stderr, "ERROR: could not open '%s' on device for reading!\n", remotefile); free(remotefile); free(localfile); goto leave_cleanup; } /* copy file over */ printf("Copying '%s' --> '%s'... ", remotefile, localfile); free(remotefile); free(localfile); uint32_t amount = 0; uint32_t total = 0; char buf[8192]; do { if (afc_file_read(afc, af, buf, sizeof(buf), &amount) != AFC_E_SUCCESS) { fprintf(stderr, "AFC Read error!\n"); break; } if (amount > 0) { size_t written = fwrite(buf, 1, amount, f); if (written != amount) { fprintf(stderr, "Error when writing %d bytes to local file!\n", amount); break; } total += written; } } while (amount > 0); afc_file_close(afc, af); fclose(f); printf("DONE.\n"); if (total != fsize) { fprintf(stderr, "WARNING: remote and local file sizes don't match (%d != %d)\n", fsize, total); if (remove_after_copy) { fprintf(stderr, "NOTE: archive file will NOT be removed from device\n"); remove_after_copy = 0; } } if (remove_after_copy) { /* remove archive if requested */ printf("Removing '%s'\n", appid); cmd = CMD_REMOVE_ARCHIVE; free(options); options = NULL; if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(phone, &client, "ideviceinstaller")) { fprintf(stderr, "Could not connect to lockdownd. Exiting.\n"); goto leave_cleanup; } goto run_again; } } goto leave_cleanup; } else if (cmd == CMD_RESTORE) { #ifdef HAVE_LIBIMOBILEDEVICE_1_1 instproxy_restore(ipc, appid, NULL, status_cb, NULL); #else instproxy_restore(ipc, appid, NULL, status_cb); #endif wait_for_op_complete = 1; notification_expected = 1; } else if (cmd == CMD_REMOVE_ARCHIVE) { #ifdef HAVE_LIBIMOBILEDEVICE_1_1 instproxy_remove_archive(ipc, appid, NULL, status_cb, NULL); #else instproxy_remove_archive(ipc, appid, NULL, status_cb); #endif wait_for_op_complete = 1; } else { printf ("ERROR: no operation selected?! This should not be reached!\n"); res = -2; goto leave_cleanup; } if (client) { /* not needed anymore */ lockdownd_client_free(client); client = NULL; } idevice_wait_for_operation_to_complete(); leave_cleanup: if (bundleidentifier) { free(bundleidentifier); } if (np) { np_client_free(np); } if (ipc) { instproxy_client_free(ipc); } if (afc) { afc_client_free(afc); } if (client) { lockdownd_client_free(client); } idevice_free(phone); if (udid) { free(udid); } if (appid) { free(appid); } if (options) { free(options); } return res; }