diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/Makefile.am | 16 | ||||
| -rw-r--r-- | tools/afcclient.c | 206 | ||||
| -rw-r--r-- | tools/idevicebackup.c | 148 | ||||
| -rw-r--r-- | tools/idevicebackup2.c | 94 | ||||
| -rw-r--r-- | tools/idevicebtlogger.c | 4 | ||||
| -rw-r--r-- | tools/idevicecrashreport.c | 144 | ||||
| -rw-r--r-- | tools/idevicedate.c | 6 | ||||
| -rw-r--r-- | tools/idevicedebug.c | 4 | ||||
| -rw-r--r-- | tools/idevicedebugserverproxy.c | 4 | ||||
| -rw-r--r-- | tools/idevicedevmodectl.c | 6 | ||||
| -rw-r--r-- | tools/idevicediagnostics.c | 4 | ||||
| -rw-r--r-- | tools/ideviceenterrecovery.c | 4 | ||||
| -rw-r--r-- | tools/ideviceimagemounter.c | 434 | ||||
| -rw-r--r-- | tools/ideviceinfo.c | 4 | ||||
| -rw-r--r-- | tools/idevicename.c | 4 | ||||
| -rw-r--r-- | tools/idevicenotificationproxy.c | 26 | ||||
| -rw-r--r-- | tools/idevicepair.c | 6 | ||||
| -rw-r--r-- | tools/ideviceprovision.c | 33 | ||||
| -rw-r--r-- | tools/idevicescreenshot.c | 4 | ||||
| -rw-r--r-- | tools/idevicesetlocation.c | 30 | ||||
| -rw-r--r-- | tools/idevicesyslog.c | 688 |
21 files changed, 1302 insertions, 567 deletions
diff --git a/tools/Makefile.am b/tools/Makefile.am index 4cac1fc..24cfc66 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -35,7 +35,7 @@ bin_PROGRAMS = \ afcclient idevicebtlogger_SOURCES = idevicebtlogger.c -iidevicebtlogger_CFLAGS = $(AM_CFLAGS) +idevicebtlogger_CFLAGS = $(AM_CFLAGS) idevicebtlogger_LDFLAGS = $(top_builddir)/common/libinternalcommon.la $(AM_LDFLAGS) idevicebtlogger_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la @@ -51,8 +51,8 @@ idevicename_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la idevicepair_SOURCES = idevicepair.c idevicepair_CFLAGS = $(AM_CFLAGS) -idevicepair_LDFLAGS = $(AM_LDFLAGS) $(libusbmuxd_LIBS) $(ssl_lib_LIBS) -idevicepair_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la $(top_builddir)/common/libinternalcommon.la $(limd_glue_LIBS) +idevicepair_LDFLAGS = $(AM_LDFLAGS) $(libusbmuxd_LIBS) +idevicepair_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la $(top_builddir)/common/libinternalcommon.la $(limd_glue_LIBS) $(ssl_lib_LIBS) idevicesyslog_SOURCES = idevicesyslog.c idevicesyslog_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS) @@ -66,7 +66,7 @@ idevice_id_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la idevicebackup_SOURCES = idevicebackup.c idevicebackup_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS) -idevicebackup_LDFLAGS = $(AM_LDFLAGS) $(ssl_lib_LIBS) $(limd_glue_LIBS) +idevicebackup_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS) idevicebackup_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la idevicebackup2_SOURCES = idevicebackup2.c @@ -75,8 +75,8 @@ idevicebackup2_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS) idevicebackup2_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la ideviceimagemounter_SOURCES = ideviceimagemounter.c -ideviceimagemounter_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS) -ideviceimagemounter_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS) +ideviceimagemounter_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS) $(libtatsu_CFLAGS) +ideviceimagemounter_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS) $(libtatsu_LIBS) ideviceimagemounter_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la idevicescreenshot_SOURCES = idevicescreenshot.c @@ -135,8 +135,8 @@ idevicesetlocation_LDFLAGS = $(AM_LDFLAGS) idevicesetlocation_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la afcclient_SOURCES = afcclient.c -afcclient_CFLAGS = $(AM_CFLAGS) -afcclient_LDFLAGS = $(AM_LDFLAGS) +afcclient_CFLAGS = $(AM_CFLAGS) $(limd_glue_CFLAGS) +afcclient_LDFLAGS = $(AM_LDFLAGS) $(limd_glue_LIBS) if HAVE_READLINE afcclient_CFLAGS += $(readline_CFLAGS) afcclient_LDFLAGS += $(readline_LIBS) diff --git a/tools/afcclient.c b/tools/afcclient.c index 71a1c32..a958c23 100644 --- a/tools/afcclient.c +++ b/tools/afcclient.c @@ -37,8 +37,10 @@ #include <ctype.h> #include <unistd.h> #include <dirent.h> +#include <time.h> +#include <sys/stat.h> -#ifdef WIN32 +#ifdef _WIN32 #include <windows.h> #include <sys/time.h> #include <conio.h> @@ -94,7 +96,7 @@ static size_t curdir_len = 0; static int file_exists(const char* path) { struct stat tst; -#ifdef WIN32 +#ifdef _WIN32 return (stat(path, &tst) == 0); #else return (lstat(path, &tst) == 0); @@ -104,7 +106,7 @@ static int file_exists(const char* path) static int is_directory(const char* path) { struct stat tst; -#ifdef WIN32 +#ifdef _WIN32 return (stat(path, &tst) == 0) && S_ISDIR(tst.st_mode); #else return (lstat(path, &tst) == 0) && S_ISDIR(tst.st_mode); @@ -137,7 +139,7 @@ static void print_usage(int argc, char **argv, int is_error) } #ifndef HAVE_READLINE -#ifdef WIN32 +#ifdef _WIN32 #define BS_CC '\b' #else #define BS_CC 0x7f @@ -174,7 +176,7 @@ int stop_requested = 0; static void handle_signal(int sig) { stop_requested++; -#ifdef WIN32 +#ifdef _WIN32 GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); #else kill(getpid(), SIGINT); @@ -363,62 +365,55 @@ static char* get_realpath(const char* path) static void handle_devinfo(afc_client_t afc, int argc, char** argv) { - char **info = NULL; - afc_error_t err = afc_get_device_info(afc, &info); + plist_t info = NULL; + afc_error_t err = afc_get_device_info_plist(afc, &info); if (err == AFC_E_SUCCESS && info) { - int i; - for (i = 0; info[i]; i += 2) { - printf("%s: %s\n", info[i], info[i+1]); + if (argc > 0 && !strcmp(argv[0], "--plain")) { + plist_write_to_stream(info, stdout, PLIST_FORMAT_LIMD, PLIST_OPT_NONE); + } else { + plist_write_to_stream(info, stdout, PLIST_FORMAT_JSON, PLIST_OPT_NONE); } } else { printf("Error: Failed to get device info: %s (%d)\n", afc_strerror(err), err); } - afc_dictionary_free(info); + plist_free(info); } static int get_file_info_stat(afc_client_t afc, const char* path, struct afc_file_stat *stbuf) { - char **info = NULL; - afc_error_t ret = afc_get_file_info(afc, path, &info); + plist_t info = NULL; + afc_error_t ret = afc_get_file_info_plist(afc, path, &info); memset(stbuf, 0, sizeof(struct afc_file_stat)); if (ret != AFC_E_SUCCESS) { return -1; } else if (!info) { return -1; - } else { - // get file attributes from info list - int i; - for (i = 0; info[i]; i += 2) { - if (!strcmp(info[i], "st_size")) { - stbuf->st_size = atoll(info[i+1]); - } else if (!strcmp(info[i], "st_blocks")) { - stbuf->st_blocks = atoi(info[i+1]); - } else if (!strcmp(info[i], "st_ifmt")) { - if (!strcmp(info[i+1], "S_IFREG")) { - stbuf->st_mode = S_IFREG; - } else if (!strcmp(info[i+1], "S_IFDIR")) { - stbuf->st_mode = S_IFDIR; - } else if (!strcmp(info[i+1], "S_IFLNK")) { - stbuf->st_mode = S_IFLNK; - } else if (!strcmp(info[i+1], "S_IFBLK")) { - stbuf->st_mode = S_IFBLK; - } else if (!strcmp(info[i+1], "S_IFCHR")) { - stbuf->st_mode = S_IFCHR; - } else if (!strcmp(info[i+1], "S_IFIFO")) { - stbuf->st_mode = S_IFIFO; - } else if (!strcmp(info[i+1], "S_IFSOCK")) { - stbuf->st_mode = S_IFSOCK; - } - } else if (!strcmp(info[i], "st_nlink")) { - stbuf->st_nlink = atoi(info[i+1]); - } else if (!strcmp(info[i], "st_mtime")) { - stbuf->st_mtime = (time_t)(atoll(info[i+1]) / 1000000000); - } else if (!strcmp(info[i], "st_birthtime")) { /* available on iOS 7+ */ - stbuf->st_birthtime = (time_t)(atoll(info[i+1]) / 1000000000); - } - } - afc_dictionary_free(info); } + stbuf->st_size = plist_dict_get_uint(info, "st_size"); + stbuf->st_blocks = plist_dict_get_uint(info, "st_blocks"); + const char* s_ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL); + if (s_ifmt) { + if (!strcmp(s_ifmt, "S_IFREG")) { + stbuf->st_mode = S_IFREG; + } else if (!strcmp(s_ifmt, "S_IFDIR")) { + stbuf->st_mode = S_IFDIR; + } else if (!strcmp(s_ifmt, "S_IFLNK")) { + stbuf->st_mode = S_IFLNK; + } else if (!strcmp(s_ifmt, "S_IFBLK")) { + stbuf->st_mode = S_IFBLK; + } else if (!strcmp(s_ifmt, "S_IFCHR")) { + stbuf->st_mode = S_IFCHR; + } else if (!strcmp(s_ifmt, "S_IFIFO")) { + stbuf->st_mode = S_IFIFO; + } else if (!strcmp(s_ifmt, "S_IFSOCK")) { + stbuf->st_mode = S_IFSOCK; + } + } + stbuf->st_nlink = plist_dict_get_uint(info, "st_nlink"); + stbuf->st_mtime = (time_t)(plist_dict_get_uint(info, "st_mtime") / 1000000000); + /* available on iOS 7+ */ + stbuf->st_birthtime = (time_t)(plist_dict_get_uint(info, "st_birthtime") / 1000000000); + plist_free(info); return 0; } @@ -429,22 +424,23 @@ static void handle_file_info(afc_client_t afc, int argc, char** argv) return; } - char **info = NULL; + plist_t info = NULL; char* abspath = get_absolute_path(argv[0]); if (!abspath) { printf("Error: Invalid argument\n"); return; } - afc_error_t err = afc_get_file_info(afc, abspath, &info); + afc_error_t err = afc_get_file_info_plist(afc, abspath, &info); if (err == AFC_E_SUCCESS && info) { - int i; - for (i = 0; info[i]; i += 2) { - printf("%s: %s\n", info[i], info[i+1]); + if (argc > 1 && !strcmp(argv[1], "--plain")) { + plist_write_to_stream(info, stdout, PLIST_FORMAT_LIMD, PLIST_OPT_NONE); + } else { + plist_write_to_stream(info, stdout, PLIST_FORMAT_JSON, PLIST_OPT_NONE); } } else { printf("Error: Failed to get file info for %s: %s (%d)\n", argv[0], afc_strerror(err), err); } - afc_dictionary_free(info); + plist_free(info); free(abspath); } @@ -482,7 +478,7 @@ static void print_file_info(afc_client_t afc, const char* path, int list_verbose printf(" "); printf("%10lld", (long long)st.st_size); printf(" "); -#ifdef WIN32 +#ifdef _WIN32 strftime(timebuf, 64, "%d %b %Y %H:%M:%S", localtime(&t)); #else strftime(timebuf, 64, "%d %h %Y %H:%M:%S", localtime(&t)); @@ -773,7 +769,7 @@ static uint8_t get_single_file(afc_client_t afc, const char *srcpath, const char static int __mkdir(const char* path) { -#ifdef WIN32 +#ifdef _WIN32 return mkdir(path); #else return mkdir(path, 0755); @@ -782,28 +778,19 @@ static int __mkdir(const char* path) static uint8_t get_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint8_t force_overwrite, uint8_t recursive_get) { - char **info = NULL; + plist_t info = NULL; uint64_t file_size = 0; - afc_error_t err = afc_get_file_info(afc, srcpath, &info); + afc_error_t err = afc_get_file_info_plist(afc, srcpath, &info); if (err == AFC_E_OBJECT_NOT_FOUND) { printf("Error: Failed to read from file '%s': %s (%d)\n", srcpath, afc_strerror(err), err); return 0; } uint8_t is_dir = 0; if (info) { - char **p = info; - while (p && *p) { - if (!strcmp(*p, "st_size")) { - p++; - file_size = (uint64_t) strtoull(*p, NULL, 10); - } - if (!strcmp(*p, "st_ifmt")) { - p++; - is_dir = !strcmp(*p, "S_IFDIR"); - } - p++; - } - afc_dictionary_free(info); + file_size = plist_dict_get_uint(info, "st_size"); + const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL); + is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR")); + plist_free(info); } uint8_t succeed = 1; if (is_dir) { @@ -836,7 +823,7 @@ static uint8_t get_file(afc_client_t afc, const char *srcpath, const char *dstpa p++; continue; } - size_t len = srcpath_is_root ? strlen(*p) + 1 : srcpath_len + 1 + strlen(*p) + 1; + size_t len = srcpath_is_root ? (strlen(*p) + 2) : (srcpath_len + 1 + strlen(*p) + 1); char *testpath = (char *) malloc(len); if (srcpath_is_root) { snprintf(testpath, len, "/%s", *p); @@ -844,7 +831,7 @@ static uint8_t get_file(afc_client_t afc, const char *srcpath, const char *dstpa snprintf(testpath, len, "%s/%s", srcpath, *p); } uint8_t dst_is_root = strcmp(srcpath, "/") == 0; - size_t dst_len = dst_is_root ? strlen(*p) + 1 : strlen(dstpath) + 1 + strlen(*p) + 1; + size_t dst_len = dst_is_root ? (strlen(*p) + 2) : (strlen(dstpath) + 1 + strlen(*p) + 1); char *newdst = (char *) malloc(dst_len); if (dst_is_root) { snprintf(newdst, dst_len, "/%s", *p); @@ -913,13 +900,16 @@ static void handle_get(afc_client_t afc, int argc, char **argv) dstpath[dst_len - 1] = '\0'; } free(tmp); + } else { + printf("Error: Invalid number of arguments\n"); + return; } // target is a directory, put file under this target if (is_directory(dstpath)) { - const char *basen = path_get_basename(argv[0]); + const char *basen = path_get_basename(srcpath); uint8_t dst_is_root = strcmp(dstpath, "/") == 0; - size_t len = dst_is_root ? (strlen(basen) + 1) : (strlen(dstpath) + 1 + strlen(basen) + 1); + size_t len = dst_is_root ? (strlen(basen) + 2) : (strlen(dstpath) + 1 + strlen(basen) + 1); char *newdst = (char *) malloc(len); if (dst_is_root) { snprintf(newdst, len, "/%s", basen); @@ -940,11 +930,11 @@ static void handle_get(afc_client_t afc, int argc, char **argv) static uint8_t put_single_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint8_t force_overwrite) { - char **info = NULL; - afc_error_t ret = afc_get_file_info(afc, dstpath, &info); + plist_t info = NULL; + afc_error_t ret = afc_get_file_info_plist(afc, dstpath, &info); // file exists, only overwrite with '-f' option was set if (ret == AFC_E_SUCCESS && info) { - afc_dictionary_free(info); + plist_free(info); if (!force_overwrite) { printf("Error: Failed to write into existing file without '-f' option: %s\n", dstpath); return 0; @@ -1025,10 +1015,11 @@ static uint8_t put_file(afc_client_t afc, const char *srcpath, const char *dstpa printf("Error: Failed to put directory without '-r' option: %s\n", srcpath); return 0; } - char **info = NULL; - afc_error_t err = afc_get_file_info(afc, dstpath, &info); + plist_t info = NULL; + afc_error_t err = afc_get_file_info_plist(afc, dstpath, &info); //create if target directory does not exist - afc_dictionary_free(info); + plist_free(info); + info = NULL; if (err == AFC_E_OBJECT_NOT_FOUND) { err = afc_make_directory(afc, dstpath); if (err != AFC_E_SUCCESS) { @@ -1039,19 +1030,12 @@ static uint8_t put_file(afc_client_t afc, const char *srcpath, const char *dstpa printf("Error: Failed to put existing directory without '-f' option: %s\n", dstpath); return 0; } - afc_get_file_info(afc, dstpath, &info); + afc_get_file_info_plist(afc, dstpath, &info); uint8_t is_dir = 0; if (info) { - char **p = info; - while (p && *p) { - if (!strcmp(*p, "st_ifmt")) { - p++; - is_dir = !strcmp(*p, "S_IFDIR"); - break; - } - p++; - } - afc_dictionary_free(info); + const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL); + is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR")); + plist_free(info); } if (!is_dir) { printf("Error: Failed to create or access directory: '%s'\n", dstpath); @@ -1069,7 +1053,7 @@ static uint8_t put_file(afc_client_t afc, const char *srcpath, const char *dstpa char *fpath = string_build_path(srcpath, ep->d_name, NULL); if (fpath) { uint8_t dst_is_root = strcmp(dstpath, "/") == 0; - size_t len = dst_is_root ? strlen(ep->d_name) + 1 : strlen(dstpath) + 1 + strlen(ep->d_name) + 1; + size_t len = dst_is_root ? (strlen(ep->d_name) + 2) : (strlen(dstpath) + 1 + strlen(ep->d_name) + 1); char *newdst = (char *) malloc(len); if (dst_is_root) { snprintf(newdst, len, "/%s", ep->d_name); @@ -1143,8 +1127,8 @@ static void handle_put(afc_client_t afc, int argc, char **argv) printf("Error: Invalid number of arguments\n"); return; } - char **info = NULL; - afc_error_t err = afc_get_file_info(afc, dstpath, &info); + plist_t info = NULL; + afc_error_t err = afc_get_file_info_plist(afc, dstpath, &info); // target does not exist, put directly if (err == AFC_E_OBJECT_NOT_FOUND) { put_file(afc, srcpath, dstpath, force_overwrite, recursive_put); @@ -1153,22 +1137,15 @@ static void handle_put(afc_client_t afc, int argc, char **argv) } else { uint8_t is_dir = 0; if (info) { - char **p = info; - while (p && *p) { - if (!strcmp(*p, "st_ifmt")) { - p++; - is_dir = !strcmp(*p, "S_IFDIR"); - break; - } - p++; - } - afc_dictionary_free(info); + const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL); + is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR")); + plist_free(info); } // target is a directory, try to put under this directory if (is_dir) { const char *basen = path_get_basename(srcpath); uint8_t dst_is_root = strcmp(dstpath, "/") == 0; - size_t len = dst_is_root ? strlen(basen) + 1 : strlen(dstpath) + 1 + strlen(basen) + 1; + size_t len = dst_is_root ? (strlen(basen) + 2) : (strlen(dstpath) + 1 + strlen(basen) + 1); char *newdst = (char *) malloc(len); if (dst_is_root) { snprintf(newdst, len, "/%s", basen); @@ -1223,19 +1200,12 @@ static void handle_cd(afc_client_t afc, int argc, char** argv) char* path = get_realpath(argv[0]); int is_dir = 0; - char **info = NULL; - afc_error_t err = afc_get_file_info(afc, path, &info); + plist_t info = NULL; + afc_error_t err = afc_get_file_info_plist(afc, path, &info); if (err == AFC_E_SUCCESS && info) { - int i; - for (i = 0; info[i]; i += 2) { - if (!strcmp(info[i], "st_ifmt")) { - if (!strcmp(info[i+1], "S_IFDIR")) { - is_dir = 1; - } - break; - } - } - afc_dictionary_free(info); + const char* ifmt = plist_get_string_ptr(plist_dict_get_item(info, "st_ifmt"), NULL); + is_dir = (ifmt && !strcmp(ifmt, "S_IFDIR")); + plist_free(info); } else { printf("Error: Failed to get file info for %s: %s (%d)\n", path, afc_strerror(err), err); free(path); @@ -1479,7 +1449,7 @@ int main(int argc, char** argv) }; signal(SIGTERM, handle_signal); -#ifndef WIN32 +#ifndef _WIN32 signal(SIGQUIT, handle_signal); signal(SIGPIPE, SIG_IGN); #endif @@ -1557,7 +1527,7 @@ int main(int argc, char** argv) idevice_events_subscribe(&context, device_event_cb, NULL); while (!connected && !stop_requested) { -#ifdef WIN32 +#ifdef _WIN32 Sleep(100); #else usleep(100000); diff --git a/tools/idevicebackup.c b/tools/idevicebackup.c index 5694c12..363abad 100644 --- a/tools/idevicebackup.c +++ b/tools/idevicebackup.c @@ -32,33 +32,17 @@ #include <stdlib.h> #include <signal.h> #include <getopt.h> -#if defined(HAVE_OPENSSL) -#include <openssl/sha.h> -#if OPENSSL_VERSION_NUMBER >= 0x30000000L -#include <openssl/evp.h> -#endif -#elif defined(HAVE_GNUTLS) -#include <gcrypt.h> -#elif defined(HAVE_MBEDTLS) -#include <mbedtls/sha1.h> -#if MBEDTLS_VERSION_NUMBER < 0x03000000 -#define mbedtls_sha1 mbedtls_sha1_ret -#define mbedtls_sha1_starts mbedtls_sha1_starts_ret -#define mbedtls_sha1_update mbedtls_sha1_update_ret -#define mbedtls_sha1_finish mbedtls_sha1_finish_ret -#endif -#else -#error No supported crypto library enabled -#endif #include <unistd.h> #include <ctype.h> #include <time.h> +#include <sys/stat.h> #include <libimobiledevice/libimobiledevice.h> #include <libimobiledevice/lockdown.h> #include <libimobiledevice/mobilebackup.h> #include <libimobiledevice/notification_proxy.h> #include <libimobiledevice/afc.h> +#include <libimobiledevice-glue/sha.h> #include <libimobiledevice-glue/utils.h> #include <plist/plist.h> @@ -68,7 +52,7 @@ #define LOCK_ATTEMPTS 50 #define LOCK_WAIT 200000 -#ifdef WIN32 +#ifdef _WIN32 #include <windows.h> #define sleep(x) Sleep(x*1000) #endif @@ -91,17 +75,6 @@ enum device_link_file_status_t { DEVICE_LINK_FILE_STATUS_LAST_HUNK }; -static void sha1_of_data(const char *input, uint32_t size, unsigned char *hash_out) -{ -#if defined(HAVE_OPENSSL) - SHA1((const unsigned char*)input, size, hash_out); -#elif defined(HAVE_GNUTLS) - gcry_md_hash_buffer(GCRY_MD_SHA1, hash_out, input, size); -#elif defined(HAVE_MBEDTLS) - mbedtls_sha1((unsigned char*)input, size, hash_out); -#endif -} - static int compare_hash(const unsigned char *hash1, const unsigned char *hash2, int hash_len) { int i; @@ -113,104 +86,49 @@ static int compare_hash(const unsigned char *hash1, const unsigned char *hash2, return 1; } -static void _sha1_update(void* context, const char* data, size_t len) -{ -#if defined(HAVE_OPENSSL) -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - EVP_DigestUpdate(context, data, len); -#else - SHA1_Update(context, data, len); -#endif -#elif defined(HAVE_GNUTLS) - gcry_md_write(context, data, len); -#elif defined(HAVE_MBEDTLS) - mbedtls_sha1_update(context, (const unsigned char*)data, len); -#endif -} - static void compute_datahash(const char *path, const char *destpath, uint8_t greylist, const char *domain, const char *appid, const char *version, unsigned char *hash_out) { -#if defined(HAVE_OPENSSL) -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - EVP_MD_CTX* sha1 = EVP_MD_CTX_new(); - EVP_DigestInit(sha1, EVP_sha1()); - void* psha1 = sha1; -#else - SHA_CTX sha1; - SHA1_Init(&sha1); - void* psha1 = &sha1; -#endif -#elif defined(HAVE_GNUTLS) - gcry_md_hd_t hd = NULL; - gcry_md_open(&hd, GCRY_MD_SHA1, 0); - if (!hd) { - printf("ERROR: Could not initialize libgcrypt/SHA1\n"); - return; - } - gcry_md_reset(hd); - void* psha1 = hd; -#elif defined(HAVE_MBEDTLS) - mbedtls_sha1_context sha1; - mbedtls_sha1_init(&sha1); - mbedtls_sha1_starts(&sha1); - void* psha1 = &sha1; -#endif + sha1_context sha1; + sha1_init(&sha1); FILE *f = fopen(path, "rb"); if (f) { unsigned char buf[16384]; size_t len; while ((len = fread(buf, 1, 16384, f)) > 0) { - _sha1_update(psha1, (const char*)buf, len); + sha1_update(&sha1, buf, len); } fclose(f); - _sha1_update(psha1, destpath, strlen(destpath)); - _sha1_update(psha1, ";", 1); + sha1_update(&sha1, destpath, strlen(destpath)); + sha1_update(&sha1, ";", 1); if (greylist == 1) { - _sha1_update(psha1, "true", 4); + sha1_update(&sha1, "true", 4); } else { - _sha1_update(psha1, "false", 5); + sha1_update(&sha1, "false", 5); } - _sha1_update(psha1, ";", 1); + sha1_update(&sha1, ";", 1); if (domain) { - _sha1_update(psha1, domain, strlen(domain)); + sha1_update(&sha1, domain, strlen(domain)); } else { - _sha1_update(psha1, "(null)", 6); + sha1_update(&sha1, "(null)", 6); } - _sha1_update(psha1, ";", 1); + sha1_update(&sha1, ";", 1); if (appid) { - _sha1_update(psha1, appid, strlen(appid)); + sha1_update(&sha1, appid, strlen(appid)); } else { - _sha1_update(psha1, "(null)", 6); + sha1_update(&sha1, "(null)", 6); } - _sha1_update(psha1, ";", 1); + sha1_update(&sha1, ";", 1); if (version) { - _sha1_update(psha1, version, strlen(version)); + sha1_update(&sha1, version, strlen(version)); } else { - _sha1_update(psha1, "(null)", 6); + sha1_update(&sha1, "(null)", 6); } -#if defined(HAVE_OPENSSL) -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - EVP_DigestFinal(sha1, hash_out, NULL); - EVP_MD_CTX_destroy(sha1); -#else - SHA1_Final(hash_out, &sha1); -#endif -#elif defined(HAVE_GNUTLS) - unsigned char *newhash = gcry_md_read(hd, GCRY_MD_SHA1); - memcpy(hash_out, newhash, 20); -#elif defined(HAVE_MBEDTLS) - mbedtls_sha1_finish(&sha1, hash_out); -#endif + sha1_final(&sha1, hash_out); } -#if defined(HAVE_GNUTLS) - gcry_md_close(hd); -#elif defined(HAVE_MBEDTLS) - mbedtls_sha1_free(&sha1); -#endif } static void print_hash(const unsigned char *hash, int len) @@ -258,7 +176,13 @@ static plist_t mobilebackup_factory_info_plist_new(const char* udid) if (value_node) plist_dict_set_item(ret, "IMEI", plist_copy(value_node)); - plist_dict_set_item(ret, "Last Backup Date", plist_new_date(time(NULL) - MAC_EPOCH, 0)); + plist_dict_set_item(ret, "Last Backup Date", +#ifdef HAVE_PLIST_UNIX_DATE + plist_new_unix_date(time(NULL)) +#else + plist_new_date(time(NULL) - MAC_EPOCH, 0) +#endif + ); value_node = plist_dict_get_item(root_node, "ProductType"); plist_dict_set_item(ret, "Product Type", plist_copy(value_node)); @@ -295,7 +219,11 @@ static void mobilebackup_info_update_last_backup_date(plist_t info_plist) return; node = plist_dict_get_item(info_plist, "Last Backup Date"); +#ifdef HAVE_PLIST_UNIX_DATE + plist_set_unix_date_val(node, time(NULL)); +#else plist_set_date_val(node, time(NULL) - MAC_EPOCH, 0); +#endif node = NULL; } @@ -547,7 +475,7 @@ static int mobilebackup_check_file_integrity(const char *backup_directory, const unsigned char fnhash[20]; char fnamehash[41]; char *p = fnamehash; - sha1_of_data(fnstr, strlen(fnstr), fnhash); + sha1((const unsigned char*)fnstr, strlen(fnstr), fnhash); free(fnstr); int i; for ( i = 0; i < 20; i++, p += 2 ) { @@ -725,7 +653,7 @@ int main(int argc, char *argv[]) /* we need to exit cleanly on running backups and restores or we cause havok */ signal(SIGINT, clean_exit); signal(SIGTERM, clean_exit); -#ifndef WIN32 +#ifndef _WIN32 signal(SIGQUIT, clean_exit); signal(SIGPIPE, SIG_IGN); #endif @@ -1285,14 +1213,14 @@ files_out: } printf("Verifying backup integrity, please wait.\n"); - char *bin = NULL; + unsigned char *bin = NULL; uint64_t binsize = 0; node = plist_dict_get_item(manifest_plist, "Data"); if (!node || (plist_get_node_type(node) != PLIST_DATA)) { printf("Could not read Data key from Manifest.plist!\n"); break; } - plist_get_data_val(node, &bin, &binsize); + plist_get_data_val(node, (char**)&bin, &binsize); plist_t backup_data = NULL; if (bin) { char *auth_ver = NULL; @@ -1309,7 +1237,7 @@ files_out: if (auth_sig && (auth_sig_len == 20)) { /* calculate the sha1, then compare */ unsigned char data_sha1[20]; - sha1_of_data(bin, binsize, data_sha1); + sha1(bin, binsize, data_sha1); if (compare_hash(auth_sig, data_sha1, 20)) { printf("AuthSignature is valid\n"); } else { @@ -1322,7 +1250,7 @@ files_out: } else if (auth_ver) { printf("Unknown AuthVersion '%s', cannot verify AuthSignature\n", auth_ver); } - plist_from_bin(bin, (uint32_t)binsize, &backup_data); + plist_from_bin((char*)bin, (uint32_t)binsize, &backup_data); free(bin); } if (!backup_data) { @@ -1435,7 +1363,7 @@ files_out: file_info_path = mobilebackup_build_path(backup_directory, hash, ".mddata"); /* determine file size */ -#ifdef WIN32 +#ifdef _WIN32 struct _stati64 fst; if (_stati64(file_info_path, &fst) != 0) #else diff --git a/tools/idevicebackup2.c b/tools/idevicebackup2.c index c73b269..12d6083 100644 --- a/tools/idevicebackup2.c +++ b/tools/idevicebackup2.c @@ -54,7 +54,7 @@ #define LOCK_ATTEMPTS 50 #define LOCK_WAIT 200000 -#ifdef WIN32 +#ifdef _WIN32 #include <windows.h> #include <conio.h> #define sleep(x) Sleep(x*1000) @@ -74,6 +74,7 @@ static int verbose = 1; static int quit_flag = 0; +static int passcode_requested = 0; #define PRINT_VERBOSE(min_level, ...) if (verbose >= min_level) { printf(__VA_ARGS__); }; @@ -115,6 +116,10 @@ static void notify_cb(const char *notification, void *userdata) quit_flag++; } else if (!strcmp(notification, NP_BACKUP_DOMAIN_CHANGED)) { backup_domain_changed = 1; + } else if (!strcmp(notification, "com.apple.LocalAuthentication.ui.presented")) { + passcode_requested = 1; + } else if (!strcmp(notification, "com.apple.LocalAuthentication.ui.dismissed")) { + passcode_requested = 0; } else { PRINT_VERBOSE(1, "Unhandled notification '%s' (TODO: implement)\n", notification); } @@ -126,21 +131,15 @@ static void mobilebackup_afc_get_file_contents(afc_client_t afc, const char *fil return; } - char **fileinfo = NULL; + plist_t fileinfo = NULL; uint32_t fsize = 0; - afc_get_file_info(afc, filename, &fileinfo); + afc_get_file_info_plist(afc, filename, &fileinfo); if (!fileinfo) { return; } - int i; - for (i = 0; fileinfo[i]; i+=2) { - if (!strcmp(fileinfo[i], "st_size")) { - fsize = atol(fileinfo[i+1]); - break; - } - } - afc_dictionary_free(fileinfo); + fsize = plist_dict_get_uint(fileinfo, "st_size"); + plist_free(fileinfo); if (fsize == 0) { return; @@ -173,7 +172,7 @@ static void mobilebackup_afc_get_file_contents(afc_client_t afc, const char *fil static int __mkdir(const char* path, int mode) { -#ifdef WIN32 +#ifdef _WIN32 return mkdir(path); #else return mkdir(path, mode); @@ -202,7 +201,7 @@ static int mkdir_with_parents(const char *dir, int mode) return res; } -#ifdef WIN32 +#ifdef _WIN32 static int win32err_to_errno(int err_value) { switch (err_value) { @@ -219,7 +218,7 @@ static int win32err_to_errno(int err_value) static int remove_file(const char* path) { int e = 0; -#ifdef WIN32 +#ifdef _WIN32 if (!DeleteFile(path)) { e = win32err_to_errno(GetLastError()); } @@ -234,7 +233,7 @@ static int remove_file(const char* path) static int remove_directory(const char* path) { int e = 0; -#ifdef WIN32 +#ifdef _WIN32 if (!RemoveDirectory(path)) { e = win32err_to_errno(GetLastError()); } @@ -455,7 +454,13 @@ static plist_t mobilebackup_factory_info_plist_new(const char* udid, idevice_t d /* Installed Applications */ plist_dict_set_item(ret, "Installed Applications", installed_apps); - plist_dict_set_item(ret, "Last Backup Date", plist_new_date(time(NULL) - MAC_EPOCH, 0)); + plist_dict_set_item(ret, "Last Backup Date", +#ifdef HAVE_PLIST_UNIX_DATE + plist_new_unix_date(time(NULL)) +#else + plist_new_date(time(NULL) - MAC_EPOCH, 0) +#endif + ); value_node = plist_dict_get_item(root_node, "MobileEquipmentIdentifier"); if (value_node) @@ -768,7 +773,7 @@ static int mb2_handle_send_file(mobilebackup2_client_t mobilebackup2, const char uint32_t bytes = 0; char *localfile = string_build_path(backup_dir, path, NULL); char buf[32768]; -#ifdef WIN32 +#ifdef _WIN32 struct _stati64 fst; #else struct stat fst; @@ -779,7 +784,7 @@ static int mb2_handle_send_file(mobilebackup2_client_t mobilebackup2, const char int errcode = -1; int result = -1; uint32_t length; -#ifdef WIN32 +#ifdef _WIN32 uint64_t total; uint64_t sent; #else @@ -810,7 +815,7 @@ static int mb2_handle_send_file(mobilebackup2_client_t mobilebackup2, const char goto leave_proto_err; } -#ifdef WIN32 +#ifdef _WIN32 if (_stati64(localfile, &fst) < 0) #else if (stat(localfile, &fst) < 0) @@ -1218,7 +1223,12 @@ static void mb2_handle_list_directory(mobilebackup2_client_t mobilebackup2, plis plist_dict_set_item(fdict, "DLFileType", plist_new_string(ftype)); plist_dict_set_item(fdict, "DLFileSize", plist_new_uint(st.st_size)); plist_dict_set_item(fdict, "DLFileModificationDate", - plist_new_date(st.st_mtime - MAC_EPOCH, 0)); +#ifdef HAVE_PLIST_UNIX_DATE + plist_new_unix_date(st.st_mtime) +#else + plist_new_date(st.st_mtime - MAC_EPOCH, 0) +#endif + ); plist_dict_set_item(dirlist, ep->d_name, fdict); free(fpath); @@ -1343,7 +1353,7 @@ static void mb2_copy_directory_by_path(const char *src, const char *dst) } } -#ifdef WIN32 +#ifdef _WIN32 #define BS_CC '\b' #define my_getch getch #else @@ -1463,8 +1473,6 @@ static void print_usage(int argc, char **argv, int is_error) ); } -#define DEVICE_VERSION(maj, min, patch) ((((maj) & 0xFF) << 16) | (((min) & 0xFF) << 8) | ((patch) & 0xFF)) - int main(int argc, char *argv[]) { idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; @@ -1530,7 +1538,7 @@ int main(int argc, char *argv[]) /* we need to exit cleanly on running backups and restores or we cause havok */ signal(SIGINT, clean_exit); signal(SIGTERM, clean_exit); -#ifndef WIN32 +#ifndef _WIN32 signal(SIGQUIT, clean_exit); signal(SIGPIPE, SIG_IGN); #endif @@ -1844,34 +1852,20 @@ int main(int argc, char *argv[]) } /* get ProductVersion */ - char *product_version = NULL; - int device_version = 0; - node_tmp = NULL; - lockdownd_get_value(lockdown, NULL, "ProductVersion", &node_tmp); - if (node_tmp) { - if (plist_get_node_type(node_tmp) == PLIST_STRING) { - plist_get_string_val(node_tmp, &product_version); - } - plist_free(node_tmp); - node_tmp = NULL; - } - if (product_version) { - int vers[3] = { 0, 0, 0 }; - if (sscanf(product_version, "%d.%d.%d", &vers[0], &vers[1], &vers[2]) >= 2) { - device_version = DEVICE_VERSION(vers[0], vers[1], vers[2]); - } - } + int device_version = idevice_get_device_version(device); /* start notification_proxy */ ldret = lockdownd_start_service(lockdown, NP_SERVICE_NAME, &service); if ((ldret == LOCKDOWN_E_SUCCESS) && service && service->port) { np_client_new(device, service, &np); np_set_notify_callback(np, notify_cb, NULL); - const char *noties[5] = { + const char *noties[7] = { NP_SYNC_CANCEL_REQUEST, NP_SYNC_SUSPEND_REQUEST, NP_SYNC_RESUME_REQUEST, NP_BACKUP_DOMAIN_CHANGED, + "com.apple.LocalAuthentication.ui.presented", + "com.apple.LocalAuthentication.ui.dismissed", NULL }; np_observe_notifications(np, noties); @@ -2058,6 +2052,16 @@ checkpoint: } else { PRINT_VERBOSE(1, "Incremental backup mode.\n"); } + if (device_version >= IDEVICE_DEVICE_VERSION(16,1,0)) { + /* let's wait 2 second to see if the device passcode is requested */ + int retries = 20; + while (retries-- > 0 && !passcode_requested) { + usleep(100000); + } + if (passcode_requested) { + printf("*** Waiting for passcode to be entered on the device ***\n"); + } + } } else { if (err == MOBILEBACKUP2_E_BAD_VERSION) { printf("ERROR: Could not start backup process: backup protocol version mismatch!\n"); @@ -2229,7 +2233,7 @@ checkpoint: if (newpw || backup_password) { mobilebackup2_send_message(mobilebackup2, "ChangePassword", opts); uint8_t passcode_hint = 0; - if (device_version >= DEVICE_VERSION(13,0,0)) { + if (device_version >= IDEVICE_DEVICE_VERSION(13,0,0)) { diagnostics_relay_client_t diag = NULL; if (diagnostics_relay_client_start_service(device, &diag, TOOL_NAME) == DIAGNOSTICS_RELAY_E_SUCCESS) { plist_t dict = NULL; @@ -2307,7 +2311,7 @@ checkpoint: /* device wants to know how much disk space is available on the computer */ uint64_t freespace = 0; int res = -1; -#ifdef WIN32 +#ifdef _WIN32 if (GetDiskFreeSpaceEx(backup_directory, (PULARGE_INTEGER)&freespace, NULL, NULL)) { res = 0; } @@ -2316,7 +2320,7 @@ checkpoint: memset(&fs, '\0', sizeof(fs)); res = statvfs(backup_directory, &fs); if (res == 0) { - freespace = (uint64_t)fs.f_bavail * (uint64_t)fs.f_bsize; + freespace = (uint64_t)fs.f_bavail * (uint64_t)fs.f_frsize; } #endif plist_t freespace_item = plist_new_uint(freespace); diff --git a/tools/idevicebtlogger.c b/tools/idevicebtlogger.c index 8de6b22..ca68b59 100644 --- a/tools/idevicebtlogger.c +++ b/tools/idevicebtlogger.c @@ -36,7 +36,7 @@ #include <assert.h> #include <fcntl.h> -#ifdef WIN32 +#ifdef _WIN32 #include <windows.h> #define sleep(x) Sleep(x*1000) #else @@ -334,7 +334,7 @@ int main(int argc, char *argv[]) signal(SIGINT, clean_exit); signal(SIGTERM, clean_exit); -#ifndef WIN32 +#ifndef _WIN32 signal(SIGQUIT, clean_exit); signal(SIGPIPE, SIG_IGN); #endif diff --git a/tools/idevicecrashreport.c b/tools/idevicecrashreport.c index 09bd537..b9869ae 100644 --- a/tools/idevicecrashreport.c +++ b/tools/idevicecrashreport.c @@ -31,7 +31,8 @@ #include <string.h> #include <unistd.h> #include <getopt.h> -#ifndef WIN32 +#include <sys/stat.h> +#ifndef _WIN32 #include <signal.h> #endif #include <libimobiledevice-glue/utils.h> @@ -42,7 +43,7 @@ #include <libimobiledevice/afc.h> #include <plist/plist.h> -#ifdef WIN32 +#ifdef _WIN32 #include <windows.h> #define S_IFLNK S_IFREG #define S_IFSOCK S_IFREG @@ -54,11 +55,12 @@ const char* target_directory = NULL; static int extract_raw_crash_reports = 0; static int keep_crash_reports = 0; +static int remove_all = 0; static int file_exists(const char* path) { struct stat tst; -#ifdef WIN32 +#ifdef _WIN32 return (stat(path, &tst) == 0); #else return (lstat(path, &tst) == 0); @@ -144,7 +146,7 @@ static int afc_client_copy_and_remove_crash_reports(afc_client_t afc, const char continue; } - char **fileinfo = NULL; + plist_t fileinfo = NULL; struct stat stbuf; memset(&stbuf, '\0', sizeof(struct stat)); @@ -152,7 +154,7 @@ static int afc_client_copy_and_remove_crash_reports(afc_client_t afc, const char strcpy(((char*)source_filename) + device_directory_length, list[k]); /* assemble absolute target filename */ -#ifdef WIN32 +#ifdef _WIN32 /* replace every ':' with '-' since ':' is an illegal character for file names in windows */ char* current_pos = strchr(list[k], ':'); while (current_pos) { @@ -171,88 +173,93 @@ static int afc_client_copy_and_remove_crash_reports(afc_client_t afc, const char } /* get file information */ - afc_get_file_info(afc, source_filename, &fileinfo); + afc_get_file_info_plist(afc, source_filename, &fileinfo); if (!fileinfo) { printf("Failed to read information for '%s'. Skipping...\n", source_filename); continue; } /* parse file information */ - int i; - for (i = 0; fileinfo[i]; i+=2) { - if (!strcmp(fileinfo[i], "st_size")) { - stbuf.st_size = atoll(fileinfo[i+1]); - } else if (!strcmp(fileinfo[i], "st_ifmt")) { - if (!strcmp(fileinfo[i+1], "S_IFREG")) { - stbuf.st_mode = S_IFREG; - } else if (!strcmp(fileinfo[i+1], "S_IFDIR")) { - stbuf.st_mode = S_IFDIR; - } else if (!strcmp(fileinfo[i+1], "S_IFLNK")) { - stbuf.st_mode = S_IFLNK; - } else if (!strcmp(fileinfo[i+1], "S_IFBLK")) { - stbuf.st_mode = S_IFBLK; - } else if (!strcmp(fileinfo[i+1], "S_IFCHR")) { - stbuf.st_mode = S_IFCHR; - } else if (!strcmp(fileinfo[i+1], "S_IFIFO")) { - stbuf.st_mode = S_IFIFO; - } else if (!strcmp(fileinfo[i+1], "S_IFSOCK")) { - stbuf.st_mode = S_IFSOCK; - } - } else if (!strcmp(fileinfo[i], "st_nlink")) { - stbuf.st_nlink = atoi(fileinfo[i+1]); - } else if (!strcmp(fileinfo[i], "st_mtime")) { - stbuf.st_mtime = (time_t)(atoll(fileinfo[i+1]) / 1000000000); - } else if (!strcmp(fileinfo[i], "LinkTarget")) { - /* report latest crash report filename */ - printf("Link: %s\n", (char*)target_filename + strlen(target_directory)); - - /* remove any previous symlink */ - if (file_exists(target_filename)) { - remove(target_filename); - } + stbuf.st_size = plist_dict_get_uint(fileinfo, "st_size"); + const char* s_ifmt = plist_get_string_ptr(plist_dict_get_item(fileinfo, "st_ifmt"), NULL); + if (s_ifmt) { + if (!strcmp(s_ifmt, "S_IFREG")) { + stbuf.st_mode = S_IFREG; + } else if (!strcmp(s_ifmt, "S_IFDIR")) { + stbuf.st_mode = S_IFDIR; + } else if (!strcmp(s_ifmt, "S_IFLNK")) { + stbuf.st_mode = S_IFLNK; + } else if (!strcmp(s_ifmt, "S_IFBLK")) { + stbuf.st_mode = S_IFBLK; + } else if (!strcmp(s_ifmt, "S_IFCHR")) { + stbuf.st_mode = S_IFCHR; + } else if (!strcmp(s_ifmt, "S_IFIFO")) { + stbuf.st_mode = S_IFIFO; + } else if (!strcmp(s_ifmt, "S_IFSOCK")) { + stbuf.st_mode = S_IFSOCK; + } + } + stbuf.st_nlink = plist_dict_get_uint(fileinfo, "st_nlink"); + stbuf.st_mtime = (time_t)(plist_dict_get_uint(fileinfo, "st_mtime") / 1000000000); + const char* linktarget = plist_get_string_ptr(plist_dict_get_item(fileinfo, "LinkTarget"), NULL); + if (linktarget && !remove_all) { + /* report latest crash report filename */ + printf("Link: %s\n", (char*)target_filename + strlen(target_directory)); + + /* remove any previous symlink */ + if (file_exists(target_filename)) { + remove(target_filename); + } -#ifndef WIN32 - /* use relative filename */ - char* b = strrchr(fileinfo[i+1], '/'); - if (b == NULL) { - b = fileinfo[i+1]; +#ifndef _WIN32 + /* use relative filename */ + const char* b = strrchr(linktarget, '/'); + if (b == NULL) { + b = linktarget; } else { - b++; - } + b++; + } - /* create a symlink pointing to latest log */ - if (symlink(b, target_filename) < 0) { - fprintf(stderr, "Can't create symlink to %s\n", b); - } + /* create a symlink pointing to latest log */ + if (symlink(b, target_filename) < 0) { + fprintf(stderr, "Can't create symlink to %s\n", b); + } #endif - if (!keep_crash_reports) - afc_remove_path(afc, source_filename); + if (!keep_crash_reports) + afc_remove_path(afc, source_filename); - res = 0; - } + res = 0; } /* free file information */ - afc_dictionary_free(fileinfo); + plist_free(fileinfo); /* recurse into child directories */ if (S_ISDIR(stbuf.st_mode)) { -#ifdef WIN32 - mkdir(target_filename); + if (!remove_all) { +#ifdef _WIN32 + mkdir(target_filename); #else - mkdir(target_filename, 0755); + mkdir(target_filename, 0755); #endif + } res = afc_client_copy_and_remove_crash_reports(afc, source_filename, target_filename, filename_filter); /* remove directory from device */ - if (!keep_crash_reports) + if (!remove_all && !keep_crash_reports) afc_remove_path(afc, source_filename); } else if (S_ISREG(stbuf.st_mode)) { if (filename_filter != NULL && strstr(source_filename, filename_filter) == NULL) { continue; } + if (remove_all) { + printf("Remove: %s\n", source_filename); + afc_remove_path(afc, source_filename); + continue; + } + /* copy file to host */ afc_error = afc_file_open(afc, source_filename, AFC_FOPEN_RDONLY, &handle); if(afc_error != AFC_E_SUCCESS) { @@ -331,6 +338,7 @@ static void print_usage(int argc, char **argv, int is_error) " -f, --filter NAME filter crash reports by NAME (case sensitive)\n" " -h, --help prints usage information\n" " -v, --version prints version information\n" + " --remove-all remove all crash logs found\n" "\n" "Homepage: <" PACKAGE_URL ">\n" "Bug Reports: <" PACKAGE_BUGREPORT ">\n" @@ -361,10 +369,11 @@ int main(int argc, char* argv[]) { "filter", required_argument, NULL, 'f' }, { "extract", no_argument, NULL, 'e' }, { "keep", no_argument, NULL, 'k' }, + { "remove-all", no_argument, NULL, 1 }, { NULL, 0, NULL, 0} }; -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif @@ -405,6 +414,9 @@ int main(int argc, char* argv[]) case 'k': keep_crash_reports = 1; break; + case 1: + remove_all = 1; + break; default: print_usage(argc, argv, 1); return 2; @@ -414,12 +426,16 @@ int main(int argc, char* argv[]) argv += optind; /* ensure a target directory was supplied */ - if (!argv[0]) { - fprintf(stderr, "ERROR: missing target directory.\n"); - print_usage(argc+optind, argv-optind, 1); - return 2; + if (!remove_all) { + if (!argv[0]) { + fprintf(stderr, "ERROR: missing target directory.\n"); + print_usage(argc+optind, argv-optind, 1); + return 2; + } + target_directory = argv[0]; + } else { + target_directory = "."; } - target_directory = argv[0]; /* check if target directory exists */ if (!file_exists(target_directory)) { diff --git a/tools/idevicedate.c b/tools/idevicedate.c index d05f63e..31b0cf7 100644 --- a/tools/idevicedate.c +++ b/tools/idevicedate.c @@ -33,7 +33,7 @@ #if HAVE_LANGINFO_CODESET #include <langinfo.h> #endif -#ifndef WIN32 +#ifndef _WIN32 #include <signal.h> #endif @@ -43,7 +43,7 @@ #ifdef _DATE_FMT #define DATE_FMT_LANGINFO nl_langinfo (_DATE_FMT) #else -#ifdef WIN32 +#ifdef _WIN32 #define DATE_FMT_LANGINFO "%a %b %#d %H:%M:%S %Z %Y" #else #define DATE_FMT_LANGINFO "%a %b %e %H:%M:%S %Z %Y" @@ -104,7 +104,7 @@ int main(int argc, char *argv[]) { NULL, 0, NULL, 0} }; -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif /* parse cmdline args */ diff --git a/tools/idevicedebug.c b/tools/idevicedebug.c index 36c594e..3f2e289 100644 --- a/tools/idevicedebug.c +++ b/tools/idevicedebug.c @@ -34,7 +34,7 @@ #include <libgen.h> #include <getopt.h> -#ifdef WIN32 +#ifdef _WIN32 #include <windows.h> #define sleep(x) Sleep(x*1000) #endif @@ -239,7 +239,7 @@ int main(int argc, char *argv[]) /* map signals */ signal(SIGINT, on_signal); signal(SIGTERM, on_signal); -#ifndef WIN32 +#ifndef _WIN32 signal(SIGQUIT, on_signal); signal(SIGPIPE, SIG_IGN); #endif diff --git a/tools/idevicedebugserverproxy.c b/tools/idevicedebugserverproxy.c index 9fe7051..fb082b3 100644 --- a/tools/idevicedebugserverproxy.c +++ b/tools/idevicedebugserverproxy.c @@ -32,7 +32,7 @@ #include <getopt.h> #include <errno.h> #include <signal.h> -#ifdef WIN32 +#ifdef _WIN32 #include <winsock2.h> #include <windows.h> #else @@ -219,7 +219,7 @@ int main(int argc, char *argv[]) { NULL, 0, NULL, 0} }; -#ifndef WIN32 +#ifndef _WIN32 struct sigaction sa; struct sigaction si; memset(&sa, '\0', sizeof(struct sigaction)); diff --git a/tools/idevicedevmodectl.c b/tools/idevicedevmodectl.c index bd1de6a..6bf1a1c 100644 --- a/tools/idevicedevmodectl.c +++ b/tools/idevicedevmodectl.c @@ -32,11 +32,11 @@ #include <sys/stat.h> #include <unistd.h> #include <errno.h> -#ifndef WIN32 +#ifndef _WIN32 #include <signal.h> #endif -#ifdef WIN32 +#ifdef _WIN32 #include <windows.h> #define __usleep(x) Sleep(x/1000) #else @@ -259,7 +259,7 @@ int main(int argc, char *argv[]) { NULL, 0, NULL, 0} }; -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif /* parse cmdline args */ diff --git a/tools/idevicediagnostics.c b/tools/idevicediagnostics.c index e699bc4..365c0a4 100644 --- a/tools/idevicediagnostics.c +++ b/tools/idevicediagnostics.c @@ -31,7 +31,7 @@ #include <getopt.h> #include <errno.h> #include <time.h> -#ifndef WIN32 +#ifndef _WIN32 #include <signal.h> #endif @@ -113,7 +113,7 @@ int main(int argc, char **argv) { NULL, 0, NULL, 0} }; -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif /* parse cmdline args */ diff --git a/tools/ideviceenterrecovery.c b/tools/ideviceenterrecovery.c index 29cc5c9..65eb882 100644 --- a/tools/ideviceenterrecovery.c +++ b/tools/ideviceenterrecovery.c @@ -30,7 +30,7 @@ #include <stdlib.h> #include <getopt.h> #include <errno.h> -#ifndef WIN32 +#ifndef _WIN32 #include <signal.h> #endif @@ -70,7 +70,7 @@ int main(int argc, char *argv[]) { NULL, 0, NULL, 0} }; -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif /* parse cmdline args */ diff --git a/tools/ideviceimagemounter.c b/tools/ideviceimagemounter.c index f551b6c..b319d05 100644 --- a/tools/ideviceimagemounter.c +++ b/tools/ideviceimagemounter.c @@ -36,7 +36,8 @@ #include <time.h> #include <sys/time.h> #include <inttypes.h> -#ifndef WIN32 +#include <sys/stat.h> +#ifndef _WIN32 #include <signal.h> #endif @@ -45,8 +46,11 @@ #include <libimobiledevice/afc.h> #include <libimobiledevice/notification_proxy.h> #include <libimobiledevice/mobile_image_mounter.h> +#include <libimobiledevice-glue/sha.h> +#include <libimobiledevice-glue/utils.h> #include <asprintf.h> #include <plist/plist.h> +#include <libtatsu/tss.h> static int list_mode = 0; static int use_network = 0; @@ -62,18 +66,38 @@ typedef enum { DISK_IMAGE_UPLOAD_TYPE_UPLOAD_IMAGE } disk_image_upload_type_t; +enum cmd_mode { + CMD_NONE = 0, + CMD_MOUNT, + CMD_UNMOUNT, + CMD_LIST, + CMD_DEVMODESTATUS +}; + +int cmd = CMD_NONE; + static void print_usage(int argc, char **argv, int is_error) { char *name = strrchr(argv[0], '/'); - fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] IMAGE_FILE IMAGE_SIGNATURE_FILE\n", (name ? name + 1: argv[0])); + fprintf(is_error ? stderr : stdout, "Usage: %s [OPTIONS] COMMAND [COMMAND OPTIONS...]\n", (name ? name + 1: argv[0])); fprintf(is_error ? stderr : stdout, "\n" - "Mounts the specified disk image on the device.\n" + "Mount, list, or unmount a disk image on the device.\n" + "\n" + "COMMANDS:\n" + " mount PATH Mount the developer disk image at PATH.\n" + " For iOS 17+, PATH is a directory containing a .dmg image,\n" + " a BuildManifest.plist, and a Firmware sub-directory;\n" + " for older versions PATH is a .dmg filename with a\n" + " .dmg.signature in the same directory, or with another\n" + " parameter pointing to a file elsewhere.\n" + " list List mounted disk images.\n" + " unmount PATH Unmount the image mounted at PATH.\n" + " devmodestatus Query the developer mode status (iOS 16+)\n" "\n" "OPTIONS:\n" " -u, --udid UDID target specific device by UDID\n" " -n, --network connect to network device\n" - " -l, --list List mount information\n" " -t, --imagetype TYPE Image type to use, default is 'Developer'\n" " -x, --xml Use XML output\n" " -d, --debug enable communication debugging\n" @@ -87,11 +111,11 @@ static void print_usage(int argc, char **argv, int is_error) static void parse_opts(int argc, char **argv) { + int debug_level = 0; static struct option longopts[] = { { "help", no_argument, NULL, 'h' }, { "udid", required_argument, NULL, 'u' }, { "network", no_argument, NULL, 'n' }, - { "list", no_argument, NULL, 'l' }, { "imagetype", required_argument, NULL, 't' }, { "xml", no_argument, NULL, 'x' }, { "debug", no_argument, NULL, 'd' }, @@ -101,7 +125,7 @@ static void parse_opts(int argc, char **argv) int c; while (1) { - c = getopt_long(argc, argv, "hu:lt:xdnv", longopts, NULL); + c = getopt_long(argc, argv, "hu:t:xdnv", longopts, NULL); if (c == -1) { break; } @@ -121,9 +145,6 @@ static void parse_opts(int argc, char **argv) case 'n': use_network = 1; break; - case 'l': - list_mode = 1; - break; case 't': imagetype = optarg; break; @@ -131,7 +152,7 @@ static void parse_opts(int argc, char **argv) xml_mode = 1; break; case 'd': - idevice_set_debug_level(1); + debug_level++; break; case 'v': printf("%s %s\n", TOOL_NAME, PACKAGE_VERSION); @@ -141,6 +162,8 @@ static void parse_opts(int argc, char **argv) exit(2); } } + idevice_set_debug_level(debug_level); + tss_set_debug_level(debug_level); } static ssize_t mim_upload_cb(void* buf, size_t size, void* userdata) @@ -161,7 +184,7 @@ int main(int argc, char **argv) size_t image_size = 0; char *image_sig_path = NULL; -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif parse_opts(argc, argv); @@ -169,29 +192,75 @@ int main(int argc, char **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]); + if (argc == 0) { + fprintf(stderr, "ERROR: Missing command.\n\n"); + print_usage(argc+optind, argv-optind, 1); + return 2; + } + + char* cmdstr = argv[0]; + + int optind2 = 0; + if (!strcmp(cmdstr, "mount")) { + cmd = CMD_MOUNT; + optind2++; + } else if (!strcmp(cmdstr, "list")) { + cmd = CMD_LIST; + optind2++; + } else if (!strcmp(cmdstr, "umount") || !strcmp(cmdstr, "unmount")) { + cmd = CMD_UNMOUNT; + optind2++; + } else if (!strcmp(cmdstr, "devmodestatus")) { + cmd = CMD_DEVMODESTATUS; + optind2++; + } else { + // assume mount command, unless -l / --list was specified + if (list_mode) { + cmd = CMD_LIST; } else { - if (asprintf(&image_sig_path, "%s.signature", image_path) < 0) { - printf("Out of memory?!\n"); - return -1; - } + cmd = CMD_MOUNT; } } + argc -= optind2; + argv += optind2; + optind += optind2; + + switch (cmd) { + case CMD_MOUNT: + if (argc < 1) { + fprintf(stderr, "ERROR: Missing IMAGE_FILE for mount command\n"); + print_usage(argc+optind, argv-optind, 1); + return 2; + } + 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; + } + } + break; + case CMD_UNMOUNT: + if (argc != 1) { + fprintf(stderr, "ERROR: Missing mount path (argc = %d)\n", argc); + print_usage(argc+optind, argv-optind, 1); + return 2; + } + break; + default: + break; + } + if (IDEVICE_E_SUCCESS != idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX)) { if (udid) { printf("No device found with udid %s.\n", udid); } else { printf("No device found.\n"); } - return -1; + return 1; } if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &lckd, TOOL_NAME))) { @@ -199,23 +268,14 @@ int main(int argc, char **argv) goto leave; } - plist_t pver = NULL; - char *product_version = NULL; - lockdownd_get_value(lckd, NULL, "ProductVersion", &pver); - if (pver && plist_get_node_type(pver) == PLIST_STRING) { - plist_get_string_val(pver, &product_version); - } + unsigned int device_version = idevice_get_device_version(device); + disk_image_upload_type_t disk_image_upload_type = DISK_IMAGE_UPLOAD_TYPE_AFC; - int product_version_major = 0; - int product_version_minor = 0; - if (product_version) { - if (sscanf(product_version, "%d.%d.%*d", &product_version_major, &product_version_minor) == 2) { - if (product_version_major >= 7) - disk_image_upload_type = DISK_IMAGE_UPLOAD_TYPE_UPLOAD_IMAGE; - } + if (device_version >= IDEVICE_DEVICE_VERSION(7,0,0)) { + disk_image_upload_type = DISK_IMAGE_UPLOAD_TYPE_UPLOAD_IMAGE; } - if (product_version_major == 16) { + if (device_version >= IDEVICE_DEVICE_VERSION(16,0,0)) { uint8_t dev_mode_status = 0; plist_t val = NULL; ldret = lockdownd_get_value(lckd, "com.apple.security.mac.amfi", "DeveloperModeStatus", &val); @@ -246,7 +306,7 @@ int main(int argc, char **argv) service = NULL; } - if (!list_mode) { + if (cmd == CMD_MOUNT) { struct stat fst; if (disk_image_upload_type == DISK_IMAGE_UPLOAD_TYPE_AFC) { if ((lockdownd_start_service(lckd, "com.apple.afc", &service) != @@ -268,7 +328,7 @@ int main(int argc, char **argv) goto leave; } image_size = fst.st_size; - if (stat(image_sig_path, &fst) != 0) { + if (device_version < IDEVICE_DEVICE_VERSION(17,0,0) && stat(image_sig_path, &fst) != 0) { fprintf(stderr, "ERROR: stat: %s: %s\n", image_sig_path, strerror(errno)); goto leave; } @@ -280,10 +340,14 @@ int main(int argc, char **argv) mobile_image_mounter_error_t err = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR; plist_t result = NULL; - if (list_mode) { + if (cmd == CMD_LIST) { /* list mounts mode */ if (!imagetype) { - imagetype = "Developer"; + if (device_version < IDEVICE_DEVICE_VERSION(17,0,0)) { + imagetype = "Developer"; + } else { + imagetype = "Personalized"; + } } err = mobile_image_mounter_lookup_image(mim, imagetype, &result); if (err == MOBILE_IMAGE_MOUNTER_E_SUCCESS) { @@ -292,25 +356,217 @@ int main(int argc, char **argv) } else { printf("Error: lookup_image returned %d\n", err); } - } else { - char sig[8192]; + } else if (cmd == CMD_MOUNT) { + unsigned char *sig = NULL; 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; - } + FILE *f; + struct stat fst; + plist_t mount_options = NULL; - f = fopen(image_path, "rb"); - if (!f) { - fprintf(stderr, "Error opening image file '%s': %s\n", image_path, strerror(errno)); - goto leave; + if (device_version < IDEVICE_DEVICE_VERSION(17,0,0)) { + f = fopen(image_sig_path, "rb"); + if (!f) { + fprintf(stderr, "Error opening signature file '%s': %s\n", image_sig_path, strerror(errno)); + goto leave; + } + if (fstat(fileno(f), &fst) != 0) { + fprintf(stderr, "Error: fstat: %s\n", strerror(errno)); + goto leave; + } + sig = malloc(fst.st_size); + sig_length = fread(sig, 1, fst.st_size, 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; + } + } else { + if (stat(image_path, &fst) != 0) { + fprintf(stderr, "Error: stat: '%s': %s\n", image_path, strerror(errno)); + goto leave; + } + if (!S_ISDIR(fst.st_mode)) { + fprintf(stderr, "Error: Personalized Disk Image mount expects a directory as image path.\n"); + goto leave; + } + char* build_manifest_path = string_build_path(image_path, "BuildManifest.plist", NULL); + plist_t build_manifest = NULL; + if (plist_read_from_file(build_manifest_path, &build_manifest, NULL) != 0) { + free(build_manifest_path); + build_manifest_path = string_build_path(image_path, "Restore", "BuildManifest.plist", NULL); + if (plist_read_from_file(build_manifest_path, &build_manifest, NULL) == 0) { + char* image_path_new = string_build_path(image_path, "Restore", NULL); + free(image_path); + image_path = image_path_new; + } + } + if (!build_manifest) { + fprintf(stderr, "Error: Could not locate BuildManifest.plist inside given disk image path!\n"); + goto leave; + } + + plist_t identifiers = NULL; + mobile_image_mounter_error_t merr = mobile_image_mounter_query_personalization_identifiers(mim, NULL, &identifiers); + if (merr != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + fprintf(stderr, "Failed to query personalization identifiers: %d\n", merr); + goto error_out; + } + + unsigned int board_id = plist_dict_get_uint(identifiers, "BoardId"); + unsigned int chip_id = plist_dict_get_uint(identifiers, "ChipID"); + + plist_t build_identities = plist_dict_get_item(build_manifest, "BuildIdentities"); + plist_array_iter iter; + plist_array_new_iter(build_identities, &iter); + plist_t item = NULL; + plist_t build_identity = NULL; + do { + plist_array_next_item(build_identities, iter, &item); + if (!item) { + break; + } + unsigned int bi_board_id = (unsigned int)plist_dict_get_uint(item, "ApBoardID"); + unsigned int bi_chip_id = (unsigned int)plist_dict_get_uint(item, "ApChipID"); + if (bi_chip_id == chip_id && bi_board_id == board_id) { + build_identity = item; + break; + } + } while (item); + plist_mem_free(iter); + if (!build_identity) { + fprintf(stderr, "Error: The given disk image is not compatible with the current device.\n"); + goto leave; + } + plist_t p_tc_path = plist_access_path(build_identity, 4, "Manifest", "LoadableTrustCache", "Info", "Path"); + if (!p_tc_path) { + fprintf(stderr, "Error: Could not determine path for trust cache!\n"); + goto leave; + } + plist_t p_dmg_path = plist_access_path(build_identity, 4, "Manifest", "PersonalizedDMG", "Info", "Path"); + if (!p_dmg_path) { + fprintf(stderr, "Error: Could not determine path for disk image!\n"); + goto leave; + } + char *tc_path = string_build_path(image_path, plist_get_string_ptr(p_tc_path, NULL), NULL); + unsigned char* trust_cache = NULL; + uint64_t trust_cache_size = 0; + if (!buffer_read_from_filename(tc_path, (char**)&trust_cache, &trust_cache_size)) { + fprintf(stderr, "Error: Trust cache does not exist at '%s'!\n", tc_path); + goto leave; + } + mount_options = plist_new_dict(); + plist_dict_set_item(mount_options, "ImageTrustCache", plist_new_data((char*)trust_cache, trust_cache_size)); + free(trust_cache); + char *dmg_path = string_build_path(image_path, plist_get_string_ptr(p_dmg_path, NULL), NULL); + free(image_path); + image_path = dmg_path; + f = fopen(image_path, "rb"); + if (!f) { + fprintf(stderr, "Error opening image file '%s': %s\n", image_path, strerror(errno)); + goto leave; + } + + unsigned char buf[8192]; + unsigned char sha384_digest[48]; + sha384_context ctx; + sha384_init(&ctx); + fstat(fileno(f), &fst); + image_size = fst.st_size; + while (!feof(f)) { + ssize_t fr = fread(buf, 1, sizeof(buf), f); + if (fr <= 0) { + break; + } + sha384_update(&ctx, buf, fr); + } + rewind(f); + sha384_final(&ctx, sha384_digest); + unsigned char* manifest = NULL; + unsigned int manifest_size = 0; + /* check if the device already has a personalization manifest for this image */ + if (mobile_image_mounter_query_personalization_manifest(mim, "DeveloperDiskImage", sha384_digest, sizeof(sha384_digest), &manifest, &manifest_size) == MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + printf("Using existing personalization manifest from device.\n"); + } else { + /* we need to re-connect in this case */ + mobile_image_mounter_free(mim); + mim = NULL; + if (mobile_image_mounter_start_service(device, &mim, TOOL_NAME) != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + goto error_out; + } + printf("No personalization manifest, requesting from TSS...\n"); + unsigned char* nonce = NULL; + unsigned int nonce_size = 0; + + /* create new TSS request and fill parameters */ + plist_t request = tss_request_new(NULL); + plist_t params = plist_new_dict(); + tss_parameters_add_from_manifest(params, build_identity, 1); + + /* copy all `Ap,*` items from identifiers */ + plist_dict_iter di = NULL; + plist_dict_new_iter(identifiers, &di); + plist_t node = NULL; + do { + char* key = NULL; + plist_dict_next_item(identifiers, di, &key, &node); + if (node) { + if (!strncmp(key, "Ap,", 3)) { + plist_dict_set_item(request, key, plist_copy(node)); + } + } + free(key); + } while (node); + plist_mem_free(di); + + plist_dict_copy_uint(params, identifiers, "ApECID", "UniqueChipID"); + plist_dict_set_item(params, "ApProductionMode", plist_new_bool(1)); + plist_dict_set_item(params, "ApSecurityMode", plist_new_bool(1)); + plist_dict_set_item(params, "ApSupportsImg4", plist_new_bool(1)); + + /* query nonce from image mounter service */ + merr = mobile_image_mounter_query_nonce(mim, "DeveloperDiskImage", &nonce, &nonce_size); + if (merr == MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + plist_dict_set_item(params, "ApNonce", plist_new_data((char*)nonce, nonce_size)); + } else { + fprintf(stderr, "ERROR: Failed to query nonce for developer disk image: %d\n", merr); + goto error_out; + } + mobile_image_mounter_free(mim); + mim = NULL; + + plist_dict_set_item(params, "ApSepNonce", plist_new_data("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 20)); + plist_dict_set_item(params, "UID_MODE", plist_new_bool(0)); + tss_request_add_ap_tags(request, params, NULL); + tss_request_add_common_tags(request, params, NULL); + tss_request_add_ap_img4_tags(request, params); + plist_free(params); + + /* request IM4M from TSS */ + plist_t response = tss_request_send(request, NULL); + plist_free(request); + + plist_t p_manifest = plist_dict_get_item(response, "ApImg4Ticket"); + if (!PLIST_IS_DATA(p_manifest)) { + fprintf(stderr, "Failed to get Img4Ticket\n"); + goto error_out; + } + + uint64_t m4m_len = 0; + plist_get_data_val(p_manifest, (char**)&manifest, &m4m_len); + manifest_size = m4m_len; + plist_free(response); + printf("Done.\n"); + } + sig = manifest; + sig_length = manifest_size; + + imagetype = "Personalized"; } char *targetname = NULL; @@ -324,11 +580,16 @@ int main(int argc, char **argv) goto leave; } - if (!imagetype) { imagetype = "Developer"; } + if (!mim) { + if (mobile_image_mounter_start_service(device, &mim, TOOL_NAME) != MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + goto error_out; + } + } + switch(disk_image_upload_type) { case DISK_IMAGE_UPLOAD_TYPE_UPLOAD_IMAGE: printf("Uploading %s\n", image_path); @@ -337,20 +598,13 @@ int main(int argc, char **argv) case DISK_IMAGE_UPLOAD_TYPE_AFC: default: printf("Uploading %s --> afc:///%s\n", image_path, targetname); - char **strs = NULL; - if (afc_get_file_info(afc, PKG_PATH, &strs) != AFC_E_SUCCESS) { + plist_t fileinfo = NULL; + if (afc_get_file_info_plist(afc, PKG_PATH, &fileinfo) != 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_free(fileinfo); uint64_t af = 0; if ((afc_file_open(afc, targetname, AFC_FOPEN_WRONLY, &af) != @@ -403,7 +657,7 @@ int main(int argc, char **argv) printf("done.\n"); printf("Mounting...\n"); - err = mobile_image_mounter_mount_image(mim, mountname, sig, sig_length, imagetype, &result); + err = mobile_image_mounter_mount_image_with_options(mim, mountname, sig, sig_length, imagetype, mount_options, &result); if (err == MOBILE_IMAGE_MOUNTER_E_SUCCESS) { if (result) { plist_t node = plist_dict_get_item(result, "Status"); @@ -435,7 +689,10 @@ int main(int argc, char **argv) printf("unexpected result:\n"); plist_write_to_stream(result, stdout, (xml_mode) ? PLIST_FORMAT_XML : PLIST_FORMAT_LIMD, 0); } - + node = plist_dict_get_item(result, "DetailedError"); + if (node) { + printf("DetailedError: %s\n", plist_get_string_ptr(node, NULL)); + } } else { plist_write_to_stream(result, stdout, (xml_mode) ? PLIST_FORMAT_XML : PLIST_FORMAT_LIMD, 0); } @@ -444,6 +701,37 @@ int main(int argc, char **argv) printf("Error: mount_image returned %d\n", err); } + } else if (cmd == CMD_UNMOUNT) { + err = mobile_image_mounter_unmount_image(mim, argv[0]); + switch (err) { + case MOBILE_IMAGE_MOUNTER_E_SUCCESS: + printf("Success\n"); + res = 0; + break; + case MOBILE_IMAGE_MOUNTER_E_COMMAND_FAILED: + printf("Error: '%s' is not mounted\n", argv[0]); + res = 1; + break; + case MOBILE_IMAGE_MOUNTER_E_NOT_SUPPORTED: + printf("Error: 'unmount' is not supported on this device\n"); + res = 1; + break; + case MOBILE_IMAGE_MOUNTER_E_DEVICE_LOCKED: + printf("Error: device is locked\n"); + res = 1; + break; + default: + printf("Error: unmount returned %d\n", err); + break; + } + } else if (cmd == CMD_DEVMODESTATUS) { + err = mobile_image_mounter_query_developer_mode_status(mim, &result); + if (err == MOBILE_IMAGE_MOUNTER_E_SUCCESS) { + res = 0; + plist_write_to_stream(result, stdout, (xml_mode) ? PLIST_FORMAT_XML : PLIST_FORMAT_LIMD, 0); + } else { + printf("Error: query_developer_mode_status returned %d\n", err); + } } if (result) { @@ -466,7 +754,7 @@ leave: idevice_free(device); if (image_path) - free(image_path); + free(image_path); if (image_sig_path) free(image_sig_path); diff --git a/tools/ideviceinfo.c b/tools/ideviceinfo.c index fd45763..20cc916 100644 --- a/tools/ideviceinfo.c +++ b/tools/ideviceinfo.c @@ -31,7 +31,7 @@ #include <errno.h> #include <stdlib.h> #include <getopt.h> -#ifndef WIN32 +#ifndef _WIN32 #include <signal.h> #endif @@ -152,7 +152,7 @@ int main(int argc, char *argv[]) { NULL, 0, NULL, 0} }; -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif diff --git a/tools/idevicename.c b/tools/idevicename.c index 69b76f6..248bda3 100644 --- a/tools/idevicename.c +++ b/tools/idevicename.c @@ -30,7 +30,7 @@ #include <unistd.h> #include <stdlib.h> #include <getopt.h> -#ifndef WIN32 +#ifndef _WIN32 #include <signal.h> #endif @@ -72,7 +72,7 @@ int main(int argc, char** argv) const char* udid = NULL; int use_network = 0; -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif diff --git a/tools/idevicenotificationproxy.c b/tools/idevicenotificationproxy.c index d1e25c1..192192a 100644 --- a/tools/idevicenotificationproxy.c +++ b/tools/idevicenotificationproxy.c @@ -2,7 +2,8 @@ * idevicenotificationproxy.c * Simple client for the notification_proxy service * - * Copyright (c) 2009-2015 Martin Szulecki All Rights Reserved. + * Copyright (c) 2018-2024 Nikias Bassen, All Rights Reserved. + * Copyright (c) 2009-2015 Martin Szulecki, All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -32,7 +33,7 @@ #include <errno.h> #include <signal.h> -#ifdef WIN32 +#ifdef _WIN32 #include <windows.h> #define sleep(x) Sleep(x*1000) #else @@ -75,6 +76,7 @@ static void print_usage(int argc, char **argv, int is_error) "\n" "The following OPTIONS are accepted:\n" " -u, --udid UDID target specific device by UDID\n" + " -i, --insecure use insecure notification proxy (non-paired device)\n" " -n, --network connect to network device\n" " -d, --debug enable communication debugging\n" " -h, --help prints usage information\n" @@ -102,6 +104,7 @@ int main(int argc, char *argv[]) int i = 0; const char* udid = NULL; int use_network = 0; + int insecure = 0; int cmd = CMD_NONE; char* cmd_arg = NULL; @@ -114,6 +117,7 @@ int main(int argc, char *argv[]) { "debug", no_argument, NULL, 'd' }, { "help", no_argument, NULL, 'h' }, { "udid", required_argument, NULL, 'u' }, + { "insecure", no_argument, NULL, 'i' }, { "network", no_argument, NULL, 'n' }, { "version", no_argument, NULL, 'v' }, { NULL, 0, NULL, 0} @@ -121,13 +125,13 @@ int main(int argc, char *argv[]) signal(SIGINT, clean_exit); signal(SIGTERM, clean_exit); -#ifndef WIN32 +#ifndef _WIN32 signal(SIGQUIT, clean_exit); signal(SIGPIPE, SIG_IGN); #endif /* parse cmdline args */ - while ((c = getopt_long(argc, argv, "dhu:nv", longopts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "dhu:inv", longopts, NULL)) != -1) { switch (c) { case 'd': idevice_set_debug_level(1); @@ -143,6 +147,9 @@ int main(int argc, char *argv[]) case 'n': use_network = 1; break; + case 'i': + insecure = 1; + break; case 'h': print_usage(argc, argv, 0); return 0; @@ -214,12 +221,17 @@ int main(int argc, char *argv[]) goto cleanup; } - if (LOCKDOWN_E_SUCCESS != (ret = lockdownd_client_new_with_handshake(device, &client, TOOL_NAME))) { - fprintf(stderr, "ERROR: Could not connect to lockdownd, error code %d\n", ret); + if (insecure) { + ret = lockdownd_client_new(device, &client, TOOL_NAME); + } else { + ret = lockdownd_client_new_with_handshake(device, &client, TOOL_NAME); + } + if (LOCKDOWN_E_SUCCESS != ret) { + fprintf(stderr, "ERROR: Could not connect to lockdownd: %s (%d)\n", lockdownd_strerror(ret), ret); goto cleanup; } - ret = lockdownd_start_service(client, NP_SERVICE_NAME, &service); + ret = lockdownd_start_service(client, (insecure) ? "com.apple.mobile.insecure_notification_proxy" : NP_SERVICE_NAME, &service); lockdownd_client_free(client); diff --git a/tools/idevicepair.c b/tools/idevicepair.c index 94d3f04..884c690 100644 --- a/tools/idevicepair.c +++ b/tools/idevicepair.c @@ -32,7 +32,7 @@ #include <getopt.h> #include <ctype.h> #include <unistd.h> -#ifdef WIN32 +#ifdef _WIN32 #include <windows.h> #include <conio.h> #else @@ -50,7 +50,7 @@ static char *udid = NULL; #ifdef HAVE_WIRELESS_PAIRING -#ifdef WIN32 +#ifdef _WIN32 #define BS_CC '\b' #define my_getch getch #else @@ -293,7 +293,7 @@ int main(int argc, char **argv) } } -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif diff --git a/tools/ideviceprovision.c b/tools/ideviceprovision.c index 4080a28..94f4ec5 100644 --- a/tools/ideviceprovision.c +++ b/tools/ideviceprovision.c @@ -32,11 +32,12 @@ #include <getopt.h> #include <sys/stat.h> #include <errno.h> -#ifndef WIN32 +#ifndef _WIN32 #include <signal.h> #endif -#ifdef WIN32 +#ifdef _WIN32 +#include <winsock2.h> #include <windows.h> #else #include <arpa/inet.h> @@ -314,7 +315,7 @@ int main(int argc, char *argv[]) { NULL, 0, NULL, 0} }; -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif /* parse cmdline args */ @@ -475,27 +476,7 @@ int main(int argc, char *argv[]) return -1; } - plist_t pver = NULL; - char *pver_s = NULL; - lockdownd_get_value(client, NULL, "ProductVersion", &pver); - if (pver && plist_get_node_type(pver) == PLIST_STRING) { - plist_get_string_val(pver, &pver_s); - } - plist_free(pver); - int product_version_major = 0; - int product_version_minor = 0; - int product_version_patch = 0; - if (pver_s) { - sscanf(pver_s, "%d.%d.%d", &product_version_major, &product_version_minor, &product_version_patch); - free(pver_s); - } - if (product_version_major == 0) { - fprintf(stderr, "ERROR: Could not determine the device's ProductVersion\n"); - lockdownd_client_free(client); - idevice_free(device); - return -1; - } - int product_version = ((product_version_major & 0xFF) << 16) | ((product_version_minor & 0xFF) << 8) | (product_version_patch & 0xFF); + unsigned int device_version = idevice_get_device_version(device); lockdownd_error_t lerr = lockdownd_start_service(client, MISAGENT_SERVICE_NAME, &service); if (lerr != LOCKDOWN_E_SUCCESS) { @@ -546,7 +527,7 @@ int main(int argc, char *argv[]) { plist_t profiles = NULL; misagent_error_t merr; - if (product_version < 0x090300) { + if (device_version < IDEVICE_DEVICE_VERSION(9,3,0)) { merr = misagent_copy(mis, &profiles); } else { merr = misagent_copy_all(mis, &profiles); @@ -631,7 +612,7 @@ int main(int argc, char *argv[]) /* remove all provisioning profiles */ plist_t profiles = NULL; misagent_error_t merr; - if (product_version < 0x090300) { + if (device_version < IDEVICE_DEVICE_VERSION(9,3,0)) { merr = misagent_copy(mis, &profiles); } else { merr = misagent_copy_all(mis, &profiles); diff --git a/tools/idevicescreenshot.c b/tools/idevicescreenshot.c index 0e694c7..bfaa059 100644 --- a/tools/idevicescreenshot.c +++ b/tools/idevicescreenshot.c @@ -32,7 +32,7 @@ #include <errno.h> #include <time.h> #include <unistd.h> -#ifndef WIN32 +#ifndef _WIN32 #include <signal.h> #endif @@ -142,7 +142,7 @@ int main(int argc, char **argv) { NULL, 0, NULL, 0} }; -#ifndef WIN32 +#ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif /* parse cmdline args */ diff --git a/tools/idevicesetlocation.c b/tools/idevicesetlocation.c index 69fbaf5..dca8830 100644 --- a/tools/idevicesetlocation.c +++ b/tools/idevicesetlocation.c @@ -113,7 +113,7 @@ int main(int argc, char **argv) if ((argc > 2) || (argc < 1)) { print_usage(argc+optind, argv-optind, 1); - return -1; + return 1; } if (argc == 2) { @@ -123,7 +123,7 @@ int main(int argc, char **argv) mode = RESET_LOCATION; } else { print_usage(argc+optind, argv-optind, 1); - return -1; + return 1; } } @@ -135,19 +135,30 @@ int main(int argc, char **argv) } else { printf("ERROR: No device found!\n"); } - return -1; + return 1; } - lockdownd_client_t lockdown; - lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME); + lockdownd_client_t lockdown = NULL; + lockdownd_error_t lerr = lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME); + if (lerr != LOCKDOWN_E_SUCCESS) { + idevice_free(device); + printf("ERROR: Could not connect to lockdownd: %s (%d)\n", lockdownd_strerror(lerr), lerr); + return 1; + } lockdownd_service_descriptor_t svc = NULL; - lockdownd_error_t lerr = lockdownd_start_service(lockdown, DT_SIMULATELOCATION_SERVICE, &svc); + lerr = lockdownd_start_service(lockdown, DT_SIMULATELOCATION_SERVICE, &svc); if (lerr != LOCKDOWN_E_SUCCESS) { + unsigned int device_version = idevice_get_device_version(device); lockdownd_client_free(lockdown); idevice_free(device); - printf("ERROR: Could not start the simulatelocation service: %s\nMake sure a developer disk image is mounted!\n", lockdownd_strerror(lerr)); - return -1; + printf("ERROR: Could not start the simulatelocation service: %s\n", lockdownd_strerror(lerr)); + if (device_version >= IDEVICE_DEVICE_VERSION(17,0,0)) { + printf("Note: This tool is currently not supported on iOS 17+\n"); + } else { + printf("Make sure a developer disk image is mounted!\n"); + } + return 1; } lockdownd_client_free(lockdown); @@ -158,10 +169,9 @@ int main(int argc, char **argv) lockdownd_service_descriptor_free(svc); if (serr != SERVICE_E_SUCCESS) { - lockdownd_client_free(lockdown); idevice_free(device); printf("ERROR: Could not connect to simulatelocation service (%d)\n", serr); - return -1; + return 1; } uint32_t l; diff --git a/tools/idevicesyslog.c b/tools/idevicesyslog.c index a0e641d..88af4c1 100644 --- a/tools/idevicesyslog.c +++ b/tools/idevicesyslog.c @@ -33,8 +33,9 @@ #include <stdlib.h> #include <unistd.h> #include <getopt.h> +#include <time.h> -#ifdef WIN32 +#ifdef _WIN32 #include <windows.h> #define sleep(x) Sleep(x*1000) #endif @@ -42,10 +43,12 @@ #include <libimobiledevice/libimobiledevice.h> #include <libimobiledevice/syslog_relay.h> #include <libimobiledevice-glue/termcolors.h> +#include <libimobiledevice/ostrace.h> static int quit_flag = 0; static int exit_on_disconnect = 0; static int show_device_name = 0; +static int force_syslog_relay = 0; static char* udid = NULL; static char** proc_filters = NULL; @@ -58,6 +61,9 @@ static int num_pid_filters = 0; static char** msg_filters = NULL; static int num_msg_filters = 0; +static char** msg_reverse_filters = NULL; +static int num_msg_reverse_filters = 0; + static char** trigger_filters = NULL; static int num_trigger_filters = 0; static char** untrigger_filters = NULL; @@ -66,11 +72,16 @@ static int triggered = 0; static idevice_t device = NULL; static syslog_relay_client_t syslog = NULL; +static ostrace_client_t ostrace = NULL; static const char QUIET_FILTER[] = "CircleJoinRequested|CommCenter|HeuristicInterpreter|MobileMail|PowerUIAgent|ProtectedCloudKeySyncing|SpringBoard|UserEventAgent|WirelessRadioManagerd|accessoryd|accountsd|aggregated|analyticsd|appstored|apsd|assetsd|assistant_service|backboardd|biometrickitd|bluetoothd|calaccessd|callservicesd|cloudd|com.apple.Safari.SafeBrowsing.Service|contextstored|corecaptured|coreduetd|corespeechd|cdpd|dasd|dataaccessd|distnoted|dprivacyd|duetexpertd|findmydeviced|fmfd|fmflocatord|gpsd|healthd|homed|identityservicesd|imagent|itunescloudd|itunesstored|kernel|locationd|maild|mDNSResponder|mediaremoted|mediaserverd|mobileassetd|nanoregistryd|nanotimekitcompaniond|navd|nsurlsessiond|passd|pasted|photoanalysisd|powerd|powerlogHelperd|ptpd|rapportd|remindd|routined|runningboardd|searchd|sharingd|suggestd|symptomsd|timed|thermalmonitord|useractivityd|vmd|wifid|wirelessproxd"; static int use_network = 0; +static long long start_time = -1; +static long long size_limit = -1; +static long long age_limit = -1; + static char *line = NULL; static int line_buffer_size = 0; static int lp = 0; @@ -129,6 +140,70 @@ static int find_char(char c, char** p, const char* end) static void stop_logging(void); +static int message_filter_matching(const char* message) +{ + if (num_msg_filters > 0) { + int found = 0; + int i; + for (i = 0; i < num_msg_filters; i++) { + if (strstr(message, msg_filters[i])) { + found = 1; + break; + } + } + if (!found) { + return 0; + } + } + if (num_msg_reverse_filters > 0) { + int found = 0; + int i; + for (i = 0; i < num_msg_reverse_filters; i++) { + if (strstr(message, msg_reverse_filters[i])) { + found = 1; + break; + } + } + if (found) { + return 0; + } + } + return 1; +} + +static int process_filter_matching(int pid, const char* process_name, int process_name_length) +{ + int proc_matched = 0; + if (num_pid_filters > 0) { + int found = proc_filter_excluding; + int i = 0; + for (i = 0; i < num_pid_filters; i++) { + if (pid == pid_filters[i]) { + found = !proc_filter_excluding; + break; + } + } + if (found) { + proc_matched = 1; + } + } + if (num_proc_filters > 0 && !proc_matched) { + int found = proc_filter_excluding; + int i = 0; + for (i = 0; i < num_proc_filters; i++) { + if (!proc_filters[i]) continue; + if (strncmp(proc_filters[i], process_name, process_name_length) == 0) { + found = !proc_filter_excluding; + break; + } + } + if (found) { + proc_matched = 1; + } + } + return proc_matched; +} + static void syslog_callback(char c, void *user_data) { if (lp >= line_buffer_size-1) { @@ -202,20 +277,9 @@ static void syslog_callback(char c, void *user_data) } /* check message filters */ - if (num_msg_filters > 0) { - int found = 0; - int i; - for (i = 0; i < num_msg_filters; i++) { - if (strstr(device_name_end+1, msg_filters[i])) { - found = 1; - break; - } - } - if (!found) { - shall_print = 0; - break; - } - shall_print = 1; + shall_print = message_filter_matching(device_name_end+1); + if (!shall_print) { + break; } /* process name */ @@ -235,39 +299,10 @@ static void syslog_callback(char c, void *user_data) proc_name_end = p; p++; - int proc_matched = 0; - if (num_pid_filters > 0) { - char* endp = NULL; - int pid_value = (int)strtol(pid_start, &endp, 10); - if (endp && (*endp == ']')) { - int found = proc_filter_excluding; - int i = 0; - for (i = 0; i < num_pid_filters; i++) { - if (pid_value == pid_filters[i]) { - found = !proc_filter_excluding; - break; - } - } - if (found) { - proc_matched = 1; - } - } - } - if (num_proc_filters > 0 && !proc_matched) { - int found = proc_filter_excluding; - int i = 0; - for (i = 0; i < num_proc_filters; i++) { - if (!proc_filters[i]) continue; - if (strncmp(proc_filters[i], process_name_start, process_name_end-process_name_start) == 0) { - found = !proc_filter_excluding; - break; - } - } - if (found) { - proc_matched = 1; - } - } - if (proc_matched) { + /* match pid / process name */ + char* endp = NULL; + int pid_value = (int)strtol(pid_start, &endp, 10); + if (process_filter_matching(pid_value, process_name_start, process_name_end-process_name_start)) { shall_print = 1; } else { if (num_pid_filters > 0 || num_proc_filters > 0) { @@ -331,7 +366,7 @@ static void syslog_callback(char c, void *user_data) } } while (0); - if ((num_msg_filters == 0 && num_proc_filters == 0 && num_pid_filters == 0 && num_trigger_filters == 0 && num_untrigger_filters == 0) || shall_print) { + if ((num_msg_filters == 0 && num_msg_reverse_filters == 0 && num_proc_filters == 0 && num_pid_filters == 0 && num_trigger_filters == 0 && num_untrigger_filters == 0) || shall_print) { fwrite(linep, 1, lp, stdout); cprintf(COLOR_RESET); fflush(stdout); @@ -345,12 +380,231 @@ static void syslog_callback(char c, void *user_data) } } -static int start_logging(void) +static void ostrace_syslog_callback(const void* buf, size_t len, void* user_data) { - idevice_error_t ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX); - if (ret != IDEVICE_E_SUCCESS) { - fprintf(stderr, "Device with udid %s not found!?\n", udid); - return -1; + if (len < 0x81) { + fprintf(stderr, "Error: not enough data in callback function?!\n"); + return; + } + + struct ostrace_packet_header_t *trace_hdr = (struct ostrace_packet_header_t*)buf; + + if (trace_hdr->marker != 2 || (trace_hdr->type != 8 && trace_hdr->type != 2)) { + fprintf(stderr, "unexpected packet data %02x %08x\n", trace_hdr->marker, trace_hdr->type); + } + + const char* dataptr = (const char*)buf + trace_hdr->header_size; + const char* process_name = dataptr; + const char* image_name = (trace_hdr->imagepath_len > 0) ? dataptr + trace_hdr->procpath_len : NULL; + const char* message = (trace_hdr->message_len > 0) ? dataptr + trace_hdr->procpath_len + trace_hdr->imagepath_len : NULL; + //const char* subsystem = (trace_hdr->subsystem_len > 0) ? dataptr + trace_hdr->procpath_len + trace_hdr->imagepath_len + trace_hdr->message_len : NULL; + //const char* category = (trace_hdr->category_len > 0) ? dataptr + trace_hdr->procpath_len + trace_hdr->imagepath_len + trace_hdr->message_len + trace_hdr->subsystem_len : NULL; + + int shall_print = 1; + int trigger_off = 0; + const char* process_name_short = (process_name) ? strrchr(process_name, '/') : ""; + process_name_short = (process_name_short) ? process_name_short+1 : process_name; + const char* image_name_short = (image_name) ? strrchr(image_name, '/') : NULL; + image_name_short = (image_name_short) ? image_name_short+1 : process_name; + if (image_name_short && !strcmp(image_name_short, process_name_short)) { + image_name_short = NULL; + } + + do { + /* check if we have any triggers/untriggers */ + if (num_untrigger_filters > 0 && triggered) { + int found = 0; + int i; + for (i = 0; i < num_untrigger_filters; i++) { + if (strstr(message, untrigger_filters[i])) { + found = 1; + break; + } + } + if (!found) { + shall_print = 1; + } else { + shall_print = 1; + trigger_off = 1; + } + } else if (num_trigger_filters > 0 && !triggered) { + int found = 0; + int i; + for (i = 0; i < num_trigger_filters; i++) { + if (strstr(message, trigger_filters[i])) { + found = 1; + break; + } + } + if (!found) { + shall_print = 0; + break; + } + triggered = 1; + shall_print = 1; + } else if (num_trigger_filters == 0 && num_untrigger_filters > 0 && !triggered) { + shall_print = 0; + quit_flag++; + break; + } + + /* check message filters */ + shall_print = message_filter_matching(message); + if (!shall_print) { + break; + } + + /* check process filters */ + if (process_filter_matching(trace_hdr->pid, process_name_short, strlen(process_name_short))) { + shall_print = 1; + } else { + if (num_pid_filters > 0 || num_proc_filters > 0) { + shall_print = 0; + } + } + if (!shall_print) { + break; + } + } while (0); + + if (!shall_print) { + return; + } + + const char* level_str = "Unknown"; + const char* level_color = FG_YELLOW; + switch (trace_hdr->level) { + case 0: + level_str = "Notice"; + level_color = FG_GREEN; + break; + case 0x01: + level_str = "Info"; + level_color = FG_WHITE; + break; + case 0x02: + level_str = "Debug"; + level_color = FG_MAGENTA; + break; + case 0x10: + level_str = "Error"; + level_color = FG_RED; + break; + case 0x11: + level_str = "Fault"; + level_color = FG_RED; + default: + break; + } + + char datebuf[24]; + struct tm *tp; + time_t time_sec = (time_t)trace_hdr->time_sec; +#ifdef HAVE_LOCALTIME_R + struct tm tp_ = {0, }; + tp = localtime_r(&time_sec, &tp_); +#else + tp = localtime(&time_sec); +#endif +#ifdef _WIN32 + strftime(datebuf, 16, "%b %#d %H:%M:%S", tp); +#else + strftime(datebuf, 16, "%b %e %H:%M:%S", tp); +#endif + snprintf(datebuf+15, 9, ".%06u", trace_hdr->time_usec); + + /* write date and time */ + cprintf(FG_LIGHT_GRAY "%s ", datebuf); + + if (show_device_name) { + /* write device name TODO do we need this? */ + //cprintf(FG_DARK_YELLOW "%s ", device_name); + } + + /* write process name */ + cprintf(FG_BRIGHT_CYAN "%s" FG_CYAN, process_name_short); + if (image_name_short) { + cprintf("(%s)", image_name_short); + } + cprintf("[%d]" COLOR_RESET " ", trace_hdr->pid); + + /* write log level */ + cprintf(level_color); + cprintf("<%s>:" COLOR_RESET " ", level_str); + + /* write message */ + cprintf(FG_WHITE); + cprintf("%s" COLOR_RESET "\n", message); + fflush(stdout); + + if (trigger_off) { + triggered = 0; + } +} + +static plist_t get_pid_list() +{ + plist_t list = NULL; + ostrace_client_t ostrace_tmp = NULL; + ostrace_client_start_service(device, &ostrace_tmp, TOOL_NAME); + if (ostrace_tmp) { + ostrace_get_pid_list(ostrace_tmp, &list); + ostrace_client_free(ostrace_tmp); + } + return list; +} + +static int pid_valid(int pid) +{ + plist_t list = get_pid_list(); + if (!list) return 0; + char valbuf[16]; + snprintf(valbuf, 16, "%d", pid); + return (plist_dict_get_item(list, valbuf)) ? 1 : 0; +} + +static int pid_for_proc(const char* procname) +{ + int result = -1; + plist_t list = get_pid_list(); + if (!list) { + return result; + } + plist_dict_iter iter = NULL; + plist_dict_new_iter(list, &iter); + if (iter) { + plist_t node = NULL; + do { + char* key = NULL; + node = NULL; + plist_dict_next_item(list, iter, &key, &node); + if (!key) { + break; + } + if (PLIST_IS_DICT(node)) { + plist_t pname = plist_dict_get_item(node, "ProcessName"); + if (PLIST_IS_STRING(pname)) { + if (!strcmp(plist_get_string_ptr(pname, NULL), procname)) { + result = (int)strtol(key, NULL, 10); + } + } + } + free(key); + } while (node); + plist_mem_free(iter); + } + plist_free(list); + return result; +} + +static int connect_service(int ostrace_required) +{ + if (!device) { + idevice_error_t ret = idevice_new_with_options(&device, udid, (use_network) ? IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX); + if (ret != IDEVICE_E_SUCCESS) { + fprintf(stderr, "Device with udid %s not found!?\n", udid); + return -1; + } } lockdownd_client_t lockdown = NULL; @@ -361,14 +615,28 @@ static int start_logging(void) device = NULL; return -1; } - - /* start syslog_relay service */ lockdownd_service_descriptor_t svc = NULL; - lerr = lockdownd_start_service(lockdown, SYSLOG_RELAY_SERVICE_NAME, &svc); + + const char* service_name = OSTRACE_SERVICE_NAME; + int use_ostrace = 1; + if (idevice_get_device_version(device) < IDEVICE_DEVICE_VERSION(9,0,0) || force_syslog_relay) { + service_name = SYSLOG_RELAY_SERVICE_NAME; + use_ostrace = 0; + } + if (ostrace_required && !use_ostrace) { + fprintf(stderr, "ERROR: This operation requires iOS 9 or later.\n"); + lockdownd_client_free(lockdown); + idevice_free(device); + device = NULL; + return -1; + } + + /* start syslog_relay/os_trace_relay service */ + lerr = lockdownd_start_service(lockdown, service_name, &svc); if (lerr == LOCKDOWN_E_PASSWORD_PROTECTED) { fprintf(stderr, "*** Device is passcode protected, enter passcode on the device to continue ***\n"); while (!quit_flag) { - lerr = lockdownd_start_service(lockdown, SYSLOG_RELAY_SERVICE_NAME, &svc); + lerr = lockdownd_start_service(lockdown, service_name, &svc); if (lerr != LOCKDOWN_E_PASSWORD_PROTECTED) { break; } @@ -376,32 +644,84 @@ static int start_logging(void) } } if (lerr != LOCKDOWN_E_SUCCESS) { - fprintf(stderr, "ERROR: Could not connect to lockdownd: %d\n", lerr); + fprintf(stderr, "ERROR: Could not start %s service: %s (%d)\n", service_name, lockdownd_strerror(lerr), lerr); idevice_free(device); device = NULL; return -1; } lockdownd_client_free(lockdown); - /* connect to syslog_relay service */ - syslog_relay_error_t serr = SYSLOG_RELAY_E_UNKNOWN_ERROR; - serr = syslog_relay_client_new(device, svc, &syslog); - lockdownd_service_descriptor_free(svc); - if (serr != SYSLOG_RELAY_E_SUCCESS) { - fprintf(stderr, "ERROR: Could not start service com.apple.syslog_relay.\n"); - idevice_free(device); - device = NULL; + if (use_ostrace) { + /* connect to os_trace_relay service */ + ostrace_error_t serr = OSTRACE_E_UNKNOWN_ERROR; + serr = ostrace_client_new(device, svc, &ostrace); + lockdownd_service_descriptor_free(svc); + if (serr != OSTRACE_E_SUCCESS) { + fprintf(stderr, "ERROR: Could not connect to %s service (%d)\n", service_name, serr); + idevice_free(device); + device = NULL; + return -1; + } + } else { + /* connect to syslog_relay service */ + syslog_relay_error_t serr = SYSLOG_RELAY_E_UNKNOWN_ERROR; + serr = syslog_relay_client_new(device, svc, &syslog); + lockdownd_service_descriptor_free(svc); + if (serr != SYSLOG_RELAY_E_SUCCESS) { + fprintf(stderr, "ERROR: Could not connect to %s service (%d)\n", service_name, serr); + idevice_free(device); + device = NULL; + return -1; + } + } + return 0; +} + +static int start_logging(void) +{ + if (connect_service(0) < 0) { return -1; } /* start capturing syslog */ - serr = syslog_relay_start_capture_raw(syslog, syslog_callback, NULL); - if (serr != SYSLOG_RELAY_E_SUCCESS) { - fprintf(stderr, "ERROR: Unable tot start capturing syslog.\n"); - syslog_relay_client_free(syslog); - syslog = NULL; - idevice_free(device); - device = NULL; + if (ostrace) { + plist_t options = plist_new_dict(); + if (num_proc_filters == 0 && num_pid_filters == 1 && !proc_filter_excluding) { + if (pid_filters[0] > 0) { + if (!pid_valid(pid_filters[0])) { + fprintf(stderr, "NOTE: A process with pid doesn't exists!\n"); + } + } + plist_dict_set_item(options, "Pid", plist_new_int(pid_filters[0])); + } else if (num_proc_filters == 1 && num_pid_filters == 0 && !proc_filter_excluding) { + int pid = pid_for_proc(proc_filters[0]); + if (!strcmp(proc_filters[0], "kernel")) { + pid = 0; + } + if (pid >= 0) { + plist_dict_set_item(options, "Pid", plist_new_int(pid)); + } + } + ostrace_error_t serr = ostrace_start_activity(ostrace, options, ostrace_syslog_callback, NULL); + if (serr != OSTRACE_E_SUCCESS) { + fprintf(stderr, "ERROR: Unable to start capturing syslog.\n"); + ostrace_client_free(ostrace); + ostrace = NULL; + idevice_free(device); + device = NULL; + return -1; + } + } else if (syslog) { + syslog_relay_error_t serr = syslog_relay_start_capture_raw(syslog, syslog_callback, NULL); + if (serr != SYSLOG_RELAY_E_SUCCESS) { + fprintf(stderr, "ERROR: Unable to start capturing syslog.\n"); + syslog_relay_client_free(syslog); + syslog = NULL; + idevice_free(device); + device = NULL; + return -1; + } + } else { return -1; } @@ -419,6 +739,11 @@ static void stop_logging(void) syslog_relay_client_free(syslog); syslog = NULL; } + if (ostrace) { + ostrace_stop_activity(ostrace); + ostrace_client_free(ostrace); + ostrace = NULL; + } if (device) { idevice_free(device); @@ -426,6 +751,77 @@ static void stop_logging(void) } } +static int write_callback(const void* buf, size_t len, void *user_data) +{ + FILE* f = (FILE*)user_data; + ssize_t res = fwrite(buf, 1, len, f); + if (res < 0) { + return -1; + } + if (quit_flag > 0) { + return -1; + } + return 0; +} + +static void print_sorted_pidlist(plist_t list) +{ + struct listelem; + struct listelem { + int val; + struct listelem *next; + }; + struct listelem* sortedlist = NULL; + + plist_dict_iter iter = NULL; + plist_dict_new_iter(list, &iter); + if (iter) { + plist_t node = NULL; + do { + char* key = NULL; + node = NULL; + plist_dict_next_item(list, iter, &key, &node); + if (key) { + int pidval = (int)strtol(key, NULL, 10); + struct listelem* elem = (struct listelem*)malloc(sizeof(struct listelem)); + elem->val = pidval; + elem->next = NULL; + struct listelem* prev = NULL; + struct listelem* curr = sortedlist; + + while (curr && pidval > curr->val) { + prev = curr; + curr = curr->next; + } + + elem->next = curr; + if (prev == NULL) { + sortedlist = elem; + } else { + prev->next = elem; + } + free(key); + } + } while (node); + plist_mem_free(iter); + } + struct listelem *listp = sortedlist; + char pidstr[16]; + while (listp) { + snprintf(pidstr, 16, "%d", listp->val); + plist_t node = plist_dict_get_item(list, pidstr); + if (PLIST_IS_DICT(node)) { + plist_t pname = plist_dict_get_item(node, "ProcessName"); + if (PLIST_IS_STRING(pname)) { + printf("%d %s\n", listp->val, plist_get_string_ptr(pname, NULL)); + } + } + struct listelem *curr = listp; + listp = listp->next; + free(curr); + } +} + static void device_event_cb(const idevice_event_t* event, void* userdata) { if (use_network && event->conn_type != CONNECTION_NETWORK) { @@ -435,7 +831,7 @@ static void device_event_cb(const idevice_event_t* event, void* userdata) return; } if (event->event == IDEVICE_DEVICE_ADD) { - if (!syslog) { + if (!syslog && !ostrace) { if (!udid) { udid = strdup(event->udid); } @@ -446,7 +842,7 @@ static void device_event_cb(const idevice_event_t* event, void* userdata) } } } else if (event->event == IDEVICE_DEVICE_REMOVE) { - if (syslog && (strcmp(udid, event->udid) == 0)) { + if ((syslog || ostrace) && (strcmp(udid, event->udid) == 0)) { stop_logging(); fprintf(stdout, "[disconnected:%s]\n", udid); if (exit_on_disconnect) { @@ -484,9 +880,20 @@ static void print_usage(int argc, char **argv, int is_error) " -o, --output FILE write to FILE instead of stdout\n" " (existing FILE will be overwritten)\n" " --colors force writing colored output, e.g. for --output\n" + " --syslog-relay force use of syslog_relay service\n" + "\n" + "COMMANDS:\n" + " pidlist Print pid and name of all running processes.\n" + " archive PATH Request a logarchive and write it to PATH.\n" + " Output can be piped to another process using - as PATH.\n" + " The file data will be in .tar format.\n" + " --start-time VALUE start time of the log data as UNIX timestamp\n" + " --age-limit VALUE maximum age of the log data\n" + " --size-limit VALUE limit the size of the archive\n" "\n" "FILTER OPTIONS:\n" " -m, --match STRING only print messages that contain STRING\n" + " -M, --unmatch STRING print messages that not contain STRING\n" " -t, --trigger STRING start logging when matching STRING\n" " -T, --untrigger STRING stop logging when matching STRING\n" " -p, --process PROCESS only print messages from matching process(es)\n" @@ -530,6 +937,12 @@ int main(int argc, char *argv[]) { "quiet-list", no_argument, NULL, 1 }, { "no-colors", no_argument, NULL, 2 }, { "colors", no_argument, NULL, 3 }, + { "syslog_relay", no_argument, NULL, 4 }, + { "syslog-relay", no_argument, NULL, 4 }, + { "legacy", no_argument, NULL, 4 }, + { "start-time", required_argument, NULL, 5 }, + { "size-limit", required_argument, NULL, 6 }, + { "age-limit", required_argument, NULL, 7 }, { "output", required_argument, NULL, 'o' }, { "version", no_argument, NULL, 'v' }, { NULL, 0, NULL, 0} @@ -537,12 +950,12 @@ int main(int argc, char *argv[]) signal(SIGINT, clean_exit); signal(SIGTERM, clean_exit); -#ifndef WIN32 +#ifndef _WIN32 signal(SIGQUIT, clean_exit); signal(SIGPIPE, SIG_IGN); #endif - while ((c = getopt_long(argc, argv, "dhu:nxt:T:m:e:p:qkKo:v", longopts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "dhu:nxt:T:m:M:e:p:qkKo:v", longopts, NULL)) != -1) { switch (c) { case 'd': idevice_set_debug_level(1); @@ -593,6 +1006,22 @@ int main(int argc, char *argv[]) num_msg_filters++; } break; + case 'M': + if (!*optarg) { + fprintf(stderr, "ERROR: reverse message filter string must not be empty!\n"); + print_usage(argc, argv, 1); + return 2; + } else { + char **new_msg_filters = realloc(msg_reverse_filters, sizeof(char*) * (num_msg_reverse_filters+1)); + if (!new_msg_filters) { + fprintf(stderr, "ERROR: realloc() failed\n"); + exit(EXIT_FAILURE); + } + msg_reverse_filters = new_msg_filters; + msg_reverse_filters[num_msg_reverse_filters] = strdup(optarg); + num_msg_reverse_filters++; + } + break; case 't': if (!*optarg) { fprintf(stderr, "ERROR: trigger filter string must not be empty!\n"); @@ -647,6 +1076,18 @@ int main(int argc, char *argv[]) case 3: force_colors = 1; break; + case 4: + force_syslog_relay = 1; + break; + case 5: + start_time = strtoll(optarg, NULL, 10); + break; + case 6: + size_limit = strtoll(optarg, NULL, 10); + break; + case 7: + age_limit = strtoll(optarg, NULL, 10); + break; case 'o': if (!*optarg) { fprintf(stderr, "ERROR: --output option requires an argument!\n"); @@ -719,14 +1160,92 @@ int main(int argc, char *argv[]) argc -= optind; argv += optind; + if (argc > 0) { + if (!strcmp(argv[0], "pidlist")) { + if (connect_service(1) < 0) { + return 1; + } + plist_t list = NULL; + ostrace_get_pid_list(ostrace, &list); + ostrace_client_free(ostrace); + ostrace = NULL; + idevice_free(device); + device = NULL; + if (!list) { + return 1; + } + print_sorted_pidlist(list); + plist_free(list); + return 0; + } else if (!strcmp(argv[0], "archive")) { + if (force_syslog_relay) { + force_syslog_relay = 0; + } + if (argc < 2) { + fprintf(stderr, "Please specify an output filename.\n"); + return 1; + } + FILE* outf = NULL; + if (!strcmp(argv[1], "-")) { + if (isatty(1)) { + fprintf(stderr, "Refusing to directly write to stdout. Pipe the output to another process.\n"); + return 1; + } + outf = stdout; + } else { + outf = fopen(argv[1], "w"); + } + if (!outf) { + fprintf(stderr, "Failed to open %s: %s\n", argv[1], strerror(errno)); + return 1; + } + if (connect_service(1) < 0) { + if (outf != stdout) { + fclose(outf); + } + return 1; + } + plist_t options = plist_new_dict(); + if (start_time > 0) { + plist_dict_set_item(options, "StartTime", plist_new_int(start_time)); + } + if (size_limit > 0) { + plist_dict_set_item(options, "SizeLimit", plist_new_int(size_limit)); + } + if (age_limit > 0) { + plist_dict_set_item(options, "AgeLimit", plist_new_int(age_limit)); + } + ostrace_create_archive(ostrace, options, write_callback, outf); + ostrace_client_free(ostrace); + ostrace = NULL; + idevice_free(device); + device = NULL; + if (outf != stdout) { + fclose(outf); + } + return 0; + } else { + fprintf(stderr, "Unknown command '%s'. See --help for valid commands.\n", argv[0]); + return 1; + } + } + int num = 0; idevice_info_t *devices = NULL; idevice_get_device_list_extended(&devices, &num); + int count = 0; + for (int i = 0; i < num; i++) { + if (devices[i]->conn_type == CONNECTION_NETWORK && use_network) { + count++; + } else if (devices[i]->conn_type == CONNECTION_USBMUXD) { + count++; + } + } idevice_device_list_extended_free(devices); - if (num == 0) { + if (count == 0) { if (!udid) { - fprintf(stderr, "No device found. Plug in a device or pass UDID with -u to wait for device to be available.\n"); - return -1; + fprintf(stderr, "No device found. Plug in a device or pass UDID with -u to wait for device to become available.\n"); + return 1; } fprintf(stderr, "Waiting for device with UDID %s to become available...\n", udid); @@ -761,6 +1280,13 @@ int main(int argc, char *argv[]) } free(msg_filters); } + if (num_msg_reverse_filters > 0) { + int i; + for (i = 0; i < num_msg_reverse_filters; i++) { + free(msg_reverse_filters[i]); + } + free(msg_reverse_filters); + } if (num_trigger_filters > 0) { int i; for (i = 0; i < num_trigger_filters; i++) { |
